5.13.5.3.2.4.2.3.3. Construct variable for return value
After adding local variables for parameters, immediately declare (possible) variable for return value.
expand_call_inline (continue)
1467
1468 COMPOUND_BODY (stmt)
1469 = chainon (COMPOUND_BODY (stmt),
1470 declare_return_variable (id, return_slot_addr, &use_stmt));
1471 #else
….
1483 #endif
Above return_slot_addr , if applying named return value optimziation (NRVO) to return aggregate object, is the slot for returning this object; otherwise is NULL (previous when copying parameters list, we remove this slot from processing).
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
…
921 #endif
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
928 int need_return_decl = 1;
929
930
932 if (!result || VOID_TYPE_P (TREE_TYPE (result)))
933 {
934 #ifndef INLINER_FOR_JAVA
935 *use_stmt = NULL_TREE;
936 #else
…
938 #endif
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
950 splay_tree_insert (id->decl_map,
951 (splay_tree_key) result,
952 (splay_tree_value) var);
953
954
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
966 if (need_return_decl)
967 return build_stmt (DECL_STMT, var);
968 #else
...
979 #endif
980
982 else
983 return NULL_TREE;
984 }
If there is no return value or it is NULL, of course need do nothing, or need copy the return value. In calling below function, result is the declaration of the function return value, fn is the function currently called, caller is the caller. As at calling function returning aggregate object, the caller needs to pass in the return slot (the way NRVO takes), this variable is declared by the caller, we needn’t care about it; but for other return value, we need declare variable for them here, and thus set need_decl (line 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
2164
2165
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
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
2191 if (TREE_CODE (var) == VAR_DECL
2192
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
2200 DECL_INITIAL (var) = DECL_INITIAL (nrv);
2201
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 saves the language_function objeect describing the function (it is set save_function_data in called by finsh_function ). In it field x_return_value is designed for NRVO purpose (which is set as return value in check_return_expr ). As at line 2174 INDIRECT_REF has been created for the object reffered by return_slot_addr , which is the object really used for return value, so set it according to field x_return_value, then update x_return_value by it.
If the return value needsn’t declaration, declare_return_variable will return NULL, or will return the corresponding DECL_STMT, which is inserted after variables for parameters at line 1470 in expand_call_inline . While use_stmt will be added in at the end of the expansion (as the associated target of ret_label).
5.13.5.3.2.4.2.3.4. Copy function body
With declaring local variables for parameters and return value, it can copy the function body and at the same time replacing the parameters and the return value, which is done by copy_body below.
expand_call_inline (continue)
1485
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
…
1503 #endif
1504
1505
1508 #ifndef INLINER_FOR_JAVA
1509 COMPOUND_BODY (stmt)
1510 = chainon (COMPOUND_BODY (stmt),
1511 build_stmt (LABEL_STMT, id->ret_label));
1512 #else
…
1519 #endif
1520
1521
1523 #ifndef INLINER_FOR_JAVA
1524 COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), use_stmt);
1525
1526
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
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 }
We have seen the most part of copy_body_r before, except below treatment of RETURN_STMT. Here first building a GOTO_STMT for ret_label prepared beforehand. If there is return value, it needs to insert EXPR_STMT of the return expression before GOTO_STMT.
copy_body_r (continue)
528 #ifndef INLINER_FOR_JAVA
529 if (TREE_CODE (*tp) == RETURN_STMT && id->ret_label)
530 #else
…
532 #endif
533 {
534 tree return_stmt = *tp;
535 tree goto_stmt;
536
537
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
547
548
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
558 TREE_CHAIN (*tp) = goto_stmt;
559 }
560 #else
…
567 #endif
568
569 else
570 *tp = goto_stmt;
Here RETURN_STMT is replaced by (possible) EXPR_STMT and GOTO_STMT, but its content is recorded by field RETURN_STMT_EXPR, which is now included by the EXPR_STMT. See that copy_body_r always returns 0, so walk_tree will still enter these new STMT nodes (walk_tree does pre-order traversal), and replaces the RETURN_DECL contained.
After copying, transforming the function body, attaches use_stmt prepared before. Thus expanding the inline function will get the result as:
double retVal = inline_f1 (int a1, short a2) =>
double retVal = { int a1; short a2; double `anon var`; { `copy and transform body` }; ret_lable: ` anon var `; }
expand_call_inline (continue)
1547
1548 splay_tree_delete (id->decl_map);
1549 id->decl_map = st;
1550
1551
1555 TREE_SIDE_EFFECTS (expr) = 1;
1556
1557
1560 #ifndef INLINER_FOR_JAVA
1561 chain = TREE_CHAIN (*tp);
1562 #endif
1563 *tp = build_expr_wfl (expr, DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn),
1564 0);
1565 EXPR_WFL_EMIT_LINE_NOTE (*tp) = 1;
1566 #ifndef INLINER_FOR_JAVA
1567 TREE_CHAIN (*tp) = chain;
1568 #endif
1569 pop_srcloc ();
1570
1571
1574 TREE_USED (*tp) = 1;
1575
1576
1577 if (id->decl)
1578 {
1579 cgraph_remove_call (id->decl, fn);
1580 cgraph_create_edges (id->decl, *inlined_body);
1581 }
1582
1583
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
1593 *walk_subtrees = 0;
1594
1595 (*lang_hooks .tree_inlining.end_inlining) (fn);
1596
1597
1598 return NULL_TREE;
1599 }
Above inlined_body points to the expanded body, as in which may contain CALL_EXPR, continue to use expand_calls_inline to expand these inline functions. See that expand_calls_inline always returns NULL, it expects walk_tree to traverse the caller entirely.