OSDN Git Service

2009-04-09 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-profile.c
index 4f6b792..06f113b 100644 (file)
@@ -1,6 +1,7 @@
 /* Calculate branch probabilities, and basic block execution counts.
    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004  Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   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.
@@ -10,7 +11,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -19,9 +20,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 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.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* Generate basic block profile instrumentation and auxiliary files.
    Tree-based version.  See profile.c for overview.  */
@@ -44,34 +44,172 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tree-pass.h"
 #include "timevar.h"
 #include "value-prof.h"
-
+#include "ggc.h"
+#include "cgraph.h"
+
+static GTY(()) tree gcov_type_node;
+static GTY(()) tree gcov_type_tmp_var;
+static GTY(()) tree tree_interval_profiler_fn;
+static GTY(()) tree tree_pow2_profiler_fn;
+static GTY(()) tree tree_one_value_profiler_fn;
+static GTY(()) tree tree_indirect_call_profiler_fn;
+static GTY(()) tree tree_average_profiler_fn;
+static GTY(()) tree tree_ior_profiler_fn;
 \f
 
+static GTY(()) tree ic_void_ptr_var;
+static GTY(()) tree ic_gcov_type_ptr_var;
+static GTY(()) tree ptr_void;
+
 /* Do initialization work for the edge profiler.  */
 
+/* Add code:
+   static gcov*        __gcov_indirect_call_counters; // pointer to actual counter
+   static void*        __gcov_indirect_call_callee; // actual callee address
+*/
+static void
+tree_init_ic_make_global_vars (void)
+{
+  tree  gcov_type_ptr;
+
+  ptr_void = build_pointer_type (void_type_node);
+  
+  ic_void_ptr_var 
+    = build_decl (VAR_DECL, 
+                 get_identifier ("__gcov_indirect_call_callee"), 
+                 ptr_void);
+  TREE_STATIC (ic_void_ptr_var) = 1;
+  TREE_PUBLIC (ic_void_ptr_var) = 0;
+  DECL_ARTIFICIAL (ic_void_ptr_var) = 1;
+  DECL_INITIAL (ic_void_ptr_var) = NULL;
+  assemble_variable (ic_void_ptr_var, 0, 0, 0);
+
+  gcov_type_ptr = build_pointer_type (get_gcov_type ());
+  ic_gcov_type_ptr_var 
+    = build_decl (VAR_DECL, 
+                 get_identifier ("__gcov_indirect_call_counters"), 
+                 gcov_type_ptr);
+  TREE_STATIC (ic_gcov_type_ptr_var) = 1;
+  TREE_PUBLIC (ic_gcov_type_ptr_var) = 0;
+  DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1;
+  DECL_INITIAL (ic_gcov_type_ptr_var) = NULL;
+  assemble_variable (ic_gcov_type_ptr_var, 0, 0, 0);
+}
+
 static void
 tree_init_edge_profiler (void)
 {
+  tree interval_profiler_fn_type;
+  tree pow2_profiler_fn_type;
+  tree one_value_profiler_fn_type;
+  tree gcov_type_ptr;
+  tree ic_profiler_fn_type;
+  tree average_profiler_fn_type;
+
+  if (!gcov_type_node)
+    {
+      gcov_type_node = get_gcov_type ();
+      gcov_type_ptr = build_pointer_type (gcov_type_node);
+
+      /* void (*) (gcov_type *, gcov_type, int, unsigned)  */
+      interval_profiler_fn_type
+             = build_function_type_list (void_type_node,
+                                         gcov_type_ptr, gcov_type_node,
+                                         integer_type_node,
+                                         unsigned_type_node, NULL_TREE);
+      tree_interval_profiler_fn
+             = build_fn_decl ("__gcov_interval_profiler",
+                                    interval_profiler_fn_type);
+
+      /* void (*) (gcov_type *, gcov_type)  */
+      pow2_profiler_fn_type
+             = build_function_type_list (void_type_node,
+                                         gcov_type_ptr, gcov_type_node,
+                                         NULL_TREE);
+      tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler",
+                                                  pow2_profiler_fn_type);
+
+      /* void (*) (gcov_type *, gcov_type)  */
+      one_value_profiler_fn_type
+             = build_function_type_list (void_type_node,
+                                         gcov_type_ptr, gcov_type_node,
+                                         NULL_TREE);
+      tree_one_value_profiler_fn
+             = build_fn_decl ("__gcov_one_value_profiler",
+                                    one_value_profiler_fn_type);
+
+      tree_init_ic_make_global_vars ();
+      
+      /* void (*) (gcov_type *, gcov_type, void *, void *)  */
+      ic_profiler_fn_type
+              = build_function_type_list (void_type_node,
+                                         gcov_type_ptr, gcov_type_node,
+                                         ptr_void,
+                                         ptr_void, NULL_TREE);
+      tree_indirect_call_profiler_fn
+             = build_fn_decl ("__gcov_indirect_call_profiler",
+                                    ic_profiler_fn_type);
+      /* void (*) (gcov_type *, gcov_type)  */
+      average_profiler_fn_type
+             = build_function_type_list (void_type_node,
+                                         gcov_type_ptr, gcov_type_node, NULL_TREE);
+      tree_average_profiler_fn
+             = build_fn_decl ("__gcov_average_profiler",
+                                    average_profiler_fn_type);
+      tree_ior_profiler_fn
+             = build_fn_decl ("__gcov_ior_profiler",
+                                    average_profiler_fn_type);
+    }
+}
+
+/* New call was added, make goto call edges if neccesary.  */
+
+static void
+add_abnormal_goto_call_edges (gimple_stmt_iterator gsi)
+{
+  gimple stmt = gsi_stmt (gsi);
+
+  if (!stmt_can_make_abnormal_goto (stmt))
+    return;
+  if (!gsi_end_p (gsi))
+    split_block (gimple_bb (stmt), stmt);
+  make_abnormal_goto_edges (gimple_bb (stmt), true);
 }
 
 /* Output instructions as GIMPLE trees to increment the edge 
    execution count, and insert them on E.  We rely on 
-   bsi_insert_on_edge to preserve the order.  */
+   gsi_insert_on_edge to preserve the order.  */
 
 static void
 tree_gen_edge_profiler (int edgeno, edge e)
 {
-  tree tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  tree tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
-  tree stmt1 = build (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref);
-  tree stmt2 = build (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
-                     build (PLUS_EXPR, GCOV_TYPE_NODE, 
-                            tmp1, integer_one_node));
-  tree stmt3 = build (MODIFY_EXPR, GCOV_TYPE_NODE, ref, tmp2);
-  bsi_insert_on_edge (e, stmt1);
-  bsi_insert_on_edge (e, stmt2);
-  bsi_insert_on_edge (e, stmt3);
+  tree ref, one;
+  gimple stmt1, stmt2, stmt3;
+
+  /* We share one temporary variable declaration per function.  This
+     gets re-set in tree_profiling.  */
+  if (gcov_type_tmp_var == NULL_TREE)
+    gcov_type_tmp_var = create_tmp_var (gcov_type_node, "PROF_edge_counter");
+  ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
+  one = build_int_cst (gcov_type_node, 1);
+  stmt1 = gimple_build_assign (gcov_type_tmp_var, ref);
+  stmt2 = gimple_build_assign_with_ops (PLUS_EXPR, gcov_type_tmp_var,
+                                       gcov_type_tmp_var, one);
+  stmt3 = gimple_build_assign (unshare_expr (ref), gcov_type_tmp_var);
+  gsi_insert_on_edge (e, stmt1);
+  gsi_insert_on_edge (e, stmt2);
+  gsi_insert_on_edge (e, stmt3);
+}
+
+/* Emits code to get VALUE to instrument at GSI, and returns the
+   variable containing the value.  */
+
+static tree
+prepare_instrumented_value (gimple_stmt_iterator *gsi, histogram_value value)
+{
+  tree val = value->hvalue.value;
+  return force_gimple_operand_gsi (gsi, fold_convert (gcov_type_node, val),
+                                  true, NULL_TREE, true, GSI_SAME_STMT);
 }
 
 /* Output instructions as GIMPLE trees to increment the interval histogram 
@@ -81,161 +219,24 @@ tree_gen_edge_profiler (int edgeno, edge e)
 static void
 tree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
 {
-  tree op, op1, op2, op1copy, op2copy;
-  tree tmp1, tmp2, tmp3, val, index;
-  tree label_decl2, label_decl3, label_decl4, label_decl5, label_decl6;
-  edge e12, e23, e34, e45, e56;
-  tree label2, label3, label4, label5, label6;
-  tree stmt1, stmt2, stmt3, stmt4;
-  /* Initializations are to prevent bogus uninitialized warnings. */
-  tree bb1end = NULL_TREE, bb2end = NULL_TREE, bb3end = NULL_TREE;
-  tree bb4end = NULL_TREE, bb5end = NULL_TREE;
-  tree ref = tree_coverage_counter_ref (tag, base), ref2;
-  basic_block bb2, bb3, bb4, bb5, bb6;
-  tree stmt = value->hvalue.tree.stmt;
-  block_stmt_iterator bsi = bsi_for_stmt (stmt);
-  basic_block bb = bb_for_stmt (stmt);
-  tree optype;
-
-  op = stmt;
-  if (TREE_CODE (stmt) == RETURN_EXPR
-      && TREE_OPERAND (stmt, 0)
-      && TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR)
-    op = TREE_OPERAND (stmt, 0);
-  /* op == MODIFY_EXPR */
-  op = TREE_OPERAND (op, 1);
-  /* op == TRUNC_DIV or TRUNC_MOD */
-  op1 = TREE_OPERAND (op, 0);
-  op2 = TREE_OPERAND (op, 1);
-  optype = TREE_TYPE (op);
-
-  /* Blocks:
-     Original = 1 
-     For 2nd compare = 2
-     Normal case, neither more nor less = 3
-     More = 4
-     Less = 5
-     End = 6  */
-  label_decl2 = create_artificial_label ();
-  label_decl3 = create_artificial_label ();
-  label_decl4 = create_artificial_label ();
-  label_decl5 = create_artificial_label ();
-  label_decl6 = create_artificial_label ();
-
-  /* Do not evaluate op1 or op2 more than once.  Probably
-     volatile loads are the only things that could cause
-     a problem, but this is harmless in any case.  */
-  op1copy = create_tmp_var (optype, "PROF");
-  op2copy = create_tmp_var (optype, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, optype, op1copy, op1);
-  stmt2 = build2 (MODIFY_EXPR, optype, op2copy, op2);
-  TREE_OPERAND (op, 0) = op1copy;
-  TREE_OPERAND (op, 1) = op2copy;
-
-  val = create_tmp_var (optype, "PROF");
-  stmt3 = build2 (MODIFY_EXPR, optype, val,
-                 build2 (TRUNC_DIV_EXPR, optype, op1copy, op2copy));
-  stmt4 = build2 (MODIFY_EXPR, optype, val,
-                 build2 (MINUS_EXPR, optype, val,
-                               build_int_cst (optype, value->hdata.intvl.int_start)));
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
-
-  index = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-
-  /* Check for too big.  */
-  stmt1 = build3 (COND_EXPR, void_type_node,
-           build2 (GE_EXPR, boolean_type_node, val,
-                       build_int_cst (optype, value->hdata.intvl.steps)),
-           build1 (GOTO_EXPR, void_type_node, label_decl4),
-           build1 (GOTO_EXPR, void_type_node, label_decl2));
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bb1end = stmt1;
-
-  /* Check for too small.  */
-  label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
-  bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
-  stmt1 = build3 (COND_EXPR, void_type_node,
-           build2 (LT_EXPR, boolean_type_node, val, integer_zero_node),
-           build1 (GOTO_EXPR, void_type_node, label_decl5),
-           build1 (GOTO_EXPR, void_type_node, label_decl3));
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bb2end = stmt1;
-
-  /* Normal case, within range. */
-  label3 = build1 (LABEL_EXPR, void_type_node, label_decl3);
-  bsi_insert_before (&bsi, label3, BSI_SAME_STMT);
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, index, 
-                   build1 (NOP_EXPR, GCOV_TYPE_NODE, val));
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bb3end = stmt1;
-
-  /* Too big */
-  label4 = build1 (LABEL_EXPR, void_type_node, label_decl4);
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, index, 
-                   build_int_cst (GCOV_TYPE_NODE, value->hdata.intvl.steps));
-  bsi_insert_before (&bsi, label4, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bb4end = stmt1;
-
-  /* Too small */
-  label5 = build1 (LABEL_EXPR, void_type_node, label_decl5);
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, index, 
-                   build_int_cst (GCOV_TYPE_NODE, value->hdata.intvl.steps + 1));
-  bsi_insert_before (&bsi, label5, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bb5end = stmt1;
-
-  /* Increment appropriate counter. */
-  label6 = build1 (LABEL_EXPR, void_type_node, label_decl6);
-  bsi_insert_before (&bsi, label6, BSI_SAME_STMT);
-
-  tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  tmp3 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, 
-                   build2 (PLUS_EXPR, GCOV_TYPE_NODE, index, 
-                           TREE_OPERAND (ref, 1)));
-  TREE_OPERAND (ref, 1) = tmp1;
-  /* Make a copy to avoid sharing complaints. */
-  ref2 = build4 (ARRAY_REF, TREE_TYPE (ref), TREE_OPERAND (ref, 0), 
-               TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2), 
-               TREE_OPERAND (ref, 3));
-
-  stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2, ref);
-  stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp3, 
-                   build2 (PLUS_EXPR, GCOV_TYPE_NODE, tmp2, integer_one_node));
-  stmt4 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref2, tmp3);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
-
-  /* Now fix up the CFG. */
-  /* 1->2,4; 2->3,5; 3->6; 4->6; 5->6 */
-  e12 = split_block (bb, bb1end);
-  bb2 = e12->dest;
-  e23 = split_block (bb2, bb2end);
-  bb3 = e23->dest;
-  e34 = split_block (bb3, bb3end);
-  bb4 = e34->dest;
-  e45 = split_block (bb4, bb4end);
-  bb5 = e45->dest;
-  e56 = split_block (bb5, bb5end);
-  bb6 = e56->dest;
-
-  e12->flags &= ~EDGE_FALLTHRU;
-  e12->flags |= EDGE_FALSE_VALUE;
-  make_edge (bb, bb4, EDGE_TRUE_VALUE);
-  e23->flags &= ~EDGE_FALLTHRU;
-  e23->flags |= EDGE_FALSE_VALUE;
-  make_edge (bb2, bb5, EDGE_TRUE_VALUE);
-  remove_edge (e34);
-  make_edge (bb3, bb6, EDGE_FALLTHRU);
-  remove_edge (e45);
-  make_edge (bb4, bb6, EDGE_FALLTHRU);
+  gimple stmt = value->hvalue.stmt;
+  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+  tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
+  gimple call;
+  tree val;
+  tree start = build_int_cst_type (integer_type_node,
+                                  value->hdata.intvl.int_start);
+  tree steps = build_int_cst_type (unsigned_type_node,
+                                  value->hdata.intvl.steps);
+  
+  ref_ptr = force_gimple_operand_gsi (&gsi,
+                                     build_addr (ref, current_function_decl),
+                                     true, NULL_TREE, true, GSI_SAME_STMT);
+  val = prepare_instrumented_value (&gsi, value);
+  call = gimple_build_call (tree_interval_profiler_fn, 4,
+                           ref_ptr, val, start, steps);
+  gsi_insert_before (&gsi, call, GSI_NEW_STMT);
+  add_abnormal_goto_call_edges (gsi);
 }
 
 /* Output instructions as GIMPLE trees to increment the power of two histogram 
@@ -245,160 +246,18 @@ tree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
 static void
 tree_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
 {
-  tree op;
-  tree tmp1, tmp2, tmp3;
-  tree index, denom;
-  tree label_decl1 = create_artificial_label ();
-  tree label_decl2 = create_artificial_label ();
-  tree label_decl3 = create_artificial_label ();
-  tree label1, label2, label3;
-  tree stmt1, stmt2, stmt3, stmt4;
-  tree bb1end, bb2end, bb3end;
-  tree ref = tree_coverage_counter_ref (tag, base), ref2;
-  basic_block bb2, bb3, bb4;
-  tree stmt = value->hvalue.tree.stmt;
-  block_stmt_iterator bsi = bsi_for_stmt (stmt);
-  basic_block bb = bb_for_stmt (stmt);
-  tree optype, optypesigned, optypeunsigned;
-
-  op = stmt;
-  if (TREE_CODE (stmt) == RETURN_EXPR
-      && TREE_OPERAND (stmt, 0)
-      && TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR)
-    op = TREE_OPERAND (stmt, 0);
-  /* op == MODIFY_EXPR */
-  op = TREE_OPERAND (op, 1);
-  /* op == TRUNC_DIV or TRUNC_MOD */
-  op = TREE_OPERAND (op, 1);
-  /* op == denominator */
-  optype = TREE_TYPE (op);
-  if (TYPE_UNSIGNED (optype))
-    {
-      /* Right shift must be unsigned. */
-      optypeunsigned = optype;
-      optypesigned = build_distinct_type_copy (optype);
-      TYPE_UNSIGNED (optypesigned) = false;
-    }
-  else
-    {
-      /* Compare to zero must be signed. */
-      optypesigned = optype;
-      optypeunsigned = build_distinct_type_copy (optype);
-      TYPE_UNSIGNED (optypeunsigned) = true;
-    }
-
-  /* Set up variables and check if denominator is negative when considered
-     as signed.  */
-  index = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  denom = create_tmp_var (optype, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, index, integer_zero_node);
-  stmt2 = build2 (MODIFY_EXPR, optype, denom, op);
-  if (optypesigned == optype)
-    {
-      tmp1 = denom;
-      stmt3 = NULL_TREE;
-    }
-  else
-    {
-      tmp1 = create_tmp_var (optypesigned, "PROF");
-      stmt3 = build2 (MODIFY_EXPR, optypesigned, tmp1,
-                           build1 (NOP_EXPR, optypesigned, denom));
-    }
-  stmt4 = build3 (COND_EXPR, void_type_node,
-               build2 (LE_EXPR, boolean_type_node, tmp1, integer_zero_node),
-               build1 (GOTO_EXPR, void_type_node, label_decl3),
-               build1 (GOTO_EXPR, void_type_node, label_decl1));
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  if (stmt3)
-    bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
-  bb1end = stmt4;
-
-  /* Nonnegative.  Check if denominator is power of 2. */
-  label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
-  tmp1 = create_tmp_var (optype, "PROF");
-  tmp2 = create_tmp_var (optype, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, optype, tmp1,
-                   build2 (PLUS_EXPR, optype, denom, integer_minus_one_node));
-  stmt2 = build2 (MODIFY_EXPR, optype, tmp2,
-                   build2 (BIT_AND_EXPR, optype, tmp1, denom));
-  stmt3 = build3 (COND_EXPR, void_type_node, 
-               build2 (NE_EXPR, boolean_type_node, tmp2, integer_zero_node),
-               build1 (GOTO_EXPR, void_type_node, label_decl3),
-               build1 (GOTO_EXPR, void_type_node, label_decl2));
-  bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-  bb2end = stmt3;
-
-  /* Loop.  Increment index, shift denominator, repeat if denominator nonzero. */
-  label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, index, 
-                   build2 (PLUS_EXPR, GCOV_TYPE_NODE, index, integer_one_node));
-  if (optypeunsigned == optype)
-    {
-      tmp1 = denom;
-      stmt2 = NULL_TREE;
-    }
-  else
-    {
-      tmp1 = create_tmp_var (optypeunsigned, "PROF");
-      stmt2 = build2 (MODIFY_EXPR, optypeunsigned, tmp1,
-                       build1 (NOP_EXPR, optypeunsigned, denom));
-    }
-  stmt3 = build2 (MODIFY_EXPR, optype, denom,
-                   build2 (RSHIFT_EXPR, optype, tmp1, integer_one_node));
-  stmt4 = build3 (COND_EXPR, void_type_node, 
-               build2 (NE_EXPR, boolean_type_node, denom, integer_zero_node),
-               build1 (GOTO_EXPR, void_type_node, label_decl2),
-               build1 (GOTO_EXPR, void_type_node, label_decl3));
-  bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  if (stmt2)
-    bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
-  bb3end = stmt4;
-
-  /* Increment the appropriate counter.  */
-  label3 = build1 (LABEL_EXPR, void_type_node, label_decl3);
-  tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  tmp3 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, 
-                   build2 (PLUS_EXPR, GCOV_TYPE_NODE, index, TREE_OPERAND (ref, 1)));
-  TREE_OPERAND (ref, 1) = tmp1;
-  /* Make a copy to avoid sharing complaints. */
-  ref2 = build4 (ARRAY_REF, TREE_TYPE (ref), TREE_OPERAND (ref, 0), 
-               TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
-  stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2, ref);
-  stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp3, 
-                   build2 (PLUS_EXPR, GCOV_TYPE_NODE, tmp2, integer_one_node));
-  stmt4 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref2, tmp3);
-  bsi_insert_before (&bsi, label3, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
-
-  /* Now fix up the CFG. */
-  bb2 = (split_block (bb, bb1end))->dest;
-  bb3 = (split_block (bb2, bb2end))->dest;
-  bb4 = (split_block (bb3, bb3end))->dest;
-
-  EDGE_SUCC (bb, 0)->flags &= ~EDGE_FALLTHRU;
-  EDGE_SUCC (bb, 0)->flags |= EDGE_FALSE_VALUE;
-  make_edge (bb, bb4, EDGE_TRUE_VALUE);
-
-  EDGE_SUCC (bb2, 0)->flags &= ~EDGE_FALLTHRU;
-  EDGE_SUCC (bb2, 0)->flags |= EDGE_FALSE_VALUE;
-  make_edge (bb2, bb4, EDGE_TRUE_VALUE);
-
-  EDGE_SUCC (bb3, 0)->flags &= ~EDGE_FALLTHRU;
-  EDGE_SUCC (bb3, 0)->flags |= EDGE_FALSE_VALUE;
-  make_edge (bb3, bb3, EDGE_TRUE_VALUE);
+  gimple stmt = value->hvalue.stmt;
+  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+  tree ref_ptr = tree_coverage_counter_addr (tag, base);
+  gimple call;
+  tree val;
+  
+  ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
+                                     true, NULL_TREE, true, GSI_SAME_STMT);
+  val = prepare_instrumented_value (&gsi, value);
+  call = gimple_build_call (tree_pow2_profiler_fn, 2, ref_ptr, val);
+  gsi_insert_before (&gsi, call, GSI_NEW_STMT);
+  add_abnormal_goto_call_edges (gsi);
 }
 
 /* Output instructions as GIMPLE trees for code to find the most common value.
@@ -408,148 +267,108 @@ tree_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
 static void
 tree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
 {
-  tree op;
-  tree tmp1, tmp2, tmp3;
-  tree label_decl1 = create_artificial_label ();
-  tree label_decl2 = create_artificial_label ();
-  tree label_decl3 = create_artificial_label ();
-  tree label_decl4 = create_artificial_label ();
-  tree label_decl5 = create_artificial_label ();
-  tree label1, label2, label3, label4, label5;
-  tree stmt1, stmt2, stmt3, stmt4;
-  tree bb1end, bb2end, bb3end, bb4end, bb5end;
-  tree ref1 = tree_coverage_counter_ref (tag, base);
-  tree ref2 = tree_coverage_counter_ref (tag, base + 1);
-  tree ref3 = tree_coverage_counter_ref (tag, base + 2);
-  basic_block bb2, bb3, bb4, bb5, bb6;
-  tree stmt = value->hvalue.tree.stmt;
-  block_stmt_iterator bsi = bsi_for_stmt (stmt);
-  basic_block bb = bb_for_stmt (stmt);
-  tree optype;
-
-  op = stmt;
-  if (TREE_CODE (stmt) == RETURN_EXPR
-      && TREE_OPERAND (stmt, 0)
-      && TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR)
-    op = TREE_OPERAND (stmt, 0);
-  /* op == MODIFY_EXPR */
-  op = TREE_OPERAND (op, 1);
-  /* op == TRUNC_DIV or TRUNC_MOD */
-  op = TREE_OPERAND (op, 1);
-  /* op == denominator */
-  optype = TREE_TYPE (op);
-
-  /* Check if the stored value matches. */
-  tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  tmp2 = create_tmp_var (optype, "PROF");
-  tmp3 = create_tmp_var (optype, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref1);
-  stmt2 = build2 (MODIFY_EXPR, optype, tmp2, 
-                   build1 (NOP_EXPR, optype, tmp1));
-  stmt3 = build2 (MODIFY_EXPR, optype, tmp3, op);
-  stmt4 = build3 (COND_EXPR, void_type_node, 
-               build2 (EQ_EXPR, boolean_type_node, tmp2, tmp3),
-               build1 (GOTO_EXPR, void_type_node, label_decl4),
-               build1 (GOTO_EXPR, void_type_node, label_decl1));
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
-  bb1end = stmt4;
-
-  /* Does not match; check whether the counter is zero. */
-  label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
-  tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref2);
-  stmt2 = build3 (COND_EXPR, void_type_node, 
-               build2 (EQ_EXPR, boolean_type_node, tmp1, integer_zero_node),
-               build1 (GOTO_EXPR, void_type_node, label_decl3), 
-               build1 (GOTO_EXPR, void_type_node, label_decl2));
-  bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bb2end = stmt2;
-
-  /* Counter is not zero yet, decrement. */
-  label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
-  tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref2);
-  stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
-                     build (MINUS_EXPR, GCOV_TYPE_NODE, 
-                            tmp1, integer_one_node));
-  stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref2, tmp2);
-  bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-  bb3end = stmt3;
-
-  /* Counter was zero, store new value. */
-  label3 = build1 (LABEL_EXPR, void_type_node, label_decl3);
-  tmp1 = create_tmp_var (optype, "PROF");
-  tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, optype, tmp1, op);
-  stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2, 
-                       build1 (NOP_EXPR, GCOV_TYPE_NODE, tmp1));
-  stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref1, tmp2);
-  bsi_insert_before (&bsi, label3, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-  bb4end = stmt3;
-  /* (fall through) */
-
-  /* Increment counter.  */
-  label4 = build1 (LABEL_EXPR, void_type_node, label_decl4);
-  tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref2);
-  stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
-                     build (PLUS_EXPR, GCOV_TYPE_NODE, 
-                            tmp1, integer_one_node));
-  stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref2, tmp2);
-  bsi_insert_before (&bsi, label4, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-  bb5end = stmt3;
-
-  /* Increment the counter of all executions; this seems redundant given
-     that we have counts for edges in cfg, but it may happen that some
-     optimization will change the counts for the block (either because
-     it is unable to update them correctly, or because it will duplicate
-     the block or its part).  */
-  label5 = build1 (LABEL_EXPR, void_type_node, label_decl5);
-  tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
-  stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref3);
-  stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
-                     build (PLUS_EXPR, GCOV_TYPE_NODE, 
-                            tmp1, integer_one_node));
-  stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref3, tmp2);
-  bsi_insert_before (&bsi, label5, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
-  bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-
-  /* Now fix up the CFG. */
-  bb2 = (split_block (bb, bb1end))->dest;
-  bb3 = (split_block (bb2, bb2end))->dest;
-  bb4 = (split_block (bb3, bb3end))->dest;
-  bb5 = (split_block (bb4, bb4end))->dest;
-  bb6 = (split_block (bb5, bb5end))->dest;
-
-  EDGE_SUCC (bb, 0)->flags &= ~EDGE_FALLTHRU;
-  EDGE_SUCC (bb, 0)->flags |= EDGE_FALSE_VALUE;
-  make_edge (bb, bb5, EDGE_TRUE_VALUE);
-
-  EDGE_SUCC (bb2, 0)->flags &= ~EDGE_FALLTHRU;
-  EDGE_SUCC (bb2, 0)->flags |= EDGE_FALSE_VALUE;
-  make_edge (bb2, bb4, EDGE_TRUE_VALUE);
-
-  remove_edge (EDGE_SUCC (bb3, 0));
-  make_edge (bb3, bb6, EDGE_FALLTHRU);
+  gimple stmt = value->hvalue.stmt;
+  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+  tree ref_ptr = tree_coverage_counter_addr (tag, base);
+  gimple call;
+  tree val;
+  
+  ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
+                                     true, NULL_TREE, true, GSI_SAME_STMT);
+  val = prepare_instrumented_value (&gsi, value);
+  call = gimple_build_call (tree_one_value_profiler_fn, 2, ref_ptr, val);
+  gsi_insert_before (&gsi, call, GSI_NEW_STMT);
+  add_abnormal_goto_call_edges (gsi);
+}
+
+
+/* Output instructions as GIMPLE trees for code to find the most
+   common called function in indirect call.  
+   VALUE is the call expression whose indirect callee is profiled.
+   TAG is the tag of the section for counters, BASE is offset of the
+   counter position.  */
+
+static void
+tree_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base)
+{
+  tree tmp1;
+  gimple stmt1, stmt2, stmt3;
+  gimple stmt = value->hvalue.stmt;
+  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+  tree ref_ptr = tree_coverage_counter_addr (tag, base);
+
+  ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
+                                     true, NULL_TREE, true, GSI_SAME_STMT);
+
+  /* Insert code:
+    
+    __gcov_indirect_call_counters = get_relevant_counter_ptr (); 
+    __gcov_indirect_call_callee = (void *) indirect call argument;
+   */
+
+  tmp1 = create_tmp_var (ptr_void, "PROF");
+  stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr);
+  stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value));
+  stmt3 = gimple_build_assign (ic_void_ptr_var, tmp1);
+
+  gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
+  gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
+  gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT);
+}
+
+
+/* Output instructions as GIMPLE trees for code to find the most
+   common called function in indirect call. Insert instructions at the
+   beginning of every possible called function.
+  */
+
+static void
+tree_gen_ic_func_profiler (void)
+{
+  struct cgraph_node * c_node = cgraph_node (current_function_decl);
+  gimple_stmt_iterator gsi;
+  edge e;
+  basic_block bb;
+  edge_iterator ei;
+  gimple stmt1, stmt2;
+  tree tree_uid, cur_func;
+
+  if (!c_node->needed)
+    return;
+  
+  tree_init_edge_profiler ();
+  
+  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
+    {
+      tree void0;
+
+      bb = split_edge (e);
+      gsi = gsi_start_bb (bb);
+
+      cur_func = force_gimple_operand_gsi (&gsi,
+                                          build_addr (current_function_decl, 
+                                                      current_function_decl),
+                                          true, NULL_TREE,
+                                          true, GSI_SAME_STMT);
+      tree_uid = build_int_cst (gcov_type_node, c_node->pid);
+      stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4,
+                                ic_gcov_type_ptr_var,
+                                tree_uid,
+                                cur_func,
+                                ic_void_ptr_var);
+      gsi_insert_after (&gsi, stmt1, GSI_NEW_STMT);
+      gcc_assert (EDGE_COUNT (bb->succs) == 1);
+      bb = split_edge (EDGE_I (bb->succs, 0));
+      add_abnormal_goto_call_edges (gsi);
+
+      gsi = gsi_start_bb (bb);
+      /* Set __gcov_indirect_call_callee to 0,
+         so that calls from other modules won't get misattributed
+        to the last caller of the current callee. */
+      void0 = build_int_cst (build_pointer_type (void_type_node), 0);
+      stmt2 = gimple_build_assign (ic_void_ptr_var, void0);
+      gsi_insert_after (&gsi, stmt2, GSI_NEW_STMT);
+    }
 }
 
 /* Output instructions as GIMPLE trees for code to find the most common value 
@@ -558,9 +377,9 @@ tree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
    section for counters, BASE is offset of the counter position.  */
 
 static void
