const SCEV *getOrCreateMulExpr(SmallVectorImpl<const SCEV *> &Ops,
SCEV::NoWrapFlags Flags);
+ /// Find all of the loops transitively used in \p S, and update \c LoopUsers
+ /// accordingly.
+ void addToLoopUseLists(const SCEV *S);
+
FoldingSet<SCEV> UniqueSCEVs;
FoldingSet<SCEVPredicate> UniquePreds;
BumpPtrAllocator SCEVAllocator;
+ /// This maps loops to a list of SCEV expressions that (transitively) use said
+ /// loop.
+ DenseMap<const Loop *, SmallVector<const SCEV *, 4>> LoopUsers;
+
/// Cache tentative mappings from UnknownSCEVs in a Loop, to a SCEV expression
/// they can be rewritten into under certain predicates.
DenseMap<std::pair<const SCEVUnknown *, const Loop *>,
SCEV *S = new (SCEVAllocator) SCEVTruncateExpr(ID.Intern(SCEVAllocator),
Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
return S;
}
SCEV *S = new (SCEVAllocator) SCEVZeroExtendExpr(ID.Intern(SCEVAllocator),
Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
return S;
}
SCEV *S = new (SCEVAllocator) SCEVZeroExtendExpr(ID.Intern(SCEVAllocator),
Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
return S;
}
SCEV *S = new (SCEVAllocator) SCEVSignExtendExpr(ID.Intern(SCEVAllocator),
Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
return S;
}
SCEV *S = new (SCEVAllocator) SCEVSignExtendExpr(ID.Intern(SCEVAllocator),
Op, Ty);
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
return S;
}
S = new (SCEVAllocator)
SCEVAddExpr(ID.Intern(SCEVAllocator), O, Ops.size());
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
}
S->setNoWrapFlags(Flags);
return S;
S = new (SCEVAllocator) SCEVMulExpr(ID.Intern(SCEVAllocator),
O, Ops.size());
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
}
S->setNoWrapFlags(Flags);
return S;
SCEV *S = new (SCEVAllocator) SCEVUDivExpr(ID.Intern(SCEVAllocator),
LHS, RHS);
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
return S;
}
S = new (SCEVAllocator) SCEVAddRecExpr(ID.Intern(SCEVAllocator),
O, Operands.size(), L);
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
}
S->setNoWrapFlags(Flags);
return S;
SCEV *S = new (SCEVAllocator) SCEVSMaxExpr(ID.Intern(SCEVAllocator),
O, Ops.size());
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
return S;
}
SCEV *S = new (SCEVAllocator) SCEVUMaxExpr(ID.Intern(SCEVAllocator),
O, Ops.size());
UniqueSCEVs.InsertNode(S, IP);
+ addToLoopUseLists(S);
return S;
}
++I;
}
+ auto LoopUsersItr = LoopUsers.find(CurrL);
+ if (LoopUsersItr != LoopUsers.end()) {
+ for (auto *S : LoopUsersItr->second)
+ forgetMemoizedResults(S);
+ LoopUsers.erase(LoopUsersItr);
+ }
+
// Drop information about expressions based on loop-header PHIs.
PushLoopPHIs(CurrL, Worklist);
UniqueSCEVs(std::move(Arg.UniqueSCEVs)),
UniquePreds(std::move(Arg.UniquePreds)),
SCEVAllocator(std::move(Arg.SCEVAllocator)),
+ LoopUsers(std::move(Arg.LoopUsers)),
PredicatedSCEVRewrites(std::move(Arg.PredicatedSCEVRewrites)),
FirstUnknown(Arg.FirstUnknown) {
Arg.FirstUnknown = nullptr;
ExitLimits.erase(I);
}
+void ScalarEvolution::addToLoopUseLists(const SCEV *S) {
+ struct FindUsedLoops {
+ SmallPtrSet<const Loop *, 8> LoopsUsed;
+ bool follow(const SCEV *S) {
+ if (auto *AR = dyn_cast<SCEVAddRecExpr>(S))
+ LoopsUsed.insert(AR->getLoop());
+ return true;
+ }
+
+ bool isDone() const { return false; }
+ };
+
+ FindUsedLoops F;
+ SCEVTraversal<FindUsedLoops>(F).visitAll(S);
+
+ for (auto *L : F.LoopsUsed)
+ LoopUsers[L].push_back(S);
+}
+
void ScalarEvolution::verify() const {
ScalarEvolution &SE = *const_cast<ScalarEvolution *>(this);
ScalarEvolution SE2(F, TLI, AC, DT, LI);
EXPECT_TRUE(isa<SCEVConstant>(EC));
EXPECT_EQ(cast<SCEVConstant>(EC)->getAPInt().getLimitedValue(), 999u);
+ // The add recurrence {5,+,1} does not correspond to any PHI in the IR, and
+ // that is relevant to this test.
+ auto *Five = SE.getConstant(APInt(/*numBits=*/64, 5));
+ auto *AR =
+ SE.getAddRecExpr(Five, SE.getOne(T_int64), Loop, SCEV::FlagAnyWrap);
+ const SCEV *ARAtLoopExit = SE.getSCEVAtScope(AR, nullptr);
+ EXPECT_FALSE(isa<SCEVCouldNotCompute>(ARAtLoopExit));
+ EXPECT_TRUE(isa<SCEVConstant>(ARAtLoopExit));
+ EXPECT_EQ(cast<SCEVConstant>(ARAtLoopExit)->getAPInt().getLimitedValue(),
+ 1004u);
+
SE.forgetLoop(Loop);
Br->eraseFromParent();
Cond->eraseFromParent();
EXPECT_FALSE(isa<SCEVCouldNotCompute>(NewEC));
EXPECT_TRUE(isa<SCEVConstant>(NewEC));
EXPECT_EQ(cast<SCEVConstant>(NewEC)->getAPInt().getLimitedValue(), 1999u);
+ const SCEV *NewARAtLoopExit = SE.getSCEVAtScope(AR, nullptr);
+ EXPECT_FALSE(isa<SCEVCouldNotCompute>(NewARAtLoopExit));
+ EXPECT_TRUE(isa<SCEVConstant>(NewARAtLoopExit));
+ EXPECT_EQ(cast<SCEVConstant>(NewARAtLoopExit)->getAPInt().getLimitedValue(),
+ 2004u);
}
// Make sure that SCEV invalidates exit limits after invalidating the values it