Commit 74a01e3d64

Jakub Konka <kubkon@jakubkonka.com>
2022-02-03 18:08:29
stage2: remove the concept of register exceptions
1 parent e0b1170
Changed files (5)
src/arch/aarch64/CodeGen.zig
@@ -774,7 +774,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
         const ptr_bits = self.target.cpu.arch.ptrBitWidth();
         const ptr_bytes: u64 = @divExact(ptr_bits, 8);
         if (abi_size <= ptr_bytes) {
-            if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
+            if (self.register_manager.tryAllocReg(inst)) |reg| {
                 return MCValue{ .register = registerAlias(reg, abi_size) };
             }
         }
@@ -797,7 +797,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
 /// allocated. A second call to `copyToTmpRegister` may return the same register.
 /// This can have a side effect of spilling instructions to the stack to free up a register.
 fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
-    const reg = try self.register_manager.allocReg(null, &.{});
+    const reg = try self.register_manager.allocReg(null);
     try self.genSetReg(ty, reg, mcv);
     return reg;
 }
@@ -806,7 +806,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
 /// `reg_owner` is the instruction that gets associated with the register in the register table.
 /// This can have a side effect of spilling instructions to the stack to free up a register.
 fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
-    const reg = try self.register_manager.allocReg(reg_owner, &.{});
+    const reg = try self.register_manager.allocReg(reg_owner);
     try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
     return MCValue{ .register = reg };
 }
@@ -1270,7 +1270,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
         .memory,
         .stack_offset,
         => {
-            const reg = try self.register_manager.allocReg(null, &.{});
+            const reg = try self.register_manager.allocReg(null);
             self.register_manager.freezeRegs(&.{reg});
             defer self.register_manager.unfreezeRegs(&.{reg});
 
@@ -1729,15 +1729,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
             if (!lhs_is_register and !rhs_is_register) {
                 const regs = try self.register_manager.allocRegs(2, .{
                     Air.refToIndex(bin_op.rhs).?, Air.refToIndex(bin_op.lhs).?,
-                }, &.{});
+                });
                 lhs_mcv = MCValue{ .register = regs[0] };
                 rhs_mcv = MCValue{ .register = regs[1] };
             } else if (!rhs_is_register) {
-                rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.rhs).?, &.{}) };
+                rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.rhs).?) };
             }
         }
         if (!lhs_is_register) {
-            lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?, &.{}) };
+            lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?) };
         }
 
         // Move the operands to the newly allocated registers
src/arch/arm/CodeGen.zig
@@ -750,7 +750,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
         const ptr_bits = self.target.cpu.arch.ptrBitWidth();
         const ptr_bytes: u64 = @divExact(ptr_bits, 8);
         if (abi_size <= ptr_bytes) {
-            if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
+            if (self.register_manager.tryAllocReg(inst)) |reg| {
                 return MCValue{ .register = reg };
             }
         }
@@ -791,7 +791,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
 /// allocated. A second call to `copyToTmpRegister` may return the same register.
 /// This can have a side effect of spilling instructions to the stack to free up a register.
 fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
-    const reg = try self.register_manager.allocReg(null, &.{});
+    const reg = try self.register_manager.allocReg(null);
     try self.genSetReg(ty, reg, mcv);
     return reg;
 }
@@ -800,7 +800,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
 /// `reg_owner` is the instruction that gets associated with the register in the register table.
 /// This can have a side effect of spilling instructions to the stack to free up a register.
 fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
-    const reg = try self.register_manager.allocReg(reg_owner, &.{});
+    const reg = try self.register_manager.allocReg(reg_owner);
     try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
     return MCValue{ .register = reg };
 }
