https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126236
--- Comment #9 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Kyrylo Tkachov <[email protected]>: https://gcc.gnu.org/g:b38631a6013f872940857bcc935f56db0b5f427a commit r17-5805-gb38631a6013f872940857bcc935f56db0b5f427a Author: Kyrylo Tkachov <[email protected]> Date: Thu Oct 15 20:06:37 2026 +0200 config: Opt out of shared jump tables where dispatch needs adjacency [PR middle-end/126236] Several ports dispatch through a table that has to follow the jump, or compute the table entries from the address of the jump. A copy of such a dispatch elsewhere in the function would branch to the wrong place, fail to assemble or break a machine reorg pass. These ports refuse to share jump tables: - arm: Thumb-2 tbb and tbh read the table at the PC, the Thumb-1 casesi helpers find it from LR, and the Arm casesi sequence defines a base label after each dispatch. arm_reorg also expects every table to follow its jump. - cris: casesi reads the table at its own PC, and cris_asm_output_case_end expects the jump right before the table label. - m68k: the relative dispatch forms read the table at a fixed offset from the PC. - sh: fixup_addr_diff_vecs makes the entries relative to the braf of one dispatch, and sh_reorg pairs every table with one mova. - xstormy16: the dispatch branches into a table of jmpf insns that follows it. - vax: the casel table is part of the instruction. These ports refuse only some forms: - pa: with PIC, which includes all 64-bit code, casesi32p and casesi64p reach the table with one ldo from their own address. Its displacement only reaches a table close to the jump. casesi32 loads the address of the table and can share it. - c6x: with PIC, casesi_internal reaches the table with addkpc, which only covers about 256 bytes. - mips: with MIPS16 short jump tables, the length of the casesi dispatch assumes the short ADDIUPC form of the la of the table, which only a nearby table guarantees. - csky: with -mconstpool, which CK801 and CK802 require, the constant pool scan steps from every tablejump to the table that follows it. - arc: the bi and bih dispatches of -mbranch-index branch into a table of branches that follows them. - rx: with -mpid or -fpic, the table entries are relative to a local label that the dispatch defines. The port maintainers can refine these predicates later. gcc/ChangeLog: PR middle-end/126236 * config/arc/arc.cc (arc_can_share_jump_table_p): New function. (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/arm/arm.cc (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/c6x/c6x.cc (c6x_can_share_jump_table_p): New function. (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/cris/cris.cc (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/csky/csky.cc (csky_can_share_jump_table_p): New function. (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/m68k/m68k.cc (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/mips/mips.cc (mips_can_share_jump_table_p): New function. (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/pa/pa.cc (pa_can_share_jump_table_p): New function. (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/rx/rx.cc (rx_can_share_jump_table_p): New function. (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/sh/sh.cc (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/stormy16/stormy16.cc (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. * config/vax/vax.cc (TARGET_CAN_SHARE_JUMP_TABLE_P): Define. Signed-off-by: Kyrylo Tkachov <[email protected]> --- Comment #10 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Kyrylo Tkachov <[email protected]>: https://gcc.gnu.org/g:87b07d2a5edc6b97f816b8b2f16bc3d13031f439 commit r17-5806-g87b07d2a5edc6b97f816b8b2f16bc3d13031f439 Author: Kyrylo Tkachov <[email protected]> Date: Thu Oct 15 20:11:38 2026 +0200 bb-reorder: Unfactor loop switch dispatches [PR middle-end/126236] A bytecode interpreter written with a switch at its loop head normally has one jump-table dispatch. Every opcode transition returns to the same indirect branch instruction. This can make indirect target prediction less effective. The existing compgotos pass already gives each eligible predecessor its own computed goto. Apply the same transformation to the jump-table form. The guarded tablejump is a short chain rather than one block: handler -> fetch and range check -> tablejump Collect the single-predecessor fall-through chain and copy it into eligible predecessors. Take a block into the chain only through a plain fall-through edge: a jump at its end that also targets the next block would still name the original block after the edge moves to the copy. The copies share the table through the representation added by the cfgrtl patch. Require a direct DFS back edge into the collected chain head before the first tablejump duplication. This limits the new transformation to a loop head. Recursive copies do not repeat the test. Computed gotos keep their existing behavior. Use the existing max-goto-duplication-insns budget. Charge the tablejump as one budget unit and every other instruction at its size, as for computed gotos. A zero budget rejects the transformation. Require the target's can_share_jump_table_p hook to permit sharing and reject partitioned functions. Reject functions that use stack registers. Stack-register conversion can split outgoing edges to reconcile different stack layouts, but a shared-table edge cannot be changed for only one dispatch. Set PROP_rtl_allow_tablejump_duplication only while the pass scans and copies dispatches. Clear it before CFG cleanup and before any later pass runs. switch-dispatch-run-5.c sends every dispatch copy to every case and to out-of-range values, and checks the exact path with a trace. run-6.c and run-7.c give handlers enough code that some copies are far from the table, with and without PIC. run-8.c has an asm goto that targets its own fall-through block above the switch. switch-dispatch-hwloop.c and the bfin and xtensa tests reach a hardware loop through a shared table. In switch-dispatch-placement.c the original dispatch is deleted after a noreturn call or a return, so its table has to move. switch-dispatch-4.c checks that both tables of the trace test are shared on the targets that the new shared_jump_tables effective target lists. Plugin tests check per-function target options, the default hook result, existing instruction-copy vetoes, and output after eligibility becomes false. On an NVIDIA Vera system, explicit enablement improves 714.cpython_r by 10.3%, mawk by 6.9%, and QuickJS-ng by 24.9%. gcc/ChangeLog: PR middle-end/126236 * common.opt (fduplicate-switch-dispatch): New option. * doc/invoke.texi: Document it. * doc/params.texi (max-goto-duplication-insns): Mention switch dispatches. * doc/sourcebuild.texi (shared_jump_tables): Document. * params.opt (max-goto-duplication-insns): Mention switch dispatches. * common.opt.urls: Regenerate. * bb-reorder.cc (dispatch_jump_p): New function. (can_attach_dispatch_copy_p): New function. (fallthru_unified_with_branch_p): New function. (find_dispatch_chain): New function. (maybe_duplicate_computed_goto): Rename to... (maybe_duplicate_dispatch): ...this. Copy a dispatch chain and optionally require a DFS back edge into its head. (duplicate_computed_gotos): Mark DFS back edges, select eligible tablejumps, and scope PROP_rtl_allow_tablejump_duplication. gcc/testsuite/ChangeLog: PR middle-end/126236 * lib/target-supports.exp (check_effective_target_shared_jump_tables): New. * gcc.dg/plugin/plugin.exp: Register the capability test. * gcc.dg/plugin/tablejump_capability_plugin.cc: New plugin. * gcc.dg/plugin/tablejump-capability.c: New test. * gcc.dg/plugin/tablejump-test.h: New test header. * gcc.dg/switch-dispatch-2.c: New test. * gcc.dg/switch-dispatch-3.c: New test. * gcc.dg/switch-dispatch-4.c: New test. * gcc.dg/torture/switch-dispatch-run-1.c: New test. * gcc.dg/torture/switch-dispatch-run-2.c: New test. * gcc.dg/torture/switch-dispatch-run-3.c: New test. * gcc.dg/torture/switch-dispatch-run-4.c: New test. * gcc.dg/torture/switch-dispatch-run-5.c: New test. * gcc.dg/torture/switch-dispatch-run-6.c: New test. * gcc.dg/torture/switch-dispatch-run-7.c: New test. * gcc.dg/torture/switch-dispatch-run-8.c: New test. * gcc.dg/torture/switch-dispatch-hwloop.c: New test. * gcc.dg/torture/switch-dispatch-placement.c: New test. * gcc.target/bfin/switch-dispatch-1.c: New test. * gcc.target/xtensa/switch-dispatch-1.c: New test. * gcc.target/aarch64/switch-dispatch-1.c: New test. * gcc.target/aarch64/switch-dispatch-2.c: New test. * gcc.target/aarch64/switch-dispatch-3.c: New test. * gcc.target/aarch64/switch-dispatch-4.c: New test. * gcc.target/aarch64/switch-dispatch-5.c: New test. * gcc.target/aarch64/switch-dispatch-6.c: New test. * gcc.target/aarch64/switch-dispatch-7.c: New test. Signed-off-by: Kyrylo Tkachov <[email protected]>
