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

5.13.5.3.2.4.2.2.    产生初始化函数实参的代码

下面为 decl_map 域构建了一个 splay 树,它用于映射内联函数中的局部声明到所内联入函数中的对等物。在 1393 行, CALL_EXPR_HAS_RETURN_SLOT_ADDR 如果不是 0 ,表示返回位置的地址是实参列表的一部分,而且这个地址总是列表中的第一个对象。

 

expand_call_inline (continue)

 

1384   /* Local declarations will be replaced by their equivalents in this

1385      map.  */

1386   st = id->decl_map;

1387   id->decl_map = splay_tree_new (splay_tree_compare_pointers,

1388                               NULL, NULL);

1389

1390   /* Initialize the parameters.  */

1391   args = TREE_OPERAND (t, 1);

1392   return_slot_addr = NULL_TREE;

1393   if (CALL_EXPR_HAS_RETURN_SLOT_ADDR (t))

1394   {

1395     return_slot_addr = TREE_VALUE (args);

1396     args = TREE_CHAIN (args);

1397   }

1398

1399 #ifndef INLINER_FOR_JAVA

1400   arg_inits = initialize_inlined_parameters (id, args, fn);

1401   /* Expand any inlined calls in the initializers. Do this before we

1402     push FN on the stack of functions we are inlining; we want to

1403     inline calls to FN that appear in the initializers for the

1404     parameters.  */

1405   expand_calls_inline (&arg_inits, id);

1406   /* And add them to the tree.  */

1407   COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), arg_inits);

 

类似于函数调用,内联函数虽然是在其调用者体内展开,其实参可能需要转换到形参类型,或者需要额外的初始化代码来得到拷贝。这些都需要下面的函数来处理。

 

718  static tree

719  #ifndef INLINER_FOR_JAVA

720  initialize_inlined_parameters (inline_data *id, tree args, tree fn)             in tree-inline.c

721  #else /* INLINER_FOR_JAVA */

722  initialize_inlined_parameters (inline_data *id, tree args, tree fn, tree block)

723  #endif /* INLINER_FOR_JAVA */

724  {

725    tree init_stmts;

726    tree parms;

727    tree a;

728    tree p;

729  #ifdef INLINER_FOR_JAVA

730    tree vars = NULL_TREE;

731  #endif /* INLINER_FOR_JAVA */

732    int argnum = 0;

733 

734    /* Figure out what the parameters are.  */

735    parms =

736         DECL_ARGUMENTS (fn);

737 

738    /* Start with no initializations whatsoever.  * /

739    init_stmts = NULL_TREE;

740 

741    /* Loop through the parameter declarations, replacing each with an

742      equivalent VAR_DECL, appropriately initialized.  */

743    for (p = parms, a = args; p;

744         a = a ? TREE_CHAIN (a) : a, p = TREE_CHAIN (p))

745    {

746  #ifndef INLINER_FOR_JAVA

747      tree init_stmt;

748      tree cleanup;

749  #endif /* not INLINER_FOR_JAVA */

750      tree var;

751      tree value;

752      tree var_sub;

753 

754      ++argnum;

755 

756      /* Find the initializer.  */

757      value = (*lang_hooks .tree_inlining.convert_parm_for_inlining)

758              (p, a ? TREE_VALUE (a) : NULL_TREE, fn, argnum);

759 

760       /* If the parameter is never assigned to, we may not need to

761          create a new variable here at all. Instead, we may be able

762         to just use the argument value.  */

763      if (TREE_READONLY (p)

764          && !TREE_ADDRESSABLE (p)

765          && value && !TREE_SIDE_EFFECTS (value))

766      {

767         /* Simplify the value, if possible.  */

768         value = fold (DECL_P (value) ? decl_constant_value (value) : value);

769 

770          /* We can't risk substituting complex expressions. They

771            might contain variables that will be assigned to later.

772           Theoretically, we could check the expression to see if

773           all of the variables that determine its value are

774           read-only, but we don't bother.  */

775         if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))

776         {

777            /* If this is a declaration, wrap it a NOP_EXPR so that

778              we don't try to put the VALUE on the list of

779             BLOCK_VARS.  */

780           if (DECL_P (value))

781            value = build1 (NOP_EXPR, TREE_TYPE (value), value);

782 

783           /* If this is a constant, make sure it has the right type.  */

784           else if (TREE_TYPE (value) != TREE_TYPE (p))

785            value = fold (build1 (NOP_EXPR, TREE_TYPE (p), value));

786 

787           splay_tree_insert (id->decl_map,

788                          (splay_tree_key) p,

789                          (splay_tree_value) value);

790           continue ;

791         }

792      }

 

