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

1.6.3.1.1.2.  获取结果

而在int_const_binop的余下部分,计算结果已经存放在lowhi中,这个结果将被合成为相应的树节点对象并检查溢出情况。下面的notrunc如果非零,表明不做值截取,而overflow则记录了计算过程中是否发生溢出,no_overflow如果非零,表明计算不会导致溢出。

 

int_const_binop (continue)

 

1331   /* If this is for a sizetype, can be represented as one (signed)

1332     HOST_WIDE_INT word, and doesn't overflow, use size_int since it caches

1333     constants.  */

1334   if (is_sizetype

1335       && ((hi == 0 && (HOST_WIDE_INT) low >= 0)

1336            || (hi == -1 && (HOST_WIDE_INT) low < 0))

1337       && overflow == 0 && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2))

1338     return size_int_type_wide (low, type);

1339   else

1340   {

1341     t = build_int_2 (low, hi);

1342     TREE_TYPE (t) = TREE_TYPE (arg1);

1343   }

1344

1345   TREE_OVERFLOW (t)

1346     = ((notrunc

1347        ? (!uns || is_sizetype) && overflow

1348          : (force_fit_type (t, (!uns || is_sizetype) && overflow)

1349        && ! no_overflow))

1350        | TREE_OVERFLOW (arg1)

1351        | TREE_OVERFLOW (arg2));

1352

1353   /* If we're doing a size calculation, unsigned arithmetic does overflow.

1354     So check if force_fit_type truncated the value.  */

1355   if (is_sizetype

1356       && ! TREE_OVERFLOW (t)

1357       && (TREE_INT_CST_HIGH (t) != hi

1358            || TREE_INT_CST_LOW (t) != low))

1359     TREE_OVERFLOW (t) = 1;

1360

1361   TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t)

1362                            | TREE_CONSTANT_OVERFLOW (arg1)

1363                            | TREE_CONSTANT_OVERFLOW (arg2));

1364   return t;

1365 }

 

上面1338行,如果计算的常量为size_t类型,其结果可被保存在一个HOST_WIDE_INT中,而且其过程没有发生溢出,那么利用size_int_type_wide将其保存在哈希表size_htab中(在这个函数中会调用force_fit_type,根据类型的精度进行必要的值截取和溢出标记)。因为size_t的精度,在我们的假想平台下只有32位,因此,其他情况都意味着有溢出,但可能结果节点的溢出标记还未设置。1355行即对这个情况进行检查。

1.6.3.1.2.            确定元素和数组的大小

在获取数组的长度后,接下来需要确定元素的大小。在下面1645行,TYPE_PACKED 返回非零值,如果该类型的对象应以尽可能紧凑的方式来布局。而在1657行,integer_one_node 指向代表常量1的全局树节点。

1669行,数组的大小按比特位来表示,而在1680行,这个大小由单位来计算(通常是字节,取决于目标机器)。

 

layout_type (continue)

 

1643         /* Special handling for arrays of bits (for Chill).  */

1644         element_size = TYPE_SIZE (element);

1645         if (TYPE_PACKED (type) && INTEGRAL_TYPE_P (element)

1646            && (integer_zerop (TYPE_MAX_VALUE (element))

1647                || integer_onep (TYPE_MAX_VALUE (element)))

1648            && host_integerp (TYPE_MIN_VALUE (element), 1))

1649         {

1650           HOST_WIDE_INT maxvalue

1651              = tree_low_cst (TYPE_MAX_VALUE (element), 1);

1652           HOST_WIDE_INT minvalue

1653              = tree_low_cst (TYPE_MIN_VALUE (element), 1);

1654

1655           if (maxvalue - minvalue == 1

1656              && (maxvalue == 1 || maxvalue == 0))

1657             element_size = integer_one_node;

1658         }

1659

1660         /* If neither bound is a constant and sizetype is signed, make

1661           sure the size is never negative. We should really do this

1662           if *either* bound is non-constant, but this is the best

1663           compromise between C and Ada.  */

1664         if (! TREE_UNSIGNED (sizetype)

1665            && TREE_CODE (TYPE_MIN_VALUE (index)) != INTEGER_CST

1666            && TREE_CODE (TYPE_MAX_VALUE (index)) != INTEGER_CST)

1667           length = size_binop (MAX_EXPR, length, size_zero_node);

1668

1669         TYPE_SIZE (type) = size_binop (MULT_EXPR, element_size,

1670                                    convert (bitsizetype, length));

1671

