[llvm] [Passes][FuncSpec] Move optsize/minsize handling into pass (PR #189952)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 1 05:59:16 PDT 2026


https://github.com/nikic created https://github.com/llvm/llvm-project/pull/189952

Instead of using the Os/Oz level during pass pipeline construction, query the optsize/minsize attribute on the function to determine whether specialization is allowed to take place. This ensures consistent behavior for per-function attributes.

It's worth noting that FuncSpec *already* checks for minsize, but at the call-site level.

>From 409fdae8a87a0bcf656b8848da5a05b3f3e3a249 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Wed, 1 Apr 2026 14:53:46 +0200
Subject: [PATCH] [Passes][FuncSpec] Move optsize/minsize handling into pass

Instead of using the Os/Oz level during pass pipeline construction,
query the optsize/minsize attribute on the function to determine
whether specialization is allowed to take place. This ensures
consistent behavior for per-function attributes.

It's worth noting that FuncSpec *already* checks for minsize, but
at the call-site level.
---
 llvm/lib/Passes/PassBuilderPipelines.cpp      | 11 ++----
 .../Transforms/IPO/FunctionSpecialization.cpp |  3 ++
 .../function-specialization-optsize.ll        | 39 +++++++++++++++++++
 3 files changed, 45 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/Transforms/FunctionSpecialization/function-specialization-optsize.ll

diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 6f5b1c2e2fcc7..5ce71899f34ab 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -1192,11 +1192,8 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
   // and prior to optimizing globals.
   // FIXME: This position in the pipeline hasn't been carefully considered in
   // years, it should be re-analyzed.
-  MPM.addPass(IPSCCPPass(
-              IPSCCPOptions(/*AllowFuncSpec=*/
-                            Level != OptimizationLevel::Os &&
-                            Level != OptimizationLevel::Oz &&
-                            !isLTOPreLink(Phase))));
+  MPM.addPass(
+      IPSCCPPass(IPSCCPOptions(/*AllowFuncSpec=*/!isLTOPreLink(Phase))));
 
   // Attach metadata to indirect call sites indicating the set of functions
   // they may target at run-time. This should follow IPSCCP.
@@ -2032,9 +2029,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
     // Propagate constants at call sites into the functions they call.  This
     // opens opportunities for globalopt (and inlining) by substituting function
     // pointers passed as arguments to direct uses of functions.
-    MPM.addPass(IPSCCPPass(IPSCCPOptions(/*AllowFuncSpec=*/
-                                         Level != OptimizationLevel::Os &&
-                                         Level != OptimizationLevel::Oz)));
+    MPM.addPass(IPSCCPPass(IPSCCPOptions(/*AllowFuncSpec=*/true)));
 
     // Attach metadata to indirect call sites indicating the set of functions
     // they may target at run-time. This should follow IPSCCP.
diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
index cd914db8434ef..1367940ad8ef8 100644
--- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
@@ -1044,6 +1044,9 @@ bool FunctionSpecializer::isCandidateFunction(Function *F) {
   if (F->hasFnAttribute(Attribute::NoDuplicate))
     return false;
 
+  if (F->hasOptSize())
+    return false;
+
   // Do not specialize the cloned function again.
   if (Specializations.contains(F))
     return false;
diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-optsize.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-optsize.ll
new file mode 100644
index 0000000000000..9a2be2865428a
--- /dev/null
+++ b/llvm/test/Transforms/FunctionSpecialization/function-specialization-optsize.ll
@@ -0,0 +1,39 @@
+; RUN: opt -passes="ipsccp<func-spec>" -S < %s | FileCheck %s
+
+; CHECK-NOT: @compute.specialized.1
+; CHECK-NOT: @compute.specialized.2
+
+define i64 @main(i64 %x, i1 %flag) {
+entry:
+  br i1 %flag, label %plus, label %minus
+
+plus:
+  %tmp0 = call i64 @compute(i64 %x, ptr @plus)
+  br label %merge
+
+minus:
+  %tmp1 = call i64 @compute(i64 %x, ptr @minus)
+  br label %merge
+
+merge:
+  %tmp2 = phi i64 [ %tmp0, %plus ], [ %tmp1, %minus]
+  ret i64 %tmp2
+}
+
+define internal i64 @compute(i64 %x, ptr %binop) optsize {
+entry:
+  %tmp0 = call i64 %binop(i64 %x)
+  ret i64 %tmp0
+}
+
+define internal i64 @plus(i64 %x) {
+entry:
+  %tmp0 = add i64 %x, 1
+  ret i64 %tmp0
+}
+
+define internal i64 @minus(i64 %x) {
+entry:
+  %tmp0 = sub i64 %x, 1
+  ret i64 %tmp0
+}



More information about the llvm-commits mailing list