On Fri, 18 Sep 2026, Jakub Jelinek wrote:

> Hi!
> 
> On the following testcase on powerpc64-linux (both -m32 and -m64) we emit
> incorrect loop condition in the separate_ext loop.
> For little endian, we do the addition on the least significant 3 limbs
> (straight line code), 2 lowest limbs regular, the third on 7 bits and
> then sign extension, and then a separate_ext loop
>   <bb 3> [local count: 1073741824]:
>   # _34 = PHI <3(2), _35(3)>
>   VIEW_CONVERT_EXPR<unsigned long[8]>(a)[_34] = _33;
>   _35 = _34 + 1;
>   if (_35 != 8)
>     goto <bb 3>; [0.05%]
>   else
>     goto <bb 4>; [99.95%]
> to copy the sign extension into the remaining 5 limbs.
> On big endian, we do the least significant 3 limbs similarly (of course,
> the result is 512-bit, so with 56, 48, 40 instead of 0, 8, 16 on LE)
> and then do the separate_ext loop:
>   <bb 3> [local count: 1073741824]:
>   # _35 = PHI <4(2), _36(3)>
>   VIEW_CONVERT_EXPR<unsigned long[8]>(a)[_35] = _34;
>   _36 = _35 + 18446744073709551615;
>   if (_36 != 0)
>     goto <bb 3>; [0.05%]
>   else
>     goto <bb 4>; [99.95%]
> That is wrong, we start on limb 4 (i.e. offset 32) and go down until
> 1 (i.e. offset 8) rather than 0 (i.e. offset 0), because like in LE in this
> case we compare idx_next (idx + increment, in BE case -1) instead of idx.
> There was already code to handle specially BE rem != 0 case.
> Note, the starting offset is
>           else if (i == (bo_shift != 0))
>             idx = create_loop (size_int (bo_idx
>                                          + (bitint_big_endian
>                                             ? total - 1 - start - i
>                                             : start + i)), &idx_next);
> and we want to perform the same number of iterations on LE and BE,
> just the LE offsets bo_idx + start + i + I for I going from 0 up until
> bo_idx + start + i + I == bo_idx + end - 1 inclusive, while for BE
> they should be bo_idx + total - 1 - start - i - I for I going from 0
> up until bo_idx + total - 1 - start - i - I == bo_idx + total - 1 - end + 1
> inclusive.  So, the BE correction is to add total - 1 and subtract instead
> of add the start + i up to end - 1 values.
> 
> So, this patch uses the exact same BE correction, with one exception.
> If bo_idx + total - 1 - end + 1 is 0 (which is quite the common case,
> when bo_idx is 0 (e.g. whenever it is not a bit-field store) and bo_shift
> isn't non-zero either (again, e.g. no bit-field store) and rem == 0),
> I think comparing idx != 0 instead of idx_next != (size_t) -1 is faster
> (plus we'd in the evaluation need to care about types of all the addends,
> do everything say in unsigned HOST_WIDE_INT and then map all ones in UHWI
> to all ones in target size_t).
> 
> Bootstrapped/regtested on x86_64-linux, i686-linux (to make sure little
> endian isn't broken), powerpc64-linux (--with-cpu=power8;
> regtested there with both -m32/-m64 and additionally tested with
> make -j192 -k check-gcc GCC_TEST_RUN_EXPENSIVE=1 
> RUNTESTFLAGS="GCC_TEST_RUN_EXPENSIVE=1 dg.exp='*bitint* pr112673.c 
> builtin-stdc-bit-*.c pr112566-2.c pr112511.c pr116588.c pr116003.c pr113693.c 
> pr113602.c flex-array-counted-by-7.c' dg-torture.exp='*bitint* pr116480-2.c 
> pr114312.c pr114121.c' dfp.exp=*bitint* 
> vect.exp='vect-early-break_99-pr113287.c' tree-ssa.exp=pr113735.c"
> ) and tested (non-bootstrapped) s390x-linux, again with the above
> make check-gcc except with much lower -j.  This fixes also
> torture/bitint-16.c FAILs for -m32 on powerpc64-linux.
> Ok for trunk?

OK.

Richard.

> 2026-09-17  Jakub Jelinek  <[email protected]>
>           Manjunath Matti  <[email protected]>
> 
>       PR middle-end/127378
>       * gimple-lower-bitint.cc (bitint_large_huge::lower_mergeable_stmt): On
>       big endian, compare idx_next in separate_ext loop against
>       bo_idx + total - 1 - end, and if that wraps around, compare idx
>       against 0 instead.
> 
>       * gcc.dg/bitint-145.c: New test.
> 
> --- a/gcc/gimple-lower-bitint.cc      2026-09-08 22:18:28.493021390 +0200
> +++ b/gcc/gimple-lower-bitint.cc      2026-09-17 17:24:10.713167910 +0200
> @@ -3271,15 +3271,18 @@ bitint_large_huge::lower_mergeable_stmt
>                                      bitint_big_endian
>                                      ? size_int (-1) : size_one_node);
>             insert_before (g);
> -           if (bitint_big_endian && rem != 0)
> -             g = gimple_build_cond (NE_EXPR, idx,
> -                                    size_int (bo_idx + 1),
> +           /* For big-endian, if bo_idx + total - 1 - end is all ones, then
> +              compare idx (which is equal to idx_next + 1) against 0
> +              instead.  */
> +           if (bitint_big_endian && bo_idx + total - end == 0)
> +             g = gimple_build_cond (NE_EXPR, idx, size_zero_node,
>                                      NULL_TREE, NULL_TREE);
>             else
>               g = gimple_build_cond (NE_EXPR, idx_next,
>                                      size_int (bo_idx
>                                                + (bitint_big_endian
> -                                                 ? 0 : end)),
> +                                                 ? total - 1 - end
> +                                                 : end)),
>                                      NULL_TREE, NULL_TREE);
>             insert_before (g);
>             m_gsi = gsi_for_stmt (stmt);
> --- a/gcc/testsuite/gcc.dg/bitint-145.c       2026-09-17 17:08:34.038519108 
> +0200
> +++ b/gcc/testsuite/gcc.dg/bitint-145.c       2026-09-17 17:08:07.047875025 
> +0200
> @@ -0,0 +1,35 @@
> +/* PR middle-end/127378 */
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-std=c23 -O2" } */
> +
> +#if __BITINT_MAXWIDTH__ >= 768
> +unsigned _BitInt(512) a;
> +unsigned _BitInt(768) b = -1;
> +
> +__attribute__((noipa)) void
> +foo (unsigned _BitInt(135) *p)
> +{
> +  a = (_BitInt(135)) (p[0] + p[1]);
> +}
> +
> +__attribute__((noipa)) void
> +bar (unsigned _BitInt(200) *p)
> +{
> +  b = p[0] + p[1];
> +}
> +#endif
> +
> +int
> +main ()
> +{
> +#if __BITINT_MAXWIDTH__ >= 768
> +  static unsigned _BitInt(135) p[2] = { -1, 0 };
> +  static unsigned _BitInt(200) q[2] = { 1, 2 };
> +  foo (p);
> +  if (a != (unsigned _BitInt(512)) -1)
> +    __builtin_abort ();
> +  bar (q);
> +  if (b != 3)
> +    __builtin_abort ();
> +#endif
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to