12d916
commit 9b28d5ecf72accc80d267a3fcfd0bd4212ff34d8
12d916
Author: florian <florian@8f6e269a-dfd6-0310-a8e1-e2731360e62c>
12d916
Date:   Tue Dec 10 16:51:15 2013 +0000
12d916
12d916
    The result of rounding a 128-bit BFP/DFP value to 32/64 bit needs to
12d916
    be stored in a register pair. This constraint was not observed previously
12d916
    and the result was stored in any FPR that happened to be chosen. If the
12d916
    selected FPR was not identifying a proper FPR pair, a SIGILL was delivered.
12d916
    Fixes BZ #328455.
12d916
    
12d916
    
12d916
    git-svn-id: svn://svn.valgrind.org/vex/trunk@2801 8f6e269a-dfd6-0310-a8e1-e2731360e62c
12d916
12d916
diff --git a/priv/host_s390_defs.c b/priv/host_s390_defs.c
12d916
index 0b61a5d..ce76285 100644
12d916
--- a/VEX/priv/host_s390_defs.c
12d916
+++ b/VEX/priv/host_s390_defs.c
12d916
@@ -5861,7 +5861,6 @@ s390_insn_bfp128_convert(UChar size, s390_bfp_conv_t tag, HReg dst_hi,
12d916
    } else {
12d916
       /* From 16 bytes to smaller size */
12d916
       vassert(is_valid_fp128_regpair(op_hi, op_lo));
12d916
-      vassert(hregIsInvalid(dst_lo));
12d916
    }
12d916
 
12d916
    insn->tag  = S390_INSN_BFP_CONVERT;
