Example #1
0
// 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 );
}
Example #2
0
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 );
}
Example #3
0
static operand pslot_to_operand( struct frame* f, int nr_locals, int pidx, bool stackonly ){
	assert( f );
	assert( f->m );

	if( stackonly || pidx >= NR_SPARE_REGS( f ) ){
#if 0
		operand r = OP_TARGETDADDR( f->m->sp, 4 * INVERSE( pidx,  2 * nr_locals ) );
#else
		operand r = OP_TARGETDADDR( f->m->fp, -(8 + 4 * pidx) );
#endif
		return r;
	} else {
		operand r = OP_TARGETREG( vreg_to_physical_reg( f, pidx ) );
		return r;
	}
			
} 
Example #4
0
static void do_niling( struct machine_ops* mop, struct emitter* e, struct machine* m, 
		operand iter, operand limit, operand dst, operand src ){

	// start loop 
	e->ops->label_local( e, 0 );
	mop->beq( e, m, iter, limit, LBL_NEXT( 0 ) ); 	// TODO: bgt is equiv to beq so swap? 

	// copy 
	mop->move( e, m, OP_TARGETDADDR( dst.reg, 0 ), OP_TARGETDADDR( src.reg, 0 ) );
	mop->move( e, m, OP_TARGETDADDR( dst.reg, -4 ), OP_TARGETDADDR( src.reg, -4 ) );
	
	// update pointers 
	mop->add( e, m, dst, dst, OP_TARGETIMMED( -8 ) );	
	mop->add( e, m, src, src, OP_TARGETIMMED( -8 ) ); 
	
	// update iterator
	mop->add( e, m, iter, iter, OP_TARGETIMMED( 1 ) );
	
	mop->b( e, m, LBL_PREV( 0 ) );
	e->ops->label_local( e, 0 );
}
Example #5
0
void popn( struct machine_ops* mop, struct emitter* e, struct machine* m, int nr_operands, ... ){
	va_list ap;
	const operand stack = OP_TARGETREG( m->sp );

	va_start( ap, nr_operands );

	if( nr_operands == 1 && mop->pop ){
		mop->pop( e, m, va_arg( ap, operand ) );
	} else {
		for( int i = 0; i < nr_operands; i++ )
			mop->move( e, m, va_arg( ap, operand ), OP_TARGETDADDR( m->sp, 4 * i ) );
		
		mop->add( e, m, stack, stack, OP_TARGETIMMED( 4 * nr_operands ) ); 
	}

	va_end( ap );
}
Example #6
0
operand get_frame_closure( struct frame* f ){
	return OP_TARGETDADDR( f->m->fp, -4 );
}
Example #7
0
void jinit_epi( struct JFunc* jf, struct machine_ops* mop, struct emitter* e, struct machine* m ){
	// phoney frame 
	struct frame F = { .m = m, .nr_locals = 1, .nr_params = 0 };
	struct frame *f = &F;

	const operand sp = OP_TARGETREG( m->sp );
	const operand fp = OP_TARGETREG( m->fp );

	operand rargs[ RA_SIZE ];
	prefer_nontemp_acquire_reg( mop, e, f->m, RA_SIZE, rargs );

	// reset stack 
//	mop->move( e, m, sp, fp );
	mop->add( e, m, sp, fp, OP_TARGETIMMED( -4 ) );
	if( m->is_ra ) 
		popn( mop, e, m , 3, rargs[ RA_DST ], fp, OP_TARGETREG( m->ra ) );
	else
		popn( mop, e, m, 2, rargs[ RA_DST ], fp ); 
//		pop( mop, e, m, fp );

	mop->ret( e, m );
	
	prefer_nontemp_release_reg( mop, e, f->m, RA_SIZE );
}

