authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-19 23:17:43+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-19 23:54:48+02:00
loge95dfac03eea942b53bbdf6117a716aaeba5eb4b
tree528e33c135c69eedde5d209b55df88a0a36365cf
parentf766b25f82a6c94d6b77f6a4172bfc4feb1d9271

regalloc: make register class bitmask non-optional


10 files changed, 264 insertions(+), 170 deletions(-)

src/arch/aarch64/CodeGen.zig+31-31
......@@ -21,9 +21,6 @@ const DW = std.dwarf;
2121const leb128 = std.leb;
2222const log = std.log.scoped(.codegen);
2323const build_options = @import("build_options");
24const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
25const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs);
26const RegisterLock = RegisterManager.RegisterLock;
2724
2825const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
2926const FnResult = @import("../../codegen.zig").FnResult;
......@@ -31,11 +28,14 @@ const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
3128
3229const bits = @import("bits.zig");
3330const abi = @import("abi.zig");
31const RegisterManager = abi.RegisterManager;
32const RegisterLock = RegisterManager.RegisterLock;
3433const Register = bits.Register;
3534const Instruction = bits.Instruction;
3635const callee_preserved_regs = abi.callee_preserved_regs;
3736const c_abi_int_param_regs = abi.c_abi_int_param_regs;
3837const c_abi_int_return_regs = abi.c_abi_int_return_regs;
38const gp = abi.RegisterClass.gp;
3939
4040const InnerError = error{
4141 OutOfMemory,
......@@ -888,7 +888,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
888888 if (reg_ok) {
889889 // Make sure the type can fit in a register before we try to allocate one.
890890 if (abi_size <= 8) {
891 if (self.register_manager.tryAllocReg(inst, .{})) |reg| {
891 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
892892 return MCValue{ .register = registerAlias(reg, abi_size) };
893893 }
894894 }
......@@ -951,7 +951,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
951951/// allocated. A second call to `copyToTmpRegister` may return the same register.
952952/// This can have a side effect of spilling instructions to the stack to free up a register.
953953fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
954 const raw_reg = try self.register_manager.allocReg(null, .{});
954 const raw_reg = try self.register_manager.allocReg(null, gp);
955955 const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));
956956 try self.genSetReg(ty, reg, mcv);
957957 return reg;
......@@ -961,7 +961,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
961961/// `reg_owner` is the instruction that gets associated with the register in the register table.
962962/// This can have a side effect of spilling instructions to the stack to free up a register.
963963fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
964 const raw_reg = try self.register_manager.allocReg(reg_owner, .{});
964 const raw_reg = try self.register_manager.allocReg(reg_owner, gp);
965965 const ty = self.air.typeOfIndex(reg_owner);
966966 const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));
967967 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
......@@ -1074,11 +1074,11 @@ fn trunc(
10741074 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
10751075 break :blk registerAlias(operand_reg, dest_ty.abiSize(self.target.*));
10761076 } else {
1077 const raw_reg = try self.register_manager.allocReg(inst, .{});
1077 const raw_reg = try self.register_manager.allocReg(inst, gp);
10781078 break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));
10791079 }
10801080 } else blk: {
1081 const raw_reg = try self.register_manager.allocReg(null, .{});
1081 const raw_reg = try self.register_manager.allocReg(null, gp);
10821082 break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));
10831083 };
10841084
......@@ -1160,7 +1160,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11601160 break :blk op_reg;
11611161 }
11621162
1163 const raw_reg = try self.register_manager.allocReg(null, .{});
1163 const raw_reg = try self.register_manager.allocReg(null, gp);
11641164 break :blk raw_reg.to32();
11651165 };
11661166
......@@ -1193,7 +1193,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11931193 break :blk op_reg;
11941194 }
11951195
1196 const raw_reg = try self.register_manager.allocReg(null, .{});
1196 const raw_reg = try self.register_manager.allocReg(null, gp);
11971197 break :blk registerAlias(raw_reg, operand_ty.abiSize(self.target.*));
11981198 };
11991199
......@@ -1293,7 +1293,7 @@ fn binOpRegister(
12931293 break :inst Air.refToIndex(md.lhs).?;
12941294 } else null;
12951295
1296 const raw_reg = try self.register_manager.allocReg(track_inst, .{});
1296 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
12971297 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
12981298
12991299 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
......@@ -1308,7 +1308,7 @@ fn binOpRegister(
13081308 break :inst Air.refToIndex(md.rhs).?;
13091309 } else null;
13101310
1311 const raw_reg = try self.register_manager.allocReg(track_inst, .{});
1311 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
13121312 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));
13131313
13141314 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
......@@ -1326,11 +1326,11 @@ fn binOpRegister(
13261326 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
13271327 break :blk rhs_reg;
13281328 } else {
1329 const raw_reg = try self.register_manager.allocReg(md.inst, .{});
1329 const raw_reg = try self.register_manager.allocReg(md.inst, gp);
13301330 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
13311331 }
13321332 } else blk: {
1333 const raw_reg = try self.register_manager.allocReg(null, .{});
1333 const raw_reg = try self.register_manager.allocReg(null, gp);
13341334 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
13351335 },
13361336 };
......@@ -1431,7 +1431,7 @@ fn binOpImmediate(
14311431 ).?;
14321432 } else null;
14331433
1434 const raw_reg = try self.register_manager.allocReg(track_inst, .{});
1434 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
14351435 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
14361436
14371437 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
......@@ -1452,11 +1452,11 @@ fn binOpImmediate(
14521452 )) {
14531453 break :blk lhs_reg;
14541454 } else {
1455 const raw_reg = try self.register_manager.allocReg(md.inst, .{});
1455 const raw_reg = try self.register_manager.allocReg(md.inst, gp);
14561456 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
14571457 }
14581458 } else blk: {
1459 const raw_reg = try self.register_manager.allocReg(null, .{});
1459 const raw_reg = try self.register_manager.allocReg(null, gp);
14601460 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
14611461 },
14621462 };
......@@ -1872,7 +1872,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
18721872 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
18731873 defer self.register_manager.unlockReg(dest_reg_lock);
18741874
1875 const raw_truncated_reg = try self.register_manager.allocReg(null, .{});
1875 const raw_truncated_reg = try self.register_manager.allocReg(null, gp);
18761876 const truncated_reg = registerAlias(raw_truncated_reg, lhs_ty.abiSize(self.target.*));
18771877 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
18781878 defer self.register_manager.unlockReg(truncated_reg_lock);
......@@ -1983,7 +1983,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
19831983 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
19841984 defer self.register_manager.unlockReg(dest_reg_lock);
19851985
1986 const truncated_reg = try self.register_manager.allocReg(null, .{});
1986 const truncated_reg = try self.register_manager.allocReg(null, gp);
19871987 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
19881988 defer self.register_manager.unlockReg(truncated_reg_lock);
19891989
......@@ -2048,7 +2048,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
20482048 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
20492049
20502050 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
2051 const raw_reg = try self.register_manager.allocReg(null, .{});
2051 const raw_reg = try self.register_manager.allocReg(null, gp);
20522052 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
20532053 break :blk reg;
20542054 };
......@@ -2056,7 +2056,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
20562056 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
20572057
20582058 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
2059 const raw_reg = try self.register_manager.allocReg(null, .{});
2059 const raw_reg = try self.register_manager.allocReg(null, gp);
20602060 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));
20612061 break :blk reg;
20622062 };
......@@ -2067,7 +2067,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
20672067 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
20682068
20692069 const dest_reg = blk: {
2070 const raw_reg = try self.register_manager.allocReg(null, .{});
2070 const raw_reg = try self.register_manager.allocReg(null, gp);
20712071 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
20722072 break :blk reg;
20732073 };
......@@ -2086,7 +2086,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
20862086 } },
20872087 });
20882088
2089 const dest_high_reg = try self.register_manager.allocReg(null, .{});
2089 const dest_high_reg = try self.register_manager.allocReg(null, gp);
20902090 const dest_high_reg_lock = self.register_manager.lockRegAssumeUnused(dest_high_reg);
20912091 defer self.register_manager.unlockReg(dest_high_reg_lock);
20922092
......@@ -2136,7 +2136,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21362136 }
21372137 },
21382138 .unsigned => {
2139 const dest_high_reg = try self.register_manager.allocReg(null, .{});
2139 const dest_high_reg = try self.register_manager.allocReg(null, gp);
21402140 const dest_high_reg_lock = self.register_manager.lockRegAssumeUnused(dest_high_reg);
21412141 defer self.register_manager.unlockReg(dest_high_reg_lock);
21422142
......@@ -2192,7 +2192,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21922192 },
21932193 }
21942194
2195 const truncated_reg = try self.register_manager.allocReg(null, .{});
2195 const truncated_reg = try self.register_manager.allocReg(null, gp);
21962196 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
21972197 defer self.register_manager.unlockReg(truncated_reg_lock);
21982198
......@@ -2663,7 +2663,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
26632663 },
26642664 .stack_offset => |off| {
26652665 if (elem_size <= 8) {
2666 const raw_tmp_reg = try self.register_manager.allocReg(null, .{});
2666 const raw_tmp_reg = try self.register_manager.allocReg(null, gp);
26672667 const tmp_reg = registerAlias(raw_tmp_reg, elem_size);
26682668 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
26692669 defer self.register_manager.unlockReg(tmp_reg_lock);
......@@ -2672,7 +2672,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
26722672 try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
26732673 } else {
26742674 // TODO optimize the register allocation
2675 const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, .{});
2675 const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, gp);
26762676 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);
26772677 defer for (regs_locks) |reg| {
26782678 self.register_manager.unlockReg(reg);
......@@ -2887,7 +2887,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
28872887 },
28882888 else => {
28892889 if (abi_size <= 8) {
2890 const raw_tmp_reg = try self.register_manager.allocReg(null, .{});
2890 const raw_tmp_reg = try self.register_manager.allocReg(null, gp);
28912891 const tmp_reg = registerAlias(raw_tmp_reg, abi_size);
28922892 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
28932893 defer self.register_manager.unlockReg(tmp_reg_lock);
......@@ -3002,7 +3002,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
30023002 // TODO return special MCValue condition flags
30033003 // get overflow bit: set register to C flag
30043004 // resp. V flag
3005 const raw_dest_reg = try self.register_manager.allocReg(null, .{});
3005 const raw_dest_reg = try self.register_manager.allocReg(null, gp);
30063006 const dest_reg = raw_dest_reg.to32();
30073007
30083008 // C flag: cset reg, cs
......@@ -4065,7 +4065,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
40654065
40664066 const overflow_bit_ty = ty.structFieldType(1);
40674067 const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*));
4068 const raw_cond_reg = try self.register_manager.allocReg(null, .{});
4068 const raw_cond_reg = try self.register_manager.allocReg(null, gp);
40694069 const cond_reg = registerAlias(
40704070 raw_cond_reg,
40714071 @intCast(u32, overflow_bit_ty.abiSize(self.target.*)),
......@@ -4113,7 +4113,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
41134113 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
41144114
41154115 // TODO call extern memcpy
4116 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, .{});
4116 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp);
41174117 const regs_locks = self.register_manager.lockRegsAssumeUnused(5, regs);
41184118 defer for (regs_locks) |reg| {
41194119 self.register_manager.unlockReg(reg);
src/arch/aarch64/abi.zig+17
......@@ -1,6 +1,7 @@
11const builtin = @import("builtin");
22const bits = @import("bits.zig");
33const Register = bits.Register;
4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
45
56const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct {
67 pub const callee_preserved_regs = [_]Register{
......@@ -18,3 +19,19 @@ pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_re
1819
1920pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
2021pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
22
23const allocatable_registers = callee_preserved_regs;
24pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
25
26// Register classes
27const RegisterBitSet = RegisterManager.RegisterBitSet;
28pub const RegisterClass = struct {
29 pub const gp: RegisterBitSet = blk: {
30 var set = RegisterBitSet.initEmpty();
31 set.setRangeValue(.{
32 .start = 0,
33 .end = callee_preserved_regs.len,
34 }, true);
35 break :blk set;
36 };
37};
src/arch/arm/CodeGen.zig+35-36
......@@ -21,9 +21,6 @@ const DW = std.dwarf;
2121const leb128 = std.leb;
2222const log = std.log.scoped(.codegen);
2323const build_options = @import("build_options");
24const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
25const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers);
26const RegisterLock = RegisterManager.RegisterLock;
2724
2825const FnResult = @import("../../codegen.zig").FnResult;
2926const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
......@@ -31,14 +28,16 @@ const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
3128
3229const bits = @import("bits.zig");
3330const abi = @import("abi.zig");
31const RegisterManager = abi.RegisterManager;
32const RegisterLock = RegisterManager.RegisterLock;
3433const Register = bits.Register;
3534const Instruction = bits.Instruction;
3635const Condition = bits.Condition;
3736const callee_preserved_regs = abi.callee_preserved_regs;
3837const caller_preserved_regs = abi.caller_preserved_regs;
39const allocatable_registers = abi.allocatable_registers;
4038const c_abi_int_param_regs = abi.c_abi_int_param_regs;
4139const c_abi_int_return_regs = abi.c_abi_int_return_regs;
40const gp = abi.RegisterClass.gp;
4241
4342const InnerError = error{
4443 OutOfMemory,
......@@ -874,7 +873,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
874873 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
875874 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
876875 if (abi_size <= ptr_bytes) {
877 if (self.register_manager.tryAllocReg(inst, .{})) |reg| {
876 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
878877 return MCValue{ .register = reg };
879878 }
880879 }
......@@ -939,7 +938,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
939938/// allocated. A second call to `copyToTmpRegister` may return the same register.
940939/// This can have a side effect of spilling instructions to the stack to free up a register.
941940fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
942 const reg = try self.register_manager.allocReg(null, .{});
941 const reg = try self.register_manager.allocReg(null, gp);
943942 try self.genSetReg(ty, reg, mcv);
944943 return reg;
945944}
......@@ -948,7 +947,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
948947/// `reg_owner` is the instruction that gets associated with the register in the register table.
949948/// This can have a side effect of spilling instructions to the stack to free up a register.
950949fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
951 const reg = try self.register_manager.allocReg(reg_owner, .{});
950 const reg = try self.register_manager.allocReg(reg_owner, gp);
952951 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
953952 return MCValue{ .register = reg };
954953}
......@@ -1065,9 +1064,9 @@ fn trunc(
10651064 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
10661065 break :blk operand_reg;
10671066 } else {
1068 break :blk try self.register_manager.allocReg(inst, .{});
1067 break :blk try self.register_manager.allocReg(inst, gp);
10691068 }
1070 } else try self.register_manager.allocReg(null, .{});
1069 } else try self.register_manager.allocReg(null, gp);
10711070
10721071 switch (info_b.bits) {
10731072 32 => {
......@@ -1153,7 +1152,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11531152 break :blk op_reg;
11541153 }
11551154
1156 break :blk try self.register_manager.allocReg(null, .{});
1155 break :blk try self.register_manager.allocReg(null, gp);
11571156 };
11581157
11591158 _ = try self.addInst(.{
......@@ -1183,7 +1182,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11831182 break :blk op_reg;
11841183 }
11851184
1186 break :blk try self.register_manager.allocReg(null, .{});
1185 break :blk try self.register_manager.allocReg(null, gp);
11871186 };
11881187
11891188 _ = try self.addInst(.{
......@@ -1254,9 +1253,9 @@ fn minMax(
12541253 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
12551254 break :blk rhs_reg;
12561255 } else {
1257 break :blk try self.register_manager.allocReg(inst, .{});
1256 break :blk try self.register_manager.allocReg(inst, gp);
12581257 }
1259 } else try self.register_manager.allocReg(null, .{});
1258 } else try self.register_manager.allocReg(null, gp);
12601259
12611260 // lhs == reg should have been checked by airMinMax
12621261 //
......@@ -1438,7 +1437,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
14381437 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
14391438 defer self.register_manager.unlockReg(dest_reg_lock);
14401439
1441 const truncated_reg = try self.register_manager.allocReg(null, .{});
1440 const truncated_reg = try self.register_manager.allocReg(null, gp);
14421441 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
14431442 defer self.register_manager.unlockReg(truncated_reg_lock);
14441443
......@@ -1543,7 +1542,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15431542 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
15441543 defer self.register_manager.unlockReg(dest_reg_lock);
15451544
1546 const truncated_reg = try self.register_manager.allocReg(null, .{});
1545 const truncated_reg = try self.register_manager.allocReg(null, gp);
15471546 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
15481547 defer self.register_manager.unlockReg(truncated_reg_lock);
15491548
......@@ -1582,18 +1581,18 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15821581 const lhs_reg = if (lhs_is_register)
15831582 lhs.register
15841583 else
1585 try self.register_manager.allocReg(null, .{});
1584 try self.register_manager.allocReg(null, gp);
15861585 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
15871586 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
15881587
15891588 const rhs_reg = if (rhs_is_register)
15901589 rhs.register
15911590 else
1592 try self.register_manager.allocReg(null, .{});
1591 try self.register_manager.allocReg(null, gp);
15931592 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
15941593 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
15951594
1596 const dest_regs = try self.register_manager.allocRegs(2, .{ null, null }, .{});
1595 const dest_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
15971596 const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
15981597 defer for (dest_regs_locks) |reg| {
15991598 self.register_manager.unlockReg(reg);
......@@ -1604,7 +1603,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
16041603 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
16051604 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
16061605
1607 const truncated_reg = try self.register_manager.allocReg(null, .{});
1606 const truncated_reg = try self.register_manager.allocReg(null, gp);
16081607 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
16091608 defer self.register_manager.unlockReg(truncated_reg_lock);
16101609
......@@ -2026,7 +2025,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
20262025 const base_reg_lock = self.register_manager.lockRegAssumeUnused(base_reg);
20272026 defer self.register_manager.unlockReg(base_reg_lock);
20282027
2029 const dst_reg = try self.register_manager.allocReg(inst, .{});
2028 const dst_reg = try self.register_manager.allocReg(inst, gp);
20302029 const dst_mcv = MCValue{ .register = dst_reg };
20312030 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
20322031 defer self.register_manager.unlockReg(dst_reg_lock);
......@@ -2234,7 +2233,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
22342233 },
22352234 .stack_offset => |off| {
22362235 if (elem_size <= 4) {
2237 const tmp_reg = try self.register_manager.allocReg(null, .{});
2236 const tmp_reg = try self.register_manager.allocReg(null, gp);
22382237 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
22392238 defer self.register_manager.unlockReg(tmp_reg_lock);
22402239
......@@ -2242,7 +2241,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
22422241 try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
22432242 } else {
22442243 // TODO optimize the register allocation
2245 const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, .{});
2244 const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, gp);
22462245 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);
22472246 defer for (regs_locks) |reg_locked| {
22482247 self.register_manager.unlockReg(reg_locked);
......@@ -2271,7 +2270,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
22712270 .stack_offset,
22722271 .stack_argument_offset,
22732272 => {
2274 const reg = try self.register_manager.allocReg(null, .{});
2273 const reg = try self.register_manager.allocReg(null, gp);
22752274 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
22762275 defer self.register_manager.unlockReg(reg_lock);
22772276
......@@ -2338,14 +2337,14 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
23382337 },
23392338 else => {
23402339 if (elem_size <= 4) {
2341 const tmp_reg = try self.register_manager.allocReg(null, .{});
2340 const tmp_reg = try self.register_manager.allocReg(null, gp);
23422341 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
23432342 defer self.register_manager.unlockReg(tmp_reg_lock);
23442343
23452344 try self.genSetReg(value_ty, tmp_reg, value);
23462345 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
23472346 } else {
2348 const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, .{});
2347 const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, gp);
23492348 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);
23502349 defer for (regs_locks) |reg| {
23512350 self.register_manager.unlockReg(reg);
......@@ -2487,7 +2486,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
24872486 1 => {
24882487 // get overflow bit: set register to C flag
24892488 // resp. V flag
2490 const dest_reg = try self.register_manager.allocReg(null, .{});
2489 const dest_reg = try self.register_manager.allocReg(null, gp);
24912490
24922491 // mov reg, #0
24932492 _ = try self.addInst(.{
......@@ -2567,7 +2566,7 @@ fn binOpRegister(
25672566 break :inst Air.refToIndex(md.lhs).?;
25682567 } else null;
25692568
2570 const reg = try self.register_manager.allocReg(track_inst, .{});
2569 const reg = try self.register_manager.allocReg(track_inst, gp);
25712570
25722571 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
25732572
......@@ -2581,7 +2580,7 @@ fn binOpRegister(
25812580 break :inst Air.refToIndex(md.rhs).?;
25822581 } else null;
25832582
2584 const reg = try self.register_manager.allocReg(track_inst, .{});
2583 const reg = try self.register_manager.allocReg(track_inst, gp);
25852584
25862585 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
25872586
......@@ -2598,9 +2597,9 @@ fn binOpRegister(
25982597 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
25992598 break :blk rhs_reg;
26002599 } else {
2601 break :blk try self.register_manager.allocReg(md.inst, .{});
2600 break :blk try self.register_manager.allocReg(md.inst, gp);
26022601 }
2603 } else try self.register_manager.allocReg(null, .{}),
2602 } else try self.register_manager.allocReg(null, gp),
26042603 };
26052604
26062605 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
......@@ -2684,7 +2683,7 @@ fn binOpImmediate(
26842683 ).?;
26852684 } else null;
26862685
2687 const reg = try self.register_manager.allocReg(track_inst, .{});
2686 const reg = try self.register_manager.allocReg(track_inst, gp);
26882687
26892688 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
26902689
......@@ -2704,9 +2703,9 @@ fn binOpImmediate(
27042703 )) {
27052704 break :blk lhs_reg;
27062705 } else {
2707 break :blk try self.register_manager.allocReg(md.inst, .{});
2706 break :blk try self.register_manager.allocReg(md.inst, gp);
27082707 }
2709 } else try self.register_manager.allocReg(null, .{}),
2708 } else try self.register_manager.allocReg(null, gp),
27102709 };
27112710
27122711 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
......@@ -4363,7 +4362,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
43634362
43644363 const overflow_bit_ty = ty.structFieldType(1);
43654364 const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*));
4366 const cond_reg = try self.register_manager.allocReg(null, .{});
4365 const cond_reg = try self.register_manager.allocReg(null, gp);
43674366
43684367 // C flag: movcs reg, #1
43694368 // V flag: movvs reg, #1
......@@ -4408,7 +4407,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
44084407 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
44094408
44104409 // TODO call extern memcpy
4411 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, .{});
4410 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp);
44124411 const src_reg = regs[0];
44134412 const dst_reg = regs[1];
44144413 const len_reg = regs[2];
......@@ -4782,7 +4781,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
47824781 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
47834782
47844783 // TODO call extern memcpy
4785 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, .{});
4784 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp);
47864785 const src_reg = regs[0];
47874786 const dst_reg = regs[1];
47884787 const len_reg = regs[2];
src/arch/arm/abi.zig+17-1
......@@ -1,9 +1,25 @@
11const bits = @import("bits.zig");
22const Register = bits.Register;
3const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
34
45pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 };
56pub const caller_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3 };
6pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs;
77
88pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 };
99pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 };
10
11const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs;
12pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
13
14// Register classes
15const RegisterBitSet = RegisterManager.RegisterBitSet;
16pub const RegisterClass = struct {
17 pub const gp: RegisterBitSet = blk: {
18 var set = RegisterBitSet.initEmpty();
19 set.setRangeValue(.{
20 .start = 0,
21 .end = caller_preserved_regs.len + callee_preserved_regs.len,
22 }, true);
23 break :blk set;
24 };
25};
src/arch/riscv64/CodeGen.zig+11-11
......@@ -21,9 +21,6 @@ const DW = std.dwarf;
2121const leb128 = std.leb;
2222const log = std.log.scoped(.codegen);
2323const build_options = @import("build_options");
24const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
25const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs);
26const RegisterLock = RegisterManager.RegisterLock;
2724
2825const FnResult = @import("../../codegen.zig").FnResult;
2926const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
......@@ -32,8 +29,11 @@ const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
3229const bits = @import("bits.zig");
3330const abi = @import("abi.zig");
3431const Register = bits.Register;
32const RegisterManager = abi.RegisterManager;
33const RegisterLock = RegisterManager.RegisterLock;
3534const Instruction = abi.Instruction;
3635const callee_preserved_regs = abi.callee_preserved_regs;
36const gp = abi.RegisterClass.gp;
3737
3838const InnerError = error{
3939 OutOfMemory,
......@@ -803,7 +803,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
803803 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
804804 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
805805 if (abi_size <= ptr_bytes) {
806 if (self.register_manager.tryAllocReg(inst, .{})) |reg| {
806 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
807807 return MCValue{ .register = reg };
808808 }
809809 }
......@@ -826,7 +826,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
826826/// allocated. A second call to `copyToTmpRegister` may return the same register.
827827/// This can have a side effect of spilling instructions to the stack to free up a register.
828828fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
829 const reg = try self.register_manager.allocReg(null, .{});
829 const reg = try self.register_manager.allocReg(null, gp);
830830 try self.genSetReg(ty, reg, mcv);
831831 return reg;
832832}
......@@ -835,7 +835,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
835835/// `reg_owner` is the instruction that gets associated with the register in the register table.
836836/// This can have a side effect of spilling instructions to the stack to free up a register.
837837fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
838 const reg = try self.register_manager.allocReg(reg_owner, .{});
838 const reg = try self.register_manager.allocReg(reg_owner, gp);
839839 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
840840 return MCValue{ .register = reg };
841841}
......@@ -958,7 +958,7 @@ fn binOpRegister(
958958 break :inst Air.refToIndex(bin_op.lhs).?;
959959 } else null;
960960
961 const reg = try self.register_manager.allocReg(track_inst, .{});
961 const reg = try self.register_manager.allocReg(track_inst, gp);
962962
963963 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
964964
......@@ -973,7 +973,7 @@ fn binOpRegister(
973973 break :inst Air.refToIndex(bin_op.rhs).?;
974974 } else null;
975975
976 const reg = try self.register_manager.allocReg(track_inst, .{});
976 const reg = try self.register_manager.allocReg(track_inst, gp);
977977
978978 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
979979
......@@ -990,9 +990,9 @@ fn binOpRegister(
990990 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
991991 break :blk rhs_reg;
992992 } else {
993 break :blk try self.register_manager.allocReg(inst, .{});
993 break :blk try self.register_manager.allocReg(inst, gp);
994994 }
995 } else try self.register_manager.allocReg(null, .{});
995 } else try self.register_manager.allocReg(null, gp);
996996
997997 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
998998 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
......@@ -1482,7 +1482,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
14821482 .memory,
14831483 .stack_offset,
14841484 => {
1485 const reg = try self.register_manager.allocReg(null, .{});
1485 const reg = try self.register_manager.allocReg(null, gp);
14861486 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
14871487 defer self.register_manager.unlockReg(reg_lock);
14881488
src/arch/riscv64/abi.zig+17
......@@ -1,6 +1,23 @@
11const bits = @import("bits.zig");
22const Register = bits.Register;
3const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
34
45pub const callee_preserved_regs = [_]Register{
56 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
67};
8
9const allocatable_registers = callee_preserved_regs;
10pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
11
12// Register classes
13const RegisterBitSet = RegisterManager.RegisterBitSet;
14pub const RegisterClass = struct {
15 pub const gp: RegisterBitSet = blk: {
16 var set = RegisterBitSet.initEmpty();
17 set.setRangeValue(.{
18 .start = 0,
19 .end = callee_preserved_regs.len,
20 }, true);
21 break :blk set;
22 };
23};
src/arch/sparc64/CodeGen.zig+16-16
......@@ -21,9 +21,6 @@ const Type = @import("../../type.zig").Type;
2121const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
2222const FnResult = @import("../../codegen.zig").FnResult;
2323const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
24const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
25const RegisterManager = RegisterManagerFn(Self, Register, &abi.allocatable_regs);
26const RegisterLock = RegisterManager.RegisterLock;
2724
2825const build_options = @import("build_options");
2926
......@@ -31,7 +28,10 @@ const bits = @import("bits.zig");
3128const abi = @import("abi.zig");
3229const Instruction = bits.Instruction;
3330const ShiftWidth = Instruction.ShiftWidth;
31const RegisterManager = abi.RegisterManager;
32const RegisterLock = RegisterManager.RegisterLock;
3433const Register = bits.Register;
34const gp = abi.RegisterClass.gp;
3535
3636const Self = @This();
3737
......@@ -1613,7 +1613,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
16131613 if (reg_ok) {
16141614 // Make sure the type can fit in a register before we try to allocate one.
16151615 if (abi_size <= 8) {
1616 if (self.register_manager.tryAllocReg(inst, .{})) |reg| {
1616 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
16171617 return MCValue{ .register = reg };
16181618 }
16191619 }
......@@ -1854,7 +1854,7 @@ fn binOpImmediate(
18541854 ).?;
18551855 } else null;
18561856
1857 const reg = try self.register_manager.allocReg(track_inst, .{});
1857 const reg = try self.register_manager.allocReg(track_inst, gp);
18581858
18591859 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
18601860
......@@ -1873,10 +1873,10 @@ fn binOpImmediate(
18731873 )) {
18741874 break :blk lhs_reg;
18751875 } else {
1876 break :blk try self.register_manager.allocReg(md.inst, .{});
1876 break :blk try self.register_manager.allocReg(md.inst, gp);
18771877 }
18781878 } else blk: {
1879 break :blk try self.register_manager.allocReg(null, .{});
1879 break :blk try self.register_manager.allocReg(null, gp);
18801880 },
18811881 };
18821882
......@@ -1953,7 +1953,7 @@ fn binOpRegister(
19531953 break :inst Air.refToIndex(md.lhs).?;
19541954 } else null;
19551955
1956 const reg = try self.register_manager.allocReg(track_inst, .{});
1956 const reg = try self.register_manager.allocReg(track_inst, gp);
19571957 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
19581958
19591959 break :blk reg;
......@@ -1966,7 +1966,7 @@ fn binOpRegister(
19661966 break :inst Air.refToIndex(md.rhs).?;
19671967 } else null;
19681968
1969 const reg = try self.register_manager.allocReg(track_inst, .{});
1969 const reg = try self.register_manager.allocReg(track_inst, gp);
19701970 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
19711971
19721972 break :blk reg;
......@@ -1981,10 +1981,10 @@ fn binOpRegister(
19811981 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
19821982 break :blk rhs_reg;
19831983 } else {
1984 break :blk try self.register_manager.allocReg(md.inst, .{});
1984 break :blk try self.register_manager.allocReg(md.inst, gp);
19851985 }
19861986 } else blk: {
1987 break :blk try self.register_manager.allocReg(null, .{});
1987 break :blk try self.register_manager.allocReg(null, gp);
19881988 },
19891989 };
19901990
......@@ -2077,7 +2077,7 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {
20772077/// allocated. A second call to `copyToTmpRegister` may return the same register.
20782078/// This can have a side effect of spilling instructions to the stack to free up a register.
20792079fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
2080 const reg = try self.register_manager.allocReg(null, .{});
2080 const reg = try self.register_manager.allocReg(null, gp);
20812081 try self.genSetReg(ty, reg, mcv);
20822082 return reg;
20832083}
......@@ -2364,7 +2364,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
23642364 });
23652365 } else {
23662366 // Need to allocate a temporary register to load 64-bit immediates.
2367 const tmp_reg = try self.register_manager.allocReg(null, .{});
2367 const tmp_reg = try self.register_manager.allocReg(null, gp);
23682368
23692369 try self.genSetReg(ty, tmp_reg, .{ .immediate = @truncate(u32, x) });
23702370 try self.genSetReg(ty, reg, .{ .immediate = @truncate(u32, x >> 32) });
......@@ -2478,7 +2478,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
24782478 };
24792479 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
24802480
2481 const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, .{});
2481 const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, gp);
24822482 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);
24832483 defer for (regs_locks) |reg| {
24842484 self.register_manager.unlockReg(reg);
......@@ -2717,14 +2717,14 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
27172717 },
27182718 .stack_offset => |off| {
27192719 if (elem_size <= 8) {
2720 const tmp_reg = try self.register_manager.allocReg(null, .{});
2720 const tmp_reg = try self.register_manager.allocReg(null, gp);
27212721 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
27222722 defer self.register_manager.unlockReg(tmp_reg_lock);
27232723
27242724 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
27252725 try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
27262726 } else {
2727 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, .{});
2727 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp);
27282728 const regs_locks = self.register_manager.lockRegsAssumeUnused(3, regs);
27292729 defer for (regs_locks) |reg| {
27302730 self.register_manager.unlockReg(reg);
src/arch/sparc64/abi.zig+17-1
......@@ -1,5 +1,6 @@
11const bits = @import("bits.zig");
22const Register = bits.Register;
3const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
34
45// SPARCv9 stack constants.
56// See: Registers and the Stack Frame, page 3P-8, SCD 2.4.1.
......@@ -21,7 +22,7 @@ pub const stack_save_area = 176;
2122pub const caller_preserved_regs = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5, .g1, .g4, .g5 };
2223
2324// Try to allocate i, l, o, then g sets of registers, in order of priority.
24pub const allocatable_regs = [_]Register{
25const allocatable_regs = [_]Register{
2526 // zig fmt: off
2627 .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5",
2728 .l0, .l1, .l2, .l3, .l4, .l5, .l6, .l7,
......@@ -35,3 +36,18 @@ pub const c_abi_int_param_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2"
3536
3637pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3 };
3738pub const c_abi_int_return_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3" };
39
40pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_regs);
41
42// Register classes
43const RegisterBitSet = RegisterManager.RegisterBitSet;
44pub const RegisterClass = struct {
45 pub const gp: RegisterBitSet = blk: {
46 var set = RegisterBitSet.initEmpty();
47 set.setRangeValue(.{
48 .start = 0,
49 .end = allocatable_regs.len,
50 }, true);
51 break :blk set;
52 };
53};
src/arch/x86_64/CodeGen.zig+23-41
......@@ -884,9 +884,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
884884 if (self.intrinsicsAllowed(elem_ty)) {
885885 const ptr_bytes: u64 = 32;
886886 if (abi_size <= ptr_bytes) {
887 if (self.register_manager.tryAllocReg(inst, .{
888 .selector_mask = sse,
889 })) |reg| {
887 if (self.register_manager.tryAllocReg(inst, sse)) |reg| {
890888 return MCValue{ .register = registerAlias(reg, abi_size) };
891889 }
892890 }
......@@ -899,9 +897,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
899897 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
900898 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
901899 if (abi_size <= ptr_bytes) {
902 if (self.register_manager.tryAllocReg(inst, .{
903 .selector_mask = gp,
904 })) |reg| {
900 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
905901 return MCValue{ .register = registerAlias(reg, abi_size) };
906902 }
907903 }
......@@ -972,16 +968,14 @@ pub fn spillRegisters(self: *Self, comptime count: comptime_int, registers: [cou
972968/// allocated. A second call to `copyToTmpRegister` may return the same register.
973969/// This can have a side effect of spilling instructions to the stack to free up a register.
974970fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
975 const mask: RegisterManager.RegisterBitSet = switch (ty.zigTypeTag()) {
971 const reg_class: RegisterManager.RegisterBitSet = switch (ty.zigTypeTag()) {
976972 .Float => blk: {
977973 if (self.intrinsicsAllowed(ty)) break :blk sse;
978974 return self.fail("TODO copy {} to register", .{ty.fmtDebug()});
979975 },
980976 else => gp,
981977 };
982 const reg: Register = try self.register_manager.allocReg(null, .{
983 .selector_mask = mask,
984 });
978 const reg: Register = try self.register_manager.allocReg(null, reg_class);
985979 try self.genSetReg(ty, reg, mcv);
986980 return reg;
987981}
......@@ -991,16 +985,14 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
991985/// This can have a side effect of spilling instructions to the stack to free up a register.
992986/// WARNING make sure that the allocated register matches the returned MCValue from an instruction!
993987fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {
994 const mask: RegisterManager.RegisterBitSet = switch (ty.zigTypeTag()) {
988 const reg_class: RegisterManager.RegisterBitSet = switch (ty.zigTypeTag()) {
995989 .Float => blk: {
996990 if (self.intrinsicsAllowed(ty)) break :blk sse;
997991 return self.fail("TODO copy {} to register", .{ty.fmtDebug()});
998992 },
999993 else => gp,
1000994 };
1001 const reg: Register = try self.register_manager.allocReg(reg_owner, .{
1002 .selector_mask = mask,
1003 });
995 const reg: Register = try self.register_manager.allocReg(reg_owner, reg_class);
1004996 try self.genSetReg(ty, reg, mcv);
1005997 return MCValue{ .register = reg };
1006998}
......@@ -1056,9 +1048,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
10561048 };
10571049 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
10581050
1059 const reg = try self.register_manager.allocReg(inst, .{
1060 .selector_mask = gp,
1061 });
1051 const reg = try self.register_manager.allocReg(inst, gp);
10621052 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
10631053 try self.genSetReg(operand_ty, reg, operand);
10641054 break :blk MCValue{ .register = reg };
......@@ -1413,9 +1403,7 @@ fn genSetStackTruncatedOverflowCompare(
14131403 .unsigned => ty,
14141404 };
14151405
1416 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, .{
1417 .selector_mask = gp,
1418 });
1406 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp);
14191407 const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);
14201408 defer for (temp_regs_locks) |rreg| {
14211409 self.register_manager.unlockReg(rreg);
......@@ -2077,9 +2065,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
20772065 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
20782066 defer self.register_manager.unlockReg(offset_reg_lock);
20792067
2080 const addr_reg = try self.register_manager.allocReg(null, .{
2081 .selector_mask = gp,
2082 });
2068 const addr_reg = try self.register_manager.allocReg(null, gp);
20832069 switch (slice_mcv) {
20842070 .stack_offset => |off| {
20852071 // mov reg, [rbp - 8]
......@@ -2158,9 +2144,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
21582144 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
21592145 defer self.register_manager.unlockReg(offset_reg_lock);
21602146
2161 const addr_reg = try self.register_manager.allocReg(null, .{
2162 .selector_mask = gp,
2163 });
2147 const addr_reg = try self.register_manager.allocReg(null, gp);
21642148 switch (array) {
21652149 .register => {
21662150 const off = @intCast(i32, try self.allocMem(
......@@ -2527,7 +2511,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
25272511 },
25282512 .stack_offset => |off| {
25292513 if (abi_size <= 8) {
2530 const tmp_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
2514 const tmp_reg = try self.register_manager.allocReg(null, gp);
25312515 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
25322516 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }, .{});
25332517 }
......@@ -2728,7 +2712,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
27282712 };
27292713 defer if (value_lock) |lock| self.register_manager.unlockReg(lock);
27302714
2731 const addr_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
2715 const addr_reg = try self.register_manager.allocReg(null, gp);
27322716 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
27332717 defer self.register_manager.unlockReg(addr_reg_lock);
27342718
......@@ -2800,7 +2784,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
28002784 .memory,
28012785 => {
28022786 if (abi_size <= 8) {
2803 const tmp_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
2787 const tmp_reg = try self.register_manager.allocReg(null, gp);
28042788 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
28052789 defer self.register_manager.unlockReg(tmp_reg_lock);
28062790
......@@ -2918,7 +2902,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
29182902 if (can_reuse_operand) {
29192903 break :blk reg;
29202904 } else {
2921 const result_reg = try self.register_manager.allocReg(inst, .{ .selector_mask = gp });
2905 const result_reg = try self.register_manager.allocReg(inst, gp);
29222906 try self.genSetReg(ptr_ty, result_reg, mcv);
29232907 break :blk result_reg;
29242908 }
......@@ -3019,7 +3003,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
30193003 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
30203004 defer self.register_manager.unlockReg(reg_lock);
30213005
3022 const dst_reg = try self.register_manager.allocReg(inst, .{ .selector_mask = gp });
3006 const dst_reg = try self.register_manager.allocReg(inst, gp);
30233007 const flags: u2 = switch (mcv) {
30243008 .register_overflow_unsigned => 0b10,
30253009 .register_overflow_signed => 0b00,
......@@ -5428,7 +5412,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
54285412
54295413 const overflow_bit_ty = ty.structFieldType(1);
54305414 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
5431 const tmp_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
5415 const tmp_reg = try self.register_manager.allocReg(null, gp);
54325416 const flags: u2 = switch (mcv) {
54335417 .register_overflow_unsigned => 0b10,
54345418 .register_overflow_signed => 0b00,
......@@ -5656,7 +5640,7 @@ fn genInlineMemcpy(
56565640 null;
56575641 defer if (dsbase_lock) |lock| self.register_manager.unlockReg(lock);
56585642
5659 const dst_addr_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
5643 const dst_addr_reg = try self.register_manager.allocReg(null, gp);
56605644 switch (dst_ptr) {
56615645 .memory,
56625646 .got_load,
......@@ -5691,7 +5675,7 @@ fn genInlineMemcpy(
56915675 const dst_addr_reg_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);
56925676 defer self.register_manager.unlockReg(dst_addr_reg_lock);
56935677
5694 const src_addr_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
5678 const src_addr_reg = try self.register_manager.allocReg(null, gp);
56955679 switch (src_ptr) {
56965680 .memory,
56975681 .got_load,
......@@ -5726,9 +5710,7 @@ fn genInlineMemcpy(
57265710 const src_addr_reg_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
57275711 defer self.register_manager.unlockReg(src_addr_reg_lock);
57285712
5729 const regs = try self.register_manager.allocRegs(2, .{ null, null }, .{
5730 .selector_mask = gp,
5731 });
5713 const regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
57325714 const count_reg = regs[0].to64();
57335715 const tmp_reg = regs[1].to8();
57345716
......@@ -5828,7 +5810,7 @@ fn genInlineMemset(
58285810 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
58295811 defer self.register_manager.unlockReg(rax_lock);
58305812
5831 const addr_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
5813 const addr_reg = try self.register_manager.allocReg(null, gp);
58325814 switch (dst_ptr) {
58335815 .memory,
58345816 .got_load,
......@@ -6087,7 +6069,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
60876069 => {
60886070 switch (ty.zigTypeTag()) {
60896071 .Float => {
6090 const base_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
6072 const base_reg = try self.register_manager.allocReg(null, gp);
60916073 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);
60926074
60936075 if (self.intrinsicsAllowed(ty)) {
......@@ -6130,7 +6112,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
61306112 },
61316113 .memory => |x| switch (ty.zigTypeTag()) {
61326114 .Float => {
6133 const base_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
6115 const base_reg = try self.register_manager.allocReg(null, gp);
61346116 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);
61356117
61366118 if (self.intrinsicsAllowed(ty)) {
......@@ -6461,7 +6443,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
64616443 const src: MCValue = blk: {
64626444 switch (src_ptr) {
64636445 .got_load, .direct_load, .memory => {
6464 const reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
6446 const reg = try self.register_manager.allocReg(null, gp);
64656447 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);
64666448 _ = try self.addInst(.{
64676449 .tag = .mov,
src/register_manager.zig+80-33
......@@ -57,6 +57,11 @@ pub fn RegisterManager(
5757 return @fieldParentPtr(Function, "register_manager", self);
5858 }
5959
60 fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool {
61 const index = indexOfRegIntoTracked(reg) orelse return true;
62 return !register_class.isSet(index);
63 }
64
6065 fn markRegAllocated(self: *Self, reg: Register) void {
6166 const index = indexOfRegIntoTracked(reg) orelse return;
6267 self.allocated_registers.set(index);
......@@ -167,10 +172,6 @@ pub fn RegisterManager(
167172 return self.locked_registers.count() > 0;
168173 }
169174
170 const AllocOpts = struct {
171 selector_mask: ?RegisterBitSet = null,
172 };
173
174175 /// Allocates a specified number of registers, optionally
175176 /// tracking them. Returns `null` if not enough registers are
176177 /// free.
......@@ -178,14 +179,12 @@ pub fn RegisterManager(
178179 self: *Self,
179180 comptime count: comptime_int,
180181 insts: [count]?Air.Inst.Index,
181 opts: AllocOpts,
182 register_class: RegisterBitSet,
182183 ) ?[count]Register {
183184 comptime assert(count > 0 and count <= tracked_registers.len);
184185
185 const available_registers = opts.selector_mask orelse RegisterBitSet.initFull();
186
187186 var free_and_not_locked_registers = self.free_registers;
188 free_and_not_locked_registers.setIntersection(available_registers);
187 free_and_not_locked_registers.setIntersection(register_class);
189188
190189 var unlocked_registers = self.locked_registers;
191190 unlocked_registers.toggleAll();
......@@ -198,6 +197,7 @@ pub fn RegisterManager(
198197 var i: usize = 0;
199198 for (tracked_registers) |reg| {
200199 if (i >= count) break;
200 if (excludeRegister(reg, register_class)) continue;
201201 if (self.isRegLocked(reg)) continue;
202202 if (!self.isRegFree(reg)) continue;
203203
......@@ -223,8 +223,8 @@ pub fn RegisterManager(
223223 /// Allocates a register and optionally tracks it with a
224224 /// corresponding instruction. Returns `null` if all registers
225225 /// are allocated.
226 pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index, opts: AllocOpts) ?Register {
227 return if (tryAllocRegs(self, 1, .{inst}, opts)) |regs| regs[0] else null;
226 pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index, register_class: RegisterBitSet) ?Register {
227 return if (tryAllocRegs(self, 1, .{inst}, register_class)) |regs| regs[0] else null;
228228 }
229229
230230 /// Allocates a specified number of registers, optionally
......@@ -234,18 +234,16 @@ pub fn RegisterManager(
234234 self: *Self,
235235 comptime count: comptime_int,
236236 insts: [count]?Air.Inst.Index,
237 opts: AllocOpts,
237 register_class: RegisterBitSet,
238238 ) AllocateRegistersError![count]Register {
239239 comptime assert(count > 0 and count <= tracked_registers.len);
240240
241 const available_registers = opts.selector_mask orelse RegisterBitSet.initFull();
242
243241 var locked_registers = self.locked_registers;
244 locked_registers.setIntersection(available_registers);
242 locked_registers.setIntersection(register_class);
245243
246 if (count > available_registers.count() - locked_registers.count()) return error.OutOfRegisters;
244 if (count > register_class.count() - locked_registers.count()) return error.OutOfRegisters;
247245
248 const result = self.tryAllocRegs(count, insts, opts) orelse blk: {
246 const result = self.tryAllocRegs(count, insts, register_class) orelse blk: {
249247 // We'll take over the first count registers. Spill
250248 // the instructions that were previously there to a
251249 // stack allocations.
......@@ -253,6 +251,7 @@ pub fn RegisterManager(
253251 var i: usize = 0;
254252 for (tracked_registers) |reg| {
255253 if (i >= count) break;
254 if (excludeRegister(reg, register_class)) continue;
256255 if (self.isRegLocked(reg)) continue;
257256
258257 regs[i] = reg;
......@@ -288,8 +287,12 @@ pub fn RegisterManager(
288287
289288 /// Allocates a register and optionally tracks it with a
290289 /// corresponding instruction.
291 pub fn allocReg(self: *Self, inst: ?Air.Inst.Index, opts: AllocOpts) AllocateRegistersError!Register {
292 return (try self.allocRegs(1, .{inst}, opts))[0];
290 pub fn allocReg(
291 self: *Self,
292 inst: ?Air.Inst.Index,
293 register_class: RegisterBitSet,
294 ) AllocateRegistersError!Register {
295 return (try self.allocRegs(1, .{inst}, register_class))[0];
293296 }
294297
295298 /// Spills the register if it is currently allocated. If a
......@@ -374,11 +377,15 @@ const MockRegister2 = enum(u2) {
374377fn MockFunction(comptime Register: type) type {
375378 return struct {
376379 allocator: Allocator,
377 register_manager: RegisterManager(Self, Register, &Register.allocatable_registers) = .{},
380 register_manager: RegisterManagerT = .{},
378381 spilled: std.ArrayListUnmanaged(Register) = .{},
379382
380383 const Self = @This();
381384
385 const RegisterManagerT = RegisterManager(Self, Register, &Register.allocatable_registers);
386
387 pub const reg_class: RegisterManagerT.RegisterBitSet = RegisterManagerT.RegisterBitSet.initFull();
388
382389 pub fn deinit(self: *Self) void {
383390 self.spilled.deinit(self.allocator);
384391 }
......@@ -423,10 +430,20 @@ test "tryAllocReg: no spilling" {
423430 defer function.deinit();
424431
425432 const mock_instruction: Air.Inst.Index = 1;
426
427 try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction, .{}));
428 try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction, .{}));
429 try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction, .{}));
433 const reg_class = MockFunction1.reg_class;
434
435 try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(
436 mock_instruction,
437 reg_class,
438 ));
439 try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(
440 mock_instruction,
441 reg_class,
442 ));
443 try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(
444 mock_instruction,
445 reg_class,
446 ));
430447
431448 try expect(function.register_manager.isRegAllocated(.r2));
432449 try expect(function.register_manager.isRegAllocated(.r3));
......@@ -451,17 +468,30 @@ test "allocReg: spilling" {
451468 defer function.deinit();
452469
453470 const mock_instruction: Air.Inst.Index = 1;
471 const reg_class = MockFunction1.reg_class;
454472
455 try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction, .{}));
456 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, .{}));
473 try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(
474 mock_instruction,
475 reg_class,
476 ));
477 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(
478 mock_instruction,
479 reg_class,
480 ));
457481
458482 // Spill a register
459 try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction, .{}));
483 try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(
484 mock_instruction,
485 reg_class,
486 ));
460487 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
461488
462489 // No spilling necessary
463490 function.register_manager.freeReg(.r3);
464 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, .{}));
491 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(
492 mock_instruction,
493 reg_class,
494 ));
465495 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
466496
467497 // Locked registers
......@@ -470,7 +500,10 @@ test "allocReg: spilling" {
470500 const lock = function.register_manager.lockReg(.r2);
471501 defer if (lock) |reg| function.register_manager.unlockReg(reg);
472502
473 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, .{}));
503 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(
504 mock_instruction,
505 reg_class,
506 ));
474507 }
475508 try expect(!function.register_manager.lockedRegsExist());
476509}
......@@ -483,7 +516,13 @@ test "tryAllocRegs" {
483516 };
484517 defer function.deinit();
485518
486 try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, .{}).?);
519 const reg_class = MockFunction2.reg_class;
520
521 try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(
522 3,
523 .{ null, null, null },
524 reg_class,
525 ).?);
487526
488527 try expect(function.register_manager.isRegAllocated(.r0));
489528 try expect(function.register_manager.isRegAllocated(.r1));
......@@ -498,7 +537,11 @@ test "tryAllocRegs" {
498537 const lock = function.register_manager.lockReg(.r1);
499538 defer if (lock) |reg| function.register_manager.unlockReg(reg);
500539
501 try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, .{}).?);
540 try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(
541 3,
542 .{ null, null, null },
543 reg_class,
544 ).?);
502545 }
503546 try expect(!function.register_manager.lockedRegsExist());
504547
......@@ -518,6 +561,8 @@ test "allocRegs: normal usage" {
518561 };
519562 defer function.deinit();
520563
564 const reg_class = MockFunction2.reg_class;
565
521566 {
522567 const result_reg: MockRegister2 = .r1;
523568
......@@ -537,7 +582,7 @@ test "allocRegs: normal usage" {
537582 const lock = function.register_manager.lockReg(result_reg);
538583 defer if (lock) |reg| function.register_manager.unlockReg(reg);
539584
540 const regs = try function.register_manager.allocRegs(2, .{ null, null }, .{});
585 const regs = try function.register_manager.allocRegs(2, .{ null, null }, reg_class);
541586 try function.genAdd(result_reg, regs[0], regs[1]);
542587 }
543588}
......@@ -552,6 +597,8 @@ test "allocRegs: selectively reducing register pressure" {
552597 };
553598 defer function.deinit();
554599
600 const reg_class = MockFunction2.reg_class;
601
555602 {
556603 const result_reg: MockRegister2 = .r1;
557604
......@@ -559,12 +606,12 @@ test "allocRegs: selectively reducing register pressure" {
559606
560607 // Here, we don't defer unlock because we manually unlock
561608 // after genAdd
562 const regs = try function.register_manager.allocRegs(2, .{ null, null }, .{});
609 const regs = try function.register_manager.allocRegs(2, .{ null, null }, reg_class);
563610
564611 try function.genAdd(result_reg, regs[0], regs[1]);
565612 function.register_manager.unlockReg(lock.?);
566613
567 const extra_summand_reg = try function.register_manager.allocReg(null, .{});
614 const extra_summand_reg = try function.register_manager.allocReg(null, reg_class);
568615 try function.genAdd(result_reg, result_reg, extra_summand_reg);
569616 }
570617}