From f37c0624ce45f5c432eb1e96c636d4caa9eba22e Mon Sep 17 00:00:00 2001 From: fennecdjay Date: Mon, 8 May 2023 21:30:28 +0200 Subject: [PATCH] :art: array casting --- include/opcode.h | 23 +++------ opcode.txt | 3 +- src/emit/emit.c | 5 -- src/env/type.c | 1 + src/lib/array.c | 121 +++++++++++++++++++++++++++++++++-------------- src/vm/vm.c | 43 +++++++++++------ src/vm/vm_code.c | 3 +- 7 files changed, 124 insertions(+), 75 deletions(-) diff --git a/include/opcode.h b/include/opcode.h index 9e8f041d..e21ff243 100644 --- a/include/opcode.h +++ b/include/opcode.h @@ -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); diff --git a/opcode.txt b/opcode.txt index f7db6f75..4a63a5da 100644 --- a/opcode.txt +++ b/opcode.txt @@ -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 diff --git a/src/emit/emit.c b/src/emit/emit.c index 24c299c9..cda18b6c 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -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); } diff --git a/src/env/type.c b/src/env/type.c index 575e32a2..8975393b 100644 --- a/src/env/type.c +++ b/src/env/type.c @@ -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; diff --git a/src/lib/array.c b/src/lib/array.c index 1faf90a2..aede652d 100644 --- a/src/lib/array.c +++ b/src/lib/array.c @@ -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)) diff --git a/src/vm/vm.c b/src/vm/vm.c index c92b12f4..61e93d3f 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -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); diff --git a/src/vm/vm_code.c b/src/vm/vm_code.c index a6895f37..649d79bb 100644 --- a/src/vm/vm_code.c +++ b/src/vm/vm_code.c @@ -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) { -- 2.43.0