diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -153,8 +153,12 @@ /// /// \param DependenceRecomputeInterval Number of iterations until the /// dependences between abstract attributes are recomputed. - Attributor(unsigned DependenceRecomputeInterval) - : DependenceRecomputeInterval(DependenceRecomputeInterval) {} + /// \param DependenceRecomputeFixpoint Flag to determine if dependences should + /// be recomputed once a fixpoint is reached. + Attributor(unsigned DependenceRecomputeInterval, + bool DependenceRecomputeFixpoint) + : DependenceRecomputeInterval(DependenceRecomputeInterval), + DependenceRecomputeFixpoint(DependenceRecomputeFixpoint) {} /// Destructor ~Attributor() { DeleteContainerPointers(AllAbstractAttributes); } @@ -310,6 +314,10 @@ /// recomputed. const unsigned DependenceRecomputeInterval; + /// Flag to determine if dependences should be recomputed once a fixpoint is + /// reached. + const bool DependenceRecomputeFixpoint; + /// Check if the state of the abstract attribute \p AA may depend on /// information derived from a non-exact definition. /// 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 @@ -64,6 +64,11 @@ cl::desc("Maximal number of fixpoint iterations."), cl::init(32)); +static cl::opt DepRecFixpoint( + "attributor-dependence-recompute-at-fixpoint", cl::Hidden, + cl::desc("Recompute dependences after a fixpoint was reached."), + cl::init(false)); + static cl::opt DepRecInterval( "attributor-dependence-recompute-interval", cl::Hidden, cl::desc("Number of iterations until dependences are recomputed."), @@ -680,11 +685,18 @@ SetVector Worklist; Worklist.insert(AllAbstractAttributes.begin(), AllAbstractAttributes.end()); + bool FinishedAtFixpoint = false; bool RecomputeDependences = false; do { - LLVM_DEBUG(dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter - << ", Worklist size: " << Worklist.size() << "\n"); + LLVM_DEBUG({ + if (FinishedAtFixpoint) + dbgs() << "\n\n[Attributor] Final iteration to recompute dependences\n"; + else + dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter + << ", Worklist size: " << Worklist.size() + << ", Recomp. Deps.: " << RecomputeDependences << "\n"; + }); // If dependences (=QueryMap) are recomputed we have to look at all abstract // attributes again, regardless of what changed in the last iteration. @@ -711,6 +723,9 @@ if (AA->update(*this) == ChangeStatus::CHANGED) ChangedAAs.push_back(AA); + if (FinishedAtFixpoint) + break; + // Check if we recompute the dependences in the next iteration. RecomputeDependences = (DependenceRecomputeInterval > 0 && @@ -722,14 +737,27 @@ if (!RecomputeDependences) Worklist.insert(ChangedAAs.begin(), ChangedAAs.end()); - } while (!Worklist.empty() && ++IterationCounter < MaxFixpointIterations); + // An optimistic fixpoint was found when the worklist is empty. While we + // could simply stop the update loop, we can traverse it once more to remove + // stale dependences from the QueryMap. This can be beneficial as it might + // prevent deep wrappers for functions with non-exact definitions. + if (Worklist.empty()) { + FinishedAtFixpoint = true; + + // Check if we run a final iteration to recompute dependences. + if (!DependenceRecomputeFixpoint) + break; + + RecomputeDependences = true; + continue; + } + + } while (++IterationCounter < MaxFixpointIterations); LLVM_DEBUG(dbgs() << "\n[Attributor] Fixpoint iteration done after: " << IterationCounter << "/" << MaxFixpointIterations << " iterations\n"); - bool FinishedAtFixpoint = Worklist.empty(); - // Reset abstract arguments not settled in a sound fixpoint by now. This // happens when we stopped the fixpoint iteration early. Note that only the // ones marked as "changed" *and* the ones transitively depending on them @@ -1009,7 +1037,7 @@ // Create an Attributor and initially empty information cache that is filled // while we identify default attribute opportunities. - Attributor A(DepRecInterval); + Attributor A(DepRecInterval, DepRecFixpoint); InformationCache InfoCache; for (Function &F : M) {