Skip to content

Commit

Permalink
[ORC][ORC_RT] Integrate ORC platforms with LLJIT and lli
Browse files Browse the repository at this point in the history
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
  • Loading branch information
housel committed Jun 10, 2022
1 parent 87c4268 commit 1aa71f8
Show file tree
Hide file tree
Showing 14 changed files with 319 additions and 23 deletions.
1 change: 1 addition & 0 deletions compiler-rt/lib/orc/CMakeLists.txt
Expand Up @@ -9,6 +9,7 @@ set(ORC_SOURCES
macho_platform.cpp
elfnix_platform.cpp
run_program_wrapper.cpp
dlfcn_wrapper.cpp
)

# Implementation files for all ORC architectures.
Expand Down
52 changes: 52 additions & 0 deletions compiler-rt/lib/orc/dlfcn_wrapper.cpp
@@ -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();
}
15 changes: 15 additions & 0 deletions compiler-rt/test/orc/TestCases/Darwin/x86-64/lljit-ehframe.cpp
@@ -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;
}
@@ -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
}
15 changes: 15 additions & 0 deletions compiler-rt/test/orc/TestCases/FreeBSD/x86-64/lljit-ehframe.cpp
@@ -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;
}
@@ -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
}
15 changes: 15 additions & 0 deletions compiler-rt/test/orc/TestCases/Linux/x86-64/lljit-ehframe.cpp
@@ -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;
}
@@ -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
}
5 changes: 4 additions & 1 deletion compiler-rt/test/orc/lit.cfg.py
Expand Up @@ -13,6 +13,7 @@ def build_invocation(compile_flags):

# Assume that llvm-jitlink is in the config.llvm_tools_dir.
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':
orc_rt_path = '%s/libclang_rt.orc_osx.a' % config.compiler_rt_libdir
else:
Expand All @@ -30,9 +31,11 @@ def build_invocation(compile_flags):
build_invocation(config.cxx_mode_flags + [config.target_cflags])))
config.substitutions.append(
('%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.
config.suffixes = ['.c', '.cpp', '.S']
config.suffixes = ['.c', '.cpp', '.S', '.ll']

# Exclude Inputs directories.
config.excludes = ['Inputs']
Expand Down
Expand Up @@ -125,7 +125,7 @@ class JITTargetMachineBuilder {
/// Set TargetOptions.
///
/// 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
/// for re-enabling these overwritten options.
JITTargetMachineBuilder &setOptions(TargetOptions Options) {
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
Expand Up @@ -263,6 +263,10 @@ ELFNixPlatform::standardRuntimeUtilityAliases() {
static const std::pair<const char *, const char *>
StandardRuntimeUtilityAliases[] = {
{"__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"}};

return ArrayRef<std::pair<const char *, const char *>>(
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/ExecutionEngine/Orc/JITTargetMachineBuilder.cpp
Expand Up @@ -19,6 +19,7 @@ JITTargetMachineBuilder::JITTargetMachineBuilder(Triple TT)
: TT(std::move(TT)) {
Options.EmulatedTLS = true;
Options.ExplicitEmulatedTLS = true;
Options.UseInitArray = true;
}

Expected<JITTargetMachineBuilder> JITTargetMachineBuilder::detectHost() {
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
Expand Up @@ -302,6 +302,10 @@ MachOPlatform::standardRuntimeUtilityAliases() {
static const std::pair<const char *, const char *>
StandardRuntimeUtilityAliases[] = {
{"___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"}};

return ArrayRef<std::pair<const char *, const char *>>(
Expand Down

0 comments on commit 1aa71f8

Please sign in to comment.