]>
Commit | Line | Data |
---|---|---|
6de9cd9a | 1 | /* Calculate branch probabilities, and basic block execution counts. |
85ec4feb | 2 | Copyright (C) 1990-2018 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" | |
4d0cdd0c | 30 | #include "memmodel.h" |
c7131fb2 | 31 | #include "backend.h" |
957060b5 | 32 | #include "target.h" |
c7131fb2 AM |
33 | #include "tree.h" |
34 | #include "gimple.h" | |
957060b5 AM |
35 | #include "cfghooks.h" |
36 | #include "tree-pass.h" | |
c7131fb2 | 37 | #include "ssa.h" |
957060b5 | 38 | #include "cgraph.h" |
6de9cd9a | 39 | #include "coverage.h" |
957060b5 | 40 | #include "diagnostic-core.h" |
40e23961 | 41 | #include "fold-const.h" |
d8a2d370 DN |
42 | #include "varasm.h" |
43 | #include "tree-nested.h" | |
45b0be94 | 44 | #include "gimplify.h" |
5be5c238 | 45 | #include "gimple-iterator.h" |
18f429e2 | 46 | #include "gimplify-me.h" |
442b4905 | 47 | #include "tree-cfg.h" |
442b4905 | 48 | #include "tree-into-ssa.h" |
6de9cd9a | 49 | #include "value-prof.h" |
903d1e67 | 50 | #include "profile.h" |
4484a35a | 51 | #include "tree-cfgcleanup.h" |
0a750165 | 52 | #include "params.h" |
314e6352 ML |
53 | #include "stringpool.h" |
54 | #include "attribs.h" | |
a53d4f20 | 55 | #include "tree-pretty-print.h" |
3edbcdbe ML |
56 | #include "langhooks.h" |
57 | #include "stor-layout.h" | |
6de9cd9a | 58 | |
9885da8e ZD |
59 | static GTY(()) tree gcov_type_node; |
60 | static GTY(()) tree tree_interval_profiler_fn; | |
61 | static GTY(()) tree tree_pow2_profiler_fn; | |
62 | static GTY(()) tree tree_one_value_profiler_fn; | |
6bad2617 | 63 | static GTY(()) tree tree_indirect_call_profiler_fn; |
079a182e JH |
64 | static GTY(()) tree tree_average_profiler_fn; |
65 | static GTY(()) tree tree_ior_profiler_fn; | |
7d29f8e3 | 66 | static GTY(()) tree tree_time_profiler_counter; |
86ce5d2f | 67 | |
f3df9541 | 68 | |
3edbcdbe ML |
69 | static GTY(()) tree ic_tuple_var; |
70 | static GTY(()) tree ic_tuple_counters_field; | |
71 | static GTY(()) tree ic_tuple_callee_field; | |
6bad2617 | 72 | |
f3df9541 AK |
73 | /* Do initialization work for the edge profiler. */ |
74 | ||
6bad2617 | 75 | /* Add code: |
2fa3d31b | 76 | __thread gcov* __gcov_indirect_call_counters; // pointer to actual counter |
86ce5d2f ML |
77 | __thread void* __gcov_indirect_call_callee; // actual callee address |
78 | __thread int __gcov_function_counter; // time profiler function counter | |
6bad2617 TB |
79 | */ |
80 | static void | |
e0cb7e1e | 81 | init_ic_make_global_vars (void) |
6bad2617 | 82 | { |
7d29f8e3 | 83 | tree gcov_type_ptr; |
6bad2617 | 84 | |
3edbcdbe | 85 | gcov_type_ptr = build_pointer_type (get_gcov_type ()); |
b8698a0f | 86 | |
3edbcdbe | 87 | tree tuple_type = lang_hooks.types.make_type (RECORD_TYPE); |
d984c8ef | 88 | |
3edbcdbe ML |
89 | /* callee */ |
90 | ic_tuple_callee_field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, | |
91 | ptr_type_node); | |
c02ae3ae | 92 | |
3edbcdbe ML |
93 | /* counters */ |
94 | ic_tuple_counters_field = build_decl (BUILTINS_LOCATION, FIELD_DECL, | |
95 | NULL_TREE, gcov_type_ptr); | |
96 | DECL_CHAIN (ic_tuple_counters_field) = ic_tuple_callee_field; | |
97 | ||
98 | finish_builtin_struct (tuple_type, "indirect_call_tuple", | |
99 | ic_tuple_counters_field, NULL_TREE); | |
100 | ||
101 | ic_tuple_var | |
c02ae3ae JH |
102 | = build_decl (UNKNOWN_LOCATION, VAR_DECL, |
103 | get_identifier ( | |
104 | (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ? | |
3edbcdbe ML |
105 | "__gcov_indirect_call_topn" : |
106 | "__gcov_indirect_call")), | |
107 | tuple_type); | |
108 | TREE_PUBLIC (ic_tuple_var) = 1; | |
109 | DECL_ARTIFICIAL (ic_tuple_var) = 1; | |
110 | DECL_INITIAL (ic_tuple_var) = NULL; | |
111 | DECL_EXTERNAL (ic_tuple_var) = 1; | |
d984c8ef | 112 | if (targetm.have_tls) |
3edbcdbe | 113 | set_decl_tls_model (ic_tuple_var, decl_default_tls_model (tuple_type)); |
6bad2617 TB |
114 | } |
115 | ||
9696c529 SB |
116 | /* Create the type and function decls for the interface with gcov. */ |
117 | ||
e0cb7e1e | 118 | void |
7d29f8e3 | 119 | gimple_init_gcov_profiler (void) |
f3df9541 | 120 | { |
9885da8e ZD |
121 | tree interval_profiler_fn_type; |
122 | tree pow2_profiler_fn_type; | |
123 | tree one_value_profiler_fn_type; | |
124 | tree gcov_type_ptr; | |
6bad2617 | 125 | tree ic_profiler_fn_type; |
079a182e | 126 | tree average_profiler_fn_type; |
22063dbc | 127 | const char *profiler_fn_name; |
a266236e | 128 | const char *fn_name; |
9885da8e ZD |
129 | |
130 | if (!gcov_type_node) | |
131 | { | |
a266236e ML |
132 | const char *fn_suffix |
133 | = flag_profile_update == PROFILE_UPDATE_ATOMIC ? "_atomic" : ""; | |
134 | ||
9885da8e ZD |
135 | gcov_type_node = get_gcov_type (); |
136 | gcov_type_ptr = build_pointer_type (gcov_type_node); | |
137 | ||
138 | /* void (*) (gcov_type *, gcov_type, int, unsigned) */ | |
139 | interval_profiler_fn_type | |
140 | = build_function_type_list (void_type_node, | |
141 | gcov_type_ptr, gcov_type_node, | |
142 | integer_type_node, | |
143 | unsigned_type_node, NULL_TREE); | |
a266236e ML |
144 | fn_name = concat ("__gcov_interval_profiler", fn_suffix, NULL); |
145 | tree_interval_profiler_fn = build_fn_decl (fn_name, | |
146 | interval_profiler_fn_type); | |
147 | free (CONST_CAST (char *, fn_name)); | |
4d3814a5 RG |
148 | TREE_NOTHROW (tree_interval_profiler_fn) = 1; |
149 | DECL_ATTRIBUTES (tree_interval_profiler_fn) | |
150 | = tree_cons (get_identifier ("leaf"), NULL, | |
151 | DECL_ATTRIBUTES (tree_interval_profiler_fn)); | |
9885da8e ZD |
152 | |
153 | /* void (*) (gcov_type *, gcov_type) */ | |
154 | pow2_profiler_fn_type | |
155 | = build_function_type_list (void_type_node, | |
156 | gcov_type_ptr, gcov_type_node, | |
157 | NULL_TREE); | |
a266236e ML |
158 | fn_name = concat ("__gcov_pow2_profiler", fn_suffix, NULL); |
159 | tree_pow2_profiler_fn = build_fn_decl (fn_name, pow2_profiler_fn_type); | |
160 | free (CONST_CAST (char *, fn_name)); | |
4d3814a5 RG |
161 | TREE_NOTHROW (tree_pow2_profiler_fn) = 1; |
162 | DECL_ATTRIBUTES (tree_pow2_profiler_fn) | |
163 | = tree_cons (get_identifier ("leaf"), NULL, | |
164 | DECL_ATTRIBUTES (tree_pow2_profiler_fn)); | |
9885da8e ZD |
165 | |
166 | /* void (*) (gcov_type *, gcov_type) */ | |
167 | one_value_profiler_fn_type | |
168 | = build_function_type_list (void_type_node, | |
169 | gcov_type_ptr, gcov_type_node, | |
170 | NULL_TREE); | |
a266236e ML |
171 | fn_name = concat ("__gcov_one_value_profiler", fn_suffix, NULL); |
172 | tree_one_value_profiler_fn = build_fn_decl (fn_name, | |
173 | one_value_profiler_fn_type); | |
174 | free (CONST_CAST (char *, fn_name)); | |
4d3814a5 RG |
175 | TREE_NOTHROW (tree_one_value_profiler_fn) = 1; |
176 | DECL_ATTRIBUTES (tree_one_value_profiler_fn) | |
177 | = tree_cons (get_identifier ("leaf"), NULL, | |
178 | DECL_ATTRIBUTES (tree_one_value_profiler_fn)); | |
6bad2617 | 179 | |
e0cb7e1e | 180 | init_ic_make_global_vars (); |
b8698a0f | 181 | |
c02ae3ae JH |
182 | /* void (*) (gcov_type, void *) */ |
183 | ic_profiler_fn_type | |
184 | = build_function_type_list (void_type_node, | |
185 | gcov_type_node, | |
3edbcdbe | 186 | ptr_type_node, |
c02ae3ae | 187 | NULL_TREE); |
22063dbc ML |
188 | profiler_fn_name = "__gcov_indirect_call_profiler_v2"; |
189 | if (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE)) | |
190 | profiler_fn_name = "__gcov_indirect_call_topn_profiler"; | |
191 | ||
c02ae3ae | 192 | tree_indirect_call_profiler_fn |
22063dbc | 193 | = build_fn_decl (profiler_fn_name, ic_profiler_fn_type); |
c02ae3ae | 194 | |
4d3814a5 RG |
195 | TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1; |
196 | DECL_ATTRIBUTES (tree_indirect_call_profiler_fn) | |
197 | = tree_cons (get_identifier ("leaf"), NULL, | |
198 | DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)); | |
199 | ||
7d29f8e3 ML |
200 | tree_time_profiler_counter |
201 | = build_decl (UNKNOWN_LOCATION, VAR_DECL, | |
202 | get_identifier ("__gcov_time_profiler_counter"), | |
203 | get_gcov_type ()); | |
204 | TREE_PUBLIC (tree_time_profiler_counter) = 1; | |
205 | DECL_EXTERNAL (tree_time_profiler_counter) = 1; | |
206 | TREE_STATIC (tree_time_profiler_counter) = 1; | |
207 | DECL_ARTIFICIAL (tree_time_profiler_counter) = 1; | |
208 | DECL_INITIAL (tree_time_profiler_counter) = NULL; | |
209 | ||
079a182e JH |
210 | /* void (*) (gcov_type *, gcov_type) */ |
211 | average_profiler_fn_type | |
212 | = build_function_type_list (void_type_node, | |
213 | gcov_type_ptr, gcov_type_node, NULL_TREE); | |
a266236e ML |
214 | fn_name = concat ("__gcov_average_profiler", fn_suffix, NULL); |
215 | tree_average_profiler_fn = build_fn_decl (fn_name, | |
216 | average_profiler_fn_type); | |
217 | free (CONST_CAST (char *, fn_name)); | |
4d3814a5 RG |
218 | TREE_NOTHROW (tree_average_profiler_fn) = 1; |
219 | DECL_ATTRIBUTES (tree_average_profiler_fn) | |
220 | = tree_cons (get_identifier ("leaf"), NULL, | |
221 | DECL_ATTRIBUTES (tree_average_profiler_fn)); | |
a266236e ML |
222 | fn_name = concat ("__gcov_ior_profiler", fn_suffix, NULL); |
223 | tree_ior_profiler_fn = build_fn_decl (fn_name, average_profiler_fn_type); | |
224 | free (CONST_CAST (char *, fn_name)); | |
4d3814a5 RG |
225 | TREE_NOTHROW (tree_ior_profiler_fn) = 1; |
226 | DECL_ATTRIBUTES (tree_ior_profiler_fn) | |
227 | = tree_cons (get_identifier ("leaf"), NULL, | |
228 | DECL_ATTRIBUTES (tree_ior_profiler_fn)); | |
229 | ||
0bc1b77f JH |
230 | /* LTO streamer needs assembler names. Because we create these decls |
231 | late, we need to initialize them by hand. */ | |
232 | DECL_ASSEMBLER_NAME (tree_interval_profiler_fn); | |
233 | DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn); | |
234 | DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn); | |
235 | DECL_ASSEMBLER_NAME (tree_indirect_call_profiler_fn); | |
236 | DECL_ASSEMBLER_NAME (tree_average_profiler_fn); | |
237 | DECL_ASSEMBLER_NAME (tree_ior_profiler_fn); | |
9885da8e | 238 | } |
f3df9541 AK |
239 | } |
240 | ||
b8698a0f L |
241 | /* Output instructions as GIMPLE trees to increment the edge |
242 | execution count, and insert them on E. We rely on | |
726a989a | 243 | gsi_insert_on_edge to preserve the order. */ |
6de9cd9a | 244 | |
e0cb7e1e SB |
245 | void |
246 | gimple_gen_edge_profiler (int edgeno, edge e) | |
6de9cd9a | 247 | { |
22063dbc | 248 | tree one; |
9225443e | 249 | |
9225443e | 250 | one = build_int_cst (gcov_type_node, 1); |
22063dbc ML |
251 | |
252 | if (flag_profile_update == PROFILE_UPDATE_ATOMIC) | |
253 | { | |
254 | /* __atomic_fetch_add (&counter, 1, MEMMODEL_RELAXED); */ | |
255 | tree addr = tree_coverage_counter_addr (GCOV_COUNTER_ARCS, edgeno); | |
892a653c ML |
256 | tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32 |
257 | ? BUILT_IN_ATOMIC_FETCH_ADD_8: | |
258 | BUILT_IN_ATOMIC_FETCH_ADD_4); | |
259 | gcall *stmt = gimple_build_call (f, 3, addr, one, | |
260 | build_int_cst (integer_type_node, | |
261 | MEMMODEL_RELAXED)); | |
22063dbc ML |
262 | gsi_insert_on_edge (e, stmt); |
263 | } | |
264 | else | |
265 | { | |
266 | tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); | |
267 | tree gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, | |
268 | NULL, "PROF_edge_counter"); | |
269 | gassign *stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); | |
270 | gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, | |
271 | NULL, "PROF_edge_counter"); | |
272 | gassign *stmt2 = gimple_build_assign (gcov_type_tmp_var, PLUS_EXPR, | |
273 | gimple_assign_lhs (stmt1), one); | |
274 | gassign *stmt3 = gimple_build_assign (unshare_expr (ref), | |
275 | gimple_assign_lhs (stmt2)); | |
276 | gsi_insert_on_edge (e, stmt1); | |
277 | gsi_insert_on_edge (e, stmt2); | |
278 | gsi_insert_on_edge (e, stmt3); | |
279 | } | |
6de9cd9a DN |
280 | } |
281 | ||
726a989a | 282 | /* Emits code to get VALUE to instrument at GSI, and returns the |
9885da8e ZD |
283 | variable containing the value. */ |
284 | ||
285 | static tree | |
726a989a | 286 | prepare_instrumented_value (gimple_stmt_iterator *gsi, histogram_value value) |
9885da8e | 287 | { |
8a76829c | 288 | tree val = value->hvalue.value; |
ada39f0b | 289 | if (POINTER_TYPE_P (TREE_TYPE (val))) |
0d82a1c8 RG |
290 | val = fold_convert (build_nonstandard_integer_type |
291 | (TYPE_PRECISION (TREE_TYPE (val)), 1), val); | |
726a989a RB |
292 | return force_gimple_operand_gsi (gsi, fold_convert (gcov_type_node, val), |
293 | true, NULL_TREE, true, GSI_SAME_STMT); | |
9885da8e ZD |
294 | } |
295 | ||
b8698a0f L |
296 | /* Output instructions as GIMPLE trees to increment the interval histogram |
297 | counter. VALUE is the expression whose value is profiled. TAG is the | |
6de9cd9a DN |
298 | tag of the section for counters, BASE is offset of the counter position. */ |
299 | ||
e0cb7e1e SB |
300 | void |
301 | gimple_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) | |
6de9cd9a | 302 | { |
355fe088 | 303 | gimple *stmt = value->hvalue.stmt; |
726a989a | 304 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
9885da8e | 305 | tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; |
538dd0b7 | 306 | gcall *call; |
726a989a RB |
307 | tree val; |
308 | tree start = build_int_cst_type (integer_type_node, | |
309 | value->hdata.intvl.int_start); | |
310 | tree steps = build_int_cst_type (unsigned_type_node, | |
311 | value->hdata.intvl.steps); | |
b8698a0f | 312 | |
726a989a | 313 | ref_ptr = force_gimple_operand_gsi (&gsi, |
aa00059c | 314 | build_addr (ref), |
726a989a RB |
315 | true, NULL_TREE, true, GSI_SAME_STMT); |
316 | val = prepare_instrumented_value (&gsi, value); | |
317 | call = gimple_build_call (tree_interval_profiler_fn, 4, | |
318 | ref_ptr, val, start, steps); | |
71ba42fa | 319 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
6de9cd9a DN |
320 | } |
321 | ||
b8698a0f L |
322 | /* Output instructions as GIMPLE trees to increment the power of two histogram |
323 | counter. VALUE is the expression whose value is profiled. TAG is the tag | |
6de9cd9a DN |
324 | of the section for counters, BASE is offset of the counter position. */ |
325 | ||
e0cb7e1e SB |
326 | void |
327 | gimple_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base) | |
6de9cd9a | 328 | { |
355fe088 | 329 | gimple *stmt = value->hvalue.stmt; |
726a989a | 330 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
fc9161c1 | 331 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
538dd0b7 | 332 | gcall *call; |
726a989a | 333 | tree val; |
b8698a0f | 334 | |
726a989a RB |
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_pow2_profiler_fn, 2, ref_ptr, val); | |
71ba42fa | 339 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
6de9cd9a DN |
340 | } |
341 | ||
342 | /* Output instructions as GIMPLE trees for code to find the most common value. | |
343 | VALUE is the expression whose value is profiled. TAG is the tag of the | |
344 | section for counters, BASE is offset of the counter position. */ | |
345 | ||
e0cb7e1e SB |
346 | void |
347 | gimple_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base) | |
6de9cd9a | 348 | { |
355fe088 | 349 | gimple *stmt = value->hvalue.stmt; |
726a989a | 350 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
fc9161c1 | 351 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
538dd0b7 | 352 | gcall *call; |
726a989a | 353 | tree val; |
b8698a0f | 354 | |
726a989a RB |
355 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
356 | true, NULL_TREE, true, GSI_SAME_STMT); | |
357 | val = prepare_instrumented_value (&gsi, value); | |
358 | call = gimple_build_call (tree_one_value_profiler_fn, 2, ref_ptr, val); | |
71ba42fa | 359 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
6de9cd9a DN |
360 | } |
361 | ||
6bad2617 TB |
362 | |
363 | /* Output instructions as GIMPLE trees for code to find the most | |
b8698a0f | 364 | common called function in indirect call. |
88512ba0 | 365 | VALUE is the call expression whose indirect callee is profiled. |
6bad2617 TB |
366 | TAG is the tag of the section for counters, BASE is offset of the |
367 | counter position. */ | |
368 | ||
e0cb7e1e SB |
369 | void |
370 | gimple_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base) | |
6bad2617 | 371 | { |
726a989a | 372 | tree tmp1; |
538dd0b7 | 373 | gassign *stmt1, *stmt2, *stmt3; |
355fe088 | 374 | gimple *stmt = value->hvalue.stmt; |
726a989a | 375 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
fc9161c1 | 376 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
6bad2617 | 377 | |
0a750165 RX |
378 | if ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) && |
379 | tag == GCOV_COUNTER_V_INDIR) || | |
380 | (!PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) && | |
381 | tag == GCOV_COUNTER_ICALL_TOPNV)) | |
382 | return; | |
383 | ||
726a989a RB |
384 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
385 | true, NULL_TREE, true, GSI_SAME_STMT); | |
6bad2617 TB |
386 | |
387 | /* Insert code: | |
b8698a0f | 388 | |
3edbcdbe | 389 | stmt1: __gcov_indirect_call.counters = get_relevant_counter_ptr (); |
9696c529 | 390 | stmt2: tmp1 = (void *) (indirect call argument value) |
3edbcdbe | 391 | stmt3: __gcov_indirect_call.callee = tmp1; |
4f751c54 ML |
392 | |
393 | Example: | |
394 | f_1 = foo; | |
3edbcdbe | 395 | __gcov_indirect_call.counters = &__gcov4.main[0]; |
4f751c54 ML |
396 | PROF_9 = f_1; |
397 | __gcov_indirect_call_callee = PROF_9; | |
398 | _4 = f_1 (); | |
6bad2617 TB |
399 | */ |
400 | ||
3edbcdbe ML |
401 | tree gcov_type_ptr = build_pointer_type (get_gcov_type ()); |
402 | ||
403 | tree counter_ref = build3 (COMPONENT_REF, gcov_type_ptr, | |
404 | ic_tuple_var, ic_tuple_counters_field, NULL_TREE); | |
405 | ||
406 | stmt1 = gimple_build_assign (counter_ref, ref_ptr); | |
407 | tmp1 = make_temp_ssa_name (ptr_type_node, NULL, "PROF"); | |
726a989a | 408 | stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value)); |
3edbcdbe ML |
409 | tree callee_ref = build3 (COMPONENT_REF, ptr_type_node, |
410 | ic_tuple_var, ic_tuple_callee_field, NULL_TREE); | |
411 | stmt3 = gimple_build_assign (callee_ref, tmp1); | |
6bad2617 | 412 | |
726a989a RB |
413 | gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); |
414 | gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); | |
415 | gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT); | |
6bad2617 TB |
416 | } |
417 | ||
418 | ||
419 | /* Output instructions as GIMPLE trees for code to find the most | |
420 | common called function in indirect call. Insert instructions at the | |
88512ba0 | 421 | beginning of every possible called function. |
6bad2617 TB |
422 | */ |
423 | ||
e0cb7e1e SB |
424 | void |
425 | gimple_gen_ic_func_profiler (void) | |
6bad2617 | 426 | { |
d52f5295 | 427 | struct cgraph_node * c_node = cgraph_node::get (current_function_decl); |
538dd0b7 | 428 | gcall *stmt1; |
2fa3d31b | 429 | tree tree_uid, cur_func, void0; |
6bad2617 | 430 | |
d52f5295 | 431 | if (c_node->only_called_directly_p ()) |
7e8b322a | 432 | return; |
b8698a0f | 433 | |
7d29f8e3 | 434 | gimple_init_gcov_profiler (); |
b8698a0f | 435 | |
4f751c54 ML |
436 | basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun); |
437 | basic_block cond_bb = split_edge (single_succ_edge (entry)); | |
438 | basic_block update_bb = split_edge (single_succ_edge (cond_bb)); | |
439 | ||
c9c15e27 ML |
440 | /* We need to do an extra split in order to not create an input |
441 | for a possible PHI node. */ | |
442 | split_edge (single_succ_edge (update_bb)); | |
443 | ||
4f751c54 ML |
444 | edge true_edge = single_succ_edge (cond_bb); |
445 | true_edge->flags = EDGE_TRUE_VALUE; | |
446 | ||
357067f2 | 447 | profile_probability probability; |
4f751c54 | 448 | if (DECL_VIRTUAL_P (current_function_decl)) |
357067f2 | 449 | probability = profile_probability::very_likely (); |
4f751c54 | 450 | else |
357067f2 | 451 | probability = profile_probability::unlikely (); |
4f751c54 ML |
452 | |
453 | true_edge->probability = probability; | |
454 | edge e = make_edge (cond_bb, single_succ_edge (update_bb)->dest, | |
455 | EDGE_FALSE_VALUE); | |
357067f2 | 456 | e->probability = true_edge->probability.invert (); |
4f751c54 | 457 | |
9696c529 SB |
458 | /* Insert code: |
459 | ||
4f751c54 ML |
460 | if (__gcov_indirect_call_callee != NULL) |
461 | __gcov_indirect_call_profiler_v2 (profile_id, ¤t_function_decl); | |
462 | ||
463 | The function __gcov_indirect_call_profiler_v2 is responsible for | |
464 | resetting __gcov_indirect_call_callee to NULL. */ | |
465 | ||
466 | gimple_stmt_iterator gsi = gsi_start_bb (cond_bb); | |
3edbcdbe ML |
467 | void0 = build_int_cst (ptr_type_node, 0); |
468 | ||
469 | tree callee_ref = build3 (COMPONENT_REF, ptr_type_node, | |
470 | ic_tuple_var, ic_tuple_callee_field, NULL_TREE); | |
4f751c54 | 471 | |
3edbcdbe | 472 | tree ref = force_gimple_operand_gsi (&gsi, callee_ref, true, NULL_TREE, |
4f751c54 ML |
473 | true, GSI_SAME_STMT); |
474 | ||
475 | gcond *cond = gimple_build_cond (NE_EXPR, ref, | |
476 | void0, NULL, NULL); | |
477 | gsi_insert_before (&gsi, cond, GSI_NEW_STMT); | |
478 | ||
479 | gsi = gsi_after_labels (update_bb); | |
4d3814a5 RG |
480 | |
481 | cur_func = force_gimple_operand_gsi (&gsi, | |
aa00059c | 482 | build_addr (current_function_decl), |
4d3814a5 RG |
483 | true, NULL_TREE, |
484 | true, GSI_SAME_STMT); | |
2fa3d31b | 485 | tree_uid = build_int_cst |
c02ae3ae JH |
486 | (gcov_type_node, |
487 | cgraph_node::get (current_function_decl)->profile_id); | |
488 | stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 2, | |
489 | tree_uid, cur_func); | |
4d3814a5 | 490 | gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); |
6bad2617 TB |
491 | } |
492 | ||
86ce5d2f ML |
493 | /* Output instructions as GIMPLE tree at the beginning for each function. |
494 | TAG is the tag of the section for counters, BASE is offset of the | |
495 | counter position and GSI is the iterator we place the counter. */ | |
496 | ||
497 | void | |
7d29f8e3 | 498 | gimple_gen_time_profiler (unsigned tag, unsigned base) |
86ce5d2f | 499 | { |
7d29f8e3 | 500 | tree type = get_gcov_type (); |
248cce34 ML |
501 | basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun); |
502 | basic_block cond_bb = split_edge (single_succ_edge (entry)); | |
7d29f8e3 ML |
503 | basic_block update_bb = split_edge (single_succ_edge (cond_bb)); |
504 | ||
c9c15e27 ML |
505 | /* We need to do an extra split in order to not create an input |
506 | for a possible PHI node. */ | |
507 | split_edge (single_succ_edge (update_bb)); | |
508 | ||
7d29f8e3 ML |
509 | edge true_edge = single_succ_edge (cond_bb); |
510 | true_edge->flags = EDGE_TRUE_VALUE; | |
357067f2 | 511 | true_edge->probability = profile_probability::unlikely (); |
7d29f8e3 ML |
512 | edge e |
513 | = make_edge (cond_bb, single_succ_edge (update_bb)->dest, EDGE_FALSE_VALUE); | |
357067f2 | 514 | e->probability = true_edge->probability.invert (); |
7d29f8e3 ML |
515 | |
516 | gimple_stmt_iterator gsi = gsi_start_bb (cond_bb); | |
517 | tree original_ref = tree_coverage_counter_ref (tag, base); | |
518 | tree ref = force_gimple_operand_gsi (&gsi, original_ref, true, NULL_TREE, | |
519 | true, GSI_SAME_STMT); | |
520 | tree one = build_int_cst (type, 1); | |
86ce5d2f | 521 | |
7d29f8e3 ML |
522 | /* Emit: if (counters[0] != 0). */ |
523 | gcond *cond = gimple_build_cond (EQ_EXPR, ref, build_int_cst (type, 0), | |
524 | NULL, NULL); | |
525 | gsi_insert_before (&gsi, cond, GSI_NEW_STMT); | |
526 | ||
527 | gsi = gsi_start_bb (update_bb); | |
528 | ||
529 | /* Emit: counters[0] = ++__gcov_time_profiler_counter. */ | |
530 | if (flag_profile_update == PROFILE_UPDATE_ATOMIC) | |
531 | { | |
5bcb571c ML |
532 | tree ptr = make_temp_ssa_name (build_pointer_type (type), NULL, |
533 | "time_profiler_counter_ptr"); | |
534 | tree addr = build1 (ADDR_EXPR, TREE_TYPE (ptr), | |
7d29f8e3 ML |
535 | tree_time_profiler_counter); |
536 | gassign *assign = gimple_build_assign (ptr, NOP_EXPR, addr); | |
537 | gsi_insert_before (&gsi, assign, GSI_NEW_STMT); | |
538 | tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32 | |
539 | ? BUILT_IN_ATOMIC_ADD_FETCH_8: | |
540 | BUILT_IN_ATOMIC_ADD_FETCH_4); | |
541 | gcall *stmt = gimple_build_call (f, 3, ptr, one, | |
542 | build_int_cst (integer_type_node, | |
543 | MEMMODEL_RELAXED)); | |
544 | tree result_type = TREE_TYPE (TREE_TYPE (f)); | |
545 | tree tmp = make_temp_ssa_name (result_type, NULL, "time_profile"); | |
546 | gimple_set_lhs (stmt, tmp); | |
547 | gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); | |
548 | tmp = make_temp_ssa_name (type, NULL, "time_profile"); | |
549 | assign = gimple_build_assign (tmp, NOP_EXPR, | |
550 | gimple_call_lhs (stmt)); | |
551 | gsi_insert_after (&gsi, assign, GSI_NEW_STMT); | |
552 | assign = gimple_build_assign (original_ref, tmp); | |
553 | gsi_insert_after (&gsi, assign, GSI_NEW_STMT); | |
554 | } | |
555 | else | |
556 | { | |
557 | tree tmp = make_temp_ssa_name (type, NULL, "time_profile"); | |
558 | gassign *assign = gimple_build_assign (tmp, tree_time_profiler_counter); | |
559 | gsi_insert_before (&gsi, assign, GSI_NEW_STMT); | |
560 | ||
561 | tmp = make_temp_ssa_name (type, NULL, "time_profile"); | |
562 | assign = gimple_build_assign (tmp, PLUS_EXPR, gimple_assign_lhs (assign), | |
563 | one); | |
564 | gsi_insert_after (&gsi, assign, GSI_NEW_STMT); | |
565 | assign = gimple_build_assign (original_ref, tmp); | |
566 | gsi_insert_after (&gsi, assign, GSI_NEW_STMT); | |
567 | assign = gimple_build_assign (tree_time_profiler_counter, tmp); | |
568 | gsi_insert_after (&gsi, assign, GSI_NEW_STMT); | |
569 | } | |
86ce5d2f ML |
570 | } |
571 | ||
b8698a0f L |
572 | /* Output instructions as GIMPLE trees to increment the average histogram |
573 | counter. VALUE is the expression whose value is profiled. TAG is the | |
079a182e JH |
574 | tag of the section for counters, BASE is offset of the counter position. */ |
575 | ||
e0cb7e1e SB |
576 | void |
577 | gimple_gen_average_profiler (histogram_value value, unsigned tag, unsigned base) | |
079a182e | 578 | { |
355fe088 | 579 | gimple *stmt = value->hvalue.stmt; |
726a989a | 580 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
fc9161c1 | 581 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
538dd0b7 | 582 | gcall *call; |
726a989a | 583 | tree val; |
b8698a0f | 584 | |
726a989a | 585 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
c6540bde | 586 | true, NULL_TREE, |
726a989a RB |
587 | true, GSI_SAME_STMT); |
588 | val = prepare_instrumented_value (&gsi, value); | |
589 | call = gimple_build_call (tree_average_profiler_fn, 2, ref_ptr, val); | |
71ba42fa | 590 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
079a182e JH |
591 | } |
592 | ||
b8698a0f L |
593 | /* Output instructions as GIMPLE trees to increment the ior histogram |
594 | counter. VALUE is the expression whose value is profiled. TAG is the | |
079a182e JH |
595 | tag of the section for counters, BASE is offset of the counter position. */ |
596 | ||
e0cb7e1e SB |
597 | void |
598 | gimple_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base) | |
079a182e | 599 | { |
355fe088 | 600 | gimple *stmt = value->hvalue.stmt; |
726a989a | 601 | gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
fc9161c1 | 602 | tree ref_ptr = tree_coverage_counter_addr (tag, base); |
538dd0b7 | 603 | gcall *call; |
726a989a | 604 | tree val; |
b8698a0f | 605 | |
726a989a RB |
606 | ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
607 | true, NULL_TREE, true, GSI_SAME_STMT); | |
608 | val = prepare_instrumented_value (&gsi, value); | |
609 | call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val); | |
71ba42fa | 610 | gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
079a182e JH |
611 | } |
612 | ||
7fe76f6a ML |
613 | #ifndef HAVE_sync_compare_and_swapsi |
614 | #define HAVE_sync_compare_and_swapsi 0 | |
615 | #endif | |
616 | #ifndef HAVE_atomic_compare_and_swapsi | |
617 | #define HAVE_atomic_compare_and_swapsi 0 | |
618 | #endif | |
619 | ||
620 | #ifndef HAVE_sync_compare_and_swapdi | |
621 | #define HAVE_sync_compare_and_swapdi 0 | |
622 | #endif | |
623 | #ifndef HAVE_atomic_compare_and_swapdi | |
624 | #define HAVE_atomic_compare_and_swapdi 0 | |
625 | #endif | |
626 | ||
4d3814a5 | 627 | /* Profile all functions in the callgraph. */ |
6de9cd9a | 628 | |
c2924966 | 629 | static unsigned int |
1f1e8527 DJ |
630 | tree_profiling (void) |
631 | { | |
4d3814a5 RG |
632 | struct cgraph_node *node; |
633 | ||
7fe76f6a | 634 | /* Verify whether we can utilize atomic update operations. */ |
4d209853 ML |
635 | bool can_support_atomic = false; |
636 | unsigned HOST_WIDE_INT gcov_type_size | |
637 | = tree_to_uhwi (TYPE_SIZE_UNIT (get_gcov_type ())); | |
638 | if (gcov_type_size == 4) | |
639 | can_support_atomic | |
640 | = HAVE_sync_compare_and_swapsi || HAVE_atomic_compare_and_swapsi; | |
641 | else if (gcov_type_size == 8) | |
642 | can_support_atomic | |
643 | = HAVE_sync_compare_and_swapdi || HAVE_atomic_compare_and_swapdi; | |
644 | ||
645 | if (flag_profile_update == PROFILE_UPDATE_ATOMIC | |
646 | && !can_support_atomic) | |
7fe76f6a | 647 | { |
4d209853 ML |
648 | warning (0, "target does not support atomic profile update, " |
649 | "single mode is selected"); | |
650 | flag_profile_update = PROFILE_UPDATE_SINGLE; | |
7fe76f6a | 651 | } |
4d209853 ML |
652 | else if (flag_profile_update == PROFILE_UPDATE_PREFER_ATOMIC) |
653 | flag_profile_update = can_support_atomic | |
654 | ? PROFILE_UPDATE_ATOMIC : PROFILE_UPDATE_SINGLE; | |
7fe76f6a | 655 | |
9696c529 SB |
656 | /* This is a small-ipa pass that gets called only once, from |
657 | cgraphunit.c:ipa_passes(). */ | |
3dafb85c | 658 | gcc_assert (symtab->state == IPA_SSA); |
9225443e | 659 | |
2fa3d31b | 660 | init_node_map (true); |
903d1e67 | 661 | |
65c70e6b | 662 | FOR_EACH_DEFINED_FUNCTION (node) |
4d3814a5 | 663 | { |
67348ccc | 664 | if (!gimple_has_body_p (node->decl)) |
4d3814a5 RG |
665 | continue; |
666 | ||
667 | /* Don't profile functions produced for builtin stuff. */ | |
67348ccc | 668 | if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) |
4d3814a5 RG |
669 | continue; |
670 | ||
1225d6b1 ML |
671 | if (lookup_attribute ("no_profile_instrument_function", |
672 | DECL_ATTRIBUTES (node->decl))) | |
673 | continue; | |
07db0f9b JH |
674 | /* Do not instrument extern inline functions when testing coverage. |
675 | While this is not perfectly consistent (early inlined extern inlines | |
676 | will get acocunted), testsuite expects that. */ | |
677 | if (DECL_EXTERNAL (node->decl) | |
678 | && flag_test_coverage) | |
679 | continue; | |
680 | ||
67348ccc | 681 | push_cfun (DECL_STRUCT_FUNCTION (node->decl)); |
4d3814a5 | 682 | |
a53d4f20 ML |
683 | if (dump_file) |
684 | dump_function_header (dump_file, cfun->decl, dump_flags); | |
685 | ||
71fb4f92 | 686 | /* Local pure-const may imply need to fixup the cfg. */ |
49bdc0a6 RG |
687 | if (execute_fixup_cfg () & TODO_cleanup_cfg) |
688 | cleanup_tree_cfg (); | |
9696c529 | 689 | |
4d3814a5 RG |
690 | branch_prob (); |
691 | ||
692 | if (! flag_branch_probabilities | |
693 | && flag_profile_values) | |
e0cb7e1e | 694 | gimple_gen_ic_func_profiler (); |
4d3814a5 RG |
695 | |
696 | if (flag_branch_probabilities | |
697 | && flag_profile_values | |
698 | && flag_value_profile_transformations) | |
e0cb7e1e | 699 | gimple_value_profile_transformations (); |
4d3814a5 RG |
700 | |
701 | /* The above could hose dominator info. Currently there is | |
702 | none coming in, this is a safety valve. It should be | |
703 | easy to adjust it, if and when there is some. */ | |
704 | free_dominance_info (CDI_DOMINATORS); | |
705 | free_dominance_info (CDI_POST_DOMINATORS); | |
4d3814a5 RG |
706 | pop_cfun (); |
707 | } | |
708 | ||
709 | /* Drop pure/const flags from instrumented functions. */ | |
86b7136a JH |
710 | if (profile_arc_flag || flag_test_coverage) |
711 | FOR_EACH_DEFINED_FUNCTION (node) | |
712 | { | |
713 | if (!gimple_has_body_p (node->decl) | |
714 | || !(!node->clone_of | |
715 | || node->decl != node->clone_of->decl)) | |
716 | continue; | |
717 | ||
718 | /* Don't profile functions produced for builtin stuff. */ | |
719 | if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) | |
720 | continue; | |
721 | ||
722 | node->set_const_flag (false, false); | |
723 | node->set_pure_flag (false, false); | |
724 | } | |
4d3814a5 RG |
725 | |
726 | /* Update call statements and rebuild the cgraph. */ | |
65c70e6b | 727 | FOR_EACH_DEFINED_FUNCTION (node) |
4d3814a5 RG |
728 | { |
729 | basic_block bb; | |
730 | ||
67348ccc | 731 | if (!gimple_has_body_p (node->decl) |
960bfb69 | 732 | || !(!node->clone_of |
67348ccc | 733 | || node->decl != node->clone_of->decl)) |
4d3814a5 RG |
734 | continue; |
735 | ||
736 | /* Don't profile functions produced for builtin stuff. */ | |
67348ccc | 737 | if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) |
4d3814a5 RG |
738 | continue; |
739 | ||
67348ccc | 740 | push_cfun (DECL_STRUCT_FUNCTION (node->decl)); |
4d3814a5 | 741 | |
11cd3bed | 742 | FOR_EACH_BB_FN (bb, cfun) |
4d3814a5 RG |
743 | { |
744 | gimple_stmt_iterator gsi; | |
745 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |
746 | { | |
355fe088 | 747 | gimple *stmt = gsi_stmt (gsi); |
4d3814a5 RG |
748 | if (is_gimple_call (stmt)) |
749 | update_stmt (stmt); | |
750 | } | |
751 | } | |
752 | ||
a64bbb3f JH |
753 | /* re-merge split blocks. */ |
754 | cleanup_tree_cfg (); | |
4d3814a5 RG |
755 | update_ssa (TODO_update_ssa); |
756 | ||
3dafb85c | 757 | cgraph_edge::rebuild_edges (); |
4d3814a5 | 758 | |
4d3814a5 RG |
759 | pop_cfun (); |
760 | } | |
f7b4a383 | 761 | |
eb4b92c1 TJ |
762 | handle_missing_profiles (); |
763 | ||
c3284718 | 764 | del_node_map (); |
c2924966 | 765 | return 0; |
1f1e8527 DJ |
766 | } |
767 | ||
27a4cd48 DM |
768 | namespace { |
769 | ||
770 | const pass_data pass_data_ipa_tree_profile = | |
6de9cd9a | 771 | { |
27a4cd48 DM |
772 | SIMPLE_IPA_PASS, /* type */ |
773 | "profile", /* name */ | |
774 | OPTGROUP_NONE, /* optinfo_flags */ | |
27a4cd48 DM |
775 | TV_IPA_PROFILE, /* tv_id */ |
776 | 0, /* properties_required */ | |
777 | 0, /* properties_provided */ | |
778 | 0, /* properties_destroyed */ | |
779 | 0, /* todo_flags_start */ | |
86b7136a | 780 | TODO_dump_symtab, /* todo_flags_finish */ |
6de9cd9a DN |
781 | }; |
782 | ||
27a4cd48 DM |
783 | class pass_ipa_tree_profile : public simple_ipa_opt_pass |
784 | { | |
785 | public: | |
c3284718 RS |
786 | pass_ipa_tree_profile (gcc::context *ctxt) |
787 | : simple_ipa_opt_pass (pass_data_ipa_tree_profile, ctxt) | |
27a4cd48 DM |
788 | {} |
789 | ||
790 | /* opt_pass methods: */ | |
1a3d085c | 791 | virtual bool gate (function *); |
be55bfe6 | 792 | virtual unsigned int execute (function *) { return tree_profiling (); } |
27a4cd48 DM |
793 | |
794 | }; // class pass_ipa_tree_profile | |
795 | ||
1a3d085c TS |
796 | bool |
797 | pass_ipa_tree_profile::gate (function *) | |
798 | { | |
be3c16c4 DC |
799 | /* When profile instrumentation, use or test coverage shall be performed. |
800 | But for AutoFDO, this there is no instrumentation, thus this pass is | |
801 | diabled. */ | |
802 | return (!in_lto_p && !flag_auto_profile | |
1a3d085c TS |
803 | && (flag_branch_probabilities || flag_test_coverage |
804 | || profile_arc_flag)); | |
805 | } | |
806 | ||
27a4cd48 DM |
807 | } // anon namespace |
808 | ||
809 | simple_ipa_opt_pass * | |
810 | make_pass_ipa_tree_profile (gcc::context *ctxt) | |
811 | { | |
812 | return new pass_ipa_tree_profile (ctxt); | |
813 | } | |
814 | ||
9885da8e | 815 | #include "gt-tree-profile.h" |