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).
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user