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

5.13.5.2.2.1.  初始值

这里在我们的目标 Linux/x86 ,输出文件将具有格式 ELF ELF 是支持重定位及 PIC (位置无关代码)的格式。【 10 】的第三章给出了关于 ELF 的一个很好的解释。从【 10 】的总结中,我们得到:

ELF 文件有 3 种稍有不同的风格的形式:可重定位( relocatable ),可执行( executable )及共享对象。可重定位文件由编译器及汇编器创建,但在运行前需要链接器的处理。可执行文件已完成所有的重定位及确定了所有的符号,除了在运行时确定的共享库符号。共享对象是共享库,包含了用于链接器的符号信息及用于运行时的直接可运行代码。

ELF 文件不寻常的二重性。编译器,汇编器,及链接器把这种文件处理作由一个节头表( section header table )所描述的一组逻辑节( logical section ),而系统加载器( system loader )把这种文件处理作由一个程序头表( program header table )所描述的一组段( segment )。一个单段通常由几个节构成。例如,一个“可加载只读”段可以包含对应于可执行代码,只读数据,及用于动态链接器符号的节。可重定位文件具有多个节表( section table ),可执行文件具有多个程序头表( program header table ),而共享对象同时具有两者。节用于链接器进一步处理的目的,而段用于映射入内存。

 

assemble_variable (continue)

 

1460 /* Output any data that we will need to use the address of.  */

1461   if (DECL_INITIAL (decl) == error_mark_node)

1462     reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;

1463   else if (DECL_INITIAL (decl))

1464   {

1465     reloc = compute_reloc_for_constant (DECL_INITIAL (decl));

1466     output_addressed_constants (DECL_INITIAL (decl));

1467   }

1468   resolve_unique_section (decl, reloc, flag_data_sections );

 

DECL_INITIAL 如果是 NULL ,表示 decl 没有初始值;而如果是 error_mark_node ,则表示 decl 具有初始值,但我们现在还没看到它。如果这个初始值还未知,就需要保守些。在 1462 行, reloc 将保存一个值,这个值被将用来与 flag_pic 比较,来选定代码所要放置的节。正如我们在前面的章节中所见, flag_pic 如果是 1 ,表示制作小 PIC ,而如果是 2 ,表示制作大 PIC 。后面我们会看到这些值的作用。

如果 decl 的类型包含指针(或引用)——由下面的函数判断,把 reloc 设置为 3 。这个值表示尽可能使用大 PIC ,不行就尝试小 PIC

 

1561 static int

1562 contains_pointers_p (tree type)                                                                   in varasm.c

1563 {

1564   switch (TREE_CODE (type))

1565   {

1566     case POINTER_TYPE:

1567     case REFERENCE_TYPE:

1568       /* I'm not sure whether OFFSET_TYPE needs this treatment,

1569          so I'll play safe and return 1.  */

1570     case OFFSET_TYPE:

1571       return 1;

1572

1573     case RECORD_TYPE:

1574     case UNION_TYPE:

1575     case QUAL_UNION_TYPE:

1576     {

1577       tree fields;

1578       /* For a type that has fields, see if the fields have pointers.  */

1579       for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))

1580         if (TREE_CODE (fields) == FIELD_DECL

1581            && contains_pointers_p (TREE_TYPE (fields)))

1582         return 1;

1583       return 0;

1584     }

1585

1586     case ARRAY_TYPE:

1587       /* An array type contains pointers if its element type does.  */

1588       return contains_pointers_p (TREE_TYPE (type));

1589

1590     default :

1591       return 0;

1592   }

1593 }

 

如果初始值是已知的,则需要看它可能需要何种重定位。如果其中包含了地址表达式, ELF PIC 编码要求对其中所援引的对象访问需要通过 GOT ,下面的函数在这个初始值中查找对象地址。如果初始值没有使用对象的地址,就会返回 0

C++ 前端钩子 expand_constant 被绑定在 cplus_expand_constant 上,这个函数把 PTRMEM_CST (成员指针常量)或者替换为 PLUS_EXPR (引用数据成员的情形),或替换为更合适的 PTRMEM_CST (从派生类引用基类方法的情形)。

 

3383 int

3384 compute_reloc_for_constant (tree exp)                                                               in varasm.c

