On Tue, Nov 19, 2024 at 4:37 PM Lewis Hyatt <lhy...@gmail.com> wrote:
>
> On Tue, Nov 19, 2024 at 9:55 AM Richard Biener
> <richard.guent...@gmail.com> wrote:
> >
> > On Sun, Nov 17, 2024 at 4:25 AM Lewis Hyatt <lhy...@gmail.com> wrote:
> > >
> > > The array gimple_ops_offset_[], which is used to find the trailing op[]
> > > array for a given gimple struct, is computed assuming that op[] will be
> > > found at sizeof(tree) bytes away from the end of the struct. This is only
> > > correct if the alignment requirement of a pointer is the same as the
> > > alignment requirement of the struct, otherwise there will be padding bytes
> > > that invalidate the calculation. On 64-bit platforms, this generally works
> > > fine because a pointer has 8-byte alignment and none of the structs make 
> > > use
> > > of more than that. On 32-bit platforms, it also currently works fine 
> > > because
> > > there are no 64-bit integers in the gimple structs. There are 32-bit
> > > platforms (e.g. sparc) on which a pointer has 4-byte alignment and a
> > > uint64_t has 8-byte alignment. On such platforms, adding a uint64_t to the
> > > gimple structs (as will take place when location_t is changed to be 
> > > 64-bit)
> > > causes gimple_ops_offset_ to be 4 bytes too large.
> > >
> > > It would be nice to use offsetof() to compute the offset exactly, but
> > > offsetof() is not guaranteed to work for these types, because they use
> > > inheritance and so are not standard layout types. This patch attempts to
> > > detect the presence of tail padding by detecting when such padding is 
> > > reused
> > > by inheritance; the padding should generally be reused for the same reason
> > > that offsetof() is not available, namely that all the relevant types use
> > > inheritance. One could envision systems on which this fix does not go far
> > > enough (e.g., if the ABI forbids reuse of tail padding), but it makes 
> > > things
> > > better without affecting anything that currently works.
> > >
> > > gcc/ChangeLog:
> > >
> > >         * gimple.cc (get_tail_padding_adjustment): New function.
> > >         (DEFGSSTRUCT): Adjust the computation of gimple_ops_offset_ to be
> > >         correct in the presence of tail padding.
> > > ---
> > >  gcc/gimple.cc | 34 +++++++++++++++++++++++++++++-----
> > >  1 file changed, 29 insertions(+), 5 deletions(-)
> > >
> > > diff --git a/gcc/gimple.cc b/gcc/gimple.cc
> > > index f7b313be40e..f0a642f5b51 100644
> > > --- a/gcc/gimple.cc
> > > +++ b/gcc/gimple.cc
> > > @@ -52,12 +52,36 @@ along with GCC; see the file COPYING3.  If not see
> > >  #include "ipa-modref.h"
> > >  #include "dbgcnt.h"
> > >
> > > -/* All the tuples have their operand vector (if present) at the very 
> > > bottom
> > > -   of the structure.  Therefore, the offset required to find the
> > > -   operands vector the size of the structure minus the size of the 1
> > > -   element tree array at the end (see gimple_ops).  */
> > > +/* All the tuples have their operand vector (if present) at the very 
> > > bottom of
> > > +   the structure.  Therefore, the offset required to find the operands 
> > > vector is
> > > +   the size of the structure minus the size of the 1-element tree array 
> > > at the
> > > +   end (see gimple_ops).  An adjustment may be required if there is tail
> > > +   padding, as may happen on a host (e.g. sparc) where a pointer has 
> > > 4-byte
> > > +   alignment while a uint64_t has 8-byte alignment.
> > > +
> > > +   Unfortunately, we can't use offsetof to do this computation 100%
> > > +   straightforwardly, because these structs use inheritance and so are 
> > > not
> > > +   standard layout types.  However, the fact that they are not standard 
> > > layout
> > > +   types also means that tail padding will be reused in inheritance, 
> > > which makes
> > > +   it possible to check for the problematic case with the following logic
> > > +   instead.  If tail padding is detected, the offset should be decreased
> > > +   accordingly.  */
> > > +
> > > +template<typename G>
> > > +static constexpr size_t
> > > +get_tail_padding_adjustment ()
> > > +{
> > > +  struct padding_check : G
> > > +  {
> > > +    tree t;
> > > +  };
> > > +  return sizeof (padding_check) == sizeof (G) ? sizeof (tree) : 0;
> > > +}
> > > +
> > >  #define DEFGSSTRUCT(SYM, STRUCT, HAS_TREE_OP) \
> > > -       (HAS_TREE_OP ? sizeof (struct STRUCT) - sizeof (tree) : 0),
> > > +  (HAS_TREE_OP \
> > > +   ? sizeof (STRUCT) - sizeof (tree) - 
> > > get_tail_padding_adjustment<STRUCT> () \
> > > +   : 0),
> >
> > I wonder if we cannot simply use offsetof (STRUCT, ops) and some
> > "trick" to avoid
> > parsing/sanitizing this when HAS_TREE_OP is false?  Maybe even a
> >
> > template <class T, bool has_offset>
> > constexpr size_t ops_offset () { return 0; }
> >
> > template <class T>
> > constexpr size_t ops_offset<T, true> ()
> > {
> >   return offsetof (T, ops);
> > /* or T x; return (char *)x.ops - (char *)x; */
> > }
> >
> > ?  That is I don't like the "indirect" adjustment via computing the padding.
> >
> > Richard.
>
> Thanks, yes, I tried to start this way as well. The template works, or
> it's not hard to change gsstruct.def so that DEFGSSTRUCT(SYM, STRUCT,
> HAS_TREE_OP) is instead two different macros, one for
> HAS_TREE_OP==true and one for false. The issue I ran into is that:
>
> -AFAIK it's not OK to call offsetof() on a struct which is not
> standard layout. All the gimple types fail to be standard layout
> because they use inheritance. GCC provides a warning "use of offsetof
> is conditionally supported". We could do this anyway and suppress the
> warning, but I am not sure if it would be too limiting in that it may
> not build right with other compilers.
>
> -AFAIK the use of reinterpret_cast as in (char *)x.ops - (char *)x is
> not permitted in a constexpr function, so doing it that way would
> require the array to be initialized at runtime instead. GCC actually
> doesn't complain about it in the constexpr function, although I think
> it's not supposed to be allowed.

We need to support non-GCC when building stage1 so we need something
strictly conforming here.

> Maybe it's not a big deal if the array becomes dynamically
> initialized, it would cause problems only if there are some global
> variables anywhere that may require it to be initialized. But I guess
> my thinking was that the tail padding approach is standard-conforming
> and works on the one platform I've found where it's necessary, and
> can't really do any harm to other platforms, so it's at least a strict
> improvement over what's there now... whereas changing it to use some
> implementation-defined behavior such as offsetof() on a non-POD type
> may have harder-to-predict implications. Happy to change it if you
> prefer one of the other options...

Unless some very C++ savy person comes around your patch is OK then.
It should work for the case the padding is exactly sizeof(tree) (in theory
it could be half a tree for 8 byte but 4 byte aligned pointers and some other
struct element forcing 8 byte alignment)

Richard.

>
> -Lewis
>
>
> -Lewis

Reply via email to