https://gcc.gnu.org/g:e55de74d50d236db0472431fe242f3244e41b884
commit r16-7431-ge55de74d50d236db0472431fe242f3244e41b884 Author: Richard Biener <[email protected]> Date: Tue Feb 10 09:46:08 2026 +0100 tree-optimization/107690 - avoid creating un-analyzable loop exits The following adds a heuristic to ifcombine that avoids turning analyzable loop exits into unanalyzable ones. This allows vectorizing the testcase in the PR again. I've refrained from actually analyzing niters but instead used a cheaper heuristic. I believe we'll only ever attempt to combine two ifs if they are in the same loop and if either both exit the loop or stay within. PR tree-optimization/107690 * tree-ssa-ifcombine.cc (ifcombine_ifandif): Do not merge possibly analyzable exit conditions. * g++.dg/vect/vect-pr107690.cc: New testcase. Diff: --- gcc/testsuite/g++.dg/vect/vect-pr107690.cc | 16 ++++++++++++++++ gcc/tree-ssa-ifcombine.cc | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/gcc/testsuite/g++.dg/vect/vect-pr107690.cc b/gcc/testsuite/g++.dg/vect/vect-pr107690.cc new file mode 100644 index 000000000000..847dbca5f62d --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/vect-pr107690.cc @@ -0,0 +1,16 @@ +// { dg-do compile } +// { dg-require-effective-target vect_int } +// { dg-additional-options "-std=gnu++20" } + +#include <algorithm> +#include <array> +#include <ranges> + +std::array<int, 16> foo(std::array<int, 16> u, std::array<int, 16> const &v) +{ + std::ranges::transform(u, v, u.begin(), std::plus<int>()); + return u; +} + +// { dg-final { scan-tree-dump "optimized: loop vectorized" "vect" } } +// { dg-final { scan-tree-dump-not "Loop being analyzed as uncounted" "vect" } } diff --git a/gcc/tree-ssa-ifcombine.cc b/gcc/tree-ssa-ifcombine.cc index 7769118b9f6e..a60e6914e68c 100644 --- a/gcc/tree-ssa-ifcombine.cc +++ b/gcc/tree-ssa-ifcombine.cc @@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "asan.h" #include "bitmap.h" +#include "cfgloop.h" #ifndef LOGICAL_OP_NON_SHORT_CIRCUIT #define LOGICAL_OP_NON_SHORT_CIRCUIT \ @@ -818,6 +819,21 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv, if (!outer_cond) return false; + /* niter analysis does not cope with boolean typed loop exit conditions. + Avoid turning an analyzable exit into an unanalyzable one. */ + if (inner_cond_bb->loop_father == outer_cond_bb->loop_father + && loop_exits_from_bb_p (inner_cond_bb->loop_father, inner_cond_bb) + && loop_exits_from_bb_p (outer_cond_bb->loop_father, outer_cond_bb)) + { + tree outer_type = TREE_TYPE (gimple_cond_lhs (outer_cond)); + tree inner_type = TREE_TYPE (gimple_cond_lhs (inner_cond)); + if (TREE_CODE (outer_type) == INTEGER_TYPE + || POINTER_TYPE_P (outer_type) + || TREE_CODE (inner_type) == INTEGER_TYPE + || POINTER_TYPE_P (inner_type)) + return false; + } + /* See if we test a single bit of the same name in both tests. In that case remove the outer test, merging both else edges, and change the inner one to test for
