stage2 regalloc: replace Register.allocIndex with generic indexOfReg

* callee_preserved_regs and other ABI-specific information have been
moved to the respective abi.zig files
This commit is contained in:
joachimschmidt557 2022-03-10 23:14:28 +01:00
parent 078037ab9b
commit 06058ed6f3
No known key found for this signature in database
GPG Key ID: E0B575BE2884ACC5
17 changed files with 121 additions and 150 deletions

View File

@ -597,14 +597,17 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/Mir.zig"
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/bits.zig"
"${CMAKE_SOURCE_DIR}/src/arch/aarch64/abi.zig"
"${CMAKE_SOURCE_DIR}/src/arch/arm/CodeGen.zig"
"${CMAKE_SOURCE_DIR}/src/arch/arm/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/arm/Mir.zig"
"${CMAKE_SOURCE_DIR}/src/arch/arm/bits.zig"
"${CMAKE_SOURCE_DIR}/src/arch/arm/abi.zig"
"${CMAKE_SOURCE_DIR}/src/arch/riscv64/CodeGen.zig"
"${CMAKE_SOURCE_DIR}/src/arch/riscv64/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/riscv64/Mir.zig"
"${CMAKE_SOURCE_DIR}/src/arch/riscv64/bits.zig"
"${CMAKE_SOURCE_DIR}/src/arch/riscv64/abi.zig"
"${CMAKE_SOURCE_DIR}/src/arch/wasm/CodeGen.zig"
"${CMAKE_SOURCE_DIR}/src/arch/wasm/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/wasm/Mir.zig"
@ -612,6 +615,7 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/arch/x86_64/Emit.zig"
"${CMAKE_SOURCE_DIR}/src/arch/x86_64/Mir.zig"
"${CMAKE_SOURCE_DIR}/src/arch/x86_64/bits.zig"
"${CMAKE_SOURCE_DIR}/src/arch/x86_64/abi.zig"
"${CMAKE_SOURCE_DIR}/src/clang.zig"
"${CMAKE_SOURCE_DIR}/src/clang_options.zig"
"${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"

View File

