In the case of initializing a vector from an initializer_list, we can provide
some help to the compiler on what the size of the vector is after the 
initialization
so that the compiler can optimize away user checks based on the size earlier.

Bootstrapped and tested on x86_64-linux-gnu with no regressions.

        PR libstdc++/110620

libstdc++-v3/ChangeLog:

        * include/bits/stl_vector.h (vector::_M_range_initialize_n(),
        vector::_M_fill_initialize(), vector::_M_default_initialize()): Add
        __builtin_unreachable() call to record the size of the vector after
        the initialization loop.

gcc/testsuite/ChangeLog:

        * g++.dg/tree-ssa/pr110620.C: New test.

Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com>
---
 gcc/testsuite/g++.dg/tree-ssa/pr110620.C | 27 ++++++++++++++++++++++++
 libstdc++-v3/include/bits/stl_vector.h   | 15 +++++++++++++
 2 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr110620.C

diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr110620.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr110620.C
new file mode 100644
index 00000000000..179cd81f35f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr110620.C
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -fdump-tree-optimized -Wextra -Wall -Warray-bounds" }
+#include <vector>
+
+typedef std::pair<int, int> inner;
+
+// By the time bounds array warning comes around, the check for >5 should have 
been optimized away
+inline
+void foo(std::vector<inner>& vec) {
+  if (vec.size() > 5)
+    vec[3].first = 0; // { dg-bogus "outside array bounds of" }
+}
+
+int ff() {
+  auto v1 = std::vector<inner>{inner(1, 2)};
+  foo(v1);
+  return v1.size();
+}
+
+
+
+// This should compile to empty function; check that no size of
+// vector is determined and there is no allocation
+// { dg-final { scan-tree-dump-not "_M_start" "optimized"  } }
+// { dg-final { scan-tree-dump-not " delete" "optimized" } }
+// { dg-final { scan-tree-dump-not " = MEM" "optimized" } }
+// { dg-final { scan-tree-dump "return 1" "optimized" } }
diff --git a/libstdc++-v3/include/bits/stl_vector.h 
b/libstdc++-v3/include/bits/stl_vector.h
index a4b1d1bda79..6553196cb8f 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -2017,12 +2017,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        _M_range_initialize_n(_Iterator __first, _Sentinel __last,
                              size_type __n)
        {
+#ifdef __OPTIMIZE__
+         const size_type __orig_n = __n;
+#endif
          pointer __start = this->_M_impl._M_start =
            this->_M_allocate(_S_check_init_len(__n, _M_get_Tp_allocator()));
          this->_M_impl._M_end_of_storage = __start + __n;
          this->_M_impl._M_finish
              = std::__uninitialized_copy_a(_GLIBCXX_MOVE(__first), __last,
                                            __start, _M_get_Tp_allocator());
+#ifdef __OPTIMIZE__
+         if (this->size() != __orig_n)
+           __builtin_unreachable();
+#endif
        }
 
       // Called by the first initialize_dispatch above and by the
@@ -2034,6 +2041,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        this->_M_impl._M_finish =
          std::__uninitialized_fill_n_a(this->_M_impl._M_start, __n, __value,
                                        _M_get_Tp_allocator());
+#ifdef __OPTIMIZE__
+         if (this->size() != __n)
+           __builtin_unreachable();
+#endif
       }
 
 #if __cplusplus >= 201103L
@@ -2045,6 +2056,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        this->_M_impl._M_finish =
          std::__uninitialized_default_n_a(this->_M_impl._M_start, __n,
                                           _M_get_Tp_allocator());
+#ifdef __OPTIMIZE__
+         if (this->size() != __n)
+           __builtin_unreachable();
+#endif
       }
 #endif
 
-- 
2.43.0

Reply via email to