[llvm] [FunctionAttrs] Don't bail out on unknown calls (PR #150958)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 28 07:26:34 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Nikita Popov (nikic)

<details>
<summary>Changes</summary>

When inferring attributes, we should not bail out early on unknown calls (such as virtual calls), as we may still have call-site attributes that can be used for inference.

This drops the HasUnknownCall flag and adjusts the norecurse implementation to check call attributes (all other inference already did that).

Fixes https://github.com/llvm/llvm-project/issues/150817.

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


5 Files Affected:

- (modified) llvm/lib/Transforms/IPO/FunctionAttrs.cpp (+11-31) 
- (modified) llvm/test/Transforms/FunctionAttrs/noalias.ll (+1-1) 
- (modified) llvm/test/Transforms/FunctionAttrs/nonnull.ll (+1-1) 
- (modified) llvm/test/Transforms/FunctionAttrs/norecurse.ll (+3-2) 
- (modified) llvm/test/Transforms/FunctionAttrs/nounwind.ll (+3-2) 


``````````diff
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index f43202eea6306..7fde4605e5686 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -1863,7 +1863,6 @@ void AttributeInferer::run(const SCCNodeSet &SCCNodes,
 
 struct SCCNodesResult {
   SCCNodeSet SCCNodes;
-  bool HasUnknownCall;
 };
 
 } // end anonymous namespace
@@ -2087,11 +2086,13 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
   for (auto &BB : *F)
     for (auto &I : BB.instructionsWithoutDebug())
       if (auto *CB = dyn_cast<CallBase>(&I)) {
+        if (CB->hasFnAttr(Attribute::NoRecurse))
+          continue;
+
         Function *Callee = CB->getCalledFunction();
         if (!Callee || Callee == F ||
-            (!Callee->doesNotRecurse() &&
-             !(Callee->isDeclaration() &&
-               Callee->hasFnAttribute(Attribute::NoCallback))))
+            !(Callee->isDeclaration() &&
+              Callee->hasFnAttribute(Attribute::NoCallback)))
           // Function calls a potentially recursive function.
           return;
       }
