This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Help understanding gcc alias analysis
Richard Guenther wrote:
On Sun, Jan 11, 2009 at 7:59 PM, Raoul Gough <RaoulGough@yahoo.co.uk> wrote:
[snip]
I guess the situation is more complicated in C++, which has explicit
destructors. Consider the following example, which is getting closer to the
problem that originally got me interested in this subject:
void** global_free_list = 0;
inline void operator delete(void* p2) throw()
{
// Save "next" pointer in re-used client storage. TODO - check for NULL
*static_cast<void **>(p2) = global_free_list;
global_free_list = static_cast<void **>(p2);
}
double foo(double* p1)
{
double result = *p1;
delete p1;
return result;
}
Now, after inlining, this example looks very similar to my original one,
except we have pointers of type double* and void** sharing the same storage
space instead of int* and double*. Note - we can easily ensure that the
corresponding operator new() always allocates storage suitably sized and
aligned for a void*.
This is also invalid. You have to use placement new to change the dynamic
type of memory.
Yes, I guess that makes sense. I've modified the example like this:
#include <new>
void** global_free_list = 0;
inline void operator delete(void* p2) throw()
{
// Save "next" pointer in re-used client storage
new (p2) (void *) (global_free_list);
global_free_list = static_cast<void **>(p2);
}
double foo(double* p1)
{
double result = *p1;
delete p1;
return result;
}
I've included the complete alias debug output below. This now includes
global_free_list in the may-alias lists, which is interesting. Also
there is a NULL-pointer check and branch, but I assume another
optimization phases could, under some circumstances, remove this. For
example, if foo() started with assert(p1) then this NULL pointer check
would be redundant. That would leave it with more or less the same code
tree as before, aside from the differences in the aliasing information.
So how is this example looking now? Does the alias analysis mean that
g++ will never reorder the read and write via p1 and p2?
--
Thanks,
Raoul Gough.
;; Function double foo(double*) (_Z3fooPd)
Points-to analysis
Constraints:
ANYTHING = &ANYTHING
READONLY = &ANYTHING
INTEGER = &ANYTHING
p1 = &ANYTHING
D.1859_5 = p1
D.1860_6 = D.1859_5
iftmp.0_7 = D.1860_6
global_free_list = &ANYTHING
global_free_list.1_8 = global_free_list
*iftmp.0_7 = global_free_list.1_8
p2.2_9 = p1
global_free_list = p2.2_9
Collapsing static cycles and doing variable substitution
Building predecessor graph
Detecting pointer and location equivalences
Rewriting constraints and unifying variables
Uniting pointer but not location equivalent variables
Finding indirect cycles
Solving graph
Points-to sets
NULL = { }
ANYTHING = { ANYTHING }
READONLY = { ANYTHING }
INTEGER = { ANYTHING }
p1 = { ANYTHING } no-tbaa-pruning
D.1859_5 = same as p1
D.1860_6 = same as p1
iftmp.0_7 = same as p1
global_free_list.1_8 = same as p1
global_free_list = same as p1
p2.2_9 = same as p1
Memory partitioning NOT NEEDED for foo
Memory reference statistics for double foo(double*)
Number of memory statements: 4
Number of call sites: 0
Number of pure/const call sites: 0
Number of asm sites: 0
Estimated number of loads: 3 (1/stmt)
Actual number of loads: 3 (1/stmt)
Estimated number of stores: 3 (1/stmt)
Actual number of stores: 3 (1/stmt)
Partitioning thresholds: MAX = 1000 AVG = 3 (NO NEED TO PARTITION)
Number of partitioned symbols: 0
Number of unpartitioned symbols: 5
Alias information for double foo(double*)
Memory partitions
0 memory partitions holding 0 symbols
Flow-insensitive alias information for double foo(double*)
Aliased symbols
SMT.7, UID D.1868, void *, is addressable, is global, score: 556356,
direct reads: 0, direct writes: 0, indirect reads: 0, indirect writes:
1, call clobbered (stored in global, is global var), may aliases: {
global_free_list }
SMT.8, UID D.1869, double, 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), may aliases: {
global_free_list }
NMT.9, UID D.1870, double, is addressable, is global, score: 8, direct
reads: 1, direct writes: 0, indirect reads: 0, indirect writes: 0, call
clobbered (is global var, is incoming pointer), may aliases: {
global_free_list SMT.8 }
NMT.10, UID D.1871, void *, is addressable, is global, score: 16, direct
reads: 0, direct writes: 1, indirect reads: 0, indirect writes: 0, call
clobbered (stored in global, is global var), may aliases: {
global_free_list SMT.7 }
global_free_list, UID D.1817, void * *, is addressable, is global,
score: 1794558, direct reads: 1, direct writes: 1, indirect reads: 1,
indirect writes: 1, call clobbered (stored in global, is global var, is
incoming pointer)
Dereferenced pointers
iftmp.0, UID D.1861, void * *, symbol memory tag: SMT.7
global_free_list.1, UID D.1862, void * *, symbol memory tag: SMT.7
p2.2, UID D.1863, void * *, symbol memory tag: SMT.7
p1, UID D.1842, double *, symbol memory tag: SMT.8, default def: p1_1(D)
Symbol memory tags
SMT.7, UID D.1868, void *, is addressable, is global, score: 556356,
direct reads: 0, direct writes: 0, indirect reads: 0, indirect writes:
1, call clobbered (stored in global, is global var), may aliases: {
global_free_list }
SMT.8, UID D.1869, double, 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), may aliases: {
global_free_list }
Flow-sensitive alias information for double foo(double*)
SSA_NAME pointers
p1_1(D), name memory tag: NMT.9, is dereferenced, its value escapes,
points-to vars: { global_free_list SMT.8 }
iftmp.0_7, name memory tag: NMT.10, is dereferenced, points-to vars: {
global_free_list SMT.7 }
global_free_list.1_8, name memory tag: NMT.10, is dereferenced, its
value escapes, points-to vars: { global_free_list SMT.7 }
p2.2_9, name memory tag: NMT.10, is dereferenced, its value escapes,
points-to vars: { global_free_list SMT.7 }
Name memory tags
NMT.9, UID D.1870, double, is addressable, is global, score: 8, direct
reads: 1, direct writes: 0, indirect reads: 0, indirect writes: 0, call
clobbered (is global var, is incoming pointer), may aliases: {
global_free_list SMT.8 }
NMT.10, UID D.1871, void *, is addressable, is global, score: 16, direct
reads: 0, direct writes: 1, indirect reads: 0, indirect writes: 0, call
clobbered (stored in global, is global var), may aliases: {
global_free_list SMT.7 }
Pointed-to sets for pointers in double foo(double*)
p1_1(D), name memory tag: NMT.9, is dereferenced, its value escapes,
points-to vars: { global_free_list SMT.8 }
D.1859_5, points-to anything
D.1860_6, points-to anything
iftmp.0_7, name memory tag: NMT.10, is dereferenced, points-to vars: {
global_free_list SMT.7 }
global_free_list.1_8, name memory tag: NMT.10, is dereferenced, its
value escapes, points-to vars: { global_free_list SMT.7 }
p2.2_9, name memory tag: NMT.10, is dereferenced, its value escapes,
points-to vars: { global_free_list SMT.7 }
Symbols to be put in SSA form
{ global_free_list SMT.7 SMT.8 NMT.9 NMT.10 }
Incremental SSA update started at block: 0
Number of blocks in CFG: 5
Number of blocks to update: 4 ( 80%)
double foo(double*) (p1)
{
void * D.1860;
void * * iftmp.0;
void * * global_free_list.1;
void * * p2.2;
void * D.1859;
void * D.1859;
double result;
<bb 2>:
result_2 = *p1_1(D);
D.1859_5 = p1_1(D);
D.1860_6 = D.1859_5;
iftmp.0_7 = (void * *) D.1860_6;
if (iftmp.0_7 != 0B)
goto <bb 3>;
else
goto <bb 4>;
<bb 3>:
global_free_list.1_8 = global_free_list;
*iftmp.0_7 = global_free_list.1_8;
<bb 4>:
p2.2_9 = (void * *) p1_1(D);
global_free_list = p2.2_9;
return result_2;
}