Skip to content

Commit

Permalink
generate direct call for invoke when all types are known at compile time
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyichao committed Jan 8, 2015
1 parent fff4f2b commit 7e8c1eb
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ static jl_value_t *expr_type(jl_value_t *e, jl_codectx_t *ctx)
return (jl_value_t*)jl_any_type;
}
type_of_constant:
if (jl_is_datatype(e) || jl_is_uniontype(e) || jl_is_typector(e))
if (jl_is_type(e))
return (jl_value_t*)jl_wrap_Type(e);
return (jl_value_t*)jl_typeof(e);
}
Expand Down
79 changes: 78 additions & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,13 @@ static Value *global_binding_pointer(jl_module_t *m, jl_sym_t *s,
jl_binding_t **pbnd, bool assign);
static Value *emit_checked_var(Value *bp, jl_sym_t *name, jl_codectx_t *ctx, bool isvol=false);
static bool might_need_root(jl_value_t *ex);
static Value *emit_condition(jl_value_t *cond, const std::string &msg, jl_codectx_t *ctx);
static Value *emit_condition(jl_value_t *cond, const std::string &msg,
jl_codectx_t *ctx);
static Value *emit_call_function_object(jl_function_t *f, Value *theF,
Value *theFptr,
bool specialized,
jl_value_t **args, size_t nargs,
jl_codectx_t *ctx);

// NoopType
static Type *NoopType;
Expand Down Expand Up @@ -1757,6 +1763,39 @@ static Value *emit_f_is(jl_value_t *rt1, jl_value_t *rt2,
return answer;
}

static int
get_invoke_types(jl_value_t *a, jl_value_t **ptemp)
{
if (jl_is_type_type(a)) {
jl_value_t *types = jl_tparam0(a);
if (jl_is_tuple(types)) {
*ptemp = types;
return 1;
}
return 0;
} else if (jl_is_tuple(a)) {
jl_tuple_t *tt = (jl_tuple_t*)a;
int tlen = jl_tuple_len(tt);
jl_tuple_t *types = jl_alloc_tuple(tlen);
*ptemp = (jl_value_t*)types;
for(int i = 0;i < tlen;i++) {
jl_value_t *el = jl_tupleref(tt, i);
jl_value_t *var_type;
if (jl_is_type_type(el)) {
jl_tupleset(types, i, jl_tparam0(el));
} else if (i == tlen - 1 && jl_is_vararg_type(el) &&
jl_is_type_type((var_type = jl_tparam0(el)))) {
jl_tupleset(types, i, jl_wrap_vararg(jl_tparam0(var_type)));
} else {
*ptemp = NULL;
return 0;
}
}
return 1;
}
return 0;
}

static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs,
jl_codectx_t *ctx,
Value **theFptr, jl_function_t **theF,
Expand Down Expand Up @@ -2375,6 +2414,44 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs,
}
}
}
else if (f->fptr == &jl_f_invoke && nargs >= 2 &&
expr_type(args[1], ctx) == (jl_value_t*)jl_function_type) {
f = (jl_function_t*)static_eval(args[1], ctx, true);
rt1 = (jl_value_t*)f;
if (!f || !jl_is_gf(f)) {
JL_GC_POP();
return NULL;
}
jl_value_t *type_types = expr_type(args[2], ctx);
rt2 = type_types;
if (!get_invoke_types(type_types, &rt3)) {
JL_GC_POP();
return NULL;
}
rt2 = NULL;
jl_tuple_t *tt = call_arg_types(&args[3], nargs - 2, ctx);
if (tt == NULL) {
JL_GC_POP();
return NULL;
}
rt2 = (jl_value_t*)tt;
jl_function_t *mfunc =
jl_gf_invoke_get_specialization(f, (jl_tuple_t*)rt3, tt);
JL_GC_POP();
if (mfunc == NULL) {
return NULL;
}
assert(mfunc->linfo->functionObject != NULL);
emit_expr(args[2], ctx);
Value *_theF = literal_pointer_val((jl_value_t*)mfunc);
Value *_theFptr = (Value*)mfunc->linfo->functionObject;
if (mfunc->linfo->cFunctionObject == NULL) {
jl_cstyle_compile(mfunc);
}
Value *result = emit_call_function_object(mfunc, _theF, _theFptr, true,
args + 2, nargs - 2, ctx);
return result;
}
// TODO: other known builtins
JL_GC_POP();
return NULL;
Expand Down
61 changes: 61 additions & 0 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1671,6 +1671,67 @@ DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_function_t *gf, jl_tuple_t *types)
return (jl_value_t*)m;
}

