// i386-emit.hg -- PowerPC instruction output macros		-*- C++ -*-
//
// Authors: Ian.Piumarta@INRIA.Fr, marcus@ira.uka.de
//
// Last edited: 2000-12-07 18:11:34 by mdenker on cologne.rd.wdi.disney.com

#ifndef _j_i386_emit_h
#define _j_i386_emit_h


#include "archdep.h"

#define _ASM_LOCALPC /* #localpc */
#include "ccg/asm-i386.h" /* #cpu i386 */
/* #escape ! */
/* #comment ; */

#include "i386-defs.h"
#include "i386-Frame.h"

#include "NativeMethod.h"

// optimiser GP and temp registers

extern int reg[];
extern int tmp[];

// temps

extern int tmpr1;
extern int tmpr2;
extern int tmpr3;

///
/// Debugging
///

#define emit_save_regs()   _ASM_APP_1 \
	PUSHLr	(_EAX); \
	PUSHLr	(_ECX); \
	PUSHLr	(_EDX); \
  _ASM_NOAPP_1

#define emit_restore_regs()   _ASM_APP_1 \
	POPLr	(_EDX); \
	POPLr	(_ECX); \
	POPLr	(_EAX); \
  _ASM_NOAPP_1	

#define emit_print_str(string)			\
  char * mystr = (string);			\
  emit_save_regs();				\
    _ASM_APP_1 \
	PUSHLi	((int)mystr); \
	CALLm	(printf,0,0,0); \
	ADDLir	(4, _ESP); \
  _ASM_NOAPP_1						\
  emit_restore_regs();				\


#define emit_print_str_arg(string, arg1) 	\
  char * mystr = (string);			\
  int myarg = (arg1);				\
  emit_save_regs();				\
    _ASM_APP_1 \
	PUSHLi	((int)myarg); \
	PUSHLi	((int)mystr); \
	CALLm	(printf,0,0,0); \
	ADDLir	(8, _ESP); \
  _ASM_NOAPP_1						\
  emit_restore_regs();

#define emit_print_str_reg(string, reg) 	\
  char * mystr = (string);			\
  emit_save_regs();				\
    _ASM_APP_1 \
	PUSHLr	((reg)); \
	PUSHLi	((int)mystr); \
	CALLm	(printf,0,0,0); \
	ADDLir	(8, _ESP); \
  _ASM_NOAPP_1						\
  emit_restore_regs();				

#define emit_print_oop_reg(reg)			\
  emit_save_regs();				\
    _ASM_APP_1 \
	PUSHLr	((reg)); \
	CALLm	(printOop,0,0,0); \
	ADDLir	(4, _ESP); \
  _ASM_NOAPP_1						\
  emit_restore_regs();				\

	 

///
/// data movement
///


#define emit_move_r_r(s,d)   _ASM_APP_1 \
	MOVLrr	((s), (d)); \
  _ASM_NOAPP_1

#define emit_move_s_r(imm, rn)			\
  emit_move_i_r(imm, rn)

#define emit_move_l_r(imm, rn)			\
  emit_move_i_r(imm, rn)

#define emit_move_i_r(imm,rn)   _ASM_APP_1 \
	MOVLir	(((int)(imm)), (rn)); \
  _ASM_NOAPP_1

#define emit_move_R_r(rd)   _ASM_APP_1 \
	MOVLmr	(f_receiver_off,(FP),0,0, (rd)); \
  _ASM_NOAPP_1

#define emit_b_move_R_r(rn)   _ASM_APP_1 \
	MOVLmr	(f_receiver_off,(FP),0,0, (rn)); \
	MOVLmr	(mx_receiver_off,(rn),0,0, (rn)); \
  _ASM_NOAPP_1

#define emit_move_v_r(v,rd)   _ASM_APP_1 \
	MOVLmr	(((int)&(v)),0,0,0, (rd)); \
  _ASM_NOAPP_1

#define emit_move_r_v(r, v)   _ASM_APP_1 \
	MOVLrm	((r), ((int)&(v)),0,0,0); \
  _ASM_NOAPP_1

#define emit_move_i_v(imm, var)   _ASM_APP_1 \
	MOVLim	(((int)(imm)), ((int)&(var)),0,0,0); \
  _ASM_NOAPP_1


#ifdef USE_GLOBAL_PTR

#define emit_move_N_r(rn)   _ASM_APP_1 \
	MOVLmr	(gp_nilObj_off,(GP),0,0, (rn)); \
  _ASM_NOAPP_1

#define emit_move_0_r(rn)   _ASM_APP_1 \
	MOVLmr	(gp_falseObj_off,(GP),0,0, (rn)); \
  _ASM_NOAPP_1

