Mercurial > hg > CbC > CbC_gcc
comparison gcc/cgraphbuild.c @ 55:77e2b8dfacca gcc-4.4.5
update it from 4.4.3 to 4.5.0
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 12 Feb 2010 23:39:51 +0900 |
parents | a06113de4d67 |
children | b7f97abdc517 |
comparison
equal
deleted
inserted
replaced
52:c156f1bd5cd9 | 55:77e2b8dfacca |
---|---|
1 /* Callgraph construction. | 1 /* Callgraph construction. |
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 | 2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
3 Free Software Foundation, Inc. | 3 Free Software Foundation, Inc. |
4 Contributed by Jan Hubicka | 4 Contributed by Jan Hubicka |
5 | 5 |
6 This file is part of GCC. | 6 This file is part of GCC. |
7 | 7 |
31 #include "intl.h" | 31 #include "intl.h" |
32 #include "gimple.h" | 32 #include "gimple.h" |
33 #include "tree-pass.h" | 33 #include "tree-pass.h" |
34 | 34 |
35 /* Walk tree and record all calls and references to functions/variables. | 35 /* Walk tree and record all calls and references to functions/variables. |
36 Called via walk_tree: TP is pointer to tree to be examined. */ | 36 Called via walk_tree: TP is pointer to tree to be examined. |
37 When DATA is non-null, record references to callgraph. | |
38 */ | |
37 | 39 |
38 static tree | 40 static tree |
39 record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) | 41 record_reference (tree *tp, int *walk_subtrees, void *data) |
40 { | 42 { |
41 tree t = *tp; | 43 tree t = *tp; |
42 tree decl; | 44 tree decl; |
45 bool do_callgraph = data != NULL; | |
43 | 46 |
44 switch (TREE_CODE (t)) | 47 switch (TREE_CODE (t)) |
45 { | 48 { |
46 case VAR_DECL: | 49 case VAR_DECL: |
47 if (TREE_STATIC (t) || DECL_EXTERNAL (t)) | 50 if (TREE_STATIC (t) || DECL_EXTERNAL (t)) |
55 case FDESC_EXPR: | 58 case FDESC_EXPR: |
56 case ADDR_EXPR: | 59 case ADDR_EXPR: |
57 /* Record dereferences to the functions. This makes the | 60 /* Record dereferences to the functions. This makes the |
58 functions reachable unconditionally. */ | 61 functions reachable unconditionally. */ |
59 decl = TREE_OPERAND (*tp, 0); | 62 decl = TREE_OPERAND (*tp, 0); |
60 if (TREE_CODE (decl) == FUNCTION_DECL) | 63 if (TREE_CODE (decl) == FUNCTION_DECL && do_callgraph) |
61 cgraph_mark_needed_node (cgraph_node (decl)); | 64 cgraph_mark_address_taken_node (cgraph_node (decl)); |
62 break; | 65 break; |
63 | 66 |
64 default: | 67 default: |
65 /* Save some cycles by not walking types and declaration as we | 68 /* Save some cycles by not walking types and declaration as we |
66 won't find anything useful there anyway. */ | 69 won't find anything useful there anyway. */ |
76 } | 79 } |
77 | 80 |
78 return NULL_TREE; | 81 return NULL_TREE; |
79 } | 82 } |
80 | 83 |
81 /* Give initial reasons why inlining would fail on all calls from | 84 /* Reset inlining information of all incoming call edges of NODE. */ |
82 NODE. Those get either nullified or usually overwritten by more precise | 85 |
83 reason later. */ | 86 void |
84 | 87 reset_inline_failed (struct cgraph_node *node) |
85 static void | |
86 initialize_inline_failed (struct cgraph_node *node) | |
87 { | 88 { |
88 struct cgraph_edge *e; | 89 struct cgraph_edge *e; |
89 | 90 |
90 for (e = node->callers; e; e = e->next_caller) | 91 for (e = node->callers; e; e = e->next_caller) |
91 { | 92 { |
92 gcc_assert (!e->callee->global.inlined_to); | 93 e->callee->global.inlined_to = NULL; |
93 gcc_assert (e->inline_failed); | 94 if (!node->analyzed) |
94 if (node->local.redefined_extern_inline) | 95 e->inline_failed = CIF_BODY_NOT_AVAILABLE; |
95 e->inline_failed = N_("redefined extern inline functions are not " | 96 else if (node->local.redefined_extern_inline) |
96 "considered for inlining"); | 97 e->inline_failed = CIF_REDEFINED_EXTERN_INLINE; |
97 else if (!node->local.inlinable) | 98 else if (!node->local.inlinable) |
98 e->inline_failed = N_("function not inlinable"); | 99 e->inline_failed = CIF_FUNCTION_NOT_INLINABLE; |
99 else if (gimple_call_cannot_inline_p (e->call_stmt)) | 100 else if (e->call_stmt_cannot_inline_p) |
100 e->inline_failed = N_("mismatched arguments"); | 101 e->inline_failed = CIF_MISMATCHED_ARGUMENTS; |
101 else | 102 else |
102 e->inline_failed = N_("function not considered for inlining"); | 103 e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED; |
103 } | 104 } |
104 } | 105 } |
105 | 106 |
106 /* Computes the frequency of the call statement so that it can be stored in | 107 /* Computes the frequency of the call statement so that it can be stored in |
107 cgraph_edge. BB is the basic block of the call statement. */ | 108 cgraph_edge. BB is the basic block of the call statement. */ |
108 int | 109 int |
109 compute_call_stmt_bb_frequency (basic_block bb) | 110 compute_call_stmt_bb_frequency (tree decl, basic_block bb) |
110 { | 111 { |
111 int entry_freq = ENTRY_BLOCK_PTR->frequency; | 112 int entry_freq = ENTRY_BLOCK_PTR_FOR_FUNCTION |
113 (DECL_STRUCT_FUNCTION (decl))->frequency; | |
112 int freq = bb->frequency; | 114 int freq = bb->frequency; |
115 | |
116 if (profile_status_for_function (DECL_STRUCT_FUNCTION (decl)) == PROFILE_ABSENT) | |
117 return CGRAPH_FREQ_BASE; | |
113 | 118 |
114 if (!entry_freq) | 119 if (!entry_freq) |
115 entry_freq = 1, freq++; | 120 entry_freq = 1, freq++; |
116 | 121 |
117 freq = freq * CGRAPH_FREQ_BASE / entry_freq; | 122 freq = freq * CGRAPH_FREQ_BASE / entry_freq; |
144 if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) | 149 if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) |
145 { | 150 { |
146 size_t i; | 151 size_t i; |
147 size_t n = gimple_call_num_args (stmt); | 152 size_t n = gimple_call_num_args (stmt); |
148 cgraph_create_edge (node, cgraph_node (decl), stmt, | 153 cgraph_create_edge (node, cgraph_node (decl), stmt, |
149 bb->count, compute_call_stmt_bb_frequency (bb), | 154 bb->count, compute_call_stmt_bb_frequency (current_function_decl, bb), |
150 bb->loop_depth); | 155 bb->loop_depth); |
151 for (i = 0; i < n; i++) | 156 for (i = 0; i < n; i++) |
152 walk_tree (gimple_call_arg_ptr (stmt, i), record_reference, | 157 walk_tree (gimple_call_arg_ptr (stmt, i), record_reference, |
153 node, visited_nodes); | 158 node, visited_nodes); |
154 if (gimple_call_lhs (stmt)) | 159 if (gimple_call_lhs (stmt)) |
192 else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl)) | 197 else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl)) |
193 walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes); | 198 walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes); |
194 } | 199 } |
195 | 200 |
196 pointer_set_destroy (visited_nodes); | 201 pointer_set_destroy (visited_nodes); |
197 initialize_inline_failed (node); | |
198 return 0; | 202 return 0; |
199 } | 203 } |
200 | 204 |
201 struct gimple_opt_pass pass_build_cgraph_edges = | 205 struct gimple_opt_pass pass_build_cgraph_edges = |
202 { | 206 { |
203 { | 207 { |
204 GIMPLE_PASS, | 208 GIMPLE_PASS, |
205 NULL, /* name */ | 209 "*build_cgraph_edges", /* name */ |
206 NULL, /* gate */ | 210 NULL, /* gate */ |
207 build_cgraph_edges, /* execute */ | 211 build_cgraph_edges, /* execute */ |
208 NULL, /* sub */ | 212 NULL, /* sub */ |
209 NULL, /* next */ | 213 NULL, /* next */ |
210 0, /* static_pass_number */ | 214 0, /* static_pass_number */ |
211 0, /* tv_id */ | 215 TV_NONE, /* tv_id */ |
212 PROP_cfg, /* properties_required */ | 216 PROP_cfg, /* properties_required */ |
213 0, /* properties_provided */ | 217 0, /* properties_provided */ |
214 0, /* properties_destroyed */ | 218 0, /* properties_destroyed */ |
215 0, /* todo_flags_start */ | 219 0, /* todo_flags_start */ |
216 0 /* todo_flags_finish */ | 220 0 /* todo_flags_finish */ |
217 } | 221 } |
218 }; | 222 }; |
219 | 223 |
220 /* Record references to functions and other variables present in the | 224 /* Record references to functions and other variables present in the |
221 initial value of DECL, a variable. */ | 225 initial value of DECL, a variable. |
226 When ONLY_VARS is true, we mark needed only variables, not functions. */ | |
222 | 227 |
223 void | 228 void |
224 record_references_in_initializer (tree decl) | 229 record_references_in_initializer (tree decl, bool only_vars) |
225 { | 230 { |
226 struct pointer_set_t *visited_nodes = pointer_set_create (); | 231 struct pointer_set_t *visited_nodes = pointer_set_create (); |
227 walk_tree (&DECL_INITIAL (decl), record_reference, NULL, visited_nodes); | 232 walk_tree (&DECL_INITIAL (decl), record_reference, |
233 only_vars ? NULL : decl, visited_nodes); | |
228 pointer_set_destroy (visited_nodes); | 234 pointer_set_destroy (visited_nodes); |
229 } | 235 } |
230 | 236 |
231 /* Rebuild cgraph edges for current function node. This needs to be run after | 237 /* Rebuild cgraph edges for current function node. This needs to be run after |
232 passes that don't update the cgraph. */ | 238 passes that don't update the cgraph. */ |
248 gimple stmt = gsi_stmt (gsi); | 254 gimple stmt = gsi_stmt (gsi); |
249 tree decl; | 255 tree decl; |
250 | 256 |
251 if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) | 257 if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) |
252 cgraph_create_edge (node, cgraph_node (decl), stmt, | 258 cgraph_create_edge (node, cgraph_node (decl), stmt, |
253 bb->count, compute_call_stmt_bb_frequency (bb), | 259 bb->count, |
260 compute_call_stmt_bb_frequency | |
261 (current_function_decl, bb), | |
254 bb->loop_depth); | 262 bb->loop_depth); |
255 | 263 |
256 } | 264 } |
257 initialize_inline_failed (node); | |
258 gcc_assert (!node->global.inlined_to); | 265 gcc_assert (!node->global.inlined_to); |
266 | |
259 return 0; | 267 return 0; |
260 } | 268 } |
261 | 269 |
262 struct gimple_opt_pass pass_rebuild_cgraph_edges = | 270 struct gimple_opt_pass pass_rebuild_cgraph_edges = |
263 { | 271 { |
264 { | 272 { |
265 GIMPLE_PASS, | 273 GIMPLE_PASS, |
266 NULL, /* name */ | 274 "*rebuild_cgraph_edges", /* name */ |
267 NULL, /* gate */ | 275 NULL, /* gate */ |
268 rebuild_cgraph_edges, /* execute */ | 276 rebuild_cgraph_edges, /* execute */ |
269 NULL, /* sub */ | 277 NULL, /* sub */ |
270 NULL, /* next */ | 278 NULL, /* next */ |
271 0, /* static_pass_number */ | 279 0, /* static_pass_number */ |
272 0, /* tv_id */ | 280 TV_NONE, /* tv_id */ |
273 PROP_cfg, /* properties_required */ | 281 PROP_cfg, /* properties_required */ |
274 0, /* properties_provided */ | 282 0, /* properties_provided */ |
275 0, /* properties_destroyed */ | 283 0, /* properties_destroyed */ |
276 0, /* todo_flags_start */ | 284 0, /* todo_flags_start */ |
277 0, /* todo_flags_finish */ | 285 0, /* todo_flags_finish */ |
278 } | 286 } |
279 }; | 287 }; |
288 | |
289 | |
290 static unsigned int | |
291 remove_cgraph_callee_edges (void) | |
292 { | |
293 cgraph_node_remove_callees (cgraph_node (current_function_decl)); | |
294 return 0; | |
295 } | |
296 | |
297 struct gimple_opt_pass pass_remove_cgraph_callee_edges = | |
298 { | |
299 { | |
300 GIMPLE_PASS, | |
301 "*remove_cgraph_callee_edges", /* name */ | |
302 NULL, /* gate */ | |
303 remove_cgraph_callee_edges, /* execute */ | |
304 NULL, /* sub */ | |
305 NULL, /* next */ | |
306 0, /* static_pass_number */ | |
307 TV_NONE, /* tv_id */ | |
308 0, /* properties_required */ | |
309 0, /* properties_provided */ | |
310 0, /* properties_destroyed */ | |
311 0, /* todo_flags_start */ | |
312 0, /* todo_flags_finish */ | |
313 } | |
314 }; |