-tree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED, 
-                               unsigned tag ATTRIBUTE_UNUSED,
-                               unsigned base ATTRIBUTE_UNUSED)
+tree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED,
+                              unsigned tag ATTRIBUTE_UNUSED,
+                              unsigned base ATTRIBUTE_UNUSED)
 {
   /* FIXME implement this.  */
 #ifdef ENABLE_CHECKING
@@ -569,6 +388,49 @@ tree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED,
   gcc_unreachable ();
 }
 
+/* Output instructions as GIMPLE trees to increment the average histogram 
+   counter.  VALUE is the expression whose value is profiled.  TAG is the 
+   tag of the section for counters, BASE is offset of the counter position.  */
+
+static void
+tree_gen_average_profiler (histogram_value value, unsigned tag, unsigned base)
+{
+  gimple stmt = value->hvalue.stmt;
+  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+  tree ref_ptr = tree_coverage_counter_addr (tag, base);
+  gimple call;
+  tree val;
+  
+  ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
+                                     true, NULL_TREE,
+                                     true, GSI_SAME_STMT);
+  val = prepare_instrumented_value (&gsi, value);
+  call = gimple_build_call (tree_average_profiler_fn, 2, ref_ptr, val);
+  gsi_insert_before (&gsi, call, GSI_NEW_STMT);
+  add_abnormal_goto_call_edges (gsi);
+}
+
+/* Output instructions as GIMPLE trees to increment the ior histogram 
+   counter.  VALUE is the expression whose value is profiled.  TAG is the 
+   tag of the section for counters, BASE is offset of the counter position.  */
+
+static void
+tree_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base)
+{
+  gimple stmt = value->hvalue.stmt;
+  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+  tree ref_ptr = tree_coverage_counter_addr (tag, base);
+  gimple call;
+  tree val;
+  
+  ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
+                                     true, NULL_TREE, true, GSI_SAME_STMT);
+  val = prepare_instrumented_value (&gsi, value);
+  call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val);
+  gsi_insert_before (&gsi, call, GSI_NEW_STMT);
+  add_abnormal_goto_call_edges (gsi);
+}
+
 /* Return 1 if tree-based profiling is in effect, else 0.
    If it is, set up hooks for tree-based profiling.
    Gate for pass_tree_profile.  */
