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;
+}

Reply via email to