From 82d6d385f9708fb6d5e2a2bacd003155cfc41c08 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 18 Apr 2024 09:49:02 +0200 Subject: libgcc: Fix up __divmodbitint4 [PR114755] The following testcase aborts on aarch64-linux but does not on x86_64-linux. In both cases there is UB in the __divmodbitint4 implemenetation. When the divisor is negative with most significant limb (even when partial) all ones, has at least 2 limbs and the second most significant limb has the most significant bit clear, when this number is negated, it will have 0 in the most significant limb. Already in the PR114397 r14-9592 fix I was dealing with such divisors, but thought the problem is only if because of that un < vn doesn't imply the quotient is 0 and remainder u. But as this testcase shows, the problem is with such divisors always. What happens is that we use __builtin_clz* on the most significant limb, and assume it will not be 0 because that is UB for the builtins. Normally the most significant limb of the divisor shouldn't be 0, as guaranteed by the bitint_reduce_prec e.g. for the positive numbers, unless the divisor is just 0 (but for vn == 1 we have special cases). The following patch moves the handling of this corner case a few lines earlier before the un < vn check, because adjusting the vn later is harder. 2024-04-18 Jakub Jelinek PR libgcc/114755 * libgcc2.c (__divmodbitint4): Perform the decrement on negative v with most significant limb all ones and the second least significant limb with most significant bit clear always, regardless of un < vn. * gcc.dg/torture/bitint-69.c: New test. --- gcc/testsuite/gcc.dg/torture/bitint-69.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/torture/bitint-69.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/torture/bitint-69.c b/gcc/testsuite/gcc.dg/torture/bitint-69.c new file mode 100644 index 0000000..5f89357 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-69.c @@ -0,0 +1,26 @@ +/* PR libgcc/114755 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#if __BITINT_MAXWIDTH__ >= 255 +_BitInt(65) +foo (void) +{ + _BitInt(255) a = 0x040404040404040404040404wb; + _BitInt(65) b = -0xffffffffffffffffwb; + _BitInt(65) r = a % b; + return r; +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 255 + _BitInt(65) x = foo (); + if (x != 0x0404040408080808wb) + __builtin_abort (); +#endif +} -- cgit v1.1