Studying note of GCC-3.4.6 source (173)

来源:互联网 发布:中控门禁系统数据库 编辑:程序博客网 时间:2024/05/21 09:45

5.13.5.3.             Analysis translation-unit

After cgraph_varpool_assemble_pending_declsemits assemble for all pending variables (note that they are visible out of thetranslation-unit), returns cgraph_finalize_compilation_unit and beginsanalyzing 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 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   }

 

Queue cgraph_nodes_queuerecords 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 thefunction-body. In some circumstance, it may be empty, for example in functiontemplate, so above condition at line 408 to filter out all functions withfunction-body unknown. Line 411 is a sainty check, if it is satisfied, means thecompiler 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 reverseinlining works properly.  */

328   cgraph_create_edges (decl,DECL_SAVED_TREE (decl));

 

Note, in below procedure, it may append to cgraph_nodes_queue, thus allfunctions visited would get handled.

Below, cgraph_create_edges iterates thefunction-body, creates cgraph_* nodes for those candidates without them, andappends 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 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  }

 

We have seen before, in walk_tree, once the function passed as itsargument returns non-null value, the iteration will be terminated. Here, record_call_1always returns NULL, and forces walk_tree to do the full iteration aspossible.

 

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. 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_PUBLICholds), output it anyhow (eliminating unused global variables can be done bylinker, which is a feature GCC will implement). And the visibility of staticvariable is only confined in the file declaring it, or files including thedefining file, once it is unused, the compiler can eliminate it from assemblercode.

(Keep in mind that cgraph_* nodes are only used for analyzingfunctions, global or static variables; local variables as only locates in thedefining function, needn’t such “heavy weapons”). At line 252, sets thevariable as “needed”, and if its associated front-end node is completed, addsthe cgraph_varpool_node into cgraph_varpool_nodes_queue queue. Note thatfunction called at line 252 can guarantee every variable would only be addedonce (neededand finalizedfields of cgraph_varpool_node of every added variable are 1, prevents it fromadding again).

For ADD_EXPR atline 255, if it is the reference of variable address, it needs not handle here,when record_call_1enters its operands, the associated VAR_DECL node will be found and processed.What needs treatment is function, see that it just stands for referring thefunction address, not invoke, and if its associated front-end node iscompleted, and adds it into queue cgraph_nodes_queue. Similarly, the insertionguarantees 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 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       }

 

Next is the handling of function invocation. It gets the noderepresenting function invocation at line 268, as in analysis using cgraph, itneeds generate map of call-relation among functions (see section  Graph ofrelation 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 declof 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 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 mustpreserve inline_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  }

 

See in previous (section Graphof relation between caller and callee), cgraph_edge is used to bindcgraph_node of the caller and callee. The callee may have been analyzedalready, then set the cgraph_edge accordingly. Further, once analyzing thetranslation-unit, cgraph_global_info_ready will be set as 1, at which time needtraverse all callees of the function (next_callee chains all callees), andcheck if existing the cgraph_edge (line 175 condition).

At line 280, the second operand of CALL_EXPR is its arguments list, walk_treenext visits it. And at line 281, walk_subtrees is set as 0, which indicates thatsubtree under this CALL_EXPR is irrelevant.

 

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  }

 

Similarly, in function analyzing, we don’t care about type anddeclaration, which are skipped at line 292. The common used code in front-endis ended at LAST_AND_UNUSED_TREE_CODE (not include), which is followed by thoseused by the language. Obvious, such nodes should be processed via languagehooks.

 

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 }

 

For C++, what needs handle is the reference of address of method,and the access of member of the base from the derived class.

 

原创粉丝点击