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)
