From f880af369d4814df7cd1ec0ef5f85343108bbe81 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 27 Jul 2022 13:22:33 -0700 Subject: LLVM: fix lowering byte-aligned packed struct field pointers --- src/codegen/llvm.zig | 18 ++++++++++++++++++ src/codegen/llvm/bindings.zig | 3 +++ 2 files changed, 21 insertions(+) (limited to 'src/codegen') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index e7915e08b3..6ebe76fb39 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3646,6 +3646,24 @@ pub const DeclGen = struct { }, .Struct => { const field_ty = parent_ty.structFieldType(field_index); + if (parent_ty.containerLayout() == .Packed) { + const llvm_usize = dg.context.intType(target.cpu.arch.ptrBitWidth()); + const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); + // count bits of fields before this one + const prev_bits = b: { + var b: usize = 0; + for (parent_ty.structFields().values()[0..field_index]) |field| { + if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; + b += field.ty.bitSize(target); + } + break :b b; + }; + const byte_offset = llvm_usize.constInt((prev_bits + 7) / 8, .False); + const field_addr = base_addr.constAdd(byte_offset); + bitcast_needed = false; + const final_llvm_ty = (try dg.lowerType(ptr_child_ty)).pointerType(0); + break :blk field_addr.constIntToPtr(final_llvm_ty); + } bitcast_needed = !field_ty.eql(ptr_child_ty, dg.module); var ty_buf: Type.Payload.Pointer = undefined; diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 07408f12b9..e4357b8060 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -169,6 +169,9 @@ pub const Value = opaque { pub const constNot = LLVMConstNot; extern fn LLVMConstNot(ConstantVal: *const Value) *const Value; + pub const constAdd = LLVMConstAdd; + extern fn LLVMConstAdd(LHSConstant: *const Value, RHSConstant: *const Value) *const Value; + pub const setWeak = LLVMSetWeak; extern fn LLVMSetWeak(CmpXchgInst: *const Value, IsWeak: Bool) void; -- cgit v1.2.3 From 3ba7098a173be4fef3b527605b89f90d39b86a4a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 27 Jul 2022 17:54:38 -0700 Subject: LLVM: fix returning extern union with C callconv --- src/codegen/llvm.zig | 18 +++++++++++++++--- test/behavior/union.zig | 30 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 6ebe76fb39..6a2e346113 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4491,17 +4491,29 @@ pub const FuncGen = struct { } return null; } + const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info); + const ptr_abi_ty = abi_ret_ty.pointerType(0); const operand = try self.resolveInst(un_op); + const target = self.dg.module.getTarget(); + const alignment = ret_ty.abiAlignment(target); + + if (isByRef(ret_ty)) { + // operand is a pointer however self.ret_ptr is null so that means + // we need to return a value. + const casted_ptr = self.builder.buildBitCast(operand, ptr_abi_ty, ""); + const load_inst = self.builder.buildLoad(casted_ptr, ""); + load_inst.setAlignment(alignment); + _ = self.builder.buildRet(load_inst); + return null; + } + const llvm_ret_ty = operand.typeOf(); if (abi_ret_ty == llvm_ret_ty) { _ = self.builder.buildRet(operand); return null; } - const target = self.dg.module.getTarget(); - const alignment = ret_ty.abiAlignment(target); - const ptr_abi_ty = abi_ret_ty.pointerType(0); const rp = self.buildAlloca(llvm_ret_ty); rp.setAlignment(alignment); const store_inst = self.builder.buildStore(operand, rp); diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 8e4b262565..2f6fa78f0c 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1226,3 +1226,33 @@ test "extern union most-aligned field is smaller" { var a: ?U = .{ .un = [_]u8{0} ** 110 }; try expect(a != null); } + +test "return an extern union from C calling convention" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const namespace = struct { + const S = extern struct { + x: c_int, + }; + const U = extern union { + l: c_long, + d: f64, + s: S, + }; + + fn bar(arg_u: U) callconv(.C) U { + var u = arg_u; + return u; + } + }; + + var u: namespace.U = namespace.U{ + .l = @as(c_long, 42), + }; + u = namespace.bar(namespace.U{ + .d = 4.0, + }); + try expect(u.d == 4.0); +} -- cgit v1.2.3