Mercurial > hg > CbC > CbC_gcc
comparison gcc/cgraphbuild.c @ 0:a06113de4d67
first commit
author | kent <kent@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2009 14:47:48 +0900 |
parents | |
children | 77e2b8dfacca |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a06113de4d67 |
---|---|
1 /* Callgraph construction. | |
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 | |
3 Free Software Foundation, Inc. | |
4 Contributed by Jan Hubicka | |
5 | |
6 This file is part of GCC. | |
7 | |
8 GCC is free software; you can redistribute it and/or modify it under | |
9 the terms of the GNU General Public License as published by the Free | |
10 Software Foundation; either version 3, or (at your option) any later | |
11 version. | |
12 | |
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with GCC; see the file COPYING3. If not see | |
20 <http://www.gnu.org/licenses/>. */ | |
21 | |
22 #include "config.h" | |
23 #include "system.h" | |
24 #include "coretypes.h" | |
25 #include "tm.h" | |
26 #include "tree.h" | |
27 #include "tree-flow.h" | |
28 #include "langhooks.h" | |
29 #include "pointer-set.h" | |
30 #include "cgraph.h" | |
31 #include "intl.h" | |
32 #include "gimple.h" | |
33 #include "tree-pass.h" | |
34 | |
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. */ | |
37 | |
38 static tree | |
39 record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) | |
40 { | |
41 tree t = *tp; | |
42 tree decl; | |
43 | |
44 switch (TREE_CODE (t)) | |
45 { | |
46 case VAR_DECL: | |
47 if (TREE_STATIC (t) || DECL_EXTERNAL (t)) | |
48 { | |
49 varpool_mark_needed_node (varpool_node (t)); | |
50 if (lang_hooks.callgraph.analyze_expr) | |
51 return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees); | |
52 } | |
53 break; | |
54 | |
55 case FDESC_EXPR: | |
56 case ADDR_EXPR: | |
57 /* Record dereferences to the functions. This makes the | |
58 functions reachable unconditionally. */ | |
59 decl = TREE_OPERAND (*tp, 0); | |
60 if (TREE_CODE (decl) == FUNCTION_DECL) | |
61 cgraph_mark_needed_node (cgraph_node (decl)); | |
62 break; | |
63 | |
64 default: | |
65 /* Save some cycles by not walking types and declaration as we | |
66 won't find anything useful there anyway. */ | |
67 if (IS_TYPE_OR_DECL_P (*tp)) | |
68 { | |
69 *walk_subtrees = 0; | |
70 break; | |
71 } | |
72 | |
73 if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE) | |
74 return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees); | |
75 break; | |
76 } | |
77 | |
78 return NULL_TREE; | |
79 } | |
80 | |
81 /* Give initial reasons why inlining would fail on all calls from | |
82 NODE. Those get either nullified or usually overwritten by more precise | |
83 reason later. */ | |
84 | |
85 static void | |
86 initialize_inline_failed (struct cgraph_node *node) | |
87 { | |
88 struct cgraph_edge *e; | |
89 | |
90 for (e = node->callers; e; e = e->next_caller) | |
91 { | |
92 gcc_assert (!e->callee->global.inlined_to); | |
93 gcc_assert (e->inline_failed); | |
94 if (node->local.redefined_extern_inline) | |
95 e->inline_failed = N_("redefined extern inline functions are not " | |
96 "considered for inlining"); | |
97 else if (!node->local.inlinable) | |
98 e->inline_failed = N_("function not inlinable"); | |
99 else if (gimple_call_cannot_inline_p (e->call_stmt)) | |
100 e->inline_failed = N_("mismatched arguments"); | |
101 else | |
102 e->inline_failed = N_("function not considered for inlining"); | |
103 } | |
104 } | |
105 | |
106 /* 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 int | |
109 compute_call_stmt_bb_frequency (basic_block bb) | |
110 { | |
111 int entry_freq = ENTRY_BLOCK_PTR->frequency; | |
112 int freq = bb->frequency; | |
113 | |
114 if (!entry_freq) | |
115 entry_freq = 1, freq++; | |
116 | |
117 freq = freq * CGRAPH_FREQ_BASE / entry_freq; | |
118 if (freq > CGRAPH_FREQ_MAX) | |
119 freq = CGRAPH_FREQ_MAX; | |
120 | |
121 return freq; | |
122 } | |
123 | |
124 /* Create cgraph edges for function calls. | |
125 Also look for functions and variables having addresses taken. */ | |
126 | |
127 static unsigned int | |
128 build_cgraph_edges (void) | |
129 { | |
130 basic_block bb; | |
131 struct cgraph_node *node = cgraph_node (current_function_decl); | |
132 struct pointer_set_t *visited_nodes = pointer_set_create (); | |
133 gimple_stmt_iterator gsi; | |
134 tree step; | |
135 | |
136 /* Create the callgraph edges and record the nodes referenced by the function. | |
137 body. */ | |
138 FOR_EACH_BB (bb) | |
139 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |
140 { | |
141 gimple stmt = gsi_stmt (gsi); | |
142 tree decl; | |
143 | |
144 if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) | |
145 { | |
146 size_t i; | |
147 size_t n = gimple_call_num_args (stmt); | |
148 cgraph_create_edge (node, cgraph_node (decl), stmt, | |
149 bb->count, compute_call_stmt_bb_frequency (bb), | |
150 bb->loop_depth); | |
151 for (i = 0; i < n; i++) | |
152 walk_tree (gimple_call_arg_ptr (stmt, i), record_reference, | |
153 node, visited_nodes); | |
154 if (gimple_call_lhs (stmt)) | |
155 walk_tree (gimple_call_lhs_ptr (stmt), record_reference, node, | |
156 visited_nodes); | |
157 } | |
158 else | |
159 { | |
160 struct walk_stmt_info wi; | |
161 memset (&wi, 0, sizeof (wi)); | |
162 wi.info = node; | |
163 wi.pset = visited_nodes; | |
164 walk_gimple_op (stmt, record_reference, &wi); | |
165 if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL | |
166 && gimple_omp_parallel_child_fn (stmt)) | |
167 { | |
168 tree fn = gimple_omp_parallel_child_fn (stmt); | |
169 cgraph_mark_needed_node (cgraph_node (fn)); | |
170 } | |
171 if (gimple_code (stmt) == GIMPLE_OMP_TASK) | |
172 { | |
173 tree fn = gimple_omp_task_child_fn (stmt); | |
174 if (fn) | |
175 cgraph_mark_needed_node (cgraph_node (fn)); | |
176 fn = gimple_omp_task_copy_fn (stmt); | |
177 if (fn) | |
178 cgraph_mark_needed_node (cgraph_node (fn)); | |
179 } | |
180 } | |
181 } | |
182 | |
183 /* Look for initializers of constant variables and private statics. */ | |
184 for (step = cfun->local_decls; | |
185 step; | |
186 step = TREE_CHAIN (step)) | |
187 { | |
188 tree decl = TREE_VALUE (step); | |
189 if (TREE_CODE (decl) == VAR_DECL | |
190 && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl))) | |
191 varpool_finalize_decl (decl); | |
192 else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl)) | |
193 walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes); | |
194 } | |
195 | |
196 pointer_set_destroy (visited_nodes); | |
197 initialize_inline_failed (node); | |
198 return 0; | |
199 } | |
200 | |
201 struct gimple_opt_pass pass_build_cgraph_edges = | |
202 { | |
203 { | |
204 GIMPLE_PASS, | |
205 NULL, /* name */ | |
206 NULL, /* gate */ | |
207 build_cgraph_edges, /* execute */ | |
208 NULL, /* sub */ | |
209 NULL, /* next */ | |
210 0, /* static_pass_number */ | |
211 0, /* tv_id */ | |
212 PROP_cfg, /* properties_required */ | |
213 0, /* properties_provided */ | |
214 0, /* properties_destroyed */ | |
215 0, /* todo_flags_start */ | |
216 0 /* todo_flags_finish */ | |
217 } | |
218 }; | |
219 | |
220 /* Record references to functions and other variables present in the | |
221 initial value of DECL, a variable. */ | |
222 | |
223 void | |
224 record_references_in_initializer (tree decl) | |
225 { | |
226 struct pointer_set_t *visited_nodes = pointer_set_create (); | |
227 walk_tree (&DECL_INITIAL (decl), record_reference, NULL, visited_nodes); | |
228 pointer_set_destroy (visited_nodes); | |
229 } | |
230 | |
231 /* Rebuild cgraph edges for current function node. This needs to be run after | |
232 passes that don't update the cgraph. */ | |
233 | |
234 unsigned int | |
235 rebuild_cgraph_edges (void) | |
236 { | |
237 basic_block bb; | |
238 struct cgraph_node *node = cgraph_node (current_function_decl); | |
239 gimple_stmt_iterator gsi; | |
240 | |
241 cgraph_node_remove_callees (node); | |
242 | |
243 node->count = ENTRY_BLOCK_PTR->count; | |
244 | |
245 FOR_EACH_BB (bb) | |
246 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |
247 { | |
248 gimple stmt = gsi_stmt (gsi); | |
249 tree decl; | |
250 | |
251 if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt))) | |
252 cgraph_create_edge (node, cgraph_node (decl), stmt, | |
253 bb->count, compute_call_stmt_bb_frequency (bb), | |
254 bb->loop_depth); | |
255 | |
256 } | |
257 initialize_inline_failed (node); | |
258 gcc_assert (!node->global.inlined_to); | |
259 return 0; | |
260 } | |
261 | |
262 struct gimple_opt_pass pass_rebuild_cgraph_edges = | |
263 { | |
264 { | |
265 GIMPLE_PASS, | |
266 NULL, /* name */ | |
267 NULL, /* gate */ | |
268 rebuild_cgraph_edges, /* execute */ | |
269 NULL, /* sub */ | |
270 NULL, /* next */ | |
271 0, /* static_pass_number */ | |
272 0, /* tv_id */ | |
273 PROP_cfg, /* properties_required */ | |
274 0, /* properties_provided */ | |
275 0, /* properties_destroyed */ | |
276 0, /* todo_flags_start */ | |
277 0, /* todo_flags_finish */ | |
278 } | |
279 }; |