OSDN Git Service

2005-06-25 Thomas Koenig <Thomas.Koenig@online.de>
[pf3gnuchains/gcc-fork.git] / gcc / rtl-profile.c
index a53a004..085ef0c 100644 (file)
@@ -1,6 +1,6 @@
 /* Calculate branch probabilities, and basic block execution counts.
    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003  Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2005  Free Software Foundation, Inc.
    Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
    based on some ideas from Dain Samples of UC Berkeley.
    Further mangling by Bob Manson, Cygnus Support.
@@ -19,34 +19,11 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /* Generate basic block profile instrumentation and auxiliary files.
-   Profile generation is optimized, so that not all arcs in the basic
-   block graph need instrumenting. First, the BB graph is closed with
-   one entry (function start), and one exit (function exit).  Any
-   ABNORMAL_EDGE cannot be instrumented (because there is no control
-   path to place the code). We close the graph by inserting fake
-   EDGE_FAKE edges to the EXIT_BLOCK, from the sources of abnormal
-   edges that do not go to the exit_block. We ignore such abnormal
-   edges.  Naturally these fake edges are never directly traversed,
-   and so *cannot* be directly instrumented.  Some other graph
-   massaging is done. To optimize the instrumentation we generate the
-   BB minimal span tree, only edges that are not on the span tree
-   (plus the entry point) need instrumenting. From that information
-   all other edge counts can be deduced.  By construction all fake
-   edges must be on the spanning tree. We also attempt to place
-   EDGE_CRITICAL edges on the spanning tree.
-
-   The auxiliary file generated is <dumpbase>.bbg. The format is
-   described in full in gcov-io.h.  */
-
-/* ??? Register allocation should use basic block execution counts to
-   give preference to the most commonly executed blocks.  */
-
-/* ??? Should calculate branch probabilities before instrumenting code, since
-   then we can use arc counts to help decide which arcs to instrument.  */
+   RTL-based version.  See profile.c for overview.  */
 
 #include "config.h"
 #include "system.h"
@@ -62,6 +39,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "coverage.h"
 #include "value-prof.h"
 #include "tree.h"
+#include "ggc.h"
+
+/* Do initialization work for the edge profiler.  */
+
+static void
+rtl_init_edge_profiler (void)
+{
+  /* gen_edge_profiler calls safe_insert_insn_on_edge which needs
+     register liveness data to be available.  */
+  life_analysis (NULL, 0);
+}
 
 /* Output instructions as RTL to increment the edge execution count.  */
 
@@ -84,7 +72,7 @@ rtl_gen_edge_profiler (int edgeno, edge e)
 
   sequence = get_insns ();
   end_sequence ();
-  insert_insn_on_edge (sequence, e);
+  safe_insert_insn_on_edge (sequence, e);
   rebuild_jump_labels (e->insns.r);
 }
 
@@ -93,44 +81,42 @@ rtl_gen_edge_profiler (int edgeno, edge e)
    section for counters, BASE is offset of the counter position.  */
 
 static void
-rtl_gen_interval_profiler (struct histogram_value *value, unsigned tag,
-                      unsigned base)
+rtl_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
 {
-  unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
-  enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
+  enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
   rtx mem_ref, tmp, tmp1, mr, val;
   rtx sequence;
   rtx more_label = gen_label_rtx ();
   rtx less_label = gen_label_rtx ();
   rtx end_of_code_label = gen_label_rtx ();
-  int per_counter = gcov_size / BITS_PER_UNIT;
-  edge e = split_block (BLOCK_FOR_INSN ((rtx)value->insn),
-                  PREV_INSN ((rtx)value->insn));
+  int per_counter = GCOV_TYPE_SIZE / BITS_PER_UNIT;
+  edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
+                  PREV_INSN (value->hvalue.rtl.insn));
 
   start_sequence ();
 
-  if (value->seq)
-    emit_insn (value->seq);
+  if (value->hvalue.rtl.seq)
+    emit_insn (value->hvalue.rtl.seq);
 
   mr = gen_reg_rtx (Pmode);
 
   tmp = rtl_coverage_counter_ref (tag, base);
   tmp = force_reg (Pmode, XEXP (tmp, 0));
 
