predict.c (propagate_freq): Clear EXIT_BLOCK_PTR frequency if it is unreachable.
authorJan Hubicka <jh@suse.cz>
Tue, 29 Jun 2010 14:14:15 +0000 (16:14 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Tue, 29 Jun 2010 14:14:15 +0000 (14:14 +0000)
* predict.c (propagate_freq): Clear EXIT_BLOCK_PTR frequency if it is
unreachable.
(rebuild_frequencies): New function.
* predict.h (rebuild_frequencies): Declare.
* tree-inline.c (copy_cfg_body): Compute properly count & frequency of
entry block and edge reaching new_entry.
(tree_function_versioning): When doing partial cloning, rebuild frequencies
when done.
* passes.c (execute_function_todo): Use rebild_frequencies.

From-SVN: r161536

gcc/ChangeLog
gcc/passes.c
gcc/predict.c
gcc/predict.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/ipa-split-3.c [new file with mode: 0644]
gcc/tree-inline.c

index ff7f4fddeb4672e54bcc1ba3a232c9e989a43f6d..0bfee7cb379913ccc1051f8d0895218205cf4522 100644 (file)
@@ -1,3 +1,15 @@
+2010-06-29  Jan Hubicka  <jh@suse.cz>
+
+       * predict.c (propagate_freq): Clear EXIT_BLOCK_PTR frequency if it is
+       unreachable.
+       (rebuild_frequencies): New function.
+       * predict.h (rebuild_frequencies): Declare.
+       * tree-inline.c (copy_cfg_body): Compute properly count & frequency of
+       entry block and edge reaching new_entry.
+       (tree_function_versioning): When doing partial cloning, rebuild frequencies
+       when done.
+       * passes.c (execute_function_todo): Use rebild_frequencies.
+
 2010-06-29  Richard Guenther  <rguenther@suse.de>
 
        * tree-dfa.c (dump_variable): Remove noalias_state dumping.
index 03de5810fb430e4706014ecfaeb1f2ccbcc8dc57..8828967d0d8ad3b24493eb138f07e96b2e4e51ca 100644 (file)
@@ -1243,22 +1243,7 @@ execute_function_todo (void *data)
     }
 
   if (flags & TODO_rebuild_frequencies)
-    {
-      if (profile_status == PROFILE_GUESSED)
-       {
-         loop_optimizer_init (0);
-         add_noreturn_fake_exit_edges ();
-         mark_irreducible_loops ();
-         connect_infinite_loops_to_exit ();
-         estimate_bb_frequencies ();
-         remove_fake_exit_edges ();
-         loop_optimizer_finalize ();
-       }
-      else if (profile_status == PROFILE_READ)
-       counts_to_freqs ();
-      else
-       gcc_unreachable ();
-    }
+    rebuild_frequencies ();
 
 #if defined ENABLE_CHECKING
   if (flags & TODO_verify_ssa
index 1bccd4d2c26b9b347060d488b0ffd982cfb6b763..5d61140e4e679d7ada5058cde521134a6760055d 100644 (file)
@@ -1855,9 +1855,6 @@ propagate_freq (basic_block head, bitmap tovisit)
       edge_iterator ei;
       int count = 0;
 
-       /* The outermost "loop" includes the exit block, which we can not
-         look up via BASIC_BLOCK.  Detect this and use EXIT_BLOCK_PTR
-         directly.  Do the same for the entry block.  */
       bb = BASIC_BLOCK (i);
 
       FOR_EACH_EDGE (e, ei, bb->preds)
@@ -1872,6 +1869,9 @@ propagate_freq (basic_block head, bitmap tovisit)
                     e->src->index, bb->index);
        }
       BLOCK_INFO (bb)->npredecessors = count;
+      /* When function never returns, we will never process exit block.  */
+      if (!count && bb == EXIT_BLOCK_PTR)
+       bb->count = bb->frequency = 0;
     }
 
   memcpy (&BLOCK_INFO (head)->frequency, &real_one, sizeof (real_one));
@@ -2282,3 +2282,27 @@ struct gimple_opt_pass pass_strip_predict_hints =
   TODO_ggc_collect | TODO_verify_ssa                   /* todo_flags_finish */
  }
 };
+
+/* Rebuild function frequencies.  Passes are in general expected to
+   maintain profile by hand, however in some cases this is not possible:
+   for example when inlining several functions with loops freuqencies might run
+   out of scale and thus needs to be recomputed.  */
+
+void
+rebuild_frequencies (void)
+{
+  if (profile_status == PROFILE_GUESSED)
+    {
+      loop_optimizer_init (0);
+      add_noreturn_fake_exit_edges ();
+      mark_irreducible_loops ();
+      connect_infinite_loops_to_exit ();
+      estimate_bb_frequencies ();
+      remove_fake_exit_edges ();
+      loop_optimizer_finalize ();
+    }
+  else if (profile_status == PROFILE_READ)
+    counts_to_freqs ();
+  else
+    gcc_unreachable ();
+}
index 18e57d7706560546f46723a3387b4e65fde4fe79..a0ca3a29071d534b5439b24355751bd6cf2b0277 100644 (file)
@@ -42,5 +42,6 @@ extern const char *predictor_name (enum br_predictor);
 extern tree build_predict_expr (enum br_predictor, enum prediction);
 extern void tree_estimate_probability (void);
 extern void compute_function_frequency (void);
