Skip to content

[StackProtector] Introduce stack-protect-refinement pass to remove unnecessary protections. #150390

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Mermen
Copy link

@Mermen Mermen commented Jul 24, 2025

This pass uses StackSafetyGlobalAnalysis to reduce number of functions that require stack protector.

All llvm lit tests passed.

In llvm-test-suite it reduces number of instrumented functions by 13% (8883 -> 7723) under -O2 -fstack-protector-strong.

Thanks to @yugr for the original idea.

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:ARM backend:AArch64 backend:X86 clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' debuginfo llvm:globalisel LTO Link time optimization (regular/full LTO or ThinLTO) llvm:transforms labels Jul 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 24, 2025

@llvm/pr-subscribers-lto
@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-driver

@llvm/pr-subscribers-llvm-globalisel

Author: None (Mermen)

Changes

This pass uses StackSafetyGlobalAnalysis to reduce number of functions that require stack protector.

All llvm lit tests passed.

In llvm-test-suite it reduces number of instrumented functions by 13% (8883 -> 7723) under -O2 -fstack-protector-strong.


Patch is 24.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/150390.diff

31 Files Affected:

  • (modified) clang/test/Driver/memtag-stack_lto.c (+3-2)
  • (added) llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h (+33)
  • (modified) llvm/lib/Passes/PassBuilder.cpp (+1)
  • (modified) llvm/lib/Passes/PassBuilderPipelines.cpp (+6)
  • (modified) llvm/lib/Passes/PassRegistry.def (+1)
  • (modified) llvm/lib/Transforms/Scalar/CMakeLists.txt (+1)
  • (added) llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp (+60)
  • (modified) llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll (+1-1)
  • (modified) llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll (+1-1)
  • (modified) llvm/test/CodeGen/ARM/ssp-data-layout.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/fast-isel-stackcheck.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/machine-outliner-noredzone.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/ssp-data-layout.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stack-protector-remarks.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stackguard-internal.ll (+1-1)
  • (modified) llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll (+1-1)
  • (modified) llvm/test/Other/new-pm-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-lto-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll (+2)
  • (modified) llvm/test/ThinLTO/X86/nossp.ll (+3-3)
  • (added) llvm/test/Transforms/StackProtectAttributor/AArch64/stack-protector-attribute.c (+64)
diff --git a/clang/test/Driver/memtag-stack_lto.c b/clang/test/Driver/memtag-stack_lto.c
index 324bdec070873..fc014c027fcf8 100644
--- a/clang/test/Driver/memtag-stack_lto.c
+++ b/clang/test/Driver/memtag-stack_lto.c
@@ -33,7 +33,7 @@
 // RUN: rm -f %t*
 
 // -O0: both are unsafe.
-// RUN: %clang -O0 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o - 2>&1 | FileCheck %s
+// RUN: %clang -O0 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o - 2>&1 | FileCheck %s -check-prefixes=CHECK-O0
 
 // No LTO: just one is safe.
 // RUN: %clang -O1 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o /dev/null 2>&1 | FileCheck %s -check-prefixes=SSI,XUNSAFE,YSAFE
@@ -87,6 +87,7 @@ int fn() {
   return x + y;
 }
 
-// CHECK-NOT: allocas uses:
+// CHECK-O0-NOT: allocas uses:
+// CHECK: allocas uses:
 
 #endif
diff --git a/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h b/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h
new file mode 100644
index 0000000000000..d0097669d3067
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h
@@ -0,0 +1,33 @@
+//===- StackProtectAttributor.h - Stack Protect Attributoor ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
+#define LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
+
+#include "llvm/Analysis/StackSafetyAnalysis.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class BasicBlock;
+class Function;
+class Instruction;
+
+class StackProtectAttributorPass
+    : public PassInfoMixin<StackProtectAttributorPass> {
+public:
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+
+private:
+  void processFunction(Function &F) const;
+
+  const StackSafetyGlobalInfo *SSI;
+};
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f810368a84940..1eebf607ef366 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -324,6 +324,7 @@
 #include "llvm/Transforms/Scalar/Reassociate.h"
 #include "llvm/Transforms/Scalar/Reg2Mem.h"
 #include "llvm/Transforms/Scalar/RewriteStatepointsForGC.h"
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
 #include "llvm/Transforms/Scalar/SCCP.h"
 #include "llvm/Transforms/Scalar/SROA.h"
 #include "llvm/Transforms/Scalar/ScalarizeMaskedMemIntrin.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 98821bb1408a7..20e297bfa3dc5 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -127,6 +127,7 @@
 #include "llvm/Transforms/Scalar/SimpleLoopUnswitch.h"
 #include "llvm/Transforms/Scalar/SimplifyCFG.h"
 #include "llvm/Transforms/Scalar/SpeculativeExecution.h"
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
 #include "llvm/Transforms/Scalar/TailRecursionElimination.h"
 #include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
 #include "llvm/Transforms/Utils/AddDiscriminators.h"
@@ -1278,6 +1279,9 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
   else
     MPM.addPass(buildInlinerPipeline(Level, Phase));
 
+  if (Level != OptimizationLevel::O0)
+    MPM.addPass(StackProtectAttributorPass());
+
   // Remove any dead arguments exposed by cleanups, constant folding globals,
   // and argument promotion.
   MPM.addPass(DeadArgumentEliminationPass());
@@ -1944,6 +1948,8 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
   // is fixed.
   MPM.addPass(WholeProgramDevirtPass(ExportSummary, nullptr));
 
