The result of rounding a 128-bit BFP/DFP value to 32/64 bit needs to
be stored in a register pair. This constraint was not observed previously
and the result was stored in any FPR that happened to be chosen. If the
selected FPR was not identifying a proper FPR pair, a SIGILL was delivered.
Fixes BZ #328455.


git-svn-id: svn://svn.valgrind.org/vex/trunk@2801 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/host_s390_isel.c b/priv/host_s390_isel.c
index aaccff6..3662ffd 100644
--- a/priv/host_s390_isel.c
+++ b/priv/host_s390_isel.c
@@ -1257,7 +1257,8 @@
          addInstr(env, s390_insn_move(8, f15, op_lo));
 
          rounding_mode = get_bfp_rounding_mode(env, arg1);
-         addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
+         addInstr(env, s390_insn_bfp128_convert_from(size, conv, res,
+                                                     INVALID_HREG, f13, f15,
                                                      rounding_mode));
          return res;
       }
@@ -1290,7 +1291,8 @@
             addInstr(env, s390_insn_move(8, f15, op_lo));
 
             rounding_mode = get_dfp_rounding_mode(env, arg1);
-            addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res, f13,
+            addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res,
+                                                        INVALID_HREG, f13,
                                                         f15, rounding_mode));
             return res;
          }
@@ -2455,7 +2457,7 @@
 
       case Iop_F128toF64:
       case Iop_F128toF32: {
-         HReg op_hi, op_lo, f13, f15;
+         HReg op_hi, op_lo, f12, f13, f14, f15;
          s390_bfp_round_t rounding_mode;
 
          conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
@@ -2463,15 +2465,18 @@
 
          s390_isel_float128_expr(&op_hi, &op_lo, env, left);
 
-         /* We use non-virtual registers as pairs (f13, f15) */
+         /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
+         f12 = make_fpr(12);
          f13 = make_fpr(13);
+         f14 = make_fpr(14);
          f15 = make_fpr(15);
 
          /* operand --> (f13, f15) */
          addInstr(env, s390_insn_move(8, f13, op_hi));
          addInstr(env, s390_insn_move(8, f15, op_lo));
 
-         dst = newVRegF(env);
+         /* result --> (f12, f14) */
+
          /* load-rounded has a rounding mode field when the floating point
             extension facility is installed. */
          if (s390_host_has_fpext) {
@@ -2480,8 +2485,12 @@
             set_bfp_rounding_mode_in_fpc(env, irrm);
             rounding_mode = S390_BFP_ROUND_PER_FPC;
          }
-         addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
-                                                     rounding_mode));
+
+         addInstr(env, s390_insn_bfp128_convert_from(size, conv, f12, f14,
+                                                     f13, f15, rounding_mode));
+         dst = newVRegF(env);
+         addInstr(env, s390_insn_move(8, dst, f12));
+
          return dst;
       }
       }
@@ -3044,22 +3053,25 @@
       }
 
       case Iop_D128toD64: {
-         HReg op_hi, op_lo, f13, f15;
+         HReg op_hi, op_lo, f12, f13, f14, f15;
          s390_dfp_round_t rounding_mode;
 
          conv = S390_DFP_D128_TO_D64;
 
          s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
 
-         /* We use non-virtual registers as pairs (f13, f15) */
+         /* We use non-virtual registers as pairs (f13, f15) and (f12, f14) */
+         f12 = make_fpr(12);
          f13 = make_fpr(13);
+         f14 = make_fpr(14);
          f15 = make_fpr(15);
 
          /* operand --> (f13, f15) */
          addInstr(env, s390_insn_move(8, f13, op_hi));
          addInstr(env, s390_insn_move(8, f15, op_lo));
 
-         dst = newVRegF(env);
+         /* result --> (f12, f14) */
+ 
          /* load-rounded has a rounding mode field when the floating point
             extension facility is installed. */
          if (s390_host_has_fpext) {
@@ -3068,8 +3080,11 @@
             set_dfp_rounding_mode_in_fpc(env, irrm);
             rounding_mode = S390_DFP_ROUND_PER_FPC_0;
          }
-         addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
-                                                     rounding_mode));
+         addInstr(env, s390_insn_dfp128_convert_from(size, conv, f12, f14,
+                                                     f13, f15, rounding_mode));
+         dst = newVRegF(env);
+         addInstr(env, s390_insn_move(8, dst, f12));
+
          return dst;
       }