Here on our target Linux/x86, the output file would be of format ELF. ELF is the format supports relocatable and PIC (position independent code). Chapter 3 of [10] gives a good description about ELF. As summeray gotten from [10], we find:
ELF files come in three slightly different flavors: relocatable, executable, and shared object. Relocatable files are created by compilers and assemblers but need to be processed by the linker before running. Executable files have all relocation done and all symbols resolved except perhaps shared library symbols to be resolved at runtime. Shared objects are shared libraries, containing both symbol information for the linker and directly runnable code for runtime.
ELF files have an unusual dual nature. Compilers, assemblers, and linkers treat the file as a set of logical sections described by a section header table, while the system loader treats the file as a set of segments described by a program header table. A single segment will usually consist of several sections. For example, a ‘‘loadable read-only’’ segment could contain sections for executable code, read-only data, and symbols for the dynamic linker. Relocatable files have section tables, executable files have program header tables, and shared objects have both. The sections are intended for further processing by a linker, while the segments are intended to be mapped into memory.
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 );
Field DECL_INITIAL if is NULL, means decl hasn’t initializer; and if is error_mark_node , means decl has initializer but it hasn’t been seen yet. If the initializer unknown, it needs be conservative. At line 1462, reloc would hold a value that will be compared with flag_pic to select the section the code will be placed. And as we have seen in before chapter, flag_pic if is 1 means doing small PIC, and if is 2 means doing big PIC. Later we will see the effect of these value.
It sets reloc as 3 if the type of decl contains pointer (or reference) which told by below function. This value indicates that uses big PIC as possible, otherwise tries small 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 }
If the initializer is known, it needs to see what kind of relocations it may need. If the initializer contains address expression, ELF code of PIC requires the accessing of the refferred object should via a GOT, below function searches addressed object within the initializer. If there is no usage of object address in the initializer, the function will return 0.
The C++ front-end hook expand_constant bound with function cplus_expand_constant , it replaces PTRMEM_CST (the pointer-to-member constants) either with PLUS_EXPR (case for referring to data member) or with more appropriate PTRMEM_CST (case for referring to method of base from derived).
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 }
For non-static data member of class or elment of array, their address is given in offset from the base address. They also need relocation at time of loading. Further TREE_PUBLIC in a VAR_DECL or FUNCTION_DECL, if is nonzero means name is to be accessible from outside this module; in an IDENTIFIER_NODE, if is nonzero means an external declaration accessible from outside this module was previously seen for this name in an inner scope. So set reloc accordingly as line 3404 to 3407 does.
Below function is inovked at line 3400 above, it finds out the object that gets referred.
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. Output constant referred
Then at line 1466 in assemble_variable , in the invocation of output_addressed_constants , its argument is this initializer. Similiarly, this function searches address used in 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 }
Condition at line 3468 if satisfied, means object upon this address is constant. And condition at line 3469 if satisfied, represents the brace-enclosed initializers for a structure or array, which may be read-only. The front-end uses data structure constant_descriptor_tree to describe these nodes for (maybe) constant.
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 };
Every constant is a singleton at least within the translation-unit. We have seen that in the front-end, tree node for constant is cached within the hash table. Now for constant descriptor node, it is the same.
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 }
If the constant descriptor is not found within const_desc_htab (see that the tree node of this constant is used as the key, and const_desc_hash is called to compare nodes’ content), build_constant_desc comes to help. Below at line 2441, copy_constant copies the tree node of the constants within exp , as below we may modify the node’s content, we need own a copy.
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 }
To visit these constants in a unified way in assemble, the front-end labels these constants; so the visit can be done via referring the associated label. It is the so-called internal label. Under our assuming platform and machine, ASM_GENERATE_INTERNAL_LABEL is defined as below. The label will contain string like: “*LC1”, “*LC2”, and so on, according to the number of constant label generated.
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))
Next we make this label into SYMBOL_REF, and build MEM node for it . Then, according to the property of this (maybe) constant, set memory attributions.
5.13.5.2.2.1.1.1. Set memory attributions
In below function, parameter objectp if nonzero, means we are making a new MEM for the type. And if bitpos is nonzero, it is an offset outstanding on parameter t that will be applied later.
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 }
Below code between line 1566 and 1569 extracts the content of corresponding fields of the MEM node. The function is also used to modify already existing MEM node. Note the caculation of alias set of t at line 1593, it overwrites the result at line 1566 anyhow.
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);
Remember ref is the MEM node, and type is the node of type of argument t (usually it is a DECL, but it still can be a type node). Below at line 1598 honor_readonly in the hook is false for all front-end in GCC current version.
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 node also needs be told if its content is unchangable (constant), RTX_UNCHANGING_P is the tag for the purpose. If above honor_readonly in the hook is true, it means setting RTX_UNCHANGING_P if TREE_READONLY or TYPE_READONLY hold. Pay attention to statement at line 1600, if t’s value is constant, setting RTX_UNCHANGING_P. Besides, if t satisfies condition at line 602 below, setting RTX_UNCHANGING_P too. See that these two conditions are not overlapped.
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 }
In previous, we have seen the process of conversion in front-end, in C/C++, conversion only changes the representation of object, but does not change the property of the memory, such as size, position occupied. The representation of object only means to semantic and syntax checking done in front-end, the back-end doesn’t care what the object looks like, but what it is in memory. So WHILE loop at line 1626 strips these enclosings useless in back-end.
Next, for constant of specified type, target platform may have specific alignment requirement, at line 1653 macro CONSTANT_ALIGNMENT is defined as ix86_constant_alignment for x86/Linux target. The function does necessary adjustment upon alignment.
Similarly, in COMPONENT_REF node, the front-end, out of purpose of maintaining the consistency of semanteme and syntax, may encapsulate it several times. Below function reveals these meaningless encapsulations.
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 }
Below ARRAY_REF stands for array accesses; first operand is the array, the second is the index. So DO WHILE loop at line works out the offset from the element accessed to the head of the array. This offset is saved in off_tree below. Note at line 1722, because it uses binary complement code, it gets the lowest bit of 1 in ioff , that is the boundary the accessed element aligns.
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 }
Above flag flag_argument_noalias , if is 0, pointer arguments may alias each other (true in C); if is 1, pointer arguments may not alias each other but may alias global variables; if is 2, pointer arguments may not alias each other and may not alias global variables (true in Fortran).
Back build_constant_desc , it should not assign alias set of the type to the constant, as it can’t be changed. Front-end prepares const_alias_set specially for constants. The first call of set_mem_alias_set at line 2455, sets the alias set of RTL node of constant into 0, to bypass the checking for alias set confliction.
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 }
Then at line 2464, refers to section Create RTX object for builtin for the detail of target platform hook encode_section_info, the function sets SYMBOL_REF_FLAGS field for the RTL node.