[llvm] [AArch64] Fix x18 being used by nest ptrs with MSVC ABI (PR #68008)

via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 2 10:10:20 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

<details>
<summary>Changes</summary>

This patch fixes an issue where x18 is used for passing pointer parameters with
the nest attribute on Windows on AArch64. The x18 register is reserved in the
WoA ABI so can't be used for this purpose. This is fixed by introducing a new
Win64PCS calling convention that differs from the standard AAPCS only by not
using x18 for nest parameters.


---
Full diff: https://github.com/llvm/llvm-project/pull/68008.diff


6 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64CallingConvention.h (+3) 
- (modified) llvm/lib/Target/AArch64/AArch64CallingConvention.td (+15-9) 
- (modified) llvm/lib/Target/AArch64/AArch64FastISel.cpp (+5-1) 
- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+8-5) 
- (modified) llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp (+15-3) 
- (added) llvm/test/CodeGen/AArch64/win64cc-x18.ll (+36) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64CallingConvention.h b/llvm/lib/Target/AArch64/AArch64CallingConvention.h
index d7ab83c946ce063..608a50689cc5b9e 100644
--- a/llvm/lib/Target/AArch64/AArch64CallingConvention.h
+++ b/llvm/lib/Target/AArch64/AArch64CallingConvention.h
@@ -31,6 +31,9 @@ bool CC_AArch64_DarwinPCS(unsigned ValNo, MVT ValVT, MVT LocVT,
 bool CC_AArch64_DarwinPCS_ILP32_VarArg(unsigned ValNo, MVT ValVT, MVT LocVT,
                           CCValAssign::LocInfo LocInfo,
                           ISD::ArgFlagsTy ArgFlags, CCState &State);
+bool CC_AArch64_Win64PCS(unsigned ValNo, MVT ValVT, MVT LocVT,
+                         CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
+                         CCState &State);
 bool CC_AArch64_Win64_VarArg(unsigned ValNo, MVT ValVT, MVT LocVT,
                              CCValAssign::LocInfo LocInfo,
                              ISD::ArgFlagsTy ArgFlags, CCState &State);
diff --git a/llvm/lib/Target/AArch64/AArch64CallingConvention.td b/llvm/lib/Target/AArch64/AArch64CallingConvention.td
index 37976a222783b22..117c9cad3916f52 100644
--- a/llvm/lib/Target/AArch64/AArch64CallingConvention.td
+++ b/llvm/lib/Target/AArch64/AArch64CallingConvention.td
@@ -22,8 +22,7 @@ class CCIfILP32<CCAction A> :
 // ARM AAPCS64 Calling Convention
 //===----------------------------------------------------------------------===//
 
-let Entry = 1 in
-def CC_AArch64_AAPCS : CallingConv<[
+defvar AArch64_Common = [
   CCIfType<[iPTR], CCBitConvertToType<i64>>,
   CCIfType<[v2f32], CCBitConvertToType<v2i32>>,
   CCIfType<[v2f64, v4f32], CCBitConvertToType<v2i64>>,
@@ -58,11 +57,6 @@ def CC_AArch64_AAPCS : CallingConv<[
   // slot is 64-bit.
   CCIfByVal<CCPassByVal<8, 8>>,
 
-  // The 'nest' parameter, if any, is passed in X18.
-  // Darwin uses X18 as the platform register and hence 'nest' isn't currently
-  // supported there.
-  CCIfNest<CCAssignToReg<[X18]>>,
-
   // Pass SwiftSelf in a callee saved register.
   CCIfSwiftSelf<CCIfType<[i64], CCAssignToReg<[X20]>>>,
 
@@ -115,7 +109,16 @@ def CC_AArch64_AAPCS : CallingConv<[
            CCAssignToStack<8, 8>>,
   CCIfType<[f128, v2i64, v4i32, v8i16, v16i8, v4f32, v2f64, v8f16, v8bf16],
            CCAssignToStack<16, 16>>
-]>;
+];
+
+let Entry = 1 in
+def CC_AArch64_AAPCS : CallingConv<!listconcat(
+  // The 'nest' parameter, if any, is passed in X18.
+  // Darwin and Windows use X18 as the platform register and hence 'nest' isn't
+  // currently supported there.
+  [CCIfNest<CCAssignToReg<[X18]>>],
+  AArch64_Common
+)>;
 
 let Entry = 1 in
 def RetCC_AArch64_AAPCS : CallingConv<[
@@ -153,13 +156,16 @@ def RetCC_AArch64_AAPCS : CallingConv<[
            CCAssignToReg<[P0, P1, P2, P3]>>
 ]>;
 
+let Entry = 1 in
+def CC_AArch64_Win64PCS : CallingConv<AArch64_Common>;
+
 // Vararg functions on windows pass floats in integer registers
 let Entry = 1 in
 def CC_AArch64_Win64_VarArg : CallingConv<[
   CCIfType<[f16, bf16], CCBitConvertToType<i16>>,
   CCIfType<[f32], CCBitConvertToType<i32>>,
   CCIfType<[f64], CCBitConvertToType<i64>>,
-  CCDelegateTo<CC_AArch64_AAPCS>
+  CCDelegateTo<CC_AArch64_Win64PCS>
 ]>;
 
 // Vararg functions on Arm64EC ABI use a different convention, using
diff --git a/llvm/lib/Target/AArch64/AArch64FastISel.cpp b/llvm/lib/Target/AArch64/AArch64FastISel.cpp
index ce1c1f7d403ad23..693a254f7013f8a 100644
--- a/llvm/lib/Target/AArch64/AArch64FastISel.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FastISel.cpp
@@ -341,7 +341,11 @@ CCAssignFn *AArch64FastISel::CCAssignFnForCall(CallingConv::ID CC) const {
     return CC_AArch64_GHC;
   if (CC == CallingConv::CFGuard_Check)
     return CC_AArch64_Win64_CFGuard_Check;
-  return Subtarget->isTargetDarwin() ? CC_AArch64_DarwinPCS : CC_AArch64_AAPCS;
+  if (Subtarget->isTargetDarwin())
+    return CC_AArch64_DarwinPCS;
+  if (Subtarget->isTargetWindows())
+    return CC_AArch64_Win64PCS;
+  return CC_AArch64_AAPCS;
 }
 
 unsigned AArch64FastISel::fastMaterializeAlloca(const AllocaInst *AI) {
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 8e5ded8dd47aa15..d287885693cafae 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -6316,10 +6316,13 @@ CCAssignFn *AArch64TargetLowering::CCAssignFnForCall(CallingConv::ID CC,
   case CallingConv::Swift:
   case CallingConv::SwiftTail:
   case CallingConv::Tail:
-    if (Subtarget->isTargetWindows() && IsVarArg) {
-      if (Subtarget->isWindowsArm64EC())
-        return CC_AArch64_Arm64EC_VarArg;
-      return CC_AArch64_Win64_VarArg;
+    if (Subtarget->isTargetWindows()) {
+      if (IsVarArg) {
+        if (Subtarget->isWindowsArm64EC())
+          return CC_AArch64_Arm64EC_VarArg;
+        return CC_AArch64_Win64_VarArg;
+      }
+      return CC_AArch64_Win64PCS;
     }
     if (!Subtarget->isTargetDarwin())
       return CC_AArch64_AAPCS;
@@ -6333,7 +6336,7 @@ CCAssignFn *AArch64TargetLowering::CCAssignFnForCall(CallingConv::ID CC,
          return CC_AArch64_Arm64EC_VarArg;
        return CC_AArch64_Win64_VarArg;
      }
-     return CC_AArch64_AAPCS;
+     return CC_AArch64_Win64PCS;
    case CallingConv::CFGuard_Check:
      return CC_AArch64_Win64_CFGuard_Check;
    case CallingConv::AArch64_VectorCall:
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
index d1ddf6d76975476..cc5384613f1ab38 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
@@ -570,8 +570,18 @@ bool AArch64RegisterInfo::isArgumentRegister(const MachineFunction &MF,
   case CallingConv::Swift:
   case CallingConv::SwiftTail:
   case CallingConv::Tail:
-    if (STI.isTargetWindows() && IsVarArg)
-      return HasReg(CC_AArch64_Win64_VarArg_ArgRegs, Reg);
+    if (STI.isTargetWindows()) {
+      if (IsVarArg)
+        return HasReg(CC_AArch64_Win64_VarArg_ArgRegs, Reg);
+      switch (CC) {
+      default:
+        return HasReg(CC_AArch64_Win64PCS_ArgRegs, Reg);
+      case CallingConv::Swift:
+      case CallingConv::SwiftTail:
+        return HasReg(CC_AArch64_Win64PCS_Swift_ArgRegs, Reg) ||
+               HasReg(CC_AArch64_Win64PCS_ArgRegs, Reg);
+      }
+    }
     if (!STI.isTargetDarwin()) {
       switch (CC) {
       default:
@@ -598,13 +608,15 @@ bool AArch64RegisterInfo::isArgumentRegister(const MachineFunction &MF,
   case CallingConv::Win64:
     if (IsVarArg)
       HasReg(CC_AArch64_Win64_VarArg_ArgRegs, Reg);
-    return HasReg(CC_AArch64_AAPCS_ArgRegs, Reg);
+    return HasReg(CC_AArch64_Win64PCS_ArgRegs, Reg);
   case CallingConv::CFGuard_Check:
     return HasReg(CC_AArch64_Win64_CFGuard_Check_ArgRegs, Reg);
   case CallingConv::AArch64_VectorCall:
   case CallingConv::AArch64_SVE_VectorCall:
   case CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0:
   case CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2:
+    if (STI.isTargetWindows())
+      return HasReg(CC_AArch64_Win64PCS_ArgRegs, Reg);
     return HasReg(CC_AArch64_AAPCS_ArgRegs, Reg);
   }
 }
diff --git a/llvm/test/CodeGen/AArch64/win64cc-x18.ll b/llvm/test/CodeGen/AArch64/win64cc-x18.ll
new file mode 100644
index 000000000000000..b3e78cc9bbb8100
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/win64cc-x18.ll
@@ -0,0 +1,36 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+
+;; Testing that x18 is not clobbered when passing pointers with the nest
+;; attribute on windows
+
+; RUN: llc < %s -mtriple=aarch64-pc-windows-msvc | FileCheck %s --check-prefixes=CHECK,CHECK-NO-X18
+; RUN: llc < %s -mtriple=aarch64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-X18
+
+define dso_local i64 @other(ptr nest %p) #0 {
+; CHECK-LABEL: other:
+; CHECK-X18: ldr x0, [x18]
+; CHECK-NO-X18: ldr x0, [x0]
+  %r = load i64, ptr %p
+; CHECK: ret
+  ret i64 %r
+}
+
+define dso_local void @func() #0 {
+; CHECK-LABEL: func:
+
+
+entry:
+  %p = alloca i64
+; CHECK: mov w8, #1
+; CHECK: stp x30, x8, [sp, #-16]
+; CHECK-X18: add x18, sp, #8
+  store i64 1, ptr %p
+; CHECK-NO-X18: add x0, sp, #8
+; CHECK: bl other
+  call void @other(ptr nest %p)
+; CHECK: ldr x30, [sp], #16
+; CHECK: ret
+  ret void
+}
+
+attributes #0 = { nounwind }

``````````

</details>


https://github.com/llvm/llvm-project/pull/68008


More information about the llvm-commits mailing list