xref: /openbsd/gnu/gcc/gcc/tree-profile.c (revision 404b540a)
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 
9 This file is part of GCC.
10 
11 GCC is free software; you can redistribute it and/or modify it under
12 the terms of the GNU General Public License as published by the Free
13 Software Foundation; either version 2, or (at your option) any later
14 version.
15 
16 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
17 WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with GCC; see the file COPYING.  If not, write to the Free
23 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
24 02110-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 
49 static GTY(()) tree gcov_type_node;
50 static GTY(()) tree tree_interval_profiler_fn;
51 static GTY(()) tree tree_pow2_profiler_fn;
52 static GTY(()) tree tree_one_value_profiler_fn;
53 
54 
55 /* Do initialization work for the edge profiler.  */
56 
57 static void
tree_init_edge_profiler(void)58 tree_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 
103 static void
tree_gen_edge_profiler(int edgeno,edge e)104 tree_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 
122 static tree
prepare_instrumented_value(block_stmt_iterator * bsi,histogram_value value)123 prepare_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 
135 static void
tree_gen_interval_profiler(histogram_value value,unsigned tag,unsigned base)136 tree_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 
162 static void
tree_gen_pow2_profiler(histogram_value value,unsigned tag,unsigned base)163 tree_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 
185 static void
tree_gen_one_value_profiler(histogram_value value,unsigned tag,unsigned base)186 tree_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 
209 static void
tree_gen_const_delta_profiler(histogram_value value ATTRIBUTE_UNUSED,unsigned tag ATTRIBUTE_UNUSED,unsigned base ATTRIBUTE_UNUSED)210 tree_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 
225 static bool
do_tree_profiling(void)226 do_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 
237 static unsigned int
tree_profiling(void)238 tree_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 
253 struct 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 
274 static bool
do_early_tree_profiling(void)275 do_early_tree_profiling (void)
276 {
277   return (do_tree_profiling () && (!flag_unit_at_a_time || !optimize));
278 }
279 
280 struct 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 
297 struct 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