-  val = expand_simple_binop (value->mode, MINUS,
-                            copy_rtx (value->value),
+  val = expand_simple_binop (value->hvalue.rtl.mode, MINUS,
+                            copy_rtx (value->hvalue.rtl.value),
                             GEN_INT (value->hdata.intvl.int_start),
                             NULL_RTX, 0, OPTAB_WIDEN);
 
-  if (value->hdata.intvl.may_be_more)
     do_compare_rtx_and_jump (copy_rtx (val), GEN_INT (value->hdata.intvl.steps),
-                            GE, 0, value->mode, NULL_RTX, NULL_RTX, more_label);
-  if (value->hdata.intvl.may_be_less)
-    do_compare_rtx_and_jump (copy_rtx (val), const0_rtx, LT, 0, value->mode,
+                          GE, 0, value->hvalue.rtl.mode, NULL_RTX, NULL_RTX, 
+                          more_label);
+  do_compare_rtx_and_jump (copy_rtx (val), const0_rtx, LT, 0, 
+                          value->hvalue.rtl.mode,
                             NULL_RTX, NULL_RTX, less_label);
 
   /* We are in range.  */
-  tmp1 = expand_simple_binop (value->mode, MULT,
+  tmp1 = expand_simple_binop (value->hvalue.rtl.mode, MULT,
                              copy_rtx (val), GEN_INT (per_counter),
                              NULL_RTX, 0, OPTAB_WIDEN);
   tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp), tmp1, mr,
@@ -138,43 +124,27 @@ rtl_gen_interval_profiler (struct histogram_value *value, unsigned tag,
   if (tmp1 != mr)
     emit_move_insn (copy_rtx (mr), tmp1);
 
-  if (value->hdata.intvl.may_be_more
-      || value->hdata.intvl.may_be_less)
-    {
       emit_jump_insn (gen_jump (end_of_code_label));
       emit_barrier ();
-    }
 
   /* Above the interval.  */
-  if (value->hdata.intvl.may_be_more)
-    {
       emit_label (more_label);
       tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp),
                                  GEN_INT (per_counter * value->hdata.intvl.steps),
                                  mr, 0, OPTAB_WIDEN);
       if (tmp1 != mr)
        emit_move_insn (copy_rtx (mr), tmp1);
-      if (value->hdata.intvl.may_be_less)
-       {
          emit_jump_insn (gen_jump (end_of_code_label));
          emit_barrier ();
-       }
-    }
 
   /* Below the interval.  */
-  if (value->hdata.intvl.may_be_less)
-    {
       emit_label (less_label);
       tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp),
-               GEN_INT (per_counter * (value->hdata.intvl.steps
-                                       + (value->hdata.intvl.may_be_more ? 1 : 0))),
+                       GEN_INT (per_counter * (value->hdata.intvl.steps +1)),
                mr, 0, OPTAB_WIDEN);
       if (tmp1 != mr)
        emit_move_insn (copy_rtx (mr), tmp1);
-    }
 
-  if (value->hdata.intvl.may_be_more
-      || value->hdata.intvl.may_be_less)
     emit_label (end_of_code_label);
 
   mem_ref = validize_mem (gen_rtx_MEM (mode, mr));
