From: Florian Krohm Date: Mon, 10 Sep 2012 03:09:04 +0000 (+0000) Subject: s390: More prep work bfp reorg. In the future unary/binary/ternary X-Git-Tag: svn/VALGRIND_3_9_0^2~247 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1f80e7e80bfc2703d6093b2f9158c0af28cb72dc;p=thirdparty%2Fvalgrind.git s390: More prep work bfp reorg. In the future unary/binary/ternary operations on bfp data will no longer require a rounding mode in the s390_insn. Only type conversion operations need a rounding mode. So in this patch S390_BFP_CONVERT is introduced and S390_BFP128_CONVERT_TO/FROM are consolidated to S390_BFP128_CONVERT. This also makes the representation of bfp and bfp128 symmetric. s390_insn gets a new variant: s390_convert. The type conversion ops get their own data type now: s390_conv_t git-svn-id: svn://svn.valgrind.org/vex/trunk@2522 --- diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index 04d8a399ae..fe5a633f56 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -680,6 +680,11 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn) addHRegUse(u, HRmRead, insn->variant.bfp_compare.op2); /* right */ break; + case S390_INSN_BFP_CONVERT: + addHRegUse(u, HRmWrite, insn->variant.bfp_convert.dst); + addHRegUse(u, HRmRead, insn->variant.bfp_convert.op); /* operand */ + break; + case S390_INSN_BFP128_BINOP: addHRegUse(u, HRmWrite, insn->variant.bfp128_binop.dst_hi); addHRegUse(u, HRmWrite, insn->variant.bfp128_binop.dst_lo); @@ -704,16 +709,13 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn) addHRegUse(u, HRmRead, insn->variant.bfp128_unop.op_lo); break; - case S390_INSN_BFP128_CONVERT_TO: - addHRegUse(u, HRmWrite, insn->variant.bfp128_unop.dst_hi); - addHRegUse(u, HRmWrite, insn->variant.bfp128_unop.dst_lo); - addHRegUse(u, HRmRead, insn->variant.bfp128_unop.op_hi); - break; - - case S390_INSN_BFP128_CONVERT_FROM: - addHRegUse(u, HRmWrite, insn->variant.bfp128_unop.dst_hi); - addHRegUse(u, HRmRead, insn->variant.bfp128_unop.op_hi); - addHRegUse(u, HRmRead, insn->variant.bfp128_unop.op_lo); + case S390_INSN_BFP128_CONVERT: + addHRegUse(u, HRmWrite, insn->variant.bfp128_convert.dst_hi); + if (insn->variant.bfp128_convert.dst_lo != INVALID_HREG) + addHRegUse(u, HRmWrite, insn->variant.bfp128_convert.dst_lo); + addHRegUse(u, HRmRead, insn->variant.bfp128_convert.op_hi); + if (insn->variant.bfp128_convert.op_lo != INVALID_HREG) + addHRegUse(u, HRmRead, insn->variant.bfp128_convert.op_lo); break; case S390_INSN_MFENCE: @@ -899,6 +901,13 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn) insn->variant.bfp_compare.op2 = lookupHRegRemap(m, insn->variant.bfp_compare.op2); break; + case S390_INSN_BFP_CONVERT: + insn->variant.bfp_convert.dst = + lookupHRegRemap(m, insn->variant.bfp_convert.dst); + insn->variant.bfp_convert.op = + lookupHRegRemap(m, insn->variant.bfp_convert.op); + break; + case S390_INSN_BFP128_BINOP: insn->variant.bfp128_binop.dst_hi = lookupHRegRemap(m, insn->variant.bfp128_binop.dst_hi); @@ -934,22 +943,17 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn) lookupHRegRemap(m, insn->variant.bfp128_unop.op_lo); break; - case S390_INSN_BFP128_CONVERT_TO: - insn->variant.bfp128_unop.dst_hi = - lookupHRegRemap(m, insn->variant.bfp128_unop.dst_hi); - insn->variant.bfp128_unop.dst_lo = - lookupHRegRemap(m, insn->variant.bfp128_unop.dst_lo); - insn->variant.bfp128_unop.op_hi = - lookupHRegRemap(m, insn->variant.bfp128_unop.op_hi); - break; - - case S390_INSN_BFP128_CONVERT_FROM: - insn->variant.bfp128_unop.dst_hi = - lookupHRegRemap(m, insn->variant.bfp128_unop.dst_hi); - insn->variant.bfp128_unop.op_hi = - lookupHRegRemap(m, insn->variant.bfp128_unop.op_hi); - insn->variant.bfp128_unop.op_lo = - lookupHRegRemap(m, insn->variant.bfp128_unop.op_lo); + case S390_INSN_BFP128_CONVERT: + insn->variant.bfp128_convert.dst_hi = + lookupHRegRemap(m, insn->variant.bfp128_convert.dst_hi); + if (insn->variant.bfp128_convert.dst_lo != INVALID_HREG) + insn->variant.bfp128_convert.dst_lo = + lookupHRegRemap(m, insn->variant.bfp128_convert.dst_lo); + insn->variant.bfp128_convert.op_hi = + lookupHRegRemap(m, insn->variant.bfp128_convert.op_hi); + if (insn->variant.bfp128_convert.op_lo != INVALID_HREG) + insn->variant.bfp128_convert.op_lo = + lookupHRegRemap(m, insn->variant.bfp128_convert.op_lo); break; case S390_INSN_MFENCE: @@ -4745,6 +4749,23 @@ s390_insn_bfp_compare(UChar size, HReg dst, HReg op1, HReg op2) } +s390_insn * +s390_insn_bfp_convert(UChar size, s390_conv_t tag, HReg dst, HReg op, + s390_round_t rounding_mode) +{ + s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + + insn->tag = S390_INSN_BFP_CONVERT; + insn->size = size; + insn->variant.bfp_convert.tag = tag; + insn->variant.bfp_convert.dst = dst; + insn->variant.bfp_convert.op = op; + insn->variant.bfp_convert.rounding_mode = rounding_mode; + + return insn; +} + + s390_insn * s390_insn_bfp128_binop(UChar size, s390_bfp_binop_t tag, HReg dst_hi, HReg dst_lo, HReg op2_hi, HReg op2_lo, @@ -4803,42 +4824,46 @@ s390_insn_bfp128_compare(UChar size, HReg dst, HReg op1_hi, HReg op1_lo, } -s390_insn * -s390_insn_bfp128_convert_to(UChar size, s390_bfp_unop_t tag, HReg dst_hi, - HReg dst_lo, HReg op) +static s390_insn * +s390_insn_bfp128_convert(UChar size, s390_conv_t tag, HReg dst_hi, + HReg dst_lo, HReg op_hi, HReg op_lo, + s390_round_t rounding_mode) { s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); - insn->tag = S390_INSN_BFP128_CONVERT_TO; + insn->tag = S390_INSN_BFP128_CONVERT; insn->size = size; - insn->variant.bfp128_unop.tag = tag; - insn->variant.bfp128_unop.dst_hi = dst_hi; - insn->variant.bfp128_unop.dst_lo = dst_lo; - insn->variant.bfp128_unop.op_hi = op; - insn->variant.bfp128_unop.op_lo = INVALID_HREG; /* unused */ - insn->variant.bfp128_unop.rounding_mode = S390_ROUND_NEAREST_EVEN; /* unused */ + insn->variant.bfp128_convert.tag = tag; + insn->variant.bfp128_convert.dst_hi = dst_hi; + insn->variant.bfp128_convert.dst_lo = dst_lo; + insn->variant.bfp128_convert.op_hi = op_hi; + insn->variant.bfp128_convert.op_lo = op_lo; + insn->variant.bfp128_convert.rounding_mode = rounding_mode; return insn; } s390_insn * -s390_insn_bfp128_convert_from(UChar size, s390_bfp_unop_t tag, HReg dst, - HReg op_hi, HReg op_lo, - s390_round_t rounding_mode) +s390_insn_bfp128_convert_to(UChar size, s390_conv_t tag, HReg dst_hi, + HReg dst_lo, HReg op) { - s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn)); + /* Conversion to bfp128 never requires a rounding mode. Provide default + rounding mode. It will not be used when emitting insns. */ + s390_round_t rounding_mode = S390_ROUND_NEAREST_EVEN; - insn->tag = S390_INSN_BFP128_CONVERT_FROM; - insn->size = size; - insn->variant.bfp128_unop.tag = tag; - insn->variant.bfp128_unop.dst_hi = dst; - insn->variant.bfp128_unop.dst_lo = INVALID_HREG; /* unused */ - insn->variant.bfp128_unop.op_hi = op_hi; - insn->variant.bfp128_unop.op_lo = op_lo; - insn->variant.bfp128_unop.rounding_mode = rounding_mode; + return s390_insn_bfp128_convert(size, tag, dst_hi, dst_lo, op, + INVALID_HREG, rounding_mode); +} - return insn; + +s390_insn * +s390_insn_bfp128_convert_from(UChar size, s390_conv_t tag, HReg dst, + HReg op_hi, HReg op_lo, + s390_round_t rounding_mode) +{ + return s390_insn_bfp128_convert(size, tag, dst, INVALID_HREG, op_hi, op_lo, + rounding_mode); } @@ -5327,6 +5352,14 @@ s390_insn_as_string(const s390_insn *insn) case S390_BFP_NABS: op = "v-fnabs"; break; case S390_BFP_NEG: op = "v-fneg"; break; case S390_BFP_SQRT: op = "v-fsqrt"; break; + default: goto fail; + } + s390_sprintf(buf, "%M %R,%R", op, insn->variant.bfp_unop.dst, + insn->variant.bfp_unop.op); + break; + + case S390_INSN_BFP_CONVERT: + switch (insn->variant.bfp_convert.tag) { case S390_BFP_I32_TO_F32: case S390_BFP_I32_TO_F64: case S390_BFP_I32_TO_F128: @@ -5359,8 +5392,8 @@ s390_insn_as_string(const s390_insn *insn) case S390_BFP_F128_TO_F64: op = "v-f2f"; break; default: goto fail; } - s390_sprintf(buf, "%M %R,%R", op, insn->variant.bfp_unop.dst, - insn->variant.bfp_unop.op); + s390_sprintf(buf, "%M %R,%R", op, insn->variant.bfp_convert.dst, + insn->variant.bfp_convert.op); break; case S390_INSN_BFP128_BINOP: @@ -5385,13 +5418,20 @@ s390_insn_as_string(const s390_insn *insn) break; case S390_INSN_BFP128_UNOP: - case S390_INSN_BFP128_CONVERT_TO: - case S390_INSN_BFP128_CONVERT_FROM: switch (insn->variant.bfp128_unop.tag) { case S390_BFP_ABS: op = "v-fabs"; break; case S390_BFP_NABS: op = "v-fnabs"; break; case S390_BFP_NEG: op = "v-fneg"; break; case S390_BFP_SQRT: op = "v-fsqrt"; break; + default: goto fail; + } + /* Only write the register that identifies the register pair */ + s390_sprintf(buf, "%M %R,%R", op, insn->variant.bfp128_unop.dst_hi, + insn->variant.bfp128_unop.op_hi); + break; + + case S390_INSN_BFP128_CONVERT: + switch (insn->variant.bfp128_convert.tag) { case S390_BFP_I32_TO_F128: case S390_BFP_I64_TO_F128: op = "v-i2f"; break; case S390_BFP_U32_TO_F128: @@ -5407,8 +5447,8 @@ s390_insn_as_string(const s390_insn *insn) default: goto fail; } /* Only write the register that identifies the register pair */ - s390_sprintf(buf, "%M %R,%R", op, insn->variant.bfp128_unop.dst_hi, - insn->variant.bfp128_unop.op_hi); + s390_sprintf(buf, "%M %R,%R", op, insn->variant.bfp128_convert.dst_hi, + insn->variant.bfp128_convert.op_hi); break; case S390_INSN_MFENCE: @@ -5531,9 +5571,10 @@ s390_insn_as_string(const s390_insn *insn) } case S390_INSN_BFP128_UNOP: - case S390_INSN_BFP128_CONVERT_TO: - case S390_INSN_BFP128_CONVERT_FROM: - switch (insn->variant.bfp128_unop.tag) { + goto common; + + case S390_INSN_BFP128_CONVERT: + switch (insn->variant.bfp128_convert.tag) { case S390_BFP_I32_TO_F128: case S390_BFP_U32_TO_F128: case S390_BFP_F32_TO_F128: p += vex_sprintf(p, "4 -> "); goto common; @@ -7398,25 +7439,6 @@ s390_insn_bfp_unop_emit(UChar *buf, const s390_insn *insn) UInt r1 = hregNumber(insn->variant.bfp_unop.dst); UInt r2 = hregNumber(insn->variant.bfp_unop.op); s390_round_t rounding_mode = insn->variant.bfp_unop.rounding_mode; - s390_round_t m3 = rounding_mode; - - /* The "convert to fixed" instructions have a field for the rounding - mode and no FPC modification is necessary. So we handle them - upfront. */ - switch (insn->variant.bfp_unop.tag) { - case S390_BFP_F32_TO_I32: return s390_emit_CFEBR(buf, m3, r1, r2); - case S390_BFP_F64_TO_I32: return s390_emit_CFDBR(buf, m3, r1, r2); - case S390_BFP_F32_TO_I64: return s390_emit_CGEBR(buf, m3, r1, r2); - case S390_BFP_F64_TO_I64: return s390_emit_CGDBR(buf, m3, r1, r2); - - /* We leave m4 as 0 - as gcc */ - case S390_BFP_F32_TO_U32: return s390_emit_CLFEBR(buf, m3, 0, r1, r2); - case S390_BFP_F64_TO_U32: return s390_emit_CLFDBR(buf, m3, 0, r1, r2); - case S390_BFP_F32_TO_U64: return s390_emit_CLGEBR(buf, m3, 0, r1, r2); - case S390_BFP_F64_TO_U64: return s390_emit_CLGDBR(buf, m3, 0, r1, r2); - - default: break; - } /* For all other insns if a special rounding mode is requested, we need to set the FPC first and restore it later. */ @@ -7461,6 +7483,54 @@ s390_insn_bfp_unop_emit(UChar *buf, const s390_insn *insn) } break; + default: goto fail; + } + + if (rounding_mode != S390_ROUND_NEAREST_EVEN) { + /* Restore FPC register from guest state */ + buf = s390_emit_LFPC(buf, S390_REGNO_GUEST_STATE_POINTER, + S390X_GUEST_OFFSET(guest_fpc)); // fpc = guest_fpc + } + return buf; + + fail: + vpanic("s390_insn_bfp_unop_emit"); +} + + +static UChar * +s390_insn_bfp_convert_emit(UChar *buf, const s390_insn *insn) +{ + UInt r1 = hregNumber(insn->variant.bfp_convert.dst); + UInt r2 = hregNumber(insn->variant.bfp_convert.op); + s390_round_t rounding_mode = insn->variant.bfp_convert.rounding_mode; + s390_round_t m3 = rounding_mode; + + /* The "convert to fixed" instructions have a field for the rounding + mode and no FPC modification is necessary. So we handle them + upfront. */ + switch (insn->variant.bfp_convert.tag) { + case S390_BFP_F32_TO_I32: return s390_emit_CFEBR(buf, m3, r1, r2); + case S390_BFP_F64_TO_I32: return s390_emit_CFDBR(buf, m3, r1, r2); + case S390_BFP_F32_TO_I64: return s390_emit_CGEBR(buf, m3, r1, r2); + case S390_BFP_F64_TO_I64: return s390_emit_CGDBR(buf, m3, r1, r2); + + /* We leave m4 as 0 - as gcc */ + case S390_BFP_F32_TO_U32: return s390_emit_CLFEBR(buf, m3, 0, r1, r2); + case S390_BFP_F64_TO_U32: return s390_emit_CLFDBR(buf, m3, 0, r1, r2); + case S390_BFP_F32_TO_U64: return s390_emit_CLGEBR(buf, m3, 0, r1, r2); + case S390_BFP_F64_TO_U64: return s390_emit_CLGDBR(buf, m3, 0, r1, r2); + + default: break; + } + + /* For all other insns if a special rounding mode is requested, + we need to set the FPC first and restore it later. */ + if (rounding_mode != S390_ROUND_NEAREST_EVEN) { + buf = s390_set_fpc_rounding_mode(buf, rounding_mode); + } + + switch (insn->variant.bfp_convert.tag) { case S390_BFP_I32_TO_F32: buf = s390_emit_CEFBRA(buf, 0, 0, r1, r2); break; case S390_BFP_I32_TO_F64: buf = s390_emit_CDFBRA(buf, 0, 0, r1, r2); break; case S390_BFP_I32_TO_F128: buf = s390_emit_CXFBRA(buf, 0, 0, r1, r2); break; @@ -7492,7 +7562,7 @@ s390_insn_bfp_unop_emit(UChar *buf, const s390_insn *insn) return buf; fail: - vpanic("s390_insn_bfp_unop_emit"); + vpanic("s390_insn_bfp_convert_emit"); } @@ -7610,8 +7680,6 @@ s390_insn_bfp128_unop_emit(UChar *buf, const s390_insn *insn) case S390_BFP_NABS: buf = s390_emit_LNXBR(buf, r1_hi, r2_hi); break; case S390_BFP_NEG: buf = s390_emit_LCXBR(buf, r1_hi, r2_hi); break; case S390_BFP_SQRT: buf = s390_emit_SQXBR(buf, r1_hi, r2_hi); break; - case S390_BFP_F128_TO_F32: buf = s390_emit_LEXBRA(buf, 0, 0, r1_hi, r2_hi); break; - case S390_BFP_F128_TO_F64: buf = s390_emit_LDXBRA(buf, 0, 0, r1_hi, r2_hi); break; default: goto fail; } @@ -7627,72 +7695,72 @@ s390_insn_bfp128_unop_emit(UChar *buf, const s390_insn *insn) } -/* Conversion to 128-bit BFP does not require a rounding mode */ static UChar * -s390_insn_bfp128_convert_to_emit(UChar *buf, const s390_insn *insn) +s390_insn_bfp128_convert_emit(UChar *buf, const s390_insn *insn) { - UInt r1_hi = hregNumber(insn->variant.bfp128_unop.dst_hi); - UInt r1_lo = hregNumber(insn->variant.bfp128_unop.dst_lo); - UInt r2 = hregNumber(insn->variant.bfp128_unop.op_hi); - - /* Paranoia */ - vassert(insn->size == 16); - vassert(r1_lo == r1_hi + 2); - vassert((r1_hi & 0x2) == 0); - - switch (insn->variant.bfp128_unop.tag) { - case S390_BFP_I32_TO_F128: buf = s390_emit_CXFBRA(buf, 0, 0, r1_hi, r2); break; - case S390_BFP_I64_TO_F128: buf = s390_emit_CXGBRA(buf, 0, 0, r1_hi, r2); break; - /* Rounding makes no sense -> m3 == 0. m4 is also 0 */ - case S390_BFP_U32_TO_F128: buf = s390_emit_CXLFBR(buf, 0, 0, r1_hi, r2); - break; - case S390_BFP_U64_TO_F128: buf = s390_emit_CXLGBR(buf, 0, 0, r1_hi, r2); - break; - case S390_BFP_F32_TO_F128: buf = s390_emit_LXEBR(buf, r1_hi, r2); break; - case S390_BFP_F64_TO_F128: buf = s390_emit_LXDBR(buf, r1_hi, r2); break; - default: goto fail; - } - - return buf; - - fail: - vpanic("s390_insn_bfp128_convert_to_emit"); -} - - -static UChar * -s390_insn_bfp128_convert_from_emit(UChar *buf, const s390_insn *insn) -{ - UInt r1 = hregNumber(insn->variant.bfp128_unop.dst_hi); - UInt r2_hi = hregNumber(insn->variant.bfp128_unop.op_hi); - UInt r2_lo = hregNumber(insn->variant.bfp128_unop.op_lo); - s390_round_t rounding_mode = insn->variant.bfp128_unop.rounding_mode; + UInt r1_hi = hregNumber(insn->variant.bfp128_convert.dst_hi); + UInt r1_lo = hregNumber(insn->variant.bfp128_convert.dst_lo); + UInt r2_hi = hregNumber(insn->variant.bfp128_convert.op_hi); + UInt r2_lo = hregNumber(insn->variant.bfp128_convert.op_lo); + s390_round_t rounding_mode = insn->variant.bfp128_convert.rounding_mode; /* Paranoia */ - vassert(insn->size != 16); - vassert(r2_lo == r2_hi + 2); - vassert((r2_hi & 0x2) == 0); - - /* The "convert to fixed" instructions have a field for the rounding - mode and no FPC modification is necessary. So we handle them - upfront. */ - switch (insn->variant.bfp_unop.tag) { + vassert(r1_lo == hregNumber(INVALID_HREG) || r1_lo == r1_hi + 2); + vassert(r2_lo == hregNumber(INVALID_HREG) || r2_lo == r2_hi + 2); + vassert(r1_lo == hregNumber(INVALID_HREG) || (r1_hi & 0x2) == 0); + vassert(r2_lo == hregNumber(INVALID_HREG) || (r2_hi & 0x2) == 0); + + switch (insn->variant.bfp128_convert.tag) { + /* Conversion to 128-bit never requires a rounding mode */ + case S390_BFP_I32_TO_F128: return s390_emit_CXFBRA(buf, 0, 0, r1_hi, r2_hi); + case S390_BFP_I64_TO_F128: return s390_emit_CXGBRA(buf, 0, 0, r1_hi, r2_hi); + case S390_BFP_U32_TO_F128: return s390_emit_CXLFBR(buf, 0, 0, r1_hi, r2_hi); + case S390_BFP_U64_TO_F128: return s390_emit_CXLGBR(buf, 0, 0, r1_hi, r2_hi); + case S390_BFP_F32_TO_F128: return s390_emit_LXEBR(buf, r1_hi, r2_hi); + case S390_BFP_F64_TO_F128: return s390_emit_LXDBR(buf, r1_hi, r2_hi); + + /* Conversion from 128-bit requires a rounding mode */ case S390_BFP_F128_TO_I32: - return s390_emit_CFXBR(buf, rounding_mode, r1, r2_hi); + return s390_emit_CFXBR(buf, rounding_mode, r1_hi, r2_hi); case S390_BFP_F128_TO_I64: - return s390_emit_CGXBR(buf, rounding_mode, r1, r2_hi); + return s390_emit_CGXBR(buf, rounding_mode, r1_hi, r2_hi); case S390_BFP_F128_TO_U32: - return s390_emit_CLFXBR(buf, rounding_mode, 0, r1, r2_hi); + return s390_emit_CLFXBR(buf, rounding_mode, 0, r1_hi, r2_hi); case S390_BFP_F128_TO_U64: - return s390_emit_CLGXBR(buf, rounding_mode, 0, r1, r2_hi); + return s390_emit_CLGXBR(buf, rounding_mode, 0, r1_hi, r2_hi); - default: break; + case S390_BFP_F128_TO_F32: + if (rounding_mode != S390_ROUND_NEAREST_EVEN) { + buf = s390_set_fpc_rounding_mode(buf, rounding_mode); + } + buf = s390_emit_LEXBRA(buf, 0, 0, r1_hi, r2_hi); + if (rounding_mode != S390_ROUND_NEAREST_EVEN) { + /* Restore FPC register from guest state */ + buf = s390_emit_LFPC(buf, S390_REGNO_GUEST_STATE_POINTER, + S390X_GUEST_OFFSET(guest_fpc)); // fpc = guest_fpc + } + return buf; + + case S390_BFP_F128_TO_F64: + if (rounding_mode != S390_ROUND_NEAREST_EVEN) { + buf = s390_set_fpc_rounding_mode(buf, rounding_mode); + } + buf = s390_emit_LDXBRA(buf, 0, 0, r1_hi, r2_hi); + if (rounding_mode != S390_ROUND_NEAREST_EVEN) { + /* Restore FPC register from guest state */ + buf = s390_emit_LFPC(buf, S390_REGNO_GUEST_STATE_POINTER, + S390X_GUEST_OFFSET(guest_fpc)); // fpc = guest_fpc + } + return buf; + + default: goto fail; } - vpanic("s390_insn_bfp128_convert_from_emit"); + fail: + vpanic("s390_insn_bfp128_convert_emit"); } @@ -8245,6 +8313,10 @@ emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, s390_insn *insn, end = s390_insn_bfp_compare_emit(buf, insn); break; + case S390_INSN_BFP_CONVERT: + end = s390_insn_bfp_convert_emit(buf, insn); + break; + case S390_INSN_BFP128_BINOP: end = s390_insn_bfp128_binop_emit(buf, insn); break; @@ -8257,12 +8329,8 @@ emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, s390_insn *insn, end = s390_insn_bfp128_unop_emit(buf, insn); break; - case S390_INSN_BFP128_CONVERT_TO: - end = s390_insn_bfp128_convert_to_emit(buf, insn); - break; - - case S390_INSN_BFP128_CONVERT_FROM: - end = s390_insn_bfp128_convert_from_emit(buf, insn); + case S390_INSN_BFP128_CONVERT: + end = s390_insn_bfp128_convert_emit(buf, insn); break; case S390_INSN_MFENCE: diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index a3c5759172..7a49f13e81 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -137,11 +137,11 @@ typedef enum { S390_INSN_BFP_UNOP, S390_INSN_BFP_TRIOP, S390_INSN_BFP_COMPARE, + S390_INSN_BFP_CONVERT, S390_INSN_BFP128_BINOP, /* Binary floating point 128-bit */ S390_INSN_BFP128_UNOP, S390_INSN_BFP128_COMPARE, - S390_INSN_BFP128_CONVERT_TO, - S390_INSN_BFP128_CONVERT_FROM, + S390_INSN_BFP128_CONVERT, S390_INSN_MFENCE, S390_INSN_GZERO, /* Assign zero to a guest register */ S390_INSN_GADD, /* Add a value to a guest register */ @@ -193,13 +193,16 @@ typedef enum { S390_BFP_DIV } s390_bfp_binop_t; - /* The kind of unary BFP operations */ typedef enum { S390_BFP_ABS, S390_BFP_NABS, S390_BFP_NEG, - S390_BFP_SQRT, + S390_BFP_SQRT +} s390_bfp_unop_t; + +/* Type conversion operations: to and/or from floating point */ +typedef enum { S390_BFP_I32_TO_F32, S390_BFP_I32_TO_F64, S390_BFP_I32_TO_F128, @@ -230,7 +233,7 @@ typedef enum { S390_BFP_F128_TO_U64, S390_BFP_F128_TO_F32, S390_BFP_F128_TO_F64 -} s390_bfp_unop_t; +} s390_conv_t; /* Condition code. The encoding of the enumerators matches the value of @@ -340,11 +343,6 @@ typedef struct { HReg src1; s390_opnd_RMI src2; } compare; - struct { - HReg dst; /* condition code in s390 encoding */ - HReg op1; - HReg op2; - } bfp_compare; struct { s390_opnd_RMI src; } test; @@ -401,6 +399,17 @@ typedef struct { HReg dst; /* result */ HReg op; /* operand */ } bfp_unop; + struct { + s390_conv_t tag; + s390_round_t rounding_mode; + HReg dst; /* result */ + HReg op; /* operand */ + } bfp_convert; + struct { + HReg dst; /* condition code in s390 encoding */ + HReg op1; + HReg op2; + } bfp_compare; struct { s390_bfp_binop_t tag; s390_round_t rounding_mode; @@ -409,8 +418,6 @@ typedef struct { HReg op2_hi; /* right operand; high part */ HReg op2_lo; /* right operand; low part */ } bfp128_binop; - /* This variant is also used by the BFP128_CONVERT_TO and - BFP128_CONVERT_FROM insns. */ struct { s390_bfp_unop_t tag; s390_round_t rounding_mode; @@ -419,6 +426,14 @@ typedef struct { HReg op_hi; /* operand; high part */ HReg op_lo; /* operand; low part */ } bfp128_unop; + struct { + s390_conv_t tag; + s390_round_t rounding_mode; + HReg dst_hi; /* 128-bit result high part; 32/64-bit result */ + HReg dst_lo; /* 128-bit result low part */ + HReg op_hi; /* 128-bit operand high part; 32/64-bit opnd */ + HReg op_lo; /* 128-bit operand low part */ + } bfp128_convert; struct { HReg dst; /* condition code in s390 encoding */ HReg op1_hi; /* left operand; high part */ @@ -510,6 +525,8 @@ s390_insn *s390_insn_bfp_binop(UChar size, s390_bfp_binop_t, HReg dst, HReg op2, s390_insn *s390_insn_bfp_unop(UChar size, s390_bfp_unop_t tag, HReg dst, HReg op, s390_round_t); s390_insn *s390_insn_bfp_compare(UChar size, HReg dst, HReg op1, HReg op2); +s390_insn *s390_insn_bfp_convert(UChar size, s390_conv_t tag, HReg dst, + HReg op, s390_round_t); s390_insn *s390_insn_bfp128_binop(UChar size, s390_bfp_binop_t, HReg dst_hi, HReg dst_lo, HReg op2_hi, HReg op2_lo, s390_round_t); @@ -518,9 +535,9 @@ s390_insn *s390_insn_bfp128_unop(UChar size, s390_bfp_unop_t, HReg dst_hi, s390_round_t); s390_insn *s390_insn_bfp128_compare(UChar size, HReg dst, HReg op1_hi, HReg op1_lo, HReg op2_hi, HReg op2_lo); -s390_insn *s390_insn_bfp128_convert_to(UChar size, s390_bfp_unop_t, +s390_insn *s390_insn_bfp128_convert_to(UChar size, s390_conv_t, HReg dst_hi, HReg dst_lo, HReg op); -s390_insn *s390_insn_bfp128_convert_from(UChar size, s390_bfp_unop_t, +s390_insn *s390_insn_bfp128_convert_from(UChar size, s390_conv_t, HReg dst, HReg op_hi, HReg op_lo, s390_round_t); s390_insn *s390_insn_mfence(void); diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index 6616aed27a..42b92c8c62 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -785,7 +785,7 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) { IRType ty = typeOfIRExpr(env->type_env, expr); UChar size; - s390_bfp_unop_t bfpop; + s390_conv_t conv; vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64); @@ -911,18 +911,18 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) return res; } - case Iop_F32toI32S: bfpop = S390_BFP_F32_TO_I32; goto do_convert; - case Iop_F32toI64S: bfpop = S390_BFP_F32_TO_I64; goto do_convert; - case Iop_F32toI32U: bfpop = S390_BFP_F32_TO_U32; goto do_convert; - case Iop_F32toI64U: bfpop = S390_BFP_F32_TO_U64; goto do_convert; - case Iop_F64toI32S: bfpop = S390_BFP_F64_TO_I32; goto do_convert; - case Iop_F64toI64S: bfpop = S390_BFP_F64_TO_I64; goto do_convert; - case Iop_F64toI32U: bfpop = S390_BFP_F64_TO_U32; goto do_convert; - case Iop_F64toI64U: bfpop = S390_BFP_F64_TO_U64; goto do_convert; - case Iop_F128toI32S: bfpop = S390_BFP_F128_TO_I32; goto do_convert_128; - case Iop_F128toI64S: bfpop = S390_BFP_F128_TO_I64; goto do_convert_128; - case Iop_F128toI32U: bfpop = S390_BFP_F128_TO_U32; goto do_convert_128; - case Iop_F128toI64U: bfpop = S390_BFP_F128_TO_U64; goto do_convert_128; + case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert; + case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert; + case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert; + case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert; + case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert; + case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert; + case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert; + case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert; + case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128; + 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; do_convert: { s390_round_t rounding_mode; @@ -931,7 +931,7 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) h1 = s390_isel_float_expr(env, arg2); /* Process operand */ rounding_mode = decode_rounding_mode(arg1); - addInstr(env, s390_insn_bfp_unop(size, bfpop, res, h1, rounding_mode)); + addInstr(env, s390_insn_bfp_convert(size, conv, res, h1, rounding_mode)); return res; } @@ -951,7 +951,7 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) addInstr(env, s390_insn_move(8, f15, op_lo)); rounding_mode = decode_rounding_mode(arg1); - addInstr(env, s390_insn_bfp128_convert_from(size, bfpop, res, f13, f15, + addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15, rounding_mode)); return res; } @@ -1665,6 +1665,7 @@ s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *left = expr->Iex.Unop.arg; s390_bfp_unop_t bfpop; s390_round_t rounding_mode; + s390_conv_t conv; HReg op_hi, op_lo, op, f12, f13, f14, f15; /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ @@ -1674,14 +1675,14 @@ s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, f15 = make_fpr(15); switch (expr->Iex.Unop.op) { - case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd; - case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd; - case Iop_I32StoF128: bfpop = S390_BFP_I32_TO_F128; goto convert_int; - case Iop_I64StoF128: bfpop = S390_BFP_I64_TO_F128; goto convert_int; - case Iop_I32UtoF128: bfpop = S390_BFP_U32_TO_F128; goto convert_int; - case Iop_I64UtoF128: bfpop = S390_BFP_U64_TO_F128; goto convert_int; - case Iop_F32toF128: bfpop = S390_BFP_F32_TO_F128; goto convert_float; - case Iop_F64toF128: bfpop = S390_BFP_F64_TO_F128; goto convert_float; + case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd; + case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd; + case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int; + case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int; + case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int; + case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int; + case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float; + case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float; default: goto irreducible; } @@ -1700,14 +1701,12 @@ s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, convert_float: op = s390_isel_float_expr(env, left); - addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14, - op)); + addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op)); goto move_dst; convert_int: op = s390_isel_int_expr(env, left); - addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14, - op)); + addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op)); goto move_dst; move_dst: @@ -1874,51 +1873,61 @@ s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr) /* --------- BINARY OP --------- */ case Iex_Binop: { IROp op = expr->Iex.Binop.op; + IRExpr *irrm = expr->Iex.Binop.arg1; IRExpr *left = expr->Iex.Binop.arg2; HReg h1, dst; - s390_bfp_unop_t bfpop; s390_round_t rounding_mode; - Int integer_operand; - - integer_operand = 1; + s390_conv_t conv; switch (op) { case Iop_SqrtF32: case Iop_SqrtF64: - bfpop = S390_BFP_SQRT; - integer_operand = 0; - break; + h1 = s390_isel_float_expr(env, left); + dst = newVRegF(env); + rounding_mode = decode_rounding_mode(irrm); + addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1, + rounding_mode)); + return dst; - case Iop_F64toF32: - bfpop = S390_BFP_F64_TO_F32; - integer_operand = 0; - break; + case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float; + case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int; + case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int; + case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int; + 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; + + convert_float: + h1 = s390_isel_float_expr(env, left); + goto convert; - case Iop_I32StoF32: bfpop = S390_BFP_I32_TO_F32; break; - case Iop_I32UtoF32: bfpop = S390_BFP_U32_TO_F32; break; - case Iop_I64StoF32: bfpop = S390_BFP_I64_TO_F32; break; - case Iop_I64StoF64: bfpop = S390_BFP_I64_TO_F64; break; - case Iop_I64UtoF32: bfpop = S390_BFP_U64_TO_F32; break; - case Iop_I64UtoF64: bfpop = S390_BFP_U64_TO_F64; break; + convert_int: + h1 = s390_isel_int_expr(env, left); + goto convert; + convert: + dst = newVRegF(env); + rounding_mode = decode_rounding_mode(irrm); + addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1, + rounding_mode)); + return dst; + default: goto irreducible; case Iop_F128toF64: case Iop_F128toF32: { - HReg op_hi, op_lo, f12, f13, f14, f15; + HReg op_hi, op_lo, f13, f15; - bfpop = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32 - : S390_BFP_F128_TO_F64; + conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32 + : S390_BFP_F128_TO_F64; - rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1); + rounding_mode = decode_rounding_mode(irrm); - s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2); + s390_isel_float128_expr(&op_hi, &op_lo, env, left); - /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ - f12 = make_fpr(12); + /* We use non-virtual registers as pairs (f13, f15) */ f13 = make_fpr(13); - f14 = make_fpr(14); f15 = make_fpr(15); /* operand --> (f13, f15) */ @@ -1926,26 +1935,11 @@ s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr) addInstr(env, s390_insn_move(8, f15, op_lo)); dst = newVRegF(env); - addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15, - rounding_mode)); - - /* Move result to virtual destination registers */ - addInstr(env, s390_insn_move(8, dst, f12)); + addInstr(env, s390_insn_bfp128_convert_from(16, conv, dst, f13, f15, + rounding_mode)); return dst; } } - - /* Process operand */ - if (integer_operand) { - h1 = s390_isel_int_expr(env, left); - } else { - h1 = s390_isel_float_expr(env, left); - } - - dst = newVRegF(env); - rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1); - addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode)); - return dst; } /* --------- UNARY OP --------- */ @@ -1953,7 +1947,10 @@ s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr) IROp op = expr->Iex.Unop.op; IRExpr *left = expr->Iex.Unop.arg; s390_bfp_unop_t bfpop; - s390_round_t rounding_mode; + /* No rounding mode is needed for these conversions. Provide the + default rounding mode. It will not be used. */ + s390_round_t rounding_mode = S390_ROUND_NEAREST_EVEN; + s390_conv_t conv; HReg h1, dst; if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) { @@ -1982,24 +1979,34 @@ s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr) break; case Iop_AbsF32: - case Iop_AbsF64: bfpop = S390_BFP_ABS; break; - case Iop_I32StoF64: bfpop = S390_BFP_I32_TO_F64; break; - case Iop_I32UtoF64: bfpop = S390_BFP_U32_TO_F64; break; - case Iop_F32toF64: bfpop = S390_BFP_F32_TO_F64; break; + case Iop_AbsF64: + bfpop = S390_BFP_ABS; + break; + + case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1; + case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1; + case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1; + + convert_float1: + h1 = s390_isel_float_expr(env, left); + goto convert1; + + convert_int1: + h1 = s390_isel_int_expr(env, left); + goto convert1; + + convert1: + dst = newVRegF(env); + addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1, rounding_mode)); + return dst; + default: goto irreducible; } /* Process operand */ - if (op == Iop_I32StoF64 || op == Iop_I32UtoF64) - h1 = s390_isel_int_expr(env, left); - else if (bfpop == S390_BFP_NABS) - h1 = s390_isel_float_expr(env, left->Iex.Unop.arg); - else - h1 = s390_isel_float_expr(env, left); - + h1 = s390_isel_float_expr(env, left); dst = newVRegF(env); - rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */ addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode)); return dst; }