Skip to content

Commit

Permalink
codegen: use constant placeholder objects instead of realizing LLVM f…
Browse files Browse the repository at this point in the history
…unctions

We already had prepare_global/prepare_call functions. This simply lets
us use that to allocate these on-demand instead of keeping around a
global copy of them to template from.
  • Loading branch information
vtjnash committed Jun 15, 2020
1 parent a12c30e commit cb993f3
Show file tree
Hide file tree
Showing 10 changed files with 763 additions and 810 deletions.
1 change: 0 additions & 1 deletion src/anticodegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ JL_DLLEXPORT size_t jl_LLVMDisasmInstruction(void *DC, uint8_t *Bytes, uint64_t
int32_t jl_assign_functionID(const char *fname) UNAVAILABLE

void jl_init_codegen(void) { }
void jl_fptr_to_llvm(void *fptr, jl_method_instance_t *lam, int specsig) { }

int jl_getFunctionInfo(jl_frame_t **frames, uintptr_t pointer, int skipC, int noInline)
{
Expand Down
2 changes: 1 addition & 1 deletion src/aotcompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ void jl_dump_native(void *native_code,

// reflect the address of the jl_RTLD_DEFAULT_handle variable
// back to the caller, so that we can check for consistency issues
GlobalValue *jlRTLD_DEFAULT_var = data->M->getNamedValue("jl_RTLD_DEFAULT_handle");
GlobalValue *jlRTLD_DEFAULT_var = jl_emit_RTLD_DEFAULT_var(data->M.get());
addComdat(new GlobalVariable(*data->M,
jlRTLD_DEFAULT_var->getType(),
true,
Expand Down
64 changes: 56 additions & 8 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
// --- the ccall, cglobal, and llvm intrinsics ---
#include "llvm/Support/Path.h" // for llvm::sys::path

// somewhat unusual variable, in that aotcompile wants to get the address of this for a sanity check
GlobalVariable *jl_emit_RTLD_DEFAULT_var(Module *M)
{
return prepare_global_in(M, jlRTLD_DEFAULT_var);
}

// Find or create the GVs for the library and symbol lookup.
// Return `runtime_lib` (whether the library name is a string)
// The `lib` and `sym` GV returned may not be in the current module.
Expand All @@ -15,17 +21,17 @@ static bool runtime_sym_gvs(jl_codegen_params_t &emission_context, const char *f
jl_codegen_params_t::SymMapGV *symMap;
#ifdef _OS_WINDOWS_
if ((intptr_t)f_lib == 1) {
libptrgv = jlexe_var;
libptrgv = prepare_global_in(M, jlexe_var);
symMap = &emission_context.symMapExe;
}
else if ((intptr_t)f_lib == 2) {
libptrgv = jldll_var;
libptrgv = prepare_global_in(M, jldll_var);
symMap = &emission_context.symMapDl;
}
else
#endif
if (f_lib == NULL) {
libptrgv = jlRTLD_DEFAULT_var;
libptrgv = jl_emit_RTLD_DEFAULT_var(M);
symMap = &emission_context.symMapDefault;
}
else {
Expand Down Expand Up @@ -636,6 +642,39 @@ static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t narg
return mark_julia_type(ctx, res, false, rt);
}

static Function *llvmcall_proto(Function *F, Module *M = nullptr)
{
// Copy the declaration characteristics of the Function (not the body)
Function *NewF = Function::Create(F->getFunctionType(),
Function::ExternalLinkage,
F->getName(),
M);

// Declarations are not allowed to have personality routines, but
// copyAttributesFrom sets them anyway. Temporarily unset the personality
// routine from `F`, since copying it and then resetting is more expensive
// as well as introducing an extra use from this unowned function, which
// can cause crashes in the LLVMContext's global destructor.
llvm::Constant *OldPersonalityFn = nullptr;
if (F->hasPersonalityFn()) {
OldPersonalityFn = F->getPersonalityFn();
F->setPersonalityFn(nullptr);
}

// FunctionType does not include any attributes. Copy them over manually
// as codegen may make decisions based on the presence of certain attributes
NewF->copyAttributesFrom(F);

if (OldPersonalityFn)
F->setPersonalityFn(OldPersonalityFn);

// DLLImport only needs to be set for the shadow module
// it just gets annoying in the JIT
NewF->setDLLStorageClass(GlobalValue::DefaultStorageClass);

return NewF;
}

class FunctionMover final : public ValueMaterializer
{
public:
Expand Down Expand Up @@ -699,7 +738,7 @@ class FunctionMover final : public ValueMaterializer
{
Function *NewF = destModule->getFunction(F->getName());
if (!NewF) {
NewF = function_proto(F);
NewF = llvmcall_proto(F);
NewF->setComdat(nullptr);
destModule->getFunctionList().push_back(NewF);
}
Expand Down Expand Up @@ -776,6 +815,15 @@ class FunctionMover final : public ValueMaterializer
};
};

static Function *prepare_llvmcall(Module *M, Function *Callee)
{
GlobalValue *local = M->getNamedValue(Callee->getName());
if (!local)
local = llvmcall_proto(Callee, M);
return cast<Function>(local);
}


// llvmcall(ir, (rettypes...), (argtypes...), args...)
static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs)
{
Expand Down Expand Up @@ -954,7 +1002,7 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar
std::stringstream name;
name << "jl_llvmcall" << llvmcallnumbering++;
f->setName(name.str());
f = cast<Function>(prepare_call(function_proto(f)).getCallee());
f = prepare_llvmcall(jl_Module, llvmcall_proto(f));
}
else {
f->setLinkage(GlobalValue::LinkOnceODRLinkage);
Expand Down Expand Up @@ -1862,9 +1910,9 @@ jl_cgval_t function_sig_t::emit_a_ccall(

OperandBundleDef OpBundle("jl_roots", gc_uses);
// the actual call
Value *ret = ctx.builder.CreateCall(prepare_call(llvmf),
ArrayRef<Value*>(&argvals[0], nccallargs + sret),
ArrayRef<OperandBundleDef>(&OpBundle, gc_uses.empty() ? 0 : 1));
CallInst *ret = ctx.builder.CreateCall(functype, llvmf,
ArrayRef<Value*>(&argvals[0], nccallargs + sret),
ArrayRef<OperandBundleDef>(&OpBundle, gc_uses.empty() ? 0 : 1));
((CallInst*)ret)->setAttributes(attributes);

if (cc != CallingConv::C)
Expand Down
76 changes: 15 additions & 61 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,54 +10,6 @@ static Instruction *tbaa_decorate(MDNode *md, Instruction *load_or_store)
return load_or_store;
}

static Function *function_proto(Function *F, Module *M = nullptr)
{
// Copy the declaration characteristics of the Function (not the body)
Function *NewF = Function::Create(F->getFunctionType(),
Function::ExternalLinkage,
F->getName(),
M);

// Declarations are not allowed to have personality routines, but
// copyAttributesFrom sets them anyway. Temporarily unset the personality
// routine from `F`, since copying it and then resetting is more expensive
// as well as introducing an extra use from this unowned function, which
// can cause crashes in the LLVMContext's global destructor.
llvm::Constant *OldPersonalityFn = nullptr;
if (F->hasPersonalityFn()) {
OldPersonalityFn = F->getPersonalityFn();
F->setPersonalityFn(nullptr);
}

// FunctionType does not include any attributes. Copy them over manually
// as codegen may make decisions based on the presence of certain attributes
NewF->copyAttributesFrom(F);

if (OldPersonalityFn)
F->setPersonalityFn(OldPersonalityFn);

// DLLImport only needs to be set for the shadow module
// it just gets annoying in the JIT
NewF->setDLLStorageClass(GlobalValue::DefaultStorageClass);

return NewF;
}

#define prepare_call(Callee) prepare_call_in(jl_Module, (Callee))
static FunctionCallee prepare_call_in(Module *M, Value *Callee)
{
if (Function *F = dyn_cast<Function>(Callee)) {
GlobalValue *local = M->getNamedValue(Callee->getName());
if (!local) {
local = function_proto(F, M);
}
Callee = local;
}
FunctionType *FnTy = cast<FunctionType>(
Callee->getType()->getPointerElementType());
return {FnTy, Callee};
}

// Take an arbitrary untracked value and make it gc-tracked
static Value *maybe_decay_untracked(IRBuilder<> &irbuilder, Value *V)
{
Expand Down Expand Up @@ -256,8 +208,9 @@ static Value *emit_pointer_from_objref(jl_codectx_t &ctx, Value *V)
Type *T = PointerType::get(T_jlvalue, AddressSpace::Derived);
if (V->getType() != T)
V = ctx.builder.CreateBitCast(V, T);
CallInst *Call = ctx.builder.CreateCall(prepare_call(pointer_from_objref_func), V);
Call->setAttributes(pointer_from_objref_func->getAttributes());
Function *F = prepare_call(pointer_from_objref_func);
CallInst *Call = ctx.builder.CreateCall(F, V);
Call->setAttributes(F->getAttributes());
return Call;
}

Expand Down Expand Up @@ -332,7 +285,7 @@ static Value *julia_pgv(jl_codectx_t &ctx, const char *prefix, jl_sym_t *name, j
return julia_pgv(ctx, fullname, addr);
}

static GlobalVariable *julia_const_gv(jl_value_t *val);
static JuliaVariable *julia_const_gv(jl_value_t *val);
static Value *literal_pointer_val_slot(jl_codectx_t &ctx, jl_value_t *p)
{
// emit a pointer to a jl_value_t* which will allow it to be valid across reloading code
Expand All @@ -345,7 +298,7 @@ static Value *literal_pointer_val_slot(jl_codectx_t &ctx, jl_value_t *p)
gv->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
return gv;
}
if (GlobalVariable *gv = julia_const_gv(p)) {
if (JuliaVariable *gv = julia_const_gv(p)) {
// if this is a known special object, use the existing GlobalValue
return prepare_global_in(jl_Module, gv);
}
Expand Down Expand Up @@ -2225,10 +2178,11 @@ static jl_value_t *static_constant_instance(Constant *constant, jl_value_t *jt)
return obj;
}

static Value *call_with_attrs(jl_codectx_t &ctx, Function *func, Value *v)
static Value *call_with_attrs(jl_codectx_t &ctx, JuliaFunction *intr, Value *v)
{
CallInst *Call = ctx.builder.CreateCall(prepare_call(func), v);
Call->setAttributes(func->getAttributes());
Function *F = prepare_call(intr);
CallInst *Call = ctx.builder.CreateCall(F, v);
Call->setAttributes(F->getAttributes());
return Call;
}

Expand Down Expand Up @@ -2607,19 +2561,19 @@ static void emit_cpointercheck(jl_codectx_t &ctx, const jl_cgval_t &x, const std
static Value *emit_allocobj(jl_codectx_t &ctx, size_t static_size, Value *jt)
{
Value *ptls_ptr = emit_bitcast(ctx, ctx.ptlsStates, T_pint8);
auto call = ctx.builder.CreateCall(prepare_call(jl_alloc_obj_func),
{ptls_ptr, ConstantInt::get(T_size, static_size),
maybe_decay_untracked(jt)});
call->setAttributes(jl_alloc_obj_func->getAttributes());
Function *F = prepare_call(jl_alloc_obj_func);
auto call = ctx.builder.CreateCall(F, {ptls_ptr, ConstantInt::get(T_size, static_size), maybe_decay_untracked(jt)});
call->setAttributes(F->getAttributes());
return call;
}

// allocation for unknown object from an untracked pointer
static Value *emit_new_bits(jl_codectx_t &ctx, Value *jt, Value *pval)
{
pval = ctx.builder.CreateBitCast(pval, T_pint8);
auto call = ctx.builder.CreateCall(prepare_call(jl_newbits_func), { jt, pval });
call->setAttributes(jl_newbits_func->getAttributes());
Function *F = prepare_call(jl_newbits_func);
auto call = ctx.builder.CreateCall(F, { jt, pval });
call->setAttributes(F->getAttributes());
return call;
}

Expand Down
Loading

0 comments on commit cb993f3

Please sign in to comment.