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:
Andrew Trick 2011-07-20 04:39:24 +00:00
parent 71bd0c3263
commit 2210448520
1 changed files with 61 additions and 54 deletions

View File

@ -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;
} }