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   /* 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 */

 

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 /* 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  }

 

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   /* 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 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   /* 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  }

 

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 /* 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;

 

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   /* 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 }

 

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.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值