llvm.org GIT mirror llvm / e96fb9a
[attrs] Split the late-revisit pattern for deducing norecurse in a top-down manner into a true top-down or RPO pass over the call graph. There are specific patterns of function attributes, notably the norecurse attribute, which are most effectively propagated top-down because all they us caller information. Walk in RPO over the call graph SCCs takes the form of a module pass run immediately after the CGSCC pass managers postorder walk of the SCCs, trying again to deduce norerucrse for each singular SCC in the call graph. This removes a very legacy pass manager specific trick of using a lazy revisit list traversed during finalization of the CGSCC pass. There is no analogous finalization step in the new pass manager, and a lazy revisit list is just trying to produce an RPO iteration of the call graph. We can do that more directly if more expensively. It seems unlikely that this will be the expensive part of any compilation though as we never examine the function bodies here. Even in an LTO run over a very large module, this should be a reasonable fast set of operations over a reasonably small working set -- the function call graph itself. In the future, if this really is a compile time performance issue, we can look at building support for both post order and RPO traversals directly into a pass manager that builds and maintains the PO list of SCCs. Differential Revision: http://reviews.llvm.org/D15785 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257163 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 4 years ago
8 changed file(s) with 138 addition(s) and 74 deletion(s). Raw diff Collapse all Expand all
131131 void initializeEliminateAvailableExternallyPass(PassRegistry&);
132132 void initializeExpandISelPseudosPass(PassRegistry&);
133133 void initializeForceFunctionAttrsLegacyPassPass(PassRegistry&);
134 void initializeFunctionAttrsPass(PassRegistry&);
135134 void initializeGCMachineCodeAnalysisPass(PassRegistry&);
136135 void initializeGCModuleInfoPass(PassRegistry&);
137136 void initializeGVNPass(PassRegistry&);
226225 void initializePostDomPrinterPass(PassRegistry&);
227226 void initializePostDomViewerPass(PassRegistry&);
228227 void initializePostDominatorTreePass(PassRegistry&);
228 void initializePostOrderFunctionAttrsPass(PassRegistry&);
229229 void initializePostRASchedulerPass(PassRegistry&);
230230 void initializePostMachineSchedulerPass(PassRegistry&);
231231 void initializePrintFunctionPassWrapperPass(PassRegistry&);
241241 void initializeRegionOnlyViewerPass(PassRegistry&);
242242 void initializeRegionPrinterPass(PassRegistry&);
243243 void initializeRegionViewerPass(PassRegistry&);
244 void initializeReversePostOrderFunctionAttrsPass(PassRegistry&);
244245 void initializeRewriteStatepointsForGCPass(PassRegistry&);
245246 void initializeSafeStackPass(PassRegistry&);
246247 void initializeSCCPPass(PassRegistry&);
156156 (void) llvm::createPostDomTree();
157157 (void) llvm::createInstructionNamerPass();
158158 (void) llvm::createMetaRenamerPass();
159 (void) llvm::createFunctionAttrsPass();
159 (void) llvm::createPostOrderFunctionAttrsPass();
160 (void) llvm::createReversePostOrderFunctionAttrsPass();
160161 (void) llvm::createMergeFunctionsPass();
161162 (void) llvm::createPrintModulePass(*(llvm::raw_ostream*)nullptr);
162163 (void) llvm::createPrintFunctionPass(*(llvm::raw_ostream*)nullptr);
182182 ModulePass *createStripDeadPrototypesPass();
183183
184184 //===----------------------------------------------------------------------===//
185 /// createFunctionAttrsPass - This pass discovers functions that do not access
186 /// memory, or only read memory, and gives them the readnone/readonly attribute.
187 /// It also discovers function arguments that are not captured by the function
188 /// and marks them with the nocapture attribute.
189 ///
190 Pass *createFunctionAttrsPass();
185 /// createPostOrderFunctionAttrsPass - This pass walks SCCs of the call graph
186 /// in post-order to deduce and propagate function attributes. It can discover
187 /// functions that do not access memory, or only read memory, and give them the
188 /// readnone/readonly attribute. It also discovers function arguments that are
189 /// not captured by the function and marks them with the nocapture attribute.
190 ///
191 Pass *createPostOrderFunctionAttrsPass();
192
193 //===----------------------------------------------------------------------===//
194 /// createReversePostOrderFunctionAttrsPass - This pass walks SCCs of the call
195 /// graph in RPO to deduce and propagate function attributes. Currently it
196 /// only handles synthesizing norecurse attributes.
197 ///
198 Pass *createReversePostOrderFunctionAttrsPass();
191199
192200 //===----------------------------------------------------------------------===//
193201 /// createMergeFunctionsPass - This pass discovers identical functions and
9191 initializeSROALegacyPassPass(R);
9292 initializeSROA_DTPass(R);
9393 initializeSROA_SSAUpPass(R);
94 initializeFunctionAttrsPass(R);
94 initializePostOrderFunctionAttrsPass(R);
95 initializeReversePostOrderFunctionAttrsPass(R);
9596 initializeGlobalsAAWrapperPassPass(R);
9697 initializeLICMPass(R);
9798 initializeMergedLoadStoreMotionPass(R);
55 // License. See LICENSE.TXT for details.
66 //
77 //===----------------------------------------------------------------------===//
8 //
9 // This file implements a simple interprocedural pass which walks the
10 // call-graph, looking for functions which do not access or only read
11 // non-local memory, and marking them readnone/readonly. It does the
12 // same with function arguments independently, marking them readonly/
13 // readnone/nocapture. Finally, well-known library call declarations
14 // are marked with all attributes that are consistent with the
15 // function's standard definition. This pass is implemented as a
16 // bottom-up traversal of the call-graph.
17 //
8 ///
9 /// \file
10 /// This file implements interprocedural passes which walk the
11 /// call-graph deducing and/or propagating function attributes.
12 ///
1813 //===----------------------------------------------------------------------===//
1914
2015 #include "llvm/Transforms/IPO.h"
5651 }
5752
5853 namespace {
59 struct FunctionAttrs : public CallGraphSCCPass {
54 struct PostOrderFunctionAttrs : public CallGraphSCCPass {
6055 static char ID; // Pass identification, replacement for typeid
61 FunctionAttrs() : CallGraphSCCPass(ID) {
62 initializeFunctionAttrsPass(*PassRegistry::getPassRegistry());
56 PostOrderFunctionAttrs() : CallGraphSCCPass(ID) {
57 initializePostOrderFunctionAttrsPass(*PassRegistry::getPassRegistry());
6358 }
6459
6560 bool runOnSCC(CallGraphSCC &SCC) override;
66 bool doInitialization(CallGraph &CG) override {
67 Revisit.clear();
68 return false;
69 }
70 bool doFinalization(CallGraph &CG) override;
71
61
7262 void getAnalysisUsage(AnalysisUsage &AU) const override {
7363 AU.setPreservesCFG();
7464 AU.addRequired();
7868
7969 private:
8070 TargetLibraryInfo *TLI;
81 SmallVector Revisit;
8271 };
8372 }
8473
85 char FunctionAttrs::ID = 0;
86 INITIALIZE_PASS_BEGIN(FunctionAttrs, "functionattrs",
74 char PostOrderFunctionAttrs::ID = 0;
75 INITIALIZE_PASS_BEGIN(PostOrderFunctionAttrs, "functionattrs",
8776 "Deduce function attributes", false, false)
8877 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
8978 INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
9079 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
91 INITIALIZE_PASS_END(FunctionAttrs, "functionattrs",
80 INITIALIZE_PASS_END(PostOrderFunctionAttrs, "functionattrs",
9281 "Deduce function attributes", false, false)
9382
94 Pass *llvm::createFunctionAttrsPass() { return new FunctionAttrs(); }
83 Pass *llvm::createPostOrderFunctionAttrsPass() { return new PostOrderFunctionAttrs(); }
9584
9685 namespace {
9786 /// The three kinds of memory access relevant to 'readonly' and
948937 return true;
949938 }
950939
951 static bool addNoRecurseAttrs(const CallGraphSCC &SCC,
952 SmallVectorImpl &Revisit) {
940 static bool addNoRecurseAttrs(const CallGraphSCC &SCC) {
953941 // Try and identify functions that do not recurse.
954942
955943 // If the SCC contains multiple nodes we know for sure there is recursion.
972960 // Function calls a potentially recursive function.
973961 return setDoesNotRecurse(*F);
974962
975 // We know that F is not obviously recursive, but we haven't been able to
976 // prove that it doesn't actually recurse. Add it to the Revisit list to try
977 // again top-down later.
978 Revisit.push_back(F);
963 // Nothing else we can deduce usefully during the postorder traversal.
979964 return false;
980965 }
981966
982 static bool addNoRecurseAttrsTopDownOnly(Function *F) {
983 // If F is internal and all uses are in norecurse functions, then F is also
984 // norecurse.
985 if (F->doesNotRecurse())
986 return false;
987 if (F->hasInternalLinkage()) {
988 for (auto *U : F->users())
989 if (auto *I = dyn_cast(U)) {
990 if (!I->getParent()->getParent()->doesNotRecurse())
991 return false;
992 } else {
993 return false;
994 }
995 return setDoesNotRecurse(*F);
996 }
997 return false;
998 }
999
1000 bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) {
967 bool PostOrderFunctionAttrs::runOnSCC(CallGraphSCC &SCC) {
1001968 TLI = &getAnalysis().getTLI();
1002969 bool Changed = false;
1003970
10391006 Changed |= addNoAliasAttrs(SCCNodes);
10401007 Changed |= addNonNullAttrs(SCCNodes, *TLI);
10411008 }
1042
1043 Changed |= addNoRecurseAttrs(SCC, Revisit);
1009
1010 Changed |= addNoRecurseAttrs(SCC);
10441011 return Changed;
10451012 }
10461013
1047 bool FunctionAttrs::doFinalization(CallGraph &CG) {
1014 namespace {
1015 /// A pass to do RPO deduction and propagation of function attributes.
1016 ///
1017 /// This pass provides a general RPO or "top down" propagation of
1018 /// function attributes. For a few (rare) cases, we can deduce significantly
1019 /// more about function attributes by working in RPO, so this pass
1020 /// provides the compliment to the post-order pass above where the majority of
1021 /// deduction is performed.
1022 // FIXME: Currently there is no RPO CGSCC pass structure to slide into and so
1023 // this is a boring module pass, but eventually it should be an RPO CGSCC pass
1024 // when such infrastructure is available.
1025 struct ReversePostOrderFunctionAttrs : public ModulePass {
1026 static char ID; // Pass identification, replacement for typeid
1027 ReversePostOrderFunctionAttrs() : ModulePass(ID) {
1028 initializeReversePostOrderFunctionAttrsPass(*PassRegistry::getPassRegistry());
1029 }
1030
1031 bool runOnModule(Module &M) override;
1032
1033 void getAnalysisUsage(AnalysisUsage &AU) const override {
1034 AU.setPreservesCFG();
1035 AU.addRequired();
1036 }
1037 };
1038 }
1039
1040 char ReversePostOrderFunctionAttrs::ID = 0;
1041 INITIALIZE_PASS_BEGIN(ReversePostOrderFunctionAttrs, "rpo-functionattrs",
1042 "Deduce function attributes in RPO", false, false)
1043 INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
1044 INITIALIZE_PASS_END(ReversePostOrderFunctionAttrs, "rpo-functionattrs",
1045 "Deduce function attributes in RPO", false, false)
1046
1047 Pass *llvm::createReversePostOrderFunctionAttrsPass() {
1048 return new ReversePostOrderFunctionAttrs();
1049 }
1050
1051 static bool addNoRecurseAttrsTopDown(Function &F) {
1052 // We check the preconditions for the function prior to calling this to avoid
1053 // the cost of building up a reversible post-order list. We assert them here
1054 // to make sure none of the invariants this relies on were violated.
1055 assert(!F.isDeclaration() && "Cannot deduce norecurse without a definition!");
1056 assert(!F.doesNotRecurse() &&
1057 "This function has already been deduced as norecurs!");
1058 assert(F.hasInternalLinkage() &&
1059 "Can only do top-down deduction for internal linkage functions!");
1060
1061 // If F is internal and all of its uses are calls from a non-recursive
1062 // functions, then none of its calls could in fact recurse without going
1063 // through a function marked norecurse, and so we can mark this function too
1064 // as norecurse. Note that the uses must actually be calls -- otherwise
1065 // a pointer to this function could be returned from a norecurse function but
1066 // this function could be recursively (indirectly) called. Note that this
1067 // also detects if F is directly recursive as F is not yet marked as
1068 // a norecurse function.
1069 for (auto *U : F.users()) {
1070 auto *I = dyn_cast(U);
1071 if (!I)
1072 return false;
1073 CallSite CS(I);
1074 if (!CS || !CS.getParent()->getParent()->doesNotRecurse())
1075 return false;
1076 }
1077 return setDoesNotRecurse(F);
1078 }
1079
1080 bool ReversePostOrderFunctionAttrs::runOnModule(Module &M) {
1081 // We only have a post-order SCC traversal (because SCCs are inherently
1082 // discovered in post-order), so we accumulate them in a vector and then walk
1083 // it in reverse. This is simpler than using the RPO iterator infrastructure
1084 // because we need to combine SCC detection and the PO walk of the call
1085 // graph. We can also cheat egregiously because we're primarily interested in
1086 // synthesizing norecurse and so we can only save the singular SCCs as SCCs
1087 // with multiple functions in them will clearly be recursive.
1088 auto &CG = getAnalysis().getCallGraph();
1089 SmallVector Worklist;
1090 for (scc_iterator I = scc_begin(&CG); !I.isAtEnd(); ++I) {
1091 if (I->size() != 1)
1092 continue;
1093
1094 Function *F = I->front()->getFunction();
1095 if (F && !F->isDeclaration() && !F->doesNotRecurse() &&
1096 F->hasInternalLinkage())
1097 Worklist.push_back(F);
1098 }
1099
10481100 bool Changed = false;
1049 // When iterating over SCCs we visit functions in a bottom-up fashion. Some of
1050 // the rules we have for identifying norecurse functions work best with a
1051 // top-down walk, so look again at all the functions we previously marked as
1052 // worth revisiting, in top-down order.
1053 for (auto &F : reverse(Revisit))
1054 if (F)
1055 Changed |= addNoRecurseAttrsTopDownOnly(cast((Value*)F));
1101 for (auto *F : reverse(Worklist))
1102 Changed |= addNoRecurseAttrsTopDown(*F);
1103
10561104 return Changed;
10571105 }
2727 initializeDAEPass(Registry);
2828 initializeDAHPass(Registry);
2929 initializeForceFunctionAttrsLegacyPassPass(Registry);
30 initializeFunctionAttrsPass(Registry);
3130 initializeGlobalDCEPass(Registry);
3231 initializeGlobalOptPass(Registry);
3332 initializeIPCPPass(Registry);
4140 initializeLowerBitSetsPass(Registry);
4241 initializeMergeFunctionsPass(Registry);
4342 initializePartialInlinerPass(Registry);
43 initializePostOrderFunctionAttrsPass(Registry);
44 initializeReversePostOrderFunctionAttrsPass(Registry);
4445 initializePruneEHPass(Registry);
4546 initializeStripDeadPrototypesLegacyPassPass(Registry);
4647 initializeStripSymbolsPass(Registry);
7071 }
7172
7273 void LLVMAddFunctionAttrsPass(LLVMPassManagerRef PM) {
73 unwrap(PM)->add(createFunctionAttrsPass());
74 unwrap(PM)->add(createPostOrderFunctionAttrsPass());
7475 }
7576
7677 void LLVMAddFunctionInliningPass(LLVMPassManagerRef PM) {
250250 Inliner = nullptr;
251251 }
252252 if (!DisableUnitAtATime)
253 MPM.add(createFunctionAttrsPass()); // Set readonly/readnone attrs
253 MPM.add(createPostOrderFunctionAttrsPass());
254254 if (OptLevel > 2)
255255 MPM.add(createArgumentPromotionPass()); // Scalarize uninlined fn args
256256
344344 // pass manager that we are specifically trying to avoid. To prevent this
345345 // we must insert a no-op module pass to reset the pass manager.
346346 MPM.add(createBarrierNoopPass());
347
348 if (!DisableUnitAtATime)
349 MPM.add(createReversePostOrderFunctionAttrsPass());
347350
348351 if (!DisableUnitAtATime && OptLevel > 1 && !PrepareForLTO) {
349352 // Remove avail extern fns and globals definitions if we aren't
501504 PM.add(createIPSCCPPass());
502505
503506 // Now that we internalized some globals, see if we can hack on them!
504 PM.add(createFunctionAttrsPass()); // Add norecurse if possible.
507 PM.add(createPostOrderFunctionAttrsPass());
508 PM.add(createReversePostOrderFunctionAttrsPass());
505509 PM.add(createGlobalOptimizerPass());
506510 // Promote any localized global vars.
507511 PM.add(createPromoteMemoryToRegisterPass());
550554 PM.add(createScalarReplAggregatesPass());
551555
552556 // Run a few AA driven optimizations here and now, to cleanup the code.
553 PM.add(createFunctionAttrsPass()); // Add nocapture.
557 PM.add(createPostOrderFunctionAttrsPass()); // Add nocapture.
554558 PM.add(createGlobalsAAWrapperPass()); // IP alias analysis.
555559
556560 PM.add(createLICMPass()); // Hoist loop invariants.
None ; RUN: opt < %s -basicaa -functionattrs -S | FileCheck %s
0 ; RUN: opt < %s -basicaa -functionattrs -rpo-functionattrs -S | FileCheck %s
11
22 ; CHECK: define i32 @leaf() #0
33 define i32 @leaf() {