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
