Index: include/llvm/Analysis/MemoryDependenceAnalysis.h =================================================================== --- include/llvm/Analysis/MemoryDependenceAnalysis.h +++ include/llvm/Analysis/MemoryDependenceAnalysis.h @@ -163,6 +163,9 @@ bool operator!=(const MemDepResult &M) const { return Value != M.Value; } bool operator<(const MemDepResult &M) const { return Value < M.Value; } bool operator>(const MemDepResult &M) const { return Value > M.Value; } + + void print(raw_ostream &OS, unsigned Depth = 0) const; + private: friend class MemoryDependenceAnalysis; /// Dirty - Entries with this marker occur in a LocalDeps map or @@ -326,6 +329,7 @@ DominatorTree *DT; AssumptionCache *AC; std::unique_ptr PredCache; + Function *Func; public: MemoryDependenceAnalysis(); @@ -421,6 +425,9 @@ unsigned MemLocSize, const LoadInst *LI); + /// \brief Print the result of the analysis when invoked with -analyze. + void print(raw_ostream &OS, const Module *M = nullptr) const override; + private: MemDepResult getCallSiteDependencyFrom(CallSite C, bool isReadOnlyCall, BasicBlock::iterator ScanIt, Index: lib/Analysis/MemoryDependenceAnalysis.cpp =================================================================== --- lib/Analysis/MemoryDependenceAnalysis.cpp +++ lib/Analysis/MemoryDependenceAnalysis.cpp @@ -65,7 +65,7 @@ "Memory Dependence Analysis", false, true) MemoryDependenceAnalysis::MemoryDependenceAnalysis() - : FunctionPass(ID), PredCache() { + : FunctionPass(ID), PredCache(), Func(nullptr) { initializeMemoryDependenceAnalysisPass(*PassRegistry::getPassRegistry()); } MemoryDependenceAnalysis::~MemoryDependenceAnalysis() { @@ -91,6 +91,7 @@ } bool MemoryDependenceAnalysis::runOnFunction(Function &F) { + Func = &F; AA = &getAnalysis(); AC = &getAnalysis().getAssumptionCache(F); DominatorTreeWrapperPass *DTWP = @@ -1702,3 +1703,49 @@ } #endif } + +void MemDepResult::print(raw_ostream &OS, unsigned Depth) const { + const char *type; + switch (Value.getInt()) { + case Clobber: type = "Clobber:"; break; + case Def: type = "Def:"; break; + case Other: + if (isNonLocal()) + type = "NonLocal"; + else if (isNonFuncLocal()) + type = "NonFuncLocal"; + else if (isUnknown()) + type = "Unknown"; + break; + default: + llvm_unreachable("unknown deptype"); + } + + OS.indent(Depth) << type; + Instruction *Inst = getInst(); + if (Inst) + OS << " " << *getInst(); + OS << "\n"; +} + +void MemoryDependenceAnalysis::print(raw_ostream &OS, + const Module *M) const { + MemoryDependenceAnalysis *MD = const_cast(this); + + for (auto &BB: *Func) + for (auto &Inst : BB) { + if (!isa(&Inst) && !isa(&Inst)) + continue; + OS << Inst << "\n"; + MemDepResult Dep = MD->getDependency(&Inst); + Dep.print(OS, 4); + if (Dep.isNonLocal()) { + SmallVector Deps; + MD->getNonLocalPointerDependency(&Inst, Deps); + for (const NonLocalDepResult &NonLocalDep : Deps) { + OS.indent(6) << NonLocalDep.getBB()->getName() << ": "; + NonLocalDep.getResult().print(OS); + } + } + } +} Index: test/Analysis/MemoryDependenceAnalysis/analyze-option.ll =================================================================== --- /dev/null +++ test/Analysis/MemoryDependenceAnalysis/analyze-option.ll @@ -0,0 +1,43 @@ +; GVN is used to ensure that domtree which is an optional analysis pass does +; not get freed before memdep. Without domtree, memdep won't perform +; non-local dependence analysis. + +; RUN: opt -analyze -basicaa -domtree -memdep -gvn < %s | FileCheck %s + +; Test that for this loop: +; +; for (unsigned i = 0; i < 100; i++) +; A[i+1] = A[i] + B[i]; +; +; memdep discovers the non-local depedence between the store of A[i+1] and the +; load of A[i] in the subsequent iteration. This is necessary so that GVN +; Load-PRE will promote this store-to-load forwarding case to a register. + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +define void @f(i8* noalias nocapture %A, i8* noalias nocapture readonly %B) { +entry: + br label %for.body + +; CHECK: Printing analysis 'Memory Dependence Analysis' for function 'f': +; CHECK-NEXT: %load = load i8, i8* %arrayidx, align 1 +; CHECK-NEXT: NonLocal +; CHECK-NEXT: for.body: Def: store i8 %add, i8* %arrayidx_next, align 1 + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %arrayidx = getelementptr inbounds i8, i8* %A, i64 %indvars.iv + %load = load i8, i8* %arrayidx, align 1 + %arrayidx2 = getelementptr inbounds i8, i8* %B, i64 %indvars.iv + %load_1 = load i8, i8* %arrayidx2, align 1 + %add = add i8 %load_1, %load + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %arrayidx_next = getelementptr inbounds i8, i8* %A, i64 %indvars.iv.next + store i8 %add, i8* %arrayidx_next, align 1 + %exitcond = icmp eq i64 %indvars.iv.next, 100 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} +