modes associated with them.
git-svn-id: svn://svn.valgrind.org/vex/trunk@616
case 2: /* FST single-real */
DIP("fstS %s", dis_buf);
- storeLE(mkexpr(addr), unop(Iop_F64toF32, get_ST(0)));
+ storeLE(mkexpr(addr),
+ binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
break;
case 3: /* FSTP single-real */
DIP("fstpS %s", dis_buf);
- storeLE(mkexpr(addr), unop(Iop_F64toF32, get_ST(0)));
+ storeLE(mkexpr(addr),
+ binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
fp_pop();
break;
assign( rmode, get_sse_roundingmode() );
putXMMRegLane32F(
- gregOfRM(modrm), 0,
- binop(Iop_I32toF32,
+ gregOfRM(modrm), 0,
+ binop(Iop_F64toF32,
mkexpr(rmode),
- unop(Iop_64to32, mkexpr(arg64)) ) );
+ unop(Iop_I32toF64,
+ unop(Iop_64to32, mkexpr(arg64)) )) );
putXMMRegLane32F(
gregOfRM(modrm), 1,
- binop(Iop_I32toF32,
+ binop(Iop_F64toF32,
mkexpr(rmode),
- unop(Iop_64HIto32, mkexpr(arg64)) ) );
+ unop(Iop_I32toF64,
+ unop(Iop_64HIto32, mkexpr(arg64)) )) );
goto decode_success;
}
assign( rmode, get_sse_roundingmode() );
putXMMRegLane32F(
- gregOfRM(modrm), 0,
- binop(Iop_I32toF32, mkexpr(rmode), mkexpr(arg32)) );
+ gregOfRM(modrm), 0,
+ binop(Iop_F64toF32,
+ mkexpr(rmode),
+ unop(Iop_I32toF64, mkexpr(arg32)) ) );
goto decode_success;
}
goto decode_success;
}
+ /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
+ /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
+ if (insn[0] == 0x0F && insn[1] == 0x56) {
+ }
+
//--
//-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
//-- if (insn[0] == 0x0F && insn[1] == 0xAE
vassert(sz == 2 || sz == 4 || sz == 8);
return i;
}
+X86Instr* X86Instr_Fp64to32 ( HReg src, HReg dst ) {
+ X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
+ i->tag = Xin_Fp64to32;
+ i->Xin.Fp64to32.src = src;
+ i->Xin.Fp64to32.dst = dst;
+ return i;
+}
X86Instr* X86Instr_FpCMov ( X86CondCode cond, HReg src, HReg dst ) {
X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
i->tag = Xin_FpCMov;
ppX86AMode(i->Xin.FpLdStI.addr);
}
return;
+ case Xin_Fp64to32:
+ vex_printf("gdtof ");
+ ppHRegX86(i->Xin.Fp64to32.src);
+ vex_printf(",");
+ ppHRegX86(i->Xin.Fp64to32.dst);
+ return;
case Xin_FpCMov:
vex_printf("gcmov%s ", showX86CondCode(i->Xin.FpCMov.cond));
ppHRegX86(i->Xin.FpCMov.src);
addHRegUse(u, i->Xin.FpLdStI.isLoad ? HRmWrite : HRmRead,
i->Xin.FpLdStI.reg);
return;
+ case Xin_Fp64to32:
+ addHRegUse(u, HRmRead, i->Xin.Fp64to32.src);
+ addHRegUse(u, HRmWrite, i->Xin.Fp64to32.dst);
+ return;
case Xin_FpCMov:
addHRegUse(u, HRmRead, i->Xin.FpCMov.src);
addHRegUse(u, HRmModify, i->Xin.FpCMov.dst);
mapRegs_X86AMode(m, i->Xin.FpLdStI.addr);
mapReg(m, &i->Xin.FpLdStI.reg);
return;
+ case Xin_Fp64to32:
+ mapReg(m, &i->Xin.Fp64to32.src);
+ mapReg(m, &i->Xin.Fp64to32.dst);
+ return;
case Xin_FpCMov:
mapReg(m, &i->Xin.FpCMov.src);
mapReg(m, &i->Xin.FpCMov.dst);
*/
p = do_ffree_st7(p);
p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
- p = do_fop2_st(p, i->Xin.FpBinary.op, 1+hregNumber(i->Xin.FpBinary.srcR));
+ p = do_fop2_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:
+ vassert(i->Xin.FpLdSt.sz == 4 || i->Xin.FpLdSt.sz == 8);
if (i->Xin.FpLdSt.isLoad) {
/* Load from memory into %fakeN.
--> ffree %st(7) ; fld{s/l} amode ; fstp st(N+1)
}
break;
+ case Xin_Fp64to32:
+ /* ffree %st7 ; fld %st(src) */
+ p = do_ffree_st7(p);
+ p = do_fld_st(p, 0+fregNo(i->Xin.Fp64to32.src));
+ /* subl $4, %esp */
+ *p++ = 0x83; *p++ = 0xEC; *p++ = 0x04;
+ /* fstps (%esp) */
+ *p++ = 0xD9; *p++ = 0x1C; *p++ = 0x24;
+ /* flds (%esp) */
+ *p++ = 0xD9; *p++ = 0x04; *p++ = 0x24;
+ /* addl $4, %esp */
+ *p++ = 0x83; *p++ = 0xC4; *p++ = 0x04;
+ /* fstp %st(1+dst) */
+ p = do_fstp_st(p, 1+fregNo(i->Xin.Fp64to32.dst));
+ goto done;
+
case Xin_FpCMov:
/* jmp fwds if !condition */
*p++ = 0x70 + (i->Xin.FpCMov.cond ^ 1);
Xin_FpBinary, /* FP fake binary op */
Xin_FpLdSt, /* FP fake load/store */
Xin_FpLdStI, /* FP fake load/store, converting to/from Int */
+ Xin_Fp64to32, /* FP round IEEE754 double to IEEE754 single */
Xin_FpCMov, /* FP fake floating point (un)conditional move */
Xin_FpLdStCW, /* fldcw / fstcw */
Xin_FpStSW_AX, /* fstsw %ax */
X86AMode* addr;
} FpLdSt;
/* Move 64-bit float to/from memory, converting to/from
- signed int on the way. */
+ signed int on the way. Note the conversions will observe
+ the host FPU rounding mode currently in force. */
struct {
Bool isLoad;
UChar sz; /* only 2, 4 or 8 */
HReg reg;
X86AMode* addr;
} FpLdStI;
+ /* By observing the current FPU rounding mode, round (etc)
+ src into dst given that dst should be interpreted as an
+ IEEE754 32-bit (float) type. */
+ struct {
+ HReg src;
+ HReg dst;
+ } Fp64to32;
/* Mov src to dst on the given condition, which may not
be the bogus Xcc_ALWAYS. */
struct {
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_Fp64to32 ( HReg src, HReg dst );
extern X86Instr* X86Instr_FpCMov ( X86CondCode, HReg src, HReg dst );
extern X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* );
extern X86Instr* X86Instr_FpStSW_AX ( void );
if (sz == 2) {
/* movzwl 0(%esp), %dst */
addInstr(env, X86Instr_LoadEX(2,False,zero_esp,dst));
- } else {
+ } else {
/* movl 0(%esp), %dst */
vassert(sz == 4);
addInstr(env, X86Instr_Alu32R(
HReg tHi = newVRegI(env);
X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
+ /* paranoia */
+ set_FPU_rounding_default(env);
/* subl $8, %esp */
addInstr(env,
X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(8), hregX86_ESP()));
return res;
}
- if (e->tag == Iex_Unop
- && e->Iex.Unop.op == Iop_F64toF32) {
- /* this is a no-op */
- return iselDblExpr(env, e->Iex.Unop.arg);
+ if (e->tag == Iex_Binop
+ && e->Iex.Binop.op == Iop_F64toF32) {
+ /* Although the result is still held in a standard FPU register,
+ we need to round it to reflect the loss of accuracy/range
+ entailed in casting it to a 32-bit float. */
+ HReg dst = newVRegF(env);
+ HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
+ set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
+ addInstr(env, X86Instr_Fp64to32(src,dst));
+ set_FPU_rounding_default( env );
+ return dst;
}
if (e->tag == Iex_Get) {
return res;
}
- if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I32toF32) {
- HReg dst = newVRegF(env);
- X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
- X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
-
- /* int value -> stack */
- addInstr(env, X86Instr_Push(rmi));
-
- /* Set host rounding mode */
- set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
-
- /* get it back from the stack, into F80 form. Rounding mode has
- no effect as this can be done exactly. */
- addInstr(env, X86Instr_FpLdStI(True/*load*/, 4, dst, zero_esp));
-
- /* write it back to the stack, as a 32-bit float. Rounding mode
- effects this. */
- addInstr(env, X86Instr_FpLdSt(False/*store*/, 4, dst, zero_esp));
-
- /* and finally ... fetch it back again. (sigh) */
- addInstr(env, X86Instr_FpLdSt(True/*load*/, 4, dst, zero_esp));
-
- /* Restore default FPU rounding. */
- set_FPU_rounding_default( env );
-
- addInstr(env, X86Instr_Alu32R(Xalu_ADD,
- X86RMI_Imm(4),
- hregX86_ESP()));
- return dst;
- }
-
ppIRExpr(e);
vpanic("iselFltExpr_wrk");
}
HReg dst = newVRegF(env);
HReg rHi, rLo;
iselInt64Expr( &rHi, &rLo, env, e->Iex.Unop.arg);
+ /* paranoia */
+ set_FPU_rounding_default(env);
addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
- set_FPU_rounding_default(env);
addInstr(env, X86Instr_FpLdSt(
True/*load*/, 8, dst,
X86AMode_IR(0, hregX86_ESP())));
case Iop_CmpF64: vex_printf("CmpF64"); return;
+ case Iop_F64toI16: vex_printf("F64toI16"); return;
+ case Iop_F64toI32: vex_printf("F64toI32"); return;
+ case Iop_F64toI64: vex_printf("F64toI64"); return;
+
+ case Iop_I16toF64: vex_printf("I16toF64"); return;
case Iop_I32toF64: vex_printf("I32toF64"); return;
case Iop_I64toF64: vex_printf("I64toF64"); return;
- case Iop_I32toF32: vex_printf("I32toF32"); return;
-
- case Iop_F64toI64: vex_printf("F64toI64"); return;
- case Iop_F64toI32: vex_printf("F64toI32"); return;
- case Iop_F64toI16: vex_printf("F64toI16"); return;
- case Iop_RoundF64: vex_printf("RoundF64"); return;
case Iop_F32toF64: vex_printf("F32toF64"); return;
case Iop_F64toF32: vex_printf("F64toF32"); return;
+ case Iop_RoundF64: vex_printf("RoundF64"); return;
+
case Iop_ReinterpF64asI64: vex_printf("ReinterpF64asI64"); return;
case Iop_ReinterpI64asF64: vex_printf("ReinterpI64asF64"); return;
case Iop_SinF64: case Iop_CosF64: case Iop_TanF64: case Iop_2xm1F64:
UNARY(Ity_F64,Ity_F64);
- case Iop_I32toF64: UNARY(Ity_F64,Ity_I32);
- case Iop_ReinterpI64asF64: UNARY(Ity_F64,Ity_I64);
+ case Iop_ReinterpI64asF64: UNARY(Ity_F64, Ity_I64);
case Iop_ReinterpF64asI64: UNARY(Ity_I64, Ity_F64);
- case Iop_I32toF32: BINARY(Ity_F32, Ity_I32,Ity_I32);
+ case Iop_F64toI16: BINARY(Ity_I16, Ity_I32,Ity_F64);
+ case Iop_F64toI32: BINARY(Ity_I32, Ity_I32,Ity_F64);
+ case Iop_F64toI64: BINARY(Ity_I64, Ity_I32,Ity_F64);
+
+ case Iop_I16toF64: UNARY(Ity_F64, Ity_I16);
+ case Iop_I32toF64: UNARY(Ity_F64, Ity_I32);
case Iop_I64toF64: BINARY(Ity_F64, Ity_I32,Ity_I64);
- case Iop_F64toI64: BINARY(Ity_I64, Ity_I32,Ity_F64);
- case Iop_F64toI32: BINARY(Ity_I32, Ity_I32,Ity_F64);
- case Iop_F64toI16: BINARY(Ity_I16, Ity_I32,Ity_F64);
- case Iop_RoundF64: BINARY(Ity_F64, Ity_I32,Ity_F64);
+ case Iop_F32toF64: UNARY(Ity_F64, Ity_F32);
+ case Iop_F64toF32: BINARY(Ity_F32, Ity_I32,Ity_F64);
- case Iop_F32toF64: UNARY(Ity_F64,Ity_F32);
- case Iop_F64toF32: UNARY(Ity_F32,Ity_F64);
+ case Iop_RoundF64: BINARY(Ity_F64, Ity_I32,Ity_F64);
case Iop_64HLto128: BINARY(Ity_V128, Ity_I64,Ity_I64);
case Iop_128to64: case Iop_128HIto64:
*/
Iop_CmpF64,
- /* int -> double */
- Iop_I32toF64, /* no rounding needed because result can always be
- represented exactly */
-
- /* double -> int. These take a first argument :: Ity_I32
- (an IRRoundingMode) which is an indication of the rounding mode,
- as per the following encoding:
+ /* --- Int to/from FP conversions. --- */
+ /* For the most part, these take a first argument :: Ity_I32
+ (as IRRoundingMode) which is an indication of the rounding
+ mode to use, as per the following encoding:
00b to nearest (the default)
01b to -infinity
10b to +infinity
the "integer indefinite" value 0x80..00 is produced.
On PPC it is either 0x80..00 or 0x7F..FF depending on the sign
of the argument.
+
+ Rounding is required whenever the destination type cannot
+ represent exactly all values of the source type.
*/
- Iop_F64toI64, Iop_F64toI32, Iop_F64toI16,
+ Iop_F64toI16, /* IRRoundingMode(I32) x F64 -> I16 */
+ Iop_F64toI32, /* IRRoundingMode(I32) x F64 -> I32 */
+ Iop_F64toI64, /* IRRoundingMode(I32) x F64 -> I64 */
- /* these also take an I32 first argument encoding the
- rounding mode. */
- Iop_I64toF64,
- Iop_I32toF32,
+ Iop_I16toF64, /* I16 -> F64 */
+ Iop_I32toF64, /* I32 -> F64 */
+ Iop_I64toF64, /* IRRoundingMode(I32) x I64 -> F64 */
+
+ Iop_F32toF64, /* F32 -> F64 */
+ Iop_F64toF32, /* IRRoundingMode(I32) x F64 -> F32 */
/* F64 -> F64, also takes an I32 first argument encoding the
rounding mode. */
Iop_RoundF64,
- /* double <-> float. What does this mean -- does it round? */
- Iop_F32toF64, Iop_F64toF32,
-
/* Reinterpretation. Take an F64 and produce an I64 with
the same bit pattern, or vice versa. */
Iop_ReinterpF64asI64, Iop_ReinterpI64asF64,