#define emit_move_1_r(rn)   _ASM_APP_1 \
	MOVLmr	(gp_trueObj_off,(GP),0,0, (rn)); \
  _ASM_NOAPP_1

#else // !USE_GLOBAL_PTR

#define emit_move_N_r(rn)   _ASM_APP_1 \
	MOVLmr	(((int)&nilObj),0,0,0, (rn)); \
  _ASM_NOAPP_1

#define emit_move_1_r(rn)   _ASM_APP_1 \
	MOVLmr	(((int)&trueObj),0,0,0, (rn)); \
  _ASM_NOAPP_1

#define emit_move_0_r(rn)   _ASM_APP_1 \
	MOVLmr	(((int)&falseObj),0,0,0, (rn)); \
  _ASM_NOAPP_1

#endif // USE_GLOBAL_PTR

#define emit_move_I_r(idx, rd)   _ASM_APP_1 \
	MOVLmr	(f_receiver_off,(FP),0,0, (rd)); \
	MOVLmr	(((idx+1)*4),(rd),0,0, (rd)); \
  _ASM_NOAPP_1

#define emit_b_move_I_r(idx, rd)   _ASM_APP_1 \
	MOVLmr	(f_receiver_off,(FP),0,0, (rd)); \
	MOVLmr	(mx_receiver_off,(rd),0,0, (rd)); \
	MOVLmr	(((idx+1)*4),(rd),0,0, (rd)); \
  _ASM_NOAPP_1

#ifdef STACK_GROWS_DOWN

# define emit_move_T_r(idx, rd)   _ASM_APP_1 \
	MOVLmr	((f_stack_off+(LargeFrame*4)-4-(idx*4)),(FP),0,0, (rd)); \
  _ASM_NOAPP_1

# define emit_move_r_T(rs, idx)   _ASM_APP_1 \
	MOVLrm	((rs), (f_stack_off+(LargeFrame*4)-4-(idx*4)),(FP),0,0); \
  _ASM_NOAPP_1

#else // !STACK_GROWS_DOWN

# define emit_move_T_r(idx, rd)   _ASM_APP_1 \
	MOVLmr	((f_stack_off+(idx*4)),(FP),0,0, (rd)); \
  _ASM_NOAPP_1

# define emit_move_r_T(rs, idx)   _ASM_APP_1 \
	MOVLrm	((rs), (f_stack_off+(idx*4)),(FP),0,0); \
  _ASM_NOAPP_1

#endif // STACK_GROWS_DOWN

// only tmp[1] not used as parameter... ups.
#define emit_move_L_r(idx, rd)   _ASM_APP_1 \
assert( (rd) != _ESI );			\
	PUSHLr	((tmp[1])); \
	MOVLmr	(f_nmeth_off,(FP),0,0, (tmp[1])); \
	ANDLir	((((1<<29-0+1)-1)<<2), (tmp[1])); \
	MOVLmr	(nm_methodIndex_off,(tmp[1]),0,0, (tmp[1])); \
	MOVLrm	((tmp[1]), ((int)&tmpr1),0,0,0); \
	ROLLir	(18, (tmp[1])); \
	ANDLir	((((1<<(29-14+1))-1)<<2), (tmp[1])); \
	ADDLir	(4, (tmp[1])); \
	ADDLmr	(((int)&methodMemoizer),0,0,0, (tmp[1])); \
	MOVLmr	(0,(tmp[1]),0,0, (tmp[1])); \
	ROLLim	(2, ((int)&tmpr1),0,0,0); \
	ANDLim	((((1<<(29-14+1))-1)<<2), ((int)&tmpr1),0,0,0); \
	ADDLim	(4, ((int)&tmpr1),0,0,0); \
	ADDLmr	(((int)&tmpr1),0,0,0, (tmp[1])); \
	MOVLmr	(0,(tmp[1]),0,0, (tmp[1])); \
	MOVLmr	(((idx+2)*4),(tmp[1]),0,0, (rd)); \
	POPLr	((tmp[1])); \
  _ASM_NOAPP_1

#define emit_b_move_L_r(idx, rd)   _ASM_APP_1 \
	MOVLmr	(f_receiver_off,(FP),0,0, (rd)); \
	MOVLmr	(mx_method_off,(rd),0,0, (rd)); \
	MOVLmr	(((idx+2)*4),(rd),0,0, (rd)); \
  _ASM_NOAPP_1


#define emit_move_F_r(rd)   _ASM_APP_1 \
	MOVLrr	((FP), (rd)); \
  _ASM_NOAPP_1


// 
// tag manipulation
// 

