authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-27 17:54:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-27 17:56:15-07:00
log3ba7098a173be4fef3b527605b89f90d39b86a4a
tree638f720edcd873d4e2d0a4735d20d70a9ec81082
parent6a4df2778e5f35fb112d87b12f94d4e3d06ee1d3

LLVM: fix returning extern union with C callconv


2 files changed, 45 insertions(+), 3 deletions(-)

src/codegen/llvm.zig+15-3
......@@ -4491,17 +4491,29 @@ pub const FuncGen = struct {
44914491 }
44924492 return null;
44934493 }
4494
44944495 const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);
4496 const ptr_abi_ty = abi_ret_ty.pointerType(0);
44954497 const operand = try self.resolveInst(un_op);
4498 const target = self.dg.module.getTarget();
4499 const alignment = ret_ty.abiAlignment(target);
4500
4501 if (isByRef(ret_ty)) {
4502 // operand is a pointer however self.ret_ptr is null so that means
4503 // we need to return a value.
4504 const casted_ptr = self.builder.buildBitCast(operand, ptr_abi_ty, "");
4505 const load_inst = self.builder.buildLoad(casted_ptr, "");
4506 load_inst.setAlignment(alignment);
4507 _ = self.builder.buildRet(load_inst);
4508 return null;
4509 }
4510
44964511 const llvm_ret_ty = operand.typeOf();
44974512 if (abi_ret_ty == llvm_ret_ty) {
44984513 _ = self.builder.buildRet(operand);
44994514 return null;
45004515 }
45014516
4502 const target = self.dg.module.getTarget();
4503 const alignment = ret_ty.abiAlignment(target);
4504 const ptr_abi_ty = abi_ret_ty.pointerType(0);
45054517 const rp = self.buildAlloca(llvm_ret_ty);
45064518 rp.setAlignment(alignment);
45074519 const store_inst = self.builder.buildStore(operand, rp);
test/behavior/union.zig+30
......@@ -1226,3 +1226,33 @@ test "extern union most-aligned field is smaller" {
12261226 var a: ?U = .{ .un = [_]u8{0} ** 110 };
12271227 try expect(a != null);
12281228}
1229
1230test "return an extern union from C calling convention" {
1231 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1232 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1234
1235 const namespace = struct {
1236 const S = extern struct {
1237 x: c_int,
1238 };
1239 const U = extern union {
1240 l: c_long,
1241 d: f64,
1242 s: S,
1243 };
1244
1245 fn bar(arg_u: U) callconv(.C) U {
1246 var u = arg_u;
1247 return u;
1248 }
1249 };
1250
1251 var u: namespace.U = namespace.U{
1252 .l = @as(c_long, 42),
1253 };
1254 u = namespace.bar(namespace.U{
1255 .d = 4.0,
1256 });
1257 try expect(u.d == 4.0);
1258}