forked from OSchip/llvm-project
[ORC] Start adding ORCv1 to ORCv2 transition tips to the ORCv2 doc.
llvm-svn: 366075
This commit is contained in:
parent
fd08dcb9db
commit
a13cca41c5
|
@ -16,7 +16,7 @@ Use-cases
|
|||
=========
|
||||
|
||||
ORC provides a modular API for building JIT compilers. There are a range
|
||||
of use cases for such an API:
|
||||
of use cases for such an API. For example:
|
||||
|
||||
1. The LLVM tutorials use a simple ORC-based JIT class to execute expressions
|
||||
compiled from a toy languge: Kaleidoscope.
|
||||
|
@ -56,11 +56,11 @@ ORC provides the following features:
|
|||
deferring compilation until first call.
|
||||
|
||||
- *Support for custom compilers and program representations*. Clients can supply
|
||||
custom compilers for each symbol that they define in their JIT session. ORC
|
||||
will run the user-supplied compiler when the a definition of a symbol is
|
||||
needed. ORC is actually fully language agnostic: LLVM IR is not treated
|
||||
specially, and is supported via the same wrapper mechanism (the
|
||||
``MaterializationUnit`` class) that is used for custom compilers.
|
||||
custom compilers for each symbol that they define in their JIT session. ORC
|
||||
will run the user-supplied compiler when the a definition of a symbol is
|
||||
needed. ORC is actually fully language agnostic: LLVM IR is not treated
|
||||
specially, and is supported via the same wrapper mechanism (the
|
||||
``MaterializationUnit`` class) that is used for custom compilers.
|
||||
|
||||
- *Concurrent JIT'd code* and *concurrent compilation*. JIT'd code may spawn
|
||||
multiple threads, and may re-enter the JIT (e.g. for lazy compilation)
|
||||
|
@ -311,10 +311,129 @@ Supporting Custom Compilers
|
|||
|
||||
TBD.
|
||||
|
||||
Low Level (MCJIT style) Use
|
||||
===========================
|
||||
Transitioning from ORCv1 to ORCv2
|
||||
=================================
|
||||
|
||||
TBD.
|
||||
Since LLVM 7.0 new ORC developement has focused on adding support for concurrent
|
||||
compilation. In order to enable concurrency new APIs were introduced
|
||||
(ExecutionSession, JITDylib, etc.) and new implementations of existing layers
|
||||
were written. In LLVM 8.0 the old layer implementations, which do not support
|
||||
concurrency, were renamed (with a "Legacy" prefix), but remained in tree. In
|
||||
LLVM 9.0 we have added a deprecation warning for the old layers and utilities,
|
||||
and in LLVM 10.0 the old layers and utilities will be removed.
|
||||
|
||||
Clients currently using the legacy (ORCv1) layers and utilities will usually
|
||||
find it easy to transition to the newer (ORCv2) variants. Most of the ORCv1
|
||||
layers and utilities have ORCv2 counterparts[2]_ that can be
|
||||
substituted. However there are some differences between ORCv1 and ORCv2 to be
|
||||
aware of:
|
||||
|
||||
1. All JIT stacks now need an ExecutionSession instance which manages the
|
||||
string pool, error reporting, synchronization, and symbol lookup.
|
||||
|
||||
2. ORCv2 uses uniqued strings (``SymbolStringPtr`` instances) to reduce memory
|
||||
overhead and improve lookup performance. To get a uniqued string, call
|
||||
``intern`` on your ExecutionSession instance:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
ExecutionSession ES;
|
||||
|
||||
/// ...
|
||||
|
||||
auto MainSymbolName = ES.intern("main");
|
||||
|
||||
3. Program representations (Modules, Object Files, etc.) are no longer added
|
||||
*to* layers. Instead they are added *to* JITDylibs *by* layers. The layer
|
||||
determines how the program representation will be compiled if it is needed.
|
||||
The JITDylib provides the symbol table, enforces linkage rules (e.g.
|
||||
rejecting duplicate definitions), and synchronizes concurrent compiles.
|
||||
|
||||
Most ORCv1 clients (or MCJIT clients wanting to try out ORCv2) should
|
||||
simply add code to the default *main* JITDylib provided by the
|
||||
ExecutionSession:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
ExecutionSession ES;
|
||||
RTDyldObjectLinkingLayer ObjLinkingLayer(
|
||||
ES, []() { return llvm::make_unique<SectionMemoryManager>(); });
|
||||
IRCompileLayer CompileLayer(ES, ObjLinkingLayer, SimpleIRCompiler(TM));
|
||||
|
||||
auto M = loadModule(...);
|
||||
|
||||
if (auto Err = CompileLayer.add(ES.getMainJITDylib(), M))
|
||||
return Err;
|
||||
|
||||
4. IR layers require ThreadSafeModule instances, rather than
|
||||
std::unique_ptr<Module>s. A ThreadSafeModule instance is a pair of a
|
||||
std::unique_ptr<Module> and a ThreadSafeContext, which is in turn a
|
||||
pair of a std::unique_ptr<LLVMContext> and a lock. This allows the JIT
|
||||
to ensure that the LLVMContext for a module is locked before the module
|
||||
is accessed. Multiple ThreadSafeModules may share a ThreadSafeContext
|
||||
value, but in that case the modules will not be able to be compiled
|
||||
concurrently[3]_.
|
||||
|
||||
ThreadSafeContexts may be constructed explicitly:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// ThreadSafeContext shared between two modules.
|
||||
ThreadSafeContext TSCtx(llvm::make_unique<LLVMContext>());
|
||||
ThreadSafeModule TSM1(
|
||||
llvm::make_unique<Module>("M1", *TSCtx.getContext()), TSCtx);
|
||||
ThreadSafeModule TSM2(
|
||||
llvm::make_unique<Module>("M2", *TSCtx.getContext()), TSCtx);
|
||||
|
||||
, or they can be created implicitly by passing a new LLVMContext to the
|
||||
ThreadSafeModuleConstructor:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// Constructing a ThreadSafeModule (and implicitly a ThreadSafeContext)
|
||||
// from a pair of a Module and a Context.
|
||||
auto Ctx = llvm::make_unique<LLVMContext>();
|
||||
auto M = llvm::make_unique<Module>("M", *Ctx);
|
||||
return ThreadSafeModule(std::move(M), std::move(Ctx));
|
||||
|
||||
5. The symbol resolution and lookup scheme have been fundamentally changed.
|
||||
Symbol lookup has been removed from the layer interface. Instead,
|
||||
symbols are looked up via the ``ExecutionSession::lookup`` method by
|
||||
scanning a list of JITDylibs.
|
||||
|
||||
SymbolResolvers have been removed entirely. Resolution rules now follow the
|
||||
linkage relationship between JITDylibs. For example, to resolve a reference
|
||||
to a symbol *F* from a module *M* that has been added to JITDylib *J1* we
|
||||
would first search for a definition of *F* in *J1* then (if no definition
|
||||
was found) search each of the JITDylibs that *J1* links against.
|
||||
|
||||
While the new resolution scheme is, strictly speaking, less flexible than
|
||||
the old scheme of customizable resolvers this has not yet led to problems
|
||||
in practice. Instead, using standard linker rules has removed a lot of
|
||||
boilerplate while providing correct[4]_ behavior for common and weak symbols.
|
||||
|
||||
One notable difference is in exposing in-process symbols to the JIT. To
|
||||
support this (without requiring the set of symbols to be enumerated up
|
||||
front), JITDylibs allow for a *GeneratorFunction* to be attached to
|
||||
generate new definitions upon lookup. Reflecting the processes symbols into
|
||||
the JIT can be done by writing:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
ExecutionSession ES;
|
||||
const auto DataLayout &DL = ...;
|
||||
|
||||
{
|
||||
auto ProcessSymbolsGenerator =
|
||||
DynamicLibrarySearchGenerator::GetForCurrentProcess(DL.getGlobalPrefix());
|
||||
if (!ProcessSymbolsGenerator)
|
||||
return ProcessSymbolsGenerator.takeError();
|
||||
ES.getMainJITDylib().setGenerator(std::move(*ProcessSymbolsGenerator));
|
||||
}
|
||||
|
||||
6. Module removal is not yet supported. There is no equivalent of the
|
||||
layer concept removeModule/removeObject methods. Work on resource tracking
|
||||
and removal in ORCv2 is ongoing.
|
||||
|
||||
Future Features
|
||||
===============
|
||||
|
@ -322,4 +441,24 @@ Future Features
|
|||
TBD: Speculative compilation. Object Caches.
|
||||
|
||||
.. [1] Formats/architectures vary in terms of supported features. MachO and
|
||||
ELF tend to have better support than COFF. Patches very welcome!
|
||||
ELF tend to have better support than COFF. Patches very welcome!
|
||||
|
||||
.. [2] The ``LazyEmittingLayer``, ``RemoteObjectClientLayer`` and
|
||||
``RemoteObjectServerLayer`` do not have counterparts in the new
|
||||
system. In the case of ``LazyEmittingLayer`` it was simply no longer
|
||||
needed: in ORCv2, deferring compilation until symbols are looked up is
|
||||
the default. The removal of ``RemoteObjectClientLayer`` and
|
||||
``RemoteObjectServerLayer`` means that JIT stacks can no longer be split
|
||||
across processes, however this functionality appears not to have been
|
||||
used.
|
||||
|
||||
.. [3] Sharing ThreadSafeModules in a concurrent compilation can be dangerous:
|
||||
if interdependent modules are loaded on the same context, but compiled
|
||||
on different threads a deadlock may occur (with each compile waiting for
|
||||
the other(s) to complete, and the other(s) unable to proceed because the
|
||||
context is locked).
|
||||
|
||||
.. [4] Mostly. Weak definitions are handled correctly within dylibs, but if
|
||||
multiple dylibs provide a weak definition of a symbol each will end up
|
||||
with its own definition (similar to how weak symbols in Windows DLLs
|
||||
behave). This will be fixed in the future.
|
|
@ -89,7 +89,7 @@ intermediate LLVM representation.
|
|||
GetElementPtr
|
||||
Frontend/PerformanceTips
|
||||
MCJITDesignAndImplementation
|
||||
ORCv2DesignAndImplementation
|
||||
ORCv2
|
||||
CodeOfConduct
|
||||
CompileCudaWithLLVM
|
||||
ReportingGuide
|
||||
|
@ -383,9 +383,9 @@ For API clients and LLVM developers.
|
|||
:doc:`MCJITDesignAndImplementation`
|
||||
Describes the inner workings of MCJIT execution engine.
|
||||
|
||||
:doc:`ORCv2DesignAndImplementation`
|
||||
:doc:`ORCv2`
|
||||
Describes the design and implementation of the ORC APIs, including some
|
||||
usage examples.
|
||||
usage examples, and a guide for users transitioning from ORCv1 to ORCv2.
|
||||
|
||||
:doc:`BranchWeightMetadata`
|
||||
Provides information about Branch Prediction Information.
|
||||
|
|
Loading…
Reference in New Issue