On Sat, Mar 07, 2020 at 01:21:41AM -0500, Jason Merrill wrote:
> On 3/6/20 8:12 PM, Marek Polacek wrote:
> > On Fri, Mar 06, 2020 at 05:49:07PM -0500, Jason Merrill wrote:
> > > On 3/5/20 2:40 PM, Marek Polacek wrote:
> > > > The static_assert in the following test was failing on armv7hl because
> > > > we were disregarding the alignas specifier on Cell.  BaseShape's data
> > > > takes up 20B on 32-bit architectures, but we failed to round up its
> > > > TYPE_SIZE.  This happens since the
> > > > <https://gcc.gnu.org/ml/gcc-patches/2019-06/msg01189.html>
> > > > patch: here, in layout_class_type for TenuredCell, we see that the size
> > > > of TenuredCell and its CLASSTYPE_AS_BASE match, so we set
> > > > 
> > > >     CLASSTYPE_AS_BASE (t) = t;
> > > > 
> > > > But while TYPE_USER_ALIGN of TenuredCell was 0, TYPE_USER_ALIGN of its
> > > > CLASSTYPE_AS_BASE was 1.
> > > 
> > > Surely the bug is that TYPE_USER_ALIGN isn't set for TenuredCell?
> > 
> > That's my understanding.
> 
> So why is that?  Where is setting TYPE_USER_ALIGN on as-base TenuredCell,
> and why isn't it setting it on the main type as well?  Or is it getting
> cleared on the main type for some reason?

Yeah, it's getting cleared in finalize_type_size, called from
 6703   /* Let the back end lay out the type.  */
 6704   finish_record_layout (rli, /*free_p=*/true);
because finalize_type_size has
1930       /* Don't override a larger alignment requirement coming from a user
1931          alignment of one of the fields.  */
1932       if (mode_align >= TYPE_ALIGN (type))
1933         {
1934           SET_TYPE_ALIGN (type, mode_align);
1935           TYPE_USER_ALIGN (type) = 0;
1936         }
(for aggregates it is only done on STRICT_ALIGNMENT platforms which is why we
 won't see this problem on e.g. i686).

Here's the story of TYPE_USER_ALIGN:
- first we set TYPE_USER_ALIGN on Cell in common_handle_aligned_attribute,
  as expected
- in layout_class_type for Cell we copy T_U_A to its as-base type:
      TYPE_USER_ALIGN (base_t) = TYPE_USER_ALIGN (t);
- then we call finish_record_layout and T_U_A is cleared on Cell, but not its
  as-base type.  In finalize_type_size mode_align == TYPE_ALIGN (type) == 64.
- so in layout_empty_base_or_field we do this:
  if (CLASSTYPE_USER_ALIGN (type))
    {
      rli->record_align = MAX (rli->record_align, CLASSTYPE_ALIGN (type));
      if (warn_packed)
        rli->unpacked_align = MAX (rli->unpacked_align, CLASSTYPE_ALIGN (type));
      TYPE_USER_ALIGN (rli->t) = 1;
    }
  type is Cell and rli->t is TenuredCell
- then in layout_class_type we copy T_U_A from TenuredCell to its as-base type,
  then finish_record_layout clears it from the main type
- then we perform the new optimization by replacing the as-base type, making
  T_U_A set to 0 
- and so BaseShape's T_U_A is never set.

Does this explain things better?

(Of course we can't simply move the optimization before finish_record_layout
because that would disable it altogether.)

I wonder about changing the >= to > in finalize_type_size...  Thoughts?

> > I think it's clear that we're losing the alignas
> > specifier and so the TYPE_SIZE of BaseShape is wrong.  Before the patch from
> > June patch we'd set it...
> > 
> > >    After we replace it, it's no longer 1.  Then
> > > > we perform layout_empty_base_or_field for TenuredCell and since
> > > > TYPE_USER_ALIGN of its CLASSTYPE_AS_BASE is now 0, we don't do this
> > > > adjustment:
> > > > 
> > > >     if (CLASSTYPE_USER_ALIGN (type))
> > > >       {
> > > >         rli->record_align = MAX (rli->record_align, CLASSTYPE_ALIGN 
> > > > (type));
> > > >         if (warn_packed)
> > > >           rli->unpacked_align = MAX (rli->unpacked_align, 
> > > > CLASSTYPE_ALIGN (type));
> > > >         TYPE_USER_ALIGN (rli->t) = 1;
> > > >       }
> 
> I would expect it to be set here on TenuredCell prime, and then copied to
> the as-base type with
> 
> >       TYPE_USER_ALIGN (base_t) = TYPE_USER_ALIGN (t);

Correct, but see above.

> > ...here, but we no longer do.  Is there any other direction I could pursue?
> > Well, perhaps...
> > 
> > > > --- a/gcc/cp/class.c
> > > > +++ b/gcc/cp/class.c
> > > > @@ -6705,6 +6705,10 @@ layout_class_type (tree t, tree *virtuals_p)
> > > >      /* If we didn't end up needing an as-base type, don't use it.  */
> > > >      if (CLASSTYPE_AS_BASE (t) != t
> > > > +      /* If T's CLASSTYPE_AS_BASE is TYPE_USER_ALIGN, but T is not,
> > > > +        replacing the as-base type would change CLASSTYPE_USER_ALIGN,
> > > > +        causing us to lose the user-specified alignment as in PR94050. 
> > > >  */
> > > > +      && !CLASSTYPE_USER_ALIGN (t)
> > > >          && tree_int_cst_equal (TYPE_SIZE (t),
> > > >                              TYPE_SIZE (CLASSTYPE_AS_BASE (t))))
> > > >        CLASSTYPE_AS_BASE (t) = t;
> > 
> > ...we could copy the TYPE_USER_ALIGN flag to t if its old CLASSTYPE_AS_BASE
> > had it.  But my fix seems to be safer.
> 
> The flag should be set properly regardless of whether we do this
> optimization.

That makes sense, yeah.

Marek

Reply via email to