Studying note of GCC-3.4.6 source (166)
2011-02-19 11:58
260 查看
5.13.5.1.3.
Prepare
alias set
However, the entry point for creating alias set is get_alias_set
below. Both node of type and node of declaration can claim for alias analysis,
but declaration’s alias set is determined by the alias set of underlying type. Condition
at line 467 selects out the node of declaration. In C++ front-end, hook get_alias_set
at line 475 points to cxx_get_alias_set
. However, the function
majorly handles node of type definition, we leave the function for the moment.
449
HOST_WIDE_INT
450
get_alias_set
(tree t)
in alias.c
451
{
452
HOST_WIDE_INT set;
453
454
/* If we're not doing any alias analysis, just
assume everything
455
aliases everything else. Also return 0 if
this or its type is
456
an error.
*/
457
if (! flag_strict_aliasing
|| t == error_mark_node
458
|| (! TYPE_P (t)
459
&& (TREE_TYPE (t) ==
0 || TREE_TYPE (t) == error_mark_node)))
460
return
0;
461
462
/* We can be passed either an expression or a
type. This and the
463
language-specific routine may make
mutually-recursive calls to each other
464
to figure out what to do. At each juncture,
we see if this is a tree
465
that the language may need to handle
specially. First handle things that
466
aren't types.
*/
467
if (! TYPE_P (t))
468
{
469
tree inner = t;
470
tree placeholder_ptr = 0;
471
472
/* Remove any nops, then give the language a
chance to do
473
something with this tree before we look at
it.
*/
474
STRIP_NOPS (t);
475
set = (*lang_hooks
.
get_alias_set
) (t);
476
if (set != -1)
477
return
set;
478
479
/* First see if the actual object referenced
is an INDIRECT_REF from a
480
restrict-qualified pointer or a "void
*". Replace
481
PLACEHOLDER_EXPRs.
*/
482
while
(TREE_CODE (inner) ==
PLACEHOLDER_EXPR
483
|| handled_component_p (inner))
484
{
485
if (TREE_CODE (inner) == PLACEHOLDER_EXPR)
486
inner = find_placeholder (inner,
&placeholder_ptr);
487
else
488
inner = TREE_OPERAND (inner,
0);
489
490
STRIP_NOPS (inner);
491
}
492
493
/* Check for accesses through
restrict-qualified pointers.
*/
494
if (TREE_CODE (inner) == INDIRECT_REF)
495
{
496
tree decl = find_base_decl
(TREE_OPERAND
(inner, 0));
497
498
if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
499
{
500
/* If we haven't computed the actual alias
set, do it now.
*/
501
if (DECL_POINTER_ALIAS_SET (decl) == -2)
502
{
503
tree pointed_to_type = TREE_TYPE
(TREE_TYPE (decl));
504
505
/* No two
restricted pointers can point at the same thing.
506
However, a restricted pointer can point at
the same thing
507
as an unrestricted pointer, if that
unrestricted pointer
508
is based on the restricted pointer. So, we
make the
509
alias set for the restricted pointer a
subset of the
510
alias set for the type pointed to by the
type of the
511
decl.
*/
512
HOST_WIDE_INT pointed_to_alias_set
513
= get_alias_set
(pointed_to_type);
514
515
if (pointed_to_alias_set == 0)
516
/* It's
not legal to make a subset of alias set zero.
*/
517
DECL_POINTER_ALIAS_SET (decl) = 0;
518
else if (AGGREGATE_TYPE_P
(pointed_to_type))
519
/* For an
aggregate, we must treat the restricted
520
pointer the same as an ordinary pointer.
If we
521
were to make the type pointed to by the
522
restricted pointer a subset of the
pointed-to
523
type, then we would believe that other
subsets
524
of the pointed-to type (such as fields
of that
525
type) do not conflict with the type
pointed to
526
by the restricted pointer.
*/
527
DECL_POINTER_ALIAS_SET (decl)
528
= pointed_to_alias_set;
529
else
530
{
531
DECL_POINTER_ALIAS_SET (decl) = new_alias_set
();
532
record_alias_subset
(pointed_to_alias_set,
533
DECL_POINTER_ALIAS_SET (decl));
534
}
535
}
536
537
/* We
use the alias set indicated in the declaration.
*/
538
return
DECL_POINTER_ALIAS_SET (decl);
539
}
540
541
/* If
we have an INDIRECT_REF via a void pointer, we don't
542
know anything about what that might
alias.
*/
543
else if (TREE_CODE (TREE_TYPE (inner)) == VOID_TYPE)
544
return
0;
545
}
546
547
/* Otherwise, pick up the outermost object that
we could have a pointer
548
to,
processing conversion and PLACEHOLDER_EXPR as above.
*/
549
placeholder_ptr = 0;
550
while
(TREE_CODE (t) == PLACEHOLDER_EXPR
551
|| (handled_component_p (t)
&& ! can_address_p (t)))
552
{
553
if (TREE_CODE (t) == PLACEHOLDER_EXPR)
554
t = find_placeholder (t,
&placeholder_ptr);
555
else
556
t = TREE_OPERAND (t, 0);
557
558
STRIP_NOPS (t);
559
}
560
561
/* If
we've already determined the alias set for a decl, just return
562
it.
This is necessary for C++ anonymous unions, whose component
563
variables don't look like union members
(boo!).
*/
564
if (TREE_CODE (t) == VAR_DECL
565
&& DECL_RTL_SET_P (t) && GET_CODE (DECL_RTL (t)) == MEM)
566
return
MEM_ALIAS_SET (DECL_RTL (t));
567
568
/* Now all we care about is the type.
*/
569
t = TREE_TYPE (t);
570
}
Above node of INDIRECT_REF in C++ language stands for an expression
for a pointer or reference (for example, char *p;), clearly the alias set of
the object referred is what we want. Thus find_base_decl
finds the DECL on which this
expression is based (For example, in `a[i]' this would be `a'). And if there is
no such DECL, or a unique DECL cannot be determined, NULL_TREE is returned.
361
static
tree
362
find_base_decl
(tree t)
in alias.c
363
{
364
tree d0, d1, d2;
365
366
if (t == 0 || t == error_mark_node || ! POINTER_TYPE_P (TREE_TYPE (t)))
367
return
0;
368
369
/* If this is a declaration, return it.
*/
370
if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
371
return
t;
372
373
/* Handle general expressions. It would be
nice to deal with
374
COMPONENT_REFs here. If we could tell that
`a' and `b' were the
375
same, then `a->f' and `b->f' are also
the same.
*/
376
switch
(TREE_CODE_CLASS (TREE_CODE (t)))
377
{
378
case
'1':
379
return
find_base_decl (TREE_OPERAND (t,
0));
380
381
case
'2':
382
/*
Return 0 if found in neither or both are the same.
*/
383
d0 = find_base_decl (TREE_OPERAND (t, 0));
384
d1 = find_base_decl (TREE_OPERAND (t, 1));
385
if (d0 == d1)
386
return
d0;
387
else if (d0 == 0)
388
return
d1;
389
else if (d1 == 0)
390
return
d0;
391
else
392
return
0;
393
394
case
'3':
395
d0 = find_base_decl (TREE_OPERAND (t, 0));
396
d1 = find_base_decl (TREE_OPERAND (t, 1));
397
d2 = find_base_decl (TREE_OPERAND (t, 2));
398
399
/* Set any nonzero values from the last, then
from the first.
*/
400
if (d1 == 0) d1 = d2;
401
if (d0 == 0) d0 = d1;
402
if (d1 == 0) d1 = d0;
403
if (d2 == 0) d2 = d1;
404
405
/* At this point all are nonzero or all are
zero. If all three are the
406
same, return it. Otherwise, return
zero.
*/
407
return
(d0 == d1 && d1 == d2) ?
d0 : 0;
408
409
default
:
410
return
0;
411
}
412
}
If we find the based DECL, back get_alias_set
at line 498, if DECL_POINTER_ALIAS_SET
doesn’t set with -1, DECL_POINTER_ALIAS_SET_KNOWN_P is true (-1 means the alias
set for the declaration has not been yet computed). Further if DECL_POINTER_ALIAS_SET
returns -2, it indicates that we need to make a unique alias set for this
pointer (it is only applied to case of using GNU extension keyword restrict
to restrict pointer alias, see c_apply_type_quals_to_decl
). It needs some
special treatement.
The restrict
pointer
qualifier can be applied to a data pointer to indicate that, during the scope
of that pointer declaration, all data accessed through it will be accessed only
through that pointer but not through any other pointer. The __restrict__
keyword thus enables the compiler to perform certain optimizations based on the
premise that a given object cannot be changed through another pointer. For
example, declaration “int
f (
int
*
restrict
x,
int
*
restrict
y)” means changing the content of address pointed by
pointer
x
can only via this pointer. So it is safe to compute alias
set as below.
Then at line 503 in
get_alias_set
,
here decl
is the based DECL, it must have type of indirect type (pointer or reference),
so pointed_to_type
holds the type the indirect type refers to. Next get_alias_set
invoked at
line 512 recursively works out the alias set for the type. So at line 518, if pointed_to_type
points to aggregate type, the alias set for this type should have been computed
in the invocation at line 512, uses this alias set for the pointer (computing
alias set for aggregate type is done by record_component_aliases
, we will see it
soon).
While if the pointer is not of aggregate type, it enters block at
line 529 in get_alias_set
,
to be conservative but correct, combines all declarations pointed by pointer of
this type into the same tree of alias set rooted by the pointer type (but note
that the alias set of decl
aliases nothing but it self, since it is
delcared as “restrict”).
Then if it comes at line 549 in get_alias_set
, because either inner is not INDIRECT_REF
or its alias set is unknown. For the case, we get the alias set from its type.
Node of WITH_RECORD_EXPR and PLACEHOLDER_EXPR are used in languages
that have types where some field in an object of the type contains a value that
is used in the computation of another field's offset or size and/or the size of
the type. The positions and/or sizes of fields can vary from object to object
of the same type or even for one and the same object within its scope. Record
types with discriminants in Ada
or schema types in Pascal are examples of such types. For C++ front-end, we
don’t need worry about these nodes.
get_alias_set (continue)
572
/* Variant qualifiers don't affect the alias
set, so get the main
573
variant. If this is a type with a known
alias set, return it.
*/
574
t = TYPE_MAIN_VARIANT (t);
575
if (TYPE_ALIAS_SET_KNOWN_P (t))
576
return
TYPE_ALIAS_SET (t);
577
578
/* See if the language has special handling
for this type.
*/
579
set = (*lang_hooks
.
get_alias_set
) (t);
580
if (set != -1)
581
return
set;
582
583
/* There are no objects of FUNCTION_TYPE, so
there's no point in
584
using up an alias set for them. (There are,
of course, pointers
585
and references to functions, but that's
different.)
*/
586
else if (TREE_CODE (t) == FUNCTION_TYPE)
587
set = 0;
588
589
/* Unless the language specifies otherwise,
let vector types alias
590
their components. This avoids some nasty
type punning issues in
591
normal usage. And indeed lets vectors be
treated more like an
592
array slice.
*/
593
else if (TREE_CODE (t) == VECTOR_TYPE)
594
set = get_alias_set (TREE_TYPE (t));
595
596
else
597
/* Otherwise make a new alias set for this
type.
*/
598
set = new_alias_set
();
599
600
TYPE_ALIAS_SET (t) = set;
601
602
/* If this is an aggregate type, we must
record any component aliasing
603
information.
*/
604
if (AGGREGATE_TYPE_P (t) || TREE_CODE (t) == COMPLEX_TYPE)
605
record_component_aliases
(t);
606
607
return
set;
608
}
First, it sees if there is any suggestion from the language. Hook get_alias_set
refers to cxx_get_alias_set
below for C++.
Recall that for non-POD class, CLASSTYPE_AS_BASE is an RECORD_TYPE
node with virtual bases stripped and its TYPE_CONTEXT refers to the RECORD_TYPE
of the class, so predicate “CLASSTYPE_AS_BASE (TYPE_CONTEXT (t)) == t” is true
if t
is the node of CLASSTYPE_AS_BASE of non-POD class (while for POD class,
CLASSTYPE_AS_BASE is the RECORD_TYPE of the class, so the mentioned predicate
is false).
So condition at line 295 tells that t
is enclosed within a class, and
it is the base part of enclosing class.
292
static
HOST_WIDE_INT
293
cxx_get_alias_set
(tree t)
in cp-lang.c
294
{
295
if (TREE_CODE (t) == RECORD_TYPE
296
&& TYPE_CONTEXT (t)
&& CLASS_TYPE_P (TYPE_CONTEXT (t))
297
&& CLASSTYPE_AS_BASE
(TYPE_CONTEXT (t)) == t)
298
/* The base variant of a type must be in the
same alias set as the
299
complete type.
*/
300
return
get_alias_set
(TYPE_CONTEXT (t));
301
302
if (/* It's not yet safe to use alias sets for
some classes in C++.
*/
303
!ok_to_generate_alias_set_for_type
(t)
304
/*
Nor is it safe to use alias sets for pointers-to-member
305
functions, due to the fact that there
may be more than one
306
RECORD_TYPE type corresponding to the
same pointer-to-member
307
type.
*/
308
|| TYPE_PTRMEMFUNC_P (t))
309
return
0;
310
311
return
c_common_get_alias_set
(t);
312
}
Then for the cases come at line 302, ok_to_generate_alias_set_for_type
checks if the type is safe for aliasing.
First, class having virtual base is unsafe for aliasing. For
example :
class
A { ... };
class
B : public
virtual
A {
... } ;
class
C : public
virtual
A {
... } ;
class
D : public
B, C { ... } ;
Though D derives from B, in D the base B has different layout than
class B even if B is empty class. Remember predicate CLASS_TYPE_P at line 250
is false for CLASSTYPE_AS_BASE of non-POD class.
Similarly, if a class contains a field of another class containing
virtual base, it is unsafe to alias this type (both cases considered as
may-alias).
239
static
bool
240
ok_to_generate_alias_set_for_type
(tree
t)
in cp-lang.c
241
{
242
if (TYPE_PTRMEMFUNC_P (t))
243
return
true;
244
if (AGGREGATE_TYPE_P (t))
245
{
246
if ((TREE_CODE (t) == RECORD_TYPE) || (TREE_CODE (t) == UNION_TYPE))
247
{
248
tree fields;
249
/* Backend-created structs are safe.
*/
250
if (! CLASS_TYPE_P (t))
251
return
true;
252
/* PODs
are safe.
*/
253
if (! CLASSTYPE_NON_POD_P(t))
254
return
true;
255
/*
Classes with virtual baseclasses are not.
*/
256
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
257
return
false;
258
/* Recursively check the base classes.
*/
259
if (TYPE_BINFO (t) != NULL && TYPE_BINFO_BASETYPES (t) != NULL)
260
{
261
int i;
262
for
(i = 0; i < TREE_VEC_LENGTH
(TYPE_BINFO_BASETYPES (t)); i++)
263
{
264
tree binfo = TREE_VEC_ELT
(TYPE_BINFO_BASETYPES (t), i);
265
if
(!ok_to_generate_alias_set_for_type (BINFO_TYPE (binfo)))
266
return
false;
267
}
268
}
269
/* Check all the fields.
*/
270
for
(fields = TYPE_FIELDS (t); fields;
fields = TREE_CHAIN (fields))
271
{
272
if (TREE_CODE (fields) != FIELD_DECL)
273
continue
;
274
if (! ok_to_generate_alias_set_for_type (TREE_TYPE (fields)))
275
return
false;
276
}
277
return
true;
278
}
279
else if (TREE_CODE (t) == ARRAY_TYPE)
280
return
ok_to_generate_alias_set_for_type
(TREE_TYPE (t));
281
else
282
/* This should never happen, we dealt with all
the aggregate
283
types that can appear in C++
above.
*/
284
abort ();
285
}
286
else
287
return
true;
288
}
Further
considering following example:
extern
"C" int
printf(const
char *,...);
class
A {
protected
: int i ;
public
:
void f1 () { printf ("%d/n",
i); }
A () : i (0) {}
};
class
B : public
A {
public
:
void f1 () { printf ("%d/n",
i); }
B () { i = 2 ; }
};
int main () {
void (A::*pf1) () = &A::f1;
B b;
(b.*pf1)();
// output “2”
A a ;
(a.*pf1)() ;
// output “0”
return
0;
}
It prints out “2, 0”, no
doubt pf1
accesses different objects in both times. So be careful in treating alias set
for member pointer. Here such pointer is regarded as may-alias (line 308 in
cxx_get_alias_set
).
Except the treatment of class, C++ front-end shares following
routine with C front-end to handle types also available in C. First for direct
accessing of union member, it aliases to the other members of the union. The
comment of the case says that setting the field via taking address is not
permitted in C standard and it has implementation-defined behave, [6] also
gives an explaination.
Immediately in below, we will see an example of incorrect code
generated out of type-punning. And that example can explain well why there may
be undefined behavior. However, GCC give NO
warning if we behave badly as above. Except this case, t
of non-type is kicked off.
2848
HOST_WIDE_INT
2849
c_common_get_alias_set
(tree t)
n c-common.c
2850
{
2851
tree u;
2852
2853
/*
Permit type-punning when accessing a union, provided the access
2854
is
directly through the union. For example, this code does not
2855
permit
taking the address of a union member and then storing
2856
through it. Even the type-punning allowed here is a GCC
2857
extension, albeit a common and useful one; the C standard says
2858
that
such accesses have implementation-defined behavior.
*/
2859
for
(u = t;
2860
TREE_CODE (u) ==
COMPONENT_REF || TREE_CODE (u) == ARRAY_REF;
2861
u = TREE_OPERAND (u,
0))
2862
if (TREE_CODE (u) ==
COMPONENT_REF
2863
&& TREE_CODE
(TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE)
2864
return
0;
2865
2866
/*
That's all the expressions we handle specially.
*/
2867
if (! TYPE_P (t))
2868
return
-1;
2869
2870
/* The C standard
guarantees that any object may be accessed via an
2871
lvalue that has character type.
*/
2872
if (t == char_type_node
2873
|| t == signed_char_type_node
2874
|| t == unsigned_char_type_node)
2875
return
0;
2876
2877
/* If it has the
may_alias attribute, it can alias anything.
*/
2878
if (lookup_attribute
("may_alias", TYPE_ATTRIBUTES (t)))
2879
return
0;
2880
2881
/* The C standard
specifically allows aliasing between signed and
2882
unsigned variants of the same type. We
treat the signed
2883
variant as canonical.
*/
2884
if (TREE_CODE (t) == INTEGER_TYPE &&
TREE_UNSIGNED (t))
2885
{
2886
tree t1 = c_common_signed_type (t);
2887
2888
/* t1 == t can
happen for boolean nodes which are always unsigned.
*/
2889
if (t1 != t)
2890
return
get_alias_set
(t1);
2891
}
2892
else if (POINTER_TYPE_P (t))
2893
{
2894
tree t1;
2895
2896
/* Unfortunately, there is no canonical form
of a pointer type.
2897
I
n particular, if we have `typedef int I', then
`int *', and
2898
`I *' are different types. So, we have to
pick a canonical
2899
representative. We do this below.
2900
2901
Technically, this approach is actually
more conservative that
2902
it needs to be. In particular, `const int
*' and `int *'
2903
should be in different alias sets,
according to the C and C++
2904
standard, since their types are not the
same, and so,
2905
technically, an `int **' and `const int
**' cannot point at
2906
the same thing.
2907
2908
But, the standard is wrong. In particular,
this code is
2909
legal C++:
2910
2911
int *ip;
2912
int **ipp = &ip;
2913
const int* const* cipp = &ipp;
2914
2915
And, it doesn't make sense for that to be
legal unless you
2916
can dereference IPP and CIPP. So, we
ignore cv-qualifiers on
2917
the pointed-to types. This issue has been
reported to the
2918
C++ committee.
*/
2919
t1 = build_type_no_quals (t);
2920
if (t1 != t)
2921
return
get_alias_set
(t1);
2922
}
2923
2924
return
-1;
2925
}
Above at line 2872, there are two case in fact would be covered.
That is declaration like : char c; and char *pc; for the former case, c
can’t alias other and no need create alias set (and consider the case of short
type, it a group of 2 bytes, thus these two bytes can alias short type and must
have alias set within the alias set of short, the front-end must prepare an
alias set for this type as we see in the code), while rear one aliases any
object that can be accessed via a lvalue. But for rear case, every time it
points to specific object, it will get its alias set through block at line 494
in get_alias_set
,
and mayn’t be zero any more (it returns 0 for c style type cast).
At here, it is clear that declarations other than indirect reference
(those pointer type or reference type) will share the alias set of their based
type. For example : “short j , k, l; ”, in this statement, variables
j, k, and l will have the same alias set of type short. However, the alias set
will be ignored as these variables can’t alias each other. Now if we change the
statement as : “short j, k, l, *p;”, now j, k, l and pointer p will share
the alias set of short. So the front-end can know that p may alias to j, k or
l.
Next consider statement “short j, k; char *p;”, j and k share the
same alias set of short, but now p hasn’t alias set because get_alias_set
(more precisely c_common_get_alias_set
) returns 0 for it. For
this statement alone, the front-end won’t alias p to j or k. If we add a
statement : “p = &j;”, in C++, it will trigger implicit
conversion error. Then if we add instead a statement: “p = (char*)&j;”,
alias set of p and j will be checked for intersection by front-end. It will pass
since p has a superset of 0 (keep in mind there is no real superset of 0
created), and generate code for the conversion. However, the alias set of p
always keeps as 0, which means it may-alias to everything can be accessed via
lvalue. This assumption prevents compiler from taking error-prone too
aggressive optimization. But it also a point as further improvement to
discriminate alias set finer.
And at line 2884 above, integer types with difference signed also
shares the same alias set.
Line 2878 mentions an interesting GNU C++ attribution “may_alias”.
[6] gives a detail.
In above example, in other words, replacing short_a with short
generates incorrect
code. However
you can use –Wstrict-aliasing to find out pointer that may break the alias. For
example, here with the option, the compiler gives a warning as : “test2.cpp:4:
warning: dereferencing type-punned pointer will break strict-aliasing rules
”.
Then, if cxx_get_alias_set
returns value other than
-1, either the alias set is found, or the object can alias nothing (i.e, char
type). Otherwise, it needs go ahead. See that at line 598 in get_alias_set
,
the type is assigned with unique alias set and will be shared by declarations
of the type. And for aggregate type or type containing more than 1 component,
the alias set should contain alias sets of its fields. Below function record_omponent_aliases
builds the alias tree in this way. Predicate TYPE_NONALIASED_COMPONENT at line
709 if true, indicates that it is not permitted to take the address of a
component of the type.
697
void
698
record_component_aliases
(tree type)
in alias.c
699
{
700
HOST_WIDE_INT superset = get_alias_set
(type);
701
tree field;
702
703
if (superset == 0)
704
return
;
705
706
switch
(TREE_CODE (type))
707
{
708
case
ARRAY_TYPE:
709
if (! TYPE_NONALIASED_COMPONENT (type))
710
record_alias_subset
(superset, get_alias_set
(TREE_TYPE (type)));
711
break
;
712
713
case
RECORD_TYPE:
714
case
UNION_TYPE:
715
case
QUAL_UNION_TYPE:
716
/* Recursively record aliases for the base
classes, if there are any.
*/
717
if (TYPE_BINFO (type) !=
NULL && TYPE_BINFO_BASETYPES (type) != NULL)
718
{
719
int i;
720
for
(i = 0; i < TREE_VEC_LENGTH
(TYPE_BINFO_BASETYPES (type)); i++)
721
{
722
tree binfo = TREE_VEC_ELT
(TYPE_BINFO_BASETYPES (type), i);
723
record_alias_subset
(superset,
724
get_alias_set
(BINFO_TYPE (binfo)));
725
}
726
}
727
for
(field = TYPE_FIELDS (type); field
!= 0; field = TREE_CHAIN (field))
728
if (TREE_CODE (field)
== FIELD_DECL && ! DECL_NONADDRESSABLE_P (field))
729
record_alias_subset
(superset, get_alias_set
(TREE_TYPE (field)));
730
break
;
731
732
case
COMPLEX_TYPE:
733
record_alias_subset
(superset, get_alias_set
(TREE_TYPE (type)));
734
break
;
735
736
default
:
737
break
;
738
}
739
}
Notice that in the aggregate type, for example, field of type of
short will use alias set of type short, which means it will share this alias
set with other declarations of this type. By this way, if there is a pointer of
short type, the compiler can tell that the pointer may alias to this field and
other declarations, and prevent too heavy optimization.
Prepare
alias set
However, the entry point for creating alias set is get_alias_set
below. Both node of type and node of declaration can claim for alias analysis,
but declaration’s alias set is determined by the alias set of underlying type. Condition
at line 467 selects out the node of declaration. In C++ front-end, hook get_alias_set
at line 475 points to cxx_get_alias_set
. However, the function
majorly handles node of type definition, we leave the function for the moment.
449
HOST_WIDE_INT
450
get_alias_set
(tree t)
in alias.c
451
{
452
HOST_WIDE_INT set;
453
454
/* If we're not doing any alias analysis, just
assume everything
455
aliases everything else. Also return 0 if
this or its type is
456
an error.
*/
457
if (! flag_strict_aliasing
|| t == error_mark_node
458
|| (! TYPE_P (t)
459
&& (TREE_TYPE (t) ==
0 || TREE_TYPE (t) == error_mark_node)))
460
return
0;
461
462
/* We can be passed either an expression or a
type. This and the
463
language-specific routine may make
mutually-recursive calls to each other
464
to figure out what to do. At each juncture,
we see if this is a tree
465
that the language may need to handle
specially. First handle things that
466
aren't types.
*/
467
if (! TYPE_P (t))
468
{
469
tree inner = t;
470
tree placeholder_ptr = 0;
471
472
/* Remove any nops, then give the language a
chance to do
473
something with this tree before we look at
it.
*/
474
STRIP_NOPS (t);
475
set = (*lang_hooks
.
get_alias_set
) (t);
476
if (set != -1)
477
return
set;
478
479
/* First see if the actual object referenced
is an INDIRECT_REF from a
480
restrict-qualified pointer or a "void
*". Replace
481
PLACEHOLDER_EXPRs.
*/
482
while
(TREE_CODE (inner) ==
PLACEHOLDER_EXPR
483
|| handled_component_p (inner))
484
{
485
if (TREE_CODE (inner) == PLACEHOLDER_EXPR)
486
inner = find_placeholder (inner,
&placeholder_ptr);
487
else
488
inner = TREE_OPERAND (inner,
0);
489
490
STRIP_NOPS (inner);
491
}
492
493
/* Check for accesses through
restrict-qualified pointers.
*/
494
if (TREE_CODE (inner) == INDIRECT_REF)
495
{
496
tree decl = find_base_decl
(TREE_OPERAND
(inner, 0));
497
498
if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
499
{
500
/* If we haven't computed the actual alias
set, do it now.
*/
501
if (DECL_POINTER_ALIAS_SET (decl) == -2)
502
{
503
tree pointed_to_type = TREE_TYPE
(TREE_TYPE (decl));
504
505
/* No two
restricted pointers can point at the same thing.
506
However, a restricted pointer can point at
the same thing
507
as an unrestricted pointer, if that
unrestricted pointer
508
is based on the restricted pointer. So, we
make the
509
alias set for the restricted pointer a
subset of the
510
alias set for the type pointed to by the
type of the
511
decl.
*/
512
HOST_WIDE_INT pointed_to_alias_set
513
= get_alias_set
(pointed_to_type);
514
515
if (pointed_to_alias_set == 0)
516
/* It's
not legal to make a subset of alias set zero.
*/
517
DECL_POINTER_ALIAS_SET (decl) = 0;
518
else if (AGGREGATE_TYPE_P
(pointed_to_type))
519
/* For an
aggregate, we must treat the restricted
520
pointer the same as an ordinary pointer.
If we
521
were to make the type pointed to by the
522
restricted pointer a subset of the
pointed-to
523
type, then we would believe that other
subsets
524
of the pointed-to type (such as fields
of that
525
type) do not conflict with the type
pointed to
526
by the restricted pointer.
*/
527
DECL_POINTER_ALIAS_SET (decl)
528
= pointed_to_alias_set;
529
else
530
{
531
DECL_POINTER_ALIAS_SET (decl) = new_alias_set
();
532
record_alias_subset
(pointed_to_alias_set,
533
DECL_POINTER_ALIAS_SET (decl));
534
}
535
}
536
537
/* We
use the alias set indicated in the declaration.
*/
538
return
DECL_POINTER_ALIAS_SET (decl);
539
}
540
541
/* If
we have an INDIRECT_REF via a void pointer, we don't
542
know anything about what that might
alias.
*/
543
else if (TREE_CODE (TREE_TYPE (inner)) == VOID_TYPE)
544
return
0;
545
}
546
547
/* Otherwise, pick up the outermost object that
we could have a pointer
548
to,
processing conversion and PLACEHOLDER_EXPR as above.
*/
549
placeholder_ptr = 0;
550
while
(TREE_CODE (t) == PLACEHOLDER_EXPR
551
|| (handled_component_p (t)
&& ! can_address_p (t)))
552
{
553
if (TREE_CODE (t) == PLACEHOLDER_EXPR)
554
t = find_placeholder (t,
&placeholder_ptr);
555
else
556
t = TREE_OPERAND (t, 0);
557
558
STRIP_NOPS (t);
559
}
560
561
/* If
we've already determined the alias set for a decl, just return
562
it.
This is necessary for C++ anonymous unions, whose component
563
variables don't look like union members
(boo!).
*/
564
if (TREE_CODE (t) == VAR_DECL
565
&& DECL_RTL_SET_P (t) && GET_CODE (DECL_RTL (t)) == MEM)
566
return
MEM_ALIAS_SET (DECL_RTL (t));
567
568
/* Now all we care about is the type.
*/
569
t = TREE_TYPE (t);
570
}
Above node of INDIRECT_REF in C++ language stands for an expression
for a pointer or reference (for example, char *p;), clearly the alias set of
the object referred is what we want. Thus find_base_decl
finds the DECL on which this
expression is based (For example, in `a[i]' this would be `a'). And if there is
no such DECL, or a unique DECL cannot be determined, NULL_TREE is returned.
361
static
tree
362
find_base_decl
(tree t)
in alias.c
363
{
364
tree d0, d1, d2;
365
366
if (t == 0 || t == error_mark_node || ! POINTER_TYPE_P (TREE_TYPE (t)))
367
return
0;
368
369
/* If this is a declaration, return it.
*/
370
if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
371
return
t;
372
373
/* Handle general expressions. It would be
nice to deal with
374
COMPONENT_REFs here. If we could tell that
`a' and `b' were the
375
same, then `a->f' and `b->f' are also
the same.
*/
376
switch
(TREE_CODE_CLASS (TREE_CODE (t)))
377
{
378
case
'1':
379
return
find_base_decl (TREE_OPERAND (t,
0));
380
381
case
'2':
382
/*
Return 0 if found in neither or both are the same.
*/
383
d0 = find_base_decl (TREE_OPERAND (t, 0));
384
d1 = find_base_decl (TREE_OPERAND (t, 1));
385
if (d0 == d1)
386
return
d0;
387
else if (d0 == 0)
388
return
d1;
389
else if (d1 == 0)
390
return
d0;
391
else
392
return
0;
393
394
case
'3':
395
d0 = find_base_decl (TREE_OPERAND (t, 0));
396
d1 = find_base_decl (TREE_OPERAND (t, 1));
397
d2 = find_base_decl (TREE_OPERAND (t, 2));
398
399
/* Set any nonzero values from the last, then
from the first.
*/
400
if (d1 == 0) d1 = d2;
401
if (d0 == 0) d0 = d1;
402
if (d1 == 0) d1 = d0;
403
if (d2 == 0) d2 = d1;
404
405
/* At this point all are nonzero or all are
zero. If all three are the
406
same, return it. Otherwise, return
zero.
*/
407
return
(d0 == d1 && d1 == d2) ?
d0 : 0;
408
409
default
:
410
return
0;
411
}
412
}
If we find the based DECL, back get_alias_set
at line 498, if DECL_POINTER_ALIAS_SET
doesn’t set with -1, DECL_POINTER_ALIAS_SET_KNOWN_P is true (-1 means the alias
set for the declaration has not been yet computed). Further if DECL_POINTER_ALIAS_SET
returns -2, it indicates that we need to make a unique alias set for this
pointer (it is only applied to case of using GNU extension keyword restrict
to restrict pointer alias, see c_apply_type_quals_to_decl
). It needs some
special treatement.
The restrict
pointer
qualifier can be applied to a data pointer to indicate that, during the scope
of that pointer declaration, all data accessed through it will be accessed only
through that pointer but not through any other pointer. The __restrict__
keyword thus enables the compiler to perform certain optimizations based on the
premise that a given object cannot be changed through another pointer. For
example, declaration “int
f (
int
*
restrict
x,
int
*
restrict
y)” means changing the content of address pointed by
pointer
x
can only via this pointer. So it is safe to compute alias
set as below.
Then at line 503 in
get_alias_set
,
here decl
is the based DECL, it must have type of indirect type (pointer or reference),
so pointed_to_type
holds the type the indirect type refers to. Next get_alias_set
invoked at
line 512 recursively works out the alias set for the type. So at line 518, if pointed_to_type
points to aggregate type, the alias set for this type should have been computed
in the invocation at line 512, uses this alias set for the pointer (computing
alias set for aggregate type is done by record_component_aliases
, we will see it
soon).
While if the pointer is not of aggregate type, it enters block at
line 529 in get_alias_set
,
to be conservative but correct, combines all declarations pointed by pointer of
this type into the same tree of alias set rooted by the pointer type (but note
that the alias set of decl
aliases nothing but it self, since it is
delcared as “restrict”).
Then if it comes at line 549 in get_alias_set
, because either inner is not INDIRECT_REF
or its alias set is unknown. For the case, we get the alias set from its type.
Node of WITH_RECORD_EXPR and PLACEHOLDER_EXPR are used in languages
that have types where some field in an object of the type contains a value that
is used in the computation of another field's offset or size and/or the size of
the type. The positions and/or sizes of fields can vary from object to object
of the same type or even for one and the same object within its scope. Record
types with discriminants in Ada
or schema types in Pascal are examples of such types. For C++ front-end, we
don’t need worry about these nodes.
get_alias_set (continue)
572
/* Variant qualifiers don't affect the alias
set, so get the main
573
variant. If this is a type with a known
alias set, return it.
*/
574
t = TYPE_MAIN_VARIANT (t);
575
if (TYPE_ALIAS_SET_KNOWN_P (t))
576
return
TYPE_ALIAS_SET (t);
577
578
/* See if the language has special handling
for this type.
*/
579
set = (*lang_hooks
.
get_alias_set
) (t);
580
if (set != -1)
581
return
set;
582
583
/* There are no objects of FUNCTION_TYPE, so
there's no point in
584
using up an alias set for them. (There are,
of course, pointers
585
and references to functions, but that's
different.)
*/
586
else if (TREE_CODE (t) == FUNCTION_TYPE)
587
set = 0;
588
589
/* Unless the language specifies otherwise,
let vector types alias
590
their components. This avoids some nasty
type punning issues in
591
normal usage. And indeed lets vectors be
treated more like an
592
array slice.
*/
593
else if (TREE_CODE (t) == VECTOR_TYPE)
594
set = get_alias_set (TREE_TYPE (t));
595
596
else
597
/* Otherwise make a new alias set for this
type.
*/
598
set = new_alias_set
();
599
600
TYPE_ALIAS_SET (t) = set;
601
602
/* If this is an aggregate type, we must
record any component aliasing
603
information.
*/
604
if (AGGREGATE_TYPE_P (t) || TREE_CODE (t) == COMPLEX_TYPE)
605
record_component_aliases
(t);
606
607
return
set;
608
}
First, it sees if there is any suggestion from the language. Hook get_alias_set
refers to cxx_get_alias_set
below for C++.
Recall that for non-POD class, CLASSTYPE_AS_BASE is an RECORD_TYPE
node with virtual bases stripped and its TYPE_CONTEXT refers to the RECORD_TYPE
of the class, so predicate “CLASSTYPE_AS_BASE (TYPE_CONTEXT (t)) == t” is true
if t
is the node of CLASSTYPE_AS_BASE of non-POD class (while for POD class,
CLASSTYPE_AS_BASE is the RECORD_TYPE of the class, so the mentioned predicate
is false).
So condition at line 295 tells that t
is enclosed within a class, and
it is the base part of enclosing class.
292
static
HOST_WIDE_INT
293
cxx_get_alias_set
(tree t)
in cp-lang.c
294
{
295
if (TREE_CODE (t) == RECORD_TYPE
296
&& TYPE_CONTEXT (t)
&& CLASS_TYPE_P (TYPE_CONTEXT (t))
297
&& CLASSTYPE_AS_BASE
(TYPE_CONTEXT (t)) == t)
298
/* The base variant of a type must be in the
same alias set as the
299
complete type.
*/
300
return
get_alias_set
(TYPE_CONTEXT (t));
301
302
if (/* It's not yet safe to use alias sets for
some classes in C++.
*/
303
!ok_to_generate_alias_set_for_type
(t)
304
/*
Nor is it safe to use alias sets for pointers-to-member
305
functions, due to the fact that there
may be more than one
306
RECORD_TYPE type corresponding to the
same pointer-to-member
307
type.
*/
308
|| TYPE_PTRMEMFUNC_P (t))
309
return
0;
310
311
return
c_common_get_alias_set
(t);
312
}
Then for the cases come at line 302, ok_to_generate_alias_set_for_type
checks if the type is safe for aliasing.
First, class having virtual base is unsafe for aliasing. For
example :
class
A { ... };
class
B : public
virtual
A {
... } ;
class
C : public
virtual
A {
... } ;
class
D : public
B, C { ... } ;
Though D derives from B, in D the base B has different layout than
class B even if B is empty class. Remember predicate CLASS_TYPE_P at line 250
is false for CLASSTYPE_AS_BASE of non-POD class.
Similarly, if a class contains a field of another class containing
virtual base, it is unsafe to alias this type (both cases considered as
may-alias).
239
static
bool
240
ok_to_generate_alias_set_for_type
(tree
t)
in cp-lang.c
241
{
242
if (TYPE_PTRMEMFUNC_P (t))
243
return
true;
244
if (AGGREGATE_TYPE_P (t))
245
{
246
if ((TREE_CODE (t) == RECORD_TYPE) || (TREE_CODE (t) == UNION_TYPE))
247
{
248
tree fields;
249
/* Backend-created structs are safe.
*/
250
if (! CLASS_TYPE_P (t))
251
return
true;
252
/* PODs
are safe.
*/
253
if (! CLASSTYPE_NON_POD_P(t))
254
return
true;
255
/*
Classes with virtual baseclasses are not.
*/
256
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
257
return
false;
258
/* Recursively check the base classes.
*/
259
if (TYPE_BINFO (t) != NULL && TYPE_BINFO_BASETYPES (t) != NULL)
260
{
261
int i;
262
for
(i = 0; i < TREE_VEC_LENGTH
(TYPE_BINFO_BASETYPES (t)); i++)
263
{
264
tree binfo = TREE_VEC_ELT
(TYPE_BINFO_BASETYPES (t), i);
265
if
(!ok_to_generate_alias_set_for_type (BINFO_TYPE (binfo)))
266
return
false;
267
}
268
}
269
/* Check all the fields.
*/
270
for
(fields = TYPE_FIELDS (t); fields;
fields = TREE_CHAIN (fields))
271
{
272
if (TREE_CODE (fields) != FIELD_DECL)
273
continue
;
274
if (! ok_to_generate_alias_set_for_type (TREE_TYPE (fields)))
275
return
false;
276
}
277
return
true;
278
}
279
else if (TREE_CODE (t) == ARRAY_TYPE)
280
return
ok_to_generate_alias_set_for_type
(TREE_TYPE (t));
281
else
282
/* This should never happen, we dealt with all
the aggregate
283
types that can appear in C++
above.
*/
284
abort ();
285
}
286
else
287
return
true;
288
}
Further
considering following example:
extern
"C" int
printf(const
char *,...);
class
A {
protected
: int i ;
public
:
void f1 () { printf ("%d/n",
i); }
A () : i (0) {}
};
class
B : public
A {
public
:
void f1 () { printf ("%d/n",
i); }
B () { i = 2 ; }
};
int main () {
void (A::*pf1) () = &A::f1;
B b;
(b.*pf1)();
// output “2”
A a ;
(a.*pf1)() ;
// output “0”
return
0;
}
It prints out “2, 0”, no
doubt pf1
accesses different objects in both times. So be careful in treating alias set
for member pointer. Here such pointer is regarded as may-alias (line 308 in
cxx_get_alias_set
).
Except the treatment of class, C++ front-end shares following
routine with C front-end to handle types also available in C. First for direct
accessing of union member, it aliases to the other members of the union. The
comment of the case says that setting the field via taking address is not
permitted in C standard and it has implementation-defined behave, [6] also
gives an explaination.
-fstrict-aliasing ² Allows the compiler to assume the strictest aliasing rules applicable to the language being compiled. For C (and C ++ ), this activates optimizations based on the type of expressions. In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. For example, an unsigned int can alias an int , but not a void* or a double . A character type may alias any other type. Pay special attention to code like this: union a_union { int i; double d; }; int f() { a_union t; t.d = 3.0; return t.i; } The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with ‘ -fstrict-aliasing ’, type-punning is allowed, provided the memory is accessed through the union type. So, the code above will work as expected. However, this code might not: int f() { a_union t; int* ip; t.d = 3.0; ip = &t.i; return *ip; } Similarly, access by taking the address, casting the resulting pointer and dereferencing the result has undefined behavior, even if the cast uses a union type, e.g.: int f() { double d = 3.0; return ((union a_union *) &d)->i; } The ‘ -fstrict-aliasing ’ option is enabled at levels ‘ -O2 ’, ‘ -O3 ’, ‘ -Os ’. |
generated out of type-punning. And that example can explain well why there may
be undefined behavior. However, GCC give NO
warning if we behave badly as above. Except this case, t
of non-type is kicked off.
2848
HOST_WIDE_INT
2849
c_common_get_alias_set
(tree t)
n c-common.c
2850
{
2851
tree u;
2852
2853
/*
Permit type-punning when accessing a union, provided the access
2854
is
directly through the union. For example, this code does not
2855
permit
taking the address of a union member and then storing
2856
through it. Even the type-punning allowed here is a GCC
2857
extension, albeit a common and useful one; the C standard says
2858
that
such accesses have implementation-defined behavior.
*/
2859
for
(u = t;
2860
TREE_CODE (u) ==
COMPONENT_REF || TREE_CODE (u) == ARRAY_REF;
2861
u = TREE_OPERAND (u,
0))
2862
if (TREE_CODE (u) ==
COMPONENT_REF
2863
&& TREE_CODE
(TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE)
2864
return
0;
2865
2866
/*
That's all the expressions we handle specially.
*/
2867
if (! TYPE_P (t))
2868
return
-1;
2869
2870
/* The C standard
guarantees that any object may be accessed via an
2871
lvalue that has character type.
*/
2872
if (t == char_type_node
2873
|| t == signed_char_type_node
2874
|| t == unsigned_char_type_node)
2875
return
0;
2876
2877
/* If it has the
may_alias attribute, it can alias anything.
*/
2878
if (lookup_attribute
("may_alias", TYPE_ATTRIBUTES (t)))
2879
return
0;
2880
2881
/* The C standard
specifically allows aliasing between signed and
2882
unsigned variants of the same type. We
treat the signed
2883
variant as canonical.
*/
2884
if (TREE_CODE (t) == INTEGER_TYPE &&
TREE_UNSIGNED (t))
2885
{
2886
tree t1 = c_common_signed_type (t);
2887
2888
/* t1 == t can
happen for boolean nodes which are always unsigned.
*/
2889
if (t1 != t)
2890
return
get_alias_set
(t1);
2891
}
2892
else if (POINTER_TYPE_P (t))
2893
{
2894
tree t1;
2895
2896
/* Unfortunately, there is no canonical form
of a pointer type.
2897
I
n particular, if we have `typedef int I', then
`int *', and
2898
`I *' are different types. So, we have to
pick a canonical
2899
representative. We do this below.
2900
2901
Technically, this approach is actually
more conservative that
2902
it needs to be. In particular, `const int
*' and `int *'
2903
should be in different alias sets,
according to the C and C++
2904
standard, since their types are not the
same, and so,
2905
technically, an `int **' and `const int
**' cannot point at
2906
the same thing.
2907
2908
But, the standard is wrong. In particular,
this code is
2909
legal C++:
2910
2911
int *ip;
2912
int **ipp = &ip;
2913
const int* const* cipp = &ipp;
2914
2915
And, it doesn't make sense for that to be
legal unless you
2916
can dereference IPP and CIPP. So, we
ignore cv-qualifiers on
2917
the pointed-to types. This issue has been
reported to the
2918
C++ committee.
*/
2919
t1 = build_type_no_quals (t);
2920
if (t1 != t)
2921
return
get_alias_set
(t1);
2922
}
2923
2924
return
-1;
2925
}
Above at line 2872, there are two case in fact would be covered.
That is declaration like : char c; and char *pc; for the former case, c
can’t alias other and no need create alias set (and consider the case of short
type, it a group of 2 bytes, thus these two bytes can alias short type and must
have alias set within the alias set of short, the front-end must prepare an
alias set for this type as we see in the code), while rear one aliases any
object that can be accessed via a lvalue. But for rear case, every time it
points to specific object, it will get its alias set through block at line 494
in get_alias_set
,
and mayn’t be zero any more (it returns 0 for c style type cast).
At here, it is clear that declarations other than indirect reference
(those pointer type or reference type) will share the alias set of their based
type. For example : “short j , k, l; ”, in this statement, variables
j, k, and l will have the same alias set of type short. However, the alias set
will be ignored as these variables can’t alias each other. Now if we change the
statement as : “short j, k, l, *p;”, now j, k, l and pointer p will share
the alias set of short. So the front-end can know that p may alias to j, k or
l.
Next consider statement “short j, k; char *p;”, j and k share the
same alias set of short, but now p hasn’t alias set because get_alias_set
(more precisely c_common_get_alias_set
) returns 0 for it. For
this statement alone, the front-end won’t alias p to j or k. If we add a
statement : “p = &j;”, in C++, it will trigger implicit
conversion error. Then if we add instead a statement: “p = (char*)&j;”,
alias set of p and j will be checked for intersection by front-end. It will pass
since p has a superset of 0 (keep in mind there is no real superset of 0
created), and generate code for the conversion. However, the alias set of p
always keeps as 0, which means it may-alias to everything can be accessed via
lvalue. This assumption prevents compiler from taking error-prone too
aggressive optimization. But it also a point as further improvement to
discriminate alias set finer.
And at line 2884 above, integer types with difference signed also
shares the same alias set.
Line 2878 mentions an interesting GNU C++ attribution “may_alias”.
[6] gives a detail.
may_alias ² Accesses through pointers to types with this attribute are NOT subject to type based alias analysis, but are instead assumed to be able to alias any other type of objects. In the context of 6.5/7 an lvalue expression dereferencing such a pointer is treated like having a character type. See ‘-fstrict-aliasing’ for more information on aliasing issues. This extension exists to support some vector APIs, in which pointers to one vector type are permitted to alias pointers to a different vector type. Note that an object of a type with this attribute does not have any special semantics. Example of use: typedef short __attribute__ ((__may_alias__ )) short_a; int main (void) { int a = 0x12345678; short_a *b = (short_a *) &a; b[1] = 0; if (a == 0x12345678) abort(); exit(0); } If you replaced short_a with short in the variable declaration, the above program would abort when compiled with ‘-fstrict-aliasing’, which is on by default at ‘-O2’ or above in recent GCC versions. |
generates incorrect
code. However
you can use –Wstrict-aliasing to find out pointer that may break the alias. For
example, here with the option, the compiler gives a warning as : “test2.cpp:4:
warning: dereferencing type-punned pointer will break strict-aliasing rules
”.
Then, if cxx_get_alias_set
returns value other than
-1, either the alias set is found, or the object can alias nothing (i.e, char
type). Otherwise, it needs go ahead. See that at line 598 in get_alias_set
,
the type is assigned with unique alias set and will be shared by declarations
of the type. And for aggregate type or type containing more than 1 component,
the alias set should contain alias sets of its fields. Below function record_omponent_aliases
builds the alias tree in this way. Predicate TYPE_NONALIASED_COMPONENT at line
709 if true, indicates that it is not permitted to take the address of a
component of the type.
697
void
698
record_component_aliases
(tree type)
in alias.c
699
{
700
HOST_WIDE_INT superset = get_alias_set
(type);
701
tree field;
702
703
if (superset == 0)
704
return
;
705
706
switch
(TREE_CODE (type))
707
{
708
case
ARRAY_TYPE:
709
if (! TYPE_NONALIASED_COMPONENT (type))
710
record_alias_subset
(superset, get_alias_set
(TREE_TYPE (type)));
711
break
;
712
713
case
RECORD_TYPE:
714
case
UNION_TYPE:
715
case
QUAL_UNION_TYPE:
716
/* Recursively record aliases for the base
classes, if there are any.
*/
717
if (TYPE_BINFO (type) !=
NULL && TYPE_BINFO_BASETYPES (type) != NULL)
718
{
719
int i;
720
for
(i = 0; i < TREE_VEC_LENGTH
(TYPE_BINFO_BASETYPES (type)); i++)
721
{
722
tree binfo = TREE_VEC_ELT
(TYPE_BINFO_BASETYPES (type), i);
723
record_alias_subset
(superset,
724
get_alias_set
(BINFO_TYPE (binfo)));
725
}
726
}
727
for
(field = TYPE_FIELDS (type); field
!= 0; field = TREE_CHAIN (field))
728
if (TREE_CODE (field)
== FIELD_DECL && ! DECL_NONADDRESSABLE_P (field))
729
record_alias_subset
(superset, get_alias_set
(TREE_TYPE (field)));
730
break
;
731
732
case
COMPLEX_TYPE:
733
record_alias_subset
(superset, get_alias_set
(TREE_TYPE (type)));
734
break
;
735
736
default
:
737
break
;
738
}
739
}
Notice that in the aggregate type, for example, field of type of
short will use alias set of type short, which means it will share this alias
set with other declarations of this type. By this way, if there is a pointer of
short type, the compiler can tell that the pointer may alias to this field and
other declarations, and prevent too heavy optimization.
相关文章推荐
- Studying note of GCC-3.4.6 source (3)
- Studying note of GCC-3.4.6 source (12)
- Studying note of GCC-3.4.6 source (15)
- Studying note of GCC-3.4.6 source (21)
- 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 (25 cont1)
- Studying note of GCC-3.4.6 source (26)
- Studying note of GCC-3.4.6 source (164)
- Studying note of GCC-3.4.6 source (175)
- Studying note of GCC-3.4.6 source (44)
- Studying note of GCC-3.4.6 source (45)
- Studying note of GCC-3.4.6 source (181)
- Studying note of GCC-3.4.6 source (70)
- 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 (129 continue)