jl_function_t*
jl_gf_invoke_get_specialization(jl_function_t *gf, jl_tuple_t *types,
jl_tuple_t *tt)
{
assert(jl_is_gf(gf));
jl_methtable_t *mt = jl_gf_mtable(gf);
jl_methlist_t *m = (jl_methlist_t*)jl_gf_invoke_lookup(gf, types);

if ((jl_value_t*)m == jl_nothing) {
return NULL;
}

// now we have found the matching definition.
// next look for or create a specialization of this definition.

jl_function_t *mfunc;
if (m->invokes == JL_NULL) {
mfunc = jl_bottom_func;
} else {
mfunc = jl_method_table_assoc_exact_by_type(m->invokes, tt);
}
if (mfunc != jl_bottom_func) {
return mfunc;
}

jl_tuple_t *tpenv = jl_null;
jl_tuple_t *newsig = NULL;
JL_GC_PUSH2(&tpenv, &newsig);

if (m->invokes == JL_NULL) {
m->invokes = new_method_table(mt->name);
// this private method table has just this one definition
jl_method_list_insert(&m->invokes->defs, m->sig, m->func,
m->tvars, 0, 0);
}
newsig = (jl_tuple_t*)m->sig;

if (m->tvars != jl_null) {
jl_value_t *ti =
lookup_match((jl_value_t*)tt, (jl_value_t*)m->sig, &tpenv, m->tvars);
assert(ti != (jl_value_t*)jl_bottom_type);
(void)ti;
// don't bother computing this if no arguments are tuples
size_t i;
for (i = 0;i < jl_tuple_len(tt);i++) {
if (jl_is_tuple(jl_tupleref(tt,i))) {
break;
}
}
if (i < jl_tuple_len(tt)) {
newsig =
(jl_tuple_t*)jl_instantiate_type_with((jl_value_t*)m->sig,
&jl_tupleref(tpenv, 0),
jl_tuple_len(tpenv) / 2);
}
}
mfunc = cache_method(m->invokes, tt, m->func, newsig, tpenv);
JL_GC_POP();
return mfunc;
}

// invoke()
// this does method dispatch with a set of types to match other than the
// types of the actual arguments. this means it sometimes does NOT call the
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ void jl_type_infer(jl_lambda_info_t *li, jl_tuple_t *argtypes,
jl_function_t *jl_method_lookup_by_type(jl_methtable_t *mt, jl_tuple_t *types,
int cache, int inexact);
jl_function_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t nargs, int cache);
jl_value_t *jl_gf_invoke_lookup(jl_function_t *gf, jl_tuple_t *types);
jl_value_t *jl_gf_invoke(jl_function_t *gf, jl_tuple_t *types,
jl_value_t **args, size_t nargs);

Expand Down
3 changes: 3 additions & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ DLLEXPORT void jl_read_sonames(void);
jl_lambda_info_t *jl_add_static_parameters(jl_lambda_info_t *l, jl_tuple_t *sp);
jl_function_t *jl_get_specialization(jl_function_t *f, jl_tuple_t *types);
jl_function_t *jl_module_get_initializer(jl_module_t *m);
jl_function_t *jl_gf_invoke_get_specialization(jl_function_t *gf,
jl_tuple_t *types,
jl_tuple_t *tt);
void jl_generate_fptr(jl_function_t *f);
void jl_fptr_to_llvm(void *fptr, jl_lambda_info_t *lam, int specsig);

Expand Down

0 comments on commit 7e8c1eb

Please sign in to comment.