@@ -1247,7 +1247,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
         defer self.register_manager.unfreezeRegs(&.{base_mcv.register});
 
         if (elem_size <= 4) {
-            const dst_reg = try self.register_manager.allocReg(inst, &.{});
+            const dst_reg = try self.register_manager.allocReg(inst);
             self.register_manager.freezeRegs(&.{dst_reg});
             defer self.register_manager.unfreezeRegs(&.{dst_reg});
 
@@ -1285,7 +1285,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
         } else {
             const dst_mcv = try self.allocRegOrMem(inst, false);
 
-            const addr_reg = try self.register_manager.allocReg(null, &.{});
+            const addr_reg = try self.register_manager.allocReg(null);
             self.register_manager.freezeRegs(&.{addr_reg});
             defer self.register_manager.unfreezeRegs(&.{addr_reg});
 
@@ -1437,7 +1437,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
                 },
                 .stack_offset => |off| {
                     if (elem_ty.abiSize(self.target.*) <= 4) {
-                        const tmp_reg = try self.register_manager.allocReg(null, &.{});
+                        const tmp_reg = try self.register_manager.allocReg(null);
                         self.register_manager.freezeRegs(&.{tmp_reg});
                         defer self.register_manager.unfreezeRegs(&.{tmp_reg});
 
@@ -1451,7 +1451,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
                         // larger
 
                         const usize_ty = Type.initTag(.usize);
-                        const tmp_regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{});
+                        const tmp_regs = try self.register_manager.allocRegs(2, .{ null, null });
                         self.register_manager.freezeRegs(&tmp_regs);
                         defer self.register_manager.unfreezeRegs(&tmp_regs);
 
@@ -1475,7 +1475,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
                         try self.genSetStack(usize_ty, off + 4, MCValue{ .register = tmp_regs[1] });
                     } else {
                         // TODO optimize the register allocation
-                        const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, &.{});
+                        const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null });
                         self.register_manager.freezeRegs(&regs);
                         defer self.register_manager.unfreezeRegs(&regs);
 
@@ -1524,7 +1524,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
         .stack_offset,
         .stack_argument_offset,
         => {
-            const reg = try self.register_manager.allocReg(null, &.{});
+            const reg = try self.register_manager.allocReg(null);
             self.register_manager.freezeRegs(&.{reg});
             defer self.register_manager.unfreezeRegs(&.{reg});
 
@@ -1597,7 +1597,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
                 },
                 else => {
                     if (value_ty.abiSize(self.target.*) <= 4) {
-                        const tmp_reg = try self.register_manager.allocReg(null, &.{});
+                        const tmp_reg = try self.register_manager.allocReg(null);
                         self.register_manager.freezeRegs(&.{tmp_reg});
                         defer self.register_manager.unfreezeRegs(&.{tmp_reg});
 
@@ -1774,14 +1774,14 @@ fn genArmBinIntOp(
     if (reuse_lhs) {
         // Allocate 0 or 1 registers
         if (!rhs_is_register and rhs_should_be_register) {
-            rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?, &.{}) };
+            rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?) };
             branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv);
         }
         dst_mcv = lhs;
     } else if (reuse_rhs and can_swap_lhs_and_rhs) {
         // Allocate 0 or 1 registers
         if (!lhs_is_register and lhs_should_be_register) {
-            lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?, &.{}) };
+            lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?) };
             branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv);
         }
         dst_mcv = rhs;
@@ -1791,18 +1791,18 @@ fn genArmBinIntOp(
         // Allocate 1 or 2 registers
         if (lhs_should_be_register and rhs_should_be_register) {
             if (lhs_is_register and rhs_is_register) {
-                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
+                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
             } else if (lhs_is_register) {
                 // Move RHS to register
-                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
+                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
                 rhs_mcv = dst_mcv;
             } else if (rhs_is_register) {
                 // Move LHS to register
-                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
+                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
                 lhs_mcv = dst_mcv;
             } else {
                 // Move LHS and RHS to register
-                const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }, &.{});
+                const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? });
                 lhs_mcv = MCValue{ .register = regs[0] };
                 rhs_mcv = MCValue{ .register = regs[1] };
                 dst_mcv = lhs_mcv;
