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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use ptrdiff_t sized offsets for gvars_offsets to allow large sysimages #57366

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions src/aotcompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "platform.h"

// target support
#include "llvm/IR/Constants.h"
#include "llvm/Support/Debug.h"
#include <llvm/TargetParser/Triple.h>
#include "llvm/Support/CodeGen.h"
#include <llvm/ADT/Statistic.h>
Expand Down Expand Up @@ -199,29 +201,28 @@ static inline SmallVector<T*, 0> consume_gv(Module &M, const char *name, bool al
return res;
}

static Constant *get_ptrdiff32(Type *T_size, Constant *ptr, Constant *base)
static Constant *get_ptrdiff(Type *T_size, Constant *ptr, Constant *base)
{
if (ptr->getType()->isPointerTy())
ptr = ConstantExpr::getPtrToInt(ptr, T_size);
auto ptrdiff = ConstantExpr::getSub(ptr, base);
return T_size->getPrimitiveSizeInBits() > 32 ? ConstantExpr::getTrunc(ptrdiff, Type::getInt32Ty(ptr->getContext())) : ptrdiff;
return ptrdiff;
}

static Constant *emit_offset_table(Module &M, Type *T_size, ArrayRef<Constant*> vars,
StringRef name, StringRef suffix)
{
auto T_int32 = Type::getInt32Ty(M.getContext());
uint32_t nvars = vars.size();
ArrayType *vars_type = ArrayType::get(T_int32, nvars + 1);
ArrayType *vars_type = ArrayType::get(T_size, nvars + 1);
auto gv = new GlobalVariable(M, vars_type, true,
GlobalVariable::ExternalLinkage,
nullptr,
name + "_offsets" + suffix);
auto vbase = ConstantExpr::getPtrToInt(gv, T_size);
SmallVector<Constant*, 0> offsets(nvars + 1);
offsets[0] = ConstantInt::get(T_int32, nvars);
offsets[0] = ConstantInt::get(T_size, nvars);
for (uint32_t i = 0; i < nvars; i++)
offsets[i + 1] = get_ptrdiff32(T_size, vars[i], vbase);
offsets[i + 1] = get_ptrdiff(T_size, vars[i], vbase);
gv->setInitializer(ConstantArray::get(vars_type, offsets));
gv->setVisibility(GlobalValue::HiddenVisibility);
gv->setDSOLocal(true);
Expand Down Expand Up @@ -1991,7 +1992,7 @@ void jl_dump_native_impl(void *native_code,

CodeModel::Model CMModel = CodeModel::Small;
if (TheTriple.isPPC() || TheTriple.isRISCV() ||
(TheTriple.isX86() && TheTriple.isArch64Bit() && TheTriple.isOSLinux())) {
(TheTriple.isX86() && TheTriple.isArch64Bit() && (TheTriple.isOSLinux() || TheTriple.isOSDarwin()))) {
// On PPC the small model is limited to 16bit offsets. For very large images the small code model
CMModel = CodeModel::Medium; // isn't good enough on x86 so use Medium, it has no cost because only the image goes in .ldata
}
Expand Down
2 changes: 1 addition & 1 deletion src/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ static inline jl_image_t parse_sysimg(void *hdl, F &&callback)
}

if (!gvars.empty()) {
auto offsets = (int32_t*)malloc(sizeof(int32_t) * gvars.size());
auto offsets = (ptrdiff_t*)malloc(sizeof(ptrdiff_t) * gvars.size());
res.gvars_base = (const char*)pointers->header;
for (size_t i = 0; i < gvars.size(); i++) {
assert(gvars[i] && "Missing global variable pointer!");
Expand Down
4 changes: 2 additions & 2 deletions src/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ typedef struct _jl_image_fptrs_t {
typedef struct {
uint64_t base;
const char *gvars_base;
const int32_t *gvars_offsets;
const ptrdiff_t *gvars_offsets;
uint32_t ngvars;
jl_image_fptrs_t fptrs;
void **jl_small_typeof;
Expand Down Expand Up @@ -126,7 +126,7 @@ typedef struct {
// Similar to fvar_offsets, but for gvars
// This is also the base data pointer
// (all data pointers in this shard are stored as offsets to this address)
const int32_t *gvar_offsets;
const ptrdiff_t *gvar_offsets;
// This is the mapping of shard global variable index -> global global variable index
// Similar to fvar_idxs, but for gvars
const uint32_t *gvar_idxs;
Expand Down
2 changes: 1 addition & 1 deletion src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ typedef struct {
static void *jl_sysimg_handle = NULL;
static jl_image_t sysimage;

static inline uintptr_t *sysimg_gvars(const char *base, const int32_t *offsets, size_t idx)
static inline uintptr_t *sysimg_gvars(const char *base, const ptrdiff_t *offsets, size_t idx)
{
return (uintptr_t*)(base + offsets[idx]);
}
Expand Down
22 changes: 17 additions & 5 deletions test/compileall.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,22 @@
# We make it a separate test target here, so that it can run in parallel
# with the rest of the tests.

mktempdir() do dir
@test success(pipeline(`$(Base.julia_cmd()) --compile=all --strip-ir --output-o $(dir)/sys.o.a -e 'exit()'`, stderr=stderr)) skip=(Sys.WORD_SIZE == 32)
if isfile(joinpath(dir, "sys.o.a"))
Base.Linking.link_image(joinpath(dir, "sys.o.a"), joinpath(dir, "sys.so"))
@test success(`$(Base.julia_cmd()) -J $(dir)/sys.so -e 'Base.scrub_repl_backtrace(nothing); exit()'`)


if !Sys.iswindows() && !(Sys.WORD_SIZE == 32) #Windows doesn't support large images
mktempdir() do dir
@test success(pipeline(`$(Base.julia_cmd()) --compile=all --strip-ir --output-o $(dir)/sys.o.a -e 'const ballast = Memory{UInt8}(undef, 1 << 31); exit()'`, stderr=stderr))
if isfile(joinpath(dir, "sys.o.a"))
Base.Linking.link_image(joinpath(dir, "sys.o.a"), joinpath(dir, "sys.so"))
@test success(`$(Base.julia_cmd()) -J $(dir)/sys.so -e 'Base.scrub_repl_backtrace(nothing); exit()'`)
end
end
else
mktempdir() do dir
@test success(pipeline(`$(Base.julia_cmd()) --compile=all --strip-ir --output-o $(dir)/sys.o.a -e 'exit()'`, stderr=stderr)) skip=(Sys.WORD_SIZE == 32)
if isfile(joinpath(dir, "sys.o.a"))
Base.Linking.link_image(joinpath(dir, "sys.o.a"), joinpath(dir, "sys.so"))
@test success(`$(Base.julia_cmd()) -J $(dir)/sys.so -e 'Base.scrub_repl_backtrace(nothing); exit()'`)
end
end
end
4 changes: 2 additions & 2 deletions test/llvmpasses/multiversioning-clone-only.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='JuliaMultiVersioning' -S %s | FileCheck %s --allow-unused-prefixes=false --check-prefixes=CHECK,OPAQUE

; CHECK: @jl_gvar_base = hidden constant i64 0
; CHECK: @jl_gvar_offsets = hidden constant [0 x i32] zeroinitializer
; CHECK: @jl_gvar_offsets = hidden constant [0 x i64] zeroinitializer
; CHECK: @jl_fvar_idxs = hidden constant [1 x i32] zeroinitializer
; CHECK: @jl_gvar_idxs = hidden constant [0 x i32] zeroinitializer
; OPAQUE: @subtarget_cloned_gv = hidden global ptr null
Expand All @@ -18,7 +18,7 @@

@jl_fvars = global [1 x i64*] [i64* bitcast (i32 (i32)* @subtarget_cloned to i64*)], align 8
@jl_gvar_base = hidden constant i64 zeroinitializer, align 8
@jl_gvar_offsets = hidden constant [0 x i32] zeroinitializer, align 8
@jl_gvar_offsets = hidden constant [0 x i64] zeroinitializer, align 8
@jl_fvar_idxs = hidden constant [1 x i32] [i32 0], align 8
@jl_gvar_idxs = hidden constant [0 x i32] zeroinitializer, align 8
@subtarget_cloned_gv = hidden global i64* bitcast (i32 (i32)* @subtarget_cloned to i64*), align 8
Expand Down