Skip to content

Commit

Permalink
use interpreter when possible in --compile=no mode
Browse files Browse the repository at this point in the history
make `JULIACODEGEN=none` builds work again
  • Loading branch information
JeffBezanson committed Nov 7, 2017
1 parent 00dafe2 commit 5f45c59
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 60 deletions.
3 changes: 2 additions & 1 deletion base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3692,7 +3692,8 @@ function finish(me::InferenceState)
end
end

if !already_inferred
# don't store inferred code if we've decided to interpret this function
if !already_inferred && me.linfo.jlcall_api != 4
const_flags = (me.const_ret) << 1 | me.const_api
if me.const_ret
if isa(me.bestguess, Const)
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ PUBLIC_HEADERS += $(LIBUV_INC)/uv*
endif
PUBLIC_HEADER_TARGETS := $(addprefix $(build_includedir)/julia/,$(notdir $(PUBLIC_HEADERS)))

ifeq ($(JULIACODEGEN),LLVM)
# In LLVM < 3.4, --ldflags includes both options and libraries, so use it both before and after --libs
# In LLVM >= 3.4, --ldflags has only options, and --system-libs has the libraries.
ifneq ($(USE_LLVM_SHLIB),1)
Expand All @@ -95,6 +96,7 @@ else
LLVMLINK += $(shell $(LLVM_CONFIG_HOST) --ldflags) -lLLVM
FLAGS += -DLLVM_SHLIB
endif # USE_LLVM_SHLIB == 1
endif

COMMON_LIBS := -L$(build_shlibdir) -L$(build_libdir) $(LIBUV) $(LIBUTF8PROC) $(NO_WHOLE_ARCHIVE) $(LLVMLINK) $(OSLIBS)
DEBUG_LIBS := $(WHOLE_ARCHIVE) $(BUILDDIR)/flisp/libflisp-debug.a $(WHOLE_ARCHIVE) $(BUILDDIR)/support/libsupport-debug.a $(COMMON_LIBS)
Expand Down
31 changes: 24 additions & 7 deletions src/anticodegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,22 @@ int globalUnique = 0;

#define UNAVAILABLE { jl_errorf("%s: not available in this build of Julia", __func__); }

void jl_dump_native(const char *bc_fname, const char *obj_fname, const char *sysimg_data, size_t sysimg_len) UNAVAILABLE
void jl_dump_objfile(char *fname, int jit_model, const char *sysimg_data, size_t sysimg_len) UNAVAILABLE
void jl_dump_native(const char *bc_fname, const char *unopt_bc_fname, const char *obj_fname, const char *sysimg_data, size_t sysimg_len) UNAVAILABLE
int32_t jl_get_llvm_gv(jl_value_t *p) UNAVAILABLE
void jl_write_malloc_log(void) UNAVAILABLE
void jl_write_coverage_data(void) UNAVAILABLE

JL_DLLEXPORT void jl_clear_malloc_data(void) UNAVAILABLE
JL_DLLEXPORT void jl_extern_c(jl_function_t *f, jl_value_t *rt, jl_value_t *argt, char *name) UNAVAILABLE
JL_DLLEXPORT void *jl_function_ptr(jl_function_t *f, jl_value_t *rt, jl_value_t *argt) UNAVAILABLE
JL_DLLEXPORT const jl_value_t *jl_dump_function_asm(void *f, int raw_mc) UNAVAILABLE
JL_DLLEXPORT const jl_value_t *jl_dump_function_asm(void *f, int raw_mc, const char* asm_variant) UNAVAILABLE
JL_DLLEXPORT const jl_value_t *jl_dump_function_ir(void *f, uint8_t strip_ir_metadata, uint8_t dump_module) UNAVAILABLE

