]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add support for binary DFP operations (64-bit).
authorFlorian Krohm <florian@eich-krohm.de>
Sat, 10 Nov 2012 22:34:14 +0000 (22:34 +0000)
committerFlorian Krohm <florian@eich-krohm.de>
Sat, 10 Nov 2012 22:34:14 +0000 (22:34 +0000)
Patch by Maran (maranp@linux.vnet.ibm.com).
Part of fixing BZ 307113.

git-svn-id: svn://svn.valgrind.org/vex/trunk@2560

VEX/priv/guest_s390_defs.h
VEX/priv/guest_s390_helpers.c
VEX/priv/guest_s390_toIR.c
VEX/priv/host_s390_defs.c
VEX/priv/host_s390_defs.h
VEX/priv/host_s390_isel.c

index f28151c454955bba8d5993996057ceed8348d9a4..3e18b8441229c26dc50f2a35f668423cd72c9718 100644 (file)
@@ -135,7 +135,8 @@ enum {
    S390_CC_OP_BFP_128_TO_UINT_32 = 38,
    S390_CC_OP_BFP_32_TO_UINT_64 = 39,
    S390_CC_OP_BFP_64_TO_UINT_64 = 40,
-   S390_CC_OP_BFP_128_TO_UINT_64 = 41
+   S390_CC_OP_BFP_128_TO_UINT_64 = 41,
+   S390_CC_OP_DFP_RESULT_64 = 42
 };
 
 /*------------------------------------------------------------*/
index eaddd29342c7599911cd6dbc9cb310167f719c96..d4f31da5d61be85252b44eeb3efc4b759d9ce7af 100644 (file)
@@ -1116,6 +1116,16 @@ decode_bfp_rounding_mode(UInt irrm)
    psw >> 28;   /* cc */ \
 })
 
+#define S390_CC_FOR_DFP_RESULT(cc_dep1) \
+({ \
+   __asm__ volatile ( \
+        ".insn rre, 0xb3d60000,0,%[op]\n\t"              /* LTDTR */ \
+        "ipm %[psw]\n\t"           : [psw] "=d"(psw) \
+                                   : [op]  "f"(cc_dep1) \
+                                   : "cc", "f0"); \
+   psw >> 28;   /* cc */ \
+})
+
 
 /* Return the value of the condition code from the supplied thunk parameters.
    This is not the value of the PSW. It is the value of the 2 CC bits within
@@ -1332,6 +1342,8 @@ s390_calculate_cc(ULong cc_op, ULong cc_dep1, ULong cc_dep2, ULong cc_ndep)
       return S390_CC_FOR_BFP128_UCONVERT(".insn rrf,0xb3ae0000", cc_dep1,
                                          cc_dep2, cc_ndep);
 
+   case S390_CC_OP_DFP_RESULT_64:
+      return S390_CC_FOR_DFP_RESULT(cc_dep1);
 
    default:
       break;
index 07486853c8081e875fc5a58f5998ccbba399e63a..64a01b7f82e60544c057dc6cba9cb0da633e3c44 100644 (file)
@@ -427,6 +427,8 @@ yield_if(IRExpr *condition)
 
 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 @@ get_fpr_dw0(UInt archreg)
    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 @@ encode_bfp_rounding_mode(UChar mode)
 
    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 @@ encode_dfp_rounding_mode(UChar mode)
 
    return mktemp(Ity_I32, rm);
 }
-#endif
+
 
 /*------------------------------------------------------------*/
 /*--- Build IR for formats                                 ---*/
@@ -1906,6 +1922,16 @@ s390_format_RRF_F0FF2(HChar *(*irgen)(UChar, UChar, UChar),
       s390_disasm(ENC4(MNM, FPR, FPR, FPR), mnm, r1, r3, r2);
 }
 
+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)
@@ -8849,6 +8875,18 @@ s390_irgen_LEDBR(UChar m3, UChar m4 __attribute__((unused)),
    return "ledbr";
 }
 
