GCC-3.4.6源代码学习笔记(181)

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 能完整遍历调用者函数。

你可能感兴趣的:(java,function,tree,null,Build,insert)