DependenceAnalysis.cpp [plain text]
#include "llvm/Analysis/DependenceAnalysis.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "da"
STATISTIC(TotalArrayPairs, "Array pairs tested");
STATISTIC(SeparableSubscriptPairs, "Separable subscript pairs");
STATISTIC(CoupledSubscriptPairs, "Coupled subscript pairs");
STATISTIC(NonlinearSubscriptPairs, "Nonlinear subscript pairs");
STATISTIC(ZIVapplications, "ZIV applications");
STATISTIC(ZIVindependence, "ZIV independence");
STATISTIC(StrongSIVapplications, "Strong SIV applications");
STATISTIC(StrongSIVsuccesses, "Strong SIV successes");
STATISTIC(StrongSIVindependence, "Strong SIV independence");
STATISTIC(WeakCrossingSIVapplications, "Weak-Crossing SIV applications");
STATISTIC(WeakCrossingSIVsuccesses, "Weak-Crossing SIV successes");
STATISTIC(WeakCrossingSIVindependence, "Weak-Crossing SIV independence");
STATISTIC(ExactSIVapplications, "Exact SIV applications");
STATISTIC(ExactSIVsuccesses, "Exact SIV successes");
STATISTIC(ExactSIVindependence, "Exact SIV independence");
STATISTIC(WeakZeroSIVapplications, "Weak-Zero SIV applications");
STATISTIC(WeakZeroSIVsuccesses, "Weak-Zero SIV successes");
STATISTIC(WeakZeroSIVindependence, "Weak-Zero SIV independence");
STATISTIC(ExactRDIVapplications, "Exact RDIV applications");
STATISTIC(ExactRDIVindependence, "Exact RDIV independence");
STATISTIC(SymbolicRDIVapplications, "Symbolic RDIV applications");
STATISTIC(SymbolicRDIVindependence, "Symbolic RDIV independence");
STATISTIC(DeltaApplications, "Delta applications");
STATISTIC(DeltaSuccesses, "Delta successes");
STATISTIC(DeltaIndependence, "Delta independence");
STATISTIC(DeltaPropagations, "Delta propagations");
STATISTIC(GCDapplications, "GCD applications");
STATISTIC(GCDsuccesses, "GCD successes");
STATISTIC(GCDindependence, "GCD independence");
STATISTIC(BanerjeeApplications, "Banerjee applications");
STATISTIC(BanerjeeIndependence, "Banerjee independence");
STATISTIC(BanerjeeSuccesses, "Banerjee successes");
static cl::opt<bool>
Delinearize("da-delinearize", cl::init(false), cl::Hidden, cl::ZeroOrMore,
cl::desc("Try to delinearize array references."));
INITIALIZE_PASS_BEGIN(DependenceAnalysis, "da",
"Dependence Analysis", true, true)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_END(DependenceAnalysis, "da",
"Dependence Analysis", true, true)
char DependenceAnalysis::ID = 0;
FunctionPass *llvm::createDependenceAnalysisPass() {
return new DependenceAnalysis();
}
bool DependenceAnalysis::runOnFunction(Function &F) {
this->F = &F;
AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
return false;
}
void DependenceAnalysis::releaseMemory() {
}
void DependenceAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequiredTransitive<AAResultsWrapperPass>();
AU.addRequiredTransitive<ScalarEvolutionWrapperPass>();
AU.addRequiredTransitive<LoopInfoWrapperPass>();
}
static
void dumpExampleDependence(raw_ostream &OS, Function *F,
DependenceAnalysis *DA) {
for (inst_iterator SrcI = inst_begin(F), SrcE = inst_end(F);
SrcI != SrcE; ++SrcI) {
if (isa<StoreInst>(*SrcI) || isa<LoadInst>(*SrcI)) {
for (inst_iterator DstI = SrcI, DstE = inst_end(F);
DstI != DstE; ++DstI) {
if (isa<StoreInst>(*DstI) || isa<LoadInst>(*DstI)) {
OS << "da analyze - ";
if (auto D = DA->depends(&*SrcI, &*DstI, true)) {
D->dump(OS);
for (unsigned Level = 1; Level <= D->getLevels(); Level++) {
if (D->isSplitable(Level)) {
OS << "da analyze - split level = " << Level;
OS << ", iteration = " << *DA->getSplitIteration(*D, Level);
OS << "!\n";
}
}
}
else
OS << "none!\n";
}
}
}
}
}
void DependenceAnalysis::print(raw_ostream &OS, const Module*) const {
dumpExampleDependence(OS, F, const_cast<DependenceAnalysis *>(this));
}
bool Dependence::isInput() const {
return Src->mayReadFromMemory() && Dst->mayReadFromMemory();
}
bool Dependence::isOutput() const {
return Src->mayWriteToMemory() && Dst->mayWriteToMemory();
}
bool Dependence::isFlow() const {
return Src->mayWriteToMemory() && Dst->mayReadFromMemory();
}
bool Dependence::isAnti() const {
return Src->mayReadFromMemory() && Dst->mayWriteToMemory();
}
bool Dependence::isScalar(unsigned level) const {
return false;
}
FullDependence::FullDependence(Instruction *Source, Instruction *Destination,
bool PossiblyLoopIndependent,
unsigned CommonLevels)
: Dependence(Source, Destination), Levels(CommonLevels),
LoopIndependent(PossiblyLoopIndependent) {
Consistent = true;
if (CommonLevels)
DV = make_unique<DVEntry[]>(CommonLevels);
}
unsigned FullDependence::getDirection(unsigned Level) const {
assert(0 < Level && Level <= Levels && "Level out of range");
return DV[Level - 1].Direction;
}
const SCEV *FullDependence::getDistance(unsigned Level) const {
assert(0 < Level && Level <= Levels && "Level out of range");
return DV[Level - 1].Distance;
}
bool FullDependence::isScalar(unsigned Level) const {
assert(0 < Level && Level <= Levels && "Level out of range");
return DV[Level - 1].Scalar;
}
bool FullDependence::isPeelFirst(unsigned Level) const {
assert(0 < Level && Level <= Levels && "Level out of range");
return DV[Level - 1].PeelFirst;
}
bool FullDependence::isPeelLast(unsigned Level) const {
assert(0 < Level && Level <= Levels && "Level out of range");
return DV[Level - 1].PeelLast;
}
bool FullDependence::isSplitable(unsigned Level) const {
assert(0 < Level && Level <= Levels && "Level out of range");
return DV[Level - 1].Splitable;
}
const SCEV *DependenceAnalysis::Constraint::getX() const {
assert(Kind == Point && "Kind should be Point");
return A;
}
const SCEV *DependenceAnalysis::Constraint::getY() const {
assert(Kind == Point && "Kind should be Point");
return B;
}
const SCEV *DependenceAnalysis::Constraint::getA() const {
assert((Kind == Line || Kind == Distance) &&
"Kind should be Line (or Distance)");
return A;
}
const SCEV *DependenceAnalysis::Constraint::getB() const {
assert((Kind == Line || Kind == Distance) &&
"Kind should be Line (or Distance)");
return B;
}
const SCEV *DependenceAnalysis::Constraint::getC() const {
assert((Kind == Line || Kind == Distance) &&
"Kind should be Line (or Distance)");
return C;
}
const SCEV *DependenceAnalysis::Constraint::getD() const {
assert(Kind == Distance && "Kind should be Distance");
return SE->getNegativeSCEV(C);
}
const Loop *DependenceAnalysis::Constraint::getAssociatedLoop() const {
assert((Kind == Distance || Kind == Line || Kind == Point) &&
"Kind should be Distance, Line, or Point");
return AssociatedLoop;
}
void DependenceAnalysis::Constraint::setPoint(const SCEV *X,
const SCEV *Y,
const Loop *CurLoop) {
Kind = Point;
A = X;
B = Y;
AssociatedLoop = CurLoop;
}
void DependenceAnalysis::Constraint::setLine(const SCEV *AA,
const SCEV *BB,
const SCEV *CC,
const Loop *CurLoop) {
Kind = Line;
A = AA;
B = BB;
C = CC;
AssociatedLoop = CurLoop;
}
void DependenceAnalysis::Constraint::setDistance(const SCEV *D,
const Loop *CurLoop) {
Kind = Distance;
A = SE->getOne(D->getType());
B = SE->getNegativeSCEV(A);
C = SE->getNegativeSCEV(D);
AssociatedLoop = CurLoop;
}
void DependenceAnalysis::Constraint::setEmpty() {
Kind = Empty;
}
void DependenceAnalysis::Constraint::setAny(ScalarEvolution *NewSE) {
SE = NewSE;
Kind = Any;
}
void DependenceAnalysis::Constraint::dump(raw_ostream &OS) const {
if (isEmpty())
OS << " Empty\n";
else if (isAny())
OS << " Any\n";
else if (isPoint())
OS << " Point is <" << *getX() << ", " << *getY() << ">\n";
else if (isDistance())
OS << " Distance is " << *getD() <<
" (" << *getA() << "*X + " << *getB() << "*Y = " << *getC() << ")\n";
else if (isLine())
OS << " Line is " << *getA() << "*X + " <<
*getB() << "*Y = " << *getC() << "\n";
else
llvm_unreachable("unknown constraint type in Constraint::dump");
}
bool DependenceAnalysis::intersectConstraints(Constraint *X,
const Constraint *Y) {
++DeltaApplications;
DEBUG(dbgs() << "\tintersect constraints\n");
DEBUG(dbgs() << "\t X ="; X->dump(dbgs()));
DEBUG(dbgs() << "\t Y ="; Y->dump(dbgs()));
assert(!Y->isPoint() && "Y must not be a Point");
if (X->isAny()) {
if (Y->isAny())
return false;
*X = *Y;
return true;
}
if (X->isEmpty())
return false;
if (Y->isEmpty()) {
X->setEmpty();
return true;
}
if (X->isDistance() && Y->isDistance()) {
DEBUG(dbgs() << "\t intersect 2 distances\n");
if (isKnownPredicate(CmpInst::ICMP_EQ, X->getD(), Y->getD()))
return false;
if (isKnownPredicate(CmpInst::ICMP_NE, X->getD(), Y->getD())) {
X->setEmpty();
++DeltaSuccesses;
return true;
}
if (isa<SCEVConstant>(Y->getD())) {
*X = *Y;
return true;
}
return false;
}
assert(!(X->isPoint() && Y->isPoint()) &&
"We shouldn't ever see X->isPoint() && Y->isPoint()");
if (X->isLine() && Y->isLine()) {
DEBUG(dbgs() << "\t intersect 2 lines\n");
const SCEV *Prod1 = SE->getMulExpr(X->getA(), Y->getB());
const SCEV *Prod2 = SE->getMulExpr(X->getB(), Y->getA());
if (isKnownPredicate(CmpInst::ICMP_EQ, Prod1, Prod2)) {
DEBUG(dbgs() << "\t\tsame slope\n");
Prod1 = SE->getMulExpr(X->getC(), Y->getB());
Prod2 = SE->getMulExpr(X->getB(), Y->getC());
if (isKnownPredicate(CmpInst::ICMP_EQ, Prod1, Prod2))
return false;
if (isKnownPredicate(CmpInst::ICMP_NE, Prod1, Prod2)) {
X->setEmpty();
++DeltaSuccesses;
return true;
}
return false;
}
if (isKnownPredicate(CmpInst::ICMP_NE, Prod1, Prod2)) {
DEBUG(dbgs() << "\t\tdifferent slopes\n");
const SCEV *C1B2 = SE->getMulExpr(X->getC(), Y->getB());
const SCEV *C1A2 = SE->getMulExpr(X->getC(), Y->getA());
const SCEV *C2B1 = SE->getMulExpr(Y->getC(), X->getB());
const SCEV *C2A1 = SE->getMulExpr(Y->getC(), X->getA());
const SCEV *A1B2 = SE->getMulExpr(X->getA(), Y->getB());
const SCEV *A2B1 = SE->getMulExpr(Y->getA(), X->getB());
const SCEVConstant *C1A2_C2A1 =
dyn_cast<SCEVConstant>(SE->getMinusSCEV(C1A2, C2A1));
const SCEVConstant *C1B2_C2B1 =
dyn_cast<SCEVConstant>(SE->getMinusSCEV(C1B2, C2B1));
const SCEVConstant *A1B2_A2B1 =
dyn_cast<SCEVConstant>(SE->getMinusSCEV(A1B2, A2B1));
const SCEVConstant *A2B1_A1B2 =
dyn_cast<SCEVConstant>(SE->getMinusSCEV(A2B1, A1B2));
if (!C1B2_C2B1 || !C1A2_C2A1 ||
!A1B2_A2B1 || !A2B1_A1B2)
return false;
APInt Xtop = C1B2_C2B1->getValue()->getValue();
APInt Xbot = A1B2_A2B1->getValue()->getValue();
APInt Ytop = C1A2_C2A1->getValue()->getValue();
APInt Ybot = A2B1_A1B2->getValue()->getValue();
DEBUG(dbgs() << "\t\tXtop = " << Xtop << "\n");
DEBUG(dbgs() << "\t\tXbot = " << Xbot << "\n");
DEBUG(dbgs() << "\t\tYtop = " << Ytop << "\n");
DEBUG(dbgs() << "\t\tYbot = " << Ybot << "\n");
APInt Xq = Xtop; APInt Xr = Xtop; APInt::sdivrem(Xtop, Xbot, Xq, Xr);
APInt Yq = Ytop;
APInt Yr = Ytop;
APInt::sdivrem(Ytop, Ybot, Yq, Yr);
if (Xr != 0 || Yr != 0) {
X->setEmpty();
++DeltaSuccesses;
return true;
}
DEBUG(dbgs() << "\t\tX = " << Xq << ", Y = " << Yq << "\n");
if (Xq.slt(0) || Yq.slt(0)) {
X->setEmpty();
++DeltaSuccesses;
return true;
}
if (const SCEVConstant *CUB =
collectConstantUpperBound(X->getAssociatedLoop(), Prod1->getType())) {
APInt UpperBound = CUB->getValue()->getValue();
DEBUG(dbgs() << "\t\tupper bound = " << UpperBound << "\n");
if (Xq.sgt(UpperBound) || Yq.sgt(UpperBound)) {
X->setEmpty();
++DeltaSuccesses;
return true;
}
}
X->setPoint(SE->getConstant(Xq),
SE->getConstant(Yq),
X->getAssociatedLoop());
++DeltaSuccesses;
return true;
}
return false;
}
assert(!(X->isLine() && Y->isPoint()) && "This case should never occur");
if (X->isPoint() && Y->isLine()) {
DEBUG(dbgs() << "\t intersect Point and Line\n");
const SCEV *A1X1 = SE->getMulExpr(Y->getA(), X->getX());
const SCEV *B1Y1 = SE->getMulExpr(Y->getB(), X->getY());
const SCEV *Sum = SE->getAddExpr(A1X1, B1Y1);
if (isKnownPredicate(CmpInst::ICMP_EQ, Sum, Y->getC()))
return false;
if (isKnownPredicate(CmpInst::ICMP_NE, Sum, Y->getC())) {
X->setEmpty();
++DeltaSuccesses;
return true;
}
return false;
}
llvm_unreachable("shouldn't reach the end of Constraint intersection");
return false;
}
void Dependence::dump(raw_ostream &OS) const {
bool Splitable = false;
if (isConfused())
OS << "confused";
else {
if (isConsistent())
OS << "consistent ";
if (isFlow())
OS << "flow";
else if (isOutput())
OS << "output";
else if (isAnti())
OS << "anti";
else if (isInput())
OS << "input";
unsigned Levels = getLevels();
OS << " [";
for (unsigned II = 1; II <= Levels; ++II) {
if (isSplitable(II))
Splitable = true;
if (isPeelFirst(II))
OS << 'p';
const SCEV *Distance = getDistance(II);
if (Distance)
OS << *Distance;
else if (isScalar(II))
OS << "S";
else {
unsigned Direction = getDirection(II);
if (Direction == DVEntry::ALL)
OS << "*";
else {
if (Direction & DVEntry::LT)
OS << "<";
if (Direction & DVEntry::EQ)
OS << "=";
if (Direction & DVEntry::GT)
OS << ">";
}
}
if (isPeelLast(II))
OS << 'p';
if (II < Levels)
OS << " ";
}
if (isLoopIndependent())
OS << "|<";
OS << "]";
if (Splitable)
OS << " splitable";
}
OS << "!\n";
}
static AliasResult underlyingObjectsAlias(AliasAnalysis *AA,
const DataLayout &DL, const Value *A,
const Value *B) {
const Value *AObj = GetUnderlyingObject(A, DL);
const Value *BObj = GetUnderlyingObject(B, DL);
return AA->alias(AObj, DL.getTypeStoreSize(AObj->getType()),
BObj, DL.getTypeStoreSize(BObj->getType()));
}
static
bool isLoadOrStore(const Instruction *I) {
if (const LoadInst *LI = dyn_cast<LoadInst>(I))
return LI->isUnordered();
else if (const StoreInst *SI = dyn_cast<StoreInst>(I))
return SI->isUnordered();
return false;
}
static
Value *getPointerOperand(Instruction *I) {
if (LoadInst *LI = dyn_cast<LoadInst>(I))
return LI->getPointerOperand();
if (StoreInst *SI = dyn_cast<StoreInst>(I))
return SI->getPointerOperand();
llvm_unreachable("Value is not load or store instruction");
return nullptr;
}
void DependenceAnalysis::establishNestingLevels(const Instruction *Src,
const Instruction *Dst) {
const BasicBlock *SrcBlock = Src->getParent();
const BasicBlock *DstBlock = Dst->getParent();
unsigned SrcLevel = LI->getLoopDepth(SrcBlock);
unsigned DstLevel = LI->getLoopDepth(DstBlock);
const Loop *SrcLoop = LI->getLoopFor(SrcBlock);
const Loop *DstLoop = LI->getLoopFor(DstBlock);
SrcLevels = SrcLevel;
MaxLevels = SrcLevel + DstLevel;
while (SrcLevel > DstLevel) {
SrcLoop = SrcLoop->getParentLoop();
SrcLevel--;
}
while (DstLevel > SrcLevel) {
DstLoop = DstLoop->getParentLoop();
DstLevel--;
}
while (SrcLoop != DstLoop) {
SrcLoop = SrcLoop->getParentLoop();
DstLoop = DstLoop->getParentLoop();
SrcLevel--;
}
CommonLevels = SrcLevel;
MaxLevels -= CommonLevels;
}
unsigned DependenceAnalysis::mapSrcLoop(const Loop *SrcLoop) const {
return SrcLoop->getLoopDepth();
}
unsigned DependenceAnalysis::mapDstLoop(const Loop *DstLoop) const {
unsigned D = DstLoop->getLoopDepth();
if (D > CommonLevels)
return D - CommonLevels + SrcLevels;
else
return D;
}
bool DependenceAnalysis::isLoopInvariant(const SCEV *Expression,
const Loop *LoopNest) const {
if (!LoopNest)
return true;
return SE->isLoopInvariant(Expression, LoopNest) &&
isLoopInvariant(Expression, LoopNest->getParentLoop());
}
void DependenceAnalysis::collectCommonLoops(const SCEV *Expression,
const Loop *LoopNest,
SmallBitVector &Loops) const {
while (LoopNest) {
unsigned Level = LoopNest->getLoopDepth();
if (Level <= CommonLevels && !SE->isLoopInvariant(Expression, LoopNest))
Loops.set(Level);
LoopNest = LoopNest->getParentLoop();
}
}
void DependenceAnalysis::unifySubscriptType(ArrayRef<Subscript *> Pairs) {
unsigned widestWidthSeen = 0;
Type *widestType;
for (unsigned i = 0; i < Pairs.size(); i++) {
const SCEV *Src = Pairs[i]->Src;
const SCEV *Dst = Pairs[i]->Dst;
IntegerType *SrcTy = dyn_cast<IntegerType>(Src->getType());
IntegerType *DstTy = dyn_cast<IntegerType>(Dst->getType());
if (SrcTy == nullptr || DstTy == nullptr) {
assert(SrcTy == DstTy && "This function only unify integer types and "
"expect Src and Dst share the same type "
"otherwise.");
continue;
}
if (SrcTy->getBitWidth() > widestWidthSeen) {
widestWidthSeen = SrcTy->getBitWidth();
widestType = SrcTy;
}
if (DstTy->getBitWidth() > widestWidthSeen) {
widestWidthSeen = DstTy->getBitWidth();
widestType = DstTy;
}
}
assert(widestWidthSeen > 0);
for (unsigned i = 0; i < Pairs.size(); i++) {
const SCEV *Src = Pairs[i]->Src;
const SCEV *Dst = Pairs[i]->Dst;
IntegerType *SrcTy = dyn_cast<IntegerType>(Src->getType());
IntegerType *DstTy = dyn_cast<IntegerType>(Dst->getType());
if (SrcTy == nullptr || DstTy == nullptr) {
assert(SrcTy == DstTy && "This function only unify integer types and "
"expect Src and Dst share the same type "
"otherwise.");
continue;
}
if (SrcTy->getBitWidth() < widestWidthSeen)
Pairs[i]->Src = SE->getSignExtendExpr(Src, widestType);
if (DstTy->getBitWidth() < widestWidthSeen) {
Pairs[i]->Dst = SE->getSignExtendExpr(Dst, widestType);
}
}
}
void DependenceAnalysis::removeMatchingExtensions(Subscript *Pair) {
const SCEV *Src = Pair->Src;
const SCEV *Dst = Pair->Dst;
if ((isa<SCEVZeroExtendExpr>(Src) && isa<SCEVZeroExtendExpr>(Dst)) ||
(isa<SCEVSignExtendExpr>(Src) && isa<SCEVSignExtendExpr>(Dst))) {
const SCEVCastExpr *SrcCast = cast<SCEVCastExpr>(Src);
const SCEVCastExpr *DstCast = cast<SCEVCastExpr>(Dst);
const SCEV *SrcCastOp = SrcCast->getOperand();
const SCEV *DstCastOp = DstCast->getOperand();
if (SrcCastOp->getType() == DstCastOp->getType()) {
Pair->Src = SrcCastOp;
Pair->Dst = DstCastOp;
}
}
}
bool DependenceAnalysis::checkSrcSubscript(const SCEV *Src,
const Loop *LoopNest,
SmallBitVector &Loops) {
const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Src);
if (!AddRec)
return isLoopInvariant(Src, LoopNest);
const SCEV *Start = AddRec->getStart();
const SCEV *Step = AddRec->getStepRecurrence(*SE);
const SCEV *UB = SE->getBackedgeTakenCount(AddRec->getLoop());
if (!isa<SCEVCouldNotCompute>(UB)) {
if (SE->getTypeSizeInBits(Start->getType()) <
SE->getTypeSizeInBits(UB->getType())) {
if (!AddRec->getNoWrapFlags())
return false;
}
}
if (!isLoopInvariant(Step, LoopNest))
return false;
Loops.set(mapSrcLoop(AddRec->getLoop()));
return checkSrcSubscript(Start, LoopNest, Loops);
}
bool DependenceAnalysis::checkDstSubscript(const SCEV *Dst,
const Loop *LoopNest,
SmallBitVector &Loops) {
const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Dst);
if (!AddRec)
return isLoopInvariant(Dst, LoopNest);
const SCEV *Start = AddRec->getStart();
const SCEV *Step = AddRec->getStepRecurrence(*SE);
const SCEV *UB = SE->getBackedgeTakenCount(AddRec->getLoop());
if (!isa<SCEVCouldNotCompute>(UB)) {
if (SE->getTypeSizeInBits(Start->getType()) <
SE->getTypeSizeInBits(UB->getType())) {
if (!AddRec->getNoWrapFlags())
return false;
}
}
if (!isLoopInvariant(Step, LoopNest))
return false;
Loops.set(mapDstLoop(AddRec->getLoop()));
return checkDstSubscript(Start, LoopNest, Loops);
}
DependenceAnalysis::Subscript::ClassificationKind
DependenceAnalysis::classifyPair(const SCEV *Src, const Loop *SrcLoopNest,
const SCEV *Dst, const Loop *DstLoopNest,
SmallBitVector &Loops) {
SmallBitVector SrcLoops(MaxLevels + 1);
SmallBitVector DstLoops(MaxLevels + 1);
if (!checkSrcSubscript(Src, SrcLoopNest, SrcLoops))
return Subscript::NonLinear;
if (!checkDstSubscript(Dst, DstLoopNest, DstLoops))
return Subscript::NonLinear;
Loops = SrcLoops;
Loops |= DstLoops;
unsigned N = Loops.count();
if (N == 0)
return Subscript::ZIV;
if (N == 1)
return Subscript::SIV;
if (N == 2 && (SrcLoops.count() == 0 ||
DstLoops.count() == 0 ||
(SrcLoops.count() == 1 && DstLoops.count() == 1)))
return Subscript::RDIV;
return Subscript::MIV;
}
bool DependenceAnalysis::isKnownPredicate(ICmpInst::Predicate Pred,
const SCEV *X,
const SCEV *Y) const {
if (Pred == CmpInst::ICMP_EQ ||
Pred == CmpInst::ICMP_NE) {
if ((isa<SCEVSignExtendExpr>(X) &&
isa<SCEVSignExtendExpr>(Y)) ||
(isa<SCEVZeroExtendExpr>(X) &&
isa<SCEVZeroExtendExpr>(Y))) {
const SCEVCastExpr *CX = cast<SCEVCastExpr>(X);
const SCEVCastExpr *CY = cast<SCEVCastExpr>(Y);
const SCEV *Xop = CX->getOperand();
const SCEV *Yop = CY->getOperand();
if (Xop->getType() == Yop->getType()) {
X = Xop;
Y = Yop;
}
}
}
if (SE->isKnownPredicate(Pred, X, Y))
return true;
const SCEV *Delta = SE->getMinusSCEV(X, Y);
switch (Pred) {
case CmpInst::ICMP_EQ:
return Delta->isZero();
case CmpInst::ICMP_NE:
return SE->isKnownNonZero(Delta);
case CmpInst::ICMP_SGE:
return SE->isKnownNonNegative(Delta);
case CmpInst::ICMP_SLE:
return SE->isKnownNonPositive(Delta);
case CmpInst::ICMP_SGT:
return SE->isKnownPositive(Delta);
case CmpInst::ICMP_SLT:
return SE->isKnownNegative(Delta);
default:
llvm_unreachable("unexpected predicate in isKnownPredicate");
}
}
const SCEV *DependenceAnalysis::collectUpperBound(const Loop *L,
Type *T) const {
if (SE->hasLoopInvariantBackedgeTakenCount(L)) {
const SCEV *UB = SE->getBackedgeTakenCount(L);
return SE->getTruncateOrZeroExtend(UB, T);
}
return nullptr;
}
const SCEVConstant *DependenceAnalysis::collectConstantUpperBound(const Loop *L,
Type *T
) const {
if (const SCEV *UB = collectUpperBound(L, T))
return dyn_cast<SCEVConstant>(UB);
return nullptr;
}
bool DependenceAnalysis::testZIV(const SCEV *Src,
const SCEV *Dst,
FullDependence &Result) const {
DEBUG(dbgs() << " src = " << *Src << "\n");
DEBUG(dbgs() << " dst = " << *Dst << "\n");
++ZIVapplications;
if (isKnownPredicate(CmpInst::ICMP_EQ, Src, Dst)) {
DEBUG(dbgs() << " provably dependent\n");
return false; }
if (isKnownPredicate(CmpInst::ICMP_NE, Src, Dst)) {
DEBUG(dbgs() << " provably independent\n");
++ZIVindependence;
return true; }
DEBUG(dbgs() << " possibly dependent\n");
Result.Consistent = false;
return false; }
bool DependenceAnalysis::strongSIVtest(const SCEV *Coeff,
const SCEV *SrcConst,
const SCEV *DstConst,
const Loop *CurLoop,
unsigned Level,
FullDependence &Result,
Constraint &NewConstraint) const {
DEBUG(dbgs() << "\tStrong SIV test\n");
DEBUG(dbgs() << "\t Coeff = " << *Coeff);
DEBUG(dbgs() << ", " << *Coeff->getType() << "\n");
DEBUG(dbgs() << "\t SrcConst = " << *SrcConst);
DEBUG(dbgs() << ", " << *SrcConst->getType() << "\n");
DEBUG(dbgs() << "\t DstConst = " << *DstConst);
DEBUG(dbgs() << ", " << *DstConst->getType() << "\n");
++StrongSIVapplications;
assert(0 < Level && Level <= CommonLevels && "level out of range");
Level--;
const SCEV *Delta = SE->getMinusSCEV(SrcConst, DstConst);
DEBUG(dbgs() << "\t Delta = " << *Delta);
DEBUG(dbgs() << ", " << *Delta->getType() << "\n");
if (const SCEV *UpperBound = collectUpperBound(CurLoop, Delta->getType())) {
DEBUG(dbgs() << "\t UpperBound = " << *UpperBound);
DEBUG(dbgs() << ", " << *UpperBound->getType() << "\n");
const SCEV *AbsDelta =
SE->isKnownNonNegative(Delta) ? Delta : SE->getNegativeSCEV(Delta);
const SCEV *AbsCoeff =
SE->isKnownNonNegative(Coeff) ? Coeff : SE->getNegativeSCEV(Coeff);
const SCEV *Product = SE->getMulExpr(UpperBound, AbsCoeff);
if (isKnownPredicate(CmpInst::ICMP_SGT, AbsDelta, Product)) {
++StrongSIVindependence;
++StrongSIVsuccesses;
return true;
}
}
if (isa<SCEVConstant>(Delta) && isa<SCEVConstant>(Coeff)) {
APInt ConstDelta = cast<SCEVConstant>(Delta)->getValue()->getValue();
APInt ConstCoeff = cast<SCEVConstant>(Coeff)->getValue()->getValue();
APInt Distance = ConstDelta; APInt Remainder = ConstDelta;
APInt::sdivrem(ConstDelta, ConstCoeff, Distance, Remainder);
DEBUG(dbgs() << "\t Distance = " << Distance << "\n");
DEBUG(dbgs() << "\t Remainder = " << Remainder << "\n");
if (Remainder != 0) {
++StrongSIVindependence;
++StrongSIVsuccesses;
return true;
}
Result.DV[Level].Distance = SE->getConstant(Distance);
NewConstraint.setDistance(SE->getConstant(Distance), CurLoop);
if (Distance.sgt(0))
Result.DV[Level].Direction &= Dependence::DVEntry::LT;
else if (Distance.slt(0))
Result.DV[Level].Direction &= Dependence::DVEntry::GT;
else
Result.DV[Level].Direction &= Dependence::DVEntry::EQ;
++StrongSIVsuccesses;
}
else if (Delta->isZero()) {
Result.DV[Level].Distance = Delta;
NewConstraint.setDistance(Delta, CurLoop);
Result.DV[Level].Direction &= Dependence::DVEntry::EQ;
++StrongSIVsuccesses;
}
else {
if (Coeff->isOne()) {
DEBUG(dbgs() << "\t Distance = " << *Delta << "\n");
Result.DV[Level].Distance = Delta; NewConstraint.setDistance(Delta, CurLoop);
}
else {
Result.Consistent = false;
NewConstraint.setLine(Coeff,
SE->getNegativeSCEV(Coeff),
SE->getNegativeSCEV(Delta), CurLoop);
}
bool DeltaMaybeZero = !SE->isKnownNonZero(Delta);
bool DeltaMaybePositive = !SE->isKnownNonPositive(Delta);
bool DeltaMaybeNegative = !SE->isKnownNonNegative(Delta);
bool CoeffMaybePositive = !SE->isKnownNonPositive(Coeff);
bool CoeffMaybeNegative = !SE->isKnownNonNegative(Coeff);
unsigned NewDirection = Dependence::DVEntry::NONE;
if ((DeltaMaybePositive && CoeffMaybePositive) ||
(DeltaMaybeNegative && CoeffMaybeNegative))
NewDirection = Dependence::DVEntry::LT;
if (DeltaMaybeZero)
NewDirection |= Dependence::DVEntry::EQ;
if ((DeltaMaybeNegative && CoeffMaybePositive) ||
(DeltaMaybePositive && CoeffMaybeNegative))
NewDirection |= Dependence::DVEntry::GT;
if (NewDirection < Result.DV[Level].Direction)
++StrongSIVsuccesses;
Result.DV[Level].Direction &= NewDirection;
}
return false;
}
bool DependenceAnalysis::weakCrossingSIVtest(const SCEV *Coeff,
const SCEV *SrcConst,
const SCEV *DstConst,
const Loop *CurLoop,
unsigned Level,
FullDependence &Result,
Constraint &NewConstraint,
const SCEV *&SplitIter) const {
DEBUG(dbgs() << "\tWeak-Crossing SIV test\n");
DEBUG(dbgs() << "\t Coeff = " << *Coeff << "\n");
DEBUG(dbgs() << "\t SrcConst = " << *SrcConst << "\n");
DEBUG(dbgs() << "\t DstConst = " << *DstConst << "\n");
++WeakCrossingSIVapplications;
assert(0 < Level && Level <= CommonLevels && "Level out of range");
Level--;
Result.Consistent = false;
const SCEV *Delta = SE->getMinusSCEV(DstConst, SrcConst);
DEBUG(dbgs() << "\t Delta = " << *Delta << "\n");
NewConstraint.setLine(Coeff, Coeff, Delta, CurLoop);
if (Delta->isZero()) {
Result.DV[Level].Direction &= unsigned(~Dependence::DVEntry::LT);
Result.DV[Level].Direction &= unsigned(~Dependence::DVEntry::GT);
++WeakCrossingSIVsuccesses;
if (!Result.DV[Level].Direction) {
++WeakCrossingSIVindependence;
return true;
}
Result.DV[Level].Distance = Delta; return false;
}
const SCEVConstant *ConstCoeff = dyn_cast<SCEVConstant>(Coeff);
if (!ConstCoeff)
return false;
Result.DV[Level].Splitable = true;
if (SE->isKnownNegative(ConstCoeff)) {
ConstCoeff = dyn_cast<SCEVConstant>(SE->getNegativeSCEV(ConstCoeff));
assert(ConstCoeff &&
"dynamic cast of negative of ConstCoeff should yield constant");
Delta = SE->getNegativeSCEV(Delta);
}
assert(SE->isKnownPositive(ConstCoeff) && "ConstCoeff should be positive");
SplitIter = SE->getUDivExpr(
SE->getSMaxExpr(SE->getZero(Delta->getType()), Delta),
SE->getMulExpr(SE->getConstant(Delta->getType(), 2), ConstCoeff));
DEBUG(dbgs() << "\t Split iter = " << *SplitIter << "\n");
const SCEVConstant *ConstDelta = dyn_cast<SCEVConstant>(Delta);
if (!ConstDelta)
return false;
DEBUG(dbgs() << "\t Delta = " << *Delta << "\n");
DEBUG(dbgs() << "\t ConstCoeff = " << *ConstCoeff << "\n");
if (SE->isKnownNegative(Delta)) {
++WeakCrossingSIVindependence;
++WeakCrossingSIVsuccesses;
return true;
}
if (const SCEV *UpperBound = collectUpperBound(CurLoop, Delta->getType())) {
DEBUG(dbgs() << "\t UpperBound = " << *UpperBound << "\n");
const SCEV *ConstantTwo = SE->getConstant(UpperBound->getType(), 2);
const SCEV *ML = SE->getMulExpr(SE->getMulExpr(ConstCoeff, UpperBound),
ConstantTwo);
DEBUG(dbgs() << "\t ML = " << *ML << "\n");
if (isKnownPredicate(CmpInst::ICMP_SGT, Delta, ML)) {
++WeakCrossingSIVindependence;
++WeakCrossingSIVsuccesses;
return true;
}
if (isKnownPredicate(CmpInst::ICMP_EQ, Delta, ML)) {
Result.DV[Level].Direction &= unsigned(~Dependence::DVEntry::LT);
Result.DV[Level].Direction &= unsigned(~Dependence::DVEntry::GT);
++WeakCrossingSIVsuccesses;
if (!Result.DV[Level].Direction) {
++WeakCrossingSIVindependence;
return true;
}
Result.DV[Level].Splitable = false;
Result.DV[Level].Distance = SE->getZero(Delta->getType());
return false;
}
}
APInt APDelta = ConstDelta->getValue()->getValue();
APInt APCoeff = ConstCoeff->getValue()->getValue();
APInt Distance = APDelta; APInt Remainder = APDelta;
APInt::sdivrem(APDelta, APCoeff, Distance, Remainder);
DEBUG(dbgs() << "\t Remainder = " << Remainder << "\n");
if (Remainder != 0) {
++WeakCrossingSIVindependence;
++WeakCrossingSIVsuccesses;
return true;
}
DEBUG(dbgs() << "\t Distance = " << Distance << "\n");
APInt Two = APInt(Distance.getBitWidth(), 2, true);
Remainder = Distance.srem(Two);
DEBUG(dbgs() << "\t Remainder = " << Remainder << "\n");
if (Remainder != 0) {
Result.DV[Level].Direction &= unsigned(~Dependence::DVEntry::EQ);
++WeakCrossingSIVsuccesses;
}
return false;
}
static
bool findGCD(unsigned Bits, APInt AM, APInt BM, APInt Delta,
APInt &G, APInt &X, APInt &Y) {
APInt A0(Bits, 1, true), A1(Bits, 0, true);
APInt B0(Bits, 0, true), B1(Bits, 1, true);
APInt G0 = AM.abs();
APInt G1 = BM.abs();
APInt Q = G0; APInt R = G0;
APInt::sdivrem(G0, G1, Q, R);
while (R != 0) {
APInt A2 = A0 - Q*A1; A0 = A1; A1 = A2;
APInt B2 = B0 - Q*B1; B0 = B1; B1 = B2;
G0 = G1; G1 = R;
APInt::sdivrem(G0, G1, Q, R);
}
G = G1;
DEBUG(dbgs() << "\t GCD = " << G << "\n");
X = AM.slt(0) ? -A1 : A1;
Y = BM.slt(0) ? B1 : -B1;
R = Delta.srem(G);
if (R != 0)
return true; Q = Delta.sdiv(G);
X *= Q;
Y *= Q;
return false;
}
static
APInt floorOfQuotient(APInt A, APInt B) {
APInt Q = A; APInt R = A;
APInt::sdivrem(A, B, Q, R);
if (R == 0)
return Q;
if ((A.sgt(0) && B.sgt(0)) ||
(A.slt(0) && B.slt(0)))
return Q;
else
return Q - 1;
}
static
APInt ceilingOfQuotient(APInt A, APInt B) {
APInt Q = A; APInt R = A;
APInt::sdivrem(A, B, Q, R);
if (R == 0)
return Q;
if ((A.sgt(0) && B.sgt(0)) ||
(A.slt(0) && B.slt(0)))
return Q + 1;
else
return Q;
}
static
APInt maxAPInt(APInt A, APInt B) {
return A.sgt(B) ? A : B;
}
static
APInt minAPInt(APInt A, APInt B) {
return A.slt(B) ? A : B;
}
bool DependenceAnalysis::exactSIVtest(const SCEV *SrcCoeff,
const SCEV *DstCoeff,
const SCEV *SrcConst,
const SCEV *DstConst,
const Loop *CurLoop,
unsigned Level,
FullDependence &Result,
Constraint &NewConstraint) const {
DEBUG(dbgs() << "\tExact SIV test\n");
DEBUG(dbgs() << "\t SrcCoeff = " << *SrcCoeff << " = AM\n");
DEBUG(dbgs() << "\t DstCoeff = " << *DstCoeff << " = BM\n");
DEBUG(dbgs() << "\t SrcConst = " << *SrcConst << "\n");
DEBUG(dbgs() << "\t DstConst = " << *DstConst << "\n");
++ExactSIVapplications;
assert(0 < Level && Level <= CommonLevels && "Level out of range");
Level--;
Result.Consistent = false;
const SCEV *Delta = SE->getMinusSCEV(DstConst, SrcConst);
DEBUG(dbgs() << "\t Delta = " << *Delta << "\n");
NewConstraint.setLine(SrcCoeff, SE->getNegativeSCEV(DstCoeff),
Delta, CurLoop);
const SCEVConstant *ConstDelta = dyn_cast<SCEVConstant>(Delta);
const SCEVConstant *ConstSrcCoeff = dyn_cast<SCEVConstant>(SrcCoeff);
const SCEVConstant *ConstDstCoeff = dyn_cast<SCEVConstant>(DstCoeff);
if (!ConstDelta || !ConstSrcCoeff || !ConstDstCoeff)
return false;
APInt G, X, Y;
APInt AM = ConstSrcCoeff->getValue()->getValue();
APInt BM = ConstDstCoeff->getValue()->getValue();
unsigned Bits = AM.getBitWidth();
if (findGCD(Bits, AM, BM, ConstDelta->getValue()->getValue(), G, X, Y)) {
++ExactSIVindependence;
++ExactSIVsuccesses;
return true;
}
DEBUG(dbgs() << "\t X = " << X << ", Y = " << Y << "\n");
APInt UM(Bits, 1, true);
bool UMvalid = false;
if (const SCEVConstant *CUB =
collectConstantUpperBound(CurLoop, Delta->getType())) {
UM = CUB->getValue()->getValue();
DEBUG(dbgs() << "\t UM = " << UM << "\n");
UMvalid = true;
}
APInt TU(APInt::getSignedMaxValue(Bits));
APInt TL(APInt::getSignedMinValue(Bits));
APInt TMUL = BM.sdiv(G);
if (TMUL.sgt(0)) {
TL = maxAPInt(TL, ceilingOfQuotient(-X, TMUL));
DEBUG(dbgs() << "\t TL = " << TL << "\n");
if (UMvalid) {
TU = minAPInt(TU, floorOfQuotient(UM - X, TMUL));
DEBUG(dbgs() << "\t TU = " << TU << "\n");
}
}
else {
TU = minAPInt(TU, floorOfQuotient(-X, TMUL));
DEBUG(dbgs() << "\t TU = " << TU << "\n");
if (UMvalid) {
TL = maxAPInt(TL, ceilingOfQuotient(UM - X, TMUL));
DEBUG(dbgs() << "\t TL = " << TL << "\n");
}
}
TMUL = AM.sdiv(G);
if (TMUL.sgt(0)) {
TL = maxAPInt(TL, ceilingOfQuotient(-Y, TMUL));
DEBUG(dbgs() << "\t TL = " << TL << "\n");
if (UMvalid) {
TU = minAPInt(TU, floorOfQuotient(UM - Y, TMUL));
DEBUG(dbgs() << "\t TU = " << TU << "\n");
}
}
else {
TU = minAPInt(TU, floorOfQuotient(-Y, TMUL));
DEBUG(dbgs() << "\t TU = " << TU << "\n");
if (UMvalid) {
TL = maxAPInt(TL, ceilingOfQuotient(UM - Y, TMUL));
DEBUG(dbgs() << "\t TL = " << TL << "\n");
}
}
if (TL.sgt(TU)) {
++ExactSIVindependence;
++ExactSIVsuccesses;
return true;
}
unsigned NewDirection = Dependence::DVEntry::NONE;
APInt SaveTU(TU); APInt SaveTL(TL);
DEBUG(dbgs() << "\t exploring LT direction\n");
TMUL = AM - BM;
if (TMUL.sgt(0)) {
TL = maxAPInt(TL, ceilingOfQuotient(X - Y + 1, TMUL));
DEBUG(dbgs() << "\t\t TL = " << TL << "\n");
}
else {
TU = minAPInt(TU, floorOfQuotient(X - Y + 1, TMUL));
DEBUG(dbgs() << "\t\t TU = " << TU << "\n");
}
if (TL.sle(TU)) {
NewDirection |= Dependence::DVEntry::LT;
++ExactSIVsuccesses;
}
TU = SaveTU; TL = SaveTL;
DEBUG(dbgs() << "\t exploring EQ direction\n");
if (TMUL.sgt(0)) {
TL = maxAPInt(TL, ceilingOfQuotient(X - Y, TMUL));
DEBUG(dbgs() << "\t\t TL = " << TL << "\n");
}
else {
TU = minAPInt(TU, floorOfQuotient(X - Y, TMUL));
DEBUG(dbgs() << "\t\t TU = " << TU << "\n");
}
TMUL = BM - AM;
if (TMUL.sgt(0)) {
TL = maxAPInt(TL, ceilingOfQuotient(Y - X, TMUL));
DEBUG(dbgs() << "\t\t TL = " << TL << "\n");
}
else {
TU = minAPInt(TU, floorOfQuotient(Y - X, TMUL));
DEBUG(dbgs() << "\t\t TU = " << TU << "\n");
}
if (TL.sle(TU)) {
NewDirection |= Dependence::DVEntry::EQ;
++ExactSIVsuccesses;
}
TU = SaveTU; TL = SaveTL;
DEBUG(dbgs() << "\t exploring GT direction\n");
if (TMUL.sgt(0)) {
TL = maxAPInt(TL, ceilingOfQuotient(Y - X + 1, TMUL));
DEBUG(dbgs() << "\t\t TL = " << TL << "\n");
}
else {
TU = minAPInt(TU, floorOfQuotient(Y - X + 1, TMUL));
DEBUG(dbgs() << "\t\t TU = " << TU << "\n");
}
if (TL.sle(TU)) {
NewDirection |= Dependence::DVEntry::GT;
++ExactSIVsuccesses;
}
Result.DV[Level].Direction &= NewDirection;
if (Result.DV[Level].Direction == Dependence::DVEntry::NONE)
++ExactSIVindependence;
return Result.DV[Level].Direction == Dependence::DVEntry::NONE;
}
static
bool isRemainderZero(const SCEVConstant *Dividend,
const SCEVConstant *Divisor) {
APInt ConstDividend = Dividend->getValue()->getValue();
APInt ConstDivisor = Divisor->getValue()->getValue();
return ConstDividend.srem(ConstDivisor) == 0;
}
bool DependenceAnalysis::weakZeroSrcSIVtest(const SCEV *DstCoeff,
const SCEV *SrcConst,
const SCEV *DstConst,
const Loop *CurLoop,
unsigned Level,
FullDependence &Result,
Constraint &NewConstraint) const {
DEBUG(dbgs() << "\tWeak-Zero (src) SIV test\n");
DEBUG(dbgs() << "\t DstCoeff = " << *DstCoeff << "\n");
DEBUG(dbgs() << "\t SrcConst = " << *SrcConst << "\n");
DEBUG(dbgs() << "\t DstConst = " << *DstConst << "\n");
++WeakZeroSIVapplications;
assert(0 < Level && Level <= MaxLevels && "Level out of range");
Level--;
Result.Consistent = false;
const SCEV *Delta = SE->getMinusSCEV(SrcConst, DstConst);
NewConstraint.setLine(SE->getZero(Delta->getType()), DstCoeff, Delta,
CurLoop);
DEBUG(dbgs() << "\t Delta = " << *Delta << "\n");
if (isKnownPredicate(CmpInst::ICMP_EQ, SrcConst, DstConst)) {
if (Level < CommonLevels) {
Result.DV[Level].Direction &= Dependence::DVEntry::LE;
Result.DV[Level].PeelFirst = true;
++WeakZeroSIVsuccesses;
}
return false; }
const SCEVConstant *ConstCoeff = dyn_cast<SCEVConstant>(DstCoeff);
if (!ConstCoeff)
return false;
const SCEV *AbsCoeff =
SE->isKnownNegative(ConstCoeff) ?
SE->getNegativeSCEV(ConstCoeff) : ConstCoeff;
const SCEV *NewDelta =
SE->isKnownNegative(ConstCoeff) ? SE->getNegativeSCEV(Delta) : Delta;
if (const SCEV *UpperBound = collectUpperBound(CurLoop, Delta->getType())) {
DEBUG(dbgs() << "\t UpperBound = " << *UpperBound << "\n");
const SCEV *Product = SE->getMulExpr(AbsCoeff, UpperBound);
if (isKnownPredicate(CmpInst::ICMP_SGT, NewDelta, Product)) {
++WeakZeroSIVindependence;
++WeakZeroSIVsuccesses;
return true;
}
if (isKnownPredicate(CmpInst::ICMP_EQ, NewDelta, Product)) {
if (Level < CommonLevels) {
Result.DV[Level].Direction &= Dependence::DVEntry::GE;
Result.DV[Level].PeelLast = true;
++WeakZeroSIVsuccesses;
}
return false;
}
}
if (SE->isKnownNegative(NewDelta)) {
++WeakZeroSIVindependence;
++WeakZeroSIVsuccesses;
return true;
}
if (isa<SCEVConstant>(Delta) &&
!isRemainderZero(cast<SCEVConstant>(Delta), ConstCoeff)) {
++WeakZeroSIVindependence;
++WeakZeroSIVsuccesses;
return true;
}
return false;
}
bool DependenceAnalysis::weakZeroDstSIVtest(const SCEV *SrcCoeff,
const SCEV *SrcConst,
const SCEV *DstConst,
const Loop *CurLoop,
unsigned Level,
FullDependence &Result,
Constraint &NewConstraint) const {
DEBUG(dbgs() << "\tWeak-Zero (dst) SIV test\n");
DEBUG(dbgs() << "\t SrcCoeff = " << *SrcCoeff << "\n");
DEBUG(dbgs() << "\t SrcConst = " << *SrcConst << "\n");
DEBUG(dbgs() << "\t DstConst = " << *DstConst << "\n");
++WeakZeroSIVapplications;
assert(0 < Level && Level <= SrcLevels && "Level out of range");
Level--;
Result.Consistent = false;
const SCEV *Delta = SE->getMinusSCEV(DstConst, SrcConst);
NewConstraint.setLine(SrcCoeff, SE->getZero(Delta->getType()), Delta,
CurLoop);
DEBUG(dbgs() << "\t Delta = " << *Delta << "\n");
if (isKnownPredicate(CmpInst::ICMP_EQ, DstConst, SrcConst)) {
if (Level < CommonLevels) {
Result.DV[Level].Direction &= Dependence::DVEntry::LE;
Result.DV[Level].PeelFirst = true;
++WeakZeroSIVsuccesses;
}
return false; }
const SCEVConstant *ConstCoeff = dyn_cast<SCEVConstant>(SrcCoeff);
if (!ConstCoeff)
return false;
const SCEV *AbsCoeff =
SE->isKnownNegative(ConstCoeff) ?
SE->getNegativeSCEV(ConstCoeff) : ConstCoeff;
const SCEV *NewDelta =
SE->isKnownNegative(ConstCoeff) ? SE->getNegativeSCEV(Delta) : Delta;
if (const SCEV *UpperBound = collectUpperBound(CurLoop, Delta->getType())) {
DEBUG(dbgs() << "\t UpperBound = " << *UpperBound << "\n");
const SCEV *Product = SE->getMulExpr(AbsCoeff, UpperBound);
if (isKnownPredicate(CmpInst::ICMP_SGT, NewDelta, Product)) {
++WeakZeroSIVindependence;
++WeakZeroSIVsuccesses;
return true;
}
if (isKnownPredicate(CmpInst::ICMP_EQ, NewDelta, Product)) {
if (Level < CommonLevels) {
Result.DV[Level].Direction &= Dependence::DVEntry::GE;
Result.DV[Level].PeelLast = true;
++WeakZeroSIVsuccesses;
}
return false;
}
}
if (SE->isKnownNegative(NewDelta)) {
++WeakZeroSIVindependence;
++WeakZeroSIVsuccesses;
return true;
}
if (isa<SCEVConstant>(Delta) &&
!isRemainderZero(cast<SCEVConstant>(Delta), ConstCoeff)) {
++WeakZeroSIVindependence;
++WeakZeroSIVsuccesses;
return true;
}
return false;
}
bool DependenceAnalysis::exactRDIVtest(const SCEV *SrcCoeff,
const SCEV *DstCoeff,
const SCEV *SrcConst,
const SCEV *DstConst,
const Loop *SrcLoop,
const Loop *DstLoop,
FullDependence &Result) const {
DEBUG(dbgs() << "\tExact RDIV test\n");
DEBUG(dbgs() << "\t SrcCoeff = " << *SrcCoeff << " = AM\n");
DEBUG(dbgs() << "\t DstCoeff = " << *DstCoeff << " = BM\n");
DEBUG(dbgs() << "\t SrcConst = " << *SrcConst << "\n");
DEBUG(dbgs() << "\t DstConst = " << *DstConst << "\n");
++ExactRDIVapplications;
Result.Consistent = false;
const SCEV *Delta = SE->getMinusSCEV(DstConst, SrcConst);
DEBUG(dbgs() << "\t Delta = " << *Delta << "\n");
const SCEVConstant *ConstDelta = dyn_cast<SCEVConstant>(Delta);
const SCEVConstant *ConstSrcCoeff = dyn_cast<SCEVConstant>(SrcCoeff);
const SCEVConstant *ConstDstCoeff = dyn_cast<SCEVConstant>(DstCoeff);
if (!ConstDelta || !ConstSrcCoeff || !ConstDstCoeff)
return false;
APInt G, X, Y;
APInt AM = ConstSrcCoeff->getValue()->getValue();
APInt BM = ConstDstCoeff->getValue()->getValue();
unsigned Bits = AM.getBitWidth();
if (findGCD(Bits, AM, BM, ConstDelta->getValue()->getValue(), G, X, Y)) {
++ExactRDIVindependence;
return true;
}
DEBUG(dbgs() << "\t X = " << X << ", Y = " << Y << "\n");
APInt SrcUM(Bits, 1, true);
bool SrcUMvalid = false;
if (const SCEVConstant *UpperBound =
collectConstantUpperBound(SrcLoop, Delta->getType())) {
SrcUM = UpperBound->getValue()->getValue();
DEBUG(dbgs() << "\t SrcUM = " << SrcUM << "\n");
SrcUMvalid = true;
}
APInt DstUM(Bits, 1, true);
bool DstUMvalid = false;
if (const SCEVConstant *UpperBound =
collectConstantUpperBound(DstLoop, Delta->getType())) {
DstUM = UpperBound->getValue()->getValue();
DEBUG(dbgs() << "\t DstUM = " << DstUM << "\n");
DstUMvalid = true;
}
APInt TU(APInt::getSignedMaxValue(Bits));
APInt TL(APInt::getSignedMinValue(Bits));
APInt TMUL = BM.sdiv(G);
if (TMUL.sgt(0)) {
TL = maxAPInt(TL, ceilingOfQuotient(-X, TMUL));
DEBUG(dbgs() << "\t TL = " << TL << "\n");
if (SrcUMvalid) {
TU = minAPInt(TU, floorOfQuotient(SrcUM - X, TMUL));
DEBUG(dbgs() << "\t TU = " << TU << "\n");
}
}
else {
TU = minAPInt(TU, floorOfQuotient(-X, TMUL));
DEBUG(dbgs() << "\t TU = " << TU << "\n");
if (SrcUMvalid) {
TL = maxAPInt(TL, ceilingOfQuotient(SrcUM - X, TMUL));
DEBUG(dbgs() << "\t TL = " << TL << "\n");
}
}
TMUL = AM.sdiv(G);
if (TMUL.sgt(0)) {
TL = maxAPInt(TL, ceilingOfQuotient(-Y, TMUL));
DEBUG(dbgs() << "\t TL = " << TL << "\n");
if (DstUMvalid) {
TU = minAPInt(TU, floorOfQuotient(DstUM - Y, TMUL));
DEBUG(dbgs() << "\t TU = " << TU << "\n");
}
}
else {
TU = minAPInt(TU, floorOfQuotient(-Y, TMUL));
DEBUG(dbgs() << "\t TU = " << TU << "\n");
if (DstUMvalid) {
TL = maxAPInt(TL, ceilingOfQuotient(DstUM - Y, TMUL));
DEBUG(dbgs() << "\t TL = " << TL << "\n");
}
}
if (TL.sgt(TU))
++ExactRDIVindependence;
return TL.sgt(TU);
}
bool DependenceAnalysis::symbolicRDIVtest(const SCEV *A1,
const SCEV *A2,
const SCEV *C1,
const SCEV *C2,
const Loop *Loop1,
const Loop *Loop2) const {
++SymbolicRDIVapplications;
DEBUG(dbgs() << "\ttry symbolic RDIV test\n");
DEBUG(dbgs() << "\t A1 = " << *A1);
DEBUG(dbgs() << ", type = " << *A1->getType() << "\n");
DEBUG(dbgs() << "\t A2 = " << *A2 << "\n");
DEBUG(dbgs() << "\t C1 = " << *C1 << "\n");
DEBUG(dbgs() << "\t C2 = " << *C2 << "\n");
const SCEV *N1 = collectUpperBound(Loop1, A1->getType());
const SCEV *N2 = collectUpperBound(Loop2, A1->getType());
DEBUG(if (N1) dbgs() << "\t N1 = " << *N1 << "\n");
DEBUG(if (N2) dbgs() << "\t N2 = " << *N2 << "\n");
const SCEV *C2_C1 = SE->getMinusSCEV(C2, C1);
const SCEV *C1_C2 = SE->getMinusSCEV(C1, C2);
DEBUG(dbgs() << "\t C2 - C1 = " << *C2_C1 << "\n");
DEBUG(dbgs() << "\t C1 - C2 = " << *C1_C2 << "\n");
if (SE->isKnownNonNegative(A1)) {
if (SE->isKnownNonNegative(A2)) {
if (N1) {
const SCEV *A1N1 = SE->getMulExpr(A1, N1);
DEBUG(dbgs() << "\t A1*N1 = " << *A1N1 << "\n");
if (isKnownPredicate(CmpInst::ICMP_SGT, C2_C1, A1N1)) {
++SymbolicRDIVindependence;
return true;
}
}
if (N2) {
const SCEV *A2N2 = SE->getMulExpr(A2, N2);
DEBUG(dbgs() << "\t A2*N2 = " << *A2N2 << "\n");
if (isKnownPredicate(CmpInst::ICMP_SLT, A2N2, C1_C2)) {
++SymbolicRDIVindependence;
return true;
}
}
}
else if (SE->isKnownNonPositive(A2)) {
if (N1 && N2) {
const SCEV *A1N1 = SE->getMulExpr(A1, N1);
const SCEV *A2N2 = SE->getMulExpr(A2, N2);
const SCEV *A1N1_A2N2 = SE->getMinusSCEV(A1N1, A2N2);
DEBUG(dbgs() << "\t A1*N1 - A2*N2 = " << *A1N1_A2N2 << "\n");
if (isKnownPredicate(CmpInst::ICMP_SGT, C2_C1, A1N1_A2N2)) {
++SymbolicRDIVindependence;
return true;
}
}
if (SE->isKnownNegative(C2_C1)) {
++SymbolicRDIVindependence;
return true;
}
}
}
else if (SE->isKnownNonPositive(A1)) {
if (SE->isKnownNonNegative(A2)) {
if (N1 && N2) {
const SCEV *A1N1 = SE->getMulExpr(A1, N1);
const SCEV *A2N2 = SE->getMulExpr(A2, N2);
const SCEV *A1N1_A2N2 = SE->getMinusSCEV(A1N1, A2N2);
DEBUG(dbgs() << "\t A1*N1 - A2*N2 = " << *A1N1_A2N2 << "\n");
if (isKnownPredicate(CmpInst::ICMP_SGT, A1N1_A2N2, C2_C1)) {
++SymbolicRDIVindependence;
return true;
}
}
if (SE->isKnownPositive(C2_C1)) {
++SymbolicRDIVindependence;
return true;
}
}
else if (SE->isKnownNonPositive(A2)) {
if (N1) {
const SCEV *A1N1 = SE->getMulExpr(A1, N1);
DEBUG(dbgs() << "\t A1*N1 = " << *A1N1 << "\n");
if (isKnownPredicate(CmpInst::ICMP_SGT, A1N1, C2_C1)) {
++SymbolicRDIVindependence;
return true;
}
}
if (N2) {
const SCEV *A2N2 = SE->getMulExpr(A2, N2);
DEBUG(dbgs() << "\t A2*N2 = " << *A2N2 << "\n");
if (isKnownPredicate(CmpInst::ICMP_SLT, C1_C2, A2N2)) {
++SymbolicRDIVindependence;
return true;
}
}
}
}
return false;
}
bool DependenceAnalysis::testSIV(const SCEV *Src,
const SCEV *Dst,
unsigned &Level,
FullDependence &Result,
Constraint &NewConstraint,
const SCEV *&SplitIter) const {
DEBUG(dbgs() << " src = " << *Src << "\n");
DEBUG(dbgs() << " dst = " << *Dst << "\n");
const SCEVAddRecExpr *SrcAddRec = dyn_cast<SCEVAddRecExpr>(Src);
const SCEVAddRecExpr *DstAddRec = dyn_cast<SCEVAddRecExpr>(Dst);
if (SrcAddRec && DstAddRec) {
const SCEV *SrcConst = SrcAddRec->getStart();
const SCEV *DstConst = DstAddRec->getStart();
const SCEV *SrcCoeff = SrcAddRec->getStepRecurrence(*SE);
const SCEV *DstCoeff = DstAddRec->getStepRecurrence(*SE);
const Loop *CurLoop = SrcAddRec->getLoop();
assert(CurLoop == DstAddRec->getLoop() &&
"both loops in SIV should be same");
Level = mapSrcLoop(CurLoop);
bool disproven;
if (SrcCoeff == DstCoeff)
disproven = strongSIVtest(SrcCoeff, SrcConst, DstConst, CurLoop,
Level, Result, NewConstraint);
else if (SrcCoeff == SE->getNegativeSCEV(DstCoeff))
disproven = weakCrossingSIVtest(SrcCoeff, SrcConst, DstConst, CurLoop,
Level, Result, NewConstraint, SplitIter);
else
disproven = exactSIVtest(SrcCoeff, DstCoeff, SrcConst, DstConst, CurLoop,
Level, Result, NewConstraint);
return disproven ||
gcdMIVtest(Src, Dst, Result) ||
symbolicRDIVtest(SrcCoeff, DstCoeff, SrcConst, DstConst, CurLoop, CurLoop);
}
if (SrcAddRec) {
const SCEV *SrcConst = SrcAddRec->getStart();
const SCEV *SrcCoeff = SrcAddRec->getStepRecurrence(*SE);
const SCEV *DstConst = Dst;
const Loop *CurLoop = SrcAddRec->getLoop();
Level = mapSrcLoop(CurLoop);
return weakZeroDstSIVtest(SrcCoeff, SrcConst, DstConst, CurLoop,
Level, Result, NewConstraint) ||
gcdMIVtest(Src, Dst, Result);
}
if (DstAddRec) {
const SCEV *DstConst = DstAddRec->getStart();
const SCEV *DstCoeff = DstAddRec->getStepRecurrence(*SE);
const SCEV *SrcConst = Src;
const Loop *CurLoop = DstAddRec->getLoop();
Level = mapDstLoop(CurLoop);
return weakZeroSrcSIVtest(DstCoeff, SrcConst, DstConst,
CurLoop, Level, Result, NewConstraint) ||
gcdMIVtest(Src, Dst, Result);
}
llvm_unreachable("SIV test expected at least one AddRec");
return false;
}
bool DependenceAnalysis::testRDIV(const SCEV *Src,
const SCEV *Dst,
FullDependence &Result) const {
const SCEV *SrcConst, *DstConst;
const SCEV *SrcCoeff, *DstCoeff;
const Loop *SrcLoop, *DstLoop;
DEBUG(dbgs() << " src = " << *Src << "\n");
DEBUG(dbgs() << " dst = " << *Dst << "\n");
const SCEVAddRecExpr *SrcAddRec = dyn_cast<SCEVAddRecExpr>(Src);
const SCEVAddRecExpr *DstAddRec = dyn_cast<SCEVAddRecExpr>(Dst);
if (SrcAddRec && DstAddRec) {
SrcConst = SrcAddRec->getStart();
SrcCoeff = SrcAddRec->getStepRecurrence(*SE);
SrcLoop = SrcAddRec->getLoop();
DstConst = DstAddRec->getStart();
DstCoeff = DstAddRec->getStepRecurrence(*SE);
DstLoop = DstAddRec->getLoop();
}
else if (SrcAddRec) {
if (const SCEVAddRecExpr *tmpAddRec =
dyn_cast<SCEVAddRecExpr>(SrcAddRec->getStart())) {
SrcConst = tmpAddRec->getStart();
SrcCoeff = tmpAddRec->getStepRecurrence(*SE);
SrcLoop = tmpAddRec->getLoop();
DstConst = Dst;
DstCoeff = SE->getNegativeSCEV(SrcAddRec->getStepRecurrence(*SE));
DstLoop = SrcAddRec->getLoop();
}
else
llvm_unreachable("RDIV reached by surprising SCEVs");
}
else if (DstAddRec) {
if (const SCEVAddRecExpr *tmpAddRec =
dyn_cast<SCEVAddRecExpr>(DstAddRec->getStart())) {
DstConst = tmpAddRec->getStart();
DstCoeff = tmpAddRec->getStepRecurrence(*SE);
DstLoop = tmpAddRec->getLoop();
SrcConst = Src;
SrcCoeff = SE->getNegativeSCEV(DstAddRec->getStepRecurrence(*SE));
SrcLoop = DstAddRec->getLoop();
}
else
llvm_unreachable("RDIV reached by surprising SCEVs");
}
else
llvm_unreachable("RDIV expected at least one AddRec");
return exactRDIVtest(SrcCoeff, DstCoeff,
SrcConst, DstConst,
SrcLoop, DstLoop,
Result) ||
gcdMIVtest(Src, Dst, Result) ||
symbolicRDIVtest(SrcCoeff, DstCoeff,
SrcConst, DstConst,
SrcLoop, DstLoop);
}
bool DependenceAnalysis::testMIV(const SCEV *Src,
const SCEV *Dst,
const SmallBitVector &Loops,
FullDependence &Result) const {
DEBUG(dbgs() << " src = " << *Src << "\n");
DEBUG(dbgs() << " dst = " << *Dst << "\n");
Result.Consistent = false;
return gcdMIVtest(Src, Dst, Result) ||
banerjeeMIVtest(Src, Dst, Loops, Result);
}
static
const SCEVConstant *getConstantPart(const SCEVMulExpr *Product) {
for (unsigned Op = 0, Ops = Product->getNumOperands(); Op < Ops; Op++) {
if (const SCEVConstant *Constant = dyn_cast<SCEVConstant>(Product->getOperand(Op)))
return Constant;
}
return nullptr;
}
bool DependenceAnalysis::gcdMIVtest(const SCEV *Src,
const SCEV *Dst,
FullDependence &Result) const {
DEBUG(dbgs() << "starting gcd\n");
++GCDapplications;
unsigned BitWidth = SE->getTypeSizeInBits(Src->getType());
APInt RunningGCD = APInt::getNullValue(BitWidth);
const SCEV *Coefficients = Src;
while (const SCEVAddRecExpr *AddRec =
dyn_cast<SCEVAddRecExpr>(Coefficients)) {
const SCEV *Coeff = AddRec->getStepRecurrence(*SE);
const SCEVConstant *Constant = dyn_cast<SCEVConstant>(Coeff);
if (const SCEVMulExpr *Product = dyn_cast<SCEVMulExpr>(Coeff))
Constant = getConstantPart(Product);
if (!Constant)
return false;
APInt ConstCoeff = Constant->getValue()->getValue();
RunningGCD = APIntOps::GreatestCommonDivisor(RunningGCD, ConstCoeff.abs());
Coefficients = AddRec->getStart();
}
const SCEV *SrcConst = Coefficients;
Coefficients = Dst;
while (const SCEVAddRecExpr *AddRec =
dyn_cast<SCEVAddRecExpr>(Coefficients)) {
const SCEV *Coeff = AddRec->getStepRecurrence(*SE);
const SCEVConstant *Constant = dyn_cast<SCEVConstant>(Coeff);
if (const SCEVMulExpr *Product = dyn_cast<SCEVMulExpr>(Coeff))
Constant = getConstantPart(Product);
if (!Constant)
return false;
APInt ConstCoeff = Constant->getValue()->getValue();
RunningGCD = APIntOps::GreatestCommonDivisor(RunningGCD, ConstCoeff.abs());
Coefficients = AddRec->getStart();
}
const SCEV *DstConst = Coefficients;
APInt ExtraGCD = APInt::getNullValue(BitWidth);
const SCEV *Delta = SE->getMinusSCEV(DstConst, SrcConst);
DEBUG(dbgs() << " Delta = " << *Delta << "\n");
const SCEVConstant *Constant = dyn_cast<SCEVConstant>(Delta);
if (const SCEVAddExpr *Sum = dyn_cast<SCEVAddExpr>(Delta)) {
for (unsigned Op = 0, Ops = Sum->getNumOperands(); Op < Ops; Op++) {
const SCEV *Operand = Sum->getOperand(Op);
if (isa<SCEVConstant>(Operand)) {
assert(!Constant && "Surprised to find multiple constants");
Constant = cast<SCEVConstant>(Operand);
}
else if (const SCEVMulExpr *Product = dyn_cast<SCEVMulExpr>(Operand)) {
const SCEVConstant *ConstOp = getConstantPart(Product);
if (!ConstOp)
return false;
APInt ConstOpValue = ConstOp->getValue()->getValue();
ExtraGCD = APIntOps::GreatestCommonDivisor(ExtraGCD,
ConstOpValue.abs());
}
else
return false;
}
}
if (!Constant)
return false;
APInt ConstDelta = cast<SCEVConstant>(Constant)->getValue()->getValue();
DEBUG(dbgs() << " ConstDelta = " << ConstDelta << "\n");
if (ConstDelta == 0)
return false;
RunningGCD = APIntOps::GreatestCommonDivisor(RunningGCD, ExtraGCD);
DEBUG(dbgs() << " RunningGCD = " << RunningGCD << "\n");
APInt Remainder = ConstDelta.srem(RunningGCD);
if (Remainder != 0) {
++GCDindependence;
return true;
}
DEBUG(dbgs() << " ExtraGCD = " << ExtraGCD << '\n');
bool Improved = false;
Coefficients = Src;
while (const SCEVAddRecExpr *AddRec =
dyn_cast<SCEVAddRecExpr>(Coefficients)) {
Coefficients = AddRec->getStart();
const Loop *CurLoop = AddRec->getLoop();
RunningGCD = ExtraGCD;
const SCEV *SrcCoeff = AddRec->getStepRecurrence(*SE);
const SCEV *DstCoeff = SE->getMinusSCEV(SrcCoeff, SrcCoeff);
const SCEV *Inner = Src;
while (RunningGCD != 1 && isa<SCEVAddRecExpr>(Inner)) {
AddRec = cast<SCEVAddRecExpr>(Inner);
const SCEV *Coeff = AddRec->getStepRecurrence(*SE);
if (CurLoop == AddRec->getLoop())
; else {
if (const SCEVMulExpr *Product = dyn_cast<SCEVMulExpr>(Coeff))
Constant = getConstantPart(Product);
else
Constant = cast<SCEVConstant>(Coeff);
APInt ConstCoeff = Constant->getValue()->getValue();
RunningGCD = APIntOps::GreatestCommonDivisor(RunningGCD, ConstCoeff.abs());
}
Inner = AddRec->getStart();
}
Inner = Dst;
while (RunningGCD != 1 && isa<SCEVAddRecExpr>(Inner)) {
AddRec = cast<SCEVAddRecExpr>(Inner);
const SCEV *Coeff = AddRec->getStepRecurrence(*SE);
if (CurLoop == AddRec->getLoop())
DstCoeff = Coeff;
else {
if (const SCEVMulExpr *Product = dyn_cast<SCEVMulExpr>(Coeff))
Constant = getConstantPart(Product);
else
Constant = cast<SCEVConstant>(Coeff);
APInt ConstCoeff = Constant->getValue()->getValue();
RunningGCD = APIntOps::GreatestCommonDivisor(RunningGCD, ConstCoeff.abs());
}
Inner = AddRec->getStart();
}
Delta = SE->getMinusSCEV(SrcCoeff, DstCoeff);
if (const SCEVMulExpr *Product = dyn_cast<SCEVMulExpr>(Delta))
Constant = getConstantPart(Product);
else if (isa<SCEVConstant>(Delta))
Constant = cast<SCEVConstant>(Delta);
else {
continue;
}
APInt ConstCoeff = Constant->getValue()->getValue();
RunningGCD = APIntOps::GreatestCommonDivisor(RunningGCD, ConstCoeff.abs());
DEBUG(dbgs() << "\tRunningGCD = " << RunningGCD << "\n");
if (RunningGCD != 0) {
Remainder = ConstDelta.srem(RunningGCD);
DEBUG(dbgs() << "\tRemainder = " << Remainder << "\n");
if (Remainder != 0) {
unsigned Level = mapSrcLoop(CurLoop);
Result.DV[Level - 1].Direction &= unsigned(~Dependence::DVEntry::EQ);
Improved = true;
}
}
}
if (Improved)
++GCDsuccesses;
DEBUG(dbgs() << "all done\n");
return false;
}
bool DependenceAnalysis::banerjeeMIVtest(const SCEV *Src,
const SCEV *Dst,
const SmallBitVector &Loops,
FullDependence &Result) const {
DEBUG(dbgs() << "starting Banerjee\n");
++BanerjeeApplications;
DEBUG(dbgs() << " Src = " << *Src << '\n');
const SCEV *A0;
CoefficientInfo *A = collectCoeffInfo(Src, true, A0);
DEBUG(dbgs() << " Dst = " << *Dst << '\n');
const SCEV *B0;
CoefficientInfo *B = collectCoeffInfo(Dst, false, B0);
BoundInfo *Bound = new BoundInfo[MaxLevels + 1];
const SCEV *Delta = SE->getMinusSCEV(B0, A0);
DEBUG(dbgs() << "\tDelta = " << *Delta << '\n');
DEBUG(dbgs() << "\tBounds[*]\n");
for (unsigned K = 1; K <= MaxLevels; ++K) {
Bound[K].Iterations = A[K].Iterations ? A[K].Iterations : B[K].Iterations;
Bound[K].Direction = Dependence::DVEntry::ALL;
Bound[K].DirSet = Dependence::DVEntry::NONE;
findBoundsALL(A, B, Bound, K);
#ifndef NDEBUG
DEBUG(dbgs() << "\t " << K << '\t');
if (Bound[K].Lower[Dependence::DVEntry::ALL])
DEBUG(dbgs() << *Bound[K].Lower[Dependence::DVEntry::ALL] << '\t');
else
DEBUG(dbgs() << "-inf\t");
if (Bound[K].Upper[Dependence::DVEntry::ALL])
DEBUG(dbgs() << *Bound[K].Upper[Dependence::DVEntry::ALL] << '\n');
else
DEBUG(dbgs() << "+inf\n");
#endif
}
bool Disproved = false;
if (testBounds(Dependence::DVEntry::ALL, 0, Bound, Delta)) {
unsigned DepthExpanded = 0;
unsigned NewDeps = exploreDirections(1, A, B, Bound,
Loops, DepthExpanded, Delta);
if (NewDeps > 0) {
bool Improved = false;
for (unsigned K = 1; K <= CommonLevels; ++K) {
if (Loops[K]) {
unsigned Old = Result.DV[K - 1].Direction;
Result.DV[K - 1].Direction = Old & Bound[K].DirSet;
Improved |= Old != Result.DV[K - 1].Direction;
if (!Result.DV[K - 1].Direction) {
Improved = false;
Disproved = true;
break;
}
}
}
if (Improved)
++BanerjeeSuccesses;
}
else {
++BanerjeeIndependence;
Disproved = true;
}
}
else {
++BanerjeeIndependence;
Disproved = true;
}
delete [] Bound;
delete [] A;
delete [] B;
return Disproved;
}
unsigned DependenceAnalysis::exploreDirections(unsigned Level,
CoefficientInfo *A,
CoefficientInfo *B,
BoundInfo *Bound,
const SmallBitVector &Loops,
unsigned &DepthExpanded,
const SCEV *Delta) const {
if (Level > CommonLevels) {
DEBUG(dbgs() << "\t[");
for (unsigned K = 1; K <= CommonLevels; ++K) {
if (Loops[K]) {
Bound[K].DirSet |= Bound[K].Direction;
#ifndef NDEBUG
switch (Bound[K].Direction) {
case Dependence::DVEntry::LT:
DEBUG(dbgs() << " <");
break;
case Dependence::DVEntry::EQ:
DEBUG(dbgs() << " =");
break;
case Dependence::DVEntry::GT:
DEBUG(dbgs() << " >");
break;
case Dependence::DVEntry::ALL:
DEBUG(dbgs() << " *");
break;
default:
llvm_unreachable("unexpected Bound[K].Direction");
}
#endif
}
}
DEBUG(dbgs() << " ]\n");
return 1;
}
if (Loops[Level]) {
if (Level > DepthExpanded) {
DepthExpanded = Level;
findBoundsLT(A, B, Bound, Level);
findBoundsGT(A, B, Bound, Level);
findBoundsEQ(A, B, Bound, Level);
#ifndef NDEBUG
DEBUG(dbgs() << "\tBound for level = " << Level << '\n');
DEBUG(dbgs() << "\t <\t");
if (Bound[Level].Lower[Dependence::DVEntry::LT])
DEBUG(dbgs() << *Bound[Level].Lower[Dependence::DVEntry::LT] << '\t');
else
DEBUG(dbgs() << "-inf\t");
if (Bound[Level].Upper[Dependence::DVEntry::LT])
DEBUG(dbgs() << *Bound[Level].Upper[Dependence::DVEntry::LT] << '\n');
else
DEBUG(dbgs() << "+inf\n");
DEBUG(dbgs() << "\t =\t");
if (Bound[Level].Lower[Dependence::DVEntry::EQ])
DEBUG(dbgs() << *Bound[Level].Lower[Dependence::DVEntry::EQ] << '\t');
else
DEBUG(dbgs() << "-inf\t");
if (Bound[Level].Upper[Dependence::DVEntry::EQ])
DEBUG(dbgs() << *Bound[Level].Upper[Dependence::DVEntry::EQ] << '\n');
else
DEBUG(dbgs() << "+inf\n");
DEBUG(dbgs() << "\t >\t");
if (Bound[Level].Lower[Dependence::DVEntry::GT])
DEBUG(dbgs() << *Bound[Level].Lower[Dependence::DVEntry::GT] << '\t');
else
DEBUG(dbgs() << "-inf\t");
if (Bound[Level].Upper[Dependence::DVEntry::GT])
DEBUG(dbgs() << *Bound[Level].Upper[Dependence::DVEntry::GT] << '\n');
else
DEBUG(dbgs() << "+inf\n");
#endif
}
unsigned NewDeps = 0;
if (testBounds(Dependence::DVEntry::LT, Level, Bound, Delta))
NewDeps += exploreDirections(Level + 1, A, B, Bound,
Loops, DepthExpanded, Delta);
if (testBounds(Dependence::DVEntry::EQ, Level, Bound, Delta))
NewDeps += exploreDirections(Level + 1, A, B, Bound,
Loops, DepthExpanded, Delta);
if (testBounds(Dependence::DVEntry::GT, Level, Bound, Delta))
NewDeps += exploreDirections(Level + 1, A, B, Bound,
Loops, DepthExpanded, Delta);
Bound[Level].Direction = Dependence::DVEntry::ALL;
return NewDeps;
}
else
return exploreDirections(Level + 1, A, B, Bound, Loops, DepthExpanded, Delta);
}
bool DependenceAnalysis::testBounds(unsigned char DirKind,
unsigned Level,
BoundInfo *Bound,
const SCEV *Delta) const {
Bound[Level].Direction = DirKind;
if (const SCEV *LowerBound = getLowerBound(Bound))
if (isKnownPredicate(CmpInst::ICMP_SGT, LowerBound, Delta))
return false;
if (const SCEV *UpperBound = getUpperBound(Bound))
if (isKnownPredicate(CmpInst::ICMP_SGT, Delta, UpperBound))
return false;
return true;
}
void DependenceAnalysis::findBoundsALL(CoefficientInfo *A,
CoefficientInfo *B,
BoundInfo *Bound,
unsigned K) const {
Bound[K].Lower[Dependence::DVEntry::ALL] = nullptr; Bound[K].Upper[Dependence::DVEntry::ALL] = nullptr; if (Bound[K].Iterations) {
Bound[K].Lower[Dependence::DVEntry::ALL] =
SE->getMulExpr(SE->getMinusSCEV(A[K].NegPart, B[K].PosPart),
Bound[K].Iterations);
Bound[K].Upper[Dependence::DVEntry::ALL] =
SE->getMulExpr(SE->getMinusSCEV(A[K].PosPart, B[K].NegPart),
Bound[K].Iterations);
}
else {
if (isKnownPredicate(CmpInst::ICMP_EQ, A[K].NegPart, B[K].PosPart))
Bound[K].Lower[Dependence::DVEntry::ALL] =
SE->getZero(A[K].Coeff->getType());
if (isKnownPredicate(CmpInst::ICMP_EQ, A[K].PosPart, B[K].NegPart))
Bound[K].Upper[Dependence::DVEntry::ALL] =
SE->getZero(A[K].Coeff->getType());
}
}
void DependenceAnalysis::findBoundsEQ(CoefficientInfo *A,
CoefficientInfo *B,
BoundInfo *Bound,
unsigned K) const {
Bound[K].Lower[Dependence::DVEntry::EQ] = nullptr; Bound[K].Upper[Dependence::DVEntry::EQ] = nullptr; if (Bound[K].Iterations) {
const SCEV *Delta = SE->getMinusSCEV(A[K].Coeff, B[K].Coeff);
const SCEV *NegativePart = getNegativePart(Delta);
Bound[K].Lower[Dependence::DVEntry::EQ] =
SE->getMulExpr(NegativePart, Bound[K].Iterations);
const SCEV *PositivePart = getPositivePart(Delta);
Bound[K].Upper[Dependence::DVEntry::EQ] =
SE->getMulExpr(PositivePart, Bound[K].Iterations);
}
else {
const SCEV *Delta = SE->getMinusSCEV(A[K].Coeff, B[K].Coeff);
const SCEV *NegativePart = getNegativePart(Delta);
if (NegativePart->isZero())
Bound[K].Lower[Dependence::DVEntry::EQ] = NegativePart; const SCEV *PositivePart = getPositivePart(Delta);
if (PositivePart->isZero())
Bound[K].Upper[Dependence::DVEntry::EQ] = PositivePart; }
}
void DependenceAnalysis::findBoundsLT(CoefficientInfo *A,
CoefficientInfo *B,
BoundInfo *Bound,
unsigned K) const {
Bound[K].Lower[Dependence::DVEntry::LT] = nullptr; Bound[K].Upper[Dependence::DVEntry::LT] = nullptr; if (Bound[K].Iterations) {
const SCEV *Iter_1 = SE->getMinusSCEV(
Bound[K].Iterations, SE->getOne(Bound[K].Iterations->getType()));
const SCEV *NegPart =
getNegativePart(SE->getMinusSCEV(A[K].NegPart, B[K].Coeff));
Bound[K].Lower[Dependence::DVEntry::LT] =
SE->getMinusSCEV(SE->getMulExpr(NegPart, Iter_1), B[K].Coeff);
const SCEV *PosPart =
getPositivePart(SE->getMinusSCEV(A[K].PosPart, B[K].Coeff));
Bound[K].Upper[Dependence::DVEntry::LT] =
SE->getMinusSCEV(SE->getMulExpr(PosPart, Iter_1), B[K].Coeff);
}
else {
const SCEV *NegPart =
getNegativePart(SE->getMinusSCEV(A[K].NegPart, B[K].Coeff));
if (NegPart->isZero())
Bound[K].Lower[Dependence::DVEntry::LT] = SE->getNegativeSCEV(B[K].Coeff);
const SCEV *PosPart =
getPositivePart(SE->getMinusSCEV(A[K].PosPart, B[K].Coeff));
if (PosPart->isZero())
Bound[K].Upper[Dependence::DVEntry::LT] = SE->getNegativeSCEV(B[K].Coeff);
}
}
void DependenceAnalysis::findBoundsGT(CoefficientInfo *A,
CoefficientInfo *B,
BoundInfo *Bound,
unsigned K) const {
Bound[K].Lower[Dependence::DVEntry::GT] = nullptr; Bound[K].Upper[Dependence::DVEntry::GT] = nullptr; if (Bound[K].Iterations) {
const SCEV *Iter_1 = SE->getMinusSCEV(
Bound[K].Iterations, SE->getOne(Bound[K].Iterations->getType()));
const SCEV *NegPart =
getNegativePart(SE->getMinusSCEV(A[K].Coeff, B[K].PosPart));
Bound[K].Lower[Dependence::DVEntry::GT] =
SE->getAddExpr(SE->getMulExpr(NegPart, Iter_1), A[K].Coeff);
const SCEV *PosPart =
getPositivePart(SE->getMinusSCEV(A[K].Coeff, B[K].NegPart));
Bound[K].Upper[Dependence::DVEntry::GT] =
SE->getAddExpr(SE->getMulExpr(PosPart, Iter_1), A[K].Coeff);
}
else {
const SCEV *NegPart = getNegativePart(SE->getMinusSCEV(A[K].Coeff, B[K].PosPart));
if (NegPart->isZero())
Bound[K].Lower[Dependence::DVEntry::GT] = A[K].Coeff;
const SCEV *PosPart = getPositivePart(SE->getMinusSCEV(A[K].Coeff, B[K].NegPart));
if (PosPart->isZero())
Bound[K].Upper[Dependence::DVEntry::GT] = A[K].Coeff;
}
}
const SCEV *DependenceAnalysis::getPositivePart(const SCEV *X) const {
return SE->getSMaxExpr(X, SE->getZero(X->getType()));
}
const SCEV *DependenceAnalysis::getNegativePart(const SCEV *X) const {
return SE->getSMinExpr(X, SE->getZero(X->getType()));
}
DependenceAnalysis::CoefficientInfo *
DependenceAnalysis::collectCoeffInfo(const SCEV *Subscript,
bool SrcFlag,
const SCEV *&Constant) const {
const SCEV *Zero = SE->getZero(Subscript->getType());
CoefficientInfo *CI = new CoefficientInfo[MaxLevels + 1];
for (unsigned K = 1; K <= MaxLevels; ++K) {
CI[K].Coeff = Zero;
CI[K].PosPart = Zero;
CI[K].NegPart = Zero;
CI[K].Iterations = nullptr;
}
while (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Subscript)) {
const Loop *L = AddRec->getLoop();
unsigned K = SrcFlag ? mapSrcLoop(L) : mapDstLoop(L);
CI[K].Coeff = AddRec->getStepRecurrence(*SE);
CI[K].PosPart = getPositivePart(CI[K].Coeff);
CI[K].NegPart = getNegativePart(CI[K].Coeff);
CI[K].Iterations = collectUpperBound(L, Subscript->getType());
Subscript = AddRec->getStart();
}
Constant = Subscript;
#ifndef NDEBUG
DEBUG(dbgs() << "\tCoefficient Info\n");
for (unsigned K = 1; K <= MaxLevels; ++K) {
DEBUG(dbgs() << "\t " << K << "\t" << *CI[K].Coeff);
DEBUG(dbgs() << "\tPos Part = ");
DEBUG(dbgs() << *CI[K].PosPart);
DEBUG(dbgs() << "\tNeg Part = ");
DEBUG(dbgs() << *CI[K].NegPart);
DEBUG(dbgs() << "\tUpper Bound = ");
if (CI[K].Iterations)
DEBUG(dbgs() << *CI[K].Iterations);
else
DEBUG(dbgs() << "+inf");
DEBUG(dbgs() << '\n');
}
DEBUG(dbgs() << "\t Constant = " << *Subscript << '\n');
#endif
return CI;
}
const SCEV *DependenceAnalysis::getLowerBound(BoundInfo *Bound) const {
const SCEV *Sum = Bound[1].Lower[Bound[1].Direction];
for (unsigned K = 2; Sum && K <= MaxLevels; ++K) {
if (Bound[K].Lower[Bound[K].Direction])
Sum = SE->getAddExpr(Sum, Bound[K].Lower[Bound[K].Direction]);
else
Sum = nullptr;
}
return Sum;
}
const SCEV *DependenceAnalysis::getUpperBound(BoundInfo *Bound) const {
const SCEV *Sum = Bound[1].Upper[Bound[1].Direction];
for (unsigned K = 2; Sum && K <= MaxLevels; ++K) {
if (Bound[K].Upper[Bound[K].Direction])
Sum = SE->getAddExpr(Sum, Bound[K].Upper[Bound[K].Direction]);
else
Sum = nullptr;
}
return Sum;
}
const SCEV *DependenceAnalysis::findCoefficient(const SCEV *Expr,
const Loop *TargetLoop) const {
const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Expr);
if (!AddRec)
return SE->getZero(Expr->getType());
if (AddRec->getLoop() == TargetLoop)
return AddRec->getStepRecurrence(*SE);
return findCoefficient(AddRec->getStart(), TargetLoop);
}
const SCEV *DependenceAnalysis::zeroCoefficient(const SCEV *Expr,
const Loop *TargetLoop) const {
const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Expr);
if (!AddRec)
return Expr; if (AddRec->getLoop() == TargetLoop)
return AddRec->getStart();
return SE->getAddRecExpr(zeroCoefficient(AddRec->getStart(), TargetLoop),
AddRec->getStepRecurrence(*SE),
AddRec->getLoop(),
AddRec->getNoWrapFlags());
}
const SCEV *DependenceAnalysis::addToCoefficient(const SCEV *Expr,
const Loop *TargetLoop,
const SCEV *Value) const {
const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Expr);
if (!AddRec) return SE->getAddRecExpr(Expr,
Value,
TargetLoop,
SCEV::FlagAnyWrap); if (AddRec->getLoop() == TargetLoop) {
const SCEV *Sum = SE->getAddExpr(AddRec->getStepRecurrence(*SE), Value);
if (Sum->isZero())
return AddRec->getStart();
return SE->getAddRecExpr(AddRec->getStart(),
Sum,
AddRec->getLoop(),
AddRec->getNoWrapFlags());
}
if (SE->isLoopInvariant(AddRec, TargetLoop))
return SE->getAddRecExpr(AddRec, Value, TargetLoop, SCEV::FlagAnyWrap);
return SE->getAddRecExpr(
addToCoefficient(AddRec->getStart(), TargetLoop, Value),
AddRec->getStepRecurrence(*SE), AddRec->getLoop(),
AddRec->getNoWrapFlags());
}
bool DependenceAnalysis::propagate(const SCEV *&Src,
const SCEV *&Dst,
SmallBitVector &Loops,
SmallVectorImpl<Constraint> &Constraints,
bool &Consistent) {
bool Result = false;
for (int LI = Loops.find_first(); LI >= 0; LI = Loops.find_next(LI)) {
DEBUG(dbgs() << "\t Constraint[" << LI << "] is");
DEBUG(Constraints[LI].dump(dbgs()));
if (Constraints[LI].isDistance())
Result |= propagateDistance(Src, Dst, Constraints[LI], Consistent);
else if (Constraints[LI].isLine())
Result |= propagateLine(Src, Dst, Constraints[LI], Consistent);
else if (Constraints[LI].isPoint())
Result |= propagatePoint(Src, Dst, Constraints[LI]);
}
return Result;
}
bool DependenceAnalysis::propagateDistance(const SCEV *&Src,
const SCEV *&Dst,
Constraint &CurConstraint,
bool &Consistent) {
const Loop *CurLoop = CurConstraint.getAssociatedLoop();
DEBUG(dbgs() << "\t\tSrc is " << *Src << "\n");
const SCEV *A_K = findCoefficient(Src, CurLoop);
if (A_K->isZero())
return false;
const SCEV *DA_K = SE->getMulExpr(A_K, CurConstraint.getD());
Src = SE->getMinusSCEV(Src, DA_K);
Src = zeroCoefficient(Src, CurLoop);
DEBUG(dbgs() << "\t\tnew Src is " << *Src << "\n");
DEBUG(dbgs() << "\t\tDst is " << *Dst << "\n");
Dst = addToCoefficient(Dst, CurLoop, SE->getNegativeSCEV(A_K));
DEBUG(dbgs() << "\t\tnew Dst is " << *Dst << "\n");
if (!findCoefficient(Dst, CurLoop)->isZero())
Consistent = false;
return true;
}
bool DependenceAnalysis::propagateLine(const SCEV *&Src,
const SCEV *&Dst,
Constraint &CurConstraint,
bool &Consistent) {
const Loop *CurLoop = CurConstraint.getAssociatedLoop();
const SCEV *A = CurConstraint.getA();
const SCEV *B = CurConstraint.getB();
const SCEV *C = CurConstraint.getC();
DEBUG(dbgs() << "\t\tA = " << *A << ", B = " << *B << ", C = " << *C << "\n");
DEBUG(dbgs() << "\t\tSrc = " << *Src << "\n");
DEBUG(dbgs() << "\t\tDst = " << *Dst << "\n");
if (A->isZero()) {
const SCEVConstant *Bconst = dyn_cast<SCEVConstant>(B);
const SCEVConstant *Cconst = dyn_cast<SCEVConstant>(C);
if (!Bconst || !Cconst) return false;
APInt Beta = Bconst->getValue()->getValue();
APInt Charlie = Cconst->getValue()->getValue();
APInt CdivB = Charlie.sdiv(Beta);
assert(Charlie.srem(Beta) == 0 && "C should be evenly divisible by B");
const SCEV *AP_K = findCoefficient(Dst, CurLoop);
Src = SE->getMinusSCEV(Src, SE->getMulExpr(AP_K, SE->getConstant(CdivB)));
Dst = zeroCoefficient(Dst, CurLoop);
if (!findCoefficient(Src, CurLoop)->isZero())
Consistent = false;
}
else if (B->isZero()) {
const SCEVConstant *Aconst = dyn_cast<SCEVConstant>(A);
const SCEVConstant *Cconst = dyn_cast<SCEVConstant>(C);
if (!Aconst || !Cconst) return false;
APInt Alpha = Aconst->getValue()->getValue();
APInt Charlie = Cconst->getValue()->getValue();
APInt CdivA = Charlie.sdiv(Alpha);
assert(Charlie.srem(Alpha) == 0 && "C should be evenly divisible by A");
const SCEV *A_K = findCoefficient(Src, CurLoop);
Src = SE->getAddExpr(Src, SE->getMulExpr(A_K, SE->getConstant(CdivA)));
Src = zeroCoefficient(Src, CurLoop);
if (!findCoefficient(Dst, CurLoop)->isZero())
Consistent = false;
}
else if (isKnownPredicate(CmpInst::ICMP_EQ, A, B)) {
const SCEVConstant *Aconst = dyn_cast<SCEVConstant>(A);
const SCEVConstant *Cconst = dyn_cast<SCEVConstant>(C);
if (!Aconst || !Cconst) return false;
APInt Alpha = Aconst->getValue()->getValue();
APInt Charlie = Cconst->getValue()->getValue();
APInt CdivA = Charlie.sdiv(Alpha);
assert(Charlie.srem(Alpha) == 0 && "C should be evenly divisible by A");
const SCEV *A_K = findCoefficient(Src, CurLoop);
Src = SE->getAddExpr(Src, SE->getMulExpr(A_K, SE->getConstant(CdivA)));
Src = zeroCoefficient(Src, CurLoop);
Dst = addToCoefficient(Dst, CurLoop, A_K);
if (!findCoefficient(Dst, CurLoop)->isZero())
Consistent = false;
}
else {
const SCEV *A_K = findCoefficient(Src, CurLoop);
Src = SE->getMulExpr(Src, A);
Dst = SE->getMulExpr(Dst, A);
Src = SE->getAddExpr(Src, SE->getMulExpr(A_K, C));
Src = zeroCoefficient(Src, CurLoop);
Dst = addToCoefficient(Dst, CurLoop, SE->getMulExpr(A_K, B));
if (!findCoefficient(Dst, CurLoop)->isZero())
Consistent = false;
}
DEBUG(dbgs() << "\t\tnew Src = " << *Src << "\n");
DEBUG(dbgs() << "\t\tnew Dst = " << *Dst << "\n");
return true;
}
bool DependenceAnalysis::propagatePoint(const SCEV *&Src,
const SCEV *&Dst,
Constraint &CurConstraint) {
const Loop *CurLoop = CurConstraint.getAssociatedLoop();
const SCEV *A_K = findCoefficient(Src, CurLoop);
const SCEV *AP_K = findCoefficient(Dst, CurLoop);
const SCEV *XA_K = SE->getMulExpr(A_K, CurConstraint.getX());
const SCEV *YAP_K = SE->getMulExpr(AP_K, CurConstraint.getY());
DEBUG(dbgs() << "\t\tSrc is " << *Src << "\n");
Src = SE->getAddExpr(Src, SE->getMinusSCEV(XA_K, YAP_K));
Src = zeroCoefficient(Src, CurLoop);
DEBUG(dbgs() << "\t\tnew Src is " << *Src << "\n");
DEBUG(dbgs() << "\t\tDst is " << *Dst << "\n");
Dst = zeroCoefficient(Dst, CurLoop);
DEBUG(dbgs() << "\t\tnew Dst is " << *Dst << "\n");
return true;
}
void DependenceAnalysis::updateDirection(Dependence::DVEntry &Level,
const Constraint &CurConstraint
) const {
DEBUG(dbgs() << "\tUpdate direction, constraint =");
DEBUG(CurConstraint.dump(dbgs()));
if (CurConstraint.isAny())
; else if (CurConstraint.isDistance()) {
Level.Scalar = false;
Level.Distance = CurConstraint.getD();
unsigned NewDirection = Dependence::DVEntry::NONE;
if (!SE->isKnownNonZero(Level.Distance)) NewDirection = Dependence::DVEntry::EQ;
if (!SE->isKnownNonPositive(Level.Distance)) NewDirection |= Dependence::DVEntry::LT;
if (!SE->isKnownNonNegative(Level.Distance)) NewDirection |= Dependence::DVEntry::GT;
Level.Direction &= NewDirection;
}
else if (CurConstraint.isLine()) {
Level.Scalar = false;
Level.Distance = nullptr;
}
else if (CurConstraint.isPoint()) {
Level.Scalar = false;
Level.Distance = nullptr;
unsigned NewDirection = Dependence::DVEntry::NONE;
if (!isKnownPredicate(CmpInst::ICMP_NE,
CurConstraint.getY(),
CurConstraint.getX()))
NewDirection |= Dependence::DVEntry::EQ;
if (!isKnownPredicate(CmpInst::ICMP_SLE,
CurConstraint.getY(),
CurConstraint.getX()))
NewDirection |= Dependence::DVEntry::LT;
if (!isKnownPredicate(CmpInst::ICMP_SGE,
CurConstraint.getY(),
CurConstraint.getX()))
NewDirection |= Dependence::DVEntry::GT;
Level.Direction &= NewDirection;
}
else
llvm_unreachable("constraint has unexpected kind");
}
bool DependenceAnalysis::tryDelinearize(Instruction *Src,
Instruction *Dst,
SmallVectorImpl<Subscript> &Pair)
{
Value *SrcPtr = getPointerOperand(Src);
Value *DstPtr = getPointerOperand(Dst);
Loop *SrcLoop = LI->getLoopFor(Src->getParent());
Loop *DstLoop = LI->getLoopFor(Dst->getParent());
const SCEV *SrcAccessFn =
SE->getSCEVAtScope(SrcPtr, SrcLoop);
const SCEV *DstAccessFn =
SE->getSCEVAtScope(DstPtr, DstLoop);
const SCEVUnknown *SrcBase =
dyn_cast<SCEVUnknown>(SE->getPointerBase(SrcAccessFn));
const SCEVUnknown *DstBase =
dyn_cast<SCEVUnknown>(SE->getPointerBase(DstAccessFn));
if (!SrcBase || !DstBase || SrcBase != DstBase)
return false;
const SCEV *ElementSize = SE->getElementSize(Src);
if (ElementSize != SE->getElementSize(Dst))
return false;
const SCEV *SrcSCEV = SE->getMinusSCEV(SrcAccessFn, SrcBase);
const SCEV *DstSCEV = SE->getMinusSCEV(DstAccessFn, DstBase);
const SCEVAddRecExpr *SrcAR = dyn_cast<SCEVAddRecExpr>(SrcSCEV);
const SCEVAddRecExpr *DstAR = dyn_cast<SCEVAddRecExpr>(DstSCEV);
if (!SrcAR || !DstAR || !SrcAR->isAffine() || !DstAR->isAffine())
return false;
SmallVector<const SCEV *, 4> Terms;
SE->collectParametricTerms(SrcAR, Terms);
SE->collectParametricTerms(DstAR, Terms);
SmallVector<const SCEV *, 4> Sizes;
SE->findArrayDimensions(Terms, Sizes, ElementSize);
SmallVector<const SCEV *, 4> SrcSubscripts, DstSubscripts;
SE->computeAccessFunctions(SrcAR, SrcSubscripts, Sizes);
SE->computeAccessFunctions(DstAR, DstSubscripts, Sizes);
if (SrcSubscripts.size() < 2 || DstSubscripts.size() < 2 ||
SrcSubscripts.size() != DstSubscripts.size())
return false;
int size = SrcSubscripts.size();
DEBUG({
dbgs() << "\nSrcSubscripts: ";
for (int i = 0; i < size; i++)
dbgs() << *SrcSubscripts[i];
dbgs() << "\nDstSubscripts: ";
for (int i = 0; i < size; i++)
dbgs() << *DstSubscripts[i];
});
Pair.resize(size);
for (int i = 0; i < size; ++i) {
Pair[i].Src = SrcSubscripts[i];
Pair[i].Dst = DstSubscripts[i];
unifySubscriptType(&Pair[i]);
}
return true;
}
#ifndef NDEBUG
static void dumpSmallBitVector(SmallBitVector &BV) {
dbgs() << "{";
for (int VI = BV.find_first(); VI >= 0; VI = BV.find_next(VI)) {
dbgs() << VI;
if (BV.find_next(VI) >= 0)
dbgs() << ' ';
}
dbgs() << "}\n";
}
#endif
std::unique_ptr<Dependence>
DependenceAnalysis::depends(Instruction *Src, Instruction *Dst,
bool PossiblyLoopIndependent) {
if (Src == Dst)
PossiblyLoopIndependent = false;
if ((!Src->mayReadFromMemory() && !Src->mayWriteToMemory()) ||
(!Dst->mayReadFromMemory() && !Dst->mayWriteToMemory()))
return nullptr;
if (!isLoadOrStore(Src) || !isLoadOrStore(Dst)) {
DEBUG(dbgs() << "can only handle simple loads and stores\n");
return make_unique<Dependence>(Src, Dst);
}
Value *SrcPtr = getPointerOperand(Src);
Value *DstPtr = getPointerOperand(Dst);
switch (underlyingObjectsAlias(AA, F->getParent()->getDataLayout(), DstPtr,
SrcPtr)) {
case MayAlias:
case PartialAlias:
DEBUG(dbgs() << "can't analyze may or partial alias\n");
return make_unique<Dependence>(Src, Dst);
case NoAlias:
DEBUG(dbgs() << "no alias\n");
return nullptr;
case MustAlias:
break; }
establishNestingLevels(Src, Dst);
DEBUG(dbgs() << " common nesting levels = " << CommonLevels << "\n");
DEBUG(dbgs() << " maximum nesting levels = " << MaxLevels << "\n");
FullDependence Result(Src, Dst, PossiblyLoopIndependent, CommonLevels);
++TotalArrayPairs;
bool UsefulGEP = false;
GEPOperator *SrcGEP = dyn_cast<GEPOperator>(SrcPtr);
GEPOperator *DstGEP = dyn_cast<GEPOperator>(DstPtr);
if (SrcGEP && DstGEP &&
SrcGEP->getPointerOperandType() == DstGEP->getPointerOperandType()) {
const SCEV *SrcPtrSCEV = SE->getSCEV(SrcGEP->getPointerOperand());
const SCEV *DstPtrSCEV = SE->getSCEV(DstGEP->getPointerOperand());
DEBUG(dbgs() << " SrcPtrSCEV = " << *SrcPtrSCEV << "\n");
DEBUG(dbgs() << " DstPtrSCEV = " << *DstPtrSCEV << "\n");
UsefulGEP = isLoopInvariant(SrcPtrSCEV, LI->getLoopFor(Src->getParent())) &&
isLoopInvariant(DstPtrSCEV, LI->getLoopFor(Dst->getParent())) &&
(SrcGEP->getNumOperands() == DstGEP->getNumOperands());
}
unsigned Pairs = UsefulGEP ? SrcGEP->idx_end() - SrcGEP->idx_begin() : 1;
SmallVector<Subscript, 4> Pair(Pairs);
if (UsefulGEP) {
DEBUG(dbgs() << " using GEPs\n");
unsigned P = 0;
for (GEPOperator::const_op_iterator SrcIdx = SrcGEP->idx_begin(),
SrcEnd = SrcGEP->idx_end(),
DstIdx = DstGEP->idx_begin();
SrcIdx != SrcEnd;
++SrcIdx, ++DstIdx, ++P) {
Pair[P].Src = SE->getSCEV(*SrcIdx);
Pair[P].Dst = SE->getSCEV(*DstIdx);
unifySubscriptType(&Pair[P]);
}
}
else {
DEBUG(dbgs() << " ignoring GEPs\n");
const SCEV *SrcSCEV = SE->getSCEV(SrcPtr);
const SCEV *DstSCEV = SE->getSCEV(DstPtr);
DEBUG(dbgs() << " SrcSCEV = " << *SrcSCEV << "\n");
DEBUG(dbgs() << " DstSCEV = " << *DstSCEV << "\n");
Pair[0].Src = SrcSCEV;
Pair[0].Dst = DstSCEV;
}
if (Delinearize && CommonLevels > 1) {
if (tryDelinearize(Src, Dst, Pair)) {
DEBUG(dbgs() << " delinerized GEP\n");
Pairs = Pair.size();
}
}
for (unsigned P = 0; P < Pairs; ++P) {
Pair[P].Loops.resize(MaxLevels + 1);
Pair[P].GroupLoops.resize(MaxLevels + 1);
Pair[P].Group.resize(Pairs);
removeMatchingExtensions(&Pair[P]);
Pair[P].Classification =
classifyPair(Pair[P].Src, LI->getLoopFor(Src->getParent()),
Pair[P].Dst, LI->getLoopFor(Dst->getParent()),
Pair[P].Loops);
Pair[P].GroupLoops = Pair[P].Loops;
Pair[P].Group.set(P);
DEBUG(dbgs() << " subscript " << P << "\n");
DEBUG(dbgs() << "\tsrc = " << *Pair[P].Src << "\n");
DEBUG(dbgs() << "\tdst = " << *Pair[P].Dst << "\n");
DEBUG(dbgs() << "\tclass = " << Pair[P].Classification << "\n");
DEBUG(dbgs() << "\tloops = ");
DEBUG(dumpSmallBitVector(Pair[P].Loops));
}
SmallBitVector Separable(Pairs);
SmallBitVector Coupled(Pairs);
for (unsigned SI = 0; SI < Pairs; ++SI) {
if (Pair[SI].Classification == Subscript::NonLinear) {
++NonlinearSubscriptPairs;
collectCommonLoops(Pair[SI].Src,
LI->getLoopFor(Src->getParent()),
Pair[SI].Loops);
collectCommonLoops(Pair[SI].Dst,
LI->getLoopFor(Dst->getParent()),
Pair[SI].Loops);
Result.Consistent = false;
} else if (Pair[SI].Classification == Subscript::ZIV) {
Separable.set(SI);
}
else {
bool Done = true;
for (unsigned SJ = SI + 1; SJ < Pairs; ++SJ) {
SmallBitVector Intersection = Pair[SI].GroupLoops;
Intersection &= Pair[SJ].GroupLoops;
if (Intersection.any()) {
Pair[SJ].GroupLoops |= Pair[SI].GroupLoops;
Pair[SJ].Group |= Pair[SI].Group;
Done = false;
}
}
if (Done) {
if (Pair[SI].Group.count() == 1) {
Separable.set(SI);
++SeparableSubscriptPairs;
}
else {
Coupled.set(SI);
++CoupledSubscriptPairs;
}
}
}
}
DEBUG(dbgs() << " Separable = ");
DEBUG(dumpSmallBitVector(Separable));
DEBUG(dbgs() << " Coupled = ");
DEBUG(dumpSmallBitVector(Coupled));
Constraint NewConstraint;
NewConstraint.setAny(SE);
for (int SI = Separable.find_first(); SI >= 0; SI = Separable.find_next(SI)) {
DEBUG(dbgs() << "testing subscript " << SI);
switch (Pair[SI].Classification) {
case Subscript::ZIV:
DEBUG(dbgs() << ", ZIV\n");
if (testZIV(Pair[SI].Src, Pair[SI].Dst, Result))
return nullptr;
break;
case Subscript::SIV: {
DEBUG(dbgs() << ", SIV\n");
unsigned Level;
const SCEV *SplitIter = nullptr;
if (testSIV(Pair[SI].Src, Pair[SI].Dst, Level, Result, NewConstraint,
SplitIter))
return nullptr;
break;
}
case Subscript::RDIV:
DEBUG(dbgs() << ", RDIV\n");
if (testRDIV(Pair[SI].Src, Pair[SI].Dst, Result))
return nullptr;
break;
case Subscript::MIV:
DEBUG(dbgs() << ", MIV\n");
if (testMIV(Pair[SI].Src, Pair[SI].Dst, Pair[SI].Loops, Result))
return nullptr;
break;
default:
llvm_unreachable("subscript has unexpected classification");
}
}
if (Coupled.count()) {
DEBUG(dbgs() << "starting on coupled subscripts\n");
DEBUG(dbgs() << "MaxLevels + 1 = " << MaxLevels + 1 << "\n");
SmallVector<Constraint, 4> Constraints(MaxLevels + 1);
for (unsigned II = 0; II <= MaxLevels; ++II)
Constraints[II].setAny(SE);
for (int SI = Coupled.find_first(); SI >= 0; SI = Coupled.find_next(SI)) {
DEBUG(dbgs() << "testing subscript group " << SI << " { ");
SmallBitVector Group(Pair[SI].Group);
SmallBitVector Sivs(Pairs);
SmallBitVector Mivs(Pairs);
SmallBitVector ConstrainedLevels(MaxLevels + 1);
SmallVector<Subscript *, 4> PairsInGroup;
for (int SJ = Group.find_first(); SJ >= 0; SJ = Group.find_next(SJ)) {
DEBUG(dbgs() << SJ << " ");
if (Pair[SJ].Classification == Subscript::SIV)
Sivs.set(SJ);
else
Mivs.set(SJ);
PairsInGroup.push_back(&Pair[SJ]);
}
unifySubscriptType(PairsInGroup);
DEBUG(dbgs() << "}\n");
while (Sivs.any()) {
bool Changed = false;
for (int SJ = Sivs.find_first(); SJ >= 0; SJ = Sivs.find_next(SJ)) {
DEBUG(dbgs() << "testing subscript " << SJ << ", SIV\n");
unsigned Level;
const SCEV *SplitIter = nullptr;
DEBUG(dbgs() << "SIV\n");
if (testSIV(Pair[SJ].Src, Pair[SJ].Dst, Level, Result, NewConstraint,
SplitIter))
return nullptr;
ConstrainedLevels.set(Level);
if (intersectConstraints(&Constraints[Level], &NewConstraint)) {
if (Constraints[Level].isEmpty()) {
++DeltaIndependence;
return nullptr;
}
Changed = true;
}
Sivs.reset(SJ);
}
if (Changed) {
DEBUG(dbgs() << " propagating\n");
DEBUG(dbgs() << "\tMivs = ");
DEBUG(dumpSmallBitVector(Mivs));
for (int SJ = Mivs.find_first(); SJ >= 0; SJ = Mivs.find_next(SJ)) {
DEBUG(dbgs() << "\tSJ = " << SJ << "\n");
if (propagate(Pair[SJ].Src, Pair[SJ].Dst, Pair[SJ].Loops,
Constraints, Result.Consistent)) {
DEBUG(dbgs() << "\t Changed\n");
++DeltaPropagations;
Pair[SJ].Classification =
classifyPair(Pair[SJ].Src, LI->getLoopFor(Src->getParent()),
Pair[SJ].Dst, LI->getLoopFor(Dst->getParent()),
Pair[SJ].Loops);
switch (Pair[SJ].Classification) {
case Subscript::ZIV:
DEBUG(dbgs() << "ZIV\n");
if (testZIV(Pair[SJ].Src, Pair[SJ].Dst, Result))
return nullptr;
Mivs.reset(SJ);
break;
case Subscript::SIV:
Sivs.set(SJ);
Mivs.reset(SJ);
break;
case Subscript::RDIV:
case Subscript::MIV:
break;
default:
llvm_unreachable("bad subscript classification");
}
}
}
}
}
for (int SJ = Mivs.find_first(); SJ >= 0; SJ = Mivs.find_next(SJ)) {
if (Pair[SJ].Classification == Subscript::RDIV) {
DEBUG(dbgs() << "RDIV test\n");
if (testRDIV(Pair[SJ].Src, Pair[SJ].Dst, Result))
return nullptr;
Mivs.reset(SJ);
}
}
for (int SJ = Mivs.find_first(); SJ >= 0; SJ = Mivs.find_next(SJ)) {
if (Pair[SJ].Classification == Subscript::MIV) {
DEBUG(dbgs() << "MIV test\n");
if (testMIV(Pair[SJ].Src, Pair[SJ].Dst, Pair[SJ].Loops, Result))
return nullptr;
}
else
llvm_unreachable("expected only MIV subscripts at this point");
}
DEBUG(dbgs() << " updating\n");
for (int SJ = ConstrainedLevels.find_first(); SJ >= 0;
SJ = ConstrainedLevels.find_next(SJ)) {
if (SJ > (int)CommonLevels)
break;
updateDirection(Result.DV[SJ - 1], Constraints[SJ]);
if (Result.DV[SJ - 1].Direction == Dependence::DVEntry::NONE)
return nullptr;
}
}
}
SmallBitVector CompleteLoops(MaxLevels + 1);
for (unsigned SI = 0; SI < Pairs; ++SI)
CompleteLoops |= Pair[SI].Loops;
for (unsigned II = 1; II <= CommonLevels; ++II)
if (CompleteLoops[II])
Result.DV[II - 1].Scalar = false;
if (PossiblyLoopIndependent) {
for (unsigned II = 1; II <= CommonLevels; ++II) {
if (!(Result.getDirection(II) & Dependence::DVEntry::EQ)) {
Result.LoopIndependent = false;
break;
}
}
}
else {
bool AllEqual = true;
for (unsigned II = 1; II <= CommonLevels; ++II) {
if (Result.getDirection(II) != Dependence::DVEntry::EQ) {
AllEqual = false;
break;
}
}
if (AllEqual)
return nullptr;
}
return make_unique<FullDependence>(std::move(Result));
}
const SCEV *DependenceAnalysis::getSplitIteration(const Dependence &Dep,
unsigned SplitLevel) {
assert(Dep.isSplitable(SplitLevel) &&
"Dep should be splitable at SplitLevel");
Instruction *Src = Dep.getSrc();
Instruction *Dst = Dep.getDst();
assert(Src->mayReadFromMemory() || Src->mayWriteToMemory());
assert(Dst->mayReadFromMemory() || Dst->mayWriteToMemory());
assert(isLoadOrStore(Src));
assert(isLoadOrStore(Dst));
Value *SrcPtr = getPointerOperand(Src);
Value *DstPtr = getPointerOperand(Dst);
assert(underlyingObjectsAlias(AA, F->getParent()->getDataLayout(), DstPtr,
SrcPtr) == MustAlias);
establishNestingLevels(Src, Dst);
FullDependence Result(Src, Dst, false, CommonLevels);
bool UsefulGEP = false;
GEPOperator *SrcGEP = dyn_cast<GEPOperator>(SrcPtr);
GEPOperator *DstGEP = dyn_cast<GEPOperator>(DstPtr);
if (SrcGEP && DstGEP &&
SrcGEP->getPointerOperandType() == DstGEP->getPointerOperandType()) {
const SCEV *SrcPtrSCEV = SE->getSCEV(SrcGEP->getPointerOperand());
const SCEV *DstPtrSCEV = SE->getSCEV(DstGEP->getPointerOperand());
UsefulGEP = isLoopInvariant(SrcPtrSCEV, LI->getLoopFor(Src->getParent())) &&
isLoopInvariant(DstPtrSCEV, LI->getLoopFor(Dst->getParent())) &&
(SrcGEP->getNumOperands() == DstGEP->getNumOperands());
}
unsigned Pairs = UsefulGEP ? SrcGEP->idx_end() - SrcGEP->idx_begin() : 1;
SmallVector<Subscript, 4> Pair(Pairs);
if (UsefulGEP) {
unsigned P = 0;
for (GEPOperator::const_op_iterator SrcIdx = SrcGEP->idx_begin(),
SrcEnd = SrcGEP->idx_end(),
DstIdx = DstGEP->idx_begin();
SrcIdx != SrcEnd;
++SrcIdx, ++DstIdx, ++P) {
Pair[P].Src = SE->getSCEV(*SrcIdx);
Pair[P].Dst = SE->getSCEV(*DstIdx);
}
}
else {
const SCEV *SrcSCEV = SE->getSCEV(SrcPtr);
const SCEV *DstSCEV = SE->getSCEV(DstPtr);
Pair[0].Src = SrcSCEV;
Pair[0].Dst = DstSCEV;
}
if (Delinearize && CommonLevels > 1) {
if (tryDelinearize(Src, Dst, Pair)) {
DEBUG(dbgs() << " delinerized GEP\n");
Pairs = Pair.size();
}
}
for (unsigned P = 0; P < Pairs; ++P) {
Pair[P].Loops.resize(MaxLevels + 1);
Pair[P].GroupLoops.resize(MaxLevels + 1);
Pair[P].Group.resize(Pairs);
removeMatchingExtensions(&Pair[P]);
Pair[P].Classification =
classifyPair(Pair[P].Src, LI->getLoopFor(Src->getParent()),
Pair[P].Dst, LI->getLoopFor(Dst->getParent()),
Pair[P].Loops);
Pair[P].GroupLoops = Pair[P].Loops;
Pair[P].Group.set(P);
}
SmallBitVector Separable(Pairs);
SmallBitVector Coupled(Pairs);
for (unsigned SI = 0; SI < Pairs; ++SI) {
if (Pair[SI].Classification == Subscript::NonLinear) {
collectCommonLoops(Pair[SI].Src,
LI->getLoopFor(Src->getParent()),
Pair[SI].Loops);
collectCommonLoops(Pair[SI].Dst,
LI->getLoopFor(Dst->getParent()),
Pair[SI].Loops);
Result.Consistent = false;
}
else if (Pair[SI].Classification == Subscript::ZIV)
Separable.set(SI);
else {
bool Done = true;
for (unsigned SJ = SI + 1; SJ < Pairs; ++SJ) {
SmallBitVector Intersection = Pair[SI].GroupLoops;
Intersection &= Pair[SJ].GroupLoops;
if (Intersection.any()) {
Pair[SJ].GroupLoops |= Pair[SI].GroupLoops;
Pair[SJ].Group |= Pair[SI].Group;
Done = false;
}
}
if (Done) {
if (Pair[SI].Group.count() == 1)
Separable.set(SI);
else
Coupled.set(SI);
}
}
}
Constraint NewConstraint;
NewConstraint.setAny(SE);
for (int SI = Separable.find_first(); SI >= 0; SI = Separable.find_next(SI)) {
switch (Pair[SI].Classification) {
case Subscript::SIV: {
unsigned Level;
const SCEV *SplitIter = nullptr;
(void) testSIV(Pair[SI].Src, Pair[SI].Dst, Level,
Result, NewConstraint, SplitIter);
if (Level == SplitLevel) {
assert(SplitIter != nullptr);
return SplitIter;
}
break;
}
case Subscript::ZIV:
case Subscript::RDIV:
case Subscript::MIV:
break;
default:
llvm_unreachable("subscript has unexpected classification");
}
}
if (Coupled.count()) {
SmallVector<Constraint, 4> Constraints(MaxLevels + 1);
for (unsigned II = 0; II <= MaxLevels; ++II)
Constraints[II].setAny(SE);
for (int SI = Coupled.find_first(); SI >= 0; SI = Coupled.find_next(SI)) {
SmallBitVector Group(Pair[SI].Group);
SmallBitVector Sivs(Pairs);
SmallBitVector Mivs(Pairs);
SmallBitVector ConstrainedLevels(MaxLevels + 1);
for (int SJ = Group.find_first(); SJ >= 0; SJ = Group.find_next(SJ)) {
if (Pair[SJ].Classification == Subscript::SIV)
Sivs.set(SJ);
else
Mivs.set(SJ);
}
while (Sivs.any()) {
bool Changed = false;
for (int SJ = Sivs.find_first(); SJ >= 0; SJ = Sivs.find_next(SJ)) {
unsigned Level;
const SCEV *SplitIter = nullptr;
(void) testSIV(Pair[SJ].Src, Pair[SJ].Dst, Level,
Result, NewConstraint, SplitIter);
if (Level == SplitLevel && SplitIter)
return SplitIter;
ConstrainedLevels.set(Level);
if (intersectConstraints(&Constraints[Level], &NewConstraint))
Changed = true;
Sivs.reset(SJ);
}
if (Changed) {
for (int SJ = Mivs.find_first(); SJ >= 0; SJ = Mivs.find_next(SJ)) {
if (propagate(Pair[SJ].Src, Pair[SJ].Dst,
Pair[SJ].Loops, Constraints, Result.Consistent)) {
Pair[SJ].Classification =
classifyPair(Pair[SJ].Src, LI->getLoopFor(Src->getParent()),
Pair[SJ].Dst, LI->getLoopFor(Dst->getParent()),
Pair[SJ].Loops);
switch (Pair[SJ].Classification) {
case Subscript::ZIV:
Mivs.reset(SJ);
break;
case Subscript::SIV:
Sivs.set(SJ);
Mivs.reset(SJ);
break;
case Subscript::RDIV:
case Subscript::MIV:
break;
default:
llvm_unreachable("bad subscript classification");
}
}
}
}
}
}
}
llvm_unreachable("somehow reached end of routine");
return nullptr;
}