re PR rtl-optimization/19210 (not using do-loop for some loops)
authorPaolo Bonzini <bonzini@gnu.org>
Thu, 21 Jul 2005 07:24:34 +0000 (07:24 +0000)
committerPaolo Bonzini <bonzini@gcc.gnu.org>
Thu, 21 Jul 2005 07:24:34 +0000 (07:24 +0000)
gcc:
2005-07-21  Paolo Bonzini  <bonzini@gnu.org>
            Zdenek Dvorak  <dvorakz@suse.cz>

PR tree-optimization/19210
* common.opt (Wunsafe-loop-optimizations, funsafe-loop-optimizations):
New.
* Makefile.in (tree-ssa-loop-niter.o): Depend intl.o.
* loop-iv.c (get_simple_loop_desc): If -funsafe-loop-optimizations,
rely on unproven assumptions.
* predict.c (predict_loops): Adjust call to number_of_iterations_exit.
* tree-flow.h (number_of_iterations_exit): Add final parameter.
* tree-scalar-evolution.c (number_of_iterations_in_loop): Adjust call
to number_of_iterations_exit.
* tree-ssa-loop-ivcanon.c (empty_loop_p): Likewise.
* tree-ssa-loop-ivopts.c (niter_for_exit): Likewise.
* tree-ssa-loop-niter.c (find_loop_niter,
estimate_numbers_of_iterations_loop): Likewise.
(number_of_iterations_exit): Honor the new options.
* doc/invoke.texi (Wunsafe-loop-optimizations,
funsafe-loop-optimizations): Document them.

gcc/testsuite:
2005-07-21  Paolo Bonzini  <bonzini@gnu.org>

        * gcc.dg/tree-ssa/pr19210-1.c: New.
        * gcc.dg/tree-ssa/pr19210-2.c: New.

Co-Authored-By: Zdenek Dvorak <dvorakz@suse.cz>
From-SVN: r102225

14 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/common.opt
gcc/doc/invoke.texi
gcc/loop-iv.c
gcc/predict.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/pr19210-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr19210-2.c [new file with mode: 0644]
gcc/tree-flow.h
gcc/tree-scalar-evolution.c
gcc/tree-ssa-loop-ivcanon.c
gcc/tree-ssa-loop-ivopts.c
gcc/tree-ssa-loop-niter.c

index e5e533f9f1109a17d6558f99620eab4281b4417b..2777cbd60061b976aa55213f69926945ba8417ec 100644 (file)
@@ -1,3 +1,24 @@
+2005-07-21  Paolo Bonzini  <bonzini@gnu.org>
+            Zdenek Dvorak  <dvorakz@suse.cz>
+
+       PR tree-optimization/19210
+       * common.opt (Wunsafe-loop-optimizations, funsafe-loop-optimizations):
+       New.
+       * Makefile.in (tree-ssa-loop-niter.o): Depend intl.o.
+       * loop-iv.c (get_simple_loop_desc): If -funsafe-loop-optimizations,
+       rely on unproven assumptions.
+       * predict.c (predict_loops): Adjust call to number_of_iterations_exit.
+       * tree-flow.h (number_of_iterations_exit): Add final parameter.
+       * tree-scalar-evolution.c (number_of_iterations_in_loop): Adjust call
+       to number_of_iterations_exit.
+       * tree-ssa-loop-ivcanon.c (empty_loop_p): Likewise.
+       * tree-ssa-loop-ivopts.c (niter_for_exit): Likewise.
+       * tree-ssa-loop-niter.c (find_loop_niter,
+       estimate_numbers_of_iterations_loop): Likewise.
+       (number_of_iterations_exit): Honor the new options.
+       * doc/invoke.texi (Wunsafe-loop-optimizations,
+       funsafe-loop-optimizations): Document them.
+
 2005-07-21  Richard Sandiford  <richard@codesourcery.com>
 
        PR rtl-optimization/22167
