authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-03-23 01:13:56-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
log92293214009cbf5d8aede56a5f54f533173324d5
treef23c26d18a65466c84ea3ee7cfad7e24a3eee4ae
parent5e010b6deac7ad34f0cd06d507fc468fd98f9abc

riscv: change up how we do args

- before we were storing each arg in it's own function arg register. with this commit now we store the args in the fa register before calling as per the RISC-V calling convention, however as soon as we enter the callee, aka in airArg, we spill the argument to the stack. this allows us to spend less effort worrying about whether we're going to clobber the function arguments when another function is called inside of the callee. - we were actually clobbering the fa regs inside of resolveCallingConvetion, because of the null argument to allocReg. now each lock is stored in an array which is then iterated over and unlocked, which actually aids in the first point of this commit.

1 files changed, 26 insertions(+), 5 deletions(-)

src/arch/riscv64/CodeGen.zig+26-5
......@@ -1858,6 +1858,7 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
18581858}
18591859
18601860fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1861 const mod = self.bin_file.comp.module.?;
18611862 var arg_index = self.arg_index;
18621863
18631864 // we skip over args that have no bits
......@@ -1867,10 +1868,21 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
18671868 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
18681869 const src_mcv = self.args[arg_index];
18691870
1871 // we want to move every arg onto the stack.
1872 // while it might no tbe the best solution right now, it simplifies
1873 // the spilling of args with multiple arg levels.
18701874 const dst_mcv = switch (src_mcv) {
18711875 .register => |src_reg| dst: {
1872 try self.register_manager.getReg(src_reg, inst);
1873 break :dst src_mcv;
1876 // TODO: get the true type of the arg, and fit the spill to size.
1877 const arg_size = Type.usize.abiSize(mod);
1878 const arg_align = Type.usize.abiAlignment(mod);
1879 const offset = try self.allocMem(inst, @intCast(arg_size), arg_align);
1880 try self.genSetStack(Type.usize, offset, .{ .register = src_reg });
1881
1882 // can go on to be reused in next function call
1883 self.register_manager.freeReg(src_reg);
1884
1885 break :dst .{ .stack_offset = offset };
18741886 },
18751887 else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),
18761888 };
......@@ -3258,17 +3270,26 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
32583270 return self.fail("TODO: support more than 8 function args", .{});
32593271 }
32603272
3273 const locks = try self.gpa.alloc(RegisterLock, result.args.len);
3274 defer self.gpa.free(locks);
3275
32613276 for (0..result.args.len) |i| {
32623277 const arg_reg = try self.register_manager.allocReg(null, fa);
3278 const lock = self.register_manager.lockRegAssumeUnused(arg_reg);
3279 locks[i] = lock;
32633280 result.args[i] = .{ .register = arg_reg };
32643281 }
32653282
3283 // we can just free the locks now, as this should be the only place where the fa
3284 // arg set is used.
3285 for (locks) |lock| {
3286 self.register_manager.unlockReg(lock);
3287 }
3288
32663289 // stack_offset = num s registers spilled + local var space
3267 var stack_offset: u32 = 0;
3268 _ = &stack_offset;
32693290 // TODO: spill used s registers here
32703291
3271 result.stack_byte_count = stack_offset;
3292 result.stack_byte_count = 0;
32723293 result.stack_align = .@"16";
32733294 },
32743295 else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}),