[PM] Add pass run listeners to the pass manager.

This commit provides the necessary C/C++ APIs and infastructure to enable fine-
grain progress report and safe suspension points after each pass in the pass
manager.

Clients can provide a callback function to the pass manager to call after each
pass. This can be used in a variety of ways (progress report, dumping of IR
between passes, safe suspension of threads, etc).

The run listener list is maintained in the LLVMContext, which allows a multi-
threaded client to be only informed for it's own thread. This of course assumes
that the client created a LLVMContext for each thread.

This fixes <rdar://problem/16728690>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207430 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Juergen Ributzka 2014-04-28 18:19:25 +00:00
parent c430d3ffcd
commit 4e0cc51d79
11 changed files with 207 additions and 8 deletions

View File

@ -112,12 +112,23 @@ typedef struct LLVMOpaqueBuilder *LLVMBuilderRef;
*/
typedef struct LLVMOpaqueModuleProvider *LLVMModuleProviderRef;
/** @see llvm::Pass */
typedef struct LLVMOpaquePass *LLVMPassRef;
/** @see llvm::PassManagerBase */
typedef struct LLVMOpaquePassManager *LLVMPassManagerRef;
/** @see llvm::PassRegistry */
typedef struct LLVMOpaquePassRegistry *LLVMPassRegistryRef;
/** @see llvm::PassRunListener */
typedef struct LLVMOpaquePassRunListener *LLVMPassRunListenerRef;
/** @see llvm::LLVMPassRunListener */
typedef void (*LLVMPassRunListenerHandlerTy)(LLVMContextRef, LLVMPassRef,
LLVMModuleRef, LLVMValueRef,
LLVMBasicBlockRef);
/**
* Used to get the users and usees of a Value.
*
@ -515,6 +526,10 @@ unsigned LLVMGetMDKindIDInContext(LLVMContextRef C, const char* Name,
unsigned SLen);
unsigned LLVMGetMDKindID(const char* Name, unsigned SLen);
LLVMPassRunListenerRef LLVMAddPassRunListener(LLVMContextRef,
LLVMPassRunListenerHandlerTy);
void LLVMRemovePassRunListener(LLVMContextRef, LLVMPassRunListenerRef);
/**
* @}
*/
@ -2759,6 +2774,18 @@ const char *LLVMGetBufferStart(LLVMMemoryBufferRef MemBuf);
size_t LLVMGetBufferSize(LLVMMemoryBufferRef MemBuf);
void LLVMDisposeMemoryBuffer(LLVMMemoryBufferRef MemBuf);
/**
* @}
*/
/**
* @defgroup LLVMCCorePass Pass
*
* @{
*/
const char *LLVMGetPassName(LLVMPassRef);
/**
* @}
*/

View File