上面在 757 行,钩子 convert_parm_for_inlining 提供实参到形参类型的转换处理。不过 C++ 是强类型语言(注意 C 不是),转换在解析时完成,因此这个钩子在这里不做任何事。

另外,如果形参是常量类型,并且其地址没有被引用,那么只要实参是没有副作用的,就可能可以直接使用实参值,而不需要另外构建新的局部变量。不过实际上, GCC 在这里采用了保守的做法,经过常量折叠优化后实参,也必须是常量或只读性的,才能直接使用其值。对于合乎要求的实参,我们使用 NOP_EXPR 来封装它们。

 

initialize_inlined_parameters (continue)

 

794       /* Make an equivalent VAR_DECL.  */

795       var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0));

796 

797       /* See if the frontend wants to pass this by invisible reference. If

798         so, our new VAR_DECL will have REFERENCE_TYPE, and we need to

799         replace uses of the PARM_DECL with dereferences.  */

800       if (TREE_TYPE (var) != TREE_TYPE (p)

801             && POINTER_TYPE_P (TREE_TYPE (var))

802             && TREE_TYPE (TREE_TYPE (var)) == TREE_TYPE (p))

803        var_sub = build1 (INDIRECT_REF, TREE_TYPE (p), var);

804      else

805        var_sub = var;

806 

807       /* Register the VAR_DECL as the equivalent for the PARM_DECL;

808         that way, when the PARM_DECL is encountered, it will be

809         automatically replaced by the VAR_DECL.  */

810      splay_tree_insert (id->decl_map,

811                       (splay_tree_key) p,

812                      (splay_tree_value) var_sub);

813 

814       /* Declare this new variable.  */

815  #ifndef INLINER_FOR_JAVA

816      init_stmt = build_stmt (DECL_STMT, var);

817      TREE_CHAIN (init_stmt) = init_stmts;

818      init_stmts = init_stmt;

819  #else /* INLINER_FOR_JAVA */

       …

822  #endif /* INLINER_FOR_JAVA */

823 

824      /* Initialize this VAR_DECL from the equivalent argument. If

825         the argument is an object, created via a constructor or copy,

826         this will not result in an extra copy: the TARGET_EXPR

827         representing the argument will be bound to VAR, and the

828         object will be constructed in VAR.  */

829      if (! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))

830  #ifndef INLINER_FOR_JAVA

831        DECL_INITIAL (var) = value;

832      else

833      {

834         /* Even if P was TREE_READONLY, the new VAR should not be.

835           I n the original code, we would have constructed a

836           temporary, and then the function body would have never

837           changed the value of P. However, now, we will be

838           constructing VAR directly. The constructor body may

839           change its value multiple times as it is being

840           constructed. Therefore, it must not be TREE_READONLY;

841           the back-end assumes that TREE_READONLY variable is

842           assigned to only once.  */

843          TREE_READONLY (var) = 0;

844 

845         /* Build a run-time initialization.  */

846         init_stmt = build_stmt (EXPR_STMT,

847                            build (INIT_EXPR, TREE_TYPE (p),

848                                  var, value));

849         /* Add this initialization to the list. Note that we want the

850           declaration *after* the initialization because we are going

851           to reverse all the initialization statements below.  */

852         TREE_CHAIN (init_stmt) = init_stmts;

853         init_stmts = init_stmt;

854      }

 

795 行, copy_decl_for_inlining 根据这个形参,在调用者函数中声明一个与该形参同名、类型相同的 VAR_DECL 。而 816 行使得 copy_decl_for_inlining 所构建的 VAR_DECL 成为一个局部声明。这样,内联函数的参数传递将转变为一组赋值操作。

另外,满足上面 800 行条件的情况是,我们向一个引用类型的形参传入一个对象,因此这里我们把这个对象封装入 INDIRECT_REF 中。

 

