Hi! The following patch attempts to fix the (view_convert (convert@0 @1)) optimization. If TREE_TYPE (@0) is a _BitInt type with padding bits and @0 has the same precision as @1 and it has a different sign and _BitInt with padding bits are extended on the target (x86 doesn't, aarch64 doesn't, but arm plans to do that), then optimizing it to just (view_convert @1) is wrong, the padding bits wouldn't be what it should be. E.g. bitint-64.c test with -O2 has _5 = (unsigned _BitInt(5)) _4; _7 = (unsigned _BitInt(5)) e.0_1; _8 = _5 + _7; _9 = (_BitInt(5)) _8; _10 = VIEW_CONVERT_EXPR<unsigned char>(_9); and forwprop1 changes that to just _5 = (unsigned _BitInt(5)) _4; _7 = (unsigned _BitInt(5)) e.0_1; _8 = _5 + _7; _10 = VIEW_CONVERT_EXPR<unsigned char>(_8); The former makes the padding bits well defined (at least on arm in the future), while the latter has those bits zero extended.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2024-03-26 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/114469 * match.pd ((view_convert (convert@0 @1))): Don't optimize if TREE_TYPE (@0) is a BITINT_TYPE with padding bits which are supposed to be extended by the ABI. --- gcc/match.pd.jj 2024-03-15 11:04:24.672914747 +0100 +++ gcc/match.pd 2024-03-26 15:49:44.177864509 +0100 @@ -4699,13 +4699,38 @@ (define_operator_list SYNC_FETCH_AND_AND zero-extend while keeping the same size (for bool-to-char). */ (simplify (view_convert (convert@0 @1)) - (if ((INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0))) - && (INTEGRAL_TYPE_P (TREE_TYPE (@1)) || POINTER_TYPE_P (TREE_TYPE (@1))) - && TYPE_SIZE (TREE_TYPE (@0)) == TYPE_SIZE (TREE_TYPE (@1)) - && (TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1)) - || (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (TREE_TYPE (@1)) - && TYPE_UNSIGNED (TREE_TYPE (@1))))) - (view_convert @1))) + (with { tree type0 = TREE_TYPE (@0); + tree type1 = TREE_TYPE (@1); + bool ok = false; + if ((INTEGRAL_TYPE_P (type0) || POINTER_TYPE_P (type0)) + && (INTEGRAL_TYPE_P (type1) || POINTER_TYPE_P (type1)) + && TYPE_SIZE (type0) == TYPE_SIZE (type1)) + { + if (TYPE_PRECISION (type0) == TYPE_PRECISION (type1)) + { + if (TREE_CODE (type0) != BITINT_TYPE) + ok = true; + else + { + /* Avoid optimizing this if type0 is a _BitInt + type with padding bits which are supposed to be + extended. */ + struct bitint_info info; + targetm.c.bitint_type_info (TYPE_PRECISION (type0), + &info); + if (!info.extended) + ok = true; + else + ok = (TYPE_PRECISION (type0) + == tree_to_uhwi (TYPE_SIZE (type0))); + } + } + else if (TYPE_PRECISION (type0) > TYPE_PRECISION (type1) + && TYPE_UNSIGNED (type1)) + ok = true; + } } + (if (ok) + (view_convert @1)))) /* Simplify a view-converted empty or single-element constructor. */ (simplify Jakub