index cc52cc3ea1322df95df1ee631fc91225dd0ba0a9..1cbdf68722fabbdbb4e3337570c7d3cb85fd14e5 100644 (file)
@@ -1869,7 +1869,7 @@ tree-ssa-loop-niter.o : tree-ssa-loop-niter.c $(TREE_FLOW_H) $(CONFIG_H) \
    $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) $(PARAMS_H) \
    tree-inline.h output.h $(DIAGNOSTIC_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
    $(FLAGS_H) tree-pass.h $(SCEV_H) $(TREE_DATA_REF_H) $(BASIC_BLOCK_H) \
-   $(GGC_H) hard-reg-set.h tree-chrec.h
+   $(GGC_H) hard-reg-set.h tree-chrec.h intl.h
 tree-ssa-loop-ivcanon.o : tree-ssa-loop-ivcanon.c $(TREE_FLOW_H) $(CONFIG_H) \
    $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) $(PARAMS_H) \
    tree-inline.h output.h $(DIAGNOSTIC_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
@@ -2288,7 +2288,7 @@ cfgloopanal.o : cfgloopanal.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
    $(OBSTACK_H) output.h
 loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
    hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) \
-   output.h
+   output.h intl.h
 loop-invariant.o : loop-invariant.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
    $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h \
    $(TM_H) function.h $(FLAGS_H) $(DF_H) $(OBSTACK_H) output.h
index c6ab1091be770f7efac00fbbbae2963538848bf6..cf138ee442e16139cc825437a4ecda549f35d22f 100644 (file)
@@ -93,6 +93,10 @@ Wlarger-than-
 Common RejectNegative Joined UInteger
 -Wlarger-than-<number> Warn if an object is larger than <number> bytes
 
+Wunsafe-loop-optimizations
+Common Var(warn_unsafe_loop_optimizations)
+Warn if the loop cannot be optimized due to nontrivial assumptions.
+
 Wmissing-noreturn
 Common Var(warn_missing_noreturn)
 Warn about functions which might be candidates for __attribute__((noreturn))
@@ -402,6 +406,10 @@ fforce-mem
 Common Report Var(flag_force_mem)
 Copy memory operands into registers before use
 
+fforward-propagate
+Common Report Var(flag_forward_propagate)
+Perform a forward propagation pass on RTL
+
 ; Nonzero means don't put addresses of constant functions in registers.
 ; Used for compiling the Unix kernel, where strange substitutions are
 ; done on the assembly output.
@@ -963,6 +971,13 @@ funroll-all-loops
 Common Report Var(flag_unroll_all_loops)
 Perform loop unrolling for all loops
 
+; Nonzero means that loop optimizer may assume that the induction variables
+; that control loops do not overflow and that the loops with nontrivial
+; exit condition are not infinite
+funsafe-loop-optimizations
+Common Report Var(flag_unsafe_loop_optimizations)
+Allow loop optimizations to assume that the loops behave in normal way
+
 ; Nonzero means that unsafe floating-point math optimizations are allowed
 ; for the sake of speed.  IEEE compliance is not guaranteed, and operations
 ; are allowed to assume that their arguments and results are "normal"
index 45e2a25dc7298e03923cc4958507f69001269d75..4685c636240384925b3a7eb4e81a97d17b06fb49 100644 (file)
@@ -230,7 +230,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wimport  -Wno-import  -Winit-self  -Winline @gol
 -Wno-int-to-pointer-cast @gol
 -Wno-invalid-offsetof  -Winvalid-pch @gol
--Wlarger-than-@var{len}  -Wlong-long @gol
+-Wlarger-than-@var{len}  -Wunsafe-loop-optimizations  -Wlong-long @gol
 -Wmain  -Wmissing-braces  -Wmissing-field-initializers @gol
 -Wmissing-format-attribute  -Wmissing-include-dirs @gol
 -Wmissing-noreturn @gol
@@ -311,7 +311,7 @@ Objective-C and Objective-C++ Dialects}.
 -fno-default-inline  -fno-defer-pop -floop-optimize2 -fmove-loop-invariants @gol
 -fno-function-cse  -fno-guess-branch-probability @gol
 -fno-inline  -fno-math-errno  -fno-peephole  -fno-peephole2 @gol
--funsafe-math-optimizations  -ffinite-math-only @gol
+-funsafe-math-optimizations  -funsafe-loop-optimizations  -ffinite-math-only @gol
 -fno-trapping-math  -fno-zero-initialized-in-bss @gol
 -fomit-frame-pointer  -foptimize-register-move @gol
 -foptimize-sibling-calls  -fprefetch-loop-arrays @gol
