]> Nishi Git Mirror - gwion.git/commitdiff
:art: array casting
authorfennecdjay <fennecdjay@gmail.com>
Mon, 8 May 2023 19:30:28 +0000 (21:30 +0200)
committerfennecdjay <fennecdjay@gmail.com>
Mon, 8 May 2023 19:30:28 +0000 (21:30 +0200)
include/opcode.h
opcode.txt
src/emit/emit.c
src/env/type.c
src/lib/array.c
src/vm/vm.c
src/vm/vm_code.c

index 9e8f041d7b5531f6a19d00154e78e1a439c9997d..e21ff243f26aeaf7a11fc5059e280d15df588a8b 100644 (file)
@@ -168,10 +168,9 @@ enum {
   eArrayAppend,
   eAutoUnrollInit,
   eAutoLoop,
+  eArrayCastLoop,
   eArrayTop,
   eArrayAccess,
-  eArrayGet,
-  eArrayAddr,
   eObjectInstantiate,
   eRegAddRef,
   eRegAddRefAddr,
@@ -388,10 +387,9 @@ enum {
 #define  ArrayAppend           (f_instr)eArrayAppend
 #define  AutoUnrollInit        (f_instr)eAutoUnrollInit
 #define  AutoLoop              (f_instr)eAutoLoop
+#define  ArrayCastLoop         (f_instr)eArrayCastLoop
 #define  ArrayTop              (f_instr)eArrayTop
 #define  ArrayAccess           (f_instr)eArrayAccess
-#define  ArrayGet              (f_instr)eArrayGet
-#define  ArrayAddr             (f_instr)eArrayAddr
 #define  ObjectInstantiate     (f_instr)eObjectInstantiate
 #define  RegAddRef             (f_instr)eRegAddRef
 #define  RegAddRefAddr         (f_instr)eRegAddRefAddr
@@ -1205,6 +1203,11 @@ ANN static inline void dump_opcodes(const VM_Code code) {
         gw_out(" {-B}=>%-12"UINT_F"{0}", instr->m_val);
         gw_out("\n");
         break;
+      case eArrayCastLoop:
+        gw_out("{Y}┃{0}{-}% 4lu{0}: ArrayCastLoop", j);
+        gw_out(" {-B}=>%-12"UINT_F"{0}", instr->m_val);
+        gw_out("\n");
+        break;
       case eArrayTop:
         gw_out("{Y}┃{0}{-}% 4lu{0}: ArrayTop    ", j);
         gw_out(" {-B}=>%-12"UINT_F"{0}", instr->m_val);
@@ -1216,18 +1219,6 @@ ANN static inline void dump_opcodes(const VM_Code code) {
         gw_out(" {-M}%-14"UINT_F"{0}", instr->m_val2);
         gw_out("\n");
         break;
-      case eArrayGet:
-        gw_out("{Y}┃{0}{-}% 4lu{0}: ArrayGet    ", j);
-        gw_out(" {-R}%-14"UINT_F"{0}", instr->m_val);
-        gw_out(" {-M}%-14"INT_F"{0}", instr->m_val2);
-        gw_out("\n");
-        break;
-      case eArrayAddr:
-        gw_out("{Y}┃{0}{-}% 4lu{0}: ArrayAddr   ", j);
-        gw_out(" {-R}%-14"UINT_F"{0}", instr->m_val);
-        gw_out(" {-M}%-14"INT_F"{0}", instr->m_val2);
-        gw_out("\n");
-        break;
       case eObjectInstantiate:
         gw_out("{Y}┃{0}{-}% 4lu{0}: ObjectInstantiate", j);
         gw_out(" {-R}%-14"INT_F"{0}", instr->m_val);
index f7db6f75e37142e224b5d9b355adbbc340a31b70..4a63a5dac13dc7023245fd6224af7e58bc551335 100644 (file)
@@ -165,10 +165,9 @@ Unroll~u~u
 ArrayAppend
 AutoUnrollInit~u
 AutoLoop~pc
+ArrayCastLoop~pc
 ArrayTop~pc
 ArrayAccess~u~u
-ArrayGet~u~i
-ArrayAddr~u~i
 ObjectInstantiate~i~t
 RegAddRef~i
 RegAddRefAddr~i
index 24c299c9bdaf52fbe24ee58f6138ae24d0b12fae..cda18b6c7fbce86b7ff49a3831b5b0a3cd598620 100644 (file)
@@ -693,11 +693,6 @@ ANN m_bool emit_array_access(const Emitter                 emit,
                           .lhs  = info->array.exp->type,
                           .rhs  = info->array.type,
                           .data = (uintptr_t)info};
-/*
-  if (!info->is_var &&
-      (GET_FLAG(info->array.type, abstract) || type_ref(info->array.type)))
-    emit_fast_except(emit, NULL, info->array.exp->pos);
-*/
   return op_emit(emit, &opi);
 }
 
index 575e32a28f461b1abb372e2d152981e393a33673..8975393ba47ec7d09dbbdab60e53b965e2e9b83c 100644 (file)
@@ -91,6 +91,7 @@ ANN /*static */ Symbol array_sym(const Env env, const Type src,
 }
 
 ANN Type array_type(const Env env, const Type src, const m_uint depth) {
+  if(!depth) return src;
   const Symbol sym  = array_sym(env, src, depth);
   const Type   type = nspc_lookup_type1(src->info->value->from->owner, sym);
   if (type) return type;
index 1faf90a2850539790b9e216fe38e75327f84771e..aede652d9326f8eef63e456d91a9406e865f3f35 100644 (file)
@@ -256,11 +256,71 @@ static OP_EMIT(opem_array_sl) {
 static OP_CHECK(opck_array_cast) {
   const Exp_Cast *cast = (Exp_Cast *)data;
   const Type      l    = array_base(cast->exp->type);
-  const Type      r    = array_base(exp_self(cast)->type);
-  if (get_depth(cast->exp->type) == get_depth(exp_self(cast)->type) &&
-      isa(l->info->base_type, r->info->base_type) > 0)
-    return l;
-  return NULL;
+  const Type      t    = known_type(env, cast->td);
+  const Type      r    = array_base(t);
+  if (get_depth(cast->exp->type) != get_depth(t))
+    return NULL;
+  if(isa(l, r) > 0) return l;
+  Type parent = t;
+  while(parent) {
+    if (tflag(parent, tflag_cdef) && parent->info->cdef->base.ext && parent->info->cdef->base.ext->array) {
+      ERR_N(cast->td->pos, "can only cast to simple array types");
+    }
+    parent = parent->info->parent;
+  }
+  struct Exp_ e = { .type = l, .pos = cast->exp->pos };
+  CHECK_BN(check_implicit(env, &e, r));
+  return t;
+}
+
+ANN static void cast_start(const Emitter emit, const m_uint depth) {
+  for(m_uint i = 0; i < depth; i++) {
+    const m_uint offset = emit_local(emit, emit->gwion->type[et_int]); // idx
+    emit_local(emit, emit->gwion->type[et_int]); // store base 
+    emit_regtomem(emit, offset, -SZ_INT);
+    emit_memsetimm(emit, offset + SZ_INT, 0);
+    emit_regmove(emit, -SZ_INT);
+    const Instr loop = emit_add_instr(emit, ArrayCastLoop);
+    loop->m_val2 = offset;
+  }
+} 
+
+ANN static void cast_end(const Emitter emit, const Type base, const m_uint depth, const m_uint start) {
+  for(m_uint i = 0; i < depth; i++) {
+    const m_uint pc = start + (depth-i) * 4 - 1;
+    const Instr top = emit_add_instr(emit, Goto);
+    top->m_val = pc;
+    const Instr loop = (Instr)vector_at(&emit->code->instr, pc);
+    loop->m_val = emit_code_size(emit);
+    const Instr end = emit_add_instr(emit, ArrayInit);
+    const Type t = array_type(emit->env, base, i + 1);
+    end->m_val = (m_uint)array_type(emit->env, base, i + 1);
+    end->m_val2 = t->actual_size ?: t->size;
+  }
+}
+
+static OP_EMIT(opem_array_cast) {
+  const Exp_Cast *cast = (Exp_Cast *)data;
+  const Env env = emit->env;
+  const Type l = array_base(cast->exp->type);
+  const Type t = known_type(env, cast->td);
+  const Type r = array_base(t);
+  if(isa(l, r) < 0) {
+    const m_uint depth = get_depth(t);
+    const m_uint start = emit_code_size(emit);
+    cast_start(emit, depth);
+    if(r->actual_size) emit_regmove(emit, r->size - r->actual_size);
+    // we need a correct exp to pass
+    struct Op_Import opi = {.op   = insert_symbol("$"),
+                            .lhs  = l,
+                            .rhs  = r,
+                            .data = (uintptr_t)cast}; // no pos ?
+    (void)op_emit(emit, &opi);
+    cast_end(emit, r, depth, start);
+    const m_uint ret_offset = emit_local(emit, t);
+    emit_regtomem(emit, ret_offset, -SZ_INT);
+  }
+  return GW_OK;
 }
 
 static OP_CHECK(opck_array_slice) {
@@ -324,44 +384,32 @@ static OP_CHECK(opck_array) {
   if (t->array_depth >= array->depth)
     return array_type(env, array_base(t), t->array_depth - array->depth);
   const Exp         curr = take_exp(array->exp, t->array_depth);
+
   struct Array_Sub_ next = {curr->next, array_base(t),
                             array->depth - t->array_depth};
   return check_array_access(env, &next) ?: env->gwion->type[et_error];
 }
 
-ANN static void array_loop(const Emitter emit, const m_uint depth) {
-  emit_regmove(emit, -depth * SZ_INT);
-  for (m_uint i = 0; i < depth - 1; ++i) {
-    const Instr access = emit_add_instr(emit, ArrayAccess);
-    access->m_val      = i * SZ_INT;
-    access->m_val2     = !i ? SZ_INT : 0;
-    const Instr get    = emit_add_instr(emit, ArrayGet);
-    get->m_val         = i * SZ_INT;
-    get->m_val2        = -SZ_INT;
-    const Instr ex     = emit_add_instr(emit, GWOP_EXCEPT);
-    ex->m_val          = -SZ_INT;
-  }
-  emit_regmove(emit, -SZ_INT);
-  const Instr access   = emit_add_instr(emit, ArrayAccess);
-  access->m_val        = depth * SZ_INT;
-}
-
-ANN static void array_finish(const Emitter emit, const Array_Sub array, const m_bool is_var) {
-  const Instr get = emit_add_instr(emit, is_var ? ArrayAddr : ArrayGet);
-  const Type t = array->type;
-  if(!is_var) {
-    if(array->depth < get_depth(t) || isa(array_base(t), emit->gwion->type[et_object]) > 0)
-      emit_add_instr(emit, GWOP_EXCEPT);
-  }
-  get->m_val      = array->depth * SZ_INT;
-  emit_regmove(emit, is_var ? SZ_INT : t->size);
-}
-
 ANN static inline m_bool array_do(const Emitter emit, const Array_Sub array,
-                                  const m_bool is_var) {
+                                  const bool is_var) {
   CHECK_BB(emit_exp(emit, array->exp));
-  array_loop(emit, array->depth);
-  array_finish(emit, array, is_var);
+  const m_uint depth = array->depth;
+  const m_uint offset = is_var ? SZ_INT : array->type->size;
+  emit_regmove(emit, -(depth+1) * SZ_INT + offset);
+  assert(depth);
+  const Type t = array->type;
+  Instr access = NULL;
+  for (m_uint i = 0; i < depth; ++i) {
+    access = emit_add_instr(emit, ArrayAccess);
+    access->m_val      = (i+1) * SZ_INT - offset;
+    access->udata.one  = offset;
+    if(i < get_depth(t) || isa(array_base(t), emit->gwion->type[et_object]) > 0) {
+      const Instr ex     = emit_add_instr(emit, GWOP_EXCEPT);
+      ex->m_val          = -SZ_INT;
+    }
+  }
+  assert(access);
+  access->udata.two = is_var;
   return GW_OK;
 }
 
@@ -994,6 +1042,7 @@ GWION_IMPORT(array) {
   GWI_BB(gwi_oper_end(gwi, ">>", NULL))
   GWI_BB(gwi_oper_ini(gwi, "Array", "Array", NULL))
   GWI_BB(gwi_oper_add(gwi, opck_array_cast))
+  GWI_BB(gwi_oper_emi(gwi, opem_array_cast))
   GWI_BB(gwi_oper_end(gwi, "$", NULL))
   GWI_BB(gwi_oper_ini(gwi, "int", "Array", "int"))
   GWI_BB(gwi_oper_add(gwi, opck_array_slice))
index c92b12f4e2652306ef3b0a43e555d31ce6b3ace2..61e93d3fd8b5fd31c3bf718c0ff76df699374504 100644 (file)
@@ -460,7 +460,8 @@ vm_prepare(const VM *vm, m_bit *prepare_code) { // lgtm [cpp/use-of-goto]
       &&sporkini, &&forkini, &&sporkfunc, &&sporkexp, &&sporkcode,
       &&forkend, &&sporkend, &&brancheqint, &&branchneint, &&brancheqfloat,
       &&branchnefloat, &&unroll, &&arrayappend, &&autounrollinit, &&autoloop,
-      &&arraytop, &&arrayaccess, &&arrayget, &&arrayaddr, &&newobj, &&addref,
+      &&arraycastloop,
+      &&arraytop, &&arrayaccess, &&newobj, &&addref,
       &&addrefaddr, &&structaddref, &&structaddrefaddr,
       &&unionaddref, &&unionaddrefaddr,
       &&objassign, &&assign,
@@ -1030,6 +1031,20 @@ vm_prepare(const VM *vm, m_bit *prepare_code) { // lgtm [cpp/use-of-goto]
       }
       BRANCH_DISPATCH(end);
     }
+arraycastloop:
+{
+  const M_Object base  = *(M_Object*)(mem + VAL2);
+  const m_uint idx = (*(m_uint*)(mem + VAL2 + SZ_INT))++;
+  M_Vector array = ARRAY(base);
+  const m_uint sz = ARRAY_SIZE(array);
+  if (idx == ARRAY_LEN(array)){
+    *(m_uint*)reg = ARRAY_LEN(array);
+    goto _goto;
+  }
+  memcpy(reg, ARRAY_PTR(array) + idx * sz, sz);
+  reg += sz;
+} 
+DISPATCH();
     arraytop:
       if (*(m_uint *)(reg - SZ_INT * 2) < *(m_uint *)(reg - SZ_INT))
         goto newobj;
@@ -1037,28 +1052,26 @@ vm_prepare(const VM *vm, m_bit *prepare_code) { // lgtm [cpp/use-of-goto]
         goto _goto;
     arrayaccess : {
       register const m_int idx = *(m_int *)(reg + VAL);
-      a.obj                    = *(M_Object *)(reg - VAL2);
+      a.obj                    = *(M_Object *)(reg - SVAL);
       if (idx < 0 || (m_uint)idx >= m_vector_size(ARRAY(a.obj))) {
-        gw_err(_("{-}  ... at index {W}[{Y}%" INT_F "{W}]{0}\n"), idx);
+        gw_err(_("{-}  ... at index {W}[{Y}%" INT_F "{W}]{2}\n"), idx);
         //    gw_err(_("  ... at dimension [%" INT_F "]\n"), VAL);
 //        VM_OUT
         handle(shred, "ArrayOutofBounds");
         continue; // or break ?
       }
-      DISPATCH()
-    }
-    arrayget:
-      m_vector_get(ARRAY(a.obj), *(m_int *)(reg + VAL), (reg + IVAL2));
-      DISPATCH()
-    arrayaddr:
-      *(m_bit **)(reg + IVAL2) =
+      if (likely(!SVAL2))
+        m_vector_get(ARRAY(a.obj), *(m_int *)(reg + VAL), (reg - SVAL));
+      else 
+        *(m_bit **)(reg - SVAL) =
           m_vector_addr(ARRAY(a.obj), *(m_int *)(reg + VAL));
       DISPATCH()
+    }
     newobj:
       *(M_Object *)reg = new_object(vm->gwion->mp, (Type)VAL2);
       reg += SZ_INT;
       DISPATCH()
-    addref : {
+    addref :  {
       const M_Object o = *(M_Object *)(reg + IVAL);
           if(o)
       ++o->ref;
@@ -1328,7 +1341,8 @@ static void *_dispatch[] = {
       &&_sporkini, &&_forkini, &&_sporkfunc, &&_sporkexp, &&_sporkcode, &&_forkend,
       &&_sporkend, &&_brancheqint, &&_branchneint, &&_brancheqfloat,
       &&_branchnefloat, &&_unroll, &&_arrayappend, &&_autounrollinit, &&_autoloop,
-      &&_arraytop, &&_arrayaccess, &&_arrayget, &&_arrayaddr, &&_newobj, &&_addref,
+&&_arraycastloop,      
+      &&_arraytop, &&_arrayaccess, &&_newobj, &&_addref,
       &&_addrefaddr, &&_structaddref, &&_structaddrefaddr,
       &&_unionaddref, &&_unionaddrefaddr, &&_objassign, &&_assign,
       &&_remref, &&_remref2, &&_structreleaseregaddr, &&_structreleasemem,
@@ -1540,11 +1554,10 @@ return;
     PREPARE(unroll);
     PREPARE(arrayappend);
     PREPARE(autounrollinit);
-    PREPARE(autoloop);
     PREPARE(arraytop);
+    PREPARE(autoloop);
+    PREPARE(arraycastloop);
     PREPARE(arrayaccess);
-    PREPARE(arrayget);
-    PREPARE(arrayaddr);
     PREPARE(newobj);
     PREPARE(addref);
     PREPARE(addrefaddr);
index a6895f379702b6e71fa9d5d9c7d4756fd43dc348..649d79bb4a88cb0982d5dbae7e0c7f1c9343249a 100644 (file)
@@ -44,7 +44,8 @@ static inline uint isgoto(const unsigned opcode) {
   return opcode == eGoto || opcode == eArrayTop || opcode == eBranchEqInt ||
          opcode == eBranchNeqInt || opcode == eBranchEqFloat ||
          opcode == eBranchNeqFloat || opcode == eHandleEffect ||
-         opcode == eRepeat || opcode == eRepeatIdx || opcode == eAutoLoop;
+         opcode == eRepeat || opcode == eRepeatIdx || opcode == eAutoLoop ||
+         opcode == eArrayCastLoop;
 }
 
 ANN static inline void setpc(const m_bit *data, const m_uint i) {