Go to main content
Oracle® Developer Studio 12.5: C User's Guide

Exit Print View

Updated: June 2017
 
 

6.4 Examples of Memory Reference Constraints

This section provides examples of code that are likely to appear in your source files. Each example is followed by a discussion of the compiler’s assumptions about the code as dictated by the applied level of type-based analysis.

6.4.1 Example: Levels of Aliasing

Consider the following code. It can be compiled with different levels of aliasing to demonstrate the aliasing relationship of the shown types.

struct foo {
    int f1;
    short f2;
    short f3;
    int f4;
} *fp;

struct bar {
    int b1;
    int b2;
    int b3;
} *bp;

int *ip;
short *sp;

If this example is compiled with the -xalias_level=any option, the compiler considers the following indirect accesses as aliases to each other:

*ip, *sp, *fp, *bp, fp->f1, fp->f2, fp->f3, fp->f4, bp->b1, bp->b2, bp->b3

If this example is compiled with the -xalias_level=basic option, the compiler considers the following indirect accesses as aliases to each other:

*ip, *bp, fp->f1, fp->f4, bp->b1, bp->b2, bp->b3

Additionally, *sp, fp->f2, and fp->f3 can alias each other, and *sp and *fp can alias each other.

However, under -xalias_level=basic, the compiler assumes the following:

  • *ip does not alias *sp.

  • *ip does not alias fp->f2 and fp->f3.

  • *sp does not alias fp->f1, fp->f4, bp->b1, bp->b2, and bp->b3.

The compiler makes these assumptions because the access types of the two indirect accesses are different basic types.

If this example is compiled with the -xalias_level=weak option, the compiler assumes the following alias information:

  • *ip can alias *fp, fp->f1, fp->f4, *bp, bp->b1, bp->b2, and bp->b3.

  • *sp can alias *fp, fp->f2 and fp->f3.

  • fp->f1 can alias bp->b1.

  • fp->f4 can alias bp->b3.

The compiler assumes that fp->fp1 does not alias bp->b2 because f1 is a field with offset 0 in a structure, whereas b2 is a field with a 4-byte offset in a structure. Similarly, the compiler assumes that fp->f1 does not alias bp->b3, and fp->f4 does not alias either bp->b1 or bp->b2.

If this example is compiled with the -xalias_level=layout option, the compiler assumes the following information:

  • *ip can alias *fp, *bp, fp->f1, fp->f4, bp->b1, bp->b2, and bp->b3.

  • *sp can alias *fp, fp->f2, and fp->f3.

  • fp->f1 can alias bp->b1 and *bp.

  • *fp and *bp can alias each other.

fp->f4 does not alias bp->b3 because f4 and b3 are not corresponding fields in the common initial sequence of foo and bar.

If this example is compiled with the -xalias_level=strict option, the compiler assumes the following alias information:

  • *ip can alias *fp, fp->f1, fp->f4, *bp, bp->b1, bp->b2, and bp->b3.

  • *sp can alias *fp, fp->f2, and fp->f3.

With -xalias_level=strict, the compiler assumes that *fp, *bp, fp->f1, fp->f2, fp->f3, fp->f4, bp->b1, bp->b2, and bp->b3 do not alias each other because foo and bar are not the same when field names are ignored. However, fp aliases fp->f1 and bp aliases bp->b1.

If this example is compiled with the -xalias_level=std option, the compiler assumes the following alias information:

  • *ip can alias *fp, fp->f1, fp->f4, *bp, bp->b1, bp->b2, and bp->b3.

  • *sp can alias *fp, fp->f2, and fp->f3.

However, fp->f1 does not alias bp->b1, bp->b2, or bp->b3 because foo and bar are not the same when field names are considered.

If this example is compiled with the -xalias_level=strong option, the compiler assumes the following alias information:

  • *ip does not alias fp->f1, fp->f4, bp->b1, bp->b2, and bp->b3 because a pointer, such as *ip, should not point to the interior of a structure.

  • Similarly, *sp does not alias fp->f1 or fp->f3.

  • *ip does not alias *fp, *bp, and *sp due to differing types.

  • *sp does not alias *fp, *bp, and *ip due to differing types.

