This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Help understanding gcc alias analysis


On Sat, Jan 10, 2009 at 12:19 PM, Raoul Gough <RaoulGough@clara.co.uk> wrote:
> I've been investigating a code-reordering question to do with g++ strict
> alias analysis, and I suspect there is a deficiency in the way type-based
> alias analysis works. I realise that's unlikely to be the case, so I'll try
> to present a concise demonstration which uses (I think) well-defined C code.
> The original problem (now long worked around) was in a much larger C++
> codebase and did result in a harmful reordering of code (although, that was
> with g++ 3.4.3). Output below is from 4.3.2
>
> Take these two example functions:
>
> extern int foo(int* p1, char* p2)
> {
>   int result = *p1;
>   *p2 = 4;
>   return result;
> }
>
> extern int bar(int* p1, double* p2)
> {
>   int result = *p1;
>   *p2 = 4;
>   return result;
> }
>
> Both of these read via one pointer, assign via another and return the first
> value. Obviously, if the two pointers alias the same storage and the
> compiler reorders the read and the write, the wrong value will result. In
> the first case, it's obvious that p2 may alias p1, since it has type char*.
> Indeed, -fdump-tree-salias from g++ 4.3.2, shows the following:
>
>
> Alias information for int foo(int*, char*)
> [...]
> Symbol memory tags
>
> SMT.4, UID D.1674, int, is addressable, is global, score: 960006, direct
> reads: 0, direct writes: 0, indirect reads: 1, indirect writes: 1, call
> clobbered (is global var, is incoming pointer), may aliases: { SMT.5 }
> SMT.5, UID D.1675, char, is addressable, is global, score: 960006, direct
> reads: 0, direct writes: 0, indirect reads: 1, indirect writes: 1, call
> clobbered (is global var, is incoming pointer), may aliases: { SMT.4 }
> [...]
>
>
> I guess this means the compiler knows that the int* and char* "may alias"
> the same storage. Now for the second function, type based alias analysis
> tells us that p1 and p2 cannot alias each other, because an int and a double
> can't simultaneously occupy the same storage. So -fdump-tree-salias shows
> the following:
>
>
> Alias information for int bar(int*, double*)
> [...]
> Symbol memory tags
>
> SMT.18, UID D.1688, int, is addressable, is global, score: 320002, direct
> reads: 0, direct writes: 0, indirect reads: 1, indirect writes: 0, call
> clobbered (is global var, is incoming pointer)
> SMT.19, UID D.1689, double, is addressable, is global, score: 640004, direct
> reads: 0, direct writes: 0, indirect reads: 0, indirect writes: 1, call
> clobbered (is global var, is incoming pointer)
> [...]
>
>
> This doesn't show any "may aliases" lists, so I assume this means the
> compiler thinks it can reorder accesses via the pointers. I've included the
> full salias output below, in case I'm missing something. So here's a
> problematic example (which was first pointed out to me by James Kanze on
> comp.std.c++):
>
> union A
> {
>   int i_;
>   double d_;
> };
>
> void bar_bad()
> {
>   A a;
>   a.i_ = 3;
>   assert(bar(&a.i_, &a.d_) == 3);
> }
>
> Here we pass into bar a pointer to int and double at the same storage
> location. So now, if the compiler goes ahead and reorders the read and write
> in function bar, the assertion would fail. Note that this code does *not*
> write one type into a union and read another. It writes an int, reads an int
> and then writes a double. All that's happening is that the storage is being
> *reused* for a different type. However, this re-use takes place within
> function bar, which doesn't necessarily know about the union (especially if
> it's in a different compilation unit).
>
> So, my question is, does the salias analysis indicate that the compiler
> thinks it can reorder the operations in function bar?

There is a defect report about this and I'm sure numerous bugreports
in bugzilla.
The conclusion is that the above invokes undefined behavior because the
accesses are not done through a union type, so the static memory typing rules
of C apply.

Richard.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]