fp_pop();
break;
+ case 0xF8: { /* FPREM -- not IEEE compliant */
+ IRTemp a1 = newTemp(Ity_F64);
+ IRTemp a2 = newTemp(Ity_F64);
+ DIP("fprem\n");
+ /* Do FPREM twice, once to get the remainder, and once
+ to get the C3210 flag values. */
+ assign( a1, get_ST(0) );
+ assign( a2, get_ST(1) );
+ put_ST_UNCHECKED(0, binop(Iop_PRemF64,
+ mkexpr(a1), mkexpr(a2)));
+ put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) );
+ break;
+ }
+
case 0xFA: /* FSQRT */
DIP("fsqrt\n");
put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0)));
i->Xin.FpLdStCW.addr = addr;
return i;
}
+X86Instr* X86Instr_FpStSW_AX ( void )
+{
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_FpStSW_AX;
+ return i;
+}
X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst )
{
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
vex_printf(i->Xin.FpLdStCW.isLoad ? "fldcw " : "fstcw ");
ppX86AMode(i->Xin.FpLdStCW.addr);
return;
+ case Xin_FpStSW_AX:
+ vex_printf("fstsw %%ax");
+ return;
case Xin_FpCmp:
vex_printf("gcmp ");
ppHRegX86(i->Xin.FpCmp.srcL);
case Xin_FpLdStCW:
addRegUsage_X86AMode(u, i->Xin.FpLdStCW.addr);
return;
+ case Xin_FpStSW_AX:
+ addHRegUse(u, HRmWrite, hregX86_EAX());
+ return;
case Xin_FpCmp:
addHRegUse(u, HRmRead, i->Xin.FpCmp.srcL);
addHRegUse(u, HRmRead, i->Xin.FpCmp.srcR);
case Xin_FpLdStCW:
mapRegs_X86AMode(m, i->Xin.FpLdStCW.addr);
return;
+ case Xin_FpStSW_AX:
+ return;
case Xin_FpCmp:
mapReg(m, &i->Xin.FpCmp.srcL);
mapReg(m, &i->Xin.FpCmp.srcR);
case Xin_FpBinary:
if (i->Xin.FpBinary.op == Xfp_ATAN) {
/* Have to do this specially. */
- /* ffree %st7 ; fld %st(srcL) ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */
+ /* ffree %st7 ; fld %st(srcL) ;
+ ffree %st7 ; fld %st(srcR+1) ; fpatan ; 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++ = 0xF3;
p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
goto done;
}
+ if (i->Xin.FpBinary.op == Xfp_PREM) {
+ /* Have to do this specially. */
+ /* ffree %st7 ; fld %st(srcR) ;
+ ffree %st7 ; fld %st(srcL+1) ; fprem ; 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 = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst));
+ *p++ = 0xD9; *p++ = 0xF7;
+ p = do_ffree_st7(p);
+ goto done;
+ }
/* General case */
/* gop %srcL, %srcR, %dst
--> ffree %st7 ; fld %st(srcL) ; fop %st(1+srcR) ; fstp %st(1+dst)
}
goto done;
+ case Xin_FpStSW_AX:
+ /* note, this emits fnstsw %ax, not fstsw %ax */
+ *p++ = 0xDF;
+ *p++ = 0xE0;
+ goto done;
case Xin_FpCmp:
/* gcmp %fL, %fR, %dst
enum {
Xfp_INVALID,
/* Binary */
- Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, Xfp_ATAN, Xfp_YL2X,
+ Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV,
+ Xfp_ATAN, Xfp_YL2X, Xfp_PREM,
/* Unary */
Xfp_SQRT, Xfp_ABS, Xfp_NEG, Xfp_MOV, Xfp_SIN, Xfp_COS,
Xfp_ROUND
Xin_FpLdStI, /* FP fake load/store, converting to/from Int */
Xin_FpCMov, /* FP fake floating point (un)conditional move */
Xin_FpLdStCW, /* fldcw / fstcw */
+ Xin_FpStSW_AX, /* fstsw %ax */
Xin_FpCmp /* FP compare, generating a C320 value into int reg */
}
X86InstrTag;
X86AMode* addr;
}
FpLdStCW;
+ /* fstsw %ax */
+ struct {
+ /* no fields */
+ }
+ FpStSW_AX;
/* Do a compare, generating the C320 bits into the dst. */
struct {
HReg srcL;
}
X86Instr;
-extern X86Instr* X86Instr_Alu32R ( X86AluOp, X86RMI*, HReg );
-extern X86Instr* X86Instr_Alu32M ( X86AluOp, X86RI*, X86AMode* );
-extern X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst );
-extern X86Instr* X86Instr_Sh32 ( X86ShiftOp, UInt, X86RM* );
-extern X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst );
-extern X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz, X86RM* );
-extern X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz, X86RM* );
-extern X86Instr* X86Instr_Sh3232 ( X86ShiftOp, UInt amt, HReg src, HReg dst );
-extern X86Instr* X86Instr_Push ( X86RMI* );
-extern X86Instr* X86Instr_Call ( HReg );
-extern X86Instr* X86Instr_Goto ( IRJumpKind, X86CondCode cond, X86RI* dst );
-extern X86Instr* X86Instr_CMov32 ( X86CondCode, X86RM* src, HReg dst );
-extern X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
- X86AMode* src, HReg dst );
-extern X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst );
-extern X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst );
-extern X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst );
-extern X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst );
-extern X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst );
-extern X86Instr* X86Instr_FpLdSt ( Bool isLoad, UChar sz, HReg reg, X86AMode* );
-extern X86Instr* X86Instr_FpLdStI ( Bool isLoad, UChar sz, HReg reg, X86AMode* );
-extern X86Instr* X86Instr_FpCMov ( X86CondCode, HReg src, HReg dst );
-extern X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* );
-extern X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst );
+extern X86Instr* X86Instr_Alu32R ( X86AluOp, X86RMI*, HReg );
+extern X86Instr* X86Instr_Alu32M ( X86AluOp, X86RI*, X86AMode* );
+extern X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst );
+extern X86Instr* X86Instr_Sh32 ( X86ShiftOp, UInt, X86RM* );
+extern X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst );
+extern X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz, X86RM* );
+extern X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz, X86RM* );
+extern X86Instr* X86Instr_Sh3232 ( X86ShiftOp, UInt amt, HReg src, HReg dst );
+extern X86Instr* X86Instr_Push ( X86RMI* );
+extern X86Instr* X86Instr_Call ( HReg );
+extern X86Instr* X86Instr_Goto ( IRJumpKind, X86CondCode cond, X86RI* dst );
+extern X86Instr* X86Instr_CMov32 ( X86CondCode, X86RM* src, HReg dst );
+extern X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
+ X86AMode* src, HReg dst );
+extern X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst );
+extern X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst );
+extern X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst );
+extern X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst );
+extern X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst );
+extern X86Instr* X86Instr_FpLdSt ( Bool isLoad, UChar sz, HReg reg, X86AMode* );
+extern X86Instr* X86Instr_FpLdStI ( Bool isLoad, UChar sz, HReg reg, X86AMode* );
+extern X86Instr* X86Instr_FpCMov ( X86CondCode, HReg src, HReg dst );
+extern X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* );
+extern X86Instr* X86Instr_FpStSW_AX ( void );
+extern X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst );
extern void ppX86Instr ( X86Instr* );
return dst;
}
+ /* C3210 flags following FPU partial remainder (fprem). */
+ if (e->Iex.Binop.op == Iop_PRemC3210F64) {
+ HReg junk = newVRegF(env);
+ HReg dst = newVRegI(env);
+ HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
+ HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
+ addInstr(env, X86Instr_FpBinary(Xfp_PREM,srcL,srcR,junk));
+ /* The previous pseudo-insn will have left the FPU's C3210
+ flags set correctly. So bag them. */
+ addInstr(env, X86Instr_FpStSW_AX());
+ addInstr(env, mk_MOVsd_RR(hregX86_EAX(), dst));
+ addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst));
+ return dst;
+ }
+
break;
}
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_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_PRemF64: fpop = Xfp_PREM; break;
default: break;
}
if (fpop != Xfp_INVALID) {
}
}
-
if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_RoundF64) {
HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
HReg rrm = iselIntExpr_R(env, e->Iex.Binop.arg1);
case Iop_64to32: vex_printf("64to32"); return;
case Iop_32HLto64: vex_printf("32HLto64"); return;
- case Iop_AtanF64: vex_printf("AtanF64"); return;
- case Iop_Yl2xF64: vex_printf("Yl2xF64"); return;
case Iop_AddF64: vex_printf("AddF64"); return;
case Iop_SubF64: vex_printf("SubF64"); return;
case Iop_MulF64: vex_printf("MulF64"); return;
case Iop_DivF64: vex_printf("DivF64"); return;
- case Iop_CmpF64: vex_printf("CmpF64"); return;
- case Iop_NegF64: vex_printf("NegF64"); return;
+
+ case Iop_AtanF64: vex_printf("AtanF64"); return;
+ case Iop_Yl2xF64: vex_printf("Yl2xF64"); return;
+ case Iop_PRemF64: vex_printf("PRemF64"); return;
+ case Iop_PRemC3210F64: vex_printf("PRemC3210F64"); return;
+ case Iop_NegF64: vex_printf("NegF64"); return;
+ case Iop_SqrtF64: vex_printf("SqrtF64"); return;
+
case Iop_AbsF64: vex_printf("AbsF64"); return;
- case Iop_SqrtF64: vex_printf("SqrtF64"); return;
case Iop_SinF64: vex_printf("SinF64"); return;
case Iop_CosF64: vex_printf("CosF64"); return;
+ case Iop_CmpF64: vex_printf("CmpF64"); return;
+
case Iop_I32toF64: vex_printf("I32toF64"); return;
case Iop_I64toF64: vex_printf("I64toF64"); return;
case Iop_32Sto64: UNARY(Ity_I64,Ity_I32);
case Iop_32to8: UNARY(Ity_I8,Ity_I32);
+ case Iop_PRemF64:
case Iop_AtanF64:
case Iop_Yl2xF64:
case Iop_AddF64: case Iop_SubF64:
case Iop_MulF64: case Iop_DivF64:
BINARY(Ity_F64,Ity_F64,Ity_F64);
+ case Iop_PRemC3210F64:
case Iop_CmpF64:
BINARY(Ity_I32,Ity_F64,Ity_F64);
case Iop_NegF64: case Iop_AbsF64: case Iop_SqrtF64:
/* ------ Floating point. We try and be IEEE754 compliant. ------ */
/* Binary operations mandated by IEEE754. */
- Iop_AddF64, Iop_SubF64, Iop_MulF64, Iop_DivF64, Iop_RemF64,
+ Iop_AddF64, Iop_SubF64, Iop_MulF64, Iop_DivF64, /* Iop_RemF64, */
/* Binary ops supported by IA32 but not mandated by 754. */
- Iop_AtanF64, /* FPATAN, arctan(arg1/arg2) */
- Iop_Yl2xF64, /* FYL2X, arg1 * log2(arg2) */
+ Iop_AtanF64, /* FPATAN, arctan(arg1/arg2) */
+ Iop_Yl2xF64, /* FYL2X, arg1 * log2(arg2) */
+ Iop_PRemF64, /* FPREM, remainder(arg1/arg2) */
+ Iop_PRemC3210F64, /* C3210 flags resulting from FPREM, :: I32 */
/* Unary operations mandated by IEEE754. */
Iop_NegF64, Iop_SqrtF64,