]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/107690 - avoid creating un-analyzable loop exits
authorRichard Biener <rguenther@suse.de>
Tue, 10 Feb 2026 08:46:08 +0000 (09:46 +0100)
committerRichard Biener <rguenth@gcc.gnu.org>
Tue, 10 Feb 2026 09:59:32 +0000 (10:59 +0100)
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.

gcc/testsuite/g++.dg/vect/vect-pr107690.cc [new file with mode: 0644]
gcc/tree-ssa-ifcombine.cc

diff --git a/gcc/testsuite/g++.dg/vect/vect-pr107690.cc b/gcc/testsuite/g++.dg/vect/vect-pr107690.cc
new file mode 100644 (file)
index 0000000..847dbca
--- /dev/null
@@ -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" } }
index 7769118b9f6e1c9640423d1b436e81b3713e59f1..a60e6914e68cd47c71ac472e289a267ed5456b33 100644 (file)
@@ -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