#define emit_posck_r_r_t(ra, rb, tr)   _ASM_APP_1 \
	TESTLir	(0, (ra)); \
	JLEm	(tr,0,0,0); \
	TESTLir	(0, (rb)); \
	JLEm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_tagck_r_t(ra, tr)   _ASM_APP_1 \
	TESTLir	(1, (ra)); \
	JEm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_tagck_r(ra)   _ASM_APP_1 \
	TESTLir	(1, (ra)); \
  _ASM_NOAPP_1


#define emit_taggeck_r_r_t(ra, rb, tr)   _ASM_APP_1 \
	TESTLir	(1, (ra)); \
	JEm	(tr,0,0,0); \
	TESTLir	(1, (rb)); \
	JEm	(tr,0,0,0); \
	CMPLir	(0, (ra)); \
	JLEm	(tr,0,0,0); \
	CMPLir	(0, (rb)); \
	JLEm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_taggeck_r_t(rn, tr)   _ASM_APP_1 \
	TESTLir	(1, (rn)); \
	JEm	(tr,0,0,0); \
	CMPLir	(0, (rn)); \
	JLm	(tr,0,0,0); \
  _ASM_NOAPP_1


#define emit_tagck_r_r_t(ra, rb, tr)   _ASM_APP_1 \
	TESTLir	(1, (ra)); \
	JEm	(tr,0,0,0); \
	TESTLir	(1, (rb)); \
	JEm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_untag_r_r(rs, rd)   _ASM_APP_1 \
	MOVLrr	((rs), (rd)); \
	SHRLir	(1, (rd)); \
  _ASM_NOAPP_1

#define emit_untag_r(rn)   _ASM_APP_1 \
	SHRLir	(1, (rn)); \
  _ASM_NOAPP_1

#define emit_untagnzck_r_r_t(rs, rd, tr)   _ASM_APP_1 \
	MOVLrr	((rs), (rd)); \
	SHRLir	(1, (rd)); \
	JZm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_untagnzck_r_t(rn, tr)   _ASM_APP_1 \
	SHRLir	(1, (rn)); \
	JZm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_untaggeck_r_r_t(rs, rd, tr)   _ASM_APP_1 \
	MOVLrr	((rs), (rd)); \
	SHRLir	(1, (rd)); \
	JLm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_untaggeck_r_t(rn, tr)   _ASM_APP_1 \
	SHRLir	(1, (rn)); \
	JLm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_untaggtck_r_r_t(rs, rd, tr)   _ASM_APP_1 \
	MOVLrr	((rs), (rd)); \
	SHRLir	(1, (rd)); \
	JLEm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_untaggtck_r_t(rn, tr)   _ASM_APP_1 \
	SHRLir	(1, (rn)); \
	JLEm	(tr,0,0,0); \
  _ASM_NOAPP_1


#define emit_entag_r_r(rs, rd)   _ASM_APP_1 \
	MOVLrr	((rs), (rd)); \
	SHLLir	(1, (rd)); \
	ORLir	(1, (rd)); \
  _ASM_NOAPP_1

#define emit_entag_r(rn)   _ASM_APP_1 \
	SHLLir	(1, (rn)); \
	ORLir	(1, (rn)); \
  _ASM_NOAPP_1


#define emit_intck_r_t(rs, tr)   _ASM_APP_1 \
	MOVLrm	((rs), ((int)&tmpr1),0,0,0); \
	SHLLim	(1, ((int)&tmpr1),0,0,0); \
	XORLrm	((rs), ((int)&tmpr1),0,0,0); \
	JLm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_entagintck_r_r_t(rs, rd, tr)   _ASM_APP_1 \
	MOVLrm	((rs), ((int)&tmpr1),0,0,0); \
	SHLLim	(1, ((int)&tmpr1),0,0,0); \
	XORLrm	((rs), ((int)&tmpr1),0,0,0); \
	JLm	(tr,0,0,0); \
	MOVLrr	((rs), (rd)); \
	SHLLir	(1, (rd)); \
	ORLir	(1, (rd)); \
  _ASM_NOAPP_1

#define emit_entagintck_r_t(rn, tr)   _ASM_APP_1 \
	MOVLrm	((rn), ((int)&tmpr1),0,0,0); \
	SHLLim	(1, ((int)&tmpr1),0,0,0); \
	XORLrm	((rn), ((int)&tmpr1),0,0,0); \
	JLm	(tr,0,0,0); \
	SHLLir	(1, (rn)); \
	ORLir	(1, (rn)); \
  _ASM_NOAPP_1

#define emit_notagck_r_t(ra, tr)   _ASM_APP_1 \
	TESTLir	(1, (ra)); \
	JNEm	(tr,0,0,0); \
  _ASM_NOAPP_1

///
/// arithmetic and logical
///