@ -21,12 +21,21 @@ const DW = std.dwarf;
const leb128 = std.leb;
const log = std.log.scoped(.codegen);
const build_options = @import("build_options");
const RegisterManager = @import("../../register_manager.zig").RegisterManager;
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs);
const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
const FnResult = @import("../../codegen.zig").FnResult;
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
const bits = @import("bits.zig");
const abi = @import("abi.zig");
const Register = bits.Register;
const Instruction = bits.Instruction;
const callee_preserved_regs = abi.callee_preserved_regs;
const c_abi_int_param_regs = abi.c_abi_int_param_regs;
const c_abi_int_return_regs = abi.c_abi_int_return_regs;
const InnerError = error{
OutOfMemory,
CodegenFail,
@ -73,7 +82,7 @@ branch_stack: *std.ArrayList(Branch),
// Key is the block instruction
blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},
register_manager: RegisterManager = .{},
/// Maps offset to what is stored there.
stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
@ -1836,7 +1845,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
.register => |reg| {
// If it's in the registers table, need to associate the register with the
// new instruction.
if (reg.allocIndex()) |index| {
if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
if (!self.register_manager.isRegFree(reg)) {
self.register_manager.registers[index] = inst;
}
@ -2475,7 +2484,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
const result: MCValue = result: {
switch (info.return_value) {
.register => |reg| {
if (Register.allocIndex(reg) == null) {
if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
// Save function return value in a callee saved register
break :result try self.copyToNewRegister(inst, info.return_value);
}
@ -4017,12 +4026,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
return error.CodegenFail;
}
const Register = @import("bits.zig").Register;
const Instruction = @import("bits.zig").Instruction;
const callee_preserved_regs = @import("bits.zig").callee_preserved_regs;
const c_abi_int_param_regs = @import("bits.zig").c_abi_int_param_regs;
const c_abi_int_return_regs = @import("bits.zig").c_abi_int_return_regs;
fn parseRegName(name: []const u8) ?Register {
if (@hasDecl(Register, "parseRegName")) {
return Register.parseRegName(name);

20
src/arch/aarch64/abi.zig Normal file
View File

@ -0,0 +1,20 @@
const builtin = @import("builtin");
const bits = @import("bits.zig");
const Register = bits.Register;
const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct {
pub const callee_preserved_regs = [_]Register{
.x20, .x21, .x22, .x23,
.x24, .x25, .x26, .x27,
.x28,
};
} else struct {
pub const callee_preserved_regs = [_]Register{
.x19, .x20, .x21, .x22, .x23,
.x24, .x25, .x26, .x27, .x28,
};
};
pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_regs;
pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };

View File

@ -72,14 +72,6 @@ pub const Register = enum(u7) {
};
}
/// Returns the index into `callee_preserved_regs`.
pub fn allocIndex(self: Register) ?u4 {
inline for (callee_preserved_regs) |cpreg, i| {
if (self.id() == cpreg.id()) return i;
}
return null;
}
pub fn dwarfLocOp(self: Register) u8 {
return @as(u8, self.enc()) + DW.OP.reg0;
}
@ -87,23 +79,6 @@ pub const Register = enum(u7) {
// zig fmt: on
const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct {
pub const callee_preserved_regs = [_]Register{
.x20, .x21, .x22, .x23,
.x24, .x25, .x26, .x27,
.x28,
};
} else struct {
pub const callee_preserved_regs = [_]Register{
.x19, .x20, .x21, .x22, .x23,
.x24, .x25, .x26, .x27, .x28,
};
};
pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_regs;
pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
test "Register.enc" {
try testing.expectEqual(@as(u5, 0), Register.x0.enc());
try testing.expectEqual(@as(u5, 0), Register.w0.enc());

View File

@ -21,12 +21,22 @@ const DW = std.dwarf;
const leb128 = std.leb;
const log = std.log.scoped(.codegen);
const build_options = @import("build_options");
const RegisterManager = @import("../../register_manager.zig").RegisterManager;
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs);
const FnResult = @import("../../codegen.zig").FnResult;
const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
const bits = @import("bits.zig");
const abi = @import("abi.zig");
const Register = bits.Register;
const Instruction = bits.Instruction;
const Condition = bits.Condition;
const callee_preserved_regs = abi.callee_preserved_regs;
const c_abi_int_param_regs = abi.c_abi_int_param_regs;
const c_abi_int_return_regs = abi.c_abi_int_return_regs;
const InnerError = error{
OutOfMemory,
CodegenFail,
@ -73,7 +83,7 @@ branch_stack: *std.ArrayList(Branch),
// Key is the block instruction
blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},
register_manager: RegisterManager = .{},
/// Maps offset to what is stored there.
stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
/// Tracks the current instruction allocated to the compare flags
@ -1561,7 +1571,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
.register => |reg| {
// If it's in the registers table, need to associate the register with the
// new instruction.
if (reg.allocIndex()) |index| {
if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
if (!self.register_manager.isRegFree(reg)) {
self.register_manager.registers[index] = inst;
}
@ -2652,7 +2662,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
const result: MCValue = result: {
switch (info.return_value) {
.register => |reg| {
if (Register.allocIndex(reg) == null) {
if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
// Save function return value in a callee saved register
break :result try self.copyToNewRegister(inst, info.return_value);
}
@ -4495,13 +4505,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
return error.CodegenFail;
}
const Register = @import("bits.zig").Register;
const Instruction = @import("bits.zig").Instruction;
const Condition = @import("bits.zig").Condition;
const callee_preserved_regs = @import("bits.zig").callee_preserved_regs;
const c_abi_int_param_regs = @import("bits.zig").c_abi_int_param_regs;
const c_abi_int_return_regs = @import("bits.zig").c_abi_int_return_regs;
fn parseRegName(name: []const u8) ?Register {
if (@hasDecl(Register, "parseRegName")) {
return Register.parseRegName(name);

6
src/arch/arm/abi.zig Normal file
View File

@ -0,0 +1,6 @@
const bits = @import("bits.zig");
const Register = bits.Register;
pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 };
pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 };
pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 };

View File

@ -162,14 +162,6 @@ pub const Register = enum(u5) {
return @truncate(u4, @enumToInt(self));
}
/// Returns the index into `callee_preserved_regs`.
pub fn allocIndex(self: Register) ?u4 {
inline for (callee_preserved_regs) |cpreg, i| {
if (self.id() == cpreg.id()) return i;
}
return null;
}
pub fn dwarfLocOp(self: Register) u8 {
return @as(u8, self.id()) + DW.OP.reg0;
}
@ -187,10 +179,6 @@ pub const Psr = enum {
spsr,
};
pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 };
pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 };
pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 };
/// Represents an instruction in the ARM instruction set architecture
pub const Instruction = union(enum) {
data_processing: packed struct {

View File

@ -21,12 +21,19 @@ const DW = std.dwarf;
const leb128 = std.leb;
const log = std.log.scoped(.codegen);
const build_options = @import("build_options");
const RegisterManager = @import("../../register_manager.zig").RegisterManager;
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs);
const FnResult = @import("../../codegen.zig").FnResult;
const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
const bits = @import("bits.zig");
const abi = @import("abi.zig");
const Register = bits.Register;
const Instruction = abi.Instruction;
const callee_preserved_regs = abi.callee_preserved_regs;
const InnerError = error{
OutOfMemory,
CodegenFail,
@ -75,7 +82,7 @@ branch_stack: *std.ArrayList(Branch),
// Key is the block instruction
blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},
register_manager: RegisterManager = .{},
/// Maps offset to what is stored there.
stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
@ -1230,7 +1237,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
.register => |reg| {
// If it's in the registers table, need to associate the register with the
// new instruction.
if (reg.allocIndex()) |index| {
if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
if (!self.register_manager.isRegFree(reg)) {
self.register_manager.registers[index] = inst;
}
@ -1545,7 +1552,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
const result: MCValue = result: {
switch (info.return_value) {
.register => |reg| {
if (Register.allocIndex(reg) == null) {
if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
// Save function return value in a callee saved register
break :result try self.copyToNewRegister(inst, info.return_value);
}
@ -2549,10 +2556,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
return error.CodegenFail;
}
const Register = @import("bits.zig").Register;
const Instruction = @import("bits.zig").Instruction;
const callee_preserved_regs = @import("bits.zig").callee_preserved_regs;
fn parseRegName(name: []const u8) ?Register {
if (@hasDecl(Register, "parseRegName")) {
return Register.parseRegName(name);

6
src/arch/riscv64/abi.zig Normal file
View File

@ -0,0 +1,6 @@
const bits = @import("bits.zig");
const Register = bits.Register;
pub const callee_preserved_regs = [_]Register{
.s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
};

View File

@ -409,14 +409,6 @@ pub const Register = enum(u6) {
return @truncate(u5, @enumToInt(self));
}
/// Returns the index into `callee_preserved_regs`.
pub fn allocIndex(self: Register) ?u4 {
inline for (callee_preserved_regs) |cpreg, i| {
if (self.id() == cpreg.id()) return i;
}
return null;
}
pub fn dwarfLocOp(reg: Register) u8 {
return @as(u8, reg.id()) + DW.OP.reg0;
}
@ -424,10 +416,6 @@ pub const Register = enum(u6) {
// zig fmt: on
pub const callee_preserved_regs = [_]Register{
.s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
};
test "serialize instructions" {
const Testcase = struct {
inst: Instruction,

View File

@ -4,16 +4,16 @@ const DW = std.dwarf;
// zig fmt: off
pub const Register = enum(u8) {
// 0 through 7, 32-bit registers. id is int value
eax, ecx, edx, ebx, esp, ebp, esi, edi,
eax, ecx, edx, ebx, esp, ebp, esi, edi,
// 8-15, 16-bit registers. id is int value - 8.
ax, cx, dx, bx, sp, bp, si, di,
// 16-23, 8-bit registers. id is int value - 16.
al, cl, dl, bl, ah, ch, dh, bh,
/// Returns the bit-width of the register.
pub fn size(self: @This()) u7 {
pub fn size(self: Register) u7 {
return switch (@enumToInt(self)) {
0...7 => 32,
8...15 => 16,
@ -25,22 +25,10 @@ pub const Register = enum(u8) {
/// Returns the register's id. This is used in practically every opcode the
/// x86 has. It is embedded in some instructions, such as the `B8 +rd` move
/// instruction, and is used in the R/M byte.
pub fn id(self: @This()) u3 {
pub fn id(self: Register) u3 {
return @truncate(u3, @enumToInt(self));
}
/// Returns the index into `callee_preserved_regs`.
pub fn allocIndex(self: Register) ?u4 {
return switch (self) {
.eax, .ax, .al => 0,
.ecx, .cx, .cl => 1,
.edx, .dx, .dl => 2,
.esi, .si => 3,
.edi, .di => 4,
else => null,
};
}
/// Convert from any register to its 32 bit alias.
pub fn to32(self: Register) Register {
return @intToEnum(Register, @as(u8, self.id()));
@ -56,7 +44,6 @@ pub const Register = enum(u8) {
return @intToEnum(Register, @as(u8, self.id()) + 16);
}
pub fn dwarfLocOp(reg: Register) u8 {
return switch (reg.to32()) {
.eax => DW.OP.reg0,

View File

@ -27,6 +27,13 @@ const Type = @import("../../type.zig").Type;
const TypedValue = @import("../../TypedValue.zig");
const Value = @import("../../value.zig").Value;
const bits = @import("bits.zig");
const abi = @import("abi.zig");
const Register = bits.Register;
const callee_preserved_regs = abi.callee_preserved_regs;
const c_abi_int_param_regs = abi.c_abi_int_param_regs;
const c_abi_int_return_regs = abi.c_abi_int_return_regs;
const InnerError = error{
OutOfMemory,
CodegenFail,
@ -2336,7 +2343,7 @@ fn reuseOperand(
.register => |reg| {
// If it's in the registers table, need to associate the register with the
// new instruction.
if (reg.allocIndex()) |index| {
if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
if (!self.register_manager.isRegFree(reg)) {
self.register_manager.registers[index] = inst;
}
@ -3483,7 +3490,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
const result: MCValue = result: {
switch (info.return_value) {
.register => |reg| {
if (Register.allocIndex(reg) == null) {
if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
// Save function return value in a callee saved register
break :result try self.copyToRegisterWithInstTracking(
inst,
@ -5966,18 +5973,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
return error.CodegenFail;
}
const Register = @import("bits.zig").Register;
const Instruction = void;
const Condition = void;
const callee_preserved_regs = @import("bits.zig").callee_preserved_regs;
const c_abi_int_param_regs = @import("bits.zig").c_abi_int_param_regs;
const c_abi_int_return_regs = @import("bits.zig").c_abi_int_return_regs;
fn parseRegName(name: []const u8) ?Register {
if (@hasDecl(Register, "parseRegName")) {
return Register.parseRegName(name);

View File

@ -6,6 +6,7 @@ const Emit = @This();
const std = @import("std");
const assert = std.debug.assert;
const bits = @import("bits.zig");
const abi = @import("abi.zig");
const leb128 = std.leb;
const link = @import("../../link.zig");
const log = std.log.scoped(.codegen);
@ -265,7 +266,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I
const data = emit.mir.extraData(Mir.RegsToPushOrPop, payload).data;
const regs = data.regs;
var disp: u32 = data.disp + 8;
for (bits.callee_preserved_regs) |reg, i| {
for (abi.callee_preserved_regs) |reg, i| {
if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
if (tag == .push) {
try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{

View File

@ -5,6 +5,7 @@ const Print = @This();
const std = @import("std");
const assert = std.debug.assert;
const bits = @import("bits.zig");
const abi = @import("abi.zig");
const leb128 = std.leb;
const link = @import("../../link.zig");
const log = std.log.scoped(.codegen);
@ -188,7 +189,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(print: *const Print, tag: Mir.Inst.Tag,
var disp: u32 = data.disp + 8;
if (regs == 0) return w.writeAll("no regs from callee_preserved_regs\n");
var printed_first_reg = false;
for (bits.callee_preserved_regs) |reg, i| {
for (abi.callee_preserved_regs) |reg, i| {
if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
if (printed_first_reg) try w.writeAll(" ");
printed_first_reg = true;

View File

@ -2,6 +2,7 @@ const std = @import("std");
const Type = @import("../../type.zig").Type;
const Target = std.Target;
const assert = std.debug.assert;
const Register = @import("bits.zig").Register;
pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none };
@ -370,3 +371,9 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
else => unreachable,
}
}
/// These registers need to be preserved (saved on the stack) and restored by the callee before getting clobbered
/// and when the callee returns.
pub const callee_preserved_regs = [_]Register{ .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };

View File

@ -30,14 +30,14 @@ pub const Register = enum(u7) {
// 16 through 31, 32-bit registers. 24-31 are extended.
// id is int value - 16.
eax, ecx, edx, ebx, esp, ebp, esi, edi,
eax, ecx, edx, ebx, esp, ebp, esi, edi,
r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d,
// 32-47, 16-bit registers. 40-47 are extended.
// id is int value - 32.
ax, cx, dx, bx, sp, bp, si, di,
r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w,
// 48-63, 8-bit registers. 56-63 are extended.
// id is int value - 48.
al, cl, dl, bl, ah, ch, dh, bh,
@ -81,20 +81,6 @@ pub const Register = enum(u7) {
return @truncate(u3, @enumToInt(self));
}
/// Returns the index into `callee_preserved_regs`.
pub fn allocIndex(self: Register) ?u4 {
return switch (self) {
.rcx, .ecx, .cx, .cl => 0,
.rsi, .esi, .si => 1,
.rdi, .edi, .di => 2,
.r8, .r8d, .r8w, .r8b => 3,
.r9, .r9d, .r9w, .r9b => 4,
.r10, .r10d, .r10w, .r10b => 5,
.r11, .r11d, .r11w, .r11b => 6,
else => null,
};
}
/// Convert from any register to its 64 bit alias.
pub fn to64(self: Register) Register {
return @intToEnum(Register, self.id());
@ -142,13 +128,6 @@ pub const Register = enum(u7) {
// zig fmt: on
/// TODO this set is actually a set of caller-saved registers.
/// These registers need to be preserved (saved on the stack) and restored by the callee before getting clobbered
/// and when the callee returns.
pub const callee_preserved_regs = [_]Register{ .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
/// Encoding helper functions for x86_64 instructions
///
/// Many of these helpers do very little, but they can help make things

View File

@ -61,7 +61,7 @@ pub fn RegisterManager(
}
fn getRegisterMask(reg: Register) ?FreeRegInt {
const index = reg.allocIndex() orelse return null;
const index = indexOfRegIntoTracked(reg) orelse return null;
const shift = @intCast(ShiftInt, index);
const mask = @as(FreeRegInt, 1) << shift;
return mask;
@ -82,6 +82,17 @@ pub fn RegisterManager(
self.free_registers |= mask;
}
pub fn indexOfReg(comptime registers: []const Register, reg: Register) ?std.math.IntFittingRange(0, registers.len - 1) {
inline for (callee_preserved_regs) |cpreg, i| {
if (reg.id() == cpreg.id()) return i;
}
return null;
}
pub fn indexOfRegIntoTracked(reg: Register) ?ShiftInt {
return indexOfReg(callee_preserved_regs, reg);
}
/// Returns true when this register is not tracked
pub fn isRegFree(self: Self, reg: Register) bool {
const mask = getRegisterMask(reg) orelse return true;
@ -157,7 +168,7 @@ pub fn RegisterManager(
if (insts[j]) |inst| {
// Track the register
const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
self.registers[index] = inst;
self.markRegUsed(reg);
}
@ -196,7 +207,7 @@ pub fn RegisterManager(
regs[i] = reg;
self.markRegAllocated(reg);
const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
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)) {
@ -235,7 +246,7 @@ pub fn RegisterManager(
/// corresponding instruction is passed, will also track this
/// register.
pub fn getReg(self: *Self, reg: Register, inst: ?Air.Inst.Index) AllocateRegistersError!void {
const index = reg.allocIndex() orelse return;
const index = indexOfRegIntoTracked(reg) orelse return;
self.markRegAllocated(reg);
if (inst) |tracked_inst|
@ -263,7 +274,7 @@ pub fn RegisterManager(
/// 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 = reg.allocIndex() orelse return;
const index = indexOfRegIntoTracked(reg) orelse return;
self.markRegAllocated(reg);
assert(self.isRegFree(reg));
@ -273,7 +284,7 @@ pub fn RegisterManager(
/// Marks the specified register as free
pub fn freeReg(self: *Self, reg: Register) void {
const index = reg.allocIndex() orelse return;
const index = indexOfRegIntoTracked(reg) orelse return;
log.debug("freeing register {}", .{reg});
self.registers[index] = undefined;
@ -288,11 +299,8 @@ const MockRegister1 = enum(u2) {
r2,
r3,
pub fn allocIndex(self: MockRegister1) ?u2 {
inline for (callee_preserved_regs) |cpreg, i| {
if (self == cpreg) return i;
}
return null;
pub fn id(reg: MockRegister1) u2 {
return @enumToInt(reg);
}
const callee_preserved_regs = [_]MockRegister1{ .r2, .r3 };
@ -304,11 +312,8 @@ const MockRegister2 = enum(u2) {
r2,
r3,
pub fn allocIndex(self: MockRegister2) ?u2 {
inline for (callee_preserved_regs) |cpreg, i| {
if (self == cpreg) return i;
}
return null;
pub fn id(reg: MockRegister2) u2 {
return @enumToInt(reg);
}
const callee_preserved_regs = [_]MockRegister2{ .r0, .r1, .r2, .r3 };