put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
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 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,
+ triop(Iop_PRemF64,
+ get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
+ mkexpr(a1),
+ mkexpr(a2)));
+ put_C3210(
+ unop(Iop_32Uto64,
+ triop(Iop_PRemC3210F64,
+ get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
+ mkexpr(a1),
+ mkexpr(a2)) ));
+ break;
+ }
+
case 0xF9: /* FYL2XP1 */
DIP("fyl2xp1\n");
put_ST_UNCHECKED(1,
case Afp_ATAN: return "atan";
case Afp_YL2X: return "yl2x";
case Afp_YL2XP1: return "yl2xp1";
-//.. case Xfp_PREM: return "prem";
+ case Afp_PREM: return "prem";
//.. case Xfp_PREM1: return "prem1";
case Afp_SQRT: return "sqrt";
//.. case Xfp_ABS: return "abs";
i->Ain.A87LdCW.addr = addr;
return i;
}
+AMD64Instr* AMD64Instr_A87StSW ( AMD64AMode* addr )
+{
+ AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr));
+ i->tag = Ain_A87StSW;
+ i->Ain.A87StSW.addr = addr;
+ return i;
+}
//.. AMD64Instr* AMD64Instr_FpUnary ( AMD64FpOp op, HReg src, HReg dst ) {
//.. AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr));
vex_printf("mfence" );
return;
case Ain_A87Free:
- vex_printf("ffree %%st(7..%d)\n", 7 - i->Ain.A87Free.nregs );
+ vex_printf("ffree %%st(7..%d)", 8 - i->Ain.A87Free.nregs );
break;
case Ain_A87PushPop:
vex_printf(i->Ain.A87PushPop.isPush ? "fldl " : "fstpl ");
ppAMD64AMode(i->Ain.A87PushPop.addr);
break;
case Ain_A87FpOp:
- vex_printf("f%s\n", showA87FpOp(i->Ain.A87FpOp.op));
+ vex_printf("f%s", showA87FpOp(i->Ain.A87FpOp.op));
break;
case Ain_A87LdCW:
vex_printf("fldcw ");
ppAMD64AMode(i->Ain.A87LdCW.addr);
break;
+ case Ain_A87StSW:
+ vex_printf("fstsw ");
+ ppAMD64AMode(i->Ain.A87StSW.addr);
+ break;
//.. case Xin_FpUnary:
//.. vex_printf("g%sD ", showAMD64FpOp(i->Xin.FpUnary.op));
//.. ppHRegAMD64(i->Xin.FpUnary.src);
case Ain_A87LdCW:
addRegUsage_AMD64AMode(u, i->Ain.A87LdCW.addr);
return;
+ case Ain_A87StSW:
+ addRegUsage_AMD64AMode(u, i->Ain.A87StSW.addr);
+ return;
//.. case Xin_FpUnary:
//.. addHRegUse(u, HRmRead, i->Xin.FpUnary.src);
//.. addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst);
case Ain_A87LdCW:
mapRegs_AMD64AMode(m, i->Ain.A87LdCW.addr);
return;
+ case Ain_A87StSW:
+ mapRegs_AMD64AMode(m, i->Ain.A87StSW.addr);
+ return;
//.. case Xin_FpUnary:
//.. mapReg(m, &i->Xin.FpUnary.src);
//.. mapReg(m, &i->Xin.FpUnary.dst);
case Afp_ATAN: *p++ = 0xD9; *p++ = 0xF3; break;
case Afp_YL2X: *p++ = 0xD9; *p++ = 0xF1; break;
case Afp_YL2XP1: *p++ = 0xD9; *p++ = 0xF9; break;
+ case Afp_PREM: *p++ = 0xD9; *p++ = 0xF8; break;
default: goto bad;
}
goto done;
p = doAMode_M(p, fake(5)/*subopcode*/, i->Ain.A87LdCW.addr);
goto done;
+ case Ain_A87StSW:
+ *p++ = clearWBit(
+ rexAMode_M(fake(7), i->Ain.A87StSW.addr) );
+ *p++ = 0xDD;
+ p = doAMode_M(p, fake(7)/*subopcode*/, i->Ain.A87StSW.addr);
+ goto done;
+
case Ain_Store:
if (i->Ain.Store.sz == 2) {
/* This just goes to show the crazyness of the instruction
enum {
Afp_INVALID,
/* Binary */
- Afp_SCALE, Afp_ATAN, Afp_YL2X, Afp_YL2XP1,
+ Afp_SCALE, Afp_ATAN, Afp_YL2X, Afp_YL2XP1, Afp_PREM,
/* Unary */
Afp_SQRT,
Afp_SIN, Afp_COS, Afp_TAN,
Ain_A87PushPop, /* x87 loads/stores */
Ain_A87FpOp, /* x87 operations */
Ain_A87LdCW, /* load x87 control word */
+ Ain_A87StSW, /* store x87 status word */
//..
//.. Xin_FpUnary, /* FP fake unary op */
//.. Xin_FpBinary, /* FP fake binary op */
AMD64AMode* addr;
} A87LdCW;
+ /* Store the FPU status word (fstsw m16) */
+ struct {
+ AMD64AMode* addr;
+ } A87StSW;
+
/* --- SSE --- */
/* Load 32 bits into %mxcsr. */
extern AMD64Instr* AMD64Instr_A87PushPop ( AMD64AMode* addr, Bool isPush );
extern AMD64Instr* AMD64Instr_A87FpOp ( A87FpOp op );
extern AMD64Instr* AMD64Instr_A87LdCW ( AMD64AMode* addr );
+extern AMD64Instr* AMD64Instr_A87StSW ( AMD64AMode* addr );
//..
//.. extern AMD64Instr* AMD64Instr_FpUnary ( AMD64FpOp op, HReg src, HReg dst );
//.. extern AMD64Instr* AMD64Instr_FpBinary ( AMD64FpOp op, HReg srcL, HReg srcR, HReg dst );
break;
}
+ /* --------- TERNARY OP --------- */
+ case Iex_Triop: {
+ /* C3210 flags following FPU partial remainder (fprem), both
+ IEEE compliant (PREM1) and non-IEEE compliant (PREM). */
+ if (e->Iex.Triop.op == Iop_PRemC3210F64) {
+ AMD64AMode* m8_rsp = AMD64AMode_IR(-8, hregAMD64_RSP());
+ HReg arg1 = iselDblExpr(env, e->Iex.Triop.arg2);
+ HReg arg2 = iselDblExpr(env, e->Iex.Triop.arg3);
+ HReg dst = newVRegI(env);
+ addInstr(env, AMD64Instr_A87Free(2));
+
+ /* one arg -> top of x87 stack */
+ addInstr(env, AMD64Instr_SseLdSt(False/*store*/, 8, arg2, m8_rsp));
+ addInstr(env, AMD64Instr_A87PushPop(m8_rsp, True/*push*/));
+
+ /* other arg -> top of x87 stack */
+ addInstr(env, AMD64Instr_SseLdSt(False/*store*/, 8, arg1, m8_rsp));
+ addInstr(env, AMD64Instr_A87PushPop(m8_rsp, True/*push*/));
+
+ switch (e->Iex.Triop.op) {
+ case Iop_PRemC3210F64:
+ addInstr(env, AMD64Instr_A87FpOp(Afp_PREM));
+ break;
+ default:
+ vassert(0);
+ }
+ /* Ignore the result, and instead make off with the FPU's
+ C3210 flags (in the status word). */
+ addInstr(env, AMD64Instr_A87StSW(m8_rsp));
+ addInstr(env, AMD64Instr_Alu64R(Aalu_MOV,AMD64RMI_Mem(m8_rsp),dst));
+ addInstr(env, AMD64Instr_Alu64R(Aalu_AND,AMD64RMI_Imm(0x4700),dst));
+ return dst;
+ }
+ break;
+ }
+
default:
break;
} /* switch (e->tag) */
&& (e->Iex.Triop.op == Iop_ScaleF64
|| e->Iex.Triop.op == Iop_AtanF64
|| e->Iex.Triop.op == Iop_Yl2xF64
- || e->Iex.Triop.op == Iop_Yl2xp1F64)
+ || e->Iex.Triop.op == Iop_Yl2xp1F64
+ || e->Iex.Triop.op == Iop_PRemF64)
) {
AMD64AMode* m8_rsp = AMD64AMode_IR(-8, hregAMD64_RSP());
HReg arg1 = iselDblExpr(env, e->Iex.Triop.arg2);
HReg arg2 = iselDblExpr(env, e->Iex.Triop.arg3);
HReg dst = newVRegV(env);
- Bool arg2first = toBool(e->Iex.Triop.op == Iop_ScaleF64);
+ Bool arg2first = toBool(e->Iex.Triop.op == Iop_ScaleF64
+ || e->Iex.Triop.op == Iop_PRemF64);
addInstr(env, AMD64Instr_A87Free(2));
/* one arg -> top of x87 stack */
case Iop_Yl2xp1F64:
addInstr(env, AMD64Instr_A87FpOp(Afp_YL2XP1));
break;
+ case Iop_PRemF64:
+ addInstr(env, AMD64Instr_A87FpOp(Afp_PREM));
+ break;
default:
vassert(0);
}