#define emit_add_r_r(rs, rd)   _ASM_APP_1 \
	ADDLrr	((rs), (rd)); \
  _ASM_NOAPP_1


#define emit_neg_r(rd)   _ASM_APP_1 \
	NEGLr	((rd)); \
  _ASM_NOAPP_1


#define emit_add_i_r(i,r)   _ASM_APP_1 \
	ADDLir	(((int)(i)), (r)); \
  _ASM_NOAPP_1

#define emit_sub_i_r(i,r)   _ASM_APP_1 \
	SUBLir	(((int)(i)), (r)); \
  _ASM_NOAPP_1

#define emit_sub_r_r(rs, rd)   _ASM_APP_1 \
	SUBLrr	((rs), (rd)); \
  _ASM_NOAPP_1

#define emit_mul_r_r_t(rs, rd, tr)   _ASM_APP_1 \
	IMULLrr	((rs), (rd)); \
	JOm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_mul_i_r_t(im, rd, tr)   _ASM_APP_1 \
	IMULLirr	((im), (rd), (rd)); \
	JOm	(tr,0,0,0); \
  _ASM_NOAPP_1

#define emit_div_r_r(rs, rd)   _ASM_APP_1 \
assert( (rs) != _EAX );			\
assert( (rs) != _EDX );			\
assert( (rd) != _EAX );			\
assert( (rd) != _EDX );			\
	PUSHLr	(_EAX); \
	PUSHLr	(_EDX); \
	MOVLrr	((rd), _EAX); \
	CWD	(); \
	IDIVLrr	((rs), _EAX); \
	MOVLrr	(_EAX, (rd)); \
	POPLr	(_EDX); \
	POPLr	(_EAX); \
  _ASM_NOAPP_1

#define emit_div_i_r(im, rd)   _ASM_APP_1 \
assert( (rd) != _EDX );			\
assert( (rd) != _ESI );			\
assert( (rd) != _EAX );			\
	PUSHLr	(_ESI); \
	PUSHLr	(_EAX); \
	PUSHLr	(_EDX); \
	MOVLrr	((rd), _EAX); \
	CWD	(); \
	MOVLir	((im), _ESI); \
	IDIVLrr	(_ESI, _EAX); \
	MOVLrr	(_EAX, (rd)); \
	POPLr	(_EDX); \
	POPLr	(_EAX); \
	POPLr	(_ESI); \
  _ASM_NOAPP_1

#define emit_mod_r_r(rs, rd)   _ASM_APP_1 \
assert( (rs) != _EAX );			\
assert( (rs) != _EDX );			\
assert( (rd) != _EAX );			\
assert( (rd) != _EDX );			\
	PUSHLr	(_EAX); \
	PUSHLr	(_EDX); \
	MOVLrr	((rd), _EAX); \
	CWD	(); \
	IDIVLrr	((rs), _EAX); \
	MOVLrr	(_EDX, (rd)); \
	POPLr	(_EDX); \
	POPLr	(_EAX); \
  _ASM_NOAPP_1


#define emit_mod_i_r(imm, rd)   _ASM_APP_1 \
assert( (rd) != _EAX );			\
assert( (rd) != _EDX );			\
assert( (rd) != _ESI );			\
	PUSHLr	(_ESI); \
	PUSHLr	(_EAX); \
	PUSHLr	(_EDX); \
	MOVLrr	((rd), _EAX); \
	MOVLir	((imm), _ESI); \
	CWD	(); \
	IDIVLrr	(_ESI, _EAX); \
	MOVLrr	(_EDX, (rd)); \
	POPLr	(_EDX); \
	POPLr	(_EAX); \
	POPLr	(_ESI); \
  _ASM_NOAPP_1


#define emit_test_r(rn)   _ASM_APP_1 \
	CMPLir	(0, (rn)); \
  _ASM_NOAPP_1

#define emit_test_v(var)   _ASM_APP_1 \
	CMPLim	(0, ((int)&var),0,0,0); \
  _ASM_NOAPP_1


// tagged addition and subtraction
// 
// NOTE: Some architectures provide an overflow condition suitable for
// performing aritmetic on tagged quantities with the tag bit in place
// and with overflow subsuming the integer value check on the final
// result.  Such architectures should define insn output macros for
// emit_t{add,sub}_[ir]_r_r_t() to benefit from better integer
// aritmetic code.  These macros are optional: if they are not defined
// then the optimiser will generate explicit untag, regular add/sub,
// integer value check and entag sequences as appropriate.

#undef emit_tadd_r_r_r_t // (a, b, d, tr)
#undef emit_tadd_i_r_r_t // (im, s, d, tr) 
#undef emit_tsub_r_r_r_t // (a, b, d, tr) 
#undef emit_tsub_i_r_r_t // (im, s, d, tr) 

