[PM] Add pass run listeners to the pass manager.
authorJuergen Ributzka <juergen@apple.com>
Mon, 28 Apr 2014 18:19:25 +0000 (18:19 +0000)
committerJuergen Ributzka <juergen@apple.com>
Mon, 28 Apr 2014 18:19:25 +0000 (18:19 +0000)
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

include/llvm-c/Core.h
include/llvm/IR/LLVMContext.h
include/llvm/Pass.h
include/llvm/PassSupport.h
lib/IR/Core.cpp
lib/IR/LLVMContext.cpp
lib/IR/LLVMContextImpl.cpp
lib/IR/LLVMContextImpl.h
lib/IR/LegacyPassManager.cpp
lib/IR/Pass.cpp
unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp

index df2de2441a24f51a4436a2b3abbf7a7da337a499..f7121a5c61a069f82104bfd234122612bcea6d22 100644 (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);
+
 /**
  * @}
  */
index 7356c17027e4478d3d81078e09a54ab2dd7ca1ce..d0ed850d8349f8f876f606b43e31b9c4b9fcb7a9 100644 (file)
 
 namespace llvm {
 
-class LLVMContextImpl;
-class StringRef;
-class Twine;
+class BasicBlock;
+class DebugLoc;
+class DiagnosticInfo;
+class Function;
 class Instruction;
+class LLVMContextImpl;
 class Module;
-class SMDiagnostic;
-class DiagnosticInfo;
+class Pass;
+struct PassRunListener;
 template <typename T> class SmallVectorImpl;
-class Function;
-class DebugLoc;
+class SMDiagnostic;
+class StringRef;
+class Twine;
 
 /// 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;
index c2b9f95956e80cb8fddbbff180f545629bc3619f..30c864c5231345f39daa1f7df78f2c52d28ab488 100644 (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,
index 8efb45f55a24763446e878db2bcd8eaf3b7d07bb..38860ee8c0b952454d38d5eae2abdc4b550b42f7 100644 (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
 
index be5727b3cb3c0e076fb77f1cb3995ce0e6a6c783..a843b9f6029881b913cf5141c821a405e3157396 100644 (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) {
index 588e1217bd45b30946898c5b38286f9f053ec55e..b2d3bc9061e58b14b6f913fd9f8fdf49d0e0819d 100644 (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);
+}
index 30a1ca28c57337e99efe0a44205088a923964e66..50740a0c348265bc78e44f7e386e7ee828849ed6 100644 (file)
 #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
index a6a65e6cacd0d34ee351a2917500bea6ad37e61d..5e4919cdf0b995c7511c9185b2991f1e45b4286b 100644 (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();
 };
index b6d75b483f8abc4a0ef33c525a14bff547936581..aea29fdc5b038cf2f486fa39a14a20cf1581a237 100644 (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
index bb55d2af7cf8d5b5ac7e6ac151cfb537c3baac20..58ae821db225672ced825c352dd5c7d0443b28df 100644 (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() {}
 
 //===----------------------------------------------------------------------===//
index 3813d59dbd1195cb0361fe98122cfc68c72a1ce4..c8e0c882299b0fe14d9eefa67ef8b5b0502bc51a 100644 (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);
+}