Mercurial > hg > CbC > CbC_gcc
comparison gcc/tree-profile.c @ 67:f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 22 Mar 2011 17:18:12 +0900 |
parents | b7f97abdc517 |
children | 04ced10e8804 |
comparison
equal
deleted
inserted
replaced
65:65488c3d617d | 67:f6334be47118 |
---|---|
30 #include "system.h" | 30 #include "system.h" |
31 #include "coretypes.h" | 31 #include "coretypes.h" |
32 #include "tm.h" | 32 #include "tm.h" |
33 #include "flags.h" | 33 #include "flags.h" |
34 #include "regs.h" | 34 #include "regs.h" |
35 #include "expr.h" | |
36 #include "function.h" | 35 #include "function.h" |
37 #include "toplev.h" | 36 #include "basic-block.h" |
37 #include "diagnostic-core.h" | |
38 #include "coverage.h" | 38 #include "coverage.h" |
39 #include "tree.h" | 39 #include "tree.h" |
40 #include "tree-flow.h" | 40 #include "tree-flow.h" |
41 #include "tree-dump.h" | 41 #include "tree-dump.h" |
42 #include "tree-pass.h" | 42 #include "tree-pass.h" |
63 /* Add code: | 63 /* Add code: |
64 static gcov* __gcov_indirect_call_counters; // pointer to actual counter | 64 static gcov* __gcov_indirect_call_counters; // pointer to actual counter |
65 static void* __gcov_indirect_call_callee; // actual callee address | 65 static void* __gcov_indirect_call_callee; // actual callee address |
66 */ | 66 */ |
67 static void | 67 static void |
68 tree_init_ic_make_global_vars (void) | 68 init_ic_make_global_vars (void) |
69 { | 69 { |
70 tree gcov_type_ptr; | 70 tree gcov_type_ptr; |
71 | 71 |
72 ptr_void = build_pointer_type (void_type_node); | 72 ptr_void = build_pointer_type (void_type_node); |
73 | 73 |
93 DECL_INITIAL (ic_gcov_type_ptr_var) = NULL; | 93 DECL_INITIAL (ic_gcov_type_ptr_var) = NULL; |
94 varpool_finalize_decl (ic_gcov_type_ptr_var); | 94 varpool_finalize_decl (ic_gcov_type_ptr_var); |
95 varpool_mark_needed_node (varpool_node (ic_gcov_type_ptr_var)); | 95 varpool_mark_needed_node (varpool_node (ic_gcov_type_ptr_var)); |
96 } | 96 } |
97 | 97 |
98 static void | 98 void |
99 tree_init_edge_profiler (void) | 99 gimple_init_edge_profiler (void) |
100 { | 100 { |
101 tree interval_profiler_fn_type; | 101 tree interval_profiler_fn_type; |
102 tree pow2_profiler_fn_type; | 102 tree pow2_profiler_fn_type; |
103 tree one_value_profiler_fn_type; | 103 tree one_value_profiler_fn_type; |
104 tree gcov_type_ptr; | 104 tree gcov_type_ptr; |
117 integer_type_node, | 117 integer_type_node, |
118 unsigned_type_node, NULL_TREE); | 118 unsigned_type_node, NULL_TREE); |
119 tree_interval_profiler_fn | 119 tree_interval_profiler_fn |
120 = build_fn_decl ("__gcov_interval_profiler", | 120 = build_fn_decl ("__gcov_interval_profiler", |
121 interval_profiler_fn_type); | 121 interval_profiler_fn_type); |
122 TREE_NOTHROW (tree_interval_profiler_fn) = 1; | |
123 DECL_ATTRIBUTES (tree_interval_profiler_fn) | |
124 = tree_cons (get_identifier ("leaf"), NULL, | |
125 DECL_ATTRIBUTES (tree_interval_profiler_fn)); | |
122 | 126 |
123 /* void (*) (gcov_type *, gcov_type) */ | 127 /* void (*) (gcov_type *, gcov_type) */ |
124 pow2_profiler_fn_type | 128 pow2_profiler_fn_type |
125 = build_function_type_list (void_type_node, | 129 = build_function_type_list (void_type_node, |
126 gcov_type_ptr, gcov_type_node, | 130 gcov_type_ptr, gcov_type_node, |
127 NULL_TREE); | 131 NULL_TREE); |
128 tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler", | 132 tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler", |
129 pow2_profiler_fn_type); | 133 pow2_profiler_fn_type); |
134 TREE_NOTHROW (tree_pow2_profiler_fn) = 1; | |
135 DECL_ATTRIBUTES (tree_pow2_profiler_fn) | |
136 = tree_cons (get_identifier ("leaf"), NULL, | |
137 DECL_ATTRIBUTES (tree_pow2_profiler_fn)); | |
130 | 138 |
131 /* void (*) (gcov_type *, gcov_type) */ | 139 /* void (*) (gcov_type *, gcov_type) */ |
132 one_value_profiler_fn_type | 140 one_value_profiler_fn_type |
133 = build_function_type_list (void_type_node, | 141 = build_function_type_list (void_type_node, |
134 gcov_type_ptr, gcov_type_node, | 142 gcov_type_ptr, gcov_type_node, |
135 NULL_TREE); | 143 NULL_TREE); |
136 tree_one_value_profiler_fn | 144 tree_one_value_profiler_fn |
137 = build_fn_decl ("__gcov_one_value_profiler", | 145 = build_fn_decl ("__gcov_one_value_profiler", |
138 one_value_profiler_fn_type); | 146 one_value_profiler_fn_type); |
139 | 147 TREE_NOTHROW (tree_one_value_profiler_fn) = 1; |
140 tree_init_ic_make_global_vars (); | 148 DECL_ATTRIBUTES (tree_one_value_profiler_fn) |
149 = tree_cons (get_identifier ("leaf"), NULL, | |
150 DECL_ATTRIBUTES (tree_one_value_profiler_fn)); | |
151 | |
152 init_ic_make_global_vars (); | |
141 | 153 |
142 /* void (*) (gcov_type *, gcov_type, void *, void *) */ | 154 /* void (*) (gcov_type *, gcov_type, void *, void *) */ |
143 ic_profiler_fn_type | 155 ic_profiler_fn_type |
144 = build_function_type_list (void_type_node, | 156 = build_function_type_list (void_type_node, |
145 gcov_type_ptr, gcov_type_node, | 157 gcov_type_ptr, gcov_type_node, |
146 ptr_void, | 158 ptr_void, |
147 ptr_void, NULL_TREE); | 159 ptr_void, NULL_TREE); |
148 tree_indirect_call_profiler_fn | 160 tree_indirect_call_profiler_fn |
149 = build_fn_decl ("__gcov_indirect_call_profiler", | 161 = build_fn_decl ("__gcov_indirect_call_profiler", |
150 ic_profiler_fn_type); | 162 ic_profiler_fn_type); |
163 TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1; | |
164 DECL_ATTRIBUTES (tree_indirect_call_profiler_fn) | |
165 = tree_cons (get_identifier ("leaf"), NULL, | |
166 DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)); | |
167 | |
151 /* void (*) (gcov_type *, gcov_type) */ | 168 /* void (*) (gcov_type *, gcov_type) */ |
152 average_profiler_fn_type | 169 average_profiler_fn_type |
153 = build_function_type_list (void_type_node, | 170 = build_function_type_list (void_type_node, |
154 gcov_type_ptr, gcov_type_node, NULL_TREE); | 171 gcov_type_ptr, gcov_type_node, NULL_TREE); |
155 tree_average_profiler_fn | 172 tree_average_profiler_fn |
156 = build_fn_decl ("__gcov_average_profiler", | 173 = build_fn_decl ("__gcov_average_profiler", |
157 average_profiler_fn_type); | 174 average_profiler_fn_type); |
175 TREE_NOTHROW (tree_average_profiler_fn) = 1; | |
176 DECL_ATTRIBUTES (tree_average_profiler_fn) | |
177 = tree_cons (get_identifier ("leaf"), NULL, | |
178 DECL_ATTRIBUTES (tree_average_profiler_fn)); | |
158 tree_ior_profiler_fn | 179 tree_ior_profiler_fn |
159 = build_fn_decl ("__gcov_ior_profiler", | 180 = build_fn_decl ("__gcov_ior_profiler", |
160 average_profiler_fn_type); | 181 average_profiler_fn_type); |
182 TREE_NOTHROW (tree_ior_profiler_fn) = 1; | |
183 DECL_ATTRIBUTES (tree_ior_profiler_fn) | |
184 = tree_cons (get_identifier ("leaf"), NULL, | |
185 DECL_ATTRIBUTES (tree_ior_profiler_fn)); | |
186 | |
161 /* LTO streamer needs assembler names. Because we create these decls | 187 /* LTO streamer needs assembler names. Because we create these decls |
162 late, we need to initialize them by hand. */ | 188 late, we need to initialize them by hand. */ |
163 DECL_ASSEMBLER_NAME (tree_interval_profiler_fn); | 189 DECL_ASSEMBLER_NAME (tree_interval_profiler_fn); |
164 DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn); | 190 DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn); |
165 DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn); | 191 DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn); |
167 DECL_ASSEMBLER_NAME (tree_average_profiler_fn); | 193 DECL_ASSEMBLER_NAME (tree_average_profiler_fn); |
168 DECL_ASSEMBLER_NAME (tree_ior_profiler_fn); | 194 DECL_ASSEMBLER_NAME (tree_ior_profiler_fn); |
169 } | 195 } |
170 } | 196 } |
171 | 197 |
172 /* New call was added, make goto call edges if neccesary. */ | |
173 | |
174 static void | |
175 add_abnormal_goto_call_edges (gimple_stmt_iterator gsi) | |
176 { | |
177 gimple stmt = gsi_stmt (gsi); | |
178 | |
179 if (!stmt_can_make_abnormal_goto (stmt)) | |
180 return; | |
181 if (!gsi_end_p (gsi)) | |
182 split_block (gimple_bb (stmt), stmt); | |
183 make_abnormal_goto_edges (gimple_bb (stmt), true); | |
184 } | |
185 | |
186 /* Output instructions as GIMPLE trees to increment the edge | 198 /* Output instructions as GIMPLE trees to increment the edge |
187 execution count, and insert them on E. We rely on | 199 execution count, and insert them on E. We rely on |
188 gsi_insert_on_edge to preserve the order. */ | 200 gsi_insert_on_edge to preserve the order. */ |
189 | 201 |
190 static void | 202 void |
191 tree_gen_edge_profiler (int edgeno, edge e) | 203 gimple_gen_edge_profiler (int edgeno, edge e) |
192 { | 204 { |
193 tree ref, one; | 205 tree ref, one; |
194 gimple stmt1, stmt2, stmt3; | 206 gimple stmt1, stmt2, stmt3; |
195 | 207 |
196 /* We share one temporary variable declaration per function. This | 208 /* We share one temporary variable declaration per function. This |
197 gets re-set in tree_profiling. */ | 209 gets re-set in tree_profiling. */ |
198 if (gcov_type_tmp_var == NULL_TREE) | 210 if (gcov_type_tmp_var == NULL_TREE) |
199 gcov_type_tmp_var = create_tmp_var (gcov_type_node, "PROF_edge_counter"); | 211 gcov_type_tmp_var = create_tmp_reg (gcov_type_node, "PROF_edge_counter"); |
200 ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); | 212 ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); |
201 one = build_int_cst (gcov_type_node, 1); | 213 one = build_int_cst (gcov_type_node, 1); |
202 stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); | 214 stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); |
215 gimple_assign_set_lhs (stmt1, make_ssa_name (gcov_type_tmp_var, stmt1)); | |
203 stmt2 = gimple_build_assign_with_ops (PLUS_EXPR, gcov_type_tmp_var, | 216 stmt2 = gimple_build_assign_with_ops (PLUS_EXPR, gcov_type_tmp_var, |
204 gcov_type_tmp_var, one); | 217 gimple_assign_lhs (stmt1), one); |
205 stmt3 = gimple_build_assign (unshare_expr (ref), gcov_type_tmp_var); | 218 gimple_assign_set_lhs (stmt2, make_ssa_name (gcov_type_tmp_var, stmt2)); |
219 stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2)); | |
206 gsi_insert_on_edge (e, stmt1); | 220 gsi_insert_on_edge (e, stmt1); |
207 gsi_insert_on_edge (e, stmt2); | 221 gsi_insert_on_edge (e, stmt2); |
208 gsi_insert_on_edge (e, stmt3); | 222 gsi_insert_on_edge (e, stmt3); |
209 } | 223 } |
210 | 224 |
223 | 237 |
224 /* Output instructions as GIMPLE trees to increment the interval histogram | 238 /* Output instructions as GIMPLE trees to increment the interval histogram |
225 counter. VALUE is the expression whose value is profiled. TAG is the | 239 counter. VALUE is the expression whose value is profiled. TAG is the |
226 tag of the section for counters, BASE is offset of the counter position. */ | 240 tag of the section for counters, BASE is offset of the counter position. */ |
227 | 241 |
228 static void | 242 void |
229 tree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) | 243 gimple_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base) |
230 { | 244 { |
231 gimple stmt = value->hvalue.stmt; | 245 gimple stmt = value->hvalue.stmt; |
232 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | 246 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
233 tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; | 247 tree ref = tree_coverage_counter_ref (tag, base), ref_ptr; |
234 gimple call; | 248 gimple call; |
243 true, NULL_TREE, true, GSI_SAME_STMT); | 257 true, NULL_TREE, true, GSI_SAME_STMT); |
244 val = prepare_instrumented_value (&gsi, value); | 258 val = prepare_instrumented_value (&gsi, value); |
245 call = gimple_build_call (tree_interval_profiler_fn, 4, | 259 call = gimple_build_call (tree_interval_profiler_fn, 4, |
246 ref_ptr, val, start, steps); | 260 ref_ptr, val, start, steps); |
247 gsi_insert_before (&gsi, call, GSI_NEW_STMT); | 261 gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
248 add_abnormal_goto_call_edges (gsi); | |
249 } | 262 } |
250 | 263 |
251 /* Output instructions as GIMPLE trees to increment the power of two histogram | 264 /* Output instructions as GIMPLE trees to increment the power of two histogram |
252 counter. VALUE is the expression whose value is profiled. TAG is the tag | 265 counter. VALUE is the expression whose value is profiled. TAG is the tag |
253 of the section for counters, BASE is offset of the counter position. */ | 266 of the section for counters, BASE is offset of the counter position. */ |
254 | 267 |
255 static void | 268 void |
256 tree_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base) | 269 gimple_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base) |
257 { | 270 { |
258 gimple stmt = value->hvalue.stmt; | 271 gimple stmt = value->hvalue.stmt; |
259 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | 272 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
260 tree ref_ptr = tree_coverage_counter_addr (tag, base); | 273 tree ref_ptr = tree_coverage_counter_addr (tag, base); |
261 gimple call; | 274 gimple call; |
264 ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, | 277 ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
265 true, NULL_TREE, true, GSI_SAME_STMT); | 278 true, NULL_TREE, true, GSI_SAME_STMT); |
266 val = prepare_instrumented_value (&gsi, value); | 279 val = prepare_instrumented_value (&gsi, value); |
267 call = gimple_build_call (tree_pow2_profiler_fn, 2, ref_ptr, val); | 280 call = gimple_build_call (tree_pow2_profiler_fn, 2, ref_ptr, val); |
268 gsi_insert_before (&gsi, call, GSI_NEW_STMT); | 281 gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
269 add_abnormal_goto_call_edges (gsi); | |
270 } | 282 } |
271 | 283 |
272 /* Output instructions as GIMPLE trees for code to find the most common value. | 284 /* Output instructions as GIMPLE trees for code to find the most common value. |
273 VALUE is the expression whose value is profiled. TAG is the tag of the | 285 VALUE is the expression whose value is profiled. TAG is the tag of the |
274 section for counters, BASE is offset of the counter position. */ | 286 section for counters, BASE is offset of the counter position. */ |
275 | 287 |
276 static void | 288 void |
277 tree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base) | 289 gimple_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base) |
278 { | 290 { |
279 gimple stmt = value->hvalue.stmt; | 291 gimple stmt = value->hvalue.stmt; |
280 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | 292 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
281 tree ref_ptr = tree_coverage_counter_addr (tag, base); | 293 tree ref_ptr = tree_coverage_counter_addr (tag, base); |
282 gimple call; | 294 gimple call; |
285 ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, | 297 ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
286 true, NULL_TREE, true, GSI_SAME_STMT); | 298 true, NULL_TREE, true, GSI_SAME_STMT); |
287 val = prepare_instrumented_value (&gsi, value); | 299 val = prepare_instrumented_value (&gsi, value); |
288 call = gimple_build_call (tree_one_value_profiler_fn, 2, ref_ptr, val); | 300 call = gimple_build_call (tree_one_value_profiler_fn, 2, ref_ptr, val); |
289 gsi_insert_before (&gsi, call, GSI_NEW_STMT); | 301 gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
290 add_abnormal_goto_call_edges (gsi); | |
291 } | 302 } |
292 | 303 |
293 | 304 |
294 /* Output instructions as GIMPLE trees for code to find the most | 305 /* Output instructions as GIMPLE trees for code to find the most |
295 common called function in indirect call. | 306 common called function in indirect call. |
296 VALUE is the call expression whose indirect callee is profiled. | 307 VALUE is the call expression whose indirect callee is profiled. |
297 TAG is the tag of the section for counters, BASE is offset of the | 308 TAG is the tag of the section for counters, BASE is offset of the |
298 counter position. */ | 309 counter position. */ |
299 | 310 |
300 static void | 311 void |
301 tree_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base) | 312 gimple_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base) |
302 { | 313 { |
303 tree tmp1; | 314 tree tmp1; |
304 gimple stmt1, stmt2, stmt3; | 315 gimple stmt1, stmt2, stmt3; |
305 gimple stmt = value->hvalue.stmt; | 316 gimple stmt = value->hvalue.stmt; |
306 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | 317 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
313 | 324 |
314 __gcov_indirect_call_counters = get_relevant_counter_ptr (); | 325 __gcov_indirect_call_counters = get_relevant_counter_ptr (); |
315 __gcov_indirect_call_callee = (void *) indirect call argument; | 326 __gcov_indirect_call_callee = (void *) indirect call argument; |
316 */ | 327 */ |
317 | 328 |
318 tmp1 = create_tmp_var (ptr_void, "PROF"); | 329 tmp1 = create_tmp_reg (ptr_void, "PROF"); |
319 stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr); | 330 stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr); |
320 stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value)); | 331 stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value)); |
321 stmt3 = gimple_build_assign (ic_void_ptr_var, tmp1); | 332 gimple_assign_set_lhs (stmt2, make_ssa_name (tmp1, stmt2)); |
333 stmt3 = gimple_build_assign (ic_void_ptr_var, gimple_assign_lhs (stmt2)); | |
322 | 334 |
323 gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); | 335 gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); |
324 gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); | 336 gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); |
325 gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT); | 337 gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT); |
326 } | 338 } |
329 /* Output instructions as GIMPLE trees for code to find the most | 341 /* Output instructions as GIMPLE trees for code to find the most |
330 common called function in indirect call. Insert instructions at the | 342 common called function in indirect call. Insert instructions at the |
331 beginning of every possible called function. | 343 beginning of every possible called function. |
332 */ | 344 */ |
333 | 345 |
334 static void | 346 void |
335 tree_gen_ic_func_profiler (void) | 347 gimple_gen_ic_func_profiler (void) |
336 { | 348 { |
337 struct cgraph_node * c_node = cgraph_node (current_function_decl); | 349 struct cgraph_node * c_node = cgraph_node (current_function_decl); |
338 gimple_stmt_iterator gsi; | 350 gimple_stmt_iterator gsi; |
339 edge e; | |
340 basic_block bb; | |
341 edge_iterator ei; | |
342 gimple stmt1, stmt2; | 351 gimple stmt1, stmt2; |
343 tree tree_uid, cur_func; | 352 tree tree_uid, cur_func, counter_ptr, ptr_var, void0; |
344 | 353 |
345 if (cgraph_only_called_directly_p (c_node)) | 354 if (cgraph_only_called_directly_p (c_node)) |
346 return; | 355 return; |
347 | 356 |
348 tree_init_edge_profiler (); | 357 gimple_init_edge_profiler (); |
349 | 358 |
350 FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) | 359 gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR)); |
351 { | 360 |
352 tree void0; | 361 cur_func = force_gimple_operand_gsi (&gsi, |
353 | 362 build_addr (current_function_decl, |
354 bb = split_edge (e); | 363 current_function_decl), |
355 gsi = gsi_start_bb (bb); | 364 true, NULL_TREE, |
356 | 365 true, GSI_SAME_STMT); |
357 cur_func = force_gimple_operand_gsi (&gsi, | 366 counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var, |
358 build_addr (current_function_decl, | 367 true, NULL_TREE, true, |
359 current_function_decl), | 368 GSI_SAME_STMT); |
360 true, NULL_TREE, | 369 ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var, |
361 true, GSI_SAME_STMT); | 370 true, NULL_TREE, true, |
362 tree_uid = build_int_cst (gcov_type_node, c_node->pid); | 371 GSI_SAME_STMT); |
363 stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4, | 372 tree_uid = build_int_cst (gcov_type_node, c_node->pid); |
364 ic_gcov_type_ptr_var, | 373 stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4, |
365 tree_uid, | 374 counter_ptr, tree_uid, cur_func, ptr_var); |
366 cur_func, | 375 gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT); |
367 ic_void_ptr_var); | 376 |
368 gsi_insert_after (&gsi, stmt1, GSI_NEW_STMT); | 377 /* Set __gcov_indirect_call_callee to 0, |
369 gcc_assert (EDGE_COUNT (bb->succs) == 1); | 378 so that calls from other modules won't get misattributed |
370 bb = split_edge (EDGE_I (bb->succs, 0)); | 379 to the last caller of the current callee. */ |
371 add_abnormal_goto_call_edges (gsi); | 380 void0 = build_int_cst (build_pointer_type (void_type_node), 0); |
372 | 381 stmt2 = gimple_build_assign (ic_void_ptr_var, void0); |
373 gsi = gsi_start_bb (bb); | 382 gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT); |
374 /* Set __gcov_indirect_call_callee to 0, | |
375 so that calls from other modules won't get misattributed | |
376 to the last caller of the current callee. */ | |
377 void0 = build_int_cst (build_pointer_type (void_type_node), 0); | |
378 stmt2 = gimple_build_assign (ic_void_ptr_var, void0); | |
379 gsi_insert_after (&gsi, stmt2, GSI_NEW_STMT); | |
380 } | |
381 } | 383 } |
382 | 384 |
383 /* Output instructions as GIMPLE trees for code to find the most common value | 385 /* Output instructions as GIMPLE trees for code to find the most common value |
384 of a difference between two evaluations of an expression. | 386 of a difference between two evaluations of an expression. |
385 VALUE is the expression whose value is profiled. TAG is the tag of the | 387 VALUE is the expression whose value is profiled. TAG is the tag of the |
386 section for counters, BASE is offset of the counter position. */ | 388 section for counters, BASE is offset of the counter position. */ |
387 | 389 |
388 static void | 390 void |
389 tree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED, | 391 gimple_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED, |
390 unsigned tag ATTRIBUTE_UNUSED, | 392 unsigned tag ATTRIBUTE_UNUSED, |
391 unsigned base ATTRIBUTE_UNUSED) | 393 unsigned base ATTRIBUTE_UNUSED) |
392 { | 394 { |
393 /* FIXME implement this. */ | 395 /* FIXME implement this. */ |
394 #ifdef ENABLE_CHECKING | 396 #ifdef ENABLE_CHECKING |
399 | 401 |
400 /* Output instructions as GIMPLE trees to increment the average histogram | 402 /* Output instructions as GIMPLE trees to increment the average histogram |
401 counter. VALUE is the expression whose value is profiled. TAG is the | 403 counter. VALUE is the expression whose value is profiled. TAG is the |
402 tag of the section for counters, BASE is offset of the counter position. */ | 404 tag of the section for counters, BASE is offset of the counter position. */ |
403 | 405 |
404 static void | 406 void |
405 tree_gen_average_profiler (histogram_value value, unsigned tag, unsigned base) | 407 gimple_gen_average_profiler (histogram_value value, unsigned tag, unsigned base) |
406 { | 408 { |
407 gimple stmt = value->hvalue.stmt; | 409 gimple stmt = value->hvalue.stmt; |
408 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | 410 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
409 tree ref_ptr = tree_coverage_counter_addr (tag, base); | 411 tree ref_ptr = tree_coverage_counter_addr (tag, base); |
410 gimple call; | 412 gimple call; |
414 true, NULL_TREE, | 416 true, NULL_TREE, |
415 true, GSI_SAME_STMT); | 417 true, GSI_SAME_STMT); |
416 val = prepare_instrumented_value (&gsi, value); | 418 val = prepare_instrumented_value (&gsi, value); |
417 call = gimple_build_call (tree_average_profiler_fn, 2, ref_ptr, val); | 419 call = gimple_build_call (tree_average_profiler_fn, 2, ref_ptr, val); |
418 gsi_insert_before (&gsi, call, GSI_NEW_STMT); | 420 gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
419 add_abnormal_goto_call_edges (gsi); | |
420 } | 421 } |
421 | 422 |
422 /* Output instructions as GIMPLE trees to increment the ior histogram | 423 /* Output instructions as GIMPLE trees to increment the ior histogram |
423 counter. VALUE is the expression whose value is profiled. TAG is the | 424 counter. VALUE is the expression whose value is profiled. TAG is the |
424 tag of the section for counters, BASE is offset of the counter position. */ | 425 tag of the section for counters, BASE is offset of the counter position. */ |
425 | 426 |
426 static void | 427 void |
427 tree_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base) | 428 gimple_gen_ior_profiler (histogram_value value, unsigned tag, unsigned base) |
428 { | 429 { |
429 gimple stmt = value->hvalue.stmt; | 430 gimple stmt = value->hvalue.stmt; |
430 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); | 431 gimple_stmt_iterator gsi = gsi_for_stmt (stmt); |
431 tree ref_ptr = tree_coverage_counter_addr (tag, base); | 432 tree ref_ptr = tree_coverage_counter_addr (tag, base); |
432 gimple call; | 433 gimple call; |
435 ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, | 436 ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr, |
436 true, NULL_TREE, true, GSI_SAME_STMT); | 437 true, NULL_TREE, true, GSI_SAME_STMT); |
437 val = prepare_instrumented_value (&gsi, value); | 438 val = prepare_instrumented_value (&gsi, value); |
438 call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val); | 439 call = gimple_build_call (tree_ior_profiler_fn, 2, ref_ptr, val); |
439 gsi_insert_before (&gsi, call, GSI_NEW_STMT); | 440 gsi_insert_before (&gsi, call, GSI_NEW_STMT); |
440 add_abnormal_goto_call_edges (gsi); | 441 } |
441 } | 442 |
442 | 443 /* Profile all functions in the callgraph. */ |
443 /* Return 1 if tree-based profiling is in effect, else 0. | |
444 If it is, set up hooks for tree-based profiling. | |
445 Gate for pass_tree_profile. */ | |
446 | |
447 static bool | |
448 do_tree_profiling (void) | |
449 { | |
450 if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities) | |
451 { | |
452 tree_register_profile_hooks (); | |
453 gimple_register_value_prof_hooks (); | |
454 return true; | |
455 } | |
456 return false; | |
457 } | |
458 | 444 |
459 static unsigned int | 445 static unsigned int |
460 tree_profiling (void) | 446 tree_profiling (void) |
461 { | 447 { |
448 struct cgraph_node *node; | |
449 | |
462 /* Don't profile functions produced at destruction time, particularly | 450 /* Don't profile functions produced at destruction time, particularly |
463 the gcov datastructure initializer. Don't profile if it has been | 451 the gcov datastructure initializer. Don't profile if it has been |
464 already instrumented either (when OpenMP expansion creates | 452 already instrumented either (when OpenMP expansion creates |
465 child function from already instrumented body). */ | 453 child function from already instrumented body). */ |
466 if (cgraph_state == CGRAPH_STATE_FINISHED | 454 if (cgraph_state == CGRAPH_STATE_FINISHED) |
467 || cfun->after_tree_profile) | |
468 return 0; | 455 return 0; |
469 | 456 |
470 /* Re-set global shared temporary variable for edge-counters. */ | 457 for (node = cgraph_nodes; node; node = node->next) |
471 gcov_type_tmp_var = NULL_TREE; | 458 { |
472 | 459 if (!node->analyzed |
473 branch_prob (); | 460 || !gimple_has_body_p (node->decl) |
474 | 461 || !(!node->clone_of || node->decl != node->clone_of->decl)) |
475 if (! flag_branch_probabilities | 462 continue; |
476 && flag_profile_values) | 463 |
477 tree_gen_ic_func_profiler (); | 464 /* Don't profile functions produced for builtin stuff. */ |
478 | 465 if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION |
479 if (flag_branch_probabilities | 466 || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) |
480 && flag_profile_values | 467 continue; |
481 && flag_value_profile_transformations) | 468 |
482 value_profile_transformations (); | 469 push_cfun (DECL_STRUCT_FUNCTION (node->decl)); |
483 /* The above could hose dominator info. Currently there is | 470 current_function_decl = node->decl; |
484 none coming in, this is a safety valve. It should be | 471 |
485 easy to adjust it, if and when there is some. */ | 472 /* Re-set global shared temporary variable for edge-counters. */ |
486 free_dominance_info (CDI_DOMINATORS); | 473 gcov_type_tmp_var = NULL_TREE; |
487 free_dominance_info (CDI_POST_DOMINATORS); | 474 |
488 cfun->after_tree_profile = 1; | 475 branch_prob (); |
476 | |
477 if (! flag_branch_probabilities | |
478 && flag_profile_values) | |
479 gimple_gen_ic_func_profiler (); | |
480 | |
481 if (flag_branch_probabilities | |
482 && flag_profile_values | |
483 && flag_value_profile_transformations) | |
484 gimple_value_profile_transformations (); | |
485 | |
486 /* The above could hose dominator info. Currently there is | |
487 none coming in, this is a safety valve. It should be | |
488 easy to adjust it, if and when there is some. */ | |
489 free_dominance_info (CDI_DOMINATORS); | |
490 free_dominance_info (CDI_POST_DOMINATORS); | |
491 | |
492 current_function_decl = NULL; | |
493 pop_cfun (); | |
494 } | |
495 | |
496 /* Drop pure/const flags from instrumented functions. */ | |
497 for (node = cgraph_nodes; node; node = node->next) | |
498 { | |
499 if (!node->analyzed | |
500 || !gimple_has_body_p (node->decl) | |
501 || !(!node->clone_of || node->decl != node->clone_of->decl)) | |
502 continue; | |
503 | |
504 /* Don't profile functions produced for builtin stuff. */ | |
505 if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION | |
506 || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) | |
507 continue; | |
508 | |
509 cgraph_set_const_flag (node, false, false); | |
510 cgraph_set_pure_flag (node, false, false); | |
511 } | |
512 | |
513 /* Update call statements and rebuild the cgraph. */ | |
514 for (node = cgraph_nodes; node; node = node->next) | |
515 { | |
516 basic_block bb; | |
517 | |
518 if (!node->analyzed | |
519 || !gimple_has_body_p (node->decl) | |
520 || !(!node->clone_of || node->decl != node->clone_of->decl)) | |
521 continue; | |
522 | |
523 /* Don't profile functions produced for builtin stuff. */ | |
524 if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION | |
525 || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) | |
526 continue; | |
527 | |
528 push_cfun (DECL_STRUCT_FUNCTION (node->decl)); | |
529 current_function_decl = node->decl; | |
530 | |
531 FOR_EACH_BB (bb) | |
532 { | |
533 gimple_stmt_iterator gsi; | |
534 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |
535 { | |
536 gimple stmt = gsi_stmt (gsi); | |
537 if (is_gimple_call (stmt)) | |
538 update_stmt (stmt); | |
539 } | |
540 } | |
541 | |
542 cfun->after_tree_profile = 1; | |
543 update_ssa (TODO_update_ssa); | |
544 | |
545 rebuild_cgraph_edges (); | |
546 | |
547 current_function_decl = NULL; | |
548 pop_cfun (); | |
549 } | |
550 | |
489 return 0; | 551 return 0; |
490 } | 552 } |
491 | 553 |
492 struct gimple_opt_pass pass_tree_profile = | 554 /* When profile instrumentation, use or test coverage shall be performed. */ |
555 | |
556 static bool | |
557 gate_tree_profile_ipa (void) | |
558 { | |
559 return (!in_lto_p | |
560 && (flag_branch_probabilities || flag_test_coverage | |
561 || profile_arc_flag)); | |
562 } | |
563 | |
564 struct simple_ipa_opt_pass pass_ipa_tree_profile = | |
493 { | 565 { |
494 { | 566 { |
495 GIMPLE_PASS, | 567 SIMPLE_IPA_PASS, |
496 "tree_profile", /* name */ | 568 "tree_profile_ipa", /* name */ |
497 do_tree_profiling, /* gate */ | 569 gate_tree_profile_ipa, /* gate */ |
498 tree_profiling, /* execute */ | 570 tree_profiling, /* execute */ |
499 NULL, /* sub */ | 571 NULL, /* sub */ |
500 NULL, /* next */ | 572 NULL, /* next */ |
501 0, /* static_pass_number */ | 573 0, /* static_pass_number */ |
502 TV_BRANCH_PROB, /* tv_id */ | 574 TV_IPA_PROFILE, /* tv_id */ |
503 PROP_gimple_leh | PROP_cfg, /* properties_required */ | 575 0, /* properties_required */ |
504 0, /* properties_provided */ | 576 0, /* properties_provided */ |
505 0, /* properties_destroyed */ | 577 0, /* properties_destroyed */ |
506 0, /* todo_flags_start */ | 578 0, /* todo_flags_start */ |
507 TODO_verify_stmts | TODO_dump_func /* todo_flags_finish */ | 579 TODO_dump_func /* todo_flags_finish */ |
508 } | 580 } |
509 }; | 581 }; |
510 | 582 |
511 struct profile_hooks tree_profile_hooks = | |
512 { | |
513 tree_init_edge_profiler, /* init_edge_profiler */ | |
514 tree_gen_edge_profiler, /* gen_edge_profiler */ | |
515 tree_gen_interval_profiler, /* gen_interval_profiler */ | |
516 tree_gen_pow2_profiler, /* gen_pow2_profiler */ | |
517 tree_gen_one_value_profiler, /* gen_one_value_profiler */ | |
518 tree_gen_const_delta_profiler, /* gen_const_delta_profiler */ | |
519 tree_gen_ic_profiler, /* gen_ic_profiler */ | |
520 tree_gen_average_profiler, /* gen_average_profiler */ | |
521 tree_gen_ior_profiler /* gen_ior_profiler */ | |
522 }; | |
523 | |
524 #include "gt-tree-profile.h" | 583 #include "gt-tree-profile.h" |