// NOTE: comparisons are always such that the branch in
//		cmp(lhs, rhs)
//		b<cond>(dest)
// will be taken if the relation
//		lhs <cond> rhs
// holds.
// 
// NOTE: Since some architectures do not have symmetric comparisons
// involving immediate operands, only one of cmp_r_i and cmp_i_r need
// be defined (the one that is cheapest to implement according to the
// above definition).  The optimiser will invert branch conditions
// whenever necessary to use the preferred operand order, when one
// operand is immediate, based on which of the two cmp_[ir]_[ri]
// macros is defined.  (Of course, defining both of them on symmetric
// architectures is perfectly legal.)

#define emit_cmp_r_r(rl,rr)   _ASM_APP_1 \
	CMPLrr	((rr), (rl)); \
  _ASM_NOAPP_1

#define emit_cmp_r_s(rl, ir)   _ASM_APP_1 \
	CMPLir	((ir), (rl)); \
  _ASM_NOAPP_1

#define emit_cmp_r_l(rl, ir)   _ASM_APP_1 \
	CMPLir	((ir), (rl)); \
  _ASM_NOAPP_1

#define emit_cmp_r_i(rl, ir)    _ASM_APP_1 \
	CMPLir	((ir), (rl)); \
  _ASM_NOAPP_1

#define emit_cmp_0_r(rn)   _ASM_APP_1 \
	CMPLir	(0, (rn)); \
  _ASM_NOAPP_1

#define emit_cmp_1_r(rn)   _ASM_APP_1 \
	CMPLir	(1, (rn)); \
  _ASM_NOAPP_1

#define emit_and_r_r(rs, rd)   _ASM_APP_1 \
	ANDLrr	((rs), (rd)); \
  _ASM_NOAPP_1

#define emit_and_i_r(imm, rd)   _ASM_APP_1 \
	ANDLir	(((int)imm), (rd)); \
  _ASM_NOAPP_1

#define emit_or_i_r(imm, rd)   _ASM_APP_1 \
	ORLir	(((int)imm), (rd)); \
  _ASM_NOAPP_1

#define emit_or_r_r(rs, rd)   _ASM_APP_1 \
	ORLrr	((rs), (rd)); \
  _ASM_NOAPP_1

#define emit_xor_r_r(rs, rd)   _ASM_APP_1 \
	XORLrr	((rs), (rd)); \
  _ASM_NOAPP_1

#define emit_lsl_i_r(imm, rd)   _ASM_APP_1 \
	SHLLir	((imm), (rd)); \
  _ASM_NOAPP_1

#define emit_lsr_i_r(imm, rd)   _ASM_APP_1 \
	SHRLir	((imm), (rd)); \
  _ASM_NOAPP_1

#define emit_lsr_i_r_r(imm, rs, rd)   _ASM_APP_1 \
	MOVLrr	((rs), (rd)); \
	SHRLir	((imm), (rd)); \
  _ASM_NOAPP_1

// BitFieldTeST(lsbit, width, reg)
#define emit_bftst_i_i_r(b0, bw, rn)   _ASM_APP_1 \
	TESTLir	((((1<<(bw))-1)<<(b0)), (rn)); \
  _ASM_NOAPP_1

// BitFieldMaSK(lsbit, width, reg)
#define emit_bfmsk_i_i_r_r(b0, bw, rs, rd)   _ASM_APP_1 \
	MOVLrr	((rs), (rd)); \
	ANDLir	((((1<<(bw))-1)<<(b0)), (rd)); \
  _ASM_NOAPP_1

#define emit_bfmsk_i_i_r(b0, bw, rn)    _ASM_APP_1 \
	ANDLir	((((1<<(bw))-1)<<(b0)), (r)); \
  _ASM_NOAPP_1

// BitFieldEXTract(lsbit, width, src, dst)
#define emit_bfext_i_i_r_r(b0, bw, rs, rd)   _ASM_APP_1 \
	MOVLrr	((rs), (rd)); \
	ANDLir	((((1<<(bw))-1)<<(b0)), (rd)); \
  _ASM_NOAPP_1

// BitFieldEXTractSHiftLeft(lsbit, width, shift, rn)
#define emit_bfextshl_i_i_i_r(b0, bw, sh, rd)   _ASM_APP_1 \
	ANDLir	((((1<<(bw))-1)<<(b0)), (rd)); \
  _ASM_NOAPP_1;								\
  if ((b0) != (sh)) {						\
     if ((b0) < (sh))						\
	  _ASM_APP_1   	SHLLir	(((sh)-(b0)), (rd)); _ASM_NOAPP_1				\
     else							\
         _ASM_APP_1   	SHRLir	(((b0)-(sh)), (rd)); _ASM_NOAPP_1				\
    }

