| ... | ... | @@ -137,6 +137,7 @@ pub fn RegisterManager( |
| 137 | 137 | /// Allocates the specified register with the specified |
| 138 | 138 | /// instruction. Spills the register if it is currently |
| 139 | 139 | /// allocated. |
| 140 | /// Before calling, must ensureCapacity + 1 on self.registers. |
| 140 | 141 | pub fn getReg(self: *Self, reg: Register, inst: *ir.Inst) !void { |
| 141 | 142 | if (!isTracked(reg)) return; |
| 142 | 143 | |
| ... | ... | @@ -148,7 +149,7 @@ pub fn RegisterManager( |
| 148 | 149 | regs_entry.value = inst; |
| 149 | 150 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); |
| 150 | 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 | 161 | if (!self.isRegFree(reg)) { |
| 161 | 162 | // Move the instruction that was previously there to a |
| 162 | 163 | // stack allocation. |
| 163 | | const regs_entry = self.registers.getEntry(reg).?; |
| 164 | const regs_entry = self.registers.remove(reg).?; |
| 164 | 165 | const spilled_inst = regs_entry.value; |
| 165 | 166 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); |
| 166 | 167 | self.markRegFree(reg); |
| ... | ... | @@ -170,10 +171,11 @@ pub fn RegisterManager( |
| 170 | 171 | /// Allocates the specified register with the specified |
| 171 | 172 | /// instruction. Assumes that the register is free and no |
| 172 | 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 | 176 | if (!isTracked(reg)) return; |
| 175 | 177 | |
| 176 | | try self.registers.putNoClobber(self.getFunction().gpa, reg, inst); |
| 178 | self.registers.putAssumeCapacityNoClobber(reg, inst); |
| 177 | 179 | self.markRegUsed(reg); |
| 178 | 180 | } |
| 179 | 181 | |
| ... | ... | @@ -279,3 +281,35 @@ test "allocReg: spilling" { |
| 279 | 281 | std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction)); |
| 280 | 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 | } |