From 4e7831d184db322f080b7a63c83ec759464063da Mon Sep 17 00:00:00 2001 From: Florian Krohm Date: Sat, 10 Nov 2012 22:34:14 +0000 Subject: [PATCH] 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 --- VEX/priv/guest_s390_defs.h | 3 +- VEX/priv/guest_s390_helpers.c | 12 +++ VEX/priv/guest_s390_toIR.c | 155 ++++++++++++++++++++++++++++-- VEX/priv/host_s390_defs.c | 172 ++++++++++++++++++++++++++++++++++ VEX/priv/host_s390_defs.h | 23 +++++ VEX/priv/host_s390_isel.c | 114 +++++++++++++++++++++- 6 files changed, 468 insertions(+), 11 deletions(-) diff --git a/VEX/priv/guest_s390_defs.h b/VEX/priv/guest_s390_defs.h index f28151c454..3e18b84412 100644 --- a/VEX/priv/guest_s390_defs.h +++ b/VEX/priv/guest_s390_defs.h @@ -135,7 +135,8 @@ enum { 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 }; /*------------------------------------------------------------*/ diff --git a/VEX/priv/guest_s390_helpers.c b/VEX/priv/guest_s390_helpers.c index eaddd29342..d4f31da5d6 100644 --- a/VEX/priv/guest_s390_helpers.c +++ b/VEX/priv/guest_s390_helpers.c @@ -1116,6 +1116,16 @@ decode_bfp_rounding_mode(UInt irrm) 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 @@ -1332,6 +1342,8 @@ s390_calculate_cc(ULong cc_op, ULong cc_dep1, ULong cc_dep2, ULong cc_ndep) 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; diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index 07486853c8..64a01b7f82 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -427,6 +427,8 @@ yield_if(IRExpr *condition) 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 */ @@ -907,6 +909,21 @@ get_fpr_dw0(UInt archreg) 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 ---*/ @@ -1481,7 +1498,6 @@ encode_bfp_rounding_mode(UChar mode) So: IR = (s390 ^ ((s390 << 1) & 2)) */ -#if 0 // fixs390: avoid compiler warnings about unused function static IRExpr * get_dfp_rounding_mode_from_fpc(void) { @@ -1541,7 +1557,7 @@ encode_dfp_rounding_mode(UChar mode) return mktemp(Ity_I32, rm); } -#endif + /*------------------------------------------------------------*/ /*--- Build IR for formats ---*/ @@ -1906,6 +1922,16 @@ s390_format_RRF_F0FF2(HChar *(*irgen)(UChar, UChar, UChar), 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) @@ -8849,6 +8875,18 @@ s390_irgen_LEDBR(UChar m3, UChar m4 __attribute__((unused)), 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) { @@ -8990,6 +9028,98 @@ s390_irgen_SDB(UChar r1, IRTemp op2addr) 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) @@ -12530,7 +12660,7 @@ s390_decode_4byte_and_irgen(UChar *bytes) 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; @@ -12982,13 +13112,22 @@ s390_decode_4byte_and_irgen(UChar *bytes) 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; diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index 6fb6d0bbd1..061b7e7a34 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -703,6 +703,17 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn) 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: @@ -935,6 +946,23 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn) 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: @@ -1115,6 +1143,20 @@ emit_RRF3(UChar *p, UInt op, UChar r3, UChar r1, UChar r2) } +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) { @@ -3830,6 +3872,69 @@ s390_emit_SXBR(UChar *p, UChar r1, UChar r2) } +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 @@ -4900,6 +5005,29 @@ s390_insn_bfp128_convert_from(UChar size, s390_conv_t tag, HReg dst, } +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) { @@ -5460,6 +5588,20 @@ s390_insn_as_string(const s390_insn *insn) 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 */ @@ -7522,6 +7664,32 @@ s390_insn_bfp_compare_emit(UChar *buf, const s390_insn *insn) } +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) { @@ -8111,6 +8279,10 @@ emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, 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; diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index d8f7dd6619..d123f706dc 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -137,6 +137,7 @@ typedef enum { 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 */ @@ -233,6 +234,15 @@ typedef enum { } 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 { @@ -487,6 +497,16 @@ typedef struct { 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 { @@ -592,6 +612,9 @@ s390_insn *s390_insn_bfp128_convert_to(UChar size, s390_conv_t, 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); diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index 6a958d1431..1d0ea6f669 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -135,6 +135,7 @@ static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *); 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 @@ get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm) /* 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 @@ get_dfp_rounding_mode(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 @@ -2222,6 +2221,107 @@ s390_isel_float_expr(ISelEnv *env, IRExpr *expr) } +/*---------------------------------------------------------*/ +/*--- 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 @@ s390_isel_stmt(ISelEnv *env, IRStmt *stmt) /* 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 @@ s390_isel_stmt(ISelEnv *env, IRStmt *stmt) 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 @@ iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host, case Ity_F32: case Ity_F64: + case Ity_D64: hreg = mkHReg(j++, HRcFlt64, True); break; -- 2.47.2