authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-26 09:06:42+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-26 12:05:51+02:00
log0e0b00fd48ea680f2d69207297e877f54dd9ec89
tree9baa6bd9110641ce42d4e02bbd1d054f6a70dde2
parentab88165326abfd81c5046e8c064bd6603198ed94

regalloc: use StaticBitSet internally


6 files changed, 121 insertions(+), 442 deletions(-)

src/arch/aarch64/abi.zig+8-10
...@@ -27,14 +27,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,...@@ -27,14 +27,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
27// Register classes27// Register classes
28const RegisterBitSet = RegisterManager.RegisterBitSet;28const RegisterBitSet = RegisterManager.RegisterBitSet;
29pub const RegisterClass = struct {29pub const RegisterClass = struct {
30 pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);30 pub const gp: RegisterBitSet = blk: {
31 // TODO uncomment once #11680 is fixed.31 var set = RegisterBitSet.initEmpty();
32 // pub const gp: RegisterBitSet = blk: {32 set.setRangeValue(.{
33 // var set = RegisterBitSet.initEmpty();33 .start = 0,
34 // set.setRangeValue(.{34 .end = callee_preserved_regs.len,
35 // .start = 0,35 }, true);
36 // .end = callee_preserved_regs.len,36 break :blk set;
37 // }, true);37 };
38 // break :blk set;
39 // };
40};38};
src/arch/arm/abi.zig+8-10
...@@ -15,14 +15,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,...@@ -15,14 +15,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
15// Register classes15// Register classes
16const RegisterBitSet = RegisterManager.RegisterBitSet;16const RegisterBitSet = RegisterManager.RegisterBitSet;
17pub const RegisterClass = struct {17pub const RegisterClass = struct {
18 pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);18 pub const gp: RegisterBitSet = blk: {
19 // TODO uncomment once #11680 is fixed.19 var set = RegisterBitSet.initEmpty();
20 // pub const gp: RegisterBitSet = blk: {20 set.setRangeValue(.{
21 // var set = RegisterBitSet.initEmpty();21 .start = 0,
22 // set.setRangeValue(.{22 .end = caller_preserved_regs.len + callee_preserved_regs.len,
23 // .start = 0,23 }, true);
24 // .end = caller_preserved_regs.len + callee_preserved_regs.len,24 break :blk set;
25 // }, true);25 };
26 // break :blk set;
27 // };
28};26};
src/arch/riscv64/abi.zig+8-10
...@@ -13,14 +13,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,...@@ -13,14 +13,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
13// Register classes13// Register classes
14const RegisterBitSet = RegisterManager.RegisterBitSet;14const RegisterBitSet = RegisterManager.RegisterBitSet;
15pub const RegisterClass = struct {15pub const RegisterClass = struct {
16 pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);16 pub const gp: RegisterBitSet = blk: {
17 // TODO uncomment once #11680 is fixed.17 var set = RegisterBitSet.initEmpty();
18 // pub const gp: RegisterBitSet = blk: {18 set.setRangeValue(.{
19 // var set = RegisterBitSet.initEmpty();19 .start = 0,
20 // set.setRangeValue(.{20 .end = callee_preserved_regs.len,
21 // .start = 0,21 }, true);
22 // .end = callee_preserved_regs.len,22 break :blk set;
23 // }, true);23 };
24 // break :blk set;
25 // };
26};24};
src/arch/sparc64/abi.zig+8-10
...@@ -43,14 +43,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,...@@ -43,14 +43,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
43// Register classes43// Register classes
44const RegisterBitSet = RegisterManager.RegisterBitSet;44const RegisterBitSet = RegisterManager.RegisterBitSet;
45pub const RegisterClass = struct {45pub const RegisterClass = struct {
46 pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);46 pub const gp: RegisterBitSet = blk: {
47 // TODO uncomment once #11680 is fixed.47 var set = RegisterBitSet.initEmpty();
48 // pub const gp: RegisterBitSet = blk: {48 set.setRangeValue(.{
49 // var set = RegisterBitSet.initEmpty();49 .start = 0,
50 // set.setRangeValue(.{50 .end = allocatable_regs.len,
51 // .start = 0,51 }, true);
52 // .end = allocatable_regs.len,52 break :blk set;
53 // }, true);53 };
54 // break :blk set;
55 // };
56};54};
src/arch/x86_64/abi.zig+16-22
...@@ -393,26 +393,20 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,...@@ -393,26 +393,20 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
393// Register classes393// Register classes
394const RegisterBitSet = RegisterManager.RegisterBitSet;394const RegisterBitSet = RegisterManager.RegisterBitSet;
395pub const RegisterClass = struct {395pub const RegisterClass = struct {
396 pub const gp: RegisterBitSet = @as(RegisterBitSet, std.math.maxInt(std.meta.Int(396 pub const gp: RegisterBitSet = blk: {
397 .unsigned,397 var set = RegisterBitSet.initEmpty();
398 caller_preserved_regs.len + callee_preserved_regs.len,398 set.setRangeValue(.{
399 )));399 .start = 0,
400 pub const sse: RegisterBitSet = std.math.maxInt(RegisterBitSet) - gp;400 .end = caller_preserved_regs.len + callee_preserved_regs.len,
401 // TODO uncomment once #11680 is fixed.401 }, true);
402 // pub const gp: RegisterBitSet = blk: {402 break :blk set;
403 // var set = RegisterBitSet.initEmpty();403 };
404 // set.setRangeValue(.{404 pub const sse: RegisterBitSet = blk: {
405 // .start = 0,405 var set = RegisterBitSet.initEmpty();
406 // .end = caller_preserved_regs.len + callee_preserved_regs.len,406 set.setRangeValue(.{
407 // }, true);407 .start = caller_preserved_regs.len + callee_preserved_regs.len,
408 // break :blk set;408 .end = allocatable_registers.len,
409 // };409 }, true);
410 // pub const sse: RegisterBitSet = blk: {410 break :blk set;
411 // var set = RegisterBitSet.initEmpty();411 };
412 // set.setRangeValue(.{
413 // .start = caller_preserved_regs.len + callee_preserved_regs.len,
414 // .end = allocatable_registers.len,
415 // }, true);
416 // break :blk set;
417 // };
418};412};
src/register_manager.zig+73-380
...@@ -4,6 +4,7 @@ const mem = std.mem;...@@ -4,6 +4,7 @@ const mem = std.mem;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
6const Air = @import("Air.zig");6const Air = @import("Air.zig");
7const StaticBitSet = std.bit_set.StaticBitSet;
7const Type = @import("type.zig").Type;8const Type = @import("type.zig").Type;
8const Module = @import("Module.zig");9const Module = @import("Module.zig");
9const expect = std.testing.expect;10const expect = std.testing.expect;
...@@ -41,49 +42,39 @@ pub fn RegisterManager(...@@ -41,49 +42,39 @@ pub fn RegisterManager(
41 registers: [tracked_registers.len]Air.Inst.Index = undefined,42 registers: [tracked_registers.len]Air.Inst.Index = undefined,
42 /// Tracks which registers are free (in which case the43 /// Tracks which registers are free (in which case the
43 /// corresponding bit is set to 1)44 /// corresponding bit is set to 1)
44 free_registers: RegisterBitSet = math.maxInt(RegisterBitSet),45 free_registers: RegisterBitSet = RegisterBitSet.initFull(),
45 /// Tracks all registers allocated in the course of this46 /// Tracks all registers allocated in the course of this
46 /// function47 /// function
47 allocated_registers: RegisterBitSet = 0,48 allocated_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
48 /// Tracks registers which are locked from being allocated49 /// Tracks registers which are locked from being allocated
49 locked_registers: RegisterBitSet = 0,50 locked_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
5051
51 const Self = @This();52 const Self = @This();
5253
53 /// An integer whose bits represent all the registers and54 pub const RegisterBitSet = StaticBitSet(tracked_registers.len);
54 /// whether they are free.
55 pub const RegisterBitSet = std.meta.Int(.unsigned, tracked_registers.len);
56 const ShiftInt = math.Log2Int(RegisterBitSet);
5755
58 fn getFunction(self: *Self) *Function {56 fn getFunction(self: *Self) *Function {
59 return @fieldParentPtr(Function, "register_manager", self);57 return @fieldParentPtr(Function, "register_manager", self);
60 }58 }
6159
62 fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool {60 fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool {
63 const mask = getRegisterMask(reg) orelse return true;61 const index = indexOfRegIntoTracked(reg) orelse return true;
64 return mask & register_class == 0;62 return !register_class.isSet(index);
65 }
66
67 fn getRegisterMask(reg: Register) ?RegisterBitSet {
68 const index = indexOfRegIntoTracked(reg) orelse return null;
69 const shift = @intCast(ShiftInt, index);
70 const mask = @as(RegisterBitSet, 1) << shift;
71 return mask;
72 }63 }
7364
74 fn markRegAllocated(self: *Self, reg: Register) void {65 fn markRegAllocated(self: *Self, reg: Register) void {
75 const mask = getRegisterMask(reg) orelse return;66 const index = indexOfRegIntoTracked(reg) orelse return;
76 self.allocated_registers |= mask;67 self.allocated_registers.set(index);
77 }68 }
7869
79 fn markRegUsed(self: *Self, reg: Register) void {70 fn markRegUsed(self: *Self, reg: Register) void {
80 const mask = getRegisterMask(reg) orelse return;71 const index = indexOfRegIntoTracked(reg) orelse return;
81 self.free_registers &= ~mask;72 self.free_registers.unset(index);
82 }73 }
8374
84 fn markRegFree(self: *Self, reg: Register) void {75 fn markRegFree(self: *Self, reg: Register) void {
85 const mask = getRegisterMask(reg) orelse return;76 const index = indexOfRegIntoTracked(reg) orelse return;
86 self.free_registers |= mask;77 self.free_registers.set(index);
87 }78 }
8879
89 pub fn indexOfReg(80 pub fn indexOfReg(
...@@ -96,14 +87,14 @@ pub fn RegisterManager(...@@ -96,14 +87,14 @@ pub fn RegisterManager(
96 return null;87 return null;
97 }88 }
9889
99 pub fn indexOfRegIntoTracked(reg: Register) ?ShiftInt {90 pub fn indexOfRegIntoTracked(reg: Register) ?RegisterBitSet.ShiftInt {
100 return indexOfReg(tracked_registers, reg);91 return indexOfReg(tracked_registers, reg);
101 }92 }
10293
103 /// Returns true when this register is not tracked94 /// Returns true when this register is not tracked
104 pub fn isRegFree(self: Self, reg: Register) bool {95 pub fn isRegFree(self: Self, reg: Register) bool {
105 const mask = getRegisterMask(reg) orelse return true;96 const index = indexOfRegIntoTracked(reg) orelse return true;
106 return self.free_registers & mask != 0;97 return self.free_registers.isSet(index);
107 }98 }
10899
109 /// Returns whether this register was allocated in the course100 /// Returns whether this register was allocated in the course
...@@ -111,16 +102,16 @@ pub fn RegisterManager(...@@ -111,16 +102,16 @@ pub fn RegisterManager(
111 ///102 ///
112 /// Returns false when this register is not tracked103 /// Returns false when this register is not tracked
113 pub fn isRegAllocated(self: Self, reg: Register) bool {104 pub fn isRegAllocated(self: Self, reg: Register) bool {
114 const mask = getRegisterMask(reg) orelse return false;105 const index = indexOfRegIntoTracked(reg) orelse return false;
115 return self.allocated_registers & mask != 0;106 return self.allocated_registers.isSet(index);
116 }107 }
117108
118 /// Returns whether this register is locked109 /// Returns whether this register is locked
119 ///110 ///
120 /// Returns false when this register is not tracked111 /// Returns false when this register is not tracked
121 pub fn isRegLocked(self: Self, reg: Register) bool {112 pub fn isRegLocked(self: Self, reg: Register) bool {
122 const mask = getRegisterMask(reg) orelse return false;113 const index = indexOfRegIntoTracked(reg) orelse return false;
123 return self.locked_registers & mask != 0;114 return self.locked_registers.isSet(index);
124 }115 }
125116
126 pub const RegisterLock = struct {117 pub const RegisterLock = struct {
...@@ -139,8 +130,8 @@ pub fn RegisterManager(...@@ -139,8 +130,8 @@ pub fn RegisterManager(
139 log.debug(" register already locked", .{});130 log.debug(" register already locked", .{});
140 return null;131 return null;
141 }132 }
142 const mask = getRegisterMask(reg) orelse return null;133 const index = indexOfRegIntoTracked(reg) orelse return null;
143 self.locked_registers |= mask;134 self.locked_registers.set(index);
144 return RegisterLock{ .register = reg };135 return RegisterLock{ .register = reg };
145 }136 }
146137
...@@ -149,8 +140,8 @@ pub fn RegisterManager(...@@ -149,8 +140,8 @@ pub fn RegisterManager(
149 pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {140 pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
150 log.debug("locking asserting free {}", .{reg});141 log.debug("locking asserting free {}", .{reg});
151 assert(!self.isRegLocked(reg));142 assert(!self.isRegLocked(reg));
152 const mask = getRegisterMask(reg) orelse unreachable;143 const index = indexOfRegIntoTracked(reg) orelse unreachable;
153 self.locked_registers |= mask;144 self.locked_registers.set(index);
154 return RegisterLock{ .register = reg };145 return RegisterLock{ .register = reg };
155 }146 }
156147
...@@ -172,13 +163,13 @@ pub fn RegisterManager(...@@ -172,13 +163,13 @@ pub fn RegisterManager(
172 /// Call `lockReg` to obtain the lock first.163 /// Call `lockReg` to obtain the lock first.
173 pub fn unlockReg(self: *Self, lock: RegisterLock) void {164 pub fn unlockReg(self: *Self, lock: RegisterLock) void {
174 log.debug("unlocking {}", .{lock.register});165 log.debug("unlocking {}", .{lock.register});
175 const mask = getRegisterMask(lock.register) orelse return;166 const index = indexOfRegIntoTracked(lock.register) orelse return;
176 self.locked_registers &= ~mask;167 self.locked_registers.unset(index);
177 }168 }
178169
179 /// Returns true when at least one register is locked170 /// Returns true when at least one register is locked
180 pub fn lockedRegsExist(self: Self) bool {171 pub fn lockedRegsExist(self: Self) bool {
181 return self.locked_registers != 0;172 return self.locked_registers.count() > 0;
182 }173 }
183174
184 /// Allocates a specified number of registers, optionally175 /// Allocates a specified number of registers, optionally
...@@ -192,10 +183,15 @@ pub fn RegisterManager(...@@ -192,10 +183,15 @@ pub fn RegisterManager(
192 ) ?[count]Register {183 ) ?[count]Register {
193 comptime assert(count > 0 and count <= tracked_registers.len);184 comptime assert(count > 0 and count <= tracked_registers.len);
194185
195 const free_registers = self.free_registers & register_class;186 var free_and_not_locked_registers = self.free_registers;
196 const free_and_not_locked_registers = free_registers & ~self.locked_registers;187 free_and_not_locked_registers.setIntersection(register_class);
197 const free_and_not_locked_registers_count = @popCount(RegisterBitSet, free_and_not_locked_registers);188
198 if (free_and_not_locked_registers_count < count) return null;189 var unlocked_registers = self.locked_registers;
190 unlocked_registers.toggleAll();
191
192 free_and_not_locked_registers.setIntersection(unlocked_registers);
193
194 if (free_and_not_locked_registers.count() < count) return null;
199195
200 var regs: [count]Register = undefined;196 var regs: [count]Register = undefined;
201 var i: usize = 0;197 var i: usize = 0;
...@@ -242,10 +238,10 @@ pub fn RegisterManager(...@@ -242,10 +238,10 @@ pub fn RegisterManager(
242 ) AllocateRegistersError![count]Register {238 ) AllocateRegistersError![count]Register {
243 comptime assert(count > 0 and count <= tracked_registers.len);239 comptime assert(count > 0 and count <= tracked_registers.len);
244240
245 const available_registers_count = @popCount(RegisterBitSet, register_class);241 var locked_registers = self.locked_registers;
246 const locked_registers = self.locked_registers & register_class;242 locked_registers.setIntersection(register_class);
247 const locked_registers_count = @popCount(RegisterBitSet, locked_registers);243
248 if (count > available_registers_count - locked_registers_count) return error.OutOfRegisters;244 if (count > register_class.count() - locked_registers.count()) return error.OutOfRegisters;
249245
250 const result = self.tryAllocRegs(count, insts, register_class) orelse blk: {246 const result = self.tryAllocRegs(count, insts, register_class) orelse blk: {
251 // We'll take over the first count registers. Spill247 // We'll take over the first count registers. Spill
...@@ -255,7 +251,7 @@ pub fn RegisterManager(...@@ -255,7 +251,7 @@ pub fn RegisterManager(
255 var i: usize = 0;251 var i: usize = 0;
256 for (tracked_registers) |reg| {252 for (tracked_registers) |reg| {
257 if (i >= count) break;253 if (i >= count) break;
258 if (excludeRegister(reg, register_class)) continue;254 if (excludeRegister(reg, register_class)) break;
259 if (self.isRegLocked(reg)) continue;255 if (self.isRegLocked(reg)) continue;
260256
261 regs[i] = reg;257 regs[i] = reg;
...@@ -352,334 +348,6 @@ pub fn RegisterManager(...@@ -352,334 +348,6 @@ pub fn RegisterManager(
352 };348 };
353}349}
354350
355// TODO delete current implementation of RegisterManager above, and uncomment the one
356// below once #11680 is fixed:
357// https://github.com/ziglang/zig/issues/11680
358
359//pub fn RegisterManager(
360// comptime Function: type,
361// comptime Register: type,
362// comptime tracked_registers: []const Register,
363//) type {
364// // architectures which do not have a concept of registers should
365// // refrain from using RegisterManager
366// assert(tracked_registers.len > 0); // see note above
367
368// return struct {
369// /// Tracks the AIR instruction allocated to every register. If
370// /// no instruction is allocated to a register (i.e. the
371// /// register is free), the value in that slot is undefined.
372// ///
373// /// The key must be canonical register.
374// registers: [tracked_registers.len]Air.Inst.Index = undefined,
375// /// Tracks which registers are free (in which case the
376// /// corresponding bit is set to 1)
377// free_registers: RegisterBitSet = RegisterBitSet.initFull(),
378// /// Tracks all registers allocated in the course of this
379// /// function
380// allocated_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
381// /// Tracks registers which are locked from being allocated
382// locked_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
383
384// const Self = @This();
385
386// pub const RegisterBitSet = StaticBitSet(tracked_registers.len);
387
388// fn getFunction(self: *Self) *Function {
389// return @fieldParentPtr(Function, "register_manager", self);
390// }
391
392// fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool {
393// const index = indexOfRegIntoTracked(reg) orelse return true;
394// return !register_class.isSet(index);
395// }
396
397// fn markRegAllocated(self: *Self, reg: Register) void {
398// const index = indexOfRegIntoTracked(reg) orelse return;
399// self.allocated_registers.set(index);
400// }
401
402// fn markRegUsed(self: *Self, reg: Register) void {
403// const index = indexOfRegIntoTracked(reg) orelse return;
404// self.free_registers.unset(index);
405// }
406
407// fn markRegFree(self: *Self, reg: Register) void {
408// const index = indexOfRegIntoTracked(reg) orelse return;
409// self.free_registers.set(index);
410// }
411
412// pub fn indexOfReg(
413// comptime registers: []const Register,
414// reg: Register,
415// ) ?std.math.IntFittingRange(0, registers.len - 1) {
416// inline for (tracked_registers) |cpreg, i| {
417// if (reg.id() == cpreg.id()) return i;
418// }
419// return null;
420// }
421
422// pub fn indexOfRegIntoTracked(reg: Register) ?RegisterBitSet.ShiftInt {
423// return indexOfReg(tracked_registers, reg);
424// }
425
426// /// Returns true when this register is not tracked
427// pub fn isRegFree(self: Self, reg: Register) bool {
428// const index = indexOfRegIntoTracked(reg) orelse return true;
429// return self.free_registers.isSet(index);
430// }
431
432// /// Returns whether this register was allocated in the course
433// /// of this function.
434// ///
435// /// Returns false when this register is not tracked
436// pub fn isRegAllocated(self: Self, reg: Register) bool {
437// const index = indexOfRegIntoTracked(reg) orelse return false;
438// return self.allocated_registers.isSet(index);
439// }
440
441// /// Returns whether this register is locked
442// ///
443// /// Returns false when this register is not tracked
444// pub fn isRegLocked(self: Self, reg: Register) bool {
445// const index = indexOfRegIntoTracked(reg) orelse return false;
446// return self.locked_registers.isSet(index);
447// }
448
449// pub const RegisterLock = struct {
450// register: Register,
451// };
452
453// /// Prevents the register from being allocated until they are
454// /// unlocked again.
455// /// Returns `RegisterLock` if the register was not already
456// /// locked, or `null` otherwise.
457// /// Only the owner of the `RegisterLock` can unlock the
458// /// register later.
459// pub fn lockReg(self: *Self, reg: Register) ?RegisterLock {
460// log.debug("locking {}", .{reg});
461// if (self.isRegLocked(reg)) {
462// log.debug(" register already locked", .{});
463// return null;
464// }
465// const index = indexOfRegIntoTracked(reg) orelse return null;
466// self.locked_registers.set(index);
467// return RegisterLock{ .register = reg };
468// }
469
470// /// Like `lockReg` but asserts the register was unused always
471// /// returning a valid lock.
472// pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
473// log.debug("locking asserting free {}", .{reg});
474// assert(!self.isRegLocked(reg));
475// const index = indexOfRegIntoTracked(reg) orelse unreachable;
476// self.locked_registers.set(index);
477// return RegisterLock{ .register = reg };
478// }
479
480// /// Like `lockRegAssumeUnused` but locks multiple registers.
481// pub fn lockRegsAssumeUnused(
482// self: *Self,
483// comptime count: comptime_int,
484// regs: [count]Register,
485// ) [count]RegisterLock {
486// var buf: [count]RegisterLock = undefined;
487// for (regs) |reg, i| {
488// buf[i] = self.lockRegAssumeUnused(reg);
489// }
490// return buf;
491// }
492
493// /// Unlocks the register allowing its re-allocation and re-use.
494// /// Requires `RegisterLock` to unlock a register.
495// /// Call `lockReg` to obtain the lock first.
496// pub fn unlockReg(self: *Self, lock: RegisterLock) void {
497// log.debug("unlocking {}", .{lock.register});
498// const index = indexOfRegIntoTracked(lock.register) orelse return;
499// self.locked_registers.unset(index);
500// }
501
502// /// Returns true when at least one register is locked
503// pub fn lockedRegsExist(self: Self) bool {
504// return self.locked_registers.count() > 0;
505// }
506
507// /// Allocates a specified number of registers, optionally
508// /// tracking them. Returns `null` if not enough registers are
509// /// free.
510// pub fn tryAllocRegs(
511// self: *Self,
512// comptime count: comptime_int,
513// insts: [count]?Air.Inst.Index,
514// register_class: RegisterBitSet,
515// ) ?[count]Register {
516// comptime assert(count > 0 and count <= tracked_registers.len);
517
518// var free_and_not_locked_registers = self.free_registers;
519// free_and_not_locked_registers.setIntersection(register_class);
520
521// var unlocked_registers = self.locked_registers;
522// unlocked_registers.toggleAll();
523
524// free_and_not_locked_registers.setIntersection(unlocked_registers);
525
526// if (free_and_not_locked_registers.count() < count) return null;
527
528// var regs: [count]Register = undefined;
529// var i: usize = 0;
530// for (tracked_registers) |reg| {
531// if (i >= count) break;
532// if (excludeRegister(reg, register_class)) continue;
533// if (self.isRegLocked(reg)) continue;
534// if (!self.isRegFree(reg)) continue;
535
536// regs[i] = reg;
537// i += 1;
538// }
539// assert(i == count);
540
541// for (regs) |reg, j| {
542// self.markRegAllocated(reg);
543
544// if (insts[j]) |inst| {
545// // Track the register
546// const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
547// self.registers[index] = inst;
548// self.markRegUsed(reg);
549// }
550// }
551
552// return regs;
553// }
554
555// /// Allocates a register and optionally tracks it with a
556// /// corresponding instruction. Returns `null` if all registers
557// /// are allocated.
558// pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index, register_class: RegisterBitSet) ?Register {
559// return if (tryAllocRegs(self, 1, .{inst}, register_class)) |regs| regs[0] else null;
560// }
561
562// /// Allocates a specified number of registers, optionally
563// /// tracking them. Asserts that count is not
564// /// larger than the total number of registers available.
565// pub fn allocRegs(
566// self: *Self,
567// comptime count: comptime_int,
568// insts: [count]?Air.Inst.Index,
569// register_class: RegisterBitSet,
570// ) AllocateRegistersError![count]Register {
571// comptime assert(count > 0 and count <= tracked_registers.len);
572
573// var locked_registers = self.locked_registers;
574// locked_registers.setIntersection(register_class);
575
576// if (count > register_class.count() - locked_registers.count()) return error.OutOfRegisters;
577
578// const result = self.tryAllocRegs(count, insts, register_class) orelse blk: {
579// // We'll take over the first count registers. Spill
580// // the instructions that were previously there to a
581// // stack allocations.
582// var regs: [count]Register = undefined;
583// var i: usize = 0;
584// for (tracked_registers) |reg| {
585// if (i >= count) break;
586// if (excludeRegister(reg, register_class)) break;
587// if (self.isRegLocked(reg)) continue;
588
589// regs[i] = reg;
590// self.markRegAllocated(reg);
591// const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
592// if (insts[i]) |inst| {
593// // Track the register
594// if (self.isRegFree(reg)) {
595// self.markRegUsed(reg);
596// } else {
597// const spilled_inst = self.registers[index];
598// try self.getFunction().spillInstruction(reg, spilled_inst);
599// }
600// self.registers[index] = inst;
601// } else {
602// // Don't track the register
603// if (!self.isRegFree(reg)) {
604// const spilled_inst = self.registers[index];
605// try self.getFunction().spillInstruction(reg, spilled_inst);
606// self.freeReg(reg);
607// }
608// }
609
610// i += 1;
611// }
612
613// break :blk regs;
614// };
615
616// log.debug("allocated registers {any} for insts {any}", .{ result, insts });
617// return result;
618// }
619
620// /// Allocates a register and optionally tracks it with a
621// /// corresponding instruction.
622// pub fn allocReg(
623// self: *Self,
624// inst: ?Air.Inst.Index,
625// register_class: RegisterBitSet,
626// ) AllocateRegistersError!Register {
627// return (try self.allocRegs(1, .{inst}, register_class))[0];
628// }
629
630// /// Spills the register if it is currently allocated. If a
631// /// corresponding instruction is passed, will also track this
632// /// register.
633// pub fn getReg(self: *Self, reg: Register, inst: ?Air.Inst.Index) AllocateRegistersError!void {
634// const index = indexOfRegIntoTracked(reg) orelse return;
635// log.debug("getReg {} for inst {}", .{ reg, inst });
636// self.markRegAllocated(reg);
637
638// if (inst) |tracked_inst|
639// if (!self.isRegFree(reg)) {
640// // Move the instruction that was previously there to a
641// // stack allocation.
642// const spilled_inst = self.registers[index];
643// self.registers[index] = tracked_inst;
644// try self.getFunction().spillInstruction(reg, spilled_inst);
645// } else {
646// self.getRegAssumeFree(reg, tracked_inst);
647// }
648// else {
649// if (!self.isRegFree(reg)) {
650// // Move the instruction that was previously there to a
651// // stack allocation.
652// const spilled_inst = self.registers[index];
653// try self.getFunction().spillInstruction(reg, spilled_inst);
654// self.freeReg(reg);
655// }
656// }
657// }
658
659// /// Allocates the specified register with the specified
660// /// instruction. Asserts that the register is free and no
661// /// spilling is necessary.
662// pub fn getRegAssumeFree(self: *Self, reg: Register, inst: Air.Inst.Index) void {
663// const index = indexOfRegIntoTracked(reg) orelse return;
664// log.debug("getRegAssumeFree {} for inst {}", .{ reg, inst });
665// self.markRegAllocated(reg);
666
667// assert(self.isRegFree(reg));
668// self.registers[index] = inst;
669// self.markRegUsed(reg);
670// }
671
672// /// Marks the specified register as free
673// pub fn freeReg(self: *Self, reg: Register) void {
674// const index = indexOfRegIntoTracked(reg) orelse return;
675// log.debug("freeing register {}", .{reg});
676
677// self.registers[index] = undefined;
678// self.markRegFree(reg);
679// }
680// };
681//}
682
683const MockRegister1 = enum(u2) {351const MockRegister1 = enum(u2) {
684 r0,352 r0,
685 r1,353 r1,
...@@ -698,7 +366,14 @@ const MockRegister1 = enum(u2) {...@@ -698,7 +366,14 @@ const MockRegister1 = enum(u2) {
698 &MockRegister1.allocatable_registers,366 &MockRegister1.allocatable_registers,
699 );367 );
700368
701 const gp: RM.RegisterBitSet = std.math.maxInt(RM.RegisterBitSet);369 const gp: RM.RegisterBitSet = blk: {
370 var set = RM.RegisterBitSet.initEmpty();
371 set.setRangeValue(.{
372 .start = 0,
373 .end = allocatable_registers.len,
374 }, true);
375 break :blk set;
376 };
702};377};
703378
704const MockRegister2 = enum(u2) {379const MockRegister2 = enum(u2) {
...@@ -719,7 +394,14 @@ const MockRegister2 = enum(u2) {...@@ -719,7 +394,14 @@ const MockRegister2 = enum(u2) {
719 &MockRegister2.allocatable_registers,394 &MockRegister2.allocatable_registers,
720 );395 );
721396
722 const gp: RM.RegisterBitSet = std.math.maxInt(RM.RegisterBitSet);397 const gp: RM.RegisterBitSet = blk: {
398 var set = RM.RegisterBitSet.initEmpty();
399 set.setRangeValue(.{
400 .start = 0,
401 .end = allocatable_registers.len,
402 }, true);
403 break :blk set;
404 };
723};405};
724406
725const MockRegister3 = enum(u3) {407const MockRegister3 = enum(u3) {
...@@ -753,11 +435,22 @@ const MockRegister3 = enum(u3) {...@@ -753,11 +435,22 @@ const MockRegister3 = enum(u3) {
753 &MockRegister3.allocatable_registers,435 &MockRegister3.allocatable_registers,
754 );436 );
755437
756 const gp: RM.RegisterBitSet = @as(RM.RegisterBitSet, std.math.maxInt(std.meta.Int(438 const gp: RM.RegisterBitSet = blk: {
757 .unsigned,439 var set = RM.RegisterBitSet.initEmpty();
758 gp_regs.len,440 set.setRangeValue(.{
759 )));441 .start = 0,
760 const ext: RM.RegisterBitSet = std.math.maxInt(RM.RegisterBitSet) - gp;442 .end = gp_regs.len,
443 }, true);
444 break :blk set;
445 };
446 const ext: RM.RegisterBitSet = blk: {
447 var set = RM.RegisterBitSet.initEmpty();
448 set.setRangeValue(.{
449 .start = gp_regs.len,
450 .end = allocatable_registers.len,
451 }, true);
452 break :blk set;
453 };
761};454};
762455
763fn MockFunction(comptime Register: type) type {456fn MockFunction(comptime Register: type) type {