]>
Commit | Line | Data |
---|---|---|
6de9cd9a DN |
1 | /* Calculate branch probabilities, and basic block execution counts. |
2 | Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, | |
5f996627 | 3 | 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. |
6de9cd9a DN |
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 | |
366ccddb KC |
23 | Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA |
24 | 02110-1301, USA. */ | |
6de9cd9a DN |
25 | |
26 | /* Generate basic block profile instrumentation and auxiliary files. | |
1f1e8527 | 27 | Tree-based version. See profile.c for overview. */ |
6de9cd9a DN |
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" | |
9885da8e | 47 | #include "ggc.h" |
6de9cd9a | 48 | |
9885da8e ZD |
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; | |
6de9cd9a | 53 | \f |
f3df9541 AK |
54 | |
55 | /* Do initialization work for the edge profiler. */ | |
56 | ||
57 | static void | |
58 | tree_init_edge_profiler (void) | |
59 | { | |
9885da8e ZD |
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 | } | |
f3df9541 AK |
97 | } |
98 | ||
6de9cd9a DN |
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 | { | |
070e3969 RS |
106 | tree tmp1 = create_tmp_var (gcov_type_node, "PROF"); |
107 | tree tmp2 = create_tmp_var (gcov_type_node, "PROF"); | |
6de9cd9a | 108 | tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); |
b4257cfc RG |
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); | |
6de9cd9a DN |
114 | bsi_insert_on_edge (e, stmt1); |
115 | bsi_insert_on_edge (e, stmt2); | |
116 | bsi_insert_on_edge (e, stmt3); | |
117 | } | |
118 | ||
9885da8e ZD |
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 | { | |
8a76829c | 126 | tree val = value->hvalue.value; |
9885da8e ZD |
127 | return force_gimple_operand_bsi (bsi, fold_convert (gcov_type_node, val), |
128 | true, NULL_TREE); | |
129 | } | |
130 | ||
6de9cd9a DN |
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 | |
1f1e8527 | 136 | tree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) |
6de9cd9a | 137 | { |
8a76829c | 138 | tree stmt = value->hvalue.stmt; |
1f1e8527 | 139 | block_stmt_iterator bsi = bsi_for_stmt (stmt); |
9885da8e ZD |
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, | |
bde6c65d | 146 | build_addr (ref, current_function_decl), |
9885da8e ZD |
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); | |
6de9cd9a DN |
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 | |
1f1e8527 | 163 | tree_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base) |
6de9cd9a | 164 | { |
8a76829c | 165 | tree stmt = value->hvalue.stmt; |
1f1e8527 | 166 | block_stmt_iterator bsi = bsi_for_stmt (stmt); |
9885da8e ZD |
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, | |
bde6c65d | 171 | build_addr (ref, current_function_decl), |
9885da8e ZD |
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); | |
6de9cd9a DN |
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 | |
1f1e8527 | 186 | tree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base) |
6de9cd9a | 187 | { |
8a76829c | 188 | tree stmt = value->hvalue.stmt; |
1f1e8527 | 189 | block_stmt_iterator bsi = bsi_for_stmt (stmt); |
9885da8e ZD |
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, | |
bde6c65d | 194 | build_addr (ref, current_function_decl), |
9885da8e ZD |
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); | |
6de9cd9a DN |
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 | |
6d9901e7 | 210 | tree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED, |
6de9cd9a DN |
211 | unsigned tag ATTRIBUTE_UNUSED, |
212 | unsigned base ATTRIBUTE_UNUSED) | |
213 | { | |
214 | /* FIXME implement this. */ | |
1e128c5f GB |
215 | #ifdef ENABLE_CHECKING |
216 | internal_error ("unimplemented functionality"); | |
217 | #endif | |
218 | gcc_unreachable (); | |
6de9cd9a DN |
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 | ||
1f1e8527 DJ |
225 | static bool |
226 | do_tree_profiling (void) | |
878f99d2 | 227 | { |
8a76829c | 228 | if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities) |
6de9cd9a DN |
229 | { |
230 | tree_register_profile_hooks (); | |
231 | tree_register_value_prof_hooks (); | |
bbd236a1 | 232 | return true; |
6de9cd9a | 233 | } |
bbd236a1 | 234 | return false; |
6de9cd9a DN |
235 | } |
236 | ||
237 | /* Return the file on which profile dump output goes, if any. */ | |
238 | ||
239 | static FILE *tree_profile_dump_file (void) { | |
240 | return dump_file; | |
241 | } | |
242 | ||
1f1e8527 DJ |
243 | static void |
244 | tree_profiling (void) | |
245 | { | |
246 | branch_prob (); | |
247 | if (flag_branch_probabilities | |
248 | && flag_profile_values | |
249 | && flag_value_profile_transformations) | |
250 | value_profile_transformations (); | |
251 | /* The above could hose dominator info. Currently there is | |
252 | none coming in, this is a safety valve. It should be | |
253 | easy to adjust it, if and when there is some. */ | |
254 | free_dominance_info (CDI_DOMINATORS); | |
255 | free_dominance_info (CDI_POST_DOMINATORS); | |
256 | } | |
257 | ||
6de9cd9a DN |
258 | struct tree_opt_pass pass_tree_profile = |
259 | { | |
260 | "tree_profile", /* name */ | |
261 | do_tree_profiling, /* gate */ | |
1f1e8527 | 262 | tree_profiling, /* execute */ |
6de9cd9a DN |
263 | NULL, /* sub */ |
264 | NULL, /* next */ | |
265 | 0, /* static_pass_number */ | |
266 | TV_BRANCH_PROB, /* tv_id */ | |
267 | PROP_gimple_leh | PROP_cfg, /* properties_required */ | |
268 | PROP_gimple_leh | PROP_cfg, /* properties_provided */ | |
269 | 0, /* properties_destroyed */ | |
270 | 0, /* todo_flags_start */ | |
9f8628ba PB |
271 | TODO_verify_stmts, /* todo_flags_finish */ |
272 | 0 /* letter */ | |
6de9cd9a DN |
273 | }; |
274 | ||
d63db217 JH |
275 | /* Return 1 if tree-based profiling is in effect, else 0. |
276 | If it is, set up hooks for tree-based profiling. | |
277 | Gate for pass_tree_profile. */ | |
278 | ||
279 | static bool | |
280 | do_early_tree_profiling (void) | |
281 | { | |
282 | return (do_tree_profiling () && (!flag_unit_at_a_time || !optimize)); | |
283 | } | |
284 | ||
285 | struct tree_opt_pass pass_early_tree_profile = | |
286 | { | |
287 | "early_tree_profile", /* name */ | |
288 | do_early_tree_profiling, /* gate */ | |
289 | tree_profiling, /* execute */ | |
290 | NULL, /* sub */ | |
291 | NULL, /* next */ | |
292 | 0, /* static_pass_number */ | |
293 | TV_BRANCH_PROB, /* tv_id */ | |
294 | PROP_gimple_leh | PROP_cfg, /* properties_required */ | |
295 | PROP_gimple_leh | PROP_cfg, /* properties_provided */ | |
296 | 0, /* properties_destroyed */ | |
297 | 0, /* todo_flags_start */ | |
298 | TODO_verify_stmts, /* todo_flags_finish */ | |
299 | 0 /* letter */ | |
300 | }; | |
301 | ||
6de9cd9a DN |
302 | struct profile_hooks tree_profile_hooks = |
303 | { | |
f3df9541 | 304 | tree_init_edge_profiler, /* init_edge_profiler */ |
6de9cd9a DN |
305 | tree_gen_edge_profiler, /* gen_edge_profiler */ |
306 | tree_gen_interval_profiler, /* gen_interval_profiler */ | |
307 | tree_gen_pow2_profiler, /* gen_pow2_profiler */ | |
308 | tree_gen_one_value_profiler, /* gen_one_value_profiler */ | |
309 | tree_gen_const_delta_profiler,/* gen_const_delta_profiler */ | |
310 | tree_profile_dump_file /* profile_dump_file */ | |
311 | }; | |
9885da8e ZD |
312 | |
313 | #include "gt-tree-profile.h" |