https://gcc.gnu.org/g:9892eb566c4cbf6feba50c7d98b10ea8c204018a

commit r17-664-g9892eb566c4cbf6feba50c7d98b10ea8c204018a
Author: Konstantinos Eleftheriou <[email protected]>
Date:   Tue Mar 24 13:21:38 2026 +0100

    avoid-store-forwarding: Remove unnecessary store_exprs_del mechanism
    
    The store_exprs_del vector was introduced in the PR119795 fix as a
    conservative safety measure alongside the actual bug fixes (adding
    forwardings.truncate(0) on vector mismatch and true_dependence
    detection).  It tracks deleted store candidates and blocks forwarding
    when a deleted store's range overlaps with the load.
    
    However, this check is not needed for correctness.  In the non-load-
    elimination path the load is kept and reads all bytes from memory;
    the bit-insert only overwrites forwarded bytes.  Deleted stores remain
    in the instruction stream, so their memory effects are visible to the
    load.  In the load-elimination path, all bytes must be covered by
    forwarded stores (enforced by the bitmap check), so missing stores
    cannot cause partial updates.
    
    The vector grows monotonically through the basic block and is scanned
    for each forwarding candidate, producing O(n^2) behavior for large
    basic blocks.
    
    Remove the mechanism entirely.  This eliminates the O(n^2) scan and
    simplifies the code.
    
    gcc/ChangeLog:
    
            * avoid-store-forwarding.cc
            (store_forwarding_analyzer::avoid_store_forwarding): Remove
            store_exprs_del vector and all associated tracking.  Remove the
            same_range_as_removed check from the forwarding loop.  Update
            block comment.

Diff:
---
 gcc/avoid-store-forwarding.cc | 70 ++++++++++++-------------------------------
 1 file changed, 19 insertions(+), 51 deletions(-)

diff --git a/gcc/avoid-store-forwarding.cc b/gcc/avoid-store-forwarding.cc
index 260c135c219f..83abdd49ba9c 100644
--- a/gcc/avoid-store-forwarding.cc
+++ b/gcc/avoid-store-forwarding.cc
@@ -435,22 +435,20 @@ store_forwarding_analyzer::avoid_store_forwarding 
(basic_block bb)
     return;
 
   auto_vec<store_fwd_info, 8> store_exprs;
-  auto_vec<rtx> store_exprs_del;
   rtx_insn *insn;
   unsigned int insn_cnt = 0;
 
-  /* We are iterating over the basic block's instructions detecting store
-     instructions.  Upon reaching a load instruction, we check if any of the
-     previously detected stores could result in store forwarding.  In that
-     case, we try to reorder the load and store instructions.
-     We skip this transformation when we encounter complex memory operations,
-     instructions that might throw an exception, instruction dependencies,
-     etc.  This is done by clearing the vector of detected stores, while
-     keeping the removed stores in another vector.  By doing so, we can check
-     if any of the removed stores operated on the load's address range, when
-     reaching a subsequent store that operates on the same address range,
-     as this would lead to incorrect values on the register that keeps the
-     loaded value.  */
+  /* Iterate over the basic block's instructions detecting store instructions.
+     Upon reaching a load instruction, check if any of the previously detected
+     stores could result in store forwarding.  In that case, try to reorder
+     the load and store instructions.  When we encounter instructions that
+     might throw an exception, instruction dependencies, etc., clear the
+     vector of detected stores and continue.
+
+     Invariant: dropping a candidate from store_exprs (via it->remove or
+     truncate) only removes it from the forwarding list; the store insn
+     stays in the IR so later loads read its effect from memory.  Only
+     process_store_forwarding may delete the original store.  */
   FOR_BB_INSNS (bb, insn)
     {
       if (!NONDEBUG_INSN_P (insn))
@@ -463,10 +461,6 @@ store_forwarding_analyzer::avoid_store_forwarding 
(basic_block bb)
 
       if (!set || insn_could_throw_p (insn))
        {
-         unsigned int i;
-         store_fwd_info *it;
-         FOR_EACH_VEC_ELT (store_exprs, i, it)
-           store_exprs_del.safe_push (it->store_mem);
          store_exprs.truncate (0);
          continue;
        }
@@ -490,10 +484,6 @@ store_forwarding_analyzer::avoid_store_forwarding 
(basic_block bb)
          || (load_mem && (!MEM_SIZE_KNOWN_P (load_mem)
                           || !MEM_SIZE (load_mem).is_constant ())))
        {
-         unsigned int i;
-         store_fwd_info *it;
-         FOR_EACH_VEC_ELT (store_exprs, i, it)
-           store_exprs_del.safe_push (it->store_mem);
          store_exprs.truncate (0);
          continue;
        }
@@ -545,7 +535,6 @@ store_forwarding_analyzer::avoid_store_forwarding 
(basic_block bb)
                    it->remove = true;
                    removed_count++;
                    remove_rest = true;
-                   store_exprs_del.safe_push (it->store_mem);
                  }
              }
          }
@@ -589,42 +578,21 @@ store_forwarding_analyzer::avoid_store_forwarding 
(basic_block bb)
                }
              else if (is_store_forwarding (store_mem, load_mem, &off_val))
                {
-                 unsigned int j;
-                 rtx *del_it;
-                 bool same_range_as_removed = false;
-
-                 /* Check if another store in the load's address range has
-                    been deleted due to a constraint violation.  In this case
-                    we can't forward any other stores that operate in this
-                    range, as it would lead to partial update of the register
-                    that holds the loaded value.  */
-                 FOR_EACH_VEC_ELT (store_exprs_del, j, del_it)
-                   {
-                     rtx del_store_mem = *del_it;
-                     same_range_as_removed
-                       = is_store_forwarding (del_store_mem, load_mem, NULL);
-                     if (same_range_as_removed)
-                       break;
-                   }
-
                  /* Check if moving this store after the load is legal.  */
                  bool write_dep = false;
-                 if (!same_range_as_removed)
+                 unsigned int j = store_exprs.length () - 1;
+                 for (; j != i; j--)
                    {
-                     unsigned int j = store_exprs.length () - 1;
-                     for (; j != i; j--)
+                     if (!store_exprs[j].forwarded
+                         && output_dependence (store_mem,
+                                               store_exprs[j].store_mem))
                        {
-                         if (!store_exprs[j].forwarded
-                             && output_dependence (store_mem,
-                                                   store_exprs[j].store_mem))
-                           {
-                             write_dep = true;
-                             break;
-                           }
+                         write_dep = true;
+                         break;
                        }
                    }
 
-                 if (!same_range_as_removed && !write_dep)
+                 if (!write_dep)
                    {
                      it->forwarded = true;
                      it->offset = off_val;

Reply via email to