GCC-3.4.6源代码学习笔记(181)
2011-03-26 09:31
471 查看
5.13.5.3.2.4.2.3.3.
构建返回变量
加入为形参构建的局部变量后,紧接着这些变量,(可能)声明用于返回的变量。
expand_call_inline (continue)
1467
/* Declare the return
variable for the function.
*/
1468
COMPOUND_BODY (stmt)
1469
= chainon (COMPOUND_BODY (stmt),
1470
declare_return_variable
(id, return_slot_addr, &use_stmt));
1471
#else
/* INLINER_FOR_JAVA */
….
1483
#endif
/* INLINER_FOR_JAVA */
上面的
return_slot_addr
,如果使用具名返回值优化(
NRVO
)通过形参返回聚集对象时,用于指向这个对象;否则就是
NULL
(在前面拷贝形参列表时,我们专门去掉了对这个对象的处理)。
913
#ifndef
INLINER_FOR_JAVA
914
static
tree
915
declare_return_variable
(struct
inline_data *id, tree return_slot_addr,
in tree-inline.c
916
tree *use_stmt)
917
#else
/* INLINER_FOR_JAVA */
…
921
#endif
/* INLINER_FOR_JAVA */
922
{
923
tree fn = VARRAY_TOP_TREE (id->fns);
924
tree result = DECL_RESULT (fn);
925
#if
ndef
INLINER_FOR_JAVA
926
tree var;
927
#endif
/* not INLINER_FOR_JAVA */
928
int need_return_decl = 1;
929
930
/* We don't need to
do anything for functions that don't return
931
anything.
*/
932
if (!result || VOID_TYPE_P (TREE_TYPE
(result)))
933
{
934
#ifndef
INLINER_FOR_JAVA
935
*use_stmt = NULL_TREE;
936
#else
/* INLINER_FOR_JAVA */
…
938
#endif
/* INLINER_FOR_JAVA */
939
return
NULL_TREE;
940
}
941
942
#ifndef
INLINER_FOR_JAVA
943
var = ((*lang_hooks
.tree_inlining.copy_res_decl_for_inlining
)
944
(result, fn, VARRAY_TREE (id->fns, 0),
id->decl_map,
945
&need_return_decl, return_slot_addr));
946
947
/* Register the
VAR_DECL as the equivalent for the RESULT_DECL; that
948
way, when the
RESULT_DECL is encountered, it will be
949
automatically
replaced by the VAR_DECL.
*/
950
splay_tree_insert (id->decl_map,
951
(splay_tree_key) result,
952
(splay_tree_value) var);
953
954
/* Build the
USE_STMT. If the return type of the function was
955
promoted, convert it back to the expected
type.
*/
956
if (TREE_TYPE (var) == TREE_TYPE (TREE_TYPE
(fn)))
957
*use_stmt = build_stmt (EXPR_STMT, var);
958
else
959
*use_stmt = build_stmt (EXPR_STMT,
960
build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE
(fn)),
961
var));
962
TREE_ADDRESSABLE (*use_stmt) = 1;
963
964
/* Build the
declaration statement if FN does not return an
965
aggregate.
*/
966
if (need_return_decl)
967
return
build_stmt (DECL_STMT, var);
968
#else
/* INLINER_FOR_JAVA */
...
979
#endif
/* INLINER_FOR_JAVA */
980
/* If FN does
return an aggregate, there's no need to declare the
981
return variable;
we're using a variable in our caller's frame.
*/
982
else
983
return
NULL_TREE;
984
}
如果没有返回值或返回值是
NULL
,显然什么都不用做,否则就要拷贝返回值。在对下面函数的调用中,
result
是函数的返回值声明,
fn
是当前被调用函数,
caller
是调用者。因为调用返回聚集对象的函数,调用者需要传入返回地址(
NRVO
的做法),这个变量由调用者负责声明,我们不需要管;但其他返回值,在这里我们需要为它们声明对应的变量,因此相应设置
need_decl
(
2171
行)。
2147
tree
2148
cp_copy_res_decl_for_inlining
(tree result,
in tree.c
2149
tree fn,
2150
tree caller,
2151
void* decl_map_,
2152
int* need_decl,
2153
tree
return_slot_addr)
2154
{
2155
splay_tree decl_map = (splay_tree)decl_map_;
2156
tree var;
2157
2158
/* If FN returns an
aggregate then the caller will always pass the
2159
address of the
return slot explicitly. If we were just to
2160
create a new
VAR_DECL here, then the result of this function
2161
would be copied
(bitwise) into the variable initialized by the
2162
TARGET_EXPR.
That's incorrect, so we must transform any
2163
references to the
RESULT into references to the target.
*/
2164
2165
/* We should have
an explicit return slot iff the return type is
2166
TREE_ADDRESSABLE.
See simplify_aggr_init_expr.
*/
2167
if (TREE_ADDRESSABLE (TREE_TYPE (result))
2168
!= (return_slot_addr != NULL_TREE))
2169
abort ();
2170
2171
*need_decl = !return_slot_addr;
2172
if (return_slot_addr)
2173
{
2174
var = build_indirect_ref
(return_slot_addr, "");
2175
if (!
same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (var),
2176
TREE_TYPE (result)))
2177
abort ();
2178
}
2179
/* Otherwise, make
an appropriate copy.
*/
2180
else
2181
var = copy_decl_for_inlining (result, fn,
caller);
2182
2183
if (DECL_SAVED_FUNCTION_DATA (fn))
2184
{
2185
tree nrv = DECL_SAVED_FUNCTION_DATA
(fn)->x_return_value;
2186
if (nrv)
2187
{
2188
/* We have a named
return value; copy the name and source
2189
position so we can get reasonable debugging information,
and
2190
register the return variable as its equivalent.
*/
2191
if (TREE_CODE (var) == VAR_DECL
2192
/* But not if we're initializing a variable from the
2193
enclosing function
which already has its own name.
*/
2194
&& DECL_NAME (var) == NULL_TREE)
2195
{
2196
DECL_NAME (var) = DECL_NAME (nrv);
2197
DECL_SOURCE_LOCATION (var) =
DECL_SOURCE_LOCATION (nrv);
2198
DECL_ABSTRACT_ORIGIN
(var) = DECL_ORIGIN (nrv);
2199
/* Don't lose initialization info.
*/
2200
DECL_INITIAL (var) = DECL_INITIAL (nrv);
2201
/* Don't forget that it needs to go in the stack.
*/
2202
TREE_ADDRESSABLE (var) = TREE_ADDRESSABLE
(nrv);
2203
}
2204
2205
splay_tree_insert (decl_map,
2206
(splay_tree_key) nrv,
2207
(splay_tree_value) var);
2208
}
2209
}
2210
2211
return
var;
2212
}
DECL_SAVED_FUNCTION_DATA
保存了描述该函数的
language_function
对象(它在被
finsh_function
调用的
save_function_data
设置)。而其中的
x_return_value
域专门用于
NRVO
的目的(它在被
check_return_expr
设置为返回值)。因为在
2174
行已经为这个返回值构建了
return_slot_addr
所指向对象的
INDRECT_REF
节点,这是真正用于返回值的对象,因此根据
x_return_value
域来设置它,并把它作为
x_return_value
的替代。
如果返回值不需要声明,
declare_return_variable
将返回
NULL
,否则就是相应的
DECL_STMT
,这个
STMT
在
expand_call_inline
的
1470
行插入到为形参声明的变量后。而
use_stmt
则要在展开末尾才能插入(作为
ret_label
的对象)。
5.13.5.3.2.4.2.3.4.
拷贝函数体
在声明了对应于形参及返回值的局部变量后,可以拷贝函数体并使用这些变量替换形参及返回值,这由下面的
copy_body
函数来进行。
expand_call_inline (continue)
1485
/* After we've
initialized the parameters, we insert the body of the
1486
function itself.
*/
1487
#ifndef
INLINER_FOR_JAVA
1488
inlined_body = &COMPOUND_BODY (stmt);
1489
while
(*inlined_body)
1490
inlined_body = &TREE_CHAIN
(*inlined_body);
1491
*inlined_body = copy_body
(id);
1492
#else
/* INLINER_FOR_JAVA */
…
1503
#endif
/* INLINER_FOR_JAVA */
1504
1505
/* After the body
of the function comes the RET_LABEL. This must come
1506
before we evaluate the returned value
below, because that evaluation
1507
may cause RTL to be generated.
*/
1508
#ifndef
INLINER_FOR_JAVA
1509
COMPOUND_BODY (stmt)
1510
= chainon (COMPOUND_BODY (stmt),
1511
build_stmt (LABEL_STMT,
id->ret_label));
1512
#else
/* INLINER_FOR_JAVA */
…
1519
#endif
/* INLINER_FOR_JAVA */
1520
1521
/* Finally, mention
the returned value so that the value of the
1522
statement-expression is the returned value
of the function.
*/
1523
#ifndef
INLINER_FOR_JAVA
1524
COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY
(stmt), use_stmt);
1525
1526
/* Close the block
for the parameters.
*/
1527
scope_stmt = build_stmt (SCOPE_STMT,
DECL_INITIAL (fn));
1528
SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
1529
remap_block
(scope_stmt, NULL_TREE, id);
1530
COMPOUND_BODY (stmt)
1531
= chainon (COMPOUND_BODY (stmt),
scope_stmt);
1532
#else
/* INLINER_FOR_JAVA */
DECL_SAVED_TREE
保存的就是代表函数体的
COMPOUND_STMT
或对等物。
704
static
tree
705
copy_body
(inline_data *id)
in tree-inline.c
706
{
707
tree body;
708
709
body = DECL_SAVED_TREE (VARRAY_TOP_TREE
(id->fns));
710
walk_tree
(&body, copy_body_r
, id, NULL);
711
712
return
body;
713
}
函数
copy_body_r
的大部我们前面已经看过,除了下面对
RETURN_STMT
的处理。这里首先为前面准备的
ret_label
构建一个
GOTO_STMT
。如果有返回值,还要在
GOTO_STMT
之前插入包含了返回值表达式的
EXPR_STMT
。
copy_body_r (continue)
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
{
534
tree return_stmt = *tp;
535
tree goto_stmt;
536
537
/* Build the
GOTO_STMT.
*/
538
#ifndef
INLINER_FOR_JAVA
539
goto_stmt = build_stmt (GOTO_STMT,
id->ret_label);
540
TREE_CHAIN (goto_stmt) = TREE_CHAIN
(return_stmt);
541
GOTO_FAKE_P (goto_stmt) = 1;
542
#else
/* INLINER_FOR_JAVA */
…
546
#endif
/* INLINER_FOR_JAVA */
547
548
/* If we're returning something, just turn
that into an
549
assignment into the equivalent of the original
550
RESULT_DECL.
*/
551
#ifndef
INLINER_FOR_JAVA
552
if (RETURN_STMT_EXPR (return_stmt))
553
{
554
*tp
= build_stmt (EXPR_STMT,
555
RETURN_STMT_EXPR (return_stmt));
556
STMT_IS_FULL_EXPR_P (*tp) = 1;
557
/* And then jump to the end of the function.
*/
558
TREE_CHAIN (*tp) = goto_stmt;
559
}
560
#else
/* INLINER_FOR_JAVA */
…
567
#endif
/* INLINER_FOR_JAVA */
568
/* If we're not
returning anything just do the jump.
*/
569
else
570
*tp = goto_stmt;
在这里
RETURN_STMT
被(可能出现)
EXPR_STMT
及
GOTO_STMT
所代替,不过其主要内容都在
RETURN_STMT_EXPR
域中,现在这个域转入了
EXPR_STMT
里。注意,
copy_body_r
总是返回
0
,那么
walk_tree
仍会进入这些新的
STMT
的内部(
walk_tree
执行前序遍历),把出现在原来
RETURN_STMT_EXPR
域中的
RETURN_DECL
(它被视为局部变量)替换掉。
拷贝、替换完函数体后,把先前准备的
use_stmt
附上。那么内联函数的展开实际上是这样一个结果:
double retVal = inline_f1 (int a1, short a2)
=>
double retVal = { int a1; short a2; double `
匿名返回值
`; { `
替换后函数体
` }; ret_lable: `
匿名返回值
`; }
expand_call_inline (continue)
1547
/* Clean up.
*/
1548
splay_tree_delete (id->decl_map);
1549
id->decl_map = st;
1550
1551
/* Although, from
the semantic viewpoint, the new expression has
1552
side-effects only if the old one did, it is
not possible, from
1553
the technical viewpoint, to evaluate the
body of a function
1554
multiple times without serious havoc.
*/
1555
TREE_SIDE_EFFECTS (expr) = 1;
1556
1557
/* Replace the call
by the inlined body. Wrap it in an
1558
EXPR_WITH_FILE_LOCATION so that we'll get
debugging line notes
1559
pointing to the right place.
*/
1560
#ifndef
INLINER_FOR_JAVA
1561
chain = TREE_CHAIN (*tp);
1562
#endif
/* INLINER_FOR_JAVA */
1563
*tp = build_expr_wfl (expr, DECL_SOURCE_FILE
(fn), DECL_SOURCE_LINE (fn),
1564
/*col=*/
0);
1565
EXPR_WFL_EMIT_LINE_NOTE (*tp) = 1;
1566
#ifndef
INLINER_FOR_JAVA
1567
TREE_CHAIN (*tp) = chain;
1568
#endif
/* not INLINER_FOR_JAVA */
1569
pop_srcloc ();
1570
1571
/* If the value of
the new expression is ignored, that's OK. We
1572
don't warn about this for CALL_EXPRs, so we
shouldn't warn about
1573
the equivalent inlined version either.
*/
1574
TREE_USED (*tp) = 1;
1575
1576
/* Update callgraph
if needed.
*/
1577
if (id->decl)
1578
{
1579
cgraph_remove_call (id->decl, fn);
1580
cgraph_create_edges
(id->decl, *inlined_body);
1581
}
1582
1583
/* Recurse into the
body of the just inlined function.
*/
1584
{
1585
tree old_decl = id->current_decl;
1586
id->current_decl = fn;
1587
expand_calls_inline
(inlined_body, id);
1588
id->current_decl = old_decl;
1589
}
1590
VARRAY_POP (id->fns);
1591
1592
/* Don't walk into
subtrees. We've already handled them above.
*/
1593
*walk_subtrees = 0;
1594
1595
(*lang_hooks
.tree_inlining.end_inlining) (fn);
1596
1597
/* Keep
iterating.
*/
1598
return
NULL_TREE;
1599
}
上面
inlined_body
指向展开的函数体,因为其中可能有
CALL_EXPR
,继续使用
expand_calls_inline
来展开可能存在的内联函数。看到
expand_calls_inline
总是返回
NULL
,它希望
walk_tree
能完整遍历调用者函数。
构建返回变量
加入为形参构建的局部变量后,紧接着这些变量,(可能)声明用于返回的变量。
expand_call_inline (continue)
1467
/* Declare the return
variable for the function.
*/
1468
COMPOUND_BODY (stmt)
1469
= chainon (COMPOUND_BODY (stmt),
1470
declare_return_variable
(id, return_slot_addr, &use_stmt));
1471
#else
/* INLINER_FOR_JAVA */
….
1483
#endif
/* INLINER_FOR_JAVA */
上面的
return_slot_addr
,如果使用具名返回值优化(
NRVO
)通过形参返回聚集对象时,用于指向这个对象;否则就是
NULL
(在前面拷贝形参列表时,我们专门去掉了对这个对象的处理)。
913
#ifndef
INLINER_FOR_JAVA
914
static
tree
915
declare_return_variable
(struct
inline_data *id, tree return_slot_addr,
in tree-inline.c
916
tree *use_stmt)
917
#else
/* INLINER_FOR_JAVA */
…
921
#endif
/* INLINER_FOR_JAVA */
922
{
923
tree fn = VARRAY_TOP_TREE (id->fns);
924
tree result = DECL_RESULT (fn);
925
#if
ndef
INLINER_FOR_JAVA
926
tree var;
927
#endif
/* not INLINER_FOR_JAVA */
928
int need_return_decl = 1;
929
930
/* We don't need to
do anything for functions that don't return
931
anything.
*/
932
if (!result || VOID_TYPE_P (TREE_TYPE
(result)))
933
{
934
#ifndef
INLINER_FOR_JAVA
935
*use_stmt = NULL_TREE;
936
#else
/* INLINER_FOR_JAVA */
…
938
#endif
/* INLINER_FOR_JAVA */
939
return
NULL_TREE;
940
}
941
942
#ifndef
INLINER_FOR_JAVA
943
var = ((*lang_hooks
.tree_inlining.copy_res_decl_for_inlining
)
944
(result, fn, VARRAY_TREE (id->fns, 0),
id->decl_map,
945
&need_return_decl, return_slot_addr));
946
947
/* Register the
VAR_DECL as the equivalent for the RESULT_DECL; that
948
way, when the
RESULT_DECL is encountered, it will be
949
automatically
replaced by the VAR_DECL.
*/
950
splay_tree_insert (id->decl_map,
951
(splay_tree_key) result,
952
(splay_tree_value) var);
953
954
/* Build the
USE_STMT. If the return type of the function was
955
promoted, convert it back to the expected
type.
*/
956
if (TREE_TYPE (var) == TREE_TYPE (TREE_TYPE
(fn)))
957
*use_stmt = build_stmt (EXPR_STMT, var);
958
else
959
*use_stmt = build_stmt (EXPR_STMT,
960
build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE
(fn)),
961
var));
962
TREE_ADDRESSABLE (*use_stmt) = 1;
963
964
/* Build the
declaration statement if FN does not return an
965
aggregate.
*/
966
if (need_return_decl)
967
return
build_stmt (DECL_STMT, var);
968
#else
/* INLINER_FOR_JAVA */
...
979
#endif
/* INLINER_FOR_JAVA */
980
/* If FN does
return an aggregate, there's no need to declare the
981
return variable;
we're using a variable in our caller's frame.
*/
982
else
983
return
NULL_TREE;
984
}
如果没有返回值或返回值是
NULL
,显然什么都不用做,否则就要拷贝返回值。在对下面函数的调用中,
result
是函数的返回值声明,
fn
是当前被调用函数,
caller
是调用者。因为调用返回聚集对象的函数,调用者需要传入返回地址(
NRVO
的做法),这个变量由调用者负责声明,我们不需要管;但其他返回值,在这里我们需要为它们声明对应的变量,因此相应设置
need_decl
(
2171
行)。
2147
tree
2148
cp_copy_res_decl_for_inlining
(tree result,
in tree.c
2149
tree fn,
2150
tree caller,
2151
void* decl_map_,
2152
int* need_decl,
2153
tree
return_slot_addr)
2154
{
2155
splay_tree decl_map = (splay_tree)decl_map_;
2156
tree var;
2157
2158
/* If FN returns an
aggregate then the caller will always pass the
2159
address of the
return slot explicitly. If we were just to
2160
create a new
VAR_DECL here, then the result of this function
2161
would be copied
(bitwise) into the variable initialized by the
2162
TARGET_EXPR.
That's incorrect, so we must transform any
2163
references to the
RESULT into references to the target.
*/
2164
2165
/* We should have
an explicit return slot iff the return type is
2166
TREE_ADDRESSABLE.
See simplify_aggr_init_expr.
*/
2167
if (TREE_ADDRESSABLE (TREE_TYPE (result))
2168
!= (return_slot_addr != NULL_TREE))
2169
abort ();
2170
2171
*need_decl = !return_slot_addr;
2172
if (return_slot_addr)
2173
{
2174
var = build_indirect_ref
(return_slot_addr, "");
2175
if (!
same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (var),
2176
TREE_TYPE (result)))
2177
abort ();
2178
}
2179
/* Otherwise, make
an appropriate copy.
*/
2180
else
2181
var = copy_decl_for_inlining (result, fn,
caller);
2182
2183
if (DECL_SAVED_FUNCTION_DATA (fn))
2184
{
2185
tree nrv = DECL_SAVED_FUNCTION_DATA
(fn)->x_return_value;
2186
if (nrv)
2187
{
2188
/* We have a named
return value; copy the name and source
2189
position so we can get reasonable debugging information,
and
2190
register the return variable as its equivalent.
*/
2191
if (TREE_CODE (var) == VAR_DECL
2192
/* But not if we're initializing a variable from the
2193
enclosing function
which already has its own name.
*/
2194
&& DECL_NAME (var) == NULL_TREE)
2195
{
2196
DECL_NAME (var) = DECL_NAME (nrv);
2197
DECL_SOURCE_LOCATION (var) =
DECL_SOURCE_LOCATION (nrv);
2198
DECL_ABSTRACT_ORIGIN
(var) = DECL_ORIGIN (nrv);
2199
/* Don't lose initialization info.
*/
2200
DECL_INITIAL (var) = DECL_INITIAL (nrv);
2201
/* Don't forget that it needs to go in the stack.
*/
2202
TREE_ADDRESSABLE (var) = TREE_ADDRESSABLE
(nrv);
2203
}
2204
2205
splay_tree_insert (decl_map,
2206
(splay_tree_key) nrv,
2207
(splay_tree_value) var);
2208
}
2209
}
2210
2211
return
var;
2212
}
DECL_SAVED_FUNCTION_DATA
保存了描述该函数的
language_function
对象(它在被
finsh_function
调用的
save_function_data
设置)。而其中的
x_return_value
域专门用于
NRVO
的目的(它在被
check_return_expr
设置为返回值)。因为在
2174
行已经为这个返回值构建了
return_slot_addr
所指向对象的
INDRECT_REF
节点,这是真正用于返回值的对象,因此根据
x_return_value
域来设置它,并把它作为
x_return_value
的替代。
如果返回值不需要声明,
declare_return_variable
将返回
NULL
,否则就是相应的
DECL_STMT
,这个
STMT
在
expand_call_inline
的
1470
行插入到为形参声明的变量后。而
use_stmt
则要在展开末尾才能插入(作为
ret_label
的对象)。
5.13.5.3.2.4.2.3.4.
拷贝函数体
在声明了对应于形参及返回值的局部变量后,可以拷贝函数体并使用这些变量替换形参及返回值,这由下面的
copy_body
函数来进行。
expand_call_inline (continue)
1485
/* After we've
initialized the parameters, we insert the body of the
1486
function itself.
*/
1487
#ifndef
INLINER_FOR_JAVA
1488
inlined_body = &COMPOUND_BODY (stmt);
1489
while
(*inlined_body)
1490
inlined_body = &TREE_CHAIN
(*inlined_body);
1491
*inlined_body = copy_body
(id);
1492
#else
/* INLINER_FOR_JAVA */
…
1503
#endif
/* INLINER_FOR_JAVA */
1504
1505
/* After the body
of the function comes the RET_LABEL. This must come
1506
before we evaluate the returned value
below, because that evaluation
1507
may cause RTL to be generated.
*/
1508
#ifndef
INLINER_FOR_JAVA
1509
COMPOUND_BODY (stmt)
1510
= chainon (COMPOUND_BODY (stmt),
1511
build_stmt (LABEL_STMT,
id->ret_label));
1512
#else
/* INLINER_FOR_JAVA */
…
1519
#endif
/* INLINER_FOR_JAVA */
1520
1521
/* Finally, mention
the returned value so that the value of the
1522
statement-expression is the returned value
of the function.
*/
1523
#ifndef
INLINER_FOR_JAVA
1524
COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY
(stmt), use_stmt);
1525
1526
/* Close the block
for the parameters.
*/
1527
scope_stmt = build_stmt (SCOPE_STMT,
DECL_INITIAL (fn));
1528
SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
1529
remap_block
(scope_stmt, NULL_TREE, id);
1530
COMPOUND_BODY (stmt)
1531
= chainon (COMPOUND_BODY (stmt),
scope_stmt);
1532
#else
/* INLINER_FOR_JAVA */
DECL_SAVED_TREE
保存的就是代表函数体的
COMPOUND_STMT
或对等物。
704
static
tree
705
copy_body
(inline_data *id)
in tree-inline.c
706
{
707
tree body;
708
709
body = DECL_SAVED_TREE (VARRAY_TOP_TREE
(id->fns));
710
walk_tree
(&body, copy_body_r
, id, NULL);
711
712
return
body;
713
}
函数
copy_body_r
的大部我们前面已经看过,除了下面对
RETURN_STMT
的处理。这里首先为前面准备的
ret_label
构建一个
GOTO_STMT
。如果有返回值,还要在
GOTO_STMT
之前插入包含了返回值表达式的
EXPR_STMT
。
copy_body_r (continue)
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
{
534
tree return_stmt = *tp;
535
tree goto_stmt;
536
537
/* Build the
GOTO_STMT.
*/
538
#ifndef
INLINER_FOR_JAVA
539
goto_stmt = build_stmt (GOTO_STMT,
id->ret_label);
540
TREE_CHAIN (goto_stmt) = TREE_CHAIN
(return_stmt);
541
GOTO_FAKE_P (goto_stmt) = 1;
542
#else
/* INLINER_FOR_JAVA */
…
546
#endif
/* INLINER_FOR_JAVA */
547
548
/* If we're returning something, just turn
that into an
549
assignment into the equivalent of the original
550
RESULT_DECL.
*/
551
#ifndef
INLINER_FOR_JAVA
552
if (RETURN_STMT_EXPR (return_stmt))
553
{
554
*tp
= build_stmt (EXPR_STMT,
555
RETURN_STMT_EXPR (return_stmt));
556
STMT_IS_FULL_EXPR_P (*tp) = 1;
557
/* And then jump to the end of the function.
*/
558
TREE_CHAIN (*tp) = goto_stmt;
559
}
560
#else
/* INLINER_FOR_JAVA */
…
567
#endif
/* INLINER_FOR_JAVA */
568
/* If we're not
returning anything just do the jump.
*/
569
else
570
*tp = goto_stmt;
在这里
RETURN_STMT
被(可能出现)
EXPR_STMT
及
GOTO_STMT
所代替,不过其主要内容都在
RETURN_STMT_EXPR
域中,现在这个域转入了
EXPR_STMT
里。注意,
copy_body_r
总是返回
0
,那么
walk_tree
仍会进入这些新的
STMT
的内部(
walk_tree
执行前序遍历),把出现在原来
RETURN_STMT_EXPR
域中的
RETURN_DECL
(它被视为局部变量)替换掉。
拷贝、替换完函数体后,把先前准备的
use_stmt
附上。那么内联函数的展开实际上是这样一个结果:
double retVal = inline_f1 (int a1, short a2)
=>
double retVal = { int a1; short a2; double `
匿名返回值
`; { `
替换后函数体
` }; ret_lable: `
匿名返回值
`; }
expand_call_inline (continue)
1547
/* Clean up.
*/
1548
splay_tree_delete (id->decl_map);
1549
id->decl_map = st;
1550
1551
/* Although, from
the semantic viewpoint, the new expression has
1552
side-effects only if the old one did, it is
not possible, from
1553
the technical viewpoint, to evaluate the
body of a function
1554
multiple times without serious havoc.
*/
1555
TREE_SIDE_EFFECTS (expr) = 1;
1556
1557
/* Replace the call
by the inlined body. Wrap it in an
1558
EXPR_WITH_FILE_LOCATION so that we'll get
debugging line notes
1559
pointing to the right place.
*/
1560
#ifndef
INLINER_FOR_JAVA
1561
chain = TREE_CHAIN (*tp);
1562
#endif
/* INLINER_FOR_JAVA */
1563
*tp = build_expr_wfl (expr, DECL_SOURCE_FILE
(fn), DECL_SOURCE_LINE (fn),
1564
/*col=*/
0);
1565
EXPR_WFL_EMIT_LINE_NOTE (*tp) = 1;
1566
#ifndef
INLINER_FOR_JAVA
1567
TREE_CHAIN (*tp) = chain;
1568
#endif
/* not INLINER_FOR_JAVA */
1569
pop_srcloc ();
1570
1571
/* If the value of
the new expression is ignored, that's OK. We
1572
don't warn about this for CALL_EXPRs, so we
shouldn't warn about
1573
the equivalent inlined version either.
*/
1574
TREE_USED (*tp) = 1;
1575
1576
/* Update callgraph
if needed.
*/
1577
if (id->decl)
1578
{
1579
cgraph_remove_call (id->decl, fn);
1580
cgraph_create_edges
(id->decl, *inlined_body);
1581
}
1582
1583
/* Recurse into the
body of the just inlined function.
*/
1584
{
1585
tree old_decl = id->current_decl;
1586
id->current_decl = fn;
1587
expand_calls_inline
(inlined_body, id);
1588
id->current_decl = old_decl;
1589
}
1590
VARRAY_POP (id->fns);
1591
1592
/* Don't walk into
subtrees. We've already handled them above.
*/
1593
*walk_subtrees = 0;
1594
1595
(*lang_hooks
.tree_inlining.end_inlining) (fn);
1596
1597
/* Keep
iterating.
*/
1598
return
NULL_TREE;
1599
}
上面
inlined_body
指向展开的函数体,因为其中可能有
CALL_EXPR
,继续使用
expand_calls_inline
来展开可能存在的内联函数。看到
expand_calls_inline
总是返回
NULL
,它希望
walk_tree
能完整遍历调用者函数。
相关文章推荐
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(164)
- GCC-3.4.6源代码学习笔记(109)
- GCC-3.4.6源代码学习笔记(56)
- GCC-3.4.6源代码学习笔记(139-续1)
- GCC-3.4.6源代码学习笔记(140)
- GCC-3.4.6源代码学习笔记(144)
- GCC-3.4.6源代码学习笔记(69)
- GCC-3.4.6源代码学习笔记(148)
- GCC-3.4.6源代码学习笔记(24)
- GCC-3.4.6源代码学习笔记(158)
- GCC-3.4.6源代码学习笔记(137)
- GCC-3.4.6源代码学习笔记(44)
- GCC-3.4.6源代码学习笔记(29)
- GCC-3.4.6源代码学习笔记(118)
- GCC-3.4.6源代码学习笔记(129 续)
- GCC-3.4.6源代码学习笔记(172)
- GCC-3.4.6源代码学习笔记(132)
- GCC-3.4.6源代码学习笔记(133)
- GCC-3.4.6源代码学习笔记(78)