Skip to content

Commit

Permalink
[LICM] Invalidate SCEV upon instruction hoisting
Browse files Browse the repository at this point in the history
Since SCEV can cache information about location of an instruction, it should be invalidated when the instruction is moved.
There should be similar bug in code sinking part of LICM, it will be fixed in a follow-up change.

Patch Author: Daniil Suchkov
Reviewers: asbirlea, mkazantsev, reames
Reviewed By: asbirlea
Subscribers: hiraditya, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D69370
  • Loading branch information
Serguei Katkov committed Oct 31, 2019
1 parent 193a7bf commit 1eb04d2
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 19 deletions.
2 changes: 1 addition & 1 deletion llvm/include/llvm/Transforms/Utils/LoopUtils.h
Expand Up @@ -133,7 +133,7 @@ bool sinkRegion(DomTreeNode *, AliasAnalysis *, LoopInfo *, DominatorTree *,
/// ORE. It returns changed status.
bool hoistRegion(DomTreeNode *, AliasAnalysis *, LoopInfo *, DominatorTree *,
TargetLibraryInfo *, Loop *, AliasSetTracker *,
MemorySSAUpdater *, ICFLoopSafetyInfo *,
MemorySSAUpdater *, ScalarEvolution *, ICFLoopSafetyInfo *,
SinkAndHoistLICMFlags &, OptimizationRemarkEmitter *);

/// This function deletes dead loops. The caller of this function needs to
Expand Down
34 changes: 20 additions & 14 deletions llvm/lib/Transforms/Scalar/LICM.cpp
Expand Up @@ -137,7 +137,8 @@ static bool isNotUsedOrFreeInLoop(const Instruction &I, const Loop *CurLoop,
TargetTransformInfo *TTI, bool &FreeInLoop);
static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
BasicBlock *Dest, ICFLoopSafetyInfo *SafetyInfo,
MemorySSAUpdater *MSSAU, OptimizationRemarkEmitter *ORE);
MemorySSAUpdater *MSSAU, ScalarEvolution *SE,
OptimizationRemarkEmitter *ORE);
static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT,
const Loop *CurLoop, ICFLoopSafetyInfo *SafetyInfo,
MemorySSAUpdater *MSSAU, OptimizationRemarkEmitter *ORE);
Expand All @@ -162,7 +163,7 @@ static void eraseInstruction(Instruction &I, ICFLoopSafetyInfo &SafetyInfo,

static void moveInstructionBefore(Instruction &I, Instruction &Dest,
ICFLoopSafetyInfo &SafetyInfo,
MemorySSAUpdater *MSSAU);
MemorySSAUpdater *MSSAU, ScalarEvolution *SE);

namespace {
struct LoopInvariantCodeMotion {
Expand Down Expand Up @@ -390,8 +391,9 @@ bool LoopInvariantCodeMotion::runOnLoop(
CurAST.get(), MSSAU.get(), &SafetyInfo, Flags, ORE);
Flags.IsSink = false;
if (Preheader)
Changed |= hoistRegion(DT->getNode(L->getHeader()), AA, LI, DT, TLI, L,
CurAST.get(), MSSAU.get(), &SafetyInfo, Flags, ORE);
Changed |=
hoistRegion(DT->getNode(L->getHeader()), AA, LI, DT, TLI, L,
CurAST.get(), MSSAU.get(), SE, &SafetyInfo, Flags, ORE);

// Now that all loop invariants have been removed from the loop, promote any
// memory references to scalars that we can.
Expand Down Expand Up @@ -795,7 +797,7 @@ class ControlFlowHoister {
bool llvm::hoistRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
DominatorTree *DT, TargetLibraryInfo *TLI, Loop *CurLoop,
AliasSetTracker *CurAST, MemorySSAUpdater *MSSAU,
ICFLoopSafetyInfo *SafetyInfo,
ScalarEvolution *SE, ICFLoopSafetyInfo *SafetyInfo,
SinkAndHoistLICMFlags &Flags,
OptimizationRemarkEmitter *ORE) {
// Verify inputs.
Expand Down Expand Up @@ -855,7 +857,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
I, DT, CurLoop, SafetyInfo, ORE,
CurLoop->getLoopPreheader()->getTerminator())) {
hoist(I, DT, CurLoop, CFH.getOrCreateHoistedBlock(BB), SafetyInfo,
MSSAU, ORE);
MSSAU, SE, ORE);
HoistedInstructions.push_back(&I);
Changed = true;
continue;
Expand All @@ -882,7 +884,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
eraseInstruction(I, *SafetyInfo, CurAST, MSSAU);

hoist(*ReciprocalDivisor, DT, CurLoop, CFH.getOrCreateHoistedBlock(BB),
SafetyInfo, MSSAU, ORE);
SafetyInfo, MSSAU, SE, ORE);
HoistedInstructions.push_back(ReciprocalDivisor);
Changed = true;
continue;
Expand All @@ -901,7 +903,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
CurLoop->hasLoopInvariantOperands(&I) &&
MustExecuteWithoutWritesBefore(I)) {
hoist(I, DT, CurLoop, CFH.getOrCreateHoistedBlock(BB), SafetyInfo,
MSSAU, ORE);
MSSAU, SE, ORE);
HoistedInstructions.push_back(&I);
Changed = true;
continue;
Expand All @@ -915,7 +917,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
PN->setIncomingBlock(
i, CFH.getOrCreateHoistedBlock(PN->getIncomingBlock(i)));
hoist(*PN, DT, CurLoop, CFH.getOrCreateHoistedBlock(BB), SafetyInfo,
MSSAU, ORE);
MSSAU, SE, ORE);
assert(DT->dominates(PN, BB) && "Conditional PHIs not expected");
Changed = true;
continue;
Expand Down Expand Up @@ -952,7 +954,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
LLVM_DEBUG(dbgs() << "LICM rehoisting to "
<< HoistPoint->getParent()->getName()
<< ": " << *I << "\n");
moveInstructionBefore(*I, *HoistPoint, *SafetyInfo, MSSAU);
moveInstructionBefore(*I, *HoistPoint, *SafetyInfo, MSSAU, SE);
HoistPoint = I;
Changed = true;
}
Expand Down Expand Up @@ -1441,14 +1443,17 @@ static void eraseInstruction(Instruction &I, ICFLoopSafetyInfo &SafetyInfo,

static void moveInstructionBefore(Instruction &I, Instruction &Dest,
ICFLoopSafetyInfo &SafetyInfo,
MemorySSAUpdater *MSSAU) {
MemorySSAUpdater *MSSAU,
ScalarEvolution *SE) {
SafetyInfo.removeInstruction(&I);
SafetyInfo.insertInstructionTo(&I, Dest.getParent());
I.moveBefore(&Dest);
if (MSSAU)
if (MemoryUseOrDef *OldMemAcc = cast_or_null<MemoryUseOrDef>(
MSSAU->getMemorySSA()->getMemoryAccess(&I)))
MSSAU->moveToPlace(OldMemAcc, Dest.getParent(), MemorySSA::End);
if (SE)
SE->forgetValue(&I);
}

static Instruction *sinkThroughTriviallyReplaceablePHI(
Expand Down Expand Up @@ -1662,7 +1667,8 @@ static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT,
///
static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
BasicBlock *Dest, ICFLoopSafetyInfo *SafetyInfo,
MemorySSAUpdater *MSSAU, OptimizationRemarkEmitter *ORE) {
MemorySSAUpdater *MSSAU, ScalarEvolution *SE,
OptimizationRemarkEmitter *ORE) {
LLVM_DEBUG(dbgs() << "LICM hoisting to " << Dest->getName() << ": " << I
<< "\n");
ORE->emit([&]() {
Expand All @@ -1683,10 +1689,10 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,

if (isa<PHINode>(I))
// Move the new node to the end of the phi list in the destination block.
moveInstructionBefore(I, *Dest->getFirstNonPHI(), *SafetyInfo, MSSAU);
moveInstructionBefore(I, *Dest->getFirstNonPHI(), *SafetyInfo, MSSAU, SE);
else
// Move the new node to the destination block, before its terminator.
moveInstructionBefore(I, *Dest->getTerminator(), *SafetyInfo, MSSAU);
moveInstructionBefore(I, *Dest->getTerminator(), *SafetyInfo, MSSAU, SE);

// Apply line 0 debug locations when we are moving instructions to different
// basic blocks because we want to avoid jumpy line tables.
Expand Down
6 changes: 2 additions & 4 deletions llvm/unittests/Transforms/Scalar/LICMTest.cpp
Expand Up @@ -86,10 +86,8 @@ TEST(LICMTest, TestSCEVInvalidationOnHoisting) {
// If LICM have properly invalidated SCEV,
// 1. SCEV of <load i64, i64* %ptr> should properly dominate the "loop" BB,
// 2. extra invalidation shouldn't change result of the query.
// FIXME: these values should be equal!
EXPECT_NE(DispositionBeforeInvalidation,
EXPECT_EQ(DispositionBeforeInvalidation,
ScalarEvolution::BlockDisposition::ProperlyDominatesBlock);
// FIXME: these values should be equal!
EXPECT_NE(DispositionBeforeInvalidation, DispositionAfterInvalidation);
EXPECT_EQ(DispositionBeforeInvalidation, DispositionAfterInvalidation);
}
}

0 comments on commit 1eb04d2

Please sign in to comment.