Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

separate codegen/LLVM from julia runtime #41936

Merged
merged 2 commits into from Oct 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 15 additions & 5 deletions Make.inc
Expand Up @@ -934,6 +934,7 @@ OPENBLAS_DYNAMIC_ARCH:=0
OPENBLAS_TARGET_ARCH:=ARMV8
USE_BLAS64:=1
BINARY:=64
HAVE_SSP:=1
ifeq ($(OS),Darwin)
# Apple Chips are all at least A12Z
MCPU:=apple-a12
Expand Down Expand Up @@ -1498,6 +1499,12 @@ LIBJULIAINTERNAL_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlib
LIBJULIAINTERNAL_DEBUG_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_shlibdir)/libjulia-internal-debug.$(JL_MAJOR_SHLIB_EXT))
LIBJULIAINTERNAL_DEBUG_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/libjulia-internal-debug.$(JL_MAJOR_SHLIB_EXT))

LIBJULIACODEGEN_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_shlibdir)/libjulia-codegen.$(JL_MAJOR_SHLIB_EXT))
LIBJULIACODEGEN_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/libjulia-codegen.$(JL_MAJOR_SHLIB_EXT))

LIBJULIACODEGEN_DEBUG_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_shlibdir)/libjulia-codegen-debug.$(JL_MAJOR_SHLIB_EXT))
LIBJULIACODEGEN_DEBUG_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/libjulia-codegen-debug.$(JL_MAJOR_SHLIB_EXT))

ifeq ($(OS),WINNT)
ifeq ($(BINARY),32)
LIBGCC_NAME := libgcc_s_sjlj-1.$(SHLIB_EXT)
Expand Down Expand Up @@ -1537,16 +1544,19 @@ LIBM_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/$(LIBMN
# We list:
# * libgcc_s, because FreeBSD needs to load ours, not the system one.
# * libopenlibm, because Windows has an untrustworthy libm, and we want to use ours more than theirs
# * libjulia, which must always come last.
# * libjulia-internal, which must always come second-to-last.
# * libjulia-codegen, which must always come last
#
# We need these four separate variables because:
# * debug builds must link against libjuliadebug, not libjulia
# * install time relative paths are not equal to build time relative paths (../lib vs. ../lib/julia)
# That second point will no longer be true for most deps once they are placed within Artifacts directories.
LOADER_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):$(LIBJULIAINTERNAL_BUILD_DEPLIB)
LOADER_DEBUG_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):$(LIBJULIAINTERNAL_DEBUG_BUILD_DEPLIB)
LOADER_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):$(LIBJULIAINTERNAL_INSTALL_DEPLIB)
LOADER_DEBUG_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):$(LIBJULIAINTERNAL_DEBUG_INSTALL_DEPLIB)
# Note that we prefix `libjulia-codegen` and `libjulia-internal` with `@` to signify to the loader that it
# should not automatically dlopen() it in its loading loop.
LOADER_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):@$(LIBJULIAINTERNAL_BUILD_DEPLIB):@$(LIBJULIACODEGEN_BUILD_DEPLIB):
LOADER_DEBUG_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):@$(LIBJULIAINTERNAL_DEBUG_BUILD_DEPLIB):@$(LIBJULIACODEGEN_DEBUG_BUILD_DEPLIB):
LOADER_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):@$(LIBJULIAINTERNAL_INSTALL_DEPLIB):@$(LIBJULIACODEGEN_INSTALL_DEPLIB):
LOADER_DEBUG_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):@$(LIBJULIAINTERNAL_DEBUG_INSTALL_DEPLIB):@$(LIBJULIACODEGEN_DEBUG_INSTALL_DEPLIB):

# Colors for make
ifndef VERBOSE
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Expand Up @@ -165,9 +165,9 @@ JL_TARGETS += julia-debug
endif

# private libraries, that are installed in $(prefix)/lib/julia
JL_PRIVATE_LIBS-0 := libccalltest libllvmcalltest libjulia-internal libblastrampoline
JL_PRIVATE_LIBS-0 := libccalltest libllvmcalltest libjulia-internal libjulia-codegen libblastrampoline
ifeq ($(BUNDLE_DEBUG_LIBS),1)
JL_PRIVATE_LIBS-0 += libjulia-internal-debug
JL_PRIVATE_LIBS-0 += libjulia-internal-debug libjulia-codegen-debug
endif
ifeq ($(USE_GPL_LIBS), 1)
JL_PRIVATE_LIBS-$(USE_SYSTEM_LIBSUITESPARSE) += libamd libbtf libcamd libccolamd libcholmod libcolamd libklu libldl librbio libspqr libsuitesparseconfig libumfpack
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Expand Up @@ -23,6 +23,10 @@ Language changes
Compiler/Runtime improvements
-----------------------------