3385 {

3386   int reloc = 0, reloc2;

3387   tree tem;

3388

3389   /* Give the front-end a chance to convert VALUE to something that

3390     looks more like a constant to the back-end.  */

3391   exp = (*lang_hooks .expand_constant) (exp);

3392

3393   switch (TREE_CODE (exp))

3394   {

3395     case ADDR_EXPR:

3396     case FDESC_EXPR:

3397       /* Go inside any operations that get_inner_reference can handle and see

3398         if what's inside is a constant: no need to do anything here for

3399         addresses of variables or functions.  */

3400       for (tem = TREE_OPERAND (exp, 0); handled_component_p (tem);

3401           tem = TREE_OPERAND (tem, 0))

3402         ;

3403

3404       if (TREE_PUBLIC (tem))

3405         reloc |= 2;

3406       else

3407         reloc |= 1;

3408       break ;

3409

3410     case PLUS_EXPR:

3411       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));

3412       reloc |= compute_reloc_for_constant (TREE_OPERAND (exp, 1));

3413       break ;

3414

3415     case MINUS_EXPR:

3416       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));

3417       reloc2 = compute_reloc_for_constant (TREE_OPERAND (exp, 1));

3418       /* The difference of two local labels is computable at link time.  */

3419       if (reloc == 1 && reloc2 == 1)

3420         reloc = 0;

3421       else

3422         reloc |= reloc2;

3423       break ;

3424

3425     case NOP_EXPR:

3426     case CONVERT_EXPR:

3427     case NON_LVALUE_EXPR:

3428       reloc = compute_reloc_for_constant (TREE_OPERAND (exp, 0));

3429       break ;

3430

3431     case CONSTRUCTOR:

3432       for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))

3433         if (TREE_VALUE (tem) != 0)

3434           reloc |= compute_reloc_for_constant (TREE_VALUE (tem));

3435

3436       break ;

3437

3438     default :

3439       break ;

3440   }

3441   return reloc;

3442 }

 

对于类的非静态数据成员或者数组的元素,它们的地址以基址加上偏移的形式给出(即 PLUS_EXPR MINUS_EXPR )。另外, TREE_PUBLIC ,在一个 FUNCTION_DECL VAR_DECL 中,如果非 0 ,表示该名字从这个模块外访问;在一个 IDENTIFIER_NODE 中,如果非 0 ,表示从这个模块外访问的一个外部声明,该声明的名字在一个内部域中先前已见。因此 3404 3407 行相应地设置 reloc

下面的函数在上面的 3400 行调用,它找出被援引的对象。

 

5620 int

5621 handled_component_p (tree t)                                                                            in expr.c

5622 {

5623   switch (TREE_CODE (t))

5624   {

5625     case BIT_FIELD_REF:

5626     case COMPONENT_REF:

5627     case ARRAY_REF:

5628     case ARRAY_RANGE_REF:

5629     case NON_LVALUE_EXPR:

5630     case VIEW_CONVERT_EXPR:

5631       return 1;

5632

5633     /* ??? Sure they are handled, but get_inner_reference may return

5634       a different PBITSIZE, depending upon whether the expression is

5635       wrapped up in a NOP_EXPR or not, e.g. for bitfields.  */

5636     case NOP_EXPR:

5637     case CONVERT_EXPR:

5638        return (TYPE_MODE (TREE_TYPE (t))

5639             == TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0))));

5640

5641     default :

5642       return 0;

5643   }

5644 }

5.13.5.2.2.1.1.          输出引用的常量

那么在上面 assemble_variable 1466 行,在对 output_addressed_constants 的调用中,其参数就是这个初始值。同样,这个函数查找 exp 中引用的地址。

 

3448 static void

3449 output_addressed_constants (tree exp)                                                               in varasm.c

