https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127983
--- Comment #5 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Jakub Jelinek <[email protected]>: https://gcc.gnu.org/g:30c751b18eaf6e72c6d1ecf46aa5e28122069a41 commit r17-5402-g30c751b18eaf6e72c6d1ecf46aa5e28122069a41 Author: Jakub Jelinek <[email protected]> Date: Tue Oct 20 12:09:47 2026 +0200 cse: Fix up cse_vec_duplicate_match optimization [PR127983] In this testcase we have: (insn 12 11 13 4 (set (reg:V4SI 108) (vec_duplicate:V4SI (reg/v:SI 104 [ s ]))) "pr127983.c":13:9 9532 {*vec_dupv4si} (nil)) ... (insn 15 14 16 4 (parallel [ (set (reg/v:SI 104 [ s ]) (plus:SI (reg/v:SI 104 [ s ]) (const_int 1 [0x1]))) (clobber (reg:CC 17 flags)) ]) "pr127983.c":14:8 288 {*addsi_1} (nil)) (insn 16 15 17 4 (set (reg:V8SI 109) (vec_duplicate:V8SI (reg/v:SI 104 [ s ]))) "pr127983.c":15:9 9543 {*vec_dupv8si} (nil)) and cse1 turns that since r17-2354 incorrectly into: (insn 16 11 12 4 (set (reg:V8SI 109) (vec_duplicate:V8SI (reg/v:SI 104 [ s ]))) "pr127983.c":15:9 9543 {*vec_dupv8si} (nil)) (insn 12 16 13 4 (set (reg:V4SI 108) (subreg:V4SI (reg:V8SI 109) 0)) "pr127983.c":13:9 2557 {movv4si_internal} (nil)) ... (insn 15 14 16 4 (parallel [ (set (reg/v:SI 104 [ s ]) (plus:SI (reg/v:SI 104 [ s ]) (const_int 1 [0x1]))) (clobber (reg:CC 17 flags)) ]) "pr127983.c":14:8 288 {*addsi_1} (nil)) (insn 17 15 18 4 (set (reg:V8SI 101 [ _2 ]) (reg:V8SI 109)) "pr127983.c":15:9 2556 {movv8si_internal} (expr_list:REG_DEAD (reg:V8SI 109) (nil))) That is wrong because pseudo 104 has been modified in between the two vec_duplicate insns. The optimization already works solely within each bb rather than ebb (it truncates vec_duplicate_cache at the start of each bb), so the current /* Safety check that WIDE_REG is not otherwise used or redefined before its original defining insn. */ if (reg_used_between_p (wide_reg, match.first_insn, match.widest_insn) || reg_set_between_p (wide_reg, match.first_insn, match.widest_insn)) continue; can work properly (on ebbs it would need to separately check in each bb along the ebb path I think). And to fix this bug we just need to also check whether scalar (a REG or SUBREG of a REG) hasn't changed in between. So that it isn't O(n^2) in case of many VEC_DUPLICATEs, this patch remembers the last corresponding VEC_DUPLICATE in the bb and only checks for reg_set_between_p since then. If the new member is NULL, it means the scalar has been or could have been modified and so we don't try to reuse/extend it anymore. Also, the if and else if conditions in the loop had some common subconditions, I've moved them to an outer if to avoid duplication, and finally the r17-2354 added code in cse_main had wrong indentation level, so I've reindented it. 2026-10-20 Jakub Jelinek <[email protected]> PR rtl-optimization/127983 * cse.cc (struct cse_vec_duplicate_match): Add last_checked_insn, initialize it in both constructors. Formatting fix. (cse_prescan_cache_vec_dup): Check common subconditions between if and else if once. Also give up if entry.last_checked_insn is NULL. If scalar is set in between last_checked_insn and insn, clear last_checked_insn and don't record a dup, otherwise update last_checked_insn. Adjust new_entry construction. (cse_main): Reindent the vec_duplicate_match code. * gcc.target/i386/avx2-pr127983.c: New test. Reviewed-by: Richard Biener <[email protected]>