@@ -2988,6 +2988,13 @@ global variable or whenever a built-in function is shadowed.
 @opindex Wlarger-than
 Warn whenever an object of larger than @var{len} bytes is defined.
 
+@item -Wunsafe-loop-optimizations
+@opindex Wunsafe-loop-optimizations
+Warn if the loop cannot be optimized because the compiler could not
+assume anything on the bounds of the loop indices.  With
+@option{-funsafe-loop-optimizations} warn if the compiler made
+such assumptions.
+
 @item -Wpointer-arith
 @opindex Wpointer-arith
 Warn about anything that depends on the ``size of'' a function type or
@@ -4728,6 +4735,15 @@ Perform loop optimizations using the new loop optimizer.  The optimizations
 (loop unrolling, peeling and unswitching, loop invariant motion) are enabled
 by separate flags.
 
+@item -funsafe-loop-optimizations
+@opindex funsafe-loop-optimizations
+If given, the loop optimizer will assume that loop indices do not
+overflow, and that the loops with nontrivial exit condition are not
+infinite.  This enables a wider range of loop optimizations even if
+the loop optimizer itself cannot prove that these assumptions are valid.
+Using @option{-Wunsafe-loop-optimizations}, the compiler will warn you
+if it finds this kind of loop.
+
 @item -fcrossjumping
 @opindex crossjumping
 Perform cross-jumping transformation.  This transformation unifies equivalent code and save code size.  The
index 48bae0bd9546cfbd0dad10adb300fe52e7cc0233..7c7a5de0a556eedd74cbf566c23bf79f9d738ece 100644 (file)
@@ -57,7 +57,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "basic-block.h"
 #include "cfgloop.h"
 #include "expr.h"
+#include "intl.h"
 #include "output.h"
+#include "toplev.h"
 
 /* The insn information.  */
 
@@ -2692,6 +2694,41 @@ get_simple_loop_desc (struct loop *loop)
   find_simple_exit (loop, desc);
   loop->aux = desc;
 
+  if (desc->simple_p && (desc->assumptions || desc->infinite))
+    {
+      const char *wording; 
+
+      /* Assume that no overflow happens and that the loop is finite.  
+        We already warned at the tree level if we ran optimizations there.  */
+      if (!flag_tree_loop_optimize && warn_unsafe_loop_optimizations)
+       {
+         if (desc->infinite)
+           {
+             wording = 
+               flag_unsafe_loop_optimizations
+               ? N_("assuming that the loop is not infinite")
+               : N_("cannot optimize possibly infinite loops");
+             warning (OPT_Wunsafe_loop_optimizations, "%s",
+                      gettext (wording));
+           }
+         if (desc->assumptions)
+           {
+             wording = 
+               flag_unsafe_loop_optimizations
+               ? N_("assuming that the loop counter does not overflow")
+               : N_("cannot optimize loop, the loop counter may overflow");
+             warning (OPT_Wunsafe_loop_optimizations, "%s",
+                      gettext (wording));
+           }
+       }
+
+      if (flag_unsafe_loop_optimizations)
+       {
+         desc->assumptions = NULL_RTX;
+         desc->infinite = NULL_RTX;
+       }
+    }
+
   return desc;
 }
 