3450 {

3451   tree tem;

3452

3453   /* Give the front-end a chance to convert VALUE to something that

3454     looks more like a constant to the back-end.  */

3455   exp = (*lang_hooks .expand_constant) (exp);

3456

3457   switch (TREE_CODE (exp))

3458   {

3459     case ADDR_EXPR:

3460     case FDESC_EXPR:

3461       /* Go inside any operations that get_inner_reference can handle and see

3462         if what's inside is a constant: no need to do anything here for

3463         addresses of variables or functions.  */

3464       for (tem = TREE_OPERAND (exp, 0); handled_component_p (tem);

3465           tem = TREE_OPERAND (tem, 0))

3466         ;

3467

3468       if (TREE_CODE_CLASS (TREE_CODE (tem)) == 'c'

3469          || TREE_CODE (tem) == CONSTRUCTOR)

3470         output_constant_def (tem, 0);

3471       break ;

3472

3473     case PLUS_EXPR:

3474     case MINUS_EXPR:

3475       output_addressed_constants (TREE_OPERAND (exp, 1));

3476       /* Fall through.  */

3477

3478     case NOP_EXPR:

3479     case CONVERT_EXPR:

3480     case NON_LVALUE_EXPR:

3481       output_addressed_constants (TREE_OPERAND (exp, 0));

3482       break ;

3483

3484     case CONSTRUCTOR:

3485       for (tem = CONSTRUCTOR_ELTS (exp); tem; tem = TREE_CHAIN (tem))

3486         if (TREE_VALUE (tem) != 0)

3487           output_addressed_constants (TREE_VALUE (tem));

3488

3489       break ;

3490

3491     default :

3492       break ;

3493   }

3494 }

 

3468 行的条件若满足,表示即找出该地址上的对象是一个常量。而 3469 行的条件若满足,则表明是一个由大括号对包括的初始值,它可以是类或数组的初始值,这个初始值有可能是只读的。对于这些(可能是)常量的节点,前端使用一个数据结构 constant_descriptor_tree 来描述之。

 

2062 struct constant_descriptor_tree GTY(())                                                      in varasm.c

2063 {

2064   /* A MEM for the constant.  */

2065   rtx rtl;

2066

2067   /* The value of the constant.  */

2068   tree value;

2069 };

 

每个常量至少在当前编译单元中是一个单件。我们已经看到在前端中,用于常量的树节点被缓存在哈希表中。现在对于常量描述符节点( constant descriptor node ),也是一样的。

 

2484 rtx

2485 output_constant_def (tree exp, int defer)                                                      in varasm.c

2486 {

2487   struct constant_descriptor_tree *desc;

2488   struct constant_descriptor_tree key;

2489   void **loc;

2490

2491   /* Look up EXP in the table of constant descriptors. If we didn't find

2492     it, create a new one.  */

2493   key.value = exp;

2494   loc = htab_find_slot (const_desc_htab , &key, INSERT);

2495

2496   desc = *loc;

2497   if (desc == 0)

2498   {

2499     desc = build_constant_desc (exp);

2500     *loc = desc;

2501   }

2502

2503   maybe_output_constant_def_contents (desc, defer);

2504   return desc->rtl;

2505 }

 

如果在 const_desc_htab 里找不到这个常量描述符(注意使用该常量的树节点作为键值,通过 const_desc_hash 来比较节点的相同内容),就需要调用 build_constant_desc 来构建之。在下面 2441 行, copy_constant 拷贝 exp 中常量的树节点,因为下面可能改变这个节点,我们需要一份单独的拷贝。

 

2431 static struct constant_descriptor_tree *

2432 build_constant_desc (tree exp)                                                                    in varasm.c

2433 {

2434   rtx symbol;

2435   rtx rtl;

2436   char label[256];

2437   int labelno;

2438   struct constant_descriptor_tree *desc;

2439

2440   desc = ggc_alloc (sizeof (*desc));

2441   desc->value = copy_constant (exp);

2442

2443   /* Create a string containing the label name, in LABEL.  */

2444   labelno = const_labelno ++;

2445   ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);

2446

2447   /* We have a symbol name; construct the SYMBOL_REF and the MEM.  */

2448   symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));

2449   SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;

2450   SYMBOL_REF_DECL (symbol) = desc->value;

2451   TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1;

2452

2453   rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol);

2454   set_mem_attributes (rtl, exp, 1);

2455   set_mem_alias_set (rtl, 0);

2456   set_mem_alias_set (rtl, const_alias_set );

2457

2458   /* Set flags or add text to the name to record information, such as

2459     that it is a local symbol. If the name is changed, the macro

2460     ASM_OUTPUT_LABELREF will have to know how to strip this

2461     information. This call might invalidate our local variable

2462     SYMBOL; we can't use it afterward.  */

2463

2464   (*targetm .encode_section_info) (exp, rtl, true);

2465

2466   desc->rtl = rtl;

2467

2468   return desc;

2469 }

 

为了在生成汇编代码时,以统一的方式引用这些常量,前端给这些常量做标记;因而对其访问可以通过引用关联的标记( label )来实现访问。这是所谓的内部标记。在我们假定的平台及机器下, ASM_GENERATE_INTERNAL_LABEL 具有下面的定义。这个标记将包含字符串:“ *LC1 ”,“ *LC2 ”,并根据所产生的常量标记的数目以此类推。

 

722  #undef ASM_GENERATE_INTERNAL_LABEL                                      in darwin.h

723  #define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM)   /

724    sprintf (LABEL, "*%s%ld", PREFIX, (long)(NUM))

 

接着我们把这个标记构建成符号引用( SYMBOL_REF ),并为之构建 MEM 节点。然后,根据(可能)常量的属性如下地设置内存属性。

5.13.5.2.2.1.1.1.    设置内存属性

在下面的函数中,参数 objectp 如果不是 0 ,表示我们正在构建一个新的 MEM 节点。而如果参数 bitpos 不是 0 ,则代表一个要应用在参数 t 上的未实现的偏移。

 

1787 void

1788 set_mem_attributes (rtx ref, tree t, int objectp)                                             in emit-rtl.c

1789 {

1790   set_mem_attributes_minus_bitpos (ref, t, objectp, 0);

1791 }

 

下面 1566 1569 行的宏提取 MEM 节点中相应域的内容。这个函数也会用于修改已存在的 MEM 节点。注意在 1593 行对 t 别名集的计算,无论如何它都将覆盖 1566 行的结果。

 

1562 void

1563 set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,                         in emit-rtl.c

1564                              HOST_WIDE_INT bitpos)

1565 {

1566   HOST_WIDE_INT alias = MEM_ALIAS_SET (ref);

1567   tree expr = MEM_EXPR (ref);

1568   rtx offset = MEM_OFFSET (ref);

1569   rtx size = MEM_SIZE (ref);

1570   unsigned int align = MEM_ALIGN (ref);

1571   HOST_WIDE_INT apply_bitpos = 0;

1572   tree type;

1573

1574   /* It can happen that type_for_mode was given a mode for which there

1575     is no language-level type. In which case it returns NULL, which

1576     we can see here.  */

1577   if (t == NULL_TREE)

1578     return ;

1579

1580   type = TYPE_P (t) ? t : TREE_TYPE (t);

1581   if (type == error_mark_node)

1582     return ;

1583

1584   /* If we have already set DECL_RTL = ref, get_alias_set will get the

1585     wrong answer, as it assumes that DECL_RTL already has the right alias

1586     info. Callers should not set DECL_RTL until after the call to

1587     set_mem_attributes.  */

1588   if (DECL_P (t) && ref == DECL_RTL_IF_SET (t))

1589     abort ();

1590

1591   /* Get the alias set from the expression or type (perhaps using a

1592     front-end routine) and use it.  */

1593   alias = get_alias_set (t);

 

记住 ref MEM 节点, type 是参数 t (通常它是一个 DECL 节点,不过它仍然可以是一个类型节点)的类型节点。下面在 1598 行,钩子中的 honor_readonly 在当前 GCC 版本中的所有前端里都是 false

 

set_mem_attributes_minus_bitpos (continue)

 

1595   MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type);

1596   MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type);

1597   RTX_UNCHANGING_P (ref)

1598       |= ((lang_hooks .honor_readonly

1599            && (TYPE_READONLY (type) || TREE_READONLY (t)))

1600          || (! TYPE_P (t) && TREE_CONSTANT (t)));

1601

1602   /* If we are making an object of this type, or if this is a DECL, we know

1603     that it is a scalar if the type is not an aggregate.  */

1604   if ((objectp || DECL_P (t)) && ! AGGREGATE_TYPE_P (type))

1605     MEM_SCALAR_P (ref) = 1;

1606

1607   /* We can set the alignment from the type if we are making an object,

1608     this is an INDIRECT_REF, or if TYPE_ALIGN_OK.  */

1609   if (objectp || TREE_CODE (t) == INDIRECT_REF || TYPE_ALIGN_OK (type))

1610     align = MAX (align, TYPE_ALIGN (type));

1611

