https://gcc.gnu.org/g:ab8d26c0d68f49841a8225be53a7f947fb664476
commit r17-5503-gab8d26c0d68f49841a8225be53a7f947fb664476 Author: Richard Biener <[email protected]> Date: Mon Oct 19 12:49:11 2026 +0200 middle-end/127981 - stack var conflicts for addresses live via PHIs Since r15-6655-g0014a858a14 add_scope_conflicts_1 processes the PHI results of a block with visit_op even when generating conflicts. visit_op only marks the stack variables as live without recording any conflicts with the variables already live on entry to the block. visit_conflict in turn only records conflicts when a variable becomes live for the first time in the block, so a variable whose address only reaches a block through a PHI argument never conflicts with variables that were already live coming in. For a block with multiple predecessors this is papered over by the merge handling which makes all live variables conflict with each other, but for a block with a single predecessor it is not. In the testcase we have <bb 2>: cr = &dl; ... <bb 8>: # dk_64 = PHI <&dj(2)> ... dj = 0; *cr.123_21 = &MEM <int[3]> [(void *)&cq + 8B]; ... _57 = *dk_64; and dj and dl end up sharing a stack slot, so the store through cr clobbers dj. Fix this by using visit (which is visit_conflict when generating conflicts) for PHI results again, like before r15-6655. PR middle-end/127981 * cfgexpand.cc (add_scope_conflicts_1): Use visit rather than visit_op for PHI results. * gcc.dg/torture/pr127981.c: New test. Diff: --- gcc/cfgexpand.cc | 2 +- gcc/testsuite/gcc.dg/torture/pr127981.c | 50 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc index 4bd311b11a34..32bc7bef4c8f 100644 --- a/gcc/cfgexpand.cc +++ b/gcc/cfgexpand.cc @@ -871,7 +871,7 @@ add_scope_conflicts_1 (vars_ssa_cache &cache, basic_block bb, bitmap work, bool /* Addresses coming into the bb via phis are alive at the entry point. */ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - add_scope_conflicts_2 (cache, gimple_phi_result (gsi_stmt (gsi)), work, visit_op); + add_scope_conflicts_2 (cache, gimple_phi_result (gsi_stmt (gsi)), work, visit); for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { diff --git a/gcc/testsuite/gcc.dg/torture/pr127981.c b/gcc/testsuite/gcc.dg/torture/pr127981.c new file mode 100644 index 000000000000..65103d8f177a --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr127981.c @@ -0,0 +1,50 @@ +/* PR middle-end/127981 */ +/* { dg-do run } */ +/* { dg-additional-options "-fgimple" } */ + +/* The address of x only becomes live in bb 3 through the PHI while y is + already live coming in from bb 2. Make sure x and y are recorded as + conflicting and do not share a stack slot. */ + +int **p; +int g; +int a[3]; + +short __GIMPLE (ssa,startwith("expand")) __attribute__((noipa)) +foo (int c) +{ + short x; + int *y; + short *q; + short _1; + int **_2; + + __BB(2): + p = &y; + if (c_3(D) != 0) + goto __BB3; + else + goto __BB4; + + __BB(3): + q_4 = __PHI (__BB2: &x); + y = &g; + x = _Literal (short) 0; + _2 = p; + *_2 = &a[2]; + _1 = *q_4; + x = __CLOBBER(eos); + y = __CLOBBER(eos); + return _1; + + __BB(4): + return _Literal (short) 1; +} + +int +main () +{ + if (foo (1) != 0) + __builtin_abort (); + return 0; +}
