put_ST(0, IRExpr_Const(IRConst_F64(0.0)));
break;
+ case 0xF0: /* F2XM1 */
+ DIP("f2xm1\n");
+ put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0)));
+ break;
+
case 0xF1: /* FYL2X */
DIP("fyl2x\n");
put_ST_UNCHECKED(1, binop(Iop_Yl2xF64,
binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) );
break;
+ case 0xFD: /* FSCALE */
+ DIP("fscale\n");
+ put_ST_UNCHECKED(0, binop(Iop_ScaleF64,
+ get_ST(0), get_ST(1)));
+ break;
+
case 0xFE: /* FSIN */
DIP("fsin\n");
put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0)));
delta++;
switch (modrm) {
+ case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
+ r_dst = (UInt)modrm - 0xD0;
+ DIP("fst %%st(0),%%st(%d)\n", r_dst);
+ /* P4 manual says: "If the destination operand is a
+ non-empty register, the invalid-operation exception
+ is not generated. Hence put_ST_UNCHECKED. */
+ put_ST_UNCHECKED(r_dst, get_ST(0));
+ break;
+
case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
r_dst = (UInt)modrm - 0xD8;
DIP("fstp %%st(0),%%st(%d)\n", r_dst);
case Xfp_MOV: return "mov";
case Xfp_SIN: return "sin";
case Xfp_COS: return "cos";
+ case Xfp_2XM1: return "2xm1";
default: vpanic("showX86FpOp");
}
}
case Xfp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break;
case Xfp_SIN: *p++ = 0xD9; *p++ = 0xFE; break;
case Xfp_COS: *p++ = 0xD9; *p++ = 0xFF; break;
+ case Xfp_2XM1: *p++ = 0xD9; *p++ = 0xF0; break;
default: vpanic("do_fop1_st: unknown op");
}
return p;
goto done;
case Xin_FpBinary:
- if (i->Xin.FpBinary.op == Xfp_YL2X) {
+ if (i->Xin.FpBinary.op == Xfp_YL2X
+ || i->Xin.FpBinary.op == Xfp_YL2XP1) {
/* Have to do this specially. */
/* ffree %st7 ; fld %st(srcL) ;
- ffree %st7 ; fld %st(srcR+1) ; fyl2x ; fstp(1+dst) */
+ ffree %st7 ; fld %st(srcR+1) ; fyl2x{p1} ; fstp(1+dst) */
p = do_ffree_st7(p);
p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
p = do_ffree_st7(p);
p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
- *p++ = 0xD9; *p++ = 0xF1;
+ *p++ = 0xD9;
+ *p++ = i->Xin.FpBinary.op==Xfp_YL2X ? 0xF1 : 0xF9;
p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
goto done;
}
p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
goto done;
}
- if (i->Xin.FpBinary.op == Xfp_PREM) {
+ if (i->Xin.FpBinary.op == Xfp_PREM
+ || i->Xin.FpBinary.op == Xfp_SCALE) {
/* Have to do this specially. */
/* ffree %st7 ; fld %st(srcR) ;
- ffree %st7 ; fld %st(srcL+1) ; fprem ; fstp(2+dst) ;
+ ffree %st7 ; fld %st(srcL+1) ; fprem/fscale ; fstp(2+dst) ;
fincstp ; ffree %st7 */
p = do_ffree_st7(p);
p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcR));
p = do_ffree_st7(p);
p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcL));
- *p++ = 0xD9; *p++ = 0xF8;
+ *p++ = 0xD9;
+ *p++ = i->Xin.FpBinary.op==Xfp_PREM ? 0xF8 : 0xFD;
p = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst));
*p++ = 0xD9; *p++ = 0xF7;
p = do_ffree_st7(p);
Xfp_INVALID,
/* Binary */
Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV,
- Xfp_ATAN, Xfp_YL2X, Xfp_PREM,
+ Xfp_SCALE, Xfp_ATAN, Xfp_YL2X, Xfp_YL2XP1, Xfp_PREM,
/* Unary */
Xfp_SQRT, Xfp_ABS, Xfp_NEG, Xfp_MOV, Xfp_SIN, Xfp_COS,
- Xfp_ROUND
+ Xfp_ROUND, Xfp_2XM1
}
X86FpOp;
if (e->tag == Iex_Binop) {
X86FpOp fpop = Xfp_INVALID;
switch (e->Iex.Binop.op) {
- case Iop_AddF64: fpop = Xfp_ADD; break;
- case Iop_SubF64: fpop = Xfp_SUB; break;
- case Iop_MulF64: fpop = Xfp_MUL; break;
- case Iop_DivF64: fpop = Xfp_DIV; break;
- case Iop_AtanF64: fpop = Xfp_ATAN; break;
- case Iop_Yl2xF64: fpop = Xfp_YL2X; break;
- case Iop_PRemF64: fpop = Xfp_PREM; break;
+ case Iop_AddF64: fpop = Xfp_ADD; break;
+ case Iop_SubF64: fpop = Xfp_SUB; break;
+ case Iop_MulF64: fpop = Xfp_MUL; break;
+ case Iop_DivF64: fpop = Xfp_DIV; break;
+ case Iop_ScaleF64: fpop = Xfp_SCALE; break;
+ case Iop_AtanF64: fpop = Xfp_ATAN; break;
+ case Iop_Yl2xF64: fpop = Xfp_YL2X; break;
+ case Iop_Yl2xp1F64: fpop = Xfp_YL2XP1; break;
+ case Iop_PRemF64: fpop = Xfp_PREM; break;
default: break;
}
if (fpop != Xfp_INVALID) {
case Iop_SqrtF64: fpop = Xfp_SQRT; break;
case Iop_SinF64: fpop = Xfp_SIN; break;
case Iop_CosF64: fpop = Xfp_COS; break;
+ case Iop_2xm1F64: fpop = Xfp_2XM1; break;
default: break;
}
if (fpop != Xfp_INVALID) {
case Iop_MulF64: vex_printf("MulF64"); return;
case Iop_DivF64: vex_printf("DivF64"); return;
+ case Iop_ScaleF64: vex_printf("ScaleF64"); return;
case Iop_AtanF64: vex_printf("AtanF64"); return;
case Iop_Yl2xF64: vex_printf("Yl2xF64"); return;
case Iop_Yl2xp1F64: vex_printf("Yl2xp1F64"); return;
case Iop_AbsF64: vex_printf("AbsF64"); return;
case Iop_SinF64: vex_printf("SinF64"); return;
case Iop_CosF64: vex_printf("CosF64"); return;
+ case Iop_2xm1F64: vex_printf("2xm1F64"); return;
case Iop_CmpF64: vex_printf("CmpF64"); return;
case Iop_32Uto64: UNARY(Ity_I64,Ity_I32);
case Iop_32to8: UNARY(Ity_I8,Ity_I32);
+ case Iop_ScaleF64:
case Iop_PRemF64:
case Iop_AtanF64:
case Iop_Yl2xF64:
case Iop_CmpF64:
BINARY(Ity_I32,Ity_F64,Ity_F64);
case Iop_NegF64: case Iop_AbsF64: case Iop_SqrtF64:
- case Iop_SinF64: case Iop_CosF64:
+ case Iop_SinF64: case Iop_CosF64: case Iop_2xm1F64:
UNARY(Ity_F64,Ity_F64);
case Iop_I32toF64: UNARY(Ity_F64,Ity_I32);
Iop_Yl2xp1F64, /* FYL2XP1, arg1 * log2(arg2+1.0) */
Iop_PRemF64, /* FPREM, remainder(arg1/arg2) */
Iop_PRemC3210F64, /* C3210 flags resulting from FPREM, :: I32 */
+ Iop_ScaleF64, /* FSCALE, arg1 * (2^RoundTowardsZero(arg2)) */
/* Unary operations mandated by IEEE754. */
Iop_NegF64, Iop_SqrtF64,
Iop_AbsF64, /* FABS */
Iop_SinF64, /* FSIN */
Iop_CosF64, /* FCOS */
+ Iop_2xm1F64, /* (2^arg - 1.0) */
/* Comparison, yielding GT/LT/EQ/UN(ordered), as per the following:
0x45 Unordered