1672         /* If we know the size of the element, calculate the total

1673           size directly, rather than do some division thing below.

1674           This optimization helps Fortran assumed-size arrays

1675           (where the size of the array is determined at runtime)

1676           substantially.

1677           Note that we can't do this in the case where the size of

1678           the elements is one bit since TYPE_SIZE_UNIT cannot be

1679           set correctly in that case.  */

1680         if (TYPE_SIZE_UNIT (element) != 0 && ! integer_onep (element_size))

1681           TYPE_SIZE_UNIT (type)

1682              = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (element), length);

1683       }

1684

1685       /* Now round the alignment and size,

1686         using machine-dependent criteria if any.  */

1687

1688 #ifdef ROUND_TYPE_ALIGN

1689      TYPE_ALIGN (type)

1690         = ROUND_TYPE_ALIGN (type, TYPE_ALIGN (element), BITS_PER_UNIT);

1691 #else

1692      TYPE_ALIGN (type) = MAX (TYPE_ALIGN (element), BITS_PER_UNIT);

1693 #endif

1694      TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (element);

1695      TYPE_MODE (type) = BLKmode;

1696      if (TYPE_SIZE (type) != 0

1697 #ifdef MEMBER_TYPE_FORCES_BLK

1698         && ! MEMBER_TYPE_FORCES_BLK (type, VOIDmode)

1699 #endif

1700         /* BLKmode elements force BLKmode aggregate;

1701           else extract/store fields may lose.  */

1702         && (TYPE_MODE (TREE_TYPE (type)) != BLKmode

1703             || TYPE_NO_FORCE_BLK (TREE_TYPE (type))))

1704      {

1705        /* One-element arrays get the component type's mode.  */

1706        if (simple_cst_equal (TYPE_SIZE (type),

1707                          TYPE_SIZE (TREE_TYPE (type))))

1708          TYPE_MODE (type) = TYPE_MODE (TREE_TYPE (type));

1709        else

1710          TYPE_MODE (type)

1711              = mode_for_size_tree (TYPE_SIZE (type), MODE_INT, 1);

1712

1713        if (TYPE_MODE (type) != BLKmode

1714           && STRICT_ALIGNMENT && TYPE_ALIGN (type) < BIGGEST_ALIGNMENT

1715           && TYPE_ALIGN (type) < GET_MODE_ALIGNMENT (TYPE_MODE (type))

1716           && TYPE_MODE (type) != BLKmode)

1717        {

1718          TYPE_NO_FORCE_BLK (type) = 1;

1719          TYPE_MODE (type) = BLKmode;

1720        }

1721      }

1722      break;

1723    }

 

ROUND_TYPE_ALIGN Linx/x86平台下没有定义1692BITS_PER_UNITLinux定义为8代表字节。因此数组至少要在字节边界上对齐(对C/C++没有这个问题,元素的大小都是字节倍数的)。在1694TYPE_USER_ALIGN如果非零表示声明使用了align这个属性(align attribute)。

进而,在1697行,MEMBER_TYPE_FORCES_BLK没有定义。在1703行,数组节点的TREE_TYPE返回元素的类型,而TYPE_NO_FORCE_BLK返回非零值,如果元素的类型是RECORD_TYPEUNION_TYPEQUAL_UNION_TYPE,而且仅当类型缺乏对齐量信息时才使用BLKmode模式。在这种情况下或者元素不是BLKmode模式,函数mode_for_size_tree将会寻找合用的非BLKmode的模式。

 

230  enum machine_mode

231  mode_for_size_tree (tree size, enum mode_class class, int limit)              in stor-layout.c

232  {

233    if (TREE_CODE (size) != INTEGER_CST

234       || TREE_OVERFLOW (size)

235       /* What we really want to say here is that the size can fit in a

236         host integer, but we know there's no way we'd find a mode for

237         this many bits, so there's no point in doing the precise test.  */

238       || compare_tree_int (size, 1000) > 0)

239      return BLKmode;

240    else

241      return mode_for_size (tree_low_cst (size, 1), class, limit);

242  }

 

对于不定长的类型,或长度超过1000字节的类型,只能使用BLKmode模式。而且在241行的mode_for_size在找不到合用的其他模式时,也会返回BLKmode

注意到在1714行,STRICT_ALIGNMENT如果非零,表示对于非对齐数据,移动指令(move instructions)将会失败。而1715行的判断,检查数据是否为某种紧凑形式。

1.7. save_expr函数的细节

