Studying note of GCC-3.4.6 source (180)

5.13.5.3.2.4.2.2.    Generate code for initializing function parameters

Below create a splay tree for field decl_map , which is used to map local declarations of the inlined function to the counterparts in the function inlined into. At line 1393, if CALL_EXPR_HAS_RETURN_SLOT_ADDR is not 0, means that the address of the return slot is part of the argument list, and this slot is always at first in the list.

 

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);

 

Like function invocation, though inline function is expanded within the caller’s body, its arguments may need be converted to the type of the parameter, or need extra code to get the copy. The job is done by below function.

 

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      }

 

Above at line 757, hook convert_parm_for_inlining provides treatment for converting type from argument’s to parameter’s. However as C++ is a strong typing language (note that C is NOT), hook here does nothing.

Further, if the parameter is constant and its address isn’t taken, as long as the argument hasn’t side effect, it can use the argument’s value directly without constructing new local variable. In fact, GCC here behaviors alittle conservative, argument after constant-folding, it must be a constant or read-only, its value can be used directly. For qualified argument, we use NOP_EXPR to encapsulate them.

 

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      }

 

At line 795, copy_decl_for_inlining will, out from the parameter, builds a VAR_DECL of the same name, same type in the caller’s body. And line 816 makes the VAR_DECL created by copy_decl_for_inlining become a local ones. Thus, argument passing of this inlined function can be turned into assignment operation.

Next, case satisfying condition at line 800 is that, we pass an object to a parameter of reference type, so here we put the object into 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  }

 

If destorying the variable needs call destructor, code of this part is generated by hook at line 857. Loop at line 886 handles ellipsis arguments, as these arguments needs be processed via macros var_start, var_arg, var_end, unless the argument is declared as “volatile” (TREE_SIDE_EFFECTS is true), it needsn’t constructs a local variable for it (var_* macro are defined as __builtin_var_* in compiler).

At line 901, the list of initializing statements is returned, in which there may be invocation of inline function, so next calls expand_calls_inline upon these statements

5.13.5.3.2.4.2.3.    Expand inline function

5.13.5.3.2.4.2.3.1.            Prepare ret_label

At line 1431, DECL_INLINED_FNS records list of function inlined into fn 's body, it is set in optimize_inline_calls at time finishes processing the function (note we are now treating function calls fn , as we handle them in invocation order, fn should have been processed). Satisfying condition at lin 1431, it indicates fn hasn’t function inlined into, and fn is called by current function, so we add it into id->inlined_fns, in optimize_inline_calls , DECL_INLINED_FNS will be updated by the data.

 

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);

 

In optimize_inline_calls at line 1636, see that the first elmenet of id->fns is current function. Above line 1444 and 1445 construct a RET_LABEL lable, which is used to trun return statement of the called function into jump statement. At line 1447, DECL_INITIAL holds the tree of bindings, which if is valid, its first element must be a BLOCK. Above at line 1455 introduces a scope to enclose these arguments.

5.13.5.3.2.4.2.3.2.            Replace parameters

Before, code for initializing arguments is ready, inlining function next to declare variables have the same name and type as parameters, and in the function body every parameter refernce should be updated to the corresponding variable. Declaring variables having the same name and type as parameters is done by remap_block at line 1458. In it, DECL_ARGUMENTS accesses the parameters list. And below at line 337, “SCOPE_STMT_BLOCK (scope_stmt)” in fact refers to “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      }

 

Note that decls above is the parameter list (nodes of PARM_DECL), while invoking remap_block at other places argument decls is always NULL (in which case accessing local variables declaration by BLOCK_VARS). See that new_block is then the substitution of old_block (it’s the parameter list), it replaces old_block at line 349, parameters after copying and transforming are linked into new_block via BLOCK_VAR (line 570), thus complete declaring the variables having the same name and type as parameters within the function body.

Below is the procedure of copying and transforming.

 

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;

 

At first, it needs find out auto variables in the funciton. Of course, different language has its own definition about auto variable, to C++, the hook is bound with below function (C, C++ have the same definition about auto variable, but due to different intermediate tree generated, they use different judge routines).

 

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 }

 

If the declaraton had been copied, it is done; otherwise copy the node by copy_decl_for_inlining ( which copies PARM_DECL and RESULT_DECL into VAR_DECL). For *_DECL node, its TREE_TYPE may need deep copy.

 

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, for type defined via typedef, records the type in used. While for other types, this field is NULL. And DECL_ARG_TYPE_AS_WRITTEN holds the type as written (perhaps a function or array, but compiler generates pointer type appropriately). However here PARM_DECL won’t appear (as invoking copy_decl_for_inlining beforehand).

 

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  }

 

At copying and transforming parameters list, RETURN_STMT won’t be seen, and currently it is hard to understand the detail to transform RETURN_STMT into GOTO statement, so we skip this part temperarily. Below at line 578, local variables are also copied, as for every expansion, it should have its own instances of the variables.

 

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 is always used as parameter of walk_tree , it goes into nodes via walk_tree . Obviously, for nodes walk_tree hasn’t idea how to work next step, copy_body_r should take the control itself, such as above SCOPE_STMT, SAVE_EXPR, MODIFY_EXPR and ADDR_EXPR etc. Note at line 639, the condition targets an expression of local variable: “var = var;’ (it may be created by macro expansion) which is meanless, here use the value after copying directly (line 672 takes the node created by copy). It is same for ADDR_EXPR of local variable, the referred object needs be replaced by object created by copy.

Note that walk_tree won’t invoke the passed function on constant node, and in remap_type , it won’t copy INTEGER_CST in the node (see in before, INTEGER_CST nodes are shared).

 

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  }

 

Similarly, for DECL_SIZE and DECL_SIZE_UNIT using INTEGER_CST, walk_tree skips them. At line 192, decl is the object being copied, and t is the object created by copy.

Back remap_block , when local variables corresponding to parameters are ready, at line 374 restore the order of the variables. And at line 376, id->cloning_p only is set in the invocation by clone_body (which invoked to clone constructor or destructor), at which time we are in the stage of parsing function being cloned. Obvious, in our scenario here, id->cloning_p is 0, and insert new_block after 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 containing the declarations contained in this scope, in scope_stmt with SCOPE_END_P held, it is the block enclosed by scope_stmt (refer to do_poplevel ). This block must be remapped already, using new block to replace the old one.

 

你可能感兴趣的:(java,function,tree,null,Parameters,variables)