]>
Commit | Line | Data |
---|---|---|
6de9cd9a | 1 | /* Calculate branch probabilities, and basic block execution counts. |
5624e564 | 2 | Copyright (C) 1990-2015 Free Software Foundation, Inc. |
6de9cd9a DN |
3 | Contributed by James E. Wilson, UC Berkeley/Cygnus Support; |
4 | based on some ideas from Dain Samples of UC Berkeley. | |
5 | Further mangling by Bob Manson, Cygnus Support. | |
6 | Converted to use trees by Dale Johannesen, Apple Computer. | |
7 | ||
8 | This file is part of GCC. | |
9 | ||
10 | GCC is free software; you can redistribute it and/or modify it under | |
11 | the terms of the GNU General Public License as published by the Free | |
9dcd6f09 | 12 | Software Foundation; either version 3, or (at your option) any later |
6de9cd9a DN |
13 | version. |
14 | ||
15 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
16 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
17 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
18 | for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
9dcd6f09 NC |
21 | along with GCC; see the file COPYING3. If not see |
22 | <http://www.gnu.org/licenses/>. */ | |
6de9cd9a DN |
23 | |
24 | /* Generate basic block profile instrumentation and auxiliary files. | |
1f1e8527 | 25 | Tree-based version. See profile.c for overview. */ |
6de9cd9a DN |
26 | |
27 | #include "config.h" | |
28 | #include "system.h" | |
29 | #include "coretypes.h" | |
30 | #include "tm.h" | |
6de9cd9a | 31 | #include "flags.h" |
83685514 AM |
32 | #include "hashtab.h" |
33 | #include "hash-set.h" | |
34 | #include "vec.h" | |
35 | #include "machmode.h" | |
36 | #include "hard-reg-set.h" | |
37 | #include "input.h" | |
6de9cd9a | 38 | #include "function.h" |
60393bbc AM |
39 | #include "predict.h" |
40 | #include "dominance.h" | |
41 | #include "cfg.h" | |
2d1a4cc1 | 42 | #include "basic-block.h" |
718f9c0f | 43 | #include "diagnostic-core.h" |
6de9cd9a | 44 | #include "coverage.h" |
40e23961 MC |
45 | #include "double-int.h" |
46 | #include "input.h" | |
47 | #include "alias.h" | |
48 | #include "symtab.h" | |
49 | #include "wide-int.h" | |
50 | #include "inchash.h" | |
6de9cd9a | 51 | #include "tree.h" |
40e23961 | 52 | #include "fold-const.h" |
2fb9a547 AM |
53 | #include "tree-ssa-alias.h" |
54 | #include "internal-fn.h" | |
55 | #include "gimple-expr.h" | |
56 | #include "is-a.h" | |
18f429e2 | 57 | #include "gimple.h" |
d8a2d370 DN |
58 | #include "varasm.h" |
59 | #include "tree-nested.h" | |
45b0be94 | 60 | #include "gimplify.h" |
5be5c238 | 61 | #include "gimple-iterator.h" |
18f429e2 | 62 | #include "gimplify-me.h" |
442b4905 | 63 | #include "gimple-ssa.h" |
c582198b AM |
64 | #include "hash-map.h" |
65 | #include "plugin-api.h" | |
66 | #include "ipa-ref.h" | |
442b4905 AM |
67 | #include "cgraph.h" |
68 | #include "tree-cfg.h" | |
d8a2d370 | 69 | #include "stringpool.h" |
442b4905 AM |
70 | #include "tree-ssanames.h" |
71 | #include "tree-into-ssa.h" | |
6de9cd9a | 72 | #include "tree-pass.h" |
6de9cd9a | 73 | #include "value-prof.h" |
903d1e67 | 74 | #include "profile.h" |
d984c8ef | 75 | #include "target.h" |
4484a35a | 76 | #include "tree-cfgcleanup.h" |
1fe37220 | 77 | #include "tree-nested.h" |
0a750165 | 78 | #include "params.h" |
6de9cd9a | 79 | |
9885da8e ZD |
80 | static GTY(()) tree gcov_type_node; |
81 | static GTY(()) tree tree_interval_profiler_fn; | |
82 | static GTY(()) tree tree_pow2_profiler_fn; | |
83 | static GTY(()) tree tree_one_value_profiler_fn; | |
6bad2617 | 84 | static GTY(()) tree tree_indirect_call_profiler_fn; |
86ce5d2f | 85 | static GTY(()) tree tree_time_profiler_fn; |
079a182e JH |
86 | static GTY(()) tree tree_average_profiler_fn; |
87 | static GTY(()) tree tree_ior_profiler_fn; | |
86ce5d2f | 88 | |
f3df9541 | 89 | |
6bad2617 TB |
90 | static GTY(()) tree ic_void_ptr_var; |
91 | static GTY(()) tree ic_gcov_type_ptr_var; | |
92 | static GTY(()) tree ptr_void; | |
93 | ||
f3df9541 AK |
94 | /* Do initialization work for the edge profiler. */ |
95 | ||
6bad2617 | 96 | /* Add code: |
2fa3d31b | 97 | __thread gcov* __gcov_indirect_call_counters; // pointer to actual counter |
86ce5d2f ML |
98 | __thread void* __gcov_indirect_call_callee; // actual callee address |
99 | __thread int __gcov_function_counter; // time profiler function counter | |
6bad2617 TB |
100 | */ |
101 | static void | |
e0cb7e1e | 102 | init_ic_make_global_vars (void) |
6bad2617 TB |
103 | { |
104 | tree gcov_type_ptr; | |
105 | ||
106 | ptr_void = build_pointer_type (void_type_node); | |
b8698a0f | 107 | |
748d71f3 JH |
108 | /* Workaround for binutils bug 14342. Once it is fixed, remove lto path. */ |
109 | if (flag_lto) | |
110 | { | |
111 | ic_void_ptr_var | |
112 | = build_decl (UNKNOWN_LOCATION, VAR_DECL, | |
113 | get_identifier ("__gcov_indirect_call_callee_ltopriv"), | |
114 | ptr_void); | |
115 | TREE_PUBLIC (ic_void_ptr_var) = 1; | |
116 | DECL_COMMON (ic_void_ptr_var) = 1; | |
117 | DECL_VISIBILITY (ic_void_ptr_var) = VISIBILITY_HIDDEN; | |
118 | DECL_VISIBILITY_SPECIFIED (ic_void_ptr_var) = true; | |
119 | } | |
120 | else | |
121 | { | |
122 | ic_void_ptr_var | |
123 | = build_decl (UNKNOWN_LOCATION, VAR_DECL, | |
0a750165 RX |
124 | get_identifier ( |
125 | (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ? | |
126 | "__gcov_indirect_call_topn_callee" : | |
127 | "__gcov_indirect_call_callee")), | |
748d71f3 JH |
128 | ptr_void); |
129 | TREE_PUBLIC (ic_void_ptr_var) = 1; | |
130 | DECL_EXTERNAL (ic_void_ptr_var) = 1; | |
131 | } | |
6bad2617 | 132 | TREE_STATIC (ic_void_ptr_var) = 1; |
6bad2617 TB |
133 | DECL_ARTIFICIAL (ic_void_ptr_var) = 1; |
134 | DECL_INITIAL (ic_void_ptr_var) = NULL; | |
d984c8ef | 135 | if (targetm.have_tls) |
56363ffd | 136 | set_decl_tls_model (ic_void_ptr_var, decl_default_tls_model (ic_void_ptr_var)); |
d984c8ef | 137 | |
9041d2e6 | 138 | varpool_node::finalize_decl (ic_void_ptr_var); |
6bad2617 TB |
139 | |
140 | gcov_type_ptr = build_pointer_type (get_gcov_type ()); | |
748d71f3 JH |
141 | /* Workaround for binutils bug 14342. Once it is fixed, remove lto path. */ |
142 | if (flag_lto) | |
143 | { | |
144 | ic_gcov_type_ptr_var | |
145 | = build_decl (UNKNOWN_LOCATION, VAR_DECL, | |
146 | get_identifier ("__gcov_indirect_call_counters_ltopriv"), | |
147 | gcov_type_ptr); | |
148 | TREE_PUBLIC (ic_gcov_type_ptr_var) = 1; | |
149 | DECL_COMMON (ic_gcov_type_ptr_var) = 1; | |
150 | DECL_VISIBILITY (ic_gcov_type_ptr_var) = VISIBILITY_HIDDEN; | |
151 | DECL_VISIBILITY_SPECIFIED (ic_gcov_type_ptr_var) = true; | |
152 | } | |
153 | else | |
154 | { | |
155 | ic_gcov_type_ptr_var | |
156 | = build_decl (UNKNOWN_LOCATION, VAR_DECL, | |
0a750165 RX |
157 | get_identifier ( |
158 | (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ? | |
159 | "__gcov_indirect_call_topn_counters" : | |
160 | "__gcov_indirect_call_counters")), | |
748d71f3 JH |
161 | gcov_type_ptr); |
162 | TREE_PUBLIC (ic_gcov_type_ptr_var) = 1; | |
163 | DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1; | |
164 | } | |
6bad2617 | 165 | TREE_STATIC (ic_gcov_type_ptr_var) = 1; |
6bad2617 TB |
166 | DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1; |
167 | DECL_INITIAL (ic_gcov_type_ptr_var) = NULL; | |
d984c8ef | 168 | if (targetm.have_tls) |
56363ffd | 169 | set_decl_tls_model (ic_gcov_type_ptr_var, decl_default_tls_model (ic_gcov_type_ptr_var)); |
d984c8ef | 170 | |
9041d2e6 | 171 | varpool_node::finalize_decl (ic_gcov_type_ptr_var); |
6bad2617 TB |
172 | } |
173 | ||
9696c529 SB |
174 | /* Create the type and function decls for the interface with gcov. */ |
175 | ||
e0cb7e1e SB |
176 | void |
177 | gimple_init_edge_profiler (void) | |
f3df9541 | 178 | { |
9885da8e ZD |
179 | tree interval_profiler_fn_type; |
180 | tree pow2_profiler_fn_type; | |
181 | tree one_value_profiler_fn_type; | |
182 | tree gcov_type_ptr; | |
6bad2617 | 183 | tree ic_profiler_fn_type; |
079a182e | 184 | tree average_profiler_fn_type; |
86ce5d2f | 185 | tree time_profiler_fn_type; |
9885da8e ZD |
186 | |
187 | if (!gcov_type_node) | |
188 | { | |
189 | gcov_type_node = get_gcov_type (); | |
190 | gcov_type_ptr = build_pointer_type (gcov_type_node); | |
191 | ||
192 | /* void (*) (gcov_type *, gcov_type, int, unsigned) */ | |
193 | interval_profiler_fn_type | |
194 | = build_function_type_list (void_type_node, | |
195 | gcov_type_ptr, gcov_type_node, | |
196 | integer_type_node, | |
197 | unsigned_type_node, NULL_TREE); | |
198 | tree_interval_profiler_fn | |
199 | = build_fn_decl ("__gcov_interval_profiler", | |
200 | interval_profiler_fn_type); | |
4d3814a5 RG |
201 | TREE_NOTHROW (tree_interval_profiler_fn) = 1; |
202 | DECL_ATTRIBUTES (tree_interval_profiler_fn) | |
203 | = tree_cons (get_identifier ("leaf"), NULL, | |
204 | DECL_ATTRIBUTES (tree_interval_profiler_fn)); | |
9885da8e ZD |
205 | |
206 | /* void (*) (gcov_type *, gcov_type) */ | |
207 | pow2_profiler_fn_type | |
208 | = build_function_type_list (void_type_node, | |
209 | gcov_type_ptr, gcov_type_node, | |
210 | NULL_TREE); | |
211 | tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler", | |
212 | pow2_profiler_fn_type); | |
4d3814a5 RG |
213 | TREE_NOTHROW (tree_pow2_profiler_fn) = 1; |
214 | DECL_ATTRIBUTES (tree_pow2_profiler_fn) | |
215 | = tree_cons (get_identifier ("leaf"), NULL, | |
216 | DECL_ATTRIBUTES (tree_pow2_profiler_fn)); | |
9885da8e ZD |
217 | |
218 | /* void (*) (gcov_type *, gcov_type) */ | |
219 | one_value_profiler_fn_type | |
220 | = build_function_type_list (void_type_node, | |
221 | gcov_type_ptr, gcov_type_node, | |
222 | NULL_TREE); | |
223 | tree_one_value_profiler_fn | |
224 | = build_fn_decl ("__gcov_one_value_profiler", | |
225 | one_value_profiler_fn_type); | |
4d3814a5 RG |
226 | TREE_NOTHROW (tree_one_value_profiler_fn) = 1; |
227 | DECL_ATTRIBUTES (tree_one_value_profiler_fn) | |
228 | = tree_cons (get_identifier ("leaf"), NULL, | |
229 | DECL_ATTRIBUTES (tree_one_value_profiler_fn)); | |
6bad2617 | 230 | |
e0cb7e1e | 231 | init_ic_make_global_vars (); |
b8698a0f | 232 | |
748d71f3 JH |
233 | /* Workaround for binutils bug 14342. Once it is fixed, remove lto path. */ |
234 | if (flag_lto) | |
235 | { | |
236 | /* void (*) (gcov_type, void *) */ | |
237 | ic_profiler_fn_type | |
238 | = build_function_type_list (void_type_node, | |
239 | gcov_type_ptr, gcov_type_node, | |
240 | ptr_void, ptr_void, | |
241 | NULL_TREE); | |
242 | tree_indirect_call_profiler_fn | |
243 | = build_fn_decl ("__gcov_indirect_call_profiler", | |
244 | ic_profiler_fn_type); | |
245 | } | |
246 | else | |
247 | { | |
248 | /* void (*) (gcov_type, void *) */ | |
249 | ic_profiler_fn_type | |
250 | = build_function_type_list (void_type_node, | |
251 | gcov_type_node, | |
252 | ptr_void, | |
253 | NULL_TREE); | |
254 | tree_indirect_call_profiler_fn | |
0a750165 RX |
255 | = build_fn_decl ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ? |
256 | "__gcov_indirect_call_topn_profiler": | |
257 | "__gcov_indirect_call_profiler_v2"), | |
258 | ic_profiler_fn_type); | |
748d71f3 | 259 | } |
4d3814a5 RG |
260 | TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1; |
261 | DECL_ATTRIBUTES (tree_indirect_call_profiler_fn) | |
262 | = tree_cons (get_identifier ("leaf"), NULL, | |
263 | DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)); | |
264 | ||
86ce5d2f ML |
265 | /* void (*) (gcov_type *, gcov_type, void *) */ |
266 | time_profiler_fn_type | |
267 | = build_function_type_list (void_type_node, | |
268 | gcov_type_ptr, NULL_TREE); | |
269 | tree_time_profiler_fn | |
270 | = build_fn_decl ("__gcov_time_profiler", | |
271 | time_profiler_fn_type); | |
272 | TREE_NOTHROW (tree_time_profiler_fn) = 1; | |
273 | DECL_ATTRIBUTES (tree_time_profiler_fn) | |
274 | = tree_cons (get_identifier ("leaf"), NULL, | |
275 | DECL_ATTRIBUTES (tree_time_profiler_fn)); | |
276 | ||
079a182e JH |
277 | /* void (*) (gcov_type *, gcov_type) */ |
278 | average_profiler_fn_type | |
279 | = build_function_type_list (void_type_node, | |
280 | gcov_type_ptr, gcov_type_node, NULL_TREE); | |
281 | tree_average_profiler_fn | |
282 | = build_fn_decl ("__gcov_average_profiler", | |
283 | average_profiler_fn_type); | |
4d3814a5 RG |
284 | TREE_NOTHROW (tree_average_profiler_fn) = 1; |
285 | DECL_ATTRIBUTES (tree_average_profiler_fn) | |
286 | = tree_cons (get_identifier ("leaf"), NULL, | |
287 | DECL_ATTRIBUTES (tree_average_profiler_fn)); | |
079a182e JH |
288 | tree_ior_profiler_fn |
289 | = build_fn_decl ("__gcov_ior_profiler", | |
290 | average_profiler_fn_type); | |
4d3814a5 RG |
291 | TREE_NOTHROW (tree_ior_profiler_fn) = 1; |
292 | DECL_ATTRIBUTES (tree_ior_profiler_fn) | |
293 | = tree_cons (get_identifier ("leaf"), NULL, | |
294 | DECL_ATTRIBUTES (tree_ior_profiler_fn)); | |
295 | ||
0bc1b77f JH |
296 | /* LTO streamer needs assembler names. Because we create these decls |
297 | late, we need to initialize them by hand. */ | |
298 | DECL_ASSEMBLER_NAME (tree_interval_profiler_fn); | |
299 | DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn); | |
300 | DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn); | |
301 | DECL_ASSEMBLER_NAME (tree_indirect_call_profiler_fn); | |
86ce5d2f | 302 | DECL_ASSEMBLER_NAME (tree_time_profiler_fn); |
0bc1b77f JH |
303 | DECL_ASSEMBLER_NAME (tree_average_profiler_fn); |
304 | DECL_ASSEMBLER_NAME (tree_ior_profiler_fn); | |
9885da8e | 305 | } |
f3df9541 AK |
306 | } |
307 | ||
b8698a0f L |
308 | /* Output instructions as GIMPLE trees to increment the edge |
309 | execution count, and insert them on E. We rely on | |
726a989a | 310 | gsi_insert_on_edge to preserve the order. */ |
6de9cd9a | 311 | |
e0cb7e1e SB |
312 | void |
313 | gimple_gen_edge_profiler (int edgeno, edge e) | |
6de9cd9a | 314 | { |
83d5977e | 315 | tree ref, one, gcov_type_tmp_var; |
538dd0b7 | 316 | gassign *stmt1, *stmt2, *stmt3; |
9225443e | 317 | |
9225443e RG |
318 | ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); |
319 | one = build_int_cst (gcov_type_node, 1); | |
83d5977e RG |
320 | gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, |
321 | NULL, "PROF_edge_counter"); | |
726a989a | 322 | stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); |
83d5977e RG |
323 | gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, |
324 | NULL, "PROF_edge_counter"); | |
0d0e4a03 JJ |
325 | stmt2 = gimple_build_assign (gcov_type_tmp_var, PLUS_EXPR, |
326 | gimple_assign_lhs (stmt1), one); | |
4d3814a5 | 327 | stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2)); |
726a989a RB |
328 | gsi_insert_on_edge (e, stmt1); |
329 | gsi_insert_on_edge (e, stmt2); | |
330 | gsi_insert_on_edge (e, stmt3); | |
6de9cd9a DN |
331 | } |
332 | ||
726a989a | 333 | /* Emits code to get VALUE to instrument at GSI, and returns the |
9885da8e ZD |
334 | variable containing the value. */ |
335 | ||
336 | static tree | |
726a989a | 337 | prepare_instrumented_value (gimple_stmt_iterator *gsi, histogram_value value) |
9885da8e | 338 | { |
8a76829c | 339 | tree val = value->hvalue.value; |
ada39f0b | 340 | if (POINTER_TYPE_P (TREE_TYPE (val))) |
0d82a1c8 RG |
341 | val = fold_convert (build_nonstandard_integer_type |
342 | (TYPE_PRECISION (TREE_TYPE (val)), 1), val); | |
726a989a RB |
343 | return force_gimple_operand_gsi (gsi, fold_convert (gcov_type_node, val), |
344 | true, NULL_TREE, true, GSI_SAME_STMT); | |
9885da8e ZD |
345 | } |
346 | ||
b8698a0f L |
347 | /* Output instructions as GIMPLE trees to increment the interval histogram |
348 | counter. VALUE is the expression whose value is profiled. TAG is the | |
6de9cd9a DN |
349 | tag of the section for counters, BASE is offset of the counter position. */ |
350 | ||
e0cb7e1e SB |
351 | void |
352 | gimple_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) | |
6de9cd9a | 353 | { |
726a989a RB |
354 | gimple stmt = value->hvalue.stmt; |
355 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
9885da8e | 356 | tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; |
538dd0b7 | 357 | gcall *call; |
726a989a RB |
358 | tree val; |
359 | tree start = build_int_cst_type (integer_type_node, | |
360 | value->hdata.intvl.int_start); | |
361 | tree steps = build_int_cst_type (unsigned_type_node, | |
362 | value->hdata.intvl.steps); | |
b8698a0f | 363 | |
726a989a | 364 | ref_ptr = force_gimple_operand_gsi (&gsi, |
bde6c65d | 365 | build_addr (ref, current_function_decl), |
726a989a RB |
366 | true, NULL_TREE, true, GSI_SAME_STMT); |
367 | val = prepare_instrumented_value (&gsi, value); | |
368 | call = gimple_build_call (tree_interval_profiler_fn, 4, | |
369 | ref_ptr, val, start, steps); | |
71ba42fa | 370 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
6de9cd9a DN |
371 | } |
372 | ||
b8698a0f L |
373 | /* Output instructions as GIMPLE trees to increment the power of two histogram |
374 | counter. VALUE is the expression whose value is profiled. TAG is the tag | |
6de9cd9a DN |
375 | of the section for counters, BASE is offset of the counter position. */ |
376 | ||
e0cb7e1e SB |
377 | void |
378 | gimple_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base) | |
6de9cd9a | 379 | { |
726a989a RB |
380 | gimple stmt = value->hvalue.stmt; |
381 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
fc9161c1 | 382 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
538dd0b7 | 383 | gcall *call; |
726a989a | 384 | tree val; |
b8698a0f | 385 | |
726a989a RB |
386 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
387 | true, NULL_TREE, true, GSI_SAME_STMT); | |
388 | val = prepare_instrumented_value (&gsi, value); | |
389 | call = gimple_build_call (tree_pow2_profiler_fn, 2, ref_ptr, val); | |
71ba42fa | 390 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
6de9cd9a DN |
391 | } |
392 | ||
393 | /* Output instructions as GIMPLE trees for code to find the most common value. | |
394 | VALUE is the expression whose value is profiled. TAG is the tag of the | |
395 | section for counters, BASE is offset of the counter position. */ | |
396 | ||
e0cb7e1e SB |
397 | void |
398 | gimple_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base) | |
6de9cd9a | 399 | { |
726a989a RB |
400 | gimple stmt = value->hvalue.stmt; |
401 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
fc9161c1 | 402 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
538dd0b7 | 403 | gcall *call; |
726a989a | 404 | tree val; |
b8698a0f | 405 | |
726a989a RB |
406 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
407 | true, NULL_TREE, true, GSI_SAME_STMT); | |
408 | val = prepare_instrumented_value (&gsi, value); | |
409 | call = gimple_build_call (tree_one_value_profiler_fn, 2, ref_ptr, val); | |
71ba42fa | 410 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
6de9cd9a DN |
411 | } |
412 | ||
6bad2617 TB |
413 | |
414 | /* Output instructions as GIMPLE trees for code to find the most | |
b8698a0f | 415 | common called function in indirect call. |
88512ba0 | 416 | VALUE is the call expression whose indirect callee is profiled. |
6bad2617 TB |
417 | TAG is the tag of the section for counters, BASE is offset of the |
418 | counter position. */ | |
419 | ||
e0cb7e1e SB |
420 | void |
421 | gimple_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base) | |
6bad2617 | 422 | { |
726a989a | 423 | tree tmp1; |
538dd0b7 | 424 | gassign *stmt1, *stmt2, *stmt3; |
726a989a RB |
425 | gimple stmt = value->hvalue.stmt; |
426 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
fc9161c1 | 427 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
6bad2617 | 428 | |
0a750165 RX |
429 | if ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) && |
430 | tag == GCOV_COUNTER_V_INDIR) || | |
431 | (!PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) && | |
432 | tag == GCOV_COUNTER_ICALL_TOPNV)) | |
433 | return; | |
434 | ||
726a989a RB |
435 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
436 | true, NULL_TREE, true, GSI_SAME_STMT); | |
6bad2617 TB |
437 | |
438 | /* Insert code: | |
b8698a0f | 439 | |
9696c529 SB |
440 | stmt1: __gcov_indirect_call_counters = get_relevant_counter_ptr (); |
441 | stmt2: tmp1 = (void *) (indirect call argument value) | |
442 | stmt3: __gcov_indirect_call_callee = tmp1; | |
6bad2617 TB |
443 | */ |
444 | ||
726a989a | 445 | stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr); |
83d5977e | 446 | tmp1 = make_temp_ssa_name (ptr_void, NULL, "PROF"); |
726a989a | 447 | stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value)); |
4d3814a5 | 448 | stmt3 = gimple_build_assign (ic_void_ptr_var, gimple_assign_lhs (stmt2)); |
6bad2617 | 449 | |
726a989a RB |
450 | gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); |
451 | gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); | |
452 | gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT); | |
6bad2617 TB |
453 | } |
454 | ||
455 | ||
456 | /* Output instructions as GIMPLE trees for code to find the most | |
457 | common called function in indirect call. Insert instructions at the | |
88512ba0 | 458 | beginning of every possible called function. |
6bad2617 TB |
459 | */ |
460 | ||
e0cb7e1e SB |
461 | void |
462 | gimple_gen_ic_func_profiler (void) | |
6bad2617 | 463 | { |
d52f5295 | 464 | struct cgraph_node * c_node = cgraph_node::get (current_function_decl); |
726a989a | 465 | gimple_stmt_iterator gsi; |
538dd0b7 DM |
466 | gcall *stmt1; |
467 | gassign *stmt2; | |
2fa3d31b | 468 | tree tree_uid, cur_func, void0; |
6bad2617 | 469 | |
d52f5295 | 470 | if (c_node->only_called_directly_p ()) |
7e8b322a | 471 | return; |
b8698a0f | 472 | |
e0cb7e1e | 473 | gimple_init_edge_profiler (); |
b8698a0f | 474 | |
9696c529 SB |
475 | /* Insert code: |
476 | ||
2fa3d31b JH |
477 | stmt1: __gcov_indirect_call_profiler_v2 (profile_id, |
478 | ¤t_function_decl) | |
9696c529 | 479 | */ |
0a750165 | 480 | gsi = gsi_after_labels (split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)))); |
4d3814a5 RG |
481 | |
482 | cur_func = force_gimple_operand_gsi (&gsi, | |
483 | build_addr (current_function_decl, | |
484 | current_function_decl), | |
485 | true, NULL_TREE, | |
486 | true, GSI_SAME_STMT); | |
2fa3d31b | 487 | tree_uid = build_int_cst |
d52f5295 | 488 | (gcov_type_node, cgraph_node::get (current_function_decl)->profile_id); |
748d71f3 JH |
489 | /* Workaround for binutils bug 14342. Once it is fixed, remove lto path. */ |
490 | if (flag_lto) | |
491 | { | |
492 | tree counter_ptr, ptr_var; | |
493 | counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var, | |
494 | true, NULL_TREE, true, | |
495 | GSI_SAME_STMT); | |
496 | ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var, | |
497 | true, NULL_TREE, true, | |
498 | GSI_SAME_STMT); | |
499 | ||
500 | stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4, | |
501 | counter_ptr, tree_uid, cur_func, ptr_var); | |
502 | } | |
503 | else | |
504 | { | |
505 | stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 2, | |
506 | tree_uid, cur_func); | |
507 | } | |
4d3814a5 RG |
508 | gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); |
509 | ||
510 | /* Set __gcov_indirect_call_callee to 0, | |
511 | so that calls from other modules won't get misattributed | |
512 | to the last caller of the current callee. */ | |
513 | void0 = build_int_cst (build_pointer_type (void_type_node), 0); | |
514 | stmt2 = gimple_build_assign (ic_void_ptr_var, void0); | |
515 | gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); | |
6bad2617 TB |
516 | } |
517 | ||
86ce5d2f ML |
518 | /* Output instructions as GIMPLE tree at the beginning for each function. |
519 | TAG is the tag of the section for counters, BASE is offset of the | |
520 | counter position and GSI is the iterator we place the counter. */ | |
521 | ||
522 | void | |
523 | gimple_gen_time_profiler (unsigned tag, unsigned base, | |
524 | gimple_stmt_iterator &gsi) | |
525 | { | |
526 | tree ref_ptr = tree_coverage_counter_addr (tag, base); | |
538dd0b7 | 527 | gcall *call; |
86ce5d2f ML |
528 | |
529 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, | |
530 | true, NULL_TREE, true, GSI_SAME_STMT); | |
531 | call = gimple_build_call (tree_time_profiler_fn, 1, ref_ptr); | |
532 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); | |
533 | } | |
534 | ||
b8698a0f | 535 | /* Output instructions as GIMPLE trees for code to find the most common value |
6de9cd9a DN |
536 | of a difference between two evaluations of an expression. |
537 | VALUE is the expression whose value is profiled. TAG is the tag of the | |
538 | section for counters, BASE is offset of the counter position. */ | |
539 | ||
e0cb7e1e SB |
540 | void |
541 | gimple_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED, | |
726a989a RB |
542 | unsigned tag ATTRIBUTE_UNUSED, |
543 | unsigned base ATTRIBUTE_UNUSED) | |
6de9cd9a DN |
544 | { |
545 | /* FIXME implement this. */ | |
1e128c5f GB |
546 | #ifdef ENABLE_CHECKING |
547 | internal_error ("unimplemented functionality"); | |
548 | #endif | |
549 | gcc_unreachable (); | |
6de9cd9a DN |
550 | } |
551 | ||
b8698a0f L |
552 | /* Output instructions as GIMPLE trees to increment the average histogram |
553 | counter. VALUE is the expression whose value is profiled. TAG is the | |
079a182e JH |
554 | tag of the section for counters, BASE is offset of the counter position. */ |
555 | ||
e0cb7e1e SB |
556 | void |
557 | gimple_gen_average_profiler (histogram_value value, unsigned tag, unsigned base) | |
079a182e | 558 | { |
726a989a RB |
559 | gimple stmt = value->hvalue.stmt; |
560 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
fc9161c1 | 561 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
538dd0b7 | 562 | gcall *call; |
726a989a | 563 | tree val; |
b8698a0f | 564 | |
726a989a | 565 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
c6540bde | 566 | true, NULL_TREE, |
726a989a RB |
567 | true, GSI_SAME_STMT); |
568 | val = prepare_instrumented_value (&gsi, value); | |
569 | call = gimple_build_call (tree_average_profiler_fn, 2, ref_ptr, val); | |
71ba42fa | 570 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
079a182e JH |
571 | } |
572 | ||
b8698a0f L |
573 | /* Output instructions as GIMPLE trees to increment the ior histogram |
574 | counter. VALUE is the expression whose value is profiled. TAG is the | |
079a182e JH |
575 | tag of the section for counters, BASE is offset of the counter position. */ |
576 | ||
e0cb7e1e SB |
577 | void |
578 | gimple_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base) | |
079a182e | 579 | { |
726a989a RB |
580 | gimple stmt = value->hvalue.stmt; |
581 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | |
fc9161c1 | 582 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
538dd0b7 | 583 | gcall *call; |
726a989a | 584 | tree val; |
b8698a0f | 585 | |
726a989a RB |
586 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
587 | true, NULL_TREE, true, GSI_SAME_STMT); | |
588 | val = prepare_instrumented_value (&gsi, value); | |
589 | call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val); | |
71ba42fa | 590 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
079a182e JH |
591 | } |
592 | ||
4d3814a5 | 593 | /* Profile all functions in the callgraph. */ |
6de9cd9a | 594 | |
c2924966 | 595 | static unsigned int |
1f1e8527 DJ |
596 | tree_profiling (void) |
597 | { | |
4d3814a5 RG |
598 | struct cgraph_node *node; |
599 | ||
9696c529 SB |
600 | /* This is a small-ipa pass that gets called only once, from |
601 | cgraphunit.c:ipa_passes(). */ | |
3dafb85c | 602 | gcc_assert (symtab->state == IPA_SSA); |
9225443e | 603 | |
2fa3d31b | 604 | init_node_map (true); |
903d1e67 | 605 | |
65c70e6b | 606 | FOR_EACH_DEFINED_FUNCTION (node) |
4d3814a5 | 607 | { |
67348ccc | 608 | if (!gimple_has_body_p (node->decl)) |
4d3814a5 RG |
609 | continue; |
610 | ||
611 | /* Don't profile functions produced for builtin stuff. */ | |
67348ccc | 612 | if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) |
4d3814a5 RG |
613 | continue; |
614 | ||
07db0f9b JH |
615 | /* Do not instrument extern inline functions when testing coverage. |
616 | While this is not perfectly consistent (early inlined extern inlines | |
617 | will get acocunted), testsuite expects that. */ | |
618 | if (DECL_EXTERNAL (node->decl) | |
619 | && flag_test_coverage) | |
620 | continue; | |
621 | ||
67348ccc | 622 | push_cfun (DECL_STRUCT_FUNCTION (node->decl)); |
4d3814a5 | 623 | |
71fb4f92 | 624 | /* Local pure-const may imply need to fixup the cfg. */ |
49bdc0a6 RG |
625 | if (execute_fixup_cfg () & TODO_cleanup_cfg) |
626 | cleanup_tree_cfg (); | |
9696c529 | 627 | |
4d3814a5 RG |
628 | branch_prob (); |
629 | ||
630 | if (! flag_branch_probabilities | |
631 | && flag_profile_values) | |
e0cb7e1e | 632 | gimple_gen_ic_func_profiler (); |
4d3814a5 RG |
633 | |
634 | if (flag_branch_probabilities | |
635 | && flag_profile_values | |
636 | && flag_value_profile_transformations) | |
e0cb7e1e | 637 | gimple_value_profile_transformations (); |
4d3814a5 RG |
638 | |
639 | /* The above could hose dominator info. Currently there is | |
640 | none coming in, this is a safety valve. It should be | |
641 | easy to adjust it, if and when there is some. */ | |
642 | free_dominance_info (CDI_DOMINATORS); | |
643 | free_dominance_info (CDI_POST_DOMINATORS); | |
4d3814a5 RG |
644 | pop_cfun (); |
645 | } | |
646 | ||
647 | /* Drop pure/const flags from instrumented functions. */ | |
65c70e6b | 648 | FOR_EACH_DEFINED_FUNCTION (node) |
4d3814a5 | 649 | { |
67348ccc | 650 | if (!gimple_has_body_p (node->decl) |
960bfb69 | 651 | || !(!node->clone_of |
67348ccc | 652 | || node->decl != node->clone_of->decl)) |
4d3814a5 RG |
653 | continue; |
654 | ||
655 | /* Don't profile functions produced for builtin stuff. */ | |
67348ccc | 656 | if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) |
4d3814a5 RG |
657 | continue; |
658 | ||
d52f5295 ML |
659 | node->set_const_flag (false, false); |
660 | node->set_pure_flag (false, false); | |
4d3814a5 RG |
661 | } |
662 | ||
663 | /* Update call statements and rebuild the cgraph. */ | |
65c70e6b | 664 | FOR_EACH_DEFINED_FUNCTION (node) |
4d3814a5 RG |
665 | { |
666 | basic_block bb; | |
667 | ||
67348ccc | 668 | if (!gimple_has_body_p (node->decl) |
960bfb69 | 669 | || !(!node->clone_of |
67348ccc | 670 | || node->decl != node->clone_of->decl)) |
4d3814a5 RG |
671 | continue; |
672 | ||
673 | /* Don't profile functions produced for builtin stuff. */ | |
67348ccc | 674 | if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) |
4d3814a5 RG |
675 | continue; |
676 | ||
67348ccc | 677 | push_cfun (DECL_STRUCT_FUNCTION (node->decl)); |
4d3814a5 | 678 | |
11cd3bed | 679 | FOR_EACH_BB_FN (bb, cfun) |
4d3814a5 RG |
680 | { |
681 | gimple_stmt_iterator gsi; | |
682 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |
683 | { | |
684 | gimple stmt = gsi_stmt (gsi); | |
685 | if (is_gimple_call (stmt)) | |
686 | update_stmt (stmt); | |
687 | } | |
688 | } | |
689 | ||
a64bbb3f JH |
690 | /* re-merge split blocks. */ |
691 | cleanup_tree_cfg (); | |
4d3814a5 RG |
692 | update_ssa (TODO_update_ssa); |
693 | ||
3dafb85c | 694 | cgraph_edge::rebuild_edges (); |
4d3814a5 | 695 | |
4d3814a5 RG |
696 | pop_cfun (); |
697 | } | |
f7b4a383 | 698 | |
eb4b92c1 TJ |
699 | handle_missing_profiles (); |
700 | ||
c3284718 | 701 | del_node_map (); |
c2924966 | 702 | return 0; |
1f1e8527 DJ |
703 | } |
704 | ||
27a4cd48 DM |
705 | namespace { |
706 | ||
707 | const pass_data pass_data_ipa_tree_profile = | |
6de9cd9a | 708 | { |
27a4cd48 DM |
709 | SIMPLE_IPA_PASS, /* type */ |
710 | "profile", /* name */ | |
711 | OPTGROUP_NONE, /* optinfo_flags */ | |
27a4cd48 DM |
712 | TV_IPA_PROFILE, /* tv_id */ |
713 | 0, /* properties_required */ | |
714 | 0, /* properties_provided */ | |
715 | 0, /* properties_destroyed */ | |
716 | 0, /* todo_flags_start */ | |
717 | 0, /* todo_flags_finish */ | |
6de9cd9a DN |
718 | }; |
719 | ||
27a4cd48 DM |
720 | class pass_ipa_tree_profile : public simple_ipa_opt_pass |
721 | { | |
722 | public: | |
c3284718 RS |
723 | pass_ipa_tree_profile (gcc::context *ctxt) |
724 | : simple_ipa_opt_pass (pass_data_ipa_tree_profile, ctxt) | |
27a4cd48 DM |
725 | {} |
726 | ||
727 | /* opt_pass methods: */ | |
1a3d085c | 728 | virtual bool gate (function *); |
be55bfe6 | 729 | virtual unsigned int execute (function *) { return tree_profiling (); } |
27a4cd48 DM |
730 | |
731 | }; // class pass_ipa_tree_profile | |
732 | ||
1a3d085c TS |
733 | bool |
734 | pass_ipa_tree_profile::gate (function *) | |
735 | { | |
be3c16c4 DC |
736 | /* When profile instrumentation, use or test coverage shall be performed. |
737 | But for AutoFDO, this there is no instrumentation, thus this pass is | |
738 | diabled. */ | |
739 | return (!in_lto_p && !flag_auto_profile | |
1a3d085c TS |
740 | && (flag_branch_probabilities || flag_test_coverage |
741 | || profile_arc_flag)); | |
742 | } | |
743 | ||
27a4cd48 DM |
744 | } // anon namespace |
745 | ||
746 | simple_ipa_opt_pass * | |
747 | make_pass_ipa_tree_profile (gcc::context *ctxt) | |
748 | { | |
749 | return new pass_ipa_tree_profile (ctxt); | |
750 | } | |
751 | ||
9885da8e | 752 | #include "gt-tree-profile.h" |