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