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

Closes  #13597
This commit is contained in:
Veikka Tuominen 2022-11-20 13:23:08 +02:00
parent 08a00f0d1c
commit 9e7293619f
3 changed files with 69 additions and 5 deletions

View File

@ -988,6 +988,25 @@ pub const Object = struct {
args.appendAssumeCapacity(load_inst);
}
},
.byref_mut => {
const param_ty = fn_info.param_types[it.zig_index - 1];
const param_llvm_ty = try dg.lowerType(param_ty);
const param = llvm_func.getParam(llvm_arg_i);
const alignment = param_ty.abiAlignment(target);
dg.addArgAttr(llvm_func, llvm_arg_i, "noundef");
llvm_arg_i += 1;
try args.ensureUnusedCapacity(1);
if (isByRef(param_ty)) {
args.appendAssumeCapacity(param);
} else {
const load_inst = builder.buildLoad(param_llvm_ty, param, "");
load_inst.setAlignment(alignment);
args.appendAssumeCapacity(load_inst);
}
},
.abi_sized_int => {
assert(!it.byval_attr);
const param_ty = fn_info.param_types[it.zig_index - 1];
@ -2583,6 +2602,9 @@ pub const DeclGen = struct {
const alignment = param_ty.abiAlignment(target);
dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
},
.byref_mut => {
dg.addArgAttr(llvm_fn, it.llvm_index - 1, "noundef");
},
// No attributes needed for these.
.no_bits,
.abi_sized_int,
@ -3101,7 +3123,7 @@ pub const DeclGen = struct {
const param_ty = fn_info.param_types[it.zig_index - 1];
try llvm_params.append(try dg.lowerType(param_ty));
},
.byref => {
.byref, .byref_mut => {
const param_ty = fn_info.param_types[it.zig_index - 1];
const raw_llvm_ty = try dg.lowerType(param_ty);
try llvm_params.append(raw_llvm_ty.pointerType(0));
@ -4726,6 +4748,27 @@ pub const FuncGen = struct {
try llvm_args.append(arg_ptr);
}
},
.byref_mut => {
const arg = args[it.zig_index - 1];
const param_ty = self.air.typeOf(arg);
const llvm_arg = try self.resolveInst(arg);
const alignment = param_ty.abiAlignment(target);
const param_llvm_ty = try self.dg.lowerType(param_ty);
const arg_ptr = self.buildAlloca(param_llvm_ty, alignment);
if (isByRef(param_ty)) {
const load_inst = self.builder.buildLoad(param_llvm_ty, llvm_arg, "");
load_inst.setAlignment(alignment);
const store_inst = self.builder.buildStore(load_inst, arg_ptr);
store_inst.setAlignment(alignment);
try llvm_args.append(arg_ptr);
} else {
const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
store_inst.setAlignment(alignment);
try llvm_args.append(arg_ptr);
}
},
.abi_sized_int => {
const arg = args[it.zig_index - 1];
const param_ty = self.air.typeOf(arg);
@ -10384,6 +10427,7 @@ const ParamTypeIterator = struct {
no_bits,
byval,
byref,
byref_mut,
abi_sized_int,
multiple_llvm_types,
slice,
@ -10547,7 +10591,7 @@ const ParamTypeIterator = struct {
it.zig_index += 1;
it.llvm_index += 1;
switch (aarch64_c_abi.classifyType(ty, it.target)) {
.memory => return .byref,
.memory => return .byref_mut,
.float_array => |len| return Lowering{ .float_array = len },
.byval => return .byval,
.integer => {
@ -10578,9 +10622,7 @@ const ParamTypeIterator = struct {
return .as_u16;
}
switch (riscv_c_abi.classifyType(ty, it.target)) {
.memory => {
return .byref;
},
.memory => return .byref_mut,
.byval => return .byval,
.integer => return .abi_sized_int,
.double_integer => return Lowering{ .i64_array = 2 },

View File

@ -833,3 +833,12 @@ struct PD zig_ret_PD();
int c_assert_ret_PD(){
return c_assert_PD(zig_ret_PD());
}
struct ByRef {
int val;
int arr[15];
};
struct ByRef c_modify_by_ref_param(struct ByRef in) {
in.val = 42;
return in;
}

View File

@ -988,3 +988,16 @@ pub export fn zig_assert_PD(lv: PD) c_int {
if (err != 0) std.debug.print("Received {}", .{lv});
return err;
}
const ByRef = extern struct {
val: c_int,
arr: [15]c_int,
};
extern fn c_modify_by_ref_param(ByRef) ByRef;
test "C function modifies by ref param" {
if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined });
try expect(res.val == 42);
}