llvm/lib/Analysis/MemDepPrinter.cpp
Chandler Carruth c5266b5293 [PM] Port memdep to the new pass manager.
This is a fairly straightforward port to the new pass manager with one
exception. It removes a very questionable use of releaseMemory() in
the old pass to invalidate its caches between runs on a function.
I don't think this is really guaranteed to be safe. I've just used the
more direct port to the new PM to address this by nuking the results
object each time the pass runs. While this could cause some minor malloc
traffic increase, I don't expect the compile time performance hit to be
noticable, and it makes the correctness and other aspects of the pass
much easier to reason about. In some cases, it may make things faster by
making the sets and maps smaller with better locality. Indeed, the
measurements collected by Bruno (thanks!!!) show mostly compile time
improvements.

There is sadly very limited testing at this point as there are only two
tests of memdep, and both rely on GVN. I'll be porting GVN next and that
will exercise this heavily though.

Differential Revision: http://reviews.llvm.org/D17962

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263082 91177308-0d34-0410-b5e6-96231b3b80d8
2016-03-10 00:55:30 +00:00

169 lines
5.2 KiB
C++

//===- MemDepPrinter.cpp - Printer for MemoryDependenceAnalysis -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/Passes.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
struct MemDepPrinter : public FunctionPass {
const Function *F;
enum DepType {
Clobber = 0,
Def,
NonFuncLocal,
Unknown
};
static const char *const DepTypeStr[];
typedef PointerIntPair<const Instruction *, 2, DepType> InstTypePair;
typedef std::pair<InstTypePair, const BasicBlock *> Dep;
typedef SmallSetVector<Dep, 4> DepSet;
typedef DenseMap<const Instruction *, DepSet> DepSetMap;
DepSetMap Deps;
static char ID; // Pass identifcation, replacement for typeid
MemDepPrinter() : FunctionPass(ID) {
initializeMemDepPrinterPass(*PassRegistry::getPassRegistry());
}
bool runOnFunction(Function &F) override;
void print(raw_ostream &OS, const Module * = nullptr) const override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequiredTransitive<AAResultsWrapperPass>();
AU.addRequiredTransitive<MemoryDependenceWrapperPass>();
AU.setPreservesAll();
}
void releaseMemory() override {
Deps.clear();
F = nullptr;
}
private:
static InstTypePair getInstTypePair(MemDepResult dep) {
if (dep.isClobber())
return InstTypePair(dep.getInst(), Clobber);
if (dep.isDef())
return InstTypePair(dep.getInst(), Def);
if (dep.isNonFuncLocal())
return InstTypePair(dep.getInst(), NonFuncLocal);
assert(dep.isUnknown() && "unexpected dependence type");
return InstTypePair(dep.getInst(), Unknown);
}
static InstTypePair getInstTypePair(const Instruction* inst, DepType type) {
return InstTypePair(inst, type);
}
};
}
char MemDepPrinter::ID = 0;
INITIALIZE_PASS_BEGIN(MemDepPrinter, "print-memdeps",
"Print MemDeps of function", false, true)
INITIALIZE_PASS_DEPENDENCY(MemoryDependenceWrapperPass)
INITIALIZE_PASS_END(MemDepPrinter, "print-memdeps",
"Print MemDeps of function", false, true)
FunctionPass *llvm::createMemDepPrinter() {
return new MemDepPrinter();
}
const char *const MemDepPrinter::DepTypeStr[]
= {"Clobber", "Def", "NonFuncLocal", "Unknown"};
bool MemDepPrinter::runOnFunction(Function &F) {
this->F = &F;
MemoryDependenceResults &MDA = getAnalysis<MemoryDependenceWrapperPass>().getMemDep();
// All this code uses non-const interfaces because MemDep is not
// const-friendly, though nothing is actually modified.
for (auto &I : instructions(F)) {
Instruction *Inst = &I;
if (!Inst->mayReadFromMemory() && !Inst->mayWriteToMemory())
continue;
MemDepResult Res = MDA.getDependency(Inst);
if (!Res.isNonLocal()) {
Deps[Inst].insert(std::make_pair(getInstTypePair(Res),
static_cast<BasicBlock *>(nullptr)));
} else if (auto CS = CallSite(Inst)) {
const MemoryDependenceResults::NonLocalDepInfo &NLDI =
MDA.getNonLocalCallDependency(CS);
DepSet &InstDeps = Deps[Inst];
for (MemoryDependenceResults::NonLocalDepInfo::const_iterator
I = NLDI.begin(), E = NLDI.end(); I != E; ++I) {
const MemDepResult &Res = I->getResult();
InstDeps.insert(std::make_pair(getInstTypePair(Res), I->getBB()));
}
} else {
SmallVector<NonLocalDepResult, 4> NLDI;
assert( (isa<LoadInst>(Inst) || isa<StoreInst>(Inst) ||
isa<VAArgInst>(Inst)) && "Unknown memory instruction!");
MDA.getNonLocalPointerDependency(Inst, NLDI);
DepSet &InstDeps = Deps[Inst];
for (SmallVectorImpl<NonLocalDepResult>::const_iterator
I = NLDI.begin(), E = NLDI.end(); I != E; ++I) {
const MemDepResult &Res = I->getResult();
InstDeps.insert(std::make_pair(getInstTypePair(Res), I->getBB()));
}
}
}
return false;
}
void MemDepPrinter::print(raw_ostream &OS, const Module *M) const {
for (const auto &I : instructions(*F)) {
const Instruction *Inst = &I;
DepSetMap::const_iterator DI = Deps.find(Inst);
if (DI == Deps.end())
continue;
const DepSet &InstDeps = DI->second;
for (const auto &I : InstDeps) {
const Instruction *DepInst = I.first.getPointer();
DepType type = I.first.getInt();
const BasicBlock *DepBB = I.second;
OS << " ";
OS << DepTypeStr[type];
if (DepBB) {
OS << " in block ";
DepBB->printAsOperand(OS, /*PrintType=*/false, M);
}
if (DepInst) {
OS << " from: ";
DepInst->print(OS);
}
OS << "\n";
}
Inst->print(OS);
OS << "\n\n";
}
}