initialize_inlined_parameters (continue)

 

856      /* See if we need to clean up the declaration.  */

857      cleanup = (*lang_hooks .maybe_build_cleanup ) (var);

858      if (cleanup)

859      {

860         tree cleanup_stmt;

861         /* Build the cleanup statement.  */

862         cleanup_stmt = build_stmt (CLEANUP_STMT, var, cleanup);

863         /* Add it to the *front* of the list; the list will be

864           reversed below.  */

865         TREE_CHAIN (cleanup_stmt) = init_stmts;

866         init_stmts = cleanup_stmt;

867      }

868  #else /* INLINER_FOR_JAVA */

      …

881  #endif /* INLINER_FOR_JAVA */

882    }

883 

884  #ifndef INLINER_FOR_JAVA

885    /* Evaluate trailing arguments.  */

886    for (; a; a = TREE_CHAIN (a))

887    {

888      tree init_stmt;

889      tree value = TREE_VALUE (a);

890 

891      if (! value || ! TREE_SIDE_EFFECTS (value))

892        continue ;

893 

894      init_stmt = build_stmt (EXPR_STMT, value);

895      TREE_CHAIN (init_stmt) = init_stmts;

896      init_stmts = init_stmt;

897    }

898 

899    /* The initialization statements have been built up in reverse

900      order. Straighten them out now.  */

901    return nreverse (init_stmts);

902  #else /* INLINER_FOR_JAVA */

       …

905  #endif /* INLINER_FOR_JAVA */

906  }

 

如果变量的析构需要调用析构函数,对应的代码则由 857 行的钩子来产生。 886 行的循环则是处理缺省参数的情况,因为这部分需要通过 var_start var_arg var_end 这样的宏来处理,除非传入的实参声明为“ volatile ”( TREE_SIDE_EFFECTS true ),不需要为其构建局部变量( var_* 系列的宏由编译器中相应的 __builtin_var_* 内建函数实现)。

901 行,这一系列初始化语句被返回。在这些初始化语句中,还可能存在内联函数的调用,因此紧接着为这些语句调用 expand_calls_inline

5.13.5.3.2.4.2.3.    展开内联函数体

5.13.5.3.2.4.2.3.1.            准备 ret_label

1431 行的 DECL_INLINED_FNS 用于记录要在函数 fn 中展开的内联函数,它在函数 optimize_inline_calls 中在完成该函数处理时设置(注意,我们现在正在处理调用 fn 的函数,因为我们按调用的先后次序处理函数, fn 应该已经完成这里的处理)。满足 1431 行条件表示 fn 没有展开内联函数,而且 fn 是被当前处理函数调用的,我们把它加入 id->inlined_fns ,在 optimize_inline_calls 中,这部分数据会被更新入 DECL_INLINED_FNS

 

expand_call_inline (continue)

 

1425   /* Record the function we are about to inline so that we can avoid

1426     recursing into it.  */

1427   VARRAY_PUSH_TREE (id->fns, fn);

1428

1429   /* Record the function we are about to inline if optimize_function

1430     has not been called on it yet and we don't have it in the list.  */

1431   if (! DECL_INLINED_FNS (fn))

1432   {

1433     int i;

1434

1435     for (i = VARRAY_ACTIVE_SIZE (id->inlined_fns) - 1; i >= 0; i--)

1436       if (VARRAY_TREE (id->inlined_fns, i) == fn)

1437          break ;

1438      if (i < 0)

1439       VARRAY_PUSH_TREE (id->inlined_fns, fn);

1440   }

1441

1442   /* Return statements in the function body will be replaced by jumps

1443     to the RET_LABEL.  */

1444   id->ret_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);

1445   DECL_CONTEXT (id->ret_label) = VARRAY_TREE (id->fns, 0);

1446

1447   if (! DECL_INITIAL (fn)

1448       || TREE_CODE (DECL_INITIAL (fn)) != BLOCK)

1449     abort ();

1450

1451 #ifndef INLINER_FOR_JAVA

1452   /* Create a block to put the parameters in. We have to do this

1453     after the parameters have been remapped because remapping

1454     parameters is different from remapping ordinary variables.  */

1455   scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));

1456   SCOPE_BEGIN_P (scope_stmt) = 1;

