Add support for binary DFP operations (64-bit).
Patch by Maran (maranp@linux.vnet.ibm.com).
Part of fixing BZ 307113.
git-svn-id: svn://svn.valgrind.org/vex/trunk@2560 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_s390_toIR.c b/priv/guest_s390_toIR.c
index 0748685..64a01b7 100644
--- a/priv/guest_s390_toIR.c
+++ b/priv/guest_s390_toIR.c
@@ -427,6 +427,8 @@
static __inline__ IRExpr *get_fpr_dw0(UInt);
static __inline__ void put_fpr_dw0(UInt, IRExpr *);
+static __inline__ IRExpr *get_dpr_dw0(UInt);
+static __inline__ void put_dpr_dw0(UInt, IRExpr *);
/* Read a floating point register pair and combine their contents into a
128-bit value */
@@ -907,6 +909,21 @@
return IRExpr_Get(fpr_dw0_offset(archreg), Ity_F64);
}
+/* Write double word #0 of a fpr containg DFP value to the guest state. */
+static __inline__ void
+put_dpr_dw0(UInt archreg, IRExpr *expr)
+{
+ vassert(typeOfIRExpr(irsb->tyenv, expr) == Ity_D64);
+
+ stmt(IRStmt_Put(fpr_dw0_offset(archreg), expr));
+}
+
+/* Read double word #0 of a fpr register containing DFP value. */
+static __inline__ IRExpr *
+get_dpr_dw0(UInt archreg)
+{
+ return IRExpr_Get(fpr_dw0_offset(archreg), Ity_D64);
+}
/*------------------------------------------------------------*/
/*--- gpr registers ---*/
@@ -1481,7 +1498,6 @@
So: IR = (s390 ^ ((s390 << 1) & 2))
*/
-#if 0 // fixs390: avoid compiler warnings about unused function
static IRExpr *
get_dfp_rounding_mode_from_fpc(void)
{
@@ -1541,7 +1557,7 @@
return mktemp(Ity_I32, rm);
}
-#endif
+
/*------------------------------------------------------------*/
/*--- Build IR for formats ---*/
@@ -1907,6 +1923,16 @@
}
static void
+s390_format_RRF_FUFF2(HChar *(*irgen)(UChar, UChar, UChar, UChar),
+ UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ HChar *mnm = irgen(r3, m4, r1, r2);
+
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+ s390_disasm(ENC5(MNM, FPR, FPR, FPR, UINT), mnm, r1, r2, r3, m4);
+}
+
+static void
s390_format_RRF_R0RR2(HChar *(*irgen)(UChar r3, UChar r1, UChar r2),
UChar r3, UChar r1, UChar r2)
{
@@ -8850,6 +8876,18 @@
}
static HChar *
+s390_irgen_LTDTR(UChar r1, UChar r2)
+{
+ IRTemp result = newTemp(Ity_D64);
+
+ assign(result, get_dpr_dw0(r2));
+ put_dpr_dw0(r1, mkexpr(result));
+ s390_cc_thunk_putF(S390_CC_OP_DFP_RESULT_64, result);
+
+ return "ltdtr";
+}
+
+static HChar *
s390_irgen_MEEBR(UChar r1, UChar r2)
{
IRTemp op1 = newTemp(Ity_F32);
@@ -8990,6 +9028,98 @@
return "sdb";
}
+static HChar *
+s390_irgen_ADTRA(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D64);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp result = newTemp(Ity_D64);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ /* when m4 = 0, S390_DFP_ROUND_PER_FPC_0 should be set.
+ since S390_DFP_ROUND_PER_FPC_0 is also 0, passing m4 is sufficient */
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_dpr_dw0(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, triop(Iop_AddD64, mkexpr(rounding_mode), mkexpr(op1),
+ mkexpr(op2)));
+ s390_cc_thunk_putF(S390_CC_OP_DFP_RESULT_64, result);
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return (m4 == 0) ? "adtr" : "adtra";
+}
+
+static HChar *
+s390_irgen_DDTRA(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D64);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp result = newTemp(Ity_D64);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ /* when m4 = 0, S390_DFP_ROUND_PER_FPC_0 should be set.
+ since S390_DFP_ROUND_PER_FPC_0 is also 0, passing m4 is sufficient */
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_dpr_dw0(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, triop(Iop_DivD64, mkexpr(rounding_mode), mkexpr(op1),
+ mkexpr(op2)));
+ s390_cc_thunk_putF(S390_CC_OP_DFP_RESULT_64, result);
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return (m4 == 0) ? "ddtr" : "ddtra";
+}
+
+static HChar *
+s390_irgen_MDTRA(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D64);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp result = newTemp(Ity_D64);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ /* when m4 = 0, S390_DFP_ROUND_PER_FPC_0 should be set.
+ since S390_DFP_ROUND_PER_FPC_0 is also 0, passing m4 is sufficient */
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_dpr_dw0(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, triop(Iop_MulD64, mkexpr(rounding_mode), mkexpr(op1),
+ mkexpr(op2)));
+ s390_cc_thunk_putF(S390_CC_OP_DFP_RESULT_64, result);
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return (m4 == 0) ? "mdtr" : "mdtra";
+}
+
+static HChar *
+s390_irgen_SDTRA(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D64);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp result = newTemp(Ity_D64);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ /* when m4 = 0, S390_DFP_ROUND_PER_FPC_0 should be set.
+ since S390_DFP_ROUND_PER_FPC_0 is also 0, passing m4 is sufficient */
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_dpr_dw0(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, triop(Iop_SubD64, mkexpr(rounding_mode), mkexpr(op1),
+ mkexpr(op2)));
+ s390_cc_thunk_putF(S390_CC_OP_DFP_RESULT_64, result);
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return (m4 == 0) ? "sdtr" : "sdtra";
+}
+
static HChar *
s390_irgen_CLC(UChar length, IRTemp start1, IRTemp start2)
@@ -12530,7 +12660,7 @@
struct {
unsigned int op : 16;
unsigned int r3 : 4;
- unsigned int : 4;
+ unsigned int m4 : 4;
unsigned int r1 : 4;
unsigned int r2 : 4;
} RRF4;
@@ -12982,13 +13112,22 @@
case 0xb3ca: /* CGXR */ goto unimplemented;
case 0xb3cd: s390_format_RRE_RF(s390_irgen_LGDR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
- case 0xb3d0: /* MDTR */ goto unimplemented;
- case 0xb3d1: /* DDTR */ goto unimplemented;
- case 0xb3d2: /* ADTR */ goto unimplemented;
- case 0xb3d3: /* SDTR */ goto unimplemented;
+ case 0xb3d0: s390_format_RRF_FUFF2(s390_irgen_MDTRA, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
+ case 0xb3d1: s390_format_RRF_FUFF2(s390_irgen_DDTRA, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
+ case 0xb3d2: s390_format_RRF_FUFF2(s390_irgen_ADTRA, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
+ case 0xb3d3: s390_format_RRF_FUFF2(s390_irgen_SDTRA, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
case 0xb3d4: /* LDETR */ goto unimplemented;
case 0xb3d5: /* LEDTR */ goto unimplemented;
- case 0xb3d6: /* LTDTR */ goto unimplemented;
+ case 0xb3d6: s390_format_RRE_FF(s390_irgen_LTDTR, ovl.fmt.RRE.r1,
+ ovl.fmt.RRE.r2); goto ok;
case 0xb3d7: /* FIDTR */ goto unimplemented;
case 0xb3d8: /* MXTR */ goto unimplemented;
case 0xb3d9: /* DXTR */ goto unimplemented;