]>
Commit | Line | Data |
---|---|---|
4ee9c684 | 1 | /* Calculate branch probabilities, and basic block execution counts. |
2 | Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, | |
7cf0dbf3 | 3 | 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 |
46a0e9e8 | 4 | Free Software Foundation, Inc. |
4ee9c684 | 5 | Contributed by James E. Wilson, UC Berkeley/Cygnus Support; |
6 | based on some ideas from Dain Samples of UC Berkeley. | |
7 | Further mangling by Bob Manson, Cygnus Support. | |
8 | Converted to use trees by Dale Johannesen, Apple Computer. | |
9 | ||
10 | This file is part of GCC. | |
11 | ||
12 | GCC is free software; you can redistribute it and/or modify it under | |
13 | the terms of the GNU General Public License as published by the Free | |
8c4c00c1 | 14 | Software Foundation; either version 3, or (at your option) any later |
4ee9c684 | 15 | version. |
16 | ||
17 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
18 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
20 | for more details. | |
21 | ||
22 | You should have received a copy of the GNU General Public License | |
8c4c00c1 | 23 | along with GCC; see the file COPYING3. If not see |
24 | <http://www.gnu.org/licenses/>. */ | |
4ee9c684 | 25 | |
26 | /* Generate basic block profile instrumentation and auxiliary files. | |
d2971487 | 27 | Tree-based version. See profile.c for overview. */ |
4ee9c684 | 28 | |
29 | #include "config.h" | |
30 | #include "system.h" | |
31 | #include "coretypes.h" | |
32 | #include "tm.h" | |
4ee9c684 | 33 | #include "flags.h" |
4ee9c684 | 34 | #include "function.h" |
a79e7523 | 35 | #include "basic-block.h" |
0b205f4c | 36 | #include "diagnostic-core.h" |
4ee9c684 | 37 | #include "coverage.h" |
38 | #include "tree.h" | |
39 | #include "tree-flow.h" | |
40 | #include "tree-dump.h" | |
41 | #include "tree-pass.h" | |
42 | #include "timevar.h" | |
43 | #include "value-prof.h" | |
167b550b | 44 | #include "cgraph.h" |
1ad3e14c | 45 | #include "profile.h" |
109cfbe4 | 46 | #include "target.h" |
4ee9c684 | 47 | |
d7683f13 | 48 | static GTY(()) tree gcov_type_node; |
f81207a7 | 49 | static GTY(()) tree gcov_type_tmp_var; |
d7683f13 | 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; | |
167b550b | 53 | static GTY(()) tree tree_indirect_call_profiler_fn; |
162719b3 | 54 | static GTY(()) tree tree_average_profiler_fn; |
55 | static GTY(()) tree tree_ior_profiler_fn; | |
4ee9c684 | 56 | \f |
4b0a9554 | 57 | |
167b550b | 58 | static GTY(()) tree ic_void_ptr_var; |
59 | static GTY(()) tree ic_gcov_type_ptr_var; | |
60 | static GTY(()) tree ptr_void; | |
61 | ||
4b0a9554 | 62 | /* Do initialization work for the edge profiler. */ |
63 | ||
167b550b | 64 | /* Add code: |
65 | static gcov* __gcov_indirect_call_counters; // pointer to actual counter | |
f0b5f617 | 66 | static void* __gcov_indirect_call_callee; // actual callee address |
167b550b | 67 | */ |
68 | static void | |
fc49fbc1 | 69 | init_ic_make_global_vars (void) |
167b550b | 70 | { |
71 | tree gcov_type_ptr; | |
72 | ||
73 | ptr_void = build_pointer_type (void_type_node); | |
48e1416a | 74 | |
75 | ic_void_ptr_var | |
76 | = build_decl (UNKNOWN_LOCATION, VAR_DECL, | |
77 | get_identifier ("__gcov_indirect_call_callee"), | |
167b550b | 78 | ptr_void); |
79 | TREE_STATIC (ic_void_ptr_var) = 1; | |
80 | TREE_PUBLIC (ic_void_ptr_var) = 0; | |
81 | DECL_ARTIFICIAL (ic_void_ptr_var) = 1; | |
82 | DECL_INITIAL (ic_void_ptr_var) = NULL; | |
109cfbe4 | 83 | if (targetm.have_tls) |
84 | DECL_TLS_MODEL (ic_void_ptr_var) = | |
85 | decl_default_tls_model (ic_void_ptr_var); | |
86 | ||
6c0782b1 | 87 | varpool_finalize_decl (ic_void_ptr_var); |
167b550b | 88 | |
89 | gcov_type_ptr = build_pointer_type (get_gcov_type ()); | |
48e1416a | 90 | ic_gcov_type_ptr_var |
91 | = build_decl (UNKNOWN_LOCATION, VAR_DECL, | |
92 | get_identifier ("__gcov_indirect_call_counters"), | |
167b550b | 93 | gcov_type_ptr); |
94 | TREE_STATIC (ic_gcov_type_ptr_var) = 1; | |
95 | TREE_PUBLIC (ic_gcov_type_ptr_var) = 0; | |
96 | DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1; | |
97 | DECL_INITIAL (ic_gcov_type_ptr_var) = NULL; | |
109cfbe4 | 98 | if (targetm.have_tls) |
99 | DECL_TLS_MODEL (ic_gcov_type_ptr_var) = | |
100 | decl_default_tls_model (ic_gcov_type_ptr_var); | |
101 | ||
6c0782b1 | 102 | varpool_finalize_decl (ic_gcov_type_ptr_var); |
167b550b | 103 | } |
104 | ||
fc49fbc1 | 105 | void |
106 | gimple_init_edge_profiler (void) | |
4b0a9554 | 107 | { |
d7683f13 | 108 | tree interval_profiler_fn_type; |
109 | tree pow2_profiler_fn_type; | |
110 | tree one_value_profiler_fn_type; | |
111 | tree gcov_type_ptr; | |
167b550b | 112 | tree ic_profiler_fn_type; |
162719b3 | 113 | tree average_profiler_fn_type; |
d7683f13 | 114 | |
115 | if (!gcov_type_node) | |
116 | { | |
117 | gcov_type_node = get_gcov_type (); | |
118 | gcov_type_ptr = build_pointer_type (gcov_type_node); | |
119 | ||
120 | /* void (*) (gcov_type *, gcov_type, int, unsigned) */ | |
121 | interval_profiler_fn_type | |
122 | = build_function_type_list (void_type_node, | |
123 | gcov_type_ptr, gcov_type_node, | |
124 | integer_type_node, | |
125 | unsigned_type_node, NULL_TREE); | |
126 | tree_interval_profiler_fn | |
127 | = build_fn_decl ("__gcov_interval_profiler", | |
128 | interval_profiler_fn_type); | |
85344eeb | 129 | TREE_NOTHROW (tree_interval_profiler_fn) = 1; |
130 | DECL_ATTRIBUTES (tree_interval_profiler_fn) | |
131 | = tree_cons (get_identifier ("leaf"), NULL, | |
132 | DECL_ATTRIBUTES (tree_interval_profiler_fn)); | |
d7683f13 | 133 | |
134 | /* void (*) (gcov_type *, gcov_type) */ | |
135 | pow2_profiler_fn_type | |
136 | = build_function_type_list (void_type_node, | |
137 | gcov_type_ptr, gcov_type_node, | |
138 | NULL_TREE); | |
139 | tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler", | |
140 | pow2_profiler_fn_type); | |
85344eeb | 141 | TREE_NOTHROW (tree_pow2_profiler_fn) = 1; |
142 | DECL_ATTRIBUTES (tree_pow2_profiler_fn) | |
143 | = tree_cons (get_identifier ("leaf"), NULL, | |
144 | DECL_ATTRIBUTES (tree_pow2_profiler_fn)); | |
d7683f13 | 145 | |
146 | /* void (*) (gcov_type *, gcov_type) */ | |
147 | one_value_profiler_fn_type | |
148 | = build_function_type_list (void_type_node, | |
149 | gcov_type_ptr, gcov_type_node, | |
150 | NULL_TREE); | |
151 | tree_one_value_profiler_fn | |
152 | = build_fn_decl ("__gcov_one_value_profiler", | |
153 | one_value_profiler_fn_type); | |
85344eeb | 154 | TREE_NOTHROW (tree_one_value_profiler_fn) = 1; |
155 | DECL_ATTRIBUTES (tree_one_value_profiler_fn) | |
156 | = tree_cons (get_identifier ("leaf"), NULL, | |
157 | DECL_ATTRIBUTES (tree_one_value_profiler_fn)); | |
167b550b | 158 | |
fc49fbc1 | 159 | init_ic_make_global_vars (); |
48e1416a | 160 | |
167b550b | 161 | /* void (*) (gcov_type *, gcov_type, void *, void *) */ |
162 | ic_profiler_fn_type | |
163 | = build_function_type_list (void_type_node, | |
164 | gcov_type_ptr, gcov_type_node, | |
165 | ptr_void, | |
166 | ptr_void, NULL_TREE); | |
167 | tree_indirect_call_profiler_fn | |
168 | = build_fn_decl ("__gcov_indirect_call_profiler", | |
169 | ic_profiler_fn_type); | |
85344eeb | 170 | TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1; |
171 | DECL_ATTRIBUTES (tree_indirect_call_profiler_fn) | |
172 | = tree_cons (get_identifier ("leaf"), NULL, | |
173 | DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)); | |
174 | ||
162719b3 | 175 | /* void (*) (gcov_type *, gcov_type) */ |
176 | average_profiler_fn_type | |
177 | = build_function_type_list (void_type_node, | |
178 | gcov_type_ptr, gcov_type_node, NULL_TREE); | |
179 | tree_average_profiler_fn | |
180 | = build_fn_decl ("__gcov_average_profiler", | |
181 | average_profiler_fn_type); | |
85344eeb | 182 | TREE_NOTHROW (tree_average_profiler_fn) = 1; |
183 | DECL_ATTRIBUTES (tree_average_profiler_fn) | |
184 | = tree_cons (get_identifier ("leaf"), NULL, | |
185 | DECL_ATTRIBUTES (tree_average_profiler_fn)); | |
162719b3 | 186 | tree_ior_profiler_fn |
187 | = build_fn_decl ("__gcov_ior_profiler", | |
188 | average_profiler_fn_type); | |
85344eeb | 189 | TREE_NOTHROW (tree_ior_profiler_fn) = 1; |
190 | DECL_ATTRIBUTES (tree_ior_profiler_fn) | |
191 | = tree_cons (get_identifier ("leaf"), NULL, | |
192 | DECL_ATTRIBUTES (tree_ior_profiler_fn)); | |
193 | ||
6c0782b1 | 194 | /* LTO streamer needs assembler names. Because we create these decls |
195 | late, we need to initialize them by hand. */ | |
196 | DECL_ASSEMBLER_NAME (tree_interval_profiler_fn); | |
197 | DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn); | |
198 | DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn); | |
199 | DECL_ASSEMBLER_NAME (tree_indirect_call_profiler_fn); | |
200 | DECL_ASSEMBLER_NAME (tree_average_profiler_fn); | |
201 | DECL_ASSEMBLER_NAME (tree_ior_profiler_fn); | |
d7683f13 | 202 | } |
4b0a9554 | 203 | } |
204 | ||
48e1416a | 205 | /* Output instructions as GIMPLE trees to increment the edge |
206 | execution count, and insert them on E. We rely on | |
75a70cf9 | 207 | gsi_insert_on_edge to preserve the order. */ |
4ee9c684 | 208 | |
fc49fbc1 | 209 | void |
210 | gimple_gen_edge_profiler (int edgeno, edge e) | |
4ee9c684 | 211 | { |
75a70cf9 | 212 | tree ref, one; |
213 | gimple stmt1, stmt2, stmt3; | |
f81207a7 | 214 | |
215 | /* We share one temporary variable declaration per function. This | |
216 | gets re-set in tree_profiling. */ | |
217 | if (gcov_type_tmp_var == NULL_TREE) | |
85344eeb | 218 | gcov_type_tmp_var = create_tmp_reg (gcov_type_node, "PROF_edge_counter"); |
f81207a7 | 219 | ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); |
220 | one = build_int_cst (gcov_type_node, 1); | |
75a70cf9 | 221 | stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); |
85344eeb | 222 | gimple_assign_set_lhs (stmt1, make_ssa_name (gcov_type_tmp_var, stmt1)); |
6d3d8bf0 | 223 | find_referenced_vars_in (stmt1); |
75a70cf9 | 224 | stmt2 = gimple_build_assign_with_ops (PLUS_EXPR, gcov_type_tmp_var, |
85344eeb | 225 | gimple_assign_lhs (stmt1), one); |
226 | gimple_assign_set_lhs (stmt2, make_ssa_name (gcov_type_tmp_var, stmt2)); | |
227 | stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2)); | |
75a70cf9 | 228 | gsi_insert_on_edge (e, stmt1); |
229 | gsi_insert_on_edge (e, stmt2); | |
230 | gsi_insert_on_edge (e, stmt3); | |
4ee9c684 | 231 | } |
232 | ||
75a70cf9 | 233 | /* Emits code to get VALUE to instrument at GSI, and returns the |
d7683f13 | 234 | variable containing the value. */ |
235 | ||
236 | static tree | |
75a70cf9 | 237 | prepare_instrumented_value (gimple_stmt_iterator *gsi, histogram_value value) |
d7683f13 | 238 | { |
ed4294da | 239 | tree val = value->hvalue.value; |
c821ef7d | 240 | if (POINTER_TYPE_P (TREE_TYPE (val))) |
a0553bff | 241 | val = fold_convert (build_nonstandard_integer_type |
242 | (TYPE_PRECISION (TREE_TYPE (val)), 1), val); | |
75a70cf9 | 243 | return force_gimple_operand_gsi (gsi, fold_convert (gcov_type_node, val), |
244 | true, NULL_TREE, true, GSI_SAME_STMT); | |
d7683f13 | 245 | } |
246 | ||
48e1416a | 247 | /* Output instructions as GIMPLE trees to increment the interval histogram |
248 | counter. VALUE is the expression whose value is profiled. TAG is the | |
4ee9c684 | 249 | tag of the section for counters, BASE is offset of the counter position. */ |
250 | ||
fc49fbc1 | 251 | void |
252 | gimple_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) | |
4ee9c684 | 253 | { |
75a70cf9 | 254 | gimple stmt = value->hvalue.stmt; |
255 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
d7683f13 | 256 | tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; |
75a70cf9 | 257 | gimple call; |
258 | tree val; | |
259 | tree start = build_int_cst_type (integer_type_node, | |
260 | value->hdata.intvl.int_start); | |
261 | tree steps = build_int_cst_type (unsigned_type_node, | |
262 | value->hdata.intvl.steps); | |
48e1416a | 263 | |
75a70cf9 | 264 | ref_ptr = force_gimple_operand_gsi (&gsi, |
d2024a0d | 265 | build_addr (ref, current_function_decl), |
75a70cf9 | 266 | true, NULL_TREE, true, GSI_SAME_STMT); |
267 | val = prepare_instrumented_value (&gsi, value); | |
268 | call = gimple_build_call (tree_interval_profiler_fn, 4, | |
269 | ref_ptr, val, start, steps); | |
6d3d8bf0 | 270 | find_referenced_vars_in (call); |
77fca8b5 | 271 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
4ee9c684 | 272 | } |
273 | ||
48e1416a | 274 | /* Output instructions as GIMPLE trees to increment the power of two histogram |
275 | counter. VALUE is the expression whose value is profiled. TAG is the tag | |
4ee9c684 | 276 | of the section for counters, BASE is offset of the counter position. */ |
277 | ||
fc49fbc1 | 278 | void |
279 | gimple_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base) | |
4ee9c684 | 280 | { |
75a70cf9 | 281 | gimple stmt = value->hvalue.stmt; |
282 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
a961cdc2 | 283 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
75a70cf9 | 284 | gimple call; |
285 | tree val; | |
48e1416a | 286 | |
75a70cf9 | 287 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
288 | true, NULL_TREE, true, GSI_SAME_STMT); | |
289 | val = prepare_instrumented_value (&gsi, value); | |
290 | call = gimple_build_call (tree_pow2_profiler_fn, 2, ref_ptr, val); | |
6d3d8bf0 | 291 | find_referenced_vars_in (call); |
77fca8b5 | 292 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
4ee9c684 | 293 | } |
294 | ||
295 | /* Output instructions as GIMPLE trees for code to find the most common value. | |
296 | VALUE is the expression whose value is profiled. TAG is the tag of the | |
297 | section for counters, BASE is offset of the counter position. */ | |
298 | ||
fc49fbc1 | 299 | void |
300 | gimple_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base) | |
4ee9c684 | 301 | { |
75a70cf9 | 302 | gimple stmt = value->hvalue.stmt; |
303 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
a961cdc2 | 304 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
75a70cf9 | 305 | gimple call; |
306 | tree val; | |
48e1416a | 307 | |
75a70cf9 | 308 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
309 | true, NULL_TREE, true, GSI_SAME_STMT); | |
310 | val = prepare_instrumented_value (&gsi, value); | |
311 | call = gimple_build_call (tree_one_value_profiler_fn, 2, ref_ptr, val); | |
6d3d8bf0 | 312 | find_referenced_vars_in (call); |
77fca8b5 | 313 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
4ee9c684 | 314 | } |
315 | ||
167b550b | 316 | |
317 | /* Output instructions as GIMPLE trees for code to find the most | |
48e1416a | 318 | common called function in indirect call. |
0d424440 | 319 | VALUE is the call expression whose indirect callee is profiled. |
167b550b | 320 | TAG is the tag of the section for counters, BASE is offset of the |
321 | counter position. */ | |
322 | ||
fc49fbc1 | 323 | void |
324 | gimple_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base) | |
167b550b | 325 | { |
75a70cf9 | 326 | tree tmp1; |
327 | gimple stmt1, stmt2, stmt3; | |
328 | gimple stmt = value->hvalue.stmt; | |
329 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
a961cdc2 | 330 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
167b550b | 331 | |
75a70cf9 | 332 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
333 | true, NULL_TREE, true, GSI_SAME_STMT); | |
167b550b | 334 | |
335 | /* Insert code: | |
48e1416a | 336 | |
337 | __gcov_indirect_call_counters = get_relevant_counter_ptr (); | |
167b550b | 338 | __gcov_indirect_call_callee = (void *) indirect call argument; |
339 | */ | |
340 | ||
85344eeb | 341 | tmp1 = create_tmp_reg (ptr_void, "PROF"); |
75a70cf9 | 342 | stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr); |
6d3d8bf0 | 343 | find_referenced_vars_in (stmt1); |
75a70cf9 | 344 | stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value)); |
85344eeb | 345 | gimple_assign_set_lhs (stmt2, make_ssa_name (tmp1, stmt2)); |
6d3d8bf0 | 346 | find_referenced_vars_in (stmt2); |
85344eeb | 347 | stmt3 = gimple_build_assign (ic_void_ptr_var, gimple_assign_lhs (stmt2)); |
167b550b | 348 | |
75a70cf9 | 349 | gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); |
350 | gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); | |
351 | gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT); | |
167b550b | 352 | } |
353 | ||
354 | ||
355 | /* Output instructions as GIMPLE trees for code to find the most | |
356 | common called function in indirect call. Insert instructions at the | |
0d424440 | 357 | beginning of every possible called function. |
167b550b | 358 | */ |
359 | ||
fc49fbc1 | 360 | void |
361 | gimple_gen_ic_func_profiler (void) | |
167b550b | 362 | { |
fd6a3c41 | 363 | struct cgraph_node * c_node = cgraph_get_node (current_function_decl); |
75a70cf9 | 364 | gimple_stmt_iterator gsi; |
75a70cf9 | 365 | gimple stmt1, stmt2; |
85344eeb | 366 | tree tree_uid, cur_func, counter_ptr, ptr_var, void0; |
167b550b | 367 | |
cdedc740 | 368 | if (cgraph_only_called_directly_p (c_node)) |
6329636b | 369 | return; |
48e1416a | 370 | |
fc49fbc1 | 371 | gimple_init_edge_profiler (); |
48e1416a | 372 | |
85344eeb | 373 | gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR)); |
374 | ||
375 | cur_func = force_gimple_operand_gsi (&gsi, | |
376 | build_addr (current_function_decl, | |
377 | current_function_decl), | |
378 | true, NULL_TREE, | |
379 | true, GSI_SAME_STMT); | |
380 | counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var, | |
381 | true, NULL_TREE, true, | |
382 | GSI_SAME_STMT); | |
383 | ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var, | |
384 | true, NULL_TREE, true, | |
385 | GSI_SAME_STMT); | |
1ad3e14c | 386 | tree_uid = build_int_cst (gcov_type_node, current_function_funcdef_no); |
85344eeb | 387 | stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4, |
388 | counter_ptr, tree_uid, cur_func, ptr_var); | |
389 | gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); | |
390 | ||
391 | /* Set __gcov_indirect_call_callee to 0, | |
392 | so that calls from other modules won't get misattributed | |
393 | to the last caller of the current callee. */ | |
394 | void0 = build_int_cst (build_pointer_type (void_type_node), 0); | |
395 | stmt2 = gimple_build_assign (ic_void_ptr_var, void0); | |
396 | gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); | |
167b550b | 397 | } |
398 | ||
48e1416a | 399 | /* Output instructions as GIMPLE trees for code to find the most common value |
4ee9c684 | 400 | of a difference between two evaluations of an expression. |
401 | VALUE is the expression whose value is profiled. TAG is the tag of the | |
402 | section for counters, BASE is offset of the counter position. */ | |
403 | ||
fc49fbc1 | 404 | void |
405 | gimple_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED, | |
75a70cf9 | 406 | unsigned tag ATTRIBUTE_UNUSED, |
407 | unsigned base ATTRIBUTE_UNUSED) | |
4ee9c684 | 408 | { |
409 | /* FIXME implement this. */ | |
8c0963c4 | 410 | #ifdef ENABLE_CHECKING |
411 | internal_error ("unimplemented functionality"); | |
412 | #endif | |
413 | gcc_unreachable (); | |
4ee9c684 | 414 | } |
415 | ||
48e1416a | 416 | /* Output instructions as GIMPLE trees to increment the average histogram |
417 | counter. VALUE is the expression whose value is profiled. TAG is the | |
162719b3 | 418 | tag of the section for counters, BASE is offset of the counter position. */ |
419 | ||
fc49fbc1 | 420 | void |
421 | gimple_gen_average_profiler (histogram_value value, unsigned tag, unsigned base) | |
162719b3 | 422 | { |
75a70cf9 | 423 | gimple stmt = value->hvalue.stmt; |
424 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
a961cdc2 | 425 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
75a70cf9 | 426 | gimple call; |
427 | tree val; | |
48e1416a | 428 | |
75a70cf9 | 429 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
0d734975 | 430 | true, NULL_TREE, |
75a70cf9 | 431 | true, GSI_SAME_STMT); |
432 | val = prepare_instrumented_value (&gsi, value); | |
433 | call = gimple_build_call (tree_average_profiler_fn, 2, ref_ptr, val); | |
6d3d8bf0 | 434 | find_referenced_vars_in (call); |
77fca8b5 | 435 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
162719b3 | 436 | } |
437 | ||
48e1416a | 438 | /* Output instructions as GIMPLE trees to increment the ior histogram |
439 | counter. VALUE is the expression whose value is profiled. TAG is the | |
162719b3 | 440 | tag of the section for counters, BASE is offset of the counter position. */ |
441 | ||
fc49fbc1 | 442 | void |
443 | gimple_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base) | |
162719b3 | 444 | { |
75a70cf9 | 445 | gimple stmt = value->hvalue.stmt; |
446 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
a961cdc2 | 447 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
75a70cf9 | 448 | gimple call; |
449 | tree val; | |
48e1416a | 450 | |
75a70cf9 | 451 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
452 | true, NULL_TREE, true, GSI_SAME_STMT); | |
453 | val = prepare_instrumented_value (&gsi, value); | |
454 | call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val); | |
6d3d8bf0 | 455 | find_referenced_vars_in (call); |
77fca8b5 | 456 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
162719b3 | 457 | } |
458 | ||
85344eeb | 459 | /* Profile all functions in the callgraph. */ |
4ee9c684 | 460 | |
2a1990e9 | 461 | static unsigned int |
d2971487 | 462 | tree_profiling (void) |
463 | { | |
85344eeb | 464 | struct cgraph_node *node; |
465 | ||
f517b36e | 466 | /* Don't profile functions produced at destruction time, particularly |
b3a3ddec | 467 | the gcov datastructure initializer. Don't profile if it has been |
468 | already instrumented either (when OpenMP expansion creates | |
469 | child function from already instrumented body). */ | |
85344eeb | 470 | if (cgraph_state == CGRAPH_STATE_FINISHED) |
f517b36e | 471 | return 0; |
f81207a7 | 472 | |
1ad3e14c | 473 | init_node_map(); |
474 | ||
7c455d87 | 475 | FOR_EACH_DEFINED_FUNCTION (node) |
85344eeb | 476 | { |
7c455d87 | 477 | if (!gimple_has_body_p (node->symbol.decl)) |
85344eeb | 478 | continue; |
479 | ||
480 | /* Don't profile functions produced for builtin stuff. */ | |
7d0d0ce1 | 481 | if (DECL_SOURCE_LOCATION (node->symbol.decl) == BUILTINS_LOCATION |
482 | || DECL_STRUCT_FUNCTION (node->symbol.decl)->after_tree_profile) | |
85344eeb | 483 | continue; |
484 | ||
7d0d0ce1 | 485 | push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); |
486 | current_function_decl = node->symbol.decl; | |
85344eeb | 487 | |
488 | /* Re-set global shared temporary variable for edge-counters. */ | |
489 | gcov_type_tmp_var = NULL_TREE; | |
490 | ||
8c1fce46 | 491 | /* Local pure-const may imply need to fixup the cfg. */ |
141de90e | 492 | if (execute_fixup_cfg () & TODO_cleanup_cfg) |
493 | cleanup_tree_cfg (); | |
85344eeb | 494 | branch_prob (); |
495 | ||
496 | if (! flag_branch_probabilities | |
497 | && flag_profile_values) | |
fc49fbc1 | 498 | gimple_gen_ic_func_profiler (); |
85344eeb | 499 | |
500 | if (flag_branch_probabilities | |
501 | && flag_profile_values | |
502 | && flag_value_profile_transformations) | |
fc49fbc1 | 503 | gimple_value_profile_transformations (); |
85344eeb | 504 | |
505 | /* The above could hose dominator info. Currently there is | |
506 | none coming in, this is a safety valve. It should be | |
507 | easy to adjust it, if and when there is some. */ | |
508 | free_dominance_info (CDI_DOMINATORS); | |
509 | free_dominance_info (CDI_POST_DOMINATORS); | |
510 | ||
511 | current_function_decl = NULL; | |
512 | pop_cfun (); | |
513 | } | |
514 | ||
515 | /* Drop pure/const flags from instrumented functions. */ | |
7c455d87 | 516 | FOR_EACH_DEFINED_FUNCTION (node) |
85344eeb | 517 | { |
7c455d87 | 518 | if (!gimple_has_body_p (node->symbol.decl) |
7d0d0ce1 | 519 | || !(!node->clone_of |
520 | || node->symbol.decl != node->clone_of->symbol.decl)) | |
85344eeb | 521 | continue; |
522 | ||
523 | /* Don't profile functions produced for builtin stuff. */ | |
7d0d0ce1 | 524 | if (DECL_SOURCE_LOCATION (node->symbol.decl) == BUILTINS_LOCATION |
525 | || DECL_STRUCT_FUNCTION (node->symbol.decl)->after_tree_profile) | |
85344eeb | 526 | continue; |
527 | ||
7f74ac6b | 528 | cgraph_set_const_flag (node, false, false); |
529 | cgraph_set_pure_flag (node, false, false); | |
85344eeb | 530 | } |
531 | ||
532 | /* Update call statements and rebuild the cgraph. */ | |
7c455d87 | 533 | FOR_EACH_DEFINED_FUNCTION (node) |
85344eeb | 534 | { |
535 | basic_block bb; | |
536 | ||
7c455d87 | 537 | if (!gimple_has_body_p (node->symbol.decl) |
7d0d0ce1 | 538 | || !(!node->clone_of |
539 | || node->symbol.decl != node->clone_of->symbol.decl)) | |
85344eeb | 540 | continue; |
541 | ||
542 | /* Don't profile functions produced for builtin stuff. */ | |
7d0d0ce1 | 543 | if (DECL_SOURCE_LOCATION (node->symbol.decl) == BUILTINS_LOCATION |
544 | || DECL_STRUCT_FUNCTION (node->symbol.decl)->after_tree_profile) | |
85344eeb | 545 | continue; |
546 | ||
7d0d0ce1 | 547 | push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); |
548 | current_function_decl = node->symbol.decl; | |
85344eeb | 549 | |
550 | FOR_EACH_BB (bb) | |
551 | { | |
552 | gimple_stmt_iterator gsi; | |
553 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |
554 | { | |
555 | gimple stmt = gsi_stmt (gsi); | |
556 | if (is_gimple_call (stmt)) | |
557 | update_stmt (stmt); | |
558 | } | |
559 | } | |
560 | ||
561 | cfun->after_tree_profile = 1; | |
562 | update_ssa (TODO_update_ssa); | |
563 | ||
564 | rebuild_cgraph_edges (); | |
565 | ||
566 | current_function_decl = NULL; | |
567 | pop_cfun (); | |
568 | } | |
fdc47e9a | 569 | |
1ad3e14c | 570 | del_node_map(); |
2a1990e9 | 571 | return 0; |
d2971487 | 572 | } |
573 | ||
85344eeb | 574 | /* When profile instrumentation, use or test coverage shall be performed. */ |
575 | ||
576 | static bool | |
577 | gate_tree_profile_ipa (void) | |
578 | { | |
579 | return (!in_lto_p | |
580 | && (flag_branch_probabilities || flag_test_coverage | |
581 | || profile_arc_flag)); | |
582 | } | |
583 | ||
584 | struct simple_ipa_opt_pass pass_ipa_tree_profile = | |
4ee9c684 | 585 | { |
20099e35 | 586 | { |
85344eeb | 587 | SIMPLE_IPA_PASS, |
855c9b82 | 588 | "profile", /* name */ |
85344eeb | 589 | gate_tree_profile_ipa, /* gate */ |
590 | tree_profiling, /* execute */ | |
591 | NULL, /* sub */ | |
592 | NULL, /* next */ | |
593 | 0, /* static_pass_number */ | |
594 | TV_IPA_PROFILE, /* tv_id */ | |
595 | 0, /* properties_required */ | |
596 | 0, /* properties_provided */ | |
597 | 0, /* properties_destroyed */ | |
598 | 0, /* todo_flags_start */ | |
771e2890 | 599 | 0 /* todo_flags_finish */ |
20099e35 | 600 | } |
4ee9c684 | 601 | }; |
602 | ||
d7683f13 | 603 | #include "gt-tree-profile.h" |