Am Montag, dem 06.07.2026 um 15:23 +0200 schrieb Jakub Jelinek:
> Hi!
> 
> I'd like to see in C2Y I/O support for _BitInt, so
> something like
> https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2858.pdf
> with obvious updates for the recent C2Y changes
> (signed _BitInt(1) support).
> Now, there are two obstackles in supporting say
>   printf ("%wb575u\n", 
> 112041924188967982740577128258454371281147745286925175670933304406883025453800257407817937118400087623607194547157147451911301069533401837411803352174766773116684201492387419uwb);
> or
>   _BitInt(575) x;
>   scanf ("%wb575d", &x);
> One is a dependency of building the C library on a compiler
> which supports _BitInt (with the right ABI), and another one
> is that there are way too many different _BitInt types.
> It is UB to use va_arg with a type which doesn't match the actually
> passed types with a couple of exceptions.
> If BITINT_MAXWIDTH is very small, say 64, one can just use next to
>   if (is_ll)
>     val = va_arg (ap, long long);
>   else if (is_l)
>     val = va_arg (ap, long);
>   else if (is_i)
>     val = va_arg (ap, int);
> also
>   else if (is_wb)
>     switch (wb_val)
>       {
> #define V(N) case N: val = va_arg (ap, _BitInt(N)); break;
>         V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) V(9)
> #define W(N) V(N##0) V(N##1) V(N##2) V(N##3) V(N##4) \
>            V(N##5) V(N##6) V(N##7) V(N##8) V(N##9)
>       W(1) W(2) W(3) W(4) W(5) V(60) V(61) V(62) V(63) V(64)
>       default: whatever;
>       }
> but if BITINT_MAXWIDTH is 65535 as in GCC or 8388608 in Clang, this
> doesn't really scale (not to mention that it is needed at least, twice,
> once for signed _BitInt and once for unsigned _BitInt).
> 
> The following WIP patch attempts to deal with both of these problems.
> 
> The goal is to add 3 new type-generic builtins, where one can be used
> in a new stdarg.h macro (or two), and the other ones in a few new
> stdbit.h macros.  The former one would be something like
> va_arg_bitint(va_list ap, size_t n, type *ptr, bool endian, bool uns)
> or
> va_arg_bitint_le(va_list ap, size_t n, type *ptr, bool uns)
> va_arg_bitint_be(va_list ap, size_t n, type *ptr, bool uns)
> where type is a standard or extended integer type other than bool, and
> then in stdbit.h
> stdc_store_bitint_le(const void *bitintptr, size_t n, type *ptr, bool uns)
> stdc_store_bitint_be(const void *bitintptr, size_t n, type *ptr, bool uns)
> stdc_load_bitint_le(void *bitintptr, size_t n, const type *ptr, bool uns)
> stdc_load_bitint_be(void *bitintptr, size_t n, const type *ptr, bool uns)
> The va_arg_bitint_le macro would work as if
>   if (uns)
>     switch (n)
>       {
>       case 1: stdc_store_bitint_le(&(_BitInt(1)){va_arg(ap, unsigned 
> _BitInt(1))}, 1, ptr, uns); break;
>       case 2: stdc_store_bitint_le(&(_BitInt(2)){va_arg(ap, unsigned 
> _BitInt(2))}, 2, ptr, uns); break;
> ...
>       case BITINT_MAXWIDTH: 
> stdc_store_bitint_le(&(_BitInt(BITINT_MAXWIDTH)){va_arg(ap, unsigned 
> _BitInt(BITINT_MAXWIDTH))}, BITINT_MAXWIDTH, ptr, uns); break;
>       }
>   else
>     switch (n)
>       {
>       case 1: stdc_store_bitint_le(&(_BitInt(1)){va_arg(ap, _BitInt(1))}, 1, 
> ptr, uns); break;
>       case 2: stdc_store_bitint_le(&(_BitInt(2)){va_arg(ap, _BitInt(2))}, 2, 
> ptr, uns); break;
> ...
>       case BITINT_MAXWIDTH: 
> stdc_store_bitint_le(&(_BitInt(BITINT_MAXWIDTH)){va_arg(ap, 
> _BitInt(BITINT_MAXWIDTH))}, BITINT_MAXWIDTH, ptr, uns); break;
>       }
> so as if using va_arg with _BitInt(N) where n == N and invoking
> stdc_store_bitint_le (or for _be _be) on it.
> Let W be the width of the standard or extended integer type type.
> The stdc_store_bitint_le macro would store to ptr[0] the least
> significant W bits of the _BitInt(N) where n == N value, to ptr[1]
> the W bits above that up to ptr[(n + W - 1) / W - 1], which would
> get the most significant of _BitInt(N) pointed by bitintptr.  If
> (n % W) != 0, with the remaining bits sign extended if !uns and
> zero extended if uns.  The be variant with the different limb
> ordering in the array.
> 
> And stdc_load_bitint_{l,b}e would do the reverse operation, intended
> for scanf etc., where user pass as va_arg pointer to some _BitInt(N)
> and we'd want to store there value from the sum of the limbs passed
> to the macro.
> 
> This way, the C library (but also C users which want to implement
> something similar in their code) can use these macros to easily
> implement the vaargs _BitInt I/O support, and for the case where
> the C library needs to be buildable by compilers which don't support
> _BitInt yet or do support it, but don't support these macros/intrinsics yet,
> one possibility is compile e.g.
> [[gnu::noipa]] void
> __libc_va_arg_bitint_le (va_list *ap, size_t n, unsigned long *ptr, bool uns)
> {
>   __builtin_va_arg_bitint (*ap, n, ptr, false, uns);
> }
> by a newer compiler into assembly and use that assembly file as fallback
> if the compiler used to build libc doesn't support those.
> 
> The following patch is a WIP, __builtin_bitint_pack is not really
> implemented, and __builtin_va_arg_bitint/__builtin_bitint_unpack
> don't support avr/msp430 due to __int20/__int24 types (but those
> don't support _BitInt yet so not an issue that needs immediate
> solving) and one needs to write the target hook for __builtin_va_arg_bitint
> (currently implemented just the generic version for char * va_list targets
> and x86).
> 
> Thoughts on this?

The design looks very reasonable to me, but I have two
comments/questions:

Do we need the full generality, i.e.  support for LE, BE and
any limb type or could we simply fix this to whatever corresponds
to the ABI?  Maybe I am missing something obvious.

In general for libraries (or user code) there is the issue
that different systems may support a different number of bits,
and once a library is compiled with one compiler could break
(or have limitations) for code using another.  This may become
a bigger concern when we want to introduce standard library
functionality using _BitInt.   So I wonder  whether these 
builtins could be made to work for an arbitrary number 
of bits exceeding what the current limit for GCC is.

