authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-10 23:14:28+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-11 13:29:16+01:00
log06058ed6f38194dfe74d232e77e33d98919d1ee7
treea47100091c86a338a85a367879d0c0d1a9f3c1c4
parent078037ab9b410fa13a86eabdfc30918fc83cdcf3
signaturelock-open Commit is signed but in an unrecognized format.

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

17 files changed, 121 insertions(+), 150 deletions(-)

CMakeLists.txt+4
......@@ -597,14 +597,17 @@ set(ZIG_STAGE2_SOURCES
597597 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig"
598598 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/Mir.zig"
599599 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/bits.zig"
600 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/abi.zig"
600601 "${CMAKE_SOURCE_DIR}/src/arch/arm/CodeGen.zig"
601602 "${CMAKE_SOURCE_DIR}/src/arch/arm/Emit.zig"
602603 "${CMAKE_SOURCE_DIR}/src/arch/arm/Mir.zig"
603604 "${CMAKE_SOURCE_DIR}/src/arch/arm/bits.zig"
605 "${CMAKE_SOURCE_DIR}/src/arch/arm/abi.zig"
604606 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/CodeGen.zig"
605607 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/Emit.zig"
606608 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/Mir.zig"
607609 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/bits.zig"
610 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/abi.zig"
608611 "${CMAKE_SOURCE_DIR}/src/arch/wasm/CodeGen.zig"
609612 "${CMAKE_SOURCE_DIR}/src/arch/wasm/Emit.zig"
610613 "${CMAKE_SOURCE_DIR}/src/arch/wasm/Mir.zig"
......@@ -612,6 +615,7 @@ set(ZIG_STAGE2_SOURCES
612615 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/Emit.zig"
613616 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/Mir.zig"
614617 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/bits.zig"
618 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/abi.zig"
615619 "${CMAKE_SOURCE_DIR}/src/clang.zig"
616620 "${CMAKE_SOURCE_DIR}/src/clang_options.zig"
617621 "${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"
src/arch/aarch64/CodeGen.zig+13-10
......@@ -21,12 +21,21 @@ const DW = std.dwarf;
2121const leb128 = std.leb;
2222const log = std.log.scoped(.codegen);
2323const build_options = @import("build_options");
24const RegisterManager = @import("../../register_manager.zig").RegisterManager;
24const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
25const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs);
2526
2627const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
2728const FnResult = @import("../../codegen.zig").FnResult;
2829const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
2930
31const bits = @import("bits.zig");
32const abi = @import("abi.zig");
33const Register = bits.Register;
34const Instruction = bits.Instruction;
35const callee_preserved_regs = abi.callee_preserved_regs;
36const c_abi_int_param_regs = abi.c_abi_int_param_regs;
37const c_abi_int_return_regs = abi.c_abi_int_return_regs;
38
3039const InnerError = error{
3140 OutOfMemory,
3241 CodegenFail,
......@@ -73,7 +82,7 @@ branch_stack: *std.ArrayList(Branch),
7382// Key is the block instruction
7483blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
7584
76register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},
85register_manager: RegisterManager = .{},
7786/// Maps offset to what is stored there.
7887stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
7988
......@@ -1836,7 +1845,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
18361845 .register => |reg| {
18371846 // If it's in the registers table, need to associate the register with the
18381847 // new instruction.
1839 if (reg.allocIndex()) |index| {
1848 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
18401849 if (!self.register_manager.isRegFree(reg)) {
18411850 self.register_manager.registers[index] = inst;
18421851 }
......@@ -2475,7 +2484,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
24752484 const result: MCValue = result: {
24762485 switch (info.return_value) {
24772486 .register => |reg| {
2478 if (Register.allocIndex(reg) == null) {
2487 if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
24792488 // Save function return value in a callee saved register
24802489 break :result try self.copyToNewRegister(inst, info.return_value);
24812490 }
......@@ -4017,12 +4026,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
40174026 return error.CodegenFail;
40184027}
40194028
4020const Register = @import("bits.zig").Register;
4021const Instruction = @import("bits.zig").Instruction;
4022const callee_preserved_regs = @import("bits.zig").callee_preserved_regs;
4023const c_abi_int_param_regs = @import("bits.zig").c_abi_int_param_regs;
4024const c_abi_int_return_regs = @import("bits.zig").c_abi_int_return_regs;
4025
40264029fn parseRegName(name: []const u8) ?Register {
40274030 if (@hasDecl(Register, "parseRegName")) {
40284031 return Register.parseRegName(name);
src/arch/aarch64/abi.zig created+20
......@@ -0,0 +1,20 @@
1const builtin = @import("builtin");
2const bits = @import("bits.zig");
3const Register = bits.Register;
4
5const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct {
6 pub const callee_preserved_regs = [_]Register{
7 .x20, .x21, .x22, .x23,
8 .x24, .x25, .x26, .x27,
9 .x28,
10 };
11} else struct {
12 pub const callee_preserved_regs = [_]Register{
13 .x19, .x20, .x21, .x22, .x23,
14 .x24, .x25, .x26, .x27, .x28,
15 };
16};
17pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_regs;
18
19pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
20pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
src/arch/aarch64/bits.zig-25
......@@ -72,14 +72,6 @@ pub const Register = enum(u7) {
7272 };
7373 }
7474
75 /// Returns the index into `callee_preserved_regs`.
76 pub fn allocIndex(self: Register) ?u4 {
77 inline for (callee_preserved_regs) |cpreg, i| {
78 if (self.id() == cpreg.id()) return i;
79 }
80 return null;
81 }
82
8375 pub fn dwarfLocOp(self: Register) u8 {
8476 return @as(u8, self.enc()) + DW.OP.reg0;
8577 }
......@@ -87,23 +79,6 @@ pub const Register = enum(u7) {
8779
8880// zig fmt: on
8981
90const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct {
91 pub const callee_preserved_regs = [_]Register{
92 .x20, .x21, .x22, .x23,
93 .x24, .x25, .x26, .x27,
94 .x28,
95 };
96} else struct {
97 pub const callee_preserved_regs = [_]Register{
98 .x19, .x20, .x21, .x22, .x23,
99 .x24, .x25, .x26, .x27, .x28,
100 };
101};
102pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_regs;
103
104pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
105pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
106
10782test "Register.enc" {
10883 try testing.expectEqual(@as(u5, 0), Register.x0.enc());
10984 try testing.expectEqual(@as(u5, 0), Register.w0.enc());
src/arch/arm/CodeGen.zig+14-11
......@@ -21,12 +21,22 @@ const DW = std.dwarf;
2121const leb128 = std.leb;
2222const log = std.log.scoped(.codegen);
2323const build_options = @import("build_options");
24const RegisterManager = @import("../../register_manager.zig").RegisterManager;
24const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
25const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs);
2526
2627const FnResult = @import("../../codegen.zig").FnResult;
2728const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
2829const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
2930
31const bits = @import("bits.zig");
32const abi = @import("abi.zig");
33const Register = bits.Register;
34const Instruction = bits.Instruction;
35const Condition = bits.Condition;
36const callee_preserved_regs = abi.callee_preserved_regs;
37const c_abi_int_param_regs = abi.c_abi_int_param_regs;
38const c_abi_int_return_regs = abi.c_abi_int_return_regs;
39
3040const InnerError = error{
3141 OutOfMemory,
3242 CodegenFail,
......@@ -73,7 +83,7 @@ branch_stack: *std.ArrayList(Branch),
7383// Key is the block instruction
7484blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
7585
76register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},
86register_manager: RegisterManager = .{},
7787/// Maps offset to what is stored there.
7888stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
7989/// 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
15611571 .register => |reg| {
15621572 // If it's in the registers table, need to associate the register with the
15631573 // new instruction.
1564 if (reg.allocIndex()) |index| {
1574 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
15651575 if (!self.register_manager.isRegFree(reg)) {
15661576 self.register_manager.registers[index] = inst;
15671577 }
......@@ -2652,7 +2662,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
26522662 const result: MCValue = result: {
26532663 switch (info.return_value) {
26542664 .register => |reg| {
2655 if (Register.allocIndex(reg) == null) {
2665 if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
26562666 // Save function return value in a callee saved register
26572667 break :result try self.copyToNewRegister(inst, info.return_value);
26582668 }
......@@ -4495,13 +4505,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
44954505 return error.CodegenFail;
44964506}
44974507
4498const Register = @import("bits.zig").Register;
4499const Instruction = @import("bits.zig").Instruction;
4500const Condition = @import("bits.zig").Condition;
4501const callee_preserved_regs = @import("bits.zig").callee_preserved_regs;
4502const c_abi_int_param_regs = @import("bits.zig").c_abi_int_param_regs;
4503const c_abi_int_return_regs = @import("bits.zig").c_abi_int_return_regs;
4504
45054508fn parseRegName(name: []const u8) ?Register {
45064509 if (@hasDecl(Register, "parseRegName")) {
45074510 return Register.parseRegName(name);
src/arch/arm/abi.zig created+6
......@@ -0,0 +1,6 @@
1const bits = @import("bits.zig");
2const Register = bits.Register;
3
4pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 };
5pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 };
6pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 };
src/arch/arm/bits.zig-12
......@@ -162,14 +162,6 @@ pub const Register = enum(u5) {
162162 return @truncate(u4, @enumToInt(self));
163163 }
164164
165 /// Returns the index into `callee_preserved_regs`.
166 pub fn allocIndex(self: Register) ?u4 {
167 inline for (callee_preserved_regs) |cpreg, i| {
168 if (self.id() == cpreg.id()) return i;
169 }
170 return null;
171 }
172
173165 pub fn dwarfLocOp(self: Register) u8 {
174166 return @as(u8, self.id()) + DW.OP.reg0;
175167 }
......@@ -187,10 +179,6 @@ pub const Psr = enum {
187179 spsr,
188180};
189181
190pub const callee_preserved_regs = [_]Register{ .r4, .r5, .r6, .r7, .r8, .r10 };
191pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 };
192pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 };
193
194182/// Represents an instruction in the ARM instruction set architecture
195183pub const Instruction = union(enum) {
196184 data_processing: packed struct {
src/arch/riscv64/CodeGen.zig+11-8
......@@ -21,12 +21,19 @@ const DW = std.dwarf;
2121const leb128 = std.leb;
2222const log = std.log.scoped(.codegen);
2323const build_options = @import("build_options");
24const RegisterManager = @import("../../register_manager.zig").RegisterManager;
24const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
25const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs);
2526
2627const FnResult = @import("../../codegen.zig").FnResult;
2728const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
2829const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
2930
31const bits = @import("bits.zig");
32const abi = @import("abi.zig");
33const Register = bits.Register;
34const Instruction = abi.Instruction;
35const callee_preserved_regs = abi.callee_preserved_regs;
36
3037const InnerError = error{
3138 OutOfMemory,
3239 CodegenFail,
......@@ -75,7 +82,7 @@ branch_stack: *std.ArrayList(Branch),
7582// Key is the block instruction
7683blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
7784
78register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},
85register_manager: RegisterManager = .{},
7986/// Maps offset to what is stored there.
8087stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
8188
......@@ -1230,7 +1237,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
12301237 .register => |reg| {
12311238 // If it's in the registers table, need to associate the register with the
12321239 // new instruction.
1233 if (reg.allocIndex()) |index| {
1240 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
12341241 if (!self.register_manager.isRegFree(reg)) {
12351242 self.register_manager.registers[index] = inst;
12361243 }
......@@ -1545,7 +1552,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
15451552 const result: MCValue = result: {
15461553 switch (info.return_value) {
15471554 .register => |reg| {
1548 if (Register.allocIndex(reg) == null) {
1555 if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
15491556 // Save function return value in a callee saved register
15501557 break :result try self.copyToNewRegister(inst, info.return_value);
15511558 }
......@@ -2549,10 +2556,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
25492556 return error.CodegenFail;
25502557}
25512558
2552const Register = @import("bits.zig").Register;
2553const Instruction = @import("bits.zig").Instruction;
2554const callee_preserved_regs = @import("bits.zig").callee_preserved_regs;
2555
25562559fn parseRegName(name: []const u8) ?Register {
25572560 if (@hasDecl(Register, "parseRegName")) {
25582561 return Register.parseRegName(name);
src/arch/riscv64/abi.zig created+6
......@@ -0,0 +1,6 @@
1const bits = @import("bits.zig");
2const Register = bits.Register;
3
4pub const callee_preserved_regs = [_]Register{
5 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
6};
src/arch/riscv64/bits.zig-12
......@@ -409,14 +409,6 @@ pub const Register = enum(u6) {
409409 return @truncate(u5, @enumToInt(self));
410410 }
411411
412 /// Returns the index into `callee_preserved_regs`.
413 pub fn allocIndex(self: Register) ?u4 {
414 inline for (callee_preserved_regs) |cpreg, i| {
415 if (self.id() == cpreg.id()) return i;
416 }
417 return null;
418 }
419
420412 pub fn dwarfLocOp(reg: Register) u8 {
421413 return @as(u8, reg.id()) + DW.OP.reg0;
422414 }
......@@ -424,10 +416,6 @@ pub const Register = enum(u6) {
424416
425417// zig fmt: on
426418
427pub const callee_preserved_regs = [_]Register{
428 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
429};
430
431419test "serialize instructions" {
432420 const Testcase = struct {
433421 inst: Instruction,
src/arch/x86/bits.zig+4-17
......@@ -4,16 +4,16 @@ const DW = std.dwarf;
44// zig fmt: off
55pub const Register = enum(u8) {
66 // 0 through 7, 32-bit registers. id is int value
7 eax, ecx, edx, ebx, esp, ebp, esi, edi,
7 eax, ecx, edx, ebx, esp, ebp, esi, edi,
88
99 // 8-15, 16-bit registers. id is int value - 8.
1010 ax, cx, dx, bx, sp, bp, si, di,
11
11
1212 // 16-23, 8-bit registers. id is int value - 16.
1313 al, cl, dl, bl, ah, ch, dh, bh,
1414
1515 /// Returns the bit-width of the register.
16 pub fn size(self: @This()) u7 {
16 pub fn size(self: Register) u7 {
1717 return switch (@enumToInt(self)) {
1818 0...7 => 32,
1919 8...15 => 16,
......@@ -25,22 +25,10 @@ pub const Register = enum(u8) {
2525 /// Returns the register's id. This is used in practically every opcode the
2626 /// x86 has. It is embedded in some instructions, such as the `B8 +rd` move
2727 /// instruction, and is used in the R/M byte.
28 pub fn id(self: @This()) u3 {
28 pub fn id(self: Register) u3 {
2929 return @truncate(u3, @enumToInt(self));
3030 }
3131
32 /// Returns the index into `callee_preserved_regs`.
33 pub fn allocIndex(self: Register) ?u4 {
34 return switch (self) {
35 .eax, .ax, .al => 0,
36 .ecx, .cx, .cl => 1,
37 .edx, .dx, .dl => 2,
38 .esi, .si => 3,
39 .edi, .di => 4,
40 else => null,
41 };
42 }
43
4432 /// Convert from any register to its 32 bit alias.
4533 pub fn to32(self: Register) Register {
4634 return @intToEnum(Register, @as(u8, self.id()));
......@@ -56,7 +44,6 @@ pub const Register = enum(u8) {
5644 return @intToEnum(Register, @as(u8, self.id()) + 16);
5745 }
5846
59
6047 pub fn dwarfLocOp(reg: Register) u8 {
6148 return switch (reg.to32()) {
6249 .eax => DW.OP.reg0,
src/arch/x86_64/CodeGen.zig+9-14
......@@ -27,6 +27,13 @@ const Type = @import("../../type.zig").Type;
2727const TypedValue = @import("../../TypedValue.zig");
2828const Value = @import("../../value.zig").Value;
2929
30const bits = @import("bits.zig");
31const abi = @import("abi.zig");
32const Register = bits.Register;
33const callee_preserved_regs = abi.callee_preserved_regs;
34const c_abi_int_param_regs = abi.c_abi_int_param_regs;
35const c_abi_int_return_regs = abi.c_abi_int_return_regs;
36
3037const InnerError = error{
3138 OutOfMemory,
3239 CodegenFail,
......@@ -2336,7 +2343,7 @@ fn reuseOperand(
23362343 .register => |reg| {
23372344 // If it's in the registers table, need to associate the register with the
23382345 // new instruction.
2339 if (reg.allocIndex()) |index| {
2346 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
23402347 if (!self.register_manager.isRegFree(reg)) {
23412348 self.register_manager.registers[index] = inst;
23422349 }
......@@ -3483,7 +3490,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
34833490 const result: MCValue = result: {
34843491 switch (info.return_value) {
34853492 .register => |reg| {
3486 if (Register.allocIndex(reg) == null) {
3493 if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
34873494 // Save function return value in a callee saved register
34883495 break :result try self.copyToRegisterWithInstTracking(
34893496 inst,
......@@ -5966,18 +5973,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
59665973 return error.CodegenFail;
59675974}
59685975
5969const Register = @import("bits.zig").Register;
5970
5971const Instruction = void;
5972
5973const Condition = void;
5974
5975const callee_preserved_regs = @import("bits.zig").callee_preserved_regs;
5976
5977const c_abi_int_param_regs = @import("bits.zig").c_abi_int_param_regs;
5978
5979const c_abi_int_return_regs = @import("bits.zig").c_abi_int_return_regs;
5980
59815976fn parseRegName(name: []const u8) ?Register {
59825977 if (@hasDecl(Register, "parseRegName")) {
59835978 return Register.parseRegName(name);
src/arch/x86_64/Emit.zig+2-1
......@@ -6,6 +6,7 @@ const Emit = @This();
66const std = @import("std");
77const assert = std.debug.assert;
88const bits = @import("bits.zig");
9const abi = @import("abi.zig");
910const leb128 = std.leb;
1011const link = @import("../../link.zig");
1112const log = std.log.scoped(.codegen);
......@@ -265,7 +266,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I
265266 const data = emit.mir.extraData(Mir.RegsToPushOrPop, payload).data;
266267 const regs = data.regs;
267268 var disp: u32 = data.disp + 8;
268 for (bits.callee_preserved_regs) |reg, i| {
269 for (abi.callee_preserved_regs) |reg, i| {
269270 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
270271 if (tag == .push) {
271272 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
src/arch/x86_64/PrintMir.zig+2-1
......@@ -5,6 +5,7 @@ const Print = @This();
55const std = @import("std");
66const assert = std.debug.assert;
77const bits = @import("bits.zig");
8const abi = @import("abi.zig");
89const leb128 = std.leb;
910const link = @import("../../link.zig");
1011const log = std.log.scoped(.codegen);
......@@ -188,7 +189,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(print: *const Print, tag: Mir.Inst.Tag,
188189 var disp: u32 = data.disp + 8;
189190 if (regs == 0) return w.writeAll("no regs from callee_preserved_regs\n");
190191 var printed_first_reg = false;
191 for (bits.callee_preserved_regs) |reg, i| {
192 for (abi.callee_preserved_regs) |reg, i| {
192193 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
193194 if (printed_first_reg) try w.writeAll(" ");
194195 printed_first_reg = true;
src/arch/x86_64/abi.zig+7
......@@ -2,6 +2,7 @@ const std = @import("std");
22const Type = @import("../../type.zig").Type;
33const Target = std.Target;
44const assert = std.debug.assert;
5const Register = @import("bits.zig").Register;
56
67pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none };
78
......@@ -370,3 +371,9 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
370371 else => unreachable,
371372 }
372373}
374
375/// These registers need to be preserved (saved on the stack) and restored by the callee before getting clobbered
376/// and when the callee returns.
377pub const callee_preserved_regs = [_]Register{ .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
378pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
379pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
src/arch/x86_64/bits.zig+2-23
......@@ -30,14 +30,14 @@ pub const Register = enum(u7) {
3030
3131 // 16 through 31, 32-bit registers. 24-31 are extended.
3232 // id is int value - 16.
33 eax, ecx, edx, ebx, esp, ebp, esi, edi,
33 eax, ecx, edx, ebx, esp, ebp, esi, edi,
3434 r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d,
3535
3636 // 32-47, 16-bit registers. 40-47 are extended.
3737 // id is int value - 32.
3838 ax, cx, dx, bx, sp, bp, si, di,
3939 r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w,
40
40
4141 // 48-63, 8-bit registers. 56-63 are extended.
4242 // id is int value - 48.
4343 al, cl, dl, bl, ah, ch, dh, bh,
......@@ -81,20 +81,6 @@ pub const Register = enum(u7) {
8181 return @truncate(u3, @enumToInt(self));
8282 }
8383
84 /// Returns the index into `callee_preserved_regs`.
85 pub fn allocIndex(self: Register) ?u4 {
86 return switch (self) {
87 .rcx, .ecx, .cx, .cl => 0,
88 .rsi, .esi, .si => 1,
89 .rdi, .edi, .di => 2,
90 .r8, .r8d, .r8w, .r8b => 3,
91 .r9, .r9d, .r9w, .r9b => 4,
92 .r10, .r10d, .r10w, .r10b => 5,
93 .r11, .r11d, .r11w, .r11b => 6,
94 else => null,
95 };
96 }
97
9884 /// Convert from any register to its 64 bit alias.
9985 pub fn to64(self: Register) Register {
10086 return @intToEnum(Register, self.id());
......@@ -142,13 +128,6 @@ pub const Register = enum(u7) {
142128
143129// zig fmt: on
144130
145/// TODO this set is actually a set of caller-saved registers.
146/// These registers need to be preserved (saved on the stack) and restored by the callee before getting clobbered
147/// and when the callee returns.
148pub const callee_preserved_regs = [_]Register{ .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
149pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
150pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
151
152131/// Encoding helper functions for x86_64 instructions
153132///
154133/// Many of these helpers do very little, but they can help make things
src/register_manager.zig+21-16
......@@ -61,7 +61,7 @@ pub fn RegisterManager(
6161 }
6262
6363 fn getRegisterMask(reg: Register) ?FreeRegInt {
64 const index = reg.allocIndex() orelse return null;
64 const index = indexOfRegIntoTracked(reg) orelse return null;
6565 const shift = @intCast(ShiftInt, index);
6666 const mask = @as(FreeRegInt, 1) << shift;
6767 return mask;
......@@ -82,6 +82,17 @@ pub fn RegisterManager(
8282 self.free_registers |= mask;
8383 }
8484
85 pub fn indexOfReg(comptime registers: []const Register, reg: Register) ?std.math.IntFittingRange(0, registers.len - 1) {
86 inline for (callee_preserved_regs) |cpreg, i| {
87 if (reg.id() == cpreg.id()) return i;
88 }
89 return null;
90 }
91
92 pub fn indexOfRegIntoTracked(reg: Register) ?ShiftInt {
93 return indexOfReg(callee_preserved_regs, reg);
94 }
95
8596 /// Returns true when this register is not tracked
8697 pub fn isRegFree(self: Self, reg: Register) bool {
8798 const mask = getRegisterMask(reg) orelse return true;
......@@ -157,7 +168,7 @@ pub fn RegisterManager(
157168
158169 if (insts[j]) |inst| {
159170 // Track the register
160 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
171 const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
161172 self.registers[index] = inst;
162173 self.markRegUsed(reg);
163174 }
......@@ -196,7 +207,7 @@ pub fn RegisterManager(
196207
197208 regs[i] = reg;
198209 self.markRegAllocated(reg);
199 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
210 const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
200211 if (insts[i]) |inst| {
201212 // Track the register
202213 if (self.isRegFree(reg)) {
......@@ -235,7 +246,7 @@ pub fn RegisterManager(
235246 /// corresponding instruction is passed, will also track this
236247 /// register.
237248 pub fn getReg(self: *Self, reg: Register, inst: ?Air.Inst.Index) AllocateRegistersError!void {
238 const index = reg.allocIndex() orelse return;
249 const index = indexOfRegIntoTracked(reg) orelse return;
239250 self.markRegAllocated(reg);
240251
241252 if (inst) |tracked_inst|
......@@ -263,7 +274,7 @@ pub fn RegisterManager(
263274 /// instruction. Asserts that the register is free and no
264275 /// spilling is necessary.
265276 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: Air.Inst.Index) void {
266 const index = reg.allocIndex() orelse return;
277 const index = indexOfRegIntoTracked(reg) orelse return;
267278 self.markRegAllocated(reg);
268279
269280 assert(self.isRegFree(reg));
......@@ -273,7 +284,7 @@ pub fn RegisterManager(
273284
274285 /// Marks the specified register as free
275286 pub fn freeReg(self: *Self, reg: Register) void {
276 const index = reg.allocIndex() orelse return;
287 const index = indexOfRegIntoTracked(reg) orelse return;
277288 log.debug("freeing register {}", .{reg});
278289
279290 self.registers[index] = undefined;
......@@ -288,11 +299,8 @@ const MockRegister1 = enum(u2) {
288299 r2,
289300 r3,
290301
291 pub fn allocIndex(self: MockRegister1) ?u2 {
292 inline for (callee_preserved_regs) |cpreg, i| {
293 if (self == cpreg) return i;
294 }
295 return null;
302 pub fn id(reg: MockRegister1) u2 {
303 return @enumToInt(reg);
296304 }
297305
298306 const callee_preserved_regs = [_]MockRegister1{ .r2, .r3 };
......@@ -304,11 +312,8 @@ const MockRegister2 = enum(u2) {
304312 r2,
305313 r3,
306314
307 pub fn allocIndex(self: MockRegister2) ?u2 {
308 inline for (callee_preserved_regs) |cpreg, i| {
309 if (self == cpreg) return i;
310 }
311 return null;
315 pub fn id(reg: MockRegister2) u2 {
316 return @enumToInt(reg);
312317 }
313318
314319 const callee_preserved_regs = [_]MockRegister2{ .r0, .r1, .r2, .r3 };