* The LLVM-based compiler has been separated from the run-time library into a new library,
`libjulia-codegen`. It is loaded by default, so normal usage should see no changes.
In deployments that do not need the compiler (e.g. system images where all needed code
is precompiled), this library (and its LLVM dependency) can simply be excluded ([#41936]).

Command-line option changes
---------------------------
Expand Down
40 changes: 30 additions & 10 deletions cli/jl_exports.h
Expand Up @@ -19,37 +19,57 @@ JL_EXPORTED_DATA_SYMBOLS(XX)
// Declare list of exported functions (sans type)
#define XX(name) JL_DLLEXPORT void name(void);
typedef void (anonfunc)(void);
JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX

// Define holder locations for function addresses as `const void * $(name)_addr = NULL;
#define XX(name) JL_HIDDEN anonfunc * name##_addr = NULL;
JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX

// Generate lists of function names and addresses
#define XX(name) "i" #name,
static const char *const jl_exported_func_names[] = {
JL_EXPORTED_FUNCS(XX)
static const char *const jl_runtime_exported_func_names[] = {
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
NULL
};
#undef XX

#define XX(name) #name"_impl",
static const char *const jl_codegen_exported_func_names[] = {
JL_CODEGEN_EXPORTED_FUNCS(XX)
NULL
};
#undef XX

#define XX(name) #name"_fallback",
static const char *const jl_codegen_fallback_func_names[] = {
JL_CODEGEN_EXPORTED_FUNCS(XX)
NULL
};
#undef XX

#define XX(name) &name##_addr,
static anonfunc **const jl_exported_func_addrs[] = {
JL_EXPORTED_FUNCS(XX)
static anonfunc **const jl_runtime_exported_func_addrs[] = {
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
NULL
};
static anonfunc **const jl_codegen_exported_func_addrs[] = {
JL_CODEGEN_EXPORTED_FUNCS(XX)
NULL
};
#undef XX
4 changes: 2 additions & 2 deletions cli/list_strip_symbols.h
Expand Up @@ -3,8 +3,8 @@
#include "jl_exported_funcs.inc"
#include "trampolines/common.h"
#define XX(x) --strip-symbol=CNAME(x)
JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
#undef XX
JeffBezanson marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 4 additions & 1 deletion cli/loader.h
Expand Up @@ -25,17 +25,19 @@
#include <stdint.h>

#ifdef _OS_WINDOWS_

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#else

#ifdef _OS_DARWIN_
#include <mach-o/dyld.h>
#endif
#ifdef _OS_FREEBSD_
#include <stddef.h>
#include <sys/sysctl.h>
#endif

#define _GNU_SOURCE // Need this for `dladdr()`
#include <stdio.h>
#include <stdlib.h>
Expand All @@ -44,6 +46,7 @@
#include <libgen.h>
#include <unistd.h>
#include <dlfcn.h>

#endif

// Borrow definition from `support/dtypes.h`
Expand Down
68 changes: 57 additions & 11 deletions cli/loader_lib.c
Expand Up @@ -16,7 +16,7 @@ extern "C" {
#endif

// Save DEP_LIBS to a variable that is explicitly sized for expansion
static char dep_libs[512] = DEP_LIBS;
static char dep_libs[1024] = DEP_LIBS;

JL_DLLEXPORT void jl_loader_print_stderr(const char * msg)
{
Expand All @@ -31,7 +31,7 @@ void jl_loader_print_stderr3(const char * msg1, const char * msg2, const char *
}

/* Wrapper around dlopen(), with extra relative pathing thrown in*/
static void * load_library(const char * rel_path, const char * src_dir) {
static void * load_library(const char * rel_path, const char * src_dir, int err) {
void * handle = NULL;

// See if a handle is already open to the basename
Expand Down Expand Up @@ -65,6 +65,8 @@ static void * load_library(const char * rel_path, const char * src_dir) {
#endif

if (handle == NULL) {
if (!err)
return NULL;
jl_loader_print_stderr3("ERROR: Unable to load dependent library ", path, "\n");
#if defined(_OS_WINDOWS_)
LPWSTR wmsg = TEXT("");
Expand Down Expand Up @@ -157,31 +159,75 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) {
// Pre-load libraries that libjulia-internal needs.
int deps_len = strlen(dep_libs);
char * curr_dep = &dep_libs[0];

// We keep track of "special" libraries names (ones whose name is prefixed with `@`)
// which are libraries that we want to load in some special, custom way, such as
// `libjulia-internal` or `libjulia-codegen`.
int special_idx = 0;
char * special_library_names[2] = {NULL};
while (1) {
// try to find next colon character, if we can't, escape out.
// try to find next colon character; if we can't, break out
char * colon = strchr(curr_dep, ':');
if (colon == NULL)
break;

// Chop the string at the colon, load this library.
// Chop the string at the colon so it's a valid-ending-string
*colon = '\0';
load_library(curr_dep, lib_dir);

// If this library name starts with `@`, don't open it here (but mark it as special)
if (curr_dep[0] == '@') {
if (special_idx > sizeof(special_library_names)/sizeof(char *)) {
jl_loader_print_stderr("ERROR: Too many special library names specified, check LOADER_BUILD_DEP_LIBS and friends!\n");
exit(1);
}
special_library_names[special_idx] = curr_dep + 1;
special_idx += 1;
} else {
load_library(curr_dep, lib_dir, 1);
}

// Skip ahead to next dependency
curr_dep = colon + 1;
}

// Last dependency is `libjulia-internal`, so load that and we're done with `dep_libs`!
libjulia_internal = load_library(curr_dep, lib_dir);
if (special_idx != sizeof(special_library_names)/sizeof(char *)) {
jl_loader_print_stderr("ERROR: Too few special library names specified, check LOADER_BUILD_DEP_LIBS and friends!\n");
exit(1);
}

// Unpack our special library names. This is why ordering of library names matters.
libjulia_internal = load_library(special_library_names[0], lib_dir, 1);
void *libjulia_codegen = load_library(special_library_names[1], lib_dir, 0);
const char * const * codegen_func_names;
if (libjulia_codegen == NULL) {
// if codegen is not available, use fallback implementation in libjulia-internal
libjulia_codegen = libjulia_internal;
codegen_func_names = jl_codegen_fallback_func_names;
}
else {
codegen_func_names = jl_codegen_exported_func_names;
}

// Once we have libjulia-internal loaded, re-export its symbols:
for (unsigned int symbol_idx=0; jl_exported_func_names[symbol_idx] != NULL; ++symbol_idx) {
void *addr = lookup_symbol(libjulia_internal, jl_exported_func_names[symbol_idx]);
for (unsigned int symbol_idx=0; jl_runtime_exported_func_names[symbol_idx] != NULL; ++symbol_idx) {
void *addr = lookup_symbol(libjulia_internal, jl_runtime_exported_func_names[symbol_idx]);
if (addr == NULL) {
jl_loader_print_stderr3("ERROR: Unable to load ", jl_runtime_exported_func_names[symbol_idx], " from libjulia-internal\n");
exit(1);
}
(*jl_runtime_exported_func_addrs[symbol_idx]) = addr;
}
// jl_options must be initialized very early, in case an embedder sets some
// values there before calling jl_init
((void (*)())jl_init_options_addr)();

for (unsigned int symbol_idx=0; codegen_func_names[symbol_idx] != NULL; ++symbol_idx) {
void *addr = lookup_symbol(libjulia_codegen, codegen_func_names[symbol_idx]);
if (addr == NULL) {
jl_loader_print_stderr3("ERROR: Unable to load ", jl_exported_func_names[symbol_idx], " from libjulia-internal\n");
jl_loader_print_stderr3("ERROR: Unable to load ", codegen_func_names[symbol_idx], " from libjulia-codegen\n");
exit(1);
}
(*jl_exported_func_addrs[symbol_idx]) = addr;
(*jl_codegen_exported_func_addrs[symbol_idx]) = addr;
}

// jl_options must be initialized very early, in case an embedder sets some
Expand Down
5 changes: 3 additions & 2 deletions cli/trampolines/trampolines_aarch64.S
Expand Up @@ -13,8 +13,9 @@ CNAME(name)##: SEP \
br x16 SEP \
.cfi_endproc SEP \

JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels a little odd to be exporting the internal plugins from here, but otherwise, this PR seems to be mostly just renaming lots of (lots of) variables, so seems very straightforward. Not sure why it would be failing on CI. Are we accidentally linking part of libLLVM statically?

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's true; I only really did this to reuse the mechanism.

#undef XX
5 changes: 3 additions & 2 deletions cli/trampolines/trampolines_arm.S
Expand Up @@ -16,8 +16,9 @@ CONCAT(.L,CNAMEADDR(name))##: ; \
.word CNAMEADDR(name)##-(CONCAT(.L,CNAME(name)) + 8); \
.cfi_endproc; \

JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX
5 changes: 3 additions & 2 deletions cli/trampolines/trampolines_i686.S
Expand Up @@ -14,8 +14,9 @@ CNAME(name)##:; \
.cfi_endproc; \
EXPORT(name); \

JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX
3 changes: 2 additions & 1 deletion cli/trampolines/trampolines_powerpc64le.S
Expand Up @@ -24,5 +24,6 @@ CNAME(name)##: ; \
.cfi_endproc; \
.size CNAME(name)##,.-CNAME(name)##; \

JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX
5 changes: 3 additions & 2 deletions cli/trampolines/trampolines_x86_64.S
Expand Up @@ -18,8 +18,9 @@ SEH_END(); \
.cfi_endproc; \
EXPORT(name); \

JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX