authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-18 12:23:07+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-19 19:39:34+02:00
logf34615082058549d8945a39195cf0dc826b688e1
tree8134a2b559441b8b583e37454146e4a2b41ca9aa
parent549174f743d3b56544e2d3d6993f4d43bba1e7fd

x64: use register classes mask to select between gp and avx


4 files changed, 81 insertions(+), 39 deletions(-)

src/arch/x86_64/CodeGen.zig+49-20
...@@ -38,6 +38,9 @@ const c_abi_int_return_regs = abi.c_abi_int_return_regs;...@@ -38,6 +38,9 @@ const c_abi_int_return_regs = abi.c_abi_int_return_regs;
38const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers);38const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers);
39const RegisterLock = RegisterManager.RegisterLock;39const RegisterLock = RegisterManager.RegisterLock;
40const Register = bits.Register;40const Register = bits.Register;
41const RegisterClass = abi.RegisterClass;
42const gp = RegisterClass.gp;
43const avx = RegisterClass.avx;
4144
42const InnerError = error{45const InnerError = error{
43 OutOfMemory,46 OutOfMemory,
...@@ -882,7 +885,9 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -882,7 +885,9 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
882 // TODO check if AVX available885 // TODO check if AVX available
883 const ptr_bytes: u64 = 32;886 const ptr_bytes: u64 = 32;
884 if (abi_size <= ptr_bytes) {887 if (abi_size <= ptr_bytes) {
885 if (self.register_manager.tryAllocReg(inst, .{})) |reg| {888 if (self.register_manager.tryAllocReg(inst, .{
889 .selector_mask = avx,
890 })) |reg| {
886 return MCValue{ .register = registerAlias(reg, abi_size) };891 return MCValue{ .register = registerAlias(reg, abi_size) };
887 }892 }
888 }893 }
...@@ -892,7 +897,9 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -892,7 +897,9 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
892 const ptr_bits = self.target.cpu.arch.ptrBitWidth();897 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
893 const ptr_bytes: u64 = @divExact(ptr_bits, 8);898 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
894 if (abi_size <= ptr_bytes) {899 if (abi_size <= ptr_bytes) {
895 if (self.register_manager.tryAllocReg(inst, .{})) |reg| {900 if (self.register_manager.tryAllocReg(inst, .{
901 .selector_mask = gp,
902 })) |reg| {
896 return MCValue{ .register = registerAlias(reg, abi_size) };903 return MCValue{ .register = registerAlias(reg, abi_size) };
897 }904 }
898 }905 }
...@@ -963,7 +970,13 @@ pub fn spillRegisters(self: *Self, comptime count: comptime_int, registers: [cou...@@ -963,7 +970,13 @@ pub fn spillRegisters(self: *Self, comptime count: comptime_int, registers: [cou
963/// allocated. A second call to `copyToTmpRegister` may return the same register.970/// allocated. A second call to `copyToTmpRegister` may return the same register.
964/// This can have a side effect of spilling instructions to the stack to free up a register.971/// This can have a side effect of spilling instructions to the stack to free up a register.
965fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {972fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
966 const reg = try self.register_manager.allocReg(null, .{});973 const mask = switch (ty.zigTypeTag()) {
974 .Float => avx,
975 else => gp,
976 };
977 const reg: Register = try self.register_manager.allocReg(null, .{
978 .selector_mask = mask,
979 });
967 try self.genSetReg(ty, reg, mcv);980 try self.genSetReg(ty, reg, mcv);
968 return reg;981 return reg;
969}982}
...@@ -973,7 +986,13 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {...@@ -973,7 +986,13 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
973/// This can have a side effect of spilling instructions to the stack to free up a register.986/// This can have a side effect of spilling instructions to the stack to free up a register.
974/// WARNING make sure that the allocated register matches the returned MCValue from an instruction!987/// WARNING make sure that the allocated register matches the returned MCValue from an instruction!
975fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {988fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {
976 const reg = try self.register_manager.allocReg(reg_owner, .{});989 const mask = switch (ty.zigTypeTag()) {
990 .Float => avx,
991 else => gp,
992 };
993 const reg: Register = try self.register_manager.allocReg(reg_owner, .{
994 .selector_mask = mask,
995 });
977 try self.genSetReg(ty, reg, mcv);996 try self.genSetReg(ty, reg, mcv);
978 return MCValue{ .register = reg };997 return MCValue{ .register = reg };
979}998}
...@@ -1029,7 +1048,9 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -1029,7 +1048,9 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1029 };1048 };
1030 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);1049 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
10311050
1032 const reg = try self.register_manager.allocReg(inst, .{});1051 const reg = try self.register_manager.allocReg(inst, .{
1052 .selector_mask = gp,
1053 });
1033 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });1054 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
1034 try self.genSetReg(operand_ty, reg, operand);1055 try self.genSetReg(operand_ty, reg, operand);
1035 break :blk MCValue{ .register = reg };1056 break :blk MCValue{ .register = reg };
...@@ -1384,7 +1405,9 @@ fn genSetStackTruncatedOverflowCompare(...@@ -1384,7 +1405,9 @@ fn genSetStackTruncatedOverflowCompare(
1384 .unsigned => ty,1405 .unsigned => ty,
1385 };1406 };
13861407
1387 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, .{});1408 const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, .{
1409 .selector_mask = gp,
1410 });
1388 const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);1411 const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);
1389 defer for (temp_regs_locks) |rreg| {1412 defer for (temp_regs_locks) |rreg| {
1390 self.register_manager.unlockReg(rreg);1413 self.register_manager.unlockReg(rreg);
...@@ -2046,7 +2069,9 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {...@@ -2046,7 +2069,9 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
2046 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);2069 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2047 defer self.register_manager.unlockReg(offset_reg_lock);2070 defer self.register_manager.unlockReg(offset_reg_lock);
20482071
2049 const addr_reg = try self.register_manager.allocReg(null, .{});2072 const addr_reg = try self.register_manager.allocReg(null, .{
2073 .selector_mask = gp,
2074 });
2050 switch (slice_mcv) {2075 switch (slice_mcv) {
2051 .stack_offset => |off| {2076 .stack_offset => |off| {
2052 // mov reg, [rbp - 8]2077 // mov reg, [rbp - 8]
...@@ -2125,7 +2150,9 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2125,7 +2150,9 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2125 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);2150 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2126 defer self.register_manager.unlockReg(offset_reg_lock);2151 defer self.register_manager.unlockReg(offset_reg_lock);
21272152
2128 const addr_reg = try self.register_manager.allocReg(null, .{});2153 const addr_reg = try self.register_manager.allocReg(null, .{
2154 .selector_mask = gp,
2155 });
2129 switch (array) {2156 switch (array) {
2130 .register => {2157 .register => {
2131 const off = @intCast(i32, try self.allocMem(2158 const off = @intCast(i32, try self.allocMem(
...@@ -2492,7 +2519,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2492,7 +2519,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2492 },2519 },
2493 .stack_offset => |off| {2520 .stack_offset => |off| {
2494 if (abi_size <= 8) {2521 if (abi_size <= 8) {
2495 const tmp_reg = try self.register_manager.allocReg(null, .{});2522 const tmp_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
2496 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);2523 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
2497 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }, .{});2524 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }, .{});
2498 }2525 }
...@@ -2693,7 +2720,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2693,7 +2720,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2693 };2720 };
2694 defer if (value_lock) |lock| self.register_manager.unlockReg(lock);2721 defer if (value_lock) |lock| self.register_manager.unlockReg(lock);
26952722
2696 const addr_reg = try self.register_manager.allocReg(null, .{});2723 const addr_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
2697 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);2724 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
2698 defer self.register_manager.unlockReg(addr_reg_lock);2725 defer self.register_manager.unlockReg(addr_reg_lock);
26992726
...@@ -2765,7 +2792,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2765,7 +2792,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2765 .memory,2792 .memory,
2766 => {2793 => {
2767 if (abi_size <= 8) {2794 if (abi_size <= 8) {
2768 const tmp_reg = try self.register_manager.allocReg(null, .{});2795 const tmp_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
2769 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);2796 const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
2770 defer self.register_manager.unlockReg(tmp_reg_lock);2797 defer self.register_manager.unlockReg(tmp_reg_lock);
27712798
...@@ -2883,7 +2910,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2883,7 +2910,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
2883 if (can_reuse_operand) {2910 if (can_reuse_operand) {
2884 break :blk reg;2911 break :blk reg;
2885 } else {2912 } else {
2886 const result_reg = try self.register_manager.allocReg(inst, .{});2913 const result_reg = try self.register_manager.allocReg(inst, .{ .selector_mask = gp });
2887 try self.genSetReg(ptr_ty, result_reg, mcv);2914 try self.genSetReg(ptr_ty, result_reg, mcv);
2888 break :blk result_reg;2915 break :blk result_reg;
2889 }2916 }
...@@ -2984,7 +3011,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2984,7 +3011,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2984 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);3011 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
2985 defer self.register_manager.unlockReg(reg_lock);3012 defer self.register_manager.unlockReg(reg_lock);
29863013
2987 const dst_reg = try self.register_manager.allocReg(inst, .{});3014 const dst_reg = try self.register_manager.allocReg(inst, .{ .selector_mask = gp });
2988 const flags: u2 = switch (mcv) {3015 const flags: u2 = switch (mcv) {
2989 .register_overflow_unsigned => 0b10,3016 .register_overflow_unsigned => 0b10,
2990 .register_overflow_signed => 0b00,3017 .register_overflow_signed => 0b00,
...@@ -5362,7 +5389,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5362,7 +5389,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
53625389
5363 const overflow_bit_ty = ty.structFieldType(1);5390 const overflow_bit_ty = ty.structFieldType(1);
5364 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);5391 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
5365 const tmp_reg = try self.register_manager.allocReg(null, .{});5392 const tmp_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
5366 const flags: u2 = switch (mcv) {5393 const flags: u2 = switch (mcv) {
5367 .register_overflow_unsigned => 0b10,5394 .register_overflow_unsigned => 0b10,
5368 .register_overflow_signed => 0b00,5395 .register_overflow_signed => 0b00,
...@@ -5580,7 +5607,7 @@ fn genInlineMemcpy(...@@ -5580,7 +5607,7 @@ fn genInlineMemcpy(
5580 null;5607 null;
5581 defer if (dsbase_lock) |lock| self.register_manager.unlockReg(lock);5608 defer if (dsbase_lock) |lock| self.register_manager.unlockReg(lock);
55825609
5583 const dst_addr_reg = try self.register_manager.allocReg(null, .{});5610 const dst_addr_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
5584 switch (dst_ptr) {5611 switch (dst_ptr) {
5585 .memory,5612 .memory,
5586 .got_load,5613 .got_load,
...@@ -5615,7 +5642,7 @@ fn genInlineMemcpy(...@@ -5615,7 +5642,7 @@ fn genInlineMemcpy(
5615 const dst_addr_reg_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);5642 const dst_addr_reg_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);
5616 defer self.register_manager.unlockReg(dst_addr_reg_lock);5643 defer self.register_manager.unlockReg(dst_addr_reg_lock);
56175644
5618 const src_addr_reg = try self.register_manager.allocReg(null, .{});5645 const src_addr_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
5619 switch (src_ptr) {5646 switch (src_ptr) {
5620 .memory,5647 .memory,
5621 .got_load,5648 .got_load,
...@@ -5650,7 +5677,9 @@ fn genInlineMemcpy(...@@ -5650,7 +5677,9 @@ fn genInlineMemcpy(
5650 const src_addr_reg_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);5677 const src_addr_reg_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
5651 defer self.register_manager.unlockReg(src_addr_reg_lock);5678 defer self.register_manager.unlockReg(src_addr_reg_lock);
56525679
5653 const regs = try self.register_manager.allocRegs(2, .{ null, null }, .{});5680 const regs = try self.register_manager.allocRegs(2, .{ null, null }, .{
5681 .selector_mask = gp,
5682 });
5654 const count_reg = regs[0].to64();5683 const count_reg = regs[0].to64();
5655 const tmp_reg = regs[1].to8();5684 const tmp_reg = regs[1].to8();
56565685
...@@ -5750,7 +5779,7 @@ fn genInlineMemset(...@@ -5750,7 +5779,7 @@ fn genInlineMemset(
5750 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);5779 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
5751 defer self.register_manager.unlockReg(rax_lock);5780 defer self.register_manager.unlockReg(rax_lock);
57525781
5753 const addr_reg = try self.register_manager.allocReg(null, .{});5782 const addr_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
5754 switch (dst_ptr) {5783 switch (dst_ptr) {
5755 .memory,5784 .memory,
5756 .got_load,5785 .got_load,
...@@ -6018,7 +6047,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6018,7 +6047,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6018 switch (ty.tag()) {6047 switch (ty.tag()) {
6019 .f32 => return self.fail("TODO genSetReg from memory for f32", .{}),6048 .f32 => return self.fail("TODO genSetReg from memory for f32", .{}),
6020 .f64 => {6049 .f64 => {
6021 const base_reg = try self.register_manager.allocReg(null, .{});6050 const base_reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
6022 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);6051 try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);
6023 _ = try self.addInst(.{6052 _ = try self.addInst(.{
6024 .tag = .mov_f64,6053 .tag = .mov_f64,
...@@ -6328,7 +6357,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -6328,7 +6357,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
6328 const src: MCValue = blk: {6357 const src: MCValue = blk: {
6329 switch (src_ptr) {6358 switch (src_ptr) {
6330 .got_load, .direct_load, .memory => {6359 .got_load, .direct_load, .memory => {
6331 const reg = try self.register_manager.allocReg(null, .{});6360 const reg = try self.register_manager.allocReg(null, .{ .selector_mask = gp });
6332 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);6361 try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr);
6333 _ = try self.addInst(.{6362 _ = try self.addInst(.{
6334 .tag = .mov,6363 .tag = .mov,
src/arch/x86_64/abi.zig+7-6
...@@ -384,11 +384,12 @@ pub const avx_regs = [_]Register{...@@ -384,11 +384,12 @@ pub const avx_regs = [_]Register{
384};384};
385pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs ++ avx_regs;385pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs ++ avx_regs;
386386
387// Masks for register manager
388const FreeRegInt = std.meta.Int(.unsigned, allocatable_registers.len);
389// TODO
390pub const gp_mask: FreeRegInt = 0x3fff;
391pub const avx_mask: FreeRegInt = 0x3fff_c000;
392
393pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };387pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
394pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };388pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
389
390// Masks for register manager
391const FreeRegInt = std.meta.Int(.unsigned, allocatable_registers.len);
392pub const RegisterClass = struct {
393 pub const gp: FreeRegInt = 0x3fff;
394 pub const avx: FreeRegInt = 0x3fff_c000;
395};
src/arch/x86_64/bits.zig+9-9
...@@ -56,10 +56,10 @@ pub const Register = enum(u7) {...@@ -56,10 +56,10 @@ pub const Register = enum(u7) {
56 // Pseudo-value for MIR instructions.56 // Pseudo-value for MIR instructions.
57 none,57 none,
5858
59 pub fn id(self: Register) u5 {59 pub fn id(self: Register) u7 {
60 return switch (@enumToInt(self)) {60 return switch (@enumToInt(self)) {
61 0...63 => @as(u5, @truncate(u4, @enumToInt(self))),61 0...63 => @as(u7, @truncate(u4, @enumToInt(self))),
62 64...79 => @truncate(u5, @enumToInt(self)),62 64...79 => @enumToInt(self),
63 else => unreachable,63 else => unreachable,
64 };64 };
65 }65 }
...@@ -101,31 +101,31 @@ pub const Register = enum(u7) {...@@ -101,31 +101,31 @@ pub const Register = enum(u7) {
101 }101 }
102102
103 pub fn to256(self: Register) Register {103 pub fn to256(self: Register) Register {
104 return @intToEnum(Register, @as(u8, self.id()) + 64);104 return @intToEnum(Register, @as(u8, self.enc()) + 64);
105 }105 }
106106
107 pub fn to128(self: Register) Register {107 pub fn to128(self: Register) Register {
108 return @intToEnum(Register, @as(u8, self.id()) + 80);108 return @intToEnum(Register, @as(u8, self.enc()) + 80);
109 }109 }
110110
111 /// Convert from any register to its 64 bit alias.111 /// Convert from any register to its 64 bit alias.
112 pub fn to64(self: Register) Register {112 pub fn to64(self: Register) Register {
113 return @intToEnum(Register, self.id());113 return @intToEnum(Register, self.enc());
114 }114 }
115115
116 /// Convert from any register to its 32 bit alias.116 /// Convert from any register to its 32 bit alias.
117 pub fn to32(self: Register) Register {117 pub fn to32(self: Register) Register {
118 return @intToEnum(Register, @as(u8, self.id()) + 16);118 return @intToEnum(Register, @as(u8, self.enc()) + 16);
119 }119 }
120120
121 /// Convert from any register to its 16 bit alias.121 /// Convert from any register to its 16 bit alias.
122 pub fn to16(self: Register) Register {122 pub fn to16(self: Register) Register {
123 return @intToEnum(Register, @as(u8, self.id()) + 32);123 return @intToEnum(Register, @as(u8, self.enc()) + 32);
124 }124 }
125125
126 /// Convert from any register to its 8 bit alias.126 /// Convert from any register to its 8 bit alias.
127 pub fn to8(self: Register) Register {127 pub fn to8(self: Register) Register {
128 return @intToEnum(Register, @as(u8, self.id()) + 48);128 return @intToEnum(Register, @as(u8, self.enc()) + 48);
129 }129 }
130130
131 pub fn dwarfLocOp(self: Register) u8 {131 pub fn dwarfLocOp(self: Register) u8 {
src/register_manager.zig+16-4
...@@ -66,6 +66,11 @@ pub fn RegisterManager(...@@ -66,6 +66,11 @@ pub fn RegisterManager(
66 return mask;66 return mask;
67 }67 }
6868
69 fn excludeRegister(reg: Register, mask: FreeRegInt) bool {
70 const reg_mask = getRegisterMask(reg) orelse return true;
71 return reg_mask & mask == 0;
72 }
73
69 fn markRegAllocated(self: *Self, reg: Register) void {74 fn markRegAllocated(self: *Self, reg: Register) void {
70 const mask = getRegisterMask(reg) orelse return;75 const mask = getRegisterMask(reg) orelse return;
71 self.allocated_registers |= mask;76 self.allocated_registers |= mask;
...@@ -186,10 +191,11 @@ pub fn RegisterManager(...@@ -186,10 +191,11 @@ pub fn RegisterManager(
186 insts: [count]?Air.Inst.Index,191 insts: [count]?Air.Inst.Index,
187 opts: AllocOpts,192 opts: AllocOpts,
188 ) ?[count]Register {193 ) ?[count]Register {
189 _ = opts;
190 comptime assert(count > 0 and count <= tracked_registers.len);194 comptime assert(count > 0 and count <= tracked_registers.len);
191195
192 const free_and_not_locked_registers = self.free_registers & ~self.locked_registers;196 const selector_mask = if (opts.selector_mask) |mask| mask else ~@as(FreeRegInt, 0);
197 const free_registers = self.free_registers & selector_mask;
198 const free_and_not_locked_registers = free_registers & ~self.locked_registers;
193 const free_and_not_locked_registers_count = @popCount(FreeRegInt, free_and_not_locked_registers);199 const free_and_not_locked_registers_count = @popCount(FreeRegInt, free_and_not_locked_registers);
194 if (free_and_not_locked_registers_count < count) return null;200 if (free_and_not_locked_registers_count < count) return null;
195201
...@@ -197,6 +203,7 @@ pub fn RegisterManager(...@@ -197,6 +203,7 @@ pub fn RegisterManager(
197 var i: usize = 0;203 var i: usize = 0;
198 for (tracked_registers) |reg| {204 for (tracked_registers) |reg| {
199 if (i >= count) break;205 if (i >= count) break;
206 if (excludeRegister(reg, selector_mask)) continue;
200 if (self.isRegLocked(reg)) continue;207 if (self.isRegLocked(reg)) continue;
201 if (!self.isRegFree(reg)) continue;208 if (!self.isRegFree(reg)) continue;
202209
...@@ -236,8 +243,12 @@ pub fn RegisterManager(...@@ -236,8 +243,12 @@ pub fn RegisterManager(
236 opts: AllocOpts,243 opts: AllocOpts,
237 ) AllocateRegistersError![count]Register {244 ) AllocateRegistersError![count]Register {
238 comptime assert(count > 0 and count <= tracked_registers.len);245 comptime assert(count > 0 and count <= tracked_registers.len);
239 const locked_registers_count = @popCount(FreeRegInt, self.locked_registers);246
240 if (count > tracked_registers.len - locked_registers_count) return error.OutOfRegisters;247 const selector_mask = if (opts.selector_mask) |mask| mask else ~@as(FreeRegInt, 0);
248 const available_registers_count = @popCount(FreeRegInt, selector_mask);
249 const locked_registers = self.locked_registers & selector_mask;
250 const locked_registers_count = @popCount(FreeRegInt, locked_registers);
251 if (count > available_registers_count - locked_registers_count) return error.OutOfRegisters;
241252
242 const result = self.tryAllocRegs(count, insts, opts) orelse blk: {253 const result = self.tryAllocRegs(count, insts, opts) orelse blk: {
243 // We'll take over the first count registers. Spill254 // We'll take over the first count registers. Spill
...@@ -247,6 +258,7 @@ pub fn RegisterManager(...@@ -247,6 +258,7 @@ pub fn RegisterManager(
247 var i: usize = 0;258 var i: usize = 0;
248 for (tracked_registers) |reg| {259 for (tracked_registers) |reg| {
249 if (i >= count) break;260 if (i >= count) break;
261 if (excludeRegister(reg, selector_mask)) continue;
250 if (self.isRegLocked(reg)) continue;262 if (self.isRegLocked(reg)) continue;
251263
252 regs[i] = reg;264 regs[i] = reg;