@@ -2227,29 +2228,13 @@ static void addWillReturn(const SCCNodeSet &SCCNodes,
 
 static SCCNodesResult createSCCNodeSet(ArrayRef<Function *> Functions) {
   SCCNodesResult Res;
-  Res.HasUnknownCall = false;
   for (Function *F : Functions) {
     if (!F || F->hasOptNone() || F->hasFnAttribute(Attribute::Naked) ||
         F->isPresplitCoroutine()) {
-      // Treat any function we're trying not to optimize as if it were an
-      // indirect call and omit it from the node set used below.
-      Res.HasUnknownCall = true;
+      // Omit any functions we're trying not to optimize from the set.
       continue;
     }
-    // Track whether any functions in this SCC have an unknown call edge.
-    // Note: if this is ever a performance hit, we can common it with
-    // subsequent routines which also do scans over the instructions of the
-    // function.
-    if (!Res.HasUnknownCall) {
-      for (Instruction &I : instructions(*F)) {
-        if (auto *CB = dyn_cast<CallBase>(&I)) {
-          if (!CB->getCalledFunction()) {
-            Res.HasUnknownCall = true;
-            break;
-          }
-        }
-      }
-    }
+
     Res.SCCNodes.insert(F);
   }
   return Res;
@@ -2282,15 +2267,10 @@ deriveAttrsInPostOrder(ArrayRef<Function *> Functions, AARGetterT &&AARGetter,
   addColdAttrs(Nodes.SCCNodes, Changed);
   addWillReturn(Nodes.SCCNodes, Changed);
   addNoUndefAttrs(Nodes.SCCNodes, Changed);
-
-  // If we have no external nodes participating in the SCC, we can deduce some
-  // more precise attributes as well.
-  if (!Nodes.HasUnknownCall) {
-    addNoAliasAttrs(Nodes.SCCNodes, Changed);
-    addNonNullAttrs(Nodes.SCCNodes, Changed);
-    inferAttrsFromFunctionBodies(Nodes.SCCNodes, Changed);
-    addNoRecurseAttrs(Nodes.SCCNodes, Changed);
-  }
+  addNoAliasAttrs(Nodes.SCCNodes, Changed);
+  addNonNullAttrs(Nodes.SCCNodes, Changed);
+  inferAttrsFromFunctionBodies(Nodes.SCCNodes, Changed);
+  addNoRecurseAttrs(Nodes.SCCNodes, Changed);
 
   // Finally, infer the maximal set of attributes from the ones we've inferred
   // above.  This is handling the cases where one attribute on a signature
diff --git a/llvm/test/Transforms/FunctionAttrs/noalias.ll b/llvm/test/Transforms/FunctionAttrs/noalias.ll
index 8beb6fe78f852..de8bd9eade621 100644
--- a/llvm/test/Transforms/FunctionAttrs/noalias.ll
+++ b/llvm/test/Transforms/FunctionAttrs/noalias.ll
@@ -235,7 +235,7 @@ define ptr @return_unknown_call(ptr %fn) {
 }
 
 define ptr @return_unknown_noalias_call(ptr %fn) {
-; CHECK-LABEL: define ptr @return_unknown_noalias_call(
+; CHECK-LABEL: define noalias ptr @return_unknown_noalias_call(
 ; CHECK-SAME: ptr readonly captures(none) [[FN:%.*]]) {
 ; CHECK-NEXT:    [[A:%.*]] = call noalias ptr [[FN]]()
 ; CHECK-NEXT:    ret ptr [[A]]
diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
index 9b17ded3bdb26..8df242fb023af 100644
--- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
@@ -1412,7 +1412,7 @@ define ptr @unknown_func(ptr %fn) {
 }
 
 define ptr @unknown_nonnull_func(ptr %fn) {
-; FNATTRS-LABEL: define ptr @unknown_nonnull_func(
+; FNATTRS-LABEL: define nonnull ptr @unknown_nonnull_func(
 ; FNATTRS-SAME: ptr readonly captures(none) [[FN:%.*]]) {
 ; FNATTRS-NEXT:    [[RES:%.*]] = call nonnull ptr [[FN]]()
 ; FNATTRS-NEXT:    ret ptr [[RES]]
diff --git a/llvm/test/Transforms/FunctionAttrs/norecurse.ll b/llvm/test/Transforms/FunctionAttrs/norecurse.ll
index 5cb8ac05847aa..a9437848150da 100644
--- a/llvm/test/Transforms/FunctionAttrs/norecurse.ll
+++ b/llvm/test/Transforms/FunctionAttrs/norecurse.ll
@@ -258,9 +258,10 @@ define void @unknown_call(ptr %fn) {
 }
 
 define void @unknown_norecurse_call(ptr %fn) {
+; FNATTRS: Function Attrs: norecurse
 ; FNATTRS-LABEL: define {{[^@]+}}@unknown_norecurse_call
-; FNATTRS-SAME: (ptr readonly captures(none) [[FN:%.*]]) {
-; FNATTRS-NEXT:    call void [[FN]]() #[[ATTR7:[0-9]+]]
+; FNATTRS-SAME: (ptr readonly captures(none) [[FN:%.*]]) #[[ATTR7:[0-9]+]] {
+; FNATTRS-NEXT:    call void [[FN]]() #[[ATTR7]]
 ; FNATTRS-NEXT:    ret void
 ;
 ; ATTRIBUTOR-LABEL: define {{[^@]+}}@unknown_norecurse_call
diff --git a/llvm/test/Transforms/FunctionAttrs/nounwind.ll b/llvm/test/Transforms/FunctionAttrs/nounwind.ll
index a64d9a6504256..076a7df2781ce 100644
--- a/llvm/test/Transforms/FunctionAttrs/nounwind.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nounwind.ll
@@ -418,9 +418,10 @@ define void @unknown_call(ptr %fn) {
 }
 
 define void @unknown_nounwind_call(ptr %fn) {
+; FNATTRS: Function Attrs: nounwind
 ; FNATTRS-LABEL: define {{[^@]+}}@unknown_nounwind_call
-; FNATTRS-SAME: (ptr readonly captures(none) [[FN:%.*]]) {
-; FNATTRS-NEXT:    call void [[FN]]() #[[ATTR2:[0-9]+]]
+; FNATTRS-SAME: (ptr readonly captures(none) [[FN:%.*]]) #[[ATTR2:[0-9]+]] {
+; FNATTRS-NEXT:    call void [[FN]]() #[[ATTR2]]
 ; FNATTRS-NEXT:    ret void
 ;
 ; ATTRIBUTOR: Function Attrs: nounwind

``````````

</details>


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


More information about the llvm-commits mailing list