[3/5] C _BitInt support [PR102989]

Message ID ZMKl72EbjP0gPNM7@tucnak
State Unresolved
Headers
Series GCC _BitInt support [PR102989] |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jakub Jelinek July 27, 2023, 5:14 p.m. UTC
  Hi!

This patch adds the C FE support, c-family support, small libcpp change
so that 123wb and 42uwb suffixes are handled plus glimits.h change
to define BITINT_MAXWIDTH macro.

The previous two patches really do nothing without this, which enables
all the support.

2023-07-27  Jakub Jelinek  <jakub@redhat.com>

	PR c/102989
gcc/
	* glimits.h (BITINT_MAXWIDTH): Define if __BITINT_MAXWIDTH__ is
	predefined.
gcc/c-family/
	* c-common.cc (c_common_reswords): Add _BitInt as keyword.
	(c_common_signed_or_unsigned_type): Handle BITINT_TYPE.
	(check_builtin_function_arguments): Handle BITINT_TYPE like
	INTEGER_TYPE.
	(keyword_begins_type_specifier): Handle RID_BITINT.
	* c-common.h (enum rid): Add RID_BITINT enumerator.
	* c-cppbuiltin.cc (c_cpp_builtins): For C call
	targetm.c.bitint_type_info and predefine __BITINT_MAXWIDTH__
	and for -fbuilding-libgcc also __LIBGCC_BITINT_LIMB_WIDTH__ and
	__LIBGCC_BITINT_ORDER__ macros if _BitInt is supported.
	* c-lex.cc (interpret_integer): Handle CPP_N_BITINT.
	* c-pretty-print.cc (c_pretty_printer::simple_type_specifier,
	c_pretty_printer::direct_abstract_declarator): Handle BITINT_TYPE.
	(pp_c_integer_constant): Handle printing of large precision wide_ints
	which would buffer overflow digit_buffer.
	* c-ubsan.cc (ubsan_instrument_shift): Use UBSAN_PRINT_FORCE_INT
	for type0 type descriptor.
gcc/c/
	* c-convert.cc (c_convert): Handle BITINT_TYPE like INTEGER_TYPE.
	* c-decl.cc (declspecs_add_type): Formatting fixes.  Handle
	cts_bitint.  Adjust for added union in *specs.  Handle RID_BITINT.
	(finish_declspecs): Handle cts_bitint.  Adjust for added union in
	*specs.
	* c-parser.cc (c_keyword_starts_typename, c_token_starts_declspecs,
	c_parser_declspecs, c_parser_gnu_attribute_any_word): Handle
	RID_BITINT.
	* c-tree.h (enum c_typespec_keyword): Mention _BitInt in comment.
	Add cts_bitint enumerator.
	(struct c_declspecs): Move int_n_idx and floatn_nx_idx into a union
	and add bitint_prec there as well.
	* c-typeck.cc (composite_type, c_common_type, comptypes_internal):
	Handle BITINT_TYPE.
	(build_array_ref, build_unary_op, build_conditional_expr,
	convert_for_assignment, digest_init, build_binary_op): Likewise.
libcpp/
	* expr.cc (interpret_int_suffix): Handle wb and WB suffixes.
	* include/cpplib.h (CPP_N_BITINT): Define.


	Jakub
  

Patch

--- gcc/glimits.h.jj	2023-01-03 00:20:35.071086812 +0100
+++ gcc/glimits.h	2023-07-27 15:03:24.238234396 +0200
@@ -157,6 +157,11 @@  see the files COPYING3 and COPYING.RUNTI
 # undef BOOL_WIDTH
 # define BOOL_WIDTH 1
 
+# ifdef __BITINT_MAXWIDTH__
+#  undef BITINT_MAXWIDTH
+#  define BITINT_MAXWIDTH __BITINT_MAXWIDTH__
+# endif
+
 # define __STDC_VERSION_LIMITS_H__	202311L
 #endif
 
--- gcc/c-family/c-common.cc.jj	2023-07-24 17:48:26.436041278 +0200
+++ gcc/c-family/c-common.cc	2023-07-27 15:03:24.276233865 +0200
@@ -349,6 +349,7 @@  const struct c_common_resword c_common_r
   { "_Alignas",		RID_ALIGNAS,   D_CONLY },
   { "_Alignof",		RID_ALIGNOF,   D_CONLY },
   { "_Atomic",		RID_ATOMIC,    D_CONLY },
+  { "_BitInt",		RID_BITINT,    D_CONLY },
   { "_Bool",		RID_BOOL,      D_CONLY },
   { "_Complex",		RID_COMPLEX,	0 },
   { "_Imaginary",	RID_IMAGINARY, D_CONLY },
@@ -2728,6 +2729,9 @@  c_common_signed_or_unsigned_type (int un
       || TYPE_UNSIGNED (type) == unsignedp)
     return type;
 
+  if (TREE_CODE (type) == BITINT_TYPE)
+    return build_bitint_type (TYPE_PRECISION (type), unsignedp);
+
 #define TYPE_OK(node)							    \
   (TYPE_MODE (type) == TYPE_MODE (node)					    \
    && TYPE_PRECISION (type) == TYPE_PRECISION (node))