@@ -576,26 +438,35 @@ tree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED,
 static bool
 do_tree_profiling (void)
 {
-  if (flag_tree_based_profiling
-      && (profile_arc_flag || flag_test_coverage || flag_branch_probabilities))
+  if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
     {
       tree_register_profile_hooks ();
-      tree_register_value_prof_hooks ();
+      gimple_register_value_prof_hooks ();
       return true;
     }
   return false;
 }
 
-/* Return the file on which profile dump output goes, if any.  */
-
-static FILE *tree_profile_dump_file (void) {
-  return dump_file;
-}
-
-static void
+static unsigned int
 tree_profiling (void)
 {
+  /* Don't profile functions produced at destruction time, particularly
+     the gcov datastructure initializer.  Don't profile if it has been
+     already instrumented either (when OpenMP expansion creates
+     child function from already instrumented body).  */
+  if (cgraph_state == CGRAPH_STATE_FINISHED
+      || cfun->after_tree_profile)
+    return 0;
+
+  /* Re-set global shared temporary variable for edge-counters.  */
+  gcov_type_tmp_var = NULL_TREE;
+
   branch_prob ();
+
+  if (! flag_branch_probabilities 
+      && flag_profile_values)
+    tree_gen_ic_func_profiler ();
+
   if (flag_branch_probabilities
       && flag_profile_values
       && flag_value_profile_transformations)
@@ -605,10 +476,14 @@ tree_profiling (void)
      easy to adjust it, if and when there is some.  */
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
+  cfun->after_tree_profile = 1;
+  return 0;
 }
 
