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 {...@@ -1858,6 +1858,7 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
1858}1858}
18591859
1860fn airArg(self: *Self, inst: Air.Inst.Index) !void {1860fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1861 const mod = self.bin_file.comp.module.?;
1861 var arg_index = self.arg_index;1862 var arg_index = self.arg_index;
18621863
1863 // we skip over args that have no bits1864 // we skip over args that have no bits
...@@ -1867,10 +1868,21 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -1867,10 +1868,21 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1867 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {1868 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1868 const src_mcv = self.args[arg_index];1869 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.
1870 const dst_mcv = switch (src_mcv) {1874 const dst_mcv = switch (src_mcv) {
1871 .register => |src_reg| dst: {1875 .register => |src_reg| dst: {
1872 try self.register_manager.getReg(src_reg, inst);1876 // TODO: get the true type of the arg, and fit the spill to size.
1873 break :dst src_mcv;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 };
1874 },1886 },
1875 else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),1887 else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),
1876 };1888 };
...@@ -3258,17 +3270,26 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -3258,17 +3270,26 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
3258 return self.fail("TODO: support more than 8 function args", .{});3270 return self.fail("TODO: support more than 8 function args", .{});
3259 }3271 }
32603272
3273 const locks = try self.gpa.alloc(RegisterLock, result.args.len);
3274 defer self.gpa.free(locks);
3275
3261 for (0..result.args.len) |i| {3276 for (0..result.args.len) |i| {
3262 const arg_reg = try self.register_manager.allocReg(null, fa);3277 const arg_reg = try self.register_manager.allocReg(null, fa);
3278 const lock = self.register_manager.lockRegAssumeUnused(arg_reg);
3279 locks[i] = lock;
3263 result.args[i] = .{ .register = arg_reg };3280 result.args[i] = .{ .register = arg_reg };
3264 }3281 }
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
3266 // stack_offset = num s registers spilled + local var space3289 // stack_offset = num s registers spilled + local var space
3267 var stack_offset: u32 = 0;
3268 _ = &stack_offset;
3269 // TODO: spill used s registers here3290 // TODO: spill used s registers here
32703291
3271 result.stack_byte_count = stack_offset;3292 result.stack_byte_count = 0;
3272 result.stack_align = .@"16";3293 result.stack_align = .@"16";
3273 },3294 },
3274 else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}),3295 else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}),