Remove the Expr member from IVUsers. Instead of remembering the expression,

just ask ScalarEvolution for it on demand. This helps IVUsers be more robust
in the case of expressions changing underneath it. This fixes PR6862.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@101819 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dan Gohman
2010-04-19 21:48:58 +00:00
parent 22e401f5d4
commit c056454ecf
4 changed files with 65 additions and 58 deletions

View File

@@ -36,9 +36,8 @@ class IVUsers;
class IVStrideUse : public CallbackVH, public ilist_node<IVStrideUse> { class IVStrideUse : public CallbackVH, public ilist_node<IVStrideUse> {
friend class IVUsers; friend class IVUsers;
public: public:
IVStrideUse(IVUsers *P, const SCEV *E, IVStrideUse(IVUsers *P, Instruction* U, Value *O)
Instruction* U, Value *O) : CallbackVH(U), Parent(P), OperandValToReplace(O) {
: CallbackVH(U), Parent(P), Expr(E), OperandValToReplace(O) {
} }
/// getUser - Return the user instruction for this use. /// getUser - Return the user instruction for this use.
@@ -51,20 +50,6 @@ public:
setValPtr(NewUser); setValPtr(NewUser);
} }
/// getParent - Return a pointer to the IVUsers that owns
/// this IVStrideUse.
IVUsers *getParent() const { return Parent; }
/// getExpr - Return the expression for the use.
const SCEV *getExpr() const { return Expr; }
/// setExpr - Assign a new expression to this use.
void setExpr(const SCEV *Val) {
Expr = Val;
}
const SCEV *getStride(const Loop *L) const;
/// getOperandValToReplace - Return the Value of the operand in the user /// getOperandValToReplace - Return the Value of the operand in the user
/// instruction that this IVStrideUse is representing. /// instruction that this IVStrideUse is representing.
Value *getOperandValToReplace() const { Value *getOperandValToReplace() const {
@@ -91,9 +76,6 @@ private:
/// Parent - a pointer to the IVUsers that owns this IVStrideUse. /// Parent - a pointer to the IVUsers that owns this IVStrideUse.
IVUsers *Parent; IVUsers *Parent;
/// Expr - The expression for this use.
const SCEV *Expr;
/// OperandValToReplace - The Value of the operand in the user instruction /// OperandValToReplace - The Value of the operand in the user instruction
/// that this IVStrideUse is representing. /// that this IVStrideUse is representing.
WeakVH OperandValToReplace; WeakVH OperandValToReplace;
@@ -161,12 +143,16 @@ public:
/// return true. Otherwise, return false. /// return true. Otherwise, return false.
bool AddUsersIfInteresting(Instruction *I); bool AddUsersIfInteresting(Instruction *I);
IVStrideUse &AddUser(const SCEV *Expr, IVStrideUse &AddUser(Instruction *User, Value *Operand);
Instruction *User, Value *Operand);
/// getReplacementExpr - Return a SCEV expression which computes the /// getReplacementExpr - Return a SCEV expression which computes the
/// value of the OperandValToReplace of the given IVStrideUse. /// value of the OperandValToReplace of the given IVStrideUse.
const SCEV *getReplacementExpr(const IVStrideUse &U) const; const SCEV *getReplacementExpr(const IVStrideUse &IU) const;
/// getExpr - Return the expression for the use.
const SCEV *getExpr(const IVStrideUse &IU) const;
const SCEV *getStride(const IVStrideUse &IU, const Loop *L) const;
typedef ilist<IVStrideUse>::iterator iterator; typedef ilist<IVStrideUse>::iterator iterator;
typedef ilist<IVStrideUse>::const_iterator const_iterator; typedef ilist<IVStrideUse>::const_iterator const_iterator;

View File

@@ -122,23 +122,21 @@ bool IVUsers::AddUsersIfInteresting(Instruction *I) {
if (AddUserToIVUsers) { if (AddUserToIVUsers) {
// Okay, we found a user that we cannot reduce. // Okay, we found a user that we cannot reduce.
IVUses.push_back(new IVStrideUse(this, ISE, User, I)); IVUses.push_back(new IVStrideUse(this, User, I));
IVStrideUse &NewUse = IVUses.back(); IVStrideUse &NewUse = IVUses.back();
// Transform the expression into a normalized form. // Transform the expression into a normalized form.
NewUse.Expr = ISE = TransformForPostIncUse(NormalizeAutodetect,
TransformForPostIncUse(NormalizeAutodetect, NewUse.Expr, ISE, User, I,
User, I, NewUse.PostIncLoops,
NewUse.PostIncLoops, *SE, *DT);
*SE, *DT); DEBUG(dbgs() << " NORMALIZED TO: " << *ISE << '\n');
DEBUG(dbgs() << " NORMALIZED TO: " << *NewUse.Expr << '\n');
} }
} }
return true; return true;
} }
IVStrideUse &IVUsers::AddUser(const SCEV *Expr, IVStrideUse &IVUsers::AddUser(Instruction *User, Value *Operand) {
Instruction *User, Value *Operand) { IVUses.push_back(new IVStrideUse(this, User, Operand));
IVUses.push_back(new IVStrideUse(this, Expr, User, Operand));
return IVUses.back(); return IVUses.back();
} }
@@ -169,15 +167,6 @@ bool IVUsers::runOnLoop(Loop *l, LPPassManager &LPM) {
return false; return false;
} }
/// getReplacementExpr - Return a SCEV expression which computes the
/// value of the OperandValToReplace of the given IVStrideUse.
const SCEV *IVUsers::getReplacementExpr(const IVStrideUse &U) const {
PostIncLoopSet &Loops = const_cast<PostIncLoopSet &>(U.PostIncLoops);
return TransformForPostIncUse(Denormalize, U.getExpr(),
U.getUser(), U.getOperandValToReplace(),
Loops, *SE, *DT);
}
void IVUsers::print(raw_ostream &OS, const Module *M) const { void IVUsers::print(raw_ostream &OS, const Module *M) const {
OS << "IV Users for loop "; OS << "IV Users for loop ";
WriteAsOperand(OS, L->getHeader(), false); WriteAsOperand(OS, L->getHeader(), false);
@@ -194,8 +183,7 @@ void IVUsers::print(raw_ostream &OS, const Module *M) const {
E = IVUses.end(); UI != E; ++UI) { E = IVUses.end(); UI != E; ++UI) {
OS << " "; OS << " ";
WriteAsOperand(OS, UI->getOperandValToReplace(), false); WriteAsOperand(OS, UI->getOperandValToReplace(), false);
OS << " = " OS << " = " << *getReplacementExpr(*UI);
<< *getReplacementExpr(*UI);
for (PostIncLoopSet::const_iterator for (PostIncLoopSet::const_iterator
I = UI->PostIncLoops.begin(), I = UI->PostIncLoops.begin(),
E = UI->PostIncLoops.end(); I != E; ++I) { E = UI->PostIncLoops.end(); I != E; ++I) {
@@ -218,6 +206,21 @@ void IVUsers::releaseMemory() {
IVUses.clear(); IVUses.clear();
} }
/// getReplacementExpr - Return a SCEV expression which computes the
/// value of the OperandValToReplace.
const SCEV *IVUsers::getReplacementExpr(const IVStrideUse &IU) const {
return SE->getSCEV(IU.getOperandValToReplace());
}
/// getExpr - Return the expression for the use.
const SCEV *IVUsers::getExpr(const IVStrideUse &IU) const {
return
TransformForPostIncUse(Normalize, getReplacementExpr(IU),
IU.getUser(), IU.getOperandValToReplace(),
const_cast<PostIncLoopSet &>(IU.getPostIncLoops()),
*SE, *DT);
}
static const SCEVAddRecExpr *findAddRecForLoop(const SCEV *S, const Loop *L) { static const SCEVAddRecExpr *findAddRecForLoop(const SCEV *S, const Loop *L) {
if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S)) { if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S)) {
if (AR->getLoop() == L) if (AR->getLoop() == L)
@@ -236,18 +239,13 @@ static const SCEVAddRecExpr *findAddRecForLoop(const SCEV *S, const Loop *L) {
return 0; return 0;
} }
const SCEV *IVStrideUse::getStride(const Loop *L) const { const SCEV *IVUsers::getStride(const IVStrideUse &IU, const Loop *L) const {
if (const SCEVAddRecExpr *AR = findAddRecForLoop(getExpr(), L)) if (const SCEVAddRecExpr *AR = findAddRecForLoop(getExpr(IU), L))
return AR->getStepRecurrence(*Parent->SE); return AR->getStepRecurrence(*SE);
return 0; return 0;
} }
void IVStrideUse::transformToPostInc(const Loop *L) { void IVStrideUse::transformToPostInc(const Loop *L) {
PostIncLoopSet Loops;
Loops.insert(L);
Expr = TransformForPostIncUse(Normalize, Expr,
getUser(), getOperandValToReplace(),
Loops, *Parent->SE, *Parent->DT);
PostIncLoops.insert(L); PostIncLoops.insert(L);
} }

View File

@@ -1575,8 +1575,8 @@ LSRInstance::OptimizeLoopTermCond() {
!DT.properlyDominates(UI->getUser()->getParent(), ExitingBlock)) { !DT.properlyDominates(UI->getUser()->getParent(), ExitingBlock)) {
// Conservatively assume there may be reuse if the quotient of their // Conservatively assume there may be reuse if the quotient of their
// strides could be a legal scale. // strides could be a legal scale.
const SCEV *A = CondUse->getStride(L); const SCEV *A = IU.getStride(*CondUse, L);
const SCEV *B = UI->getStride(L); const SCEV *B = IU.getStride(*UI, L);
if (!A || !B) continue; if (!A || !B) continue;
if (SE.getTypeSizeInBits(A->getType()) != if (SE.getTypeSizeInBits(A->getType()) !=
SE.getTypeSizeInBits(B->getType())) { SE.getTypeSizeInBits(B->getType())) {
@@ -1629,8 +1629,7 @@ LSRInstance::OptimizeLoopTermCond() {
ExitingBlock->getInstList().insert(TermBr, Cond); ExitingBlock->getInstList().insert(TermBr, Cond);
// Clone the IVUse, as the old use still exists! // Clone the IVUse, as the old use still exists!
CondUse = &IU.AddUser(CondUse->getExpr(), CondUse = &IU.AddUser(Cond, CondUse->getOperandValToReplace());
Cond, CondUse->getOperandValToReplace());
TermBr->replaceUsesOfWith(OldCond, Cond); TermBr->replaceUsesOfWith(OldCond, Cond);
} }
} }
@@ -1748,7 +1747,7 @@ void LSRInstance::CollectInterestingTypesAndFactors() {
// Collect interesting types and strides. // Collect interesting types and strides.
SmallVector<const SCEV *, 4> Worklist; SmallVector<const SCEV *, 4> Worklist;
for (IVUsers::const_iterator UI = IU.begin(), E = IU.end(); UI != E; ++UI) { for (IVUsers::const_iterator UI = IU.begin(), E = IU.end(); UI != E; ++UI) {
const SCEV *Expr = UI->getExpr(); const SCEV *Expr = IU.getExpr(*UI);
// Collect interesting types. // Collect interesting types.
Types.insert(SE.getEffectiveSCEVType(Expr->getType())); Types.insert(SE.getEffectiveSCEVType(Expr->getType()));
@@ -1819,7 +1818,7 @@ void LSRInstance::CollectFixupsAndInitialFormulae() {
AccessTy = getAccessType(LF.UserInst); AccessTy = getAccessType(LF.UserInst);
} }
const SCEV *S = UI->getExpr(); const SCEV *S = IU.getExpr(*UI);
// Equality (== and !=) ICmps are special. We can rewrite (i == N) as // Equality (== and !=) ICmps are special. We can rewrite (i == N) as
// (N - i == 0), and this allows (N - i) to be the expression that we work // (N - i == 0), and this allows (N - i) to be the expression that we work

View File

@@ -82,3 +82,27 @@ bb20.loopexit:
%tmp.0.ph = phi i32 [ 0, %bb18 ], [ 1, %bb15 ], [ 0, %bb13 ] %tmp.0.ph = phi i32 [ 0, %bb18 ], [ 1, %bb15 ], [ 0, %bb13 ]
ret i32 %tmp.0.ph ret i32 %tmp.0.ph
} }
; Indvars should eliminate the icmp here.
; CHECK: @func_10
; CHECK-NOT: icmp
; CHECK: ret void
define void @func_10() nounwind {
entry:
br label %loop
loop:
%i = phi i32 [ %i.next, %loop ], [ 0, %entry ]
%t0 = icmp slt i32 %i, 0
%t1 = zext i1 %t0 to i32
%t2 = add i32 %t1, %i
%u3 = zext i32 %t2 to i64
store i64 %u3, i64* null
%i.next = add i32 %i, 1
br i1 undef, label %loop, label %return
return:
ret void
}