https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127758
--- Comment #2 from Richard Biener <rguenth at gcc dot gnu.org> ---
So I think this is because of
callarg(15) = &val0.0+64
callarg(15) = callarg(15) + UNKNOWN
callarg(15) = *callarg(15) + UNKNOWN
CALLUSED(13) = callarg(15)
*callarg(15) = callescape(12)
CALLCLOBBERED(14) = callarg(15)
callescape(12) = callarg(15)
ESCAPED = &val0.0+64
callescape(37) = NONLOCAL
CALLUSED(38) = callescape(37)
in the end all common bits in
val0.0+64 = { ESCAPED NONLOCAL val0.0+64 val0.64+64 val0.128+64 val0.192+64
val0.256+64 val0.320+64 val0.384+64 val0.448+64 val0.512+64 val0.576+64
val0.640+64 val0.704+64 val0.768+64 val0.832+64 val0.896+64 val0.960+64
val0.1024+64 val0.1088+64 val0.1152+64 val0.1216+64 _ZN2S3D1Ev __dso_handle
val1.0+64 val1.64+64 val1.128+64 val1.192+64 val1.256+64 val1.320+64
val1.384+64 val1.448+64 val1.512+64 val1.576+64 val1.640+64 val1.704+64
val1.768+64 val1.832+64 val1.896+64 val1.960+64 val1.1024+64 val1.1088+64
val1.1152+64 val1.1216+64 }
with
ESCAPED = { NULL ESCAPED NONLOCAL val0.0+64 val0.64+64 val0.128+64 val0.192+64
val0.256+64 val0.320+64 val0.384+64 val0.448+64 val0.512+64 val0.576+64
val0.640+64 val0.704+64 val0.768+64 val0.832+64 val0.896+64 val0.960+64
val0.1024+64 val0.1088+64 val0.1152+64 val0.1216+64 _ZN2S3D1Ev __dso_handle
val1.0+64 val1.64+64 val1.128+64 val1.192+64 val1.256+64 val1.320+64
val1.384+64 val1.448+64 val1.512+64 val1.576+64 val1.640+64 val1.704+64
val1.768+64 val1.832+64 val1.896+64 val1.960+64 val1.1024+64 val1.1088+64
val1.1152+64 val1.1216+64 }
are redundant.
The interesting bit is that when 'x' is elided from the testcase we get
the graph solving in an order that avoids this. Relevant static-init-ctor
contstraints are
x.0+32 = NONLOCAL
x.64+64 = NONLOCAL
x.0+32 = &NULL
ESCAPED = &NULL
for
x.i = 0;
A reduced C testcase would be the following. Initializing 'i' instad of 'x.i'
resolves it.
struct S1 { int *_M1; int *_M2; int *_M3; };
struct S1 val0;
struct X { int i; long x; };
struct X x;
int i;
void foo (struct S1 *);
void bar()
{
x.i = 0;
foo (&val0);
}
and the relevant difference is possibly
+Unifying NONLOCAL to x.64+64
the order difference of solve_graph processing is
-callarg(14) = { ESCAPED NONLOCAL val0.0+64 val0.64+64 val0.128+64 }
-NONLOCAL = { ESCAPED NONLOCAL }
-callescape(11) = { ESCAPED NONLOCAL val0.0+64 val0.64+64 val0.128+64 }
-i = { NULL ESCAPED NONLOCAL }
-val0.128+64 = { ESCAPED NONLOCAL }
-val0.64+64 = { ESCAPED NONLOCAL }
-val0.0+64 = { ESCAPED NONLOCAL }
+callarg(15) = { val0.0+64 val0.64+64 val0.128+64 }
+x.64+64 = { ESCAPED NONLOCAL }
+callescape(12) = { ESCAPED NONLOCAL val0.0+64 val0.64+64 val0.128+64 }
+x.0+32 = { NULL ESCAPED NONLOCAL }
+val0.128+64 = { ESCAPED NONLOCAL val0.0+64 val0.64+64 val0.128+64 }
+val0.64+64 = { ESCAPED NONLOCAL val0.0+64 val0.64+64 val0.128+64 }
+val0.0+64 = { ESCAPED NONLOCAL val0.0+64 val0.64+64 val0.128+64 }
+PTA iteration 2
+callarg(15) = { ESCAPED NONLOCAL val0.0+64 val0.64+64 val0.128+64 }
where the issue is that we unite a regular var with a special one
and depending on the order of constraints ... (find_equivalent_node).
I have a mitigation patch that possibly leaves some graph optimization
on the plate.
diff --git a/gcc/pta-andersen.cc b/gcc/pta-andersen.cc
index bba34b3c9a0..e1db17e298b 100644
--- a/gcc/pta-andersen.cc
+++ b/gcc/pta-andersen.cc
@@ -149,7 +149,11 @@ static bool
unite (unsigned int to, unsigned int from)
{
gcc_checking_assert (to < graph->size && from < graph->size);
- if (to != from && graph->rep[from] != to)
+ if (to != from
+ && graph->rep[from] != to
+ /* Do not merge an artificial variable into another, this will
+ explode solution sets unnecessarily. */
+ && !get_varinfo (from)->is_artificial_var)
{
graph->rep[from] = to;
return true;
Another mitigation would be to somehow make find_equivalent_node prefer
the smallest variable info ID as leader, but I'm not sure if we can
simply alter graph->pe_rep after the fact.