| author | |
| committer | |
| log | e95dfac03eea942b53bbdf6117a716aaeba5eb4b |
| tree | 528e33c135c69eedde5d209b55df88a0a36365cf |
| parent | f766b25f82a6c94d6b77f6a4172bfc4feb1d9271 |
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; |
| 21 | const leb128 = std.leb; | 21 | const leb128 = std.leb; |
| 22 | const log = std.log.scoped(.codegen); | 22 | const log = std.log.scoped(.codegen); |
| 23 | const build_options = @import("build_options"); | 23 | const build_options = @import("build_options"); |
| 24 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | ||
| 25 | const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs); | ||
| 26 | const RegisterLock = RegisterManager.RegisterLock; | ||
| 27 | 24 | ||
| 28 | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; | 25 | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; |
| 29 | const FnResult = @import("../../codegen.zig").FnResult; | 26 | const 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; |
| 31 | 28 | ||
| 32 | const bits = @import("bits.zig"); | 29 | const bits = @import("bits.zig"); |
| 33 | const abi = @import("abi.zig"); | 30 | const abi = @import("abi.zig"); |
| 31 | const RegisterManager = abi.RegisterManager; | ||
| 32 | const RegisterLock = RegisterManager.RegisterLock; | ||
| 34 | const Register = bits.Register; | 33 | const Register = bits.Register; |
| 35 | const Instruction = bits.Instruction; | 34 | const Instruction = bits.Instruction; |
| 36 | const callee_preserved_regs = abi.callee_preserved_regs; | 35 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 37 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; | 36 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 38 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; | 37 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 38 | const gp = abi.RegisterClass.gp; | ||
| 39 | 39 | ||
| 40 | const InnerError = error{ | 40 | const 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. |
| 953 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 953 | fn 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. |
| 963 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 963 | fn 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 | }; |
| 1084 | 1084 | ||
| ... | @@ -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 | } |
| 1162 | 1162 | ||
| 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 | }; |
| 1166 | 1166 | ||
| ... | @@ -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 | } |
| 1195 | 1195 | ||
| 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 | }; |
| 1199 | 1199 | ||
| ... | @@ -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; |
| 1295 | 1295 | ||
| 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.*)); |
| 1298 | 1298 | ||
| 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; |
| 1310 | 1310 | ||
| 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.*)); |
| 1313 | 1313 | ||
| 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; |
| 1433 | 1433 | ||
| 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.*)); |
| 1436 | 1436 | ||
| 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); |
| 1874 | 1874 | ||
| 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); |
| 1985 | 1985 | ||
| 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); |
| 1989 | 1989 | ||
| ... | @@ -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); |
| 2049 | 2049 | ||
| 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); |
| 2057 | 2057 | ||
| 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); |
| 2068 | 2068 | ||
| 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 | }); |
| 2088 | 2088 | ||
| 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); |
| 2092 | 2092 | ||
| ... | @@ -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); |
| 2142 | 2142 | ||
| ... | @@ -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 | } |
| 2194 | 2194 | ||
| 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); |
| 2198 | 2198 | ||
| ... | @@ -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 allocation | 2674 | // 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 flags | 3002 | // TODO return special MCValue condition flags |
| 3003 | // get overflow bit: set register to C flag | 3003 | // get overflow bit: set register to C flag |
| 3004 | // resp. V flag | 3004 | // 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(); |
| 3007 | 3007 | ||
| 3008 | // C flag: cset reg, cs | 3008 | // 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 |
| 4065 | 4065 | ||
| 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); |
| 4114 | 4114 | ||
| 4115 | // TODO call extern memcpy | 4115 | // 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 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const bits = @import("bits.zig"); | 2 | const bits = @import("bits.zig"); |
| 3 | const Register = bits.Register; | 3 | const Register = bits.Register; |
| 4 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | ||
| 4 | 5 | ||
| 5 | const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct { | 6 | const 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 |
| 18 | 19 | ||
| 19 | pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; | 20 | pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; |
| 20 | pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; | 21 | pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; |
| 22 | |||
| 23 | const allocatable_registers = callee_preserved_regs; | ||
| 24 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers); | ||
| 25 | |||
| 26 | // Register classes | ||
| 27 | const RegisterBitSet = RegisterManager.RegisterBitSet; | ||
| 28 | pub 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; |
| 21 | const leb128 = std.leb; | 21 | const leb128 = std.leb; |
| 22 | const log = std.log.scoped(.codegen); | 22 | const log = std.log.scoped(.codegen); |
| 23 | const build_options = @import("build_options"); | 23 | const build_options = @import("build_options"); |
| 24 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | ||
| 25 | const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers); | ||
| 26 | const RegisterLock = RegisterManager.RegisterLock; | ||
| 27 | 24 | ||
| 28 | const FnResult = @import("../../codegen.zig").FnResult; | 25 | const FnResult = @import("../../codegen.zig").FnResult; |
| 29 | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; | 26 | const 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; |
| 31 | 28 | ||
| 32 | const bits = @import("bits.zig"); | 29 | const bits = @import("bits.zig"); |
| 33 | const abi = @import("abi.zig"); | 30 | const abi = @import("abi.zig"); |
| 31 | const RegisterManager = abi.RegisterManager; | ||
| 32 | const RegisterLock = RegisterManager.RegisterLock; | ||
| 34 | const Register = bits.Register; | 33 | const Register = bits.Register; |
| 35 | const Instruction = bits.Instruction; | 34 | const Instruction = bits.Instruction; |
| 36 | const Condition = bits.Condition; | 35 | const Condition = bits.Condition; |
| 37 | const callee_preserved_regs = abi.callee_preserved_regs; | 36 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 38 | const caller_preserved_regs = abi.caller_preserved_regs; | 37 | const caller_preserved_regs = abi.caller_preserved_regs; |
| 39 | const allocatable_registers = abi.allocatable_registers; | ||
| 40 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; | 38 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 41 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; | 39 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 40 | const gp = abi.RegisterClass.gp; | ||
| 42 | 41 | ||
| 43 | const InnerError = error{ | 42 | const 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. |
| 941 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 940 | fn 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. |
| 950 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 949 | fn 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); |
| 1071 | 1070 | ||
| 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 | } |
| 1155 | 1154 | ||
| 1156 | break :blk try self.register_manager.allocReg(null, .{}); | 1155 | break :blk try self.register_manager.allocReg(null, gp); |
| 1157 | }; | 1156 | }; |
| 1158 | 1157 | ||
| 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 | } |
| 1185 | 1184 | ||
| 1186 | break :blk try self.register_manager.allocReg(null, .{}); | 1185 | break :blk try self.register_manager.allocReg(null, gp); |
| 1187 | }; | 1186 | }; |
| 1188 | 1187 | ||
| 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); |
| 1260 | 1259 | ||
| 1261 | // lhs == reg should have been checked by airMinMax | 1260 | // 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); |
| 1440 | 1439 | ||
| 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); |
| 1444 | 1443 | ||
| ... | @@ -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); |
| 1545 | 1544 | ||
| 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); |
| 1549 | 1548 | ||
| ... | @@ -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.register | 1582 | lhs.register |
| 1584 | else | 1583 | 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); |
| 1588 | 1587 | ||
| 1589 | const rhs_reg = if (rhs_is_register) | 1588 | const rhs_reg = if (rhs_is_register) |
| 1590 | rhs.register | 1589 | rhs.register |
| 1591 | else | 1590 | 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); |
| 1595 | 1594 | ||
| 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); |
| 1606 | 1605 | ||
| 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); |
| 1610 | 1609 | ||
| ... | @@ -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); |
| 2028 | 2027 | ||
| 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); |
| 2240 | 2239 | ||
| ... | @@ -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 allocation | 2243 | // 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); |
| 2277 | 2276 | ||
| ... | @@ -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); |
| 2344 | 2343 | ||
| 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 flag | 2487 | // get overflow bit: set register to C flag |
| 2489 | // resp. V flag | 2488 | // resp. V flag |
| 2490 | const dest_reg = try self.register_manager.allocReg(null, .{}); | 2489 | const dest_reg = try self.register_manager.allocReg(null, gp); |
| 2491 | 2490 | ||
| 2492 | // mov reg, #0 | 2491 | // 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; |
| 2569 | 2568 | ||
| 2570 | const reg = try self.register_manager.allocReg(track_inst, .{}); | 2569 | const reg = try self.register_manager.allocReg(track_inst, gp); |
| 2571 | 2570 | ||
| 2572 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | 2571 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| 2573 | 2572 | ||
| ... | @@ -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; |
| 2583 | 2582 | ||
| 2584 | const reg = try self.register_manager.allocReg(track_inst, .{}); | 2583 | const reg = try self.register_manager.allocReg(track_inst, gp); |
| 2585 | 2584 | ||
| 2586 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | 2585 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| 2587 | 2586 | ||
| ... | @@ -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 | }; |
| 2605 | 2604 | ||
| 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; |
| 2686 | 2685 | ||
| 2687 | const reg = try self.register_manager.allocReg(track_inst, .{}); | 2686 | const reg = try self.register_manager.allocReg(track_inst, gp); |
| 2688 | 2687 | ||
| 2689 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | 2688 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| 2690 | 2689 | ||
| ... | @@ -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 | }; |
| 2711 | 2710 | ||
| 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 |
| 4363 | 4362 | ||
| 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); |
| 4367 | 4366 | ||
| 4368 | // C flag: movcs reg, #1 | 4367 | // C flag: movcs reg, #1 |
| 4369 | // V flag: movvs reg, #1 | 4368 | // 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); |
| 4409 | 4408 | ||
| 4410 | // TODO call extern memcpy | 4409 | // 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); |
| 4783 | 4782 | ||
| 4784 | // TODO call extern memcpy | 4783 | // 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 @@ |
| 1 | const bits = @import("bits.zig"); | 1 | const bits = @import("bits.zig"); |
| 2 | const Register = bits.Register; | 2 | const Register = bits.Register; |
| 3 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | ||
| 3 | 4 | ||
| 4 | pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 }; | 5 | pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 }; |
| 5 | pub const caller_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3 }; | 6 | pub const caller_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3 }; |
| 6 | pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs; | ||
| 7 | 7 | ||
| 8 | pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 }; | 8 | pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 }; |
| 9 | pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 }; | 9 | pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 }; |
| 10 | |||
| 11 | const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs; | ||
| 12 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers); | ||
| 13 | |||
| 14 | // Register classes | ||
| 15 | const RegisterBitSet = RegisterManager.RegisterBitSet; | ||
| 16 | pub 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; |
| 21 | const leb128 = std.leb; | 21 | const leb128 = std.leb; |
| 22 | const log = std.log.scoped(.codegen); | 22 | const log = std.log.scoped(.codegen); |
| 23 | const build_options = @import("build_options"); | 23 | const build_options = @import("build_options"); |
| 24 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | ||
| 25 | const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs); | ||
| 26 | const RegisterLock = RegisterManager.RegisterLock; | ||
| 27 | 24 | ||
| 28 | const FnResult = @import("../../codegen.zig").FnResult; | 25 | const FnResult = @import("../../codegen.zig").FnResult; |
| 29 | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; | 26 | const 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; |
| 32 | const bits = @import("bits.zig"); | 29 | const bits = @import("bits.zig"); |
| 33 | const abi = @import("abi.zig"); | 30 | const abi = @import("abi.zig"); |
| 34 | const Register = bits.Register; | 31 | const Register = bits.Register; |
| 32 | const RegisterManager = abi.RegisterManager; | ||
| 33 | const RegisterLock = RegisterManager.RegisterLock; | ||
| 35 | const Instruction = abi.Instruction; | 34 | const Instruction = abi.Instruction; |
| 36 | const callee_preserved_regs = abi.callee_preserved_regs; | 35 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 36 | const gp = abi.RegisterClass.gp; | ||
| 37 | 37 | ||
| 38 | const InnerError = error{ | 38 | const 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. |
| 828 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 828 | fn 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. |
| 837 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 837 | fn 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; |
| 960 | 960 | ||
| 961 | const reg = try self.register_manager.allocReg(track_inst, .{}); | 961 | const reg = try self.register_manager.allocReg(track_inst, gp); |
| 962 | 962 | ||
| 963 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | 963 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| 964 | 964 | ||
| ... | @@ -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; |
| 975 | 975 | ||
| 976 | const reg = try self.register_manager.allocReg(track_inst, .{}); | 976 | const reg = try self.register_manager.allocReg(track_inst, gp); |
| 977 | 977 | ||
| 978 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | 978 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| 979 | 979 | ||
| ... | @@ -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); |
| 996 | 996 | ||
| 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); |
| 1488 | 1488 |
src/arch/riscv64/abi.zig+17| ... | @@ -1,6 +1,23 @@ | ... | @@ -1,6 +1,23 @@ |
| 1 | const bits = @import("bits.zig"); | 1 | const bits = @import("bits.zig"); |
| 2 | const Register = bits.Register; | 2 | const Register = bits.Register; |
| 3 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | ||
| 3 | 4 | ||
| 4 | pub const callee_preserved_regs = [_]Register{ | 5 | pub 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 | |||
| 9 | const allocatable_registers = callee_preserved_regs; | ||
| 10 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers); | ||
| 11 | |||
| 12 | // Register classes | ||
| 13 | const RegisterBitSet = RegisterManager.RegisterBitSet; | ||
| 14 | pub 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; |
| 21 | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; | 21 | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; |
| 22 | const FnResult = @import("../../codegen.zig").FnResult; | 22 | const FnResult = @import("../../codegen.zig").FnResult; |
| 23 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | 23 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 24 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | ||
| 25 | const RegisterManager = RegisterManagerFn(Self, Register, &abi.allocatable_regs); | ||
| 26 | const RegisterLock = RegisterManager.RegisterLock; | ||
| 27 | 24 | ||
| 28 | const build_options = @import("build_options"); | 25 | const build_options = @import("build_options"); |
| 29 | 26 | ||
| ... | @@ -31,7 +28,10 @@ const bits = @import("bits.zig"); | ... | @@ -31,7 +28,10 @@ const bits = @import("bits.zig"); |
| 31 | const abi = @import("abi.zig"); | 28 | const abi = @import("abi.zig"); |
| 32 | const Instruction = bits.Instruction; | 29 | const Instruction = bits.Instruction; |
| 33 | const ShiftWidth = Instruction.ShiftWidth; | 30 | const ShiftWidth = Instruction.ShiftWidth; |
| 31 | const RegisterManager = abi.RegisterManager; | ||
| 32 | const RegisterLock = RegisterManager.RegisterLock; | ||
| 34 | const Register = bits.Register; | 33 | const Register = bits.Register; |
| 34 | const gp = abi.RegisterClass.gp; | ||
| 35 | 35 | ||
| 36 | const Self = @This(); | 36 | const Self = @This(); |
| 37 | 37 | ||
| ... | @@ -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; |
| 1856 | 1856 | ||
| 1857 | const reg = try self.register_manager.allocReg(track_inst, .{}); | 1857 | const reg = try self.register_manager.allocReg(track_inst, gp); |
| 1858 | 1858 | ||
| 1859 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | 1859 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| 1860 | 1860 | ||
| ... | @@ -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 | }; |
| 1882 | 1882 | ||
| ... | @@ -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; |
| 1955 | 1955 | ||
| 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 }); |
| 1958 | 1958 | ||
| 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; |
| 1968 | 1968 | ||
| 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 }); |
| 1971 | 1971 | ||
| 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 | }; |
| 1990 | 1990 | ||
| ... | @@ -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. |
| 2079 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 2079 | fn 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); |
| 2368 | 2368 | ||
| 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); |
| 2480 | 2480 | ||
| 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); |
| 2723 | 2723 | ||
| 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 @@ |
| 1 | const bits = @import("bits.zig"); | 1 | const bits = @import("bits.zig"); |
| 2 | const Register = bits.Register; | 2 | const Register = bits.Register; |
| 3 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | ||
| 3 | 4 | ||
| 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; |
| 21 | pub const caller_preserved_regs = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5, .g1, .g4, .g5 }; | 22 | pub const caller_preserved_regs = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5, .g1, .g4, .g5 }; |
| 22 | 23 | ||
| 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. |
| 24 | pub const allocatable_regs = [_]Register{ | 25 | const allocatable_regs = [_]Register{ |
| 25 | // zig fmt: off | 26 | // 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" |
| 35 | 36 | ||
| 36 | pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3 }; | 37 | pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3 }; |
| 37 | pub const c_abi_int_return_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3" }; | 38 | pub const c_abi_int_return_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3" }; |
| 39 | |||
| 40 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_regs); | ||
| 41 | |||
| 42 | // Register classes | ||
| 43 | const RegisterBitSet = RegisterManager.RegisterBitSet; | ||
| 44 | pub 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. |
| 974 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 970 | fn 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! |
| 993 | fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue { | 987 | fn 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); |
| 1058 | 1050 | ||
| 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 | }; |
| 1415 | 1405 | ||
| 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); |
| 2079 | 2067 | ||
| 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); |
| 2160 | 2146 | ||
| 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); |
| 2730 | 2714 | ||
| 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); |
| 2734 | 2718 | ||
| ... | @@ -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); |
| 2806 | 2790 | ||
| ... | @@ -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); |
| 3021 | 3005 | ||
| 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 |
| 5428 | 5412 | ||
| 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); |
| 5658 | 5642 | ||
| 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); |
| 5693 | 5677 | ||
| 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); |
| 5728 | 5712 | ||
| 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(); |
| 5734 | 5716 | ||
| ... | @@ -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); |
| 5830 | 5812 | ||
| 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); |
| 6092 | 6074 | ||
| 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); |
| 6135 | 6117 | ||
| 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 | } |
| 59 | 59 | ||
| 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 | } |
| 169 | 174 | ||
| 170 | const AllocOpts = struct { | ||
| 171 | selector_mask: ?RegisterBitSet = null, | ||
| 172 | }; | ||
| 173 | |||
| 174 | /// Allocates a specified number of registers, optionally | 175 | /// Allocates a specified number of registers, optionally |
| 175 | /// tracking them. Returns `null` if not enough registers are | 176 | /// 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); |
| 184 | 185 | ||
| 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); |
| 189 | 188 | ||
| 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; |
| 203 | 203 | ||
| ... | @@ -223,8 +223,8 @@ pub fn RegisterManager( | ... | @@ -223,8 +223,8 @@ pub fn RegisterManager( |
| 223 | /// Allocates a register and optionally tracks it with a | 223 | /// Allocates a register and optionally tracks it with a |
| 224 | /// corresponding instruction. Returns `null` if all registers | 224 | /// 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 | } |
| 229 | 229 | ||
| 230 | /// Allocates a specified number of registers, optionally | 230 | /// 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); |
| 240 | 240 | ||
| 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); |
| 245 | 243 | ||
| 246 | if (count > available_registers.count() - locked_registers.count()) return error.OutOfRegisters; | 244 | if (count > register_class.count() - locked_registers.count()) return error.OutOfRegisters; |
| 247 | 245 | ||
| 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. Spill | 247 | // We'll take over the first count registers. Spill |
| 250 | // the instructions that were previously there to a | 248 | // 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; |
| 257 | 256 | ||
| 258 | regs[i] = reg; | 257 | regs[i] = reg; |
| ... | @@ -288,8 +287,12 @@ pub fn RegisterManager( | ... | @@ -288,8 +287,12 @@ pub fn RegisterManager( |
| 288 | 287 | ||
| 289 | /// Allocates a register and optionally tracks it with a | 288 | /// 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 | } |
| 294 | 297 | ||
| 295 | /// Spills the register if it is currently allocated. If a | 298 | /// 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) { |
| 374 | fn MockFunction(comptime Register: type) type { | 377 | fn 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) = .{}, |
| 379 | 382 | ||
| 380 | const Self = @This(); | 383 | const Self = @This(); |
| 381 | 384 | ||
| 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(); |
| 424 | 431 | ||
| 425 | const mock_instruction: Air.Inst.Index = 1; | 432 | const mock_instruction: Air.Inst.Index = 1; |
| 426 | 433 | 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 | )); | ||
| 430 | 447 | ||
| 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(); |
| 452 | 469 | ||
| 453 | const mock_instruction: Air.Inst.Index = 1; | 470 | const mock_instruction: Air.Inst.Index = 1; |
| 471 | const reg_class = MockFunction1.reg_class; | ||
| 454 | 472 | ||
| 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 | )); | ||
| 457 | 481 | ||
| 458 | // Spill a register | 482 | // 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); |
| 461 | 488 | ||
| 462 | // No spilling necessary | 489 | // 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); |
| 466 | 496 | ||
| 467 | // Locked registers | 497 | // 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); |
| 472 | 502 | ||
| 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(); |
| 485 | 518 | ||
| 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 | ).?); | ||
| 487 | 526 | ||
| 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); |
| 500 | 539 | ||
| 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()); |
| 504 | 547 | ||
| ... | @@ -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(); |
| 520 | 563 | ||
| 564 | const reg_class = MockFunction2.reg_class; | ||
| 565 | |||
| 521 | { | 566 | { |
| 522 | const result_reg: MockRegister2 = .r1; | 567 | const result_reg: MockRegister2 = .r1; |
| 523 | 568 | ||
| ... | @@ -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); |
| 539 | 584 | ||
| 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(); |
| 554 | 599 | ||
| 600 | const reg_class = MockFunction2.reg_class; | ||
| 601 | |||
| 555 | { | 602 | { |
| 556 | const result_reg: MockRegister2 = .r1; | 603 | const result_reg: MockRegister2 = .r1; |
| 557 | 604 | ||
| ... | @@ -559,12 +606,12 @@ test "allocRegs: selectively reducing register pressure" { | ... | @@ -559,12 +606,12 @@ test "allocRegs: selectively reducing register pressure" { |
| 559 | 606 | ||
| 560 | // Here, we don't defer unlock because we manually unlock | 607 | // Here, we don't defer unlock because we manually unlock |
| 561 | // after genAdd | 608 | // 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); |
| 563 | 610 | ||
| 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.?); |
| 566 | 613 | ||
| 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 | } |