@@ -196,60 +166,44 @@ rtl_gen_interval_profiler (struct histogram_value *value, unsigned tag,
    section for counters, BASE is offset of the counter position.  */
 
 static void
-rtl_gen_pow2_profiler (struct histogram_value *value, unsigned tag, 
-                       unsigned base)
+rtl_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
 {
-  unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
-  enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
+  enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
   rtx mem_ref, tmp, mr, uval;
   rtx sequence;
   rtx end_of_code_label = gen_label_rtx ();
-  rtx loop_label = gen_label_rtx ();
-  int per_counter = gcov_size / BITS_PER_UNIT;
-  edge e = split_block (BLOCK_FOR_INSN ((rtx)value->insn),
-                  PREV_INSN ((rtx)value->insn));
+  int per_counter = GCOV_TYPE_SIZE / BITS_PER_UNIT;
+  edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
+                       PREV_INSN (value->hvalue.rtl.insn));
 
   start_sequence ();
 
-  if (value->seq)
-    emit_insn (value->seq);
+  if (value->hvalue.rtl.seq)
+    emit_insn (value->hvalue.rtl.seq);
 
   mr = gen_reg_rtx (Pmode);
   tmp = rtl_coverage_counter_ref (tag, base);
   tmp = force_reg (Pmode, XEXP (tmp, 0));
   emit_move_insn (mr, tmp);
 
-  uval = gen_reg_rtx (value->mode);
-  emit_move_insn (uval, copy_rtx (value->value));
+  uval = gen_reg_rtx (value->hvalue.rtl.mode);
+  emit_move_insn (uval, copy_rtx (value->hvalue.rtl.value));
 
   /* Check for non-power of 2.  */
-  if (value->hdata.pow2.may_be_other)
-    {
-      do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, LE, 0, value->mode,
-                              NULL_RTX, NULL_RTX, end_of_code_label);
-      tmp = expand_simple_binop (value->mode, PLUS, copy_rtx (uval),
-                                constm1_rtx, NULL_RTX, 0, OPTAB_WIDEN);
-      tmp = expand_simple_binop (value->mode, AND, copy_rtx (uval), tmp,
-                                NULL_RTX, 0, OPTAB_WIDEN);
-      do_compare_rtx_and_jump (tmp, const0_rtx, NE, 0, value->mode, NULL_RTX,
-                              NULL_RTX, end_of_code_label);
-    }
-
-  /* Count log_2(value).  */
-  emit_label (loop_label);
-
-  tmp = expand_simple_binop (Pmode, PLUS, copy_rtx (mr), GEN_INT (per_counter), mr, 0, OPTAB_WIDEN);
+  do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, LE, 0, value->hvalue.rtl.mode,
+                          NULL_RTX, NULL_RTX, end_of_code_label);
+  tmp = expand_simple_binop (value->hvalue.rtl.mode, PLUS, copy_rtx (uval),
+                            constm1_rtx, NULL_RTX, 0, OPTAB_WIDEN);
+  tmp = expand_simple_binop (value->hvalue.rtl.mode, AND, copy_rtx (uval), tmp,
+                            NULL_RTX, 0, OPTAB_WIDEN);
+  do_compare_rtx_and_jump (tmp, const0_rtx, NE, 0, value->hvalue.rtl.mode, NULL_RTX,
+                          NULL_RTX, end_of_code_label);
+
+  tmp = expand_simple_binop (Pmode, PLUS, copy_rtx (mr), GEN_INT (per_counter),
+                            mr, 0, OPTAB_WIDEN);
   if (tmp != mr)
     emit_move_insn (copy_rtx (mr), tmp);
 
-  tmp = expand_simple_binop (value->mode, ASHIFTRT, copy_rtx (uval), const1_rtx,
-                            uval, 0, OPTAB_WIDEN);
-  if (tmp != uval)
-    emit_move_insn (copy_rtx (uval), tmp);
-
-  do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, NE, 0, value->mode,
-                          NULL_RTX, NULL_RTX, loop_label);
-
   /* Increase the counter.  */
   emit_label (end_of_code_label);
 
