diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h index df2de2441a2..f7121a5c61a 100644 --- a/include/llvm-c/Core.h +++ b/include/llvm-c/Core.h @@ -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); + /** * @} */ diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h index 7356c17027e..d0ed850d834 100644 --- a/include/llvm/IR/LLVMContext.h +++ b/include/llvm/IR/LLVMContext.h @@ -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 class SmallVectorImpl; +class SMDiagnostic; class StringRef; class Twine; -class Instruction; -class Module; -class SMDiagnostic; -class DiagnosticInfo; -template 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; diff --git a/include/llvm/Pass.h b/include/llvm/Pass.h index c2b9f95956e..30c864c5231 100644 --- a/include/llvm/Pass.h +++ b/include/llvm/Pass.h @@ -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 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, diff --git a/include/llvm/PassSupport.h b/include/llvm/PassSupport.h index 8efb45f55a2..38860ee8c0b 100644 --- a/include/llvm/PassSupport.h +++ b/include/llvm/PassSupport.h @@ -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 diff --git a/lib/IR/Core.cpp b/lib/IR/Core.cpp index be5727b3cb3..a843b9f6029 100644 --- a/lib/IR/Core.cpp +++ b/lib/IR/Core.cpp @@ -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) { diff --git a/lib/IR/LLVMContext.cpp b/lib/IR/LLVMContext.cpp index 588e1217bd4..b2d3bc9061e 100644 --- a/lib/IR/LLVMContext.cpp +++ b/lib/IR/LLVMContext.cpp @@ -214,3 +214,23 @@ void LLVMContext::getMDKindNames(SmallVectorImpl &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); +} diff --git a/lib/IR/LLVMContextImpl.cpp b/lib/IR/LLVMContextImpl.cpp index 30a1ca28c57..50740a0c348 100644 --- a/lib/IR/LLVMContextImpl.cpp +++ b/lib/IR/LLVMContextImpl.cpp @@ -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 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 diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h index a6a65e6cacd..5e4919cdf0b 100644 --- a/lib/IR/LLVMContextImpl.h +++ b/lib/IR/LLVMContextImpl.h @@ -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 PrefixDataMapTy; PrefixDataMapTy PrefixDataMap; + /// \brief List of listeners to notify about a pass run. + SmallVector 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(); }; diff --git a/lib/IR/LegacyPassManager.cpp b/lib/IR/LegacyPassManager.cpp index b6d75b483f8..aea29fdc5b0 100644 --- a/lib/IR/LegacyPassManager.cpp +++ b/lib/IR/LegacyPassManager.cpp @@ -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 diff --git a/lib/IR/Pass.cpp b/lib/IR/Pass.cpp index bb55d2af7cf..58ae821db22 100644 --- a/lib/IR/Pass.cpp +++ b/lib/IR/Pass.cpp @@ -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() {} //===----------------------------------------------------------------------===// diff --git a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp index 3813d59dbd1..c8e0c882299 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp @@ -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(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); +}