authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-29 11:50:25+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-30 00:37:42+02:00
logd447cd940d7da884f0d699d9da679d8bbabb237a
treee5a70bc4491a70498c4b4c3af473c9503410bbbd
parent60879bc8ae216ddd33fab2e07d1d460e32636c95

x64: track callee and caller saved registers

This is now required to correctly track and spill registers required for some ops such `mul` or `div` (both required use of `.rax` and `.rdx` registers).

2 files changed, 16 insertions(+), 5 deletions(-)

src/arch/x86_64/CodeGen.zig+8-2
...@@ -31,6 +31,8 @@ const bits = @import("bits.zig");...@@ -31,6 +31,8 @@ const bits = @import("bits.zig");
31const abi = @import("abi.zig");31const abi = @import("abi.zig");
32const Register = bits.Register;32const Register = bits.Register;
33const callee_preserved_regs = abi.callee_preserved_regs;33const callee_preserved_regs = abi.callee_preserved_regs;
34const caller_preserved_regs = abi.caller_preserved_regs;
35const allocatable_registers = abi.allocatable_registers;
34const c_abi_int_param_regs = abi.c_abi_int_param_regs;36const c_abi_int_param_regs = abi.c_abi_int_param_regs;
35const c_abi_int_return_regs = abi.c_abi_int_return_regs;37const c_abi_int_return_regs = abi.c_abi_int_return_regs;
3638
...@@ -40,7 +42,7 @@ const InnerError = error{...@@ -40,7 +42,7 @@ const InnerError = error{
40 OutOfRegisters,42 OutOfRegisters,
41};43};
4244
43const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs);45const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers);
4446
45gpa: Allocator,47gpa: Allocator,
46air: Air,48air: Air,
...@@ -3519,6 +3521,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3519,6 +3521,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
35193521
3520 try self.spillCompareFlagsIfOccupied();3522 try self.spillCompareFlagsIfOccupied();
35213523
3524 for (caller_preserved_regs) |reg| {
3525 try self.register_manager.getReg(reg, null);
3526 }
3527
3522 if (info.return_value == .stack_offset) {3528 if (info.return_value == .stack_offset) {
3523 const ret_ty = fn_ty.fnReturnType();3529 const ret_ty = fn_ty.fnReturnType();
3524 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));3530 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
...@@ -3715,7 +3721,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3715,7 +3721,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3715 const result: MCValue = result: {3721 const result: MCValue = result: {
3716 switch (info.return_value) {3722 switch (info.return_value) {
3717 .register => |reg| {3723 .register => |reg| {
3718 if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) {3724 if (RegisterManager.indexOfRegIntoTracked(reg) == null) {
3719 // Save function return value in a callee saved register3725 // Save function return value in a callee saved register
3720 break :result try self.copyToRegisterWithInstTracking(3726 break :result try self.copyToRegisterWithInstTracking(
3721 inst,3727 inst,
src/arch/x86_64/abi.zig+8-3
...@@ -370,8 +370,13 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {...@@ -370,8 +370,13 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
370 }370 }
371}371}
372372
373/// These registers need to be preserved (saved on the stack) and restored by the callee before getting clobbered373/// Note that .rsp and .rbp also belong to this set, however, we never expect to use them
374/// and when the callee returns.374/// for anything else but stack offset tracking therefore we exclude them from this set.
375pub const callee_preserved_regs = [_]Register{ .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11 };375pub const callee_preserved_regs = [_]Register{ .rbx, .r12, .r13, .r14, .r15 };
376/// These registers need to be preserved (saved on the stack) and restored by the caller before
377/// the caller relinquishes control to a subroutine via call instruction (or similar).
378/// In other words, these registers are free to use by the callee.
379pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
380pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs;
376pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };381pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
377pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };382pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };