re PR tree-optimization/83326 (SPEC CPU2017 648.exchange2_s ~6% performance regressio...
authorRichard Biener <rguenther@suse.de>
Thu, 14 Dec 2017 14:32:24 +0000 (14:32 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 14 Dec 2017 14:32:24 +0000 (14:32 +0000)
2017-12-14  Richard Biener  <rguenther@suse.de>

PR tree-optimization/83326
* tree-ssa-loop-ivcanon.c (try_unroll_loop_completely): Add
may_be_zero parameter and handle it by not marking the first
peeled copy as not exiting the loop.
(try_peel_loop): Likewise.
(canonicalize_loop_induction_variables): Use number_of_iterations_exit
to handle the case of constant or zero iterations and perform
loop header copying on-the-fly.

* gcc.dg/tree-ssa/pr81388-2.c: Adjust.

From-SVN: r255635

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/pr81388-2.c
gcc/tree-ssa-loop-ivcanon.c

index d182308..4f97ca2 100644 (file)
@@ -1,5 +1,16 @@
 2017-12-14  Richard Biener  <rguenther@suse.de>
 
+       PR tree-optimization/83326
+       * tree-ssa-loop-ivcanon.c (try_unroll_loop_completely): Add
+       may_be_zero parameter and handle it by not marking the first
+       peeled copy as not exiting the loop.
+       (try_peel_loop): Likewise.
+       (canonicalize_loop_induction_variables): Use number_of_iterations_exit
+       to handle the case of constant or zero iterations and perform
+       loop header copying on-the-fly.
+
+2017-12-14  Richard Biener  <rguenther@suse.de>
+
        PR tree-optimization/83418
        * vr-values.c (vr_values::extract_range_for_var_from_comparison_expr):
        Instead of asserting we don't get unfolded comparisons deal with
index a7686ce..9bd5cbb 100644 (file)
@@ -1,3 +1,8 @@
+2017-12-14  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/83326
+       * gcc.dg/tree-ssa/pr81388-2.c: Adjust.
+
 2017-12-14  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gnat.dg/alignment11.adb: New test.
index 71fd289..aa40588 100644 (file)
@@ -11,4 +11,4 @@ void foo(unsigned dst)
   } while (dst < end);
 }
 
-/* { dg-final { scan-tree-dump-times " zero if " 1 "ivcanon" } } */
+/* { dg-final { scan-tree-dump " zero if " "ivcanon" } } */
index ae66ace..ce5a833 100644 (file)
@@ -681,7 +681,7 @@ unloop_loops (bitmap loop_closed_ssa_invalidated,
 
 static bool
 try_unroll_loop_completely (struct loop *loop,
-                           edge exit, tree niter,
+                           edge exit, tree niter, bool may_be_zero,
                            enum unroll_level ul,
                            HOST_WIDE_INT maxiter,
                            location_t locus, bool allow_peel)
@@ -893,6 +893,8 @@ try_unroll_loop_completely (struct loop *loop,
          exit = NULL;
          bitmap_clear (wont_exit);
        }
+      if (may_be_zero)
+       bitmap_clear_bit (wont_exit, 1);
 
       if (!gimple_duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
                                                 n_unroll, wont_exit,
@@ -977,7 +979,7 @@ estimated_peeled_sequence_size (struct loop_size *size,
 
 static bool
 try_peel_loop (struct loop *loop,
-              edge exit, tree niter,
+              edge exit, tree niter, bool may_be_zero,
               HOST_WIDE_INT maxiter)
 {
   HOST_WIDE_INT npeel;
@@ -1080,6 +1082,8 @@ try_peel_loop (struct loop *loop,
       exit = NULL;
       bitmap_clear (wont_exit);
     }
+  if (may_be_zero)
+    bitmap_clear_bit (wont_exit, 1);
   if (!gimple_duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
                                             npeel, wont_exit,
                                             exit, &edges_to_remove,
@@ -1152,13 +1156,35 @@ canonicalize_loop_induction_variables (struct loop *loop,
   HOST_WIDE_INT maxiter;
   bool modified = false;
   location_t locus = UNKNOWN_LOCATION;
+  struct tree_niter_desc niter_desc;
+  bool may_be_zero = false;
 
-  niter = number_of_latch_executions (loop);
+  /* For unrolling allow conditional constant or zero iterations, thus
+     perform loop-header copying on-the-fly.  */
   exit = single_exit (loop);
+  niter = chrec_dont_know;
+  if (exit && number_of_iterations_exit (loop, exit, &niter_desc, false))
+    {
+      niter = niter_desc.niter;
+      may_be_zero
+       = niter_desc.may_be_zero && !integer_zerop (niter_desc.may_be_zero);
+    }
   if (TREE_CODE (niter) == INTEGER_CST)
     locus = gimple_location (last_stmt (exit->src));
   else
     {
+      /* For non-constant niter fold may_be_zero into niter again.  */
+      if (may_be_zero)
+       {
+         if (COMPARISON_CLASS_P (niter_desc.may_be_zero))
+           niter = fold_build3 (COND_EXPR, TREE_TYPE (niter),
+                                niter_desc.may_be_zero,
+                                build_int_cst (TREE_TYPE (niter), 0), niter);
+         else
+           niter = chrec_dont_know;
+         may_be_zero = false;
+       }
+
       /* If the loop has more than one exit, try checking all of them
         for # of iterations determinable through scev.  */
       if (!exit)
@@ -1213,17 +1239,31 @@ canonicalize_loop_induction_variables (struct loop *loop,
      populates the loop bounds.  */
   modified |= remove_redundant_iv_tests (loop);
 
-  if (try_unroll_loop_completely (loop, exit, niter, ul, maxiter, locus,
-                                 allow_peel))
+  if (try_unroll_loop_completely (loop, exit, niter, may_be_zero, ul,
+                                 maxiter, locus, allow_peel))
     return true;
 
   if (create_iv
       && niter && !chrec_contains_undetermined (niter)
       && exit && just_once_each_iteration_p (loop, exit->src))
-    create_canonical_iv (loop, exit, niter);
+    {
+      tree iv_niter = niter;
+      if (may_be_zero)
+       {
+         if (COMPARISON_CLASS_P (niter_desc.may_be_zero))
+           iv_niter = fold_build3 (COND_EXPR, TREE_TYPE (iv_niter),
+                                   niter_desc.may_be_zero,
+                                   build_int_cst (TREE_TYPE (iv_niter), 0),
+                                   iv_niter);
+         else
+           iv_niter = NULL_TREE;
+       }
+      if (iv_niter)
+       create_canonical_iv (loop, exit, iv_niter);
+    }
 
   if (ul == UL_ALL)
-    modified |= try_peel_loop (loop, exit, niter, maxiter);
+    modified |= try_peel_loop (loop, exit, niter, may_be_zero, maxiter);
 
   return modified;
 }