public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 4/12] Middle-end _BitInt support [PR102989]
@ 2023-08-09 18:17 Jakub Jelinek
  2023-08-22  8:41 ` Richard Biener
  2023-09-07  8:36 ` Thomas Schwinge
  0 siblings, 2 replies; 4+ messages in thread
From: Jakub Jelinek @ 2023-08-09 18:17 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

Hi!

The following patch introduces the middle-end part of the _BitInt
support, a new BITINT_TYPE, handling it where needed, except the lowering
pass and sanitizer support.

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

	PR c/102989
	* tree.def (BITINT_TYPE): New type.
	* tree.h (TREE_CHECK6, TREE_NOT_CHECK6): Define.
	(NUMERICAL_TYPE_CHECK, INTEGRAL_TYPE_P): Include
	BITINT_TYPE.
	(BITINT_TYPE_P): Define.
	(CONSTRUCTOR_BITFIELD_P): Return true even for BLKmode bit-fields if
	they have BITINT_TYPE type.
	(tree_check6, tree_not_check6): New inline functions.
	(any_integral_type_check): Include BITINT_TYPE.
	(build_bitint_type): Declare.
	* tree.cc (tree_code_size, wide_int_to_tree_1, cache_integer_cst,
	build_zero_cst, type_hash_canon_hash, type_cache_hasher::equal,
	type_hash_canon): Handle BITINT_TYPE.
	(bitint_type_cache): New variable.
	(build_bitint_type): New function.
	(signed_or_unsigned_type_for, verify_type_variant, verify_type):
	Handle BITINT_TYPE.
	(tree_cc_finalize): Free bitint_type_cache.
	* builtins.cc (type_to_class): Handle BITINT_TYPE.
	(fold_builtin_unordered_cmp): Handle BITINT_TYPE like INTEGER_TYPE.
	* cfgexpand.cc (expand_debug_expr): Punt on BLKmode BITINT_TYPE
	INTEGER_CSTs.
	* convert.cc (convert_to_pointer_1, convert_to_real_1,
	convert_to_complex_1): Handle BITINT_TYPE like INTEGER_TYPE.
	(convert_to_integer_1): Likewise.  For BITINT_TYPE don't check
	GET_MODE_PRECISION (TYPE_MODE (type)).
	* doc/generic.texi (BITINT_TYPE): Document.
	* doc/tm.texi.in (TARGET_C_BITINT_TYPE_INFO): New.
	* doc/tm.texi: Regenerated.
	* dwarf2out.cc (base_type_die, is_base_type, modified_type_die,
	gen_type_die_with_usage): Handle BITINT_TYPE.
	(rtl_for_decl_init): Punt on BLKmode BITINT_TYPE INTEGER_CSTs or
	handle those which fit into shwi.
	* expr.cc (expand_expr_real_1): Define EXTEND_BITINT macro, reduce
	to bitfield precision reads from BITINT_TYPE vars, parameters or
	memory locations.  Expand large/huge BITINT_TYPE INTEGER_CSTs into
	memory.
	* fold-const.cc (fold_convert_loc, make_range_step): Handle
	BITINT_TYPE.
	(extract_muldiv_1): For BITINT_TYPE use TYPE_PRECISION rather than
	GET_MODE_SIZE (SCALAR_INT_TYPE_MODE).
	(native_encode_int, native_interpret_int, native_interpret_expr):
	Handle BITINT_TYPE.
	* gimple-expr.cc (useless_type_conversion_p): Make BITINT_TYPE
	to some other integral type or vice versa conversions non-useless.
	* gimple-fold.cc (gimple_fold_builtin_memset): Punt for BITINT_TYPE.
	(clear_padding_unit): Mention in comment that _BitInt types don't need
	to fit either.
	(clear_padding_bitint_needs_padding_p): New function.
	(clear_padding_type_may_have_padding_p): Handle BITINT_TYPE.
	(clear_padding_type): Likewise.
	* internal-fn.cc (expand_mul_overflow): For unsigned non-mode
	precision operands force pos_neg? to 1.
	(expand_MULBITINT, expand_DIVMODBITINT, expand_FLOATTOBITINT,
	expand_BITINTTOFLOAT): New functions.
	* internal-fn.def (MULBITINT, DIVMODBITINT, FLOATTOBITINT,
	BITINTTOFLOAT): New internal functions.
	* internal-fn.h (expand_MULBITINT, expand_DIVMODBITINT,
	expand_FLOATTOBITINT, expand_BITINTTOFLOAT): Declare.
	* match.pd (non-equality compare simplifications from fold_binary):
	Punt if TYPE_MODE (arg1_type) is BLKmode.
	* pretty-print.h (pp_wide_int): Handle printing of large precision
	wide_ints which would buffer overflow digit_buffer.
	* stor-layout.cc (finish_bitfield_representative): For bit-fields
	with BITINT_TYPE, prefer representatives with precisions in
	multiple of limb precision.
	(layout_type): Handle BITINT_TYPE.  Handle COMPLEX_TYPE with BLKmode
	element type and assert it is BITINT_TYPE.
	* target.def (bitint_type_info): New C target hook.
	* target.h (struct bitint_info): New type.
	* targhooks.cc (default_bitint_type_info): New function.
	* targhooks.h (default_bitint_type_info): Declare.
	* tree-pretty-print.cc (dump_generic_node): Handle BITINT_TYPE.
	Handle printing large wide_ints which would buffer overflow
	digit_buffer.
	* tree-ssa-sccvn.cc: Include target.h.
	(eliminate_dom_walker::eliminate_stmt): Punt for large/huge
	BITINT_TYPE.
	* tree-switch-conversion.cc (jump_table_cluster::emit): For more than
	64-bit BITINT_TYPE subtract low bound from expression and cast to
	64-bit integer type both the controlling expression and case labels.
	* typeclass.h (enum type_class): Add bitint_type_class enumerator.
	* varasm.cc (output_constant): Handle BITINT_TYPE INTEGER_CSTs.
	* vr-values.cc (check_for_binary_op_overflow): Use widest2_int rather
	than widest_int.
	(simplify_using_ranges::simplify_internal_call_using_ranges): Use
	unsigned_type_for rather than build_nonstandard_integer_type.

--- gcc/tree.def.jj	2023-08-08 15:54:35.387600243 +0200
+++ gcc/tree.def	2023-08-08 16:57:23.708840829 +0200
@@ -113,7 +113,7 @@ DEFTREECODE (BLOCK, "block", tcc_excepti
 /* The ordering of the following codes is optimized for the checking
    macros in tree.h.  Changing the order will degrade the speed of the
    compiler.  OFFSET_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, INTEGER_TYPE,
-   REAL_TYPE, POINTER_TYPE.  */
+   BITINT_TYPE, REAL_TYPE, POINTER_TYPE.  */
 
 /* An offset is a pointer relative to an object.
    The TREE_TYPE field is the type of the object at the offset.
@@ -144,6 +144,13 @@ DEFTREECODE (BOOLEAN_TYPE, "boolean_type
    and TYPE_PRECISION (number of bits used by this type).  */
 DEFTREECODE (INTEGER_TYPE, "integer_type", tcc_type, 0)
 
+/* Bit-precise integer type.  These are similar to INTEGER_TYPEs, but
+   can have arbitrary user selected precisions and do or can have different
+   alignment, function argument and return value passing conventions.
+   Larger BITINT_TYPEs can have BLKmode TYPE_MODE and need to be lowered
+   by a special BITINT_TYPE lowering pass.  */
+DEFTREECODE (BITINT_TYPE, "bitint_type", tcc_type, 0)
+
 /* C's float and double.  Different floating types are distinguished
    by machine mode and by the TYPE_SIZE and the TYPE_PRECISION.  */
 DEFTREECODE (REAL_TYPE, "real_type", tcc_type, 0)
--- gcc/tree.h.jj	2023-08-08 15:55:09.601121115 +0200
+++ gcc/tree.h	2023-08-08 16:15:41.003877836 +0200
@@ -363,6 +363,14 @@ code_helper::is_builtin_fn () const
 (tree_not_check5 ((T), __FILE__, __LINE__, __FUNCTION__, \
                                (CODE1), (CODE2), (CODE3), (CODE4), (CODE5)))
 
+#define TREE_CHECK6(T, CODE1, CODE2, CODE3, CODE4, CODE5, CODE6) \
+(tree_check6 ((T), __FILE__, __LINE__, __FUNCTION__, \
+			(CODE1), (CODE2), (CODE3), (CODE4), (CODE5), (CODE6)))
+
+#define TREE_NOT_CHECK6(T, CODE1, CODE2, CODE3, CODE4, CODE5, CODE6) \
+(tree_not_check6 ((T), __FILE__, __LINE__, __FUNCTION__, \
+			(CODE1), (CODE2), (CODE3), (CODE4), (CODE5), (CODE6)))
+
 #define CONTAINS_STRUCT_CHECK(T, STRUCT) \
 (contains_struct_check ((T), (STRUCT), __FILE__, __LINE__, __FUNCTION__))
 
@@ -485,6 +493,8 @@ extern void omp_clause_range_check_faile
 #define TREE_NOT_CHECK4(T, CODE1, CODE2, CODE3, CODE4) (T)
 #define TREE_CHECK5(T, CODE1, CODE2, CODE3, CODE4, CODE5) (T)
 #define TREE_NOT_CHECK5(T, CODE1, CODE2, CODE3, CODE4, CODE5) (T)
+#define TREE_CHECK6(T, CODE1, CODE2, CODE3, CODE4, CODE5, CODE6) (T)
+#define TREE_NOT_CHECK6(T, CODE1, CODE2, CODE3, CODE4, CODE5, CODE6) (T)
 #define TREE_CLASS_CHECK(T, CODE)		(T)
 #define TREE_RANGE_CHECK(T, CODE1, CODE2)	(T)
 #define EXPR_CHECK(T)				(T)
@@ -528,8 +538,8 @@ extern void omp_clause_range_check_faile
   TREE_CHECK2 (T, ARRAY_TYPE, INTEGER_TYPE)
 
 #define NUMERICAL_TYPE_CHECK(T)					\
-  TREE_CHECK5 (T, INTEGER_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, REAL_TYPE,	\
-	       FIXED_POINT_TYPE)
+  TREE_CHECK6 (T, INTEGER_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, REAL_TYPE,	\
+	       FIXED_POINT_TYPE, BITINT_TYPE)
 
 /* Here is how primitive or already-canonicalized types' hash codes
    are made.  */
@@ -603,7 +613,8 @@ extern void omp_clause_range_check_faile
 #define INTEGRAL_TYPE_P(TYPE)  \
   (TREE_CODE (TYPE) == ENUMERAL_TYPE  \
    || TREE_CODE (TYPE) == BOOLEAN_TYPE \
-   || TREE_CODE (TYPE) == INTEGER_TYPE)
+   || TREE_CODE (TYPE) == INTEGER_TYPE \
+   || TREE_CODE (TYPE) == BITINT_TYPE)
 
 /* Nonzero if TYPE represents an integral type, including complex
    and vector integer types.  */
@@ -614,6 +625,10 @@ extern void omp_clause_range_check_faile
         || VECTOR_TYPE_P (TYPE))		\
        && INTEGRAL_TYPE_P (TREE_TYPE (TYPE))))
 
+/* Nonzero if TYPE is bit-precise integer type.  */
+
+#define BITINT_TYPE_P(TYPE) (TREE_CODE (TYPE) == BITINT_TYPE)
+
 /* Nonzero if TYPE represents a non-saturating fixed-point type.  */
 
 #define NON_SAT_FIXED_POINT_TYPE_P(TYPE) \
@@ -1244,7 +1259,9 @@ extern void omp_clause_range_check_faile
 /* True if NODE, a FIELD_DECL, is to be processed as a bitfield for
    constructor output purposes.  */
 #define CONSTRUCTOR_BITFIELD_P(NODE) \
-  (DECL_BIT_FIELD (FIELD_DECL_CHECK (NODE)) && DECL_MODE (NODE) != BLKmode)
+  (DECL_BIT_FIELD (FIELD_DECL_CHECK (NODE)) \
+   && (DECL_MODE (NODE) != BLKmode \
+       || TREE_CODE (TREE_TYPE (NODE)) == BITINT_TYPE))
 
 /* True if NODE is a clobber right hand side, an expression of indeterminate
    value that clobbers the LHS in a copy instruction.  We use a volatile
@@ -3684,6 +3701,38 @@ tree_not_check5 (tree __t, const char *_
 }
 
 inline tree
+tree_check6 (tree __t, const char *__f, int __l, const char *__g,
+	     enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
+	     enum tree_code __c4, enum tree_code __c5, enum tree_code __c6)
+{
+  if (TREE_CODE (__t) != __c1
+      && TREE_CODE (__t) != __c2
+      && TREE_CODE (__t) != __c3
+      && TREE_CODE (__t) != __c4
+      && TREE_CODE (__t) != __c5
+      && TREE_CODE (__t) != __c6)
+    tree_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, __c5, __c6,
+		       0);
+  return __t;
+}
+
+inline tree
+tree_not_check6 (tree __t, const char *__f, int __l, const char *__g,
+		 enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
+		 enum tree_code __c4, enum tree_code __c5, enum tree_code __c6)
+{
+  if (TREE_CODE (__t) == __c1
+      || TREE_CODE (__t) == __c2
+      || TREE_CODE (__t) == __c3
+      || TREE_CODE (__t) == __c4
+      || TREE_CODE (__t) == __c5
+      || TREE_CODE (__t) == __c6)
+    tree_not_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, __c5,
+			   __c6, 0);
+  return __t;
+}
+
+inline tree
 contains_struct_check (tree __t, const enum tree_node_structure_enum __s,
                        const char *__f, int __l, const char *__g)
 {
@@ -3821,7 +3870,7 @@ any_integral_type_check (tree __t, const
 {
   if (!ANY_INTEGRAL_TYPE_P (__t))
     tree_check_failed (__t, __f, __l, __g, BOOLEAN_TYPE, ENUMERAL_TYPE,
-		       INTEGER_TYPE, 0);
+		       INTEGER_TYPE, BITINT_TYPE, 0);
   return __t;
 }
 
@@ -3940,6 +3989,38 @@ tree_not_check5 (const_tree __t, const c
 }
 
 inline const_tree
+tree_check6 (const_tree __t, const char *__f, int __l, const char *__g,
+	     enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
+	     enum tree_code __c4, enum tree_code __c5, enum tree_code __c6)
+{
+  if (TREE_CODE (__t) != __c1
+      && TREE_CODE (__t) != __c2
+      && TREE_CODE (__t) != __c3
+      && TREE_CODE (__t) != __c4
+      && TREE_CODE (__t) != __c5
+      && TREE_CODE (__t) != __c6)
+    tree_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, __c5, __c6,
+		       0);
+  return __t;
+}
+
+inline const_tree
+tree_not_check6 (const_tree __t, const char *__f, int __l, const char *__g,
+		 enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
+		 enum tree_code __c4, enum tree_code __c5, enum tree_code __c6)
+{
+  if (TREE_CODE (__t) == __c1
+      || TREE_CODE (__t) == __c2
+      || TREE_CODE (__t) == __c3
+      || TREE_CODE (__t) == __c4
+      || TREE_CODE (__t) == __c5
+      || TREE_CODE (__t) == __c6)
+    tree_not_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, __c5,
+			   __c6, 0);
+  return __t;
+}
+
+inline const_tree
 contains_struct_check (const_tree __t, const enum tree_node_structure_enum __s,
                        const char *__f, int __l, const char *__g)
 {
@@ -4047,7 +4128,7 @@ any_integral_type_check (const_tree __t,
 {
   if (!ANY_INTEGRAL_TYPE_P (__t))
     tree_check_failed (__t, __f, __l, __g, BOOLEAN_TYPE, ENUMERAL_TYPE,
-		       INTEGER_TYPE, 0);
+		       INTEGER_TYPE, BITINT_TYPE, 0);
   return __t;
 }
 
@@ -5579,6 +5660,7 @@ extern void build_common_builtin_nodes (
 extern void tree_cc_finalize (void);
 extern tree build_nonstandard_integer_type (unsigned HOST_WIDE_INT, int);
 extern tree build_nonstandard_boolean_type (unsigned HOST_WIDE_INT);
+extern tree build_bitint_type (unsigned HOST_WIDE_INT, int);
 extern tree build_range_type (tree, tree, tree);
 extern tree build_nonshared_range_type (tree, tree, tree);
 extern bool subrange_type_for_debug_p (const_tree, tree *, tree *);
--- gcc/tree.cc.jj	2023-08-08 15:54:35.331601028 +0200
+++ gcc/tree.cc	2023-08-08 16:12:02.302940175 +0200
@@ -991,6 +991,7 @@ tree_code_size (enum tree_code code)
 	case VOID_TYPE:
 	case FUNCTION_TYPE:
 	case METHOD_TYPE:
+	case BITINT_TYPE:
 	case LANG_TYPE:		return sizeof (tree_type_non_common);
 	default:
 	  gcc_checking_assert (code >= NUM_TREE_CODES);
@@ -1732,6 +1733,7 @@ wide_int_to_tree_1 (tree type, const wid
 
 	case INTEGER_TYPE:
 	case OFFSET_TYPE:
+	case BITINT_TYPE:
 	  if (TYPE_SIGN (type) == UNSIGNED)
 	    {
 	      /* Cache [0, N).  */
