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