+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)
 {
@@ -8990,6 +9028,98 @@ s390_irgen_SDB(UChar r1, IRTemp op2addr)
    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 @@ s390_decode_4byte_and_irgen(UChar *bytes)
       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 @@ s390_decode_4byte_and_irgen(UChar *bytes)
    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;
index 6fb6d0bbd1ee4ec7817610a420a151fcf161f606..061b7e7a34d63bdca64c26c1b31eec755a3180f9 100644 (file)
@@ -703,6 +703,17 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn)
          addHRegUse(u, HRmRead, insn->variant.bfp_convert.op_lo);
       break;
 
+   case S390_INSN_DFP_BINOP:
+      addHRegUse(u, HRmWrite, insn->variant.dfp_binop.dst_hi);
+      addHRegUse(u, HRmRead,  insn->variant.dfp_binop.op2_hi);  /* left */
+      addHRegUse(u, HRmRead,  insn->variant.dfp_binop.op3_hi);  /* right */
+      if (insn->size == 16) {
+         addHRegUse(u, HRmWrite, insn->variant.dfp_binop.dst_lo);
+         addHRegUse(u, HRmRead,  insn->variant.dfp_binop.op2_lo);  /* left */
+         addHRegUse(u, HRmRead,  insn->variant.dfp_binop.op3_lo);  /* right */
+      }
+      break;
+
    case S390_INSN_MFENCE:
    case S390_INSN_GZERO:
    case S390_INSN_GADD:
@@ -935,6 +946,23 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn)
             lookupHRegRemap(m, insn->variant.bfp_convert.op_lo);
       break;
 
+   case S390_INSN_DFP_BINOP:
+      insn->variant.dfp_binop.dst_hi =
+         lookupHRegRemap(m, insn->variant.dfp_binop.dst_hi);
+      insn->variant.dfp_binop.op2_hi =
+         lookupHRegRemap(m, insn->variant.dfp_binop.op2_hi);
+      insn->variant.dfp_binop.op3_hi =
+         lookupHRegRemap(m, insn->variant.dfp_binop.op3_hi);
+      if (insn->size == 16) {
+         insn->variant.dfp_binop.dst_lo =
+            lookupHRegRemap(m, insn->variant.dfp_binop.dst_lo);
+         insn->variant.dfp_binop.op2_lo  =
+            lookupHRegRemap(m, insn->variant.dfp_binop.op2_lo);
+         insn->variant.dfp_binop.op3_lo  =
+            lookupHRegRemap(m, insn->variant.dfp_binop.op3_lo);
+      }
+      break;
+
    case S390_INSN_MFENCE:
    case S390_INSN_GZERO:
    case S390_INSN_GADD:
@@ -1115,6 +1143,20 @@ emit_RRF3(UChar *p, UInt op, UChar r3, UChar r1, UChar r2)
 }
 
 
+static UChar *
+emit_RRF4(UChar *p, UInt op, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   ULong the_insn = op;
+
+   the_insn |= ((ULong)r3) << 12;
+   the_insn |= ((ULong)m4) << 8;
+   the_insn |= ((ULong)r1) << 4;
+   the_insn |= ((ULong)r2) << 0;
+
+   return emit_4bytes(p, the_insn);
+}
+
+
 static UChar *
 emit_RS(UChar *p, UInt op, UChar r1, UChar r3, UChar b2, UShort d2)
 {
@@ -3830,6 +3872,69 @@ s390_emit_SXBR(UChar *p, UChar r1, UChar r2)
 }
 
 
+static UChar *
+s390_emit_ADTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   vassert(m4 == 0 || s390_host_has_fpext);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+      if (m4 == 0)
+         s390_disasm(ENC4(MNM, FPR, FPR, FPR), "adtr", r1, r2, r3);
+      else
+         s390_disasm(ENC5(MNM, FPR, UINT, FPR, FPR), "adtra", r1, m4, r2, r3);
+   }
+
+   return emit_RRF4(p, 0xb3d20000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_DDTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   vassert(m4 == 0 || s390_host_has_fpext);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+      if (m4 == 0)
+         s390_disasm(ENC4(MNM, FPR, FPR, FPR), "ddtr", r1, r2, r3);
+      else
+         s390_disasm(ENC5(MNM, FPR, UINT, FPR, FPR), "ddtra", r1, m4, r2, r3);
+   }
+
+   return emit_RRF4(p, 0xb3d10000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_MDTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   vassert(m4 == 0 || s390_host_has_fpext);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+      if (m4 == 0)
+         s390_disasm(ENC4(MNM, FPR, FPR, FPR), "mdtr", r1, r2, r3);
+      else
+         s390_disasm(ENC5(MNM, FPR, UINT, FPR, FPR), "mdtra", r1, m4, r2, r3);
+   }
+
+   return emit_RRF4(p, 0xb3d00000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_SDTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   vassert(m4 == 0 || s390_host_has_fpext);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+      if (m4 == 0)
+         s390_disasm(ENC4(MNM, FPR, FPR, FPR), "sdtr", r1, r2, r3);
+      else
+         s390_disasm(ENC5(MNM, FPR, UINT, FPR, FPR), "sdtra", r1, m4, r2, r3);
+   }
+
+   return emit_RRF4(p, 0xb3d30000, r3, m4, r1, r2);
+}
+
 /* Provide a symbolic name for register "R0" */
 #define R0 0
 
