https://gcc.gnu.org/g:5a4f77eb6afffb16fae3effe9965dc8b216c84ce
commit r17-5409-g5a4f77eb6afffb16fae3effe9965dc8b216c84ce Author: Richard Biener <[email protected]> Date: Tue Oct 20 12:14:31 2026 +0200 lto/127922 - TBAA and unsigned vs. signed _BitInt With LTO we fail to ensure signed and unsigned _BitInt of the same precision get the same alias set. Without LTO this is ensured by c_common_get_alias_set which uses the other signedness variants alias-set. With LTO this is complicated by streaming not populating the bitint_type_cache so a similar approach cannot work. The following instead handles this during canonical type merging. I have still fixed gimple_signed_or_unsigned_type to support _BitInt and amended gimple_get_alias_set with a comment. PR lto/127922 * tree.cc (type_with_interoperable_signedness): Return true for BITINT_TYPE. * gimple.cc (gimple_signed_or_unsigned_type): Properly handle BITINT_TYPE. (gimple_get_alias_set): Add comment about signed/unsigned BITINT_TYPE. * gcc.dg/lto/bitint-lto-1_0.c: New testcase. Diff: --- gcc/gimple.cc | 6 +++++- gcc/testsuite/gcc.dg/lto/bitint-lto-1_0.c | 22 ++++++++++++++++++++++ gcc/tree.cc | 14 ++++++++++---- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/gcc/gimple.cc b/gcc/gimple.cc index 3b68902b6109..2295f353472b 100644 --- a/gcc/gimple.cc +++ b/gcc/gimple.cc @@ -2807,6 +2807,9 @@ gimple_signed_or_unsigned_type (bool unsignedp, tree type) || TYPE_UNSIGNED (type) == unsignedp) return type; + if (BITINT_TYPE_P (type)) + return build_bitint_type (TYPE_PRECISION (type), unsignedp); + #define TYPE_OK(node) \ (TYPE_MODE (type) == TYPE_MODE (node) \ && TYPE_PRECISION (type) == TYPE_PRECISION (node)) @@ -2891,7 +2894,8 @@ gimple_get_alias_set (tree t) return 0; /* Allow aliasing between signed and unsigned variants of the same - type. We treat the signed variant as canonical. */ + type. We treat the signed variant as canonical. BITINT_TYPEs + are handled by canonical type merging. */ if (TREE_CODE (t) == INTEGER_TYPE && TYPE_UNSIGNED (t)) { tree t1 = gimple_signed_type (t); diff --git a/gcc/testsuite/gcc.dg/lto/bitint-lto-1_0.c b/gcc/testsuite/gcc.dg/lto/bitint-lto-1_0.c new file mode 100644 index 000000000000..c73c79f3ad69 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/bitint-lto-1_0.c @@ -0,0 +1,22 @@ +/* PR/127922 */ +/* { dg-lto-do run } */ +/* { dg-require-effective-target bitint } */ + +typedef _BitInt(17) S; +typedef unsigned _BitInt(17) U; + +__attribute__((noipa)) S +f(S *p, U *q) +{ + *p = 1; + *q = 2; + return *p; +} + +int main() +{ + S x = 0; + S result = f(&x, (U *)&x); + if (result != 2) + __builtin_abort (); +} diff --git a/gcc/tree.cc b/gcc/tree.cc index 63edf1959ce2..e43a2b78c61c 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -14211,10 +14211,16 @@ type_with_interoperable_signedness (const_tree type) signed char and unsigned char. Similarly fortran FE builds C_SIZE_T as signed type, while C defines it unsigned. */ - return tree_code_for_canonical_type_merging (TREE_CODE (type)) - == INTEGER_TYPE - && (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node) - || TYPE_PRECISION (type) == TYPE_PRECISION (size_type_node)); + if (tree_code_for_canonical_type_merging (TREE_CODE (type)) == INTEGER_TYPE) + return (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node) + || TYPE_PRECISION (type) == TYPE_PRECISION (size_type_node)); + + /* The C standard allows aliasing between signed and unsigned variants + of the same type. For INTEGER_TYPEs gimple_get_alias_set handles + this and this works because the integer type cache is pre-loaded + during streaming. We do not do this for bitint_type_cache, so handle + the aliasing via assigning the same canonical type. */ + return TREE_CODE (type) == BITINT_TYPE; } /* Return true iff T1 and T2 are structurally identical for what
