OSDN Git Service

2006-12-06 Tobias Burnus <burnus@net-b.de>
[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
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 \f
54
55 /* Do initialization work for the edge profiler.  */
56
57 static 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
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 (GIMPLE_MODIFY_STMT, gcov_type_node, tmp1, ref);
110   tree stmt2 = build2 (GIMPLE_MODIFY_STMT, gcov_type_node, tmp2,
111                        build2 (PLUS_EXPR, gcov_type_node, 
112                               tmp1, integer_one_node));
113   tree stmt3 = build2 (GIMPLE_MODIFY_STMT, 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
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
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
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
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
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
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
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
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"