@@ -4900,6 +5005,29 @@ s390_insn_bfp128_convert_from(UChar size, s390_conv_t tag, HReg dst,
 }
 
 
+s390_insn *
+s390_insn_dfp_binop(UChar size, s390_dfp_binop_t tag, HReg dst, HReg op2,
+                    HReg op3, s390_dfp_round_t rounding_mode)
+{
+   s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
+
+   vassert(size == 8);
+
+   insn->tag  = S390_INSN_DFP_BINOP;
+   insn->size = size;
+   insn->variant.dfp_binop.tag = tag;
+   insn->variant.dfp_binop.dst_hi = dst;
+   insn->variant.dfp_binop.op2_hi = op2;
+   insn->variant.dfp_binop.op3_hi = op3;
+   insn->variant.dfp_binop.dst_lo = INVALID_HREG;
+   insn->variant.dfp_binop.op2_lo = INVALID_HREG;
+   insn->variant.dfp_binop.op3_lo = INVALID_HREG;
+   insn->variant.dfp_binop.rounding_mode = rounding_mode;
+
+   return insn;
+}
+
+
 s390_insn *
 s390_insn_mfence(void)
 {
@@ -5460,6 +5588,20 @@ s390_insn_as_string(const s390_insn *insn)
                    insn->variant.bfp_convert.op_hi);
       break;
 
+   case S390_INSN_DFP_BINOP:
+      switch (insn->variant.dfp_binop.tag) {
+      case S390_DFP_ADD:  op = "v-dadd";  break;
+      case S390_DFP_SUB:  op = "v-dsub";  break;
+      case S390_DFP_MUL:  op = "v-dmul";  break;
+      case S390_DFP_DIV:  op = "v-ddiv";  break;
+      default: goto fail;
+      }
+      s390_sprintf(buf, "%M %R,%R,%R", op,
+                   insn->variant.dfp_binop.dst_hi,
+                   insn->variant.dfp_binop.op2_hi,
+                   insn->variant.dfp_binop.op3_hi);
+      break;
+
    case S390_INSN_MFENCE:
       s390_sprintf(buf, "%M", "v-mfence");
       return buf;   /* avoid printing "size = ..." which is meaningless */
@@ -7522,6 +7664,32 @@ s390_insn_bfp_compare_emit(UChar *buf, const s390_insn *insn)
 }
 
 