index a448c0449b88445296b4906e35473a2d273bf181..9fc8f4501cc6cd56c4571ec2b44b0bd78c22dbac 100644 (file)
@@ -643,7 +643,7 @@ predict_loops (struct loops *loops_info, bool rtlsimpleloops)
            {
              tree niter = NULL;
 
-             if (number_of_iterations_exit (loop, exits[j], &niter_desc))
+             if (number_of_iterations_exit (loop, exits[j], &niter_desc, false))
                niter = niter_desc.niter;
              if (!niter || TREE_CODE (niter_desc.niter) != INTEGER_CST)
                niter = loop_niter_by_eval (loop, exits[j]);
index 99b9c799651fbf3980375e70ac86a95e89646181..7e4f35bd01c2bf75741b18a01011171d89925405 100644 (file)
@@ -1,3 +1,8 @@
+2005-07-21  Paolo Bonzini  <bonzini@gnu.org>
+
+        * gcc.dg/tree-ssa/pr19210-1.c: New.
+        * gcc.dg/tree-ssa/pr19210-2.c: New.
+
 2005-07-21  Richard Sandiford  <richard@codesourcery.com>
 
        PR rtl-optimization/22167
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr19210-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr19210-1.c
new file mode 100644 (file)
index 0000000..4d6100a
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wunsafe-loop-optimizations" } */
+extern void g(void);
+
+void
+f (unsigned n)
+{
+  unsigned k;
+  for(k = 0;k <= n;k++) /* { dg-warning "cannot optimize.*infinite loops" } */
+    g();
+
+  for(k = 0;k <= n;k += 4) /* { dg-warning "cannot optimize.*overflow" } */
+    g();
+
+  for(k = 5;k <= n;k += 5) /* { dg-warning "cannot optimize.*overflow" } */
+    g();
+
+  for(k = 15;k >= n;k--) /* { dg-warning "cannot optimize.*infinite" } */
+    g();
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr19210-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr19210-2.c
new file mode 100644 (file)
index 0000000..498c658
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -funsafe-loop-optimizations -Wunsafe-loop-optimizations" } */
+extern void g(void);
+
+void
+f (unsigned n)
+{
+  unsigned k;
+  for(k = 0;k <= n;k++) /* { dg-warning "assuming.*not infinite" } */
+    g();
+
+  for(k = 5;k <= n;k += 4) /* { dg-warning "assuming.*not overflow" } */
+    g();
+
+  for(k = 5;k <= n;k += 5) /* { dg-warning "assuming.*not overflow" } */
+    g();
+
+  for(k = 15;k >= n;k--) /* { dg-warning "assuming.*not infinite" } */
+    g();
+
+}
index 16bcb803c3eacfbd6ed1661090f36aa9c4928c77..d41a79c1b72062baec637398ee5cf322df387eed 100644 (file)
@@ -722,7 +722,7 @@ void remove_empty_loops (struct loops *);
 void tree_ssa_iv_optimize (struct loops *);
 
 bool number_of_iterations_exit (struct loop *, edge,
-                               struct tree_niter_desc *niter);
+                               struct tree_niter_desc *niter, bool);
 tree find_loop_niter (struct loop *, edge *);
 tree loop_niter_by_eval (struct loop *, edge);
 tree find_loop_niter_by_eval (struct loop *, edge *);
index 2470cc1b51b10f145af5ed27609bf38e4134c280..f12ec09fc45220c844d195f29d0709abacf79e88 100644 (file)
@@ -2235,7 +2235,7 @@ number_of_iterations_in_loop (struct loop *loop)
   if (!exit)
     goto end;
 
-  if (!number_of_iterations_exit (loop, exit, &niter_desc))
+  if (!number_of_iterations_exit (loop, exit, &niter_desc, false))
     goto end;
 
   type = TREE_TYPE (niter_desc.niter);
index 4d02baabd2ddc8d4640a6d1c7210f07fcbe06255..e8a94d66e6ce3bb6dddbebeb649d5630216467c6 100644 (file)
@@ -393,7 +393,7 @@ empty_loop_p (struct loop *loop)
     return false;
 
   /* The loop must be finite.  */
-  if (!number_of_iterations_exit (loop, exit, &niter))
+  if (!number_of_iterations_exit (loop, exit, &niter, false))
     return false;
 
   /* Values of all loop exit phi nodes must be invariants.  */
index 84c68abad9c57702ace244008dffda090570d535..fda17f9c56d74dd0379eb16a44fe91ec6428d0f7 100644 (file)
@@ -712,7 +712,8 @@ niter_for_exit (struct ivopts_data *data, edge exit)
       nfe_desc = xmalloc (sizeof (struct nfe_cache_elt));
       nfe_desc->exit = exit;
       nfe_desc->valid_p = number_of_iterations_exit (data->current_loop,
-                                                    exit, &nfe_desc->niter);
+                                                    exit, &nfe_desc->niter,
+                                                    true);
       *slot = nfe_desc;
     }
   else
