Skip to content

Commit d4f1637

Browse files
committed
Infer norecurse for functions with external function call/library function callls if none of the user functions have had there address taken
1 parent b51fa88 commit d4f1637

File tree

4 files changed

+60
-14
lines changed

4 files changed

+60
-14
lines changed

llvm/include/llvm/Transforms/IPO/FunctionAttrs.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ LLVM_ABI bool thinLTOPropagateFunctionAttrs(
4949
/// attribute. It also discovers function arguments that are not captured by
5050
/// the function and marks them with the nocapture attribute.
5151
struct PostOrderFunctionAttrsPass : PassInfoMixin<PostOrderFunctionAttrsPass> {
52-
PostOrderFunctionAttrsPass(bool SkipNonRecursive = false)
53-
: SkipNonRecursive(SkipNonRecursive) {}
52+
PostOrderFunctionAttrsPass(bool SkipNonRecursive = false,
53+
bool IsLTOPostLink = false)
54+
: SkipNonRecursive(SkipNonRecursive), IsLTOPostLink(IsLTOPostLink) {}
5455
LLVM_ABI PreservedAnalyses run(LazyCallGraph::SCC &C,
5556
CGSCCAnalysisManager &AM, LazyCallGraph &CG,
5657
CGSCCUpdateResult &UR);
@@ -61,6 +62,7 @@ struct PostOrderFunctionAttrsPass : PassInfoMixin<PostOrderFunctionAttrsPass> {
6162

6263
private:
6364
bool SkipNonRecursive;
65+
bool IsLTOPostLink;
6466
};
6567

6668
/// A pass to do RPO deduction and propagation of function attributes.

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,8 @@ PassBuilder::buildInlinerPipeline(OptimizationLevel Level,
970970
// simplification pipeline, so this only needs to run when it could affect the
971971
// function simplification pipeline, which is only the case with recursive
972972
// functions.
973-
MainCGPipeline.addPass(PostOrderFunctionAttrsPass(/*SkipNonRecursive*/ true));
973+
MainCGPipeline.addPass(PostOrderFunctionAttrsPass(
974+
/*SkipNonRecursive*/ true, Phase == ThinOrFullLTOPhase::FullLTOPostLink));
974975

975976
// When at O3 add argument promotion to the pass pipeline.
976977
// FIXME: It isn't at all clear why this should be limited to O3.
@@ -992,7 +993,8 @@ PassBuilder::buildInlinerPipeline(OptimizationLevel Level,
992993

993994
// Finally, deduce any function attributes based on the fully simplified
994995
// function.
995-
MainCGPipeline.addPass(PostOrderFunctionAttrsPass());
996+
MainCGPipeline.addPass(PostOrderFunctionAttrsPass(
997+
false, Phase == ThinOrFullLTOPhase::FullLTOPostLink));
996998

997999
// Mark that the function is fully simplified and that it shouldn't be
9981000
// simplified again if we somehow revisit it due to CGSCC mutations unless
@@ -1914,7 +1916,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
19141916
// Promoting by-reference arguments to by-value exposes more constants to
19151917
// IPSCCP.
19161918
CGSCCPassManager CGPM;
1917-
CGPM.addPass(PostOrderFunctionAttrsPass());
1919+
CGPM.addPass(PostOrderFunctionAttrsPass(false, true));
19181920
CGPM.addPass(ArgumentPromotionPass());
19191921
CGPM.addPass(
19201922
createCGSCCToFunctionPassAdaptor(SROAPass(SROAOptions::ModifyCFG)));
@@ -2076,8 +2078,8 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
20762078
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM),
20772079
PTO.EagerlyInvalidateAnalyses));
20782080

2079-
MPM.addPass(
2080-
createModuleToPostOrderCGSCCPassAdaptor(PostOrderFunctionAttrsPass()));
2081+
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
2082+
PostOrderFunctionAttrsPass(false, true)));
20812083

20822084
// Require the GlobalsAA analysis for the module so we can query it within
20832085
// MainFPM.

llvm/lib/Transforms/IPO/FunctionAttrs.cpp

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,7 +2068,9 @@ static void inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes,
20682068
}
20692069

