The backward threader only handles paths ending in a GIMPLE_COND or
GIMPLE_SWITCH, even though the profitability code and the generic
copier already accounts for GIMPLE_GOTO. When we rewrote the
backwards threader, the GIMPLE_GOTO handling was silently dropped
because (a) ranger couldn't handle symbolics (b) DOM was picking our
slack. Now with DOM removal in our sights, we need to handle computed
gotos. This has been made trivial, by the recent work in prange
providing points-to info.
Note that a destination occurring in an abnormal PHI (when the goto
block is itself one of the goto's targets) is still not handled. I'll
be working on abnormal edge handling as a follow-up.
Tested on ppc64le Linux.
Pushed.
gcc/ChangeLog:
PR tree-optimization/126103
* tree-ssa-threadbackward.cc (class back_threader): Add
find_taken_edge_goto.
(back_threader::find_taken_edge): Handle GIMPLE_GOTO.
(back_threader::find_taken_edge_goto): New.
(back_threader::maybe_thread_block): Handle GIMPLE_GOTO.
gcc/testsuite/ChangeLog:
PR tree-optimization/126103
* gcc.dg/pr89737.c: Add -fno-thread-jumps.
* gcc.dg/tree-ssa/backthread-computed-goto-1.c: New test.
* gcc.dg/tree-ssa/backthread-computed-goto-3.c: New test.
---
gcc/testsuite/gcc.dg/pr89737.c | 2 +-
.../tree-ssa/backthread-computed-goto-1.c | 24 ++++++++++++
.../tree-ssa/backthread-computed-goto-3.c | 24 ++++++++++++
gcc/tree-ssa-threadbackward.cc | 37 ++++++++++++++++++-
4 files changed, 85 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/backthread-computed-goto-1.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/backthread-computed-goto-3.c
diff --git a/gcc/testsuite/gcc.dg/pr89737.c b/gcc/testsuite/gcc.dg/pr89737.c
index 7dc48cdce98..301da26175e 100644
--- a/gcc/testsuite/gcc.dg/pr89737.c
+++ b/gcc/testsuite/gcc.dg/pr89737.c
@@ -1,7 +1,7 @@
/* { dg-do compile } */
/* { dg-require-effective-target indirect_jumps } */
/* { dg-require-effective-target label_values } */
-/* { dg-options "-O2 -fdump-tree-profile_estimate" } */
+/* { dg-options "-O2 -fno-thread-jumps -fdump-tree-profile_estimate" } */
int a, b;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/backthread-computed-goto-1.c
b/gcc/testsuite/gcc.dg/tree-ssa/backthread-computed-goto-1.c
new file mode 100644
index 00000000000..c768b639b44
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/backthread-computed-goto-1.c
@@ -0,0 +1,24 @@
+/* PR tree-optimization/126103 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdisable-tree-ethread -fdump-tree-threadfull1-details" }
*/
+
+/* Both predecessors of the computed goto block know the destination
+ label exactly, so the backward threader must thread both paths
+ through it. */
+
+int
+f (int a)
+{
+ void *p;
+ if (a)
+ p = &&L0;
+ else
+ p = &&L1;
+ goto *p;
+L0:
+ return 1;
+L1:
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "Registering jump thread" 2 "threadfull1"
} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/backthread-computed-goto-3.c
b/gcc/testsuite/gcc.dg/tree-ssa/backthread-computed-goto-3.c
new file mode 100644
index 00000000000..25476943c79
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/backthread-computed-goto-3.c
@@ -0,0 +1,24 @@
+/* PR tree-optimization/126103 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ethread-details" } */
+
+/* Like backthread-computed-goto-1.c, but check that the early
+ threader, which runs without ranger resolution, already threads
+ both predecessors of the computed goto. */
+
+int
+f (int a)
+{
+ void *p;
+ if (a)
+ p = &&L0;
+ else
+ p = &&L1;
+ goto *p;
+L0:
+ return 1;
+L1:
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "Registering jump thread" 2 "ethread" } }
*/
diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc
index 895b2fa8164..77726ba66cd 100644
--- a/gcc/tree-ssa-threadbackward.cc
+++ b/gcc/tree-ssa-threadbackward.cc
@@ -112,6 +112,7 @@ private:
edge find_taken_edge (const vec<basic_block> &path);
edge find_taken_edge_cond (const vec<basic_block> &path, gcond *);
edge find_taken_edge_switch (const vec<basic_block> &path, gswitch *);
+ edge find_taken_edge_goto (const vec<basic_block> &path, ggoto *);
virtual void debug ();
virtual void dump (FILE *out);
@@ -280,11 +281,44 @@ back_threader::find_taken_edge (const vec<basic_block>
&path)
case GIMPLE_SWITCH:
return find_taken_edge_switch (path, as_a<gswitch *> (m_last_stmt));
+ case GIMPLE_GOTO:
+ return find_taken_edge_goto (path, as_a<ggoto *> (m_last_stmt));
+
default:
return NULL;
}
}
+// Same as find_taken_edge, but for paths ending in a computed goto.
+
+edge
+back_threader::find_taken_edge_goto (const vec<basic_block> &path,
+ ggoto *stmt)
+{
+ tree dest = gimple_goto_dest (stmt);
+
+ if (TREE_CODE (dest) == SSA_NAME)
+ {
+ prange r;
+ path_range_query solver (*m_ranger, path, m_imports,
+ m_flags & BT_RESOLVE);
+ if (!solver.range_of_expr (r, dest, stmt))
+ return NULL;
+
+ if (r.undefined_p ())
+ return UNREACHABLE_EDGE;
+
+ dest = r.pt_invariant ();
+ if (!dest)
+ return NULL;
+ }
+
+ // For a destination that did not resolve to a label,
+ // ::find_taken_edge at most returns the block's single successor,
+ // the only place it could go.
+ return ::find_taken_edge (gimple_bb (stmt), dest);
+}
+
// Same as find_taken_edge, but for paths ending in a switch.
edge
@@ -515,7 +549,8 @@ back_threader::maybe_thread_block (basic_block bb)
enum gimple_code code = gimple_code (stmt);
if (code != GIMPLE_SWITCH
- && code != GIMPLE_COND)
+ && code != GIMPLE_COND
+ && code != GIMPLE_GOTO)
return;
m_last_stmt = stmt;
--
2.47.3