* [PATCH v3 0/5] target/s390x: Implement DIVIDE TO INTEGER
@ 2026-01-29 18:57 Ilya Leoshkevich
2026-01-29 18:57 ` [PATCH v3 1/5] target/s390x: Dump Floating-Point-Control Register Ilya Leoshkevich
` (4 more replies)
0 siblings, 5 replies; 11+ messages in thread
From: Ilya Leoshkevich @ 2026-01-29 18:57 UTC (permalink / raw)
To: Thomas Huth, Richard Henderson
Cc: David Hildenbrand, qemu-s390x, qemu-devel, Ilya Leoshkevich
v2: https://lore.kernel.org/qemu-devel/20260127153736.62730-1-iii@linux.ibm.com/
v2 -> v3: Use FloatParts64 (Richard).
Improve "smallish" comment (Richard).
Use parts_muladd_scalbn (Richard).
Get rid of manual precision rounding (Richard).
New patch: parts_round_to_int_normal() improvement.
New 64-bit testcase for a fuzzer finding on one of the
intermediate versions. I have to admit I did not put down and
then forgot what exactly it was about, but it must be
interesting, so I decided to keep it.
v1: https://lore.kernel.org/qemu-devel/20260121222116.713325-1-iii@linux.ibm.com/
v1 -> v2: Move the implementatation to fpu/ and rewrite using
FloatParts (Richard). I can't say I particularly like the way
it looks, but at least most macros are gone and it survives
fuzzing.
Explain why we need -O0 for the test (Alex).
New patch: s390_get_bfp_rounding_mode().
Add a few comments with calculation examples to the test.
Hi,
This series implements DIVIDE TO INTEGER instruction, which is
required to run LuaJIT.
Patch 1 is a debugging helper, patch 2 is a small refactoring, patch 3
is an improvement for an FPU rounding helper, patch 4 is the
implementation.
Since the instruction is quite complex, I've extensively tested it
using a libFuzzer-based harness [1] that compares emulation with native
execution at ~15k exec/s. The tests (patch 5) use data generated
this way.
Best regards,
Ilya
[1] https://github.com/iii-i/qemu/commits/iii/wip/fuzz-tcg-v1/
Ilya Leoshkevich (5):
target/s390x: Dump Floating-Point-Control Register
target/s390x: Extract s390_get_bfp_rounding_mode()
fpu: Restrict parts_round_to_int_normal to target precision
target/s390x: Implement DIVIDE TO INTEGER
tests/tcg/s390x: Test DIVIDE TO INTEGER
fpu/softfloat-parts.c.inc | 7 +-
fpu/softfloat.c | 144 +++++++++++++++
include/fpu/softfloat.h | 11 ++
target/s390x/cpu-dump.c | 1 +
target/s390x/helper.h | 1 +
target/s390x/tcg/fpu_helper.c | 118 +++++++++----
target/s390x/tcg/insn-data.h.inc | 5 +-
target/s390x/tcg/translate.c | 26 +++
tests/tcg/s390x/Makefile.target | 5 +
tests/tcg/s390x/divide-to-integer.c | 265 ++++++++++++++++++++++++++++
10 files changed, 545 insertions(+), 38 deletions(-)
create mode 100644 tests/tcg/s390x/divide-to-integer.c
--
2.52.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/5] target/s390x: Dump Floating-Point-Control Register
2026-01-29 18:57 [PATCH v3 0/5] target/s390x: Implement DIVIDE TO INTEGER Ilya Leoshkevich
@ 2026-01-29 18:57 ` Ilya Leoshkevich
2026-01-30 7:27 ` Thomas Huth
2026-01-29 18:57 ` [PATCH v3 2/5] target/s390x: Extract s390_get_bfp_rounding_mode() Ilya Leoshkevich
` (3 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Ilya Leoshkevich @ 2026-01-29 18:57 UTC (permalink / raw)
To: Thomas Huth, Richard Henderson
Cc: David Hildenbrand, qemu-s390x, qemu-devel, Ilya Leoshkevich,
Alex Bennée
Knowing the value of this register is very useful for debugging
floating-point code.
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
target/s390x/cpu-dump.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/target/s390x/cpu-dump.c b/target/s390x/cpu-dump.c
index 869d3a4ad54..5b852928031 100644
--- a/target/s390x/cpu-dump.c
+++ b/target/s390x/cpu-dump.c
@@ -63,6 +63,7 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags)
(i % 4) == 3 ? '\n' : ' ');
}
}
+ qemu_fprintf(f, "FPC=%08" PRIx32 "\n", env->fpc);
}
#ifndef CONFIG_USER_ONLY
--
2.52.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 2/5] target/s390x: Extract s390_get_bfp_rounding_mode()
2026-01-29 18:57 [PATCH v3 0/5] target/s390x: Implement DIVIDE TO INTEGER Ilya Leoshkevich
2026-01-29 18:57 ` [PATCH v3 1/5] target/s390x: Dump Floating-Point-Control Register Ilya Leoshkevich
@ 2026-01-29 18:57 ` Ilya Leoshkevich
2026-01-30 7:30 ` Thomas Huth
2026-01-29 18:57 ` [PATCH v3 3/5] fpu: Restrict parts_round_to_int_normal to target precision Ilya Leoshkevich
` (2 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Ilya Leoshkevich @ 2026-01-29 18:57 UTC (permalink / raw)
To: Thomas Huth, Richard Henderson
Cc: David Hildenbrand, qemu-s390x, qemu-devel, Ilya Leoshkevich
For DIVIDE TO INTEGER it will be helpful to pass final-quotient
rounding mode around explicitly rather than setting it in fpu_status
implicitly. To facilitate this, extract a function for converting the
mask to the rounding mode.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
target/s390x/tcg/fpu_helper.c | 62 +++++++++++++++++------------------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c
index 1ba43715ac1..7a3ff501a46 100644
--- a/target/s390x/tcg/fpu_helper.c
+++ b/target/s390x/tcg/fpu_helper.c
@@ -56,6 +56,35 @@ uint8_t s390_softfloat_exc_to_ieee(unsigned int exc)
return s390_exc;
}
+static int s390_get_bfp_rounding_mode(CPUS390XState *env, int m3)
+{
+ switch (m3) {
+ case 0:
+ /* current mode */
+ return env->fpu_status.float_rounding_mode;
+ case 1:
+ /* round to nearest with ties away from 0 */
+ return float_round_ties_away;
+ case 3:
+ /* round to prepare for shorter precision */
+ return float_round_to_odd;
+ case 4:
+ /* round to nearest with ties to even */
+ return float_round_nearest_even;
+ case 5:
+ /* round to zero */
+ return float_round_to_zero;
+ case 6:
+ /* round to +inf */
+ return float_round_up;
+ case 7:
+ /* round to -inf */
+ return float_round_down;
+ default:
+ g_assert_not_reached();
+ }
+}
+
/* Should be called after any operation that may raise IEEE exceptions. */
static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr)
{
@@ -416,37 +445,8 @@ int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3)
{
int ret = env->fpu_status.float_rounding_mode;
- switch (m3) {
- case 0:
- /* current mode */
- break;
- case 1:
- /* round to nearest with ties away from 0 */
- set_float_rounding_mode(float_round_ties_away, &env->fpu_status);
- break;
- case 3:
- /* round to prepare for shorter precision */
- set_float_rounding_mode(float_round_to_odd, &env->fpu_status);
- break;
- case 4:
- /* round to nearest with ties to even */
- set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
- break;
- case 5:
- /* round to zero */
- set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
- break;
- case 6:
- /* round to +inf */
- set_float_rounding_mode(float_round_up, &env->fpu_status);
- break;
- case 7:
- /* round to -inf */
- set_float_rounding_mode(float_round_down, &env->fpu_status);
- break;
- default:
- g_assert_not_reached();
- }
+ set_float_rounding_mode(s390_get_bfp_rounding_mode(env, m3),
+ &env->fpu_status);
return ret;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 3/5] fpu: Restrict parts_round_to_int_normal to target precision
2026-01-29 18:57 [PATCH v3 0/5] target/s390x: Implement DIVIDE TO INTEGER Ilya Leoshkevich
2026-01-29 18:57 ` [PATCH v3 1/5] target/s390x: Dump Floating-Point-Control Register Ilya Leoshkevich
2026-01-29 18:57 ` [PATCH v3 2/5] target/s390x: Extract s390_get_bfp_rounding_mode() Ilya Leoshkevich
@ 2026-01-29 18:57 ` Ilya Leoshkevich
2026-02-02 6:16 ` Richard Henderson
2026-01-29 18:57 ` [PATCH v3 4/5] target/s390x: Implement DIVIDE TO INTEGER Ilya Leoshkevich
2026-01-29 18:57 ` [PATCH v3 5/5] tests/tcg/s390x: Test " Ilya Leoshkevich
4 siblings, 1 reply; 11+ messages in thread
From: Ilya Leoshkevich @ 2026-01-29 18:57 UTC (permalink / raw)
To: Thomas Huth, Richard Henderson
Cc: David Hildenbrand, qemu-s390x, qemu-devel, Ilya Leoshkevich
Currently parts_round_to_int_normal() assumes that its input has just
been unpacked and therefore doesn't expect non-zero fraction bits past
target precision.
The upcoming DIVIDE TO INTEGER use cases needs it to support
calculations on intermediate values that utilize all fraction bits,
while at the same time restricting the result's precision to frac_size.
Delete the "All integral" check, because even though really large
values are always integer, their low fraction bits still need to be
truncated. For the same reason, make sure rnd_mask covers at least
fraction bits past target precision.
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
fpu/softfloat-parts.c.inc | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
index 5e0438fc0b7..93ed59626e5 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -1118,11 +1118,6 @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode,
return true;
}
- if (a->exp >= frac_size) {
- /* All integral */
- return false;
- }
-
if (N > 64 && a->exp < N - 64) {
/*
* Rounding is not in the low word -- shift lsb to bit 2,
@@ -1133,7 +1128,7 @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode,
frac_lsb = 1 << 2;
} else {
shift_adj = 0;
- frac_lsb = DECOMPOSED_IMPLICIT_BIT >> (a->exp & 63);
+ frac_lsb = DECOMPOSED_IMPLICIT_BIT >> MIN(a->exp, frac_size);
}
frac_lsbm1 = frac_lsb >> 1;
--
2.52.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 4/5] target/s390x: Implement DIVIDE TO INTEGER
2026-01-29 18:57 [PATCH v3 0/5] target/s390x: Implement DIVIDE TO INTEGER Ilya Leoshkevich
` (2 preceding siblings ...)
2026-01-29 18:57 ` [PATCH v3 3/5] fpu: Restrict parts_round_to_int_normal to target precision Ilya Leoshkevich
@ 2026-01-29 18:57 ` Ilya Leoshkevich
2026-01-29 23:28 ` Ilya Leoshkevich
2026-01-29 18:57 ` [PATCH v3 5/5] tests/tcg/s390x: Test " Ilya Leoshkevich
4 siblings, 1 reply; 11+ messages in thread
From: Ilya Leoshkevich @ 2026-01-29 18:57 UTC (permalink / raw)
To: Thomas Huth, Richard Henderson
Cc: David Hildenbrand, qemu-s390x, qemu-devel, Ilya Leoshkevich
DIVIDE TO INTEGER computes floating point remainder and is used by
LuaJIT, so add it to QEMU.
Put the main logic into fpu/, because it is way more convenient to
operate on FloatParts than to convert floats back-and-forth.
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
fpu/softfloat.c | 144 +++++++++++++++++++++++++++++++
include/fpu/softfloat.h | 11 +++
target/s390x/helper.h | 1 +
target/s390x/tcg/fpu_helper.c | 56 ++++++++++++
target/s390x/tcg/insn-data.h.inc | 5 +-
target/s390x/tcg/translate.c | 26 ++++++
6 files changed, 242 insertions(+), 1 deletion(-)
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 8094358c2e4..dd744c657ef 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -5361,6 +5361,150 @@ floatx80 floatx80_round(floatx80 a, float_status *status)
return floatx80_round_pack_canonical(&p, status);
}
+static void parts_s390_divide_to_integer(FloatParts64 *a, FloatParts64 *b,
+ int final_quotient_rounding_mode,
+ bool mask_underflow, bool mask_inexact,
+ const FloatFmt *fmt,
+ FloatParts64 *r, FloatParts64 *n,
+ uint32_t *cc, int *dxc,
+ float_status *status)
+{
+ /* POp table "Results: DIVIDE TO INTEGER (Part 1 of 2)" */
+ if ((float_cmask(a->cls) | float_cmask(b->cls)) & float_cmask_anynan) {
+ *r = *parts_pick_nan(a, b, status);
+ *n = *r;
+ *cc = 1;
+ } else if (a->cls == float_class_inf || b->cls == float_class_zero) {
+ parts_default_nan(r, status);
+ *n = *r;
+ *cc = 1;
+ status->float_exception_flags |= float_flag_invalid;
+ } else if (b->cls == float_class_inf) {
+ *r = *a;
+ n->cls = float_class_zero;
+ n->sign = a->sign ^ b->sign;
+ *cc = 0;
+ } else {
+ FloatParts64 *q, q_buf, *r_precise, r_precise_buf;
+ int float_exception_flags = 0;
+ bool is_q_smallish;
+ uint32_t r_flags;
+ int saved_flags;
+
+ /* Compute precise quotient */
+ q_buf = *a;
+ q = parts_div(&q_buf, b, status);
+
+ /*
+ * Check whether two closest integers can be precisely represented,
+ * i.e., all their bits fit into the fractional part.
+ */
+ is_q_smallish = q->exp < (fmt->frac_size + 1);
+
+ /*
+ * Final quotient is rounded using final-quotient-rounding method, and
+ * partial quotient is rounded toward zero.
+ *
+ * Rounding of partial quotient may be inexact. This is the whole point
+ * of distinguishing partial quotients, so ignore the exception.
+ */
+ *n = *q;
+ saved_flags = status->float_exception_flags;
+ parts_round_to_int(n,
+ is_q_smallish ? final_quotient_rounding_mode :
+ float_round_to_zero,
+ 0, status, fmt);
+ float_exception_flags = saved_flags;
+
+ /* Compute precise remainder */
+ r_precise_buf = *b;
+ status->float_exception_flags = 0;
+ r_precise = parts_muladd_scalbn(&r_precise_buf, n, a, 0,
+ float_muladd_negate_product, status);
+
+ /* Round remainder to the target format */
+ *r = *r_precise;
+ parts_uncanon(r, status, fmt);
+ r->frac &= (1ULL << fmt->frac_size) - 1;
+ parts_canonicalize(r, status, fmt);
+ r_flags = status->float_exception_flags;
+
+ /* POp table "Results: DIVIDE TO INTEGER (Part 2 of 2)" */
+ if (is_q_smallish) {
+ if (r->cls != float_class_zero) {
+ if (r->exp < 2 - (1 << (fmt->exp_size - 1))) {
+ if (mask_underflow) {
+ float_exception_flags |= float_flag_underflow;
+ *dxc = 0x10;
+ r->exp += fmt->exp_re_bias;
+ }
+ } else if (r_flags & float_flag_inexact) {
+ float_exception_flags |= float_flag_inexact;
+ if (mask_inexact) {
+ bool saved_r_sign, saved_r_precise_sign;
+
+ /*
+ * Check whether remainder was truncated (rounded
+ * toward zero) or incremented.
+ */
+ saved_r_sign = r->sign;
+ saved_r_precise_sign = r_precise->sign;
+ r->sign = false;
+ r_precise->sign = false;
+ if (parts_compare(r, r_precise, status, true) <
+ float_relation_equal) {
+ *dxc = 0x8;
+ } else {
+ *dxc = 0xc;
+ }
+ r->sign = saved_r_sign;
+ r_precise->sign = saved_r_precise_sign;
+ }
+ }
+ }
+ *cc = 0;
+ } else if (n->exp > (1 << (fmt->exp_size - 1)) - 1) {
+ n->exp -= fmt->exp_re_bias;
+ *cc = r->cls == float_class_zero ? 1 : 3;
+ } else {
+ *cc = r->cls == float_class_zero ? 0 : 2;
+ }
+
+ /* Adjust signs of zero results */
+ if (r->cls == float_class_zero) {
+ r->sign = a->sign;
+ }
+ if (n->cls == float_class_zero) {
+ n->sign = a->sign ^ b->sign;
+ }
+
+ status->float_exception_flags = float_exception_flags;
+ }
+}
+
+#define DEFINE_S390_DIVIDE_TO_INTEGER(floatN) \
+void floatN ## _s390_divide_to_integer(floatN a, floatN b, \
+ int final_quotient_rounding_mode, \
+ bool mask_underflow, bool mask_inexact, \
+ floatN *r, floatN *n, \
+ uint32_t *cc, int *dxc, \
+ float_status *status) \
+{ \
+ FloatParts64 pa, pb, pr, pn; \
+ \
+ floatN ## _unpack_canonical(&pa, a, status); \
+ floatN ## _unpack_canonical(&pb, b, status); \
+ parts_s390_divide_to_integer(&pa, &pb, final_quotient_rounding_mode, \
+ mask_underflow, mask_inexact, \
+ &floatN ## _params, \
+ &pr, &pn, cc, dxc, status); \
+ *r = floatN ## _round_pack_canonical(&pr, status); \
+ *n = floatN ## _round_pack_canonical(&pn, status); \
+}
+
+DEFINE_S390_DIVIDE_TO_INTEGER(float32)
+DEFINE_S390_DIVIDE_TO_INTEGER(float64)
+
static void __attribute__((constructor)) softfloat_init(void)
{
union_float64 ua, ub, uc, ur;
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index c18ab2cb609..66b0c47b5eb 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -1372,4 +1372,15 @@ static inline bool float128_unordered_quiet(float128 a, float128 b,
*----------------------------------------------------------------------------*/
float128 float128_default_nan(float_status *status);
+#define DECLARE_S390_DIVIDE_TO_INTEGER(floatN) \
+void floatN ## _s390_divide_to_integer(floatN a, floatN b, \
+ int final_quotient_rounding_mode, \
+ bool mask_underflow, bool mask_inexact, \
+ floatN *r, floatN *n, \
+ uint32_t *cc, int *dxc, \
+ float_status *status)
+DECLARE_S390_DIVIDE_TO_INTEGER(float32);
+DECLARE_S390_DIVIDE_TO_INTEGER(float64);
+
+
#endif /* SOFTFLOAT_H */
diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index 1a8a76abb98..6a7426fdac7 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -46,6 +46,7 @@ DEF_HELPER_FLAGS_3(sxb, TCG_CALL_NO_WG, i128, env, i128, i128)
DEF_HELPER_FLAGS_3(deb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(ddb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(dxb, TCG_CALL_NO_WG, i128, env, i128, i128)
+DEF_HELPER_6(dib, void, env, i32, i32, i32, i32, i32)
DEF_HELPER_FLAGS_3(meeb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(mdeb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(mdb, TCG_CALL_NO_WG, i64, env, i64, i64)
diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c
index 7a3ff501a46..122994960a6 100644
--- a/target/s390x/tcg/fpu_helper.c
+++ b/target/s390x/tcg/fpu_helper.c
@@ -315,6 +315,62 @@ Int128 HELPER(dxb)(CPUS390XState *env, Int128 a, Int128 b)
return RET128(ret);
}
+void HELPER(dib)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
+ uint32_t m4, uint32_t bits)
+{
+ int final_quotient_rounding_mode = s390_get_bfp_rounding_mode(env, m4);
+ bool mask_underflow = (env->fpc >> 24) & S390_IEEE_MASK_UNDERFLOW;
+ bool mask_inexact = (env->fpc >> 24) & S390_IEEE_MASK_INEXACT;
+ float32 a32, b32, n32, r32;
+ float64 a64, b64, n64, r64;
+ int dxc = -1;
+ uint32_t cc;
+
+ if (bits == 32) {
+ a32 = env->vregs[r1][0] >> 32;
+ b32 = env->vregs[r2][0] >> 32;
+
+ float32_s390_divide_to_integer(
+ a32, b32,
+ final_quotient_rounding_mode,
+ mask_underflow, mask_inexact,
+ &r32, &n32, &cc, &dxc, &env->fpu_status);
+ } else {
+ a64 = env->vregs[r1][0];
+ b64 = env->vregs[r2][0];
+
+ float64_s390_divide_to_integer(
+ a64, b64,
+ final_quotient_rounding_mode,
+ mask_underflow, mask_inexact,
+ &r64, &n64, &cc, &dxc, &env->fpu_status);
+ }
+
+ /* Flush the results if needed */
+ if ((env->fpu_status.float_exception_flags & float_flag_invalid) &&
+ ((env->fpc >> 24) & S390_IEEE_MASK_INVALID)) {
+ /* The action for invalid operation is "Suppress" */
+ } else {
+ /* The action for other exceptions is "Complete" */
+ if (bits == 32) {
+ env->vregs[r1][0] = deposit64(env->vregs[r1][0], 32, 32, r32);
+ env->vregs[r3][0] = deposit64(env->vregs[r3][0], 32, 32, n32);
+ } else {
+ env->vregs[r1][0] = r64;
+ env->vregs[r3][0] = n64;
+ }
+ env->cc_op = cc;
+ }
+
+ /* Raise an exception if needed */
+ if (dxc == -1) {
+ handle_exceptions(env, false, GETPC());
+ } else {
+ env->fpu_status.float_exception_flags = 0;
+ tcg_s390_data_exception(env, dxc, GETPC());
+ }
+}
+
/* 32-bit FP multiplication */
uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc
index baaafe922e9..0d5392eac54 100644
--- a/target/s390x/tcg/insn-data.h.inc
+++ b/target/s390x/tcg/insn-data.h.inc
@@ -9,7 +9,7 @@
* OPC = (op << 8) | op2 where op is the major, op2 the minor opcode
* NAME = name of the opcode, used internally
* FMT = format of the opcode (defined in insn-format.h.inc)
- * FAC = facility the opcode is available in (defined in DisasFacility)
+ * FAC = facility the opcode is available in (define in translate.c)
* I1 = func in1_xx fills o->in1
* I2 = func in2_xx fills o->in2
* P = func prep_xx initializes o->*out*
@@ -361,6 +361,9 @@
C(0xb91d, DSGFR, RRE, Z, r1p1, r2_32s, r1_P, 0, divs64, 0)
C(0xe30d, DSG, RXY_a, Z, r1p1, m2_64, r1_P, 0, divs64, 0)
C(0xe31d, DSGF, RXY_a, Z, r1p1, m2_32s, r1_P, 0, divs64, 0)
+/* DIVIDE TO INTEGER */
+ D(0xb35b, DIDBR, RRF_b, Z, 0, 0, 0, 0, dib, 0, 64)
+ D(0xb353, DIEBR, RRF_b, Z, 0, 0, 0, 0, dib, 0, 32)
/* EXCLUSIVE OR */
C(0x1700, XR, RR_a, Z, r1, r2, new, r1_32, xor, nz32)
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 540c5a569c0..dee0e710f39 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -2283,6 +2283,32 @@ static DisasJumpType op_dxb(DisasContext *s, DisasOps *o)
return DISAS_NEXT;
}
+static DisasJumpType op_dib(DisasContext *s, DisasOps *o)
+{
+ const bool fpe = s390_has_feat(S390_FEAT_FLOATING_POINT_EXT);
+ uint8_t m4 = get_field(s, m4);
+
+ if (get_field(s, r1) == get_field(s, r2) ||
+ get_field(s, r1) == get_field(s, r3) ||
+ get_field(s, r2) == get_field(s, r3)) {
+ gen_program_exception(s, PGM_SPECIFICATION);
+ return DISAS_NORETURN;
+ }
+
+ if (m4 == 2 || (!fpe && m4 == 3) || m4 > 7) {
+ gen_program_exception(s, PGM_SPECIFICATION);
+ return DISAS_NORETURN;
+ }
+
+ gen_helper_dib(tcg_env, tcg_constant_i32(get_field(s, r1)),
+ tcg_constant_i32(get_field(s, r2)),
+ tcg_constant_i32(get_field(s, r3)), tcg_constant_i32(m4),
+ tcg_constant_i32(s->insn->data));
+ set_cc_static(s);
+
+ return DISAS_NEXT;
+}
+
static DisasJumpType op_ear(DisasContext *s, DisasOps *o)
{
int r2 = get_field(s, r2);
--
2.52.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 5/5] tests/tcg/s390x: Test DIVIDE TO INTEGER
2026-01-29 18:57 [PATCH v3 0/5] target/s390x: Implement DIVIDE TO INTEGER Ilya Leoshkevich
` (3 preceding siblings ...)
2026-01-29 18:57 ` [PATCH v3 4/5] target/s390x: Implement DIVIDE TO INTEGER Ilya Leoshkevich
@ 2026-01-29 18:57 ` Ilya Leoshkevich
4 siblings, 0 replies; 11+ messages in thread
From: Ilya Leoshkevich @ 2026-01-29 18:57 UTC (permalink / raw)
To: Thomas Huth, Richard Henderson
Cc: David Hildenbrand, qemu-s390x, qemu-devel, Ilya Leoshkevich,
Alex Bennée
Add a test to prevent regressions. Data is generated using a
libFuzzer-based fuzzer and hopefully covers all the important corner
cases.
Acked-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
tests/tcg/s390x/Makefile.target | 5 +
tests/tcg/s390x/divide-to-integer.c | 265 ++++++++++++++++++++++++++++
2 files changed, 270 insertions(+)
create mode 100644 tests/tcg/s390x/divide-to-integer.c
diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target
index da5fe71a407..0ca030ded01 100644
--- a/tests/tcg/s390x/Makefile.target
+++ b/tests/tcg/s390x/Makefile.target
@@ -49,14 +49,19 @@ TESTS+=cvd
TESTS+=cvb
TESTS+=ts
TESTS+=ex-smc
+TESTS+=divide-to-integer
cdsg: CFLAGS+=-pthread
cdsg: LDFLAGS+=-pthread
+# The following tests contain inline assembly that requires inlining,
+# and thus cannot be built with -O0.
rxsbg: CFLAGS+=-O2
+divide-to-integer: CFLAGS+=-O2
cgebra: LDFLAGS+=-lm
clgebr: LDFLAGS+=-lm
+divide-to-integer: LDFLAGS+=-lm
include $(S390X_SRC)/pgm-specification.mak
$(PGM_SPECIFICATION_TESTS): pgm-specification-user.o
diff --git a/tests/tcg/s390x/divide-to-integer.c b/tests/tcg/s390x/divide-to-integer.c
new file mode 100644
index 00000000000..62b4787ec0e
--- /dev/null
+++ b/tests/tcg/s390x/divide-to-integer.c
@@ -0,0 +1,265 @@
+/*
+ * Test DIEBR and DIDBR instructions.
+ *
+ * Most inputs were discovered by fuzzing and exercise various corner cases in
+ * the helpers.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <asm/ucontext.h>
+
+static void sigfpe_handler(int sig, siginfo_t *info, void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned short *xr_insn;
+ int r;
+
+ xr_insn = (unsigned short *)(uc->uc_mcontext.regs.psw.addr - 6);
+ r = *xr_insn & 0xf;
+ uc->uc_mcontext.regs.gprs[r] = sig;
+}
+
+#define DIVIDE_TO_INTEGER(name, floatN) \
+static inline __attribute__((__always_inline__)) int \
+name(floatN *r1, floatN r2, floatN *r3, int m4, int *sig) \
+{ \
+ int cc; \
+ \
+ asm(/* Make the initial CC predictable for suppression tests */ \
+ "xr %[sig],%[sig]\n" \
+ #name " %[r1],%[r3],%[r2],%[m4]\n" \
+ "ipm %[cc]\n" \
+ "srl %[cc],28" \
+ /* \
+ * Use earlyclobbers to prevent the compiler from reusing floating \
+ * point registers. This instruction doesn't like it. \
+ */ \
+ : [r1] "+&f" (*r1), [r3] "+&f" (*r3), [sig] "=r" (*sig), [cc] "=d" (cc)\
+ : [r2] "f" (r2), [m4] "i" (m4) \
+ : "cc"); \
+ \
+ return cc; \
+}
+
+DIVIDE_TO_INTEGER(diebr, float)
+DIVIDE_TO_INTEGER(didbr, double)
+
+#define TEST_DIVIDE_TO_INTEGER(name, intN, int_fmt, floatN, float_fmt) \
+static inline __attribute__((__always_inline__)) int \
+test_ ## name(unsigned intN r1i, unsigned intN r2i, int m4, int fpc, \
+ unsigned intN r1o, unsigned intN r3o, int cco, unsigned int fpco,\
+ int sigo) \
+{ \
+ union { \
+ floatN f; \
+ unsigned intN i; \
+ } r1, r2, r3; \
+ int cc, err = 0, sig; \
+ \
+ r1.i = r1i; \
+ r2.i = r2i; \
+ r3.i = 0x12345678; \
+ printf("[ RUN ] %" float_fmt "(0x%" int_fmt \
+ ") / %" float_fmt "(0x%" int_fmt ")\n", r1.f, r1.i, r2.f, r2.i); \
+ asm volatile("sfpc %[fpc]" : : [fpc] "r" (fpc)); \
+ cc = name(&r1.f, r2.f, &r3.f, m4, &sig); \
+ asm volatile("stfpc %[fpc]" : [fpc] "=Q" (fpc)); \
+ if (r1.i != r1o) { \
+ printf("[ FAILED ] remainder 0x%" int_fmt \
+ " != expected 0x%" int_fmt "\n", r1.i, r1o); \
+ err += 1; \
+ } \
+ if (r3.i != r3o) { \
+ printf("[ FAILED ] quotient 0x%" int_fmt \
+ " != expected 0x%" int_fmt "\n", r3.i, r3o); \
+ err += 1; \
+ } \
+ if (cc != cco) { \
+ printf("[ FAILED ] cc %d != expected %d\n", cc, cco); \
+ err += 1; \
+ } \
+ if (fpc != fpco) { \
+ printf("[ FAILED ] fpc 0x%x != expected 0x%x\n", fpc, fpco); \
+ err += 1; \
+ } \
+ if (sig != sigo) { \
+ printf("[ FAILED ] signal 0x%x != expected 0x%x\n", sig, sigo); \
+ err += 1; \
+ } \
+ \
+ return err; \
+}
+
+TEST_DIVIDE_TO_INTEGER(diebr, int, "x", float, "f")
+TEST_DIVIDE_TO_INTEGER(didbr, long, "lx", double, "lf")
+
+int main(void)
+{
+ struct sigaction act = {
+ .sa_sigaction = sigfpe_handler,
+ .sa_flags = SA_SIGINFO,
+ };
+ int err = 0;
+
+ /* Set up SIG handler */
+ if (sigaction(SIGFPE, &act, NULL)) {
+ printf("[ FAILED ] sigaction(SIGFPE) failed\n");
+ return EXIT_FAILURE;
+ }
+
+ /* 451 / 460 */
+ err += test_diebr(0x43e1f1f1, 0x43e61616, 7, 0,
+ 0x43e1f1f1, 0, 0, 0, 0);
+
+ /* 480 / 0 */
+ err += test_diebr(0x43f00000, 0, 0, 0,
+ 0x7fc00000, 0x7fc00000, 1, 0x800000, 0);
+
+ /* QNaN / QNaN */
+ err += test_diebr(0xffffffff, 0xffffffff, 0, 0,
+ 0xffffffff, 0xffffffff, 1, 0, 0);
+
+ /* -2.08E-8 / -2.08E-8 */
+ err += test_diebr(0xb2b2b2b2, 0xb2b2b2b2, 0, 0,
+ 0x80000000, 0x3f800000, 0, 0, 0);
+
+ /*
+ * Test partial remainder without quotient scaling (cc2).
+ *
+ * a = 12401981 / 268435456
+ * b = -5723991 / 72057594037927936
+ * q = a / b = -3329131425038336 / 5723991 =~ -581610178.1
+ * n = round(q, float32, nearest_even) = -581610176
+ * r_precise = a - b * n = 189155 / 1125899906842624
+ * r = round(r_precise, float32, nearest_even) = r_precise
+ */
+ err += test_diebr(0x3d3d3d3d, 0xaeaeaeae, 0, 0,
+ 0x2f38b8c0, 0xce0aaaab, 2, 0, 0);
+
+ /* 1.07E-31 / 2.19 */
+ err += test_diebr(0x0c0c0c0c, 0x400c0c0c, 6, 0,
+ 0xc00c0c0c, 0x3f800000, 0, 0x80000, 0);
+
+ /*
+ * Test partial remainder with quotient scaling (cc3).
+ *
+ * a = 298343530578310714772108083200
+ * b = -592137/10384593717069655257060992658440192
+ * q = a / b
+ * = -1032725451057301340137043014721780674141077289604872315653324800 /
+ * 197379
+ * =~ -5232195173029052432817285601415452880707052369324357280426.6
+ * n = round(q, float32, nearest_even)
+ * = -5232194943010009439437691768433469154159343131709361094656
+ * n / 2^192 = -6992213 / 8388608
+ * r_precise = a - b * n = 13115851209189604982784
+ * r = round(r_precise, float32, nearest_even) = r_precise
+ */
+ err += test_diebr(0x7070ffff, 0x90909090, 0, 0,
+ 0x6431c0c0, 0xbf5562aa, 3, 0, 0);
+
+ /*
+ * Test large, but representable quotient.
+ *
+ * a = -12040119 / 549755813888
+ * b = 1 / 38685626227668133590597632
+ * q = a / b = -847248053779631702016
+ * n = round(q, float32, to_odd) = q
+ * r_precise = a - b * n = -0
+ * r = round(r_precise, float32, nearest_even) = -0
+ */
+ err += test_diebr(0xb7b7b7b7, 0x15000000, 7, 0,
+ 0x80000000, 0xe237b7b7, 0, 0, 0);
+
+ /* 0 / 0 */
+ err += test_diebr(0, 0, 1, 0,
+ 0x7fc00000, 0x7fc00000, 1, 0x800000, 0);
+
+ /* 4.3E-33 / -2.08E-8 with SIGFPE */
+ err += test_diebr(0x09b2b2b2, 0xb2b2b2b2, 0, 0xfc000007,
+ 0xb2b2b2b1, 0xbf800000, 0, 0xfc000807, SIGFPE);
+
+ /*
+ * Test tiny remainder scaling when FPC Underflow Mask is set.
+ *
+ * 1.19E-39 / -1.28E-9 = { r = 1.19E-39 * 2^192, n = -0 }
+ */
+ err += test_diebr(0x000d0100, 0xb0b0b0b0, 6, 0xfc000000,
+ 0x5ed01000, 0x80000000, 0, 0xfc001000, SIGFPE);
+
+ /*
+ * Test "inexact and incremented" DXC.
+ *
+ * a = 53555504
+ * b = -520849213389117849600
+ * q = a / b = -3347219 / 32553075836819865600
+ * n = round(q, float32, to_odd) = -1
+ * r_precise = a - b * n = -520849213389064294096
+ * r = round(r_precise, float32, to_odd) = -520849213389117849600
+ * abs(r) - abs(r_precise) = 53555504
+ */
+ err += test_diebr(0x4c4c4c4c, 0xe1e1e1e1, 0, 0xfc000007,
+ 0xe1e1e1e1, 0xbf800000, 0, 0xfc000c07, SIGFPE);
+
+ /* 0 / 0 with SIGFPE */
+ err += test_diebr(0, 0, 0, 0xfc000007,
+ 0, 0x12345678, 0, 0xfc008007, SIGFPE);
+
+ /* 5.76E-16 / 5.39E+34 */
+ err += test_diebr(0x26262626, 0x79262626, 6, 0,
+ 0xf9262626, 0x3f800000, 0, 0x80000, 0);
+
+ /* -4.97E+17 / 2.03E-38 */
+ err += test_diebr(0xdcdcdcdc, 0x00dcdcdc, 7, 0xfc000000,
+ 0x80000000, 0xbb800000, 1, 0xfc000000, 0);
+
+ /* -1.23E+17 / SNaN */
+ err += test_diebr(0xdbdb240b, 0xffac73ff, 4, 0,
+ 0xffec73ff, 0xffec73ff, 1, 0x800000, 0);
+
+ /* 2.34E-38 / 3.27E-33 with SIGFPE */
+ err += test_diebr(0x00ff0987, 0x0987c6f6, 6, 0x08000000,
+ 0x8987c6b6, 0x3f800000, 0, 0x8000800, SIGFPE);
+
+ /* -5.93E+11 / -2.7E+4 */
+ err += test_diebr(0xd30a0040, 0xc6d30a00, 0, 0xc4000000,
+ 0xc74a4400, 0x4ba766c6, 2, 0xc4000000, 0);
+
+ /* 9.86E-32 / -inf */
+ err += test_diebr(0x0c000029, 0xff800000, 0, 0,
+ 0xc000029, 0x80000000, 0, 0, 0);
+
+ /* QNaN / SNaN */
+ err += test_diebr(0xffff94ff, 0xff94ff24, 4, 7,
+ 0xffd4ff24, 0xffd4ff24, 1, 0x800007, 0);
+
+ /* 2.8E-43 / -inf */
+ err += test_diebr(0x000000c8, 0xff800000, 0, 0x7c000007,
+ 0x000000c8, 0x80000000, 0, 0x7c000007, 0);
+
+ /* -1.7E+38 / -inf */
+ err += test_diebr(0xff00003d, 0xff800000, 0, 0,
+ 0xff00003d, 0, 0, 0, 0);
+
+ /* 1.94E-304 / 1.94E-304 */
+ err += test_didbr(0x00e100e100e100e1, 0x00e100e100e100e1, 0, 1,
+ 0, 0x3ff0000000000000, 0, 1, 0);
+
+ /* 4.82E-299 / 5.29E-308 */
+ err += test_didbr(0x0200230200230200, 0x0023020023020023, 0, 0,
+ 0x8001a017d247b3f4, 0x41cb2aa05f000000, 0, 0, 0);
+
+ /* -1.38E-75 / -3.77E+208 */
+ err += test_didbr(0xb063eb3d63b063eb, 0xeb3d63b063eb3d63, 3, 0xe8000000,
+ 0x6b3d63b063eb3d63, 0x3ff0000000000000, 0, 0xe8000c00,
+ SIGFPE);
+
+ /* 4.78E-299 / 6.88E-315 */
+ err += test_didbr(0x0200000000000000, 0x0000000053020000, 0, 0,
+ 0x8000000020820000, 0x4338ac20dd47c6c1, 0, 0, 0);
+
+ return err ? EXIT_FAILURE : EXIT_SUCCESS;
+}
--
2.52.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v3 4/5] target/s390x: Implement DIVIDE TO INTEGER
2026-01-29 18:57 ` [PATCH v3 4/5] target/s390x: Implement DIVIDE TO INTEGER Ilya Leoshkevich
@ 2026-01-29 23:28 ` Ilya Leoshkevich
2026-02-04 6:01 ` Richard Henderson
0 siblings, 1 reply; 11+ messages in thread
From: Ilya Leoshkevich @ 2026-01-29 23:28 UTC (permalink / raw)
To: Thomas Huth, Richard Henderson; +Cc: David Hildenbrand, qemu-s390x, qemu-devel
On 2026-01-29 19:57, Ilya Leoshkevich wrote:
> DIVIDE TO INTEGER computes floating point remainder and is used by
> LuaJIT, so add it to QEMU.
>
> Put the main logic into fpu/, because it is way more convenient to
> operate on FloatParts than to convert floats back-and-forth.
>
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> ---
> fpu/softfloat.c | 144 +++++++++++++++++++++++++++++++
> include/fpu/softfloat.h | 11 +++
> target/s390x/helper.h | 1 +
> target/s390x/tcg/fpu_helper.c | 56 ++++++++++++
> target/s390x/tcg/insn-data.h.inc | 5 +-
> target/s390x/tcg/translate.c | 26 ++++++
> 6 files changed, 242 insertions(+), 1 deletion(-)
I've taken a fresh look and I think I can improve one small thing.
I will change this alongside other feedback (if any) in v4.
[...]
> +
> + /*
> + * Final quotient is rounded using final-quotient-rounding
> method, and
> + * partial quotient is rounded toward zero.
> + *
> + * Rounding of partial quotient may be inexact. This is the
> whole point
> + * of distinguishing partial quotients, so ignore the
> exception.
> + */
> + *n = *q;
> + saved_flags = status->float_exception_flags;
> + parts_round_to_int(n,
> + is_q_smallish ?
> final_quotient_rounding_mode :
> + float_round_to_zero,
> + 0, status, fmt);
> + float_exception_flags = saved_flags;
saved_flags can probably be eliminated; I can assign directly to
float_exception_flags.
I think I can also use parts_round_to_int_normal(), because all the
other cases are taken care of above.
[...]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 1/5] target/s390x: Dump Floating-Point-Control Register
2026-01-29 18:57 ` [PATCH v3 1/5] target/s390x: Dump Floating-Point-Control Register Ilya Leoshkevich
@ 2026-01-30 7:27 ` Thomas Huth
0 siblings, 0 replies; 11+ messages in thread
From: Thomas Huth @ 2026-01-30 7:27 UTC (permalink / raw)
To: Ilya Leoshkevich, Richard Henderson
Cc: David Hildenbrand, qemu-s390x, qemu-devel, Alex Bennée
On 29/01/2026 19.57, Ilya Leoshkevich wrote:
> Knowing the value of this register is very useful for debugging
> floating-point code.
>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> ---
> target/s390x/cpu-dump.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/target/s390x/cpu-dump.c b/target/s390x/cpu-dump.c
> index 869d3a4ad54..5b852928031 100644
> --- a/target/s390x/cpu-dump.c
> +++ b/target/s390x/cpu-dump.c
> @@ -63,6 +63,7 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> (i % 4) == 3 ? '\n' : ' ');
> }
> }
> + qemu_fprintf(f, "FPC=%08" PRIx32 "\n", env->fpc);
> }
Reviewed-by: Thomas Huth <thuth@redhat.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 2/5] target/s390x: Extract s390_get_bfp_rounding_mode()
2026-01-29 18:57 ` [PATCH v3 2/5] target/s390x: Extract s390_get_bfp_rounding_mode() Ilya Leoshkevich
@ 2026-01-30 7:30 ` Thomas Huth
0 siblings, 0 replies; 11+ messages in thread
From: Thomas Huth @ 2026-01-30 7:30 UTC (permalink / raw)
To: Ilya Leoshkevich, Richard Henderson
Cc: David Hildenbrand, qemu-s390x, qemu-devel
On 29/01/2026 19.57, Ilya Leoshkevich wrote:
> For DIVIDE TO INTEGER it will be helpful to pass final-quotient
> rounding mode around explicitly rather than setting it in fpu_status
> implicitly. To facilitate this, extract a function for converting the
> mask to the rounding mode.
>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> ---
> target/s390x/tcg/fpu_helper.c | 62 +++++++++++++++++------------------
> 1 file changed, 31 insertions(+), 31 deletions(-)
Reviewed-by: Thomas Huth <thuth@redhat.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 3/5] fpu: Restrict parts_round_to_int_normal to target precision
2026-01-29 18:57 ` [PATCH v3 3/5] fpu: Restrict parts_round_to_int_normal to target precision Ilya Leoshkevich
@ 2026-02-02 6:16 ` Richard Henderson
0 siblings, 0 replies; 11+ messages in thread
From: Richard Henderson @ 2026-02-02 6:16 UTC (permalink / raw)
To: Ilya Leoshkevich, Thomas Huth; +Cc: David Hildenbrand, qemu-s390x, qemu-devel
On 1/30/26 04:57, Ilya Leoshkevich wrote:
> Currently parts_round_to_int_normal() assumes that its input has just
> been unpacked and therefore doesn't expect non-zero fraction bits past
> target precision.
>
> The upcoming DIVIDE TO INTEGER use cases needs it to support
> calculations on intermediate values that utilize all fraction bits,
> while at the same time restricting the result's precision to frac_size.
>
> Delete the "All integral" check, because even though really large
> values are always integer, their low fraction bits still need to be
> truncated. For the same reason, make sure rnd_mask covers at least
> fraction bits past target precision.
>
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> ---
> fpu/softfloat-parts.c.inc | 7 +------
> 1 file changed, 1 insertion(+), 6 deletions(-)
>
> diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
> index 5e0438fc0b7..93ed59626e5 100644
> --- a/fpu/softfloat-parts.c.inc
> +++ b/fpu/softfloat-parts.c.inc
> @@ -1118,11 +1118,6 @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode,
> return true;
> }
>
> - if (a->exp >= frac_size) {
> - /* All integral */
> - return false;
> - }
> -
> if (N > 64 && a->exp < N - 64) {
> /*
> * Rounding is not in the low word -- shift lsb to bit 2,
> @@ -1133,7 +1128,7 @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode,
> frac_lsb = 1 << 2;
> } else {
> shift_adj = 0;
> - frac_lsb = DECOMPOSED_IMPLICIT_BIT >> (a->exp & 63);
> + frac_lsb = DECOMPOSED_IMPLICIT_BIT >> MIN(a->exp, frac_size);
> }
>
> frac_lsbm1 = frac_lsb >> 1;
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 4/5] target/s390x: Implement DIVIDE TO INTEGER
2026-01-29 23:28 ` Ilya Leoshkevich
@ 2026-02-04 6:01 ` Richard Henderson
0 siblings, 0 replies; 11+ messages in thread
From: Richard Henderson @ 2026-02-04 6:01 UTC (permalink / raw)
To: Ilya Leoshkevich, Thomas Huth; +Cc: David Hildenbrand, qemu-s390x, qemu-devel
On 1/30/26 09:28, Ilya Leoshkevich wrote:
> I think I can also use parts_round_to_int_normal(), because all the other cases are taken
> care of above.
Yep. I think I even mentioned that vs a previous version.
r~
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-02-04 6:02 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-29 18:57 [PATCH v3 0/5] target/s390x: Implement DIVIDE TO INTEGER Ilya Leoshkevich
2026-01-29 18:57 ` [PATCH v3 1/5] target/s390x: Dump Floating-Point-Control Register Ilya Leoshkevich
2026-01-30 7:27 ` Thomas Huth
2026-01-29 18:57 ` [PATCH v3 2/5] target/s390x: Extract s390_get_bfp_rounding_mode() Ilya Leoshkevich
2026-01-30 7:30 ` Thomas Huth
2026-01-29 18:57 ` [PATCH v3 3/5] fpu: Restrict parts_round_to_int_normal to target precision Ilya Leoshkevich
2026-02-02 6:16 ` Richard Henderson
2026-01-29 18:57 ` [PATCH v3 4/5] target/s390x: Implement DIVIDE TO INTEGER Ilya Leoshkevich
2026-01-29 23:28 ` Ilya Leoshkevich
2026-02-04 6:01 ` Richard Henderson
2026-01-29 18:57 ` [PATCH v3 5/5] tests/tcg/s390x: Test " Ilya Leoshkevich
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.