[tree-ssa] Speedup alias analysis [patch]
Diego Novillo
dnovillo@redhat.com
Tue Jun 24 22:41:00 GMT 2003
On Tue, 2003-06-24 at 10:30, Andrew MacLeod wrote:
> On Tue, 2003-06-24 at 09:43, Diego Novillo wrote:
> > Right, and that's exactly what we do. We only emit a copy when the
> > variables on either side of the VDEF end up in different partitions.
> >
>
> HOw do you know which VDEFs are significant? because there is no real
> def of them?
>
Again: those that have their LHS and RHS in different partitions :)
The rationale is that given a VDEF of the form 'a_3 = VDEF <a_2>', if
a_3 and a_2 coalesce to different partitions, then we need to transfer
the value from a_2's partition to initialize a_3's partition.
This copy operation is apparently very rarely needed. In the collection
of .i and .ii files I've got from GCC we do not generate a single
instance of this. I've only seen it emitted in
gcc.c-torture/execute/980701-1.c.
It also triggers zero times in the POOMA testcases I've got. Not
particularly encouraging :/ And I still haven't been able to find out
either a proof of correctness nor a counter-example that shows that the
transformation is wrong. Sigh.
> So what does GLOBAL_VARs have to do with mixing virtual and non-virtual
> operands? Its going to produce mixes like this which you are
> demonstrating?
>
No, the problem with .GLOBAL_VAR is that it is forcefully added to the
may-alias set of every call-clobbered variable. So:
{
foo (&a, &b);
a = 3;
b = 2;
return a + b;
}
will add .GLOBAL_VAR to the may-alias list of 'a' and 'b', producing
{
a.1 = &a;
b.1 = &b;
# .GLOBAL_VAR_2 = VDEF <.GLOBAL_VAR_1>
foo (a.1, b.1);
# .GLOBAL_VAR_3 = VDEF <.GLOBAL_VAR_2>
a = 3;
# .GLOBAL_VAR_4 = VDEF <.GLOBAL_VAR_3>
b = 2;
# VUSE <.GLOBAL_VAR_4>
# VUSE <.GLOBAL_VAR_4>
return a + b;
}
Instead of the more reasonable:
{
a.1 = &a;
b.1 = &b;
# a_2 = VDEF <a_1>
# b_4 = VDEF <b_3>
foo (a.1, b.1);
a_5 = 3;
b_8 = 2;
return 5;
}
So, the trick is to handle .GLOBAL_VAR the other way around. We add 'a'
and 'b' to the list of .GLOBAL_VAR's may-aliases. The definition points
of .GLOBAL_VAR are function calls. At every function call, we generate
one VDEF operation for each call-clobbered variable. Meaning that we
shouldn't see references to .GLOBAL_VAR in most cases (which is good).
However, .GLOBAL_VAR is needed for the grouping heuristics. If there
are thousands of call-clobbered variables in a function, each function
call will generate thousands of VDEFs. So, when the may-alias set for
.GLOBAL_VAR grows too large, we need to revert to the current behaviour
and just put up with the loss of precision.
>
>
> > The only unaliased virtual ops are non-scalar data references. Or you
> > mean a must-alias pass? In the first case we need a scalarizer of some
> > kind. In the second one, we'd prove that 'p' always points to 'a' and
> > replace every reference to '*p' with 'a' directly.
> >
>
> The stuff we talked about in ottawa which allows promotion of a VDEF'd
> variable to a real one when all its VUSES can be real uses. This allowed
> effective live-range splitting of variables into aliasined and
> non-aliased parts. Or something to that effect.
>
Yes, that's when you can prove a must-alias relation in some section of
code:
if (i_3 > j_2)
{
p_5 = &a;
b_8 = 9;
*p_5 = b_8 + 3;
}
else
{
p_6 = &j;
*p_6 = b_1 - 10;
}
# p_7 = PHI <p_5, p_6>
< ... other de-references of p_7 ... >
You have 'p_5 must alias a' inside the THEN clause, and 'p_6 must alias
j' inside the ELSE clause. As Jeff pointed out, we need to figure out
the SSA numbering in this case. I seem to remember a paper that used
SSA information to do something along these lines.
> SO, a couple of things.
> First, why isnt the first one
>
> p_3 = &a_2 ?
>
ADDR_EXPR is a funny operator. If you expose it in the IL you may run
into aliasing problems and the optimizers will likely mess things up.
Two examples:
{
a_1 = 0;
p_2 = &a_1;
return *p_2;
}
CCP will convert the above into:
{
a_1 = 3;
p_2 = &0;
return *p_2;
}
At runtime, the program will SEGV. The second one involves copy
propagation:
{
a_2 = b_1;
p_3 = &a_2;
# a_4 = VDEF <a_2>
*p_3 = 5;
return a_4;
}
Copy propagation will turn this into:
{
a_2 = b_1;
p_3 = &b_1;
# a_4 = VDEF <a_2>
*p_3 = 5;
return a_4;
}
At runtime, the program will never update 'a'.
> I thought we were going to expose that into the IL... otherwise
> rewriting it is a pain because I have to delve into the stmt to find the
> variable to rewrite if a_2 didn't get coalesced with the storage for
> 'a'.
>
If we were to expose it into the IL we would have to teach the
optimizers to treat it with care. I'm not sure I want that. This topic
comes up every now and then. We still haven't found a more gracious way
of dealing with ADDR_EXPRs, unfortunately.
Diego.
More information about the Gcc-patches
mailing list