authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-20 13:23:08+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-20 20:25:12+02:00
log9e7293619ffb26049af2248226a3d75ef274bfb0
tree865c0b264c054feb79e363ba6ab8468075554938
parent08a00f0d1ce477c2c57072b9b0e27eb36a73092a

llvm: aarch64 C ABI: pass byref params as mutable pointers

Closes #13597

3 files changed, 69 insertions(+), 5 deletions(-)

src/codegen/llvm.zig+47-5
......@@ -988,6 +988,25 @@ pub const Object = struct {
988988 args.appendAssumeCapacity(load_inst);
989989 }
990990 },
991 .byref_mut => {
992 const param_ty = fn_info.param_types[it.zig_index - 1];
993 const param_llvm_ty = try dg.lowerType(param_ty);
994 const param = llvm_func.getParam(llvm_arg_i);
995 const alignment = param_ty.abiAlignment(target);
996
997 dg.addArgAttr(llvm_func, llvm_arg_i, "noundef");
998 llvm_arg_i += 1;
999
1000 try args.ensureUnusedCapacity(1);
1001
1002 if (isByRef(param_ty)) {
1003 args.appendAssumeCapacity(param);
1004 } else {
1005 const load_inst = builder.buildLoad(param_llvm_ty, param, "");
1006 load_inst.setAlignment(alignment);
1007 args.appendAssumeCapacity(load_inst);
1008 }
1009 },
9911010 .abi_sized_int => {
9921011 assert(!it.byval_attr);
9931012 const param_ty = fn_info.param_types[it.zig_index - 1];
......@@ -2583,6 +2602,9 @@ pub const DeclGen = struct {
25832602 const alignment = param_ty.abiAlignment(target);
25842603 dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
25852604 },
2605 .byref_mut => {
2606 dg.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");
2607 },
25862608 // No attributes needed for these.
25872609 .no_bits,
25882610 .abi_sized_int,
......@@ -3101,7 +3123,7 @@ pub const DeclGen = struct {
31013123 const param_ty = fn_info.param_types[it.zig_index - 1];
31023124 try llvm_params.append(try dg.lowerType(param_ty));
31033125 },
3104 .byref => {
3126 .byref, .byref_mut => {
31053127 const param_ty = fn_info.param_types[it.zig_index - 1];
31063128 const raw_llvm_ty = try dg.lowerType(param_ty);
31073129 try llvm_params.append(raw_llvm_ty.pointerType(0));
......@@ -4726,6 +4748,27 @@ pub const FuncGen = struct {
47264748 try llvm_args.append(arg_ptr);
47274749 }
47284750 },
4751 .byref_mut => {
4752 const arg = args[it.zig_index - 1];
4753 const param_ty = self.air.typeOf(arg);
4754 const llvm_arg = try self.resolveInst(arg);
4755
4756 const alignment = param_ty.abiAlignment(target);
4757 const param_llvm_ty = try self.dg.lowerType(param_ty);
4758 const arg_ptr = self.buildAlloca(param_llvm_ty, alignment);
4759 if (isByRef(param_ty)) {
4760 const load_inst = self.builder.buildLoad(param_llvm_ty, llvm_arg, "");
4761 load_inst.setAlignment(alignment);
4762
4763 const store_inst = self.builder.buildStore(load_inst, arg_ptr);
4764 store_inst.setAlignment(alignment);
4765 try llvm_args.append(arg_ptr);
4766 } else {
4767 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
4768 store_inst.setAlignment(alignment);
4769 try llvm_args.append(arg_ptr);
4770 }
4771 },
47294772 .abi_sized_int => {
47304773 const arg = args[it.zig_index - 1];
47314774 const param_ty = self.air.typeOf(arg);
......@@ -10384,6 +10427,7 @@ const ParamTypeIterator = struct {
1038410427 no_bits,
1038510428 byval,
1038610429 byref,
10430 byref_mut,
1038710431 abi_sized_int,
1038810432 multiple_llvm_types,
1038910433 slice,
......@@ -10547,7 +10591,7 @@ const ParamTypeIterator = struct {
1054710591 it.zig_index += 1;
1054810592 it.llvm_index += 1;
1054910593 switch (aarch64_c_abi.classifyType(ty, it.target)) {
10550 .memory => return .byref,
10594 .memory => return .byref_mut,
1055110595 .float_array => |len| return Lowering{ .float_array = len },
1055210596 .byval => return .byval,
1055310597 .integer => {
......@@ -10578,9 +10622,7 @@ const ParamTypeIterator = struct {
1057810622 return .as_u16;
1057910623 }
1058010624 switch (riscv_c_abi.classifyType(ty, it.target)) {
10581 .memory => {
10582 return .byref;
10583 },
10625 .memory => return .byref_mut,
1058410626 .byval => return .byval,
1058510627 .integer => return .abi_sized_int,
1058610628 .double_integer => return Lowering{ .i64_array = 2 },
test/c_abi/cfuncs.c+9
......@@ -833,3 +833,12 @@ struct PD zig_ret_PD();
833833int c_assert_ret_PD(){
834834 return c_assert_PD(zig_ret_PD());
835835}
836
837struct ByRef {
838 int val;
839 int arr[15];
840};
841struct ByRef c_modify_by_ref_param(struct ByRef in) {
842 in.val = 42;
843 return in;
844}
test/c_abi/main.zig+13
......@@ -988,3 +988,16 @@ pub export fn zig_assert_PD(lv: PD) c_int {
988988 if (err != 0) std.debug.print("Received {}", .{lv});
989989 return err;
990990}
991
992const ByRef = extern struct {
993 val: c_int,
994 arr: [15]c_int,
995};
996extern fn c_modify_by_ref_param(ByRef) ByRef;
997
998test "C function modifies by ref param" {
999 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
1000
1001 const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined });
1002 try expect(res.val == 42);
1003}