From: Florian Krohm Date: Thu, 14 Feb 2013 14:27:12 +0000 (+0000) Subject: s390: Support the following DFP insns: X-Git-Tag: svn/VALGRIND_3_9_0^2~110 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=66d4264a58b540f841cd0a18097501f151f3abd0;p=thirdparty%2Fvalgrind.git s390: Support the following DFP insns: - extract basied exponent - insert biased exponent - quantize - reround to significance Patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com). Part of fixing BZ #307113. git-svn-id: svn://svn.valgrind.org/vex/trunk@2684 --- diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index f1fc849098..b013e192bd 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -2015,6 +2015,16 @@ s390_format_RRF_F0FF(const HChar *(*irgen)(UChar, UChar, UChar), 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), @@ -2079,6 +2089,26 @@ s390_format_RRF_F0FF2(const HChar *(*irgen)(UChar, UChar, UChar), 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) @@ -9712,6 +9742,24 @@ s390_irgen_DXTRA(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) { @@ -9728,6 +9776,40 @@ s390_irgen_ESXTR(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) { @@ -9868,6 +9950,110 @@ s390_irgen_MXTRA(UChar r3, UChar m4, 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) { @@ -14077,7 +14263,8 @@ s390_decode_4byte_and_irgen(UChar *bytes) 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; @@ -14088,7 +14275,8 @@ s390_decode_4byte_and_irgen(UChar *bytes) 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, @@ -14098,9 +14286,14 @@ s390_decode_4byte_and_irgen(UChar *bytes) 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; @@ -14108,9 +14301,14 @@ s390_decode_4byte_and_irgen(UChar *bytes) 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, diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index 9bef0e9e1e..6b3d9b58bc 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -765,6 +765,16 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn) 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; @@ -1083,6 +1093,21 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn) 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; @@ -4445,6 +4470,26 @@ s390_emit_DXTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2) } +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) { @@ -4465,6 +4510,26 @@ s390_emit_ESXTR(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) { @@ -4551,6 +4616,50 @@ s390_emit_MXTRA(UChar *p, UChar r3, 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) { @@ -5867,6 +5976,27 @@ s390_insn_dfp_convert(UChar size, s390_dfp_conv_t tag, HReg dst, HReg op, } +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, @@ -6018,6 +6148,30 @@ s390_insn_dfp128_convert_from(UChar size, s390_dfp_conv_t tag, HReg dst, } +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) { @@ -6605,6 +6759,7 @@ s390_insn_as_string(const s390_insn *insn) 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, @@ -6614,6 +6769,8 @@ s390_insn_as_string(const s390_insn *insn) 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; @@ -6626,6 +6783,7 @@ s390_insn_as_string(const s390_insn *insn) 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, @@ -6672,6 +6830,13 @@ s390_insn_as_string(const s390_insn *insn) 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 */ @@ -8844,6 +9009,7 @@ s390_insn_dfp_binop_emit(UChar *buf, const s390_insn *insn) 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; @@ -8854,6 +9020,7 @@ s390_insn_dfp_binop_emit(UChar *buf, const s390_insn *insn) 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; @@ -8866,6 +9033,28 @@ s390_insn_dfp_binop_emit(UChar *buf, const s390_insn *insn) } +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) { @@ -8873,6 +9062,8 @@ 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; @@ -8894,6 +9085,7 @@ s390_insn_dfp_intop_emit(UChar *buf, const s390_insn *insn) 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; @@ -8902,6 +9094,7 @@ s390_insn_dfp_intop_emit(UChar *buf, const s390_insn *insn) 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; @@ -9658,6 +9851,10 @@ emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, s390_insn *insn, 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; diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index e13893da6b..05f1f67733 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -146,6 +146,7 @@ typedef enum { 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 */ @@ -270,11 +271,14 @@ typedef enum { 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; @@ -282,7 +286,8 @@ typedef enum { /* 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 */ @@ -291,7 +296,6 @@ typedef enum { 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 { @@ -509,6 +513,14 @@ 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 { @@ -626,6 +638,8 @@ s390_insn *s390_insn_dfp_compare(UChar size, s390_dfp_cmp_t, HReg dst, 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, @@ -643,6 +657,9 @@ s390_insn *s390_insn_dfp128_convert_to(UChar size, s390_dfp_conv_t, 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, diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index 1203459920..2f42afd3b6 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -1495,16 +1495,28 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) 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 */ @@ -1516,8 +1528,7 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) 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; } @@ -2417,9 +2428,6 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 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); @@ -2429,42 +2437,68 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 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 --------- */ @@ -2477,15 +2511,29 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 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; } @@ -2496,11 +2544,13 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 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)); @@ -2695,21 +2745,35 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr) } 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)); @@ -2780,29 +2844,43 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr) 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: