/* jit-i386.def
 * i386 instruction definition.
 *
 * Copyright (c) 1996 Systems Architecture Research Centre,
 *		   City University, London, UK.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * Written by Tim Wilkinson <tim@sarc.city.ac.uk>, June 1996.
 */

#undef	DEBUG

#ifdef DEBUG
#define	debug(x)	printf##x
#else
#define	debug(x)
#endif

#define	do_move_int(t, f) {					\
		OUT = 0x89;					\
		OUT = 0xC0|(f<<3)|t;				\
		debug(("movl %s,%s\n", regname(f), regname(t)));\
	}

#define	check_reg_01() { 					\
		int _r_ = rreg_int(1);				\
		int _w_ = wreg_int(0);				\
		assert(_r_ == _w_);				\
	}

#define	do_force_move_int(t, f, n)				\
	if ((t) != (f)) {					\
		forceRegister(seq_slot(s, (n)), (t), Rint);	\
		do_move_int((t), (f));				\
		f = (t);					\
	}

#define	return_dst()	slot_return(seq_dst(s))


char* rnames[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
#define	regname(n)	rnames[n]

#define	REG_eax		0
#define	REG_ecx		1
#define	REG_edx		2
#define	REG_ebx		3
#define	REG_esp		4
#define	REG_ebp		5
#define	REG_esi		6
#define	REG_edi		7
#define	REG_flt0	8
#define	REG_dbl0	REG_flt0

/* --------------------------------------------------------------------- */

define_insn(unimplemented, unimplemented)
{
	abort();
}

define_insn(nop, nop)
{
	OUT = 0x90;
}

/* --------------------------------------------------------------------- */

define_insn(prologue, prologue_xxx)
{
	int framesize = SLOTSIZE * (maxLocal + maxStack + maxTemp - maxArgs);

	OUT = 0x50|REG_ebp;
	OUT = 0x89;
	OUT = 0xC0|(REG_esp<<3)|REG_ebp;
	if (framesize > 0) {
		OUT = 0x81;
		OUT = 0xE8|REG_esp;
		OUT = framesize & 0xff;
		OUT = (framesize >> 8) & 0xff;
		OUT = (framesize >> 16) & 0xff;
		OUT = (framesize >> 24) & 0xff;
	}
	OUT = 0x50|REG_edi;
	OUT = 0x50|REG_esi;
	OUT = 0x50|REG_ebx;

	debug(("pushl ebp\n"));
	debug(("movl esp,ebp\n"));
	if (framesize > 0) {
		debug(("subl #%d,esp\n", framesize));
	}
	debug(("pushl edi\n"));
	debug(("pushl esi\n"));
	debug(("pushl ebx\n"));
}

define_insn(epilogue, epilogue_xxx)
{
	OUT = 0x58|REG_ebx;
	OUT = 0x58|REG_esi;
	OUT = 0x58|REG_edi;
	OUT = 0x89;
	OUT = 0xC0|(REG_ebp<<3)|REG_esp;
	OUT = 0x58|REG_ebp;

	debug(("popl ebx\n"));
	debug(("popl esi\n"));
	debug(("popl edi\n"));
	debug(("movl ebp,esp\n"));
	debug(("popl ebp\n"));
}

/* --------------------------------------------------------------------- */

define_insn(spill_int, spill_Rxx)
{
	int r = rreg_int(0);
	/* int o = -4 * (1 + const_int(1)); */
	int o = SLOT2FRAMEOFFSET(seq_dst(s));

	OUT = 0x89;
	OUT = 0x80|(r<<3)|REG_ebp;
	OUT = o & 0xff;
	OUT = (o >> 8) & 0xff;
	OUT = (o >> 16) & 0xff;
	OUT = (o >> 24) & 0xff;

	debug(("movl %s,%d(ebp)\n", regname(r), o));
}

define_insn(spill_float, fspill_Rxx)
{
	int r = rreg_float(0);
	int o = SLOT2FRAMEOFFSET(seq_dst(s));

	OUT = 0xD9;
	OUT = 0x98|REG_ebp;
	OUT = o & 0xff;
	OUT = (o >> 8) & 0xff;
	OUT = (o >> 16) & 0xff;
	OUT = (o >> 24) & 0xff;

	debug(("fstp %d(ebp)\n", o));
}

define_insn(spill_double, fspilll_Rxx)
{
	int r = rreg_double(0);
	int o = SLOT2FRAMEOFFSET(seq_dst(s));

	OUT = 0xDD;
	OUT = 0x98|REG_ebp;
	OUT = o & 0xff;
	OUT = (o >> 8) & 0xff;
	OUT = (o >> 16) & 0xff;
	OUT = (o >> 24) & 0xff;

	debug(("fstpl %d(ebp)\n", o));
}

define_insn(reload_int, reload_Rxx)
{
	int r = rreg_int(0);
	/* int o = -4 * (1 + const_int(1)); */
	int o = SLOT2FRAMEOFFSET(seq_dst(s));

	OUT = 0x8B; 
	OUT = 0x80|(r<<3)|REG_ebp;
	OUT = o & 0xff;
	OUT = (o >> 8) & 0xff;
	OUT = (o >> 16) & 0xff;
	OUT = (o >> 24) & 0xff;

	debug(("movl %d(ebp),%s\n", o, regname(r)));
}

define_insn(reload_float, freload_Rxx)
{
	int w = wreg_float(0);
	int o = SLOT2FRAMEOFFSET(seq_dst(s));

	OUT = 0xD9;
	OUT = 0x80|REG_ebp;
	OUT = o & 0xff;
	OUT = (o >> 8) & 0xff;
	OUT = (o >> 16) & 0xff;
	OUT = (o >> 24) & 0xff;

	debug(("fld %d(ebp)\n", o));
}

define_insn(reload_double, freloadl_Rxx)
{
	int w = wreg_double(0);
	int o = SLOT2FRAMEOFFSET(seq_dst(s));

	OUT = 0xDD;
	OUT = 0x80|REG_ebp;
	OUT = o & 0xff;
	OUT = (o >> 8) & 0xff;
	OUT = (o >> 16) & 0xff;
	OUT = (o >> 24) & 0xff;

	debug(("fldl %d(ebp)\n", o));
}

/* --------------------------------------------------------------------- */

define_insn(move_int_const, move_RxC)
{
	int val = const_int(2);
	int w = wreg_int(0);
	OUT = 0xB8|w;
	OUT = val & 0xff;
	OUT = (val >> 8) & 0xff;
	OUT = (val >> 16) & 0xff;
	OUT = (val >> 24) & 0xff;

	debug(("movl #%d,%s\n", val, regname(w)));
}

define_insn(move_label_const, move_RxL)
{
	label* l = (label*)const_int(2);
	int w = wreg_int(0);

	OUT = 0xB8|w;
	l->type |= Llong|Labsolute;
	l->at = (uintp)CODEPC;
	OUT = 0;
	OUT = 0;
	OUT = 0;
	OUT = 0;

	debug(("movl #?,%s\n", regname(w)));
}

define_insn(move_int, move_RxR)
{
	int r = rreg_int(2);
	int w = wreg_int(0);

	if (r != w) {
		/* If destination is a return slot, clobber the register
		 * associated with it.  If we dont do this we might
		 * overwrite something which is still important.
		 */
		if (return_dst()) {
			clobberRegister(w);
		}

		OUT = 0x89;
		OUT = 0xC0|(r<<3)|w;

		debug(("movl %s,%s\n", regname(r), regname(w)));
	}
}

define_insn(move_float_const, fmove_RxC)
{
	double val = const_float(2);
	int w = wreg_float(0);

	if (val == 0.0) {
		OUT = 0xD9;
		OUT = 0xEE;

		debug(("fldz\n"));
	}
	else if (val == 1.0) {
		OUT = 0xD9;
		OUT = 0xE8;

		debug(("fld1\n"));
	}
	else {
		abort();
	}
}

define_insn(move_float, fmove_RxR)
{
	int or = rslot_float(2);
	int ow = rslot_float(0);

	if (or != ow) {
		int w = wreg_float(0);

		OUT = 0xD9;
		OUT = 0x80|REG_ebp;
		OUT = or & 0xff;
		OUT = (or >> 8) & 0xff;
		OUT = (or >> 16) & 0xff;
		OUT = (or >> 24) & 0xff;

		debug(("fld %d(ebp)\n", or));
	}
}

define_insn(move_double_const, fmovel_RxC)
{
	double val = const_double(2);
	int w = wreg_double(0);

	if (val == 0.0) {
		OUT = 0xD9;
		OUT = 0xEE;

		debug(("fldz\n"));
	}
	else if (val == 1.0) {
		OUT = 0xD9;
		OUT = 0xE8;

		debug(("fld1\n"));
	}
	else {
		abort();
	}
}

define_insn(move_double, fmovel_RxR)
{
	int or = rslot_double(2);
	int ow = rslot_double(0);

	if (or != ow) {
		int w = wreg_double(0);

		OUT = 0xDD;
		OUT = 0x80|REG_ebp;
		OUT = or & 0xff;
		OUT = (or >> 8) & 0xff;
		OUT = (or >> 16) & 0xff;
		OUT = (or >> 24) & 0xff;

		debug(("fldl %d(ebp)\n", or));
	}
}

/* --------------------------------------------------------------------- */

define_insn(add_int, add_RRR)
{
	int r;
	int w;

	check_reg_01();

	r = rreg_int(2);
	w = rwreg_int(0);

	OUT = 0x01;
        OUT = 0xC0|(r<<3)|w;

	debug(("addl %s,%s\n", regname(r), regname(w)));
}

define_insn(adc_int, adc_RRR)
{
	int r;
	int w;

	r = rreg_int(2);
	w = rwreg_int(0);

	OUT = 0x11;
        OUT = 0xC0|(r<<3)|w;

	debug(("adcl %s,%s\n", regname(r), regname(w)));
}

define_insn(add_float, fadd_RRR)
{
	int r2 = rslot_float(2);	/* Get r2 into memory */
	int r1 = rreg_float(1);		/* Load r1 into the register stack */
	int w = wreg_float(0);		/* Result will be in register stack */

	OUT = 0xD8;
	OUT = 0x80|REG_ebp;
	OUT = r2 & 0xff;
	OUT = (r2 >> 8) & 0xff;
	OUT = (r2 >> 16) & 0xff;
	OUT = (r2 >> 24) & 0xff;

	debug(("fadd %d(ebp)\n", r2));
}

define_insn(add_double, faddl_RRR)
{
	int r2 = rslot_double(2);	/* Get r2 into memory */
	int r1 = rreg_double(1);	/* Load r1 into the register stack */
	int w = wreg_double(0);		/* Result will be in register stack */

	OUT = 0xDC;
	OUT = 0x80|REG_ebp;
	OUT = r2 & 0xff;
	OUT = (r2 >> 8) & 0xff;
	OUT = (r2 >> 16) & 0xff;
	OUT = (r2 >> 24) & 0xff;

	debug(("faddl %d(ebp)\n", r2));
}

define_insn(sub_int, sub_RRR)
{
	int r;
	int w;

	check_reg_01();

	r = rreg_int(2);
	w = rwreg_int(0);

	OUT = 0x29;
        OUT = 0xC0|(r<<3)|w;

	debug(("subl %s,%s\n", regname(r), regname(w)));
}

define_insn(sbc_int, sbc_RRR)
{
	int r;
	int w;

	r = rreg_int(2);
	w = rwreg_int(0);

	OUT = 0x19;
        OUT = 0xC0|(r<<3)|w;

	debug(("sbbl %s,%s\n", regname(r), regname(w)));
}

define_insn(sub_float, fsub_RRR)
{
	int r2 = rslot_float(2);	/* Get r2 into memory */
	int r1 = rreg_float(1);		/* Load r1 into the register stack */
	int w = wreg_float(0);		/* Result will be in register stack */

	OUT = 0xD8;
	OUT = 0xA0|REG_ebp;
	OUT = r2 & 0xff;
	OUT = (r2 >> 8) & 0xff;
	OUT = (r2 >> 16) & 0xff;
	OUT = (r2 >> 24) & 0xff;

	debug(("fsub %d(ebp)\n", r2));
}

define_insn(sub_double, fsubl_RRR)
{
	int r2 = rslot_double(2);	/* Get r2 into memory */
	int r1 = rreg_double(1);	/* Load r1 into the register stack */
	int w = wreg_double(0);		/* Result will be in register stack */

	OUT = 0xDC;
	OUT = 0xA0|REG_ebp;
	OUT = r2 & 0xff;
	OUT = (r2 >> 8) & 0xff;
	OUT = (r2 >> 16) & 0xff;
	OUT = (r2 >> 24) & 0xff;

	debug(("fsubl %d(ebp)\n", r2));
}

define_insn(mul_int, mul_RRR)
{
	int r;
	int w;

	check_reg_01();

	r = rreg_int(2);
	w = rwreg_int(0);

	OUT = 0x0F;
	OUT = 0xAF;
        OUT = 0xC0|(w<<3)|r;

	debug(("imull %s,%s\n", regname(r), regname(w)));
}

define_insn(mul_float, fmul_RRR)
{
	int r2 = rslot_float(2);	/* Get r2 into memory */
	int r1 = rreg_float(1);		/* Load r1 into the register stack */
	int w = wreg_float(0);		/* Result will be in register stack */

	OUT = 0xD8;
	OUT = 0x88|REG_ebp;
	OUT = r2 & 0xff;
	OUT = (r2 >> 8) & 0xff;
	OUT = (r2 >> 16) & 0xff;
	OUT = (r2 >> 24) & 0xff;

	debug(("fmul %d(ebp)\n", r2));
}

define_insn(mul_double, fmull_RRR)
{
	int r2 = rslot_double(2);	/* Get r2 into memory */
	int r1 = rreg_double(1);	/* Load r1 into the register stack */
	int w = wreg_double(0);		/* Result will be in register stack */

	OUT = 0xDC;
	OUT = 0x88|REG_ebp;
	OUT = r2 & 0xff;
	OUT = (r2 >> 8) & 0xff;
	OUT = (r2 >> 16) & 0xff;
	OUT = (r2 >> 24) & 0xff;

	debug(("fmull %d(ebp)\n", r2));
}

define_insn(div_int, div_RRR)
{
	int r;
	int w;

	check_reg_01();

	w = rwreg_int(0);

	/* Can only divide accumulator. */
	do_force_move_int(REG_eax, w, 0);

	/* EDX is also used so get hold of it */
	clobberRegister(REG_edx);

	/* Setup EDX - should contains the sign of EAX */
	do_move_int(REG_edx, REG_eax);
	OUT = 0xC1;
	OUT = 0xF8|REG_edx;
	OUT = 31;
	debug(("sarl #31,edx\n"));

	r = rreg_int(2);

	OUT = 0xF7;
        OUT = 0xF8|r;

	assert(r != REG_eax);
	assert(r != REG_edx);
	debug(("idivl %s,%s\n", regname(r), regname(w)));
}

define_insn(div_float, fdiv_RRR)
{
	int r2 = rslot_float(2);	/* Get r2 into memory */
	int r1 = rreg_float(1);		/* Load r1 into the register stack */
	int w = wreg_float(0);		/* Result will be in register stack */

	OUT = 0xD8;
	OUT = 0xB0|REG_ebp;
	OUT = r2 & 0xff;
	OUT = (r2 >> 8) & 0xff;
	OUT = (r2 >> 16) & 0xff;
	OUT = (r2 >> 24) & 0xff;

	debug(("fdiv %d(ebp)\n", r2));
}

define_insn(div_double, fdivl_RRR)
{
	int r2 = rslot_double(2);	/* Get r2 into memory */
	int r1 = rreg_double(1);	/* Load r1 into the register stack */
	int w = wreg_double(0);		/* Result will be in register stack */

	OUT = 0xDC;
	OUT = 0xB0|REG_ebp;
	OUT = r2 & 0xff;
	OUT = (r2 >> 8) & 0xff;
	OUT = (r2 >> 16) & 0xff;
	OUT = (r2 >> 24) & 0xff;

	debug(("fdivl %d(ebp)\n", r2));
}

define_insn(rem_int, rem_RRR)
{
	int r;
	int w;

	check_reg_01();

	w = rwreg_int(0);

	/* Can only divide accumulator. */
	do_force_move_int(REG_eax, w, 0);

	/* EDX is also used so get hold of it */
	clobberRegister(REG_edx);

	/* Setup EDX - should contains the sign of EAX */
	do_move_int(REG_edx, REG_eax);
	OUT = 0xC1;
	OUT = 0xF8|REG_edx;
	OUT = 31;
	debug(("sarl #31,edx\n"));

	r = rreg_int(2);

	OUT = 0xF7;
        OUT = 0xF8|r;

	assert(r != REG_eax);
	assert(r != REG_edx);
	debug(("idivl %s,%s\n", regname(r), regname(w)));

	/* Result is in EDX not EAX - we must force the slot register */
	forceRegister(seq_dst(s), REG_edx, Rint);
}

/* --------------------------------------------------------------------- */

define_insn(and_int, and_RRR)
{
	int r;
	int w;

	check_reg_01();

	r = rreg_int(2);
	w = rwreg_int(0);

	OUT = 0x21;
        OUT = 0xC0|(r<<3)|w;

	debug(("andl %s,%s\n", regname(r), regname(w)));
}

define_insn(or_int, or_RRR)
{
	int r;
	int w;

	check_reg_01();

	r = rreg_int(2);
	w = rwreg_int(0);

	OUT = 0x09;
        OUT = 0xC0|(r<<3)|w;

	debug(("orl %s,%s\n", regname(r), regname(w)));
}

define_insn(xor_int, xor_RRR)
{
	int r;
	int w;

	check_reg_01();

	r = rreg_int(2);
	w = rwreg_int(0);

	OUT = 0x31;
        OUT = 0xC0|(r<<3)|w;

	debug(("xorl %s,%s\n", regname(r), regname(w)));
}

define_insn(ashr_int, ashr_RRR)
{
	int r;
	int w;

	check_reg_01();

	r = rreg_int(2);

	/* Can only shift by ECX. */
	do_force_move_int(REG_ecx, r, 2);

	w = rwreg_int(0);

	OUT = 0xD3;
        OUT = 0xF8|w;

	debug(("sarl %s,%s\n", regname(r), regname(w)));
}

define_insn(lshr_int, lshr_RRR)
{
	int r;
	int w;

	check_reg_01();

	r = rreg_int(2);

	/* Can only shift by ECX. */
	do_force_move_int(REG_ecx, r, 2);

	w = rwreg_int(0);

	OUT = 0xD3;
        OUT = 0xE8|w;

	debug(("shrl %s,%s\n", regname(r), regname(w)));
}

define_insn(lshl_int, lshl_RRR)
{
	int r;
	int w;

	check_reg_01();

	r = rreg_int(2);

	/* Can only shift by ECX. */
	do_force_move_int(REG_ecx, r, 2);

	w = rwreg_int(0);

	OUT = 0xD3;
        OUT = 0xE0|w;

	debug(("shll %s,%s\n", regname(r), regname(w)));
}

/* --------------------------------------------------------------------- */

define_insn(load_int, load_RxR)
{
	int r = rreg_int(2);
	int w = wreg_int(0);

	OUT = 0x8B;
	OUT = 0x00|(w<<3)|r;
	if (r == REG_esp) {
		OUT = 0x20|REG_esp;
	}

	debug(("movl (%s),%s\n", regname(r), regname(w)));
}

define_insn(load_float, fload_RxR)
{
	int r = rreg_int(2);
	int w = wreg_float(0);

	OUT = 0xD9;
	OUT = 0x00|r;

	debug(("fld (%s)\n", regname(r)));
}

define_insn(load_double, floadl_RxR)
{
	int r = rreg_int(2);
	int w = wreg_double(0);

	OUT = 0xDD;
	OUT = 0x00|r;

	debug(("fldl (%s)\n", regname(r)));
}

define_insn(store_int, store_xRR)
{
	int r = rreg_int(2);
	int w = rreg_int(1);

	OUT = 0x89;
	OUT = 0x00|(r<<3)|w;
	if (w == REG_esp) {
		OUT = 0x20|REG_esp;
	}

	debug(("movl %s,(%s)\n", regname(r), regname(w)));
}

define_insn(store_float, fstore_RxR)
{
	int r = rreg_float(2);
	int w = rreg_int(1);

	OUT = 0xD9;
	OUT = 0x18|w;

	debug(("fstp (%s)\n", regname(w)));
}

define_insn(store_double, fstorel_RxR)
{
	int r = rreg_double(2);
	int w = rreg_int(1);

	OUT = 0xDD;
	OUT = 0x18|w;

	debug(("fstlp (%s)\n", regname(w)));
}

/* --------------------------------------------------------------------- */

define_insn(cmp_int, cmp_xRR)
{
	int r1 = rreg_int(1);
	int r2 = rreg_int(2);

	OUT = 0x39;
	OUT = 0xC0|(r2<<3)|r1;

	debug(("cmpl %s,%s\n", regname(r2), regname(r1)));
}

/* --------------------------------------------------------------------- */

define_insn(cvt_int_float, cvtif_RxR)
{
	int r = rslot_int(2);
	int w = wreg_float(0);

	OUT = 0xDB;
	OUT = 0x80|REG_ebp;
	OUT = r & 0xff;
	OUT = (r >> 8) & 0xff;
	OUT = (r >> 16) & 0xff;
	OUT = (r >> 24) & 0xff;

	debug(("fild %d(ebp)\n", r));
}

define_insn(cvt_int_double, cvtid_RxR)
{
	int r = rslot_int(2);
	int w = wreg_double(0);

	OUT = 0xDB;
	OUT = 0x80|REG_ebp;
	OUT = r & 0xff;
	OUT = (r >> 8) & 0xff;
	OUT = (r >> 16) & 0xff;
	OUT = (r >> 24) & 0xff;

	debug(("fild %d(ebp)\n", r));
}

define_insn(cvt_long_float, cvtlf_RxR)
{
	int r = rslot_long(2);
	int w = wreg_float(0);

	OUT = 0xDF;
	OUT = 0xA8|REG_ebp;
	OUT = r & 0xff;
	OUT = (r >> 8) & 0xff;
	OUT = (r >> 16) & 0xff;
	OUT = (r >> 24) & 0xff;

	debug(("fildll %d(ebp)\n", r));
}

define_insn(cvt_long_double, cvtld_RxR)
{
	int r = rslot_long(2);
	int w = wreg_double(0);

	OUT = 0xDF;
	OUT = 0xA8|REG_ebp;
	OUT = r & 0xff;
	OUT = (r >> 8) & 0xff;
	OUT = (r >> 16) & 0xff;
	OUT = (r >> 24) & 0xff;

	debug(("fildll %d(ebp)\n", r));
}

define_insn(cvt_float_int, cvtfi_RxR)
{
	int r = rreg_float(2);
	int w = wslot_int(0);

	OUT = 0xDB;
	OUT = 0x98|REG_ebp;
	OUT = w & 0xff;
	OUT = (w >> 8) & 0xff;
	OUT = (w >> 16) & 0xff;
	OUT = (w >> 24) & 0xff;

	debug(("fistp %d(ebp)\n", w));
}

define_insn(cvt_double_int, cvtdi_RxR)
{
	int r = rreg_double(2);
	int w = wslot_int(0);

	OUT = 0xDB;
	OUT = 0x98|REG_ebp;
	OUT = w & 0xff;
	OUT = (w >> 8) & 0xff;
	OUT = (w >> 16) & 0xff;
	OUT = (w >> 24) & 0xff;

	debug(("fistp %d(ebp)\n", w));
}

define_insn(cvt_float_long, cvtfl_RxR)
{
	int r = rreg_float(2);
	int w = wslot_long(0);

	OUT = 0xDF;
	OUT = 0xB8|REG_ebp;
	OUT = w & 0xff;
	OUT = (w >> 8) & 0xff;
	OUT = (w >> 16) & 0xff;
	OUT = (w >> 24) & 0xff;

	debug(("fistpl %d(ebp)\n", w));
}

define_insn(cvt_double_long, cvtdl_RxR)
{
	int r = rreg_double(2);
	int w = wslot_long(0);

	OUT = 0xDF;
	OUT = 0xB8|REG_ebp;
	OUT = w & 0xff;
	OUT = (w >> 8) & 0xff;
	OUT = (w >> 16) & 0xff;
	OUT = (w >> 24) & 0xff;

	debug(("fistpl %d(ebp)\n", w));
}

define_insn(cvt_float_double, cvtfd_RxR)
{
	int o = rslot_float(2);
	int w = wreg_double(0);

	OUT = 0xD9;
	OUT = 0x80|REG_ebp;
	OUT = o & 0xff;
	OUT = (o >> 8) & 0xff;
	OUT = (o >> 16) & 0xff;
	OUT = (o >> 24) & 0xff;

	debug(("fld %d(ebp)\n", o));
}

define_insn(cvt_double_float, cvtdf_RxR)
{
	int o = rslot_double(2);
	int w = wreg_float(0);

	OUT = 0xDD;
	OUT = 0x80|REG_ebp;
	OUT = o & 0xff;
	OUT = (o >> 8) & 0xff;
	OUT = (o >> 16) & 0xff;
	OUT = (o >> 24) & 0xff;

	debug(("fldl %d(ebp)\n", o));
}

/* --------------------------------------------------------------------- */

define_insn(build_key, set_word_xxC)
{
	jint val = const_int(2);

	OUT = val & 0xff;
	OUT = (val >> 8) & 0xff;
	OUT = (val >> 16) & 0xff;
	OUT = (val >> 24) & 0xff;

	debug((".word %08x\n", val));
}

define_insn(build_code_ref, set_wordpc_xxC)
{
	label* l = (label*)const_int(2);

	l->type |= Llong|Labsolute;
	l->at = (uintp)CODEPC;
	OUT = 0;
	OUT = 0;
	OUT = 0;
	OUT = 0;
	l->from = (uintp)CODEPC;
	debug((".word ?\n"));
}

/* --------------------------------------------------------------------- */

define_insn(set_label, set_label_xxC)
{
	label* l = (label*)const_int(2);
	l->to = (uint32)CODEPC;
}

define_insn(branch, branch_xCC)
{
	label* l = (label*)const_int(1);
	int bt = const_int(2);

	l->type |= Llong|Lrelative;
	switch (bt) {
	case ba:
		OUT = 0xE9;
		l->at = (uintp)CODEPC;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		l->from = (uintp)CODEPC;
		debug(("jmpl ?\n"));
		break;
	case beq:
		OUT = 0x0F;
		OUT = 0x84;
		l->at = (uintp)CODEPC;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		l->from = (uintp)CODEPC;
		debug(("je ?\n"));
		break;
	case bne:
		OUT = 0x0F;
		OUT = 0x85;
		l->at = (uintp)CODEPC;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		l->from = (uintp)CODEPC;
		debug(("jne ?\n"));
		break;
	case blt:
		OUT = 0x0F;
		OUT = 0x8C;
		l->at = (uintp)CODEPC;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		l->from = (uintp)CODEPC;
		debug(("jlt ?\n"));
		break;
	case ble:
		OUT = 0x0F;
		OUT = 0x8E;
		l->at = (uintp)CODEPC;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		l->from = (uintp)CODEPC;
		debug(("jle ?\n"));
		break;
	case bgt:
		OUT = 0x0F;
		OUT = 0x8F;
		l->at = (uintp)CODEPC;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		l->from = (uintp)CODEPC;
		debug(("jgt ?\n"));
		break;
	case bge:
		OUT = 0x0F;
		OUT = 0x8D;
		l->at = (uintp)CODEPC;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		OUT = 0;
		l->from = (uintp)CODEPC;
		debug(("jge ?\n"));
		break;
	default:
		abort();
	}
}

define_insn(branch_indirect, branch_indirect_xRC)
{
	int r = rreg_int(1);
	assert(const_int(2) == ba);

	OUT = 0xFF;
	OUT = 0xE0|r;

	debug(("jmp (%s)\n", regname(r)));
}

define_insn(call_ref, call_xCC)
{
	label* l = (label*)const_int(1);
	assert(const_int(2) == ba);

	OUT = 0xE8;
	l->type |= Llong|Lrelative;
	l->at = (uintp)CODEPC;
	OUT = 0;
	OUT = 0;
	OUT = 0;
	OUT = 0;
	l->from = (uintp)CODEPC;

	debug(("call ?\n"));
}

define_insn(call, call_xRC)
{
	int r = rreg_int(1);
	assert(const_int(2) == ba);

	OUT = 0xFF;
	OUT = 0xD0|r;

	debug(("call %s\n", regname(r)));
}

define_insn(ret, ret_xxx)
{
	OUT = 0xC3;

	debug(("ret\n"));
}

define_insn(push_int, push_xxR)
{
	int r = rreg_int(2);

	OUT = 0xFF;
	OUT = 0xF0|r;

	debug(("pushl %s\n", regname(r)));
}

define_insn(push_float, fpush_xxR)
{
	int r = rreg_int(2);	/* Move the float into a register */

	OUT = 0xFF;
	OUT = 0xF0|r;

	debug(("pushl %s\n", regname(r)));
}

define_insn(push_double, fpushl_xxR)
{
	int r = rslot_int(2);	/* Move the float into a slot */

	OUT = 0xFF;
	OUT = 0xB0|REG_ebp;
	OUT = (r+4) & 0xff;
	OUT = ((r+4) >> 8) & 0xff;
	OUT = ((r+4) >> 16) & 0xff;
	OUT = ((r+4) >> 24) & 0xff;

	debug(("pushl %d(ebp)\n", (r+4)));

	OUT = 0xFF;
	OUT = 0xB0|REG_ebp;
	OUT = r & 0xff;
	OUT = (r >> 8) & 0xff;
	OUT = (r >> 16) & 0xff;
	OUT = (r >> 24) & 0xff;

	debug(("pushl %d(ebp)\n", r));
}

define_insn(popargs, popargs_xxC)
{
	int o = const_int(2);
	o *= 4;

	OUT = 0x81;
	OUT = 0xC0|REG_esp;
	OUT = o & 0xff;
	OUT = (o >> 8) & 0xff;
	OUT = (o >> 16) & 0xff;
	OUT = (o >> 24) & 0xff;

	debug(("addl %d,esp\n", o));
}

define_insn(return_int, return_Rxx)
{
	forceRegister(seq_dst(s), REG_eax, Rint);
}

define_insn(return_long, returnl_Rxx)
{
	forceRegister(seq_dst(s), REG_eax, Rint);
	forceRegister(seq_dst(s)+1, REG_edx, Rint);
}

define_insn(return_float, freturn_Rxx)
{
	forceRegister(seq_dst(s), REG_flt0, Rfloat);
}

define_insn(return_double, freturnl_Rxx)
{
	forceRegister(seq_dst(s), REG_dbl0, Rdouble);
}

/* --------------------------------------------------------------------- */

define_insn(add_int_const, add_RRC)
{
	int rw;
	int v;

	check_reg_01();

	v = const_int(2);
	rw = rwreg_int(0);

	OUT = 0x81;
        OUT = 0xC0|rw;
	OUT = v & 0xff;
	OUT = (v >> 8) & 0xff;
	OUT = (v >> 16) & 0xff;
	OUT = (v >> 24) & 0xff;

	debug(("addl #%d,%s\n", v, regname(rw)));
}

define_insn(sub_int_const, sub_RRC)
{
	int rw;
	int v;

	check_reg_01();

	v = const_int(2);
	rw = rwreg_int(0);

	OUT = 0x81;
        OUT = 0xE8|rw;
	OUT = v & 0xff;
	OUT = (v >> 8) & 0xff;
	OUT = (v >> 16) & 0xff;
	OUT = (v >> 24) & 0xff;

	debug(("subl #%d,%s\n", v, regname(rw)));
}

define_insn(load_int_addregconst, load_RRC)
{
	int v = const_int(2);
	int r = rreg_int(1);
	int w = wreg_int(0);

	assert(r != REG_esp);
	OUT = 0x8B; 
	OUT = 0x80|(w<<3)|r;
	OUT = v & 0xff;
	OUT = (v >> 8) & 0xff;
	OUT = (v >> 16) & 0xff;
	OUT = (v >> 24) & 0xff;

	debug(("movl %d(%s),%s\n", o, regname(r), regname(w)));
}

define_insn(load_byte, loadb_RxR)
{
	int r = rreg_int(2);
	int w = wreg_int(0);

	OUT = 0x0F;
	OUT = 0xBE;
	OUT = 0x00|(w<<3)|r;
	if (r == REG_esp) {
		OUT = 0x20|REG_esp;
	}

	debug(("movsb (%s),%s\n", regname(r), regname(w)));
}

define_insn(load_char, loadc_RxR)
{
	int r = rreg_int(2);
	int w = wreg_int(0);

	OUT = 0x0F;
	OUT = 0xB6;
	OUT = 0x00|(w<<3)|r;
	if (r == REG_esp) {
		OUT = 0x20|REG_esp;
	}

	debug(("movzb (%s),%s\n", regname(r), regname(w)));
}

define_insn(load_short, loads_RxR)
{
	int r = rreg_int(2);
	int w = wreg_int(0);

	OUT = 0x0F;
	OUT = 0xBF;
	OUT = 0x00|(w<<3)|r;
	if (r == REG_esp) {
		OUT = 0x20|REG_esp;
	}

	debug(("movsw (%s),%s\n", regname(r), regname(w)));
}

define_insn(store_int_addregconst, store_xRRC)
{
	int v;
	int r1;
	int r0;

	r0 = rreg_int(2);
	s = seq_seq(s, 1);
	assert(s->ref == 0);
	v = const_int(2);
	r1 = rreg_int(1);

	assert(r0 != REG_esp);
	OUT = 0x89; 
	OUT = 0x80|(r0<<3)|r1;
	OUT = v & 0xff;
	OUT = (v >> 8) & 0xff;
	OUT = (v >> 16) & 0xff;
	OUT = (v >> 24) & 0xff;

	debug(("movl %s,%d(%s)\n", regname(r0), v, regname(r1)));
}

define_insn(store_byte, storeb_xRR)
{
	int r = rreg_int(2);
	int w = rreg_int(1);

	OUT = 0x88;
	OUT = 0x00|(r<<3)|w;
	if (w == REG_esp) {
		OUT = 0x20|REG_esp;
	}

	debug(("movb %s,(%s)\n", regname(r), regname(w)));
}

define_insn(store_short, stores_xRR)
{
	int r = rreg_int(2);
	int w = rreg_int(1);

	OUT = 0x66;
	OUT = 0x89;
	OUT = 0x00|(r<<3)|w;
	if (w == REG_esp) {
		OUT = 0x20|REG_esp;
	}

	debug(("movw %s,(%s)\n", regname(r), regname(w)));
}

define_insn(cmp_int_const, cmp_xRC)
{
	int r1 = rreg_int(1);
	int v = const_int(2);

	OUT = 0x81;
        OUT = 0xF8|r1;
	OUT = v & 0xff;
	OUT = (v >> 8) & 0xff;
	OUT = (v >> 16) & 0xff;
	OUT = (v >> 24) & 0xff;

	debug(("cmpl #%d,%s\n", v, regname(r1)));
}

define_insn(push_int_const, push_xxC)
{
	int v = const_int(2);

	OUT = 0x68;
	OUT = v & 0xff;
	OUT = (v >> 8) & 0xff;
	OUT = (v >> 16) & 0xff;
	OUT = (v >> 24) & 0xff;

	debug(("pushl #%d\n", v));
}

define_insn(lshl_int_const, lshl_RRC)
{
	int rw;
	int v;

	check_reg_01();

	rw = rreg_int(0);
	v = const_int(2);

	assert(v < 256);

	OUT = 0xC1;
        OUT = 0xE0|rw;
	OUT = v

	debug(("shll #%d,%s\n", v, regname(rw)));
}