@@ -1812,17 +1812,17 @@ fn genArmBinIntOp(
         } else if (lhs_should_be_register) {
             // RHS is immediate
             if (lhs_is_register) {
-                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
+                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
             } else {
-                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
+                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
                 lhs_mcv = dst_mcv;
             }
         } else if (rhs_should_be_register and can_swap_lhs_and_rhs) {
             // LHS is immediate
             if (rhs_is_register) {
-                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
+                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
             } else {
-                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
+                dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
                 rhs_mcv = dst_mcv;
             }
 
@@ -1983,32 +1983,32 @@ fn genArmMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Ai
     if (reuse_lhs) {
         // Allocate 0 or 1 registers
         if (!rhs_is_register) {
-            rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?, &.{}) };
+            rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?) };
             branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv);
         }
         dst_mcv = lhs;
     } else if (reuse_rhs) {
         // Allocate 0 or 1 registers
         if (!lhs_is_register) {
-            lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?, &.{}) };
+            lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?) };
             branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv);
         }
         dst_mcv = rhs;
     } else {
         // Allocate 1 or 2 registers
         if (lhs_is_register and rhs_is_register) {
-            dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
+            dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
         } else if (lhs_is_register) {
             // Move RHS to register
-            dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
+            dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
             rhs_mcv = dst_mcv;
         } else if (rhs_is_register) {
             // Move LHS to register
-            dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
+            dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
             lhs_mcv = dst_mcv;
         } else {
             // Move LHS and RHS to register
-            const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }, &.{});
+            const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? });
             lhs_mcv = MCValue{ .register = regs[0] };
             rhs_mcv = MCValue{ .register = regs[1] };
             dst_mcv = lhs_mcv;
@@ -2056,17 +2056,17 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind
     // Allocate registers for operands and/or destination
     if (reuse_lhs) {
         // Allocate 1 register
-        rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(null, &.{}) };
+        rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };
         dst_mcv = lhs;
     } else {
         // Allocate 1 or 2 registers
         if (lhs_is_register) {
             // Move RHS to register
-            dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null, &.{}) };
+            dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };
             rhs_mcv = dst_mcv;
         } else {
             // Move LHS and RHS to register
-            const regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{});
+            const regs = try self.register_manager.allocRegs(2, .{ null, null });
             lhs_mcv = MCValue{ .register = regs[0] };
             rhs_mcv = MCValue{ .register = regs[1] };
             dst_mcv = lhs_mcv;
@@ -2432,20 +2432,20 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
             if (!lhs_is_register and !rhs_is_register) {
                 const regs = try self.register_manager.allocRegs(2, .{
                     Air.refToIndex(bin_op.lhs).?, Air.refToIndex(bin_op.rhs).?,
-                }, &.{});
+                });
                 lhs_mcv = MCValue{ .register = regs[0] };
                 rhs_mcv = MCValue{ .register = regs[1] };
             } else if (!rhs_is_register) {
                 const track_inst = if (self.liveness.operandDies(inst, 1)) null else Air.refToIndex(bin_op.rhs).?;
-                rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) };
+                rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) };
             } else if (!lhs_is_register) {
                 const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?;
-                lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) };
+                lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) };
             }
         } else {
             if (!lhs_is_register) {
                 const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?;
-                lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) };
+                lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) };
             }
         }
 
@@ -3185,7 +3185,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
                 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
             } else {
                 // TODO optimize the register allocation
-                const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, &.{});
+                const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null });
                 const src_reg = regs[0];
                 const dst_reg = regs[1];
                 const len_reg = regs[2];
src/arch/riscv64/CodeGen.zig
@@ -749,7 +749,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
         const ptr_bits = self.target.cpu.arch.ptrBitWidth();
         const ptr_bytes: u64 = @divExact(ptr_bits, 8);
         if (abi_size <= ptr_bytes) {
-            if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
+            if (self.register_manager.tryAllocReg(inst)) |reg| {
                 return MCValue{ .register = reg };
             }
         }
@@ -772,7 +772,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
 /// allocated. A second call to `copyToTmpRegister` may return the same register.
 /// This can have a side effect of spilling instructions to the stack to free up a register.
 fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
