Studying note of GCC-3.4.6 source (9)

1.4. Create node for uniary expression - build1

build1 is same as build, but only builds for unary operators. Saves lion share of calls to build; cuts down use of varargs, which is expensive for RISC machines.

 

2411 tree

2412 build1 (enum tree_code code, tree type, tree node)                                               in tree.c

2413 {

2414   int length = sizeof (struct tree_exp);

2415 #ifdef GATHER_STATISTICS

2416   tree_node_kind kind;

2417 #endif

2418   tree t;

2419

2420 #ifdef GATHER_STATISTICS

2421   switch (TREE_CODE_CLASS (code))

2422   {

2423     case 's':  /* an expression with side effects */

2424       kind = s_kind;

2425       break;

2426     case 'r':  /* a reference */

2427       kind = r_kind;

2428       break;

2429     default:

2430       kind = e_kind;

2431       break;

2432   }

2433

2434   tree_node_counts[(int) kind]++;

2435   tree_node_sizes[(int) kind] += length;

2436 #endif

2437

2438 #ifdef ENABLE_CHECKING

2439   if (TREE_CODE_CLASS (code) == '2'

2440       || TREE_CODE_CLASS (code) == '<'

2441       || TREE_CODE_LENGTH (code) != 1)

2442     abort ();

2443 #endif /* ENABLE_CHECKING */

2444

2445   t = ggc_alloc_tree (length);

2446

2447   memset (t, 0, sizeof (struct tree_common));

2448

2449   TREE_SET_CODE (t, code);

2450

2451   TREE_TYPE (t) = type;

2452   TREE_COMPLEXITY (t) = 0;

2453   TREE_OPERAND (t, 0) = node;

2454   if (node && first_rtl_op (code) != 0)

2455   {

2456     TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (node);

2457     TREE_READONLY (t) = TREE_READONLY (node);

2458   }

2459

2460   if (TREE_CODE_CLASS (code) == 's')

2461     TREE_SIDE_EFFECTS (t) = 1;

2462   else switch (code)

2463   {

2464     case INIT_EXPR:

2465     case MODIFY_EXPR:

2466     case VA_ARG_EXPR:

2467     case RTL_EXPR:

2468     case PREDECREMENT_EXPR:

2469     case PREINCREMENT_EXPR:

2470     case POSTDECREMENT_EXPR:

2471     case POSTINCREMENT_EXPR:

2472       /* All of these have side-effects, no matter what their

2473         operands are.  */

2474       TREE_SIDE_EFFECTS (t) = 1;

2475       TREE_READONLY (t) = 0;

2476       break;

2477

2478     case INDIRECT_REF:

2479       /* Whether a dereference is readonly has nothing to do with whether

2480         its operand is readonly.  */

2481       TREE_READONLY (t) = 0;

2482       break;

2483

2484     case ADDR_EXPR:

2485       if (node)

2486       {

2487         /* The address of a volatile decl or reference does not have

2488           side-effects. But be careful not to ignore side-effects from

2489           other sources deeper in the expression--if node is a _REF and

2490           one of its operands has side-effects, so do we.  */

2491         if (TREE_THIS_VOLATILE (node))

2492         {

2493           TREE_SIDE_EFFECTS (t) = 0;

2494           if (!DECL_P (node))

2495           {

2496             int i = first_rtl_op (TREE_CODE (node)) - 1;

2497             for (; i >= 0; --i)

2498             {

2499               if (TREE_SIDE_EFFECTS (TREE_OPERAND (node, i)))

2500                 TREE_SIDE_EFFECTS (t) = 1;

2501             }

2502           }

2503         }

2504       }

2505       break;

2506

2507     default:

2508       if (TREE_CODE_CLASS (code) == '1' && node && TREE_CONSTANT (node))

2509         TREE_CONSTANT (t) = 1;

2510       break;

2511     }

2512

2513   return t;

2514 }

 

Above at line 2460, code class of ‘s’ means statement with side-effects, but usually no interesting value.

1.5. Create node of declaration

Routine build_decl is the function to create object of tree_decl - the node for declarations. Pay attention to line 2565 below, in object file, function definition will be placed within text section. And its invocation will be compiled into a jump instruction and related stack or registers operation. It acts like a pointer, so function mode (FUNCTION_MODE) corresponding to the function declaration, on target machines, usually is the same mode as pointer.

 

2547 tree

2548 build_decl (enum tree_code code, tree name, tree type)                                       in tree.c

2549 {

2550   tree t;

2551

2552   t = make_node (code);

2553

2554 /*  if (type == error_mark_node)

2555     type = integer_type_node; */

2556 /* That is not done, deliberately, so that having error_mark_node

2557   as the type can suppress useless errors in the use of this variable.  */

2558

2559   DECL_NAME (t) = name;

2560   TREE_TYPE (t) = type;

2561

2562   if (code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)

2563     layout_decl (t, 0);

2564   else if (code == FUNCTION_DECL)

2565     DECL_MODE (t) = FUNCTION_MODE;

2566

2567   return t;

2568 }

 

In above, for VAR_DECL, PARM_DECL and RESULT_DECL special treatment is required. So first we see what are PARM_DECL and RESULT_DECL.

PARM_DECL[2]

²        Used to represent a parameter to a function. Treat these nodes similarly to VAR_DECL nodes. These nodes only appear in the DECL_ARGUMENTS for a FUNCTION_DECL. The DECL_ARG_TYPE for a PARM_DECL is the type that will actually be used when a value is passed to this function. It may be a wider type than the TREE_TYPE of the parameter; for example, the ordinary type might be short while the DECL_ARG_TYPE is int.

RESULT_DECL[2]

