forked from OSchip/llvm-project
indvars -disable-iv-rewrite: Add NarrowIVDefUse to cache def-use
info. Holding Use* pointers is bad form even though it happened to work in this case. llvm-svn: 135566
This commit is contained in:
parent
71bd0c3263
commit
2210448520
|
@ -784,6 +784,21 @@ static void CollectExtend(CastInst *Cast, bool IsSigned, WideIVInfo &WI,
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
/// NarrowIVDefUse - Record a link in the Narrow IV def-use chain along with the
|
||||||
|
/// WideIV that computes the same value as the Narrow IV def. This avoids
|
||||||
|
/// caching Use* pointers.
|
||||||
|
struct NarrowIVDefUse {
|
||||||
|
Instruction *NarrowDef;
|
||||||
|
Instruction *NarrowUse;
|
||||||
|
Instruction *WideDef;
|
||||||
|
|
||||||
|
NarrowIVDefUse(): NarrowDef(0), NarrowUse(0), WideDef(0) {}
|
||||||
|
|
||||||
|
NarrowIVDefUse(Instruction *ND, Instruction *NU, Instruction *WD):
|
||||||
|
NarrowDef(ND), NarrowUse(NU), WideDef(WD) {}
|
||||||
|
};
|
||||||
|
|
||||||
/// WidenIV - The goal of this transform is to remove sign and zero extends
|
/// WidenIV - The goal of this transform is to remove sign and zero extends
|
||||||
/// without creating any new induction variables. To do this, it creates a new
|
/// without creating any new induction variables. To do this, it creates a new
|
||||||
/// phi of the wider type and redirects all users, either removing extends or
|
/// phi of the wider type and redirects all users, either removing extends or
|
||||||
|
@ -808,7 +823,7 @@ class WidenIV {
|
||||||
SmallVectorImpl<WeakVH> &DeadInsts;
|
SmallVectorImpl<WeakVH> &DeadInsts;
|
||||||
|
|
||||||
SmallPtrSet<Instruction*,16> Widened;
|
SmallPtrSet<Instruction*,16> Widened;
|
||||||
SmallVector<std::pair<Use *, Instruction *>, 8> NarrowIVUsers;
|
SmallVector<NarrowIVDefUse, 8> NarrowIVUsers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WidenIV(PHINode *PN, const WideIVInfo &WI, LoopInfo *LInfo,
|
WidenIV(PHINode *PN, const WideIVInfo &WI, LoopInfo *LInfo,
|
||||||
|
@ -831,14 +846,11 @@ public:
|
||||||
PHINode *CreateWideIV(SCEVExpander &Rewriter);
|
PHINode *CreateWideIV(SCEVExpander &Rewriter);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Instruction *CloneIVUser(Instruction *NarrowUse,
|
Instruction *CloneIVUser(NarrowIVDefUse DU);
|
||||||
Instruction *NarrowDef,
|
|
||||||
Instruction *WideDef);
|
|
||||||
|
|
||||||
const SCEVAddRecExpr *GetWideRecurrence(Instruction *NarrowUse);
|
const SCEVAddRecExpr *GetWideRecurrence(Instruction *NarrowUse);
|
||||||
|
|
||||||
Instruction *WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
Instruction *WidenIVUse(NarrowIVDefUse DU);
|
||||||
Instruction *WideDef);
|
|
||||||
|
|
||||||
void pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef);
|
void pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef);
|
||||||
};
|
};
|
||||||
|
@ -853,10 +865,8 @@ static Value *getExtend( Value *NarrowOper, Type *WideType,
|
||||||
/// CloneIVUser - Instantiate a wide operation to replace a narrow
|
/// CloneIVUser - Instantiate a wide operation to replace a narrow
|
||||||
/// operation. This only needs to handle operations that can evaluation to
|
/// operation. This only needs to handle operations that can evaluation to
|
||||||
/// SCEVAddRec. It can safely return 0 for any operation we decide not to clone.
|
/// SCEVAddRec. It can safely return 0 for any operation we decide not to clone.
|
||||||
Instruction *WidenIV::CloneIVUser(Instruction *NarrowUse,
|
Instruction *WidenIV::CloneIVUser(NarrowIVDefUse DU) {
|
||||||
Instruction *NarrowDef,
|
unsigned Opcode = DU.NarrowUse->getOpcode();
|
||||||
Instruction *WideDef) {
|
|
||||||
unsigned Opcode = NarrowUse->getOpcode();
|
|
||||||
switch (Opcode) {
|
switch (Opcode) {
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -870,21 +880,21 @@ Instruction *WidenIV::CloneIVUser(Instruction *NarrowUse,
|
||||||
case Instruction::Shl:
|
case Instruction::Shl:
|
||||||
case Instruction::LShr:
|
case Instruction::LShr:
|
||||||
case Instruction::AShr:
|
case Instruction::AShr:
|
||||||
DEBUG(dbgs() << "Cloning IVUser: " << *NarrowUse << "\n");
|
DEBUG(dbgs() << "Cloning IVUser: " << *DU.NarrowUse << "\n");
|
||||||
|
|
||||||
IRBuilder<> Builder(NarrowUse);
|
IRBuilder<> Builder(DU.NarrowUse);
|
||||||
|
|
||||||
// Replace NarrowDef operands with WideDef. Otherwise, we don't know
|
// Replace NarrowDef operands with WideDef. Otherwise, we don't know
|
||||||
// anything about the narrow operand yet so must insert a [sz]ext. It is
|
// anything about the narrow operand yet so must insert a [sz]ext. It is
|
||||||
// probably loop invariant and will be folded or hoisted. If it actually
|
// probably loop invariant and will be folded or hoisted. If it actually
|
||||||
// comes from a widened IV, it should be removed during a future call to
|
// comes from a widened IV, it should be removed during a future call to
|
||||||
// WidenIVUse.
|
// WidenIVUse.
|
||||||
Value *LHS = (NarrowUse->getOperand(0) == NarrowDef) ? WideDef :
|
Value *LHS = (DU.NarrowUse->getOperand(0) == DU.NarrowDef) ? DU.WideDef :
|
||||||
getExtend(NarrowUse->getOperand(0), WideType, IsSigned, Builder);
|
getExtend(DU.NarrowUse->getOperand(0), WideType, IsSigned, Builder);
|
||||||
Value *RHS = (NarrowUse->getOperand(1) == NarrowDef) ? WideDef :
|
Value *RHS = (DU.NarrowUse->getOperand(1) == DU.NarrowDef) ? DU.WideDef :
|
||||||
getExtend(NarrowUse->getOperand(1), WideType, IsSigned, Builder);
|
getExtend(DU.NarrowUse->getOperand(1), WideType, IsSigned, Builder);
|
||||||
|
|
||||||
BinaryOperator *NarrowBO = cast<BinaryOperator>(NarrowUse);
|
BinaryOperator *NarrowBO = cast<BinaryOperator>(DU.NarrowUse);
|
||||||
BinaryOperator *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(),
|
BinaryOperator *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(),
|
||||||
LHS, RHS,
|
LHS, RHS,
|
||||||
NarrowBO->getName());
|
NarrowBO->getName());
|
||||||
|
@ -962,41 +972,40 @@ const SCEVAddRecExpr *WidenIV::GetWideRecurrence(Instruction *NarrowUse) {
|
||||||
|
|
||||||
/// WidenIVUse - Determine whether an individual user of the narrow IV can be
|
/// WidenIVUse - Determine whether an individual user of the narrow IV can be
|
||||||
/// widened. If so, return the wide clone of the user.
|
/// widened. If so, return the wide clone of the user.
|
||||||
Instruction *WidenIV::WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
Instruction *WidenIV::WidenIVUse(NarrowIVDefUse DU) {
|
||||||
Instruction *WideDef) {
|
|
||||||
Instruction *NarrowUse = cast<Instruction>(NarrowDefUse.getUser());
|
|
||||||
|
|
||||||
// Stop traversing the def-use chain at inner-loop phis or post-loop phis.
|
// Stop traversing the def-use chain at inner-loop phis or post-loop phis.
|
||||||
if (isa<PHINode>(NarrowUse) && LI->getLoopFor(NarrowUse->getParent()) != L)
|
if (isa<PHINode>(DU.NarrowUse) &&
|
||||||
|
LI->getLoopFor(DU.NarrowUse->getParent()) != L)
|
||||||
return 0;
|
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>(DU.NarrowUse) : isa<ZExtInst>(DU.NarrowUse)) {
|
||||||
Value *NewDef = WideDef;
|
Value *NewDef = DU.WideDef;
|
||||||
if (NarrowUse->getType() != WideType) {
|
if (DU.NarrowUse->getType() != WideType) {
|
||||||
unsigned CastWidth = SE->getTypeSizeInBits(NarrowUse->getType());
|
unsigned CastWidth = SE->getTypeSizeInBits(DU.NarrowUse->getType());
|
||||||
unsigned IVWidth = SE->getTypeSizeInBits(WideType);
|
unsigned IVWidth = SE->getTypeSizeInBits(WideType);
|
||||||
if (CastWidth < IVWidth) {
|
if (CastWidth < IVWidth) {
|
||||||
// The cast isn't as wide as the IV, so insert a Trunc.
|
// The cast isn't as wide as the IV, so insert a Trunc.
|
||||||
IRBuilder<> Builder(NarrowDefUse);
|
IRBuilder<> Builder(DU.NarrowUse);
|
||||||
NewDef = Builder.CreateTrunc(WideDef, NarrowUse->getType());
|
NewDef = Builder.CreateTrunc(DU.WideDef, DU.NarrowUse->getType());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// A wider extend was hidden behind a narrower one. This may induce
|
// A wider extend was hidden behind a narrower one. This may induce
|
||||||
// another round of IV widening in which the intermediate IV becomes
|
// another round of IV widening in which the intermediate IV becomes
|
||||||
// dead. It should be very rare.
|
// dead. It should be very rare.
|
||||||
DEBUG(dbgs() << "INDVARS: New IV " << *WidePhi
|
DEBUG(dbgs() << "INDVARS: New IV " << *WidePhi
|
||||||
<< " not wide enough to subsume " << *NarrowUse << "\n");
|
<< " not wide enough to subsume " << *DU.NarrowUse << "\n");
|
||||||
NarrowUse->replaceUsesOfWith(NarrowDef, WideDef);
|
DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, DU.WideDef);
|
||||||
NewDef = NarrowUse;
|
NewDef = DU.NarrowUse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (NewDef != NarrowUse) {
|
if (NewDef != DU.NarrowUse) {
|
||||||
DEBUG(dbgs() << "INDVARS: eliminating " << *NarrowUse
|
DEBUG(dbgs() << "INDVARS: eliminating " << *DU.NarrowUse
|
||||||
<< " replaced by " << *WideDef << "\n");
|
<< " replaced by " << *DU.WideDef << "\n");
|
||||||
++NumElimExt;
|
++NumElimExt;
|
||||||
NarrowUse->replaceAllUsesWith(NewDef);
|
DU.NarrowUse->replaceAllUsesWith(NewDef);
|
||||||
DeadInsts.push_back(NarrowUse);
|
DeadInsts.push_back(DU.NarrowUse);
|
||||||
}
|
}
|
||||||
// Now that the extend is gone, we want to expose it's uses for potential
|
// Now that the extend is gone, we want to expose it's uses for potential
|
||||||
// further simplification. We don't need to directly inform SimplifyIVUsers
|
// further simplification. We don't need to directly inform SimplifyIVUsers
|
||||||
|
@ -1009,29 +1018,31 @@ Instruction *WidenIV::WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does this user itself evaluate to a recurrence after widening?
|
// Does this user itself evaluate to a recurrence after widening?
|
||||||
const SCEVAddRecExpr *WideAddRec = GetWideRecurrence(NarrowUse);
|
const SCEVAddRecExpr *WideAddRec = GetWideRecurrence(DU.NarrowUse);
|
||||||
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,
|
||||||
// eventually isolating the original narrow IV so it can be removed.
|
// eventually isolating the original narrow IV so it can be removed.
|
||||||
IRBuilder<> Builder(NarrowDefUse);
|
Use *U = std::find(DU.NarrowUse->op_begin(), DU.NarrowUse->op_end(),
|
||||||
Value *Trunc = Builder.CreateTrunc(WideDef, NarrowDef->getType());
|
DU.NarrowDef);
|
||||||
NarrowUse->replaceUsesOfWith(NarrowDef, Trunc);
|
IRBuilder<> Builder(*U);
|
||||||
|
Value *Trunc = Builder.CreateTrunc(DU.WideDef, DU.NarrowDef->getType());
|
||||||
|
DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, Trunc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Assume block terminators cannot evaluate to a recurrence. We can't to
|
// Assume block terminators cannot evaluate to a recurrence. We can't to
|
||||||
// insert a Trunc after a terminator if there happens to be a critical edge.
|
// insert a Trunc after a terminator if there happens to be a critical edge.
|
||||||
assert(NarrowUse != NarrowUse->getParent()->getTerminator() &&
|
assert(DU.NarrowUse != DU.NarrowUse->getParent()->getTerminator() &&
|
||||||
"SCEV is not expected to evaluate a block terminator");
|
"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.
|
||||||
Instruction *WideUse = 0;
|
Instruction *WideUse = 0;
|
||||||
if (WideAddRec == WideIncExpr && HoistStep(WideInc, NarrowUse, DT)) {
|
if (WideAddRec == WideIncExpr && HoistStep(WideInc, DU.NarrowUse, DT)) {
|
||||||
WideUse = WideInc;
|
WideUse = WideInc;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
WideUse = CloneIVUser(NarrowUse, NarrowDef, WideDef);
|
WideUse = CloneIVUser(DU);
|
||||||
if (!WideUse)
|
if (!WideUse)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1056,13 +1067,13 @@ Instruction *WidenIV::WidenIVUse(Use &NarrowDefUse, Instruction *NarrowDef,
|
||||||
void WidenIV::pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef) {
|
void WidenIV::pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef) {
|
||||||
for (Value::use_iterator UI = NarrowDef->use_begin(),
|
for (Value::use_iterator UI = NarrowDef->use_begin(),
|
||||||
UE = NarrowDef->use_end(); UI != UE; ++UI) {
|
UE = NarrowDef->use_end(); UI != UE; ++UI) {
|
||||||
Use &U = UI.getUse();
|
Instruction *NarrowUse = cast<Instruction>(*UI);
|
||||||
|
|
||||||
// Handle data flow merges and bizarre phi cycles.
|
// Handle data flow merges and bizarre phi cycles.
|
||||||
if (!Widened.insert(cast<Instruction>(U.getUser())))
|
if (!Widened.insert(NarrowUse))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
NarrowIVUsers.push_back(std::make_pair(&UI.getUse(), WideDef));
|
NarrowIVUsers.push_back(NarrowIVDefUse(NarrowDef, NarrowUse, WideDef));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1129,23 +1140,19 @@ PHINode *WidenIV::CreateWideIV(SCEVExpander &Rewriter) {
|
||||||
pushNarrowIVUsers(OrigPhi, WidePhi);
|
pushNarrowIVUsers(OrigPhi, WidePhi);
|
||||||
|
|
||||||
while (!NarrowIVUsers.empty()) {
|
while (!NarrowIVUsers.empty()) {
|
||||||
Use *UsePtr;
|
NarrowIVDefUse DU = NarrowIVUsers.pop_back_val();
|
||||||
Instruction *WideDef;
|
|
||||||
tie(UsePtr, WideDef) = NarrowIVUsers.pop_back_val();
|
|
||||||
Use &NarrowDefUse = *UsePtr;
|
|
||||||
|
|
||||||
// Process a def-use edge. This may replace the use, so don't hold a
|
// Process a def-use edge. This may replace the use, so don't hold a
|
||||||
// use_iterator across it.
|
// use_iterator across it.
|
||||||
Instruction *NarrowDef = cast<Instruction>(NarrowDefUse.get());
|
Instruction *WideUse = WidenIVUse(DU);
|
||||||
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)
|
||||||
pushNarrowIVUsers(cast<Instruction>(NarrowDefUse.getUser()), WideUse);
|
pushNarrowIVUsers(DU.NarrowUse, WideUse);
|
||||||
|
|
||||||
// WidenIVUse may have removed the def-use edge.
|
// WidenIVUse may have removed the def-use edge.
|
||||||
if (NarrowDef->use_empty())
|
if (DU.NarrowDef->use_empty())
|
||||||
DeadInsts.push_back(NarrowDef);
|
DeadInsts.push_back(DU.NarrowDef);
|
||||||
}
|
}
|
||||||
return WidePhi;
|
return WidePhi;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue