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

[Julep/WIP] Standalone AOT compilation mode #32273

Closed
Closed
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
326 changes: 317 additions & 9 deletions src/aotcompile.cpp

Large diffs are not rendered by default.

31 changes: 28 additions & 3 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ lazyModule(Func &&func)
std::forward<Func>(func));
}

extern "C" JL_DLLEXPORT void jl_set_standalone_aot_mode(void)
{
standalone_aot_mode = true;
}

extern "C" JL_DLLEXPORT void jl_clear_standalone_aot_mode(void)
{
standalone_aot_mode = false;
}


// global variables to pointers are pretty common,
// so this method is available as a convenience for emitting them.
Expand All @@ -55,7 +65,7 @@ lazyModule(Func &&func)
void** jl_emit_and_add_to_shadow(GlobalVariable *gv)
{
// make a copy in the shadow_output
assert(imaging_mode);
assert(imaging_mode || standalone_aot_mode);
PointerType *T = cast<PointerType>(gv->getValueType()); // pointer is the only supported type here
GlobalVariable *shadowvar = global_proto(gv, shadow_output);
shadowvar->setInitializer(ConstantPointerNull::get(T));
Expand Down Expand Up @@ -326,7 +336,7 @@ static Value *emit_plt(
const AttributeList &attrs,
CallingConv::ID cc, const char *f_lib, const char *f_name)
{
assert(imaging_mode);
assert(imaging_mode || standalone_aot_mode);
// 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 @@ -599,6 +609,11 @@ static void interpret_symbol_arg(jl_codectx_t &ctx, native_sym_arg_t &out, jl_va
const char *&f_lib = out.f_lib;

jl_value_t *ptr = static_eval(ctx, arg, true);
if (ptr == NULL && standalone_aot_mode && jl_is_expr(arg)) {
jl_expr_t *ex = (jl_expr_t*)arg;
jl_value_t **eargs = (jl_value_t**)jl_array_data(ex->args);
ptr = static_eval(ctx, eargs[1], true);
}
if (ptr == NULL) {
jl_cgval_t arg1 = emit_expr(ctx, arg);
jl_value_t *ptr_ty = arg1.typ;
Expand Down Expand Up @@ -728,7 +743,10 @@ static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t narg

interpret_symbol_arg(ctx, sym, args[1], "cglobal", false);

if (sym.jl_ptr != NULL) {
if (standalone_aot_mode) {
res = jl_Module->getOrInsertGlobal(sym.f_name, lrt);
}
else if (sym.jl_ptr != NULL) {
res = ctx.builder.CreateBitCast(sym.jl_ptr, lrt);
}
else if (sym.fptr != NULL) {
Expand Down Expand Up @@ -1937,6 +1955,11 @@ jl_cgval_t function_sig_t::emit_a_ccall(
jl_error("llvmcall only supports intrinsic calls");
}
}
else if (standalone_aot_mode) {
assert(symarg.f_name != NULL);
llvmf = jl_Module->getOrInsertFunction(symarg.f_name, functype);
cast<Function>(llvmf)->setLinkage(Function::ExternalLinkage);
}
else if (symarg.jl_ptr != NULL) {
null_pointer_check(ctx, symarg.jl_ptr);
Type *funcptype = PointerType::get(functype, 0);
Expand Down Expand Up @@ -1983,6 +2006,7 @@ 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], nargs + sret),
Expand Down Expand Up @@ -2066,3 +2090,4 @@ jl_cgval_t function_sig_t::emit_a_ccall(

return mark_or_box_ccall_result(ctx, result, jlretboxed, rt, unionall_env, static_rt);
}

146 changes: 136 additions & 10 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ static Value *stringConstPtr(IRBuilder<> &irbuilder, const std::string &txt)
StringMap<GlobalVariable*>::iterator pooledval =
stringConstants.insert(std::pair<StringRef, GlobalVariable*>(ctxt, NULL)).first;
StringRef pooledtxt = pooledval->getKey();
if (imaging_mode) {
if (imaging_mode || standalone_aot_mode) {
if (pooledval->second == NULL) {
static int strno = 0;
std::stringstream ssno;
Expand Down Expand Up @@ -288,7 +288,10 @@ static Value *julia_pgv(jl_codectx_t &ctx, const char *cname, void *addr)
if (!gv) {
// otherwise emit a new GlobalVariable for a jl_value_t named "cname"
std::stringstream gvname;
gvname << cname << globalUnique++;
if (standalone_aot_mode)
gvname << cname;
else
gvname << cname << globalUnique++;
// no existing GlobalVariable, create one and store it
gv = new GlobalVariable(*M, T_pjlvalue,
false, GlobalVariable::ExternalLinkage,
Expand Down Expand Up @@ -330,12 +333,120 @@ static Value *julia_pgv(jl_codectx_t &ctx, const char *prefix, jl_sym_t *name, j
return julia_pgv(ctx, fullname, addr);
}

#define CRNAME(x) if (p == (void *)x) return #x

static std::string jl_name_from_type(void *p) {
CRNAME(jl_typeofbottom_type);
CRNAME(jl_datatype_type);
CRNAME(jl_uniontype_type);
CRNAME(jl_unionall_type);
CRNAME(jl_tvar_type);
CRNAME(jl_any_type);
CRNAME(jl_type_type);
CRNAME(jl_typetype_type);
CRNAME(jl_typename_type);
CRNAME(jl_type_typename);
CRNAME(jl_symbol_type);
CRNAME(jl_ssavalue_type);
CRNAME(jl_abstractslot_type);
CRNAME(jl_slotnumber_type);
CRNAME(jl_typedslot_type);
CRNAME(jl_simplevector_type);
CRNAME(jl_tuple_typename);
CRNAME(jl_vecelement_typename);
CRNAME(jl_anytuple_type);
CRNAME(jl_emptytuple_type);
CRNAME(jl_anytuple_type_type);
CRNAME(jl_vararg_type);
CRNAME(jl_vararg_typename);
CRNAME(jl_task_type);
CRNAME(jl_function_type);
CRNAME(jl_builtin_type);
CRNAME(jl_bottom_type);
CRNAME(jl_method_instance_type);
CRNAME(jl_code_info_type);
CRNAME(jl_method_type);
CRNAME(jl_module_type);
CRNAME(jl_abstractarray_type);
CRNAME(jl_densearray_type);
CRNAME(jl_array_type);
CRNAME(jl_array_typename);
CRNAME(jl_weakref_type);
CRNAME(jl_abstractstring_type);
CRNAME(jl_string_type);
CRNAME(jl_errorexception_type);
CRNAME(jl_argumenterror_type);
CRNAME(jl_loaderror_type);
CRNAME(jl_initerror_type);
CRNAME(jl_typeerror_type);
CRNAME(jl_methoderror_type);
CRNAME(jl_undefvarerror_type);
CRNAME(jl_lineinfonode_type);
CRNAME(jl_stackovf_exception);
CRNAME(jl_memory_exception);
CRNAME(jl_readonlymemory_exception);
CRNAME(jl_diverror_exception);
CRNAME(jl_undefref_exception);
CRNAME(jl_interrupt_exception);
CRNAME(jl_boundserror_type);
CRNAME(jl_an_empty_vec_any);
CRNAME(jl_an_empty_string);
CRNAME(jl_bool_type);
CRNAME(jl_char_type);
CRNAME(jl_int8_type);
CRNAME(jl_uint8_type);
CRNAME(jl_int16_type);
CRNAME(jl_uint16_type);
CRNAME(jl_int32_type);
CRNAME(jl_uint32_type);
CRNAME(jl_int64_type);
CRNAME(jl_uint64_type);
CRNAME(jl_float16_type);
CRNAME(jl_float32_type);
CRNAME(jl_float64_type);
CRNAME(jl_floatingpoint_type);
CRNAME(jl_number_type);
CRNAME(jl_void_type);
CRNAME(jl_signed_type);
CRNAME(jl_voidpointer_type);
CRNAME(jl_pointer_type);
CRNAME(jl_ref_type);
CRNAME(jl_pointer_typename);
CRNAME(jl_namedtuple_typename);
CRNAME(jl_namedtuple_type);
CRNAME(jl_array_uint8_type);
CRNAME(jl_array_any_type);
CRNAME(jl_array_symbol_type);
CRNAME(jl_array_int32_type);
CRNAME(jl_expr_type);
CRNAME(jl_globalref_type);
CRNAME(jl_linenumbernode_type);
CRNAME(jl_gotonode_type);
CRNAME(jl_phinode_type);
CRNAME(jl_pinode_type);
CRNAME(jl_phicnode_type);
CRNAME(jl_upsilonnode_type);
CRNAME(jl_quotenode_type);
CRNAME(jl_newvarnode_type);
CRNAME(jl_intrinsic_type);
CRNAME(jl_methtable_type);
CRNAME(jl_typemap_level_type);
CRNAME(jl_typemap_entry_type);
CRNAME(jl_emptysvec);
CRNAME(jl_emptytuple);
CRNAME(jl_true);
CRNAME(jl_false);
CRNAME(jl_nothing);
return "";
}


static GlobalVariable *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
// also, try to give it a nice name for gdb, for easy identification
if (!imaging_mode) {
if (!imaging_mode && !standalone_aot_mode) {
Module *M = jl_Module;
GlobalVariable *gv = new GlobalVariable(
*M, T_pjlvalue, true, GlobalVariable::PrivateLinkage,
Expand All @@ -349,6 +460,11 @@ static Value *literal_pointer_val_slot(jl_codectx_t &ctx, jl_value_t *p)
}
if (jl_is_datatype(p)) {
jl_datatype_t *addr = (jl_datatype_t*)p;
if (standalone_aot_mode) {
std::string name = jl_name_from_type(addr);
if (!name.empty())
return julia_pgv(ctx, name.c_str(), p);
}
// DataTypes are prefixed with a +
return julia_pgv(ctx, "+", addr->name->name, addr->name->module, p);
}
Expand Down Expand Up @@ -445,7 +561,7 @@ static Value *literal_pointer_val(jl_codectx_t &ctx, jl_value_t *p)
{
if (p == NULL)
return V_null;
if (!imaging_mode)
if (!imaging_mode && !standalone_aot_mode)
return literal_static_pointer_val(p);
Value *pgv = literal_pointer_val_slot(ctx, p);
return tbaa_decorate(tbaa_const, maybe_mark_load_dereferenceable(
Expand All @@ -457,7 +573,7 @@ static Value *literal_pointer_val(jl_codectx_t &ctx, jl_binding_t *p)
// emit a pointer to any jl_value_t which will be valid across reloading code
if (p == NULL)
return V_null;
if (!imaging_mode)
if (!imaging_mode && !standalone_aot_mode)
return literal_static_pointer_val(p);
// bindings are prefixed with jl_bnd#
Value *pgv = julia_pgv(ctx, "jl_bnd#", p->name, p->owner, p);
Expand Down Expand Up @@ -498,12 +614,22 @@ static Value *julia_binding_gv(jl_codectx_t &ctx, jl_binding_t *b)
{
// emit a literal_pointer_val to the value field of a jl_binding_t
// binding->value are prefixed with *
if (b && standalone_aot_mode && jl_is_datatype(b->value)) {
std::string name = jl_name_from_type((jl_datatype_t*)b->value);
if (!name.empty())
return julia_binding_gv(ctx, emit_bitcast(ctx,
tbaa_decorate(tbaa_const,
ctx.builder.CreateLoad(T_pjlvalue, julia_pgv(ctx, name.c_str(), b->value))),
T_pprjlvalue));
}
Value *bv;
if (imaging_mode)
if (imaging_mode || standalone_aot_mode) {
bv = emit_bitcast(ctx,
tbaa_decorate(tbaa_const,
ctx.builder.CreateLoad(T_pjlvalue, julia_pgv(ctx, "*", b->name, b->owner, b))),
ctx.builder.CreateLoad(T_pjlvalue, julia_pgv(ctx, "*", b->name, b->owner,
standalone_aot_mode ? b->value : (jl_value_t*)b))),
T_pprjlvalue);
}
else
bv = ConstantExpr::getBitCast(literal_static_pointer_val(b), T_pprjlvalue);
return julia_binding_gv(ctx, bv);
Expand Down Expand Up @@ -869,14 +995,14 @@ static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p)
[&](unsigned idx, jl_datatype_t *jt) { },
p.typ,
counter);
Value *datatype_or_p = (imaging_mode ? Constant::getNullValue(T_ppjlvalue) :
Value *datatype_or_p = (imaging_mode || standalone_aot_mode ? Constant::getNullValue(T_ppjlvalue) :
Constant::getNullValue(T_prjlvalue));
counter = 0;
for_each_uniontype_small(
[&](unsigned idx, jl_datatype_t *jt) {
Value *cmp = ctx.builder.CreateICmpEQ(tindex, ConstantInt::get(T_int8, idx));
Value *ptr;
if (imaging_mode) {
if (imaging_mode || standalone_aot_mode) {
ptr = literal_pointer_val_slot(ctx, (jl_value_t*)jt);
}
else {
Expand All @@ -887,7 +1013,7 @@ static jl_cgval_t emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p)
p.typ,
counter);
auto emit_unboxty = [&] () -> Value* {
if (imaging_mode)
if (imaging_mode || standalone_aot_mode)
return maybe_decay_untracked(
tbaa_decorate(tbaa_const, ctx.builder.CreateLoad(T_pjlvalue, datatype_or_p)));
return datatype_or_p;
Expand Down
17 changes: 17 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ extern JITEventListener *CreateJuliaJITEventListener();
// for image reloading
bool imaging_mode = false;

// for standalone compilation meant for linking with libjulia
bool standalone_aot_mode = false;

// shared llvm state
static LLVMContext jl_LLVMContext;
TargetMachine *jl_TargetMachine;
Expand Down Expand Up @@ -2654,6 +2657,10 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt)
if (!handled) {
Value *r = emit_jlcall(ctx, prepare_call(jlinvoke_func), boxed(ctx, lival), argv, nargs, JLCALL_F2_CC);
result = mark_julia_type(ctx, r, true, rt);
if (standalone_aot_mode) {
jl_printf(JL_STDERR, "Warning: jl_invoke() used for `%s` in `%s`.\n",
jl_symbol_name(jl_globalref_name(args[1])), ctx.name);
}
}
if (result.typ == jl_bottom_type)
CreateTrap(ctx.builder);
Expand Down Expand Up @@ -2698,6 +2705,16 @@ static jl_cgval_t emit_call(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt)
}
}

if (standalone_aot_mode) {
if (jl_is_globalref(args[0])) {
jl_printf(JL_STDERR, "Warning: jl_apply_generic() used for `%s` in `%s`.\n",
jl_symbol_name(jl_globalref_name(args[0])), ctx.name);
}
else if (jl_is_ssavalue(args[0])) {
jl_printf(JL_STDERR, "Warning: jl_apply_generic() used for an SSAValue in `%s`.\n",
ctx.name);
}
}
// emit function and arguments
Value *callval = emit_jlcall(ctx, jlapplygeneric_func, nullptr, argv, nargs, JLCALL_F_CC);
return mark_julia_type(ctx, callval, true, rt);
Expand Down
Loading