GCC-3.4.6源代码学习笔记(173)
来源:互联网 发布:中控门禁系统数据库 编辑:程序博客网 时间:2024/05/21 06:39
5.13.5.3. 分析编译单元
在cgraph_varpool_assemble_pending_decls为所有待定变量(注意它们是编译单元外可见)发布汇编后,回到cgraph_finalize_compilation_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 lowerrepresentation of all reachable
394 functions. In the future, lowering willintroduce new functions and
395 new entry points on the way (by templateinstantiation 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 inlinefunction 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 }
队列cgraph_nodes_queue记录了与函数关联的cgraph_node节点。
5.13.5.3.1. 分析函数
5.13.5.3.1.1. 构建函数调用图
DECL_SAVED_TREE是代表函数体的中间树。在某些情况下,它可能为空,比如在函数模板中,因此上面408行的条件挑出了所有的函数体尚不确定的函数定义。411行是一个合法性检查,满足此条件说明编译器出问题了。
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 reverseinlining works properly. */
328 cgraph_create_edges (decl,DECL_SAVED_TREE (decl));
注意,在下面的过程中,将可能向cgraph_nodes_queue中加入节点,这样所有在程序中被访问到的函数都会得到处理。
下面的cgraph_create_edges遍历指定的函数体,为尚未构建cgraph_*节点的合适对象构建cgraph_*节点,并加入相应的队列中。
306 void
307 cgraph_create_edges (tree decl, tree body) in cgraphunit.c
308 {
309 /* The nodes we're interested in are nevershared, 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 }
前面我们已经看到,在walk_tree中,一旦作为其参数的函数返回非0值,就会退出遍历。这里,record_call_1总是返回NULL,强制walk_tree尽可能完成完整的遍历。
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 thedecl 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. Thismakes 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;
全局变量因为在编译单元外可见(TREE_PUBLIC成立),不管怎样都要输出它(消除未使用的全局变量只能由链接器完成,这是GCC将要构想的一个特性)。而静态变量的可访问性仅局限于声明它的文件,及包含其声明文件的文件中,一旦发现它没有被使用,编译器即可从产生的汇编代码将其删除。
(记住cgraph_*节点仅用于函数,全局及静态变量的分析,局部变量因为局限在某个函数,用不着这么“重型的武器”)。在252行,把变量设置为是需要的,并且如果其前端节点已完成,就把它加入cgraph_varpool_nodes_queue队列。注意252行所调用的函数能确保每个变量只会被加入一次(每个加入的变量其cgraph_varpool_node节点的needed及finalized域都将是1,防止它被再次加入)。
对于255行的ADD_EXPR,如果是对变量的地址引用,这里不用处理,等record_call_1进入其操作数后,自然会见到相应地VAR_DECL节点并处理之。需要处理的是函数,注意这里只是表示了对函数地址的引用,并不是调用。同样把这个函数节点为需要的,并且如果其前端节点已完成,就把它加入cgraph_nodes_queue队列。同样,这里也能确保每个需要的函数只加入一次。
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 wesee a function call, we don't want to look at the
274 function reference in the ADDR_EXPR thatis hanging from
275 the CALL_EXPR we're examining here,because we would
276 conclude incorrectly that the function'saddress could be
277 taken by something that is not afunction call. So only
278 walk the function parameter list, skipthe 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 }
接着就是对函数调用的处理。在268行得到代表被调用函数声明的节点,在使用cgraph分析时,需要构建函数间的调用关系图(参考函数调用关系图一节)。
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 }
这里注意,271行的实参data(即参数caller)是被分析函数的FUNCTION_DECL节点(它是cgraph_create_edges的参数decl)。
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 arenot "
164 "considered forinlining");
165 else if (callee->local.inlinable)
166 edge->inline_failed = N_("function not considered forinlining");
167 else
168 edge->inline_failed = N_("function not inlinable");
169
170 /* At the moment we don't associate calls withspecific CALL_EXPRs
171 as we probably ought to, so we must preserveinline_call flags to
172 be the same in all copies of the sameedge. */
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 }
前面已经知道(函数调用关系图一节),cgraph_edge用于绑定调用者及被调用者的cgraph_node节点。被调用者可能已经被分析过了,那么相应设置cgraph_edge。另外,在完成了编译单元的分析后,cgraph_global_info_ready将被置为1,这时就要遍历该函数所调用的函数(next_callee把所有被该函数调用的函数链接起来),检查是否已经有该cgraph_edge(175行的条件)。
在280行,CALL_EXPR的第二个操作数是其实参列表,walk_tree进而遍历之。而在281行,walk_subtrees被设置为0,表示该CALL_EXPR子树以下部分已无关重要。
record_call_1 (continue)
287 default:
288 /* Save some cycles by not walking types anddeclaration 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 }
同样,对于函数分析,我们不关心类型及变量声明,因此在292行跳过之。前端公用的中间树节点的编码由LAST_AND_UNUSED_TREE_CODE结尾(不包括),语言自用的部分跟在其后。显然,这部分节点只能由语言钩子来处理。
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 casePTRMEM_CST:
2507 if (TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
2508 cgraph_mark_needed_node(cgraph_node (PTRMEM_CST_MEMBER (t)));
2509 break;
2510 caseBASELINK:
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 }
对于C++来说,需要考虑就是对成员函数地址的引用,及派生类对基类成员函数的调用,这两种情况。
- GCC-3.4.6源代码学习笔记(173)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记 (102)
- GCC-3.4.6源代码学习笔记 (103)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记 (106)
- GCC-3.4.6源代码学习笔记(166)
- GCC-3.4.6源代码学习笔记
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(2)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(4)
- GCC-3.4.6源代码学习笔记(5)
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(8)
- 资源函数
- SCU 2011 warmup contest 5
- 摘抄一些函数
- 《人生六部书——处世经典 之方圆处世》
- android之字符串自动关联相应程序,主要有email/phone/web
- GCC-3.4.6源代码学习笔记(173)
- word 文字 阴影 背景
- c中的续行符为"/"
- Studying note of GCC-3.4.6 source (173)
- 无线通信技术
- 1200
- DSP240x_Sci.h
- Python、VPython、NumPy、MatPlotLib简介
- #pragma用法(1)#pragma startup和#pragma exit