s390_disasm(ENC4(MNM, FPR, FPR, FPR), mnm, r1, r3, r2);
}
+static void
+s390_format_RRF_F0FR(const HChar *(*irgen)(UChar, UChar, UChar),
+ UChar r3, UChar r1, UChar r2)
+{
+ const HChar *mnm = irgen(r3, r1, r2);
+
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+ s390_disasm(ENC4(MNM, FPR, FPR, GPR), mnm, r1, r3, r2);
+}
+
static void
s390_format_RRF_UUFF(const HChar *(*irgen)(UChar m3, UChar m4, UChar r1,
UChar r2),
s390_disasm(ENC4(MNM, FPR, FPR, FPR), mnm, r1, r3, r2);
}
+static void
+s390_format_RRF_FFRU(const HChar *(*irgen)(UChar, UChar, UChar, UChar),
+ UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ const HChar *mnm = irgen(r3, m4, r1, r2);
+
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+ s390_disasm(ENC5(MNM, FPR, FPR, GPR, UINT), mnm, r1, r3, r2, m4);
+}
+
+static void
+s390_format_RRF_FUFF(const HChar *(*irgen)(UChar, UChar, UChar, UChar),
+ UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ const HChar *mnm = irgen(r3, m4, r1, r2);
+
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_FE))
+ s390_disasm(ENC5(MNM, FPR, FPR, FPR, UINT), mnm, r1, r3, r2, m4);
+}
+
static void
s390_format_RRF_FUFF2(const HChar *(*irgen)(UChar, UChar, UChar, UChar),
UChar r3, UChar m4, UChar r1, UChar r2)
return (m4 == 0) ? "dxtr" : "dxtra";
}
+static const HChar *
+s390_irgen_EEDTR(UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+
+ put_gpr_dw0(r1, unop(Iop_ExtractExpD64, get_dpr_dw0(r2)));
+ return "eedtr";
+}
+
+static const HChar *
+s390_irgen_EEXTR(UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+
+ put_gpr_dw0(r1, unop(Iop_ExtractExpD128, get_dpr_pair(r2)));
+ return "eextr";
+}
+
static const HChar *
s390_irgen_ESDTR(UChar r1, UChar r2)
{
return "esxtr";
}
+static const HChar *
+s390_irgen_IEDTR(UChar r3, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_I64);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp result = newTemp(Ity_D64);
+
+ vassert(s390_host_has_dfp);
+
+ assign(op1, get_gpr_dw0(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, binop(Iop_InsertExpD64, mkexpr(op1), mkexpr(op2)));
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return "iedtr";
+}
+
+static const HChar *
+s390_irgen_IEXTR(UChar r3, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_I64);
+ IRTemp op2 = newTemp(Ity_D128);
+ IRTemp result = newTemp(Ity_D128);
+
+ vassert(s390_host_has_dfp);
+
+ assign(op1, get_gpr_dw0(r2));
+ assign(op2, get_dpr_pair(r3));
+ assign(result, binop(Iop_InsertExpD128, mkexpr(op1), mkexpr(op2)));
+ put_dpr_pair(r1, mkexpr(result));
+
+ return "iextr";
+}
+
static const HChar *
s390_irgen_LDETR(UChar m4 __attribute__((unused)), UChar r1, UChar r2)
{
return (m4 == 0) ? "mxtr" : "mxtra";
}
+static const HChar *
+s390_irgen_QADTR(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);
+ /* If fpext is not installed and m4 is in 1:7,
+ rounding mode performed is unpredictable */
+ if (! s390_host_has_fpext && m4 > 0 && m4 < 8) {
+ emulation_warning(EmWarn_S390X_fpext_rounding);
+ m4 = S390_DFP_ROUND_PER_FPC_0;
+ }
+
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_dpr_dw0(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, triop(Iop_QuantizeD64, mkexpr(rounding_mode), mkexpr(op1),
+ mkexpr(op2)));
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return "qadtr";
+}
+
+static const HChar *
+s390_irgen_QAXTR(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_D128);
+ IRTemp op2 = newTemp(Ity_D128);
+ IRTemp result = newTemp(Ity_D128);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ /* If fpext is not installed and m4 is in 1:7,
+ rounding mode performed is unpredictable */
+ if (! s390_host_has_fpext && m4 > 0 && m4 < 8) {
+ emulation_warning(EmWarn_S390X_fpext_rounding);
+ m4 = S390_DFP_ROUND_PER_FPC_0;
+ }
+
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_dpr_pair(r2));
+ assign(op2, get_dpr_pair(r3));
+ assign(result, triop(Iop_QuantizeD128, mkexpr(rounding_mode), mkexpr(op1),
+ mkexpr(op2)));
+ put_dpr_pair(r1, mkexpr(result));
+
+ return "qaxtr";
+}
+
+static const HChar *
+s390_irgen_RRDTR(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_I8);
+ IRTemp op2 = newTemp(Ity_D64);
+ IRTemp result = newTemp(Ity_D64);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ /* If fpext is not installed and m4 is in 1:7,
+ rounding mode performed is unpredictable */
+ if (! s390_host_has_fpext && m4 > 0 && m4 < 8) {
+ emulation_warning(EmWarn_S390X_fpext_rounding);
+ m4 = S390_DFP_ROUND_PER_FPC_0;
+ }
+
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_gpr_b7(r2));
+ assign(op2, get_dpr_dw0(r3));
+ assign(result, triop(Iop_SignificanceRoundD64, mkexpr(rounding_mode),
+ mkexpr(op1), mkexpr(op2)));
+ put_dpr_dw0(r1, mkexpr(result));
+
+ return "rrdtr";
+}
+
+static const HChar *
+s390_irgen_RRXTR(UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ IRTemp op1 = newTemp(Ity_I8);
+ IRTemp op2 = newTemp(Ity_D128);
+ IRTemp result = newTemp(Ity_D128);
+ IRTemp rounding_mode;
+
+ vassert(s390_host_has_dfp);
+ /* If fpext is not installed and m4 is in 1:7,
+ rounding mode performed is unpredictable */
+ if (! s390_host_has_fpext && m4 > 0 && m4 < 8) {
+ emulation_warning(EmWarn_S390X_fpext_rounding);
+ m4 = S390_DFP_ROUND_PER_FPC_0;
+ }
+
+ rounding_mode = encode_dfp_rounding_mode(m4);
+ assign(op1, get_gpr_b7(r2));
+ assign(op2, get_dpr_pair(r3));
+ assign(result, triop(Iop_SignificanceRoundD128, mkexpr(rounding_mode),
+ mkexpr(op1), mkexpr(op2)));
+ put_dpr_pair(r1, mkexpr(result));
+
+ return "rrxtr";
+}
+
static const HChar *
s390_irgen_SDTRA(UChar r3, UChar m4, UChar r1, UChar r2)
{
case 0xb3e3: /* CSDTR */ goto unimplemented;
case 0xb3e4: s390_format_RRE_FF(s390_irgen_CDTR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
- case 0xb3e5: /* EEDTR */ goto unimplemented;
+ case 0xb3e5: s390_format_RRE_RF(s390_irgen_EEDTR, ovl.fmt.RRE.r1,
+ ovl.fmt.RRE.r2); goto ok;
case 0xb3e7: s390_format_RRE_RF(s390_irgen_ESDTR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
case 0xb3e8: /* KXTR */ goto unimplemented;
case 0xb3eb: /* CSXTR */ goto unimplemented;
case 0xb3ec: s390_format_RRE_FF(s390_irgen_CXTR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
- case 0xb3ed: /* EEXTR */ goto unimplemented;
+ case 0xb3ed: s390_format_RRE_RF(s390_irgen_EEXTR, ovl.fmt.RRE.r1,
+ ovl.fmt.RRE.r2); goto ok;
case 0xb3ef: s390_format_RRE_RF(s390_irgen_ESXTR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
case 0xb3f1: s390_format_RRF_UUFR(s390_irgen_CDGTRA, ovl.fmt.RRF2.m3,
case 0xb3f3: /* CDSTR */ goto unimplemented;
case 0xb3f4: s390_format_RRE_FF(s390_irgen_CEDTR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
- case 0xb3f5: /* QADTR */ goto unimplemented;
- case 0xb3f6: /* IEDTR */ goto unimplemented;
- case 0xb3f7: /* RRDTR */ goto unimplemented;
+ case 0xb3f5: s390_format_RRF_FUFF(s390_irgen_QADTR, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
+ case 0xb3f6: s390_format_RRF_F0FR(s390_irgen_IEDTR, ovl.fmt.RRF3.r3,
+ ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2); goto ok;
+ case 0xb3f7: s390_format_RRF_FFRU(s390_irgen_RRDTR, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
case 0xb3f9: s390_format_RRF_UUFR(s390_irgen_CXGTR, ovl.fmt.RRF2.m3,
ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1,
ovl.fmt.RRF2.r2); goto ok;
case 0xb3fb: /* CXSTR */ goto unimplemented;
case 0xb3fc: s390_format_RRE_FF(s390_irgen_CEXTR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
- case 0xb3fd: /* QAXTR */ goto unimplemented;
- case 0xb3fe: /* IEXTR */ goto unimplemented;
- case 0xb3ff: /* RRXTR */ goto unimplemented;
+ case 0xb3fd: s390_format_RRF_FUFF(s390_irgen_QAXTR, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
+ case 0xb3fe: s390_format_RRF_F0FR(s390_irgen_IEXTR, ovl.fmt.RRF3.r3,
+ ovl.fmt.RRF3.r1, ovl.fmt.RRF3.r2); goto ok;
+ case 0xb3ff: s390_format_RRF_FFRU(s390_irgen_RRXTR, ovl.fmt.RRF4.r3,
+ ovl.fmt.RRF4.m4, ovl.fmt.RRF4.r1,
+ ovl.fmt.RRF4.r2); goto ok;
case 0xb900: s390_format_RRE_RR(s390_irgen_LPGR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
case 0xb901: s390_format_RRE_RR(s390_irgen_LNGR, ovl.fmt.RRE.r1,
addHRegUse(u, HRmRead, insn->variant.dfp_convert.op_lo); /* operand */
break;
+ case S390_INSN_DFP_REROUND:
+ addHRegUse(u, HRmWrite, insn->variant.dfp_reround.dst_hi);
+ addHRegUse(u, HRmRead, insn->variant.dfp_reround.op2); /* left */
+ addHRegUse(u, HRmRead, insn->variant.dfp_reround.op3_hi); /* right */
+ if (insn->size == 16) {
+ addHRegUse(u, HRmWrite, insn->variant.dfp_reround.dst_lo);
+ addHRegUse(u, HRmRead, insn->variant.dfp_reround.op3_lo); /* right */
+ }
+ break;
+
case S390_INSN_MIMM:
s390_amode_get_reg_usage(u, insn->variant.mimm.dst);
break;
lookupHRegRemap(m, insn->variant.dfp_convert.op_lo);
break;
+ case S390_INSN_DFP_REROUND:
+ insn->variant.dfp_reround.dst_hi =
+ lookupHRegRemap(m, insn->variant.dfp_reround.dst_hi);
+ insn->variant.dfp_reround.op2 =
+ lookupHRegRemap(m, insn->variant.dfp_reround.op2);
+ insn->variant.dfp_reround.op3_hi =
+ lookupHRegRemap(m, insn->variant.dfp_reround.op3_hi);
+ if (insn->size == 16) {
+ insn->variant.dfp_reround.dst_lo =
+ lookupHRegRemap(m, insn->variant.dfp_reround.dst_lo);
+ insn->variant.dfp_reround.op3_lo =
+ lookupHRegRemap(m, insn->variant.dfp_reround.op3_lo);
+ }
+ break;
+
case S390_INSN_MIMM:
s390_amode_map_regs(m, insn->variant.mimm.dst);
break;
}
+static UChar *
+s390_emit_EEDTR(UChar *p, UChar r1, UChar r2)
+{
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC3(MNM, GPR, FPR), "eedtr", r1, r2);
+
+ return emit_RRE(p, 0xb3e50000, r1, r2);
+}
+
+
+static UChar *
+s390_emit_EEXTR(UChar *p, UChar r1, UChar r2)
+{
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC3(MNM, GPR, FPR), "eextr", r1, r2);
+
+ return emit_RRE(p, 0xb3ed0000, r1, r2);
+}
+
+
static UChar *
s390_emit_ESDTR(UChar *p, UChar r1, UChar r2)
{
}
+static UChar *
+s390_emit_IEDTR(UChar *p, UChar r3, UChar r1, UChar r2)
+{
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC4(MNM, FPR, FPR, GPR), "iedtr", r1, r3, r2);
+
+ return emit_RRF(p, 0xb3f60000, r3, r1, r2);
+}
+
+
+static UChar *
+s390_emit_IEXTR(UChar *p, UChar r3, UChar r1, UChar r2)
+{
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC4(MNM, FPR, FPR, GPR), "iextr", r1, r3, r2);
+
+ return emit_RRF(p, 0xb3fe0000, r3, r1, r2);
+}
+
+
static UChar *
s390_emit_LDETR(UChar *p, UChar m4, UChar r1, UChar r2)
{
}
+static UChar *
+s390_emit_QADTR(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC5(MNM, FPR, FPR, FPR, UINT), "qadtr", r1, r3, r2, m4);
+
+ return emit_RRF4(p, 0xb3f50000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_QAXTR(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC5(MNM, FPR, FPR, FPR, UINT), "qaxtr", r1, r3, r2, m4);
+
+ return emit_RRF4(p, 0xb3fd0000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_RRDTR(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC5(MNM, FPR, FPR, GPR, UINT), "rrdtr", r1, r3, r2, m4);
+
+ return emit_RRF4(p, 0xb3f70000, r3, m4, r1, r2);
+}
+
+
+static UChar *
+s390_emit_RRXTR(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
+{
+ vassert(s390_host_has_dfp);
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
+ s390_disasm(ENC5(MNM, FPR, FPR, GPR, UINT), "rrxtr", r1, r3, r2, m4);
+
+ return emit_RRF4(p, 0xb3ff0000, r3, m4, r1, r2);
+}
+
+
static UChar *
s390_emit_SDTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
{
}
+s390_insn *
+s390_insn_dfp_reround(UChar size, 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_REROUND;
+ insn->size = size;
+ insn->variant.dfp_reround.dst_hi = dst;
+ insn->variant.dfp_reround.op2 = op2;
+ insn->variant.dfp_reround.op3_hi = op3;
+ insn->variant.dfp_reround.dst_lo = INVALID_HREG;
+ insn->variant.dfp_reround.op3_lo = INVALID_HREG;
+ insn->variant.dfp_reround.rounding_mode = rounding_mode;
+
+ return insn;
+}
+
+
s390_insn *
s390_insn_dfp128_binop(UChar size, s390_dfp_binop_t tag, HReg dst_hi,
HReg dst_lo, HReg op2_hi, HReg op2_lo, HReg op3_hi,
}
+s390_insn *
+s390_insn_dfp128_reround(UChar size, HReg dst_hi, HReg dst_lo, HReg op2,
+ HReg op3_hi, HReg op3_lo,
+ s390_dfp_round_t rounding_mode)
+{
+ s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
+
+ vassert(size == 16);
+ vassert(is_valid_fp128_regpair(dst_hi, dst_lo));
+ vassert(is_valid_fp128_regpair(op3_hi, op3_lo));
+
+ insn->tag = S390_INSN_DFP_REROUND;
+ insn->size = size;
+ insn->variant.dfp_reround.dst_hi = dst_hi;
+ insn->variant.dfp_reround.dst_lo = dst_lo;
+ insn->variant.dfp_reround.op2 = op2;
+ insn->variant.dfp_reround.op3_hi = op3_hi;
+ insn->variant.dfp_reround.op3_lo = op3_lo;
+ insn->variant.dfp_reround.rounding_mode = rounding_mode;
+
+ return insn;
+}
+
+
s390_insn *
s390_insn_mfence(void)
{
case S390_DFP_SUB: op = "v-dsub"; break;
case S390_DFP_MUL: op = "v-dmul"; break;
case S390_DFP_DIV: op = "v-ddiv"; break;
+ case S390_DFP_QUANTIZE: op = "v-dqua"; break;
default: goto fail;
}
s390_sprintf(buf, "%M %R,%R,%R", op, dfp_binop->dst_hi,
case S390_INSN_DFP_UNOP:
switch (insn->variant.dfp_unop.tag) {
+ case S390_DFP_EXTRACT_EXP_D64:
+ case S390_DFP_EXTRACT_EXP_D128: op = "v-d2exp"; break;
case S390_DFP_EXTRACT_SIG_D64:
case S390_DFP_EXTRACT_SIG_D128: op = "v-d2sig"; break;
default: goto fail;
switch (insn->variant.dfp_intop.tag) {
case S390_DFP_SHIFT_LEFT: op = "v-dshl"; break;
case S390_DFP_SHIFT_RIGHT: op = "v-dshr"; break;
+ case S390_DFP_INSERT_EXP: op = "v-diexp"; break;
default: goto fail;
}
s390_sprintf(buf, "%M %R,%R,%R", op, insn->variant.dfp_intop.dst_hi,
insn->variant.dfp_convert.op_hi);
break;
+ case S390_INSN_DFP_REROUND:
+ s390_sprintf(buf, "%M %R,%R,%R", "v-drrnd",
+ insn->variant.dfp_reround.dst_hi,
+ insn->variant.dfp_reround.op2,
+ insn->variant.dfp_reround.op3_hi);
+ break;
+
case S390_INSN_MFENCE:
s390_sprintf(buf, "%M", "v-mfence");
return buf; /* avoid printing "size = ..." which is meaningless */
case S390_DFP_SUB: return s390_emit_SDTRA(buf, r3, m4, r1, r2);
case S390_DFP_MUL: return s390_emit_MDTRA(buf, r3, m4, r1, r2);
case S390_DFP_DIV: return s390_emit_DDTRA(buf, r3, m4, r1, r2);
+ case S390_DFP_QUANTIZE: return s390_emit_QADTR(buf, r3, m4, r1, r2);
default: goto fail;
}
break;
case S390_DFP_SUB: return s390_emit_SXTRA(buf, r3, m4, r1, r2);
case S390_DFP_MUL: return s390_emit_MXTRA(buf, r3, m4, r1, r2);
case S390_DFP_DIV: return s390_emit_DXTRA(buf, r3, m4, r1, r2);
+ case S390_DFP_QUANTIZE: return s390_emit_QAXTR(buf, r3, m4, r1, r2);
default: goto fail;
}
break;
}
+static UChar *
+s390_insn_dfp_reround_emit(UChar *buf, const s390_insn *insn)
+{
+ UInt r1 = hregNumber(insn->variant.dfp_reround.dst_hi);
+ UInt r2 = hregNumber(insn->variant.dfp_reround.op2);
+ UInt r3 = hregNumber(insn->variant.dfp_reround.op3_hi);
+ s390_dfp_round_t m4 = insn->variant.dfp_reround.rounding_mode;
+
+ switch (insn->size) {
+ case 8:
+ return s390_emit_RRDTR(buf, r3, m4, r1, r2);
+
+ case 16:
+ return s390_emit_RRXTR(buf, r3, m4, r1, r2);
+
+ default: goto fail;
+ }
+ fail:
+ vpanic("s390_insn_dfp_reround_emit");
+}
+
+
static UChar *
s390_insn_dfp_unop_emit(UChar *buf, const s390_insn *insn)
{
UInt r2 = hregNumber(insn->variant.dfp_unop.op_hi);
switch (insn->variant.dfp_unop.tag) {
+ case S390_DFP_EXTRACT_EXP_D64: return s390_emit_EEDTR(buf, r1, r2); break;
+ case S390_DFP_EXTRACT_EXP_D128: return s390_emit_EEXTR(buf, r1, r2); break;
case S390_DFP_EXTRACT_SIG_D64: return s390_emit_ESDTR(buf, r1, r2); break;
case S390_DFP_EXTRACT_SIG_D128: return s390_emit_ESXTR(buf, r1, r2); break;
default: goto fail;
switch (insn->variant.dfp_intop.tag) {
case S390_DFP_SHIFT_LEFT: return s390_emit_SLDT(buf, r3, r1, r2);
case S390_DFP_SHIFT_RIGHT: return s390_emit_SRDT(buf, r3, r1, r2);
+ case S390_DFP_INSERT_EXP: return s390_emit_IEDTR(buf, r3, r1, r2);
default: goto fail;
}
break;
switch (insn->variant.dfp_intop.tag) {
case S390_DFP_SHIFT_LEFT: return s390_emit_SLXT(buf, r3, r1, r2);
case S390_DFP_SHIFT_RIGHT: return s390_emit_SRXT(buf, r3, r1, r2);
+ case S390_DFP_INSERT_EXP: return s390_emit_IEXTR(buf, r3, r1, r2);
default: goto fail;
}
break;
end = s390_insn_dfp_convert_emit(buf, insn);
break;
+ case S390_INSN_DFP_REROUND:
+ end = s390_insn_dfp_reround_emit(buf, insn);
+ break;
+
case S390_INSN_MFENCE:
end = s390_insn_mfence_emit(buf, insn);
break;
S390_INSN_DFP_INTOP,
S390_INSN_DFP_COMPARE,
S390_INSN_DFP_CONVERT,
+ S390_INSN_DFP_REROUND,
S390_INSN_MFENCE,
S390_INSN_MIMM, /* Assign an immediate constant to a memory location */
S390_INSN_MADD, /* Add a value to a memory location */
S390_DFP_ADD,
S390_DFP_SUB,
S390_DFP_MUL,
- S390_DFP_DIV
+ S390_DFP_DIV,
+ S390_DFP_QUANTIZE
} s390_dfp_binop_t;
/* The kind of unary DFP operations */
typedef enum {
+ S390_DFP_EXTRACT_EXP_D64,
+ S390_DFP_EXTRACT_EXP_D128,
S390_DFP_EXTRACT_SIG_D64,
S390_DFP_EXTRACT_SIG_D128,
} s390_dfp_unop_t;
/* The DFP operations with 2 operands one of them being integer */
typedef enum {
S390_DFP_SHIFT_LEFT,
- S390_DFP_SHIFT_RIGHT
+ S390_DFP_SHIFT_RIGHT,
+ S390_DFP_INSERT_EXP
} s390_dfp_intop_t;
/* The kind of DFP compare operations */
S390_DFP_COMPARE_EXP,
} s390_dfp_cmp_t;
-
/* The details of a CDAS insn. Carved out to keep the size of
s390_insn low */
typedef struct {
HReg op2_hi; /* 128-bit operand high part; 64-bit opnd 2 */
HReg op2_lo; /* 128-bit operand low part */
} dfp_compare;
+ struct {
+ s390_dfp_round_t rounding_mode;
+ HReg dst_hi; /* 128-bit result high part; 64-bit result */
+ HReg dst_lo; /* 128-bit result low part */
+ HReg op2; /* integer operand */
+ HReg op3_hi; /* 128-bit operand high part; 64-bit opnd */
+ HReg op3_lo; /* 128-bit operand low part */
+ } dfp_reround;
/* Miscellaneous */
struct {
HReg op1, HReg op2);
s390_insn *s390_insn_dfp_convert(UChar size, s390_dfp_conv_t tag, HReg dst,
HReg op, s390_dfp_round_t);
+s390_insn *s390_insn_dfp_reround(UChar size, HReg dst, HReg op2, HReg op3,
+ s390_dfp_round_t);
s390_insn *s390_insn_dfp128_binop(UChar size, s390_dfp_binop_t, HReg dst_hi,
HReg dst_lo, HReg op2_hi, HReg op2_lo,
HReg op3_hi, HReg op3_lo,
s390_insn *s390_insn_dfp128_convert_from(UChar size, s390_dfp_conv_t,
HReg dst, HReg op_hi, HReg op_lo,
s390_dfp_round_t);
+s390_insn *s390_insn_dfp128_reround(UChar size, HReg dst_hi, HReg dst_lo,
+ HReg op2, HReg op3_hi, HReg op3_lo,
+ s390_dfp_round_t);
s390_insn *s390_insn_mfence(void);
s390_insn *s390_insn_mimm(UChar size, s390_amode *dst, ULong value);
s390_insn *s390_insn_madd(UChar size, s390_amode *dst, UChar delta,
return dst;
}
- if (unop == Iop_ExtractSigD64) {
+ if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) {
+ s390_dfp_unop_t dfpop;
+ switch(unop) {
+ case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break;
+ case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break;
+ default: goto irreducible;
+ }
dst = newVRegI(env);
h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
- addInstr(env,
- s390_insn_dfp_unop(size, S390_DFP_EXTRACT_SIG_D64, dst, h1));
+ addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1));
return dst;
}
- if (unop == Iop_ExtractSigD128) {
+ if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) {
+ s390_dfp_unop_t dfpop;
HReg op_hi, op_lo, f13, f15;
+
+ switch(unop) {
+ case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break;
+ case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break;
+ default: goto irreducible;
+ }
dst = newVRegI(env);
s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
addInstr(env, s390_insn_move(8, f13, op_hi));
addInstr(env, s390_insn_move(8, f15, op_lo));
- addInstr(env, s390_insn_dfp128_unop(size, S390_DFP_EXTRACT_SIG_D128,
- dst, f13, f15));
+ addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15));
return dst;
}
s390_dfp_binop_t dfpop;
HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
- s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
- s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
-
/* We use non-virtual registers as pairs with (f9, f11) as op1,
(f12, f14) as op2 and (f13, f15) as destination) */
f9 = make_fpr(9);
f14 = make_fpr(14);
f15 = make_fpr(15);
- /* 1st operand --> (f9, f11) */
- addInstr(env, s390_insn_move(8, f9, op1_hi));
- addInstr(env, s390_insn_move(8, f11, op1_lo));
+ switch (op) {
+ case Iop_AddD128: dfpop = S390_DFP_ADD; goto evaluate_dfp128;
+ case Iop_SubD128: dfpop = S390_DFP_SUB; goto evaluate_dfp128;
+ case Iop_MulD128: dfpop = S390_DFP_MUL; goto evaluate_dfp128;
+ case Iop_DivD128: dfpop = S390_DFP_DIV; goto evaluate_dfp128;
+ case Iop_QuantizeD128: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128;
+
+ evaluate_dfp128: {
+ /* Process 1st operand */
+ s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);
+ /* 1st operand --> (f9, f11) */
+ addInstr(env, s390_insn_move(8, f9, op1_hi));
+ addInstr(env, s390_insn_move(8, f11, op1_lo));
- /* 2nd operand --> (f12, f14) */
- addInstr(env, s390_insn_move(8, f12, op2_hi));
- addInstr(env, s390_insn_move(8, f14, op2_lo));
+ /* Process 2nd operand */
+ s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
+ /* 2nd operand --> (f12, f14) */
+ addInstr(env, s390_insn_move(8, f12, op2_hi));
+ addInstr(env, s390_insn_move(8, f14, op2_lo));
- switch (op) {
- case Iop_AddD128: dfpop = S390_DFP_ADD; break;
- case Iop_SubD128: dfpop = S390_DFP_SUB; break;
- case Iop_MulD128: dfpop = S390_DFP_MUL; break;
- case Iop_DivD128: dfpop = S390_DFP_DIV; break;
- default:
- goto irreducible;
+ /* DFP arithmetic ops take rounding mode only when fpext is
+ installed. But, DFP quantize operation takes rm irrespective
+ of fpext facility . */
+ if (s390_host_has_fpext || dfpop == Iop_QuantizeD128) {
+ 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_dfp128_binop(16, dfpop, f13, f15, f9, f11,
+ f12, f14, rounding_mode));
+ /* Move result to virtual destination register */
+ *dst_hi = newVRegF(env);
+ *dst_lo = newVRegF(env);
+ addInstr(env, s390_insn_move(8, *dst_hi, f13));
+ addInstr(env, s390_insn_move(8, *dst_lo, f15));
+ return;
}
- /* DFP binary ops have insns with rounding mode field
- when the floating point extension facility is installed. */
- if (s390_host_has_fpext) {
+ case Iop_SignificanceRoundD128: {
+ /* Process 1st operand */
+ HReg op1 = s390_isel_int_expr(env, left);
+ /* Process 2nd operand */
+ s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
+ /* 2nd operand --> (f12, f14) */
+ addInstr(env, s390_insn_move(8, f12, op2_hi));
+ addInstr(env, s390_insn_move(8, f14, op2_lo));
+
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_dfp128_reround(16, f13, f15, op1, f12, f14,
+ rounding_mode));
+ /* Move result to virtual destination register */
+ *dst_hi = newVRegF(env);
+ *dst_lo = newVRegF(env);
+ addInstr(env, s390_insn_move(8, *dst_hi, f13));
+ addInstr(env, s390_insn_move(8, *dst_lo, f15));
+ return;
}
- addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
- f12, f14, rounding_mode));
-
- /* Move result to virtual destination register */
- *dst_hi = newVRegF(env);
- *dst_lo = newVRegF(env);
- addInstr(env, s390_insn_move(8, *dst_hi, f13));
- addInstr(env, s390_insn_move(8, *dst_lo, f15));
-
- return;
+ default:
+ goto irreducible;
+ }
}
/* --------- BINARY OP --------- */
return;
case Iop_ShlD128:
- case Iop_ShrD128: {
+ case Iop_ShrD128:
+ case Iop_InsertExpD128: {
HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
s390_dfp_intop_t intop;
- IRExpr *left = expr->Iex.Binop.arg1;
- IRExpr *right = expr->Iex.Binop.arg2;
+ IRExpr *dfp_op;
+ IRExpr *int_op;
switch (expr->Iex.Binop.op) {
- case Iop_ShlD128: intop = S390_DFP_SHIFT_LEFT; break;
- case Iop_ShrD128: intop = S390_DFP_SHIFT_RIGHT; break;
+ case Iop_ShlD128: /* (D128, I64) -> D128 */
+ intop = S390_DFP_SHIFT_LEFT;
+ dfp_op = expr->Iex.Binop.arg1;
+ int_op = expr->Iex.Binop.arg2;
+ break;
+ case Iop_ShrD128: /* (D128, I64) -> D128 */
+ intop = S390_DFP_SHIFT_RIGHT;
+ dfp_op = expr->Iex.Binop.arg1;
+ int_op = expr->Iex.Binop.arg2;
+ break;
+ case Iop_InsertExpD128: /* (I64, D128) -> D128 */
+ intop = S390_DFP_INSERT_EXP;
+ int_op = expr->Iex.Binop.arg1;
+ dfp_op = expr->Iex.Binop.arg2;
+ break;
default: goto irreducible;
}
f13 = make_fpr(13); /* 128 bit dfp destination */
f15 = make_fpr(15);
- s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* dfp operand */
+ /* Process dfp operand */
+ s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op);
+ /* op1 -> (f9,f11) */
addInstr(env, s390_insn_move(8, f9, op1_hi));
addInstr(env, s390_insn_move(8, f11, op1_lo));
- op2 = s390_isel_int_expr(env, right); /* int operand */
+ op2 = s390_isel_int_expr(env, int_op); /* int operand */
addInstr(env,
s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
}
case Iop_ShlD64:
- case Iop_ShrD64: {
+ case Iop_ShrD64:
+ case Iop_InsertExpD64: {
HReg op2;
HReg op3;
+ IRExpr *dfp_op;
+ IRExpr *int_op;
s390_dfp_intop_t intop;
- IRExpr *op1 = expr->Iex.Binop.arg1;
- IRExpr *shift = expr->Iex.Binop.arg2;
switch (expr->Iex.Binop.op) {
- case Iop_ShlD64: intop = S390_DFP_SHIFT_LEFT; break;
- case Iop_ShrD64: intop = S390_DFP_SHIFT_RIGHT; break;
+ case Iop_ShlD64: /* (D64, I64) -> D64 */
+ intop = S390_DFP_SHIFT_LEFT;
+ dfp_op = expr->Iex.Binop.arg1;
+ int_op = expr->Iex.Binop.arg2;
+ break;
+ case Iop_ShrD64: /* (D64, I64) -> D64 */
+ intop = S390_DFP_SHIFT_RIGHT;
+ dfp_op = expr->Iex.Binop.arg1;
+ int_op = expr->Iex.Binop.arg2;
+ break;
+ case Iop_InsertExpD64: /* (I64, D64) -> D64 */
+ intop = S390_DFP_INSERT_EXP;
+ int_op = expr->Iex.Binop.arg1;
+ dfp_op = expr->Iex.Binop.arg2;
+ break;
default: goto irreducible;
}
- op2 = s390_isel_int_expr(env, shift);
- op3 = s390_isel_dfp_expr(env, op1);
+ op2 = s390_isel_int_expr(env, int_op);
+ op3 = s390_isel_dfp_expr(env, dfp_op);
dst = newVRegF(env);
addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
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;
+ case Iop_AddD64: dfpop = S390_DFP_ADD; goto evaluate_dfp;
+ case Iop_SubD64: dfpop = S390_DFP_SUB; goto evaluate_dfp;
+ case Iop_MulD64: dfpop = S390_DFP_MUL; goto evaluate_dfp;
+ case Iop_DivD64: dfpop = S390_DFP_DIV; goto evaluate_dfp;
+ case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp;
+
+ evaluate_dfp: {
+ op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
+ op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
+ dst = newVRegF(env);
+ /* DFP arithmetic ops take rounding mode only when fpext is
+ installed. But, DFP quantize operation takes rm irrespective
+ of fpext facility . */
+ if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) {
+ 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;
}
- /* DFP binary ops have insns with rounding mode field
- when the floating point extension facility is installed. */
- if (s390_host_has_fpext) {
+
+ case Iop_SignificanceRoundD64:
+ op2 = s390_isel_int_expr(env, left); /* Process 1st operand */
+ op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
+ dst = newVRegF(env);
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_reround(size, dst, op2, op3,
+ rounding_mode));
+ return dst;
- addInstr(env,
- s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
- return dst;
+ default:
+ goto irreducible;
+ }
}
default: