diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/.fuse_hidden0001ab7d00000002 copy from llvm/lib/Transforms/IPO/Attributor.cpp copy to llvm/lib/Transforms/IPO/.fuse_hidden0001ab7d00000002 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/.fuse_hidden0001ab7d00000002 @@ -36,9 +36,9 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/NoFolder.h" #include "llvm/IR/Verifier.h" #include "llvm/InitializePasses.h" -#include "llvm/IR/NoFolder.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -1747,7 +1747,9 @@ AANoFreeFloating(const IRPosition &IRP) : AANoFreeImpl(IRP) {} /// See AbstractAttribute::trackStatistics() - void trackStatistics() const override{STATS_DECLTRACK_FLOATING_ATTR(nofree)} + void trackStatistics() const override { + STATS_DECLTRACK_FLOATING_ATTR(nofree) + } /// See Abstract Attribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { @@ -2368,16 +2370,48 @@ // Helper function that checks whether a function has any cycle. // 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); + if (!L) + return true; + + 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 +2420,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 +2432,7 @@ AAWillReturn::initialize(A); Function *F = getAssociatedFunction(); - if (containsPossiblyEndlessLoop(F)) + if (containsPossiblyEndlessLoop(F, A)) indicatePessimisticFixpoint(); } @@ -4617,7 +4651,7 @@ // If a candicate was found in this update, return CHANGED. return HasValueBefore == SimplifiedAssociatedValue.hasValue() ? ChangeStatus::UNCHANGED - : ChangeStatus ::CHANGED; + : ChangeStatus::CHANGED; } /// See AbstractAttribute::trackStatistics() @@ -4644,7 +4678,7 @@ // If a candicate was found in this update, return CHANGED. return HasValueBefore == SimplifiedAssociatedValue.hasValue() ? ChangeStatus::UNCHANGED - : ChangeStatus ::CHANGED; + : ChangeStatus::CHANGED; } ChangeStatus manifest(Attributor &A) override { @@ -4728,7 +4762,7 @@ return HasValueBefore == SimplifiedAssociatedValue.hasValue() ? ChangeStatus::UNCHANGED - : ChangeStatus ::CHANGED; + : ChangeStatus::CHANGED; } /// See AbstractAttribute::trackStatistics() @@ -4903,8 +4937,8 @@ return true; if (auto *SI = dyn_cast(UserI)) { if (SI->getValueOperand() == U.get()) { - LLVM_DEBUG(dbgs() - << "[H2S] escaping store to memory: " << *UserI << "\n"); + LLVM_DEBUG(dbgs() << "[H2S] escaping store to memory: " << *UserI + << "\n"); ValidUsesOnly = false; } else { // A store into the malloc'ed memory is fine. @@ -5438,7 +5472,7 @@ createReplacementValues( PrivatizableType.getValue(), ACS, ACS.getCallArgOperand(ARI.getReplacedArg().getArgNo()), - NewArgOperands); + NewArgOperands); }; // Collect the types that will replace the privatizable type in the function @@ -7217,9 +7251,10 @@ const Function *ScopeFn = IRP.getAnchorScope(); const auto *LivenessAA = - ScopeFn ? &getAAFor(QueryingAA, IRPosition::function(*ScopeFn), - /* TrackDependence */ false) - : nullptr; + ScopeFn + ? &getAAFor(QueryingAA, IRPosition::function(*ScopeFn), + /* TrackDependence */ false) + : nullptr; while (!Worklist.empty()) { const Use *U = Worklist.pop_back_val(); @@ -7359,10 +7394,8 @@ if (!AARetVal.getState().isValidState()) return false; - return AARetVal.checkForAllReturnedValuesAndReturnInsts( - [&](Value &RV, const SmallSetVector &) { - return Pred(RV); - }); + return AARetVal.checkForAllReturnedValuesAndReturnInsts([&]( + Value &RV, const SmallSetVector &) { return Pred(RV); }); } static bool checkForAllInstructionsImpl( @@ -7373,8 +7406,9 @@ for (unsigned Opcode : Opcodes) { for (Instruction *I : OpcodeInstMap[Opcode]) { // Skip dead instructions. - if (A && A->isAssumedDead(IRPosition::value(*I), QueryingAA, LivenessAA, - CheckBBLivenessOnly)) + if (A && + A->isAssumedDead(IRPosition::value(*I), QueryingAA, LivenessAA, + CheckBBLivenessOnly)) continue; if (!Pred(*I)) @@ -8091,9 +8125,9 @@ "Attributor."); break; case Instruction::Load: - // The alignment of a pointer is interesting for loads. + // The alignment of a pointer is interesting for loads. case Instruction::Store: - // The alignment of a pointer is interesting for stores. + // The alignment of a pointer is interesting for stores. case Instruction::Call: case Instruction::CallBr: case Instruction::Invoke: @@ -8359,9 +8393,9 @@ } template -raw_ostream & -llvm::operator<<(raw_ostream &OS, - const IntegerStateBase &S) { +raw_ostream &llvm:: +operator<<(raw_ostream &OS, + const IntegerStateBase &S) { return OS << "(" << S.getKnown() << "-" << S.getAssumed() << ")" << static_cast(S); } 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 #