From: Jérémie Astor Date: Sat, 22 May 2021 22:47:33 +0000 (+0200) Subject: :art: Introduce inlining X-Git-Tag: nightly~626 X-Git-Url: http://10.10.0.4:5575/?a=commitdiff_plain;h=f22c021aa349dfa2e938a8911f51ab2cbddf63cb;p=gwion.git :art: Introduce inlining --- diff --git a/include/emit.h b/include/emit.h index f48db3ab..c64154a7 100644 --- a/include/emit.h +++ b/include/emit.h @@ -36,6 +36,8 @@ struct Emitter_ { struct Gwion_ *gwion; struct EmitterInfo_ *info; struct Vector_ stack; + m_uint this_offset; // reset + m_uint vararg_offset; // reset }; ANEW ANN Emitter new_emitter(MemPool); diff --git a/include/env/context.h b/include/env/context.h index a302f04c..7f8e964a 100644 --- a/include/env/context.h +++ b/include/env/context.h @@ -6,6 +6,7 @@ struct Context_ { m_str name; Ast tree; uint16_t ref; + uint16_t weight; bool error; bool global; }; diff --git a/include/env/env.h b/include/env/env.h index 85ff9565..c9372b11 100644 --- a/include/env/env.h +++ b/include/env/env.h @@ -14,6 +14,7 @@ struct Env_Scope_ { struct Vector_ effects; uint16_t depth; bool in_try; + bool in_loop; }; typedef struct Env_ { diff --git a/include/env/func.h b/include/env/func.h index 90e76c1a..3ff76fc2 100644 --- a/include/env/func.h +++ b/include/env/func.h @@ -8,6 +8,7 @@ enum fflag { fflag_tmpl = 1 << 3, fflag_valid = 1 << 4, fflag_return = 1 << 5, + fflag_recurs = 1 << 6, } __attribute__((packed)); struct Func_ { @@ -16,9 +17,11 @@ struct Func_ { Value value_ref; Func next; m_str name; - size_t vt_index; - struct Map_ upvalues; + float inline_mult; + uint16_t weight; uint16_t ref; + struct Map_ upvalues; + uint16_t vt_index; ae_flag flag; enum fflag fflag; }; diff --git a/include/env/type.h b/include/env/type.h index 109dd29d..c0777f44 100644 --- a/include/env/type.h +++ b/include/env/type.h @@ -45,6 +45,7 @@ struct Type_ { size_t array_depth; struct Vector_ effects; // pre-ctor effects uint16_t ref; + uint16_t weight; ae_flag flag; enum tflag tflag; }; diff --git a/include/parse.h b/include/parse.h index 3a851511..98a6166e 100644 --- a/include/parse.h +++ b/include/parse.h @@ -76,4 +76,18 @@ ANN m_bool check_subscripts(const Env, const Array_Sub, const m_bool is_decl); ANN m_bool check_implicit(const Env env, const Exp e, const Type t); ANN m_bool ensure_traverse(const Env env, const Type t); ANN m_bool check_traverse_fdef(const Env env, const Func_Def fdef); + +ANN static inline void env_weight(const Env env, const uint16_t weight) { + if(env->func) + env->func->weight += weight; + else if(env->class_def) + env->class_def->weight += weight; + else if(env->context) + env->context->weight += weight; +} + +ANN static inline void env_inline_mult(const Env env, const float mult) { + if(env->func) + env->func->inline_mult += mult; +} #endif diff --git a/src/emit/emit.c b/src/emit/emit.c index 1b3f5825..f62afc69 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -958,7 +958,117 @@ ANN static m_bool prepare_call(const Emitter emit, const Exp_Call* exp_call) { return emit_exp(emit, exp_call->func); } -ANN static m_bool emit_exp_call(const Emitter emit, const Exp_Call* exp_call) { +ANN static inline void emit_return_pc(const Emitter emit, const m_uint val) { + LOOP_OPTIM + for(m_uint i = vector_size(&emit->code->stack_return) + 1; --i; ) { + const Instr instr = (Instr)vector_at(&emit->code->stack_return, i-1); + instr->m_val = val; + } +} + +ANN static inline void pop_exp(const Emitter emit, Exp e); + +ANN static inline bool check_inline(const Emitter emit, const Func f) { + const uint16_t caller_size = emit->env->func ? emit->env->func->weight : + emit->env->class_def ? emit->env->class_def->weight : + emit->env->context ? emit->env->context->weight : 0; + const float threshold = caller_size * f->inline_mult; + return f->weight < threshold; +} + +ANN static inline bool member_inlinable(const Func f, const Exp e) { + if(fflag(f, fflag_recurs)) + return false; + const Type owner_class =f->value_ref->from->owner_class; + if(!owner_class) + return true; + return GET_FLAG(owner_class, final) || + GET_FLAG(f->def->base, final) || + (e->exp_type == ae_exp_dot && e->d.exp_dot.base->exp_type == ae_exp_cast); +} + +ANN static inline Func is_inlinable(const Emitter emit, const Exp_Call *exp_call) { + const Type ftype = exp_call->func->type; + if(isa(ftype, emit->gwion->type[et_function]) < 0 || is_fptr(emit->gwion, ftype) || + !ftype->info->func->code || ftype->info->func->code->builtin) + return false; + const Func f = ftype->info->func; + return (member_inlinable(f, exp_call->func) && check_inline(emit, f)) ? + f : NULL; +} + +ANN static inline void inline_args_ini(const Emitter emit, const Func f, const Vector v) { + const m_uint start_offset = emit_code_offset(emit); + Arg_List arg = f->def->base->args; + while(arg) { + const Value value = arg->var_decl->value; + vector_add(v, value->from->offset); + value->from->offset = emit_local(emit, value->type); + nspc_add_value(emit->env->curr, arg->var_decl->xid, value); + arg = arg->next; + } + if(fbflag(f->def->base, fbflag_variadic)) + emit->vararg_offset = emit_local(emit, emit->gwion->type[et_int]) + SZ_INT; + regpop(emit, f->code->stack_depth); + const Instr cpy = emit_add_instr(emit, Reg2Mem4); + cpy->m_val2 = f->code->stack_depth; + cpy->m_val = start_offset; +} + +ANN static inline void inline_args_end(const Func f, const Vector v) { + Arg_List arg = f->def->base->args; + m_uint i = 0; + while(arg) { + const Value value = arg->var_decl->value; + value->from->offset = vector_at(v, i++); + arg = arg->next; + } +} + +ANN static m_bool scoped_stmt(const Emitter emit, const Stmt stmt, const m_bool pop); +ANN static inline m_bool inline_body(const Emitter emit, const Func f) { + struct Vector_ v = { .ptr=emit->code->stack_return.ptr }; + vector_init(&emit->code->stack_return); + nspc_push_value(emit->gwion->mp, emit->env->curr); + const m_bool ret = scoped_stmt(emit, f->def->d.code, 1); + nspc_pop_value(emit->gwion->mp, emit->env->curr); + emit_return_pc(emit, emit_code_size(emit)); + vector_release(&emit->code->stack_return); + emit->code->stack_return.ptr = v.ptr; + return ret; +} + +ANN static inline m_bool inline_run(const Emitter emit, const Func f) { + struct Vector_ arg_offset; + vector_init(&arg_offset); + const uint16_t this_offset = emit->this_offset; + const uint16_t vararg_offset = emit->vararg_offset; + inline_args_ini(emit, f, &arg_offset); + const m_bool ret = inline_body(emit, f); + emit->this_offset = this_offset; + emit->vararg_offset = vararg_offset; + inline_args_end(f, &arg_offset); + vector_release(&arg_offset); + return ret; +} + +ANN static inline m_bool emit_inline(const Emitter emit, const Func f, const Exp_Call *exp_call) { + if(!f->weight) + return GW_OK; + if(f->value_ref->from->owner_class && vflag(f->value_ref, vflag_member)) { + CHECK_BB(emit_exp(emit, exp_call->func->d.exp_dot.base)); + emit->this_offset = emit_local(emit, emit->gwion->type[et_int]); + } + CHECK_BB(emit_func_args(emit, exp_call)); + return inline_run(emit, f); +} + +ANN static m_bool _emit_exp_call(const Emitter emit, const Exp_Call* exp_call) { +#ifndef GWION_NOINLINE + const Func f = is_inlinable(emit, exp_call); + if(f) + return emit_inline(emit, f, exp_call); +#endif CHECK_BB(prepare_call(emit, exp_call)); const Type t = actual_type(emit->gwion, exp_call->func->type); if(isa(t, emit->gwion->type[et_function]) > 0) @@ -968,12 +1078,18 @@ ANN static m_bool emit_exp_call(const Emitter emit, const Exp_Call* exp_call) { .data=(uintptr_t)exp_call, .pos=exp_self(exp_call)->pos }; CHECK_BB(op_emit(emit, &opi)); } + return GW_OK; +} + +ANN static m_bool emit_exp_call(const Emitter emit, const Exp_Call* exp_call) { const Exp e = exp_self(exp_call); + if(exp_getvar(e)) + regpush(emit, SZ_INT); + CHECK_BB(_emit_exp_call(emit, exp_call)); if(exp_getvar(e)) { - regpop(emit, exp_self(exp_call)->type->size - SZ_INT); + regpop(emit, exp_self(exp_call)->type->size); const Instr instr = emit_add_instr(emit, Reg2RegAddr); instr->m_val = -SZ_INT; - instr->m_val2 = -SZ_INT; } else if(isa(exp_call->func->type, emit->gwion->type[et_function]) < 0 && tflag(e->type, tflag_struct)) regpop(emit, SZ_INT); @@ -1202,6 +1318,9 @@ ANN static Instr emit_call(const Emitter emit, const Func f) { } ANN m_bool emit_exp_call1(const Emitter emit, const Func f) { + const m_uint this_offset = emit->this_offset; + const m_uint vararg_offset = emit->vararg_offset; + emit->this_offset = 0; const int tmpl = fflag(f, fflag_tmpl); if(!f->code || (fflag(f, fflag_ftmpl) && !vflag(f->value_ref, vflag_builtin))) { if(tmpl && !is_fptr(emit->gwion, f->value_ref->type)) { @@ -1267,6 +1386,8 @@ ANN m_bool emit_exp_call1(const Emitter emit, const Func f) { const Instr instr = emit_call(emit, f); instr->m_val = f->def->base->ret_type->size; instr->m_val2 = offset; + emit->this_offset = this_offset; + emit->vararg_offset = vararg_offset; return GW_OK; } @@ -1879,7 +2000,8 @@ ANN static m_bool _emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt, const m_uint offset = emit_local(emit, emit->gwion->type[et_int]); if(stmt->idx) { const Instr instr = emit_add_instr(emit, MemSetImm); - instr->m_val = stmt->idx->v->from->offset = emit_local(emit, emit->gwion->type[et_int]); + instr->m_val = emit_local(emit, emit->gwion->type[et_int]); + stmt->idx->v->from->offset = offset; } CHECK_BB(emit_exp_pop_next(emit, stmt->cond)); regpop(emit, SZ_INT); @@ -2224,11 +2346,7 @@ ANN static void emit_func_def_ensure(const Emitter emit, const Func_Def fdef) { ANN static m_bool emit_func_def_return(const Emitter emit) { const m_uint val = emit_code_size(emit); CHECK_BB(emit_defers(emit)); - LOOP_OPTIM - for(m_uint i = vector_size(&emit->code->stack_return) + 1; --i; ) { - const Instr instr = (Instr)vector_at(&emit->code->stack_return, i-1); - instr->m_val = val; - } + emit_return_pc(emit, val); vector_clear(&emit->code->stack_return); if(emit->info->memoize && fflag(emit->env->func, fflag_pure)) { const Instr instr = emit_add_instr(emit, MemoizeStore); @@ -2483,6 +2601,10 @@ ANN static VM_Code emit_free_stack(const Emitter emit) { ANN m_bool emit_ast(const Env env, Ast ast) { const Emitter emit = env->gwion->emit; emit->info->memoize = 0; + emit->info->unroll = 0; + emit->info->line = 0; + emit->this_offset = 0; + emit->vararg_offset = 0; emit->code = new_code(emit, emit->env->name); emit_push_scope(emit); const m_bool ret = emit_ast_inner(emit, ast); diff --git a/src/env/func.c b/src/env/func.c index 893eee7e..9855ff42 100644 --- a/src/env/func.c +++ b/src/env/func.c @@ -19,6 +19,7 @@ ANN Func new_func(MemPool p, const m_str name, const Func_Def def) { Func func = mp_calloc(p, Func); func->name = name; func->def = def; + func->inline_mult = 1.0; func->ref = 1; return func; } diff --git a/src/lib/instr.c b/src/lib/instr.c index 41f83473..ae30ed7f 100644 --- a/src/lib/instr.c +++ b/src/lib/instr.c @@ -102,7 +102,7 @@ INSTR(DotTmpl) { const Func f = nspc_lookup_func0(t->nspc, insert_symbol(emit->env->gwion->st, str)); if(f) { if(!f->code) - break; + continue; if(vflag(f->value_ref, vflag_member)) shred->reg += SZ_INT; *(VM_Code*)(shred->reg-SZ_INT) = f->code; diff --git a/src/lib/lib_func.c b/src/lib/lib_func.c index 8fb80a5c..08f622d4 100644 --- a/src/lib/lib_func.c +++ b/src/lib/lib_func.c @@ -108,7 +108,7 @@ ANN static bool fptr_effects(const Env env, struct FptrInfo *info) { if(!info->lhs->def->base->effects.ptr) return true; if(!info->rhs->def->base->effects.ptr) { - puts("too many effects"); + gwerr_secondary("too many effects", env->name, info->pos); return false; } const Vector lhs = &info->lhs->def->base->effects; @@ -486,8 +486,9 @@ static OP_EMIT(opem_op_impl) { struct Implicit *impl = (struct Implicit*)data; const Func_Def fdef = impl->e->type->info->func->def; const m_bool ret = emit_func_def(emit, fdef); - const Instr instr = emit_add_instr(emit, RegPushImm); + const Instr instr = emit_add_instr(emit, RegSetImm); instr->m_val = (m_uint)fdef->base->func->code; + instr->m_val2 = -SZ_INT; return ret; } diff --git a/src/lib/object.c b/src/lib/object.c index 69dd9f41..4afab57b 100644 --- a/src/lib/object.c +++ b/src/lib/object.c @@ -106,7 +106,9 @@ static ID_EMIT(opem_this) { instr->m_val2 = emit->env->class_def->size; return (Instr)GW_OK; } - return emit_add_instr(emit, RegPushMem); + const Instr instr = emit_add_instr(emit, RegPushMem); + instr->m_val = emit->this_offset; + return instr; } GWION_IMPORT(object) { diff --git a/src/lib/vararg.c b/src/lib/vararg.c index 938b7622..f418b88a 100644 --- a/src/lib/vararg.c +++ b/src/lib/vararg.c @@ -145,7 +145,7 @@ static ID_CHECK(idck_vararg) { static ID_EMIT(idem_vararg) { const Instr instr = emit_add_instr(emit, RegPushMem); - instr->m_val = emit->code->stack_depth - SZ_INT; + instr->m_val = emit->vararg_offset + emit->code->stack_depth - SZ_INT; return instr; } diff --git a/src/parse/check.c b/src/parse/check.c index 27e4ead5..4f63a818 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -793,6 +793,8 @@ ANN Type check_exp_call1(const Env env, Exp_Call *const exp) { } exp->func->type = func->value_ref->type; call_add_effect(env, func, exp->func->pos); + if(func == env->func) + set_fflag(env->func, fflag_recurs); return func->def->base->ret_type; } const loc_t pos = exp->args ? exp->args->pos : exp->func->pos; @@ -999,6 +1001,7 @@ DECL_EXP_FUNC(check, Type, Env) ANN Type check_exp(const Env env, const Exp exp) { Exp curr = exp; if(!exp->type) { + env_weight(env, 1); do { CHECK_OO((curr->type = check_exp_func[curr->exp_type](env, &curr->d))); if(env->func && isa(curr->type, env->gwion->type[et_lambda]) < 0 && isa(curr->type, env->gwion->type[et_function]) > 0 && @@ -1115,22 +1118,22 @@ ANN static inline m_bool cond_type(const Env env, const Exp e) { stmt_func_xxx(if, Stmt_If,, !(!check_flow(env, stmt->cond) || check_stmt(env, stmt->if_body) < 0 || (stmt->else_body && check_stmt(env, stmt->else_body) < 0)) ? 1 : -1) -stmt_func_xxx(flow, Stmt_Flow,, +stmt_func_xxx(flow, Stmt_Flow, env_inline_mult(env, 1.5), !(!check_exp(env, stmt->cond) || !_flow(env, stmt->cond, !stmt->is_do ? stmt_self(stmt)->stmt_type == ae_stmt_while : stmt_self(stmt)->stmt_type != ae_stmt_while) || check_conts(env, stmt_self(stmt), stmt->body) < 0) ? 1 : -1) -stmt_func_xxx(for, Stmt_For,, !( +stmt_func_xxx(for, Stmt_For, env_inline_mult(env, 1.5), !( for_empty(env, stmt) < 0 || check_stmt(env, stmt->c1) < 0 || !check_flow(env, stmt->c2->d.stmt_exp.val) || (stmt->c3 && !check_exp(env, stmt->c3)) || check_conts(env, stmt_self(stmt), stmt->body) < 0) ? 1 : -1) -stmt_func_xxx(loop, Stmt_Loop, check_idx(env, stmt->idx), !(!check_exp(env, stmt->cond) || +stmt_func_xxx(loop, Stmt_Loop, env_inline_mult(env, 1.5); check_idx(env, stmt->idx), !(!check_exp(env, stmt->cond) || cond_type(env, stmt->cond) < 0 || do_stmt_repeat(env, stmt) < 0) ? 1 : -1) -stmt_func_xxx(each, Stmt_Each,, do_stmt_each(env, stmt)) +stmt_func_xxx(each, Stmt_Each, env_inline_mult(env, 1.5), do_stmt_each(env, stmt)) ANN static m_bool check_stmt_return(const Env env, const Stmt_Exp stmt) { if(!env->func) @@ -1511,6 +1514,10 @@ ANN m_bool check_func_def(const Env env, const Func_Def f) { } if(GET_FLAG(fdef->base, global)) env_pop(env,scope); + if(func->value_ref->from->owner_class) + func->inline_mult += 3; + else + func->inline_mult += 4; return ret; } @@ -1635,7 +1642,7 @@ ANN static m_bool _check_class_def(const Env env, const Class_Def cdef) { inherit(t); if(cdef->body) { CHECK_BB(env_body(env, cdef, check_body)); - if(class_def_has_body(env, cdef->body)) + if(cflag(cdef, cflag_struct) || class_def_has_body(env, cdef->body)) set_tflag(t, tflag_ctor); } if(!GET_FLAG(cdef, abstract)) diff --git a/src/vm/vm.c b/src/vm/vm.c index bc7118eb..fe2c110d 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -534,9 +534,9 @@ memaddimm: // (*(m_int*)(mem+VAL))--; DISPATCH(); repeatidx: - BRANCH_DISPATCH(*(m_int*)(mem+VAL2+SZ_INT) == ++(*(m_int*)(mem+VAL2))); + BRANCH_DISPATCH(*(m_int*)(mem+VAL2+SZ_INT) == (*(m_int*)(mem+VAL2))++); repeat: - BRANCH_DISPATCH(!--*(m_uint*)(mem+VAL2)); + BRANCH_DISPATCH(!(*(m_uint*)(mem+VAL2))--); regpushme: *(M_Object*)reg = shred->info->me; reg += SZ_INT; diff --git a/tests/error/template_dyn2.gw b/tests/error/template_dyn2.gw deleted file mode 100644 index c8bb5a3d..00000000 --- a/tests/error/template_dyn2.gw +++ /dev/null @@ -1,48 +0,0 @@ -#! [contains] MissigTmplException -fun void test(C cc) { <<< cc.test(2) >>>; } - -fun void test(C cc, int i) { <<< 1 >>>; <<< cc.test(i, i) >>>; } - - -class C { - fun void test:[A](A a) { <<< " A ", a >>>; } - fun void test:[A](A a, int i) { <<< " ", a >>>; } - fun void test:[A](A a, int i, int j) { <<< a >>>; } -} -class D extends C { - fun void test:[A](A a, int i) { <<< this, " extent ", a, __func__ >>>; } -} -class E extends D { - fun void test:[A](A a, int i) { <<< this, " Extent ", a, _func__ >>>; } -} - - -<<< var C c >>>; -<<< var D d >>>; -<<< var E e >>>; - -test(c); -test(d); -test(e); -test(c,1); -test(d,2); -test(e,3); -<<< test >>>; - - -c.test(1); -c.test(123,1); -c.test(1, 2, 3); - -d.test(2); -d.test(123,3); -d.test(2, 2, 3); - -e.test(3); -e.test(123,3); -e.test(3, 2, 3); - -fun void _test() {<<< "test" >>>; } -fun void test() { _test(); } -test(); -