6.4.2 Example: Compiling with Different Aliasing Levels

Consider the following example source code. It demonstrates the aliasing relationship of the shown types when compiled with different levels of aliasing.

struct foo {
    int f1;
    int f2;
    int f3;
} *fp;

struct bar {
    int b1;
    int b2;
    int b3;
} *bp;

If this example is compiled with the -xalias_level=any option, the compiler assumes the following alias information:

*fp, *bp, fp->f1, fp->f2, fp->f3, bp->b1, bp->b2 and bp->b3 all can alias each other because any two memory accesses alias each other at the level of -xalias_level=any.

If this example is compiled with the -xalias_level=basic option, the compiler assumes the following alias information:

*fp, *bp, fp->f1, fp->f2, fp->f3, bp->b1, bp->b2 and bp->b3 all can alias each other. Any two field accesses using pointers *fp and *bp can alias each other in this example because all the structure fields are the same basic type.

If this example is compiled with the -xalias_level=weak option, the compiler assumes the following alias information:

  • *fp and *fp can alias each other.

  • fp->f1 can alias bp->b1, *bp and *fp.

  • fp->f2 can alias bp->b2, *bp and *fp.

  • fp->f3 can alias bp->b3, *bp and *fp.

However, -xalias_level=weak imposes the following restrictions:

  • fp->f1 does not alias bp->b2 or bp->b3 because f1 has an offset of zero, which is different from that of b2 (four bytes) and b3 (eight bytes).

  • fp->f2 does not alias bp->b1 or bp->b3 because f2 has an offset of four bytes, which is different from b1 (zero bytes) and b3 (eight bytes).

  • fp->f3 does not alias bp->b1 or bp->b2 because f3 has an offset of eight bytes, which is different from b1 (zero bytes) and b2 (four bytes).

If this example is compiled with the -xalias_level=layout options, the compiler assumes the following alias information:

  • *fp and *bp can alias each other.

  • fp->f1 can alias bp->b1, *bp, and *fp.

  • fp->f2 can alias bp->b2, *bp, and *fp.

  • fp->f3 can alias bp->b3, *bp, and *fp.

However, -xalias_level=layout imposes the following restrictions:

  • fp->f1 does not alias bp->b2 or bp->b3 because field f1 corresponds to field b1 in the common initial sequence of foo and bar.

  • fp->f2 does not alias bp->b1 or bp->b3 because f2 corresponds to field b2 in the common initial sequence of foo and bar.

  • fp->f3 does not alias bp->b1 or bp->b2 because f3 corresponds to field b3 in the common initial sequence of foo and bar.

If this example is compiled with the -xalias_level=strict option, the compiler assumes the following alias information:

  • *fp and *bp can alias each other.

  • fp->f1 can alias bp->b1, *bp, and *fp.

  • fp->f2 can alias bp->b2, *bp, and *fp.

  • fp->f3 can alias bp->b3, *bp, and *fp.

However, -xalias_level=strict imposes the following restrictions:

  • fp->f1 does not alias bp->b2 or bp->b3 because field f1 corresponds to field b1 in the common initial sequence of foo and bar.

  • fp->f2 does not alias bp->b1 or bp->b3 because f2 corresponds to field b2 in the common initial sequence of foo and bar.

  • fp->f3 does not alias bp->b1 or bp->b2 because f3 corresponds to field b3 in the common initial sequence of foo and bar.

If this example is compiled with the -xalias_level=std option, the compiler assumes the following alias information:

fp->f1, fp->f2, fp->f3, bp->b1, bp->b2, and bp->b3 do not alias each other.

If this example is compiled with the -xalias_level=strong option, the compiler assumes the following alias information:

fp->f1, fp->f2, fp->f3, bp->b1, bp->b2, and bp->b3 do not alias each other.

6.4.3 Example: Interior Pointers

Consider the following example source code that demonstrates that certain levels of aliasing cannot handle interior pointers. For a definition of interior pointers see Table 49.

struct foo {
        int f1;
        struct bar *f2;
        struct bar *f3;
        int f4;
        int f5;
        struct bar fb[10];
} *fp;

