[4/12] Middle-end _BitInt support [PR102989]
Checks
Commit Message
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.
Jakub
Comments
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
>
> /* 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
>
>
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
@@ -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)
@@ -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 *);
@@ -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
@@ -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);
@@ -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);
@@ -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));
@@ -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
@@ -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
@@ -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
@@ -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;
@@ -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
/* Subroutine of above: reduce EXP to the precision of TYPE (in the
signedness of TYPE), possibly returning the result in TARGET.
@@ -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:
@@ -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. */
@@ -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)
@@ -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);
+}
@@ -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
@@ -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);
@@ -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
@@ -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) \
@@ -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))));
@@ -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. */
@@ -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. */
@@ -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
@@ -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 *);
@@ -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))
@@ -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))),
@@ -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);
@@ -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 */
@@ -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))
@@ -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)))