After cgraph_varpool_assemble_pending_decls emits assemble for all pending variables (note that they are visible out of the translation-unit), returns cgraph_finalize_compilation_unit and begins analyzing the translation-unit.
cgraph_finalize_compilation_unit (continue)
383 timevar_push (TV_CGRAPH);
384 if (cgraph_dump_file )
385 {
386 fprintf (cgraph_dump_file , "Initial entry points:");
387 for (node = cgraph_nodes ; node; node = node->next)
388 if (node->needed && DECL_SAVED_TREE (node->decl))
389 fprintf (cgraph_dump_file , " %s", cgraph_node_name (node));
390 fprintf (cgraph_dump_file , "/n");
391 }
392
393 /* Propagate reachability flag and lower representation of all reachable
394 functions. In the future, lowering will introduce new functions and
395 new entry points on the way (by template instantiation and virtual
396 method table generation for instance). */
397 while (cgraph_nodes_queue )
398 {
399 struct cgraph_edge *edge;
400 tree decl = cgraph_nodes_queue ->decl;
401
402 node = cgraph_nodes_queue;
403 cgraph_nodes_queue = cgraph_nodes_queue ->next_needed;
404
405 /* ??? It is possible to create extern inline function and later using
406 weak alas attribute to kill it's body. See
407 gcc.c-torture/compile/20011119-1.c */
408 if (!DECL_SAVED_TREE (decl))
409 continue ;
410
411 if (node->analyzed || !node->reachable || !DECL_SAVED_TREE (decl))
412 abort ();
413
414 cgraph_analyze_function (node);
415
416 for (edge = node->callees; edge; edge = edge->next_callee)
417 if (!edge->callee->reachable)
418 cgraph_mark_reachable_node (edge->callee);
419
420 cgraph_varpool_assemble_pending_decls ();
421 }
Queue cgraph_nodes_queue records cgraph_node associating with the function.
DECL_SAVED_TREE is the intermediate tree representing the function-body. In some circumstance, it may be empty, for example in function template, so above condition at line 408 to filter out all functions with function-body unknown. Line 411 is a sainty check, if it is satisfied, means the compiler has something wrong.
319 static void
320 cgraph_analyze_function (struct cgraph_node *node) in cgraphunit.c
321 {
322 tree decl = node->decl;
323 struct cgraph_edge *e;
324
325 current_function_decl = decl;
326
327 /* First kill forward declaration so reverse inlining works properly. */
328 cgraph_create_edges (decl, DECL_SAVED_TREE (decl));
Note, in below procedure, it may append to cgraph_nodes_queue , thus all functions visited would get handled.
Below, cgraph_create_edges iterates the function-body, creates cgraph_* nodes for those candidates without them, and appends them to corresponding queues.
306 void
307 cgraph_create_edges (tree decl, tree body) in cgraphunit.c
308 {
309 /* The nodes we're interested in are never shared, so walk
310 the tree ignoring duplicates. */
311 visited_nodes = htab_create (37, htab_hash_pointer ,
312 htab_eq_pointer , NULL);
313 walk_tree (&body, record_call_1 , decl, visited_nodes );
314 htab_delete (visited_nodes );
315 visited_nodes = NULL;
316 }
We have seen before, in walk_tree , once the function passed as its argument returns non-null value, the iteration will be terminated. Here, record_call_1 always returns NULL, and forces walk_tree to do the full iteration as possible.
240 static tree
241 record_call_1 (tree *tp, int *walk_subtrees, void *data) in cgraphunit.c
242 {
243 tree t = *tp;
244
245 switch (TREE_CODE (t))
246 {
247 case VAR_DECL:
248 /* ??? Really, we should mark this decl as *potentially* referenced
249 by this function and re-examine whether the decl is actually used
250 after rtl has been generated. */
251 if (TREE_STATIC (t))
252 cgraph_varpool_mark_needed_node (cgraph_varpool_node (t));
253 break ;
254
255 case ADDR_EXPR:
256 if (flag_unit_at_a_time )
257 {
258 /* Record dereferences to the functions. This makes the
259 functions reachable unconditionally. */
260 tree decl = TREE_OPERAND (*tp, 0);
261 if (TREE_CODE (decl) == FUNCTION_DECL)
262 cgraph_mark_needed_node (cgraph_node (decl));
263 }
264 break ;
As global variable is visible outside of the translation-unit (TREE_PUBLIC holds), output it anyhow (eliminating unused global variables can be done by linker, which is a feature GCC will implement). And the visibility of static variable is only confined in the file declaring it, or files including the defining file, once it is unused, the compiler can eliminate it from assembler code.
(Keep in mind that cgraph_* nodes are only used for analyzing functions, global or static variables; local variables as only locates in the defining function, needn’t such “heavy weapons”). At line 252, sets the variable as “needed”, and if its associated front-end node is completed, adds the cgraph_varpool_node into cgraph_varpool_nodes_queue queue. Note that function called at line 252 can guarantee every variable would only be added once (needed and finalized fields of cgraph_varpool_node of every added variable are 1, prevents it from adding again).
For ADD_EXPR at line 255, if it is the reference of variable address, it needs not handle here, when record_call_1 enters its operands, the associated VAR_DECL node will be found and processed. What needs treatment is function, see that it just stands for referring the function address, not invoke, and if its associated front-end node is completed, and adds it into queue cgraph_nodes_queue . Similarly, the insertion guarantees once addition too.
record_call_1 (continue)
266 case CALL_EXPR:
267 {
268 tree decl = get_callee_fndecl (*tp);
269 if (decl && TREE_CODE (decl) == FUNCTION_DECL)
270 {
271 cgraph_record_call (data, decl);
272
273 /* When we see a function call, we don't want to look at the
274 function reference in the ADDR_EXPR that is hanging from
275 the CALL_EXPR we're examining here, because we would
276 conclude incorrectly that the function's address could be
277 taken by something that is not a function call. So only
278 walk the function parameter list, skip the other subtrees. */
279
280 walk_tree (&TREE_OPERAND (*tp, 1), record_call_1 , data,
281 visited_nodes );
282 *walk_subtrees = 0;
283 }
284 break ;
285 }
Next is the handling of function invocation. It gets the node representing function invocation at line 268, as in analysis using cgraph, it needs generate map of call-relation among functions (see section Graph of relation between caller and callee ).
295 struct cgraph_edge *
296 cgraph_record_call (tree caller, tree callee) in cgraph.c
297 {
298 return create_edge (cgraph_node (caller), cgraph_node (callee));
299 }
Here note that, at line 271, argument data (that is parameter caller ) is the FUNCTION_DECL node of the function under analyzing (it is parameter decl of cgraph_create_edges ).
154 static struct cgraph_edge *
155 create_edge (struct cgraph_node *caller, struct cgraph_node *callee) in cgraph.c
156 {
157 struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge));
158 struct cgraph_edge *edge2;
159
160 if (!DECL_SAVED_TREE (callee->decl))
161 edge->inline_failed = N_("function body not available");
162 else if (callee->local.redefined_extern_inline)
163 edge->inline_failed = N_("redefined extern inline functions are not "
164 "considered for inlining");
165 else if (callee->local.inlinable)
166 edge->inline_failed = N_("function not considered for inlining");
167 else
168 edge->inline_failed = N_("function not inlinable");
169
170 /* At the moment we don't associate calls with specific CALL_EXPRs
171 as we probably ought to, so we must preserve inline_call flags to
172 be the same in all copies of the same edge. */
173 if (cgraph_global_info_ready )
174 for (edge2 = caller->callees; edge2; edge2 = edge2->next_callee)
175 if (edge2->callee == callee)
176 {
177 edge->inline_failed = edge2->inline_failed;
178 break ;
179 }
180
181 edge->caller = caller;
182 edge->callee = callee;
183 edge->next_caller = callee->callers;
184 edge->next_callee = caller->callees;
185 caller->callees = edge;
186 callee->callers = edge;
187 return edge;
188 }
See in previous (section Graph of relation between caller and callee ), cgraph_edge is used to bind cgraph_node of the caller and callee. The callee may have been analyzed already, then set the cgraph_edge accordingly. Further, once analyzing the translation-unit, cgraph_global_info_ready will be set as 1, at which time need traverse all callees of the function (next_callee chains all callees), and check if existing the cgraph_edge (line 175 condition).
At line 280, the second operand of CALL_EXPR is its arguments list, walk_tree next visits it. And at line 281, walk_subtrees is set as 0, which indicates that subtree under this CALL_EXPR is irrelevant.
record_call_1 (continue)
287 default :
288 /* Save some cycles by not walking types and declaration as we
289 won't find anything useful there anyway. */
290 if (DECL_P (*tp) || TYPE_P (*tp))
291 {
292 *walk_subtrees = 0;
293 break ;
294 }
295
296 if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE)
297 return (*lang_hooks .callgraph.analyze_expr ) (tp, walk_subtrees, data);
298 break ;
299 }
300
301 return NULL;
302 }
Similarly, in function analyzing, we don’t care about type and declaration, which are skipped at line 292. The common used code in front-end is ended at LAST_AND_UNUSED_TREE_CODE (not include), which is followed by those used by the language. Obvious, such nodes should be processed via language hooks.
2497 tree
2498 cxx_callgraph_analyze_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, in decl2.c
2499 tree from ATTRIBUTE_UNUSED)
2500 {
2501 tree t = *tp;
2502
2503 if (flag_unit_at_a_time )
2504 switch (TREE_CODE (t))
2505 {
2506 case PTRMEM_CST:
2507 if (TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
2508 cgraph_mark_needed_node (cgraph_node (PTRMEM_CST_MEMBER (t)));
2509 break ;
2510 case BASELINK:
2511 if (TREE_CODE (BASELINK_FUNCTIONS (t)) == FUNCTION_DECL)
2512 cgraph_mark_needed_node (cgraph_node (BASELINK_FUNCTIONS (t)));
2513 break ;
2514
2515 default :
2516 break ;
2517 }
2518
2519 return NULL;
2520 }
For C++, what needs handle is the reference of address of method, and the access of member of the base from the derived class.