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.

Reply via email to