| author | |
| committer | |
| log | 3832b582292d3065f600e7c7a8393c411e6cdb0a |
| tree | 357d9fd6aad0da36b8c09c4a890001976ceac9e3 |
| parent | 228b798af5b2c9e417d145aff171879cdee8ae04 |
| parent | 74a01e3d64cc5d941486e5bd037f6f55e030339c |
| signature |
stage2: migrate x64 to freeze regalloc API, and remove the concept of register exceptions5 files changed, 167 insertions(+), 165 deletions(-)
src/arch/aarch64/CodeGen.zig+7-7| ... | @@ -774,7 +774,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -774,7 +774,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 774 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 774 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 775 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 775 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 776 | if (abi_size <= ptr_bytes) { | 776 | if (abi_size <= ptr_bytes) { |
| 777 | if (self.register_manager.tryAllocReg(inst, &.{})) |reg| { | 777 | if (self.register_manager.tryAllocReg(inst)) |reg| { |
| 778 | return MCValue{ .register = registerAlias(reg, abi_size) }; | 778 | return MCValue{ .register = registerAlias(reg, abi_size) }; |
| 779 | } | 779 | } |
| 780 | } | 780 | } |
| ... | @@ -797,7 +797,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -797,7 +797,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 797 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 797 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 798 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 798 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 799 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 799 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 800 | const reg = try self.register_manager.allocReg(null, &.{}); | 800 | const reg = try self.register_manager.allocReg(null); |
| 801 | try self.genSetReg(ty, reg, mcv); | 801 | try self.genSetReg(ty, reg, mcv); |
| 802 | return reg; | 802 | return reg; |
| 803 | } | 803 | } |
| ... | @@ -806,7 +806,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | ... | @@ -806,7 +806,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 806 | /// `reg_owner` is the instruction that gets associated with the register in the register table. | 806 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 807 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 807 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 808 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 808 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { |
| 809 | const reg = try self.register_manager.allocReg(reg_owner, &.{}); | 809 | const reg = try self.register_manager.allocReg(reg_owner); |
| 810 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); | 810 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); |
| 811 | return MCValue{ .register = reg }; | 811 | return MCValue{ .register = reg }; |
| 812 | } | 812 | } |
| ... | @@ -1270,7 +1270,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1270,7 +1270,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1270 | .memory, | 1270 | .memory, |
| 1271 | .stack_offset, | 1271 | .stack_offset, |
| 1272 | => { | 1272 | => { |
| 1273 | const reg = try self.register_manager.allocReg(null, &.{}); | 1273 | const reg = try self.register_manager.allocReg(null); |
| 1274 | self.register_manager.freezeRegs(&.{reg}); | 1274 | self.register_manager.freezeRegs(&.{reg}); |
| 1275 | defer self.register_manager.unfreezeRegs(&.{reg}); | 1275 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 1276 | 1276 | ||
| ... | @@ -1729,15 +1729,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -1729,15 +1729,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1729 | if (!lhs_is_register and !rhs_is_register) { | 1729 | if (!lhs_is_register and !rhs_is_register) { |
| 1730 | const regs = try self.register_manager.allocRegs(2, .{ | 1730 | const regs = try self.register_manager.allocRegs(2, .{ |
| 1731 | Air.refToIndex(bin_op.rhs).?, Air.refToIndex(bin_op.lhs).?, | 1731 | Air.refToIndex(bin_op.rhs).?, Air.refToIndex(bin_op.lhs).?, |
| 1732 | }, &.{}); | 1732 | }); |
| 1733 | lhs_mcv = MCValue{ .register = regs[0] }; | 1733 | lhs_mcv = MCValue{ .register = regs[0] }; |
| 1734 | rhs_mcv = MCValue{ .register = regs[1] }; | 1734 | rhs_mcv = MCValue{ .register = regs[1] }; |
| 1735 | } else if (!rhs_is_register) { | 1735 | } else if (!rhs_is_register) { |
| 1736 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.rhs).?, &.{}) }; | 1736 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.rhs).?) }; |
| 1737 | } | 1737 | } |
| 1738 | } | 1738 | } |
| 1739 | if (!lhs_is_register) { | 1739 | if (!lhs_is_register) { |
| 1740 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?, &.{}) }; | 1740 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?) }; |
| 1741 | } | 1741 | } |
| 1742 | 1742 | ||
| 1743 | // Move the operands to the newly allocated registers | 1743 | // Move the operands to the newly allocated registers |
src/arch/arm/CodeGen.zig+34-34| ... | @@ -750,7 +750,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -750,7 +750,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 750 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 750 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 751 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 751 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 752 | if (abi_size <= ptr_bytes) { | 752 | if (abi_size <= ptr_bytes) { |
| 753 | if (self.register_manager.tryAllocReg(inst, &.{})) |reg| { | 753 | if (self.register_manager.tryAllocReg(inst)) |reg| { |
| 754 | return MCValue{ .register = reg }; | 754 | return MCValue{ .register = reg }; |
| 755 | } | 755 | } |
| 756 | } | 756 | } |
| ... | @@ -791,7 +791,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { | ... | @@ -791,7 +791,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 791 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 791 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 792 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 792 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 793 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 793 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 794 | const reg = try self.register_manager.allocReg(null, &.{}); | 794 | const reg = try self.register_manager.allocReg(null); |
| 795 | try self.genSetReg(ty, reg, mcv); | 795 | try self.genSetReg(ty, reg, mcv); |
| 796 | return reg; | 796 | return reg; |
| 797 | } | 797 | } |
| ... | @@ -800,7 +800,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | ... | @@ -800,7 +800,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 800 | /// `reg_owner` is the instruction that gets associated with the register in the register table. | 800 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 801 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 801 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 802 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 802 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { |
| 803 | const reg = try self.register_manager.allocReg(reg_owner, &.{}); | 803 | const reg = try self.register_manager.allocReg(reg_owner); |
| 804 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); | 804 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); |
| 805 | return MCValue{ .register = reg }; | 805 | return MCValue{ .register = reg }; |
| 806 | } | 806 | } |
| ... | @@ -1247,7 +1247,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1247,7 +1247,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1247 | defer self.register_manager.unfreezeRegs(&.{base_mcv.register}); | 1247 | defer self.register_manager.unfreezeRegs(&.{base_mcv.register}); |
| 1248 | 1248 | ||
| 1249 | if (elem_size <= 4) { | 1249 | if (elem_size <= 4) { |
| 1250 | const dst_reg = try self.register_manager.allocReg(inst, &.{}); | 1250 | const dst_reg = try self.register_manager.allocReg(inst); |
| 1251 | self.register_manager.freezeRegs(&.{dst_reg}); | 1251 | self.register_manager.freezeRegs(&.{dst_reg}); |
| 1252 | defer self.register_manager.unfreezeRegs(&.{dst_reg}); | 1252 | defer self.register_manager.unfreezeRegs(&.{dst_reg}); |
| 1253 | 1253 | ||
| ... | @@ -1285,7 +1285,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1285,7 +1285,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1285 | } else { | 1285 | } else { |
| 1286 | const dst_mcv = try self.allocRegOrMem(inst, false); | 1286 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1287 | 1287 | ||
| 1288 | const addr_reg = try self.register_manager.allocReg(null, &.{}); | 1288 | const addr_reg = try self.register_manager.allocReg(null); |
| 1289 | self.register_manager.freezeRegs(&.{addr_reg}); | 1289 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 1290 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); | 1290 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| 1291 | 1291 | ||
| ... | @@ -1437,7 +1437,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1437,7 +1437,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1437 | }, | 1437 | }, |
| 1438 | .stack_offset => |off| { | 1438 | .stack_offset => |off| { |
| 1439 | if (elem_ty.abiSize(self.target.*) <= 4) { | 1439 | if (elem_ty.abiSize(self.target.*) <= 4) { |
| 1440 | const tmp_reg = try self.register_manager.allocReg(null, &.{}); | 1440 | const tmp_reg = try self.register_manager.allocReg(null); |
| 1441 | self.register_manager.freezeRegs(&.{tmp_reg}); | 1441 | self.register_manager.freezeRegs(&.{tmp_reg}); |
| 1442 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); | 1442 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); |
| 1443 | 1443 | ||
| ... | @@ -1451,7 +1451,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1451,7 +1451,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1451 | // larger | 1451 | // larger |
| 1452 | 1452 | ||
| 1453 | const usize_ty = Type.initTag(.usize); | 1453 | const usize_ty = Type.initTag(.usize); |
| 1454 | const tmp_regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{}); | 1454 | const tmp_regs = try self.register_manager.allocRegs(2, .{ null, null }); |
| 1455 | self.register_manager.freezeRegs(&tmp_regs); | 1455 | self.register_manager.freezeRegs(&tmp_regs); |
| 1456 | defer self.register_manager.unfreezeRegs(&tmp_regs); | 1456 | defer self.register_manager.unfreezeRegs(&tmp_regs); |
| 1457 | 1457 | ||
| ... | @@ -1475,7 +1475,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1475,7 +1475,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1475 | try self.genSetStack(usize_ty, off + 4, MCValue{ .register = tmp_regs[1] }); | 1475 | try self.genSetStack(usize_ty, off + 4, MCValue{ .register = tmp_regs[1] }); |
| 1476 | } else { | 1476 | } else { |
| 1477 | // TODO optimize the register allocation | 1477 | // TODO optimize the register allocation |
| 1478 | const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, &.{}); | 1478 | const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }); |
| 1479 | self.register_manager.freezeRegs(&regs); | 1479 | self.register_manager.freezeRegs(&regs); |
| 1480 | defer self.register_manager.unfreezeRegs(&regs); | 1480 | defer self.register_manager.unfreezeRegs(&regs); |
| 1481 | 1481 | ||
| ... | @@ -1524,7 +1524,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1524,7 +1524,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1524 | .stack_offset, | 1524 | .stack_offset, |
| 1525 | .stack_argument_offset, | 1525 | .stack_argument_offset, |
| 1526 | => { | 1526 | => { |
| 1527 | const reg = try self.register_manager.allocReg(null, &.{}); | 1527 | const reg = try self.register_manager.allocReg(null); |
| 1528 | self.register_manager.freezeRegs(&.{reg}); | 1528 | self.register_manager.freezeRegs(&.{reg}); |
| 1529 | defer self.register_manager.unfreezeRegs(&.{reg}); | 1529 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 1530 | 1530 | ||
| ... | @@ -1597,7 +1597,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1597,7 +1597,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1597 | }, | 1597 | }, |
| 1598 | else => { | 1598 | else => { |
| 1599 | if (value_ty.abiSize(self.target.*) <= 4) { | 1599 | if (value_ty.abiSize(self.target.*) <= 4) { |
| 1600 | const tmp_reg = try self.register_manager.allocReg(null, &.{}); | 1600 | const tmp_reg = try self.register_manager.allocReg(null); |
| 1601 | self.register_manager.freezeRegs(&.{tmp_reg}); | 1601 | self.register_manager.freezeRegs(&.{tmp_reg}); |
| 1602 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); | 1602 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); |
| 1603 | 1603 | ||
| ... | @@ -1774,14 +1774,14 @@ fn genArmBinIntOp( | ... | @@ -1774,14 +1774,14 @@ fn genArmBinIntOp( |
| 1774 | if (reuse_lhs) { | 1774 | if (reuse_lhs) { |
| 1775 | // Allocate 0 or 1 registers | 1775 | // Allocate 0 or 1 registers |
| 1776 | if (!rhs_is_register and rhs_should_be_register) { | 1776 | if (!rhs_is_register and rhs_should_be_register) { |
| 1777 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?, &.{}) }; | 1777 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?) }; |
| 1778 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); | 1778 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); |
| 1779 | } | 1779 | } |
| 1780 | dst_mcv = lhs; | 1780 | dst_mcv = lhs; |
| 1781 | } else if (reuse_rhs and can_swap_lhs_and_rhs) { | 1781 | } else if (reuse_rhs and can_swap_lhs_and_rhs) { |
| 1782 | // Allocate 0 or 1 registers | 1782 | // Allocate 0 or 1 registers |
| 1783 | if (!lhs_is_register and lhs_should_be_register) { | 1783 | if (!lhs_is_register and lhs_should_be_register) { |
| 1784 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?, &.{}) }; | 1784 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?) }; |
| 1785 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv); | 1785 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv); |
| 1786 | } | 1786 | } |
| 1787 | dst_mcv = rhs; | 1787 | dst_mcv = rhs; |
| ... | @@ -1791,18 +1791,18 @@ fn genArmBinIntOp( | ... | @@ -1791,18 +1791,18 @@ fn genArmBinIntOp( |
| 1791 | // Allocate 1 or 2 registers | 1791 | // Allocate 1 or 2 registers |
| 1792 | if (lhs_should_be_register and rhs_should_be_register) { | 1792 | if (lhs_should_be_register and rhs_should_be_register) { |
| 1793 | if (lhs_is_register and rhs_is_register) { | 1793 | if (lhs_is_register and rhs_is_register) { |
| 1794 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; | 1794 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 1795 | } else if (lhs_is_register) { | 1795 | } else if (lhs_is_register) { |
| 1796 | // Move RHS to register | 1796 | // Move RHS to register |
| 1797 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; | 1797 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 1798 | rhs_mcv = dst_mcv; | 1798 | rhs_mcv = dst_mcv; |
| 1799 | } else if (rhs_is_register) { | 1799 | } else if (rhs_is_register) { |
| 1800 | // Move LHS to register | 1800 | // Move LHS to register |
| 1801 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; | 1801 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 1802 | lhs_mcv = dst_mcv; | 1802 | lhs_mcv = dst_mcv; |
| 1803 | } else { | 1803 | } else { |
| 1804 | // Move LHS and RHS to register | 1804 | // Move LHS and RHS to register |
| 1805 | const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }, &.{}); | 1805 | const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }); |
| 1806 | lhs_mcv = MCValue{ .register = regs[0] }; | 1806 | lhs_mcv = MCValue{ .register = regs[0] }; |
| 1807 | rhs_mcv = MCValue{ .register = regs[1] }; | 1807 | rhs_mcv = MCValue{ .register = regs[1] }; |
| 1808 | dst_mcv = lhs_mcv; | 1808 | dst_mcv = lhs_mcv; |
| ... | @@ -1812,17 +1812,17 @@ fn genArmBinIntOp( | ... | @@ -1812,17 +1812,17 @@ fn genArmBinIntOp( |
| 1812 | } else if (lhs_should_be_register) { | 1812 | } else if (lhs_should_be_register) { |
| 1813 | // RHS is immediate | 1813 | // RHS is immediate |
| 1814 | if (lhs_is_register) { | 1814 | if (lhs_is_register) { |
| 1815 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; | 1815 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 1816 | } else { | 1816 | } else { |
| 1817 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; | 1817 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 1818 | lhs_mcv = dst_mcv; | 1818 | lhs_mcv = dst_mcv; |
| 1819 | } | 1819 | } |
| 1820 | } else if (rhs_should_be_register and can_swap_lhs_and_rhs) { | 1820 | } else if (rhs_should_be_register and can_swap_lhs_and_rhs) { |
| 1821 | // LHS is immediate | 1821 | // LHS is immediate |
| 1822 | if (rhs_is_register) { | 1822 | if (rhs_is_register) { |
| 1823 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; | 1823 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 1824 | } else { | 1824 | } else { |
| 1825 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; | 1825 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 1826 | rhs_mcv = dst_mcv; | 1826 | rhs_mcv = dst_mcv; |
| 1827 | } | 1827 | } |
| 1828 | 1828 | ||
| ... | @@ -1983,32 +1983,32 @@ fn genArmMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Ai | ... | @@ -1983,32 +1983,32 @@ fn genArmMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Ai |
| 1983 | if (reuse_lhs) { | 1983 | if (reuse_lhs) { |
| 1984 | // Allocate 0 or 1 registers | 1984 | // Allocate 0 or 1 registers |
| 1985 | if (!rhs_is_register) { | 1985 | if (!rhs_is_register) { |
| 1986 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?, &.{}) }; | 1986 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?) }; |
| 1987 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); | 1987 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); |
| 1988 | } | 1988 | } |
| 1989 | dst_mcv = lhs; | 1989 | dst_mcv = lhs; |
| 1990 | } else if (reuse_rhs) { | 1990 | } else if (reuse_rhs) { |
| 1991 | // Allocate 0 or 1 registers | 1991 | // Allocate 0 or 1 registers |
| 1992 | if (!lhs_is_register) { | 1992 | if (!lhs_is_register) { |
| 1993 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?, &.{}) }; | 1993 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?) }; |
| 1994 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv); | 1994 | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv); |
| 1995 | } | 1995 | } |
| 1996 | dst_mcv = rhs; | 1996 | dst_mcv = rhs; |
| 1997 | } else { | 1997 | } else { |
| 1998 | // Allocate 1 or 2 registers | 1998 | // Allocate 1 or 2 registers |
| 1999 | if (lhs_is_register and rhs_is_register) { | 1999 | if (lhs_is_register and rhs_is_register) { |
| 2000 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; | 2000 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 2001 | } else if (lhs_is_register) { | 2001 | } else if (lhs_is_register) { |
| 2002 | // Move RHS to register | 2002 | // Move RHS to register |
| 2003 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; | 2003 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 2004 | rhs_mcv = dst_mcv; | 2004 | rhs_mcv = dst_mcv; |
| 2005 | } else if (rhs_is_register) { | 2005 | } else if (rhs_is_register) { |
| 2006 | // Move LHS to register | 2006 | // Move LHS to register |
| 2007 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) }; | 2007 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 2008 | lhs_mcv = dst_mcv; | 2008 | lhs_mcv = dst_mcv; |
| 2009 | } else { | 2009 | } else { |
| 2010 | // Move LHS and RHS to register | 2010 | // Move LHS and RHS to register |
| 2011 | const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }, &.{}); | 2011 | const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }); |
| 2012 | lhs_mcv = MCValue{ .register = regs[0] }; | 2012 | lhs_mcv = MCValue{ .register = regs[0] }; |
| 2013 | rhs_mcv = MCValue{ .register = regs[1] }; | 2013 | rhs_mcv = MCValue{ .register = regs[1] }; |
| 2014 | dst_mcv = lhs_mcv; | 2014 | dst_mcv = lhs_mcv; |
| ... | @@ -2056,17 +2056,17 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind | ... | @@ -2056,17 +2056,17 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind |
| 2056 | // Allocate registers for operands and/or destination | 2056 | // Allocate registers for operands and/or destination |
| 2057 | if (reuse_lhs) { | 2057 | if (reuse_lhs) { |
| 2058 | // Allocate 1 register | 2058 | // Allocate 1 register |
| 2059 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(null, &.{}) }; | 2059 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(null) }; |
| 2060 | dst_mcv = lhs; | 2060 | dst_mcv = lhs; |
| 2061 | } else { | 2061 | } else { |
| 2062 | // Allocate 1 or 2 registers | 2062 | // Allocate 1 or 2 registers |
| 2063 | if (lhs_is_register) { | 2063 | if (lhs_is_register) { |
| 2064 | // Move RHS to register | 2064 | // Move RHS to register |
| 2065 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null, &.{}) }; | 2065 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) }; |
| 2066 | rhs_mcv = dst_mcv; | 2066 | rhs_mcv = dst_mcv; |
| 2067 | } else { | 2067 | } else { |
| 2068 | // Move LHS and RHS to register | 2068 | // Move LHS and RHS to register |
| 2069 | const regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{}); | 2069 | const regs = try self.register_manager.allocRegs(2, .{ null, null }); |
| 2070 | lhs_mcv = MCValue{ .register = regs[0] }; | 2070 | lhs_mcv = MCValue{ .register = regs[0] }; |
| 2071 | rhs_mcv = MCValue{ .register = regs[1] }; | 2071 | rhs_mcv = MCValue{ .register = regs[1] }; |
| 2072 | dst_mcv = lhs_mcv; | 2072 | dst_mcv = lhs_mcv; |
| ... | @@ -2432,20 +2432,20 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -2432,20 +2432,20 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2432 | if (!lhs_is_register and !rhs_is_register) { | 2432 | if (!lhs_is_register and !rhs_is_register) { |
| 2433 | const regs = try self.register_manager.allocRegs(2, .{ | 2433 | const regs = try self.register_manager.allocRegs(2, .{ |
| 2434 | Air.refToIndex(bin_op.lhs).?, Air.refToIndex(bin_op.rhs).?, | 2434 | Air.refToIndex(bin_op.lhs).?, Air.refToIndex(bin_op.rhs).?, |
| 2435 | }, &.{}); | 2435 | }); |
| 2436 | lhs_mcv = MCValue{ .register = regs[0] }; | 2436 | lhs_mcv = MCValue{ .register = regs[0] }; |
| 2437 | rhs_mcv = MCValue{ .register = regs[1] }; | 2437 | rhs_mcv = MCValue{ .register = regs[1] }; |
| 2438 | } else if (!rhs_is_register) { | 2438 | } else if (!rhs_is_register) { |
| 2439 | const track_inst = if (self.liveness.operandDies(inst, 1)) null else Air.refToIndex(bin_op.rhs).?; | 2439 | const track_inst = if (self.liveness.operandDies(inst, 1)) null else Air.refToIndex(bin_op.rhs).?; |
| 2440 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) }; | 2440 | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) }; |
| 2441 | } else if (!lhs_is_register) { | 2441 | } else if (!lhs_is_register) { |
| 2442 | const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?; | 2442 | const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?; |
| 2443 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) }; | 2443 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) }; |
| 2444 | } | 2444 | } |
| 2445 | } else { | 2445 | } else { |
| 2446 | if (!lhs_is_register) { | 2446 | if (!lhs_is_register) { |
| 2447 | const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?; | 2447 | const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?; |
| 2448 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) }; | 2448 | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) }; |
| 2449 | } | 2449 | } |
| 2450 | } | 2450 | } |
| 2451 | 2451 | ||
| ... | @@ -3185,7 +3185,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3185,7 +3185,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3185 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 3185 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3186 | } else { | 3186 | } else { |
| 3187 | // TODO optimize the register allocation | 3187 | // TODO optimize the register allocation |
| 3188 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, &.{}); | 3188 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }); |
| 3189 | const src_reg = regs[0]; | 3189 | const src_reg = regs[0]; |
| 3190 | const dst_reg = regs[1]; | 3190 | const dst_reg = regs[1]; |
| 3191 | const len_reg = regs[2]; | 3191 | const len_reg = regs[2]; |
src/arch/riscv64/CodeGen.zig+4-4| ... | @@ -749,7 +749,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -749,7 +749,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 749 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 749 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 750 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 750 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 751 | if (abi_size <= ptr_bytes) { | 751 | if (abi_size <= ptr_bytes) { |
| 752 | if (self.register_manager.tryAllocReg(inst, &.{})) |reg| { | 752 | if (self.register_manager.tryAllocReg(inst)) |reg| { |
| 753 | return MCValue{ .register = reg }; | 753 | return MCValue{ .register = reg }; |
| 754 | } | 754 | } |
| 755 | } | 755 | } |
| ... | @@ -772,7 +772,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -772,7 +772,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 772 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 772 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 773 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 773 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 774 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 774 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 775 | const reg = try self.register_manager.allocReg(null, &.{}); | 775 | const reg = try self.register_manager.allocReg(null); |
| 776 | try self.genSetReg(ty, reg, mcv); | 776 | try self.genSetReg(ty, reg, mcv); |
| 777 | return reg; | 777 | return reg; |
| 778 | } | 778 | } |
| ... | @@ -781,7 +781,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | ... | @@ -781,7 +781,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 781 | /// `reg_owner` is the instruction that gets associated with the register in the register table. | 781 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 782 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 782 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 783 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 783 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { |
| 784 | const reg = try self.register_manager.allocReg(reg_owner, &.{}); | 784 | const reg = try self.register_manager.allocReg(reg_owner); |
| 785 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); | 785 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); |
| 786 | return MCValue{ .register = reg }; | 786 | return MCValue{ .register = reg }; |
| 787 | } | 787 | } |
| ... | @@ -1211,7 +1211,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1211,7 +1211,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1211 | .memory, | 1211 | .memory, |
| 1212 | .stack_offset, | 1212 | .stack_offset, |
| 1213 | => { | 1213 | => { |
| 1214 | const reg = try self.register_manager.allocReg(null, &.{}); | 1214 | const reg = try self.register_manager.allocReg(null); |
| 1215 | self.register_manager.freezeRegs(&.{reg}); | 1215 | self.register_manager.freezeRegs(&.{reg}); |
| 1216 | defer self.register_manager.unfreezeRegs(&.{reg}); | 1216 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 1217 | 1217 |
src/arch/x86_64/CodeGen.zig+104-60| ... | @@ -21,7 +21,7 @@ const Emit = @import("Emit.zig"); | ... | @@ -21,7 +21,7 @@ const Emit = @import("Emit.zig"); |
| 21 | const Liveness = @import("../../Liveness.zig"); | 21 | const Liveness = @import("../../Liveness.zig"); |
| 22 | const Mir = @import("Mir.zig"); | 22 | const Mir = @import("Mir.zig"); |
| 23 | const Module = @import("../../Module.zig"); | 23 | const Module = @import("../../Module.zig"); |
| 24 | const RegisterManager = @import("../../register_manager.zig").RegisterManager; | 24 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 25 | const Target = std.Target; | 25 | const Target = std.Target; |
| 26 | const Type = @import("../../type.zig").Type; | 26 | const Type = @import("../../type.zig").Type; |
| 27 | const TypedValue = @import("../../TypedValue.zig"); | 27 | const TypedValue = @import("../../TypedValue.zig"); |
| ... | @@ -33,6 +33,8 @@ const InnerError = error{ | ... | @@ -33,6 +33,8 @@ const InnerError = error{ |
| 33 | CodegenFail, | 33 | CodegenFail, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs); | ||
| 37 | |||
| 36 | gpa: Allocator, | 38 | gpa: Allocator, |
| 37 | air: Air, | 39 | air: Air, |
| 38 | liveness: Liveness, | 40 | liveness: Liveness, |
| ... | @@ -73,7 +75,7 @@ branch_stack: *std.ArrayList(Branch), | ... | @@ -73,7 +75,7 @@ branch_stack: *std.ArrayList(Branch), |
| 73 | // Key is the block instruction | 75 | // Key is the block instruction |
| 74 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, | 76 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{}, |
| 75 | 77 | ||
| 76 | register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{}, | 78 | register_manager: RegisterManager = .{}, |
| 77 | /// Maps offset to what is stored there. | 79 | /// Maps offset to what is stored there. |
| 78 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, | 80 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, |
| 79 | 81 | ||
| ... | @@ -169,6 +171,24 @@ pub const MCValue = union(enum) { | ... | @@ -169,6 +171,24 @@ pub const MCValue = union(enum) { |
| 169 | else => false, | 171 | else => false, |
| 170 | }; | 172 | }; |
| 171 | } | 173 | } |
| 174 | |||
| 175 | fn freezeIfRegister(mcv: MCValue, mgr: *RegisterManager) void { | ||
| 176 | switch (mcv) { | ||
| 177 | .register => |reg| { | ||
| 178 | mgr.freezeRegs(&.{reg}); | ||
| 179 | }, | ||
| 180 | else => {}, | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | fn unfreezeIfRegister(mcv: MCValue, mgr: *RegisterManager) void { | ||
| 185 | switch (mcv) { | ||
| 186 | .register => |reg| { | ||
| 187 | mgr.unfreezeRegs(&.{reg}); | ||
| 188 | }, | ||
| 189 | else => {}, | ||
| 190 | } | ||
| 191 | } | ||
| 172 | }; | 192 | }; |
| 173 | 193 | ||
| 174 | const Branch = struct { | 194 | const Branch = struct { |
| ... | @@ -799,7 +819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -799,7 +819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 799 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 819 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 800 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 820 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 801 | if (abi_size <= ptr_bytes) { | 821 | if (abi_size <= ptr_bytes) { |
| 802 | if (self.register_manager.tryAllocReg(inst, &.{})) |reg| { | 822 | if (self.register_manager.tryAllocReg(inst)) |reg| { |
| 803 | return MCValue{ .register = registerAlias(reg, abi_size) }; | 823 | return MCValue{ .register = registerAlias(reg, abi_size) }; |
| 804 | } | 824 | } |
| 805 | } | 825 | } |
| ... | @@ -822,7 +842,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -822,7 +842,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 822 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 842 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 823 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 843 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 824 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 844 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 825 | const reg = try self.register_manager.allocReg(null, &.{}); | 845 | const reg = try self.register_manager.allocReg(null); |
| 826 | try self.genSetReg(ty, reg, mcv); | 846 | try self.genSetReg(ty, reg, mcv); |
| 827 | return reg; | 847 | return reg; |
| 828 | } | 848 | } |
| ... | @@ -831,21 +851,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | ... | @@ -831,21 +851,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 831 | /// `reg_owner` is the instruction that gets associated with the register in the register table. | 851 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 832 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 852 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 833 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue { | 853 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue { |
| 834 | const reg = try self.register_manager.allocReg(reg_owner, &.{}); | 854 | const reg = try self.register_manager.allocReg(reg_owner); |
| 835 | try self.genSetReg(ty, reg, mcv); | ||
| 836 | return MCValue{ .register = reg }; | ||
| 837 | } | ||
| 838 | |||
| 839 | /// Like `copyToNewRegister` but allows to specify a list of excluded registers which | ||
| 840 | /// will not be selected for allocation. This can be done via `exceptions` slice. | ||
| 841 | fn copyToNewRegisterWithExceptions( | ||
| 842 | self: *Self, | ||
| 843 | reg_owner: Air.Inst.Index, | ||
| 844 | ty: Type, | ||
| 845 | mcv: MCValue, | ||
| 846 | exceptions: []const Register, | ||
| 847 | ) !MCValue { | ||
| 848 | const reg = try self.register_manager.allocReg(reg_owner, exceptions); | ||
| 849 | try self.genSetReg(ty, reg, mcv); | 855 | try self.genSetReg(ty, reg, mcv); |
| 850 | return MCValue{ .register = reg }; | 856 | return MCValue{ .register = reg }; |
| 851 | } | 857 | } |
| ... | @@ -897,8 +903,9 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -897,8 +903,9 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 897 | return self.fail("TODO implement intCast for abi sizes larger than 8", .{}); | 903 | return self.fail("TODO implement intCast for abi sizes larger than 8", .{}); |
| 898 | } | 904 | } |
| 899 | 905 | ||
| 900 | if (operand.isRegister()) self.register_manager.freezeRegs(&.{operand.register}); | 906 | operand.freezeIfRegister(&self.register_manager); |
| 901 | defer if (operand.isRegister()) self.register_manager.unfreezeRegs(&.{operand.register}); | 907 | defer operand.unfreezeIfRegister(&self.register_manager); |
| 908 | |||
| 902 | break :blk try self.copyToNewRegister(inst, dest_ty, operand); | 909 | break :blk try self.copyToNewRegister(inst, dest_ty, operand); |
| 903 | }; | 910 | }; |
| 904 | 911 | ||
| ... | @@ -925,7 +932,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -925,7 +932,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 925 | const reg = switch (operand) { | 932 | const reg = switch (operand) { |
| 926 | .register => |reg| reg, | 933 | .register => |reg| reg, |
| 927 | else => inner: { | 934 | else => inner: { |
| 928 | const reg = try self.register_manager.allocReg(inst, &.{}); | 935 | const reg = try self.register_manager.allocReg(inst); |
| 929 | try self.genSetReg(src_ty, reg, operand); | 936 | try self.genSetReg(src_ty, reg, operand); |
| 930 | break :inner reg; | 937 | break :inner reg; |
| 931 | }, | 938 | }, |
| ... | @@ -1366,8 +1373,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1366,8 +1373,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1366 | } | 1373 | } |
| 1367 | 1374 | ||
| 1368 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { | 1375 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| 1369 | const reg = try self.register_manager.allocReg(null, &.{}); | 1376 | const reg = try self.copyToTmpRegister(index_ty, index); |
| 1370 | try self.genSetReg(index_ty, reg, index); | ||
| 1371 | try self.genIMulOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size }); | 1377 | try self.genIMulOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size }); |
| 1372 | return reg; | 1378 | return reg; |
| 1373 | } | 1379 | } |
| ... | @@ -1376,16 +1382,26 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1376,16 +1382,26 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1376 | const is_volatile = false; // TODO | 1382 | const is_volatile = false; // TODO |
| 1377 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1383 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1378 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { | 1384 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { |
| 1379 | const slice_mcv = try self.resolveInst(bin_op.lhs); | ||
| 1380 | const slice_ty = self.air.typeOf(bin_op.lhs); | 1385 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 1386 | const slice_mcv = try self.resolveInst(bin_op.lhs); | ||
| 1387 | slice_mcv.freezeIfRegister(&self.register_manager); | ||
| 1388 | defer slice_mcv.unfreezeIfRegister(&self.register_manager); | ||
| 1389 | |||
| 1381 | const elem_ty = slice_ty.childType(); | 1390 | const elem_ty = slice_ty.childType(); |
| 1382 | const elem_size = elem_ty.abiSize(self.target.*); | 1391 | const elem_size = elem_ty.abiSize(self.target.*); |
| 1383 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1392 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1384 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | 1393 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| 1394 | |||
| 1385 | const index_ty = self.air.typeOf(bin_op.rhs); | 1395 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 1386 | const index_mcv = try self.resolveInst(bin_op.rhs); | 1396 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 1397 | index_mcv.freezeIfRegister(&self.register_manager); | ||
| 1398 | defer index_mcv.unfreezeIfRegister(&self.register_manager); | ||
| 1399 | |||
| 1387 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); | 1400 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); |
| 1388 | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); | 1401 | self.register_manager.freezeRegs(&.{offset_reg}); |
| 1402 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); | ||
| 1403 | |||
| 1404 | const addr_reg = try self.register_manager.allocReg(null); | ||
| 1389 | switch (slice_mcv) { | 1405 | switch (slice_mcv) { |
| 1390 | .stack_offset => |off| { | 1406 | .stack_offset => |off| { |
| 1391 | // mov reg, [rbp - 8] | 1407 | // mov reg, [rbp - 8] |
| ... | @@ -1401,7 +1417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1401,7 +1417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1401 | }, | 1417 | }, |
| 1402 | else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}), | 1418 | else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}), |
| 1403 | } | 1419 | } |
| 1404 | // TODO we could allocate register here, but need to except addr register and potentially | 1420 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 1405 | // offset register. | 1421 | // offset register. |
| 1406 | const dst_mcv = try self.allocRegOrMem(inst, false); | 1422 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1407 | try self.genBinMathOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg.to64() }, .{ | 1423 | try self.genBinMathOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg.to64() }, .{ |
| ... | @@ -1427,14 +1443,23 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1427,14 +1443,23 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1427 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1443 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1428 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1444 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1429 | const array_ty = self.air.typeOf(bin_op.lhs); | 1445 | const array_ty = self.air.typeOf(bin_op.lhs); |
| 1430 | const array = try self.resolveInst(bin_op.lhs); | ||
| 1431 | const array_abi_size = array_ty.abiSize(self.target.*); | 1446 | const array_abi_size = array_ty.abiSize(self.target.*); |
| 1447 | const array = try self.resolveInst(bin_op.lhs); | ||
| 1448 | array.freezeIfRegister(&self.register_manager); | ||
| 1449 | defer array.unfreezeIfRegister(&self.register_manager); | ||
| 1450 | |||
| 1432 | const elem_ty = array_ty.childType(); | 1451 | const elem_ty = array_ty.childType(); |
| 1433 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 1452 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 1434 | const index_ty = self.air.typeOf(bin_op.rhs); | 1453 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 1435 | const index = try self.resolveInst(bin_op.rhs); | 1454 | const index = try self.resolveInst(bin_op.rhs); |
| 1455 | index.freezeIfRegister(&self.register_manager); | ||
| 1456 | defer index.unfreezeIfRegister(&self.register_manager); | ||
| 1457 | |||
| 1436 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); | 1458 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 1437 | const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); | 1459 | self.register_manager.freezeRegs(&.{offset_reg}); |
| 1460 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); | ||
| 1461 | |||
| 1462 | const addr_reg = try self.register_manager.allocReg(null); | ||
| 1438 | switch (array) { | 1463 | switch (array) { |
| 1439 | .stack_offset => |off| { | 1464 | .stack_offset => |off| { |
| 1440 | // lea reg, [rbp] | 1465 | // lea reg, [rbp] |
| ... | @@ -1449,7 +1474,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1449,7 +1474,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1449 | }, | 1474 | }, |
| 1450 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), | 1475 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), |
| 1451 | } | 1476 | } |
| 1452 | // TODO we could allocate register here, but need to except addr register and potentially | 1477 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 1453 | // offset register. | 1478 | // offset register. |
| 1454 | const dst_mcv = try self.allocRegOrMem(inst, false); | 1479 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 1455 | try self.genBinMathOpMir(.add, array_ty, .{ .register = addr_reg.to64() }, .{ .register = offset_reg.to64() }); | 1480 | try self.genBinMathOpMir(.add, array_ty, .{ .register = addr_reg.to64() }, .{ .register = offset_reg.to64() }); |
| ... | @@ -1475,12 +1500,17 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1475,12 +1500,17 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1475 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1500 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1476 | const ptr_ty = self.air.typeOf(extra.lhs); | 1501 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 1477 | const ptr = try self.resolveInst(extra.lhs); | 1502 | const ptr = try self.resolveInst(extra.lhs); |
| 1503 | ptr.freezeIfRegister(&self.register_manager); | ||
| 1504 | defer ptr.unfreezeIfRegister(&self.register_manager); | ||
| 1505 | |||
| 1478 | const elem_ty = ptr_ty.elemType2(); | 1506 | const elem_ty = ptr_ty.elemType2(); |
| 1479 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 1507 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 1480 | const index_ty = self.air.typeOf(extra.rhs); | 1508 | const index_ty = self.air.typeOf(extra.rhs); |
| 1481 | const index = try self.resolveInst(extra.rhs); | 1509 | const index = try self.resolveInst(extra.rhs); |
| 1482 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); | 1510 | index.freezeIfRegister(&self.register_manager); |
| 1511 | defer index.unfreezeIfRegister(&self.register_manager); | ||
| 1483 | 1512 | ||
| 1513 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); | ||
| 1484 | self.register_manager.freezeRegs(&.{offset_reg}); | 1514 | self.register_manager.freezeRegs(&.{offset_reg}); |
| 1485 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); | 1515 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 1486 | 1516 | ||
| ... | @@ -1587,6 +1617,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1587,6 +1617,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1587 | return self.fail("TODO implement loading from MCValue.embedded_in_code", .{}); | 1617 | return self.fail("TODO implement loading from MCValue.embedded_in_code", .{}); |
| 1588 | }, | 1618 | }, |
| 1589 | .register => |reg| { | 1619 | .register => |reg| { |
| 1620 | self.register_manager.freezeRegs(&.{reg}); | ||
| 1621 | defer self.register_manager.unfreezeRegs(&.{reg}); | ||
| 1622 | |||
| 1590 | switch (dst_mcv) { | 1623 | switch (dst_mcv) { |
| 1591 | .dead => unreachable, | 1624 | .dead => unreachable, |
| 1592 | .undef => unreachable, | 1625 | .undef => unreachable, |
| ... | @@ -1607,16 +1640,15 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1607,16 +1640,15 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1607 | }, | 1640 | }, |
| 1608 | .stack_offset => |off| { | 1641 | .stack_offset => |off| { |
| 1609 | if (abi_size <= 8) { | 1642 | if (abi_size <= 8) { |
| 1610 | const tmp_reg = try self.register_manager.allocReg(null, &.{reg}); | 1643 | const tmp_reg = try self.register_manager.allocReg(null); |
| 1611 | try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); | 1644 | try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); |
| 1612 | return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); | 1645 | return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); |
| 1613 | } | 1646 | } |
| 1614 | 1647 | ||
| 1615 | const regs = try self.register_manager.allocRegs( | 1648 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 1616 | 3, | 1649 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 1617 | .{ null, null, null }, | 1650 | |
| 1618 | &.{ reg, .rax, .rcx }, | 1651 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }); |
| 1619 | ); | ||
| 1620 | const addr_reg = regs[0]; | 1652 | const addr_reg = regs[0]; |
| 1621 | const count_reg = regs[1]; | 1653 | const count_reg = regs[1]; |
| 1622 | const tmp_reg = regs[2]; | 1654 | const tmp_reg = regs[2]; |
| ... | @@ -1634,7 +1666,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1634,7 +1666,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1634 | try self.register_manager.getReg(.rcx, null); | 1666 | try self.register_manager.getReg(.rcx, null); |
| 1635 | 1667 | ||
| 1636 | // TODO allow for abi size to be u64 | 1668 | // TODO allow for abi size to be u64 |
| 1637 | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); | 1669 | try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) }); |
| 1638 | 1670 | ||
| 1639 | return self.genInlineMemcpy( | 1671 | return self.genInlineMemcpy( |
| 1640 | -(off + @intCast(i32, abi_size)), | 1672 | -(off + @intCast(i32, abi_size)), |
| ... | @@ -1786,8 +1818,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1786,8 +1818,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1786 | // TODO: in case the address fits in an imm32 we can use [ds:imm32] | 1818 | // TODO: in case the address fits in an imm32 we can use [ds:imm32] |
| 1787 | // instead of wasting an instruction copying the address to a register | 1819 | // instead of wasting an instruction copying the address to a register |
| 1788 | 1820 | ||
| 1789 | if (value.isRegister()) self.register_manager.freezeRegs(&.{value.register}); | 1821 | value.freezeIfRegister(&self.register_manager); |
| 1790 | defer if (value.isRegister()) self.register_manager.unfreezeRegs(&.{value.register}); | 1822 | defer value.unfreezeIfRegister(&self.register_manager); |
| 1791 | 1823 | ||
| 1792 | const addr_reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr }); | 1824 | const addr_reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr }); |
| 1793 | // to get the actual address of the value we want to modify we have to go through the GOT | 1825 | // to get the actual address of the value we want to modify we have to go through the GOT |
| ... | @@ -1925,7 +1957,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde | ... | @@ -1925,7 +1957,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 1925 | break :blk reg; | 1957 | break :blk reg; |
| 1926 | } else { | 1958 | } else { |
| 1927 | self.register_manager.freezeRegs(&.{reg}); | 1959 | self.register_manager.freezeRegs(&.{reg}); |
| 1928 | const result_reg = try self.register_manager.allocReg(inst, &.{}); | 1960 | const result_reg = try self.register_manager.allocReg(inst); |
| 1929 | try self.genSetReg(ptr_ty, result_reg, mcv); | 1961 | try self.genSetReg(ptr_ty, result_reg, mcv); |
| 1930 | break :blk result_reg; | 1962 | break :blk result_reg; |
| 1931 | } | 1963 | } |
| ... | @@ -2012,22 +2044,16 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -2012,22 +2044,16 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 2012 | } | 2044 | } |
| 2013 | } else { | 2045 | } else { |
| 2014 | if (lhs.isMemory()) { | 2046 | if (lhs.isMemory()) { |
| 2015 | dst_mcv = if (rhs.isRegister()) | 2047 | rhs.freezeIfRegister(&self.register_manager); |
| 2016 | // If the allocated register is the same as the rhs register, don't allocate that one | 2048 | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 2017 | // and instead spill a subsequent one. Otherwise, this can result in a miscompilation | 2049 | |
| 2018 | // in the presence of several binary operations performed in a single block. | 2050 | dst_mcv = try self.copyToNewRegister(inst, dst_ty, lhs); |
| 2019 | try self.copyToNewRegisterWithExceptions(inst, dst_ty, lhs, &.{rhs.register}) | ||
| 2020 | else | ||
| 2021 | try self.copyToNewRegister(inst, dst_ty, lhs); | ||
| 2022 | src_mcv = rhs; | 2051 | src_mcv = rhs; |
| 2023 | } else { | 2052 | } else { |
| 2024 | dst_mcv = if (lhs.isRegister()) | 2053 | lhs.freezeIfRegister(&self.register_manager); |
| 2025 | // If the allocated register is the same as the rhs register, don't allocate that one | 2054 | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 2026 | // and instead spill a subsequent one. Otherwise, this can result in a miscompilation | 2055 | |
| 2027 | // in the presence of several binary operations performed in a single block. | 2056 | dst_mcv = try self.copyToNewRegister(inst, dst_ty, rhs); |
| 2028 | try self.copyToNewRegisterWithExceptions(inst, dst_ty, rhs, &.{lhs.register}) | ||
| 2029 | else | ||
| 2030 | try self.copyToNewRegister(inst, dst_ty, rhs); | ||
| 2031 | src_mcv = lhs; | 2057 | src_mcv = lhs; |
| 2032 | } | 2058 | } |
| 2033 | } | 2059 | } |
| ... | @@ -2039,7 +2065,11 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -2039,7 +2065,11 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 2039 | switch (src_mcv) { | 2065 | switch (src_mcv) { |
| 2040 | .immediate => |imm| { | 2066 | .immediate => |imm| { |
| 2041 | if (imm > math.maxInt(u31)) { | 2067 | if (imm > math.maxInt(u31)) { |
| 2042 | src_mcv = MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.u64), src_mcv) }; | 2068 | dst_mcv.freezeIfRegister(&self.register_manager); |
| 2069 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); | ||
| 2070 | |||
| 2071 | const tmp_reg = try self.copyToTmpRegister(Type.u64, src_mcv); | ||
| 2072 | src_mcv = MCValue{ .register = tmp_reg }; | ||
| 2043 | } | 2073 | } |
| 2044 | }, | 2074 | }, |
| 2045 | else => {}, | 2075 | else => {}, |
| ... | @@ -2901,6 +2931,8 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2901,6 +2931,8 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2901 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2931 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2902 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2932 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2903 | const operand_ptr = try self.resolveInst(un_op); | 2933 | const operand_ptr = try self.resolveInst(un_op); |
| 2934 | operand_ptr.freezeIfRegister(&self.register_manager); | ||
| 2935 | defer operand_ptr.unfreezeIfRegister(&self.register_manager); | ||
| 2904 | const operand: MCValue = blk: { | 2936 | const operand: MCValue = blk: { |
| 2905 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 2937 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2906 | // The MCValue that holds the pointer can be re-used as the value. | 2938 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | @@ -2930,6 +2962,8 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2930,6 +2962,8 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2930 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2962 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2931 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2963 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2932 | const operand_ptr = try self.resolveInst(un_op); | 2964 | const operand_ptr = try self.resolveInst(un_op); |
| 2965 | operand_ptr.freezeIfRegister(&self.register_manager); | ||
| 2966 | defer operand_ptr.unfreezeIfRegister(&self.register_manager); | ||
| 2933 | const operand: MCValue = blk: { | 2967 | const operand: MCValue = blk: { |
| 2934 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 2968 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2935 | // The MCValue that holds the pointer can be re-used as the value. | 2969 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | @@ -2959,6 +2993,8 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2959,6 +2993,8 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2959 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2993 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2960 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2994 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2961 | const operand_ptr = try self.resolveInst(un_op); | 2995 | const operand_ptr = try self.resolveInst(un_op); |
| 2996 | operand_ptr.freezeIfRegister(&self.register_manager); | ||
| 2997 | defer operand_ptr.unfreezeIfRegister(&self.register_manager); | ||
| 2962 | const operand: MCValue = blk: { | 2998 | const operand: MCValue = blk: { |
| 2963 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 2999 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2964 | // The MCValue that holds the pointer can be re-used as the value. | 3000 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | @@ -2988,6 +3024,8 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2988,6 +3024,8 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2988 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 3024 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2989 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3025 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2990 | const operand_ptr = try self.resolveInst(un_op); | 3026 | const operand_ptr = try self.resolveInst(un_op); |
| 3027 | operand_ptr.freezeIfRegister(&self.register_manager); | ||
| 3028 | defer operand_ptr.unfreezeIfRegister(&self.register_manager); | ||
| 2991 | const operand: MCValue = blk: { | 3029 | const operand: MCValue = blk: { |
| 2992 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 3030 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2993 | // The MCValue that holds the pointer can be re-used as the value. | 3031 | // The MCValue that holds the pointer can be re-used as the value. |
| ... | @@ -3345,7 +3383,10 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -3345,7 +3383,10 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3345 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); | 3383 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 3346 | } | 3384 | } |
| 3347 | 3385 | ||
| 3348 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx }); | 3386 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 3387 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); | ||
| 3388 | |||
| 3389 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }); | ||
| 3349 | const addr_reg = regs[0]; | 3390 | const addr_reg = regs[0]; |
| 3350 | const count_reg = regs[1]; | 3391 | const count_reg = regs[1]; |
| 3351 | const tmp_reg = regs[2]; | 3392 | const tmp_reg = regs[2]; |
| ... | @@ -3363,7 +3404,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -3363,7 +3404,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3363 | }); | 3404 | }); |
| 3364 | 3405 | ||
| 3365 | // TODO allow for abi_size to be u64 | 3406 | // TODO allow for abi_size to be u64 |
| 3366 | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); | 3407 | try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) }); |
| 3367 | try self.genInlineMemcpy( | 3408 | try self.genInlineMemcpy( |
| 3368 | -(stack_offset + @intCast(i32, abi_size)), | 3409 | -(stack_offset + @intCast(i32, abi_size)), |
| 3369 | .rsp, | 3410 | .rsp, |
| ... | @@ -3510,7 +3551,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro | ... | @@ -3510,7 +3551,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3510 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 3551 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3511 | } | 3552 | } |
| 3512 | 3553 | ||
| 3513 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx, .rbp }); | 3554 | self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp }); |
| 3555 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp }); | ||
| 3556 | |||
| 3557 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }); | ||
| 3514 | const addr_reg = regs[0]; | 3558 | const addr_reg = regs[0]; |
| 3515 | const count_reg = regs[1]; | 3559 | const count_reg = regs[1]; |
| 3516 | const tmp_reg = regs[2]; | 3560 | const tmp_reg = regs[2]; |
| ... | @@ -3528,7 +3572,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro | ... | @@ -3528,7 +3572,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3528 | }); | 3572 | }); |
| 3529 | 3573 | ||
| 3530 | // TODO allow for abi_size to be u64 | 3574 | // TODO allow for abi_size to be u64 |
| 3531 | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); | 3575 | try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) }); |
| 3532 | 3576 | ||
| 3533 | return self.genInlineMemcpy( | 3577 | return self.genInlineMemcpy( |
| 3534 | -(stack_offset + @intCast(i32, abi_size)), | 3578 | -(stack_offset + @intCast(i32, abi_size)), |
src/register_manager.zig+18-60| ... | @@ -118,17 +118,12 @@ pub fn RegisterManager( | ... | @@ -118,17 +118,12 @@ pub fn RegisterManager( |
| 118 | /// Allocates a specified number of registers, optionally | 118 | /// Allocates a specified number of registers, optionally |
| 119 | /// tracking them. Returns `null` if not enough registers are | 119 | /// tracking them. Returns `null` if not enough registers are |
| 120 | /// free. | 120 | /// free. |
| 121 | /// | ||
| 122 | /// Exceptions are deprecated, use freezeRegs and unfreezeRegs | ||
| 123 | /// instead. | ||
| 124 | pub fn tryAllocRegs( | 121 | pub fn tryAllocRegs( |
| 125 | self: *Self, | 122 | self: *Self, |
| 126 | comptime count: comptime_int, | 123 | comptime count: comptime_int, |
| 127 | insts: [count]?Air.Inst.Index, | 124 | insts: [count]?Air.Inst.Index, |
| 128 | exceptions: []const Register, | ||
| 129 | ) ?[count]Register { | 125 | ) ?[count]Register { |
| 130 | comptime assert(count > 0 and count <= callee_preserved_regs.len); | 126 | comptime assert(count > 0 and count <= callee_preserved_regs.len); |
| 131 | assert(count + exceptions.len <= callee_preserved_regs.len); | ||
| 132 | 127 | ||
| 133 | const free_registers = @popCount(FreeRegInt, self.free_registers); | 128 | const free_registers = @popCount(FreeRegInt, self.free_registers); |
| 134 | if (free_registers < count) return null; | 129 | if (free_registers < count) return null; |
| ... | @@ -137,7 +132,6 @@ pub fn RegisterManager( | ... | @@ -137,7 +132,6 @@ pub fn RegisterManager( |
| 137 | var i: usize = 0; | 132 | var i: usize = 0; |
| 138 | for (callee_preserved_regs) |reg| { | 133 | for (callee_preserved_regs) |reg| { |
| 139 | if (i >= count) break; | 134 | if (i >= count) break; |
| 140 | if (mem.indexOfScalar(Register, exceptions, reg) != null) continue; | ||
| 141 | if (self.isRegFrozen(reg)) continue; | 135 | if (self.isRegFrozen(reg)) continue; |
| 142 | if (self.isRegFree(reg)) { | 136 | if (self.isRegFree(reg)) { |
| 143 | regs[i] = reg; | 137 | regs[i] = reg; |
| ... | @@ -163,29 +157,21 @@ pub fn RegisterManager( | ... | @@ -163,29 +157,21 @@ pub fn RegisterManager( |
| 163 | /// Allocates a register and optionally tracks it with a | 157 | /// Allocates a register and optionally tracks it with a |
| 164 | /// corresponding instruction. Returns `null` if all registers | 158 | /// corresponding instruction. Returns `null` if all registers |
| 165 | /// are allocated. | 159 | /// are allocated. |
| 166 | /// | 160 | pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index) ?Register { |
| 167 | /// Exceptions are deprecated, use freezeRegs and unfreezeRegs | 161 | return if (tryAllocRegs(self, 1, .{inst})) |regs| regs[0] else null; |
| 168 | /// instead. | ||
| 169 | pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index, exceptions: []const Register) ?Register { | ||
| 170 | return if (tryAllocRegs(self, 1, .{inst}, exceptions)) |regs| regs[0] else null; | ||
| 171 | } | 162 | } |
| 172 | 163 | ||
| 173 | /// Allocates a specified number of registers, optionally | 164 | /// Allocates a specified number of registers, optionally |
| 174 | /// tracking them. Asserts that count + exceptions.len is not | 165 | /// tracking them. Asserts that count is not |
| 175 | /// larger than the total number of registers available. | 166 | /// larger than the total number of registers available. |
| 176 | /// | ||
| 177 | /// Exceptions are deprecated, use freezeRegs and unfreezeRegs | ||
| 178 | /// instead. | ||
| 179 | pub fn allocRegs( | 167 | pub fn allocRegs( |
| 180 | self: *Self, | 168 | self: *Self, |
| 181 | comptime count: comptime_int, | 169 | comptime count: comptime_int, |
| 182 | insts: [count]?Air.Inst.Index, | 170 | insts: [count]?Air.Inst.Index, |
| 183 | exceptions: []const Register, | ||
| 184 | ) ![count]Register { | 171 | ) ![count]Register { |
| 185 | comptime assert(count > 0 and count <= callee_preserved_regs.len); | 172 | comptime assert(count > 0 and count <= callee_preserved_regs.len); |
| 186 | assert(count + exceptions.len <= callee_preserved_regs.len); | ||
| 187 | 173 | ||
| 188 | const result = self.tryAllocRegs(count, insts, exceptions) orelse blk: { | 174 | const result = self.tryAllocRegs(count, insts) orelse blk: { |
| 189 | // We'll take over the first count registers. Spill | 175 | // We'll take over the first count registers. Spill |
| 190 | // the instructions that were previously there to a | 176 | // the instructions that were previously there to a |
| 191 | // stack allocations. | 177 | // stack allocations. |
| ... | @@ -193,7 +179,6 @@ pub fn RegisterManager( | ... | @@ -193,7 +179,6 @@ pub fn RegisterManager( |
| 193 | var i: usize = 0; | 179 | var i: usize = 0; |
| 194 | for (callee_preserved_regs) |reg| { | 180 | for (callee_preserved_regs) |reg| { |
| 195 | if (i >= count) break; | 181 | if (i >= count) break; |
| 196 | if (mem.indexOfScalar(Register, exceptions, reg) != null) continue; | ||
| 197 | if (self.isRegFrozen(reg)) continue; | 182 | if (self.isRegFrozen(reg)) continue; |
| 198 | 183 | ||
| 199 | regs[i] = reg; | 184 | regs[i] = reg; |
| ... | @@ -229,11 +214,8 @@ pub fn RegisterManager( | ... | @@ -229,11 +214,8 @@ pub fn RegisterManager( |
| 229 | 214 | ||
| 230 | /// Allocates a register and optionally tracks it with a | 215 | /// Allocates a register and optionally tracks it with a |
| 231 | /// corresponding instruction. | 216 | /// corresponding instruction. |
| 232 | /// | 217 | pub fn allocReg(self: *Self, inst: ?Air.Inst.Index) !Register { |
| 233 | /// Exceptions are deprecated, use freezeRegs and unfreezeRegs | 218 | return (try self.allocRegs(1, .{inst}))[0]; |
| 234 | /// instead. | ||
| 235 | pub fn allocReg(self: *Self, inst: ?Air.Inst.Index, exceptions: []const Register) !Register { | ||
| 236 | return (try self.allocRegs(1, .{inst}, exceptions))[0]; | ||
| 237 | } | 219 | } |
| 238 | 220 | ||
| 239 | /// Spills the register if it is currently allocated. If a | 221 | /// Spills the register if it is currently allocated. If a |
| ... | @@ -365,9 +347,9 @@ test "tryAllocReg: no spilling" { | ... | @@ -365,9 +347,9 @@ test "tryAllocReg: no spilling" { |
| 365 | 347 | ||
| 366 | const mock_instruction: Air.Inst.Index = 1; | 348 | const mock_instruction: Air.Inst.Index = 1; |
| 367 | 349 | ||
| 368 | try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction, &.{})); | 350 | try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction)); |
| 369 | try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction, &.{})); | 351 | try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction)); |
| 370 | try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction, &.{})); | 352 | try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction)); |
| 371 | 353 | ||
| 372 | try expect(function.register_manager.isRegAllocated(.r2)); | 354 | try expect(function.register_manager.isRegAllocated(.r2)); |
| 373 | try expect(function.register_manager.isRegAllocated(.r3)); | 355 | try expect(function.register_manager.isRegAllocated(.r3)); |
| ... | @@ -393,33 +375,25 @@ test "allocReg: spilling" { | ... | @@ -393,33 +375,25 @@ test "allocReg: spilling" { |
| 393 | 375 | ||
| 394 | const mock_instruction: Air.Inst.Index = 1; | 376 | const mock_instruction: Air.Inst.Index = 1; |
| 395 | 377 | ||
| 396 | try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction, &.{})); | 378 | try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction)); |
| 397 | try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{})); | 379 | try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction)); |
| 398 | 380 | ||
| 399 | // Spill a register | 381 | // Spill a register |
| 400 | try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction, &.{})); | 382 | try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction)); |
| 401 | try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items); | 383 | try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items); |
| 402 | 384 | ||
| 403 | // No spilling necessary | 385 | // No spilling necessary |
| 404 | function.register_manager.freeReg(.r3); | 386 | function.register_manager.freeReg(.r3); |
| 405 | try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{})); | 387 | try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction)); |
| 406 | try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items); | 388 | try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items); |
| 407 | 389 | ||
| 408 | // Exceptions | ||
| 409 | // | ||
| 410 | // TODO deprecated, remove test once no backend uses exceptions | ||
| 411 | // anymore | ||
| 412 | function.register_manager.freeReg(.r2); | ||
| 413 | function.register_manager.freeReg(.r3); | ||
| 414 | try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{.r2})); | ||
| 415 | |||
| 416 | // Frozen registers | 390 | // Frozen registers |
| 417 | function.register_manager.freeReg(.r3); | 391 | function.register_manager.freeReg(.r3); |
| 418 | { | 392 | { |
| 419 | function.register_manager.freezeRegs(&.{.r2}); | 393 | function.register_manager.freezeRegs(&.{.r2}); |
| 420 | defer function.register_manager.unfreezeRegs(&.{.r2}); | 394 | defer function.register_manager.unfreezeRegs(&.{.r2}); |
| 421 | 395 | ||
| 422 | try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{})); | 396 | try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction)); |
| 423 | } | 397 | } |
| 424 | try expect(!function.register_manager.frozenRegsExist()); | 398 | try expect(!function.register_manager.frozenRegsExist()); |
| 425 | } | 399 | } |
| ... | @@ -432,22 +406,13 @@ test "tryAllocRegs" { | ... | @@ -432,22 +406,13 @@ test "tryAllocRegs" { |
| 432 | }; | 406 | }; |
| 433 | defer function.deinit(); | 407 | defer function.deinit(); |
| 434 | 408 | ||
| 435 | try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?); | 409 | try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }).?); |
| 436 | 410 | ||
| 437 | try expect(function.register_manager.isRegAllocated(.r0)); | 411 | try expect(function.register_manager.isRegAllocated(.r0)); |
| 438 | try expect(function.register_manager.isRegAllocated(.r1)); | 412 | try expect(function.register_manager.isRegAllocated(.r1)); |
| 439 | try expect(function.register_manager.isRegAllocated(.r2)); | 413 | try expect(function.register_manager.isRegAllocated(.r2)); |
| 440 | try expect(!function.register_manager.isRegAllocated(.r3)); | 414 | try expect(!function.register_manager.isRegAllocated(.r3)); |
| 441 | 415 | ||
| 442 | // Exceptions | ||
| 443 | // | ||
| 444 | // TODO deprecated, remove test once no backend uses exceptions | ||
| 445 | // anymore | ||
| 446 | function.register_manager.freeReg(.r0); | ||
| 447 | function.register_manager.freeReg(.r1); | ||
| 448 | function.register_manager.freeReg(.r2); | ||
| 449 | try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{.r1}).?); | ||
| 450 | |||
| 451 | // Frozen registers | 416 | // Frozen registers |
| 452 | function.register_manager.freeReg(.r0); | 417 | function.register_manager.freeReg(.r0); |
| 453 | function.register_manager.freeReg(.r2); | 418 | function.register_manager.freeReg(.r2); |
| ... | @@ -456,7 +421,7 @@ test "tryAllocRegs" { | ... | @@ -456,7 +421,7 @@ test "tryAllocRegs" { |
| 456 | function.register_manager.freezeRegs(&.{.r1}); | 421 | function.register_manager.freezeRegs(&.{.r1}); |
| 457 | defer function.register_manager.unfreezeRegs(&.{.r1}); | 422 | defer function.register_manager.unfreezeRegs(&.{.r1}); |
| 458 | 423 | ||
| 459 | try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?); | 424 | try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }).?); |
| 460 | } | 425 | } |
| 461 | try expect(!function.register_manager.frozenRegsExist()); | 426 | try expect(!function.register_manager.frozenRegsExist()); |
| 462 | 427 | ||
| ... | @@ -480,20 +445,13 @@ test "allocRegs" { | ... | @@ -480,20 +445,13 @@ test "allocRegs" { |
| 480 | mock_instruction, | 445 | mock_instruction, |
| 481 | mock_instruction, | 446 | mock_instruction, |
| 482 | mock_instruction, | 447 | mock_instruction, |
| 483 | }, &.{})); | 448 | })); |
| 484 | 449 | ||
| 485 | try expect(function.register_manager.isRegAllocated(.r0)); | 450 | try expect(function.register_manager.isRegAllocated(.r0)); |
| 486 | try expect(function.register_manager.isRegAllocated(.r1)); | 451 | try expect(function.register_manager.isRegAllocated(.r1)); |
| 487 | try expect(function.register_manager.isRegAllocated(.r2)); | 452 | try expect(function.register_manager.isRegAllocated(.r2)); |
| 488 | try expect(!function.register_manager.isRegAllocated(.r3)); | 453 | try expect(!function.register_manager.isRegAllocated(.r3)); |
| 489 | 454 | ||
| 490 | // Exceptions | ||
| 491 | // | ||
| 492 | // TODO deprecated, remove test once no backend uses exceptions | ||
| 493 | // anymore | ||
| 494 | try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }, &.{.r1})); | ||
| 495 | try expectEqualSlices(MockRegister2, &[_]MockRegister2{ .r0, .r2 }, function.spilled.items); | ||
| 496 | |||
| 497 | // Frozen registers | 455 | // Frozen registers |
| 498 | function.register_manager.freeReg(.r0); | 456 | function.register_manager.freeReg(.r0); |
| 499 | function.register_manager.freeReg(.r2); | 457 | function.register_manager.freeReg(.r2); |
| ... | @@ -502,7 +460,7 @@ test "allocRegs" { | ... | @@ -502,7 +460,7 @@ test "allocRegs" { |
| 502 | function.register_manager.freezeRegs(&.{.r1}); | 460 | function.register_manager.freezeRegs(&.{.r1}); |
| 503 | defer function.register_manager.unfreezeRegs(&.{.r1}); | 461 | defer function.register_manager.unfreezeRegs(&.{.r1}); |
| 504 | 462 | ||
| 505 | try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }, &.{})); | 463 | try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null })); |
| 506 | } | 464 | } |
| 507 | try expect(!function.register_manager.frozenRegsExist()); | 465 | try expect(!function.register_manager.frozenRegsExist()); |
| 508 | 466 |