public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 10/12] C _BitInt support [PR102989]
@ 2023-08-09 18:25 Jakub Jelinek
  2023-09-05 22:40 ` Joseph Myers
  0 siblings, 1 reply; 4+ messages in thread
From: Jakub Jelinek @ 2023-08-09 18:25 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches

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 patches really do nothing without this, which enables
all the support.

2023-08-09  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.
	(sync_resolve_size): Add ORIG_FORMAT argument.  If
	FETCH && !ORIG_FORMAT, type is BITINT_TYPE, return -1 if size isn't
	one of 1, 2, 4, 8 or 16 or if it is 16 but TImode is not supported.
	(atomic_bitint_fetch_using_cas_loop): New function.
	(resolve_overloaded_builtin): Adjust sync_resolve_size caller.  If
	-1 is returned, use atomic_bitint_fetch_using_cas_loop to lower it.
	Formatting fix.
	(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.
gcc/c/
	* c-convert.cc (c_convert): Handle BITINT_TYPE like INTEGER_TYPE.
	* c-decl.cc (check_bitfield_type_and_width): Allow BITINT_TYPE
	bit-fields.
	(finish_struct): Prefer to use BITINT_TYPE for BITINT_TYPE bit-fields
	if possible.
	(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.
	(perform_integral_promotions): Promote BITINT_TYPE bit-fields to
	their declared 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.

--- gcc/glimits.h.jj	2023-08-08 15:54:34.481612931 +0200
+++ gcc/glimits.h	2023-08-08 16:12:02.321939910 +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-08-08 15:55:05.243182143 +0200
+++ gcc/c-family/c-common.cc	2023-08-08 16:19:29.102683903 +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);
@@ -7185,12 +7191,16 @@ speculation_safe_value_resolve_return (t
 /* A helper function for resolve_overloaded_builtin in resolving the
    overloaded __sync_ builtins.  Returns a positive power of 2 if the
    first operand of PARAMS is a pointer to a supported data type.
-   Returns 0 if an error is encountered.
+   Returns 0 if an error is encountered.  Return -1 for _BitInt
+   __atomic*fetch* with unsupported type which should be handled by
+   a cas loop.
    FETCH is true when FUNCTION is one of the _FETCH_OP_ or _OP_FETCH_
+   built-ins.  ORIG_FORMAT is for __sync_* rather than __atomic_*
    built-ins.  */
 
 static int
-sync_resolve_size (tree function, vec<tree, va_gc> *params, bool fetch)
+sync_resolve_size (tree function, vec<tree, va_gc> *params, bool fetch,
+		   bool orig_format)
 {
   /* Type of the argument.  */
   tree argtype;
@@ -7225,9 +7235,19 @@ sync_resolve_size (tree function, vec<tr
     goto incompatible;
 
   size = tree_to_uhwi (TYPE_SIZE_UNIT (type));
+  if (size == 16
+      && fetch
+      && !orig_format
+      && TREE_CODE (type) == BITINT_TYPE
+      && !targetm.scalar_mode_supported_p (TImode))
+    return -1;
+
   if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16)
     return size;
 
+  if (fetch && !orig_format && TREE_CODE (type) == BITINT_TYPE)
+    return -1;
+
  incompatible:
   /* Issue the diagnostic only if the argument is valid, otherwise
      it would be redundant at best and could be misleading.  */
@@ -7844,6 +7864,223 @@ resolve_overloaded_atomic_store (locatio
 }
 
 
+/* Emit __atomic*fetch* on _BitInt which doesn't have a size of
+   1, 2, 4, 8 or 16 bytes using __atomic_compare_exchange loop.
+   ORIG_CODE is the DECL_FUNCTION_CODE of ORIG_FUNCTION and
+   ORIG_PARAMS arguments of the call.  */
+
+static tree
+atomic_bitint_fetch_using_cas_loop (location_t loc,
+				    enum built_in_function orig_code,
+				    tree orig_function,
+				    vec<tree, va_gc> *orig_params)
+{
+  enum tree_code code = ERROR_MARK;
+  bool return_old_p = false;
+  switch (orig_code)
+    {
+    case BUILT_IN_ATOMIC_ADD_FETCH_N:
+      code = PLUS_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_SUB_FETCH_N:
+      code = MINUS_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_AND_FETCH_N:
+      code = BIT_AND_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_NAND_FETCH_N:
+      break;
+    case BUILT_IN_ATOMIC_XOR_FETCH_N:
+      code = BIT_XOR_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_OR_FETCH_N:
+      code = BIT_IOR_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_ADD_N:
+      code = PLUS_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_SUB_N:
+      code = MINUS_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_AND_N:
+      code = BIT_AND_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_NAND_N:
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_XOR_N:
+      code = BIT_XOR_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_OR_N:
+      code = BIT_IOR_EXPR;
+      return_old_p = true;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (orig_params->length () != 3)
+    {
+      if (orig_params->length () < 3)
+	error_at (loc, "too few arguments to function %qE", orig_function);
+      else
+	error_at (loc, "too many arguments to function %qE", orig_function);
+      return error_mark_node;
+    }
+
+  tree stmts = push_stmt_list ();
+
+  tree nonatomic_lhs_type = TREE_TYPE (TREE_TYPE ((*orig_params)[0]));
+  nonatomic_lhs_type = TYPE_MAIN_VARIANT (nonatomic_lhs_type);
+  gcc_assert (TREE_CODE (nonatomic_lhs_type) == BITINT_TYPE);
+
+  tree lhs_addr = (*orig_params)[0];
+  tree val = convert (nonatomic_lhs_type, (*orig_params)[1]);
+  tree model = convert (integer_type_node, (*orig_params)[2]);
+  if (TREE_SIDE_EFFECTS (lhs_addr))
+    {
+      tree var = create_tmp_var_raw (TREE_TYPE (lhs_addr));
+      lhs_addr = build4 (TARGET_EXPR, TREE_TYPE (lhs_addr), var, lhs_addr,
+			 NULL_TREE, NULL_TREE);
+      add_stmt (lhs_addr);
+    }
+  if (TREE_SIDE_EFFECTS (val))
+    {
+      tree var = create_tmp_var_raw (nonatomic_lhs_type);
+      val = build4 (TARGET_EXPR, nonatomic_lhs_type, var, val, NULL_TREE,
+		    NULL_TREE);
+      add_stmt (val);
+    }
+  if (TREE_SIDE_EFFECTS (model))
+    {
+      tree var = create_tmp_var_raw (integer_type_node);
+      model = build4 (TARGET_EXPR, integer_type_node, var, model, NULL_TREE,
+		      NULL_TREE);
+      add_stmt (model);
+    }
+
+  tree old = create_tmp_var_raw (nonatomic_lhs_type);
+  tree old_addr = build_unary_op (loc, ADDR_EXPR, old, false);
+  TREE_ADDRESSABLE (old) = 1;
+  suppress_warning (old);
+
+  tree newval = create_tmp_var_raw (nonatomic_lhs_type);
+  tree newval_addr = build_unary_op (loc, ADDR_EXPR, newval, false);
+  TREE_ADDRESSABLE (newval) = 1;
+  suppress_warning (newval);
+
+  tree loop_decl = create_artificial_label (loc);
+  tree loop_label = build1 (LABEL_EXPR, void_type_node, loop_decl);
+
+  tree done_decl = create_artificial_label (loc);
+  tree done_label = build1 (LABEL_EXPR, void_type_node, done_decl);
+
+  vec<tree, va_gc> *params;
+  vec_alloc (params, 6);
+
+  /* __atomic_load (addr, &old, SEQ_CST).  */
+  tree fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD);
+  params->quick_push (lhs_addr);
+  params->quick_push (old_addr);
+  params->quick_push (build_int_cst (integer_type_node, MEMMODEL_RELAXED));
+  tree func_call = resolve_overloaded_builtin (loc, fndecl, params);
+  if (func_call == NULL_TREE)
+    func_call = build_function_call_vec (loc, vNULL, fndecl, params, NULL);
+  old = build4 (TARGET_EXPR, nonatomic_lhs_type, old, func_call, NULL_TREE,
+		NULL_TREE);
+  add_stmt (old);
+  params->truncate (0);
+
+  /* loop:  */
+  add_stmt (loop_label);
+
+  /* newval = old + val;  */
+  tree rhs;
+  switch (code)
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      if (!TYPE_OVERFLOW_WRAPS (nonatomic_lhs_type))
+	{
+	  tree utype
+	    = build_bitint_type (TYPE_PRECISION (nonatomic_lhs_type), 1);
+	  rhs = convert (nonatomic_lhs_type,
+			 build2_loc (loc, code, utype,
+				     convert (utype, old),
+				     convert (utype, val)));
+	}
+      else
+	rhs = build2_loc (loc, code, nonatomic_lhs_type, old, val);
+      break;
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+      rhs = build2_loc (loc, code, nonatomic_lhs_type, old, val);
+      break;
+    case ERROR_MARK:
+      rhs = build2_loc (loc, BIT_AND_EXPR, nonatomic_lhs_type,
+			build1_loc (loc, BIT_NOT_EXPR,
+				    nonatomic_lhs_type, old), val);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  rhs = build4 (TARGET_EXPR, nonatomic_lhs_type, newval, rhs, NULL_TREE,
+		NULL_TREE);
+  SET_EXPR_LOCATION (rhs, loc);
+  add_stmt (rhs);
+
+  /* if (__atomic_compare_exchange (addr, &old, &new, false, model, model))
+       goto done;  */
+  fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_COMPARE_EXCHANGE);
+  params->quick_push (lhs_addr);
+  params->quick_push (old_addr);
+  params->quick_push (newval_addr);
+  params->quick_push (integer_zero_node);
+  params->quick_push (model);
+  if (tree_fits_uhwi_p (model)
+      && (tree_to_uhwi (model) == MEMMODEL_RELEASE
+	  || tree_to_uhwi (model) == MEMMODEL_ACQ_REL))
+    params->quick_push (build_int_cst (integer_type_node, MEMMODEL_RELAXED));
+  else
+    params->quick_push (model);
+  func_call = resolve_overloaded_builtin (loc, fndecl, params);
+  if (func_call == NULL_TREE)
+    func_call = build_function_call_vec (loc, vNULL, fndecl, params, NULL);
+
+  tree goto_stmt = build1 (GOTO_EXPR, void_type_node, done_decl);
+  SET_EXPR_LOCATION (goto_stmt, loc);
+
+  tree stmt
+    = build3 (COND_EXPR, void_type_node, func_call, goto_stmt, NULL_TREE);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+
+  /* goto loop;  */
+  goto_stmt = build1 (GOTO_EXPR, void_type_node, loop_decl);
+  SET_EXPR_LOCATION (goto_stmt, loc);
+  add_stmt (goto_stmt);
+
+  /* done:  */
+  add_stmt (done_label);
+
+  tree ret = create_tmp_var_raw (nonatomic_lhs_type);
+  stmt = build2_loc (loc, MODIFY_EXPR, void_type_node, ret,
+		     return_old_p ? old : newval);
+  add_stmt (stmt);
+
+  /* Finish the compound statement.  */
+  stmts = pop_stmt_list (stmts);
+
+  return build4 (TARGET_EXPR, nonatomic_lhs_type, ret, stmts, NULL_TREE,
+		 NULL_TREE);
+}
+
+
 /* Some builtin functions are placeholders for other expressions.  This
    function should be called immediately after parsing the call expression
    before surrounding code has committed to the type of the expression.
@@ -8025,19 +8262,22 @@ resolve_overloaded_builtin (location_t l
 	/* The following are not _FETCH_OPs and must be accepted with
 	   pointers to _Bool (or C++ bool).  */
 	if (fetch_op)
-	  fetch_op =
-	    (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N
-	     && orig_code != BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
-	     && orig_code != BUILT_IN_SYNC_LOCK_TEST_AND_SET_N
-	     && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N);
+	  fetch_op = (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N
+		      && orig_code != BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
+		      && orig_code != BUILT_IN_SYNC_LOCK_TEST_AND_SET_N
+		      && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N);
 
-	int n = sync_resolve_size (function, params, fetch_op);
+	int n = sync_resolve_size (function, params, fetch_op, orig_format);
 	tree new_function, first_param, result;
 	enum built_in_function fncode;
 
 	if (n == 0)
 	  return error_mark_node;
 
+	if (n == -1)
+	  return atomic_bitint_fetch_using_cas_loop (loc, orig_code,
+						     function, params);
+
 	fncode = (enum built_in_function)((int)orig_code + exact_log2 (n) + 1);
 	new_function = builtin_decl_explicit (fncode);
 	if (!sync_resolve_params (loc, function, new_function, params,
@@ -8402,6 +8642,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-08-08 15:55:05.244182129 +0200
+++ gcc/c-family/c-common.h	2023-08-08 16:12:02.331939770 +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-08-08 15:54:33.448627395 +0200
+++ gcc/c-family/c-cppbuiltin.cc	2023-08-08 16:12:02.331939770 +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-08-08 15:55:05.245182116 +0200
+++ gcc/c-family/c-lex.cc	2023-08-08 16:12:02.332939756 +0200
@@ -837,6 +837,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-08-08 15:54:33.553625925 +0200
+++ gcc/c-family/c-pretty-print.cc	2023-08-08 16:12:02.332939756 +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/c-convert.cc.jj	2023-08-08 15:54:33.642624678 +0200
+++ gcc/c/c-convert.cc	2023-08-08 16:12:02.332939756 +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-08-08 15:55:05.277181667 +0200
+++ gcc/c/c-decl.cc	2023-08-08 16:15:41.006877794 +0200
@@ -6390,7 +6390,8 @@ check_bitfield_type_and_width (location_
   /* Detect invalid bit-field type.  */
   if (TREE_CODE (*type) != INTEGER_TYPE
       && TREE_CODE (*type) != BOOLEAN_TYPE
-      && TREE_CODE (*type) != ENUMERAL_TYPE)
+      && TREE_CODE (*type) != ENUMERAL_TYPE
+      && TREE_CODE (*type) != BITINT_TYPE)
     {
       error_at (loc, "bit-field %qs has invalid type", name);
       *type = unsigned_type_node;
@@ -9330,8 +9331,14 @@ finish_struct (location_t loc, tree t, t
 	  tree type = TREE_TYPE (field);
 	  if (width != TYPE_PRECISION (type))
 	    {
-	      TREE_TYPE (field)
-		= c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type));
+	      if (TREE_CODE (type) == BITINT_TYPE
+		  && (width > 1 || TYPE_UNSIGNED (type)))
+		TREE_TYPE (field)
+		  = build_bitint_type (width, TYPE_UNSIGNED (type));
+	      else
+		TREE_TYPE (field)
+		  = c_build_bitfield_integer_type (width,
+						   TYPE_UNSIGNED (type));
 	      SET_DECL_MODE (field, TYPE_MODE (TREE_TYPE (field)));
 	    }
 	  DECL_INITIAL (field) = NULL_TREE;
@@ -11546,14 +11553,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 "
@@ -11566,8 +11577,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)
@@ -11606,11 +11617,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 "
@@ -11627,8 +11642,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)
@@ -11679,8 +11694,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)
@@ -11731,8 +11746,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)
@@ -11770,6 +11785,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 "
@@ -11809,7 +11828,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,
@@ -11823,6 +11842,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 "
@@ -11843,8 +11866,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)
@@ -11882,7 +11905,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)
 	    {
@@ -11927,7 +11950,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.  */
@@ -11935,29 +11958,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
 		{
@@ -12115,12 +12138,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"
 			  : ""));
 
@@ -12128,49 +12151,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"
 			     : ""));
 		}
@@ -12267,6 +12290,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;
@@ -12668,12 +12748,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,
@@ -12733,12 +12813,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:
@@ -12840,6 +12920,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-08-08 15:55:05.286181541 +0200
+++ gcc/c/c-parser.cc	2023-08-08 16:12:02.336939700 +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:
@@ -3358,6 +3360,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
@@ -5005,6 +5031,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-08-08 15:54:33.812622298 +0200
+++ gcc/c/c-tree.h	2023-08-08 16:12:02.336939700 +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-08-08 15:54:33.822622158 +0200
+++ gcc/c/c-typeck.cc	2023-08-08 16:15:41.008877766 +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
@@ -2260,12 +2279,17 @@ perform_integral_promotions (tree exp)
   /* ??? This should no longer be needed now bit-fields have their
      proper types.  */
   if (TREE_CODE (exp) == COMPONENT_REF
-      && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))
+      && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1)))
+    {
+      if (TREE_CODE (DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1)))
+	  == BITINT_TYPE)
+	return convert (DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1)), exp);
       /* If it's thinner than an int, promote it like a
 	 c_promoting_integer_type_p, otherwise leave it alone.  */
-      && compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)),
-			   TYPE_PRECISION (integer_type_node)) < 0)
-    return convert (integer_type_node, exp);
+      if (compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)),
+			    TYPE_PRECISION (integer_type_node)) < 0)
+	return convert (integer_type_node, exp);
+    }
 
   if (c_promoting_integer_type_p (type))
     {
@@ -2790,7 +2814,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 +4583,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 +4597,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 +4610,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 +4685,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 +4798,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 +5423,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 +5612,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 +5624,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 +7162,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 +8593,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 +12389,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 +12415,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 +12438,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 +12453,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 +12471,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 +12492,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 +12511,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 +12579,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 +12640,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 +12757,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 +12821,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 +12916,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 +12977,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 +13038,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-08-08 15:54:35.666596337 +0200
+++ libcpp/expr.cc	2023-08-08 16:12:02.346939560 +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-08-08 15:54:35.691595987 +0200
+++ libcpp/include/cpplib.h	2023-08-08 16:12:02.346939560 +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.  */

	Jakub


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 10/12] C _BitInt support [PR102989]
  2023-08-09 18:25 [PATCH 10/12] C _BitInt support [PR102989] Jakub Jelinek
@ 2023-09-05 22:40 ` Joseph Myers
  2023-09-06 16:07   ` [committed 10/12 v2] " Jakub Jelinek
  2023-09-06 16:09   ` [committed 19/12] Additional _BitInt test coverage [PR102989] Jakub Jelinek
  0 siblings, 2 replies; 4+ messages in thread
