OSDN Git Service

Patch by Tomas Bily <tbily@suse.cz>
[pf3gnuchains/gcc-fork.git] / gcc / tree-profile.c
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 #include "cgraph.h"
49
50 static GTY(()) tree gcov_type_node;
51 static GTY(()) tree tree_interval_profiler_fn;
52 static GTY(()) tree tree_pow2_profiler_fn;
53 static GTY(()) tree tree_one_value_profiler_fn;
54 static GTY(()) tree tree_indirect_call_profiler_fn;
55 \f
56
57 static GTY(()) tree ic_void_ptr_var;
58 static GTY(()) tree ic_gcov_type_ptr_var;
59 static GTY(()) tree ptr_void;
60
61 /* Do initialization work for the edge profiler.  */
62
63 /* Add code:
64    static gcov* __gcov_indirect_call_counters; // pointer to actual counter
65    static void* __gcov_indirect_call_callee; // actual callie addres
66 */
67 static void
68 tree_init_ic_make_global_vars (void)
69 {
70   tree  gcov_type_ptr;
71
72   ptr_void = build_pointer_type (void_type_node);
73   
74   ic_void_ptr_var 
75     = build_decl (VAR_DECL, 
76                   get_identifier ("__gcov_indirect_call_callee"), 
77                   ptr_void);
78   TREE_STATIC (ic_void_ptr_var) = 1;
79   TREE_PUBLIC (ic_void_ptr_var) = 0;
80   DECL_ARTIFICIAL (ic_void_ptr_var) = 1;
81   DECL_INITIAL (ic_void_ptr_var) = NULL;
82   assemble_variable (ic_void_ptr_var, 0, 0, 0);
83
84   gcov_type_ptr = build_pointer_type (get_gcov_type ());
85   ic_gcov_type_ptr_var 
86     = build_decl (VAR_DECL, 
87                   get_identifier ("__gcov_indirect_call_counters"), 
88                   gcov_type_ptr);
89   TREE_STATIC (ic_gcov_type_ptr_var) = 1;
90   TREE_PUBLIC (ic_gcov_type_ptr_var) = 0;
91   DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1;
92   DECL_INITIAL (ic_gcov_type_ptr_var) = NULL;
93   assemble_variable (ic_gcov_type_ptr_var, 0, 0, 0);
94 }
95
96 static void
97 tree_init_edge_profiler (void)
98 {
99   tree interval_profiler_fn_type;
100   tree pow2_profiler_fn_type;
101   tree one_value_profiler_fn_type;
102   tree gcov_type_ptr;
103   tree ic_profiler_fn_type;
104
105   if (!gcov_type_node)
106     {
107       gcov_type_node = get_gcov_type ();
108       gcov_type_ptr = build_pointer_type (gcov_type_node);
109
110       /* void (*) (gcov_type *, gcov_type, int, unsigned)  */
111       interval_profiler_fn_type
112               = build_function_type_list (void_type_node,
113                                           gcov_type_ptr, gcov_type_node,
114                                           integer_type_node,
115                                           unsigned_type_node, NULL_TREE);
116       tree_interval_profiler_fn
117               = build_fn_decl ("__gcov_interval_profiler",
118                                      interval_profiler_fn_type);
119
120       /* void (*) (gcov_type *, gcov_type)  */
121       pow2_profiler_fn_type
122               = build_function_type_list (void_type_node,
123                                           gcov_type_ptr, gcov_type_node,
124                                           NULL_TREE);
125       tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler",
126                                                    pow2_profiler_fn_type);
127
128       /* void (*) (gcov_type *, gcov_type)  */
129       one_value_profiler_fn_type
130               = build_function_type_list (void_type_node,
131                                           gcov_type_ptr, gcov_type_node,
132                                           NULL_TREE);
133       tree_one_value_profiler_fn
134               = build_fn_decl ("__gcov_one_value_profiler",
135                                      one_value_profiler_fn_type);
136
137       tree_init_ic_make_global_vars ();
138       
139       /* void (*) (gcov_type *, gcov_type, void *, void *)  */
140       ic_profiler_fn_type
141                = build_function_type_list (void_type_node,
142                                           gcov_type_ptr, gcov_type_node,
143                                           ptr_void,
144                                           ptr_void, NULL_TREE);
145       tree_indirect_call_profiler_fn
146               = build_fn_decl ("__gcov_indirect_call_profiler",
147                                      ic_profiler_fn_type);
148     }
149 }
150
151 /* Output instructions as GIMPLE trees to increment the edge 
152    execution count, and insert them on E.  We rely on 
153    bsi_insert_on_edge to preserve the order.  */
154
155 static void
156 tree_gen_edge_profiler (int edgeno, edge e)
157 {
158   tree tmp1 = create_tmp_var (gcov_type_node, "PROF");
159   tree tmp2 = create_tmp_var (gcov_type_node, "PROF");
160   tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
161   tree stmt1 = build2 (GIMPLE_MODIFY_STMT, gcov_type_node, tmp1, ref);
162   tree stmt2 = build2 (GIMPLE_MODIFY_STMT, gcov_type_node, tmp2,
163                        build2 (PLUS_EXPR, gcov_type_node, 
164                               tmp1, integer_one_node));
165   tree stmt3 = build2 (GIMPLE_MODIFY_STMT, gcov_type_node, ref, tmp2);
166   bsi_insert_on_edge (e, stmt1);
167   bsi_insert_on_edge (e, stmt2);
168   bsi_insert_on_edge (e, stmt3);
169 }
170
171 /* Emits code to get VALUE to instrument at BSI, and returns the
172    variable containing the value.  */
173
174 static tree
175 prepare_instrumented_value (block_stmt_iterator *bsi,
176                             histogram_value value)
177 {
178   tree val = value->hvalue.value;
179   return force_gimple_operand_bsi (bsi, fold_convert (gcov_type_node, val),
180                                    true, NULL_TREE);
181 }
182
183 /* Output instructions as GIMPLE trees to increment the interval histogram 
184    counter.  VALUE is the expression whose value is profiled.  TAG is the 
185    tag of the section for counters, BASE is offset of the counter position.  */
186
187 static void
188 tree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
189 {
190   tree stmt = value->hvalue.stmt;
191   block_stmt_iterator bsi = bsi_for_stmt (stmt);
192   tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
193   tree args, call, val;
194   tree start = build_int_cst_type (integer_type_node, value->hdata.intvl.int_start);
195   tree steps = build_int_cst_type (unsigned_type_node, value->hdata.intvl.steps);
196   
197   ref_ptr = force_gimple_operand_bsi (&bsi,
198                                       build_addr (ref, current_function_decl),
199                                       true, NULL_TREE);
200   val = prepare_instrumented_value (&bsi, value);
201   args = tree_cons (NULL_TREE, ref_ptr,
202                     tree_cons (NULL_TREE, val,
203                                tree_cons (NULL_TREE, start,
204                                           tree_cons (NULL_TREE, steps,
205                                                      NULL_TREE))));
206   call = build_function_call_expr (tree_interval_profiler_fn, args);
207   bsi_insert_before (&bsi, call, BSI_SAME_STMT);
208 }
209
210 /* Output instructions as GIMPLE trees to increment the power of two histogram 
211    counter.  VALUE is the expression whose value is profiled.  TAG is the tag 
212    of the section for counters, BASE is offset of the counter position.  */
213
214 static void
215 tree_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
216 {
217   tree stmt = value->hvalue.stmt;
218   block_stmt_iterator bsi = bsi_for_stmt (stmt);
219   tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
220   tree args, call, val;
221   
222   ref_ptr = force_gimple_operand_bsi (&bsi,
223                                       build_addr (ref, current_function_decl),
224                                       true, NULL_TREE);
225   val = prepare_instrumented_value (&bsi, value);
226   args = tree_cons (NULL_TREE, ref_ptr,
227                     tree_cons (NULL_TREE, val,
228                                NULL_TREE));
229   call = build_function_call_expr (tree_pow2_profiler_fn, args);
230   bsi_insert_before (&bsi, call, BSI_SAME_STMT);
231 }
232
233 /* Output instructions as GIMPLE trees for code to find the most common value.
234    VALUE is the expression whose value is profiled.  TAG is the tag of the
235    section for counters, BASE is offset of the counter position.  */
236
237 static void
238 tree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
239 {
240   tree stmt = value->hvalue.stmt;
241   block_stmt_iterator bsi = bsi_for_stmt (stmt);
242   tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
243   tree args, call, val;
244   
245   ref_ptr = force_gimple_operand_bsi (&bsi,
246                                       build_addr (ref, current_function_decl),
247                                       true, NULL_TREE);
248   val = prepare_instrumented_value (&bsi, value);
249   args = tree_cons (NULL_TREE, ref_ptr,
250                     tree_cons (NULL_TREE, val,
251                                NULL_TREE));
252   call = build_function_call_expr (tree_one_value_profiler_fn, args);
253   bsi_insert_before (&bsi, call, BSI_SAME_STMT);
254 }
255
256
257 /* Output instructions as GIMPLE trees for code to find the most
258    common called function in indirect call.  
259    VALUE is the call expression whose indirect callie is profiled.
260    TAG is the tag of the section for counters, BASE is offset of the
261    counter position.  */
262
263 static void
264 tree_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base)
265 {
266   tree tmp1, stmt1, stmt2, stmt3;
267   tree stmt = value->hvalue.stmt;
268   block_stmt_iterator bsi = bsi_for_stmt (stmt);
269   tree ref = tree_coverage_counter_ref (tag, base), ref_ptr;
270
271   ref_ptr = force_gimple_operand_bsi (&bsi,
272                                       build_addr (ref, current_function_decl),
273                                       true, NULL_TREE);
274
275   /* Insert code:
276     
277     __gcov_indirect_call_counters = get_relevant_counter_ptr (); 
278     __gcov_indirect_call_callee = (void *) indirect call argument;
279    */
280
281   tmp1 = create_tmp_var (ptr_void, "PROF");
282   stmt1 = build2 (GIMPLE_MODIFY_STMT, 
283                   build_pointer_type (get_gcov_type ()), 
284                   ic_gcov_type_ptr_var, ref_ptr);
285   stmt2 = build2 (GIMPLE_MODIFY_STMT, ptr_void, tmp1, 
286                   unshare_expr (value->hvalue.value));
287   stmt3 = build2 (GIMPLE_MODIFY_STMT, ptr_void, 
288                   ic_void_ptr_var, tmp1);
289
290   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
291   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
292   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
293 }
294
295
296 /* Output instructions as GIMPLE trees for code to find the most
297    common called function in indirect call. Insert instructions at the
298    begining of every possible called function.
299   */
300
301 static void
302 tree_gen_ic_func_profiler (void)
303 {
304   struct cgraph_node * c_node = cgraph_node (current_function_decl);
305   block_stmt_iterator bsi;
306   edge e;
307   basic_block bb;
308   edge_iterator ei;
309   tree stmt1;
310   tree args, tree_uid, cur_func;
311
312   if (flag_unit_at_a_time)
313     {
314       if (!c_node->needed)
315         return;
316     }
317   
318   tree_init_edge_profiler ();
319   
320   FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
321     {
322       bb = split_edge (e);
323       bsi = bsi_start (bb);
324       cur_func = force_gimple_operand_bsi (&bsi,
325                                            build_addr (current_function_decl, 
326                                                        current_function_decl),
327                                            true, NULL_TREE);
328       tree_uid = build_int_cst (gcov_type_node, c_node->pid);
329       args = tree_cons (NULL_TREE, ic_gcov_type_ptr_var,
330                         tree_cons (NULL_TREE, tree_uid,
331                                    tree_cons (NULL_TREE, cur_func,
332                                               tree_cons (NULL_TREE, 
333                                                          ic_void_ptr_var,
334                                                          NULL_TREE))));
335       stmt1 = build_function_call_expr (tree_indirect_call_profiler_fn, args);
336       bsi_insert_after (&bsi, stmt1, BSI_SAME_STMT);
337     }
338 }
339
340 /* Output instructions as GIMPLE trees for code to find the most common value 
341    of a difference between two evaluations of an expression.
342    VALUE is the expression whose value is profiled.  TAG is the tag of the
343    section for counters, BASE is offset of the counter position.  */
344
345 static void
346 tree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED, 
347                                 unsigned tag ATTRIBUTE_UNUSED,
348                                 unsigned base ATTRIBUTE_UNUSED)
349 {
350   /* FIXME implement this.  */
351 #ifdef ENABLE_CHECKING
352   internal_error ("unimplemented functionality");
353 #endif
354   gcc_unreachable ();
355 }
356
357 /* Return 1 if tree-based profiling is in effect, else 0.
358    If it is, set up hooks for tree-based profiling.
359    Gate for pass_tree_profile.  */
360
361 static bool
362 do_tree_profiling (void)
363 {
364   if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
365     {
366       tree_register_profile_hooks ();
367       tree_register_value_prof_hooks ();
368       return true;
369     }
370   return false;
371 }
372
373 static unsigned int
374 tree_profiling (void)
375 {
376   /* Don't profile functions produced at destruction time, particularly
377      the gcov datastructure initializer.  */
378   if (cgraph_state == CGRAPH_STATE_FINISHED)
379     return 0;
380   branch_prob ();
381
382   if (! flag_branch_probabilities 
383       && flag_profile_values)
384     tree_gen_ic_func_profiler ();
385
386   if (flag_branch_probabilities
387       && flag_profile_values
388       && flag_value_profile_transformations)
389     value_profile_transformations ();
390   /* The above could hose dominator info.  Currently there is
391      none coming in, this is a safety valve.  It should be
392      easy to adjust it, if and when there is some.  */
393   free_dominance_info (CDI_DOMINATORS);
394   free_dominance_info (CDI_POST_DOMINATORS);
395   return 0;
396 }
397
398 struct tree_opt_pass pass_tree_profile = 
399 {
400   "tree_profile",                       /* name */
401   do_tree_profiling,                    /* gate */
402   tree_profiling,                       /* execute */
403   NULL,                                 /* sub */
404   NULL,                                 /* next */
405   0,                                    /* static_pass_number */
406   TV_BRANCH_PROB,                       /* tv_id */
407   PROP_gimple_leh | PROP_cfg,           /* properties_required */
408   PROP_gimple_leh | PROP_cfg,           /* properties_provided */
409   0,                                    /* properties_destroyed */
410   0,                                    /* todo_flags_start */
411   TODO_verify_stmts,                    /* todo_flags_finish */
412   0                                     /* letter */
413 };
414
415 struct profile_hooks tree_profile_hooks =
416 {
417   tree_init_edge_profiler,      /* init_edge_profiler */
418   tree_gen_edge_profiler,       /* gen_edge_profiler */
419   tree_gen_interval_profiler,   /* gen_interval_profiler */
420   tree_gen_pow2_profiler,       /* gen_pow2_profiler */
421   tree_gen_one_value_profiler,  /* gen_one_value_profiler */
422   tree_gen_const_delta_profiler,/* gen_const_delta_profiler */
423   tree_gen_ic_profiler,         /* gen_ic_profiler */
424 };
425
426 #include "gt-tree-profile.h"