GCC-3.4.6源代码学习笔记(112)

来源:互联网 发布:js中国地图插件 编辑:程序博客网 时间:2024/06/05 14:58

5.12.3.2.1.2.1.4.    为产生代码准备

cp_parser_function_definition_after_declarator最后调用的函数是expand_or_defer_fn。在适当的情况下,它将为该函数产生RTL代码;否则为RTL代码的产生做一些准备。

 

2973   void

2974   expand_or_defer_fn (tree fn)                                                             in semantics.c

2975   {

2976     /*When the parser calls us after finishing the body of a template

2977      function, we don't really want to expand the body.  */

2978     if (processing_template_decl)

2979     {

2980       /*Normally, collection only occurs in rest_of_compilation. So,

2981         ifwe don't collect here, we never collect junk generated

2982        during the processing of templates until we hit a

2983        non-template function.  */

2984       ggc_collect ();

2985       return;

2986     }

2987  

2988     /*Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs.  */

2989     walk_tree_without_duplicates(&DECL_SAVED_TREE (fn),

2990                              simplify_aggr_init_exprs_r,

2991                              NULL);

2992  

2993     /*If this is a constructor or destructor body, we have to clone

2994      it.  */

2995     if (maybe_clone_body (fn))

2996     {

2997       /*We don't want to process FN again, so pretend we've written

2998         itout, even though we haven't.  */

2999       TREE_ASM_WRITTEN (fn) = 1;

3000       return;

3001     }

3002  

3003     /*There's no reason to do any of the work here if we're only doing

3004      semantic analysis; this code just generates RTL.  */

3005     if (flag_syntax_only)

3006       return;

3007  

3008    /*Compute the appropriate object-file linkage for inline functions.  */

3009     if (DECL_DECLARED_INLINE_P(fn))

3010       import_export_decl (fn);

3011  

3012    /*If this function is marked with the constructor attribute, add it

3013       to thelist of functions to be called along with constructors

3014       fromstatic duration objects.  */

3015     if (DECL_STATIC_CONSTRUCTOR(fn))

3016       static_ctors = tree_cons(NULL_TREE, fn, static_ctors);

3017  

3018    /*If this function is marked with the destructor attribute, add it

3019       to thelist of functions to be called along with destructors from

3020       staticduration objects.  */

3021     if (DECL_STATIC_DESTRUCTOR(fn))

3022       static_dtors = tree_cons(NULL_TREE, fn, static_dtors);

3023  

3024     function_depth++;

3025  

3026    /*Expand or defer, at the whim of the compilation unit manager.  */

3027     cgraph_finalize_function (fn, function_depth> 1);

3028  

3029     function_depth--;

3030   }

 

2989行对函数定义树进行遍历,处理对经过具名返回值优化处理的函数的调用。我们将结合具名返回值优化来看。

上面判断DECL_STATIC_CONSTRUCTORDECL_STATIC_DESTRUCTOR成立,如果函数的声明中带有__attribute__ ((constructor))__attribute__ ((destructor))。属性constructor使得该函数,在进入main ()执行前,被自动调用。类似的,属性destructor使得该函数,main ()已经完成或exit ()已经被调用后,被自动调用。具有这些属性的函数对于初始化那些在程序执行期间被隐含使用的数据很有用。

5.12.3.2.1.2.1.4.1.           更新函数调用图

前面的章节函数调用关系图中描述了数据结构cgraph_nodecgraph_edge。另外还学习了函数cgraph_node,这个函数为每个函数在第一次调用时构建唯一的cgraph_node节点,而在后面的调用中返回这个唯一的节点。这是在编译过程中,为由decl指定的函数第一次调用cgraph_finalize_functioncgraph_node

 

157    void

158    cgraph_finalize_function (tree decl,bool nested)                                 in cgraphunit.c

