On Fri, Aug 7, 2020 at 9:57 AM Jonathan Wakely <jwak...@redhat.com> wrote: > > On 07/08/20 08:48 +0200, Richard Biener wrote: > >On Thu, Aug 6, 2020 at 9:24 PM Jonathan Wakely <jwak...@redhat.com> wrote: > >> > >> On 06/08/20 19:58 +0200, Aldy Hernandez wrote: > >> > > >> > > >> >On 8/6/20 6:30 PM, Jonathan Wakely wrote: > >> >>On 06/08/20 16:17 +0200, Aldy Hernandez wrote: > >> >>> > >> >>> > >> >>>On 8/6/20 12:48 PM, Jonathan Wakely wrote: > >> >>>>On 06/08/20 12:31 +0200, Richard Biener wrote: > >> >>>>>On Thu, Aug 6, 2020 at 12:19 PM Jonathan Wakely > >> >>>>><jwak...@redhat.com> wrote: > >> >>>>>> > >> >>>>>>On 06/08/20 06:16 +0100, Richard Sandiford wrote: > >> >>>>>>>Andrew MacLeod via Gcc-patches <gcc-patches@gcc.gnu.org> writes: > >> >>>>>>>>On 8/5/20 12:54 PM, Richard Biener via Gcc-patches wrote: > >> >>>>>>>>>On August 5, 2020 5:09:19 PM GMT+02:00, Martin Jambor > >> >>>>>><mjam...@suse.cz> wrote: > >> >>>>>>>>>>On Fri, Jul 31 2020, Aldy Hernandez via Gcc-patches wrote: > >> >>>>>>>>>>[...] > >> >>>>>>>>>> > >> >>>>>>>>>>>* ipa-cp changes from vec<value_range> to std::vec<value_range>. > >> >>>>>>>>>>> > >> >>>>>>>>>>>We are using std::vec to ensure constructors are run, which they > >> >>>>>>>>>>aren't > >> >>>>>>>>>>>in our internal vec<> implementation. Although we > >> >>>>>>>>>>>usually > >> >>>>>>steer away > >> >>>>>>>>>>>from using std::vec because of interactions with our GC system, > >> >>>>>>>>>>>ipcp_param_lattices is only live within the pass > >> >>>>>>>>>>>and > >> >>>>>>allocated with > >> >>>>>>>>>>calloc. > >> >>>>>>>>>>Ummm... I did not object but I will save the URL of > >> >>>>>>>>>>this > >> >>>>>>message in the > >> >>>>>>>>>>archive so that I can waive it in front of anyone > >> >>>>>>>>>>complaining why I > >> >>>>>>>>>>don't use our internal vec's in IPA data structures. > >> >>>>>>>>>> > >> >>>>>>>>>>But it actually raises a broader question: was this > >> >>>>>>supposed to be an > >> >>>>>>>>>>exception, allowed only not to complicate the irange > >> >>>>>>>>>>patch > >> >>>>>>further, or > >> >>>>>>>>>>will this be generally accepted thing to do when > >> >>>>>>>>>>someone > >> >>>>>>wants to have > >> >>>>>>>>>>a > >> >>>>>>>>>>vector of constructed items? > >> >>>>>>>>>It's definitely not what we want. You have to find > >> >>>>>>>>>another > >> >>>>>>solution to this problem. > >> >>>>>>>>> > >> >>>>>>>>>Richard. > >> >>>>>>>>> > >> >>>>>>>> > >> >>>>>>>>Why isn't it what we want? > >> >>>>>>>> > >> >>>>>>>>This is a small vector local to the pass so it doesn't > >> >>>>>>>>interfere with > >> >>>>>>>>our PITA GTY. > >> >>>>>>>>The class is pretty straightforward, but we do need a constructor > >> >>>>>>>>to > >> >>>>>>>>initialize the pointer and the max-size field. There is > >> >>>>>>>>no > >> >>>>>>allocation > >> >>>>>>>>done per element, so a small number of elements have a > >> >>>>>>>>couple > >> >>>>>>of fields > >> >>>>>>>>initialized per element. We'd have to loop to do that anyway. > >> >>>>>>>> > >> >>>>>>>>GCC's vec<> does not provide he ability to run a > >> >>>>>>>>constructor, > >> >>>>>>std::vec > >> >>>>>>>>does. > >> >>>>>>> > >> >>>>>>>I realise you weren't claiming otherwise, but: that could > >> >>>>>>>be fixed :-) > >> >>>>>> > >> >>>>>>It really should be. > >> >>>>>> > >> >>>>>>Artificial limitations like that are just a booby trap for the > >> >>>>>>unwary. > >> >>>>> > >> >>>>>It's probably also historic because we couldn't even implement > >> >>>>>the case of re-allocation correctly without std::move, could we? > >> >>>> > >> >>>>I don't see why not. std::vector worked fine without std::move, it's > >> >>>>just more efficient with std::move, and can be used with a wider set > >> >>>>of element types. > >> >>>> > >> >>>>When reallocating you can just copy each element to the new storage > >> >>>>and destroy the old element. If your type is non-copyable then you > >> >>>>need std::move, but I don't think the types I see used with vec<> are > >> >>>>non-copyable. Most of them are trivially-copyable. > >> >>>> > >> >>>>I think the benefit of std::move to GCC is likely to be permitting > >> >>>>cheap copies to be made where previously they were banned for > >> >>>>performance reasons, but not because those copies were impossible. > >> >>> > >> >>>For the record, neither value_range nor int_range<N> require any > >> >>>allocations. The sub-range storage resides in the stack or > >> >>>wherever it was defined. However, it is definitely not a POD. > >> >>> > >> >>>Digging deeper, I notice that the original issue that caused us to > >> >>>use std::vector was not in-place new but the safe_grow_cleared. > >> >>>The original code had: > >> >>> > >> >>>> auto_vec<value_range, 32> known_value_ranges; > >> >>>>... > >> >>>>... > >> >>>> if (!vr.undefined_p () && !vr.varying_p ()) > >> >>>> { > >> >>>> if (!known_value_ranges.length ()) > >> >>>> known_value_ranges.safe_grow_cleared (count); > >> >>>> known_value_ranges[i] = vr; > >> >>>> } > >> >>> > >> >>>I would've gladly kept the auto_vec, had I been able to do call > >> >>>the constructor by doing an in-place new: > >> >>> > >> >>>> if (!vr.undefined_p () && !vr.varying_p ()) > >> >>>> { > >> >>>> if (!known_value_ranges.length ()) > >> >>>>- known_value_ranges.safe_grow_cleared (count); > >> >>>>+ { > >> >>>>+ known_value_ranges.safe_grow_cleared > >> >>>>(count); > >> >>>>+ for (int i = 0; i < count; ++i) > >> >>>>+ new (&known_value_ranges[i]) > >> >>>>value_range (); > >> >>>>+ } > >> >>>> known_value_ranges[i] = vr; > >> >>>> } > >> >>>> } > >> >>> > >> >>>But alas, compiling yields: > >> >>> > >> >>>>In file included from /usr/include/wchar.h:35, > >> >>>> from /usr/include/c++/10/cwchar:44, > >> >>>> from /usr/include/c++/10/bits/postypes.h:40, > >> >>>> from /usr/include/c++/10/iosfwd:40, > >> >>>> from /usr/include/gmp-x86_64.h:34, > >> >>>> from /usr/include/gmp.h:59, > >> >>>> from /home/aldyh/src/gcc/gcc/system.h:687, > >> >>>> from /home/aldyh/src/gcc/gcc/ipa-fnsummary.c:55: > >> >>>>/home/aldyh/src/gcc/gcc/vec.h: In instantiation of ‘static > >> >>>>size_t vec<T, A, vl_embed>::embedded_size(unsigned int) [with T > >> >>>>= int_range<1>; A = va_heap; size_t = long unsigned int]’: > >> >>>>/home/aldyh/src/gcc/gcc/vec.h:288:58: required from ‘static > >> >>>>void va_heap::reserve(vec<T, va_heap, vl_embed>*&, unsigned int, > >> >>>>bool) [with T = int_range<1>]’ > >> >>>>/home/aldyh/src/gcc/gcc/vec.h:1746:20: required from ‘bool > >> >>>>vec<T>::reserve(unsigned int, bool) [with T = int_range<1>]’ > >> >>>>/home/aldyh/src/gcc/gcc/vec.h:1766:10: required from ‘bool > >> >>>>vec<T>::reserve_exact(unsigned int) [with T = int_range<1>]’ > >> >>>>/home/aldyh/src/gcc/gcc/vec.h:1894:3: required from ‘void > >> >>>>vec<T>::safe_grow(unsigned int) [with T = int_range<1>]’ > >> >>>>/home/aldyh/src/gcc/gcc/vec.h:1912:3: required from ‘void > >> >>>>vec<T>::safe_grow_cleared(unsigned int) [with T = int_range<1>]’ > >> >>>>/home/aldyh/src/gcc/gcc/ipa-fnsummary.c:634:51: required from here > >> >>>>/home/aldyh/src/gcc/gcc/vec.h:1285:20: warning: ‘offsetof’ > >> >>>>within non-standard-layout type ‘vec_embedded’ {aka > >> >>>>‘vec<int_range<1>, va_heap, vl_embed>’} is > >> >>>>conditionally-supported [-Winvalid-offsetof] > >> >>>>1285 | return offsetof (vec_embedded, m_vecdata) + alloc * sizeof > >> >>>>(T); > >> >>>> | ^ > >> >> > >> >>Can we just avoid using offsetof there? > >> >> > >> >>Untested ... > >> >> > >> >>--- a/gcc/vec.h > >> >>+++ b/gcc/vec.h > >> >>@@ -1281,8 +1281,8 @@ template<typename T, typename A> > >> >> inline size_t > >> >> vec<T, A, vl_embed>::embedded_size (unsigned alloc) > >> >> { > >> >>- typedef vec<T, A, vl_embed> vec_embedded; > >> >>- return offsetof (vec_embedded, m_vecdata) + alloc * sizeof (T); > >> >>+ size_t offset = (char*)&m_vecdata - (char*)this; > >> >>+ return offset + alloc * sizeof (T); > >> >> } > >> >> > >> >> > >> > > >> >Now we have: > >> > > >> >In file included from /home/aldyh/src/gcc/gcc/rtl.h:30, > >> > from /home/aldyh/src/gcc/gcc/genpreds.c:27: > >> >/home/aldyh/src/gcc/gcc/vec.h: In static member function ‘static > >> >size_t vec<T, A, vl_embed>::embedded_size(unsigned int)’: > >> >/home/aldyh/src/gcc/gcc/vec.h:1284:27: error: invalid use of member > >> >‘vec<T, A, vl_embed>::m_vecdata’ in static member function > >> > 1284 | size_t offset = (char*)&m_vecdata - (char*)this; > >> > | ^~~~~~~~~ > >> >/home/aldyh/src/gcc/gcc/vec.h:626:5: note: declared here > >> > 626 | T m_vecdata[1]; > >> > | ^~~~~~~~~ > >> >/home/aldyh/src/gcc/gcc/vec.h:1284:46: error: ‘this’ is unavailable > >> >for static member functions > >> > 1284 | size_t offset = (char*)&m_vecdata - (char*)this; > >> > | ^~~~ > >> > > >> > > >> > >> Oh sorry, I didn't realise it was static. > > > >Yeah, we eventually have no object when we need the offset. Does > >offsetof refusing to operate on this mean that using a temporary > >object on the stack like the following can yield a different answer > >from the "real" object? I guess examples where it breaks boil > >down to virtual inheritance. Anyway, so the following _should_ work ... > > > >template<typename T, typename A> > >inline size_t > >vec<T, A, vl_embed>::embedded_size (unsigned alloc) > >{ > > typedef vec<T, A, vl_embed> vec_embedded; > > This typedef is redundant, the name 'vec' in thos scope refers to the > current instantiation, so you can just say 'vec'. > > > vec_embedded tem; > > i.e. 'vec tem;' here, and remove the typedef on the previous line. > > > return (char *)&tem.m_vecdata - (char *)&tem + alloc * sizeof (T); > >} > > > >? > > Yes, that should work fine. In general you wouldn't want to create an > object just to do this, but creating and destroying a vec has no side > effects so is fine.
Now that you say it, vec has a T[1] member so depending on T there might be a side-effect as invoking its CTOR? Or it might even not compile if there is no default CTOR available... Ick :/ Richard. > >