[gcc r16-9422] ifcvt: Reject hard-register destinations in multiple sets [PR126184]
Kyrylo Tkachov via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:9226f469f9e19783ac2d7fbb7498d73f75e079ac commit r16-9422-g9226f469f9e19783ac2d7fbb7498d73f75e079ac Author: Kyrylo Tkachov <[email protected]> Date: Wed Jul 22 16:45:16 2026 +0200 ifcvt: Reject hard-register destinations in multiple sets [PR126184] noce_convert_multiple_sets keys its dependency information by destination register number. Hard registers can have overlapping definitions in different modes. An exact RTL replacement cannot represent the value from a partial or mode-changing definition. Reject hard-register destinations in the block eligibility check. Assert the resulting pseudo-only invariant when dependency information is initialized. Add an RTL execution test with mixed-mode hard-register definitions. It verifies that the block remains unconverted. Bootstrapped and regtested on aarch64-none-linux-gnu and x86_64-pc-linux-gnu. gcc/ChangeLog: PR rtl-optimization/126184 * ifcvt.cc (init_noce_multiple_sets_info): Assert that destinations are pseudos. (bb_ok_for_noce_convert_multiple_sets): Reject hard-register destinations. gcc/testsuite/ChangeLog: PR rtl-optimization/126184 * gcc.target/aarch64/pr126184-2.c: New test. Signed-off-by: Kyrylo Tkachov <[email protected]> (cherry picked from commit 7b4d5b42a78859b30c9b48fa0a426effbbd71ff7) Diff: --- gcc/ifcvt.cc | 14 +++-- gcc/testsuite/gcc.target/aarch64/pr126184-2.c | 75 +++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc index c151146c1b22..6f5aa72681bc 100644 --- a/gcc/ifcvt.cc +++ b/gcc/ifcvt.cc @@ -4156,7 +4156,7 @@ init_noce_multiple_sets_info (basic_block bb, rtx src = SET_SRC (set); rtx dest = SET_DEST (set); - gcc_checking_assert (REG_P (dest)); + gcc_checking_assert (REG_P (dest) && !HARD_REGISTER_P (dest)); info->need_cmov = bitmap_bit_p (bb_live_out, REGNO (dest)); /* Check if the current SET's source is the same @@ -4201,10 +4201,14 @@ bb_ok_for_noce_convert_multiple_sets (basic_block test_bb, unsigned *cost) rtx dest = SET_DEST (set); rtx src = SET_SRC (set); - /* Do not handle anything involving memory loads/stores since it might - violate data-race-freedom guarantees. Make sure we can force SRC - to a register as that may be needed in try_emit_cmove_seq. */ - if (!REG_P (dest) || contains_mem_rtx_p (src) + /* Dependency rewiring is keyed by register number, so restrict + destinations to pseudos. Hard-register definitions can overlap + without having the same mode. Do not handle anything involving + memory loads/stores since it might violate data-race-freedom + guarantees. Make sure we can force SRC to a register as that may + be needed in try_emit_cmove_seq. */ + if (!REG_P (dest) || HARD_REGISTER_P (dest) + || contains_mem_rtx_p (src) || !noce_can_force_operand (src)) return false; diff --git a/gcc/testsuite/gcc.target/aarch64/pr126184-2.c b/gcc/testsuite/gcc.target/aarch64/pr126184-2.c new file mode 100644 index 000000000000..5e0274660413 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/pr126184-2.c @@ -0,0 +1,75 @@ +/* PR rtl-optimization/126184 */ +/* { dg-do run } */ +/* { dg-options "-O2 --param=max-rtl-if-conversion-unpredictable-cost=100 -fdump-rtl-ce1" } */ + +/* Mixed-mode hard-register definitions cannot be rewired through a single + temporary. Verify that the multi-set conversion rejects the block. */ + +unsigned long long __RTL (startwith ("ce1")) +f (unsigned long long c, unsigned long long x, unsigned long long y) +{ +(function "f" + (param "c" (DECL_RTL (reg/v:DI x4 [ c ])) + (DECL_RTL_INCOMING (reg/v:DI x0 [ c ]))) + (param "x" (DECL_RTL (reg/v:DI <1> [ x ])) + (DECL_RTL_INCOMING (reg/v:DI x1 [ x ]))) + (param "y" (DECL_RTL (reg/v:DI <2> [ y ])) + (DECL_RTL_INCOMING (reg/v:DI x2 [ y ]))) + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cinsn 2 (set (reg/v:DI x4 [ c ]) (reg:DI x0))) + (cinsn 3 (set (reg/v:DI <1> [ x ]) (reg:DI x1))) + (cinsn 4 (set (reg/v:DI <2> [ y ]) (reg:DI x2))) + (cinsn 5 (set (reg:DI <3>) + (plus:DI (reg/v:DI <1>) (const_int 11)))) + (cinsn 6 (set (reg:DI <4>) + (plus:DI (reg/v:DI <2>) (const_int -2)))) + (cinsn 7 (set (reg:CC cc) + (compare:CC (reg/v:DI x4) (const_int 0)))) + (cjump_insn 8 (set (pc) + (if_then_else (eq (reg:CC cc) (const_int 0)) + (label_ref 30) (pc)))) + (edge-to 3 (flags "FALLTHRU")) + (edge-to 4) + ) + (block 3 + (edge-from 2 (flags "FALLTHRU")) + (cnote 9 [bb 3] NOTE_INSN_BASIC_BLOCK) + (cinsn 10 (set (reg/v:DI x4 [ c ]) + (plus:DI (reg/v:DI <1>) (const_int 1)))) + (cinsn 11 (set (reg:DI <3>) + (plus:DI (reg/v:DI x4) (reg/v:DI <2>)))) + (cinsn 12 (set (reg:SI x4) (const_int 26))) + (cinsn 13 (set (reg:DI <4>) + (plus:DI (reg/v:DI x4) (reg/v:DI <1>)))) + (edge-to 4 (flags "FALLTHRU")) + ) + (block 4 + (edge-from 2) + (edge-from 3 (flags "FALLTHRU")) + (clabel 30 2) + (cnote 31 [bb 4] NOTE_INSN_BASIC_BLOCK) + (cinsn 32 (set (reg:DI <5>) + (plus:DI (reg:DI <3>) (reg:DI <4>)))) + (cinsn 33 (set (reg/i:DI x0) (reg:DI <5>))) + (cinsn 34 (use (reg/i:DI x0))) + (edge-to exit (flags "FALLTHRU")) + ) + ) + (crtl (return_rtx (reg/i:DI x0))) +) +} + +int +main (void) +{ + if (f (7, 13, 17) != 70) + __builtin_abort (); + if (f (0, 13, 17) != 39) + __builtin_abort (); + return 0; +} + +/* { dg-final { scan-rtl-dump-not "if-conversion succeeded through noce_convert_multiple_sets" "ce1" } } */