https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112716

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |hubicka at gcc dot gnu.org

--- Comment #17 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to uecker from comment #16)
> (In reply to Richard Biener from comment #15)
> > (In reply to uecker from comment #14)
> > > (In reply to Richard Biener from comment #13)
> > > > (In reply to uecker from comment #11)
> 
> 
> > > > 
> > > > But yes, when there are new C standards like C23 changing 
> > > > interoperability
> > > > rules a GCC extension needs to be amended to say how it behaves here.  I
> > > > would simply say the types covered by the GCC extension are exempt from 
> > > > the
> > > > C23 tag compatibility rules.
> > > 
> > > The new C23 tag compatibility rules apply inside one TU only and cross-TU
> > > nothing has changed. Across TUs, structurally equivalent types which also
> > > have the same tag are already required to be compatible in all previous
> > > versions of C and this works correctly in GCC for all structure/union 
> > > types
> > > without GNU extensions. It also works in GCC for structures with GNU
> > > extensions and across TUs but only without LTO. 
> > > 
> > > So the bug here is that LTO - unrelated to C23 - behaves inconsistently 
> > > for
> > > structs with GNU extension relative to  1) non-LTO GCC and 2) to what 
> > > could
> > > be expected from general C rules. Note that we have a similar LTO bug for
> > > flexible array members with [] and [0].
> > > (for non-LTO it works, of course, because there is no cross-TU TBAA in 
> > > this
> > > case).
> > > 
> > > So I think the rule how LTO decides to do structural comparison should be
> > > changed. 
> > 
> > LTO only has "rules" for globally visible types.  For local types it simply
> > assumes the frontends took care of everything.  LTO doesn't even get to see
> > those at unification time.
> 
> Can you explain what "globally visible types" are in the context of C? All
> types in C have cross-TU structural equivalency (when considering the tag as
> part of the strucutre). There is no concept of local of global for types in
> C.
> 
> If "local type" is a type where some size expression depends on a variable,
> I do not see where those are treated differently in GCC. The C FE does not
> distinguish them and neither does the C standard.

Indeed LTO type unification gets to see only types streamed into the global
types and declarations table.  Entities (including types) streamed together
with function bodies because they reference function-local entities are
"local".

The C frontend distinguishes them during name-lookup and it doesn't
complain about conflicting same-tag types in different contexts.

> > 
> > How does the C frontend handle two such "local" tag equivalent types?  That
> > is, how does it "find" them and how does it ensure they are either unified
> > or at least have the same TYPE_CANONICAL?
> 
> It collects them in a hash table, forms equivalency classes compatible with
> the type compatibility rules (which are not transitive), and then assigns
> the same TYPE_CANONICAL to all types in the same class. We discussed this
> previously. 

OK, so it unifies types from different contexts and thus for equivalence
class purposes all types are "global", right?

> > 
> > Note that LTO ignores TAG differences of global types and unifies solely
> 
> Does "unifies" mean "assigns a new TYPE_CANONICAL" ? 

There is "tree" data structure unification for identical trees and there is
semantic unification (aka forming equivalences for TBAA purposes) by
adjusting TYPE_CANONICAL to a leader of the found equivalence classes.
We're talking about the latter (given TYPE_CONTEXT would necessarily
differ).

> > based on a very weak form of structural equality (I'd have to check the
> > exact behavior for VLAs).  See gimple_canonical_types_compatible_p.
> 
> Yes, I will look at this. Probably a tweak to this function might be enough.

As said above it won't - we are not altering the types streamed during
input_function (), nor do we keep the required unification hashtable
between streaming of different functions.

Maybe we could at LTO output time, for each function stream a set of
hashes for types locally defined (and thus candidate for unification)
and only maintain a unification hash for those (at LTO input time).

I'll note that IPA modref also records "types" stored/read and does not
consider "local types" to alias with anything IIRC.  Honza might know
better how we deal with this case during WPA.  This is a case that wouldn't
be fixed with a fixup at input_function () time.  Instead we would need to
bring in local trees for the actual comparison.

What might also work would be if the frontend would, for each local
"VLA" type, create a TYPE_CANONICAL with the "VLA" bits (the reference
to local entities) elided - for example int[a] replaced with just int[].
Those TYPE_CANONICAL would be "global" I think and subject to LTO
unification and fix the issue that way?

Btw, see tree_is_indexable () for what entities are considered "global",
in particular while TYPE_DECLs with function context are "local",
TREE_TYPE are "global" unless they are variably_modified_type_p.

> > 
> > > > 
> > > > That said - if C23 tag compatibility is something like the C++ ODR then
> > > > the frontend could produce a "mangling" (simply the tag name) and direct
> > > > the middle-end to handle compatibility that way.  Note that C++ 
> > > > specifically
> > > > exempts "local" types from the ODR.  I think C is wrong here to not 
> > > > allow
> > > > this - it will basically force all structs with that T to be 
> > > > "compatible"
> > > > whether or not the types are even structurally related?
> > > 
> > > The struct have to have the same tag (or both no tag) and must be
> > > structurally equivalent. Structs with different tag or which are not
> > > structurally equivalent are not compatible. But nothing has changed here
> > > with C23 for the cross-TU case, the only question is how the GNU 
> > > extensions
> > > fit in her.
> > > 
> > > IMHO at least the cases where the arrays are at the end of the struct
> > > 
> > > struct foo { ...; int x[]; }
> > > struct foo { ...; int x[0]; };
> > > struct foo { ...; int x[n]; };
> > > 
> > > should all be treated as compatible for TBAA purposes. 
> > > 
> > > The case where there is a VLA in the middle of a struct
> > > 
> > > struct foo { int x[n]; ... };
> > > 
> > > it also would be good if this worked. But those are very obscure.
> > 
> > So a pragmatic "solution" would be to get all affected types alias set zero.
> 
> I think the problem with alias set zero might be that this is not enough
> to allow derived types to alias, e.g. pointers to such structs, or functions
> returning them. Or?

Yes, a struct containing such struct doesn't automatically alias unless
the containing struct is then marked TYPE_TYPELESS_STORAGE.  For example
aggregate copy of such struct would break.

Using alias-set zero is of course also pessimizing.

> > 
> > I'll note that in case a type is defined locally and is not VLA LTO
> > treats it as local as well (or at least it would be free to do so).
> > 
> > I'll also note there are some existing LTO issues around VLA types
> > when they are refered to by function argument or return types.
> 
> I think I filed some bugs.  For function types the solution is probably to
> set TYPE_CANONICAL in the FE similar to what we do for structs.
> 
> Martin

Reply via email to