blob: c35e189de6fc69bec3161c88d3ce3f0727a3d28f [file] [log] [blame]
//===-- DOTGraphTraitsPass.h - Print/View dotty graphs-----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Templates to create dotty viewer and printer passes for GraphTraits graphs.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ANALYSIS_DOTGRAPHTRAITSPASS_H
#define LLVM_ANALYSIS_DOTGRAPHTRAITSPASS_H
#include "llvm/Analysis/CFGPrinter.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/GraphWriter.h"
namespace llvm {
/// Default traits class for extracting a graph from an analysis pass.
///
/// This assumes that 'GraphT' is 'AnalysisT::Result *', and pass it through
template <typename Result, typename GraphT = Result *>
struct DefaultAnalysisGraphTraits {
static GraphT getGraph(Result R) { return &R; }
};
template <typename GraphT>
void viewGraphForFunction(Function &F, GraphT Graph, StringRef Name,
bool IsSimple) {
std::string GraphName = DOTGraphTraits<GraphT *>::getGraphName(&Graph);
ViewGraph(Graph, Name, IsSimple,
GraphName + " for '" + F.getName() + "' function");
}
template <typename AnalysisT, bool IsSimple,
typename GraphT = typename AnalysisT::Result *,
typename AnalysisGraphTraitsT =
DefaultAnalysisGraphTraits<typename AnalysisT::Result &, GraphT>>
struct DOTGraphTraitsViewer
: PassInfoMixin<DOTGraphTraitsViewer<AnalysisT, IsSimple, GraphT,
AnalysisGraphTraitsT>> {
DOTGraphTraitsViewer(StringRef GraphName) : Name(GraphName) {}
/// Return true if this function should be processed.
///
/// An implementation of this class my override this function to indicate that
/// only certain functions should be viewed.
///
/// @param Result The current analysis result for this function.
virtual bool processFunction(Function &F,
const typename AnalysisT::Result &Result) {
return true;
}
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
auto &Result = FAM.getResult<AnalysisT>(F);
if (!processFunction(F, Result))
return PreservedAnalyses::all();
GraphT Graph = AnalysisGraphTraitsT::getGraph(Result);
viewGraphForFunction(F, Graph, Name, IsSimple);
return PreservedAnalyses::all();
};
protected:
/// Avoid compiler warning "has virtual functions but non-virtual destructor
/// [-Wnon-virtual-dtor]" in derived classes.
///
/// DOTGraphTraitsViewer is also used as a mixin for avoiding repeated
/// implementation of viewer passes, ie there should be no
/// runtime-polymorphisms/downcasting involving this class and hence no
/// virtual destructor needed. Making this dtor protected stops accidental
/// invocation when the derived class destructor should have been called.
/// Those derived classes sould be marked final to avoid the warning.
~DOTGraphTraitsViewer() {}
private:
StringRef Name;
};
template <typename GraphT>
void printGraphForFunction(Function &F, GraphT Graph, StringRef Name,
bool IsSimple) {
std::string Filename = Name.str() + "." + F.getName().str() + ".dot";
std::error_code EC;
errs() << "Writing '" << Filename << "'...";
raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
if (!EC)
WriteGraph(File, Graph, IsSimple,
GraphName + " for '" + F.getName() + "' function");
else
errs() << " error opening file for writing!";
errs() << "\n";
}
template <typename AnalysisT, bool IsSimple,
typename GraphT = typename AnalysisT::Result *,
typename AnalysisGraphTraitsT =
DefaultAnalysisGraphTraits<typename AnalysisT::Result &, GraphT>>
struct DOTGraphTraitsPrinter
: PassInfoMixin<DOTGraphTraitsPrinter<AnalysisT, IsSimple, GraphT,
AnalysisGraphTraitsT>> {
DOTGraphTraitsPrinter(StringRef GraphName) : Name(GraphName) {}
/// Return true if this function should be processed.
///
/// An implementation of this class my override this function to indicate that
/// only certain functions should be viewed.
///
/// @param Analysis The current analysis result for this function.
virtual bool processFunction(Function &F,
const typename AnalysisT::Result &Result) {
return true;
}
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
auto &Result = FAM.getResult<AnalysisT>(F);
if (!processFunction(F, Result))
return PreservedAnalyses::all();
GraphT Graph = AnalysisGraphTraitsT::getGraph(Result);
printGraphForFunction(F, Graph, Name, IsSimple);
return PreservedAnalyses::all();
};
protected:
/// Avoid compiler warning "has virtual functions but non-virtual destructor
/// [-Wnon-virtual-dtor]" in derived classes.
///
/// DOTGraphTraitsPrinter is also used as a mixin for avoiding repeated
/// implementation of printer passes, ie there should be no
/// runtime-polymorphisms/downcasting involving this class and hence no
/// virtual destructor needed. Making this dtor protected stops accidental
/// invocation when the derived class destructor should have been called.
/// Those derived classes sould be marked final to avoid the warning.
~DOTGraphTraitsPrinter() {}
private:
StringRef Name;
};
/// Default traits class for extracting a graph from an analysis pass.
///
/// This assumes that 'GraphT' is 'AnalysisT *' and so just passes it through.
template <typename AnalysisT, typename GraphT = AnalysisT *>
struct LegacyDefaultAnalysisGraphTraits {
static GraphT getGraph(AnalysisT *A) { return A; }
};
template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
typename AnalysisGraphTraitsT =
LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
class DOTGraphTraitsViewerWrapperPass : public FunctionPass {
public:
DOTGraphTraitsViewerWrapperPass(StringRef GraphName, char &ID)
: FunctionPass(ID), Name(GraphName) {}
/// Return true if this function should be processed.
///
/// An implementation of this class my override this function to indicate that
/// only certain functions should be viewed.
///
/// @param Analysis The current analysis result for this function.
virtual bool processFunction(Function &F, AnalysisT &Analysis) {
return true;
}
bool runOnFunction(Function &F) override {
auto &Analysis = getAnalysis<AnalysisT>();
if (!processFunction(F, Analysis))
return false;
GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis);
viewGraphForFunction(F, Graph, Name, IsSimple);
return false;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<AnalysisT>();
}
private:
std::string Name;
};
template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
typename AnalysisGraphTraitsT =
LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
class DOTGraphTraitsPrinterWrapperPass : public FunctionPass {
public:
DOTGraphTraitsPrinterWrapperPass(StringRef GraphName, char &ID)
: FunctionPass(ID), Name(GraphName) {}
/// Return true if this function should be processed.
///
/// An implementation of this class my override this function to indicate that
/// only certain functions should be printed.
///
/// @param Analysis The current analysis result for this function.
virtual bool processFunction(Function &F, AnalysisT &Analysis) {
return true;
}
bool runOnFunction(Function &F) override {
auto &Analysis = getAnalysis<AnalysisT>();
if (!processFunction(F, Analysis))
return false;
GraphT Graph = AnalysisGraphTraitsT::getGraph(&Analysis);
printGraphForFunction(F, Graph, Name, IsSimple);
return false;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<AnalysisT>();
}
private:
std::string Name;
};
template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
typename AnalysisGraphTraitsT =
LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
class DOTGraphTraitsModuleViewerWrapperPass : public ModulePass {
public:
DOTGraphTraitsModuleViewerWrapperPass(StringRef GraphName, char &ID)
: ModulePass(ID), Name(GraphName) {}
bool runOnModule(Module &M) override {
GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
ViewGraph(Graph, Name, IsSimple, Title);
return false;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<AnalysisT>();
}
private:
std::string Name;
};
template <typename AnalysisT, bool IsSimple, typename GraphT = AnalysisT *,
typename AnalysisGraphTraitsT =
LegacyDefaultAnalysisGraphTraits<AnalysisT, GraphT>>
class DOTGraphTraitsModulePrinterWrapperPass : public ModulePass {
public:
DOTGraphTraitsModulePrinterWrapperPass(StringRef GraphName, char &ID)
: ModulePass(ID), Name(GraphName) {}
bool runOnModule(Module &M) override {
GraphT Graph = AnalysisGraphTraitsT::getGraph(&getAnalysis<AnalysisT>());
std::string Filename = Name + ".dot";
std::error_code EC;
errs() << "Writing '" << Filename << "'...";
raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
if (!EC)
WriteGraph(File, Graph, IsSimple, Title);
else
errs() << " error opening file for writing!";
errs() << "\n";
return false;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<AnalysisT>();
}
private:
std::string Name;
};
template <typename GraphT>
void WriteDOTGraphToFile(Function &F, GraphT &&Graph,
std::string FileNamePrefix, bool IsSimple) {
std::string Filename = FileNamePrefix + "." + F.getName().str() + ".dot";
std::error_code EC;
errs() << "Writing '" << Filename << "'...";
raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
std::string Title = GraphName + " for '" + F.getName().str() + "' function";
if (!EC)
WriteGraph(File, Graph, IsSimple, Title);
else
errs() << " error opening file for writing!";
errs() << "\n";
}
} // end namespace llvm
#endif