+extern void rebuild_frequencies (void);
 
 #endif  /* GCC_PREDICT_H */
index 73383546e28cac5e1668044cac4380c5976bd8b6..00e5e840404848c5cb6d84da6775394f512ed113 100644 (file)
@@ -1,3 +1,7 @@
+2010-06-29  Jan Hubicka  <jh@suse.cz>
+
+       * gcc.dg/tree-ssa/ipa-split-3.c: New testcase.
+
 2010-06-29  Bernd Schmidt  <bernds@codesourcery.com>
 
        PR target/43902
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ipa-split-3.c b/gcc/testsuite/gcc.dg/tree-ssa/ipa-split-3.c
new file mode 100644 (file)
index 0000000..05a37f8
--- /dev/null
@@ -0,0 +1,21 @@
+int baz (void);
+static int
+foo (int x)
+{
+  if (__builtin_expect (x <= 0, 0))
+    {
+      __builtin_printf ("foo\n");
+      __builtin_printf ("foo\n");
+      __builtin_printf ("foo\n");
+      __builtin_abort ();
+    }
+  return 6;
+}
+
+int a,b,c;
+
+int
+bar (int x)
+{
+  return foo (a) + foo (b) + foo (c);
+}
index 2604c6b11272def06b7cd8b7696e64b299ec1bc4..3ef1cc3832e8c61f61f1cfa72c14da2c5318aa95 100644 (file)
@@ -2159,6 +2159,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale,
   bool need_debug_cleanup = false;
   gcov_type count_scale;
   int last;
+  int incomming_frequency = 0;
+  gcov_type incomming_count = 0;
 
   if (ENTRY_BLOCK_PTR_FOR_FUNCTION (src_cfun)->count)
     count_scale = (REG_BR_PROB_BASE * count
@@ -2169,6 +2171,28 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale,
   /* Register specific tree functions.  */
   gimple_register_cfg_hooks ();
 
+  /* If we are inlining just region of the function, make sure to connect new entry
+     to ENTRY_BLOCK_PTR.  Since new entry can be part of loop, we must compute
+     frequency and probability of ENTRY_BLOCK_PTR based on the frequencies and
+     probabilities of edges incomming from nonduplicated region.  */
+  if (new_entry)
+    {
+      edge e;
+      edge_iterator ei;
+
+      FOR_EACH_EDGE (e, ei, new_entry->preds)
+       if (!e->src->aux)
+         {
+           incomming_frequency += EDGE_FREQUENCY (e);
+           incomming_count += e->count;
+         }
+      incomming_count = incomming_count * count_scale / REG_BR_PROB_BASE;
+      incomming_frequency
+       = incomming_frequency * frequency_scale / REG_BR_PROB_BASE;
+      ENTRY_BLOCK_PTR->count = incomming_count;
+      ENTRY_BLOCK_PTR->frequency = incomming_frequency;
+    }
+
   /* Must have a CFG here at this point.  */
   gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION
              (DECL_STRUCT_FUNCTION (callee_fndecl)));
@@ -2204,10 +2228,9 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale,
 
   if (new_entry)
     {
-      edge e;
-      e = make_edge (entry_block_map, (basic_block)new_entry->aux, EDGE_FALLTHRU);
+      edge e = make_edge (entry_block_map, (basic_block)new_entry->aux, EDGE_FALLTHRU);
       e->probability = REG_BR_PROB_BASE;
-      e->count = entry_block_map->count;
+      e->count = incomming_count;
     }
 
   if (gimple_in_ssa_p (cfun))
@@ -5206,6 +5229,23 @@ tree_function_versioning (tree old_decl, tree new_decl,
   if (id.dst_node->analyzed)
     cgraph_rebuild_references ();
   update_ssa (TODO_update_ssa);
+
+  /* After partial cloning we need to rescale frequencies, so they are
+     within proper range in the cloned function.  */
+  if (new_entry)
+    {
+      struct cgraph_edge *e;
+      rebuild_frequencies ();
+
+      new_version_node->count = ENTRY_BLOCK_PTR->count;
+      for (e = new_version_node->callees; e; e = e->next_callee)
+       {
+         basic_block bb = gimple_bb (e->call_stmt);
+         e->frequency = compute_call_stmt_bb_frequency (current_function_decl, bb);
+         e->count = bb->count;
+       }
+    }
+
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);