5.13.5.3.2.4.2.2. 产生初始化函数实参的代码
下面为 decl_map 域构建了一个 splay 树,它用于映射内联函数中的局部声明到所内联入函数中的对等物。在 1393 行, CALL_EXPR_HAS_RETURN_SLOT_ADDR 如果不是 0 ,表示返回位置的地址是实参列表的一部分,而且这个地址总是列表中的第一个对象。
expand_call_inline (continue)
1384 /* Local declarations will be replaced by their equivalents in this
1385 map. */
1386 st = id->decl_map;
1387 id->decl_map = splay_tree_new (splay_tree_compare_pointers,
1388 NULL, NULL);
1389
1390 /* Initialize the parameters. */
1391 args = TREE_OPERAND (t, 1);
1392 return_slot_addr = NULL_TREE;
1393 if (CALL_EXPR_HAS_RETURN_SLOT_ADDR (t))
1394 {
1395 return_slot_addr = TREE_VALUE (args);
1396 args = TREE_CHAIN (args);
1397 }
1398
1399 #ifndef INLINER_FOR_JAVA
1400 arg_inits = initialize_inlined_parameters (id, args, fn);
1401 /* Expand any inlined calls in the initializers. Do this before we
1402 push FN on the stack of functions we are inlining; we want to
1403 inline calls to FN that appear in the initializers for the
1404 parameters. */
1405 expand_calls_inline (&arg_inits, id);
1406 /* And add them to the tree. */
1407 COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), arg_inits);
类似于函数调用,内联函数虽然是在其调用者体内展开,其实参可能需要转换到形参类型,或者需要额外的初始化代码来得到拷贝。这些都需要下面的函数来处理。
718 static tree
719 #ifndef INLINER_FOR_JAVA
720 initialize_inlined_parameters (inline_data *id, tree args, tree fn) in tree-inline.c
721 #else /* INLINER_FOR_JAVA */
722 initialize_inlined_parameters (inline_data *id, tree args, tree fn, tree block)
723 #endif /* INLINER_FOR_JAVA */
724 {
725 tree init_stmts;
726 tree parms;
727 tree a;
728 tree p;
729 #ifdef INLINER_FOR_JAVA
730 tree vars = NULL_TREE;
731 #endif /* INLINER_FOR_JAVA */
732 int argnum = 0;
733
734 /* Figure out what the parameters are. */
735 parms =
736 DECL_ARGUMENTS (fn);
737
738 /* Start with no initializations whatsoever. * /
739 init_stmts = NULL_TREE;
740
741 /* Loop through the parameter declarations, replacing each with an
742 equivalent VAR_DECL, appropriately initialized. */
743 for (p = parms, a = args; p;
744 a = a ? TREE_CHAIN (a) : a, p = TREE_CHAIN (p))
745 {
746 #ifndef INLINER_FOR_JAVA
747 tree init_stmt;
748 tree cleanup;
749 #endif /* not INLINER_FOR_JAVA */
750 tree var;
751 tree value;
752 tree var_sub;
753
754 ++argnum;
755
756 /* Find the initializer. */
757 value = (*lang_hooks .tree_inlining.convert_parm_for_inlining)
758 (p, a ? TREE_VALUE (a) : NULL_TREE, fn, argnum);
759
760 /* If the parameter is never assigned to, we may not need to
761 create a new variable here at all. Instead, we may be able
762 to just use the argument value. */
763 if (TREE_READONLY (p)
764 && !TREE_ADDRESSABLE (p)
765 && value && !TREE_SIDE_EFFECTS (value))
766 {
767 /* Simplify the value, if possible. */
768 value = fold (DECL_P (value) ? decl_constant_value (value) : value);
769
770 /* We can't risk substituting complex expressions. They
771 might contain variables that will be assigned to later.
772 Theoretically, we could check the expression to see if
773 all of the variables that determine its value are
774 read-only, but we don't bother. */
775 if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))
776 {
777 /* If this is a declaration, wrap it a NOP_EXPR so that
778 we don't try to put the VALUE on the list of
779 BLOCK_VARS. */
780 if (DECL_P (value))
781 value = build1 (NOP_EXPR, TREE_TYPE (value), value);
782
783 /* If this is a constant, make sure it has the right type. */
784 else if (TREE_TYPE (value) != TREE_TYPE (p))
785 value = fold (build1 (NOP_EXPR, TREE_TYPE (p), value));
786
787 splay_tree_insert (id->decl_map,
788 (splay_tree_key) p,
789 (splay_tree_value) value);
790 continue ;
791 }
792 }
上面在 757 行,钩子 convert_parm_for_inlining 提供实参到形参类型的转换处理。不过 C++ 是强类型语言(注意 C 不是),转换在解析时完成,因此这个钩子在这里不做任何事。
另外,如果形参是常量类型,并且其地址没有被引用,那么只要实参是没有副作用的,就可能可以直接使用实参值,而不需要另外构建新的局部变量。不过实际上, GCC 在这里采用了保守的做法,经过常量折叠优化后实参,也必须是常量或只读性的,才能直接使用其值。对于合乎要求的实参,我们使用 NOP_EXPR 来封装它们。
initialize_inlined_parameters (continue)
794 /* Make an equivalent VAR_DECL. */
795 var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0));
796
797 /* See if the frontend wants to pass this by invisible reference. If
798 so, our new VAR_DECL will have REFERENCE_TYPE, and we need to
799 replace uses of the PARM_DECL with dereferences. */
800 if (TREE_TYPE (var) != TREE_TYPE (p)
801 && POINTER_TYPE_P (TREE_TYPE (var))
802 && TREE_TYPE (TREE_TYPE (var)) == TREE_TYPE (p))
803 var_sub = build1 (INDIRECT_REF, TREE_TYPE (p), var);
804 else
805 var_sub = var;
806
807 /* Register the VAR_DECL as the equivalent for the PARM_DECL;
808 that way, when the PARM_DECL is encountered, it will be
809 automatically replaced by the VAR_DECL. */
810 splay_tree_insert (id->decl_map,
811 (splay_tree_key) p,
812 (splay_tree_value) var_sub);
813
814 /* Declare this new variable. */
815 #ifndef INLINER_FOR_JAVA
816 init_stmt = build_stmt (DECL_STMT, var);
817 TREE_CHAIN (init_stmt) = init_stmts;
818 init_stmts = init_stmt;
819 #else /* INLINER_FOR_JAVA */
…
822 #endif /* INLINER_FOR_JAVA */
823
824 /* Initialize this VAR_DECL from the equivalent argument. If
825 the argument is an object, created via a constructor or copy,
826 this will not result in an extra copy: the TARGET_EXPR
827 representing the argument will be bound to VAR, and the
828 object will be constructed in VAR. */
829 if (! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
830 #ifndef INLINER_FOR_JAVA
831 DECL_INITIAL (var) = value;
832 else
833 {
834 /* Even if P was TREE_READONLY, the new VAR should not be.
835 I n the original code, we would have constructed a
836 temporary, and then the function body would have never
837 changed the value of P. However, now, we will be
838 constructing VAR directly. The constructor body may
839 change its value multiple times as it is being
840 constructed. Therefore, it must not be TREE_READONLY;
841 the back-end assumes that TREE_READONLY variable is
842 assigned to only once. */
843 TREE_READONLY (var) = 0;
844
845 /* Build a run-time initialization. */
846 init_stmt = build_stmt (EXPR_STMT,
847 build (INIT_EXPR, TREE_TYPE (p),
848 var, value));
849 /* Add this initialization to the list. Note that we want the
850 declaration *after* the initialization because we are going
851 to reverse all the initialization statements below. */
852 TREE_CHAIN (init_stmt) = init_stmts;
853 init_stmts = init_stmt;
854 }
在 795 行, copy_decl_for_inlining 根据这个形参,在调用者函数中声明一个与该形参同名、类型相同的 VAR_DECL 。而 816 行使得 copy_decl_for_inlining 所构建的 VAR_DECL 成为一个局部声明。这样,内联函数的参数传递将转变为一组赋值操作。
另外,满足上面 800 行条件的情况是,我们向一个引用类型的形参传入一个对象,因此这里我们把这个对象封装入 INDIRECT_REF 中。
initialize_inlined_parameters (continue)
856 /* See if we need to clean up the declaration. */
857 cleanup = (*lang_hooks .maybe_build_cleanup ) (var);
858 if (cleanup)
859 {
860 tree cleanup_stmt;
861 /* Build the cleanup statement. */
862 cleanup_stmt = build_stmt (CLEANUP_STMT, var, cleanup);
863 /* Add it to the *front* of the list; the list will be
864 reversed below. */
865 TREE_CHAIN (cleanup_stmt) = init_stmts;
866 init_stmts = cleanup_stmt;
867 }
868 #else /* INLINER_FOR_JAVA */
…
881 #endif /* INLINER_FOR_JAVA */
882 }
883
884 #ifndef INLINER_FOR_JAVA
885 /* Evaluate trailing arguments. */
886 for (; a; a = TREE_CHAIN (a))
887 {
888 tree init_stmt;
889 tree value = TREE_VALUE (a);
890
891 if (! value || ! TREE_SIDE_EFFECTS (value))
892 continue ;
893
894 init_stmt = build_stmt (EXPR_STMT, value);
895 TREE_CHAIN (init_stmt) = init_stmts;
896 init_stmts = init_stmt;
897 }
898
899 /* The initialization statements have been built up in reverse
900 order. Straighten them out now. */
901 return nreverse (init_stmts);
902 #else /* INLINER_FOR_JAVA */
…
905 #endif /* INLINER_FOR_JAVA */
906 }
如果变量的析构需要调用析构函数,对应的代码则由 857 行的钩子来产生。 886 行的循环则是处理缺省参数的情况,因为这部分需要通过 var_start , var_arg , var_end 这样的宏来处理,除非传入的实参声明为“ volatile ”( TREE_SIDE_EFFECTS 为 true ),不需要为其构建局部变量( var_* 系列的宏由编译器中相应的 __builtin_var_* 内建函数实现)。
在 901 行,这一系列初始化语句被返回。在这些初始化语句中,还可能存在内联函数的调用,因此紧接着为这些语句调用 expand_calls_inline 。
5.13.5.3.2.4.2.3. 展开内联函数体
5.13.5.3.2.4.2.3.1. 准备 ret_label
1431 行的 DECL_INLINED_FNS 用于记录要在函数 fn 中展开的内联函数,它在函数 optimize_inline_calls 中在完成该函数处理时设置(注意,我们现在正在处理调用 fn 的函数,因为我们按调用的先后次序处理函数, fn 应该已经完成这里的处理)。满足 1431 行条件表示 fn 没有展开内联函数,而且 fn 是被当前处理函数调用的,我们把它加入 id->inlined_fns ,在 optimize_inline_calls 中,这部分数据会被更新入 DECL_INLINED_FNS 。
expand_call_inline (continue)
1425 /* Record the function we are about to inline so that we can avoid
1426 recursing into it. */
1427 VARRAY_PUSH_TREE (id->fns, fn);
1428
1429 /* Record the function we are about to inline if optimize_function
1430 has not been called on it yet and we don't have it in the list. */
1431 if (! DECL_INLINED_FNS (fn))
1432 {
1433 int i;
1434
1435 for (i = VARRAY_ACTIVE_SIZE (id->inlined_fns) - 1; i >= 0; i--)
1436 if (VARRAY_TREE (id->inlined_fns, i) == fn)
1437 break ;
1438 if (i < 0)
1439 VARRAY_PUSH_TREE (id->inlined_fns, fn);
1440 }
1441
1442 /* Return statements in the function body will be replaced by jumps
1443 to the RET_LABEL. */
1444 id->ret_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
1445 DECL_CONTEXT (id->ret_label) = VARRAY_TREE (id->fns, 0);
1446
1447 if (! DECL_INITIAL (fn)
1448 || TREE_CODE (DECL_INITIAL (fn)) != BLOCK)
1449 abort ();
1450
1451 #ifndef INLINER_FOR_JAVA
1452 /* Create a block to put the parameters in. We have to do this
1453 after the parameters have been remapped because remapping
1454 parameters is different from remapping ordinary variables. */
1455 scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
1456 SCOPE_BEGIN_P (scope_stmt) = 1;
1457 SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
1458 remap_block (scope_stmt, DECL_ARGUMENTS (fn), id);
1459 TREE_CHAIN (scope_stmt) = COMPOUND_BODY (stmt);
1460 COMPOUND_BODY (stmt) = scope_stmt;
14161
1462 /* Tell the debugging backends that this block represents the
1463 outermost scope of the inlined function. */
1464 if (SCOPE_STMT_BLOCK (scope_stmt))
1465 BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);
在 optimize_inline_calls 的 1636 行,看到 id->fns 中的第一个元素就是当前处理的函数。上面 1444 及 1445 行构建了一个 RET_LABEL 标签,用于把被调用函数的返回语句转变成跳转语句。在 1447 行, DECL_INITIAL 中保存了表示该函数绑定域的中间树,如果有效,它的第一个节点一定是 BLOCK 。上面在 1455 行引入了一个作用域来包含这些参数。
5.13.5.3.2.4.2.3.2. 替换形参
前面,已经准备好了初始化实参的代码,内联函数展开接下来的工作就是声明与形参同名、同类型的变量,而且函数体内所有引用到形参的地方都要改为引用相应的变量。其中声明与形参同名、同类型的变量由在 1458 行对 remap_block 的调用来完成。其中, DECL_ARGUMENTS 得到函数的形参列表。而在下面 337 行,“ SCOPE_STMT_BLOCK (scope_stmt) ”实际上得到的是“ DECL_INITIAL (fn) ”。
315 static void
316 #ifndef INLINER_FOR_JAVA
317 remap_block (tree scope_stmt, tree decls, inline_data *id) in tree-inline.c
…
320 #endif /* INLINER_FOR_JAVA */
321 {
322 #ifndef INLINER_FOR_JAVA
323 /* We cannot do this in the cleanup for a TARGET_EXPR since we do
324 not know whether or not expand_expr will actually write out the
325 code we put there. If it does not, then we'll have more BLOCKs
326 than block-notes, and things will go awry. At some point, we
327 should make the back-end handle BLOCK notes in a tidier way,
328 without requiring a strict correspondence to the block-tree; then
329 this check can go. */
330 if (id->in_target_cleanup_p)
331 {
332 SCOPE_STMT_BLOCK (scope_stmt) = NULL_TREE;
333 return ;
334 }
335
336 /* If this is the beginning of a scope, remap the associated BLOCK. */
337 if (SCOPE_BEGIN_P (scope_stmt) && SCOPE_STMT_BLOCK (scope_stmt))
338 {
339 tree old_block;
340 tree new_block;
341 tree old_var;
342 tree fn;
343
344 /* Make the new block. */
345 old_block = SCOPE_STMT_BLOCK (scope_stmt);
346 new_block = make_node (BLOCK);
347 TREE_USED (new_block) = TREE_USED (old_block);
348 BLOCK_ABSTRACT_ORIGIN (new_block) = old_block;
349 SCOPE_STMT_BLOCK (scope_stmt) = new_block;
350
351 /* Remap its variables. */
352 for (old_var = decls ? decls : BLOCK_VARS (old_block);
353 old_var;
354 old_var = TREE_CHAIN (old_var))
355 {
356 tree new_var;
357
358 /* Remap the variable. */
359 new_var = remap_decl (old_var, id);
360 /* If we didn't remap this variable, so we can't mess with
361 its TREE_CHAIN. If we remapped this variable to
362 something other than a declaration (say, if we mapped it
363 to a constant), then we must similarly omit any mention
364 of it here. */
365 if (!new_var || !DECL_P (new_var))
366 ;
367 else
368 {
369 TREE_CHAIN (new_var) = BLOCK_VARS (new_block);
370 BLOCK_VARS (new_block) = new_var;
371 }
372 }
注意上面的 decls 是函数的参数列表( PARM_DECL ),而在其他地方调用 remap_block ,参数 decls 都是 NULL (这种情况下则通过 BLOCK_VARS 获取相应代码块中的变量声明)。看到上面的 new_block 则是 old_block (这里是参数列表)的一个替代物,它在 349 行代替了 old_block ,经过拷贝及转换的参数通过 BLOCK_VAR 链入 new_block ( 570 行),这样就完成了与形参同名、同类型变量在函数体内的声明。
下面是构建与形参同名、同类型变量的具体过程。
133 static tree
134 remap_decl (tree decl, inline_data *id) in tree-inline.c
135 {
136 splay_tree_node n;
137 tree fn;
138
139 /* We only remap local variables in the current function. */
140 fn = VARRAY_TOP_TREE (id->fns);
141 if (! (*lang_hooks .tree_inlining.auto_var_in_fn_p ) (decl, fn))
142 return NULL_TREE;
首先,需要选出声明在函数中的自动变量。显然,不同的语言对于自动变量会有自己的定义,对于 C++ ,钩子绑定到如下的函数( C , C++ 对自动变量的定义实际上基本相同,但由于产生的语言中间树不同,它们采用了不同的判断函数)。
2136 int
2137 cp_auto_var_in_fn_p (tree var, tree fn) in tree.c
2138 {
2139 return (DECL_P (var) && DECL_CONTEXT (var) == fn
2140 && nonstatic_local_decl_p (var));
2141 }
如果声明已经被拷贝过了,那就万事大吉;否则就要先通过 copy_decl_for_inlining 拷贝节点在内容(其中把 PARM_DECL 及 RESULT_DECL 拷贝成 VAR_DECL )。对于 *_DECL 节点,其 TREE_TYPE 可能需要进一步拷贝。
remap_decl (continue)
144 /* See if we have remapped this declaration. */
145 n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
146
147 /* If we didn't already have an equivalent for this declaration,
148 create one now. */
149 if (!n)
150 {
151 tree t;
152
153 /* Make a copy of the variable or label. */
154 t = copy_decl_for_inlining (decl, fn, VARRAY_TREE (id->fns, 0));
155
156 /* Remap types, if necessary. */
157 TREE_TYPE (t) = remap_type (TREE_TYPE (t), id);
158 if (TREE_CODE (t) == TYPE_DECL)
159 DECL_ORIGINAL_TYPE (t) = remap_type (DECL_ORIGINAL_TYPE (t), id);
160 else if (TREE_CODE (t) == PARM_DECL)
161 DECL_ARG_TYPE_AS_WRITTEN (t)
162 = remap_type (DECL_ARG_TYPE_AS_WRITTEN (t), id);
DECL_ORIGINAL_TYPE ,对于通过 typedef 定义的类型,保存了这个类型所引用的类型。而对于其他类型,这个域是 NULL 。而 DECL_ARG_TYPE_AS_WRITTEN 保存的是参数被写成的类型(比如函数或数组类型,但编译器为之产生的却是相应的指针类型)。不过在这里 PARM_DECL 不会出现(因为之前调用了 copy_decl_for_inlining )
200 static tree
201 remap_type (tree type, inline_data *id) in tree-inline.c
202 {
203 splay_tree_node node;
204 tree new, t;
205
206 if (type == NULL)
207 return type;
208
209 /* See if we have remapped this type. */
210 node = splay_tree_lookup (id->decl_map, (splay_tree_key) type);
211 if (node)
212 return (tree) node->value;
213
214 /* The type only needs remapping if it's variably modified. */
215 if (! variably_modified_type_p (type))
216 {
217 splay_tree_insert (id->decl_map, (splay_tree_key) type,
218 (splay_tree_value) type);
219 return type;
220 }
221
222 /* We do need a copy. build and register it now. */
223 new = copy_node (type);
224 splay_tree_insert (id->decl_map, (splay_tree_key) type,
225 (splay_tree_value) new);
226
227 /* This is a new type, not a copy of an old type. Need to reassociate
228 variants. We can handle everything except the main variant lazily. */
229 t = TYPE_MAIN_VARIANT (type);
230 if (type != t)
231 {
232 t = remap_type (t, id);
233 TYPE_MAIN_VARIANT (new) = t;
234 TYPE_NEXT_VARIANT (new) = TYPE_MAIN_VARIANT (t);
235 TYPE_NEXT_VARIANT (t) = new;
236 }
237 else
238 {
239 TYPE_MAIN_VARIANT (new) = new;
240 TYPE_NEXT_VARIANT (new) = NULL;
241 }
242
243 /* Lazily create pointer and reference types. */
244 TYPE_POINTER_TO (new) = NULL;
245 TYPE_REFERENCE_TO (new) = NULL;
246
247 switch (TREE_CODE (new))
248 {
249 case INTEGER_TYPE:
250 case REAL_TYPE:
251 case ENUMERAL_TYPE:
252 case BOOLEAN_TYPE:
253 case CHAR_TYPE:
254 t = TYPE_MIN_VALUE (new);
255 if (t && TREE_CODE (t) != INTEGER_CST)
256 walk_tree (&TYPE_MIN_VALUE (new), copy_body_r , id, NULL);
257 t = TYPE_MAX_VALUE (new);
258 if (t && TREE_CODE (t) != INTEGER_CST)
259 walk_tree (&TYPE_MAX_VALUE (new), copy_body_r , id, NULL);
260 return new;
261
262 case POINTER_TYPE:
263 TREE_TYPE (new) = t = remap_type (TREE_TYPE (new), id);
264 if (TYPE_MODE (new) == ptr_mode)
265 TYPE_POINTER_TO (t) = new;
266 return new;
267
268 case REFERENCE_TYPE:
269 TREE_TYPE (new) = t = remap_type (TREE_TYPE (new), id);
270 if (TYPE_MODE (new) == ptr_mode)
271 TYPE_REFERENCE_TO (t) = new;
272 return new;
273
274 case METHOD_TYPE:
275 case FUNCTION_TYPE:
276 TREE_TYPE (new) = remap_type (TREE_TYPE (new), id);
277 walk_tree (&TYPE_ARG_TYPES (new), copy_body_r , id, NULL);
278 return new;
279
280 case ARRAY_TYPE:
281 TREE_TYPE (new) = remap_type (TREE_TYPE (new), id);
282 TYPE_DOMAIN (new) = remap_type (TYPE_DOMAIN (new), id);
283 break ;
284
285 case RECORD_TYPE:
286 case UNION_TYPE:
287 case QUAL_UNION_TYPE:
288 walk_tree (&TYPE_FIELDS (new), copy_body_r , id, NULL);
289 break ;
290
291 case FILE_TYPE:
292 case SET_TYPE:
293 case OFFSET_TYPE:
294 default :
295 /* Shouldn't have been thought variable sized. */
296 abort ();
297 }
298
299 walk_tree (&TYPE_SIZE (new), copy_body_r , id, NULL);
300 walk_tree (&TYPE_SIZE_UNIT (new), copy_body_r , id, NULL);
301
302 return new;
303 }
在拷贝及处理参数列表时,不会出现 RETURN_STMT ,并且在现在这一点上也很难看清把 RETURN_STMT 转变为 GOTO 语句的细节,我们暂时跳过这一部分。而在下面的 578 行,对于块内的局部变量也要进行拷贝,因为每次展开都应该有自己的变量实例。
502 static tree
503 copy_body_r (tree *tp, int *walk_subtrees, void *data) in tree-inline.c
504 {
505 inline_data* id;
506 tree fn;
507
508 /* Set up. */
509 id = (inline_data *) data;
510 fn = VARRAY_TOP_TREE (id->fns);
511
512 #if 0
…
519 #endif
520
521 #ifdef INLINER_FOR_JAVA
…
524 #endif
525
526 /* If this is a RETURN_STMT, change it into an EXPR_STMT and a
527 GOTO_STMT with the RET_LABEL as its target. */
528 #ifndef INLINER_FOR_JAVA
529 if (TREE_CODE (*tp) == RETURN_STMT && id->ret_label)
530 #else /* INLINER_FOR_JAVA */
…
532 #endif /* INLINER_FOR_JAVA */
533 {
…
571 }
572 /* Local variables and labels need to be replaced by equivalent
573 variables. We don't want to copy static variables; there's only
574 one of those, no matter how many times we inline the containing
575 function.
576 We do not also want to copy the label which we put into
577 GOTO_STMT which replaced RETURN_STMT. */
578 else if (*tp != id->ret_label
579 && (*lang_hooks .tree_inlining.auto_var_in_fn_p ) (*tp, fn))
580 {
581 tree new_decl;
582
583 /* Remap the declaration. */
584 new_decl = remap_decl (*tp, id);
585 if (! new_decl)
586 abort ();
587 /* Replace this variable with the copy. */
588 STRIP_TYPE_NOPS (new_decl);
589 *tp = new_decl;
590 }
591 #if 0
…
595 #endif
596 else if (TREE_CODE (*tp) == SAVE_EXPR)
597 remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0),
598 walk_subtrees);
599 else if (TREE_CODE (*tp) == UNSAVE_EXPR)
600 /* UNSAVE_EXPRs should not be generated until expansion time. */
601 abort ();
602 #ifndef INLINER_FOR_JAVA
603 /* For a SCOPE_STMT, we must copy the associated block so that we
604 can write out debugging information for the inlined variables. */
605 else if (TREE_CODE (*tp) == SCOPE_STMT && !id->in_target_cleanup_p)
606 copy_scope_stmt (tp, walk_subtrees, id);
607 #else /* INLINER_FOR_JAVA */
…
630 #endif /* INLINER_FOR_JAVA */
631 /* Types may need remapping as well. */
632 else if (TYPE_P (*tp))
633 *tp = remap_type (*tp, id);
634
635 /* Otherwise, just copy the node. Note that copy_tree_r already
636 knows not to copy VAR_DECLs, etc., so this is safe. */
637 else
638 {
639 if (TREE_CODE (*tp) == MODIFY_EXPR
640 && TREE_OPERAND (*tp, 0) == TREE_OPERAND (*tp, 1)
641 && ((*lang_hooks .tree_inlining.auto_var_in_fn_p )
642 (TREE_OPERAND (*tp, 0), fn)))
643 {
644 /* Some assignments VAR = VAR; don't generate any rtl code
645 and thus don't count as variable modification. Avoid
646 keeping bogosities like 0 = 0. */
647 tree decl = TREE_OPERAND (*tp, 0), value;
648 splay_tree_node n;
649
650 n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
651 if (n)
652 {
653 value = (tree) n->value;
654 STRIP_TYPE_NOPS (value);
655 if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))
656 {
657 *tp = value;
658 return copy_body_r (tp, walk_subtrees, data);
659 }
660 }
661 }
662 else if (TREE_CODE (*tp) == ADDR_EXPR
663 && ((*lang_hooks .tree_inlining.auto_var_in_fn_p )
664 (TREE_OPERAND (*tp, 0), fn)))
665 {
666 /* Get rid of &* from inline substitutions. It can occur when
667 someone takes the address of a parm or return slot passed by
668 invisible reference. */
669 tree decl = TREE_OPERAND (*tp, 0), value;
670 splay_tree_node n;
671
672 n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
673 if (n)
674 {
675 value = (tree) n->value;
676 if (TREE_CODE (value) == INDIRECT_REF)
677 {
678 *tp = convert (TREE_TYPE (*tp), TREE_OPERAND (value, 0));
679 return copy_body_r (tp, walk_subtrees, data);
680 }
681 }
682 }
683
684 copy_tree_r (tp, walk_subtrees, NULL);
685
686 TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id);
687
688 /* The copied TARGET_EXPR has never been expanded, even if the
689 original node was expanded already. */
690 if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3))
691 {
692 TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3);
693 TREE_OPERAND (*tp, 3) = NULL_TREE;
694 }
695 }
696
697 /* Keep iterating. */
698 return NULL_TREE;
699 }
copy_body_r 总是作为 walk_tree 的参数来使用的,通过 walk_tree 深入到每个节点的内部。显然,对于 walk_tree 不知道下一步该如何处理的节点, copy_body_r 需要自己来处理,像上面的 SCOPE_STMT , SAVE_EXPR , MODIFY_EXPR 及 ADDR_EXPR 等。注意 639 行,这个条件代表一个局部变量的:“ var = var; ”的表达式(可能是由宏展开生成的),这句语句是没有意义的,这里直接使用拷贝后的值( 672 行获取对应的拷贝节点)。对于引用局部对象的 ADDR_EXPR 亦然,要用拷贝的对象替换其中引用的对象。
注意 walk_tree 并不会在常量节点上调用传给它的函数,而在 remap_type 中,不会拷贝节点内部 INTEGER_CST (前面看过 INTEGER_CST 是共享的)。
remap_decl (continue)
164 /* Remap sizes as necessary. */
165 walk_tree (&DECL_SIZE (t), copy_body_r , id, NULL);
166 walk_tree (&DECL_SIZE_UNIT (t), copy_body_r , id, NULL);
167
168 #ifndef INLINER_FOR_JAVA
169 if (! DECL_NAME (t) && TREE_TYPE (t)
170 && (*lang_hooks .tree_inlining.anon_aggr_type_p) (TREE_TYPE (t)))
171 {
172 /* For a VAR_DECL of anonymous type, we must also copy the
173 member VAR_DECLS here and rechain the DECL_ANON_UNION_ELEMS. */
174 tree members = NULL;
175 tree src;
176
177 for (src = DECL_ANON_UNION_ELEMS (t); src;
178 src = TREE_CHAIN (src))
179 {
180 tree member = remap_decl (TREE_VALUE (src), id);
181
182 if (TREE_PURPOSE (src))
183 abort ();
184 members = tree_cons (NULL, member, members);
185 }
186 DECL_ANON_UNION_ELEMS (t) = nreverse (members);
187 }
188 #endif /* not INLINER_FOR_JAVA */
189
190 /* Remember it, so that if we encounter this local entity
191 again we can reuse this copy. */
192 n = splay_tree_insert (id->decl_map,
193 (splay_tree_key) decl,
194 (splay_tree_value) t);
195 }
196
197 return (tree) n->value;
198 }
同样,对于使用 INTEGER_CST 的 DECL_SIZE 及 DECL_SIZE_UNIT , walk_tree 绕过之。在 192 行, decl 是被拷贝的对象, t 则是对象的拷贝。
回到 remap_block ,准备好了形参对应的局部变量后,在 374 行恢复块内变量的次序。而在 376 行 id->cloning_p 只在来自 clone_body 函数(调用于克隆构造函数或析构函数)的调用中设置,此时,我们还在解析被克隆函数的阶段。显然,在我们的场景中, id->cloning_p 为 0 ,把 new_block 插入到 DECL_INITIAL 之后。
remap_block (continue)
373 /* We put the BLOCK_VARS in reverse order; fix that now. */
374 BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block));
375 fn = VARRAY_TREE (id->fns, 0);
376 if (id->cloning_p)
377 /* We're building a clone; DECL_INITIAL is still
378 error_mark_node, and current_binding_level is the parm
379 binding level. */
380 (*lang_hooks .decls.insert_block) (new_block);
381 else
382 {
383 /* Attach this new block after the DECL_INITIAL block for the
384 function into which this block is being inlined. In
385 rest_of_compilation we will straighten out the BLOCK tree. */
386 tree *first_block;
387 if (DECL_INITIAL (fn))
388 first_block = &BLOCK_CHAIN (DECL_INITIAL (fn));
389 else
390 first_block = &DECL_INITIAL (fn);
391 BLOCK_CHAIN (new_block) = *first_block;
392 *first_block = new_block;
393 }
394 /* Remember the remapped block. */
395 splay_tree_insert (id->decl_map,
396 (splay_tree_key) old_block,
397 (splay_tree_value) new_block);
398 }
399 /* If this is the end of a scope, set the SCOPE_STMT_BLOCK to be the
400 remapped block. */
401 else if (SCOPE_END_P (scope_stmt) && SCOPE_STMT_BLOCK (scope_stmt))
402 {
403 splay_tree_node n;
404
405 /* Find this block in the table of remapped things. */
406 n = splay_tree_lookup (id->decl_map,
407 (splay_tree_key) SCOPE_STMT_BLOCK (scope_stmt));
408 if (! n)
409 abort ();
410 SCOPE_STMT_BLOCK (scope_stmt) = (tree) n->value;
411 }
412 #else /* INLINER_FOR_JAVA */
…
474 #endif /* INLINER_FOR_JAVA */
475 }
SCOPE_STMT_BLOCK 是一个包含了在这个局部作用域中所声明变量的 BLOCK ,对于 SCOPE_END_P 成立的 scope_stmt 而言,它是这个 scope_stmt 所封装的块(参见 do_poplevel )。这个封装的块必定已经 remap 了,那么用拷贝出的块来替换原有的块。