| author | |
| committer | |
| log | d447cd940d7da884f0d699d9da679d8bbabb237a |
| tree | e5a70bc4491a70498c4b4c3af473c9503410bbbd |
| parent | 60879bc8ae216ddd33fab2e07d1d460e32636c95 |
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 | 31 | const abi = @import("abi.zig"); |
| 32 | 32 | const Register = bits.Register; |
| 33 | 33 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 34 | const caller_preserved_regs = abi.caller_preserved_regs; | |
| 35 | const allocatable_registers = abi.allocatable_registers; | |
| 34 | 36 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 35 | 37 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 36 | 38 | |
| ... | ... | @@ -40,7 +42,7 @@ const InnerError = error{ |
| 40 | 42 | OutOfRegisters, |
| 41 | 43 | }; |
| 42 | 44 | |
| 43 | const RegisterManager = RegisterManagerFn(Self, Register, &callee_preserved_regs); | |
| 45 | const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers); | |
| 44 | 46 | |
| 45 | 47 | gpa: Allocator, |
| 46 | 48 | air: Air, |
| ... | ... | @@ -3519,6 +3521,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3519 | 3521 | |
| 3520 | 3522 | try self.spillCompareFlagsIfOccupied(); |
| 3521 | 3523 | |
| 3524 | for (caller_preserved_regs) |reg| { | |
| 3525 | try self.register_manager.getReg(reg, null); | |
| 3526 | } | |
| 3527 | ||
| 3522 | 3528 | if (info.return_value == .stack_offset) { |
| 3523 | 3529 | const ret_ty = fn_ty.fnReturnType(); |
| 3524 | 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 | 3721 | const result: MCValue = result: { |
| 3716 | 3722 | switch (info.return_value) { |
| 3717 | 3723 | .register => |reg| { |
| 3718 | if (RegisterManager.indexOfReg(&callee_preserved_regs, reg) == null) { | |
| 3724 | if (RegisterManager.indexOfRegIntoTracked(reg) == null) { | |
| 3719 | 3725 | // Save function return value in a callee saved register |
| 3720 | 3726 | break :result try self.copyToRegisterWithInstTracking( |
| 3721 | 3727 | inst, |
src/arch/x86_64/abi.zig+8-3| ... | ... | @@ -370,8 +370,13 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 370 | 370 | } |
| 371 | 371 | } |
| 372 | 372 | |
| 373 | /// These registers need to be preserved (saved on the stack) and restored by the callee before getting clobbered | |
| 374 | /// and when the callee returns. | |
| 375 | pub const callee_preserved_regs = [_]Register{ .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11 }; | |
| 373 | /// Note that .rsp and .rbp also belong to this set, however, we never expect to use them | |
| 374 | /// for anything else but stack offset tracking therefore we exclude them from this set. | |
| 375 | pub 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. | |
| 379 | pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 }; | |
| 380 | pub const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs; | |
| 376 | 381 | pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 }; |
| 377 | 382 | pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx }; |