diff options
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/llvm.zig | 77 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 3 |
2 files changed, 63 insertions, 17 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 2c58ee56f8..bab476306a 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -757,11 +757,14 @@ pub const DeclGen = struct { try dg.llvmType(Type.usize), }; return dg.context.structType(&fields, fields.len, .False); - } else { - const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace()); - const llvm_elem_ty = try dg.llvmType(t.childType()); - return llvm_elem_ty.pointerType(llvm_addrspace); } + const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace()); + const elem_ty = t.childType(); + const llvm_elem_ty = if (elem_ty.hasCodeGenBits()) + try dg.llvmType(elem_ty) + else + dg.context.intType(8); + return llvm_elem_ty.pointerType(llvm_addrspace); }, .Opaque => { const gop = try dg.object.type_map.getOrPut(gpa, t); @@ -791,10 +794,14 @@ pub const DeclGen = struct { .Optional => { var buf: Type.Payload.ElemType = undefined; const child_type = t.optionalChild(&buf); + if (!child_type.hasCodeGenBits()) { + return dg.context.intType(1); + } const payload_llvm_ty = try dg.llvmType(child_type); - if (t.isPtrLikeOptional()) { return payload_llvm_ty; + } else if (!child_type.hasCodeGenBits()) { + return dg.context.intType(1); } const fields: [2]*const llvm.Type = .{ @@ -826,7 +833,6 @@ pub const DeclGen = struct { gop.key_ptr.* = try t.copy(&dg.object.type_map_arena.allocator); const struct_obj = t.castTag(.@"struct").?.data; - assert(struct_obj.haveFieldTypes()); const name = try struct_obj.getFullyQualifiedName(gpa); defer gpa.free(name); @@ -834,6 +840,8 @@ pub const DeclGen = struct { const llvm_struct_ty = dg.context.structCreateNamed(name); gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls + assert(struct_obj.haveFieldTypes()); + var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{}; try llvm_field_types.ensureTotalCapacity(gpa, struct_obj.fields.count()); defer llvm_field_types.deinit(gpa); @@ -1129,7 +1137,12 @@ pub const DeclGen = struct { .Optional => { var buf: Type.Payload.ElemType = undefined; const payload_ty = tv.ty.optionalChild(&buf); - + const llvm_i1 = self.context.intType(1); + const is_pl = !tv.val.isNull(); + const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull(); + if (!payload_ty.hasCodeGenBits()) { + return non_null_bit; + } if (tv.ty.isPtrLikeOptional()) { if (tv.val.castTag(.opt_payload)) |payload| { return self.genTypedValue(.{ .ty = payload_ty, .val = payload.data }); @@ -1138,15 +1151,12 @@ pub const DeclGen = struct { return llvm_ty.constNull(); } } - const is_pl = !tv.val.isNull(); - const llvm_i1 = self.context.intType(1); - const fields: [2]*const llvm.Value = .{ try self.genTypedValue(.{ .ty = payload_ty, .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), }), - if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull(), + non_null_bit, }; return self.context.constStruct(&fields, fields.len, .False); }, @@ -1307,6 +1317,10 @@ pub const DeclGen = struct { decl.alive = true; const llvm_type = try self.llvmType(tv.ty); + if (!tv.ty.childType().hasCodeGenBits()) { + return self.lowerPtrToVoid(tv.ty); + } + const llvm_val = if (decl.ty.zigTypeTag() == .Fn) try self.resolveLlvmFunction(decl) else @@ -1314,6 +1328,32 @@ pub const DeclGen = struct { return llvm_val.constBitCast(llvm_type); } + fn lowerPtrToVoid(dg: *DeclGen, ptr_ty: Type) !*const llvm.Value { + const target = dg.module.getTarget(); + const alignment = ptr_ty.ptrAlignment(target); + // Even though we are pointing at something which has zero bits (e.g. `void`), + // Pointers are defined to have bits. So we must return something here. + // The value cannot be undefined, because we use the `nonnull` annotation + // for non-optional pointers. We also need to respect the alignment, even though + // the address will never be dereferenced. + const llvm_usize = try dg.llvmType(Type.usize); + const llvm_ptr_ty = dg.context.intType(8).pointerType(0); + if (alignment != 0) { + return llvm_usize.constInt(alignment, .False).constIntToPtr(llvm_ptr_ty); + } + // Note that these 0xaa values are appropriate even in release-optimized builds + // because we need a well-defined value that is not null, and LLVM does not + // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR + // instruction is followed by a `wrap_optional`, it will return this value + // verbatim, and the result should test as non-null. + const int = switch (target.cpu.arch.ptrBitWidth()) { + 32 => llvm_usize.constInt(0xaaaaaaaa, .False), + 64 => llvm_usize.constInt(0xaaaaaaaa_aaaaaaaa, .False), + else => unreachable, + }; + return int.constIntToPtr(llvm_ptr_ty); + } + fn addAttr(dg: DeclGen, val: *const llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { return dg.addAttrInt(val, index, name, 0); } @@ -1972,12 +2012,13 @@ pub const FuncGen = struct { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; - const lhs_ty = self.air.typeOf(bin_op.lhs); - if (!lhs_ty.hasCodeGenBits()) return null; + const ptr_ty = self.air.typeOf(bin_op.lhs); + const elem_ty = ptr_ty.childType(); + if (!elem_ty.hasCodeGenBits()) return null; const base_ptr = try self.resolveInst(bin_op.lhs); const rhs = try self.resolveInst(bin_op.rhs); - if (lhs_ty.isSinglePointer()) { + if (ptr_ty.isSinglePointer()) { // If this is a single-item pointer to an array, we need another index in the GEP. const indices: [2]*const llvm.Value = .{ self.context.intType(32).constNull(), rhs }; return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, ""); @@ -2832,11 +2873,13 @@ pub const FuncGen = struct { if (self.liveness.isUnused(inst)) return null; const ptr_ty = self.air.typeOfIndex(inst); const pointee_type = ptr_ty.childType(); - if (!pointee_type.hasCodeGenBits()) return null; + if (!pointee_type.hasCodeGenBits()) return self.dg.lowerPtrToVoid(ptr_ty); + const pointee_llvm_ty = try self.dg.llvmType(pointee_type); - const target = self.dg.module.getTarget(); const alloca_inst = self.buildAlloca(pointee_llvm_ty); - alloca_inst.setAlignment(ptr_ty.ptrAlignment(target)); + const target = self.dg.module.getTarget(); + const alignment = ptr_ty.ptrAlignment(target); + alloca_inst.setAlignment(alignment); return alloca_inst; } diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 5b6824f02a..29a46a81ee 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -137,6 +137,9 @@ pub const Value = opaque { pub const constIntToPtr = LLVMConstIntToPtr; extern fn LLVMConstIntToPtr(ConstantVal: *const Value, ToType: *const Type) *const Value; + pub const constPtrToInt = LLVMConstPtrToInt; + extern fn LLVMConstPtrToInt(ConstantVal: *const Value, ToType: *const Type) *const Value; + pub const setWeak = LLVMSetWeak; extern fn LLVMSetWeak(CmpXchgInst: *const Value, IsWeak: Bool) void; |