JL_DLLEXPORT void *jl_LLVMCreateDisasm(const char *TripleName, void *DisInfo, int TagType, void *GetOpInfo, void *SymbolLookUp) UNAVAILABLE
JL_DLLEXPORT size_t jl_LLVMDisasmInstruction(void *DC, uint8_t *Bytes, uint64_t BytesSize, uint64_t PC, char *OutString, size_t OutStringSize) UNAVAILABLE

int32_t jl_assign_functionID(const char *fname) UNAVAILABLE

void jl_init_codegen(void) { }
void jl_fptr_to_llvm(jl_fptr_t fptr, jl_method_instance_t *lam, int specsig)
{
Expand All @@ -42,13 +43,29 @@ void jl_register_fptrs(uint64_t sysimage_base, const struct _jl_sysimg_fptrs_t *
(void)sysimage_base; (void)fptrs; (void)linfos; (void)n;
}

void jl_compile_linfo(jl_method_instance_t *li) { }
jl_llvm_functions_t jl_compile_linfo(jl_method_instance_t **pli, jl_code_info_t *src, size_t world, const jl_cgparams_t *params)
{
jl_method_instance_t *li = *pli;
jl_llvm_functions_t decls = {};

if (jl_is_method(li->def.method)) {
jl_printf(JL_STDERR, "code missing for ");
jl_static_show(JL_STDERR, (jl_value_t*)li);
jl_printf(JL_STDERR, " : sysimg may not have been built with --compile=all\n");
}
else {
jl_printf(JL_STDERR, "top level expression cannot be compiled in this build of Julia");
}
return decls;
}

jl_value_t *jl_interpret_call(jl_method_instance_t *lam, jl_value_t **args, uint32_t nargs);
void jl_generate_fptr(jl_method_instance_t *li)
jl_generic_fptr_t jl_generate_fptr(jl_method_instance_t *li, const char *F, size_t world)
{
li->fptr = (jl_fptr_t)&jl_interpret_call;
li->jlcall_api = JL_API_INTERPRETED;
jl_generic_fptr_t fptr;
fptr.fptr = (jl_fptr_t)&jl_interpret_call;
fptr.jlcall_api = JL_API_INTERPRETED;
return fptr;
}

JL_DLLEXPORT uint32_t jl_get_LLVM_VERSION(void)
Expand Down
20 changes: 3 additions & 17 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,22 +247,6 @@ static DIDerivedType *jl_ppvalue_dillvmt;
static DISubroutineType *jl_di_func_sig;
static DISubroutineType *jl_di_func_null_sig;

extern "C"
int32_t jl_jlcall_api(const char *fname)
{
// give the function an index in the constant lookup table
if (fname == NULL)
return 0;
StringRef Name(fname);
if (Name.startswith("japi3_")) // jlcall abi 3 from JIT
return JL_API_WITH_PARAMETERS;
assert(Name.startswith("japi1_") || // jlcall abi 1 from JIT
Name.startswith("jsys1_") || // jlcall abi 1 from sysimg
Name.startswith("jlcall_") || // jlcall abi 1 from JIT wrapping a specsig method
Name.startswith("jlsysw_")); // jlcall abi 1 from sysimg wrapping a specsig method
return JL_API_GENERIC;
}


// constants
static Constant *V_null;
Expand Down Expand Up @@ -1563,7 +1547,9 @@ void *jl_get_llvmf_decl(jl_method_instance_t *linfo, size_t world, bool getwrapp
}

// compile this normally
jl_llvm_functions_t decls = jl_compile_for_dispatch(&linfo, world);
if (linfo->inferred == NULL)
linfo->inferred = jl_nothing;
jl_llvm_functions_t decls = jl_compile_linfo(&linfo, NULL, world, &jl_default_cgparams);

if (decls.functionObject == NULL && linfo->jlcall_api == JL_API_CONST && jl_is_method(linfo->def.method)) {
// normally we don't generate native code for these functions, so need an exception here
Expand Down
13 changes: 10 additions & 3 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1680,9 +1680,16 @@ jl_llvm_functions_t jl_compile_for_dispatch(jl_method_instance_t **pli, size_t w
}
}
if (jl_options.compile_enabled == JL_OPTIONS_COMPILE_OFF) {
jl_printf(JL_STDERR, "code missing for ");
jl_static_show(JL_STDERR, (jl_value_t*)li);
jl_printf(JL_STDERR, " : sysimg may not have been built with --compile=all\n");
jl_code_info_t *src = jl_code_for_interpreter(li);
if (!jl_code_requires_compiler(src)) {
li->inferred = (jl_value_t*)src;
jl_gc_wb(li, src);
li->functionObjectsDecls.functionObject = NULL;
li->functionObjectsDecls.specFunctionObject = NULL;
li->fptr = (jl_fptr_t)&jl_interpret_call;
li->jlcall_api = JL_API_INTERPRETED;
return li->functionObjectsDecls;
}
}
}
jl_llvm_functions_t decls = li->functionObjectsDecls;
Expand Down
44 changes: 25 additions & 19 deletions src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -668,36 +668,42 @@ SECT_INTERP static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s
return NULL;
}

