mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-11-23 16:19:52 +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:
@@ -388,24 +388,19 @@ entry:
|
|||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>This illustrates that we can now call user code, but there is something a bit subtle
|
<p>This illustrates that we can now call user code, but there is something a bit
|
||||||
going on here. Note that we only invoke the JIT on the anonymous functions
|
subtle going on here. Note that we only invoke the JIT on the anonymous
|
||||||
that <em>call testfunc</em>, but we never invoked it on <em>testfunc
|
functions that <em>call testfunc</em>, but we never invoked it
|
||||||
</em>itself.</p>
|
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
|
<p>The JIT provides a number of other more advanced interfaces for things like
|
||||||
JIT'd when requested. When the Kaleidoscope app calls through the function
|
freeing allocated machine code, rejit'ing functions to update them, etc.
|
||||||
pointer that is returned, the anonymous function starts executing. It ends up
|
However, even with this simple code, we get some surprisingly powerful
|
||||||
making the call to the "testfunc" function, and ends up in a stub that invokes
|
capabilities - check this out (I removed the dump of the anonymous functions,
|
||||||
the JIT, lazily, on testfunc. Once the JIT finishes lazily compiling testfunc,
|
you should get the idea by now :) :</p>
|
||||||
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>
|
|
||||||
|
|
||||||
<div class="doc_code">
|
<div class="doc_code">
|
||||||
<pre>
|
<pre>
|
||||||
@@ -453,8 +448,8 @@ directly.</p>
|
|||||||
resolved. It allows you to establish explicit mappings between IR objects and
|
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
|
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
|
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
|
function name, and even allows you to have the JIT compile functions lazily the
|
||||||
compilation is attempted.</p>
|
first time they're called.</p>
|
||||||
|
|
||||||
<p>One interesting application of this is that we can now extend the language
|
<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:
|
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
|
<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
|
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
|
functions that <em>call testfunc</em>, but we never invoked it
|
||||||
</em>itself.</p>
|
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
|
<p>The JIT provides a number of other more advanced interfaces for things like
|
||||||
requested. When the Kaleidoscope app calls through the function pointer that is
|
freeing allocated machine code, rejit'ing functions to update them, etc.
|
||||||
returned, the anonymous function starts executing. It ends up making the call
|
However, even with this simple code, we get some surprisingly powerful
|
||||||
to the "testfunc" function, and ends up in a stub that invokes the JIT, lazily,
|
capabilities - check this out (I removed the dump of the anonymous functions,
|
||||||
on testfunc. Once the JIT finishes lazily compiling testfunc,
|
you should get the idea by now :) :</p>
|
||||||
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>
|
|
||||||
|
|
||||||
<div class="doc_code">
|
<div class="doc_code">
|
||||||
<pre>
|
<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
|
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
|
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
|
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
|
function name, and even allows you to have the JIT compile functions lazily the
|
||||||
compilation is attempted.</p>
|
first time they're called.</p>
|
||||||
|
|
||||||
<p>One interesting application of this is that we can now extend the language
|
<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:
|
by writing arbitrary C code to implement operations. For example, if we add:
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public:
|
|||||||
class ExecutionEngine {
|
class ExecutionEngine {
|
||||||
const TargetData *TD;
|
const TargetData *TD;
|
||||||
ExecutionEngineState EEState;
|
ExecutionEngineState EEState;
|
||||||
bool LazyCompilationDisabled;
|
bool CompilingLazily;
|
||||||
bool GVCompilationDisabled;
|
bool GVCompilationDisabled;
|
||||||
bool SymbolSearchingDisabled;
|
bool SymbolSearchingDisabled;
|
||||||
bool DlsymStubsEnabled;
|
bool DlsymStubsEnabled;
|
||||||
@@ -319,13 +319,24 @@ public:
|
|||||||
virtual void RegisterJITEventListener(JITEventListener *) {}
|
virtual void RegisterJITEventListener(JITEventListener *) {}
|
||||||
virtual void UnregisterJITEventListener(JITEventListener *) {}
|
virtual void UnregisterJITEventListener(JITEventListener *) {}
|
||||||
|
|
||||||
/// DisableLazyCompilation - If called, the JIT will abort if lazy compilation
|
/// EnableLazyCompilation - When lazy compilation is off (the default), the
|
||||||
/// is ever attempted.
|
/// JIT will eagerly compile every function reachable from the argument to
|
||||||
void DisableLazyCompilation(bool Disabled = true) {
|
/// getPointerToFunction. If lazy compilation is turned on, the JIT will only
|
||||||
LazyCompilationDisabled = Disabled;
|
/// 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 {
|
bool isCompilingLazily() const {
|
||||||
return LazyCompilationDisabled;
|
return CompilingLazily;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DisableGVCompilation - If called, the JIT will abort if it's asked to
|
/// 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)
|
ExecutionEngine::ExecutionEngine(ModuleProvider *P)
|
||||||
: EEState(*this),
|
: EEState(*this),
|
||||||
LazyFunctionCreator(0) {
|
LazyFunctionCreator(0) {
|
||||||
LazyCompilationDisabled = false;
|
CompilingLazily = false;
|
||||||
GVCompilationDisabled = false;
|
GVCompilationDisabled = false;
|
||||||
SymbolSearchingDisabled = false;
|
SymbolSearchingDisabled = false;
|
||||||
DlsymStubsEnabled = false;
|
DlsymStubsEnabled = false;
|
||||||
|
|||||||
@@ -599,7 +599,7 @@ void JIT::runJITOnFunctionUnlocked(Function *F, const MutexGuard &locked) {
|
|||||||
isAlreadyCodeGenerating = false;
|
isAlreadyCodeGenerating = false;
|
||||||
|
|
||||||
// If the function referred to another function that had not yet been
|
// 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()) {
|
while (!jitstate->getPendingFunctions(locked).empty()) {
|
||||||
Function *PF = jitstate->getPendingFunctions(locked).back();
|
Function *PF = jitstate->getPendingFunctions(locked).back();
|
||||||
jitstate->getPendingFunctions(locked).pop_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
|
// If the JIT is configured to emit info so that dlsym can be used to
|
||||||
// rewrite stubs to external globals, do so now.
|
// rewrite stubs to external globals, do so now.
|
||||||
if (areDlsymStubsEnabled() && isLazyCompilationDisabled())
|
if (areDlsymStubsEnabled() && !isCompilingLazily())
|
||||||
updateDlsymStubTable();
|
updateDlsymStubTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -295,10 +295,10 @@ void *JITResolver::getFunctionStub(Function *F) {
|
|||||||
void *&Stub = state.getFunctionToStubMap(locked)[F];
|
void *&Stub = state.getFunctionToStubMap(locked)[F];
|
||||||
if (Stub) return Stub;
|
if (Stub) return Stub;
|
||||||
|
|
||||||
// Call the lazy resolver function unless we are JIT'ing non-lazily, in which
|
// Call the lazy resolver function if we are JIT'ing lazily. Otherwise we
|
||||||
// case we must resolve the symbol now.
|
// must resolve the symbol now.
|
||||||
void *Actual = TheJIT->isLazyCompilationDisabled()
|
void *Actual = TheJIT->isCompilingLazily()
|
||||||
? (void *)0 : (void *)(intptr_t)LazyResolverFn;
|
? (void *)(intptr_t)LazyResolverFn : (void *)0;
|
||||||
|
|
||||||
// If this is an external declaration, attempt to resolve the address now
|
// If this is an external declaration, attempt to resolve the address now
|
||||||
// to place in the stub.
|
// to place in the stub.
|
||||||
@@ -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
|
// 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
|
// exist yet, add it to the JIT's work list so that we can fill in the stub
|
||||||
// address later.
|
// address later.
|
||||||
if (!Actual && TheJIT->isLazyCompilationDisabled())
|
if (!Actual && !TheJIT->isCompilingLazily())
|
||||||
if (!F->isDeclaration() || F->hasNotBeenReadFromBitcode())
|
if (!F->isDeclaration() || F->hasNotBeenReadFromBitcode())
|
||||||
TheJIT->addPendingFunction(F);
|
TheJIT->addPendingFunction(F);
|
||||||
|
|
||||||
@@ -471,7 +471,7 @@ void *JITResolver::JITCompilerFn(void *Stub) {
|
|||||||
// Otherwise we don't have it, do lazy compilation now.
|
// Otherwise we don't have it, do lazy compilation now.
|
||||||
|
|
||||||
// If lazy compilation is disabled, emit a useful error message and abort.
|
// 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 '"
|
llvm_report_error("LLVM JIT requested to do lazy compilation of function '"
|
||||||
+ F->getName() + "' when lazy compiles are disabled!");
|
+ 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
|
// 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
|
// that instead of emitting a stub. This uses the lazy resolver, so is not
|
||||||
// legal if lazy compilation is disabled.
|
// legal if lazy compilation is disabled.
|
||||||
if (DoesntNeedStub && !TheJIT->isLazyCompilationDisabled())
|
if (DoesntNeedStub && TheJIT->isCompilingLazily())
|
||||||
return Resolver.AddCallbackAtLocation(F, Reference);
|
return Resolver.AddCallbackAtLocation(F, Reference);
|
||||||
|
|
||||||
// Otherwise, we have to emit a stub.
|
// Otherwise, we have to emit a stub.
|
||||||
|
|||||||
@@ -165,8 +165,7 @@ int main(int argc, char **argv, char * const *envp) {
|
|||||||
|
|
||||||
EE->RegisterJITEventListener(createOProfileJITEventListener());
|
EE->RegisterJITEventListener(createOProfileJITEventListener());
|
||||||
|
|
||||||
if (NoLazyCompilation)
|
EE->EnableLazyCompilation(!NoLazyCompilation);
|
||||||
EE->DisableLazyCompilation();
|
|
||||||
|
|
||||||
// If the user specifically requested an argv[0] to pass into the program,
|
// If the user specifically requested an argv[0] to pass into the program,
|
||||||
// do it now.
|
// do it now.
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ TEST_F(JITTest, FarCallToKnownFunction) {
|
|||||||
Builder.CreateRet(result);
|
Builder.CreateRet(result);
|
||||||
|
|
||||||
TheJIT->EnableDlsymStubs(false);
|
TheJIT->EnableDlsymStubs(false);
|
||||||
TheJIT->DisableLazyCompilation();
|
TheJIT->EnableLazyCompilation(false);
|
||||||
int (*TestFunctionPtr)() = reinterpret_cast<int(*)()>(
|
int (*TestFunctionPtr)() = reinterpret_cast<int(*)()>(
|
||||||
(intptr_t)TheJIT->getPointerToFunction(TestFunction));
|
(intptr_t)TheJIT->getPointerToFunction(TestFunction));
|
||||||
// This used to crash in trying to call PlusOne().
|
// This used to crash in trying to call PlusOne().
|
||||||
@@ -314,7 +314,7 @@ TEST_F(JITTest, FarCallToKnownFunction) {
|
|||||||
#if !defined(__arm__) && !defined(__powerpc__) && !defined(__ppc__)
|
#if !defined(__arm__) && !defined(__powerpc__) && !defined(__ppc__)
|
||||||
// Test a function C which calls A and B which call each other.
|
// Test a function C which calls A and B which call each other.
|
||||||
TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
|
TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
|
||||||
TheJIT->DisableLazyCompilation();
|
TheJIT->EnableLazyCompilation(false);
|
||||||
|
|
||||||
const FunctionType *Func1Ty =
|
const FunctionType *Func1Ty =
|
||||||
cast<FunctionType>(TypeBuilder<void(void), false>::get(Context));
|
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
|
// Regression test for PR5162. This used to trigger an AssertingVH inside the
|
||||||
// JIT's Function to stub mapping.
|
// JIT's Function to stub mapping.
|
||||||
TEST_F(JITTest, NonLazyLeaksNoStubs) {
|
TEST_F(JITTest, NonLazyLeaksNoStubs) {
|
||||||
TheJIT->DisableLazyCompilation();
|
TheJIT->EnableLazyCompilation(false);
|
||||||
|
|
||||||
// Create two functions with a single basic block each.
|
// Create two functions with a single basic block each.
|
||||||
const FunctionType *FuncTy =
|
const FunctionType *FuncTy =
|
||||||
|
|||||||
Reference in New Issue
Block a user