159    {

160      structcgraph_node *node = cgraph_node (decl);

161   

162      if (node->local.finalized)

163      {

164        /* As an GCCextension we allow redefinition of the function. The

165          semantics whenboth copies of bodies differ is not well defined.

166          We replace theold body with new body so in unit at a time mode

167          we always usenew body, while in normal mode we may end up with

168          old bodyinlined into some functions and new body expanded and

169          inlined inothers.

170        

171          ??? It may makemore sense to use one body for inlining and other

172          body forexpanding the function but this is difficult to do.  */

173   

174        /* Ifnode->output is set, then this is a unit-at-a-time compilation

175          and we havealready begun whole-unit analysis. This is *not*

176          testing forwhether we've already emitted the function. That

177          case can besort-of legitimately seen with real function

178          redefinitionerrors. I would argue that the front end should

179          never presentus with such a case, but don't enforce that for now.  */

180        if (node->output)

181          abort ();

182   

183        /* Reset ourdatastructures so we can analyze the function again.  */

184        memset (&node->local, 0, sizeof (node->local));

185        memset (&node->global, 0, sizeof (node->global));

186        memset (&node->rtl, 0, sizeof (node->rtl));

187        node->analyzed = false;

188        node->local.redefined_extern_inline =true;

189        while(node->callees)

190          cgraph_remove_edge (node,node->callees->callee);

191   

192        /* We may need tore-queue the node for assembling in case

193          we alreadyproceeded it and ignored as not needed. */

194        if (node->reachable && !flag_unit_at_a_time)

195        {

196          structcgraph_node *n;

197   

198          for (n = cgraph_nodes_queue;n; n = n->next_needed)

199            if (n == node)

200              break;

201          if(!n)

202            node->reachable = 0;

203        }

204      }

205   

206      notice_global_symbol(decl);

207      node->decl = decl;

208      node->local.finalized = true;

209   

210      /* If not unit at atime, then we need to create the call graph

211         now, so thatcalled functions can be queued and emitted now. */

212      if (!flag_unit_at_a_time)

213      {

214        cgraph_analyze_function (node);

215        cgraph_decide_inlining_incrementally(node);

216      }

 

在这个第一次调用中,node->local.finalized一定是false,而它很快在208行被更新为true。在206行,notice_global_symbol收集第一个可见的全局符号。因为全局符号指针这个编译单元是唯一的,这个信息对于编译器为匿名对象产生唯一名字是有用的,比如,在这里收集的符号将被用于产生匿名名字空间的内部名字。

 

1034   void

1035   notice_global_symbol (tree decl)                                                              in varasm.c

1036   {

1037     const char**type = &first_global_object_name;

1038  

1039     if (first_global_object_name

1040         || !TREE_PUBLIC (decl) || DECL_EXTERNAL(decl)

1041         || !DECL_NAME (decl)

1042         || (TREE_CODE (decl) != FUNCTION_DECL

1043            && (TREE_CODE (decl) !=VAR_DECL

1044                 || (DECL_COMMON (decl)

1045                   && (DECL_INITIAL (decl)== 0

1046                       || DECL_INITIAL (decl) ==error_mark_node))))

1047         || GET_CODE (DECL_RTL (decl)) != MEM)

1048       return;

1049  

1050     /* We win whenglobal object is found, but it is usefull to know about weak

1051       symbol as well so we canproduce nicer unique names.  */

1052     if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl))

1053       type = &weak_global_object_name;

1054  

1055     if (!*type)

1056     {

1057       const char*p;

1058       char *name;

1059       rtx decl_rtl = DECL_RTL (decl);

1060  

1061       p = (* targetm.strip_name_encoding) (XSTR (XEXP(decl_rtl, 0), 0));

1062       name = xstrdup (p);

1063  

1064       *type = name;

1065     }

1066   }

 

cgraph_finalize_function212行,如果我们在编译指令中指定了高于-O2的优化选项,flag_unit_at_a_time被设置为1。通常,我们倾向使用–O3选项来榨取编译器的所有优化能力。在这里假定flag_unit_at_a_time1

 

cgraph_finalize_function (continue)

 

218      if (decide_is_function_needed(node, decl))

219        cgraph_mark_needed_node(node);

220   

221      /* If not unit at atime, go ahead and emit everything we've found

222        to be reachableat this time.  */

223      if (!nested)

224      {

225        if (!cgraph_assemble_pending_functions ())

226          ggc_collect ();

227      }

228   

229     /* If we've not yetemitted decl, tell the debug info about it. */

230      if (!TREE_ASM_WRITTEN (decl))

231        (*debug_hooks->deferred_inline_function) (decl);

232   

233     /* We will neverreally output the function body, clear the SAVED_INSNS array

234        early then.  */

235      if (DECL_EXTERNAL (decl))

236        DECL_SAVED_INSNS (decl) = NULL;

