diff --git a/llvm/lib/Target/AArch64/AArch64CallingConvention.td b/llvm/lib/Target/AArch64/AArch64CallingConvention.td --- a/llvm/lib/Target/AArch64/AArch64CallingConvention.td +++ b/llvm/lib/Target/AArch64/AArch64CallingConvention.td @@ -444,6 +444,15 @@ def CSR_Darwin_AArch64_AAVPCS : CalleeSavedRegs<(add LR, FP, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, (sequence "Q%u", 8, 23))>; + +// For Windows calling convention on a non-windows OS, where X18 is treated +// as reserved, back up X18 when entering non-windows code (marked with the +// Windows calling convention) and restore when returning regardless of +// whether the individual function uses it - it might call other functions +// that clobber it. +def CSR_Darwin_AArch64_AAPCS_Win64 + : CalleeSavedRegs<(add CSR_Darwin_AArch64_AAPCS, X18)>; + def CSR_Darwin_AArch64_AAPCS_ThisReturn : CalleeSavedRegs<(add CSR_Darwin_AArch64_AAPCS, X0)>; diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -2522,8 +2522,8 @@ (void)CC; // MachO's compact unwind format relies on all registers being stored in // pairs. - assert((!produceCompactUnwindFrame(MF) || - CC == CallingConv::PreserveMost || CC == CallingConv::CXX_FAST_TLS || + assert((!produceCompactUnwindFrame(MF) || CC == CallingConv::PreserveMost || + CC == CallingConv::CXX_FAST_TLS || CC == CallingConv::Win64 || (Count & 1) == 0) && "Odd number of callee-saved regs to spill!"); int ByteOffset = AFI->getCalleeSavedStackSize(); @@ -2608,8 +2608,8 @@ // MachO's compact unwind format relies on all registers being stored in // adjacent register pairs. - assert((!produceCompactUnwindFrame(MF) || - CC == CallingConv::PreserveMost || CC == CallingConv::CXX_FAST_TLS || + assert((!produceCompactUnwindFrame(MF) || CC == CallingConv::PreserveMost || + CC == CallingConv::CXX_FAST_TLS || CC == CallingConv::Win64 || (RPI.isPaired() && ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) || RPI.Reg1 + 1 == RPI.Reg2))) && diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp --- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -135,6 +135,8 @@ return CSR_Darwin_AArch64_AAPCS_SwiftTail_SaveList; if (MF->getFunction().getCallingConv() == CallingConv::PreserveMost) return CSR_Darwin_AArch64_RT_MostRegs_SaveList; + if (MF->getFunction().getCallingConv() == CallingConv::Win64) + return CSR_Darwin_AArch64_AAPCS_Win64_SaveList; return CSR_Darwin_AArch64_AAPCS_SaveList; } diff --git a/llvm/test/CodeGen/AArch64/win64cc-darwin-backup-x18.ll b/llvm/test/CodeGen/AArch64/win64cc-darwin-backup-x18.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/win64cc-darwin-backup-x18.ll @@ -0,0 +1,31 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py + +;; Testing that x18 is backed up and restored, and that x29 (if used) still +;; points to the x29,x30 pair on the stack. + +; RUN: llc < %s -mtriple=arm64-apple-darwin | FileCheck %s +; RUN: llc < %s -mtriple=arm64-apple-darwin -mattr=+reserve-x18 | FileCheck %s + +declare dso_local void @other() + +define win64cc void @func(i32 noundef %0) #0 { +; CHECK-LABEL: func: +; CHECK: ; %bb.0: ; %entry +; CHECK-NEXT: str x18, [sp, #-32]! ; 8-byte Folded Spill +; CHECK-NEXT: stp x29, x30, [sp, #16] ; 16-byte Folded Spill +; CHECK: ldp x29, x30, [sp, #16] ; 16-byte Folded Reload +; CHECK-NEXT: ldr x18, [sp], #32 ; 8-byte Folded Reload +; CHECK-NEXT: ret +entry: + %al = alloca i32, align 4 + store i32 %0, ptr %al, align 4 + tail call void @other() + ret void +} + +define i32 @main() { + call win64cc void @func(i32 noundef 17) + ret i32 0 +} + +attributes #0 = { nounwind }