Studying note of GCC-3.4.6 source (168)
2011-02-26 15:48
232 查看
5.13.5.2.2.1.
The initializer
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.
The initializer
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.
相关文章推荐
- Studying note of GCC-3.4.6 source (48)
- Studying note of GCC-3.4.6 source (53)
- Studying note of GCC-3.4.6 source (56)
- Studying note of GCC-3.4.6 source (85)
- Studying note of GCC-3.4.6 source (89)
- Studying note of GCC-3.4.6 source (91)
- Studying note of GCC-3.4.6 source (95)
- Studying note of GCC-3.4.6 source (107)
- Studying note of GCC-3.4.6 source (18)
- Studying note of GCC-3.4.6 source (152)
- Studying note of GCC-3.4.6 source (159)
- Studying note of GCC-3.4.6 source (164)
- Studying note of GCC-3.4.6 source (167)
- Studying note of GCC-3.4.6 source (175)
- Studying note of GCC-3.4.6 source (181)
- Studying note of GCC-3.4.6 source (57)
- Studying note of GCC-3.4.6 source (82)
- Studying note of GCC-3.4.6 source (87)
- Studying note of GCC-3.4.6 source (103)
- Studying note of GCC-3.4.6 source (104)