llvm.org GIT mirror llvm / 6cd07b4
Revert "[FunctionAttrs] Identify norecurse functions" This reverts commit r252862. This introduced test failures and I'm reverting while I investigate how this happened. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252863 91177308-0d34-0410-b5e6-96231b3b80d8 James Molloy 4 years ago
7 changed file(s) with 12 addition(s) and 153 deletion(s). Raw diff Collapse all Expand all
4949 STATISTIC(NumNoAlias, "Number of function returns marked noalias");
5050 STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull");
5151 STATISTIC(NumAnnotated, "Number of attributes added to library functions");
52 STATISTIC(NumNoRecurse, "Number of functions marked as norecurse");
5352
5453 namespace {
5554 typedef SmallSetVector SCCNodeSet;
6362 }
6463
6564 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
65
7266 void getAnalysisUsage(AnalysisUsage &AU) const override {
7367 AU.setPreservesCFG();
7468 AU.addRequired();
7872
7973 private:
8074 TargetLibraryInfo *TLI;
81 SmallVector Revisit;
8275 };
8376 }
8477
982975 }
983976 }
984977
985 static bool setDoesNotRecurse(Function &F) {
986 if (F.doesNotRecurse())
987 return false;
988 F.setDoesNotRecurse();
989 ++NumNoRecurse;
990 return true;
991 }
992
993978 /// Analyze the name and prototype of the given function and set any applicable
994979 /// attributes.
995980 ///
17931778 return true;
17941779 }
17951780
1796 static bool addNoRecurseAttrs(const CallGraphSCC &SCC,
1797 SmallVectorImpl &Revisit) {
1798 // Try and identify functions that do not recurse.
1799
1800 // If the SCC contains multiple nodes we know for sure there is recursion.
1801 if (!SCC.isSingular())
1802 return false;
1803
1804 const CallGraphNode *CGN = *SCC.begin();
1805 Function *F = CGN->getFunction();
1806 if (!F || F->isDeclaration() || F->doesNotRecurse())
1807 return false;
1808
1809 // If all of the calls in F are identifiable and are to norecurse functions, F
1810 // is norecurse. This check also detects self-recursion as F is not currently
1811 // marked norecurse, so any called from F to F will not be marked norecurse.
1812 if (std::all_of(CGN->begin(), CGN->end(),
1813 [](const CallGraphNode::CallRecord &CR) {
1814 Function *F = CR.second->getFunction();
1815 return F && F->doesNotRecurse();
1816 }))
1817 // Function calls a potentially recursive function.
1818 return setDoesNotRecurse(*F);
1819
1820 // We know that F is not obviously recursive, but we haven't been able to
1821 // prove that it doesn't actually recurse. Add it to the Revisit list to try
1822 // again top-down later.
1823 Revisit.push_back(F);
1824 return false;
1825 }
1826
1827 static bool addNoRecurseAttrsTopDownOnly(Function *F) {
1828 // If F is internal and all uses are in norecurse functions, then F is also
1829 // norecurse.
1830 if (F->doesNotRecurse())
1831 return false;
1832 if (F->hasInternalLinkage()) {
1833 for (auto *U : F->users())
1834 if (auto *I = dyn_cast(U)) {
1835 if (!I->getParent()->getParent()->doesNotRecurse())
1836 return false;
1837 } else {
1838 return false;
1839 }
1840 return setDoesNotRecurse(*F);
1841 }
1842 return false;
1843 }
1844
18451781 bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) {
18461782 TLI = &getAnalysis().getTLI();
18471783 bool Changed = false;
18891825 Changed |= addNoAliasAttrs(SCCNodes);
18901826 Changed |= addNonNullAttrs(SCCNodes, *TLI);
18911827 }
1892
1893 Changed |= addNoRecurseAttrs(SCC, Revisit);
1828
18941829 return Changed;
18951830 }
1896
1897 bool FunctionAttrs::doFinalization(CallGraph &CG) {
1898 bool Changed = false;
1899 // When iterating over SCCs we visit functions in a bottom-up fashion. Some of
1900 // the rules we have for identifying norecurse functions work best with a
1901 // top-down walk, so look again at all the functions we previously marked as
1902 // worth revisiting, in top-down order.
1903 for (auto &F : reverse(Revisit))
1904 if (F)
1905 Changed |= addNoRecurseAttrsTopDownOnly(cast((Value*)F));
1906 return Changed;
1907 }
2929 ret void
3030 }
3131
32 ; CHECK: define void @test1_no(i32* %p) #3 {
32 ; CHECK: define void @test1_no(i32* %p) #1 {
3333 define void @test1_no(i32* %p) nounwind {
3434 call void @callee(i32* %p), !tbaa !2
3535 ret void
7171 declare void @callee(i32* %p) nounwind
7272 declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1) nounwind
7373
74 ; CHECK: attributes #0 = { norecurse nounwind readnone }
75 ; CHECK: attributes #1 = { norecurse nounwind }
74 ; CHECK: attributes #0 = { nounwind readnone }
75 ; CHECK: attributes #1 = { nounwind }
7676 ; CHECK: attributes #2 = { nounwind readonly }
77 ; CHECK: attributes #3 = { nounwind }
78 ; CHECK: attributes #4 = { nounwind argmemonly }
7977
8078 ; Root note.
8179 !0 = !{ }
99 ret i32 %tmp
1010 }
1111
12 ; CHECK: define i32 @g() #1
12 ; CHECK: define i32 @g() #0
1313 define i32 @g() readonly {
1414 ret i32 0
1515 }
1616
17 ; CHECK: define i32 @h() #1
17 ; CHECK: define i32 @h() #0
1818 define i32 @h() readnone {
1919 %tmp = load i32, i32* @x ; [#uses=1]
2020 ret i32 %tmp
2121 }
2222
2323 ; CHECK: attributes #0 = { readnone }
24 ; CHECK: attributes #1 = { norecurse readnone }
33 @g = constant i32 1
44
55 define void @foo() {
6 ; CHECK: void @foo() #0 {
6 ; CHECK: void @foo() {
77 %tmp = load volatile i32, i32* @g
88 ret void
99 }
10
11 ; CHECK: attributes #0 = { norecurse }
1818 ret i32 %r
1919 }
2020
21 ; CHECK: attributes #0 = { norecurse readnone ssp uwtable }
22 ; CHECK: attributes #1 = { norecurse ssp uwtable }
21 ; CHECK: attributes #0 = { readnone ssp uwtable }
22 ; CHECK: attributes #1 = { ssp uwtable }
+0
-57
test/Transforms/FunctionAttrs/norecurse.ll less more
None ; RUN: opt < %s -basicaa -functionattrs -S | FileCheck %s
1
2 ; CHECK: define i32 @leaf() #0
3 define i32 @leaf() {
4 ret i32 1
5 }
6
7 ; CHECK: define i32 @self_rec() #1
8 define i32 @self_rec() {
9 %a = call i32 @self_rec()
10 ret i32 4
11 }
12
13 ; CHECK: define i32 @indirect_rec() #1
14 define i32 @indirect_rec() {
15 %a = call i32 @indirect_rec2()
16 ret i32 %a
17 }
18 ; CHECK: define i32 @indirect_rec2() #1
19 define i32 @indirect_rec2() {
20 %a = call i32 @indirect_rec()
21 ret i32 %a
22 }
23
24 ; CHECK: define i32 @extern() #1
25 define i32 @extern() {
26 %a = call i32 @k()
27 ret i32 %a
28 }
29 declare i32 @k() readnone
30
31 ; CHECK: define internal i32 @called_by_norecurse() #0
32 define internal i32 @called_by_norecurse() {
33 %a = call i32 @k()
34 ret i32 %a
35 }
36 define void @m() norecurse {
37 %a = call i32 @called_by_norecurse()
38 ret void
39 }
40
41 ; CHECK: define internal i32 @called_by_norecurse_indirectly() #0
42 define internal i32 @called_by_norecurse_indirectly() {
43 %a = call i32 @k()
44 ret i32 %a
45 }
46 define internal void @o() {
47 %a = call i32 @called_by_norecurse_indirectly()
48 ret void
49 }
50 define void @p() norecurse {
51 call void @o()
52 ret void
53 }
54
55 ; CHECK: attributes #0 = { norecurse readnone }
56 ; CHECK: attributes #1 = { readnone }
1515
1616 declare i8 @strlen(i8*) noinline optnone
1717 ; CHECK-LABEL: @strlen
18 ; CHECK: (i8*) #2
18 ; CHECK: (i8*) #1
1919
2020 ; CHECK-LABEL: attributes #0
21 ; CHECK: = { norecurse readnone }
21 ; CHECK: = { readnone }
2222 ; CHECK-LABEL: attributes #1
23 ; CHECK: = { noinline norecurse optnone }
24 ; CHECK-LABEL: attributes #2
2523 ; CHECK: = { noinline optnone }