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);
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:
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);
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:
}
+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_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);
}
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:
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:
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:
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:
}
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;
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. */
}
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;
return buf;
fail:
- vpanic("s390_insn_bfp_unop_emit");
+ vpanic("s390_insn_bfp_convert_emit");
}
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;
}
}
-/* 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");
}
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;
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:
{
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);
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;
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;
}
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;
}
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)) */
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;
}
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:
/* --------- 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) */
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 --------- */
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) {
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;
}