1457   SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;

1458   remap_block (scope_stmt, DECL_ARGUMENTS (fn), id);

1459   TREE_CHAIN (scope_stmt) = COMPOUND_BODY (stmt);

1460   COMPOUND_BODY (stmt) = scope_stmt;

14161    

1462   /* Tell the debugging backends that this block represents the

1463     outermost scope of the inlined function.  */

1464   if (SCOPE_STMT_BLOCK (scope_stmt))

1465     BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);

 

optimize_inline_calls 1636 行,看到 id->fns 中的第一个元素就是当前处理的函数。上面 1444 1445 行构建了一个 RET_LABEL 标签,用于把被调用函数的返回语句转变成跳转语句。在 1447 行, DECL_INITIAL 中保存了表示该函数绑定域的中间树,如果有效,它的第一个节点一定是 BLOCK 。上面在 1455 行引入了一个作用域来包含这些参数。

5.13.5.3.2.4.2.3.2.            替换形参

前面,已经准备好了初始化实参的代码,内联函数展开接下来的工作就是声明与形参同名、同类型的变量,而且函数体内所有引用到形参的地方都要改为引用相应的变量。其中声明与形参同名、同类型的变量由在 1458 行对 remap_block 的调用来完成。其中, DECL_ARGUMENTS 得到函数的形参列表。而在下面 337 行,“ SCOPE_STMT_BLOCK (scope_stmt) ”实际上得到的是“ DECL_INITIAL (fn) ”。

 

315  static void

316  #ifndef INLINER_FOR_JAVA

317  remap_block (tree scope_stmt, tree decls, inline_data *id)                       in tree-inline.c

       …

320  #endif /* INLINER_FOR_JAVA */

