void syn_memsetw( struct machine_ops* mop, struct emitter* e, struct machine* m, operand d, operand v, operand size ){ operand iter = OP_TARGETREG( acquire_temp( mop, e, m ) ); operand dst = OP_TARGETREG( acquire_temp( mop, e, m ) ); // init iterator mop->move( e, m, iter, OP_TARGETIMMED( 0 ) ); mop->move( e, m, dst, d ); // start loop e->ops->label_local( e, 0 ); mop->beq( e, m, iter, size, LBL_NEXT( 0 ) ); // copy mop->move( e, m, OP_TARGETDADDR( dst.reg, 0 ), v ); // update pointers mop->add( e, m, dst, dst, OP_TARGETIMMED( 4 ) ); // update iterator mop->add( e, m, iter, iter, OP_TARGETIMMED( 1 ) ); mop->b( e, m, LBL_PREV( 0 ) ); e->ops->label_local( e, 0 ); release_tempn( mop, e, m, 2 ); }
// this function could be inline void syn_memcpyw( struct machine_ops* mop, struct emitter* e, struct machine* m, operand d, operand s, operand size ){ operand iter = OP_TARGETREG( acquire_temp( mop, e, m ) ); operand src = OP_TARGETREG( acquire_temp( mop, e, m ) ); operand dst = OP_TARGETREG( acquire_temp( mop, e, m ) ); // init iterator mop->move( e, m, iter, OP_TARGETIMMED( 0 ) ); mop->move( e, m, src, s ); mop->move( e, m, dst, d ); // start loop e->ops->label_local( e, 0 ); mop->beq( e, m, iter, size, LBL_NEXT( 0 ) ); // copy mop->move( e, m, OP_TARGETDADDR( dst.reg, 0 ), OP_TARGETDADDR( src.reg, 0 ) ); // update pointers mop->add( e, m, dst, dst, OP_TARGETIMMED( -4 ) ); // TODO: this is incorrect in general but correct for copyargs mop->add( e, m, src, src, OP_TARGETIMMED( -4 ) ); // update iterator mop->add( e, m, iter, iter, OP_TARGETIMMED( 1 ) ); mop->b( e, m, LBL_PREV( 0 ) ); e->ops->label_local( e, 0 ); release_tempn( mop, e, m, 3 ); }
void jinit_cpy_arg_res( struct JFunc* jf, struct machine_ops* mop, struct emitter* e, struct machine* m ){ operand rargs[ RA_SIZE ]; prefer_nontemp_acquire_reg( mop, e, m, RA_SIZE, rargs ); syn_min( mop, e, m, rargs[ RA_EXIST ], rargs[ RA_EXIST ], rargs[ RA_EXPECT ] ); // init iterator operand iter = OP_TARGETREG( acquire_temp( mop, e, m ) ); mop->move( e, m, iter, OP_TARGETIMMED( 0 ) ); do_copying( mop, e, m, iter, rargs[ RA_EXIST ], rargs[ RA_DST ], rargs[ RA_SRC ] ); /* * TODO: Below logic is incorrect the first is most likely to get spilled. So change enum order. BUT * then you have to think about prefer saved reg and the order there. * TODO: add error prefer_nontemps to error when not all live simultenously * * RA_EXPECT is last register therefore its the most likely to be spilled. So to stop repeat * spill/unspill move it to exist. */ mop->move( e, m, rargs[ RA_SIZE ], rargs[ RA_EXIST ] ); do_nilling( mop, e, m, iter, rargs[ RA_EXIST ], rargs[ RA_DST ] ); release_temp( mop, e, m ); prefer_nontemp_release_reg( mop, e, m, RA_SIZE ); mop->ret( e, m ); }
/* Grab non temps first then temps */ static void prefer_nontemp_acquire_reg( struct machine_ops* mop, struct emitter* e, struct machine* m, int n, operand reg[n] ){ // must fit into registers only assert( n <= m->nr_reg ); const int nr_temps = m->nr_temp_regs; const int nr_nontemps = m->nr_reg - nr_temps; for( int i = 0; i < n; i++ ){ if( i < nr_nontemps ) reg[i] = OP_TARGETREG( m->reg[ nr_temps + i ] ); else reg[i] = OP_TARGETREG( acquire_temp( mop, e, m ) ); // ( i - nr_nontemps ); } // disable spill disable_spill( m ); }
void mips_b( struct emitter* me, struct machine* m, label l ){ if( !ISL_ABS( l ) ){ EMIT( MI_B( mips_branch( me, l ) ) ); } else if ( ISL_ABSDIRECT( l ) ){ // TODO: make sure within 256MB region by calling MI_J_SAFE EMIT( MI_J( l.abs.k ) ); } else if ( ISO_REG( l.abs ) ) { EMIT( MI_JR( l.abs.reg ) ); } else { assert( ISO_DADDR( l.abs ) ); operand t = OP_TARGETREG( acquire_temp( _MOP, me, m ) ); move( me, m, t, l.abs ); EMIT( MI_JR( t.reg ) ); RELEASE_OR_NOP( me, m ); return; } // delay slot EMIT( MI_NOP() ); }
static lua_Number ljc_relational( lua_Number st, lua_Number sv , lua_Number tt, lua_Number tv , int op ) { assert( !( st == LUA_TNUMBER && tt == LUA_TNUMBER ) ); struct TValue s = { .t = st, .v = (union Value)sv }; struct TValue t = { .t = tt, .v = (union Value)tv }; switch( op ){ case REL_LT: return do_lt( &s, &t ); case REL_LEQ: return do_leq( &s, &t ); case REL_EQ: return do_eq( &s, &t ); default: assert( false ); } } typedef void (*arch_rel)( struct emitter*, struct machine* , operand, operand, label ); static void emit_relational( struct emitter *me, struct machine_ops *mop , struct frame* f , loperand s, loperand t , arch_rel ar, int op , bool expect ){ vreg_operand os = loperand_to_operand( f, s ), ot = loperand_to_operand( f, t ); unsigned int pc = me->ops->pc( me ) + 2; label l = LBL_PC( pc ); // determine if coercion is required operand tag = OP_TARGETREG( acquire_temp( mop, me, f->m ) ); mop->bor( me, f->m, tag, os.type, ot.type ); mop->beq( me, f->m, tag, OP_TARGETIMMED( 0 ), LBL_NEXT( 0 ) ); // do coercion mop->call_static_cfn( me, f, (uintptr_t)&ljc_relational , &tag, 5, os.type, os.value , ot.type, ot.value , OP_TARGETIMMED( op ) ); mop->beq( me, f->m, tag, OP_TARGETIMMED( expect ), l ); mop->b( me, f->m, LBL_NEXT( 1 ) ); // do primitive relational me->ops->label_local( me, 0 ); ar( me, f->m, os.value, ot.value, l ); me->ops->label_local( me, 1 ); release_temp( mop, me, f->m ); return; } void emit_jmp( struct emitter** mce, struct machine_ops* mop , struct frame *f , loperand a , int offset ){ assert( a.islocal ); // if not zero then any upvalues below the vreg need to be closed. if( a.index > 0 ){ vreg_operand op = vreg_to_operand( f, a.index + 1, true ); operand base = OP_TARGETREG( acquire_temp( mop, REF, f->m ) ); address_of( mop, REF, f->m, base, op.type ); mop->call_static_cfn( REF, f, (uintptr_t)&closure_close, NULL , 1 , base ); release_temp( mop, REF, f->m ); } unsigned int pc = (int)REF->ops->pc( REF ) + offset + 1; mop->b( REF, f->m, LBL_PC( pc ) ); }