Skip to content

Commit 8eded24

Browse files
committed
Recommit "[SCEVExpander] Add helper to clean up instrs inserted while expanding."
Recommit the patch after fixing an issue reported caused by the fact that re-used values are also added to InsertedValues. Additional tests have been added in 8881849 This reverts the revert commit 3888464.
1 parent 36dbb8f commit 8eded24

File tree

3 files changed

+96
-35
lines changed

3 files changed

+96
-35
lines changed

llvm/include/llvm/Transforms/Utils/ScalarEvolutionExpander.h

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ class SCEVExpander : public SCEVVisitor<SCEVExpander, Value *> {
6363
DenseSet<AssertingVH<Value>> InsertedValues;
6464
DenseSet<AssertingVH<Value>> InsertedPostIncValues;
6565

66+
/// Keep track of the existing IR values re-used during expansion.
67+
/// FIXME: Ideally re-used instructions would not be added to
68+
/// InsertedValues/InsertedPostIncValues.
69+
SmallPtrSet<Value *, 16> ReusedValues;
70+
6671
/// A memoization of the "relevant" loop for a given SCEV.
6772
DenseMap<const SCEV *, const Loop *> RelevantLoops;
6873

@@ -177,9 +182,31 @@ class SCEVExpander : public SCEVVisitor<SCEVExpander, Value *> {
177182
InsertedExpressions.clear();
178183
InsertedValues.clear();
179184
InsertedPostIncValues.clear();
185+
ReusedValues.clear();
180186
ChainedPhis.clear();
181187
}
182188

189+
/// Return a vector containing all instructions inserted during expansion.
190+
SmallVector<Instruction *, 32> getAllInsertedInstructions() const {
191+
SmallVector<Instruction *, 32> Result;
192+
for (auto &VH : InsertedValues) {
193+
Value *V = VH;
194+
if (ReusedValues.contains(V))
195+
continue;
196+
if (auto *Inst = dyn_cast<Instruction>(V))
197+
Result.push_back(Inst);
198+
}
199+
for (auto &VH : InsertedPostIncValues) {
200+
Value *V = VH;
201+
if (ReusedValues.contains(V))
202+
continue;
203+
if (auto *Inst = dyn_cast<Instruction>(V))
204+
Result.push_back(Inst);
205+
}
206+
207+
return Result;
208+
}
209+
183210
/// Return true for expressions that can't be evaluated at runtime
184211
/// within given \b Budget.
185212
///
@@ -317,7 +344,8 @@ class SCEVExpander : public SCEVVisitor<SCEVExpander, Value *> {
317344
}
318345

319346
/// Return true if the specified instruction was inserted by the code
320-
/// rewriter. If so, the client should not modify the instruction.
347+
/// rewriter. If so, the client should not modify the instruction. Note that
348+
/// this also includes instructions re-used during expansion.
321349
bool isInsertedInstruction(Instruction *I) const {
322350
return InsertedValues.count(I) || InsertedPostIncValues.count(I);
323351
}
@@ -452,6 +480,27 @@ class SCEVExpander : public SCEVVisitor<SCEVExpander, Value *> {
452480
/// If no PHIs have been created, return the unchanged operand \p OpIdx.
453481
Value *fixupLCSSAFormFor(Instruction *User, unsigned OpIdx);
454482
};
483+
484+
/// Helper to remove instructions inserted during SCEV expansion, unless they
485+
/// are marked as used.
486+
class SCEVExpanderCleaner {
487+
SCEVExpander &Expander;
488+
489+
DominatorTree &DT;
490+
491+
/// Indicates whether the result of the expansion is used. If false, the
492+
/// instructions added during expansion are removed.
493+
bool ResultUsed;
494+
495+
public:
496+
SCEVExpanderCleaner(SCEVExpander &Expander, DominatorTree &DT)
497+
: Expander(Expander), DT(DT), ResultUsed(false) {}
498+
499+
~SCEVExpanderCleaner();
500+
501+
/// Indicate that the result of the expansion is used.
502+
void markResultUsed() { ResultUsed = true; }
503+
};
455504
} // namespace llvm
456505

