]> Nishi Git Mirror - gwion.git/commitdiff
:art: Allow unroll on foreach loops
authorJérémie Astor <fennecdjay@gmail.com>
Fri, 22 Jan 2021 11:11:18 +0000 (12:11 +0100)
committerJérémie Astor <fennecdjay@gmail.com>
Fri, 22 Jan 2021 11:11:18 +0000 (12:11 +0100)
include/opcode.h
opcode.txt
src/emit/emit.c
src/vm/vm.c
src/vm/vm_code.c

index 064bee1ad0218813a18d10f81f00ace66b5242ec..79e4492892a5b87a9192676341dca9bd84fd2011 100644 (file)
@@ -143,6 +143,7 @@ enum {
   eBranchNeqFloat,
   eUnroll,
   eArrayAppend,
+  eAutoUnrollInit,
   eAutoLoop,
   eArrayTop,
   eArrayAccess,
@@ -331,6 +332,7 @@ enum {
 #define  BranchNeqFloat       (f_instr)eBranchNeqFloat
 #define  Unroll               (f_instr)eUnroll
 #define  ArrayAppend          (f_instr)eArrayAppend
+#define  AutoUnrollInit       (f_instr)eAutoUnrollInit
 #define  AutoLoop             (f_instr)eAutoLoop
 #define  ArrayTop             (f_instr)eArrayTop
 #define  ArrayAccess          (f_instr)eArrayAccess
index 4504ca628fda666a50234ab52725fbcd1ca80d3a..6457e216728e12544f474993979a997cc1960d8c 100644 (file)
@@ -140,6 +140,7 @@ BranchEqFloat
 BranchNeqFloat
 Unroll
 ArrayAppend
+AutoUnrollInit
 AutoLoop
 ArrayTop
 ArrayAccess
index 9188b1f96bf95a77988b6ce902b5e6b8844c687a..0ba87f4d8f9b80fe7bec4ec19642e6322c6c38e0 100644 (file)
@@ -1223,14 +1223,12 @@ ANN static inline Instr scoped_ini(const Emitter emit) {
   return emit_add_instr(emit, NoOp);
 }
 
-ANN2(1) static inline void scoped_end(const Emitter emit, const Instr gc) {
+ANN static inline void scoped_end(const Emitter emit, const Instr gc) {
   emit_pop_scope(emit);
-  if(gc) {
-    const m_bool pure = !vector_back(&emit->info->pure);
-    if(!pure) {
-      gc->opcode = eGcIni;
-      emit_add_instr(emit, GcEnd);
-    }
+  const m_bool pure = !vector_back(&emit->info->pure);
+  if(!pure) {
+    gc->opcode = eGcIni;
+    emit_add_instr(emit, GcEnd);
   }
   --emit->env->scope->depth;
 }
@@ -1238,7 +1236,7 @@ ANN2(1) static inline void scoped_end(const Emitter emit, const Instr gc) {
 ANN static m_bool scoped_stmt(const Emitter emit, const Stmt stmt, const m_bool pop) {
   const Instr gc = scoped_ini(emit);
   const m_bool ret = emit_stmt(emit, stmt, pop);
-  scoped_end(emit, ret > 0 ? gc : NULL);
+  scoped_end(emit, gc);
   return ret;
 }
 
@@ -1650,7 +1648,77 @@ ANN static m_bool emit_stmt_for(const Emitter emit, const Stmt_For stmt) {
   return ret;
 }
 
+
+struct Looper;
+typedef void (*f_looper)(const Emitter, const struct Looper *);
+struct Looper {
+  const Stmt stmt;
+  /*const */m_uint offset;
+  const m_uint n;
+  const f_looper roll;
+  const f_looper unroll;
+};
+
+ANN static inline m_bool roll(const Emitter emit, const struct Looper *loop) {
+  if(loop->roll)
+    loop->roll(emit, loop);
+  const Instr instr = emit_add_instr(emit, BranchEqInt);
+  CHECK_BB(scoped_stmt(emit, loop->stmt, 1))
+  instr->m_val = emit_code_size(emit) + 1; // pass after goto
+  return GW_OK;
+}
+
+ANN static void stmt_each_roll(const Emitter emit, const struct Looper *loop) {
+  const Instr instr = emit_add_instr(emit, AutoLoop);
+  instr->m_val = loop->offset + SZ_INT;
+  regpush(emit, SZ_INT);
+}
+
+ANN static inline void unroll_init(const Emitter emit, const m_uint n) {
+  emit->info->unroll = 0;
+  const Instr instr = emit_add_instr(emit, MemSetImm);
+  instr->m_val = emit_local(emit, emit->gwion->type[et_int]);
+  instr->m_val2 = n;
+}
+
+ANN static inline m_bool unroll_run(const Emitter emit, const struct Looper *loop) {
+  if(loop->unroll)
+    loop->unroll(emit, loop);
+  return emit_stmt(emit, loop->stmt, 1);
+}
+
+ANN static m_bool unroll(const Emitter emit, const struct Looper *loop) {
+  const Instr unroll = emit_add_instr(emit, Unroll);
+  unroll->m_val = loop->offset;
+  const m_uint start = emit_code_size(emit);
+  const Instr gc = scoped_ini(emit);
+  CHECK_BB(unroll_run(emit, loop))
+  const m_uint end = emit_code_size(emit);
+  for(m_uint i = 1; i < loop->n; ++i)
+    CHECK_BB(unroll_run(emit, loop))
+  unroll->m_val2 = end - start;
+  scoped_end(emit, gc);
+  const Instr unroll2 = emit_add_instr(emit, Unroll2);
+  unroll2->m_val = (m_uint)unroll;
+  return GW_OK;
+}
+
+ANN static void stmt_each_unroll(const Emitter emit, const struct Looper *loop) {
+  const Instr instr = emit_add_instr(emit, AutoLoop);
+  instr->m_val = loop->offset + SZ_INT*2;
+}
+
+ANN static inline m_bool looper_run(const Emitter emit, const struct Looper *loop) {
+  return (!loop->n ? roll : unroll)(emit, loop);
+}
+
 ANN static m_bool _emit_stmt_each(const Emitter emit, const Stmt_Each stmt, m_uint *end_pc) {
+  const uint n = emit->info->unroll;
+  if(n) {
+    unroll_init(emit, n);
+    emit_local(emit, emit->gwion->type[et_int]);
+  }
+
   CHECK_BB(emit_exp(emit, stmt->exp)) // add ref?
   regpop(emit, SZ_INT);
   const m_uint offset = emit_local(emit, emit->gwion->type[et_int]);//array?
@@ -1659,18 +1727,22 @@ ANN static m_bool _emit_stmt_each(const Emitter emit, const Stmt_Each stmt, m_ui
   const Instr tomem = emit_add_instr(emit, Reg2Mem);
   tomem->m_val = offset;
   const Instr s1 = emit_add_instr(emit, MemSetImm);
+  s1->m_val = offset + SZ_INT;
   stmt->v->from->offset = offset + SZ_INT*2;
+  if(n) {
+    const Instr instr = emit_add_instr(emit, AutoUnrollInit);
+    instr->m_val = offset-SZ_INT;
+  }
   const m_uint ini_pc  = emit_code_size(emit);
-  const Instr loop = emit_add_instr(emit, AutoLoop);
-  const Instr end = emit_add_instr(emit, BranchEqInt);
-  const m_bool ret = scoped_stmt(emit, stmt->body, 1);
+  struct Looper loop = { .stmt=stmt->body, .offset=offset, .n=n,
+   .roll=stmt_each_roll, .unroll=stmt_each_unroll };
+  if(n)
+    loop.offset -= SZ_INT;
+  CHECK_BB(looper_run(emit, &loop))
   *end_pc = emit_code_size(emit);
-  loop->m_val2 = (m_uint)stmt->v->type;
   const Instr tgt = emit_add_instr(emit, Goto);
-  end->m_val = emit_code_size(emit);
   tgt->m_val = ini_pc;
-  s1->m_val = loop->m_val = offset + SZ_INT;
-  return ret;
+  return GW_OK;
 }
 
 ANN static m_bool emit_stmt_each(const Emitter emit, const Stmt_Each stmt) {
@@ -1681,38 +1753,10 @@ ANN static m_bool emit_stmt_each(const Emitter emit, const Stmt_Each stmt) {
   return ret;
 }
 
-ANN static m_bool stmt_loop_roll(const Emitter emit, const Stmt stmt, const m_uint offset) {
+ANN static void stmt_loop_roll(const Emitter emit, const struct Looper *loop) {
   const Instr cpy = emit_add_instr(emit, RegPushMem4);
-  cpy->m_val = offset;
+  cpy->m_val = loop->offset;
   emit_add_instr(emit, int_post_dec);
-  const Instr op = emit_add_instr(emit, BranchEqInt);
-  CHECK_BB(scoped_stmt(emit, stmt, 1))
-  op->m_val = emit_code_size(emit) + 1; // pass after goto
-  return GW_OK;
-}
-
-ANN static inline void unroll_init(const Emitter emit, const m_uint n) {
-  emit->info->unroll = 0;
-  const Instr instr = emit_add_instr(emit, MemSetImm);
-  instr->m_val = emit_local(emit, emit->gwion->type[et_int]);
-  instr->m_val2 = n;
-}
-
-ANN static m_bool stmt_loop_unroll(const Emitter emit, const Stmt stmt,
-          const m_uint offset, const m_uint n) {
-  const Instr unroll = emit_add_instr(emit, Unroll);
-  unroll->m_val = offset;
-  const m_uint start = emit_code_size(emit);
-  const Instr gc = scoped_ini(emit);
-  CHECK_BB(emit_stmt(emit, stmt, 1))
-  const m_uint end = emit_code_size(emit);
-  for(m_uint i = 1; i < n; ++i)
-    CHECK_BB(emit_stmt(emit, stmt, 1))
-  unroll->m_val2 = end - start;
-  scoped_end(emit, gc);
-  const Instr unroll2 = emit_add_instr(emit, Unroll2);
-  unroll2->m_val = (m_uint)unroll;
-  return GW_OK;
 }
 
 ANN static m_bool _emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt, m_uint *index) {
@@ -1725,10 +1769,10 @@ ANN static m_bool _emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt, m_ui
   const Instr tomem = emit_add_instr(emit, Reg2Mem);
   tomem->m_val = offset;
   *index = emit_code_size(emit);
-  if(!n)
-    CHECK_BB(stmt_loop_roll(emit, stmt->body, offset))
-  else
-    CHECK_BB(stmt_loop_unroll(emit, stmt->body, offset, n))
+  struct Looper loop = { .stmt=stmt->body, .offset=offset, .n=n,
+    .roll=stmt_loop_roll };
+//roll(emit, &loop);
+  CHECK_BB(looper_run(emit, &loop))
   const Instr _goto = emit_add_instr(emit, Goto);
   _goto->m_val = *index;
   return GW_OK;
index 451852ceb839850c16342ae06e5512acc2311c1f..5133dde72f835e3a5526a2b0a547010e4156f615 100644 (file)
@@ -323,7 +323,7 @@ ANN void vm_run(const VM* vm) { // lgtm [cpp/use-of-goto]
     &&regmove, &&regtomem, &&regtomemother, &&overflow, &&funcusrend, &&funcmemberend,
     &&sporkini, &&forkini, &&sporkfunc, &&sporkmemberfptr, &&sporkexp, &&sporkend,
     &&brancheqint, &&branchneint, &&brancheqfloat, &&branchnefloat, &&unroll,
-    &&arrayappend, &&autoloop, &&arraytop, &&arrayaccess, &&arrayget, &&arrayaddr, &&arrayvalid,
+    &&arrayappend, &&autounrollinit, &&autoloop, &&arraytop, &&arrayaccess, &&arrayget, &&arrayaddr, &&arrayvalid,
     &&newobj, &&addref, &&addrefaddr, &&structaddref, &&structaddrefaddr, &&objassign, &&assign, &&remref,
     &&except, &&allocmemberaddr, &&dotmember, &&dotfloat, &&dotother, &&dotaddr,
     &&unioncheck, &&unionint, &&unionfloat, &&unionother, &&unionaddr,
@@ -715,7 +715,7 @@ unroll:
 {
   const m_uint n = *(m_uint*)(mem + VAL - SZ_INT);
   const m_uint idx = *(m_uint*)(mem + VAL);
-  if(idx) {
+  if(idx > 0) {
     if(idx >= n) {
       *(m_uint*)(mem + VAL) -= n;
        DISPATCH()
@@ -728,10 +728,12 @@ unroll:
 arrayappend:
   m_vector_add(ARRAY(*(M_Object*)(reg-SZ_INT)), reg);
   DISPATCH()
+autounrollinit:
+  *(m_uint*)(mem + VAL) = m_vector_size(ARRAY(*(M_Object*)(mem+VAL+SZ_INT)));
+  DISPATCH()
 autoloop:
   *(m_bit**)(mem + VAL + SZ_INT) = m_vector_addr(ARRAY(*(M_Object*)(mem+VAL-SZ_INT)), *(m_uint*)(mem + VAL));
   *(m_uint*)reg = m_vector_size(ARRAY(*(M_Object*)(mem+VAL-SZ_INT))) - (*(m_uint*)(mem + VAL))++;
-  reg += SZ_INT;
   DISPATCH()
 arraytop:
   if(*(m_uint*)(reg - SZ_INT * 2) < *(m_uint*)(reg-SZ_INT))
index 6a12813fbe91c4c3d5e535f33fd4b903b4e51ee9..d5ec5adfb32dde43aed070a4b61f3e162016c2ad 100644 (file)
@@ -86,7 +86,7 @@ ANN static m_bit* tobytecode(MemPool p, const VM_Code code) {
           if(at < pc)
             ++reduce_pre;
           if(at >= pc) {
-            if(at >= (pc + unroll->m_val2))
+            if(at > (pc + unroll->m_val2))
               break;
             ++reduce;
           }