1612   /* If the size is known, we can set that.  */

1613   if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))

1614     size = GEN_INT (tree_low_cst (TYPE_SIZE_UNIT (type), 1));

1615

1616   /* If T is not a type, we may be able to deduce some more information about

1617     the expression.  */

1618   if (! TYPE_P (t))

1619   {

1620     maybe_set_unchanging (ref, t);

1621     if (TREE_THIS_VOLATILE (t))

1622       MEM_VOLATILE_P (ref) = 1;

1623

1624      /* Now remove any conversions: they don't change what the underlying

1625       object is. Likewise for SAVE_EXPR.  */

1626     while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR

1627            || TREE_CODE (t) == NON_LVALUE_EXPR

1628            || TREE_CODE (t) == VIEW_CONVERT_EXPR

1629            || TREE_CODE (t) == SAVE_EXPR)

1630       t = TREE_OPERAND (t, 0);

1631

1632     /* If this expression can't be addressed (e.g., it contains a reference

1633       to a non-addressable field), show we don't change its alias set.  */

1634     if (! can_address_p (t))

1635        MEM_KEEP_ALIAS_SET_P (ref) = 1;

1636

1637     /* If this is a decl, set the attributes of the MEM from it.  */

1638     if (DECL_P (t))

1639     {

1640       expr = t;

1641       offset = const0_rtx;

1642       apply_bitpos = bitpos;

1643       size = (DECL_SIZE_UNIT (t)

1644                && host_integerp (DECL_SIZE_UNIT (t), 1)

1645             ? GEN_INT (tree_low_cst (DECL_SIZE_UNIT (t), 1)) : 0);

1646       align = DECL_ALIGN (t);

1647     }

1648

1649     /* If this is a constant, we know the alignment.  */

1650     else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'c')

1651     {

1652       align = TYPE_ALIGN (type);

1653 #ifdef CONSTANT_ALIGNMENT

1654       align = CONSTANT_ALIGNMENT (t, align);

1655 #endif

1656        }

1657

1658     /* If this is a field reference and not a bit-field, record it.  */

1659     /* ??? There is some information that can be gleened from bit-fields,

1660       such as the word offset in the structure that might be modified.

1661       But skip it for now.  */

1662     else if (TREE_CODE (t) == COMPONENT_REF

1663            && ! DECL_BIT_FIELD (TREE_OPERAND (t, 1)))

1664     {

1665       expr = component_ref_for_mem_expr (t);

1666       offset = const0_rtx;

1667       apply_bitpos = bitpos;

1668       /* ??? Any reason the field size would be different than

1669          the size we got from the type?  */

1670     }

 

RTL 节点也需要标识其中的对象是否是不变的(常量), RTX_UNCHANGING_P 就是这个标记。如果上面钩子中的 honor_readonly true ,表示如果 TREE_READONLY TYPE_READONLY 成立,设置 RTX_UNCHANGING_P 。注意 1600 行的语句,如果 t 的值是常量,设置 RTX_UNCHANGING_P 。另外如果 t 满足以下 602 行的条件,也要设置 RTX_UNCHANGING_P 。注意这两个条件不重复。

 

594  void

595  maybe_set_unchanging (rtx ref, tree t)                                                                in explow.c

596  {

597    /* We can set RTX_UNCHANGING_P from TREE_READONLY for decls whose

598      initialization is only executed once, or whose initializer always

599      has the same value. Currently we simplify this to PARM_DECLs in the

600      first case, and decls with TREE_CONSTANT initializers in the second.  */

601 

602    if ((TREE_READONLY (t) && DECL_P (t)

603         && (DECL_EXTERNAL (t)

604            || TREE_CODE (t) == PARM_DECL

605            || (DECL_INITIAL (t) && TREE_CONSTANT (DECL_INITIAL (t)))))

606        || TREE_CODE_CLASS (TREE_CODE (t)) == 'c')

607      RTX_UNCHANGING_P (ref) = 1;

608  }

 

前面我们看过了前端对转换的处理,在 C/C++ 中,转换只改变对象的表达形式,而不改变其所占内存的大小、位置等属性。而且对象的表达形式,只对前端执行语法、语义检查具有意义,后端不在乎对象看起来像什么,而在乎对象在内存中是什么。因此, 1626 行的 WHILE 循环剥除这些对后端不起作用的封装。