457506
#endif

llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -295,31 +295,6 @@ static void deleteDeadInstruction(Instruction *I) {
295295
I->eraseFromParent();
296296
}
297297

298-
namespace {
299-
class ExpandedValuesCleaner {
300-
SCEVExpander &Expander;
301-
TargetLibraryInfo *TLI;
302-
SmallVector<Value *, 4> ExpandedValues;
303-
bool Commit = false;
304-
305-
public:
306-
ExpandedValuesCleaner(SCEVExpander &Expander, TargetLibraryInfo *TLI)
307-
: Expander(Expander), TLI(TLI) {}
308-
309-
void add(Value *V) { ExpandedValues.push_back(V); }
310-
311-
void commit() { Commit = true; }
312-
313-
~ExpandedValuesCleaner() {
314-
if (!Commit) {
315-
Expander.clear();
316-
for (auto *V : ExpandedValues)
317-
RecursivelyDeleteTriviallyDeadInstructions(V, TLI);
318-
}
319-
}
320-
};
321-
} // namespace
322-
323298
//===----------------------------------------------------------------------===//
324299
//
325300
// Implementation of LoopIdiomRecognize
@@ -933,7 +908,7 @@ bool LoopIdiomRecognize::processLoopStridedStore(
933908
BasicBlock *Preheader = CurLoop->getLoopPreheader();
934909
IRBuilder<> Builder(Preheader->getTerminator());
935910
SCEVExpander Expander(*SE, *DL, "loop-idiom");
936-
ExpandedValuesCleaner EVC(Expander, TLI);
911+
SCEVExpanderCleaner ExpCleaner(Expander, *DT);
937912

938913
Type *DestInt8PtrTy = Builder.getInt8PtrTy(DestAS);
939914
Type *IntIdxTy = DL->getIndexType(DestPtr->getType());
@@ -956,7 +931,6 @@ bool LoopIdiomRecognize::processLoopStridedStore(
956931
// base pointer and checking the region.
957932
Value *BasePtr =
958933
Expander.expandCodeFor(Start, DestInt8PtrTy, Preheader->getTerminator());
959-
EVC.add(BasePtr);
960934

961935
// From here on out, conservatively report to the pass manager that we've
962936
// changed the IR, even if we later clean up these added instructions. There
@@ -1041,7 +1015,7 @@ bool LoopIdiomRecognize::processLoopStridedStore(
10411015
if (MSSAU && VerifyMemorySSA)
10421016
MSSAU->getMemorySSA()->verifyMemorySSA();
10431017
++NumMemSet;
1044-
EVC.commit();
1018+
ExpCleaner.markResultUsed();
10451019
return true;
10461020
}
10471021

@@ -1075,7 +1049,7 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
10751049
IRBuilder<> Builder(Preheader->getTerminator());
10761050
SCEVExpander Expander(*SE, *DL, "loop-idiom");
10771051

1078-
ExpandedValuesCleaner EVC(Expander, TLI);
1052+
SCEVExpanderCleaner ExpCleaner(Expander, *DT);
10791053

10801054
bool Changed = false;
10811055
const SCEV *StrStart = StoreEv->getStart();
@@ -1094,7 +1068,6 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
10941068
// checking everything.
10951069
Value *StoreBasePtr = Expander.expandCodeFor(
10961070
StrStart, Builder.getInt8PtrTy(StrAS), Preheader->getTerminator());
1097-
EVC.add(StoreBasePtr);
10981071

10991072
// From here on out, conservatively report to the pass manager that we've
11001073
// changed the IR, even if we later clean up these added instructions. There
@@ -1122,7 +1095,6 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
11221095
// mutated by the loop.
11231096
Value *LoadBasePtr = Expander.expandCodeFor(
11241097
LdStart, Builder.getInt8PtrTy(LdAS), Preheader->getTerminator());
1125-
EVC.add(LoadBasePtr);
11261098

11271099
if (mayLoopAccessLocation(LoadBasePtr, ModRefInfo::Mod, CurLoop, BECount,
11281100
StoreSize, *AA, Stores))
@@ -1138,7 +1110,6 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
11381110

11391111
Value *NumBytes =
11401112
Expander.expandCodeFor(NumBytesS, IntIdxTy, Preheader->getTerminator());
1141-
EVC.add(NumBytes);
11421113

11431114
CallInst *NewCall = nullptr;
11441115
// Check whether to generate an unordered atomic memcpy:
@@ -1198,7 +1169,7 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
11981169
if (MSSAU && VerifyMemorySSA)
11991170
MSSAU->getMemorySSA()->verifyMemorySSA();
12001171
++NumMemCpy;
1201-
EVC.commit();
1172+
ExpCleaner.markResultUsed();
12021173
return true;
12031174
}
12041175

llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,9 @@ SCEVExpander::getAddRecExprPHILiterally(const SCEVAddRecExpr *Normalized,
12581258
InsertedValues.insert(AddRecPhiMatch);
12591259
// Remember the increment.
12601260
rememberInstruction(IncV);
1261+
// Those values were not actually inserted but re-used.
1262+
ReusedValues.insert(AddRecPhiMatch);
1263+
ReusedValues.insert(IncV);
12611264
return AddRecPhiMatch;
12621265
}
12631266
}
@@ -1882,10 +1885,12 @@ Value *SCEVExpander::expand(const SCEV *S) {
18821885
// there) so that it is guaranteed to dominate any user inside the loop.
18831886
if (L && SE.hasComputableLoopEvolution(S, L) && !PostIncLoops.count(L))
18841887
InsertPt = &*L->getHeader()->getFirstInsertionPt();
1888+
18851889
while (InsertPt->getIterator() != Builder.GetInsertPoint() &&
18861890
(isInsertedInstruction(InsertPt) ||
1887-
isa<DbgInfoIntrinsic>(InsertPt)))
1891+
isa<DbgInfoIntrinsic>(InsertPt))) {
18881892
InsertPt = &*std::next(InsertPt->getIterator());
1893+
}
18891894
break;
18901895
}
18911896
}
@@ -2630,4 +2635,40 @@ bool isSafeToExpandAt(const SCEV *S, const Instruction *InsertionPoint,
26302635
}
26312636
return false;
26322637
}
2638+
2639+
SCEVExpanderCleaner::~SCEVExpanderCleaner() {
2640+
// Result is used, nothing to remove.
2641+
if (ResultUsed)
2642+
return;
2643+
2644+
auto InsertedInstructions = Expander.getAllInsertedInstructions();
2645+
#ifndef NDEBUG
2646+
SmallPtrSet<Instruction *, 8> InsertedSet(InsertedInstructions.begin(),
2647+
InsertedInstructions.end());
2648+
(void)InsertedSet;
2649+
#endif
2650+
// Remove sets with value handles.
2651+
Expander.clear();
2652+
2653+
// Sort so that earlier instructions do not dominate later instructions.
2654+
stable_sort(InsertedInstructions, [this](Instruction *A, Instruction *B) {
2655+
return DT.dominates(B, A);
2656+
});
2657+
// Remove all inserted instructions.
2658+
for (Instruction *I : InsertedInstructions) {
2659+
2660+
#ifndef NDEBUG
2661+
assert(all_of(I->users(),
2662+
[&InsertedSet](Value *U) {
2663+
return InsertedSet.contains(cast<Instruction>(U));
2664+
}) &&
2665+
"removed instruction should only be used by instructions inserted "
2666+
"during expansion");
2667+
#endif
2668+
assert(!I->getType()->isVoidTy() &&
2669+
"inserted instruction should have non-void types");
2670+
I->replaceAllUsesWith(UndefValue::get(I->getType()));
2671+
I->eraseFromParent();
2672+
}
2673+
}
26332674
}

0 commit comments

Comments
 (0)