c, c++, bitintlower: Add __builtin_{bswap,bitreverse}g type-generic builtins [PR122731]

Message ID ah9O9FkAymwbK4i4@tucnak
State New
Headers
Series c, c++, bitintlower: Add __builtin_{bswap,bitreverse}g type-generic builtins [PR122731] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-aarch64-bootstrap success Build passed
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap success Build passed

Commit Message

Jakub Jelinek June 2, 2026, 9:45 p.m. UTC
  Hi!

Clang has added recently type-generic versions of __builtin_bswap{16,32,64}
and __builtin_bitreverse{8,16,32,64} builtins.

The following patch adds them to GCC as well.
Unlike the other __builtin_*g type-generic builtins, these are different in
that the return type is not fixed (usually int or unsigned int), but is the
same as the argument type, so these can't be handled as normal builtins
and are handled in the C and C++ parsers instead.

For consistency with the other __builtin_*g builtins, these only accept
unsigned INTEGER_TYPE (or for C BITINT_TYPE) - users can use various ways
to request unsigned variant of arbitrary types.  For __builtin_bswapg
additionally this requires the type to have precision which is a multiple of
8 (unlike clang, which for some strange reason requires multiple of 16).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2026-06-02  Jakub Jelinek  <jakub@redhat.com>

	PR c/122731
gcc/
	* doc/extend.texi (__builtin_bswapg, __builtin_bitreverseg): Document.
	* internal-fn.def (DEF_INTERNAL_INTSZ_FN): Define.
	(DEF_INTERNAL_INTSZ_EXT_FN): Define.
	(BSWAP): New internal fn.
	(BITREVERSE): Likewise.
	* internal-fn.h (expand_BSWAP, expand_BITREVERSE): Declare.
	* internal-fn.cc (DEF_INTERNAL_INTSZ_EXT_FN): Define.
	(expand_BSWAP, expand_BITREVERSE): New functions.
	* builtins.h (fold_build_builtin_bswapg_bitreverseg): Declare.
	* builtins.cc (fold_build_builtin_bswapg_bitreverseg): New function.
	* wide-int.h (wi::bswap): Fix up docs that only multiple of 8 bits
	is required.
	* gimple-match-exports.cc (build_call_internal): Handle IFN_BSWAP
	and IFN_BITREVERSE.
	* gencfn-macros.cc (internal_fn_intsz_names): New variable.
	(intsz_suffixes): Likewise.
	(suffix_lists): Add intsz_suffixes.
	(main): Handle internal_fn_intsz_names.
	* match.pd (BSWAP, BITREVERSE): Remove.
	(popcount(bswap(x)) is popcount(x)): Use BSWAP BITREVERSE
	op lists.
	* tree-ssa-phiopt.cc (empty_bb_or_one_feeding_into_p): Use
	CASE_CFN_BSWAP and CASE_CFN_BITREVERSE.
	(cond_removal_in_builtin_zero_pattern): Likewise.
	* fold-const-call.cc (fold_const_call_ss): Likewise.
	* fold-const.cc (tree_call_nonnegative_p): Likewise.
	* gimple-lower-bitint.cc (struct bitint_large_huge): Declare
	lower_bswap_bitreverse method.
	(bitint_large_huge::lower_bswap_bitreverse): New method.
	(bitint_large_huge::lower_call): Call it.
	(build_bitint_stmt_ssa_conflicts): Set muldiv_p for IFN_BSWAP
	and IFN_BITREVERSE.
gcc/c-family/
	* c-common.h (enum rid): Add RID_BUILTIN_BSWAPG and
	RID_BUILTIN_BITREVERSEG.
	* c-common.cc (c_common_reswords): Add __builtin_bswapg
	and __builtin_bitreverseg.
gcc/c/
	* c-parser.cc (c_parser_postfix_expression): Parse
	__builtin_bswapg and __builtin_bitreverseg.
gcc/cp/
	* parser.cc (cp_parser_postfix_expression): Parse
	__builtin_bswapg and __builtin_bitreverseg.
	* typeck.cc (build_x_bswapg_bitreverseg): New function.
	* cp-tree.h (build_x_bswapg_bitreverseg): Declare.
	* pt.cc (tsubst_expr): Handle IFN_BSWAP and IFN_BITREVERSE.
	* constexpr.cc (cxx_eval_internal_function): Likewise.
	(potential_constant_expression_1): Likewise.
	* cp-gimplify.cc (cp_gimplify_expr): Likewise.
gcc/testsuite/
	* c-c++-common/builtin-bswapg-1.c: New test.
	* c-c++-common/builtin-bswapg-2.c: New test.
	* c-c++-common/builtin-bswapg-3.c: New test.
	* c-c++-common/builtin-bitreverseg-1.c: New test.
	* c-c++-common/builtin-bitreverseg-2.c: New test.


	Jakub
  

Comments

Joseph Myers June 3, 2026, 6:14 p.m. UTC | #1
On Tue, 2 Jun 2026, Jakub Jelinek wrote:

> Hi!
> 
> Clang has added recently type-generic versions of __builtin_bswap{16,32,64}
> and __builtin_bitreverse{8,16,32,64} builtins.
> 
> The following patch adds them to GCC as well.
> Unlike the other __builtin_*g type-generic builtins, these are different in
> that the return type is not fixed (usually int or unsigned int), but is the
> same as the argument type, so these can't be handled as normal builtins
> and are handled in the C and C++ parsers instead.
> 
> For consistency with the other __builtin_*g builtins, these only accept
> unsigned INTEGER_TYPE (or for C BITINT_TYPE) - users can use various ways
> to request unsigned variant of arbitrary types.  For __builtin_bswapg
> additionally this requires the type to have precision which is a multiple of
> 8 (unlike clang, which for some strange reason requires multiple of 16).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

The C front-end changes are OK (but see note below about missing test 
coverage).

> --- gcc/testsuite/c-c++-common/builtin-bswapg-2.c.jj	2026-06-02 19:00:30.252144603 +0200
> +++ gcc/testsuite/c-c++-common/builtin-bswapg-2.c	2026-06-02 19:28:21.081815725 +0200
> @@ -0,0 +1,21 @@
> +/* Test __builtin_bswapg.  */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +int
> +main ()
> +{
> +  __builtin_bswapg ();		/* { dg-error "wrong number of arguments to '__builtin_bswapg'" } */
> +  __builtin_bswapg (1U, 1U);	/* { dg-error "wrong number of arguments to '__builtin_bswapg'" } */
> +  __builtin_bswapg (1.0);	/* { dg-error "'__builtin_bswapg' operand not an integral type" } */
> +  __builtin_bswapg (1.0f);	/* { dg-error "'__builtin_bswapg' operand not an integral type" } */
> +  __builtin_bswapg (1.0L);	/* { dg-error "'__builtin_bswapg' operand not an integral type" } */
> +  struct S { int a; };
> +  __builtin_bswapg ((struct S) { 42 });	/* { dg-error "'__builtin_bswapg' operand not an integral type" } */
> +  enum E { E0, E1 };
> +  __builtin_bswapg (E1);	/* { dg-error "argument 1 in call to function '__builtin_bswapg' has signed type" "" { target c } } */
> +				/* { dg-error "argument 1 in call to function '__builtin_bswapg' has enumerated type" "" { target c++ } .-1 } */

The enumerated type error seems to be tested only for C++ (likewise for 
__builtin_bitreverseg).  Presumably it could be tested for C with a cast 
to or variable of enumerated type, or by using an enumeration with fixed 
underlying type.
  
Jason Merrill June 4, 2026, 1:01 a.m. UTC | #2
On 6/2/26 5:45 PM, Jakub Jelinek wrote:
> Hi!
> 
> Clang has added recently type-generic versions of __builtin_bswap{16,32,64}
> and __builtin_bitreverse{8,16,32,64} builtins.
> 
> The following patch adds them to GCC as well.
> Unlike the other __builtin_*g type-generic builtins, these are different in
> that the return type is not fixed (usually int or unsigned int), but is the
> same as the argument type, so these can't be handled as normal builtins
> and are handled in the C and C++ parsers instead.
> 
> For consistency with the other __builtin_*g builtins, these only accept
> unsigned INTEGER_TYPE (or for C BITINT_TYPE) - users can use various ways
> to request unsigned variant of arbitrary types.  For __builtin_bswapg
> additionally this requires the type to have precision which is a multiple of
> 8 (unlike clang, which for some strange reason requires multiple of 16).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> --- gcc/cp/parser.cc.jj	2026-06-02 08:15:04.592141644 +0200
> +++ gcc/cp/parser.cc	2026-06-02 11:35:20.211913589 +0200
> @@ -8617,6 +8617,8 @@ cp_parser_postfix_expression (cp_parser
>       case RID_BUILTIN_ASSOC_BARRIER:
>       case RID_BUILTIN_OPERATOR_NEW:
>       case RID_BUILTIN_OPERATOR_DELETE:
> +    case RID_BUILTIN_BSWAPG:
> +    case RID_BUILTIN_BITREVERSEG:
>         {
>   	vec<tree, va_gc> *vec;
>   
> @@ -8736,6 +8738,32 @@ cp_parser_postfix_expression (cp_parser
>   	      }
>   	    break;
>   
> +	  case RID_BUILTIN_BSWAPG:
> +	    if (vec->length () == 1)
> +	      postfix_expression
> +		= build_x_bswapg_bitreverseg (loc, IFN_BSWAP, vec,
> +					      tf_warning_or_error);
> +	    else
> +	      {
> +		error_at (loc, "wrong number of arguments to "
> +			       "%<__builtin_bswapg%>");
> +		postfix_expression = error_mark_node;
> +	      }

Since you pass the vec to the new build_... function, why not give this 
error there along with all the others?

> +	    break;
> +
> +	  case RID_BUILTIN_BITREVERSEG:
> +	    if (vec->length () == 1)
> +	      postfix_expression
> +		= build_x_bswapg_bitreverseg (loc, IFN_BITREVERSE, vec,
> +					      tf_warning_or_error);
> +	    else
> +	      {
> +		error_at (loc, "wrong number of arguments to "
> +			       "%<__builtin_bitreverseg%>");
> +		postfix_expression = error_mark_node;
> +	      }
> +	    break;
> +
>   	  default:
>   	    gcc_unreachable ();
>   	  }
> --- gcc/cp/typeck.cc.jj	2026-05-29 10:08:33.380536476 +0200
> +++ gcc/cp/typeck.cc	2026-06-02 12:48:53.944496483 +0200
> @@ -7111,6 +7111,72 @@ build_x_shufflevector (location_t loc, v
>       }
>     return exp;
>   }
> +
> +/* Build __builtin_bswapg (ARG) or __builtin_bitreverseg (ARG).  */
> +tree
> +build_x_bswapg_bitreverseg (location_t loc, internal_fn ifn,
> +			    vec<tree, va_gc> *args, tsubst_flags_t complain)
> +{
> +  tree arg = (*args)[0];
> +  if (type_dependent_expression_p (arg))
> +    {
> +      tree exp = build_min_nt_call_vec (NULL, args);
> +      CALL_EXPR_IFN (exp) = ifn;
> +      return exp;
> +    }
> +  const char *name
> +    = ifn == IFN_BSWAP ? "__builtin_bswapg" : "__builtin_bitreverseg";
> +  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (arg));
> +  if (!INTEGRAL_TYPE_P (type))
> +    {
> +      if (complain & tf_error)
> +	error_at (loc, "%qs operand not an integral type", name);
> +      return error_mark_node;
> +    }
> +  if (TREE_CODE (type) == ENUMERAL_TYPE)
> +    {
> +      if (complain & tf_error)
> +	error_at (loc, "argument %u in call to function "
> +		       "%qs has enumerated type", 1, name);
> +      return error_mark_node;
> +    }
> +  if (TREE_CODE (type) == BOOLEAN_TYPE)
> +    {
> +      if (complain & tf_error)
> +	error_at (loc, "argument %u in call to function "
> +		       "%qs has boolean type", 1, name);
> +      return error_mark_node;
> +    }
> +  if (!TYPE_UNSIGNED (type))
> +    {
> +      if (complain & tf_error)
> +	error_at (loc, "argument 1 in call to function "
> +		       "%qs has signed type", name);
> +      return error_mark_node;
> +    }
> +  if (type == char_type_node)
> +    {
> +      if (complain & tf_error)
> +	error_at (loc, "argument 1 in call to function "
> +		       "%qs has %<char%> type", name);

This might suggest using "unsigned char" instead, for clarity.

> @@ -3245,6 +3245,30 @@ cxx_eval_internal_function (const conste
>       case IFN_DEFERRED_INIT:
>         return build_clobber (TREE_TYPE (t), CLOBBER_OBJECT_BEGIN);
>   
> +    case IFN_BSWAP:
> +    case IFN_BITREVERSE:
> +      {
> +	tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
> +						 vc_prvalue, non_constant_p,
> +						 overflow_p, jump_target);
> +	if (*jump_target)
> +	  return NULL_TREE;

I think we want to check *non_constant_p here rather than fall through 
to giving a redundant error.

The C++ changes are OK with those adjustments.

Jason
  

Patch

--- gcc/doc/extend.texi.jj	2026-06-01 09:15:39.025605479 +0200
+++ gcc/doc/extend.texi	2026-06-02 19:20:31.697824450 +0200
@@ -16095,6 +16095,12 @@  Similar to @code{__builtin_bswap64}, exc
 are 128-bit.  Only supported on targets when 128-bit types are supported.
 @enddefbuiltin
 
+@defbuiltin{@var{type} __builtin_bswapg (@var{type} @var{x})}
+Similar to @code{__builtin_bswap64}, except the argument is type-generic
+unsigned integer (standard, extended or bit-precise) with width which is
+multiple of 8.  No integral argument promotions are performed on the argument.
+@enddefbuiltin
+
 @defbuiltin{uint8_t __builtin_bitreverse8 (uint8_t @var{x})}
 Returns @var{x} with all bits reversed.
 @enddefbuiltin
@@ -16119,6 +16125,12 @@  Similar to @code{__builtin_bitreverse64}
 are 128-bit.  Only supported on targets when 128-bit types are supported.
 @enddefbuiltin
 
+@defbuiltin{@var{type} __builtin_bitreverseg (@var{type} @var{x})}
+Similar to @code{__builtin_bitreverse64}, except the argument is type-generic
+unsigned integer (standard, extended or bit-precise).
+No integral argument promotions are performed on the argument.
+@enddefbuiltin
+
 @node CRC Builtins
 @subsection CRC Builtins
 @cindex CRC builtins
--- gcc/internal-fn.def.jj	2026-06-02 08:14:59.761207073 +0200
+++ gcc/internal-fn.def	2026-06-02 11:20:13.565339257 +0200
@@ -36,6 +36,8 @@  along with GCC; see the file COPYING3.
      DEF_INTERNAL_FLT_FLOATN_FN (NAME, FLAGS, OPTAB, TYPE)
      DEF_INTERNAL_INT_FN (NAME, FLAGS, OPTAB, TYPE)
      DEF_INTERNAL_INT_EXT_FN (NAME, FLAGS, OPTAB, TYPE)
+     DEF_INTERNAL_INTSZ_FN (NAME, FLAGS, OPTAB, TYPE)
+     DEF_INTERNAL_INTSZ_EXT_FN (NAME, FLAGS, OPTAB, TYPE)
      DEF_INTERNAL_COND_FN (NAME, FLAGS, OPTAB, TYPE)
      DEF_INTERNAL_SIGNED_COND_FN (NAME, FLAGS, OPTAB, TYPE)
      DEF_INTERNAL_WIDENING_OPTAB_FN (NAME, FLAGS, SELECTOR, SOPTAB, UOPTAB,
@@ -107,6 +109,14 @@  along with GCC; see the file COPYING3.
    has expand_##NAME defined in internal-fn.cc to override the
    DEF_INTERNAL_INT_FN expansion behavior.
 
+   DEF_INTERNAL_INTSZ_FN is like DEF_INTERNAL_OPTAB_FN, but in addition
+   says that the function extends the C-level BUILT_IN_<NAME>{8,16,32,64,128}
+   group of functions to any integral mode (including vector modes).
+
+   DEF_INTERNAL_INTSZ_EXT_FN is like DEF_INTERNAL_INTSZ_FN, except that it
+   has expand_##NAME defined in internal-fn.cc to override the
+   DEF_INTERNAL_INTSZ_FN expansion behavior.
+
    DEF_INTERNAL_WIDENING_OPTAB_FN is a wrapper that defines five internal
    functions with DEF_INTERNAL_SIGNED_OPTAB_FN:
    - one that describes a widening operation with the same number of elements
@@ -175,6 +185,16 @@  along with GCC; see the file COPYING3.
   DEF_INTERNAL_INT_FN (NAME, FLAGS, OPTAB, TYPE)
 #endif
 
+#ifndef DEF_INTERNAL_INTSZ_FN
+#define DEF_INTERNAL_INTSZ_FN(NAME, FLAGS, OPTAB, TYPE) \
+  DEF_INTERNAL_OPTAB_FN (NAME, FLAGS, OPTAB, TYPE)
+#endif
+
+#ifndef DEF_INTERNAL_INTSZ_EXT_FN
+#define DEF_INTERNAL_INTSZ_EXT_FN(NAME, FLAGS, OPTAB, TYPE) \
+  DEF_INTERNAL_INTSZ_FN (NAME, FLAGS, OPTAB, TYPE)
+#endif
+
 #ifndef DEF_INTERNAL_WIDENING_OPTAB_FN
 #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, FLAGS, SELECTOR, SOPTAB, UOPTAB, TYPE)		    \
   DEF_INTERNAL_SIGNED_OPTAB_FN (NAME, FLAGS, SELECTOR, SOPTAB, UOPTAB, TYPE)			    \
@@ -471,6 +491,9 @@  DEF_INTERNAL_INT_EXT_FN (CTZ, ECF_CONST
 DEF_INTERNAL_INT_EXT_FN (FFS, ECF_CONST | ECF_NOTHROW, ffs, unary)
 DEF_INTERNAL_INT_EXT_FN (PARITY, ECF_CONST | ECF_NOTHROW, parity, unary)
 DEF_INTERNAL_INT_EXT_FN (POPCOUNT, ECF_CONST | ECF_NOTHROW, popcount, unary)
+DEF_INTERNAL_INTSZ_EXT_FN (BSWAP, ECF_CONST | ECF_NOTHROW, bswap, unary)
+DEF_INTERNAL_INTSZ_EXT_FN (BITREVERSE, ECF_CONST | ECF_NOTHROW, bitreverse,
+			   unary)
 
 DEF_INTERNAL_FN (GOMP_TARGET_REV, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (GOMP_USE_SIMT, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
@@ -627,6 +650,8 @@  DEF_INTERNAL_OPTAB_FN (BIT_IORN, ECF_CON
 #undef DEF_INTERNAL_COND_FN
 #undef DEF_INTERNAL_INT_EXT_FN
 #undef DEF_INTERNAL_INT_FN
+#undef DEF_INTERNAL_INTSZ_EXT_FN
+#undef DEF_INTERNAL_INTSZ_FN
 #undef DEF_INTERNAL_FLT_FN
 #undef DEF_INTERNAL_FLT_FLOATN_FN
 #undef DEF_INTERNAL_SIGNED_OPTAB_FN
--- gcc/internal-fn.h.jj	2026-06-02 08:14:59.761207073 +0200
+++ gcc/internal-fn.h	2026-06-02 11:20:13.565561425 +0200
@@ -285,6 +285,8 @@  extern void expand_CTZ (internal_fn, gca
 extern void expand_FFS (internal_fn, gcall *);
 extern void expand_PARITY (internal_fn, gcall *);
 extern void expand_POPCOUNT (internal_fn, gcall *);
+extern void expand_BSWAP (internal_fn, gcall *);
+extern void expand_BITREVERSE (internal_fn, gcall *);
 
 extern bool vectorized_internal_fn_supported_p (internal_fn, tree);
 
--- gcc/internal-fn.cc.jj	2026-06-02 08:14:59.761207073 +0200
+++ gcc/internal-fn.cc	2026-06-02 11:20:13.565878590 +0200
@@ -4765,6 +4765,7 @@  set_edom_supported_p (void)
     expand_##TYPE##_optab_fn (fn, stmt, OPTAB##_optab);	\
   }
 #define DEF_INTERNAL_INT_EXT_FN(CODE, FLAGS, OPTAB, TYPE)
+#define DEF_INTERNAL_INTSZ_EXT_FN(CODE, FLAGS, OPTAB, TYPE)
 #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
 				     UNSIGNED_OPTAB, TYPE)		\
   static void								\
@@ -5930,3 +5931,17 @@  expand_POPCOUNT (internal_fn fn, gcall *
       emit_insn (all_insns);
     }
 }
+
+void
+expand_BSWAP (internal_fn fn, gcall *stmt)
+{
+  if (expand_bitquery (fn, stmt))
+    expand_unary_optab_fn (fn, stmt, bswap_optab);
+}
+
+void
+expand_BITREVERSE (internal_fn fn, gcall *stmt)
+{
+  if (expand_bitquery (fn, stmt))
+    expand_unary_optab_fn (fn, stmt, bitreverse_optab);
+}
--- gcc/builtins.h.jj	2026-06-02 08:14:59.731207479 +0200
+++ gcc/builtins.h	2026-06-02 11:20:13.567773163 +0200
@@ -140,6 +140,8 @@  extern rtx expand_builtin (tree, rtx, rt
 extern enum built_in_function builtin_mathfn_code (const_tree);
 extern tree fold_builtin_expect (location_t, tree, tree, tree, tree);
 extern tree fold_builtin_constant_p (tree);
+extern tree fold_build_builtin_bswapg_bitreverseg (location_t, internal_fn,
+						   tree);
 extern bool avoid_folding_inline_builtin (tree);
 extern tree fold_call_expr (location_t, tree, bool);
 extern tree fold_builtin_call_array (location_t, tree, tree, int, tree *);
--- gcc/builtins.cc.jj	2026-06-02 08:14:59.722207601 +0200
+++ gcc/builtins.cc	2026-06-02 11:20:13.566725155 +0200
@@ -10522,6 +10522,53 @@  fold_builtin_bit_query (location_t loc,
   return call;
 }
 
+/* Fold or build a __builtin_bswapg (ARG) (if IFN is IFN_BSWAP) or
+   __builtin_bitreverseg (ARG (otherwise) call.  The FE should have
+   verified earlier that the argument type is unsigned INTEGER_TYPE
+   or BITINT_TYPE, for __builtin_bswapg with precision divisible by 8.  */
+
+tree
+fold_build_builtin_bswapg_bitreverseg (location_t loc, enum internal_fn ifn,
+				       tree arg)
+{
+  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (arg));
+  if (ifn == IFN_BSWAP && TYPE_PRECISION (type) == 8)
+    return fold_convert_loc (loc, type, arg);
+  struct { tree type; built_in_function bswap, bitreverse; } fns[]
+    = { { unsigned_char_type_node, END_BUILTINS, BUILT_IN_BITREVERSE8 },
+	{ uint16_type_node, BUILT_IN_BSWAP16, BUILT_IN_BITREVERSE16 },
+	{ uint32_type_node, BUILT_IN_BSWAP32, BUILT_IN_BITREVERSE32 },
+	{ uint64_type_node, BUILT_IN_BSWAP64, BUILT_IN_BITREVERSE64 },
+	{ uint128_type_node, BUILT_IN_BSWAP128, BUILT_IN_BITREVERSE128 } };
+  if (TREE_CODE (arg) == INTEGER_CST)
+    {
+      wide_int res;
+      if (ifn == IFN_BSWAP)
+	res = wi::bswap (wi::to_wide (arg));
+      else
+	res = wi::bitreverse (wi::to_wide (arg));
+      return wide_int_to_tree (type, res);
+    }
+  for (unsigned i = 0; i < ARRAY_SIZE (fns); ++i)
+    if (fns[i].type
+	&& TYPE_PRECISION (fns[i].type) >= TYPE_PRECISION (type))
+      {
+	arg = fold_convert_loc (loc, fns[i].type, arg);
+	tree fndecl
+	  = builtin_decl_explicit (ifn == IFN_BSWAP
+				   ? fns[i].bswap : fns[i].bitreverse);
+	tree ret = build_call_expr_loc (loc, fndecl, 1, arg);
+	if (TYPE_PRECISION (type) != TYPE_PRECISION (fns[i].type))
+	  ret = fold_build2_loc (loc, RSHIFT_EXPR, fns[i].type, ret,
+				 build_int_cst (unsigned_type_node,
+						TYPE_PRECISION (fns[i].type)
+						- TYPE_PRECISION (type)));
+	return fold_convert_loc (loc, type, ret);
+      }
+  gcc_assert (TREE_CODE (type) == BITINT_TYPE);
+  return build_call_expr_internal_loc (loc, ifn, type, 1, arg);
+}
+
 /* Fold __builtin_{add,sub}c{,l,ll} into pair of internal functions
    that return both result of arithmetics and overflowed boolean
    flag in a complex integer result.  */
--- gcc/wide-int.h.jj	2026-06-02 08:14:59.768206978 +0200
+++ gcc/wide-int.h	2026-06-02 11:20:13.567483302 +0200
@@ -2655,7 +2655,7 @@  wi::set_bit (const T &x, unsigned int bi
 
 /* Byte swap the integer X.
    ??? This always swaps 8-bit octets, regardless of BITS_PER_UNIT.
-   This function requires X's precision to be a multiple of 16 bits,
+   This function requires X's precision to be a multiple of 8 bits,
    so care needs to be taken for targets where BITS_PER_UNIT != 8.  */
 template <typename T>
 inline WI_UNARY_RESULT (T)
--- gcc/gimple-match-exports.cc.jj	2026-06-02 08:14:59.757207127 +0200
+++ gcc/gimple-match-exports.cc	2026-06-02 11:20:13.567951128 +0200
@@ -266,7 +266,9 @@  build_call_internal (internal_fn fn, gim
 	    case IFN_FFS:
 	    case IFN_POPCOUNT:
 	    case IFN_PARITY:
-	      /* For these 6 builtins large/huge _BitInt operand is ok
+	    case IFN_BSWAP:
+	    case IFN_BITREVERSE:
+	      /* For these 8 builtins large/huge _BitInt operand is ok
 		 before bitint lowering pass.  */
 	      if (res_op->num_ops >= 1
 		  && BITINT_TYPE_P (TREE_TYPE (res_op->ops[0]))
--- gcc/gencfn-macros.cc.jj	2026-06-02 08:14:59.752207195 +0200
+++ gcc/gencfn-macros.cc	2026-06-02 11:20:13.568130445 +0200
@@ -154,6 +154,13 @@  const char *const internal_fn_int_names[
   NULL
 };
 
+const char *const internal_fn_intsz_names[] = {
+#define DEF_INTERNAL_INTSZ_FN(NAME, FLAGS, OPTAB, TYPE) \
+  #NAME,
+#include "internal-fn.def"
+  NULL
+};
+
 static const char *const flt_suffixes[] = { "F", "", "L", NULL };
 static const char *const fltfn_suffixes[] = { "F16", "F32", "F64", "F128",
 					      "F32X", "F64X", "F128X", NULL };
@@ -161,10 +168,13 @@  static const char *const fltall_suffixes
 					       "F64", "F128", "F32X", "F64X",
 					       "F128X", NULL };
 static const char *const int_suffixes[] = { "", "L", "LL", "IMAX", NULL };
+static const char *const intsz_suffixes[] = { "8", "16", "32", "64", "128",
+					      NULL };
 
 static const char *const *const suffix_lists[] = {
   flt_suffixes,
   int_suffixes,
+  intsz_suffixes,
   NULL
 };
 
@@ -186,6 +196,7 @@  main (int argc, char **argv)
   add_to_set (&builtins, builtin_names);
   add_to_set (&internal_fns, internal_fn_flt_names);
   add_to_set (&internal_fns, internal_fn_int_names);
+  add_to_set (&internal_fns, internal_fn_intsz_names);
 
   /* Check the functions.  */
   for (unsigned int i = 0; internal_fn_flt_names[i]; ++i)
@@ -202,6 +213,15 @@  main (int argc, char **argv)
 	error ("DEF_INTERNAL_INT_FN (%s) has no associated built-in"
 	       " functions", name);
     }
+  for (unsigned int i = 0; internal_fn_intsz_names[i]; ++i)
+    {
+      const char *name = internal_fn_intsz_names[i];
+      if (!is_group (&builtins, name,
+		     /* There is no BUILT_IN_BSWAP8.  */
+		     intsz_suffixes + (startswith (name, "BSWAP") ? 1 : 0)))
+	error ("DEF_INTERNAL_INTSZ_FN (%s) has no associated built-in"
+	       " functions", name);
+    }
 
   /* Go through the built-in functions in declaration order, outputting
      definitions as appropriate.  */
@@ -211,10 +231,25 @@  main (int argc, char **argv)
       if (startswith (name, "BUILT_IN_"))
 	{
 	  const char *root = name + 9;
+	  char buf[128];
 	  for (unsigned int j = 0; suffix_lists[j]; ++j)
 	    {
-	      const char *const *const suffix = suffix_lists[j];
+	      const char *const *suffix = suffix_lists[j];
 
+	      if (suffix == intsz_suffixes)
+		{
+		  if (!endswith (root, "32"))
+		    continue;
+		  size_t len = strlen (root);
+		  if (len > sizeof (buf))
+		    continue;
+		  /* There is no BUILT_IN_BSWAP8.  */
+		  if (startswith (root, "BSWAP"))
+		    suffix++;
+		  memcpy (buf, root, len - 2);
+		  buf[len - 2] = '\0';
+		  root = buf;
+		}
 	      if (is_group (&builtins, root, suffix))
 		{
 		  bool internal_p = internal_fns.contains (root);
--- gcc/match.pd.jj	2026-06-02 08:14:59.764207032 +0200
+++ gcc/match.pd	2026-06-02 11:20:13.568685657 +0200
@@ -53,10 +53,6 @@  (define_operator_list swapped_tcc_compar
   gt   ge   eq ne le   lt   unordered ordered   ungt unge unlt unle uneq ltgt)
 (define_operator_list simple_comparison         lt   le   eq ne ge   gt)
 (define_operator_list swapped_simple_comparison gt   ge   eq ne le   lt)
-(define_operator_list BSWAP BUILT_IN_BSWAP16 BUILT_IN_BSWAP32
-	    BUILT_IN_BSWAP64 BUILT_IN_BSWAP128)
-(define_operator_list BITREVERSE BUILT_IN_BITREVERSE8 BUILT_IN_BITREVERSE16
-	    BUILT_IN_BITREVERSE32 BUILT_IN_BITREVERSE64 BUILT_IN_BITREVERSE128)
 
 #include "cfn-operators.pd"
 
@@ -10317,8 +10313,7 @@  (define_operator_list SYNC_FETCH_AND_AND
 
 /* popcount(bswap(x)) is popcount(x).  */
 (for popcount (POPCOUNT)
-  (for bswap (BUILT_IN_BSWAP16 BUILT_IN_BSWAP32
-	      BUILT_IN_BSWAP64 BUILT_IN_BSWAP128)
+  (for bswap (BSWAP BITREVERSE)
     (simplify
       (popcount (convert?@0 (bswap:s@1 @2)))
       (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
--- gcc/tree-ssa-phiopt.cc.jj	2026-06-02 08:14:59.768206978 +0200
+++ gcc/tree-ssa-phiopt.cc	2026-06-02 19:34:11.880846430 +0200
@@ -813,15 +813,8 @@  empty_bb_or_one_feeding_into_p (basic_bl
 	{
 	default:
 	  return false;
-	case CFN_BUILT_IN_BSWAP16:
-	case CFN_BUILT_IN_BSWAP32:
-	case CFN_BUILT_IN_BSWAP64:
-	case CFN_BUILT_IN_BSWAP128:
-	case CFN_BUILT_IN_BITREVERSE8:
-	case CFN_BUILT_IN_BITREVERSE16:
-	case CFN_BUILT_IN_BITREVERSE32:
-	case CFN_BUILT_IN_BITREVERSE64:
-	case CFN_BUILT_IN_BITREVERSE128:
+	CASE_CFN_BSWAP:
+	CASE_CFN_BITREVERSE:
 	CASE_CFN_FFS:
 	CASE_CFN_PARITY:
 	CASE_CFN_POPCOUNT:
@@ -2577,15 +2570,8 @@  cond_removal_in_builtin_zero_pattern (ba
   bool any_val = false;
   switch (cfn)
     {
-    case CFN_BUILT_IN_BSWAP16:
-    case CFN_BUILT_IN_BSWAP32:
-    case CFN_BUILT_IN_BSWAP64:
-    case CFN_BUILT_IN_BSWAP128:
-    case CFN_BUILT_IN_BITREVERSE8:
-    case CFN_BUILT_IN_BITREVERSE16:
-    case CFN_BUILT_IN_BITREVERSE32:
-    case CFN_BUILT_IN_BITREVERSE64:
-    case CFN_BUILT_IN_BITREVERSE128:
+    CASE_CFN_BSWAP:
+    CASE_CFN_BITREVERSE:
     CASE_CFN_FFS:
     CASE_CFN_PARITY:
     CASE_CFN_POPCOUNT:
--- gcc/fold-const-call.cc.jj	2026-06-02 08:14:59.744207303 +0200
+++ gcc/fold-const-call.cc	2026-06-02 11:20:13.569901898 +0200
@@ -1094,19 +1094,12 @@  fold_const_call_ss (wide_int *result, co
       *result = wi::shwi (wi::parity (arg), precision);
       return true;
 
-    case CFN_BUILT_IN_BSWAP16:
-    case CFN_BUILT_IN_BSWAP32:
-    case CFN_BUILT_IN_BSWAP64:
-    case CFN_BUILT_IN_BSWAP128:
+    CASE_CFN_BSWAP:
       *result = wi::bswap (wide_int::from (arg, precision,
 					   TYPE_SIGN (arg_type)));
       return true;
 
-    case CFN_BUILT_IN_BITREVERSE8:
-    case CFN_BUILT_IN_BITREVERSE16:
-    case CFN_BUILT_IN_BITREVERSE32:
-    case CFN_BUILT_IN_BITREVERSE64:
-    case CFN_BUILT_IN_BITREVERSE128:
+    CASE_CFN_BITREVERSE:
       *result = wi::bitreverse (wide_int::from (arg, precision,
 						TYPE_SIGN (arg_type)));
       return true;
--- gcc/fold-const.cc.jj	2026-06-02 08:14:59.747207263 +0200
+++ gcc/fold-const.cc	2026-06-02 11:20:13.570875331 +0200
@@ -14627,15 +14627,8 @@  tree_call_nonnegative_p (tree type, comb
     CASE_CFN_PARITY:
     CASE_CFN_POPCOUNT:
     CASE_CFN_CLRSB:
-    case CFN_BUILT_IN_BSWAP16:
-    case CFN_BUILT_IN_BSWAP32:
-    case CFN_BUILT_IN_BSWAP64:
-    case CFN_BUILT_IN_BSWAP128:
-    case CFN_BUILT_IN_BITREVERSE8:
-    case CFN_BUILT_IN_BITREVERSE16:
-    case CFN_BUILT_IN_BITREVERSE32:
-    case CFN_BUILT_IN_BITREVERSE64:
-    case CFN_BUILT_IN_BITREVERSE128:
+    CASE_CFN_BSWAP:
+    CASE_CFN_BITREVERSE:
       /* Always true.  */
       return true;
 
--- gcc/gimple-lower-bitint.cc.jj	2026-05-30 09:46:04.403303922 +0200
+++ gcc/gimple-lower-bitint.cc	2026-06-02 19:34:11.881570293 +0200
@@ -474,6 +474,7 @@  struct bitint_large_huge
   void lower_cplxpart_stmt (tree, gimple *);
   void lower_complexexpr_stmt (gimple *);
   void lower_bit_query (gimple *);
+  void lower_bswap_bitreverse (gimple *);
   void lower_call (tree, gimple *);
   void lower_asm (gimple *);
   void lower_stmt (gimple *);
@@ -6106,6 +6107,181 @@  bitint_large_huge::lower_bit_query (gimp
     }
 }
 
+/* Lower a .{BSWAP,BITREVERSE} call with one large/huge _BitInt argument.  */
+
+void
+bitint_large_huge::lower_bswap_bitreverse (gimple *stmt)
+{
+  tree arg = gimple_call_arg (stmt, 0);
+  tree lhs = gimple_call_lhs (stmt);
+  gimple *g;
+
+  if (!lhs)
+    {
+      gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+      gsi_remove (&gsi, true);
+      return;
+    }
+  tree type = TREE_TYPE (arg);
+  gcc_assert (BITINT_TYPE_P (type));
+  bitint_prec_kind kind = bitint_precision_kind (type);
+  gcc_assert (kind >= bitint_prec_large);
+  int part = var_to_partition (m_map, lhs);
+  gcc_assert (m_vars[part] != NULL_TREE);
+  tree obj = m_vars[part];
+  enum internal_fn ifn = gimple_call_internal_fn (stmt);
+  enum built_in_function bcode = END_BUILTINS;
+  switch (limb_prec)
+    {
+    case 16:
+      bcode = ifn == IFN_BSWAP ? BUILT_IN_BSWAP16 : BUILT_IN_BITREVERSE16;
+      break;
+    case 32:
+      bcode = ifn == IFN_BSWAP ? BUILT_IN_BSWAP32 : BUILT_IN_BITREVERSE32;
+      break;
+    case 64:
+      bcode = ifn == IFN_BSWAP ? BUILT_IN_BSWAP64 : BUILT_IN_BITREVERSE64;
+      break;
+    case 128:
+      bcode = ifn == IFN_BSWAP ? BUILT_IN_BSWAP128 : BUILT_IN_BITREVERSE128;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  tree fndecl = builtin_decl_explicit (bcode);
+  unsigned prec = TYPE_PRECISION (type);
+  tree p = build_int_cst (sizetype,
+			  prec / limb_prec - (prec % limb_prec == 0));
+  /* For IFN .BSWAP or .BITREVERSE and
+     FN corresponding __builtin_bswapN or __builtin_bitreverseN where N
+     is limb_prec, lower
+       dst = IFN (src);
+     as
+       size_t p = prec / limb_prec - (prec % limb_prec == 0);
+       if constexpr ((prec % limb_prec) == 0)
+	 {
+	   for (idx = 0; idx <= p; ++idx)
+	     dst[p - idx] = FN (src[idx]);
+	 }
+       else
+	 {
+	   unsigned n1 = prec % limb_prec;
+	   unsigned n2 = limb_prec - n1;
+	   dst[p] = FN (src[0]) >> n2;
+	   for (idx = p - 1; (ssize_t) idx >= 0; --idx)
+	     dst[idx] = FN ((src[p - idx] << n2) | (src[p - idx - 1] >> n1));
+	 }  */
+  if (prec % limb_prec == 0)
+    {
+      tree idx_next;
+      tree idx = create_loop (size_zero_node, &idx_next);
+      tree pmidx = make_ssa_name (sizetype);
+      g = gimple_build_assign (pmidx, MINUS_EXPR, p, idx);
+      insert_before (g);
+      m_data_cnt = 0;
+      tree t = handle_operand (arg, idx);
+      m_first = false;
+      g = gimple_build_call (fndecl, 1, t);
+      t = make_ssa_name (m_limb_type);
+      gimple_call_set_lhs (g, t);
+      insert_before (g);
+      tree l = limb_access (TREE_TYPE (lhs), obj, pmidx, true);
+      g = gimple_build_assign (l, t);
+      insert_before (g);
+      g = gimple_build_assign (idx_next, PLUS_EXPR, idx, size_one_node);
+      insert_before (g);
+      g = gimple_build_cond (LE_EXPR, idx_next, p, NULL_TREE, NULL_TREE);
+      insert_before (g);
+    }
+  else
+    {
+      tree n1 = build_int_cst (unsigned_type_node, prec % limb_prec);
+      tree n2 = build_int_cst (unsigned_type_node,
+			       limb_prec - (prec % limb_prec));
+      m_data_cnt = 0;
+      tree t = handle_operand (arg, bitint_big_endian ? p : size_zero_node);
+      m_first = false;
+      /* Nothing is needed to bswap 8 bits or bitreverse 1 bit, so just
+	 mask off higher bits in that case.  */
+      if ((prec % limb_prec) != (ifn == IFN_BSWAP ? 8 : 1))
+	{
+	  g = gimple_build_call (fndecl, 1, t);
+	  t = make_ssa_name (m_limb_type);
+	  gimple_call_set_lhs (g, t);
+	  insert_before (g);
+	  g = gimple_build_assign (make_ssa_name (m_limb_type), RSHIFT_EXPR,
+				   t, n2);
+	}
+      else
+	g = gimple_build_assign (make_ssa_name (m_limb_type), BIT_AND_EXPR,
+				 t, build_int_cst (m_limb_type,
+						   ifn == IFN_BSWAP
+						   ? 0xff : 1));
+      insert_before (g);
+      t = gimple_assign_lhs (g);
+      tree l = limb_access (TREE_TYPE (lhs), obj,
+			    bitint_big_endian ? size_zero_node : p, true);
+      g = gimple_build_assign (l, t);
+      insert_before (g);
+      tree pm1 = build_int_cst (sizetype, prec / limb_prec - 1);
+      tree idx_next;
+      tree idx = create_loop (pm1, &idx_next);
+      tree pmidx = make_ssa_name (sizetype);
+      g = gimple_build_assign (pmidx, MINUS_EXPR, p, idx);
+      insert_before (g);
+      m_data_cnt = 0;
+      t = handle_operand (arg, bitint_big_endian ? idx : pmidx);
+      m_data_cnt = 0;
+      g = gimple_build_assign (make_ssa_name (m_limb_type), LSHIFT_EXPR,
+			       t, n2);
+      insert_before (g);
+      t = gimple_assign_lhs (g);
+      tree t2 = make_ssa_name (sizetype);
+      if (bitint_big_endian)
+	g = gimple_build_assign (t2, PLUS_EXPR, idx, size_one_node);
+      else
+	g = gimple_build_assign (t2, PLUS_EXPR, pmidx, size_int (-1));
+      insert_before (g);
+      t2 = handle_operand (arg, t2);
+      g = gimple_build_assign (make_ssa_name (m_limb_type), RSHIFT_EXPR,
+			       t2, n1);
+      insert_before (g);
+      t2 = gimple_assign_lhs (g);
+      g = gimple_build_assign (make_ssa_name (m_limb_type), BIT_IOR_EXPR,
+			       t, t2);
+      insert_before (g);
+      t = gimple_assign_lhs (g);
+      g = gimple_build_call (fndecl, 1, t);
+      t = make_ssa_name (m_limb_type);
+      gimple_call_set_lhs (g, t);
+      insert_before (g);
+      l = limb_access (TREE_TYPE (lhs), obj,
+		       bitint_big_endian ? pmidx : idx, true);
+      g = gimple_build_assign (l, t);
+      insert_before (g);
+      g = gimple_build_assign (idx_next, PLUS_EXPR, idx, size_int (-1));
+      insert_before (g);
+      g = gimple_build_cond (NE_EXPR, idx, size_zero_node, NULL_TREE,
+			     NULL_TREE);
+      insert_before (g);
+    }
+  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+  if (bitint_extended == bitint_ext_full
+      && abi_limb_prec > limb_prec
+      && (CEIL (prec, abi_limb_prec) * abi_limb_prec
+	  > CEIL (prec, limb_prec) * limb_prec))
+    {
+      m_gsi = gsi;
+      tree p2 = build_int_cst (sizetype,
+			       CEIL (prec, abi_limb_prec)
+			       * abi_limb_prec / limb_prec - 1);
+      tree l = limb_access (TREE_TYPE (lhs), obj, p2, true);
+      g = gimple_build_assign (l, build_zero_cst (m_limb_type));
+      insert_before (g);
+    }
+  gsi_remove (&gsi, true);
+}
+
 /* Lower a call statement with one or more large/huge _BitInt
    arguments or large/huge _BitInt return value.  */
 
@@ -6135,6 +6311,10 @@  bitint_large_huge::lower_call (tree obj,
       case IFN_POPCOUNT:
 	lower_bit_query (stmt);
 	return;
+      case IFN_BSWAP:
+      case IFN_BITREVERSE:
+	lower_bswap_bitreverse (stmt);
+	return;
       default:
 	break;
       }
@@ -6815,8 +6995,7 @@  build_bitint_stmt_ssa_conflicts (gimple
 	    }
 	}
     }
-  else if (bitint_big_endian
-	   && is_gimple_call (stmt)
+  else if (is_gimple_call (stmt)
 	   && gimple_call_internal_p (stmt))
     switch (gimple_call_internal_fn (stmt))
       {
@@ -6826,6 +7005,15 @@  build_bitint_stmt_ssa_conflicts (gimple
       case IFN_UBSAN_CHECK_SUB:
       case IFN_MUL_OVERFLOW:
       case IFN_UBSAN_CHECK_MUL:
+	if (bitint_big_endian)
+	  {
+	    lhs = gimple_call_lhs (stmt);
+	    if (lhs)
+	      muldiv_p = true;
+	  }
+	break;
+      case IFN_BSWAP:
+      case IFN_BITREVERSE:
 	lhs = gimple_call_lhs (stmt);
 	if (lhs)
 	  muldiv_p = true;
--- gcc/c-family/c-common.h.jj	2026-06-02 08:14:59.739207371 +0200
+++ gcc/c-family/c-common.h	2026-06-02 11:20:13.560983540 +0200
@@ -111,7 +111,8 @@  enum rid
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
   RID_BUILTIN_SHUFFLEVECTOR,   RID_BUILTIN_CONVERTVECTOR,  RID_BUILTIN_TGMATH,
   RID_BUILTIN_HAS_ATTRIBUTE,   RID_BUILTIN_ASSOC_BARRIER,  RID_BUILTIN_STDC,
-  RID_BUILTIN_COUNTED_BY_REF,
+  RID_BUILTIN_COUNTED_BY_REF,  RID_BUILTIN_BSWAPG,
+  RID_BUILTIN_BITREVERSEG,
   RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, RID_DFLOAT64X,
 
   /* TS 18661-3 keywords, in the same sequence as the TI_* values.  */
--- gcc/c-family/c-common.cc.jj	2026-06-02 08:15:04.495142958 +0200
+++ gcc/c-family/c-common.cc	2026-06-02 11:20:13.561741435 +0200
@@ -433,7 +433,9 @@  const struct c_common_resword c_common_r
   { "__auto_type",	RID_AUTO_TYPE,	D_CONLY },
   { "__builtin_addressof", RID_ADDRESSOF, D_CXXONLY },
   { "__builtin_assoc_barrier", RID_BUILTIN_ASSOC_BARRIER, 0 },
+  { "__builtin_bitreverseg", RID_BUILTIN_BITREVERSEG, 0 },
   { "__builtin_bit_cast", RID_BUILTIN_BIT_CAST, D_CXXONLY },
+  { "__builtin_bswapg", RID_BUILTIN_BSWAPG, 0 },
   { "__builtin_call_with_static_chain",
     RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY },
   { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
--- gcc/c/c-parser.cc.jj	2026-06-02 08:14:59.741207344 +0200
+++ gcc/c/c-parser.cc	2026-06-02 19:34:11.878325063 +0200
@@ -13530,6 +13530,83 @@  c_parser_postfix_expression (c_parser *p
 				       expr.value);
 	    break;
 	  }
+	case RID_BUILTIN_BSWAPG:
+	case RID_BUILTIN_BITREVERSEG:
+	  {
+	    vec<c_expr_t, va_gc> *cexpr_list;
+	    location_t close_paren_loc;
+	    internal_fn ifn
+	      = (c_parser_peek_token (parser)->keyword == RID_BUILTIN_BSWAPG
+		 ? IFN_BSWAP : IFN_BITREVERSE);
+	    const char *name
+	      = (ifn == IFN_BSWAP ? "__builtin_bswapg"
+		 : "__builtin_bitreverseg");
+
+	    c_parser_consume_token (parser);
+	    if (!c_parser_get_builtin_args (parser, name, &cexpr_list, false,
+					    &close_paren_loc))
+	      {
+		expr.set_error ();
+		break;
+	      }
+
+	    if (vec_safe_length (cexpr_list) != 1)
+	      {
+		error_at (loc, "wrong number of arguments to %qs", name);
+		expr.set_error ();
+		break;
+	      }
+
+	    c_expr_t *arg_p = &(*cexpr_list)[0];
+	    *arg_p = convert_lvalue_to_rvalue (loc, *arg_p, true, true);
+	    tree arg = arg_p->value;
+	    tree type = TYPE_MAIN_VARIANT (TREE_TYPE (arg));
+	    if (!INTEGRAL_TYPE_P (type))
+	      {
+		error_at (loc, "%qs operand not an integral type", name);
+		expr.set_error ();
+		break;
+	      }
+	    if (TREE_CODE (type) == ENUMERAL_TYPE)
+	      {
+		error_at (loc, "argument %u in call to function "
+			  "%qs has enumerated type", 1, name);
+		expr.set_error ();
+		break;
+	      }
+	    if (TREE_CODE (type) == BOOLEAN_TYPE)
+	      {
+		error_at (loc, "argument %u in call to function "
+			  "%qs has boolean type", 1, name);
+		expr.set_error ();
+		break;
+	      }
+	    if (!TYPE_UNSIGNED (type))
+	      {
+		error_at (loc, "argument 1 in call to function "
+			  "%qs has signed type", name);
+		expr.set_error ();
+		break;
+	      }
+	    if (type == char_type_node)
+	      {
+		error_at (loc, "argument 1 in call to function "
+			  "%qs has %<char%> type", name);
+		expr.set_error ();
+		break;
+	      }
+	    if (ifn == IFN_BSWAP && (TYPE_PRECISION (type) % 8) != 0)
+	      {
+		error_at (loc, "precision %d of argument 1 to function "
+			  "%qs is not a multiple of 8",
+			  TYPE_PRECISION (type), name);
+		expr.set_error ();
+		break;
+	      }
+	    expr.value = fold_build_builtin_bswapg_bitreverseg (loc, ifn, arg);
+	    set_c_expr_source_range (&expr, loc, close_paren_loc);
+	    break;
+	  }
 	case RID_AT_SELECTOR:
 	  {
 	    gcc_assert (c_dialect_objc ());
--- gcc/cp/parser.cc.jj	2026-06-02 08:15:04.592141644 +0200
+++ gcc/cp/parser.cc	2026-06-02 11:35:20.211913589 +0200
@@ -8617,6 +8617,8 @@  cp_parser_postfix_expression (cp_parser
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_OPERATOR_NEW:
     case RID_BUILTIN_OPERATOR_DELETE:
+    case RID_BUILTIN_BSWAPG:
+    case RID_BUILTIN_BITREVERSEG:
       {
 	vec<tree, va_gc> *vec;
 
@@ -8736,6 +8738,32 @@  cp_parser_postfix_expression (cp_parser
 	      }
 	    break;
 
+	  case RID_BUILTIN_BSWAPG:
+	    if (vec->length () == 1)
+	      postfix_expression
+		= build_x_bswapg_bitreverseg (loc, IFN_BSWAP, vec,
+					      tf_warning_or_error);
+	    else
+	      {
+		error_at (loc, "wrong number of arguments to "
+			       "%<__builtin_bswapg%>");
+		postfix_expression = error_mark_node;
+	      }
+	    break;
+
+	  case RID_BUILTIN_BITREVERSEG:
+	    if (vec->length () == 1)
+	      postfix_expression
+		= build_x_bswapg_bitreverseg (loc, IFN_BITREVERSE, vec,
+					      tf_warning_or_error);
+	    else
+	      {
+		error_at (loc, "wrong number of arguments to "
+			       "%<__builtin_bitreverseg%>");
+		postfix_expression = error_mark_node;
+	      }
+	    break;
+
 	  default:
 	    gcc_unreachable ();
 	  }
--- gcc/cp/typeck.cc.jj	2026-05-29 10:08:33.380536476 +0200
+++ gcc/cp/typeck.cc	2026-06-02 12:48:53.944496483 +0200
@@ -7111,6 +7111,72 @@  build_x_shufflevector (location_t loc, v
     }
   return exp;
 }
+
+/* Build __builtin_bswapg (ARG) or __builtin_bitreverseg (ARG).  */
+tree
+build_x_bswapg_bitreverseg (location_t loc, internal_fn ifn,
+			    vec<tree, va_gc> *args, tsubst_flags_t complain)
+{
+  tree arg = (*args)[0];
+  if (type_dependent_expression_p (arg))
+    {
+      tree exp = build_min_nt_call_vec (NULL, args);
+      CALL_EXPR_IFN (exp) = ifn;
+      return exp;
+    }
+  const char *name
+    = ifn == IFN_BSWAP ? "__builtin_bswapg" : "__builtin_bitreverseg";
+  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (arg));
+  if (!INTEGRAL_TYPE_P (type))
+    {
+      if (complain & tf_error)
+	error_at (loc, "%qs operand not an integral type", name);
+      return error_mark_node;
+    }
+  if (TREE_CODE (type) == ENUMERAL_TYPE)
+    {
+      if (complain & tf_error)
+	error_at (loc, "argument %u in call to function "
+		       "%qs has enumerated type", 1, name);
+      return error_mark_node;
+    }
+  if (TREE_CODE (type) == BOOLEAN_TYPE)
+    {
+      if (complain & tf_error)
+	error_at (loc, "argument %u in call to function "
+		       "%qs has boolean type", 1, name);
+      return error_mark_node;
+    }
+  if (!TYPE_UNSIGNED (type))
+    {
+      if (complain & tf_error)
+	error_at (loc, "argument 1 in call to function "
+		       "%qs has signed type", name);
+      return error_mark_node;
+    }
+  if (type == char_type_node)
+    {
+      if (complain & tf_error)
+	error_at (loc, "argument 1 in call to function "
+		       "%qs has %<char%> type", name);
+      return error_mark_node;
+    }
+  if (ifn == IFN_BSWAP && (TYPE_PRECISION (type) % 8) != 0)
+    {
+      if (complain & tf_error)
+	error_at (loc, "precision %d of argument 1 to function "
+		       "%qs is not a multiple of 8",
+		  TYPE_PRECISION (type), name);
+      return error_mark_node;
+    }
+  tree exp = build_call_expr_internal_loc (loc, ifn, type, 1, arg);
+  if (processing_template_decl)
+    {
+      exp = build_min_non_dep_call_vec (exp, NULL, args);
+      CALL_EXPR_IFN (exp) = ifn;
+    }
+  return exp;
+}
 
 /* Return a tree for the sum or difference (RESULTCODE says which)
    of pointer PTROP and integer INTOP.  */
--- gcc/cp/cp-tree.h.jj	2026-05-30 17:45:09.365110027 +0200
+++ gcc/cp/cp-tree.h	2026-06-02 11:41:54.609714752 +0200
@@ -9050,6 +9050,9 @@  extern tree build_x_vec_perm_expr
 extern tree build_x_shufflevector               (location_t,
 						 vec<tree, va_gc> *,
 						 tsubst_flags_t);
+extern tree build_x_bswapg_bitreverseg		(location_t, internal_fn,
+						 vec<tree, va_gc> *,
+						 tsubst_flags_t);
 #define cxx_sizeof(T)  cxx_sizeof_or_alignof_type (input_location, T, SIZEOF_EXPR, false, true)
 extern tree build_simple_component_ref		(tree, tree);
 extern tree build_ptrmemfunc_access_expr	(tree, tree);
--- gcc/cp/pt.cc.jj	2026-05-30 17:49:11.819041571 +0200
+++ gcc/cp/pt.cc	2026-06-02 11:43:39.750328823 +0200
@@ -22468,6 +22468,17 @@  tsubst_expr (tree t, tree args, tsubst_f
 		break;
 	      }
 
+	    case IFN_BSWAP:
+	    case IFN_BITREVERSE:
+	      {
+		ret = build_x_bswapg_bitreverseg (input_location,
+						  CALL_EXPR_IFN (t), call_args,
+						  complain);
+		if (ret != error_mark_node)
+		  RETURN (ret);
+		break;
+	      }
+
 	    case IFN_ASSUME:
 	      gcc_assert (nargs == 1);
 	      if (vec_safe_length (call_args) != 1)
--- gcc/cp/constexpr.cc.jj	2026-05-30 17:45:09.363110052 +0200
+++ gcc/cp/constexpr.cc	2026-06-02 12:54:58.012735377 +0200
@@ -3245,6 +3245,30 @@  cxx_eval_internal_function (const conste
     case IFN_DEFERRED_INIT:
       return build_clobber (TREE_TYPE (t), CLOBBER_OBJECT_BEGIN);
 
+    case IFN_BSWAP:
+    case IFN_BITREVERSE:
+      {
+	tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
+						 vc_prvalue, non_constant_p,
+						 overflow_p, jump_target);
+	if (*jump_target)
+	  return NULL_TREE;
+	location_t loc = cp_expr_loc_or_input_loc (t);
+	if (TREE_CODE (arg) != INTEGER_CST
+	    || !INTEGRAL_TYPE_P (TREE_TYPE (arg))
+	    || !TYPE_UNSIGNED (TREE_TYPE (arg))
+	    || (CALL_EXPR_IFN (t) == IFN_BSWAP
+		&& (TYPE_PRECISION (TREE_TYPE (arg)) % 8) != 0))
+	  {
+	    if (!ctx->quiet)
+	      error_at (loc, "call to internal function %qE", t);
+	    *non_constant_p = true;
+	    return t;
+	  }
+	return fold_build_builtin_bswapg_bitreverseg (loc, CALL_EXPR_IFN (t),
+						      arg);
+      }
+
     case IFN_VEC_CONVERT:
       {
 	tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
@@ -12026,6 +12050,8 @@  potential_constant_expression_1 (tree t,
 		case IFN_MUL_OVERFLOW:
 		case IFN_LAUNDER:
 		case IFN_VEC_CONVERT:
+		case IFN_BSWAP:
+		case IFN_BITREVERSE:
 		  bail = false;
 		  break;
 
--- gcc/cp/cp-gimplify.cc.jj	2026-05-26 16:32:28.611304806 +0200
+++ gcc/cp/cp-gimplify.cc	2026-06-02 12:47:52.178304231 +0200
@@ -44,6 +44,7 @@  along with GCC; see the file COPYING3.
 #include "opts.h"
 #include "gcc-urlifier.h"
 #include "contracts.h" // build_contract_check ()
+#include "builtins.h"
 
 /* Keep track of forward references to immediate-escalating functions in
    case they become consteval.  This vector contains ADDR_EXPRs and
@@ -880,7 +881,29 @@  cp_gimplify_expr (tree *expr_p, gimple_s
 	      = build1 (NOP_EXPR, fnptrtype, CALL_EXPR_FN (*expr_p));
 	}
       if (!CALL_EXPR_FN (*expr_p))
-	/* Internal function call.  */;
+	/* Internal function call.  */
+	switch (CALL_EXPR_IFN (*expr_p))
+	  {
+	  case IFN_BSWAP:
+	  case IFN_BITREVERSE:
+	    if (ret == GS_OK)
+	      {
+		location_t loc = EXPR_LOCATION (*expr_p);
+		internal_fn ifn = CALL_EXPR_IFN (*expr_p);
+		tree arg = CALL_EXPR_ARG (*expr_p, 0);
+		tree r = fold_build_builtin_bswapg_bitreverseg (loc, ifn,
+								arg);
+		if (TREE_CODE (r) == CALL_EXPR
+		    && !CALL_EXPR_FN (r)
+		    && CALL_EXPR_IFN (r) == ifn)
+		  break;
+		*expr_p = r;
+		return ret;
+	      }
+	    break;
+	  default:
+	    break;
+	  }
       else if (CALL_EXPR_REVERSE_ARGS (*expr_p))
 	{
 	  /* This is a call to a (compound) assignment operator that used
--- gcc/testsuite/c-c++-common/builtin-bswapg-1.c.jj	2026-06-02 18:55:52.546730877 +0200
+++ gcc/testsuite/c-c++-common/builtin-bswapg-1.c	2026-06-02 18:53:23.591654474 +0200
@@ -0,0 +1,153 @@ 
+/* Test __builtin_bswapg.  */
+/* { dg-do run { target { c || c++11 } } } */
+/* { dg-options "-O2" } */
+
+#if __CHAR_BIT__ == 8
+#if __SIZEOF_INT__ == 4
+static_assert (__builtin_bswapg (0x12345678U) == 0x78563412U, "");
+#endif
+#if __SIZEOF_LONG_LONG__ == 8
+static_assert (__builtin_bswapg (0x123456789abcdef0ULL) == 0xf0debc9a78563412ULL, "");
+#endif
+static_assert (__builtin_bswapg ((unsigned char) 0x23) == (unsigned char) 0x23, "");
+#if __SIZEOF_SHORT__ == 2
+static_assert (__builtin_bswapg ((unsigned short) 0x2345) == (unsigned short) 0x4523, "");
+#endif
+#if __SIZEOF_INT128__ == 16
+static_assert (__builtin_bswapg ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
+				 | 0x23456789abcdef01ULL)
+				 == ((((unsigned __int128) 0x01efcdab89674523ULL) << 64)
+				     | 0xf0debc9a78563412ULL), "");
+#endif
+#endif
+#if __BITINT_MAXWIDTH__ >= 856
+static_assert (__builtin_bswapg (0xabcdefuwb) == 0xefcdabuwb, "");
+static_assert (__builtin_bswapg (0xabcdef8081uwb) == 0x8180efcdabuwb, "");
+static_assert (__builtin_bswapg ((unsigned _BitInt(136)) 0x66b52574b5fd190b15a1b99858c27d0ac2uwb)
+	       == 0xc20a7dc25898b9a1150b19fdb57425b566uwb, "");
+static_assert (__builtin_bswapg ((unsigned _BitInt(832)) 0x021256fc7a59ee4dab277edcadfdbfd45c0690f99249cf9e31ad0b16f91a0efb2d64f8a7bde6f4680d7244ba70038ecc091fc59c68943a994146b03a60be368d222e34e0142948229b8ddc0b906bd79a8a9c36f230708b71b63bac17f9e2a41c10d9fc240244469duwb)
+	       == 0x9d46440224fcd9101ca4e2f917ac3bb6718b7030f2369c8a9ad76b900bdc8d9b22482914e0342e228d36be603ab04641993a94689cc51f09cc8e0370ba44720d68f4e6bda7f8642dfb0e1af9160bad319ecf4992f990065cd4bffdaddc7e27ab4dee597afc561202uwb, "");
+static_assert (__builtin_bswapg ((unsigned _BitInt(840)) 0x4c23edce0b5ffd538da2112c333d17f100a0db44f7c9cfb097538e995f3a5bab5d487969a776bc3518cd614b0a783d0b18184f10e11ec078714f11d0896c7be6b5f54f5c6b0c9184d9f3cfe46b0cef84243e94055d547dcea38f9f2cfb1a13b00f620d7b6e9eff4891uwb)
+	       == 0x9148ff9e6e7b0d620fb0131afb2c9f8fa3ce7d545d05943e2484ef0c6be4cff3d984910c6b5c4ff5b5e67b6c89d0114f7178c01ee1104f18180b3d780a4b61cd1835bc76a76979485dab5b3a5f998e5397b0cfc9f744dba000f1173d332c11a28d53fd5f0bceed234cuwb, "");
+static_assert (__builtin_bswapg ((unsigned _BitInt(856)) 0x41c39e2f987be9c81688ecc08a4ded319e4010952ecb6e4ac738a6924d81668f4404bedd7fa7a5952f9156bade43eb7d83fb12b2c780fc8eb9a22006238695678a53440afbe99f2a7af5e45938cfd6bccbe86e92696a20220c41282fc7be965211db5c0cc4fb373ff11b98uwb)
+	       == 0x981bf13f37fbc40c5cdb115296bec72f28410c22206a69926ee8cbbcd6cf3859e4f57a2a9fe9fb0a44538a679586230620a2b98efc80c7b212fb837deb43deba56912f95a5a77fddbe04448f66814d92a638c74a6ecb2e9510409e31ed4d8ac0ec8816c8e97b982f9ec341uwb, "");
+#endif
+
+#if __CHAR_BIT__ == 8
+#if __SIZEOF_INT__ == 4
+[[gnu::noipa]] unsigned
+bswap32 (unsigned x)
+{
+  return __builtin_bswapg (x);
+}
+#endif
+#if __SIZEOF_LONG_LONG__ == 8
+[[gnu::noipa]] unsigned long long
+bswap64 (unsigned long long x)
+{
+  return __builtin_bswapg (x);
+}
+#endif
+[[gnu::noipa]] unsigned char
+bswap8 (unsigned char x)
+{
+  return __builtin_bswapg (x);
+}
+#if __SIZEOF_SHORT__ == 2
+[[gnu::noipa]] unsigned short
+bswap16 (unsigned short x)
+{
+  return __builtin_bswapg (x);
+}
+#endif
+#if __SIZEOF_INT128__ == 16
+[[gnu::noipa]] unsigned __int128
+bswap128 (unsigned __int128 x)
+{
+  return __builtin_bswapg (x);
+}
+#endif
+#endif
+#if __BITINT_MAXWIDTH__ >= 856
+[[gnu::noipa]] unsigned _BitInt(24)
+bswap24 (unsigned _BitInt(24) x)
+{
+  return __builtin_bswapg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(40)
+bswap40 (unsigned _BitInt(40) x)
+{
+  return __builtin_bswapg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(136)
+bswap136 (unsigned _BitInt(136) x)
+{
+  return __builtin_bswapg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(832)
+bswap832 (unsigned _BitInt(832) x)
+{
+  return __builtin_bswapg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(840)
+bswap840 (unsigned _BitInt(840) x)
+{
+  return __builtin_bswapg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(856)
+bswap856 (unsigned _BitInt(856) x)
+{
+  return __builtin_bswapg (x);
+}
+#endif
+
+int
+main ()
+{
+#if __CHAR_BIT__ == 8
+#if __SIZEOF_INT__ == 4
+  if (bswap32 (0x12345678U) != 0x78563412U)
+    __builtin_abort ();
+#endif
+#if __SIZEOF_LONG_LONG__ == 8
+  if (bswap64 (0x123456789abcdef0ULL) != 0xf0debc9a78563412ULL)
+    __builtin_abort ();
+#endif
+  if (bswap8 ((unsigned char) 0x23) != (unsigned char) 0x23)
+    __builtin_abort ();
+#if __SIZEOF_SHORT__ == 2
+  if (bswap16 ((unsigned short) 0x2345) != (unsigned short) 0x4523)
+    __builtin_abort ();
+#endif
+#if __SIZEOF_INT128__ == 16
+  if (bswap128 ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
+		| 0x23456789abcdef01ULL)
+      != ((((unsigned __int128) 0x01efcdab89674523ULL) << 64)
+	  | 0xf0debc9a78563412ULL))
+    __builtin_abort ();
+#endif
+#endif
+#if __BITINT_MAXWIDTH__ >= 856
+  if (bswap24 (0xabcdefuwb) != 0xefcdabuwb)
+    __builtin_abort ();
+  if (bswap40 (0xabcdef8081uwb) != 0x8180efcdabuwb)
+    __builtin_abort ();
+  if (bswap136 (0x66b52574b5fd190b15a1b99858c27d0ac2uwb)
+      != 0xc20a7dc25898b9a1150b19fdb57425b566uwb)
+    __builtin_abort ();
+  if (bswap832 (0x021256fc7a59ee4dab277edcadfdbfd45c0690f99249cf9e31ad0b16f91a0efb2d64f8a7bde6f4680d7244ba70038ecc091fc59c68943a994146b03a60be368d222e34e0142948229b8ddc0b906bd79a8a9c36f230708b71b63bac17f9e2a41c10d9fc240244469duwb)
+      != 0x9d46440224fcd9101ca4e2f917ac3bb6718b7030f2369c8a9ad76b900bdc8d9b22482914e0342e228d36be603ab04641993a94689cc51f09cc8e0370ba44720d68f4e6bda7f8642dfb0e1af9160bad319ecf4992f990065cd4bffdaddc7e27ab4dee597afc561202uwb)
+    __builtin_abort ();
+  if (bswap840 (0x4c23edce0b5ffd538da2112c333d17f100a0db44f7c9cfb097538e995f3a5bab5d487969a776bc3518cd614b0a783d0b18184f10e11ec078714f11d0896c7be6b5f54f5c6b0c9184d9f3cfe46b0cef84243e94055d547dcea38f9f2cfb1a13b00f620d7b6e9eff4891uwb)
+      != 0x9148ff9e6e7b0d620fb0131afb2c9f8fa3ce7d545d05943e2484ef0c6be4cff3d984910c6b5c4ff5b5e67b6c89d0114f7178c01ee1104f18180b3d780a4b61cd1835bc76a76979485dab5b3a5f998e5397b0cfc9f744dba000f1173d332c11a28d53fd5f0bceed234cuwb)
+    __builtin_abort ();
+  if (bswap856 (0x41c39e2f987be9c81688ecc08a4ded319e4010952ecb6e4ac738a6924d81668f4404bedd7fa7a5952f9156bade43eb7d83fb12b2c780fc8eb9a22006238695678a53440afbe99f2a7af5e45938cfd6bccbe86e92696a20220c41282fc7be965211db5c0cc4fb373ff11b98uwb)
+      != 0x981bf13f37fbc40c5cdb115296bec72f28410c22206a69926ee8cbbcd6cf3859e4f57a2a9fe9fb0a44538a679586230620a2b98efc80c7b212fb837deb43deba56912f95a5a77fddbe04448f66814d92a638c74a6ecb2e9510409e31ed4d8ac0ec8816c8e97b982f9ec341uwb)
+    __builtin_abort ();
+#endif
+}
--- gcc/testsuite/c-c++-common/builtin-bswapg-2.c.jj	2026-06-02 19:00:30.252144603 +0200
+++ gcc/testsuite/c-c++-common/builtin-bswapg-2.c	2026-06-02 19:28:21.081815725 +0200
@@ -0,0 +1,21 @@ 
+/* Test __builtin_bswapg.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+int
+main ()
+{
+  __builtin_bswapg ();		/* { dg-error "wrong number of arguments to '__builtin_bswapg'" } */
+  __builtin_bswapg (1U, 1U);	/* { dg-error "wrong number of arguments to '__builtin_bswapg'" } */
+  __builtin_bswapg (1.0);	/* { dg-error "'__builtin_bswapg' operand not an integral type" } */
+  __builtin_bswapg (1.0f);	/* { dg-error "'__builtin_bswapg' operand not an integral type" } */
+  __builtin_bswapg (1.0L);	/* { dg-error "'__builtin_bswapg' operand not an integral type" } */
+  struct S { int a; };
+  __builtin_bswapg ((struct S) { 42 });	/* { dg-error "'__builtin_bswapg' operand not an integral type" } */
+  enum E { E0, E1 };
+  __builtin_bswapg (E1);	/* { dg-error "argument 1 in call to function '__builtin_bswapg' has signed type" "" { target c } } */
+				/* { dg-error "argument 1 in call to function '__builtin_bswapg' has enumerated type" "" { target c++ } .-1 } */
+  __builtin_bswapg (false);	/* { dg-error "argument 1 in call to function '__builtin_bswapg' has boolean type" } */
+  __builtin_bswapg (1);		/* { dg-error "argument 1 in call to function '__builtin_bswapg' has signed type" } */
+  __builtin_bswapg ((char) 1);	/* { dg-error "(?:argument 1 in call to function '__builtin_bswapg' has signed type|argument 1 in call to function '__builtin_bswapg' has 'char' type)" } */
+}
--- gcc/testsuite/c-c++-common/builtin-bswapg-3.c.jj	2026-06-02 19:28:56.451362952 +0200
+++ gcc/testsuite/c-c++-common/builtin-bswapg-3.c	2026-06-02 19:32:28.058654098 +0200
@@ -0,0 +1,15 @@ 
+/* Test __builtin_bswapg.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+int
+main ()
+{
+#if __BITINT_MAXWIDTH__ >= 575
+  __builtin_bswapg (0x0uwb);	/* { dg-error "precision 1 of argument 1 to function '__builtin_bswapg' is not a multiple of 8" "" { target bitint575 } } */
+  __builtin_bswapg (0x3uwb);	/* { dg-error "precision 2 of argument 1 to function '__builtin_bswapg' is not a multiple of 8" "" { target bitint575 } } */
+  __builtin_bswapg (0x34938571398572uwb); /* { dg-error "precision 54 of argument 1 to function '__builtin_bswapg' is not a multiple of 8" "" { target bitint575 } } */
+  __builtin_bswapg (0x34938571398572abcd9837298dabef9187983uwb); /* { dg-error "precision 146 of argument 1 to function '__builtin_bswapg' is not a multiple of 8" "" { target bitint575 } } */
+  __builtin_bswapg (0x34938571398572abcd9837298dabef918798329387987abef98792837549857983745983475329847uwb); /* { dg-error "precision 322 of argument 1 to function '__builtin_bswapg' is not a multiple of 8" "" { target bitint575 } } */
+#endif
+}
--- gcc/testsuite/c-c++-common/builtin-bitreverseg-1.c.jj	2026-06-02 18:55:52.546730877 +0200
+++ gcc/testsuite/c-c++-common/builtin-bitreverseg-1.c	2026-06-02 20:31:04.876355418 +0200
@@ -0,0 +1,164 @@ 
+/* Test __builtin_bitreverseg.  */
+/* { dg-do run { target { c || c++11 } } } */
+/* { dg-options "-O2" } */
+
+#if __CHAR_BIT__ == 8
+#if __SIZEOF_INT__ == 4
+static_assert (__builtin_bitreverseg (0x2fa889a7U) == 0xe59115f4U, "");
+#endif
+#if __SIZEOF_LONG_LONG__ == 8
+static_assert (__builtin_bitreverseg (0xd7632f428bdccb94ULL) == 0x29d33bd142f4c6ebULL, "");
+#endif
+static_assert (__builtin_bitreverseg ((unsigned char) 0xac) == (unsigned char) 0x35, "");
+#if __SIZEOF_SHORT__ == 2
+static_assert (__builtin_bitreverseg ((unsigned short) 0xc4f0) == (unsigned short) 0x0f23, "");
+#endif
+#if __SIZEOF_INT128__ == 16
+static_assert (__builtin_bitreverseg ((((unsigned __int128) 0x398773ddb9250c54ULL) << 64)
+				 | 0x26933639cdf63ea6ULL)
+				 == ((((unsigned __int128) 0x657c6fb39c6cc964ULL) << 64)
+				     | 0x2a30a49dbbcee19cULL), "");
+#endif
+#endif
+#if __BITINT_MAXWIDTH__ >= 856
+static_assert (__builtin_bitreverseg (0xb75774uwb) == 0x2eeaeduwb, "");
+static_assert (__builtin_bitreverseg (0xd55668c010uwb) == 0x0803166aabuwb, "");
+static_assert (__builtin_bitreverseg ((unsigned _BitInt(129)) 0x01cc4426458663d6c35ad6f0c7117fc2b7uwb)
+	       == 0x01da87fd11c61ed6b586d78cc344c84467uwb, "");
+static_assert (__builtin_bitreverseg ((unsigned _BitInt(136)) 0xc73210faaad84376ebd396f82a166ac5f9uwb)
+	       == 0x9fa35668541f69cbd76ec21b555f084ce3uwb, "");
+static_assert (__builtin_bitreverseg ((unsigned _BitInt(832)) 0x09d2702b49ac2e9b1010df028451dceaf2cf9938035fa708921fb53a5d509d66220d916bb9bf07c9cfe6cc5437a83e2977d7617a360882c82838038588a0ecaaae7d16673d1d310c03fd603aa59f631c76c497adcc1975f451787ad9196684c7e39a2e20b75f2dbauwb)
+	       == 0x5db4faed047459c7e32166989b5e1e8a2fae9833b5e9236e38c6f9a55c06bfc0308cb8bce668be7555370511a1c01c141341106c5e86ebee947c15ec2a3367f393e0fd9dd689b04466b90aba5cadf84910e5fac01c99f34f573b8a2140fb0808d9743592d40e4b90uwb, "");
+static_assert (__builtin_bitreverseg ((unsigned _BitInt(833)) 0x0054078b08ef56720bb2a2cc52ddac983838de381c548c346e0b4274d51635f36b3c7e732bd4e536868702d864ae709ce74fd403a36037116c79854190bb34fbf7b26e238654590cdb5ce4400a54dcf1a3b1f546112c587da6ddbe3698f23190a49fb32af30c36cf68uwb)
+	       == 0x002de6d8619ea99bf24a13189e32d8fb76cb7c346910c55f1b8b1e7654a0044e75b6613454c388ec9bdfbe59ba1305433c6d11d80d8b8057e5ce721cea4c3681c2c2d94e57a99cfc79ad9f58d1565c85a0ec5862547038f63838326b7694668a9ba09cd5ee21a3c054uwb, "");
+static_assert (__builtin_bitreverseg ((unsigned _BitInt(856)) 0x6aa3d211688a1bc275204e2e83f7ecacfdc42aecdc1ae8093b901c207dc089e8645bf9cce6148e5b34dc89b7d47563d13a8ebd16a8a51fe3353b04b3fc8d9b60e9942ccfa8bb2adc97b4936b29f63c6384f9792c9f9810d4d41487d0a122308ab65c595e17843aaf38cd1auwb)
+	       == 0x58b31cf55c21e87a9a3a6d510c44850be1282b2b0819f9349e9f21c63c6f94d6c92de93b54dd15f334299706d9b13fcd20dcacc7f8a51568bd715c8bc6ae2bed913b2cda712867339fda26179103be043809dc9017583b375423bf3537efc1747204ae43d85116884bc556uwb, "");
+#endif
+
+#if __CHAR_BIT__ == 8
+#if __SIZEOF_INT__ == 4
+[[gnu::noipa]] unsigned
+bitreverse32 (unsigned x)
+{
+  return __builtin_bitreverseg (x);
+}
+#endif
+#if __SIZEOF_LONG_LONG__ == 8
+[[gnu::noipa]] unsigned long long
+bitreverse64 (unsigned long long x)
+{
+  return __builtin_bitreverseg (x);
+}
+#endif
+[[gnu::noipa]] unsigned char
+bitreverse8 (unsigned char x)
+{
+  return __builtin_bitreverseg (x);
+}
+#if __SIZEOF_SHORT__ == 2
+[[gnu::noipa]] unsigned short
+bitreverse16 (unsigned short x)
+{
+  return __builtin_bitreverseg (x);
+}
+#endif
+#if __SIZEOF_INT128__ == 16
+[[gnu::noipa]] unsigned __int128
+bitreverse128 (unsigned __int128 x)
+{
+  return __builtin_bitreverseg (x);
+}
+#endif
+#endif
+#if __BITINT_MAXWIDTH__ >= 856
+[[gnu::noipa]] unsigned _BitInt(24)
+bitreverse24 (unsigned _BitInt(24) x)
+{
+  return __builtin_bitreverseg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(40)
+bitreverse40 (unsigned _BitInt(40) x)
+{
+  return __builtin_bitreverseg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(129)
+bitreverse129 (unsigned _BitInt(129) x)
+{
+  return __builtin_bitreverseg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(136)
+bitreverse136 (unsigned _BitInt(136) x)
+{
+  return __builtin_bitreverseg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(832)
+bitreverse832 (unsigned _BitInt(832) x)
+{
+  return __builtin_bitreverseg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(833)
+bitreverse833 (unsigned _BitInt(833) x)
+{
+  return __builtin_bitreverseg (x);
+}
+
+[[gnu::noipa]] unsigned _BitInt(856)
+bitreverse856 (unsigned _BitInt(856) x)
+{
+  return __builtin_bitreverseg (x);
+}
+#endif
+
+int
+main ()
+{
+#if __CHAR_BIT__ == 8
+#if __SIZEOF_INT__ == 4
+  if (bitreverse32 (0x2fa889a7U) != 0xe59115f4U)
+    __builtin_abort ();
+#endif
+#if __SIZEOF_LONG_LONG__ == 8
+  if (bitreverse64 (0xd7632f428bdccb94ULL) != 0x29d33bd142f4c6ebULL)
+    __builtin_abort ();
+#endif
+  if (bitreverse8 ((unsigned char) 0xac) != (unsigned char) 0x35)
+    __builtin_abort ();
+#if __SIZEOF_SHORT__ == 2
+  if (bitreverse16 ((unsigned short) 0xc4f0) != (unsigned short) 0x0f23)
+    __builtin_abort ();
+#endif
+#if __SIZEOF_INT128__ == 16
+  if (bitreverse128 ((((unsigned __int128) 0x398773ddb9250c54ULL) << 64)
+		| 0x26933639cdf63ea6ULL)
+      != ((((unsigned __int128) 0x657c6fb39c6cc964ULL) << 64)
+	  | 0x2a30a49dbbcee19cULL))
+    __builtin_abort ();
+#endif
+#endif
+#if __BITINT_MAXWIDTH__ >= 856
+  if (bitreverse24 (0xb75774uwb) != 0x2eeaed)
+    __builtin_abort ();
+  if (bitreverse40 (0xd55668c010uwb) != 0x0803166aabuwb)
+    __builtin_abort ();
+  if (bitreverse129 (0x01cc4426458663d6c35ad6f0c7117fc2b7uwb)
+	       != 0x01da87fd11c61ed6b586d78cc344c84467uwb)
+    __builtin_abort ();
+  if (bitreverse136 (0xc73210faaad84376ebd396f82a166ac5f9uwb)
+      != 0x9fa35668541f69cbd76ec21b555f084ce3uwb)
+    __builtin_abort ();
+  if (bitreverse832 (0x09d2702b49ac2e9b1010df028451dceaf2cf9938035fa708921fb53a5d509d66220d916bb9bf07c9cfe6cc5437a83e2977d7617a360882c82838038588a0ecaaae7d16673d1d310c03fd603aa59f631c76c497adcc1975f451787ad9196684c7e39a2e20b75f2dbauwb)
+      != 0x5db4faed047459c7e32166989b5e1e8a2fae9833b5e9236e38c6f9a55c06bfc0308cb8bce668be7555370511a1c01c141341106c5e86ebee947c15ec2a3367f393e0fd9dd689b04466b90aba5cadf84910e5fac01c99f34f573b8a2140fb0808d9743592d40e4b90uwb)
+    __builtin_abort ();
+  if (bitreverse833 (0x0054078b08ef56720bb2a2cc52ddac983838de381c548c346e0b4274d51635f36b3c7e732bd4e536868702d864ae709ce74fd403a36037116c79854190bb34fbf7b26e238654590cdb5ce4400a54dcf1a3b1f546112c587da6ddbe3698f23190a49fb32af30c36cf68uwb)
+      != 0x002de6d8619ea99bf24a13189e32d8fb76cb7c346910c55f1b8b1e7654a0044e75b6613454c388ec9bdfbe59ba1305433c6d11d80d8b8057e5ce721cea4c3681c2c2d94e57a99cfc79ad9f58d1565c85a0ec5862547038f63838326b7694668a9ba09cd5ee21a3c054uwb)
+    __builtin_abort ();
+  if (bitreverse856 (0x6aa3d211688a1bc275204e2e83f7ecacfdc42aecdc1ae8093b901c207dc089e8645bf9cce6148e5b34dc89b7d47563d13a8ebd16a8a51fe3353b04b3fc8d9b60e9942ccfa8bb2adc97b4936b29f63c6384f9792c9f9810d4d41487d0a122308ab65c595e17843aaf38cd1auwb)
+      != 0x58b31cf55c21e87a9a3a6d510c44850be1282b2b0819f9349e9f21c63c6f94d6c92de93b54dd15f334299706d9b13fcd20dcacc7f8a51568bd715c8bc6ae2bed913b2cda712867339fda26179103be043809dc9017583b375423bf3537efc1747204ae43d85116884bc556uwb)
+    __builtin_abort ();
+#endif
+}
--- gcc/testsuite/c-c++-common/builtin-bitreverseg-2.c.jj	2026-06-02 19:00:30.252144603 +0200
+++ gcc/testsuite/c-c++-common/builtin-bitreverseg-2.c	2026-06-02 20:18:23.575187233 +0200
@@ -0,0 +1,21 @@ 
+/* Test __builtin_bitreverseg.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+int
+main ()
+{
+  __builtin_bitreverseg ();		/* { dg-error "wrong number of arguments to '__builtin_bitreverseg'" } */
+  __builtin_bitreverseg (1U, 1U);	/* { dg-error "wrong number of arguments to '__builtin_bitreverseg'" } */
+  __builtin_bitreverseg (1.0);		/* { dg-error "'__builtin_bitreverseg' operand not an integral type" } */
+  __builtin_bitreverseg (1.0f);		/* { dg-error "'__builtin_bitreverseg' operand not an integral type" } */
+  __builtin_bitreverseg (1.0L);		/* { dg-error "'__builtin_bitreverseg' operand not an integral type" } */
+  struct S { int a; };
+  __builtin_bitreverseg ((struct S) { 42 });	/* { dg-error "'__builtin_bitreverseg' operand not an integral type" } */
+  enum E { E0, E1 };
+  __builtin_bitreverseg (E1);		/* { dg-error "argument 1 in call to function '__builtin_bitreverseg' has signed type" "" { target c } } */
+					/* { dg-error "argument 1 in call to function '__builtin_bitreverseg' has enumerated type" "" { target c++ } .-1 } */
+  __builtin_bitreverseg (false);	/* { dg-error "argument 1 in call to function '__builtin_bitreverseg' has boolean type" } */
+  __builtin_bitreverseg (1);		/* { dg-error "argument 1 in call to function '__builtin_bitreverseg' has signed type" } */
+  __builtin_bitreverseg ((char) 1);	/* { dg-error "(?:argument 1 in call to function '__builtin_bitreverseg' has signed type|argument 1 in call to function '__builtin_bitreverseg' has 'char' type)" } */
+}