Warn on undefined loop exit.
authorAndrew Stubbs <ams@codesourcery.com>
Thu, 20 Nov 2014 20:22:54 +0000 (20:22 +0000)
committerAndrew Stubbs <ams@gcc.gnu.org>
Thu, 20 Nov 2014 20:22:54 +0000 (20:22 +0000)
2014-11-20  Andrew Stubbs  <ams@codesourcery.com>

gcc/
* tree-ssa-loop-niter.c (maybe_lower_iteration_bound): Warn if a loop
condition would be removed due to undefined behaviour.

gcc/testsuite/
* gcc.dg/undefined-loop-1.c: New file.
* gcc.dg/undefined-loop-2.c: New file.

From-SVN: r217891

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/undefined-loop-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/undefined-loop-2.c [new file with mode: 0644]
gcc/tree-ssa-loop-niter.c

index 537fa882631c228b105af4db0ae9c24eaec48acf..7153d67ad3a3c6812ebcc9be328ece8a12de422d 100644 (file)
@@ -1,3 +1,8 @@
+2014-11-20  Andrew Stubbs  <ams@codesourcery.com>
+
+       * tree-ssa-loop-niter.c (maybe_lower_iteration_bound): Warn if a loop
+       condition would be removed due to undefined behaviour.
+
 2014-11-20  Andrew Pinski  <apinski@cavium.com>
 
        PR ipa/63981
index 61f8a495a42d8978293b3315a7960f5010208be1..4aba5fb9e86a6dce3116ac8a45ab2e9a6d0cc510 100644 (file)
@@ -1,3 +1,8 @@
+2014-11-20  Andrew Stubbs  <ams@codesourcery.com>
+
+       * gcc.dg/undefined-loop-1.c: New file.
+       * gcc.dg/undefined-loop-2.c: New file.
+
 2014-11-20  Tejas Belagod  <tejas.belagod@arm.com>
 
        * gcc.target/aarch64/symbol-range.c: New.
diff --git a/gcc/testsuite/gcc.dg/undefined-loop-1.c b/gcc/testsuite/gcc.dg/undefined-loop-1.c
new file mode 100644 (file)
index 0000000..80260cc
--- /dev/null
@@ -0,0 +1,18 @@
+/* Check that loops whose final iteration is undefined are detected.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Waggressive-loop-optimizations" } */
+
+void doSomething(char);
+
+char array[5];
+
+void
+foo (void)
+{
+  int i;
+  for (i = 0;
+       array[i]  /* { dg-message "note: possible undefined statement is here" } */
+       && i < 5; /* { dg-warning "loop exit may only be reached after undefined behavior" } */
+       i++)
+    doSomething(array[i]);
+}
diff --git a/gcc/testsuite/gcc.dg/undefined-loop-2.c b/gcc/testsuite/gcc.dg/undefined-loop-2.c
new file mode 100644 (file)
index 0000000..dbea62c
--- /dev/null
@@ -0,0 +1,22 @@
+/* Check that loops whose final iteration is undefined are detected.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Waggressive-loop-optimizations" } */
+
+void doSomething(char);
+
+char array1[5];
+char array2[5];
+
+void
+foo (int p)
+{
+  int i;
+  for (i=0;
+       (p
+        ? array1[i]  /* { dg-message "note: possible undefined statement is here" } */
+        : array2[i]) /* { dg-message "note: possible undefined statement is here" } */
+       && i < 5      /* { dg-warning "loop exit may only be reached after undefined behavior" } */
+       && i < 100;   /* { dg-warning "loop exit may only be reached after undefined behavior" } */
+       i++)
+    doSomething(array1[i]);
+}
index fd4d5bf7b5ee93597b38f2739f86727dc3f11a4b..8ba365c4f34395265b627be0894b626c6cae961e 100644 (file)
@@ -3294,6 +3294,7 @@ maybe_lower_iteration_bound (struct loop *loop)
   struct nb_iter_bound *elt;
   bool found_exit = false;
   vec<basic_block> queue = vNULL;
+  vec<gimple> problem_stmts = vNULL;
   bitmap visited;
 
   /* Collect all statements with interesting (i.e. lower than
@@ -3339,6 +3340,7 @@ maybe_lower_iteration_bound (struct loop *loop)
          if (not_executed_last_iteration->contains (stmt))
            {
              stmt_found = true;
+             problem_stmts.safe_push (stmt);
              break;
            }
          if (gimple_has_side_effects (stmt))
@@ -3382,9 +3384,53 @@ maybe_lower_iteration_bound (struct loop *loop)
                 "undefined statement must be executed at the last iteration.\n");
       record_niter_bound (loop, loop->nb_iterations_upper_bound - 1,
                          false, true);
+
+      if (warn_aggressive_loop_optimizations)
+       {
+         bool exit_warned = false;
+         for (elt = loop->bounds; elt; elt = elt->next)
+           {
+             if (elt->is_exit
+                 && wi::gtu_p (elt->bound, loop->nb_iterations_upper_bound))
+               {
+                 basic_block bb = gimple_bb (elt->stmt);
+                 edge exit_edge = EDGE_SUCC (bb, 0);
+                 struct tree_niter_desc niter;
+
+                 if (!loop_exit_edge_p (loop, exit_edge))
+                   exit_edge = EDGE_SUCC (bb, 1);
+
+                 if(number_of_iterations_exit (loop, exit_edge,
+                                               &niter, false, false)
+                    && integer_onep (niter.assumptions)
+                    && integer_zerop (niter.may_be_zero)
+                    && niter.niter
+                    && TREE_CODE (niter.niter) == INTEGER_CST
+                    && wi::ltu_p (loop->nb_iterations_upper_bound,
+                                  wi::to_widest (niter.niter)))
+                  {
+                    if (warning_at (gimple_location (elt->stmt),
+                                    OPT_Waggressive_loop_optimizations,
+                                    "loop exit may only be reached after undefined behavior"))
+                      exit_warned = true;
+                  }
+               }
+           }
+
+         if (exit_warned && !problem_stmts.empty ())
+           {
+             gimple stmt;
+             int index;
+             FOR_EACH_VEC_ELT (problem_stmts, index, stmt)
+               inform (gimple_location (stmt),
+                       "possible undefined statement is here");
+           }
+      }
     }
+
   BITMAP_FREE (visited);
   queue.release ();
+  problem_stmts.release ();
   delete not_executed_last_iteration;
 }