1169689Skan/* Calculate branch probabilities, and basic block execution counts. 2169689Skan Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 3169689Skan 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 4169689Skan Contributed by James E. Wilson, UC Berkeley/Cygnus Support; 5169689Skan based on some ideas from Dain Samples of UC Berkeley. 6169689Skan Further mangling by Bob Manson, Cygnus Support. 7169689Skan Converted to use trees by Dale Johannesen, Apple Computer. 8169689Skan 9169689SkanThis file is part of GCC. 10169689Skan 11169689SkanGCC is free software; you can redistribute it and/or modify it under 12169689Skanthe terms of the GNU General Public License as published by the Free 13169689SkanSoftware Foundation; either version 2, or (at your option) any later 14169689Skanversion. 15169689Skan 16169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 17169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 18169689SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19169689Skanfor more details. 20169689Skan 21169689SkanYou should have received a copy of the GNU General Public License 22169689Skanalong with GCC; see the file COPYING. If not, write to the Free 23169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 24169689Skan02110-1301, USA. */ 25169689Skan 26169689Skan/* Generate basic block profile instrumentation and auxiliary files. 27169689Skan Tree-based version. See profile.c for overview. */ 28169689Skan 29169689Skan#include "config.h" 30169689Skan#include "system.h" 31169689Skan#include "coretypes.h" 32169689Skan#include "tm.h" 33169689Skan#include "rtl.h" 34169689Skan#include "flags.h" 35169689Skan#include "output.h" 36169689Skan#include "regs.h" 37169689Skan#include "expr.h" 38169689Skan#include "function.h" 39169689Skan#include "toplev.h" 40169689Skan#include "coverage.h" 41169689Skan#include "tree.h" 42169689Skan#include "tree-flow.h" 43169689Skan#include "tree-dump.h" 44169689Skan#include "tree-pass.h" 45169689Skan#include "timevar.h" 46169689Skan#include "value-prof.h" 47169689Skan#include "ggc.h" 48169689Skan 49169689Skanstatic GTY(()) tree gcov_type_node; 50169689Skanstatic GTY(()) tree tree_interval_profiler_fn; 51169689Skanstatic GTY(()) tree tree_pow2_profiler_fn; 52169689Skanstatic GTY(()) tree tree_one_value_profiler_fn; 53169689Skan 54169689Skan 55169689Skan/* Do initialization work for the edge profiler. */ 56169689Skan 57169689Skanstatic void 58169689Skantree_init_edge_profiler (void) 59169689Skan{ 60169689Skan tree interval_profiler_fn_type; 61169689Skan tree pow2_profiler_fn_type; 62169689Skan tree one_value_profiler_fn_type; 63169689Skan tree gcov_type_ptr; 64169689Skan 65169689Skan if (!gcov_type_node) 66169689Skan { 67169689Skan gcov_type_node = get_gcov_type (); 68169689Skan gcov_type_ptr = build_pointer_type (gcov_type_node); 69169689Skan 70169689Skan /* void (*) (gcov_type *, gcov_type, int, unsigned) */ 71169689Skan interval_profiler_fn_type 72169689Skan = build_function_type_list (void_type_node, 73169689Skan gcov_type_ptr, gcov_type_node, 74169689Skan integer_type_node, 75169689Skan unsigned_type_node, NULL_TREE); 76169689Skan tree_interval_profiler_fn 77169689Skan = build_fn_decl ("__gcov_interval_profiler", 78169689Skan interval_profiler_fn_type); 79169689Skan 80169689Skan /* void (*) (gcov_type *, gcov_type) */ 81169689Skan pow2_profiler_fn_type 82169689Skan = build_function_type_list (void_type_node, 83169689Skan gcov_type_ptr, gcov_type_node, 84169689Skan NULL_TREE); 85169689Skan tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler", 86169689Skan pow2_profiler_fn_type); 87169689Skan 88169689Skan /* void (*) (gcov_type *, gcov_type) */ 89169689Skan one_value_profiler_fn_type 90169689Skan = build_function_type_list (void_type_node, 91169689Skan gcov_type_ptr, gcov_type_node, 92169689Skan NULL_TREE); 93169689Skan tree_one_value_profiler_fn 94169689Skan = build_fn_decl ("__gcov_one_value_profiler", 95169689Skan one_value_profiler_fn_type); 96169689Skan } 97169689Skan} 98169689Skan 99169689Skan/* Output instructions as GIMPLE trees to increment the edge 100169689Skan execution count, and insert them on E. We rely on 101169689Skan bsi_insert_on_edge to preserve the order. */ 102169689Skan 103169689Skanstatic void 104169689Skantree_gen_edge_profiler (int edgeno, edge e) 105169689Skan{ 106169689Skan tree tmp1 = create_tmp_var (gcov_type_node, "PROF"); 107169689Skan tree tmp2 = create_tmp_var (gcov_type_node, "PROF"); 108169689Skan tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); 109169689Skan tree stmt1 = build2 (MODIFY_EXPR, gcov_type_node, tmp1, ref); 110169689Skan tree stmt2 = build2 (MODIFY_EXPR, gcov_type_node, tmp2, 111169689Skan build2 (PLUS_EXPR, gcov_type_node, 112169689Skan tmp1, integer_one_node)); 113169689Skan tree stmt3 = build2 (MODIFY_EXPR, gcov_type_node, ref, tmp2); 114169689Skan bsi_insert_on_edge (e, stmt1); 115169689Skan bsi_insert_on_edge (e, stmt2); 116169689Skan bsi_insert_on_edge (e, stmt3); 117169689Skan} 118169689Skan 119169689Skan/* Emits code to get VALUE to instrument at BSI, and returns the 120169689Skan variable containing the value. */ 121169689Skan 122169689Skanstatic tree 123169689Skanprepare_instrumented_value (block_stmt_iterator *bsi, 124169689Skan histogram_value value) 125169689Skan{ 126169689Skan tree val = value->hvalue.value; 127169689Skan return force_gimple_operand_bsi (bsi, fold_convert (gcov_type_node, val), 128169689Skan true, NULL_TREE); 129169689Skan} 130169689Skan 131169689Skan/* Output instructions as GIMPLE trees to increment the interval histogram 132169689Skan counter. VALUE is the expression whose value is profiled. TAG is the 133169689Skan tag of the section for counters, BASE is offset of the counter position. */ 134169689Skan 135169689Skanstatic void 136169689Skantree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) 137169689Skan{ 138169689Skan tree stmt = value->hvalue.stmt; 139169689Skan block_stmt_iterator bsi = bsi_for_stmt (stmt); 140169689Skan tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; 141169689Skan tree args, call, val; 142169689Skan tree start = build_int_cst_type (integer_type_node, value->hdata.intvl.int_start); 143169689Skan tree steps = build_int_cst_type (unsigned_type_node, value->hdata.intvl.steps); 144169689Skan 145169689Skan ref_ptr = force_gimple_operand_bsi (&bsi, 146169689Skan build_addr (ref, current_function_decl), 147169689Skan true, NULL_TREE); 148169689Skan val = prepare_instrumented_value (&bsi, value); 149169689Skan args = tree_cons (NULL_TREE, ref_ptr, 150169689Skan tree_cons (NULL_TREE, val, 151169689Skan tree_cons (NULL_TREE, start, 152169689Skan tree_cons (NULL_TREE, steps, 153169689Skan NULL_TREE)))); 154169689Skan call = build_function_call_expr (tree_interval_profiler_fn, args); 155169689Skan bsi_insert_before (&bsi, call, BSI_SAME_STMT); 156169689Skan} 157169689Skan 158169689Skan/* Output instructions as GIMPLE trees to increment the power of two histogram 159169689Skan counter. VALUE is the expression whose value is profiled. TAG is the tag 160169689Skan of the section for counters, BASE is offset of the counter position. */ 161169689Skan 162169689Skanstatic void 163169689Skantree_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base) 164169689Skan{ 165169689Skan tree stmt = value->hvalue.stmt; 166169689Skan block_stmt_iterator bsi = bsi_for_stmt (stmt); 167169689Skan tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; 168169689Skan tree args, call, val; 169169689Skan 170169689Skan ref_ptr = force_gimple_operand_bsi (&bsi, 171169689Skan build_addr (ref, current_function_decl), 172169689Skan true, NULL_TREE); 173169689Skan val = prepare_instrumented_value (&bsi, value); 174169689Skan args = tree_cons (NULL_TREE, ref_ptr, 175169689Skan tree_cons (NULL_TREE, val, 176169689Skan NULL_TREE)); 177169689Skan call = build_function_call_expr (tree_pow2_profiler_fn, args); 178169689Skan bsi_insert_before (&bsi, call, BSI_SAME_STMT); 179169689Skan} 180169689Skan 181169689Skan/* Output instructions as GIMPLE trees for code to find the most common value. 182169689Skan VALUE is the expression whose value is profiled. TAG is the tag of the 183169689Skan section for counters, BASE is offset of the counter position. */ 184169689Skan 185169689Skanstatic void 186169689Skantree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base) 187169689Skan{ 188169689Skan tree stmt = value->hvalue.stmt; 189169689Skan block_stmt_iterator bsi = bsi_for_stmt (stmt); 190169689Skan tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; 191169689Skan tree args, call, val; 192169689Skan 193169689Skan ref_ptr = force_gimple_operand_bsi (&bsi, 194169689Skan build_addr (ref, current_function_decl), 195169689Skan true, NULL_TREE); 196169689Skan val = prepare_instrumented_value (&bsi, value); 197169689Skan args = tree_cons (NULL_TREE, ref_ptr, 198169689Skan tree_cons (NULL_TREE, val, 199169689Skan NULL_TREE)); 200169689Skan call = build_function_call_expr (tree_one_value_profiler_fn, args); 201169689Skan bsi_insert_before (&bsi, call, BSI_SAME_STMT); 202169689Skan} 203169689Skan 204169689Skan/* Output instructions as GIMPLE trees for code to find the most common value 205169689Skan of a difference between two evaluations of an expression. 206169689Skan VALUE is the expression whose value is profiled. TAG is the tag of the 207169689Skan section for counters, BASE is offset of the counter position. */ 208169689Skan 209169689Skanstatic void 210169689Skantree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED, 211169689Skan unsigned tag ATTRIBUTE_UNUSED, 212169689Skan unsigned base ATTRIBUTE_UNUSED) 213169689Skan{ 214169689Skan /* FIXME implement this. */ 215169689Skan#ifdef ENABLE_CHECKING 216169689Skan internal_error ("unimplemented functionality"); 217169689Skan#endif 218169689Skan gcc_unreachable (); 219169689Skan} 220169689Skan 221169689Skan/* Return 1 if tree-based profiling is in effect, else 0. 222169689Skan If it is, set up hooks for tree-based profiling. 223169689Skan Gate for pass_tree_profile. */ 224169689Skan 225169689Skanstatic bool 226169689Skando_tree_profiling (void) 227169689Skan{ 228169689Skan if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities) 229169689Skan { 230169689Skan tree_register_profile_hooks (); 231169689Skan tree_register_value_prof_hooks (); 232169689Skan return true; 233169689Skan } 234169689Skan return false; 235169689Skan} 236169689Skan 237169689Skanstatic unsigned int 238169689Skantree_profiling (void) 239169689Skan{ 240169689Skan branch_prob (); 241169689Skan if (flag_branch_probabilities 242169689Skan && flag_profile_values 243169689Skan && flag_value_profile_transformations) 244169689Skan value_profile_transformations (); 245169689Skan /* The above could hose dominator info. Currently there is 246169689Skan none coming in, this is a safety valve. It should be 247169689Skan easy to adjust it, if and when there is some. */ 248169689Skan free_dominance_info (CDI_DOMINATORS); 249169689Skan free_dominance_info (CDI_POST_DOMINATORS); 250169689Skan return 0; 251169689Skan} 252169689Skan 253169689Skanstruct tree_opt_pass pass_tree_profile = 254169689Skan{ 255169689Skan "tree_profile", /* name */ 256169689Skan do_tree_profiling, /* gate */ 257169689Skan tree_profiling, /* execute */ 258169689Skan NULL, /* sub */ 259169689Skan NULL, /* next */ 260169689Skan 0, /* static_pass_number */ 261169689Skan TV_BRANCH_PROB, /* tv_id */ 262169689Skan PROP_gimple_leh | PROP_cfg, /* properties_required */ 263169689Skan PROP_gimple_leh | PROP_cfg, /* properties_provided */ 264169689Skan 0, /* properties_destroyed */ 265169689Skan 0, /* todo_flags_start */ 266169689Skan TODO_verify_stmts, /* todo_flags_finish */ 267169689Skan 0 /* letter */ 268169689Skan}; 269169689Skan 270169689Skan/* Return 1 if tree-based profiling is in effect, else 0. 271169689Skan If it is, set up hooks for tree-based profiling. 272169689Skan Gate for pass_tree_profile. */ 273169689Skan 274169689Skanstatic bool 275169689Skando_early_tree_profiling (void) 276169689Skan{ 277169689Skan return (do_tree_profiling () && (!flag_unit_at_a_time || !optimize)); 278169689Skan} 279169689Skan 280169689Skanstruct tree_opt_pass pass_early_tree_profile = 281169689Skan{ 282169689Skan "early_tree_profile", /* name */ 283169689Skan do_early_tree_profiling, /* gate */ 284169689Skan tree_profiling, /* execute */ 285169689Skan NULL, /* sub */ 286169689Skan NULL, /* next */ 287169689Skan 0, /* static_pass_number */ 288169689Skan TV_BRANCH_PROB, /* tv_id */ 289169689Skan PROP_gimple_leh | PROP_cfg, /* properties_required */ 290169689Skan PROP_gimple_leh | PROP_cfg, /* properties_provided */ 291169689Skan 0, /* properties_destroyed */ 292169689Skan 0, /* todo_flags_start */ 293169689Skan TODO_verify_stmts, /* todo_flags_finish */ 294169689Skan 0 /* letter */ 295169689Skan}; 296169689Skan 297169689Skanstruct profile_hooks tree_profile_hooks = 298169689Skan{ 299169689Skan tree_init_edge_profiler, /* init_edge_profiler */ 300169689Skan tree_gen_edge_profiler, /* gen_edge_profiler */ 301169689Skan tree_gen_interval_profiler, /* gen_interval_profiler */ 302169689Skan tree_gen_pow2_profiler, /* gen_pow2_profiler */ 303169689Skan tree_gen_one_value_profiler, /* gen_one_value_profiler */ 304169689Skan tree_gen_const_delta_profiler /* gen_const_delta_profiler */ 305169689Skan}; 306169689Skan 307169689Skan#include "gt-tree-profile.h" 308