diff mbox series

[committed,PR,rtl-optimization/87053.c] Keep EDGE_IGNORE from leading out of jump threader

Message ID b4227875-2e76-dd07-635d-f89f02f1488d@redhat.com
State New
Headers show
Series [committed,PR,rtl-optimization/87053.c] Keep EDGE_IGNORE from leading out of jump threader | expand

Commit Message

Jeff Law Nov. 24, 2018, 6:51 a.m. UTC
As mentioned in the BZ, EDGE_IGNORE is leaking out of the threader.

If we have a jump threading path through a block with one or more
EDGE_IGNORE outgoing edges, then the duplicate block's outgoing edges
will have the EDGE_IGNORE flag set.

I looked at doing the switch statement and edge cleanups earlier, but
it's just not going to fly.  That's too bad because it'd be cheaper to
copy the simplified block.  Oh well.

I considered adding the newly created block and edges to the queue of
things to clean up.  But that means having to share a vec across
elements (or copy it I guess).  It also meant some rather gross layering
violations.

So the final option was just to wipe the EDGE_IGNORE flag as we create
the duplicates, which is what this patch does.

Bootstrapped and regression tested on x86_64, ppc64le, ppc64, s390x
aarch64.  Also regression tested on a ton of *-elf targets.

Installing on the trunk.

jeff
diff mbox series

Patch

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b0b85bac352..f9a12f88a60 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@ 
+2018-11-23  Jeff Law  <law@redhat.com>
+
+	PR rtl-optimization/87468
+	* tree-ssa-threadupdate.c (create_block_for_threading): Clear
+	EDGE_IGNORE on all outgoing edges of the duplicate block.
+
 2018-11-23  Vladimir Makarov  <vmakarov@redhat.com>
 
 	PR bootstrap/88157
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e31d40d7924..587526e7443 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@ 
+2018-11-23  Jeff Law  <law@redhat.com>
+
+	PR rtl-optimization/84768
+	* gcc.c-torture/compile/pr84768.c: New test.
+
 2018-11-23  Vladimir Makarov  <vmakarov@redhat.com>
 
 	* gcc.target/powerpc/pr70669.c: Use unary minus instead of
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr87468.c b/gcc/testsuite/gcc.c-torture/compile/pr87468.c
new file mode 100644
index 00000000000..2f5cf80bf9f
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr87468.c
@@ -0,0 +1,15 @@ 
+a;
+b() {
+  int c = 1;
+  for (; c <= 3;) {
+    int d = e() && !0;
+    switch (c)
+    case 1:
+      if (d)
+      case 2:
+      case 3:
+        f();
+    if (a)
+      c++;
+  }
+}
diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c
index 6630516b99a..e7c7ca6fb15 100644
--- a/gcc/tree-ssa-threadupdate.c
+++ b/gcc/tree-ssa-threadupdate.c
@@ -336,7 +336,17 @@  create_block_for_threading (basic_block bb,
   rd->dup_blocks[count] = duplicate_block (bb, NULL, NULL);
 
   FOR_EACH_EDGE (e, ei, rd->dup_blocks[count]->succs)
-    e->aux = NULL;
+    {
+      e->aux = NULL;
+
+      /* If we duplicate a block with an outgoing edge marked as
+	 EDGE_IGNORE, we must clear EDGE_IGNORE so that it doesn't
+	 leak out of the current pass.
+
+	 It would be better to simplify switch statements and remove
+	 the edges before we get here, but the sequencing is nontrivial.  */
+      e->flags &= ~EDGE_IGNORE;
+    }
 
   /* Zero out the profile, since the block is unreachable for now.  */
   rd->dup_blocks[count]->count = profile_count::uninitialized ();