On Thu, Feb 23, 2023 at 01:54:27PM +0100, Richard Biener wrote:
> The following avoids default-initializing auto_vec storage for
> non-POD T since that's not what the allocated storage fallback
> will do and it's also not expected for existing cases like
> 
>   auto_vec<std::pair<unsigned, unsigned>, 64> elts;
> 
> which exist to optimize the allocation.
> 
> Bootstrapped and tested on x86_64-unknown-linux-gnu.
> 
> It saves around 1kB of text size for cc1.
> 
> OK for trunk?
> 
> Thanks,
> Richard.
> 
>       * vec.h (auto_vec<T, N>): Turn m_data storage into
>       uninitialized unsigned char.

Given that we actually never reference the m_data array anywhere,
it is just to reserve space, I think even the alignas(T) there is
useless.  The point is that m_auto has as data members:
  vec_prefix m_vecpfx;
  T m_vecdata[1];
and we rely on it (admittedly -fstrict-flex-arrays{,=2,=3} or
-fsanitize=bound-sstrict incompatible) being treated as
flexible array member flowing into the m_data storage after it.

Though, this shows we still have work to do.  Because
1) T m_vecdata[1]; still has element type T in m_auto and
   so is actually constructed/destructed uselessly
2) the non-POD support is certainly incomplete; we have
   vec_default_construct and vec_copy_construct and use that
   for say grow_cleared etc. or vector copies, but don't have
   anything that would invoke the destructors and don't invoke
   vec_copy_construct (aka placement new) when we just push
   stuff into the vector; so, I bet what we do is invalid
   and kind of works for non-PODs which have assignment operator
   which overwrites everything, doesn't use anything from the
   overwritten object and has the same overall effect
   as copy constructor, and only support trivial dtors
For full non-POD support, I bet we'd need to vec_copy_construct (..., 1)
on quick_push rather than invoke operator= there, we'd need
to destruct stuff on pop/truncate etc., and quick_grow would need
to be effectively the same as quick_grow_cleared for non-PODs.
As for 1), if even m_vecdata was
  alignas(T) unsigned char m_vecdata[sizeof (T)];
we'll need casts in various spots and it will printing vectors
by hand in gdb when the .gdbinit printers don't work properly.

Oh, and perhaps we should start marking such spots in GCC with
strict_flex_array attribute to make it clear where we rely on the
non-strict behavior.

> --- a/gcc/vec.h
> +++ b/gcc/vec.h
> @@ -1584,7 +1584,7 @@ public:
>  
>  private:
>    vec<T, va_heap, vl_embed> m_auto;
> -  T m_data[MAX (N - 1, 1)];
> +  alignas(T) unsigned char m_data[sizeof (T) * MAX (N - 1, 1)];
>  };
>  
>  /* auto_vec is a sub class of vec whose storage is released when it is

        Jakub

Reply via email to