OSDN Git Service

2007-02-13 Seongbae Park <seongbae.park@gmail.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-profile.c
index 329ebcd..bd7556a 100644 (file)
@@ -45,15 +45,56 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "timevar.h"
 #include "value-prof.h"
 #include "ggc.h"
+#include "cgraph.h"
 
 static GTY(()) tree gcov_type_node;
 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 addres
+*/
+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)
 {
@@ -61,6 +102,8 @@ tree_init_edge_profiler (void)
   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)
     {
@@ -93,6 +136,28 @@ tree_init_edge_profiler (void)
       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);
     }
 }
 
@@ -201,6 +266,90 @@ tree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
   bsi_insert_before (&bsi, call, BSI_SAME_STMT);
 }
 
+
+/* 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, stmt1, stmt2, stmt3;
+  tree stmt = value->hvalue.stmt;
+  block_stmt_iterator bsi = bsi_for_stmt (stmt);
+  tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
+
+  ref_ptr = force_gimple_operand_bsi (&bsi,
+                                     build_addr (ref, current_function_decl),
+                                     true, NULL_TREE);
+
+  /* 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 = build2 (GIMPLE_MODIFY_STMT, 
+                 build_pointer_type (get_gcov_type ()), 
+                 ic_gcov_type_ptr_var, ref_ptr);
+  stmt2 = build2 (GIMPLE_MODIFY_STMT, ptr_void, tmp1, 
+                 unshare_expr (value->hvalue.value));
+  stmt3 = build2 (GIMPLE_MODIFY_STMT, ptr_void, 
+                 ic_void_ptr_var, tmp1);
+
+  bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
+  bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
+  bsi_insert_before (&bsi, stmt3, BSI_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);
+  block_stmt_iterator bsi;
+  edge e;
+  basic_block bb;
+  edge_iterator ei;
+  tree stmt1;
+  tree args, tree_uid, cur_func;
+
+  if (flag_unit_at_a_time)
+    {
+      if (!c_node->needed)
+       return;
+    }
+  
+  tree_init_edge_profiler ();
+  
+  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
+    {
+      bb = split_edge (e);
+      bsi = bsi_start (bb);
+      cur_func = force_gimple_operand_bsi (&bsi,
+                                          build_addr (current_function_decl, 
+                                                      current_function_decl),
+                                          true, NULL_TREE);
+      tree_uid = build_int_cst (gcov_type_node, c_node->pid);
+      args = tree_cons (NULL_TREE, ic_gcov_type_ptr_var,
+                       tree_cons (NULL_TREE, tree_uid,
+                                  tree_cons (NULL_TREE, cur_func,
+                                             tree_cons (NULL_TREE, 
+                                                        ic_void_ptr_var,
+                                                        NULL_TREE))));
+      stmt1 = build_function_call_expr (tree_indirect_call_profiler_fn, args);
+      bsi_insert_after (&bsi, stmt1, BSI_SAME_STMT);
+    }
+}
+
 /* Output instructions as GIMPLE trees for code to find the most common value 
    of a difference between two evaluations of an expression.
    VALUE is the expression whose value is profiled.  TAG is the tag of the
@@ -218,6 +367,48 @@ 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)
+{
+  tree stmt = value->hvalue.stmt;
+  block_stmt_iterator bsi = bsi_for_stmt (stmt);
+  tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
+  tree args, call, val;
+  
+  ref_ptr = force_gimple_operand_bsi (&bsi,
+                                     build_addr (ref, current_function_decl),
+                                     true, NULL_TREE);
+  val = prepare_instrumented_value (&bsi, value);
+  args = tree_cons (NULL_TREE, ref_ptr, tree_cons (NULL_TREE, val, NULL_TREE));
+  call = build_function_call_expr (tree_average_profiler_fn, args);
+  bsi_insert_before (&bsi, call, BSI_SAME_STMT);
+}
+
+/* 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)
+{
+  tree stmt = value->hvalue.stmt;
+  block_stmt_iterator bsi = bsi_for_stmt (stmt);
+  tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
+  tree args, call, val;
+  
+  ref_ptr = force_gimple_operand_bsi (&bsi,
+                                     build_addr (ref, current_function_decl),
+                                     true, NULL_TREE);
+  val = prepare_instrumented_value (&bsi, value);
+  args = tree_cons (NULL_TREE, ref_ptr, tree_cons (NULL_TREE, val, NULL_TREE));
+  call = build_function_call_expr (tree_ior_profiler_fn, args);
+  bsi_insert_before (&bsi, call, BSI_SAME_STMT);
+}
+
 /* 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.  */
@@ -237,7 +428,16 @@ do_tree_profiling (void)
 static unsigned int
 tree_profiling (void)
 {
+  /* Don't profile functions produced at destruction time, particularly
+     the gcov datastructure initializer.  */
+  if (cgraph_state == CGRAPH_STATE_FINISHED)
+    return 0;
   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)
@@ -263,45 +463,21 @@ struct tree_opt_pass pass_tree_profile =
   PROP_gimple_leh | PROP_cfg,          /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_verify_stmts,                   /* todo_flags_finish */
-  0                                    /* letter */
-};
-
-/* 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.  */
-
-static bool
-do_early_tree_profiling (void)
-{
-  return (do_tree_profiling () && (!flag_unit_at_a_time || !optimize));
-}
-
-struct tree_opt_pass pass_early_tree_profile = 
-{
-  "early_tree_profile",                        /* name */
-  do_early_tree_profiling,             /* gate */
-  tree_profiling,                      /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  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_destroyed */
-  0,                                   /* todo_flags_start */
-  TODO_verify_stmts,                   /* todo_flags_finish */
+  TODO_verify_stmts | TODO_dump_func,  /* todo_flags_finish */
   0                                    /* letter */
 };
 
 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_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"