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...@@ -597,14 +597,17 @@ set(ZIG_STAGE2_SOURCES
597 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig"597 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/Emit.zig"
598 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/Mir.zig"598 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/Mir.zig"
599 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/bits.zig"599 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/bits.zig"
600 "${CMAKE_SOURCE_DIR}/src/arch/aarch64/abi.zig"
600 "${CMAKE_SOURCE_DIR}/src/arch/arm/CodeGen.zig"601 "${CMAKE_SOURCE_DIR}/src/arch/arm/CodeGen.zig"
601 "${CMAKE_SOURCE_DIR}/src/arch/arm/Emit.zig"602 "${CMAKE_SOURCE_DIR}/src/arch/arm/Emit.zig"
602 "${CMAKE_SOURCE_DIR}/src/arch/arm/Mir.zig"603 "${CMAKE_SOURCE_DIR}/src/arch/arm/Mir.zig"
603 "${CMAKE_SOURCE_DIR}/src/arch/arm/bits.zig"604 "${CMAKE_SOURCE_DIR}/src/arch/arm/bits.zig"
605 "${CMAKE_SOURCE_DIR}/src/arch/arm/abi.zig"
604 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/CodeGen.zig"606 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/CodeGen.zig"
605 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/Emit.zig"607 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/Emit.zig"
606 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/Mir.zig"608 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/Mir.zig"
607 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/bits.zig"609 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/bits.zig"
610 "${CMAKE_SOURCE_DIR}/src/arch/riscv64/abi.zig"
608 "${CMAKE_SOURCE_DIR}/src/arch/wasm/CodeGen.zig"611 "${CMAKE_SOURCE_DIR}/src/arch/wasm/CodeGen.zig"
609 "${CMAKE_SOURCE_DIR}/src/arch/wasm/Emit.zig"612 "${CMAKE_SOURCE_DIR}/src/arch/wasm/Emit.zig"
610 "${CMAKE_SOURCE_DIR}/src/arch/wasm/Mir.zig"613 "${CMAKE_SOURCE_DIR}/src/arch/wasm/Mir.zig"
...@@ -612,6 +615,7 @@ set(ZIG_STAGE2_SOURCES...@@ -612,6 +615,7 @@ set(ZIG_STAGE2_SOURCES
612 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/Emit.zig"615 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/Emit.zig"
613 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/Mir.zig"616 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/Mir.zig"
614 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/bits.zig"617 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/bits.zig"
618 "${CMAKE_SOURCE_DIR}/src/arch/x86_64/abi.zig"
615 "${CMAKE_SOURCE_DIR}/src/clang.zig"619 "${CMAKE_SOURCE_DIR}/src/clang.zig"
616 "${CMAKE_SOURCE_DIR}/src/clang_options.zig"620 "${CMAKE_SOURCE_DIR}/src/clang_options.zig"
617 "${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"621 "${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"
src/arch/aarch64/CodeGen.zig+13-10
...@@ -21,12 +21,21 @@ const DW = std.dwarf;...@@ -21,12 +21,21 @@ const DW = std.dwarf;
21const leb128 = std.leb;21const leb128 = std.leb;
22const log = std.log.scoped(.codegen);22const log = std.log.scoped(.codegen);
23const build_options = @import("build_options");23const 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
26const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;27const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
27const FnResult = @import("../../codegen.zig").FnResult;28const FnResult = @import("../../codegen.zig").FnResult;
28const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;29const 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
30const InnerError = error{39const InnerError = error{
31 OutOfMemory,40 OutOfMemory,
32 CodegenFail,41 CodegenFail,
...@@ -73,7 +82,7 @@ branch_stack: *std.ArrayList(Branch),...@@ -73,7 +82,7 @@ branch_stack: *std.ArrayList(Branch),
73// Key is the block instruction82// Key is the block instruction
74blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},83blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
7584
76register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},85register_manager: RegisterManager = .{},
77/// Maps offset to what is stored there.86/// Maps offset to what is stored there.
78stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},87stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
7988
...@@ -1836,7 +1845,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind...@@ -1836,7 +1845,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
1836 .register => |reg| {1845 .register => |reg| {
1837 // If it's in the registers table, need to associate the register with the1846 // If it's in the registers table, need to associate the register with the
1838 // new instruction.1847 // new instruction.
1839 if (reg.allocIndex()) |index| {1848 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
1840 if (!self.register_manager.isRegFree(reg)) {1849 if (!self.register_manager.isRegFree(reg)) {
1841 self.register_manager.registers[index] = inst;1850 self.register_manager.registers[index] = inst;
1842 }1851 }
...@@ -2475,7 +2484,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -2475,7 +2484,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
2475 const result: MCValue = result: {2484 const result: MCValue = result: {
2476 switch (info.return_value) {2485 switch (info.return_value) {
2477 .register => |reg| {2486 .register => |reg| {
2478 if (Register.allocIndex(reg) == null) {2487 if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
2479 // Save function return value in a callee saved register2488 // Save function return value in a callee saved register
2480 break :result try self.copyToNewRegister(inst, info.return_value);2489 break :result try self.copyToNewRegister(inst, info.return_value);
2481 }2490 }
...@@ -4017,12 +4026,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro...@@ -4017,12 +4026,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
4017 return error.CodegenFail;4026 return error.CodegenFail;
4018}4027}
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
4026fn parseRegName(name: []const u8) ?Register {4029fn parseRegName(name: []const u8) ?Register {
4027 if (@hasDecl(Register, "parseRegName")) {4030 if (@hasDecl(Register, "parseRegName")) {
4028 return Register.parseRegName(name);4031 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) {...@@ -72,14 +72,6 @@ pub const Register = enum(u7) {
72 };72 };
73 }73 }
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
83 pub fn dwarfLocOp(self: Register) u8 {75 pub fn dwarfLocOp(self: Register) u8 {
84 return @as(u8, self.enc()) + DW.OP.reg0;76 return @as(u8, self.enc()) + DW.OP.reg0;
85 }77 }
...@@ -87,23 +79,6 @@ pub const Register = enum(u7) {...@@ -87,23 +79,6 @@ pub const Register = enum(u7) {
8779
88// zig fmt: on80// 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
107test "Register.enc" {82test "Register.enc" {
108 try testing.expectEqual(@as(u5, 0), Register.x0.enc());83 try testing.expectEqual(@as(u5, 0), Register.x0.enc());
109 try testing.expectEqual(@as(u5, 0), Register.w0.enc());84 try testing.expectEqual(@as(u5, 0), Register.w0.enc());
src/arch/arm/CodeGen.zig+14-11
...@@ -21,12 +21,22 @@ const DW = std.dwarf;...@@ -21,12 +21,22 @@ const DW = std.dwarf;
21const leb128 = std.leb;21const leb128 = std.leb;
22const log = std.log.scoped(.codegen);22const log = std.log.scoped(.codegen);
23const build_options = @import("build_options");23const 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
26const FnResult = @import("../../codegen.zig").FnResult;27const FnResult = @import("../../codegen.zig").FnResult;
27const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;28const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
28const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;29const 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
30const InnerError = error{40const InnerError = error{
31 OutOfMemory,41 OutOfMemory,
32 CodegenFail,42 CodegenFail,
...@@ -73,7 +83,7 @@ branch_stack: *std.ArrayList(Branch),...@@ -73,7 +83,7 @@ branch_stack: *std.ArrayList(Branch),
73// Key is the block instruction83// Key is the block instruction
74blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},84blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
7585
76register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},86register_manager: RegisterManager = .{},
77/// Maps offset to what is stored there.87/// Maps offset to what is stored there.
78stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},88stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
79/// Tracks the current instruction allocated to the compare flags89/// 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...@@ -1561,7 +1571,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
1561 .register => |reg| {1571 .register => |reg| {
1562 // If it's in the registers table, need to associate the register with the1572 // If it's in the registers table, need to associate the register with the
1563 // new instruction.1573 // new instruction.
1564 if (reg.allocIndex()) |index| {1574 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
1565 if (!self.register_manager.isRegFree(reg)) {1575 if (!self.register_manager.isRegFree(reg)) {
1566 self.register_manager.registers[index] = inst;1576 self.register_manager.registers[index] = inst;
1567 }1577 }
...@@ -2652,7 +2662,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -2652,7 +2662,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
2652 const result: MCValue = result: {2662 const result: MCValue = result: {
2653 switch (info.return_value) {2663 switch (info.return_value) {
2654 .register => |reg| {2664 .register => |reg| {
2655 if (Register.allocIndex(reg) == null) {2665 if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
2656 // Save function return value in a callee saved register2666 // Save function return value in a callee saved register
2657 break :result try self.copyToNewRegister(inst, info.return_value);2667 break :result try self.copyToNewRegister(inst, info.return_value);
2658 }2668 }
...@@ -4495,13 +4505,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro...@@ -4495,13 +4505,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
4495 return error.CodegenFail;4505 return error.CodegenFail;
4496}4506}
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
4505fn parseRegName(name: []const u8) ?Register {4508fn parseRegName(name: []const u8) ?Register {
4506 if (@hasDecl(Register, "parseRegName")) {4509 if (@hasDecl(Register, "parseRegName")) {
4507 return Register.parseRegName(name);4510 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) {...@@ -162,14 +162,6 @@ pub const Register = enum(u5) {
162 return @truncate(u4, @enumToInt(self));162 return @truncate(u4, @enumToInt(self));
163 }163 }
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
173 pub fn dwarfLocOp(self: Register) u8 {165 pub fn dwarfLocOp(self: Register) u8 {
174 return @as(u8, self.id()) + DW.OP.reg0;166 return @as(u8, self.id()) + DW.OP.reg0;
175 }167 }
...@@ -187,10 +179,6 @@ pub const Psr = enum {...@@ -187,10 +179,6 @@ pub const Psr = enum {
187 spsr,179 spsr,
188};180};
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
194/// Represents an instruction in the ARM instruction set architecture182/// Represents an instruction in the ARM instruction set architecture
195pub const Instruction = union(enum) {183pub const Instruction = union(enum) {
196 data_processing: packed struct {184 data_processing: packed struct {
src/arch/riscv64/CodeGen.zig+11-8
...@@ -21,12 +21,19 @@ const DW = std.dwarf;...@@ -21,12 +21,19 @@ const DW = std.dwarf;
21const leb128 = std.leb;21const leb128 = std.leb;
22const log = std.log.scoped(.codegen);22const log = std.log.scoped(.codegen);
23const build_options = @import("build_options");23const 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
26const FnResult = @import("../../codegen.zig").FnResult;27const FnResult = @import("../../codegen.zig").FnResult;
27const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;28const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;
28const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;29const 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
30const InnerError = error{37const InnerError = error{
31 OutOfMemory,38 OutOfMemory,
32 CodegenFail,39 CodegenFail,
...@@ -75,7 +82,7 @@ branch_stack: *std.ArrayList(Branch),...@@ -75,7 +82,7 @@ branch_stack: *std.ArrayList(Branch),
75// Key is the block instruction82// Key is the block instruction
76blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},83blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
7784
78register_manager: RegisterManager(Self, Register, &callee_preserved_regs) = .{},85register_manager: RegisterManager = .{},
79/// Maps offset to what is stored there.86/// Maps offset to what is stored there.
80stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},87stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
8188
...@@ -1230,7 +1237,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind...@@ -1230,7 +1237,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
1230 .register => |reg| {1237 .register => |reg| {
1231 // If it's in the registers table, need to associate the register with the1238 // If it's in the registers table, need to associate the register with the
1232 // new instruction.1239 // new instruction.
1233 if (reg.allocIndex()) |index| {1240 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
1234 if (!self.register_manager.isRegFree(reg)) {1241 if (!self.register_manager.isRegFree(reg)) {
1235 self.register_manager.registers[index] = inst;1242 self.register_manager.registers[index] = inst;
1236 }1243 }
...@@ -1545,7 +1552,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1545,7 +1552,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
1545 const result: MCValue = result: {1552 const result: MCValue = result: {
1546 switch (info.return_value) {1553 switch (info.return_value) {
1547 .register => |reg| {1554 .register => |reg| {
1548 if (Register.allocIndex(reg) == null) {1555 if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
1549 // Save function return value in a callee saved register1556 // Save function return value in a callee saved register
1550 break :result try self.copyToNewRegister(inst, info.return_value);1557 break :result try self.copyToNewRegister(inst, info.return_value);
1551 }1558 }
...@@ -2549,10 +2556,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro...@@ -2549,10 +2556,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
2549 return error.CodegenFail;2556 return error.CodegenFail;
2550}2557}
25512558
2552const Register = @import("bits.zig").Register;
2553const Instruction = @import("bits.zig").Instruction;
2554const callee_preserved_regs = @import("bits.zig").callee_preserved_regs;
2555
2556fn parseRegName(name: []const u8) ?Register {2559fn parseRegName(name: []const u8) ?Register {
2557 if (@hasDecl(Register, "parseRegName")) {2560 if (@hasDecl(Register, "parseRegName")) {
2558 return Register.parseRegName(name);2561 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) {...@@ -409,14 +409,6 @@ pub const Register = enum(u6) {
409 return @truncate(u5, @enumToInt(self));409 return @truncate(u5, @enumToInt(self));
410 }410 }
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
420 pub fn dwarfLocOp(reg: Register) u8 {412 pub fn dwarfLocOp(reg: Register) u8 {
421 return @as(u8, reg.id()) + DW.OP.reg0;413 return @as(u8, reg.id()) + DW.OP.reg0;
422 }414 }
...@@ -424,10 +416,6 @@ pub const Register = enum(u6) {...@@ -424,10 +416,6 @@ pub const Register = enum(u6) {
424416
425// zig fmt: on417// 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
431test "serialize instructions" {419test "serialize instructions" {
432 const Testcase = struct {420 const Testcase = struct {
433 inst: Instruction,421 inst: Instruction,
src/arch/x86/bits.zig+4-17
...@@ -4,16 +4,16 @@ const DW = std.dwarf;...@@ -4,16 +4,16 @@ const DW = std.dwarf;
4// zig fmt: off4// zig fmt: off
5pub const Register = enum(u8) {5pub const Register = enum(u8) {
6 // 0 through 7, 32-bit registers. id is int value6 // 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
9 // 8-15, 16-bit registers. id is int value - 8.9 // 8-15, 16-bit registers. id is int value - 8.
10 ax, cx, dx, bx, sp, bp, si, di,10 ax, cx, dx, bx, sp, bp, si, di,
11 11
12 // 16-23, 8-bit registers. id is int value - 16.12 // 16-23, 8-bit registers. id is int value - 16.
13 al, cl, dl, bl, ah, ch, dh, bh,13 al, cl, dl, bl, ah, ch, dh, bh,
1414
15 /// Returns the bit-width of the register.15 /// Returns the bit-width of the register.
16 pub fn size(self: @This()) u7 {16 pub fn size(self: Register) u7 {
17 return switch (@enumToInt(self)) {17 return switch (@enumToInt(self)) {
18 0...7 => 32,18 0...7 => 32,
19 8...15 => 16,19 8...15 => 16,
...@@ -25,22 +25,10 @@ pub const Register = enum(u8) {...@@ -25,22 +25,10 @@ pub const Register = enum(u8) {
25 /// Returns the register's id. This is used in practically every opcode the25 /// Returns the register's id. This is used in practically every opcode the
26 /// x86 has. It is embedded in some instructions, such as the `B8 +rd` move26 /// x86 has. It is embedded in some instructions, such as the `B8 +rd` move
27 /// instruction, and is used in the R/M byte.27 /// instruction, and is used in the R/M byte.
28 pub fn id(self: @This()) u3 {28 pub fn id(self: Register) u3 {
29 return @truncate(u3, @enumToInt(self));29 return @truncate(u3, @enumToInt(self));
30 }30 }
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
44 /// Convert from any register to its 32 bit alias.32 /// Convert from any register to its 32 bit alias.
45 pub fn to32(self: Register) Register {33 pub fn to32(self: Register) Register {
46 return @intToEnum(Register, @as(u8, self.id()));34 return @intToEnum(Register, @as(u8, self.id()));
...@@ -56,7 +44,6 @@ pub const Register = enum(u8) {...@@ -56,7 +44,6 @@ pub const Register = enum(u8) {
56 return @intToEnum(Register, @as(u8, self.id()) + 16);44 return @intToEnum(Register, @as(u8, self.id()) + 16);
57 }45 }
5846
59
60 pub fn dwarfLocOp(reg: Register) u8 {47 pub fn dwarfLocOp(reg: Register) u8 {
61 return switch (reg.to32()) {48 return switch (reg.to32()) {
62 .eax => DW.OP.reg0,49 .eax => DW.OP.reg0,
src/arch/x86_64/CodeGen.zig+9-14
...@@ -27,6 +27,13 @@ const Type = @import("../../type.zig").Type;...@@ -27,6 +27,13 @@ const Type = @import("../../type.zig").Type;
27const TypedValue = @import("../../TypedValue.zig");27const TypedValue = @import("../../TypedValue.zig");
28const Value = @import("../../value.zig").Value;28const 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
30const InnerError = error{37const InnerError = error{
31 OutOfMemory,38 OutOfMemory,
32 CodegenFail,39 CodegenFail,
...@@ -2336,7 +2343,7 @@ fn reuseOperand(...@@ -2336,7 +2343,7 @@ fn reuseOperand(
2336 .register => |reg| {2343 .register => |reg| {
2337 // If it's in the registers table, need to associate the register with the2344 // If it's in the registers table, need to associate the register with the
2338 // new instruction.2345 // new instruction.
2339 if (reg.allocIndex()) |index| {2346 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
2340 if (!self.register_manager.isRegFree(reg)) {2347 if (!self.register_manager.isRegFree(reg)) {
2341 self.register_manager.registers[index] = inst;2348 self.register_manager.registers[index] = inst;
2342 }2349 }
...@@ -3483,7 +3490,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3483,7 +3490,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3483 const result: MCValue = result: {3490 const result: MCValue = result: {
3484 switch (info.return_value) {3491 switch (info.return_value) {
3485 .register => |reg| {3492 .register => |reg| {
3486 if (Register.allocIndex(reg) == null) {3493 if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {
3487 // Save function return value in a callee saved register3494 // Save function return value in a callee saved register
3488 break :result try self.copyToRegisterWithInstTracking(3495 break :result try self.copyToRegisterWithInstTracking(
3489 inst,3496 inst,
...@@ -5966,18 +5973,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro...@@ -5966,18 +5973,6 @@ fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerErro
5966 return error.CodegenFail;5973 return error.CodegenFail;
5967}5974}
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
5981fn parseRegName(name: []const u8) ?Register {5976fn parseRegName(name: []const u8) ?Register {
5982 if (@hasDecl(Register, "parseRegName")) {5977 if (@hasDecl(Register, "parseRegName")) {
5983 return Register.parseRegName(name);5978 return Register.parseRegName(name);
src/arch/x86_64/Emit.zig+2-1
...@@ -6,6 +6,7 @@ const Emit = @This();...@@ -6,6 +6,7 @@ const Emit = @This();
6const std = @import("std");6const std = @import("std");
7const assert = std.debug.assert;7const assert = std.debug.assert;
8const bits = @import("bits.zig");8const bits = @import("bits.zig");
9const abi = @import("abi.zig");
9const leb128 = std.leb;10const leb128 = std.leb;
10const link = @import("../../link.zig");11const link = @import("../../link.zig");
11const log = std.log.scoped(.codegen);12const log = std.log.scoped(.codegen);
...@@ -265,7 +266,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I...@@ -265,7 +266,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I
265 const data = emit.mir.extraData(Mir.RegsToPushOrPop, payload).data;266 const data = emit.mir.extraData(Mir.RegsToPushOrPop, payload).data;
266 const regs = data.regs;267 const regs = data.regs;
267 var disp: u32 = data.disp + 8;268 var disp: u32 = data.disp + 8;
268 for (bits.callee_preserved_regs) |reg, i| {269 for (abi.callee_preserved_regs) |reg, i| {
269 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;270 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
270 if (tag == .push) {271 if (tag == .push) {
271 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{272 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
src/arch/x86_64/PrintMir.zig+2-1
...@@ -5,6 +5,7 @@ const Print = @This();...@@ -5,6 +5,7 @@ const Print = @This();
5const std = @import("std");5const std = @import("std");
6const assert = std.debug.assert;6const assert = std.debug.assert;
7const bits = @import("bits.zig");7const bits = @import("bits.zig");
8const abi = @import("abi.zig");
8const leb128 = std.leb;9const leb128 = std.leb;
9const link = @import("../../link.zig");10const link = @import("../../link.zig");
10const log = std.log.scoped(.codegen);11const log = std.log.scoped(.codegen);
...@@ -188,7 +189,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(print: *const Print, tag: Mir.Inst.Tag,...@@ -188,7 +189,7 @@ fn mirPushPopRegsFromCalleePreservedRegs(print: *const Print, tag: Mir.Inst.Tag,
188 var disp: u32 = data.disp + 8;189 var disp: u32 = data.disp + 8;
189 if (regs == 0) return w.writeAll("no regs from callee_preserved_regs\n");190 if (regs == 0) return w.writeAll("no regs from callee_preserved_regs\n");
190 var printed_first_reg = false;191 var printed_first_reg = false;
191 for (bits.callee_preserved_regs) |reg, i| {192 for (abi.callee_preserved_regs) |reg, i| {
192 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;193 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
193 if (printed_first_reg) try w.writeAll(" ");194 if (printed_first_reg) try w.writeAll(" ");
194 printed_first_reg = true;195 printed_first_reg = true;
src/arch/x86_64/abi.zig+7
...@@ -2,6 +2,7 @@ const std = @import("std");...@@ -2,6 +2,7 @@ const std = @import("std");
2const Type = @import("../../type.zig").Type;2const Type = @import("../../type.zig").Type;
3const Target = std.Target;3const Target = std.Target;
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const Register = @import("bits.zig").Register;
56
6pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none };7pub 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 {...@@ -370,3 +371,9 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
370 else => unreachable,371 else => unreachable,
371 }372 }
372}373}
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) {...@@ -30,14 +30,14 @@ pub const Register = enum(u7) {
3030
31 // 16 through 31, 32-bit registers. 24-31 are extended.31 // 16 through 31, 32-bit registers. 24-31 are extended.
32 // id is int value - 16.32 // id is int value - 16.
33 eax, ecx, edx, ebx, esp, ebp, esi, edi, 33 eax, ecx, edx, ebx, esp, ebp, esi, edi,
34 r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d,34 r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d,
3535
36 // 32-47, 16-bit registers. 40-47 are extended.36 // 32-47, 16-bit registers. 40-47 are extended.
37 // id is int value - 32.37 // id is int value - 32.
38 ax, cx, dx, bx, sp, bp, si, di,38 ax, cx, dx, bx, sp, bp, si, di,
39 r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w,39 r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w,
40 40
41 // 48-63, 8-bit registers. 56-63 are extended.41 // 48-63, 8-bit registers. 56-63 are extended.
42 // id is int value - 48.42 // id is int value - 48.
43 al, cl, dl, bl, ah, ch, dh, bh,43 al, cl, dl, bl, ah, ch, dh, bh,
...@@ -81,20 +81,6 @@ pub const Register = enum(u7) {...@@ -81,20 +81,6 @@ pub const Register = enum(u7) {
81 return @truncate(u3, @enumToInt(self));81 return @truncate(u3, @enumToInt(self));
82 }82 }
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
98 /// Convert from any register to its 64 bit alias.84 /// Convert from any register to its 64 bit alias.
99 pub fn to64(self: Register) Register {85 pub fn to64(self: Register) Register {
100 return @intToEnum(Register, self.id());86 return @intToEnum(Register, self.id());
...@@ -142,13 +128,6 @@ pub const Register = enum(u7) {...@@ -142,13 +128,6 @@ pub const Register = enum(u7) {
142128
143// zig fmt: on129// 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
152/// Encoding helper functions for x86_64 instructions131/// Encoding helper functions for x86_64 instructions
153///132///
154/// Many of these helpers do very little, but they can help make things133/// 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(...@@ -61,7 +61,7 @@ pub fn RegisterManager(
61 }61 }
6262
63 fn getRegisterMask(reg: Register) ?FreeRegInt {63 fn getRegisterMask(reg: Register) ?FreeRegInt {
64 const index = reg.allocIndex() orelse return null;64 const index = indexOfRegIntoTracked(reg) orelse return null;
65 const shift = @intCast(ShiftInt, index);65 const shift = @intCast(ShiftInt, index);
66 const mask = @as(FreeRegInt, 1) << shift;66 const mask = @as(FreeRegInt, 1) << shift;
67 return mask;67 return mask;
...@@ -82,6 +82,17 @@ pub fn RegisterManager(...@@ -82,6 +82,17 @@ pub fn RegisterManager(
82 self.free_registers |= mask;82 self.free_registers |= mask;
83 }83 }
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
85 /// Returns true when this register is not tracked96 /// Returns true when this register is not tracked
86 pub fn isRegFree(self: Self, reg: Register) bool {97 pub fn isRegFree(self: Self, reg: Register) bool {
87 const mask = getRegisterMask(reg) orelse return true;98 const mask = getRegisterMask(reg) orelse return true;
...@@ -157,7 +168,7 @@ pub fn RegisterManager(...@@ -157,7 +168,7 @@ pub fn RegisterManager(
157168
158 if (insts[j]) |inst| {169 if (insts[j]) |inst| {
159 // Track the register170 // Track the register
160 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null171 const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
161 self.registers[index] = inst;172 self.registers[index] = inst;
162 self.markRegUsed(reg);173 self.markRegUsed(reg);
163 }174 }
...@@ -196,7 +207,7 @@ pub fn RegisterManager(...@@ -196,7 +207,7 @@ pub fn RegisterManager(
196207
197 regs[i] = reg;208 regs[i] = reg;
198 self.markRegAllocated(reg);209 self.markRegAllocated(reg);
199 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null210 const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
200 if (insts[i]) |inst| {211 if (insts[i]) |inst| {
201 // Track the register212 // Track the register
202 if (self.isRegFree(reg)) {213 if (self.isRegFree(reg)) {
...@@ -235,7 +246,7 @@ pub fn RegisterManager(...@@ -235,7 +246,7 @@ pub fn RegisterManager(
235 /// corresponding instruction is passed, will also track this246 /// corresponding instruction is passed, will also track this
236 /// register.247 /// register.
237 pub fn getReg(self: *Self, reg: Register, inst: ?Air.Inst.Index) AllocateRegistersError!void {248 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;
239 self.markRegAllocated(reg);250 self.markRegAllocated(reg);
240251
241 if (inst) |tracked_inst|252 if (inst) |tracked_inst|
...@@ -263,7 +274,7 @@ pub fn RegisterManager(...@@ -263,7 +274,7 @@ pub fn RegisterManager(
263 /// instruction. Asserts that the register is free and no274 /// instruction. Asserts that the register is free and no
264 /// spilling is necessary.275 /// spilling is necessary.
265 pub fn getRegAssumeFree(self: *Self, reg: Register, inst: Air.Inst.Index) void {276 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;
267 self.markRegAllocated(reg);278 self.markRegAllocated(reg);
268279
269 assert(self.isRegFree(reg));280 assert(self.isRegFree(reg));
...@@ -273,7 +284,7 @@ pub fn RegisterManager(...@@ -273,7 +284,7 @@ pub fn RegisterManager(
273284
274 /// Marks the specified register as free285 /// Marks the specified register as free
275 pub fn freeReg(self: *Self, reg: Register) void {286 pub fn freeReg(self: *Self, reg: Register) void {
276 const index = reg.allocIndex() orelse return;287 const index = indexOfRegIntoTracked(reg) orelse return;
277 log.debug("freeing register {}", .{reg});288 log.debug("freeing register {}", .{reg});
278289
279 self.registers[index] = undefined;290 self.registers[index] = undefined;
...@@ -288,11 +299,8 @@ const MockRegister1 = enum(u2) {...@@ -288,11 +299,8 @@ const MockRegister1 = enum(u2) {
288 r2,299 r2,
289 r3,300 r3,
290301
291 pub fn allocIndex(self: MockRegister1) ?u2 {302 pub fn id(reg: MockRegister1) u2 {
292 inline for (callee_preserved_regs) |cpreg, i| {303 return @enumToInt(reg);
293 if (self == cpreg) return i;
294 }
295 return null;
296 }304 }
297305
298 const callee_preserved_regs = [_]MockRegister1{ .r2, .r3 };306 const callee_preserved_regs = [_]MockRegister1{ .r2, .r3 };
...@@ -304,11 +312,8 @@ const MockRegister2 = enum(u2) {...@@ -304,11 +312,8 @@ const MockRegister2 = enum(u2) {
304 r2,312 r2,
305 r3,313 r3,
306314
307 pub fn allocIndex(self: MockRegister2) ?u2 {315 pub fn id(reg: MockRegister2) u2 {
308 inline for (callee_preserved_regs) |cpreg, i| {316 return @enumToInt(reg);
309 if (self == cpreg) return i;
310 }
311 return null;
312 }317 }
313318
314 const callee_preserved_regs = [_]MockRegister2{ .r0, .r1, .r2, .r3 };319 const callee_preserved_regs = [_]MockRegister2{ .r0, .r1, .r2, .r3 };