On Mon 2026-06-22 09:16:05, Richard Biener wrote:
> On Sat, 20 Jun 2026, Filip Kastl wrote:
>
> > Hi richi,
> >
> > I found a case where the function.clobber varinfo gets included in a
> > points-to
> > set. That shouldn't happen right? It causes trouble for my PTA Steensgaard
> > project.
> >
> > Here is a testcase:
> >
> > ---- pr35065-reduced.c ----
> > enum vlc_module_properties { VLC_MODULE_CB_OPEN };
> > char ParseNALBlock_p_frag_0;
> > int vlc_entry__0_9_0f_p_submodule;
> > void Open();
> > void vlc_module_set(int *, enum vlc_module_properties, void *);
> > void vlc_entry__0_9_0f() {
> > vlc_module_set(&vlc_entry__0_9_0f_p_submodule, VLC_MODULE_CB_OPEN, Open);
> > }
> > void ParseNALBlock();
> > void Open() { ParseNALBlock(); }
> > void bs_read_ue();
> > void ParseNALBlock() {
> > if (ParseNALBlock_p_frag_0)
> > bs_read_ue();
> > }
> > ---- ----
> >
> > I compile it with trunk GCC using these flags:
> > gcc -c pr35065-reduced.c -fipa-pta -O2 -march=native -fno-inline
> > -fdump-ipa-pta2-details-alias
> >
> > In the dump you can see this set:
> > callarg(34) = { ESCAPED Open Open.clobber Open.use Open.result }
> >
> > I've stepped through PTA in GDB and found that initially,
> > callarg(34) = { Open }
> > When we process the constraints callarg(34) = callarg(34) + UNKNOWN,
> > pta-andersen.cc:solution_set_expand() happilly expands the Open varinfo into
> > all the subvariables Open.clobber Open.use Open.result.
> >
> > Is this intentional?
> >
> > Open.clobber, Open.use, Open.result all have is_full_var = 1, but Open does
> > not. What's your gut feeling about setting is_full_var = 1 for fninfos? It
> > does help with this testcase but I didn't yet look through the sources to
> > see
> > if it doesn't break something else.
>
> I think this will break indirect call handling. So what we have is
>
> vlc_entry__0_9_0f ()
> {
> vlc_module_set (&vlc_entry__0_9_0f_p_submodule, 0u, &Open);
> }
>
> where 'Open' is internal but vlc_module_set is not. We generate
>
> callarg(34) = &Open
> callarg(34) = callarg(34) + UNKNOWN
> callarg(34) = *callarg(34) + UNKNOWN
> CALLUSED(30) = callarg(34)
> *callarg(34) = callescape(29)
> CALLCLOBBERED(31) = callarg(34)
> callescape(29) = callarg(34)
> ESCAPED = &Open
>
> where this tries to set up things in a way to allow vlc_module_set
> to call 'Open' indirectly, meaning the vlc_module_set call clobbers
> include call clobbers of 'Open' and the 'Open' incoming arguments
> now have to contain the vars escaped to vlc_module_set and of course
> all other ESCAPED vars. If you consider 'Open' being program-local,
> having actual arguments and having meaningful uses/clobbers, then
> this should make sense.
> If you consider vlc_module_set being
> not external and an indirect call visble you can also see how the
> indirect call processing then works during PTA solving.
I'm not sure if I understand this part. Are variables like callarg(...) used
even in IPA PTA and even when all involved function bodies are visible? Or are
you refering to intra PTA?
> So I'm not sure that only solution_set_expand is an issue with
> the way you do clobbers/uses, even if we'd do this in a more
> explicit way you'd get clobbers and uses part of the solving
> process.
So you think that my approach of handling clobbers and uses separately (not in
the solver) won't work? I understand that CALLCLOBBERED(31) must be a superset
of Open.clobber. But I don't see why callarg(34) must be a superset of
Open.clobbers. Couln't we modify GCC to not expand Open into all the
subvariables and instead handle them explicitly like this?
Instead of:
callarg(34) = &Open
callarg(34) = callarg(34) + UNKNOWN
callarg(34) = *callarg(34) + UNKNOWN
CALLUSED(30) = callarg(34)
*callarg(34) = callescape(29)
CALLCLOBBERED(31) = callarg(34)
callescape(29) = callarg(34)
ESCAPED = &Open
Do:
callarg(34) = &Open
callarg(34) = callarg(34) + UNKNOWN
(but this only expands real aggregates, not fninfo subvariables)
callarg(34) = *callarg(34) + UNKNOWN
CALLUSED(30) = &Open.use
*callarg(34) = callescape(29)
CALLCLOBBERED(31) = &Open.clobber
callescape(29) = callarg(34)
ESCAPED = &Open
With constraints like this, it would no longer happen that clobbers are used to
compute non-clobbers sets and I could return to the idea of handling clobbers
separately (similarly for uses).
We would have to think through how to handle situation like this where Open
isn't passed into the parameter directly but through a variable instead:
void vlc_entry__0_9_0f() {
void *fn;
if (p)
fn = Open1;
else
fn = Open2;
vlc_module_set(&vlc_entry__0_9_0f_p_submodule, VLC_MODULE_CB_OPEN, fn);
}
We could do something like this (assume that the offsets for .use and .clobber
are +1 and +2, I don't remember right now what they actually are):
fn = &Open1;
fn = &Open2;
CALLUSED(30) = fn + 1;
CALLCLOBBERED(31) = fn + 2;
But then what if fn can be both a function pointer and a data pointer:
void vlc_entry__0_9_0f() {
void *fn;
if (p)
fn = Open1;
else
fn = malloc(4);
vlc_module_set(&vlc_entry__0_9_0f_p_submodule, VLC_MODULE_CB_OPEN, fn);
}
Not sure what to do here to not mix up actuall aggregates and fninfo
subvariables. But we currently mix them up anyway, right? So the constraints
above would still be an improvement.
> There should be some very incomplete coverage of indirect call
> handing in the gcc.dg/ipa/ipa-pta-* tests.
>
> Now, that we get
>
> allarg(34) = { ESCAPED Open Open.clobber Open.use Open.result }
>
> shows that we fail to maintain the fact that we of course cannot
> take the address of Open.clobber or Open.use. I think this
> means we fail to set ->is_artificial_var on those (but not on
> arguments or result)? So if that helps, I think that's the
> correct thing to do here.
I'll look into this (though maybe not right away).
> Richard.