From: Joseph Myers @ 2023-09-05 22:40 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On Wed, 9 Aug 2023, Jakub Jelinek via Gcc-patches wrote:

> 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 patches really do nothing without this, which enables
> all the support.

Additional tests I think should be added (for things I expect should 
already work):

* Tests for BITINT_MAXWIDTH in <limits.h>.  Test that it's defined for 
C2x, but not defined for C11/C17 (the latter independent of whether the 
target has _BitInt support).  Test the value as well: _BitInt 
(BITINT_MAXWIDTH) should be OK (both signed and unsigned) but _BitInt 
(BITINT_MAXWIDTH + 1) should not be OK.  Also test that BITINT_MAXWIDTH >= 
ULLONG_MAX.

* Test _BitInt (N) where N is a constexpr variable or enum constant (I 
expect these should work - the required call to convert_lvalue_to_rvalue 
for constexpr to work is present - but I don't see such tests in the 
testsuite).

* Test that -funsigned-bitfields does not affect the signedness of _BitInt 
(N) bit-fields (the standard wording isn't entirely clear, but that's 
what's implemented in the patches).

* Test the errors for _Sat used with _BitInt (though such a test might not 
actually run at present because no target supports both features).

I looked at places in c-family/ and c/ that refer to INTEGER_TYPE to 
consider whether they should handle BITINT_TYPE and whether that matches 
what the patch does there.  I think the following places that don't handle 
it probably should (with appropriate testcases added for the relevant 
functionality, e.g. warnings) unless there is some specific reason in each 
case why that's unnecessary or incorrect.  c-pretty-print.cc: 
c_pretty_printer::direct_declarator and c_pretty_printer::declarator.  
c-warn.cc throughout.  Maybe c-ada-spec.cc, though it might be best to ask 
the Ada maintainers there.  c-common.cc: unsafe_conversion_p, 
c_common_truthvalue_conversion warnings, c_common_get_alias_set, 
check_builtin_function_arguments BUILT_IN_ASSUME_ALIGNED case.  
c-aux-info.cc (might need other support for generating appropriate names 
in output).  c-parser.cc:c_parser_omp_clause_schedule.  c-fold.cc 
throughout.  c-typeck.c: the build_conditional_expr case where one operand 
is EXCESS_PRECISION_EXPR; build_c_cast; convert_for_assignment checks for 
integer/pointer conversions.

In the parser, the syntax comment on c_parser_declspecs should have 
_BitInt syntax added.

> +		      error_at (loc, "%<_BitInt%> argument %qE is not "
> +				     "positive integer constant expression",

"is not positive" should be "is not a positive" here.

> --- gcc/c/c-typeck.cc.jj	2023-08-08 15:54:33.822622158 +0200
> +++ gcc/c/c-typeck.cc	2023-08-08 16:15:41.008877766 +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;

I think these changes to handle BITINT_TYPE are unnecessary (don't do 
anything), since enumerated types can't have bit-precise underlying type 
(this code is about making a predictable choice of the enumerated type as 
the composite of an enumerated type and its underlying integer type).

OK with those fixes.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [committed 10/12 v2] C _BitInt support [PR102989]
  2023-09-05 22:40 ` Joseph Myers
@ 2023-09-06 16:07   ` Jakub Jelinek
  2023-09-06 16:09   ` [committed 19/12] Additional _BitInt test coverage [PR102989] Jakub Jelinek
  1 sibling, 0 replies; 4+ messages in thread
From: Jakub Jelinek @ 2023-09-06 16:07 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches

Hi!

Thanks for the patch reviews (and to Richi and Uros as well) and everyone
who participated in discussions.

Here is the updated version of the C _BitInt support [PR102989] patch
I've committed to trunk in addition to the rest of the series (except the
_BitInt a ? ~b : b match.pd fix patch, which will need to be resolved
eventually).

On Tue, Sep 05, 2023 at 10:40:26PM +0000, Joseph Myers wrote:
> Maybe c-ada-spec.cc, though it might be best to ask 
> the Ada maintainers there.

I've skipped c-ada-spec.cc and will file a PR for Ada maintainers,
it is up to them to decide what they want and how to implement that.

2023-09-06  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.
	(unsafe_conversion_p): Handle BITINT_TYPE like INTEGER_TYPE.
	(c_common_signed_or_unsigned_type): Handle BITINT_TYPE.
	(c_common_truthvalue_conversion, c_common_get_alias_set,
	check_builtin_function_arguments): Handle BITINT_TYPE like
	INTEGER_TYPE.
	(sync_resolve_size): Add ORIG_FORMAT argument.  If
	FETCH && !ORIG_FORMAT, type is BITINT_TYPE, return -1 if size isn't
	one of 1, 2, 4, 8 or 16 or if it is 16 but TImode is not supported.
	(atomic_bitint_fetch_using_cas_loop): New function.
	(resolve_overloaded_builtin): Adjust sync_resolve_size caller.  If
	-1 is returned, use atomic_bitint_fetch_using_cas_loop to lower it.
	Formatting fix.
	(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,
	c_pretty_printer::direct_declarator, c_pretty_printer::declarator):
	Handle BITINT_TYPE.
	(pp_c_integer_constant): Handle printing of large precision wide_ints
	which would buffer overflow digit_buffer.
	* c-warn.cc (conversion_warning, warnings_for_convert_and_check,
	warnings_for_convert_and_check): Handle BITINT_TYPE like
	INTEGER_TYPE.
gcc/c/
	* c-convert.cc (c_convert): Handle BITINT_TYPE like INTEGER_TYPE.
	* c-decl.cc (check_bitfield_type_and_width): Allow BITINT_TYPE
	bit-fields.
	(finish_struct): Prefer to use BITINT_TYPE for BITINT_TYPE bit-fields
	if possible.
	(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_parser_omp_clause_schedule): Handle BITINT_TYPE like INTEGER_TYPE.
	* 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 (c_common_type, comptypes_internal):
	Handle BITINT_TYPE.
	(perform_integral_promotions): Promote BITINT_TYPE bit-fields to
	their declared type.
	(build_array_ref, build_unary_op, build_conditional_expr,
	build_c_cast, convert_for_assignment, digest_init, build_binary_op):
	Handle BITINT_TYPE.
	* c-fold.cc (c_fully_fold_internal): Handle BITINT_TYPE like
	INTEGER_TYPE.
	* c-aux-info.cc (gen_type): Handle BITINT_TYPE.
libcpp/
	* expr.cc (interpret_int_suffix): Handle wb and WB suffixes.
	* include/cpplib.h (CPP_N_BITINT): Define.

--- gcc/glimits.h.jj	2023-09-05 16:44:32.269305435 +0200
+++ gcc/glimits.h	2023-09-06 09:14:53.950335938 +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-09-05 16:44:32.110307593 +0200
+++ gcc/c-family/c-common.cc	2023-09-06 09:55:30.836992346 +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 },
@@ -1490,14 +1491,17 @@ unsafe_conversion_p (tree type, tree exp
       /* Warn for real constant that is not an exact integer converted
 	 to integer type.  */
       if (SCALAR_FLOAT_TYPE_P (expr_type)
-	  && TREE_CODE (type) == INTEGER_TYPE)
+	  && (TREE_CODE (type) == INTEGER_TYPE
+	      || TREE_CODE (type) == BITINT_TYPE))
 	{
 	  if (!real_isinteger (TREE_REAL_CST_PTR (expr), TYPE_MODE (expr_type)))
 	    give_warning = UNSAFE_REAL;
 	}
       /* Warn for an integer constant that does not fit into integer type.  */
-      else if (TREE_CODE (expr_type) == INTEGER_TYPE
-	       && TREE_CODE (type) == INTEGER_TYPE
+      else if ((TREE_CODE (expr_type) == INTEGER_TYPE
+		|| TREE_CODE (expr_type) == BITINT_TYPE)
+	       && (TREE_CODE (type) == INTEGER_TYPE
+		   || TREE_CODE (type) == BITINT_TYPE)
 	       && !int_fits_type_p (expr, type))
 	{
 	  if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)
@@ -1517,7 +1521,8 @@ unsafe_conversion_p (tree type, tree exp
       else if (SCALAR_FLOAT_TYPE_P (type))
 	{
 	  /* Warn for an integer constant that does not fit into real type.  */
-	  if (TREE_CODE (expr_type) == INTEGER_TYPE)
+	  if (TREE_CODE (expr_type) == INTEGER_TYPE
+	      || TREE_CODE (expr_type) == BITINT_TYPE)
 	    {
 	      REAL_VALUE_TYPE a = real_value_from_int_cst (0, expr);
 	      if (!exact_real_truncate (TYPE_MODE (type), &a))
@@ -1586,11 +1591,14 @@ unsafe_conversion_p (tree type, tree exp
     {
       /* Warn for real types converted to integer types.  */
       if (SCALAR_FLOAT_TYPE_P (expr_type)
-	  && TREE_CODE (type) == INTEGER_TYPE)
+	  && (TREE_CODE (type) == INTEGER_TYPE
+	      || TREE_CODE (type) == BITINT_TYPE))
 	give_warning = UNSAFE_REAL;
 
-      else if (TREE_CODE (expr_type) == INTEGER_TYPE
-	       && TREE_CODE (type) == INTEGER_TYPE)
+      else if ((TREE_CODE (expr_type) == INTEGER_TYPE
+		|| TREE_CODE (expr_type) == BITINT_TYPE)
+	       && (TREE_CODE (type) == INTEGER_TYPE
+		   || TREE_CODE (type) == BITINT_TYPE))
 	{
 	  /* Don't warn about unsigned char y = 0xff, x = (int) y;  */
 	  expr = get_unwidened (expr, 0);
@@ -1656,7 +1664,8 @@ unsafe_conversion_p (tree type, tree exp
       /* Warn for integer types converted to real types if and only if
 	 all the range of values of the integer type cannot be
 	 represented by the real type.  */
-      else if (TREE_CODE (expr_type) == INTEGER_TYPE
+      else if ((TREE_CODE (expr_type) == INTEGER_TYPE
+		|| TREE_CODE (expr_type) == BITINT_TYPE)
 	       && SCALAR_FLOAT_TYPE_P (type))
 	{
 	  /* Don't warn about char y = 0xff; float x = (int) y;  */
@@ -2730,6 +2739,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))
@@ -3603,7 +3615,8 @@ c_common_truthvalue_conversion (location
 	 was used in anticipation of a possible overflow.
 	 Furthermore, if we see an unsigned type here we know that the
 	 result of the shift is not subject to integer promotion rules.  */
-      if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+      if ((TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+	   || TREE_CODE (TREE_TYPE (expr)) == BITINT_TYPE)
 	  && !TYPE_UNSIGNED (TREE_TYPE (expr)))
 	warning_at (EXPR_LOCATION (expr), OPT_Wint_in_bool_context,
 		    "%<<<%> in boolean context, did you mean %<<%>?");
@@ -3687,7 +3700,8 @@ c_common_truthvalue_conversion (location
 	  {
 	    tree op0 = TREE_OPERAND (expr, 0);
 	    if ((TREE_CODE (fromtype) == POINTER_TYPE
-		 && TREE_CODE (totype) == INTEGER_TYPE)
+		 && (TREE_CODE (totype) == INTEGER_TYPE
+		     || TREE_CODE (totype) == BITINT_TYPE))
 		|| warning_suppressed_p (expr, OPT_Waddress))
 	      /* Suppress -Waddress for casts to intptr_t, propagating
 		 any suppression from the enclosing expression to its
@@ -3826,7 +3840,8 @@ c_common_get_alias_set (tree t)
   /* The C standard specifically allows aliasing between signed and
      unsigned variants of the same type.  We treat the signed
      variant as canonical.  */
-  if (TREE_CODE (t) == INTEGER_TYPE && TYPE_UNSIGNED (t))
+  if ((TREE_CODE (t) == INTEGER_TYPE || TREE_CODE (t) == BITINT_TYPE)
+      && TYPE_UNSIGNED (t))
     {
       tree t1 = c_common_signed_type (t);
 
@@ -6343,8 +6358,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);
@@ -6378,7 +6395,9 @@ check_builtin_function_arguments (locati
     case BUILT_IN_ASSUME_ALIGNED:
       if (builtin_function_validate_nargs (loc, fndecl, nargs, 2 + (nargs > 2)))
 	{
-	  if (nargs >= 3 && TREE_CODE (TREE_TYPE (args[2])) != INTEGER_TYPE)
+	  if (nargs >= 3
+	      && TREE_CODE (TREE_TYPE (args[2])) != INTEGER_TYPE
+	      && TREE_CODE (TREE_TYPE (args[2])) != BITINT_TYPE)
 	    {
 	      error_at (ARG_LOCATION (2), "non-integer argument 3 in call to "
 			"function %qE", fndecl);
@@ -7187,12 +7206,16 @@ speculation_safe_value_resolve_return (t
 /* A helper function for resolve_overloaded_builtin in resolving the
    overloaded __sync_ builtins.  Returns a positive power of 2 if the
    first operand of PARAMS is a pointer to a supported data type.
-   Returns 0 if an error is encountered.
+   Returns 0 if an error is encountered.  Return -1 for _BitInt
+   __atomic*fetch* with unsupported type which should be handled by
+   a cas loop.
    FETCH is true when FUNCTION is one of the _FETCH_OP_ or _OP_FETCH_
+   built-ins.  ORIG_FORMAT is for __sync_* rather than __atomic_*
    built-ins.  */
 
 static int
-sync_resolve_size (tree function, vec<tree, va_gc> *params, bool fetch)
+sync_resolve_size (tree function, vec<tree, va_gc> *params, bool fetch,
+		   bool orig_format)
 {
   /* Type of the argument.  */
   tree argtype;
@@ -7227,9 +7250,19 @@ sync_resolve_size (tree function, vec<tr
     goto incompatible;
 
   size = tree_to_uhwi (TYPE_SIZE_UNIT (type));
+  if (size == 16
+      && fetch
+      && !orig_format
+      && TREE_CODE (type) == BITINT_TYPE
+      && !targetm.scalar_mode_supported_p (TImode))
+    return -1;
+
   if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16)
     return size;
 
+  if (fetch && !orig_format && TREE_CODE (type) == BITINT_TYPE)
+    return -1;
+
  incompatible:
   /* Issue the diagnostic only if the argument is valid, otherwise
      it would be redundant at best and could be misleading.  */
@@ -7846,6 +7879,223 @@ resolve_overloaded_atomic_store (locatio
 }
 
 
+/* Emit __atomic*fetch* on _BitInt which doesn't have a size of
+   1, 2, 4, 8 or 16 bytes using __atomic_compare_exchange loop.
+   ORIG_CODE is the DECL_FUNCTION_CODE of ORIG_FUNCTION and
+   ORIG_PARAMS arguments of the call.  */
+
+static tree
+atomic_bitint_fetch_using_cas_loop (location_t loc,
+				    enum built_in_function orig_code,
+				    tree orig_function,
+				    vec<tree, va_gc> *orig_params)
+{
+  enum tree_code code = ERROR_MARK;
+  bool return_old_p = false;
+  switch (orig_code)
+    {
+    case BUILT_IN_ATOMIC_ADD_FETCH_N:
+      code = PLUS_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_SUB_FETCH_N:
+      code = MINUS_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_AND_FETCH_N:
+      code = BIT_AND_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_NAND_FETCH_N:
+      break;
+    case BUILT_IN_ATOMIC_XOR_FETCH_N:
+      code = BIT_XOR_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_OR_FETCH_N:
+      code = BIT_IOR_EXPR;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_ADD_N:
+      code = PLUS_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_SUB_N:
+      code = MINUS_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_AND_N:
+      code = BIT_AND_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_NAND_N:
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_XOR_N:
+      code = BIT_XOR_EXPR;
+      return_old_p = true;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_OR_N:
+      code = BIT_IOR_EXPR;
+      return_old_p = true;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (orig_params->length () != 3)
+    {
+      if (orig_params->length () < 3)
+	error_at (loc, "too few arguments to function %qE", orig_function);
+      else
+	error_at (loc, "too many arguments to function %qE", orig_function);
+      return error_mark_node;
+    }
+
+  tree stmts = push_stmt_list ();
+
+  tree nonatomic_lhs_type = TREE_TYPE (TREE_TYPE ((*orig_params)[0]));
+  nonatomic_lhs_type = TYPE_MAIN_VARIANT (nonatomic_lhs_type);
+  gcc_assert (TREE_CODE (nonatomic_lhs_type) == BITINT_TYPE);
+
+  tree lhs_addr = (*orig_params)[0];
+  tree val = convert (nonatomic_lhs_type, (*orig_params)[1]);
+  tree model = convert (integer_type_node, (*orig_params)[2]);
+  if (TREE_SIDE_EFFECTS (lhs_addr))
+    {
+      tree var = create_tmp_var_raw (TREE_TYPE (lhs_addr));
+      lhs_addr = build4 (TARGET_EXPR, TREE_TYPE (lhs_addr), var, lhs_addr,
+			 NULL_TREE, NULL_TREE);
+      add_stmt (lhs_addr);
+    }
+  if (TREE_SIDE_EFFECTS (val))
+    {
+      tree var = create_tmp_var_raw (nonatomic_lhs_type);
+      val = build4 (TARGET_EXPR, nonatomic_lhs_type, var, val, NULL_TREE,
+		    NULL_TREE);
+      add_stmt (val);
+    }
+  if (TREE_SIDE_EFFECTS (model))
+    {
+      tree var = create_tmp_var_raw (integer_type_node);
+      model = build4 (TARGET_EXPR, integer_type_node, var, model, NULL_TREE,
+		      NULL_TREE);
+      add_stmt (model);
+    }
+
+  tree old = create_tmp_var_raw (nonatomic_lhs_type);
+  tree old_addr = build_unary_op (loc, ADDR_EXPR, old, false);
+  TREE_ADDRESSABLE (old) = 1;
+  suppress_warning (old);
+
+  tree newval = create_tmp_var_raw (nonatomic_lhs_type);
+  tree newval_addr = build_unary_op (loc, ADDR_EXPR, newval, false);
+  TREE_ADDRESSABLE (newval) = 1;
+  suppress_warning (newval);
+
+  tree loop_decl = create_artificial_label (loc);
+  tree loop_label = build1 (LABEL_EXPR, void_type_node, loop_decl);
+
+  tree done_decl = create_artificial_label (loc);
+  tree done_label = build1 (LABEL_EXPR, void_type_node, done_decl);
+
+  vec<tree, va_gc> *params;
+  vec_alloc (params, 6);
+
+  /* __atomic_load (addr, &old, SEQ_CST).  */
+  tree fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD);
+  params->quick_push (lhs_addr);
+  params->quick_push (old_addr);
+  params->quick_push (build_int_cst (integer_type_node, MEMMODEL_RELAXED));
+  tree func_call = resolve_overloaded_builtin (loc, fndecl, params);
+  if (func_call == NULL_TREE)
+    func_call = build_function_call_vec (loc, vNULL, fndecl, params, NULL);
+  old = build4 (TARGET_EXPR, nonatomic_lhs_type, old, func_call, NULL_TREE,
+		NULL_TREE);
+  add_stmt (old);
+  params->truncate (0);
+
+  /* loop:  */
+  add_stmt (loop_label);
+
+  /* newval = old + val;  */
+  tree rhs;
+  switch (code)
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      if (!TYPE_OVERFLOW_WRAPS (nonatomic_lhs_type))
+	{
+	  tree utype
+	    = build_bitint_type (TYPE_PRECISION (nonatomic_lhs_type), 1);
+	  rhs = convert (nonatomic_lhs_type,
+			 build2_loc (loc, code, utype,
+				     convert (utype, old),
+				     convert (utype, val)));
+	}
+      else
+	rhs = build2_loc (loc, code, nonatomic_lhs_type, old, val);
+      break;
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+      rhs = build2_loc (loc, code, nonatomic_lhs_type, old, val);
+      break;
+    case ERROR_MARK:
+      rhs = build2_loc (loc, BIT_AND_EXPR, nonatomic_lhs_type,
+			build1_loc (loc, BIT_NOT_EXPR,
+				    nonatomic_lhs_type, old), val);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  rhs = build4 (TARGET_EXPR, nonatomic_lhs_type, newval, rhs, NULL_TREE,
+		NULL_TREE);
+  SET_EXPR_LOCATION (rhs, loc);
+  add_stmt (rhs);
+
+  /* if (__atomic_compare_exchange (addr, &old, &new, false, model, model))
+       goto done;  */
+  fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_COMPARE_EXCHANGE);
+  params->quick_push (lhs_addr);
+  params->quick_push (old_addr);
+  params->quick_push (newval_addr);
+  params->quick_push (integer_zero_node);
+  params->quick_push (model);
+  if (tree_fits_uhwi_p (model)
+      && (tree_to_uhwi (model) == MEMMODEL_RELEASE
+	  || tree_to_uhwi (model) == MEMMODEL_ACQ_REL))
+    params->quick_push (build_int_cst (integer_type_node, MEMMODEL_RELAXED));
+  else
+    params->quick_push (model);
+  func_call = resolve_overloaded_builtin (loc, fndecl, params);
+  if (func_call == NULL_TREE)
+    func_call = build_function_call_vec (loc, vNULL, fndecl, params, NULL);
+
+  tree goto_stmt = build1 (GOTO_EXPR, void_type_node, done_decl);
+  SET_EXPR_LOCATION (goto_stmt, loc);
+
+  tree stmt
+    = build3 (COND_EXPR, void_type_node, func_call, goto_stmt, NULL_TREE);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+
+  /* goto loop;  */
+  goto_stmt = build1 (GOTO_EXPR, void_type_node, loop_decl);
+  SET_EXPR_LOCATION (goto_stmt, loc);
+  add_stmt (goto_stmt);
+
+  /* done:  */
+  add_stmt (done_label);
+
+  tree ret = create_tmp_var_raw (nonatomic_lhs_type);
+  stmt = build2_loc (loc, MODIFY_EXPR, void_type_node, ret,
+		     return_old_p ? old : newval);
+  add_stmt (stmt);
+
+  /* Finish the compound statement.  */
+  stmts = pop_stmt_list (stmts);
+
+  return build4 (TARGET_EXPR, nonatomic_lhs_type, ret, stmts, NULL_TREE,
+		 NULL_TREE);
+}
+
+
 /* Some builtin functions are placeholders for other expressions.  This
    function should be called immediately after parsing the call expression
    before surrounding code has committed to the type of the expression.
@@ -8027,19 +8277,22 @@ resolve_overloaded_builtin (location_t l
 	/* The following are not _FETCH_OPs and must be accepted with
 	   pointers to _Bool (or C++ bool).  */
 	if (fetch_op)
-	  fetch_op =
-	    (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N
-	     && orig_code != BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
-	     && orig_code != BUILT_IN_SYNC_LOCK_TEST_AND_SET_N
-	     && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N);
+	  fetch_op = (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N
+		      && orig_code != BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
+		      && orig_code != BUILT_IN_SYNC_LOCK_TEST_AND_SET_N
+		      && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N);
 
-	int n = sync_resolve_size (function, params, fetch_op);
+	int n = sync_resolve_size (function, params, fetch_op, orig_format);
 	tree new_function, first_param, result;
 	enum built_in_function fncode;
 
 	if (n == 0)
 	  return error_mark_node;
 
+	if (n == -1)
+	  return atomic_bitint_fetch_using_cas_loop (loc, orig_code,
+						     function, params);
+
 	fncode = (enum built_in_function)((int)orig_code + exact_log2 (n) + 1);
 	new_function = builtin_decl_explicit (fncode);
 	if (!sync_resolve_params (loc, function, new_function, params,
@@ -8404,6 +8657,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-09-05 16:44:32.111307579 +0200
+++ gcc/c-family/c-common.h	2023-09-06 09:14:53.952335909 +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-09-05 16:44:32.111307579 +0200
+++ gcc/c-family/c-cppbuiltin.cc	2023-09-06 09:14:53.952335909 +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-09-06 08:42:44.716239011 +0200
+++ gcc/c-family/c-lex.cc	2023-09-06 09:14:53.953335895 +0200
@@ -837,6 +837,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-09-05 16:44:32.112307566 +0200
+++ gcc/c-family/c-pretty-print.cc	2023-09-06 09:34:41.365581156 +0200
@@ -402,6 +402,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);
@@ -691,6 +708,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:
@@ -811,6 +829,7 @@ c_pretty_printer::direct_declarator (tre
     case REAL_TYPE:
     case FIXED_POINT_TYPE:
     case ENUMERAL_TYPE:
+    case BITINT_TYPE:
     case UNION_TYPE:
     case RECORD_TYPE:
       break;
@@ -834,6 +853,7 @@ c_pretty_printer::declarator (tree t)
     case REAL_TYPE:
     case FIXED_POINT_TYPE:
     case ENUMERAL_TYPE:
+    case BITINT_TYPE:
     case UNION_TYPE:
     case RECORD_TYPE:
       break;
@@ -1022,8 +1042,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-warn.cc.jj	2023-08-22 11:08:22.322559894 +0200
+++ gcc/c-family/c-warn.cc	2023-09-06 09:42:13.335295647 +0200
@@ -1306,8 +1306,10 @@ conversion_warning (location_t loc, tree
       }
 
     case BIT_AND_EXPR:
-      if (TREE_CODE (expr_type) == INTEGER_TYPE
-	  && TREE_CODE (type) == INTEGER_TYPE)
+      if ((TREE_CODE (expr_type) == INTEGER_TYPE
+	   || TREE_CODE (expr_type) == BITINT_TYPE)
+	  && (TREE_CODE (type) == INTEGER_TYPE
+	      || TREE_CODE (type) == BITINT_TYPE))
 	for (int i = 0; i < 2; ++i)
 	  {
 	    tree op = TREE_OPERAND (expr, i);
@@ -1416,6 +1418,7 @@ warnings_for_convert_and_check (location
 
   if (TREE_CODE (expr) == INTEGER_CST
       && (TREE_CODE (type) == INTEGER_TYPE
+	  || TREE_CODE (type) == BITINT_TYPE
 	  || (TREE_CODE (type) == ENUMERAL_TYPE
 	      && TREE_CODE (ENUM_UNDERLYING_TYPE (type)) != BOOLEAN_TYPE))
       && !int_fits_type_p (expr, type))
@@ -1466,9 +1469,10 @@ warnings_for_convert_and_check (location
 	}
       /* No warning for converting 0x80000000 to int.  */
       else if (pedantic
-	       && (TREE_CODE (exprtype) != INTEGER_TYPE
-		   || TYPE_PRECISION (exprtype)
-		   != TYPE_PRECISION (type)))
+	       && ((TREE_CODE (exprtype) != INTEGER_TYPE
+		    && TREE_CODE (exprtype) != BITINT_TYPE)
+		   || (TYPE_PRECISION (exprtype)
+		       != TYPE_PRECISION (type))))
 	{
 	  if (cst)
 	    warning_at (loc, OPT_Woverflow,
--- gcc/c/c-convert.cc.jj	2023-09-05 16:44:32.112307566 +0200
+++ gcc/c/c-convert.cc	2023-09-06 09:14:53.970335650 +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-09-06 08:44:56.438330573 +0200
+++ gcc/c/c-decl.cc	2023-09-06 09:16:31.328942411 +0200
@@ -6390,7 +6390,8 @@ check_bitfield_type_and_width (location_
   /* Detect invalid bit-field type.  */
   if (TREE_CODE (*type) != INTEGER_TYPE
       && TREE_CODE (*type) != BOOLEAN_TYPE
-      && TREE_CODE (*type) != ENUMERAL_TYPE)
+      && TREE_CODE (*type) != ENUMERAL_TYPE
+      && TREE_CODE (*type) != BITINT_TYPE)
     {
       error_at (loc, "bit-field %qs has invalid type", name);
       *type = unsigned_type_node;
@@ -9330,8 +9331,14 @@ finish_struct (location_t loc, tree t, t
 	  tree type = TREE_TYPE (field);
 	  if (width != TYPE_PRECISION (type))
 	    {
-	      TREE_TYPE (field)
-		= c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type));
+	      if (TREE_CODE (type) == BITINT_TYPE
+		  && (width > 1 || TYPE_UNSIGNED (type)))
+		TREE_TYPE (field)
+		  = build_bitint_type (width, TYPE_UNSIGNED (type));
+	      else
+		TREE_TYPE (field)
+		  = c_build_bitfield_integer_type (width,
+						   TYPE_UNSIGNED (type));
 	      SET_DECL_MODE (field, TYPE_MODE (TREE_TYPE (field)));
 	    }
 	  DECL_INITIAL (field) = NULL_TREE;
@@ -11546,14 +11553,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 "
@@ -11566,8 +11577,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)
@@ -11606,11 +11617,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 "
@@ -11627,8 +11642,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)
@@ -11679,8 +11694,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)
@@ -11731,8 +11746,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)
@@ -11770,6 +11785,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 "
@@ -11809,7 +11828,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,
@@ -11823,6 +11842,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 "
@@ -11843,8 +11866,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)
@@ -11882,7 +11905,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)
 	    {
@@ -11927,7 +11950,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.  */
@@ -11935,29 +11958,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
 		{
@@ -12115,13 +12138,13 @@ 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_c11 (loc, OPT_Wpedantic,
 			     "ISO C does not support the %<_Float%d%s%> type"
 			     " before C2X",
-			     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"
 			      : ""));
 
@@ -12129,49 +12152,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"
 			     : ""));
 		}
@@ -12268,6 +12291,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 a "
+				     "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;
@@ -12669,12 +12749,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,
@@ -12734,12 +12814,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:
@@ -12841,6 +12921,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-09-05 17:26:28.901232989 +0200
+++ gcc/c/c-parser.cc	2023-09-06 10:10:14.760380237 +0200
@@ -584,6 +584,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:
@@ -787,6 +788,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:
@@ -3118,6 +3120,7 @@ c_parser_static_assert_declaration_no_se
      _Bool
      _Complex
      [_Imaginary removed in C99 TC2]
+     _BitInt ( constant-expression )
      struct-or-union-specifier
      enum-specifier
      typedef-name
@@ -3125,6 +3128,7 @@ c_parser_static_assert_declaration_no_se
 
    (_Bool and _Complex are new in C99.)
    (atomic-type-specifier is new in C11.)
+   (_BitInt is new in C2X.)
 
    C90 6.5.3, C99 6.7.3, C11 6.7.3:
 
@@ -3401,6 +3405,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
@@ -5049,6 +5077,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:
@@ -16308,7 +16337,8 @@ c_parser_omp_clause_schedule (c_parser *
 	error_at (here,
 		  "schedule %<auto%> does not take "
 		  "a %<chunk_size%> parameter");
-      else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE)
+      else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
+	       || TREE_CODE (TREE_TYPE (t)) == BITINT_TYPE)
 	{
 	  /* Attempt to statically determine when the number isn't
 	     positive.  */
--- gcc/c/c-tree.h.jj	2023-09-05 16:44:32.118307484 +0200
+++ gcc/c/c-tree.h	2023-09-06 09:14:53.991335348 +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-09-05 16:44:32.120307457 +0200
+++ gcc/c/c-typeck.cc	2023-09-06 10:23:47.030839839 +0200
@@ -413,10 +413,12 @@ 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))
     return t1;
   if (code2 == ENUMERAL_TYPE
-      && (code1 == INTEGER_TYPE || code1 == BOOLEAN_TYPE))
+      && (code1 == INTEGER_TYPE
+	  || code1 == BOOLEAN_TYPE))
     return t2;
 
   gcc_assert (code1 == code2);
@@ -764,10 +766,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 +1006,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 +1193,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
@@ -2260,12 +2277,17 @@ perform_integral_promotions (tree exp)
   /* ??? This should no longer be needed now bit-fields have their
      proper types.  */
   if (TREE_CODE (exp) == COMPONENT_REF
-      && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))
+      && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1)))
+    {
+      if (TREE_CODE (DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1)))
+	  == BITINT_TYPE)
+	return convert (DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1)), exp);
       /* If it's thinner than an int, promote it like a
 	 c_promoting_integer_type_p, otherwise leave it alone.  */
-      && compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)),
-			   TYPE_PRECISION (integer_type_node)) < 0)
-    return convert (integer_type_node, exp);
+      if (compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)),
+			    TYPE_PRECISION (integer_type_node)) < 0)
+	return convert (integer_type_node, exp);
+    }
 
   if (c_promoting_integer_type_p (type))
     {
@@ -2790,7 +2812,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 +4581,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 +4595,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 +4608,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 +4683,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 +4796,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)
@@ -5351,9 +5378,9 @@ build_conditional_expr (location_t colon
   if ((TREE_CODE (op1) == EXCESS_PRECISION_EXPR
        || TREE_CODE (op2) == EXCESS_PRECISION_EXPR)
       && (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))
     {
       semantic_result_type = c_common_type (type1, type2);
       if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR)
@@ -5394,9 +5421,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 +5610,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 +5622,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,
@@ -6165,7 +6194,8 @@ build_c_cast (location_t loc, tree type,
 	warning_at (loc, OPT_Wcast_align,
 		    "cast increases required alignment of target type");
 
-      if (TREE_CODE (type) == INTEGER_TYPE
+      if ((TREE_CODE (type) == INTEGER_TYPE
+	   || TREE_CODE (type) == BITINT_TYPE)
 	  && TREE_CODE (otype) == POINTER_TYPE
 	  && TYPE_PRECISION (type) != TYPE_PRECISION (otype))
       /* Unlike conversion of integers to pointers, where the
@@ -6183,7 +6213,8 @@ build_c_cast (location_t loc, tree type,
 		    "to non-matching type %qT", otype, type);
 
       if (TREE_CODE (type) == POINTER_TYPE
-	  && TREE_CODE (otype) == INTEGER_TYPE
+	  && (TREE_CODE (otype) == INTEGER_TYPE
+	      || TREE_CODE (otype) == BITINT_TYPE)
 	  && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
 	  /* Don't warn about converting any constant.  */
 	  && !TREE_CONSTANT (value))
@@ -7135,11 +7166,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,
@@ -7715,7 +7746,9 @@ convert_for_assignment (location_t locat
       return error_mark_node;
     }
   else if (codel == POINTER_TYPE
-	   && (coder == INTEGER_TYPE || coder == NULLPTR_TYPE))
+	   && (coder == INTEGER_TYPE
+	       || coder == NULLPTR_TYPE
+	       || coder == BITINT_TYPE))
     {
       /* An explicit constant 0 or type nullptr_t can convert to a pointer,
 	 or one that results from arithmetic, even including a cast to
@@ -7756,7 +7789,8 @@ convert_for_assignment (location_t locat
 
       return convert (type, rhs);
     }
-  else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
+  else if ((codel == INTEGER_TYPE || codel == BITINT_TYPE)
+	   && coder == POINTER_TYPE)
     {
       switch (errtype)
 	{
@@ -8566,7 +8600,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
@@ -12361,12 +12396,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;
@@ -12385,7 +12422,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;
@@ -12407,11 +12445,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)))
 	{
@@ -12422,8 +12460,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
@@ -12439,7 +12478,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)
@@ -12459,7 +12499,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
@@ -12477,10 +12518,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
@@ -12543,9 +12586,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)
@@ -12603,9 +12647,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
@@ -12719,9 +12764,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
@@ -12782,12 +12828,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");
@@ -12875,9 +12923,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)
 	{
@@ -12936,12 +12984,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");
@@ -12995,12 +13045,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);
--- gcc/c/c-fold.cc.jj	2023-01-16 11:52:15.902736732 +0100
+++ gcc/c/c-fold.cc	2023-09-06 10:12:52.033141961 +0200
@@ -379,7 +379,8 @@ c_fully_fold_internal (tree expr, bool i
 	overflow_warning (EXPR_LOC_OR_LOC (expr, input_location), ret, expr);
       if (code == LSHIFT_EXPR
 	  && TREE_CODE (orig_op0) != INTEGER_CST
-	  && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+	  && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+	      || TREE_CODE (TREE_TYPE (orig_op0)) == BITINT_TYPE)
 	  && TREE_CODE (op0) == INTEGER_CST
 	  && c_inhibit_evaluation_warnings == 0
 	  && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (orig_op0))
@@ -398,6 +399,7 @@ c_fully_fold_internal (tree expr, bool i
 			 ? G_("left shift count is negative")
 			 : G_("right shift count is negative")));
 	  else if ((TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+		    || TREE_CODE (TREE_TYPE (orig_op0)) == BITINT_TYPE
 		    || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE)
 		   && compare_tree_int (op1,
 					TYPE_PRECISION (TREE_TYPE (orig_op0)))
@@ -418,11 +420,13 @@ c_fully_fold_internal (tree expr, bool i
       if (code == LSHIFT_EXPR
 	  /* If either OP0 has been folded to INTEGER_CST...  */
 	  && ((TREE_CODE (orig_op0) != INTEGER_CST
-	       && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+	       && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+		   || TREE_CODE (TREE_TYPE (orig_op0)) == BITINT_TYPE)
 	       && TREE_CODE (op0) == INTEGER_CST)
 	      /* ...or if OP1 has been folded to INTEGER_CST...  */
 	      || (TREE_CODE (orig_op1) != INTEGER_CST
-		  && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE
+		  && (TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE
+		      || TREE_CODE (TREE_TYPE (orig_op1)) == BITINT_TYPE)
 		  && TREE_CODE (op1) == INTEGER_CST))
 	  && c_inhibit_evaluation_warnings == 0)
 	/* ...then maybe we can detect an overflow.  */
@@ -435,8 +439,10 @@ c_fully_fold_internal (tree expr, bool i
 	  && TREE_CODE (orig_op1) != INTEGER_CST
 	  && TREE_CODE (op1) == INTEGER_CST
 	  && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+	      || TREE_CODE (TREE_TYPE (orig_op0)) == BITINT_TYPE
 	      || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE)
-	  && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE)
+	  && (TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE
+	      || TREE_CODE (TREE_TYPE (orig_op1)) == BITINT_TYPE))
 	warn_for_div_by_zero (loc, op1);
       if (code == MEM_REF
 	  && ret != expr
--- gcc/c/c-aux-info.cc.jj	2023-01-16 11:52:15.900736761 +0100
+++ gcc/c/c-aux-info.cc	2023-09-06 10:05:15.271654488 +0200
@@ -409,6 +409,17 @@ gen_type (const char *ret_val, tree t, f
 	    data_type = concat ("unsigned ", data_type, NULL);
 	  break;
 
+	case BITINT_TYPE:
+	  {
+	    char buf[sizeof ("2147483647")];
+	    sprintf (buf, "%d", TYPE_PRECISION (t));
+	    if (TYPE_UNSIGNED (t))
+	      data_type = concat ("unsigned _BitInt(", buf, ")", NULL);
+	    else
+	      data_type = concat ("_BitInt(", buf, ")", NULL);
+	    break;
+	  }
+
 	case OPAQUE_TYPE:
 	case REAL_TYPE:
 	  data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)));
--- libcpp/expr.cc.jj	2023-08-08 15:54:35.666596337 +0200
+++ libcpp/expr.cc	2023-08-08 16:12:02.346939560 +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-08-08 15:54:35.691595987 +0200
+++ libcpp/include/cpplib.h	2023-08-08 16:12:02.346939560 +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.  */


	Jakub


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [committed 19/12] Additional _BitInt test coverage [PR102989]
  2023-09-05 22:40 ` Joseph Myers
  2023-09-06 16:07   ` [committed 10/12 v2] " Jakub Jelinek
@ 2023-09-06 16:09   ` Jakub Jelinek
  1 sibling, 0 replies; 4+ messages in thread
From: Jakub Jelinek @ 2023-09-06 16:09 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches

On Tue, Sep 05, 2023 at 10:40:26PM +0000, Joseph Myers wrote:
> Additional tests I think should be added (for things I expect should 
> already work):
> 
> * Tests for BITINT_MAXWIDTH in <limits.h>.  Test that it's defined for 
> C2x, but not defined for C11/C17 (the latter independent of whether the 
> target has _BitInt support).  Test the value as well: _BitInt 
> (BITINT_MAXWIDTH) should be OK (both signed and unsigned) but _BitInt 
> (BITINT_MAXWIDTH + 1) should not be OK.  Also test that BITINT_MAXWIDTH >= 
> ULLONG_MAX.
> 
> * Test _BitInt (N) where N is a constexpr variable or enum constant (I 
> expect these should work - the required call to convert_lvalue_to_rvalue 
> for constexpr to work is present - but I don't see such tests in the 
> testsuite).
> 
> * Test that -funsigned-bitfields does not affect the signedness of _BitInt 
> (N) bit-fields (the standard wording isn't entirely clear, but that's 
> what's implemented in the patches).
> 
> * Test the errors for _Sat used with _BitInt (though such a test might not 
> actually run at present because no target supports both features).

Here is a patch which adds that test coverage.

> I looked at places in c-family/ and c/ that refer to INTEGER_TYPE to 
> consider whether they should handle BITINT_TYPE and whether that matches 
> what the patch does there.  I think the following places that don't handle 
> it probably should (with appropriate testcases added for the relevant 
> functionality, e.g. warnings) unless there is some specific reason in each 
> case why that's unnecessary or incorrect.  c-pretty-print.cc: 
> c_pretty_printer::direct_declarator and c_pretty_printer::declarator.  
> c-warn.cc throughout.  Maybe c-ada-spec.cc, though it might be best to ask 
> the Ada maintainers there.  c-common.cc: unsafe_conversion_p, 
> c_common_truthvalue_conversion warnings, c_common_get_alias_set, 
> check_builtin_function_arguments BUILT_IN_ASSUME_ALIGNED case.  
> c-aux-info.cc (might need other support for generating appropriate names 
> in output).  c-parser.cc:c_parser_omp_clause_schedule.  c-fold.cc 
> throughout.  c-typeck.c: the build_conditional_expr case where one operand 
> is EXCESS_PRECISION_EXPR; build_c_cast; convert_for_assignment checks for 
> integer/pointer conversions.

As well as what I've managed to come up for the above changes.

2023-09-06  Jakub Jelinek  <jakub@redhat.com>

	PR c/102989
	* gcc.dg/bitint-2.c (foo): Add tests for constexpr var or enumerator
	arguments of _BitInt.
	* gcc.dg/bitint-31.c: Remove forgotten 0 &&.
	* gcc.dg/bitint-32.c: New test.
	* gcc.dg/bitint-33.c: New test.
	* gcc.dg/bitint-34.c: New test.
	* gcc.dg/bitint-35.c: New test.
	* gcc.dg/bitint-36.c: New test.
	* gcc.dg/fixed-point/bitint-1.c: New test.

--- gcc/testsuite/gcc.dg/bitint-2.c.jj	2023-09-06 10:57:48.771535739 +0200
+++ gcc/testsuite/gcc.dg/bitint-2.c	2023-09-06 12:17:39.764073758 +0200
@@ -14,6 +14,10 @@ foo (void)
   _BitInt(5) unsigned d = (unsigned _BitInt(5)) 4;
   _BitInt(32) e = (_BitInt(32)) 5;
   _BitInt(32) unsigned f = (unsigned _BitInt(32)) 6;
+  constexpr int g = 43;
+  enum E { F = 44 };
+  _BitInt(g) h;
+  unsigned _BitInt(F) i;
   static_assert (expr_has_type (a, signed _BitInt(42)), "");
   static_assert (expr_has_type (a, _BitInt(42)), "");
   static_assert (!expr_has_type (a, unsigned _BitInt(42)), "");
@@ -66,6 +70,8 @@ foo (void)
   static_assert (expr_has_type (-1UWB, unsigned _BitInt(1)), "");
   static_assert (expr_has_type (1uWB, unsigned _BitInt(1)), "");
   static_assert (expr_has_type (2Uwb, unsigned _BitInt(2)), "");
+  static_assert (expr_has_type (h, signed _BitInt(43)), "");
+  static_assert (expr_has_type (i, unsigned _BitInt(44)), "");
   static_assert (0wb == 0, "");
   static_assert (-1wb == -1, "");
   static_assert (0xffffffffwb == 4294967295wb, "");
--- gcc/testsuite/gcc.dg/bitint-31.c.jj	2023-09-06 10:57:48.799535349 +0200
+++ gcc/testsuite/gcc.dg/bitint-31.c	2023-09-06 11:52:57.675594550 +0200
@@ -255,7 +255,7 @@ main ()
   check_round (testfltu_192 (340282356779733661637539395458142568448uwb), __builtin_inff (), 0xffffffp+104f, __builtin_inff (), 0xffffffp+104f);
   check_round (testfltu_192 (6277101735386680763835789423207666416102355444464034512895uwb), __builtin_inff (), 0xffffffp+104f, __builtin_inff (), 0xffffffp+104f);
 #endif
-#if 0 && __BITINT_MAXWIDTH__ >= 575
+#if __BITINT_MAXWIDTH__ >= 575
   check_round (testflt_575 (10633823015541376812058405359715352575wb), 0xfffffep+99f, 0xfffffep+99f, 0xffffffp+99f, 0xfffffep+99f);
   check_round (testflt_575 (10633823015541376812058405359715352576wb), 0xfffffep+99f, 0xfffffep+99f, 0xffffffp+99f, 0xfffffep+99f);
   check_round (testflt_575 (10633823015541376812058405359715352577wb), 0xffffffp+99f, 0xfffffep+99f, 0xffffffp+99f, 0xfffffep+99f);
--- gcc/testsuite/gcc.dg/bitint-32.c.jj	2023-09-06 11:57:24.391907466 +0200
+++ gcc/testsuite/gcc.dg/bitint-32.c	2023-09-06 12:00:04.885688154 +0200
@@ -0,0 +1,14 @@
+/* PR c/102989 */
+/* { dg-do compile { target bitint } } */
+/* { dg-options "-std=c2x" } */
+
+#include <limits.h>
+
+#ifndef BITINT_MAXWIDTH
+#error BITINT_MAXWIDTH not defined
+#elif BITINT_MAXWIDTH < ULLONG_WIDTH
+#error BITINT_MAXWIDTH smaller than ULLONG_WIDTH
+#endif
+
+_BitInt(BITINT_MAXWIDTH) a;
+_BitInt(BITINT_MAXWIDTH + 1) b;		/* { dg-error "'_BitInt' argument '\[0-9]+' is larger than 'BITINT_MAXWIDTH' '\[0-9]+'" } */
--- gcc/testsuite/gcc.dg/bitint-33.c.jj	2023-09-06 12:00:13.678566566 +0200
+++ gcc/testsuite/gcc.dg/bitint-33.c	2023-09-06 12:11:52.160893347 +0200
@@ -0,0 +1,9 @@
+/* PR c/102989 */
+/* { dg-do compile } */
+/* { dg-options "-std=c17" } */
+
+#include <limits.h>
+
+#ifdef BITINT_MAXWIDTH
+#error BITINT_MAXWIDTH defined in C11
+#endif
--- gcc/testsuite/gcc.dg/bitint-34.c.jj	2023-09-06 12:23:03.036601107 +0200
+++ gcc/testsuite/gcc.dg/bitint-34.c	2023-09-06 12:26:18.847894449 +0200
@@ -0,0 +1,16 @@
+/* PR c/102989 */
+/* Test that -funsigned-bitfields doesn't affect _BitInt bit-fields which are always signed.  */
+/* { dg-do run { target bitint } } */
+/* { dg-options "-std=c2x -funsigned-bitfields" } */
+
+struct S { _BitInt(22) a : 7; signed _BitInt(22) b : 7; unsigned _BitInt(22) c : 7; } s;
+
+int
+main ()
+{
+  s.a = -64;
+  s.b = -64;
+  s.c = -64;
+  if (s.a != -64 || s.b != -64 || s.c != 64)
+    __builtin_abort ();
+}
--- gcc/testsuite/gcc.dg/bitint-35.c.jj	2023-09-06 12:44:39.073802523 +0200
+++ gcc/testsuite/gcc.dg/bitint-35.c	2023-09-06 13:20:45.181074316 +0200
@@ -0,0 +1,37 @@
+/* PR c/102989 */
+/* { dg-do compile { target { bitint && { float32 && int32 } } } } */
+/* { dg-options "-std=c2x -Wconversion -Wfloat-conversion" } */
+/* { dg-add-options float32 } */
+
+void
+foo (_Float32 x)
+{
+  _BitInt(57) a = 1.5F32;				/* { dg-warning "conversion from '_Float32' to '_BitInt\\\(57\\\)' changes value from '1.5e\\\+0f32' to '1'" } */
+  _BitInt(27) b = 76117358uwb;				/* { dg-warning "signed conversion from 'unsigned _BitInt\\\(27\\\)' to '_BitInt\\\(27\\\)' changes value from '76117358' to '-58100370'" } */
+  unsigned _BitInt(27) c = -15wb;			/* { dg-warning "unsigned conversion from '_BitInt\\\(5\\\)' to 'unsigned _BitInt\\\(27\\\)' changes value from '-15' to '134217713'" } */
+  _BitInt(27) d = -390288573wb;				/* { dg-warning "overflow in conversion from '_BitInt\\\(30\\\)' to '_BitInt\\\(27\\\)' changes value from '-390288573' to '12364611'" } */
+  unsigned _BitInt(27) e = 309641337uwb;		/* { dg-warning "conversion from 'unsigned _BitInt\\\(29\\\)' to 'unsigned _BitInt\\\(27\\\)' changes value from '309641337' to '41205881'" } */
+  _BitInt(27) f = 76117358U;				/* { dg-warning "signed conversion from 'unsigned int' to '_BitInt\\\(27\\\)' changes value from '76117358' to '-58100370'" } */
+  unsigned _BitInt(27) g = -15;				/* { dg-warning "unsigned conversion from 'int' to 'unsigned _BitInt\\\(27\\\)' changes value from '-15' to '134217713'" } */
+  _BitInt(27) h = -390288573;				/* { dg-warning "overflow in conversion from 'int' to '_BitInt\\\(27\\\)' changes value from '-390288573' to '12364611'" } */
+  unsigned _BitInt(27) i = 309641337U;			/* { dg-warning "conversion from 'unsigned int' to 'unsigned _BitInt\\\(27\\\)' changes value from '309641337' to '41205881'" } */
+  int j = 2936216298uwb;				/* { dg-warning "signed conversion from 'unsigned _BitInt\\\(32\\\)' to 'int' changes value from '2936216298' to '-1358750998'" } */
+  unsigned int k = -15wb;				/* { dg-warning "unsigned conversion from '_BitInt\\\(5\\\)' to 'unsigned int' changes value from '-15' to '4294967281'" } */
+  int l = -8087431137529383656wb;			/* { dg-warning "overflow in conversion from '_BitInt\\\(64\\\)' to 'int' changes value from '-8087431137529383656' to '-1105152744'" } */
+  unsigned int m = 1664073919553255778uwb;		/* { dg-warning "conversion from 'unsigned _BitInt\\\(61\\\)' to 'unsigned int' changes value from '1664073919553255778' to '3338058082'" } */
+#if __BITINT_MAXWIDTH__ >= 575
+  _Float32 n = 51441631083309184313435496923626431699697406185384986811300218556561965470218425783308778801748592322915101142266821623326688106425864884688172114173397118407357447763009120wb;	/* { dg-warning "conversion from '_BitInt\\\(575\\\)' to '_Float32' changes value from '0x353eab28b46b03ea99b84f9736cd8dbe5e986915a0383c3cb381c0da41e31b3621c75fd53262bfcb1b0e6251dbf00f3988784e29b08b65640c263e4d0959832a20e2ff5245be1e60' to '\\\+Inff32'" "" { target bitint575 } } */
+#endif
+  _BitInt(57) o = x;					/* { dg-warning "conversion from '_Float32' to '_BitInt\\\(57\\\)' may change value" } */
+  unsigned _BitInt(15) p = 32767uwb;
+  unsigned _BitInt(15) q = (_BitInt(42)) p;
+  _BitInt(17) r = 0;
+  _BitInt(17) s = ((_BitInt(42)) r) & 32767wb;
+#if __BITINT_MAXWIDTH__ >= 575
+  _BitInt(575) t = 0;
+  _Float32 u = t;					/* { dg-warning "conversion from '_BitInt\\\(575\\\)' to '_Float32' may change value" "" { target bitint575 } } */
+#endif
+  _BitInt(42) v = 0;
+  unsigned _BitInt(17) w = v;				/* { dg-warning "conversion from '_BitInt\\\(42\\\)' to 'unsigned _BitInt\\\(17\\\)' may change value" } */
+  _BitInt(17) y = v;					/* { dg-warning "conversion from '_BitInt\\\(42\\\)' to '_BitInt\\\(17\\\)' may change value" } */
+}
--- gcc/testsuite/gcc.dg/bitint-36.c.jj	2023-09-06 13:43:35.891209025 +0200
+++ gcc/testsuite/gcc.dg/bitint-36.c	2023-09-06 14:29:17.805476679 +0200
@@ -0,0 +1,39 @@
+/* PR c/102989 */
+/* { dg-do compile { target { bitint } } } */
+/* { dg-options "-std=c2x -Wint-in-bool-context -Waddress -Wpointer-to-int-cast -Wint-to-pointer-cast -Wint-conversion -Wshift-negative-value -Wshift-count-overflow -Wdiv-by-zero" } */
+
+extern char *ax[];
+
+void bar (int);
+
+void
+foo (_BitInt(61) x, long long *y)
+{
+  if (x << 15)						/* { dg-warning "'<<' in boolean context, did you mean '<'" } */
+    ;
+  bar ((_BitInt(sizeof (void *) * __CHAR_BIT__)) (ax + 0) == 0);
+  bar ((unsigned _BitInt(sizeof (void *) * __CHAR_BIT__)) (ax + 1) == 0);
+  char *z = __builtin_assume_aligned (y, 32wb, 8wb);
+  *z = 42;
+  _BitInt(sizeof (void *) * __CHAR_BIT__ + 1) a = (_BitInt(sizeof (void *) * __CHAR_BIT__ + 1)) y;			/* { dg-warning "cast from pointer to integer of different size" } */
+  unsigned _BitInt(sizeof (void *) * __CHAR_BIT__ + 1) b = (unsigned _BitInt(sizeof (void *) * __CHAR_BIT__ + 1)) y;	/* { dg-warning "cast from pointer to integer of different size" } */
+  _BitInt(sizeof (void *) * __CHAR_BIT__ - 1) c = (_BitInt(sizeof (void *) * __CHAR_BIT__ - 1)) y;			/* { dg-warning "cast from pointer to integer of different size" } */
+  unsigned _BitInt(sizeof (void *) * __CHAR_BIT__ - 1) d = (unsigned _BitInt(sizeof (void *) * __CHAR_BIT__ - 1)) y;	/* { dg-warning "cast from pointer to integer of different size" } */
+  void *e = (void *) a;					/* { dg-warning "cast to pointer from integer of different size" } */
+  void *f = (void *) b;					/* { dg-warning "cast to pointer from integer of different size" } */
+  void *g = (void *) c;					/* { dg-warning "cast to pointer from integer of different size" } */
+  void *h = (void *) d;					/* { dg-warning "cast to pointer from integer of different size" } */
+  a = y;						/* { dg-warning "assignment to '_BitInt\\\(\[0-9]+\\\)' from 'long long int \\\*' makes integer from pointer without a cast" } */
+  b = y;						/* { dg-warning "assignment to 'unsigned _BitInt\\\(\[0-9]+\\\)' from 'long long int \\\*' makes integer from pointer without a cast" } */
+  c = y;						/* { dg-warning "assignment to '_BitInt\\\(\[0-9]+\\\)' from 'long long int \\\*' makes integer from pointer without a cast" } */
+  d = y;						/* { dg-warning "assignment to 'unsigned _BitInt\\\(\[0-9]+\\\)' from 'long long int \\\*' makes integer from pointer without a cast" } */
+  e = a;						/* { dg-warning "assignment to 'void \\\*' from '_BitInt\\\(\[0-9]+\\\)' makes pointer from integer without a cast" } */
+  f = b;						/* { dg-warning "assignment to 'void \\\*' from 'unsigned _BitInt\\\(\[0-9]+\\\)' makes pointer from integer without a cast" } */
+  g = c;						/* { dg-warning "assignment to 'void \\\*' from '_BitInt\\\(\[0-9]+\\\)' makes pointer from integer without a cast" } */
+  h = d;						/* { dg-warning "assignment to 'void \\\*' from 'unsigned _BitInt\\\(\[0-9]+\\\)' makes pointer from integer without a cast" } */
+  _BitInt(61) i = (1wb - 1152921504606846975wb) << 1;	/* { dg-warning "left shift of negative value" } */
+							/* { dg-warning "result of '-1152921504606846974 << 1' requires 62 bits to represent, but '_BitInt\\\(61\\\)' only has 61 bits" "" { target *-*-* } .-1 } */
+  _BitInt(61) j = i << (60 + 1);			/* { dg-warning "left shift count >= width of type" } */
+  _BitInt(61) k = i >> (60 + 1);			/* { dg-warning "right shift count >= width of type" } */
+  _BitInt(61) l = i / (51wb - 51wb);			/* { dg-warning "division by zero" } */
+}
--- gcc/testsuite/gcc.dg/fixed-point/bitint-1.c.jj	2023-09-06 12:32:12.152030135 +0200
+++ gcc/testsuite/gcc.dg/fixed-point/bitint-1.c	2023-09-06 12:32:30.457778458 +0200
@@ -0,0 +1,10 @@
+/* PR c/102989 */
+/* { dg-do compile { target bitint } } */
+/* { dg-options "-std=c2x" } */
+
+void
+foo (void)
+{
+  _Sat _BitInt (42) a;		/* { dg-error "both '_Sat' and '_BitInt' in declaration specifiers" } */
+  _BitInt (42) _Sat b;		/* { dg-error "both '_Sat' and '_BitInt' in declaration specifiers" } */
+}


	Jakub


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-09-06 16:09 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-09 18:25 [PATCH 10/12] C _BitInt support [PR102989] Jakub Jelinek
2023-09-05 22:40 ` Joseph Myers
2023-09-06 16:07   ` [committed 10/12 v2] " Jakub Jelinek
2023-09-06 16:09   ` [committed 19/12] Additional _BitInt test coverage [PR102989] Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).