struct bar
        struct bar *b2;
        struct bar *b3;
        int b4;
} *bp;

bp=(struct bar*)(&fp->f2);

The dereference in this example is not supported by weak, layout, strict, or std. After the pointer assignment bp=(struct bar*)(&fp->f2), the following pair of memory accesses touches the same memory locations:

  • fp->f2 and bp->b2 access the same memory location

  • fp->f3 and bp->b3 access the same memory location

  • fp->f4 and bp->b4 access the same memory location

However, with the options weak, layout, strict, and std, the compiler assumes that fp->f2 and bp->b2 do not alias. The compiler makes this assumption because b2 has an offset of zero, which is different from the offset of f2 (four bytes), and foo and bar do not have a common initial sequence. Similarly, the compiler also assumes that bp->b3 does not alias fp->f3, and bp->b4 does not alias fp->f4.

Thus, the pointer assignment bp=(struct bar*)(&fp->f2)creates a situation in which the compiler’s assumptions about alias information are incorrect. This situation could lead to incorrect optimization.

Try compiling after you make the modifications shown in the following example.

struct foo {
        int f1;
        struct bar fb;   /* Modified line */
#define f2 fb.b2         /* Modified line */
#define f3 fb.b3         /* Modified line */
#define f4 fb.b4         /* Modified line */
        int f5;
        struct bar fb[10];
} *fp;

struct bar
        struct bar *b2;
        struct bar *b3;
        int b4;
} *bp;

bp=(struct bar*)(&fp->f2);

After the pointer assignment bp=(struct bar*)(&fp->f2), the following pair of memory accesses touches the same memory locations:

  • fp->f2 and bp->b2

  • fp->f3 and bp->b3

  • fp->f4 and bp->b4

The changes shown in this code example illustrate that the expression fp->f2 is another form of the expression fp->fb.b2. Because fp->fb is of type bar, fp->f2 accesses the b2 field of bar. Furthermore, bp->b2 also accesses the b2 field of bar. Therefore, the compiler assumes that fp->f2 aliases bp->b2. Similarly, the compiler assumes that fp->f3 aliases bp->b3, and fp->f4 aliases bp->b4. As a result, the aliasing assumed by the compiler matches the actual aliases caused by the pointer assignment.

6.4.4 Example: Struct Fields

Consider the following example source code.

struct foo {
        int f1;
        int f2;
} *fp;

struct bar {
        int b1;
        int b2;
} *bp;

struct cat {
        int c1;
        struct foo cf;
        int c2;
        int c3;
} *cp;

struct dog {
        int d1;
        int d2;
        struct bar db;
        int d3;
} *dp;

If this example is compiled with the -xalias_level=weak option, the compiler assumes the following alias information:

  • fp->f1 can alias bp->b1, cp->c1, dp->d1, cp->cf.f1, and df->db.b1.

  • fp->f2 can alias bp->b2, cp->cf.f1, dp->d2, cp->cf.f2, df->db.b2, cp->c2.

  • bp->b1 can alias fp->f1, cp->c1, dp->d1, cp->cf.f1, and df->db.b1.

  • bp->b2 can alias fp->f2, cp->cf.f1, dp->d2, cp->cf.f1, and df->db.b2.

fp->f2 can alias cp->c2 because *dp can alias *cp and *fp can alias dp->db.

  • cp->c1 can alias fp->f1, bp->b1, dp->d1, and dp->db.b1.

  • cp->cf.f1 can alias fp->f1, fp->f2, bp->b1, bp->b2, dp->d2, and dp->d1.

cp->cf.f1 does not alias dp->db.b1.

  • cp->cf.f2 can alias fp->f2, bp->b2, dp->db.b1, and dp->d2.

  • cp->c2 can alias dp->db.b2.

cp->c2 does not alias dp->db.b1 and cp->c2 does not alias dp->d3.

With respect to offsets, cp->c2 can alias db->db.b1 only if *dp aliases cp->cf. However, if *dp aliases cp->cf, then dp->db.b1 must alias beyond the end of foo cf, which is prohibited by object restrictions. Therefore, the compiler assumes that cp->c2 cannot alias db->db.b1.

cp->c3 can alias dp->d3.

