s390: Change the handling of S390_ROUND_PER_FPC (which indicates that the
actual rounding mode is to be taken from the FPC register). Previously, this
was just mapped to S390_ROUND_NEAREST_EVEN, which obviously has correctness
issues.

First, we add a function get_bfp_rounding_mode_from_fpc to extract the
rounding mode from the guest FPC when building IR.
Second, have encode_bfp_rounding_mode invoke get_bfp_rounding_mode_from_fpc
whenever a S390_ROUND_PER_FPC is requested.
Third, in insn selection track whether (and if so to what value) the
rounding mode was set for the IRSB at hand. That way redundant assignments
can be avoided. This works well because the IR optimiser do a fine job
recognising end eliminating the expressions returned earlier from
get_bfp_rounding_more_from_fpc. So they get all mapped to the same IRTemp.
Note, VEX r2524 is essential to get this behaviour.
Fourth, remove the rounding more from the bfp_unop/binop/triop s390_insns.
Fifth, if the rounding mode can be set on the insn directly, prefer that
over setting it in the FPC and picking it up from there.


git-svn-id: svn://svn.valgrind.org/vex/trunk@2525 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_s390_toIR.c b/priv/guest_s390_toIR.c
index aa3e133..d796171 100644
--- a/priv/guest_s390_toIR.c
+++ b/priv/guest_s390_toIR.c
@@ -425,31 +425,6 @@
                     S390X_GUEST_OFFSET(guest_IA)));
 }
 
-/* Encode the s390 rounding mode as it appears in the m3 field of certain
-   instructions to VEX's IRRoundingMode. Rounding modes that cannot be
-   represented in VEX are converted to Irrm_NEAREST. The rationale is, that
-   Irrm_NEAREST refers to IEEE 754's roundTiesToEven which the standard
-   considers the default rounding mode (4.3.3). */
-static IRTemp
-encode_bfp_rounding_mode(UChar mode)
-{
-   IRExpr *rm;
-
-   switch (mode) {
-   case S390_ROUND_PER_FPC:       /* not supported */
-   case S390_ROUND_NEAREST_AWAY:  /* not supported */
-   case S390_ROUND_PREPARE_SHORT: /* not supported */
-   case S390_ROUND_NEAREST_EVEN:  rm = mkU32(Irrm_NEAREST); break;
-   case S390_ROUND_ZERO:          rm = mkU32(Irrm_ZERO);    break;
-   case S390_ROUND_POSINF:        rm = mkU32(Irrm_PosINF);  break;
-   case S390_ROUND_NEGINF:        rm = mkU32(Irrm_NegINF);  break;
-   default:
-      vpanic("encode_bfp_rounding_mode");
-   }
-
-   return mktemp(Ity_I32, rm);
-}
-
 static __inline__ IRExpr *get_fpr_dw0(UInt);
 static __inline__ void    put_fpr_dw0(UInt, IRExpr *);
 
@@ -1419,6 +1394,76 @@
 
 
 /*------------------------------------------------------------*/
+/*--- Rounding modes                                       ---*/
+/*------------------------------------------------------------*/
+
+/* Extract the rounding mode from the guest FPC reg and encode it as an
+   IRRoundingMode:
+
+   rounding mode | s390 | IR
+   -------------------------
+   to nearest    |  00  | 00
+   to zero       |  01  | 11
+   to +infinity  |  10  | 10
+   to -infinity  |  11  | 01
+
+   So:  IR = (4 - s390) & 3
+*/
+static IRExpr *
+get_rounding_mode_from_fpc(void)
+{
+   IRTemp fpc_bits = newTemp(Ity_I32);
+
+   /* For z196 and later the bfp rounding mode is stored in bits [29:31].
+      Prior to that bits [30:31] contained the bfp rounding mode with
+      bit 29 being unused and having a value of 0. So we can always
+      extract the least significant 3 bits. */
+   assign(fpc_bits, binop(Iop_And32, get_fpc_w0(), mkU32(7)));
+
+   /* fixs390:
+
+
+      if (! s390_host_has_fpext && rounding_mode > 3) {
+         emulation warning @ runtime and
+         set fpc to round nearest
+      }
+   */
+
+   /* For now silently adjust an unsupported rounding mode to "nearest" */
+   IRExpr *rm_s390 = mkite(binop(Iop_CmpLE32S, mkexpr(fpc_bits), mkU32(3)),
+                           mkexpr(fpc_bits),
+                           mkU32(S390_FPC_ROUND_NEAREST_EVEN));
+
+   // rm_IR = (4 - rm_s390) & 3;
+   return binop(Iop_And32, binop(Iop_Sub32, mkU32(4), rm_s390), mkU32(3));
+}
+
+/* Encode the s390 rounding mode as it appears in the m3 field of certain
+   instructions to VEX's IRRoundingMode. Rounding modes that cannot be
+   represented in VEX are converted to Irrm_NEAREST. The rationale is, that
+   Irrm_NEAREST refers to IEEE 754's roundTiesToEven which the standard
+   considers the default rounding mode (4.3.3). */
+static IRTemp
+encode_bfp_rounding_mode(UChar mode)
+{
+   IRExpr *rm;
+
+   switch (mode) {
+   case S390_ROUND_PER_FPC:       rm = get_rounding_mode_from_fpc(); break;
+   case S390_ROUND_NEAREST_AWAY:  /* not supported */
+   case S390_ROUND_PREPARE_SHORT: /* not supported */
+   case S390_ROUND_NEAREST_EVEN:  rm = mkU32(Irrm_NEAREST); break;
+   case S390_ROUND_ZERO:          rm = mkU32(Irrm_ZERO);    break;
+   case S390_ROUND_POSINF:        rm = mkU32(Irrm_PosINF);  break;
+   case S390_ROUND_NEGINF:        rm = mkU32(Irrm_NegINF);  break;
+   default:
+      vpanic("encode_bfp_rounding_mode");
+   }
+
+   return mktemp(Ity_I32, rm);
+}
+
+/*------------------------------------------------------------*/
 /*--- Build IR for formats                                 ---*/
 /*------------------------------------------------------------*/
 static void