authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-19 15:34:13+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-19 19:39:34+02:00
log283f40e4e9c44986353ba8abcc760684e9adf6cc
tree1c46fba4df6ea88b7d375b26c54058cc088aa74f
parent080d138b9d06402a8fbb70b4addc90751c6b798e

x64: use StaticBitSet instead of an integer internally in RegisterManager


3 files changed, 78 insertions(+), 68 deletions(-)

src/arch/x86_64/CodeGen.zig+5-6
......@@ -21,7 +21,6 @@ const Emit = @import("Emit.zig");
2121const Liveness = @import("../../Liveness.zig");
2222const Mir = @import("Mir.zig");
2323const Module = @import("../../Module.zig");
24const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
2524const Target = std.Target;
2625const Type = @import("../../type.zig").Type;
2726const TypedValue = @import("../../TypedValue.zig");
......@@ -32,15 +31,15 @@ const abi = @import("abi.zig");
3231
3332const callee_preserved_regs = abi.callee_preserved_regs;
3433const caller_preserved_regs = abi.caller_preserved_regs;
35const allocatable_registers = abi.allocatable_registers;
3634const c_abi_int_param_regs = abi.c_abi_int_param_regs;
3735const c_abi_int_return_regs = abi.c_abi_int_return_regs;
38const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers);
36
37const RegisterManager = abi.RegisterManager;
3938const RegisterLock = RegisterManager.RegisterLock;
4039const Register = bits.Register;
41const RegisterClass = abi.RegisterClass;
42const gp = RegisterClass.gp;
43const avx = RegisterClass.avx;
40
41const gp = abi.RegisterClass.gp;
42const avx = abi.RegisterClass.avx;
4443
4544const InnerError = error{
4645 OutOfMemory,
src/arch/x86_64/abi.zig+26-9
......@@ -3,6 +3,7 @@ const Type = @import("../../type.zig").Type;
33const Target = std.Target;
44const assert = std.debug.assert;
55const Register = @import("bits.zig").Register;
6const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
67
78pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none };
89
......@@ -378,18 +379,34 @@ pub const callee_preserved_regs = [_]Register{ .rbx, .r12, .r13, .r14, .r15 };
378379/// the caller relinquishes control to a subroutine via call instruction (or similar).
379380/// In other words, these registers are free to use by the callee.
380381pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
381pub const avx_regs = [_]Register{
382 .ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7,
383 .ymm8, .ymm9, .ymm10, .ymm11, .ymm12, .ymm13, .ymm14, .ymm15,
384};
385pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs ++ avx_regs;
386382
387383pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
388384pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
389385
390// Masks for register manager
391const FreeRegInt = std.meta.Int(.unsigned, allocatable_registers.len);
386const avx_regs = [_]Register{
387 .ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7,
388 .ymm8, .ymm9, .ymm10, .ymm11, .ymm12, .ymm13, .ymm14, .ymm15,
389};
390const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs ++ avx_regs;
391pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
392
393// Register classes
394const RegisterBitSet = RegisterManager.RegisterBitSet;
392395pub const RegisterClass = struct {
393 pub const gp: FreeRegInt = 0x3fff;
394 pub const avx: FreeRegInt = 0x3fff_c000;
396 pub const gp: RegisterBitSet = blk: {
397 var set = RegisterBitSet.initEmpty();
398 set.setRangeValue(.{
399 .start = 0,
400 .end = caller_preserved_regs.len + callee_preserved_regs.len,
401 }, true);
402 break :blk set;
403 };
404 pub const avx: RegisterBitSet = blk: {
405 var set = RegisterBitSet.initEmpty();
406 set.setRangeValue(.{
407 .start = caller_preserved_regs.len + callee_preserved_regs.len,
408 .end = allocatable_registers.len,
409 }, true);
410 break :blk set;
411 };
395412};
src/register_manager.zig+47-53
......@@ -4,6 +4,7 @@ const mem = std.mem;
44const assert = std.debug.assert;
55const Allocator = std.mem.Allocator;
66const Air = @import("Air.zig");
7const StaticBitSet = std.bit_set.StaticBitSet;
78const Type = @import("type.zig").Type;
89const Module = @import("Module.zig");
910const expect = std.testing.expect;
......@@ -41,66 +42,54 @@ pub fn RegisterManager(
4142 registers: [tracked_registers.len]Air.Inst.Index = undefined,
4243 /// Tracks which registers are free (in which case the
4344 /// corresponding bit is set to 1)
44 free_registers: FreeRegInt = math.maxInt(FreeRegInt),
45 free_registers: RegisterBitSet = RegisterBitSet.initFull(),
4546 /// Tracks all registers allocated in the course of this
4647 /// function
47 allocated_registers: FreeRegInt = 0,
48 allocated_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
4849 /// Tracks registers which are locked from being allocated
49 locked_registers: FreeRegInt = 0,
50 locked_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
5051
5152 const Self = @This();
5253
53 /// An integer whose bits represent all the registers and
54 /// whether they are free.
55 const FreeRegInt = std.meta.Int(.unsigned, tracked_registers.len);
56 const ShiftInt = math.Log2Int(FreeRegInt);
54 pub const RegisterBitSet = StaticBitSet(tracked_registers.len);
5755
5856 fn getFunction(self: *Self) *Function {
5957 return @fieldParentPtr(Function, "register_manager", self);
6058 }
6159
62 fn getRegisterMask(reg: Register) ?FreeRegInt {
63 const index = indexOfRegIntoTracked(reg) orelse return null;
64 const shift = @intCast(ShiftInt, index);
65 const mask = @as(FreeRegInt, 1) << shift;
66 return mask;
67 }
68
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
7460 fn markRegAllocated(self: *Self, reg: Register) void {
75 const mask = getRegisterMask(reg) orelse return;
76 self.allocated_registers |= mask;
61 const index = indexOfRegIntoTracked(reg) orelse return;
62 self.allocated_registers.set(index);
7763 }
7864
7965 fn markRegUsed(self: *Self, reg: Register) void {
80 const mask = getRegisterMask(reg) orelse return;
81 self.free_registers &= ~mask;
66 const index = indexOfRegIntoTracked(reg) orelse return;
67 self.free_registers.unset(index);
8268 }
8369
8470 fn markRegFree(self: *Self, reg: Register) void {
85 const mask = getRegisterMask(reg) orelse return;
86 self.free_registers |= mask;
71 const index = indexOfRegIntoTracked(reg) orelse return;
72 self.free_registers.set(index);
8773 }
8874
89 pub fn indexOfReg(comptime registers: []const Register, reg: Register) ?std.math.IntFittingRange(0, registers.len - 1) {
75 pub fn indexOfReg(
76 comptime registers: []const Register,
77 reg: Register,
78 ) ?std.math.IntFittingRange(0, registers.len - 1) {
9079 inline for (tracked_registers) |cpreg, i| {
9180 if (reg.id() == cpreg.id()) return i;
9281 }
9382 return null;
9483 }
9584
96 pub fn indexOfRegIntoTracked(reg: Register) ?ShiftInt {
85 pub fn indexOfRegIntoTracked(reg: Register) ?RegisterBitSet.ShiftInt {
9786 return indexOfReg(tracked_registers, reg);
9887 }
9988
10089 /// Returns true when this register is not tracked
10190 pub fn isRegFree(self: Self, reg: Register) bool {
102 const mask = getRegisterMask(reg) orelse return true;
103 return self.free_registers & mask != 0;
91 const index = indexOfRegIntoTracked(reg) orelse return true;
92 return self.free_registers.isSet(index);
10493 }
10594
10695 /// Returns whether this register was allocated in the course
......@@ -108,16 +97,16 @@ pub fn RegisterManager(
10897 ///
10998 /// Returns false when this register is not tracked
11099 pub fn isRegAllocated(self: Self, reg: Register) bool {
111 const mask = getRegisterMask(reg) orelse return false;
112 return self.allocated_registers & mask != 0;
100 const index = indexOfRegIntoTracked(reg) orelse return false;
101 return self.allocated_registers.isSet(index);
113102 }
114103
115104 /// Returns whether this register is locked
116105 ///
117106 /// Returns false when this register is not tracked
118107 pub fn isRegLocked(self: Self, reg: Register) bool {
119 const mask = getRegisterMask(reg) orelse return false;
120 return self.locked_registers & mask != 0;
108 const index = indexOfRegIntoTracked(reg) orelse return false;
109 return self.locked_registers.isSet(index);
121110 }
122111
123112 pub const RegisterLock = struct {
......@@ -136,8 +125,8 @@ pub fn RegisterManager(
136125 log.debug(" register already locked", .{});
137126 return null;
138127 }
139 const mask = getRegisterMask(reg) orelse return null;
140 self.locked_registers |= mask;
128 const index = indexOfRegIntoTracked(reg) orelse return null;
129 self.locked_registers.set(index);
141130 return RegisterLock{ .register = reg };
142131 }
143132
......@@ -146,8 +135,8 @@ pub fn RegisterManager(
146135 pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
147136 log.debug("locking asserting free {}", .{reg});
148137 assert(!self.isRegLocked(reg));
149 const mask = getRegisterMask(reg) orelse unreachable;
150 self.locked_registers |= mask;
138 const index = indexOfRegIntoTracked(reg) orelse unreachable;
139 self.locked_registers.set(index);
151140 return RegisterLock{ .register = reg };
152141 }
153142
......@@ -169,17 +158,17 @@ pub fn RegisterManager(
169158 /// Call `lockReg` to obtain the lock first.
170159 pub fn unlockReg(self: *Self, lock: RegisterLock) void {
171160 log.debug("unlocking {}", .{lock.register});
172 const mask = getRegisterMask(lock.register) orelse return;
173 self.locked_registers &= ~mask;
161 const index = indexOfRegIntoTracked(lock.register) orelse return;
162 self.locked_registers.unset(index);
174163 }
175164
176165 /// Returns true when at least one register is locked
177166 pub fn lockedRegsExist(self: Self) bool {
178 return self.locked_registers != 0;
167 return self.locked_registers.count() > 0;
179168 }
180169
181170 const AllocOpts = struct {
182 selector_mask: ?FreeRegInt = null,
171 selector_mask: ?RegisterBitSet = null,
183172 };
184173
185174 /// Allocates a specified number of registers, optionally
......@@ -193,17 +182,22 @@ pub fn RegisterManager(
193182 ) ?[count]Register {
194183 comptime assert(count > 0 and count <= tracked_registers.len);
195184
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;
199 const free_and_not_locked_registers_count = @popCount(FreeRegInt, free_and_not_locked_registers);
200 if (free_and_not_locked_registers_count < count) return null;
185 const available_registers = opts.selector_mask orelse RegisterBitSet.initFull();
186
187 var free_and_not_locked_registers = self.free_registers;
188 free_and_not_locked_registers.setIntersection(available_registers);
189
190 var unlocked_registers = self.locked_registers;
191 unlocked_registers.toggleAll();
192
193 free_and_not_locked_registers.setIntersection(unlocked_registers);
194
195 if (free_and_not_locked_registers.count() < count) return null;
201196
202197 var regs: [count]Register = undefined;
203198 var i: usize = 0;
204199 for (tracked_registers) |reg| {
205200 if (i >= count) break;
206 if (excludeRegister(reg, selector_mask)) continue;
207201 if (self.isRegLocked(reg)) continue;
208202 if (!self.isRegFree(reg)) continue;
209203
......@@ -244,11 +238,12 @@ pub fn RegisterManager(
244238 ) AllocateRegistersError![count]Register {
245239 comptime assert(count > 0 and count <= tracked_registers.len);
246240
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;
241 const available_registers = opts.selector_mask orelse RegisterBitSet.initFull();
242
243 var locked_registers = self.locked_registers;
244 locked_registers.setIntersection(available_registers);
245
246 if (count > available_registers.count() - locked_registers.count()) return error.OutOfRegisters;
252247
253248 const result = self.tryAllocRegs(count, insts, opts) orelse blk: {
254249 // We'll take over the first count registers. Spill
......@@ -258,7 +253,6 @@ pub fn RegisterManager(
258253 var i: usize = 0;
259254 for (tracked_registers) |reg| {
260255 if (i >= count) break;
261 if (excludeRegister(reg, selector_mask)) continue;
262256 if (self.isRegLocked(reg)) continue;
263257
264258 regs[i] = reg;