summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm-c/Core.h9
-rw-r--r--llvm/include/llvm/IR/LLVMContext.h30
-rw-r--r--llvm/lib/Analysis/IPA/CallGraphSCCPass.cpp8
-rw-r--r--llvm/lib/Analysis/LoopPass.cpp3
-rw-r--r--llvm/lib/IR/Core.cpp7
-rw-r--r--llvm/lib/IR/LLVMContext.cpp11
-rw-r--r--llvm/lib/IR/LLVMContextImpl.cpp2
-rw-r--r--llvm/lib/IR/LLVMContextImpl.h3
-rw-r--r--llvm/lib/IR/LegacyPassManager.cpp9
-rw-r--r--llvm/lib/IR/PassManager.cpp5
-rw-r--r--llvm/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp27
11 files changed, 110 insertions, 4 deletions
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index a86079e0ec0..151165e704d 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -467,6 +467,7 @@ void LLVMEnablePrettyStackTrace(void);
*/
typedef void (*LLVMDiagnosticHandler)(LLVMDiagnosticInfoRef, void *);
+typedef void (*LLVMYieldCallback)(LLVMContextRef, void *);
/**
* Create a new context.
@@ -489,6 +490,14 @@ void LLVMContextSetDiagnosticHandler(LLVMContextRef C,
void *DiagnosticContext);
/**
+ * Set the yield callback function for this context.
+ *
+ * @see LLVMContext::setYieldCallback()
+ */
+void LLVMContextSetYieldCallback(LLVMContextRef C, LLVMYieldCallback Callback,
+ void *OpaqueHandle);
+
+/**
* Destroy a context instance.
*
* This should be called for every call to LLVMContextCreate() or memory
diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h
index 7356c17027e..f9644aca6b4 100644
--- a/llvm/include/llvm/IR/LLVMContext.h
+++ b/llvm/include/llvm/IR/LLVMContext.h
@@ -72,6 +72,10 @@ public:
/// \see LLVMContext::diagnose.
typedef void (*DiagnosticHandlerTy)(const DiagnosticInfo &DI, void *Context);
+ /// Defines the type of a yield callback.
+ /// \see LLVMContext::setYieldCallback.
+ typedef void (*YieldCallbackTy)(LLVMContext *Context, void *OpaqueHandle);
+
/// setInlineAsmDiagnosticHandler - This method sets a handler that is invoked
/// when problems with inline asm are detected by the backend. The first
/// argument is a function pointer and the second is a context pointer that
@@ -118,6 +122,32 @@ public:
/// for RS_Error, "warning: " for RS_Warning, and "note: " for RS_Note.
void diagnose(const DiagnosticInfo &DI);
+ /// \brief Registers a yield callback with the given context.
+ ///
+ /// The yield callback function may be called by LLVM to transfer control back
+ /// to the client that invoked the LLVM compilation. This can be used to yield
+ /// control of the thread, or perform periodic work needed by the client.
+ /// There is no guaranteed frequency at which callbacks must occur; in fact,
+ /// the client is not guaranteed to ever receive this callback. It is at the
+ /// sole discretion of LLVM to do so and only if it can guarantee that
+ /// suspending the thread won't block any forward progress in other LLVM
+ /// contexts in the same process.
+ ///
+ /// At a suspend point, the state of the current LLVM context is intentionally
+ /// undefined. No assumptions about it can or should be made. Only LLVM
+ /// context API calls that explicitly state that they can be used during a
+ /// yield callback are allowed to be used. Any other API calls into the
+ /// context are not supported until the yield callback function returns
+ /// control to LLVM. Other LLVM contexts are unaffected by this restriction.
+ void setYieldCallback(YieldCallbackTy Callback, void *OpaqueHandle);
+
+ /// \brief Calls the yield callback (if applicable).
+ ///
+ /// This transfers control of the current thread back to the client, which may
+ /// suspend the current thread. Only call this method when LLVM doesn't hold
+ /// any global mutex or cannot block the execution in another LLVM context.
+ void yield();
+
/// emitError - Emit an error message to the currently installed error handler
/// with optional location information. This function returns, so code should
/// be prepared to drop the erroneous construct on the floor and "not crash".
diff --git a/llvm/lib/Analysis/IPA/CallGraphSCCPass.cpp b/llvm/lib/Analysis/IPA/CallGraphSCCPass.cpp
index fa9159d13d4..bfab744d479 100644
--- a/llvm/lib/Analysis/IPA/CallGraphSCCPass.cpp
+++ b/llvm/lib/Analysis/IPA/CallGraphSCCPass.cpp
@@ -22,6 +22,7 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LegacyPassManagers.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Timer.h"
@@ -145,8 +146,11 @@ bool CGPassManager::RunPassOnSCC(Pass *P, CallGraphSCC &CurSCC,
I != E; ++I) {
if (Function *F = (*I)->getFunction()) {
dumpPassInfo(P, EXECUTION_MSG, ON_FUNCTION_MSG, F->getName());
- TimeRegion PassTimer(getPassTimer(FPP));
- Changed |= FPP->runOnFunction(*F);
+ {
+ TimeRegion PassTimer(getPassTimer(FPP));
+ Changed |= FPP->runOnFunction(*F);
+ }
+ F->getContext().yield();
}
}
diff --git a/llvm/lib/Analysis/LoopPass.cpp b/llvm/lib/Analysis/LoopPass.cpp
index 683d6d74ab4..8df18e75c64 100644
--- a/llvm/lib/Analysis/LoopPass.cpp
+++ b/llvm/lib/Analysis/LoopPass.cpp
@@ -15,6 +15,7 @@
#include "llvm/Analysis/LoopPass.h"
#include "llvm/IR/IRPrintingPasses.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Timer.h"
using namespace llvm;
@@ -253,6 +254,8 @@ bool LPPassManager::runOnFunction(Function &F) {
// Then call the regular verifyAnalysis functions.
verifyPreservedAnalysis(P);
+
+ F.getContext().yield();
}
removeNotPreservedAnalysis(P);
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index b1b0abb9eff..81d137edfe0 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -89,6 +89,13 @@ void LLVMContextSetDiagnosticHandler(LLVMContextRef C,
DiagnosticContext);
}
+void LLVMContextSetYieldCallback(LLVMContextRef C, LLVMYieldCallback Callback,
+ void *OpaqueHandle) {
+ auto YieldCallback =
+ LLVM_EXTENSION reinterpret_cast<LLVMContext::YieldCallbackTy>(Callback);
+ unwrap(C)->setYieldCallback(YieldCallback, OpaqueHandle);
+}
+
void LLVMContextDispose(LLVMContextRef C) {
delete unwrap(C);
}
diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp
index 588e1217bd4..5f94dca1eb9 100644
--- a/llvm/lib/IR/LLVMContext.cpp
+++ b/llvm/lib/IR/LLVMContext.cpp
@@ -115,6 +115,17 @@ void *LLVMContext::getDiagnosticContext() const {
return pImpl->DiagnosticContext;
}
+void LLVMContext::setYieldCallback(YieldCallbackTy Callback, void *OpaqueHandle)
+{
+ pImpl->YieldCallback = Callback;
+ pImpl->YieldOpaqueHandle = OpaqueHandle;
+}
+
+void LLVMContext::yield() {
+ if (pImpl->YieldCallback)
+ pImpl->YieldCallback(this, pImpl->YieldOpaqueHandle);
+}
+
void LLVMContext::emitError(const Twine &ErrorStr) {
diagnose(DiagnosticInfoInlineAsm(ErrorStr));
}
diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp
index 78a3c2d304b..2042374647d 100644
--- a/llvm/lib/IR/LLVMContextImpl.cpp
+++ b/llvm/lib/IR/LLVMContextImpl.cpp
@@ -41,6 +41,8 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
InlineAsmDiagContext = nullptr;
DiagnosticHandler = nullptr;
DiagnosticContext = nullptr;
+ YieldCallback = nullptr;
+ YieldOpaqueHandle = nullptr;
NamedStructTypesUniqueID = 0;
}
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index a6a65e6cacd..b1ad9ff4a5a 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -242,6 +242,9 @@ public:
LLVMContext::DiagnosticHandlerTy DiagnosticHandler;
void *DiagnosticContext;
+ LLVMContext::YieldCallbackTy YieldCallback;
+ void *YieldOpaqueHandle;
+
typedef DenseMap<DenseMapAPIntKeyInfo::KeyTy, ConstantInt *,
DenseMapAPIntKeyInfo> IntMapTy;
IntMapTy IntConstants;
diff --git a/llvm/lib/IR/LegacyPassManager.cpp b/llvm/lib/IR/LegacyPassManager.cpp
index b6d75b483f8..d3f3482dc02 100644
--- a/llvm/lib/IR/LegacyPassManager.cpp
+++ b/llvm/lib/IR/LegacyPassManager.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
+#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LegacyPassManagers.h"
@@ -1489,8 +1490,10 @@ bool FunctionPassManagerImpl::run(Function &F) {
TimingInfo::createTheTimeInfo();
initializeAllAnalysisInfo();
- for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index)
+ for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) {
Changed |= getContainedManager(Index)->runOnFunction(F);
+ F.getContext().yield();
+ }
for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index)
getContainedManager(Index)->cleanup();
@@ -1723,8 +1726,10 @@ bool PassManagerImpl::run(Module &M) {
}
initializeAllAnalysisInfo();
- for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index)
+ for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) {
Changed |= getContainedManager(Index)->runOnModule(M);
+ M.getContext().yield();
+ }
for (SmallVectorImpl<ImmutablePass *>::const_iterator I = IPV.begin(),
E = IPV.end(); I != E; ++I) {
diff --git a/llvm/lib/IR/PassManager.cpp b/llvm/lib/IR/PassManager.cpp
index 3344b099537..0defb6ab3e4 100644
--- a/llvm/lib/IR/PassManager.cpp
+++ b/llvm/lib/IR/PassManager.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
@@ -32,6 +33,8 @@ PreservedAnalyses ModulePassManager::run(Module *M, ModuleAnalysisManager *AM) {
if (AM)
AM->invalidate(M, PassPA);
PA.intersect(std::move(PassPA));
+
+ M->getContext().yield();
}
if (DebugPM)
@@ -92,6 +95,8 @@ PreservedAnalyses FunctionPassManager::run(Function *F,
if (AM)
AM->invalidate(F, PassPA);
PA.intersect(std::move(PassPA));
+
+ F->getContext().yield();
}
if (DebugPM)
diff --git a/llvm/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp b/llvm/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
index 3813d59dbd1..20d3f139b4c 100644
--- a/llvm/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
+++ b/llvm/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp
@@ -28,6 +28,7 @@ using namespace llvm;
static bool didCallAllocateCodeSection;
static bool didAllocateCompactUnwindSection;
+static bool didCallYield;
static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
unsigned alignment,
@@ -64,6 +65,10 @@ static void roundTripDestroy(void *object) {
delete static_cast<SectionMemoryManager*>(object);
}
+static void yield(LLVMContextRef, void *) {
+ didCallYield = true;
+}
+
namespace {
// memory manager to test reserve allocation space callback
@@ -142,6 +147,7 @@ protected:
virtual void SetUp() {
didCallAllocateCodeSection = false;
didAllocateCompactUnwindSection = false;
+ didCallYield = false;
Module = 0;
Function = 0;
Engine = 0;
@@ -429,3 +435,24 @@ TEST_F(MCJITCAPITest, reserve_allocation_space) {
EXPECT_TRUE(MM->UsedCodeSize > 0);
EXPECT_TRUE(MM->UsedDataSizeRW > 0);
}
+
+TEST_F(MCJITCAPITest, yield) {
+ SKIP_UNSUPPORTED_PLATFORM;
+
+ buildSimpleFunction();
+ buildMCJITOptions();
+ buildMCJITEngine();
+ LLVMContextRef C = LLVMGetGlobalContext();
+ LLVMContextSetYieldCallback(C, yield, NULL);
+ buildAndRunPasses();
+
+ union {
+ void *raw;
+ int (*usable)();
+ } functionPointer;
+ functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
+
+ EXPECT_EQ(42, functionPointer.usable());
+ EXPECT_TRUE(didCallYield);
+}
+
OpenPOWER on IntegriCloud