mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
This nutty patch has been in my tree since before 1.3 went out, and it needs
to go in. This patch allows us to compute the trip count of loops controlled by values loaded from constant arrays. The cannonnical example of this is strlen when passed a constant argument: for (int i = 0; "constantstring"[i]; ++i) ; return i; In this case, it will compute that the loop executes 14 times, which means that the exit value of i is 14. Because of this, the loop gets DCE'd and we are happy. This also applies to anything that does similar things, e.g. loops like this: const float Array[] = { 0.1, 2.1, 3.2, 23.21 }; for (int i = 0; Array[i] < 20; ++i) and is actually fairly general. The problem with this is that it almost never triggers. The reason is that we run indvars and the loop optimizer only at compile time, which is before things like strlen and strcpy have been inlined into the program from libc. Because of this, it almost never is used (it triggers twice in specint2k). I'm committing it because it DOES work, may be useful in the future, and doesn't slow us down at all. If/when we start running the loop optimizer at link-time (-O4?) this will be very nice indeed :) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16926 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
989cbd58fb
commit
673e02b0c3
@ -62,9 +62,8 @@
|
|||||||
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
||||||
#include "llvm/Constants.h"
|
#include "llvm/Constants.h"
|
||||||
#include "llvm/DerivedTypes.h"
|
#include "llvm/DerivedTypes.h"
|
||||||
|
#include "llvm/GlobalVariable.h"
|
||||||
#include "llvm/Instructions.h"
|
#include "llvm/Instructions.h"
|
||||||
#include "llvm/Type.h"
|
|
||||||
#include "llvm/Value.h"
|
|
||||||
#include "llvm/Analysis/LoopInfo.h"
|
#include "llvm/Analysis/LoopInfo.h"
|
||||||
#include "llvm/Assembly/Writer.h"
|
#include "llvm/Assembly/Writer.h"
|
||||||
#include "llvm/Transforms/Scalar.h"
|
#include "llvm/Transforms/Scalar.h"
|
||||||
@ -84,7 +83,11 @@ namespace {
|
|||||||
|
|
||||||
Statistic<>
|
Statistic<>
|
||||||
NumBruteForceEvaluations("scalar-evolution",
|
NumBruteForceEvaluations("scalar-evolution",
|
||||||
"Number of brute force evaluations needed to calculate high-order polynomial exit values");
|
"Number of brute force evaluations needed to "
|
||||||
|
"calculate high-order polynomial exit values");
|
||||||
|
Statistic<>
|
||||||
|
NumArrayLenItCounts("scalar-evolution",
|
||||||
|
"Number of trip counts computed with array length");
|
||||||
Statistic<>
|
Statistic<>
|
||||||
NumTripCountsComputed("scalar-evolution",
|
NumTripCountsComputed("scalar-evolution",
|
||||||
"Number of loops with predictable loop counts");
|
"Number of loops with predictable loop counts");
|
||||||
@ -1090,6 +1093,13 @@ namespace {
|
|||||||
/// will iterate.
|
/// will iterate.
|
||||||
SCEVHandle ComputeIterationCount(const Loop *L);
|
SCEVHandle ComputeIterationCount(const Loop *L);
|
||||||
|
|
||||||
|
/// ComputeLoadConstantCompareIterationCount - Given an exit condition of
|
||||||
|
/// 'setcc load X, cst', try to se if we can compute the trip count.
|
||||||
|
SCEVHandle ComputeLoadConstantCompareIterationCount(LoadInst *LI,
|
||||||
|
Constant *RHS,
|
||||||
|
const Loop *L,
|
||||||
|
unsigned SetCCOpcode);
|
||||||
|
|
||||||
/// ComputeIterationCountExhaustively - If the trip is known to execute a
|
/// ComputeIterationCountExhaustively - If the trip is known to execute a
|
||||||
/// constant number of times (the condition evolves only from constants),
|
/// constant number of times (the condition evolves only from constants),
|
||||||
/// try to evaluate a few iterations of the loop until we get the exit
|
/// try to evaluate a few iterations of the loop until we get the exit
|
||||||
@ -1387,6 +1397,21 @@ SCEVHandle ScalarEvolutionsImpl::ComputeIterationCount(const Loop *L) {
|
|||||||
return ComputeIterationCountExhaustively(L, ExitBr->getCondition(),
|
return ComputeIterationCountExhaustively(L, ExitBr->getCondition(),
|
||||||
ExitBr->getSuccessor(0) == ExitBlock);
|
ExitBr->getSuccessor(0) == ExitBlock);
|
||||||
|
|
||||||
|
// If the condition was exit on true, convert the condition to exit on false.
|
||||||
|
Instruction::BinaryOps Cond;
|
||||||
|
if (ExitBr->getSuccessor(1) == ExitBlock)
|
||||||
|
Cond = ExitCond->getOpcode();
|
||||||
|
else
|
||||||
|
Cond = ExitCond->getInverseCondition();
|
||||||
|
|
||||||
|
// Handle common loops like: for (X = "string"; *X; ++X)
|
||||||
|
if (LoadInst *LI = dyn_cast<LoadInst>(ExitCond->getOperand(0)))
|
||||||
|
if (Constant *RHS = dyn_cast<Constant>(ExitCond->getOperand(1))) {
|
||||||
|
SCEVHandle ItCnt =
|
||||||
|
ComputeLoadConstantCompareIterationCount(LI, RHS, L, Cond);
|
||||||
|
if (!isa<SCEVCouldNotCompute>(ItCnt)) return ItCnt;
|
||||||
|
}
|
||||||
|
|
||||||
SCEVHandle LHS = getSCEV(ExitCond->getOperand(0));
|
SCEVHandle LHS = getSCEV(ExitCond->getOperand(0));
|
||||||
SCEVHandle RHS = getSCEV(ExitCond->getOperand(1));
|
SCEVHandle RHS = getSCEV(ExitCond->getOperand(1));
|
||||||
|
|
||||||
@ -1396,13 +1421,6 @@ SCEVHandle ScalarEvolutionsImpl::ComputeIterationCount(const Loop *L) {
|
|||||||
Tmp = getSCEVAtScope(RHS, L);
|
Tmp = getSCEVAtScope(RHS, L);
|
||||||
if (!isa<SCEVCouldNotCompute>(Tmp)) RHS = Tmp;
|
if (!isa<SCEVCouldNotCompute>(Tmp)) RHS = Tmp;
|
||||||
|
|
||||||
// If the condition was exit on true, convert the condition to exit on false.
|
|
||||||
Instruction::BinaryOps Cond;
|
|
||||||
if (ExitBr->getSuccessor(1) == ExitBlock)
|
|
||||||
Cond = ExitCond->getOpcode();
|
|
||||||
else
|
|
||||||
Cond = ExitCond->getInverseCondition();
|
|
||||||
|
|
||||||
// At this point, we would like to compute how many iterations of the loop the
|
// At this point, we would like to compute how many iterations of the loop the
|
||||||
// predicate will return true for these inputs.
|
// predicate will return true for these inputs.
|
||||||
if (isa<SCEVConstant>(LHS) && !isa<SCEVConstant>(RHS)) {
|
if (isa<SCEVConstant>(LHS) && !isa<SCEVConstant>(RHS)) {
|
||||||
@ -1473,6 +1491,125 @@ SCEVHandle ScalarEvolutionsImpl::ComputeIterationCount(const Loop *L) {
|
|||||||
ExitBr->getSuccessor(0) == ExitBlock);
|
ExitBr->getSuccessor(0) == ExitBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ConstantInt *
|
||||||
|
EvaluateConstantChrecAtConstant(const SCEVAddRecExpr *AddRec, Constant *C) {
|
||||||
|
SCEVHandle InVal = SCEVConstant::get(cast<ConstantInt>(C));
|
||||||
|
SCEVHandle Val = AddRec->evaluateAtIteration(InVal);
|
||||||
|
assert(isa<SCEVConstant>(Val) &&
|
||||||
|
"Evaluation of SCEV at constant didn't fold correctly?");
|
||||||
|
return cast<SCEVConstant>(Val)->getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// GetAddressedElementFromGlobal - Given a global variable with an initializer
|
||||||
|
/// and a GEP expression (missing the pointer index) indexing into it, return
|
||||||
|
/// the addressed element of the initializer or null if the index expression is
|
||||||
|
/// invalid.
|
||||||
|
static Constant *
|
||||||
|
GetAddressedElementFromGlobal(GlobalVariable *GV,
|
||||||
|
const std::vector<ConstantInt*> &Indices) {
|
||||||
|
Constant *Init = GV->getInitializer();
|
||||||
|
for (unsigned i = 0, e = Indices.size(); i != e; ++i) {
|
||||||
|
uint64_t Idx = Indices[i]->getRawValue();
|
||||||
|
if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Init)) {
|
||||||
|
assert(Idx < CS->getNumOperands() && "Bad struct index!");
|
||||||
|
Init = cast<Constant>(CS->getOperand(Idx));
|
||||||
|
} else if (ConstantArray *CA = dyn_cast<ConstantArray>(Init)) {
|
||||||
|
if (Idx >= CA->getNumOperands()) return 0; // Bogus program
|
||||||
|
Init = cast<Constant>(CA->getOperand(Idx));
|
||||||
|
} else if (isa<ConstantAggregateZero>(Init)) {
|
||||||
|
if (const StructType *STy = dyn_cast<StructType>(Init->getType())) {
|
||||||
|
assert(Idx < STy->getNumElements() && "Bad struct index!");
|
||||||
|
Init = Constant::getNullValue(STy->getElementType(Idx));
|
||||||
|
} else if (const ArrayType *ATy = dyn_cast<ArrayType>(Init->getType())) {
|
||||||
|
if (Idx >= ATy->getNumElements()) return 0; // Bogus program
|
||||||
|
Init = Constant::getNullValue(ATy->getElementType());
|
||||||
|
} else {
|
||||||
|
assert(0 && "Unknown constant aggregate type!");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 0; // Unknown initializer type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Init;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ComputeLoadConstantCompareIterationCount - Given an exit condition of
|
||||||
|
/// 'setcc load X, cst', try to se if we can compute the trip count.
|
||||||
|
SCEVHandle ScalarEvolutionsImpl::
|
||||||
|
ComputeLoadConstantCompareIterationCount(LoadInst *LI, Constant *RHS,
|
||||||
|
const Loop *L, unsigned SetCCOpcode) {
|
||||||
|
if (LI->isVolatile()) return UnknownValue;
|
||||||
|
|
||||||
|
// Check to see if the loaded pointer is a getelementptr of a global.
|
||||||
|
GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(LI->getOperand(0));
|
||||||
|
if (!GEP) return UnknownValue;
|
||||||
|
|
||||||
|
// Make sure that it is really a constant global we are gepping, with an
|
||||||
|
// initializer, and make sure the first IDX is really 0.
|
||||||
|
GlobalVariable *GV = dyn_cast<GlobalVariable>(GEP->getOperand(0));
|
||||||
|
if (!GV || !GV->isConstant() || !GV->hasInitializer() ||
|
||||||
|
GEP->getNumOperands() < 3 || !isa<Constant>(GEP->getOperand(1)) ||
|
||||||
|
!cast<Constant>(GEP->getOperand(1))->isNullValue())
|
||||||
|
return UnknownValue;
|
||||||
|
|
||||||
|
// Okay, we allow one non-constant index into the GEP instruction.
|
||||||
|
Value *VarIdx = 0;
|
||||||
|
std::vector<ConstantInt*> Indexes;
|
||||||
|
unsigned VarIdxNum = 0;
|
||||||
|
for (unsigned i = 2, e = GEP->getNumOperands(); i != e; ++i)
|
||||||
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(GEP->getOperand(i))) {
|
||||||
|
Indexes.push_back(CI);
|
||||||
|
} else if (!isa<ConstantInt>(GEP->getOperand(i))) {
|
||||||
|
if (VarIdx) return UnknownValue; // Multiple non-constant idx's.
|
||||||
|
VarIdx = GEP->getOperand(i);
|
||||||
|
VarIdxNum = i-2;
|
||||||
|
Indexes.push_back(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, we know we have a (load (gep GV, 0, X)) comparison with a constant.
|
||||||
|
// Check to see if X is a loop variant variable value now.
|
||||||
|
SCEVHandle Idx = getSCEV(VarIdx);
|
||||||
|
SCEVHandle Tmp = getSCEVAtScope(Idx, L);
|
||||||
|
if (!isa<SCEVCouldNotCompute>(Tmp)) Idx = Tmp;
|
||||||
|
|
||||||
|
// We can only recognize very limited forms of loop index expressions, in
|
||||||
|
// particular, only affine AddRec's like {C1,+,C2}.
|
||||||
|
SCEVAddRecExpr *IdxExpr = dyn_cast<SCEVAddRecExpr>(Idx);
|
||||||
|
if (!IdxExpr || !IdxExpr->isAffine() || IdxExpr->isLoopInvariant(L) ||
|
||||||
|
!isa<SCEVConstant>(IdxExpr->getOperand(0)) ||
|
||||||
|
!isa<SCEVConstant>(IdxExpr->getOperand(1)))
|
||||||
|
return UnknownValue;
|
||||||
|
|
||||||
|
unsigned MaxSteps = MaxBruteForceIterations;
|
||||||
|
for (unsigned IterationNum = 0; IterationNum != MaxSteps; ++IterationNum) {
|
||||||
|
ConstantUInt *ItCst =
|
||||||
|
ConstantUInt::get(IdxExpr->getType()->getUnsignedVersion(), IterationNum);
|
||||||
|
ConstantInt *Val = EvaluateConstantChrecAtConstant(IdxExpr, ItCst);
|
||||||
|
|
||||||
|
// Form the GEP offset.
|
||||||
|
Indexes[VarIdxNum] = Val;
|
||||||
|
|
||||||
|
Constant *Result = GetAddressedElementFromGlobal(GV, Indexes);
|
||||||
|
if (Result == 0) break; // Cannot compute!
|
||||||
|
|
||||||
|
// Evaluate the condition for this iteration.
|
||||||
|
Result = ConstantExpr::get(SetCCOpcode, Result, RHS);
|
||||||
|
if (!isa<ConstantBool>(Result)) break; // Couldn't decide for sure
|
||||||
|
if (Result == ConstantBool::False) {
|
||||||
|
#if 0
|
||||||
|
std::cerr << "\n***\n*** Computed loop count " << *ItCst
|
||||||
|
<< "\n*** From global " << *GV << "*** BB: " << *L->getHeader()
|
||||||
|
<< "***\n";
|
||||||
|
#endif
|
||||||
|
++NumArrayLenItCounts;
|
||||||
|
return SCEVConstant::get(ItCst); // Found terminating iteration!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UnknownValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// CanConstantFold - Return true if we can constant fold an instruction of the
|
/// CanConstantFold - Return true if we can constant fold an instruction of the
|
||||||
/// specified type, assuming that all operands were constants.
|
/// specified type, assuming that all operands were constants.
|
||||||
static bool CanConstantFold(const Instruction *I) {
|
static bool CanConstantFold(const Instruction *I) {
|
||||||
@ -1978,16 +2115,6 @@ SCEVHandle ScalarEvolutionsImpl::HowFarToNonZero(SCEV *V, const Loop *L) {
|
|||||||
return UnknownValue;
|
return UnknownValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstantInt *
|
|
||||||
EvaluateConstantChrecAtConstant(const SCEVAddRecExpr *AddRec, Constant *C) {
|
|
||||||
SCEVHandle InVal = SCEVConstant::get(cast<ConstantInt>(C));
|
|
||||||
SCEVHandle Val = AddRec->evaluateAtIteration(InVal);
|
|
||||||
assert(isa<SCEVConstant>(Val) &&
|
|
||||||
"Evaluation of SCEV at constant didn't fold correctly?");
|
|
||||||
return cast<SCEVConstant>(Val)->getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// getNumIterationsInRange - Return the number of iterations of this loop that
|
/// getNumIterationsInRange - Return the number of iterations of this loop that
|
||||||
/// produce values in the specified constant range. Another way of looking at
|
/// produce values in the specified constant range. Another way of looking at
|
||||||
/// this is that it returns the first iteration number where the value is not in
|
/// this is that it returns the first iteration number where the value is not in
|
||||||
|
Loading…
Reference in New Issue
Block a user