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

Optimize PLT and jl_load_and_lookup calls #50745

Merged
merged 4 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions src/aotcompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2144,6 +2144,9 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, siz
global.second->setVisibility(GlobalValue::DefaultVisibility);
}
}
if (!jl_options.image_codegen) {
optimizeDLSyms(*m.getModuleUnlocked());
}
assert(!verifyLLVMIR(*m.getModuleUnlocked()));
if (optimize) {
#ifndef JL_USE_NEW_PM
Expand Down
104 changes: 52 additions & 52 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,15 @@ static Value *runtime_sym_lookup(
// f_lib is actually one of the special sentinel values
libname = ConstantExpr::getIntToPtr(ConstantInt::get(emission_context.DL.getIntPtrType(irbuilder.getContext()), (uintptr_t)f_lib), getInt8PtrTy(irbuilder.getContext()));
}
llvmf = irbuilder.CreateCall(prepare_call_in(jl_builderModule(irbuilder), jldlsym_func),
auto lookup = irbuilder.CreateCall(prepare_call_in(jl_builderModule(irbuilder), jldlsym_func),
{ libname, nameval, libptrgv });
if (runtime_lib) {
lookup->addFnAttr(Attribute::get(lookup->getContext(), "julia.libname", f_lib));
} else {
lookup->addFnAttr(Attribute::get(lookup->getContext(), "julia.libidx", std::to_string((uintptr_t) f_lib)));
}
lookup->addFnAttr(Attribute::get(lookup->getContext(), "julia.fname", f_name));
llvmf = lookup;
}
setName(emission_context, llvmf, f_name + StringRef(".found"));
StoreInst *store = irbuilder.CreateAlignedStore(llvmf, llvmgv, Align(sizeof(void*)));
Expand All @@ -187,17 +194,6 @@ static Value *runtime_sym_lookup(
return irbuilder.CreateBitCast(p, funcptype);
}

static Value *runtime_sym_lookup(
jl_codectx_t &ctx,
PointerType *funcptype, const char *f_lib, jl_value_t *lib_expr,
const char *f_name, Function *f,
GlobalVariable *libptrgv,
GlobalVariable *llvmgv, bool runtime_lib)
{
return runtime_sym_lookup(ctx.emission_context, ctx.builder, &ctx, funcptype, f_lib, lib_expr,
f_name, f, libptrgv, llvmgv, runtime_lib);
}

static Value *runtime_sym_lookup(
jl_codectx_t &ctx,
PointerType *funcptype, const char *f_lib, jl_value_t *lib_expr,
Expand Down Expand Up @@ -225,7 +221,7 @@ static Value *runtime_sym_lookup(
libptrgv = prepare_global_in(jl_Module, libptrgv);
}
llvmgv = prepare_global_in(jl_Module, llvmgv);
return runtime_sym_lookup(ctx, funcptype, f_lib, lib_expr, f_name, f, libptrgv, llvmgv, runtime_lib);
return runtime_sym_lookup(ctx.emission_context, ctx.builder, &ctx, funcptype, f_lib, lib_expr, f_name, f, libptrgv, llvmgv, runtime_lib);
}

// Emit a "PLT" entry that will be lazily initialized
Expand All @@ -250,21 +246,26 @@ static GlobalVariable *emit_plt_thunk(
plt->setAttributes(attrs);
if (cc != CallingConv::C)
plt->setCallingConv(cc);
fname += "_got";
auto T_pvoidfunc = JuliaType::get_pvoidfunc_ty(M->getContext());
GlobalVariable *got = new GlobalVariable(*M, T_pvoidfunc, false,
GlobalVariable::ExternalLinkage,
ConstantExpr::getBitCast(plt, T_pvoidfunc),
fname);
fname + "_got");
if (runtime_lib) {
got->addAttribute("julia.libname", f_lib);
} else {
got->addAttribute("julia.libidx", std::to_string((uintptr_t) f_lib));
}
got->addAttribute("julia.fname", f_name);
BasicBlock *b0 = BasicBlock::Create(M->getContext(), "top", plt);
IRBuilder<> irbuilder(b0);
Value *ptr = runtime_sym_lookup(ctx.emission_context, irbuilder, NULL, funcptype, f_lib, NULL, f_name, plt, libptrgv,
llvmgv, runtime_lib);
StoreInst *store = irbuilder.CreateAlignedStore(irbuilder.CreateBitCast(ptr, T_pvoidfunc), got, Align(sizeof(void*)));
store->setAtomic(AtomicOrdering::Release);
SmallVector<Value*, 16> args;
for (Function::arg_iterator arg = plt->arg_begin(), arg_e = plt->arg_end(); arg != arg_e; ++arg)
args.push_back(&*arg);
for (auto &arg : plt->args())
args.push_back(&arg);
assert(cast<PointerType>(ptr->getType())->isOpaqueOrPointeeTypeMatches(functype));
CallInst *ret = irbuilder.CreateCall(
functype,
Expand Down Expand Up @@ -307,7 +308,6 @@ static Value *emit_plt(
CallingConv::ID cc, const char *f_lib, const char *f_name)
{
++PLT;
assert(ctx.emission_context.imaging);
// Don't do this for vararg functions so that the `musttail` is only
// an optimization and is not required to function correctly.
assert(!functype->isVarArg());
Expand Down Expand Up @@ -724,26 +724,26 @@ static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t narg
if (sym.lib_expr) {
res = runtime_sym_lookup(ctx, cast<PointerType>(getInt8PtrTy(ctx.builder.getContext())), NULL, sym.lib_expr, sym.f_name, ctx.f);
}
else if (ctx.emission_context.imaging) {
else /*if (ctx.emission_context.imaging) */{
res = runtime_sym_lookup(ctx, cast<PointerType>(getInt8PtrTy(ctx.builder.getContext())), sym.f_lib, NULL, sym.f_name, ctx.f);
res = ctx.builder.CreatePtrToInt(res, lrt);
}
else {
void *symaddr;

void* libsym = jl_get_library_(sym.f_lib, 0);
int symbol_found = jl_dlsym(libsym, sym.f_name, &symaddr, 0);
if (!libsym || !symbol_found) {
// Error mode, either the library or the symbol couldn't be find during compiletime.
// Fallback to a runtime symbol lookup.
res = runtime_sym_lookup(ctx, cast<PointerType>(getInt8PtrTy(ctx.builder.getContext())), sym.f_lib, NULL, sym.f_name, ctx.f);
res = ctx.builder.CreatePtrToInt(res, lrt);
} else {
// since we aren't saving this code, there's no sense in
// putting anything complicated here: just JIT the address of the cglobal
res = ConstantInt::get(lrt, (uint64_t)symaddr);
}
}
// else {
// void *symaddr;

// void* libsym = jl_get_library_(sym.f_lib, 0);
// int symbol_found = jl_dlsym(libsym, sym.f_name, &symaddr, 0);
// if (!libsym || !symbol_found) {
// // Error mode, either the library or the symbol couldn't be find during compiletime.
// // Fallback to a runtime symbol lookup.
// res = runtime_sym_lookup(ctx, cast<PointerType>(getInt8PtrTy(ctx.builder.getContext())), sym.f_lib, NULL, sym.f_name, ctx.f);
// res = ctx.builder.CreatePtrToInt(res, lrt);
// } else {
// // since we aren't saving this code, there's no sense in
// // putting anything complicated here: just JIT the address of the cglobal
// res = ConstantInt::get(lrt, (uint64_t)symaddr);
// }
// }
}

JL_GC_POP();
Expand Down Expand Up @@ -2106,7 +2106,7 @@ jl_cgval_t function_sig_t::emit_a_ccall(
++DeferredCCallLookups;
llvmf = runtime_sym_lookup(ctx, funcptype, NULL, symarg.lib_expr, symarg.f_name, ctx.f);
}
else if (ctx.emission_context.imaging) {
else /*if (ctx.emission_context.imaging) */{
++DeferredCCallLookups;
// vararg requires musttail,
// but musttail is incompatible with noreturn.
Expand All @@ -2115,22 +2115,22 @@ jl_cgval_t function_sig_t::emit_a_ccall(
else
llvmf = emit_plt(ctx, functype, attributes, cc, symarg.f_lib, symarg.f_name);
}
else {
void *symaddr;
void *libsym = jl_get_library_(symarg.f_lib, 0);
int symbol_found = jl_dlsym(libsym, symarg.f_name, &symaddr, 0);
if (!libsym || !symbol_found) {
++DeferredCCallLookups;
// either the library or the symbol could not be found, place a runtime
// lookup here instead.
llvmf = runtime_sym_lookup(ctx, funcptype, symarg.f_lib, NULL, symarg.f_name, ctx.f);
} else {
++LiteralCCalls;
// since we aren't saving this code, there's no sense in
// putting anything complicated here: just JIT the function address
llvmf = literal_static_pointer_val(symaddr, funcptype);
}
}
// else {
// void *symaddr;
// void *libsym = jl_get_library_(symarg.f_lib, 0);
// int symbol_found = jl_dlsym(libsym, symarg.f_name, &symaddr, 0);
// if (!libsym || !symbol_found) {
// ++DeferredCCallLookups;
// // either the library or the symbol could not be found, place a runtime
// // lookup here instead.
// llvmf = runtime_sym_lookup(ctx, funcptype, symarg.f_lib, NULL, symarg.f_name, ctx.f);
// } else {
// ++LiteralCCalls;
// // since we aren't saving this code, there's no sense in
// // putting anything complicated here: just JIT the function address
// llvmf = literal_static_pointer_val(symaddr, funcptype);
// }
// }
Copy link
Member

Choose a reason for hiding this comment

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

style nit: delete code, do not comment it out

}

OperandBundleDef OpBundle("jl_roots", gc_uses);
Expand Down
7 changes: 6 additions & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1796,8 +1796,11 @@ static inline GlobalVariable *prepare_global_in(Module *M, GlobalVariable *G)
if (!local) {
// Copy the GlobalVariable, but without the initializer, so it becomes a declaration
GlobalVariable *proto = new GlobalVariable(*M, G->getValueType(),
G->isConstant(), GlobalVariable::ExternalLinkage,
G->isConstant(), G->getLinkage(),
nullptr, G->getName(), nullptr, G->getThreadLocalMode());
if (proto->hasLocalLinkage()) {
proto->setInitializer(G->getInitializer());
}
proto->copyAttributesFrom(G);
// DLLImport only needs to be set for the shadow module
// it just gets annoying in the JIT
Expand Down Expand Up @@ -2363,6 +2366,8 @@ std::unique_ptr<Module> jl_create_llvm_module(StringRef name, LLVMContext &conte
if (!m->getModuleFlag("Debug Info Version"))
m->addModuleFlag(llvm::Module::Warning, "Debug Info Version",
llvm::DEBUG_METADATA_VERSION);
if (imaging_mode)
m->addModuleFlag(llvm::Module::Error, "julia.imaging_mode", 1);
Copy link
Member

Choose a reason for hiding this comment

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

Why is this a property of the code itself (rather than a choice of the use site of the code)? That seems weird

Copy link
Member Author

Choose a reason for hiding this comment

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

At the moment we make different choices in imaging mode vs non-imaging mode, so I wanted to carry that over (particularly in jl_dump_native, where we guess imaging mode from the global defaults rather than from how the code was generated).

m->setDataLayout(DL);
m->setTargetTriple(triple.str());

Expand Down
Loading