@ -21,16 +21,19 @@
namespace llvm {
class BasicBlock;
class DebugLoc;
class DiagnosticInfo;
class Function;
class Instruction;
class LLVMContextImpl;
class Module;
class Pass;
struct PassRunListener;
template <typename T> class SmallVectorImpl;
class SMDiagnostic;
class StringRef;
class Twine;
class Instruction;
class Module;
class SMDiagnostic;
class DiagnosticInfo;
template <typename T> class SmallVectorImpl;
class Function;
class DebugLoc;
/// This is an important class for using LLVM in a threaded context. It
/// (opaquely) owns and manages the core "global" data of LLVM's core
@ -136,6 +139,16 @@ public:
void emitOptimizationRemark(const char *PassName, const Function &Fn,
const DebugLoc &DLoc, const Twine &Msg);
/// \brief Notify that we finished running a pass.
void notifyPassRun(Pass *P, Module *M, Function *F = nullptr,
BasicBlock *BB = nullptr);
/// \brief Register the given PassRunListener to receive notifyPassRun()
/// callbacks whenever a pass ran. The context will take ownership of the
/// listener and free it when the context is destroyed.
void addRunListener(PassRunListener *L);
/// \brief Unregister a PassRunListener so that it no longer receives
/// notifyPassRun() callbacks. Remove and free the listener from the context.
void removeRunListener(PassRunListener *L);
private:
LLVMContext(LLVMContext&) LLVM_DELETED_FUNCTION;
void operator=(LLVMContext&) LLVM_DELETED_FUNCTION;

View File

@ -29,7 +29,9 @@
#ifndef LLVM_PASS_H
#define LLVM_PASS_H
#include "llvm/Support/CBindingWrapping.h"
#include "llvm/Support/Compiler.h"
#include "llvm-c/Core.h"
#include <string>
namespace llvm {
@ -369,6 +371,9 @@ protected:
/// @brief This is the storage for the -time-passes option.
extern bool TimePassesIsEnabled;
// Create wrappers for C Binding types (see CBindingWrapping.h).
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
} // End llvm namespace
// Include support files that contain important APIs commonly used by Passes,

View File

@ -31,6 +31,7 @@
namespace llvm {
class TargetMachine;
class LLVMContext;
//===---------------------------------------------------------------------------
/// PassInfo class - An instance of this class exists for every pass known by
/// the system, and can be obtained from a live Pass by calling its
@ -355,6 +356,21 @@ struct PassRegistrationListener {
virtual void passEnumerate(const PassInfo *) {}
};
//===---------------------------------------------------------------------------
/// PassRunListener class - This class is meant to be derived from by
/// clients that are interested in which and when passes are run at runtime.
struct PassRunListener {
/// PassRunListener ctor - Add the current object to the list of
/// PassRunListeners...
PassRunListener(LLVMContext *);
virtual ~PassRunListener();
/// Callback function - This functions is invoked whenever a pass has run.
virtual void passRun(LLVMContext *, Pass *, Module *, Function *,
BasicBlock *) {}
};
} // End llvm namespace

View File

@ -27,6 +27,7 @@
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/PassManager.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
@ -43,6 +44,21 @@ using namespace llvm;
#define DEBUG_TYPE "ir"
namespace {
struct LLVMPassRunListener : PassRunListener {
LLVMPassRunListenerHandlerTy Callback;
LLVMPassRunListener(LLVMContext *Context, LLVMPassRunListenerHandlerTy Fn)
: PassRunListener(Context), Callback(Fn) {}
void passRun(LLVMContext *C, Pass *P, Module *M, Function *F,
BasicBlock *BB) override {
Callback(wrap(C), wrap(P), wrap(M), wrap(F), wrap(BB));
}
};
// Create wrappers for C Binding types (see CBindingWrapping.h).
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMPassRunListener, LLVMPassRunListenerRef)
} // end anonymous namespace
void llvm::initializeCore(PassRegistry &Registry) {
initializeDominatorTreeWrapperPassPass(Registry);
initializePrintModulePassWrapperPass(Registry);
@ -133,7 +149,15 @@ LLVMDiagnosticSeverity LLVMGetDiagInfoSeverity(LLVMDiagnosticInfoRef DI){
return severity;
}
LLVMPassRunListenerRef LLVMAddPassRunListener(LLVMContextRef Context,
LLVMPassRunListenerHandlerTy Fn) {
return wrap(new LLVMPassRunListener(unwrap(Context), Fn));
}
void LLVMRemovePassRunListener(LLVMContextRef Context,
LLVMPassRunListenerRef Listener) {
unwrap(Context)->removeRunListener(unwrap(Listener));
}
/*===-- Operations on modules ---------------------------------------------===*/
@ -2646,6 +2670,12 @@ void LLVMDisposeMemoryBuffer(LLVMMemoryBufferRef MemBuf) {
delete unwrap(MemBuf);
}
/*===-- Pass -------------------------------------------------------------===*/
const char *LLVMGetPassName(LLVMPassRef P) {
return unwrap(P)->getPassName();
}
/*===-- Pass Registry -----------------------------------------------------===*/
LLVMPassRegistryRef LLVMGetGlobalPassRegistry(void) {

View File

@ -214,3 +214,23 @@ void LLVMContext::getMDKindNames(SmallVectorImpl<StringRef> &Names) const {
E = pImpl->CustomMDKindNames.end(); I != E; ++I)
Names[I->second] = I->first();
}
//===----------------------------------------------------------------------===//
// Pass Run Listeners
//===----------------------------------------------------------------------===//
/// Notify that we finished running a pass.
void LLVMContext::notifyPassRun(Pass *P, Module *M, Function *F, BasicBlock *BB)
{
pImpl->notifyPassRun(this, P, M, F, BB);
}
/// Register the given PassRunListener to receive notifyPassRun() callbacks
/// whenever a pass ran. The context will take ownership of the listener and
/// free it when the context is destroyed.
void LLVMContext::addRunListener(PassRunListener *L) {
pImpl->addRunListener(L);
}
/// Unregister a PassRunListener so that it no longer receives notifyPassRun()
/// callbacks. Remove and free the listener from the context.
void LLVMContext::removeRunListener(PassRunListener *L) {
pImpl->removeRunListener(L);
}

View File

@ -15,11 +15,32 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Module.h"
#include "llvm/PassSupport.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Regex.h"
#include <algorithm>
using namespace llvm;
/// Notify that we finished running a pass.
void LLVMContextImpl::notifyPassRun(LLVMContext *C, Pass *P, Module *M,
Function *F, BasicBlock *BB) {
for (auto const &L : RunListeners)
L->passRun(C, P, M, F, BB);
}
/// Register the given PassRunListener to receive notifyPassRun()
/// callbacks whenever a pass ran.
void LLVMContextImpl::addRunListener(PassRunListener *L) {
RunListeners.push_back(L);
}
/// Unregister a PassRunListener so that it no longer receives
/// notifyPassRun() callbacks.
void LLVMContextImpl::removeRunListener(PassRunListener *L) {
auto I = std::find(RunListeners.begin(), RunListeners.end(), L);
assert(I != RunListeners.end() && "RunListener not registered!");
delete *I;
RunListeners.erase(I);
}
LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
: TheTrueVal(nullptr), TheFalseVal(nullptr),
VoidTy(C, Type::VoidTyID),
@ -188,6 +209,11 @@ LLVMContextImpl::~LLVMContextImpl() {
// Destroy MDStrings.
DeleteContainerSeconds(MDStringCache);
// Destroy all run listeners.
for (auto &L : RunListeners)
delete L;
RunListeners.clear();
}
// ConstantsContext anchors

View File

@ -40,6 +40,7 @@ class ConstantFP;
class LLVMContext;
class Type;
class Value;
struct PassRunListener;
struct DenseMapAPIntKeyInfo {
struct KeyTy {
@ -368,13 +369,26 @@ public:
typedef DenseMap<const Function *, ReturnInst *> PrefixDataMapTy;
PrefixDataMapTy PrefixDataMap;
/// \brief List of listeners to notify about a pass run.
SmallVector<PassRunListener *, 4> RunListeners;
/// \brief Return true if the given pass name should emit optimization
/// remarks.
bool optimizationRemarksEnabledFor(const char *PassName) const;
int getOrAddScopeRecordIdxEntry(MDNode *N, int ExistingIdx);
int getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,int ExistingIdx);
/// \brief Notify that we finished running a pass.
void notifyPassRun(LLVMContext *, Pass *, Module *, Function *, BasicBlock *);
/// \brief Register the given PassRunListener to receive notifyPassRun()
/// callbacks whenever a pass ran. The context will take ownership of the
/// listener and free it when the context is destroyed.
void addRunListener(PassRunListener *);
/// \brief Unregister a PassRunListener so that it no longer receives
/// notifyPassRun() callbacks. Remove and free the listener from the context.
void removeRunListener(PassRunListener *);
LLVMContextImpl(LLVMContext &C);
~LLVMContextImpl();
};

View File

@ -16,6 +16,7 @@
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LegacyPassManagers.h"
#include "llvm/IR/LegacyPassNameParser.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
@ -1313,6 +1314,8 @@ bool BBPassManager::runOnFunction(Function &F) {
TimeRegion PassTimer(getPassTimer(BP));
LocalChanged |= BP->runOnBasicBlock(*I);
F.getContext().notifyPassRun(BP, F.getParent(), &F, &*I);
}
Changed |= LocalChanged;
@ -1551,6 +1554,8 @@ bool FPPassManager::runOnFunction(Function &F) {
removeNotPreservedAnalysis(FP);
recordAvailableAnalysis(FP);
removeDeadPasses(FP, F.getName(), ON_FUNCTION_MSG);
F.getContext().notifyPassRun(FP, F.getParent(), &F);
}
return Changed;
}
@ -1630,6 +1635,8 @@ MPPassManager::runOnModule(Module &M) {
removeNotPreservedAnalysis(MP);
recordAvailableAnalysis(MP);
removeDeadPasses(MP, M.getModuleIdentifier(), ON_MODULE_MSG);
M.getContext().notifyPassRun(MP, &M);
}
// Finalize module passes

