mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
regalloc: use StaticBitSet internally
This commit is contained in:
parent
ab88165326
commit
0e0b00fd48
@ -27,14 +27,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
|
||||
// Register classes
|
||||
const RegisterBitSet = RegisterManager.RegisterBitSet;
|
||||
pub const RegisterClass = struct {
|
||||
pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);
|
||||
// TODO uncomment once #11680 is fixed.
|
||||
// pub const gp: RegisterBitSet = blk: {
|
||||
// var set = RegisterBitSet.initEmpty();
|
||||
// set.setRangeValue(.{
|
||||
// .start = 0,
|
||||
// .end = callee_preserved_regs.len,
|
||||
// }, true);
|
||||
// break :blk set;
|
||||
// };
|
||||
pub const gp: RegisterBitSet = blk: {
|
||||
var set = RegisterBitSet.initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = callee_preserved_regs.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
};
|
||||
|
||||
@ -15,14 +15,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
|
||||
// Register classes
|
||||
const RegisterBitSet = RegisterManager.RegisterBitSet;
|
||||
pub const RegisterClass = struct {
|
||||
pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);
|
||||
// TODO uncomment once #11680 is fixed.
|
||||
// pub const gp: RegisterBitSet = blk: {
|
||||
// var set = RegisterBitSet.initEmpty();
|
||||
// set.setRangeValue(.{
|
||||
// .start = 0,
|
||||
// .end = caller_preserved_regs.len + callee_preserved_regs.len,
|
||||
// }, true);
|
||||
// break :blk set;
|
||||
// };
|
||||
pub const gp: RegisterBitSet = blk: {
|
||||
var set = RegisterBitSet.initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = caller_preserved_regs.len + callee_preserved_regs.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
};
|
||||
|
||||
@ -13,14 +13,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
|
||||
// Register classes
|
||||
const RegisterBitSet = RegisterManager.RegisterBitSet;
|
||||
pub const RegisterClass = struct {
|
||||
pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);
|
||||
// TODO uncomment once #11680 is fixed.
|
||||
// pub const gp: RegisterBitSet = blk: {
|
||||
// var set = RegisterBitSet.initEmpty();
|
||||
// set.setRangeValue(.{
|
||||
// .start = 0,
|
||||
// .end = callee_preserved_regs.len,
|
||||
// }, true);
|
||||
// break :blk set;
|
||||
// };
|
||||
pub const gp: RegisterBitSet = blk: {
|
||||
var set = RegisterBitSet.initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = callee_preserved_regs.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
};
|
||||
|
||||
@ -43,14 +43,12 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
|
||||
// Register classes
|
||||
const RegisterBitSet = RegisterManager.RegisterBitSet;
|
||||
pub const RegisterClass = struct {
|
||||
pub const gp: RegisterBitSet = std.math.maxInt(RegisterBitSet);
|
||||
// TODO uncomment once #11680 is fixed.
|
||||
// pub const gp: RegisterBitSet = blk: {
|
||||
// var set = RegisterBitSet.initEmpty();
|
||||
// set.setRangeValue(.{
|
||||
// .start = 0,
|
||||
// .end = allocatable_regs.len,
|
||||
// }, true);
|
||||
// break :blk set;
|
||||
// };
|
||||
pub const gp: RegisterBitSet = blk: {
|
||||
var set = RegisterBitSet.initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = allocatable_regs.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
};
|
||||
|
||||
@ -393,26 +393,20 @@ pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register,
|
||||
// Register classes
|
||||
const RegisterBitSet = RegisterManager.RegisterBitSet;
|
||||
pub const RegisterClass = struct {
|
||||
pub const gp: RegisterBitSet = @as(RegisterBitSet, std.math.maxInt(std.meta.Int(
|
||||
.unsigned,
|
||||
caller_preserved_regs.len + callee_preserved_regs.len,
|
||||
)));
|
||||
pub const sse: RegisterBitSet = std.math.maxInt(RegisterBitSet) - gp;
|
||||
// TODO uncomment once #11680 is fixed.
|
||||
// pub const gp: RegisterBitSet = blk: {
|
||||
// var set = RegisterBitSet.initEmpty();
|
||||
// set.setRangeValue(.{
|
||||
// .start = 0,
|
||||
// .end = caller_preserved_regs.len + callee_preserved_regs.len,
|
||||
// }, true);
|
||||
// break :blk set;
|
||||
// };
|
||||
// pub const sse: RegisterBitSet = blk: {
|
||||
// var set = RegisterBitSet.initEmpty();
|
||||
// set.setRangeValue(.{
|
||||
// .start = caller_preserved_regs.len + callee_preserved_regs.len,
|
||||
// .end = allocatable_registers.len,
|
||||
// }, true);
|
||||
// break :blk set;
|
||||
// };
|
||||
pub const gp: RegisterBitSet = blk: {
|
||||
var set = RegisterBitSet.initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = caller_preserved_regs.len + callee_preserved_regs.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
pub const sse: RegisterBitSet = blk: {
|
||||
var set = RegisterBitSet.initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = caller_preserved_regs.len + callee_preserved_regs.len,
|
||||
.end = allocatable_registers.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
};
|
||||
|
||||
@ -4,6 +4,7 @@ const mem = std.mem;
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Air = @import("Air.zig");
|
||||
const StaticBitSet = std.bit_set.StaticBitSet;
|
||||
const Type = @import("type.zig").Type;
|
||||
const Module = @import("Module.zig");
|
||||
const expect = std.testing.expect;
|
||||
@ -41,49 +42,39 @@ pub fn RegisterManager(
|
||||
registers: [tracked_registers.len]Air.Inst.Index = undefined,
|
||||
/// Tracks which registers are free (in which case the
|
||||
/// corresponding bit is set to 1)
|
||||
free_registers: RegisterBitSet = math.maxInt(RegisterBitSet),
|
||||
free_registers: RegisterBitSet = RegisterBitSet.initFull(),
|
||||
/// Tracks all registers allocated in the course of this
|
||||
/// function
|
||||
allocated_registers: RegisterBitSet = 0,
|
||||
allocated_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
|
||||
/// Tracks registers which are locked from being allocated
|
||||
locked_registers: RegisterBitSet = 0,
|
||||
locked_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
|
||||
|
||||
const Self = @This();
|
||||
|
||||
/// An integer whose bits represent all the registers and
|
||||
/// whether they are free.
|
||||
pub const RegisterBitSet = std.meta.Int(.unsigned, tracked_registers.len);
|
||||
const ShiftInt = math.Log2Int(RegisterBitSet);
|
||||
pub const RegisterBitSet = StaticBitSet(tracked_registers.len);
|
||||
|
||||
fn getFunction(self: *Self) *Function {
|
||||
return @fieldParentPtr(Function, "register_manager", self);
|
||||
}
|
||||
|
||||
fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool {
|
||||
const mask = getRegisterMask(reg) orelse return true;
|
||||
return mask & register_class == 0;
|
||||
}
|
||||
|
||||
fn getRegisterMask(reg: Register) ?RegisterBitSet {
|
||||
const index = indexOfRegIntoTracked(reg) orelse return null;
|
||||
const shift = @intCast(ShiftInt, index);
|
||||
const mask = @as(RegisterBitSet, 1) << shift;
|
||||
return mask;
|
||||
const index = indexOfRegIntoTracked(reg) orelse return true;
|
||||
return !register_class.isSet(index);
|
||||
}
|
||||
|
||||
fn markRegAllocated(self: *Self, reg: Register) void {
|
||||
const mask = getRegisterMask(reg) orelse return;
|
||||
self.allocated_registers |= mask;
|
||||
const index = indexOfRegIntoTracked(reg) orelse return;
|
||||
self.allocated_registers.set(index);
|
||||
}
|
||||
|
||||
fn markRegUsed(self: *Self, reg: Register) void {
|
||||
const mask = getRegisterMask(reg) orelse return;
|
||||
self.free_registers &= ~mask;
|
||||
const index = indexOfRegIntoTracked(reg) orelse return;
|
||||
self.free_registers.unset(index);
|
||||
}
|
||||
|
||||
fn markRegFree(self: *Self, reg: Register) void {
|
||||
const mask = getRegisterMask(reg) orelse return;
|
||||
self.free_registers |= mask;
|
||||
const index = indexOfRegIntoTracked(reg) orelse return;
|
||||
self.free_registers.set(index);
|
||||
}
|
||||
|
||||
pub fn indexOfReg(
|
||||
@ -96,14 +87,14 @@ pub fn RegisterManager(
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn indexOfRegIntoTracked(reg: Register) ?ShiftInt {
|
||||
pub fn indexOfRegIntoTracked(reg: Register) ?RegisterBitSet.ShiftInt {
|
||||
return indexOfReg(tracked_registers, reg);
|
||||
}
|
||||
|
||||
/// Returns true when this register is not tracked
|
||||
pub fn isRegFree(self: Self, reg: Register) bool {
|
||||
const mask = getRegisterMask(reg) orelse return true;
|
||||
return self.free_registers & mask != 0;
|
||||
const index = indexOfRegIntoTracked(reg) orelse return true;
|
||||
return self.free_registers.isSet(index);
|
||||
}
|
||||
|
||||
/// Returns whether this register was allocated in the course
|
||||
@ -111,16 +102,16 @@ pub fn RegisterManager(
|
||||
///
|
||||
/// Returns false when this register is not tracked
|
||||
pub fn isRegAllocated(self: Self, reg: Register) bool {
|
||||
const mask = getRegisterMask(reg) orelse return false;
|
||||
return self.allocated_registers & mask != 0;
|
||||
const index = indexOfRegIntoTracked(reg) orelse return false;
|
||||
return self.allocated_registers.isSet(index);
|
||||
}
|
||||
|
||||
/// Returns whether this register is locked
|
||||
///
|
||||
/// Returns false when this register is not tracked
|
||||
pub fn isRegLocked(self: Self, reg: Register) bool {
|
||||
const mask = getRegisterMask(reg) orelse return false;
|
||||
return self.locked_registers & mask != 0;
|
||||
const index = indexOfRegIntoTracked(reg) orelse return false;
|
||||
return self.locked_registers.isSet(index);
|
||||
}
|
||||
|
||||
pub const RegisterLock = struct {
|
||||
@ -139,8 +130,8 @@ pub fn RegisterManager(
|
||||
log.debug(" register already locked", .{});
|
||||
return null;
|
||||
}
|
||||
const mask = getRegisterMask(reg) orelse return null;
|
||||
self.locked_registers |= mask;
|
||||
const index = indexOfRegIntoTracked(reg) orelse return null;
|
||||
self.locked_registers.set(index);
|
||||
return RegisterLock{ .register = reg };
|
||||
}
|
||||
|
||||
@ -149,8 +140,8 @@ pub fn RegisterManager(
|
||||
pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
|
||||
log.debug("locking asserting free {}", .{reg});
|
||||
assert(!self.isRegLocked(reg));
|
||||
const mask = getRegisterMask(reg) orelse unreachable;
|
||||
self.locked_registers |= mask;
|
||||
const index = indexOfRegIntoTracked(reg) orelse unreachable;
|
||||
self.locked_registers.set(index);
|
||||
return RegisterLock{ .register = reg };
|
||||
}
|
||||
|
||||
@ -172,13 +163,13 @@ pub fn RegisterManager(
|
||||
/// Call `lockReg` to obtain the lock first.
|
||||
pub fn unlockReg(self: *Self, lock: RegisterLock) void {
|
||||
log.debug("unlocking {}", .{lock.register});
|
||||
const mask = getRegisterMask(lock.register) orelse return;
|
||||
self.locked_registers &= ~mask;
|
||||
const index = indexOfRegIntoTracked(lock.register) orelse return;
|
||||
self.locked_registers.unset(index);
|
||||
}
|
||||
|
||||
/// Returns true when at least one register is locked
|
||||
pub fn lockedRegsExist(self: Self) bool {
|
||||
return self.locked_registers != 0;
|
||||
return self.locked_registers.count() > 0;
|
||||
}
|
||||
|
||||
/// Allocates a specified number of registers, optionally
|
||||
@ -192,10 +183,15 @@ pub fn RegisterManager(
|
||||
) ?[count]Register {
|
||||
comptime assert(count > 0 and count <= tracked_registers.len);
|
||||
|
||||
const free_registers = self.free_registers & register_class;
|
||||
const free_and_not_locked_registers = free_registers & ~self.locked_registers;
|
||||
const free_and_not_locked_registers_count = @popCount(RegisterBitSet, free_and_not_locked_registers);
|
||||
if (free_and_not_locked_registers_count < count) return null;
|
||||
var free_and_not_locked_registers = self.free_registers;
|
||||
free_and_not_locked_registers.setIntersection(register_class);
|
||||
|
||||
var unlocked_registers = self.locked_registers;
|
||||
unlocked_registers.toggleAll();
|
||||
|
||||
free_and_not_locked_registers.setIntersection(unlocked_registers);
|
||||
|
||||
if (free_and_not_locked_registers.count() < count) return null;
|
||||
|
||||
var regs: [count]Register = undefined;
|
||||
var i: usize = 0;
|
||||
@ -242,10 +238,10 @@ pub fn RegisterManager(
|
||||
) AllocateRegistersError![count]Register {
|
||||
comptime assert(count > 0 and count <= tracked_registers.len);
|
||||
|
||||
const available_registers_count = @popCount(RegisterBitSet, register_class);
|
||||
const locked_registers = self.locked_registers & register_class;
|
||||
const locked_registers_count = @popCount(RegisterBitSet, locked_registers);
|
||||
if (count > available_registers_count - locked_registers_count) return error.OutOfRegisters;
|
||||
var locked_registers = self.locked_registers;
|
||||
locked_registers.setIntersection(register_class);
|
||||
|
||||
if (count > register_class.count() - locked_registers.count()) return error.OutOfRegisters;
|
||||
|
||||
const result = self.tryAllocRegs(count, insts, register_class) orelse blk: {
|
||||
// We'll take over the first count registers. Spill
|
||||
@ -255,7 +251,7 @@ pub fn RegisterManager(
|
||||
var i: usize = 0;
|
||||
for (tracked_registers) |reg| {
|
||||
if (i >= count) break;
|
||||
if (excludeRegister(reg, register_class)) continue;
|
||||
if (excludeRegister(reg, register_class)) break;
|
||||
if (self.isRegLocked(reg)) continue;
|
||||
|
||||
regs[i] = reg;
|
||||
@ -352,334 +348,6 @@ pub fn RegisterManager(
|
||||
};
|
||||
}
|
||||
|
||||
// TODO delete current implementation of RegisterManager above, and uncomment the one
|
||||
// below once #11680 is fixed:
|
||||
// https://github.com/ziglang/zig/issues/11680
|
||||
|
||||
//pub fn RegisterManager(
|
||||
// comptime Function: type,
|
||||
// comptime Register: type,
|
||||
// comptime tracked_registers: []const Register,
|
||||
//) type {
|
||||
// // architectures which do not have a concept of registers should
|
||||
// // refrain from using RegisterManager
|
||||
// assert(tracked_registers.len > 0); // see note above
|
||||
|
||||
// return struct {
|
||||
// /// Tracks the AIR instruction allocated to every register. If
|
||||
// /// no instruction is allocated to a register (i.e. the
|
||||
// /// register is free), the value in that slot is undefined.
|
||||
// ///
|
||||
// /// The key must be canonical register.
|
||||
// registers: [tracked_registers.len]Air.Inst.Index = undefined,
|
||||
// /// Tracks which registers are free (in which case the
|
||||
// /// corresponding bit is set to 1)
|
||||
// free_registers: RegisterBitSet = RegisterBitSet.initFull(),
|
||||
// /// Tracks all registers allocated in the course of this
|
||||
// /// function
|
||||
// allocated_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
|
||||
// /// Tracks registers which are locked from being allocated
|
||||
// locked_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
|
||||
|
||||
// const Self = @This();
|
||||
|
||||
// pub const RegisterBitSet = StaticBitSet(tracked_registers.len);
|
||||
|
||||
// fn getFunction(self: *Self) *Function {
|
||||
// return @fieldParentPtr(Function, "register_manager", self);
|
||||
// }
|
||||
|
||||
// fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool {
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return true;
|
||||
// return !register_class.isSet(index);
|
||||
// }
|
||||
|
||||
// fn markRegAllocated(self: *Self, reg: Register) void {
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return;
|
||||
// self.allocated_registers.set(index);
|
||||
// }
|
||||
|
||||
// fn markRegUsed(self: *Self, reg: Register) void {
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return;
|
||||
// self.free_registers.unset(index);
|
||||
// }
|
||||
|
||||
// fn markRegFree(self: *Self, reg: Register) void {
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return;
|
||||
// self.free_registers.set(index);
|
||||
// }
|
||||
|
||||
// pub fn indexOfReg(
|
||||
// comptime registers: []const Register,
|
||||
// reg: Register,
|
||||
// ) ?std.math.IntFittingRange(0, registers.len - 1) {
|
||||
// inline for (tracked_registers) |cpreg, i| {
|
||||
// if (reg.id() == cpreg.id()) return i;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// pub fn indexOfRegIntoTracked(reg: Register) ?RegisterBitSet.ShiftInt {
|
||||
// return indexOfReg(tracked_registers, reg);
|
||||
// }
|
||||
|
||||
// /// Returns true when this register is not tracked
|
||||
// pub fn isRegFree(self: Self, reg: Register) bool {
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return true;
|
||||
// return self.free_registers.isSet(index);
|
||||
// }
|
||||
|
||||
// /// Returns whether this register was allocated in the course
|
||||
// /// of this function.
|
||||
// ///
|
||||
// /// Returns false when this register is not tracked
|
||||
// pub fn isRegAllocated(self: Self, reg: Register) bool {
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return false;
|
||||
// return self.allocated_registers.isSet(index);
|
||||
// }
|
||||
|
||||
// /// Returns whether this register is locked
|
||||
// ///
|
||||
// /// Returns false when this register is not tracked
|
||||
// pub fn isRegLocked(self: Self, reg: Register) bool {
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return false;
|
||||
// return self.locked_registers.isSet(index);
|
||||
// }
|
||||
|
||||
// pub const RegisterLock = struct {
|
||||
// register: Register,
|
||||
// };
|
||||
|
||||
// /// Prevents the register from being allocated until they are
|
||||
// /// unlocked again.
|
||||
// /// Returns `RegisterLock` if the register was not already
|
||||
// /// locked, or `null` otherwise.
|
||||
// /// Only the owner of the `RegisterLock` can unlock the
|
||||
// /// register later.
|
||||
// pub fn lockReg(self: *Self, reg: Register) ?RegisterLock {
|
||||
// log.debug("locking {}", .{reg});
|
||||
// if (self.isRegLocked(reg)) {
|
||||
// log.debug(" register already locked", .{});
|
||||
// return null;
|
||||
// }
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return null;
|
||||
// self.locked_registers.set(index);
|
||||
// return RegisterLock{ .register = reg };
|
||||
// }
|
||||
|
||||
// /// Like `lockReg` but asserts the register was unused always
|
||||
// /// returning a valid lock.
|
||||
// pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
|
||||
// log.debug("locking asserting free {}", .{reg});
|
||||
// assert(!self.isRegLocked(reg));
|
||||
// const index = indexOfRegIntoTracked(reg) orelse unreachable;
|
||||
// self.locked_registers.set(index);
|
||||
// return RegisterLock{ .register = reg };
|
||||
// }
|
||||
|
||||
// /// Like `lockRegAssumeUnused` but locks multiple registers.
|
||||
// pub fn lockRegsAssumeUnused(
|
||||
// self: *Self,
|
||||
// comptime count: comptime_int,
|
||||
// regs: [count]Register,
|
||||
// ) [count]RegisterLock {
|
||||
// var buf: [count]RegisterLock = undefined;
|
||||
// for (regs) |reg, i| {
|
||||
// buf[i] = self.lockRegAssumeUnused(reg);
|
||||
// }
|
||||
// return buf;
|
||||
// }
|
||||
|
||||
// /// Unlocks the register allowing its re-allocation and re-use.
|
||||
// /// Requires `RegisterLock` to unlock a register.
|
||||
// /// Call `lockReg` to obtain the lock first.
|
||||
// pub fn unlockReg(self: *Self, lock: RegisterLock) void {
|
||||
// log.debug("unlocking {}", .{lock.register});
|
||||
// const index = indexOfRegIntoTracked(lock.register) orelse return;
|
||||
// self.locked_registers.unset(index);
|
||||
// }
|
||||
|
||||
// /// Returns true when at least one register is locked
|
||||
// pub fn lockedRegsExist(self: Self) bool {
|
||||
// return self.locked_registers.count() > 0;
|
||||
// }
|
||||
|
||||
// /// Allocates a specified number of registers, optionally
|
||||
// /// tracking them. Returns `null` if not enough registers are
|
||||
// /// free.
|
||||
// pub fn tryAllocRegs(
|
||||
// self: *Self,
|
||||
// comptime count: comptime_int,
|
||||
// insts: [count]?Air.Inst.Index,
|
||||
// register_class: RegisterBitSet,
|
||||
// ) ?[count]Register {
|
||||
// comptime assert(count > 0 and count <= tracked_registers.len);
|
||||
|
||||
// var free_and_not_locked_registers = self.free_registers;
|
||||
// free_and_not_locked_registers.setIntersection(register_class);
|
||||
|
||||
// var unlocked_registers = self.locked_registers;
|
||||
// unlocked_registers.toggleAll();
|
||||
|
||||
// free_and_not_locked_registers.setIntersection(unlocked_registers);
|
||||
|
||||
// if (free_and_not_locked_registers.count() < count) return null;
|
||||
|
||||
// var regs: [count]Register = undefined;
|
||||
// var i: usize = 0;
|
||||
// for (tracked_registers) |reg| {
|
||||
// if (i >= count) break;
|
||||
// if (excludeRegister(reg, register_class)) continue;
|
||||
// if (self.isRegLocked(reg)) continue;
|
||||
// if (!self.isRegFree(reg)) continue;
|
||||
|
||||
// regs[i] = reg;
|
||||
// i += 1;
|
||||
// }
|
||||
// assert(i == count);
|
||||
|
||||
// for (regs) |reg, j| {
|
||||
// self.markRegAllocated(reg);
|
||||
|
||||
// if (insts[j]) |inst| {
|
||||
// // Track the register
|
||||
// const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
|
||||
// self.registers[index] = inst;
|
||||
// self.markRegUsed(reg);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return regs;
|
||||
// }
|
||||
|
||||
// /// Allocates a register and optionally tracks it with a
|
||||
// /// corresponding instruction. Returns `null` if all registers
|
||||
// /// are allocated.
|
||||
// pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index, register_class: RegisterBitSet) ?Register {
|
||||
// return if (tryAllocRegs(self, 1, .{inst}, register_class)) |regs| regs[0] else null;
|
||||
// }
|
||||
|
||||
// /// Allocates a specified number of registers, optionally
|
||||
// /// tracking them. Asserts that count is not
|
||||
// /// larger than the total number of registers available.
|
||||
// pub fn allocRegs(
|
||||
// self: *Self,
|
||||
// comptime count: comptime_int,
|
||||
// insts: [count]?Air.Inst.Index,
|
||||
// register_class: RegisterBitSet,
|
||||
// ) AllocateRegistersError![count]Register {
|
||||
// comptime assert(count > 0 and count <= tracked_registers.len);
|
||||
|
||||
// var locked_registers = self.locked_registers;
|
||||
// locked_registers.setIntersection(register_class);
|
||||
|
||||
// if (count > register_class.count() - locked_registers.count()) return error.OutOfRegisters;
|
||||
|
||||
// const result = self.tryAllocRegs(count, insts, register_class) orelse blk: {
|
||||
// // We'll take over the first count registers. Spill
|
||||
// // the instructions that were previously there to a
|
||||
// // stack allocations.
|
||||
// var regs: [count]Register = undefined;
|
||||
// var i: usize = 0;
|
||||
// for (tracked_registers) |reg| {
|
||||
// if (i >= count) break;
|
||||
// if (excludeRegister(reg, register_class)) break;
|
||||
// if (self.isRegLocked(reg)) continue;
|
||||
|
||||
// regs[i] = reg;
|
||||
// self.markRegAllocated(reg);
|
||||
// const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
|
||||
// if (insts[i]) |inst| {
|
||||
// // Track the register
|
||||
// if (self.isRegFree(reg)) {
|
||||
// self.markRegUsed(reg);
|
||||
// } else {
|
||||
// const spilled_inst = self.registers[index];
|
||||
// try self.getFunction().spillInstruction(reg, spilled_inst);
|
||||
// }
|
||||
// self.registers[index] = inst;
|
||||
// } else {
|
||||
// // Don't track the register
|
||||
// if (!self.isRegFree(reg)) {
|
||||
// const spilled_inst = self.registers[index];
|
||||
// try self.getFunction().spillInstruction(reg, spilled_inst);
|
||||
// self.freeReg(reg);
|
||||
// }
|
||||
// }
|
||||
|
||||
// i += 1;
|
||||
// }
|
||||
|
||||
// break :blk regs;
|
||||
// };
|
||||
|
||||
// log.debug("allocated registers {any} for insts {any}", .{ result, insts });
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// /// Allocates a register and optionally tracks it with a
|
||||
// /// corresponding instruction.
|
||||
// pub fn allocReg(
|
||||
// self: *Self,
|
||||
// inst: ?Air.Inst.Index,
|
||||
// register_class: RegisterBitSet,
|
||||
// ) AllocateRegistersError!Register {
|
||||
// return (try self.allocRegs(1, .{inst}, register_class))[0];
|
||||
// }
|
||||
|
||||
// /// Spills the register if it is currently allocated. If a
|
||||
// /// corresponding instruction is passed, will also track this
|
||||
// /// register.
|
||||
// pub fn getReg(self: *Self, reg: Register, inst: ?Air.Inst.Index) AllocateRegistersError!void {
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return;
|
||||
// log.debug("getReg {} for inst {}", .{ reg, inst });
|
||||
// self.markRegAllocated(reg);
|
||||
|
||||
// if (inst) |tracked_inst|
|
||||
// if (!self.isRegFree(reg)) {
|
||||
// // Move the instruction that was previously there to a
|
||||
// // stack allocation.
|
||||
// const spilled_inst = self.registers[index];
|
||||
// self.registers[index] = tracked_inst;
|
||||
// try self.getFunction().spillInstruction(reg, spilled_inst);
|
||||
// } else {
|
||||
// self.getRegAssumeFree(reg, tracked_inst);
|
||||
// }
|
||||
// else {
|
||||
// if (!self.isRegFree(reg)) {
|
||||
// // Move the instruction that was previously there to a
|
||||
// // stack allocation.
|
||||
// const spilled_inst = self.registers[index];
|
||||
// try self.getFunction().spillInstruction(reg, spilled_inst);
|
||||
// self.freeReg(reg);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Allocates the specified register with the specified
|
||||
// /// instruction. Asserts that the register is free and no
|
||||
// /// spilling is necessary.
|
||||
// pub fn getRegAssumeFree(self: *Self, reg: Register, inst: Air.Inst.Index) void {
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return;
|
||||
// log.debug("getRegAssumeFree {} for inst {}", .{ reg, inst });
|
||||
// self.markRegAllocated(reg);
|
||||
|
||||
// assert(self.isRegFree(reg));
|
||||
// self.registers[index] = inst;
|
||||
// self.markRegUsed(reg);
|
||||
// }
|
||||
|
||||
// /// Marks the specified register as free
|
||||
// pub fn freeReg(self: *Self, reg: Register) void {
|
||||
// const index = indexOfRegIntoTracked(reg) orelse return;
|
||||
// log.debug("freeing register {}", .{reg});
|
||||
|
||||
// self.registers[index] = undefined;
|
||||
// self.markRegFree(reg);
|
||||
// }
|
||||
// };
|
||||
//}
|
||||
|
||||
const MockRegister1 = enum(u2) {
|
||||
r0,
|
||||
r1,
|
||||
@ -698,7 +366,14 @@ const MockRegister1 = enum(u2) {
|
||||
&MockRegister1.allocatable_registers,
|
||||
);
|
||||
|
||||
const gp: RM.RegisterBitSet = std.math.maxInt(RM.RegisterBitSet);
|
||||
const gp: RM.RegisterBitSet = blk: {
|
||||
var set = RM.RegisterBitSet.initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = allocatable_registers.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
};
|
||||
|
||||
const MockRegister2 = enum(u2) {
|
||||
@ -719,7 +394,14 @@ const MockRegister2 = enum(u2) {
|
||||
&MockRegister2.allocatable_registers,
|
||||
);
|
||||
|
||||
const gp: RM.RegisterBitSet = std.math.maxInt(RM.RegisterBitSet);
|
||||
const gp: RM.RegisterBitSet = blk: {
|
||||
var set = RM.RegisterBitSet.initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = allocatable_registers.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
};
|
||||
|
||||
const MockRegister3 = enum(u3) {
|
||||
@ -753,11 +435,22 @@ const MockRegister3 = enum(u3) {
|
||||
&MockRegister3.allocatable_registers,
|
||||
);
|
||||
|
||||
const gp: RM.RegisterBitSet = @as(RM.RegisterBitSet, std.math.maxInt(std.meta.Int(
|
||||
.unsigned,
|
||||
gp_regs.len,
|
||||
)));
|
||||
const ext: RM.RegisterBitSet = std.math.maxInt(RM.RegisterBitSet) - gp;
|
||||
const gp: RM.RegisterBitSet = blk: {
|
||||
var set = RM.RegisterBitSet.initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = gp_regs.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
const ext: RM.RegisterBitSet = blk: {
|
||||
var set = RM.RegisterBitSet.initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = gp_regs.len,
|
||||
.end = allocatable_registers.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
};
|
||||
|
||||
fn MockFunction(comptime Register: type) type {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user