authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-03 20:12:35+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-03 20:12:35+01:00
log3832b582292d3065f600e7c7a8393c411e6cdb0a
tree357d9fd6aad0da36b8c09c4a890001976ceac9e3
parent228b798af5b2c9e417d145aff171879cdee8ae04
parent74a01e3d64cc5d941486e5bd037f6f55e030339c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10775 from ziglang/x64-freeze-api

stage2: migrate x64 to freeze regalloc API, and remove the concept of register exceptions

5 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 {
774774 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
775775 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
776776 if (abi_size <= ptr_bytes) {
777 if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
777 if (self.register_manager.tryAllocReg(inst)) |reg| {
778778 return MCValue{ .register = registerAlias(reg, abi_size) };
779779 }
780780 }
......@@ -797,7 +797,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
797797/// allocated. A second call to `copyToTmpRegister` may return the same register.
798798/// This can have a side effect of spilling instructions to the stack to free up a register.
799799fn 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);
801801 try self.genSetReg(ty, reg, mcv);
802802 return reg;
803803}
......@@ -806,7 +806,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
806806/// `reg_owner` is the instruction that gets associated with the register in the register table.
807807/// This can have a side effect of spilling instructions to the stack to free up a register.
808808fn 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);
810810 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
811811 return MCValue{ .register = reg };
812812}
......@@ -1270,7 +1270,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
12701270 .memory,
12711271 .stack_offset,
12721272 => {
1273 const reg = try self.register_manager.allocReg(null, &.{});
1273 const reg = try self.register_manager.allocReg(null);
12741274 self.register_manager.freezeRegs(&.{reg});
12751275 defer self.register_manager.unfreezeRegs(&.{reg});
12761276
......@@ -1729,15 +1729,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
17291729 if (!lhs_is_register and !rhs_is_register) {
17301730 const regs = try self.register_manager.allocRegs(2, .{
17311731 Air.refToIndex(bin_op.rhs).?, Air.refToIndex(bin_op.lhs).?,
1732 }, &.{});
1732 });
17331733 lhs_mcv = MCValue{ .register = regs[0] };
17341734 rhs_mcv = MCValue{ .register = regs[1] };
17351735 } 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).?) };
17371737 }
17381738 }
17391739 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).?) };
17411741 }
17421742
17431743 // 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 {
750750 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
751751 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
752752 if (abi_size <= ptr_bytes) {
753 if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
753 if (self.register_manager.tryAllocReg(inst)) |reg| {
754754 return MCValue{ .register = reg };
755755 }
756756 }
......@@ -791,7 +791,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
791791/// allocated. A second call to `copyToTmpRegister` may return the same register.
792792/// This can have a side effect of spilling instructions to the stack to free up a register.
793793fn 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);
795795 try self.genSetReg(ty, reg, mcv);
796796 return reg;
797797}
......@@ -800,7 +800,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
800800/// `reg_owner` is the instruction that gets associated with the register in the register table.
801801/// This can have a side effect of spilling instructions to the stack to free up a register.
802802fn 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);
804804 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
805805 return MCValue{ .register = reg };
806806}
......@@ -1247,7 +1247,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
12471247 defer self.register_manager.unfreezeRegs(&.{base_mcv.register});
12481248
12491249 if (elem_size <= 4) {
1250 const dst_reg = try self.register_manager.allocReg(inst, &.{});
1250 const dst_reg = try self.register_manager.allocReg(inst);
12511251 self.register_manager.freezeRegs(&.{dst_reg});
12521252 defer self.register_manager.unfreezeRegs(&.{dst_reg});
12531253
......@@ -1285,7 +1285,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
12851285 } else {
12861286 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);
12891289 self.register_manager.freezeRegs(&.{addr_reg});
12901290 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
14371437 },
14381438 .stack_offset => |off| {
14391439 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);
14411441 self.register_manager.freezeRegs(&.{tmp_reg});
14421442 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
14511451 // larger
14521452
14531453 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 });
14551455 self.register_manager.freezeRegs(&tmp_regs);
14561456 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
14751475 try self.genSetStack(usize_ty, off + 4, MCValue{ .register = tmp_regs[1] });
14761476 } else {
14771477 // 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 });
14791479 self.register_manager.freezeRegs(&regs);
14801480 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
15241524 .stack_offset,
15251525 .stack_argument_offset,
15261526 => {
1527 const reg = try self.register_manager.allocReg(null, &.{});
1527 const reg = try self.register_manager.allocReg(null);
15281528 self.register_manager.freezeRegs(&.{reg});
15291529 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
15971597 },
15981598 else => {
15991599 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);
16011601 self.register_manager.freezeRegs(&.{tmp_reg});
16021602 defer self.register_manager.unfreezeRegs(&.{tmp_reg});
16031603
......@@ -1774,14 +1774,14 @@ fn genArmBinIntOp(
17741774 if (reuse_lhs) {
17751775 // Allocate 0 or 1 registers
17761776 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).?) };
17781778 branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv);
17791779 }
17801780 dst_mcv = lhs;
17811781 } else if (reuse_rhs and can_swap_lhs_and_rhs) {
17821782 // Allocate 0 or 1 registers
17831783 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).?) };
17851785 branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv);
17861786 }
17871787 dst_mcv = rhs;
......@@ -1791,18 +1791,18 @@ fn genArmBinIntOp(
17911791 // Allocate 1 or 2 registers
17921792 if (lhs_should_be_register and rhs_should_be_register) {
17931793 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) };
17951795 } else if (lhs_is_register) {
17961796 // 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) };
17981798 rhs_mcv = dst_mcv;
17991799 } else if (rhs_is_register) {
18001800 // 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) };
18021802 lhs_mcv = dst_mcv;
18031803 } else {
18041804 // 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).? });
18061806 lhs_mcv = MCValue{ .register = regs[0] };
18071807 rhs_mcv = MCValue{ .register = regs[1] };
18081808 dst_mcv = lhs_mcv;
......@@ -1812,17 +1812,17 @@ fn genArmBinIntOp(
18121812 } else if (lhs_should_be_register) {
18131813 // RHS is immediate
18141814 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) };
18161816 } else {
1817 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
1817 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
18181818 lhs_mcv = dst_mcv;
18191819 }
18201820 } else if (rhs_should_be_register and can_swap_lhs_and_rhs) {
18211821 // LHS is immediate
18221822 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) };
18241824 } else {
1825 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
1825 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
18261826 rhs_mcv = dst_mcv;
18271827 }
18281828
......@@ -1983,32 +1983,32 @@ fn genArmMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Ai
19831983 if (reuse_lhs) {
19841984 // Allocate 0 or 1 registers
19851985 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).?) };
19871987 branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv);
19881988 }
19891989 dst_mcv = lhs;
19901990 } else if (reuse_rhs) {
19911991 // Allocate 0 or 1 registers
19921992 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).?) };
19941994 branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv);
19951995 }
19961996 dst_mcv = rhs;
19971997 } else {
19981998 // Allocate 1 or 2 registers
19991999 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) };
20012001 } else if (lhs_is_register) {
20022002 // 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) };
20042004 rhs_mcv = dst_mcv;
20052005 } else if (rhs_is_register) {
20062006 // 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) };
20082008 lhs_mcv = dst_mcv;
20092009 } else {
20102010 // 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).? });
20122012 lhs_mcv = MCValue{ .register = regs[0] };
20132013 rhs_mcv = MCValue{ .register = regs[1] };
20142014 dst_mcv = lhs_mcv;
......@@ -2056,17 +2056,17 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind
20562056 // Allocate registers for operands and/or destination
20572057 if (reuse_lhs) {
20582058 // 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) };
20602060 dst_mcv = lhs;
20612061 } else {
20622062 // Allocate 1 or 2 registers
20632063 if (lhs_is_register) {
20642064 // 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) };
20662066 rhs_mcv = dst_mcv;
20672067 } else {
20682068 // 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 });
20702070 lhs_mcv = MCValue{ .register = regs[0] };
20712071 rhs_mcv = MCValue{ .register = regs[1] };
20722072 dst_mcv = lhs_mcv;
......@@ -2432,20 +2432,20 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
24322432 if (!lhs_is_register and !rhs_is_register) {
24332433 const regs = try self.register_manager.allocRegs(2, .{
24342434 Air.refToIndex(bin_op.lhs).?, Air.refToIndex(bin_op.rhs).?,
2435 }, &.{});
2435 });
24362436 lhs_mcv = MCValue{ .register = regs[0] };
24372437 rhs_mcv = MCValue{ .register = regs[1] };
24382438 } else if (!rhs_is_register) {
24392439 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) };
24412441 } else if (!lhs_is_register) {
24422442 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) };
24442444 }
24452445 } else {
24462446 if (!lhs_is_register) {
24472447 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) };
24492449 }
24502450 }
24512451
......@@ -3185,7 +3185,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
31853185 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
31863186 } else {
31873187 // 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 });
31893189 const src_reg = regs[0];
31903190 const dst_reg = regs[1];
31913191 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 {
749749 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
750750 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
751751 if (abi_size <= ptr_bytes) {
752 if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
752 if (self.register_manager.tryAllocReg(inst)) |reg| {
753753 return MCValue{ .register = reg };
754754 }
755755 }
......@@ -772,7 +772,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
772772/// allocated. A second call to `copyToTmpRegister` may return the same register.
773773/// This can have a side effect of spilling instructions to the stack to free up a register.
774774fn 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);
776776 try self.genSetReg(ty, reg, mcv);
777777 return reg;
778778}
......@@ -781,7 +781,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
781781/// `reg_owner` is the instruction that gets associated with the register in the register table.
782782/// This can have a side effect of spilling instructions to the stack to free up a register.
783783fn 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);
785785 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
786786 return MCValue{ .register = reg };
787787}
......@@ -1211,7 +1211,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
12111211 .memory,
12121212 .stack_offset,
12131213 => {
1214 const reg = try self.register_manager.allocReg(null, &.{});
1214 const reg = try self.register_manager.allocReg(null);
12151215 self.register_manager.freezeRegs(&.{reg});
12161216 defer self.register_manager.unfreezeRegs(&.{reg});
12171217
src/arch/x86_64/CodeGen.zig+104-60
......@@ -21,7 +21,7 @@ const Emit = @import("Emit.zig");
2121const Liveness = @import("../../Liveness.zig");
2222const Mir = @import("Mir.zig");
2323const Module = @import("../../Module.zig");
24const RegisterManager = @import("../../register_manager.zig").RegisterManager;
24const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
2525const Target = std.Target;
2626const Type = @import("../../type.zig").Type;
2727const TypedValue = @import("../../TypedValue.zig");
......@@ -33,6 +33,8 @@ const InnerError = error{
3333 CodegenFail,
3434};
3535
36const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs);
37
3638gpa: Allocator,
3739air: Air,
3840liveness: Liveness,
......@@ -73,7 +75,7 @@ branch_stack: *std.ArrayList(Branch),
7375// Key is the block instruction
7476blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
7577
76register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},
78register_manager: RegisterManager = .{},
7779/// Maps offset to what is stored there.
7880stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
7981
......@@ -169,6 +171,24 @@ pub const MCValue = union(enum) {
169171 else => false,
170172 };
171173 }
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 }
172192};
173193
174194const Branch = struct {
......@@ -799,7 +819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
799819 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
800820 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
801821 if (abi_size <= ptr_bytes) {
802 if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
822 if (self.register_manager.tryAllocReg(inst)) |reg| {
803823 return MCValue{ .register = registerAlias(reg, abi_size) };
804824 }
805825 }
......@@ -822,7 +842,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
822842/// allocated. A second call to `copyToTmpRegister` may return the same register.
823843/// This can have a side effect of spilling instructions to the stack to free up a register.
824844fn 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);
826846 try self.genSetReg(ty, reg, mcv);
827847 return reg;
828848}
......@@ -831,21 +851,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
831851/// `reg_owner` is the instruction that gets associated with the register in the register table.
832852/// This can have a side effect of spilling instructions to the stack to free up a register.
833853fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {
834 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.
841fn 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);
854 const reg = try self.register_manager.allocReg(reg_owner);
849855 try self.genSetReg(ty, reg, mcv);
850856 return MCValue{ .register = reg };
851857}
......@@ -897,8 +903,9 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
897903 return self.fail("TODO implement intCast for abi sizes larger than 8", .{});
898904 }
899905
900 if (operand.isRegister()) self.register_manager.freezeRegs(&.{operand.register});
901 defer if (operand.isRegister()) self.register_manager.unfreezeRegs(&.{operand.register});
906 operand.freezeIfRegister(&self.register_manager);
907 defer operand.unfreezeIfRegister(&self.register_manager);
908
902909 break :blk try self.copyToNewRegister(inst, dest_ty, operand);
903910 };
904911
......@@ -925,7 +932,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
925932 const reg = switch (operand) {
926933 .register => |reg| reg,
927934 else => inner: {
928 const reg = try self.register_manager.allocReg(inst, &.{});
935 const reg = try self.register_manager.allocReg(inst);
929936 try self.genSetReg(src_ty, reg, operand);
930937 break :inner reg;
931938 },
......@@ -1366,8 +1373,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
13661373}
13671374
13681375fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {
1369 const reg = try self.register_manager.allocReg(null, &.{});
1370 try self.genSetReg(index_ty, reg, index);
1376 const reg = try self.copyToTmpRegister(index_ty, index);
13711377 try self.genIMulOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size });
13721378 return reg;
13731379}
......@@ -1376,16 +1382,26 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
13761382 const is_volatile = false; // TODO
13771383 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
13781384 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: {
1379 const slice_mcv = try self.resolveInst(bin_op.lhs);
13801385 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
13811390 const elem_ty = slice_ty.childType();
13821391 const elem_size = elem_ty.abiSize(self.target.*);
13831392 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
13841393 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
1394
13851395 const index_ty = self.air.typeOf(bin_op.rhs);
13861396 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
13871400 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);
13891405 switch (slice_mcv) {
13901406 .stack_offset => |off| {
13911407 // mov reg, [rbp - 8]
......@@ -1401,7 +1417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
14011417 },
14021418 else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}),
14031419 }
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
14051421 // offset register.
14061422 const dst_mcv = try self.allocRegOrMem(inst, false);
14071423 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 {
14271443 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
14281444 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
14291445 const array_ty = self.air.typeOf(bin_op.lhs);
1430 const array = try self.resolveInst(bin_op.lhs);
14311446 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
14321451 const elem_ty = array_ty.childType();
14331452 const elem_abi_size = elem_ty.abiSize(self.target.*);
14341453 const index_ty = self.air.typeOf(bin_op.rhs);
14351454 const index = try self.resolveInst(bin_op.rhs);
1455 index.freezeIfRegister(&self.register_manager);
1456 defer index.unfreezeIfRegister(&self.register_manager);
1457
14361458 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);
14381463 switch (array) {
14391464 .stack_offset => |off| {
14401465 // lea reg, [rbp]
......@@ -1449,7 +1474,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
14491474 },
14501475 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
14511476 }
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
14531478 // offset register.
14541479 const dst_mcv = try self.allocRegOrMem(inst, false);
14551480 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 {
14751500 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
14761501 const ptr_ty = self.air.typeOf(extra.lhs);
14771502 const ptr = try self.resolveInst(extra.lhs);
1503 ptr.freezeIfRegister(&self.register_manager);
1504 defer ptr.unfreezeIfRegister(&self.register_manager);
1505
14781506 const elem_ty = ptr_ty.elemType2();
14791507 const elem_abi_size = elem_ty.abiSize(self.target.*);
14801508 const index_ty = self.air.typeOf(extra.rhs);
14811509 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);
14831512
1513 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
14841514 self.register_manager.freezeRegs(&.{offset_reg});
14851515 defer self.register_manager.unfreezeRegs(&.{offset_reg});
14861516
......@@ -1587,6 +1617,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
15871617 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});
15881618 },
15891619 .register => |reg| {
1620 self.register_manager.freezeRegs(&.{reg});
1621 defer self.register_manager.unfreezeRegs(&.{reg});
1622
15901623 switch (dst_mcv) {
15911624 .dead => unreachable,
15921625 .undef => unreachable,
......@@ -1607,16 +1640,15 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
16071640 },
16081641 .stack_offset => |off| {
16091642 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);
16111644 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
16121645 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
16131646 }
16141647
1615 const regs = try self.register_manager.allocRegs(
1616 3,
1617 .{ null, null, null },
1618 &.{ reg, .rax, .rcx },
1619 );
1648 self.register_manager.freezeRegs(&.{ .rax, .rcx });
1649 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
1650
1651 const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
16201652 const addr_reg = regs[0];
16211653 const count_reg = regs[1];
16221654 const tmp_reg = regs[2];
......@@ -1634,7 +1666,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
16341666 try self.register_manager.getReg(.rcx, null);
16351667
16361668 // 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) });
16381670
16391671 return self.genInlineMemcpy(
16401672 -(off + @intCast(i32, abi_size)),
......@@ -1786,8 +1818,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
17861818 // TODO: in case the address fits in an imm32 we can use [ds:imm32]
17871819 // instead of wasting an instruction copying the address to a register
17881820
1789 if (value.isRegister()) self.register_manager.freezeRegs(&.{value.register});
1790 defer if (value.isRegister()) self.register_manager.unfreezeRegs(&.{value.register});
1821 value.freezeIfRegister(&self.register_manager);
1822 defer value.unfreezeIfRegister(&self.register_manager);
17911823
17921824 const addr_reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr });
17931825 // 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
19251957 break :blk reg;
19261958 } else {
19271959 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);
19291961 try self.genSetReg(ptr_ty, result_reg, mcv);
19301962 break :blk result_reg;
19311963 }
......@@ -2012,22 +2044,16 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
20122044 }
20132045 } else {
20142046 if (lhs.isMemory()) {
2015 dst_mcv = if (rhs.isRegister())
2016 // If the allocated register is the same as the rhs register, don't allocate that one
2017 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation
2018 // in the presence of several binary operations performed in a single block.
2019 try self.copyToNewRegisterWithExceptions(inst, dst_ty, lhs, &.{rhs.register})
2020 else
2021 try self.copyToNewRegister(inst, dst_ty, lhs);
2047 rhs.freezeIfRegister(&self.register_manager);
2048 defer rhs.unfreezeIfRegister(&self.register_manager);
2049
2050 dst_mcv = try self.copyToNewRegister(inst, dst_ty, lhs);
20222051 src_mcv = rhs;
20232052 } else {
2024 dst_mcv = if (lhs.isRegister())
2025 // If the allocated register is the same as the rhs register, don't allocate that one
2026 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation
2027 // in the presence of several binary operations performed in a single block.
2028 try self.copyToNewRegisterWithExceptions(inst, dst_ty, rhs, &.{lhs.register})
2029 else
2030 try self.copyToNewRegister(inst, dst_ty, rhs);
2053 lhs.freezeIfRegister(&self.register_manager);
2054 defer lhs.unfreezeIfRegister(&self.register_manager);
2055
2056 dst_mcv = try self.copyToNewRegister(inst, dst_ty, rhs);
20312057 src_mcv = lhs;
20322058 }
20332059 }
......@@ -2039,7 +2065,11 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
20392065 switch (src_mcv) {
20402066 .immediate => |imm| {
20412067 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 };
20432073 }
20442074 },
20452075 else => {},
......@@ -2901,6 +2931,8 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
29012931 const un_op = self.air.instructions.items(.data)[inst].un_op;
29022932 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
29032933 const operand_ptr = try self.resolveInst(un_op);
2934 operand_ptr.freezeIfRegister(&self.register_manager);
2935 defer operand_ptr.unfreezeIfRegister(&self.register_manager);
29042936 const operand: MCValue = blk: {
29052937 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
29062938 // 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 {
29302962 const un_op = self.air.instructions.items(.data)[inst].un_op;
29312963 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
29322964 const operand_ptr = try self.resolveInst(un_op);
2965 operand_ptr.freezeIfRegister(&self.register_manager);
2966 defer operand_ptr.unfreezeIfRegister(&self.register_manager);
29332967 const operand: MCValue = blk: {
29342968 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
29352969 // 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 {
29592993 const un_op = self.air.instructions.items(.data)[inst].un_op;
29602994 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
29612995 const operand_ptr = try self.resolveInst(un_op);
2996 operand_ptr.freezeIfRegister(&self.register_manager);
2997 defer operand_ptr.unfreezeIfRegister(&self.register_manager);
29622998 const operand: MCValue = blk: {
29632999 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
29643000 // 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 {
29883024 const un_op = self.air.instructions.items(.data)[inst].un_op;
29893025 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
29903026 const operand_ptr = try self.resolveInst(un_op);
3027 operand_ptr.freezeIfRegister(&self.register_manager);
3028 defer operand_ptr.unfreezeIfRegister(&self.register_manager);
29913029 const operand: MCValue = blk: {
29923030 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
29933031 // 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
33453383 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
33463384 }
33473385
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 });
33493390 const addr_reg = regs[0];
33503391 const count_reg = regs[1];
33513392 const tmp_reg = regs[2];
......@@ -3363,7 +3404,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
33633404 });
33643405
33653406 // 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) });
33673408 try self.genInlineMemcpy(
33683409 -(stack_offset + @intCast(i32, abi_size)),
33693410 .rsp,
......@@ -3510,7 +3551,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
35103551 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
35113552 }
35123553
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 });
35143558 const addr_reg = regs[0];
35153559 const count_reg = regs[1];
35163560 const tmp_reg = regs[2];
......@@ -3528,7 +3572,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
35283572 });
35293573
35303574 // 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) });
35323576
35333577 return self.genInlineMemcpy(
35343578 -(stack_offset + @intCast(i32, abi_size)),
src/register_manager.zig+18-60
......@@ -118,17 +118,12 @@ pub fn RegisterManager(
118118 /// Allocates a specified number of registers, optionally
119119 /// tracking them. Returns `null` if not enough registers are
120120 /// free.
121 ///
122 /// Exceptions are deprecated, use freezeRegs and unfreezeRegs
123 /// instead.
124121 pub fn tryAllocRegs(
125122 self: *Self,
126123 comptime count: comptime_int,
127124 insts: [count]?Air.Inst.Index,
128 exceptions: []const Register,
129125 ) ?[count]Register {
130126 comptime assert(count > 0 and count <= callee_preserved_regs.len);
131 assert(count + exceptions.len <= callee_preserved_regs.len);
132127
133128 const free_registers = @popCount(FreeRegInt, self.free_registers);
134129 if (free_registers < count) return null;
......@@ -137,7 +132,6 @@ pub fn RegisterManager(
137132 var i: usize = 0;
138133 for (callee_preserved_regs) |reg| {
139134 if (i >= count) break;
140 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
141135 if (self.isRegFrozen(reg)) continue;
142136 if (self.isRegFree(reg)) {
143137 regs[i] = reg;
......@@ -163,29 +157,21 @@ pub fn RegisterManager(
163157 /// Allocates a register and optionally tracks it with a
164158 /// corresponding instruction. Returns `null` if all registers
165159 /// are allocated.
166 ///
167 /// Exceptions are deprecated, use freezeRegs and unfreezeRegs
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;
160 pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index) ?Register {
161 return if (tryAllocRegs(self, 1, .{inst})) |regs| regs[0] else null;
171162 }
172163
173164 /// 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
175166 /// larger than the total number of registers available.
176 ///
177 /// Exceptions are deprecated, use freezeRegs and unfreezeRegs
178 /// instead.
179167 pub fn allocRegs(
180168 self: *Self,
181169 comptime count: comptime_int,
182170 insts: [count]?Air.Inst.Index,
183 exceptions: []const Register,
184171 ) ![count]Register {
185172 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: {
189175 // We'll take over the first count registers. Spill
190176 // the instructions that were previously there to a
191177 // stack allocations.
......@@ -193,7 +179,6 @@ pub fn RegisterManager(
193179 var i: usize = 0;
194180 for (callee_preserved_regs) |reg| {
195181 if (i >= count) break;
196 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
197182 if (self.isRegFrozen(reg)) continue;
198183
199184 regs[i] = reg;
......@@ -229,11 +214,8 @@ pub fn RegisterManager(
229214
230215 /// Allocates a register and optionally tracks it with a
231216 /// corresponding instruction.
232 ///
233 /// Exceptions are deprecated, use freezeRegs and unfreezeRegs
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];
217 pub fn allocReg(self: *Self, inst: ?Air.Inst.Index) !Register {
218 return (try self.allocRegs(1, .{inst}))[0];
237219 }
238220
239221 /// Spills the register if it is currently allocated. If a
......@@ -365,9 +347,9 @@ test "tryAllocReg: no spilling" {
365347
366348 const mock_instruction: Air.Inst.Index = 1;
367349
368 try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction, &.{}));
369 try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction, &.{}));
370 try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction, &.{}));
350 try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction));
351 try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction));
352 try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction));
371353
372354 try expect(function.register_manager.isRegAllocated(.r2));
373355 try expect(function.register_manager.isRegAllocated(.r3));
......@@ -393,33 +375,25 @@ test "allocReg: spilling" {
393375
394376 const mock_instruction: Air.Inst.Index = 1;
395377
396 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, &.{}));
378 try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction));
379 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));
398380
399381 // 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));
401383 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
402384
403385 // No spilling necessary
404386 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));
406388 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
416390 // Frozen registers
417391 function.register_manager.freeReg(.r3);
418392 {
419393 function.register_manager.freezeRegs(&.{.r2});
420394 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));
423397 }
424398 try expect(!function.register_manager.frozenRegsExist());
425399}
......@@ -432,22 +406,13 @@ test "tryAllocRegs" {
432406 };
433407 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
437411 try expect(function.register_manager.isRegAllocated(.r0));
438412 try expect(function.register_manager.isRegAllocated(.r1));
439413 try expect(function.register_manager.isRegAllocated(.r2));
440414 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
451416 // Frozen registers
452417 function.register_manager.freeReg(.r0);
453418 function.register_manager.freeReg(.r2);
......@@ -456,7 +421,7 @@ test "tryAllocRegs" {
456421 function.register_manager.freezeRegs(&.{.r1});
457422 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 }).?);
460425 }
461426 try expect(!function.register_manager.frozenRegsExist());
462427
......@@ -480,20 +445,13 @@ test "allocRegs" {
480445 mock_instruction,
481446 mock_instruction,
482447 mock_instruction,
483 }, &.{}));
448 }));
484449
485450 try expect(function.register_manager.isRegAllocated(.r0));
486451 try expect(function.register_manager.isRegAllocated(.r1));
487452 try expect(function.register_manager.isRegAllocated(.r2));
488453 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
497455 // Frozen registers
498456 function.register_manager.freeReg(.r0);
499457 function.register_manager.freeReg(.r2);
......@@ -502,7 +460,7 @@ test "allocRegs" {
502460 function.register_manager.freezeRegs(&.{.r1});
503461 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 }));
506464 }
507465 try expect(!function.register_manager.frozenRegsExist());
508466