#ifndef LLVM_PASSES_STANDARDINSTRUMENTATIONS_H
#define LLVM_PASSES_STANDARDINSTRUMENTATIONS_H
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/OptBisect.h"
#include "llvm/IR/PassTimingInfo.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/IPO/SampleProfileProbe.h"
#include <string>
#include <utility>
namespace llvm {
class Module;
class Function;
class PassInstrumentationCallbacks;
class PrintIRInstrumentation {
public:
~PrintIRInstrumentation();
void registerCallbacks(PassInstrumentationCallbacks &PIC);
private:
void printBeforePass(StringRef PassID, Any IR);
void printAfterPass(StringRef PassID, Any IR);
void printAfterPassInvalidated(StringRef PassID);
bool shouldPrintBeforePass(StringRef PassID);
bool shouldPrintAfterPass(StringRef PassID);
using PrintModuleDesc = std::tuple<const Module *, std::string, StringRef>;
void pushModuleDesc(StringRef PassID, Any IR);
PrintModuleDesc popModuleDesc(StringRef PassID);
PassInstrumentationCallbacks *PIC;
SmallVector<PrintModuleDesc, 2> ModuleDescStack;
};
class OptNoneInstrumentation {
public:
OptNoneInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
void registerCallbacks(PassInstrumentationCallbacks &PIC);
private:
bool DebugLogging;
bool shouldRun(StringRef PassID, Any IR);
};
class OptBisectInstrumentation {
public:
OptBisectInstrumentation() = default;
void registerCallbacks(PassInstrumentationCallbacks &PIC);
};
struct PrintPassOptions {
bool Verbose = false;
bool SkipAnalyses = false;
bool Indent = false;
};
class PrintPassInstrumentation {
raw_ostream &print();
public:
PrintPassInstrumentation(bool Enabled, PrintPassOptions Opts)
: Enabled(Enabled), Opts(Opts) {}
void registerCallbacks(PassInstrumentationCallbacks &PIC);
private:
bool Enabled;
PrintPassOptions Opts;
int Indent = 0;
};
class PreservedCFGCheckerInstrumentation {
public:
struct BBGuard final : public CallbackVH {
BBGuard(const BasicBlock *BB) : CallbackVH(BB) {}
void deleted() override { CallbackVH::deleted(); }
void allUsesReplacedWith(Value *) override { CallbackVH::deleted(); }
bool isPoisoned() const { return !getValPtr(); }
};
struct CFG {
Optional<DenseMap<intptr_t, BBGuard>> BBGuards;
DenseMap<const BasicBlock *, DenseMap<const BasicBlock *, unsigned>> Graph;
CFG(const Function *F, bool TrackBBLifetime);
bool operator==(const CFG &G) const {
return !isPoisoned() && !G.isPoisoned() && Graph == G.Graph;
}
bool isPoisoned() const {
return BBGuards && llvm::any_of(*BBGuards, [](const auto &BB) {
return BB.second.isPoisoned();
});
}
static void printDiff(raw_ostream &out, const CFG &Before,
const CFG &After);
bool invalidate(Function &F, const PreservedAnalyses &PA,
FunctionAnalysisManager::Invalidator &);
};
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
SmallVector<StringRef, 8> PassStack;
#endif
static cl::opt<bool> VerifyPreservedCFG;
void registerCallbacks(PassInstrumentationCallbacks &PIC,
FunctionAnalysisManager &FAM);
};
template <typename IRUnitT> class ChangeReporter {
protected:
ChangeReporter(bool RunInVerboseMode) : VerboseMode(RunInVerboseMode) {}
public:
virtual ~ChangeReporter();
void saveIRBeforePass(Any IR, StringRef PassID);
void handleIRAfterPass(Any IR, StringRef PassID);
void handleInvalidatedPass(StringRef PassID);
protected:
void registerRequiredCallbacks(PassInstrumentationCallbacks &PIC);
virtual void handleInitialIR(Any IR) = 0;
virtual void generateIRRepresentation(Any IR, StringRef PassID,
IRUnitT &Output) = 0;
virtual void omitAfter(StringRef PassID, std::string &Name) = 0;
virtual void handleAfter(StringRef PassID, std::string &Name,
const IRUnitT &Before, const IRUnitT &After,
Any) = 0;
virtual void handleInvalidated(StringRef PassID) = 0;
virtual void handleFiltered(StringRef PassID, std::string &Name) = 0;
virtual void handleIgnored(StringRef PassID, std::string &Name) = 0;
std::vector<IRUnitT> BeforeStack;
bool InitialIR = true;
const bool VerboseMode;
};
template <typename IRUnitT>
class TextChangeReporter : public ChangeReporter<IRUnitT> {
protected:
TextChangeReporter(bool Verbose);
void handleInitialIR(Any IR) override;
void omitAfter(StringRef PassID, std::string &Name) override;
void handleInvalidated(StringRef PassID) override;
void handleFiltered(StringRef PassID, std::string &Name) override;
void handleIgnored(StringRef PassID, std::string &Name) override;
raw_ostream &Out;
};
class IRChangedPrinter : public TextChangeReporter<std::string> {
public:
IRChangedPrinter(bool VerboseMode)
: TextChangeReporter<std::string>(VerboseMode) {}
~IRChangedPrinter() override;
void registerCallbacks(PassInstrumentationCallbacks &PIC);
protected:
void generateIRRepresentation(Any IR, StringRef PassID,
std::string &Output) override;
void handleAfter(StringRef PassID, std::string &Name,
const std::string &Before, const std::string &After,
Any) override;
};
template <typename T> class BlockDataT {
public:
BlockDataT(const BasicBlock &B) : Label(B.getName().str()), Data(B) {
raw_string_ostream SS(Body);
B.print(SS, nullptr, true, true);
}
bool operator==(const BlockDataT &That) const { return Body == That.Body; }
bool operator!=(const BlockDataT &That) const { return Body != That.Body; }
StringRef getLabel() const { return Label; }
StringRef getBody() const { return Body; }
const T &getData() const { return Data; }
protected:
std::string Label;
std::string Body;
T Data;
};
template <typename T> class OrderedChangedData {
public:
std::vector<std::string> &getOrder() { return Order; }
const std::vector<std::string> &getOrder() const { return Order; }
StringMap<T> &getData() { return Data; }
const StringMap<T> &getData() const { return Data; }
bool operator==(const OrderedChangedData<T> &That) const {
return Data == That.getData();
}
static void report(const OrderedChangedData &Before,
const OrderedChangedData &After,
function_ref<void(const T *, const T *)> HandlePair);
protected:
std::vector<std::string> Order;
StringMap<T> Data;
};
class EmptyData {
public:
EmptyData(const BasicBlock &) {}
};
template <typename T>
class FuncDataT : public OrderedChangedData<BlockDataT<T>> {
public:
FuncDataT(std::string S) : EntryBlockName(S) {}
std::string getEntryBlockName() const { return EntryBlockName; }
protected:
std::string EntryBlockName;
};
template <typename T>
class IRDataT : public OrderedChangedData<FuncDataT<T>> {};
template <typename T> class IRComparer {
public:
IRComparer(const IRDataT<T> &Before, const IRDataT<T> &After)
: Before(Before), After(After) {}
void compare(
bool CompareModule,
std::function<void(bool InModule, unsigned Minor,
const FuncDataT<T> &Before, const FuncDataT<T> &After)>
CompareFunc);
static void analyzeIR(Any IR, IRDataT<T> &Data);
protected:
static bool generateFunctionData(IRDataT<T> &Data, const Function &F);
const IRDataT<T> &Before;
const IRDataT<T> &After;
};
class InLineChangePrinter : public TextChangeReporter<IRDataT<EmptyData>> {
public:
InLineChangePrinter(bool VerboseMode, bool ColourMode)
: TextChangeReporter<IRDataT<EmptyData>>(VerboseMode),
UseColour(ColourMode) {}
~InLineChangePrinter() override;
void registerCallbacks(PassInstrumentationCallbacks &PIC);
protected:
void generateIRRepresentation(Any IR, StringRef PassID,
IRDataT<EmptyData> &Output) override;
void handleAfter(StringRef PassID, std::string &Name,
const IRDataT<EmptyData> &Before,
const IRDataT<EmptyData> &After, Any) override;
void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
StringRef Divider, bool InModule, unsigned Minor,
const FuncDataT<EmptyData> &Before,
const FuncDataT<EmptyData> &After);
bool UseColour;
};
class VerifyInstrumentation {
bool DebugLogging;
public:
VerifyInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
void registerCallbacks(PassInstrumentationCallbacks &PIC);
};
class DCData {
public:
DCData(const BasicBlock &B);
StringMap<std::string>::const_iterator begin() const {
return Successors.begin();
}
StringMap<std::string>::const_iterator end() const {
return Successors.end();
}
StringRef getSuccessorLabel(StringRef S) const {
assert(Successors.count(S) == 1 && "Expected to find successor.");
return Successors.find(S)->getValue();
}
protected:
void addSuccessorLabel(StringRef Succ, StringRef Label) {
std::pair<std::string, std::string> SS{Succ.str(), Label.str()};
Successors.insert(SS);
}
StringMap<std::string> Successors;
};
class DotCfgChangeReporter : public ChangeReporter<IRDataT<DCData>> {
public:
DotCfgChangeReporter(bool Verbose);
~DotCfgChangeReporter() override;
void registerCallbacks(PassInstrumentationCallbacks &PIC);
protected:
bool initializeHTML();
void handleInitialIR(Any IR) override;
void generateIRRepresentation(Any IR, StringRef PassID,
IRDataT<DCData> &Output) override;
void omitAfter(StringRef PassID, std::string &Name) override;
void handleAfter(StringRef PassID, std::string &Name,
const IRDataT<DCData> &Before, const IRDataT<DCData> &After,
Any) override;
void handleInvalidated(StringRef PassID) override;
void handleFiltered(StringRef PassID, std::string &Name) override;
void handleIgnored(StringRef PassID, std::string &Name) override;
static std::string genHTML(StringRef Text, StringRef DotFile,
StringRef PDFFileName);
void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
StringRef Divider, bool InModule, unsigned Minor,
const FuncDataT<DCData> &Before,
const FuncDataT<DCData> &After);
unsigned N = 0;
std::unique_ptr<raw_fd_ostream> HTML;
};
class PrintCrashIRInstrumentation {
public:
PrintCrashIRInstrumentation()
: SavedIR("*** Dump of IR Before Last Pass Unknown ***") {}
~PrintCrashIRInstrumentation();
void registerCallbacks(PassInstrumentationCallbacks &PIC);
void reportCrashIR();
protected:
std::string SavedIR;
private:
static PrintCrashIRInstrumentation *CrashReporter;
static void SignalHandler(void *);
};
class StandardInstrumentations {
PrintIRInstrumentation PrintIR;
PrintPassInstrumentation PrintPass;
TimePassesHandler TimePasses;
OptNoneInstrumentation OptNone;
OptBisectInstrumentation OptBisect;
PreservedCFGCheckerInstrumentation PreservedCFGChecker;
IRChangedPrinter PrintChangedIR;
PseudoProbeVerifier PseudoProbeVerification;
InLineChangePrinter PrintChangedDiff;
DotCfgChangeReporter WebsiteChangeReporter;
PrintCrashIRInstrumentation PrintCrashIR;
VerifyInstrumentation Verify;
bool VerifyEach;
public:
StandardInstrumentations(bool DebugLogging, bool VerifyEach = false,
PrintPassOptions PrintPassOpts = PrintPassOptions());
void registerCallbacks(PassInstrumentationCallbacks &PIC,
FunctionAnalysisManager *FAM = nullptr);
TimePassesHandler &getTimePasses() { return TimePasses; }
};
extern template class ChangeReporter<std::string>;
extern template class TextChangeReporter<std::string>;
extern template class BlockDataT<EmptyData>;
extern template class FuncDataT<EmptyData>;
extern template class IRDataT<EmptyData>;
extern template class ChangeReporter<IRDataT<EmptyData>>;
extern template class TextChangeReporter<IRDataT<EmptyData>>;
extern template class IRComparer<EmptyData>;
}
#endif