[gcc r17-3214] Thread paths ending in a computed goto
Aldy Hernandez via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:218575554420ded75052e56d5a89cd23522f20a7 commit r17-3214-g218575554420ded75052e56d5a89cd23522f20a7 Author: Aldy Hernandez <[email protected]> Date: Tue Aug 11 08:36:36 2026 +0000 Thread paths ending in a computed goto 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. 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. Diff: --- gcc/testsuite/gcc.dg/pr89737.c | 2 +- .../gcc.dg/tree-ssa/backthread-computed-goto-1.c | 24 ++++++++++++++ .../gcc.dg/tree-ssa/backthread-computed-goto-3.c | 24 ++++++++++++++ gcc/tree-ssa-threadbackward.cc | 37 +++++++++++++++++++++- 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/gcc/testsuite/gcc.dg/pr89737.c b/gcc/testsuite/gcc.dg/pr89737.c index 7dc48cdce980..301da26175e9 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 000000000000..c768b639b440 --- /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 000000000000..25476943c790 --- /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 895b2fa81648..77726ba66cd9 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;