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