authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-20 00:04:56+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-20 07:36:15+02:00
log0e43d007c098837d1863f2dab80b99e95910e0aa
tree96afa09c9d18c96d2183591b3be7e0fb9688b422
parente95dfac03eea942b53bbdf6117a716aaeba5eb4b

regalloc: temporarily nerf back to raw ints until stage2 catches up


6 files changed, 439 insertions(+), 89 deletions(-)

src/arch/aarch64/abi.zig+11-8
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const std = @import("std");
1const builtin = @import("builtin");2const builtin = @import("builtin");
2const bits = @import("bits.zig");3const bits = @import("bits.zig");
3const Register = bits.Register;4const Register = bits.Register;
...@@ -26,12 +27,14 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,...@@ -26,12 +27,14 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
26// Register classes27// Register classes
27const RegisterBitSet = RegisterManager.RegisterBitSet;28const RegisterBitSet = RegisterManager.RegisterBitSet;
28pub const RegisterClass = struct {29pub const RegisterClass = struct {
29 pub const gp: RegisterBitSet = blk: {30 pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);
30 var set = RegisterBitSet.initEmpty();31 // TODO uncomment once #11680 is fixed.
31 set.setRangeValue(.{32 // pub const gp: RegisterBitSet = blk: {
32 .start = 0,33 // var set = RegisterBitSet.initEmpty();
33 .end = callee_preserved_regs.len,34 // set.setRangeValue(.{
34 }, true);35 // .start = 0,
35 break :blk set;36 // .end = callee_preserved_regs.len,
36 };37 // }, true);
38 // break :blk set;
39 // };
37};40};
src/arch/arm/abi.zig+11-8
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const std = @import("std");
1const bits = @import("bits.zig");2const bits = @import("bits.zig");
2const Register = bits.Register;3const Register = bits.Register;
3const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
...@@ -14,12 +15,14 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,...@@ -14,12 +15,14 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
14// Register classes15// Register classes
15const RegisterBitSet = RegisterManager.RegisterBitSet;16const RegisterBitSet = RegisterManager.RegisterBitSet;
16pub const RegisterClass = struct {17pub const RegisterClass = struct {
17 pub const gp: RegisterBitSet = blk: {18 pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);
18 var set = RegisterBitSet.initEmpty();19 // TODO uncomment once #11680 is fixed.
19 set.setRangeValue(.{20 // pub const gp: RegisterBitSet = blk: {
20 .start = 0,21 // var set = RegisterBitSet.initEmpty();
21 .end = caller_preserved_regs.len + callee_preserved_regs.len,22 // set.setRangeValue(.{
22 }, true);23 // .start = 0,
23 break :blk set;24 // .end = caller_preserved_regs.len + callee_preserved_regs.len,
24 };25 // }, true);
26 // break :blk set;
27 // };
25};28};
src/arch/riscv64/abi.zig+11-8
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const std = @import("std");
1const bits = @import("bits.zig");2const bits = @import("bits.zig");
2const Register = bits.Register;3const Register = bits.Register;
3const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
...@@ -12,12 +13,14 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,...@@ -12,12 +13,14 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
12// Register classes13// Register classes
13const RegisterBitSet = RegisterManager.RegisterBitSet;14const RegisterBitSet = RegisterManager.RegisterBitSet;
14pub const RegisterClass = struct {15pub const RegisterClass = struct {
15 pub const gp: RegisterBitSet = blk: {16 pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);
16 var set = RegisterBitSet.initEmpty();17 // TODO uncomment once #11680 is fixed.
17 set.setRangeValue(.{18 // pub const gp: RegisterBitSet = blk: {
18 .start = 0,19 // var set = RegisterBitSet.initEmpty();
19 .end = callee_preserved_regs.len,20 // set.setRangeValue(.{
20 }, true);21 // .start = 0,
21 break :blk set;22 // .end = callee_preserved_regs.len,
22 };23 // }, true);
24 // break :blk set;
25 // };
23};26};
src/arch/sparc64/abi.zig+11-8
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const std = @import("std");
1const bits = @import("bits.zig");2const bits = @import("bits.zig");
2const Register = bits.Register;3const Register = bits.Register;
3const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
...@@ -42,12 +43,14 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,...@@ -42,12 +43,14 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
42// Register classes43// Register classes
43const RegisterBitSet = RegisterManager.RegisterBitSet;44const RegisterBitSet = RegisterManager.RegisterBitSet;
44pub const RegisterClass = struct {45pub const RegisterClass = struct {
45 pub const gp: RegisterBitSet = blk: {46 pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);
46 var set = RegisterBitSet.initEmpty();47 // TODO uncomment once #11680 is fixed.
47 set.setRangeValue(.{48 // pub const gp: RegisterBitSet = blk: {
48 .start = 0,49 // var set = RegisterBitSet.initEmpty();
49 .end = allocatable_regs.len,50 // set.setRangeValue(.{
50 }, true);51 // .start = 0,
51 break :blk set;52 // .end = allocatable_regs.len,
52 };53 // }, true);
54 // break :blk set;
55 // };
53};56};
src/arch/x86_64/abi.zig+22-16
...@@ -393,20 +393,26 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,...@@ -393,20 +393,26 @@ 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 = blk: {396 pub const gp: RegisterBitSet = @as(RegisterBitSet, std.math.maxInt(std.meta.Int(
397 var set = RegisterBitSet.initEmpty();397 .unsigned,
398 set.setRangeValue(.{398 caller_preserved_regs.len + callee_preserved_regs.len,
399 .start = 0,399 )));
400 .end = caller_preserved_regs.len + callee_preserved_regs.len,400 pub const sse: RegisterBitSet = std.math.maxInt(RegisterBitSet) - gp;
401 }, true);401 // TODO uncomment once #11680 is fixed.
402 break :blk set;402 // pub const gp: RegisterBitSet = blk: {
403 };403 // var set = RegisterBitSet.initEmpty();
404 pub const sse: RegisterBitSet = blk: {404 // set.setRangeValue(.{
405 var set = RegisterBitSet.initEmpty();405 // .start = 0,
406 set.setRangeValue(.{406 // .end = caller_preserved_regs.len + callee_preserved_regs.len,
407 .start = caller_preserved_regs.len + callee_preserved_regs.len,407 // }, true);
408 .end = allocatable_registers.len,408 // break :blk set;
409 }, true);409 // };
410 break :blk set;410 // pub const sse: RegisterBitSet = blk: {
411 };411 // var set = RegisterBitSet.initEmpty();
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 // };
412};418};
src/register_manager.zig+373-41
...@@ -4,7 +4,6 @@ const mem = std.mem;...@@ -4,7 +4,6 @@ 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;
8const Type = @import("type.zig").Type;7const Type = @import("type.zig").Type;
9const Module = @import("Module.zig");8const Module = @import("Module.zig");
10const expect = std.testing.expect;9const expect = std.testing.expect;
...@@ -42,39 +41,49 @@ pub fn RegisterManager(...@@ -42,39 +41,49 @@ pub fn RegisterManager(
42 registers: [tracked_registers.len]Air.Inst.Index = undefined,41 registers: [tracked_registers.len]Air.Inst.Index = undefined,
43 /// Tracks which registers are free (in which case the42 /// Tracks which registers are free (in which case the
44 /// corresponding bit is set to 1)43 /// corresponding bit is set to 1)
45 free_registers: RegisterBitSet = RegisterBitSet.initFull(),44 free_registers: RegisterBitSet = math.maxInt(RegisterBitSet),
46 /// Tracks all registers allocated in the course of this45 /// Tracks all registers allocated in the course of this
47 /// function46 /// function
48 allocated_registers: RegisterBitSet = RegisterBitSet.initEmpty(),47 allocated_registers: RegisterBitSet = 0,
49 /// Tracks registers which are locked from being allocated48 /// Tracks registers which are locked from being allocated
50 locked_registers: RegisterBitSet = RegisterBitSet.initEmpty(),49 locked_registers: RegisterBitSet = 0,
5150
52 const Self = @This();51 const Self = @This();
5352
54 pub const RegisterBitSet = StaticBitSet(tracked_registers.len);53 /// An integer whose bits represent all the registers and
54 /// whether they are free.
55 pub const RegisterBitSet = std.meta.Int(.unsigned, tracked_registers.len);
56 const ShiftInt = math.Log2Int(RegisterBitSet);
5557
56 fn getFunction(self: *Self) *Function {58 fn getFunction(self: *Self) *Function {
57 return @fieldParentPtr(Function, "register_manager", self);59 return @fieldParentPtr(Function, "register_manager", self);
58 }60 }
5961
60 fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool {62 fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool {
61 const index = indexOfRegIntoTracked(reg) orelse return true;63 const mask = getRegisterMask(reg) orelse return true;
62 return !register_class.isSet(index);64 return mask & register_class == 0;
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;
63 }72 }
6473
65 fn markRegAllocated(self: *Self, reg: Register) void {74 fn markRegAllocated(self: *Self, reg: Register) void {
66 const index = indexOfRegIntoTracked(reg) orelse return;75 const mask = getRegisterMask(reg) orelse return;
67 self.allocated_registers.set(index);76 self.allocated_registers |= mask;
68 }77 }
6978
70 fn markRegUsed(self: *Self, reg: Register) void {79 fn markRegUsed(self: *Self, reg: Register) void {
71 const index = indexOfRegIntoTracked(reg) orelse return;80 const mask = getRegisterMask(reg) orelse return;
72 self.free_registers.unset(index);81 self.free_registers &= ~mask;
73 }82 }
7483
75 fn markRegFree(self: *Self, reg: Register) void {84 fn markRegFree(self: *Self, reg: Register) void {
76 const index = indexOfRegIntoTracked(reg) orelse return;85 const mask = getRegisterMask(reg) orelse return;
77 self.free_registers.set(index);86 self.free_registers |= mask;
78 }87 }
7988
80 pub fn indexOfReg(89 pub fn indexOfReg(
...@@ -87,14 +96,14 @@ pub fn RegisterManager(...@@ -87,14 +96,14 @@ pub fn RegisterManager(
87 return null;96 return null;
88 }97 }
8998
90 pub fn indexOfRegIntoTracked(reg: Register) ?RegisterBitSet.ShiftInt {99 pub fn indexOfRegIntoTracked(reg: Register) ?ShiftInt {
91 return indexOfReg(tracked_registers, reg);100 return indexOfReg(tracked_registers, reg);
92 }101 }
93102
94 /// Returns true when this register is not tracked103 /// Returns true when this register is not tracked
95 pub fn isRegFree(self: Self, reg: Register) bool {104 pub fn isRegFree(self: Self, reg: Register) bool {
96 const index = indexOfRegIntoTracked(reg) orelse return true;105 const mask = getRegisterMask(reg) orelse return true;
97 return self.free_registers.isSet(index);106 return self.free_registers & mask != 0;
98 }107 }
99108
100 /// Returns whether this register was allocated in the course109 /// Returns whether this register was allocated in the course
...@@ -102,16 +111,16 @@ pub fn RegisterManager(...@@ -102,16 +111,16 @@ pub fn RegisterManager(
102 ///111 ///
103 /// Returns false when this register is not tracked112 /// Returns false when this register is not tracked
104 pub fn isRegAllocated(self: Self, reg: Register) bool {113 pub fn isRegAllocated(self: Self, reg: Register) bool {
105 const index = indexOfRegIntoTracked(reg) orelse return false;114 const mask = getRegisterMask(reg) orelse return false;
106 return self.allocated_registers.isSet(index);115 return self.allocated_registers & mask != 0;
107 }116 }
108117
109 /// Returns whether this register is locked118 /// Returns whether this register is locked
110 ///119 ///
111 /// Returns false when this register is not tracked120 /// Returns false when this register is not tracked
112 pub fn isRegLocked(self: Self, reg: Register) bool {121 pub fn isRegLocked(self: Self, reg: Register) bool {
113 const index = indexOfRegIntoTracked(reg) orelse return false;122 const mask = getRegisterMask(reg) orelse return false;
114 return self.locked_registers.isSet(index);123 return self.locked_registers & mask != 0;
115 }124 }
116125
117 pub const RegisterLock = struct {126 pub const RegisterLock = struct {
...@@ -130,8 +139,8 @@ pub fn RegisterManager(...@@ -130,8 +139,8 @@ pub fn RegisterManager(
130 log.debug(" register already locked", .{});139 log.debug(" register already locked", .{});
131 return null;140 return null;
132 }141 }
133 const index = indexOfRegIntoTracked(reg) orelse return null;142 const mask = getRegisterMask(reg) orelse return null;
134 self.locked_registers.set(index);143 self.locked_registers |= mask;
135 return RegisterLock{ .register = reg };144 return RegisterLock{ .register = reg };
136 }145 }
137146
...@@ -140,8 +149,8 @@ pub fn RegisterManager(...@@ -140,8 +149,8 @@ pub fn RegisterManager(
140 pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {149 pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
141 log.debug("locking asserting free {}", .{reg});150 log.debug("locking asserting free {}", .{reg});
142 assert(!self.isRegLocked(reg));151 assert(!self.isRegLocked(reg));
143 const index = indexOfRegIntoTracked(reg) orelse unreachable;152 const mask = getRegisterMask(reg) orelse unreachable;
144 self.locked_registers.set(index);153 self.locked_registers |= mask;
145 return RegisterLock{ .register = reg };154 return RegisterLock{ .register = reg };
146 }155 }
147156
...@@ -163,13 +172,13 @@ pub fn RegisterManager(...@@ -163,13 +172,13 @@ pub fn RegisterManager(
163 /// Call `lockReg` to obtain the lock first.172 /// Call `lockReg` to obtain the lock first.
164 pub fn unlockReg(self: *Self, lock: RegisterLock) void {173 pub fn unlockReg(self: *Self, lock: RegisterLock) void {
165 log.debug("unlocking {}", .{lock.register});174 log.debug("unlocking {}", .{lock.register});
166 const index = indexOfRegIntoTracked(lock.register) orelse return;175 const mask = getRegisterMask(lock.register) orelse return;
167 self.locked_registers.unset(index);176 self.locked_registers &= ~mask;
168 }177 }
169178
170 /// Returns true when at least one register is locked179 /// Returns true when at least one register is locked
171 pub fn lockedRegsExist(self: Self) bool {180 pub fn lockedRegsExist(self: Self) bool {
172 return self.locked_registers.count() > 0;181 return self.locked_registers != 0;
173 }182 }
174183
175 /// Allocates a specified number of registers, optionally184 /// Allocates a specified number of registers, optionally
...@@ -183,15 +192,10 @@ pub fn RegisterManager(...@@ -183,15 +192,10 @@ pub fn RegisterManager(
183 ) ?[count]Register {192 ) ?[count]Register {
184 comptime assert(count > 0 and count <= tracked_registers.len);193 comptime assert(count > 0 and count <= tracked_registers.len);
185194
186 var free_and_not_locked_registers = self.free_registers;195 const free_registers = self.free_registers & register_class;
187 free_and_not_locked_registers.setIntersection(register_class);196 const free_and_not_locked_registers = free_registers & ~self.locked_registers;
188197 const free_and_not_locked_registers_count = @popCount(RegisterBitSet, free_and_not_locked_registers);
189 var unlocked_registers = self.locked_registers;198 if (free_and_not_locked_registers_count < count) return null;
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;
195199
196 var regs: [count]Register = undefined;200 var regs: [count]Register = undefined;
197 var i: usize = 0;201 var i: usize = 0;
...@@ -238,10 +242,10 @@ pub fn RegisterManager(...@@ -238,10 +242,10 @@ pub fn RegisterManager(
238 ) AllocateRegistersError![count]Register {242 ) AllocateRegistersError![count]Register {
239 comptime assert(count > 0 and count <= tracked_registers.len);243 comptime assert(count > 0 and count <= tracked_registers.len);
240244
241 var locked_registers = self.locked_registers;245 const available_registers_count = @popCount(RegisterBitSet, register_class);
242 locked_registers.setIntersection(register_class);246 const locked_registers = self.locked_registers & register_class;
243247 const locked_registers_count = @popCount(RegisterBitSet, locked_registers);
244 if (count > register_class.count() - locked_registers.count()) return error.OutOfRegisters;248 if (count > available_registers_count - locked_registers_count) return error.OutOfRegisters;
245249
246 const result = self.tryAllocRegs(count, insts, register_class) orelse blk: {250 const result = self.tryAllocRegs(count, insts, register_class) orelse blk: {
247 // We'll take over the first count registers. Spill251 // We'll take over the first count registers. Spill
...@@ -348,6 +352,334 @@ pub fn RegisterManager(...@@ -348,6 +352,334 @@ pub fn RegisterManager(
348 };352 };
349}353}
350354
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
351const MockRegister1 = enum(u2) {683const MockRegister1 = enum(u2) {
352 r0,684 r0,
353 r1,685 r1,
...@@ -384,7 +716,7 @@ fn MockFunction(comptime Register: type) type {...@@ -384,7 +716,7 @@ fn MockFunction(comptime Register: type) type {
384716
385 const RegisterManagerT = RegisterManager(Self, Register, &Register.allocatable_registers);717 const RegisterManagerT = RegisterManager(Self, Register, &Register.allocatable_registers);
386718
387 pub const reg_class: RegisterManagerT.RegisterBitSet = RegisterManagerT.RegisterBitSet.initFull();719 pub const reg_class: RegisterManagerT.RegisterBitSet = math.maxInt(RegisterManagerT.RegisterBitSet);
388720
389 pub fn deinit(self: *Self) void {721 pub fn deinit(self: *Self) void {
390 self.spilled.deinit(self.allocator);722 self.spilled.deinit(self.allocator);