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

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         if we 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         it out, 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 the list of functions to be called along with constructors

3014       from static 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 the list of functions to be called along with destructors from

3020       static duration 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_CONSTRUCTOR DECL_STATIC_DESTRUCTOR 成立,如果函数的声明中带有 __attribute__ ((constructor)) __attribute__ ((destructor)) 。属性 constructor 使得该函数,在进入 main () 执行前,被自动调用。类似的,属性 destructor 使得该函数, main () 已经完成或 exit () 已经被调用后,被自动调用。具有这些属性的函数对于初始化那些在程序执行期间被隐含使用的数据很有用。

5.12.3.2.1.2.1.4.1.            更新函数调用图

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

 

157    void

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

159    {

160      struct cgraph_node *node = cgraph_node (decl);

161   

162      if (node->local.finalized)

163      {

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

165          semantics when both copies of bodies differ is not well defined.

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

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

168          old body inlined into some functions and new body expanded and

169          inlined in others.

170        

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

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

173   

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

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

176          testing for whether we've already emitted the function. That

177          case can be sort-of legitimately seen with real function

178          redefinition errors. I would argue that the front end should

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

180        if (node->output)

181          abort ();

182   

183          /* Reset our datastructures 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 to re-queue the node for assembling in case

193          we already proceeded it and ignored as not needed.  */

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

195        {

196          struct cgraph_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 a time, then we need to create the call graph

211         now, so that called 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 when global object is found, but it is usefull to know about weak

1051       symbol as well so we can produce 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_function 212 行,如果我们在编译指令中指定了高于 -O2 的优化选项, flag_unit_at_a_time 被设置为 1 。通常,我们倾向使用 –O3 选项来榨取编译器的所有优化能力。在这里假定 flag_unit_at_a_time 1

 

cgraph_finalize_function (continue)

 

218      if (decide_is_function_needed (node, decl))

219        cgraph_mark_needed_node (node);

220   

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

222        to be reachable at this time.  */

223      if (!nested)

224      {

225        if (!cgraph_assemble_pending_functions ())

226          ggc_collect ();

227      }

228   

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

230      if (!TREE_ASM_WRITTEN (decl))

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

232   

233      /* We will never really 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 it was needed before, but at the time we didn't have

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

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

79        if (node->needed)

80          return true;

81     

82        /* Externally visible functions must be output. The exception is

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

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

85          return true;

86     

87        /* Constructors and destructors are reachable from the runtime by

88          some mechanism.  */

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

90          return true;

91     

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

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

94          return true;

95     

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

97          the name later after finalizing the function and the fact is noticed

98          i n assemble_name then. This is arguably a bug.  */

99        if (DECL_ASSEMBLER_NAME_SET_P (decl)

100          && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))

101        return true;

102   

103      if (flag_unit_at_a_time )

104        return false;

105   

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

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

108   

109      /* "extern inline" functions are never output locally.  */

110       if (DECL_EXTERNAL (decl))

111         return false;

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

113       if (DECL_COMDAT (decl))

114         return false;

115       if (!DECL_INLINE (decl)

116          || (!node->local.disregard_inline_limits

117            /* When declared inline, defer even the uninlinable functions.

118               This allows them to be eliminated when unused.  */

119            && !DECL_DECLARED_INLINE_P (decl)

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

121        return true;

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 中,从 123 128 行,域 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 moment frontend automatically emits all nested functions.  */

272        if (node->nested)

273        {

274          struct cgraph_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_time true cgraph_assemble_pending_functions 直接返回 false ,触发垃圾回收。

 

你可能感兴趣的:(GCC-3.4.6源代码学习笔记(112))