2007-07-07 01:14:35 +02:00
|
|
|
//===- MemoryDependenceAnalysis.cpp - Mem Deps Implementation --*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by the Owen Anderson and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements an analysis that determines, for a given memory
|
|
|
|
// operation, what preceding memory operations it depends on. It builds on
|
|
|
|
// alias analysis information, and tries to provide a lazy, caching interface to
|
|
|
|
// a common kind of alias information query.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
|
2007-07-10 19:25:03 +02:00
|
|
|
#include "llvm/Constants.h"
|
2007-07-07 01:14:35 +02:00
|
|
|
#include "llvm/Instructions.h"
|
|
|
|
#include "llvm/Function.h"
|
|
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
2007-07-24 23:52:37 +02:00
|
|
|
#include "llvm/Support/CFG.h"
|
2007-07-07 01:14:35 +02:00
|
|
|
#include "llvm/Target/TargetData.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
char MemoryDependenceAnalysis::ID = 0;
|
|
|
|
|
2007-07-25 21:57:03 +02:00
|
|
|
Instruction* MemoryDependenceAnalysis::NonLocal = (Instruction*)-2;
|
|
|
|
Instruction* MemoryDependenceAnalysis::None = (Instruction*)-3;
|
2007-07-07 01:14:35 +02:00
|
|
|
|
|
|
|
// Register this pass...
|
2007-07-10 22:21:08 +02:00
|
|
|
static RegisterPass<MemoryDependenceAnalysis> X("memdep",
|
|
|
|
"Memory Dependence Analysis");
|
2007-07-07 01:14:35 +02:00
|
|
|
|
|
|
|
/// getAnalysisUsage - Does not modify anything. It uses Alias Analysis.
|
|
|
|
///
|
|
|
|
void MemoryDependenceAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
|
|
AU.setPreservesAll();
|
|
|
|
AU.addRequiredTransitive<AliasAnalysis>();
|
|
|
|
AU.addRequiredTransitive<TargetData>();
|
|
|
|
}
|
|
|
|
|
2007-07-10 19:59:22 +02:00
|
|
|
// Find the dependency of a CallSite
|
2007-07-16 23:52:50 +02:00
|
|
|
Instruction* MemoryDependenceAnalysis::getCallSiteDependency(CallSite C, Instruction* start,
|
|
|
|
bool local) {
|
2007-07-10 19:59:22 +02:00
|
|
|
assert(local && "Non-local memory dependence analysis not yet implemented");
|
|
|
|
|
|
|
|
AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
|
|
|
|
TargetData& TD = getAnalysis<TargetData>();
|
|
|
|
BasicBlock::iterator blockBegin = C.getInstruction()->getParent()->begin();
|
|
|
|
BasicBlock::iterator QI = C.getInstruction();
|
|
|
|
|
|
|
|
while (QI != blockBegin) {
|
|
|
|
--QI;
|
|
|
|
|
|
|
|
// If this inst is a memory op, get the pointer it accessed
|
|
|
|
Value* pointer = 0;
|
|
|
|
uint64_t pointerSize = 0;
|
|
|
|
if (StoreInst* S = dyn_cast<StoreInst>(QI)) {
|
|
|
|
pointer = S->getPointerOperand();
|
|
|
|
pointerSize = TD.getTypeSize(S->getOperand(0)->getType());
|
|
|
|
} else if (LoadInst* L = dyn_cast<LoadInst>(QI)) {
|
|
|
|
pointer = L->getPointerOperand();
|
|
|
|
pointerSize = TD.getTypeSize(L->getType());
|
|
|
|
} else if (AllocationInst* AI = dyn_cast<AllocationInst>(QI)) {
|
|
|
|
pointer = AI;
|
|
|
|
if (ConstantInt* C = dyn_cast<ConstantInt>(AI->getArraySize()))
|
2007-07-10 22:48:38 +02:00
|
|
|
pointerSize = C->getZExtValue() * TD.getTypeSize(AI->getAllocatedType());
|
2007-07-10 19:59:22 +02:00
|
|
|
else
|
|
|
|
pointerSize = ~0UL;
|
2007-07-10 20:43:15 +02:00
|
|
|
} else if (VAArgInst* V = dyn_cast<VAArgInst>(QI)) {
|
|
|
|
pointer = V->getOperand(0);
|
|
|
|
pointerSize = TD.getTypeSize(V->getType());
|
2007-07-10 19:59:22 +02:00
|
|
|
} else if (FreeInst* F = dyn_cast<FreeInst>(QI)) {
|
|
|
|
pointer = F->getPointerOperand();
|
|
|
|
|
|
|
|
// FreeInsts erase the entire structure
|
|
|
|
pointerSize = ~0UL;
|
|
|
|
} else if (CallSite::get(QI).getInstruction() != 0) {
|
|
|
|
if (AA.getModRefInfo(C, CallSite::get(QI)) != AliasAnalysis::NoModRef) {
|
|
|
|
depGraphLocal.insert(std::make_pair(C.getInstruction(), std::make_pair(QI, true)));
|
|
|
|
reverseDep.insert(std::make_pair(QI, C.getInstruction()));
|
|
|
|
return QI;
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
2007-07-10 22:39:07 +02:00
|
|
|
} else
|
|
|
|
continue;
|
2007-07-10 19:59:22 +02:00
|
|
|
|
|
|
|
if (AA.getModRefInfo(C, pointer, pointerSize) != AliasAnalysis::NoModRef) {
|
|
|
|
depGraphLocal.insert(std::make_pair(C.getInstruction(), std::make_pair(QI, true)));
|
|
|
|
reverseDep.insert(std::make_pair(QI, C.getInstruction()));
|
|
|
|
return QI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No dependence found
|
|
|
|
depGraphLocal.insert(std::make_pair(C.getInstruction(), std::make_pair(NonLocal, true)));
|
|
|
|
reverseDep.insert(std::make_pair(NonLocal, C.getInstruction()));
|
|
|
|
return NonLocal;
|
|
|
|
}
|
|
|
|
|
2007-07-25 21:57:03 +02:00
|
|
|
bool MemoryDependenceAnalysis::nonLocalHelper(Instruction* query,
|
|
|
|
BasicBlock* block,
|
2007-07-25 23:26:36 +02:00
|
|
|
DenseMap<BasicBlock*, Value*>& resp,
|
|
|
|
SmallPtrSet<BasicBlock*, 4>& visited) {
|
2007-07-25 21:57:03 +02:00
|
|
|
if (resp.count(block))
|
|
|
|
return resp[block] != None;
|
2007-07-24 23:52:37 +02:00
|
|
|
|
2007-07-25 21:57:03 +02:00
|
|
|
Instruction* localDep = getDependency(query, 0, block);
|
2007-07-24 23:52:37 +02:00
|
|
|
if (localDep != NonLocal) {
|
2007-07-25 21:57:03 +02:00
|
|
|
resp.insert(std::make_pair(block, localDep));
|
|
|
|
return true;
|
2007-07-24 23:52:37 +02:00
|
|
|
}
|
|
|
|
|
2007-07-25 23:26:36 +02:00
|
|
|
visited.insert(block);
|
|
|
|
|
2007-07-25 21:57:03 +02:00
|
|
|
bool inserted = false;
|
2007-07-26 20:57:04 +02:00
|
|
|
bool predOnStack = false;
|
2007-07-24 23:52:37 +02:00
|
|
|
for (pred_iterator PI = pred_begin(block), PE = pred_end(block);
|
2007-07-25 21:57:03 +02:00
|
|
|
PI != PE; ++PI)
|
2007-07-25 23:26:36 +02:00
|
|
|
if (!visited.count(*PI))
|
|
|
|
inserted |= nonLocalHelper(query, *PI, resp, visited);
|
2007-07-26 20:57:04 +02:00
|
|
|
else
|
|
|
|
predOnStack = true;
|
|
|
|
|
2007-07-25 23:26:36 +02:00
|
|
|
visited.erase(block);
|
2007-07-26 20:57:04 +02:00
|
|
|
|
|
|
|
if (!inserted && !predOnStack)
|
|
|
|
resp.insert(std::make_pair(block, None));
|
2007-07-30 19:29:24 +02:00
|
|
|
else if (inserted && predOnStack)
|
|
|
|
resp.insert(std::make_pair(block, NonLocal));
|
2007-07-24 23:52:37 +02:00
|
|
|
|
2007-07-25 21:57:03 +02:00
|
|
|
return inserted;
|
2007-07-24 23:52:37 +02:00
|
|
|
}
|
|
|
|
|
2007-07-25 21:57:03 +02:00
|
|
|
bool MemoryDependenceAnalysis::getNonLocalDependency(Instruction* query,
|
|
|
|
DenseMap<BasicBlock*, Value*>& resp) {
|
2007-07-24 23:52:37 +02:00
|
|
|
Instruction* localDep = getDependency(query);
|
|
|
|
if (localDep != NonLocal) {
|
2007-07-25 21:57:03 +02:00
|
|
|
resp.insert(std::make_pair(query->getParent(), localDep));
|
|
|
|
return true;
|
2007-07-24 23:52:37 +02:00
|
|
|
}
|
|
|
|
|
2007-07-25 21:57:03 +02:00
|
|
|
bool inserted = false;
|
2007-07-25 23:26:36 +02:00
|
|
|
SmallPtrSet<BasicBlock*, 4> visited;
|
|
|
|
visited.insert(query->getParent());
|
2007-07-25 21:57:03 +02:00
|
|
|
|
2007-07-24 23:52:37 +02:00
|
|
|
BasicBlock* parent = query->getParent();
|
|
|
|
for (pred_iterator PI = pred_begin(parent), PE = pred_end(parent);
|
|
|
|
PI != PE; ++PI) {
|
2007-07-25 23:26:36 +02:00
|
|
|
if (!visited.count(*PI))
|
|
|
|
inserted |= nonLocalHelper(query, *PI, resp, visited);
|
2007-07-24 23:52:37 +02:00
|
|
|
}
|
|
|
|
|
2007-07-25 21:57:03 +02:00
|
|
|
if (!inserted)
|
|
|
|
resp.insert(std::make_pair(query->getParent(), None));
|
2007-07-24 23:52:37 +02:00
|
|
|
|
2007-07-25 21:57:03 +02:00
|
|
|
return inserted;
|
2007-07-24 23:52:37 +02:00
|
|
|
}
|
|
|
|
|
2007-07-07 01:14:35 +02:00
|
|
|
/// getDependency - Return the instruction on which a memory operation
|
2007-07-10 19:08:11 +02:00
|
|
|
/// depends. The local paramter indicates if the query should only
|
|
|
|
/// evaluate dependencies within the same basic block.
|
2007-07-07 01:14:35 +02:00
|
|
|
Instruction* MemoryDependenceAnalysis::getDependency(Instruction* query,
|
2007-07-16 23:52:50 +02:00
|
|
|
Instruction* start,
|
2007-07-24 23:52:37 +02:00
|
|
|
BasicBlock* block) {
|
2007-07-07 01:14:35 +02:00
|
|
|
// Start looking for dependencies with the queried inst
|
|
|
|
BasicBlock::iterator QI = query;
|
|
|
|
|
|
|
|
// Check for a cached result
|
|
|
|
std::pair<Instruction*, bool> cachedResult = depGraphLocal[query];
|
|
|
|
// If we have a _confirmed_ cached entry, return it
|
|
|
|
if (cachedResult.second)
|
|
|
|
return cachedResult.first;
|
2007-07-25 21:57:03 +02:00
|
|
|
else if (cachedResult.first && cachedResult.first != NonLocal)
|
2007-07-07 01:14:35 +02:00
|
|
|
// If we have an unconfirmed cached entry, we can start our search from there
|
|
|
|
QI = cachedResult.first;
|
|
|
|
|
2007-07-16 23:52:50 +02:00
|
|
|
if (start)
|
|
|
|
QI = start;
|
2007-07-25 21:57:03 +02:00
|
|
|
else if (!start && block)
|
|
|
|
QI = block->end();
|
2007-07-16 23:52:50 +02:00
|
|
|
|
2007-07-07 01:14:35 +02:00
|
|
|
AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
|
2007-07-10 19:08:11 +02:00
|
|
|
TargetData& TD = getAnalysis<TargetData>();
|
2007-07-07 01:14:35 +02:00
|
|
|
|
|
|
|
// Get the pointer value for which dependence will be determined
|
|
|
|
Value* dependee = 0;
|
2007-07-10 19:08:11 +02:00
|
|
|
uint64_t dependeeSize = 0;
|
2007-07-10 20:11:42 +02:00
|
|
|
bool queryIsVolatile = false;
|
2007-07-16 23:52:50 +02:00
|
|
|
if (StoreInst* S = dyn_cast<StoreInst>(query)) {
|
2007-07-07 01:14:35 +02:00
|
|
|
dependee = S->getPointerOperand();
|
2007-07-10 19:25:03 +02:00
|
|
|
dependeeSize = TD.getTypeSize(S->getOperand(0)->getType());
|
2007-07-10 20:11:42 +02:00
|
|
|
queryIsVolatile = S->isVolatile();
|
2007-07-16 23:52:50 +02:00
|
|
|
} else if (LoadInst* L = dyn_cast<LoadInst>(query)) {
|
2007-07-07 01:14:35 +02:00
|
|
|
dependee = L->getPointerOperand();
|
2007-07-10 19:25:03 +02:00
|
|
|
dependeeSize = TD.getTypeSize(L->getType());
|
2007-07-10 20:11:42 +02:00
|
|
|
queryIsVolatile = L->isVolatile();
|
2007-07-16 23:52:50 +02:00
|
|
|
} else if (VAArgInst* V = dyn_cast<VAArgInst>(query)) {
|
2007-07-10 20:43:15 +02:00
|
|
|
dependee = V->getOperand(0);
|
|
|
|
dependeeSize = TD.getTypeSize(V->getType());
|
2007-07-16 23:52:50 +02:00
|
|
|
} else if (FreeInst* F = dyn_cast<FreeInst>(query)) {
|
2007-07-07 01:14:35 +02:00
|
|
|
dependee = F->getPointerOperand();
|
2007-07-10 19:08:11 +02:00
|
|
|
|
|
|
|
// FreeInsts erase the entire structure, not just a field
|
|
|
|
dependeeSize = ~0UL;
|
2007-07-16 23:52:50 +02:00
|
|
|
} else if (CallSite::get(query).getInstruction() != 0)
|
|
|
|
return getCallSiteDependency(CallSite::get(query), start);
|
2007-07-10 19:59:22 +02:00
|
|
|
else if (isa<AllocationInst>(query))
|
2007-07-07 01:14:35 +02:00
|
|
|
return None;
|
2007-07-10 19:25:03 +02:00
|
|
|
else
|
2007-07-10 19:08:11 +02:00
|
|
|
return None;
|
2007-07-07 01:14:35 +02:00
|
|
|
|
2007-07-24 23:52:37 +02:00
|
|
|
BasicBlock::iterator blockBegin = block ? block->begin()
|
|
|
|
: query->getParent()->begin();
|
2007-07-07 01:14:35 +02:00
|
|
|
|
|
|
|
while (QI != blockBegin) {
|
2007-07-10 19:08:11 +02:00
|
|
|
--QI;
|
|
|
|
|
2007-07-07 01:14:35 +02:00
|
|
|
// If this inst is a memory op, get the pointer it accessed
|
|
|
|
Value* pointer = 0;
|
2007-07-10 19:08:11 +02:00
|
|
|
uint64_t pointerSize = 0;
|
|
|
|
if (StoreInst* S = dyn_cast<StoreInst>(QI)) {
|
2007-07-10 20:11:42 +02:00
|
|
|
// All volatile loads/stores depend on each other
|
|
|
|
if (queryIsVolatile && S->isVolatile()) {
|
2007-07-25 21:57:03 +02:00
|
|
|
if (!start || block) {
|
2007-07-16 23:52:50 +02:00
|
|
|
depGraphLocal.insert(std::make_pair(query, std::make_pair(S, true)));
|
|
|
|
reverseDep.insert(std::make_pair(S, query));
|
|
|
|
}
|
|
|
|
|
2007-07-10 20:11:42 +02:00
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2007-07-07 01:14:35 +02:00
|
|
|
pointer = S->getPointerOperand();
|
2007-07-10 19:25:03 +02:00
|
|
|
pointerSize = TD.getTypeSize(S->getOperand(0)->getType());
|
2007-07-10 19:08:11 +02:00
|
|
|
} else if (LoadInst* L = dyn_cast<LoadInst>(QI)) {
|
2007-07-10 20:11:42 +02:00
|
|
|
// All volatile loads/stores depend on each other
|
|
|
|
if (queryIsVolatile && L->isVolatile()) {
|
2007-07-25 21:57:03 +02:00
|
|
|
if (!start || block) {
|
2007-07-16 23:52:50 +02:00
|
|
|
depGraphLocal.insert(std::make_pair(query, std::make_pair(L, true)));
|
|
|
|
reverseDep.insert(std::make_pair(L, query));
|
|
|
|
}
|
|
|
|
|
2007-07-10 20:11:42 +02:00
|
|
|
return L;
|
|
|
|
}
|
|
|
|
|
2007-07-07 01:14:35 +02:00
|
|
|
pointer = L->getPointerOperand();
|
2007-07-10 19:25:03 +02:00
|
|
|
pointerSize = TD.getTypeSize(L->getType());
|
2007-07-10 19:08:11 +02:00
|
|
|
} else if (AllocationInst* AI = dyn_cast<AllocationInst>(QI)) {
|
|
|
|
pointer = AI;
|
2007-07-10 19:25:03 +02:00
|
|
|
if (ConstantInt* C = dyn_cast<ConstantInt>(AI->getArraySize()))
|
2007-07-10 22:48:38 +02:00
|
|
|
pointerSize = C->getZExtValue() * TD.getTypeSize(AI->getAllocatedType());
|
2007-07-10 19:08:11 +02:00
|
|
|
else
|
|
|
|
pointerSize = ~0UL;
|
2007-07-10 20:43:15 +02:00
|
|
|
} else if (VAArgInst* V = dyn_cast<VAArgInst>(QI)) {
|
|
|
|
pointer = V->getOperand(0);
|
|
|
|
pointerSize = TD.getTypeSize(V->getType());
|
2007-07-10 19:08:11 +02:00
|
|
|
} else if (FreeInst* F = dyn_cast<FreeInst>(QI)) {
|
2007-07-07 01:14:35 +02:00
|
|
|
pointer = F->getPointerOperand();
|
2007-07-10 19:08:11 +02:00
|
|
|
|
|
|
|
// FreeInsts erase the entire structure
|
|
|
|
pointerSize = ~0UL;
|
2007-07-10 19:59:22 +02:00
|
|
|
} else if (CallSite::get(QI).getInstruction() != 0) {
|
2007-07-07 01:14:35 +02:00
|
|
|
// Call insts need special handling. Check is they can modify our pointer
|
2007-07-10 19:59:22 +02:00
|
|
|
if (AA.getModRefInfo(CallSite::get(QI), dependee, dependeeSize) !=
|
|
|
|
AliasAnalysis::NoModRef) {
|
2007-07-25 21:57:03 +02:00
|
|
|
if (!start || block) {
|
2007-07-16 23:52:50 +02:00
|
|
|
depGraphLocal.insert(std::make_pair(query, std::make_pair(QI, true)));
|
|
|
|
reverseDep.insert(std::make_pair(QI, query));
|
|
|
|
}
|
|
|
|
|
2007-07-10 19:59:22 +02:00
|
|
|
return QI;
|
2007-07-10 19:25:03 +02:00
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
2007-07-07 01:14:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we found a pointer, check if it could be the same as our pointer
|
|
|
|
if (pointer) {
|
2007-07-10 19:08:11 +02:00
|
|
|
AliasAnalysis::AliasResult R = AA.alias(pointer, pointerSize,
|
|
|
|
dependee, dependeeSize);
|
2007-07-07 01:14:35 +02:00
|
|
|
|
|
|
|
if (R != AliasAnalysis::NoAlias) {
|
2007-07-25 21:57:03 +02:00
|
|
|
if (!start || block) {
|
2007-07-16 23:52:50 +02:00
|
|
|
depGraphLocal.insert(std::make_pair(query, std::make_pair(QI, true)));
|
|
|
|
reverseDep.insert(std::make_pair(QI, query));
|
|
|
|
}
|
|
|
|
|
2007-07-07 01:14:35 +02:00
|
|
|
return QI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we found nothing, return the non-local flag
|
2007-07-25 21:57:03 +02:00
|
|
|
if (!start || block) {
|
2007-07-16 23:52:50 +02:00
|
|
|
depGraphLocal.insert(std::make_pair(query,
|
|
|
|
std::make_pair(NonLocal, true)));
|
|
|
|
reverseDep.insert(std::make_pair(NonLocal, query));
|
|
|
|
}
|
2007-07-07 01:14:35 +02:00
|
|
|
|
|
|
|
return NonLocal;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// removeInstruction - Remove an instruction from the dependence analysis,
|
|
|
|
/// updating the dependence of instructions that previously depended on it.
|
|
|
|
void MemoryDependenceAnalysis::removeInstruction(Instruction* rem) {
|
|
|
|
// Figure out the new dep for things that currently depend on rem
|
|
|
|
Instruction* newDep = NonLocal;
|
2007-07-20 08:16:07 +02:00
|
|
|
if (depGraphLocal[rem].first != NonLocal &&
|
|
|
|
depGraphLocal[rem].second) {
|
2007-07-07 01:14:35 +02:00
|
|
|
// If we have dep info for rem, set them to it
|
|
|
|
BasicBlock::iterator RI = depGraphLocal[rem].first;
|
|
|
|
RI++;
|
|
|
|
newDep = RI;
|
|
|
|
} else if (depGraphLocal[rem].first == NonLocal &&
|
|
|
|
depGraphLocal[rem].second ) {
|
|
|
|
// If we have a confirmed non-local flag, use it
|
|
|
|
newDep = NonLocal;
|
|
|
|
} else {
|
|
|
|
// Otherwise, use the immediate successor of rem
|
|
|
|
// NOTE: This is because, when getDependence is called, it will first check
|
|
|
|
// the immediate predecessor of what is in the cache.
|
|
|
|
BasicBlock::iterator RI = rem;
|
|
|
|
RI++;
|
|
|
|
newDep = RI;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::multimap<Instruction*, Instruction*>::iterator I = reverseDep.find(rem);
|
|
|
|
while (I->first == rem) {
|
|
|
|
// Insert the new dependencies
|
|
|
|
// Mark it as unconfirmed as long as it is not the non-local flag
|
|
|
|
depGraphLocal[I->second] = std::make_pair(newDep, !newDep);
|
|
|
|
reverseDep.erase(I);
|
|
|
|
I = reverseDep.find(rem);
|
|
|
|
}
|
2007-07-12 02:06:21 +02:00
|
|
|
|
|
|
|
getAnalysis<AliasAnalysis>().deleteValue(rem);
|
2007-07-07 01:14:35 +02:00
|
|
|
}
|