另外,对于特定类型的常量,目标平台会有特定的对齐要求, 1653 行的宏 CONSTANT_ALIGNMENT ,对于 x86/Linux 平台,定义为 ix86_constant_alignment 。该函数对对齐量进行必要的调整。

同样,对于 COMPONENT_REF 节点,前端出于维护语法、语义一致性的需要,在所引用的对象节点上可能进行了多次转换的封装。下面的函数剥除了这些对后端无意义的封装。

 

1489 static tree

1490 component_ref_for_mem_expr (tree ref)                                                     in emit-rtl.c

1491 {

1492   tree inner = TREE_OPERAND (ref, 0);

1493

1494   if (TREE_CODE (inner) == COMPONENT_REF)

1495     inner = component_ref_for_mem_expr (inner);

1496   else

1497   {

1498     tree placeholder_ptr = 0;

1499

1500     /* Now remove any conversions: they don't change what the underlying

1501       object is. Likewise for SAVE_EXPR. Also handle PLACEHOLDER_EXPR.  */

1502     while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR

1503           || TREE_CODE (inner) == NON_LVALUE_EXPR

1504           || TREE_CODE (inner) == VIEW_CONVERT_EXPR

1505           || TREE_CODE (inner) == SAVE_EXPR

1506           || TREE_CODE (inner) == PLACEHOLDER_EXPR)

1507       if (TREE_CODE (inner) == PLACEHOLDER_EXPR)

1508         inner = find_placeholder (inner, &placeholder_ptr);

1509       else

1510         inner = TREE_OPERAND (inner, 0);

1511

1512     if (! DECL_P (inner))

1513       inner = NULL_TREE;

1514   }

1515

1516   if (inner == TREE_OPERAND (ref, 0))

1517     return ref;

1518   else

1519     return build (COMPONENT_REF, TREE_TYPE (ref), inner,

1520               TREE_OPERAND (ref, 1));

1521 }

 

下面的 ARRAY_REF 节点代表对数组的访问,其第一个操作数是这个数组,第二个操作数是访问索引。那么 1680 行的 DO WHILE 循环计算出所访问元素到数组开头的偏移。这个偏移保存在下面的 off_tree 中。注意在 1722 行,因为使用 2 进制补码,得到的是 ioff 中为 1 的最低位,也就是所访问元素地址所对齐的边界。

 

set_mem_attributes_minus_bitpos (continue)

 

1672     /* If this is an array reference, look for an outer field reference.  */

1673     else if (TREE_CODE (t) == ARRAY_REF)

1674     {

1675       tree off_tree = size_zero_node;

1676       /* We can't modify t, because we use it at the end of the

1677         function.  */

1678       tree t2 = t;

1679

1680       do

1681       {

1682         tree index = TREE_OPERAND (t2, 1);

1683         tree array = TREE_OPERAND (t2, 0);

1684         tree domain = TYPE_DOMAIN (TREE_TYPE (array));

1685         tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);

1686         tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));

1687

1688         /* We assume all arrays have sizes that are a multiple of a byte.

1689           First subtract the lower bound, if any, in the type of the

1690           index, then convert to sizetype and multiply by the size of the

1691           array element.  */

1692         if (low_bound != 0 && ! integer_zerop (low_bound))

1693           index = fold (build (MINUS_EXPR, TREE_TYPE (index),

1694                            index, low_bound));

1695

1696         /* If the index has a self-referential type, pass it to a

1697           WITH_RECORD_EXPR; if the component size is, pass our

1698           component to one.  */

1699         if (CONTAINS_PLACEHOLDER_P (index))

1700           index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, t2);

1701         if (CONTAINS_PLACEHOLDER_P (unit_size))

1702           unit_size = build (WITH_RECORD_EXPR, sizetype,

1703                          unit_size, array);

1704

1705         off_tree

1706            = fold (build (PLUS_EXPR, sizetype,

1707                        fold (build (MULT_EXPR, sizetype,

1708                                 index,

1709                                 unit_size)),

1710                       off_tree));

1711         t2 = TREE_OPERAND (t2, 0);

1712       }

1713       while (TREE_CODE (t2) == ARRAY_REF);

1714

1715       if (DECL_P (t2))

1716       {

1717         expr = t2;

1718         offset = NULL;

1719         if (host_integerp (off_tree, 1))

1720         {

1721           HOST_WIDE_INT ioff = tree_low_cst (off_tree, 1);

1722            HOST_WIDE_INT aoff = (ioff & -ioff) * BITS_PER_UNIT;

1723           align = DECL_ALIGN (t2);

1724           if (aoff && (unsigned HOST_WIDE_INT) aoff < align)

1725             align = aoff;

1726           offset = GEN_INT (ioff);

1727           apply_bitpos = bitpos;

1728         }

1729       }

1730       else if (TREE_CODE (t2) == COMPONENT_REF)

1731       {

1732         expr = component_ref_for_mem_expr (t2);

1733         if (host_integerp (off_tree, 1))

1734         {

1735           offset = GEN_INT (tree_low_cst (off_tree, 1));

1736           apply_bitpos = bitpos;

1737         }

1738         /* ??? Any reason the field size would be different than

1739           the size we got from the type?  */

1740       }

1741       else if (flag_argument_noalias > 1

1742             && TREE_CODE (t2) == INDIRECT_REF

1743             && TREE_CODE (TREE_OPERAND (t2, 0)) == PARM_DECL)

1744       {

1745         expr = t2;

1746         offset = NULL;

1747       }

1748     }

1749

1750     /* If this is a Fortran indirect argument reference, record the

1751       parameter decl.  */

1752     else if (flag_argument_noalias > 1

1753           && TREE_CODE (t) == INDIRECT_REF

1754           && TREE_CODE (TREE_OPERAND (t, 0)) == PARM_DECL)

1755     {

1756       expr = t;

1757       offset = NULL;

1758     }

1759   }

1760

1761   /* If we modified OFFSET based on T, then subtract the outstanding

1762     bit position offset. Similarly, increase the size of the accessed

1763     object to contain the negative offset.  */

1764   if (apply_bitpos)

1765   {

1766     offset = plus_constant (offset, -(apply_bitpos / BITS_PER_UNIT));

1767     if (size)

1768       size = plus_constant (size, apply_bitpos / BITS_PER_UNIT);

1769   }

1770

1771   /* Now set the attributes we computed above.  */

1772   MEM_ATTRS (ref)

1773     = get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref));

1774

1775   /* If this is already known to be a scalar or aggregate, we are done.  */

1776   if (MEM_IN_STRUCT_P (ref) || MEM_SCALAR_P (ref))

1777     return ;

1778

1779   /* If it is a reference into an aggregate, this is part of an aggregate.

1780     Otherwise we don't know.  */

1781   else if (TREE_CODE (t) == COMPONENT_REF || TREE_CODE (t) == ARRAY_REF

1782         || TREE_CODE (t) == ARRAY_RANGE_REF

1783         || TREE_CODE (t) == BIT_FIELD_REF)

1784     MEM_IN_STRUCT_P (ref) = 1;

1785 }

 

上面的标记 flag_argument_noalias ,如果是 0 ,指针实参可能互为别名(这是 C 的情形);如果是 1 ,指针实参不可能互为别名,但可能是全局变量的别名;如果是 2 ,指针实参不可能互为别名,也不可能是全局变量的别名( Fortran 的情况)。

回到 build_constant_desc ,对于常量不应该赋予其类型关联的别名集,因为它不能改变。前端专门为常量准备了别名集 const_alias_set 。在 2455 行对 set_mem_alias_set 的第一次调用,把常量 RTL 节点的别名集设置为 0 ,是为了绕过该函数中对别名集冲突的检查。

 

1806 void

1807 set_mem_alias_set (rtx mem, HOST_WIDE_INT set)                                   in emit-rtl.c

1808 {

1809 #ifdef ENABLE_CHECKING

1810   /* If the new and old alias sets don't conflict, something is wrong.  */

1811   if (!alias_sets_conflict_p (set, MEM_ALIAS_SET (mem)))

1812     abort ();

1813 #endif

1814

1815   MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem),

1816                                      MEM_SIZE (mem), MEM_ALIGN (mem),

1817                                      GET_MODE (mem));

1818 }

 

而在 2464 行,目标平台钩子 encode_section_info 的细节参考 为内建函数创 RTX对象 一节,这个函数设置了 RTL 节点的 SYMBOL_REF_FLAGS 域。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值