Add support for binary DFP operations (64-bit).
Patch by Maran (maranp@linux.vnet.ibm.com).
Part of fixing BZ 307113.


git-svn-id: svn://svn.valgrind.org/vex/trunk@2560 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/host_s390_isel.c b/priv/host_s390_isel.c
index 6a958d1..1d0ea6f 100644
--- a/priv/host_s390_isel.c
+++ b/priv/host_s390_isel.c
@@ -135,6 +135,7 @@
 static void          s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
 static HReg          s390_isel_float_expr(ISelEnv *, IRExpr *);
 static void          s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
+static HReg          s390_isel_dfp_expr(ISelEnv *, IRExpr *);
 
 
 static Int
@@ -615,7 +616,6 @@
 /* Set the DFP rounding mode in the FPC. This function is called for
    all non-conversion DFP instructions as those will always get the
    rounding mode from the FPC. */
-#if 0  // fixs390: avoid compiler warnings about unused function
 static void
 set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
 {
@@ -725,7 +725,6 @@
    set_dfp_rounding_mode_in_fpc(env, irrm);
    return S390_DFP_ROUND_PER_FPC_0;
 }
-#endif
 
 /* CC_S390 holds the condition code in s390 encoding. Convert it to
    VEX encoding
@@ -2223,6 +2222,107 @@
 
 
 /*---------------------------------------------------------*/
+/*--- ISEL: Decimal point expressions (64 bit)          ---*/
+/*---------------------------------------------------------*/
+
+static HReg
+s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
+{
+   IRType ty = typeOfIRExpr(env->type_env, expr);
+   UChar size;
+
+   vassert(ty == Ity_D64);
+
+   size = sizeofIRType(ty);
+
+   switch (expr->tag) {
+   case Iex_RdTmp:
+      /* Return the virtual register that holds the temporary. */
+      return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
+
+      /* --------- LOAD --------- */
+   case Iex_Load: {
+      HReg        dst = newVRegF(env);
+      s390_amode *am  = s390_isel_amode(env, expr->Iex.Load.addr);
+
+      if (expr->Iex.Load.end != Iend_BE)
+         goto irreducible;
+
+      addInstr(env, s390_insn_load(size, dst, am));
+
+      return dst;
+   }
+
+      /* --------- GET --------- */
+   case Iex_Get: {
+      HReg dst = newVRegF(env);
+      s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
+
+      addInstr(env, s390_insn_load(size, dst, am));
+
+      return dst;
+   }
+
+      /* --------- TERNARY OP --------- */
+   case Iex_Triop: {
+      IRTriop *triop = expr->Iex.Triop.details;
+      IROp    op     = triop->op;
+      IRExpr *irrm   = triop->arg1;
+      IRExpr *left   = triop->arg2;
+      IRExpr *right  = triop->arg3;
+      s390_dfp_round_t rounding_mode;
+      s390_dfp_binop_t dfpop;
+      HReg op2, op3, dst;
+
+      op2  = s390_isel_dfp_expr(env, left);  /* Process 1st operand */
+      op3  = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
+      dst  = newVRegF(env);
+      switch (op) {
+      case Iop_AddD64:  dfpop = S390_DFP_ADD; break;
+      case Iop_SubD64:  dfpop = S390_DFP_SUB; break;
+      case Iop_MulD64:  dfpop = S390_DFP_MUL; break;
+      case Iop_DivD64:  dfpop = S390_DFP_DIV; break;
+      default:
+         goto irreducible;
+      }
+      /* DFP binary ops have insns with rounding mode field
+         when the floating point extension facility is installed. */
+      if (s390_host_has_fpext) {
+         rounding_mode = get_dfp_rounding_mode(env, irrm);
+      } else {
+         set_dfp_rounding_mode_in_fpc(env, irrm);
+         rounding_mode = S390_DFP_ROUND_PER_FPC_0;
+      }
+
+      addInstr(env,
+               s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
+      return dst;
+   }
+
+   default:
+      goto irreducible;
+   }
+
+   /* We get here if no pattern matched. */
+ irreducible:
+   ppIRExpr(expr);
+   vpanic("s390_isel_dfp_expr: cannot reduce tree");
+}
+
+static HReg
+s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
+{
+   HReg dst = s390_isel_dfp_expr_wrk(env, expr);
+
+   /* Sanity checks ... */
+   vassert(hregClass(dst) == HRcFlt64);
+   vassert(hregIsVirtual(dst));
+
+   return dst;
+}
+
+
+/*---------------------------------------------------------*/
 /*--- ISEL: Condition Code                              ---*/
 /*---------------------------------------------------------*/
 
@@ -2601,6 +2701,10 @@
          /* Does not occur. See function put_fpr_pair. */
          vpanic("Ist_Put with F128 data");
 
+      case Ity_D64:
+         src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
+         break;
+
       default:
          goto stmt_fail;
       }
@@ -2659,6 +2763,11 @@
          return;
       }
 
+      case Ity_D64:
+         src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
+         dst = lookupIRTemp(env, tmp);
+         break;
+
       default:
          goto stmt_fail;
       }
@@ -3024,6 +3133,7 @@
 
       case Ity_F32:
       case Ity_F64:
+      case Ity_D64:
          hreg = mkHReg(j++, HRcFlt64, True);
          break;