Reapply the new LoopStrengthReduction code, with compile time and

bug fixes, and with improved heuristics for analyzing foreign-loop
addrecs.

This change also flattens IVUsers, eliminating the stride-oriented
groupings, which makes it easier to work with.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@95975 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dan Gohman
2010-02-12 10:34:29 +00:00
parent 5cef638855
commit 572645cf84
35 changed files with 3523 additions and 2689 deletions

View File

@@ -36,42 +36,30 @@ Pass *llvm::createIVUsersPass() {
return new IVUsers();
}
/// containsAddRecFromDifferentLoop - Determine whether expression S involves a
/// subexpression that is an AddRec from a loop other than L. An outer loop
/// of L is OK, but not an inner loop nor a disjoint loop.
static bool containsAddRecFromDifferentLoop(const SCEV *S, Loop *L) {
// This is very common, put it first.
if (isa<SCEVConstant>(S))
return false;
if (const SCEVCommutativeExpr *AE = dyn_cast<SCEVCommutativeExpr>(S)) {
for (unsigned int i=0; i< AE->getNumOperands(); i++)
if (containsAddRecFromDifferentLoop(AE->getOperand(i), L))
return true;
return false;
}
if (const SCEVAddRecExpr *AE = dyn_cast<SCEVAddRecExpr>(S)) {
if (const Loop *newLoop = AE->getLoop()) {
if (newLoop == L)
return false;
// if newLoop is an outer loop of L, this is OK.
if (newLoop->contains(L))
return false;
/// CollectSubexprs - Split S into subexpressions which can be pulled out into
/// separate registers.
static void CollectSubexprs(const SCEV *S,
SmallVectorImpl<const SCEV *> &Ops,
ScalarEvolution &SE) {
if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(S)) {
// Break out add operands.
for (SCEVAddExpr::op_iterator I = Add->op_begin(), E = Add->op_end();
I != E; ++I)
CollectSubexprs(*I, Ops, SE);
return;
} else if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S)) {
// Split a non-zero base out of an addrec.
if (!AR->getStart()->isZero()) {
CollectSubexprs(AR->getStart(), Ops, SE);
CollectSubexprs(SE.getAddRecExpr(SE.getIntegerSCEV(0, AR->getType()),
AR->getStepRecurrence(SE),
AR->getLoop()), Ops, SE);
return;
}
return true;
}
if (const SCEVUDivExpr *DE = dyn_cast<SCEVUDivExpr>(S))
return containsAddRecFromDifferentLoop(DE->getLHS(), L) ||
containsAddRecFromDifferentLoop(DE->getRHS(), L);
#if 0
// SCEVSDivExpr has been backed out temporarily, but will be back; we'll
// need this when it is.
if (const SCEVSDivExpr *DE = dyn_cast<SCEVSDivExpr>(S))
return containsAddRecFromDifferentLoop(DE->getLHS(), L) ||
containsAddRecFromDifferentLoop(DE->getRHS(), L);
#endif
if (const SCEVCastExpr *CE = dyn_cast<SCEVCastExpr>(S))
return containsAddRecFromDifferentLoop(CE->getOperand(), L);
return false;
// Otherwise use the value itself.
Ops.push_back(S);
}
/// getSCEVStartAndStride - Compute the start and stride of this expression,
@@ -90,35 +78,42 @@ static bool getSCEVStartAndStride(const SCEV *&SH, Loop *L, Loop *UseLoop,
if (const SCEVAddExpr *AE = dyn_cast<SCEVAddExpr>(SH)) {
for (unsigned i = 0, e = AE->getNumOperands(); i != e; ++i)
if (const SCEVAddRecExpr *AddRec =
dyn_cast<SCEVAddRecExpr>(AE->getOperand(i))) {
if (AddRec->getLoop() == L)
TheAddRec = SE->getAddExpr(AddRec, TheAddRec);
else
return false; // Nested IV of some sort?
} else {
dyn_cast<SCEVAddRecExpr>(AE->getOperand(i)))
TheAddRec = SE->getAddExpr(AddRec, TheAddRec);
else
Start = SE->getAddExpr(Start, AE->getOperand(i));
}
} else if (isa<SCEVAddRecExpr>(SH)) {
TheAddRec = SH;
} else {
return false; // not analyzable.
}
const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(TheAddRec);
if (!AddRec || AddRec->getLoop() != L) return false;
// Break down TheAddRec into its component parts.
SmallVector<const SCEV *, 4> Subexprs;
CollectSubexprs(TheAddRec, Subexprs, *SE);
// Look for an addrec on the current loop among the parts.
const SCEV *AddRecStride = 0;
for (SmallVectorImpl<const SCEV *>::iterator I = Subexprs.begin(),
E = Subexprs.end(); I != E; ++I) {
const SCEV *S = *I;
if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S))
if (AR->getLoop() == L) {
*I = AR->getStart();
AddRecStride = AR->getStepRecurrence(*SE);
break;
}
}
if (!AddRecStride)
return false;
// Add up everything else into a start value (which may not be
// loop-invariant).
const SCEV *AddRecStart = SE->getAddExpr(Subexprs);
// Use getSCEVAtScope to attempt to simplify other loops out of
// the picture.
const SCEV *AddRecStart = AddRec->getStart();
AddRecStart = SE->getSCEVAtScope(AddRecStart, UseLoop);
const SCEV *AddRecStride = AddRec->getStepRecurrence(*SE);
// FIXME: If Start contains an SCEVAddRecExpr from a different loop, other
// than an outer loop of the current loop, reject it. LSR has no concept of
// operating on more than one loop at a time so don't confuse it with such
// expressions.
if (containsAddRecFromDifferentLoop(AddRecStart, L))
return false;
Start = SE->getAddExpr(Start, AddRecStart);
@@ -131,7 +126,7 @@ static bool getSCEVStartAndStride(const SCEV *&SH, Loop *L, Loop *UseLoop,
DEBUG(dbgs() << "[";
WriteAsOperand(dbgs(), L->getHeader(), /*PrintType=*/false);
dbgs() << "] Variable stride: " << *AddRec << "\n");
dbgs() << "] Variable stride: " << *AddRecStride << "\n");
}
Stride = AddRecStride;
@@ -247,14 +242,6 @@ bool IVUsers::AddUsersIfInteresting(Instruction *I) {
}
if (AddUserToIVUsers) {
IVUsersOfOneStride *StrideUses = IVUsesByStride[Stride];
if (!StrideUses) { // First occurrence of this stride?
StrideOrder.push_back(Stride);
StrideUses = new IVUsersOfOneStride(Stride);
IVUses.push_back(StrideUses);
IVUsesByStride[Stride] = StrideUses;
}
// Okay, we found a user that we cannot reduce. Analyze the instruction
// and decide what to do with it. If we are a use inside of the loop, use
// the value before incrementation, otherwise use it after incrementation.
@@ -262,27 +249,21 @@ bool IVUsers::AddUsersIfInteresting(Instruction *I) {
// The value used will be incremented by the stride more than we are
// expecting, so subtract this off.
const SCEV *NewStart = SE->getMinusSCEV(Start, Stride);
StrideUses->addUser(NewStart, User, I);
StrideUses->Users.back().setIsUseOfPostIncrementedValue(true);
IVUses.push_back(new IVStrideUse(this, Stride, NewStart, User, I));
IVUses.back().setIsUseOfPostIncrementedValue(true);
DEBUG(dbgs() << " USING POSTINC SCEV, START=" << *NewStart<< "\n");
} else {
StrideUses->addUser(Start, User, I);
IVUses.push_back(new IVStrideUse(this, Stride, Start, User, I));
}
}
}
return true;
}
void IVUsers::AddUser(const SCEV *Stride, const SCEV *Offset,
Instruction *User, Value *Operand) {
IVUsersOfOneStride *StrideUses = IVUsesByStride[Stride];
if (!StrideUses) { // First occurrence of this stride?
StrideOrder.push_back(Stride);
StrideUses = new IVUsersOfOneStride(Stride);
IVUses.push_back(StrideUses);
IVUsesByStride[Stride] = StrideUses;
}
IVUsesByStride[Stride]->addUser(Offset, User, Operand);
IVStrideUse &IVUsers::AddUser(const SCEV *Stride, const SCEV *Offset,
Instruction *User, Value *Operand) {
IVUses.push_back(new IVStrideUse(this, Stride, Offset, User, Operand));
return IVUses.back();
}
IVUsers::IVUsers()
@@ -316,15 +297,15 @@ bool IVUsers::runOnLoop(Loop *l, LPPassManager &LPM) {
/// value of the OperandValToReplace of the given IVStrideUse.
const SCEV *IVUsers::getReplacementExpr(const IVStrideUse &U) const {
// Start with zero.
const SCEV *RetVal = SE->getIntegerSCEV(0, U.getParent()->Stride->getType());
const SCEV *RetVal = SE->getIntegerSCEV(0, U.getStride()->getType());
// Create the basic add recurrence.
RetVal = SE->getAddRecExpr(RetVal, U.getParent()->Stride, L);
RetVal = SE->getAddRecExpr(RetVal, U.getStride(), L);
// Add the offset in a separate step, because it may be loop-variant.
RetVal = SE->getAddExpr(RetVal, U.getOffset());
// For uses of post-incremented values, add an extra stride to compute
// the actual replacement value.
if (U.isUseOfPostIncrementedValue())
RetVal = SE->getAddExpr(RetVal, U.getParent()->Stride);
RetVal = SE->getAddExpr(RetVal, U.getStride());
return RetVal;
}
@@ -333,9 +314,9 @@ const SCEV *IVUsers::getReplacementExpr(const IVStrideUse &U) const {
/// isUseOfPostIncrementedValue flag.
const SCEV *IVUsers::getCanonicalExpr(const IVStrideUse &U) const {
// Start with zero.
const SCEV *RetVal = SE->getIntegerSCEV(0, U.getParent()->Stride->getType());
const SCEV *RetVal = SE->getIntegerSCEV(0, U.getStride()->getType());
// Create the basic add recurrence.
RetVal = SE->getAddRecExpr(RetVal, U.getParent()->Stride, L);
RetVal = SE->getAddRecExpr(RetVal, U.getStride(), L);
// Add the offset in a separate step, because it may be loop-variant.
RetVal = SE->getAddExpr(RetVal, U.getOffset());
return RetVal;
@@ -358,24 +339,17 @@ void IVUsers::print(raw_ostream &OS, const Module *M) const {
OS << ":\n";
IVUsersAsmAnnotator Annotator;
for (unsigned Stride = 0, e = StrideOrder.size(); Stride != e; ++Stride) {
std::map<const SCEV *, IVUsersOfOneStride*>::const_iterator SI =
IVUsesByStride.find(StrideOrder[Stride]);
assert(SI != IVUsesByStride.end() && "Stride doesn't exist!");
OS << " Stride " << *SI->first->getType() << " " << *SI->first << ":\n";
for (ilist<IVStrideUse>::const_iterator UI = SI->second->Users.begin(),
E = SI->second->Users.end(); UI != E; ++UI) {
OS << " ";
WriteAsOperand(OS, UI->getOperandValToReplace(), false);
OS << " = ";
OS << *getReplacementExpr(*UI);
if (UI->isUseOfPostIncrementedValue())
OS << " (post-inc)";
OS << " in ";
UI->getUser()->print(OS, &Annotator);
OS << '\n';
}
for (ilist<IVStrideUse>::const_iterator UI = IVUses.begin(),
E = IVUses.end(); UI != E; ++UI) {
OS << " ";
WriteAsOperand(OS, UI->getOperandValToReplace(), false);
OS << " = "
<< *getReplacementExpr(*UI);
if (UI->isUseOfPostIncrementedValue())
OS << " (post-inc)";
OS << " in ";
UI->getUser()->print(OS, &Annotator);
OS << '\n';
}
}
@@ -384,37 +358,12 @@ void IVUsers::dump() const {
}
void IVUsers::releaseMemory() {
IVUsesByStride.clear();
StrideOrder.clear();
Processed.clear();
IVUses.clear();
}
void IVStrideUse::deleted() {
// Remove this user from the list.
Parent->Users.erase(this);
Parent->IVUses.erase(this);
// this now dangles!
}
void IVUsersOfOneStride::print(raw_ostream &OS) const {
OS << "IV Users of one stride:\n";
if (Stride)
OS << " Stride: " << *Stride << '\n';
OS << " Users:\n";
unsigned Count = 1;
for (ilist<IVStrideUse>::const_iterator
I = Users.begin(), E = Users.end(); I != E; ++I) {
const IVStrideUse &SU = *I;
OS << " " << Count++ << '\n';
OS << " Offset: " << *SU.getOffset() << '\n';
OS << " Instr: " << *SU << '\n';
}
}
void IVUsersOfOneStride::dump() const {
print(dbgs());
}