[ORC][ORC_RT] Integrate ORC platforms with LLJIT and lli

This change enables integrating orc::LLJIT with the ORCv2
platforms (MachOPlatform and ELFNixPlatform) and the compiler-rt orc
runtime. Changes include:

- Adding SPS wrapper functions for the orc runtime's dlfcn emulation
  functions, allowing initialization and deinitialization to be invoked
  by LLJIT.

- Changing the LLJIT code generation default to add UseInitArray so
  that .init_array constructors are generated for ELF platforms.

- Integrating the ORCv2 Platforms into lli, and adding a
  PlatformSupport implementation to the LLJIT instance used by lli which
  implements initialization and deinitialization by calling the new
  wrapper functions in the runtime.

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D126492
This commit is contained in:
Peter S. Housel 2022-05-25 17:04:01 -07:00
parent 87c4268329
commit 1aa71f8679
14 changed files with 319 additions and 23 deletions

View File

@ -9,6 +9,7 @@ set(ORC_SOURCES
macho_platform.cpp macho_platform.cpp
elfnix_platform.cpp elfnix_platform.cpp
run_program_wrapper.cpp run_program_wrapper.cpp
dlfcn_wrapper.cpp
) )
# Implementation files for all ORC architectures. # Implementation files for all ORC architectures.

View File

@ -0,0 +1,52 @@
//===- dlfcn_wrapper.cpp --------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of the ORC runtime support library.
//
//===----------------------------------------------------------------------===//
#include "adt.h"
#include "common.h"
#include "wrapper_function_utils.h"
#include <vector>
using namespace __orc_rt;
extern "C" const char *__orc_rt_jit_dlerror();
extern "C" void *__orc_rt_jit_dlopen(const char *path, int mode);
extern "C" int __orc_rt_jit_dlclose(void *dso_handle);
ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
__orc_rt_jit_dlerror_wrapper(const char *ArgData, size_t ArgSize) {
return WrapperFunction<SPSString()>::handle(
ArgData, ArgSize,
[]() { return std::string(__orc_rt_jit_dlerror()); })
.release();
}
ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
__orc_rt_jit_dlopen_wrapper(const char *ArgData, size_t ArgSize) {
return WrapperFunction<SPSExecutorAddr(SPSString, int32_t)>::handle(
ArgData, ArgSize,
[](const std::string &Path, int32_t mode) {
return ExecutorAddr::fromPtr(
__orc_rt_jit_dlopen(Path.c_str(), mode));
})
.release();
}
ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
__orc_rt_jit_dlclose_wrapper(const char *ArgData, size_t ArgSize) {
return WrapperFunction<int32_t(SPSExecutorAddr)>::handle(
ArgData, ArgSize,
[](ExecutorAddr &DSOHandle) {
return __orc_rt_jit_dlclose(DSOHandle.toPtr<void *>());
})
.release();
}

View File

@ -0,0 +1,15 @@
// RUN: %clangxx -fPIC -emit-llvm -c -o %t %s
// RUN: %lli_orc_jitlink -relocation-model=pic %t | FileCheck %s
// CHECK: catch
#include <stdio.h>
int main(int argc, char *argv[]) {
try {
throw 0;
} catch (int X) {
puts("catch");
}
return 0;
}

View File

@ -0,0 +1,32 @@
; RUN: %lli_orc_jitlink -relocation-model=pic %s | FileCheck %s
; CHECK: constructor
; CHECK-NEXT: main
; CHECK-NEXT: destructor
@__dso_handle = external hidden global i8
@.str = private unnamed_addr constant [5 x i8] c"main\00", align 1
@.str.1 = private unnamed_addr constant [12 x i8] c"constructor\00", align 1
@.str.2 = private unnamed_addr constant [11 x i8] c"destructor\00", align 1
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @constructor, i8* null }]
define dso_local void @destructor(i8* %0) {
%2 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i64 0, i64 0))
ret void
}
declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*)
; Function Attrs: nofree norecurse nounwind uwtable
define dso_local i32 @main(i32 %0, i8** nocapture readnone %1) local_unnamed_addr #2 {
%3 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0))
ret i32 0
}
declare i32 @puts(i8* nocapture readonly)
define internal void @constructor() {
%1 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str.1, i64 0, i64 0)) #5
%2 = tail call i32 @__cxa_atexit(void (i8*)* @destructor, i8* null, i8* nonnull @__dso_handle) #5
ret void
}

