| ... | @@ -137,6 +137,7 @@ pub fn RegisterManager( | ... | @@ -137,6 +137,7 @@ pub fn RegisterManager( |
| 137 | /// Allocates the specified register with the specified | 137 | /// Allocates the specified register with the specified |
| 138 | /// instruction. Spills the register if it is currently | 138 | /// instruction. Spills the register if it is currently |
| 139 | /// allocated. | 139 | /// allocated. |
| | 140 | /// Before calling, must ensureCapacity + 1 on self.registers. |
| 140 | pub fn getReg(self: *Self, reg: Register, inst: *ir.Inst) !void { | 141 | pub fn getReg(self: *Self, reg: Register, inst: *ir.Inst) !void { |
| 141 | if (!isTracked(reg)) return; | 142 | if (!isTracked(reg)) return; |
| 142 | | 143 | |
| ... | @@ -148,7 +149,7 @@ pub fn RegisterManager( | ... | @@ -148,7 +149,7 @@ pub fn RegisterManager( |
| 148 | regs_entry.value = inst; | 149 | regs_entry.value = inst; |
| 149 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); | 150 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); |
| 150 | } else { | 151 | } else { |
| 151 | try self.getRegAssumeFree(reg, inst); | 152 | self.getRegAssumeFree(reg, inst); |
| 152 | } | 153 | } |
| 153 | } | 154 | } |
| 154 | | 155 | |
| ... | @@ -160,7 +161,7 @@ pub fn RegisterManager( | ... | @@ -160,7 +161,7 @@ pub fn RegisterManager( |
| 160 | if (!self.isRegFree(reg)) { | 161 | if (!self.isRegFree(reg)) { |
| 161 | // Move the instruction that was previously there to a | 162 | // Move the instruction that was previously there to a |
| 162 | // stack allocation. | 163 | // stack allocation. |
| 163 | const regs_entry = self.registers.getEntry(reg).?; | 164 | const regs_entry = self.registers.remove(reg).?; |
| 164 | const spilled_inst = regs_entry.value; | 165 | const spilled_inst = regs_entry.value; |
| 165 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); | 166 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); |
| 166 | self.markRegFree(reg); | 167 | self.markRegFree(reg); |
| ... | @@ -170,10 +171,11 @@ pub fn RegisterManager( | ... | @@ -170,10 +171,11 @@ pub fn RegisterManager( |
| 170 | /// Allocates the specified register with the specified | 171 | /// Allocates the specified register with the specified |
| 171 | /// instruction. Assumes that the register is free and no | 172 | /// instruction. Assumes that the register is free and no |
| 172 | /// spilling is necessary. | 173 | /// spilling is necessary. |
| 173 | pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) !void { | 174 | /// Before calling, must ensureCapacity + 1 on self.registers. |
| | 175 | pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) void { |
| 174 | if (!isTracked(reg)) return; | 176 | if (!isTracked(reg)) return; |
| 175 | | 177 | |
| 176 | try self.registers.putNoClobber(self.getFunction().gpa, reg, inst); | 178 | self.registers.putAssumeCapacityNoClobber(reg, inst); |
| 177 | self.markRegUsed(reg); | 179 | self.markRegUsed(reg); |
| 178 | } | 180 | } |
| 179 | | 181 | |
| ... | @@ -279,3 +281,35 @@ test "allocReg: spilling" { | ... | @@ -279,3 +281,35 @@ test "allocReg: spilling" { |
| 279 | std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction)); | 281 | std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction)); |
| 280 | std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items); | 282 | std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items); |
| 281 | } | 283 | } |
| | 284 | |
| | 285 | test "getReg" { |
| | 286 | const allocator = std.testing.allocator; |
| | 287 | |
| | 288 | var function = MockFunction{ |
| | 289 | .allocator = allocator, |
| | 290 | }; |
| | 291 | defer function.deinit(); |
| | 292 | |
| | 293 | var mock_instruction = ir.Inst{ |
| | 294 | .tag = .breakpoint, |
| | 295 | .ty = Type.initTag(.void), |
| | 296 | .src = .unneeded, |
| | 297 | }; |
| | 298 | |
| | 299 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); |
| | 300 | std.testing.expect(!function.register_manager.isRegAllocated(.r3)); |
| | 301 | |
| | 302 | try function.register_manager.registers.ensureCapacity(allocator, function.register_manager.registers.count() + 2); |
| | 303 | try function.register_manager.getReg(.r3, &mock_instruction); |
| | 304 | |
| | 305 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); |
| | 306 | std.testing.expect(function.register_manager.isRegAllocated(.r3)); |
| | 307 | |
| | 308 | // Spill r3 |
| | 309 | try function.register_manager.registers.ensureCapacity(allocator, function.register_manager.registers.count() + 2); |
| | 310 | try function.register_manager.getReg(.r3, &mock_instruction); |
| | 311 | |
| | 312 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); |
| | 313 | std.testing.expect(function.register_manager.isRegAllocated(.r3)); |
| | 314 | std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r3}, function.spilled.items); |
| | 315 | } |