#ifndef LLVM_IR_PASSINSTRUMENTATION_H
#define LLVM_IR_PASSINSTRUMENTATION_H
#include "llvm/ADT/Any.h"
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include <type_traits>
#include <vector>
namespace llvm {
class PreservedAnalyses;
class StringRef;
class PassInstrumentationCallbacks {
public:
using BeforePassFunc = bool(StringRef, Any);
using BeforeSkippedPassFunc = void(StringRef, Any);
using BeforeNonSkippedPassFunc = void(StringRef, Any);
using AfterPassFunc = void(StringRef, Any, const PreservedAnalyses &);
using AfterPassInvalidatedFunc = void(StringRef, const PreservedAnalyses &);
using BeforeAnalysisFunc = void(StringRef, Any);
using AfterAnalysisFunc = void(StringRef, Any);
using AnalysisInvalidatedFunc = void(StringRef, Any);
using AnalysesClearedFunc = void(StringRef);
public:
PassInstrumentationCallbacks() = default;
PassInstrumentationCallbacks(const PassInstrumentationCallbacks &) = delete;
void operator=(const PassInstrumentationCallbacks &) = delete;
template <typename CallableT>
void registerShouldRunOptionalPassCallback(CallableT C) {
ShouldRunOptionalPassCallbacks.emplace_back(std::move(C));
}
template <typename CallableT>
void registerBeforeSkippedPassCallback(CallableT C) {
BeforeSkippedPassCallbacks.emplace_back(std::move(C));
}
template <typename CallableT>
void registerBeforeNonSkippedPassCallback(CallableT C) {
BeforeNonSkippedPassCallbacks.emplace_back(std::move(C));
}
template <typename CallableT> void registerAfterPassCallback(CallableT C) {
AfterPassCallbacks.emplace_back(std::move(C));
}
template <typename CallableT>
void registerAfterPassInvalidatedCallback(CallableT C) {
AfterPassInvalidatedCallbacks.emplace_back(std::move(C));
}
template <typename CallableT>
void registerBeforeAnalysisCallback(CallableT C) {
BeforeAnalysisCallbacks.emplace_back(std::move(C));
}
template <typename CallableT>
void registerAfterAnalysisCallback(CallableT C) {
AfterAnalysisCallbacks.emplace_back(std::move(C));
}
template <typename CallableT>
void registerAnalysisInvalidatedCallback(CallableT C) {
AnalysisInvalidatedCallbacks.emplace_back(std::move(C));
}
template <typename CallableT>
void registerAnalysesClearedCallback(CallableT C) {
AnalysesClearedCallbacks.emplace_back(std::move(C));
}
void addClassToPassName(StringRef ClassName, StringRef PassName);
StringRef getPassNameForClassName(StringRef ClassName);
private:
friend class PassInstrumentation;
SmallVector<llvm::unique_function<BeforePassFunc>, 4>
ShouldRunOptionalPassCallbacks;
SmallVector<llvm::unique_function<BeforeSkippedPassFunc>, 4>
BeforeSkippedPassCallbacks;
SmallVector<llvm::unique_function<BeforeNonSkippedPassFunc>, 4>
BeforeNonSkippedPassCallbacks;
SmallVector<llvm::unique_function<AfterPassFunc>, 4> AfterPassCallbacks;
SmallVector<llvm::unique_function<AfterPassInvalidatedFunc>, 4>
AfterPassInvalidatedCallbacks;
SmallVector<llvm::unique_function<BeforeAnalysisFunc>, 4>
BeforeAnalysisCallbacks;
SmallVector<llvm::unique_function<AfterAnalysisFunc>, 4>
AfterAnalysisCallbacks;
SmallVector<llvm::unique_function<AnalysisInvalidatedFunc>, 4>
AnalysisInvalidatedCallbacks;
SmallVector<llvm::unique_function<AnalysesClearedFunc>, 4>
AnalysesClearedCallbacks;
StringMap<std::string> ClassToPassName;
};
class PassInstrumentation {
PassInstrumentationCallbacks *Callbacks;
template <typename PassT>
using has_required_t = decltype(std::declval<PassT &>().isRequired());
template <typename PassT>
static std::enable_if_t<is_detected<has_required_t, PassT>::value, bool>
isRequired(const PassT &Pass) {
return Pass.isRequired();
}
template <typename PassT>
static std::enable_if_t<!is_detected<has_required_t, PassT>::value, bool>
isRequired(const PassT &Pass) {
return false;
}
public:
PassInstrumentation(PassInstrumentationCallbacks *CB = nullptr)
: Callbacks(CB) {}
template <typename IRUnitT, typename PassT>
bool runBeforePass(const PassT &Pass, const IRUnitT &IR) const {
if (!Callbacks)
return true;
bool ShouldRun = true;
if (!isRequired(Pass)) {
for (auto &C : Callbacks->ShouldRunOptionalPassCallbacks)
ShouldRun &= C(Pass.name(), llvm::Any(&IR));
}
if (ShouldRun) {
for (auto &C : Callbacks->BeforeNonSkippedPassCallbacks)
C(Pass.name(), llvm::Any(&IR));
} else {
for (auto &C : Callbacks->BeforeSkippedPassCallbacks)
C(Pass.name(), llvm::Any(&IR));
}
return ShouldRun;
}
template <typename IRUnitT, typename PassT>
void runAfterPass(const PassT &Pass, const IRUnitT &IR,
const PreservedAnalyses &PA) const {
if (Callbacks)
for (auto &C : Callbacks->AfterPassCallbacks)
C(Pass.name(), llvm::Any(&IR), PA);
}
template <typename IRUnitT, typename PassT>
void runAfterPassInvalidated(const PassT &Pass,
const PreservedAnalyses &PA) const {
if (Callbacks)
for (auto &C : Callbacks->AfterPassInvalidatedCallbacks)
C(Pass.name(), PA);
}
template <typename IRUnitT, typename PassT>
void runBeforeAnalysis(const PassT &Analysis, const IRUnitT &IR) const {
if (Callbacks)
for (auto &C : Callbacks->BeforeAnalysisCallbacks)
C(Analysis.name(), llvm::Any(&IR));
}
template <typename IRUnitT, typename PassT>
void runAfterAnalysis(const PassT &Analysis, const IRUnitT &IR) const {
if (Callbacks)
for (auto &C : Callbacks->AfterAnalysisCallbacks)
C(Analysis.name(), llvm::Any(&IR));
}
template <typename IRUnitT, typename PassT>
void runAnalysisInvalidated(const PassT &Analysis, const IRUnitT &IR) const {
if (Callbacks)
for (auto &C : Callbacks->AnalysisInvalidatedCallbacks)
C(Analysis.name(), llvm::Any(&IR));
}
void runAnalysesCleared(StringRef Name) const {
if (Callbacks)
for (auto &C : Callbacks->AnalysesClearedCallbacks)
C(Name);
}
template <typename IRUnitT, typename... ExtraArgsT>
bool invalidate(IRUnitT &, const class llvm::PreservedAnalyses &,
ExtraArgsT...) {
return false;
}
template <typename CallableT>
void pushBeforeNonSkippedPassCallback(CallableT C) {
if (Callbacks)
Callbacks->BeforeNonSkippedPassCallbacks.emplace_back(std::move(C));
}
void popBeforeNonSkippedPassCallback() {
if (Callbacks)
Callbacks->BeforeNonSkippedPassCallbacks.pop_back();
}
};
bool isSpecialPass(StringRef PassID, const std::vector<StringRef> &Specials);
}
#endif