The following fixes PR78185 by properly honoring possibly infinite child loops when computing what blocks are always executed during loop invariant motion. Such loops behave as if the loop would exit at this point.
Both GIMPLE and RTL level passes have that very same issue and the following fixes the GIMPLE one and simply disables hoisting of possibly trapping or faulting instructions in the RTL pass ... Eric seems to remember this might regress gzip so I'm going to put this on one of our SPEC testers for tonights run as well. Maybe somebody else wants to check the performance impact (I'm interested in both, GIMPLE and RTL change fallout for performance). Bootstrap and regtest running on x86_64-unknown-linux-gnu. If all goes well I'll followup with the obvious removal of no longer needed stuff in loop-invariant.c. Another variant for RTL would be to simply treat all edges entering a child loop (not only those entering possibly infinitely looping ones) as an exit. I think finite_loop_p has no RTL level variant (yet). Richard. 2016-11-02 Richard Biener <rguent...@suse.de> PR middle-end/78185 * loop-invariant.c (find_invariant_insn): Never hoist trapping or faulting instructions. * tree-ssa-loop-im.c: Include tree-ssa-loop-niter.h. (fill_always_executed_in_1): Honor infinite child loops. * gcc.dg/pr78185.c: New testcase. diff --git a/gcc/loop-invariant.c b/gcc/loop-invariant.c index 551103f..deb5be6 100644 --- a/gcc/loop-invariant.c +++ b/gcc/loop-invariant.c @@ -1076,7 +1076,7 @@ pre_check_invariant_p (bool simple, rtx dest) unless the program ends due to a function call. */ static void -find_invariant_insn (rtx_insn *insn, bool always_reached, bool always_executed) +find_invariant_insn (rtx_insn *insn, bool, bool always_executed) { df_ref ref; struct def *def; @@ -1108,8 +1108,8 @@ find_invariant_insn (rtx_insn *insn, bool always_reached, bool always_executed) if (can_throw_internal (insn)) return; - /* We cannot make trapping insn executed, unless it was executed before. */ - if (may_trap_or_fault_p (PATTERN (insn)) && !always_reached) + /* We cannot make trapping insn executed. */ + if (may_trap_or_fault_p (PATTERN (insn))) return; depends_on = BITMAP_ALLOC (NULL); diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c index 463db04..0524e57 100644 --- a/gcc/tree-ssa-loop-im.c +++ b/gcc/tree-ssa-loop-im.c @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see #include "trans-mem.h" #include "gimple-fold.h" #include "tree-scalar-evolution.h" +#include "tree-ssa-loop-niter.h" /* TODO: Support for predicated code motion. I.e. @@ -2369,8 +2370,16 @@ fill_always_executed_in_1 (struct loop *loop, sbitmap contains_call) break; FOR_EACH_EDGE (e, ei, bb->succs) - if (!flow_bb_inside_loop_p (loop, e->dest)) - break; + { + /* If there is an exit from this BB. */ + if (!flow_bb_inside_loop_p (loop, e->dest)) + break; + /* Or we enter a possibly non-finite loop. */ + if (flow_loop_nested_p (bb->loop_father, + e->dest->loop_father) + && ! finite_loop_p (e->dest->loop_father)) + break; + } if (e) break; Index: trunk/gcc/testsuite/gcc.dg/pr78185.c =================================================================== --- trunk/gcc/testsuite/gcc.dg/pr78185.c (revision 0) +++ trunk/gcc/testsuite/gcc.dg/pr78185.c (revision 0) @@ -0,0 +1,28 @@ +/* { dg-do run { target *-*-linux* *-*-gnu* } } */ +/* { dg-options "-O" } */ + +#include <unistd.h> +#include <signal.h> +#include <stdlib.h> + +static char var1 = 0L; +static char *var2 = &var1; + +void do_exit (int i) +{ + exit (0); +} + +int main(void) +{ + struct sigaction s; + sigemptyset (&s.sa_mask); + s.sa_handler = do_exit; + s.sa_flags = 0; + sigaction (SIGALRM, &s, NULL); + alarm (1); + /* The following loop is infinite, the division by zero should not + be hoisted out of it. */ + for (; (var1 == 0 ? 0 : (100 / var1)) == *var2; ); + return 0; +}