|
From: <sv...@va...> - 2015-09-05 20:36:00
|
Author: florian
Date: Sat Sep 5 21:35:52 2015
New Revision: 3183
Log:
s390: Add support for fixbr(a) instructions.
New IROp Iop_RoundF128toInt.
Patch by Andreas Arnez <ar...@li...>.
Part of fixing BZ #350290.
Modified:
trunk/priv/guest_s390_toIR.c
trunk/priv/host_s390_defs.c
trunk/priv/host_s390_defs.h
trunk/priv/host_s390_isel.c
trunk/priv/ir_defs.c
trunk/pub/libvex_ir.h
Modified: trunk/priv/guest_s390_toIR.c
==============================================================================
--- trunk/priv/guest_s390_toIR.c (original)
+++ trunk/priv/guest_s390_toIR.c Sat Sep 5 21:35:52 2015
@@ -12410,6 +12410,19 @@
}
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)
{
IRTemp result = newTemp(Ity_F32);
@@ -14531,7 +14544,9 @@
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;
Modified: trunk/priv/host_s390_defs.c
==============================================================================
--- trunk/priv/host_s390_defs.c (original)
+++ trunk/priv/host_s390_defs.c Sat Sep 5 21:35:52 2015
@@ -3973,6 +3973,23 @@
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)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
@@ -5748,7 +5765,7 @@
}
-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)
@@ -5756,9 +5773,10 @@
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));
@@ -6728,7 +6746,8 @@
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,
@@ -9003,6 +9022,7 @@
/* 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;
}
Modified: trunk/priv/host_s390_defs.h
==============================================================================
--- trunk/priv/host_s390_defs.h (original)
+++ trunk/priv/host_s390_defs.h Sat Sep 5 21:35:52 2015
@@ -244,7 +244,8 @@
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 */
@@ -660,6 +661,9 @@
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,
Modified: trunk/priv/host_s390_isel.c
==============================================================================
--- trunk/priv/host_s390_isel.c (original)
+++ trunk/priv/host_s390_isel.c Sat Sep 5 21:35:52 2015
@@ -2143,6 +2143,42 @@
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;
}
Modified: trunk/priv/ir_defs.c
==============================================================================
--- trunk/priv/ir_defs.c (original)
+++ trunk/priv/ir_defs.c Sat Sep 5 21:35:52 2015
@@ -396,6 +396,7 @@
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;
@@ -3161,6 +3162,7 @@
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);
Modified: trunk/pub/libvex_ir.h
==============================================================================
--- trunk/pub/libvex_ir.h (original)
+++ trunk/pub/libvex_ir.h Sat Sep 5 21:35:52 2015
@@ -713,6 +713,8 @@
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
|