When if-conversion converts a switch statement it requires a certain
shape of the CFG. This is verified via if_convertible_switch_p
but the check is incorrectly elided for blocks dominating the loop
latch. The following rectifies this.
Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.
PR tree-optimization/126760
* tree-if-conv.cc (if_convertible_stmt_p): Delay switch
validation to ...
(if_convertible_loop_p_1): ... the loop iterating over
PHIs.
* gcc.dg/vect/vect-pr126760.c: New testcase.
* gcc.dg/vect/vect-pr127391.c: Likewise.
---
gcc/testsuite/gcc.dg/vect/vect-pr126760.c | 33 +++++++++++++++++++++++
gcc/testsuite/gcc.dg/vect/vect-pr127391.c | 28 +++++++++++++++++++
gcc/tree-if-conv.cc | 10 +++++--
3 files changed, 69 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/vect/vect-pr126760.c
create mode 100644 gcc/testsuite/gcc.dg/vect/vect-pr127391.c
diff --git a/gcc/testsuite/gcc.dg/vect/vect-pr126760.c
b/gcc/testsuite/gcc.dg/vect/vect-pr126760.c
new file mode 100644
index 00000000000..ded34a2e2f7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-pr126760.c
@@ -0,0 +1,33 @@
+#include "tree-vect.h"
+
+long __attribute__((noipa))
+foo (short a)
+{
+ long c = a;
+ unsigned f;
+ int d = 0, e;
+ for (; d < 6; d++) {
+ e = 0;
+ while (e < 6) {
+ e++;
+ f = c;
+ switch (f) {
+ case 1:
+ c = c + d;
+ case 3:
+ break;
+ default:
+ c = c + d;
+ }
+ }
+ }
+ return c;
+}
+
+int main()
+{
+ check_vect ();
+ if (foo (0) != 3)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/vect/vect-pr127391.c
b/gcc/testsuite/gcc.dg/vect/vect-pr127391.c
new file mode 100644
index 00000000000..b3d70171e85
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-pr127391.c
@@ -0,0 +1,28 @@
+/* { dg-additional-options "-O3" } */
+
+#include "tree-vect.h"
+
+int __attribute__((noipa))
+fn1 (void)
+{
+ int b = 0;
+ for (int f = 0; f < 16; f++)
+ switch (f % 3) {
+ case 2:
+ b += f;
+ break;
+ case 0:
+ b |= f;
+ case 1:
+ b |= f;
+ }
+ return b;
+}
+int main()
+{
+ check_vect ();
+ if (fn1 () != 63)
+ __builtin_abort ();
+ return 0;
+}
+
diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc
index fe749f94bd0..cc3e1dfb4ef 100644
--- a/gcc/tree-if-conv.cc
+++ b/gcc/tree-if-conv.cc
@@ -1170,7 +1170,8 @@ if_convertible_stmt_p (gimple *stmt,
vec<data_reference_p> refs)
return true;
case GIMPLE_SWITCH:
- return if_convertible_switch_p (as_a <gswitch *> (stmt));
+ /* Checked elsewhere. */
+ return true;
case GIMPLE_ASSIGN:
return if_convertible_gimple_assign_stmt_p (stmt, refs);
@@ -1708,7 +1709,9 @@ if_convertible_loop_p_1 (class loop *loop,
vec<data_reference_p> *refs)
}
/* Checking PHIs needs to be done after stmts, as the fact whether there
- are any masked loads or stores affects the tests. */
+ are any masked loads or stores affects the tests. Also check switch
+ stmts for supported shape as that cannot be skipped for always
+ executed blocks. */
for (i = 0; i < loop->num_nodes; i++)
{
basic_block bb = ifc_bbs[i];
@@ -1717,6 +1720,9 @@ if_convertible_loop_p_1 (class loop *loop,
vec<data_reference_p> *refs)
for (itr = gsi_start_phis (bb); !gsi_end_p (itr); gsi_next (&itr))
if (!if_convertible_phi_p (loop, bb, itr.phi ()))
return false;
+ if (gswitch *s = safe_dyn_cast <gswitch *> (*gsi_last_bb (bb)))
+ if (!if_convertible_switch_p (s))
+ return false;
}
if (dump_file)
--
2.51.0