321  {

322  #ifndef INLINER_FOR_JAVA

323    /* We cannot do this in the cleanup for a TARGET_EXPR since we do

324       not know whether or not expand_expr will actually write out the

325      code we put there. If it does not, then we'll have more BLOCKs

326      than block-notes, and things will go awry. At some point, we

327       should make the back-end handle BLOCK notes in a tidier way,

328      without requiring a strict correspondence to the block-tree; then

329      this check can go.  */

330    if (id->in_target_cleanup_p)

331    {

332      SCOPE_STMT_BLOCK (scope_stmt) = NULL_TREE;

333      return ;

334    }

335 

336    /* If this is the beginning of a scope, remap the associated BLOCK.  */

337    if (SCOPE_BEGIN_P (scope_stmt) && SCOPE_STMT_BLOCK (scope_stmt))

338    {

339      tree old_block;

340      tree new_block;

341      tree old_var;

342      tree fn;

343 

344       /* Make the new block.  */

345      old_block = SCOPE_STMT_BLOCK (scope_stmt);

346      new_block = make_node (BLOCK);

347      TREE_USED (new_block) = TREE_USED (old_block);

348      BLOCK_ABSTRACT_ORIGIN (new_block) = old_block;

349      SCOPE_STMT_BLOCK (scope_stmt) = new_block;

350 

351      /* Remap its variables.  */

352      for (old_var = decls ? decls : BLOCK_VARS (old_block);

353             old_var;

354              old_var = TREE_CHAIN (old_var))

355      {

356         tree new_var;

357 

358         /* Remap the variable.  */

359         new_var = remap_decl (old_var, id);

360         /* If we didn't remap this variable, so we can't mess with

361           its TREE_CHAIN. If we remapped this variable to

362            something other than a declaration (say, if we mapped it

363           to a constant), then we must similarly omit any mention

364           of it here.  */

365          if (!new_var || !DECL_P (new_var))

366             ;

367          else

368         {

369             TREE_CHAIN (new_var) = BLOCK_VARS (new_block);

370           BLOCK_VARS (new_block) = new_var;

371           }

372      }

 

注意上面的 decls 是函数的参数列表( PARM_DECL ),而在其他地方调用 remap_block ,参数 decls 都是 NULL (这种情况下则通过 BLOCK_VARS 获取相应代码块中的变量声明)。看到上面的 new_block 则是 old_block (这里是参数列表)的一个替代物,它在 349 行代替了 old_block ,经过拷贝及转换的参数通过 BLOCK_VAR 链入 new_block 570 行),这样就完成了与形参同名、同类型变量在函数体内的声明。

下面是构建与形参同名、同类型变量的具体过程。

 

133  static tree

134  remap_decl (tree decl, inline_data *id)                                                  in tree-inline.c

135  {

136    splay_tree_node n;

137    tree fn;

138 

139    /* We only remap local variables in the current function.  */

140    fn = VARRAY_TOP_TREE (id->fns);

141    if (! (*lang_hooks .tree_inlining.auto_var_in_fn_p ) (decl, fn))

142      return NULL_TREE;

 

首先,需要选出声明在函数中的自动变量。显然,不同的语言对于自动变量会有自己的定义,对于 C++ ,钩子绑定到如下的函数( C C++ 对自动变量的定义实际上基本相同,但由于产生的语言中间树不同,它们采用了不同的判断函数)。

 

2136 int

2137 cp_auto_var_in_fn_p (tree var, tree fn)                                                        in tree.c

2138 {

2139   return (DECL_P (var) && DECL_CONTEXT (var) == fn

2140         && nonstatic_local_decl_p (var));

2141 }

 

如果声明已经被拷贝过了,那就万事大吉;否则就要先通过 copy_decl_for_inlining 拷贝节点在内容(其中把 PARM_DECL RESULT_DECL 拷贝成 VAR_DECL )。对于 *_DECL 节点,其 TREE_TYPE 可能需要进一步拷贝。

 

remap_decl (continue)

 

144    /* See if we have remapped this declaration.  */

145    n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);

146 

147    /* If we didn't already have an equivalent for this declaration,

148      create one now.  */

149    if (!n)

150    {

151      tree t;

152 

153      /* Make a copy of the variable or label.  */

154      t = copy_decl_for_inlining (decl, fn, VARRAY_TREE (id->fns, 0));

155 

156       /* Remap types, if necessary.  */

157      TREE_TYPE (t) = remap_type (TREE_TYPE (t), id);

158      if (TREE_CODE (t) == TYPE_DECL)

159        DECL_ORIGINAL_TYPE (t) = remap_type (DECL_ORIGINAL_TYPE (t), id);

160      else if (TREE_CODE (t) == PARM_DECL)

161        DECL_ARG_TYPE_AS_WRITTEN (t)

162              = remap_type (DECL_ARG_TYPE_AS_WRITTEN (t), id);

 

DECL_ORIGINAL_TYPE ,对于通过 typedef 定义的类型,保存了这个类型所引用的类型。而对于其他类型,这个域是 NULL 。而 DECL_ARG_TYPE_AS_WRITTEN 保存的是参数被写成的类型(比如函数或数组类型,但编译器为之产生的却是相应的指针类型)。不过在这里 PARM_DECL 不会出现(因为之前调用了 copy_decl_for_inlining

 

200  static tree

201  remap_type (tree type, inline_data *id)                                                 in tree-inline.c

202  {

203    splay_tree_node node;

204    tree new, t;

205 

206    if (type == NULL)

207      return type;

208 

209    /* See if we have remapped this type.  */

210    node = splay_tree_lookup (id->decl_map, (splay_tree_key) type);

211     if (node)

212      return (tree) node->value;

213 

214    /* The type only needs remapping if it's variably modified.  */

215    if (! variably_modified_type_p (type))

216    {

217      splay_tree_insert (id->decl_map, (splay_tree_key) type,

218                      (splay_tree_value) type);

219      return type;

220    }

221   

222    /* We do need a copy. build and register it now.  */

223    new = copy_node (type);

224    splay_tree_insert (id->decl_map, (splay_tree_key) type,

225                    (splay_tree_value) new);

226 

227    /* This is a new type, not a copy of an old type. Need to reassociate

228      variants. We can handle everything except the main variant lazily.  */

229    t = TYPE_MAIN_VARIANT (type);

230    if (type != t)

231    {

232      t = remap_type (t, id);

233      TYPE_MAIN_VARIANT (new) = t;

234      TYPE_NEXT_VARIANT (new) = TYPE_MAIN_VARIANT (t);

235      TYPE_NEXT_VARIANT (t) = new;

236    }

237    else

238    {

239      TYPE_MAIN_VARIANT (new) = new;

240      TYPE_NEXT_VARIANT (new) = NULL;

241    }

242 

243    /* Lazily create pointer and reference types.  */

244    TYPE_POINTER_TO (new) = NULL;

245    TYPE_REFERENCE_TO (new) = NULL;

246 

247    switch (TREE_CODE (new))

248    {

249      case INTEGER_TYPE:

250      case REAL_TYPE:

251      case ENUMERAL_TYPE:

252      case BOOLEAN_TYPE:

253      case CHAR_TYPE:

254        t = TYPE_MIN_VALUE (new);

255        if (t && TREE_CODE (t) != INTEGER_CST)

256          walk_tree (&TYPE_MIN_VALUE (new), copy_body_r , id, NULL);

257        t = TYPE_MAX_VALUE (new);

258        if (t && TREE_CODE (t) != INTEGER_CST)

259          walk_tree (&TYPE_MAX_VALUE (new), copy_body_r , id, NULL);

260        return new;

261     

262      case POINTER_TYPE:

263        TREE_TYPE (new) = t = remap_type (TREE_TYPE (new), id);

264        if (TYPE_MODE (new) == ptr_mode)

265          TYPE_POINTER_TO (t) = new;

266        return new;

267 

268      case REFERENCE_TYPE:

269        TREE_TYPE (new) = t = remap_type (TREE_TYPE (new), id);

270        if (TYPE_MODE (new) == ptr_mode)

271          TYPE_REFERENCE_TO (t) = new;

272        return new;

273 

274      case METHOD_TYPE:

275      case FUNCTION_TYPE:

276        TREE_TYPE (new) = remap_type (TREE_TYPE (new), id);

277        walk_tree (&TYPE_ARG_TYPES (new), copy_body_r , id, NULL);

278        return new;

279 

280      case ARRAY_TYPE:

281        TREE_TYPE (new) = remap_type (TREE_TYPE (new), id);

282        TYPE_DOMAIN (new) = remap_type (TYPE_DOMAIN (new), id);

283        break ;

284 

285      case RECORD_TYPE:

286      case UNION_TYPE:

287      case QUAL_UNION_TYPE:

288        walk_tree (&TYPE_FIELDS (new), copy_body_r , id, NULL);

289        break ;

290 

291      case FILE_TYPE:

292      case SET_TYPE:

293      case OFFSET_TYPE:

294      default :

295         /* Shouldn't have been thought variable sized.  */

296        abort ();

297    }

298 

299    walk_tree (&TYPE_SIZE (new), copy_body_r , id, NULL);

300    walk_tree (&TYPE_SIZE_UNIT (new), copy_body_r , id, NULL);

301 

302    return new;

303  }

 

在拷贝及处理参数列表时,不会出现 RETURN_STMT ,并且在现在这一点上也很难看清把 RETURN_STMT 转变为 GOTO 语句的细节,我们暂时跳过这一部分。而在下面的 578 行,对于块内的局部变量也要进行拷贝,因为每次展开都应该有自己的变量实例。

 

502  static tree

503  copy_body_r (tree *tp, int *walk_subtrees, void *data)                          in tree-inline.c

504  {

505    inline_data* id;

506    tree fn;

507 

508    /* Set up.  */

509    id = (inline_data *) data;

510    fn = VARRAY_TOP_TREE (id->fns);

511  

512  #if 0

      …

519  #endif

520 

521  #ifdef INLINER_FOR_JAVA

      …

524  #endif

525 

526    /* If this is a RETURN_STMT, change it into an EXPR_STMT and a

527       GOTO_STMT with the RET_LABEL as its target.  */

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    {

        …

571    }

572    /* Local variables and labels need to be replaced by equivalent

573      variables. We don't want to copy static variables; there's only

574      one of those, no matter how many times we inline the containing

575      function.

576      We do not also want to copy the label which we put into

577      GOTO_STMT which replaced RETURN_STMT.  */

578    else if (*tp != id->ret_label

579           && (*lang_hooks .tree_inlining.auto_var_in_fn_p ) (*tp, fn))

580    {

581      tree new_decl;

582 

583      /* Remap the declaration.  */

584      new_decl = remap_decl (*tp, id);

585      if (! new_decl)

586        abort ();

587      /* Replace this variable with the copy.  */

588      STRIP_TYPE_NOPS (new_decl);

589      *tp = new_decl;

590    }

591  #if 0

      …

595  #endif

596    else if (TREE_CODE (*tp) == SAVE_EXPR)

597      remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0),

598                       walk_subtrees);

599    else if (TREE_CODE (*tp) == UNSAVE_EXPR)

600      /* UNSAVE_EXPRs should not be generated until expansion time.  */

601      abort ();

602  #ifndef INLINER_FOR_JAVA

603    /* For a SCOPE_STMT, we must copy the associated block so that we

604      can write out debugging information for the inlined variables.  */

605    else if (TREE_CODE (*tp) == SCOPE_STMT && !id->in_target_cleanup_p)

606      copy_scope_stmt (tp, walk_subtrees, id);

607  #else /* INLINER_FOR_JAVA */

       …

630  #endif /* INLINER_FOR_JAVA */

631    /* Types may need remapping as well.  */

632    else if (TYPE_P (*tp))

633      *tp = remap_type (*tp, id);

634 

635    /* Otherwise, just copy the node. Note that copy_tree_r already

636       knows not to copy VAR_DECLs, etc., so this is safe.  */

637    else

638    {

639      if (TREE_CODE (*tp) == MODIFY_EXPR

640          && TREE_OPERAND (*tp, 0) == TREE_OPERAND (*tp, 1)

641          && ((*lang_hooks .tree_inlining.auto_var_in_fn_p )

642                        (TREE_OPERAND (*tp, 0), fn)))

643      {

644         /* Some assignments VAR = VAR; don't generate any rtl code

645            and thus don't count as variable modification. Avoid

646           keeping bogosities like 0 = 0.  */

647         tree decl = TREE_OPERAND (*tp, 0), value;

648         splay_tree_node n;

649 

650         n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);

651         if (n)

652          {

653           value = (tree) n->value;

654            STRIP_TYPE_NOPS (value);

655           if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))

656          {

657             *tp = value;

658             return copy_body_r (tp, walk_subtrees, data);

659          }

660         }

661      }

662      else if (TREE_CODE (*tp) == ADDR_EXPR

663              && ((*lang_hooks .tree_inlining.auto_var_in_fn_p )

664                         (TREE_OPERAND (*tp, 0), fn)))

665      {

666         /* Get rid of &* from inline substitutions. It can occur when

667           someone takes the address of a parm or return slot passed by

668           invisible reference.  */

669         tree decl = TREE_OPERAND (*tp, 0), value;

670         splay_tree_node n;

671 

672         n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);

673         if (n)

674         {

675           value = (tree) n->value;

676           if (TREE_CODE (value) == INDIRECT_REF)

677          {

678             *tp = convert (TREE_TYPE (*tp), TREE_OPERAND (value, 0));

679             return copy_body_r (tp, walk_subtrees, data);

680          }

681         }

682      }

683 

684      copy_tree_r (tp, walk_subtrees, NULL);

685 

686      TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id);

687 

688      /* The copied TARGET_EXPR has never been expanded, even if the

689         original node was expanded already.  */

690      if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3))

691      {

692         TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3);

693         TREE_OPERAND (*tp, 3) = NULL_TREE;

694      }

695    }

696 

697    /* Keep iterating.  */

698    return NULL_TREE;

699  }

 

copy_body_r 总是作为 walk_tree 的参数来使用的,通过 walk_tree 深入到每个节点的内部。显然,对于 walk_tree 不知道下一步该如何处理的节点, copy_body_r 需要自己来处理,像上面的 SCOPE_STMT SAVE_EXPR MODIFY_EXPR ADDR_EXPR 等。注意 639 行,这个条件代表一个局部变量的:“ var = var; ”的表达式(可能是由宏展开生成的),这句语句是没有意义的,这里直接使用拷贝后的值( 672 行获取对应的拷贝节点)。对于引用局部对象的 ADDR_EXPR 亦然,要用拷贝的对象替换其中引用的对象。

注意 walk_tree 并不会在常量节点上调用传给它的函数,而在 remap_type 中,不会拷贝节点内部 INTEGER_CST (前面看过 INTEGER_CST 是共享的)。

 

remap_decl (continue)

 

164       /* Remap sizes as necessary.  */

165      walk_tree (&DECL_SIZE (t), copy_body_r , id, NULL);

166      walk_tree (&DECL_SIZE_UNIT (t), copy_body_r , id, NULL);

167 

168  #ifndef INLINER_FOR_JAVA

169      if (! DECL_NAME (t) && TREE_TYPE (t)

170           && (*lang_hooks .tree_inlining.anon_aggr_type_p) (TREE_TYPE (t)))

171      {

172         /* For a VAR_DECL of anonymous type, we must also copy the

173            member VAR_DECLS here and rechain the DECL_ANON_UNION_ELEMS.  */

174         tree members = NULL;

175         tree src;

176 

177         for (src = DECL_ANON_UNION_ELEMS (t); src;

178              src = TREE_CHAIN (src))

179         {

180           tree member = remap_decl (TREE_VALUE (src), id);

181 

182           if (TREE_PURPOSE (src))

183            abort ();

184           members = tree_cons (NULL, member, members);

185         }

186         DECL_ANON_UNION_ELEMS (t) = nreverse (members);

187      }

