New IROp Iop_RoundF128toInt.
Patch by Andreas Arnez <arnez@linux.vnet.ibm.com>.
Part of fixing BZ #350290.
git-svn-id: svn://svn.valgrind.org/vex/trunk@3183
return "fidbra";
}
+static const HChar *
+s390_irgen_FIXBRA(UChar m3, UChar m4 __attribute__((unused)),
+ UChar r1, UChar r2)
+{
+ IRTemp result = newTemp(Ity_F128);
+
+ assign(result, binop(Iop_RoundF128toInt, mkexpr(encode_bfp_rounding_mode(m3)),
+ get_fpr_pair(r2)));
+ put_fpr_pair(r1, mkexpr(result));
+
+ return "fixbra";
+}
+
static const HChar *
s390_irgen_LNEBR(UChar r1, UChar r2)
{
case 0xb346: s390_format_RRF_UUFF(s390_irgen_LEXBR, ovl.fmt.RRF2.m3,
ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1,
ovl.fmt.RRF2.r2); goto ok;
- case 0xb347: /* FIXBR */ goto unimplemented;
+ case 0xb347: s390_format_RRF_UUFF(s390_irgen_FIXBRA, ovl.fmt.RRF2.m3,
+ ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1,
+ ovl.fmt.RRF2.r2); goto ok;
case 0xb348: /* KXBR */ goto unimplemented;
case 0xb349: s390_format_RRE_FF(s390_irgen_CXBR, ovl.fmt.RRE.r1,
ovl.fmt.RRE.r2); goto ok;
}
+static UChar *
+s390_emit_FIXBRA(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2)
+{
+ vassert(m3 == 0 || s390_host_has_fpext);
+
+ if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+ if (m4 == 0)
+ s390_disasm(ENC4(MNM, FPR, UINT, FPR), "fixbr", r1, m3, r2);
+ else
+ s390_disasm(ENC5(MNM, FPR, UINT, FPR, UINT),
+ "fixbra", r1, m3, r2, m4);
+ }
+
+ return emit_RRF2(p, 0xb3470000, m3, m4, r1, r2);
+}
+
+
static UChar *
s390_emit_MEEBR(UChar *p, UChar r1, UChar r2)
{
}
-static s390_insn *
+s390_insn *
s390_insn_bfp128_convert(UChar size, s390_bfp_conv_t tag, HReg dst_hi,
HReg dst_lo, HReg op_hi, HReg op_lo,
s390_bfp_round_t rounding_mode)
s390_insn *insn = LibVEX_Alloc_inline(sizeof(s390_insn));
if (size == 16) {
- /* From smaller size to 16 bytes */
+ /* From smaller or equal size to 16 bytes */
vassert(is_valid_fp128_regpair(dst_hi, dst_lo));
- vassert(hregIsInvalid(op_lo));
+ vassert(hregIsInvalid(op_lo)
+ || is_valid_fp128_regpair(op_hi, op_lo));
} else {
/* From 16 bytes to smaller size */
vassert(is_valid_fp128_regpair(op_hi, op_lo));
case S390_BFP_F128_TO_F32:
case S390_BFP_F128_TO_F64: op = "v-f2f"; break;
case S390_BFP_F32_TO_F32I:
- case S390_BFP_F64_TO_F64I: op = "v-f2fi"; break;
+ case S390_BFP_F64_TO_F64I:
+ case S390_BFP_F128_TO_F128I: op = "v-f2fi"; break;
default: goto fail;
}
s390_sprintf(buf, "%M %R,%R", op, insn->variant.bfp_convert.dst_hi,
/* Load FP integer */
case S390_BFP_F32_TO_F32I: return s390_emit_FIEBRA(buf, m3, m4, r1, r2);
case S390_BFP_F64_TO_F64I: return s390_emit_FIDBRA(buf, m3, m4, r1, r2);
+ case S390_BFP_F128_TO_F128I: return s390_emit_FIXBRA(buf, m3, m4, r1, r2);
default: goto fail;
}
S390_BFP_F128_TO_F32,
S390_BFP_F128_TO_F64,
S390_BFP_F32_TO_F32I,
- S390_BFP_F64_TO_F64I
+ S390_BFP_F64_TO_F64I,
+ S390_BFP_F128_TO_F128I
} s390_bfp_conv_t;
/* Type conversion operations: to and/or from decimal floating point */
s390_insn *s390_insn_bfp_compare(UChar size, HReg dst, HReg op1, HReg op2);
s390_insn *s390_insn_bfp_convert(UChar size, s390_bfp_conv_t tag, HReg dst,
HReg op, s390_bfp_round_t);
+s390_insn *s390_insn_bfp128_convert(UChar size, s390_bfp_conv_t tag, HReg dst_hi,
+ HReg dst_lo, HReg op_hi, HReg op_lo,
+ s390_bfp_round_t rounding_mode);
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_insn *s390_insn_bfp128_unop(UChar size, s390_bfp_unop_t, HReg dst_hi,
return;
}
+ case Iop_RoundF128toInt: {
+ IRExpr *irrm;
+ IRExpr *left;
+ s390_bfp_round_t rm;
+ HReg op_hi, op_lo;
+ HReg f0, f2, f4, f6; /* real registers */
+
+ f4 = make_fpr(4); /* source */
+ f6 = make_fpr(6); /* source */
+ f0 = make_fpr(0); /* destination */
+ f2 = make_fpr(2); /* destination */
+
+ irrm = expr->Iex.Binop.arg1;
+ left = expr->Iex.Binop.arg2;
+
+ if (s390_host_has_fpext) {
+ rm = get_bfp_rounding_mode(env, irrm);
+ } else {
+ set_bfp_rounding_mode_in_fpc(env, irrm);
+ rm = S390_BFP_ROUND_PER_FPC;
+ }
+
+ s390_isel_float128_expr(&op_hi, &op_lo, env, left);
+ /* 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_bfp128_convert(16, S390_BFP_F128_TO_F128I,
+ f0, f2, f4, f6, 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;
+ }
+
default:
goto irreducible;
}
case Iop_F32toF64: vex_printf("F32toF64"); return;
case Iop_F64toF32: vex_printf("F64toF32"); return;
+ case Iop_RoundF128toInt: vex_printf("RoundF128toInt"); return;
case Iop_RoundF64toInt: vex_printf("RoundF64toInt"); return;
case Iop_RoundF32toInt: vex_printf("RoundF32toInt"); return;
case Iop_RoundF64toF32: vex_printf("RoundF64toF32"); return;
UNARY(Ity_F128, Ity_F128);
case Iop_SqrtF128:
+ case Iop_RoundF128toInt:
BINARY(ity_RMode,Ity_F128, Ity_F128);
case Iop_I32StoF128: UNARY(Ity_I32, Ity_F128);
Iop_CosF64, /* FCOS */
Iop_TanF64, /* FTAN */
Iop_2xm1F64, /* (2^arg - 1.0) */
+ Iop_RoundF128toInt, /* F128 value to nearest integral value (still
+ as F128) */
Iop_RoundF64toInt, /* F64 value to nearest integral value (still
as F64) */
Iop_RoundF32toInt, /* F32 value to nearest integral value (still