https://gcc.gnu.org/g:26aae2119eb79bfbea23b86ea1a58f9a3a0911a6
commit r17-529-g26aae2119eb79bfbea23b86ea1a58f9a3a0911a6 Author: Xi Ruoyao <[email protected]> Date: Wed May 13 00:22:15 2026 +0800 scev: Sign extend step in peeled converted IV handling [PR 125291] For 3 iterations of unsigned char flagbits; _877 = flagbits_832 + 254; _879 = (int) _877; # prephitmp_880 = PHI <_879(40), 6(41)> _70 = _68 >> prephitmp_880; The peeled converted IV handling added in r16-3562 incorrectly analyzes it as [6, 6 + 254, 6 + 254 * 2] instead of [6, 4, 2]. Then VRP uses the intersect of {6, 560, 514} and {2, 4, 6}, i.e. {6} as the possible value range, and propagates the constant 6 for _70. Extend the step (for example, 254 => -2) to fix the issue. PR tree-optimization/125291 gcc/ * tree-scalar-evolution.cc (simplify_peeled_chrec): Sign-extend the step for peeled converted IV. gcc/testsuite/ * gcc.c-torture/execute/pr125291.c: New test. Diff: --- gcc/testsuite/gcc.c-torture/execute/pr125291.c | 39 ++++++++++++++++++++++++++ gcc/tree-scalar-evolution.cc | 17 ++++++++--- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/gcc/testsuite/gcc.c-torture/execute/pr125291.c b/gcc/testsuite/gcc.c-torture/execute/pr125291.c new file mode 100644 index 000000000000..073866a9b736 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr125291.c @@ -0,0 +1,39 @@ +/* PR tree-optimization/125291 */ + +char buf[1111]; +char *archive_le16dec_filename = buf; +unsigned int archive_le16dec_end, archive_le16dec_fn_end, + archive_le16dec_filename_size, archive_le16dec_offset; +char archive_le16dec_p[] = { 21, 0x7f }; + +[[gnu::noipa]] +void +archive_le16dec () +{ + archive_le16dec_filename_size = (short)archive_le16dec_filename_size; + unsigned char flagbits = 0, flagbyte; + archive_le16dec_end = archive_le16dec_filename_size; + archive_le16dec_fn_end = archive_le16dec_filename_size * 2; + archive_le16dec_filename_size = flagbits = 0; + while (archive_le16dec_offset < archive_le16dec_end + && archive_le16dec_filename_size < archive_le16dec_fn_end) + { + if (!flagbits) + { + flagbyte = archive_le16dec_p[archive_le16dec_offset++]; + flagbits = 8; + } + flagbits -= 2; + if (!(flagbyte >> flagbits & 3)) + archive_le16dec_filename_size++; + } +} + +int +main () +{ + archive_le16dec_filename_size = 2; + archive_le16dec (); + if (archive_le16dec_filename_size != 1) + __builtin_trap (); +} diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc index f524786f33be..b27037cb02fd 100644 --- a/gcc/tree-scalar-evolution.cc +++ b/gcc/tree-scalar-evolution.cc @@ -1391,10 +1391,19 @@ simplify_peeled_chrec (class loop *loop, tree arg, tree init_cond) && wi::to_widest (init_cond) == wi::to_widest (left_before) && !scev_probably_wraps_p (NULL_TREE, left_before, right, NULL, loop, false)) - return build_polynomial_chrec (loop->num, init_cond, - chrec_convert (TREE_TYPE (ev), - right, NULL, - false, NULL_TREE)); + { + tree tp = TREE_TYPE (right); + + /* We need a sign-extension to make things like + u8(6, 4, 2) => i32(6, 4, 2), instead of i32(6, 260, 514). */ + if (TYPE_UNSIGNED (tp)) + right = fold_convert (signed_type_for (tp), right); + + return build_polynomial_chrec (loop->num, init_cond, + chrec_convert (TREE_TYPE (ev), + right, NULL, + false, NULL_TREE)); + } return chrec_dont_know; }