@@ -272,11 +226,10 @@ rtl_gen_pow2_profiler (struct histogram_value *value, unsigned tag,
    section for counters, BASE is offset of the counter position.  */
 
 static rtx
-rtl_gen_one_value_profiler_no_edge_manipulation (struct histogram_value *value,
-                                               unsigned tag, unsigned base)
+rtl_gen_one_value_profiler_no_edge_manipulation (histogram_value value,
+                                                unsigned tag, unsigned base)
 {
-  unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
-  enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
+  enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
   rtx stored_value_ref, counter_ref, all_ref, stored_value, counter, all;
   rtx tmp, uval;
   rtx sequence;
@@ -286,8 +239,8 @@ rtl_gen_one_value_profiler_no_edge_manipulation (struct histogram_value *value,
 
   start_sequence ();
 
-  if (value->seq)
-    emit_insn (value->seq);
+  if (value->hvalue.rtl.seq)
+    emit_insn (value->hvalue.rtl.seq);
 
   stored_value_ref = rtl_coverage_counter_ref (tag, base);
   counter_ref = rtl_coverage_counter_ref (tag, base + 1);
@@ -297,7 +250,7 @@ rtl_gen_one_value_profiler_no_edge_manipulation (struct histogram_value *value,
   all = validize_mem (all_ref);
 
   uval = gen_reg_rtx (mode);
-  convert_move (uval, copy_rtx (value->value), 0);
+  convert_move (uval, copy_rtx (value->hvalue.rtl.value), 0);
 
   /* Check if the stored value matches.  */
   do_compare_rtx_and_jump (copy_rtx (uval), copy_rtx (stored_value), EQ,
@@ -351,11 +304,10 @@ rtl_gen_one_value_profiler_no_edge_manipulation (struct histogram_value *value,
    section for counters, BASE is offset of the counter position.  */
 
 static void
-rtl_gen_one_value_profiler (struct histogram_value *value, unsigned tag,
-                       unsigned base)
+rtl_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
 {
-  edge e = split_block (BLOCK_FOR_INSN ((rtx)value->insn),
-                  PREV_INSN ((rtx)value->insn));
+  edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
+                  PREV_INSN (value->hvalue.rtl.insn));
   rtx sequence = rtl_gen_one_value_profiler_no_edge_manipulation (value, 
                        tag, base);
   rebuild_jump_labels (sequence);
@@ -368,38 +320,37 @@ rtl_gen_one_value_profiler (struct histogram_value *value, unsigned tag,
    section for counters, BASE is offset of the counter position.  */
 
 static void
-rtl_gen_const_delta_profiler (struct histogram_value *value, unsigned tag,
-                         unsigned base)
+rtl_gen_const_delta_profiler (histogram_value value, unsigned tag, unsigned base)
 {
-  struct histogram_value one_value_delta;
-  unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
-  enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
+  histogram_value one_value_delta;
+  enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
   rtx stored_value_ref, stored_value, tmp, uval;
   rtx sequence;
-  edge e = split_block (BLOCK_FOR_INSN ((rtx)value->insn),
-                  PREV_INSN ((rtx)value->insn));
+  edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
+                  PREV_INSN (value->hvalue.rtl.insn));
 
   start_sequence ();
 
-  if (value->seq)
-    emit_insn (value->seq);
+  if (value->hvalue.rtl.seq)
+    emit_insn (value->hvalue.rtl.seq);
 
   stored_value_ref = rtl_coverage_counter_ref (tag, base);
   stored_value = validize_mem (stored_value_ref);
 
   uval = gen_reg_rtx (mode);
-  convert_move (uval, copy_rtx (value->value), 0);
+  convert_move (uval, copy_rtx (value->hvalue.rtl.value), 0);
   tmp = expand_simple_binop (mode, MINUS,
                             copy_rtx (uval), copy_rtx (stored_value),
                             NULL_RTX, 0, OPTAB_WIDEN);
 
-  one_value_delta.value = tmp;
-  one_value_delta.mode = mode;
-  one_value_delta.seq = NULL_RTX;
-  one_value_delta.insn = value->insn;
-  one_value_delta.type = HIST_TYPE_SINGLE_VALUE;
-  emit_insn (rtl_gen_one_value_profiler_no_edge_manipulation (&one_value_delta,
-                                            tag, base + 1));
+  one_value_delta = ggc_alloc (sizeof (*one_value_delta));
+  one_value_delta->hvalue.rtl.value = tmp;
+  one_value_delta->hvalue.rtl.mode = mode;
+  one_value_delta->hvalue.rtl.seq = NULL_RTX;
+  one_value_delta->hvalue.rtl.insn = value->hvalue.rtl.insn;
+  one_value_delta->type = HIST_TYPE_SINGLE_VALUE;
+  emit_insn (rtl_gen_one_value_profiler_no_edge_manipulation (one_value_delta,
+                                                             tag, base + 1));
   emit_move_insn (copy_rtx (stored_value), uval);
   sequence = get_insns ();
   end_sequence ();
@@ -415,6 +366,7 @@ static FILE *rtl_profile_dump_file (void) {
 \f
 struct profile_hooks rtl_profile_hooks =
 {
+  rtl_init_edge_profiler,
   rtl_gen_edge_profiler,
   rtl_gen_interval_profiler,
   rtl_gen_pow2_profiler,