diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -2366,19 +2366,61 @@ /// ------------------------ Will-Return Attributes ---------------------------- -// Helper function that checks whether a function has any cycle. +// Helper function that checks whether a function has any cycle and check if +// the cycle have an upper bound or not. // TODO: Replace with more efficent code -static bool containsCycle(Function &F) { - SmallPtrSet Visited; - - // Traverse BB by dfs and check whether successor is already visited. - for (BasicBlock *BB : depth_first(&F)) { - Visited.insert(BB); - for (auto *SuccBB : successors(BB)) { - if (Visited.count(SuccBB)) +static bool containsCycle(Function &F, Attributor &A) { + bool NoAnalysis = false; + + ScalarEvolution *SE = + A.getInfoCache().getAnalysisResultForFunction(F); + LoopInfo *LI = A.getInfoCache().getAnalysisResultForFunction(F); + + if (!LI || !SE) + NoAnalysis = true; + + for (scc_iterator I = scc_begin(&F), IE = scc_end(&F); I != IE; + ++I) { + const std::vector &SCCBBs = *I; + bool SCCHasLoop = I.hasLoop(); + // When NoAnalysis available then check only if the SCC has loop or not. + if (NoAnalysis) { + if (SCCHasLoop) return true; + else + continue; } + // When current SCC has a single block with no loop continue to the next + // SCC. + if (!SCCHasLoop) + continue; + + std::vector::const_iterator BBI = SCCBBs.begin(); + + Loop *L = LI->getLoopFor(*BBI); + // Check whether the current SCC is a loop or not(Loop is Null). + if (!L) + return true; + + // Compare the number of blocks of SCC and the loop and check : + // When the loop have more number of blocks then the current SCC is not + // a loop. + // When they are equal then it is a loop and check the maxTripCount if it + // has an upper bound. + // Else we get the parent loop and check again. + do { + if (L->getNumBlocks() > SCCBBs.size()) + return true; + + if (L->getNumBlocks() == SCCBBs.size()) { + if (!SE->getSmallConstantMaxTripCount(L)) + return true; + else + continue; + } + } while (L != L->getParentLoop() && (L = L->getParentLoop())); } + return false; } @@ -2386,8 +2428,8 @@ // endless loop // FIXME: Any cycle is regarded as endless loop for now. // We have to allow some patterns. -static bool containsPossiblyEndlessLoop(Function *F) { - return !F || !F->hasExactDefinition() || containsCycle(*F); +static bool containsPossiblyEndlessLoop(Function *F, Attributor &A) { + return !F || !F->hasExactDefinition() || containsCycle(*F, A); } struct AAWillReturnImpl : public AAWillReturn { @@ -2398,7 +2440,7 @@ AAWillReturn::initialize(A); Function *F = getAssociatedFunction(); - if (containsPossiblyEndlessLoop(F)) + if (containsPossiblyEndlessLoop(F, A)) indicatePessimisticFixpoint(); } diff --git a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll --- a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll +++ b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll @@ -101,7 +101,7 @@ ret i32* %retval.0 } -; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind +; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn ; CHECK-NEXT: define i32* @external_sink_ret2_nrw(i32* nofree readnone %n0, i32* nocapture nofree readonly %r0, i32* nofree returned writeonly "no-capture-maybe-returned" %w0) define i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) { entry: @@ -160,6 +160,7 @@ ; ; CHECK-NOT: attributes # ; CHECK: attributes #{{.*}} = { argmemonly nofree nosync nounwind } -; CHECK: attributes #{{.*}} = { argmemonly nofree norecurse nosync nounwind } +; CHECK: attributes #{{.*}} = { argmemonly nofree norecurse nosync nounwind willreturn } ; CHECK: attributes #{{.*}} = { nosync nounwind } +; CHECK: attributes #{{.*}} = { norecurse nosync nounwind willreturn } ; CHECK-NOT: attributes #