From: Kyrylo Tkachov <[email protected]>

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]>
---
 .../g++.dg/tree-ssa/noncall-store-1.C         | 20 +++++++++++++++++++
 gcc/tree-ssa-loop-im.cc                       | 16 +++++++++++----
 2 files changed, 32 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/noncall-store-1.C

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 00000000000..fc6a7684671
--- /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 19523fb157a..f38a5831b58 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
-- 
2.50.1 (Apple Git-155)

Reply via email to