mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:43:36 +01:00
1c866d4e4f
This is a followup to D103422. The DenseMapInfo implementations for ArrayRef and StringRef are moved into the ArrayRef.h and StringRef.h headers, which means that these two headers no longer need to be included by DenseMapInfo.h. This required adding a few additional includes, as many files were relying on various things pulled in by ArrayRef.h. Differential Revision: https://reviews.llvm.org/D103491
323 lines
13 KiB
C++
323 lines
13 KiB
C++
//===- llvm/IR/PassInstrumentation.h ----------------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
/// \file
|
|
///
|
|
/// This file defines the Pass Instrumentation classes that provide
|
|
/// instrumentation points into the pass execution by PassManager.
|
|
///
|
|
/// There are two main classes:
|
|
/// - PassInstrumentation provides a set of instrumentation points for
|
|
/// pass managers to call on.
|
|
///
|
|
/// - PassInstrumentationCallbacks registers callbacks and provides access
|
|
/// to them for PassInstrumentation.
|
|
///
|
|
/// PassInstrumentation object is being used as a result of
|
|
/// PassInstrumentationAnalysis (so it is intended to be easily copyable).
|
|
///
|
|
/// Intended scheme of use for Pass Instrumentation is as follows:
|
|
/// - register instrumentation callbacks in PassInstrumentationCallbacks
|
|
/// instance. PassBuilder provides helper for that.
|
|
///
|
|
/// - register PassInstrumentationAnalysis with all the PassManagers.
|
|
/// PassBuilder handles that automatically when registering analyses.
|
|
///
|
|
/// - Pass Manager requests PassInstrumentationAnalysis from analysis manager
|
|
/// and gets PassInstrumentation as its result.
|
|
///
|
|
/// - Pass Manager invokes PassInstrumentation entry points appropriately,
|
|
/// passing StringRef identification ("name") of the pass currently being
|
|
/// executed and IRUnit it works on. There can be different schemes of
|
|
/// providing names in future, currently it is just a name() of the pass.
|
|
///
|
|
/// - PassInstrumentation wraps address of IRUnit into llvm::Any and passes
|
|
/// control to all the registered callbacks. Note that we specifically wrap
|
|
/// 'const IRUnitT*' so as to avoid any accidental changes to IR in
|
|
/// instrumenting callbacks.
|
|
///
|
|
/// - Some instrumentation points (BeforePass) allow to control execution
|
|
/// of a pass. For those callbacks returning false means pass will not be
|
|
/// executed.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#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;
|
|
|
|
/// This class manages callbacks registration, as well as provides a way for
|
|
/// PassInstrumentation to pass control to the registered callbacks.
|
|
class PassInstrumentationCallbacks {
|
|
public:
|
|
// Before/After callbacks accept IRUnits whenever appropriate, so they need
|
|
// to take them as constant pointers, wrapped with llvm::Any.
|
|
// For the case when IRUnit has been invalidated there is a different
|
|
// callback to use - AfterPassInvalidated.
|
|
// We call all BeforePassFuncs to determine if a pass should run or not.
|
|
// BeforeNonSkippedPassFuncs are called only if the pass should run.
|
|
// TODO: currently AfterPassInvalidated does not accept IRUnit, since passing
|
|
// already invalidated IRUnit is unsafe. There are ways to handle invalidated
|
|
// IRUnits in a safe way, and we might pursue that as soon as there is a
|
|
// useful instrumentation that needs it.
|
|
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() {}
|
|
|
|
/// Copying PassInstrumentationCallbacks is not intended.
|
|
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));
|
|
}
|
|
|
|
/// Add a class name to pass name mapping for use by pass instrumentation.
|
|
void addClassToPassName(StringRef ClassName, StringRef PassName);
|
|
/// Get the pass name for a given pass class name.
|
|
StringRef getPassNameForClassName(StringRef ClassName);
|
|
|
|
private:
|
|
friend class PassInstrumentation;
|
|
|
|
/// These are only run on passes that are not required. They return false when
|
|
/// an optional pass should be skipped.
|
|
SmallVector<llvm::unique_function<BeforePassFunc>, 4>
|
|
ShouldRunOptionalPassCallbacks;
|
|
/// These are run on passes that are skipped.
|
|
SmallVector<llvm::unique_function<BeforeSkippedPassFunc>, 4>
|
|
BeforeSkippedPassCallbacks;
|
|
/// These are run on passes that are about to be run.
|
|
SmallVector<llvm::unique_function<BeforeNonSkippedPassFunc>, 4>
|
|
BeforeNonSkippedPassCallbacks;
|
|
/// These are run on passes that have just run.
|
|
SmallVector<llvm::unique_function<AfterPassFunc>, 4> AfterPassCallbacks;
|
|
/// These are run passes that have just run on invalidated IR.
|
|
SmallVector<llvm::unique_function<AfterPassInvalidatedFunc>, 4>
|
|
AfterPassInvalidatedCallbacks;
|
|
/// These are run on analyses that are about to be run.
|
|
SmallVector<llvm::unique_function<BeforeAnalysisFunc>, 4>
|
|
BeforeAnalysisCallbacks;
|
|
/// These are run on analyses that have been run.
|
|
SmallVector<llvm::unique_function<AfterAnalysisFunc>, 4>
|
|
AfterAnalysisCallbacks;
|
|
/// These are run on analyses that have been invalidated.
|
|
SmallVector<llvm::unique_function<AnalysisInvalidatedFunc>, 4>
|
|
AnalysisInvalidatedCallbacks;
|
|
/// These are run on analyses that have been cleared.
|
|
SmallVector<llvm::unique_function<AnalysesClearedFunc>, 4>
|
|
AnalysesClearedCallbacks;
|
|
|
|
StringMap<std::string> ClassToPassName;
|
|
};
|
|
|
|
/// This class provides instrumentation entry points for the Pass Manager,
|
|
/// doing calls to callbacks registered in PassInstrumentationCallbacks.
|
|
class PassInstrumentation {
|
|
PassInstrumentationCallbacks *Callbacks;
|
|
|
|
// Template argument PassT of PassInstrumentation::runBeforePass could be two
|
|
// kinds: (1) a regular pass inherited from PassInfoMixin (happen when
|
|
// creating a adaptor pass for a regular pass); (2) a type-erased PassConcept
|
|
// created from (1). Here we want to make case (1) skippable unconditionally
|
|
// since they are regular passes. We call PassConcept::isRequired to decide
|
|
// for case (2).
|
|
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:
|
|
/// Callbacks object is not owned by PassInstrumentation, its life-time
|
|
/// should at least match the life-time of corresponding
|
|
/// PassInstrumentationAnalysis (which usually is till the end of current
|
|
/// compilation).
|
|
PassInstrumentation(PassInstrumentationCallbacks *CB = nullptr)
|
|
: Callbacks(CB) {}
|
|
|
|
/// BeforePass instrumentation point - takes \p Pass instance to be executed
|
|
/// and constant reference to IR it operates on. \Returns true if pass is
|
|
/// allowed to be executed. These are only run on optional pass since required
|
|
/// passes must always be run. This allows these callbacks to print info when
|
|
/// they want to skip a pass.
|
|
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;
|
|
}
|
|
|
|
/// AfterPass instrumentation point - takes \p Pass instance that has
|
|
/// just been executed and constant reference to \p IR it operates on.
|
|
/// \p IR is guaranteed to be valid at this point.
|
|
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);
|
|
}
|
|
|
|
/// AfterPassInvalidated instrumentation point - takes \p Pass instance
|
|
/// that has just been executed. For use when IR has been invalidated
|
|
/// by \p Pass execution.
|
|
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);
|
|
}
|
|
|
|
/// BeforeAnalysis instrumentation point - takes \p Analysis instance
|
|
/// to be executed and constant reference to IR it operates on.
|
|
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));
|
|
}
|
|
|
|
/// AfterAnalysis instrumentation point - takes \p Analysis instance
|
|
/// that has just been executed and constant reference to IR it operated on.
|
|
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));
|
|
}
|
|
|
|
/// AnalysisInvalidated instrumentation point - takes \p Analysis instance
|
|
/// that has just been invalidated and constant reference to IR it operated
|
|
/// on.
|
|
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));
|
|
}
|
|
|
|
/// AnalysesCleared instrumentation point - takes name of IR that analyses
|
|
/// operated on.
|
|
void runAnalysesCleared(StringRef Name) const {
|
|
if (Callbacks)
|
|
for (auto &C : Callbacks->AnalysesClearedCallbacks)
|
|
C(Name);
|
|
}
|
|
|
|
/// Handle invalidation from the pass manager when PassInstrumentation
|
|
/// is used as the result of PassInstrumentationAnalysis.
|
|
///
|
|
/// On attempt to invalidate just return false. There is nothing to become
|
|
/// invalid here.
|
|
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);
|
|
|
|
} // namespace llvm
|
|
|
|
#endif
|