From 6cd07b45e172b457428b291fa28252e507a7c50c Mon Sep 17 00:00:00 2001 From: James Molloy Date: Thu, 12 Nov 2015 09:05:43 +0000 Subject: [PATCH] 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 --- lib/Transforms/IPO/FunctionAttrs.cpp | 79 +------------------ .../TypeBasedAliasAnalysis/functionattrs.ll | 8 +- .../FunctionAttrs/2008-09-03-ReadNone.ll | 5 +- .../FunctionAttrs/2010-10-30-volatile.ll | 4 +- test/Transforms/FunctionAttrs/atomic.ll | 4 +- test/Transforms/FunctionAttrs/norecurse.ll | 57 ------------- test/Transforms/FunctionAttrs/optnone.ll | 6 +- 7 files changed, 11 insertions(+), 152 deletions(-) delete mode 100644 test/Transforms/FunctionAttrs/norecurse.ll diff --git a/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index edebc26d475..351809ddede 100644 --- a/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/lib/Transforms/IPO/FunctionAttrs.cpp @@ -50,7 +50,6 @@ STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly"); STATISTIC(NumNoAlias, "Number of function returns marked noalias"); STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull"); STATISTIC(NumAnnotated, "Number of attributes added to library functions"); -STATISTIC(NumNoRecurse, "Number of functions marked as norecurse"); namespace { typedef SmallSetVector SCCNodeSet; @@ -64,12 +63,7 @@ struct FunctionAttrs : public CallGraphSCCPass { } bool runOnSCC(CallGraphSCC &SCC) override; - bool doInitialization(CallGraph &CG) override { - Revisit.clear(); - return false; - } - bool doFinalization(CallGraph &CG) override; - + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addRequired(); @@ -79,7 +73,6 @@ struct FunctionAttrs : public CallGraphSCCPass { private: TargetLibraryInfo *TLI; - SmallVector Revisit; }; } @@ -983,14 +976,6 @@ static void setDoesNotAlias(Function &F, unsigned n) { } } -static bool setDoesNotRecurse(Function &F) { - if (F.doesNotRecurse()) - return false; - F.setDoesNotRecurse(); - ++NumNoRecurse; - return true; -} - /// Analyze the name and prototype of the given function and set any applicable /// attributes. /// @@ -1794,55 +1779,6 @@ static bool inferPrototypeAttributes(Function &F, const TargetLibraryInfo &TLI) return true; } -static bool addNoRecurseAttrs(const CallGraphSCC &SCC, - SmallVectorImpl &Revisit) { - // Try and identify functions that do not recurse. - - // If the SCC contains multiple nodes we know for sure there is recursion. - if (!SCC.isSingular()) - return false; - - const CallGraphNode *CGN = *SCC.begin(); - Function *F = CGN->getFunction(); - if (!F || F->isDeclaration() || F->doesNotRecurse()) - return false; - - // If all of the calls in F are identifiable and are to norecurse functions, F - // is norecurse. This check also detects self-recursion as F is not currently - // marked norecurse, so any called from F to F will not be marked norecurse. - if (std::all_of(CGN->begin(), CGN->end(), - [](const CallGraphNode::CallRecord &CR) { - Function *F = CR.second->getFunction(); - return F && F->doesNotRecurse(); - })) - // Function calls a potentially recursive function. - return setDoesNotRecurse(*F); - - // We know that F is not obviously recursive, but we haven't been able to - // prove that it doesn't actually recurse. Add it to the Revisit list to try - // again top-down later. - Revisit.push_back(F); - return false; -} - -static bool addNoRecurseAttrsTopDownOnly(Function *F) { - // If F is internal and all uses are in norecurse functions, then F is also - // norecurse. - if (F->doesNotRecurse()) - return false; - if (F->hasInternalLinkage()) { - for (auto *U : F->users()) - if (auto *I = dyn_cast(U)) { - if (!I->getParent()->getParent()->doesNotRecurse()) - return false; - } else { - return false; - } - return setDoesNotRecurse(*F); - } - return false; -} - bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) { TLI = &getAnalysis().getTLI(); bool Changed = false; @@ -1890,19 +1826,6 @@ bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) { Changed |= addNoAliasAttrs(SCCNodes); Changed |= addNonNullAttrs(SCCNodes, *TLI); } - - Changed |= addNoRecurseAttrs(SCC, Revisit); - return Changed; -} -bool FunctionAttrs::doFinalization(CallGraph &CG) { - bool Changed = false; - // When iterating over SCCs we visit functions in a bottom-up fashion. Some of - // the rules we have for identifying norecurse functions work best with a - // top-down walk, so look again at all the functions we previously marked as - // worth revisiting, in top-down order. - for (auto &F : reverse(Revisit)) - if (F) - Changed |= addNoRecurseAttrsTopDownOnly(cast((Value*)F)); return Changed; } diff --git a/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll b/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll index 44031417032..6c9439afeea 100644 --- a/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll +++ b/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll @@ -30,7 +30,7 @@ define void @test1_yes(i32* %p) nounwind { ret void } -; CHECK: define void @test1_no(i32* %p) #3 { +; CHECK: define void @test1_no(i32* %p) #1 { define void @test1_no(i32* %p) nounwind { call void @callee(i32* %p), !tbaa !2 ret void @@ -72,11 +72,9 @@ define i32 @test3_no(i8* %p) nounwind { declare void @callee(i32* %p) nounwind declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1) nounwind -; CHECK: attributes #0 = { norecurse nounwind readnone } -; CHECK: attributes #1 = { norecurse nounwind } +; CHECK: attributes #0 = { nounwind readnone } +; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { nounwind readonly } -; CHECK: attributes #3 = { nounwind } -; CHECK: attributes #4 = { nounwind argmemonly } ; Root note. !0 = !{ } diff --git a/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll b/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll index b62698a776f..ca05d63743b 100644 --- a/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll +++ b/test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll @@ -10,16 +10,15 @@ define i32 @f() { ret i32 %tmp } -; CHECK: define i32 @g() #1 +; CHECK: define i32 @g() #0 define i32 @g() readonly { ret i32 0 } -; CHECK: define i32 @h() #1 +; CHECK: define i32 @h() #0 define i32 @h() readnone { %tmp = load i32, i32* @x ; [#uses=1] ret i32 %tmp } ; CHECK: attributes #0 = { readnone } -; CHECK: attributes #1 = { norecurse readnone } diff --git a/test/Transforms/FunctionAttrs/2010-10-30-volatile.ll b/test/Transforms/FunctionAttrs/2010-10-30-volatile.ll index 23bb18e92b4..1a64a839380 100644 --- a/test/Transforms/FunctionAttrs/2010-10-30-volatile.ll +++ b/test/Transforms/FunctionAttrs/2010-10-30-volatile.ll @@ -4,9 +4,7 @@ @g = constant i32 1 define void @foo() { -; CHECK: void @foo() #0 { +; CHECK: void @foo() { %tmp = load volatile i32, i32* @g ret void } - -; CHECK: attributes #0 = { norecurse } diff --git a/test/Transforms/FunctionAttrs/atomic.ll b/test/Transforms/FunctionAttrs/atomic.ll index dd915a6027f..bb867011cc2 100644 --- a/test/Transforms/FunctionAttrs/atomic.ll +++ b/test/Transforms/FunctionAttrs/atomic.ll @@ -19,5 +19,5 @@ entry: ret i32 %r } -; CHECK: attributes #0 = { norecurse readnone ssp uwtable } -; CHECK: attributes #1 = { norecurse ssp uwtable } +; CHECK: attributes #0 = { readnone ssp uwtable } +; CHECK: attributes #1 = { ssp uwtable } diff --git a/test/Transforms/FunctionAttrs/norecurse.ll b/test/Transforms/FunctionAttrs/norecurse.ll deleted file mode 100644 index 47481191d27..00000000000 --- a/test/Transforms/FunctionAttrs/norecurse.ll +++ /dev/null @@ -1,57 +0,0 @@ -; RUN: opt < %s -basicaa -functionattrs -S | FileCheck %s - -; CHECK: define i32 @leaf() #0 -define i32 @leaf() { - ret i32 1 -} - -; CHECK: define i32 @self_rec() #1 -define i32 @self_rec() { - %a = call i32 @self_rec() - ret i32 4 -} - -; CHECK: define i32 @indirect_rec() #1 -define i32 @indirect_rec() { - %a = call i32 @indirect_rec2() - ret i32 %a -} -; CHECK: define i32 @indirect_rec2() #1 -define i32 @indirect_rec2() { - %a = call i32 @indirect_rec() - ret i32 %a -} - -; CHECK: define i32 @extern() #1 -define i32 @extern() { - %a = call i32 @k() - ret i32 %a -} -declare i32 @k() readnone - -; CHECK: define internal i32 @called_by_norecurse() #0 -define internal i32 @called_by_norecurse() { - %a = call i32 @k() - ret i32 %a -} -define void @m() norecurse { - %a = call i32 @called_by_norecurse() - ret void -} - -; CHECK: define internal i32 @called_by_norecurse_indirectly() #0 -define internal i32 @called_by_norecurse_indirectly() { - %a = call i32 @k() - ret i32 %a -} -define internal void @o() { - %a = call i32 @called_by_norecurse_indirectly() - ret void -} -define void @p() norecurse { - call void @o() - ret void -} - -; CHECK: attributes #0 = { norecurse readnone } -; CHECK: attributes #1 = { readnone } diff --git a/test/Transforms/FunctionAttrs/optnone.ll b/test/Transforms/FunctionAttrs/optnone.ll index 441ff4da65e..7694bfe13aa 100644 --- a/test/Transforms/FunctionAttrs/optnone.ll +++ b/test/Transforms/FunctionAttrs/optnone.ll @@ -16,11 +16,9 @@ define void @test_optnone(i8* %p) noinline optnone { declare i8 @strlen(i8*) noinline optnone ; CHECK-LABEL: @strlen -; CHECK: (i8*) #2 +; CHECK: (i8*) #1 ; CHECK-LABEL: attributes #0 -; CHECK: = { norecurse readnone } +; CHECK: = { readnone } ; CHECK-LABEL: attributes #1 -; CHECK: = { noinline norecurse optnone } -; CHECK-LABEL: attributes #2 ; CHECK: = { noinline optnone } -- 2.34.1