+static UChar *
+s390_insn_dfp_binop_emit(UChar *buf, const s390_insn *insn)
+{
+   UInt r1 = hregNumber(insn->variant.dfp_binop.dst_hi);
+   UInt r2 = hregNumber(insn->variant.dfp_binop.op2_hi);
+   UInt r3 = hregNumber(insn->variant.dfp_binop.op3_hi);
+   UInt m4 = hregNumber(insn->variant.dfp_binop.rounding_mode);
+
+   switch (insn->size) {
+   case 8:
+      switch (insn->variant.dfp_binop.tag) {
+      case S390_DFP_ADD: return s390_emit_ADTRA(buf, r3, m4, r1, r2); break;
+      case S390_DFP_SUB: return s390_emit_SDTRA(buf, r3, m4, r1, r2); break;
+      case S390_DFP_MUL: return s390_emit_MDTRA(buf, r3, m4, r1, r2); break;
+      case S390_DFP_DIV: return s390_emit_DDTRA(buf, r3, m4, r1, r2); break;
+      default:  goto fail;
+      }
+      break;
+   default:  goto fail;
+   }
+
+ fail:
+   vpanic("s390_insn_dfp_binop_emit");
+}
+
+
 static UChar *
 s390_insn_mfence_emit(UChar *buf, const s390_insn *insn)
 {
@@ -8111,6 +8279,10 @@ emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, s390_insn *insn,
       end = s390_insn_bfp_convert_emit(buf, insn);
       break;
 
+   case S390_INSN_DFP_BINOP:
+      end = s390_insn_dfp_binop_emit(buf, insn);
+      break;
+
    case S390_INSN_MFENCE:
       end = s390_insn_mfence_emit(buf, insn);
       break;
index d8f7dd6619d858e1956cdb81111a40ab7fa8a84f..d123f706dc03903ea5245a5f5cd576ffb43639c1 100644 (file)
@@ -137,6 +137,7 @@ typedef enum {
    S390_INSN_BFP_TRIOP,
    S390_INSN_BFP_COMPARE,
    S390_INSN_BFP_CONVERT,
+   S390_INSN_DFP_BINOP, /* Decimal floating point */
    S390_INSN_MFENCE,
    S390_INSN_GZERO,   /* Assign zero to a guest register */
    S390_INSN_GADD,    /* Add a value to a guest register */
@@ -233,6 +234,15 @@ typedef enum {
 } s390_conv_t;
 
 
+/* The kind of binary DFP operations */
+typedef enum {
+   S390_DFP_ADD,
+   S390_DFP_SUB,
+   S390_DFP_MUL,
+   S390_DFP_DIV
+} s390_dfp_binop_t;
+
+
 /* Condition code. The encoding of the enumerators matches the value of
    the mask field in the various branch opcodes. */
 typedef enum {
@@ -487,6 +497,16 @@ typedef struct {
          HReg         op2_hi;  /* 128-bit operand high part; 32/64-bit opnd */
          HReg         op2_lo;  /* 128-bit operand low part */
       } bfp_compare;
+      struct {
+         s390_dfp_binop_t tag;
+         HReg         dst_hi; /* 128-bit result high part; 64-bit result */
+         HReg         dst_lo; /* 128-bit result low part */
+         HReg         op2_hi; /* 128-bit operand high part; 64-bit opnd 1 */
+         HReg         op2_lo; /* 128-bit operand low part */
+         HReg         op3_hi; /* 128-bit operand high part; 64-bit opnd 2 */
+         HReg         op3_lo; /* 128-bit operand low part */
+         s390_dfp_round_t rounding_mode;
+      } dfp_binop;
 
       /* Miscellaneous */
       struct {
@@ -592,6 +612,9 @@ s390_insn *s390_insn_bfp128_convert_to(UChar size, s390_conv_t,
 s390_insn *s390_insn_bfp128_convert_from(UChar size, s390_conv_t,
                                          HReg dst, HReg op_hi, HReg op_lo,
                                          s390_bfp_round_t);
+s390_insn *s390_insn_dfp_binop(UChar size, s390_dfp_binop_t, HReg dst,
+                               HReg op2, HReg op3,
+                               s390_dfp_round_t rounding_mode);
 s390_insn *s390_insn_mfence(void);
 s390_insn *s390_insn_gzero(UChar size, UInt offset);
 s390_insn *s390_insn_gadd(UChar size, UInt offset, UChar delta, ULong value);
index 6a958d1431f4376c977e5ce89714b51fa5ba14ae..1d0ea6f669179f1c57933cd0c5bbbaa9b2837ca9 100644 (file)
@@ -135,6 +135,7 @@ static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
 static void          s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
 static HReg          s390_isel_float_expr(ISelEnv *, IRExpr *);
 static void          s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
+static HReg          s390_isel_dfp_expr(ISelEnv *, IRExpr *);
 
 
 static Int
@@ -615,7 +616,6 @@ get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
 /* Set the DFP rounding mode in the FPC. This function is called for
    all non-conversion DFP instructions as those will always get the
    rounding mode from the FPC. */
-#if 0  // fixs390: avoid compiler warnings about unused function
 static void
 set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
 {
@@ -725,7 +725,6 @@ get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
    set_dfp_rounding_mode_in_fpc(env, irrm);
    return S390_DFP_ROUND_PER_FPC_0;
 }
-#endif
 
 /* CC_S390 holds the condition code in s390 encoding. Convert it to
    VEX encoding
@@ -2222,6 +2221,107 @@ s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
 }
 
 
+/*---------------------------------------------------------*/
+/*--- ISEL: Decimal point expressions (64 bit)          ---*/
+/*---------------------------------------------------------*/
+
+static HReg
+s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
+{
+   IRType ty = typeOfIRExpr(env->type_env, expr);
+   UChar size;
+
+   vassert(ty == Ity_D64);
+
+   size = sizeofIRType(ty);
+
+   switch (expr->tag) {
+   case Iex_RdTmp:
+      /* Return the virtual register that holds the temporary. */
+      return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
+
+      /* --------- LOAD --------- */
+   case Iex_Load: {
+      HReg        dst = newVRegF(env);
+      s390_amode *am  = s390_isel_amode(env, expr->Iex.Load.addr);
+
+      if (expr->Iex.Load.end != Iend_BE)
+         goto irreducible;
+
+      addInstr(env, s390_insn_load(size, dst, am));
+
+      return dst;
+   }
+
+      /* --------- GET --------- */
+   case Iex_Get: {
+      HReg dst = newVRegF(env);
+      s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
+
+      addInstr(env, s390_insn_load(size, dst, am));
+
+      return dst;
+   }
+
+      /* --------- TERNARY OP --------- */
+   case Iex_Triop: {
+      IRTriop *triop = expr->Iex.Triop.details;
+      IROp    op     = triop->op;
+      IRExpr *irrm   = triop->arg1;
+      IRExpr *left   = triop->arg2;
+      IRExpr *right  = triop->arg3;
+      s390_dfp_round_t rounding_mode;
+      s390_dfp_binop_t dfpop;
+      HReg op2, op3, dst;
+
+      op2  = s390_isel_dfp_expr(env, left);  /* Process 1st operand */
+      op3  = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
+      dst  = newVRegF(env);
+      switch (op) {
+      case Iop_AddD64:  dfpop = S390_DFP_ADD; break;
+      case Iop_SubD64:  dfpop = S390_DFP_SUB; break;
+      case Iop_MulD64:  dfpop = S390_DFP_MUL; break;
+      case Iop_DivD64:  dfpop = S390_DFP_DIV; break;
+      default:
+         goto irreducible;
+      }
+      /* DFP binary ops have insns with rounding mode field
+         when the floating point extension facility is installed. */
+      if (s390_host_has_fpext) {
+         rounding_mode = get_dfp_rounding_mode(env, irrm);
+      } else {
+         set_dfp_rounding_mode_in_fpc(env, irrm);
+         rounding_mode = S390_DFP_ROUND_PER_FPC_0;
+      }
+
+      addInstr(env,
+               s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
+      return dst;
+   }
+
+   default:
+      goto irreducible;
+   }
+
+   /* We get here if no pattern matched. */
+ irreducible:
+   ppIRExpr(expr);
+   vpanic("s390_isel_dfp_expr: cannot reduce tree");
+}
+
+static HReg
+s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
+{
+   HReg dst = s390_isel_dfp_expr_wrk(env, expr);
+
+   /* Sanity checks ... */
+   vassert(hregClass(dst) == HRcFlt64);
+   vassert(hregIsVirtual(dst));
+
+   return dst;
+}
+
+
 /*---------------------------------------------------------*/
 /*--- ISEL: Condition Code                              ---*/
 /*---------------------------------------------------------*/
@@ -2601,6 +2701,10 @@ s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
          /* Does not occur. See function put_fpr_pair. */
          vpanic("Ist_Put with F128 data");
 
+      case Ity_D64:
+         src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
+         break;
+
       default:
          goto stmt_fail;
       }
@@ -2659,6 +2763,11 @@ s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
          return;
       }
 
+      case Ity_D64:
+         src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
+         dst = lookupIRTemp(env, tmp);
+         break;
+
       default:
          goto stmt_fail;
       }
@@ -3024,6 +3133,7 @@ iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
 
       case Ity_F32:
       case Ity_F64:
+      case Ity_D64:
          hreg = mkHReg(j++, HRcFlt64, True);
          break;