mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-25 21:00:00 +00:00
Change the JIT to compile eagerly by default as agreed in
http://llvm.org/PR5184, and beef up the comments to describe what both options do and the risks of lazy compilation in the presence of threads. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85295 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
5f75cf511b
commit
dc85724f70
@ -388,24 +388,19 @@ entry:
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>This illustrates that we can now call user code, but there is something a bit subtle
|
||||
going on here. Note that we only invoke the JIT on the anonymous functions
|
||||
that <em>call testfunc</em>, but we never invoked it on <em>testfunc
|
||||
</em>itself.</p>
|
||||
<p>This illustrates that we can now call user code, but there is something a bit
|
||||
subtle going on here. Note that we only invoke the JIT on the anonymous
|
||||
functions that <em>call testfunc</em>, but we never invoked it
|
||||
on <em>testfunc</em> itself. What actually happened here is that the JIT
|
||||
scanned for all non-JIT'd functions transitively called from the anonymous
|
||||
function and compiled all of them before returning
|
||||
from <tt>getPointerToFunction()</tt>.</p>
|
||||
|
||||
<p>What actually happened here is that the anonymous function was
|
||||
JIT'd when requested. When the Kaleidoscope app calls through the function
|
||||
pointer that is returned, the anonymous function starts executing. It ends up
|
||||
making the call to the "testfunc" function, and ends up in a stub that invokes
|
||||
the JIT, lazily, on testfunc. Once the JIT finishes lazily compiling testfunc,
|
||||
it returns and the code re-executes the call.</p>
|
||||
|
||||
<p>In summary, the JIT will lazily JIT code, on the fly, as it is needed. The
|
||||
JIT provides a number of other more advanced interfaces for things like freeing
|
||||
allocated machine code, rejit'ing functions to update them, etc. However, even
|
||||
with this simple code, we get some surprisingly powerful capabilities - check
|
||||
this out (I removed the dump of the anonymous functions, you should get the idea
|
||||
by now :) :</p>
|
||||
<p>The JIT provides a number of other more advanced interfaces for things like
|
||||
freeing allocated machine code, rejit'ing functions to update them, etc.
|
||||
However, even with this simple code, we get some surprisingly powerful
|
||||
capabilities - check this out (I removed the dump of the anonymous functions,
|
||||
you should get the idea by now :) :</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
@ -453,8 +448,8 @@ directly.</p>
|
||||
resolved. It allows you to establish explicit mappings between IR objects and
|
||||
addresses (useful for LLVM global variables that you want to map to static
|
||||
tables, for example), allows you to dynamically decide on the fly based on the
|
||||
function name, and even allows you to have the JIT abort itself if any lazy
|
||||
compilation is attempted.</p>
|
||||
function name, and even allows you to have the JIT compile functions lazily the
|
||||
first time they're called.</p>
|
||||
|
||||
<p>One interesting application of this is that we can now extend the language
|
||||
by writing arbitrary C++ code to implement operations. For example, if we add:
|
||||
|
@ -406,22 +406,17 @@ entry:
|
||||
|
||||
<p>This illustrates that we can now call user code, but there is something a bit
|
||||
subtle going on here. Note that we only invoke the JIT on the anonymous
|
||||
functions that <em>call testfunc</em>, but we never invoked it on <em>testfunc
|
||||
</em>itself.</p>
|
||||
functions that <em>call testfunc</em>, but we never invoked it
|
||||
on <em>testfunc</em> itself. What actually happened here is that the JIT
|
||||
scanned for all non-JIT'd functions transitively called from the anonymous
|
||||
function and compiled all of them before returning
|
||||
from <tt>run_function</tt>.</p>
|
||||
|
||||
<p>What actually happened here is that the anonymous function was JIT'd when
|
||||
requested. When the Kaleidoscope app calls through the function pointer that is
|
||||
returned, the anonymous function starts executing. It ends up making the call
|
||||
to the "testfunc" function, and ends up in a stub that invokes the JIT, lazily,
|
||||
on testfunc. Once the JIT finishes lazily compiling testfunc,
|
||||
it returns and the code re-executes the call.</p>
|
||||
|
||||
<p>In summary, the JIT will lazily JIT code, on the fly, as it is needed. The
|
||||
JIT provides a number of other more advanced interfaces for things like freeing
|
||||
allocated machine code, rejit'ing functions to update them, etc. However, even
|
||||
with this simple code, we get some surprisingly powerful capabilities - check
|
||||
this out (I removed the dump of the anonymous functions, you should get the idea
|
||||
by now :) :</p>
|
||||
<p>The JIT provides a number of other more advanced interfaces for things like
|
||||
freeing allocated machine code, rejit'ing functions to update them, etc.
|
||||
However, even with this simple code, we get some surprisingly powerful
|
||||
capabilities - check this out (I removed the dump of the anonymous functions,
|
||||
you should get the idea by now :) :</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
@ -467,8 +462,8 @@ calls in the module to call the libm version of <tt>sin</tt> directly.</p>
|
||||
get resolved. It allows you to establish explicit mappings between IR objects
|
||||
and addresses (useful for LLVM global variables that you want to map to static
|
||||
tables, for example), allows you to dynamically decide on the fly based on the
|
||||
function name, and even allows you to have the JIT abort itself if any lazy
|
||||
compilation is attempted.</p>
|
||||
function name, and even allows you to have the JIT compile functions lazily the
|
||||
first time they're called.</p>
|
||||
|
||||
<p>One interesting application of this is that we can now extend the language
|
||||
by writing arbitrary C code to implement operations. For example, if we add:
|
||||
|
@ -88,7 +88,7 @@ public:
|
||||
class ExecutionEngine {
|
||||
const TargetData *TD;
|
||||
ExecutionEngineState EEState;
|
||||
bool LazyCompilationDisabled;
|
||||
bool CompilingLazily;
|
||||
bool GVCompilationDisabled;
|
||||
bool SymbolSearchingDisabled;
|
||||
bool DlsymStubsEnabled;
|
||||
@ -319,13 +319,24 @@ public:
|
||||
virtual void RegisterJITEventListener(JITEventListener *) {}
|
||||
virtual void UnregisterJITEventListener(JITEventListener *) {}
|
||||
|
||||
/// DisableLazyCompilation - If called, the JIT will abort if lazy compilation
|
||||
/// is ever attempted.
|
||||
void DisableLazyCompilation(bool Disabled = true) {
|
||||
LazyCompilationDisabled = Disabled;
|
||||
/// EnableLazyCompilation - When lazy compilation is off (the default), the
|
||||
/// JIT will eagerly compile every function reachable from the argument to
|
||||
/// getPointerToFunction. If lazy compilation is turned on, the JIT will only
|
||||
/// compile the one function and emit stubs to compile the rest when they're
|
||||
/// first called. If lazy compilation is turned off again while some lazy
|
||||
/// stubs are still around, and one of those stubs is called, the program will
|
||||
/// abort.
|
||||
///
|
||||
/// In order to safely compile lazily in a threaded program, the user must
|
||||
/// ensure that 1) only one thread at a time can call any particular lazy
|
||||
/// stub, and 2) any thread modifying LLVM IR must hold the JIT's lock
|
||||
/// (ExecutionEngine::lock) or otherwise ensure that no other thread calls a
|
||||
/// lazy stub. See http://llvm.org/PR5184 for details.
|
||||
void EnableLazyCompilation(bool Enabled = true) {
|
||||
CompilingLazily = Enabled;
|
||||
}
|
||||
bool isLazyCompilationDisabled() const {
|
||||
return LazyCompilationDisabled;
|
||||
bool isCompilingLazily() const {
|
||||
return CompilingLazily;
|
||||
}
|
||||
|
||||
/// DisableGVCompilation - If called, the JIT will abort if it's asked to
|
||||
|
@ -49,7 +49,7 @@ ExecutionEngine::EERegisterFn ExecutionEngine::ExceptionTableRegister = 0;
|
||||
ExecutionEngine::ExecutionEngine(ModuleProvider *P)
|
||||
: EEState(*this),
|
||||
LazyFunctionCreator(0) {
|
||||
LazyCompilationDisabled = false;
|
||||
CompilingLazily = false;
|
||||
GVCompilationDisabled = false;
|
||||
SymbolSearchingDisabled = false;
|
||||
DlsymStubsEnabled = false;
|
||||
|
@ -599,7 +599,7 @@ void JIT::runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked) {
|
||||
isAlreadyCodeGenerating = false;
|
||||
|
||||
// If the function referred to another function that had not yet been
|
||||
// read from bitcode, but we are jitting non-lazily, emit it now.
|
||||
// read from bitcode, and we are jitting non-lazily, emit it now.
|
||||
while (!jitstate->getPendingFunctions(locked).empty()) {
|
||||
Function *PF = jitstate->getPendingFunctions(locked).back();
|
||||
jitstate->getPendingFunctions(locked).pop_back();
|
||||
@ -616,7 +616,7 @@ void JIT::runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked) {
|
||||
|
||||
// If the JIT is configured to emit info so that dlsym can be used to
|
||||
// rewrite stubs to external globals, do so now.
|
||||
if (areDlsymStubsEnabled() && isLazyCompilationDisabled())
|
||||
if (areDlsymStubsEnabled() && !isCompilingLazily())
|
||||
updateDlsymStubTable();
|
||||
}
|
||||
|
||||
|
@ -295,11 +295,11 @@ void *JITResolver::getFunctionStub(Function *F) {
|
||||
void *&Stub = state.getFunctionToStubMap(locked)[F];
|
||||
if (Stub) return Stub;
|
||||
|
||||
// Call the lazy resolver function unless we are JIT'ing non-lazily, in which
|
||||
// case we must resolve the symbol now.
|
||||
void *Actual = TheJIT->isLazyCompilationDisabled()
|
||||
? (void *)0 : (void *)(intptr_t)LazyResolverFn;
|
||||
|
||||
// Call the lazy resolver function if we are JIT'ing lazily. Otherwise we
|
||||
// must resolve the symbol now.
|
||||
void *Actual = TheJIT->isCompilingLazily()
|
||||
? (void *)(intptr_t)LazyResolverFn : (void *)0;
|
||||
|
||||
// If this is an external declaration, attempt to resolve the address now
|
||||
// to place in the stub.
|
||||
if (F->isDeclaration() && !F->hasNotBeenReadFromBitcode()) {
|
||||
@ -334,7 +334,7 @@ void *JITResolver::getFunctionStub(Function *F) {
|
||||
// If we are JIT'ing non-lazily but need to call a function that does not
|
||||
// exist yet, add it to the JIT's work list so that we can fill in the stub
|
||||
// address later.
|
||||
if (!Actual && TheJIT->isLazyCompilationDisabled())
|
||||
if (!Actual && !TheJIT->isCompilingLazily())
|
||||
if (!F->isDeclaration() || F->hasNotBeenReadFromBitcode())
|
||||
TheJIT->addPendingFunction(F);
|
||||
|
||||
@ -471,7 +471,7 @@ void *JITResolver::JITCompilerFn(void *Stub) {
|
||||
// Otherwise we don't have it, do lazy compilation now.
|
||||
|
||||
// If lazy compilation is disabled, emit a useful error message and abort.
|
||||
if (TheJIT->isLazyCompilationDisabled()) {
|
||||
if (!TheJIT->isCompilingLazily()) {
|
||||
llvm_report_error("LLVM JIT requested to do lazy compilation of function '"
|
||||
+ F->getName() + "' when lazy compiles are disabled!");
|
||||
}
|
||||
@ -769,7 +769,7 @@ void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference,
|
||||
// mechanism is capable of rewriting the instruction directly, prefer to do
|
||||
// that instead of emitting a stub. This uses the lazy resolver, so is not
|
||||
// legal if lazy compilation is disabled.
|
||||
if (DoesntNeedStub && !TheJIT->isLazyCompilationDisabled())
|
||||
if (DoesntNeedStub && TheJIT->isCompilingLazily())
|
||||
return Resolver.AddCallbackAtLocation(F, Reference);
|
||||
|
||||
// Otherwise, we have to emit a stub.
|
||||
|
@ -165,8 +165,7 @@ int main(int argc, char **argv, char * const *envp) {
|
||||
|
||||
EE->RegisterJITEventListener(createOProfileJITEventListener());
|
||||
|
||||
if (NoLazyCompilation)
|
||||
EE->DisableLazyCompilation();
|
||||
EE->EnableLazyCompilation(!NoLazyCompilation);
|
||||
|
||||
// If the user specifically requested an argv[0] to pass into the program,
|
||||
// do it now.
|
||||
|
@ -304,7 +304,7 @@ TEST_F(JITTest, FarCallToKnownFunction) {
|
||||
Builder.CreateRet(result);
|
||||
|
||||
TheJIT->EnableDlsymStubs(false);
|
||||
TheJIT->DisableLazyCompilation();
|
||||
TheJIT->EnableLazyCompilation(false);
|
||||
int (*TestFunctionPtr)() = reinterpret_cast<int(*)()>(
|
||||
(intptr_t)TheJIT->getPointerToFunction(TestFunction));
|
||||
// This used to crash in trying to call PlusOne().
|
||||
@ -314,7 +314,7 @@ TEST_F(JITTest, FarCallToKnownFunction) {
|
||||
#if !defined(__arm__) && !defined(__powerpc__) && !defined(__ppc__)
|
||||
// Test a function C which calls A and B which call each other.
|
||||
TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
|
||||
TheJIT->DisableLazyCompilation();
|
||||
TheJIT->EnableLazyCompilation(false);
|
||||
|
||||
const FunctionType *Func1Ty =
|
||||
cast<FunctionType>(TypeBuilder<void(void), false>::get(Context));
|
||||
@ -370,7 +370,7 @@ TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
|
||||
// Regression test for PR5162. This used to trigger an AssertingVH inside the
|
||||
// JIT's Function to stub mapping.
|
||||
TEST_F(JITTest, NonLazyLeaksNoStubs) {
|
||||
TheJIT->DisableLazyCompilation();
|
||||
TheJIT->EnableLazyCompilation(false);
|
||||
|
||||
// Create two functions with a single basic block each.
|
||||
const FunctionType *FuncTy =
|
||||
|
Loading…
Reference in New Issue
Block a user