On Thu, Jun 19, 2025 at 05:59:09PM +0800, Yang Yujie wrote:
> In LoongArch psABI, large _BitInt(N) (N > 64) objects are only
> extended to fill the highest 8-byte chunk that contains any used bit,
> but the size of such a large _BitInt type is a multiple of their
> 16-byte alignment.  So there may be an entire unused 8-byte
> chunk that is not filled by extension, and this chunk shouldn't be
> checked when testing if the object is properly extended.
> 
> The original bitintext.h assumed that all bits within
> sizeof(_BitInt(N)) beyond used bits are filled by extension.
> This patch changes that for LoongArch and possibly
> any future ports with a similar behavior.
> 
> P.S. For encoding this test as well as type-generic programming,
> it would be nice to have a builtin function to obtain "N" at
> compile time from _BitInt(N)-typed expressions.  But here
> we stick to existing ones (__builtin_clrsbg / __builtin_clzg).
> 
> gcc/testsuite/ChangeLog:
> 
>       * gcc.dg/bitintext.h: Generalize BEXTC to only check extension
>       within {S,U}_PROMOTED_SIZE bits.
>       * gcc.dg/torture/bitint-82.c: Use the new BEXTC_{U,S} macros.
> ---
>  gcc/testsuite/gcc.dg/bitintext.h         | 48 +++++++++++++-------
>  gcc/testsuite/gcc.dg/torture/bitint-82.c | 56 ++++++++++++------------
>  2 files changed, 60 insertions(+), 44 deletions(-)
> 
> diff --git a/gcc/testsuite/gcc.dg/bitintext.h 
> b/gcc/testsuite/gcc.dg/bitintext.h
> index 99fedb32a9a..48d5673440f 100644
> --- a/gcc/testsuite/gcc.dg/bitintext.h
> +++ b/gcc/testsuite/gcc.dg/bitintext.h
> @@ -4,26 +4,42 @@ do_copy (void *p, const void *q, __SIZE_TYPE__ r)
>    __builtin_memcpy (p, q, r);
>  }
>  
> +#define S_N(x) (__builtin_clrsbg ((typeof (x)) -1) + 1)
> +#define U_N(x) (__builtin_clzg ((typeof (x)) 1) + 1)
> +#define CEIL(x,y) (((x) + (y) - 1) / (y))
> +
> +/* Promote a _BitInt type to include its padding bits.  */
> +#if defined (__s390x__) || defined(__arm__)
> +#define S_PROMOTED_SIZE(x) sizeof (x)
> +#define U_PROMOTED_SIZE(x) sizeof (x)
> +#elif defined(__loongarch__)
> +#define S_PROMOTED_SIZE(x) (sizeof (x) > 8 ? CEIL (S_N (x), 64) * 8: sizeof 
> (x))
> +#define U_PROMOTED_SIZE(x) (sizeof (x) > 8 ? CEIL (U_N (x), 64) * 8: sizeof 
> (x))

Space before :
More importantly, I really don't like the need to differentiate in the
source code between BEXTC_U and BEXTC_S, the macro should figure that out
automatically and before your changes it did, through the
if ((typeof (x)) -1 < 0)
conditional which folds at compile time to 0 or 1.
#define S(x) \
  ((typeof (x)) -1 < 0                                                  \
   ? __builtin_clrsbg (__builtin_choose_expr ((typeof (x)) -1 < 0,      \
                                              (typeof (x)) -1, -1)) + 1 \
   : __builtin_popcountg (__builtin_choose_expr ((typeof (x)) -1 < 0,   \
                                                 0U, (typeof (x)) -1)))
macro provides the right _BitInt width for both signed and unsigned values.
But because the BEXTC macro already uses an if ((typeof (x)) -1 < 0)
conditional, you could as well define the S_N and U_N macros as the
second and third subexpressions of ?: above and just use it in the
corresponding parts of the code.

> +#endif
> +
> +#define S_PROMOTED_TYPE(x) _BitInt (S_PROMOTED_SIZE (x) * __CHAR_BIT__)
> +#define U_PROMOTED_TYPE(x) unsigned _BitInt (U_PROMOTED_SIZE (x) * 
> __CHAR_BIT__)
> +
>  /* Macro to test whether (on targets where psABI requires it) _BitInt
>     with padding bits have those filled with sign or zero extension.  */
>  #if defined(__s390x__) || defined(__arm__) || defined(__loongarch__)
> -#define BEXTC(x) \
> +#define BEXTC_U(x) \
>    do {                                                               \
> -    if ((typeof (x)) -1 < 0)                                 \
> -      {                                                              \
> -     _BitInt(sizeof (x) * __CHAR_BIT__) __x;                 \
> -     do_copy (&__x, &(x), sizeof (__x));                     \
> -     if (__x != (x))                                         \
> -       __builtin_abort ();                                   \
> -      }                                                              \
> -    else                                                     \
> -      {                                                              \
> -     unsigned _BitInt(sizeof (x) * __CHAR_BIT__) __x;        \
> -     do_copy (&__x, &(x), sizeof (__x));                     \
> -     if (__x != (x))                                         \
> -       __builtin_abort ();                                   \
> -      }                                                              \
> +    U_PROMOTED_TYPE (x) __x;                                 \
> +    do_copy (&__x, &(x), U_PROMOTED_SIZE (x));                       \
> +    if (__x != (x))                                          \
> +      __builtin_abort ();                                    \
>    } while (0)
> +
> +#define BEXTC_S(x) \
> +  do {                                                               \
> +    S_PROMOTED_TYPE (x) __x;                                 \
> +    do_copy (&__x, &(x), S_PROMOTED_SIZE (x));                       \
> +    if (__x != (x))                                          \
> +      __builtin_abort ();                                    \
> +  } while (0)
> +
>  #else
> -#define BEXTC(x) do { (void) (x); } while (0)
> +#define BEXTC_S(x) do { (void) (x); } while (0)
> +#define BEXTC_U(x) do { (void) (x); } while (0)
>  #endif

        Jakub

Reply via email to