您的位置:首页 > 其它

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.

-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
’.

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.

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.

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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: