From: Florian Krohm Date: Mon, 17 Jun 2013 21:03:56 +0000 (+0000) Subject: s390: Support some more BFP <-> DFP conversions (the ones X-Git-Tag: svn/VALGRIND_3_9_0^2~67 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5868d3a984f79fd6b2178fcd8b88f4fb8d79fb5e;p=thirdparty%2Fvalgrind.git s390: Support some more BFP <-> DFP conversions (the ones that were added in VEX r2727). Patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com). Part of fixing BZ 307113. git-svn-id: svn://svn.valgrind.org/vex/trunk@2728 --- diff --git a/VEX/priv/guest_s390_defs.h b/VEX/priv/guest_s390_defs.h index 950c7892a5..5f2ae20dd1 100644 --- a/VEX/priv/guest_s390_defs.h +++ b/VEX/priv/guest_s390_defs.h @@ -154,8 +154,9 @@ enum { S390_CC_OP_DFP_128_TO_INT_32 = 55, S390_CC_OP_DFP_64_TO_INT_64 = 56, S390_CC_OP_DFP_128_TO_INT_64 = 57, - S390_CC_OP_PFPO_64 = 58, - S390_CC_OP_PFPO_128 = 59 + S390_CC_OP_PFPO_32 = 58, + S390_CC_OP_PFPO_64 = 59, + S390_CC_OP_PFPO_128 = 60 }; /*------------------------------------------------------------*/ @@ -229,6 +230,7 @@ enum { | S390_CC_OP_DFP_128_TO_INT_32 | 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 | + | S390_CC_OP_PFPO_32 | F|D source | Z GR0 low 32 bits | | | S390_CC_OP_PFPO_64 | F|D source | Z GR0 low 32 bits | | | S390_CC_OP_PFPO_128 | F|D source hi 64 bits | F|D src low 64 bits | Z GR0 low 32 bits | +--------------------------------+-----------------------+----------------------+-----------------+ diff --git a/VEX/priv/guest_s390_helpers.c b/VEX/priv/guest_s390_helpers.c index 2ad798a3f6..f27092972a 100644 --- a/VEX/priv/guest_s390_helpers.c +++ b/VEX/priv/guest_s390_helpers.c @@ -1741,6 +1741,18 @@ s390_calculate_cc(ULong cc_op, ULong cc_dep1, ULong cc_dep2, ULong cc_ndep) return S390_CC_FOR_DFP128_UCONVERT(".insn rrf,0xb94a0000", cc_dep1, cc_dep2, cc_ndep); + case S390_CC_OP_PFPO_32: { + __asm__ volatile( + "ler 4, %[cc_dep1]\n\t" /* 32 bit FR move */ + "lr 0, %[cc_dep2]\n\t" /* 32 bit GR move */ + ".short 0x010a\n\t" /* PFPO */ + "ipm %[psw]\n\t" : [psw] "=d"(psw) + : [cc_dep1] "f"(cc_dep1), + [cc_dep2] "d"(cc_dep2) + : "r0", "r1", "f4"); + return psw >> 28; /* cc */ + } + case S390_CC_OP_PFPO_64: { __asm__ volatile( "ldr 4, %[cc_dep1]\n\t" diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index 2aefba2535..2f715978a8 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -7199,18 +7199,42 @@ s390_irgen_PFPO(void) IRTemp test_bit = newTemp(Ity_I32); /* bit 32 of GR 0 - test validity */ IRTemp fn = newTemp(Ity_I32); /* [33:55] of GR 0 - function code */ IRTemp ef = newTemp(Ity_I32); /* Emulation Failure */ - IRTemp src1 = newTemp(Ity_F64); - IRTemp dst1 = newTemp(Ity_D64); - IRTemp src2 = newTemp(Ity_D64); - IRTemp dst2 = newTemp(Ity_F64); - IRTemp src3 = newTemp(Ity_F64); + IRTemp src1 = newTemp(Ity_F32); + IRTemp dst1 = newTemp(Ity_D32); + IRTemp src2 = newTemp(Ity_F32); + IRTemp dst2 = newTemp(Ity_D64); + IRTemp src3 = newTemp(Ity_F32); IRTemp dst3 = newTemp(Ity_D128); - IRTemp src4 = newTemp(Ity_D128); - IRTemp dst4 = newTemp(Ity_F64); - IRTemp src5 = newTemp(Ity_F128); - IRTemp dst5 = newTemp(Ity_D128); - IRTemp src6 = newTemp(Ity_D128); - IRTemp dst6 = newTemp(Ity_F128); + IRTemp src4 = newTemp(Ity_F64); + IRTemp dst4 = newTemp(Ity_D32); + IRTemp src5 = newTemp(Ity_F64); + IRTemp dst5 = newTemp(Ity_D64); + IRTemp src6 = newTemp(Ity_F64); + IRTemp dst6 = newTemp(Ity_D128); + IRTemp src7 = newTemp(Ity_F128); + IRTemp dst7 = newTemp(Ity_D32); + IRTemp src8 = newTemp(Ity_F128); + IRTemp dst8 = newTemp(Ity_D64); + IRTemp src9 = newTemp(Ity_F128); + IRTemp dst9 = newTemp(Ity_D128); + IRTemp src10 = newTemp(Ity_D32); + IRTemp dst10 = newTemp(Ity_F32); + IRTemp src11 = newTemp(Ity_D32); + IRTemp dst11 = newTemp(Ity_F64); + IRTemp src12 = newTemp(Ity_D32); + IRTemp dst12 = newTemp(Ity_F128); + IRTemp src13 = newTemp(Ity_D64); + IRTemp dst13 = newTemp(Ity_F32); + IRTemp src14 = newTemp(Ity_D64); + IRTemp dst14 = newTemp(Ity_F64); + IRTemp src15 = newTemp(Ity_D64); + IRTemp dst15 = newTemp(Ity_F128); + IRTemp src16 = newTemp(Ity_D128); + IRTemp dst16 = newTemp(Ity_F32); + IRTemp src17 = newTemp(Ity_D128); + IRTemp dst17 = newTemp(Ity_F64); + IRTemp src18 = newTemp(Ity_D128); + IRTemp dst18 = newTemp(Ity_F128); IRExpr *irrm; vassert(s390_host_has_pfpo); @@ -7225,7 +7249,7 @@ s390_irgen_PFPO(void) irrm = get_rounding_mode_from_gr0(); /* test_bit is 1 */ - assign(src1, get_fpr_dw0(4)); /* get source from FPR 4,6 */ + assign(src1, get_fpr_w0(4)); /* get source from FPR 4,6 */ s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src1, gr0); /* Return code set in GR1 is usually 0. Non-zero value is set only @@ -7253,52 +7277,148 @@ s390_irgen_PFPO(void) ) ); - /* F64 -> D64 */ + /* F32 -> D32 */ /* get source from FPR 4,6 - already set in src1 */ - assign(dst1, binop(Iop_F64toD64, irrm, mkexpr(src1))); - put_dpr_dw0(0, mkexpr(dst1)); /* put the result in FPR 0,2 */ + assign(dst1, binop(Iop_F32toD32, irrm, mkexpr(src1))); + put_dpr_w0(0, mkexpr(dst1)); /* put the result in FPR 0,2 */ put_gpr_w1(1, mkU32(0x0)); - s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src1, gr0); - next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F64_TO_D64))); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_32, src1, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F32_TO_D32))); - /* D64 -> F64 */ - assign(src2, get_dpr_dw0(4)); /* get source from FPR 4,6 */ - assign(dst2, binop(Iop_D64toF64, irrm, mkexpr(src2))); - put_fpr_dw0(0, mkexpr(dst2)); /* put the result in FPR 0,2 */ + /* F32 -> D64 */ + assign(src2, get_fpr_w0(4)); /* get source from FPR 4,6 */ + assign(dst2, binop(Iop_F32toD64, irrm, mkexpr(src2))); + put_dpr_dw0(0, mkexpr(dst2)); /* put the result in FPR 0,2 */ put_gpr_w1(1, mkU32(0x0)); - s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src2, gr0); - next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D64_TO_F64))); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_32, src2, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F32_TO_D64))); - /* F64 -> D128 */ - assign(src3, get_fpr_dw0(4)); /* get source from FPR 4,6 */ - assign(dst3, binop(Iop_F64toD128, irrm, mkexpr(src3))); + /* F32 -> D128 */ + assign(src3, get_fpr_w0(4)); /* get source from FPR 4,6 */ + assign(dst3, binop(Iop_F32toD128, irrm, mkexpr(src3))); put_dpr_pair(0, mkexpr(dst3)); /* put the result in FPR 0,2 */ put_gpr_w1(1, mkU32(0x0)); - s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src3, gr0); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_32, src3, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F32_TO_D128))); + + /* F64 -> D32 */ + assign(src4, get_fpr_dw0(4)); /* get source from FPR 4,6 */ + assign(dst4, binop(Iop_F64toD32, irrm, mkexpr(src4))); + put_dpr_w0(0, mkexpr(dst4)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src4, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F64_TO_D32))); + + /* F64 -> D64 */ + assign(src5, get_fpr_dw0(4)); /* get source from FPR 4,6 */ + assign(dst5, binop(Iop_F64toD64, irrm, mkexpr(src5))); + put_dpr_dw0(0, mkexpr(dst5)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src5, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F64_TO_D64))); + + /* F64 -> D128 */ + assign(src6, get_fpr_dw0(4)); /* get source from FPR 4,6 */ + assign(dst6, binop(Iop_F64toD128, irrm, mkexpr(src6))); + put_dpr_pair(0, mkexpr(dst6)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src6, gr0); next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F64_TO_D128))); - /* D128 -> F64 */ - assign(src4, get_dpr_pair(4)); /* get source from FPR 4,6 */ - assign(dst4, binop(Iop_D128toF64, irrm, mkexpr(src4))); - put_fpr_dw0(0, mkexpr(dst4)); /* put the result in FPR 0,2 */ + /* F128 -> D32 */ + assign(src7, get_fpr_pair(4)); /* get source from FPR 4,6 */ + assign(dst7, binop(Iop_F128toD32, irrm, mkexpr(src7))); + put_dpr_w0(0, mkexpr(dst7)); /* put the result in FPR 0,2 */ put_gpr_w1(1, mkU32(0x0)); - s390_cc_thunk_put1d128Z(S390_CC_OP_PFPO_128, src4, gr0); - next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D128_TO_F64))); + s390_cc_thunk_put1f128Z(S390_CC_OP_PFPO_128, src7, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F128_TO_D32))); + + /* F128 -> D64 */ + assign(src8, get_fpr_pair(4)); /* get source from FPR 4,6 */ + assign(dst8, binop(Iop_F128toD64, irrm, mkexpr(src8))); + put_dpr_dw0(0, mkexpr(dst8)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_put1f128Z(S390_CC_OP_PFPO_128, src8, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F128_TO_D64))); /* F128 -> D128 */ - assign(src5, get_fpr_pair(4)); /* get source from FPR 4,6 */ - assign(dst5, binop(Iop_F128toD128, irrm, mkexpr(src5))); - put_dpr_pair(0, mkexpr(dst5)); /* put the result in FPR 0,2 */ + assign(src9, get_fpr_pair(4)); /* get source from FPR 4,6 */ + assign(dst9, binop(Iop_F128toD128, irrm, mkexpr(src9))); + put_dpr_pair(0, mkexpr(dst9)); /* put the result in FPR 0,2 */ put_gpr_w1(1, mkU32(0x0)); - s390_cc_thunk_put1f128Z(S390_CC_OP_PFPO_128, src5, gr0); + s390_cc_thunk_put1f128Z(S390_CC_OP_PFPO_128, src9, gr0); next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_F128_TO_D128))); + /* D32 -> F32 */ + assign(src10, get_dpr_w0(4)); /* get source from FPR 4,6 */ + assign(dst10, binop(Iop_D32toF32, irrm, mkexpr(src10))); + put_fpr_w0(0, mkexpr(dst10)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_32, src10, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D32_TO_F32))); + + /* D32 -> F64 */ + assign(src11, get_dpr_w0(4)); /* get source from FPR 4,6 */ + assign(dst11, binop(Iop_D32toF64, irrm, mkexpr(src11))); + put_fpr_dw0(0, mkexpr(dst11)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_32, src11, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D32_TO_F64))); + + /* D32 -> F128 */ + assign(src12, get_dpr_w0(4)); /* get source from FPR 4,6 */ + assign(dst12, binop(Iop_D32toF128, irrm, mkexpr(src12))); + put_fpr_pair(0, mkexpr(dst12)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_32, src12, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D32_TO_F128))); + + /* D64 -> F32 */ + assign(src13, get_dpr_dw0(4)); /* get source from FPR 4,6 */ + assign(dst13, binop(Iop_D64toF32, irrm, mkexpr(src13))); + put_fpr_w0(0, mkexpr(dst13)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src13, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D64_TO_F32))); + + /* D64 -> F64 */ + assign(src14, get_dpr_dw0(4)); /* get source from FPR 4,6 */ + assign(dst14, binop(Iop_D64toF64, irrm, mkexpr(src14))); + put_fpr_dw0(0, mkexpr(dst14)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src14, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D64_TO_F64))); + + /* D64 -> F128 */ + assign(src15, get_dpr_dw0(4)); /* get source from FPR 4,6 */ + assign(dst15, binop(Iop_D64toF128, irrm, mkexpr(src15))); + put_fpr_pair(0, mkexpr(dst15)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_putFZ(S390_CC_OP_PFPO_64, src15, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D64_TO_F128))); + + /* D128 -> F32 */ + assign(src16, get_dpr_pair(4)); /* get source from FPR 4,6 */ + assign(dst16, binop(Iop_D128toF32, irrm, mkexpr(src16))); + put_fpr_w0(0, mkexpr(dst16)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_put1d128Z(S390_CC_OP_PFPO_128, src16, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D128_TO_F32))); + + /* D128 -> F64 */ + assign(src17, get_dpr_pair(4)); /* get source from FPR 4,6 */ + assign(dst17, binop(Iop_D128toF64, irrm, mkexpr(src17))); + put_fpr_dw0(0, mkexpr(dst17)); /* put the result in FPR 0,2 */ + put_gpr_w1(1, mkU32(0x0)); + s390_cc_thunk_put1d128Z(S390_CC_OP_PFPO_128, src17, gr0); + next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D128_TO_F64))); + /* D128 -> F128 */ - assign(src6, get_dpr_pair(4)); /* get source from FPR 4,6 */ - assign(dst6, binop(Iop_D128toF128, irrm, mkexpr(src6))); - put_fpr_pair(0, mkexpr(dst6)); /* put the result in FPR 0,2 */ + assign(src18, get_dpr_pair(4)); /* get source from FPR 4,6 */ + assign(dst18, binop(Iop_D128toF128, irrm, mkexpr(src18))); + put_fpr_pair(0, mkexpr(dst18)); /* put the result in FPR 0,2 */ put_gpr_w1(1, mkU32(0x0)); - s390_cc_thunk_put1d128Z(S390_CC_OP_PFPO_128, src6, gr0); + s390_cc_thunk_put1d128Z(S390_CC_OP_PFPO_128, src18, gr0); next_insn_if(binop(Iop_CmpEQ32, mkexpr(fn), mkU32(S390_PFPO_D128_TO_F128))); return "pfpo"; diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index e9dc34d781..7a3eab7d50 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -6923,11 +6923,23 @@ s390_insn_as_string(const s390_insn *insn) s390_fp_convert *fp_convert = insn->variant.fp_convert.details; switch (fp_convert->tag) { - case S390_FP_F64_TO_D64: op = "v-f2d"; break; - case S390_FP_D64_TO_F64: op = "v-d2f"; break; - case S390_FP_F64_TO_D128: op = "v-f2d"; break; - case S390_FP_D128_TO_F64: op = "v-d2f"; break; + case S390_FP_F32_TO_D32: + case S390_FP_F32_TO_D64: + case S390_FP_F32_TO_D128: + case S390_FP_F64_TO_D32: + case S390_FP_F64_TO_D64: + case S390_FP_F64_TO_D128: + case S390_FP_F128_TO_D32: + case S390_FP_F128_TO_D64: case S390_FP_F128_TO_D128: op = "v-f2d"; break; + case S390_FP_D32_TO_F32: + case S390_FP_D32_TO_F64: + case S390_FP_D32_TO_F128: + case S390_FP_D64_TO_F32: + case S390_FP_D64_TO_F64: + case S390_FP_D64_TO_F128: + case S390_FP_D128_TO_F32: + case S390_FP_D128_TO_F64: case S390_FP_D128_TO_F128: op = "v-d2f"; break; default: goto fail; } @@ -7096,11 +7108,23 @@ s390_insn_as_string(const s390_insn *insn) s390_fp_convert *fp_convert = insn->variant.fp_convert.details; switch (fp_convert->tag) { + case S390_FP_F32_TO_D32: + case S390_FP_F32_TO_D64: + case S390_FP_F32_TO_D128: + case S390_FP_D32_TO_F32: + case S390_FP_D32_TO_F64: + case S390_FP_D32_TO_F128: p += vex_sprintf(p, "4 -> "); goto common; + case S390_FP_F64_TO_D32: case S390_FP_F64_TO_D64: + case S390_FP_F64_TO_D128: + case S390_FP_D64_TO_F32: case S390_FP_D64_TO_F64: - case S390_FP_F64_TO_D128: p += vex_sprintf(p, "8 -> "); goto common; - case S390_FP_D128_TO_F64: + case S390_FP_D64_TO_F128: p += vex_sprintf(p, "8 -> "); goto common; + case S390_FP_F128_TO_D32: + case S390_FP_F128_TO_D64: case S390_FP_F128_TO_D128: + case S390_FP_D128_TO_F32: + case S390_FP_D128_TO_F64: case S390_FP_D128_TO_F128: p += vex_sprintf(p, "16 -> "); goto common; default: goto common; @@ -9317,11 +9341,23 @@ s390_insn_fp_convert_emit(UChar *buf, const s390_insn *insn) vassert(rm < 2 || rm > 7); switch (fp_convert->tag) { + case S390_FP_F32_TO_D32: pfpo = S390_PFPO_F32_TO_D32 << 8; break; + case S390_FP_F32_TO_D64: pfpo = S390_PFPO_F32_TO_D64 << 8; break; + case S390_FP_F32_TO_D128: pfpo = S390_PFPO_F32_TO_D128 << 8; break; + case S390_FP_F64_TO_D32: pfpo = S390_PFPO_F64_TO_D32 << 8; break; case S390_FP_F64_TO_D64: pfpo = S390_PFPO_F64_TO_D64 << 8; break; - case S390_FP_D64_TO_F64: pfpo = S390_PFPO_D64_TO_F64 << 8; break; case S390_FP_F64_TO_D128: pfpo = S390_PFPO_F64_TO_D128 << 8; break; - case S390_FP_D128_TO_F64: pfpo = S390_PFPO_D128_TO_F64 << 8; break; + case S390_FP_F128_TO_D32: pfpo = S390_PFPO_F128_TO_D32 << 8; break; + case S390_FP_F128_TO_D64: pfpo = S390_PFPO_F128_TO_D64 << 8; break; case S390_FP_F128_TO_D128: pfpo = S390_PFPO_F128_TO_D128 << 8; break; + case S390_FP_D32_TO_F32: pfpo = S390_PFPO_D32_TO_F32 << 8; break; + case S390_FP_D32_TO_F64: pfpo = S390_PFPO_D32_TO_F64 << 8; break; + case S390_FP_D32_TO_F128: pfpo = S390_PFPO_D32_TO_F128 << 8; break; + case S390_FP_D64_TO_F32: pfpo = S390_PFPO_D64_TO_F32 << 8; break; + case S390_FP_D64_TO_F64: pfpo = S390_PFPO_D64_TO_F64 << 8; break; + case S390_FP_D64_TO_F128: pfpo = S390_PFPO_D64_TO_F128 << 8; break; + case S390_FP_D128_TO_F32: pfpo = S390_PFPO_D128_TO_F32 << 8; break; + case S390_FP_D128_TO_F64: pfpo = S390_PFPO_D128_TO_F64 << 8; break; case S390_FP_D128_TO_F128: pfpo = S390_PFPO_D128_TO_F128 << 8; break; default: goto fail; } diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index c6a91fc172..3fca721fcf 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -268,11 +268,23 @@ typedef enum { } s390_dfp_conv_t; typedef enum { + S390_FP_F32_TO_D32, + S390_FP_F32_TO_D64, + S390_FP_F32_TO_D128, + S390_FP_F64_TO_D32, S390_FP_F64_TO_D64, - S390_FP_D64_TO_F64, S390_FP_F64_TO_D128, - S390_FP_D128_TO_F64, + S390_FP_F128_TO_D32, + S390_FP_F128_TO_D64, S390_FP_F128_TO_D128, + S390_FP_D32_TO_F32, + S390_FP_D32_TO_F64, + S390_FP_D32_TO_F128, + S390_FP_D64_TO_F32, + S390_FP_D64_TO_F64, + S390_FP_D64_TO_F128, + S390_FP_D128_TO_F32, + S390_FP_D128_TO_F64, S390_FP_D128_TO_F128 } s390_fp_conv_t; diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index c20bf592b8..d84125d8ab 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -1974,6 +1974,45 @@ s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2); return; + case Iop_D32toF128: + case Iop_D64toF128: { + IRExpr *irrm; + IRExpr *left; + s390_dfp_round_t rm; + HReg h1; /* virtual reg. to hold source */ + HReg f0, f2, f4, r1; /* real registers used by PFPO */ + s390_fp_conv_t fpconv; + + switch (expr->Iex.Binop.op) { + case Iop_D32toF128: + fpconv = S390_FP_D32_TO_F128; + break; + case Iop_D64toF128: + fpconv = S390_FP_D64_TO_F128; + break; + default: goto irreducible; + } + + f4 = make_fpr(4); /* source */ + f0 = make_fpr(0); /* destination */ + f2 = make_fpr(2); /* destination */ + r1 = make_gpr(1); /* GPR #1 clobbered */ + irrm = expr->Iex.Binop.arg1; + left = expr->Iex.Binop.arg2; + rm = get_dfp_rounding_mode(env, irrm); + h1 = s390_isel_dfp_expr(env, left); + addInstr(env, s390_insn_move(8, f4, h1)); + addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2, + f4, INVALID_HREG, r1, rm)); + /* (f0, f2) --> destination */ + *dst_hi = newVRegF(env); + *dst_lo = newVRegF(env); + addInstr(env, s390_insn_move(8, *dst_hi, f0)); + addInstr(env, s390_insn_move(8, *dst_lo, f2)); + + return; + } + case Iop_D128toF128: { IRExpr *irrm; IRExpr *left; @@ -2246,7 +2285,11 @@ s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr) case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int; case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int; case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int; + case Iop_D32toF32: fpconv = S390_FP_D32_TO_F32; goto convert_dfp; + case Iop_D32toF64: fpconv = S390_FP_D32_TO_F64; goto convert_dfp; + case Iop_D64toF32: fpconv = S390_FP_D64_TO_F32; goto convert_dfp; case Iop_D64toF64: fpconv = S390_FP_D64_TO_F64; goto convert_dfp; + case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128; case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128; convert_float: @@ -2638,12 +2681,24 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, return; } + case Iop_F32toD128: case Iop_F64toD128: { IRExpr *irrm; IRExpr *left; s390_dfp_round_t rm; HReg h1; /* virtual reg. to hold source */ HReg f0, f2, f4, r1; /* real registers used by PFPO */ + s390_fp_conv_t fpconv; + + switch (expr->Iex.Binop.op) { + case Iop_F32toD128: /* (D128, I64) -> D128 */ + fpconv = S390_FP_F32_TO_D128; + break; + case Iop_F64toD128: /* (D128, I64) -> D128 */ + fpconv = S390_FP_F64_TO_D128; + break; + default: goto irreducible; + } f4 = make_fpr(4); /* source */ f0 = make_fpr(0); /* destination */ @@ -2654,7 +2709,7 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, rm = get_dfp_rounding_mode(env, irrm); h1 = s390_isel_float_expr(env, left); addInstr(env, s390_insn_move(8, f4, h1)); - addInstr(env, s390_insn_fp128_convert(16, S390_FP_F64_TO_D128, f0, f2, + addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2, f4, INVALID_HREG, r1, rm)); /* (f0, f2) --> destination */ *dst_hi = newVRegF(env); @@ -2823,7 +2878,12 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr) case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp; case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int; case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int; + case Iop_F32toD32: fpconv = S390_FP_F32_TO_D32; goto convert_bfp; + case Iop_F32toD64: fpconv = S390_FP_F32_TO_D64; goto convert_bfp; + case Iop_F64toD32: fpconv = S390_FP_F64_TO_D32; goto convert_bfp; case Iop_F64toD64: fpconv = S390_FP_F64_TO_D64; goto convert_bfp; + case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128; + case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128; convert_dfp: h1 = s390_isel_dfp_expr(env, left); @@ -2867,6 +2927,28 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr) return dst; } + convert_bfp128: { + s390_dfp_round_t rm; + HReg op_hi, op_lo; + HReg f0, f4, f6, r1; /* real registers used by PFPO */ + + f4 = make_fpr(4); /* source */ + f6 = make_fpr(6); /* source */ + f0 = make_fpr(0); /* destination */ + r1 = make_gpr(1); /* GPR #1 clobbered */ + s390_isel_float128_expr(&op_hi, &op_lo, env, left); + dst = newVRegF(env); + rm = get_dfp_rounding_mode(env, irrm); + /* operand --> (f4, f6) */ + addInstr(env, s390_insn_move(8, f4, op_hi)); + addInstr(env, s390_insn_move(8, f6, op_lo)); + addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG, + f4, f6, r1, rm)); + /* f0 --> destination */ + addInstr(env, s390_insn_move(8, dst, f0)); + return dst; + } + case Iop_D128toD64: { HReg op_hi, op_lo, f13, f15; s390_dfp_round_t rounding_mode; diff --git a/VEX/priv/s390_defs.h b/VEX/priv/s390_defs.h index 9a3ef3d67e..7d576eea50 100644 --- a/VEX/priv/s390_defs.h +++ b/VEX/priv/s390_defs.h @@ -123,14 +123,26 @@ typedef enum { S390_FPC_DFP_ROUND_PREPARE_SHORT = 7 } s390_fpc_dfp_round_t; -/* PFPO function code as it is encoded in bits [33:55] of GP0 +/* PFPO function code as it is encoded in bits [33:55] of GR0 when PFPO insn is executed. */ typedef enum { + S390_PFPO_F32_TO_D32 = 0x010805, + S390_PFPO_F32_TO_D64 = 0x010905, + S390_PFPO_F32_TO_D128 = 0x010A05, + S390_PFPO_F64_TO_D32 = 0x010806, S390_PFPO_F64_TO_D64 = 0x010906, - S390_PFPO_D64_TO_F64 = 0x010609, S390_PFPO_F64_TO_D128 = 0x010A06, - S390_PFPO_D128_TO_F64 = 0x01060A, + S390_PFPO_F128_TO_D32 = 0x010807, + S390_PFPO_F128_TO_D64 = 0x010907, S390_PFPO_F128_TO_D128 = 0x010A07, + S390_PFPO_D32_TO_F32 = 0x010508, + S390_PFPO_D32_TO_F64 = 0x010608, + S390_PFPO_D32_TO_F128 = 0x010708, + S390_PFPO_D64_TO_F32 = 0x010509, + S390_PFPO_D64_TO_F64 = 0x010609, + S390_PFPO_D64_TO_F128 = 0x010709, + S390_PFPO_D128_TO_F32 = 0x01050A, + S390_PFPO_D128_TO_F64 = 0x01060A, S390_PFPO_D128_TO_F128 = 0x01070A } s390_pfpo_function_t;