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