s390: First round of changes to support the PFPO insn.
Support these IROps:
Iop_F64toD64, Iop_D64toF64
Iop_F64toD128, Iop_D128toF64,
Iop_F128toD128, Iop_D128toF128,

Patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com).
Part of fixing BZ #307113


git-svn-id: svn://svn.valgrind.org/vex/trunk@2719 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/host_s390_isel.c b/priv/host_s390_isel.c
index 21b8867..ac51e90 100644
--- a/priv/host_s390_isel.c
+++ b/priv/host_s390_isel.c
@@ -1941,16 +1941,16 @@
 
       /* --------- BINARY OP --------- */
    case Iex_Binop: {
-      HReg op_hi, op_lo, f12, f13, f14, 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);
-
       switch (expr->Iex.Binop.op) {
-      case Iop_SqrtF128:
+      case Iop_SqrtF128: {
+         HReg op_hi, op_lo, f12, f13, f14, 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);
+
          s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
 
          /* operand --> (f13, f15) */
@@ -1967,12 +1967,44 @@
          addInstr(env, s390_insn_move(8, *dst_hi, f12));
          addInstr(env, s390_insn_move(8, *dst_lo, f14));
          return;
+      }
 
       case Iop_F64HLtoF128:
          *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
          *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
          return;
 
+      case Iop_D128toF128: {
+         IRExpr *irrm;
+         IRExpr *left;
+         s390_dfp_round_t rm;
+         HReg op_hi, op_lo;
+         HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
+
+         f4 = make_fpr(4); /* source */
+         f6 = make_fpr(6); /* 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);
+         s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
+         /* 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, S390_FP_D128_TO_F128, f0, f2,
+                                               f4, f6, 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;
+      }
+
       default:
          goto irreducible;
       }
@@ -2196,6 +2228,7 @@
       IRExpr *left = expr->Iex.Binop.arg2;
       HReg h1, dst;
       s390_bfp_conv_t  conv;
+      s390_fp_conv_t fpconv;
 
       switch (op) {
       case Iop_SqrtF32:
@@ -2213,6 +2246,8 @@
       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_D64toF64:  fpconv = S390_FP_D64_TO_F64;  goto convert_dfp;
+      case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128;
 
       convert_float:
          h1 = s390_isel_float_expr(env, left);
@@ -2237,7 +2272,47 @@
                                              rounding_mode));
          return dst;
       }
-         
+
+      convert_dfp: {
+         s390_dfp_round_t rm;
+         HReg f0, f4, r1; /* real registers used by PFPO */
+
+         f4 = make_fpr(4); /* source */
+         f0 = make_fpr(0); /* destination */
+         r1 = make_gpr(1); /* GPR #1 clobbered */
+         h1 = s390_isel_dfp_expr(env, left);
+         dst = newVRegF(env);
+         rm = get_dfp_rounding_mode(env, irrm);
+         /* operand --> f4 */
+         addInstr(env, s390_insn_move(8, f4, h1));
+         addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
+         /* f0 --> destination */
+         addInstr(env, s390_insn_move(8, dst, f0));
+         return dst;
+      }
+
+      convert_dfp128: {
+         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_dfp128_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;
+      }
+
       default:
          goto irreducible;
 
@@ -2563,6 +2638,64 @@
          return;
       }
 
+      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 */
+
+         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_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,
+                                               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_F128toD128: {
+         IRExpr *irrm;
+         IRExpr *left;
+         s390_dfp_round_t rm;
+         HReg op_hi, op_lo;
+         HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
+
+         f4 = make_fpr(4); /* source */
+         f6 = make_fpr(6); /* 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);
+         s390_isel_float128_expr(&op_hi, &op_lo, env, left);
+         /* 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, S390_FP_F128_TO_D128, f0, f2,
+                                               f4, f6, 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;
+      }
+
       default:
          goto irreducible;
       }
@@ -2684,11 +2817,13 @@
       IRExpr *left = expr->Iex.Binop.arg2;
       HReg h1, dst;
       s390_dfp_conv_t  conv;
+      s390_fp_conv_t  fpconv;
 
       switch (op) {
       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_F64toD64:  fpconv = S390_FP_F64_TO_D64; goto convert_bfp;
 
       convert_dfp:
          h1 = s390_isel_dfp_expr(env, left);
@@ -2714,6 +2849,24 @@
             return dst;
          }
 
+      convert_bfp: {
+         s390_dfp_round_t rm;
+         HReg f0, f4, r1; /* real registers used by PFPO */
+
+         f4 = make_fpr(4); /* source */
+         f0 = make_fpr(0); /* destination */
+         r1 = make_gpr(1); /* GPR #1 clobbered */
+         h1 = s390_isel_float_expr(env, left);
+         dst = newVRegF(env);
+         rm = get_dfp_rounding_mode(env, irrm);
+         /* operand --> f4 */
+         addInstr(env, s390_insn_move(8, f4, h1));
+         addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, 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;