]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390: Support the following DFP insns:
authorFlorian Krohm <florian@eich-krohm.de>
Thu, 14 Feb 2013 14:27:12 +0000 (14:27 +0000)
committerFlorian Krohm <florian@eich-krohm.de>
Thu, 14 Feb 2013 14:27:12 +0000 (14:27 +0000)
- extract basied exponent
- insert biased exponent
- quantize
- reround to significance
Patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com).
Part of fixing BZ #307113.

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

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 f1fc84909853c8ac738eadfc3a438580f17b8557..b013e192bdc6e90a431d2ebf4d23c3c09a51bcae 100644 (file)
@@ -2015,6 +2015,16 @@ s390_format_RRF_F0FF(const HChar *(*irgen)(UChar, UChar, UChar),
       s390_disasm(ENC4(MNM, FPR, FPR, FPR), mnm, r1, r3, r2);
 }
 
+static void
+s390_format_RRF_F0FR(const HChar *(*irgen)(UChar, UChar, UChar),
+                     UChar r3, UChar r1, UChar r2)
+{
+   const HChar *mnm = irgen(r3, r1, r2);
+
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+      s390_disasm(ENC4(MNM, FPR, FPR, GPR), mnm, r1, r3, r2);
+}
+
 static void
 s390_format_RRF_UUFF(const HChar *(*irgen)(UChar m3, UChar m4, UChar r1,
                                            UChar r2),
@@ -2079,6 +2089,26 @@ s390_format_RRF_F0FF2(const HChar *(*irgen)(UChar, UChar, UChar),
       s390_disasm(ENC4(MNM, FPR, FPR, FPR), mnm, r1, r3, r2);
 }
 
+static void
+s390_format_RRF_FFRU(const HChar *(*irgen)(UChar, UChar, UChar, UChar),
+                     UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   const HChar *mnm = irgen(r3, m4, r1, r2);
+
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+      s390_disasm(ENC5(MNM, FPR, FPR, GPR, UINT), mnm, r1, r3, r2, m4);
+}
+
+static void
+s390_format_RRF_FUFF(const HChar *(*irgen)(UChar, UChar, UChar, UChar),
+                     UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   const HChar *mnm = irgen(r3, m4, r1, r2);
+
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+      s390_disasm(ENC5(MNM, FPR, FPR, FPR, UINT), mnm, r1, r3, r2, m4);
+}
+
 static void
 s390_format_RRF_FUFF2(const HChar *(*irgen)(UChar, UChar, UChar, UChar),
                       UChar r3, UChar m4, UChar r1, UChar r2)
@@ -9712,6 +9742,24 @@ s390_irgen_DXTRA(UChar r3, UChar m4, UChar r1, UChar r2)
    return (m4 == 0) ? "dxtr" : "dxtra";
 }
 
+static const HChar *
+s390_irgen_EEDTR(UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+
+   put_gpr_dw0(r1, unop(Iop_ExtractExpD64, get_dpr_dw0(r2)));
+   return "eedtr";
+}
+
+static const HChar *
+s390_irgen_EEXTR(UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+
+   put_gpr_dw0(r1, unop(Iop_ExtractExpD128, get_dpr_pair(r2)));
+   return "eextr";
+}
+
 static const HChar *
 s390_irgen_ESDTR(UChar r1, UChar r2)
 {
@@ -9728,6 +9776,40 @@ s390_irgen_ESXTR(UChar r1, UChar r2)
    return "esxtr";
 }
 
+static const HChar *
+s390_irgen_IEDTR(UChar r3, UChar r1, UChar r2)
+{
+   IRTemp op1 = newTemp(Ity_I64);
+   IRTemp op2 = newTemp(Ity_D64);
+   IRTemp result = newTemp(Ity_D64);
+
+   vassert(s390_host_has_dfp);
+
+   assign(op1, get_gpr_dw0(r2));
+   assign(op2, get_dpr_dw0(r3));
+   assign(result, binop(Iop_InsertExpD64, mkexpr(op1), mkexpr(op2)));
+   put_dpr_dw0(r1, mkexpr(result));
+
+   return "iedtr";
+}
+
+static const HChar *
+s390_irgen_IEXTR(UChar r3, UChar r1, UChar r2)
+{
+   IRTemp op1 = newTemp(Ity_I64);
+   IRTemp op2 = newTemp(Ity_D128);
+   IRTemp result = newTemp(Ity_D128);
+
+   vassert(s390_host_has_dfp);
+
+   assign(op1, get_gpr_dw0(r2));
+   assign(op2, get_dpr_pair(r3));
+   assign(result, binop(Iop_InsertExpD128, mkexpr(op1), mkexpr(op2)));
+   put_dpr_pair(r1, mkexpr(result));
+
+   return "iextr";
+}
+
 static const HChar *
 s390_irgen_LDETR(UChar m4 __attribute__((unused)), UChar r1, UChar r2)
 {
@@ -9868,6 +9950,110 @@ s390_irgen_MXTRA(UChar r3, UChar m4, UChar r1, UChar r2)
    return (m4 == 0) ? "mxtr" : "mxtra";
 }
 
