GCC-3.4.6源代码学习笔记(10续1)

1.6.3. 创建数组类型节点

当调用build_array_type时,第二个参数index_type应该是由上一节所创建的索引节点。注意C++中没有函数数组类型,因为C++函数拥有常量地址。

 

3790 tree

3791 build_array_type (tree elt_type, tree index_type)                                                 in tree.c

3792 {

3793   tree t;

3794   unsigned int hashcode;

3795

3796   if (TREE_CODE (elt_type) == FUNCTION_TYPE)

3797   {

3798     error ("arrays of functions are not meaningful");

3799     elt_type = integer_type_node;

3800   }

3801

3802   /* Make sure TYPE_POINTER_TO (elt_type) is filled in.  */

3803   build_pointer_type (elt_type);

3804

3805   /* Allocate the array after the pointer type,

3806     in case we free it in type_hash_canon.  */

3807   t = make_node (ARRAY_TYPE);

3808   TREE_TYPE (t) = elt_type;

3809   TYPE_DOMAIN (t) = index_type;

3810

3811   if (index_type == 0)

3812   {

3813     return t;

3814   }

3815

3816   hashcode = TYPE_HASH (elt_type) + TYPE_HASH (index_type);

3817   t = type_hash_canon (hashcode, t);

3818

3819   if (!COMPLETE_TYPE_P (t))

3820     layout_type (t);

3821   return t;

3822 }

 

C++中,数组名可作为数组的首地址,数组名加索引为指向对应元素的指针。例如:

int a[5];

int *p = a + 3;         // but can’t be int &p = a +3;

因此在3803行,为元素创建指针类型(创建该数组类型时,元素的类型节点肯定已创建了,但其指针类型未必)。

1.6.3.1.      类型的布局

对于数组类型,我们需要知道数组按比特计算的长度,数组按字节计算的长度,数组的对齐量,连同其元素的相关信息。

 

1528 void

1529 layout_type (tree type)                                                                              in stor-layout.c

