diff --git a/CMakeLists.txt b/CMakeLists.txt index 247626f5e9..0f7be06e4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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" diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 0bd549a45d..dcac2c0a60 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.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); diff --git a/src/arch/aarch64/abi.zig b/src/arch/aarch64/abi.zig new file mode 100644 index 0000000000..1c5225104a --- /dev/null +++ b/src/arch/aarch64/abi.zig @@ -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 }; diff --git a/src/arch/aarch64/bits.zig b/src/arch/aarch64/bits.zig index 9e5ad30701..afe14f3204 100644 --- a/src/arch/aarch64/bits.zig +++ b/src/arch/aarch64/bits.zig @@ -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()); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 3a247c09f2..d6bda85377 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -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); diff --git a/src/arch/arm/abi.zig b/src/arch/arm/abi.zig new file mode 100644 index 0000000000..a5a84e8f8b --- /dev/null +++ b/src/arch/arm/abi.zig @@ -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 }; diff --git a/src/arch/arm/bits.zig b/src/arch/arm/bits.zig index a23f99f789..c6dafb6924 100644 --- a/src/arch/arm/bits.zig +++ b/src/arch/arm/bits.zig @@ -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 { diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index b38ec6ed93..07903cebdc 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -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); diff --git a/src/arch/riscv64/abi.zig b/src/arch/riscv64/abi.zig new file mode 100644 index 0000000000..dd0feeea49 --- /dev/null +++ b/src/arch/riscv64/abi.zig @@ -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, +}; diff --git a/src/arch/riscv64/bits.zig b/src/arch/riscv64/bits.zig index f143af4a42..6b94927df8 100644 --- a/src/arch/riscv64/bits.zig +++ b/src/arch/riscv64/bits.zig @@ -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, diff --git a/src/arch/x86/bits.zig b/src/arch/x86/bits.zig index 9af71b8a78..3f4ad26e26 100644 --- a/src/arch/x86/bits.zig +++ b/src/arch/x86/bits.zig @@ -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, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index be3d09bc8f..4adc59e662 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -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); diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 3409894fc4..b6a3ffdf30 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -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, .{ diff --git a/src/arch/x86_64/PrintMir.zig b/src/arch/x86_64/PrintMir.zig index 4ab32878be..8c07350c2d 100644 --- a/src/arch/x86_64/PrintMir.zig +++ b/src/arch/x86_64/PrintMir.zig @@ -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; diff --git a/src/arch/x86_64/abi.zig b/src/arch/x86_64/abi.zig index b0ab1acefd..5e9bd6e071 100644 --- a/src/arch/x86_64/abi.zig +++ b/src/arch/x86_64/abi.zig @@ -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 }; diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index 46da8a247e..02f032ab72 100644 --- a/src/arch/x86_64/bits.zig +++ b/src/arch/x86_64/bits.zig @@ -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 diff --git a/src/register_manager.zig b/src/register_manager.zig index 3d76e94ba0..a29cfbf921 100644 --- a/src/register_manager.zig +++ b/src/register_manager.zig @@ -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 };