UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
{
Int len;
+ UInt src;
Char dis_buf[32];
- UInt opc_aux;
+ IRTemp t1;
/* On entry, delta points at the second byte of the insn (the modrm
byte).*/
/* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
else
if (first_opcode == 0xD9) {
- goto decode_fail;
+ if (modrm < 0xC0) {
+ goto decode_fail;
+ } else {
+ delta++;
+ switch (modrm) {
+ case 0xC0 ... 0xC7: /* FLD %st(?) */
+ src = (UInt)modrm - 0xC0;
+ DIP("fld %%st(%d)\n", src);
+ t1 = newTemp(Ity_F64);
+ assign(t1, get_ST(src));
+ stmt( do_push() );
+ stmt( put_ST(0, mkexpr(t1)) );
+ break;
+
+ default:
+ goto decode_fail;
+ }
+ }
}
/* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
else
if (first_opcode == 0xDA) {
- 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 1: /* FIMUL m32int */
+ DIP("fimull %s", dis_buf);
+ stmt( put_ST(0,
+ binop(Iop_MulF64,
+ get_ST(0),
+ unop(Iop_I64toF64,
+ unop(Iop_32Sto64,
+ loadLE(Ity_I32, mkexpr(addr)))))));
+ break;
+
+ default:
+ vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
+ vex_printf("first_opcode == 0xDA\n");
+ goto decode_fail;
+ }
+ } else {
+ goto decode_fail;
+ }
}
/* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
if (modrm < 0xC0) {
- /* bits 5,4,3 are an opcode extension, and the modRM also
+ /* 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;
+ IRTemp addr = disAMode( &len, sorb, delta, dis_buf );
+ delta += len;
switch (gregOfRM(modrm)) {
case 0: /* FLD double-real */
DIP("fldD %s\n", dis_buf);
- stmt( do_push() );
- stmt( put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr))) );
- break;
+ stmt( do_push() );
+ stmt( put_ST(0, IRExpr_LDle(Ity_F64, mkexpr(addr))) );
+ break;
#if 0
case 2: /* FST double-real */
#endif
default:
- vex_printf("unhandled opc_aux = 0x%2x\n", opc_aux);
- vex_printf("first_opcode == 0xDD");
+ vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm));
+ vex_printf("first_opcode == 0xDD\n");
goto decode_fail;
- }
+ }
} else {
goto decode_fail;
}
mask))) );
setFlags_DSTus_DST1 ( left_shift ? Iop_Shl32 : Iop_Sar32,
- tmpSubSh, tmpRes, ty, tmpSH );
+ tmpSubSh, tmpRes, ty, tmpSH );
/* Put result back. */
//-- static
//-- Addr dis_SSE3_reg_or_mem ( UCodeBlock* cb,
//-- UChar sorb,
-//-- Addr eip,
+//-- Addr eip,
//-- Int sz,
//-- Char* name,
//-- UChar opc1,
Char* showX86FpOp ( X86FpOp op ) {
switch (op) {
- case Xfp_Add: return "add";
- case Xfp_Sub: return "sub";
- case Xfp_Mul: return "mul";
- case Xfp_Div: return "div";
- case Xfp_Sqrt: return "sqrt";
- case Xfp_Negate: return "chs";
+ case Xfp_ADD: return "add";
+ case Xfp_SUB: return "sub";
+ case Xfp_MUL: return "mul";
+ case Xfp_DIV: return "div";
+ case Xfp_SQRT: return "sqrt";
+ case Xfp_NEGATE: return "chs";
+ case Xfp_MOV: return "mov";
default: vpanic("ppX86FpOp");
}
}
case Xin_Sh32:
vex_printf("%sl ", showX86ShiftOp(i->Xin.Sh32.op));
if (i->Xin.Sh32.src == 0)
- vex_printf(" %%cl,");
+ vex_printf("%%cl,");
else
- vex_printf(" $%d,", i->Xin.Sh32.src);
+ vex_printf("$%d,", i->Xin.Sh32.src);
ppX86RM(i->Xin.Sh32.dst);
return;
case Xin_Test32:
vex_printf(",");
ppX86AMode(i->Xin.Store.dst);
return;
+ case Xin_FpUnary:
+ vex_printf("g%sD ", showX86FpOp(i->Xin.FpUnary.op));
+ ppHRegX86(i->Xin.FpUnary.src);
+ vex_printf(",");
+ ppHRegX86(i->Xin.FpUnary.dst);
+ break;
+ case Xin_FpBinary:
+ vex_printf("g%sD ", showX86FpOp(i->Xin.FpBinary.op));
+ ppHRegX86(i->Xin.FpBinary.srcL);
+ vex_printf(",");
+ ppHRegX86(i->Xin.FpBinary.srcR);
+ vex_printf(",");
+ ppHRegX86(i->Xin.FpBinary.dst);
+ break;
case Xin_FpLdSt:
if (i->Xin.FpLdSt.isLoad) {
vex_printf("gld%c " , i->Xin.FpLdSt.sz==8 ? 'D' : 'F');
ppX86AMode(i->Xin.FpLdSt.addr);
}
return;
+ case Xin_FpI64:
+ if (i->Xin.FpI64.toInt) {
+ vassert(0);
+ } else {
+ vex_printf("gi64tof64 ");
+ ppHRegX86(i->Xin.FpI64.iregHi);
+ vex_printf(":");
+ ppHRegX86(i->Xin.FpI64.iregLo);
+ vex_printf(", ");
+ ppHRegX86(i->Xin.FpI64.freg);
+ }
+ return;
default:
vpanic("ppX86Instr");
}
addHRegUse(u, HRmRead, i->Xin.Store.src);
addRegUsage_X86AMode(u, i->Xin.Store.dst);
return;
+ case Xin_FpUnary:
+ addHRegUse(u, HRmRead, i->Xin.FpUnary.src);
+ addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst);
+ return;
+ case Xin_FpBinary:
+ addHRegUse(u, HRmRead, i->Xin.FpBinary.srcL);
+ addHRegUse(u, HRmRead, i->Xin.FpBinary.srcR);
+ addHRegUse(u, HRmWrite, i->Xin.FpBinary.dst);
+ return;
case Xin_FpLdSt:
addRegUsage_X86AMode(u, i->Xin.FpLdSt.addr);
addHRegUse(u, i->Xin.FpLdSt.isLoad ? HRmWrite : HRmRead,
i->Xin.FpLdSt.reg);
return;
+ case Xin_FpI64:
+ if (i->Xin.FpI64.toInt) {
+ vassert(0);
+ } else {
+ addHRegUse(u, HRmWrite, i->Xin.FpI64.freg);
+ addHRegUse(u, HRmRead, i->Xin.FpI64.iregHi);
+ addHRegUse(u, HRmRead, i->Xin.FpI64.iregLo);
+ }
+ return;
default:
ppX86Instr(i);
vpanic("getRegUsage_X86Instr");
mapReg(m, &i->Xin.Store.src);
mapRegs_X86AMode(m, i->Xin.Store.dst);
return;
+ case Xin_FpBinary:
+ mapReg(m, &i->Xin.FpBinary.srcL);
+ mapReg(m, &i->Xin.FpBinary.srcR);
+ mapReg(m, &i->Xin.FpBinary.dst);
+ return;
case Xin_FpLdSt:
mapRegs_X86AMode(m, i->Xin.FpLdSt.addr);
mapReg(m, &i->Xin.FpLdSt.reg);
return;
+ case Xin_FpI64:
+ mapReg(m, &i->Xin.FpI64.freg);
+ mapReg(m, &i->Xin.FpI64.iregHi);
+ mapReg(m, &i->Xin.FpI64.iregLo);
+ return;
default:
ppX86Instr(i);
vpanic("mapRegs_X86Instr");
}
}
+/* Figure out if i represents a reg-reg move, and if so assign the
+ source and destination to *src and *dst. If in doubt say No. Used
+ by the register allocator to do move coalescing.
+*/
Bool isMove_X86Instr ( X86Instr* i, HReg* src, HReg* dst )
{
- if (i->tag != Xin_Alu32R)
- return False;
- if (i->Xin.Alu32R.op != Xalu_MOV)
- return False;
- if (i->Xin.Alu32R.src->tag != Xrmi_Reg)
- return False;
- *src = i->Xin.Alu32R.src->Xrmi.Reg.reg;
- *dst = i->Xin.Alu32R.dst;
- return True;
+ /* Moves between integer regs */
+ if (i->tag == Xin_Alu32R) {
+ if (i->Xin.Alu32R.op != Xalu_MOV)
+ return False;
+ if (i->Xin.Alu32R.src->tag != Xrmi_Reg)
+ return False;
+ *src = i->Xin.Alu32R.src->Xrmi.Reg.reg;
+ *dst = i->Xin.Alu32R.dst;
+ return True;
+ }
+ /* Moves between FP regs */
+ if (i->tag == Xin_FpUnary) {
+ if (i->Xin.FpUnary.op != Xfp_MOV)
+ return False;
+ *src = i->Xin.FpUnary.src;
+ *dst = i->Xin.FpUnary.dst;
+ return True;
+ }
+ return False;
}
+
/* x86 spill/reload using the hacked104 testbed. Spill slots
start at word 51, and there are 24 in total.
*/
return p;
}
+/* Emit f<op> %st(i), 1 <= i <= 5 */
+static UChar* do_fop_st ( UChar* p, X86FpOp op, Int i )
+{
+# define fake(_n) mkHReg((_n), HRcInt, False)
+ Int subopc;
+ switch (op) {
+ case Xfp_MUL: subopc = 1; break;
+ default: vpanic("do_fop_st: unknown op");
+ }
+ *p++ = 0xD8;
+ p = doAMode_R(p, fake(subopc), fake(i));
+ return p;
+# undef fake
+}
/* Emit an instruction into buf and return the number of bytes used.
Note that buf is not the insn's final place, and therefore it is
} /* if (i->Xin.Store.sz == 1) */
break;
+ case Xin_FpBinary:
+ /* gop %srcL, %srcR, %dst
+ --> ffree %st7 ; fld %st(srcL) ; fop %st(1+srcR) ; fstp %st(1+dst)
+ */
+ p = do_ffree_st7(p);
+ p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
+ p = do_fop_st(p, i->Xin.FpBinary.op, 1+hregNumber(i->Xin.FpBinary.srcR));
+ p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
+ goto done;
+
case Xin_FpLdSt:
if (i->Xin.FpLdSt.isLoad) {
/* Load from memory into %fakeN.
- --> ffree %st(7) ; fld{s/l} amode ; fstp st(I+1)
+ --> ffree %st(7) ; fld{s/l} amode ; fstp st(N+1)
*/
p = do_ffree_st7(p);
*p++ = i->Xin.FpLdSt.sz==4 ? 0xD9 : 0xDD;
goto done;
} else {
/* Store from %fakeN into memory.
- --> ffree %st(7) ; fld st(I) ; fstp{l|s} amode
+ --> ffree %st(7) ; fld st(N) ; fstp{l|s} amode
*/
p = do_ffree_st7(p);
p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdSt.reg));
}
break;
+ case Xin_FpI64:
+ if (i->Xin.FpI64.toInt) {
+ vassert(0);
+ } else {
+ /* gi64tof64 %hi:%lo %fakeN
+ --> ffree %st7; pushl hi ; pushl lo ; fildll 0(%esp) ;
+ addl $8,%esp ; fstpl %st(N+1)
+ */
+ /* ffree %st(7) */
+ p = do_ffree_st7(p);
+ /* pushl %hi ; pushl %lo */
+ *p++ = 0x50 + hregNumber(i->Xin.FpI64.iregHi);
+ *p++ = 0x50 + hregNumber(i->Xin.FpI64.iregLo);
+ /* fildll 0(%esp) */
+ *p++ = 0xDF; *p++ = 0x6C; *p++ = 0x24; *p++ = 0x00;
+ /* addl $8, %esp */
+ *p++ = 0x83; *p++ = 0xC4; *p++ = 0x08;
+ p = do_fstp_st(p, 1+hregNumber(i->Xin.FpI64.freg));
+ goto done;
+ }
+
default:
goto bad;
}
/* --------- */
typedef
enum {
- Xfp_Add, Xfp_Sub, Xfp_Mul, Xfp_Div,
- Xfp_Sqrt, Xfp_Negate
+ Xfp_INVALID,
+ /* Binary */
+ Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV,
+ /* Unary */
+ Xfp_SQRT, Xfp_NEGATE, Xfp_MOV
}
X86FpOp;
return;
}
+ /* 32Sto64(e) */
+ if (e->tag == Iex_Unop
+ && e->Iex.Unop.op == Iop_32Sto64) {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, mk_MOVsd_RR(src,tHi));
+ addInstr(env, mk_MOVsd_RR(src,tLo));
+ addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tHi)));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
/* 64-bit shifts */
if (e->tag == Iex_Binop
&& e->Iex.Binop.op == Iop_Shl64) {
vassert(e);
vassert(typeOfIRExpr(env->type_env,e) == Ity_F64);
+ if (e->tag == Iex_Tmp) {
+ return lookupIRTemp(env, e->Iex.Tmp.tmp);
+ }
+
if (e->tag == Iex_LDle) {
X86AMode* am;
HReg res = newVRegF(env);
return res;
}
+ if (e->tag == Iex_GetI) {
+ /* First off, compute the index expression into an integer reg.
+ The written address will then be 0 + ebp + reg*1, that is, an
+ X86AMode_IRRS. */
+ HReg idx = iselIntExpr_R(env, e->Iex.GetI.offset);
+ HReg res = newVRegF(env);
+ addInstr(env,
+ X86Instr_FpLdSt( True/*load*/, 8, res,
+ X86AMode_IRRS(0, hregX86_EBP(), idx, 0)) );
+ return res;
+ }
+
+ if (e->tag == Iex_Binop) {
+ X86FpOp fpop = Xfp_INVALID;
+ switch (e->Iex.Binop.op) {
+ case Iop_MulF64: fpop = Xfp_MUL; break;
+ default: break;
+ }
+ if (fpop != Xfp_INVALID) {
+ HReg res = newVRegF(env);
+ HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
+ HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
+ addInstr(env, X86Instr_FpBinary(fpop,srcL,srcR,res));
+ return res;
+ }
+ }
+
+ if (e->tag == Iex_Unop) {
+ if (e->Iex.Unop.op == Iop_I64toF64) {
+ HReg iHi, iLo;
+ HReg dst = newVRegF(env);
+ iselIntExpr64(&iHi, &iLo, env, e->Iex.Unop.arg);
+ addInstr(env, X86Instr_FpI64(False/*i->f*/,dst,iHi,iLo));
+ return dst;
+ }
+ }
+
ppIRExpr(e);
- vpanic("iselIntExpr64");
+ vpanic("iselDblExpr");
}
return;
}
if (ty == Ity_I8 || ty == Ity_I16) {
- /* We're going to write to memory, so compute the RHS into an
- X86RI. */
- HReg r = iselIntExpr_R(env, stmt->Ist.Put.expr);
+ HReg r = iselIntExpr_R(env, stmt->Ist.Put.expr);
addInstr(env, X86Instr_Store(
ty==Ity_I8 ? 1 : 2,
r,
addInstr(env, mk_MOVsd_RR(rLo,dstLo) );
return;
}
+ if (ty == Ity_F64) {
+ HReg dst = lookupIRTemp(env, tmp);
+ HReg src = iselDblExpr(env, stmt->Ist.Tmp.expr);
+ addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst));
+ return;
+ }
break;
}
case Ity_I32: hreg = mkHReg(j++, HRcInt, True); break;
case Ity_I64: hreg = mkHReg(j++, HRcInt, True);
hregHI = mkHReg(j++, HRcInt, True); break;
+ case Ity_F64: hreg = mkHReg(j++, HRcFloat, True); break;
default: ppIRType(bb->tyenv->types[i]);
vpanic("iselBB: IRTemp type");
}
case Iop_8Sto16: vex_printf("8Sto16"); return;
case Iop_8Sto32: vex_printf("8Sto32"); return;
case Iop_16Sto32: vex_printf("16Sto32"); return;
+ case Iop_32Sto64: vex_printf("32Sto64"); return;
case Iop_32to8: vex_printf("32to8"); return;
case Iop_32to1: vex_printf("32to1"); return;
case Iop_1Uto8: vex_printf("1Uto8"); return;
case Iop_64to32: vex_printf("64to32"); return;
case Iop_32HLto64: vex_printf("32HLto64"); return;
+ case Iop_MulF64: vex_printf("MulF64"); return;
+ case Iop_I64toF64: vex_printf("I64toF64"); return;
+
default: vpanic("ppIROp(1)");
}
ppIRType(e->Iex.Get.ty);
vex_printf(")");
break;
+ case Iex_GetI:
+ vex_printf( "GETI[%d,%d](", e->Iex.GetI.minoff, e->Iex.GetI.maxoff);
+ ppIRExpr(e->Iex.GetI.offset);
+ vex_printf("):");
+ ppIRType(e->Iex.GetI.ty);
+ break;
case Iex_Tmp:
ppIRTemp(e->Iex.Tmp.tmp);
break;
case Iop_8Sto32: UNARY(Ity_I32,Ity_I8);
case Iop_16Uto32: UNARY(Ity_I32,Ity_I16);
case Iop_16Sto32: UNARY(Ity_I32,Ity_I16);
+ 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_I64toF64: UNARY(Ity_F64,Ity_I64);
+
default:
ppIROp(op);
vpanic("typeOfPrimop");
return e->Iex.LDle.ty;
case Iex_Get:
return e->Iex.Get.ty;
+ case Iex_GetI:
+ return e->Iex.GetI.ty;
case Iex_Tmp:
return lookupIRTypeEnv(tyenv, e->Iex.Tmp.tmp);
case Iex_Const:
switch (ty) {
case Ity_INVALID: case Ity_Bit:
case Ity_I8: case Ity_I16: case Ity_I32: case Ity_I64:
+ case Ity_F32: case Ity_F64:
return True;
default:
return False;
switch (expr->tag) {
case Iex_Get:
break;
+ case Iex_GetI:
+ useBeforeDef_Expr(bb,stmt,expr->Iex.GetI.offset,def_counts);
+ break;
case Iex_Tmp:
if (expr->Iex.Tmp.tmp < 0 || expr->Iex.Tmp.tmp >= bb->tyenv->types_used)
sanityCheckFail(bb,stmt, "out of range Temp in IRExpr");
case Iex_Get:
case Iex_Tmp:
break;
+ case Iex_GetI:
+ tcExpr(bb,stmt, expr->Iex.GetI.offset, gWordTy );
+ if (typeOfIRExpr(tyenv,expr->Iex.GetI.offset) != Ity_I32)
+ sanityCheckFail(bb,stmt,"IRExpr.GetI.offset: not :: Ity_I32");
+ break;
case Iex_Binop: {
IRType ttarg1, ttarg2;
tcExpr(bb,stmt, expr->Iex.Binop.arg1, gWordTy );
Iop_DivModS64to32, // ditto, signed
/* Widening conversions */
Iop_8Uto16, Iop_8Uto32, Iop_16Uto32,
- Iop_8Sto16, Iop_8Sto32, Iop_16Sto32,
+ Iop_8Sto16, Iop_8Sto32, Iop_16Sto32, Iop_32Sto64,
/* Narrowing conversions */
Iop_32to8,
/* 8 <-> 16 bit conversions */