Notice that cp->c3 does not alias dp->db.b2. These memory references do not alias because the offsets of the fields of the types involved in the dereferences differ and do not overlap. Based on this, the compiler assumes they cannot alias.

  • dp->d1 can alias fp->f1, bp->b1, and cp->c1.

  • dp->d2 can alias fp->f2, bp->b2, and cp->cf.f1.

  • dp->db.b1 can alias fp->f1, bp->b1, and cp->c1.

  • dp->db.b2 can alias fp->f2, bp->b2, cp->c2, and cp->cf.f1.

  • dp->d3 can alias cp->c3.

Notice that dp->d3 does not alias cp->cf.f2. These memory references do not alias because the offsets of the fields of the types involved in the dereferences differ and do not overlap. Based on this analysis, the compiler assumes they cannot alias.

If this example is compiled with the -xalias_level=layout option, the compiler assumes only the following alias information:

  • fp->f1, bp->b1, cp->c1 and dp->d1 all can alias each other.

  • fp->f2, bp->b2 and dp->d2 all can alias each other.

  • fp->f1 can alias cp->cf.f1 and dp->db.b1.

  • bp->b1 can alias cp->cf.f1 and dp->db.b1.

  • fp->f2 can alias cp->cf.f2 and dp->db.b2.

  • bp->b2 can alias cp->cf.f2 and dp->db.b2.

If this example is compiled with the -xalias_level=strict option, the compiler assumes only the following alias information:

  • fp->f1 and bp->b1 can alias each other.

  • fp->f2 and bp->b2 can alias each other.

  • fp->f1 can alias cp->cf.f1 and dp->db.b1.

  • bp->b1 can alias cp->cf.f1 and dp->db.b1.

  • fp->f2 can alias cp->cf.f2 and dp->db.b2.

  • bp->b2 can alias cp->cf.f2 and dp->db.b2.

If this example is compiled with the -xalias_level=std option, the compiler assumes only the following alias information:

  • fp->f1 can alias cp->cf.f1.

  • bp->b1 can alias dp->db.b1.

  • fp->f2 can alias cp->cf.f2.

  • bp->b2 can alias dp->db.b2.

6.4.5 Example: Unions

Consider the following example source code.

struct foo {
        short f1;
        short f2;
        int   f3;
} *fp;

struct bar {
        int b1;
        int b2;
} *bp;

union moo {
        struct foo u_f;
        struct bar u_b;
} u;

The compiler’s assumptions based on various alias levels are the following:

  • If this example is compiled with the -xalias_level=weak option, fp->f3 and bp->b2 can alias each other.

  • If this example is compiled with the -xalias_level=layout option, no fields can alias each other.

  • If this example is compiled with the -xalias_level=strict option, fp->f3 and bp->b2 can alias each other.

  • If this example is compiled with the -xalias_level=std option, no fields can alias each other.

6.4.6 Example: Structs of Structs

Consider the following example source code.

struct bar;

struct foo {
        struct foo *ffp;
        struct bar *fbp;
} *fp;

struct bar {
        struct bar *bbp;
        long        b2;
} *bp;

The compiler’s assumptions based on various alias levels are the following:

  • If this example is compiled with the -xalias_level=weak option, only fp->ffp and bp->bbp can alias each other.

  • If this example is compiled with the -xalias_level=layout option, only fp->ffp and bp->bbp can alias each other.

  • If this example is compiled with the -xalias_level=strict option, no fields can alias because the two struct types are still different even after their tags are removed.

  • If this example is compiled with the -xalias_level=std option, no fields can alias because the two types and the tags are not the same.

6.4.7 Example: Using a Pragma

Consider the following example source code:

struct foo;
struct bar;
#pragma alias (struct foo, struct bar)

struct foo {
        int f1;
        int f2;
} *fp;

struct bar {
        short b1;
        short b2;
        int   b3;
} *bp;

The pragma in this example tells the compiler that foo and bar are allowed to alias each other. The compiler makes the following assumptions about alias information:

  • fp->f1 can alias with bp->b1, bp->b2, and bp->b3

  • fp->f2 can alias with bp->b1, bp->b2, and bp->b3