From ac2211118fe9030aa8a524549c9bb7caf8795f4d Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Tue, 6 Apr 2021 21:14:00 +0200 Subject: stage2 regalloc: Add getReg and getRegWithoutTracking --- src/codegen.zig | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'src/codegen.zig') diff --git a/src/codegen.zig b/src/codegen.zig index fbd412ceba..cacf51730a 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1783,8 +1783,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { switch (mc_arg) { .none => continue, .register => |reg| { + try self.register_manager.getRegWithoutTracking(reg); try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); - // TODO interact with the register allocator to mark the instruction as moved. }, .stack_offset => { // Here we need to emit instructions like this: @@ -1925,8 +1925,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .compare_flags_signed => unreachable, .compare_flags_unsigned => unreachable, .register => |reg| { + try self.register_manager.getRegWithoutTracking(reg); try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); - // TODO interact with the register allocator to mark the instruction as moved. }, .stack_offset => { return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{}); @@ -1988,8 +1988,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .compare_flags_signed => unreachable, .compare_flags_unsigned => unreachable, .register => |reg| { + try self.register_manager.getRegWithoutTracking(reg); try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); - // TODO interact with the register allocator to mark the instruction as moved. }, .stack_offset => { return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{}); @@ -2039,8 +2039,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { switch (mc_arg) { .none => continue, .register => |reg| { + try self.register_manager.getRegWithoutTracking(reg); try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); - // TODO interact with the register allocator to mark the instruction as moved. }, .stack_offset => { // Here we need to emit instructions like this: @@ -2704,8 +2704,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const reg_name = input[1 .. input.len - 1]; const reg = parseRegName(reg_name) orelse return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); - const arg = try self.resolveInst(inst.args[i]); - try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg); + + const arg = inst.args[i]; + const arg_mcv = try self.resolveInst(arg); + try self.register_manager.getRegWithoutTracking(reg); + try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv); } if (mem.eql(u8, inst.asm_source, "svc #0")) { @@ -2734,8 +2737,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const reg_name = input[1 .. input.len - 1]; const reg = parseRegName(reg_name) orelse return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); - const arg = try self.resolveInst(inst.args[i]); - try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg); + + const arg = inst.args[i]; + const arg_mcv = try self.resolveInst(arg); + try self.register_manager.getRegWithoutTracking(reg); + try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv); } if (mem.eql(u8, inst.asm_source, "svc #0")) { @@ -2766,8 +2772,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const reg_name = input[1 .. input.len - 1]; const reg = parseRegName(reg_name) orelse return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); - const arg = try self.resolveInst(inst.args[i]); - try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg); + + const arg = inst.args[i]; + const arg_mcv = try self.resolveInst(arg); + try self.register_manager.getRegWithoutTracking(reg); + try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv); } if (mem.eql(u8, inst.asm_source, "ecall")) { @@ -2796,8 +2805,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const reg_name = input[1 .. input.len - 1]; const reg = parseRegName(reg_name) orelse return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name}); - const arg = try self.resolveInst(inst.args[i]); - try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg); + + const arg = inst.args[i]; + const arg_mcv = try self.resolveInst(arg); + try self.register_manager.getRegWithoutTracking(reg); + try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv); } if (mem.eql(u8, inst.asm_source, "syscall")) { -- cgit v1.2.3 From 4ff5a3cd94b0532f2cd713082948b00a8a36336f Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Wed, 7 Apr 2021 15:15:14 +0200 Subject: stage2 regalloc: Add unit test for getReg --- src/codegen.zig | 3 ++- src/register_manager.zig | 42 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 5 deletions(-) (limited to 'src/codegen.zig') diff --git a/src/codegen.zig b/src/codegen.zig index cacf51730a..220a8fa374 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1735,7 +1735,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { switch (result) { .register => |reg| { - try self.register_manager.getRegAssumeFree(toCanonicalReg(reg), &inst.base); + try self.register_manager.registers.ensureCapacity(self.gpa, self.register_manager.registers.count() + 1); + self.register_manager.getRegAssumeFree(toCanonicalReg(reg), &inst.base); }, else => {}, } diff --git a/src/register_manager.zig b/src/register_manager.zig index 356251eed8..e11f2c3111 100644 --- a/src/register_manager.zig +++ b/src/register_manager.zig @@ -137,6 +137,7 @@ pub fn RegisterManager( /// Allocates the specified register with the specified /// instruction. Spills the register if it is currently /// allocated. + /// Before calling, must ensureCapacity + 1 on self.registers. pub fn getReg(self: *Self, reg: Register, inst: *ir.Inst) !void { if (!isTracked(reg)) return; @@ -148,7 +149,7 @@ pub fn RegisterManager( regs_entry.value = inst; try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); } else { - try self.getRegAssumeFree(reg, inst); + self.getRegAssumeFree(reg, inst); } } @@ -160,7 +161,7 @@ pub fn RegisterManager( if (!self.isRegFree(reg)) { // Move the instruction that was previously there to a // stack allocation. - const regs_entry = self.registers.getEntry(reg).?; + const regs_entry = self.registers.remove(reg).?; const spilled_inst = regs_entry.value; try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); self.markRegFree(reg); @@ -170,10 +171,11 @@ pub fn RegisterManager( /// Allocates the specified register with the specified /// instruction. Assumes that the register is free and no /// spilling is necessary. - pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) !void { + /// Before calling, must ensureCapacity + 1 on self.registers. + pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) void { if (!isTracked(reg)) return; - try self.registers.putNoClobber(self.getFunction().gpa, reg, inst); + self.registers.putAssumeCapacityNoClobber(reg, inst); self.markRegUsed(reg); } @@ -279,3 +281,35 @@ test "allocReg: spilling" { std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction)); std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items); } + +test "getReg" { + const allocator = std.testing.allocator; + + var function = MockFunction{ + .allocator = allocator, + }; + defer function.deinit(); + + var mock_instruction = ir.Inst{ + .tag = .breakpoint, + .ty = Type.initTag(.void), + .src = .unneeded, + }; + + std.testing.expect(!function.register_manager.isRegAllocated(.r2)); + std.testing.expect(!function.register_manager.isRegAllocated(.r3)); + + try function.register_manager.registers.ensureCapacity(allocator, function.register_manager.registers.count() + 2); + try function.register_manager.getReg(.r3, &mock_instruction); + + std.testing.expect(!function.register_manager.isRegAllocated(.r2)); + std.testing.expect(function.register_manager.isRegAllocated(.r3)); + + // Spill r3 + try function.register_manager.registers.ensureCapacity(allocator, function.register_manager.registers.count() + 2); + try function.register_manager.getReg(.r3, &mock_instruction); + + std.testing.expect(!function.register_manager.isRegAllocated(.r2)); + std.testing.expect(function.register_manager.isRegAllocated(.r3)); + std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r3}, function.spilled.items); +} -- cgit v1.2.3