https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80813
--- Comment #3 from Jan Hubicka <hubicka at gcc dot gnu.org> --- OK, so the horrid codegen is because bvector's [] operator is imlemented using iterator: return begin()[__n]; iterator's [] operator is implemented using: _GLIBCXX20_CONSTEXPR void _M_incr(ptrdiff_t __i) { _M_assume_normalized(); difference_type __n = __i + _M_offset; _M_p += __n / int(_S_word_bit); __n = __n % int(_S_word_bit); if (__n < 0) { __n += int(_S_word_bit); --_M_p; } _M_offset = static_cast<unsigned int>(__n); } So the conditional is a check for negative __n which makes sense for iterator's [], but not for vector's []. We could add __builtin_unreachable hint that __n is at most max_size, but since [] is such a common operation on vectors, I think it makes sense to make life of compiler easier and micro-optimize it in the array. diff --git a/libstdc++-v3/include/bits/stl_bvector.h b/libstdc++-v3/include/bits/stl_bvector.h index 341eee33b21..43a07bc3e55 100644 --- a/libstdc++-v3/include/bits/stl_bvector.h +++ b/libstdc++-v3/include/bits/stl_bvector.h @@ -1132,7 +1141,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER operator[](size_type __n) { __glibcxx_requires_subscript(__n); - return begin()[__n]; + return _Bit_reference (this->_M_impl._M_start._M_p + + __n / int(_S_word_bit), + __n % int(_S_word_bit)); } _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR @@ -1140,7 +1151,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER operator[](size_type __n) const { __glibcxx_requires_subscript(__n); - return begin()[__n]; + return _Bit_reference (this->_M_impl._M_start._M_p + + __n / int(_S_word_bit), + __n % int(_S_word_bit)); } protected: With this I now get: .LFB1248: .cfi_startproc movq (%rdi), %rax movq %rsi, %rdx shrq $6, %rdx andq (%rax,%rdx,8), %rsi andl $63, %esi setne %al ret that is certainly better. Still does not use BT. Not sure if _M_incr can be tweaked for less horrid codegen.