]>
Commit | Line | Data |
---|---|---|
4ee9c684 | 1 | /* Calculate branch probabilities, and basic block execution counts. |
f1717362 | 2 | Copyright (C) 1990-2016 Free Software Foundation, Inc. |
4ee9c684 | 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 | |
8c4c00c1 | 12 | Software Foundation; either version 3, or (at your option) any later |
4ee9c684 | 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 | |
8c4c00c1 | 21 | along with GCC; see the file COPYING3. If not see |
22 | <http://www.gnu.org/licenses/>. */ | |
4ee9c684 | 23 | |
24 | /* Generate basic block profile instrumentation and auxiliary files. | |
d2971487 | 25 | Tree-based version. See profile.c for overview. */ |
4ee9c684 | 26 | |
27 | #include "config.h" | |
28 | #include "system.h" | |
29 | #include "coretypes.h" | |
9ef16211 | 30 | #include "backend.h" |
7c29e30e | 31 | #include "target.h" |
9ef16211 | 32 | #include "tree.h" |
33 | #include "gimple.h" | |
7c29e30e | 34 | #include "cfghooks.h" |
35 | #include "tree-pass.h" | |
9ef16211 | 36 | #include "ssa.h" |
7c29e30e | 37 | #include "cgraph.h" |
4ee9c684 | 38 | #include "coverage.h" |
7c29e30e | 39 | #include "diagnostic-core.h" |
b20a8bb4 | 40 | #include "fold-const.h" |
9ed99284 | 41 | #include "varasm.h" |
42 | #include "tree-nested.h" | |
a8783bee | 43 | #include "gimplify.h" |
dcf1a1ec | 44 | #include "gimple-iterator.h" |
e795d6e1 | 45 | #include "gimplify-me.h" |
073c1fd5 | 46 | #include "tree-cfg.h" |
073c1fd5 | 47 | #include "tree-into-ssa.h" |
4ee9c684 | 48 | #include "value-prof.h" |
1ad3e14c | 49 | #include "profile.h" |
424a4a92 | 50 | #include "tree-cfgcleanup.h" |
b74245ec | 51 | #include "params.h" |
4ee9c684 | 52 | |
d7683f13 | 53 | static GTY(()) tree gcov_type_node; |
54 | static GTY(()) tree tree_interval_profiler_fn; | |
55 | static GTY(()) tree tree_pow2_profiler_fn; | |
56 | static GTY(()) tree tree_one_value_profiler_fn; | |
167b550b | 57 | static GTY(()) tree tree_indirect_call_profiler_fn; |
38fe12e3 | 58 | static GTY(()) tree tree_time_profiler_fn; |
162719b3 | 59 | static GTY(()) tree tree_average_profiler_fn; |
60 | static GTY(()) tree tree_ior_profiler_fn; | |
38fe12e3 | 61 | |
4b0a9554 | 62 | |
167b550b | 63 | static GTY(()) tree ic_void_ptr_var; |
64 | static GTY(()) tree ic_gcov_type_ptr_var; | |
65 | static GTY(()) tree ptr_void; | |
66 | ||
4b0a9554 | 67 | /* Do initialization work for the edge profiler. */ |
68 | ||
167b550b | 69 | /* Add code: |
fe37be54 | 70 | __thread gcov* __gcov_indirect_call_counters; // pointer to actual counter |
38fe12e3 | 71 | __thread void* __gcov_indirect_call_callee; // actual callee address |
72 | __thread int __gcov_function_counter; // time profiler function counter | |
167b550b | 73 | */ |
74 | static void | |
fc49fbc1 | 75 | init_ic_make_global_vars (void) |
167b550b | 76 | { |
77 | tree gcov_type_ptr; | |
78 | ||
79 | ptr_void = build_pointer_type (void_type_node); | |
48e1416a | 80 | |
ca13b0e8 | 81 | ic_void_ptr_var |
82 | = build_decl (UNKNOWN_LOCATION, VAR_DECL, | |
83 | get_identifier ( | |
84 | (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ? | |
85 | "__gcov_indirect_call_topn_callee" : | |
86 | "__gcov_indirect_call_callee")), | |
87 | ptr_void); | |
88 | TREE_PUBLIC (ic_void_ptr_var) = 1; | |
89 | DECL_EXTERNAL (ic_void_ptr_var) = 1; | |
167b550b | 90 | TREE_STATIC (ic_void_ptr_var) = 1; |
167b550b | 91 | DECL_ARTIFICIAL (ic_void_ptr_var) = 1; |
92 | DECL_INITIAL (ic_void_ptr_var) = NULL; | |
109cfbe4 | 93 | if (targetm.have_tls) |
5e68df57 | 94 | set_decl_tls_model (ic_void_ptr_var, decl_default_tls_model (ic_void_ptr_var)); |
109cfbe4 | 95 | |
97221fd7 | 96 | varpool_node::finalize_decl (ic_void_ptr_var); |
167b550b | 97 | |
98 | gcov_type_ptr = build_pointer_type (get_gcov_type ()); | |
ca13b0e8 | 99 | |
100 | ic_gcov_type_ptr_var | |
101 | = build_decl (UNKNOWN_LOCATION, VAR_DECL, | |
102 | get_identifier ( | |
103 | (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ? | |
104 | "__gcov_indirect_call_topn_counters" : | |
105 | "__gcov_indirect_call_counters")), | |
106 | gcov_type_ptr); | |
107 | TREE_PUBLIC (ic_gcov_type_ptr_var) = 1; | |
108 | DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1; | |
167b550b | 109 | TREE_STATIC (ic_gcov_type_ptr_var) = 1; |
167b550b | 110 | DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1; |
111 | DECL_INITIAL (ic_gcov_type_ptr_var) = NULL; | |
109cfbe4 | 112 | if (targetm.have_tls) |
5e68df57 | 113 | set_decl_tls_model (ic_gcov_type_ptr_var, decl_default_tls_model (ic_gcov_type_ptr_var)); |
109cfbe4 | 114 | |
97221fd7 | 115 | varpool_node::finalize_decl (ic_gcov_type_ptr_var); |
167b550b | 116 | } |
117 | ||
3e7f455b | 118 | /* Create the type and function decls for the interface with gcov. */ |
119 | ||
fc49fbc1 | 120 | void |
121 | gimple_init_edge_profiler (void) | |
4b0a9554 | 122 | { |
d7683f13 | 123 | tree interval_profiler_fn_type; |
124 | tree pow2_profiler_fn_type; | |
125 | tree one_value_profiler_fn_type; | |
126 | tree gcov_type_ptr; | |
167b550b | 127 | tree ic_profiler_fn_type; |
162719b3 | 128 | tree average_profiler_fn_type; |
38fe12e3 | 129 | tree time_profiler_fn_type; |
d7683f13 | 130 | |
131 | if (!gcov_type_node) | |
132 | { | |
133 | gcov_type_node = get_gcov_type (); | |
134 | gcov_type_ptr = build_pointer_type (gcov_type_node); | |
135 | ||
136 | /* void (*) (gcov_type *, gcov_type, int, unsigned) */ | |
137 | interval_profiler_fn_type | |
138 | = build_function_type_list (void_type_node, | |
139 | gcov_type_ptr, gcov_type_node, | |
140 | integer_type_node, | |
141 | unsigned_type_node, NULL_TREE); | |
142 | tree_interval_profiler_fn | |
143 | = build_fn_decl ("__gcov_interval_profiler", | |
144 | interval_profiler_fn_type); | |
85344eeb | 145 | TREE_NOTHROW (tree_interval_profiler_fn) = 1; |
146 | DECL_ATTRIBUTES (tree_interval_profiler_fn) | |
147 | = tree_cons (get_identifier ("leaf"), NULL, | |
148 | DECL_ATTRIBUTES (tree_interval_profiler_fn)); | |
d7683f13 | 149 | |
150 | /* void (*) (gcov_type *, gcov_type) */ | |
151 | pow2_profiler_fn_type | |
152 | = build_function_type_list (void_type_node, | |
153 | gcov_type_ptr, gcov_type_node, | |
154 | NULL_TREE); | |
155 | tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler", | |
156 | pow2_profiler_fn_type); | |
85344eeb | 157 | TREE_NOTHROW (tree_pow2_profiler_fn) = 1; |
158 | DECL_ATTRIBUTES (tree_pow2_profiler_fn) | |
159 | = tree_cons (get_identifier ("leaf"), NULL, | |
160 | DECL_ATTRIBUTES (tree_pow2_profiler_fn)); | |
d7683f13 | 161 | |
162 | /* void (*) (gcov_type *, gcov_type) */ | |
163 | one_value_profiler_fn_type | |
164 | = build_function_type_list (void_type_node, | |
165 | gcov_type_ptr, gcov_type_node, | |
166 | NULL_TREE); | |
167 | tree_one_value_profiler_fn | |
168 | = build_fn_decl ("__gcov_one_value_profiler", | |
169 | one_value_profiler_fn_type); | |
85344eeb | 170 | TREE_NOTHROW (tree_one_value_profiler_fn) = 1; |
171 | DECL_ATTRIBUTES (tree_one_value_profiler_fn) | |
172 | = tree_cons (get_identifier ("leaf"), NULL, | |
173 | DECL_ATTRIBUTES (tree_one_value_profiler_fn)); | |
167b550b | 174 | |
fc49fbc1 | 175 | init_ic_make_global_vars (); |
48e1416a | 176 | |
ca13b0e8 | 177 | /* void (*) (gcov_type, void *) */ |
178 | ic_profiler_fn_type | |
179 | = build_function_type_list (void_type_node, | |
180 | gcov_type_node, | |
181 | ptr_void, | |
182 | NULL_TREE); | |
183 | tree_indirect_call_profiler_fn | |
184 | = build_fn_decl ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ? | |
185 | "__gcov_indirect_call_topn_profiler": | |
186 | "__gcov_indirect_call_profiler_v2"), | |
187 | ic_profiler_fn_type); | |
188 | ||
85344eeb | 189 | TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1; |
190 | DECL_ATTRIBUTES (tree_indirect_call_profiler_fn) | |
191 | = tree_cons (get_identifier ("leaf"), NULL, | |
192 | DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)); | |
193 | ||
38fe12e3 | 194 | /* void (*) (gcov_type *, gcov_type, void *) */ |
195 | time_profiler_fn_type | |
196 | = build_function_type_list (void_type_node, | |
197 | gcov_type_ptr, NULL_TREE); | |
198 | tree_time_profiler_fn | |
199 | = build_fn_decl ("__gcov_time_profiler", | |
200 | time_profiler_fn_type); | |
201 | TREE_NOTHROW (tree_time_profiler_fn) = 1; | |
202 | DECL_ATTRIBUTES (tree_time_profiler_fn) | |
203 | = tree_cons (get_identifier ("leaf"), NULL, | |
204 | DECL_ATTRIBUTES (tree_time_profiler_fn)); | |
205 | ||
162719b3 | 206 | /* void (*) (gcov_type *, gcov_type) */ |
207 | average_profiler_fn_type | |
208 | = build_function_type_list (void_type_node, | |
209 | gcov_type_ptr, gcov_type_node, NULL_TREE); | |
210 | tree_average_profiler_fn | |
211 | = build_fn_decl ("__gcov_average_profiler", | |
212 | average_profiler_fn_type); | |
85344eeb | 213 | TREE_NOTHROW (tree_average_profiler_fn) = 1; |
214 | DECL_ATTRIBUTES (tree_average_profiler_fn) | |
215 | = tree_cons (get_identifier ("leaf"), NULL, | |
216 | DECL_ATTRIBUTES (tree_average_profiler_fn)); | |
162719b3 | 217 | tree_ior_profiler_fn |
218 | = build_fn_decl ("__gcov_ior_profiler", | |
219 | average_profiler_fn_type); | |
85344eeb | 220 | TREE_NOTHROW (tree_ior_profiler_fn) = 1; |
221 | DECL_ATTRIBUTES (tree_ior_profiler_fn) | |
222 | = tree_cons (get_identifier ("leaf"), NULL, | |
223 | DECL_ATTRIBUTES (tree_ior_profiler_fn)); | |
224 | ||
6c0782b1 | 225 | /* LTO streamer needs assembler names. Because we create these decls |
226 | late, we need to initialize them by hand. */ | |
227 | DECL_ASSEMBLER_NAME (tree_interval_profiler_fn); | |
228 | DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn); | |
229 | DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn); | |
230 | DECL_ASSEMBLER_NAME (tree_indirect_call_profiler_fn); | |
38fe12e3 | 231 | DECL_ASSEMBLER_NAME (tree_time_profiler_fn); |
6c0782b1 | 232 | DECL_ASSEMBLER_NAME (tree_average_profiler_fn); |
233 | DECL_ASSEMBLER_NAME (tree_ior_profiler_fn); | |
d7683f13 | 234 | } |
4b0a9554 | 235 | } |
236 | ||
48e1416a | 237 | /* Output instructions as GIMPLE trees to increment the edge |
238 | execution count, and insert them on E. We rely on | |
75a70cf9 | 239 | gsi_insert_on_edge to preserve the order. */ |
4ee9c684 | 240 | |
fc49fbc1 | 241 | void |
242 | gimple_gen_edge_profiler (int edgeno, edge e) | |
4ee9c684 | 243 | { |
03d37e4e | 244 | tree ref, one, gcov_type_tmp_var; |
1a91d914 | 245 | gassign *stmt1, *stmt2, *stmt3; |
f81207a7 | 246 | |
f81207a7 | 247 | ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); |
248 | one = build_int_cst (gcov_type_node, 1); | |
03d37e4e | 249 | gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, |
250 | NULL, "PROF_edge_counter"); | |
75a70cf9 | 251 | stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); |
03d37e4e | 252 | gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, |
253 | NULL, "PROF_edge_counter"); | |
e9cf809e | 254 | stmt2 = gimple_build_assign (gcov_type_tmp_var, PLUS_EXPR, |
255 | gimple_assign_lhs (stmt1), one); | |
85344eeb | 256 | stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2)); |
75a70cf9 | 257 | gsi_insert_on_edge (e, stmt1); |
258 | gsi_insert_on_edge (e, stmt2); | |
259 | gsi_insert_on_edge (e, stmt3); | |
4ee9c684 | 260 | } |
261 | ||
75a70cf9 | 262 | /* Emits code to get VALUE to instrument at GSI, and returns the |
d7683f13 | 263 | variable containing the value. */ |
264 | ||
265 | static tree | |
75a70cf9 | 266 | prepare_instrumented_value (gimple_stmt_iterator *gsi, histogram_value value) |
d7683f13 | 267 | { |
ed4294da | 268 | tree val = value->hvalue.value; |
c821ef7d | 269 | if (POINTER_TYPE_P (TREE_TYPE (val))) |
a0553bff | 270 | val = fold_convert (build_nonstandard_integer_type |
271 | (TYPE_PRECISION (TREE_TYPE (val)), 1), val); | |
75a70cf9 | 272 | return force_gimple_operand_gsi (gsi, fold_convert (gcov_type_node, val), |
273 | true, NULL_TREE, true, GSI_SAME_STMT); | |
d7683f13 | 274 | } |
275 | ||
48e1416a | 276 | /* Output instructions as GIMPLE trees to increment the interval histogram |
277 | counter. VALUE is the expression whose value is profiled. TAG is the | |
4ee9c684 | 278 | tag of the section for counters, BASE is offset of the counter position. */ |
279 | ||
fc49fbc1 | 280 | void |
281 | gimple_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) | |
4ee9c684 | 282 | { |
42acab1c | 283 | gimple *stmt = value->hvalue.stmt; |
75a70cf9 | 284 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
d7683f13 | 285 | tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; |
1a91d914 | 286 | gcall *call; |
75a70cf9 | 287 | tree val; |
288 | tree start = build_int_cst_type (integer_type_node, | |
289 | value->hdata.intvl.int_start); | |
290 | tree steps = build_int_cst_type (unsigned_type_node, | |
291 | value->hdata.intvl.steps); | |
48e1416a | 292 | |
75a70cf9 | 293 | ref_ptr = force_gimple_operand_gsi (&gsi, |
0e49e441 | 294 | build_addr (ref), |
75a70cf9 | 295 | true, NULL_TREE, true, GSI_SAME_STMT); |
296 | val = prepare_instrumented_value (&gsi, value); | |
297 | call = gimple_build_call (tree_interval_profiler_fn, 4, | |
298 | ref_ptr, val, start, steps); | |
77fca8b5 | 299 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
4ee9c684 | 300 | } |
301 | ||
48e1416a | 302 | /* Output instructions as GIMPLE trees to increment the power of two histogram |
303 | counter. VALUE is the expression whose value is profiled. TAG is the tag | |
4ee9c684 | 304 | of the section for counters, BASE is offset of the counter position. */ |
305 | ||
fc49fbc1 | 306 | void |
307 | gimple_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base) | |
4ee9c684 | 308 | { |
42acab1c | 309 | gimple *stmt = value->hvalue.stmt; |
75a70cf9 | 310 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
a961cdc2 | 311 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
1a91d914 | 312 | gcall *call; |
75a70cf9 | 313 | tree val; |
48e1416a | 314 | |
75a70cf9 | 315 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
316 | true, NULL_TREE, true, GSI_SAME_STMT); | |
317 | val = prepare_instrumented_value (&gsi, value); | |
318 | call = gimple_build_call (tree_pow2_profiler_fn, 2, ref_ptr, val); | |
77fca8b5 | 319 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
4ee9c684 | 320 | } |
321 | ||
322 | /* Output instructions as GIMPLE trees for code to find the most common value. | |
323 | VALUE is the expression whose value is profiled. TAG is the tag of the | |
324 | section for counters, BASE is offset of the counter position. */ | |
325 | ||
fc49fbc1 | 326 | void |
327 | gimple_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base) | |
4ee9c684 | 328 | { |
42acab1c | 329 | gimple *stmt = value->hvalue.stmt; |
75a70cf9 | 330 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
a961cdc2 | 331 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
1a91d914 | 332 | gcall *call; |
75a70cf9 | 333 | tree val; |
48e1416a | 334 | |
75a70cf9 | 335 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
336 | true, NULL_TREE, true, GSI_SAME_STMT); | |
337 | val = prepare_instrumented_value (&gsi, value); | |
338 | call = gimple_build_call (tree_one_value_profiler_fn, 2, ref_ptr, val); | |
77fca8b5 | 339 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
4ee9c684 | 340 | } |
341 | ||
167b550b | 342 | |
343 | /* Output instructions as GIMPLE trees for code to find the most | |
48e1416a | 344 | common called function in indirect call. |
0d424440 | 345 | VALUE is the call expression whose indirect callee is profiled. |
167b550b | 346 | TAG is the tag of the section for counters, BASE is offset of the |
347 | counter position. */ | |
348 | ||
fc49fbc1 | 349 | void |
350 | gimple_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base) | |
167b550b | 351 | { |
75a70cf9 | 352 | tree tmp1; |
1a91d914 | 353 | gassign *stmt1, *stmt2, *stmt3; |
42acab1c | 354 | gimple *stmt = value->hvalue.stmt; |
75a70cf9 | 355 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
a961cdc2 | 356 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
167b550b | 357 | |
b74245ec | 358 | if ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) && |
359 | tag == GCOV_COUNTER_V_INDIR) || | |
360 | (!PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) && | |
361 | tag == GCOV_COUNTER_ICALL_TOPNV)) | |
362 | return; | |
363 | ||
75a70cf9 | 364 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
365 | true, NULL_TREE, true, GSI_SAME_STMT); | |
167b550b | 366 | |
367 | /* Insert code: | |
48e1416a | 368 | |
3e7f455b | 369 | stmt1: __gcov_indirect_call_counters = get_relevant_counter_ptr (); |
370 | stmt2: tmp1 = (void *) (indirect call argument value) | |
371 | stmt3: __gcov_indirect_call_callee = tmp1; | |
167b550b | 372 | */ |
373 | ||
75a70cf9 | 374 | stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr); |
03d37e4e | 375 | tmp1 = make_temp_ssa_name (ptr_void, NULL, "PROF"); |
75a70cf9 | 376 | stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value)); |
85344eeb | 377 | stmt3 = gimple_build_assign (ic_void_ptr_var, gimple_assign_lhs (stmt2)); |
167b550b | 378 | |
75a70cf9 | 379 | gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); |
380 | gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); | |
381 | gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT); | |
167b550b | 382 | } |
383 | ||
384 | ||
385 | /* Output instructions as GIMPLE trees for code to find the most | |
386 | common called function in indirect call. Insert instructions at the | |
0d424440 | 387 | beginning of every possible called function. |
167b550b | 388 | */ |
389 | ||
fc49fbc1 | 390 | void |
391 | gimple_gen_ic_func_profiler (void) | |
167b550b | 392 | { |
415d1b9a | 393 | struct cgraph_node * c_node = cgraph_node::get (current_function_decl); |
75a70cf9 | 394 | gimple_stmt_iterator gsi; |
1a91d914 | 395 | gcall *stmt1; |
396 | gassign *stmt2; | |
fe37be54 | 397 | tree tree_uid, cur_func, void0; |
167b550b | 398 | |
415d1b9a | 399 | if (c_node->only_called_directly_p ()) |
6329636b | 400 | return; |
48e1416a | 401 | |
fc49fbc1 | 402 | gimple_init_edge_profiler (); |
48e1416a | 403 | |
3e7f455b | 404 | /* Insert code: |
405 | ||
fe37be54 | 406 | stmt1: __gcov_indirect_call_profiler_v2 (profile_id, |
407 | ¤t_function_decl) | |
3e7f455b | 408 | */ |
ca13b0e8 | 409 | gsi = gsi_after_labels (split_edge (single_succ_edge |
410 | (ENTRY_BLOCK_PTR_FOR_FN (cfun)))); | |
85344eeb | 411 | |
412 | cur_func = force_gimple_operand_gsi (&gsi, | |
0e49e441 | 413 | build_addr (current_function_decl), |
85344eeb | 414 | true, NULL_TREE, |
415 | true, GSI_SAME_STMT); | |
fe37be54 | 416 | tree_uid = build_int_cst |
ca13b0e8 | 417 | (gcov_type_node, |
418 | cgraph_node::get (current_function_decl)->profile_id); | |
419 | stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 2, | |
420 | tree_uid, cur_func); | |
85344eeb | 421 | gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); |
422 | ||
423 | /* Set __gcov_indirect_call_callee to 0, | |
424 | so that calls from other modules won't get misattributed | |
425 | to the last caller of the current callee. */ | |
426 | void0 = build_int_cst (build_pointer_type (void_type_node), 0); | |
427 | stmt2 = gimple_build_assign (ic_void_ptr_var, void0); | |
428 | gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); | |
167b550b | 429 | } |
430 | ||
38fe12e3 | 431 | /* Output instructions as GIMPLE tree at the beginning for each function. |
432 | TAG is the tag of the section for counters, BASE is offset of the | |
433 | counter position and GSI is the iterator we place the counter. */ | |
434 | ||
435 | void | |
436 | gimple_gen_time_profiler (unsigned tag, unsigned base, | |
437 | gimple_stmt_iterator &gsi) | |
438 | { | |
439 | tree ref_ptr = tree_coverage_counter_addr (tag, base); | |
1a91d914 | 440 | gcall *call; |
38fe12e3 | 441 | |
442 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, | |
443 | true, NULL_TREE, true, GSI_SAME_STMT); | |
444 | call = gimple_build_call (tree_time_profiler_fn, 1, ref_ptr); | |
445 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); | |
446 | } | |
447 | ||
48e1416a | 448 | /* Output instructions as GIMPLE trees for code to find the most common value |
4ee9c684 | 449 | of a difference between two evaluations of an expression. |
450 | VALUE is the expression whose value is profiled. TAG is the tag of the | |
451 | section for counters, BASE is offset of the counter position. */ | |
452 | ||
fc49fbc1 | 453 | void |
454 | gimple_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED, | |
75a70cf9 | 455 | unsigned tag ATTRIBUTE_UNUSED, |
456 | unsigned base ATTRIBUTE_UNUSED) | |
4ee9c684 | 457 | { |
458 | /* FIXME implement this. */ | |
382ecba7 | 459 | if (flag_checking) |
460 | internal_error ("unimplemented functionality"); | |
8c0963c4 | 461 | gcc_unreachable (); |
4ee9c684 | 462 | } |
463 | ||
48e1416a | 464 | /* Output instructions as GIMPLE trees to increment the average histogram |
465 | counter. VALUE is the expression whose value is profiled. TAG is the | |
162719b3 | 466 | tag of the section for counters, BASE is offset of the counter position. */ |
467 | ||
fc49fbc1 | 468 | void |
469 | gimple_gen_average_profiler (histogram_value value, unsigned tag, unsigned base) | |
162719b3 | 470 | { |
42acab1c | 471 | gimple *stmt = value->hvalue.stmt; |
75a70cf9 | 472 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
a961cdc2 | 473 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
1a91d914 | 474 | gcall *call; |
75a70cf9 | 475 | tree val; |
48e1416a | 476 | |
75a70cf9 | 477 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
0d734975 | 478 | true, NULL_TREE, |
75a70cf9 | 479 | true, GSI_SAME_STMT); |
480 | val = prepare_instrumented_value (&gsi, value); | |
481 | call = gimple_build_call (tree_average_profiler_fn, 2, ref_ptr, val); | |
77fca8b5 | 482 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
162719b3 | 483 | } |
484 | ||
48e1416a | 485 | /* Output instructions as GIMPLE trees to increment the ior histogram |
486 | counter. VALUE is the expression whose value is profiled. TAG is the | |
162719b3 | 487 | tag of the section for counters, BASE is offset of the counter position. */ |
488 | ||
fc49fbc1 | 489 | void |
490 | gimple_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base) | |
162719b3 | 491 | { |
42acab1c | 492 | gimple *stmt = value->hvalue.stmt; |
75a70cf9 | 493 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
a961cdc2 | 494 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
1a91d914 | 495 | gcall *call; |
75a70cf9 | 496 | tree val; |
48e1416a | 497 | |
75a70cf9 | 498 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
499 | true, NULL_TREE, true, GSI_SAME_STMT); | |
500 | val = prepare_instrumented_value (&gsi, value); | |
501 | call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val); | |
77fca8b5 | 502 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
162719b3 | 503 | } |
504 | ||
85344eeb | 505 | /* Profile all functions in the callgraph. */ |
4ee9c684 | 506 | |
2a1990e9 | 507 | static unsigned int |
d2971487 | 508 | tree_profiling (void) |
509 | { | |
85344eeb | 510 | struct cgraph_node *node; |
511 | ||
3e7f455b | 512 | /* This is a small-ipa pass that gets called only once, from |
513 | cgraphunit.c:ipa_passes(). */ | |
35ee1c66 | 514 | gcc_assert (symtab->state == IPA_SSA); |
f81207a7 | 515 | |
fe37be54 | 516 | init_node_map (true); |
1ad3e14c | 517 | |
7c455d87 | 518 | FOR_EACH_DEFINED_FUNCTION (node) |
85344eeb | 519 | { |
02774f2d | 520 | if (!gimple_has_body_p (node->decl)) |
85344eeb | 521 | continue; |
522 | ||
523 | /* Don't profile functions produced for builtin stuff. */ | |
02774f2d | 524 | if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) |
85344eeb | 525 | continue; |
526 | ||
1a382068 | 527 | /* Do not instrument extern inline functions when testing coverage. |
528 | While this is not perfectly consistent (early inlined extern inlines | |
529 | will get acocunted), testsuite expects that. */ | |
530 | if (DECL_EXTERNAL (node->decl) | |
531 | && flag_test_coverage) | |
532 | continue; | |
533 | ||
02774f2d | 534 | push_cfun (DECL_STRUCT_FUNCTION (node->decl)); |
85344eeb | 535 | |
8c1fce46 | 536 | /* Local pure-const may imply need to fixup the cfg. */ |
141de90e | 537 | if (execute_fixup_cfg () & TODO_cleanup_cfg) |
538 | cleanup_tree_cfg (); | |
3e7f455b | 539 | |
85344eeb | 540 | branch_prob (); |
541 | ||
542 | if (! flag_branch_probabilities | |
543 | && flag_profile_values) | |
fc49fbc1 | 544 | gimple_gen_ic_func_profiler (); |
85344eeb | 545 | |
546 | if (flag_branch_probabilities | |
547 | && flag_profile_values | |
548 | && flag_value_profile_transformations) | |
fc49fbc1 | 549 | gimple_value_profile_transformations (); |
85344eeb | 550 | |
551 | /* The above could hose dominator info. Currently there is | |
552 | none coming in, this is a safety valve. It should be | |
553 | easy to adjust it, if and when there is some. */ | |
554 | free_dominance_info (CDI_DOMINATORS); | |
555 | free_dominance_info (CDI_POST_DOMINATORS); | |
85344eeb | 556 | pop_cfun (); |
557 | } | |
558 | ||
559 | /* Drop pure/const flags from instrumented functions. */ | |
1059fe86 | 560 | if (profile_arc_flag || flag_test_coverage) |
561 | FOR_EACH_DEFINED_FUNCTION (node) | |
562 | { | |
563 | if (!gimple_has_body_p (node->decl) | |
564 | || !(!node->clone_of | |
565 | || node->decl != node->clone_of->decl)) | |
566 | continue; | |
567 | ||
568 | /* Don't profile functions produced for builtin stuff. */ | |
569 | if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) | |
570 | continue; | |
571 | ||
572 | node->set_const_flag (false, false); | |
573 | node->set_pure_flag (false, false); | |
574 | } | |
85344eeb | 575 | |
576 | /* Update call statements and rebuild the cgraph. */ | |
7c455d87 | 577 | FOR_EACH_DEFINED_FUNCTION (node) |
85344eeb | 578 | { |
579 | basic_block bb; | |
580 | ||
02774f2d | 581 | if (!gimple_has_body_p (node->decl) |
7d0d0ce1 | 582 | || !(!node->clone_of |
02774f2d | 583 | || node->decl != node->clone_of->decl)) |
85344eeb | 584 | continue; |
585 | ||
586 | /* Don't profile functions produced for builtin stuff. */ | |
02774f2d | 587 | if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) |
85344eeb | 588 | continue; |
589 | ||
02774f2d | 590 | push_cfun (DECL_STRUCT_FUNCTION (node->decl)); |
85344eeb | 591 | |
fc00614f | 592 | FOR_EACH_BB_FN (bb, cfun) |
85344eeb | 593 | { |
594 | gimple_stmt_iterator gsi; | |
595 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |
596 | { | |
42acab1c | 597 | gimple *stmt = gsi_stmt (gsi); |
85344eeb | 598 | if (is_gimple_call (stmt)) |
599 | update_stmt (stmt); | |
600 | } | |
601 | } | |
602 | ||
2701a3fd | 603 | /* re-merge split blocks. */ |
604 | cleanup_tree_cfg (); | |
85344eeb | 605 | update_ssa (TODO_update_ssa); |
606 | ||
35ee1c66 | 607 | cgraph_edge::rebuild_edges (); |
85344eeb | 608 | |
85344eeb | 609 | pop_cfun (); |
610 | } | |
fdc47e9a | 611 | |
38a65d4e | 612 | handle_missing_profiles (); |
613 | ||
9af5ce0c | 614 | del_node_map (); |
2a1990e9 | 615 | return 0; |
d2971487 | 616 | } |
617 | ||
cbe8bda8 | 618 | namespace { |
619 | ||
620 | const pass_data pass_data_ipa_tree_profile = | |
4ee9c684 | 621 | { |
cbe8bda8 | 622 | SIMPLE_IPA_PASS, /* type */ |
623 | "profile", /* name */ | |
624 | OPTGROUP_NONE, /* optinfo_flags */ | |
cbe8bda8 | 625 | TV_IPA_PROFILE, /* tv_id */ |
626 | 0, /* properties_required */ | |
627 | 0, /* properties_provided */ | |
628 | 0, /* properties_destroyed */ | |
629 | 0, /* todo_flags_start */ | |
1059fe86 | 630 | TODO_dump_symtab, /* todo_flags_finish */ |
4ee9c684 | 631 | }; |
632 | ||
cbe8bda8 | 633 | class pass_ipa_tree_profile : public simple_ipa_opt_pass |
634 | { | |
635 | public: | |
9af5ce0c | 636 | pass_ipa_tree_profile (gcc::context *ctxt) |
637 | : simple_ipa_opt_pass (pass_data_ipa_tree_profile, ctxt) | |
cbe8bda8 | 638 | {} |
639 | ||
640 | /* opt_pass methods: */ | |
31315c24 | 641 | virtual bool gate (function *); |
65b0537f | 642 | virtual unsigned int execute (function *) { return tree_profiling (); } |
cbe8bda8 | 643 | |
644 | }; // class pass_ipa_tree_profile | |
645 | ||
31315c24 | 646 | bool |
647 | pass_ipa_tree_profile::gate (function *) | |
648 | { | |
94bed7c3 | 649 | /* When profile instrumentation, use or test coverage shall be performed. |
650 | But for AutoFDO, this there is no instrumentation, thus this pass is | |
651 | diabled. */ | |
652 | return (!in_lto_p && !flag_auto_profile | |
31315c24 | 653 | && (flag_branch_probabilities || flag_test_coverage |
654 | || profile_arc_flag)); | |
655 | } | |
656 | ||
cbe8bda8 | 657 | } // anon namespace |
658 | ||
659 | simple_ipa_opt_pass * | |
660 | make_pass_ipa_tree_profile (gcc::context *ctxt) | |
661 | { | |
662 | return new pass_ipa_tree_profile (ctxt); | |
663 | } | |
664 | ||
d7683f13 | 665 | #include "gt-tree-profile.h" |