]> Nishi Git Mirror - gwion.git/commitdiff
:art: Introduce inlining
authorJérémie Astor <fennecdjay@gmail.com>
Sat, 22 May 2021 22:47:33 +0000 (00:47 +0200)
committerJérémie Astor <fennecdjay@gmail.com>
Sat, 22 May 2021 22:47:33 +0000 (00:47 +0200)
15 files changed:
include/emit.h
include/env/context.h
include/env/env.h
include/env/func.h
include/env/type.h
include/parse.h
src/emit/emit.c
src/env/func.c
src/lib/instr.c
src/lib/lib_func.c
src/lib/object.c
src/lib/vararg.c
src/parse/check.c
src/vm/vm.c
tests/error/template_dyn2.gw [deleted file]

index f48db3abae86a57073949c9adcf6f280ae1d27a2..c64154a7dcfd09a8d2af6c50006cb6eb591fab6b 100644 (file)
@@ -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);
index a302f04c948aa2c2dfb5d1c73488cb99aecefa3e..7f8e964a3eb864f08f0ef76c8a22a2e11a81771e 100644 (file)
@@ -6,6 +6,7 @@ struct Context_ {
   m_str       name;
   Ast         tree;
   uint16_t ref;
+  uint16_t weight;
   bool error;
   bool global;
 };
index 85ff9565163479b629f2292b27319433a81332b9..c9372b11a0621099eff4088b875068ad77291a7c 100644 (file)
@@ -14,6 +14,7 @@ struct Env_Scope_ {
   struct Vector_  effects;
   uint16_t        depth;
   bool            in_try;
+  bool            in_loop;
 };
 
 typedef struct Env_ {
index 90e76c1a241edbfaec5ef2963e1654b29b7df290..3ff76fc2b4a94be5839933bfc24fecd176a4eee4 100644 (file)
@@ -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;
 };
index 109dd29d47253d7597a6793a4bbc572207f2a382..c0777f449b15e174f94da64b6887a79d3ac8d64e 100644 (file)
@@ -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;
 };
index 3a8515117298c94b050f94374f48df928067ab7c..98a6166e42d482497176404382fbaf9cc892b30a 100644 (file)
@@ -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
index 1b3f5825fe4e2dc6f0b9c8e4a295b2dc6b170589..f62afc692db703f28036361d6085fd621f8ad28a 100644 (file)
@@ -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);
index 893eee7ef9abf03891d73d7370c3f38f96e9890e..9855ff421c0b7608c88930d0bb8f113cb69772c2 100644 (file)
@@ -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;
 }
index 41f834730e0546ed9e375eab6cdf7c80b9944c96..ae30ed7faf6c751e88c94824303c919d371729cd 100644 (file)
@@ -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;
index 8fb80a5c05128bbaf0eb8355aaab6fc32377406e..08f622d482f3cec53e4e0dc4206a647cc9bf12d8 100644 (file)
@@ -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;
 }
 
index 69dd9f41c3f8108043491ed24a0b353539eca473..4afab57b6dae179ca57ec3caef73d16eaa3b1438 100644 (file)
@@ -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) {
index 938b76224c2bdcd4b086b32f334dec76f4a04508..f418b88aee942482dd49d2e9677139e3c024eb84 100644 (file)
@@ -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;
 }
 
index 27e4ead57774409dd6604c806e3e776758daf79c..4f63a818151431b4477a61ac7fdad8710fe84080 100644 (file)
@@ -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))
index bc7118eb7ff42b4b0b83add0428a518d0f32975f..fe2c110de02c0515ca90d28afdb12d56c08ace03 100644 (file)
@@ -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 (file)
index c8bb5a3..0000000
+++ /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();
-