mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
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:
parent
078037ab9b
commit
06058ed6f3
@ -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"
|
||||
|
||||
@ -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
20
src/arch/aarch64/abi.zig
Normal 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 };
|
||||
@ -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());
|
||||
|
||||
@ -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
6
src/arch/arm/abi.zig
Normal 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 };
|
||||
@ -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 {
|
||||
|
||||
@ -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
6
src/arch/riscv64/abi.zig
Normal 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,
|
||||
};
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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, .{
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 };
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user