Add machinery to support DFP rounding modes.
Part of fixing BZ 307113.
Patch by Maran <maranp@linux.vnet.ibm.com>
git-svn-id: svn://svn.valgrind.org/vex/trunk@2557 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/host_s390_isel.c b/priv/host_s390_isel.c
index d42a3ab..6a958d1 100644
--- a/priv/host_s390_isel.c
+++ b/priv/host_s390_isel.c
@@ -114,6 +114,7 @@
UInt hwcaps;
IRExpr *previous_bfp_rounding_mode;
+ IRExpr *previous_dfp_rounding_mode;
ULong old_value[NUM_TRACKED_REGS];
@@ -607,6 +608,125 @@
}
+/*---------------------------------------------------------*/
+/*--- DFP helper functions ---*/
+/*---------------------------------------------------------*/
+
+/* 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)
+{
+ vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
+
+ /* Do we need to do anything? */
+ if (env->previous_dfp_rounding_mode &&
+ env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
+ irrm->tag == Iex_RdTmp &&
+ env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
+ /* No - new mode is identical to previous mode. */
+ return;
+ }
+
+ /* No luck - we better set it, and remember what we set it to. */
+ env->previous_dfp_rounding_mode = irrm;
+
+ /* The incoming rounding mode is in VEX IR encoding. Need to change
+ to s390.
+
+ rounding mode | S390 | IR
+ -----------------------------------------------
+ to nearest, ties to even | 000 | 000
+ to zero | 001 | 011
+ to +infinity | 010 | 010
+ to -infinity | 011 | 001
+ to nearest, ties away from 0 | 100 | 100
+ to nearest, ties toward 0 | 101 | 111
+ to away from 0 | 110 | 110
+ to prepare for shorter precision | 111 | 101
+
+ So: s390 = (IR ^ ((IR << 1) & 2))
+ */
+ HReg ir = s390_isel_int_expr(env, irrm);
+
+ HReg mode = newVRegI(env);
+
+ addInstr(env, s390_insn_move(4, mode, ir));
+ addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
+ addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
+ addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
+
+ addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
+}
+
+
+/* This function is invoked for insns that support a specification of
+ a rounding mode in the insn itself. In that case there is no need to
+ stick the rounding mode into the FPC -- a good thing. However, the
+ rounding mode must be known.
+ The IR to s390 encoding is chosen in the range 0:7 except
+ S390_DFP_ROUND_NEAREST_TIE_TOWARD_0 and
+ S390_DFP_ROUND_AWAY_0 which have no choice within the range.
+ Since the s390 dfp rounding mode encoding in 8:15 is not used, the
+ quantum excpetion is not suppressed and this is fine as valgrind does
+ not model this exception.
+
+ Translation table of
+ s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
+
+ s390(S390_DFP_ROUND_) | IR(Irrm_DFP_) | s390(S390_DFP_ROUND_)
+ --------------------------------------------------------------------
+ NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_1
+ NEAREST_TIE_AWAY_0_12 | " | "
+ PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_3
+ PREPARE_SHORT_15 | " | "
+ NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_4
+ NEAREST_EVEN_8 | " | "
+ ZERO_5 | ZERO | ZERO_5
+ ZERO_9 | " | "
+ POSINF_6 | PosINF | POSINF_6
+ POSINF_10 | " | "
+ NEGINF_7 | NegINF | NEGINF_7
+ NEGINF_11 | " | "
+ NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
+ AWAY_0 | AWAY_FROM_ZERO | AWAY_0
+*/
+static s390_dfp_round_t
+get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
+{
+ if (irrm->tag == Iex_Const) { /* rounding mode is known */
+ vassert(irrm->Iex.Const.con->tag == Ico_U32);
+ IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
+
+ switch (mode) {
+ case Irrm_DFP_NEAREST:
+ return S390_DFP_ROUND_NEAREST_EVEN_4;
+ case Irrm_DFP_NegINF:
+ return S390_DFP_ROUND_NEGINF_7;
+ case Irrm_DFP_PosINF:
+ return S390_DFP_ROUND_POSINF_6;
+ case Irrm_DFP_ZERO:
+ return S390_DFP_ROUND_ZERO_5;
+ case Irrm_DFP_NEAREST_TIE_AWAY_0:
+ return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1;
+ case Irrm_DFP_PREPARE_SHORTER:
+ return S390_DFP_ROUND_PREPARE_SHORT_3;
+ case Irrm_DFP_AWAY_FROM_ZERO:
+ return S390_DFP_ROUND_AWAY_0;
+ case Irrm_DFP_NEAREST_TIE_TOWARD_0:
+ return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
+ default:
+ vpanic("get_dfp_rounding_mode");
+ }
+ }
+
+ 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
@@ -2872,6 +2992,7 @@
env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
env->previous_bfp_rounding_mode = NULL;
+ env->previous_dfp_rounding_mode = NULL;
/* and finally ... */
env->hwcaps = hwcaps_host;