authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-03 18:08:29+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-03 18:08:29+01:00
log74a01e3d64cc5d941486e5bd037f6f55e030339c
tree9cdbe1d2c262d78e9bfec6dff5c4167e216fcaf4
parente0b1170b676c04d1293970c717e13bdc01584671

stage2: remove the concept of register exceptions


5 files changed, 74 insertions(+), 116 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.
799fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {799fn 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.
808fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {808fn 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});
12761276
...@@ -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 }
17421742
1743 // Move the operands to the newly allocated registers1743 // 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.
793fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {793fn 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.
802fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {802fn 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});
12481248
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});
12531253
...@@ -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);
12871287
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});
12911291
...@@ -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});
14431443
...@@ -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 // larger1451 // larger
14521452
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);
14571457
...@@ -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 allocation1477 // 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);
14811481
...@@ -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});
15301530
...@@ -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});
16031603
...@@ -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 registers1775 // 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 registers1782 // 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 registers1791 // 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 register1796 // 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 register1800 // 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 register1804 // 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 immediate1813 // 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 immediate1821 // 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 }
18281828
...@@ -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 registers1984 // 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 registers1991 // 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 registers1998 // 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 register2002 // 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 register2006 // 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 register2010 // 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 destination2056 // Allocate registers for operands and/or destination
2057 if (reuse_lhs) {2057 if (reuse_lhs) {
2058 // Allocate 1 register2058 // 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 registers2062 // Allocate 1 or 2 registers
2063 if (lhs_is_register) {2063 if (lhs_is_register) {
2064 // Move RHS to register2064 // 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 register2068 // 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 }
24512451
...@@ -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 allocation3187 // 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.
774fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {774fn 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.
783fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {783fn 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});
12171217
src/arch/x86_64/CodeGen.zig+11-11
...@@ -819,7 +819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -819,7 +819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
819 const ptr_bits = self.target.cpu.arch.ptrBitWidth();819 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
820 const ptr_bytes: u64 = @divExact(ptr_bits, 8);820 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
821 if (abi_size <= ptr_bytes) {821 if (abi_size <= ptr_bytes) {
822 if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {822 if (self.register_manager.tryAllocReg(inst)) |reg| {
823 return MCValue{ .register = registerAlias(reg, abi_size) };823 return MCValue{ .register = registerAlias(reg, abi_size) };
824 }824 }
825 }825 }
...@@ -842,7 +842,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -842,7 +842,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
842/// allocated. A second call to `copyToTmpRegister` may return the same register.842/// allocated. A second call to `copyToTmpRegister` may return the same register.
843/// 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.
844fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {844fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
845 const reg = try self.register_manager.allocReg(null, &.{});845 const reg = try self.register_manager.allocReg(null);
846 try self.genSetReg(ty, reg, mcv);846 try self.genSetReg(ty, reg, mcv);
847 return reg;847 return reg;
848}848}
...@@ -851,7 +851,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {...@@ -851,7 +851,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
851/// `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.
852/// 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.
853fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {853fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {
854 const reg = try self.register_manager.allocReg(reg_owner, &.{});854 const reg = try self.register_manager.allocReg(reg_owner);
855 try self.genSetReg(ty, reg, mcv);855 try self.genSetReg(ty, reg, mcv);
856 return MCValue{ .register = reg };856 return MCValue{ .register = reg };
857}857}
...@@ -932,7 +932,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {...@@ -932,7 +932,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
932 const reg = switch (operand) {932 const reg = switch (operand) {
933 .register => |reg| reg,933 .register => |reg| reg,
934 else => inner: {934 else => inner: {
935 const reg = try self.register_manager.allocReg(inst, &.{});935 const reg = try self.register_manager.allocReg(inst);
936 try self.genSetReg(src_ty, reg, operand);936 try self.genSetReg(src_ty, reg, operand);
937 break :inner reg;937 break :inner reg;
938 },938 },
...@@ -1401,7 +1401,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1401,7 +1401,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1401 self.register_manager.freezeRegs(&.{offset_reg});1401 self.register_manager.freezeRegs(&.{offset_reg});
1402 defer self.register_manager.unfreezeRegs(&.{offset_reg});1402 defer self.register_manager.unfreezeRegs(&.{offset_reg});
14031403
1404 const addr_reg = try self.register_manager.allocReg(null, &.{});1404 const addr_reg = try self.register_manager.allocReg(null);
1405 switch (slice_mcv) {1405 switch (slice_mcv) {
1406 .stack_offset => |off| {1406 .stack_offset => |off| {
1407 // mov reg, [rbp - 8]1407 // mov reg, [rbp - 8]
...@@ -1459,7 +1459,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1459,7 +1459,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1459 self.register_manager.freezeRegs(&.{offset_reg});1459 self.register_manager.freezeRegs(&.{offset_reg});
1460 defer self.register_manager.unfreezeRegs(&.{offset_reg});1460 defer self.register_manager.unfreezeRegs(&.{offset_reg});
14611461
1462 const addr_reg = try self.register_manager.allocReg(null, &.{});1462 const addr_reg = try self.register_manager.allocReg(null);
1463 switch (array) {1463 switch (array) {
1464 .stack_offset => |off| {1464 .stack_offset => |off| {
1465 // lea reg, [rbp]1465 // lea reg, [rbp]
...@@ -1640,7 +1640,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1640,7 +1640,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1640 },1640 },
1641 .stack_offset => |off| {1641 .stack_offset => |off| {
1642 if (abi_size <= 8) {1642 if (abi_size <= 8) {
1643 const tmp_reg = try self.register_manager.allocReg(null, &.{});1643 const tmp_reg = try self.register_manager.allocReg(null);
1644 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);1644 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
1645 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });1645 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
1646 }1646 }
...@@ -1648,7 +1648,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1648,7 +1648,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1648 self.register_manager.freezeRegs(&.{ .rax, .rcx });1648 self.register_manager.freezeRegs(&.{ .rax, .rcx });
1649 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });1649 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
16501650
1651 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{});1651 const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
1652 const addr_reg = regs[0];1652 const addr_reg = regs[0];
1653 const count_reg = regs[1];1653 const count_reg = regs[1];
1654 const tmp_reg = regs[2];1654 const tmp_reg = regs[2];
...@@ -1957,7 +1957,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -1957,7 +1957,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
1957 break :blk reg;1957 break :blk reg;
1958 } else {1958 } else {
1959 self.register_manager.freezeRegs(&.{reg});1959 self.register_manager.freezeRegs(&.{reg});
1960 const result_reg = try self.register_manager.allocReg(inst, &.{});1960 const result_reg = try self.register_manager.allocReg(inst);
1961 try self.genSetReg(ptr_ty, result_reg, mcv);1961 try self.genSetReg(ptr_ty, result_reg, mcv);
1962 break :blk result_reg;1962 break :blk result_reg;
1963 }1963 }
...@@ -3386,7 +3386,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3386,7 +3386,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3386 self.register_manager.freezeRegs(&.{ .rax, .rcx });3386 self.register_manager.freezeRegs(&.{ .rax, .rcx });
3387 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });3387 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
33883388
3389 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{});3389 const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
3390 const addr_reg = regs[0];3390 const addr_reg = regs[0];
3391 const count_reg = regs[1];3391 const count_reg = regs[1];
3392 const tmp_reg = regs[2];3392 const tmp_reg = regs[2];
...@@ -3554,7 +3554,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3554,7 +3554,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3554 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });3554 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });
3555 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });3555 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });
35563556
3557 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{});3557 const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
3558 const addr_reg = regs[0];3558 const addr_reg = regs[0];
3559 const count_reg = regs[1];3559 const count_reg = regs[1];
3560 const tmp_reg = regs[2];3560 const tmp_reg = regs[2];
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, optionally118 /// Allocates a specified number of registers, optionally
119 /// tracking them. Returns `null` if not enough registers are119 /// 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);
132127
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 a157 /// Allocates a register and optionally tracks it with a
164 /// corresponding instruction. Returns `null` if all registers158 /// 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 unfreezeRegs161 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 }
172163
173 /// Allocates a specified number of registers, optionally164 /// Allocates a specified number of registers, optionally
174 /// tracking them. Asserts that count + exceptions.len is not165 /// 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);
187173
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. Spill175 // We'll take over the first count registers. Spill
190 // the instructions that were previously there to a176 // 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;
198183
199 regs[i] = reg;184 regs[i] = reg;
...@@ -229,11 +214,8 @@ pub fn RegisterManager(...@@ -229,11 +214,8 @@ pub fn RegisterManager(
229214
230 /// Allocates a register and optionally tracks it with a215 /// 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 unfreezeRegs218 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 }
238220
239 /// Spills the register if it is currently allocated. If a221 /// 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" {
365347
366 const mock_instruction: Air.Inst.Index = 1;348 const mock_instruction: Air.Inst.Index = 1;
367349
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));
371353
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" {
393375
394 const mock_instruction: Air.Inst.Index = 1;376 const mock_instruction: Air.Inst.Index = 1;
395377
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));
398380
399 // Spill a register381 // 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);
402384
403 // No spilling necessary385 // 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);
407389
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 registers390 // 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});
421395
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();
434408
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 }).?);
436410
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));
441415
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 registers416 // 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});
458423
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());
462427
...@@ -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 }));
484449
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));
489454
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 registers455 // 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});
504462
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());
508466