mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-08 21:32:39 +00:00
indvars -disable-iv-rewrite: bug fix involving weird geps and related cleanup.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@134306 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1a988004db
commit
4b02915386
@ -581,6 +581,7 @@ class WidenIV {
|
|||||||
SmallVectorImpl<WeakVH> &DeadInsts;
|
SmallVectorImpl<WeakVH> &DeadInsts;
|
||||||
|
|
||||||
SmallPtrSet<Instruction*,16> Widened;
|
SmallPtrSet<Instruction*,16> Widened;
|
||||||
|
SmallVector<std::pair<Use *, Instruction *>, 8> NarrowIVUsers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WidenIV(PHINode *PN, const WideIVInfo &WI, LoopInfo *LInfo,
|
WidenIV(PHINode *PN, const WideIVInfo &WI, LoopInfo *LInfo,
|
||||||
@ -607,10 +608,10 @@ protected:
|
|||||||
Instruction *NarrowDef,
|
Instruction *NarrowDef,
|
||||||
Instruction *WideDef);
|
Instruction *WideDef);
|
||||||
|
|
||||||
const SCEVAddRecExpr *GetWideRecurrence(Instruction *NarrowUse);
|
|
||||||
|
|
||||||
Instruction *WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
Instruction *WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
||||||
Instruction *WideDef);
|
Instruction *WideDef);
|
||||||
|
|
||||||
|
void pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef);
|
||||||
};
|
};
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
@ -669,26 +670,6 @@ Instruction *WidenIV::CloneIVUser(Instruction *NarrowUse,
|
|||||||
llvm_unreachable(0);
|
llvm_unreachable(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWideRecurrence - Is this instruction potentially interesting from IVUsers'
|
|
||||||
// perspective after widening it's type? In other words, can the extend be
|
|
||||||
// safely hoisted out of the loop with SCEV reducing the value to a recurrence
|
|
||||||
// on the same loop. If so, return the sign or zero extended
|
|
||||||
// recurrence. Otherwise return NULL.
|
|
||||||
const SCEVAddRecExpr *WidenIV::GetWideRecurrence(Instruction *NarrowUse) {
|
|
||||||
if (!SE->isSCEVable(NarrowUse->getType()))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
const SCEV *NarrowExpr = SE->getSCEV(NarrowUse);
|
|
||||||
const SCEV *WideExpr = IsSigned ?
|
|
||||||
SE->getSignExtendExpr(NarrowExpr, WideType) :
|
|
||||||
SE->getZeroExtendExpr(NarrowExpr, WideType);
|
|
||||||
const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(WideExpr);
|
|
||||||
if (!AddRec || AddRec->getLoop() != L)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return AddRec;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HoistStep - Attempt to hoist an IV increment above a potential use.
|
/// HoistStep - Attempt to hoist an IV increment above a potential use.
|
||||||
///
|
///
|
||||||
/// To successfully hoist, two criteria must be met:
|
/// To successfully hoist, two criteria must be met:
|
||||||
@ -729,15 +710,10 @@ Instruction *WidenIV::WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
|||||||
Instruction *WideDef) {
|
Instruction *WideDef) {
|
||||||
Instruction *NarrowUse = cast<Instruction>(NarrowDefUse.getUser());
|
Instruction *NarrowUse = cast<Instruction>(NarrowDefUse.getUser());
|
||||||
|
|
||||||
// To be consistent with IVUsers, stop traversing the def-use chain at
|
// Stop traversing the def-use chain at inner-loop phis or post-loop phis.
|
||||||
// inner-loop phis or post-loop phis.
|
|
||||||
if (isa<PHINode>(NarrowUse) && LI->getLoopFor(NarrowUse->getParent()) != L)
|
if (isa<PHINode>(NarrowUse) && LI->getLoopFor(NarrowUse->getParent()) != L)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Handle data flow merges and bizarre phi cycles.
|
|
||||||
if (!Widened.insert(NarrowUse))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Our raison d'etre! Eliminate sign and zero extension.
|
// Our raison d'etre! Eliminate sign and zero extension.
|
||||||
if (IsSigned ? isa<SExtInst>(NarrowUse) : isa<ZExtInst>(NarrowUse)) {
|
if (IsSigned ? isa<SExtInst>(NarrowUse) : isa<ZExtInst>(NarrowUse)) {
|
||||||
Value *NewDef = WideDef;
|
Value *NewDef = WideDef;
|
||||||
@ -775,7 +751,26 @@ Instruction *WidenIV::WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
|||||||
// No further widening is needed. The deceased [sz]ext had done it for us.
|
// No further widening is needed. The deceased [sz]ext had done it for us.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const SCEVAddRecExpr *WideAddRec = GetWideRecurrence(NarrowUse);
|
|
||||||
|
// Does this user itself evaluate to a recurrence after widening?
|
||||||
|
const SCEVAddRecExpr *WideAddRec = 0;
|
||||||
|
if (SE->isSCEVable(NarrowUse->getType())) {
|
||||||
|
const SCEV *NarrowExpr = SE->getSCEV(NarrowUse);
|
||||||
|
if (SE->getTypeSizeInBits(NarrowExpr->getType())
|
||||||
|
>= SE->getTypeSizeInBits(WideType)) {
|
||||||
|
// NarrowUse implicitly widens its operand. e.g. a gep with a narrow
|
||||||
|
// index. We have already extended the operand, so we're done.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const SCEV *WideExpr = IsSigned ?
|
||||||
|
SE->getSignExtendExpr(NarrowExpr, WideType) :
|
||||||
|
SE->getZeroExtendExpr(NarrowExpr, WideType);
|
||||||
|
|
||||||
|
// Only widen past values that evaluate to a recurrence in the same loop.
|
||||||
|
const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(WideExpr);
|
||||||
|
if (AddRec && AddRec->getLoop() == L)
|
||||||
|
WideAddRec = AddRec;
|
||||||
|
}
|
||||||
if (!WideAddRec) {
|
if (!WideAddRec) {
|
||||||
// This user does not evaluate to a recurence after widening, so don't
|
// This user does not evaluate to a recurence after widening, so don't
|
||||||
// follow it. Instead insert a Trunc to kill off the original use,
|
// follow it. Instead insert a Trunc to kill off the original use,
|
||||||
@ -785,9 +780,10 @@ Instruction *WidenIV::WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
|||||||
NarrowUse->replaceUsesOfWith(NarrowDef, Trunc);
|
NarrowUse->replaceUsesOfWith(NarrowDef, Trunc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// We assume that block terminators are not SCEVable.
|
// We assume that block terminators are not SCEVable. We wouldn't want to
|
||||||
|
// insert a Trunc after a terminator if there happens to be a critical edge.
|
||||||
assert(NarrowUse != NarrowUse->getParent()->getTerminator() &&
|
assert(NarrowUse != NarrowUse->getParent()->getTerminator() &&
|
||||||
"can't split terminators");
|
"SCEV is not expected to evaluate a block terminator");
|
||||||
|
|
||||||
// Reuse the IV increment that SCEVExpander created as long as it dominates
|
// Reuse the IV increment that SCEVExpander created as long as it dominates
|
||||||
// NarrowUse.
|
// NarrowUse.
|
||||||
@ -800,8 +796,8 @@ Instruction *WidenIV::WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
|||||||
if (!WideUse)
|
if (!WideUse)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// GetWideRecurrence ensured that the narrow expression could be extended
|
// Evaluation of WideAddRec ensured that the narrow expression could be
|
||||||
// outside the loop without overflow. This suggests that the wide use
|
// extended outside the loop without overflow. This suggests that the wide use
|
||||||
// evaluates to the same expression as the extended narrow use, but doesn't
|
// evaluates to the same expression as the extended narrow use, but doesn't
|
||||||
// absolutely guarantee it. Hence the following failsafe check. In rare cases
|
// absolutely guarantee it. Hence the following failsafe check. In rare cases
|
||||||
// where it fails, we simply throw away the newly created wide use.
|
// where it fails, we simply throw away the newly created wide use.
|
||||||
@ -816,6 +812,21 @@ Instruction *WidenIV::WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
|||||||
return WideUse;
|
return WideUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// pushNarrowIVUsers - Add eligible users of NarrowDef to NarrowIVUsers.
|
||||||
|
///
|
||||||
|
void WidenIV::pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef) {
|
||||||
|
for (Value::use_iterator UI = NarrowDef->use_begin(),
|
||||||
|
UE = NarrowDef->use_end(); UI != UE; ++UI) {
|
||||||
|
Use &U = UI.getUse();
|
||||||
|
|
||||||
|
// Handle data flow merges and bizarre phi cycles.
|
||||||
|
if (!Widened.insert(cast<Instruction>(U.getUser())))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
NarrowIVUsers.push_back(std::make_pair(&UI.getUse(), WideDef));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// CreateWideIV - Process a single induction variable. First use the
|
/// CreateWideIV - Process a single induction variable. First use the
|
||||||
/// SCEVExpander to create a wide induction variable that evaluates to the same
|
/// SCEVExpander to create a wide induction variable that evaluates to the same
|
||||||
/// recurrence as the original narrow IV. Then use a worklist to forward
|
/// recurrence as the original narrow IV. Then use a worklist to forward
|
||||||
@ -873,14 +884,11 @@ PHINode *WidenIV::CreateWideIV(SCEVExpander &Rewriter) {
|
|||||||
++NumWidened;
|
++NumWidened;
|
||||||
|
|
||||||
// Traverse the def-use chain using a worklist starting at the original IV.
|
// Traverse the def-use chain using a worklist starting at the original IV.
|
||||||
assert(Widened.empty() && "expect initial state" );
|
assert(Widened.empty() && NarrowIVUsers.empty() && "expect initial state" );
|
||||||
|
|
||||||
|
Widened.insert(OrigPhi);
|
||||||
|
pushNarrowIVUsers(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()) {
|
while (!NarrowIVUsers.empty()) {
|
||||||
Use *UsePtr;
|
Use *UsePtr;
|
||||||
Instruction *WideDef;
|
Instruction *WideDef;
|
||||||
@ -893,12 +901,9 @@ PHINode *WidenIV::CreateWideIV(SCEVExpander &Rewriter) {
|
|||||||
Instruction *WideUse = WidenIVUse(NarrowDefUse, NarrowDef, WideDef);
|
Instruction *WideUse = WidenIVUse(NarrowDefUse, NarrowDef, WideDef);
|
||||||
|
|
||||||
// Follow all def-use edges from the previous narrow use.
|
// Follow all def-use edges from the previous narrow use.
|
||||||
if (WideUse) {
|
if (WideUse)
|
||||||
for (Value::use_iterator UI = NarrowDefUse.getUser()->use_begin(),
|
pushNarrowIVUsers(cast<Instruction>(NarrowDefUse.getUser()), WideUse);
|
||||||
UE = NarrowDefUse.getUser()->use_end(); UI != UE; ++UI) {
|
|
||||||
NarrowIVUsers.push_back(std::make_pair(&UI.getUse(), WideUse));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// WidenIVUse may have removed the def-use edge.
|
// WidenIVUse may have removed the def-use edge.
|
||||||
if (NarrowDef->use_empty())
|
if (NarrowDef->use_empty())
|
||||||
DeadInsts.push_back(NarrowDef);
|
DeadInsts.push_back(NarrowDef);
|
||||||
|
@ -246,3 +246,27 @@ exit:
|
|||||||
%result = and i64 %val, %t3
|
%result = and i64 %val, %t3
|
||||||
ret i64 %result
|
ret i64 %result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; The i induction variable looks like a wrap-around, but it really is just
|
||||||
|
; a simple affine IV. Make sure that indvars simplifies through.
|
||||||
|
define i32 @indirectRecurrence() nounwind {
|
||||||
|
entry:
|
||||||
|
br label %loop
|
||||||
|
|
||||||
|
; ReplaceLoopExitValue should fold the return value to constant 9.
|
||||||
|
; CHECK: loop:
|
||||||
|
; CHECK: phi i32
|
||||||
|
; CHECK: ret i32 9
|
||||||
|
loop:
|
||||||
|
%j.0 = phi i32 [ 1, %entry ], [ %j.next, %cond_true ]
|
||||||
|
%i.0 = phi i32 [ 0, %entry ], [ %j.0, %cond_true ]
|
||||||
|
%tmp = icmp ne i32 %j.0, 10
|
||||||
|
br i1 %tmp, label %cond_true, label %return
|
||||||
|
|
||||||
|
cond_true:
|
||||||
|
%j.next = add i32 %j.0, 1
|
||||||
|
br label %loop
|
||||||
|
|
||||||
|
return:
|
||||||
|
ret i32 %i.0
|
||||||
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
; RUN: opt < %s -indvars -S > %t
|
; RUN: opt < %s -indvars -S | FileCheck %s
|
||||||
; RUN: grep sext %t | count 1
|
; RUN: opt < %s -indvars -disable-iv-rewrite -S | FileCheck %s
|
||||||
; RUN: grep phi %t | count 1
|
|
||||||
; RUN: grep {phi i64} %t
|
|
||||||
|
|
||||||
; Indvars should insert a 64-bit induction variable to eliminate the
|
; Indvars should insert a 64-bit induction variable to eliminate the
|
||||||
; sext for the addressing, however it shouldn't eliminate the sext
|
; sext for the addressing, however it shouldn't eliminate the sext
|
||||||
@ -15,6 +13,10 @@ entry:
|
|||||||
bb.nph: ; preds = %entry
|
bb.nph: ; preds = %entry
|
||||||
br label %bb
|
br label %bb
|
||||||
|
|
||||||
|
; CHECK: bb:
|
||||||
|
; CHECK: phi i64
|
||||||
|
; CHECK: sext i8
|
||||||
|
; CHECK-NOT: sext
|
||||||
bb: ; preds = %bb1, %bb.nph
|
bb: ; preds = %bb1, %bb.nph
|
||||||
%i.02 = phi i32 [ %5, %bb1 ], [ 0, %bb.nph ] ; <i32> [#uses=2]
|
%i.02 = phi i32 [ %5, %bb1 ], [ 0, %bb.nph ] ; <i32> [#uses=2]
|
||||||
%p.01 = phi i8 [ %4, %bb1 ], [ -1, %bb.nph ] ; <i8> [#uses=2]
|
%p.01 = phi i8 [ %4, %bb1 ], [ -1, %bb.nph ] ; <i8> [#uses=2]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user