您的位置:首页 > 编程语言

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

能完整遍历调用者函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: