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

来源:互联网 发布:知乎 日本 编辑:程序博客网 时间:2024/05/19 20:48

1.4. 为一元表达式创建节点

函数build1类似于build,但用于一元操作符。它用于代替相当一部分的build调用。减少对于RISC机器来说相当昂贵的可变参量的使用。

 

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 }

 

在上面2460行,树类别码‘s’表明一个有副作用,但其值不被关注的语句(statement)。

1.5. 为声明创建节点

函数build_decl被用于创建tree_decl类型节点,该节点用于表示声明。注意下面的2565行,在目标文件中,函数定义将被放于代码段。而我们对函数的调用,则会编译成一条跳转语句和相关的进出栈或寄存器操作指令。它类似于指针,因此函数声明所对应的函数模式(FUNCTION_MODE),在目标机器上,通常等同于指针的模式。

 

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 }

 

在上面看到,对于VAR_DECLPARM_DECLRESULT_DECL节点需要特别的处理。 因此,我们首先看一下PARM_DECLRESULT_DECL节点是什么。

PARM_DECL[2]

²        用于表示函数的一个形参。其处理类似于VAR_DECL节点。该节点只出现在FUNCTION_DECLDECL_ARGUMENTS域中。其DECL_ARG_TYPE域是当向这个函数传入一个值时,这个值所实际对应的类型。它可能是比形参的类型更宽(wider)的类型。例如,形参类型是shortDECL_ARG_TYPEint

RESULT_DECL[2]

²        这个节点表示函数的返回值。如果一个值被赋予RESULT_DECL,就意味着函数将以按位拷贝(bitwise copy)的方式返回这个值。你可以向对待VAR_DECL那样,用宏DECL_SIZEDECL_ALIGN访问RESULT_DECL 节点。

1.5.1. 对声明的布局

对于VAR_DECLPARM_DECLRESULT_DECL,它们需要在节点中设置大小,模式和对齐量,这些信息。

 

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    }

 

当从build_decl进入这个函数时,tree_decl节点中,除了nametype域已经设置外,其余由0填充(参见make_node)。注意到382行,VOIDmode0。而在394行,如果我们不是从layout_type来的,节点不可能是FIELD_DECL。因此,在396行,do_type_align将参考声明所对应的类型的对齐量,来为声明节点设置对齐量。

 

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++有一个有趣的扩展,允许局部数组的维度是一个非常量,例如:

void func () {

   int j = 5;

   int arrJ[j++];

}

是合法的。显然arrJ的大小是一个表达式,而非一个INTEGER_CST节点。这个表示大小的表达式可能会有副作用(这里的j++即是)。这意味着对该表达式的求值只能做一次,其余时候只能用缓存的值。在前端中,节点SAVE_EXPR就是为这个目的设置的。在下面函数variable_size将会把这些非常量的表示声明大小的节点替换为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  }

 

523行,rtl是节点对应的RTL节点,它只会在完成编译单元的解析后,才会产生。RTL节点将指引汇编的产生,如果声明的布局发生变化,可能会对内存的分配产生影响,必须更新对应的RTL节点的属性(如果已生成RTL节点的话)。

原创粉丝点击