struct jl_interpret_call_args {
jl_method_instance_t *lam;
jl_value_t **args;
uint32_t nargs;
};

SECT_INTERP CALLBACK_ABI void *jl_interpret_call_callback(interpreter_state *s, void *vargs)
jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *lam)
{
struct jl_interpret_call_args *args =
(struct jl_interpret_call_args *)vargs;
jl_code_info_t *src = (jl_code_info_t*)args->lam->inferred;
jl_code_info_t *src = (jl_code_info_t*)lam->inferred;
JL_GC_PUSH1(&src);
if (!src || (jl_value_t*)src == jl_nothing) {
if (args->lam->def.method->source) {
src = (jl_code_info_t*)args->lam->def.method->source;
if (lam->def.method->source) {
src = (jl_code_info_t*)lam->def.method->source;
}
else {
assert(args->lam->def.method->generator);
src = jl_code_for_staged(args->lam);
args->lam->inferred = (jl_value_t*)src;
jl_gc_wb(args->lam, src);
assert(lam->def.method->generator);
src = jl_code_for_staged(lam);
}
}
if (src && (jl_value_t*)src != jl_nothing) {
src = jl_uncompress_ast(args->lam->def.method, (jl_array_t*)src);
args->lam->inferred = (jl_value_t*)src;
jl_gc_wb(args->lam, src);
src = jl_uncompress_ast(lam->def.method, (jl_array_t*)src);
}
if (!src || !jl_is_code_info(src)) {
jl_error("source missing for method called in interpreter");
}
JL_GC_POP();
return src;
}

struct jl_interpret_call_args {
jl_method_instance_t *lam;
jl_value_t **args;
uint32_t nargs;
};

SECT_INTERP CALLBACK_ABI void *jl_interpret_call_callback(interpreter_state *s, void *vargs)
{
struct jl_interpret_call_args *args =
(struct jl_interpret_call_args *)vargs;
jl_code_info_t *src = jl_code_for_interpreter(args->lam);
args->lam->inferred = (jl_value_t*)src;
jl_gc_wb(args->lam, src);

jl_array_t *stmts = src->code;
assert(jl_typeis(stmts, jl_array_any_type));
Expand Down
3 changes: 3 additions & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,9 @@ jl_llvm_functions_t jl_compile_linfo(
const jl_cgparams_t *params);
jl_llvm_functions_t jl_compile_for_dispatch(jl_method_instance_t **li, size_t world);
JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types);
jl_value_t *jl_interpret_call(jl_method_instance_t *lam, jl_value_t **args, uint32_t nargs);
jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *lam);
int jl_code_requires_compiler(jl_code_info_t *src);
jl_code_info_t *jl_new_code_info_from_ast(jl_expr_t *ast);