+static const HChar *
+s390_irgen_QADTR(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);
+   /* If fpext is not installed and m4 is in 1:7,
+      rounding mode performed is unpredictable */
+   if (! s390_host_has_fpext && m4 > 0 && m4 < 8) {
+      emulation_warning(EmWarn_S390X_fpext_rounding);
+      m4 = S390_DFP_ROUND_PER_FPC_0;
+   }
+
+   rounding_mode = encode_dfp_rounding_mode(m4);
+   assign(op1, get_dpr_dw0(r2));
+   assign(op2, get_dpr_dw0(r3));
+   assign(result, triop(Iop_QuantizeD64, mkexpr(rounding_mode), mkexpr(op1),
+                        mkexpr(op2)));
+   put_dpr_dw0(r1, mkexpr(result));
+
+   return "qadtr";
+}
+
+static const HChar *
+s390_irgen_QAXTR(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   IRTemp op1 = newTemp(Ity_D128);
+   IRTemp op2 = newTemp(Ity_D128);
+   IRTemp result = newTemp(Ity_D128);
+   IRTemp rounding_mode;
+
+   vassert(s390_host_has_dfp);
+   /* If fpext is not installed and m4 is in 1:7,
+      rounding mode performed is unpredictable */
+   if (! s390_host_has_fpext && m4 > 0 && m4 < 8) {
+      emulation_warning(EmWarn_S390X_fpext_rounding);
+      m4 = S390_DFP_ROUND_PER_FPC_0;
+   }
+
+   rounding_mode = encode_dfp_rounding_mode(m4);
+   assign(op1, get_dpr_pair(r2));
+   assign(op2, get_dpr_pair(r3));
+   assign(result, triop(Iop_QuantizeD128, mkexpr(rounding_mode), mkexpr(op1),
+                        mkexpr(op2)));
+   put_dpr_pair(r1, mkexpr(result));
+
+   return "qaxtr";
+}
+
+static const HChar *
+s390_irgen_RRDTR(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   IRTemp op1 = newTemp(Ity_I8);
+   IRTemp op2 = newTemp(Ity_D64);
+   IRTemp result = newTemp(Ity_D64);
+   IRTemp rounding_mode;
+
+   vassert(s390_host_has_dfp);
+   /* If fpext is not installed and m4 is in 1:7,
+      rounding mode performed is unpredictable */
+   if (! s390_host_has_fpext && m4 > 0 && m4 < 8) {
+      emulation_warning(EmWarn_S390X_fpext_rounding);
+      m4 = S390_DFP_ROUND_PER_FPC_0;
+   }
+
+   rounding_mode = encode_dfp_rounding_mode(m4);
+   assign(op1, get_gpr_b7(r2));
+   assign(op2, get_dpr_dw0(r3));
+   assign(result, triop(Iop_SignificanceRoundD64, mkexpr(rounding_mode),
+                        mkexpr(op1), mkexpr(op2)));
+   put_dpr_dw0(r1, mkexpr(result));
+
+   return "rrdtr";
+}
+
+static const HChar *
+s390_irgen_RRXTR(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   IRTemp op1 = newTemp(Ity_I8);
+   IRTemp op2 = newTemp(Ity_D128);
+   IRTemp result = newTemp(Ity_D128);
+   IRTemp rounding_mode;
+
+   vassert(s390_host_has_dfp);
+   /* If fpext is not installed and m4 is in 1:7,
+      rounding mode performed is unpredictable */
+   if (! s390_host_has_fpext && m4 > 0 && m4 < 8) {
+      emulation_warning(EmWarn_S390X_fpext_rounding);
+      m4 = S390_DFP_ROUND_PER_FPC_0;
+   }
+
+   rounding_mode = encode_dfp_rounding_mode(m4);
+   assign(op1, get_gpr_b7(r2));
+   assign(op2, get_dpr_pair(r3));
+   assign(result, triop(Iop_SignificanceRoundD128, mkexpr(rounding_mode),
+                        mkexpr(op1), mkexpr(op2)));
+   put_dpr_pair(r1, mkexpr(result));
+
+   return "rrxtr";
+}
+
 static const HChar *
 s390_irgen_SDTRA(UChar r3, UChar m4, UChar r1, UChar r2)
 {
@@ -14077,7 +14263,8 @@ s390_decode_4byte_and_irgen(UChar *bytes)
    case 0xb3e3: /* CSDTR */ goto unimplemented;
    case 0xb3e4: s390_format_RRE_FF(s390_irgen_CDTR, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
-   case 0xb3e5: /* EEDTR */ goto unimplemented;
+   case 0xb3e5: s390_format_RRE_RF(s390_irgen_EEDTR, ovl.fmt.RRE.r1,
+                                   ovl.fmt.RRE.r2);  goto ok;
    case 0xb3e7: s390_format_RRE_RF(s390_irgen_ESDTR, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
    case 0xb3e8: /* KXTR */ goto unimplemented;
@@ -14088,7 +14275,8 @@ s390_decode_4byte_and_irgen(UChar *bytes)
    case 0xb3eb: /* CSXTR */ goto unimplemented;
    case 0xb3ec: s390_format_RRE_FF(s390_irgen_CXTR, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
-   case 0xb3ed: /* EEXTR */ goto unimplemented;
+   case 0xb3ed: s390_format_RRE_RF(s390_irgen_EEXTR, ovl.fmt.RRE.r1,
+                                   ovl.fmt.RRE.r2);  goto ok;
    case 0xb3ef: s390_format_RRE_RF(s390_irgen_ESXTR, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
    case 0xb3f1: s390_format_RRF_UUFR(s390_irgen_CDGTRA, ovl.fmt.RRF2.m3,
@@ -14098,9 +14286,14 @@ s390_decode_4byte_and_irgen(UChar *bytes)
    case 0xb3f3: /* CDSTR */ goto unimplemented;
    case 0xb3f4: s390_format_RRE_FF(s390_irgen_CEDTR, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
-   case 0xb3f5: /* QADTR */ goto unimplemented;
-   case 0xb3f6: /* IEDTR */ goto unimplemented;
-   case 0xb3f7: /* RRDTR */ goto unimplemented;
+   case 0xb3f5: s390_format_RRF_FUFF(s390_irgen_QADTR, ovl.fmt.RRF4.r3,
+                                     ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+                                     ovl.fmt.RRF4.r2); goto ok;
+   case 0xb3f6: s390_format_RRF_F0FR(s390_irgen_IEDTR, ovl.fmt.RRF3.r3,
+                                     ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2); goto ok;
+   case 0xb3f7: s390_format_RRF_FFRU(s390_irgen_RRDTR, ovl.fmt.RRF4.r3,
+                                     ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+                                     ovl.fmt.RRF4.r2); goto ok;
    case 0xb3f9: s390_format_RRF_UUFR(s390_irgen_CXGTR, ovl.fmt.RRF2.m3,
                                      ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1,
                                      ovl.fmt.RRF2.r2);  goto ok;
@@ -14108,9 +14301,14 @@ s390_decode_4byte_and_irgen(UChar *bytes)
    case 0xb3fb: /* CXSTR */ goto unimplemented;
    case 0xb3fc: s390_format_RRE_FF(s390_irgen_CEXTR, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
-   case 0xb3fd: /* QAXTR */ goto unimplemented;
-   case 0xb3fe: /* IEXTR */ goto unimplemented;
-   case 0xb3ff: /* RRXTR */ goto unimplemented;
+   case 0xb3fd: s390_format_RRF_FUFF(s390_irgen_QAXTR, ovl.fmt.RRF4.r3,
+                                     ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+                                     ovl.fmt.RRF4.r2); goto ok;
+   case 0xb3fe: s390_format_RRF_F0FR(s390_irgen_IEXTR, ovl.fmt.RRF3.r3,
+                                     ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2); goto ok;
+   case 0xb3ff: s390_format_RRF_FFRU(s390_irgen_RRXTR, ovl.fmt.RRF4.r3,
+                                     ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+                                     ovl.fmt.RRF4.r2); goto ok;
    case 0xb900: s390_format_RRE_RR(s390_irgen_LPGR, ovl.fmt.RRE.r1,
                                    ovl.fmt.RRE.r2);  goto ok;
    case 0xb901: s390_format_RRE_RR(s390_irgen_LNGR, ovl.fmt.RRE.r1,
index 9bef0e9e1e0f841cad5f0880d9638a33b2b8aeca..6b3d9b58bce644bd29ce136b225a0ac08da92481 100644 (file)
@@ -765,6 +765,16 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn)
          addHRegUse(u, HRmRead, insn->variant.dfp_convert.op_lo); /* operand */
       break;
 
+   case S390_INSN_DFP_REROUND:
+      addHRegUse(u, HRmWrite, insn->variant.dfp_reround.dst_hi);
+      addHRegUse(u, HRmRead,  insn->variant.dfp_reround.op2);     /* left */
+      addHRegUse(u, HRmRead,  insn->variant.dfp_reround.op3_hi);  /* right */
+      if (insn->size == 16) {
+         addHRegUse(u, HRmWrite, insn->variant.dfp_reround.dst_lo);
+         addHRegUse(u, HRmRead,  insn->variant.dfp_reround.op3_lo); /* right */
+      }
+      break;
+
    case S390_INSN_MIMM:
       s390_amode_get_reg_usage(u, insn->variant.mimm.dst);
       break;
@@ -1083,6 +1093,21 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn)
             lookupHRegRemap(m, insn->variant.dfp_convert.op_lo);
       break;
 
+   case S390_INSN_DFP_REROUND:
+      insn->variant.dfp_reround.dst_hi =
+         lookupHRegRemap(m, insn->variant.dfp_reround.dst_hi);
+      insn->variant.dfp_reround.op2    =
+         lookupHRegRemap(m, insn->variant.dfp_reround.op2);
+      insn->variant.dfp_reround.op3_hi =
+         lookupHRegRemap(m, insn->variant.dfp_reround.op3_hi);
+      if (insn->size == 16) {
+         insn->variant.dfp_reround.dst_lo =
+            lookupHRegRemap(m, insn->variant.dfp_reround.dst_lo);
+         insn->variant.dfp_reround.op3_lo =
+            lookupHRegRemap(m, insn->variant.dfp_reround.op3_lo);
+      }
+      break;
+
    case S390_INSN_MIMM:
       s390_amode_map_regs(m, insn->variant.mimm.dst);
       break;
@@ -4445,6 +4470,26 @@ s390_emit_DXTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
 }
 
 
+static UChar *
+s390_emit_EEDTR(UChar *p, UChar r1, UChar r2)
+{
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC3(MNM, GPR, FPR), "eedtr", r1, r2);
+
+   return emit_RRE(p, 0xb3e50000, r1, r2);
+}
+
+
+static UChar *
+s390_emit_EEXTR(UChar *p, UChar r1, UChar r2)
+{
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC3(MNM, GPR, FPR), "eextr", r1, r2);
+
+   return emit_RRE(p, 0xb3ed0000, r1, r2);
+}
+
+
 static UChar *
 s390_emit_ESDTR(UChar *p, UChar r1, UChar r2)
 {
@@ -4465,6 +4510,26 @@ s390_emit_ESXTR(UChar *p, UChar r1, UChar r2)
 }
 
 
+static UChar *
+s390_emit_IEDTR(UChar *p, UChar r3, UChar r1, UChar r2)
+{
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC4(MNM, FPR, FPR, GPR), "iedtr", r1, r3, r2);
+
+   return emit_RRF(p, 0xb3f60000, r3, r1, r2);
+}
+
+
+static UChar *
+s390_emit_IEXTR(UChar *p, UChar r3, UChar r1, UChar r2)
+{
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC4(MNM, FPR, FPR, GPR), "iextr", r1, r3, r2);
+
+   return emit_RRF(p, 0xb3fe0000, r3, r1, r2);
+}
+
+
 static UChar *
 s390_emit_LDETR(UChar *p, UChar m4, UChar r1, UChar r2)
 {
@@ -4551,6 +4616,50 @@ s390_emit_MXTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
 }
 
 
+static UChar *
+s390_emit_QADTR(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC5(MNM, FPR, FPR, FPR, UINT), "qadtr", r1, r3, r2, m4);
+
+   return emit_RRF4(p, 0xb3f50000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_QAXTR(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC5(MNM, FPR, FPR, FPR, UINT), "qaxtr", r1, r3, r2, m4);
+
+   return emit_RRF4(p, 0xb3fd0000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_RRDTR(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC5(MNM, FPR, FPR, GPR, UINT), "rrdtr", r1, r3, r2, m4);
+
+   return emit_RRF4(p, 0xb3f70000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_RRXTR(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+      s390_disasm(ENC5(MNM, FPR, FPR, GPR, UINT), "rrxtr", r1, r3, r2, m4);
+
+   return emit_RRF4(p, 0xb3ff0000, r3, m4, r1, r2);
+}
+
+
 static UChar *
 s390_emit_SDTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
 {
@@ -5867,6 +5976,27 @@ s390_insn_dfp_convert(UChar size, s390_dfp_conv_t tag, HReg dst, HReg op,
 }
 
 
+s390_insn *
+s390_insn_dfp_reround(UChar size, 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_REROUND;
+   insn->size = size;
+   insn->variant.dfp_reround.dst_hi = dst;
+   insn->variant.dfp_reround.op2 = op2;
+   insn->variant.dfp_reround.op3_hi = op3;
+   insn->variant.dfp_reround.dst_lo = INVALID_HREG;
+   insn->variant.dfp_reround.op3_lo = INVALID_HREG;
+   insn->variant.dfp_reround.rounding_mode = rounding_mode;
+
+   return insn;
+}
+
+
 s390_insn *
 s390_insn_dfp128_binop(UChar size, s390_dfp_binop_t tag, HReg dst_hi,
                        HReg dst_lo, HReg op2_hi, HReg op2_lo, HReg op3_hi,
@@ -6018,6 +6148,30 @@ s390_insn_dfp128_convert_from(UChar size, s390_dfp_conv_t tag, HReg dst,
 }
 
 
+s390_insn *
+s390_insn_dfp128_reround(UChar size, HReg dst_hi, HReg dst_lo, HReg op2,
+                         HReg op3_hi, HReg op3_lo,
+                         s390_dfp_round_t rounding_mode)
+{
+   s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
+
+   vassert(size == 16);
+   vassert(is_valid_fp128_regpair(dst_hi, dst_lo));
+   vassert(is_valid_fp128_regpair(op3_hi, op3_lo));
+
+   insn->tag  = S390_INSN_DFP_REROUND;
+   insn->size = size;
+   insn->variant.dfp_reround.dst_hi = dst_hi;
+   insn->variant.dfp_reround.dst_lo = dst_lo;
+   insn->variant.dfp_reround.op2    = op2;
+   insn->variant.dfp_reround.op3_hi = op3_hi;
+   insn->variant.dfp_reround.op3_lo = op3_lo;
+   insn->variant.dfp_reround.rounding_mode = rounding_mode;
+
+   return insn;
+}
+
+
 s390_insn *
 s390_insn_mfence(void)
 {
@@ -6605,6 +6759,7 @@ s390_insn_as_string(const s390_insn *insn)
       case S390_DFP_SUB:  op = "v-dsub";  break;
       case S390_DFP_MUL:  op = "v-dmul";  break;
       case S390_DFP_DIV:  op = "v-ddiv";  break;
+      case S390_DFP_QUANTIZE:  op = "v-dqua";  break;
       default: goto fail;
       }
       s390_sprintf(buf, "%M %R,%R,%R", op, dfp_binop->dst_hi,
@@ -6614,6 +6769,8 @@ s390_insn_as_string(const s390_insn *insn)
 
    case S390_INSN_DFP_UNOP:
       switch (insn->variant.dfp_unop.tag) {
+      case S390_DFP_EXTRACT_EXP_D64:
+      case S390_DFP_EXTRACT_EXP_D128:  op = "v-d2exp";  break;
       case S390_DFP_EXTRACT_SIG_D64:
       case S390_DFP_EXTRACT_SIG_D128:  op = "v-d2sig";  break;
       default: goto fail;
@@ -6626,6 +6783,7 @@ s390_insn_as_string(const s390_insn *insn)
       switch (insn->variant.dfp_intop.tag) {
       case S390_DFP_SHIFT_LEFT:  op = "v-dshl"; break;
       case S390_DFP_SHIFT_RIGHT: op = "v-dshr"; break;
+      case S390_DFP_INSERT_EXP:  op = "v-diexp"; break;
       default: goto fail;
       }
       s390_sprintf(buf, "%M %R,%R,%R", op, insn->variant.dfp_intop.dst_hi,
@@ -6672,6 +6830,13 @@ s390_insn_as_string(const s390_insn *insn)
                    insn->variant.dfp_convert.op_hi);
       break;
 
+   case S390_INSN_DFP_REROUND:
+      s390_sprintf(buf, "%M %R,%R,%R", "v-drrnd",
+                   insn->variant.dfp_reround.dst_hi,
+                   insn->variant.dfp_reround.op2,
+                   insn->variant.dfp_reround.op3_hi);
+      break;
+
    case S390_INSN_MFENCE:
       s390_sprintf(buf, "%M", "v-mfence");
       return buf;   /* avoid printing "size = ..." which is meaningless */
@@ -8844,6 +9009,7 @@ s390_insn_dfp_binop_emit(UChar *buf, const s390_insn *insn)
       case S390_DFP_SUB: return s390_emit_SDTRA(buf, r3, m4, r1, r2);
       case S390_DFP_MUL: return s390_emit_MDTRA(buf, r3, m4, r1, r2);
       case S390_DFP_DIV: return s390_emit_DDTRA(buf, r3, m4, r1, r2);
+      case S390_DFP_QUANTIZE: return s390_emit_QADTR(buf, r3, m4, r1, r2);
       default:  goto fail;
       }
       break;
@@ -8854,6 +9020,7 @@ s390_insn_dfp_binop_emit(UChar *buf, const s390_insn *insn)
       case S390_DFP_SUB:     return s390_emit_SXTRA(buf, r3, m4, r1, r2);
       case S390_DFP_MUL:     return s390_emit_MXTRA(buf, r3, m4, r1, r2);
       case S390_DFP_DIV:     return s390_emit_DXTRA(buf, r3, m4, r1, r2);
+      case S390_DFP_QUANTIZE: return s390_emit_QAXTR(buf, r3, m4, r1, r2);
       default:  goto fail;
       }
       break;
@@ -8866,6 +9033,28 @@ s390_insn_dfp_binop_emit(UChar *buf, const s390_insn *insn)
 }
 
 
+static UChar *
+s390_insn_dfp_reround_emit(UChar *buf, const s390_insn *insn)
+{
+   UInt r1 = hregNumber(insn->variant.dfp_reround.dst_hi);
+   UInt r2 = hregNumber(insn->variant.dfp_reround.op2);
+   UInt r3 = hregNumber(insn->variant.dfp_reround.op3_hi);
+   s390_dfp_round_t m4 = insn->variant.dfp_reround.rounding_mode;
+
+   switch (insn->size) {
+   case 8:
+      return s390_emit_RRDTR(buf, r3, m4, r1, r2);
+
+   case 16:
+      return s390_emit_RRXTR(buf, r3, m4, r1, r2);
+
+   default: goto fail;
+   }
+ fail:
+   vpanic("s390_insn_dfp_reround_emit");
+}
+
+
 static UChar *
 s390_insn_dfp_unop_emit(UChar *buf, const s390_insn *insn)
 {
@@ -8873,6 +9062,8 @@ s390_insn_dfp_unop_emit(UChar *buf, const s390_insn *insn)
    UInt  r2 = hregNumber(insn->variant.dfp_unop.op_hi);
 
    switch (insn->variant.dfp_unop.tag) {
+   case S390_DFP_EXTRACT_EXP_D64:  return s390_emit_EEDTR(buf, r1, r2); break;
+   case S390_DFP_EXTRACT_EXP_D128: return s390_emit_EEXTR(buf, r1, r2); break;
    case S390_DFP_EXTRACT_SIG_D64:  return s390_emit_ESDTR(buf, r1, r2); break;
    case S390_DFP_EXTRACT_SIG_D128: return s390_emit_ESXTR(buf, r1, r2); break;
    default: goto fail;
@@ -8894,6 +9085,7 @@ s390_insn_dfp_intop_emit(UChar *buf, const s390_insn *insn)
       switch (insn->variant.dfp_intop.tag) {
       case S390_DFP_SHIFT_LEFT:  return s390_emit_SLDT(buf, r3, r1, r2);
       case S390_DFP_SHIFT_RIGHT: return s390_emit_SRDT(buf, r3, r1, r2);
+      case S390_DFP_INSERT_EXP:  return s390_emit_IEDTR(buf, r3, r1, r2);
       default:  goto fail;
       }
       break;
@@ -8902,6 +9094,7 @@ s390_insn_dfp_intop_emit(UChar *buf, const s390_insn *insn)
       switch (insn->variant.dfp_intop.tag) {
       case S390_DFP_SHIFT_LEFT:  return s390_emit_SLXT(buf, r3, r1, r2);
       case S390_DFP_SHIFT_RIGHT: return s390_emit_SRXT(buf, r3, r1, r2);
+      case S390_DFP_INSERT_EXP:  return s390_emit_IEXTR(buf, r3, r1, r2);
       default:  goto fail;
       }
       break;
@@ -9658,6 +9851,10 @@ emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, s390_insn *insn,
       end = s390_insn_dfp_convert_emit(buf, insn);
       break;
 
+   case S390_INSN_DFP_REROUND:
+      end = s390_insn_dfp_reround_emit(buf, insn);
+      break;
+
    case S390_INSN_MFENCE:
       end = s390_insn_mfence_emit(buf, insn);
       break;
index e13893da6be0c07df91109dfc0092aae7080a52b..05f1f67733f3778ee8239dd11cbd9a78b9ea787e 100644 (file)
@@ -146,6 +146,7 @@ typedef enum {
    S390_INSN_DFP_INTOP,
    S390_INSN_DFP_COMPARE,
    S390_INSN_DFP_CONVERT,
+   S390_INSN_DFP_REROUND,
    S390_INSN_MFENCE,
    S390_INSN_MIMM,    /* Assign an immediate constant to a memory location */
    S390_INSN_MADD,    /* Add a value to a memory location */
@@ -270,11 +271,14 @@ typedef enum {
    S390_DFP_ADD,
    S390_DFP_SUB,
    S390_DFP_MUL,
-   S390_DFP_DIV
+   S390_DFP_DIV,
+   S390_DFP_QUANTIZE
 } s390_dfp_binop_t;
 
 /* The kind of unary DFP operations */
 typedef enum {
+   S390_DFP_EXTRACT_EXP_D64,
+   S390_DFP_EXTRACT_EXP_D128,
    S390_DFP_EXTRACT_SIG_D64,
    S390_DFP_EXTRACT_SIG_D128,
 } s390_dfp_unop_t;
@@ -282,7 +286,8 @@ typedef enum {
 /* The DFP operations with 2 operands one of them being integer */
 typedef enum {
    S390_DFP_SHIFT_LEFT,
-   S390_DFP_SHIFT_RIGHT
+   S390_DFP_SHIFT_RIGHT,
+   S390_DFP_INSERT_EXP
 } s390_dfp_intop_t;
 
 /* The kind of DFP compare operations */
@@ -291,7 +296,6 @@ typedef enum {
    S390_DFP_COMPARE_EXP,
 } s390_dfp_cmp_t;
 
-
 /* The details of a CDAS insn. Carved out to keep the size of
    s390_insn low */
 typedef struct {
@@ -509,6 +513,14 @@ typedef struct {
          HReg         op2_hi;  /* 128-bit operand high part; 64-bit opnd 2 */
          HReg         op2_lo;  /* 128-bit operand low part */
       } dfp_compare;
+      struct {
+         s390_dfp_round_t rounding_mode;
+         HReg         dst_hi; /* 128-bit result high part; 64-bit result */
+         HReg         dst_lo; /* 128-bit result low part */
+         HReg         op2;    /* integer operand */
+         HReg         op3_hi; /* 128-bit operand high part; 64-bit opnd */
+         HReg         op3_lo; /* 128-bit operand low part */
+      } dfp_reround;
 
       /* Miscellaneous */
       struct {
@@ -626,6 +638,8 @@ s390_insn *s390_insn_dfp_compare(UChar size, s390_dfp_cmp_t, HReg dst,
                                  HReg op1, HReg op2);
 s390_insn *s390_insn_dfp_convert(UChar size, s390_dfp_conv_t tag, HReg dst,
                                  HReg op, s390_dfp_round_t);
+s390_insn *s390_insn_dfp_reround(UChar size, HReg dst, HReg op2, HReg op3,
+                                 s390_dfp_round_t);
 s390_insn *s390_insn_dfp128_binop(UChar size, s390_dfp_binop_t, HReg dst_hi,
                                   HReg dst_lo, HReg op2_hi, HReg op2_lo,
                                   HReg op3_hi, HReg op3_lo,
@@ -643,6 +657,9 @@ s390_insn *s390_insn_dfp128_convert_to(UChar size, s390_dfp_conv_t,
 s390_insn *s390_insn_dfp128_convert_from(UChar size, s390_dfp_conv_t,
                                          HReg dst, HReg op_hi, HReg op_lo,
                                          s390_dfp_round_t);
+s390_insn *s390_insn_dfp128_reround(UChar size, HReg dst_hi, HReg dst_lo,
+                                    HReg op2, HReg op3_hi, HReg op3_lo,
+                                    s390_dfp_round_t);
 s390_insn *s390_insn_mfence(void);
 s390_insn *s390_insn_mimm(UChar size, s390_amode *dst, ULong value);
 s390_insn *s390_insn_madd(UChar size, s390_amode *dst, UChar delta,
index 1203459920a417b072b1eac873aeaa8b8866be11..2f42afd3b62c0403ad714e1ada0ef05f68d12247 100644 (file)
@@ -1495,16 +1495,28 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
          return dst;
       }
 
-      if (unop == Iop_ExtractSigD64) {
+      if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) {
+         s390_dfp_unop_t dfpop;
+         switch(unop) {
+         case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break;
+         case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break;
+         default: goto irreducible;
+         }
          dst = newVRegI(env);
          h1  = s390_isel_dfp_expr(env, arg);     /* Process the operand */
-         addInstr(env,
-                  s390_insn_dfp_unop(size, S390_DFP_EXTRACT_SIG_D64, dst, h1));
+         addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1));
          return dst;
       }
 
-      if (unop == Iop_ExtractSigD128) {
+      if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) {
+         s390_dfp_unop_t dfpop;
          HReg op_hi, op_lo, f13, f15;
+
+         switch(unop) {
+         case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break;
+         case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break;
+         default: goto irreducible;
+         }
          dst = newVRegI(env);
          s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
 
@@ -1516,8 +1528,7 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
          addInstr(env, s390_insn_move(8, f13, op_hi));
          addInstr(env, s390_insn_move(8, f15, op_lo));
 
-         addInstr(env, s390_insn_dfp128_unop(size, S390_DFP_EXTRACT_SIG_D128,
-                                             dst, f13, f15));
+         addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15));
          return dst;
       }
 
@@ -2417,9 +2428,6 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
       s390_dfp_binop_t dfpop;
       HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
 
-      s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);  /* 1st operand */
-      s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
-
       /* We use non-virtual registers as pairs with (f9, f11) as op1,
          (f12, f14) as op2 and (f13, f15)  as destination) */
       f9  = make_fpr(9);
@@ -2429,42 +2437,68 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
       f14 = make_fpr(14);
       f15 = make_fpr(15);
 
-      /* 1st operand --> (f9, f11) */
-      addInstr(env, s390_insn_move(8, f9,  op1_hi));
-      addInstr(env, s390_insn_move(8, f11, op1_lo));
+      switch (op) {
+      case Iop_AddD128:       dfpop = S390_DFP_ADD;      goto evaluate_dfp128;
+      case Iop_SubD128:       dfpop = S390_DFP_SUB;      goto evaluate_dfp128;
+      case Iop_MulD128:       dfpop = S390_DFP_MUL;      goto evaluate_dfp128;
+      case Iop_DivD128:       dfpop = S390_DFP_DIV;      goto evaluate_dfp128;
+      case Iop_QuantizeD128:  dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128;
+
+      evaluate_dfp128: {
+         /* Process 1st operand */
+         s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);
+         /* 1st operand --> (f9, f11) */
+         addInstr(env, s390_insn_move(8, f9,  op1_hi));
+         addInstr(env, s390_insn_move(8, f11, op1_lo));
 
-      /* 2nd operand --> (f12, f14) */
-      addInstr(env, s390_insn_move(8, f12, op2_hi));
-      addInstr(env, s390_insn_move(8, f14, op2_lo));
+         /* Process 2nd operand */
+         s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
+         /* 2nd operand --> (f12, f14) */
+         addInstr(env, s390_insn_move(8, f12, op2_hi));
+         addInstr(env, s390_insn_move(8, f14, op2_lo));
 
-      switch (op) {
-      case Iop_AddD128: dfpop = S390_DFP_ADD; break;
-      case Iop_SubD128: dfpop = S390_DFP_SUB; break;
-      case Iop_MulD128: dfpop = S390_DFP_MUL; break;
-      case Iop_DivD128: dfpop = S390_DFP_DIV; break;
-      default:
-         goto irreducible;
+         /* DFP arithmetic ops take rounding mode only when fpext is
+            installed. But, DFP quantize operation takes rm irrespective
+            of fpext facility . */
+         if (s390_host_has_fpext || dfpop == Iop_QuantizeD128) {
+            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_dfp128_binop(16, dfpop, f13, f15, f9, f11,
+                                              f12, f14, rounding_mode));
+         /* Move result to virtual destination register */
+         *dst_hi = newVRegF(env);
+         *dst_lo = newVRegF(env);
+         addInstr(env, s390_insn_move(8, *dst_hi, f13));
+         addInstr(env, s390_insn_move(8, *dst_lo, f15));
+         return;
       }
 
-      /* DFP binary ops have insns with rounding mode field
-         when the floating point extension facility is installed. */
-      if (s390_host_has_fpext) {
+      case Iop_SignificanceRoundD128: {
+         /* Process 1st operand */
+         HReg op1 = s390_isel_int_expr(env, left);
+         /* Process 2nd operand */
+         s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
+         /* 2nd operand --> (f12, f14) */
+         addInstr(env, s390_insn_move(8, f12, op2_hi));
+         addInstr(env, s390_insn_move(8, f14, op2_lo));
+
          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_dfp128_reround(16, f13, f15, op1, f12, f14,
+                                                rounding_mode));
+         /* Move result to virtual destination register */
+         *dst_hi = newVRegF(env);
+         *dst_lo = newVRegF(env);
+         addInstr(env, s390_insn_move(8, *dst_hi, f13));
+         addInstr(env, s390_insn_move(8, *dst_lo, f15));
+         return;
       }
 
-      addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
-                                           f12, f14, rounding_mode));
-
-      /* Move result to virtual destination register */
-      *dst_hi = newVRegF(env);
-      *dst_lo = newVRegF(env);
-      addInstr(env, s390_insn_move(8, *dst_hi, f13));
-      addInstr(env, s390_insn_move(8, *dst_lo, f15));
-
-      return;
+      default:
+         goto irreducible;
+      }
    }
 
       /* --------- BINARY OP --------- */
@@ -2477,15 +2511,29 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
          return;
 
       case Iop_ShlD128:
-      case Iop_ShrD128: {
+      case Iop_ShrD128:
+      case Iop_InsertExpD128: {
          HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
          s390_dfp_intop_t intop;
-         IRExpr *left   = expr->Iex.Binop.arg1;
-         IRExpr *right  = expr->Iex.Binop.arg2;
+         IRExpr *dfp_op;
+         IRExpr *int_op;
 
          switch (expr->Iex.Binop.op) {
-         case Iop_ShlD128: intop = S390_DFP_SHIFT_LEFT;  break;
-         case Iop_ShrD128: intop = S390_DFP_SHIFT_RIGHT; break;
+         case Iop_ShlD128:       /* (D128, I64) -> D128 */
+            intop = S390_DFP_SHIFT_LEFT;
+            dfp_op = expr->Iex.Binop.arg1;
+            int_op = expr->Iex.Binop.arg2;
+            break;
+         case Iop_ShrD128:       /* (D128, I64) -> D128 */
+            intop = S390_DFP_SHIFT_RIGHT;
+            dfp_op = expr->Iex.Binop.arg1;
+            int_op = expr->Iex.Binop.arg2;
+            break;
+         case Iop_InsertExpD128: /* (I64, D128) -> D128 */
+            intop = S390_DFP_INSERT_EXP;
+            int_op = expr->Iex.Binop.arg1;
+            dfp_op = expr->Iex.Binop.arg2;
+            break;
          default: goto irreducible;
          }
 
@@ -2496,11 +2544,13 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
          f13 = make_fpr(13); /* 128 bit dfp destination */
          f15 = make_fpr(15);
 
-         s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);  /* dfp operand */
+         /* Process dfp operand */
+         s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op);
+         /* op1 -> (f9,f11) */
          addInstr(env, s390_insn_move(8, f9,  op1_hi));
          addInstr(env, s390_insn_move(8, f11, op1_lo));
 
-         op2 = s390_isel_int_expr(env, right);  /* int operand */
+         op2 = s390_isel_int_expr(env, int_op);  /* int operand */
 
          addInstr(env,
                   s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
@@ -2695,21 +2745,35 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
       }
 
       case Iop_ShlD64:
-      case Iop_ShrD64: {
+      case Iop_ShrD64:
+      case Iop_InsertExpD64: {
          HReg op2;
          HReg op3;
+         IRExpr *dfp_op;
+         IRExpr *int_op;
          s390_dfp_intop_t intop;
-         IRExpr *op1   = expr->Iex.Binop.arg1;
-         IRExpr *shift = expr->Iex.Binop.arg2;
 
          switch (expr->Iex.Binop.op) {
-         case Iop_ShlD64: intop = S390_DFP_SHIFT_LEFT;  break;
-         case Iop_ShrD64: intop = S390_DFP_SHIFT_RIGHT; break;
+         case Iop_ShlD64:       /* (D64, I64) -> D64 */
+            intop = S390_DFP_SHIFT_LEFT;
+            dfp_op = expr->Iex.Binop.arg1;
+            int_op = expr->Iex.Binop.arg2;
+            break;
+         case Iop_ShrD64:       /* (D64, I64) -> D64 */
+            intop = S390_DFP_SHIFT_RIGHT;
+            dfp_op = expr->Iex.Binop.arg1;
+            int_op = expr->Iex.Binop.arg2;
+            break;
+         case Iop_InsertExpD64: /* (I64, D64) -> D64 */
+            intop = S390_DFP_INSERT_EXP;
+            int_op = expr->Iex.Binop.arg1;
+            dfp_op = expr->Iex.Binop.arg2;
+            break;
          default: goto irreducible;
          }
 
-         op2 = s390_isel_int_expr(env, shift);
-         op3 = s390_isel_dfp_expr(env, op1);
+         op2 = s390_isel_int_expr(env, int_op);
+         op3 = s390_isel_dfp_expr(env, dfp_op);
          dst = newVRegF(env);
 
          addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
@@ -2780,29 +2844,43 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
       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;
+      case Iop_AddD64:      dfpop = S390_DFP_ADD;      goto evaluate_dfp;
+      case Iop_SubD64:      dfpop = S390_DFP_SUB;      goto evaluate_dfp;
+      case Iop_MulD64:      dfpop = S390_DFP_MUL;      goto evaluate_dfp;
+      case Iop_DivD64:      dfpop = S390_DFP_DIV;      goto evaluate_dfp;
+      case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp;
+
+      evaluate_dfp: {
+         op2  = s390_isel_dfp_expr(env, left);  /* Process 1st operand */
+         op3  = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
+         dst  = newVRegF(env);
+         /* DFP arithmetic ops take rounding mode only when fpext is
+            installed. But, DFP quantize operation takes rm irrespective
+            of fpext facility . */
+         if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) {
+            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;
       }
-      /* DFP binary ops have insns with rounding mode field
-         when the floating point extension facility is installed. */
-      if (s390_host_has_fpext) {
+
+      case Iop_SignificanceRoundD64:
+         op2  = s390_isel_int_expr(env, left);  /* Process 1st operand */
+         op3  = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
+         dst  = newVRegF(env);
          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_reround(size, dst, op2, op3,
+                                             rounding_mode));
+         return dst;
 
-      addInstr(env,
-               s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
-      return dst;
+      default:
+         goto irreducible;
+      }
    }
 
    default: