Studying note of GCC-3.4.6 source (173)

5.13.5.3.              Analysis translation-unit

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.

5.13.5.3.1.        Analyzing functions
5.13.5.3.1.1.  Build cgraph for caller-callee

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.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值