天天看点

Studying note of GCC-3.4.6 source (181)

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.