@@ -6341,8 +6345,10 @@  check_builtin_function_arguments (locati
 	  code0 = TREE_CODE (TREE_TYPE (args[0]));
 	  code1 = TREE_CODE (TREE_TYPE (args[1]));
 	  if (!((code0 == REAL_TYPE && code1 == REAL_TYPE)
-		|| (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
-		|| (code0 == INTEGER_TYPE && code1 == REAL_TYPE)))
+		|| (code0 == REAL_TYPE
+		    && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
+		|| ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+		    && code1 == REAL_TYPE)))
 	    {
 	      error_at (loc, "non-floating-point arguments in call to "
 			"function %qE", fndecl);
@@ -8402,6 +8408,7 @@  keyword_begins_type_specifier (enum rid
     case RID_FRACT:
     case RID_ACCUM:
     case RID_BOOL:
+    case RID_BITINT:
     case RID_WCHAR:
     case RID_CHAR8:
     case RID_CHAR16:
--- gcc/c-family/c-common.h.jj	2023-06-26 09:27:04.276367532 +0200
+++ gcc/c-family/c-common.h	2023-07-27 15:03:24.278233837 +0200
@@ -101,7 +101,7 @@  enum rid
   RID_ENUM,    RID_STRUCT, RID_UNION,    RID_IF,     RID_ELSE,
   RID_WHILE,   RID_DO,     RID_FOR,      RID_SWITCH, RID_CASE,
   RID_DEFAULT, RID_BREAK,  RID_CONTINUE, RID_RETURN, RID_GOTO,
-  RID_SIZEOF,
+  RID_SIZEOF,  RID_BITINT,
 
   /* C extensions */
   RID_ASM,       RID_TYPEOF,   RID_TYPEOF_UNQUAL, RID_ALIGNOF,  RID_ATTRIBUTE,
--- gcc/c-family/c-cppbuiltin.cc.jj	2023-07-02 12:07:08.382165397 +0200
+++ gcc/c-family/c-cppbuiltin.cc	2023-07-27 15:03:24.278233837 +0200
@@ -1190,6 +1190,29 @@  c_cpp_builtins (cpp_reader *pfile)
   builtin_define_type_width ("__PTRDIFF_WIDTH__", ptrdiff_type_node, NULL_TREE);
   builtin_define_type_width ("__SIZE_WIDTH__", size_type_node, NULL_TREE);
 
+  if (!c_dialect_cxx ())
+    {
+      struct bitint_info info;
+      /* For now, restrict __BITINT_MAXWIDTH__ to what can be represented in
+	 wide_int and widest_int.  */
+      if (targetm.c.bitint_type_info (WIDE_INT_MAX_PRECISION - 1, &info))
+	{
+	  cpp_define_formatted (pfile, "__BITINT_MAXWIDTH__=%d",
+				(int) WIDE_INT_MAX_PRECISION - 1);
+	  if (flag_building_libgcc)
+	    {
+	      scalar_int_mode limb_mode
+		= as_a <scalar_int_mode> (info.limb_mode);
+	      cpp_define_formatted (pfile, "__LIBGCC_BITINT_LIMB_WIDTH__=%d",
+				    (int) GET_MODE_PRECISION (limb_mode));
+	      cpp_define_formatted (pfile, "__LIBGCC_BITINT_ORDER__=%s",
+				    info.big_endian
+				    ? "__ORDER_BIG_ENDIAN__"
+				    : "__ORDER_LITTLE_ENDIAN__");
+	    }
+	}
+    }
+
   if (c_dialect_cxx ())
     for (i = 0; i < NUM_INT_N_ENTS; i ++)
       if (int_n_enabled_p[i])
--- gcc/c-family/c-lex.cc.jj	2023-05-16 18:51:56.669064839 +0200
+++ gcc/c-family/c-lex.cc	2023-07-27 15:03:24.279233823 +0200
@@ -809,6 +809,170 @@  interpret_integer (const cpp_token *toke
 
   *overflow = OT_NONE;
 
+  if (UNLIKELY (flags & CPP_N_BITINT))
+    {
+      unsigned int suffix_len = 2 + ((flags & CPP_N_UNSIGNED) ? 1 : 0);
+      int max_bits_per_digit = 4; // ceil (log2 (10))
+      unsigned int prefix_len = 0;
+      bool hex = false;
+      const int bitint_maxwidth = WIDE_INT_MAX_PRECISION - 1;
+      if ((flags & CPP_N_RADIX) == CPP_N_OCTAL)
+	{
+	  max_bits_per_digit = 3;
+	  prefix_len = 1;
+	}
+      else if ((flags & CPP_N_RADIX) == CPP_N_HEX)
+	{
+	  max_bits_per_digit = 4;
+	  prefix_len = 2;
+	  hex = true;
+	}
+      else if ((flags & CPP_N_RADIX) == CPP_N_BINARY)
+	{
+	  max_bits_per_digit = 1;
+	  prefix_len = 2;
+	}
+      int max_digits
+	= TYPE_PRECISION (intmax_type_node) >> max_bits_per_digit;
+      const int max_buf = 128;
+      if (max_digits > max_buf)
+	max_digits = max_buf;
+
+      widest_int wval;
+      unsigned int prec;
+      gcc_checking_assert (token->val.str.len > prefix_len + suffix_len
+			   || token->val.str.len == 1 + suffix_len);
+      if (token->val.str.len - (prefix_len + suffix_len)
+	  <= (unsigned) max_digits)
+	{
+	  integer = cpp_interpret_integer (parse_in, token,
+					   (flags & CPP_N_RADIX)
+					   | CPP_N_UNSIGNED);
+	  ival[0] = integer.low;
+	  ival[1] = integer.high;
+	  ival[2] = 0;
+	  wval = widest_int::from_array (ival, 3);
+	}
+      else
+	{
+	  unsigned char buf[3 + max_buf];
+	  memcpy (buf, token->val.str.text, prefix_len);
+	  wval = 0U;
+	  const unsigned char *p = token->val.str.text + prefix_len;
+	  cpp_token tok = *token;
+	  tok.val.str.text = buf;
+	  if (!prefix_len)
+	    max_digits = 19;
+	  do
+	    {
+	      unsigned char *q = buf + prefix_len;
+	      do
+		{
+		  unsigned char c = *p++;
+		  if (ISDIGIT (c) || (hex && ISXDIGIT (c)))
+		    {
+		      *q++ = c;
+		      if (q == buf + prefix_len + max_digits)
+			break;
+		    }
+		  else if (c != '\'')
+		    {
+		      --p;
+		      break;
+		    }
+		}
+	      while (1);
+	      if (q == buf + prefix_len)
+		break;
+	      else
+		{
+		  wi::overflow_type wioverflow;
+		  *q = '\0';
+		  tok.val.str.len = q - buf;
+		  if (wval == 0)
+		    ;
+		  else if (prefix_len)
+		    {
+		      prec = wi::min_precision (wval, UNSIGNED);
+		      unsigned HOST_WIDE_INT shift
+			= (tok.val.str.len - prefix_len) * max_bits_per_digit;
+		      if (prec + shift > bitint_maxwidth)
+			goto bitint_overflow;
+		      wval = wi::lshift (wval, shift);
+		    }
+		  else
+		    {
+		      static unsigned HOST_WIDE_INT tens[]
+			= { 1U, 10U, 100U, 1000U,
+			    HOST_WIDE_INT_UC (10000),
+			    HOST_WIDE_INT_UC (100000),
+			    HOST_WIDE_INT_UC (1000000),
+			    HOST_WIDE_INT_UC (10000000),
+			    HOST_WIDE_INT_UC (100000000),
+			    HOST_WIDE_INT_UC (1000000000),
+			    HOST_WIDE_INT_UC (10000000000),
+			    HOST_WIDE_INT_UC (100000000000),
+			    HOST_WIDE_INT_UC (1000000000000),
+			    HOST_WIDE_INT_UC (10000000000000),
+			    HOST_WIDE_INT_UC (100000000000000),
+			    HOST_WIDE_INT_UC (1000000000000000),
+			    HOST_WIDE_INT_UC (10000000000000000),
+			    HOST_WIDE_INT_UC (100000000000000000),
+			    HOST_WIDE_INT_UC (1000000000000000000),
+			    HOST_WIDE_INT_UC (10000000000000000000) };
+		      widest_int ten = tens[q - buf];
+		      wval = wi::umul (wval, ten, &wioverflow);
+		      if (wioverflow)
+			goto bitint_overflow;
+		    }
+		  integer = cpp_interpret_integer (parse_in, &tok,
+						   (flags & CPP_N_RADIX)
+						   | CPP_N_UNSIGNED);
+		  ival[0] = integer.low;
+		  ival[1] = integer.high;
+		  ival[2] = 0;
+		  if (prefix_len)
+		    wval = wval + widest_int::from_array (ival, 3);
+		  else
+		    {
+		      widest_int addend = widest_int::from_array (ival, 3);
+		      wval = wi::add (wval, addend, UNSIGNED, &wioverflow);
+		      if (wioverflow)
+			goto bitint_overflow;
+		    }
+		}
+	    }
+	  while (1);
+	}
+
+      prec = wi::min_precision (wval, UNSIGNED);
+      if (prec == 0)
+	prec = 1;
+      if ((flags & CPP_N_UNSIGNED) == 0)
+	++prec;
+      if (prec > bitint_maxwidth)
+	{
+	bitint_overflow:
+	  if ((flags & CPP_N_UNSIGNED) != 0)
+	    error ("integer constant is too large for "
+		   "%<unsigned _BitInt(%d)%> type", bitint_maxwidth);
+	  else
+	    error ("integer constant is too large for "
+		   "%<_BitInt(%d)%> type", bitint_maxwidth);
+	  return integer_zero_node;
+	}
+
+      struct bitint_info info;
+      if (!targetm.c.bitint_type_info (prec, &info))
+	{
+	  sorry ("%<_BitInt(%d)%> is not supported on this target", prec);
+	  return integer_zero_node;
+	}
+
+      type = build_bitint_type (prec, (flags & CPP_N_UNSIGNED) != 0);
+      return wide_int_to_tree (type, wval);
+    }
+
   integer = cpp_interpret_integer (parse_in, token, flags);
   if (integer.overflow)
     *overflow = OT_OVERFLOW;
--- gcc/c-family/c-pretty-print.cc.jj	2023-01-16 23:19:05.561727075 +0100
+++ gcc/c-family/c-pretty-print.cc	2023-07-27 15:03:24.277233851 +0200
@@ -399,6 +399,23 @@  c_pretty_printer::simple_type_specifier
 	}
       break;
 
+    case BITINT_TYPE:
+      if (TYPE_NAME (t))
+	{
+	  t = TYPE_NAME (t);
+	  simple_type_specifier (t);
+	}
+      else
+	{
+	  int prec = TYPE_PRECISION (t);
+	  if (TYPE_UNSIGNED (t))
+	    pp_c_ws_string (this, "unsigned");
+	  pp_c_ws_string (this, "_BitInt(");;
+	  pp_decimal_int (this, prec);
+	  pp_right_paren (this);
+	}
+      break;
+
     case TYPE_DECL:
       if (DECL_NAME (t))
 	id_expression (t);
@@ -688,6 +705,7 @@  c_pretty_printer::direct_abstract_declar
     case REAL_TYPE:
     case FIXED_POINT_TYPE:
     case ENUMERAL_TYPE:
+    case BITINT_TYPE:
     case RECORD_TYPE:
     case UNION_TYPE:
     case VECTOR_TYPE:
@@ -1019,8 +1037,18 @@  pp_c_integer_constant (c_pretty_printer
 	  pp_minus (pp);
 	  wi = -wi;
 	}
-      print_hex (wi, pp_buffer (pp)->digit_buffer);
-      pp_string (pp, pp_buffer (pp)->digit_buffer);
+      unsigned int prec = wi.get_precision ();
+      if ((prec + 3) / 4 > sizeof (pp_buffer (pp)->digit_buffer) - 3)
+	{
+	  char *buf = XALLOCAVEC (char, (prec + 3) / 4 + 3);
+	  print_hex (wi, buf);
+	  pp_string (pp, buf);
+	}
+      else
+	{
+	  print_hex (wi, pp_buffer (pp)->digit_buffer);
+	  pp_string (pp, pp_buffer (pp)->digit_buffer);
+	}
     }
 }
 
