Expand Up
@@ -19,6 +19,7 @@
#include " llvm/Analysis/CodeMetrics.h"
#include " llvm/Analysis/InstructionSimplify.h"
#include " llvm/Analysis/LoopPass.h"
#include " llvm/Analysis/LoopUnrollAnalyzer.h"
#include " llvm/Analysis/ScalarEvolution.h"
#include " llvm/Analysis/ScalarEvolutionExpressions.h"
#include " llvm/Analysis/TargetTransformInfo.h"
Expand Down
Expand Up
@@ -168,245 +169,6 @@ static TargetTransformInfo::UnrollingPreferences gatherUnrollingPreferences(
return UP;
}
namespace {
// This class is used to get an estimate of the optimization effects that we
// could get from complete loop unrolling. It comes from the fact that some
// loads might be replaced with concrete constant values and that could trigger
// a chain of instruction simplifications.
//
// E.g. we might have:
// int a[] = {0, 1, 0};
// v = 0;
// for (i = 0; i < 3; i ++)
// v += b[i]*a[i];
// If we completely unroll the loop, we would get:
// v = b[0]*a[0] + b[1]*a[1] + b[2]*a[2]
// Which then will be simplified to:
// v = b[0]* 0 + b[1]* 1 + b[2]* 0
// And finally:
// v = b[1]
class UnrolledInstAnalyzer : private InstVisitor <UnrolledInstAnalyzer, bool > {
typedef InstVisitor<UnrolledInstAnalyzer, bool > Base;
friend class InstVisitor <UnrolledInstAnalyzer, bool >;
struct SimplifiedAddress {
Value *Base = nullptr ;
ConstantInt *Offset = nullptr ;
};
public:
UnrolledInstAnalyzer (unsigned Iteration,
DenseMap<Value *, Constant *> &SimplifiedValues,
ScalarEvolution &SE)
: SimplifiedValues(SimplifiedValues), SE(SE) {
IterationNumber = SE.getConstant (APInt (64 , Iteration));
}
// Allow access to the initial visit method.
using Base::visit;
private:
// / \brief A cache of pointer bases and constant-folded offsets corresponding
// / to GEP (or derived from GEP) instructions.
// /
// / In order to find the base pointer one needs to perform non-trivial
// / traversal of the corresponding SCEV expression, so it's good to have the
// / results saved.
DenseMap<Value *, SimplifiedAddress> SimplifiedAddresses;
// / \brief SCEV expression corresponding to number of currently simulated
// / iteration.
const SCEV *IterationNumber;
// / \brief A Value->Constant map for keeping values that we managed to
// / constant-fold on the given iteration.
// /
// / While we walk the loop instructions, we build up and maintain a mapping
// / of simplified values specific to this iteration. The idea is to propagate
// / any special information we have about loads that can be replaced with
// / constants after complete unrolling, and account for likely simplifications
// / post-unrolling.
DenseMap<Value *, Constant *> &SimplifiedValues;
ScalarEvolution &SE;
// / \brief Try to simplify instruction \param I using its SCEV expression.
// /
// / The idea is that some AddRec expressions become constants, which then
// / could trigger folding of other instructions. However, that only happens
// / for expressions whose start value is also constant, which isn't always the
// / case. In another common and important case the start value is just some
// / address (i.e. SCEVUnknown) - in this case we compute the offset and save
// / it along with the base address instead.
bool simplifyInstWithSCEV (Instruction *I) {
if (!SE.isSCEVable (I->getType ()))
return false ;
const SCEV *S = SE.getSCEV (I);
if (auto *SC = dyn_cast<SCEVConstant>(S)) {
SimplifiedValues[I] = SC->getValue ();
return true ;
}
auto *AR = dyn_cast<SCEVAddRecExpr>(S);
if (!AR)
return false ;
const SCEV *ValueAtIteration = AR->evaluateAtIteration (IterationNumber, SE);
// Check if the AddRec expression becomes a constant.
if (auto *SC = dyn_cast<SCEVConstant>(ValueAtIteration)) {
SimplifiedValues[I] = SC->getValue ();
return true ;
}
// Check if the offset from the base address becomes a constant.
auto *Base = dyn_cast<SCEVUnknown>(SE.getPointerBase (S));
if (!Base)
return false ;
auto *Offset =
dyn_cast<SCEVConstant>(SE.getMinusSCEV (ValueAtIteration, Base));
if (!Offset)
return false ;
SimplifiedAddress Address;
Address.Base = Base->getValue ();
Address.Offset = Offset->getValue ();
SimplifiedAddresses[I] = Address;
return true ;
}
// / Base case for the instruction visitor.
bool visitInstruction (Instruction &I) {
return simplifyInstWithSCEV (&I);
}
// / Try to simplify binary operator I.
// /
// / TODO: Probably it's worth to hoist the code for estimating the
// / simplifications effects to a separate class, since we have a very similar
// / code in InlineCost already.
bool visitBinaryOperator (BinaryOperator &I) {
Value *LHS = I.getOperand (0 ), *RHS = I.getOperand (1 );
if (!isa<Constant>(LHS))
if (Constant *SimpleLHS = SimplifiedValues.lookup (LHS))
LHS = SimpleLHS;
if (!isa<Constant>(RHS))
if (Constant *SimpleRHS = SimplifiedValues.lookup (RHS))
RHS = SimpleRHS;
Value *SimpleV = nullptr ;
const DataLayout &DL = I.getModule ()->getDataLayout ();
if (auto FI = dyn_cast<FPMathOperator>(&I))
SimpleV =
SimplifyFPBinOp (I.getOpcode (), LHS, RHS, FI->getFastMathFlags (), DL);
else
SimpleV = SimplifyBinOp (I.getOpcode (), LHS, RHS, DL);
if (Constant *C = dyn_cast_or_null<Constant>(SimpleV))
SimplifiedValues[&I] = C;
if (SimpleV)
return true ;
return Base::visitBinaryOperator (I);
}
// / Try to fold load I.
bool visitLoad (LoadInst &I) {
Value *AddrOp = I.getPointerOperand ();
auto AddressIt = SimplifiedAddresses.find (AddrOp);
if (AddressIt == SimplifiedAddresses.end ())
return false ;
ConstantInt *SimplifiedAddrOp = AddressIt->second .Offset ;
auto *GV = dyn_cast<GlobalVariable>(AddressIt->second .Base );
// We're only interested in loads that can be completely folded to a
// constant.
if (!GV || !GV->hasDefinitiveInitializer () || !GV->isConstant ())
return false ;
ConstantDataSequential *CDS =
dyn_cast<ConstantDataSequential>(GV->getInitializer ());
if (!CDS)
return false ;
// We might have a vector load from an array. FIXME: for now we just bail
// out in this case, but we should be able to resolve and simplify such
// loads.
if (!CDS->isElementTypeCompatible (I.getType ()))
return false ;
int ElemSize = CDS->getElementType ()->getPrimitiveSizeInBits () / 8U ;
assert (SimplifiedAddrOp->getValue ().getActiveBits () < 64 &&
" Unexpectedly large index value." );
int64_t Index = SimplifiedAddrOp->getSExtValue () / ElemSize;
if (Index >= CDS->getNumElements ()) {
// FIXME: For now we conservatively ignore out of bound accesses, but
// we're allowed to perform the optimization in this case.
return false ;
}
Constant *CV = CDS->getElementAsConstant (Index);
assert (CV && " Constant expected." );
SimplifiedValues[&I] = CV;
return true ;
}
bool visitCastInst (CastInst &I) {
// Propagate constants through casts.
Constant *COp = dyn_cast<Constant>(I.getOperand (0 ));
if (!COp)
COp = SimplifiedValues.lookup (I.getOperand (0 ));
if (COp)
if (Constant *C =
ConstantExpr::getCast (I.getOpcode (), COp, I.getType ())) {
SimplifiedValues[&I] = C;
return true ;
}
return Base::visitCastInst (I);
}
bool visitCmpInst (CmpInst &I) {
Value *LHS = I.getOperand (0 ), *RHS = I.getOperand (1 );
// First try to handle simplified comparisons.
if (!isa<Constant>(LHS))
if (Constant *SimpleLHS = SimplifiedValues.lookup (LHS))
LHS = SimpleLHS;
if (!isa<Constant>(RHS))
if (Constant *SimpleRHS = SimplifiedValues.lookup (RHS))
RHS = SimpleRHS;
if (!isa<Constant>(LHS) && !isa<Constant>(RHS)) {
auto SimplifiedLHS = SimplifiedAddresses.find (LHS);
if (SimplifiedLHS != SimplifiedAddresses.end ()) {
auto SimplifiedRHS = SimplifiedAddresses.find (RHS);
if (SimplifiedRHS != SimplifiedAddresses.end ()) {
SimplifiedAddress &LHSAddr = SimplifiedLHS->second ;
SimplifiedAddress &RHSAddr = SimplifiedRHS->second ;
if (LHSAddr.Base == RHSAddr.Base ) {
LHS = LHSAddr.Offset ;
RHS = RHSAddr.Offset ;
}
}
}
}
if (Constant *CLHS = dyn_cast<Constant>(LHS)) {
if (Constant *CRHS = dyn_cast<Constant>(RHS)) {
if (Constant *C = ConstantExpr::getCompare (I.getPredicate (), CLHS, CRHS)) {
SimplifiedValues[&I] = C;
return true ;
}
}
}
return Base::visitCmpInst (I);
}
};
} // namespace
namespace {
struct EstimatedUnrollCost {
// / \brief The estimated cost after unrolling.
Expand Down