1/* Calculate branch probabilities, and basic block execution counts.
2   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
3   2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
4   Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
5   based on some ideas from Dain Samples of UC Berkeley.
6   Further mangling by Bob Manson, Cygnus Support.
7   Converted to use trees by Dale Johannesen, Apple Computer.
8
9This file is part of GCC.
10
11GCC is free software; you can redistribute it and/or modify it under
12the terms of the GNU General Public License as published by the Free
13Software Foundation; either version 2, or (at your option) any later
14version.
15
16GCC is distributed in the hope that it will be useful, but WITHOUT ANY
17WARRANTY; without even the implied warranty of MERCHANTABILITY or
18FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19for more details.
20
21You should have received a copy of the GNU General Public License
22along with GCC; see the file COPYING.  If not, write to the Free
23Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2402110-1301, USA.  */
25
26/* Generate basic block profile instrumentation and auxiliary files.
27   Tree-based version.  See profile.c for overview.  */
28
29#include "config.h"
30#include "system.h"
31#include "coretypes.h"
32#include "tm.h"
33#include "rtl.h"
34#include "flags.h"
35#include "output.h"
36#include "regs.h"
37#include "expr.h"
38#include "function.h"
39#include "toplev.h"
40#include "coverage.h"
41#include "tree.h"
42#include "tree-flow.h"
43#include "tree-dump.h"
44#include "tree-pass.h"
45#include "timevar.h"
46#include "value-prof.h"
47#include "ggc.h"
48
49static GTY(()) tree gcov_type_node;
50static GTY(()) tree tree_interval_profiler_fn;
51static GTY(()) tree tree_pow2_profiler_fn;
52static GTY(()) tree tree_one_value_profiler_fn;
53
54
55/* Do initialization work for the edge profiler.  */
56
57static void
58tree_init_edge_profiler (void)
59{
60  tree interval_profiler_fn_type;
61  tree pow2_profiler_fn_type;
62  tree one_value_profiler_fn_type;
63  tree gcov_type_ptr;
64
65  if (!gcov_type_node)
66    {
67      gcov_type_node = get_gcov_type ();
68      gcov_type_ptr = build_pointer_type (gcov_type_node);
69
70      /* void (*) (gcov_type *, gcov_type, int, unsigned)  */
71      interval_profiler_fn_type
72	      = build_function_type_list (void_type_node,
73					  gcov_type_ptr, gcov_type_node,
74					  integer_type_node,
75					  unsigned_type_node, NULL_TREE);
76      tree_interval_profiler_fn
77	      = build_fn_decl ("__gcov_interval_profiler",
78				     interval_profiler_fn_type);
79
80      /* void (*) (gcov_type *, gcov_type)  */
81      pow2_profiler_fn_type
82	      = build_function_type_list (void_type_node,
83					  gcov_type_ptr, gcov_type_node,
84					  NULL_TREE);
85      tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler",
86						   pow2_profiler_fn_type);
87
88      /* void (*) (gcov_type *, gcov_type)  */
89      one_value_profiler_fn_type
90	      = build_function_type_list (void_type_node,
91					  gcov_type_ptr, gcov_type_node,
92					  NULL_TREE);
93      tree_one_value_profiler_fn
94	      = build_fn_decl ("__gcov_one_value_profiler",
95				     one_value_profiler_fn_type);
96    }
97}
98
99/* Output instructions as GIMPLE trees to increment the edge
100   execution count, and insert them on E.  We rely on
101   bsi_insert_on_edge to preserve the order.  */
102
103static void
104tree_gen_edge_profiler (int edgeno, edge e)
105{
106  tree tmp1 = create_tmp_var (gcov_type_node, "PROF");
107  tree tmp2 = create_tmp_var (gcov_type_node, "PROF");
108  tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
109  tree stmt1 = build2 (MODIFY_EXPR, gcov_type_node, tmp1, ref);
110  tree stmt2 = build2 (MODIFY_EXPR, gcov_type_node, tmp2,
111		       build2 (PLUS_EXPR, gcov_type_node,
112			      tmp1, integer_one_node));
113  tree stmt3 = build2 (MODIFY_EXPR, gcov_type_node, ref, tmp2);
114  bsi_insert_on_edge (e, stmt1);
115  bsi_insert_on_edge (e, stmt2);
116  bsi_insert_on_edge (e, stmt3);
117}
118
119/* Emits code to get VALUE to instrument at BSI, and returns the
120   variable containing the value.  */
121
122static tree
123prepare_instrumented_value (block_stmt_iterator *bsi,
124			    histogram_value value)
125{
126  tree val = value->hvalue.value;
127  return force_gimple_operand_bsi (bsi, fold_convert (gcov_type_node, val),
128				   true, NULL_TREE);
129}
130
131/* Output instructions as GIMPLE trees to increment the interval histogram
132   counter.  VALUE is the expression whose value is profiled.  TAG is the
133   tag of the section for counters, BASE is offset of the counter position.  */
134
135static void
136tree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
137{
138  tree stmt = value->hvalue.stmt;
139  block_stmt_iterator bsi = bsi_for_stmt (stmt);
140  tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
141  tree args, call, val;
142  tree start = build_int_cst_type (integer_type_node, value->hdata.intvl.int_start);
143  tree steps = build_int_cst_type (unsigned_type_node, value->hdata.intvl.steps);
144
145  ref_ptr = force_gimple_operand_bsi (&bsi,
146				      build_addr (ref, current_function_decl),
147				      true, NULL_TREE);
148  val = prepare_instrumented_value (&bsi, value);
149  args = tree_cons (NULL_TREE, ref_ptr,
150		    tree_cons (NULL_TREE, val,
151			       tree_cons (NULL_TREE, start,
152					  tree_cons (NULL_TREE, steps,
153						     NULL_TREE))));
154  call = build_function_call_expr (tree_interval_profiler_fn, args);
155  bsi_insert_before (&bsi, call, BSI_SAME_STMT);
156}
157
158/* Output instructions as GIMPLE trees to increment the power of two histogram
159   counter.  VALUE is the expression whose value is profiled.  TAG is the tag
160   of the section for counters, BASE is offset of the counter position.  */
161
162static void
163tree_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
164{
165  tree stmt = value->hvalue.stmt;
166  block_stmt_iterator bsi = bsi_for_stmt (stmt);
167  tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
168  tree args, call, val;
169
170  ref_ptr = force_gimple_operand_bsi (&bsi,
171				      build_addr (ref, current_function_decl),
172				      true, NULL_TREE);
173  val = prepare_instrumented_value (&bsi, value);
174  args = tree_cons (NULL_TREE, ref_ptr,
175		    tree_cons (NULL_TREE, val,
176			       NULL_TREE));
177  call = build_function_call_expr (tree_pow2_profiler_fn, args);
178  bsi_insert_before (&bsi, call, BSI_SAME_STMT);
179}
180
181/* Output instructions as GIMPLE trees for code to find the most common value.
182   VALUE is the expression whose value is profiled.  TAG is the tag of the
183   section for counters, BASE is offset of the counter position.  */
184
185static void
186tree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
187{
188  tree stmt = value->hvalue.stmt;
189  block_stmt_iterator bsi = bsi_for_stmt (stmt);
190  tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
191  tree args, call, val;
192
193  ref_ptr = force_gimple_operand_bsi (&bsi,
194				      build_addr (ref, current_function_decl),
195				      true, NULL_TREE);
196  val = prepare_instrumented_value (&bsi, value);
197  args = tree_cons (NULL_TREE, ref_ptr,
198		    tree_cons (NULL_TREE, val,
199			       NULL_TREE));
200  call = build_function_call_expr (tree_one_value_profiler_fn, args);
201  bsi_insert_before (&bsi, call, BSI_SAME_STMT);
202}
203
204/* Output instructions as GIMPLE trees for code to find the most common value
205   of a difference between two evaluations of an expression.
206   VALUE is the expression whose value is profiled.  TAG is the tag of the
207   section for counters, BASE is offset of the counter position.  */
208
209static void
210tree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED,
211				unsigned tag ATTRIBUTE_UNUSED,
212				unsigned base ATTRIBUTE_UNUSED)
213{
214  /* FIXME implement this.  */
215#ifdef ENABLE_CHECKING
216  internal_error ("unimplemented functionality");
217#endif
218  gcc_unreachable ();
219}
220
221/* Return 1 if tree-based profiling is in effect, else 0.
222   If it is, set up hooks for tree-based profiling.
223   Gate for pass_tree_profile.  */
224
225static bool
226do_tree_profiling (void)
227{
228  if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
229    {
230      tree_register_profile_hooks ();
231      tree_register_value_prof_hooks ();
232      return true;
233    }
234  return false;
235}
236
237static unsigned int
238tree_profiling (void)
239{
240  branch_prob ();
241  if (flag_branch_probabilities
242      && flag_profile_values
243      && flag_value_profile_transformations)
244    value_profile_transformations ();
245  /* The above could hose dominator info.  Currently there is
246     none coming in, this is a safety valve.  It should be
247     easy to adjust it, if and when there is some.  */
248  free_dominance_info (CDI_DOMINATORS);
249  free_dominance_info (CDI_POST_DOMINATORS);
250  return 0;
251}
252
253struct tree_opt_pass pass_tree_profile =
254{
255  "tree_profile",			/* name */
256  do_tree_profiling,			/* gate */
257  tree_profiling,			/* execute */
258  NULL,					/* sub */
259  NULL,					/* next */
260  0,					/* static_pass_number */
261  TV_BRANCH_PROB,			/* tv_id */
262  PROP_gimple_leh | PROP_cfg,		/* properties_required */
263  PROP_gimple_leh | PROP_cfg,		/* properties_provided */
264  0,					/* properties_destroyed */
265  0,					/* todo_flags_start */
266  TODO_verify_stmts,			/* todo_flags_finish */
267  0					/* letter */
268};
269
270/* Return 1 if tree-based profiling is in effect, else 0.
271   If it is, set up hooks for tree-based profiling.
272   Gate for pass_tree_profile.  */
273
274static bool
275do_early_tree_profiling (void)
276{
277  return (do_tree_profiling () && (!flag_unit_at_a_time || !optimize));
278}
279
280struct tree_opt_pass pass_early_tree_profile =
281{
282  "early_tree_profile",			/* name */
283  do_early_tree_profiling,		/* gate */
284  tree_profiling,			/* execute */
285  NULL,					/* sub */
286  NULL,					/* next */
287  0,					/* static_pass_number */
288  TV_BRANCH_PROB,			/* tv_id */
289  PROP_gimple_leh | PROP_cfg,		/* properties_required */
290  PROP_gimple_leh | PROP_cfg,		/* properties_provided */
291  0,					/* properties_destroyed */
292  0,					/* todo_flags_start */
293  TODO_verify_stmts,			/* todo_flags_finish */
294  0					/* letter */
295};
296
297struct profile_hooks tree_profile_hooks =
298{
299  tree_init_edge_profiler,      /* init_edge_profiler */
300  tree_gen_edge_profiler,	/* gen_edge_profiler */
301  tree_gen_interval_profiler,   /* gen_interval_profiler */
302  tree_gen_pow2_profiler,       /* gen_pow2_profiler */
303  tree_gen_one_value_profiler,  /* gen_one_value_profiler */
304  tree_gen_const_delta_profiler /* gen_const_delta_profiler */
305};
306
307#include "gt-tree-profile.h"
308