From d447cd940d7da884f0d699d9da679d8bbabb237a Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 29 Mar 2022 11:50:25 +0200 Subject: 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). --- src/arch/x86_64/CodeGen.zig | 10 ++++++++-- src/arch/x86_64/abi.zig | 11 ++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 744c7fbf75..854017054b 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -31,6 +31,8 @@ const bits = @import("bits.zig"); const abi = @import("abi.zig"); const Register = bits.Register; const callee_preserved_regs = abi.callee_preserved_regs; +const caller_preserved_regs = abi.caller_preserved_regs; +const allocatable_registers = abi.allocatable_registers; const c_abi_int_param_regs = abi.c_abi_int_param_regs; const c_abi_int_return_regs = abi.c_abi_int_return_regs; @@ -40,7 +42,7 @@ const InnerError = error{ OutOfRegisters, }; -const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs); +const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers); gpa: Allocator, air: Air, @@ -3519,6 +3521,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. try self.spillCompareFlagsIfOccupied(); + for (caller_preserved_regs) |reg| { + try self.register_manager.getReg(reg, null); + } + if (info.return_value == .stack_offset) { const ret_ty = fn_ty.fnReturnType(); 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. const result: MCValue = result: { switch (info.return_value) { .register => |reg| { - if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) { + if (RegisterManager.indexOfRegIntoTracked(reg) == null) { // Save function return value in a callee saved register break :result try self.copyToRegisterWithInstTracking( inst, diff --git a/src/arch/x86_64/abi.zig b/src/arch/x86_64/abi.zig index 9fd09ab60a..4afa3ad792 100644 --- a/src/arch/x86_64/abi.zig +++ b/src/arch/x86_64/abi.zig @@ -370,8 +370,13 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { } } -/// 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 }; +/// Note that .rsp and .rbp also belong to this set, however, we never expect to use them +/// for anything else but stack offset tracking therefore we exclude them from this set. +pub const callee_preserved_regs = [_]Register{ .rbx, .r12, .r13, .r14, .r15 }; +/// These registers need to be preserved (saved on the stack) and restored by the caller before +/// the caller relinquishes control to a subroutine via call instruction (or similar). +/// In other words, these registers are free to use by the callee. +pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 }; +pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs; pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 }; pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx }; -- cgit v1.2.3