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;...@@ -21,9 +21,6 @@ const DW = std.dwarf;
21const leb128 = std.leb;21const leb128 = std.leb;
22const log = std.log.scoped(.codegen);22const log = std.log.scoped(.codegen);
23const build_options = @import("build_options");23const 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
28const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;25const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
29const FnResult = @import("../../codegen.zig").FnResult;26const FnResult = @import("../../codegen.zig").FnResult;
...@@ -31,11 +28,14 @@ const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;...@@ -31,11 +28,14 @@ const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
3128
32const bits = @import("bits.zig");29const bits = @import("bits.zig");
33const abi = @import("abi.zig");30const abi = @import("abi.zig");
31const RegisterManager = abi.RegisterManager;
32const RegisterLock = RegisterManager.RegisterLock;
34const Register = bits.Register;33const Register = bits.Register;
35const Instruction = bits.Instruction;34const Instruction = bits.Instruction;
36const callee_preserved_regs = abi.callee_preserved_regs;35const callee_preserved_regs = abi.callee_preserved_regs;
37const c_abi_int_param_regs = abi.c_abi_int_param_regs;36const c_abi_int_param_regs = abi.c_abi_int_param_regs;
38const c_abi_int_return_regs = abi.c_abi_int_return_regs;37const c_abi_int_return_regs = abi.c_abi_int_return_regs;
38const gp = abi.RegisterClass.gp;
3939
40const InnerError = error{40const InnerError = error{
41 OutOfMemory,41 OutOfMemory,
...@@ -888,7 +888,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -888,7 +888,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
888 if (reg_ok) {888 if (reg_ok) {
889 // Make sure the type can fit in a register before we try to allocate one.889 // Make sure the type can fit in a register before we try to allocate one.
890 if (abi_size <= 8) {890 if (abi_size <= 8) {
891 if (self.register_manager.tryAllocReg(inst, .{})) |reg| {891 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
892 return MCValue{ .register = registerAlias(reg, abi_size) };892 return MCValue{ .register = registerAlias(reg, abi_size) };
893 }893 }
894 }894 }
...@@ -951,7 +951,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {...@@ -951,7 +951,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
951/// allocated. A second call to `copyToTmpRegister` may return the same register.951/// allocated. A second call to `copyToTmpRegister` may return the same register.
952/// This can have a side effect of spilling instructions to the stack to free up a register.952/// This can have a side effect of spilling instructions to the stack to free up a register.
953fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {953fn 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);
955 const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));955 const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));
956 try self.genSetReg(ty, reg, mcv);956 try self.genSetReg(ty, reg, mcv);
957 return reg;957 return reg;
...@@ -961,7 +961,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {...@@ -961,7 +961,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
961/// `reg_owner` is the instruction that gets associated with the register in the register table.961/// `reg_owner` is the instruction that gets associated with the register in the register table.
962/// This can have a side effect of spilling instructions to the stack to free up a register.962/// This can have a side effect of spilling instructions to the stack to free up a register.
963fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {963fn 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);
965 const ty = self.air.typeOfIndex(reg_owner);965 const ty = self.air.typeOfIndex(reg_owner);
966 const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));966 const reg = registerAlias(raw_reg, ty.abiSize(self.target.*));
967 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);967 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
...@@ -1074,11 +1074,11 @@ fn trunc(...@@ -1074,11 +1074,11 @@ fn trunc(
1074 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {1074 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1075 break :blk registerAlias(operand_reg, dest_ty.abiSize(self.target.*));1075 break :blk registerAlias(operand_reg, dest_ty.abiSize(self.target.*));
1076 } else {1076 } else {
1077 const raw_reg = try self.register_manager.allocReg(inst, .{});1077 const raw_reg = try self.register_manager.allocReg(inst, gp);
1078 break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));1078 break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));
1079 }1079 }
1080 } else blk: {1080 } else blk: {
1081 const raw_reg = try self.register_manager.allocReg(null, .{});1081 const raw_reg = try self.register_manager.allocReg(null, gp);
1082 break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));1082 break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*));
1083 };1083 };
10841084
...@@ -1160,7 +1160,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1160,7 +1160,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1160 break :blk op_reg;1160 break :blk op_reg;
1161 }1161 }
11621162
1163 const raw_reg = try self.register_manager.allocReg(null, .{});1163 const raw_reg = try self.register_manager.allocReg(null, gp);
1164 break :blk raw_reg.to32();1164 break :blk raw_reg.to32();
1165 };1165 };
11661166
...@@ -1193,7 +1193,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1193,7 +1193,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1193 break :blk op_reg;1193 break :blk op_reg;
1194 }1194 }
11951195
1196 const raw_reg = try self.register_manager.allocReg(null, .{});1196 const raw_reg = try self.register_manager.allocReg(null, gp);
1197 break :blk registerAlias(raw_reg, operand_ty.abiSize(self.target.*));1197 break :blk registerAlias(raw_reg, operand_ty.abiSize(self.target.*));
1198 };1198 };
11991199
...@@ -1293,7 +1293,7 @@ fn binOpRegister(...@@ -1293,7 +1293,7 @@ fn binOpRegister(
1293 break :inst Air.refToIndex(md.lhs).?;1293 break :inst Air.refToIndex(md.lhs).?;
1294 } else null;1294 } 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);
1297 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1297 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
12981298
1299 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1299 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
...@@ -1308,7 +1308,7 @@ fn binOpRegister(...@@ -1308,7 +1308,7 @@ fn binOpRegister(
1308 break :inst Air.refToIndex(md.rhs).?;1308 break :inst Air.refToIndex(md.rhs).?;
1309 } else null;1309 } 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);
1312 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));1312 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));
13131313
1314 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1314 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
...@@ -1326,11 +1326,11 @@ fn binOpRegister(...@@ -1326,11 +1326,11 @@ fn binOpRegister(
1326 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {1326 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
1327 break :blk rhs_reg;1327 break :blk rhs_reg;
1328 } else {1328 } else {
1329 const raw_reg = try self.register_manager.allocReg(md.inst, .{});1329 const raw_reg = try self.register_manager.allocReg(md.inst, gp);
1330 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1330 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
1331 }1331 }
1332 } else blk: {1332 } else blk: {
1333 const raw_reg = try self.register_manager.allocReg(null, .{});1333 const raw_reg = try self.register_manager.allocReg(null, gp);
1334 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1334 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
1335 },1335 },
1336 };1336 };
...@@ -1431,7 +1431,7 @@ fn binOpImmediate(...@@ -1431,7 +1431,7 @@ fn binOpImmediate(
1431 ).?;1431 ).?;
1432 } else null;1432 } 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);
1435 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1435 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
14361436
1437 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1437 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
...@@ -1452,11 +1452,11 @@ fn binOpImmediate(...@@ -1452,11 +1452,11 @@ fn binOpImmediate(
1452 )) {1452 )) {
1453 break :blk lhs_reg;1453 break :blk lhs_reg;
1454 } else {1454 } else {
1455 const raw_reg = try self.register_manager.allocReg(md.inst, .{});1455 const raw_reg = try self.register_manager.allocReg(md.inst, gp);
1456 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1456 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
1457 }1457 }
1458 } else blk: {1458 } else blk: {
1459 const raw_reg = try self.register_manager.allocReg(null, .{});1459 const raw_reg = try self.register_manager.allocReg(null, gp);
1460 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1460 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
1461 },1461 },
1462 };1462 };
...@@ -1872,7 +1872,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1872,7 +1872,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1872 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1872 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1873 defer self.register_manager.unlockReg(dest_reg_lock);1873 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);
1876 const truncated_reg = registerAlias(raw_truncated_reg, lhs_ty.abiSize(self.target.*));1876 const truncated_reg = registerAlias(raw_truncated_reg, lhs_ty.abiSize(self.target.*));
1877 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);1877 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
1878 defer self.register_manager.unlockReg(truncated_reg_lock);1878 defer self.register_manager.unlockReg(truncated_reg_lock);
...@@ -1983,7 +1983,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1983,7 +1983,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1983 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1983 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1984 defer self.register_manager.unlockReg(dest_reg_lock);1984 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);
1987 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);1987 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
1988 defer self.register_manager.unlockReg(truncated_reg_lock);1988 defer self.register_manager.unlockReg(truncated_reg_lock);
19891989
...@@ -2048,7 +2048,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2048,7 +2048,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2048 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);2048 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
20492049
2050 const lhs_reg = if (lhs_is_register) lhs.register else blk: {2050 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);
2052 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));2052 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
2053 break :blk reg;2053 break :blk reg;
2054 };2054 };
...@@ -2056,7 +2056,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2056,7 +2056,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2056 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);2056 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
20572057
2058 const rhs_reg = if (rhs_is_register) rhs.register else blk: {2058 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);
2060 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));2060 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));
2061 break :blk reg;2061 break :blk reg;
2062 };2062 };
...@@ -2067,7 +2067,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2067,7 +2067,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2067 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);2067 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
20682068
2069 const dest_reg = blk: {2069 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);
2071 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));2071 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
2072 break :blk reg;2072 break :blk reg;
2073 };2073 };
...@@ -2086,7 +2086,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2086,7 +2086,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2086 } },2086 } },
2087 });2087 });
20882088
2089 const dest_high_reg = try self.register_manager.allocReg(null, .{});2089 const dest_high_reg = try self.register_manager.allocReg(null, gp);
2090 const dest_high_reg_lock = self.register_manager.lockRegAssumeUnused(dest_high_reg);2090 const dest_high_reg_lock = self.register_manager.lockRegAssumeUnused(dest_high_reg);
2091 defer self.register_manager.unlockReg(dest_high_reg_lock);2091 defer self.register_manager.unlockReg(dest_high_reg_lock);
20922092
...@@ -2136,7 +2136,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2136,7 +2136,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2136 }2136 }
2137 },2137 },
2138 .unsigned => {2138 .unsigned => {
2139 const dest_high_reg = try self.register_manager.allocReg(null, .{});2139 const dest_high_reg = try self.register_manager.allocReg(null, gp);
2140 const dest_high_reg_lock = self.register_manager.lockRegAssumeUnused(dest_high_reg);2140 const dest_high_reg_lock = self.register_manager.lockRegAssumeUnused(dest_high_reg);
2141 defer self.register_manager.unlockReg(dest_high_reg_lock);2141 defer self.register_manager.unlockReg(dest_high_reg_lock);
21422142
...@@ -2192,7 +2192,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2192,7 +2192,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2192 },2192 },
2193 }2193 }
21942194
2195 const truncated_reg = try self.register_manager.allocReg(null, .{});2195 const truncated_reg = try self.register_manager.allocReg(null, gp);
2196 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);2196 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
2197 defer self.register_manager.unlockReg(truncated_reg_lock);2197 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...@@ -2663,7 +2663,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2663 },2663 },
2664 .stack_offset => |off| {2664 .stack_offset => |off| {
2665 if (elem_size <= 8) {2665 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);
2667 const tmp_reg = registerAlias(raw_tmp_reg, elem_size);2667 const tmp_reg = registerAlias(raw_tmp_reg, elem_size);
2668 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);2668 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
2669 defer self.register_manager.unlockReg(tmp_reg_lock);2669 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...@@ -2672,7 +2672,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2672 try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });2672 try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
2673 } else {2673 } else {
2674 // TODO optimize the register allocation2674 // 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);
2676 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);2676 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);
2677 defer for (regs_locks) |reg| {2677 defer for (regs_locks) |reg| {
2678 self.register_manager.unlockReg(reg);2678 self.register_manager.unlockReg(reg);
...@@ -2887,7 +2887,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2887,7 +2887,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2887 },2887 },
2888 else => {2888 else => {
2889 if (abi_size <= 8) {2889 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);
2891 const tmp_reg = registerAlias(raw_tmp_reg, abi_size);2891 const tmp_reg = registerAlias(raw_tmp_reg, abi_size);
2892 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);2892 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
2893 defer self.register_manager.unlockReg(tmp_reg_lock);2893 defer self.register_manager.unlockReg(tmp_reg_lock);
...@@ -3002,7 +3002,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3002,7 +3002,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3002 // TODO return special MCValue condition flags3002 // TODO return special MCValue condition flags
3003 // get overflow bit: set register to C flag3003 // get overflow bit: set register to C flag
3004 // resp. V flag3004 // 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);
3006 const dest_reg = raw_dest_reg.to32();3006 const dest_reg = raw_dest_reg.to32();
30073007
3008 // C flag: cset reg, cs3008 // C flag: cset reg, cs
...@@ -4065,7 +4065,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4065,7 +4065,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
40654065
4066 const overflow_bit_ty = ty.structFieldType(1);4066 const overflow_bit_ty = ty.structFieldType(1);
4067 const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*));4067 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);
4069 const cond_reg = registerAlias(4069 const cond_reg = registerAlias(
4070 raw_cond_reg,4070 raw_cond_reg,
4071 @intCast(u32, overflow_bit_ty.abiSize(self.target.*)),4071 @intCast(u32, overflow_bit_ty.abiSize(self.target.*)),
...@@ -4113,7 +4113,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4113,7 +4113,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4113 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);4113 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
41144114
4115 // TODO call extern memcpy4115 // 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);
4117 const regs_locks = self.register_manager.lockRegsAssumeUnused(5, regs);4117 const regs_locks = self.register_manager.lockRegsAssumeUnused(5, regs);
4118 defer for (regs_locks) |reg| {4118 defer for (regs_locks) |reg| {
4119 self.register_manager.unlockReg(reg);4119 self.register_manager.unlockReg(reg);
src/arch/aarch64/abi.zig+17
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const bits = @import("bits.zig");2const bits = @import("bits.zig");
3const Register = bits.Register;3const Register = bits.Register;
4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
45
5const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct {6const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct {
6 pub const callee_preserved_regs = [_]Register{7 pub const callee_preserved_regs = [_]Register{
...@@ -18,3 +19,19 @@ pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_re...@@ -18,3 +19,19 @@ pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_re
1819
19pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };20pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
20pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };21pub 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;...@@ -21,9 +21,6 @@ const DW = std.dwarf;
21const leb128 = std.leb;21const leb128 = std.leb;
22const log = std.log.scoped(.codegen);22const log = std.log.scoped(.codegen);
23const build_options = @import("build_options");23const build_options = @import("build_options");
24const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
25const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers);
26const RegisterLock = RegisterManager.RegisterLock;
2724
28const FnResult = @import("../../codegen.zig").FnResult;25const FnResult = @import("../../codegen.zig").FnResult;
29const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;26const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
...@@ -31,14 +28,16 @@ const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;...@@ -31,14 +28,16 @@ const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
3128
32const bits = @import("bits.zig");29const bits = @import("bits.zig");
33const abi = @import("abi.zig");30const abi = @import("abi.zig");
31const RegisterManager = abi.RegisterManager;
32const RegisterLock = RegisterManager.RegisterLock;
34const Register = bits.Register;33const Register = bits.Register;
35const Instruction = bits.Instruction;34const Instruction = bits.Instruction;
36const Condition = bits.Condition;35const Condition = bits.Condition;
37const callee_preserved_regs = abi.callee_preserved_regs;36const callee_preserved_regs = abi.callee_preserved_regs;
38const caller_preserved_regs = abi.caller_preserved_regs;37const caller_preserved_regs = abi.caller_preserved_regs;
39const allocatable_registers = abi.allocatable_registers;
40const c_abi_int_param_regs = abi.c_abi_int_param_regs;38const c_abi_int_param_regs = abi.c_abi_int_param_regs;
41const c_abi_int_return_regs = abi.c_abi_int_return_regs;39const c_abi_int_return_regs = abi.c_abi_int_return_regs;
40const gp = abi.RegisterClass.gp;
4241
43const InnerError = error{42const InnerError = error{
44 OutOfMemory,43 OutOfMemory,
...@@ -874,7 +873,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -874,7 +873,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
874 const ptr_bits = self.target.cpu.arch.ptrBitWidth();873 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
875 const ptr_bytes: u64 = @divExact(ptr_bits, 8);874 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
876 if (abi_size <= ptr_bytes) {875 if (abi_size <= ptr_bytes) {
877 if (self.register_manager.tryAllocReg(inst, .{})) |reg| {876 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
878 return MCValue{ .register = reg };877 return MCValue{ .register = reg };
879 }878 }
880 }879 }
...@@ -939,7 +938,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {...@@ -939,7 +938,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
939/// allocated. A second call to `copyToTmpRegister` may return the same register.938/// allocated. A second call to `copyToTmpRegister` may return the same register.
940/// This can have a side effect of spilling instructions to the stack to free up a register.939/// This can have a side effect of spilling instructions to the stack to free up a register.
941fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {940fn 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);
943 try self.genSetReg(ty, reg, mcv);942 try self.genSetReg(ty, reg, mcv);
944 return reg;943 return reg;
945}944}
...@@ -948,7 +947,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {...@@ -948,7 +947,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
948/// `reg_owner` is the instruction that gets associated with the register in the register table.947/// `reg_owner` is the instruction that gets associated with the register in the register table.
949/// This can have a side effect of spilling instructions to the stack to free up a register.948/// This can have a side effect of spilling instructions to the stack to free up a register.
950fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {949fn 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);
952 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);951 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
953 return MCValue{ .register = reg };952 return MCValue{ .register = reg };
954}953}
...@@ -1065,9 +1064,9 @@ fn trunc(...@@ -1065,9 +1064,9 @@ fn trunc(
1065 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {1064 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1066 break :blk operand_reg;1065 break :blk operand_reg;
1067 } else {1066 } else {
1068 break :blk try self.register_manager.allocReg(inst, .{});1067 break :blk try self.register_manager.allocReg(inst, gp);
1069 }1068 }
1070 } else try self.register_manager.allocReg(null, .{});1069 } else try self.register_manager.allocReg(null, gp);
10711070
1072 switch (info_b.bits) {1071 switch (info_b.bits) {
1073 32 => {1072 32 => {
...@@ -1153,7 +1152,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1153,7 +1152,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1153 break :blk op_reg;1152 break :blk op_reg;
1154 }1153 }
11551154
1156 break :blk try self.register_manager.allocReg(null, .{});1155 break :blk try self.register_manager.allocReg(null, gp);
1157 };1156 };
11581157
1159 _ = try self.addInst(.{1158 _ = try self.addInst(.{
...@@ -1183,7 +1182,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1183,7 +1182,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1183 break :blk op_reg;1182 break :blk op_reg;
1184 }1183 }
11851184
1186 break :blk try self.register_manager.allocReg(null, .{});1185 break :blk try self.register_manager.allocReg(null, gp);
1187 };1186 };
11881187
1189 _ = try self.addInst(.{1188 _ = try self.addInst(.{
...@@ -1254,9 +1253,9 @@ fn minMax(...@@ -1254,9 +1253,9 @@ fn minMax(
1254 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {1253 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
1255 break :blk rhs_reg;1254 break :blk rhs_reg;
1256 } else {1255 } else {
1257 break :blk try self.register_manager.allocReg(inst, .{});1256 break :blk try self.register_manager.allocReg(inst, gp);
1258 }1257 }
1259 } else try self.register_manager.allocReg(null, .{});1258 } else try self.register_manager.allocReg(null, gp);
12601259
1261 // lhs == reg should have been checked by airMinMax1260 // lhs == reg should have been checked by airMinMax
1262 //1261 //
...@@ -1438,7 +1437,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1438,7 +1437,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1438 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1437 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1439 defer self.register_manager.unlockReg(dest_reg_lock);1438 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);
1442 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);1441 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
1443 defer self.register_manager.unlockReg(truncated_reg_lock);1442 defer self.register_manager.unlockReg(truncated_reg_lock);
14441443
...@@ -1543,7 +1542,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1543,7 +1542,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1543 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1542 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1544 defer self.register_manager.unlockReg(dest_reg_lock);1543 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);
1547 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);1546 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
1548 defer self.register_manager.unlockReg(truncated_reg_lock);1547 defer self.register_manager.unlockReg(truncated_reg_lock);
15491548
...@@ -1582,18 +1581,18 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1582,18 +1581,18 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1582 const lhs_reg = if (lhs_is_register)1581 const lhs_reg = if (lhs_is_register)
1583 lhs.register1582 lhs.register
1584 else1583 else
1585 try self.register_manager.allocReg(null, .{});1584 try self.register_manager.allocReg(null, gp);
1586 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);1585 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
1587 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);1586 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
15881587
1589 const rhs_reg = if (rhs_is_register)1588 const rhs_reg = if (rhs_is_register)
1590 rhs.register1589 rhs.register
1591 else1590 else
1592 try self.register_manager.allocReg(null, .{});1591 try self.register_manager.allocReg(null, gp);
1593 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);1592 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
1594 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);1593 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);
1597 const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);1596 const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
1598 defer for (dest_regs_locks) |reg| {1597 defer for (dest_regs_locks) |reg| {
1599 self.register_manager.unlockReg(reg);1598 self.register_manager.unlockReg(reg);
...@@ -1604,7 +1603,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1604,7 +1603,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1604 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);1603 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1605 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);1604 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);
1608 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);1607 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
1609 defer self.register_manager.unlockReg(truncated_reg_lock);1608 defer self.register_manager.unlockReg(truncated_reg_lock);
16101609
...@@ -2026,7 +2025,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2026,7 +2025,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2026 const base_reg_lock = self.register_manager.lockRegAssumeUnused(base_reg);2025 const base_reg_lock = self.register_manager.lockRegAssumeUnused(base_reg);
2027 defer self.register_manager.unlockReg(base_reg_lock);2026 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);
2030 const dst_mcv = MCValue{ .register = dst_reg };2029 const dst_mcv = MCValue{ .register = dst_reg };
2031 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);2030 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
2032 defer self.register_manager.unlockReg(dst_reg_lock);2031 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...@@ -2234,7 +2233,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2234 },2233 },
2235 .stack_offset => |off| {2234 .stack_offset => |off| {
2236 if (elem_size <= 4) {2235 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);
2238 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);2237 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
2239 defer self.register_manager.unlockReg(tmp_reg_lock);2238 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...@@ -2242,7 +2241,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2242 try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });2241 try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
2243 } else {2242 } else {
2244 // TODO optimize the register allocation2243 // 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);
2246 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);2245 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);
2247 defer for (regs_locks) |reg_locked| {2246 defer for (regs_locks) |reg_locked| {
2248 self.register_manager.unlockReg(reg_locked);2247 self.register_manager.unlockReg(reg_locked);
...@@ -2271,7 +2270,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2271,7 +2270,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2271 .stack_offset,2270 .stack_offset,
2272 .stack_argument_offset,2271 .stack_argument_offset,
2273 => {2272 => {
2274 const reg = try self.register_manager.allocReg(null, .{});2273 const reg = try self.register_manager.allocReg(null, gp);
2275 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);2274 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
2276 defer self.register_manager.unlockReg(reg_lock);2275 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...@@ -2338,14 +2337,14 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2338 },2337 },
2339 else => {2338 else => {
2340 if (elem_size <= 4) {2339 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);
2342 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);2341 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
2343 defer self.register_manager.unlockReg(tmp_reg_lock);2342 defer self.register_manager.unlockReg(tmp_reg_lock);
23442343
2345 try self.genSetReg(value_ty, tmp_reg, value);2344 try self.genSetReg(value_ty, tmp_reg, value);
2346 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);2345 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
2347 } else {2346 } 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);
2349 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);2348 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);
2350 defer for (regs_locks) |reg| {2349 defer for (regs_locks) |reg| {
2351 self.register_manager.unlockReg(reg);2350 self.register_manager.unlockReg(reg);
...@@ -2487,7 +2486,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2487,7 +2486,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2487 1 => {2486 1 => {
2488 // get overflow bit: set register to C flag2487 // get overflow bit: set register to C flag
2489 // resp. V flag2488 // 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
2492 // mov reg, #02491 // mov reg, #0
2493 _ = try self.addInst(.{2492 _ = try self.addInst(.{
...@@ -2567,7 +2566,7 @@ fn binOpRegister(...@@ -2567,7 +2566,7 @@ fn binOpRegister(
2567 break :inst Air.refToIndex(md.lhs).?;2566 break :inst Air.refToIndex(md.lhs).?;
2568 } else null;2567 } 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
2572 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });2571 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
25732572
...@@ -2581,7 +2580,7 @@ fn binOpRegister(...@@ -2581,7 +2580,7 @@ fn binOpRegister(
2581 break :inst Air.refToIndex(md.rhs).?;2580 break :inst Air.refToIndex(md.rhs).?;
2582 } else null;2581 } 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
2586 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });2585 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
25872586
...@@ -2598,9 +2597,9 @@ fn binOpRegister(...@@ -2598,9 +2597,9 @@ fn binOpRegister(
2598 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {2597 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
2599 break :blk rhs_reg;2598 break :blk rhs_reg;
2600 } else {2599 } else {
2601 break :blk try self.register_manager.allocReg(md.inst, .{});2600 break :blk try self.register_manager.allocReg(md.inst, gp);
2602 }2601 }
2603 } else try self.register_manager.allocReg(null, .{}),2602 } else try self.register_manager.allocReg(null, gp),
2604 };2603 };
26052604
2606 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);2605 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
...@@ -2684,7 +2683,7 @@ fn binOpImmediate(...@@ -2684,7 +2683,7 @@ fn binOpImmediate(
2684 ).?;2683 ).?;
2685 } else null;2684 } 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
2689 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });2688 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
26902689
...@@ -2704,9 +2703,9 @@ fn binOpImmediate(...@@ -2704,9 +2703,9 @@ fn binOpImmediate(
2704 )) {2703 )) {
2705 break :blk lhs_reg;2704 break :blk lhs_reg;
2706 } else {2705 } else {
2707 break :blk try self.register_manager.allocReg(md.inst, .{});2706 break :blk try self.register_manager.allocReg(md.inst, gp);
2708 }2707 }
2709 } else try self.register_manager.allocReg(null, .{}),2708 } else try self.register_manager.allocReg(null, gp),
2710 };2709 };
27112710
2712 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);2711 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...@@ -4363,7 +4362,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
43634362
4364 const overflow_bit_ty = ty.structFieldType(1);4363 const overflow_bit_ty = ty.structFieldType(1);
4365 const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*));4364 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
4368 // C flag: movcs reg, #14367 // C flag: movcs reg, #1
4369 // V flag: movvs reg, #14368 // V flag: movvs reg, #1
...@@ -4408,7 +4407,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4408,7 +4407,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4408 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);4407 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
44094408
4410 // TODO call extern memcpy4409 // 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);
4412 const src_reg = regs[0];4411 const src_reg = regs[0];
4413 const dst_reg = regs[1];4412 const dst_reg = regs[1];
4414 const len_reg = regs[2];4413 const len_reg = regs[2];
...@@ -4782,7 +4781,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -4782,7 +4781,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4782 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);4781 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
47834782
4784 // TODO call extern memcpy4783 // 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);
4786 const src_reg = regs[0];4785 const src_reg = regs[0];
4787 const dst_reg = regs[1];4786 const dst_reg = regs[1];
4788 const len_reg = regs[2];4787 const len_reg = regs[2];
src/arch/arm/abi.zig+17-1
...@@ -1,9 +1,25 @@...@@ -1,9 +1,25 @@
1const bits = @import("bits.zig");1const bits = @import("bits.zig");
2const Register = bits.Register;2const Register = bits.Register;
3const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
34
4pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 };5pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 };
5pub const caller_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3 };6pub const caller_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3 };
6pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs;
77
8pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 };8pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 };
9pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 };9pub 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;...@@ -21,9 +21,6 @@ const DW = std.dwarf;
21const leb128 = std.leb;21const leb128 = std.leb;
22const log = std.log.scoped(.codegen);22const log = std.log.scoped(.codegen);
23const build_options = @import("build_options");23const 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
28const FnResult = @import("../../codegen.zig").FnResult;25const FnResult = @import("../../codegen.zig").FnResult;
29const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;26const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
...@@ -32,8 +29,11 @@ const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;...@@ -32,8 +29,11 @@ const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
32const bits = @import("bits.zig");29const bits = @import("bits.zig");
33const abi = @import("abi.zig");30const abi = @import("abi.zig");
34const Register = bits.Register;31const Register = bits.Register;
32const RegisterManager = abi.RegisterManager;
33const RegisterLock = RegisterManager.RegisterLock;
35const Instruction = abi.Instruction;34const Instruction = abi.Instruction;
36const callee_preserved_regs = abi.callee_preserved_regs;35const callee_preserved_regs = abi.callee_preserved_regs;
36const gp = abi.RegisterClass.gp;
3737
38const InnerError = error{38const InnerError = error{
39 OutOfMemory,39 OutOfMemory,
...@@ -803,7 +803,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -803,7 +803,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
803 const ptr_bits = self.target.cpu.arch.ptrBitWidth();803 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
804 const ptr_bytes: u64 = @divExact(ptr_bits, 8);804 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
805 if (abi_size <= ptr_bytes) {805 if (abi_size <= ptr_bytes) {
806 if (self.register_manager.tryAllocReg(inst, .{})) |reg| {806 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
807 return MCValue{ .register = reg };807 return MCValue{ .register = reg };
808 }808 }
809 }809 }
...@@ -826,7 +826,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -826,7 +826,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
826/// allocated. A second call to `copyToTmpRegister` may return the same register.826/// allocated. A second call to `copyToTmpRegister` may return the same register.
827/// This can have a side effect of spilling instructions to the stack to free up a register.827/// This can have a side effect of spilling instructions to the stack to free up a register.
828fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {828fn 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);
830 try self.genSetReg(ty, reg, mcv);830 try self.genSetReg(ty, reg, mcv);
831 return reg;831 return reg;
832}832}
...@@ -835,7 +835,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {...@@ -835,7 +835,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
835/// `reg_owner` is the instruction that gets associated with the register in the register table.835/// `reg_owner` is the instruction that gets associated with the register in the register table.
836/// This can have a side effect of spilling instructions to the stack to free up a register.836/// This can have a side effect of spilling instructions to the stack to free up a register.
837fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {837fn 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);
839 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);839 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
840 return MCValue{ .register = reg };840 return MCValue{ .register = reg };
841}841}
...@@ -958,7 +958,7 @@ fn binOpRegister(...@@ -958,7 +958,7 @@ fn binOpRegister(
958 break :inst Air.refToIndex(bin_op.lhs).?;958 break :inst Air.refToIndex(bin_op.lhs).?;
959 } else null;959 } 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
963 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });963 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
964964
...@@ -973,7 +973,7 @@ fn binOpRegister(...@@ -973,7 +973,7 @@ fn binOpRegister(
973 break :inst Air.refToIndex(bin_op.rhs).?;973 break :inst Air.refToIndex(bin_op.rhs).?;
974 } else null;974 } 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
978 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });978 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
979979
...@@ -990,9 +990,9 @@ fn binOpRegister(...@@ -990,9 +990,9 @@ fn binOpRegister(
990 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {990 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
991 break :blk rhs_reg;991 break :blk rhs_reg;
992 } else {992 } else {
993 break :blk try self.register_manager.allocReg(inst, .{});993 break :blk try self.register_manager.allocReg(inst, gp);
994 }994 }
995 } else try self.register_manager.allocReg(null, .{});995 } else try self.register_manager.allocReg(null, gp);
996996
997 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);997 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
998 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);998 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...@@ -1482,7 +1482,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1482 .memory,1482 .memory,
1483 .stack_offset,1483 .stack_offset,
1484 => {1484 => {
1485 const reg = try self.register_manager.allocReg(null, .{});1485 const reg = try self.register_manager.allocReg(null, gp);
1486 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);1486 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
1487 defer self.register_manager.unlockReg(reg_lock);1487 defer self.register_manager.unlockReg(reg_lock);
14881488
src/arch/riscv64/abi.zig+17
...@@ -1,6 +1,23 @@...@@ -1,6 +1,23 @@
1const bits = @import("bits.zig");1const bits = @import("bits.zig");
2const Register = bits.Register;2const Register = bits.Register;
3const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
34
4pub const callee_preserved_regs = [_]Register{5pub const callee_preserved_regs = [_]Register{
5 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,6 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
6};7};
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;...@@ -21,9 +21,6 @@ const Type = @import("../../type.zig").Type;
21const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;21const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
22const FnResult = @import("../../codegen.zig").FnResult;22const FnResult = @import("../../codegen.zig").FnResult;
23const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;23const 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
28const build_options = @import("build_options");25const build_options = @import("build_options");
2926
...@@ -31,7 +28,10 @@ const bits = @import("bits.zig");...@@ -31,7 +28,10 @@ const bits = @import("bits.zig");
31const abi = @import("abi.zig");28const abi = @import("abi.zig");
32const Instruction = bits.Instruction;29const Instruction = bits.Instruction;
33const ShiftWidth = Instruction.ShiftWidth;30const ShiftWidth = Instruction.ShiftWidth;
31const RegisterManager = abi.RegisterManager;
32const RegisterLock = RegisterManager.RegisterLock;
34const Register = bits.Register;33const Register = bits.Register;
34const gp = abi.RegisterClass.gp;
3535
36const Self = @This();36const Self = @This();
3737
...@@ -1613,7 +1613,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -1613,7 +1613,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
1613 if (reg_ok) {1613 if (reg_ok) {
1614 // Make sure the type can fit in a register before we try to allocate one.1614 // Make sure the type can fit in a register before we try to allocate one.
1615 if (abi_size <= 8) {1615 if (abi_size <= 8) {
1616 if (self.register_manager.tryAllocReg(inst, .{})) |reg| {1616 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
1617 return MCValue{ .register = reg };1617 return MCValue{ .register = reg };
1618 }1618 }
1619 }1619 }
...@@ -1854,7 +1854,7 @@ fn binOpImmediate(...@@ -1854,7 +1854,7 @@ fn binOpImmediate(
1854 ).?;1854 ).?;
1855 } else null;1855 } 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
1859 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1859 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
18601860
...@@ -1873,10 +1873,10 @@ fn binOpImmediate(...@@ -1873,10 +1873,10 @@ fn binOpImmediate(
1873 )) {1873 )) {
1874 break :blk lhs_reg;1874 break :blk lhs_reg;
1875 } else {1875 } else {
1876 break :blk try self.register_manager.allocReg(md.inst, .{});1876 break :blk try self.register_manager.allocReg(md.inst, gp);
1877 }1877 }
1878 } else blk: {1878 } else blk: {
1879 break :blk try self.register_manager.allocReg(null, .{});1879 break :blk try self.register_manager.allocReg(null, gp);
1880 },1880 },
1881 };1881 };
18821882
...@@ -1953,7 +1953,7 @@ fn binOpRegister(...@@ -1953,7 +1953,7 @@ fn binOpRegister(
1953 break :inst Air.refToIndex(md.lhs).?;1953 break :inst Air.refToIndex(md.lhs).?;
1954 } else null;1954 } else null;
19551955
1956 const reg = try self.register_manager.allocReg(track_inst, .{});1956 const reg = try self.register_manager.allocReg(track_inst, gp);
1957 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1957 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
19581958
1959 break :blk reg;1959 break :blk reg;
...@@ -1966,7 +1966,7 @@ fn binOpRegister(...@@ -1966,7 +1966,7 @@ fn binOpRegister(
1966 break :inst Air.refToIndex(md.rhs).?;1966 break :inst Air.refToIndex(md.rhs).?;
1967 } else null;1967 } else null;
19681968
1969 const reg = try self.register_manager.allocReg(track_inst, .{});1969 const reg = try self.register_manager.allocReg(track_inst, gp);
1970 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1970 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
19711971
1972 break :blk reg;1972 break :blk reg;
...@@ -1981,10 +1981,10 @@ fn binOpRegister(...@@ -1981,10 +1981,10 @@ fn binOpRegister(
1981 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {1981 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
1982 break :blk rhs_reg;1982 break :blk rhs_reg;
1983 } else {1983 } else {
1984 break :blk try self.register_manager.allocReg(md.inst, .{});1984 break :blk try self.register_manager.allocReg(md.inst, gp);
1985 }1985 }
1986 } else blk: {1986 } else blk: {
1987 break :blk try self.register_manager.allocReg(null, .{});1987 break :blk try self.register_manager.allocReg(null, gp);
1988 },1988 },
1989 };1989 };
19901990
...@@ -2077,7 +2077,7 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {...@@ -2077,7 +2077,7 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {
2077/// allocated. A second call to `copyToTmpRegister` may return the same register.2077/// allocated. A second call to `copyToTmpRegister` may return the same register.
2078/// This can have a side effect of spilling instructions to the stack to free up a register.2078/// This can have a side effect of spilling instructions to the stack to free up a register.
2079fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {2079fn 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);
2081 try self.genSetReg(ty, reg, mcv);2081 try self.genSetReg(ty, reg, mcv);
2082 return reg;2082 return reg;
2083}2083}
...@@ -2364,7 +2364,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2364,7 +2364,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2364 });2364 });
2365 } else {2365 } else {
2366 // Need to allocate a temporary register to load 64-bit immediates.2366 // 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
2369 try self.genSetReg(ty, tmp_reg, .{ .immediate = @truncate(u32, x) });2369 try self.genSetReg(ty, tmp_reg, .{ .immediate = @truncate(u32, x) });
2370 try self.genSetReg(ty, reg, .{ .immediate = @truncate(u32, x >> 32) });2370 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...@@ -2478,7 +2478,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2478 };2478 };
2479 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);2479 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);
2482 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);2482 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);
2483 defer for (regs_locks) |reg| {2483 defer for (regs_locks) |reg| {
2484 self.register_manager.unlockReg(reg);2484 self.register_manager.unlockReg(reg);
...@@ -2717,14 +2717,14 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2717,14 +2717,14 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2717 },2717 },
2718 .stack_offset => |off| {2718 .stack_offset => |off| {
2719 if (elem_size <= 8) {2719 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);
2721 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);2721 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
2722 defer self.register_manager.unlockReg(tmp_reg_lock);2722 defer self.register_manager.unlockReg(tmp_reg_lock);
27232723
2724 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);2724 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
2725 try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });2725 try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
2726 } else {2726 } 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);
2728 const regs_locks = self.register_manager.lockRegsAssumeUnused(3, regs);2728 const regs_locks = self.register_manager.lockRegsAssumeUnused(3, regs);
2729 defer for (regs_locks) |reg| {2729 defer for (regs_locks) |reg| {
2730 self.register_manager.unlockReg(reg);2730 self.register_manager.unlockReg(reg);
src/arch/sparc64/abi.zig+17-1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const bits = @import("bits.zig");1const bits = @import("bits.zig");
2const Register = bits.Register;2const Register = bits.Register;
3const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
34
4// SPARCv9 stack constants.5// SPARCv9 stack constants.
5// See: Registers and the Stack Frame, page 3P-8, SCD 2.4.1.6// See: Registers and the Stack Frame, page 3P-8, SCD 2.4.1.
...@@ -21,7 +22,7 @@ pub const stack_save_area = 176;...@@ -21,7 +22,7 @@ pub const stack_save_area = 176;
21pub const caller_preserved_regs = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5, .g1, .g4, .g5 };22pub const caller_preserved_regs = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5, .g1, .g4, .g5 };
2223
23// Try to allocate i, l, o, then g sets of registers, in order of priority.24// Try to allocate i, l, o, then g sets of registers, in order of priority.
24pub const allocatable_regs = [_]Register{25const allocatable_regs = [_]Register{
25 // zig fmt: off26 // zig fmt: off
26 .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5",27 .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5",
27 .l0, .l1, .l2, .l3, .l4, .l5, .l6, .l7,28 .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"...@@ -35,3 +36,18 @@ pub const c_abi_int_param_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2"
3536
36pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3 };37pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3 };
37pub const c_abi_int_return_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3" };38pub 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 {...@@ -884,9 +884,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
884 if (self.intrinsicsAllowed(elem_ty)) {884 if (self.intrinsicsAllowed(elem_ty)) {
885 const ptr_bytes: u64 = 32;885 const ptr_bytes: u64 = 32;
886 if (abi_size <= ptr_bytes) {886 if (abi_size <= ptr_bytes) {
887 if (self.register_manager.tryAllocReg(inst, .{887 if (self.register_manager.tryAllocReg(inst, sse)) |reg| {
888 .selector_mask = sse,
889 })) |reg| {
890 return MCValue{ .register = registerAlias(reg, abi_size) };888 return MCValue{ .register = registerAlias(reg, abi_size) };
891 }889 }
892 }890 }
...@@ -899,9 +897,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -899,9 +897,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
899 const ptr_bits = self.target.cpu.arch.ptrBitWidth();897 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
900 const ptr_bytes: u64 = @divExact(ptr_bits, 8);898 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
901 if (abi_size <= ptr_bytes) {899 if (abi_size <= ptr_bytes) {
902 if (self.register_manager.tryAllocReg(inst, .{900 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
903 .selector_mask = gp,
904 })) |reg| {
905 return MCValue{ .register = registerAlias(reg, abi_size) };901 return MCValue{ .register = registerAlias(reg, abi_size) };
906 }902 }
907 }903 }
...@@ -972,16 +968,14 @@ pub fn spillRegisters(self: *Self, comptime count: comptime_int, registers: [cou...@@ -972,16 +968,14 @@ pub fn spillRegisters(self: *Self, comptime count: comptime_int, registers: [cou
972/// allocated. A second call to `copyToTmpRegister` may return the same register.968/// allocated. A second call to `copyToTmpRegister` may return the same register.
973/// This can have a side effect of spilling instructions to the stack to free up a register.969/// This can have a side effect of spilling instructions to the stack to free up a register.
974fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {970fn 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()) {
976 .Float => blk: {972 .Float => blk: {
977 if (self.intrinsicsAllowed(ty)) break :blk sse;973 if (self.intrinsicsAllowed(ty)) break :blk sse;
978 return self.fail("TODO copy {} to register", .{ty.fmtDebug()});974 return self.fail("TODO copy {} to register", .{ty.fmtDebug()});
979 },975 },
980 else => gp,976 else => gp,
981 };977 };
982 const reg: Register = try self.register_manager.allocReg(null, .{978 const reg: Register = try self.register_manager.allocReg(null, reg_class);
983 .selector_mask = mask,
984 });
985 try self.genSetReg(ty, reg, mcv);979 try self.genSetReg(ty, reg, mcv);
986 return reg;980 return reg;
987}981}
...@@ -991,16 +985,14 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {...@@ -991,16 +985,14 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
991/// This can have a side effect of spilling instructions to the stack to free up a register.985/// This can have a side effect of spilling instructions to the stack to free up a register.
992/// WARNING make sure that the allocated register matches the returned MCValue from an instruction!986/// WARNING make sure that the allocated register matches the returned MCValue from an instruction!
993fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {987fn 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()) {
995 .Float => blk: {989 .Float => blk: {
996 if (self.intrinsicsAllowed(ty)) break :blk sse;990 if (self.intrinsicsAllowed(ty)) break :blk sse;
997 return self.fail("TODO copy {} to register", .{ty.fmtDebug()});991 return self.fail("TODO copy {} to register", .{ty.fmtDebug()});
998 },992 },
999 else => gp,993 else => gp,
1000 };994 };
1001 const reg: Register = try self.register_manager.allocReg(reg_owner, .{995 const reg: Register = try self.register_manager.allocReg(reg_owner, reg_class);
1002 .selector_mask = mask,
1003 });
1004 try self.genSetReg(ty, reg, mcv);996 try self.genSetReg(ty, reg, mcv);
1005 return MCValue{ .register = reg };997 return MCValue{ .register = reg };
1006}998}
...@@ -1056,9 +1048,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -1056,9 +1048,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1056 };1048 };
1057 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);1049 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
10581050
1059 const reg = try self.register_manager.allocReg(inst, .{1051 const reg = try self.register_manager.allocReg(inst, gp);
1060 .selector_mask = gp,
1061 });
1062 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });1052 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
1063 try self.genSetReg(operand_ty, reg, operand);1053 try self.genSetReg(operand_ty, reg, operand);
1064 break :blk MCValue{ .register = reg };1054 break :blk MCValue{ .register = reg };
...@@ -1413,9 +1403,7 @@ fn genSetStackTruncatedOverflowCompare(...@@ -1413,9 +1403,7 @@ fn genSetStackTruncatedOverflowCompare(
1413 .unsigned => ty,1403 .unsigned => ty,
1414 };1404 };
14151405
1416 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, .{1406 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp);
1417 .selector_mask = gp,
1418 });
1419 const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);1407 const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);
1420 defer for (temp_regs_locks) |rreg| {1408 defer for (temp_regs_locks) |rreg| {
1421 self.register_manager.unlockReg(rreg);1409 self.register_manager.unlockReg(rreg);
...@@ -2077,9 +2065,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {...@@ -2077,9 +2065,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
2077 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);2065 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2078 defer self.register_manager.unlockReg(offset_reg_lock);2066 defer self.register_manager.unlockReg(offset_reg_lock);
20792067
2080 const addr_reg = try self.register_manager.allocReg(null, .{2068 const addr_reg = try self.register_manager.allocReg(null, gp);
2081 .selector_mask = gp,
2082 });
2083 switch (slice_mcv) {2069 switch (slice_mcv) {
2084 .stack_offset => |off| {2070 .stack_offset => |off| {
2085 // mov reg, [rbp - 8]2071 // mov reg, [rbp - 8]
...@@ -2158,9 +2144,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2158,9 +2144,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2158 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);2144 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2159 defer self.register_manager.unlockReg(offset_reg_lock);2145 defer self.register_manager.unlockReg(offset_reg_lock);
21602146
2161 const addr_reg = try self.register_manager.allocReg(null, .{2147 const addr_reg = try self.register_manager.allocReg(null, gp);
2162 .selector_mask = gp,
2163 });
2164 switch (array) {2148 switch (array) {
2165 .register => {2149 .register => {
2166 const off = @intCast(i32, try self.allocMem(2150 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...@@ -2527,7 +2511,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2527 },2511 },
2528 .stack_offset => |off| {2512 .stack_offset => |off| {
2529 if (abi_size <= 8) {2513 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);
2531 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);2515 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
2532 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }, .{});2516 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }, .{});
2533 }2517 }
...@@ -2728,7 +2712,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2728,7 +2712,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2728 };2712 };
2729 defer if (value_lock) |lock| self.register_manager.unlockReg(lock);2713 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);
2732 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);2716 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
2733 defer self.register_manager.unlockReg(addr_reg_lock);2717 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...@@ -2800,7 +2784,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2800 .memory,2784 .memory,
2801 => {2785 => {
2802 if (abi_size <= 8) {2786 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);
2804 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);2788 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
2805 defer self.register_manager.unlockReg(tmp_reg_lock);2789 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...@@ -2918,7 +2902,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
2918 if (can_reuse_operand) {2902 if (can_reuse_operand) {
2919 break :blk reg;2903 break :blk reg;
2920 } else {2904 } 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);
2922 try self.genSetReg(ptr_ty, result_reg, mcv);2906 try self.genSetReg(ptr_ty, result_reg, mcv);
2923 break :blk result_reg;2907 break :blk result_reg;
2924 }2908 }
...@@ -3019,7 +3003,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3019,7 +3003,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3019 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);3003 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
3020 defer self.register_manager.unlockReg(reg_lock);3004 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);
3023 const flags: u2 = switch (mcv) {3007 const flags: u2 = switch (mcv) {
3024 .register_overflow_unsigned => 0b10,3008 .register_overflow_unsigned => 0b10,
3025 .register_overflow_signed => 0b00,3009 .register_overflow_signed => 0b00,
...@@ -5428,7 +5412,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5428,7 +5412,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
54285412
5429 const overflow_bit_ty = ty.structFieldType(1);5413 const overflow_bit_ty = ty.structFieldType(1);
5430 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);5414 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);
5432 const flags: u2 = switch (mcv) {5416 const flags: u2 = switch (mcv) {
5433 .register_overflow_unsigned => 0b10,5417 .register_overflow_unsigned => 0b10,
5434 .register_overflow_signed => 0b00,5418 .register_overflow_signed => 0b00,
...@@ -5656,7 +5640,7 @@ fn genInlineMemcpy(...@@ -5656,7 +5640,7 @@ fn genInlineMemcpy(
5656 null;5640 null;
5657 defer if (dsbase_lock) |lock| self.register_manager.unlockReg(lock);5641 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);
5660 switch (dst_ptr) {5644 switch (dst_ptr) {
5661 .memory,5645 .memory,
5662 .got_load,5646 .got_load,
...@@ -5691,7 +5675,7 @@ fn genInlineMemcpy(...@@ -5691,7 +5675,7 @@ fn genInlineMemcpy(
5691 const dst_addr_reg_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);5675 const dst_addr_reg_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);
5692 defer self.register_manager.unlockReg(dst_addr_reg_lock);5676 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);
5695 switch (src_ptr) {5679 switch (src_ptr) {
5696 .memory,5680 .memory,
5697 .got_load,5681 .got_load,
...@@ -5726,9 +5710,7 @@ fn genInlineMemcpy(...@@ -5726,9 +5710,7 @@ fn genInlineMemcpy(
5726 const src_addr_reg_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);5710 const src_addr_reg_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
5727 defer self.register_manager.unlockReg(src_addr_reg_lock);5711 defer self.register_manager.unlockReg(src_addr_reg_lock);
57285712
5729 const regs = try self.register_manager.allocRegs(2, .{ null, null }, .{5713 const regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
5730 .selector_mask = gp,
5731 });
5732 const count_reg = regs[0].to64();5714 const count_reg = regs[0].to64();
5733 const tmp_reg = regs[1].to8();5715 const tmp_reg = regs[1].to8();
57345716
...@@ -5828,7 +5810,7 @@ fn genInlineMemset(...@@ -5828,7 +5810,7 @@ fn genInlineMemset(
5828 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);5810 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
5829 defer self.register_manager.unlockReg(rax_lock);5811 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);
5832 switch (dst_ptr) {5814 switch (dst_ptr) {
5833 .memory,5815 .memory,
5834 .got_load,5816 .got_load,
...@@ -6087,7 +6069,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6087,7 +6069,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6087 => {6069 => {
6088 switch (ty.zigTypeTag()) {6070 switch (ty.zigTypeTag()) {
6089 .Float => {6071 .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);
6091 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);6073 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);
60926074
6093 if (self.intrinsicsAllowed(ty)) {6075 if (self.intrinsicsAllowed(ty)) {
...@@ -6130,7 +6112,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6130,7 +6112,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6130 },6112 },
6131 .memory => |x| switch (ty.zigTypeTag()) {6113 .memory => |x| switch (ty.zigTypeTag()) {
6132 .Float => {6114 .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);
6134 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);6116 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);
61356117
6136 if (self.intrinsicsAllowed(ty)) {6118 if (self.intrinsicsAllowed(ty)) {
...@@ -6461,7 +6443,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -6461,7 +6443,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
6461 const src: MCValue = blk: {6443 const src: MCValue = blk: {
6462 switch (src_ptr) {6444 switch (src_ptr) {
6463 .got_load, .direct_load, .memory => {6445 .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);
6465 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);6447 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);
6466 _ = try self.addInst(.{6448 _ = try self.addInst(.{
6467 .tag = .mov,6449 .tag = .mov,
src/register_manager.zig+80-33
...@@ -57,6 +57,11 @@ pub fn RegisterManager(...@@ -57,6 +57,11 @@ pub fn RegisterManager(
57 return @fieldParentPtr(Function, "register_manager", self);57 return @fieldParentPtr(Function, "register_manager", self);
58 }58 }
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
60 fn markRegAllocated(self: *Self, reg: Register) void {65 fn markRegAllocated(self: *Self, reg: Register) void {
61 const index = indexOfRegIntoTracked(reg) orelse return;66 const index = indexOfRegIntoTracked(reg) orelse return;
62 self.allocated_registers.set(index);67 self.allocated_registers.set(index);
...@@ -167,10 +172,6 @@ pub fn RegisterManager(...@@ -167,10 +172,6 @@ pub fn RegisterManager(
167 return self.locked_registers.count() > 0;172 return self.locked_registers.count() > 0;
168 }173 }
169174
170 const AllocOpts = struct {
171 selector_mask: ?RegisterBitSet = null,
172 };
173
174 /// Allocates a specified number of registers, optionally175 /// Allocates a specified number of registers, optionally
175 /// tracking them. Returns `null` if not enough registers are176 /// tracking them. Returns `null` if not enough registers are
176 /// free.177 /// free.
...@@ -178,14 +179,12 @@ pub fn RegisterManager(...@@ -178,14 +179,12 @@ pub fn RegisterManager(
178 self: *Self,179 self: *Self,
179 comptime count: comptime_int,180 comptime count: comptime_int,
180 insts: [count]?Air.Inst.Index,181 insts: [count]?Air.Inst.Index,
181 opts: AllocOpts,182 register_class: RegisterBitSet,
182 ) ?[count]Register {183 ) ?[count]Register {
183 comptime assert(count > 0 and count <= tracked_registers.len);184 comptime assert(count > 0 and count <= tracked_registers.len);
184185
185 const available_registers = opts.selector_mask orelse RegisterBitSet.initFull();
186
187 var free_and_not_locked_registers = self.free_registers;186 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
190 var unlocked_registers = self.locked_registers;189 var unlocked_registers = self.locked_registers;
191 unlocked_registers.toggleAll();190 unlocked_registers.toggleAll();
...@@ -198,6 +197,7 @@ pub fn RegisterManager(...@@ -198,6 +197,7 @@ pub fn RegisterManager(
198 var i: usize = 0;197 var i: usize = 0;
199 for (tracked_registers) |reg| {198 for (tracked_registers) |reg| {
200 if (i >= count) break;199 if (i >= count) break;
200 if (excludeRegister(reg, register_class)) continue;
201 if (self.isRegLocked(reg)) continue;201 if (self.isRegLocked(reg)) continue;
202 if (!self.isRegFree(reg)) continue;202 if (!self.isRegFree(reg)) continue;
203203
...@@ -223,8 +223,8 @@ pub fn RegisterManager(...@@ -223,8 +223,8 @@ pub fn RegisterManager(
223 /// Allocates a register and optionally tracks it with a223 /// Allocates a register and optionally tracks it with a
224 /// corresponding instruction. Returns `null` if all registers224 /// corresponding instruction. Returns `null` if all registers
225 /// are allocated.225 /// are allocated.
226 pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index, opts: AllocOpts) ?Register {226 pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index, register_class: RegisterBitSet) ?Register {
227 return if (tryAllocRegs(self, 1, .{inst}, opts)) |regs| regs[0] else null;227 return if (tryAllocRegs(self, 1, .{inst}, register_class)) |regs| regs[0] else null;
228 }228 }
229229
230 /// Allocates a specified number of registers, optionally230 /// Allocates a specified number of registers, optionally
...@@ -234,18 +234,16 @@ pub fn RegisterManager(...@@ -234,18 +234,16 @@ pub fn RegisterManager(
234 self: *Self,234 self: *Self,
235 comptime count: comptime_int,235 comptime count: comptime_int,
236 insts: [count]?Air.Inst.Index,236 insts: [count]?Air.Inst.Index,
237 opts: AllocOpts,237 register_class: RegisterBitSet,
238 ) AllocateRegistersError![count]Register {238 ) AllocateRegistersError![count]Register {
239 comptime assert(count > 0 and count <= tracked_registers.len);239 comptime assert(count > 0 and count <= tracked_registers.len);
240240
241 const available_registers = opts.selector_mask orelse RegisterBitSet.initFull();
242
243 var locked_registers = self.locked_registers;241 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: {
249 // We'll take over the first count registers. Spill247 // We'll take over the first count registers. Spill
250 // the instructions that were previously there to a248 // the instructions that were previously there to a
251 // stack allocations.249 // stack allocations.
...@@ -253,6 +251,7 @@ pub fn RegisterManager(...@@ -253,6 +251,7 @@ pub fn RegisterManager(
253 var i: usize = 0;251 var i: usize = 0;
254 for (tracked_registers) |reg| {252 for (tracked_registers) |reg| {
255 if (i >= count) break;253 if (i >= count) break;
254 if (excludeRegister(reg, register_class)) continue;
256 if (self.isRegLocked(reg)) continue;255 if (self.isRegLocked(reg)) continue;
257256
258 regs[i] = reg;257 regs[i] = reg;
...@@ -288,8 +287,12 @@ pub fn RegisterManager(...@@ -288,8 +287,12 @@ pub fn RegisterManager(
288287
289 /// Allocates a register and optionally tracks it with a288 /// Allocates a register and optionally tracks it with a
290 /// corresponding instruction.289 /// corresponding instruction.
291 pub fn allocReg(self: *Self, inst: ?Air.Inst.Index, opts: AllocOpts) AllocateRegistersError!Register {290 pub fn allocReg(
292 return (try self.allocRegs(1, .{inst}, opts))[0];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];
293 }296 }
294297
295 /// Spills the register if it is currently allocated. If a298 /// Spills the register if it is currently allocated. If a
...@@ -374,11 +377,15 @@ const MockRegister2 = enum(u2) {...@@ -374,11 +377,15 @@ const MockRegister2 = enum(u2) {
374fn MockFunction(comptime Register: type) type {377fn MockFunction(comptime Register: type) type {
375 return struct {378 return struct {
376 allocator: Allocator,379 allocator: Allocator,
377 register_manager: RegisterManager(Self, Register, &Register.allocatable_registers) = .{},380 register_manager: RegisterManagerT = .{},
378 spilled: std.ArrayListUnmanaged(Register) = .{},381 spilled: std.ArrayListUnmanaged(Register) = .{},
379382
380 const Self = @This();383 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
382 pub fn deinit(self: *Self) void {389 pub fn deinit(self: *Self) void {
383 self.spilled.deinit(self.allocator);390 self.spilled.deinit(self.allocator);
384 }391 }
...@@ -423,10 +430,20 @@ test "tryAllocReg: no spilling" {...@@ -423,10 +430,20 @@ test "tryAllocReg: no spilling" {
423 defer function.deinit();430 defer function.deinit();
424431
425 const mock_instruction: Air.Inst.Index = 1;432 const mock_instruction: Air.Inst.Index = 1;
426433 const reg_class = MockFunction1.reg_class;
427 try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction, .{}));434
428 try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction, .{}));435 try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(
429 try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction, .{}));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
431 try expect(function.register_manager.isRegAllocated(.r2));448 try expect(function.register_manager.isRegAllocated(.r2));
432 try expect(function.register_manager.isRegAllocated(.r3));449 try expect(function.register_manager.isRegAllocated(.r3));
...@@ -451,17 +468,30 @@ test "allocReg: spilling" {...@@ -451,17 +468,30 @@ test "allocReg: spilling" {
451 defer function.deinit();468 defer function.deinit();
452469
453 const mock_instruction: Air.Inst.Index = 1;470 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, .{}));473 try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(
456 try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, .{}));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
458 // Spill a register482 // 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 ));
460 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);487 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
461488
462 // No spilling necessary489 // No spilling necessary
463 function.register_manager.freeReg(.r3);490 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 ));
465 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);495 try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
466496
467 // Locked registers497 // Locked registers
...@@ -470,7 +500,10 @@ test "allocReg: spilling" {...@@ -470,7 +500,10 @@ test "allocReg: spilling" {
470 const lock = function.register_manager.lockReg(.r2);500 const lock = function.register_manager.lockReg(.r2);
471 defer if (lock) |reg| function.register_manager.unlockReg(reg);501 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 ));
474 }507 }
475 try expect(!function.register_manager.lockedRegsExist());508 try expect(!function.register_manager.lockedRegsExist());
476}509}
...@@ -483,7 +516,13 @@ test "tryAllocRegs" {...@@ -483,7 +516,13 @@ test "tryAllocRegs" {
483 };516 };
484 defer function.deinit();517 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
488 try expect(function.register_manager.isRegAllocated(.r0));527 try expect(function.register_manager.isRegAllocated(.r0));
489 try expect(function.register_manager.isRegAllocated(.r1));528 try expect(function.register_manager.isRegAllocated(.r1));
...@@ -498,7 +537,11 @@ test "tryAllocRegs" {...@@ -498,7 +537,11 @@ test "tryAllocRegs" {
498 const lock = function.register_manager.lockReg(.r1);537 const lock = function.register_manager.lockReg(.r1);
499 defer if (lock) |reg| function.register_manager.unlockReg(reg);538 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 ).?);
502 }545 }
503 try expect(!function.register_manager.lockedRegsExist());546 try expect(!function.register_manager.lockedRegsExist());
504547
...@@ -518,6 +561,8 @@ test "allocRegs: normal usage" {...@@ -518,6 +561,8 @@ test "allocRegs: normal usage" {
518 };561 };
519 defer function.deinit();562 defer function.deinit();
520563
564 const reg_class = MockFunction2.reg_class;
565
521 {566 {
522 const result_reg: MockRegister2 = .r1;567 const result_reg: MockRegister2 = .r1;
523568
...@@ -537,7 +582,7 @@ test "allocRegs: normal usage" {...@@ -537,7 +582,7 @@ test "allocRegs: normal usage" {
537 const lock = function.register_manager.lockReg(result_reg);582 const lock = function.register_manager.lockReg(result_reg);
538 defer if (lock) |reg| function.register_manager.unlockReg(reg);583 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);
541 try function.genAdd(result_reg, regs[0], regs[1]);586 try function.genAdd(result_reg, regs[0], regs[1]);
542 }587 }
543}588}
...@@ -552,6 +597,8 @@ test "allocRegs: selectively reducing register pressure" {...@@ -552,6 +597,8 @@ test "allocRegs: selectively reducing register pressure" {
552 };597 };
553 defer function.deinit();598 defer function.deinit();
554599
600 const reg_class = MockFunction2.reg_class;
601
555 {602 {
556 const result_reg: MockRegister2 = .r1;603 const result_reg: MockRegister2 = .r1;
557604
...@@ -559,12 +606,12 @@ test "allocRegs: selectively reducing register pressure" {...@@ -559,12 +606,12 @@ test "allocRegs: selectively reducing register pressure" {
559606
560 // Here, we don't defer unlock because we manually unlock607 // Here, we don't defer unlock because we manually unlock
561 // after genAdd608 // 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
564 try function.genAdd(result_reg, regs[0], regs[1]);611 try function.genAdd(result_reg, regs[0], regs[1]);
565 function.register_manager.unlockReg(lock.?);612 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);
568 try function.genAdd(result_reg, result_reg, extra_summand_reg);615 try function.genAdd(result_reg, result_reg, extra_summand_reg);
569 }616 }
570}617}