https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117764

Jan Hubicka <hubicka at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|cddce should handle         |[15 Regression] cddce
                   |__builtin_unreachable       |should handle
                   |guards                      |__builtin_unreachable
                   |                            |guards
                 CC|                            |mjambor at suse dot cz

--- Comment #1 from Jan Hubicka <hubicka at gcc dot gnu.org> ---
This is a regression, since I introduced the __builtin_unreachable guards to
std::vector::size.

I wonder if reasonable heuristics would be to mark the conditionals guarding
__builtin_unreachable as live provided that their control-dependency block is
already live for other reason.  This will allow removal of unnecesary loops.

We may however need to do something about ipa-sra as well.  If inlining failed,
it is not a best idea to keep dead argument just because we know its range.

Jonathan's reverted patch:

diff --git a/libstdc++-v3/include/bits/stl_vector.h
b/libstdc++-v3/include/bits/stl_vector.h
index acb29396d264..e593be443bc2 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -388,6 +388,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       }

     protected:
+
+      __attribute__((__always_inline__))
+      _GLIBCXX20_CONSTEXPR void
+      _M_invariant() const
+      {
+#if __OPTIMIZE__
+       if (this->_M_impl._M_finish < this->_M_impl._M_start)
+         __builtin_unreachable();
+       if (this->_M_impl._M_finish > this->_M_impl._M_end_of_storage)
+         __builtin_unreachable();
+
+       size_t __sz = this->_M_impl._M_finish - this->_M_impl._M_start;
+       size_t __cap = this->_M_impl._M_end_of_storage -
this->_M_impl._M_start;
+       if (__sz > __cap)
+         __builtin_unreachable();
+#endif
+      }
+
       _GLIBCXX20_CONSTEXPR
       void
       _M_create_storage(size_t __n)
@@ -987,7 +1005,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
       size_type
       size() const _GLIBCXX_NOEXCEPT
-      { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
+      {
+       _Base::_M_invariant();
+       return size_type(this->_M_impl._M_finish - this->_M_impl._M_start);
+      }

       /**  Returns the size() of the largest possible %vector.  */
       _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR


shows that people may do such things.  Here _M_invariant is empty, but Jonathan
clearly assumed that we will always inline it to every size() invokation and
then FRE multiple loads from _M_finish, M_start and friends and then after
inlining use this to derive useful value ranges for live code...

We may declare this as impossible, but I wonder what are the options :)

Also ipa-modref can detect the parameter as effectively unused...

Reply via email to