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 {...@@ -1783,8 +1783,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1783 switch (mc_arg) {1783 switch (mc_arg) {
1784 .none => continue,1784 .none => continue,
1785 .register => |reg| {1785 .register => |reg| {
1786 try self.register_manager.getRegWithoutTracking(reg);
1786 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);1787 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1787 // TODO interact with the register allocator to mark the instruction as moved.
1788 },1788 },
1789 .stack_offset => {1789 .stack_offset => {
1790 // Here we need to emit instructions like this:1790 // Here we need to emit instructions like this:
...@@ -1925,8 +1925,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1925,8 +1925,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1925 .compare_flags_signed => unreachable,1925 .compare_flags_signed => unreachable,
1926 .compare_flags_unsigned => unreachable,1926 .compare_flags_unsigned => unreachable,
1927 .register => |reg| {1927 .register => |reg| {
1928 try self.register_manager.getRegWithoutTracking(reg);
1928 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);1929 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1929 // TODO interact with the register allocator to mark the instruction as moved.
1930 },1930 },
1931 .stack_offset => {1931 .stack_offset => {
1932 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});1932 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 {...@@ -1988,8 +1988,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1988 .compare_flags_signed => unreachable,1988 .compare_flags_signed => unreachable,
1989 .compare_flags_unsigned => unreachable,1989 .compare_flags_unsigned => unreachable,
1990 .register => |reg| {1990 .register => |reg| {
1991 try self.register_manager.getRegWithoutTracking(reg);
1991 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);1992 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1992 // TODO interact with the register allocator to mark the instruction as moved.
1993 },1993 },
1994 .stack_offset => {1994 .stack_offset => {
1995 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});1995 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 {...@@ -2039,8 +2039,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2039 switch (mc_arg) {2039 switch (mc_arg) {
2040 .none => continue,2040 .none => continue,
2041 .register => |reg| {2041 .register => |reg| {
2042 try self.register_manager.getRegWithoutTracking(reg);
2042 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);2043 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2043 // TODO interact with the register allocator to mark the instruction as moved.
2044 },2044 },
2045 .stack_offset => {2045 .stack_offset => {
2046 // Here we need to emit instructions like this:2046 // Here we need to emit instructions like this:
...@@ -2704,8 +2704,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2704,8 +2704,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2704 const reg_name = input[1 .. input.len - 1];2704 const reg_name = input[1 .. input.len - 1];
2705 const reg = parseRegName(reg_name) orelse2705 const reg = parseRegName(reg_name) orelse
2706 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2706 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2707 const arg = try self.resolveInst(inst.args[i]);2707
2708 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);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);
2709 }2712 }
27102713
2711 if (mem.eql(u8, inst.asm_source, "svc #0")) {2714 if (mem.eql(u8, inst.asm_source, "svc #0")) {
...@@ -2734,8 +2737,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2734,8 +2737,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2734 const reg_name = input[1 .. input.len - 1];2737 const reg_name = input[1 .. input.len - 1];
2735 const reg = parseRegName(reg_name) orelse2738 const reg = parseRegName(reg_name) orelse
2736 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2739 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2737 const arg = try self.resolveInst(inst.args[i]);2740
2738 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);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);
2739 }2745 }
27402746
2741 if (mem.eql(u8, inst.asm_source, "svc #0")) {2747 if (mem.eql(u8, inst.asm_source, "svc #0")) {
...@@ -2766,8 +2772,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2766,8 +2772,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2766 const reg_name = input[1 .. input.len - 1];2772 const reg_name = input[1 .. input.len - 1];
2767 const reg = parseRegName(reg_name) orelse2773 const reg = parseRegName(reg_name) orelse
2768 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2774 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2769 const arg = try self.resolveInst(inst.args[i]);2775
2770 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);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);
2771 }2780 }
27722781
2773 if (mem.eql(u8, inst.asm_source, "ecall")) {2782 if (mem.eql(u8, inst.asm_source, "ecall")) {
...@@ -2796,8 +2805,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2796,8 +2805,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2796 const reg_name = input[1 .. input.len - 1];2805 const reg_name = input[1 .. input.len - 1];
2797 const reg = parseRegName(reg_name) orelse2806 const reg = parseRegName(reg_name) orelse
2798 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2807 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2799 const arg = try self.resolveInst(inst.args[i]);2808
2800 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);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);
2801 }2813 }
28022814
2803 if (mem.eql(u8, inst.asm_source, "syscall")) {2815 if (mem.eql(u8, inst.asm_source, "syscall")) {
src/register_manager.zig+53
...@@ -35,6 +35,10 @@ pub fn RegisterManager(...@@ -35,6 +35,10 @@ pub fn RegisterManager(
35 self.registers.deinit(allocator);35 self.registers.deinit(allocator);
36 }36 }
3737
38 fn isTracked(reg: Register) bool {
39 return std.mem.indexOfScalar(Register, callee_preserved_regs, reg) != null;
40 }
41
38 fn markRegUsed(self: *Self, reg: Register) void {42 fn markRegUsed(self: *Self, reg: Register) void {
39 if (FreeRegInt == u0) return;43 if (FreeRegInt == u0) return;
40 const index = reg.allocIndex() orelse return;44 const index = reg.allocIndex() orelse return;
...@@ -51,6 +55,13 @@ pub fn RegisterManager(...@@ -51,6 +55,13 @@ pub fn RegisterManager(
51 self.free_registers |= @as(FreeRegInt, 1) << shift;55 self.free_registers |= @as(FreeRegInt, 1) << shift;
52 }56 }
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
54 /// Returns whether this register was allocated in the course65 /// Returns whether this register was allocated in the course
55 /// of this function66 /// of this function
56 pub fn isRegAllocated(self: Self, reg: Register) bool {67 pub fn isRegAllocated(self: Self, reg: Register) bool {
...@@ -117,17 +128,59 @@ pub fn RegisterManager(...@@ -117,17 +128,59 @@ pub fn RegisterManager(
117 const regs_entry = self.registers.remove(reg).?;128 const regs_entry = self.registers.remove(reg).?;
118 const spilled_inst = regs_entry.value;129 const spilled_inst = regs_entry.value;
119 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);130 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
131 self.markRegFree(reg);
120132
121 break :b reg;133 break :b reg;
122 };134 };
123 }135 }
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.
125 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) !void {173 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) !void {
174 if (!isTracked(reg)) return;
175
126 try self.registers.putNoClobber(self.getFunction().gpa, reg, inst);176 try self.registers.putNoClobber(self.getFunction().gpa, reg, inst);
127 self.markRegUsed(reg);177 self.markRegUsed(reg);
128 }178 }
129179
180 /// Marks the specified register as free
130 pub fn freeReg(self: *Self, reg: Register) void {181 pub fn freeReg(self: *Self, reg: Register) void {
182 if (!isTracked(reg)) return;
183
131 _ = self.registers.remove(reg);184 _ = self.registers.remove(reg);
132 self.markRegFree(reg);185 self.markRegFree(reg);
133 }186 }