@@ -1915,6 +1917,7 @@ cache_integer_cst (tree t, bool might_du
 
     case INTEGER_TYPE:
     case OFFSET_TYPE:
+    case BITINT_TYPE:
       if (TYPE_UNSIGNED (type))
 	{
 	  /* Cache 0..N */
@@ -2637,7 +2640,7 @@ build_zero_cst (tree type)
     {
     case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
     case POINTER_TYPE: case REFERENCE_TYPE:
-    case OFFSET_TYPE: case NULLPTR_TYPE:
+    case OFFSET_TYPE: case NULLPTR_TYPE: case BITINT_TYPE:
       return build_int_cst (type, 0);
 
     case REAL_TYPE:
@@ -6053,7 +6056,16 @@ type_hash_canon_hash (tree type)
 	  hstate.add_object (TREE_INT_CST_ELT (t, i));
 	break;
       }
-      
+
+    case BITINT_TYPE:
+      {
+	unsigned prec = TYPE_PRECISION (type);
+	unsigned uns = TYPE_UNSIGNED (type);
+	hstate.add_object (prec);
+	hstate.add_int (uns);
+	break;
+      }
+
     case REAL_TYPE:
     case FIXED_POINT_TYPE:
       {
@@ -6136,6 +6148,11 @@ type_cache_hasher::equal (type_hash *a,
 		  || tree_int_cst_equal (TYPE_MIN_VALUE (a->type),
 					 TYPE_MIN_VALUE (b->type))));
 
+    case BITINT_TYPE:
+      if (TYPE_PRECISION (a->type) != TYPE_PRECISION (b->type))
+	return false;
+      return TYPE_UNSIGNED (a->type) == TYPE_UNSIGNED (b->type);
+
     case FIXED_POINT_TYPE:
       return TYPE_SATURATING (a->type) == TYPE_SATURATING (b->type);
 
@@ -6236,7 +6253,7 @@ type_hash_canon (unsigned int hashcode,
       /* Free also min/max values and the cache for integer
 	 types.  This can't be done in free_node, as LTO frees
 	 those on its own.  */
-      if (TREE_CODE (type) == INTEGER_TYPE)
+      if (TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == BITINT_TYPE)
 	{
 	  if (TYPE_MIN_VALUE (type)
 	      && TREE_TYPE (TYPE_MIN_VALUE (type)) == type)
@@ -7154,6 +7171,44 @@ build_nonstandard_boolean_type (unsigned
   return type;
 }
 
+static GTY(()) vec<tree, va_gc> *bitint_type_cache;
+
+/* Builds a signed or unsigned _BitInt(PRECISION) type.  */
+tree
+build_bitint_type (unsigned HOST_WIDE_INT precision, int unsignedp)
+{
+  tree itype, ret;
+
+  if (unsignedp)
+    unsignedp = MAX_INT_CACHED_PREC + 1;
+
+  if (bitint_type_cache == NULL)
+    vec_safe_grow_cleared (bitint_type_cache, 2 * MAX_INT_CACHED_PREC + 2);
+
+  if (precision <= MAX_INT_CACHED_PREC)
+    {
+      itype = (*bitint_type_cache)[precision + unsignedp];
+      if (itype)
+	return itype;
+    }
+
+  itype = make_node (BITINT_TYPE);
+  TYPE_PRECISION (itype) = precision;
+
+  if (unsignedp)
+    fixup_unsigned_type (itype);
+  else
+    fixup_signed_type (itype);
+
+  inchash::hash hstate;
+  inchash::add_expr (TYPE_MAX_VALUE (itype), hstate);
+  ret = type_hash_canon (hstate.end (), itype);
+  if (precision <= MAX_INT_CACHED_PREC)
+    (*bitint_type_cache)[precision + unsignedp] = ret;
+
+  return ret;
+}
+
 /* Create a range of some discrete type TYPE (an INTEGER_TYPE, ENUMERAL_TYPE
    or BOOLEAN_TYPE) with low bound LOWVAL and high bound HIGHVAL.  If SHARED
    is true, reuse such a type that has already been constructed.  */
@@ -11041,6 +11096,8 @@ signed_or_unsigned_type_for (int unsigne
   else
     return NULL_TREE;
 
+  if (TREE_CODE (type) == BITINT_TYPE)
+    return build_bitint_type (bits, unsignedp);
   return build_nonstandard_integer_type (bits, unsignedp);
 }
 
@@ -13462,6 +13519,7 @@ verify_type_variant (const_tree t, tree
   if ((TREE_CODE (t) == ENUMERAL_TYPE && COMPLETE_TYPE_P (t))
        || TREE_CODE (t) == INTEGER_TYPE
        || TREE_CODE (t) == BOOLEAN_TYPE
+       || TREE_CODE (t) == BITINT_TYPE
        || SCALAR_FLOAT_TYPE_P (t)
        || FIXED_POINT_TYPE_P (t))
     {
@@ -14201,6 +14259,7 @@ verify_type (const_tree t)
     }
   else if (TREE_CODE (t) == INTEGER_TYPE
 	   || TREE_CODE (t) == BOOLEAN_TYPE
+	   || TREE_CODE (t) == BITINT_TYPE
 	   || TREE_CODE (t) == OFFSET_TYPE
 	   || TREE_CODE (t) == REFERENCE_TYPE
 	   || TREE_CODE (t) == NULLPTR_TYPE
@@ -14260,6 +14319,7 @@ verify_type (const_tree t)
     }
   if (TREE_CODE (t) != INTEGER_TYPE
       && TREE_CODE (t) != BOOLEAN_TYPE
+      && TREE_CODE (t) != BITINT_TYPE
       && TREE_CODE (t) != OFFSET_TYPE
       && TREE_CODE (t) != REFERENCE_TYPE
       && TREE_CODE (t) != NULLPTR_TYPE
@@ -15035,6 +15095,7 @@ void
 tree_cc_finalize (void)
 {
   clear_nonstandard_integer_type_cache ();
+  vec_free (bitint_type_cache);
 }
 
 #if CHECKING_P
--- gcc/builtins.cc.jj	2023-08-08 15:55:05.230182325 +0200
+++ gcc/builtins.cc	2023-08-08 16:12:02.303940161 +0200
@@ -1876,6 +1876,7 @@ type_to_class (tree type)
 				   ? string_type_class : array_type_class);
     case LANG_TYPE:	   return lang_type_class;
     case OPAQUE_TYPE:      return opaque_type_class;
+    case BITINT_TYPE:	   return bitint_type_class;
     default:		   return no_type_class;
     }
 }
@@ -9423,9 +9424,11 @@ fold_builtin_unordered_cmp (location_t l
     /* Choose the wider of two real types.  */
     cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1)
       ? type0 : type1;
-  else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
+  else if (code0 == REAL_TYPE
+	   && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
     cmp_type = type0;
-  else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
+  else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
+	   && code1 == REAL_TYPE)
     cmp_type = type1;
 
   arg0 = fold_convert_loc (loc, cmp_type, arg0);
--- gcc/cfgexpand.cc.jj	2023-08-08 15:54:33.893621164 +0200
+++ gcc/cfgexpand.cc	2023-08-08 17:19:26.025312540 +0200
@@ -4524,6 +4524,10 @@ expand_debug_expr (tree exp)
       /* Fall through.  */
 
     case INTEGER_CST:
+      if (TREE_CODE (TREE_TYPE (exp)) == BITINT_TYPE
+	  && TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+	return NULL;
+      /* FALLTHRU */
     case REAL_CST:
     case FIXED_CST:
       op0 = expand_expr (exp, NULL_RTX, mode, EXPAND_INITIALIZER);
--- gcc/convert.cc.jj	2023-08-08 15:54:33.998619694 +0200
+++ gcc/convert.cc	2023-08-08 16:12:02.308940091 +0200
@@ -77,6 +77,7 @@ convert_to_pointer_1 (tree type, tree ex
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
+    case BITINT_TYPE:
       {
 	/* If the input precision differs from the target pointer type
 	   precision, first convert the input expression to an integer type of
@@ -316,6 +317,7 @@ convert_to_real_1 (tree type, tree expr,
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
+    case BITINT_TYPE:
       return build1 (FLOAT_EXPR, type, expr);
 
     case FIXED_POINT_TYPE:
@@ -660,6 +662,7 @@ convert_to_integer_1 (tree type, tree ex
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
     case OFFSET_TYPE:
+    case BITINT_TYPE:
       /* If this is a logical operation, which just returns 0 or 1, we can
 	 change the type of the expression.  */
 
@@ -701,7 +704,9 @@ convert_to_integer_1 (tree type, tree ex
 	 type corresponding to its mode, then do a nop conversion
 	 to TYPE.  */
       else if (TREE_CODE (type) == ENUMERAL_TYPE
-	       || maybe_ne (outprec, GET_MODE_PRECISION (TYPE_MODE (type))))
+	       || (TREE_CODE (type) != BITINT_TYPE
+		   && maybe_ne (outprec,
+				GET_MODE_PRECISION (TYPE_MODE (type)))))
 	{
 	  expr
 	    = convert_to_integer_1 (lang_hooks.types.type_for_mode
@@ -1000,6 +1005,7 @@ convert_to_complex_1 (tree type, tree ex
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
+    case BITINT_TYPE:
       return build2 (COMPLEX_EXPR, type, convert (subtype, expr),
 		     convert (subtype, integer_zero_node));
 
--- gcc/doc/generic.texi.jj	2023-06-07 09:42:14.593131807 +0200
+++ gcc/doc/generic.texi	2023-08-08 17:04:48.062612388 +0200
@@ -290,6 +290,7 @@ The elements are indexed from zero.
 @tindex INTEGER_TYPE
 @tindex TYPE_MIN_VALUE
 @tindex TYPE_MAX_VALUE
+@tindex BITINT_TYPE
 @tindex REAL_TYPE
 @tindex FIXED_POINT_TYPE
 @tindex COMPLEX_TYPE
@@ -449,6 +450,14 @@ integer that may be represented by this
 @code{TYPE_MAX_VALUE} is an @code{INTEGER_CST} for the largest integer
 that may be represented by this type.
 
+@item BITINT_TYPE
+Used to represent the bit-precise integer types, @code{_BitInt(@var{N})}.
+These types are similar to @code{INTEGER_TYPE}, but can have arbitrary
+user selected precisions and do or can have different alignment, function
+argument and return value passing conventions.
+Larger BITINT_TYPEs can have @code{BLKmode} @code{TYPE_MODE} and need to
+be lowered by a special BITINT_TYPE lowering pass.
+
 @item REAL_TYPE
 Used to represent the @code{float}, @code{double}, and @code{long
 double} types.  The number of bits in the floating-point representation
--- gcc/doc/tm.texi.in.jj	2023-08-08 15:54:34.156617482 +0200
+++ gcc/doc/tm.texi.in	2023-08-08 16:12:02.309940077 +0200
@@ -936,6 +936,8 @@ Return a value, with the same meaning as
 @code{FLT_EVAL_METHOD} that describes which excess precision should be
 applied.
 
+@hook TARGET_C_BITINT_TYPE_INFO
+
 @hook TARGET_PROMOTE_FUNCTION_MODE
 
 @defmac PARM_BOUNDARY
--- gcc/doc/tm.texi.jj	2023-08-08 15:54:34.090618406 +0200
+++ gcc/doc/tm.texi	2023-08-08 19:24:12.438581403 +0200
@@ -1020,6 +1020,21 @@ Return a value, with the same meaning as
 @code{FLT_EVAL_METHOD} that describes which excess precision should be
 applied.
 
+@deftypefn {Target Hook} bool TARGET_C_BITINT_TYPE_INFO (int @var{n}, struct bitint_info *@var{info})
+This target hook returns true if @code{_BitInt(@var{N})} is supported and
+provides details on it.  @code{_BitInt(@var{N})} is to be represented as
+series of @code{info->limb_mode}
+@code{CEIL (@var{N}, GET_MODE_PRECISION (info->limb_mode))} limbs,
+ordered from least significant to most significant if
+@code{!info->big_endian}, otherwise from most significant to least
+significant.  If @code{info->extended} is false, the bits above or equal to
+@var{N} are undefined when stored in a register or memory, otherwise they
+are zero or sign extended depending on if it is
+@code{unsigned _BitInt(@var{N})} or one of @code{_BitInt(@var{N})} or
+@code{signed _BitInt(@var{N})}.  Alignment of the type is
+@code{GET_MODE_ALIGNMENT (info->limb_mode)}.
+@end deftypefn
+
 @deftypefn {Target Hook} machine_mode TARGET_PROMOTE_FUNCTION_MODE (const_tree @var{type}, machine_mode @var{mode}, int *@var{punsignedp}, const_tree @var{funtype}, int @var{for_return})
 Like @code{PROMOTE_MODE}, but it is applied to outgoing function arguments or
 function return values.  The target hook should return the new mode
--- gcc/dwarf2out.cc.jj	2023-08-08 15:55:06.471164947 +0200
+++ gcc/dwarf2out.cc	2023-08-08 19:06:17.624644391 +0200
@@ -13298,6 +13298,14 @@ base_type_die (tree type, bool reverse)
       encoding = DW_ATE_boolean;
       break;
 
+    case BITINT_TYPE:
+      /* C23 _BitInt(N).  */
+      if (TYPE_UNSIGNED (type))
+	encoding = DW_ATE_unsigned;
+      else
+	encoding = DW_ATE_signed;
+      break;
+
     default:
       /* No other TREE_CODEs are Dwarf fundamental types.  */
       gcc_unreachable ();
@@ -13308,6 +13316,8 @@ base_type_die (tree type, bool reverse)
   add_AT_unsigned (base_type_result, DW_AT_byte_size,
 		   int_size_in_bytes (type));
   add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
+  if (TREE_CODE (type) == BITINT_TYPE)
+    add_AT_unsigned (base_type_result, DW_AT_bit_size, TYPE_PRECISION (type));
 
   if (need_endianity_attribute_p (reverse))
     add_AT_unsigned (base_type_result, DW_AT_endianity,
@@ -13392,6 +13402,7 @@ is_base_type (tree type)
     case FIXED_POINT_TYPE:
     case COMPLEX_TYPE:
     case BOOLEAN_TYPE:
+    case BITINT_TYPE:
       return true;
 
     case VOID_TYPE:
@@ -13990,12 +14001,24 @@ modified_type_die (tree type, int cv_qua
 	name = DECL_NAME (name);
       add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
     }
-  /* This probably indicates a bug.  */
   else if (mod_type_die && mod_type_die->die_tag == DW_TAG_base_type)
     {
-      name = TYPE_IDENTIFIER (type);
-      add_name_attribute (mod_type_die,
-			  name ? IDENTIFIER_POINTER (name) : "__unknown__");
+      if (TREE_CODE (type) == BITINT_TYPE)
+	{
+	  char name_buf[sizeof ("unsigned _BitInt(2147483647)")];
+	  snprintf (name_buf, sizeof (name_buf),
+		    "%s_BitInt(%d)", TYPE_UNSIGNED (type) ? "unsigned " : "",
+		    TYPE_PRECISION (type));
+	  add_name_attribute (mod_type_die, name_buf);
+	}
+      else
+	{
+	  /* This probably indicates a bug.  */
+	  name = TYPE_IDENTIFIER (type);
+	  add_name_attribute (mod_type_die,
+			      name
+			      ? IDENTIFIER_POINTER (name) : "__unknown__");
+	}
     }
 
   if (qualified_type && !reverse_base_type)
@@ -20523,6 +20546,17 @@ rtl_for_decl_init (tree init, tree type)
 	    return NULL;
 	  }
 
+      /* Large _BitInt BLKmode INTEGER_CSTs would yield a MEM.  */
+      if (TREE_CODE (init) == INTEGER_CST
+	  && TREE_CODE (TREE_TYPE (init)) == BITINT_TYPE
+	  && TYPE_MODE (TREE_TYPE (init)) == BLKmode)
+	{
+	  if (tree_fits_shwi_p (init))
+	    return GEN_INT (tree_to_shwi (init));
+	  else
+	    return NULL;
+	}
+
       rtl = expand_expr (init, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
 
       /* If expand_expr returns a MEM, it wasn't immediate.  */
@@ -26361,6 +26395,7 @@ gen_type_die_with_usage (tree type, dw_d
     case FIXED_POINT_TYPE:
     case COMPLEX_TYPE:
     case BOOLEAN_TYPE:
+    case BITINT_TYPE:
       /* No DIEs needed for fundamental types.  */
       break;
 
--- gcc/expr.cc.jj	2023-08-08 16:02:52.837633995 +0200
+++ gcc/expr.cc	2023-08-09 10:30:13.524295673 +0200
@@ -10650,6 +10650,25 @@ expand_expr_real_1 (tree exp, rtx target
   tree ssa_name = NULL_TREE;
   gimple *g;
 
+  /* Some ABIs define padding bits in _BitInt uninitialized.  Normally, RTL
+     expansion sign/zero extends integral types with less than mode precision
+     when reading from bit-fields and after arithmetic operations (see
+     REDUCE_BIT_FIELD in expand_expr_real_2) and on subsequent loads relies
+     on those extensions to have been already performed, but because of the
+     above for _BitInt they need to be sign/zero extended when reading from
+     locations that could be exposed to ABI boundaries (when loading from
+     objects in memory, or function arguments, return value).  Because we
+     internally extend after arithmetic operations, we can avoid doing that
+     when reading from SSA_NAMEs of vars.  */
+#define EXTEND_BITINT(expr) \
+  ((TREE_CODE (type) == BITINT_TYPE					\
+    && reduce_bit_field							\
+    && mode != BLKmode							\
+    && modifier != EXPAND_MEMORY					\
+    && modifier != EXPAND_WRITE						\
+    && modifier != EXPAND_CONST_ADDRESS)				\
+   ? reduce_to_bit_field_precision ((expr), NULL_RTX, type) : (expr))
+
   type = TREE_TYPE (exp);
   mode = TYPE_MODE (type);
   unsignedp = TYPE_UNSIGNED (type);
@@ -10823,6 +10842,13 @@ expand_expr_real_1 (tree exp, rtx target
       ssa_name = exp;
       decl_rtl = get_rtx_for_ssa_name (ssa_name);
       exp = SSA_NAME_VAR (ssa_name);
+      /* Optimize and avoid to EXTEND_BITINIT doing anything if it is an
+	 SSA_NAME computed within the current function.  In such case the
+	 value have been already extended before.  While if it is a function
+	 parameter, result or some memory location, we need to be prepared
+	 for some other compiler leaving the bits uninitialized.  */
+      if (!exp || VAR_P (exp))
+	reduce_bit_field = false;
       goto expand_decl_rtl;
 
     case VAR_DECL:
@@ -10956,7 +10982,7 @@ expand_expr_real_1 (tree exp, rtx target
 	    temp = expand_misaligned_mem_ref (temp, mode, unsignedp,
 					      MEM_ALIGN (temp), NULL_RTX, NULL);
 
-	  return temp;
+	  return EXTEND_BITINT (temp);
 	}
 
       if (exp)
@@ -11002,13 +11028,35 @@ expand_expr_real_1 (tree exp, rtx target
 	  temp = gen_lowpart_SUBREG (mode, decl_rtl);
 	  SUBREG_PROMOTED_VAR_P (temp) = 1;
 	  SUBREG_PROMOTED_SET (temp, unsignedp);
-	  return temp;
+	  return EXTEND_BITINT (temp);
 	}
 
-      return decl_rtl;
+      return EXTEND_BITINT (decl_rtl);
 
     case INTEGER_CST:
       {
+	if (TREE_CODE (type) == BITINT_TYPE)
+	  {
+	    unsigned int prec = TYPE_PRECISION (type);
+	    struct bitint_info info;
+	    gcc_assert (targetm.c.bitint_type_info (prec, &info));
+	    scalar_int_mode limb_mode
+	      = as_a <scalar_int_mode> (info.limb_mode);
+	    unsigned int limb_prec = GET_MODE_PRECISION (limb_mode);
+	    if (prec > limb_prec)
+	      {
+		scalar_int_mode arith_mode
+		  = (targetm.scalar_mode_supported_p (TImode)
+		     ? TImode : DImode);
+		if (prec > GET_MODE_PRECISION (arith_mode))
+		  {
+		    /* Emit large/huge _BitInt INTEGER_CSTs into memory.  */
+		    exp = tree_output_constant_def (exp);
+		    return expand_expr (exp, target, VOIDmode, modifier);
+		  }
+	      }
+	  }
+
 	/* Given that TYPE_PRECISION (type) is not always equal to
 	   GET_MODE_PRECISION (TYPE_MODE (type)), we need to extend from
 	   the former to the latter according to the signedness of the
@@ -11187,7 +11235,7 @@ expand_expr_real_1 (tree exp, rtx target
 	    && align < GET_MODE_ALIGNMENT (mode))
 	  temp = expand_misaligned_mem_ref (temp, mode, unsignedp,
 					    align, NULL_RTX, NULL);
-	return temp;
+	return EXTEND_BITINT (temp);
       }
 
     case MEM_REF:
@@ -11258,7 +11306,7 @@ expand_expr_real_1 (tree exp, rtx target
 					    ? NULL_RTX : target, alt_rtl);
 	if (reverse)
 	  temp = flip_storage_order (mode, temp);
-	return temp;
+	return EXTEND_BITINT (temp);
       }
 
     case ARRAY_REF:
@@ -11810,6 +11858,8 @@ expand_expr_real_1 (tree exp, rtx target
 	    && modifier != EXPAND_WRITE)
 	  op0 = flip_storage_order (mode1, op0);
 
+	op0 = EXTEND_BITINT (op0);
+
 	if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
 	    || modifier == EXPAND_CONST_ADDRESS
 	    || modifier == EXPAND_INITIALIZER)
@@ -12155,6 +12205,7 @@ expand_expr_real_1 (tree exp, rtx target
       return expand_expr_real_2 (&ops, target, tmode, modifier);
     }
 }
+#undef EXTEND_BITINT
 \f
 /* Subroutine of above: reduce EXP to the precision of TYPE (in the
    signedness of TYPE), possibly returning the result in TARGET.
--- gcc/fold-const.cc.jj	2023-08-08 15:55:06.507164442 +0200
+++ gcc/fold-const.cc	2023-08-08 16:12:02.318939952 +0200
@@ -2557,7 +2557,7 @@ fold_convert_loc (location_t loc, tree t
       /* fall through */
 
     case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
-    case OFFSET_TYPE:
+    case OFFSET_TYPE: case BITINT_TYPE:
       if (TREE_CODE (arg) == INTEGER_CST)
 	{
 	  tem = fold_convert_const (NOP_EXPR, type, arg);
@@ -2597,7 +2597,7 @@ fold_convert_loc (location_t loc, tree t
 
       switch (TREE_CODE (orig))
 	{
-	case INTEGER_TYPE:
+	case INTEGER_TYPE: case BITINT_TYPE:
 	case BOOLEAN_TYPE: case ENUMERAL_TYPE:
 	case POINTER_TYPE: case REFERENCE_TYPE:
 	  return fold_build1_loc (loc, FLOAT_EXPR, type, arg);
@@ -2632,6 +2632,7 @@ fold_convert_loc (location_t loc, tree t
 	case ENUMERAL_TYPE:
 	case BOOLEAN_TYPE:
 	case REAL_TYPE:
+	case BITINT_TYPE:
 	  return fold_build1_loc (loc, FIXED_CONVERT_EXPR, type, arg);
 
 	case COMPLEX_TYPE:
@@ -2645,7 +2646,7 @@ fold_convert_loc (location_t loc, tree t
     case COMPLEX_TYPE:
       switch (TREE_CODE (orig))
 	{
-	case INTEGER_TYPE:
+	case INTEGER_TYPE: case BITINT_TYPE:
 	case BOOLEAN_TYPE: case ENUMERAL_TYPE:
 	case POINTER_TYPE: case REFERENCE_TYPE:
 	case REAL_TYPE:
@@ -5324,6 +5325,8 @@ make_range_step (location_t loc, enum tr
 	    equiv_type
 	      = lang_hooks.types.type_for_mode (TYPE_MODE (arg0_type),
 						TYPE_SATURATING (arg0_type));
+	  else if (TREE_CODE (arg0_type) == BITINT_TYPE)
+	    equiv_type = arg0_type;
 	  else
 	    equiv_type
 	      = lang_hooks.types.type_for_mode (TYPE_MODE (arg0_type), 1);
@@ -6850,10 +6853,19 @@ extract_muldiv_1 (tree t, tree c, enum t
 {
   tree type = TREE_TYPE (t);
   enum tree_code tcode = TREE_CODE (t);
-  tree ctype = (wide_type != 0
-		&& (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (wide_type))
-		    > GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type)))
-		? wide_type : type);
+  tree ctype = type;
+  if (wide_type)
+    {
+      if (TREE_CODE (type) == BITINT_TYPE
+	  || TREE_CODE (wide_type) == BITINT_TYPE)
+	{
+	  if (TYPE_PRECISION (wide_type) > TYPE_PRECISION (type))
+	    ctype = wide_type;
+	}
+      else if (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (wide_type))
+	       > GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type)))
+	ctype = wide_type;
+    }
   tree t1, t2;
   bool same_p = tcode == code;
   tree op0 = NULL_TREE, op1 = NULL_TREE;
@@ -7714,7 +7726,29 @@ static int
 native_encode_int (const_tree expr, unsigned char *ptr, int len, int off)
 {
   tree type = TREE_TYPE (expr);
-  int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
+  int total_bytes;
+  if (TREE_CODE (type) == BITINT_TYPE)
+    {
+      struct bitint_info info;
+      gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
+					      &info));
+      scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+      if (TYPE_PRECISION (type) > GET_MODE_PRECISION (limb_mode))
+	{
+	  total_bytes = tree_to_uhwi (TYPE_SIZE_UNIT (type));
+	  /* More work is needed when adding _BitInt support to PDP endian
+	     if limb is smaller than word, or if _BitInt limb ordering doesn't
+	     match target endianity here.  */
+	  gcc_checking_assert (info.big_endian == WORDS_BIG_ENDIAN
+			       && (BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
+				   || (GET_MODE_SIZE (limb_mode)
+				       >= UNITS_PER_WORD)));
+	}
+      else
+	total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
+    }
+  else
+    total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
   int byte, offset, word, words;
   unsigned char value;
 
@@ -8622,7 +8656,29 @@ native_encode_initializer (tree init, un
 static tree
 native_interpret_int (tree type, const unsigned char *ptr, int len)
 {
-  int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
+  int total_bytes;
+  if (TREE_CODE (type) == BITINT_TYPE)
+    {
+      struct bitint_info info;
+      gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
+					      &info));
+      scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+      if (TYPE_PRECISION (type) > GET_MODE_PRECISION (limb_mode))
+	{
+	  total_bytes = tree_to_uhwi (TYPE_SIZE_UNIT (type));
+	  /* More work is needed when adding _BitInt support to PDP endian
+	     if limb is smaller than word, or if _BitInt limb ordering doesn't
+	     match target endianity here.  */
+	  gcc_checking_assert (info.big_endian == WORDS_BIG_ENDIAN
+			       && (BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
+				   || (GET_MODE_SIZE (limb_mode)
+				       >= UNITS_PER_WORD)));
+	}
+      else
+	total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
+    }
+  else
+    total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
 
   if (total_bytes > len
       || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
@@ -8824,6 +8880,7 @@ native_interpret_expr (tree type, const
     case POINTER_TYPE:
     case REFERENCE_TYPE:
     case OFFSET_TYPE:
+    case BITINT_TYPE:
       return native_interpret_int (type, ptr, len);
 
     case REAL_TYPE:
--- gcc/gimple-expr.cc.jj	2023-08-08 15:54:34.369614499 +0200
+++ gcc/gimple-expr.cc	2023-08-08 16:12:02.318939952 +0200
@@ -111,6 +111,15 @@ useless_type_conversion_p (tree outer_ty
 	  && TYPE_PRECISION (outer_type) != 1)
 	return false;
 
+      /* Preserve conversions to/from BITINT_TYPE.  While we don't
+	 need to care that much about such conversions within a function's
+	 body, we need to prevent changing BITINT_TYPE to INTEGER_TYPE
+	 of the same precision or vice versa when passed to functions,
+	 especially for varargs.  */
+      if ((TREE_CODE (inner_type) == BITINT_TYPE)
+	  != (TREE_CODE (outer_type) == BITINT_TYPE))
+	return false;
+
       /* We don't need to preserve changes in the types minimum or
 	 maximum value in general as these do not generate code
 	 unless the types precisions are different.  */
--- gcc/gimple-fold.cc.jj	2023-08-08 15:55:06.609163014 +0200
+++ gcc/gimple-fold.cc	2023-08-08 16:18:44.828303852 +0200
@@ -1475,8 +1475,9 @@ gimple_fold_builtin_memset (gimple_stmt_
   if (TREE_CODE (etype) == ARRAY_TYPE)
     etype = TREE_TYPE (etype);
 
-  if (!INTEGRAL_TYPE_P (etype)
-      && !POINTER_TYPE_P (etype))
+  if ((!INTEGRAL_TYPE_P (etype)
+       && !POINTER_TYPE_P (etype))
+      || TREE_CODE (etype) == BITINT_TYPE)
     return NULL_TREE;
 
   if (! var_decl_component_p (var))
@@ -4102,8 +4103,8 @@ gimple_fold_builtin_realloc (gimple_stmt
   return false;
 }
 
-/* Number of bytes into which any type but aggregate or vector types
-   should fit.  */
+/* Number of bytes into which any type but aggregate, vector or
+   _BitInt types should fit.  */
 static constexpr size_t clear_padding_unit
   = MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT;
 /* Buffer size on which __builtin_clear_padding folding code works.  */
@@ -4594,6 +4595,26 @@ clear_padding_real_needs_padding_p (tree
 	  && (fmt->signbit_ro == 79 || fmt->signbit_ro == 95));
 }
 
+/* _BitInt has padding bits if it isn't extended in the ABI and has smaller
+   precision than bits in limb or corresponding number of limbs.  */
+
+static bool
+clear_padding_bitint_needs_padding_p (tree type)
+{
+  struct bitint_info info;
+  gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
+  if (info.extended)
+    return false;
+  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+  if (TYPE_PRECISION (type) < GET_MODE_PRECISION (limb_mode))
+    return true;
+  else if (TYPE_PRECISION (type) == GET_MODE_PRECISION (limb_mode))
+    return false;
+  else
+    return (((unsigned) TYPE_PRECISION (type))
+	    % GET_MODE_PRECISION (limb_mode)) != 0;
+}
+
 /* Return true if TYPE might contain any padding bits.  */
 
 bool
@@ -4610,6 +4631,8 @@ clear_padding_type_may_have_padding_p (t
       return clear_padding_type_may_have_padding_p (TREE_TYPE (type));
     case REAL_TYPE:
       return clear_padding_real_needs_padding_p (type);
+    case BITINT_TYPE:
+      return clear_padding_bitint_needs_padding_p (type);
     default:
       return false;
     }
@@ -4854,6 +4877,57 @@ clear_padding_type (clear_padding_struct
       memset (buf->buf + buf->size, ~0, sz);
       buf->size += sz;
       break;
+    case BITINT_TYPE:
+      {
+	struct bitint_info info;
+	gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
+	scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+	if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
+	  {
+	    gcc_assert ((size_t) sz <= clear_padding_unit);
+	    if ((unsigned HOST_WIDE_INT) sz + buf->size
+		> clear_padding_buf_size)
+	      clear_padding_flush (buf, false);
+	    if (!info.extended
+		&& TYPE_PRECISION (type) < GET_MODE_PRECISION (limb_mode))
+	      {
+		int tprec = GET_MODE_PRECISION (limb_mode);
+		int prec = TYPE_PRECISION (type);
+		tree t = build_nonstandard_integer_type (tprec, 1);
+		tree cst = wide_int_to_tree (t, wi::mask (prec, true, tprec));
+		int len = native_encode_expr (cst, buf->buf + buf->size, sz);
+		gcc_assert (len > 0 && (size_t) len == (size_t) sz);
+	      }
+	    else
+	      memset (buf->buf + buf->size, 0, sz);
+	    buf->size += sz;
+	    break;
+	  }
+	tree limbtype
+	  = build_nonstandard_integer_type (GET_MODE_PRECISION (limb_mode), 1);
+	fldsz = int_size_in_bytes (limbtype);
+	nelts = int_size_in_bytes (type) / fldsz;
+	for (HOST_WIDE_INT i = 0; i < nelts; i++)
+	  {
+	    if (!info.extended
+		&& i == (info.big_endian ? 0 : nelts - 1)
+		&& (((unsigned) TYPE_PRECISION (type))
+		    % TYPE_PRECISION (limbtype)) != 0)
+	      {
+		int tprec = GET_MODE_PRECISION (limb_mode);
+		int prec = (((unsigned) TYPE_PRECISION (type)) % tprec);
+		tree cst = wide_int_to_tree (limbtype,
+					     wi::mask (prec, true, tprec));
+		int len = native_encode_expr (cst, buf->buf + buf->size,
+					      fldsz);
+		gcc_assert (len > 0 && (size_t) len == (size_t) fldsz);
+		buf->size += fldsz;
+	      }
+	    else
+	      clear_padding_type (buf, limbtype, fldsz, for_auto_init);
+	  }
+	break;
+      }
     default:
       gcc_assert ((size_t) sz <= clear_padding_unit);
       if ((unsigned HOST_WIDE_INT) sz + buf->size > clear_padding_buf_size)
--- gcc/internal-fn.cc.jj	2023-08-08 15:55:06.709161614 +0200
+++ gcc/internal-fn.cc	2023-08-08 16:22:09.404440148 +0200
@@ -1646,6 +1676,12 @@ expand_mul_overflow (location_t loc, tre
 
   int pos_neg0 = get_range_pos_neg (arg0);
   int pos_neg1 = get_range_pos_neg (arg1);
+  /* Unsigned types with smaller than mode precision, even if they have most
+     significant bit set, are still zero-extended.  */
+  if (uns0_p && TYPE_PRECISION (TREE_TYPE (arg0)) < GET_MODE_PRECISION (mode))
+    pos_neg0 = 1;
+  if (uns1_p && TYPE_PRECISION (TREE_TYPE (arg1)) < GET_MODE_PRECISION (mode))
+    pos_neg1 = 1;
 
   /* s1 * u2 -> ur  */
   if (!uns0_p && uns1_p && unsr_p)
@@ -4923,3 +4959,104 @@ expand_MASK_CALL (internal_fn, gcall *)
   /* This IFN should only exist between ifcvt and vect passes.  */
   gcc_unreachable ();
 }
+
+void
+expand_MULBITINT (internal_fn, gcall *stmt)
+{
+  rtx_mode_t args[6];
+  for (int i = 0; i < 6; i++)
+    args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
+			  (i & 1) ? SImode : ptr_mode);
+  rtx fun = init_one_libfunc ("__mulbitint3");
+  emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 6, args);
+}
+
+void
+expand_DIVMODBITINT (internal_fn, gcall *stmt)
+{
+  rtx_mode_t args[8];
+  for (int i = 0; i < 8; i++)
+    args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
+			  (i & 1) ? SImode : ptr_mode);
+  rtx fun = init_one_libfunc ("__divmodbitint4");
+  emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 8, args);
+}
+
+void
+expand_FLOATTOBITINT (internal_fn, gcall *stmt)
+{
+  machine_mode mode = TYPE_MODE (TREE_TYPE (gimple_call_arg (stmt, 2)));
+  rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
+  rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
+  rtx arg2 = expand_normal (gimple_call_arg (stmt, 2));
+  const char *mname = GET_MODE_NAME (mode);
+  unsigned mname_len = strlen (mname);
+  int len = 12 + mname_len;
+  if (DECIMAL_FLOAT_MODE_P (mode))
+    len += 4;
+  char *libfunc_name = XALLOCAVEC (char, len);
+  char *p = libfunc_name;
+  const char *q;
+  if (DECIMAL_FLOAT_MODE_P (mode))
+    {
+#if ENABLE_DECIMAL_BID_FORMAT
+      memcpy (p, "__bid_fix", 9);
+#else
+      memcpy (p, "__dpd_fix", 9);
+#endif
+      p += 9;
+    }
+  else
+    {
+      memcpy (p, "__fix", 5);
+      p += 5;
+    }
+  for (q = mname; *q; q++)
+    *p++ = TOLOWER (*q);
+  memcpy (p, "bitint", 7);
+  rtx fun = init_one_libfunc (libfunc_name);
+  emit_library_call (fun, LCT_NORMAL, VOIDmode, arg0, ptr_mode, arg1,
+		     SImode, arg2, mode);
+}
+
+void
+expand_BITINTTOFLOAT (internal_fn, gcall *stmt)
+{
+  tree lhs = gimple_call_lhs (stmt);
+  if (!lhs)
+    return;
+  machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
+  rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
+  rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
+  const char *mname = GET_MODE_NAME (mode);
+  unsigned mname_len = strlen (mname);
+  int len = 14 + mname_len;
+  if (DECIMAL_FLOAT_MODE_P (mode))
+    len += 4;
+  char *libfunc_name = XALLOCAVEC (char, len);
+  char *p = libfunc_name;
+  const char *q;
+  if (DECIMAL_FLOAT_MODE_P (mode))
+    {
+#if ENABLE_DECIMAL_BID_FORMAT
+      memcpy (p, "__bid_floatbitint", 17);
+#else
+      memcpy (p, "__dpd_floatbitint", 17);
+#endif
+      p += 17;
+    }
+  else
+    {
+      memcpy (p, "__floatbitint", 13);
+      p += 13;
+    }
+  for (q = mname; *q; q++)
+    *p++ = TOLOWER (*q);
+  *p = '\0';
+  rtx fun = init_one_libfunc (libfunc_name);
+  rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+  rtx val = emit_library_call_value (fun, target, LCT_PURE, mode,
+				     arg0, ptr_mode, arg1, SImode);
+  if (val != target)
+    emit_move_insn (target, val);
+}
--- gcc/internal-fn.def.jj	2023-08-08 15:55:06.710161600 +0200
+++ gcc/internal-fn.def	2023-08-08 16:12:02.322939896 +0200
@@ -548,6 +548,12 @@ DEF_INTERNAL_FN (ASSUME, ECF_CONST | ECF
 /* For if-conversion of inbranch SIMD clones.  */
 DEF_INTERNAL_FN (MASK_CALL, ECF_NOVOPS, NULL)
 
+/* _BitInt support.  */
+DEF_INTERNAL_FN (MULBITINT, ECF_LEAF | ECF_NOTHROW, ". O . R . R . ")
+DEF_INTERNAL_FN (DIVMODBITINT, ECF_LEAF, ". O . O . R . R . ")
+DEF_INTERNAL_FN (FLOATTOBITINT, ECF_LEAF | ECF_NOTHROW, ". O . . ")
+DEF_INTERNAL_FN (BITINTTOFLOAT, ECF_PURE | ECF_LEAF, ". R . ")
+
 #undef DEF_INTERNAL_INT_FN
 #undef DEF_INTERNAL_FLT_FN
 #undef DEF_INTERNAL_FLT_FLOATN_FN
--- gcc/internal-fn.h.jj	2023-08-08 15:55:06.710161600 +0200
+++ gcc/internal-fn.h	2023-08-08 16:12:02.322939896 +0200
@@ -257,6 +257,10 @@ extern void expand_SPACESHIP (internal_f
 extern void expand_TRAP (internal_fn, gcall *);
 extern void expand_ASSUME (internal_fn, gcall *);
 extern void expand_MASK_CALL (internal_fn, gcall *);
+extern void expand_MULBITINT (internal_fn, gcall *);
+extern void expand_DIVMODBITINT (internal_fn, gcall *);
+extern void expand_FLOATTOBITINT (internal_fn, gcall *);
+extern void expand_BITINTTOFLOAT (internal_fn, gcall *);
 
 extern bool vectorized_internal_fn_supported_p (internal_fn, tree);
 
--- gcc/match.pd.jj	2023-08-08 15:55:07.057156740 +0200
+++ gcc/match.pd	2023-08-08 16:12:02.323939882 +0200
@@ -6557,6 +6557,7 @@ (define_operator_list SYNC_FETCH_AND_AND
 						      - 1)); }))))
      (if (wi::to_wide (cst) == signed_max
 	  && TYPE_UNSIGNED (arg1_type)
+	  && TYPE_MODE (arg1_type) != BLKmode
 	  /* We will flip the signedness of the comparison operator
 	     associated with the mode of @1, so the sign bit is
 	     specified by this mode.  Check that @1 is the signed
--- gcc/pretty-print.h.jj	2023-08-08 15:54:34.806608379 +0200
+++ gcc/pretty-print.h	2023-08-08 16:12:02.324939868 +0200
@@ -336,8 +336,23 @@ pp_get_prefix (const pretty_printer *pp)
 #define pp_wide_int(PP, W, SGN)					\
   do								\
     {								\
-      print_dec (W, pp_buffer (PP)->digit_buffer, SGN);		\
-      pp_string (PP, pp_buffer (PP)->digit_buffer);		\
+      const wide_int_ref &pp_wide_int_ref = (W);		\
+      unsigned int pp_wide_int_prec				\
+	= pp_wide_int_ref.get_precision ();			\
+      if ((pp_wide_int_prec + 3) / 4				\
+	  > sizeof (pp_buffer (PP)->digit_buffer) - 3)		\
+	{							\
+	  char *pp_wide_int_buf					\
+	    = XALLOCAVEC (char, (pp_wide_int_prec + 3) / 4 + 3);\
+	  print_dec (pp_wide_int_ref, pp_wide_int_buf, SGN);	\
+	  pp_string (PP, pp_wide_int_buf);			\
+	}							\
+      else							\
+	{							\
+	  print_dec (pp_wide_int_ref,				\
+		     pp_buffer (PP)->digit_buffer, SGN);	\
+	  pp_string (PP, pp_buffer (PP)->digit_buffer);		\
+	}							\
     }								\
   while (0)
 #define pp_vrange(PP, R)					\
--- gcc/stor-layout.cc.jj	2023-08-08 15:54:34.855607692 +0200
+++ gcc/stor-layout.cc	2023-08-08 16:15:41.003877836 +0200
@@ -2148,6 +2148,22 @@ finish_bitfield_representative (tree rep
       || GET_MODE_BITSIZE (mode) > maxbitsize
       || GET_MODE_BITSIZE (mode) > MAX_FIXED_MODE_SIZE)
     {
+      if (TREE_CODE (TREE_TYPE (field)) == BITINT_TYPE)
+	{
+	  struct bitint_info info;
+	  unsigned prec = TYPE_PRECISION (TREE_TYPE (field));
+	  gcc_assert (targetm.c.bitint_type_info (prec, &info));
+	  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+	  unsigned lprec = GET_MODE_PRECISION (limb_mode);
+	  if (prec > lprec)
+	    {
+	      /* For middle/large/huge _BitInt prefer bitsize being a multiple
+		 of limb precision.  */
+	      unsigned HOST_WIDE_INT bsz = CEIL (bitsize, lprec) * lprec;
+	      if (bsz <= maxbitsize)
+		bitsize = bsz;
+	    }
+	}
       /* We really want a BLKmode representative only as a last resort,
          considering the member b in
 	   struct { int a : 7; int b : 17; int c; } __attribute__((packed));
@@ -2393,6 +2409,64 @@ layout_type (tree type)
 	break;
       }
 
+    case BITINT_TYPE:
+      {
+	struct bitint_info info;
+	int cnt;
+	gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
+	scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+	if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
+	  {
+	    SET_TYPE_MODE (type, limb_mode);
+	    cnt = 1;
+	  }
+	else
+	  {
+	    SET_TYPE_MODE (type, BLKmode);
+	    cnt = CEIL (TYPE_PRECISION (type), GET_MODE_PRECISION (limb_mode));
+	  }
+	TYPE_SIZE (type) = bitsize_int (cnt * GET_MODE_BITSIZE (limb_mode));
+	TYPE_SIZE_UNIT (type) = size_int (cnt * GET_MODE_SIZE (limb_mode));
+	SET_TYPE_ALIGN (type, GET_MODE_ALIGNMENT (limb_mode));
+	if (cnt > 1)
+	  {
+	    /* Use same mode as compute_record_mode would use for a structure
+	       containing cnt limb_mode elements.  */
+	    machine_mode mode = mode_for_size_tree (TYPE_SIZE (type),
+						    MODE_INT, 1).else_blk ();
+	    if (mode == BLKmode)
+	      break;
+	    finalize_type_size (type);
+	    SET_TYPE_MODE (type, mode);
+	    if (STRICT_ALIGNMENT
+		&& !(TYPE_ALIGN (type) >= BIGGEST_ALIGNMENT
+		     || TYPE_ALIGN (type) >= GET_MODE_ALIGNMENT (mode)))
+	      {
+		/* If this is the only reason this type is BLKmode, then
+		   don't force containing types to be BLKmode.  */
+		TYPE_NO_FORCE_BLK (type) = 1;
+		SET_TYPE_MODE (type, BLKmode);
+	      }
+	    if (TYPE_NEXT_VARIANT (type) || type != TYPE_MAIN_VARIANT (type))
+	      for (tree variant = TYPE_MAIN_VARIANT (type);
+		   variant != NULL_TREE;
+		   variant = TYPE_NEXT_VARIANT (variant))
+		{
+		  SET_TYPE_MODE (variant, mode);
+		  if (STRICT_ALIGNMENT
+		      && !(TYPE_ALIGN (variant) >= BIGGEST_ALIGNMENT
+			   || (TYPE_ALIGN (variant)
+			       >= GET_MODE_ALIGNMENT (mode))))
+		    {
+		      TYPE_NO_FORCE_BLK (variant) = 1;
+		      SET_TYPE_MODE (variant, BLKmode);
+		    }
+		}
+	    return;
+	  }
+	break;
+      }
+
     case REAL_TYPE:
       {
 	/* Allow the caller to choose the type mode, which is how decimal
@@ -2417,6 +2491,18 @@ layout_type (tree type)
 
     case COMPLEX_TYPE:
       TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
+      if (TYPE_MODE (TREE_TYPE (type)) == BLKmode)
+	{
+	  gcc_checking_assert (TREE_CODE (TREE_TYPE (type)) == BITINT_TYPE);
+	  SET_TYPE_MODE (type, BLKmode);
+	  TYPE_SIZE (type)
+	    = int_const_binop (MULT_EXPR, TYPE_SIZE (TREE_TYPE (type)),
+			       bitsize_int (2));
+	  TYPE_SIZE_UNIT (type)
+	    = int_const_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (type)),
+			       bitsize_int (2));
+	  break;
+	}
       SET_TYPE_MODE (type,
 		     GET_MODE_COMPLEX_MODE (TYPE_MODE (TREE_TYPE (type))));
 
--- gcc/target.def.jj	2023-08-08 15:54:34.860607622 +0200
+++ gcc/target.def	2023-08-08 19:24:08.280639676 +0200
@@ -6241,6 +6241,25 @@ when @var{type} is @code{EXCESS_PRECISIO
  enum flt_eval_method, (enum excess_precision_type type),
  default_excess_precision)
 
+/* Return true if _BitInt(N) is supported and fill details about it into
+   *INFO.  */
+DEFHOOK
+(bitint_type_info,
+ "This target hook returns true if @code{_BitInt(@var{N})} is supported and\n\
+provides details on it.  @code{_BitInt(@var{N})} is to be represented as\n\
+series of @code{info->limb_mode}\n\
+@code{CEIL (@var{N}, GET_MODE_PRECISION (info->limb_mode))} limbs,\n\
+ordered from least significant to most significant if\n\
+@code{!info->big_endian}, otherwise from most significant to least\n\
+significant.  If @code{info->extended} is false, the bits above or equal to\n\
+@var{N} are undefined when stored in a register or memory, otherwise they\n\
+are zero or sign extended depending on if it is\n\
+@code{unsigned _BitInt(@var{N})} or one of @code{_BitInt(@var{N})} or\n\
+@code{signed _BitInt(@var{N})}.  Alignment of the type is\n\
+@code{GET_MODE_ALIGNMENT (info->limb_mode)}.",
+ bool, (int n, struct bitint_info *info),
+ default_bitint_type_info)
+
 HOOK_VECTOR_END (c)
 
 /* Functions specific to the C++ frontend.  */
--- gcc/target.h.jj	2023-08-08 15:54:34.903607020 +0200
+++ gcc/target.h	2023-08-08 16:12:02.325939854 +0200
@@ -68,6 +68,20 @@ union cumulative_args_t { void *p; };
 
 #endif /* !CHECKING_P */
 
+/* Target properties of _BitInt(N) type.  _BitInt(N) is to be represented
+   as series of limb_mode CEIL (N, GET_MODE_PRECISION (limb_mode)) limbs,
+   ordered from least significant to most significant if !big_endian,
+   otherwise from most significant to least significant.  If extended is
+   false, the bits above or equal to N are undefined when stored in a register
+   or memory, otherwise they are zero or sign extended depending on if
+   it is unsigned _BitInt(N) or _BitInt(N) / signed _BitInt(N).  */
+
+struct bitint_info {
+  machine_mode limb_mode;
+  bool big_endian;
+  bool extended;
+};
+
 /* Types of memory operation understood by the "by_pieces" infrastructure.
    Used by the TARGET_USE_BY_PIECES_INFRASTRUCTURE_P target hook and
    internally by the functions in expr.cc.  */
--- gcc/targhooks.cc.jj	2023-08-08 15:54:34.954606306 +0200
+++ gcc/targhooks.cc	2023-08-08 16:12:02.325939854 +0200
@@ -2595,6 +2595,14 @@ default_excess_precision (enum excess_pr
   return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT;
 }
 
+/* Return true if _BitInt(N) is supported and fill details about it into
+   *INFO.  */
+bool
+default_bitint_type_info (int, struct bitint_info *)
+{
+  return false;
+}
+
 /* Default implementation for
   TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE.  */
 HOST_WIDE_INT
--- gcc/targhooks.h.jj	2023-08-08 15:54:34.981605928 +0200
+++ gcc/targhooks.h	2023-08-08 16:12:02.326939840 +0200
@@ -284,6 +284,7 @@ extern unsigned int default_min_arithmet
 
 extern enum flt_eval_method
 default_excess_precision (enum excess_precision_type ATTRIBUTE_UNUSED);
+extern bool default_bitint_type_info (int, struct bitint_info *);
 extern HOST_WIDE_INT default_stack_clash_protection_alloca_probe_range (void);
 extern void default_select_early_remat_modes (sbitmap);
 extern tree default_preferred_else_value (unsigned, tree, unsigned, tree *);
--- gcc/tree-pretty-print.cc.jj	2023-08-08 15:54:35.084604486 +0200
+++ gcc/tree-pretty-print.cc	2023-08-08 16:12:02.326939840 +0200
@@ -1924,6 +1924,7 @@ dump_generic_node (pretty_printer *pp, t
     case VECTOR_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
+    case BITINT_TYPE:
     case OPAQUE_TYPE:
       {
 	unsigned int quals = TYPE_QUALS (node);
@@ -2038,6 +2039,14 @@ dump_generic_node (pretty_printer *pp, t
 		pp_decimal_int (pp, TYPE_PRECISION (node));
 		pp_greater (pp);
 	      }
+	    else if (TREE_CODE (node) == BITINT_TYPE)
+	      {
+		if (TYPE_UNSIGNED (node))
+		  pp_string (pp, "unsigned ");
+		pp_string (pp, "_BitInt(");
+		pp_decimal_int (pp, TYPE_PRECISION (node));
+		pp_right_paren (pp);
+	      }
 	    else if (TREE_CODE (node) == VOID_TYPE)
 	      pp_string (pp, "void");
 	    else
@@ -2234,8 +2243,18 @@ dump_generic_node (pretty_printer *pp, t
 	      pp_minus (pp);
 	      val = -val;
 	    }
-	  print_hex (val, pp_buffer (pp)->digit_buffer);
-	  pp_string (pp, pp_buffer (pp)->digit_buffer);
+	  unsigned int prec = val.get_precision ();
+	  if ((prec + 3) / 4 > sizeof (pp_buffer (pp)->digit_buffer) - 3)
+	    {
+	      char *buf = XALLOCAVEC (char, (prec + 3) / 4 + 3);
+	      print_hex (val, buf);
+	      pp_string (pp, buf);
+	    }
+	  else
+	    {
+	      print_hex (val, pp_buffer (pp)->digit_buffer);
+	      pp_string (pp, pp_buffer (pp)->digit_buffer);
+	    }
 	}
       if ((flags & TDF_GIMPLE)
 	  && ! (POINTER_TYPE_P (TREE_TYPE (node))
--- gcc/tree-ssa-sccvn.cc.jj	2023-08-08 15:55:09.533122067 +0200
+++ gcc/tree-ssa-sccvn.cc	2023-08-08 16:12:02.328939812 +0200
@@ -74,6 +74,7 @@ along with GCC; see the file COPYING3.
 #include "ipa-modref-tree.h"
 #include "ipa-modref.h"
 #include "tree-ssa-sccvn.h"
+#include "target.h"
 
 /* This algorithm is based on the SCC algorithm presented by Keith
    Cooper and L. Taylor Simpson in "SCC-Based Value numbering"
@@ -6969,8 +6970,14 @@ eliminate_dom_walker::eliminate_stmt (ba
 	      || !DECL_BIT_FIELD_TYPE (TREE_OPERAND (lhs, 1)))
 	  && !type_has_mode_precision_p (TREE_TYPE (lhs)))
 	{
-	  if (TREE_CODE (lhs) == COMPONENT_REF
-	      || TREE_CODE (lhs) == MEM_REF)
+	  if (TREE_CODE (TREE_TYPE (lhs)) == BITINT_TYPE
+	      && (TYPE_PRECISION (TREE_TYPE (lhs))
+		  > (targetm.scalar_mode_supported_p (TImode)
+		     ? GET_MODE_PRECISION (TImode)
+		     : GET_MODE_PRECISION (DImode))))
+	    lookup_lhs = NULL_TREE;
+	  else if (TREE_CODE (lhs) == COMPONENT_REF
+		   || TREE_CODE (lhs) == MEM_REF)
 	    {
 	      tree ltype = build_nonstandard_integer_type
 				(TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (lhs))),
--- gcc/tree-switch-conversion.cc.jj	2023-08-08 15:54:35.311601307 +0200
+++ gcc/tree-switch-conversion.cc	2023-08-09 10:15:33.197094959 +0200
@@ -1143,32 +1143,89 @@ jump_table_cluster::emit (tree index_exp
 			  tree default_label_expr, basic_block default_bb,
 			  location_t loc)
 {
-  unsigned HOST_WIDE_INT range = get_range (get_low (), get_high ());
+  tree low = get_low ();
+  unsigned HOST_WIDE_INT range = get_range (low, get_high ());
   unsigned HOST_WIDE_INT nondefault_range = 0;
+  bool bitint = false;
+  gimple_stmt_iterator gsi = gsi_start_bb (m_case_bb);
+
+  /* For large/huge _BitInt, subtract low from index_expr, cast to unsigned
+     DImode type (get_range doesn't support ranges larger than 64-bits)
+     and subtract low from all case values as well.  */
+  if (TREE_CODE (TREE_TYPE (index_expr)) == BITINT_TYPE
+      && TYPE_PRECISION (TREE_TYPE (index_expr)) > GET_MODE_PRECISION (DImode))
+    {
+      bitint = true;
+      tree this_low = low, type;
+      gimple *g;
+      gimple_seq seq = NULL;
+      if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (index_expr)))
+	{
+	  type = unsigned_type_for (TREE_TYPE (index_expr));
+	  index_expr = gimple_convert (&seq, type, index_expr);
+	  this_low = fold_convert (type, this_low);
+	}
+      this_low = const_unop (NEGATE_EXPR, TREE_TYPE (this_low), this_low);
+      index_expr = gimple_build (&seq, PLUS_EXPR, TREE_TYPE (index_expr),
+				 index_expr, this_low);
+      type = build_nonstandard_integer_type (GET_MODE_PRECISION (DImode), 1);
+      g = gimple_build_cond (GT_EXPR, index_expr,
+			     fold_convert (TREE_TYPE (index_expr),
+					   TYPE_MAX_VALUE (type)),
+			     NULL_TREE, NULL_TREE);
+      gimple_seq_add_stmt (&seq, g);
+      gimple_seq_set_location (seq, loc);
+      gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT);
+      edge e1 = split_block (m_case_bb, g);
+      e1->flags = EDGE_FALSE_VALUE;
+      e1->probability = profile_probability::likely ();
+      edge e2 = make_edge (e1->src, default_bb, EDGE_TRUE_VALUE);
+      e2->probability = e1->probability.invert ();
+      gsi = gsi_start_bb (e1->dest);
+      seq = NULL;
+      index_expr = gimple_convert (&seq, type, index_expr);
+      gimple_seq_set_location (seq, loc);
+      gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT);
+    }
 
   /* For jump table we just emit a new gswitch statement that will
      be latter lowered to jump table.  */
   auto_vec <tree> labels;
   labels.create (m_cases.length ());
 
-  make_edge (m_case_bb, default_bb, 0);
+  basic_block case_bb = gsi_bb (gsi);
+  make_edge (case_bb, default_bb, 0);
   for (unsigned i = 0; i < m_cases.length (); i++)
     {
-      labels.quick_push (unshare_expr (m_cases[i]->m_case_label_expr));
-      make_edge (m_case_bb, m_cases[i]->m_case_bb, 0);
+      tree lab = unshare_expr (m_cases[i]->m_case_label_expr);
+      if (bitint)
+	{
+	  CASE_LOW (lab)
+	    = fold_convert (TREE_TYPE (index_expr),
+			    const_binop (MINUS_EXPR,
+					 TREE_TYPE (CASE_LOW (lab)),
+					 CASE_LOW (lab), low));
+	  if (CASE_HIGH (lab))
+	    CASE_HIGH (lab)
+	      = fold_convert (TREE_TYPE (index_expr),
+			      const_binop (MINUS_EXPR,
+					   TREE_TYPE (CASE_HIGH (lab)),
+					   CASE_HIGH (lab), low));
+	}
+      labels.quick_push (lab);
+      make_edge (case_bb, m_cases[i]->m_case_bb, 0);
     }
 
   gswitch *s = gimple_build_switch (index_expr,
 				    unshare_expr (default_label_expr), labels);
   gimple_set_location (s, loc);
-  gimple_stmt_iterator gsi = gsi_start_bb (m_case_bb);
   gsi_insert_after (&gsi, s, GSI_NEW_STMT);
 
   /* Set up even probabilities for all cases.  */
   for (unsigned i = 0; i < m_cases.length (); i++)
     {
       simple_cluster *sc = static_cast<simple_cluster *> (m_cases[i]);
-      edge case_edge = find_edge (m_case_bb, sc->m_case_bb);
+      edge case_edge = find_edge (case_bb, sc->m_case_bb);
       unsigned HOST_WIDE_INT case_range
 	= sc->get_range (sc->get_low (), sc->get_high ());
       nondefault_range += case_range;
@@ -1184,7 +1241,7 @@ jump_table_cluster::emit (tree index_exp
   for (unsigned i = 0; i < m_cases.length (); i++)
     {
       simple_cluster *sc = static_cast<simple_cluster *> (m_cases[i]);
-      edge case_edge = find_edge (m_case_bb, sc->m_case_bb);
+      edge case_edge = find_edge (case_bb, sc->m_case_bb);
       case_edge->probability
 	= profile_probability::always ().apply_scale ((intptr_t)case_edge->aux,
 						      range);
--- gcc/typeclass.h.jj	2023-08-08 15:54:35.434599585 +0200
+++ gcc/typeclass.h	2023-08-08 16:12:02.328939812 +0200
@@ -37,7 +37,8 @@ enum type_class
   function_type_class, method_type_class,
   record_type_class, union_type_class,
   array_type_class, string_type_class,
-  lang_type_class, opaque_type_class
+  lang_type_class, opaque_type_class,
+  bitint_type_class
 };
 
 #endif /* GCC_TYPECLASS_H */
--- gcc/varasm.cc.jj	2023-08-08 15:54:35.517598423 +0200
+++ gcc/varasm.cc	2023-08-08 16:12:02.330939784 +0200
@@ -5281,6 +5281,61 @@ output_constant (tree exp, unsigned HOST
 		       reverse, false);
       break;
 
+    case BITINT_TYPE:
+      if (TREE_CODE (exp) != INTEGER_CST)
+	error ("initializer for %<_BitInt(%d)%> value is not an integer "
+	       "constant", TYPE_PRECISION (TREE_TYPE (exp)));
+      else
+	{
+	  struct bitint_info info;
+	  tree type = TREE_TYPE (exp);
+	  gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
+						  &info));
+	  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+	  if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
+	    {
+	      cst = expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
+	      if (reverse)
+		cst = flip_storage_order (TYPE_MODE (TREE_TYPE (exp)), cst);
+	      if (!assemble_integer (cst, MIN (size, thissize), align, 0))
+		error ("initializer for integer/fixed-point value is too "
+		       "complicated");
+	      break;
+	    }
+	  int prec = GET_MODE_PRECISION (limb_mode);
+	  int cnt = CEIL (TYPE_PRECISION (type), prec);
+	  tree limb_type = build_nonstandard_integer_type (prec, 1);
+	  int elt_size = GET_MODE_SIZE (limb_mode);
+	  unsigned int nalign = MIN (align, GET_MODE_ALIGNMENT (limb_mode));
+	  thissize = 0;
+	  if (prec == HOST_BITS_PER_WIDE_INT)
+	    for (int i = 0; i < cnt; i++)
+	      {
+		int idx = (info.big_endian ^ reverse) ? cnt - 1 - i : i;
+		tree c;
+		if (idx >= TREE_INT_CST_EXT_NUNITS (exp))
+		  c = build_int_cst (limb_type,
+				     tree_int_cst_sgn (exp) < 0 ? -1 : 0);
+		else
+		  c = build_int_cst (limb_type,
+				     TREE_INT_CST_ELT (exp, idx));
+		output_constant (c, elt_size, nalign, reverse, false);
+		thissize += elt_size;
+	      }
+	  else
+	    for (int i = 0; i < cnt; i++)
+	      {
+		int idx = (info.big_endian ^ reverse) ? cnt - 1 - i : i;
+		wide_int w = wi::rshift (wi::to_wide (exp), idx * prec,
+					 TYPE_SIGN (TREE_TYPE (exp)));
+		tree c = wide_int_to_tree (limb_type,
+					   wide_int::from (w, prec, UNSIGNED));
+		output_constant (c, elt_size, nalign, reverse, false);
+		thissize += elt_size;
+	      }
+	}
+      break;
+
     case ARRAY_TYPE:
     case VECTOR_TYPE:
       switch (TREE_CODE (exp))
--- gcc/vr-values.cc.jj	2023-08-08 15:54:35.560597822 +0200
+++ gcc/vr-values.cc	2023-08-08 16:12:02.330939784 +0200
@@ -111,21 +111,21 @@ check_for_binary_op_overflow (range_quer
     {
       /* So far we found that there is an overflow on the boundaries.
 	 That doesn't prove that there is an overflow even for all values
-	 in between the boundaries.  For that compute widest_int range
+	 in between the boundaries.  For that compute widest2_int range
 	 of the result and see if it doesn't overlap the range of
 	 type.  */
-      widest_int wmin, wmax;
-      widest_int w[4];
+      widest2_int wmin, wmax;
+      widest2_int w[4];
       int i;
       signop sign0 = TYPE_SIGN (TREE_TYPE (op0));
       signop sign1 = TYPE_SIGN (TREE_TYPE (op1));
-      w[0] = widest_int::from (vr0.lower_bound (), sign0);
-      w[1] = widest_int::from (vr0.upper_bound (), sign0);
-      w[2] = widest_int::from (vr1.lower_bound (), sign1);
-      w[3] = widest_int::from (vr1.upper_bound (), sign1);
+      w[0] = widest2_int::from (vr0.lower_bound (), sign0);
+      w[1] = widest2_int::from (vr0.upper_bound (), sign0);
+      w[2] = widest2_int::from (vr1.lower_bound (), sign1);
+      w[3] = widest2_int::from (vr1.upper_bound (), sign1);
       for (i = 0; i < 4; i++)
 	{
-	  widest_int wt;
+	  widest2_int wt;
 	  switch (subcode)
 	    {
 	    case PLUS_EXPR:
@@ -153,10 +153,10 @@ check_for_binary_op_overflow (range_quer
 	}
       /* The result of op0 CODE op1 is known to be in range
 	 [wmin, wmax].  */
-      widest_int wtmin
-	= widest_int::from (irange_val_min (type), TYPE_SIGN (type));
-      widest_int wtmax
-	= widest_int::from (irange_val_max (type), TYPE_SIGN (type));
+      widest2_int wtmin
+	= widest2_int::from (irange_val_min (type), TYPE_SIGN (type));
+      widest2_int wtmax
+	= widest2_int::from (irange_val_max (type), TYPE_SIGN (type));
       /* If all values in [wmin, wmax] are smaller than
 	 [wtmin, wtmax] or all are larger than [wtmin, wtmax],
 	 the arithmetic operation will always overflow.  */
@@ -1717,12 +1717,11 @@ simplify_using_ranges::simplify_internal
     g = gimple_build_assign (gimple_call_lhs (stmt), subcode, op0, op1);
   else
     {
-      int prec = TYPE_PRECISION (type);
       tree utype = type;
       if (ovf
 	  || !useless_type_conversion_p (type, TREE_TYPE (op0))
 	  || !useless_type_conversion_p (type, TREE_TYPE (op1)))
-	utype = build_nonstandard_integer_type (prec, 1);
+	utype = unsigned_type_for (type);
       if (TREE_CODE (op0) == INTEGER_CST)
 	op0 = fold_convert (utype, op0);
       else if (!useless_type_conversion_p (utype, TREE_TYPE (op0)))

	Jakub


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

* Re: [PATCH 4/12] Middle-end _BitInt support [PR102989]
  2023-08-09 18:17 [PATCH 4/12] Middle-end _BitInt support [PR102989] Jakub Jelinek
@ 2023-08-22  8:41 ` Richard Biener
  2023-09-07  8:36 ` Thomas Schwinge
  1 sibling, 0 replies; 4+ messages in thread
From: Richard Biener @ 2023-08-22  8:41 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On Wed, 9 Aug 2023, Jakub Jelinek wrote:

> Hi!
> 
> The following patch introduces the middle-end part of the _BitInt
> support, a new BITINT_TYPE, handling it where needed, except the lowering
> pass and sanitizer support.

This is OK.

Thanks,
Richard.

> 2023-08-09  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c/102989
> 	* tree.def (BITINT_TYPE): New type.
> 	* tree.h (TREE_CHECK6, TREE_NOT_CHECK6): Define.
> 	(NUMERICAL_TYPE_CHECK, INTEGRAL_TYPE_P): Include
> 	BITINT_TYPE.
> 	(BITINT_TYPE_P): Define.
> 	(CONSTRUCTOR_BITFIELD_P): Return true even for BLKmode bit-fields if
> 	they have BITINT_TYPE type.
> 	(tree_check6, tree_not_check6): New inline functions.
> 	(any_integral_type_check): Include BITINT_TYPE.
> 	(build_bitint_type): Declare.
> 	* tree.cc (tree_code_size, wide_int_to_tree_1, cache_integer_cst,
> 	build_zero_cst, type_hash_canon_hash, type_cache_hasher::equal,
> 	type_hash_canon): Handle BITINT_TYPE.
> 	(bitint_type_cache): New variable.
> 	(build_bitint_type): New function.
> 	(signed_or_unsigned_type_for, verify_type_variant, verify_type):
> 	Handle BITINT_TYPE.
> 	(tree_cc_finalize): Free bitint_type_cache.
> 	* builtins.cc (type_to_class): Handle BITINT_TYPE.
> 	(fold_builtin_unordered_cmp): Handle BITINT_TYPE like INTEGER_TYPE.
> 	* cfgexpand.cc (expand_debug_expr): Punt on BLKmode BITINT_TYPE
> 	INTEGER_CSTs.
> 	* convert.cc (convert_to_pointer_1, convert_to_real_1,
> 	convert_to_complex_1): Handle BITINT_TYPE like INTEGER_TYPE.
> 	(convert_to_integer_1): Likewise.  For BITINT_TYPE don't check
> 	GET_MODE_PRECISION (TYPE_MODE (type)).
> 	* doc/generic.texi (BITINT_TYPE): Document.
> 	* doc/tm.texi.in (TARGET_C_BITINT_TYPE_INFO): New.
> 	* doc/tm.texi: Regenerated.
> 	* dwarf2out.cc (base_type_die, is_base_type, modified_type_die,
> 	gen_type_die_with_usage): Handle BITINT_TYPE.
> 	(rtl_for_decl_init): Punt on BLKmode BITINT_TYPE INTEGER_CSTs or
> 	handle those which fit into shwi.
> 	* expr.cc (expand_expr_real_1): Define EXTEND_BITINT macro, reduce
> 	to bitfield precision reads from BITINT_TYPE vars, parameters or
> 	memory locations.  Expand large/huge BITINT_TYPE INTEGER_CSTs into
> 	memory.
> 	* fold-const.cc (fold_convert_loc, make_range_step): Handle
> 	BITINT_TYPE.
> 	(extract_muldiv_1): For BITINT_TYPE use TYPE_PRECISION rather than
> 	GET_MODE_SIZE (SCALAR_INT_TYPE_MODE).
> 	(native_encode_int, native_interpret_int, native_interpret_expr):
> 	Handle BITINT_TYPE.
> 	* gimple-expr.cc (useless_type_conversion_p): Make BITINT_TYPE
> 	to some other integral type or vice versa conversions non-useless.
> 	* gimple-fold.cc (gimple_fold_builtin_memset): Punt for BITINT_TYPE.
> 	(clear_padding_unit): Mention in comment that _BitInt types don't need
> 	to fit either.
> 	(clear_padding_bitint_needs_padding_p): New function.
> 	(clear_padding_type_may_have_padding_p): Handle BITINT_TYPE.
> 	(clear_padding_type): Likewise.
> 	* internal-fn.cc (expand_mul_overflow): For unsigned non-mode
> 	precision operands force pos_neg? to 1.
> 	(expand_MULBITINT, expand_DIVMODBITINT, expand_FLOATTOBITINT,
> 	expand_BITINTTOFLOAT): New functions.
> 	* internal-fn.def (MULBITINT, DIVMODBITINT, FLOATTOBITINT,
> 	BITINTTOFLOAT): New internal functions.
> 	* internal-fn.h (expand_MULBITINT, expand_DIVMODBITINT,
> 	expand_FLOATTOBITINT, expand_BITINTTOFLOAT): Declare.
> 	* match.pd (non-equality compare simplifications from fold_binary):
> 	Punt if TYPE_MODE (arg1_type) is BLKmode.
> 	* pretty-print.h (pp_wide_int): Handle printing of large precision
> 	wide_ints which would buffer overflow digit_buffer.
> 	* stor-layout.cc (finish_bitfield_representative): For bit-fields
> 	with BITINT_TYPE, prefer representatives with precisions in
> 	multiple of limb precision.
> 	(layout_type): Handle BITINT_TYPE.  Handle COMPLEX_TYPE with BLKmode
> 	element type and assert it is BITINT_TYPE.
> 	* target.def (bitint_type_info): New C target hook.
> 	* target.h (struct bitint_info): New type.
> 	* targhooks.cc (default_bitint_type_info): New function.
> 	* targhooks.h (default_bitint_type_info): Declare.
> 	* tree-pretty-print.cc (dump_generic_node): Handle BITINT_TYPE.
> 	Handle printing large wide_ints which would buffer overflow
> 	digit_buffer.
> 	* tree-ssa-sccvn.cc: Include target.h.
> 	(eliminate_dom_walker::eliminate_stmt): Punt for large/huge
> 	BITINT_TYPE.
> 	* tree-switch-conversion.cc (jump_table_cluster::emit): For more than
> 	64-bit BITINT_TYPE subtract low bound from expression and cast to
> 	64-bit integer type both the controlling expression and case labels.
> 	* typeclass.h (enum type_class): Add bitint_type_class enumerator.
> 	* varasm.cc (output_constant): Handle BITINT_TYPE INTEGER_CSTs.
> 	* vr-values.cc (check_for_binary_op_overflow): Use widest2_int rather
> 	than widest_int.
> 	(simplify_using_ranges::simplify_internal_call_using_ranges): Use
> 	unsigned_type_for rather than build_nonstandard_integer_type.
> 
> --- gcc/tree.def.jj	2023-08-08 15:54:35.387600243 +0200
> +++ gcc/tree.def	2023-08-08 16:57:23.708840829 +0200
> @@ -113,7 +113,7 @@ DEFTREECODE (BLOCK, "block", tcc_excepti
>  /* The ordering of the following codes is optimized for the checking
>     macros in tree.h.  Changing the order will degrade the speed of the
>     compiler.  OFFSET_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, INTEGER_TYPE,
> -   REAL_TYPE, POINTER_TYPE.  */
> +   BITINT_TYPE, REAL_TYPE, POINTER_TYPE.  */
>  
>  /* An offset is a pointer relative to an object.
>     The TREE_TYPE field is the type of the object at the offset.
> @@ -144,6 +144,13 @@ DEFTREECODE (BOOLEAN_TYPE, "boolean_type
>     and TYPE_PRECISION (number of bits used by this type).  */
>  DEFTREECODE (INTEGER_TYPE, "integer_type", tcc_type, 0)
>  
> +/* Bit-precise integer type.  These are similar to INTEGER_TYPEs, but
> +   can have arbitrary user selected precisions and do or can have different
> +   alignment, function argument and return value passing conventions.
> +   Larger BITINT_TYPEs can have BLKmode TYPE_MODE and need to be lowered
> +   by a special BITINT_TYPE lowering pass.  */
> +DEFTREECODE (BITINT_TYPE, "bitint_type", tcc_type, 0)
> +
>  /* C's float and double.  Different floating types are distinguished
>     by machine mode and by the TYPE_SIZE and the TYPE_PRECISION.  */
>  DEFTREECODE (REAL_TYPE, "real_type", tcc_type, 0)
> --- gcc/tree.h.jj	2023-08-08 15:55:09.601121115 +0200
> +++ gcc/tree.h	2023-08-08 16:15:41.003877836 +0200
> @@ -363,6 +363,14 @@ code_helper::is_builtin_fn () const
>  (tree_not_check5 ((T), __FILE__, __LINE__, __FUNCTION__, \
>                                 (CODE1), (CODE2), (CODE3), (CODE4), (CODE5)))
>  
> +#define TREE_CHECK6(T, CODE1, CODE2, CODE3, CODE4, CODE5, CODE6) \
> +(tree_check6 ((T), __FILE__, __LINE__, __FUNCTION__, \
> +			(CODE1), (CODE2), (CODE3), (CODE4), (CODE5), (CODE6)))
> +
> +#define TREE_NOT_CHECK6(T, CODE1, CODE2, CODE3, CODE4, CODE5, CODE6) \
> +(tree_not_check6 ((T), __FILE__, __LINE__, __FUNCTION__, \
> +			(CODE1), (CODE2), (CODE3), (CODE4), (CODE5), (CODE6)))
> +
>  #define CONTAINS_STRUCT_CHECK(T, STRUCT) \
>  (contains_struct_check ((T), (STRUCT), __FILE__, __LINE__, __FUNCTION__))
>  
> @@ -485,6 +493,8 @@ extern void omp_clause_range_check_faile
>  #define TREE_NOT_CHECK4(T, CODE1, CODE2, CODE3, CODE4) (T)
>  #define TREE_CHECK5(T, CODE1, CODE2, CODE3, CODE4, CODE5) (T)
>  #define TREE_NOT_CHECK5(T, CODE1, CODE2, CODE3, CODE4, CODE5) (T)
> +#define TREE_CHECK6(T, CODE1, CODE2, CODE3, CODE4, CODE5, CODE6) (T)
> +#define TREE_NOT_CHECK6(T, CODE1, CODE2, CODE3, CODE4, CODE5, CODE6) (T)
>  #define TREE_CLASS_CHECK(T, CODE)		(T)
>  #define TREE_RANGE_CHECK(T, CODE1, CODE2)	(T)
>  #define EXPR_CHECK(T)				(T)
> @@ -528,8 +538,8 @@ extern void omp_clause_range_check_faile
>    TREE_CHECK2 (T, ARRAY_TYPE, INTEGER_TYPE)
>  
>  #define NUMERICAL_TYPE_CHECK(T)					\
> -  TREE_CHECK5 (T, INTEGER_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, REAL_TYPE,	\
> -	       FIXED_POINT_TYPE)
> +  TREE_CHECK6 (T, INTEGER_TYPE, ENUMERAL_TYPE, BOOLEAN_TYPE, REAL_TYPE,	\
> +	       FIXED_POINT_TYPE, BITINT_TYPE)
>  
>  /* Here is how primitive or already-canonicalized types' hash codes
>     are made.  */
> @@ -603,7 +613,8 @@ extern void omp_clause_range_check_faile
>  #define INTEGRAL_TYPE_P(TYPE)  \
>    (TREE_CODE (TYPE) == ENUMERAL_TYPE  \
>     || TREE_CODE (TYPE) == BOOLEAN_TYPE \
> -   || TREE_CODE (TYPE) == INTEGER_TYPE)
> +   || TREE_CODE (TYPE) == INTEGER_TYPE \
> +   || TREE_CODE (TYPE) == BITINT_TYPE)
>  
>  /* Nonzero if TYPE represents an integral type, including complex
>     and vector integer types.  */
> @@ -614,6 +625,10 @@ extern void omp_clause_range_check_faile
>          || VECTOR_TYPE_P (TYPE))		\
>         && INTEGRAL_TYPE_P (TREE_TYPE (TYPE))))
>  
> +/* Nonzero if TYPE is bit-precise integer type.  */
> +
> +#define BITINT_TYPE_P(TYPE) (TREE_CODE (TYPE) == BITINT_TYPE)
> +
>  /* Nonzero if TYPE represents a non-saturating fixed-point type.  */
>  
>  #define NON_SAT_FIXED_POINT_TYPE_P(TYPE) \
> @@ -1244,7 +1259,9 @@ extern void omp_clause_range_check_faile
>  /* True if NODE, a FIELD_DECL, is to be processed as a bitfield for
>     constructor output purposes.  */
>  #define CONSTRUCTOR_BITFIELD_P(NODE) \
> -  (DECL_BIT_FIELD (FIELD_DECL_CHECK (NODE)) && DECL_MODE (NODE) != BLKmode)
> +  (DECL_BIT_FIELD (FIELD_DECL_CHECK (NODE)) \
> +   && (DECL_MODE (NODE) != BLKmode \
> +       || TREE_CODE (TREE_TYPE (NODE)) == BITINT_TYPE))
>  
>  /* True if NODE is a clobber right hand side, an expression of indeterminate
>     value that clobbers the LHS in a copy instruction.  We use a volatile
> @@ -3684,6 +3701,38 @@ tree_not_check5 (tree __t, const char *_
>  }
>  
>  inline tree
> +tree_check6 (tree __t, const char *__f, int __l, const char *__g,
> +	     enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
> +	     enum tree_code __c4, enum tree_code __c5, enum tree_code __c6)
> +{
> +  if (TREE_CODE (__t) != __c1
> +      && TREE_CODE (__t) != __c2
> +      && TREE_CODE (__t) != __c3
> +      && TREE_CODE (__t) != __c4
> +      && TREE_CODE (__t) != __c5
> +      && TREE_CODE (__t) != __c6)
> +    tree_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, __c5, __c6,
> +		       0);
> +  return __t;
> +}
> +
> +inline tree
> +tree_not_check6 (tree __t, const char *__f, int __l, const char *__g,
> +		 enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
> +		 enum tree_code __c4, enum tree_code __c5, enum tree_code __c6)
> +{
> +  if (TREE_CODE (__t) == __c1
> +      || TREE_CODE (__t) == __c2
> +      || TREE_CODE (__t) == __c3
> +      || TREE_CODE (__t) == __c4
> +      || TREE_CODE (__t) == __c5
> +      || TREE_CODE (__t) == __c6)
> +    tree_not_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, __c5,
> +			   __c6, 0);
> +  return __t;
> +}
> +
> +inline tree
>  contains_struct_check (tree __t, const enum tree_node_structure_enum __s,
>                         const char *__f, int __l, const char *__g)
>  {
> @@ -3821,7 +3870,7 @@ any_integral_type_check (tree __t, const
>  {
>    if (!ANY_INTEGRAL_TYPE_P (__t))
>      tree_check_failed (__t, __f, __l, __g, BOOLEAN_TYPE, ENUMERAL_TYPE,
> -		       INTEGER_TYPE, 0);
> +		       INTEGER_TYPE, BITINT_TYPE, 0);
>    return __t;
>  }
>  
> @@ -3940,6 +3989,38 @@ tree_not_check5 (const_tree __t, const c
>  }
>  
>  inline const_tree
> +tree_check6 (const_tree __t, const char *__f, int __l, const char *__g,
> +	     enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
> +	     enum tree_code __c4, enum tree_code __c5, enum tree_code __c6)
> +{
> +  if (TREE_CODE (__t) != __c1
> +      && TREE_CODE (__t) != __c2
> +      && TREE_CODE (__t) != __c3
> +      && TREE_CODE (__t) != __c4
> +      && TREE_CODE (__t) != __c5
> +      && TREE_CODE (__t) != __c6)
> +    tree_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, __c5, __c6,
> +		       0);
> +  return __t;
> +}
> +
> +inline const_tree
> +tree_not_check6 (const_tree __t, const char *__f, int __l, const char *__g,
> +		 enum tree_code __c1, enum tree_code __c2, enum tree_code __c3,
> +		 enum tree_code __c4, enum tree_code __c5, enum tree_code __c6)
> +{
> +  if (TREE_CODE (__t) == __c1
> +      || TREE_CODE (__t) == __c2
> +      || TREE_CODE (__t) == __c3
> +      || TREE_CODE (__t) == __c4
> +      || TREE_CODE (__t) == __c5
> +      || TREE_CODE (__t) == __c6)
> +    tree_not_check_failed (__t, __f, __l, __g, __c1, __c2, __c3, __c4, __c5,
> +			   __c6, 0);
> +  return __t;
> +}
> +
> +inline const_tree
>  contains_struct_check (const_tree __t, const enum tree_node_structure_enum __s,
>                         const char *__f, int __l, const char *__g)
>  {
> @@ -4047,7 +4128,7 @@ any_integral_type_check (const_tree __t,
>  {
>    if (!ANY_INTEGRAL_TYPE_P (__t))
>      tree_check_failed (__t, __f, __l, __g, BOOLEAN_TYPE, ENUMERAL_TYPE,
> -		       INTEGER_TYPE, 0);
> +		       INTEGER_TYPE, BITINT_TYPE, 0);
>    return __t;
>  }
>  
> @@ -5579,6 +5660,7 @@ extern void build_common_builtin_nodes (
>  extern void tree_cc_finalize (void);
>  extern tree build_nonstandard_integer_type (unsigned HOST_WIDE_INT, int);
>  extern tree build_nonstandard_boolean_type (unsigned HOST_WIDE_INT);
> +extern tree build_bitint_type (unsigned HOST_WIDE_INT, int);
>  extern tree build_range_type (tree, tree, tree);
>  extern tree build_nonshared_range_type (tree, tree, tree);
>  extern bool subrange_type_for_debug_p (const_tree, tree *, tree *);
> --- gcc/tree.cc.jj	2023-08-08 15:54:35.331601028 +0200
> +++ gcc/tree.cc	2023-08-08 16:12:02.302940175 +0200
> @@ -991,6 +991,7 @@ tree_code_size (enum tree_code code)
>  	case VOID_TYPE:
>  	case FUNCTION_TYPE:
>  	case METHOD_TYPE:
> +	case BITINT_TYPE:
>  	case LANG_TYPE:		return sizeof (tree_type_non_common);
>  	default:
>  	  gcc_checking_assert (code >= NUM_TREE_CODES);
> @@ -1732,6 +1733,7 @@ wide_int_to_tree_1 (tree type, const wid
>  
>  	case INTEGER_TYPE:
>  	case OFFSET_TYPE:
> +	case BITINT_TYPE:
>  	  if (TYPE_SIGN (type) == UNSIGNED)
>  	    {
>  	      /* Cache [0, N).  */
> @@ -1915,6 +1917,7 @@ cache_integer_cst (tree t, bool might_du
>  
>      case INTEGER_TYPE:
>      case OFFSET_TYPE:
> +    case BITINT_TYPE:
>        if (TYPE_UNSIGNED (type))
>  	{
>  	  /* Cache 0..N */
> @@ -2637,7 +2640,7 @@ build_zero_cst (tree type)
>      {
>      case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
>      case POINTER_TYPE: case REFERENCE_TYPE:
> -    case OFFSET_TYPE: case NULLPTR_TYPE:
> +    case OFFSET_TYPE: case NULLPTR_TYPE: case BITINT_TYPE:
>        return build_int_cst (type, 0);
>  
>      case REAL_TYPE:
> @@ -6053,7 +6056,16 @@ type_hash_canon_hash (tree type)
>  	  hstate.add_object (TREE_INT_CST_ELT (t, i));
>  	break;
>        }
> -      
> +
> +    case BITINT_TYPE:
> +      {
> +	unsigned prec = TYPE_PRECISION (type);
> +	unsigned uns = TYPE_UNSIGNED (type);
> +	hstate.add_object (prec);
> +	hstate.add_int (uns);
> +	break;
> +      }
> +
>      case REAL_TYPE:
>      case FIXED_POINT_TYPE:
>        {
> @@ -6136,6 +6148,11 @@ type_cache_hasher::equal (type_hash *a,
>  		  || tree_int_cst_equal (TYPE_MIN_VALUE (a->type),
>  					 TYPE_MIN_VALUE (b->type))));
>  
> +    case BITINT_TYPE:
> +      if (TYPE_PRECISION (a->type) != TYPE_PRECISION (b->type))
> +	return false;
> +      return TYPE_UNSIGNED (a->type) == TYPE_UNSIGNED (b->type);
> +
>      case FIXED_POINT_TYPE:
>        return TYPE_SATURATING (a->type) == TYPE_SATURATING (b->type);
>  
> @@ -6236,7 +6253,7 @@ type_hash_canon (unsigned int hashcode,
>        /* Free also min/max values and the cache for integer
>  	 types.  This can't be done in free_node, as LTO frees
>  	 those on its own.  */
> -      if (TREE_CODE (type) == INTEGER_TYPE)
> +      if (TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == BITINT_TYPE)
>  	{
>  	  if (TYPE_MIN_VALUE (type)
>  	      && TREE_TYPE (TYPE_MIN_VALUE (type)) == type)
> @@ -7154,6 +7171,44 @@ build_nonstandard_boolean_type (unsigned
>    return type;
>  }
>  
> +static GTY(()) vec<tree, va_gc> *bitint_type_cache;
> +
> +/* Builds a signed or unsigned _BitInt(PRECISION) type.  */
> +tree
> +build_bitint_type (unsigned HOST_WIDE_INT precision, int unsignedp)
> +{
> +  tree itype, ret;
> +
> +  if (unsignedp)
> +    unsignedp = MAX_INT_CACHED_PREC + 1;
> +
> +  if (bitint_type_cache == NULL)
> +    vec_safe_grow_cleared (bitint_type_cache, 2 * MAX_INT_CACHED_PREC + 2);
> +
> +  if (precision <= MAX_INT_CACHED_PREC)
> +    {
> +      itype = (*bitint_type_cache)[precision + unsignedp];
> +      if (itype)
> +	return itype;
> +    }
> +
> +  itype = make_node (BITINT_TYPE);
> +  TYPE_PRECISION (itype) = precision;
> +
> +  if (unsignedp)
> +    fixup_unsigned_type (itype);
> +  else
> +    fixup_signed_type (itype);
> +
> +  inchash::hash hstate;
> +  inchash::add_expr (TYPE_MAX_VALUE (itype), hstate);
> +  ret = type_hash_canon (hstate.end (), itype);
> +  if (precision <= MAX_INT_CACHED_PREC)
> +    (*bitint_type_cache)[precision + unsignedp] = ret;
> +
> +  return ret;
> +}
> +
>  /* Create a range of some discrete type TYPE (an INTEGER_TYPE, ENUMERAL_TYPE
>     or BOOLEAN_TYPE) with low bound LOWVAL and high bound HIGHVAL.  If SHARED
>     is true, reuse such a type that has already been constructed.  */
> @@ -11041,6 +11096,8 @@ signed_or_unsigned_type_for (int unsigne
>    else
>      return NULL_TREE;
>  
> +  if (TREE_CODE (type) == BITINT_TYPE)
> +    return build_bitint_type (bits, unsignedp);
>    return build_nonstandard_integer_type (bits, unsignedp);
>  }
>  
> @@ -13462,6 +13519,7 @@ verify_type_variant (const_tree t, tree
>    if ((TREE_CODE (t) == ENUMERAL_TYPE && COMPLETE_TYPE_P (t))
>         || TREE_CODE (t) == INTEGER_TYPE
>         || TREE_CODE (t) == BOOLEAN_TYPE
> +       || TREE_CODE (t) == BITINT_TYPE
>         || SCALAR_FLOAT_TYPE_P (t)
>         || FIXED_POINT_TYPE_P (t))
>      {
> @@ -14201,6 +14259,7 @@ verify_type (const_tree t)
>      }
>    else if (TREE_CODE (t) == INTEGER_TYPE
>  	   || TREE_CODE (t) == BOOLEAN_TYPE
> +	   || TREE_CODE (t) == BITINT_TYPE
>  	   || TREE_CODE (t) == OFFSET_TYPE
>  	   || TREE_CODE (t) == REFERENCE_TYPE
>  	   || TREE_CODE (t) == NULLPTR_TYPE
> @@ -14260,6 +14319,7 @@ verify_type (const_tree t)
>      }
>    if (TREE_CODE (t) != INTEGER_TYPE
>        && TREE_CODE (t) != BOOLEAN_TYPE
> +      && TREE_CODE (t) != BITINT_TYPE
>        && TREE_CODE (t) != OFFSET_TYPE
>        && TREE_CODE (t) != REFERENCE_TYPE
>        && TREE_CODE (t) != NULLPTR_TYPE
> @@ -15035,6 +15095,7 @@ void
>  tree_cc_finalize (void)
>  {
>    clear_nonstandard_integer_type_cache ();
> +  vec_free (bitint_type_cache);
>  }
>  
>  #if CHECKING_P
> --- gcc/builtins.cc.jj	2023-08-08 15:55:05.230182325 +0200
> +++ gcc/builtins.cc	2023-08-08 16:12:02.303940161 +0200
> @@ -1876,6 +1876,7 @@ type_to_class (tree type)
>  				   ? string_type_class : array_type_class);
>      case LANG_TYPE:	   return lang_type_class;
>      case OPAQUE_TYPE:      return opaque_type_class;
> +    case BITINT_TYPE:	   return bitint_type_class;
>      default:		   return no_type_class;
>      }
>  }
> @@ -9423,9 +9424,11 @@ fold_builtin_unordered_cmp (location_t l
>      /* Choose the wider of two real types.  */
>      cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1)
>        ? type0 : type1;
> -  else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
> +  else if (code0 == REAL_TYPE
> +	   && (code1 == INTEGER_TYPE || code1 == BITINT_TYPE))
>      cmp_type = type0;
> -  else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
> +  else if ((code0 == INTEGER_TYPE || code0 == BITINT_TYPE)
> +	   && code1 == REAL_TYPE)
>      cmp_type = type1;
>  
>    arg0 = fold_convert_loc (loc, cmp_type, arg0);
> --- gcc/cfgexpand.cc.jj	2023-08-08 15:54:33.893621164 +0200
> +++ gcc/cfgexpand.cc	2023-08-08 17:19:26.025312540 +0200
> @@ -4524,6 +4524,10 @@ expand_debug_expr (tree exp)
>        /* Fall through.  */
>  
>      case INTEGER_CST:
> +      if (TREE_CODE (TREE_TYPE (exp)) == BITINT_TYPE
> +	  && TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
> +	return NULL;
> +      /* FALLTHRU */
>      case REAL_CST:
>      case FIXED_CST:
>        op0 = expand_expr (exp, NULL_RTX, mode, EXPAND_INITIALIZER);
> --- gcc/convert.cc.jj	2023-08-08 15:54:33.998619694 +0200
> +++ gcc/convert.cc	2023-08-08 16:12:02.308940091 +0200
> @@ -77,6 +77,7 @@ convert_to_pointer_1 (tree type, tree ex
>      case INTEGER_TYPE:
>      case ENUMERAL_TYPE:
>      case BOOLEAN_TYPE:
> +    case BITINT_TYPE:
>        {
>  	/* If the input precision differs from the target pointer type
>  	   precision, first convert the input expression to an integer type of
> @@ -316,6 +317,7 @@ convert_to_real_1 (tree type, tree expr,
>      case INTEGER_TYPE:
>      case ENUMERAL_TYPE:
>      case BOOLEAN_TYPE:
> +    case BITINT_TYPE:
>        return build1 (FLOAT_EXPR, type, expr);
>  
>      case FIXED_POINT_TYPE:
> @@ -660,6 +662,7 @@ convert_to_integer_1 (tree type, tree ex
>      case ENUMERAL_TYPE:
>      case BOOLEAN_TYPE:
>      case OFFSET_TYPE:
> +    case BITINT_TYPE:
>        /* If this is a logical operation, which just returns 0 or 1, we can
>  	 change the type of the expression.  */
>  
> @@ -701,7 +704,9 @@ convert_to_integer_1 (tree type, tree ex
>  	 type corresponding to its mode, then do a nop conversion
>  	 to TYPE.  */
>        else if (TREE_CODE (type) == ENUMERAL_TYPE
> -	       || maybe_ne (outprec, GET_MODE_PRECISION (TYPE_MODE (type))))
> +	       || (TREE_CODE (type) != BITINT_TYPE
> +		   && maybe_ne (outprec,
> +				GET_MODE_PRECISION (TYPE_MODE (type)))))
>  	{
>  	  expr
>  	    = convert_to_integer_1 (lang_hooks.types.type_for_mode
> @@ -1000,6 +1005,7 @@ convert_to_complex_1 (tree type, tree ex
>      case INTEGER_TYPE:
>      case ENUMERAL_TYPE:
>      case BOOLEAN_TYPE:
> +    case BITINT_TYPE:
>        return build2 (COMPLEX_EXPR, type, convert (subtype, expr),
>  		     convert (subtype, integer_zero_node));
>  
> --- gcc/doc/generic.texi.jj	2023-06-07 09:42:14.593131807 +0200
> +++ gcc/doc/generic.texi	2023-08-08 17:04:48.062612388 +0200
> @@ -290,6 +290,7 @@ The elements are indexed from zero.
>  @tindex INTEGER_TYPE
>  @tindex TYPE_MIN_VALUE
>  @tindex TYPE_MAX_VALUE
> +@tindex BITINT_TYPE
>  @tindex REAL_TYPE
>  @tindex FIXED_POINT_TYPE
>  @tindex COMPLEX_TYPE
> @@ -449,6 +450,14 @@ integer that may be represented by this
>  @code{TYPE_MAX_VALUE} is an @code{INTEGER_CST} for the largest integer
>  that may be represented by this type.
>  
> +@item BITINT_TYPE
> +Used to represent the bit-precise integer types, @code{_BitInt(@var{N})}.
> +These types are similar to @code{INTEGER_TYPE}, but can have arbitrary
> +user selected precisions and do or can have different alignment, function
> +argument and return value passing conventions.
> +Larger BITINT_TYPEs can have @code{BLKmode} @code{TYPE_MODE} and need to
> +be lowered by a special BITINT_TYPE lowering pass.
> +
>  @item REAL_TYPE
>  Used to represent the @code{float}, @code{double}, and @code{long
>  double} types.  The number of bits in the floating-point representation
> --- gcc/doc/tm.texi.in.jj	2023-08-08 15:54:34.156617482 +0200
> +++ gcc/doc/tm.texi.in	2023-08-08 16:12:02.309940077 +0200
> @@ -936,6 +936,8 @@ Return a value, with the same meaning as
>  @code{FLT_EVAL_METHOD} that describes which excess precision should be
>  applied.
>  
> +@hook TARGET_C_BITINT_TYPE_INFO
> +
>  @hook TARGET_PROMOTE_FUNCTION_MODE
>  
>  @defmac PARM_BOUNDARY
> --- gcc/doc/tm.texi.jj	2023-08-08 15:54:34.090618406 +0200
> +++ gcc/doc/tm.texi	2023-08-08 19:24:12.438581403 +0200
> @@ -1020,6 +1020,21 @@ Return a value, with the same meaning as
>  @code{FLT_EVAL_METHOD} that describes which excess precision should be
>  applied.
>  
> +@deftypefn {Target Hook} bool TARGET_C_BITINT_TYPE_INFO (int @var{n}, struct bitint_info *@var{info})
> +This target hook returns true if @code{_BitInt(@var{N})} is supported and
> +provides details on it.  @code{_BitInt(@var{N})} is to be represented as
> +series of @code{info->limb_mode}
> +@code{CEIL (@var{N}, GET_MODE_PRECISION (info->limb_mode))} limbs,
> +ordered from least significant to most significant if
> +@code{!info->big_endian}, otherwise from most significant to least
> +significant.  If @code{info->extended} is false, the bits above or equal to
> +@var{N} are undefined when stored in a register or memory, otherwise they
> +are zero or sign extended depending on if it is
> +@code{unsigned _BitInt(@var{N})} or one of @code{_BitInt(@var{N})} or
> +@code{signed _BitInt(@var{N})}.  Alignment of the type is
> +@code{GET_MODE_ALIGNMENT (info->limb_mode)}.
> +@end deftypefn
> +
>  @deftypefn {Target Hook} machine_mode TARGET_PROMOTE_FUNCTION_MODE (const_tree @var{type}, machine_mode @var{mode}, int *@var{punsignedp}, const_tree @var{funtype}, int @var{for_return})
>  Like @code{PROMOTE_MODE}, but it is applied to outgoing function arguments or
>  function return values.  The target hook should return the new mode
> --- gcc/dwarf2out.cc.jj	2023-08-08 15:55:06.471164947 +0200
> +++ gcc/dwarf2out.cc	2023-08-08 19:06:17.624644391 +0200
> @@ -13298,6 +13298,14 @@ base_type_die (tree type, bool reverse)
>        encoding = DW_ATE_boolean;
>        break;
>  
> +    case BITINT_TYPE:
> +      /* C23 _BitInt(N).  */
> +      if (TYPE_UNSIGNED (type))
> +	encoding = DW_ATE_unsigned;
> +      else
> +	encoding = DW_ATE_signed;
> +      break;
> +
>      default:
>        /* No other TREE_CODEs are Dwarf fundamental types.  */
>        gcc_unreachable ();
> @@ -13308,6 +13316,8 @@ base_type_die (tree type, bool reverse)
>    add_AT_unsigned (base_type_result, DW_AT_byte_size,
>  		   int_size_in_bytes (type));
>    add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
> +  if (TREE_CODE (type) == BITINT_TYPE)
> +    add_AT_unsigned (base_type_result, DW_AT_bit_size, TYPE_PRECISION (type));
>  
>    if (need_endianity_attribute_p (reverse))
>      add_AT_unsigned (base_type_result, DW_AT_endianity,
> @@ -13392,6 +13402,7 @@ is_base_type (tree type)
>      case FIXED_POINT_TYPE:
>      case COMPLEX_TYPE:
>      case BOOLEAN_TYPE:
> +    case BITINT_TYPE:
>        return true;
>  
>      case VOID_TYPE:
> @@ -13990,12 +14001,24 @@ modified_type_die (tree type, int cv_qua
>  	name = DECL_NAME (name);
>        add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name));
>      }
> -  /* This probably indicates a bug.  */
>    else if (mod_type_die && mod_type_die->die_tag == DW_TAG_base_type)
>      {
> -      name = TYPE_IDENTIFIER (type);
> -      add_name_attribute (mod_type_die,
> -			  name ? IDENTIFIER_POINTER (name) : "__unknown__");
> +      if (TREE_CODE (type) == BITINT_TYPE)
> +	{
> +	  char name_buf[sizeof ("unsigned _BitInt(2147483647)")];
> +	  snprintf (name_buf, sizeof (name_buf),
> +		    "%s_BitInt(%d)", TYPE_UNSIGNED (type) ? "unsigned " : "",
> +		    TYPE_PRECISION (type));
> +	  add_name_attribute (mod_type_die, name_buf);
> +	}
> +      else
> +	{
> +	  /* This probably indicates a bug.  */
> +	  name = TYPE_IDENTIFIER (type);
> +	  add_name_attribute (mod_type_die,
> +			      name
> +			      ? IDENTIFIER_POINTER (name) : "__unknown__");
> +	}
>      }
>  
>    if (qualified_type && !reverse_base_type)
> @@ -20523,6 +20546,17 @@ rtl_for_decl_init (tree init, tree type)
>  	    return NULL;
>  	  }
>  
> +      /* Large _BitInt BLKmode INTEGER_CSTs would yield a MEM.  */
> +      if (TREE_CODE (init) == INTEGER_CST
> +	  && TREE_CODE (TREE_TYPE (init)) == BITINT_TYPE
> +	  && TYPE_MODE (TREE_TYPE (init)) == BLKmode)
> +	{
> +	  if (tree_fits_shwi_p (init))
> +	    return GEN_INT (tree_to_shwi (init));
> +	  else
> +	    return NULL;
> +	}
> +
>        rtl = expand_expr (init, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
>  
>        /* If expand_expr returns a MEM, it wasn't immediate.  */
> @@ -26361,6 +26395,7 @@ gen_type_die_with_usage (tree type, dw_d
>      case FIXED_POINT_TYPE:
>      case COMPLEX_TYPE:
>      case BOOLEAN_TYPE:
> +    case BITINT_TYPE:
>        /* No DIEs needed for fundamental types.  */
>        break;
>  
> --- gcc/expr.cc.jj	2023-08-08 16:02:52.837633995 +0200
> +++ gcc/expr.cc	2023-08-09 10:30:13.524295673 +0200
> @@ -10650,6 +10650,25 @@ expand_expr_real_1 (tree exp, rtx target
>    tree ssa_name = NULL_TREE;
>    gimple *g;
>  
> +  /* Some ABIs define padding bits in _BitInt uninitialized.  Normally, RTL
> +     expansion sign/zero extends integral types with less than mode precision
> +     when reading from bit-fields and after arithmetic operations (see
> +     REDUCE_BIT_FIELD in expand_expr_real_2) and on subsequent loads relies
> +     on those extensions to have been already performed, but because of the
> +     above for _BitInt they need to be sign/zero extended when reading from
> +     locations that could be exposed to ABI boundaries (when loading from
> +     objects in memory, or function arguments, return value).  Because we
> +     internally extend after arithmetic operations, we can avoid doing that
> +     when reading from SSA_NAMEs of vars.  */
> +#define EXTEND_BITINT(expr) \
> +  ((TREE_CODE (type) == BITINT_TYPE					\
> +    && reduce_bit_field							\
> +    && mode != BLKmode							\
> +    && modifier != EXPAND_MEMORY					\
> +    && modifier != EXPAND_WRITE						\
> +    && modifier != EXPAND_CONST_ADDRESS)				\
> +   ? reduce_to_bit_field_precision ((expr), NULL_RTX, type) : (expr))
> +
>    type = TREE_TYPE (exp);
>    mode = TYPE_MODE (type);
>    unsignedp = TYPE_UNSIGNED (type);
> @@ -10823,6 +10842,13 @@ expand_expr_real_1 (tree exp, rtx target
>        ssa_name = exp;
>        decl_rtl = get_rtx_for_ssa_name (ssa_name);
>        exp = SSA_NAME_VAR (ssa_name);
> +      /* Optimize and avoid to EXTEND_BITINIT doing anything if it is an
> +	 SSA_NAME computed within the current function.  In such case the
> +	 value have been already extended before.  While if it is a function
> +	 parameter, result or some memory location, we need to be prepared
> +	 for some other compiler leaving the bits uninitialized.  */
> +      if (!exp || VAR_P (exp))
> +	reduce_bit_field = false;
>        goto expand_decl_rtl;
>  
>      case VAR_DECL:
> @@ -10956,7 +10982,7 @@ expand_expr_real_1 (tree exp, rtx target
>  	    temp = expand_misaligned_mem_ref (temp, mode, unsignedp,
>  					      MEM_ALIGN (temp), NULL_RTX, NULL);
>  
> -	  return temp;
> +	  return EXTEND_BITINT (temp);
>  	}
>  
>        if (exp)
> @@ -11002,13 +11028,35 @@ expand_expr_real_1 (tree exp, rtx target
>  	  temp = gen_lowpart_SUBREG (mode, decl_rtl);
>  	  SUBREG_PROMOTED_VAR_P (temp) = 1;
>  	  SUBREG_PROMOTED_SET (temp, unsignedp);
> -	  return temp;
> +	  return EXTEND_BITINT (temp);
>  	}
>  
> -      return decl_rtl;
> +      return EXTEND_BITINT (decl_rtl);
>  
>      case INTEGER_CST:
>        {
> +	if (TREE_CODE (type) == BITINT_TYPE)
> +	  {
> +	    unsigned int prec = TYPE_PRECISION (type);
> +	    struct bitint_info info;
> +	    gcc_assert (targetm.c.bitint_type_info (prec, &info));
> +	    scalar_int_mode limb_mode
> +	      = as_a <scalar_int_mode> (info.limb_mode);
> +	    unsigned int limb_prec = GET_MODE_PRECISION (limb_mode);
> +	    if (prec > limb_prec)
> +	      {
> +		scalar_int_mode arith_mode
> +		  = (targetm.scalar_mode_supported_p (TImode)
> +		     ? TImode : DImode);
> +		if (prec > GET_MODE_PRECISION (arith_mode))
> +		  {
> +		    /* Emit large/huge _BitInt INTEGER_CSTs into memory.  */
> +		    exp = tree_output_constant_def (exp);
> +		    return expand_expr (exp, target, VOIDmode, modifier);
> +		  }
> +	      }
> +	  }
> +
>  	/* Given that TYPE_PRECISION (type) is not always equal to
>  	   GET_MODE_PRECISION (TYPE_MODE (type)), we need to extend from
>  	   the former to the latter according to the signedness of the
> @@ -11187,7 +11235,7 @@ expand_expr_real_1 (tree exp, rtx target
>  	    && align < GET_MODE_ALIGNMENT (mode))
>  	  temp = expand_misaligned_mem_ref (temp, mode, unsignedp,
>  					    align, NULL_RTX, NULL);
> -	return temp;
> +	return EXTEND_BITINT (temp);
>        }
>  
>      case MEM_REF:
> @@ -11258,7 +11306,7 @@ expand_expr_real_1 (tree exp, rtx target
>  					    ? NULL_RTX : target, alt_rtl);
>  	if (reverse)
>  	  temp = flip_storage_order (mode, temp);
> -	return temp;
> +	return EXTEND_BITINT (temp);
>        }
>  
>      case ARRAY_REF:
> @@ -11810,6 +11858,8 @@ expand_expr_real_1 (tree exp, rtx target
>  	    && modifier != EXPAND_WRITE)
>  	  op0 = flip_storage_order (mode1, op0);
>  
> +	op0 = EXTEND_BITINT (op0);
> +
>  	if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
>  	    || modifier == EXPAND_CONST_ADDRESS
>  	    || modifier == EXPAND_INITIALIZER)
> @@ -12155,6 +12205,7 @@ expand_expr_real_1 (tree exp, rtx target
>        return expand_expr_real_2 (&ops, target, tmode, modifier);
>      }
>  }
> +#undef EXTEND_BITINT
>  \f
>  /* Subroutine of above: reduce EXP to the precision of TYPE (in the
>     signedness of TYPE), possibly returning the result in TARGET.
> --- gcc/fold-const.cc.jj	2023-08-08 15:55:06.507164442 +0200
> +++ gcc/fold-const.cc	2023-08-08 16:12:02.318939952 +0200
> @@ -2557,7 +2557,7 @@ fold_convert_loc (location_t loc, tree t
>        /* fall through */
>  
>      case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
> -    case OFFSET_TYPE:
> +    case OFFSET_TYPE: case BITINT_TYPE:
>        if (TREE_CODE (arg) == INTEGER_CST)
>  	{
>  	  tem = fold_convert_const (NOP_EXPR, type, arg);
> @@ -2597,7 +2597,7 @@ fold_convert_loc (location_t loc, tree t
>  
>        switch (TREE_CODE (orig))
>  	{
> -	case INTEGER_TYPE:
> +	case INTEGER_TYPE: case BITINT_TYPE:
>  	case BOOLEAN_TYPE: case ENUMERAL_TYPE:
>  	case POINTER_TYPE: case REFERENCE_TYPE:
>  	  return fold_build1_loc (loc, FLOAT_EXPR, type, arg);
> @@ -2632,6 +2632,7 @@ fold_convert_loc (location_t loc, tree t
>  	case ENUMERAL_TYPE:
>  	case BOOLEAN_TYPE:
>  	case REAL_TYPE:
> +	case BITINT_TYPE:
>  	  return fold_build1_loc (loc, FIXED_CONVERT_EXPR, type, arg);
>  
>  	case COMPLEX_TYPE:
> @@ -2645,7 +2646,7 @@ fold_convert_loc (location_t loc, tree t
>      case COMPLEX_TYPE:
>        switch (TREE_CODE (orig))
>  	{
> -	case INTEGER_TYPE:
> +	case INTEGER_TYPE: case BITINT_TYPE:
>  	case BOOLEAN_TYPE: case ENUMERAL_TYPE:
>  	case POINTER_TYPE: case REFERENCE_TYPE:
>  	case REAL_TYPE:
> @@ -5324,6 +5325,8 @@ make_range_step (location_t loc, enum tr
>  	    equiv_type
>  	      = lang_hooks.types.type_for_mode (TYPE_MODE (arg0_type),
>  						TYPE_SATURATING (arg0_type));
> +	  else if (TREE_CODE (arg0_type) == BITINT_TYPE)
> +	    equiv_type = arg0_type;
>  	  else
>  	    equiv_type
>  	      = lang_hooks.types.type_for_mode (TYPE_MODE (arg0_type), 1);
> @@ -6850,10 +6853,19 @@ extract_muldiv_1 (tree t, tree c, enum t
>  {
>    tree type = TREE_TYPE (t);
>    enum tree_code tcode = TREE_CODE (t);
> -  tree ctype = (wide_type != 0
> -		&& (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (wide_type))
> -		    > GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type)))
> -		? wide_type : type);
> +  tree ctype = type;
> +  if (wide_type)
> +    {
> +      if (TREE_CODE (type) == BITINT_TYPE
> +	  || TREE_CODE (wide_type) == BITINT_TYPE)
> +	{
> +	  if (TYPE_PRECISION (wide_type) > TYPE_PRECISION (type))
> +	    ctype = wide_type;
> +	}
> +      else if (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (wide_type))
> +	       > GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type)))
> +	ctype = wide_type;
> +    }
>    tree t1, t2;
>    bool same_p = tcode == code;
>    tree op0 = NULL_TREE, op1 = NULL_TREE;
> @@ -7714,7 +7726,29 @@ static int
>  native_encode_int (const_tree expr, unsigned char *ptr, int len, int off)
>  {
>    tree type = TREE_TYPE (expr);
> -  int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
> +  int total_bytes;
> +  if (TREE_CODE (type) == BITINT_TYPE)
> +    {
> +      struct bitint_info info;
> +      gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
> +					      &info));
> +      scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
> +      if (TYPE_PRECISION (type) > GET_MODE_PRECISION (limb_mode))
> +	{
> +	  total_bytes = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> +	  /* More work is needed when adding _BitInt support to PDP endian
> +	     if limb is smaller than word, or if _BitInt limb ordering doesn't
> +	     match target endianity here.  */
> +	  gcc_checking_assert (info.big_endian == WORDS_BIG_ENDIAN
> +			       && (BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
> +				   || (GET_MODE_SIZE (limb_mode)
> +				       >= UNITS_PER_WORD)));
> +	}
> +      else
> +	total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
> +    }
> +  else
> +    total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
>    int byte, offset, word, words;
>    unsigned char value;
>  
> @@ -8622,7 +8656,29 @@ native_encode_initializer (tree init, un
>  static tree
>  native_interpret_int (tree type, const unsigned char *ptr, int len)
>  {
> -  int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
> +  int total_bytes;
> +  if (TREE_CODE (type) == BITINT_TYPE)
> +    {
> +      struct bitint_info info;
> +      gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
> +					      &info));
> +      scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
> +      if (TYPE_PRECISION (type) > GET_MODE_PRECISION (limb_mode))
> +	{
> +	  total_bytes = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> +	  /* More work is needed when adding _BitInt support to PDP endian
> +	     if limb is smaller than word, or if _BitInt limb ordering doesn't
> +	     match target endianity here.  */
> +	  gcc_checking_assert (info.big_endian == WORDS_BIG_ENDIAN
> +			       && (BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
> +				   || (GET_MODE_SIZE (limb_mode)
> +				       >= UNITS_PER_WORD)));
> +	}
> +      else
> +	total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
> +    }
> +  else
> +    total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
>  
>    if (total_bytes > len
>        || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
> @@ -8824,6 +8880,7 @@ native_interpret_expr (tree type, const
>      case POINTER_TYPE:
>      case REFERENCE_TYPE:
>      case OFFSET_TYPE:
> +    case BITINT_TYPE:
>        return native_interpret_int (type, ptr, len);
>  
>      case REAL_TYPE:
> --- gcc/gimple-expr.cc.jj	2023-08-08 15:54:34.369614499 +0200
> +++ gcc/gimple-expr.cc	2023-08-08 16:12:02.318939952 +0200
> @@ -111,6 +111,15 @@ useless_type_conversion_p (tree outer_ty
>  	  && TYPE_PRECISION (outer_type) != 1)
>  	return false;
>  
> +      /* Preserve conversions to/from BITINT_TYPE.  While we don't
> +	 need to care that much about such conversions within a function's
> +	 body, we need to prevent changing BITINT_TYPE to INTEGER_TYPE
> +	 of the same precision or vice versa when passed to functions,
> +	 especially for varargs.  */
> +      if ((TREE_CODE (inner_type) == BITINT_TYPE)
> +	  != (TREE_CODE (outer_type) == BITINT_TYPE))
> +	return false;
> +
>        /* We don't need to preserve changes in the types minimum or
>  	 maximum value in general as these do not generate code
>  	 unless the types precisions are different.  */
> --- gcc/gimple-fold.cc.jj	2023-08-08 15:55:06.609163014 +0200
> +++ gcc/gimple-fold.cc	2023-08-08 16:18:44.828303852 +0200
> @@ -1475,8 +1475,9 @@ gimple_fold_builtin_memset (gimple_stmt_
>    if (TREE_CODE (etype) == ARRAY_TYPE)
>      etype = TREE_TYPE (etype);
>  
> -  if (!INTEGRAL_TYPE_P (etype)
> -      && !POINTER_TYPE_P (etype))
> +  if ((!INTEGRAL_TYPE_P (etype)
> +       && !POINTER_TYPE_P (etype))
> +      || TREE_CODE (etype) == BITINT_TYPE)
>      return NULL_TREE;
>  
>    if (! var_decl_component_p (var))
> @@ -4102,8 +4103,8 @@ gimple_fold_builtin_realloc (gimple_stmt
>    return false;
>  }
>  
> -/* Number of bytes into which any type but aggregate or vector types
> -   should fit.  */
> +/* Number of bytes into which any type but aggregate, vector or
> +   _BitInt types should fit.  */
>  static constexpr size_t clear_padding_unit
>    = MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT;
>  /* Buffer size on which __builtin_clear_padding folding code works.  */
> @@ -4594,6 +4595,26 @@ clear_padding_real_needs_padding_p (tree
>  	  && (fmt->signbit_ro == 79 || fmt->signbit_ro == 95));
>  }
>  
> +/* _BitInt has padding bits if it isn't extended in the ABI and has smaller
> +   precision than bits in limb or corresponding number of limbs.  */
> +
> +static bool
> +clear_padding_bitint_needs_padding_p (tree type)
> +{
> +  struct bitint_info info;
> +  gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
> +  if (info.extended)
> +    return false;
> +  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
> +  if (TYPE_PRECISION (type) < GET_MODE_PRECISION (limb_mode))
> +    return true;
> +  else if (TYPE_PRECISION (type) == GET_MODE_PRECISION (limb_mode))
> +    return false;
> +  else
> +    return (((unsigned) TYPE_PRECISION (type))
> +	    % GET_MODE_PRECISION (limb_mode)) != 0;
> +}
> +
>  /* Return true if TYPE might contain any padding bits.  */
>  
>  bool
> @@ -4610,6 +4631,8 @@ clear_padding_type_may_have_padding_p (t
>        return clear_padding_type_may_have_padding_p (TREE_TYPE (type));
>      case REAL_TYPE:
>        return clear_padding_real_needs_padding_p (type);
> +    case BITINT_TYPE:
> +      return clear_padding_bitint_needs_padding_p (type);
>      default:
>        return false;
>      }
> @@ -4854,6 +4877,57 @@ clear_padding_type (clear_padding_struct
>        memset (buf->buf + buf->size, ~0, sz);
>        buf->size += sz;
>        break;
> +    case BITINT_TYPE:
> +      {
> +	struct bitint_info info;
> +	gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
> +	scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
> +	if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
> +	  {
> +	    gcc_assert ((size_t) sz <= clear_padding_unit);
> +	    if ((unsigned HOST_WIDE_INT) sz + buf->size
> +		> clear_padding_buf_size)
> +	      clear_padding_flush (buf, false);
> +	    if (!info.extended
> +		&& TYPE_PRECISION (type) < GET_MODE_PRECISION (limb_mode))
> +	      {
> +		int tprec = GET_MODE_PRECISION (limb_mode);
> +		int prec = TYPE_PRECISION (type);
> +		tree t = build_nonstandard_integer_type (tprec, 1);
> +		tree cst = wide_int_to_tree (t, wi::mask (prec, true, tprec));
> +		int len = native_encode_expr (cst, buf->buf + buf->size, sz);
> +		gcc_assert (len > 0 && (size_t) len == (size_t) sz);
> +	      }
> +	    else
> +	      memset (buf->buf + buf->size, 0, sz);
> +	    buf->size += sz;
> +	    break;
> +	  }
> +	tree limbtype
> +	  = build_nonstandard_integer_type (GET_MODE_PRECISION (limb_mode), 1);
> +	fldsz = int_size_in_bytes (limbtype);
> +	nelts = int_size_in_bytes (type) / fldsz;
> +	for (HOST_WIDE_INT i = 0; i < nelts; i++)
> +	  {
> +	    if (!info.extended
> +		&& i == (info.big_endian ? 0 : nelts - 1)
> +		&& (((unsigned) TYPE_PRECISION (type))
> +		    % TYPE_PRECISION (limbtype)) != 0)
> +	      {
> +		int tprec = GET_MODE_PRECISION (limb_mode);
> +		int prec = (((unsigned) TYPE_PRECISION (type)) % tprec);
> +		tree cst = wide_int_to_tree (limbtype,
> +					     wi::mask (prec, true, tprec));
> +		int len = native_encode_expr (cst, buf->buf + buf->size,
> +					      fldsz);
> +		gcc_assert (len > 0 && (size_t) len == (size_t) fldsz);
> +		buf->size += fldsz;
> +	      }
> +	    else
> +	      clear_padding_type (buf, limbtype, fldsz, for_auto_init);
> +	  }
> +	break;
> +      }
>      default:
>        gcc_assert ((size_t) sz <= clear_padding_unit);
>        if ((unsigned HOST_WIDE_INT) sz + buf->size > clear_padding_buf_size)
> --- gcc/internal-fn.cc.jj	2023-08-08 15:55:06.709161614 +0200
> +++ gcc/internal-fn.cc	2023-08-08 16:22:09.404440148 +0200
> @@ -1646,6 +1676,12 @@ expand_mul_overflow (location_t loc, tre
>  
>    int pos_neg0 = get_range_pos_neg (arg0);
>    int pos_neg1 = get_range_pos_neg (arg1);
> +  /* Unsigned types with smaller than mode precision, even if they have most
> +     significant bit set, are still zero-extended.  */
> +  if (uns0_p && TYPE_PRECISION (TREE_TYPE (arg0)) < GET_MODE_PRECISION (mode))
> +    pos_neg0 = 1;
> +  if (uns1_p && TYPE_PRECISION (TREE_TYPE (arg1)) < GET_MODE_PRECISION (mode))
> +    pos_neg1 = 1;
>  
>    /* s1 * u2 -> ur  */
>    if (!uns0_p && uns1_p && unsr_p)
> @@ -4923,3 +4959,104 @@ expand_MASK_CALL (internal_fn, gcall *)
>    /* This IFN should only exist between ifcvt and vect passes.  */
>    gcc_unreachable ();
>  }
> +
> +void
> +expand_MULBITINT (internal_fn, gcall *stmt)
> +{
> +  rtx_mode_t args[6];
> +  for (int i = 0; i < 6; i++)
> +    args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
> +			  (i & 1) ? SImode : ptr_mode);
> +  rtx fun = init_one_libfunc ("__mulbitint3");
> +  emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 6, args);
> +}
> +
> +void
> +expand_DIVMODBITINT (internal_fn, gcall *stmt)
> +{
> +  rtx_mode_t args[8];
> +  for (int i = 0; i < 8; i++)
> +    args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
> +			  (i & 1) ? SImode : ptr_mode);
> +  rtx fun = init_one_libfunc ("__divmodbitint4");
> +  emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 8, args);
> +}
> +
> +void
> +expand_FLOATTOBITINT (internal_fn, gcall *stmt)
> +{
> +  machine_mode mode = TYPE_MODE (TREE_TYPE (gimple_call_arg (stmt, 2)));
> +  rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
> +  rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
> +  rtx arg2 = expand_normal (gimple_call_arg (stmt, 2));
> +  const char *mname = GET_MODE_NAME (mode);
> +  unsigned mname_len = strlen (mname);
> +  int len = 12 + mname_len;
> +  if (DECIMAL_FLOAT_MODE_P (mode))
> +    len += 4;
> +  char *libfunc_name = XALLOCAVEC (char, len);
> +  char *p = libfunc_name;
> +  const char *q;
> +  if (DECIMAL_FLOAT_MODE_P (mode))
> +    {
> +#if ENABLE_DECIMAL_BID_FORMAT
> +      memcpy (p, "__bid_fix", 9);
> +#else
> +      memcpy (p, "__dpd_fix", 9);
> +#endif
> +      p += 9;
> +    }
> +  else
> +    {
> +      memcpy (p, "__fix", 5);
> +      p += 5;
> +    }
> +  for (q = mname; *q; q++)
> +    *p++ = TOLOWER (*q);
> +  memcpy (p, "bitint", 7);
> +  rtx fun = init_one_libfunc (libfunc_name);
> +  emit_library_call (fun, LCT_NORMAL, VOIDmode, arg0, ptr_mode, arg1,
> +		     SImode, arg2, mode);
> +}
> +
> +void
> +expand_BITINTTOFLOAT (internal_fn, gcall *stmt)
> +{
> +  tree lhs = gimple_call_lhs (stmt);
> +  if (!lhs)
> +    return;
> +  machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
> +  rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
> +  rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
> +  const char *mname = GET_MODE_NAME (mode);
> +  unsigned mname_len = strlen (mname);
> +  int len = 14 + mname_len;
> +  if (DECIMAL_FLOAT_MODE_P (mode))
> +    len += 4;
> +  char *libfunc_name = XALLOCAVEC (char, len);
> +  char *p = libfunc_name;
> +  const char *q;
> +  if (DECIMAL_FLOAT_MODE_P (mode))
> +    {
> +#if ENABLE_DECIMAL_BID_FORMAT
> +      memcpy (p, "__bid_floatbitint", 17);
> +#else
> +      memcpy (p, "__dpd_floatbitint", 17);
> +#endif
> +      p += 17;
> +    }
> +  else
> +    {
> +      memcpy (p, "__floatbitint", 13);
> +      p += 13;
> +    }
> +  for (q = mname; *q; q++)
> +    *p++ = TOLOWER (*q);
> +  *p = '\0';
> +  rtx fun = init_one_libfunc (libfunc_name);
> +  rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +  rtx val = emit_library_call_value (fun, target, LCT_PURE, mode,
> +				     arg0, ptr_mode, arg1, SImode);
> +  if (val != target)
> +    emit_move_insn (target, val);
> +}
> --- gcc/internal-fn.def.jj	2023-08-08 15:55:06.710161600 +0200
> +++ gcc/internal-fn.def	2023-08-08 16:12:02.322939896 +0200
> @@ -548,6 +548,12 @@ DEF_INTERNAL_FN (ASSUME, ECF_CONST | ECF
>  /* For if-conversion of inbranch SIMD clones.  */
>  DEF_INTERNAL_FN (MASK_CALL, ECF_NOVOPS, NULL)
>  
> +/* _BitInt support.  */
> +DEF_INTERNAL_FN (MULBITINT, ECF_LEAF | ECF_NOTHROW, ". O . R . R . ")
> +DEF_INTERNAL_FN (DIVMODBITINT, ECF_LEAF, ". O . O . R . R . ")
> +DEF_INTERNAL_FN (FLOATTOBITINT, ECF_LEAF | ECF_NOTHROW, ". O . . ")
> +DEF_INTERNAL_FN (BITINTTOFLOAT, ECF_PURE | ECF_LEAF, ". R . ")
> +
>  #undef DEF_INTERNAL_INT_FN
>  #undef DEF_INTERNAL_FLT_FN
>  #undef DEF_INTERNAL_FLT_FLOATN_FN
> --- gcc/internal-fn.h.jj	2023-08-08 15:55:06.710161600 +0200
> +++ gcc/internal-fn.h	2023-08-08 16:12:02.322939896 +0200
> @@ -257,6 +257,10 @@ extern void expand_SPACESHIP (internal_f
>  extern void expand_TRAP (internal_fn, gcall *);
>  extern void expand_ASSUME (internal_fn, gcall *);
>  extern void expand_MASK_CALL (internal_fn, gcall *);
> +extern void expand_MULBITINT (internal_fn, gcall *);
> +extern void expand_DIVMODBITINT (internal_fn, gcall *);
> +extern void expand_FLOATTOBITINT (internal_fn, gcall *);
> +extern void expand_BITINTTOFLOAT (internal_fn, gcall *);
>  
>  extern bool vectorized_internal_fn_supported_p (internal_fn, tree);
>  
> --- gcc/match.pd.jj	2023-08-08 15:55:07.057156740 +0200
> +++ gcc/match.pd	2023-08-08 16:12:02.323939882 +0200
> @@ -6557,6 +6557,7 @@ (define_operator_list SYNC_FETCH_AND_AND
>  						      - 1)); }))))
>       (if (wi::to_wide (cst) == signed_max
>  	  && TYPE_UNSIGNED (arg1_type)
> +	  && TYPE_MODE (arg1_type) != BLKmode
>  	  /* We will flip the signedness of the comparison operator
>  	     associated with the mode of @1, so the sign bit is
>  	     specified by this mode.  Check that @1 is the signed
> --- gcc/pretty-print.h.jj	2023-08-08 15:54:34.806608379 +0200
> +++ gcc/pretty-print.h	2023-08-08 16:12:02.324939868 +0200
> @@ -336,8 +336,23 @@ pp_get_prefix (const pretty_printer *pp)
>  #define pp_wide_int(PP, W, SGN)					\
>    do								\
>      {								\
> -      print_dec (W, pp_buffer (PP)->digit_buffer, SGN);		\
> -      pp_string (PP, pp_buffer (PP)->digit_buffer);		\
> +      const wide_int_ref &pp_wide_int_ref = (W);		\
> +      unsigned int pp_wide_int_prec				\
> +	= pp_wide_int_ref.get_precision ();			\
> +      if ((pp_wide_int_prec + 3) / 4				\
> +	  > sizeof (pp_buffer (PP)->digit_buffer) - 3)		\
> +	{							\
> +	  char *pp_wide_int_buf					\
> +	    = XALLOCAVEC (char, (pp_wide_int_prec + 3) / 4 + 3);\
> +	  print_dec (pp_wide_int_ref, pp_wide_int_buf, SGN);	\
> +	  pp_string (PP, pp_wide_int_buf);			\
> +	}							\
> +      else							\
> +	{							\
> +	  print_dec (pp_wide_int_ref,				\
> +		     pp_buffer (PP)->digit_buffer, SGN);	\
> +	  pp_string (PP, pp_buffer (PP)->digit_buffer);		\
> +	}							\
>      }								\
>    while (0)
>  #define pp_vrange(PP, R)					\
> --- gcc/stor-layout.cc.jj	2023-08-08 15:54:34.855607692 +0200
> +++ gcc/stor-layout.cc	2023-08-08 16:15:41.003877836 +0200
> @@ -2148,6 +2148,22 @@ finish_bitfield_representative (tree rep
>        || GET_MODE_BITSIZE (mode) > maxbitsize
>        || GET_MODE_BITSIZE (mode) > MAX_FIXED_MODE_SIZE)
>      {
> +      if (TREE_CODE (TREE_TYPE (field)) == BITINT_TYPE)
> +	{
> +	  struct bitint_info info;
> +	  unsigned prec = TYPE_PRECISION (TREE_TYPE (field));
> +	  gcc_assert (targetm.c.bitint_type_info (prec, &info));
> +	  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
> +	  unsigned lprec = GET_MODE_PRECISION (limb_mode);
> +	  if (prec > lprec)
> +	    {
> +	      /* For middle/large/huge _BitInt prefer bitsize being a multiple
> +		 of limb precision.  */
> +	      unsigned HOST_WIDE_INT bsz = CEIL (bitsize, lprec) * lprec;
> +	      if (bsz <= maxbitsize)
> +		bitsize = bsz;
> +	    }
> +	}
>        /* We really want a BLKmode representative only as a last resort,
>           considering the member b in
>  	   struct { int a : 7; int b : 17; int c; } __attribute__((packed));
> @@ -2393,6 +2409,64 @@ layout_type (tree type)
>  	break;
>        }
>  
> +    case BITINT_TYPE:
> +      {
> +	struct bitint_info info;
> +	int cnt;
> +	gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
> +	scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
> +	if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
> +	  {
> +	    SET_TYPE_MODE (type, limb_mode);
> +	    cnt = 1;
> +	  }
> +	else
> +	  {
> +	    SET_TYPE_MODE (type, BLKmode);
> +	    cnt = CEIL (TYPE_PRECISION (type), GET_MODE_PRECISION (limb_mode));
> +	  }
> +	TYPE_SIZE (type) = bitsize_int (cnt * GET_MODE_BITSIZE (limb_mode));
> +	TYPE_SIZE_UNIT (type) = size_int (cnt * GET_MODE_SIZE (limb_mode));
> +	SET_TYPE_ALIGN (type, GET_MODE_ALIGNMENT (limb_mode));
> +	if (cnt > 1)
> +	  {
> +	    /* Use same mode as compute_record_mode would use for a structure
> +	       containing cnt limb_mode elements.  */
> +	    machine_mode mode = mode_for_size_tree (TYPE_SIZE (type),
> +						    MODE_INT, 1).else_blk ();
> +	    if (mode == BLKmode)
> +	      break;
> +	    finalize_type_size (type);
> +	    SET_TYPE_MODE (type, mode);
> +	    if (STRICT_ALIGNMENT
> +		&& !(TYPE_ALIGN (type) >= BIGGEST_ALIGNMENT
> +		     || TYPE_ALIGN (type) >= GET_MODE_ALIGNMENT (mode)))
> +	      {
> +		/* If this is the only reason this type is BLKmode, then
> +		   don't force containing types to be BLKmode.  */
> +		TYPE_NO_FORCE_BLK (type) = 1;
> +		SET_TYPE_MODE (type, BLKmode);
> +	      }
> +	    if (TYPE_NEXT_VARIANT (type) || type != TYPE_MAIN_VARIANT (type))
> +	      for (tree variant = TYPE_MAIN_VARIANT (type);
> +		   variant != NULL_TREE;
> +		   variant = TYPE_NEXT_VARIANT (variant))
> +		{
> +		  SET_TYPE_MODE (variant, mode);
> +		  if (STRICT_ALIGNMENT
> +		      && !(TYPE_ALIGN (variant) >= BIGGEST_ALIGNMENT
> +			   || (TYPE_ALIGN (variant)
> +			       >= GET_MODE_ALIGNMENT (mode))))
> +		    {
> +		      TYPE_NO_FORCE_BLK (variant) = 1;
> +		      SET_TYPE_MODE (variant, BLKmode);
> +		    }
> +		}
> +	    return;
> +	  }
> +	break;
> +      }
> +
>      case REAL_TYPE:
>        {
>  	/* Allow the caller to choose the type mode, which is how decimal
> @@ -2417,6 +2491,18 @@ layout_type (tree type)
>  
>      case COMPLEX_TYPE:
>        TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
> +      if (TYPE_MODE (TREE_TYPE (type)) == BLKmode)
> +	{
> +	  gcc_checking_assert (TREE_CODE (TREE_TYPE (type)) == BITINT_TYPE);
> +	  SET_TYPE_MODE (type, BLKmode);
> +	  TYPE_SIZE (type)
> +	    = int_const_binop (MULT_EXPR, TYPE_SIZE (TREE_TYPE (type)),
> +			       bitsize_int (2));
> +	  TYPE_SIZE_UNIT (type)
> +	    = int_const_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (type)),
> +			       bitsize_int (2));
> +	  break;
> +	}
>        SET_TYPE_MODE (type,
>  		     GET_MODE_COMPLEX_MODE (TYPE_MODE (TREE_TYPE (type))));
>  
> --- gcc/target.def.jj	2023-08-08 15:54:34.860607622 +0200
> +++ gcc/target.def	2023-08-08 19:24:08.280639676 +0200
> @@ -6241,6 +6241,25 @@ when @var{type} is @code{EXCESS_PRECISIO
>   enum flt_eval_method, (enum excess_precision_type type),
>   default_excess_precision)
>  
> +/* Return true if _BitInt(N) is supported and fill details about it into
> +   *INFO.  */
> +DEFHOOK
> +(bitint_type_info,
> + "This target hook returns true if @code{_BitInt(@var{N})} is supported and\n\
> +provides details on it.  @code{_BitInt(@var{N})} is to be represented as\n\
> +series of @code{info->limb_mode}\n\
> +@code{CEIL (@var{N}, GET_MODE_PRECISION (info->limb_mode))} limbs,\n\
> +ordered from least significant to most significant if\n\
> +@code{!info->big_endian}, otherwise from most significant to least\n\
> +significant.  If @code{info->extended} is false, the bits above or equal to\n\
> +@var{N} are undefined when stored in a register or memory, otherwise they\n\
> +are zero or sign extended depending on if it is\n\
> +@code{unsigned _BitInt(@var{N})} or one of @code{_BitInt(@var{N})} or\n\
> +@code{signed _BitInt(@var{N})}.  Alignment of the type is\n\
> +@code{GET_MODE_ALIGNMENT (info->limb_mode)}.",
> + bool, (int n, struct bitint_info *info),
> + default_bitint_type_info)
> +
>  HOOK_VECTOR_END (c)
>  
>  /* Functions specific to the C++ frontend.  */
> --- gcc/target.h.jj	2023-08-08 15:54:34.903607020 +0200
> +++ gcc/target.h	2023-08-08 16:12:02.325939854 +0200
> @@ -68,6 +68,20 @@ union cumulative_args_t { void *p; };
>  
>  #endif /* !CHECKING_P */
>  
> +/* Target properties of _BitInt(N) type.  _BitInt(N) is to be represented
> +   as series of limb_mode CEIL (N, GET_MODE_PRECISION (limb_mode)) limbs,
> +   ordered from least significant to most significant if !big_endian,
> +   otherwise from most significant to least significant.  If extended is
> +   false, the bits above or equal to N are undefined when stored in a register
> +   or memory, otherwise they are zero or sign extended depending on if
> +   it is unsigned _BitInt(N) or _BitInt(N) / signed _BitInt(N).  */
> +
> +struct bitint_info {
> +  machine_mode limb_mode;
> +  bool big_endian;
> +  bool extended;
> +};
> +
>  /* Types of memory operation understood by the "by_pieces" infrastructure.
>     Used by the TARGET_USE_BY_PIECES_INFRASTRUCTURE_P target hook and
>     internally by the functions in expr.cc.  */
> --- gcc/targhooks.cc.jj	2023-08-08 15:54:34.954606306 +0200
> +++ gcc/targhooks.cc	2023-08-08 16:12:02.325939854 +0200
> @@ -2595,6 +2595,14 @@ default_excess_precision (enum excess_pr
>    return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT;
>  }
>  
> +/* Return true if _BitInt(N) is supported and fill details about it into
> +   *INFO.  */
> +bool
> +default_bitint_type_info (int, struct bitint_info *)
> +{
> +  return false;
> +}
> +
>  /* Default implementation for
>    TARGET_STACK_CLASH_PROTECTION_ALLOCA_PROBE_RANGE.  */
>  HOST_WIDE_INT
> --- gcc/targhooks.h.jj	2023-08-08 15:54:34.981605928 +0200
> +++ gcc/targhooks.h	2023-08-08 16:12:02.326939840 +0200
> @@ -284,6 +284,7 @@ extern unsigned int default_min_arithmet
>  
>  extern enum flt_eval_method
>  default_excess_precision (enum excess_precision_type ATTRIBUTE_UNUSED);
> +extern bool default_bitint_type_info (int, struct bitint_info *);
>  extern HOST_WIDE_INT default_stack_clash_protection_alloca_probe_range (void);
>  extern void default_select_early_remat_modes (sbitmap);
>  extern tree default_preferred_else_value (unsigned, tree, unsigned, tree *);
> --- gcc/tree-pretty-print.cc.jj	2023-08-08 15:54:35.084604486 +0200
> +++ gcc/tree-pretty-print.cc	2023-08-08 16:12:02.326939840 +0200
> @@ -1924,6 +1924,7 @@ dump_generic_node (pretty_printer *pp, t
>      case VECTOR_TYPE:
>      case ENUMERAL_TYPE:
>      case BOOLEAN_TYPE:
> +    case BITINT_TYPE:
>      case OPAQUE_TYPE:
>        {
>  	unsigned int quals = TYPE_QUALS (node);
> @@ -2038,6 +2039,14 @@ dump_generic_node (pretty_printer *pp, t
>  		pp_decimal_int (pp, TYPE_PRECISION (node));
>  		pp_greater (pp);
>  	      }
> +	    else if (TREE_CODE (node) == BITINT_TYPE)
> +	      {
> +		if (TYPE_UNSIGNED (node))
> +		  pp_string (pp, "unsigned ");
> +		pp_string (pp, "_BitInt(");
> +		pp_decimal_int (pp, TYPE_PRECISION (node));
> +		pp_right_paren (pp);
> +	      }
>  	    else if (TREE_CODE (node) == VOID_TYPE)
>  	      pp_string (pp, "void");
>  	    else
> @@ -2234,8 +2243,18 @@ dump_generic_node (pretty_printer *pp, t
>  	      pp_minus (pp);
>  	      val = -val;
>  	    }
> -	  print_hex (val, pp_buffer (pp)->digit_buffer);
> -	  pp_string (pp, pp_buffer (pp)->digit_buffer);
> +	  unsigned int prec = val.get_precision ();
> +	  if ((prec + 3) / 4 > sizeof (pp_buffer (pp)->digit_buffer) - 3)
> +	    {
> +	      char *buf = XALLOCAVEC (char, (prec + 3) / 4 + 3);
> +	      print_hex (val, buf);
> +	      pp_string (pp, buf);
> +	    }
> +	  else
> +	    {
> +	      print_hex (val, pp_buffer (pp)->digit_buffer);
> +	      pp_string (pp, pp_buffer (pp)->digit_buffer);
> +	    }
>  	}
>        if ((flags & TDF_GIMPLE)
>  	  && ! (POINTER_TYPE_P (TREE_TYPE (node))
> --- gcc/tree-ssa-sccvn.cc.jj	2023-08-08 15:55:09.533122067 +0200
> +++ gcc/tree-ssa-sccvn.cc	2023-08-08 16:12:02.328939812 +0200
> @@ -74,6 +74,7 @@ along with GCC; see the file COPYING3.
>  #include "ipa-modref-tree.h"
>  #include "ipa-modref.h"
>  #include "tree-ssa-sccvn.h"
> +#include "target.h"
>  
>  /* This algorithm is based on the SCC algorithm presented by Keith
>     Cooper and L. Taylor Simpson in "SCC-Based Value numbering"
> @@ -6969,8 +6970,14 @@ eliminate_dom_walker::eliminate_stmt (ba
>  	      || !DECL_BIT_FIELD_TYPE (TREE_OPERAND (lhs, 1)))
>  	  && !type_has_mode_precision_p (TREE_TYPE (lhs)))
>  	{
> -	  if (TREE_CODE (lhs) == COMPONENT_REF
> -	      || TREE_CODE (lhs) == MEM_REF)
> +	  if (TREE_CODE (TREE_TYPE (lhs)) == BITINT_TYPE
> +	      && (TYPE_PRECISION (TREE_TYPE (lhs))
> +		  > (targetm.scalar_mode_supported_p (TImode)
> +		     ? GET_MODE_PRECISION (TImode)
> +		     : GET_MODE_PRECISION (DImode))))
> +	    lookup_lhs = NULL_TREE;
> +	  else if (TREE_CODE (lhs) == COMPONENT_REF
> +		   || TREE_CODE (lhs) == MEM_REF)
>  	    {
>  	      tree ltype = build_nonstandard_integer_type
>  				(TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (lhs))),
> --- gcc/tree-switch-conversion.cc.jj	2023-08-08 15:54:35.311601307 +0200
> +++ gcc/tree-switch-conversion.cc	2023-08-09 10:15:33.197094959 +0200
> @@ -1143,32 +1143,89 @@ jump_table_cluster::emit (tree index_exp
>  			  tree default_label_expr, basic_block default_bb,
>  			  location_t loc)
>  {
> -  unsigned HOST_WIDE_INT range = get_range (get_low (), get_high ());
> +  tree low = get_low ();
> +  unsigned HOST_WIDE_INT range = get_range (low, get_high ());
>    unsigned HOST_WIDE_INT nondefault_range = 0;
> +  bool bitint = false;
> +  gimple_stmt_iterator gsi = gsi_start_bb (m_case_bb);
> +
> +  /* For large/huge _BitInt, subtract low from index_expr, cast to unsigned
> +     DImode type (get_range doesn't support ranges larger than 64-bits)
> +     and subtract low from all case values as well.  */
> +  if (TREE_CODE (TREE_TYPE (index_expr)) == BITINT_TYPE
> +      && TYPE_PRECISION (TREE_TYPE (index_expr)) > GET_MODE_PRECISION (DImode))
> +    {
> +      bitint = true;
> +      tree this_low = low, type;
> +      gimple *g;
> +      gimple_seq seq = NULL;
> +      if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (index_expr)))
> +	{
> +	  type = unsigned_type_for (TREE_TYPE (index_expr));
> +	  index_expr = gimple_convert (&seq, type, index_expr);
> +	  this_low = fold_convert (type, this_low);
> +	}
> +      this_low = const_unop (NEGATE_EXPR, TREE_TYPE (this_low), this_low);
> +      index_expr = gimple_build (&seq, PLUS_EXPR, TREE_TYPE (index_expr),
> +				 index_expr, this_low);
> +      type = build_nonstandard_integer_type (GET_MODE_PRECISION (DImode), 1);
> +      g = gimple_build_cond (GT_EXPR, index_expr,
> +			     fold_convert (TREE_TYPE (index_expr),
> +					   TYPE_MAX_VALUE (type)),
> +			     NULL_TREE, NULL_TREE);
> +      gimple_seq_add_stmt (&seq, g);
> +      gimple_seq_set_location (seq, loc);
> +      gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT);
> +      edge e1 = split_block (m_case_bb, g);
> +      e1->flags = EDGE_FALSE_VALUE;
> +      e1->probability = profile_probability::likely ();
> +      edge e2 = make_edge (e1->src, default_bb, EDGE_TRUE_VALUE);
> +      e2->probability = e1->probability.invert ();
> +      gsi = gsi_start_bb (e1->dest);
> +      seq = NULL;
> +      index_expr = gimple_convert (&seq, type, index_expr);
> +      gimple_seq_set_location (seq, loc);
> +      gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT);
> +    }
>  
>    /* For jump table we just emit a new gswitch statement that will
>       be latter lowered to jump table.  */
>    auto_vec <tree> labels;
>    labels.create (m_cases.length ());
>  
> -  make_edge (m_case_bb, default_bb, 0);
> +  basic_block case_bb = gsi_bb (gsi);
> +  make_edge (case_bb, default_bb, 0);
>    for (unsigned i = 0; i < m_cases.length (); i++)
>      {
> -      labels.quick_push (unshare_expr (m_cases[i]->m_case_label_expr));
> -      make_edge (m_case_bb, m_cases[i]->m_case_bb, 0);
> +      tree lab = unshare_expr (m_cases[i]->m_case_label_expr);
> +      if (bitint)
> +	{
> +	  CASE_LOW (lab)
> +	    = fold_convert (TREE_TYPE (index_expr),
> +			    const_binop (MINUS_EXPR,
> +					 TREE_TYPE (CASE_LOW (lab)),
> +					 CASE_LOW (lab), low));
> +	  if (CASE_HIGH (lab))
> +	    CASE_HIGH (lab)
> +	      = fold_convert (TREE_TYPE (index_expr),
> +			      const_binop (MINUS_EXPR,
> +					   TREE_TYPE (CASE_HIGH (lab)),
> +					   CASE_HIGH (lab), low));
> +	}
> +      labels.quick_push (lab);
> +      make_edge (case_bb, m_cases[i]->m_case_bb, 0);
>      }
>  
>    gswitch *s = gimple_build_switch (index_expr,
>  				    unshare_expr (default_label_expr), labels);
>    gimple_set_location (s, loc);
> -  gimple_stmt_iterator gsi = gsi_start_bb (m_case_bb);
>    gsi_insert_after (&gsi, s, GSI_NEW_STMT);
>  
>    /* Set up even probabilities for all cases.  */
>    for (unsigned i = 0; i < m_cases.length (); i++)
>      {
>        simple_cluster *sc = static_cast<simple_cluster *> (m_cases[i]);
> -      edge case_edge = find_edge (m_case_bb, sc->m_case_bb);
> +      edge case_edge = find_edge (case_bb, sc->m_case_bb);
>        unsigned HOST_WIDE_INT case_range
>  	= sc->get_range (sc->get_low (), sc->get_high ());
>        nondefault_range += case_range;
> @@ -1184,7 +1241,7 @@ jump_table_cluster::emit (tree index_exp
>    for (unsigned i = 0; i < m_cases.length (); i++)
>      {
>        simple_cluster *sc = static_cast<simple_cluster *> (m_cases[i]);
> -      edge case_edge = find_edge (m_case_bb, sc->m_case_bb);
> +      edge case_edge = find_edge (case_bb, sc->m_case_bb);
>        case_edge->probability
>  	= profile_probability::always ().apply_scale ((intptr_t)case_edge->aux,
>  						      range);
> --- gcc/typeclass.h.jj	2023-08-08 15:54:35.434599585 +0200
> +++ gcc/typeclass.h	2023-08-08 16:12:02.328939812 +0200
> @@ -37,7 +37,8 @@ enum type_class
>    function_type_class, method_type_class,
>    record_type_class, union_type_class,
>    array_type_class, string_type_class,
> -  lang_type_class, opaque_type_class
> +  lang_type_class, opaque_type_class,
> +  bitint_type_class
>  };
>  
>  #endif /* GCC_TYPECLASS_H */
> --- gcc/varasm.cc.jj	2023-08-08 15:54:35.517598423 +0200
> +++ gcc/varasm.cc	2023-08-08 16:12:02.330939784 +0200
> @@ -5281,6 +5281,61 @@ output_constant (tree exp, unsigned HOST
>  		       reverse, false);
>        break;
>  
> +    case BITINT_TYPE:
> +      if (TREE_CODE (exp) != INTEGER_CST)
> +	error ("initializer for %<_BitInt(%d)%> value is not an integer "
> +	       "constant", TYPE_PRECISION (TREE_TYPE (exp)));
> +      else
> +	{
> +	  struct bitint_info info;
> +	  tree type = TREE_TYPE (exp);
> +	  gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
> +						  &info));
> +	  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
> +	  if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
> +	    {
> +	      cst = expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
> +	      if (reverse)
> +		cst = flip_storage_order (TYPE_MODE (TREE_TYPE (exp)), cst);
> +	      if (!assemble_integer (cst, MIN (size, thissize), align, 0))
> +		error ("initializer for integer/fixed-point value is too "
> +		       "complicated");
> +	      break;
> +	    }
> +	  int prec = GET_MODE_PRECISION (limb_mode);
> +	  int cnt = CEIL (TYPE_PRECISION (type), prec);
> +	  tree limb_type = build_nonstandard_integer_type (prec, 1);
> +	  int elt_size = GET_MODE_SIZE (limb_mode);
> +	  unsigned int nalign = MIN (align, GET_MODE_ALIGNMENT (limb_mode));
> +	  thissize = 0;
> +	  if (prec == HOST_BITS_PER_WIDE_INT)
> +	    for (int i = 0; i < cnt; i++)
> +	      {
> +		int idx = (info.big_endian ^ reverse) ? cnt - 1 - i : i;
> +		tree c;
> +		if (idx >= TREE_INT_CST_EXT_NUNITS (exp))
> +		  c = build_int_cst (limb_type,
> +				     tree_int_cst_sgn (exp) < 0 ? -1 : 0);
> +		else
> +		  c = build_int_cst (limb_type,
> +				     TREE_INT_CST_ELT (exp, idx));
> +		output_constant (c, elt_size, nalign, reverse, false);
> +		thissize += elt_size;
> +	      }
> +	  else
> +	    for (int i = 0; i < cnt; i++)
> +	      {
> +		int idx = (info.big_endian ^ reverse) ? cnt - 1 - i : i;
> +		wide_int w = wi::rshift (wi::to_wide (exp), idx * prec,
> +					 TYPE_SIGN (TREE_TYPE (exp)));
> +		tree c = wide_int_to_tree (limb_type,
> +					   wide_int::from (w, prec, UNSIGNED));
> +		output_constant (c, elt_size, nalign, reverse, false);
> +		thissize += elt_size;
> +	      }
> +	}
> +      break;
> +
>      case ARRAY_TYPE:
>      case VECTOR_TYPE:
>        switch (TREE_CODE (exp))
> --- gcc/vr-values.cc.jj	2023-08-08 15:54:35.560597822 +0200
> +++ gcc/vr-values.cc	2023-08-08 16:12:02.330939784 +0200
> @@ -111,21 +111,21 @@ check_for_binary_op_overflow (range_quer
>      {
>        /* So far we found that there is an overflow on the boundaries.
>  	 That doesn't prove that there is an overflow even for all values
> -	 in between the boundaries.  For that compute widest_int range
> +	 in between the boundaries.  For that compute widest2_int range
>  	 of the result and see if it doesn't overlap the range of
>  	 type.  */
> -      widest_int wmin, wmax;
> -      widest_int w[4];
> +      widest2_int wmin, wmax;
> +      widest2_int w[4];
>        int i;
>        signop sign0 = TYPE_SIGN (TREE_TYPE (op0));
>        signop sign1 = TYPE_SIGN (TREE_TYPE (op1));
> -      w[0] = widest_int::from (vr0.lower_bound (), sign0);
> -      w[1] = widest_int::from (vr0.upper_bound (), sign0);
> -      w[2] = widest_int::from (vr1.lower_bound (), sign1);
> -      w[3] = widest_int::from (vr1.upper_bound (), sign1);
> +      w[0] = widest2_int::from (vr0.lower_bound (), sign0);
> +      w[1] = widest2_int::from (vr0.upper_bound (), sign0);
> +      w[2] = widest2_int::from (vr1.lower_bound (), sign1);
> +      w[3] = widest2_int::from (vr1.upper_bound (), sign1);
>        for (i = 0; i < 4; i++)
>  	{
> -	  widest_int wt;
> +	  widest2_int wt;
>  	  switch (subcode)
>  	    {
>  	    case PLUS_EXPR:
> @@ -153,10 +153,10 @@ check_for_binary_op_overflow (range_quer
>  	}
>        /* The result of op0 CODE op1 is known to be in range
>  	 [wmin, wmax].  */
> -      widest_int wtmin
> -	= widest_int::from (irange_val_min (type), TYPE_SIGN (type));
> -      widest_int wtmax
> -	= widest_int::from (irange_val_max (type), TYPE_SIGN (type));
> +      widest2_int wtmin
> +	= widest2_int::from (irange_val_min (type), TYPE_SIGN (type));
> +      widest2_int wtmax
> +	= widest2_int::from (irange_val_max (type), TYPE_SIGN (type));
>        /* If all values in [wmin, wmax] are smaller than
>  	 [wtmin, wtmax] or all are larger than [wtmin, wtmax],
>  	 the arithmetic operation will always overflow.  */
> @@ -1717,12 +1717,11 @@ simplify_using_ranges::simplify_internal
>      g = gimple_build_assign (gimple_call_lhs (stmt), subcode, op0, op1);
>    else
>      {
> -      int prec = TYPE_PRECISION (type);
>        tree utype = type;
>        if (ovf
>  	  || !useless_type_conversion_p (type, TREE_TYPE (op0))
>  	  || !useless_type_conversion_p (type, TREE_TYPE (op1)))
> -	utype = build_nonstandard_integer_type (prec, 1);
> +	utype = unsigned_type_for (type);
>        if (TREE_CODE (op0) == INTEGER_CST)
>  	op0 = fold_convert (utype, op0);
>        else if (!useless_type_conversion_p (utype, TREE_TYPE (op0)))
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

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

* Re: [PATCH 4/12] Middle-end _BitInt support [PR102989]
  2023-08-09 18:17 [PATCH 4/12] Middle-end _BitInt support [PR102989] Jakub Jelinek
  2023-08-22  8:41 ` Richard Biener
@ 2023-09-07  8:36 ` Thomas Schwinge
  2023-09-07  9:22   ` [committed] middle-end: Avoid calling targetm.c.bitint_type_info inside of gcc_assert [PR102989] Jakub Jelinek
  1 sibling, 1 reply; 4+ messages in thread
From: Thomas Schwinge @ 2023-09-07  8:36 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Richard Biener

Hi Jakub!

On 2023-08-09T20:17:50+0200, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> The following patch introduces the middle-end part of the _BitInt
> support, a new BITINT_TYPE, handling it where needed, except the lowering
> pass and sanitizer support.

Minor comment/question: are we doing away with the property that
'assert'-like "calls" must not have side effects?  Per 'gcc/system.h',
this is "OK" for 'gcc_assert' for '#if ENABLE_ASSERT_CHECKING' or
'#elif (GCC_VERSION >= 4005)' -- that is, GCC 4.5, which is always-true,
thus the "offending" '#else' is never active.  However, it's different
for standard 'assert' and 'gcc_checking_assert', so I'm not sure if
that's a good property for 'gcc_assert' only?  For example, see also
<https://gcc.gnu.org/PR6906> "warn about asserts with side effects", or
recent <https://gcc.gnu.org/PR111144>
"RFE: could -fanalyzer warn about assertions that have side effects?".

> --- gcc/expr.cc.jj    2023-08-08 16:02:52.837633995 +0200
> +++ gcc/expr.cc       2023-08-09 10:30:13.524295673 +0200

> @@ -11002,13 +11028,35 @@ expand_expr_real_1 (tree exp, rtx target

> +         struct bitint_info info;
> +         gcc_assert (targetm.c.bitint_type_info (prec, &info));
> +         scalar_int_mode limb_mode
> +           = as_a <scalar_int_mode> (info.limb_mode);

> --- gcc/fold-const.cc.jj      2023-08-08 15:55:06.507164442 +0200
> +++ gcc/fold-const.cc 2023-08-08 16:12:02.318939952 +0200

> @@ -7714,7 +7726,29 @@ static int

> +      struct bitint_info info;
> +      gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
> +                                           &info));
> +      scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);

> @@ -8622,7 +8656,29 @@ native_encode_initializer (tree init, un

> +      struct bitint_info info;
> +      gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
> +                                           &info));
> +      scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);

> --- gcc/gimple-fold.cc.jj     2023-08-08 15:55:06.609163014 +0200
> +++ gcc/gimple-fold.cc        2023-08-08 16:18:44.828303852 +0200

> +static bool
> +clear_padding_bitint_needs_padding_p (tree type)
> +{
> +  struct bitint_info info;
> +  gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
> +  if (info.extended)
> +    return false;

> @@ -4854,6 +4877,57 @@ clear_padding_type (clear_padding_struct

> +     struct bitint_info info;
> +     gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
> +     scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);

> --- gcc/stor-layout.cc.jj     2023-08-08 15:54:34.855607692 +0200
> +++ gcc/stor-layout.cc        2023-08-08 16:15:41.003877836 +0200

> @@ -2148,6 +2148,22 @@ finish_bitfield_representative (tree rep

> +       struct bitint_info info;
> +       unsigned prec = TYPE_PRECISION (TREE_TYPE (field));
> +       gcc_assert (targetm.c.bitint_type_info (prec, &info));
> +       scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);

> @@ -2393,6 +2409,64 @@ layout_type (tree type)

> +     struct bitint_info info;
> +     int cnt;
> +     gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
> +     scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);

> --- gcc/varasm.cc.jj  2023-08-08 15:54:35.517598423 +0200
> +++ gcc/varasm.cc     2023-08-08 16:12:02.330939784 +0200

> @@ -5281,6 +5281,61 @@ output_constant (tree exp, unsigned HOST

> +       struct bitint_info info;
> +       tree type = TREE_TYPE (exp);
> +       gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
> +                                               &info));
> +       scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);


Grüße
 Thomas
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

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

* [committed] middle-end: Avoid calling targetm.c.bitint_type_info inside of gcc_assert [PR102989]
  2023-09-07  8:36 ` Thomas Schwinge
@ 2023-09-07  9:22   ` Jakub Jelinek
  0 siblings, 0 replies; 4+ messages in thread
From: Jakub Jelinek @ 2023-09-07  9:22 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, Richard Biener

On Thu, Sep 07, 2023 at 10:36:02AM +0200, Thomas Schwinge wrote:
> Minor comment/question: are we doing away with the property that
> 'assert'-like "calls" must not have side effects?  Per 'gcc/system.h',
> this is "OK" for 'gcc_assert' for '#if ENABLE_ASSERT_CHECKING' or
> '#elif (GCC_VERSION >= 4005)' -- that is, GCC 4.5, which is always-true,
> thus the "offending" '#else' is never active.  However, it's different
> for standard 'assert' and 'gcc_checking_assert', so I'm not sure if
> that's a good property for 'gcc_assert' only?  For example, see also
> <https://gcc.gnu.org/PR6906> "warn about asserts with side effects", or
> recent <https://gcc.gnu.org/PR111144>
> "RFE: could -fanalyzer warn about assertions that have side effects?".

You're right, the
  #define gcc_assert(EXPR) ((void)(0 && (EXPR)))
fallback definition is incompatible with the way I've used it, so for
--disable-checking built by non-GCC it would not work properly.

Fixed thusly, committed to trunk as obvious.

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

	PR c/102989
	* expr.cc (expand_expr_real_1): Don't call targetm.c.bitint_type_info
	inside gcc_assert, as later code relies on it filling info variable.
	* gimple-fold.cc (clear_padding_bitint_needs_padding_p,
	clear_padding_type): Likewise.
	* varasm.cc (output_constant): Likewise.
	* fold-const.cc (native_encode_int, native_interpret_int): Likewise.
	* stor-layout.cc (finish_bitfield_representative, layout_type):
	Likewise.
	* gimple-lower-bitint.cc (bitint_precision_kind): Likewise.

--- gcc/expr.cc.jj	2023-09-06 17:28:24.216977643 +0200
+++ gcc/expr.cc	2023-09-07 11:11:57.761912944 +0200
@@ -11039,7 +11039,8 @@ expand_expr_real_1 (tree exp, rtx target
 	  {
 	    unsigned int prec = TYPE_PRECISION (type);
 	    struct bitint_info info;
-	    gcc_assert (targetm.c.bitint_type_info (prec, &info));
+	    bool ok = targetm.c.bitint_type_info (prec, &info);
+	    gcc_assert (ok);
 	    scalar_int_mode limb_mode
 	      = as_a <scalar_int_mode> (info.limb_mode);
 	    unsigned int limb_prec = GET_MODE_PRECISION (limb_mode);
--- gcc/gimple-fold.cc.jj	2023-09-06 17:28:24.221977578 +0200
+++ gcc/gimple-fold.cc	2023-09-07 11:11:57.765912888 +0200
@@ -4602,7 +4602,8 @@ static bool
 clear_padding_bitint_needs_padding_p (tree type)
 {
   struct bitint_info info;
-  gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
+  bool ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info);
+  gcc_assert (ok);
   if (info.extended)
     return false;
   scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
@@ -4880,7 +4881,8 @@ clear_padding_type (clear_padding_struct
     case BITINT_TYPE:
       {
 	struct bitint_info info;
-	gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
+	bool ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info);
+	gcc_assert (ok);
 	scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
 	if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
 	  {
--- gcc/varasm.cc.jj	2023-09-06 17:28:24.239977342 +0200
+++ gcc/varasm.cc	2023-09-07 11:11:57.769912832 +0200
@@ -5289,8 +5289,8 @@ output_constant (tree exp, unsigned HOST
 	{
 	  struct bitint_info info;
 	  tree type = TREE_TYPE (exp);
-	  gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
-						  &info));
+	  bool ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info);
+	  gcc_assert (ok);
 	  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
 	  if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
 	    {
--- gcc/fold-const.cc.jj	2023-09-06 17:28:24.219977604 +0200
+++ gcc/fold-const.cc	2023-09-07 11:11:57.772912790 +0200
@@ -7731,8 +7731,8 @@ native_encode_int (const_tree expr, unsi
   if (TREE_CODE (type) == BITINT_TYPE)
     {
       struct bitint_info info;
-      gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
-					      &info));
+      bool ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info);
+      gcc_assert (ok);
       scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
       if (TYPE_PRECISION (type) > GET_MODE_PRECISION (limb_mode))
 	{
@@ -8661,8 +8661,8 @@ native_interpret_int (tree type, const u
   if (TREE_CODE (type) == BITINT_TYPE)
     {
       struct bitint_info info;
-      gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type),
-					      &info));
+      bool ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info);
+      gcc_assert (ok);
       scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
       if (TYPE_PRECISION (type) > GET_MODE_PRECISION (limb_mode))
 	{
--- gcc/stor-layout.cc.jj	2023-09-06 17:28:24.226977512 +0200
+++ gcc/stor-layout.cc	2023-09-07 11:11:57.775912748 +0200
@@ -2152,7 +2152,8 @@ finish_bitfield_representative (tree rep
 	{
 	  struct bitint_info info;
 	  unsigned prec = TYPE_PRECISION (TREE_TYPE (field));
-	  gcc_assert (targetm.c.bitint_type_info (prec, &info));
+	  bool ok = targetm.c.bitint_type_info (prec, &info);
+	  gcc_assert (ok);
 	  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
 	  unsigned lprec = GET_MODE_PRECISION (limb_mode);
 	  if (prec > lprec)
@@ -2413,7 +2414,8 @@ layout_type (tree type)
       {
 	struct bitint_info info;
 	int cnt;
-	gcc_assert (targetm.c.bitint_type_info (TYPE_PRECISION (type), &info));
+	bool ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info);
+	gcc_assert (ok);
 	scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
 	if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
 	  {
--- gcc/gimple-lower-bitint.cc.jj	2023-09-06 17:49:21.945490318 +0200
+++ gcc/gimple-lower-bitint.cc	2023-09-07 11:11:57.778912706 +0200
@@ -92,7 +92,8 @@ bitint_precision_kind (int prec)
     return bitint_prec_middle;
 
   struct bitint_info info;
-  gcc_assert (targetm.c.bitint_type_info (prec, &info));
+  bool ok = targetm.c.bitint_type_info (prec, &info);
+  gcc_assert (ok);
   scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
   if (prec <= GET_MODE_PRECISION (limb_mode))
     {


	Jakub


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

end of thread, other threads:[~2023-09-07  9:22 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:17 [PATCH 4/12] Middle-end _BitInt support [PR102989] Jakub Jelinek
2023-08-22  8:41 ` Richard Biener
2023-09-07  8:36 ` Thomas Schwinge
2023-09-07  9:22   ` [committed] middle-end: Avoid calling targetm.c.bitint_type_info inside of gcc_assert [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).