View File

@ -0,0 +1,15 @@
// RUN: %clangxx -fPIC -emit-llvm -c -o %t %s
// RUN: %lli_orc_jitlink -relocation-model=pic %t | FileCheck %s
// CHECK: catch
#include <stdio.h>
int main(int argc, char *argv[]) {
try {
throw 0;
} catch (int X) {
puts("catch");
}
return 0;
}

View File

@ -0,0 +1,32 @@
; RUN: %lli_orc_jitlink %s | FileCheck %s
; CHECK: constructor
; CHECK-NEXT: main
; CHECK-NEXT: destructor
@__dso_handle = external hidden global i8
@.str = private unnamed_addr constant [5 x i8] c"main\00", align 1
@.str.1 = private unnamed_addr constant [12 x i8] c"constructor\00", align 1
@.str.2 = private unnamed_addr constant [11 x i8] c"destructor\00", align 1
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @constructor, i8* null }]
define dso_local void @destructor(i8* %0) {
%2 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i64 0, i64 0))
ret void
}
declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*)
; Function Attrs: nofree norecurse nounwind uwtable
define dso_local i32 @main(i32 %0, i8** nocapture readnone %1) local_unnamed_addr #2 {
%3 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0))
ret i32 0
}
declare i32 @puts(i8* nocapture readonly)
define internal void @constructor() {
%1 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str.1, i64 0, i64 0)) #5
%2 = tail call i32 @__cxa_atexit(void (i8*)* @destructor, i8* null, i8* nonnull @__dso_handle) #5
ret void
}

View File

@ -0,0 +1,15 @@
// RUN: %clangxx -fPIC -emit-llvm -c -o %t %s
// RUN: %lli_orc_jitlink -relocation-model=pic %t | FileCheck %s
// CHECK: catch
#include <stdio.h>
int main(int argc, char *argv[]) {
try {
throw 0;
} catch (int X) {
puts("catch");
}
return 0;
}

View File

@ -0,0 +1,32 @@
; RUN: %lli_orc_jitlink %s | FileCheck %s
; CHECK: constructor
; CHECK-NEXT: main
; CHECK-NEXT: destructor
@__dso_handle = external hidden global i8
@.str = private unnamed_addr constant [5 x i8] c"main\00", align 1
@.str.1 = private unnamed_addr constant [12 x i8] c"constructor\00", align 1
@.str.2 = private unnamed_addr constant [11 x i8] c"destructor\00", align 1
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @constructor, i8* null }]
define dso_local void @destructor(i8* %0) {
%2 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i64 0, i64 0))
ret void
}
declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*)
; Function Attrs: nofree norecurse nounwind uwtable
define dso_local i32 @main(i32 %0, i8** nocapture readnone %1) local_unnamed_addr #2 {
%3 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0))
ret i32 0
}
declare i32 @puts(i8* nocapture readonly)
define internal void @constructor() {
%1 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str.1, i64 0, i64 0)) #5
%2 = tail call i32 @__cxa_atexit(void (i8*)* @destructor, i8* null, i8* nonnull @__dso_handle) #5
ret void
}

View File

@ -13,6 +13,7 @@ def build_invocation(compile_flags):
# Assume that llvm-jitlink is in the config.llvm_tools_dir. # Assume that llvm-jitlink is in the config.llvm_tools_dir.
llvm_jitlink = os.path.join(config.llvm_tools_dir, 'llvm-jitlink') llvm_jitlink = os.path.join(config.llvm_tools_dir, 'llvm-jitlink')
lli = os.path.join(config.llvm_tools_dir, 'lli')
if config.host_os == 'Darwin': if config.host_os == 'Darwin':
orc_rt_path = '%s/libclang_rt.orc_osx.a' % config.compiler_rt_libdir orc_rt_path = '%s/libclang_rt.orc_osx.a' % config.compiler_rt_libdir
else: else:
@ -30,9 +31,11 @@ config.substitutions.append(
build_invocation(config.cxx_mode_flags + [config.target_cflags]))) build_invocation(config.cxx_mode_flags + [config.target_cflags])))
config.substitutions.append( config.substitutions.append(
('%llvm_jitlink', (llvm_jitlink + ' -orc-runtime=' + orc_rt_path))) ('%llvm_jitlink', (llvm_jitlink + ' -orc-runtime=' + orc_rt_path)))
config.substitutions.append(
('%lli_orc_jitlink', (lli + ' -jit-kind=orc -jit-linker=jitlink -orc-runtime=' + orc_rt_path)))
# Default test suffixes. # Default test suffixes.
config.suffixes = ['.c', '.cpp', '.S'] config.suffixes = ['.c', '.cpp', '.S', '.ll']
# Exclude Inputs directories. # Exclude Inputs directories.
config.excludes = ['Inputs'] config.excludes = ['Inputs']

