On Wed, 6 Aug 2025, Jakub Jelinek wrote:

> Hi!
> 
> The following testcase is miscompiled on aarch64-linux.
> The problem is in the optimization to shorten large constants
> in PHI arguments.
> In a couple of places during bitint lowering we compute
> minimal precision of constant and if it is significantly
> smaller than the precision of the type, store smaller constant
> in memory and extend it at runtime (zero or all ones).
> Now, in most places that works fine, we handle the stored number
> of limbs by loading them from memory and then the rest is
> extended.  In the PHI INTEGER_CST argument handling we do
> it differently, we don't form there any loops (because we
> insert stmt sequences on the edges).
> The problem is that we copy the whole _BitInt variable from
> memory to the PHI VAR_DECL + initialize the rest to = {} or
> memset to -1.  It has
> min_prec = CEIL (min_prec, limb_prec) * limb_prec;
> precision, so e.g. on x86_64 there is no padding and it works
> just fine.  But on aarch64 which has abi_limb_mode TImode
> and limb_mode DImode it doesn't in some cases.
> In the testcase the constant has 408 bits min precision, rounded up
> to limb_prec (64) is 448, i.e. 7 limbs.  But aarch64 with TImode
> abi_limb_mode will actually allocate 8 limbs and the most significant
> limb is solely padding.  As we want to extend the constant with all
> ones, copying the padding (from memory, so 0s) will result in
> 64 0 bits where 1 bits were needed.
> 
> The following patch fixes it by detecting this case and setting
> min_prec to a multiple of abi limb precision so that it has
> no padding.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> I'll backport to 15.3 later.

OK.

Richard.

> 2025-08-06  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR tree-optimization/121413
>       * gimple-lower-bitint.cc (abi_limb_prec): New variable
>       (bitint_precision_kind): Initialize it.
>       (gimple_lower_bitint): Clear it at the start.  For
>       min_prec > limb_prec descreased precision vars for
>       INTEGER_CST PHI arguments ensure min_prec is either
>       prec or multiple of abi_limb_prec.
> 
>       * gcc.dg/torture/bitint-85.c: New test.
> 
> --- gcc/gimple-lower-bitint.cc.jj     2025-08-05 12:50:43.509021820 +0200
> +++ gcc/gimple-lower-bitint.cc        2025-08-05 19:14:22.114419945 +0200
> @@ -76,7 +76,7 @@ enum bitint_prec_kind {
>  /* Caches to speed up bitint_precision_kind.  */
>  
>  static int small_max_prec, mid_min_prec, large_min_prec, huge_min_prec;
> -static int limb_prec;
> +static int limb_prec, abi_limb_prec;
>  static bool bitint_big_endian, bitint_extended;
>  
>  /* Categorize _BitInt(PREC) as small, middle, large or huge.  */
> @@ -109,6 +109,9 @@ bitint_precision_kind (int prec)
>      large_min_prec = MAX_FIXED_MODE_SIZE + 1;
>    if (!limb_prec)
>      limb_prec = GET_MODE_PRECISION (limb_mode);
> +  if (!abi_limb_prec)
> +    abi_limb_prec
> +      = GET_MODE_PRECISION (as_a <scalar_int_mode> (info.abi_limb_mode));
>    if (!huge_min_prec)
>      {
>        if (4 * limb_prec >= MAX_FIXED_MODE_SIZE)
> @@ -6669,7 +6672,7 @@ static unsigned int
>  gimple_lower_bitint (void)
>  {
>    small_max_prec = mid_min_prec = large_min_prec = huge_min_prec = 0;
> -  limb_prec = 0;
> +  limb_prec = abi_limb_prec = 0;
>    bitint_big_endian = false;
>  
>    unsigned int i;
> @@ -7631,7 +7634,19 @@ gimple_lower_bitint (void)
>                      from smaller number.  */
>                   min_prec = prec;
>                 else
> -                 min_prec = CEIL (min_prec, limb_prec) * limb_prec;
> +                 {
> +                   min_prec = CEIL (min_prec, limb_prec) * limb_prec;
> +                   if (min_prec > limb_prec && abi_limb_prec > limb_prec)
> +                     {
> +                       /* For targets with ABI limb precision higher than
> +                          limb precision round to ABI limb precision,
> +                          otherwise c can contain padding bits.  */
> +                       min_prec
> +                         = CEIL (min_prec, abi_limb_prec) * abi_limb_prec;
> +                       if (min_prec > prec - rem - 2 * limb_prec)
> +                         min_prec = prec;
> +                     }
> +                 }
>                 if (min_prec == 0)
>                   c = NULL_TREE;
>                 else if (min_prec == prec)
> --- gcc/testsuite/gcc.dg/torture/bitint-85.c.jj       2025-08-05 
> 19:07:30.722749541 +0200
> +++ gcc/testsuite/gcc.dg/torture/bitint-85.c  2025-08-05 19:12:59.979484714 
> +0200
> @@ -0,0 +1,34 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-std=c23 -pedantic-errors" } */
> +/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
> +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */
> +
> +#if __BITINT_MAXWIDTH__ >= 1024
> +constexpr _BitInt(1024) d = 
> -541140097068598424394740839221562143161511518875518765552323978870598341733206554363735813878577506997168480201818027232521wb;
> +int c;
> +
> +static inline void
> +foo (_BitInt(1024) b, _BitInt(1024) *r)
> +{
> +  if (c)
> +    b = 0;
> +  *r = b;
> +}
> +
> +[[gnu::noipa]] void
> +bar (_BitInt(1024) y)
> +{
> +  if (y != d)
> +    __builtin_abort ();
> +}
> +#endif
> +
> +int
> +main ()
> +{
> +#if __BITINT_MAXWIDTH__ >= 1024
> +  _BitInt(1024) x;
> +  foo (d, &x);
> +  bar (x);
> +#endif
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to