Patch by Maran (maranp@linux.vnet.ibm.com).
Part of fixing BZ 307113.
git-svn-id: svn://svn.valgrind.org/vex/trunk@2560
S390_CC_OP_BFP_128_TO_UINT_32 = 38,
S390_CC_OP_BFP_32_TO_UINT_64 = 39,
S390_CC_OP_BFP_64_TO_UINT_64 = 40,
- S390_CC_OP_BFP_128_TO_UINT_64 = 41
+ S390_CC_OP_BFP_128_TO_UINT_64 = 41,
+ S390_CC_OP_DFP_RESULT_64 = 42
};
/*------------------------------------------------------------*/
psw >> 28; /* cc */ \
})
+#define S390_CC_FOR_DFP_RESULT(cc_dep1) \
+({ \
+ __asm__ volatile ( \
+ ".insn rre, 0xb3d60000,0,%[op]\n\t" /* LTDTR */ \
+ "ipm %[psw]\n\t" : [psw] "=d"(psw) \
+ : [op] "f"(cc_dep1) \
+ : "cc", "f0"); \
+ psw >> 28; /* cc */ \
+})
+
/* Return the value of the condition code from the supplied thunk parameters.
This is not the value of the PSW. It is the value of the 2 CC bits within
return S390_CC_FOR_BFP128_UCONVERT(".insn rrf,0xb3ae0000", cc_dep1,
cc_dep2, cc_ndep);
+ case S390_CC_OP_DFP_RESULT_64:
+ return S390_CC_FOR_DFP_RESULT(cc_dep1);
default:
break;
static __inline__ IRExpr *get_fpr_dw0(UInt);
static __inline__ void put_fpr_dw0(UInt, IRExpr *);
+static __inline__ IRExpr *get_dpr_dw0(UInt);
+static __inline__ void put_dpr_dw0(UInt, IRExpr *);
/* Read a floating point register pair and combine their contents into a
128-bit value */
return IRExpr_Get(fpr_dw0_offset(archreg), Ity_F64);
}
+/* Write double word #0 of a fpr containg DFP value to the guest state. */
+static __inline__ void
+put_dpr_dw0(UInt archreg, IRExpr *expr)
+{
+ vassert(typeOfIRExpr(irsb->tyenv, expr) == Ity_D64);
+
+ stmt(IRStmt_Put(fpr_dw0_offset(archreg), expr));
+}
+
+/* Read double word #0 of a fpr register containing DFP value. */
+static __inline__ IRExpr *
+get_dpr_dw0(UInt archreg)
+{
+ return IRExpr_Get(fpr_dw0_offset(archreg), Ity_D64);
+}
/*------------------------------------------------------------*/
/*--- gpr registers ---*/
So: IR = (s390 ^ ((s390 << 1) & 2))
*/
-#if 0 // fixs390: avoid compiler warnings about unused function
static IRExpr *
get_dfp_rounding_mode_from_fpc(void)
{
return mktemp(Ity_I32, rm);
}
-#endif
+
/*------------------------------------------------------------*/
/*--- Build IR for formats ---*/
s390_disasm(ENC4(MNM, FPR, FPR, FPR), mnm, r1, r3, r2);
}
+static void
+s390_format_RRF_FUFF2(HChar *(*irgen)(UChar, UChar, UChar, UChar),
+ UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ HChar *mnm = irgen(r3, m4, r1, r2);
+
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+ s390_disasm(ENC5(MNM, FPR, FPR, FPR, UINT), mnm, r1, r2, r3, m4);
+}
+
static void
s390_format_RRF_R0RR2(HChar *(*irgen)(UChar r3, UChar r1, UChar r2),
UChar r3, UChar r1, UChar r2)
return "ledbr";
}
+static HChar *
+s390_irgen_LTDTR(UChar r1, UChar r2)
+{
+ IRTemp result = newTemp(Ity_D64);
+
+ assign(result, get_dpr_dw0(r2));
+ put_dpr_dw0(r1, mkexpr(result));
+ s390_cc_thunk_putF(S390_CC_OP_DFP_RESULT_64, result);
+
+ return "ltdtr";
+}
+
static HChar *
s390_irgen_MEEBR(UChar r1, UChar r2)
{
return "sdb";
}
+static HChar *
+s390_irgen_ADTRA(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D64);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp result = newTemp(Ity_D64);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ /* when m4 = 0, S390_DFP_ROUND_PER_FPC_0 should be set.
+ since S390_DFP_ROUND_PER_FPC_0 is also 0, passing m4 is sufficient */
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_dpr_dw0(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, triop(Iop_AddD64, mkexpr(rounding_mode), mkexpr(op1),
+ mkexpr(op2)));
+ s390_cc_thunk_putF(S390_CC_OP_DFP_RESULT_64, result);
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return (m4 == 0) ? "adtr" : "adtra";
+}
+
+static HChar *
+s390_irgen_DDTRA(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D64);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp result = newTemp(Ity_D64);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ /* when m4 = 0, S390_DFP_ROUND_PER_FPC_0 should be set.
+ since S390_DFP_ROUND_PER_FPC_0 is also 0, passing m4 is sufficient */
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_dpr_dw0(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, triop(Iop_DivD64, mkexpr(rounding_mode), mkexpr(op1),
+ mkexpr(op2)));
+ s390_cc_thunk_putF(S390_CC_OP_DFP_RESULT_64, result);
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return (m4 == 0) ? "ddtr" : "ddtra";
+}
+
+static HChar *
+s390_irgen_MDTRA(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D64);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp result = newTemp(Ity_D64);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ /* when m4 = 0, S390_DFP_ROUND_PER_FPC_0 should be set.
+ since S390_DFP_ROUND_PER_FPC_0 is also 0, passing m4 is sufficient */
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_dpr_dw0(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, triop(Iop_MulD64, mkexpr(rounding_mode), mkexpr(op1),
+ mkexpr(op2)));
+ s390_cc_thunk_putF(S390_CC_OP_DFP_RESULT_64, result);
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return (m4 == 0) ? "mdtr" : "mdtra";
+}
+
+static HChar *
+s390_irgen_SDTRA(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D64);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp result = newTemp(Ity_D64);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ /* when m4 = 0, S390_DFP_ROUND_PER_FPC_0 should be set.
+ since S390_DFP_ROUND_PER_FPC_0 is also 0, passing m4 is sufficient */
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_dpr_dw0(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, triop(Iop_SubD64, mkexpr(rounding_mode), mkexpr(op1),
+ mkexpr(op2)));
+ s390_cc_thunk_putF(S390_CC_OP_DFP_RESULT_64, result);
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return (m4 == 0) ? "sdtr" : "sdtra";
+}
+
static HChar *
s390_irgen_CLC(UChar length, IRTemp start1, IRTemp start2)
struct {
unsigned int op : 16;
unsigned int r3 : 4;
- unsigned int : 4;
+ unsigned int m4 : 4;
unsigned int r1 : 4;
unsigned int r2 : 4;
} RRF4;
case 0xb3ca: /* CGXR */ goto unimplemented;
case 0xb3cd: s390_format_RRE_RF(s390_irgen_LGDR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
- case 0xb3d0: /* MDTR */ goto unimplemented;
- case 0xb3d1: /* DDTR */ goto unimplemented;
- case 0xb3d2: /* ADTR */ goto unimplemented;
- case 0xb3d3: /* SDTR */ goto unimplemented;
+ case 0xb3d0: s390_format_RRF_FUFF2(s390_irgen_MDTRA, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
+ case 0xb3d1: s390_format_RRF_FUFF2(s390_irgen_DDTRA, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
+ case 0xb3d2: s390_format_RRF_FUFF2(s390_irgen_ADTRA, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
+ case 0xb3d3: s390_format_RRF_FUFF2(s390_irgen_SDTRA, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
case 0xb3d4: /* LDETR */ goto unimplemented;
case 0xb3d5: /* LEDTR */ goto unimplemented;
- case 0xb3d6: /* LTDTR */ goto unimplemented;
+ case 0xb3d6: s390_format_RRE_FF(s390_irgen_LTDTR, ovl.fmt.RRE.r1,
+ ovl.fmt.RRE.r2); goto ok;
case 0xb3d7: /* FIDTR */ goto unimplemented;
case 0xb3d8: /* MXTR */ goto unimplemented;
case 0xb3d9: /* DXTR */ goto unimplemented;
addHRegUse(u, HRmRead, insn->variant.bfp_convert.op_lo);
break;
+ case S390_INSN_DFP_BINOP:
+ addHRegUse(u, HRmWrite, insn->variant.dfp_binop.dst_hi);
+ addHRegUse(u, HRmRead, insn->variant.dfp_binop.op2_hi); /* left */
+ addHRegUse(u, HRmRead, insn->variant.dfp_binop.op3_hi); /* right */
+ if (insn->size == 16) {
+ addHRegUse(u, HRmWrite, insn->variant.dfp_binop.dst_lo);
+ addHRegUse(u, HRmRead, insn->variant.dfp_binop.op2_lo); /* left */
+ addHRegUse(u, HRmRead, insn->variant.dfp_binop.op3_lo); /* right */
+ }
+ break;
+
case S390_INSN_MFENCE:
case S390_INSN_GZERO:
case S390_INSN_GADD:
lookupHRegRemap(m, insn->variant.bfp_convert.op_lo);
break;
+ case S390_INSN_DFP_BINOP:
+ insn->variant.dfp_binop.dst_hi =
+ lookupHRegRemap(m, insn->variant.dfp_binop.dst_hi);
+ insn->variant.dfp_binop.op2_hi =
+ lookupHRegRemap(m, insn->variant.dfp_binop.op2_hi);
+ insn->variant.dfp_binop.op3_hi =
+ lookupHRegRemap(m, insn->variant.dfp_binop.op3_hi);
+ if (insn->size == 16) {
+ insn->variant.dfp_binop.dst_lo =
+ lookupHRegRemap(m, insn->variant.dfp_binop.dst_lo);
+ insn->variant.dfp_binop.op2_lo =
+ lookupHRegRemap(m, insn->variant.dfp_binop.op2_lo);
+ insn->variant.dfp_binop.op3_lo =
+ lookupHRegRemap(m, insn->variant.dfp_binop.op3_lo);
+ }
+ break;
+
case S390_INSN_MFENCE:
case S390_INSN_GZERO:
case S390_INSN_GADD:
}
+static UChar *
+emit_RRF4(UChar *p, UInt op, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ ULong the_insn = op;
+
+ the_insn |= ((ULong)r3) << 12;
+ the_insn |= ((ULong)m4) << 8;
+ the_insn |= ((ULong)r1) << 4;
+ the_insn |= ((ULong)r2) << 0;
+
+ return emit_4bytes(p, the_insn);
+}
+
+
static UChar *
emit_RS(UChar *p, UInt op, UChar r1, UChar r3, UChar b2, UShort d2)
{
}
+static UChar *
+s390_emit_ADTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+ if (m4 == 0)
+ s390_disasm(ENC4(MNM, FPR, FPR, FPR), "adtr", r1, r2, r3);
+ else
+ s390_disasm(ENC5(MNM, FPR, UINT, FPR, FPR), "adtra", r1, m4, r2, r3);
+ }
+
+ return emit_RRF4(p, 0xb3d20000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_DDTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+ if (m4 == 0)
+ s390_disasm(ENC4(MNM, FPR, FPR, FPR), "ddtr", r1, r2, r3);
+ else
+ s390_disasm(ENC5(MNM, FPR, UINT, FPR, FPR), "ddtra", r1, m4, r2, r3);
+ }
+
+ return emit_RRF4(p, 0xb3d10000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_MDTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+ if (m4 == 0)
+ s390_disasm(ENC4(MNM, FPR, FPR, FPR), "mdtr", r1, r2, r3);
+ else
+ s390_disasm(ENC5(MNM, FPR, UINT, FPR, FPR), "mdtra", r1, m4, r2, r3);
+ }
+
+ return emit_RRF4(p, 0xb3d00000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_SDTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+ vassert(m4 == 0 || s390_host_has_fpext);
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+ if (m4 == 0)
+ s390_disasm(ENC4(MNM, FPR, FPR, FPR), "sdtr", r1, r2, r3);
+ else
+ s390_disasm(ENC5(MNM, FPR, UINT, FPR, FPR), "sdtra", r1, m4, r2, r3);
+ }
+
+ return emit_RRF4(p, 0xb3d30000, r3, m4, r1, r2);
+}
+
/* Provide a symbolic name for register "R0" */
#define R0 0
}
+s390_insn *
+s390_insn_dfp_binop(UChar size, s390_dfp_binop_t tag, HReg dst, HReg op2,
+ HReg op3, s390_dfp_round_t rounding_mode)
+{
+ s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
+
+ vassert(size == 8);
+
+ insn->tag = S390_INSN_DFP_BINOP;
+ insn->size = size;
+ insn->variant.dfp_binop.tag = tag;
+ insn->variant.dfp_binop.dst_hi = dst;
+ insn->variant.dfp_binop.op2_hi = op2;
+ insn->variant.dfp_binop.op3_hi = op3;
+ insn->variant.dfp_binop.dst_lo = INVALID_HREG;
+ insn->variant.dfp_binop.op2_lo = INVALID_HREG;
+ insn->variant.dfp_binop.op3_lo = INVALID_HREG;
+ insn->variant.dfp_binop.rounding_mode = rounding_mode;
+
+ return insn;
+}
+
+
s390_insn *
s390_insn_mfence(void)
{
insn->variant.bfp_convert.op_hi);
break;
+ case S390_INSN_DFP_BINOP:
+ switch (insn->variant.dfp_binop.tag) {
+ case S390_DFP_ADD: op = "v-dadd"; break;
+ case S390_DFP_SUB: op = "v-dsub"; break;
+ case S390_DFP_MUL: op = "v-dmul"; break;
+ case S390_DFP_DIV: op = "v-ddiv"; break;
+ default: goto fail;
+ }
+ s390_sprintf(buf, "%M %R,%R,%R", op,
+ insn->variant.dfp_binop.dst_hi,
+ insn->variant.dfp_binop.op2_hi,
+ insn->variant.dfp_binop.op3_hi);
+ break;
+
case S390_INSN_MFENCE:
s390_sprintf(buf, "%M", "v-mfence");
return buf; /* avoid printing "size = ..." which is meaningless */
}
+static UChar *
+s390_insn_dfp_binop_emit(UChar *buf, const s390_insn *insn)
+{
+ UInt r1 = hregNumber(insn->variant.dfp_binop.dst_hi);
+ UInt r2 = hregNumber(insn->variant.dfp_binop.op2_hi);
+ UInt r3 = hregNumber(insn->variant.dfp_binop.op3_hi);
+ UInt m4 = hregNumber(insn->variant.dfp_binop.rounding_mode);
+
+ switch (insn->size) {
+ case 8:
+ switch (insn->variant.dfp_binop.tag) {
+ case S390_DFP_ADD: return s390_emit_ADTRA(buf, r3, m4, r1, r2); break;
+ case S390_DFP_SUB: return s390_emit_SDTRA(buf, r3, m4, r1, r2); break;
+ case S390_DFP_MUL: return s390_emit_MDTRA(buf, r3, m4, r1, r2); break;
+ case S390_DFP_DIV: return s390_emit_DDTRA(buf, r3, m4, r1, r2); break;
+ default: goto fail;
+ }
+ break;
+ default: goto fail;
+ }
+
+ fail:
+ vpanic("s390_insn_dfp_binop_emit");
+}
+
+
static UChar *
s390_insn_mfence_emit(UChar *buf, const s390_insn *insn)
{
end = s390_insn_bfp_convert_emit(buf, insn);
break;
+ case S390_INSN_DFP_BINOP:
+ end = s390_insn_dfp_binop_emit(buf, insn);
+ break;
+
case S390_INSN_MFENCE:
end = s390_insn_mfence_emit(buf, insn);
break;
S390_INSN_BFP_TRIOP,
S390_INSN_BFP_COMPARE,
S390_INSN_BFP_CONVERT,
+ S390_INSN_DFP_BINOP, /* Decimal floating point */
S390_INSN_MFENCE,
S390_INSN_GZERO, /* Assign zero to a guest register */
S390_INSN_GADD, /* Add a value to a guest register */
} s390_conv_t;
+/* The kind of binary DFP operations */
+typedef enum {
+ S390_DFP_ADD,
+ S390_DFP_SUB,
+ S390_DFP_MUL,
+ S390_DFP_DIV
+} s390_dfp_binop_t;
+
+
/* Condition code. The encoding of the enumerators matches the value of
the mask field in the various branch opcodes. */
typedef enum {
HReg op2_hi; /* 128-bit operand high part; 32/64-bit opnd */
HReg op2_lo; /* 128-bit operand low part */
} bfp_compare;
+ struct {
+ s390_dfp_binop_t tag;
+ HReg dst_hi; /* 128-bit result high part; 64-bit result */
+ HReg dst_lo; /* 128-bit result low part */
+ HReg op2_hi; /* 128-bit operand high part; 64-bit opnd 1 */
+ HReg op2_lo; /* 128-bit operand low part */
+ HReg op3_hi; /* 128-bit operand high part; 64-bit opnd 2 */
+ HReg op3_lo; /* 128-bit operand low part */
+ s390_dfp_round_t rounding_mode;
+ } dfp_binop;
/* Miscellaneous */
struct {
s390_insn *s390_insn_bfp128_convert_from(UChar size, s390_conv_t,
HReg dst, HReg op_hi, HReg op_lo,
s390_bfp_round_t);
+s390_insn *s390_insn_dfp_binop(UChar size, s390_dfp_binop_t, HReg dst,
+ HReg op2, HReg op3,
+ s390_dfp_round_t rounding_mode);
s390_insn *s390_insn_mfence(void);
s390_insn *s390_insn_gzero(UChar size, UInt offset);
s390_insn *s390_insn_gadd(UChar size, UInt offset, UChar delta, ULong value);
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
/* 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)
{
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
}
+/*---------------------------------------------------------*/
+/*--- 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 ---*/
/*---------------------------------------------------------*/
/* 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;
}
return;
}
+ case Ity_D64:
+ src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
+ dst = lookupIRTemp(env, tmp);
+ break;
+
default:
goto stmt_fail;
}
case Ity_F32:
case Ity_F64:
+ case Ity_D64:
hreg = mkHReg(j++, HRcFlt64, True);
break;