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 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/host_s390_defs.c b/priv/host_s390_defs.c
index 04d8a39..fe5a633 100644
--- a/priv/host_s390_defs.c
+++ b/priv/host_s390_defs.c
@@ -680,6 +680,11 @@
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 @@
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 @@
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 @@
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:
@@ -4746,6 +4750,23 @@
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,
s390_round_t rounding_mode)
@@ -4803,42 +4824,46 @@
}
-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,
+s390_insn_bfp128_convert_to(UChar size, s390_conv_t tag, HReg dst_hi,
+ HReg dst_lo, HReg op)
+{
+ /* 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;
+
+ return s390_insn_bfp128_convert(size, tag, dst_hi, dst_lo, op,
+ INVALID_HREG, rounding_mode);
+}
+
+
+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)
{
- s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
-
- 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 insn;
+ return s390_insn_bfp128_convert(size, tag, dst, INVALID_HREG, op_hi, op_lo,
+ rounding_mode);
}
@@ -5327,6 +5352,14 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
}
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 @@
return buf;
fail:
- vpanic("s390_insn_bfp_unop_emit");
+ vpanic("s390_insn_bfp_convert_emit");
}
@@ -7610,8 +7680,6 @@
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 @@
}
-/* 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);
+ 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(r1_lo == r1_hi + 2);
- vassert((r1_hi & 0x2) == 0);
+ 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_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;
+ 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_hi, r2_hi);
+
+ case S390_BFP_F128_TO_I64:
+ 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_hi, r2_hi);
+
+ case S390_BFP_F128_TO_U64:
+ return s390_emit_CLGXBR(buf, rounding_mode, 0, r1_hi, r2_hi);
+
+ 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;
}
- 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;
-
- /* 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) {
- case S390_BFP_F128_TO_I32:
- return s390_emit_CFXBR(buf, rounding_mode, r1, r2_hi);
-
- case S390_BFP_F128_TO_I64:
- return s390_emit_CGXBR(buf, rounding_mode, r1, r2_hi);
-
- case S390_BFP_F128_TO_U32:
- return s390_emit_CLFXBR(buf, rounding_mode, 0, r1, r2_hi);
-
- case S390_BFP_F128_TO_U64:
- return s390_emit_CLGXBR(buf, rounding_mode, 0, r1, r2_hi);
-
- default: break;
- }
-
- vpanic("s390_insn_bfp128_convert_from_emit");
+ vpanic("s390_insn_bfp128_convert_emit");
}
@@ -8245,6 +8313,10 @@
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 @@
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/priv/host_s390_defs.h b/priv/host_s390_defs.h
index a3c5759..7a49f13 100644
--- a/priv/host_s390_defs.h
+++ b/priv/host_s390_defs.h
@@ -137,11 +137,11 @@
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 @@
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 @@
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
@@ -341,11 +344,6 @@
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;
/* Convert the condition code to a boolean value. */
@@ -402,6 +400,17 @@
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;
HReg dst_hi; /* left operand; high part */
@@ -409,8 +418,6 @@
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;
@@ -420,6 +427,14 @@
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 */
HReg op1_lo; /* left operand; low part */
@@ -510,6 +525,8 @@
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_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/priv/host_s390_isel.c b/priv/host_s390_isel.c
index 6616aed..42b92c8 100644
--- a/priv/host_s390_isel.c
+++ b/priv/host_s390_isel.c
@@ -785,7 +785,7 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* --------- 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;
- 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_float:
+ h1 = s390_isel_float_expr(env, left);
+ goto convert;
+ 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 @@
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 @@
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 @@
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;
}