+  MPM.addPass(StackProtectAttributorPass());
+
   // Stop here at -O1.
   if (Level == OptimizationLevel::O1) {
     // The LowerTypeTestsPass needs to run to lower type metadata and the
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index bb7ccdb2bc187..d1a22c9ece01e 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -59,6 +59,7 @@ MODULE_PASS("canonicalize-aliases", CanonicalizeAliasesPass())
 MODULE_PASS("check-debugify", NewPMCheckDebugifyPass())
 MODULE_PASS("constmerge", ConstantMergePass())
 MODULE_PASS("coro-cleanup", CoroCleanupPass())
+MODULE_PASS("stack-protect-attributor", StackProtectAttributorPass())
 MODULE_PASS("coro-early", CoroEarlyPass())
 MODULE_PASS("cross-dso-cfi", CrossDSOCFIPass())
 MODULE_PASS("ctx-instr-gen",
diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt
index 84a5b02043d01..b161ab6810a8c 100644
--- a/llvm/lib/Transforms/Scalar/CMakeLists.txt
+++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt
@@ -64,6 +64,7 @@ add_llvm_component_library(LLVMScalarOpts
   PlaceSafepoints.cpp
   Reassociate.cpp
   Reg2Mem.cpp
+  StackProtectAttributor.cpp
   RewriteStatepointsForGC.cpp
   SCCP.cpp
   SROA.cpp
diff --git a/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp b/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp
new file mode 100644
index 0000000000000..8695cb32c4e5d
--- /dev/null
+++ b/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp
@@ -0,0 +1,60 @@
+//===- StackProtectAttributor.cpp - Stack Protect Attributoor -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "stack-protect-attributor"
+
+STATISTIC(
+    NumFuncsWithAllocaInst,
+    "Number of functions with an instruction to allocate memory on the stack");
+STATISTIC(NumFuncsWithRemovedStackProtectAttr,
+          "Number of functions with alloca and removed stack protect attr");
+
+static cl::opt<bool>
+    UseStackSafety("ctpa-optimize-ssp", cl::init(true), cl::Hidden,
+                   cl::desc("Use Stack Safety analysis results"));
+
+void StackProtectAttributorPass::processFunction(Function &F) const {
+
+  bool hasAlloca = false;
+
+  for (auto &I : instructions(&F))
+    if (auto *AI = dyn_cast<AllocaInst>(&I)) {
+      hasAlloca = true;
+      NumFuncsWithAllocaInst++;
+      if (!SSI->isSafe(*AI))
+        return;
+    }
+
+  if (hasAlloca)
+    NumFuncsWithRemovedStackProtectAttr++;
+
+  F.removeFnAttr(Attribute::StackProtect);
+  F.removeFnAttr(Attribute::StackProtectStrong);
+}
+
+PreservedAnalyses StackProtectAttributorPass::run(Module &M,
+                                                  ModuleAnalysisManager &MAM) {
+  if (!UseStackSafety)
+    return PreservedAnalyses::all();
+
+  SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);
+  for (Function &F : M)
+    if (F.hasFnAttribute(Attribute::StackProtect) ||
+        F.hasFnAttribute(Attribute::StackProtectStrong))
+      processFunction(F);
+
+  return PreservedAnalyses::all();
+}
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll b/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
index 683cdfd9eeac8..5faa0a6fc8d59 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple aarch64-unknown-unknown -global-isel \
+; RUN: llc -ctpa-optimize-ssp=false -mtriple aarch64-unknown-unknown -global-isel \
 ; RUN:     -no-stack-coloring=false -pass-remarks-missed=gisel* < %s \
 ; RUN:      2>&1 | FileCheck %s
 
diff --git a/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll b/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
index 4dc71bc90dcdc..32268bf29331c 100644
--- a/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
+++ b/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -o - -verify-machineinstrs | FileCheck %s
+; RUN: llc %s -o - -ctpa-optimize-ssp=false -verify-machineinstrs | FileCheck %s
 
 target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
 target triple = "thumbv7s-apple-ios8.0.0"
diff --git a/llvm/test/CodeGen/ARM/ssp-data-layout.ll b/llvm/test/CodeGen/ARM/ssp-data-layout.ll
index c5f13a66c11ca..ceffe076b985f 100644
--- a/llvm/test/CodeGen/ARM/ssp-data-layout.ll
+++ b/llvm/test/CodeGen/ARM/ssp-data-layout.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -frame-pointer=all -mcpu=cortex-a8 -mtriple arm-linux-gnu -target-abi=apcs -o - | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -frame-pointer=all -mcpu=cortex-a8 -mtriple arm-linux-gnu -target-abi=apcs -o - | FileCheck %s
 ;  This test is fairly fragile.  The goal is to ensure that "large" stack
 ;  objects are allocated closest to the stack protector (i.e., farthest away
 ;  from the Stack Pointer.)  In standard SSP mode this means that large (>=
diff --git a/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll b/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
index 822f6a4c4616e..ead9bc9b64245 100644
--- a/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
+++ b/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=i386-apple-darwin -O0 -regalloc=fast | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=i386-apple-darwin -O0 -regalloc=fast | FileCheck %s
 ; rdar://6787136
 
 	%struct.X = type { i8, [32 x i8] }
diff --git a/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll b/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
index 99a50295727c4..8062704971a5f 100644
--- a/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
+++ b/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s
 ; rdar://7396984
 
 @str = private unnamed_addr constant [28 x i8] c"xxxxxxxxxxxxxxxxxxxxxxxxxxx\00", align 1
diff --git a/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll b/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
index ecaa105dedcfe..112001dcf450f 100644
--- a/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
+++ b/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=x86_64-- -mcpu=core2 | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=x86_64-- -mcpu=core2 | FileCheck %s
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
 declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1) nounwind
diff --git a/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll b/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
index abd1d4e7d350c..fc50bc9072395 100644
--- a/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
+++ b/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
@@ -1,4 +1,4 @@
-; RUN: llc -no-stack-coloring=false < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -no-stack-coloring=false < %s | FileCheck %s
 
 ; This test crashed in PEI because the stack protector was dead.
 ; This was due to it being colored, which was in turn due to incorrect
diff --git a/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll b/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
index a4e5ae66b1fd8..04c75e0915c92 100644
--- a/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
+++ b/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
@@ -1,4 +1,4 @@
-; RUN: llc -o - %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -o - %s | FileCheck %s
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-apple-macosx"
 
diff --git a/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll b/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
index 72d75456ce4ce..6ea291c876be5 100644
--- a/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
+++ b/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
@@ -1,4 +1,4 @@
-; RUN: llc -enable-machine-outliner -mtriple=x86_64-apple-darwin < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -enable-machine-outliner -mtriple=x86_64-apple-darwin < %s | FileCheck %s
 ; Ensure that the outliner doesn't outline from any functions that use a redzone.
 
 declare ptr @llvm.stacksave() #1
diff --git a/llvm/test/CodeGen/X86/ssp-data-layout.ll b/llvm/test/CodeGen/X86/ssp-data-layout.ll
index bda2598384db8..16075f0149cc1 100644
--- a/llvm/test/CodeGen/X86/ssp-data-layout.ll
+++ b/llvm/test/CodeGen/X86/ssp-data-layout.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -stack-symbol-ordering=0 -frame-pointer=all -mtriple=x86_64-pc-linux-gnu -mcpu=corei7 -o - | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -stack-symbol-ordering=0 -frame-pointer=all -mtriple=x86_64-pc-linux-gnu -mcpu=corei7 -o - | FileCheck %s
 ;  This test is fairly fragile.  The goal is to ensure that "large" stack
 ;  objects are allocated closest to the stack protector (i.e., farthest away
 ;  from the Stack Pointer.)  In standard SSP mode this means that large (>=
diff --git a/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll b/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
index d18353a89126c..d136c70ff44bb 100644
--- a/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
+++ b/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple=x86_64 -O0 < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -mtriple=x86_64 -O0 < %s | FileCheck %s
 
 ; Check that we don't crash on this input.
 ; CHECK-LABEL: @foo
diff --git a/llvm/test/CodeGen/X86/stack-protector-remarks.ll b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
index cbd986a64eac6..cb08058e50fb6 100644
--- a/llvm/test/CodeGen/X86/stack-protector-remarks.ll
+++ b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -mtriple=x86_64-unknown-unknown -pass-remarks=stack-protector -o /dev/null 2>&1 | FileCheck %s
+; RUN: llc %s -ctpa-optimize-ssp=false -mtriple=x86_64-unknown-unknown -pass-remarks=stack-protector -o /dev/null 2>&1 | FileCheck %s
 ; CHECK-NOT: nossp
 ; CHECK: function attribute_ssp
 ; CHECK-SAME: a function attribute or command-line switch
diff --git a/llvm/test/CodeGen/X86/stackguard-internal.ll b/llvm/test/CodeGen/X86/stackguard-internal.ll
index 328e04b9a718c..15177b4d3d866 100644
--- a/llvm/test/CodeGen/X86/stackguard-internal.ll
+++ b/llvm/test/CodeGen/X86/stackguard-internal.ll
@@ -1,5 +1,5 @@
 ; Check that the backend doesn't crash.
-; RUN: llc -mtriple=x86_64-pc-freebsd %s -o - | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -mtriple=x86_64-pc-freebsd %s -o - | FileCheck %s
 
 @__stack_chk_guard = internal global [8 x i64] zeroinitializer, align 16
 
diff --git a/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll b/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
index 53202f19f7602..6aa986a9ebd7a 100644
--- a/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
+++ b/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -o - -stop-after=finalize-isel -verify-machineinstrs -experimental-debug-variable-locations | FileCheck %s
+; RUN: llc %s -o - -ctpa-optimize-ssp=false -stop-after=finalize-isel -verify-machineinstrs -experimental-debug-variable-locations | FileCheck %s
 
 ; In the sequence below, the sdiv is converted to a function call to __divsi3,
 ; which is then tail call optimised. The dbg.value is suddenly stuck between
diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll
index c554fdbf4c799..bb8e00c5b260b 100644
--- a/llvm/test/Other/new-pm-defaults.ll
+++ b/llvm/test/Other/new-pm-defaults.ll
@@ -235,6 +235,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
 ; CHECK-O-NEXT: Running pass: GlobalOptPass
diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll
index 3aea0f2061f3e..f8b4eabcbcdbc 100644
--- a/llvm/test/Other/new-pm-lto-defaults.ll
+++ b/llvm/test/Other/new-pm-lto-defaults.ll
@@ -67,6 +67,8 @@
 ; CHECK-O1-NEXT: Running analysis: TargetLibraryAnalysis
 ; CHECK-O-NEXT: Running pass: GlobalSplitPass
 ; CHECK-O-NEXT: Running pass: WholeProgramDevirtPass
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O23SZ-NEXT: Running pass: CoroEarlyPass
 ; CHECK-O1-NEXT: Running pass: LowerTypeTestsPass
 ; CHECK-O23SZ-NEXT: Running pass: GlobalOptPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
index 62bb02d9b3c40..fd1faf4bd9067 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
@@ -158,6 +158,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
index 0da7a9f73bdce..f25fce6fe497f 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
@@ -142,6 +142,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
index 38b7890682783..4422e9b7bb9e4 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
@@ -151,6 +151,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
index 5aacd26def2be..ba3d7e2fb58ad 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
@@ -188,6 +188,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: Shou...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jul 24, 2025

@llvm/pr-subscribers-backend-x86

Author: None (Mermen)

Changes

This pass uses StackSafetyGlobalAnalysis to reduce number of functions that require stack protector.

All llvm lit tests passed.

In llvm-test-suite it reduces number of instrumented functions by 13% (8883 -> 7723) under -O2 -fstack-protector-strong.


Patch is 24.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/150390.diff

31 Files Affected:

  • (modified) clang/test/Driver/memtag-stack_lto.c (+3-2)
  • (added) llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h (+33)
  • (modified) llvm/lib/Passes/PassBuilder.cpp (+1)
  • (modified) llvm/lib/Passes/PassBuilderPipelines.cpp (+6)
  • (modified) llvm/lib/Passes/PassRegistry.def (+1)
  • (modified) llvm/lib/Transforms/Scalar/CMakeLists.txt (+1)
  • (added) llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp (+60)
  • (modified) llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll (+1-1)
  • (modified) llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll (+1-1)
  • (modified) llvm/test/CodeGen/ARM/ssp-data-layout.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/fast-isel-stackcheck.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/machine-outliner-noredzone.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/ssp-data-layout.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stack-protector-remarks.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stackguard-internal.ll (+1-1)
  • (modified) llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll (+1-1)
  • (modified) llvm/test/Other/new-pm-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-lto-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll (+2)
  • (modified) llvm/test/ThinLTO/X86/nossp.ll (+3-3)
  • (added) llvm/test/Transforms/StackProtectAttributor/AArch64/stack-protector-attribute.c (+64)
diff --git a/clang/test/Driver/memtag-stack_lto.c b/clang/test/Driver/memtag-stack_lto.c
index 324bdec070873..fc014c027fcf8 100644
--- a/clang/test/Driver/memtag-stack_lto.c
+++ b/clang/test/Driver/memtag-stack_lto.c
@@ -33,7 +33,7 @@
 // RUN: rm -f %t*
 
 // -O0: both are unsafe.
-// RUN: %clang -O0 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o - 2>&1 | FileCheck %s
+// RUN: %clang -O0 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o - 2>&1 | FileCheck %s -check-prefixes=CHECK-O0
 
 // No LTO: just one is safe.
 // RUN: %clang -O1 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o /dev/null 2>&1 | FileCheck %s -check-prefixes=SSI,XUNSAFE,YSAFE
@@ -87,6 +87,7 @@ int fn() {
   return x + y;
 }
 
-// CHECK-NOT: allocas uses:
+// CHECK-O0-NOT: allocas uses:
+// CHECK: allocas uses:
 
 #endif
diff --git a/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h b/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h
new file mode 100644
index 0000000000000..d0097669d3067
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h
@@ -0,0 +1,33 @@
+//===- StackProtectAttributor.h - Stack Protect Attributoor ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
+#define LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
+
+#include "llvm/Analysis/StackSafetyAnalysis.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class BasicBlock;
+class Function;
+class Instruction;
+
+class StackProtectAttributorPass
+    : public PassInfoMixin<StackProtectAttributorPass> {
+public:
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+
+private:
+  void processFunction(Function &F) const;
+
+  const StackSafetyGlobalInfo *SSI;
+};
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f810368a84940..1eebf607ef366 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -324,6 +324,7 @@
 #include "llvm/Transforms/Scalar/Reassociate.h"
 #include "llvm/Transforms/Scalar/Reg2Mem.h"
 #include "llvm/Transforms/Scalar/RewriteStatepointsForGC.h"
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
 #include "llvm/Transforms/Scalar/SCCP.h"
 #include "llvm/Transforms/Scalar/SROA.h"
 #include "llvm/Transforms/Scalar/ScalarizeMaskedMemIntrin.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 98821bb1408a7..20e297bfa3dc5 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -127,6 +127,7 @@
 #include "llvm/Transforms/Scalar/SimpleLoopUnswitch.h"
 #include "llvm/Transforms/Scalar/SimplifyCFG.h"
 #include "llvm/Transforms/Scalar/SpeculativeExecution.h"
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
 #include "llvm/Transforms/Scalar/TailRecursionElimination.h"
 #include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
 #include "llvm/Transforms/Utils/AddDiscriminators.h"
@@ -1278,6 +1279,9 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
   else
     MPM.addPass(buildInlinerPipeline(Level, Phase));
 
+  if (Level != OptimizationLevel::O0)
+    MPM.addPass(StackProtectAttributorPass());
+
   // Remove any dead arguments exposed by cleanups, constant folding globals,
   // and argument promotion.
   MPM.addPass(DeadArgumentEliminationPass());
@@ -1944,6 +1948,8 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
   // is fixed.
   MPM.addPass(WholeProgramDevirtPass(ExportSummary, nullptr));
 
+  MPM.addPass(StackProtectAttributorPass());
+
   // Stop here at -O1.
   if (Level == OptimizationLevel::O1) {
     // The LowerTypeTestsPass needs to run to lower type metadata and the
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index bb7ccdb2bc187..d1a22c9ece01e 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -59,6 +59,7 @@ MODULE_PASS("canonicalize-aliases", CanonicalizeAliasesPass())
 MODULE_PASS("check-debugify", NewPMCheckDebugifyPass())
 MODULE_PASS("constmerge", ConstantMergePass())
 MODULE_PASS("coro-cleanup", CoroCleanupPass())
+MODULE_PASS("stack-protect-attributor", StackProtectAttributorPass())
 MODULE_PASS("coro-early", CoroEarlyPass())
 MODULE_PASS("cross-dso-cfi", CrossDSOCFIPass())
 MODULE_PASS("ctx-instr-gen",
diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt
index 84a5b02043d01..b161ab6810a8c 100644
--- a/llvm/lib/Transforms/Scalar/CMakeLists.txt
+++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt
@@ -64,6 +64,7 @@ add_llvm_component_library(LLVMScalarOpts
   PlaceSafepoints.cpp
   Reassociate.cpp
   Reg2Mem.cpp
+  StackProtectAttributor.cpp
   RewriteStatepointsForGC.cpp
   SCCP.cpp
   SROA.cpp
diff --git a/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp b/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp
new file mode 100644
index 0000000000000..8695cb32c4e5d
--- /dev/null
+++ b/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp
@@ -0,0 +1,60 @@
+//===- StackProtectAttributor.cpp - Stack Protect Attributoor -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "stack-protect-attributor"
+
+STATISTIC(
+    NumFuncsWithAllocaInst,
+    "Number of functions with an instruction to allocate memory on the stack");
+STATISTIC(NumFuncsWithRemovedStackProtectAttr,
+          "Number of functions with alloca and removed stack protect attr");
+
+static cl::opt<bool>
+    UseStackSafety("ctpa-optimize-ssp", cl::init(true), cl::Hidden,
+                   cl::desc("Use Stack Safety analysis results"));
+
+void StackProtectAttributorPass::processFunction(Function &F) const {
+
+  bool hasAlloca = false;
+
+  for (auto &I : instructions(&F))
+    if (auto *AI = dyn_cast<AllocaInst>(&I)) {
+      hasAlloca = true;
+      NumFuncsWithAllocaInst++;
+      if (!SSI->isSafe(*AI))
+        return;
+    }
+
+  if (hasAlloca)
+    NumFuncsWithRemovedStackProtectAttr++;
+
+  F.removeFnAttr(Attribute::StackProtect);
+  F.removeFnAttr(Attribute::StackProtectStrong);
+}
+
+PreservedAnalyses StackProtectAttributorPass::run(Module &M,
+                                                  ModuleAnalysisManager &MAM) {
+  if (!UseStackSafety)
+    return PreservedAnalyses::all();
+
+  SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);
+  for (Function &F : M)
+    if (F.hasFnAttribute(Attribute::StackProtect) ||
+        F.hasFnAttribute(Attribute::StackProtectStrong))
+      processFunction(F);
+
+  return PreservedAnalyses::all();
+}
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll b/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
index 683cdfd9eeac8..5faa0a6fc8d59 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple aarch64-unknown-unknown -global-isel \
+; RUN: llc -ctpa-optimize-ssp=false -mtriple aarch64-unknown-unknown -global-isel \
 ; RUN:     -no-stack-coloring=false -pass-remarks-missed=gisel* < %s \
 ; RUN:      2>&1 | FileCheck %s
 
diff --git a/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll b/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
index 4dc71bc90dcdc..32268bf29331c 100644
--- a/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
+++ b/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -o - -verify-machineinstrs | FileCheck %s
+; RUN: llc %s -o - -ctpa-optimize-ssp=false -verify-machineinstrs | FileCheck %s
 
 target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
 target triple = "thumbv7s-apple-ios8.0.0"
diff --git a/llvm/test/CodeGen/ARM/ssp-data-layout.ll b/llvm/test/CodeGen/ARM/ssp-data-layout.ll
index c5f13a66c11ca..ceffe076b985f 100644
--- a/llvm/test/CodeGen/ARM/ssp-data-layout.ll
+++ b/llvm/test/CodeGen/ARM/ssp-data-layout.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -frame-pointer=all -mcpu=cortex-a8 -mtriple arm-linux-gnu -target-abi=apcs -o - | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -frame-pointer=all -mcpu=cortex-a8 -mtriple arm-linux-gnu -target-abi=apcs -o - | FileCheck %s
 ;  This test is fairly fragile.  The goal is to ensure that "large" stack
 ;  objects are allocated closest to the stack protector (i.e., farthest away
 ;  from the Stack Pointer.)  In standard SSP mode this means that large (>=
diff --git a/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll b/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
index 822f6a4c4616e..ead9bc9b64245 100644
--- a/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
+++ b/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=i386-apple-darwin -O0 -regalloc=fast | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=i386-apple-darwin -O0 -regalloc=fast | FileCheck %s
 ; rdar://6787136
 
 	%struct.X = type { i8, [32 x i8] }
diff --git a/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll b/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
index 99a50295727c4..8062704971a5f 100644
--- a/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
+++ b/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s
 ; rdar://7396984
 
 @str = private unnamed_addr constant [28 x i8] c"xxxxxxxxxxxxxxxxxxxxxxxxxxx\00", align 1
diff --git a/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll b/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
index ecaa105dedcfe..112001dcf450f 100644
--- a/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
+++ b/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=x86_64-- -mcpu=core2 | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=x86_64-- -mcpu=core2 | FileCheck %s
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
 declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1) nounwind
diff --git a/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll b/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
index abd1d4e7d350c..fc50bc9072395 100644
--- a/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
+++ b/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
@@ -1,4 +1,4 @@
-; RUN: llc -no-stack-coloring=false < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -no-stack-coloring=false < %s | FileCheck %s
 
 ; This test crashed in PEI because the stack protector was dead.
 ; This was due to it being colored, which was in turn due to incorrect
diff --git a/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll b/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
index a4e5ae66b1fd8..04c75e0915c92 100644
--- a/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
+++ b/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
@@ -1,4 +1,4 @@
-; RUN: llc -o - %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -o - %s | FileCheck %s
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-apple-macosx"
 
diff --git a/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll b/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
index 72d75456ce4ce..6ea291c876be5 100644
--- a/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
+++ b/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
@@ -1,4 +1,4 @@
-; RUN: llc -enable-machine-outliner -mtriple=x86_64-apple-darwin < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -enable-machine-outliner -mtriple=x86_64-apple-darwin < %s | FileCheck %s
 ; Ensure that the outliner doesn't outline from any functions that use a redzone.
 
 declare ptr @llvm.stacksave() #1
diff --git a/llvm/test/CodeGen/X86/ssp-data-layout.ll b/llvm/test/CodeGen/X86/ssp-data-layout.ll
index bda2598384db8..16075f0149cc1 100644
--- a/llvm/test/CodeGen/X86/ssp-data-layout.ll
+++ b/llvm/test/CodeGen/X86/ssp-data-layout.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -stack-symbol-ordering=0 -frame-pointer=all -mtriple=x86_64-pc-linux-gnu -mcpu=corei7 -o - | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -stack-symbol-ordering=0 -frame-pointer=all -mtriple=x86_64-pc-linux-gnu -mcpu=corei7 -o - | FileCheck %s
 ;  This test is fairly fragile.  The goal is to ensure that "large" stack
 ;  objects are allocated closest to the stack protector (i.e., farthest away
 ;  from the Stack Pointer.)  In standard SSP mode this means that large (>=
diff --git a/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll b/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
index d18353a89126c..d136c70ff44bb 100644
--- a/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
+++ b/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple=x86_64 -O0 < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -mtriple=x86_64 -O0 < %s | FileCheck %s
 
 ; Check that we don't crash on this input.
 ; CHECK-LABEL: @foo
diff --git a/llvm/test/CodeGen/X86/stack-protector-remarks.ll b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
index cbd986a64eac6..cb08058e50fb6 100644
--- a/llvm/test/CodeGen/X86/stack-protector-remarks.ll
+++ b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -mtriple=x86_64-unknown-unknown -pass-remarks=stack-protector -o /dev/null 2>&1 | FileCheck %s
+; RUN: llc %s -ctpa-optimize-ssp=false -mtriple=x86_64-unknown-unknown -pass-remarks=stack-protector -o /dev/null 2>&1 | FileCheck %s
 ; CHECK-NOT: nossp
 ; CHECK: function attribute_ssp
 ; CHECK-SAME: a function attribute or command-line switch
diff --git a/llvm/test/CodeGen/X86/stackguard-internal.ll b/llvm/test/CodeGen/X86/stackguard-internal.ll
index 328e04b9a718c..15177b4d3d866 100644
--- a/llvm/test/CodeGen/X86/stackguard-internal.ll
+++ b/llvm/test/CodeGen/X86/stackguard-internal.ll
@@ -1,5 +1,5 @@
 ; Check that the backend doesn't crash.
-; RUN: llc -mtriple=x86_64-pc-freebsd %s -o - | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -mtriple=x86_64-pc-freebsd %s -o - | FileCheck %s
 
 @__stack_chk_guard = internal global [8 x i64] zeroinitializer, align 16
 
diff --git a/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll b/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
index 53202f19f7602..6aa986a9ebd7a 100644
--- a/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
+++ b/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -o - -stop-after=finalize-isel -verify-machineinstrs -experimental-debug-variable-locations | FileCheck %s
+; RUN: llc %s -o - -ctpa-optimize-ssp=false -stop-after=finalize-isel -verify-machineinstrs -experimental-debug-variable-locations | FileCheck %s
 
 ; In the sequence below, the sdiv is converted to a function call to __divsi3,
 ; which is then tail call optimised. The dbg.value is suddenly stuck between
diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll
index c554fdbf4c799..bb8e00c5b260b 100644
--- a/llvm/test/Other/new-pm-defaults.ll
+++ b/llvm/test/Other/new-pm-defaults.ll
@@ -235,6 +235,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
 ; CHECK-O-NEXT: Running pass: GlobalOptPass
diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll
index 3aea0f2061f3e..f8b4eabcbcdbc 100644
--- a/llvm/test/Other/new-pm-lto-defaults.ll
+++ b/llvm/test/Other/new-pm-lto-defaults.ll
@@ -67,6 +67,8 @@
 ; CHECK-O1-NEXT: Running analysis: TargetLibraryAnalysis
 ; CHECK-O-NEXT: Running pass: GlobalSplitPass
 ; CHECK-O-NEXT: Running pass: WholeProgramDevirtPass
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O23SZ-NEXT: Running pass: CoroEarlyPass
 ; CHECK-O1-NEXT: Running pass: LowerTypeTestsPass
 ; CHECK-O23SZ-NEXT: Running pass: GlobalOptPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
index 62bb02d9b3c40..fd1faf4bd9067 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
@@ -158,6 +158,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
index 0da7a9f73bdce..f25fce6fe497f 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
@@ -142,6 +142,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
index 38b7890682783..4422e9b7bb9e4 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
@@ -151,6 +151,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
index 5aacd26def2be..ba3d7e2fb58ad 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
@@ -188,6 +188,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: Shou...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jul 24, 2025

@llvm/pr-subscribers-debuginfo

Author: None (Mermen)

Changes

This pass uses StackSafetyGlobalAnalysis to reduce number of functions that require stack protector.

All llvm lit tests passed.

In llvm-test-suite it reduces number of instrumented functions by 13% (8883 -> 7723) under -O2 -fstack-protector-strong.


Patch is 24.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/150390.diff

31 Files Affected:

  • (modified) clang/test/Driver/memtag-stack_lto.c (+3-2)
  • (added) llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h (+33)
  • (modified) llvm/lib/Passes/PassBuilder.cpp (+1)
  • (modified) llvm/lib/Passes/PassBuilderPipelines.cpp (+6)
  • (modified) llvm/lib/Passes/PassRegistry.def (+1)
  • (modified) llvm/lib/Transforms/Scalar/CMakeLists.txt (+1)
  • (added) llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp (+60)
  • (modified) llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll (+1-1)
  • (modified) llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll (+1-1)
  • (modified) llvm/test/CodeGen/ARM/ssp-data-layout.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/fast-isel-stackcheck.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/machine-outliner-noredzone.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/ssp-data-layout.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stack-protector-remarks.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stackguard-internal.ll (+1-1)
  • (modified) llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll (+1-1)
  • (modified) llvm/test/Other/new-pm-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-lto-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll (+2)
  • (modified) llvm/test/ThinLTO/X86/nossp.ll (+3-3)
  • (added) llvm/test/Transforms/StackProtectAttributor/AArch64/stack-protector-attribute.c (+64)
diff --git a/clang/test/Driver/memtag-stack_lto.c b/clang/test/Driver/memtag-stack_lto.c
index 324bdec070873..fc014c027fcf8 100644
--- a/clang/test/Driver/memtag-stack_lto.c
+++ b/clang/test/Driver/memtag-stack_lto.c
@@ -33,7 +33,7 @@
 // RUN: rm -f %t*
 
 // -O0: both are unsafe.
-// RUN: %clang -O0 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o - 2>&1 | FileCheck %s
+// RUN: %clang -O0 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o - 2>&1 | FileCheck %s -check-prefixes=CHECK-O0
 
 // No LTO: just one is safe.
 // RUN: %clang -O1 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o /dev/null 2>&1 | FileCheck %s -check-prefixes=SSI,XUNSAFE,YSAFE
@@ -87,6 +87,7 @@ int fn() {
   return x + y;
 }
 
-// CHECK-NOT: allocas uses:
+// CHECK-O0-NOT: allocas uses:
+// CHECK: allocas uses:
 
 #endif
diff --git a/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h b/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h
new file mode 100644
index 0000000000000..d0097669d3067
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h
@@ -0,0 +1,33 @@
+//===- StackProtectAttributor.h - Stack Protect Attributoor ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
+#define LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
+
+#include "llvm/Analysis/StackSafetyAnalysis.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class BasicBlock;
+class Function;
+class Instruction;
+
+class StackProtectAttributorPass
+    : public PassInfoMixin<StackProtectAttributorPass> {
+public:
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+
+private:
+  void processFunction(Function &F) const;
+
+  const StackSafetyGlobalInfo *SSI;
+};
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f810368a84940..1eebf607ef366 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -324,6 +324,7 @@
 #include "llvm/Transforms/Scalar/Reassociate.h"
 #include "llvm/Transforms/Scalar/Reg2Mem.h"
 #include "llvm/Transforms/Scalar/RewriteStatepointsForGC.h"
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
 #include "llvm/Transforms/Scalar/SCCP.h"
 #include "llvm/Transforms/Scalar/SROA.h"
 #include "llvm/Transforms/Scalar/ScalarizeMaskedMemIntrin.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 98821bb1408a7..20e297bfa3dc5 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -127,6 +127,7 @@
 #include "llvm/Transforms/Scalar/SimpleLoopUnswitch.h"
 #include "llvm/Transforms/Scalar/SimplifyCFG.h"
 #include "llvm/Transforms/Scalar/SpeculativeExecution.h"
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
 #include "llvm/Transforms/Scalar/TailRecursionElimination.h"
 #include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
 #include "llvm/Transforms/Utils/AddDiscriminators.h"
@@ -1278,6 +1279,9 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
   else
     MPM.addPass(buildInlinerPipeline(Level, Phase));
 
+  if (Level != OptimizationLevel::O0)
+    MPM.addPass(StackProtectAttributorPass());
+
   // Remove any dead arguments exposed by cleanups, constant folding globals,
   // and argument promotion.
   MPM.addPass(DeadArgumentEliminationPass());
@@ -1944,6 +1948,8 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
   // is fixed.
   MPM.addPass(WholeProgramDevirtPass(ExportSummary, nullptr));
 
+  MPM.addPass(StackProtectAttributorPass());
+
   // Stop here at -O1.
   if (Level == OptimizationLevel::O1) {
     // The LowerTypeTestsPass needs to run to lower type metadata and the
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index bb7ccdb2bc187..d1a22c9ece01e 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -59,6 +59,7 @@ MODULE_PASS("canonicalize-aliases", CanonicalizeAliasesPass())
 MODULE_PASS("check-debugify", NewPMCheckDebugifyPass())
 MODULE_PASS("constmerge", ConstantMergePass())
 MODULE_PASS("coro-cleanup", CoroCleanupPass())
+MODULE_PASS("stack-protect-attributor", StackProtectAttributorPass())
 MODULE_PASS("coro-early", CoroEarlyPass())
 MODULE_PASS("cross-dso-cfi", CrossDSOCFIPass())
 MODULE_PASS("ctx-instr-gen",
diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt
index 84a5b02043d01..b161ab6810a8c 100644
--- a/llvm/lib/Transforms/Scalar/CMakeLists.txt
+++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt
@@ -64,6 +64,7 @@ add_llvm_component_library(LLVMScalarOpts
   PlaceSafepoints.cpp
   Reassociate.cpp
   Reg2Mem.cpp
+  StackProtectAttributor.cpp
   RewriteStatepointsForGC.cpp
   SCCP.cpp
   SROA.cpp
diff --git a/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp b/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp
new file mode 100644
index 0000000000000..8695cb32c4e5d
--- /dev/null
+++ b/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp
@@ -0,0 +1,60 @@
+//===- StackProtectAttributor.cpp - Stack Protect Attributoor -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "stack-protect-attributor"
+
+STATISTIC(
+    NumFuncsWithAllocaInst,
+    "Number of functions with an instruction to allocate memory on the stack");
+STATISTIC(NumFuncsWithRemovedStackProtectAttr,
+          "Number of functions with alloca and removed stack protect attr");
+
+static cl::opt<bool>
+    UseStackSafety("ctpa-optimize-ssp", cl::init(true), cl::Hidden,
+                   cl::desc("Use Stack Safety analysis results"));
+
+void StackProtectAttributorPass::processFunction(Function &F) const {
+
+  bool hasAlloca = false;
+
+  for (auto &I : instructions(&F))
+    if (auto *AI = dyn_cast<AllocaInst>(&I)) {
+      hasAlloca = true;
+      NumFuncsWithAllocaInst++;
+      if (!SSI->isSafe(*AI))
+        return;
+    }
+
+  if (hasAlloca)
+    NumFuncsWithRemovedStackProtectAttr++;
+
+  F.removeFnAttr(Attribute::StackProtect);
+  F.removeFnAttr(Attribute::StackProtectStrong);
+}
+
+PreservedAnalyses StackProtectAttributorPass::run(Module &M,
+                                                  ModuleAnalysisManager &MAM) {
+  if (!UseStackSafety)
+    return PreservedAnalyses::all();
+
+  SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);
+  for (Function &F : M)
+    if (F.hasFnAttribute(Attribute::StackProtect) ||
+        F.hasFnAttribute(Attribute::StackProtectStrong))
+      processFunction(F);
+
+  return PreservedAnalyses::all();
+}
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll b/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
index 683cdfd9eeac8..5faa0a6fc8d59 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple aarch64-unknown-unknown -global-isel \
+; RUN: llc -ctpa-optimize-ssp=false -mtriple aarch64-unknown-unknown -global-isel \
 ; RUN:     -no-stack-coloring=false -pass-remarks-missed=gisel* < %s \
 ; RUN:      2>&1 | FileCheck %s
 
diff --git a/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll b/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
index 4dc71bc90dcdc..32268bf29331c 100644
--- a/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
+++ b/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -o - -verify-machineinstrs | FileCheck %s
+; RUN: llc %s -o - -ctpa-optimize-ssp=false -verify-machineinstrs | FileCheck %s
 
 target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
 target triple = "thumbv7s-apple-ios8.0.0"
diff --git a/llvm/test/CodeGen/ARM/ssp-data-layout.ll b/llvm/test/CodeGen/ARM/ssp-data-layout.ll
index c5f13a66c11ca..ceffe076b985f 100644
--- a/llvm/test/CodeGen/ARM/ssp-data-layout.ll
+++ b/llvm/test/CodeGen/ARM/ssp-data-layout.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -frame-pointer=all -mcpu=cortex-a8 -mtriple arm-linux-gnu -target-abi=apcs -o - | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -frame-pointer=all -mcpu=cortex-a8 -mtriple arm-linux-gnu -target-abi=apcs -o - | FileCheck %s
 ;  This test is fairly fragile.  The goal is to ensure that "large" stack
 ;  objects are allocated closest to the stack protector (i.e., farthest away
 ;  from the Stack Pointer.)  In standard SSP mode this means that large (>=
diff --git a/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll b/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
index 822f6a4c4616e..ead9bc9b64245 100644
--- a/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
+++ b/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=i386-apple-darwin -O0 -regalloc=fast | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=i386-apple-darwin -O0 -regalloc=fast | FileCheck %s
 ; rdar://6787136
 
 	%struct.X = type { i8, [32 x i8] }
diff --git a/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll b/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
index 99a50295727c4..8062704971a5f 100644
--- a/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
+++ b/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s
 ; rdar://7396984
 
 @str = private unnamed_addr constant [28 x i8] c"xxxxxxxxxxxxxxxxxxxxxxxxxxx\00", align 1
diff --git a/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll b/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
index ecaa105dedcfe..112001dcf450f 100644
--- a/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
+++ b/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=x86_64-- -mcpu=core2 | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=x86_64-- -mcpu=core2 | FileCheck %s
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
 declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1) nounwind
diff --git a/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll b/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
index abd1d4e7d350c..fc50bc9072395 100644
--- a/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
+++ b/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
@@ -1,4 +1,4 @@
-; RUN: llc -no-stack-coloring=false < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -no-stack-coloring=false < %s | FileCheck %s
 
 ; This test crashed in PEI because the stack protector was dead.
 ; This was due to it being colored, which was in turn due to incorrect
diff --git a/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll b/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
index a4e5ae66b1fd8..04c75e0915c92 100644
--- a/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
+++ b/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
@@ -1,4 +1,4 @@
-; RUN: llc -o - %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -o - %s | FileCheck %s
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-apple-macosx"
 
diff --git a/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll b/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
index 72d75456ce4ce..6ea291c876be5 100644
--- a/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
+++ b/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
@@ -1,4 +1,4 @@
-; RUN: llc -enable-machine-outliner -mtriple=x86_64-apple-darwin < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -enable-machine-outliner -mtriple=x86_64-apple-darwin < %s | FileCheck %s
 ; Ensure that the outliner doesn't outline from any functions that use a redzone.
 
 declare ptr @llvm.stacksave() #1
diff --git a/llvm/test/CodeGen/X86/ssp-data-layout.ll b/llvm/test/CodeGen/X86/ssp-data-layout.ll
index bda2598384db8..16075f0149cc1 100644
--- a/llvm/test/CodeGen/X86/ssp-data-layout.ll
+++ b/llvm/test/CodeGen/X86/ssp-data-layout.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -stack-symbol-ordering=0 -frame-pointer=all -mtriple=x86_64-pc-linux-gnu -mcpu=corei7 -o - | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -stack-symbol-ordering=0 -frame-pointer=all -mtriple=x86_64-pc-linux-gnu -mcpu=corei7 -o - | FileCheck %s
 ;  This test is fairly fragile.  The goal is to ensure that "large" stack
 ;  objects are allocated closest to the stack protector (i.e., farthest away
 ;  from the Stack Pointer.)  In standard SSP mode this means that large (>=
diff --git a/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll b/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
index d18353a89126c..d136c70ff44bb 100644
--- a/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
+++ b/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple=x86_64 -O0 < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -mtriple=x86_64 -O0 < %s | FileCheck %s
 
 ; Check that we don't crash on this input.
 ; CHECK-LABEL: @foo
diff --git a/llvm/test/CodeGen/X86/stack-protector-remarks.ll b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
index cbd986a64eac6..cb08058e50fb6 100644
--- a/llvm/test/CodeGen/X86/stack-protector-remarks.ll
+++ b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -mtriple=x86_64-unknown-unknown -pass-remarks=stack-protector -o /dev/null 2>&1 | FileCheck %s
+; RUN: llc %s -ctpa-optimize-ssp=false -mtriple=x86_64-unknown-unknown -pass-remarks=stack-protector -o /dev/null 2>&1 | FileCheck %s
 ; CHECK-NOT: nossp
 ; CHECK: function attribute_ssp
 ; CHECK-SAME: a function attribute or command-line switch
diff --git a/llvm/test/CodeGen/X86/stackguard-internal.ll b/llvm/test/CodeGen/X86/stackguard-internal.ll
index 328e04b9a718c..15177b4d3d866 100644
--- a/llvm/test/CodeGen/X86/stackguard-internal.ll
+++ b/llvm/test/CodeGen/X86/stackguard-internal.ll
@@ -1,5 +1,5 @@
 ; Check that the backend doesn't crash.
-; RUN: llc -mtriple=x86_64-pc-freebsd %s -o - | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -mtriple=x86_64-pc-freebsd %s -o - | FileCheck %s
 
 @__stack_chk_guard = internal global [8 x i64] zeroinitializer, align 16
 
diff --git a/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll b/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
index 53202f19f7602..6aa986a9ebd7a 100644
--- a/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
+++ b/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -o - -stop-after=finalize-isel -verify-machineinstrs -experimental-debug-variable-locations | FileCheck %s
+; RUN: llc %s -o - -ctpa-optimize-ssp=false -stop-after=finalize-isel -verify-machineinstrs -experimental-debug-variable-locations | FileCheck %s
 
 ; In the sequence below, the sdiv is converted to a function call to __divsi3,
 ; which is then tail call optimised. The dbg.value is suddenly stuck between
diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll
index c554fdbf4c799..bb8e00c5b260b 100644
--- a/llvm/test/Other/new-pm-defaults.ll
+++ b/llvm/test/Other/new-pm-defaults.ll
@@ -235,6 +235,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
 ; CHECK-O-NEXT: Running pass: GlobalOptPass
diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll
index 3aea0f2061f3e..f8b4eabcbcdbc 100644
--- a/llvm/test/Other/new-pm-lto-defaults.ll
+++ b/llvm/test/Other/new-pm-lto-defaults.ll
@@ -67,6 +67,8 @@
 ; CHECK-O1-NEXT: Running analysis: TargetLibraryAnalysis
 ; CHECK-O-NEXT: Running pass: GlobalSplitPass
 ; CHECK-O-NEXT: Running pass: WholeProgramDevirtPass
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O23SZ-NEXT: Running pass: CoroEarlyPass
 ; CHECK-O1-NEXT: Running pass: LowerTypeTestsPass
 ; CHECK-O23SZ-NEXT: Running pass: GlobalOptPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
index 62bb02d9b3c40..fd1faf4bd9067 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
@@ -158,6 +158,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
index 0da7a9f73bdce..f25fce6fe497f 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
@@ -142,6 +142,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
index 38b7890682783..4422e9b7bb9e4 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
@@ -151,6 +151,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
index 5aacd26def2be..ba3d7e2fb58ad 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
@@ -188,6 +188,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: Shou...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jul 24, 2025

@llvm/pr-subscribers-llvm-transforms

Author: None (Mermen)

Changes

This pass uses StackSafetyGlobalAnalysis to reduce number of functions that require stack protector.

All llvm lit tests passed.

In llvm-test-suite it reduces number of instrumented functions by 13% (8883 -> 7723) under -O2 -fstack-protector-strong.


Patch is 24.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/150390.diff

31 Files Affected:

  • (modified) clang/test/Driver/memtag-stack_lto.c (+3-2)
  • (added) llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h (+33)
  • (modified) llvm/lib/Passes/PassBuilder.cpp (+1)
  • (modified) llvm/lib/Passes/PassBuilderPipelines.cpp (+6)
  • (modified) llvm/lib/Passes/PassRegistry.def (+1)
  • (modified) llvm/lib/Transforms/Scalar/CMakeLists.txt (+1)
  • (added) llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp (+60)
  • (modified) llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll (+1-1)
  • (modified) llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll (+1-1)
  • (modified) llvm/test/CodeGen/ARM/ssp-data-layout.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/fast-isel-stackcheck.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/machine-outliner-noredzone.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/ssp-data-layout.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stack-protector-remarks.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/stackguard-internal.ll (+1-1)
  • (modified) llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll (+1-1)
  • (modified) llvm/test/Other/new-pm-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-lto-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll (+2)
  • (modified) llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll (+2)
  • (modified) llvm/test/ThinLTO/X86/nossp.ll (+3-3)
  • (added) llvm/test/Transforms/StackProtectAttributor/AArch64/stack-protector-attribute.c (+64)
diff --git a/clang/test/Driver/memtag-stack_lto.c b/clang/test/Driver/memtag-stack_lto.c
index 324bdec070873..fc014c027fcf8 100644
--- a/clang/test/Driver/memtag-stack_lto.c
+++ b/clang/test/Driver/memtag-stack_lto.c
@@ -33,7 +33,7 @@
 // RUN: rm -f %t*
 
 // -O0: both are unsafe.
-// RUN: %clang -O0 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o - 2>&1 | FileCheck %s
+// RUN: %clang -O0 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o - 2>&1 | FileCheck %s -check-prefixes=CHECK-O0
 
 // No LTO: just one is safe.
 // RUN: %clang -O1 --target=aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag-stack -mllvm -stack-safety-print %s -S -o /dev/null 2>&1 | FileCheck %s -check-prefixes=SSI,XUNSAFE,YSAFE
@@ -87,6 +87,7 @@ int fn() {
   return x + y;
 }
 
-// CHECK-NOT: allocas uses:
+// CHECK-O0-NOT: allocas uses:
+// CHECK: allocas uses:
 
 #endif
diff --git a/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h b/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h
new file mode 100644
index 0000000000000..d0097669d3067
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Scalar/StackProtectAttributor.h
@@ -0,0 +1,33 @@
+//===- StackProtectAttributor.h - Stack Protect Attributoor ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
+#define LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
+
+#include "llvm/Analysis/StackSafetyAnalysis.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class BasicBlock;
+class Function;
+class Instruction;
+
+class StackProtectAttributorPass
+    : public PassInfoMixin<StackProtectAttributorPass> {
+public:
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+
+private:
+  void processFunction(Function &F) const;
+
+  const StackSafetyGlobalInfo *SSI;
+};
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_ATTRIBUTTOR_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f810368a84940..1eebf607ef366 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -324,6 +324,7 @@
 #include "llvm/Transforms/Scalar/Reassociate.h"
 #include "llvm/Transforms/Scalar/Reg2Mem.h"
 #include "llvm/Transforms/Scalar/RewriteStatepointsForGC.h"
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
 #include "llvm/Transforms/Scalar/SCCP.h"
 #include "llvm/Transforms/Scalar/SROA.h"
 #include "llvm/Transforms/Scalar/ScalarizeMaskedMemIntrin.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 98821bb1408a7..20e297bfa3dc5 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -127,6 +127,7 @@
 #include "llvm/Transforms/Scalar/SimpleLoopUnswitch.h"
 #include "llvm/Transforms/Scalar/SimplifyCFG.h"
 #include "llvm/Transforms/Scalar/SpeculativeExecution.h"
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
 #include "llvm/Transforms/Scalar/TailRecursionElimination.h"
 #include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
 #include "llvm/Transforms/Utils/AddDiscriminators.h"
@@ -1278,6 +1279,9 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
   else
     MPM.addPass(buildInlinerPipeline(Level, Phase));
 
+  if (Level != OptimizationLevel::O0)
+    MPM.addPass(StackProtectAttributorPass());
+
   // Remove any dead arguments exposed by cleanups, constant folding globals,
   // and argument promotion.
   MPM.addPass(DeadArgumentEliminationPass());
@@ -1944,6 +1948,8 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
   // is fixed.
   MPM.addPass(WholeProgramDevirtPass(ExportSummary, nullptr));
 
+  MPM.addPass(StackProtectAttributorPass());
+
   // Stop here at -O1.
   if (Level == OptimizationLevel::O1) {
     // The LowerTypeTestsPass needs to run to lower type metadata and the
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index bb7ccdb2bc187..d1a22c9ece01e 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -59,6 +59,7 @@ MODULE_PASS("canonicalize-aliases", CanonicalizeAliasesPass())
 MODULE_PASS("check-debugify", NewPMCheckDebugifyPass())
 MODULE_PASS("constmerge", ConstantMergePass())
 MODULE_PASS("coro-cleanup", CoroCleanupPass())
+MODULE_PASS("stack-protect-attributor", StackProtectAttributorPass())
 MODULE_PASS("coro-early", CoroEarlyPass())
 MODULE_PASS("cross-dso-cfi", CrossDSOCFIPass())
 MODULE_PASS("ctx-instr-gen",
diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt
index 84a5b02043d01..b161ab6810a8c 100644
--- a/llvm/lib/Transforms/Scalar/CMakeLists.txt
+++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt
@@ -64,6 +64,7 @@ add_llvm_component_library(LLVMScalarOpts
   PlaceSafepoints.cpp
   Reassociate.cpp
   Reg2Mem.cpp
+  StackProtectAttributor.cpp
   RewriteStatepointsForGC.cpp
   SCCP.cpp
   SROA.cpp
diff --git a/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp b/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp
new file mode 100644
index 0000000000000..8695cb32c4e5d
--- /dev/null
+++ b/llvm/lib/Transforms/Scalar/StackProtectAttributor.cpp
@@ -0,0 +1,60 @@
+//===- StackProtectAttributor.cpp - Stack Protect Attributoor -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "stack-protect-attributor"
+
+STATISTIC(
+    NumFuncsWithAllocaInst,
+    "Number of functions with an instruction to allocate memory on the stack");
+STATISTIC(NumFuncsWithRemovedStackProtectAttr,
+          "Number of functions with alloca and removed stack protect attr");
+
+static cl::opt<bool>
+    UseStackSafety("ctpa-optimize-ssp", cl::init(true), cl::Hidden,
+                   cl::desc("Use Stack Safety analysis results"));
+
+void StackProtectAttributorPass::processFunction(Function &F) const {
+
+  bool hasAlloca = false;
+
+  for (auto &I : instructions(&F))
+    if (auto *AI = dyn_cast<AllocaInst>(&I)) {
+      hasAlloca = true;
+      NumFuncsWithAllocaInst++;
+      if (!SSI->isSafe(*AI))
+        return;
+    }
+
+  if (hasAlloca)
+    NumFuncsWithRemovedStackProtectAttr++;
+
+  F.removeFnAttr(Attribute::StackProtect);
+  F.removeFnAttr(Attribute::StackProtectStrong);
+}
+
+PreservedAnalyses StackProtectAttributorPass::run(Module &M,
+                                                  ModuleAnalysisManager &MAM) {
+  if (!UseStackSafety)
+    return PreservedAnalyses::all();
+
+  SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);
+  for (Function &F : M)
+    if (F.hasFnAttribute(Attribute::StackProtect) ||
+        F.hasFnAttribute(Attribute::StackProtectStrong))
+      processFunction(F);
+
+  return PreservedAnalyses::all();
+}
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll b/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
index 683cdfd9eeac8..5faa0a6fc8d59 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/dynamic-alloca-lifetime.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple aarch64-unknown-unknown -global-isel \
+; RUN: llc -ctpa-optimize-ssp=false -mtriple aarch64-unknown-unknown -global-isel \
 ; RUN:     -no-stack-coloring=false -pass-remarks-missed=gisel* < %s \
 ; RUN:      2>&1 | FileCheck %s
 
diff --git a/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll b/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
index 4dc71bc90dcdc..32268bf29331c 100644
--- a/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
+++ b/llvm/test/CodeGen/ARM/ifcvt-regmask-noreturn.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -o - -verify-machineinstrs | FileCheck %s
+; RUN: llc %s -o - -ctpa-optimize-ssp=false -verify-machineinstrs | FileCheck %s
 
 target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
 target triple = "thumbv7s-apple-ios8.0.0"
diff --git a/llvm/test/CodeGen/ARM/ssp-data-layout.ll b/llvm/test/CodeGen/ARM/ssp-data-layout.ll
index c5f13a66c11ca..ceffe076b985f 100644
--- a/llvm/test/CodeGen/ARM/ssp-data-layout.ll
+++ b/llvm/test/CodeGen/ARM/ssp-data-layout.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -frame-pointer=all -mcpu=cortex-a8 -mtriple arm-linux-gnu -target-abi=apcs -o - | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -frame-pointer=all -mcpu=cortex-a8 -mtriple arm-linux-gnu -target-abi=apcs -o - | FileCheck %s
 ;  This test is fairly fragile.  The goal is to ensure that "large" stack
 ;  objects are allocated closest to the stack protector (i.e., farthest away
 ;  from the Stack Pointer.)  In standard SSP mode this means that large (>=
diff --git a/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll b/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
index 822f6a4c4616e..ead9bc9b64245 100644
--- a/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
+++ b/llvm/test/CodeGen/X86/2009-04-14-IllegalRegs.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=i386-apple-darwin -O0 -regalloc=fast | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=i386-apple-darwin -O0 -regalloc=fast | FileCheck %s
 ; rdar://6787136
 
 	%struct.X = type { i8, [32 x i8] }
diff --git a/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll b/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
index 99a50295727c4..8062704971a5f 100644
--- a/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
+++ b/llvm/test/CodeGen/X86/2009-11-16-UnfoldMemOpBug.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s
 ; rdar://7396984
 
 @str = private unnamed_addr constant [28 x i8] c"xxxxxxxxxxxxxxxxxxxxxxxxxxx\00", align 1
diff --git a/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll b/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
index ecaa105dedcfe..112001dcf450f 100644
--- a/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
+++ b/llvm/test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=x86_64-- -mcpu=core2 | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -mtriple=x86_64-- -mcpu=core2 | FileCheck %s
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
 declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1) nounwind
diff --git a/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll b/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
index abd1d4e7d350c..fc50bc9072395 100644
--- a/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
+++ b/llvm/test/CodeGen/X86/dynamic-alloca-lifetime.ll
@@ -1,4 +1,4 @@
-; RUN: llc -no-stack-coloring=false < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -no-stack-coloring=false < %s | FileCheck %s
 
 ; This test crashed in PEI because the stack protector was dead.
 ; This was due to it being colored, which was in turn due to incorrect
diff --git a/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll b/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
index a4e5ae66b1fd8..04c75e0915c92 100644
--- a/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
+++ b/llvm/test/CodeGen/X86/fast-isel-stackcheck.ll
@@ -1,4 +1,4 @@
-; RUN: llc -o - %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -o - %s | FileCheck %s
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-apple-macosx"
 
diff --git a/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll b/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
index 72d75456ce4ce..6ea291c876be5 100644
--- a/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
+++ b/llvm/test/CodeGen/X86/machine-outliner-noredzone.ll
@@ -1,4 +1,4 @@
-; RUN: llc -enable-machine-outliner -mtriple=x86_64-apple-darwin < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -enable-machine-outliner -mtriple=x86_64-apple-darwin < %s | FileCheck %s
 ; Ensure that the outliner doesn't outline from any functions that use a redzone.
 
 declare ptr @llvm.stacksave() #1
diff --git a/llvm/test/CodeGen/X86/ssp-data-layout.ll b/llvm/test/CodeGen/X86/ssp-data-layout.ll
index bda2598384db8..16075f0149cc1 100644
--- a/llvm/test/CodeGen/X86/ssp-data-layout.ll
+++ b/llvm/test/CodeGen/X86/ssp-data-layout.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -stack-symbol-ordering=0 -frame-pointer=all -mtriple=x86_64-pc-linux-gnu -mcpu=corei7 -o - | FileCheck %s
+; RUN: llc < %s -ctpa-optimize-ssp=false -stack-symbol-ordering=0 -frame-pointer=all -mtriple=x86_64-pc-linux-gnu -mcpu=corei7 -o - | FileCheck %s
 ;  This test is fairly fragile.  The goal is to ensure that "large" stack
 ;  objects are allocated closest to the stack protector (i.e., farthest away
 ;  from the Stack Pointer.)  In standard SSP mode this means that large (>=
diff --git a/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll b/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
index d18353a89126c..d136c70ff44bb 100644
--- a/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
+++ b/llvm/test/CodeGen/X86/stack-guard-memloc-vararg.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mtriple=x86_64 -O0 < %s | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -mtriple=x86_64 -O0 < %s | FileCheck %s
 
 ; Check that we don't crash on this input.
 ; CHECK-LABEL: @foo
diff --git a/llvm/test/CodeGen/X86/stack-protector-remarks.ll b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
index cbd986a64eac6..cb08058e50fb6 100644
--- a/llvm/test/CodeGen/X86/stack-protector-remarks.ll
+++ b/llvm/test/CodeGen/X86/stack-protector-remarks.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -mtriple=x86_64-unknown-unknown -pass-remarks=stack-protector -o /dev/null 2>&1 | FileCheck %s
+; RUN: llc %s -ctpa-optimize-ssp=false -mtriple=x86_64-unknown-unknown -pass-remarks=stack-protector -o /dev/null 2>&1 | FileCheck %s
 ; CHECK-NOT: nossp
 ; CHECK: function attribute_ssp
 ; CHECK-SAME: a function attribute or command-line switch
diff --git a/llvm/test/CodeGen/X86/stackguard-internal.ll b/llvm/test/CodeGen/X86/stackguard-internal.ll
index 328e04b9a718c..15177b4d3d866 100644
--- a/llvm/test/CodeGen/X86/stackguard-internal.ll
+++ b/llvm/test/CodeGen/X86/stackguard-internal.ll
@@ -1,5 +1,5 @@
 ; Check that the backend doesn't crash.
-; RUN: llc -mtriple=x86_64-pc-freebsd %s -o - | FileCheck %s
+; RUN: llc -ctpa-optimize-ssp=false -mtriple=x86_64-pc-freebsd %s -o - | FileCheck %s
 
 @__stack_chk_guard = internal global [8 x i64] zeroinitializer, align 16
 
diff --git a/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll b/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
index 53202f19f7602..6aa986a9ebd7a 100644
--- a/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
+++ b/llvm/test/DebugInfo/ARM/instr-ref-tcreturn.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s -o - -stop-after=finalize-isel -verify-machineinstrs -experimental-debug-variable-locations | FileCheck %s
+; RUN: llc %s -o - -ctpa-optimize-ssp=false -stop-after=finalize-isel -verify-machineinstrs -experimental-debug-variable-locations | FileCheck %s
 
 ; In the sequence below, the sdiv is converted to a function call to __divsi3,
 ; which is then tail call optimised. The dbg.value is suddenly stuck between
diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll
index c554fdbf4c799..bb8e00c5b260b 100644
--- a/llvm/test/Other/new-pm-defaults.ll
+++ b/llvm/test/Other/new-pm-defaults.ll
@@ -235,6 +235,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
 ; CHECK-O-NEXT: Running pass: GlobalOptPass
diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll
index 3aea0f2061f3e..f8b4eabcbcdbc 100644
--- a/llvm/test/Other/new-pm-lto-defaults.ll
+++ b/llvm/test/Other/new-pm-lto-defaults.ll
@@ -67,6 +67,8 @@
 ; CHECK-O1-NEXT: Running analysis: TargetLibraryAnalysis
 ; CHECK-O-NEXT: Running pass: GlobalSplitPass
 ; CHECK-O-NEXT: Running pass: WholeProgramDevirtPass
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O23SZ-NEXT: Running pass: CoroEarlyPass
 ; CHECK-O1-NEXT: Running pass: LowerTypeTestsPass
 ; CHECK-O23SZ-NEXT: Running pass: GlobalOptPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
index 62bb02d9b3c40..fd1faf4bd9067 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
@@ -158,6 +158,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
index 0da7a9f73bdce..f25fce6fe497f 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
@@ -142,6 +142,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
index 38b7890682783..4422e9b7bb9e4 100644
--- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
@@ -151,6 +151,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis
+; CHECK-O-NEXT: Running pass: StackProtectAttributorPass
+; CHECK-O-NEXT: Running analysis: StackSafetyGlobalAnalysis
 ; CHECK-O-NEXT: Running pass: DeadArgumentEliminationPass
 ; CHECK-O-NEXT: Running pass: SimplifyTypeTestsPass
 ; CHECK-O-NEXT: Running pass: CoroCleanupPass
diff --git a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
index 5aacd26def2be..ba3d7e2fb58ad 100644
--- a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
+++ b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll
@@ -188,6 +188,8 @@
 ; CHECK-O-NEXT: Running pass: InvalidateAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis
 ; CHECK-O-NEXT: Invalidating analysis: Shou...
[truncated]

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a separate pass that removes attributes from the function if all allocas are safe, rather than integrated with the actual stack protection, so that the decision can be made per alloca?

@Mermen
Copy link
Author

Mermen commented Jul 24, 2025

@vitalybuka @eugenis FYI

@Mermen
Copy link
Author

Mermen commented Jul 24, 2025

Why is this a separate pass that removes attributes from the function if all allocas are safe, rather than integrated with the actual stack protection, so that the decision can be made per alloca?

StackSafetyAnalysis is a module pass so using it in StackProtectorPass (which is a function pass) changes pipeline significantly (introducing spurious changes in tests and performance jitter).

@Mermen Mermen force-pushed the stack-protect-attributor branch 2 times, most recently from 627fe89 to ce503cf Compare July 24, 2025 09:34
@@ -324,6 +324,7 @@
#include "llvm/Transforms/Scalar/Reassociate.h"
#include "llvm/Transforms/Scalar/Reg2Mem.h"
#include "llvm/Transforms/Scalar/RewriteStatepointsForGC.h"
#include "llvm/Transforms/Scalar/StackProtectAttributor.h"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sorted correctly

Copy link
Collaborator

@pogo59 pogo59 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"StackProtectAttributor" sounds like it is adding stack-protection attributes, but it is actually removing them. Please find a better name; "StackProtectRefinement" maybe?

Copy link
Contributor

@arsenm arsenm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not use attributor and should not have attributor in the name

@Mermen Mermen force-pushed the stack-protect-attributor branch from ce503cf to 2242daa Compare August 2, 2025 08:22
@Mermen Mermen changed the title [StackProtector] Introduce stack-protect-attributor pass to remove unnecessary protections. [StackProtector] Introduce stack-protect-refinement pass to remove unnecessary protections. Aug 4, 2025
@Mermen Mermen force-pushed the stack-protect-attributor branch from 2242daa to f1c7f73 Compare August 4, 2025 11:35
@Mermen
Copy link
Author

Mermen commented Aug 4, 2025

I have chosen new name "StackProtectRefinement" and made necessary changes.
Please check @pogo59 @arsenm

Copy link
Collaborator

@pogo59 pogo59 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly stylistic suggestions.

@@ -59,6 +59,7 @@ MODULE_PASS("canonicalize-aliases", CanonicalizeAliasesPass())
MODULE_PASS("check-debugify", NewPMCheckDebugifyPass())
MODULE_PASS("constmerge", ConstantMergePass())
MODULE_PASS("coro-cleanup", CoroCleanupPass())
MODULE_PASS("stack-protect-refinement", StackProtectRefinementPass())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The list is sorted, pls put in correct position


bool hasAlloca = false;

for (auto &I : instructions(&F))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls put braces around this for-loop body. It is technically one statement but contains nested statements with their own braces.

@@ -0,0 +1,64 @@
// RUN: clang -O2 -fstack-protector-strong -emit-llvm -S %s -o - | FileCheck %s


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls remove excess blank lines, you need only one

}

//.
// CHECK-NOT: attributes #[[ATTR1]] = {{.* sspstrong}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// CHECK-NOT: attributes #[[ATTR1]] = {{.* sspstrong}}
// CHECK: attributes #[[ATTR1]] =
// CHECK-NOT: sspstrong

Not a big deal but slightly more robust IMO to have positive checks for each attribute number

// CHECK: attributes #[[ATTR2]] = {{.* sspstrong}}
// CHECK: attributes #[[ATTR3]] = {{.* sspstrong}}
// CHECK: attributes #[[ATTR4]] = {{.* sspstrong}}
// CHECK-NOT: attributes #[[ATTR5]] = {{.* sspstrong}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// CHECK-NOT: attributes #[[ATTR5]] = {{.* sspstrong}}
// CHECK: attributes #[[ATTR5]] =
// CHECK-NOT: sspstrong

Comment on lines 9 to 10
#ifndef LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_REFINEMENT_H
#define LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_REFINEMENT_H
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#ifndef LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_REFINEMENT_H
#define LLVM_TRANSFORMS_SCALAR_STACK_PROTECT_REFINEMENT_H
#ifndef LLVM_TRANSFORMS_SCALAR_STACKPROTECTREFINEMENT_H
#define LLVM_TRANSFORMS_SCALAR_STACKPROTECTREFINEMENT_H

Underscores replace punctuation rather than separating words

// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Remove ssp attributes from functions where we can prove it is safe.

@pogo59
Copy link
Collaborator

pogo59 commented Aug 4, 2025

Any data on compile-time cost? I imagine it won't be huge but worth it to look at one decent-sized example.

…necessary protections.

This pass uses StackSafetyGlobalAnalysis to reduce number of functions that require stack protector.
@Mermen Mermen force-pushed the stack-protect-attributor branch from f1c7f73 to 7a7ced9 Compare August 6, 2025 19:39
for (auto &I : instructions(&F)) {
if (auto *AI = dyn_cast<AllocaInst>(&I)) {
hasAlloca = true;
if (!SSI->isSafe(*AI)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is all the pass is doing, should this just be done directly in the SSP lowering pass?

Stripping the attribute seems potentially dangerous. Suppose a later pass chooses to introduce a new unsafe alloca, which will now no longer be appropriately processed during lowering

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 backend:ARM backend:X86 clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category debuginfo llvm:globalisel llvm:transforms LTO Link time optimization (regular/full LTO or ThinLTO)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants