mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-05 12:31:33 +00:00
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:
parent
b8d936bc17
commit
fcdc9a44e5
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user