s390: Support some more BFP <-> DFP conversions (the ones
that were added in VEX r2727).
Patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com).
Part of fixing BZ 307113.


git-svn-id: svn://svn.valgrind.org/vex/trunk@2728 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/host_s390_isel.c b/priv/host_s390_isel.c
index c20bf59..d84125d 100644
--- a/priv/host_s390_isel.c
+++ b/priv/host_s390_isel.c
@@ -1974,6 +1974,45 @@
          *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
          return;
 
+      case Iop_D32toF128:
+      case Iop_D64toF128: {
+         IRExpr *irrm;
+         IRExpr *left;
+         s390_dfp_round_t rm;
+         HReg h1; /* virtual reg. to hold source */
+         HReg f0, f2, f4, r1; /* real registers used by PFPO */
+         s390_fp_conv_t fpconv;
+
+         switch (expr->Iex.Binop.op) {
+         case Iop_D32toF128:
+            fpconv = S390_FP_D32_TO_F128;
+            break;
+         case Iop_D64toF128:
+            fpconv = S390_FP_D64_TO_F128;
+            break;
+         default: goto irreducible;
+         }
+
+         f4 = make_fpr(4); /* source */
+         f0 = make_fpr(0); /* destination */
+         f2 = make_fpr(2); /* destination */
+         r1 = make_gpr(1); /* GPR #1 clobbered */
+         irrm = expr->Iex.Binop.arg1;
+         left = expr->Iex.Binop.arg2;
+         rm = get_dfp_rounding_mode(env, irrm);
+         h1 = s390_isel_dfp_expr(env, left);
+         addInstr(env, s390_insn_move(8, f4, h1));
+         addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
+                                               f4, INVALID_HREG, r1, rm));
+         /* (f0, f2) --> destination */
+         *dst_hi = newVRegF(env);
+         *dst_lo = newVRegF(env);
+         addInstr(env, s390_insn_move(8, *dst_hi, f0));
+         addInstr(env, s390_insn_move(8, *dst_lo, f2));
+
+         return;
+      }
+
       case Iop_D128toF128: {
          IRExpr *irrm;
          IRExpr *left;
@@ -2246,7 +2285,11 @@
       case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
       case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
       case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
+      case Iop_D32toF32:  fpconv = S390_FP_D32_TO_F32;  goto convert_dfp;
+      case Iop_D32toF64:  fpconv = S390_FP_D32_TO_F64;  goto convert_dfp;
+      case Iop_D64toF32:  fpconv = S390_FP_D64_TO_F32;  goto convert_dfp;
       case Iop_D64toF64:  fpconv = S390_FP_D64_TO_F64;  goto convert_dfp;
+      case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128;
       case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128;
 
       convert_float:
@@ -2638,12 +2681,24 @@
          return;
       }
 
+      case Iop_F32toD128:
       case Iop_F64toD128: {
          IRExpr *irrm;
          IRExpr *left;
          s390_dfp_round_t rm;
          HReg h1; /* virtual reg. to hold source */
          HReg f0, f2, f4, r1; /* real registers used by PFPO */
+         s390_fp_conv_t fpconv;
+
+         switch (expr->Iex.Binop.op) {
+         case Iop_F32toD128:       /* (D128, I64) -> D128 */
+            fpconv = S390_FP_F32_TO_D128;
+            break;
+         case Iop_F64toD128:       /* (D128, I64) -> D128 */
+            fpconv = S390_FP_F64_TO_D128;
+            break;
+         default: goto irreducible;
+         }
 
          f4 = make_fpr(4); /* source */
          f0 = make_fpr(0); /* destination */
@@ -2654,7 +2709,7 @@
          rm = get_dfp_rounding_mode(env, irrm);
          h1 = s390_isel_float_expr(env, left);
          addInstr(env, s390_insn_move(8, f4, h1));
-         addInstr(env, s390_insn_fp128_convert(16, S390_FP_F64_TO_D128, f0, f2,
+         addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
                                                f4, INVALID_HREG, r1, rm));
          /* (f0, f2) --> destination */
          *dst_hi = newVRegF(env);
@@ -2823,7 +2878,12 @@
       case Iop_D64toD32:  conv = S390_DFP_D64_TO_D32; goto convert_dfp;
       case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
       case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
+      case Iop_F32toD32:  fpconv = S390_FP_F32_TO_D32; goto convert_bfp;
+      case Iop_F32toD64:  fpconv = S390_FP_F32_TO_D64; goto convert_bfp;
+      case Iop_F64toD32:  fpconv = S390_FP_F64_TO_D32; goto convert_bfp;
       case Iop_F64toD64:  fpconv = S390_FP_F64_TO_D64; goto convert_bfp;
+      case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128;
+      case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128;
 
       convert_dfp:
          h1 = s390_isel_dfp_expr(env, left);
@@ -2867,6 +2927,28 @@
          return dst;
       }
 
+      convert_bfp128: {
+         s390_dfp_round_t rm;
+         HReg op_hi, op_lo;
+         HReg f0, f4, f6, r1; /* real registers used by PFPO */
+
+         f4 = make_fpr(4); /* source */
+         f6 = make_fpr(6); /* source */
+         f0 = make_fpr(0); /* destination */
+         r1 = make_gpr(1); /* GPR #1 clobbered */
+         s390_isel_float128_expr(&op_hi, &op_lo, env, left);
+         dst = newVRegF(env);
+         rm = get_dfp_rounding_mode(env, irrm);
+         /* operand --> (f4, f6) */
+         addInstr(env, s390_insn_move(8, f4, op_hi));
+         addInstr(env, s390_insn_move(8, f6, op_lo));
+         addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
+                                               f4, f6, r1, rm));
+         /* f0 --> destination */
+         addInstr(env, s390_insn_move(8, dst, f0));
+         return dst;
+      }
+
       case Iop_D128toD64: {
          HReg op_hi, op_lo, f13, f15;
          s390_dfp_round_t rounding_mode;