20702070
static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
2071-
SmallPtrSet<Function *, 8> &Changed) {
2071+
SmallPtrSet<Function *, 8> &Changed,
2072+
bool AnyFunctionsAddressIsTaken,
2073+
bool IsLTOPostLink) {
20722074
// Try and identify functions that do not recurse.
20732075

20742076
// If the SCC contains multiple nodes we know for sure there is recursion.
@@ -2081,6 +2083,10 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
20812083

20822084
if (F->hasAddressTaken())
20832085
return;
2086+
2087+
Module *M = F->getParent();
2088+
llvm::TargetLibraryInfoImpl TLII(llvm::Triple(M->getTargetTriple()));
2089+
llvm::TargetLibraryInfo TLI(TLII);
20842090
// If all of the calls in F are identifiable and can be proven to not
20852091
// callback F, F is norecurse. This check also detects self-recursion
20862092
// as F is not currently marked norecurse, so any call from F to F
@@ -2096,11 +2102,21 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
20962102
if (Callee->doesNotRecurse())
20972103
continue;
20982104

2099-
// External call with NoCallback attribute.
2105+
LibFunc LF;
21002106
if (Callee->isDeclaration()) {
2107+
// External call with NoCallback attribute.
21012108
if (Callee->hasFnAttribute(Attribute::NoCallback))
21022109
continue;
2103-
return;
2110+
// We rely on this only in post link stage when all functions in the
2111+
// program are known.
2112+
if (IsLTOPostLink && !AnyFunctionsAddressIsTaken &&
2113+
TLI.getLibFunc(Callee->getName(), LF))
2114+
continue;
2115+
// Do not consider external functions safe unless we are in LTO
2116+
// post-link stage and have information about all functions in the
2117+
// program.
2118+
if (!IsLTOPostLink)
2119+
return;
21042120
}
21052121
}
21062122
}
@@ -2252,7 +2268,8 @@ static SCCNodesResult createSCCNodeSet(ArrayRef<Function *> Functions) {
22522268
template <typename AARGetterT>
22532269
static SmallPtrSet<Function *, 8>
22542270
deriveAttrsInPostOrder(ArrayRef<Function *> Functions, AARGetterT &&AARGetter,
2255-
bool ArgAttrsOnly) {
2271+
bool ArgAttrsOnly, bool AnyFunctionAddressTaken = false,
2272+
bool IsLTOPostLink = false) {
22562273
SCCNodesResult Nodes = createSCCNodeSet(Functions);
22572274

22582275
// Bail if the SCC only contains optnone functions.
@@ -2282,7 +2299,8 @@ deriveAttrsInPostOrder(ArrayRef<Function *> Functions, AARGetterT &&AARGetter,
22822299
addNoAliasAttrs(Nodes.SCCNodes, Changed);
22832300
addNonNullAttrs(Nodes.SCCNodes, Changed);
22842301
inferAttrsFromFunctionBodies(Nodes.SCCNodes, Changed);
2285-
addNoRecurseAttrs(Nodes.SCCNodes, Changed);
2302+
addNoRecurseAttrs(Nodes.SCCNodes, Changed, AnyFunctionAddressTaken,
2303+
IsLTOPostLink);
22862304

22872305
// Finally, infer the maximal set of attributes from the ones we've inferred
22882306
// above. This is handling the cases where one attribute on a signature
@@ -2324,8 +2342,29 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,
23242342
Functions.push_back(&N.getFunction());
23252343
}
23262344

2345+
bool AnyFunctionsAddressIsTaken = false;
2346+
// Check if any function in the whole program has its address taken.
2347+
// We use this information when inferring norecurse attribute: If there is
2348+
// no function whose address is taken, we conclude that any external function
2349+
// cannot callback into any user function.
2350+
if (IsLTOPostLink) {
2351+
// Get the parent Module of the Function
2352+
Module &M = *C.begin()->getFunction().getParent();
2353+
for (Function &F : M) {
2354+
// We only care about functions defined in user program whose addresses
2355+
// escape, making them potential callback targets.
2356+
if (F.isDeclaration())
2357+
continue;
2358+
2359+
if (F.hasAddressTaken()) {
2360+
AnyFunctionsAddressIsTaken = true;
2361+
break; // break if we found one
2362+
}
2363+
}
2364+
}
23272365
auto ChangedFunctions =
2328-
deriveAttrsInPostOrder(Functions, AARGetter, ArgAttrsOnly);
2366+
deriveAttrsInPostOrder(Functions, AARGetter, ArgAttrsOnly,
2367+
AnyFunctionsAddressIsTaken, IsLTOPostLink);
23292368
if (ChangedFunctions.empty())
23302369
return PreservedAnalyses::all();
23312370

llvm/test/Other/new-pm-lto-defaults.ll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@
166166
; CHECK-O-NEXT: Running pass: PrintModulePass
167167

168168
; Make sure we get the IR back out without changes when we print the module.
169-
; CHECK-O-LABEL: define void @foo(i32 %n) local_unnamed_addr {
169+
; CHECK-O23SZ: ; Function Attrs: norecurse
170+
; CHECK-O1-LABEL: define void @foo(i32 %n) local_unnamed_addr {
171+
; CHECK-O23SZ-LABEL: define void @foo(i32 %n) local_unnamed_addr #0 {
170172
; CHECK-O-NEXT: entry:
171173
; CHECK-O-NEXT: br label %loop
172174
; CHECK-O: loop:
@@ -178,6 +180,7 @@
178180
; CHECK-O: exit:
179181
; CHECK-O-NEXT: ret void
180182
; CHECK-O-NEXT: }
183+
; CHECK-O23SZ: attributes #0 = { norecurse }
181184
;
182185

183186
declare void @bar() local_unnamed_addr

0 commit comments

Comments
 (0)