--- gcc/c-family/c-ubsan.cc.jj	2023-05-20 15:31:09.071663282 +0200
+++ gcc/c-family/c-ubsan.cc	2023-07-27 15:03:24.279233823 +0200
@@ -256,8 +256,8 @@  ubsan_instrument_shift (location_t loc,
     tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
   else
     {
-      tree data = ubsan_create_data ("__ubsan_shift_data", 1, &loc,
-				     ubsan_type_descriptor (type0),
+      tree utd0 = ubsan_type_descriptor (type0, UBSAN_PRINT_FORCE_INT);
+      tree data = ubsan_create_data ("__ubsan_shift_data", 1, &loc, utd0,
 				     ubsan_type_descriptor (type1), NULL_TREE,
 				     NULL_TREE);
       data = build_fold_addr_expr_loc (loc, data);
--- gcc/c/c-convert.cc.jj	2023-05-20 15:31:09.073663254 +0200
+++ gcc/c/c-convert.cc	2023-07-27 15:03:24.272233921 +0200
@@ -117,6 +117,7 @@  c_convert (tree type, tree expr, bool in
       gcc_fallthrough ();
 
     case INTEGER_TYPE:
+    case BITINT_TYPE:
       if (sanitize_flags_p (SANITIZE_FLOAT_CAST)
 	  && current_function_decl != NULL_TREE
 	  && SCALAR_FLOAT_TYPE_P (TREE_TYPE (expr))
--- gcc/c/c-decl.cc.jj	2023-07-02 12:07:08.386165342 +0200
+++ gcc/c/c-decl.cc	2023-07-27 15:03:24.265234019 +0200
@@ -11538,14 +11538,18 @@  declspecs_add_type (location_t loc, stru
 			  ("both %<long%> and %<void%> in "
 			   "declaration specifiers"));
 	      else if (specs->typespec_word == cts_int_n)
-		  error_at (loc,
-			    ("both %<long%> and %<__int%d%> in "
-			     "declaration specifiers"),
-			    int_n_data[specs->int_n_idx].bitsize);
+		error_at (loc,
+			  ("both %<long%> and %<__int%d%> in "
+			   "declaration specifiers"),
+			  int_n_data[specs->u.int_n_idx].bitsize);
 	      else if (specs->typespec_word == cts_bool)
 		error_at (loc,
 			  ("both %<long%> and %<_Bool%> in "
 			   "declaration specifiers"));
+	      else if (specs->typespec_word == cts_bitint)
+		error_at (loc,
+			  ("both %<long%> and %<_BitInt%> in "
+			   "declaration specifiers"));
 	      else if (specs->typespec_word == cts_char)
 		error_at (loc,
 			  ("both %<long%> and %<char%> in "
@@ -11558,8 +11562,8 @@  declspecs_add_type (location_t loc, stru
 		error_at (loc,
 			  ("both %<long%> and %<_Float%d%s%> in "
 			   "declaration specifiers"),
-			  floatn_nx_types[specs->floatn_nx_idx].n,
-			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			  floatn_nx_types[specs->u.floatn_nx_idx].n,
+			  (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			   ? "x"
 			   : ""));
 	      else if (specs->typespec_word == cts_dfloat32)
@@ -11598,11 +11602,15 @@  declspecs_add_type (location_t loc, stru
 		error_at (loc,
 			  ("both %<short%> and %<__int%d%> in "
 			   "declaration specifiers"),
-			  int_n_data[specs->int_n_idx].bitsize);
+			  int_n_data[specs->u.int_n_idx].bitsize);
 	      else if (specs->typespec_word == cts_bool)
 		error_at (loc,
 			  ("both %<short%> and %<_Bool%> in "
 			   "declaration specifiers"));
+	      else if (specs->typespec_word == cts_bitint)
+		error_at (loc,
+			  ("both %<short%> and %<_BitInt%> in "
+			   "declaration specifiers"));
 	      else if (specs->typespec_word == cts_char)
 		error_at (loc,
 			  ("both %<short%> and %<char%> in "
@@ -11619,8 +11627,8 @@  declspecs_add_type (location_t loc, stru
 		error_at (loc,
 			  ("both %<short%> and %<_Float%d%s%> in "
 			   "declaration specifiers"),
-			  floatn_nx_types[specs->floatn_nx_idx].n,
-			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			  floatn_nx_types[specs->u.floatn_nx_idx].n,
+			  (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			   ? "x"
 			   : ""));
 	      else if (specs->typespec_word == cts_dfloat32)
@@ -11671,8 +11679,8 @@  declspecs_add_type (location_t loc, stru
 		error_at (loc,
 			  ("both %<signed%> and %<_Float%d%s%> in "
 			   "declaration specifiers"),
-			  floatn_nx_types[specs->floatn_nx_idx].n,
-			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			  floatn_nx_types[specs->u.floatn_nx_idx].n,
+			  (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			   ? "x"
 			   : ""));
 	      else if (specs->typespec_word == cts_dfloat32)
@@ -11723,8 +11731,8 @@  declspecs_add_type (location_t loc, stru
 		error_at (loc,
 			  ("both %<unsigned%> and %<_Float%d%s%> in "
 			   "declaration specifiers"),
-			  floatn_nx_types[specs->floatn_nx_idx].n,
-			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			  floatn_nx_types[specs->u.floatn_nx_idx].n,
+			  (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			   ? "x"
 			   : ""));
               else if (specs->typespec_word == cts_dfloat32)
@@ -11762,6 +11770,10 @@  declspecs_add_type (location_t loc, stru
 		error_at (loc,
 			  ("both %<complex%> and %<_Bool%> in "
 			   "declaration specifiers"));
+	      else if (specs->typespec_word == cts_bitint)
+		error_at (loc,
+			  ("both %<complex%> and %<_BitInt%> in "
+			   "declaration specifiers"));
               else if (specs->typespec_word == cts_dfloat32)
 		error_at (loc,
 			  ("both %<complex%> and %<_Decimal32%> in "
@@ -11801,7 +11813,7 @@  declspecs_add_type (location_t loc, stru
 		  error_at (loc,
 			    ("both %<_Sat%> and %<__int%d%> in "
 			     "declaration specifiers"),
-			    int_n_data[specs->int_n_idx].bitsize);
+			    int_n_data[specs->u.int_n_idx].bitsize);
 	        }
 	      else if (specs->typespec_word == cts_auto_type)
 		error_at (loc,
@@ -11815,6 +11827,10 @@  declspecs_add_type (location_t loc, stru
 		error_at (loc,
 			  ("both %<_Sat%> and %<_Bool%> in "
 			   "declaration specifiers"));
+	      else if (specs->typespec_word == cts_bitint)
+		error_at (loc,
+			  ("both %<_Sat%> and %<_BitInt%> in "
+			   "declaration specifiers"));
 	      else if (specs->typespec_word == cts_char)
 		error_at (loc,
 			  ("both %<_Sat%> and %<char%> in "
@@ -11835,8 +11851,8 @@  declspecs_add_type (location_t loc, stru
 		error_at (loc,
 			  ("both %<_Sat%> and %<_Float%d%s%> in "
 			   "declaration specifiers"),
-			  floatn_nx_types[specs->floatn_nx_idx].n,
-			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			  floatn_nx_types[specs->u.floatn_nx_idx].n,
+			  (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			   ? "x"
 			   : ""));
               else if (specs->typespec_word == cts_dfloat32)
@@ -11874,7 +11890,7 @@  declspecs_add_type (location_t loc, stru
 	{
 	  /* "void", "_Bool", "char", "int", "float", "double",
 	     "_FloatN", "_FloatNx", "_Decimal32", "__intN",
-	     "_Decimal64", "_Decimal128", "_Fract", "_Accum" or
+	     "_Decimal64", "_Decimal128", "_Fract", "_Accum", "_BitInt(N)" or
 	     "__auto_type".  */
 	  if (specs->typespec_word != cts_none)
 	    {
@@ -11919,7 +11935,7 @@  declspecs_add_type (location_t loc, stru
 	    case RID_INT_N_1:
 	    case RID_INT_N_2:
 	    case RID_INT_N_3:
-	      specs->int_n_idx = i - RID_INT_N_0;
+	      specs->u.int_n_idx = i - RID_INT_N_0;
 	      if (!in_system_header_at (input_location)
 		  /* If the INT_N type ends in "__", and so is of the format
 		     "__intN__", don't pedwarn.  */
@@ -11927,29 +11943,29 @@  declspecs_add_type (location_t loc, stru
 			       + (IDENTIFIER_LENGTH (type) - 2), "__", 2) != 0))
 		pedwarn (loc, OPT_Wpedantic,
 			 "ISO C does not support %<__int%d%> types",
-			 int_n_data[specs->int_n_idx].bitsize);
+			 int_n_data[specs->u.int_n_idx].bitsize);
 
 	      if (specs->long_p)
 		error_at (loc,
 			  ("both %<__int%d%> and %<long%> in "
 			   "declaration specifiers"),
-			  int_n_data[specs->int_n_idx].bitsize);
+			  int_n_data[specs->u.int_n_idx].bitsize);
 	      else if (specs->saturating_p)
 		error_at (loc,
 			  ("both %<_Sat%> and %<__int%d%> in "
 			   "declaration specifiers"),
-			  int_n_data[specs->int_n_idx].bitsize);
+			  int_n_data[specs->u.int_n_idx].bitsize);
 	      else if (specs->short_p)
 		error_at (loc,
 			  ("both %<__int%d%> and %<short%> in "
 			   "declaration specifiers"),
-			  int_n_data[specs->int_n_idx].bitsize);
-	      else if (! int_n_enabled_p[specs->int_n_idx])
+			  int_n_data[specs->u.int_n_idx].bitsize);
+	      else if (! int_n_enabled_p[specs->u.int_n_idx])
 		{
 		  specs->typespec_word = cts_int_n;
 		  error_at (loc,
 			    "%<__int%d%> is not supported on this target",
-			    int_n_data[specs->int_n_idx].bitsize);
+			    int_n_data[specs->u.int_n_idx].bitsize);
 		}
 	      else
 		{
@@ -12107,12 +12123,12 @@  declspecs_add_type (location_t loc, stru
 		}
 	      return specs;
 	    CASE_RID_FLOATN_NX:
-	      specs->floatn_nx_idx = i - RID_FLOATN_NX_FIRST;
+	      specs->u.floatn_nx_idx = i - RID_FLOATN_NX_FIRST;
 	      if (!in_system_header_at (input_location))
 		pedwarn (loc, OPT_Wpedantic,
 			 "ISO C does not support the %<_Float%d%s%> type",
-			 floatn_nx_types[specs->floatn_nx_idx].n,
-			 (floatn_nx_types[specs->floatn_nx_idx].extended
+			 floatn_nx_types[specs->u.floatn_nx_idx].n,
+			 (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			  ? "x"
 			  : ""));
 
@@ -12120,49 +12136,49 @@  declspecs_add_type (location_t loc, stru
 		error_at (loc,
 			  ("both %<long%> and %<_Float%d%s%> in "
 			   "declaration specifiers"),
-			  floatn_nx_types[specs->floatn_nx_idx].n,
-			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			  floatn_nx_types[specs->u.floatn_nx_idx].n,
+			  (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			   ? "x"
 			   : ""));
 	      else if (specs->short_p)
 		error_at (loc,
 			  ("both %<short%> and %<_Float%d%s%> in "
 			   "declaration specifiers"),
-			  floatn_nx_types[specs->floatn_nx_idx].n,
-			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			  floatn_nx_types[specs->u.floatn_nx_idx].n,
+			  (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			   ? "x"
 			   : ""));
 	      else if (specs->signed_p)
 		error_at (loc,
 			  ("both %<signed%> and %<_Float%d%s%> in "
 			   "declaration specifiers"),
-			  floatn_nx_types[specs->floatn_nx_idx].n,
-			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			  floatn_nx_types[specs->u.floatn_nx_idx].n,
+			  (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			   ? "x"
 			   : ""));
 	      else if (specs->unsigned_p)
 		error_at (loc,
 			  ("both %<unsigned%> and %<_Float%d%s%> in "
 			   "declaration specifiers"),
-			  floatn_nx_types[specs->floatn_nx_idx].n,
-			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			  floatn_nx_types[specs->u.floatn_nx_idx].n,
+			  (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			   ? "x"
 			   : ""));
 	      else if (specs->saturating_p)
 		error_at (loc,
 			  ("both %<_Sat%> and %<_Float%d%s%> in "
 			   "declaration specifiers"),
-			  floatn_nx_types[specs->floatn_nx_idx].n,
-			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			  floatn_nx_types[specs->u.floatn_nx_idx].n,
+			  (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			   ? "x"
 			   : ""));
-	      else if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE)
+	      else if (FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx) == NULL_TREE)
 		{
 		  specs->typespec_word = cts_floatn_nx;
 		  error_at (loc,
 			    "%<_Float%d%s%> is not supported on this target",
-			    floatn_nx_types[specs->floatn_nx_idx].n,
-			    (floatn_nx_types[specs->floatn_nx_idx].extended
+			    floatn_nx_types[specs->u.floatn_nx_idx].n,
+			    (floatn_nx_types[specs->u.floatn_nx_idx].extended
 			     ? "x"
 			     : ""));
 		}
@@ -12259,6 +12275,63 @@  declspecs_add_type (location_t loc, stru
 	      pedwarn (loc, OPT_Wpedantic,
 		       "ISO C does not support fixed-point types");
 	      return specs;
+	    case RID_BITINT:
+	      if (specs->long_p)
+		error_at (loc,
+			  ("both %<long%> and %<_BitInt%> in "
+			   "declaration specifiers"));
+	      else if (specs->short_p)
+		error_at (loc,
+			  ("both %<short%> and %<_BitInt%> in "
+			   "declaration specifiers"));
+	      else if (specs->complex_p)
+		error_at (loc,
+			  ("both %<complex%> and %<_BitInt%> in "
+			   "declaration specifiers"));
+	      else if (specs->saturating_p)
+		error_at (loc,
+			  ("both %<_Sat%> and %<_BitInt%> in "
+			   "declaration specifiers"));
+	      else
+		{
+		  specs->typespec_word = cts_bitint;
+		  specs->locations[cdw_typespec] = loc;
+		  specs->u.bitint_prec = -1;
+		  if (error_operand_p (spec.expr))
+		    return specs;
+		  if (TREE_CODE (spec.expr) != INTEGER_CST
+		      || !INTEGRAL_TYPE_P (TREE_TYPE (spec.expr)))
+		    {
+		      error_at (loc, "%<_BitInt%> argument is not an integer "
+				     "constant expression");
+		      return specs;
+		    }
+		  if (tree_int_cst_sgn (spec.expr) <= 0)
+		    {
+		      error_at (loc, "%<_BitInt%> argument %qE is not "
+				     "positive integer constant expression",
+				spec.expr);
+		      return specs;
+		    }
+		  if (wi::to_widest (spec.expr) > WIDE_INT_MAX_PRECISION - 1)
+		    {
+		      error_at (loc, "%<_BitInt%> argument %qE is larger than "
+				     "%<BITINT_MAXWIDTH%> %qd",
+				spec.expr, (int) WIDE_INT_MAX_PRECISION - 1);
+		      return specs;
+		    }
+		  specs->u.bitint_prec = tree_to_uhwi (spec.expr);
+		  struct bitint_info info;
+		  if (!targetm.c.bitint_type_info (specs->u.bitint_prec,
+						   &info))
+		    {
+		      sorry_at (loc, "%<_BitInt(%d)%> is not supported on "
+				     "this target", specs->u.bitint_prec);
+		      specs->u.bitint_prec = -1;
+		      return specs;
+		    }
+		}
+	      return specs;
 	    default:
 	      /* ObjC reserved word "id", handled below.  */
 	      break;
@@ -12660,12 +12733,12 @@  finish_declspecs (struct c_declspecs *sp
     case cts_int_n:
       gcc_assert (!specs->long_p && !specs->short_p && !specs->long_long_p);
       gcc_assert (!(specs->signed_p && specs->unsigned_p));
-      if (! int_n_enabled_p[specs->int_n_idx])
+      if (! int_n_enabled_p[specs->u.int_n_idx])
 	specs->type = integer_type_node;
       else
 	specs->type = (specs->unsigned_p
-		       ? int_n_trees[specs->int_n_idx].unsigned_type
-		       : int_n_trees[specs->int_n_idx].signed_type);
+		       ? int_n_trees[specs->u.int_n_idx].unsigned_type
+		       : int_n_trees[specs->u.int_n_idx].signed_type);
       if (specs->complex_p)
 	{
 	  pedwarn (specs->locations[cdw_complex], OPT_Wpedantic,
@@ -12725,12 +12798,12 @@  finish_declspecs (struct c_declspecs *sp
     case cts_floatn_nx:
       gcc_assert (!specs->long_p && !specs->short_p
 		  && !specs->signed_p && !specs->unsigned_p);
-      if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE)
+      if (FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx) == NULL_TREE)
 	specs->type = integer_type_node;
       else if (specs->complex_p)
-	specs->type = COMPLEX_FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx);
+	specs->type = COMPLEX_FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx);
       else
-	specs->type = FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx);
+	specs->type = FLOATN_NX_TYPE_NODE (specs->u.floatn_nx_idx);
       break;
     case cts_dfloat32:
     case cts_dfloat64:
@@ -12832,6 +12905,22 @@  finish_declspecs (struct c_declspecs *sp
 			  : accum_type_node;
 	}
       break;
+    case cts_bitint:
+      gcc_assert (!specs->long_p && !specs->short_p
+		  && !specs->complex_p);
+      if (!specs->unsigned_p && specs->u.bitint_prec == 1)
+	{
+	  error_at (specs->locations[cdw_typespec],
+		    "%<signed _BitInt%> argument must be at least 2");
+	  specs->type = integer_type_node;
+	  break;
+	}
+      if (specs->u.bitint_prec == -1)
+	specs->type = integer_type_node;
+      else
+	specs->type = build_bitint_type (specs->u.bitint_prec,
+					 specs->unsigned_p);
+      break;
     default:
       gcc_unreachable ();
     }
--- gcc/c/c-parser.cc.jj	2023-06-16 12:01:15.001684150 +0200
+++ gcc/c/c-parser.cc	2023-07-27 15:03:24.272233921 +0200
@@ -580,6 +580,7 @@  c_keyword_starts_typename (enum rid keyw
     case RID_DFLOAT128:
     CASE_RID_FLOATN_NX:
     case RID_BOOL:
+    case RID_BITINT:
     case RID_ENUM:
     case RID_STRUCT:
     case RID_UNION:
@@ -783,6 +784,7 @@  c_token_starts_declspecs (c_token *token
 	case RID_DFLOAT128:
 	CASE_RID_FLOATN_NX:
 	case RID_BOOL:
+	case RID_BITINT:
 	case RID_ENUM:
 	case RID_STRUCT:
 	case RID_UNION:
@@ -3332,6 +3334,30 @@  c_parser_declspecs (c_parser *parser, st
 	  t = c_parser_typeof_specifier (parser);
 	  declspecs_add_type (loc, specs, t);
 	  break;
+	case RID_BITINT:
+	  if (!typespec_ok)
+	    goto out;
+	  else
+	    {
+	      attrs_ok = true;
+	      seen_type = true;
+	      t.kind = ctsk_resword;
+	      t.spec = c_parser_peek_token (parser)->value;
+	      t.expr = error_mark_node;
+	      t.expr_const_operands = true;
+	      t.has_enum_type_specifier = false;
+	      c_parser_consume_token (parser);
+	      matching_parens parens;
+	      if (parens.require_open (parser))
+		{
+		  c_expr expr = c_parser_expr_no_commas (parser, NULL);
+		  t.expr = convert_lvalue_to_rvalue (loc, expr, true,
+						     true).value;
+		  parens.skip_until_found_close (parser);
+		}
+	      declspecs_add_type (loc, specs, t);
+	    }
+	  break;
 	case RID_ATOMIC:
 	  /* C parser handling of Objective-C constructs needs
 	     checking for correct lvalue-to-rvalue conversions, and
@@ -4979,6 +5005,7 @@  c_parser_gnu_attribute_any_word (c_parse
 	case RID_DFLOAT128:
 	CASE_RID_FLOATN_NX:
 	case RID_BOOL:
+	case RID_BITINT:
 	case RID_FRACT:
 	case RID_ACCUM:
 	case RID_SAT:
--- gcc/c/c-tree.h.jj	2023-05-30 17:52:34.410858192 +0200
+++ gcc/c/c-tree.h	2023-07-27 15:03:24.273233907 +0200
@@ -270,7 +270,7 @@  enum c_storage_class {
 
 /* A type specifier keyword "void", "_Bool", "char", "int", "float",
    "double", "_Decimal32", "_Decimal64", "_Decimal128", "_Fract", "_Accum",
-   or none of these.  */
+   "_BitInt", or none of these.  */
 enum c_typespec_keyword {
   cts_none,
   cts_void,
@@ -286,6 +286,7 @@  enum c_typespec_keyword {
   cts_floatn_nx,
   cts_fract,
   cts_accum,
+  cts_bitint,
   cts_auto_type
 };
 
@@ -366,11 +367,16 @@  struct c_declspecs {
      specifier, in bytes, or -1 if no such specifiers with nonzero
      alignment.  */
   int align_log;
-  /* For the __intN declspec, this stores the index into the int_n_* arrays.  */
-  int int_n_idx;
-  /* For the _FloatN and _FloatNx declspec, this stores the index into
-     the floatn_nx_types array.  */
-  int floatn_nx_idx;
+  union {
+    /* For the __intN declspec, this stores the index into the int_n_*
+       arrays.  */
+    int int_n_idx;
+    /* For the _FloatN and _FloatNx declspec, this stores the index into
+       the floatn_nx_types array.  */
+    int floatn_nx_idx;
+    /* For _BitInt(N) this stores the N.  */
+    int bitint_prec;
+  } u;
   /* The storage class specifier, or csc_none if none.  */
   enum c_storage_class storage_class;
   /* Any type specifier keyword used such as "int", not reflecting
--- gcc/c/c-typeck.cc.jj	2023-07-02 12:07:08.388165315 +0200
+++ gcc/c/c-typeck.cc	2023-07-27 15:03:24.268233977 +0200
@@ -413,10 +413,14 @@  composite_type (tree t1, tree t2)
      the composite type.  */
 
   if (code1 == ENUMERAL_TYPE
-      && (code2 == INTEGER_TYPE || code2 == BOOLEAN_TYPE))
+      && (code2 == INTEGER_TYPE
+	  || code2 == BOOLEAN_TYPE
+	  || code2 == BITINT_TYPE))
     return t1;
   if (code2 == ENUMERAL_TYPE
-      && (code1 == INTEGER_TYPE || code1 == BOOLEAN_TYPE))
+      && (code1 == INTEGER_TYPE
+	  || code1 == BOOLEAN_TYPE
+	  || code1 == BITINT_TYPE))
     return t2;
 
   gcc_assert (code1 == code2);
@@ -764,10 +768,10 @@  c_common_type (tree t1, tree t2)
 
   gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE
 	      || code1 == FIXED_POINT_TYPE || code1 == REAL_TYPE
-	      || code1 == INTEGER_TYPE);
+	      || code1 == INTEGER_TYPE || code1 == BITINT_TYPE);
   gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE
 	      || code2 == FIXED_POINT_TYPE || code2 == REAL_TYPE
-	      || code2 == INTEGER_TYPE);
+	      || code2 == INTEGER_TYPE || code2 == BITINT_TYPE);
 
   /* When one operand is a decimal float type, the other operand cannot be
      a generic float type or a complex type.  We also disallow vector types
@@ -1004,6 +1008,20 @@  c_common_type (tree t1, tree t2)
     if (mv1 == FLOATNX_TYPE_NODE (i) || mv2 == FLOATNX_TYPE_NODE (i))
       return FLOATNX_TYPE_NODE (i);
 
+  if ((code1 == BITINT_TYPE || code2 == BITINT_TYPE) && code1 != code2)
+    {
+      /* Prefer any other integral types over bit-precise integer types.  */
+      if (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2))
+	return code1 == BITINT_TYPE ? t2 : t1;
+      /* If BITINT_TYPE is unsigned and the other type is signed
+	 non-BITINT_TYPE with the same precision, the latter has higher rank.
+	 In that case:
+	 Otherwise, both operands are converted to the unsigned integer type
+	 corresponding to the type of the operand with signed integer type.  */
+      if (TYPE_UNSIGNED (code1 == BITINT_TYPE ? t1 : t2))
+	return c_common_unsigned_type (code1 == BITINT_TYPE ? t2 : t1);
+    }
+
   /* Otherwise prefer the unsigned one.  */
 
   if (TYPE_UNSIGNED (t1))
@@ -1177,6 +1195,7 @@  comptypes_internal (const_tree type1, co
     case INTEGER_TYPE:
     case FIXED_POINT_TYPE:
     case REAL_TYPE:
+    case BITINT_TYPE:
       /* With these nodes, we can't determine type equivalence by
 	 looking at what is stored in the nodes themselves, because
 	 two nodes might have different TYPE_MAIN_VARIANTs but still
@@ -2790,7 +2809,8 @@  build_array_ref (location_t loc, tree ar
   if (index == error_mark_node)
     return error_mark_node;
 
-  gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE);
+  gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE
+	      || TREE_CODE (TREE_TYPE (index)) == BITINT_TYPE);
 
   bool was_vector = VECTOR_TYPE_P (TREE_TYPE (array));
   bool non_lvalue = convert_vector_to_array_for_subscript (loc, &array, index);
@@ -4558,6 +4578,7 @@  build_unary_op (location_t location, enu
 	 associativity, but won't generate any code.  */
       if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
 	    || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
+	    || typecode == BITINT_TYPE
 	    || gnu_vector_type_p (TREE_TYPE (arg))))
 	{
 	  error_at (location, "wrong type argument to unary plus");
@@ -4571,6 +4592,7 @@  build_unary_op (location_t location, enu
     case NEGATE_EXPR:
       if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
 	    || typecode == FIXED_POINT_TYPE || typecode == COMPLEX_TYPE
+	    || typecode == BITINT_TYPE
 	    || gnu_vector_type_p (TREE_TYPE (arg))))
 	{
 	  error_at (location, "wrong type argument to unary minus");
@@ -4583,6 +4605,7 @@  build_unary_op (location_t location, enu
     case BIT_NOT_EXPR:
       /* ~ works on integer types and non float vectors. */
       if (typecode == INTEGER_TYPE
+	  || typecode == BITINT_TYPE
 	  || (gnu_vector_type_p (TREE_TYPE (arg))
 	      && !VECTOR_FLOAT_TYPE_P (TREE_TYPE (arg))))
 	{
@@ -4657,7 +4680,8 @@  build_unary_op (location_t location, enu
     case TRUTH_NOT_EXPR:
       if (typecode != INTEGER_TYPE && typecode != FIXED_POINT_TYPE
 	  && typecode != REAL_TYPE && typecode != POINTER_TYPE
-	  && typecode != COMPLEX_TYPE && typecode != NULLPTR_TYPE)
+	  && typecode != COMPLEX_TYPE && typecode != NULLPTR_TYPE
+	  && typecode != BITINT_TYPE)
 	{
 	  error_at (location,
 		    "wrong type argument to unary exclamation mark");
@@ -4769,7 +4793,7 @@  build_unary_op (location_t location, enu
 
       if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE
 	  && typecode != INTEGER_TYPE && typecode != REAL_TYPE
-	  && typecode != COMPLEX_TYPE
+	  && typecode != COMPLEX_TYPE && typecode != BITINT_TYPE
 	  && !gnu_vector_type_p (TREE_TYPE (arg)))
 	{
 	  if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
@@ -5394,9 +5418,9 @@  build_conditional_expr (location_t colon
 	result_type = TYPE_MAIN_VARIANT (type1);
     }
   else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE
-	    || code1 == COMPLEX_TYPE)
+	    || code1 == COMPLEX_TYPE || code1 == BITINT_TYPE)
 	   && (code2 == INTEGER_TYPE || code2 == REAL_TYPE
-	       || code2 == COMPLEX_TYPE))
+	       || code2 == COMPLEX_TYPE || code2 == BITINT_TYPE))
     {
       /* In C11, a conditional expression between a floating-point
 	 type and an integer type should convert the integer type to
@@ -5583,7 +5607,8 @@  build_conditional_expr (location_t colon
 			  (build_qualified_type (void_type_node, qual));
 	}
     }
-  else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
+  else if (code1 == POINTER_TYPE
+	   && (code2 == INTEGER_TYPE || code2 == BITINT_TYPE))
     {
       if (!null_pointer_constant_p (orig_op2))
 	pedwarn (colon_loc, 0,
@@ -5594,7 +5619,8 @@  build_conditional_expr (location_t colon
 	}
       result_type = type1;
     }
-  else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
+  else if (code2 == POINTER_TYPE
+	   && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
     {
       if (!null_pointer_constant_p (orig_op1))
 	pedwarn (colon_loc, 0,
@@ -7131,11 +7157,11 @@  convert_for_assignment (location_t locat
   else if ((codel == INTEGER_TYPE || codel == REAL_TYPE
 	    || codel == FIXED_POINT_TYPE
 	    || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE
-	    || codel == BOOLEAN_TYPE)
+	    || codel == BOOLEAN_TYPE || codel == BITINT_TYPE)
 	   && (coder == INTEGER_TYPE || coder == REAL_TYPE
 	       || coder == FIXED_POINT_TYPE
 	       || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
-	       || coder == BOOLEAN_TYPE))
+	       || coder == BOOLEAN_TYPE || coder == BITINT_TYPE))
     {
       if (warnopt && errtype == ic_argpass)
 	maybe_warn_builtin_no_proto_arg (expr_loc, fundecl, parmnum, type,
@@ -8562,7 +8588,8 @@  digest_init (location_t init_loc, tree t
 
   if (code == INTEGER_TYPE || code == REAL_TYPE || code == FIXED_POINT_TYPE
       || code == POINTER_TYPE || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE
-      || code == COMPLEX_TYPE || code == VECTOR_TYPE || code == NULLPTR_TYPE)
+      || code == COMPLEX_TYPE || code == VECTOR_TYPE || code == NULLPTR_TYPE
+      || code == BITINT_TYPE)
     {
       tree unconverted_init = inside_init;
       if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
@@ -12357,12 +12384,14 @@  build_binary_op (location_t location, en
     {
     case PLUS_EXPR:
       /* Handle the pointer + int case.  */
-      if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+      if (code0 == POINTER_TYPE
+	  && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
 	{
 	  ret = pointer_int_sum (location, PLUS_EXPR, op0, op1);
 	  goto return_build_binary_op;
 	}
-      else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
+      else if (code1 == POINTER_TYPE
+	       && (code0 == INTEGER_TYPE || code0 == BITINT_TYPE))
 	{
 	  ret = pointer_int_sum (location, PLUS_EXPR, op1, op0);
 	  goto return_build_binary_op;
@@ -12381,7 +12410,8 @@  build_binary_op (location_t location, en
 	  goto return_build_binary_op;
 	}
       /* Handle pointer minus int.  Just like pointer plus int.  */
-      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+      else if (code0 == POINTER_TYPE
+	       && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
 	{
 	  ret = pointer_int_sum (location, MINUS_EXPR, op0, op1);
 	  goto return_build_binary_op;
@@ -12403,11 +12433,11 @@  build_binary_op (location_t location, en
       warn_for_div_by_zero (location, op1);
 
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
-	   || code0 == FIXED_POINT_TYPE
+	   || code0 == FIXED_POINT_TYPE || code0 == BITINT_TYPE
 	   || code0 == COMPLEX_TYPE
 	   || gnu_vector_type_p (type0))
 	  && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
-	      || code1 == FIXED_POINT_TYPE
+	      || code1 == FIXED_POINT_TYPE || code1 == BITINT_TYPE
 	      || code1 == COMPLEX_TYPE
 	      || gnu_vector_type_p (type1)))
 	{
@@ -12418,8 +12448,9 @@  build_binary_op (location_t location, en
 	  if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
 	    tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
 
-	  if (!((tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE)
-	      || (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE)))
+	  if (!(((tcode0 == INTEGER_TYPE || tcode0 == BITINT_TYPE)
+		 && (tcode1 == INTEGER_TYPE || tcode1 == BITINT_TYPE))
+		|| (tcode0 == FIXED_POINT_TYPE && tcode1 == FIXED_POINT_TYPE)))
 	    resultcode = RDIV_EXPR;
 	  else
 	    /* Although it would be tempting to shorten always here, that
@@ -12435,7 +12466,8 @@  build_binary_op (location_t location, en
     case BIT_AND_EXPR:
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
-      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+      if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+	  && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
 	shorten = -1;
       /* Allow vector types which are not floating point types.   */
       else if (gnu_vector_type_p (type0)
@@ -12455,7 +12487,8 @@  build_binary_op (location_t location, en
 	  && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
 	  && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE)
 	common = 1;
-      else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+      else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+	       && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
 	{
 	  /* Although it would be tempting to shorten always here, that loses
 	     on some targets, since the modulo instruction is undefined if the
@@ -12473,10 +12506,12 @@  build_binary_op (location_t location, en
     case TRUTH_XOR_EXPR:
       if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE
 	   || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
-	   || code0 == FIXED_POINT_TYPE || code0 == NULLPTR_TYPE)
+	   || code0 == FIXED_POINT_TYPE || code0 == NULLPTR_TYPE
+	   || code0 == BITINT_TYPE)
 	  && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE
 	      || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
-	      || code1 == FIXED_POINT_TYPE || code1 ==  NULLPTR_TYPE))
+	      || code1 == FIXED_POINT_TYPE || code1 == NULLPTR_TYPE
+	      || code1 == BITINT_TYPE))
 	{
 	  /* Result of these operations is always an int,
 	     but that does not mean the operands should be
@@ -12539,9 +12574,10 @@  build_binary_op (location_t location, en
 	  converted = 1;
 	}
       else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE
+		|| code0 == BITINT_TYPE
 		|| (gnu_vector_type_p (type0)
 		    && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE))
-	       && code1 == INTEGER_TYPE)
+	       && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
 	{
 	  doing_shift = true;
 	  if (TREE_CODE (op1) == INTEGER_CST)
@@ -12599,9 +12635,10 @@  build_binary_op (location_t location, en
 	  converted = 1;
 	}
       else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE
+		|| code0 == BITINT_TYPE
 		|| (gnu_vector_type_p (type0)
 		    && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE))
-	       && code1 == INTEGER_TYPE)
+	       && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
 	{
 	  doing_shift = true;
 	  if (TREE_CODE (op0) == INTEGER_CST
@@ -12715,9 +12752,10 @@  build_binary_op (location_t location, en
       /* Result of comparison is always int,
 	 but don't convert the args to int!  */
       build_type = integer_type_node;
-      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == BITINT_TYPE
 	   || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE)
 	  && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+	      || code1 == BITINT_TYPE
 	      || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE))
 	short_compare = 1;
       else if (code0 == POINTER_TYPE
@@ -12778,12 +12816,14 @@  build_binary_op (location_t location, en
 			      (build_qualified_type (void_type_node, qual));
 	    }
 	}
-      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+      else if (code0 == POINTER_TYPE
+	       && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
 	{
 	  result_type = type0;
 	  pedwarn (location, 0, "comparison between pointer and integer");
 	}
-      else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
+      else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+	       && code1 == POINTER_TYPE)
 	{
 	  result_type = type1;
 	  pedwarn (location, 0, "comparison between pointer and integer");
@@ -12871,9 +12911,9 @@  build_binary_op (location_t location, en
         }
       build_type = integer_type_node;
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
-	   || code0 == FIXED_POINT_TYPE)
+	   || code0 == BITINT_TYPE || code0 == FIXED_POINT_TYPE)
 	  && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
-	      || code1 == FIXED_POINT_TYPE))
+	      || code1 == BITINT_TYPE || code1 == FIXED_POINT_TYPE))
 	short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
 	{
@@ -12932,12 +12972,14 @@  build_binary_op (location_t location, en
 	    warning_at (location, OPT_Wextra,
 			"ordered comparison of pointer with integer zero");
 	}
-      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+      else if (code0 == POINTER_TYPE
+	       && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
 	{
 	  result_type = type0;
 	  pedwarn (location, 0, "comparison between pointer and integer");
 	}
-      else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
+      else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+	       && code1 == POINTER_TYPE)
 	{
 	  result_type = type1;
 	  pedwarn (location, 0, "comparison between pointer and integer");
@@ -12991,12 +13033,11 @@  build_binary_op (location_t location, en
     }
 
   if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
-       || code0 == FIXED_POINT_TYPE
+       || code0 == FIXED_POINT_TYPE || code0 == BITINT_TYPE
        || gnu_vector_type_p (type0))
-      &&
-      (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
-       || code1 == FIXED_POINT_TYPE
-       || gnu_vector_type_p (type1)))
+      && (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
+	  || code1 == FIXED_POINT_TYPE || code1 == BITINT_TYPE
+	  || gnu_vector_type_p (type1)))
     {
       bool first_complex = (code0 == COMPLEX_TYPE);
       bool second_complex = (code1 == COMPLEX_TYPE);
--- libcpp/expr.cc.jj	2023-07-11 13:39:49.680108934 +0200
+++ libcpp/expr.cc	2023-07-11 15:28:55.224672554 +0200
@@ -327,9 +327,9 @@  static unsigned int
 interpret_int_suffix (cpp_reader *pfile, const uchar *s, size_t len)
 {
   size_t orig_len = len;
-  size_t u, l, i, z;
+  size_t u, l, i, z, wb;
 
-  u = l = i = z = 0;
+  u = l = i = z = wb = 0;
 
   while (len--)
     switch (s[len])
@@ -343,11 +343,23 @@  interpret_int_suffix (cpp_reader *pfile,
 	if (l == 2 && s[len] != s[len + 1])
 	  return 0;
 	break;
+      case 'b':
+	if (len == 0 || s[len - 1] != 'w')
+	  return 0;
+	wb++;
+	len--;
+	break;
+      case 'B':
+	if (len == 0 || s[len - 1] != 'W')
+	  return 0;
+	wb++;
+	len--;
+	break;
       default:
 	return 0;
       }
 
-  if (l > 2 || u > 1 || i > 1 || z > 1)
+  if (l > 2 || u > 1 || i > 1 || z > 1 || wb > 1)
     return 0;
 
   if (z)
@@ -358,6 +370,14 @@  interpret_int_suffix (cpp_reader *pfile,
 	return 0;
     }
 
+  if (wb)
+    {
+      if (CPP_OPTION (pfile, cplusplus))
+	return 0;
+      if (l > 0 || i > 0 || z > 0)
+	return 0;
+    }
+
   if (i)
     {
       if (!CPP_OPTION (pfile, ext_numeric_literals))
@@ -376,7 +396,8 @@  interpret_int_suffix (cpp_reader *pfile,
 	  | (u ? CPP_N_UNSIGNED : 0)
 	  | ((l == 0) ? CPP_N_SMALL
 	     : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE)
-	  | (z ? CPP_N_SIZE_T : 0));
+	  | (z ? CPP_N_SIZE_T : 0)
+	  | (wb ? CPP_N_BITINT : 0));
 }
 
 /* Return the classification flags for an int suffix.  */
--- libcpp/include/cpplib.h.jj	2023-07-11 13:40:40.400429973 +0200
+++ libcpp/include/cpplib.h	2023-07-11 15:28:55.225672540 +0200
@@ -1284,6 +1284,7 @@  struct cpp_num
 
 #define CPP_N_SIZE_T	0x2000000 /* C++23 size_t literal.  */
 #define CPP_N_BFLOAT16	0x4000000 /* std::bfloat16_t type.  */
+#define CPP_N_BITINT	0x8000000 /* C2X _BitInt literal.  */
 
 #define CPP_N_WIDTH_FLOATN_NX	0xF0000000 /* _FloatN / _FloatNx value
 					      of N, divided by 16.  */