View File

@ -125,7 +125,7 @@ public:
/// Set TargetOptions. /// Set TargetOptions.
/// ///
/// Note: This operation will overwrite any previously configured options, /// Note: This operation will overwrite any previously configured options,
/// including EmulatedTLS and ExplicitEmulatedTLS which /// including EmulatedTLS, ExplicitEmulatedTLS, and UseInitArray which
/// the JITTargetMachineBuilder sets by default. Clients are responsible /// the JITTargetMachineBuilder sets by default. Clients are responsible
/// for re-enabling these overwritten options. /// for re-enabling these overwritten options.
JITTargetMachineBuilder &setOptions(TargetOptions Options) { JITTargetMachineBuilder &setOptions(TargetOptions Options) {

View File

@ -263,6 +263,10 @@ ELFNixPlatform::standardRuntimeUtilityAliases() {
static const std::pair<const char *, const char *> static const std::pair<const char *, const char *>
StandardRuntimeUtilityAliases[] = { StandardRuntimeUtilityAliases[] = {
{"__orc_rt_run_program", "__orc_rt_elfnix_run_program"}, {"__orc_rt_run_program", "__orc_rt_elfnix_run_program"},
{"__orc_rt_jit_dlerror", "__orc_rt_elfnix_jit_dlerror"},
{"__orc_rt_jit_dlopen", "__orc_rt_elfnix_jit_dlopen"},
{"__orc_rt_jit_dlclose", "__orc_rt_elfnix_jit_dlclose"},
{"__orc_rt_jit_dlsym", "__orc_rt_elfnix_jit_dlsym"},
{"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}}; {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}};
return ArrayRef<std::pair<const char *, const char *>>( return ArrayRef<std::pair<const char *, const char *>>(

View File

@ -19,6 +19,7 @@ JITTargetMachineBuilder::JITTargetMachineBuilder(Triple TT)
: TT(std::move(TT)) { : TT(std::move(TT)) {
Options.EmulatedTLS = true; Options.EmulatedTLS = true;
Options.ExplicitEmulatedTLS = true; Options.ExplicitEmulatedTLS = true;
Options.UseInitArray = true;
} }
Expected<JITTargetMachineBuilder> JITTargetMachineBuilder::detectHost() { Expected<JITTargetMachineBuilder> JITTargetMachineBuilder::detectHost() {

View File

@ -302,6 +302,10 @@ MachOPlatform::standardRuntimeUtilityAliases() {
static const std::pair<const char *, const char *> static const std::pair<const char *, const char *>
StandardRuntimeUtilityAliases[] = { StandardRuntimeUtilityAliases[] = {
{"___orc_rt_run_program", "___orc_rt_macho_run_program"}, {"___orc_rt_run_program", "___orc_rt_macho_run_program"},
{"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"},
{"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"},
{"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"},
{"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"},
{"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}}; {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}};
return ArrayRef<std::pair<const char *, const char *>>( return ArrayRef<std::pair<const char *, const char *>>(

View File

@ -28,12 +28,15 @@
#include "llvm/ExecutionEngine/ObjectCache.h" #include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
#include "llvm/ExecutionEngine/Orc/DebugUtils.h" #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h" #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
#include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h" #include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h"
#include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h" #include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h" #include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
@ -120,6 +123,9 @@ namespace {
"RuntimeDyld"), "RuntimeDyld"),
clEnumValN(JITLinkerKind::JITLink, "jitlink", clEnumValN(JITLinkerKind::JITLink, "jitlink",
"Orc-specific linker"))); "Orc-specific linker")));
cl::opt<std::string> OrcRuntime("orc-runtime",
cl::desc("Use ORC runtime from given path"),
cl::init(""));
cl::opt<unsigned> cl::opt<unsigned>
LazyJITCompileThreads("compile-threads", LazyJITCompileThreads("compile-threads",
@ -230,13 +236,15 @@ namespace {
cl::desc("Do not resolve lli process symbols in JIT'd code"), cl::desc("Do not resolve lli process symbols in JIT'd code"),
cl::init(false)); cl::init(false));
enum class LLJITPlatform { Inactive, DetectHost, GenericIR }; enum class LLJITPlatform { Inactive, DetectHost, ORC, GenericIR };
cl::opt<LLJITPlatform> cl::opt<LLJITPlatform>
Platform("lljit-platform", cl::desc("Platform to use with LLJIT"), Platform("lljit-platform", cl::desc("Platform to use with LLJIT"),
cl::init(LLJITPlatform::DetectHost), cl::init(LLJITPlatform::DetectHost),
cl::values(clEnumValN(LLJITPlatform::DetectHost, "DetectHost", cl::values(clEnumValN(LLJITPlatform::DetectHost, "DetectHost",
"Select based on JIT target triple"), "Select based on JIT target triple"),
clEnumValN(LLJITPlatform::ORC, "ORC",
"Use ORCPlatform with the ORC runtime"),
clEnumValN(LLJITPlatform::GenericIR, "GenericIR", clEnumValN(LLJITPlatform::GenericIR, "GenericIR",
"Use LLJITGenericIRPlatform"), "Use LLJITGenericIRPlatform"),
clEnumValN(LLJITPlatform::Inactive, "Inactive", clEnumValN(LLJITPlatform::Inactive, "Inactive",
@ -365,6 +373,53 @@ private:
} }
}; };
class ORCPlatformSupport : public orc::LLJIT::PlatformSupport {
public:
ORCPlatformSupport(orc::LLJIT &J) : J(J) {}
Error initialize(orc::JITDylib &JD) override {
using llvm::orc::shared::SPSExecutorAddr;
using llvm::orc::shared::SPSString;
using SPSDLOpenSig = SPSExecutorAddr(SPSString, int32_t);
enum dlopen_mode : int32_t {
ORC_RT_RTLD_LAZY = 0x1,
ORC_RT_RTLD_NOW = 0x2,
ORC_RT_RTLD_LOCAL = 0x4,
ORC_RT_RTLD_GLOBAL = 0x8
};
if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlopen_wrapper")) {
return J.getExecutionSession().callSPSWrapper<SPSDLOpenSig>(
*WrapperAddr, DSOHandles[&JD], JD.getName(),
int32_t(ORC_RT_RTLD_LAZY));
} else
return WrapperAddr.takeError();
}
Error deinitialize(orc::JITDylib &JD) override {
using llvm::orc::shared::SPSExecutorAddr;
using SPSDLCloseSig = int32_t(SPSExecutorAddr);
if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlclose_wrapper")) {
int32_t result;
auto E = J.getExecutionSession().callSPSWrapper<SPSDLCloseSig>(
*WrapperAddr, result, DSOHandles[&JD]);
if (E)
return E;
else if (result)
return make_error<StringError>("dlclose failed",
inconvertibleErrorCode());
DSOHandles.erase(&JD);
} else
return WrapperAddr.takeError();
return Error::success();
}
private:
orc::LLJIT &J;
DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles;
};
// On Mingw and Cygwin, an external symbol named '__main' is called from the // On Mingw and Cygwin, an external symbol named '__main' is called from the
// generated 'main' function to allow static initialization. To avoid linking // generated 'main' function to allow static initialization. To avoid linking
// problems with remote targets (because lli's remote target support does not // problems with remote targets (because lli's remote target support does not
@ -904,21 +959,29 @@ int runOrcJIT(const char *ProgName) {
} }
// Set up LLJIT platform. // Set up LLJIT platform.
{ LLJITPlatform P = Platform;
LLJITPlatform P = Platform; if (P == LLJITPlatform::DetectHost) {
if (P == LLJITPlatform::DetectHost) if (JITLinker == JITLinkerKind::JITLink && !OrcRuntime.empty() &&
(TT->isOSBinFormatMachO() || TT->isOSBinFormatELF()))
P = LLJITPlatform::ORC;
else
P = LLJITPlatform::GenericIR; P = LLJITPlatform::GenericIR;
}
switch (P) { switch (P) {
case LLJITPlatform::GenericIR: case LLJITPlatform::ORC:
// Nothing to do: LLJITBuilder will use this by default. Builder.setPlatformSetUp([](llvm::orc::LLJIT &J) -> llvm::Error {
break; J.setPlatformSupport(std::make_unique<ORCPlatformSupport>(J));
case LLJITPlatform::Inactive: return Error::success();
Builder.setPlatformSetUp(orc::setUpInactivePlatform); });
break; break;
default: case LLJITPlatform::GenericIR:
llvm_unreachable("Unrecognized platform value"); // Nothing to do: LLJITBuilder will use this by default.
} break;
case LLJITPlatform::Inactive:
Builder.setPlatformSetUp(orc::setUpInactivePlatform);
break;
default:
llvm_unreachable("Unrecognized platform value");
} }
std::unique_ptr<orc::ExecutorProcessControl> EPC = nullptr; std::unique_ptr<orc::ExecutorProcessControl> EPC = nullptr;
@ -926,13 +989,15 @@ int runOrcJIT(const char *ProgName) {
EPC = ExitOnErr(orc::SelfExecutorProcessControl::Create( EPC = ExitOnErr(orc::SelfExecutorProcessControl::Create(
std::make_shared<orc::SymbolStringPool>())); std::make_shared<orc::SymbolStringPool>()));
Builder.setObjectLinkingLayerCreator([&EPC](orc::ExecutionSession &ES, Builder.setObjectLinkingLayerCreator([&EPC, &P](orc::ExecutionSession &ES,
const Triple &) { const Triple &TT) {
auto L = std::make_unique<orc::ObjectLinkingLayer>(ES, EPC->getMemMgr()); auto L = std::make_unique<orc::ObjectLinkingLayer>(ES, EPC->getMemMgr());
L->addPlugin(std::make_unique<orc::EHFrameRegistrationPlugin>( if (P != LLJITPlatform::ORC) {
ES, ExitOnErr(orc::EPCEHFrameRegistrar::Create(ES)))); L->addPlugin(std::make_unique<orc::EHFrameRegistrationPlugin>(
L->addPlugin(std::make_unique<orc::DebugObjectManagerPlugin>( ES, ExitOnErr(orc::EPCEHFrameRegistrar::Create(ES))));
ES, ExitOnErr(orc::createJITLoaderGDBRegistrar(ES)))); L->addPlugin(std::make_unique<orc::DebugObjectManagerPlugin>(
ES, ExitOnErr(orc::createJITLoaderGDBRegistrar(ES))));
}
return L; return L;
}); });
} }
@ -979,6 +1044,31 @@ int runOrcJIT(const char *ProgName) {
std::make_unique<LLIBuiltinFunctionGenerator>(GenerateBuiltinFunctions, std::make_unique<LLIBuiltinFunctionGenerator>(GenerateBuiltinFunctions,
Mangle)); Mangle));
if (P == LLJITPlatform::ORC) {
if (auto *OLL = llvm::dyn_cast<llvm::orc::ObjectLinkingLayer>(ObjLayer)) {
auto &ES = J->getExecutionSession();
if (TT->isOSBinFormatMachO()) {
if (auto P = llvm::orc::MachOPlatform::Create(
ES, *OLL, J->getMainJITDylib(), OrcRuntime.c_str()))
ES.setPlatform(std::move(*P));
else
ExitOnErr(P.takeError());
} else if (TT->isOSBinFormatELF()) {
if (auto P = llvm::orc::ELFNixPlatform::Create(
ES, *OLL, J->getMainJITDylib(), OrcRuntime.c_str()))
ES.setPlatform(std::move(*P));
else
ExitOnErr(P.takeError());
} else {
errs() << "No ORC platform support\n";
exit(1);
}
} else {
errs() << "ORC platform requires JITLink\n";
exit(1);
}
}
// Regular modules are greedy: They materialize as a whole and trigger // Regular modules are greedy: They materialize as a whole and trigger
// materialization for all required symbols recursively. Lazy modules go // materialization for all required symbols recursively. Lazy modules go
// through partitioning and they replace outgoing calls with reexport stubs // through partitioning and they replace outgoing calls with reexport stubs