diff --git a/include/llvm/Analysis/InductionVariable.h b/include/llvm/Analysis/InductionVariable.h index 36dcaebda00e..0282eb02db74 100644 --- a/include/llvm/Analysis/InductionVariable.h +++ b/include/llvm/Analysis/InductionVariable.h @@ -34,7 +34,7 @@ class InductionVariable { Unknown, // Unknown type. Start & Step are null } InductionType; - Value *Start, *Step; // Start and step expressions for this indvar + Value *Start, *Step, *End; // Start, step, and end expressions for this indvar PHINode *Phi; // The PHI node that corresponds to this indvar public: @@ -47,6 +47,9 @@ class InductionVariable { static enum iType Classify(const Value *Start, const Value *Step, const Loop *L = 0); + // Get number of times this loop will execute. Returns NULL if unpredictable. + Value* getExecutionCount(LoopInfo *LoopInfo); + void print(std::ostream &OS) const; }; diff --git a/lib/Analysis/InductionVariable.cpp b/lib/Analysis/InductionVariable.cpp index ec6461ccdcb7..6aaf8c018e14 100644 --- a/lib/Analysis/InductionVariable.cpp +++ b/lib/Analysis/InductionVariable.cpp @@ -19,11 +19,15 @@ #include "llvm/Analysis/InductionVariable.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/Expressions.h" +#include "llvm/BasicBlock.h" #include "llvm/iPHINode.h" -#include "llvm/InstrTypes.h" +#include "llvm/iOperators.h" +#include "llvm/iTerminators.h" #include "llvm/Type.h" #include "llvm/Constants.h" +#include "llvm/Support/CFG.h" #include "llvm/Assembly/Writer.h" +#include "Support/Statistic.h" static bool isLoopInvariant(const Value *V, const Loop *L) { if (isa(V) || isa(V) || isa(V)) @@ -37,14 +41,14 @@ static bool isLoopInvariant(const Value *V, const Loop *L) { enum InductionVariable::iType InductionVariable::Classify(const Value *Start, const Value *Step, - const Loop *L) { + const Loop *L) { // Check for cannonical and simple linear expressions now... if (const ConstantInt *CStart = dyn_cast(Start)) if (const ConstantInt *CStep = dyn_cast(Step)) { if (CStart->equalsInt(0) && CStep->equalsInt(1)) - return Cannonical; + return Cannonical; else - return SimpleLinear; + return SimpleLinear; } // Without loop information, we cannot do any better, so bail now... @@ -58,7 +62,7 @@ InductionVariable::Classify(const Value *Start, const Value *Step, // Create an induction variable for the specified value. If it is a PHI, and // if it's recognizable, classify it and fill in instance variables. // -InductionVariable::InductionVariable(PHINode *P, LoopInfo *LoopInfo) { +InductionVariable::InductionVariable(PHINode *P, LoopInfo *LoopInfo): End(0) { InductionType = Unknown; // Assume the worst Phi = P; @@ -92,7 +96,7 @@ InductionVariable::InductionVariable(PHINode *P, LoopInfo *LoopInfo) { // with respect to the PHI node. // if (E1.ExprTy > ExprType::Constant || E2.ExprTy != ExprType::Linear || - E2.Var != Phi) + E2.Var != Phi) return; // Okay, we have found an induction variable. Save the start and step values @@ -117,17 +121,17 @@ InductionVariable::InductionVariable(PHINode *P, LoopInfo *LoopInfo) { } else if (BinaryOperator *I = dyn_cast(V2)) { // TODO: This could be much better... if (I->getOpcode() == Instruction::Add) { - if (I->getOperand(0) == Phi) - Step = I->getOperand(1); - else if (I->getOperand(1) == Phi) - Step = I->getOperand(0); + if (I->getOperand(0) == Phi) + Step = I->getOperand(1); + else if (I->getOperand(1) == Phi) + Step = I->getOperand(0); } } if (Step == 0) { // Unrecognized step value... ExprType StepE = ClassifyExpression(V2); if (StepE.ExprTy != ExprType::Linear || - StepE.Var != Phi) return; + StepE.Var != Phi) return; const Type *ETy = Phi->getType(); if (isa(ETy)) ETy = Type::ULongTy; @@ -153,6 +157,125 @@ InductionVariable::InductionVariable(PHINode *P, LoopInfo *LoopInfo) { InductionType = InductionVariable::Classify(Start, Step, L); } + +Value* InductionVariable::getExecutionCount(LoopInfo *LoopInfo) { + DEBUG(std::cerr << "entering getExecutionCount\n"); + + // Don't recompute if already available + if (End) { + DEBUG(std::cerr << "returning cached End value.\n"); + return End; + } + + const Loop *L = LoopInfo ? LoopInfo->getLoopFor(Phi->getParent()) : 0; + if (!L) { + DEBUG(std::cerr << "null loop. oops\n"); + return NULL; + } + + // >1 backedge => cannot predict number of iterations + if (Phi->getNumIncomingValues() != 2) { + DEBUG(std::cerr << ">2 incoming values. oops\n"); + return NULL; + } + + // Find final node: predecesor of the loop header that's also an exit + BasicBlock *terminator; + BasicBlock *header = L->getHeader(); + for (pred_iterator PI = pred_begin(header), PE = pred_end(header); + PI != PE; ++PI) { + if (L->isLoopExit(*PI)) { + terminator = *PI; + break; + } + } + + // Break in the loop => cannot predict number of iterations + // break: any block which is an exit node whose successor is not in loop, + // and this block is not marked as the terminator + // + const std::vector &blocks = L->getBlocks(); + for (std::vector::const_iterator i = blocks.begin(), e = blocks.end(); + i != e; ++i) { + if (L->isLoopExit(*i) && (*i != terminator)) { + for (succ_iterator SI = succ_begin(*i), SE = succ_end(*i); SI != SE; ++SI) { + if (! L->contains(*SI)) { + DEBUG(std::cerr << "break found in loop"); + return NULL; + } + } + } + } + + BranchInst *B = dyn_cast(terminator->getTerminator()); + if (!B) { + // this really should not happen + DEBUG(std::cerr << "no terminator instruction!"); + return NULL; + } + SetCondInst *SCI = dyn_cast(&*B->getCondition()); + + if (SCI && InductionType == Cannonical) { + DEBUG(std::cerr << "sci:" << *SCI); + Value *condVal0 = SCI->getOperand(0); + Value *condVal1 = SCI->getOperand(1); + Value *indVar = 0; + + // the induction variable is the one coming from the backedge + if (L->contains(Phi->getIncomingBlock(0))) { + indVar = Phi->getIncomingValue(0); + } else { + indVar = Phi->getIncomingValue(1); + } + + // check to see if indVar is one of the parameters in SCI + // and if the other is loop-invariant, it is the UB + if (indVar == condVal0) { + if (isLoopInvariant(condVal1, L)) { + End = condVal1; + } else { + DEBUG(std::cerr << "not loop invariant 1\n"); + } + } else if (indVar == condVal1) { + if (isLoopInvariant(condVal0, L)) { + End = condVal0; + } else { + DEBUG(std::cerr << "not loop invariant 0\n"); + } + } + + if (End) { + switch (SCI->getOpcode()) { + case Instruction::SetLT: + case Instruction::SetNE: break; // already done + case Instruction::SetLE: { + // if compared to a constant int N, then predict N+1 iterations + if (ConstantSInt *ubSigned = dyn_cast(End)) { + End = ConstantSInt::get(ubSigned->getType(), ubSigned->getValue()+1); + DEBUG(std::cerr << "signed int constant\n"); + } else if (ConstantUInt *ubUnsigned = dyn_cast(End)) { + End = ConstantUInt::get(ubUnsigned->getType(), ubUnsigned->getValue()+1); + DEBUG(std::cerr << "unsigned int constant\n"); + } else { + DEBUG(std::cerr << "symbolic bound\n"); + //End = NULL; + // new expression N+1 + End = BinaryOperator::create(Instruction::Add, End, + ConstantUInt::get(ubUnsigned->getType(), 1)); + } + break; + } + default: End = NULL; // cannot predict + } + } + return End; + } else { + DEBUG(std::cerr << "SCI null or non-cannonical ind var\n"); + } + return NULL; +} + + void InductionVariable::print(std::ostream &o) const { switch (InductionType) { case InductionVariable::Cannonical: o << "Cannonical "; break; @@ -171,5 +294,8 @@ void InductionVariable::print(std::ostream &o) const { o << " Start = "; WriteAsOperand(o, Start); o << " Step = " ; WriteAsOperand(o, Step); + if (End) { + o << " End = " ; WriteAsOperand(o, End); + } o << "\n"; }