Add machinery to support DFP rounding modes.
Part of fixing BZ 307113.
Patch by Maran <maranp@linux.vnet.ibm.com>


git-svn-id: svn://svn.valgrind.org/vex/trunk@2557 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_s390_toIR.c b/priv/guest_s390_toIR.c
index bde121b..0748685 100644
--- a/priv/guest_s390_toIR.c
+++ b/priv/guest_s390_toIR.c
@@ -1465,6 +1465,84 @@
    return mktemp(Ity_I32, rm);
 }
 
+/* Extract the DFP rounding mode from the guest FPC reg and encode it as an
+   IRRoundingMode:
+
+   rounding mode                     | s390  | IR
+   ------------------------------------------------
+   to nearest, ties to even          |  000  | 000
+   to zero                           |  001  | 011
+   to +infinity                      |  010  | 010
+   to -infinity                      |  011  | 001
+   to nearest, ties away from 0      |  100  | 100
+   to nearest, ties toward 0         |  101  | 111
+   to away from 0                    |  110  | 110
+   to prepare for shorter precision  |  111  | 101
+
+   So:  IR = (s390 ^ ((s390 << 1) & 2))
+*/
+#if 0  // fixs390: avoid compiler warnings about unused function
+static IRExpr *
+get_dfp_rounding_mode_from_fpc(void)
+{
+   IRTemp fpc_bits = newTemp(Ity_I32);
+
+   /* The dfp rounding mode is stored in bits [25:27].
+      extract the bits at 25:27 and right shift 4 times. */
+   assign(fpc_bits, binop(Iop_Shr32,
+                          binop(Iop_And32, get_fpc_w0(), mkU32(0x70)),
+                          mkU8(4)));
+
+   IRExpr *rm_s390 = mkexpr(fpc_bits);
+   // rm_IR = (rm_s390 ^ ((rm_s390 << 1) & 2));
+
+   return binop(Iop_Xor32, rm_s390,
+                binop( Iop_And32,
+                       binop(Iop_Shl32, rm_s390, mkU8(1)),
+                       mkU32(2)));
+}
+
+/* Encode the s390 rounding mode as it appears in the m3 field of certain
+   instructions to VEX's IRRoundingMode. */
+static IRTemp
+encode_dfp_rounding_mode(UChar mode)
+{
+   IRExpr *rm;
+
+   switch (mode) {
+   case S390_DFP_ROUND_PER_FPC_0:
+   case S390_DFP_ROUND_PER_FPC_2:
+      rm = get_dfp_rounding_mode_from_fpc(); break;
+   case S390_DFP_ROUND_NEAREST_EVEN_4:
+   case S390_DFP_ROUND_NEAREST_EVEN_8:
+      rm = mkU32(Irrm_DFP_NEAREST); break;
+   case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1:
+   case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12:
+      rm = mkU32(Irrm_DFP_NEAREST_TIE_AWAY_0); break;
+   case S390_DFP_ROUND_PREPARE_SHORT_3:
+   case S390_DFP_ROUND_PREPARE_SHORT_15:
+      rm = mkU32(Irrm_DFP_PREPARE_SHORTER); break;
+   case S390_DFP_ROUND_ZERO_5:
+   case S390_DFP_ROUND_ZERO_9:
+      rm = mkU32(Irrm_DFP_ZERO ); break;
+   case S390_DFP_ROUND_POSINF_6:
+   case S390_DFP_ROUND_POSINF_10:
+      rm = mkU32(Irrm_DFP_PosINF); break;
+   case S390_DFP_ROUND_NEGINF_7:
+   case S390_DFP_ROUND_NEGINF_11:
+      rm = mkU32(Irrm_DFP_NegINF); break;
+   case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0:
+      rm = mkU32(Irrm_DFP_NEAREST_TIE_TOWARD_0); break;
+   case S390_DFP_ROUND_AWAY_0:
+      rm = mkU32(Irrm_DFP_AWAY_FROM_ZERO); break;
+   default:
+      vpanic("encode_dfp_rounding_mode");
+   }
+
+   return mktemp(Ity_I32, rm);
+}
+#endif
+
 /*------------------------------------------------------------*/
 /*--- Build IR for formats                                 ---*/
 /*------------------------------------------------------------*/