²        These nodes represent the value returned by a function. When a value is assigned to a RESULT_DECL, that indicates that the value should be returned, via bitwise copy, by the function. You can use DECL_SIZE and DECL_ALIGN on a RESULT_DECL, just as with a VAR_DECL.

1.5.1. Layout the declaration

For VAR_DECL, PARM_DECL and RESULT_DECL, they need set inforamtion of size, mode and alignment in the nodes.

 

352  void

353  layout_decl (tree decl, unsigned int known_align)                                  in stor-layout.c

354  {

355    tree type = TREE_TYPE (decl);

356    enum tree_code code = TREE_CODE (decl);

357    rtx rtl = NULL_RTX;

358 

359    if (code == CONST_DECL)

360      return;

361    else if (code != VAR_DECL && code != PARM_DECL && code != RESULT_DECL

362            && code != TYPE_DECL && code != FIELD_DECL)

363      abort ();

364 

365    rtl = DECL_RTL_IF_SET (decl);

366 

367    if (type == error_mark_node)

368      type = void_type_node;

369 

370    /* Usually the size and mode come from the data type without change,

371      however, the front-end may set the explicit width of the field, so its

372      size may not be the same as the size of its type. This happens with

373      bitfields, of course (an `int' bitfield may be only 2 bits, say), but it

374      also happens with other fields. For example, the C++ front-end creates

375      zero-sized fields corresponding to empty base classes, and depends on

376      layout_type setting DECL_FIELD_BITPOS correctly for the field. Set the

377      size in bytes from the size in bits. If we have already set the mode,

378      don't set it again since we can be called twice for FIELD_DECLs.  */

379 

380    TREE_UNSIGNED (decl) = TREE_UNSIGNED (type);

381    if (DECL_MODE (decl) == VOIDmode)

382      DECL_MODE (decl) = TYPE_MODE (type);

383 

384    if (DECL_SIZE (decl) == 0)

385    {

386      DECL_SIZE (decl) = TYPE_SIZE (type);

387      DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (type);

388    }

389    else if (DECL_SIZE_UNIT (decl) == 0)

390      DECL_SIZE_UNIT (decl)

391        = convert (sizetype, size_binop (CEIL_DIV_EXPR, DECL_SIZE (decl),

392                                     bitsize_unit_node));

393 

394    if (code != FIELD_DECL)

395      /* For non-fields, update the alignment from the type.  */

396      do_type_align (type, decl);

397    else

398      /* For fields, it's a bit more complicated...  */

399    {

   

493    }

 

When entering from build_decl, the node of tree_decl is filled with 0 (see make_node), only the name and type fields are updated. Notice that at line 382, VOIDmode is 0. And at line 394, we should not be FIELD_DECL as we are not from layout_type. So at line 396, do_type_align forces the alignment to that of the type.

 

328  static inline void

329  do_type_align (tree type, tree decl)                                                       in stor-layout.c

330  {

331    if (TYPE_ALIGN (type) > DECL_ALIGN (decl))

332    {

333      DECL_ALIGN (decl) = TYPE_ALIGN (type);

334      if (TREE_CODE (decl) == FIELD_DECL)

335        DECL_USER_ALIGN (decl) = TYPE_USER_ALIGN (type);

336    }

337  }

 

GNU C++ has an interesting extension. It allows the deminsion of a local array being a non-constant value. For example:

void func () {

   int j = 5;

   int arrJ[j++];

}

It is a good code! Obviously, the size of arrJ is an expression instead of an INTEGER_CST. This size represented expression may have side-effect (here, j++ is the kind), which means can only evaluate the expression once, and later reference should be towards the cached value. In the front-end, node of SAVE_EXPR is provided for the purpose. And below routine variable_size would replace those size nodes of expression with SAVE_EXPR.

 

layout_decl (continue)

 

495    /* Evaluate nonconstant size only once, either now or as soon as safe.  */

496    if (DECL_SIZE (decl) != 0 && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)

497      DECL_SIZE (decl) = variable_size (DECL_SIZE (decl));

498    if (DECL_SIZE_UNIT (decl) != 0

499        && TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST)

500      DECL_SIZE_UNIT (decl) = variable_size (DECL_SIZE_UNIT (decl));

501 

502    /* If requested, warn about definitions of large data objects.  */

503    if (warn_larger_than

504        && (code == VAR_DECL || code == PARM_DECL)

505        && ! DECL_EXTERNAL (decl))

506    {

507      tree size = DECL_SIZE_UNIT (decl);

508 

509      if (size != 0 && TREE_CODE (size) == INTEGER_CST

510         && compare_tree_int (size, larger_than_size) > 0)

511      {

512        int size_as_int = TREE_INT_CST_LOW (size);

513 

514        if (compare_tree_int (size, size_as_int) == 0)

515          warning ("%Jsize of '%D' is %d bytes", decl, decl, size_as_int);

516        else

517          warning ("%Jsize of '%D' is larger than %d bytes",

518                       decl, decl, larger_than_size);

519      }

520    }

521 

522    /* If the RTL was already set, update its mode and mem attributes.  */

523    if (rtl)

524    {

525      PUT_MODE (rtl, DECL_MODE (decl));

526      SET_DECL_RTL (decl, 0);

527      set_mem_attributes (rtl, decl, 1);

528      SET_DECL_RTL (decl, rtl);

529    }

530  }

 

Above at line 523, rtl is the RTL node associating with the declaration node. It is only available after parsing the whole translation-unit. The node of RTL will guide the output of assemble. So if the layout of the declaration has been changed, it may affect the allocation of memory for the declaration, it must update the fields in the RTL node accordingly.

 

你可能感兴趣的:(function,tree,Integer,Build,reference,alignment)