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/guest_s390_toIR.c b/priv/guest_s390_toIR.c
index 7ffeef3..f331897 100644
--- a/priv/guest_s390_toIR.c
+++ b/priv/guest_s390_toIR.c
@@ -1714,6 +1714,15 @@
 }
 
 static void
+s390_format_E(const HChar *(*irgen)(void))
+{
+   const HChar *mnm = irgen();
+
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+      s390_disasm(ENC1(MNM), mnm);
+}
+
+static void
 s390_format_RI(const HChar *(*irgen)(UChar r1, UShort i2),
                UChar r1, UShort i2)
 {
@@ -7111,6 +7120,174 @@
    return "pfdrl";
 }
 
+static IRExpr *
+get_rounding_mode_from_gr0(void)
+{
+   IRTemp rm_bits = newTemp(Ity_I32);
+   IRExpr *s390rm;
+   IRExpr *irrm;
+
+   vassert(s390_host_has_pfpo);
+   /* The dfp/bfp rounding mode is stored in bits [60:63] of GR 0
+      when PFPO insn is called. So, extract the bits at [60:63] */
+   assign(rm_bits, binop(Iop_And32, get_gpr_w1(0), mkU32(0xf)));
+   s390rm = mkexpr(rm_bits);
+   irrm = mkite(binop(Iop_CmpEQ32, s390rm, mkU32(0x1)),
+            mkexpr(encode_bfp_rounding_mode( S390_BFP_ROUND_PER_FPC)),
+            mkite(binop(Iop_CmpEQ32, s390rm, mkU32(0x8)),
+              mkexpr(encode_dfp_rounding_mode(S390_DFP_ROUND_NEAREST_EVEN_8)),
+              mkite(binop(Iop_CmpEQ32, s390rm, mkU32(0x9)),
+                mkexpr(encode_dfp_rounding_mode(S390_DFP_ROUND_ZERO_9)),
+                mkite(binop(Iop_CmpEQ32, s390rm, mkU32(0xa)),
+                  mkexpr(encode_dfp_rounding_mode(S390_DFP_ROUND_POSINF_10)),
+                  mkite(binop(Iop_CmpEQ32, s390rm, mkU32(0xb)),
+                    mkexpr(encode_dfp_rounding_mode(S390_DFP_ROUND_NEGINF_11)),
+                    mkite(binop(Iop_CmpEQ32, s390rm, mkU32(0xc)),
+                      mkexpr(encode_dfp_rounding_mode(
+                               S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12)),
+                      mkite(binop(Iop_CmpEQ32, s390rm, mkU32(0xd)),
+                        mkexpr(encode_dfp_rounding_mode(
+                                 S390_DFP_ROUND_NEAREST_TIE_TOWARD_0)),
+                        mkite(binop(Iop_CmpEQ32, s390rm, mkU32(0xe)),
+                          mkexpr(encode_dfp_rounding_mode(
+                                   S390_DFP_ROUND_AWAY_0)),
+                          mkite(binop(Iop_CmpEQ32, s390rm, mkU32(0xf)),
+                            mkexpr(encode_dfp_rounding_mode(
+                                     S390_DFP_ROUND_PREPARE_SHORT_15)),
+                                /* if rounding mode is 0 or invalid (2-7)
+                                   set S390_DFP_ROUND_PER_FPC_0 */
+                            mkexpr(encode_dfp_rounding_mode(
+                                     S390_DFP_ROUND_PER_FPC_0)))))))))));
+
+   return irrm;
+}
+
+static IRExpr *
+s390_call_pfpo_helper(IRExpr *gr0)
+{
+   IRExpr **args, *call;
+
+   args = mkIRExprVec_1(gr0);
+   call = mkIRExprCCall(Ity_I32, 0 /*regparm*/,
+                        "s390_do_pfpo", &s390_do_pfpo, args);
+   /* Nothing is excluded from definedness checking. */
+   call->Iex.CCall.cee->mcx_mask = 0;
+
+   return call;
+}
+
+static const HChar *
+s390_irgen_PFPO(void)
+{
+   IRTemp gr0 = newTemp(Ity_I32);     /* word 1 [32:63] of GR 0 */
+   IRTemp test_bit = newTemp(Ity_I32); /* bit 32 of GR 0 - test validity */
+   IRTemp fn = newTemp(Ity_I32);       /* [33:55] of GR 0 - function code */
+   IRTemp ef = newTemp(Ity_I32);       /* Emulation Failure */
+   IRTemp src1 = newTemp(Ity_F64);
+   IRTemp dst1 = newTemp(Ity_D64);
+   IRTemp src2 = newTemp(Ity_D64);
+   IRTemp dst2 = newTemp(Ity_F64);
+   IRTemp src3 = newTemp(Ity_F64);
+   IRTemp dst3 = newTemp(Ity_D128);
+   IRTemp src4 = newTemp(Ity_D128);
+   IRTemp dst4 = newTemp(Ity_F64);
+   IRTemp src5 = newTemp(Ity_F128);
+   IRTemp dst5 = newTemp(Ity_D128);
+   IRTemp src6 = newTemp(Ity_D128);
+   IRTemp dst6 = newTemp(Ity_F128);
+   IRExpr *irrm;
+
+   vassert(s390_host_has_pfpo);
+
+   assign(gr0, get_gpr_w1(0));
+   /* get function code */
+   assign(fn, binop(Iop_And32, binop(Iop_Shr32, mkexpr(gr0), mkU8(8)),
+                    mkU32(0x7fffff)));
+   /* get validity test bit */
+   assign(test_bit, binop(Iop_And32, binop(Iop_Shr32, mkexpr(gr0), mkU8(31)),
+                          mkU32(0x1)));
+   irrm = get_rounding_mode_from_gr0();
+
+   /* test_bit is 1 */
+   assign(src1, get_fpr_dw0(4)); /* get source from FPR 4,6 */
+   s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src1, gr0);
+
+   /* Return code set in GR1 is usually 0. Non-zero value is set only
+      when exceptions are raised. See Programming Notes point 5 in the
+      instrcution description of pfpo in POP. Since valgrind does not
+      model exception, it might be safe to just set 0 to GR 1. */
+   put_gpr_w1(1, mkU32(0x0));
+   next_insn_if(binop(Iop_CmpEQ32, mkexpr(test_bit), mkU32(0x1)));
+
+   /* Check validity of function code in GR 0 */
+   assign(ef, s390_call_pfpo_helper(unop(Iop_32Uto64, mkexpr(gr0))));
+
+   /* fixs390: Function emulation_failure can be used if it takes argument as
+      IRExpr * instead of VexEmNote. */
+   stmt(IRStmt_Put(S390X_GUEST_OFFSET(guest_EMNOTE), mkexpr(ef)));
+   dis_res->whatNext = Dis_StopHere;
+   dis_res->jk_StopHere = Ijk_EmFail;
+
+   stmt(
+        IRStmt_Exit(
+                    binop(Iop_CmpNE32, mkexpr(ef), mkU32(EmNote_NONE)),
+                    Ijk_EmFail,
+                    IRConst_U64(guest_IA_next_instr),
+                    S390X_GUEST_OFFSET(guest_IA)
+                    )
+        );
+
+   /* F64 -> D64 */
+   /* get source from FPR 4,6 - already set in src1 */
+   assign(dst1, binop(Iop_F64toD64, irrm, mkexpr(src1)));
+   put_dpr_dw0(0, mkexpr(dst1)); /* put the result in FPR 0,2 */
+   put_gpr_w1(1, mkU32(0x0));
+   s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src1, gr0);
+   next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F64_TO_D64)));
+
+   /* D64 -> F64 */
+   assign(src2, get_dpr_dw0(4)); /* get source from FPR 4,6 */
+   assign(dst2, binop(Iop_D64toF64, irrm, mkexpr(src2)));
+   put_fpr_dw0(0, mkexpr(dst2)); /* put the result in FPR 0,2 */
+   put_gpr_w1(1, mkU32(0x0));
+   s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src2, gr0);
+   next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D64_TO_F64)));
+
+   /* F64 -> D128 */
+   assign(src3, get_fpr_dw0(4)); /* get source from FPR 4,6 */
+   assign(dst3, binop(Iop_F64toD128, irrm, mkexpr(src3)));
+   put_dpr_pair(0, mkexpr(dst3)); /* put the result in FPR 0,2 */
+   put_gpr_w1(1, mkU32(0x0));
+   s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src3, gr0);
+   next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F64_TO_D128)));
+
+   /* D128 -> F64 */
+   assign(src4, get_dpr_pair(4)); /* get source from FPR 4,6 */
+   assign(dst4, binop(Iop_D128toF64, irrm, mkexpr(src4)));
+   put_fpr_dw0(0, mkexpr(dst4)); /* put the result in FPR 0,2 */
+   put_gpr_w1(1, mkU32(0x0));
+   s390_cc_thunk_put1d128Z(S390_CC_OP_PFPO_128, src4, gr0);
+   next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D128_TO_F64)));
+
+   /* F128 -> D128 */
+   assign(src5, get_fpr_pair(4)); /* get source from FPR 4,6 */
+   assign(dst5, binop(Iop_F128toD128, irrm, mkexpr(src5)));
+   put_dpr_pair(0, mkexpr(dst5)); /* put the result in FPR 0,2 */
+   put_gpr_w1(1, mkU32(0x0));
+   s390_cc_thunk_put1f128Z(S390_CC_OP_PFPO_128, src5, gr0);
+   next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F128_TO_D128)));
+
+   /* D128 -> F128 */
+   assign(src6, get_dpr_pair(4)); /* get source from FPR 4,6 */
+   assign(dst6, binop(Iop_D128toF128, irrm, mkexpr(src6)));
+   put_fpr_pair(0, mkexpr(dst6)); /* put the result in FPR 0,2 */
+   put_gpr_w1(1, mkU32(0x0));
+   s390_cc_thunk_put1d128Z(S390_CC_OP_PFPO_128, src6, gr0);
+   next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D128_TO_F128)));
+
+   return "pfpo";
+}
+
 static const HChar *
 s390_irgen_RLL(UChar r1, UChar r3, IRTemp op2addr)
 {
@@ -13611,7 +13788,7 @@
    case 0x0102: /* UPT */ goto unimplemented;
    case 0x0104: /* PTFF */ goto unimplemented;
    case 0x0107: /* SCKPF */ goto unimplemented;
-   case 0x010a: /* PFPO */ goto unimplemented;
+   case 0x010a: s390_format_E(s390_irgen_PFPO); goto ok;
    case 0x010b: /* TAM */ goto unimplemented;
    case 0x010c: /* SAM24 */ goto unimplemented;
    case 0x010d: /* SAM31 */ goto unimplemented;