[llvm] 429afac - [aarch64] Mix the frame pointer with the stack cookie when protecting the stack (#197346)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 1 00:34:02 PDT 2026


Author: Pan Tao
Date: 2026-07-01T15:33:56+08:00
New Revision: 429afacb27aaa0ce66920e9cbab47028d182bd8b

URL: https://github.com/llvm/llvm-project/commit/429afacb27aaa0ce66920e9cbab47028d182bd8b
DIFF: https://github.com/llvm/llvm-project/commit/429afacb27aaa0ce66920e9cbab47028d182bd8b.diff

LOG: [aarch64] Mix the frame pointer with the stack cookie when protecting the stack (#197346)

For MSVC-compatible targets on AArch64, mix the stack cookie with the
frame pointer (FP) to create a position-dependent guard value. This
strengthens protection against attacks where the attacker knows or can
predict the cookie value, as they would also need to know the exact
frame pointer location.

Implementation details:
- Uses SUB (FP - Cookie) instead of XOR like X86 because:
  * SUB maintains the existing AArch64 instruction selection patterns
  * SUB provides equivalent security properties (bijective mixing)
  * The result is still unpredictable without knowing both inputs
- The same SUB operation is performed in both prologue (to store the
  mixed value) and epilogue (to unmix and verify the cookie)
- Forces frame pointer usage for functions with stack guards on MSVCRT
  to ensure consistent addressing with dynamic stack allocation

This matches the MSVC behavior and strengthens stack protection on
AArch64 Windows platforms.

Fixes #156573.

Added: 
    

Modified: 
    llvm/include/llvm/CodeGen/TargetLowering.h
    llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
    llvm/lib/CodeGen/StackProtector.cpp
    llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
    llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
    llvm/lib/Target/AArch64/AArch64ISelLowering.h
    llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
    llvm/lib/Target/AArch64/AArch64InstrInfo.td
    llvm/lib/Target/X86/X86ISelLowering.cpp
    llvm/lib/Target/X86/X86ISelLowering.h
    llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-windows.ll
    llvm/test/CodeGen/AArch64/arm64ec-indirect-call.ll
    llvm/test/CodeGen/AArch64/mingw-refptr.ll
    llvm/test/CodeGen/AArch64/stack-protector-target.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 9cab67b6e657a..09f522742da4e 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -2183,11 +2183,11 @@ class LLVM_ABI TargetLoweringBase {
   virtual Value *getSDagStackGuard(const Module &M,
                                    const LibcallLoweringInfo &Libcalls) const;
 
-  /// If this function returns true, stack protection checks should XOR the
+  /// If this function returns true, stack protection checks should mix the
   /// frame pointer (or whichever pointer is used to address locals) into the
   /// stack guard value before checking it. getIRStackGuard must return nullptr
   /// if this returns true.
-  virtual bool useStackGuardXorFP() const { return false; }
+  virtual bool useStackGuardMixFP() const { return false; }
 
   /// If the target has a standard stack protection check function that
   /// performs validation and error handling, returns the function. Otherwise,
@@ -5988,7 +5988,7 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase {
   /// LOAD_STACK_GUARD node when it is lowering Intrinsic::stackprotector.
   virtual bool useLoadStackGuardNode(const Module &M) const { return false; }
 
-  virtual SDValue emitStackGuardXorFP(SelectionDAG &DAG, SDValue Val,
+  virtual SDValue emitStackGuardMixFP(SelectionDAG &DAG, SDValue Val,
                                       const SDLoc &DL) const {
     llvm_unreachable("not implemented for this target");
   }

diff  --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 8b792aaac77c3..9567162275e4c 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -4102,11 +4102,6 @@ bool IRTranslator::emitSPDescriptorParent(StackProtectorDescriptor &SPD,
                       MachineMemOperand::MOLoad | MachineMemOperand::MOVolatile)
           .getReg(0);
 
-  if (TLI->useStackGuardXorFP()) {
-    LLVM_DEBUG(dbgs() << "Stack protector xor'ing with FP not yet implemented");
-    return false;
-  }
-
   // Retrieve guard check function, nullptr if instrumentation is inlined.
   if (const Function *GuardCheckFn = TLI->getSSPStackGuardCheck(M, *Libcalls)) {
     // This path is currently untestable on GlobalISel, since the only platform

diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index f5a4e891ce133..ba79b83f4cd54 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3134,8 +3134,12 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD,
       MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), Align,
       MachineMemOperand::MOVolatile);
 
-  if (TLI.useStackGuardXorFP())
-    GuardVal = TLI.emitStackGuardXorFP(DAG, GuardVal, dl);
+  // If cookie mixing is enabled, unmix the stored GuardVal to get back the
+  // original cookie for comparison. The prologue stored (FP - Cookie) or
+  // (FP XOR Cookie), so we apply the same operation again to unmix:
+  // FP - (FP - Cookie) = Cookie, or (FP XOR Cookie) XOR FP = Cookie.
+  if (TLI.useStackGuardMixFP())
+    GuardVal = TLI.emitStackGuardMixFP(DAG, GuardVal, dl);
 
   // If we're using function-based instrumentation, call the guard check
   // function
@@ -3169,12 +3173,12 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD,
     return;
   }
 
-  // If useLoadStackGuardNode returns true, generate LOAD_STACK_GUARD.
-  // Otherwise, emit a volatile load to retrieve the stack guard value.
+  // Load the fresh guard value for comparison.
+  // For targets that mix the cookie in LOAD_STACK_GUARD expansion, we need to
+  // load directly without using LOAD_STACK_GUARD to avoid unwanted mixing.
   SDValue Chain = DAG.getEntryNode();
-  if (TLI.useLoadStackGuardNode(M)) {
-    Guard = getLoadStackGuard(DAG, dl, Chain);
-  } else {
+  if (TLI.useStackGuardMixFP()) {
+    // Mixing targets: load cookie directly to avoid mixing in LOAD_STACK_GUARD
     if (const Value *IRGuard = TLI.getSDagStackGuard(M, DAG.getLibcalls())) {
       SDValue GuardPtr = getValue(IRGuard);
       Guard = DAG.getLoad(PtrMemTy, dl, Chain, GuardPtr,
@@ -3185,8 +3189,27 @@ void SelectionDAGBuilder::visitSPDescriptorParent(StackProtectorDescriptor &SPD,
       Ctx.diagnose(DiagnosticInfoGeneric("unable to lower stackguard"));
       Guard = DAG.getPOISON(PtrMemTy);
     }
+  } else {
+    // Non-mixing targets: use LOAD_STACK_GUARD or direct load as usual
+    if (TLI.useLoadStackGuardNode(M)) {
+      Guard = getLoadStackGuard(DAG, dl, Chain);
+    } else {
+      if (const Value *IRGuard = TLI.getSDagStackGuard(M, DAG.getLibcalls())) {
+        SDValue GuardPtr = getValue(IRGuard);
+        Guard = DAG.getLoad(PtrMemTy, dl, Chain, GuardPtr,
+                            MachinePointerInfo(IRGuard, 0), Align,
+                            MachineMemOperand::MOVolatile);
+      } else {
+        LLVMContext &Ctx = *DAG.getContext();
+        Ctx.diagnose(DiagnosticInfoGeneric("unable to lower stackguard"));
+        Guard = DAG.getPOISON(PtrMemTy);
+      }
+    }
   }
 
+  // Now both Guard (fresh cookie) and GuardVal (unmixed from stored value)
+  // contain unmixed cookie values that can be compared directly.
+
   // Perform the comparison via a getsetcc.
   SDValue Cmp = DAG.getSetCC(
       dl, TLI.getSetCCResultType(DL, *DAG.getContext(), Guard.getValueType()),
@@ -3243,8 +3266,8 @@ void SelectionDAGBuilder::visitSPDescriptorFailure(
         MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), Align,
         MachineMemOperand::MOVolatile);
 
-    if (TLI.useStackGuardXorFP())
-      GuardVal = TLI.emitStackGuardXorFP(DAG, GuardVal, dl);
+    if (TLI.useStackGuardMixFP())
+      GuardVal = TLI.emitStackGuardMixFP(DAG, GuardVal, dl);
 
     // The target provides a guard check function to validate the guard value.
     // Generate a call to that function with the content of the guard slot as
@@ -7650,8 +7673,11 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
                         MachinePointerInfo(Global, 0), Align,
                         MachineMemOperand::MOVolatile);
     }
-    if (TLI.useStackGuardXorFP())
-      Res = TLI.emitStackGuardXorFP(DAG, Res, sdl);
+    // Mix the cookie with FP if enabled. Skip if using LOAD_STACK_GUARD
+    // with post-RA mixing (AArch64 MSVCRT), as the mixing will be done during
+    // post-RA expansion of LOAD_STACK_GUARD.
+    if (TLI.useStackGuardMixFP() && !TLI.useLoadStackGuardNode(M))
+      Res = TLI.emitStackGuardMixFP(DAG, Res, sdl);
     DAG.setRoot(Chain);
     setValue(&I, Res);
     return;

diff  --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp
index cad3ea7868e37..f8134c93e50b7 100644
--- a/llvm/lib/CodeGen/StackProtector.cpp
+++ b/llvm/lib/CodeGen/StackProtector.cpp
@@ -610,7 +610,7 @@ bool InsertStackProtectors(const TargetLowering &TLI,
   // impossible to emit the check in IR, so the target *must* support stack
   // protection in SDAG.
   bool SupportsSelectionDAGSP =
-      TLI.useStackGuardXorFP() ||
+      TLI.useStackGuardMixFP() ||
       (EnableSelectionDAGSP && !TLI.getTargetMachine().Options.EnableFastISel);
   AllocaInst *AI = nullptr; // Place on stack that stores the stack guard.
   BasicBlock *FailBB = nullptr;

diff  --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 026f807124d2f..6aa8380c99c8b 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -575,6 +575,16 @@ bool AArch64FrameLowering::hasFPImpl(const MachineFunction &MF) const {
   // funclets.
   if (MF.hasEHFunclets())
     return true;
+
+  // When the stack guard is mixed with the frame pointer, a dedicated FP is
+  // required so the guard value remains stable in the presence of dynamic
+  // stack allocations (e.g. _alloca on MSVCRT).
+  if (MFI.hasStackProtectorIndex()) {
+    const auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
+    if (Subtarget.getTargetLowering()->useStackGuardMixFP())
+      return true;
+  }
+
   // Retain behavior of always omitting the FP for leaf functions when possible.
   if (MF.getTarget().Options.DisableFramePointerElim(MF))
     return true;

diff  --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 0a10ad0346d89..c4c52dbe395e8 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -31594,6 +31594,22 @@ bool AArch64TargetLowering::useLoadStackGuardNode(const Module &M) const {
   return true;
 }
 
+bool AArch64TargetLowering::useStackGuardMixFP() const {
+  // Currently only MSVC CRTs mix the frame pointer into the stack guard value.
+  return Subtarget->getTargetTriple().isOSMSVCRT();
+}
+
+SDValue AArch64TargetLowering::emitStackGuardMixFP(SelectionDAG &DAG,
+                                                   SDValue Val,
+                                                   const SDLoc &DL) const {
+  // Mix the cookie value with FP to create a position-dependent guard.
+  // Both prologue (stores FP - Cookie) and epilogue (compares FP - Cookie)
+  // use the same mixing operation: FP - Val.
+  return DAG.getNode(
+      ISD::SUB, DL, Val.getValueType(),
+      DAG.getCopyFromReg(DAG.getEntryNode(), DL, AArch64::FP, MVT::i64), Val);
+}
+
 unsigned AArch64TargetLowering::combineRepeatedFPDivisors() const {
   // Combine multiple FDIVs with the same divisor into multiple FMULs by the
   // reciprocal if there are three or more FDIVs.

diff  --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index ad67705377661..1341a4b3e03b6 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -376,6 +376,9 @@ class AArch64TargetLowering : public TargetLowering {
   }
 
   bool useLoadStackGuardNode(const Module &M) const override;
+  bool useStackGuardMixFP() const override;
+  SDValue emitStackGuardMixFP(SelectionDAG &DAG, SDValue Val,
+                              const SDLoc &DL) const override;
   TargetLoweringBase::LegalizeTypeAction
   getPreferredVectorAction(MVT VT) const override;
 

diff  --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index ca1a729dd1dd1..b2ec50ee3835c 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -2525,7 +2525,8 @@ bool AArch64InstrInfo::removeCmpToZeroOrOne(
 
 bool AArch64InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
   if (MI.getOpcode() != TargetOpcode::LOAD_STACK_GUARD &&
-      MI.getOpcode() != AArch64::CATCHRET)
+      MI.getOpcode() != AArch64::CATCHRET &&
+      MI.getOpcode() != AArch64::STACK_GUARD_UNMIX)
     return false;
 
   MachineBasicBlock &MBB = *MI.getParent();
@@ -2533,6 +2534,20 @@ bool AArch64InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
   auto TRI = Subtarget.getRegisterInfo();
   DebugLoc DL = MI.getDebugLoc();
 
+  if (MI.getOpcode() == AArch64::STACK_GUARD_UNMIX) {
+    // Expand STACK_GUARD_UNMIX to: sub Rd, fp, Rs
+    // This computes FP - stored_mixed_value to unmix the cookie
+    Register DstReg = MI.getOperand(0).getReg();
+    Register SrcReg = MI.getOperand(1).getReg();
+
+    BuildMI(MBB, MI, DL, get(AArch64::SUBXrr), DstReg)
+        .addReg(AArch64::FP)
+        .addReg(SrcReg);
+
+    MBB.erase(MI);
+    return true;
+  }
+
   if (MI.getOpcode() == AArch64::CATCHRET) {
     // Skip to the first instruction before the epilog.
     const TargetInstrInfo *TII =
@@ -2689,6 +2704,14 @@ bool AArch64InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
           .addMemOperand(*MI.memoperands_begin());
     }
   }
+  // To match MSVC. Unlike x86_64 which uses xor instruction to mix the cookie,
+  // we use sub instruction to mix the cookie on aarch64.
+  // The mixing happens here in expandPostRAPseudo (after RA) to ensure we use
+  // the final frame pointer value.
+  if (Subtarget.getTargetTriple().isOSMSVCRT())
+    BuildMI(MBB, MI, DL, get(AArch64::SUBXrr), Reg)
+        .addReg(AArch64::FP)
+        .addReg(Reg, RegState::Kill);
 
   MBB.erase(MI);
 

diff  --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 729f858de308d..a898d1e228053 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2758,6 +2758,12 @@ def copyFromSP: PatLeaf<(i64 GPR64:$src), [{
          cast<RegisterSDNode>(N->getOperand(1))->getReg() == AArch64::SP;
 }]>;
 
+// Pseudo instruction for stack guard cookie unmixing (epilogue).
+// This will be expanded post-RA to use FP directly, avoiding an extra mov.
+// Pattern matching for this will be done via custom C++ code during instruction selection.
+def STACK_GUARD_UNMIX : Pseudo<(outs GPR64:$dst), (ins GPR64:$stored_val), []>,
+                        Sched<[]>;
+
 // Use SUBS instead of SUB to enable CSE between SUBS and SUB.
 def : Pat<(sub GPR32sp:$Rn, addsub_shifted_imm32:$imm),
           (SUBSWri GPR32sp:$Rn, addsub_shifted_imm32:$imm)>;

diff  --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 03cad8457484e..30dc228443415 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -2868,12 +2868,12 @@ bool X86TargetLowering::useLoadStackGuardNode(const Module &M) const {
   return Subtarget.isTargetMachO() && Subtarget.is64Bit();
 }
 
-bool X86TargetLowering::useStackGuardXorFP() const {
-  // Currently only MSVC CRTs XOR the frame pointer into the stack guard value.
+bool X86TargetLowering::useStackGuardMixFP() const {
+  // Currently only MSVC CRTs mix the frame pointer into the stack guard value.
   return Subtarget.getTargetTriple().isOSMSVCRT() && !Subtarget.isTargetMachO();
 }
 
-SDValue X86TargetLowering::emitStackGuardXorFP(SelectionDAG &DAG, SDValue Val,
+SDValue X86TargetLowering::emitStackGuardMixFP(SelectionDAG &DAG, SDValue Val,
                                                const SDLoc &DL) const {
   EVT PtrTy = getPointerTy(DAG.getDataLayout());
   unsigned XorOp = Subtarget.is64Bit() ? X86::XOR64_FP : X86::XOR32_FP;

diff  --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index 0d05c5772a707..5283c377b97c0 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -636,14 +636,13 @@ namespace llvm {
                            const LibcallLoweringInfo &Libcalls) const override;
 
     bool useLoadStackGuardNode(const Module &M) const override;
-    bool useStackGuardXorFP() const override;
+    bool useStackGuardMixFP() const override;
     void
     insertSSPDeclarations(Module &M,
                           const LibcallLoweringInfo &Libcalls) const override;
-    SDValue emitStackGuardXorFP(SelectionDAG &DAG, SDValue Val,
+    SDValue emitStackGuardMixFP(SelectionDAG &DAG, SDValue Val,
                                 const SDLoc &DL) const override;
 
-
     /// Return true if the target stores SafeStack pointer at a fixed offset in
     /// some non-standard address space, and populates the address space and
     /// offset as appropriate.

diff  --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-windows.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-windows.ll
index 447267cf57f76..0be0fb5b9137e 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-windows.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-stack-protector-windows.ll
@@ -9,29 +9,34 @@ define void @caller() sspreq {
 ; CHECK-NEXT:  // %bb.0: // %entry
 ; CHECK-NEXT:    sub sp, sp, #32
 ; CHECK-NEXT:    .seh_stackalloc 32
-; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Spill
-; CHECK-NEXT:    .seh_save_reg x30, 16
+; CHECK-NEXT:    stp x29, x30, [sp, #16] // 16-byte Folded Spill
+; CHECK-NEXT:    .seh_save_fplr 16
+; CHECK-NEXT:    add x29, sp, #16
+; CHECK-NEXT:    .seh_add_fp 16
 ; CHECK-NEXT:    .seh_endprologue
 ; CHECK-NEXT:    adrp x8, __security_cookie
 ; CHECK-NEXT:    add x0, sp, #4
 ; CHECK-NEXT:    ldr x8, [x8, :lo12:__security_cookie]
+; CHECK-NEXT:    sub x8, x29, x8
 ; CHECK-NEXT:    str x8, [sp, #8]
 ; CHECK-NEXT:    bl callee
-; CHECK-NEXT:    adrp x8, __security_cookie
-; CHECK-NEXT:    ldr x9, [sp, #8]
-; CHECK-NEXT:    ldr x8, [x8, :lo12:__security_cookie]
-; CHECK-NEXT:    cmp x8, x9
+; CHECK-NEXT:    ldr x8, [sp, #8]
+; CHECK-NEXT:    adrp x9, __security_cookie
+; CHECK-NEXT:    ldr x9, [x9, :lo12:__security_cookie]
+; CHECK-NEXT:    sub x8, x29, x8
+; CHECK-NEXT:    cmp x9, x8
 ; CHECK-NEXT:    b.ne .LBB0_2
 ; CHECK-NEXT:  // %bb.1: // %entry
 ; CHECK-NEXT:    .seh_startepilogue
-; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Reload
-; CHECK-NEXT:    .seh_save_reg x30, 16
+; CHECK-NEXT:    ldp x29, x30, [sp, #16] // 16-byte Folded Reload
+; CHECK-NEXT:    .seh_save_fplr 16
 ; CHECK-NEXT:    add sp, sp, #32
 ; CHECK-NEXT:    .seh_stackalloc 32
 ; CHECK-NEXT:    .seh_endepilogue
 ; CHECK-NEXT:    ret
 ; CHECK-NEXT:  .LBB0_2: // %entry
-; CHECK-NEXT:    ldr x0, [sp, #8]
+; CHECK-NEXT:    ldr x8, [sp, #8]
+; CHECK-NEXT:    sub x0, x29, x8
 ; CHECK-NEXT:    bl __security_check_cookie
 ; CHECK-NEXT:    brk #0x1
 ; CHECK-NEXT:    .seh_endfunclet

diff  --git a/llvm/test/CodeGen/AArch64/arm64ec-indirect-call.ll b/llvm/test/CodeGen/AArch64/arm64ec-indirect-call.ll
index e6a42c382e4f6..dce77ca343511 100644
--- a/llvm/test/CodeGen/AArch64/arm64ec-indirect-call.ll
+++ b/llvm/test/CodeGen/AArch64/arm64ec-indirect-call.ll
@@ -29,16 +29,17 @@ define void @stackguard(ptr %g) sspreq {
 ; CHECK:          adrp    x8, __os_arm64x_check_icall
 ; CHECK-NEXT:     ldr     x8, [x8, :lo12:__os_arm64x_check_icall]
 ; CHECK-NEXT:     blr     x8
-; CHECK-NEXT:     adrp    x8, __security_cookie
-; CHECK-NEXT:     ldr     x10, [sp, #8]
-; CHECK-NEXT:     ldr     x8, [x8, :lo12:__security_cookie]
-; CHECK-NEXT:     cmp     x8, x10
+; CHECK-NEXT:     ldr     x8, [sp, #8]
+; CHECK-NEXT:     adrp    x10, __security_cookie
+; CHECK-NEXT:     ldr     x10, [x10, :lo12:__security_cookie]
+; CHECK-NEXT:     sub     x8, x29, x8
+; CHECK-NEXT:     cmp     x10, x8
 ; CHECK-NEXT:     b.ne    .LBB1_2
 ; CHECK-NEXT: // %bb.1:
 ; CHECK-NEXT:     fmov    d0, #1.00000000
 ; CHECK-NEXT:     .seh_startepilogue
-; CHECK-NEXT:     ldr     x30, [sp, #16]
-; CHECK-NEXT:     .seh_save_reg   x30, 16
+; CHECK-NEXT:     ldp     x29, x30, [sp, #16]
+; CHECK-NEXT:     .seh_save_fplr  16
 ; CHECK-NEXT:     add     sp, sp, #32
 ; CHECK-NEXT:     .seh_stackalloc 32
 ; CHECK-NEXT:     .seh_endepilogue

diff  --git a/llvm/test/CodeGen/AArch64/mingw-refptr.ll b/llvm/test/CodeGen/AArch64/mingw-refptr.ll
index 02c81440dd753..e3fcdb38ea613 100644
--- a/llvm/test/CodeGen/AArch64/mingw-refptr.ll
+++ b/llvm/test/CodeGen/AArch64/mingw-refptr.ll
@@ -77,39 +77,81 @@ entry:
 declare dso_local void @otherFunc()
 
 define dso_local void @sspFunc() #0 {
-; CHECK-LABEL: sspFunc:
-; CHECK:       .seh_proc sspFunc
-; CHECK-NEXT:  // %bb.0: // %entry
-; CHECK-NEXT:    sub sp, sp, #32
-; CHECK-NEXT:    .seh_stackalloc 32
-; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Spill
-; CHECK-NEXT:    .seh_save_reg x30, 16
-; CHECK-NEXT:    .seh_endprologue
-; CHECK-NEXT:    adrp x8, .refptr.__stack_chk_guard
-; CHECK-NEXT:    add x0, sp, #7
-; CHECK-NEXT:    ldr x8, [x8, :lo12:.refptr.__stack_chk_guard]
-; CHECK-NEXT:    ldr x8, [x8]
-; CHECK-NEXT:    str x8, [sp, #8]
-; CHECK-NEXT:    bl ptrUser
-; CHECK-NEXT:    adrp x8, .refptr.__stack_chk_guard
-; CHECK-NEXT:    ldr x8, [x8, :lo12:.refptr.__stack_chk_guard]
-; CHECK-NEXT:    ldr x9, [sp, #8]
-; CHECK-NEXT:    ldr x8, [x8]
-; CHECK-NEXT:    cmp x8, x9
-; CHECK-NEXT:    b.ne .LBB6_2
-; CHECK-NEXT:  // %bb.1: // %entry
-; CHECK-NEXT:    .seh_startepilogue
-; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Reload
-; CHECK-NEXT:    .seh_save_reg x30, 16
-; CHECK-NEXT:    add sp, sp, #32
-; CHECK-NEXT:    .seh_stackalloc 32
-; CHECK-NEXT:    .seh_endepilogue
-; CHECK-NEXT:    ret
-; CHECK-NEXT:  .LBB6_2: // %entry
-; CHECK-NEXT:    bl __stack_chk_fail
-; CHECK-NEXT:    brk #0x1
-; CHECK-NEXT:    .seh_endfunclet
-; CHECK-NEXT:    .seh_endproc
+; CHECK-SD-LABEL: sspFunc:
+; CHECK-SD:       .seh_proc sspFunc
+; CHECK-SD-NEXT:  // %bb.0: // %entry
+; CHECK-SD-NEXT:    sub sp, sp, #32
+; CHECK-SD-NEXT:    .seh_stackalloc 32
+; CHECK-SD-NEXT:    stp x29, x30, [sp, #16] // 16-byte Folded Spill
+; CHECK-SD-NEXT:    .seh_save_fplr 16
+; CHECK-SD-NEXT:    add x29, sp, #16
+; CHECK-SD-NEXT:    .seh_add_fp 16
+; CHECK-SD-NEXT:    .seh_endprologue
+; CHECK-SD-NEXT:    adrp x8, .refptr.__stack_chk_guard
+; CHECK-SD-NEXT:    add x0, sp, #7
+; CHECK-SD-NEXT:    ldr x8, [x8, :lo12:.refptr.__stack_chk_guard]
+; CHECK-SD-NEXT:    ldr x8, [x8]
+; CHECK-SD-NEXT:    sub x8, x29, x8
+; CHECK-SD-NEXT:    str x8, [sp, #8]
+; CHECK-SD-NEXT:    bl ptrUser
+; CHECK-SD-NEXT:    adrp x8, .refptr.__stack_chk_guard
+; CHECK-SD-NEXT:    ldr x8, [x8, :lo12:.refptr.__stack_chk_guard]
+; CHECK-SD-NEXT:    ldr x9, [sp, #8]
+; CHECK-SD-NEXT:    ldr x8, [x8]
+; CHECK-SD-NEXT:    sub x9, x29, x9
+; CHECK-SD-NEXT:    cmp x8, x9
+; CHECK-SD-NEXT:    b.ne .LBB6_2
+; CHECK-SD-NEXT:  // %bb.1: // %entry
+; CHECK-SD-NEXT:    .seh_startepilogue
+; CHECK-SD-NEXT:    ldp x29, x30, [sp, #16] // 16-byte Folded Reload
+; CHECK-SD-NEXT:    .seh_save_fplr 16
+; CHECK-SD-NEXT:    add sp, sp, #32
+; CHECK-SD-NEXT:    .seh_stackalloc 32
+; CHECK-SD-NEXT:    .seh_endepilogue
+; CHECK-SD-NEXT:    ret
+; CHECK-SD-NEXT:  .LBB6_2: // %entry
+; CHECK-SD-NEXT:    bl __stack_chk_fail
+; CHECK-SD-NEXT:    brk #0x1
+; CHECK-SD-NEXT:    .seh_endfunclet
+; CHECK-SD-NEXT:    .seh_endproc
+;
+; CHECK-GI-LABEL: sspFunc:
+; CHECK-GI:       .seh_proc sspFunc
+; CHECK-GI-NEXT:  // %bb.0: // %entry
+; CHECK-GI-NEXT:    sub sp, sp, #32
+; CHECK-GI-NEXT:    .seh_stackalloc 32
+; CHECK-GI-NEXT:    stp x29, x30, [sp, #16] // 16-byte Folded Spill
+; CHECK-GI-NEXT:    .seh_save_fplr 16
+; CHECK-GI-NEXT:    add x29, sp, #16
+; CHECK-GI-NEXT:    .seh_add_fp 16
+; CHECK-GI-NEXT:    .seh_endprologue
+; CHECK-GI-NEXT:    adrp x8, .refptr.__stack_chk_guard
+; CHECK-GI-NEXT:    add x0, sp, #7
+; CHECK-GI-NEXT:    ldr x8, [x8, :lo12:.refptr.__stack_chk_guard]
+; CHECK-GI-NEXT:    ldr x8, [x8]
+; CHECK-GI-NEXT:    sub x8, x29, x8
+; CHECK-GI-NEXT:    str x8, [sp, #8]
+; CHECK-GI-NEXT:    bl ptrUser
+; CHECK-GI-NEXT:    adrp x8, .refptr.__stack_chk_guard
+; CHECK-GI-NEXT:    ldr x8, [x8, :lo12:.refptr.__stack_chk_guard]
+; CHECK-GI-NEXT:    ldr x9, [sp, #8]
+; CHECK-GI-NEXT:    ldr x8, [x8]
+; CHECK-GI-NEXT:    sub x8, x29, x8
+; CHECK-GI-NEXT:    cmp x8, x9
+; CHECK-GI-NEXT:    b.ne .LBB6_2
+; CHECK-GI-NEXT:  // %bb.1: // %entry
+; CHECK-GI-NEXT:    .seh_startepilogue
+; CHECK-GI-NEXT:    ldp x29, x30, [sp, #16] // 16-byte Folded Reload
+; CHECK-GI-NEXT:    .seh_save_fplr 16
+; CHECK-GI-NEXT:    add sp, sp, #32
+; CHECK-GI-NEXT:    .seh_stackalloc 32
+; CHECK-GI-NEXT:    .seh_endepilogue
+; CHECK-GI-NEXT:    ret
+; CHECK-GI-NEXT:  .LBB6_2: // %entry
+; CHECK-GI-NEXT:    bl __stack_chk_fail
+; CHECK-GI-NEXT:    brk #0x1
+; CHECK-GI-NEXT:    .seh_endfunclet
+; CHECK-GI-NEXT:    .seh_endproc
 entry:
   %c = alloca i8, align 1
   call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %c)
@@ -133,6 +175,3 @@ attributes #0 = { sspstrong }
 ; CHECK: .refptr.var:
 ; CHECK:        .xword  var
 
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK-GI: {{.*}}
-; CHECK-SD: {{.*}}

diff  --git a/llvm/test/CodeGen/AArch64/stack-protector-target.ll b/llvm/test/CodeGen/AArch64/stack-protector-target.ll
index b1ddd1d0d160f..1f20c526628be 100644
--- a/llvm/test/CodeGen/AArch64/stack-protector-target.ll
+++ b/llvm/test/CodeGen/AArch64/stack-protector-target.ll
@@ -31,14 +31,18 @@ declare void @_Z7CapturePi(ptr)
 
 ; WINDOWS-AARCH64: adrp x8, __security_cookie
 ; WINDOWS-AARCH64: ldr x8, [x8, :lo12:__security_cookie]
+; WINDOWS-AARCH64: sub x8, x29, x8
 ; WINDOWS-AARCH64: str x8, [sp, #8]
 ; WINDOWS-AARCH64: bl  _Z7CapturePi
-; WINDOWS-AARCH64: ldr x0, [sp, #8]
+; WINDOWS-AARCH64: ldr x8, [sp, #8]
+; WINDOWS-AARCH64: sub x0, x29, x8
 ; WINDOWS-AARCH64: bl  __security_check_cookie
 
 ; WINDOWS-ARM64EC: adrp x8, __security_cookie
 ; WINDOWS-ARM64EC: ldr x8, [x8, :lo12:__security_cookie]
+; WINDOWS-ARM64EC: sub x8, x29, x8
 ; WINDOWS-ARM64EC: str x8, [sp, #8]
 ; WINDOWS-ARM64EC: bl "#_Z7CapturePi"
-; WINDOWS-ARM64EC: ldr x0, [sp, #8]
+; WINDOWS-ARM64EC: ldr x8, [sp, #8]
+; WINDOWS-ARM64EC: sub x0, x29, x8
 ; WINDOWS-ARM64EC: bl "#__security_check_cookie_arm64ec"


        


More information about the llvm-commits mailing list