From: Florian Krohm Date: Sun, 13 Jan 2013 02:29:05 +0000 (+0000) Subject: s390: Support insns to convert between DFP values and signed/unsigned X-Git-Tag: svn/VALGRIND_3_9_0^2~155 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=036149f516a202a1e8d70c1c72074fd90642d1be;p=thirdparty%2Fvalgrind.git s390: Support insns to convert between DFP values and signed/unsigned integers. Patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com). Part of fixing BZ 307113. git-svn-id: svn://svn.valgrind.org/vex/trunk@2632 --- diff --git a/VEX/priv/guest_s390_defs.h b/VEX/priv/guest_s390_defs.h index 8d71d68e4d..58ae70fef7 100644 --- a/VEX/priv/guest_s390_defs.h +++ b/VEX/priv/guest_s390_defs.h @@ -144,7 +144,13 @@ enum { S390_CC_OP_DFP_TDC_128 = 46, S390_CC_OP_DFP_TDG_32 = 47, S390_CC_OP_DFP_TDG_64 = 48, - S390_CC_OP_DFP_TDG_128 = 49 + S390_CC_OP_DFP_TDG_128 = 49, + S390_CC_OP_DFP_64_TO_UINT_32 = 50, + S390_CC_OP_DFP_128_TO_UINT_32 = 51, + S390_CC_OP_DFP_64_TO_UINT_64 = 52, + S390_CC_OP_DFP_128_TO_UINT_64 = 53, + S390_CC_OP_DFP_64_TO_INT_32 = 54, + S390_CC_OP_DFP_128_TO_INT_32 = 55 }; /*------------------------------------------------------------*/ @@ -210,6 +216,12 @@ enum { | S390_CC_OP_DFP_TDG_32 | D value | Z group | | | S390_CC_OP_DFP_TDG_64 | D value | Z group | | | S390_CC_OP_DFP_TDG_128 | D value hi 64 bits | D value low 64 bits | Z group | + | S390_CC_OP_DFP_64_TO_UINT_32 | D source | Z rounding mode | | + | S390_CC_OP_DFP_128_TO_UINT_32 | D source hi 64 bits | D source low 64 bits | Z rounding mode | + | S390_CC_OP_DFP_64_TO_UINT_64 | D source | Z rounding mode | | + | S390_CC_OP_DFP_128_TO_UINT_64 | D source hi 64 bits | D source low 64 bits | Z rounding mode | + | S390_CC_OP_DFP_64_TO_INT_64 | D source | Z rounding mode | | + | S390_CC_OP_DFP_128_TO_INT_64 | D source hi 64 bits | D source low 64 bits | Z rounding mode | +--------------------------------+-----------------------+----------------------+-----------------+ */ diff --git a/VEX/priv/guest_s390_helpers.c b/VEX/priv/guest_s390_helpers.c index ee0463a7a6..3fce5df090 100644 --- a/VEX/priv/guest_s390_helpers.c +++ b/VEX/priv/guest_s390_helpers.c @@ -1155,6 +1155,33 @@ decode_bfp_rounding_mode(UInt irrm) psw >> 28; /* cc */ \ }) +/* Convert an IRRoundingModeDFP value to s390_dfp_round_t */ +#if defined(VGA_s390x) +static s390_dfp_round_t +decode_dfp_rounding_mode(UInt irrm) +{ + switch (irrm) { + case Irrm_DFP_NEAREST: + return S390_DFP_ROUND_NEAREST_EVEN_4; + case Irrm_DFP_NegINF: + return S390_DFP_ROUND_NEGINF_7; + case Irrm_DFP_PosINF: + return S390_DFP_ROUND_POSINF_6; + case Irrm_DFP_ZERO: + return S390_DFP_ROUND_ZERO_5; + case Irrm_DFP_NEAREST_TIE_AWAY_0: + return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1; + case Irrm_DFP_PREPARE_SHORTER: + return S390_DFP_ROUND_PREPARE_SHORT_3; + case Irrm_DFP_AWAY_FROM_ZERO: + return S390_DFP_ROUND_AWAY_0; + case Irrm_DFP_NEAREST_TIE_TOWARD_0: + return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0; + } + vpanic("decode_dfp_rounding_mode"); +} +#endif + #define S390_CC_FOR_DFP_RESULT(cc_dep1) \ ({ \ __asm__ volatile ( \ @@ -1204,6 +1231,216 @@ decode_bfp_rounding_mode(UInt irrm) psw >> 28; /* cc */ \ }) +#define S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,rounding_mode) \ + ({ \ + __asm__ volatile ( \ + opcode ",0,%[op]," #rounding_mode ",0\n\t" \ + "ipm %[psw]\n\t" : [psw] "=d"(psw) \ + : [op] "f"(cc_dep1) \ + : "cc", "r0"); \ + psw >> 28; /* cc */ \ + }) + +#define S390_CC_FOR_DFP_CONVERT(opcode,cc_dep1,cc_dep2) \ + ({ \ + UInt cc; \ + switch (decode_dfp_rounding_mode(cc_dep2)) { \ + case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \ + case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \ + cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,1); \ + break; \ + case S390_DFP_ROUND_PREPARE_SHORT_3: \ + case S390_DFP_ROUND_PREPARE_SHORT_15: \ + cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,3); \ + break; \ + case S390_DFP_ROUND_NEAREST_EVEN_4: \ + case S390_DFP_ROUND_NEAREST_EVEN_8: \ + cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,4); \ + break; \ + case S390_DFP_ROUND_ZERO_5: \ + case S390_DFP_ROUND_ZERO_9: \ + cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,5); \ + break; \ + case S390_DFP_ROUND_POSINF_6: \ + case S390_DFP_ROUND_POSINF_10: \ + cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,6); \ + break; \ + case S390_DFP_ROUND_NEGINF_7: \ + case S390_DFP_ROUND_NEGINF_11: \ + cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,7); \ + break; \ + case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \ + cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,13); \ + break; \ + case S390_DFP_ROUND_AWAY_0: \ + cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,14); \ + break; \ + default: \ + vpanic("unexpected dfp rounding mode"); \ + } \ + cc; \ + }) + +#define S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,rounding_mode) \ + ({ \ + __asm__ volatile ( \ + opcode ",0,%[op]," #rounding_mode ",0\n\t" \ + "ipm %[psw]\n\t" : [psw] "=d"(psw) \ + : [op] "f"(cc_dep1) \ + : "cc", "r0"); \ + psw >> 28; /* cc */ \ + }) + +#define S390_CC_FOR_DFP_UCONVERT(opcode,cc_dep1,cc_dep2) \ + ({ \ + UInt cc; \ + switch (decode_dfp_rounding_mode(cc_dep2)) { \ + case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \ + case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \ + cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,1); \ + break; \ + case S390_DFP_ROUND_PREPARE_SHORT_3: \ + case S390_DFP_ROUND_PREPARE_SHORT_15: \ + cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,3); \ + break; \ + case S390_DFP_ROUND_NEAREST_EVEN_4: \ + case S390_DFP_ROUND_NEAREST_EVEN_8: \ + cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,4); \ + break; \ + case S390_DFP_ROUND_ZERO_5: \ + case S390_DFP_ROUND_ZERO_9: \ + cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,5); \ + break; \ + case S390_DFP_ROUND_POSINF_6: \ + case S390_DFP_ROUND_POSINF_10: \ + cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,6); \ + break; \ + case S390_DFP_ROUND_NEGINF_7: \ + case S390_DFP_ROUND_NEGINF_11: \ + cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,7); \ + break; \ + case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \ + cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,13); \ + break; \ + case S390_DFP_ROUND_AWAY_0: \ + cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,14); \ + break; \ + default: \ + vpanic("unexpected dfp rounding mode"); \ + } \ + cc; \ + }) + +#define S390_CC_FOR_DFP128_CONVERT_AUX(opcode,hi,lo,rounding_mode) \ + ({ \ + __asm__ volatile ( \ + "ldr 4,%[high]\n\t" \ + "ldr 6,%[low]\n\t" \ + opcode ",0,4," #rounding_mode ",0\n\t" \ + "ipm %[psw]\n\t" : [psw] "=d"(psw) \ + : [high] "f"(hi), [low] "f"(lo) \ + : "cc", "r0", "f4", "f6"); \ + psw >> 28; /* cc */ \ + }) + +#define S390_CC_FOR_DFP128_CONVERT(opcode,cc_dep1,cc_dep2,cc_ndep) \ + ({ \ + UInt cc; \ + /* Recover the original DEP2 value. See comment near \ + s390_cc_thunk_put3 for rationale. */ \ + cc_dep2 = cc_dep2 ^ cc_ndep; \ + switch (decode_dfp_rounding_mode(cc_ndep)) { \ + case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \ + case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \ + cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,1); \ + break; \ + case S390_DFP_ROUND_PREPARE_SHORT_3: \ + case S390_DFP_ROUND_PREPARE_SHORT_15: \ + cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,3); \ + break; \ + case S390_DFP_ROUND_NEAREST_EVEN_4: \ + case S390_DFP_ROUND_NEAREST_EVEN_8: \ + cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,4); \ + break; \ + case S390_DFP_ROUND_ZERO_5: \ + case S390_DFP_ROUND_ZERO_9: \ + cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,5); \ + break; \ + case S390_DFP_ROUND_POSINF_6: \ + case S390_DFP_ROUND_POSINF_10: \ + cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,6); \ + break; \ + case S390_DFP_ROUND_NEGINF_7: \ + case S390_DFP_ROUND_NEGINF_11: \ + cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,7); \ + break; \ + case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \ + cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,13); \ + break; \ + case S390_DFP_ROUND_AWAY_0: \ + cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,14); \ + break; \ + default: \ + vpanic("unexpected dfp rounding mode"); \ + } \ + cc; \ + }) + +#define S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,hi,lo,rounding_mode) \ + ({ \ + __asm__ volatile ( \ + "ldr 4,%[high]\n\t" \ + "ldr 6,%[low]\n\t" \ + opcode ",0,4," #rounding_mode ",0\n\t" \ + "ipm %[psw]\n\t" : [psw] "=d"(psw) \ + : [high] "f"(hi), [low] "f"(lo) \ + : "cc", "r0", "f4", "f6"); \ + psw >> 28; /* cc */ \ + }) + +#define S390_CC_FOR_DFP128_UCONVERT(opcode,cc_dep1,cc_dep2,cc_ndep) \ + ({ \ + UInt cc; \ + /* Recover the original DEP2 value. See comment near \ + s390_cc_thunk_put3 for rationale. */ \ + cc_dep2 = cc_dep2 ^ cc_ndep; \ + switch (decode_dfp_rounding_mode(cc_ndep)) { \ + case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \ + case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \ + cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,1); \ + break; \ + case S390_DFP_ROUND_PREPARE_SHORT_3: \ + case S390_DFP_ROUND_PREPARE_SHORT_15: \ + cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,3); \ + break; \ + case S390_DFP_ROUND_NEAREST_EVEN_4: \ + case S390_DFP_ROUND_NEAREST_EVEN_8: \ + cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,4); \ + break; \ + case S390_DFP_ROUND_ZERO_5: \ + case S390_DFP_ROUND_ZERO_9: \ + cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,5); \ + break; \ + case S390_DFP_ROUND_POSINF_6: \ + case S390_DFP_ROUND_POSINF_10: \ + cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,6); \ + break; \ + case S390_DFP_ROUND_NEGINF_7: \ + case S390_DFP_ROUND_NEGINF_11: \ + cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,7); \ + break; \ + case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \ + cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,13); \ + break; \ + case S390_DFP_ROUND_AWAY_0: \ + cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,14); \ + break; \ + default: \ + vpanic("unexpected dfp rounding mode"); \ + } \ + 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 @@ -1446,6 +1683,27 @@ s390_calculate_cc(ULong cc_op, ULong cc_dep1, ULong cc_dep2, ULong cc_ndep) return S390_CC_FOR_DFP128_TD(".insn rxe, 0xed0000000059", cc_dep1, cc_dep2, cc_ndep); + case S390_CC_OP_DFP_64_TO_INT_32: /* CFDTR */ + return S390_CC_FOR_DFP_CONVERT(".insn rrf,0xb9410000", cc_dep1, cc_dep2); + + case S390_CC_OP_DFP_128_TO_INT_32: /* CFXTR */ + return S390_CC_FOR_DFP128_CONVERT(".insn rrf,0xb9490000", cc_dep1, + cc_dep2, cc_ndep); + + case S390_CC_OP_DFP_64_TO_UINT_32: /* CLFDTR */ + return S390_CC_FOR_DFP_UCONVERT(".insn rrf,0xb9430000", cc_dep1, cc_dep2); + + case S390_CC_OP_DFP_128_TO_UINT_32: /* CLFXTR */ + return S390_CC_FOR_DFP128_UCONVERT(".insn rrf,0xb94b0000", cc_dep1, + cc_dep2, cc_ndep); + + case S390_CC_OP_DFP_64_TO_UINT_64: /* CLGDTR */ + return S390_CC_FOR_DFP_UCONVERT(".insn rrf,0xb9420000", cc_dep1, cc_dep2); + + case S390_CC_OP_DFP_128_TO_UINT_64: /* CLGXTR */ + return S390_CC_FOR_DFP128_UCONVERT(".insn rrf,0xb94a0000", cc_dep1, + cc_dep2, cc_ndep); + default: break; } diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index 750250b935..ec9dbe4c4c 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -9300,6 +9300,154 @@ s390_irgen_CXTR(UChar r1, UChar r2) return "cxtr"; } +static const HChar * +s390_irgen_CDFTR(UChar m3 __attribute__((unused)), + UChar m4 __attribute__((unused)), UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op2 = newTemp(Ity_I32); + + assign(op2, get_gpr_w1(r2)); + put_dpr_dw0(r1, unop(Iop_I32StoD64, mkexpr(op2))); + } + return "cdftr"; +} + +static const HChar * +s390_irgen_CXFTR(UChar m3 __attribute__((unused)), + UChar m4 __attribute__((unused)), UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op2 = newTemp(Ity_I32); + + assign(op2, get_gpr_w1(r2)); + put_dpr_pair(r1, unop(Iop_I32StoD128, mkexpr(op2))); + } + return "cxftr"; +} + +static const HChar * +s390_irgen_CDLFTR(UChar m3 __attribute__((unused)), + UChar m4 __attribute__((unused)), UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op2 = newTemp(Ity_I32); + + assign(op2, get_gpr_w1(r2)); + put_dpr_dw0(r1, unop(Iop_I32UtoD64, mkexpr(op2))); + } + return "cdlftr"; +} + +static const HChar * +s390_irgen_CXLFTR(UChar m3 __attribute__((unused)), + UChar m4 __attribute__((unused)), UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op2 = newTemp(Ity_I32); + + assign(op2, get_gpr_w1(r2)); + put_dpr_pair(r1, unop(Iop_I32UtoD128, mkexpr(op2))); + } + return "cxlftr"; +} + +static const HChar * +s390_irgen_CDLGTR(UChar m3, UChar m4 __attribute__((unused)), + UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op2 = newTemp(Ity_I64); + + assign(op2, get_gpr_dw0(r2)); + put_dpr_dw0(r1, binop(Iop_I64UtoD64, + mkexpr(encode_dfp_rounding_mode(m3)), + mkexpr(op2))); + } + return "cdlgtr"; +} + +static const HChar * +s390_irgen_CXLGTR(UChar m3 __attribute__((unused)), + UChar m4 __attribute__((unused)), UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op2 = newTemp(Ity_I64); + + assign(op2, get_gpr_dw0(r2)); + put_dpr_pair(r1, unop(Iop_I64UtoD128, mkexpr(op2))); + } + return "cxlgtr"; +} + +static const HChar * +s390_irgen_CFDTR(UChar m3, UChar m4 __attribute__((unused)), + UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op = newTemp(Ity_D64); + IRTemp result = newTemp(Ity_I32); + IRTemp rounding_mode = encode_dfp_rounding_mode(m3); + + assign(op, get_dpr_dw0(r2)); + assign(result, binop(Iop_D64toI32S, mkexpr(rounding_mode), + mkexpr(op))); + put_gpr_w1(r1, mkexpr(result)); + s390_cc_thunk_putFZ(S390_CC_OP_DFP_64_TO_INT_32, op, rounding_mode); + } + return "cfdtr"; +} + +static const HChar * +s390_irgen_CFXTR(UChar m3, UChar m4 __attribute__((unused)), + UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op = newTemp(Ity_D128); + IRTemp result = newTemp(Ity_I32); + IRTemp rounding_mode = encode_dfp_rounding_mode(m3); + + assign(op, get_dpr_pair(r2)); + assign(result, binop(Iop_D128toI32S, mkexpr(rounding_mode), + mkexpr(op))); + put_gpr_w1(r1, mkexpr(result)); + s390_cc_thunk_put1d128Z(S390_CC_OP_DFP_128_TO_INT_32, op, rounding_mode); + } + return "cfxtr"; +} + static const HChar * s390_irgen_CEDTR(UChar r1, UChar r2) { @@ -9338,6 +9486,95 @@ s390_irgen_CEXTR(UChar r1, UChar r2) return "cextr"; } +static const HChar * +s390_irgen_CLFDTR(UChar m3, UChar m4 __attribute__((unused)), + UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op = newTemp(Ity_D64); + IRTemp result = newTemp(Ity_I32); + IRTemp rounding_mode = encode_dfp_rounding_mode(m3); + + assign(op, get_dpr_dw0(r2)); + assign(result, binop(Iop_D64toI32U, mkexpr(rounding_mode), + mkexpr(op))); + put_gpr_w1(r1, mkexpr(result)); + s390_cc_thunk_putFZ(S390_CC_OP_DFP_64_TO_UINT_32, op, rounding_mode); + } + return "clfdtr"; +} + +static const HChar * +s390_irgen_CLFXTR(UChar m3, UChar m4 __attribute__((unused)), + UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op = newTemp(Ity_D128); + IRTemp result = newTemp(Ity_I32); + IRTemp rounding_mode = encode_dfp_rounding_mode(m3); + + assign(op, get_dpr_pair(r2)); + assign(result, binop(Iop_D128toI32U, mkexpr(rounding_mode), + mkexpr(op))); + put_gpr_w1(r1, mkexpr(result)); + s390_cc_thunk_put1d128Z(S390_CC_OP_DFP_128_TO_UINT_32, op, rounding_mode); + } + return "clfxtr"; +} + +static const HChar * +s390_irgen_CLGDTR(UChar m3, UChar m4 __attribute__((unused)), + UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op = newTemp(Ity_D64); + IRTemp result = newTemp(Ity_I64); + IRTemp rounding_mode = encode_dfp_rounding_mode(m3); + + assign(op, get_dpr_dw0(r2)); + assign(result, binop(Iop_D64toI64U, mkexpr(rounding_mode), + mkexpr(op))); + put_gpr_dw0(r1, mkexpr(result)); + s390_cc_thunk_putFZ(S390_CC_OP_DFP_64_TO_UINT_64, op, rounding_mode); + } + return "clgdtr"; +} + +static const HChar * +s390_irgen_CLGXTR(UChar m3, UChar m4 __attribute__((unused)), + UChar r1, UChar r2) +{ + vassert(s390_host_has_dfp); + + if (! s390_host_has_fpext) { + emulation_failure(EmFail_S390X_fpext); + } else { + IRTemp op = newTemp(Ity_D128); + IRTemp result = newTemp(Ity_I64); + IRTemp rounding_mode = encode_dfp_rounding_mode(m3); + + assign(op, get_dpr_pair(r2)); + assign(result, binop(Iop_D128toI64U, mkexpr(rounding_mode), + mkexpr(op))); + put_gpr_dw0(r1, mkexpr(result)); + s390_cc_thunk_put1d128Z(S390_CC_OP_DFP_128_TO_UINT_64, op, + rounding_mode); + } + return "clgxtr"; +} + static const HChar * s390_irgen_DDTRA(UChar r3, UChar m4, UChar r1, UChar r2) { @@ -13836,20 +14073,44 @@ s390_decode_4byte_and_irgen(UChar *bytes) ovl.fmt.RRE.r2); goto ok; case 0xb93e: /* KIMD */ goto unimplemented; case 0xb93f: /* KLMD */ goto unimplemented; - case 0xb941: /* CFDTR */ goto unimplemented; - case 0xb942: /* CLGDTR */ goto unimplemented; - case 0xb943: /* CLFDTR */ goto unimplemented; + case 0xb941: s390_format_RRF_UURF(s390_irgen_CFDTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; + case 0xb942: s390_format_RRF_UURF(s390_irgen_CLGDTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; + case 0xb943: s390_format_RRF_UURF(s390_irgen_CLFDTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; case 0xb946: s390_format_RRE_RR(s390_irgen_BCTGR, ovl.fmt.RRE.r1, ovl.fmt.RRE.r2); goto ok; - case 0xb949: /* CFXTR */ goto unimplemented; - case 0xb94a: /* CLGXTR */ goto unimplemented; - case 0xb94b: /* CLFXTR */ goto unimplemented; - case 0xb951: /* CDFTR */ goto unimplemented; - case 0xb952: /* CDLGTR */ goto unimplemented; - case 0xb953: /* CDLFTR */ goto unimplemented; - case 0xb959: /* CXFTR */ goto unimplemented; - case 0xb95a: /* CXLGTR */ goto unimplemented; - case 0xb95b: /* CXLFTR */ goto unimplemented; + case 0xb949: s390_format_RRF_UURF(s390_irgen_CFXTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; + case 0xb94a: s390_format_RRF_UURF(s390_irgen_CLGXTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; + case 0xb94b: s390_format_RRF_UURF(s390_irgen_CLFXTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; + case 0xb951: s390_format_RRF_UUFR(s390_irgen_CDFTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; + case 0xb952: s390_format_RRF_UUFR(s390_irgen_CDLGTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; + case 0xb953: s390_format_RRF_UUFR(s390_irgen_CDLFTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; + case 0xb959: s390_format_RRF_UUFR(s390_irgen_CXFTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; + case 0xb95a: s390_format_RRF_UUFR(s390_irgen_CXLGTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; + case 0xb95b: s390_format_RRF_UUFR(s390_irgen_CXLFTR, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; case 0xb960: /* CGRT */ goto unimplemented; case 0xb961: /* CLGRT */ goto unimplemented; case 0xb972: /* CRT */ goto unimplemented; diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index 642c959d0e..035cc47bc1 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -4136,6 +4136,92 @@ s390_emit_CXTR(UChar *p, UChar r1, UChar r2) } +static UChar * +s390_emit_CDFTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) { + s390_disasm(ENC5(MNM, FPR, UINT, GPR, UINT), "cdftr", r1, m3, r2, m4); + } + + return emit_RRF2(p, 0xb9510000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_CXFTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) { + s390_disasm(ENC5(MNM, FPR, UINT, GPR, UINT), "cxftr", r1, m3, r2, m4); + } + + return emit_RRF2(p, 0xb9590000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_CDLFTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) + s390_disasm(ENC5(MNM, FPR, UINT, GPR, UINT), "cdlftr", r1, m3, r2, m4); + + return emit_RRF2(p, 0xb9530000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_CXLFTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) + s390_disasm(ENC5(MNM, FPR, UINT, GPR, UINT), "cxlftr", r1, m3, r2, m4); + + return emit_RRF2(p, 0xb95b0000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_CDLGTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) + s390_disasm(ENC5(MNM, FPR, UINT, GPR, UINT), "cdlgtr", r1, m3, r2, m4); + + return emit_RRF2(p, 0xb9520000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_CXLGTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) + s390_disasm(ENC5(MNM, FPR, UINT, GPR, UINT), "cxlgtr", r1, m3, r2, m4); + + return emit_RRF2(p, 0xb95a0000, m3, m4, r1, r2); +} + + static UChar * s390_emit_CEDTR(UChar *p, UChar r1, UChar r2) { @@ -4156,6 +4242,92 @@ s390_emit_CEXTR(UChar *p, UChar r1, UChar r2) } +static UChar * +s390_emit_CFDTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) { + s390_disasm(ENC5(MNM, GPR, UINT, FPR, UINT), "cfdtr", r1, m3, r2, m4); + } + + return emit_RRF2(p, 0xb9410000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_CFXTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) { + s390_disasm(ENC5(MNM, GPR, UINT, FPR, UINT), "cfxtr", r1, m3, r2, m4); + } + + return emit_RRF2(p, 0xb9490000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_CLFDTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) + s390_disasm(ENC5(MNM, GPR, UINT, FPR, UINT), "clfdtr", r1, m3, r2, m4); + + return emit_RRF2(p, 0xb9430000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_CLFXTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) + s390_disasm(ENC5(MNM, GPR, UINT, FPR, UINT), "clfxtr", r1, m3, r2, m4); + + return emit_RRF2(p, 0xb94b0000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_CLGDTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) + s390_disasm(ENC5(MNM, GPR, UINT, FPR, UINT), "clgdtr", r1, m3, r2, m4); + + return emit_RRF2(p, 0xb9420000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_CLGXTR(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) +{ + vassert(m4 == 0); + vassert(s390_host_has_dfp); + vassert(s390_host_has_fpext); + + if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) + s390_disasm(ENC5(MNM, GPR, UINT, FPR, UINT), "clgxtr", r1, m3, r2, m4); + + return emit_RRF2(p, 0xb94a0000, m3, m4, r1, r2); +} + + static UChar * s390_emit_DDTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2) { @@ -6367,6 +6539,18 @@ s390_insn_as_string(const s390_insn *insn) case S390_DFP_D64_TO_D32: case S390_DFP_D64_TO_D128: case S390_DFP_D128_TO_D64: op = "v-d2d"; break; + case S390_DFP_I32_TO_D64: + case S390_DFP_I32_TO_D128: op = "v-i2d"; break; + case S390_DFP_U32_TO_D64: + case S390_DFP_U32_TO_D128: + case S390_DFP_U64_TO_D64: + case S390_DFP_U64_TO_D128: op = "v-u2d"; break; + case S390_DFP_D64_TO_I32: + case S390_DFP_D128_TO_I32: op = "v-d2i"; break; + case S390_DFP_D64_TO_U32: + case S390_DFP_D64_TO_U64: + case S390_DFP_D128_TO_U32: + case S390_DFP_D128_TO_U64: op = "v-d2u"; break; default: goto fail; } s390_sprintf(buf, "%M %R,%R", op, insn->variant.dfp_convert.dst_hi, @@ -6505,10 +6689,22 @@ s390_insn_as_string(const s390_insn *insn) case S390_INSN_DFP_CONVERT: switch (insn->variant.dfp_convert.tag) { - case S390_DFP_D32_TO_D64: p += vex_sprintf(p, "4 -> "); goto common; + case S390_DFP_D32_TO_D64: + case S390_DFP_I32_TO_D64: + case S390_DFP_I32_TO_D128: + case S390_DFP_U32_TO_D64: + case S390_DFP_U32_TO_D128: p += vex_sprintf(p, "4 -> "); goto common; case S390_DFP_D64_TO_D32: - case S390_DFP_D64_TO_D128:p += vex_sprintf(p, "8 -> "); goto common; - case S390_DFP_D128_TO_D64:p += vex_sprintf(p, "16 -> "); goto common; + case S390_DFP_D64_TO_D128: + case S390_DFP_U64_TO_D64: + case S390_DFP_U64_TO_D128: + case S390_DFP_D64_TO_I32: + case S390_DFP_D64_TO_U32: + case S390_DFP_D64_TO_U64: p += vex_sprintf(p, "8 -> "); goto common; + case S390_DFP_D128_TO_D64: + case S390_DFP_D128_TO_I32: + case S390_DFP_D128_TO_U32: + case S390_DFP_D128_TO_U64: p += vex_sprintf(p, "16 -> "); goto common; default: goto common; } @@ -8633,6 +8829,26 @@ s390_insn_dfp_convert_emit(UChar *buf, const s390_insn *insn) switch (insn->variant.dfp_convert.tag) { + /* Convert to fixed */ + case S390_DFP_D64_TO_I32: return s390_emit_CFDTR(buf, m3, m4, r1, r2); + case S390_DFP_D128_TO_I32: return s390_emit_CFXTR(buf, m3, m4, r1, r2); + + /* Convert to logical */ + case S390_DFP_D64_TO_U32: return s390_emit_CLFDTR(buf, m3, m4, r1, r2); + case S390_DFP_D128_TO_U32: return s390_emit_CLFXTR(buf, m3, m4, r1, r2); + case S390_DFP_D64_TO_U64: return s390_emit_CLGDTR(buf, m3, m4, r1, r2); + case S390_DFP_D128_TO_U64: return s390_emit_CLGXTR(buf, m3, m4, r1, r2); + + /* Convert from fixed */ + case S390_DFP_I32_TO_D64: return s390_emit_CDFTR(buf, 0, m4, r1, r2); + case S390_DFP_I32_TO_D128: return s390_emit_CXFTR(buf, 0, m4, r1, r2); + + /* Convert from logical */ + case S390_DFP_U32_TO_D64: return s390_emit_CDLFTR(buf, m3, m4, r1, r2); + case S390_DFP_U64_TO_D64: return s390_emit_CDLGTR(buf, m3, m4, r1, r2); + case S390_DFP_U32_TO_D128: return s390_emit_CXLFTR(buf, m3, m4, r1, r2); + case S390_DFP_U64_TO_D128: return s390_emit_CXLGTR(buf, m3, m4, r1, r2); + /* Load lengthened */ case S390_DFP_D32_TO_D64: return s390_emit_LDETR(buf, m4, r1, r2); case S390_DFP_D64_TO_D128: return s390_emit_LXDTR(buf, m4, r1, r2); diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index ba64bd15d3..476cc12b64 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -245,7 +245,19 @@ typedef enum { S390_DFP_D32_TO_D64, S390_DFP_D64_TO_D32, S390_DFP_D64_TO_D128, - S390_DFP_D128_TO_D64 + S390_DFP_D128_TO_D64, + S390_DFP_I32_TO_D64, + S390_DFP_I32_TO_D128, + S390_DFP_U32_TO_D64, + S390_DFP_U32_TO_D128, + S390_DFP_U64_TO_D64, + S390_DFP_U64_TO_D128, + S390_DFP_D64_TO_I32, + S390_DFP_D64_TO_U32, + S390_DFP_D64_TO_U64, + S390_DFP_D128_TO_I32, + S390_DFP_D128_TO_U32, + S390_DFP_D128_TO_U64 } s390_dfp_conv_t; /* The kind of binary DFP operations */ diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index e5851195b6..6142b271e9 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -1128,6 +1128,12 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128; case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128; case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128; + case Iop_D64toI32S: conv = S390_DFP_D64_TO_I32; goto do_convert_dfp; + case Iop_D64toI32U: conv = S390_DFP_D64_TO_U32; goto do_convert_dfp; + case Iop_D64toI64U: conv = S390_DFP_D64_TO_U64; goto do_convert_dfp; + case Iop_D128toI32S: conv = S390_DFP_D128_TO_I32; goto do_convert_dfp128; + case Iop_D128toI32U: conv = S390_DFP_D128_TO_U32; goto do_convert_dfp128; + case Iop_D128toI64U: conv = S390_DFP_D128_TO_U64; goto do_convert_dfp128; do_convert: { s390_bfp_round_t rounding_mode; @@ -1162,6 +1168,39 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) return res; } + do_convert_dfp: { + s390_dfp_round_t rounding_mode; + + res = newVRegI(env); + h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */ + + rounding_mode = get_dfp_rounding_mode(env, arg1); + addInstr(env, s390_insn_dfp_convert(size, conv, res, h1, + rounding_mode)); + return res; + } + + do_convert_dfp128: { + s390_dfp_round_t rounding_mode; + HReg op_hi, op_lo, f13, f15; + + res = newVRegI(env); + s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */ + + /* We use non-virtual registers r13 and r15 as pair */ + f13 = make_fpr(13); + f15 = make_fpr(15); + + /* operand --> (f13, f15) */ + addInstr(env, s390_insn_move(8, f13, op_hi)); + addInstr(env, s390_insn_move(8, f15, op_lo)); + + rounding_mode = get_dfp_rounding_mode(env, arg1); + addInstr(env, s390_insn_dfp128_convert_from(size, conv, res, f13, + f15, rounding_mode)); + return res; + } + case Iop_8HLto16: case Iop_16HLto32: case Iop_32HLto64: { @@ -2507,6 +2546,9 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, switch (expr->Iex.Unop.op) { case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp; + case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int; + case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int; + case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int; default: goto irreducible; } @@ -2516,6 +2558,11 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op)); goto move_dst; + convert_int: + op = s390_isel_int_expr(env, left); + addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op)); + goto move_dst; + move_dst: /* Move result to virtual destination registers */ *dst_hi = newVRegF(env); @@ -2605,11 +2652,16 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr) switch (op) { case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp; + case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int; convert_dfp: h1 = s390_isel_dfp_expr(env, left); goto convert; + convert_int: + h1 = s390_isel_int_expr(env, left); + goto convert; + convert: { s390_dfp_round_t rounding_mode; /* convert-from-fixed and load-rounded have a rounding mode field @@ -2707,11 +2759,17 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr) switch (op) { case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1; + case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1; + case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1; convert_dfp1: h1 = s390_isel_dfp_expr(env, left); goto convert1; + convert_int1: + h1 = s390_isel_int_expr(env, left); + goto convert1; + convert1: dst = newVRegF(env); /* No rounding mode is needed for these conversions. Just stick