#define emit_bfextshl_i_i_i_r_r(b0, bw, sh, rs, rd)		\
    _ASM_APP_1   	MOVLrr	((rs), (rd)); _ASM_NOAPP_1				\
  emit_bfextshl_i_i_i_r(b0, bw, sh, rd)

// BitFieldCLeaR(lsbit, width, dst)
#define emit_bfclr_i_i_r(b0, bw, rd)   _ASM_APP_1 \
	ANDLir	((~(((1<<(bw))-1)<<(b0))), (rd)); \
  _ASM_NOAPP_1

/// 
/// object access
/// 

#define emit_rootck_r(rs)   _ASM_APP_1 \
	TESTLir	((Object::RootBit), (rs)); \
  _ASM_NOAPP_1

#define emit_setroot_r(rd)   _ASM_APP_1 \
	ORLir	((Object::RootBit), (rd)); \
  _ASM_NOAPP_1

#define emit_ccick_i_r(cci, rs)	  _ASM_APP_1 \
	MOVLrm	((rs), ((int)&tmpr1),0,0,0); \
	ANDLim	((Object::ccMask), ((int)&tmpr1),0,0,0); \
	CMPLim	(((cci)<<12), ((int)&tmpr1),0,0,0); \
  _ASM_NOAPP_1

#define emit_get_i_r_r(off, rs, rd)   _ASM_APP_1 \
	MOVLmr	(((int)off),(rs),0,0, (rd)); \
  _ASM_NOAPP_1

#define emit_put_r_i_r(rs, off, rd)   _ASM_APP_1 \
	MOVLrm	((rs), ((int)off),(rd),0,0); \
  _ASM_NOAPP_1

#define emit_get_r_r_r(ri, rs, rd)   _ASM_APP_1 \
	MOVLmr	(0,(rs),(ri),1, (rd)); \
  _ASM_NOAPP_1

#define emit_put_r_r_r(rs, ri, rd)   _ASM_APP_1 \
	MOVLrm	((rs), 0,(rd),(ri),1); \
  _ASM_NOAPP_1

#define emit_rput_r_r_r(rs, ri, rd)   _ASM_APP_1 \
assert( (ri) != _EAX );			\
assert( (rd) != _EAX );			\
	PUSHLr	(_EAX); \
	MOVLrr	((rs), _EAX); \
	BSWAPr	(_EAX); \
	MOVLrm	(_EAX, 0,(rd),(ri),1); \
	POPLr	(_EAX); \
  _ASM_NOAPP_1

#define emit_getb_r_r_r(ri, rs, rd)   _ASM_APP_1 \
	MOVBmr	(0,(rs),(ri),1, (rd)); \
  _ASM_NOAPP_1

#define emit_putb_r_r_r(rs, ri, rd)   _ASM_APP_1 \
	MOVBrm	((rs), 0,(rd),(ri),1); \
  _ASM_NOAPP_1

///
/// stack manipulation
///


#ifdef STACK_GROWS_DOWN

#define emit_drop(nItems)   _ASM_APP_1 \
	ADDLir	(((int)(4*nItems)), (SP)); \
  _ASM_NOAPP_1

#define emit_pop_r(r)   _ASM_APP_1 \
	MOVLmr	(0,(SP),0,0, (r)); \
	ADDLir	(4, (SP)); \
  _ASM_NOAPP_1

#define emit_move_popS_r(idx, rd)   _ASM_APP_1 \
	MOVLmr	((4*(idx)),(SP),0,0, (rd)); \
	ADDLir	((4*(idx)), (SP)); \
  _ASM_NOAPP_1

#define emit_move_r_popS(rn, idx)   _ASM_APP_1 \
	MOVLrm	((rn), ((idx)*4),(SP),0,0); \
	ADDLir	(((int)(4*(idx))), (SP)); \
  _ASM_NOAPP_1

#define emit_move_S_r(idx, rn)   _ASM_APP_1 \
	MOVLmr	((4*(idx)),(SP),0,0, (rn)); \
  _ASM_NOAPP_1

#define emit_move_r_S(rn, idx)   _ASM_APP_1 \
	MOVLrm	((rn), (4*(idx)),(SP),0,0); \
  _ASM_NOAPP_1

#define emit_push_r(r)   _ASM_APP_1 \
	SUBLir	(4, (SP)); \
	MOVLrm	((r), 0,(SP),0,0); \
  _ASM_NOAPP_1

#else // !STACK_GROWS_DOWN

#define emit_drop(nItems)   _ASM_APP_1 \
	SUBLir	(((int)(4*nItems)), (SP)); \
  _ASM_NOAPP_1


#define emit_pop_r(r)   _ASM_APP_1 \
	MOVLmr	(0,(SP),0,0, (r)); \
	SUBLir	(4, (SP)); \
  _ASM_NOAPP_1

#define emit_move_popS_r(idx, rd)   _ASM_APP_1 \
	MOVLmr	((-4*(idx)),(SP),0,0, (rd)); \
	SUBLim	((4*(idx)), 0,(SP),0,0); \
  _ASM_NOAPP_1

#define emit_move_r_popS(rn, idx)   _ASM_APP_1 \
	MOVLrm	((rn), (-4*(idx)),(SP),0,0); \
	SUBLir	((4*(idx)), (SP)); \
  _ASM_NOAPP_1

#define emit_move_S_r(idx, rn)   _ASM_APP_1 \
	MOVLmr	((-4*(idx)),(SP),0,0, (rn)); \
  _ASM_NOAPP_1

#define emit_move_r_S(rn, idx)   _ASM_APP_1 \
	MOVLrm	((rn), (-4*(idx)),(SP),0,0); \
  _ASM_NOAPP_1

#define emit_push_r(r)   _ASM_APP_1 \
	ADDLir	(4, (SP)); \
	MOVLrm	((r), 0,(SP),0,0); \
  _ASM_NOAPP_1

#endif // !STACK_GROWS_DOWN


///
/// calls (method or glue)
/// 

# define emit_initcall(dest)

# define emit_execcall(dest)   _ASM_APP_1 \
	CALLm	(dest,0,0,0); \
assert (dest!=0); \
  _ASM_NOAPP_1

# define emit_execjmp(dest)   _ASM_APP_1 \
	JMPm	(dest,0,0,0); \
  _ASM_NOAPP_1

#define emit_call(dest)				\
  emit_initcall(dest);				\
  emit_execcall(dest)
	
#define emit_call_l(dest, arg)			\
  emit_initcall(dest);				\
    _ASM_APP_1 \
	MOVLir	(((int)arg), (reg[1])); \
  _ASM_NOAPP_1;						\
  emit_execcall(dest)
  
#define emit_call_s(dest, arg)  emit_call_l(dest, arg)

#define emit_lcall_l(send, patch, dest, arg)   _ASM_APP_1 \
	PUSHLi	(((int)(send))); \
	MOVLir	(((int)(patch)), (reg[2])); \
	MOVLir	(((int)(arg)), (reg[1])); \
	JMPm	(dest,0,0,0); \
  _ASM_NOAPP_1

#define emit_initccall(dest)

#define emit_execccall(dest)   _ASM_APP_1 \
	CALLm	(dest,0,0,0); \
  _ASM_NOAPP_1

#define emit_ccall(dest)			\
	emit_initccall(dest)			\
	emit_execccall(dest)

#define emit_retck_t(trap)   _ASM_APP_1 \
	CMPLim	(0, f_sender_off,(FP),0,0); \
	JEm	(trap,0,0,0); \
	CMPLim	(0, f_pseudo_off,(FP),0,0); \
	JNEm	(trap,0,0,0); \
  _ASM_NOAPP_1

#define emit_savepc()    _ASM_APP_1 \
	POPLm	(f_pc_off,(FP),0,0); \
  _ASM_NOAPP_1

#define emit_savepc_r(rs)   _ASM_APP_1 \
	MOVLrm	((rs), f_pc_off,(FP),0,0); \
  _ASM_NOAPP_1

#define emit_restorepc()   _ASM_APP_1 \
	PUSHLm	(f_pc_off,(FP),0,0); \
  _ASM_NOAPP_1

#define emit_extern()   _ASM_APP_1 \
	MOVLrm	((SP), f_stackp_off,(FP),0,0); \
  _ASM_NOAPP_1

#define emit_externp()	  _ASM_APP_1 \
	MOVLrm	((SP), ((int)&stackPointer),0,0,0); \
  _ASM_NOAPP_1

#define emit_popf()   _ASM_APP_1 \
	PUSHLm	((f_pc_off+sizeof(Frame)),(FP),0,0); \
	LEALmr	((sizeof(Frame)),(FP),0,0, (FP)); \
  _ASM_NOAPP_1

#define emit_popfto_r(rfp)   _ASM_APP_1 \
	PUSHLm	(f_pc_off,(rfp),0,0); \
	MOVLrr	((rfp), (FP)); \
  _ASM_NOAPP_1

#define emit_intern()   _ASM_APP_1 \
	MOVLmr	(f_stackp_off,(FP),0,0, (SP)); \
  _ASM_NOAPP_1

