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_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 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_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 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中,从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 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_time是true,cgraph_assemble_pending_functions直接返回false,触发垃圾回收。
- GCC-3.4.6源代码学习笔记(112)
- 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)
- FZU 网赛最后K题 Three kingdoms(有点卡常数的)
- Android JNI
- 转一个支付宝接口的ASP代码 支付宝接口(应用实例)2008-08-22 16:33支付宝接口的ASP代码
- Studying note of GCC-3.4.6 source (111)
- 支付宝接口(asp-支持UTF8、GB2312)
- GCC-3.4.6源代码学习笔记(112)
- KNN分类算法
- C# where用法
- arm-linux-gcc 安装和使用(交叉编译环境搭建)
- Studying note of GCC-3.4.6 source (112)
- c#中的interface abstract与virtual
- 将文本文件插入Oracle表中
- 安装freeradius步骤(freeradius 2.1.9+oracle 10g+ubuntu10.4)
- 重新开工啦