/*
* Do the majority ( function independent ) part of the prologue. That is: store the frame section,
* update src and dst pointers and call the memcpy.
*
* The function specific code needs to set the number of params, update the stack ( requires # of locals )
* and then unspill params.  
*/
void jinit_pro( struct JFunc* jf, struct machine_ops* mop, struct emitter* e, struct machine* m ){
	// phoney frame 
	struct frame F = { .m = m, .nr_locals = 1, .nr_params = 0 };
	struct frame *f = &F;

	const operand sp = OP_TARGETREG( f->m->sp );
	const operand fp = OP_TARGETREG( f->m->fp );
	const vreg_operand basestack = vreg_to_operand( f, 0, true );		// destination is first local
	const int maxstack = JFUNC_UNLIMITED_STACK; 
	
	operand rargs[ RA_SIZE ];
	prefer_nontemp_acquire_reg( mop, e, f->m, RA_SIZE, rargs );

	// push old frame pointer, closure addr / result start addr, expected nr or results 
	if( f->m->is_ra )
		pushn( mop, e, f->m, 3, OP_TARGETREG( f->m->ra), fp, rargs[ RA_SRC ] ); 
	else
		pushn( mop, e, f->m, 2, fp, rargs[ RA_SRC ] ); 
	
	// set ebp and update stack
	mop->add( e, f->m, fp, sp, OP_TARGETIMMED( 4 ) );	// point to ebp so add 4 

	// set src ( always start after closure see Lua VM for reason )
	mop->add( e, f->m, rargs[ RA_SRC ], rargs[ RA_SRC ], OP_TARGETIMMED( -8 ) );
	mop->add( e, f->m, rargs[ RA_DST ], OP_TARGETREG( basestack.value.base ), OP_TARGETIMMED( basestack.value.offset ) );
		

	/*
	* Call the actual function, which is the closure. On RISC this will clobber
	* temp hopefully this isn't a live reg or we will get exception. On CISC
	* there is probably indirect direct address jmp instruction ( x86 does 0 ). 
	*/
	mop->b( e, f->m, LBL_ABS( OP_TARGETDADDR( rargs[ RA_SRC ].reg, 8 ) ) );

	prefer_nontemp_release_reg( mop, e, f->m, RA_SIZE );

}

/*
* The number of results is not know before hand. Need to update stack for future
* calls.
*/
void jinit_vresult_postcall( struct JFunc* jf, struct machine_ops* mop, struct emitter* e, struct machine* m ){
	// phoney frame 
	struct frame F = { .m = m, .nr_locals = 1, .nr_params = 0 };
	struct frame *f = &F;

	operand rargs[ RA_SIZE ];
	prefer_nontemp_acquire_reg( mop, e, f->m, RA_SIZE, rargs );

	// max stack clobber 
	const int maxstack = 3;	// prior frame has buffer of pushed return addr, frame pointer and closure

	// consume as many results as available 
	mop->move( e, f->m, rargs[ RA_EXPECT ], rargs[ RA_EXIST ] );
	
	// if register based remember return address 
	if( f->m->is_ra )
		pushn( mop, e, f->m, 1, OP_TARGETREG( f->m->ra) );	// not safe cause of stack

	// copy args across 
	jfunc_call( mop, e, f->m, JF_ARG_RES_CPY, 0, maxstack, 4, rargs[ RA_SRC ], rargs[ RA_DST ], 
						rargs[ RA_EXPECT ], rargs[ RA_EXIST ] );

	if( f->m->is_ra )
		popn( mop, e, f->m, 1, OP_TARGETREG( f->m->ra) );

	
	/*
	* this depends heavily on copy arg implementation, it assumes ptrs will point to 
	* the top of the stack after copying i.e. the last result copied.
	*/
	mop->add( e, m, OP_TARGETREG( f->m->sp ), rargs[ RA_DST ], OP_TARGETIMMED( 0 ) ); 

	prefer_nontemp_release_reg( mop, e, f->m, RA_SIZE );

	// return 
	mop->ret( e, m );

	
}