loop-unswitch-2.c: New testcase.
authorJan Hubicka <hubicka@ucw.cz>
Thu, 9 Feb 2017 18:13:35 +0000 (19:13 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Thu, 9 Feb 2017 18:13:35 +0000 (18:13 +0000)
* gcc.dg/loop-unswitch-2.c: New testcase.
* gcc.dg/loop-unswitch-1.c: New testcase.
* tree-ssa-loop-unswitch.c (hoist_guard): Update profile.

From-SVN: r245311

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/loop-unswitch-2.c
gcc/testsuite/gcc.dg/loop-unswitch-3.c
gcc/tree-ssa-loop-unswitch.c

index 863678a195ef63a38f01c48cd821e4253012d29b..9af921975a3021b130c8fc2139a7b174be73d52e 100644 (file)
@@ -1,3 +1,7 @@
+2017-02-09  Jan Hubicka  <hubicka@ucw.cz>
+
+       * tree-ssa-loop-unswitch.c (hoist_guard): Update profile.
+
 2017-02-09  Jakub Jelinek  <jakub@redhat.com>
 
        * omp-offload.c (oacc_loop_auto_partitions): Use || instead of |
index c1161fb5338ad5767c0b62a05051f3c165f618e4..599780624e43637d263fa5e41b11a8915954ab85 100644 (file)
@@ -1,3 +1,8 @@
+2017-02-09  Jan Hubicka  <hubicka@ucw.cz>
+
+       * gcc.dg/loop-unswitch-2.c: Update testcase.
+       * gcc.dg/loop-unswitch-1.c: Update testcase.
+
 2017-02-09  Marek Polacek  <polacek@redhat.com>
 
        PR c/79428
index 77900f9e955e722b9b352adfb725adc149abd253..f8d314e34de28714325646ebe356596ad1cc7dea 100644 (file)
@@ -12,4 +12,5 @@ void foo (float **a, float **b, float *c, int n, int m, int l)
 }
 
 /* { dg-final { scan-tree-dump-times "guard hoisted" 3 "unswitch" } } */
+/* { dg-final { scan-tree-dump-not "Invalid sum" "unswitch" } } */
 
index e3552866dfe3f7cee3981f0918609421068ac187..089b6106711235ebe2b0f190d60bbd32dfda4e46 100644 (file)
@@ -22,5 +22,6 @@ float *foo(int ustride, int size, float *src)
 }
 
 /* { dg-final { scan-tree-dump-times "guard hoisted" 1 "unswitch" } } */
+/* { dg-final { scan-tree-dump-not "Invalid sum" "unswitch" } } */
 
 
index 1d0305a2a8bfec119e6a51ad9631363d00fcd1ba..143caf73e8653cb4ed92d3ac80ef3ace0af10bcb 100644 (file)
@@ -787,6 +787,7 @@ hoist_guard (struct loop *loop, edge guard)
   edge te, fe, e, new_edge;
   gimple *stmt;
   basic_block guard_bb = guard->src;
+  edge not_guard;
   gimple_stmt_iterator gsi;
   int flags = 0;
   bool fix_dom_of_exit;
@@ -818,18 +819,80 @@ hoist_guard (struct loop *loop, edge guard)
   update_stmt (cond_stmt);
   /* Create new loop pre-header.  */
   e = split_block (pre_header, last_stmt (pre_header));
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "  Moving guard %i->%i (prob %i) to bb %i, "   
+            "new preheader is %i\n",
+            guard->src->index, guard->dest->index, guard->probability,
+            e->src->index, e->dest->index);
+
   gcc_assert (loop_preheader_edge (loop)->src == e->dest);
+
   if (guard == fe)
     {
       e->flags = EDGE_TRUE_VALUE;
       flags |= EDGE_FALSE_VALUE;
+      not_guard = te;
     }
   else
     {
       e->flags = EDGE_FALSE_VALUE;
       flags |= EDGE_TRUE_VALUE;
+      not_guard = fe;
     }
   new_edge = make_edge (pre_header, exit->dest, flags);
+
+  /* Determine the probability that we skip the loop.  Assume that loop has
+     same average number of iterations regardless outcome of guard.  */
+  new_edge->probability = guard->probability;
+  int skip_count = guard->src->count
+                  ? RDIV (guard->count * pre_header->count, guard->src->count)
+                  : apply_probability (guard->count, new_edge->probability);
+
+  if (skip_count > e->count)
+    {
+      fprintf (dump_file, "  Capping count; expect profile inconsistency\n");
+      skip_count = e->count;
+    }
+  new_edge->count = skip_count;
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "  Estimated probability of skipping loop is %i\n",
+            new_edge->probability);
+
+  /* Update profile after the transform:
+
+     First decrease count of path from newly hoisted loop guard
+     to loop header...  */
+  e->count -= skip_count;
+  e->probability = REG_BR_PROB_BASE - new_edge->probability;
+  e->dest->count = e->count;
+  e->dest->frequency = EDGE_FREQUENCY (e);
+
+  /* ... now update profile to represent that original guard will be optimized
+     away ...  */
+  guard->probability = 0;
+  guard->count = 0;
+  not_guard->probability = REG_BR_PROB_BASE;
+  /* This count is wrong (frequency of not_guard does not change),
+     but will be scaled later.  */
+  not_guard->count = guard->src->count;
+
+  /* ... finally scale everything in the loop except for guarded basic blocks
+     where profile does not change.  */
+  basic_block *body = get_loop_body (loop);
+  
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "  Scaling nonguarded BBs in loop:");
+  for (unsigned int i = 0; i < loop->num_nodes; i++)
+    {
+      basic_block bb = body[i];
+      if (!dominated_by_p (CDI_DOMINATORS, bb, not_guard->dest))
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file, " %i", bb->index);
+          scale_bbs_frequencies_int (&bb, 1, e->probability, REG_BR_PROB_BASE);
+       }
+    }
+
   if (fix_dom_of_exit)
     set_immediate_dominator (CDI_DOMINATORS, exit->dest, pre_header);
   /* Add NEW_ADGE argument for all phi in post-header block.  */
@@ -856,7 +919,7 @@ hoist_guard (struct loop *loop, edge guard)
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "  guard hoisted.\n");
+    fprintf (dump_file, "\n  guard hoisted.\n");
 }
 
 /* Return true if phi argument for exit edge can be used