(I haven't looked at the patch yet).

Martin

> 
> 2026-07-06  Jakub Jelinek  <[email protected]>
> 
> gcc/
>       * builtin-types.def (BT_FN_VOID_PTR_VAR): New.
>       * builtins.def (BUILT_IN_VA_ARG_BITINT,
>       BUILT_IN_BITINT_UNPACK, BUILT_IN_BITINT_PACK): New builtins.
>       * builtins.cc (fold_builtin_bitint_pack): New function.
>       (fold_builtin_varargs): Use it for BUILT_IN_VA_ARG_BITINT,
>       BUILT_IN_BITINT_UNPACK and BUILT_IN_BITINT_PACK.
>       * target.def (gimplify_va_arg_expr): Tweak description and
>       comment.
>       (gimplify_va_arg_bitint): New target hook.
>       * doc/tm.texi.in: Add TARGET_GIMPLIFY_VA_ARG_BITINT.
>       * doc/tm.texi: Regenerate.
>       * targhooks.h (std_gimplify_va_arg_bitint): Declare.
>       * targhooks.cc (std_gimplify_va_arg_bitint): New function.
>       * passes.def (pass_all_optimizations_g): Add pass_stdarg.
>       * tree-stdarg.cc (expand_ifn_va_arg_1): Expand also
>       BUILT_IN_VA_ARG_BITINT.  Fix comment typo, inbetween
>       -> in between.
>       (pass_stdarg::clone): New method.
>       * gimplify.cc (gimplify_call_expr): Handle
>       BUILT_IN_VA_ARG_BITINT, BUILT_IN_BITINT_UNPACK and
>       BUILT_IN_BITINT_PACK.
>       * function.h (struct function): Add has_bitint_pack bitfield.
>       * tree-inline.cc (expand_call_inline): Or in has_bitint_pack.
>       * gimple-lower-bitint.cc (struct bitint_large_huge): Declare
>       add_mult and lower_pack_unpack methods.
>       (bitint_large_huge::add_mult): New method.
>       (bitint_large_huge::lower_pack_unpack): New method.
>       (bitint_large_huge::lower_call): Handle
>       BUILT_IN_BITINT_UNPACK and BUILT_IN_BITINT_PACK using
>       lower_pack_unpack.
>       (gimple_lower_bitint): Don't ignore functions with no
>       _BitInt SSA_NAMEs if cfun->has_bitint_pack is set, arrange
>       in that case for limb_prec etc. being computed.  Pretend
>       BUILT_IN_BITINT_UNPACK and BUILT_IN_BITINT_PACK calls have
>       kind bitint_prec_large.
>       * lto-streamer-in.cc (input_struct_function_base): Stream in
>       has_bitint_pack.
>       * lto-streamer-out.cc (output_struct_function_base): Stream out
>       has_bitint_pack.
>       * config/i386/i386.cc (ix86_gimplify_va_arg_bitint): New function.
>       (TARGET_GIMPLIFY_VA_ARG_BITINT): Redefine.
> gcc/c-family/
>       * c-common.cc (check_builtin_function_arguments): Handle
>       BUILT_IN_VA_ARG_BITINT, BUILT_IN_BITINT_UNPACK and
>       BUILT_IN_BITINT_PACK.
> gcc/testsuite/
>       * gcc.dg/bitint-138.c: New test.
>       * gcc.dg/bitint-139.c: New test.
>       * gcc.dg/bitint-140.c: New test.
>       * gcc.dg/bitint-141.c: New test.
>       * gcc.dg/bitint-142.c: New test.
>       * gcc.dg/bitint-143.c: New test.
>       * gcc.dg/bitint-144.c: New test.
>       * gcc.dg/bitint-145.c: New test.
>       * gcc.dg/bitint-146.c: New test.
>       * gcc.dg/bitint-147.c: New test.
>       * gcc.dg/bitint-148.c: New test.
>       * gcc.dg/bitint-149.c: New test.
>       * gcc.dg/bitint-150.c: New test.
>       * gcc.dg/bitint-151.c: New test.
>       * gcc.dg/bitint-152.c: New test.
>       * gcc.dg/bitint-153.c: New test.
>       * gcc.dg/bitint-154.c: New test.
>       * gcc.dg/bitint-155.c: New test.
> 
> --- gcc/builtin-types.def.jj  2026-07-03 20:39:18.971958769 +0200
> +++ gcc/builtin-types.def     2026-07-04 09:55:05.395610572 +0200
> @@ -1046,6 +1046,7 @@ DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I2_I2_VAR
>  DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I4_I4_VAR, BT_I4, BT_I4)
>  DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I8_I8_VAR, BT_I8, BT_I8)
>  DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I16_I16_VAR, BT_I16, BT_I16)
> +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_VOID_PTR_VAR, BT_VOID, BT_PTR)
>  
>  DEF_FUNCTION_TYPE_VAR_2 (BT_FN_INT_FILEPTR_CONST_STRING_VAR,
>                        BT_INT, BT_FILEPTR, BT_CONST_STRING)
> --- gcc/builtins.def.jj       2026-07-03 20:39:18.973958745 +0200
> +++ gcc/builtins.def  2026-07-04 09:55:05.396657381 +0200
> @@ -1157,6 +1157,9 @@ DEF_GCC_BUILTIN        (BUILT_IN_VA_END,
>  DEF_GCC_BUILTIN        (BUILT_IN_VA_START, "va_start", 
> BT_FN_VOID_VALIST_REF_VAR, ATTR_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_VA_ARG_PACK, "va_arg_pack", BT_FN_INT, 
> ATTR_PURE_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_VA_ARG_PACK_LEN, "va_arg_pack_len", 
> BT_FN_INT, ATTR_PURE_NOTHROW_LEAF_LIST)
> +DEF_GCC_BUILTIN        (BUILT_IN_VA_ARG_BITINT, "va_arg_bitint", 
> BT_FN_VOID_VALIST_REF_VAR, ATTR_NULL)
> +DEF_GCC_BUILTIN        (BUILT_IN_BITINT_UNPACK, "bitint_unpack", 
> BT_FN_VOID_CONST_PTR_VAR, ATTR_NULL)
> +DEF_GCC_BUILTIN        (BUILT_IN_BITINT_PACK, "bitint_pack", 
> BT_FN_VOID_PTR_VAR, ATTR_NULL)
>  DEF_EXT_LIB_BUILTIN    (BUILT_IN__EXIT, "_exit", BT_FN_VOID_INT, 
> ATTR_NORETURN_NOTHROW_LEAF_LIST)
>  DEF_C99_BUILTIN        (BUILT_IN__EXIT2, "_Exit", BT_FN_VOID_INT, 
> ATTR_NORETURN_NOTHROW_LEAF_LIST)
>  
> --- gcc/builtins.cc.jj        2026-07-03 20:39:18.973958745 +0200
> +++ gcc/builtins.cc   2026-07-06 10:59:18.374406272 +0200
> @@ -10636,6 +10636,26 @@ fold_builtin_addc_subc (location_t loc,
>    return build2_loc (loc, COMPOUND_EXPR, type, store, intres);
>  }
>  
> +/* Adjust __builtin_va_arg_bitint, __builtin_bitint_pack or
> +   __builtin_bitint_unpack calls, if they have 5 arguments, to remember
> +   the type of the 3rd argument in new 6th argument.  Pointer conversions
> +   in GIMPLE are useless, so we can't rely on TREE_TYPE of the 3rd
> +   argument later on.  */
> +
> +static tree
> +fold_builtin_bitint_pack (location_t loc, enum built_in_function fcode,
> +                       tree *args, int nargs)
> +{
> +  if (nargs != 5)
> +    return NULL_TREE;
> +  nargs = fcode == BUILT_IN_VA_ARG_BITINT ? 7 : 6;
> +  return build_call_expr_loc (loc, builtin_decl_explicit (fcode), nargs,
> +                           args[0], args[1], args[2], args[3], args[4],
> +                           build_zero_cst (TREE_TYPE (args[2])),
> +                           nargs == 7 ? build_zero_cst (TREE_TYPE (args[0]))
> +                           : NULL_TREE);
> +}
> +
>  /* Fold a call to __builtin_FILE to a constant string.  */
>  
>  static inline tree
> @@ -11957,6 +11977,11 @@ fold_builtin_varargs (location_t loc, tr
>      case BUILT_IN_SUBCLL:
>        return fold_builtin_addc_subc (loc, fcode, args);
>  
> +    case BUILT_IN_VA_ARG_BITINT:
> +    case BUILT_IN_BITINT_UNPACK:
> +    case BUILT_IN_BITINT_PACK:
> +      return fold_builtin_bitint_pack (loc, fcode, args, nargs);
> +
>      default:
>        break;
>      }
> --- gcc/target.def.jj 2026-07-03 20:39:18.999958429 +0200
> +++ gcc/target.def    2026-07-04 09:55:05.396060299 +0200
> @@ -4469,16 +4469,29 @@ DEFHOOK_UNDOC
>  "Expand the @code{__builtin_va_start} builtin.",
>   void, (tree valist, rtx nextarg), NULL)
>  
> -/* Gimplifies a VA_ARG_EXPR.  */
> +/* Gimplifies an IFN_VA_ARG call.  */
>  DEFHOOK
>  (gimplify_va_arg_expr,
>   "This hook performs target-specific gimplification of\n\
> -@code{VA_ARG_EXPR}.  The first two parameters correspond to the\n\
> +@code{IFN_VA_ARG} call.  The first two parameters correspond to the\n\
>  arguments to @code{va_arg}; the latter two are as in\n\
>  @code{gimplify.cc:gimplify_expr}.",
>   tree, (tree valist, tree type, gimple_seq *pre_p, gimple_seq *post_p),
>   std_gimplify_va_arg_expr)
>  
> +/* Gimplifies an __builtin_va_arg_bitint call except the
> +   __builtin_bitint_unpack part.  */
> +DEFHOOK
> +(gimplify_va_arg_bitint,
> + "This hook performs target-specific gimplification of\n\
> +@code{__builtin_va_arg_bitint} call except the\n\
> +@code{__builtin_bitint_unpack} part.  The first two\n\
> +parameters correspond to the first two arguments to\n\
> +@code{__builtin_va_arg_bitint}; the latter two are as in\n\
> +@code{gimplify.cc:gimplify_expr}.",
> + tree, (tree valist, tree type, gimple_seq *pre_p, gimple_seq *post_p),
> + std_gimplify_va_arg_bitint)
> +
>  /* Validity-checking routines for PCH files, target-specific.
>     get_pch_validity returns a pointer to the data to be stored,
>     and stores the size in its argument.  pch_valid_p gets the same
> --- gcc/doc/tm.texi.in.jj     2026-07-03 20:39:18.984958611 +0200
> +++ gcc/doc/tm.texi.in        2026-07-04 09:55:05.392708803 +0200
> @@ -3498,6 +3498,8 @@ stack.
>  
>  @hook TARGET_GIMPLIFY_VA_ARG_EXPR
>  
> +@hook TARGET_GIMPLIFY_VA_ARG_BITINT
> +
>  @hook TARGET_VALID_POINTER_MODE
>  
>  @hook TARGET_REF_MAY_ALIAS_ERRNO
> --- gcc/doc/tm.texi.jj        2026-07-03 20:39:18.983958623 +0200
> +++ gcc/doc/tm.texi   2026-07-04 09:55:05.393756717 +0200
> @@ -4574,11 +4574,20 @@ type of @var{type}. If @var{type} is not
>  
>  @deftypefn {Target Hook} tree TARGET_GIMPLIFY_VA_ARG_EXPR (tree 
> @var{valist}, tree @var{type}, gimple_seq *@var{pre_p}, gimple_seq 
> *@var{post_p})
>  This hook performs target-specific gimplification of
> -@code{VA_ARG_EXPR}.  The first two parameters correspond to the
> +@code{IFN_VA_ARG} call.  The first two parameters correspond to the
>  arguments to @code{va_arg}; the latter two are as in
>  @code{gimplify.cc:gimplify_expr}.
>  @end deftypefn
>  
> +@deftypefn {Target Hook} tree TARGET_GIMPLIFY_VA_ARG_BITINT (tree 
> @var{valist}, tree @var{type}, gimple_seq *@var{pre_p}, gimple_seq 
> *@var{post_p})
> +This hook performs target-specific gimplification of
> +@code{__builtin_va_arg_bitint} call except the
> +@code{__builtin_bitint_unpack} part.  The first two
> +parameters correspond to the first two arguments to
> +@code{__builtin_va_arg_bitint}; the latter two are as in
> +@code{gimplify.cc:gimplify_expr}.
> +@end deftypefn
> +
>  @deftypefn {Target Hook} bool TARGET_VALID_POINTER_MODE (scalar_int_mode 
> @var{mode})
>  Define this to return nonzero if the port can handle pointers
>  with machine mode @var{mode}.  The default version of this
> --- gcc/targhooks.h.jj        2026-07-03 20:39:19.002958392 +0200
> +++ gcc/targhooks.h   2026-07-04 09:55:05.395417423 +0200
> @@ -289,6 +289,8 @@ extern bool default_member_type_forces_b
>  extern void default_atomic_assign_expand_fenv (tree *, tree *, tree *);
>  extern tree build_va_arg_indirect_ref (tree);
>  extern tree std_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq 
> *);
> +extern tree std_gimplify_va_arg_bitint (tree, tree, gimple_seq *,
> +                                     gimple_seq *);
>  extern bool can_use_doloop_if_innermost (const widest_int &,
>                                        const widest_int &,
>                                        unsigned int, bool);
> --- gcc/targhooks.cc.jj       2026-07-03 20:39:19.001958405 +0200
> +++ gcc/targhooks.cc  2026-07-04 09:55:05.394886423 +0200
> @@ -2706,6 +2706,173 @@ std_gimplify_va_arg_expr (tree valist, t
>    return build_va_arg_indirect_ref (addr);
>  }
>  
> +/* The "standard" implementation of __builtin_va_arg_bitint: read the
> +   _BitInt(n) value from the current (padded) address and increment
> +   by the (padded) size and return its address, so that
> +   __builtin_bitint_unpack can be called on that address.  */
> +
> +tree
> +std_gimplify_va_arg_bitint (tree valist, tree n, gimple_seq *pre_p,
> +                         gimple_seq *post_p)
> +{
> +  /* All of the alignment and movement below is for args-grow-up machines.  
> */
> +  gcc_assert (!ARGS_GROW_DOWNWARD);
> +
> +  scalar_int_mode last_limb_mode = QImode;
> +  struct bitint_info info;
> +  tree ptr = create_tmp_var (const_ptr_type_node, "bitint_ptr");
> +  tree labend = create_artificial_label (input_location);
> +  int i;
> +  for (i = 1; i <= 256; ++i)
> +    {
> +      bool ok = targetm.c.bitint_type_info (i, &info);
> +      gcc_assert (ok);
> +      scalar_int_mode limb_mode
> +     = as_a <scalar_int_mode> (info.abi_limb_mode);
> +      if (i > GET_MODE_PRECISION (limb_mode)
> +       || (i != 1 && limb_mode != last_limb_mode))
> +     {
> +       tree type = build_bitint_type (i - 1, 1);
> +       gimple_seq post_seq = NULL;
> +       tree labtrue = create_artificial_label (input_location);
> +       tree labfalse = create_artificial_label (input_location);
> +       gcond *cond_stmt
> +         = gimple_build_cond (LE_EXPR, n,
> +                              build_int_cst (TREE_TYPE (n), i - 1),
> +                              labtrue, labfalse);
> +       gimple_seq_add_stmt (pre_p, cond_stmt);
> +       gimple_seq_add_stmt (pre_p, gimple_build_label (labtrue));
> +       tree mem_ref
> +         = std_gimplify_va_arg_expr (unshare_expr (valist), type, pre_p,
> +                                     &post_seq);
> +       gcc_assert (TREE_CODE (mem_ref) == MEM_REF);
> +       gimplify_assign (ptr, build_fold_addr_expr (mem_ref), pre_p);
> +       if (post_seq)
> +         gimple_seq_add_seq (pre_p, post_seq);
> +       gimple_seq_add_stmt (pre_p, gimple_build_goto (labend));
> +       gimple_seq_add_stmt (pre_p, gimple_build_label (labfalse));
> +       if (i > GET_MODE_PRECISION (limb_mode))
> +         break;
> +     }
> +      last_limb_mode = limb_mode;
> +      /* Optimize for the common case where N 1-8 use QImode,
> +      9-16 use HImode, 17-32 use SImode etc.  */
> +      int j = -1;
> +      switch (i)
> +     {
> +     case 1: j = 8; break;
> +     case 9: j = 16; break;
> +     case 17: j = 32; break;
> +     case 33: j = 64; break;
> +     case 65: j = 128; break;
> +     default: break;
> +     }
> +      if (j != -1)
> +     {
> +       ok = targetm.c.bitint_type_info (j, &info);
> +       gcc_assert (ok);
> +       scalar_int_mode limb_mode
> +         = as_a <scalar_int_mode> (info.abi_limb_mode);
> +       if (limb_mode == last_limb_mode)
> +         i = j - 1;
> +     }
> +    }
> +
> +  tree type = build_bitint_type (i, 1);
> +  bool indirect = pass_va_arg_by_reference (type);
> +  if (indirect)
> +    type = build_pointer_type (type);
> +  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.abi_limb_mode);
> +  int abi_limb_prec = GET_MODE_PRECISION (limb_mode);
> +
> +  unsigned HOST_WIDE_INT align = PARM_BOUNDARY / BITS_PER_UNIT;
> +  unsigned HOST_WIDE_INT boundary
> +    = targetm.calls.function_arg_boundary (TYPE_MODE (type), type);
> +
> +  /* When we align parameter on stack for caller, if the parameter
> +     alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
> +     aligned at MAX_SUPPORTED_STACK_ALIGNMENT.  We will match callee
> +     here with caller.  */
> +  if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
> +    boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
> +
> +  boundary /= BITS_PER_UNIT;
> +
> +  tree valist_tmp = get_initialized_tmp_var (valist, pre_p);
> +
> +  /* va_list pointer is aligned to PARM_BOUNDARY.  If argument actually
> +     requires greater alignment, we must perform dynamic alignment.  */
> +  if (boundary > align)
> +    {
> +      tree t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
> +                    fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
> +      gimplify_and_add (t, pre_p);
> +
> +      t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
> +               fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist),
> +                            valist_tmp,
> +                            build_int_cst (TREE_TYPE (valist), -boundary)));
> +      gimplify_and_add (t, pre_p);
> +    }
> +  else
> +    boundary = align;
> +
> +  /* If the actual alignment is less than the alignment of the type,
> +     adjust the type accordingly so that we don't assume strict alignment
> +     when dereferencing the pointer.  */
> +  boundary *= BITS_PER_UNIT;
> +  if (boundary < TYPE_ALIGN (type))
> +    {
> +      type = build_variant_type_copy (type);
> +      SET_TYPE_ALIGN (type, boundary);
> +    }
> +
> +  /* Compute the rounded size of the type.  */
> +  tree type_size;
> +  if (indirect)
> +    type_size = arg_size_in_bytes (type);
> +  else
> +    {
> +      tree t = fold_convert (sizetype, n);
> +      t = size_binop (PLUS_EXPR, t, size_int (abi_limb_prec - 1));
> +      t = size_binop (TRUNC_DIV_EXPR, t, size_int (abi_limb_prec));
> +      type_size = size_binop (MULT_EXPR, t,
> +                           size_int (GET_MODE_SIZE (limb_mode)));
> +    }
> +  tree rounded_size = round_up (type_size, align);
> +
> +  /* Reduce rounded_size so it's sharable with the postqueue.  */
> +  gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
> +
> +  /* Get AP.  */
> +  tree addr = valist_tmp;
> +  if (PAD_VARARGS_DOWN)
> +    {
> +      /* Small args are padded downward.  */
> +      tree t = fold_build2_loc (input_location, GT_EXPR, sizetype,
> +                             rounded_size, size_int (align));
> +      t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
> +                    size_binop (MINUS_EXPR, rounded_size, type_size));
> +      addr = fold_build_pointer_plus (addr, t);
> +    }
> +
> +  /* Compute new value for AP.  */
> +  tree t = fold_build_pointer_plus (valist_tmp, rounded_size);
> +  t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
> +  gimplify_and_add (t, pre_p);
> +
> +  addr = fold_convert (build_pointer_type (type), addr);
> +
> +  if (indirect)
> +    addr = build_va_arg_indirect_ref (addr);
> +
> +  gimplify_assign (ptr, addr, pre_p);
> +
> +  gimple_seq_add_stmt (pre_p, gimple_build_label (labend));
> +
> +  return ptr;
> +}
> +
>  /* An implementation of TARGET_CAN_USE_DOLOOP_P for targets that do
>     not support nested low-overhead loops.  */
>  
> --- gcc/passes.def.jj 2026-07-03 20:39:18.998958441 +0200
> +++ gcc/passes.def    2026-07-04 09:55:05.396906713 +0200
> @@ -397,6 +397,7 @@ along with GCC; see the file COPYING3.
>        passes and all optimization work is done early.  */
>        NEXT_PASS (pass_remove_cgraph_callee_edges);
>        NEXT_PASS (pass_strip_predict_hints, false /* early_p */);
> +      NEXT_PASS (pass_stdarg);
>        /* Lower remaining pieces of GIMPLE.  */
>        NEXT_PASS (pass_lower_complex);
>        NEXT_PASS (pass_lower_bitint);
> --- gcc/tree-stdarg.cc.jj     2026-07-03 20:39:19.006958344 +0200
> +++ gcc/tree-stdarg.cc        2026-07-06 13:28:28.256424506 +0200
> @@ -1003,17 +1003,17 @@ expand_ifn_va_arg_1 (function *fun)
>      for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
>        {
>       gimple *stmt = gsi_stmt (i);
> -     tree ap, aptype, expr, lhs, type;
> +     tree ap, aptype;
>       gimple_seq pre = NULL, post = NULL;
> -
> -     if (!gimple_call_internal_p (stmt, IFN_VA_ARG))
> +     bool ifn_va_arg = gimple_call_internal_p (stmt, IFN_VA_ARG);
> +     if (!ifn_va_arg
> +         && !gimple_call_builtin_p (stmt, BUILT_IN_VA_ARG_BITINT))
>         continue;
>  
>       modified = true;
>  
> -     type = TREE_TYPE (TREE_TYPE (gimple_call_arg (stmt, 1)));
>       ap = gimple_call_arg (stmt, 0);
> -     aptype = TREE_TYPE (gimple_call_arg (stmt, 2));
> +     aptype = TREE_TYPE (gimple_call_arg (stmt, ifn_va_arg ? 2 : 6));
>       gcc_assert (POINTER_TYPE_P (aptype));
>  
>       /* Balanced out the &ap, usually added by build_va_arg.  */
> @@ -1028,30 +1028,54 @@ expand_ifn_va_arg_1 (function *fun)
>          from multiple evaluations.  */
>       gimplify_expr (&ap, &pre, &post, is_gimple_min_lval, fb_lvalue);
>  
> -     expr = targetm.gimplify_va_arg_expr (ap, type, &pre, &post);
> -
> -     lhs = gimple_call_lhs (stmt);
> -     if (lhs != NULL_TREE)
> +     if (ifn_va_arg)
>         {
> -         unsigned int nargs = gimple_call_num_args (stmt);
> -         gcc_assert (useless_type_conversion_p (TREE_TYPE (lhs), type));
> +         tree type = TREE_TYPE (TREE_TYPE (gimple_call_arg (stmt, 1)));
> +         tree expr = targetm.gimplify_va_arg_expr (ap, type, &pre, &post);
>  
> -         if (nargs == 4)
> +         tree lhs = gimple_call_lhs (stmt);
> +         if (lhs != NULL_TREE)
>             {
> -             /* We've transported the size of with WITH_SIZE_EXPR here as
> -                the last argument of the internal fn call.  Now reinstate
> -                it.  */
> -             tree size = gimple_call_arg (stmt, nargs - 1);
> -             expr = build2 (WITH_SIZE_EXPR, TREE_TYPE (expr), expr, size);
> -           }
> +             unsigned int nargs = gimple_call_num_args (stmt);
> +             gcc_assert (useless_type_conversion_p (TREE_TYPE (lhs), type));
>  
> -         /* We use gimplify_assign here, rather than gimple_build_assign,
> -            because gimple_assign knows how to deal with variable-sized
> -            types.  */
> -         gimplify_assign (lhs, expr, &pre);
> +             if (nargs == 4)
> +               {
> +                 /* We've transported the size of with WITH_SIZE_EXPR here
> +                    as the last argument of the internal fn call.  Now
> +                    reinstate it.  */
> +                 tree size = gimple_call_arg (stmt, nargs - 1);
> +                 expr = build2 (WITH_SIZE_EXPR, TREE_TYPE (expr), expr,
> +                                size);
> +               }
> +
> +             /* We use gimplify_assign here, rather than
> +                gimple_build_assign, because gimple_assign knows how to deal
> +                with variable-sized types.  */
> +             gimplify_assign (lhs, expr, &pre);
> +           }
> +         else
> +           gimplify_and_add (expr, &pre);
>         }
>       else
> -       gimplify_and_add (expr, &pre);
> +       {
> +         tree n = gimple_call_arg (stmt, 1);
> +         tree dptr = gimple_call_arg (stmt, 2);
> +         tree endian = gimple_call_arg (stmt, 3);
> +         tree uns = gimple_call_arg (stmt, 4);
> +         tree dptr_type = gimple_call_arg (stmt, 5);
> +         tree sptr = targetm.gimplify_va_arg_bitint (ap, n, &pre, &post);
> +
> +         /* Emit
> +            __builtin_bitint_unpack (sptr, n, dptr, endian, uns);
> +            call that bitint lowering lowers later on (with original
> +            pointer type of dptr as an extra argument of NULL pointer).  */
> +         tree fn = builtin_decl_explicit (BUILT_IN_BITINT_UNPACK);
> +         gimple *g = gimple_build_call (fn, 6, sptr, n, dptr, endian, uns,
> +                                        dptr_type);
> +         gimple_seq_add_stmt (&pre, g);
> +         cfun->has_bitint_pack = 1;
> +       }
>  
>       input_location = saved_location;
>       pop_gimplify_context (NULL);
> @@ -1061,7 +1085,7 @@ expand_ifn_va_arg_1 (function *fun)
>  
>       /* Add the sequence after IFN_VA_ARG.  This splits the bb right
>          after IFN_VA_ARG, and adds the sequence in one or more new bbs
> -        inbetween.  */
> +        in between.  */
>       gimple_find_sub_bbs (pre, &i);
>  
>       /* Remove the IFN_VA_ARG gimple_call.  It's the last stmt in the
> @@ -1126,6 +1150,11 @@ public:
>    {}
>  
>    /* opt_pass methods: */
> +  opt_pass * clone () final override
> +    {
> +      return new pass_stdarg (m_ctxt);
> +    }
> +
>    bool gate (function *) final override
>      {
>        /* Always run this pass, in order to expand va_arg internal_fns.  We
> --- gcc/gimplify.cc.jj        2026-07-03 20:39:18.992958514 +0200
> +++ gcc/gimplify.cc   2026-07-04 09:55:05.397828605 +0200
> @@ -4669,6 +4669,17 @@ gimplify_call_expr (tree *expr_p, gimple
>         }
>       break;
>  
> +      case BUILT_IN_VA_ARG_BITINT:
> +     /* Clear the tentatively set PROP_gimple_lva, to indicate that
> +        __builtin_va_arg_bitint needs to be expanded.  */
> +     cfun->curr_properties &= ~PROP_gimple_lva;
> +     break;
> +
> +      case BUILT_IN_BITINT_PACK:
> +      case BUILT_IN_BITINT_UNPACK:
> +     cfun->has_bitint_pack = 1;
> +     break;
> +
>        default:
>          ;
>        }
> --- gcc/function.h.jj 2026-07-03 20:39:18.987958575 +0200
> +++ gcc/function.h    2026-07-04 09:55:05.398938619 +0200
> @@ -456,6 +456,9 @@ struct GTY(()) function {
>  
>    /* Nonzero if reload will have to split basic blocks.  */
>    unsigned int split_basic_blocks_after_reload : 1;
> +
> +  /* Nonzero if function has any __builtin_bitint_{,un}pack calls.  */
> +  unsigned int has_bitint_pack : 1;
>  };
>  
>  /* Add the decl D to the local_decls list of FUN.  */
> --- gcc/tree-inline.cc.jj     2026-07-03 20:39:19.003958380 +0200
> +++ gcc/tree-inline.cc        2026-07-04 09:55:05.399280058 +0200
> @@ -5097,6 +5097,7 @@ expand_call_inline (basic_block bb, gimp
>    if (src_properties != prop_mask)
>      dst_cfun->curr_properties &= src_properties | ~prop_mask;
>    dst_cfun->calls_eh_return |= id->src_cfun->calls_eh_return;
> +  dst_cfun->has_bitint_pack |= id->src_cfun->has_bitint_pack;
>    id->dst_node->has_omp_variant_constructs
>      |= id->src_node->has_omp_variant_constructs;
>  
> --- gcc/gimple-lower-bitint.cc.jj     2026-07-03 20:39:18.989958551 +0200
> +++ gcc/gimple-lower-bitint.cc        2026-07-06 13:15:49.312372924 +0200
> @@ -452,6 +452,7 @@ struct bitint_large_huge
>    tree handle_operand (tree, tree);
>    tree prepare_data_in_out (tree, tree, tree *, tree = NULL_TREE);
>    tree add_cast (tree, tree);
> +  gimple *add_mult (tree, tree, unsigned HOST_WIDE_INT);
>    tree handle_plus_minus (tree_code, tree, tree, tree);
>    tree handle_lshift (tree, tree, tree);
>    tree handle_cast (tree, tree, tree);
> @@ -475,6 +476,7 @@ struct bitint_large_huge
>    void lower_complexexpr_stmt (gimple *);
>    void lower_bit_query (gimple *);
>    void lower_bswap_bitreverse (tree, gimple *);
> +  void lower_pack_unpack (gimple *);
>    void lower_call (tree, gimple *);
>    void lower_asm (gimple *);
>    void lower_stmt (gimple *);
> @@ -1202,6 +1204,24 @@ bitint_large_huge::add_cast (tree type,
>    return lhs;
>  }
>  
> +/* Emit a stmt to set dest = src * m; before the current location.  */
> +
> +gimple *
> +bitint_large_huge::add_mult (tree dest, tree src, unsigned HOST_WIDE_INT m)
> +{
> +  gimple *g;
> +  if (m == 1)
> +    g = gimple_build_assign (dest, src);
> +  else if (pow2p_hwi (m))
> +    g = gimple_build_assign (dest, LSHIFT_EXPR, src,
> +                          build_int_cst (unsigned_type_node,
> +                                         exact_log2 (m)));
> +  else
> +    g = gimple_build_assign (dest, MULT_EXPR, src, size_int (m));
> +  insert_before (g);
> +  return g;
> +}
> +
>  /* Helper of handle_stmt method, handle PLUS_EXPR or MINUS_EXPR.  */
>  
>  tree
> @@ -6284,6 +6304,587 @@ bitint_large_huge::lower_bswap_bitrevers
>      }
>  }
>  
> +/* Lower a __builtin_bitint_{,un}pack call.  */
> +
> +void
> +bitint_large_huge::lower_pack_unpack (gimple *stmt)
> +{
> +  bool pack_p = gimple_call_builtin_p (stmt, BUILT_IN_BITINT_PACK);
> +  location_t loc = gimple_location (stmt);
> +  tree bitint_ptr = gimple_call_arg (stmt, 0);
> +  tree n = gimple_call_arg (stmt, 1);
> +  tree limb_ptr = gimple_call_arg (stmt, 2);
> +  tree big_endian_p = gimple_call_arg (stmt, 3);
> +  tree uns_p = gimple_call_arg (stmt, 4);
> +  tree limb_ptr_type = TREE_TYPE (gimple_call_arg (stmt, 5));
> +  gcc_assert (POINTER_TYPE_P (limb_ptr_type));
> +  tree limb_type = TYPE_MAIN_VARIANT (TREE_TYPE (limb_ptr_type));
> +  gcc_assert (TREE_CODE (limb_type) == INTEGER_TYPE);
> +  /* When _BitInt support is added for avr or msp430 or if some
> +     target chooses to use some non power-of-two limb_prec, this might
> +     need to change and add full-blown support for arbitrary
> +     TYPE_PRECISION (limb_type) (for avr this could be 24 and for msp430
> +     20) and limb_prec combinations.  Until then, we just support
> +     the cases where TYPE_PRECISION (limb_prec) and limb_prec are
> +     power-of-two and one of them is divisible by the other one.
> +     And for the case where limb_type is wider than limb_prec, only
> +     support when limb_type has precision limb_prec * 2.  */
> +  if ((TYPE_PRECISION (limb_type) > limb_prec
> +       && TYPE_PRECISION (limb_type) != 2 * limb_prec)
> +      || (TYPE_PRECISION (limb_type) < limb_prec
> +       && (limb_prec % TYPE_PRECISION (limb_type)) != 0))
> +    {
> +      sorry_at (loc, "currently unsupported combination of requested limb "
> +                  "type %qT and internal %<_BitInt%> limb type %qT",
> +             limb_type, m_limb_type);
> +      return;
> +    }
> +
> +  scalar_int_mode last_limb_mode = QImode;
> +  struct bitint_info info;
> +  auto_vec <tree, 10> small_types;
> +  int i;
> +  for (i = 1; i <= 256; ++i)
> +    {
> +      bool ok = targetm.c.bitint_type_info (i, &info);
> +      gcc_assert (ok);
> +      scalar_int_mode limb_mode
> +     = as_a <scalar_int_mode> (info.abi_limb_mode);
> +      if (i > GET_MODE_PRECISION (limb_mode)
> +       || (i != 1 && limb_mode != last_limb_mode))
> +     {
> +       small_types.safe_push (build_bitint_type (i - 1, 1));
> +       if (i > GET_MODE_PRECISION (limb_mode))
> +         break;
> +     }
> +      last_limb_mode = limb_mode;
> +      /* Optimize for the common case where N 1-8 use QImode,
> +      9-16 use HImode, 17-32 use SImode etc.  */
> +      int j = -1;
> +      switch (i)
> +     {
> +     case 1: j = 8; break;
> +     case 9: j = 16; break;
> +     case 17: j = 32; break;
> +     case 33: j = 64; break;
> +     case 65: j = 128; break;
> +     default: break;
> +     }
> +      if (j != -1)
> +     {
> +       ok = targetm.c.bitint_type_info (j, &info);
> +       gcc_assert (ok);
> +       scalar_int_mode limb_mode
> +         = as_a <scalar_int_mode> (info.abi_limb_mode);
> +       if (limb_mode == last_limb_mode)
> +         i = j - 1;
> +     }
> +    }
> +  if (TYPE_PRECISION (small_types.last ()) < TYPE_PRECISION (limb_type))
> +    small_types.safe_push (build_bitint_type (TYPE_PRECISION (limb_type), 
> 1));
> +  if (!pack_p)
> +    {
> +      int prec = TYPE_PRECISION (small_types.last ());
> +      tree itype = build_nonstandard_integer_type (prec, 1), type, val;
> +      edge edge_small, edge_next = NULL, edge_large;
> +      if_then_else (gimple_build_cond (LE_EXPR, n,
> +                                    size_int (prec),
> +                                    NULL_TREE,
> +                                    NULL_TREE),
> +                 profile_probability::unlikely (),
> +                 edge_small, edge_large);
> +      unsigned j;
> +      FOR_EACH_VEC_ELT (small_types, j, type)
> +     {
> +       if (TYPE_PRECISION (type) < prec)
> +         if_then_else (gimple_build_cond (LE_EXPR, n,
> +                                          size_int (TYPE_PRECISION (type)),
> +                                          NULL_TREE,
> +                                          NULL_TREE),
> +                       profile_probability::even (),
> +                       edge_small, edge_next);
> +       tree mem = build2 (MEM_REF, type, bitint_ptr,
> +                          build_int_cst (ptr_type_node, 0));
> +       gimple *g = gimple_build_assign (make_ssa_name (type), mem);
> +       insert_before (g);
> +       g = gimple_build_assign (make_ssa_name (itype), NOP_EXPR,
> +                                gimple_assign_lhs (g));
> +       insert_before (g);
> +       small_types[j] = gimple_assign_lhs (g);
> +       if (TYPE_PRECISION (type) < prec)
> +         m_gsi = gsi_after_labels (edge_next->src);
> +     }
> +      tree v = small_types.last ();
> +      edge e;
> +      do
> +     {
> +       e = single_succ_edge (gimple_bb (SSA_NAME_DEF_STMT (v)));
> +       if (e->dest == edge_large->dest)
> +         {
> +           m_gsi = gsi_after_labels (e->src);
> +           break;
> +         }
> +       gphi *phi = create_phi_node (make_ssa_name (TREE_TYPE (v)), e->dest);
> +       add_phi_arg (phi, v, e, UNKNOWN_LOCATION);
> +       v = gimple_phi_result (phi);
> +     }
> +      while (1);
> +      FOR_EACH_VEC_ELT (small_types, j, val)
> +     if (val == small_types.last ())
> +       break;
> +     else
> +       {
> +         e = single_succ_edge (gimple_bb (SSA_NAME_DEF_STMT (val)));
> +         gphi_iterator gsi = gsi_start_phis (e->dest);
> +         add_phi_arg (gsi.phi (), val, e, UNKNOWN_LOCATION);
> +       }
> +      if (TYPE_PRECISION (limb_type) > prec)
> +     v = add_cast (limb_type, v);
> +      e = single_succ_edge (gsi_bb (m_gsi));
> +      gphi *phiv = create_phi_node (make_ssa_name (TREE_TYPE (v)), e->dest);
> +      add_phi_arg (phiv, v, e, UNKNOWN_LOCATION);
> +      gphi *phin = create_phi_node (make_ssa_name (sizetype), e->dest);
> +      add_phi_arg (phin, n, e, UNKNOWN_LOCATION);
> +      gphi *phip = create_phi_node (make_ssa_name (TREE_TYPE (limb_ptr)),
> +                                 e->dest);
> +      add_phi_arg (phip, limb_ptr, e, UNKNOWN_LOCATION);
> +
> +      m_gsi = gsi_after_labels (edge_large->src);
> +      tree ndiv = make_ssa_name (sizetype);
> +      tree nmod = make_ssa_name (sizetype);
> +      int p = MAX (TYPE_PRECISION (limb_type), limb_prec);
> +      gimple *g;
> +      if (pow2p_hwi (p))
> +     {
> +       g = gimple_build_assign (ndiv, RSHIFT_EXPR, n,
> +                                build_int_cst (unsigned_type_node,
> +                                               exact_log2 (p)));
> +       insert_before (g);
> +       g = gimple_build_assign (nmod, BIT_AND_EXPR, n, size_int (p - 1));
> +       insert_before (g);
> +     }
> +      else
> +     {
> +       g = gimple_build_assign (ndiv, TRUNC_DIV_EXPR, n, size_int (p));
> +       insert_before (g);
> +       g = gimple_build_assign (nmod, TRUNC_MOD_EXPR, n, size_int (p));
> +       insert_before (g);
> +     }
> +      g = gimple_build_assign (make_ssa_name (boolean_type_node),
> +                            EQ_EXPR, nmod, size_zero_node);
> +      insert_before (g);
> +      g = gimple_build_assign (make_ssa_name (sizetype), NOP_EXPR,
> +                            gimple_assign_lhs (g));
> +      insert_before (g);
> +      tree ndivm = make_ssa_name (sizetype);
> +      g = gimple_build_assign (ndivm, MINUS_EXPR, ndiv, gimple_assign_lhs 
> (g));
> +      insert_before (g);
> +      tree ndiv2 = NULL_TREE, nmod2 = NULL_TREE, ndivm2 = NULL_TREE;
> +      if (TYPE_PRECISION (limb_type) < limb_prec)
> +     {
> +       ndiv2 = make_ssa_name (sizetype);
> +       nmod2 = make_ssa_name (sizetype);
> +       p = TYPE_PRECISION (limb_type);
> +       if (pow2p_hwi (p))
> +         {
> +           g = gimple_build_assign (ndiv2, RSHIFT_EXPR, n,
> +                                    build_int_cst (unsigned_type_node,
> +                                                   exact_log2 (p)));
> +           insert_before (g);
> +           g = gimple_build_assign (nmod2, BIT_AND_EXPR, n,
> +                                    size_int (p - 1));
> +           insert_before (g);
> +         }
> +       else
> +         {
> +           g = gimple_build_assign (ndiv2, TRUNC_DIV_EXPR, n, size_int (p));
> +           insert_before (g);
> +           g = gimple_build_assign (nmod2, TRUNC_MOD_EXPR, n, size_int (p));
> +           insert_before (g);
> +         }
> +       g = gimple_build_assign (make_ssa_name (boolean_type_node),
> +                                EQ_EXPR, nmod2, size_zero_node);
> +       insert_before (g);
> +       g = gimple_build_assign (make_ssa_name (sizetype), NOP_EXPR,
> +                                gimple_assign_lhs (g));
> +       insert_before (g);
> +       g = gimple_build_assign (make_ssa_name (sizetype), MINUS_EXPR,
> +                                ndiv2, gimple_assign_lhs (g));
> +       insert_before (g);
> +       ndivm2 = make_ssa_name (sizetype);
> +       add_mult (ndivm2, gimple_assign_lhs (g),
> +                 tree_to_uhwi (TYPE_SIZE_UNIT (limb_type)));
> +     }
> +      tree idx_next;
> +      tree idx = create_loop (size_zero_node, &idx_next);
> +      tree t;
> +      if (bitint_big_endian)
> +     {
> +       g = gimple_build_assign (make_ssa_name (sizetype),
> +                                MINUS_EXPR, ndivm, idx);
> +       insert_before (g);
> +       t = gimple_assign_lhs (g);
> +     }
> +      else
> +     t = idx;
> +      bool double_sz = TYPE_PRECISION (limb_type) > limb_prec;
> +      tree ptr = make_ssa_name (TREE_TYPE (bitint_ptr));
> +      g = add_mult (make_ssa_name (sizetype), t,
> +                 m_limb_size * (double_sz + 1));
> +      g = gimple_build_assign (ptr, POINTER_PLUS_EXPR, bitint_ptr,
> +                            gimple_assign_lhs (g));
> +      insert_before (g);
> +      tree mem = build2 (MEM_REF, m_limb_type, ptr,
> +                      build_int_cst (ptr_type_node, 0));
> +      g = gimple_build_assign (make_ssa_name (m_limb_type), mem);
> +      insert_before (g);
> +      auto_vec<tree, 16> parts;
> +      tree idxtimessize = NULL_TREE;
> +      if (TYPE_PRECISION (limb_type) >= limb_prec)
> +     {
> +       if (TYPE_PRECISION (limb_type) > limb_prec)
> +         {
> +           t = add_cast (limb_type, gimple_assign_lhs (g));
> +           mem = build2 (MEM_REF, m_limb_type, ptr,
> +                         build_int_cst (ptr_type_node,
> +                                        bitint_big_endian
> +                                        ? -m_limb_size : m_limb_size));
> +           g = gimple_build_assign (make_ssa_name (m_limb_type), mem);
> +           insert_before (g);
> +           tree t2 = add_cast (limb_type, gimple_assign_lhs (g));
> +           if (bitint_big_endian)
> +             std::swap (t, t2);
> +           g = gimple_build_assign (make_ssa_name (limb_type),
> +                                    LSHIFT_EXPR, t2,
> +                                    build_int_cst (unsigned_type_node,
> +                                                   limb_prec));
> +           insert_before (g);
> +           g = gimple_build_assign (make_ssa_name (limb_type),
> +                                    BIT_IOR_EXPR, t, gimple_assign_lhs (g));
> +           insert_before (g);
> +           parts.safe_push (gimple_assign_lhs (g));
> +         }
> +       else if (useless_type_conversion_p (limb_type, m_limb_type))
> +         parts.safe_push (gimple_assign_lhs (g));
> +       else
> +         parts.safe_push (add_cast (limb_type, gimple_assign_lhs (g)));
> +     }
> +      else
> +     {
> +       tree l = gimple_assign_lhs (g);
> +       parts.safe_push (add_cast (limb_type, l));
> +       for (p = TYPE_PRECISION (limb_type); p < limb_prec;
> +            p += TYPE_PRECISION (limb_type))
> +         {
> +           g = gimple_build_assign (make_ssa_name (m_limb_type),
> +                                    RSHIFT_EXPR, l,
> +                                    build_int_cst (unsigned_type_node, p));
> +           insert_before (g);
> +           parts.safe_push (add_cast (limb_type, gimple_assign_lhs (g)));
> +         }
> +       idxtimessize = make_ssa_name (sizetype);
> +       add_mult (idxtimessize, idx,
> +                 tree_to_uhwi (TYPE_SIZE_UNIT (limb_type))
> +                 * (limb_prec / TYPE_PRECISION (limb_type)));
> +     }
> +      if_then_else (gimple_build_cond (NE_EXPR, big_endian_p,
> +                                    boolean_false_node,
> +                                    NULL_TREE, NULL_TREE),
> +                 profile_probability::even (),
> +                 edge_small, edge_next);
> +      if (TYPE_PRECISION (limb_type) >= limb_prec)
> +     {
> +       g = gimple_build_assign (make_ssa_name (sizetype),
> +                                MINUS_EXPR, ndivm, idx);
> +       insert_before (g);
> +       tree tbe = gimple_assign_lhs (g);
> +       m_gsi = gsi_after_labels (edge_next->dest);
> +       gphi *phi = create_phi_node (make_ssa_name (sizetype),
> +                                    gsi_bb (m_gsi));
> +       add_phi_arg (phi, tbe, edge_small, UNKNOWN_LOCATION);
> +       add_phi_arg (phi, idx, edge_next, UNKNOWN_LOCATION);
> +       g = add_mult (make_ssa_name (sizetype), gimple_phi_result (phi),
> +                     tree_to_uhwi (TYPE_SIZE_UNIT (limb_type)));
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (limb_ptr)),
> +                                POINTER_PLUS_EXPR, limb_ptr,
> +                                gimple_assign_lhs (g));
> +       insert_before (g);
> +       mem = build2 (MEM_REF, limb_type, gimple_assign_lhs (g),
> +                     build_int_cst (limb_ptr_type, 0));
> +       g = gimple_build_assign (mem, parts[0]);
> +       insert_before (g);
> +     }
> +      else
> +     {
> +       g = gimple_build_assign (make_ssa_name (sizetype), MINUS_EXPR,
> +                                ndivm2, idxtimessize);
> +       insert_before (g);
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (limb_ptr)),
> +                                POINTER_PLUS_EXPR, limb_ptr,
> +                                gimple_assign_lhs (g));
> +       insert_before (g);
> +       tree base = gimple_assign_lhs (g);
> +       int sz = tree_to_uhwi (TYPE_SIZE_UNIT (limb_type));
> +       unsigned int j;
> +       FOR_EACH_VEC_ELT (parts, j, t)
> +         {
> +           mem = build2 (MEM_REF, limb_type, base,
> +                         build_int_cst (limb_ptr_type,
> +                                        (- (int) j) * sz));
> +           g = gimple_build_assign (mem, t);
> +           insert_before (g);
> +         }
> +       m_gsi = gsi_after_labels (edge_next->src);
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (limb_ptr)),
> +                                POINTER_PLUS_EXPR, limb_ptr,
> +                                idxtimessize);
> +       insert_before (g);
> +       base = gimple_assign_lhs (g);
> +       FOR_EACH_VEC_ELT (parts, j, t)
> +         {
> +           mem = build2 (MEM_REF, limb_type, base,
> +                         build_int_cst (limb_ptr_type, j * sz));
> +           g = gimple_build_assign (mem, t);
> +           insert_before (g);
> +         }
> +       m_gsi = gsi_after_labels (edge_next->dest);
> +     }
> +      g = gimple_build_assign (idx_next, PLUS_EXPR, idx, size_one_node);
> +      insert_before (g);
> +      g = gimple_build_cond (NE_EXPR, idx_next, ndiv, NULL_TREE,
> +                          NULL_TREE);
> +      insert_before (g);
> +
> +      m_gsi = gsi_after_labels (edge_large->src);
> +      if_then (gimple_build_cond (NE_EXPR, nmod, size_zero_node,
> +                               NULL_TREE, NULL_TREE),
> +            profile_probability::even (), edge_small, e);
> +      if (bitint_big_endian)
> +     t = bitint_ptr;
> +      else
> +     {
> +       g = add_mult (make_ssa_name (sizetype), ndivm,
> +                     m_limb_size * (double_sz + 1));
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (bitint_ptr)),
> +                                POINTER_PLUS_EXPR, bitint_ptr,
> +                                gimple_assign_lhs (g));
> +       insert_before (g);
> +       t = gimple_assign_lhs (g);
> +     }
> +      mem = build2 (MEM_REF, m_limb_type, t,
> +                 build_int_cst (ptr_type_node, 0));
> +      g = gimple_build_assign (make_ssa_name (m_limb_type), mem);
> +      insert_before (g);
> +      t = gimple_assign_lhs (g);
> +      if (double_sz)
> +     {
> +       t = add_cast (TREE_TYPE (v), t);
> +       if_then (gimple_build_cond (GT_EXPR, nmod, size_int (limb_prec),
> +                                   NULL_TREE, NULL_TREE),
> +                profile_probability::even (),
> +                edge_small, edge_next);
> +       mem = build2 (MEM_REF, m_limb_type, TREE_OPERAND (mem, 0),
> +                     build_int_cst (ptr_type_node, m_limb_size));
> +       g = gimple_build_assign (make_ssa_name (m_limb_type), mem);
> +       insert_before (g);
> +       tree t2 = add_cast (TREE_TYPE (v), gimple_assign_lhs (g));
> +       tree t3 = t;
> +       if (bitint_big_endian)
> +         std::swap (t2, t3);
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (v)),
> +                                LSHIFT_EXPR, t2,
> +                                build_int_cst (unsigned_type_node,
> +                                               limb_prec));
> +       insert_before (g);
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (v)),
> +                                BIT_IOR_EXPR, t3, gimple_assign_lhs (g));
> +       insert_before (g);
> +       gphi *phi = create_phi_node (make_ssa_name (TREE_TYPE (v)),
> +                                    edge_small->dest);
> +       add_phi_arg (phi, gimple_assign_lhs (g), edge_small,
> +                    UNKNOWN_LOCATION);
> +       add_phi_arg (phi, t, edge_next, UNKNOWN_LOCATION);
> +       t = gimple_phi_result (phi);
> +       m_gsi = gsi_after_labels (edge_next->dest);
> +     }
> +      else if (!useless_type_conversion_p (TREE_TYPE (v), m_limb_type))
> +     t = add_cast (TREE_TYPE (v), t);
> +      if_then_else (gimple_build_cond (NE_EXPR, big_endian_p,
> +                                    boolean_false_node,
> +                                    NULL_TREE, NULL_TREE),
> +                 profile_probability::even (),
> +                 edge_small, edge_next);
> +      m_gsi = gsi_after_labels (edge_next->src);
> +      p = tree_to_uhwi (TYPE_SIZE_UNIT (limb_type));
> +      if (TYPE_PRECISION (limb_type) < limb_prec)
> +     p *= limb_prec / TYPE_PRECISION (limb_type);
> +      g = add_mult (make_ssa_name (sizetype), ndiv, p);
> +      g = gimple_build_assign (make_ssa_name (TREE_TYPE (limb_ptr)),
> +                            POINTER_PLUS_EXPR, limb_ptr,
> +                            gimple_assign_lhs (g));
> +      insert_before (g);
> +      gphi *phip3 = create_phi_node (make_ssa_name (TREE_TYPE (limb_ptr)),
> +                                  edge_next->dest);
> +      add_phi_arg (phip3, limb_ptr, edge_small, UNKNOWN_LOCATION);
> +      add_phi_arg (phip3, gimple_assign_lhs (g), edge_next, 
> UNKNOWN_LOCATION);
> +      edge_next = single_succ_edge (edge_next->dest);
> +      gphi *phiv2 = create_phi_node (make_ssa_name (TREE_TYPE (v)), e->dest);
> +      add_phi_arg (phiv2, build_zero_cst (TREE_TYPE (v)), e, 
> UNKNOWN_LOCATION);
> +      add_phi_arg (phiv2, t, edge_next, UNKNOWN_LOCATION);
> +      gphi *phip2 = create_phi_node (make_ssa_name (TREE_TYPE (limb_ptr)),
> +                                  e->dest);
> +      add_phi_arg (phip2, limb_ptr, e, UNKNOWN_LOCATION);
> +      add_phi_arg (phip2, gimple_phi_result (phip3), edge_next,
> +                UNKNOWN_LOCATION);
> +
> +      add_phi_arg (phiv, gimple_phi_result (phiv2), edge_large,
> +                UNKNOWN_LOCATION);
> +      add_phi_arg (phin, nmod, edge_large, UNKNOWN_LOCATION);
> +      add_phi_arg (phip, gimple_phi_result (phip2), edge_large,
> +                UNKNOWN_LOCATION);
> +      m_gsi = gsi_after_labels (edge_large->dest);
> +      if_then (gimple_build_cond (NE_EXPR, gimple_phi_result (phin),
> +                               size_zero_node, NULL_TREE, NULL_TREE),
> +            profile_probability::even (), edge_small, e);
> +      if_then (gimple_build_cond (NE_EXPR, gimple_phi_result (phin),
> +                               size_int (TYPE_PRECISION (TREE_TYPE (v))),
> +                               NULL_TREE, NULL_TREE),
> +            profile_probability::even (), e, edge_large);
> +      tree shift = make_ssa_name (sizetype);
> +      g = gimple_build_assign (shift, MINUS_EXPR,
> +                            size_int (TYPE_PRECISION (TREE_TYPE (v))),
> +                            gimple_phi_result (phin));
> +      insert_before (g);
> +      if (!useless_type_conversion_p (unsigned_type_node, sizetype))
> +     shift = add_cast (unsigned_type_node, shift);
> +      v = make_ssa_name (TREE_TYPE (v));
> +      g = gimple_build_assign (v, LSHIFT_EXPR, gimple_phi_result (phiv),
> +                            shift);
> +      insert_before (g);
> +      if_then_else (gimple_build_cond (NE_EXPR, uns_p, boolean_false_node,
> +                                    NULL_TREE, NULL_TREE),
> +                 profile_probability::even (),
> +                 edge_next, e);
> +      g = gimple_build_assign (make_ssa_name (TREE_TYPE (v)), RSHIFT_EXPR,
> +                            v, shift);
> +      insert_before (g);
> +      gphi *phi = create_phi_node (make_ssa_name (TREE_TYPE (v)), e->dest);
> +      add_phi_arg (phi, gimple_assign_lhs (g), edge_next, UNKNOWN_LOCATION);
> +      m_gsi = gsi_after_labels (e->src);
> +      tree stype = signed_type_for (TREE_TYPE (v));
> +      g = gimple_build_assign (make_ssa_name (stype), RSHIFT_EXPR,
> +                            add_cast (stype, v), shift);
> +      insert_before (g);
> +      add_phi_arg (phi, add_cast (TREE_TYPE (v), gimple_assign_lhs (g)),
> +                e, UNKNOWN_LOCATION);
> +      gphi *phi2 = create_phi_node (make_ssa_name (TREE_TYPE (v)),
> +                                 edge_large->dest);
> +      add_phi_arg (phi2, gimple_phi_result (phiv), edge_large,
> +                UNKNOWN_LOCATION);
> +      add_phi_arg (phi2, gimple_phi_result (phi), single_succ_edge (e->dest),
> +                UNKNOWN_LOCATION);
> +      m_gsi = gsi_after_labels (edge_large->dest);
> +      t = gimple_phi_result (phi2);
> +      if (TYPE_PRECISION (limb_type) >= TYPE_PRECISION (TREE_TYPE (v)))
> +     {
> +       if (!useless_type_conversion_p (limb_type, TREE_TYPE (v)))
> +         t = add_cast (limb_type, t);
> +       mem = build2 (MEM_REF, limb_type, gimple_phi_result (phip),
> +                     build_int_cst (limb_ptr_type, 0));
> +       g = gimple_build_assign (mem, t);
> +       insert_before (g);
> +     }
> +      else
> +     {
> +       if_then_else (gimple_build_cond (NE_EXPR, big_endian_p,
> +                                        boolean_false_node, NULL_TREE,
> +                                        NULL_TREE),
> +                     profile_probability::even (),
> +                     edge_next, e);
> +       p = TYPE_PRECISION (limb_type);
> +       g = gimple_build_assign (make_ssa_name (sizetype), PLUS_EXPR,
> +                                gimple_phi_result (phin), size_int (p - 1));
> +       insert_before (g);
> +       if (pow2p_hwi (p))
> +         g = gimple_build_assign (make_ssa_name (sizetype), RSHIFT_EXPR,
> +                                  gimple_assign_lhs (g),
> +                                  build_int_cst (unsigned_type_node,
> +                                                 exact_log2 (p)));
> +       else
> +         g = gimple_build_assign (make_ssa_name (sizetype), TRUNC_DIV_EXPR,
> +                                  gimple_assign_lhs (g), size_int (p));
> +       insert_before (g);
> +       g = add_mult (make_ssa_name (sizetype), gimple_assign_lhs (g),
> +                     tree_to_uhwi (TYPE_SIZE_UNIT (limb_type)));
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (limb_ptr)),
> +                                POINTER_PLUS_EXPR, gimple_phi_result (phip),
> +                                gimple_assign_lhs (g));
> +       insert_before (g);
> +       idx = create_loop (size_zero_node, &idx_next);
> +       phi = create_phi_node (make_ssa_name (TREE_TYPE (limb_ptr)), m_bb);
> +       add_phi_arg (phi, gimple_assign_lhs (g),
> +                    find_edge (m_preheader_bb, m_bb), UNKNOWN_LOCATION);
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (v)),
> +                                RSHIFT_EXPR, t,
> +                                add_cast (unsigned_type_node, idx));
> +       insert_before (g);
> +       tree minuslimbsz
> +         = fold_unary (NEGATE_EXPR, sizetype, TYPE_SIZE_UNIT (limb_type));
> +       mem = build2 (MEM_REF, limb_type, gimple_phi_result (phi),
> +                     fold_convert (limb_ptr_type, minuslimbsz));
> +       g = gimple_build_assign (mem, add_cast (limb_type,
> +                                               gimple_assign_lhs (g)));
> +       insert_before (g);
> +       g = gimple_build_assign (idx_next, PLUS_EXPR, idx,
> +                                size_int (TYPE_PRECISION (limb_type)));
> +       insert_before (g);
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (limb_ptr)),
> +                                POINTER_PLUS_EXPR, gimple_phi_result (phi),
> +                                minuslimbsz);
> +       insert_before (g);
> +       add_phi_arg (phi, gimple_assign_lhs (g), find_edge (m_bb, m_bb),
> +                    UNKNOWN_LOCATION);
> +       g = gimple_build_cond (LT_EXPR, idx_next, gimple_phi_result (phin),
> +                              NULL_TREE, NULL_TREE);
> +       insert_before (g);
> +
> +       m_gsi = gsi_after_labels (e->src);
> +       idx = create_loop (size_zero_node, &idx_next);
> +       phi = create_phi_node (make_ssa_name (TREE_TYPE (limb_ptr)), m_bb);
> +       add_phi_arg (phi, gimple_phi_result (phip),
> +                    find_edge (m_preheader_bb, m_bb), UNKNOWN_LOCATION);
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (v)),
> +                                RSHIFT_EXPR, t,
> +                                add_cast (unsigned_type_node, idx));
> +       insert_before (g);
> +       mem = build2 (MEM_REF, limb_type, gimple_phi_result (phi),
> +                     build_int_cst (limb_ptr_type, 0));
> +       g = gimple_build_assign (mem, add_cast (limb_type,
> +                                               gimple_assign_lhs (g)));
> +       insert_before (g);
> +       g = gimple_build_assign (idx_next, PLUS_EXPR, idx,
> +                                size_int (TYPE_PRECISION (limb_type)));
> +       insert_before (g);
> +       g = gimple_build_assign (make_ssa_name (TREE_TYPE (limb_ptr)),
> +                                POINTER_PLUS_EXPR, gimple_phi_result (phi),
> +                                TYPE_SIZE_UNIT (limb_type));
> +       insert_before (g);
> +       add_phi_arg (phi, gimple_assign_lhs (g), find_edge (m_bb, m_bb),
> +                    UNKNOWN_LOCATION);
> +       g = gimple_build_cond (LT_EXPR, idx_next, gimple_phi_result (phin),
> +                              NULL_TREE, NULL_TREE);
> +       insert_before (g);
> +     }
> +    }
> +  else
> +    sorry_at (gimple_location (stmt),
> +           "%<__builtin_bitint_pack%> not supported yet");
> +  m_gsi = gsi_for_stmt (stmt);
> +  unlink_stmt_vdef (stmt);
> +  release_ssa_name (gimple_vdef (stmt));
> +  gsi_remove (&m_gsi, true);
> +}
> +
>  /* Lower a call statement with one or more large/huge _BitInt
>     arguments or large/huge _BitInt return value.  */
>  
> @@ -6320,6 +6921,12 @@ bitint_large_huge::lower_call (tree obj,
>        default:
>       break;
>        }
> +  if (gimple_call_builtin_p (stmt, BUILT_IN_BITINT_PACK)
> +      || gimple_call_builtin_p (stmt, BUILT_IN_BITINT_UNPACK))
> +    {
> +      lower_pack_unpack (stmt);
> +      return;
> +    }
>    bool returns_twice = (gimple_call_flags (stmt) & ECF_RETURNS_TWICE) != 0;
>    for (unsigned int i = 0; i < nargs; ++i)
>      {
> @@ -7274,7 +7881,7 @@ gimple_lower_bitint (void)
>           }
>       }
>      }
> -  if (i == num_ssa_names)
> +  if (i == num_ssa_names && !cfun->has_bitint_pack)
>      return 0;
>  
>    basic_block bb;
> @@ -7973,8 +8580,20 @@ gimple_lower_bitint (void)
>       }
>      }
>  
> -  if (large_huge.m_names || has_large_huge)
> +  if (large_huge.m_names || has_large_huge || cfun->has_bitint_pack)
>      {
> +      if (cfun->has_bitint_pack && !limb_prec)
> +     {
> +       struct bitint_info info;
> +       for (int i = 64; i < WIDE_INT_MAX_PRECISION - 1; i *= 2)
> +         {
> +           if (!targetm.c.bitint_type_info (i, &info))
> +             return 0;
> +           if (bitint_precision_kind (i) >= bitint_prec_large)
> +             break;
> +         }
> +       gcc_assert (limb_prec);
> +     }
>        ret = TODO_update_ssa_only_virtuals | TODO_cleanup_cfg;
>        calculate_dominance_info (CDI_DOMINATORS);
>        if (optimize)
> @@ -8112,6 +8731,9 @@ gimple_lower_bitint (void)
>                     kind = MAX (kind, this_kind);
>                   }
>               }
> +           if (gimple_call_builtin_p (stmt, BUILT_IN_BITINT_PACK)
> +               || gimple_call_builtin_p (stmt, BUILT_IN_BITINT_UNPACK))
> +             kind = bitint_prec_large;
>           }
>         if (kind == bitint_prec_small)
>           continue;
> @@ -8453,7 +9075,7 @@ gimple_lower_bitint (void)
>       }
>      }
>  
> -  if (large_huge.m_names || has_large_huge)
> +  if (large_huge.m_names || has_large_huge || cfun->has_bitint_pack)
>      {
>        gimple *nop = NULL;
>        for (i = 0; i < num_ssa_names; ++i)
> --- gcc/lto-streamer-in.cc.jj 2026-07-03 20:39:18.995958477 +0200
> +++ gcc/lto-streamer-in.cc    2026-07-04 09:55:05.400650265 +0200
> @@ -1329,6 +1329,7 @@ input_struct_function_base (struct funct
>    fn->has_musttail = bp_unpack_value (&bp, 1);
>    fn->has_unroll = bp_unpack_value (&bp, 1);
>    fn->assume_function = bp_unpack_value (&bp, 1);
> +  fn->has_bitint_pack = bp_unpack_value (&bp, 1);
>    fn->va_list_fpr_size = bp_unpack_value (&bp, 8);
>    fn->va_list_gpr_size = bp_unpack_value (&bp, 8);
>    fn->last_clique = bp_unpack_value (&bp, sizeof (short) * 8);
> --- gcc/lto-streamer-out.cc.jj        2026-07-03 20:39:18.995958477 +0200
> +++ gcc/lto-streamer-out.cc   2026-07-04 09:55:05.400960499 +0200
> @@ -2319,6 +2319,7 @@ output_struct_function_base (struct outp
>    bp_pack_value (&bp, fn->has_musttail, 1);
>    bp_pack_value (&bp, fn->has_unroll, 1);
>    bp_pack_value (&bp, fn->assume_function, 1);
> +  bp_pack_value (&bp, fn->has_bitint_pack, 1);
>    bp_pack_value (&bp, fn->va_list_fpr_size, 8);
>    bp_pack_value (&bp, fn->va_list_gpr_size, 8);
>    bp_pack_value (&bp, fn->last_clique, sizeof (short) * 8);
> --- gcc/config/i386/i386.cc.jj        2026-07-04 09:52:04.479188874 +0200
> +++ gcc/config/i386/i386.cc   2026-07-04 09:55:05.390728140 +0200
> @@ -5271,6 +5271,83 @@ ix86_gimplify_va_arg (tree valist, tree
>      addr = build_va_arg_indirect_ref (addr);
>    return build_va_arg_indirect_ref (addr);
>  }
> +
> +/* Implement __builtin_va_arg_bitint.  */
> +
> +static tree
> +ix86_gimplify_va_arg_bitint (tree valist, tree n, gimple_seq *pre_p,
> +                          gimple_seq *post_p)
> +{
> +  /* Only 64bit target needs something special.  */
> +  if (is_va_list_char_pointer (TREE_TYPE (valist)))
> +    return std_gimplify_va_arg_bitint (valist, n, pre_p, post_p);
> +
> +  tree f_gpr = TYPE_FIELDS (TREE_TYPE (sysv_va_list_type_node));
> +  tree f_fpr = DECL_CHAIN (f_gpr);
> +  tree f_ovf = DECL_CHAIN (f_fpr);
> +
> +  tree ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf,
> +                  NULL_TREE);
> +
> +  tree ptr = create_tmp_var (const_ptr_type_node, "bitint_ptr");
> +  tree labend = create_artificial_label (input_location);
> +  for (int i = BITS_PER_UNIT; i <= BITS_PER_WORD * 2; i <<= 1)
> +    {
> +      tree type = build_bitint_type (i, 1);
> +      gimple_seq post_seq = NULL;
> +      tree labtrue = create_artificial_label (input_location);
> +      tree labfalse = create_artificial_label (input_location);
> +      gcond *cond_stmt
> +     = gimple_build_cond (LE_EXPR, n,
> +                          build_int_cst (TREE_TYPE (n), i),
> +                          labtrue, labfalse);
> +      gimple_seq_add_stmt (pre_p, cond_stmt);
> +      gimple_seq_add_stmt (pre_p, gimple_build_label (labtrue));
> +      tree mem_ref
> +     = ix86_gimplify_va_arg (unshare_expr (valist), type, pre_p, &post_seq);
> +      gcc_assert (TREE_CODE (mem_ref) == MEM_REF);
> +      gimplify_assign (ptr, build_fold_addr_expr (mem_ref), pre_p);
> +      if (post_seq)
> +     gimple_seq_add_seq (pre_p, post_seq);
> +      gimple_seq_add_stmt (pre_p, gimple_build_goto (labend));
> +      gimple_seq_add_stmt (pre_p, gimple_build_label (labfalse));
> +    }
> +
> +  tree type = build_bitint_type (BITS_PER_WORD * 4, 1);
> +  bool indirect_p = pass_va_arg_by_reference (type);
> +  int size = 0, rsize = 0;
> +  tree type_size = NULL_TREE;
> +  if (indirect_p)
> +    {
> +      type = build_pointer_type (type);
> +      size = arg_int_size_in_bytes (type);
> +      rsize = CEIL (size, UNITS_PER_WORD);
> +    }
> +  else
> +    {
> +      tree t = fold_convert (sizetype, n);
> +      t = size_binop (PLUS_EXPR, t, size_int (BITS_PER_WORD - 1));
> +      t = size_binop (TRUNC_DIV_EXPR, t, size_int (BITS_PER_WORD));
> +      type_size = size_binop (MULT_EXPR, t,
> +                           size_int (UNITS_PER_WORD));
> +    }
> +
> +  tree t = ovf;
> +  gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
> +  if (indirect_p)
> +    gimplify_assign (ptr, build_va_arg_indirect_ref (t), pre_p);
> +  else
> +    gimplify_assign (ptr, t, pre_p);
> +
> +  if (indirect_p)
> +    t = fold_build_pointer_plus_hwi (t, rsize * UNITS_PER_WORD);
> +  else
> +    t = fold_build_pointer_plus (t, type_size);
> +  gimplify_assign (unshare_expr (ovf), t, pre_p);
> +
> +  gimple_seq_add_stmt (pre_p, gimple_build_label (labend));
> +  return ptr;
> +}
>  
>  /* Return true if OPNUM's MEM should be matched
>     in movabs* patterns.  */
> @@ -28586,6 +28663,9 @@ static const scoped_attribute_specs *con
>  #undef TARGET_GIMPLIFY_VA_ARG_EXPR
>  #define TARGET_GIMPLIFY_VA_ARG_EXPR ix86_gimplify_va_arg
>  
> +#undef TARGET_GIMPLIFY_VA_ARG_BITINT
> +#define TARGET_GIMPLIFY_VA_ARG_BITINT ix86_gimplify_va_arg_bitint
> +
>  #undef TARGET_SCALAR_MODE_SUPPORTED_P
>  #define TARGET_SCALAR_MODE_SUPPORTED_P ix86_scalar_mode_supported_p
>  
> --- gcc/c-family/c-common.cc.jj       2026-07-03 20:39:18.977958696 +0200
> +++ gcc/c-family/c-common.cc  2026-07-04 09:55:05.388954104 +0200
> @@ -6972,6 +6972,103 @@ check_builtin_function_arguments (locati
>       }
>        return true;
>  
> +    case BUILT_IN_VA_ARG_BITINT:
> +    case BUILT_IN_BITINT_UNPACK:
> +    case BUILT_IN_BITINT_PACK:
> +      if (!builtin_function_validate_nargs (loc, fndecl, nargs, 5, complain))
> +     return false;
> +      if (!INTEGRAL_TYPE_P (TREE_TYPE (args[1])))
> +     {
> +       if (complain)
> +         error_at (ARG_LOCATION (1),
> +                   "argument %u in call to function "
> +                   "%qE does not have integral type",
> +                   2, fndecl);
> +       return false;
> +     }
> +      if (TREE_CODE (TREE_TYPE (args[2])) != POINTER_TYPE)
> +     {
> +       if (complain)
> +         error_at (ARG_LOCATION (2),
> +                   "argument %u in call to function "
> +                   "%qE does not have pointer type",
> +                   3, fndecl);
> +       return false;
> +     }
> +      if (TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) != INTEGER_TYPE)
> +     {
> +       if (complain)
> +         error_at (ARG_LOCATION (2),
> +                   "argument %u in call to function "
> +                   "%qE does not have pointer to integer type",
> +                   3, fndecl);
> +       return false;
> +     }
> +      if (DECL_FUNCTION_CODE (fndecl) != BUILT_IN_BITINT_PACK
> +       && TYPE_READONLY (TREE_TYPE (TREE_TYPE (args[2]))))
> +     {
> +       if (complain)
> +         error_at (ARG_LOCATION (2),
> +                   "argument %u in call to function "
> +                   "%qE is a pointer to %<const%> integer type",
> +                   3, fndecl);
> +       return false;
> +     }
> +      if (!INTEGRAL_TYPE_P (TREE_TYPE (args[3])))
> +     {
> +       if (complain)
> +         error_at (ARG_LOCATION (3),
> +                   "argument %u in call to function "
> +                   "%qE does not have integral type",
> +                   4, fndecl);
> +       return false;
> +     }
> +      if (!INTEGRAL_TYPE_P (TREE_TYPE (args[4])))
> +     {
> +       if (complain)
> +         error_at (ARG_LOCATION (4),
> +                   "argument %u in call to function "
> +                   "%qE does not have integral type",
> +                   5, fndecl);
> +       return false;
> +     }
> +      args[1] = fold_convert (sizetype, args[1]);
> +      if (TREE_CODE (TREE_TYPE (args[3])) != BOOLEAN_TYPE)
> +     {
> +       if (TREE_CODE (args[3]) == INTEGER_CST)
> +         args[3] = constant_boolean_node (integer_nonzerop (args[3]),
> +                                          boolean_type_node);
> +       else
> +         args[3] = build2 (NE_EXPR, boolean_type_node,
> +                           args[3], build_zero_cst (TREE_TYPE (args[3])));
> +     }
> +      if (TREE_CODE (TREE_TYPE (args[4])) != BOOLEAN_TYPE)
> +     {
> +       if (TREE_CODE (args[4]) == INTEGER_CST)
> +         args[4] = constant_boolean_node (integer_nonzerop (args[4]),
> +                                          boolean_type_node);
> +       else
> +         args[4] = build2 (NE_EXPR, boolean_type_node,
> +                           args[4], build_zero_cst (TREE_TYPE (args[4])));
> +     }
> +      {
> +     if (c_dialect_cxx ())
> +       {
> +         sorry_at (loc, "%qD used when %<_BitInt(N)%> is not supported "
> +                        "in C++", fndecl);
> +         return false;
> +       }
> +     struct bitint_info info;
> +     if (!targetm.c.bitint_type_info (256, &info))
> +       {
> +         sorry_at (loc, "%qD used when %<_BitInt(N)%> is not supported "
> +                        "on this target", fndecl);
> +         return false;
> +       }
> +      }
> +
> +      return true;
> +
>      default:
>        return true;
>      }
> --- gcc/testsuite/gcc.dg/bitint-138.c.jj      2026-07-04 09:55:05.394614638 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-138.c 2026-07-04 16:56:27.065444577 +0200
> @@ -0,0 +1,219 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdarg.h>
> +
> +#ifndef T
> +#define T long
> +#endif
> +
> +[[gnu::noipa]] void
> +foo (va_list *ap, int n, unsigned T *p, bool e, bool u)
> +{
> +  __builtin_va_arg_bitint (*ap, n, p, e, u);
> +}
> +
> +#if __BITINT_MAXWIDTH__ >= 837
> +#define W (sizeof (T) * __CHAR_BIT__)
> +
> +[[gnu::noipa]] _BitInt(837)
> +bar (int n, ...)
> +{
> +  va_list ap;
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  va_start (ap);
> +  a[(n + W - 1) / W] = 42;
> +  foo (&ap, n, a, false, true);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  if (va_arg (ap, int) != 42)
> +    __builtin_abort ();
> +  va_end (ap);
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[j]) << i;
> +  return r;
> +}
> +
> +[[gnu::noipa]] _BitInt(837)
> +baz (int n, ...)
> +{
> +  va_list ap;
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  va_start (ap);
> +  a[(n + W - 1) / W] = 42;
> +  foo (&ap, n, a, true, true);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  if (va_arg (ap, int) != 42)
> +    __builtin_abort ();
> +  va_end (ap);
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[(n + W - 1) / W - 1 - j]) << i;
> +  return r;
> +}
> +#endif
> +
> +[[gnu::noipa]] void
> +qux (void *b, int n, unsigned T *p, bool e, bool u)
> +{
> +  __builtin_bitint_unpack (b, n, p, e, u);
> +}
> +
> +#if __BITINT_MAXWIDTH__ >= 837
> +[[gnu::noipa]] _BitInt(837)
> +corge (int n, void *b)
> +{
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  a[(n + W - 1) / W] = 42;
> +  qux (b, n, a, false, true);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[j]) << i;
> +  return r;
> +}
> +
> +[[gnu::noipa]] _BitInt(837)
> +garply (int n, void *b)
> +{
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  a[(n + W - 1) / W] = 42;
> +  qux (b, n, a, true, true);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[(n + W - 1) / W - 1 - j]) << i;
> +  return r;
> +}
> +#endif
> +
> +int
> +main ()
> +{
> +#if __BITINT_MAXWIDTH__ >= 837
> +  if (bar (1, 0uwb, 42) != 0uwb)
> +    __builtin_abort ();
> +  if (bar (1, 1uwb, 42) != 1uwb)
> +    __builtin_abort ();
> +  if (bar (5, 19uwb, 42) != 19uwb)
> +    __builtin_abort ();
> +  if (bar (8, 206uwb, 42) != 206uwb)
> +    __builtin_abort ();
> +  if (bar (13, 7570uwb, 42) != 7570uwb)
> +    __builtin_abort ();
> +  if (bar (16, 38151uwb, 42) != 38151uwb)
> +    __builtin_abort ();
> +  if (bar (27, 85311871uwb, 42) != 85311871uwb)
> +    __builtin_abort ();
> +  if (bar (32, 2918365024uwb, 42) != 2918365024uwb)
> +    __builtin_abort ();
> +  if (bar (52, 2418319599906367uwb, 42) != 2418319599906367uwb)
> +    __builtin_abort ();
> +  if (bar (64, 10324453899960610638uwb, 42) != 10324453899960610638uwb)
> +    __builtin_abort ();
> +  if (bar (115, 35493143902794610347964586515544041uwb, 42)
> +      != 35493143902794610347964586515544041uwb)
> +    __builtin_abort ();
> +  if (bar (128, 242619899432347503858857658506928415851uwb, 42)
> +      != 242619899432347503858857658506928415851uwb)
> +    __builtin_abort ();
> +  if (bar (526, 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb,
>  42)
> +      != 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb)
> +    __builtin_abort ();
> +  if (bar (817, 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb,
>  42)
> +      != 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb)
> +    __builtin_abort ();
> +  if (bar (832, 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb,
>  42)
> +      != 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb)
> +    __builtin_abort ();
> +  if (baz (1, 0uwb, 42) != 0uwb)
> +    __builtin_abort ();
> +  if (baz (1, 1uwb, 42) != 1uwb)
> +    __builtin_abort ();
> +  if (baz (5, 19uwb, 42) != 19uwb)
> +    __builtin_abort ();
> +  if (baz (8, 206uwb, 42) != 206uwb)
> +    __builtin_abort ();
> +  if (baz (13, 7570uwb, 42) != 7570uwb)
> +    __builtin_abort ();
> +  if (baz (16, 38151uwb, 42) != 38151uwb)
> +    __builtin_abort ();
> +  if (baz (27, 85311871uwb, 42) != 85311871uwb)
> +    __builtin_abort ();
> +  if (baz (32, 2918365024uwb, 42) != 2918365024uwb)
> +    __builtin_abort ();
> +  if (baz (52, 2418319599906367uwb, 42) != 2418319599906367uwb)
> +    __builtin_abort ();
> +  if (baz (64, 10324453899960610638uwb, 42) != 10324453899960610638uwb)
> +    __builtin_abort ();
> +  if (baz (115, 35493143902794610347964586515544041uwb, 42)
> +      != 35493143902794610347964586515544041uwb)
> +    __builtin_abort ();
> +  if (baz (128, 242619899432347503858857658506928415851uwb, 42)
> +      != 242619899432347503858857658506928415851uwb)
> +    __builtin_abort ();
> +  if (baz (526, 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb,
>  42)
> +      != 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb)
> +    __builtin_abort ();
> +  if (baz (817, 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb,
>  42)
> +      != 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb)
> +    __builtin_abort ();
> +  if (baz (832, 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb,
>  42)
> +      != 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb)
> +    __builtin_abort ();
> +#define corge(n, v) \
> +  do                                 \
> +    {                                        \
> +      unsigned _BitInt(n) w = v;     \
> +      if ((corge) (n, &w) != v)              \
> +     __builtin_abort ();             \
> +    }                                        \
> +  while (0)
> +#define garply(n, v) \
> +  do                                 \
> +    {                                        \
> +      unsigned _BitInt(n) w = v;     \
> +      if ((garply) (n, &w) != v)     \
> +     __builtin_abort ();             \
> +    }                                        \
> +  while (0)
> +  corge (1, 0uwb);
> +  corge (1, 1uwb);
> +  corge (5, 19uwb);
> +  corge (8, 206uwb);
> +  corge (13, 7570uwb);
> +  corge (16, 38151uwb);
> +  corge (27, 85311871uwb);
> +  corge (32, 2918365024uwb);
> +  corge (52, 2418319599906367uwb);
> +  corge (64, 10324453899960610638uwb);
> +  corge (115, 35493143902794610347964586515544041uwb);
> +  corge (128, 242619899432347503858857658506928415851uwb);
> +  corge (526, 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb);
> +  corge (817, 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb);
> +  corge (832, 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb);
> +  garply (1, 0uwb);
> +  garply (1, 1uwb);
> +  garply (5, 19uwb);
> +  garply (8, 206uwb);
> +  garply (13, 7570uwb);
> +  garply (16, 38151uwb);
> +  garply (27, 85311871uwb);
> +  garply (32, 2918365024uwb);
> +  garply (52, 2418319599906367uwb);
> +  garply (64, 10324453899960610638uwb);
> +  garply (115, 35493143902794610347964586515544041uwb);
> +  garply (128, 242619899432347503858857658506928415851uwb);
> +  garply (526, 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb);
> +  garply (817, 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb);
> +  garply (832, 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb);
> +#endif
> +}
> --- gcc/testsuite/gcc.dg/bitint-139.c.jj      2026-07-04 14:04:26.330909315 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-139.c 2026-07-04 16:55:49.494939690 +0200
> @@ -0,0 +1,227 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-std=c2y -O2" } */
> +
> +#include <stdarg.h>
> +
> +#ifndef T
> +#define T long
> +#endif
> +
> +[[gnu::noipa]] void
> +foo (va_list *ap, int n, unsigned T *p, bool e, bool u)
> +{
> +  __builtin_va_arg_bitint (*ap, n, p, e, u);
> +}
> +
> +#if __BITINT_MAXWIDTH__ >= 837
> +#define W (sizeof (T) * __CHAR_BIT__)
> +
> +[[gnu::noipa]] _BitInt(837)
> +bar (int n, ...)
> +{
> +  va_list ap;
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  va_start (ap);
> +  a[(n + W - 1) / W] = 42;
> +  foo (&ap, n, a, false, false);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  if (va_arg (ap, int) != 42)
> +    __builtin_abort ();
> +  va_end (ap);
> +  _BitInt(837) r = 0;
> +  int i = 0, j;
> +  for (j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[j]) << i;
> +  if ((signed T) a[j - 1] < 0)
> +    r += ((_BitInt(837)) -1) << i;
> +  return r;
> +}
> +
> +[[gnu::noipa]] _BitInt(837)
> +baz (int n, ...)
> +{
> +  va_list ap;
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  va_start (ap);
> +  a[(n + W - 1) / W] = 42;
> +  foo (&ap, n, a, true, false);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  if (va_arg (ap, int) != 42)
> +    __builtin_abort ();
> +  va_end (ap);
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[(n + W - 1) / W - 1 - j]) << i;
> +  if ((signed T) a[0] < 0)
> +    r += ((_BitInt(837)) -1) << i;
> +  return r;
> +}
> +#endif
> +
> +[[gnu::noipa]] void
> +qux (void *b, int n, unsigned T *p, bool e, bool u)
> +{
> +  __builtin_bitint_unpack (b, n, p, e, u);
> +}
> +
> +#if __BITINT_MAXWIDTH__ >= 837
> +[[gnu::noipa]] _BitInt(837)
> +corge (int n, void *b)
> +{
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  a[(n + W - 1) / W] = 42;
> +  qux (b, n, a, false, false);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  _BitInt(837) r = 0;
> +  int i = 0, j;
> +  for (j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[j]) << i;
> +  if ((signed T) a[j - 1] < 0)
> +    r += ((_BitInt(837)) -1) << i;
> +  return r;
> +}
> +
> +[[gnu::noipa]] _BitInt(837)
> +garply (int n, void *b)
> +{
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  a[(n + W - 1) / W] = 42;
> +  qux (b, n, a, true, false);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[(n + W - 1) / W - 1 - j]) << i;
> +  if ((signed T) a[0] < 0)
> +    r += ((_BitInt(837)) -1) << i;
> +  return r;
> +}
> +#endif
> +
> +int
> +main ()
> +{
> +#if __BITINT_MAXWIDTH__ >= 837
> +  if (bar (1, 0wb, 42) != 0wb)
> +    __builtin_abort ();
> +  if (bar (1, (_BitInt(1)) -1wb, 42) != -1)
> +    __builtin_abort ();
> +  if (bar (5, -12wb, 42) != -12wb)
> +    __builtin_abort ();
> +  if (bar (8, 107wb, 42) != 107wb)
> +    __builtin_abort ();
> +  if (bar (13, -3412wb, 42) != -3412wb)
> +    __builtin_abort ();
> +  if (bar (16, 24476wb, 42) != 24476wb)
> +    __builtin_abort ();
> +  if (bar (27, 62759870wb, 42) != 62759870wb)
> +    __builtin_abort ();
> +  if (bar (32, -1940906384wb, 42) != -1940906384wb)
> +    __builtin_abort ();
> +  if (bar (52, 1858183038390462wb, 42) != 1858183038390462wb)
> +    __builtin_abort ();
> +  if (bar (64, -8256680225559468133wb, 42) != -8256680225559468133wb)
> +    __builtin_abort ();
> +  if (bar (115, -19567690694941323284865986666034440wb, 42)
> +      != -19567690694941323284865986666034440wb)
> +    __builtin_abort ();
> +  if (bar (128, 161295407943090171995441423582245738873wb, 42)
> +      != 161295407943090171995441423582245738873wb)
> +    __builtin_abort ();
> +  if (bar (526, 
> -74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb,
>  42)
> +      != 
> -74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb)
> +    __builtin_abort ();
> +  if (bar (817, 
> 334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb,
>  42)
> +      != 
> 334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb)
> +    __builtin_abort ();
> +  if (bar (832, 
> -10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb,
>  42)
> +      != 
> -10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb)
> +    __builtin_abort ();
> +  if (baz (1, 0wb, 42) != 0wb)
> +    __builtin_abort ();
> +  if (baz (1, (_BitInt(1)) -1wb, 42) != -1)
> +    __builtin_abort ();
> +  if (baz (5, 12wb, 42) != 12wb)
> +    __builtin_abort ();
> +  if (baz (8, -107wb, 42) != -107wb)
> +    __builtin_abort ();
> +  if (baz (13, 3412wb, 42) != 3412wb)
> +    __builtin_abort ();
> +  if (baz (16, -24476wb, 42) != -24476wb)
> +    __builtin_abort ();
> +  if (baz (27, -62759870wb, 42) != -62759870wb)
> +    __builtin_abort ();
> +  if (baz (32, 1940906384wb, 42) != 1940906384wb)
> +    __builtin_abort ();
> +  if (baz (52, -1858183038390462wb, 42) != -1858183038390462wb)
> +    __builtin_abort ();
> +  if (baz (64, 8256680225559468133wb, 42) != 8256680225559468133wb)
> +    __builtin_abort ();
> +  if (baz (115, 19567690694941323284865986666034440wb, 42)
> +      != 19567690694941323284865986666034440wb)
> +    __builtin_abort ();
> +  if (baz (128, -161295407943090171995441423582245738873wb, 42)
> +      != -161295407943090171995441423582245738873wb)
> +    __builtin_abort ();
> +  if (baz (526, 
> 74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb,
>  42)
> +      != 
> 74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb)
> +    __builtin_abort ();
> +  if (baz (817, 
> -334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb,
>  42)
> +      != 
> -334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb)
> +    __builtin_abort ();
> +  if (baz (832, 
> 10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb,
>  42)
> +      != 
> 10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb)
> +    __builtin_abort ();
> +#define corge(n, v) \
> +  do                                 \
> +    {                                        \
> +      unsigned _BitInt(n) w = v;     \
> +      if ((corge) (n, &w) != v)              \
> +     __builtin_abort ();             \
> +    }                                        \
> +  while (0)
> +#define garply(n, v) \
> +  do                                 \
> +    {                                        \
> +      unsigned _BitInt(n) w = v;     \
> +      if ((garply) (n, &w) != v)     \
> +     __builtin_abort ();             \
> +    }                                        \
> +  while (0)
> +  corge (1, 0wb);
> +  corge (1, (_BitInt(1)) -1wb);
> +  corge (5, -12wb);
> +  corge (8, 107wb);
> +  corge (13, -3412wb);
> +  corge (16, 24476wb);
> +  corge (27, 62759870wb);
> +  corge (32, -1940906384wb);
> +  corge (52, 1858183038390462wb);
> +  corge (64, -8256680225559468133wb);
> +  corge (115, -19567690694941323284865986666034440wb);
> +  corge (128, 161295407943090171995441423582245738873wb);
> +  corge (526, 
> -74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb);
> +  corge (817, 
> 334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb);
> +  corge (832, 
> -10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb);
> +  garply (1, 0wb);
> +  garply (1, (_BitInt(1)) -1wb);
> +  garply (5, 12wb);
> +  garply (8, -107wb);
> +  garply (13, 3412wb);
> +  garply (16, -24476wb);
> +  garply (27, -62759870wb);
> +  garply (32, 1940906384wb);
> +  garply (52, -1858183038390462wb);
> +  garply (64, 8256680225559468133wb);
> +  garply (115, 19567690694941323284865986666034440wb);
> +  garply (128, -161295407943090171995441423582245738873wb);
> +  garply (526, 
> 74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb);
> +  garply (817, 
> -334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb);
> +  garply (832, 
> 10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb);
> +#endif
> +}
> --- gcc/testsuite/gcc.dg/bitint-140.c.jj      2026-07-04 16:53:11.388023264 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-140.c 2026-07-04 16:56:53.846091756 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T short
> +#include "bitint-138.c"
> --- gcc/testsuite/gcc.dg/bitint-141.c.jj      2026-07-06 10:09:51.894338823 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-141.c 2026-07-06 10:10:04.340173989 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-std=c2y -O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T short
> +#include "bitint-139.c"
> --- gcc/testsuite/gcc.dg/bitint-142.c.jj      2026-07-06 10:10:18.141991203 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-142.c 2026-07-06 10:10:32.242804452 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T char
> +#include "bitint-138.c"
> --- gcc/testsuite/gcc.dg/bitint-143.c.jj      2026-07-06 10:10:20.974953681 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-143.c 2026-07-06 10:10:41.418682930 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-std=c2y -O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T char
> +#include "bitint-139.c"
> --- gcc/testsuite/gcc.dg/bitint-144.c.jj      2026-07-06 10:10:58.889451547 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-144.c 2026-07-06 10:11:08.401325574 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T int
> +#include "bitint-138.c"
> --- gcc/testsuite/gcc.dg/bitint-145.c.jj      2026-07-06 10:11:01.735413856 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-145.c 2026-07-06 10:11:14.146249489 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-std=c2y -O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T int
> +#include "bitint-139.c"
> --- gcc/testsuite/gcc.dg/bitint-146.c.jj      2026-07-06 10:11:26.324088210 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-146.c 2026-07-06 10:11:40.595899197 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T long long
> +#include "bitint-138.c"
> --- gcc/testsuite/gcc.dg/bitint-147.c.jj      2026-07-06 10:11:29.116051233 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-147.c 2026-07-06 10:11:51.268757848 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-std=c2y -O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T long long
> +#include "bitint-139.c"
> --- gcc/testsuite/gcc.dg/bitint-148.c.jj      2026-07-06 10:11:59.170653195 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-148.c 2026-07-06 10:12:19.071389631 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target { bitint && int128 } } } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T __int128
> +#include "bitint-138.c"
> --- gcc/testsuite/gcc.dg/bitint-149.c.jj      2026-07-06 10:12:06.143560848 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-149.c 2026-07-06 10:18:58.203104785 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target { bitint && int128 } } } */
> +/* { dg-options "-std=gnu2y -O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T __int128
> +#include "bitint-139.c"
> --- gcc/testsuite/gcc.dg/bitint-150.c.jj      2026-07-06 13:18:24.085344012 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-150.c 2026-07-06 13:19:43.870298114 +0200
> @@ -0,0 +1,207 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdarg.h>
> +
> +#ifndef T
> +#define T long
> +#endif
> +
> +#if __BITINT_MAXWIDTH__ >= 837
> +#define W (sizeof (T) * __CHAR_BIT__)
> +
> +[[gnu::noipa]] _BitInt(837)
> +bar (int n, ...)
> +{
> +  va_list ap;
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  va_start (ap);
> +  a[(n + W - 1) / W] = 42;
> +  __builtin_va_arg_bitint (ap, n, a, false, true);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  if (va_arg (ap, int) != 42)
> +    __builtin_abort ();
> +  va_end (ap);
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[j]) << i;
> +  return r;
> +}
> +
> +[[gnu::noipa]] _BitInt(837)
> +baz (int n, ...)
> +{
> +  va_list ap;
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  va_start (ap);
> +  a[(n + W - 1) / W] = 42;
> +  __builtin_va_arg_bitint (ap, n, a, true, true);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  if (va_arg (ap, int) != 42)
> +    __builtin_abort ();
> +  va_end (ap);
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[(n + W - 1) / W - 1 - j]) << i;
> +  return r;
> +}
> +#endif
> +
> +#if __BITINT_MAXWIDTH__ >= 837
> +[[gnu::noipa]] _BitInt(837)
> +corge (int n, void *b)
> +{
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  a[(n + W - 1) / W] = 42;
> +  __builtin_bitint_unpack (b, n, a, false, true);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[j]) << i;
> +  return r;
> +}
> +
> +[[gnu::noipa]] _BitInt(837)
> +garply (int n, void *b)
> +{
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  a[(n + W - 1) / W] = 42;
> +  __builtin_bitint_unpack (b, n, a, true, true);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[(n + W - 1) / W - 1 - j]) << i;
> +  return r;
> +}
> +#endif
> +
> +int
> +main ()
> +{
> +#if __BITINT_MAXWIDTH__ >= 837
> +  if (bar (1, 0uwb, 42) != 0uwb)
> +    __builtin_abort ();
> +  if (bar (1, 1uwb, 42) != 1uwb)
> +    __builtin_abort ();
> +  if (bar (5, 19uwb, 42) != 19uwb)
> +    __builtin_abort ();
> +  if (bar (8, 206uwb, 42) != 206uwb)
> +    __builtin_abort ();
> +  if (bar (13, 7570uwb, 42) != 7570uwb)
> +    __builtin_abort ();
> +  if (bar (16, 38151uwb, 42) != 38151uwb)
> +    __builtin_abort ();
> +  if (bar (27, 85311871uwb, 42) != 85311871uwb)
> +    __builtin_abort ();
> +  if (bar (32, 2918365024uwb, 42) != 2918365024uwb)
> +    __builtin_abort ();
> +  if (bar (52, 2418319599906367uwb, 42) != 2418319599906367uwb)
> +    __builtin_abort ();
> +  if (bar (64, 10324453899960610638uwb, 42) != 10324453899960610638uwb)
> +    __builtin_abort ();
> +  if (bar (115, 35493143902794610347964586515544041uwb, 42)
> +      != 35493143902794610347964586515544041uwb)
> +    __builtin_abort ();
> +  if (bar (128, 242619899432347503858857658506928415851uwb, 42)
> +      != 242619899432347503858857658506928415851uwb)
> +    __builtin_abort ();
> +  if (bar (526, 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb,
>  42)
> +      != 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb)
> +    __builtin_abort ();
> +  if (bar (817, 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb,
>  42)
> +      != 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb)
> +    __builtin_abort ();
> +  if (bar (832, 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb,
>  42)
> +      != 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb)
> +    __builtin_abort ();
> +  if (baz (1, 0uwb, 42) != 0uwb)
> +    __builtin_abort ();
> +  if (baz (1, 1uwb, 42) != 1uwb)
> +    __builtin_abort ();
> +  if (baz (5, 19uwb, 42) != 19uwb)
> +    __builtin_abort ();
> +  if (baz (8, 206uwb, 42) != 206uwb)
> +    __builtin_abort ();
> +  if (baz (13, 7570uwb, 42) != 7570uwb)
> +    __builtin_abort ();
> +  if (baz (16, 38151uwb, 42) != 38151uwb)
> +    __builtin_abort ();
> +  if (baz (27, 85311871uwb, 42) != 85311871uwb)
> +    __builtin_abort ();
> +  if (baz (32, 2918365024uwb, 42) != 2918365024uwb)
> +    __builtin_abort ();
> +  if (baz (52, 2418319599906367uwb, 42) != 2418319599906367uwb)
> +    __builtin_abort ();
> +  if (baz (64, 10324453899960610638uwb, 42) != 10324453899960610638uwb)
> +    __builtin_abort ();
> +  if (baz (115, 35493143902794610347964586515544041uwb, 42)
> +      != 35493143902794610347964586515544041uwb)
> +    __builtin_abort ();
> +  if (baz (128, 242619899432347503858857658506928415851uwb, 42)
> +      != 242619899432347503858857658506928415851uwb)
> +    __builtin_abort ();
> +  if (baz (526, 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb,
>  42)
> +      != 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb)
> +    __builtin_abort ();
> +  if (baz (817, 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb,
>  42)
> +      != 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb)
> +    __builtin_abort ();
> +  if (baz (832, 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb,
>  42)
> +      != 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb)
> +    __builtin_abort ();
> +#define corge(n, v) \
> +  do                                 \
> +    {                                        \
> +      unsigned _BitInt(n) w = v;     \
> +      if ((corge) (n, &w) != v)              \
> +     __builtin_abort ();             \
> +    }                                        \
> +  while (0)
> +#define garply(n, v) \
> +  do                                 \
> +    {                                        \
> +      unsigned _BitInt(n) w = v;     \
> +      if ((garply) (n, &w) != v)     \
> +     __builtin_abort ();             \
> +    }                                        \
> +  while (0)
> +  corge (1, 0uwb);
> +  corge (1, 1uwb);
> +  corge (5, 19uwb);
> +  corge (8, 206uwb);
> +  corge (13, 7570uwb);
> +  corge (16, 38151uwb);
> +  corge (27, 85311871uwb);
> +  corge (32, 2918365024uwb);
> +  corge (52, 2418319599906367uwb);
> +  corge (64, 10324453899960610638uwb);
> +  corge (115, 35493143902794610347964586515544041uwb);
> +  corge (128, 242619899432347503858857658506928415851uwb);
> +  corge (526, 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb);
> +  corge (817, 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb);
> +  corge (832, 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb);
> +  garply (1, 0uwb);
> +  garply (1, 1uwb);
> +  garply (5, 19uwb);
> +  garply (8, 206uwb);
> +  garply (13, 7570uwb);
> +  garply (16, 38151uwb);
> +  garply (27, 85311871uwb);
> +  garply (32, 2918365024uwb);
> +  garply (52, 2418319599906367uwb);
> +  garply (64, 10324453899960610638uwb);
> +  garply (115, 35493143902794610347964586515544041uwb);
> +  garply (128, 242619899432347503858857658506928415851uwb);
> +  garply (526, 
> 180194070356886021255857914345126405999398316757939019056773385284724305086631574185580484256183791238681315262210197901922727810824312479861470581236057569742uwb);
> +  garply (817, 
> 873989987746428259412194333913416701987357762822590714399458303903535888835232670878457161432636363996257309241302481691723537010408733419813385804491106555801784494262060916206872597091033287849274902594962928694944169726768114734355431735427071uwb);
> +  garply (832, 
> 23594434241796262031251233318841235347130683007441570017128772622267774079572850334920487667606346508713826956600386054750426773544457159868730626269255744559973640839812924189319711235173267236738614098413184882928609457627967564162746003214826547541uwb);
> +#endif
> +}
> --- gcc/testsuite/gcc.dg/bitint-151.c.jj      2026-07-06 13:18:27.001305788 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-151.c 2026-07-06 13:20:25.573751427 +0200
> @@ -0,0 +1,215 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-std=c2y -O2" } */
> +
> +#include <stdarg.h>
> +
> +#ifndef T
> +#define T long
> +#endif
> +
> +#if __BITINT_MAXWIDTH__ >= 837
> +#define W (sizeof (T) * __CHAR_BIT__)
> +
> +[[gnu::noipa]] _BitInt(837)
> +bar (int n, ...)
> +{
> +  va_list ap;
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  va_start (ap);
> +  a[(n + W - 1) / W] = 42;
> +  __builtin_va_arg_bitint (ap, n, a, false, false);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  if (va_arg (ap, int) != 42)
> +    __builtin_abort ();
> +  va_end (ap);
> +  _BitInt(837) r = 0;
> +  int i = 0, j;
> +  for (j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[j]) << i;
> +  if ((signed T) a[j - 1] < 0)
> +    r += ((_BitInt(837)) -1) << i;
> +  return r;
> +}
> +
> +[[gnu::noipa]] _BitInt(837)
> +baz (int n, ...)
> +{
> +  va_list ap;
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  va_start (ap);
> +  a[(n + W - 1) / W] = 42;
> +  __builtin_va_arg_bitint (ap, n, a, true, false);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  if (va_arg (ap, int) != 42)
> +    __builtin_abort ();
> +  va_end (ap);
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[(n + W - 1) / W - 1 - j]) << i;
> +  if ((signed T) a[0] < 0)
> +    r += ((_BitInt(837)) -1) << i;
> +  return r;
> +}
> +#endif
> +
> +#if __BITINT_MAXWIDTH__ >= 837
> +[[gnu::noipa]] _BitInt(837)
> +corge (int n, void *b)
> +{
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  a[(n + W - 1) / W] = 42;
> +  __builtin_bitint_unpack (b, n, a, false, false);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  _BitInt(837) r = 0;
> +  int i = 0, j;
> +  for (j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[j]) << i;
> +  if ((signed T) a[j - 1] < 0)
> +    r += ((_BitInt(837)) -1) << i;
> +  return r;
> +}
> +
> +[[gnu::noipa]] _BitInt(837)
> +garply (int n, void *b)
> +{
> +  unsigned T a[(837 + W - 1) / W + 1]; 
> +  a[(n + W - 1) / W] = 42;
> +  __builtin_bitint_unpack (b, n, a, true, false);
> +  if (a[(n + W - 1) / W] != 42)
> +    __builtin_abort ();
> +  _BitInt(837) r = 0;
> +  int i = 0;
> +  for (int j = 0; i < n; i += W, ++j)
> +    r += ((_BitInt(837)) a[(n + W - 1) / W - 1 - j]) << i;
> +  if ((signed T) a[0] < 0)
> +    r += ((_BitInt(837)) -1) << i;
> +  return r;
> +}
> +#endif
> +
> +int
> +main ()
> +{
> +#if __BITINT_MAXWIDTH__ >= 837
> +  if (bar (1, 0wb, 42) != 0wb)
> +    __builtin_abort ();
> +  if (bar (1, (_BitInt(1)) -1wb, 42) != -1)
> +    __builtin_abort ();
> +  if (bar (5, -12wb, 42) != -12wb)
> +    __builtin_abort ();
> +  if (bar (8, 107wb, 42) != 107wb)
> +    __builtin_abort ();
> +  if (bar (13, -3412wb, 42) != -3412wb)
> +    __builtin_abort ();
> +  if (bar (16, 24476wb, 42) != 24476wb)
> +    __builtin_abort ();
> +  if (bar (27, 62759870wb, 42) != 62759870wb)
> +    __builtin_abort ();
> +  if (bar (32, -1940906384wb, 42) != -1940906384wb)
> +    __builtin_abort ();
> +  if (bar (52, 1858183038390462wb, 42) != 1858183038390462wb)
> +    __builtin_abort ();
> +  if (bar (64, -8256680225559468133wb, 42) != -8256680225559468133wb)
> +    __builtin_abort ();
> +  if (bar (115, -19567690694941323284865986666034440wb, 42)
> +      != -19567690694941323284865986666034440wb)
> +    __builtin_abort ();
> +  if (bar (128, 161295407943090171995441423582245738873wb, 42)
> +      != 161295407943090171995441423582245738873wb)
> +    __builtin_abort ();
> +  if (bar (526, 
> -74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb,
>  42)
> +      != 
> -74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb)
> +    __builtin_abort ();
> +  if (bar (817, 
> 334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb,
>  42)
> +      != 
> 334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb)
> +    __builtin_abort ();
> +  if (bar (832, 
> -10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb,
>  42)
> +      != 
> -10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb)
> +    __builtin_abort ();
> +  if (baz (1, 0wb, 42) != 0wb)
> +    __builtin_abort ();
> +  if (baz (1, (_BitInt(1)) -1wb, 42) != -1)
> +    __builtin_abort ();
> +  if (baz (5, 12wb, 42) != 12wb)
> +    __builtin_abort ();
> +  if (baz (8, -107wb, 42) != -107wb)
> +    __builtin_abort ();
> +  if (baz (13, 3412wb, 42) != 3412wb)
> +    __builtin_abort ();
> +  if (baz (16, -24476wb, 42) != -24476wb)
> +    __builtin_abort ();
> +  if (baz (27, -62759870wb, 42) != -62759870wb)
> +    __builtin_abort ();
> +  if (baz (32, 1940906384wb, 42) != 1940906384wb)
> +    __builtin_abort ();
> +  if (baz (52, -1858183038390462wb, 42) != -1858183038390462wb)
> +    __builtin_abort ();
> +  if (baz (64, 8256680225559468133wb, 42) != 8256680225559468133wb)
> +    __builtin_abort ();
> +  if (baz (115, 19567690694941323284865986666034440wb, 42)
> +      != 19567690694941323284865986666034440wb)
> +    __builtin_abort ();
> +  if (baz (128, -161295407943090171995441423582245738873wb, 42)
> +      != -161295407943090171995441423582245738873wb)
> +    __builtin_abort ();
> +  if (baz (526, 
> 74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb,
>  42)
> +      != 
> 74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb)
> +    __builtin_abort ();
> +  if (baz (817, 
> -334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb,
>  42)
> +      != 
> -334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb)
> +    __builtin_abort ();
> +  if (baz (832, 
> 10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb,
>  42)
> +      != 
> 10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb)
> +    __builtin_abort ();
> +#define corge(n, v) \
> +  do                                 \
> +    {                                        \
> +      unsigned _BitInt(n) w = v;     \
> +      if ((corge) (n, &w) != v)              \
> +     __builtin_abort ();             \
> +    }                                        \
> +  while (0)
> +#define garply(n, v) \
> +  do                                 \
> +    {                                        \
> +      unsigned _BitInt(n) w = v;     \
> +      if ((garply) (n, &w) != v)     \
> +     __builtin_abort ();             \
> +    }                                        \
> +  while (0)
> +  corge (1, 0wb);
> +  corge (1, (_BitInt(1)) -1wb);
> +  corge (5, -12wb);
> +  corge (8, 107wb);
> +  corge (13, -3412wb);
> +  corge (16, 24476wb);
> +  corge (27, 62759870wb);
> +  corge (32, -1940906384wb);
> +  corge (52, 1858183038390462wb);
> +  corge (64, -8256680225559468133wb);
> +  corge (115, -19567690694941323284865986666034440wb);
> +  corge (128, 161295407943090171995441423582245738873wb);
> +  corge (526, 
> -74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb);
> +  corge (817, 
> 334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb);
> +  corge (832, 
> -10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb);
> +  garply (1, 0wb);
> +  garply (1, (_BitInt(1)) -1wb);
> +  garply (5, 12wb);
> +  garply (8, -107wb);
> +  garply (13, 3412wb);
> +  garply (16, -24476wb);
> +  garply (27, -62759870wb);
> +  garply (32, 1940906384wb);
> +  garply (52, -1858183038390462wb);
> +  garply (64, 8256680225559468133wb);
> +  garply (115, 19567690694941323284865986666034440wb);
> +  garply (128, -161295407943090171995441423582245738873wb);
> +  garply (526, 
> 74271886962589044440447868575290160981240275268510476349065102288448110495100787566581815991681080970045571964341005744164492099577970625349715415120434591551wb);
> +  garply (817, 
> -334564236539647801894756601387982526099412299271253169952919468031421908511714389453640635282951515192153648697545656682447892978128484511111304249912088833406530236950518222889146208703714474459832662825296577861528390922881280570442885198821395wb);
> +  garply (832, 
> 10126372172398046441720587244981184637120620339348885338829980023036886270537721600610561760907517491635974396689410675687310513034165727511443880739391604187139125794232654654443819264830956682943559210170711510767483980557257583148651885937914964439wb);
> +#endif
> +}
> --- gcc/testsuite/gcc.dg/bitint-152.c.jj      2026-07-06 13:20:53.523385039 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-152.c 2026-07-06 13:21:02.968261223 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T short
> +#include "bitint-150.c"
> --- gcc/testsuite/gcc.dg/bitint-153.c.jj      2026-07-06 13:20:56.616344491 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-153.c 2026-07-06 13:21:09.581174533 +0200
> @@ -0,0 +1,7 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-std=c2y -O2" } */
> +
> +#include <stdarg.h>
> +
> +#define T short
> +#include "bitint-151.c"
> --- gcc/testsuite/gcc.dg/bitint-154.c.jj      2026-07-06 13:21:29.375915045 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-154.c 2026-07-06 13:21:51.636623232 +0200
> @@ -0,0 +1,11 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdarg.h>
> +
> +#ifdef __SIZEOF_INT128__
> +#define T __int128
> +#else
> +#define T long long
> +#endif
> +#include "bitint-150.c"
> --- gcc/testsuite/gcc.dg/bitint-155.c.jj      2026-07-06 13:21:32.455874672 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-155.c 2026-07-06 13:22:34.869056503 +0200
> @@ -0,0 +1,11 @@
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-std=gnu2y -O2" } */
> +
> +#include <stdarg.h>
> +
> +#ifdef __SIZEOF_INT128__
> +#define T __int128
> +#else
> +#define T long long
> +#endif
> +#include "bitint-151.c"
> 
>       Jakub

-- 
Univ.-Prof. Dr. rer. nat. Martin Uecker
Graz University of Technology
Institute of Biomedical Imaging

Reply via email to