[llvm] [FuncAttrs] Relax norecurse attribute inference (PR #139943)
David Sherwood via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 7 01:28:59 PDT 2025
================
@@ -2322,8 +2343,39 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,
Functions.push_back(&N.getFunction());
}
- auto ChangedFunctions =
- deriveAttrsInPostOrder(Functions, AARGetter, ArgAttrsOnly);
+ bool NoFunctionsAddressIsTaken = false;
+ // Check if any function in the whole program has its address taken or has
+ // potentially external linkage.
+ // We use this information when inferring norecurse attribute: If there is
+ // no function whose address is taken and all functions have internal
+ // linkage, there is no path for a callback to any user function.
+ if (IsLTOPostLink || ForceLTOFuncAttrs) {
+ bool AnyFunctionsAddressIsTaken = false;
+ // Get the parent Module of the Function
+ Module &M = *C.begin()->getFunction().getParent();
+ for (Function &F : M) {
+ // We only care about functions defined in user program whose addresses
+ // escape, making them potential callback targets.
+ if (F.isDeclaration())
+ continue;
+
+ // If the function is already marked as norecurse, this should not block
+ // norecurse inference even though it may have external linkage.
+ // For ex: main() in C++.
+ if (F.doesNotRecurse())
+ continue;
----------------
david-arm wrote:
Would the call graph actually help in all cases though? For the example you gave above, i.e.
```
/*external linkage*/void foo() {
a(0);
}
static void a(int v) {
if (v)
bar(); /*external function*/
return;
}
extern void bar();
```
the call graph will still say that foo is potentially recursive I think. Unless we have a call graph that takes control flow into account based on function arguments? I agree with you, that if we cannot use `norecurse` to infer `norecurse` then it sounds like the whole RPO pass is unsound.
Is it possible that the definition of `norecurse` in the LangRef refers to the call graph, which would simply show that foo() calls a(), which calls bar(), which could call foo()? In this definition adding `norecurse` to `foo` would be incorrect.
https://github.com/llvm/llvm-project/pull/139943
More information about the llvm-commits
mailing list