/// NOTE: The mechanics of adding a new "concrete" abstract attribute are
/// described in the file comment.
struct Attributor {
- Attributor(InformationCache &InfoCache) : InfoCache(InfoCache) {}
+ /// Constructor
+ ///
+ /// \param InformationCache Cache to hold various information accessible for
+ /// the abstract attributes.
+ /// \param DepRecomputeInterval Number of iterations until the dependences
+ /// between abstract attributes are recomputed.
+ Attributor(InformationCache &InfoCache, unsigned DepRecomputeInterval)
+ : InfoCache(InfoCache), DepRecomputeInterval(DepRecomputeInterval) {}
+
~Attributor() { DeleteContainerPointers(AllAbstractAttributes); }
/// Run the analyses until a fixpoint is reached or enforced (timeout).
/// The information cache that holds pre-processed (LLVM-IR) information.
InformationCache &InfoCache;
+ /// Number of iterations until the dependences between abstract attributes are
+ /// recomputed.
+ const unsigned DepRecomputeInterval;
+
/// Functions, blocks, and instructions we delete after manifest is done.
///
///{
"manifestation of attributes -- may issue false-positive errors"),
cl::init(false));
+static cl::opt<unsigned> DepRecInterval(
+ "attributor-dependence-recompute-interval", cl::Hidden,
+ cl::desc("Number of iterations until dependences are recomputed."),
+ cl::init(4));
+
/// Logic operators for the change status enum class.
///
///{
SetVector<AbstractAttribute *> Worklist;
Worklist.insert(AllAbstractAttributes.begin(), AllAbstractAttributes.end());
+ bool RecomputeDependences = false;
+
do {
// Remember the size to determine new attributes.
size_t NumAAs = AllAbstractAttributes.size();
LLVM_DEBUG(dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter
<< ", Worklist size: " << Worklist.size() << "\n");
+ // If dependences (=QueryMap) are recomputed we have to look at all abstract
+ // attributes again, regardless of what changed in the last iteration.
+ if (RecomputeDependences) {
+ LLVM_DEBUG(
+ dbgs() << "[Attributor] Run all AAs to recompute dependences\n");
+ QueryMap.clear();
+ ChangedAAs.clear();
+ Worklist.insert(AllAbstractAttributes.begin(),
+ AllAbstractAttributes.end());
+ }
+
// Add all abstract attributes that are potentially dependent on one that
// changed to the work list.
for (AbstractAttribute *ChangedAA : ChangedAAs) {
if (AA->update(*this) == ChangeStatus::CHANGED)
ChangedAAs.push_back(AA);
+ // Check if we recompute the dependences in the next iteration.
+ RecomputeDependences = (DepRecomputeInterval > 0 &&
+ IterationCounter % DepRecomputeInterval == 0);
+
// Add attributes to the changed set if they have been created in the last
// iteration.
ChangedAAs.append(AllAbstractAttributes.begin() + NumAAs,
size_t NumFinalAAs = AllAbstractAttributes.size();
+ if (VerifyMaxFixpointIterations && IterationCounter != MaxFixpointIterations) {
+ errs() << "\n[Attributor] Fixpoint iteration done after: "
+ << IterationCounter << "/" << MaxFixpointIterations
+ << " iterations\n";
+ llvm_unreachable("The fixpoint was not reached with exactly the number of "
+ "specified iterations!");
+ }
+
LLVM_DEBUG(dbgs() << "\n[Attributor] Fixpoint iteration done after: "
<< IterationCounter << "/" << MaxFixpointIterations
<< " iterations\n");
- if (VerifyMaxFixpointIterations && IterationCounter != MaxFixpointIterations)
- llvm_unreachable("The fixpoint was not reached with exactly the number of "
- "specified iterations!");
bool FinishedAtFixpoint = Worklist.empty();
// Create an Attributor and initially empty information cache that is filled
// while we identify default attribute opportunities.
InformationCache InfoCache(M.getDataLayout());
- Attributor A(InfoCache);
+ Attributor A(InfoCache, DepRecInterval);
for (Function &F : M) {
// TODO: Not all attributes require an exact definition. Find a way to