https://gcc.gnu.org/g:41596ef9be648c8488165c95be1aacb228ad6750

commit r17-4031-g41596ef9be648c8488165c95be1aacb228ad6750
Author: Kyrylo Tkachov <[email protected]>
Date:   Thu Sep 3 18:27:10 2026 +0200

    tree-ssa-loop-im: Reject trapping store motion with non-call EH
    
    LIM store motion does not update EH information.  can_sm_ref_p rejects a
    reference when tree_could_throw_p says that it can throw.  That query 
treats a
    bare memory reference as a load.  A safe load does not prove that a store to
    the same address cannot trap.
    
    The later store-specific check only requires a trapping store to execute on
    every loop iteration.  It does not protect its EH region when the store is
    moved out of the loop.
    
    Compute the store trap result once.  When exception handling is enabled and
    the function can throw non-call exceptions, reject every trapping store.  
Keep
    the existing execution test for the other cases.
    
    Bootstrapped and tested on aarch64-unknown-linux-gnu.
    
    gcc/ChangeLog:
    
            * tree-ssa-loop-im.cc (can_sm_ref_p): Reject a trapping store when
            non-call exceptions are enabled.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/tree-ssa/noncall-store-1.C: New test.
    
    Signed-off-by: Kyrylo Tkachov <[email protected]>

Diff:
---
 gcc/testsuite/g++.dg/tree-ssa/noncall-store-1.C | 20 ++++++++++++++++++++
 gcc/tree-ssa-loop-im.cc                         | 16 ++++++++++++----
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/gcc/testsuite/g++.dg/tree-ssa/noncall-store-1.C 
b/gcc/testsuite/g++.dg/tree-ssa/noncall-store-1.C
new file mode 100644
index 000000000000..fc6a76846718
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/noncall-store-1.C
@@ -0,0 +1,20 @@
+// A store through the this parameter can throw a non-call exception even when
+// the function has no local exception handler.
+
+// { dg-do compile }
+// { dg-options "-O2 -fnon-call-exceptions -fdump-tree-lim2-details" }
+
+struct S
+{
+  int value;
+  void loop (int);
+};
+
+void
+S::loop (int n)
+{
+  for (int i = 0; i < n; ++i)
+    value = i;
+}
+
+// { dg-final { scan-tree-dump-not "Executing store motion" "lim2" } }
diff --git a/gcc/tree-ssa-loop-im.cc b/gcc/tree-ssa-loop-im.cc
index 19523fb157a5..f38a5831b585 100644
--- a/gcc/tree-ssa-loop-im.cc
+++ b/gcc/tree-ssa-loop-im.cc
@@ -3351,6 +3351,8 @@ ref_in_loop_hot_body::operator () (mem_ref_loc *loc)
 static bool
 can_sm_ref_p (class loop *loop, im_mem_ref *ref)
 {
+  bool store_could_trap;
+
   /* Can't hoist unanalyzable refs.  */
   if (!MEM_ANALYZABLE (ref))
     return false;
@@ -3365,12 +3367,18 @@ can_sm_ref_p (class loop *loop, im_mem_ref *ref)
       || !for_each_index (&ref->mem.ref, may_move_till, loop))
     return false;
 
-  /* If it can throw fail, we do not properly update EH info.  */
-  if (tree_could_throw_p (ref->mem.ref))
+  store_could_trap = lhs_could_trap_p (ref->mem.ref);
+
+  /* Do not move a load or store that can throw.  Store motion does not
+     update EH information.  */
+  if (tree_could_throw_p (ref->mem.ref)
+      || (flag_exceptions
+         && cfun->can_throw_non_call_exceptions
+         && store_could_trap))
     return false;
 
-  /* If the store can trap, it must be always executed in LOOP.  */
-  if (lhs_could_trap_p (ref->mem.ref)
+  /* If a store can trap, it must be always executed in LOOP.  */
+  if (store_could_trap
       /* ???  We can at least use false here, allowing loads?  We
         are forcing conditional stores if the ref is not always
         stored to later anyway.  So this would only guard

Reply via email to