authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-04-06 21:14:00+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-04-06 21:14:00+02:00
logac2211118fe9030aa8a524549c9bb7caf8795f4d
tree32701a0735237638341180c720fd65da6376b1b6
parent2bfc6d14d500dcaf66b8ee7d24637e25e3795a5e
signaturelock-open Commit is signed but in an unrecognized format.

stage2 regalloc: Add getReg and getRegWithoutTracking


2 files changed, 77 insertions(+), 12 deletions(-)

src/codegen.zig+24-12
......@@ -1783,8 +1783,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
17831783 switch (mc_arg) {
17841784 .none => continue,
17851785 .register => |reg| {
1786 try self.register_manager.getRegWithoutTracking(reg);
17861787 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1787 // TODO interact with the register allocator to mark the instruction as moved.
17881788 },
17891789 .stack_offset => {
17901790 // Here we need to emit instructions like this:
......@@ -1925,8 +1925,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19251925 .compare_flags_signed => unreachable,
19261926 .compare_flags_unsigned => unreachable,
19271927 .register => |reg| {
1928 try self.register_manager.getRegWithoutTracking(reg);
19281929 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1929 // TODO interact with the register allocator to mark the instruction as moved.
19301930 },
19311931 .stack_offset => {
19321932 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 {
19881988 .compare_flags_signed => unreachable,
19891989 .compare_flags_unsigned => unreachable,
19901990 .register => |reg| {
1991 try self.register_manager.getRegWithoutTracking(reg);
19911992 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1992 // TODO interact with the register allocator to mark the instruction as moved.
19931993 },
19941994 .stack_offset => {
19951995 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 {
20392039 switch (mc_arg) {
20402040 .none => continue,
20412041 .register => |reg| {
2042 try self.register_manager.getRegWithoutTracking(reg);
20422043 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2043 // TODO interact with the register allocator to mark the instruction as moved.
20442044 },
20452045 .stack_offset => {
20462046 // Here we need to emit instructions like this:
......@@ -2704,8 +2704,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27042704 const reg_name = input[1 .. input.len - 1];
27052705 const reg = parseRegName(reg_name) orelse
27062706 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2707 const arg = try self.resolveInst(inst.args[i]);
2708 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2707
2708 const arg = inst.args[i];
2709 const arg_mcv = try self.resolveInst(arg);
2710 try self.register_manager.getRegWithoutTracking(reg);
2711 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
27092712 }
27102713
27112714 if (mem.eql(u8, inst.asm_source, "svc #0")) {
......@@ -2734,8 +2737,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27342737 const reg_name = input[1 .. input.len - 1];
27352738 const reg = parseRegName(reg_name) orelse
27362739 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2737 const arg = try self.resolveInst(inst.args[i]);
2738 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2740
2741 const arg = inst.args[i];
2742 const arg_mcv = try self.resolveInst(arg);
2743 try self.register_manager.getRegWithoutTracking(reg);
2744 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
27392745 }
27402746
27412747 if (mem.eql(u8, inst.asm_source, "svc #0")) {
......@@ -2766,8 +2772,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27662772 const reg_name = input[1 .. input.len - 1];
27672773 const reg = parseRegName(reg_name) orelse
27682774 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2769 const arg = try self.resolveInst(inst.args[i]);
2770 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2775
2776 const arg = inst.args[i];
2777 const arg_mcv = try self.resolveInst(arg);
2778 try self.register_manager.getRegWithoutTracking(reg);
2779 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
27712780 }
27722781
27732782 if (mem.eql(u8, inst.asm_source, "ecall")) {
......@@ -2796,8 +2805,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27962805 const reg_name = input[1 .. input.len - 1];
27972806 const reg = parseRegName(reg_name) orelse
27982807 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2799 const arg = try self.resolveInst(inst.args[i]);
2800 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2808
2809 const arg = inst.args[i];
2810 const arg_mcv = try self.resolveInst(arg);
2811 try self.register_manager.getRegWithoutTracking(reg);
2812 try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
28012813 }
28022814
28032815 if (mem.eql(u8, inst.asm_source, "syscall")) {
src/register_manager.zig+53
......@@ -35,6 +35,10 @@ pub fn RegisterManager(
3535 self.registers.deinit(allocator);
3636 }
3737
38 fn isTracked(reg: Register) bool {
39 return std.mem.indexOfScalar(Register, callee_preserved_regs, reg) != null;
40 }
41
3842 fn markRegUsed(self: *Self, reg: Register) void {
3943 if (FreeRegInt == u0) return;
4044 const index = reg.allocIndex() orelse return;
......@@ -51,6 +55,13 @@ pub fn RegisterManager(
5155 self.free_registers |= @as(FreeRegInt, 1) << shift;
5256 }
5357
58 pub fn isRegFree(self: Self, reg: Register) bool {
59 if (FreeRegInt == u0) return true;
60 const index = reg.allocIndex() orelse return true;
61 const shift = @intCast(ShiftInt, index);
62 return self.free_registers & @as(FreeRegInt, 1) << shift != 0;
63 }
64
5465 /// Returns whether this register was allocated in the course
5566 /// of this function
5667 pub fn isRegAllocated(self: Self, reg: Register) bool {
......@@ -117,17 +128,59 @@ pub fn RegisterManager(
117128 const regs_entry = self.registers.remove(reg).?;
118129 const spilled_inst = regs_entry.value;
119130 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
131 self.markRegFree(reg);
120132
121133 break :b reg;
122134 };
123135 }
124136
137 /// Allocates the specified register with the specified
138 /// instruction. Spills the register if it is currently
139 /// allocated.
140 pub fn getReg(self: *Self, reg: Register, inst: *ir.Inst) !void {
141 if (!isTracked(reg)) return;
142
143 if (!self.isRegFree(reg)) {
144 // Move the instruction that was previously there to a
145 // stack allocation.
146 const regs_entry = self.registers.getEntry(reg).?;
147 const spilled_inst = regs_entry.value;
148 regs_entry.value = inst;
149 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
150 } else {
151 try self.getRegAssumeFree(reg, inst);
152 }
153 }
154
155 /// Spills the register if it is currently allocated.
156 /// Does not track the register.
157 pub fn getRegWithoutTracking(self: *Self, reg: Register) !void {
158 if (!isTracked(reg)) return;
159
160 if (!self.isRegFree(reg)) {
161 // Move the instruction that was previously there to a
162 // stack allocation.
163 const regs_entry = self.registers.getEntry(reg).?;
164 const spilled_inst = regs_entry.value;
165 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
166 self.markRegFree(reg);
167 }
168 }
169
170 /// Allocates the specified register with the specified
171 /// instruction. Assumes that the register is free and no
172 /// spilling is necessary.
125173 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) !void {
174 if (!isTracked(reg)) return;
175
126176 try self.registers.putNoClobber(self.getFunction().gpa, reg, inst);
127177 self.markRegUsed(reg);
128178 }
129179
180 /// Marks the specified register as free
130181 pub fn freeReg(self: *Self, reg: Register) void {
182 if (!isTracked(reg)) return;
183
131184 _ = self.registers.remove(reg);
132185 self.markRegFree(reg);
133186 }