authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-01-28 20:40:36+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-28 18:03:03-05:00
log1a324a8ad603853728e3a052ec82756c9128cb0c
treea2f77316e1c3d799ef95839299be944eed7c5713
parentd7deffee8d1861720ba4f9d3cb6a7f6dfb7ccb33

stage2 regalloc: Fix bug where regs were not marked as allocated


1 files changed, 44 insertions(+), 14 deletions(-)

src/register_manager.zig+44-14
...@@ -17,6 +17,10 @@ pub fn RegisterManager(...@@ -17,6 +17,10 @@ pub fn RegisterManager(
17 comptime Register: type,17 comptime Register: type,
18 comptime callee_preserved_regs: []const Register,18 comptime callee_preserved_regs: []const Register,
19) type {19) type {
20 // architectures which do not have a concept of registers should
21 // refrain from using RegisterManager
22 assert(callee_preserved_regs.len > 0); // see note above
23
20 return struct {24 return struct {
21 /// Tracks the AIR instruction allocated to every register or25 /// Tracks the AIR instruction allocated to every register or
22 /// `null` if no instruction is allocated to a register26 /// `null` if no instruction is allocated to a register
...@@ -45,17 +49,20 @@ pub fn RegisterManager(...@@ -45,17 +49,20 @@ pub fn RegisterManager(
45 }49 }
4650
47 fn getRegisterMask(reg: Register) ?FreeRegInt {51 fn getRegisterMask(reg: Register) ?FreeRegInt {
48 if (FreeRegInt == u0) return null;
49 const index = reg.allocIndex() orelse return null;52 const index = reg.allocIndex() orelse return null;
50 const shift = @intCast(ShiftInt, index);53 const shift = @intCast(ShiftInt, index);
51 const mask = @as(FreeRegInt, 1) << shift;54 const mask = @as(FreeRegInt, 1) << shift;
52 return mask;55 return mask;
53 }56 }
5457
58 fn markRegAllocated(self: *Self, reg: Register) void {
59 const mask = getRegisterMask(reg) orelse return;
60 self.allocated_registers |= mask;
61 }
62
55 fn markRegUsed(self: *Self, reg: Register) void {63 fn markRegUsed(self: *Self, reg: Register) void {
56 const mask = getRegisterMask(reg) orelse return;64 const mask = getRegisterMask(reg) orelse return;
57 self.free_registers &= ~mask;65 self.free_registers &= ~mask;
58 self.allocated_registers |= mask;
59 }66 }
6067
61 fn markRegFree(self: *Self, reg: Register) void {68 fn markRegFree(self: *Self, reg: Register) void {
...@@ -120,7 +127,6 @@ pub fn RegisterManager(...@@ -120,7 +127,6 @@ pub fn RegisterManager(
120 insts: [count]?Air.Inst.Index,127 insts: [count]?Air.Inst.Index,
121 exceptions: []const Register,128 exceptions: []const Register,
122 ) ?[count]Register {129 ) ?[count]Register {
123 comptime if (callee_preserved_regs.len == 0) return null;
124 comptime assert(count > 0 and count <= callee_preserved_regs.len);130 comptime assert(count > 0 and count <= callee_preserved_regs.len);
125 assert(count + exceptions.len <= callee_preserved_regs.len);131 assert(count + exceptions.len <= callee_preserved_regs.len);
126132
...@@ -138,19 +144,20 @@ pub fn RegisterManager(...@@ -138,19 +144,20 @@ pub fn RegisterManager(
138 i += 1;144 i += 1;
139 }145 }
140 }146 }
147 assert(i == count);
141148
142 if (i == count) {149 for (regs) |reg, j| {
143 for (regs) |reg, j| {150 self.markRegAllocated(reg);
144 if (insts[j]) |inst| {151
145 // Track the register152 if (insts[j]) |inst| {
146 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null153 // Track the register
147 self.registers[index] = inst;154 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
148 self.markRegUsed(reg);155 self.registers[index] = inst;
149 }156 self.markRegUsed(reg);
150 }157 }
158 }
151159
152 return regs;160 return regs;
153 } else return null;
154 }161 }
155162
156 /// Allocates a register and optionally tracks it with a163 /// Allocates a register and optionally tracks it with a
...@@ -188,8 +195,9 @@ pub fn RegisterManager(...@@ -188,8 +195,9 @@ pub fn RegisterManager(
188 if (i >= count) break;195 if (i >= count) break;
189 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;196 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
190 if (self.isRegFrozen(reg)) continue;197 if (self.isRegFrozen(reg)) continue;
191 regs[i] = reg;
192198
199 regs[i] = reg;
200 self.markRegAllocated(reg);
193 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null201 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
194 if (insts[i]) |inst| {202 if (insts[i]) |inst| {
195 // Track the register203 // Track the register
...@@ -233,6 +241,7 @@ pub fn RegisterManager(...@@ -233,6 +241,7 @@ pub fn RegisterManager(
233 /// register.241 /// register.
234 pub fn getReg(self: *Self, reg: Register, inst: ?Air.Inst.Index) !void {242 pub fn getReg(self: *Self, reg: Register, inst: ?Air.Inst.Index) !void {
235 const index = reg.allocIndex() orelse return;243 const index = reg.allocIndex() orelse return;
244 self.markRegAllocated(reg);
236245
237 if (inst) |tracked_inst|246 if (inst) |tracked_inst|
238 if (!self.isRegFree(reg)) {247 if (!self.isRegFree(reg)) {
...@@ -260,6 +269,7 @@ pub fn RegisterManager(...@@ -260,6 +269,7 @@ pub fn RegisterManager(
260 /// spilling is necessary.269 /// spilling is necessary.
261 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: Air.Inst.Index) void {270 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: Air.Inst.Index) void {
262 const index = reg.allocIndex() orelse return;271 const index = reg.allocIndex() orelse return;
272 self.markRegAllocated(reg);
263273
264 assert(self.registers[index] == null);274 assert(self.registers[index] == null);
265 self.registers[index] = inst;275 self.registers[index] = inst;
...@@ -424,6 +434,11 @@ test "tryAllocRegs" {...@@ -424,6 +434,11 @@ test "tryAllocRegs" {
424434
425 try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?);435 try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?);
426436
437 try expect(function.register_manager.isRegAllocated(.r0));
438 try expect(function.register_manager.isRegAllocated(.r1));
439 try expect(function.register_manager.isRegAllocated(.r2));
440 try expect(!function.register_manager.isRegAllocated(.r3));
441
427 // Exceptions442 // Exceptions
428 //443 //
429 // TODO deprecated, remove test once no backend uses exceptions444 // TODO deprecated, remove test once no backend uses exceptions
...@@ -444,6 +459,11 @@ test "tryAllocRegs" {...@@ -444,6 +459,11 @@ test "tryAllocRegs" {
444 try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?);459 try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?);
445 }460 }
446 try expect(!function.register_manager.frozenRegsExist());461 try expect(!function.register_manager.frozenRegsExist());
462
463 try expect(function.register_manager.isRegAllocated(.r0));
464 try expect(function.register_manager.isRegAllocated(.r1));
465 try expect(function.register_manager.isRegAllocated(.r2));
466 try expect(function.register_manager.isRegAllocated(.r3));
447}467}
448468
449test "allocRegs" {469test "allocRegs" {
...@@ -462,6 +482,11 @@ test "allocRegs" {...@@ -462,6 +482,11 @@ test "allocRegs" {
462 mock_instruction,482 mock_instruction,
463 }, &.{}));483 }, &.{}));
464484
485 try expect(function.register_manager.isRegAllocated(.r0));
486 try expect(function.register_manager.isRegAllocated(.r1));
487 try expect(function.register_manager.isRegAllocated(.r2));
488 try expect(!function.register_manager.isRegAllocated(.r3));
489
465 // Exceptions490 // Exceptions
466 //491 //
467 // TODO deprecated, remove test once no backend uses exceptions492 // TODO deprecated, remove test once no backend uses exceptions
...@@ -480,6 +505,11 @@ test "allocRegs" {...@@ -480,6 +505,11 @@ test "allocRegs" {
480 try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }, &.{}));505 try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }, &.{}));
481 }506 }
482 try expect(!function.register_manager.frozenRegsExist());507 try expect(!function.register_manager.frozenRegsExist());
508
509 try expect(function.register_manager.isRegAllocated(.r0));
510 try expect(function.register_manager.isRegAllocated(.r1));
511 try expect(function.register_manager.isRegAllocated(.r2));
512 try expect(function.register_manager.isRegAllocated(.r3));
483}513}
484514
485test "getReg" {515test "getReg" {