Skip to content

Commit

Permalink
[SCEV] Support clearing Block/LoopDispositions for a single value.
Browse files Browse the repository at this point in the history
Extend forgetBlockAndLoopDisposition to allow clearing information for a
single value. This can be useful when only a single value is changed,
e.g. because the instruction is moved.

We also need to clear the cached values for all SCEV users, because they
may depend on the starting value's disposition.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D134614
  • Loading branch information
fhahn committed Oct 7, 2022
1 parent 3b652fc commit 9e93143
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 20 deletions.
2 changes: 1 addition & 1 deletion llvm/include/llvm/Analysis/ScalarEvolution.h
Expand Up @@ -944,7 +944,7 @@ class ScalarEvolution {
///
/// We don't have a way to invalidate per-loop/per-block dispositions. Clear
/// and recompute is simpler.
void forgetBlockAndLoopDispositions();
void forgetBlockAndLoopDispositions(Value *V = nullptr);

/// Determine the minimum number of zero bits that S is guaranteed to end in
/// (at every loop iteration). It is, at the same time, the minimum number
Expand Down
33 changes: 30 additions & 3 deletions llvm/lib/Analysis/ScalarEvolution.cpp
Expand Up @@ -8384,9 +8384,36 @@ void ScalarEvolution::forgetValue(Value *V) {

void ScalarEvolution::forgetLoopDispositions() { LoopDispositions.clear(); }

void ScalarEvolution::forgetBlockAndLoopDispositions() {
BlockDispositions.clear();
LoopDispositions.clear();
void ScalarEvolution::forgetBlockAndLoopDispositions(Value *V) {
// Unless a specific value is passed to invalidation, completely clear both
// caches.
if (!V) {
BlockDispositions.clear();
LoopDispositions.clear();
return;
}

const SCEV *S = getExistingSCEV(V);
if (!S)
return;

// Invalidate the block and loop dispositions cached for S. Dispositions of
// S's users may change if S's disposition changes (i.e. a user may change to
// loop-invariant, if S changes to loop invariant), so also invalidate
// dispositions of S's users recursively.
SmallVector<const SCEV *, 8> Worklist = {S};
SmallPtrSet<const SCEV *, 8> Seen = {S};
while (!Worklist.empty()) {
const SCEV *Curr = Worklist.pop_back_val();
if (!LoopDispositions.erase(Curr) && !BlockDispositions.erase(S))
continue;

auto Users = SCEVUsers.find(Curr);
if (Users != SCEVUsers.end())
for (const auto *User : Users->second)
if (Seen.insert(User).second)
Worklist.push_back(User);
}
}

/// Get the exact loop backedge taken count considering all loop exits. A
Expand Down
11 changes: 5 additions & 6 deletions llvm/lib/Transforms/Scalar/LoopDeletion.cpp
Expand Up @@ -90,22 +90,21 @@ static bool isLoopDead(Loop *L, ScalarEvolution &SE,
break;

if (Instruction *I = dyn_cast<Instruction>(incoming)) {
if (!L->makeLoopInvariant(I, Changed, Preheader->getTerminator())) {
bool InstrMoved = false;
if (!L->makeLoopInvariant(I, InstrMoved, Preheader->getTerminator())) {
AllEntriesInvariant = false;
break;
}
if (Changed) {
Changed |= InstrMoved;
if (InstrMoved) {
// Moving I to a different location may change its block disposition,
// so invalidate its SCEV.
SE.forgetValue(I);
SE.forgetBlockAndLoopDispositions(I);
}
}
}
}

if (Changed)
SE.forgetLoopDispositions();

if (!AllEntriesInvariant || !AllOutgoingValuesSame)
return false;

Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Transforms/Scalar/LoopSink.cpp
Expand Up @@ -312,12 +312,13 @@ static bool sinkLoopInvariantInstructions(Loop &L, AAResults &AA, LoopInfo &LI,
if (!canSinkOrHoistInst(I, &AA, &DT, &L, MSSAU, false, LICMFlags))
continue;
if (sinkInstruction(L, I, ColdLoopBBs, LoopBlockNumber, LI, DT, BFI,
&MSSAU))
&MSSAU)) {
Changed = true;
if (SE)
SE->forgetBlockAndLoopDispositions(&I);
}
}

if (Changed && SE)
SE->forgetLoopDispositions();
return Changed;
}

Expand Down
16 changes: 9 additions & 7 deletions llvm/lib/Transforms/Utils/LoopSimplify.cpp
Expand Up @@ -647,20 +647,22 @@ static bool simplifyOneLoop(Loop *L, SmallVectorImpl<Loop *> &Worklist,
Instruction *Inst = &*I++;
if (Inst == CI)
continue;
bool InstInvariant = false;
if (!L->makeLoopInvariant(
Inst, AnyInvariant,
Inst, InstInvariant,
Preheader ? Preheader->getTerminator() : nullptr, MSSAU)) {
AllInvariant = false;
break;
}
if (InstInvariant && SE) {
// The loop disposition of all SCEV expressions that depend on any
// hoisted values have also changed.
SE->forgetBlockAndLoopDispositions(Inst);
}
AnyInvariant |= InstInvariant;
}
if (AnyInvariant) {
if (AnyInvariant)
Changed = true;
// The loop disposition of all SCEV expressions that depend on any
// hoisted values have also changed.
if (SE)
SE->forgetLoopDispositions();
}
if (!AllInvariant) continue;

// The block has now been cleared of all instructions except for
Expand Down

0 comments on commit 9e93143

Please sign in to comment.