https://gcc.gnu.org/g:028b8b62979f7e6326cb15ec8e519b1600e86a36

commit r17-4922-g028b8b62979f7e6326cb15ec8e519b1600e86a36
Author: Kyrylo Tkachov <[email protected]>
Date:   Fri Sep 11 16:31:01 2026 +0200

    cfgcleanup: keep tail merging out of an unfactored computed goto [PR127246]
    
    bbcb0c056be (PR15242) stopped try_crossjump_bb from sharing the tails of
    the predecessors of a computed jump unless optimizing for size.
    pass_duplicate_computed_gotos copies the jump back into each predecessor
    and a shared tail defeats that.  efd8f7507b3 replaced !optimize_size with
    optimize_bb_for_size_p (bb), which inverted the test: tails are now shared
    in code optimized for speed and kept apart in code optimized for size.
    
    Test the condition of the gate of pass_duplicate_computed_gotos instead,
    !optimize_function_for_size_p (cfun) && flag_expensive_optimizations.
    PR42621 fixed the bb-reorder half of the same change in that gate.  As
    in bbcb0c056be, the guard then applies to the whole function, also to a
    block that is too large to be unfactored.  try_head_merge_bb has a copy
    of the inverted test that cannot change code, because every successor
    edge of a computed jump is abnormal.  It stays as it is.
    
    On the PR127246 testcase with identical handler tails and
    -fno-tree-slp-vectorize, jump2 no longer crossjumps the handlers at -O2
    only for compgotos to copy the tails back.  With BB SLP the handlers jump
    to a block of vector copies in front of the dispatch, which is a separate
    problem of the PR.  At -Os the handler tails are shared again, which makes
    the aarch64 code of the PR testcase 54% smaller.  With
    -fno-expensive-optimizations, which disables the duplication, the tails
    are shared as well.
    
    Bootstrapped and regression tested on aarch64-unknown-linux-gnu and
    x86_64-pc-linux-gnu.
    
    gcc/ChangeLog:
    
            PR rtl-optimization/127246
            * cfgcleanup.cc (try_crossjump_bb): Keep the predecessors of a
            computed jump apart under the condition of the gate of
            pass_duplicate_computed_gotos.
    
    gcc/testsuite/ChangeLog:
    
            PR rtl-optimization/127246
            * gcc.dg/pr127246-1.c: New test.
            * gcc.dg/pr127246-2.c: New test.
            * gcc.dg/pr127246-3.c: New test.
    
    Signed-off-by: Kyrylo Tkachov <[email protected]>

Diff:
---
 gcc/cfgcleanup.cc                 |  8 ++++---
 gcc/testsuite/gcc.dg/pr127246-1.c | 48 +++++++++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr127246-2.c | 12 ++++++++++
 gcc/testsuite/gcc.dg/pr127246-3.c | 12 ++++++++++
 4 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/gcc/cfgcleanup.cc b/gcc/cfgcleanup.cc
index 1d9ec908dab0..f9178a92c392 100644
--- a/gcc/cfgcleanup.cc
+++ b/gcc/cfgcleanup.cc
@@ -2180,9 +2180,11 @@ try_crossjump_bb (int mode, basic_block bb)
   if (EDGE_COUNT (bb->preds) < 2)
     return false;
 
-  /* Don't crossjump if this block ends in a computed jump,
-     unless we are optimizing for size.  */
-  if (optimize_bb_for_size_p (bb)
+  /* Don't crossjump the predecessors of a computed jump when computed
+     gotos are duplicated (see pass_duplicate_computed_gotos::gate), as
+     that copies the jump back into each predecessor.  */
+  if (!optimize_function_for_size_p (cfun)
+      && flag_expensive_optimizations
       && bb != EXIT_BLOCK_PTR_FOR_FN (cfun)
       && computed_jump_p (BB_END (bb)))
     return false;
diff --git a/gcc/testsuite/gcc.dg/pr127246-1.c 
b/gcc/testsuite/gcc.dg/pr127246-1.c
new file mode 100644
index 000000000000..cfea56d631df
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr127246-1.c
@@ -0,0 +1,48 @@
+/* PR rtl-optimization/127246 */
+/* { dg-do compile } */
+/* { dg-require-effective-target label_values } */
+/* { dg-require-effective-target indirect_jumps } */
+/* { dg-options "-O2 -fno-tree-slp-vectorize -fdump-rtl-jump2-details" } */
+
+/* pass_duplicate_computed_gotos copies the dispatch back into every handler,
+   so tail merging must not share the identical handler tails in front of
+   it.  */
+
+struct frame
+{
+  const unsigned short *instr_ptr;
+  long *stackpointer;
+};
+
+#define OPS(X) \
+  X (0) X (1) X (2) X (3) X (4) X (5) X (6) X (7) X (8) X (9) X (10) \
+  X (11) X (12) X (13) X (14) X (15) X (16) X (17) X (18) X (19)
+
+extern long op (long);
+
+#define DISPATCH() goto *targets[*next_instr & 0xff]
+
+#define HANDLER(N) \
+  L_##N: \
+    frame->instr_ptr = next_instr; \
+    next_instr += 1; \
+    frame->stackpointer = stack_pointer; \
+    stack_pointer[-1] = op (N); \
+    stack_pointer -= 1; \
+    DISPATCH ();
+
+#define ENTRY(N) &&L_##N,
+
+void
+interp (struct frame *frame)
+{
+  static const void *const targets[] = { OPS (ENTRY) };
+  const unsigned short *next_instr = frame->instr_ptr;
+  long *stack_pointer = frame->stackpointer;
+
+  DISPATCH ();
+
+  OPS (HANDLER)
+}
+
+/* { dg-final { scan-rtl-dump-not "Cross jumping" "jump2" } } */
diff --git a/gcc/testsuite/gcc.dg/pr127246-2.c 
b/gcc/testsuite/gcc.dg/pr127246-2.c
new file mode 100644
index 000000000000..02328f04eab1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr127246-2.c
@@ -0,0 +1,12 @@
+/* PR rtl-optimization/127246 */
+/* { dg-do compile } */
+/* { dg-require-effective-target label_values } */
+/* { dg-require-effective-target indirect_jumps } */
+/* { dg-options "-Os -fdump-rtl-jump2-details" } */
+
+/* When optimizing for size the computed goto is not unfactored, so tail
+   merging the handler tails is what we want.  */
+
+#include "pr127246-1.c"
+
+/* { dg-final { scan-rtl-dump "Cross jumping" "jump2" } } */
diff --git a/gcc/testsuite/gcc.dg/pr127246-3.c 
b/gcc/testsuite/gcc.dg/pr127246-3.c
new file mode 100644
index 000000000000..a4da38da167c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr127246-3.c
@@ -0,0 +1,12 @@
+/* PR rtl-optimization/127246 */
+/* { dg-do compile } */
+/* { dg-require-effective-target label_values } */
+/* { dg-require-effective-target indirect_jumps } */
+/* { dg-options "-O2 -fno-expensive-optimizations -fno-tree-slp-vectorize 
-fdump-rtl-jump2-details" } */
+
+/* Without -fexpensive-optimizations computed gotos are not duplicated, so
+   tail merging the handler tails is what we want.  */
+
+#include "pr127246-1.c"
+
+/* { dg-final { scan-rtl-dump "Cross jumping" "jump2" } } */

Reply via email to