https://gcc.gnu.org/g:9ab08d664545bcea9164040e806385369fdaaf0e

commit r17-1367-g9ab08d664545bcea9164040e806385369fdaaf0e
Author: Jakub Jelinek <[email protected]>
Date:   Fri Jun 5 10:39:55 2026 +0200

    c, c++, bitintlower: Add __builtin_{bswap,bitreverse}g type-generic 
builtins [PR122731]
    
    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).
    
    2026-06-05  Jakub Jelinek  <[email protected]>
    
            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.
    
    Reviewed-by: Richard Biener <[email protected]>
    Reviewed-by: Joseph Myers <[email protected]>
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/builtins.cc                                    |  47 +++++
 gcc/builtins.h                                     |   2 +
 gcc/c-family/c-common.cc                           |   2 +
 gcc/c-family/c-common.h                            |   3 +-
 gcc/c/c-parser.cc                                  |  70 ++++++++
 gcc/cp/constexpr.cc                                |  28 +++
 gcc/cp/cp-gimplify.cc                              |  25 ++-
 gcc/cp/cp-tree.h                                   |   3 +
 gcc/cp/parser.cc                                   |  14 ++
 gcc/cp/pt.cc                                       |  11 ++
 gcc/cp/typeck.cc                                   |  65 +++++++
 gcc/doc/extend.texi                                |  12 ++
 gcc/fold-const-call.cc                             |  11 +-
 gcc/fold-const.cc                                  |  11 +-
 gcc/gencfn-macros.cc                               |  37 +++-
 gcc/gimple-lower-bitint.cc                         | 192 ++++++++++++++++++++-
 gcc/gimple-match-exports.cc                        |   4 +-
 gcc/internal-fn.cc                                 |  15 ++
 gcc/internal-fn.def                                |  25 +++
 gcc/internal-fn.h                                  |   2 +
 gcc/match.pd                                       |   7 +-
 gcc/testsuite/c-c++-common/builtin-bitreverseg-1.c | 164 ++++++++++++++++++
 gcc/testsuite/c-c++-common/builtin-bitreverseg-2.c |  21 +++
 gcc/testsuite/c-c++-common/builtin-bswapg-1.c      | 153 ++++++++++++++++
 gcc/testsuite/c-c++-common/builtin-bswapg-2.c      |  21 +++
 gcc/testsuite/c-c++-common/builtin-bswapg-3.c      |  15 ++
 gcc/tree-ssa-phiopt.cc                             |  22 +--
 gcc/wide-int.h                                     |   2 +-
 28 files changed, 935 insertions(+), 49 deletions(-)

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 79fadfe9320d..52f3ee029d0b 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -10522,6 +10522,53 @@ fold_builtin_bit_query (location_t loc, enum 
built_in_function fcode,
   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.  */
diff --git a/gcc/builtins.h b/gcc/builtins.h
index 1a56b5ed2ba4..9cca88c647cc 100644
--- a/gcc/builtins.h
+++ b/gcc/builtins.h
@@ -140,6 +140,8 @@ extern rtx expand_builtin (tree, rtx, rtx, machine_mode, 
int);
 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 *);
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 8904913c82f2..ba72278bd522 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -433,7 +433,9 @@ const struct c_common_resword c_common_reswords[] =
   { "__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 },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index d9ed2b070f51..52dba69b7305 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -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.  */
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index b578de7b15aa..d30b36619538 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -13534,6 +13534,76 @@ c_parser_postfix_expression (c_parser *parser)
                                       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 (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 ());
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 97dde5a310d3..88947bbb7850 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3245,6 +3245,32 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, 
tree t,
     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;
+       if (*non_constant_p)
+         return t;
+       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 +12052,8 @@ potential_constant_expression_1 (tree t, bool 
want_rval, bool strict, bool now,
                case IFN_MUL_OVERFLOW:
                case IFN_LAUNDER:
                case IFN_VEC_CONVERT:
+               case IFN_BSWAP:
+               case IFN_BITREVERSE:
                  bail = false;
                  break;
 
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 6845134c01d1..23a1b7ea2ccd 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #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_seq *pre_p, 
gimple_seq *post_p)
              = 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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bf477a67a349..8807d80a21a3 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -9050,6 +9050,9 @@ extern tree build_x_vec_perm_expr               
(location_t,
 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);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index c59f61d4212e..35f7653a4f1b 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -8626,6 +8626,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool 
address_p, bool cast_p,
     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;
 
@@ -8745,6 +8747,18 @@ cp_parser_postfix_expression (cp_parser *parser, bool 
address_p, bool cast_p,
              }
            break;
 
+         case RID_BUILTIN_BSWAPG:
+           postfix_expression
+             = build_x_bswapg_bitreverseg (loc, IFN_BSWAP, vec,
+                                           tf_warning_or_error);
+           break;
+
+         case RID_BUILTIN_BITREVERSEG:
+           postfix_expression
+             = build_x_bswapg_bitreverseg (loc, IFN_BITREVERSE, vec,
+                                           tf_warning_or_error);
+           break;
+
          default:
            gcc_unreachable ();
          }
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3802b3771b6f..ba2d14fa73dd 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -22561,6 +22561,17 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
                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)
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 37a0c3cfb7ab..89795238057d 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -7111,6 +7111,71 @@ build_x_shufflevector (location_t loc, vec<tree, va_gc> 
*args,
     }
   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)
+{
+  const char *name
+    = ifn == IFN_BSWAP ? "__builtin_bswapg" : "__builtin_bitreverseg";
+  if (args->length () != 1)
+    {
+      if (complain & tf_error)
+       error_at (loc, "wrong number of arguments to %qs", name);
+      return error_mark_node;
+    }
+  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;
+    }
+  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 (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.  */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 48f10feb8af8..4fbdc87f17c9 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -16095,6 +16095,12 @@ Similar to @code{__builtin_bswap64}, except the 
argument and return types
 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}, except the 
argument and return types
 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
diff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc
index 6e3487b34a75..b3a9d7715d66 100644
--- a/gcc/fold-const-call.cc
+++ b/gcc/fold-const-call.cc
@@ -1094,19 +1094,12 @@ fold_const_call_ss (wide_int *result, combined_fn fn, 
const wide_int_ref &arg,
       *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;
diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 179c7e167a3f..7f49126c95ab 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -14627,15 +14627,8 @@ tree_call_nonnegative_p (tree type, combined_fn fn, 
tree arg0, tree arg1,
     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;
 
diff --git a/gcc/gencfn-macros.cc b/gcc/gencfn-macros.cc
index 6aeb11bf94f1..2c4e2f1da1be 100644
--- a/gcc/gencfn-macros.cc
+++ b/gcc/gencfn-macros.cc
@@ -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[] = { "F", "", 
"L", "F16", "F32",
                                               "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);
diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc
index a33269b3ec2c..dc443a4a72f6 100644
--- a/gcc/gimple-lower-bitint.cc
+++ b/gcc/gimple-lower-bitint.cc
@@ -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 (gimple *stmt)
     }
 }
 
+/* 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, gimple *stmt)
       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 *stmt, live_track 
*live,
            }
        }
     }
-  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 *stmt, 
live_track *live,
       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;
diff --git a/gcc/gimple-match-exports.cc b/gcc/gimple-match-exports.cc
index 3be06ddd9a4d..2cbdc9833817 100644
--- a/gcc/gimple-match-exports.cc
+++ b/gcc/gimple-match-exports.cc
@@ -266,7 +266,9 @@ build_call_internal (internal_fn fn, gimple_match_op 
*res_op)
            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]))
diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index 2aaf98f29380..8a4622da7949 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -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 *stmt)
       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);
+}
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index d214ee46b4f7..a9fb933021f8 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -36,6 +36,8 @@ along with GCC; see the file COPYING3.  If not see
      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.  If not see
    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.  If not see
   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 | ECF_NOTHROW, ctz, 
unary)
 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_CONST, iorn, binary)
 #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
diff --git a/gcc/internal-fn.h b/gcc/internal-fn.h
index 5e7cb73f0a37..bd9ba8d6929a 100644
--- a/gcc/internal-fn.h
+++ b/gcc/internal-fn.h
@@ -285,6 +285,8 @@ extern void expand_CTZ (internal_fn, gcall *);
 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);
 
diff --git a/gcc/match.pd b/gcc/match.pd
index 6b70999fab5a..14567d8a1f10 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -53,10 +53,6 @@ along with GCC; see the file COPYING3.  If not see
   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"
 
@@ -10319,8 +10315,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* 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))
diff --git a/gcc/testsuite/c-c++-common/builtin-bitreverseg-1.c 
b/gcc/testsuite/c-c++-common/builtin-bitreverseg-1.c
new file mode 100644
index 000000000000..dec3d6d7b2ba
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-bitreverseg-1.c
@@ -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
+}
diff --git a/gcc/testsuite/c-c++-common/builtin-bitreverseg-2.c 
b/gcc/testsuite/c-c++-common/builtin-bitreverseg-2.c
new file mode 100644
index 000000000000..cee5f061d635
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-bitreverseg-2.c
@@ -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" "" { target { ! unsigned_char 
} } } */
+}
diff --git a/gcc/testsuite/c-c++-common/builtin-bswapg-1.c 
b/gcc/testsuite/c-c++-common/builtin-bswapg-1.c
new file mode 100644
index 000000000000..75bc0a11dc5c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-bswapg-1.c
@@ -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
+}
diff --git a/gcc/testsuite/c-c++-common/builtin-bswapg-2.c 
b/gcc/testsuite/c-c++-common/builtin-bswapg-2.c
new file mode 100644
index 000000000000..6004aa64c86f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-bswapg-2.c
@@ -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" "" { target { ! unsigned_char } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/builtin-bswapg-3.c 
b/gcc/testsuite/c-c++-common/builtin-bswapg-3.c
new file mode 100644
index 000000000000..e2d94854b786
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-bswapg-3.c
@@ -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
+}
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index 6a7e4c70722a..6005a945a8c1 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -813,15 +813,8 @@ empty_bb_or_one_feeding_into_p (basic_block bb,
        {
        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 (basic_block 
cond_bb,
   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:
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
index f8d6af0fb48f..9c30f320b91d 100644
--- a/gcc/wide-int.h
+++ b/gcc/wide-int.h
@@ -2655,7 +2655,7 @@ wi::set_bit (const T &x, unsigned int bit)
 
 /* 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)

Reply via email to