From: Florian Krohm Date: Sat, 5 Sep 2015 20:35:52 +0000 (+0000) Subject: s390: Add support for fixbr(a) instructions. X-Git-Tag: svn/VALGRIND_3_11_0^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=34cad98bc458b617e2b87d3b556720e71550b66a;p=thirdparty%2Fvalgrind.git s390: Add support for fixbr(a) instructions. New IROp Iop_RoundF128toInt. Patch by Andreas Arnez . Part of fixing BZ #350290. git-svn-id: svn://svn.valgrind.org/vex/trunk@3183 --- diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index 5ac5380cf6..116a606259 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -12409,6 +12409,19 @@ s390_irgen_FIDBRA(UChar m3, UChar m4 __attribute__((unused)), 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) { @@ -14531,7 +14544,9 @@ s390_decode_4byte_and_irgen(const UChar *bytes) 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; diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index 94344ca495..9885d474f0 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -3972,6 +3972,23 @@ s390_emit_FIDBRA(UChar *p, UChar m3, UChar m4, UChar r1, UChar r2) } +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) { @@ -5748,7 +5765,7 @@ s390_insn_bfp128_compare(UChar size, HReg dst, HReg op1_hi, HReg op1_lo, } -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_bfp128_convert(UChar size, s390_bfp_conv_t tag, HReg dst_hi, 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 @@ s390_insn_as_string(const s390_insn *insn) 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 @@ s390_insn_bfp_convert_emit(UChar *buf, const s390_insn *insn) /* 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; } diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index 7390f7f5e5..a7c4b1e9f2 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -244,7 +244,8 @@ typedef enum { 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_unop(UChar size, s390_bfp_unop_t tag, HReg dst, 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, diff --git a/VEX/priv/host_s390_isel.c b/VEX/priv/host_s390_isel.c index 84e42f0b72..02f399d049 100644 --- a/VEX/priv/host_s390_isel.c +++ b/VEX/priv/host_s390_isel.c @@ -2143,6 +2143,42 @@ s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 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; } diff --git a/VEX/priv/ir_defs.c b/VEX/priv/ir_defs.c index 8c9b9ab032..88a2bf0fce 100644 --- a/VEX/priv/ir_defs.c +++ b/VEX/priv/ir_defs.c @@ -396,6 +396,7 @@ void ppIROp ( IROp op ) 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 @@ void typeOfPrimop ( IROp op, 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); diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index f1c09abab5..9f10991d54 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -713,6 +713,8 @@ typedef 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