-    const reg = try self.register_manager.allocReg(null, &.{});
+    const reg = try self.register_manager.allocReg(null);
     try self.genSetReg(ty, reg, mcv);
     return reg;
 }
@@ -781,7 +781,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
 /// `reg_owner` is the instruction that gets associated with the register in the register table.
 /// This can have a side effect of spilling instructions to the stack to free up a register.
 fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
-    const reg = try self.register_manager.allocReg(reg_owner, &.{});
+    const reg = try self.register_manager.allocReg(reg_owner);
     try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
     return MCValue{ .register = reg };
 }
@@ -1211,7 +1211,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
         .memory,
         .stack_offset,
         => {
-            const reg = try self.register_manager.allocReg(null, &.{});
+            const reg = try self.register_manager.allocReg(null);
             self.register_manager.freezeRegs(&.{reg});
             defer self.register_manager.unfreezeRegs(&.{reg});
 
src/arch/x86_64/CodeGen.zig
@@ -819,7 +819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
         const ptr_bits = self.target.cpu.arch.ptrBitWidth();
         const ptr_bytes: u64 = @divExact(ptr_bits, 8);
         if (abi_size <= ptr_bytes) {
-            if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
+            if (self.register_manager.tryAllocReg(inst)) |reg| {
                 return MCValue{ .register = registerAlias(reg, abi_size) };
             }
         }
@@ -842,7 +842,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
 /// allocated. A second call to `copyToTmpRegister` may return the same register.
 /// This can have a side effect of spilling instructions to the stack to free up a register.
 fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
-    const reg = try self.register_manager.allocReg(null, &.{});
+    const reg = try self.register_manager.allocReg(null);
     try self.genSetReg(ty, reg, mcv);
     return reg;
 }
@@ -851,7 +851,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
 /// `reg_owner` is the instruction that gets associated with the register in the register table.
 /// This can have a side effect of spilling instructions to the stack to free up a register.
 fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {
-    const reg = try self.register_manager.allocReg(reg_owner, &.{});
+    const reg = try self.register_manager.allocReg(reg_owner);
     try self.genSetReg(ty, reg, mcv);
     return MCValue{ .register = reg };
 }
@@ -932,7 +932,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
         const reg = switch (operand) {
             .register => |reg| reg,
             else => inner: {
-                const reg = try self.register_manager.allocReg(inst, &.{});
+                const reg = try self.register_manager.allocReg(inst);
                 try self.genSetReg(src_ty, reg, operand);
                 break :inner reg;
             },
@@ -1401,7 +1401,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
         self.register_manager.freezeRegs(&.{offset_reg});
         defer self.register_manager.unfreezeRegs(&.{offset_reg});
 
-        const addr_reg = try self.register_manager.allocReg(null, &.{});
+        const addr_reg = try self.register_manager.allocReg(null);
         switch (slice_mcv) {
             .stack_offset => |off| {
                 // mov reg, [rbp - 8]
@@ -1459,7 +1459,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
         self.register_manager.freezeRegs(&.{offset_reg});
         defer self.register_manager.unfreezeRegs(&.{offset_reg});
 
-        const addr_reg = try self.register_manager.allocReg(null, &.{});
+        const addr_reg = try self.register_manager.allocReg(null);
         switch (array) {
             .stack_offset => |off| {
                 // lea reg, [rbp]
@@ -1640,7 +1640,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
                 },
                 .stack_offset => |off| {
                     if (abi_size <= 8) {
-                        const tmp_reg = try self.register_manager.allocReg(null, &.{});
+                        const tmp_reg = try self.register_manager.allocReg(null);
                         try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
                         return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
                     }
@@ -1648,7 +1648,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
                     self.register_manager.freezeRegs(&.{ .rax, .rcx });
                     defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
 
-                    const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{});
+                    const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
                     const addr_reg = regs[0];
                     const count_reg = regs[1];
                     const tmp_reg = regs[2];
@@ -1957,7 +1957,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
                         break :blk reg;
                     } else {
                         self.register_manager.freezeRegs(&.{reg});
-                        const result_reg = try self.register_manager.allocReg(inst, &.{});
+                        const result_reg = try self.register_manager.allocReg(inst);
                         try self.genSetReg(ptr_ty, result_reg, mcv);
                         break :blk result_reg;
                     }
@@ -3386,7 +3386,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
             self.register_manager.freezeRegs(&.{ .rax, .rcx });
             defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
 
-            const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{});
+            const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
             const addr_reg = regs[0];
             const count_reg = regs[1];
             const tmp_reg = regs[2];
@@ -3554,7 +3554,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
             self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });
             defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });
 