188  #endif /* not INLINER_FOR_JAVA */

189 

190      /* Remember it, so that if we encounter this local entity

191         again we can reuse this copy.  */

192      n = splay_tree_insert (id->decl_map,

193                         (splay_tree_key) decl,

194                         (splay_tree_value) t);

195    }

196 

197    return (tree) n->value;

198  }

 

同样,对于使用 INTEGER_CST DECL_SIZE DECL_SIZE_UNIT walk_tree 绕过之。在 192 行, decl 是被拷贝的对象, t 则是对象的拷贝。

回到 remap_block ,准备好了形参对应的局部变量后,在 374 行恢复块内变量的次序。而在 376 id->cloning_p 只在来自 clone_body 函数(调用于克隆构造函数或析构函数)的调用中设置,此时,我们还在解析被克隆函数的阶段。显然,在我们的场景中, id->cloning_p 0 ,把 new_block 插入到 DECL_INITIAL 之后。

 

remap_block (continue)

 

373       /* We put the BLOCK_VARS in reverse order; fix that now.  */

374        BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block));

375       fn = VARRAY_TREE (id->fns, 0);

376        if (id->cloning_p)

377        /* We're building a clone; DECL_INITIAL is still

378           error_mark_node, and current_binding_level is the parm

379             binding level.  */

380        (*lang_hooks .decls.insert_block) (new_block);

381        else

382      {

383         /* Attach this new block after the DECL_INITIAL block for the

384           function into which this block is being inlined. In

385           rest_of_compilation we will straighten out the BLOCK tree.  */

386         tree *first_block;

387         if (DECL_INITIAL (fn))

388           first_block = &BLOCK_CHAIN (DECL_INITIAL (fn));

389         else

390           first_block = &DECL_INITIAL (fn);

391         BLOCK_CHAIN (new_block) = *first_block;

392         *first_block = new_block;

393      }

394      /* Remember the remapped block.  */

395      splay_tree_insert (id->decl_map,

396                      (splay_tree_key) old_block,

397                      (splay_tree_value) new_block);

398    }

399    /* If this is the end of a scope, set the SCOPE_STMT_BLOCK to be the

400      remapped block.  */

401    else if (SCOPE_END_P (scope_stmt) && SCOPE_STMT_BLOCK (scope_stmt))

402    {

403      splay_tree_node n;

404 

405       /* Find this block in the table of remapped things.  */

406      n = splay_tree_lookup (id->decl_map,

407                           (splay_tree_key) SCOPE_STMT_BLOCK (scope_stmt));

408      if (! n)

409        abort ();

410      SCOPE_STMT_BLOCK (scope_stmt) = (tree) n->value;

411     }

412  #else /* INLINER_FOR_JAVA */

       …

474  #endif /* INLINER_FOR_JAVA */

475  }

 

SCOPE_STMT_BLOCK 是一个包含了在这个局部作用域中所声明变量的 BLOCK ,对于 SCOPE_END_P 成立的 scope_stmt 而言,它是这个 scope_stmt 所封装的块(参见 do_poplevel )。这个封装的块必定已经 remap 了,那么用拷贝出的块来替换原有的块。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值