Revert "[FunctionAttrs] Identify norecurse functions"
authorJames Molloy <james.molloy@arm.com>
Thu, 12 Nov 2015 09:05:43 +0000 (09:05 +0000)
committerJames Molloy <james.molloy@arm.com>
Thu, 12 Nov 2015 09:05:43 +0000 (09:05 +0000)
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
test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll
test/Transforms/FunctionAttrs/2008-09-03-ReadNone.ll
test/Transforms/FunctionAttrs/2010-10-30-volatile.ll
test/Transforms/FunctionAttrs/atomic.ll
test/Transforms/FunctionAttrs/norecurse.ll [deleted file]
test/Transforms/FunctionAttrs/optnone.ll

index edebc26d475e53262b58aa71b7f3e304aa1c5908..351809ddedec6475dc961dc0a630c5218df8f46c 100644 (file)
@@ -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<Function *, 8> 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<AssumptionCacheTracker>();
@@ -79,7 +73,6 @@ struct FunctionAttrs : public CallGraphSCCPass {
 
 private:
   TargetLibraryInfo *TLI;
-  SmallVector<WeakVH,16> 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<WeakVH> &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<Instruction>(U)) {
-        if (!I->getParent()->getParent()->doesNotRecurse())
-          return false;
-      } else {
-        return false;
-      }
-    return setDoesNotRecurse(*F);
-  }
-  return false;
-}
-
 bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) {
   TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().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<Function>((Value*)F));
   return Changed;
 }
index 44031417032d2edeea5f677cd790efbc663c56ae..6c9439afeeabbd205476e5a1acca0485da397f24 100644 (file)
@@ -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 = !{ }
index b62698a776fb5e226649ef419aa24408cd663cce..ca05d63743b5eaa3605ddcd58413b4bf67170de6 100644 (file)
@@ -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                ; <i32> [#uses=1]
        ret i32 %tmp
 }
 
 ; CHECK: attributes #0 = { readnone }
-; CHECK: attributes #1 = { norecurse readnone }
index 23bb18e92b4cbef7441471f5dddaf08cacb65f3b..1a64a83938048833029365852a581a1a1f8d7f1c 100644 (file)
@@ -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 }
index dd915a6027f2cdd903e73ab6055dddc2bac0093d..bb867011cc2a9df3911612ff72b7731a45bc0b55 100644 (file)
@@ -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 (file)
index 4748119..0000000
+++ /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 }
index 441ff4da65ecc991f04db46ef148b02ba36c9ce7..7694bfe13aa519ea746bcfa9d92c021fa960439f 100644 (file)
@@ -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 }