-struct tree_opt_pass pass_tree_profile = 
+struct gimple_opt_pass pass_tree_profile = 
 {
+ {
+  GIMPLE_PASS,
   "tree_profile",                      /* name */
   do_tree_profiling,                   /* gate */
   tree_profiling,                      /* execute */
@@ -617,20 +492,24 @@ struct tree_opt_pass pass_tree_profile =
   0,                                   /* static_pass_number */
   TV_BRANCH_PROB,                      /* tv_id */
   PROP_gimple_leh | PROP_cfg,          /* properties_required */
-  PROP_gimple_leh | PROP_cfg,          /* properties_provided */
+  0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_verify_stmts,                   /* todo_flags_finish */
-  0                                    /* letter */
+  TODO_verify_stmts | TODO_dump_func   /* todo_flags_finish */
+ }
 };
 
 struct profile_hooks tree_profile_hooks =
 {
-  tree_init_edge_profiler,      /* init_edge_profiler */
-  tree_gen_edge_profiler,      /* gen_edge_profiler */
-  tree_gen_interval_profiler,   /* gen_interval_profiler */
-  tree_gen_pow2_profiler,       /* gen_pow2_profiler */
-  tree_gen_one_value_profiler,  /* gen_one_value_profiler */
-  tree_gen_const_delta_profiler,/* gen_const_delta_profiler */
-  tree_profile_dump_file       /* profile_dump_file */
+  tree_init_edge_profiler,       /* init_edge_profiler */
+  tree_gen_edge_profiler,       /* gen_edge_profiler */
+  tree_gen_interval_profiler,    /* gen_interval_profiler */
+  tree_gen_pow2_profiler,        /* gen_pow2_profiler */
+  tree_gen_one_value_profiler,   /* gen_one_value_profiler */
+  tree_gen_const_delta_profiler, /* gen_const_delta_profiler */
+  tree_gen_ic_profiler,                 /* gen_ic_profiler */
+  tree_gen_average_profiler,     /* gen_average_profiler */
+  tree_gen_ior_profiler          /* gen_ior_profiler */
 };
+
+#include "gt-tree-profile.h"