[WIP PATCH]: Add __builtin_va_arg_bitint, __builtin_bitint_unpack and __builtin_bitint_pack builtins

Jakub Jelinek <[email protected]>
Newsgroups gmane.comp.gcc.patches,gmane.comp.lib.glibc.alpha
Message-ID <akusSsc8nkT-pTm2@tucnak>
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?

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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.