函数save_expr把表达式封装入一个SAVE_EXPR节点中。任何只能被求值一次,但被编译器多次使用的表达式需要被封装入SAVE_EXPR节点(例如:++j += k; 会被编译器展开为++j = ++j + k; ++j是有副作用的,对它2次求值会导致不同的结果。编译器必须抑制除了原始语义要求外的求值)。

通常,函数expand_expr每次都会对表达式重新求值(reevaluate)。在expand_expr第一次处理这个表达式时,调用save_expr将产生的结果缓存。随后的expand_expr调用将使用这个保存的值。

产生真正计算代码的那次对expand_expr的调用是编译时的第一次调用。编译时后续的调用将产生使用对应的保存值的代码。只要在运行时,第一次调用expand_expr的指令在其他使用这个对应的save_expr的指令前执行,就能得到正确的结果。save_expr的调用者必须保证这一点。

常量和只读的节点不需要封装入SAVE_EXPR。这样做仍然是安全的。对包含占位符(placeholder)的表达式,save_expr也不做处理。

 

1340 tree

1341 save_expr (tree expr)                                                                                       in tree.c

1342 {

1343   tree t = fold (expr);

1344   tree inner;

1345

1346   /* If the tree evaluates to a constant, then we don't want to hide that

1347     fact (i.e. this allows further folding, and direct checks for constants).

1348     However, a read-only object that has side effects cannot be bypassed.

1349     Since it is no problem to reevaluate literals, we just return the

1350     literal node.  */

1351   inner = skip_simple_arithmetic (t);

1352   if (TREE_CONSTANT (inner)

1353       || (TREE_READONLY (inner) && ! TREE_SIDE_EFFECTS (inner))

1354       || TREE_CODE (inner) == SAVE_EXPR

1355       || TREE_CODE (inner) == ERROR_MARK)

1356     return t;

1357

1358   /* If INNER contains a PLACEHOLDER_EXPR, we must evaluate it each time, since

1359     it means that the size or offset of some field of an object depends on

1360     the value within another field.

1361

1362     Note that it must not be the case that T contains both a PLACEHOLDER_EXPR

1363     and some variable since it would then need to be both evaluated once and

1364     evaluated more than once. Front-ends must assure this case cannot

1365     happen by surrounding any such subexpressions in their own SAVE_EXPR

1366     and forcing evaluation at the proper time.  */

1367   if (contains_placeholder_p (inner))

1368     return t;

1369

1370   t = build (SAVE_EXPR, TREE_TYPE (expr), t, current_function_decl, NULL_TREE);

1371

1372   /* This expression might be placed ahead of a jump to ensure that the

1373     value was computed on both sides of the jump. So make sure it isn't

1374     eliminated as dead.  */

1375   TREE_SIDE_EFFECTS (t) = 1;

1376   TREE_READONLY (t) = 1;

1377   return t;

1378 }

 

上面的1351行,skip_simple_arithmetic提取出表达式封装入SAVE_EXPR的必要部分。这样可以减少需要封装的表达式的数量,加快编译时间。

 

1383 tree

1384 skip_simple_arithmetic (tree expr)                                                                     in tree.c

1385 {

1386   tree inner;

1387

1388   /* We don't care about whether this can be used as an lvalue in this

1389     context.  */

1390   while (TREE_CODE (expr) == NON_LVALUE_EXPR)

1391     expr = TREE_OPERAND (expr, 0);

1392

1393   /* If we have simple operations applied to a SAVE_EXPR or to a SAVE_EXPR and

1394     a constant, it will be more efficient to not make another SAVE_EXPR since

1395     it will allow better simplification and GCSE will be able to merge the

1396     computations if they actually occur.  */

1397   inner = expr;

1398   while (1)

1399   {

1400     if (TREE_CODE_CLASS (TREE_CODE (inner)) == '1')

1401       inner = TREE_OPERAND (inner, 0);

1402     else if (TREE_CODE_CLASS (TREE_CODE (inner)) == '2')

1403     {

1404       if (TREE_CONSTANT (TREE_OPERAND (inner, 1)))

1405         inner = TREE_OPERAND (inner, 0);

1406       else if (TREE_CONSTANT (TREE_OPERAND (inner, 0)))

1407         inner = TREE_OPERAND (inner, 1);

1408       else

1409         break;

1410     }

1411     else

1412       break;

1413   }

1414

1415   return inner;

1416 }

 

显然,确认没有副作用的节点才可以被忽略。函数一直沿着子树下降,直至没有节点可以被忽略。注意,操作符++是二元操作符,它隐含了“1”这个操作数。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值