Skip to content

Conversation

@arsenm
Copy link
Contributor

@arsenm arsenm commented Dec 2, 2025

No description provided.

Copy link
Contributor Author

arsenm commented Dec 2, 2025

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@llvmbot
Copy link
Member

llvmbot commented Dec 2, 2025

@llvm/pr-subscribers-llvm-transforms
@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-llvm-globalisel

Author: Matt Arsenault (arsenm)

Changes

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

6 Files Affected:

  • (modified) llvm/lib/CodeGen/StackProtector.cpp (+55-27)
  • (modified) llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stack-protector-atomicrmw-xchg.ll (+2-2)
  • (modified) llvm/test/Transforms/StackProtector/cross-dso-cfi-stack-chk-fail.ll (+1-1)
  • (added) llvm/test/Transforms/StackProtector/missing-analysis.ll (+7)
  • (modified) llvm/test/Transforms/StackProtector/stack-chk-fail-alias.ll (+1-1)
diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp
index 5fd5d6cce23df..d56ef00ac7d08 100644
--- a/llvm/lib/CodeGen/StackProtector.cpp
+++ b/llvm/lib/CodeGen/StackProtector.cpp
@@ -69,13 +69,15 @@ static cl::opt<bool> DisableCheckNoReturn("disable-check-noreturn-call",
 ///  - The prologue code loads and stores the stack guard onto the stack.
 ///  - The epilogue checks the value stored in the prologue against the original
 ///    value. It calls __stack_chk_fail if they differ.
-static bool InsertStackProtectors(const TargetMachine *TM, Function *F,
-                                  DomTreeUpdater *DTU, bool &HasPrologue,
-                                  bool &HasIRCheck);
+static bool InsertStackProtectors(const TargetLowering &TLI,
+                                  const LibcallLoweringInfo &Libcalls,
+                                  Function *F, DomTreeUpdater *DTU,
+                                  bool &HasPrologue, bool &HasIRCheck);
 
 /// CreateFailBB - Create a basic block to jump to when the stack protector
 /// check fails.
-static BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI);
+static BasicBlock *CreateFailBB(Function *F,
+                                const LibcallLoweringInfo &Libcalls);
 
 bool SSPLayoutInfo::shouldEmitSDCheck(const BasicBlock &BB) const {
   return HasPrologue && !HasIRCheck && isa<ReturnInst>(BB.getTerminator());
@@ -131,8 +133,23 @@ PreservedAnalyses StackProtectorPass::run(Function &F,
       return PreservedAnalyses::all();
   }
 
+  auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
+  const LibcallLoweringModuleAnalysisResult *LibcallLowering =
+      MAMProxy.getCachedResult<LibcallLoweringModuleAnalysis>(*F.getParent());
+
+  if (!LibcallLowering) {
+    F.getContext().emitError("'" + LibcallLoweringModuleAnalysis::name() +
+                             "' analysis required");
+    return PreservedAnalyses::all();
+  }
+
+  const TargetSubtargetInfo *STI = TM->getSubtargetImpl(F);
+  const TargetLowering *TLI = STI->getTargetLowering();
+  const LibcallLoweringInfo &Libcalls =
+      LibcallLowering->getLibcallLowering(*STI);
+
   ++NumFunProtected;
-  bool Changed = InsertStackProtectors(TM, &F, DT ? &DTU : nullptr,
+  bool Changed = InsertStackProtectors(*TLI, Libcalls, &F, DT ? &DTU : nullptr,
                                        Info.HasPrologue, Info.HasIRCheck);
 #ifdef EXPENSIVE_CHECKS
   assert((!DT ||
@@ -156,6 +173,7 @@ StackProtector::StackProtector() : FunctionPass(ID) {
 
 INITIALIZE_PASS_BEGIN(StackProtector, DEBUG_TYPE,
                       "Insert stack protectors", false, true)
+INITIALIZE_PASS_DEPENDENCY(LibcallLoweringInfoWrapper)
 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
 INITIALIZE_PASS_END(StackProtector, DEBUG_TYPE,
@@ -164,6 +182,7 @@ INITIALIZE_PASS_END(StackProtector, DEBUG_TYPE,
 FunctionPass *llvm::createStackProtectorPass() { return new StackProtector(); }
 
 void StackProtector::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<LibcallLoweringInfoWrapper>();
   AU.addRequired<TargetPassConfig>();
   AU.addPreserved<DominatorTreeWrapperPass>();
 }
@@ -190,9 +209,16 @@ bool StackProtector::runOnFunction(Function &Fn) {
       return false;
   }
 
+  const TargetSubtargetInfo *Subtarget = TM->getSubtargetImpl(Fn);
+  const LibcallLoweringInfo &Libcalls =
+      getAnalysis<LibcallLoweringInfoWrapper>().getLibcallLowering(*M,
+                                                                   *Subtarget);
+
+  const TargetLowering *TLI = Subtarget->getTargetLowering();
+
   ++NumFunProtected;
   bool Changed =
-      InsertStackProtectors(TM, F, DTU ? &*DTU : nullptr,
+      InsertStackProtectors(*TLI, Libcalls, F, DTU ? &*DTU : nullptr,
                             LayoutInfo.HasPrologue, LayoutInfo.HasIRCheck);
 #ifdef EXPENSIVE_CHECKS
   assert((!DTU ||
@@ -519,10 +545,10 @@ bool SSPLayoutAnalysis::requiresStackProtector(Function *F,
 
 /// Create a stack guard loading and populate whether SelectionDAG SSP is
 /// supported.
-static Value *getStackGuard(const TargetLoweringBase *TLI, Module *M,
+static Value *getStackGuard(const TargetLoweringBase &TLI, Module *M,
                             IRBuilder<> &B,
                             bool *SupportsSelectionDAGSP = nullptr) {
-  Value *Guard = TLI->getIRStackGuard(B);
+  Value *Guard = TLI.getIRStackGuard(B);
   StringRef GuardMode = M->getStackProtectorGuard();
   if ((GuardMode == "tls" || GuardMode.empty()) && Guard)
     return B.CreateLoad(B.getPtrTy(), Guard, true, "StackGuard");
@@ -540,7 +566,7 @@ static Value *getStackGuard(const TargetLoweringBase *TLI, Module *M,
   // actually conveys the same information getIRStackGuard() already gives.
   if (SupportsSelectionDAGSP)
     *SupportsSelectionDAGSP = true;
-  TLI->insertSSPDeclarations(*M);
+  TLI.insertSSPDeclarations(*M);
   return B.CreateIntrinsic(Intrinsic::stackguard, {});
 }
 
@@ -561,23 +587,23 @@ static bool CreatePrologue(Function *F, Module *M, Instruction *CheckLoc,
   PointerType *PtrTy = PointerType::getUnqual(CheckLoc->getContext());
   AI = B.CreateAlloca(PtrTy, nullptr, "StackGuardSlot");
 
-  Value *GuardSlot = getStackGuard(TLI, M, B, &SupportsSelectionDAGSP);
+  Value *GuardSlot = getStackGuard(*TLI, M, B, &SupportsSelectionDAGSP);
   B.CreateIntrinsic(Intrinsic::stackprotector, {GuardSlot, AI});
   return SupportsSelectionDAGSP;
 }
 
-bool InsertStackProtectors(const TargetMachine *TM, Function *F,
+bool InsertStackProtectors(const TargetLowering &TLI,
+                           const LibcallLoweringInfo &Libcalls, Function *F,
                            DomTreeUpdater *DTU, bool &HasPrologue,
                            bool &HasIRCheck) {
   auto *M = F->getParent();
-  auto *TLI = TM->getSubtargetImpl(*F)->getTargetLowering();
 
   // If the target wants to XOR the frame pointer into the guard value, it's
   // impossible to emit the check in IR, so the target *must* support stack
   // protection in SDAG.
   bool SupportsSelectionDAGSP =
-      TLI->useStackGuardXorFP() ||
-      (EnableSelectionDAGSP && !TM->Options.EnableFastISel);
+      TLI.useStackGuardXorFP() ||
+      (EnableSelectionDAGSP && !TLI.getTargetMachine().Options.EnableFastISel);
   AllocaInst *AI = nullptr; // Place on stack that stores the stack guard.
   BasicBlock *FailBB = nullptr;
 
@@ -610,7 +636,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
     // Generate prologue instrumentation if not already generated.
     if (!HasPrologue) {
       HasPrologue = true;
-      SupportsSelectionDAGSP &= CreatePrologue(F, M, CheckLoc, TLI, AI);
+      SupportsSelectionDAGSP &= CreatePrologue(F, M, CheckLoc, &TLI, AI);
     }
 
     // SelectionDAG based code generation. Nothing else needs to be done here.
@@ -635,13 +661,13 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
     // inserted before the call rather than between it and the return.
     Instruction *Prev = CheckLoc->getPrevNode();
     if (auto *CI = dyn_cast_if_present<CallInst>(Prev))
-      if (CI->isTailCall() && isInTailCallPosition(*CI, *TM))
+      if (CI->isTailCall() && isInTailCallPosition(*CI, TLI.getTargetMachine()))
         CheckLoc = Prev;
 
     // Generate epilogue instrumentation. The epilogue intrumentation can be
     // function-based or inlined depending on which mechanism the target is
     // providing.
-    if (Function *GuardCheck = TLI->getSSPStackGuardCheck(*M)) {
+    if (Function *GuardCheck = TLI.getSSPStackGuardCheck(*M)) {
       // Generate the function-based epilogue instrumentation.
       // The target provides a guard check function, generate a call to it.
       IRBuilder<> B(CheckLoc);
@@ -680,7 +706,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
       // merge pass will merge together all of the various BB into one including
       // fail BB generated by the stack protector pseudo instruction.
       if (!FailBB)
-        FailBB = CreateFailBB(F, *TLI);
+        FailBB = CreateFailBB(F, Libcalls);
 
       IRBuilder<> B(CheckLoc);
       Value *Guard = getStackGuard(TLI, M, B);
@@ -713,7 +739,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
   return HasPrologue;
 }
 
-BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI) {
+BasicBlock *CreateFailBB(Function *F, const LibcallLoweringInfo &Libcalls) {
   auto *M = F->getParent();
   LLVMContext &Context = F->getContext();
   BasicBlock *FailBB = BasicBlock::Create(Context, "CallStackCheckFailBlk", F);
@@ -724,14 +750,16 @@ BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI) {
   FunctionCallee StackChkFail;
   SmallVector<Value *, 1> Args;
 
-  if (const char *ChkFailName =
-          TLI.getLibcallName(RTLIB::STACKPROTECTOR_CHECK_FAIL)) {
-    StackChkFail =
-        M->getOrInsertFunction(ChkFailName, Type::getVoidTy(Context));
-  } else if (const char *SSHName =
-                 TLI.getLibcallName(RTLIB::STACK_SMASH_HANDLER)) {
-    StackChkFail = M->getOrInsertFunction(SSHName, Type::getVoidTy(Context),
-                                          PointerType::getUnqual(Context));
+  if (RTLIB::LibcallImpl ChkFailImpl =
+          Libcalls.getLibcallImpl(RTLIB::STACKPROTECTOR_CHECK_FAIL)) {
+    StackChkFail = M->getOrInsertFunction(
+        RTLIB::RuntimeLibcallsInfo::getLibcallImplName(ChkFailImpl),
+        Type::getVoidTy(Context));
+  } else if (RTLIB::LibcallImpl SSHImpl =
+                 Libcalls.getLibcallImpl(RTLIB::STACK_SMASH_HANDLER)) {
+    StackChkFail = M->getOrInsertFunction(
+        RTLIB::RuntimeLibcallsInfo::getLibcallImplName(SSHImpl),
+        Type::getVoidTy(Context), PointerType::getUnqual(Context));
     Args.push_back(B.CreateGlobalString(F->getName(), "SSH"));
   } else {
     Context.emitError("no libcall available for stack protector");
diff --git a/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll b/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll
index f877d95dd3769..69f3c2945064e 100644
--- a/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll
+++ b/llvm/test/CodeGen/NVPTX/no-stack-protector-libcall-error.ll
@@ -1,4 +1,4 @@
-; RUN: not opt -disable-output -mtriple=nvptx64-- -enable-selectiondag-sp=0 -passes=stack-protector %s 2>&1 | FileCheck %s
+; RUN: not opt -disable-output -mtriple=nvptx64-- -enable-selectiondag-sp=0 -passes='require<libcall-lowering-info>,stack-protector' %s 2>&1 | FileCheck %s
 
 ; CHECK: error: no libcall available for stack protector
 define void @func() sspreq nounwind {
diff --git a/llvm/test/CodeGen/X86/stack-protector-atomicrmw-xchg.ll b/llvm/test/CodeGen/X86/stack-protector-atomicrmw-xchg.ll
index 486cb4cfa509d..7eb809c927b93 100644
--- a/llvm/test/CodeGen/X86/stack-protector-atomicrmw-xchg.ll
+++ b/llvm/test/CodeGen/X86/stack-protector-atomicrmw-xchg.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
-; RUN: opt -S -mtriple=x86_64-unknown-linux-gnu -passes=stack-protector < %s | FileCheck %s
-; RUN: opt -S -mtriple=x86_64-unknown-linux-gnu -passes='require<domtree>,stack-protector' < %s | FileCheck %s
+; RUN: opt -S -mtriple=x86_64-unknown-linux-gnu -passes='require<libcall-lowering-info>,stack-protector' < %s | FileCheck %s
+; RUN: opt -S -mtriple=x86_64-unknown-linux-gnu -passes='require<libcall-lowering-info>,function(require<domtree>,stack-protector)' < %s | FileCheck %s
 
 define void @atomicrmw_xchg(ptr %p) sspstrong {
 ; CHECK-LABEL: define void @atomicrmw_xchg(
diff --git a/llvm/test/Transforms/StackProtector/cross-dso-cfi-stack-chk-fail.ll b/llvm/test/Transforms/StackProtector/cross-dso-cfi-stack-chk-fail.ll
index 9a102768b1277..53b109914ebf7 100644
--- a/llvm/test/Transforms/StackProtector/cross-dso-cfi-stack-chk-fail.ll
+++ b/llvm/test/Transforms/StackProtector/cross-dso-cfi-stack-chk-fail.ll
@@ -1,7 +1,7 @@
 ;; This is a minimal reproducer that caused StackProtector to crash with a bad cast when
 ;; CrossDSOCFI is used. This test just needs to not crash.
 ; REQUIRES: x86-registered-target
-; RUN: opt -mtriple=x86_64-pc-linux-gnu %s -passes=lowertypetests,cross-dso-cfi,stack-protector
+; RUN: opt -mtriple=x86_64-pc-linux-gnu %s -passes='require<libcall-lowering-info>,lowertypetests,cross-dso-cfi,stack-protector'
 
 define hidden void @__stack_chk_fail() !type !1{
   unreachable
diff --git a/llvm/test/Transforms/StackProtector/missing-analysis.ll b/llvm/test/Transforms/StackProtector/missing-analysis.ll
new file mode 100644
index 0000000000000..a9f86edb22783
--- /dev/null
+++ b/llvm/test/Transforms/StackProtector/missing-analysis.ll
@@ -0,0 +1,7 @@
+; REQUIRES: x86-registered-target
+; RUN: not opt -mtriple=x86_64-- -passes=expand-fp -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: 'LibcallLoweringModuleAnalysis' analysis required
+define void @empty() {
+  ret void
+}
diff --git a/llvm/test/Transforms/StackProtector/stack-chk-fail-alias.ll b/llvm/test/Transforms/StackProtector/stack-chk-fail-alias.ll
index def3e014797de..4b1d8919b5499 100644
--- a/llvm/test/Transforms/StackProtector/stack-chk-fail-alias.ll
+++ b/llvm/test/Transforms/StackProtector/stack-chk-fail-alias.ll
@@ -1,6 +1,6 @@
 ;; __stack_chk_fail should have the noreturn attr even if it is an alias
 ; REQUIRES: x86-registered-target
-; RUN: opt -mtriple=x86_64-pc-linux-gnu %s -passes=stack-protector -S | FileCheck %s
+; RUN: opt -mtriple=x86_64-pc-linux-gnu %s -passes='require<libcall-lowering-info>,stack-protector' -S | FileCheck %s
 
 define hidden void @__stack_chk_fail_impl() {
   unreachable

@arsenm arsenm force-pushed the users/arsenm/global-isel/use-libcall-lowering-info-legalizer-helper branch from 17769e5 to 0c95e55 Compare December 2, 2025 17:38
@arsenm arsenm force-pushed the users/arsenm/codegen/stack-protector-use-libcall-analysis branch from 9cf982a to 05d4afa Compare December 2, 2025 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants