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

Reply via email to