#define emit_internp()   _ASM_APP_1 \
	MOVLmr	(((int)stackPointer),0,0,0, (SP)); \
  _ASM_NOAPP_1

#define emit_resume()   _ASM_APP_1 \
	RET	(); \
  _ASM_NOAPP_1

#define emit_resume_ne(retinsn)   _ASM_APP_2 \
  _ASM_LBL(cont_ne);\
	JEm	(cont_ne,0,0,0); \
	RET	(); \
  _ASM_DEF(cont_ne);\
  _ASM_NOAPP_2

#define emit_resume_ge(retinsn)   _ASM_APP_2 \
  _ASM_LBL(cont_ge);\
	JLm	(cont_ge,0,0,0); \
	RET	(); \
  _ASM_DEF(cont_ge);\
  _ASM_NOAPP_2

#define emit_resume_lt(retinsn)   _ASM_APP_2 \
  _ASM_LBL(cont_lt);\
	JGEm	(cont_lt,0,0,0); \
	RET	(); \
  _ASM_DEF(cont_lt);\
  _ASM_NOAPP_2

#define emit_gcprotect()   _ASM_APP_1 \
	MOVLrm	((FP), ((int)&activeFrame),0,0,0); \
  _ASM_NOAPP_1

#ifdef NDEBUG
#define emit_gcunprotect()
#else
#define emit_gcunprotect()   _ASM_APP_1 \
	MOVLim	(0, ((int)&activeFrame),0,0,0); \
  _ASM_NOAPP_1
#endif

#define emit_mkcargs1()   _ASM_APP_1 \
	PUSHLr	((reg[0])); \
  _ASM_NOAPP_1
 
#define emit_mkcargs2()   _ASM_APP_1 \
	PUSHLr	((reg[1])); \
	PUSHLr	((reg[0])); \
  _ASM_NOAPP_1

#define emit_mkcargs3()   _ASM_APP_1 \
	PUSHLr	((reg[2])); \
	PUSHLr	((reg[1])); \
	PUSHLr	((reg[0])); \
  _ASM_NOAPP_1

#define emit_killcargs1()   _ASM_APP_1   	ADDLir	(4, _ESP); _ASM_NOAPP_1
#define emit_killcargs2()   _ASM_APP_1   	ADDLir	(8, _ESP); _ASM_NOAPP_1
#define emit_killcargs3()   _ASM_APP_1   	ADDLir	(12, _ESP); _ASM_NOAPP_1


///
/// branches
///

#define emit_blt(dest)   _ASM_APP_1 \
	JLm	(dest,0,0,0); \
  _ASM_NOAPP_1


#define emit_ble(dest)   _ASM_APP_1 \
	JLEm	(dest,0,0,0); \
  _ASM_NOAPP_1

#define emit_beq(dest)   _ASM_APP_1 \
	JEm	(dest,0,0,0); \
  _ASM_NOAPP_1

#define emit_bne(dest)   _ASM_APP_1 \
	JNEm	(dest,0,0,0); \
  _ASM_NOAPP_1

#define emit_bge(dest)    _ASM_APP_1 \
	JGEm	(dest,0,0,0); \
  _ASM_NOAPP_1

#define emit_bgt(dest)   _ASM_APP_1 \
	JGm	(dest,0,0,0); \
  _ASM_NOAPP_1


///
/// jumps
///

#define emit_jmp(dest)   _ASM_APP_1 \
	JMPm	(dest,0,0,0); \
  _ASM_NOAPP_1

#define emit_initjmp_r(rd)

#define emit_execjmp_r(rd)   _ASM_APP_1 \
	JMPm	(0,(rd),0,0); \
  _ASM_NOAPP_1

#define emit_jmp_r(rd)			\
  emit_initjmp_r(rd)			\
  emit_execjmp_r(rd) 


#define emit_jmpck(dest)   _ASM_APP_1 \
	DECLm	(((int)&interruptCheckCounter),0,0,0); \
	CMPLim	(0, ((int)&interruptCheckCounter),0,0,0); \
	JGm	(dest,0,0,0); \
  _ASM_NOAPP_1

#define emit_jmp0_r(rs, dest) {			\
	emit_cmp_0_r(rs);			\
	emit_beq(dest);				\
 }

#define emit_jmpN0_r(rs, dest) {		\
	emit_cmp_0_r(rs);			\
	emit_bne(dest);				\
  }

#define emit_jmp1_r(rs, dest) {			\
	emit_cmp_1_r(rs);			\
	emit_beq(dest);				\
  }

#define emit_jmpN1_r(rs, dest) {		\
	emit_cmp_1_r(rs);			\
	emit_bne(dest);				\
  }

#endif // _j_i386_emit_h
















