]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cfgexpand: Verify that partitions do not share a MEM_EXPR [PR126405]
authorKyrylo Tkachov <ktkachov@nvidia.com>
Sun, 26 Jul 2026 10:18:46 +0000 (03:18 -0700)
committerKyrylo Tkachov <ktkachov@nvidia.com>
Tue, 28 Jul 2026 07:19:20 +0000 (09:19 +0200)
Two stack slots carrying one MEM_EXPR read as a single object to
MEM_EXPR-based disambiguation.  That is how PR121957, PR123625 and PR126405
each became wrong code: the load/store pair-fusion pass identifies a location
by a MEM_EXPR base and an offset from it, so it fused accesses that belong to
different slots and redirected a store.

out-of-SSA maintains the invariant, but a break in it stays silent until some
consumer acts on it, and only for the subset of functions that consumer happens
to look at.
Check it directly once per function under flag_checking, after every partition
has been given its RTL, so that a regression here is an ICE rather than a
miscompile.

Bootstrapped and tested on aarch64-none-linux-gnu and x86_64-linux-gnu.

gcc/ChangeLog:

PR middle-end/126405
* cfgexpand.cc (verify_partition_mem_exprs): New function.
(pass_expand::execute): Call it.

Signed-off-by: Kyrylo Tkachov <ktkachov@nvidia.com>
gcc/cfgexpand.cc

index 8b6b5b923ee0a83f62c5bddd6acc987c072975d7..9c56b928376e1823395d1d36fdc5ed5e255e0e3d 100644 (file)
@@ -2462,6 +2462,31 @@ stack_protect_return_slot_p ()
   return false;
 }
 
+/* Verify that partitions which claim to be the same object really are at the
+   same address.  MEM_EXPR-based disambiguation identifies a location by a
+   MEM_EXPR base and an offset from it, so two stack slots carrying one
+   MEM_EXPR read as a single object, which lets an access to one be redirected
+   to the other.  out-of-SSA keeps them apart, see the comment above
+   split_overlapping_partition_decls.  */
+
+static void
+verify_partition_mem_exprs (void)
+{
+  hash_map<tree, rtx> slots;
+  for (unsigned i = 0; i < num_var_partitions (SA.map); i++)
+    {
+      rtx x = SA.partition_to_pseudo[i];
+      if (!x || !MEM_P (x) || !MEM_EXPR (x))
+       continue;
+      bool existed;
+      rtx &known = slots.get_or_insert (MEM_EXPR (x), &existed);
+      if (!existed)
+       known = x;
+      else
+       gcc_assert (rtx_equal_p (XEXP (known, 0), XEXP (x, 0)));
+    }
+}
+
 /* Expand all variables used in the function.  */
 
 static rtx_insn *
@@ -7172,6 +7197,9 @@ pass_expand::execute (function *fun)
       adjust_one_expanded_partition_var (name);
     }
 
+  if (flag_checking)
+    verify_partition_mem_exprs ();
+
   /* Clean up RTL of variables that straddle across multiple
      partitions, and check that the rtl of any PARM_DECLs that are not
      cleaned up is that of their default defs.  */