237    }

 

函数decide_is_function_needed确定decl所引用的函数是否在编译单元以外,或者在系统配置的戏法中可见;或者(如果不是unit-at-a-time—一个单元一起处理)为我们还没遇到的部分所可见。在93行,属性“used”表示该变量的代码必须被生成,就算看起来这个变量没有被引用(编译器会清除死代码)。

 

73      static bool

74      decide_is_function_needed (struct cgraph_node *node, tree decl)          in cgraphunit.c

75      {

76       /* If we decided itwas needed before, but at the time we didn't have

77          the body of thefunction available, then it's still needed. We have

78          to go back andre-check its dependencies now.  */

79        if (node->needed)

80          returntrue;

81     

82        /* Externally visiblefunctions must be output. The exception is

83          COMDAT functionsthat must be output only when they are needed. */

84        if (TREE_PUBLIC (decl)&& !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))

85          returntrue;

86     

87       /* Constructors anddestructors are reachable from the runtime by

88          somemechanism.  */

89        if (DECL_STATIC_CONSTRUCTOR (decl) ||DECL_STATIC_DESTRUCTOR (decl))

90          returntrue;

91     

92       /* If the user toldus it is used, then it must be so.  */

93        if (lookup_attribute("used", DECL_ATTRIBUTES (decl)))

94          returntrue;

95     

96       /* ??? If theassembler name is set by hand, it is possible to assemble

97          the name laterafter finalizing the function and the fact is noticed

98          in assemble_name then. This is arguably abug.  */

99        if (DECL_ASSEMBLER_NAME_SET_P (decl)

100          && TREE_SYMBOL_REFERENCED(DECL_ASSEMBLER_NAME (decl)))

101        returntrue;

102   

103      if (flag_unit_at_a_time)

104        returnfalse;

105   

106     /* If not doing unitat a time, then we'll only defer this function

107        if its marked forinlining. Otherwise we want to emit it now. */

108   

109      /* "externinline" functions are never output locally.  */

110       if (DECL_EXTERNAL (decl))

111         returnfalse;

112       /* We want to emitCOMDAT functions only when absolutely necessary.  */

113       if (DECL_COMDAT (decl))

114         returnfalse;

115       if (!DECL_INLINE (decl)

116          ||(!node->local.disregard_inline_limits

117            /* Whendeclared inline, defer even the uninlinable functions.

118              This allows them to be eliminated whenunused.  */

119            && !DECL_DECLARED_INLINE_P(decl)

120           && (!node->local.inlinable ||!cgraph_default_inline_p (node))))

121        returntrue;

122   

123      return false;

124    }

 

如果该声明是可见的,cgraph_mark_needed_node需要把相关的cgraph_node节点设置为needed并且标记其中的子节点为可到达。

 

286    void

287    cgraph_mark_needed_node (struct cgraph_node *node)                               in cgraph.c

288    {

289      node->needed = 1;

290      cgraph_mark_reachable_node(node);

291    }

 

cgraph_finalize_function中,域local.finalized已经被设置为true。在函数cgraph_node中,从123128行,域origin指向包含这个函数的节点;域nested指向这个被包含函数的节点(即在其中所调用的函数),而域next_nested指向被包含的兄弟函数(sibling functions)。

 

260    void

261    cgraph_mark_reachable_node (struct cgraph_node *node)                           in cgraph.c

262    {

263      if (!node->reachable &&node->local.finalized)

264      {

265        notice_global_symbol(node->decl);

266        node->reachable = 1;

267   

268        node->next_needed = cgraph_nodes_queue;

269        cgraph_nodes_queue = node;

270   

271        /* At the momentfrontend automatically emits all nested functions.  */

272        if (node->nested)

273        {

274          structcgraph_node *node2;

275   

276          for(node2 = node->nested; node2; node2 = node2->next_nested)

277            if (!node2->reachable)

278              cgraph_mark_reachable_node (node2);

279        }

280      }

281    }

 

所有外部可见的函数都应该被串接起来。这个链表为cgraph_nodes_queue所指向。

回到cgraph_finalize_function,如果这不是一个嵌套函数(在函数作用域中或类定义中定义的内联函数),而且flag_unit_at_a_timetruecgraph_assemble_pending_functions直接返回false,触发垃圾回收。

 

原创粉丝点击