View File

@ -17,6 +17,7 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LegacyPassNameParser.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/PassRegistry.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@ -242,6 +243,18 @@ void PassRegistrationListener::enumeratePasses() {
PassRegistry::getPassRegistry()->enumerateWith(this);
}
//===----------------------------------------------------------------------===//
// PassRunListener implementation
//
// PassRunListener ctor - Add the current object to the list of
// PassRunListeners...
PassRunListener::PassRunListener(LLVMContext *C) {
C->addRunListener(this);
}
PassRunListener::~PassRunListener() {}
PassNameParser::~PassNameParser() {}
//===----------------------------------------------------------------------===//

View File

@ -28,6 +28,7 @@ using namespace llvm;
static bool didCallAllocateCodeSection;
static bool didAllocateCompactUnwindSection;
static bool didCallPassRunListener;
static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
unsigned alignment,
@ -64,6 +65,12 @@ static void roundTripDestroy(void *object) {
delete static_cast<SectionMemoryManager*>(object);
}
static void passRunListenerCallback(LLVMContextRef C, LLVMPassRef P,
LLVMModuleRef M, LLVMValueRef F,
LLVMBasicBlockRef BB) {
didCallPassRunListener = true;
}
namespace {
// memory manager to test reserve allocation space callback
@ -142,6 +149,7 @@ protected:
virtual void SetUp() {
didCallAllocateCodeSection = false;
didAllocateCompactUnwindSection = false;
didCallPassRunListener = false;
Module = 0;
Function = 0;
Engine = 0;
@ -429,3 +437,23 @@ TEST_F(MCJITCAPITest, reserve_allocation_space) {
EXPECT_TRUE(MM->UsedCodeSize > 0);
EXPECT_TRUE(MM->UsedDataSizeRW > 0);
}
TEST_F(MCJITCAPITest, pass_run_listener) {
SKIP_UNSUPPORTED_PLATFORM;
buildSimpleFunction();
buildMCJITOptions();
buildMCJITEngine();
LLVMContextRef C = LLVMGetGlobalContext();
LLVMAddPassRunListener(C, passRunListenerCallback);
buildAndRunPasses();
union {
void *raw;
int (*usable)();
} functionPointer;
functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
EXPECT_EQ(42, functionPointer.usable());
EXPECT_TRUE(didCallPassRunListener);
}