12d916
@@ -5891,11 +5890,11 @@ s390_insn_bfp128_convert_to(UChar size, s390_bfp_conv_t tag, HReg dst_hi,
12d916
 
12d916
 
12d916
 s390_insn *
12d916
-s390_insn_bfp128_convert_from(UChar size, s390_bfp_conv_t tag, HReg dst,
12d916
-                              HReg op_hi, HReg op_lo,
12d916
+s390_insn_bfp128_convert_from(UChar size, s390_bfp_conv_t tag, HReg dst_hi,
12d916
+                              HReg dst_lo, HReg op_hi, HReg op_lo,
12d916
                               s390_bfp_round_t rounding_mode)
12d916
 {
12d916
-   return s390_insn_bfp128_convert(size, tag, dst, INVALID_HREG, op_hi, op_lo,
12d916
+   return s390_insn_bfp128_convert(size, tag, dst_hi, dst_lo, op_hi, op_lo,
12d916
                                    rounding_mode);
12d916
 }
12d916
 
12d916
@@ -6192,7 +6191,6 @@ s390_insn_dfp128_convert(UChar size, s390_dfp_conv_t tag, HReg dst_hi,
12d916
    } else {
12d916
       /* From 16 bytes to smaller size */
12d916
       vassert(is_valid_fp128_regpair(op_hi, op_lo));
12d916
-      vassert(hregIsInvalid(dst_lo));
12d916
    }
12d916
 
12d916
    insn->tag  = S390_INSN_DFP_CONVERT;
12d916
@@ -6222,11 +6220,11 @@ s390_insn_dfp128_convert_to(UChar size, s390_dfp_conv_t tag, HReg dst_hi,
12d916
 
12d916
 
12d916
 s390_insn *
12d916
-s390_insn_dfp128_convert_from(UChar size, s390_dfp_conv_t tag, HReg dst,
12d916
-                              HReg op_hi, HReg op_lo,
12d916
+s390_insn_dfp128_convert_from(UChar size, s390_dfp_conv_t tag, HReg dst_hi,
12d916
+                              HReg dst_lo, HReg op_hi, HReg op_lo,
12d916
                               s390_dfp_round_t rounding_mode)
12d916
 {
12d916
-   return s390_insn_dfp128_convert(size, tag, dst, INVALID_HREG, op_hi, op_lo,
12d916
+   return s390_insn_dfp128_convert(size, tag, dst_hi, dst_lo, op_hi, op_lo,
12d916
                                    rounding_mode);
12d916
 }
12d916
 
12d916
diff --git a/priv/host_s390_defs.h b/priv/host_s390_defs.h
12d916
index dafc8ae..5b6fc1f 100644
12d916
--- a/VEX/priv/host_s390_defs.h
12d916
+++ b/VEX/priv/host_s390_defs.h
12d916
@@ -665,8 +665,8 @@ s390_insn *s390_insn_bfp128_compare(UChar size, HReg dst, HReg op1_hi,
12d916
 s390_insn *s390_insn_bfp128_convert_to(UChar size, s390_bfp_conv_t,
12d916
                                        HReg dst_hi, HReg dst_lo, HReg op);
12d916
 s390_insn *s390_insn_bfp128_convert_from(UChar size, s390_bfp_conv_t,
12d916
-                                         HReg dst, HReg op_hi, HReg op_lo,
12d916
-                                         s390_bfp_round_t);
12d916
+                                         HReg dst_hi, HReg dst_lo, HReg op_hi,
12d916
+                                         HReg op_lo, s390_bfp_round_t);
12d916
 s390_insn *s390_insn_dfp_binop(UChar size, s390_dfp_binop_t, HReg dst,
12d916
                                HReg op2, HReg op3,
12d916
                                s390_dfp_round_t rounding_mode);
12d916
@@ -699,8 +699,8 @@ s390_insn *s390_insn_dfp128_compare(UChar size, s390_dfp_cmp_t, HReg dst,
12d916
 s390_insn *s390_insn_dfp128_convert_to(UChar size, s390_dfp_conv_t,
12d916
                                        HReg dst_hi, HReg dst_lo, HReg op);
12d916
 s390_insn *s390_insn_dfp128_convert_from(UChar size, s390_dfp_conv_t,
12d916
-                                         HReg dst, HReg op_hi, HReg op_lo,
12d916
-                                         s390_dfp_round_t);
12d916
+                                         HReg dst_hi, HReg dst_lo, HReg op_hi,
12d916
+                                         HReg op_lo, s390_dfp_round_t);
12d916
 s390_insn *s390_insn_dfp128_reround(UChar size, HReg dst_hi, HReg dst_lo,
12d916
                                     HReg op2, HReg op3_hi, HReg op3_lo,
12d916
                                     s390_dfp_round_t);
12d916
diff --git a/priv/host_s390_isel.c b/priv/host_s390_isel.c
12d916
index aaccff6..3662ffd 100644
12d916
--- a/VEX/priv/host_s390_isel.c
12d916
+++ b/VEX/priv/host_s390_isel.c
12d916
@@ -1257,7 +1257,8 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
12d916
          addInstr(env, s390_insn_move(8, f15, op_lo));
12d916
 
12d916
          rounding_mode = get_bfp_rounding_mode(env, arg1);
12d916
-         addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
12d916
+         addInstr(env, s390_insn_bfp128_convert_from(size, conv, res,
12d916
+                                                     INVALID_HREG, f13, f15,
12d916
                                                      rounding_mode));
12d916
          return res;
12d916
       }
12d916
@@ -1290,7 +1291,8 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
12d916
             addInstr(env, s390_insn_move(8, f15, op_lo));
12d916
 
12d916
             rounding_mode = get_dfp_rounding_mode(env, arg1);
12d916
-            addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res, f13,
12d916
+            addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res,
12d916
+                                                        INVALID_HREG, f13,
12d916
                                                         f15, rounding_mode));
12d916
             return res;
12d916
          }
12d916
@@ -2455,7 +2457,7 @@ s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
12d916
 
12d916
       case Iop_F128toF64:
12d916
       case Iop_F128toF32: {
12d916
-         HReg op_hi, op_lo, f13, f15;
12d916
+         HReg op_hi, op_lo, f12, f13, f14, f15;
12d916
          s390_bfp_round_t rounding_mode;
12d916
 
12d916
          conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
12d916
@@ -2463,15 +2465,18 @@ s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
12d916
 
12d916
          s390_isel_float128_expr(&op_hi, &op_lo, env, left);
12d916
 
12d916
-         /* We use non-virtual registers as pairs (f13, f15) */
12d916
+         /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
12d916
+         f12 = make_fpr(12);
12d916
          f13 = make_fpr(13);
12d916
+         f14 = make_fpr(14);
12d916
          f15 = make_fpr(15);
12d916
 
12d916
          /* operand --> (f13, f15) */
12d916
          addInstr(env, s390_insn_move(8, f13, op_hi));
12d916
          addInstr(env, s390_insn_move(8, f15, op_lo));
12d916
 
12d916
-         dst = newVRegF(env);
12d916
+         /* result --> (f12, f14) */
12d916
+
12d916
          /* load-rounded has a rounding mode field when the floating point
12d916
             extension facility is installed. */
12d916
          if (s390_host_has_fpext) {
12d916
@@ -2480,8 +2485,12 @@ s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
12d916
             set_bfp_rounding_mode_in_fpc(env, irrm);
12d916
             rounding_mode = S390_BFP_ROUND_PER_FPC;
12d916
          }
12d916
-         addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
12d916
-                                                     rounding_mode));
12d916
+
12d916
+         addInstr(env, s390_insn_bfp128_convert_from(size, conv, f12, f14,
12d916
+                                                     f13, f15, rounding_mode));
12d916
+         dst = newVRegF(env);
12d916
+         addInstr(env, s390_insn_move(8, dst, f12));
12d916
+
12d916
          return dst;
12d916
       }
