Bool debugging_translation;
static Int v0thresh = 940;
- static Int v2thresh = 940;
+ static Int v2thresh = 940000;
TranslateResult tres;
static Bool vex_init_done = False;
/* Adjust FTOP downwards by one register. */
-static IRStmt* do_push ( void )
+static IRStmt* fp_push ( void )
{
return
put_ftop(
);
}
+/* Adjust FTOP upwards by one register. */
+
+static IRStmt* fp_pop ( void )
+{
+ return
+ put_ftop(
+ binop(Iop_And32,
+ binop(Iop_Add32, get_ftop(), mkU32(1)),
+ mkU32(7))
+ );
+}
+
+static
+void fp_do_op_mem_ST_0 ( IRTemp addr, UChar* op_txt, UChar* dis_buf,
+ IROp op, Bool dbl )
+{
+ DIP("f%s%c %s", op_txt, dbl?'l':'s', dis_buf);
+ if (dbl) {
+ stmt( put_ST(0, binop(op, get_ST(0), loadLE(Ity_F64,mkexpr(addr)))));
+ } else {
+ vassert(0);
+ }
+}
+
static
UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
{
- Int len;
- UInt src;
- Char dis_buf[32];
+ Int len;
+ UInt r_src, r_dst;
+ Char dis_buf[32];
IRTemp t1;
/* On entry, delta points at the second byte of the insn (the modrm
delta++;
switch (modrm) {
case 0xC0 ... 0xC7: /* FLD %st(?) */
- src = (UInt)modrm - 0xC0;
- DIP("fld %%st(%d)\n", src);
+ r_src = (UInt)modrm - 0xC0;
+ DIP("fld %%st(%d)\n", r_src);
t1 = newTemp(Ity_F64);
- assign(t1, get_ST(src));
- stmt( do_push() );
+ assign(t1, get_ST(r_src));
+ stmt( fp_push() );
stmt( put_ST(0, mkexpr(t1)) );
break;
+ case 0xEE: /* FLDZ */
+ DIP("fldz");
+ stmt( fp_push() );
+ stmt( put_ST(0, IRExpr_Const(IRConst_F64(0.0))) );
+ break;
+
default:
goto decode_fail;
}
/* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
else
if (first_opcode == 0xDC) {
- goto decode_fail;
+ if (modrm < 0xC0) {
+
+ /* bits 5,4,3 are an opcode extension, and the modRM also
+ specifies an address. */
+ IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
+ delta += len;
+
+ switch (gregOfRM(modrm)) {
+
+ case 0: /* FADD double-real */
+ fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
+ break;
+
+ default:
+ vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
+ vex_printf("first_opcode == 0xDC\n");
+ goto decode_fail;
+ }
+
+ } else {
+ goto decode_fail;
+ }
}
/* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
case 0: /* FLD double-real */
DIP("fldD %s\n", dis_buf);
- stmt( do_push() );
+ stmt( fp_push() );
stmt( put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr))) );
break;
}
setDMem(a_addr,vd_addr);
break;
-
+#endif
case 3: /* FSTP double-real */
- IFDB( if (dis) printf("\tfstpD\t%s\n",t_addr); )
- if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
- vd_addr = fp_pop();
- } else {
- vd_addr = fp_pop(); /* then throw away result */
- vd_addr = NAN;
- fp_set_stack_underflow();
- }
- setDMem(a_addr,vd_addr);
+ DIP("fstpD %s", dis_buf);
+ storeLE(mkexpr(addr), get_ST(0));
+ stmt( fp_pop() );
break;
-#endif
default:
vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
goto decode_fail;
}
} else {
- goto decode_fail;
+ delta++;
+ switch (modrm) {
+ case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
+ r_dst = (UInt)modrm - 0xD8;
+ DIP("fstp %%st(0),%%st(%d)\n", r_dst);
+ stmt( put_ST(r_dst, get_ST(0)) );
+ stmt( fp_pop() );
+ break;
+ default:
+ goto decode_fail;
+ }
}
}
greg, d32(ereg) | ereg != ESP
= 10 greg ereg, d32
+ greg, d8(%esp) = 01 greg 100, 0x24, d8
+
-----------------------------------------------
greg, d8(base,index,scale)
p = emit32(p, am->Xam.IR.imm);
return p;
}
+ if (am->Xam.IR.reg == hregX86_ESP()
+ && fits8bits(am->Xam.IR.imm)) {
+ *p++ = mkModRegRM(1, iregNo(greg), 4);
+ *p++ = 0x24;
+ *p++ = am->Xam.IR.imm & 0xFF;
+ return p;
+ }
ppX86AMode(am);
vpanic("doAMode_M: can't emit amode IR");
/*NOTREACHED*/
# define fake(_n) mkHReg((_n), HRcInt, False)
Int subopc;
switch (op) {
+ case Xfp_ADD: subopc = 0; break;
case Xfp_MUL: subopc = 1; break;
default: vpanic("do_fop_st: unknown op");
}
*p++ = 0xFF;
p = doAMode_M(p, fake(6), i->Xin.Push.src->Xrmi.Mem.am);
goto done;
- default:
+ case Xrmi_Imm:
+ *p++ = 0x68;
+ p = emit32(p, i->Xin.Push.src->Xrmi.Imm.imm32);
+ goto done;
+ default:
goto bad;
}
? (p->Iex.Const.con->Ico.U64
== e->Iex.Const.con->Ico.U64)
: False;
+ case Ico_F64: return e->Iex.Const.con->tag==Ico_F64
+ ? (p->Iex.Const.con->Ico.F64
+ == e->Iex.Const.con->Ico.F64)
+ : False;
}
vpanic("matchIRExpr.Iex_Const");
/*NOTREACHED*/
return lookupIRTemp(env, e->Iex.Tmp.tmp);
}
+ if (e->tag == Iex_Const) {
+ union { UInt i64[2]; Double f64; } u;
+ HReg freg = newVRegF(env);
+ vassert(sizeof(u) == 8);
+ vassert(sizeof(u.i64) == 8);
+ vassert(sizeof(u.f64) == 8);
+ vassert(e->Iex.Const.con->tag == Ico_F64);
+ u.f64 = e->Iex.Const.con->Ico.F64;
+ addInstr(env, X86Instr_Push(X86RMI_Imm(u.i64[1])));
+ addInstr(env, X86Instr_Push(X86RMI_Imm(u.i64[0])));
+ addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, freg,
+ X86AMode_IR(0, hregX86_ESP())));
+ addInstr(env, X86Instr_Alu32R(Xalu_ADD,
+ X86RMI_Imm(8),
+ hregX86_ESP()));
+ return freg;
+ }
+
if (e->tag == Iex_LDle) {
X86AMode* am;
HReg res = newVRegF(env);
if (e->tag == Iex_Binop) {
X86FpOp fpop = Xfp_INVALID;
switch (e->Iex.Binop.op) {
+ case Iop_AddF64: fpop = Xfp_ADD; break;
case Iop_MulF64: fpop = Xfp_MUL; break;
default: break;
}
/* --------- STORE --------- */
case Ist_STle: {
+ X86AMode* am;
IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr);
IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data);
vassert(tya == Ity_I32);
+ am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
if (tyd == Ity_I32) {
- X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
- X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data);
+ X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data);
addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am));
return;
}
if (tyd == Ity_I8 || tyd == Ity_I16) {
- X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
- HReg r = iselIntExpr_R(env, stmt->Ist.STle.data);
+ HReg r = iselIntExpr_R(env, stmt->Ist.STle.data);
addInstr(env, X86Instr_Store(tyd==Ity_I8 ? 1 : 2,
r,am));
return;
}
+ if (tyd == Ity_F64) {
+ HReg r = iselDblExpr(env, stmt->Ist.STle.data);
+ addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, r, am));
+ return;
+ }
break;
}
case Ico_U16: vex_printf( "0x%x", (UInt)(con->Ico.U16)); break;
case Ico_U32: vex_printf( "0x%x", (UInt)(con->Ico.U32)); break;
case Ico_U64: vex_printf( "0x%llx", (ULong)(con->Ico.U64)); break;
+ case Ico_F64: vex_printf("(f64 value)"); break;
default: vpanic("ppIRConst");
}
}
case Iop_64to32: vex_printf("64to32"); return;
case Iop_32HLto64: vex_printf("32HLto64"); return;
+ case Iop_AddF64: vex_printf("AddF64"); return;
case Iop_MulF64: vex_printf("MulF64"); return;
case Iop_I64toF64: vex_printf("I64toF64"); return;
c->Ico.U64 = u64;
return c;
}
-
+IRConst* IRConst_F64 ( Double f64 )
+{
+ IRConst* c = LibVEX_Alloc(sizeof(IRConst));
+ c->tag = Ico_F64;
+ c->Ico.F64 = f64;
+ return c;
+}
/* Constructors -- IRExpr */
case Iop_32Sto64: UNARY(Ity_I64,Ity_I32);
case Iop_32to8: UNARY(Ity_I8,Ity_I32);
- case Iop_MulF64: BINARY(Ity_F64,Ity_F64,Ity_F64);
+ case Iop_AddF64: case Iop_MulF64:
+ BINARY(Ity_F64,Ity_F64,Ity_F64);
case Iop_I64toF64: UNARY(Ity_F64,Ity_I64);
default:
case Ico_U16: return Ity_I16;
case Ico_U32: return Ity_I32;
case Ico_U64: return Ity_I64;
+ case Ico_F64: return Ity_F64;
default: vpanic("typeOfIRConst");
}
}
typedef unsigned long long int ULong;
typedef signed long long int Long;
+typedef float Float; /* IEEE754 single-precision (32-bit) value */
+typedef double Double; /* IEEE754 double-precision (64-bit) value */
+
typedef unsigned char Bool;
#define True ((Bool)1)
#define False ((Bool)0)
typedef
enum { Ico_U8=0x12000,
- Ico_U16, Ico_U32, Ico_U64 }
+ Ico_U16, Ico_U32, Ico_U64, Ico_F64 }
IRConstTag;
typedef
UShort U16;
UInt U32;
ULong U64;
+ Double F64;
} Ico;
}
IRConst;
extern IRConst* IRConst_U16 ( UShort );
extern IRConst* IRConst_U32 ( UInt );
extern IRConst* IRConst_U64 ( ULong );
+extern IRConst* IRConst_F64 ( Double );
extern void ppIRConst ( IRConst* );