Subject: [PATCH v2] s390x: Fix unrecognized instruction fiebra Add support for the z/Architecture instructions FIEBRA and FIDBRA. Also add a suitable test case. GCC may emit FIEBRA since the following GCC patch: S/390: Add support for the "load fp integer" instructions: https://gcc.gnu.org/ml/gcc-patches/2013-09/msg00112.html Index: valgrind/none/tests/s390x/rounding-6.c =================================================================== --- valgrind.orig/none/tests/s390x/rounding-6.c +++ valgrind/none/tests/s390x/rounding-6.c @@ -44,6 +44,20 @@ do { \ opcode, src, dst, cc, rtext(round)); \ } while (0) +#define round_to_int(opcode,type,round,value) \ +do { \ + type src = value; \ + type dst; \ + \ + __asm__ volatile (opcode " %[dst]," #round ",%[src]\n\t" \ + : [dst] "=f"(dst) \ + : [src] "f"(src) \ + : ); \ + \ + printf("%s %.5f\t-> %g %s\n", \ + opcode, src, dst, rtext(round)); \ +} while (0) + #define cfebr(value, round) \ convert_to_int("cfebr",float,int32_t,PRId32,round,value) @@ -54,6 +68,11 @@ do { \ #define cgdbr(value, round) \ convert_to_int("cgdbr",double,int64_t,PRId64,round,value) +#define fiebr(value, round) \ + round_to_int("fiebr",float,round,value) +#define fidbr(value, round) \ + round_to_int("fidbr",double,round,value) + void set_rounding_mode(unsigned mode) { @@ -117,5 +136,25 @@ int main(void) cgdbr(dval[j], M3_BFP_ROUND_NEGINF); } + /* f32 -> f32, round to int */ + for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) { + set_rounding_mode(FPC_BFP_ROUND_ZERO); + fiebr(dval[j], M3_BFP_ROUND_NEAREST_EVEN); + set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN); + fiebr(dval[j], M3_BFP_ROUND_ZERO); + fiebr(dval[j], M3_BFP_ROUND_POSINF); + fiebr(dval[j], M3_BFP_ROUND_NEGINF); + } + + /* f64 -> f64, round to int */ + for (j = 0; j < sizeof dval / sizeof dval[0]; ++j) { + set_rounding_mode(FPC_BFP_ROUND_ZERO); + fidbr(dval[j], M3_BFP_ROUND_NEAREST_EVEN); + set_rounding_mode(FPC_BFP_ROUND_NEAREST_EVEN); + fidbr(dval[j], M3_BFP_ROUND_ZERO); + fidbr(dval[j], M3_BFP_ROUND_POSINF); + fidbr(dval[j], M3_BFP_ROUND_NEGINF); + } + return 0; } Index: valgrind/none/tests/s390x/rounding-6.stdout.exp =================================================================== --- valgrind.orig/none/tests/s390x/rounding-6.stdout.exp +++ valgrind/none/tests/s390x/rounding-6.stdout.exp @@ -142,3 +142,75 @@ cgdbr 0.000000 -> 0 cc = 0 [-> nearest cgdbr 0.000000 -> 0 cc = 0 [-> 0] cgdbr 0.000000 -> 0 cc = 0 [-> +inf] cgdbr 0.000000 -> 0 cc = 0 [-> -inf] +fiebr 1.25000 -> 1 [-> nearest even] +fiebr 1.25000 -> 1 [-> 0] +fiebr 1.25000 -> 2 [-> +inf] +fiebr 1.25000 -> 1 [-> -inf] +fiebr 1.50000 -> 2 [-> nearest even] +fiebr 1.50000 -> 1 [-> 0] +fiebr 1.50000 -> 2 [-> +inf] +fiebr 1.50000 -> 1 [-> -inf] +fiebr 2.50000 -> 2 [-> nearest even] +fiebr 2.50000 -> 2 [-> 0] +fiebr 2.50000 -> 3 [-> +inf] +fiebr 2.50000 -> 2 [-> -inf] +fiebr 1.75000 -> 2 [-> nearest even] +fiebr 1.75000 -> 1 [-> 0] +fiebr 1.75000 -> 2 [-> +inf] +fiebr 1.75000 -> 1 [-> -inf] +fiebr -1.25000 -> -1 [-> nearest even] +fiebr -1.25000 -> -1 [-> 0] +fiebr -1.25000 -> -1 [-> +inf] +fiebr -1.25000 -> -2 [-> -inf] +fiebr -1.50000 -> -2 [-> nearest even] +fiebr -1.50000 -> -1 [-> 0] +fiebr -1.50000 -> -1 [-> +inf] +fiebr -1.50000 -> -2 [-> -inf] +fiebr -2.50000 -> -2 [-> nearest even] +fiebr -2.50000 -> -2 [-> 0] +fiebr -2.50000 -> -2 [-> +inf] +fiebr -2.50000 -> -3 [-> -inf] +fiebr -1.75000 -> -2 [-> nearest even] +fiebr -1.75000 -> -1 [-> 0] +fiebr -1.75000 -> -1 [-> +inf] +fiebr -1.75000 -> -2 [-> -inf] +fiebr 0.00000 -> 0 [-> nearest even] +fiebr 0.00000 -> 0 [-> 0] +fiebr 0.00000 -> 0 [-> +inf] +fiebr 0.00000 -> 0 [-> -inf] +fidbr 1.25000 -> 1 [-> nearest even] +fidbr 1.25000 -> 1 [-> 0] +fidbr 1.25000 -> 2 [-> +inf] +fidbr 1.25000 -> 1 [-> -inf] +fidbr 1.50000 -> 2 [-> nearest even] +fidbr 1.50000 -> 1 [-> 0] +fidbr 1.50000 -> 2 [-> +inf] +fidbr 1.50000 -> 1 [-> -inf] +fidbr 2.50000 -> 2 [-> nearest even] +fidbr 2.50000 -> 2 [-> 0] +fidbr 2.50000 -> 3 [-> +inf] +fidbr 2.50000 -> 2 [-> -inf] +fidbr 1.75000 -> 2 [-> nearest even] +fidbr 1.75000 -> 1 [-> 0] +fidbr 1.75000 -> 2 [-> +inf] +fidbr 1.75000 -> 1 [-> -inf] +fidbr -1.25000 -> -1 [-> nearest even] +fidbr -1.25000 -> -1 [-> 0] +fidbr -1.25000 -> -1 [-> +inf] +fidbr -1.25000 -> -2 [-> -inf] +fidbr -1.50000 -> -2 [-> nearest even] +fidbr -1.50000 -> -1 [-> 0] +fidbr -1.50000 -> -1 [-> +inf] +fidbr -1.50000 -> -2 [-> -inf] +fidbr -2.50000 -> -2 [-> nearest even] +fidbr -2.50000 -> -2 [-> 0] +fidbr -2.50000 -> -2 [-> +inf] +fidbr -2.50000 -> -3 [-> -inf] +fidbr -1.75000 -> -2 [-> nearest even] +fidbr -1.75000 -> -1 [-> 0] +fidbr -1.75000 -> -1 [-> +inf] +fidbr -1.75000 -> -2 [-> -inf] +fidbr 0.00000 -> 0 [-> nearest even] +fidbr 0.00000 -> 0 [-> 0] +fidbr 0.00000 -> 0 [-> +inf] +fidbr 0.00000 -> 0 [-> -inf] Index: valgrind/VEX/priv/guest_s390_toIR.c =================================================================== --- valgrind.orig/VEX/priv/guest_s390_toIR.c +++ valgrind/VEX/priv/guest_s390_toIR.c @@ -12384,6 +12384,32 @@ s390_irgen_LXEB(UChar r1, IRTemp op2addr } static const HChar * +s390_irgen_FIEBRA(UChar m3, UChar m4 __attribute__((unused)), + UChar r1, UChar r2) +{ + IRTemp result = newTemp(Ity_F32); + + assign(result, binop(Iop_RoundF32toInt, mkexpr(encode_bfp_rounding_mode(m3)), + get_fpr_w0(r2))); + put_fpr_w0(r1, mkexpr(result)); + + return "fiebra"; +} + +static const HChar * +s390_irgen_FIDBRA(UChar m3, UChar m4 __attribute__((unused)), + UChar r1, UChar r2) +{ + IRTemp result = newTemp(Ity_F64); + + assign(result, binop(Iop_RoundF64toInt, mkexpr(encode_bfp_rounding_mode(m3)), + get_fpr_dw0(r2))); + put_fpr_dw0(r1, mkexpr(result)); + + return "fidbra"; +} + +static const HChar * s390_irgen_LNEBR(UChar r1, UChar r2) { IRTemp result = newTemp(Ity_F32); @@ -14520,11 +14546,15 @@ s390_decode_4byte_and_irgen(const UChar case 0xb350: /* TBEDR */ goto unimplemented; case 0xb351: /* TBDR */ goto unimplemented; case 0xb353: /* DIEBR */ goto unimplemented; - case 0xb357: /* FIEBR */ goto unimplemented; + case 0xb357: s390_format_RRF_UUFF(s390_irgen_FIEBRA, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; case 0xb358: /* THDER */ goto unimplemented; case 0xb359: /* THDR */ goto unimplemented; case 0xb35b: /* DIDBR */ goto unimplemented; - case 0xb35f: /* FIDBR */ goto unimplemented; + case 0xb35f: s390_format_RRF_UUFF(s390_irgen_FIDBRA, ovl.fmt.RRF2.m3, + ovl.fmt.RRF2.m4, ovl.fmt.RRF2.r1, + ovl.fmt.RRF2.r2); goto ok; case 0xb360: /* LPXR */ goto unimplemented; case 0xb361: /* LNXR */ goto unimplemented; case 0xb362: /* LTXR */ goto unimplemented; Index: valgrind/VEX/priv/host_s390_defs.c =================================================================== --- valgrind.orig/VEX/priv/host_s390_defs.c +++ valgrind/VEX/priv/host_s390_defs.c @@ -3939,6 +3939,40 @@ s390_emit_LEXBRA(UChar *p, UChar m3, UCh static UChar * +s390_emit_FIEBRA(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), "fiebr", r1, m3, r2); + else + s390_disasm(ENC5(MNM, FPR, UINT, FPR, UINT), + "fiebra", r1, m3, r2, m4); + } + + return emit_RRF2(p, 0xb3570000, m3, m4, r1, r2); +} + + +static UChar * +s390_emit_FIDBRA(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), "fidbr", r1, m3, r2); + else + s390_disasm(ENC5(MNM, FPR, UINT, FPR, UINT), + "fidbra", r1, m3, r2, m4); + } + + return emit_RRF2(p, 0xb35f0000, m3, m4, r1, r2); +} + + +static UChar * s390_emit_MEEBR(UChar *p, UChar r1, UChar r2) { if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) @@ -6693,6 +6727,8 @@ s390_insn_as_string(const s390_insn *ins case S390_BFP_F64_TO_F128: 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; default: goto fail; } s390_sprintf(buf, "%M %R,%R", op, insn->variant.bfp_convert.dst_hi, @@ -8964,6 +9000,10 @@ s390_insn_bfp_convert_emit(UChar *buf, c case S390_BFP_F128_TO_F32: return s390_emit_LEXBRA(buf, m3, m4, r1, r2); case S390_BFP_F128_TO_F64: return s390_emit_LDXBRA(buf, m3, m4, r1, r2); + /* 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); + default: goto fail; } Index: valgrind/VEX/priv/host_s390_defs.h =================================================================== --- valgrind.orig/VEX/priv/host_s390_defs.h +++ valgrind/VEX/priv/host_s390_defs.h @@ -242,7 +242,9 @@ typedef enum { S390_BFP_F128_TO_U32, S390_BFP_F128_TO_U64, S390_BFP_F128_TO_F32, - S390_BFP_F128_TO_F64 + S390_BFP_F128_TO_F64, + S390_BFP_F32_TO_F32I, + S390_BFP_F64_TO_F64I } s390_bfp_conv_t; /* Type conversion operations: to and/or from decimal floating point */ Index: valgrind/VEX/priv/host_s390_isel.c =================================================================== --- valgrind.orig/VEX/priv/host_s390_isel.c +++ valgrind/VEX/priv/host_s390_isel.c @@ -2378,6 +2378,8 @@ s390_isel_float_expr_wrk(ISelEnv *env, I return dst; case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float; + case Iop_RoundF32toInt: conv = S390_BFP_F32_TO_F32I; goto convert_float; + case Iop_RoundF64toInt: conv = S390_BFP_F64_TO_F64I; 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;