| ... | @@ -757,11 +757,14 @@ pub const DeclGen = struct { | ... | @@ -757,11 +757,14 @@ pub const DeclGen = struct { |
| 757 | try dg.llvmType(Type.usize), | 757 | try dg.llvmType(Type.usize), |
| 758 | }; | 758 | }; |
| 759 | return dg.context.structType(&fields, fields.len, .False); | 759 | return dg.context.structType(&fields, fields.len, .False); |
| 760 | } else { | | |
| 761 | const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace()); | | |
| 762 | const llvm_elem_ty = try dg.llvmType(t.childType()); | | |
| 763 | return llvm_elem_ty.pointerType(llvm_addrspace); | | |
| 764 | } | 760 | } |
| | 761 | const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace()); |
| | 762 | const elem_ty = t.childType(); |
| | 763 | const llvm_elem_ty = if (elem_ty.hasCodeGenBits()) |
| | 764 | try dg.llvmType(elem_ty) |
| | 765 | else |
| | 766 | dg.context.intType(8); |
| | 767 | return llvm_elem_ty.pointerType(llvm_addrspace); |
| 765 | }, | 768 | }, |
| 766 | .Opaque => { | 769 | .Opaque => { |
| 767 | const gop = try dg.object.type_map.getOrPut(gpa, t); | 770 | const gop = try dg.object.type_map.getOrPut(gpa, t); |
| ... | @@ -791,10 +794,14 @@ pub const DeclGen = struct { | ... | @@ -791,10 +794,14 @@ pub const DeclGen = struct { |
| 791 | .Optional => { | 794 | .Optional => { |
| 792 | var buf: Type.Payload.ElemType = undefined; | 795 | var buf: Type.Payload.ElemType = undefined; |
| 793 | const child_type = t.optionalChild(&buf); | 796 | const child_type = t.optionalChild(&buf); |
| | 797 | if (!child_type.hasCodeGenBits()) { |
| | 798 | return dg.context.intType(1); |
| | 799 | } |
| 794 | const payload_llvm_ty = try dg.llvmType(child_type); | 800 | const payload_llvm_ty = try dg.llvmType(child_type); |
| 795 | | | |
| 796 | if (t.isPtrLikeOptional()) { | 801 | if (t.isPtrLikeOptional()) { |
| 797 | return payload_llvm_ty; | 802 | return payload_llvm_ty; |
| | 803 | } else if (!child_type.hasCodeGenBits()) { |
| | 804 | return dg.context.intType(1); |
| 798 | } | 805 | } |
| 799 | | 806 | |
| 800 | const fields: [2]*const llvm.Type = .{ | 807 | const fields: [2]*const llvm.Type = .{ |
| ... | @@ -826,7 +833,6 @@ pub const DeclGen = struct { | ... | @@ -826,7 +833,6 @@ pub const DeclGen = struct { |
| 826 | gop.key_ptr.* = try t.copy(&dg.object.type_map_arena.allocator); | 833 | gop.key_ptr.* = try t.copy(&dg.object.type_map_arena.allocator); |
| 827 | | 834 | |
| 828 | const struct_obj = t.castTag(.@"struct").?.data; | 835 | const struct_obj = t.castTag(.@"struct").?.data; |
| 829 | assert(struct_obj.haveFieldTypes()); | | |
| 830 | | 836 | |
| 831 | const name = try struct_obj.getFullyQualifiedName(gpa); | 837 | const name = try struct_obj.getFullyQualifiedName(gpa); |
| 832 | defer gpa.free(name); | 838 | defer gpa.free(name); |
| ... | @@ -834,6 +840,8 @@ pub const DeclGen = struct { | ... | @@ -834,6 +840,8 @@ pub const DeclGen = struct { |
| 834 | const llvm_struct_ty = dg.context.structCreateNamed(name); | 840 | const llvm_struct_ty = dg.context.structCreateNamed(name); |
| 835 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | 841 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| 836 | | 842 | |
| | 843 | assert(struct_obj.haveFieldTypes()); |
| | 844 | |
| 837 | var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{}; | 845 | var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{}; |
| 838 | try llvm_field_types.ensureTotalCapacity(gpa, struct_obj.fields.count()); | 846 | try llvm_field_types.ensureTotalCapacity(gpa, struct_obj.fields.count()); |
| 839 | defer llvm_field_types.deinit(gpa); | 847 | defer llvm_field_types.deinit(gpa); |
| ... | @@ -1129,7 +1137,12 @@ pub const DeclGen = struct { | ... | @@ -1129,7 +1137,12 @@ pub const DeclGen = struct { |
| 1129 | .Optional => { | 1137 | .Optional => { |
| 1130 | var buf: Type.Payload.ElemType = undefined; | 1138 | var buf: Type.Payload.ElemType = undefined; |
| 1131 | const payload_ty = tv.ty.optionalChild(&buf); | 1139 | const payload_ty = tv.ty.optionalChild(&buf); |
| 1132 | | 1140 | const llvm_i1 = self.context.intType(1); |
| | 1141 | const is_pl = !tv.val.isNull(); |
| | 1142 | const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull(); |
| | 1143 | if (!payload_ty.hasCodeGenBits()) { |
| | 1144 | return non_null_bit; |
| | 1145 | } |
| 1133 | if (tv.ty.isPtrLikeOptional()) { | 1146 | if (tv.ty.isPtrLikeOptional()) { |
| 1134 | if (tv.val.castTag(.opt_payload)) |payload| { | 1147 | if (tv.val.castTag(.opt_payload)) |payload| { |
| 1135 | return self.genTypedValue(.{ .ty = payload_ty, .val = payload.data }); | 1148 | return self.genTypedValue(.{ .ty = payload_ty, .val = payload.data }); |
| ... | @@ -1138,15 +1151,12 @@ pub const DeclGen = struct { | ... | @@ -1138,15 +1151,12 @@ pub const DeclGen = struct { |
| 1138 | return llvm_ty.constNull(); | 1151 | return llvm_ty.constNull(); |
| 1139 | } | 1152 | } |
| 1140 | } | 1153 | } |
| 1141 | const is_pl = !tv.val.isNull(); | | |
| 1142 | const llvm_i1 = self.context.intType(1); | | |
| 1143 | | | |
| 1144 | const fields: [2]*const llvm.Value = .{ | 1154 | const fields: [2]*const llvm.Value = .{ |
| 1145 | try self.genTypedValue(.{ | 1155 | try self.genTypedValue(.{ |
| 1146 | .ty = payload_ty, | 1156 | .ty = payload_ty, |
| 1147 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), | 1157 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), |
| 1148 | }), | 1158 | }), |
| 1149 | if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull(), | 1159 | non_null_bit, |
| 1150 | }; | 1160 | }; |
| 1151 | return self.context.constStruct(&fields, fields.len, .False); | 1161 | return self.context.constStruct(&fields, fields.len, .False); |
| 1152 | }, | 1162 | }, |
| ... | @@ -1307,6 +1317,10 @@ pub const DeclGen = struct { | ... | @@ -1307,6 +1317,10 @@ pub const DeclGen = struct { |
| 1307 | | 1317 | |
| 1308 | decl.alive = true; | 1318 | decl.alive = true; |
| 1309 | const llvm_type = try self.llvmType(tv.ty); | 1319 | const llvm_type = try self.llvmType(tv.ty); |
| | 1320 | if (!tv.ty.childType().hasCodeGenBits()) { |
| | 1321 | return self.lowerPtrToVoid(tv.ty); |
| | 1322 | } |
| | 1323 | |
| 1310 | const llvm_val = if (decl.ty.zigTypeTag() == .Fn) | 1324 | const llvm_val = if (decl.ty.zigTypeTag() == .Fn) |
| 1311 | try self.resolveLlvmFunction(decl) | 1325 | try self.resolveLlvmFunction(decl) |
| 1312 | else | 1326 | else |
| ... | @@ -1314,6 +1328,32 @@ pub const DeclGen = struct { | ... | @@ -1314,6 +1328,32 @@ pub const DeclGen = struct { |
| 1314 | return llvm_val.constBitCast(llvm_type); | 1328 | return llvm_val.constBitCast(llvm_type); |
| 1315 | } | 1329 | } |
| 1316 | | 1330 | |
| | 1331 | fn lowerPtrToVoid(dg: *DeclGen, ptr_ty: Type) !*const llvm.Value { |
| | 1332 | const target = dg.module.getTarget(); |
| | 1333 | const alignment = ptr_ty.ptrAlignment(target); |
| | 1334 | // Even though we are pointing at something which has zero bits (e.g. `void`), |
| | 1335 | // Pointers are defined to have bits. So we must return something here. |
| | 1336 | // The value cannot be undefined, because we use the `nonnull` annotation |
| | 1337 | // for non-optional pointers. We also need to respect the alignment, even though |
| | 1338 | // the address will never be dereferenced. |
| | 1339 | const llvm_usize = try dg.llvmType(Type.usize); |
| | 1340 | const llvm_ptr_ty = dg.context.intType(8).pointerType(0); |
| | 1341 | if (alignment != 0) { |
| | 1342 | return llvm_usize.constInt(alignment, .False).constIntToPtr(llvm_ptr_ty); |
| | 1343 | } |
| | 1344 | // Note that these 0xaa values are appropriate even in release-optimized builds |
| | 1345 | // because we need a well-defined value that is not null, and LLVM does not |
| | 1346 | // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR |
| | 1347 | // instruction is followed by a `wrap_optional`, it will return this value |
| | 1348 | // verbatim, and the result should test as non-null. |
| | 1349 | const int = switch (target.cpu.arch.ptrBitWidth()) { |
| | 1350 | 32 => llvm_usize.constInt(0xaaaaaaaa, .False), |
| | 1351 | 64 => llvm_usize.constInt(0xaaaaaaaa_aaaaaaaa, .False), |
| | 1352 | else => unreachable, |
| | 1353 | }; |
| | 1354 | return int.constIntToPtr(llvm_ptr_ty); |
| | 1355 | } |
| | 1356 | |
| 1317 | fn addAttr(dg: DeclGen, val: *const llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { | 1357 | fn addAttr(dg: DeclGen, val: *const llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { |
| 1318 | return dg.addAttrInt(val, index, name, 0); | 1358 | return dg.addAttrInt(val, index, name, 0); |
| 1319 | } | 1359 | } |
| ... | @@ -1972,12 +2012,13 @@ pub const FuncGen = struct { | ... | @@ -1972,12 +2012,13 @@ pub const FuncGen = struct { |
| 1972 | | 2012 | |
| 1973 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2013 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1974 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2014 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1975 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 2015 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 1976 | if (!lhs_ty.hasCodeGenBits()) return null; | 2016 | const elem_ty = ptr_ty.childType(); |
| | 2017 | if (!elem_ty.hasCodeGenBits()) return null; |
| 1977 | | 2018 | |
| 1978 | const base_ptr = try self.resolveInst(bin_op.lhs); | 2019 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 1979 | const rhs = try self.resolveInst(bin_op.rhs); | 2020 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1980 | if (lhs_ty.isSinglePointer()) { | 2021 | if (ptr_ty.isSinglePointer()) { |
| 1981 | // If this is a single-item pointer to an array, we need another index in the GEP. | 2022 | // If this is a single-item pointer to an array, we need another index in the GEP. |
| 1982 | const indices: [2]*const llvm.Value = .{ self.context.intType(32).constNull(), rhs }; | 2023 | const indices: [2]*const llvm.Value = .{ self.context.intType(32).constNull(), rhs }; |
| 1983 | return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, ""); | 2024 | return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, ""); |
| ... | @@ -2832,11 +2873,13 @@ pub const FuncGen = struct { | ... | @@ -2832,11 +2873,13 @@ pub const FuncGen = struct { |
| 2832 | if (self.liveness.isUnused(inst)) return null; | 2873 | if (self.liveness.isUnused(inst)) return null; |
| 2833 | const ptr_ty = self.air.typeOfIndex(inst); | 2874 | const ptr_ty = self.air.typeOfIndex(inst); |
| 2834 | const pointee_type = ptr_ty.childType(); | 2875 | const pointee_type = ptr_ty.childType(); |
| 2835 | if (!pointee_type.hasCodeGenBits()) return null; | 2876 | if (!pointee_type.hasCodeGenBits()) return self.dg.lowerPtrToVoid(ptr_ty); |
| | 2877 | |
| 2836 | const pointee_llvm_ty = try self.dg.llvmType(pointee_type); | 2878 | const pointee_llvm_ty = try self.dg.llvmType(pointee_type); |
| 2837 | const target = self.dg.module.getTarget(); | | |
| 2838 | const alloca_inst = self.buildAlloca(pointee_llvm_ty); | 2879 | const alloca_inst = self.buildAlloca(pointee_llvm_ty); |
| 2839 | alloca_inst.setAlignment(ptr_ty.ptrAlignment(target)); | 2880 | const target = self.dg.module.getTarget(); |
| | 2881 | const alignment = ptr_ty.ptrAlignment(target); |
| | 2882 | alloca_inst.setAlignment(alignment); |
| 2840 | return alloca_inst; | 2883 | return alloca_inst; |
| 2841 | } | 2884 | } |
| 2842 | | 2885 | |