-            const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{});
+            const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
             const addr_reg = regs[0];
             const count_reg = regs[1];
             const tmp_reg = regs[2];
src/register_manager.zig
@@ -118,17 +118,12 @@ pub fn RegisterManager(
         /// Allocates a specified number of registers, optionally
         /// tracking them. Returns `null` if not enough registers are
         /// free.
-        ///
-        /// Exceptions are deprecated, use freezeRegs and unfreezeRegs
-        /// instead.
         pub fn tryAllocRegs(
             self: *Self,
             comptime count: comptime_int,
             insts: [count]?Air.Inst.Index,
-            exceptions: []const Register,
         ) ?[count]Register {
             comptime assert(count > 0 and count <= callee_preserved_regs.len);
-            assert(count + exceptions.len <= callee_preserved_regs.len);
 
             const free_registers = @popCount(FreeRegInt, self.free_registers);
             if (free_registers < count) return null;
@@ -137,7 +132,6 @@ pub fn RegisterManager(
             var i: usize = 0;
             for (callee_preserved_regs) |reg| {
                 if (i >= count) break;
-                if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
                 if (self.isRegFrozen(reg)) continue;
                 if (self.isRegFree(reg)) {
                     regs[i] = reg;
@@ -163,29 +157,21 @@ pub fn RegisterManager(
         /// Allocates a register and optionally tracks it with a
         /// corresponding instruction. Returns `null` if all registers
         /// are allocated.
-        ///
-        /// Exceptions are deprecated, use freezeRegs and unfreezeRegs
-        /// instead.
-        pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index, exceptions: []const Register) ?Register {
-            return if (tryAllocRegs(self, 1, .{inst}, exceptions)) |regs| regs[0] else null;
+        pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index) ?Register {
+            return if (tryAllocRegs(self, 1, .{inst})) |regs| regs[0] else null;
         }
 
         /// Allocates a specified number of registers, optionally
-        /// tracking them. Asserts that count + exceptions.len is not
+        /// tracking them. Asserts that count is not
         /// larger than the total number of registers available.
-        ///
-        /// Exceptions are deprecated, use freezeRegs and unfreezeRegs
-        /// instead.
         pub fn allocRegs(
             self: *Self,
             comptime count: comptime_int,
             insts: [count]?Air.Inst.Index,
-            exceptions: []const Register,
         ) ![count]Register {
             comptime assert(count > 0 and count <= callee_preserved_regs.len);
-            assert(count + exceptions.len <= callee_preserved_regs.len);
 
-            const result = self.tryAllocRegs(count, insts, exceptions) orelse blk: {
+            const result = self.tryAllocRegs(count, insts) orelse blk: {
                 // We'll take over the first count registers. Spill
                 // the instructions that were previously there to a
                 // stack allocations.
@@ -193,7 +179,6 @@ pub fn RegisterManager(
                 var i: usize = 0;
                 for (callee_preserved_regs) |reg| {
                     if (i >= count) break;
-                    if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
                     if (self.isRegFrozen(reg)) continue;
 
                     regs[i] = reg;
@@ -229,11 +214,8 @@ pub fn RegisterManager(
 
         /// Allocates a register and optionally tracks it with a
         /// corresponding instruction.
-        ///
-        /// Exceptions are deprecated, use freezeRegs and unfreezeRegs
-        /// instead.
-        pub fn allocReg(self: *Self, inst: ?Air.Inst.Index, exceptions: []const Register) !Register {
-            return (try self.allocRegs(1, .{inst}, exceptions))[0];
+        pub fn allocReg(self: *Self, inst: ?Air.Inst.Index) !Register {
+            return (try self.allocRegs(1, .{inst}))[0];
         }
 
         /// Spills the register if it is currently allocated. If a
@@ -365,9 +347,9 @@ test "tryAllocReg: no spilling" {
 
     const mock_instruction: Air.Inst.Index = 1;
 
-    try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction, &.{}));
-    try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction, &.{}));
-    try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction, &.{}));
+    try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction));
+    try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction));
+    try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction));
 
     try expect(function.register_manager.isRegAllocated(.r2));
     try expect(function.register_manager.isRegAllocated(.r3));
@@ -393,33 +375,25 @@ test "allocReg: spilling" {
 
     const mock_instruction: Air.Inst.Index = 1;
 
-    try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction, &.{}));
-    try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{}));
+    try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction));
+    try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));
 
     // Spill a register