STATIC_INLINE jl_value_t *jl_compile_method_internal(jl_generic_fptr_t *fptr,
Expand Down
14 changes: 14 additions & 0 deletions src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,20 @@ static uintptr_t jl_fptr_id(void *fptr)
return *(uintptr_t*)pbp;
}

int32_t jl_jlcall_api(const char *fname)
{
// give the function an index in the constant lookup table
if (fname == NULL)
return 0;
if (!strncmp(fname, "japi3_", 6)) // jlcall abi 3 from JIT
return JL_API_WITH_PARAMETERS;
assert(!strncmp(fname, "japi1_", 6) || // jlcall abi 1 from JIT
!strncmp(fname, "jsys1_", 6) || // jlcall abi 1 from sysimg
!strncmp(fname, "jlcall_", 7) || // jlcall abi 1 from JIT wrapping a specsig method
!strncmp(fname, "jlsysw_", 7)); // jlcall abi 1 from sysimg wrapping a specsig method
return JL_API_GENERIC;
}


#define jl_serialize_value(s, v) jl_serialize_value_(s,(jl_value_t*)(v))
static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v);
Expand Down
41 changes: 28 additions & 13 deletions src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,12 +313,25 @@ int jl_has_intrinsics(jl_value_t *v)
return 0;
}

int jl_code_requires_compiler(jl_code_info_t *src)
{
jl_array_t *body = src->code;
assert(jl_typeis(body, jl_array_any_type));
size_t i;
for(i=0; i < jl_array_len(body); i++) {
jl_value_t *stmt = jl_array_ptr_ref(body,i);
if (jl_has_intrinsics(stmt))
return 1;
}
return 0;
}

// heuristic for whether a top-level input should be evaluated with
// the compiler or the interpreter.
static int jl_eval_with_compiler_p(jl_code_info_t *src, jl_array_t *body, int compileloops, jl_module_t *m)
{
size_t i, maxlabl=0;
// compile if there are backwards branches
// compile if there are backwards branches and compiler is enabled
for(i=0; i < jl_array_len(body); i++) {
jl_value_t *stmt = jl_array_ptr_ref(body,i);
if (jl_is_labelnode(stmt)) {
Expand All @@ -330,23 +343,25 @@ static int jl_eval_with_compiler_p(jl_code_info_t *src, jl_array_t *body, int co
char *labls = (char*)alloca(sz); memset(labls,0,sz);
for(i=0; i < jl_array_len(body); i++) {
jl_value_t *stmt = jl_array_ptr_ref(body,i);
if (jl_is_labelnode(stmt)) {
int l = jl_labelnode_label(stmt);
labls[l/8] |= (1<<(l&7));
}
else if (compileloops && jl_is_gotonode(stmt)) {
int l = jl_gotonode_label(stmt);
if (labls[l/8]&(1<<(l&7))) {
return 1;
if (jl_options.compile_enabled != JL_OPTIONS_COMPILE_OFF) {
if (jl_is_labelnode(stmt)) {
int l = jl_labelnode_label(stmt);
labls[l/8] |= (1<<(l&7));
}
}
else if (jl_is_expr(stmt)) {
if (compileloops && ((jl_expr_t*)stmt)->head==goto_ifnot_sym) {
int l = jl_unbox_long(jl_exprarg(stmt,1));
else if (compileloops && jl_is_gotonode(stmt)) {
int l = jl_gotonode_label(stmt);
if (labls[l/8]&(1<<(l&7))) {
return 1;
}
}
else if (jl_is_expr(stmt)) {
if (compileloops && ((jl_expr_t*)stmt)->head==goto_ifnot_sym) {
int l = jl_unbox_long(jl_exprarg(stmt,1));
if (labls[l/8]&(1<<(l&7))) {
return 1;
}
}
}
}
if (jl_has_intrinsics(stmt))
return 1;
Expand Down

0 comments on commit 5f45c59

Please sign in to comment.