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 {...@@ -988,6 +988,25 @@ pub const Object = struct {
988 args.appendAssumeCapacity(load_inst);988 args.appendAssumeCapacity(load_inst);
989 }989 }
990 },990 },
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 },
991 .abi_sized_int => {1010 .abi_sized_int => {
992 assert(!it.byval_attr);1011 assert(!it.byval_attr);
993 const param_ty = fn_info.param_types[it.zig_index - 1];1012 const param_ty = fn_info.param_types[it.zig_index - 1];
...@@ -2583,6 +2602,9 @@ pub const DeclGen = struct {...@@ -2583,6 +2602,9 @@ pub const DeclGen = struct {
2583 const alignment = param_ty.abiAlignment(target);2602 const alignment = param_ty.abiAlignment(target);
2584 dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);2603 dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
2585 },2604 },
2605 .byref_mut => {
2606 dg.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");
2607 },
2586 // No attributes needed for these.2608 // No attributes needed for these.
2587 .no_bits,2609 .no_bits,
2588 .abi_sized_int,2610 .abi_sized_int,
...@@ -3101,7 +3123,7 @@ pub const DeclGen = struct {...@@ -3101,7 +3123,7 @@ pub const DeclGen = struct {
3101 const param_ty = fn_info.param_types[it.zig_index - 1];3123 const param_ty = fn_info.param_types[it.zig_index - 1];
3102 try llvm_params.append(try dg.lowerType(param_ty));3124 try llvm_params.append(try dg.lowerType(param_ty));
3103 },3125 },
3104 .byref => {3126 .byref, .byref_mut => {
3105 const param_ty = fn_info.param_types[it.zig_index - 1];3127 const param_ty = fn_info.param_types[it.zig_index - 1];
3106 const raw_llvm_ty = try dg.lowerType(param_ty);3128 const raw_llvm_ty = try dg.lowerType(param_ty);
3107 try llvm_params.append(raw_llvm_ty.pointerType(0));3129 try llvm_params.append(raw_llvm_ty.pointerType(0));
...@@ -4726,6 +4748,27 @@ pub const FuncGen = struct {...@@ -4726,6 +4748,27 @@ pub const FuncGen = struct {
4726 try llvm_args.append(arg_ptr);4748 try llvm_args.append(arg_ptr);
4727 }4749 }
4728 },4750 },
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 },
4729 .abi_sized_int => {4772 .abi_sized_int => {
4730 const arg = args[it.zig_index - 1];4773 const arg = args[it.zig_index - 1];
4731 const param_ty = self.air.typeOf(arg);4774 const param_ty = self.air.typeOf(arg);
...@@ -10384,6 +10427,7 @@ const ParamTypeIterator = struct {...@@ -10384,6 +10427,7 @@ const ParamTypeIterator = struct {
10384 no_bits,10427 no_bits,
10385 byval,10428 byval,
10386 byref,10429 byref,
10430 byref_mut,
10387 abi_sized_int,10431 abi_sized_int,
10388 multiple_llvm_types,10432 multiple_llvm_types,
10389 slice,10433 slice,
...@@ -10547,7 +10591,7 @@ const ParamTypeIterator = struct {...@@ -10547,7 +10591,7 @@ const ParamTypeIterator = struct {
10547 it.zig_index += 1;10591 it.zig_index += 1;
10548 it.llvm_index += 1;10592 it.llvm_index += 1;
10549 switch (aarch64_c_abi.classifyType(ty, it.target)) {10593 switch (aarch64_c_abi.classifyType(ty, it.target)) {
10550 .memory => return .byref,10594 .memory => return .byref_mut,
10551 .float_array => |len| return Lowering{ .float_array = len },10595 .float_array => |len| return Lowering{ .float_array = len },
10552 .byval => return .byval,10596 .byval => return .byval,
10553 .integer => {10597 .integer => {
...@@ -10578,9 +10622,7 @@ const ParamTypeIterator = struct {...@@ -10578,9 +10622,7 @@ const ParamTypeIterator = struct {
10578 return .as_u16;10622 return .as_u16;
10579 }10623 }
10580 switch (riscv_c_abi.classifyType(ty, it.target)) {10624 switch (riscv_c_abi.classifyType(ty, it.target)) {
10581 .memory => {10625 .memory => return .byref_mut,
10582 return .byref;
10583 },
10584 .byval => return .byval,10626 .byval => return .byval,
10585 .integer => return .abi_sized_int,10627 .integer => return .abi_sized_int,
10586 .double_integer => return Lowering{ .i64_array = 2 },10628 .double_integer => return Lowering{ .i64_array = 2 },
test/c_abi/cfuncs.c+9
...@@ -833,3 +833,12 @@ struct PD zig_ret_PD();...@@ -833,3 +833,12 @@ struct PD zig_ret_PD();
833int c_assert_ret_PD(){833int c_assert_ret_PD(){
834 return c_assert_PD(zig_ret_PD());834 return c_assert_PD(zig_ret_PD());
835}835}
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 {...@@ -988,3 +988,16 @@ pub export fn zig_assert_PD(lv: PD) c_int {
988 if (err != 0) std.debug.print("Received {}", .{lv});988 if (err != 0) std.debug.print("Received {}", .{lv});
989 return err;989 return err;
990}990}
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}