indvars: incremental fixes for -disable-iv-rewrite and testcases.

Use a proper worklist for use-def traversal without holding onto an
iterator. Now that we process all IV uses, we need complete logic for
resusing existing derived IV defs. See HoistStep.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@132103 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Trick 2011-05-26 00:46:11 +00:00
parent b8d936bc17
commit fcdc9a44e5
2 changed files with 136 additions and 20 deletions

View File

@ -537,6 +537,7 @@ class WidenIV {
LoopInfo *LI;
Loop *L;
ScalarEvolution *SE;
DominatorTree *DT;
SmallVectorImpl<WeakVH> &DeadInsts;
PHINode *WidePhi;
@ -547,7 +548,8 @@ class WidenIV {
public:
WidenIV(PHINode *PN, const WideIVInfo &IVInfo, IVUsers *IUsers,
LoopInfo *LInfo, ScalarEvolution *SEv, SmallVectorImpl<WeakVH> &DI) :
LoopInfo *LInfo, ScalarEvolution *SEv, DominatorTree *DTree,
SmallVectorImpl<WeakVH> &DI) :
OrigPhi(PN),
WideType(IVInfo.WidestNativeType),
IsSigned(IVInfo.IsSigned),
@ -555,6 +557,7 @@ public:
LI(LInfo),
L(LI->getLoopFor(OrigPhi->getParent())),
SE(SEv),
DT(DTree),
DeadInsts(DI),
WidePhi(0),
WideInc(0),
@ -616,7 +619,7 @@ void IndVarSimplify::SimplifyIVUsers(SCEVExpander &Rewriter) {
}
for (WideIVMap::const_iterator I = IVMap.begin(), E = IVMap.end();
I != E; ++I) {
WidenIV Widener(I->first, I->second, IU, LI, SE, DeadInsts);
WidenIV Widener(I->first, I->second, IU, LI, SE, DT, DeadInsts);
if (Widener.CreateWideIV(Rewriter))
Changed = true;
}
@ -696,6 +699,40 @@ const SCEVAddRecExpr *WidenIV::GetWideRecurrence(Instruction *NarrowUse) {
return AddRec;
}
/// HoistStep - Attempt to hoist an IV increment above a potential use.
///
/// To successfully hoist, two criteria must be met:
/// - IncV operands dominate InsertPos and
/// - InsertPos dominates IncV
///
/// Meeting the second condition means that we don't need to check all of IncV's
/// existing uses (it's moving up in the domtree).
///
/// This does not yet recursively hoist the operands, although that would
/// not be difficult.
static bool HoistStep(Instruction *IncV, Instruction *InsertPos,
const DominatorTree *DT)
{
if (DT->dominates(IncV, InsertPos))
return true;
if (!DT->dominates(InsertPos->getParent(), IncV->getParent()))
return false;
if (IncV->mayHaveSideEffects())
return false;
// Attempt to hoist IncV
for (User::op_iterator OI = IncV->op_begin(), OE = IncV->op_end();
OI != OE; ++OI) {
Instruction *OInst = dyn_cast<Instruction>(OI);
if (OInst && !DT->dominates(OInst, InsertPos))
return false;
}
IncV->moveBefore(InsertPos);
return true;
}
/// WidenIVUse - Determine whether an individual user of the narrow IV can be
/// widened. If so, return the wide clone of the user.
Instruction *WidenIV::WidenIVUse(Instruction *NarrowUse,
@ -755,9 +792,10 @@ Instruction *WidenIV::WidenIVUse(Instruction *NarrowUse,
NarrowUse->replaceUsesOfWith(NarrowDef, Trunc);
return 0;
}
// Reuse the IV increment that SCEVExpander created as long as it dominates
// NarrowUse.
Instruction *WideUse = 0;
if (WideAddRec == WideIncExpr) {
// Reuse the IV increment that SCEVExpander created.
if (WideAddRec == WideIncExpr && HoistStep(WideInc, NarrowUse, DT)) {
WideUse = WideInc;
}
else {
@ -828,32 +866,45 @@ bool WidenIV::CreateWideIV(SCEVExpander &Rewriter) {
// WidenIVUse to reuse it when widening the narrow IV's increment. We don't
// employ a general reuse mechanism because the call above is the only call to
// SCEVExpander. Henceforth, we produce 1-to-1 narrow to wide uses.
assert(WidePhi->hasOneUse() && "New IV has multiple users");
WideInc = WidePhi->use_back();
WideIncExpr = SE->getSCEV(WideInc);
if (BasicBlock *LatchBlock = L->getLoopLatch()) {
WideInc =
cast<Instruction>(WidePhi->getIncomingValueForBlock(LatchBlock));
WideIncExpr = SE->getSCEV(WideInc);
}
DEBUG(dbgs() << "Wide IV: " << *WidePhi << "\n");
++NumWidened;
// Traverse the def-use chain using a worklist starting at the original IV.
assert(Processed.empty() && "expect initial state" );
SmallVector<std::pair<Instruction *, Instruction *>, 8> NarrowIVUsers;
NarrowIVUsers.push_back(std::make_pair(OrigPhi, WidePhi));
// Each worklist entry has a Narrow def-use link and Wide def.
SmallVector<std::pair<Use *, Instruction *>, 8> NarrowIVUsers;
for (Value::use_iterator UI = OrigPhi->use_begin(),
UE = OrigPhi->use_end(); UI != UE; ++UI) {
NarrowIVUsers.push_back(std::make_pair(&UI.getUse(), WidePhi));
}
while (!NarrowIVUsers.empty()) {
Instruction *NarrowInst, *WideInst;
tie(NarrowInst, WideInst) = NarrowIVUsers.pop_back_val();
Use *NarrowDefUse;
Instruction *WideDef;
tie(NarrowDefUse, WideDef) = NarrowIVUsers.pop_back_val();
for (Value::use_iterator UI = NarrowInst->use_begin(),
UE = NarrowInst->use_end(); UI != UE; ++UI) {
Instruction *NarrowUse = cast<Instruction>(*UI);
Instruction *WideUse = WidenIVUse(NarrowUse, NarrowInst, WideInst);
if (WideUse)
NarrowIVUsers.push_back(std::make_pair(NarrowUse, WideUse));
// Process a def-use edge. This may replace the use, so don't hold a
// use_iterator across it.
Instruction *NarrowDef = cast<Instruction>(NarrowDefUse->get());
Instruction *NarrowUse = cast<Instruction>(NarrowDefUse->getUser());
Instruction *WideUse = WidenIVUse(NarrowUse, NarrowDef, WideDef);
if (NarrowInst->use_empty())
DeadInsts.push_back(NarrowInst);
// Follow all def-use edges from the previous narrow use.
if (WideUse) {
for (Value::use_iterator UI = NarrowUse->use_begin(),
UE = NarrowUse->use_end(); UI != UE; ++UI) {
NarrowIVUsers.push_back(std::make_pair(&UI.getUse(), WideUse));
}
}
// WidenIVUse may have removed the def-use edge.
if (NarrowDef->use_empty())
DeadInsts.push_back(NarrowDef);
}
return true;
}

View File

@ -2,7 +2,72 @@
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
; Tests sign extend elimination in the inner and outer loop.
; Test reusing the same IV with constant start for preinc and postinc values
; with and without NSW.
; IV rewrite only removes one sext. WidenIVs should remove all three.
define void @postincConstIV(i8* %base, i32 %limit) nounwind {
entry:
br label %loop
; CHECK: loop:
; CHECK-NOT: sext
; CHECK: exit:
loop:
%iv = phi i32 [ %postiv, %loop ], [ 0, %entry ]
%ivnsw = phi i32 [ %postivnsw, %loop ], [ 0, %entry ]
%preofs = sext i32 %iv to i64
%preadr = getelementptr i8* %base, i64 %preofs
store i8 0, i8* %preadr
%postiv = add i32 %iv, 1
%postofs = sext i32 %postiv to i64
%postadr = getelementptr i8* %base, i64 %postofs
store i8 0, i8* %postadr
%postivnsw = add nsw i32 %ivnsw, 1
%postofsnsw = sext i32 %postivnsw to i64
%postadrnsw = getelementptr i8* %base, i64 %postofsnsw
store i8 0, i8* %postadrnsw
%cond = icmp sgt i32 %limit, %iv
br i1 %cond, label %loop, label %exit
exit:
br label %return
return:
ret void
}
; Test reusing the same IV with nonconstant start for preinc and postinc values
; with and without NSW.
; As with constant IV start, WidenIVs should remove all three.
;
; FIXME: WidenIVs should remove %postofs just like %postofsnsw
define void @postincVarIV(i8* %base, i32 %init, i32 %limit) nounwind {
entry:
br label %loop
; CHECK: loop:
; CHECK: sext
; CHECK-NOT: sext
; CHECK: exit:
loop:
%iv = phi i32 [ %postiv, %loop ], [ %init, %entry ]
%ivnsw = phi i32 [ %postivnsw, %loop ], [ 0, %entry ]
%preofs = sext i32 %iv to i64
%preadr = getelementptr i8* %base, i64 %preofs
store i8 0, i8* %preadr
%postiv = add i32 %iv, 1
%postofs = sext i32 %postiv to i64
%postadr = getelementptr i8* %base, i64 %postofs
store i8 0, i8* %postadr
%postivnsw = add nsw i32 %ivnsw, 1
%postofsnsw = sext i32 %postivnsw to i64
%postadrnsw = getelementptr i8* %base, i64 %postofsnsw
store i8 0, i8* %postadrnsw
%cond = icmp sgt i32 %limit, %iv
br i1 %cond, label %loop, label %exit
exit:
br label %return
return:
ret void
}
; Test sign extend elimination in the inner and outer loop.
; %outercount is straightforward to widen, besides being in an outer loop.
; %innercount is currently blocked by lcssa, so is not widened.
; %inneriv can be widened only after proving it has no signed-overflow