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 <[email protected]>
>
> 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 <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)