@@ -2067,6 +2067,36 @@ static void inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes,
2067
2067
AI.run (SCCNodes, Changed);
2068
2068
}
2069
2069
2070
+ // Determines if the function 'F' can be marked 'norecurse'.
2071
+ // It returns true if any call within 'F' could lead to a recursive
2072
+ // call back to 'F', and false otherwise.
2073
+ // The 'AnyFunctionsAddressIsTaken' parameter is a module-wide flag
2074
+ // that is true if any function's address is taken, or if any function
2075
+ // has external linkage. This is used to determine the safety of
2076
+ // external/library calls.
2077
+ static bool hasRecursiveCallee (Function &F,
2078
+ bool AnyFunctionsAddressIsTaken = true ) {
2079
+ for (const auto &BB : F) {
2080
+ for (const auto &I : BB.instructionsWithoutDebug ()) {
2081
+ if (const auto *CB = dyn_cast<CallBase>(&I)) {
2082
+ const Function *Callee = CB->getCalledFunction ();
2083
+ if (!Callee || Callee == &F)
2084
+ return true ;
2085
+
2086
+ if (Callee->doesNotRecurse ())
2087
+ continue ;
2088
+
2089
+ if (!AnyFunctionsAddressIsTaken ||
2090
+ (Callee->isDeclaration () &&
2091
+ Callee->hasFnAttribute (Attribute::NoCallback)))
2092
+ continue ;
2093
+ return true ;
2094
+ }
2095
+ }
2096
+ }
2097
+ return false ;
2098
+ }
2099
+
2070
2100
static void addNoRecurseAttrs (const SCCNodeSet &SCCNodes,
2071
2101
SmallPtrSet<Function *, 8 > &Changed) {
2072
2102
// Try and identify functions that do not recurse.
@@ -2078,28 +2108,14 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
2078
2108
Function *F = *SCCNodes.begin ();
2079
2109
if (!F || !F->hasExactDefinition () || F->doesNotRecurse ())
2080
2110
return ;
2081
-
2082
- // If all of the calls in F are identifiable and are to norecurse functions, F
2083
- // is norecurse. This check also detects self-recursion as F is not currently
2084
- // marked norecurse, so any called from F to F will not be marked norecurse.
2085
- for (auto &BB : *F)
2086
- for (auto &I : BB.instructionsWithoutDebug ())
2087
- if (auto *CB = dyn_cast<CallBase>(&I)) {
2088
- Function *Callee = CB->getCalledFunction ();
2089
- if (!Callee || Callee == F ||
2090
- (!Callee->doesNotRecurse () &&
2091
- !(Callee->isDeclaration () &&
2092
- Callee->hasFnAttribute (Attribute::NoCallback))))
2093
- // Function calls a potentially recursive function.
2094
- return ;
2095
- }
2096
-
2097
- // Every call was to a non-recursive function other than this function, and
2098
- // we have no indirect recursion as the SCC size is one. This function cannot
2099
- // recurse.
2100
- F->setDoesNotRecurse ();
2101
- ++NumNoRecurse;
2102
- Changed.insert (F);
2111
+ if (!hasRecursiveCallee (*F)) {
2112
+ // Every call was to a non-recursive function other than this function, and
2113
+ // we have no indirect recursion as the SCC size is one. This function
2114
+ // cannot recurse.
2115
+ F->setDoesNotRecurse ();
2116
+ ++NumNoRecurse;
2117
+ Changed.insert (F);
2118
+ }
2103
2119
}
2104
2120
2105
2121
// Set the noreturn function attribute if possible.
@@ -2429,3 +2445,66 @@ ReversePostOrderFunctionAttrsPass::run(Module &M, ModuleAnalysisManager &AM) {
2429
2445
PA.preserve <LazyCallGraphAnalysis>();
2430
2446
return PA;
2431
2447
}
2448
+
2449
+ PreservedAnalyses NoRecurseLTOInferencePass::run (Module &M,
2450
+ ModuleAnalysisManager &MAM) {
2451
+
2452
+ // Check if any function in the whole program has its address taken or has
2453
+ // potentially external linkage.
2454
+ // We use this information when inferring norecurse attribute: If there is
2455
+ // no function whose address is taken and all functions have internal
2456
+ // linkage, there is no path for a callback to any user function.
2457
+ bool AnyFunctionsAddressIsTaken = false ;
2458
+ for (Function &F : M) {
2459
+ if (F.isDeclaration () || F.doesNotRecurse ()) {
2460
+ continue ;
2461
+ }
2462
+ if (!F.hasLocalLinkage () || F.hasAddressTaken ()) {
2463
+ AnyFunctionsAddressIsTaken = true ;
2464
+ break ;
2465
+ }
2466
+ }
2467
+
2468
+ // Run norecurse inference on all RefSCCs in the LazyCallGraph for this
2469
+ // module.
2470
+ bool Changed = false ;
2471
+ LazyCallGraph &CG = MAM.getResult <LazyCallGraphAnalysis>(M);
2472
+ CG.buildRefSCCs ();
2473
+
2474
+ for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs ()) {
2475
+ // Skip any RefSCC that is part of a call cycle. A RefSCC containing more
2476
+ // than one SCC indicates a recursive relationship, which could involve
2477
+ // direct or indirect calls.
2478
+ if (RC.size () > 1 ) {
2479
+ continue ;
2480
+ }
2481
+
2482
+ // A single-SCC RefSCC could still be a self-loop.
2483
+ LazyCallGraph::SCC &S = *RC.begin ();
2484
+ if (S.size () > 1 ) {
2485
+ continue ;
2486
+ }
2487
+
2488
+ // Get the single function from this SCC.
2489
+ Function &F = S.begin ()->getFunction ();
2490
+ if (!F.hasExactDefinition () || F.doesNotRecurse ()) {
2491
+ continue ;
2492
+ }
2493
+
2494
+ // If the analysis confirms that this function has no recursive calls
2495
+ // (either direct, indirect, or through external linkages),
2496
+ // we can safely apply the norecurse attribute.
2497
+ if (!hasRecursiveCallee (F, AnyFunctionsAddressIsTaken)) {
2498
+ F.setDoesNotRecurse ();
2499
+ ++NumNoRecurse;
2500
+ Changed = true ;
2501
+ }
2502
+ }
2503
+
2504
+ PreservedAnalyses PA;
2505
+ if (Changed)
2506
+ PA.preserve <LazyCallGraphAnalysis>();
2507
+ else
2508
+ PA = PreservedAnalyses::all ();
2509
+ return PA;
2510
+ }
0 commit comments