-    try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction, &.{}));
+    try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction));
     try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
 
     // No spilling necessary
     function.register_manager.freeReg(.r3);
-    try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{}));
+    try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));
     try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
 
-    // Exceptions
-    //
-    // TODO deprecated, remove test once no backend uses exceptions
-    // anymore
-    function.register_manager.freeReg(.r2);
-    function.register_manager.freeReg(.r3);
-    try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{.r2}));
-
     // Frozen registers
     function.register_manager.freeReg(.r3);
     {
         function.register_manager.freezeRegs(&.{.r2});
         defer function.register_manager.unfreezeRegs(&.{.r2});
 
-        try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{}));
+        try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));
     }
     try expect(!function.register_manager.frozenRegsExist());
 }
@@ -432,22 +406,13 @@ test "tryAllocRegs" {
     };
     defer function.deinit();
 
-    try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?);
+    try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }).?);
 
     try expect(function.register_manager.isRegAllocated(.r0));
     try expect(function.register_manager.isRegAllocated(.r1));
     try expect(function.register_manager.isRegAllocated(.r2));
     try expect(!function.register_manager.isRegAllocated(.r3));
 
-    // Exceptions
-    //
-    // TODO deprecated, remove test once no backend uses exceptions
-    // anymore
-    function.register_manager.freeReg(.r0);
-    function.register_manager.freeReg(.r1);
-    function.register_manager.freeReg(.r2);
-    try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{.r1}).?);
-
     // Frozen registers
     function.register_manager.freeReg(.r0);
     function.register_manager.freeReg(.r2);
@@ -456,7 +421,7 @@ test "tryAllocRegs" {
         function.register_manager.freezeRegs(&.{.r1});
         defer function.register_manager.unfreezeRegs(&.{.r1});
 
-        try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?);
+        try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }).?);
     }
     try expect(!function.register_manager.frozenRegsExist());
 
@@ -480,20 +445,13 @@ test "allocRegs" {
         mock_instruction,
         mock_instruction,
         mock_instruction,
-    }, &.{}));
+    }));
 
     try expect(function.register_manager.isRegAllocated(.r0));
     try expect(function.register_manager.isRegAllocated(.r1));
     try expect(function.register_manager.isRegAllocated(.r2));
     try expect(!function.register_manager.isRegAllocated(.r3));
 
-    // Exceptions
-    //
-    // TODO deprecated, remove test once no backend uses exceptions
-    // anymore
-    try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }, &.{.r1}));
-    try expectEqualSlices(MockRegister2, &[_]MockRegister2{ .r0, .r2 }, function.spilled.items);
-
     // Frozen registers
     function.register_manager.freeReg(.r0);
     function.register_manager.freeReg(.r2);
@@ -502,7 +460,7 @@ test "allocRegs" {
         function.register_manager.freezeRegs(&.{.r1});
         defer function.register_manager.unfreezeRegs(&.{.r1});
 
-        try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }, &.{}));
+        try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }));
     }
     try expect(!function.register_manager.frozenRegsExist());