index c99aa386be33032770bda131c519fc698c0a4acf..891dc0c13d1fe34dddbc0e3a3bae707ab649ffe5 100644 (file)
@@ -29,6 +29,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "basic-block.h"
 #include "output.h"
 #include "diagnostic.h"
+#include "intl.h"
 #include "tree-flow.h"
 #include "tree-dump.h"
 #include "cfgloop.h"
@@ -39,6 +40,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tree-data-ref.h"
 #include "params.h"
 #include "flags.h"
+#include "toplev.h"
 #include "tree-inline.h"
 
 #define SWAP(X, Y) do { void *tmp = (X); (X) = (Y); (Y) = tmp; } while (0)
@@ -906,11 +908,14 @@ simplify_using_outer_evolutions (struct loop *loop, tree expr)
    EXIT (an exit edge of the LOOP) in NITER.  Returns true if some
    useful information could be derived (and fields of NITER has
    meaning described in comments at struct tree_niter_desc
-   declaration), false otherwise.  */
+   declaration), false otherwise.  If WARN is true and
+   -Wunsafe-loop-optimizations was given, warn if the optimizer is going to use
+   potentially unsafe assumptions.  */
 
 bool
 number_of_iterations_exit (struct loop *loop, edge exit,
-                          struct tree_niter_desc *niter)
+                          struct tree_niter_desc *niter,
+                          bool warn)
 {
   tree stmt, cond, type;
   tree op0, base0, step0;
@@ -990,7 +995,45 @@ number_of_iterations_exit (struct loop *loop, edge exit,
          = simplify_using_initial_conditions (loop,
                                               niter->may_be_zero,
                                               &niter->additional_info);
-  return integer_onep (niter->assumptions);
+
+  if (integer_onep (niter->assumptions))
+    return true;
+
+  /* With -funsafe-loop-optimizations we assume that nothing bad can happen.
+     But if we can prove that there is overflow or some other source of weird
+     behavior, ignore the loop even with -funsafe-loop-optimizations.  */
+  if (integer_zerop (niter->assumptions))
+    return false;
+
+  if (flag_unsafe_loop_optimizations)
+    niter->assumptions = boolean_true_node;
+
+  if (warn)
+    {
+      const char *wording;
+      location_t loc = EXPR_LOCATION (stmt);
+  
+      /* We can provide a more specific warning if one of the operator is
+        constant and the other advances by +1 or -1.  */
+      if (step1 ? !step0 && (integer_onep (step1) || integer_all_onesp (step1))
+               : step0 && (integer_onep (step0) || integer_all_onesp (step0)))
+        wording =
+          flag_unsafe_loop_optimizations
+          ? N_("assuming that the loop is not infinite")
+          : N_("cannot optimize possibly infinite loops");
+      else
+       wording = 
+         flag_unsafe_loop_optimizations
+         ? N_("assuming that the loop counter does not overflow")
+         : N_("cannot optimize loop, the loop counter may overflow");
+
+      if (LOCATION_LINE (loc) > 0)
+       warning (OPT_Wunsafe_loop_optimizations, "%H%s", &loc, gettext (wording));
+      else
+       warning (OPT_Wunsafe_loop_optimizations, "%s", gettext (wording));
+    }
+
+  return flag_unsafe_loop_optimizations;
 }
 
 /* Try to determine the number of iterations of LOOP.  If we succeed,
@@ -1014,7 +1057,7 @@ find_loop_niter (struct loop *loop, edge *exit)
       if (!just_once_each_iteration_p (loop, ex->src))
        continue;
 
-      if (!number_of_iterations_exit (loop, ex, &desc))
+      if (!number_of_iterations_exit (loop, ex, &desc, false))
        continue;
 
       if (nonzero_p (desc.may_be_zero))
@@ -1360,7 +1403,7 @@ estimate_numbers_of_iterations_loop (struct loop *loop)
   exits = get_loop_exit_edges (loop, &n_exits);
   for (i = 0; i < n_exits; i++)
     {
-      if (!number_of_iterations_exit (loop, exits[i], &niter_desc))
+      if (!number_of_iterations_exit (loop, exits[i], &niter_desc, false))
        continue;
 
       niter = niter_desc.niter;