From: Richard Biener Date: Tue, 10 Feb 2026 08:46:08 +0000 (+0100) Subject: tree-optimization/107690 - avoid creating un-analyzable loop exits X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e55de74d50d236db0472431fe242f3244e41b884;p=thirdparty%2Fgcc.git 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 --git a/gcc/testsuite/g++.dg/vect/vect-pr107690.cc b/gcc/testsuite/g++.dg/vect/vect-pr107690.cc new file mode 100644 index 00000000000..847dbca5f62 --- /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 +#include +#include + +std::array foo(std::array u, std::array const &v) +{ + std::ranges::transform(u, v, u.begin(), std::plus()); + 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 7769118b9f6..a60e6914e68 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