Hi,
This fixes a 6/7/8 regression, a P3 ICE in the tail-merge pass.
Consider the test-case from the patch.
When compiling at -O2, duplicates are found in tail-merge:
...
find_duplicates: <bb 6> duplicate of <bb 7>
find_duplicates: <bb 6> duplicate of <bb 9>
...
So, tail-merge calls replace_block_by (bb7, bb6).
However, bb7 has an abnormal edge bb5 -> bb7 as predecessor (bb6 has an
abnormal edge as predecessor as well, but that doesn't look necessary to
trigger the ICE):
...
;; basic block 9, loop depth 0
;; prev block 3, next block 4, flags: (NEW, REACHABLE)
;; pred: 3 [50.0% (guessed)] (FALSE_VALUE,EXECUTABLE)
goto <bb 8>; [100.00%]
;; succ: 8 [always] (FALLTHRU,EXECUTABLE)
;; basic block 6, loop depth 0
;; prev block 5, next block 7, flags: (NEW, REACHABLE, VISITED)
;; pred: 5 [33.3% (guessed)] (ABNORMAL,EXECUTABLE)
goto <bb 8>; [100.00%]
;; succ: 8 [always] (FALLTHRU,EXECUTABLE)
;; basic block 7, loop depth 0
;; prev block 6, next block 8, flags: (NEW, REACHABLE, VISITED)
;; pred: 5 [33.3% (guessed)] (ABNORMAL,EXECUTABLE)
;; succ: 8 [always] (FALLTHRU,EXECUTABLE)
...
So when replace_block_by calls redirect_edge_and_branch (bb5 -> bb7,
bb6) it lands in gimple_redirect_edge_and_branch, and fails here:
...
6024 if (e->flags & EDGE_ABNORMAL)
6025 return NULL;
...
which causes this assert to trigger:
...
gcc_assert (pred_edge != NULL);
...
The patch fixes the ICE conservatively by skipping bbs with
bb_has_abnormal_preds in find_clusters_1.
[ A more optimal fix could be to detect in this example that there's an
abnormal edge bb5 -> bb6, and skip redirecting bb5 -> bb7 to bb6. ]
Bootstrapped and reg-tested on x86_64.
OK for stage4, gcc-6-branch and gcc-7-branch?
Thanks,
- Tom
[tail-merge] Don't merge bbs with bb_has_abnormal_pred
2018-03-21 Tom de Vries <t...@codesourcery.com>
PR tree-optimization/84956
* tree-ssa-tail-merge.c (find_clusters_1): Skip bbs with
bb_has_abnormal_pred.
* gcc.dg/pr84956.c: New test.
---
gcc/testsuite/gcc.dg/pr84956.c | 27 +++++++++++++++++++++++++++
gcc/tree-ssa-tail-merge.c | 6 ++++--
2 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/gcc/testsuite/gcc.dg/pr84956.c b/gcc/testsuite/gcc.dg/pr84956.c
new file mode 100644
index 0000000..055a749
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr84956.c
@@ -0,0 +1,27 @@
+/* { dg-options "-O2 -ftree-tail-merge" } */
+
+char a;
+int c;
+unsigned b ();
+
+unsigned
+setjmp ()
+{
+}
+
+static void
+d ()
+{
+ if (b ())
+ c = 3;
+}
+
+void
+e ()
+{
+ d ();
+ a && ({ setjmp (); });
+ a && ({ setjmp (); });
+ a && ({ setjmp (); });
+}
+
diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index a687c3f..f482ce1 100644
--- a/gcc/tree-ssa-tail-merge.c
+++ b/gcc/tree-ssa-tail-merge.c
@@ -1455,7 +1455,8 @@ find_clusters_1 (same_succ *same_succ)
/* TODO: handle blocks with phi-nodes. We'll have to find corresponding
phi-nodes in bb1 and bb2, with the same alternatives for the same
preds. */
- if (bb_has_non_vop_phi (bb1) || bb_has_eh_pred (bb1))
+ if (bb_has_non_vop_phi (bb1) || bb_has_eh_pred (bb1)
+ || bb_has_abnormal_pred (bb1))
continue;
nr_comparisons = 0;
@@ -1463,7 +1464,8 @@ find_clusters_1 (same_succ *same_succ)
{
bb2 = BASIC_BLOCK_FOR_FN (cfun, j);
- if (bb_has_non_vop_phi (bb2) || bb_has_eh_pred (bb2))
+ if (bb_has_non_vop_phi (bb2) || bb_has_eh_pred (bb2)
+ || bb_has_abnormal_pred (bb2))
continue;
if (BB_CLUSTER (bb1) != NULL && BB_CLUSTER (bb1) == BB_CLUSTER (bb2))