mips32: VEX Support for 64bit FPU on MIPS32 platforms.
This patch is adding support for mips32 with 64bit FPU.
Assume that floating-point registers are 64 bits wide.
git-svn-id: svn://svn.valgrind.org/vex/trunk@2821 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_mips_defs.h b/priv/guest_mips_defs.h
index dc7163c..da112c5 100644
--- a/priv/guest_mips_defs.h
+++ b/priv/guest_mips_defs.h
@@ -99,8 +99,12 @@
extern ULong mips64_dirtyhelper_rdhwr ( ULong rt, ULong rd );
#endif
-extern UInt mips_dirtyhelper_calculate_FCSR ( void* guest_state, UInt fs,
- UInt ft, flt_op op );
+/* Calculate FCSR in fp32 mode. */
+extern UInt mips_dirtyhelper_calculate_FCSR_fp32 ( void* guest_state, UInt fs,
+ UInt ft, flt_op op );
+/* Calculate FCSR in fp64 mode. */
+extern UInt mips_dirtyhelper_calculate_FCSR_fp64 ( void* guest_state, UInt fs,
+ UInt ft, flt_op op );
/*---------------------------------------------------------*/
/*--- Condition code stuff ---*/
diff --git a/priv/guest_mips_helpers.c b/priv/guest_mips_helpers.c
index 9e47bc7..9258016 100644
--- a/priv/guest_mips_helpers.c
+++ b/priv/guest_mips_helpers.c
@@ -44,7 +44,7 @@
these functions are generated by the back end.
*/
-#define ALWAYSDEFD32(field) \
+#define ALWAYSDEFD32(field) \
{ offsetof(VexGuestMIPS32State, field), \
(sizeof ((VexGuestMIPS32State*)0)->field) }
@@ -1133,14 +1133,14 @@
);
#define ASM_VOLATILE_UNARY64(inst) \
- __asm__ volatile("cfc1 $t0, $31" "\n\t" \
- "ctc1 %2, $31" "\n\t" \
- "dmtc1 %1, $f24" "\n\t" \
- #inst" $f24, $f24" "\n\t" \
- "cfc1 %0, $31" "\n\t" \
- "ctc1 $t0, $31" "\n\t" \
+ __asm__ volatile("cfc1 $t0, $31" "\n\t" \
+ "ctc1 %2, $31" "\n\t" \
+ "ldc1 $f24, 0(%1)" "\n\t" \
+ #inst" $f24, $f24" "\n\t" \
+ "cfc1 %0, $31" "\n\t" \
+ "ctc1 $t0, $31" "\n\t" \
: "=r" (ret) \
- : "r" (fsVal), "r" (fcsr) \
+ : "r" (&(addr[fs])), "r" (fcsr) \
: "t0", "$f24" \
);
@@ -1173,144 +1173,257 @@
: "t0", "$f20", "$f21", "$f22", "$f23" \
);
-#define ASM_VOLATILE_BINARY64(inst) \
- __asm__ volatile("cfc1 $t0, $31" "\n\t" \
- "ctc1 %3, $31" "\n\t" \
- "dmtc1 %1, $f24" "\n\t" \
- "dmtc1 %2, $f25" "\n\t" \
- #inst" $f24, $f24, $f25" "\n\t" \
- "cfc1 %0, $31" "\n\t" \
- "ctc1 $t0, $31" "\n\t" \
- : "=r" (ret) \
- : "r" (fsVal), "r" (ftVal), "r" (fcsr) \
- : "t0", "$f24", "$f25" \
+#define ASM_VOLATILE_BINARY64(inst) \
+ __asm__ volatile("cfc1 $t0, $31" "\n\t" \
+ "ctc1 %3, $31" "\n\t" \
+ "ldc1 $f24, 0(%1)" "\n\t" \
+ "ldc1 $f26, 0(%2)" "\n\t" \
+ #inst" $f24, $f24, $f26" "\n\t" \
+ "cfc1 %0, $31" "\n\t" \
+ "ctc1 $t0, $31" "\n\t" \
+ : "=r" (ret) \
+ : "r" (&(addr[fs])), "r" (&(addr[ft])), "r" (fcsr) \
+ : "t0", "$f24", "$f26" \
);
/* TODO: Add cases for all fpu instructions because all fpu instructions are
change the value of FCSR register. */
-extern UInt mips_dirtyhelper_calculate_FCSR ( void* gs, UInt fs, UInt ft,
- flt_op inst )
+extern UInt mips_dirtyhelper_calculate_FCSR_fp32 ( void* gs, UInt fs, UInt ft,
+ flt_op inst )
+{
+ UInt ret = 0;
+#if defined(__mips__)
+ VexGuestMIPS32State* guest_state = (VexGuestMIPS32State*)gs;
+ UInt loFsVal, hiFsVal, loFtVal, hiFtVal;
+#if defined (_MIPSEL)
+ ULong *addr = (ULong *)&guest_state->guest_f0;
+ loFsVal = (UInt)addr[fs];
+ hiFsVal = (UInt)addr[fs+1];
+ loFtVal = (UInt)addr[ft];
+ hiFtVal = (UInt)addr[ft+1];
+#elif defined (_MIPSEB)
+ UInt *addr = (UInt *)&guest_state->guest_f0;
+ loFsVal = (UInt)addr[fs*2];
+ hiFsVal = (UInt)addr[fs*2+2];
+ loFtVal = (UInt)addr[ft*2];
+ hiFtVal = (UInt)addr[ft*2+2];
+#endif
+ UInt fcsr = guest_state->guest_FCSR;
+ switch (inst) {
+ case ROUNDWD:
+ ASM_VOLATILE_UNARY32_DOUBLE(round.w.d)
+ break;
+ case FLOORWS:
+ ASM_VOLATILE_UNARY32(floor.w.s)
+ break;
+ case FLOORWD:
+ ASM_VOLATILE_UNARY32_DOUBLE(floor.w.d)
+ break;
+ case TRUNCWS:
+ ASM_VOLATILE_UNARY32(trunc.w.s)
+ break;
+ case TRUNCWD:
+ ASM_VOLATILE_UNARY32_DOUBLE(trunc.w.d)
+ break;
+ case CEILWS:
+ ASM_VOLATILE_UNARY32(ceil.w.s)
+ break;
+ case CEILWD:
+ ASM_VOLATILE_UNARY32_DOUBLE(ceil.w.d)
+ break;
+ case CVTDS:
+ ASM_VOLATILE_UNARY32(cvt.d.s)
+ break;
+ case CVTDW:
+ ASM_VOLATILE_UNARY32(cvt.d.w)
+ break;
+ case CVTSW:
+ ASM_VOLATILE_UNARY32(cvt.s.w)
+ break;
+ case CVTSD:
+ ASM_VOLATILE_UNARY32_DOUBLE(cvt.s.d)
+ break;
+ case CVTWS:
+ ASM_VOLATILE_UNARY32(cvt.w.s)
+ break;
+ case CVTWD:
+ ASM_VOLATILE_UNARY32_DOUBLE(cvt.w.d)
+ break;
+ case ROUNDWS:
+ ASM_VOLATILE_UNARY32(round.w.s)
+ break;
+#if ((__mips == 32) && defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) \
+ || (__mips == 64)
+ case CEILLS:
+ ASM_VOLATILE_UNARY32(ceil.l.s)
+ break;
+ case CEILLD:
+ ASM_VOLATILE_UNARY32_DOUBLE(ceil.l.d)
+ break;
+ case CVTDL:
+ ASM_VOLATILE_UNARY32_DOUBLE(cvt.d.l)
+ break;
+ case CVTLS:
+ ASM_VOLATILE_UNARY32(cvt.l.s)
+ break;
+ case CVTLD:
+ ASM_VOLATILE_UNARY32_DOUBLE(cvt.l.d)
+ break;
+ case CVTSL:
+ ASM_VOLATILE_UNARY32_DOUBLE(cvt.s.l)
+ break;
+ case FLOORLS:
+ ASM_VOLATILE_UNARY32(floor.l.s)
+ break;
+ case FLOORLD:
+ ASM_VOLATILE_UNARY32_DOUBLE(floor.l.d)
+ break;
+ case ROUNDLS:
+ ASM_VOLATILE_UNARY32(round.l.s)
+ break;
+ case ROUNDLD:
+ ASM_VOLATILE_UNARY32_DOUBLE(round.l.d)
+ break;
+ case TRUNCLS:
+ ASM_VOLATILE_UNARY32(trunc.l.s)
+ break;
+ case TRUNCLD:
+ ASM_VOLATILE_UNARY32_DOUBLE(trunc.l.d)
+ break;
+#endif
+ case ADDS:
+ ASM_VOLATILE_BINARY32(add.s)
+ break;
+ case ADDD:
+ ASM_VOLATILE_BINARY32_DOUBLE(add.d)
+ break;
+ case SUBS:
+ ASM_VOLATILE_BINARY32(sub.s)
+ break;
+ case SUBD:
+ ASM_VOLATILE_BINARY32_DOUBLE(sub.d)
+ break;
+ case DIVS:
+ ASM_VOLATILE_BINARY32(div.s)
+ break;
+ default:
+ vassert(0);
+ break;
+ }
+#endif
+ return ret;
+}
+
+/* TODO: Add cases for all fpu instructions because all fpu instructions are
+ change the value of FCSR register. */
+extern UInt mips_dirtyhelper_calculate_FCSR_fp64 ( void* gs, UInt fs, UInt ft,
+ flt_op inst )
{
UInt ret = 0;
#if defined(__mips__)
#if defined(VGA_mips32)
VexGuestMIPS32State* guest_state = (VexGuestMIPS32State*)gs;
- UInt *addr = (UInt *)&guest_state->guest_f0;
- UInt loFsVal = addr[fs];
- UInt hiFsVal = addr[fs+1];
- UInt loFtVal = addr[ft];
- UInt hiFtVal = addr[ft+1];
-#define ASM_VOLATILE_UNARY(inst) ASM_VOLATILE_UNARY32(inst)
-#define ASM_VOLATILE_UNARY_DOUBLE(inst) ASM_VOLATILE_UNARY32_DOUBLE(inst)
-#define ASM_VOLATILE_BINARY(inst) ASM_VOLATILE_BINARY32(inst)
-#define ASM_VOLATILE_BINARY_DOUBLE(inst) ASM_VOLATILE_BINARY32_DOUBLE(inst)
#else
VexGuestMIPS64State* guest_state = (VexGuestMIPS64State*)gs;
- ULong *addr = (ULong *)&guest_state->guest_f0;
- ULong fsVal = addr[fs];
- ULong ftVal = addr[ft];
-#define ASM_VOLATILE_UNARY(inst) ASM_VOLATILE_UNARY64(inst)
-#define ASM_VOLATILE_UNARY_DOUBLE(inst) ASM_VOLATILE_UNARY64(inst)
-#define ASM_VOLATILE_BINARY(inst) ASM_VOLATILE_BINARY64(inst)
-#define ASM_VOLATILE_BINARY_DOUBLE(inst) ASM_VOLATILE_BINARY64(inst)
#endif
- UInt fcsr = guest_state->guest_FCSR;
+ ULong *addr = (ULong *)&guest_state->guest_f0;
+ UInt fcsr = guest_state->guest_FCSR;
switch (inst) {
case ROUNDWD:
- ASM_VOLATILE_UNARY_DOUBLE(round.w.d)
+ ASM_VOLATILE_UNARY64(round.w.d)
break;
case FLOORWS:
- ASM_VOLATILE_UNARY(floor.w.s)
+ ASM_VOLATILE_UNARY64(floor.w.s)
break;
case FLOORWD:
- ASM_VOLATILE_UNARY_DOUBLE(floor.w.d)
+ ASM_VOLATILE_UNARY64(floor.w.d)
break;
case TRUNCWS:
- ASM_VOLATILE_UNARY(trunc.w.s)
+ ASM_VOLATILE_UNARY64(trunc.w.s)
break;
case TRUNCWD:
- ASM_VOLATILE_UNARY_DOUBLE(trunc.w.d)
+ ASM_VOLATILE_UNARY64(trunc.w.d)
break;
case CEILWS:
- ASM_VOLATILE_UNARY(ceil.w.s)
+ ASM_VOLATILE_UNARY64(ceil.w.s)
break;
case CEILWD:
- ASM_VOLATILE_UNARY_DOUBLE(ceil.w.d)
+ ASM_VOLATILE_UNARY64(ceil.w.d)
break;
case CVTDS:
- ASM_VOLATILE_UNARY(cvt.d.s)
+ ASM_VOLATILE_UNARY64(cvt.d.s)
break;
case CVTDW:
- ASM_VOLATILE_UNARY(cvt.d.w)
+ ASM_VOLATILE_UNARY64(cvt.d.w)
break;
case CVTSW:
- ASM_VOLATILE_UNARY(cvt.s.w)
+ ASM_VOLATILE_UNARY64(cvt.s.w)
break;
case CVTSD:
- ASM_VOLATILE_UNARY_DOUBLE(cvt.s.d)
+ ASM_VOLATILE_UNARY64(cvt.s.d)
break;
case CVTWS:
- ASM_VOLATILE_UNARY(cvt.w.s)
+ ASM_VOLATILE_UNARY64(cvt.w.s)
break;
case CVTWD:
- ASM_VOLATILE_UNARY_DOUBLE(cvt.w.d)
+ ASM_VOLATILE_UNARY64(cvt.w.d)
break;
case ROUNDWS:
- ASM_VOLATILE_UNARY(round.w.s)
+ ASM_VOLATILE_UNARY64(round.w.s)
break;
#if ((__mips == 32) && defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) \
|| (__mips == 64)
case CEILLS:
- ASM_VOLATILE_UNARY(ceil.l.s)
+ ASM_VOLATILE_UNARY64(ceil.l.s)
break;
case CEILLD:
- ASM_VOLATILE_UNARY_DOUBLE(ceil.l.d)
+ ASM_VOLATILE_UNARY64(ceil.l.d)
break;
case CVTDL:
- ASM_VOLATILE_UNARY_DOUBLE(cvt.d.l)
+ ASM_VOLATILE_UNARY64(cvt.d.l)
break;
case CVTLS:
- ASM_VOLATILE_UNARY(cvt.l.s)
+ ASM_VOLATILE_UNARY64(cvt.l.s)
break;
case CVTLD:
- ASM_VOLATILE_UNARY_DOUBLE(cvt.l.d)
+ ASM_VOLATILE_UNARY64(cvt.l.d)
break;
case CVTSL:
- ASM_VOLATILE_UNARY_DOUBLE(cvt.s.l)
+ ASM_VOLATILE_UNARY64(cvt.s.l)
break;
case FLOORLS:
- ASM_VOLATILE_UNARY(floor.l.s)
+ ASM_VOLATILE_UNARY64(floor.l.s)
break;
case FLOORLD:
- ASM_VOLATILE_UNARY_DOUBLE(floor.l.d)
+ ASM_VOLATILE_UNARY64(floor.l.d)
break;
case ROUNDLS:
- ASM_VOLATILE_UNARY(round.l.s)
+ ASM_VOLATILE_UNARY64(round.l.s)
break;
case ROUNDLD:
- ASM_VOLATILE_UNARY_DOUBLE(round.l.d)
+ ASM_VOLATILE_UNARY64(round.l.d)
break;
case TRUNCLS:
- ASM_VOLATILE_UNARY(trunc.l.s)
+ ASM_VOLATILE_UNARY64(trunc.l.s)
break;
case TRUNCLD:
- ASM_VOLATILE_UNARY_DOUBLE(trunc.l.d)
+ ASM_VOLATILE_UNARY64(trunc.l.d)
break;
#endif
case ADDS:
- ASM_VOLATILE_BINARY(add.s)
+ ASM_VOLATILE_BINARY64(add.s)
break;
case ADDD:
- ASM_VOLATILE_BINARY_DOUBLE(add.d)
+ ASM_VOLATILE_BINARY64(add.d)
break;
case SUBS:
- ASM_VOLATILE_BINARY(sub.s)
+ ASM_VOLATILE_BINARY64(sub.s)
break;
case SUBD:
- ASM_VOLATILE_BINARY_DOUBLE(sub.d)
+ ASM_VOLATILE_BINARY64(sub.d)
break;
case DIVS:
- ASM_VOLATILE_BINARY(div.s)
+ ASM_VOLATILE_BINARY64(div.s)
break;
default:
vassert(0);
diff --git a/priv/guest_mips_toIR.c b/priv/guest_mips_toIR.c
index 9ee65bf..94ec293 100644
--- a/priv/guest_mips_toIR.c
+++ b/priv/guest_mips_toIR.c
@@ -72,6 +72,9 @@
disInstr_MIPS below. */
static Bool mode64 = False;
+/* CPU has FPU and 32 dbl. prec. FP registers. */
+static Bool fp_mode64 = False;
+
/* Define 1.0 in single and double precision. */
#define ONE_SINGLE 0x3F800000
#define ONE_DOUBLE 0x3FF0000000000000ULL
@@ -541,6 +544,11 @@
binop(Iop_Shr32, getFCSR(), mkU8(24+cc))), \
mkU32(0x1)));
+#define ILLEGAL_INSTRUCTON \
+ putPC(mkU32(guest_PC_curr_instr + 4)); \
+ dres.jk_StopHere = Ijk_SigILL; \
+ dres.whatNext = Dis_StopHere;
+
/*------------------------------------------------------------*/
/*--- Field helpers ---*/
/*------------------------------------------------------------*/
@@ -1105,22 +1113,30 @@
{
IRDirty *d;
IRTemp fcsr = newTemp(Ity_I32);
- /* IRExpr_BBPTR() => Need to pass pointer to guest
- state to helper. */
- d = unsafeIRDirty_1_N(fcsr, 0,
- "mips_dirtyhelper_calculate_FCSR",
- &mips_dirtyhelper_calculate_FCSR,
- mkIRExprVec_4(IRExpr_BBPTR(),
- mkU32(fs),
- mkU32(ft),
- mkU32(inst)));
+ /* IRExpr_BBPTR() => Need to pass pointer to guest state to helper. */
+ if (fp_mode64)
+ d = unsafeIRDirty_1_N(fcsr, 0,
+ "mips_dirtyhelper_calculate_FCSR_fp64",
+ &mips_dirtyhelper_calculate_FCSR_fp64,
+ mkIRExprVec_4(IRExpr_BBPTR(),
+ mkU32(fs),
+ mkU32(ft),
+ mkU32(inst)));
+ else
+ d = unsafeIRDirty_1_N(fcsr, 0,
+ "mips_dirtyhelper_calculate_FCSR_fp32",
+ &mips_dirtyhelper_calculate_FCSR_fp32,
+ mkIRExprVec_4(IRExpr_BBPTR(),
+ mkU32(fs),
+ mkU32(ft),
+ mkU32(inst)));
if (opN == 1) { /* Unary operation. */
/* Declare we're reading guest state. */
- if (!mode64 && !sz32)
- d->nFxState = 3;
- else
+ if (sz32 || fp_mode64)
d->nFxState = 2;
+ else
+ d->nFxState = 3;
vex_bzero(&d->fxState, sizeof(d->fxState));
d->fxState[0].fx = Ifx_Read; /* read */
@@ -1128,22 +1144,19 @@
d->fxState[0].size = sizeof(UInt);
d->fxState[1].fx = Ifx_Read; /* read */
d->fxState[1].offset = floatGuestRegOffset(fs);
- if (mode64)
- d->fxState[1].size = sizeof(ULong);
- else
- d->fxState[1].size = sizeof(UInt);
+ d->fxState[1].size = sizeof(ULong);
- if (!mode64 && !sz32) {
+ if (!(sz32 || fp_mode64)) {
d->fxState[2].fx = Ifx_Read; /* read */
d->fxState[2].offset = floatGuestRegOffset(fs+1);
- d->fxState[2].size = sizeof(UInt);
+ d->fxState[2].size = sizeof(ULong);
}
} else if (opN == 2) { /* Binary operation. */
/* Declare we're reading guest state. */
- if (!mode64 && !sz32)
- d->nFxState = 5;
- else
+ if (sz32 || fp_mode64)
d->nFxState = 3;
+ else
+ d->nFxState = 5;
vex_bzero(&d->fxState, sizeof(d->fxState));
d->fxState[0].fx = Ifx_Read; /* read */
@@ -1151,22 +1164,18 @@
d->fxState[0].size = sizeof(UInt);
d->fxState[1].fx = Ifx_Read; /* read */
d->fxState[1].offset = floatGuestRegOffset(fs);
+ d->fxState[1].size = sizeof(ULong);
d->fxState[2].fx = Ifx_Read; /* read */
d->fxState[2].offset = floatGuestRegOffset(ft);
- if (mode64) {
- d->fxState[1].size = sizeof(ULong);
- d->fxState[2].size = sizeof(ULong);
- } else {
- d->fxState[1].size = sizeof(UInt);
- d->fxState[2].size = sizeof(UInt);
- }
- if (!mode64 && !sz32) {
+ d->fxState[2].size = sizeof(ULong);
+
+ if (!(sz32 || fp_mode64)) {
d->fxState[3].fx = Ifx_Read; /* read */
d->fxState[3].offset = floatGuestRegOffset(fs+1);
- d->fxState[3].size = sizeof(UInt);
+ d->fxState[3].size = sizeof(ULong);
d->fxState[4].fx = Ifx_Read; /* read */
d->fxState[4].offset = floatGuestRegOffset(ft+1);
- d->fxState[4].size = sizeof(UInt);
+ d->fxState[4].size = sizeof(ULong);
}
}
@@ -1192,6 +1201,12 @@
stmt(IRStmt_Put(integerGuestRegOffset(archreg), e));
}
+static IRExpr *mkNarrowTo32(IRType ty, IRExpr * src)
+{
+ vassert(ty == Ity_I32 || ty == Ity_I64);
+ return ty == Ity_I64 ? unop(Iop_64to32, src) : src;
+}
+
static void putLO(IRExpr * e)
{
if (mode64) {
@@ -1285,12 +1300,6 @@
return 0;
}
-static IRExpr *mkNarrowTo32(IRType ty, IRExpr * src)
-{
- vassert(ty == Ity_I32 || ty == Ity_I64);
- return ty == Ity_I64 ? unop(Iop_64to32, src) : src;
-}
-
static IRExpr *getLoFromF64(IRType ty, IRExpr * src)
{
vassert(ty == Ity_F32 || ty == Ity_F64);
@@ -1386,21 +1395,21 @@
(UInt) branch_offset), OFFB_PC);
}
-static IRExpr *getFReg(UInt dregNo)
+static IRExpr *getFReg(UInt fregNo)
{
- vassert(dregNo < 32);
- IRType ty = mode64 ? Ity_F64 : Ity_F32;
- return IRExpr_Get(floatGuestRegOffset(dregNo), ty);
+ vassert(fregNo < 32);
+ IRType ty = fp_mode64 ? Ity_F64 : Ity_F32;
+ return IRExpr_Get(floatGuestRegOffset(fregNo), ty);
}
static IRExpr *getDReg(UInt dregNo)
{
- if (mode64) {
- vassert(dregNo < 32);
- IRType ty = Ity_F64;
- return IRExpr_Get(floatGuestRegOffset(dregNo), ty);
+ vassert(dregNo < 32);
+ if (fp_mode64) {
+ return IRExpr_Get(floatGuestRegOffset(dregNo), Ity_F64);
} else {
- vassert(dregNo < 32);
+ /* Read a floating point register pair and combine their contents into a
+ 64-bit value */
IRTemp t0 = newTemp(Ity_F32);
IRTemp t1 = newTemp(Ity_F32);
IRTemp t2 = newTemp(Ity_F64);
@@ -1423,14 +1432,14 @@
static void putFReg(UInt dregNo, IRExpr * e)
{
vassert(dregNo < 32);
- IRType ty = mode64 ? Ity_F64 : Ity_F32;
+ IRType ty = fp_mode64 ? Ity_F64 : Ity_F32;
vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e));
}
static void putDReg(UInt dregNo, IRExpr * e)
{
- if (mode64) {
+ if (fp_mode64) {
vassert(dregNo < 32);
IRType ty = Ity_F64;
vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
@@ -1725,7 +1734,7 @@
switch (fmt) {
case 0x10: { /* C.cond.S */
DIP("C.%s.S %d, f%d, f%d", showCondCode(cond), fpc_cc, fs, ft);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
@@ -1740,7 +1749,8 @@
getFReg(ft))));
assign(ccIR, binop(Iop_CmpF64, mkexpr(tmp5), mkexpr(tmp6)));
- putHI(mkWidenFrom32(Ity_I64, mkexpr(ccIR), True));
+ putHI(mkWidenFrom32(mode64 ? Ity_I64: Ity_I32,
+ mkexpr(ccIR), True));
/* Map compare result from IR to MIPS
FP cmp result | MIPS | IR
--------------------------
@@ -1757,7 +1767,8 @@
binop(Iop_And32, binop(Iop_Xor32, mkexpr(ccIR),
binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
mkU32(1))))));
- putLO(mkWidenFrom32(Ity_I64, mkexpr(ccMIPS), True));
+ putLO(mkWidenFrom32(mode64 ? Ity_I64: Ity_I32,
+ mkexpr(ccMIPS), True));
/* UN */
assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1)));
@@ -11829,7 +11840,7 @@
trap_code = get_code(cins);
function = get_function(cins);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
- IRType tyF = mode64 ? Ity_F64 : Ity_F32;
+ IRType tyF = fp_mode64 ? Ity_F64 : Ity_F32;
ac = get_acNo(cins);
@@ -11862,110 +11873,119 @@
lastn = mkexpr(t0);
break;
- case 0x11: /* COP1 */
- {
- UInt bc1_cc = get_bc1_cc(cins);
- if (0x08 == fmt) {
- switch (fmt) {
- case 0x08: /* BC */
- {
- DIP("tf: %d, nd: %d", tf, nd);
- /* FcConditionalCode(bc1_cc) */
- t1 = newTemp(Ity_I1);
- t2 = newTemp(Ity_I32);
- t3 = newTemp(Ity_I1);
-
- assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(bc1_cc)));
- assign(t2, IRExpr_ITE(mkexpr(t1),
- binop(Iop_And32,
- binop(Iop_Shr32, getFCSR(),
- mkU8(23)),
- mkU32(0x1)),
- binop(Iop_And32,
- binop(Iop_Shr32, getFCSR(),
- mkU8(24 + bc1_cc)),
- mkU32(0x1))
- ));
-
- if (tf == 1 && nd == 0) {
- /* branch on true */
- DIP("bc1t %d, %d", bc1_cc, imm);
- assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
- dis_branch(False, mkexpr(t3), imm, &bstmt);
- break;
- } else if (tf == 0 && nd == 0) {
- /* branch on false */
- DIP("bc1f %d, %d", bc1_cc, imm);
- assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
- dis_branch(False, mkexpr(t3), imm, &bstmt);
- break;
- } else if (nd == 1 && tf == 0) {
- DIP("bc1fl %d, %d", bc1_cc, imm);
- lastn = dis_branch_likely(binop(Iop_CmpNE32, mkexpr(t2),
- mkU32(0x0)), imm);
- break;
- } else if (nd == 1 && tf == 1) {
- DIP("bc1tl %d, %d", bc1_cc, imm);
- lastn = dis_branch_likely(binop(Iop_CmpEQ32, mkexpr(t2),
- mkU32(0x0)), imm);
- break;
- } else
- goto decode_failure;
- }
-
- default:
- goto decode_failure;
- }
+ case 0x11: { /* COP1 */
+ if (fmt == 0x3 && fd == 0 && function == 0) { /* MFHC1 */
+ DIP("mfhc1 r%d, f%d", rt, fs);
+ if (fp_mode64) {
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I32);
+ assign(t0, unop(Iop_ReinterpF64asI64, getDReg(fs)));
+ assign(t1, unop(Iop_64HIto32, mkexpr(t0)));
+ putIReg(rt, mkWidenFrom32(ty, mkexpr(t1), True));
} else {
- switch (function) {
+ ILLEGAL_INSTRUCTON;
+ }
+ break;
+ } else if (fmt == 0x7 && fd == 0 && function == 0) { /* MTHC1 */
+ DIP("mthc1 r%d, f%d", rt, fs);
+ if (fp_mode64) {
+ t0 = newTemp(Ity_I64);
+ assign(t0, binop(Iop_32HLto64, getIReg(rt),
+ unop(Iop_ReinterpF32asI32,
+ getLoFromF64(Ity_F64 /* 32FPR mode. */,
+ getDReg(fs)))));
+ putDReg(fs, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
+ break;
+ } else if (fmt == 0x8) { /* BC */
+ /* FcConditionalCode(bc1_cc) */
+ UInt bc1_cc = get_bc1_cc(cins);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
- case 0x4: /* SQRT.fmt */
- {
- switch (fmt) {
- case 0x10: /* S */
- {
- IRExpr *rm = get_IR_roundingmode();
- putFReg(fd, mkWidenFromF32(tyF, binop(Iop_SqrtF32, rm,
- getLoFromF64(tyF, getFReg(fs)))));
- }
+ assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(bc1_cc)));
+ assign(t2, IRExpr_ITE(mkexpr(t1),
+ binop(Iop_And32,
+ binop(Iop_Shr32, getFCSR(), mkU8(23)),
+ mkU32(0x1)),
+ binop(Iop_And32,
+ binop(Iop_Shr32, getFCSR(),
+ mkU8(24 + bc1_cc)),
+ mkU32(0x1))));
+
+ if (tf == 1 && nd == 0) {
+ /* branch on true */
+ DIP("bc1t %d, %d", bc1_cc, imm);
+ assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
+ dis_branch(False, mkexpr(t3), imm, &bstmt);
+ break;
+ } else if (tf == 0 && nd == 0) {
+ /* branch on false */
+ DIP("bc1f %d, %d", bc1_cc, imm);
+ assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
+ dis_branch(False, mkexpr(t3), imm, &bstmt);
+ break;
+ } else if (nd == 1 && tf == 0) {
+ DIP("bc1fl %d, %d", bc1_cc, imm);
+ lastn = dis_branch_likely(binop(Iop_CmpNE32, mkexpr(t2),
+ mkU32(0x0)), imm);
+ break;
+ } else if (nd == 1 && tf == 1) {
+ DIP("bc1tl %d, %d", bc1_cc, imm);
+ lastn = dis_branch_likely(binop(Iop_CmpEQ32, mkexpr(t2),
+ mkU32(0x0)), imm);
+ break;
+ } else
+ goto decode_failure;
+ } else {
+ switch (function) {
+ case 0x4: { /* SQRT.fmt */
+ switch (fmt) {
+ case 0x10: { /* S */
+ IRExpr *rm = get_IR_roundingmode();
+ putFReg(fd, mkWidenFromF32(tyF, binop(Iop_SqrtF32, rm,
+ getLoFromF64(tyF, getFReg(fs)))));
break;
- case 0x11: /* D */
- {
- IRExpr *rm = get_IR_roundingmode();
- putDReg(fd, binop(Iop_SqrtF64, rm, getDReg(fs)));
- }
+ }
+ case 0x11: { /* D */
+ IRExpr *rm = get_IR_roundingmode();
+ putDReg(fd, binop(Iop_SqrtF64, rm, getDReg(fs)));
break;
}
+ default:
+ goto decode_failure;
+ }
}
break;
case 0x5: /* abs.fmt */
switch (fmt) {
- case 0x10: /* S */
- DIP("abs.s f%d, f%d", fd, fs);
- putFReg(fd, mkWidenFromF32(tyF, unop(Iop_AbsF32,
- getLoFromF64(tyF, getFReg(fs)))));
- break;
- case 0x11: /* D */
- DIP("abs.d f%d, f%d", fd, fs);
- putDReg(fd, unop(Iop_AbsF64, getDReg(fs)));
- break;
- default:
- goto decode_failure;
+ case 0x10: /* S */
+ DIP("abs.s f%d, f%d", fd, fs);
+ putFReg(fd, mkWidenFromF32(tyF, unop(Iop_AbsF32,
+ getLoFromF64(tyF, getFReg(fs)))));
+ break;
+ case 0x11: /* D */
+ DIP("abs.d f%d, f%d", fd, fs);
+ putDReg(fd, unop(Iop_AbsF64, getDReg(fs)));
+ break;
+ default:
+ goto decode_failure;
}
break; /* case 0x5 */
case 0x02: /* MUL.fmt */
switch (fmt) {
- case 0x11: /* D */
- {
+ case 0x11: { /* D */
DIP("mul.d f%d, f%d, f%d", fd, fs, ft);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, triop(Iop_MulF64, rm, getDReg(fs),
getDReg(ft)));
break;
}
- case 0x10: /* S */
- {
+ case 0x10: { /* S */
DIP("mul.s f%d, f%d, f%d", fd, fs, ft);
IRExpr *rm = get_IR_roundingmode();
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_MulF32, rm,
@@ -11973,23 +11993,21 @@
getLoFromF64(tyF, getFReg(ft)))));
break;
}
- default:
- goto decode_failure;
+ default:
+ goto decode_failure;
}
break; /* MUL.fmt */
case 0x03: /* DIV.fmt */
switch (fmt) {
- case 0x11: /* D */
- {
+ case 0x11: { /* D */
DIP("div.d f%d, f%d, f%d", fd, fs, ft);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, triop(Iop_DivF64, rm, getDReg(fs),
getDReg(ft)));
break;
}
- case 0x10: /* S */
- {
+ case 0x10: { /* S */
DIP("div.s f%d, f%d, f%d", fd, fs, ft);
calculateFCSR(fs, ft, DIVS, False, 2);
IRExpr *rm = get_IR_roundingmode();
@@ -11998,8 +12016,8 @@
getLoFromF64(tyF, getFReg(ft)))));
break;
}
- default:
- goto decode_failure;
+ default:
+ goto decode_failure;
}
break; /* DIV.fmt */
@@ -12031,8 +12049,8 @@
switch (fmt) {
case 0x11: /* D */
DIP("mov.d f%d, f%d", fd, fs);
- if (mode64) {
- putFReg(fd, getFReg(fs));
+ if (fp_mode64) {
+ putDReg(fd, getDReg(fs));
} else {
putFReg(fd, getFReg(fs));
putFReg(fd + 1, getFReg(fs + 1));
@@ -12067,19 +12085,27 @@
switch (fmt) {
case 0x10: /* S */
DIP("round.l.s f%d, f%d", fd, fs);
- calculateFCSR(fs, 0, ROUNDLS, True, 1);
- t0 = newTemp(Ity_I64);
+ if (fp_mode64) {
+ calculateFCSR(fs, 0, ROUNDLS, True, 1);
+ t0 = newTemp(Ity_I64);
- assign(t0, binop(Iop_F32toI64S, mkU32(0x0),
- getLoFromF64(Ity_F64, getFReg(fs))));
+ assign(t0, binop(Iop_F32toI64S, mkU32(0x0),
+ getLoFromF64(Ity_F64, getFReg(fs))));
- putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
- break;
+ putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
+ break;
case 0x11: /* D */
DIP("round.l.d f%d, f%d", fd, fs);
- calculateFCSR(fs, 0, ROUNDLD, False, 1);
- putFReg(fd, binop(Iop_RoundF64toInt, mkU32(0x0),
- getFReg(fs)));
+ if (fp_mode64) {
+ calculateFCSR(fs, 0, ROUNDLD, False, 1);
+ putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x0),
+ getDReg(fs)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
break;
default:
goto decode_failure;
@@ -12091,18 +12117,26 @@
switch (fmt) {
case 0x10: /* S */
DIP("trunc.l.s f%d, f%d", fd, fs);
- calculateFCSR(fs, 0, TRUNCLS, True, 1);
- t0 = newTemp(Ity_I64);
- assign(t0, binop(Iop_F32toI64S, mkU32(0x3),
- getLoFromF64(Ity_F64, getFReg(fs))));
+ if (fp_mode64) {
+ calculateFCSR(fs, 0, TRUNCLS, True, 1);
+ t0 = newTemp(Ity_I64);
+ assign(t0, binop(Iop_F32toI64S, mkU32(0x3),
+ getLoFromF64(Ity_F64, getFReg(fs))));
- putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
+ putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
break;
case 0x11: /* D */
DIP("trunc.l.d f%d, f%d", fd, fs);
- calculateFCSR(fs, 0, TRUNCLD, False, 1);
- putFReg(fd, binop(Iop_RoundF64toInt, mkU32(0x3),
- getFReg(fs)));
+ if (fp_mode64) {
+ calculateFCSR(fs, 0, TRUNCLD, False, 1);
+ putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x3),
+ getDReg(fs)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
break;
default:
goto decode_failure;
@@ -12139,7 +12173,6 @@
switch (fmt) {
case 0x10: /* S */
DIP("movn.s f%d, f%d, r%d", fd, fs, rt);
-
t1 = newTemp(Ity_F64);
t2 = newTemp(Ity_F64);
t3 = newTemp(Ity_I1);
@@ -12149,13 +12182,19 @@
assign(t2, getFReg(fd));
assign(t3, binop(Iop_CmpNE64, mkU64(0), getIReg(rt)));
} else {
- assign(t1, unop(Iop_F32toF64, getFReg(fs)));
- assign(t2, unop(Iop_F32toF64, getFReg(fd)));
- assign(t3, binop(Iop_CmpNE32, mkU32(0), getIReg(rt)));
+ if (fp_mode64) {
+ assign(t1, getFReg(fs));
+ assign(t2, getFReg(fd));
+ assign(t3, binop(Iop_CmpNE32, mkU32(0), getIReg(rt)));
+ } else {
+ assign(t1, unop(Iop_F32toF64, getFReg(fs)));
+ assign(t2, unop(Iop_F32toF64, getFReg(fd)));
+ assign(t3, binop(Iop_CmpNE32, mkU32(0), getIReg(rt)));
+ }
}
assign(t4, IRExpr_ITE(mkexpr(t3), mkexpr(t1), mkexpr(t2)));
- if (mode64) {
+ if (fp_mode64) {
IRTemp f = newTemp(Ity_F64);
IRTemp fd_hi = newTemp(Ity_I32);
t5 = newTemp(Ity_I64);
@@ -12163,7 +12202,7 @@
assign(fd_hi, unop(Iop_64HIto32, unop(Iop_ReinterpF64asI64,
mkexpr(f))));
- assign(t5, mkWidenFrom32(ty, unop(Iop_64to32,
+ assign(t5, mkWidenFrom32(Ity_I64, unop(Iop_64to32,
unop(Iop_ReinterpF64asI64, mkexpr(t4))), True));
putFReg(fd, unop (Iop_ReinterpI64asF64, mkexpr(t5)));
@@ -12198,10 +12237,13 @@
t2 = newTemp(Ity_F64);
t3 = newTemp(Ity_I1);
t4 = newTemp(Ity_F64);
- if (mode64) {
+ if (fp_mode64) {
assign(t1, getFReg(fs));
assign(t2, getFReg(fd));
- assign(t3, binop(Iop_CmpEQ64, mkU64(0), getIReg(rt)));
+ if (mode64)
+ assign(t3, binop(Iop_CmpEQ64, mkU64(0), getIReg(rt)));
+ else
+ assign(t3, binop(Iop_CmpEQ32, mkU32(0), getIReg(rt)));
} else {
assign(t1, unop(Iop_F32toF64, getFReg(fs)));
assign(t2, unop(Iop_F32toF64, getFReg(fd)));
@@ -12209,14 +12251,14 @@
}
assign(t4, IRExpr_ITE(mkexpr(t3), mkexpr(t1), mkexpr(t2)));
- if (mode64) {
+ if (fp_mode64) {
IRTemp f = newTemp(Ity_F64);
IRTemp fd_hi = newTemp(Ity_I32);
t7 = newTemp(Ity_I64);
assign(f, getFReg(fd));
assign(fd_hi, unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64, mkexpr(f))));
- assign(t7, mkWidenFrom32(ty, unop(Iop_64to32,
+ assign(t7, mkWidenFrom32(Ity_I64, unop(Iop_64to32,
unop(Iop_ReinterpF64asI64, mkexpr(t4))), True));
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t7)));
@@ -12279,7 +12321,7 @@
t6 = newTemp(Ity_F64);
t7 = newTemp(Ity_I64);
- if (mode64) {
+ if (fp_mode64) {
assign(t5, getFReg(fs));
assign(t6, getFReg(fd));
} else {
@@ -12303,13 +12345,13 @@
assign(t4, IRExpr_ITE(mkexpr(t3),
mkexpr(t5), mkexpr(t6)));
- if (mode64) {
+ if (fp_mode64) {
IRTemp f = newTemp(Ity_F64);
IRTemp fd_hi = newTemp(Ity_I32);
assign(f, getFReg(fd));
assign(fd_hi, unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64, mkexpr(f))));
- assign(t7, mkWidenFrom32(ty, unop(Iop_64to32,
+ assign(t7, mkWidenFrom32(Ity_I64, unop(Iop_64to32,
unop(Iop_ReinterpF64asI64, mkexpr(t4))),
True));
@@ -12359,7 +12401,7 @@
t5 = newTemp(Ity_F64);
t6 = newTemp(Ity_F64);
- if (mode64) {
+ if (fp_mode64) {
assign(t5, getFReg(fs));
assign(t6, getFReg(fd));
} else {
@@ -12383,14 +12425,14 @@
assign(t4, IRExpr_ITE(mkexpr(t3),
mkexpr(t5), mkexpr(t6)));
- if (mode64) {
+ if (fp_mode64) {
IRTemp f = newTemp(Ity_F64);
IRTemp fd_hi = newTemp(Ity_I32);
t7 = newTemp(Ity_I64);
assign(f, getFReg(fd));
assign(fd_hi, unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64, mkexpr(f))));
- assign(t7, mkWidenFrom32(ty, unop(Iop_64to32,
+ assign(t7, mkWidenFrom32(Ity_I64, unop(Iop_64to32,
unop(Iop_ReinterpF64asI64, mkexpr(t4))),
True));
@@ -12427,10 +12469,10 @@
case 0x4: /* MTC1 (Move Word to Floating Point) */
DIP("mtc1 r%d, f%d", rt, fs);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_F32);
- assign(t0, unop(Iop_64to32, getIReg(rt)));
+ assign(t0, mkNarrowTo32(ty, getIReg(rt)));
assign(t1, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
putFReg(fs, mkWidenFromF32(tyF, mkexpr(t1)));
@@ -12446,7 +12488,7 @@
case 0x0: /* MFC1 */
DIP("mfc1 r%d, f%d", rt, fs);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
@@ -12570,7 +12612,7 @@
case 0x10: /* S */
DIP("cvt.d.s f%d, f%d", fd, fs);
calculateFCSR(fs, 0, CVTDS, True, 1);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
@@ -12590,7 +12632,7 @@
case 0x14:
DIP("cvt.d.w %d, %d", fd, fs);
calculateFCSR(fs, 0, CVTDW, True, 1);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
@@ -12609,7 +12651,7 @@
}
case 0x15: { /* L */
- if (mode64) {
+ if (fp_mode64) {
DIP("cvt.d.l %d, %d", fd, fs);
calculateFCSR(fs, 0, CVTDL, False, 1);
t0 = newTemp(Ity_I64);
@@ -12631,7 +12673,7 @@
case 0x14: /* W */
DIP("cvt.s.w %d, %d", fd, fs);
calculateFCSR(fs, 0, CVTSW, True, 1);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
@@ -12653,14 +12695,10 @@
case 0x11: /* D */
DIP("cvt.s.d %d, %d", fd, fs);
calculateFCSR(fs, 0, CVTSD, False, 1);
- if (mode64) {
- t0 = newTemp(Ity_F32);
- assign(t0, binop(Iop_F64toF32, get_IR_roundingmode(),
- getFReg(fs)));
- putFReg(fd, mkWidenFromF32(tyF, mkexpr(t0)));
- } else
- putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
- getDReg(fs)));
+ t0 = newTemp(Ity_F32);
+ assign(t0, binop(Iop_F64toF32, get_IR_roundingmode(),
+ getDReg(fs)));
+ putFReg(fd, mkWidenFromF32(tyF, mkexpr(t0)));
break;
case 0x15: /* L */
@@ -12683,33 +12721,23 @@
case 0x10: /* S */
DIP("cvt.w.s %d, %d", fd, fs);
calculateFCSR(fs, 0, CVTWS, True, 1);
- if (mode64) {
- putFReg(fd, mkWidenFromF32(tyF, binop(Iop_RoundF32toInt,
- get_IR_roundingmode(), getLoFromF64(tyF,
- getFReg(fs)))));
- } else
- putFReg(fd, binop(Iop_RoundF32toInt, get_IR_roundingmode(),
- getFReg(fs)));
+ putFReg(fd,
+ mkWidenFromF32(tyF,
+ binop(Iop_RoundF32toInt,
+ get_IR_roundingmode(),
+ getLoFromF64(tyF, getFReg(fs))))
+ );
break;
case 0x11:
DIP("cvt.w.d %d, %d", fd, fs);
calculateFCSR(fs, 0, CVTWD, False, 1);
- if (mode64) {
- t0 = newTemp(Ity_I32);
- t1 = newTemp(Ity_F32);
- assign(t0, binop(Iop_F64toI32S, get_IR_roundingmode(),
- getFReg(fs)));
- assign(t1, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
- putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
- } else {
- t0 = newTemp(Ity_I32);
-
- assign(t0, binop(Iop_F64toI32S, get_IR_roundingmode(),
- getDReg(fs)));
-
- putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
- }
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_F32);
+ assign(t0, binop(Iop_F64toI32S, get_IR_roundingmode(),
+ getDReg(fs)));
+ assign(t1, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
+ putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
break;
default:
@@ -12722,20 +12750,28 @@
switch (fmt) {
case 0x10: /* S */
DIP("cvt.l.s %d, %d", fd, fs);
- calculateFCSR(fs, 0, CVTLS, True, 1);
- t0 = newTemp(Ity_I64);
+ if (fp_mode64) {
+ calculateFCSR(fs, 0, CVTLS, True, 1);
+ t0 = newTemp(Ity_I64);
- assign(t0, binop(Iop_F32toI64S, get_IR_roundingmode(),
- getLoFromF64(Ity_F64, getFReg(fs))));
+ assign(t0, binop(Iop_F32toI64S, get_IR_roundingmode(),
+ getLoFromF64(tyF, getFReg(fs))));
- putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
+ putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
break;
case 0x11: { /* D */
DIP("cvt.l.d %d, %d", fd, fs);
- calculateFCSR(fs, 0, CVTLD, False, 1);
- putFReg(fd, binop(Iop_RoundF64toInt,
- get_IR_roundingmode(), getFReg(fs)));
+ if (fp_mode64) {
+ calculateFCSR(fs, 0, CVTLD, False, 1);
+ putDReg(fd, binop(Iop_RoundF64toInt,
+ get_IR_roundingmode(), getDReg(fs)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
break;
}
@@ -12748,20 +12784,28 @@
switch (fmt) {
case 0x10: /* S */
DIP("floor.l.s %d, %d", fd, fs);
- calculateFCSR(fs, 0, FLOORLS, True, 1);
- t0 = newTemp(Ity_I64);
+ if (fp_mode64) {
+ calculateFCSR(fs, 0, FLOORLS, True, 1);
+ t0 = newTemp(Ity_I64);
- assign(t0, binop(Iop_F32toI64S, mkU32(0x1),
- getLoFromF64(Ity_F64, getFReg(fs))));
+ assign(t0, binop(Iop_F32toI64S, mkU32(0x1),
+ getLoFromF64(tyF, getFReg(fs))));
- putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
+ putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
break;
case 0x11: /* D */
DIP("floor.l.d %d, %d", fd, fs);
- calculateFCSR(fs, 0, FLOORLD, False, 1);
- putFReg(fd, binop(Iop_RoundF64toInt, mkU32(0x1),
- getFReg(fs)));
+ if (fp_mode64) {
+ calculateFCSR(fs, 0, FLOORLD, False, 1);
+ putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x1),
+ getDReg(fs)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
break;
default:
goto decode_failure;
@@ -12773,7 +12817,7 @@
case 0x10: /* S */
DIP("round.w.s f%d, f%d", fd, fs);
calculateFCSR(fs, 0, ROUNDWS, True, 1);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
@@ -12797,7 +12841,7 @@
case 0x11: /* D */
DIP("round.w.d f%d, f%d", fd, fs);
calculateFCSR(fs, 0, ROUNDWD, False, 1);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x0),
getDReg(fs)));
@@ -12823,7 +12867,7 @@
case 0x10: /* S */
DIP("floor.w.s f%d, f%d", fd, fs);
calculateFCSR(fs, 0, FLOORWS, True, 1);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
@@ -12847,7 +12891,7 @@
case 0x11: /* D */
DIP("floor.w.d f%d, f%d", fd, fs);
calculateFCSR(fs, 0, FLOORWD, False, 1);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x1),
getDReg(fs)));
@@ -12874,7 +12918,7 @@
case 0x10: /* S */
DIP("trunc.w.s %d, %d", fd, fs);
calculateFCSR(fs, 0, TRUNCWS, True, 1);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
@@ -12897,7 +12941,7 @@
case 0x11: /* D */
DIP("trunc.w.d %d, %d", fd, fs);
calculateFCSR(fs, 0, TRUNCWD, False, 1);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x3),
@@ -12925,7 +12969,7 @@
case 0x10: /* S */
DIP("ceil.w.s %d, %d", fd, fs);
calculateFCSR(fs, 0, CEILWS, True, 1);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
@@ -12949,7 +12993,7 @@
case 0x11: /* D */
DIP("ceil.w.d %d, %d", fd, fs);
calculateFCSR(fs, 0, CEILWD, False, 1);
- if (!mode64) {
+ if (!fp_mode64) {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x2),
getDReg(fs)));
@@ -12972,20 +13016,28 @@
switch (fmt) {
case 0x10: /* S */
DIP("ceil.l.s %d, %d", fd, fs);
- calculateFCSR(fs, 0, CEILLS, True, 1);
- t0 = newTemp(Ity_I64);
+ if (fp_mode64) {
+ calculateFCSR(fs, 0, CEILLS, True, 1);
+ t0 = newTemp(Ity_I64);
- assign(t0, binop(Iop_F32toI64S, mkU32(0x2),
- getLoFromF64(Ity_F64, getFReg(fs))));
+ assign(t0, binop(Iop_F32toI64S, mkU32(0x2),
+ getLoFromF64(tyF, getFReg(fs))));
- putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
+ putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
break;
case 0x11: /* D */
DIP("ceil.l.d %d, %d", fd, fs);
- calculateFCSR(fs, 0, CEILLD, False, 1);
- putFReg(fd, binop(Iop_RoundF64toInt, mkU32(0x2),
- getFReg(fs)));
+ if (fp_mode64) {
+ calculateFCSR(fs, 0, CEILLD, False, 1);
+ putFReg(fd, binop(Iop_RoundF64toInt, mkU32(0x2),
+ getFReg(fs)));
+ } else {
+ ILLEGAL_INSTRUCTON;
+ }
break;
default:
@@ -13061,17 +13113,24 @@
case 0x31: /* LWC1 */
/* Load Word to Floating Point - LWC1 (MIPS32) */
DIP("lwc1 f%d, %d(r%d)", ft, imm, rs);
- if (mode64) {
- t0 = newTemp(Ity_I64);
+ if (fp_mode64) {
t1 = newTemp(Ity_F32);
t2 = newTemp(Ity_I64);
- /* new LO */
- assign(t0, binop(Iop_Add64, getIReg(rs),
- mkU64(extend_s_16to64(imm))));
+ if (mode64) {
+ t0 = newTemp(Ity_I64);
+ /* new LO */
+ assign(t0, binop(Iop_Add64, getIReg(rs),
+ mkU64(extend_s_16to64(imm))));
+ } else {
+ t0 = newTemp(Ity_I32);
+ /* new LO */
+ assign(t0, binop(Iop_Add32, getIReg(rs),
+ mkU32(extend_s_16to32(imm))));
+ }
assign(t1, load(Ity_F32, mkexpr(t0)));
- assign(t2, mkWidenFrom32(ty, unop(Iop_ReinterpF32asI32,
- mkexpr(t1)), True));
- putFReg(ft, unop(Iop_ReinterpI64asF64, mkexpr(t2)));
+ assign(t2, mkWidenFrom32(Ity_I64, unop(Iop_ReinterpF32asI32,
+ mkexpr(t1)), True));
+ putDReg(ft, unop(Iop_ReinterpI64asF64, mkexpr(t2)));
} else {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_Add32, getIReg(rs),
@@ -13082,7 +13141,7 @@
case 0x39: /* SWC1 */
DIP("swc1 f%d, %d(r%d)", ft, imm, rs);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I64);
t2 = newTemp(Ity_I32);
LOAD_STORE_PATTERN;
@@ -13101,22 +13160,16 @@
case 0x35:
/* Load Doubleword to Floating Point - LDC1 (MIPS32) */
- LOAD_STORE_PATTERN;
- if (mode64)
- putFReg(ft, load(Ity_F64, mkexpr(t1)));
- else
- putDReg(ft, load(Ity_F64, mkexpr(t1)));
DIP("ldc1 f%d, %d(%d)", rt, imm, rs);
+ LOAD_STORE_PATTERN;
+ putDReg(ft, load(Ity_F64, mkexpr(t1)));
break;
case 0x3D:
/* Store Doubleword from Floating Point - SDC1 */
- LOAD_STORE_PATTERN;
- if (mode64)
- store(mkexpr(t1), getFReg(ft));
- else
- store(mkexpr(t1), getDReg(ft));
DIP("sdc1 f%d, %d(%d)", ft, imm, rs);
+ LOAD_STORE_PATTERN;
+ store(mkexpr(t1), getDReg(ft));
break;
case 0x23: /* LW */
@@ -13175,19 +13228,20 @@
case 0x0: { /* LWXC1 */
/* Load Word Indexed to Floating Point - LWXC1 (MIPS32r2) */
DIP("lwxc1 f%d, r%d(r%d)", fd, rt, rs);
- if (mode64) {
+ if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
- t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_F32);
t4 = newTemp(Ity_I64);
+ t2 = newTemp(ty);
/* new LO */
- assign(t2, binop(Iop_Add64, getIReg(rs), getIReg(rt)));
+ assign(t2, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
+ getIReg(rt)));
assign(t3, load(Ity_F32, mkexpr(t2)));
- assign(t4, mkWidenFrom32(ty, unop(Iop_ReinterpF32asI32,
- mkexpr(t3)), True));
+ assign(t4, mkWidenFrom32(Ity_I64, unop(Iop_ReinterpF32asI32,
+ mkexpr(t3)), True));
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t4)));
} else {
@@ -13201,10 +13255,11 @@
case 0x1: { /* LDXC1 */
/* Load Doubleword Indexed to Floating Point
LDXC1 (MIPS32r2 and MIPS64) */
- if (mode64) {
+ if (fp_mode64) {
DIP("ldxc1 f%d, r%d(r%d)", fd, rt, rs);
- t0 = newTemp(Ity_I64);
- assign(t0, binop(Iop_Add64, getIReg(rs), getIReg(rt)));
+ t0 = newTemp(ty);
+ assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
+ getIReg(rt)));
putFReg(fd, load(Ity_F64, mkexpr(t0)));
break;
} else {
@@ -13238,10 +13293,10 @@
case 0x8: { /* Store Word Indexed from Floating Point - SWXC1 */
DIP("swxc1 f%d, r%d(r%d)", ft, rt, rs);
- if (mode64) {
- t0 = newTemp(Ity_I64);
- assign(t0, binop(Iop_Add64, getIReg(rs), getIReg(rt)));
-
+ if (fp_mode64) {
+ t0 = newTemp(ty);
+ assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
+ getIReg(rt)));
store(mkexpr(t0), getLoFromF64(tyF, getFReg(fs)));
} else {
@@ -13254,9 +13309,10 @@
}
case 0x9: { /* Store Doubleword Indexed from Floating Point - SDXC1 */
DIP("sdc1 f%d, %d(%d)", ft, imm, rs);
- if (mode64) {
- t0 = newTemp(Ity_I64);
- assign(t0, binop(Iop_Add64, getIReg(rs), getIReg(rt)));
+ if (fp_mode64) {
+ t0 = newTemp(ty);
+ assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
+ getIReg(rt)));
store(mkexpr(t0), getFReg(fs));
} else {
t0 = newTemp(Ity_I32);
@@ -16693,8 +16749,8 @@
decode_failure_dsp:
vex_printf("Error occured while trying to decode MIPS32 DSP "
- "instruction.\nYour platform probably doesn't support "
- "MIPS32 DSP ASE.\n");
+ "instruction.\nYour platform probably doesn't support "
+ "MIPS32 DSP ASE.\n");
decode_failure:
/* All decode failures end up here. */
if (sigill_diag)
@@ -16797,7 +16853,6 @@
/* Disassemble a single instruction into IR. The instruction
is located in host memory at &guest_code[delta]. */
-
DisResult disInstr_MIPS( IRSB* irsb_IN,
Bool (*resteerOkFn) ( void *, Addr64 ),
Bool resteerCisOk,
@@ -16816,6 +16871,10 @@
vassert(guest_arch == VexArchMIPS32 || guest_arch == VexArchMIPS64);
mode64 = guest_arch != VexArchMIPS32;
+#if (__mips_fpr==64)
+ fp_mode64 = ((VEX_MIPS_REV(archinfo->hwcaps) == VEX_PRID_CPU_32FPR)
+ || guest_arch == VexArchMIPS64);
+#endif
guest_code = guest_code_IN;
irsb = irsb_IN;
diff --git a/priv/host_mips_defs.c b/priv/host_mips_defs.c
index 1addd04..e708434 100644
--- a/priv/host_mips_defs.c
+++ b/priv/host_mips_defs.c
@@ -37,7 +37,7 @@
#include "host_mips_defs.h"
/* guest_COND offset. */
-#define COND_OFFSET(__mode64) (__mode64 ? 612 : 316)
+#define COND_OFFSET(__mode64) (__mode64 ? 612 : 448)
/* Register number for guest state pointer in host code. */
#define GuestSP 23
@@ -81,7 +81,7 @@
/* But specific for real regs. */
vassert(hregClass(reg) == HRcInt32 || hregClass(reg) == HRcInt64 ||
- hregClass(reg) == HRcFlt32 || hregClass(reg) == HRcFlt64);
+ hregClass(reg) == HRcFlt32 || hregClass(reg) == HRcFlt64);
/* But specific for real regs. */
switch (hregClass(reg)) {
@@ -91,7 +91,6 @@
vex_printf("%s", ireg32_names[r]);
return;
case HRcInt64:
- vassert(mode64);
r = hregNumber (reg);
vassert (r >= 0 && r < 32);
vex_printf ("%s", ireg32_names[r]);
@@ -773,6 +772,12 @@
case Mfp_CVTWD:
ret = "cvt.w.d";
break;
+ case Mfp_CVTLD:
+ ret = "cvt.l.d";
+ break;
+ case Mfp_CVTLS:
+ ret = "cvt.l.s";
+ break;
case Mfp_TRUWD:
ret = "trunc.w.d";
break;
@@ -801,6 +806,7 @@
ret = "C.cond.d";
break;
default:
+ vex_printf("Unknown op: %d", op);
vpanic("showMIPSFpOp");
break;
}
@@ -1864,7 +1870,7 @@
return;
}
case Min_FpGpMove: {
- vex_printf("%s", showMIPSFpGpMoveOp(i->Min.FpGpMove.op));
+ vex_printf("%s ", showMIPSFpGpMoveOp(i->Min.FpGpMove.op));
ppHRegMIPS(i->Min.FpGpMove.dst, mode64);
vex_printf(", ");
ppHRegMIPS(i->Min.FpGpMove.src, mode64);
@@ -2380,7 +2386,6 @@
static UChar fregNo(HReg r, Bool mode64)
{
UInt n;
- vassert(hregClass(r) == (mode64 ? HRcFlt64 : HRcFlt32));
vassert(!hregIsVirtual(r));
n = hregNumber(r);
vassert(n <= 31);
@@ -2390,7 +2395,6 @@
static UChar dregNo(HReg r)
{
UInt n;
- vassert(hregClass(r) == HRcFlt64);
vassert(!hregIsVirtual(r));
n = hregNumber(r);
vassert(n <= 31);
@@ -3457,6 +3461,7 @@
case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break;
case Ijk_TInval: trcval = VEX_TRC_JMP_TINVAL; break;
case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break;
+ case Ijk_SigILL: trcval = VEX_TRC_JMP_SIGILL; break;
case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break;
/* case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break; */
case Ijk_SigBUS: trcval = VEX_TRC_JMP_SIGBUS; break;
@@ -3886,8 +3891,13 @@
p = mkFormR(p, 0x11, 0x15, 0, fr_src, fr_dst, 0x20);
break;
case Mfp_CVTLS:
- fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
- fr_src = dregNo(i->Min.FpConvert.src);
+ if (mode64) {
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = dregNo(i->Min.FpConvert.src);
+ } else {
+ fr_dst = dregNo(i->Min.FpConvert.dst);
+ fr_src = fregNo(i->Min.FpConvert.src, mode64);
+ }
p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x25);
break;
case Mfp_CVTLD:
diff --git a/priv/host_mips_isel.c b/priv/host_mips_isel.c
index 346e411..088b808 100644
--- a/priv/host_mips_isel.c
+++ b/priv/host_mips_isel.c
@@ -47,12 +47,14 @@
ZERO0 Reserved
GPR12:22 Allocateable
23 GuestStatePointer
- 23 Allocateable
SP StackFramePointer
RA LinkRegister */
static Bool mode64 = False;
+/* Host CPU has FPU and 32 dbl. prec. FP registers. */
+static Bool fp_mode64 = False;
+
/* GPR register class for mips32/64 */
#define HRcGPR(__mode64) (__mode64 ? HRcInt64 : HRcInt32)
@@ -60,7 +62,7 @@
#define HRcFPR(__mode64) (__mode64 ? HRcFlt64 : HRcFlt32)
/* guest_COND offset */
-#define COND_OFFSET(__mode64) (__mode64 ? 612 : 316)
+#define COND_OFFSET(__mode64) (__mode64 ? 612 : 448)
/*---------------------------------------------------------*/
/*--- ISelEnv ---*/
@@ -117,6 +119,7 @@
UInt hwcaps;
Bool mode64;
+ Bool fp_mode64;
Bool chainingAllowed;
Addr64 max_ga;
@@ -180,7 +183,7 @@
static HReg newVRegF(ISelEnv * env)
{
- HReg reg = mkHReg(env->vreg_ctr, HRcFPR(env->mode64),
+ HReg reg = mkHReg(env->vreg_ctr, HRcFPR(env->fp_mode64),
True /*virtual reg */ );
env->vreg_ctr++;
return reg;
@@ -230,13 +233,13 @@
static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e);
static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e);
-/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter being an immediate in
- the range 1 .. 31 inclusive. Used for doing shift amounts. */
+/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter being an
+ immediate in the range 1 .. 31 inclusive. Used for doing shift amounts. */
static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e);
static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e);
-/* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter being an immediate in
- the range 1 .. 63 inclusive. Used for doing shift amounts. */
+/* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter being an
+ immediate in the range 1 .. 63 inclusive. Used for doing shift amounts. */
static MIPSRH *iselWordExpr_RH6u_wrk(ISelEnv * env, IRExpr * e);
static MIPSRH *iselWordExpr_RH6u(ISelEnv * env, IRExpr * e);
@@ -2754,6 +2757,44 @@
return;
}
+ case Iop_F32toI64S: {
+ HReg tmpD = newVRegD(env);
+ HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ MIPSAMode *am_addr;
+
+ /* CVTLS tmpD, valF */
+ set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpD, valF));
+ set_MIPS_rounding_default(env);
+
+ sub_from_sp(env, 16); /* Move SP down 16 bytes */
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ /* store as F64 */
+ addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, tmpD,
+ am_addr));
+ /* load as 2xI32 */
+#if defined (_MIPSEL)
+ addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
+ addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
+ mode64));
+#elif defined (_MIPSEB)
+ addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64));
+ addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr),
+ mode64));
+#endif
+
+ /* Reset SP */
+ add_to_sp(env, 16);
+
+ *rHi = tHi;
+ *rLo = tLo;
+
+ return;
+ }
+
default:
break;
}
@@ -2936,33 +2977,38 @@
static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e)
{
IRType ty = typeOfIRExpr(env->type_env, e);
- vassert(ty == Ity_F32 || (ty == Ity_F64 && mode64));
+ vassert(ty == Ity_F32 || (ty == Ity_F64 && fp_mode64));
if (e->tag == Iex_RdTmp) {
return lookupIRTemp(env, e->Iex.RdTmp.tmp);
}
if (e->tag == Iex_Load) {
- MIPSAMode *am_addr;
- HReg r_dst = newVRegF(env);
vassert(e->Iex.Load.ty == Ity_F32
- || (e->Iex.Load.ty == Ity_F64 && mode64));
- am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
- if (mode64 && e->Iex.Load.ty == Ity_F64)
+ || (e->Iex.Load.ty == Ity_F64 && fp_mode64));
+ HReg r_dst;
+ MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
+ if (e->Iex.Load.ty == Ity_F64) {
+ r_dst = newVRegD(env);
addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
- else
+ } else {
+ r_dst = newVRegF(env);
addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr));
+ }
return r_dst;
}
if (e->tag == Iex_Get) {
- HReg r_dst = newVRegF(env);
MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
GuestStatePointer(mode64));
- if (mode64)
+ HReg r_dst;
+ if (e->Iex.Load.ty == Ity_F64) {
+ r_dst = newVRegD(env);
addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
- else
+ } else {
+ r_dst = newVRegF(env);
addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr));
+ }
return r_dst;
}
@@ -2979,7 +3025,7 @@
return r_dst;
}
case Iop_F32toF64: {
- vassert(mode64);
+ vassert(fp_mode64);
HReg src = iselFltExpr(env, e->Iex.Unop.arg);
HReg dst = newVRegD(env);
@@ -2987,24 +3033,29 @@
return dst;
}
case Iop_ReinterpI64asF64: {
- vassert(mode64);
- HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
- HReg r_dst = newVRegF(env);
-
- /* Move Doubleword to Floating Point
- dmtc1 r_dst, fr_src */
- addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmtc1, r_dst, fr_src));
-
+ HReg r_dst;
+ if (mode64) {
+ HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ r_dst = newVRegF(env);
+ /* Move Doubleword to Floating Point
+ dmtc1 r_dst, fr_src */
+ addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmtc1, r_dst, fr_src));
+ } else {
+ HReg Hi, Lo;
+ r_dst = newVRegD(env);
+ iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
+ r_dst = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
+ }
return r_dst;
}
case Iop_I32StoF64: {
- vassert(mode64);
+ vassert(fp_mode64);
HReg dst = newVRegF(env);
HReg tmp = newVRegF(env);
HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
/* Move Word to Floating Point
- mtc1 tmp1, r_src */
+ mtc1 tmp, r_src */
addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src));
/* and do convert */
@@ -3081,28 +3132,28 @@
op = Mfp_DIVS;
break;
case Iop_DivF64:
- vassert(mode64);
+ vassert(fp_mode64);
op = Mfp_DIVD;
break;
case Iop_MulF32:
op = Mfp_MULS;
break;
case Iop_MulF64:
- vassert(mode64);
+ vassert(fp_mode64);
op = Mfp_MULD;
break;
case Iop_AddF32:
op = Mfp_ADDS;
break;
case Iop_AddF64:
- vassert(mode64);
+ vassert(fp_mode64);
op = Mfp_ADDD;
break;
case Iop_SubF32:
op = Mfp_SUBS;
break;
case Iop_SubF64:
- vassert(mode64);
+ vassert(fp_mode64);
op = Mfp_SUBD;
break;
default:
@@ -3172,23 +3223,29 @@
case Iop_I64StoF64: {
HReg r_dst = newVRegF(env);
-
MIPSAMode *am_addr;
- HReg fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
- HReg tmp = newVRegF(env);
+ HReg tmp, fr_src;
+ if (mode64) {
+ tmp = newVRegF(env);
+ fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ /* Move SP down 8 bytes */
+ sub_from_sp(env, 8);
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
- /* Move SP down 8 bytes */
- sub_from_sp(env, 8);
- am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+ /* store as I64 */
+ addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
- /* store as I64 */
- addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
+ /* load as Ity_F64 */
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
- /* load as Ity_F64 */
- addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
-
- /* Reset SP */
- add_to_sp(env, 8);
+ /* Reset SP */
+ add_to_sp(env, 8);
+ } else {
+ HReg Hi, Lo;
+ tmp = newVRegD(env);
+ iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
+ tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
+ }
set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, r_dst, tmp));
@@ -3199,23 +3256,29 @@
case Iop_I64StoF32: {
HReg r_dst = newVRegF(env);
-
MIPSAMode *am_addr;
- HReg fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
- HReg tmp = newVRegF(env);
+ HReg fr_src, tmp;
+ if (mode64) {
+ tmp = newVRegF(env);
+ fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ /* Move SP down 8 bytes */
+ sub_from_sp(env, 8);
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
- /* Move SP down 8 bytes */
- sub_from_sp(env, 8);
- am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+ /* store as I64 */
+ addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
- /* store as I64 */
- addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
+ /* load as Ity_F64 */
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
- /* load as Ity_F64 */
- addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
-
- /* Reset SP */
- add_to_sp(env, 8);
+ /* Reset SP */
+ add_to_sp(env, 8);
+ } else {
+ HReg Hi, Lo;
+ tmp = newVRegD(env);
+ iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
+ tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
+ }
set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSL, r_dst, tmp));
@@ -3438,19 +3501,14 @@
if (e->tag == Iex_Binop) {
switch (e->Iex.Binop.op) {
case Iop_RoundF64toInt: {
- HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
- MIPSRH *fmt = iselWordExpr_RH(env, False, e->Iex.Binop.arg1);
- HReg valD1 = newVRegD(env);
+ HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
+ HReg dst = newVRegD(env);
- if (fmt->Mrh.Imm.imm16 == 0x3)
- addInstr(env, MIPSInstr_FpConvert(Mfp_TRULD, valD1, valD));
- else if (fmt->Mrh.Imm.imm16 == 0x2)
- addInstr(env, MIPSInstr_FpConvert(Mfp_CEILLD, valD1, valD));
- else if (fmt->Mrh.Imm.imm16 == 0x0)
- addInstr(env, MIPSInstr_FpConvert(Mfp_ROUNDLD, valD1, valD));
- else
- vassert(0);
- return valD1;
+ set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, dst, src));
+ set_MIPS_rounding_default(env);
+
+ return dst;
}
case Iop_SqrtF64: {
@@ -4047,6 +4105,7 @@
case Ijk_NoDecode:
case Ijk_NoRedir:
case Ijk_SigBUS:
+ case Ijk_SigILL:
case Ijk_SigTRAP:
case Ijk_SigFPE_IntDiv:
case Ijk_SigFPE_IntOvf:
@@ -4097,11 +4156,16 @@
|| VEX_PRID_COMP_NETLOGIC);
mode64 = arch_host != VexArchMIPS32;
+#if (__mips_fpr==64)
+ fp_mode64 = ((VEX_MIPS_REV(hwcaps_host) == VEX_PRID_CPU_32FPR)
+ || arch_host == VexArchMIPS64);
+#endif
/* Make up an initial environment to use. */
env = LibVEX_Alloc(sizeof(ISelEnv));
env->vreg_ctr = 0;
env->mode64 = mode64;
+ env->fp_mode64 = fp_mode64;
/* Set up output code array. */
env->code = newHInstrArray();
@@ -4166,6 +4230,7 @@
default:
ppIRType(bb->tyenv->types[i]);
vpanic("iselBB(mips): IRTemp type");
+ break;
}
env->vregmap[i] = hreg;
env->vregmapHI[i] = hregHI;
diff --git a/priv/ir_defs.c b/priv/ir_defs.c
index 575575c..87b0b63 100644
--- a/priv/ir_defs.c
+++ b/priv/ir_defs.c
@@ -1414,6 +1414,7 @@
case Ijk_MapFail: vex_printf("MapFail"); break;
case Ijk_TInval: vex_printf("Invalidate"); break;
case Ijk_NoRedir: vex_printf("NoRedir"); break;
+ case Ijk_SigILL: vex_printf("SigILL"); break;
case Ijk_SigTRAP: vex_printf("SigTRAP"); break;
case Ijk_SigSEGV: vex_printf("SigSEGV"); break;
case Ijk_SigBUS: vex_printf("SigBUS"); break;
diff --git a/pub/libvex.h b/pub/libvex.h
index 4cc6156..2d40833 100644
--- a/pub/libvex.h
+++ b/pub/libvex.h
@@ -200,10 +200,15 @@
#define VEX_PRID_IMP_34K 0x9500
#define VEX_PRID_IMP_74K 0x9700
+/* CPU has FPU and 32 dbl. prec. FP registers */
+#define VEX_PRID_CPU_32FPR 0x00000040
+
/* Get MIPS Company ID from HWCAPS */
#define VEX_MIPS_COMP_ID(x) ((x) & 0x00FF0000)
/* Get MIPS Processor ID from HWCAPS */
-#define VEX_MIPS_PROC_ID(x) ((x) & 0x0000FFFF)
+#define VEX_MIPS_PROC_ID(x) ((x) & 0x0000FF00)
+/* Get MIPS Revision from HWCAPS */
+#define VEX_MIPS_REV(x) ((x) & 0x000000FF)
/* Check if the processor supports DSP ASE Rev 2. */
#define VEX_MIPS_PROC_DSP2(x) ((VEX_MIPS_COMP_ID(x) == VEX_PRID_COMP_MIPS) && \
(VEX_MIPS_PROC_ID(x) == VEX_PRID_IMP_74K))
diff --git a/pub/libvex_guest_mips32.h b/pub/libvex_guest_mips32.h
index 95c2a58..65318fe 100644
--- a/pub/libvex_guest_mips32.h
+++ b/pub/libvex_guest_mips32.h
@@ -41,81 +41,81 @@
typedef
struct {
/* CPU Registers */
- /* 0 */ UInt guest_r0; /* Hardwired to 0 */
- /* 4 */ UInt guest_r1; /* Assembler temporary */
- /* 8 */ UInt guest_r2; /* Values for function returns ...*/
- /* 12 */ UInt guest_r3; /* ...and expression evaluation */
- /* 16 */ UInt guest_r4; /* Function arguments */
- /* 20 */ UInt guest_r5;
- /* 24 */ UInt guest_r6;
- /* 28 */ UInt guest_r7;
- /* 32 */ UInt guest_r8; /* Temporaries */
- /* 36 */ UInt guest_r9;
- /* 40 */ UInt guest_r10;
- /* 44 */ UInt guest_r11;
- /* 48 */ UInt guest_r12;
- /* 52 */ UInt guest_r13;
- /* 56 */ UInt guest_r14;
- /* 60 */ UInt guest_r15;
- /* 64 */ UInt guest_r16; /* Saved temporaries */
- /* 68 */ UInt guest_r17;
- /* 72 */ UInt guest_r18;
- /* 76 */ UInt guest_r19;
- /* 80 */ UInt guest_r20;
- /* 84 */ UInt guest_r21;
- /* 88 */ UInt guest_r22;
- /* 92 */ UInt guest_r23;
- /* 96 */ UInt guest_r24; /* Temporaries */
- /* 100 */ UInt guest_r25;
- /* 104 */ UInt guest_r26; /* Reserved for OS kernel */
- /* 108 */ UInt guest_r27;
- /* 112 */ UInt guest_r28; /* Global pointer */
- /* 116 */ UInt guest_r29; /* Stack pointer */
- /* 120 */ UInt guest_r30; /* Frame pointer */
- /* 124 */ UInt guest_r31; /* Return address */
- /* 128 */ UInt guest_PC; /* Program counter */
- /* 132 */ UInt guest_HI;/* Multiply and divide register higher result */
- /* 136 */ UInt guest_LO;/* Multiply and divide register lower result */
+ /* 0 */ UInt guest_r0; /* Hardwired to 0 */
+ /* 4 */ UInt guest_r1; /* Assembler temporary */
+ /* 8 */ UInt guest_r2; /* Values for function returns ...*/
+ /* 12 */ UInt guest_r3; /* ...and expression evaluation */
+ /* 16 */ UInt guest_r4; /* Function arguments */
+ /* 20 */ UInt guest_r5;
+ /* 24 */ UInt guest_r6;
+ /* 28 */ UInt guest_r7;
+ /* 32 */ UInt guest_r8; /* Temporaries */
+ /* 36 */ UInt guest_r9;
+ /* 40 */ UInt guest_r10;
+ /* 44 */ UInt guest_r11;
+ /* 48 */ UInt guest_r12;
+ /* 52 */ UInt guest_r13;
+ /* 56 */ UInt guest_r14;
+ /* 60 */ UInt guest_r15;
+ /* 64 */ UInt guest_r16; /* Saved temporaries */
+ /* 68 */ UInt guest_r17;
+ /* 72 */ UInt guest_r18;
+ /* 76 */ UInt guest_r19;
+ /* 80 */ UInt guest_r20;
+ /* 84 */ UInt guest_r21;
+ /* 88 */ UInt guest_r22;
+ /* 92 */ UInt guest_r23;
+ /* 96 */ UInt guest_r24; /* Temporaries */
+ /* 100 */ UInt guest_r25;
+ /* 104 */ UInt guest_r26; /* Reserved for OS kernel */
+ /* 108 */ UInt guest_r27;
+ /* 112 */ UInt guest_r28; /* Global pointer */
+ /* 116 */ UInt guest_r29; /* Stack pointer */
+ /* 120 */ UInt guest_r30; /* Frame pointer */
+ /* 124 */ UInt guest_r31; /* Return address */
+ /* 128 */ UInt guest_PC; /* Program counter */
+ /* 132 */ UInt guest_HI; /* Multiply and divide register higher result */
+ /* 136 */ UInt guest_LO; /* Multiply and divide register lower result */
/* FPU Registers */
- /* 140 */ UInt guest_f0; /* Floting point general purpose registers */
- /* 144 */ UInt guest_f1;
- /* 148 */ UInt guest_f2;
- /* 152 */ UInt guest_f3;
- /* 156 */ UInt guest_f4;
- /* 160 */ UInt guest_f5;
- /* 164 */ UInt guest_f6;
- /* 168 */ UInt guest_f7;
- /* 172 */ UInt guest_f8;
- /* 176 */ UInt guest_f9;
- /* 180 */ UInt guest_f10;
- /* 184 */ UInt guest_f11;
- /* 188 */ UInt guest_f12;
- /* 192 */ UInt guest_f13;
- /* 196 */ UInt guest_f14;
- /* 200 */ UInt guest_f15;
- /* 204 */ UInt guest_f16;
- /* 208 */ UInt guest_f17;
- /* 212 */ UInt guest_f18;
- /* 216 */ UInt guest_f19;
- /* 220 */ UInt guest_f20;
- /* 224 */ UInt guest_f21;
- /* 228 */ UInt guest_f22;
- /* 232 */ UInt guest_f23;
- /* 236 */ UInt guest_f24;
- /* 240 */ UInt guest_f25;
- /* 244 */ UInt guest_f26;
- /* 248 */ UInt guest_f27;
- /* 252 */ UInt guest_f28;
- /* 256 */ UInt guest_f29;
- /* 260 */ UInt guest_f30;
- /* 264 */ UInt guest_f31;
-
- /* 268 */ UInt guest_FIR;
- /* 272 */ UInt guest_FCCR;
- /* 276 */ UInt guest_FEXR;
- /* 280 */ UInt guest_FENR;
- /* 284 */ UInt guest_FCSR;
+ /* 144 */ ULong guest_f0; /* Floating point general purpose registers */
+ /* 152 */ ULong guest_f1;
+ /* 160 */ ULong guest_f2;
+ /* 168 */ ULong guest_f3;
+ /* 176 */ ULong guest_f4;
+ /* 184 */ ULong guest_f5;
+ /* 192 */ ULong guest_f6;
+ /* 200 */ ULong guest_f7;
+ /* 208 */ ULong guest_f8;
+ /* 216 */ ULong guest_f9;
+ /* 224 */ ULong guest_f10;
+ /* 232 */ ULong guest_f11;
+ /* 240 */ ULong guest_f12;
+ /* 248 */ ULong guest_f13;
+ /* 256 */ ULong guest_f14;
+ /* 264 */ ULong guest_f15;
+ /* 272 */ ULong guest_f16;
+ /* 280 */ ULong guest_f17;
+ /* 288 */ ULong guest_f18;
+ /* 296 */ ULong guest_f19;
+ /* 304 */ ULong guest_f20;
+ /* 312 */ ULong guest_f21;
+ /* 320 */ ULong guest_f22;
+ /* 328 */ ULong guest_f23;
+ /* 336 */ ULong guest_f24;
+ /* 344 */ ULong guest_f25;
+ /* 352 */ ULong guest_f26;
+ /* 360 */ ULong guest_f27;
+ /* 368 */ ULong guest_f28;
+ /* 376 */ ULong guest_f29;
+ /* 384 */ ULong guest_f30;
+ /* 392 */ ULong guest_f31;
+
+ /* 400 */ UInt guest_FIR;
+ /* 404 */ UInt guest_FCCR;
+ /* 408 */ UInt guest_FEXR;
+ /* 412 */ UInt guest_FENR;
+ /* 416 */ UInt guest_FCSR;
/* TLS pointer for the thread. It's read-only in user space.
On Linux it is set in user space by various thread-related
@@ -126,29 +126,28 @@
environments, the UserLocal register is a pointer to a
thread-specific storage block.
*/
- /* 288 */ UInt guest_ULR;
+ /* 420 */ UInt guest_ULR;
/* Emulation notes */
- UInt guest_EMNOTE; /* 292 */
+ /* 424 */ UInt guest_EMNOTE;
/* For clflush: record start and length of area to invalidate */
- UInt guest_TISTART; /* 296 */
- UInt guest_TILEN; /* 300 */
- UInt guest_NRADDR; /* 304 */
+ /* 428 */ UInt guest_TISTART;
+ /* 432 */ UInt guest_TILEN;
+ /* 436 */ UInt guest_NRADDR;
- UInt host_EvC_FAILADDR; /* 308 */
- UInt host_EvC_COUNTER; /* 312 */
- UInt guest_COND; /* 316 */
+ /* 440 */ UInt host_EvC_FAILADDR;
+ /* 444 */ UInt host_EvC_COUNTER;
+ /* 448 */ UInt guest_COND;
- UInt padding1;
/* MIPS32 DSP ASE(r2) specific registers. */
- UInt guest_DSPControl; /* 324 */
- ULong guest_ac0; /* 328 */
- ULong guest_ac1; /* 336 */
- ULong guest_ac2; /* 344 */
- ULong guest_ac3; /* 352 */
-
- UInt padding[2];
+ /* 452 */ UInt guest_DSPControl;
+ /* 456 */ ULong guest_ac0;
+ /* 464 */ ULong guest_ac1;
+ /* 472 */ ULong guest_ac2;
+ /* 480 */ ULong guest_ac3;
+
+ UInt padding;
} VexGuestMIPS32State;
/*---------------------------------------------------------------*/
/*--- Utility functions for MIPS32 guest stuff. ---*/
diff --git a/pub/libvex_ir.h b/pub/libvex_ir.h
index c89b608..39d45e4 100644
--- a/pub/libvex_ir.h
+++ b/pub/libvex_ir.h
@@ -2107,6 +2107,7 @@
Ijk_MapFail, /* Vex-provided address translation failed */
Ijk_TInval, /* Invalidate translations before continuing. */
Ijk_NoRedir, /* Jump to un-redirected guest addr */
+ Ijk_SigILL, /* current instruction synths SIGILL */
Ijk_SigTRAP, /* current instruction synths SIGTRAP */
Ijk_SigSEGV, /* current instruction synths SIGSEGV */
Ijk_SigBUS, /* current instruction synths SIGBUS */
diff --git a/pub/libvex_trc_values.h b/pub/libvex_trc_values.h
index c0f3cc8..58a8e30 100644
--- a/pub/libvex_trc_values.h
+++ b/pub/libvex_trc_values.h
@@ -68,6 +68,9 @@
#define VEX_TRC_JMP_SIGFPE_INTOVF 99 /* deliver SIGFPE (integer overflow)
before continuing */
+#define VEX_TRC_JMP_SIGILL 101 /* deliver SIGILL (Illegal instruction)
+ before continuing */
+
#define VEX_TRC_JMP_EMWARN 63 /* deliver emulation warning before
continuing */
#define VEX_TRC_JMP_EMFAIL 83 /* emulation fatal error; abort system */