On Fri, 14 Feb 2025, 18:34 Andrew Pinski (QUIC), <quic_apin...@quicinc.com> wrote:
> > -----Original Message----- > > From: Jonathan Wakely <jwak...@redhat.com> > > Sent: Friday, February 14, 2025 6:49 AM > > To: Andrew Pinski (QUIC) <quic_apin...@quicinc.com> > > Cc: gcc-patches@gcc.gnu.org; libstd...@gcc.gnu.org > > Subject: Re: [PATCH] libstc++: Improve list assumption after > > constructor [PR118865] > > > > On Fri, 14 Feb 2025 at 03:03, Andrew Pinski > > <quic_apin...@quicinc.com> wrote: > > > > > > The code example here does: > > > ``` > > > if (begin == end) __builtin_unreachable(); std::list nl(begin, > > end); > > > > > > for (auto it = nl.begin(); it != nl.end(); it++) { ... > > > } > > > /* Remove the first element of the list. */ > > nl.erase(nl.begin()); ``` > > > > > > And we get a warning because because we jump threaded > > the case were we > > > think the list was empty from the for loop BUT we populated > > it without > > > an empty array. So can help the compiler here by adding that > > after > > > initializing the list with non empty array, that the list will not > > be empty either. > > > > > > This is able to remove the -Wfree-nonheap-object warning in > > the first > > > reduced testcase (with the fix for `begin == end` case added) > > in the > > > PR 118865; the second reduced testcase has been filed off as > > PR 118867. > > > > > > Bootstrapped and tested on x86_64-linux-gnu. > > > > > > libstdc++-v3/ChangeLog: > > > > > > PR libstdc++/118865 > > > * include/bits/stl_list.h (_M_initialize_dispatch): Add an > > > unreachable if the iterator was not empty that the list > > will > > > now be not empty. > > > > > > Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com> > > > --- > > > libstdc++-v3/include/bits/stl_list.h | 6 ++++++ > > > 1 file changed, 6 insertions(+) > > > > > > diff --git a/libstdc++-v3/include/bits/stl_list.h > > > b/libstdc++-v3/include/bits/stl_list.h > > > index be33eeb03d4..f987d8b9d0a 100644 > > > --- a/libstdc++-v3/include/bits/stl_list.h > > > +++ b/libstdc++-v3/include/bits/stl_list.h > > > @@ -2384,12 +2384,18 @@ > > _GLIBCXX_BEGIN_NAMESPACE_CXX11 > > > _M_initialize_dispatch(_InputIterator __first, > > _InputIterator __last, > > > __false_type) > > > { > > > + bool __notempty = __first != __last; > > > for (; __first != __last; ++__first) #if __cplusplus >= > > > 201103L > > > emplace_back(*__first); > > > #else > > > push_back(*__first); > > > #endif > > > + if (__notempty) > > > + { > > > + if (begin() == end()) > > > + __builtin_unreachable(); > > > + } > > > > Would there be any benefit in also telling the compiler that > > when first==last that the resulting list *is* empty? > > I was debating if that would be useful but then I looked and noticed the > compiler could already figure it. The reason is begin for a list is a > wrapper around an addition of a pointer and a constant. Pre is able to > optimize the case which then will be used to jump thread later on. > Also I think a too complex leading to the unreachable will not help the > compiler out at all. > > An example is: > ``` > > int *g(int); > > int f(int **a, int b, int c, int *d) > { > *a = d; > for(int i = 0; i < c; i++) > *a = g(i); > #ifdef ADD_UNREACHABLE > if (c >= 0) > if (*a == d) > __builtin_unreachable(); > #endif > if (*a == d) > return 1; > return 0; > } > ``` > GCC is able to optimize away the last condition for the case of `(c <= 0)` > and when defining ADD_UNREACHABLE can now optimize away the condition fully. > > > > > so e.g. > > > > const bool __empty = __first == __last; > > // loop > > if (__empty != (begin() == end())) > > __builtin_unreachable(); > > > > > > Testing first == last twice for the first iteration bugs me a little, > > but I assume that can be optimized? Or should we use a do- > > while? > > Yes does get optimized away. See above. For the typical iterator the > comparison, will be max 2 loads followed by a comparison of that (or no > loads) and GCC's early passes does a nice job at optimizing that. The patch is OK for trunk then, thanks. > > Thanks, > Andrew Pinski > > > > > if (__first != __last) > > { > > do > > { > > #if __cplusplus >= 201103L > > emplace_back(*__first); #else > > push_back(*__first); > > #endif > > } while (++__first != __last); > > if (begin() == end()) > > __builtin_unreachable(); > > } > >