1530 {

1531   if (type == 0)

1532     abort ();

1533

1534   /* Do nothing if type has been laid out before.  */

1535   if (TYPE_SIZE (type))

1536     return;

1537

1538   switch (TREE_CODE (type))

1539   {

         

1619     case ARRAY_TYPE:

1620     {

1621       tree index = TYPE_DOMAIN (type);

1622       tree element = TREE_TYPE (type);

1623

1624       build_pointer_type (element);

1625

1626       /* We need to know both bounds in order to compute the size.  */

1627       if (index && TYPE_MAX_VALUE (index) && TYPE_MIN_VALUE (index)

1628          && TYPE_SIZE (element))

1629       {

1630         tree ub = TYPE_MAX_VALUE (index);

1631         tree lb = TYPE_MIN_VALUE (index);

1632         tree length;

1633         tree element_size;

1634

1635         /* The initial subtraction should happen in the original type so

1636           that (possible) negative values are handled appropriately.  */

1637         length = size_binop (PLUS_EXPR, size_one_node,

1638                          convert (sizetype,

1639                                 fold (build (MINUS_EXPR,

1640                                          TREE_TYPE (lb),

1641                                     ub, lb))));

 

C++允许类似int a[] = {…};这样的数组定义。对于这样的定义,数组类型的布局需要推迟到完成对”{…}”部分的解析。同时由于模板的引入,元素可为某个模板类型。模板类型的大小往往是不固定的,取决于具现时的模板实参,编译器会把这个模板类型的大小定义为0。这种情况下,数组的布局也需要推迟到具现时。

1.6.3.1.1.            获取数组的边界

不过即便推迟了布局,我们最终还是会走进来的。否则编译器迟早会给出一个错误消息,停下来。因为没有布局信息,我们将不知道如何在内存中创建这个类型的实例。

在上面1637行,size_binop按参数code所指定的算术操作,尝试结合操作数arg0arg1 在这里需要处理的表达式是(上边界 下边界)+ 1,它是数组元素的个数。在1637行, size_one_node是数值为1的整型树节点。它被当作常量1使用。

 

1594 tree

1595 size_binop (enum tree_code code, tree arg0, tree arg1)                          in fold-const.c

1596 {

1597   tree type = TREE_TYPE (arg0);

1598

1599   if (TREE_CODE (type) != INTEGER_TYPE || ! TYPE_IS_SIZETYPE (type)

1600       || type != TREE_TYPE (arg1))

1601     abort ();

1602

1603   /* Handle the special case of two integer constants faster.  */

1604   if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)

1605   {

1606     /* And some specific cases even faster than that.  */

1607     if (code == PLUS_EXPR && integer_zerop (arg0))

1608       return arg1;

1609     else if ((code == MINUS_EXPR || code == PLUS_EXPR)

1610            && integer_zerop (arg1))

1611       return arg0;

1612     else if (code == MULT_EXPR && integer_onep (arg0))

1613       return arg1;

1614

1615     /* Handle general case of two integer constants.  */

1616     return int_const_binop (code, arg0, arg1, 0);

1617   }

1618

1619   if (arg0 == error_mark_node || arg1 == error_mark_node)

1620     return error_mark_node;

1621

1622   return fold (build (code, type, arg0, arg1));

1623 }

 

如果arg0arg1不都是整型常量,这个表达式需要更为复杂的处理,则它被交由1622行的fold

1.6.3.1.1.1.  对整型常量的操作

首先查看是否存在可以消除的项。如果参数expr是整型常量0或是复数常量0,函数integer_zerop返回1

 

579  int

580  integer_zerop (tree expr)                                                                                    in tree.c

581  {

582    STRIP_NOPS (expr);

583 

584    return ((TREE_CODE (expr) == INTEGER_CST

585            && ! TREE_CONSTANT_OVERFLOW (expr)

586            && TREE_INT_CST_LOW (expr) == 0

587            && TREE_INT_CST_HIGH (expr) == 0)

588           || (TREE_CODE (expr) == COMPLEX_CST

589               && integer_zerop (TREE_REALPART (expr))

590               && integer_zerop (TREE_IMAGPART (expr))));

591  }

 

下面,给定一个树形式的表达式,STRIP_NOPS剥除所有不改变机器模式的,最外层的转换表达式NOP_EXPRNON_LVALUE_EXPR

 

405  #define STRIP_NOPS(EXP)                                    /                                         in tree.h

406    while ((TREE_CODE (EXP) == NOP_EXPR                      /

407           || TREE_CODE (EXP) == CONVERT_EXPR               /

408           || TREE_CODE (EXP) == NON_LVALUE_EXPR)        /

409         && TREE_OPERAND (EXP, 0) != error_mark_node             /

410         && (TYPE_MODE (TREE_TYPE (EXP))                     /

411              == TYPE_MODE (TREE_TYPE (TREE_OPERAND (EXP, 0))))) /

412      (EXP) = TREE_OPERAND (EXP, 0)

 

其中,NOP_EXPR表示不需要产生代码的转换。NON_LVALUE_EXPR返回和参数EXP相同的值,但保证其为右值。这些表达式都不改变它们参数的值。

同样在1612行,如果参数expr是整型常量1或是复数常量1integer_onep返回1

 

596  int

597  integer_onep (tree expr)                                                                                    in tree.c

598  {

599   STRIP_NOPS (expr);

600 

601    return ((TREE_CODE (expr) == INTEGER_CST

602            && ! TREE_CONSTANT_OVERFLOW (expr)

603            && TREE_INT_CST_LOW (expr) == 1

604            && TREE_INT_CST_HIGH (expr) == 0)

605           || (TREE_CODE (expr) == COMPLEX_CST

606               && integer_onep (TREE_REALPART (expr))

607               && integer_zerop (TREE_IMAGPART (expr))));

608  }

 

如果没有操作数可以被消除,那么就需要1616行的int_const_binop进行计算。

 

1185 static tree

1186 int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)        in fold-const.c

1187 {

1188   unsigned HOST_WIDE_INT int1l, int2l;

1189   HOST_WIDE_INT int1h, int2h;

1190   unsigned HOST_WIDE_INT low;

1191   HOST_WIDE_INT hi;

1192   unsigned HOST_WIDE_INT garbagel;

1193   HOST_WIDE_INT garbageh;

1194   tree t;

1195   tree type = TREE_TYPE (arg1);

1196   int uns = TREE_UNSIGNED (type);

1197   int is_sizetype

1198     = (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type));

1199   int overflow = 0;

1200   int no_overflow = 0;

1201

1202   int1l = TREE_INT_CST_LOW (arg1);

1203   int1h = TREE_INT_CST_HIGH (arg1);

1204   int2l = TREE_INT_CST_LOW (arg2);

1205   int2h = TREE_INT_CST_HIGH (arg2);

1206

1207   switch (code)

1208   {

1209     case BIT_IOR_EXPR:

1210       low = int1l | int2l, hi = int1h | int2h;

1211       break;

1212

1213     case BIT_XOR_EXPR:

1214       low = int1l ^ int2l, hi = int1h ^ int2h;

1215       break;

1216

1217     case BIT_AND_EXPR:

1218       low = int1l & int2l, hi = int1h & int2h;

1219       break;

1220

1221     case RSHIFT_EXPR:

1222       int2l = -int2l;

1223     case LSHIFT_EXPR:

1224       /* It's unclear from the C standard whether shifts can overflow.

1225         The following code ignores overflow; perhaps a C standard

1226         interpretation ruling is needed.  */

1227       lshift_double (int1l, int1h, int2l, TYPE_PRECISION (type),

1228                   &low, &hi, !uns);

1229       no_overflow = 1;

1230       break;

1231

1232     case RROTATE_EXPR:

1233       int2l = - int2l;

1234     case LROTATE_EXPR:

1235       lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (type),

1236                    &low, &hi);

1237       break;

 

对于位操作,只需把相应的高位部分和低位部分(在前端整型常量有128位)分别进行计算。

1.6.3.1.1.1.1.              左移

而对于移位操作,对于有符号数是需要符号位扩展的。在函数lshift_double中,参数ll是被移位数的低位部分,而hl是高位部分,count则是要移动的位数,计算结果存放在lvhv中,arith非零指明是进行算术左移,否则为逻辑左移。

 

364  void

365  lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,    in fold-const.c

366                HOST_WIDE_INT count, unsigned int prec,

367                unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, int arith)

368  {

369    unsigned HOST_WIDE_INT signmask;

370 

371    if (count < 0)

372    {

373      rshift_double (l1, h1, -count, prec, lv, hv, arith);

374      return;

375    }

376 

377  #ifdef SHIFT_COUNT_TRUNCATED

378    if (SHIFT_COUNT_TRUNCATED)

379      count %= prec;

380  #endif

381 

382    if (count >= 2 * HOST_BITS_PER_WIDE_INT)

383    {

384      /* Shifting by the host word size is undefined according to the

385        ANSI standard, so we must handle this as a special case.  */

386      *hv = 0;

387      *lv = 0;

388    }

389    else if (count >= HOST_BITS_PER_WIDE_INT)

390    {

391     *hv = l1 << (count - HOST_BITS_PER_WIDE_INT);

392      *lv = 0;

393    }

394    else

395    {

396      *hv = (((unsigned HOST_WIDE_INT) h1 << count)

397              | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1));

398      *lv = l1 << count;

399    }

400 

401   /* Sign extend all bits that are beyond the precision.  */

402 

403    signmask = -((prec > HOST_BITS_PER_WIDE_INT

404                ? ((unsigned HOST_WIDE_INT) *hv

405                   >> (prec - HOST_BITS_PER_WIDE_INT - 1))

406                : (*lv >> (prec - 1))) & 1);

407 

408    if (prec >= 2 * HOST_BITS_PER_WIDE_INT)

409      ;

410    else if (prec >= HOST_BITS_PER_WIDE_INT)

411    {

412      *hv &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));

413      *hv |= signmask << (prec - HOST_BITS_PER_WIDE_INT);

414    }

415    else

416   {

417      *hv = signmask;

418      *lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec);

419      *lv |= signmask << prec;

420    }

421  }

 

虽然左移操作没有符号位的扩展,但如下图所示,在值的精度小于2*HOST_WIDE_INT时,超出精度外的位也需要符号位扩展。如果移位后的结果超出精度,超出的位需要被扩展符号位来填充。

gcc-2

2精度外的位需要被符号位填充

 

 

gcc-3

3超出精度的位需要被符号位填充

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值