https://gcc.gnu.org/g:5836d9322a2adb0b6d1a5d576fb5ceb9569009b2
commit r16-5574-g5836d9322a2adb0b6d1a5d576fb5ceb9569009b2 Author: Jakub Jelinek <[email protected]> Date: Tue Nov 25 10:06:46 2025 +0100 alias: Fix up BITINT_TYPE and non-standard INTEGER_TYPE alias handling [PR122624] The testcase in the PR is miscompiled on aarch64 with --param=ggc-min-expand=0 --param=ggc-min-heapsize=0 -O2 (not including it in the testsuite because it is too much of a lottery). Anyway, the problem is that the testcase only uses unsigned _BitInt(66) and never uses _BitInt(66), get_alias_set remembers alias set for ARRAY_TYPE (of its element type in ARRAY_TYPE's TYPE_ALIAS_SET), c_common_get_alias_set does not remember in TYPE_ALIAS_SET alias of unsigned types and instead asks for get_alias_set of corresponding signed type and that creates a new alias set for each new canonical type. So, in this case, when being asked about get_alias_set on ARRAY_TYPE unsigned _BitInt(66) [N], it recurses down to c_common_get_alias_set which asks for alias set of at that point newly created signed type _BitInt(66), new alias set is created for it, remembered in that signed _BitInt(66) TYPE_ALIAS_SET, not remembered in unsigned _BitInt(66) and remembered in ARRAY_TYPE's TYPE_ALIAS_SET. Next a GC collection comes, signed _BitInt(66) is not used anywhere in any reachable from GC roots, so it is removed. Later on we ask alias oracle whether the above mentioned ARRAY_TYPE can for TBAA alias pointer dereference with the same unsigned _BitInt(66) type. For the ARRAY_TYPE, we have the above created alias set remembered in TYPE_ALIAS_SET, so that is what we use, but for the unsigned _BitInt(66) we don't, so create a new signed _BitInt(66), create a new alias set for it and that is what is returned, so we have to distinct alias sets and return that they can't alias. Now, for standard INTEGER_TYPEs this isn't a problem, because both the signed and unsigned variants of those types are always reachable from GTY roots. For BITINT_TYPE (or build_nonstandard_integer_type built types) that isn't the case. I'm not convinced we need to fix it for build_nonstandard_integer_type built INTEGER_TYPEs though, for bit-fields their address can't be taken in C/C++, but for BITINT_TYPE this clearly is a problem. So, the following patch solves it by 1) remembering the alias set we got from get_alias_set on the signed _BitInt(N) type in the unsigned _BitInt(N) type 2) returning -1 for unsigned _BitInt(1), because there is no corresponding signed _BitInt type and so we can handle it normally 3) so that the signed _BitInt(N) type isn't later GC collected and later readded with a new alias set incompatible with the still reachable unsigned _BitInt(N) type, the patch for signed _BitInt(N) types checks if corresponding unsigned _BitInt(N) type doesn't already have TYPE_ALIAS_SET_KNOWN_P, in that case it remembers and returns that; in order to avoid infinite recursion, it doesn't call get_alias_set on the unsigned _BitInt(N) type though 4) while type_hash_canon remembers in the type_hash_table both the hash and the type, so what exactly we use as the hash isn't that important, I think using type_hash_canon_hash for BITINT_TYPEs is actually better over hasing TYPE_MAX_VALUE, because especially for larger BITINT_TYPEs TYPE_MAX_VALUE can have lots of HWIs in the number, for type_hash_canon_hash hashes for BITINT_TYPEs only i) TREE_CODE (i.e. BITINT_TYPE) ii) TYPE_STRUCTURAL_EQUALITY_P flag (likely false) iii) TYPE_PRECISION iv) TYPE_UNSIGNED so 3 ints and one flag, while the old way can hash one HWI up to 1024 HWIs; note it is also more consistent with most other type_hash_canon calls, except for build_nonstandard_integer_type; for some reason changing that one to use also type_hash_canon_hash doesn't work, causes tons of ICEs This version of the patch handles INTEGER_TYPEs the same as BITINT_TYPE. 2025-11-25 Jakub Jelinek <[email protected]> PR middle-end/122624 * tree.cc (build_bitint_type): Use type_hash_canon_hash. * c-common.cc (c_common_get_alias_set): Fix up handling of BITINT_TYPE and non-standard INTEGER_TYPEs. For unsigned _BitInt(1) always return -1. For other unsigned types set TYPE_ALIAS_SET to get_alias_set of corresponding signed type and return that. For signed types check if corresponding unsigned type has TYPE_ALIAS_SET_KNOWN_P and if so copy its TYPE_ALIAS_SET and return that. Diff: --- gcc/c-family/c-common.cc | 42 ++++++++++++++++++++++++++++++++++-------- gcc/tree.cc | 5 ++--- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 9b97a0fe6224..ef1ce62068dd 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -3943,14 +3943,40 @@ c_common_get_alias_set (tree t) /* The C standard specifically allows aliasing between signed and unsigned variants of the same type. We treat the signed variant as canonical. */ - if ((TREE_CODE (t) == INTEGER_TYPE || TREE_CODE (t) == BITINT_TYPE) - && TYPE_UNSIGNED (t)) - { - tree t1 = c_common_signed_type (t); - - /* t1 == t can happen for boolean nodes which are always unsigned. */ - if (t1 != t) - return get_alias_set (t1); + if (TREE_CODE (t) == INTEGER_TYPE || TREE_CODE (t) == BITINT_TYPE) + { + /* For normal INTEGER_TYPEs (except ones built by + build_nonstandard_integer_type), both signed and unsigned variants + of the type are always reachable from GTY roots, so just calling + get_alias_set on the signed type is ok. For BITINT_TYPE and + non-standard INTEGER_TYPEs, only unsigned could be used and the + corresponding signed type could be created on demand and garbage + collected as unused, so the alias set of unsigned type could keep + changing. + Avoid that by remembering the signed type alias set in + TYPE_ALIAS_SET and also when being asked about !TYPE_UNSIGNED + check if there isn't a corresponding unsigned type with + TYPE_ALIAS_SET_KNOWN_P. */ + if (TYPE_UNSIGNED (t)) + { + /* There is no signed _BitInt(1). */ + if (TREE_CODE (t) == BITINT_TYPE && TYPE_PRECISION (t) == 1) + return -1; + tree t1 = c_common_signed_type (t); + gcc_checking_assert (t != t1); + TYPE_ALIAS_SET (t) = get_alias_set (t1); + return TYPE_ALIAS_SET (t); + } + else + { + tree t1 = c_common_unsigned_type (t); + gcc_checking_assert (t != t1); + if (TYPE_ALIAS_SET_KNOWN_P (t1)) + { + TYPE_ALIAS_SET (t) = TYPE_ALIAS_SET (t1); + return TYPE_ALIAS_SET (t); + } + } } return -1; diff --git a/gcc/tree.cc b/gcc/tree.cc index 4c8e31cfb122..e8376dd04bd7 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -7414,9 +7414,8 @@ build_bitint_type (unsigned HOST_WIDE_INT precision, int unsignedp) else fixup_signed_type (itype); - inchash::hash hstate; - inchash::add_expr (TYPE_MAX_VALUE (itype), hstate); - ret = type_hash_canon (hstate.end (), itype); + hashval_t hash = type_hash_canon_hash (itype); + ret = type_hash_canon (hash, itype); if (precision <= MAX_INT_CACHED_PREC) (*bitint_type_cache)[precision + unsignedp] = ret;
