llvm/lib/Analysis/LoopDependenceAnalysis.cpp
Owen Anderson 2ab36d3502 Begin adding static dependence information to passes, which will allow us to
perform initialization without static constructors AND without explicit initialization
by the client.  For the moment, passes are required to initialize both their
(potential) dependencies and any passes they preserve.  I hope to be able to relax
the latter requirement in the future.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116334 91177308-0d34-0410-b5e6-96231b3b80d8
2010-10-12 19:48:12 +00:00

356 lines
12 KiB
C++

//===- LoopDependenceAnalysis.cpp - LDA Implementation ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the (beginning) of an implementation of a loop dependence analysis
// framework, which is used to detect dependences in memory accesses in loops.
//
// Please note that this is work in progress and the interface is subject to
// change.
//
// TODO: adapt as implementation progresses.
//
// TODO: document lingo (pair, subscript, index)
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "lda"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/LoopDependenceAnalysis.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Instructions.h"
#include "llvm/Operator.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetData.h"
using namespace llvm;
STATISTIC(NumAnswered, "Number of dependence queries answered");
STATISTIC(NumAnalysed, "Number of distinct dependence pairs analysed");
STATISTIC(NumDependent, "Number of pairs with dependent accesses");
STATISTIC(NumIndependent, "Number of pairs with independent accesses");
STATISTIC(NumUnknown, "Number of pairs with unknown accesses");
LoopPass *llvm::createLoopDependenceAnalysisPass() {
return new LoopDependenceAnalysis();
}
INITIALIZE_PASS_BEGIN(LoopDependenceAnalysis, "lda",
"Loop Dependence Analysis", false, true)
INITIALIZE_PASS_DEPENDENCY(ScalarEvolution)
INITIALIZE_AG_DEPENDENCY(AliasAnalysis)
INITIALIZE_PASS_END(LoopDependenceAnalysis, "lda",
"Loop Dependence Analysis", false, true)
char LoopDependenceAnalysis::ID = 0;
//===----------------------------------------------------------------------===//
// Utility Functions
//===----------------------------------------------------------------------===//
static inline bool IsMemRefInstr(const Value *V) {
const Instruction *I = dyn_cast<const Instruction>(V);
return I && (I->mayReadFromMemory() || I->mayWriteToMemory());
}
static void GetMemRefInstrs(const Loop *L,
SmallVectorImpl<Instruction*> &Memrefs) {
for (Loop::block_iterator b = L->block_begin(), be = L->block_end();
b != be; ++b)
for (BasicBlock::iterator i = (*b)->begin(), ie = (*b)->end();
i != ie; ++i)
if (IsMemRefInstr(i))
Memrefs.push_back(i);
}
static bool IsLoadOrStoreInst(Value *I) {
return isa<LoadInst>(I) || isa<StoreInst>(I);
}
static Value *GetPointerOperand(Value *I) {
if (LoadInst *i = dyn_cast<LoadInst>(I))
return i->getPointerOperand();
if (StoreInst *i = dyn_cast<StoreInst>(I))
return i->getPointerOperand();
llvm_unreachable("Value is no load or store instruction!");
// Never reached.
return 0;
}
static AliasAnalysis::AliasResult UnderlyingObjectsAlias(AliasAnalysis *AA,
const Value *A,
const Value *B) {
const Value *aObj = A->getUnderlyingObject();
const Value *bObj = B->getUnderlyingObject();
return AA->alias(aObj, AA->getTypeStoreSize(aObj->getType()),
bObj, AA->getTypeStoreSize(bObj->getType()));
}
static inline const SCEV *GetZeroSCEV(ScalarEvolution *SE) {
return SE->getConstant(Type::getInt32Ty(SE->getContext()), 0L);
}
//===----------------------------------------------------------------------===//
// Dependence Testing
//===----------------------------------------------------------------------===//
bool LoopDependenceAnalysis::isDependencePair(const Value *A,
const Value *B) const {
return IsMemRefInstr(A) &&
IsMemRefInstr(B) &&
(cast<const Instruction>(A)->mayWriteToMemory() ||
cast<const Instruction>(B)->mayWriteToMemory());
}
bool LoopDependenceAnalysis::findOrInsertDependencePair(Value *A,
Value *B,
DependencePair *&P) {
void *insertPos = 0;
FoldingSetNodeID id;
id.AddPointer(A);
id.AddPointer(B);
P = Pairs.FindNodeOrInsertPos(id, insertPos);
if (P) return true;
P = new (PairAllocator) DependencePair(id, A, B);
Pairs.InsertNode(P, insertPos);
return false;
}
void LoopDependenceAnalysis::getLoops(const SCEV *S,
DenseSet<const Loop*>* Loops) const {
// Refactor this into an SCEVVisitor, if efficiency becomes a concern.
for (const Loop *L = this->L; L != 0; L = L->getParentLoop())
if (!S->isLoopInvariant(L))
Loops->insert(L);
}
bool LoopDependenceAnalysis::isLoopInvariant(const SCEV *S) const {
DenseSet<const Loop*> loops;
getLoops(S, &loops);
return loops.empty();
}
bool LoopDependenceAnalysis::isAffine(const SCEV *S) const {
const SCEVAddRecExpr *rec = dyn_cast<SCEVAddRecExpr>(S);
return isLoopInvariant(S) || (rec && rec->isAffine());
}
bool LoopDependenceAnalysis::isZIVPair(const SCEV *A, const SCEV *B) const {
return isLoopInvariant(A) && isLoopInvariant(B);
}
bool LoopDependenceAnalysis::isSIVPair(const SCEV *A, const SCEV *B) const {
DenseSet<const Loop*> loops;
getLoops(A, &loops);
getLoops(B, &loops);
return loops.size() == 1;
}
LoopDependenceAnalysis::DependenceResult
LoopDependenceAnalysis::analyseZIV(const SCEV *A,
const SCEV *B,
Subscript *S) const {
assert(isZIVPair(A, B) && "Attempted to ZIV-test non-ZIV SCEVs!");
return A == B ? Dependent : Independent;
}
LoopDependenceAnalysis::DependenceResult
LoopDependenceAnalysis::analyseSIV(const SCEV *A,
const SCEV *B,
Subscript *S) const {
return Unknown; // TODO: Implement.
}
LoopDependenceAnalysis::DependenceResult
LoopDependenceAnalysis::analyseMIV(const SCEV *A,
const SCEV *B,
Subscript *S) const {
return Unknown; // TODO: Implement.
}
LoopDependenceAnalysis::DependenceResult
LoopDependenceAnalysis::analyseSubscript(const SCEV *A,
const SCEV *B,
Subscript *S) const {
DEBUG(dbgs() << " Testing subscript: " << *A << ", " << *B << "\n");
if (A == B) {
DEBUG(dbgs() << " -> [D] same SCEV\n");
return Dependent;
}
if (!isAffine(A) || !isAffine(B)) {
DEBUG(dbgs() << " -> [?] not affine\n");
return Unknown;
}
if (isZIVPair(A, B))
return analyseZIV(A, B, S);
if (isSIVPair(A, B))
return analyseSIV(A, B, S);
return analyseMIV(A, B, S);
}
LoopDependenceAnalysis::DependenceResult
LoopDependenceAnalysis::analysePair(DependencePair *P) const {
DEBUG(dbgs() << "Analysing:\n" << *P->A << "\n" << *P->B << "\n");
// We only analyse loads and stores but no possible memory accesses by e.g.
// free, call, or invoke instructions.
if (!IsLoadOrStoreInst(P->A) || !IsLoadOrStoreInst(P->B)) {
DEBUG(dbgs() << "--> [?] no load/store\n");
return Unknown;
}
Value *aPtr = GetPointerOperand(P->A);
Value *bPtr = GetPointerOperand(P->B);
switch (UnderlyingObjectsAlias(AA, aPtr, bPtr)) {
case AliasAnalysis::MayAlias:
// We can not analyse objects if we do not know about their aliasing.
DEBUG(dbgs() << "---> [?] may alias\n");
return Unknown;
case AliasAnalysis::NoAlias:
// If the objects noalias, they are distinct, accesses are independent.
DEBUG(dbgs() << "---> [I] no alias\n");
return Independent;
case AliasAnalysis::MustAlias:
break; // The underlying objects alias, test accesses for dependence.
}
const GEPOperator *aGEP = dyn_cast<GEPOperator>(aPtr);
const GEPOperator *bGEP = dyn_cast<GEPOperator>(bPtr);
if (!aGEP || !bGEP)
return Unknown;
// FIXME: Is filtering coupled subscripts necessary?
// Collect GEP operand pairs (FIXME: use GetGEPOperands from BasicAA), adding
// trailing zeroes to the smaller GEP, if needed.
typedef SmallVector<std::pair<const SCEV*, const SCEV*>, 4> GEPOpdPairsTy;
GEPOpdPairsTy opds;
for(GEPOperator::const_op_iterator aIdx = aGEP->idx_begin(),
aEnd = aGEP->idx_end(),
bIdx = bGEP->idx_begin(),
bEnd = bGEP->idx_end();
aIdx != aEnd && bIdx != bEnd;
aIdx += (aIdx != aEnd), bIdx += (bIdx != bEnd)) {
const SCEV* aSCEV = (aIdx != aEnd) ? SE->getSCEV(*aIdx) : GetZeroSCEV(SE);
const SCEV* bSCEV = (bIdx != bEnd) ? SE->getSCEV(*bIdx) : GetZeroSCEV(SE);
opds.push_back(std::make_pair(aSCEV, bSCEV));
}
if (!opds.empty() && opds[0].first != opds[0].second) {
// We cannot (yet) handle arbitrary GEP pointer offsets. By limiting
//
// TODO: this could be relaxed by adding the size of the underlying object
// to the first subscript. If we have e.g. (GEP x,0,i; GEP x,2,-i) and we
// know that x is a [100 x i8]*, we could modify the first subscript to be
// (i, 200-i) instead of (i, -i).
return Unknown;
}
// Now analyse the collected operand pairs (skipping the GEP ptr offsets).
for (GEPOpdPairsTy::const_iterator i = opds.begin() + 1, end = opds.end();
i != end; ++i) {
Subscript subscript;
DependenceResult result = analyseSubscript(i->first, i->second, &subscript);
if (result != Dependent) {
// We either proved independence or failed to analyse this subscript.
// Further subscripts will not improve the situation, so abort early.
return result;
}
P->Subscripts.push_back(subscript);
}
// We successfully analysed all subscripts but failed to prove independence.
return Dependent;
}
bool LoopDependenceAnalysis::depends(Value *A, Value *B) {
assert(isDependencePair(A, B) && "Values form no dependence pair!");
++NumAnswered;
DependencePair *p;
if (!findOrInsertDependencePair(A, B, p)) {
// The pair is not cached, so analyse it.
++NumAnalysed;
switch (p->Result = analysePair(p)) {
case Dependent: ++NumDependent; break;
case Independent: ++NumIndependent; break;
case Unknown: ++NumUnknown; break;
}
}
return p->Result != Independent;
}
//===----------------------------------------------------------------------===//
// LoopDependenceAnalysis Implementation
//===----------------------------------------------------------------------===//
bool LoopDependenceAnalysis::runOnLoop(Loop *L, LPPassManager &) {
this->L = L;
AA = &getAnalysis<AliasAnalysis>();
SE = &getAnalysis<ScalarEvolution>();
return false;
}
void LoopDependenceAnalysis::releaseMemory() {
Pairs.clear();
PairAllocator.Reset();
}
void LoopDependenceAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequiredTransitive<AliasAnalysis>();
AU.addRequiredTransitive<ScalarEvolution>();
}
static void PrintLoopInfo(raw_ostream &OS,
LoopDependenceAnalysis *LDA, const Loop *L) {
if (!L->empty()) return; // ignore non-innermost loops
SmallVector<Instruction*, 8> memrefs;
GetMemRefInstrs(L, memrefs);
OS << "Loop at depth " << L->getLoopDepth() << ", header block: ";
WriteAsOperand(OS, L->getHeader(), false);
OS << "\n";
OS << " Load/store instructions: " << memrefs.size() << "\n";
for (SmallVector<Instruction*, 8>::const_iterator x = memrefs.begin(),
end = memrefs.end(); x != end; ++x)
OS << "\t" << (x - memrefs.begin()) << ": " << **x << "\n";
OS << " Pairwise dependence results:\n";
for (SmallVector<Instruction*, 8>::const_iterator x = memrefs.begin(),
end = memrefs.end(); x != end; ++x)
for (SmallVector<Instruction*, 8>::const_iterator y = x + 1;
y != end; ++y)
if (LDA->isDependencePair(*x, *y))
OS << "\t" << (x - memrefs.begin()) << "," << (y - memrefs.begin())
<< ": " << (LDA->depends(*x, *y) ? "dependent" : "independent")
<< "\n";
}
void LoopDependenceAnalysis::print(raw_ostream &OS, const Module*) const {
// TODO: doc why const_cast is safe
PrintLoopInfo(OS, const_cast<LoopDependenceAnalysis*>(this), this->L);
}