12d916
       }
12d916
@@ -3044,22 +3053,25 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
12d916
       }
12d916
 
12d916
       case Iop_D128toD64: {
12d916
-         HReg op_hi, op_lo, f13, f15;
12d916
+         HReg op_hi, op_lo, f12, f13, f14, f15;
12d916
          s390_dfp_round_t rounding_mode;
12d916
 
12d916
          conv = S390_DFP_D128_TO_D64;
12d916
 
12d916
          s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
12d916
 
12d916
-         /* We use non-virtual registers as pairs (f13, f15) */
12d916
+         /* We use non-virtual registers as pairs (f13, f15) and (f12, f14) */
12d916
+         f12 = make_fpr(12);
12d916
          f13 = make_fpr(13);
12d916
+         f14 = make_fpr(14);
12d916
          f15 = make_fpr(15);
12d916
 
12d916
          /* operand --> (f13, f15) */
12d916
          addInstr(env, s390_insn_move(8, f13, op_hi));
12d916
          addInstr(env, s390_insn_move(8, f15, op_lo));
12d916
 
12d916
-         dst = newVRegF(env);
12d916
+         /* result --> (f12, f14) */
12d916
+ 
12d916
          /* load-rounded has a rounding mode field when the floating point
12d916
             extension facility is installed. */
12d916
          if (s390_host_has_fpext) {
12d916
@@ -3068,8 +3080,11 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
12d916
             set_dfp_rounding_mode_in_fpc(env, irrm);
12d916
             rounding_mode = S390_DFP_ROUND_PER_FPC_0;
12d916
          }
12d916
-         addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
12d916
-                                                     rounding_mode));
12d916
+         addInstr(env, s390_insn_dfp128_convert_from(size, conv, f12, f14,
12d916
+                                                     f13, f15, rounding_mode));
12d916
+         dst = newVRegF(env);
12d916
+         addInstr(env, s390_insn_move(8, dst, f12));
12d916
+
12d916
          return dst;
12d916
       }
12d916