PR libstdc++/91788 improve codegen for std::variant<T...>::index()
authorJonathan Wakely <jwakely@redhat.com>
Mon, 23 Sep 2019 15:54:16 +0000 (16:54 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 23 Sep 2019 15:54:16 +0000 (16:54 +0100)
If __index_type is a smaller type than size_t, then the result of
size_t(__index_type(-1)) is not equal to size_t(-1), but to an incorrect
value such as size_t(255) or size_t(65535). The old implementation of
variant<T...>::index() uses (size_t(__index_type(_M_index + 1)) - 1)
which is always correct, but generates suboptimal code for many common
cases.

When the __index_type is size_t or valueless variants are not possible
we can just return the value directly.

When the number of alternatives is sufficiently small the result of
converting the _M_index value to the corresponding signed type will be
either non-negative or -1. In those cases converting to the signed type
and then to size_t will either produce the correct positive value or
will sign extend -1 to (size_t)-1 as desired.

For the remaining case we keep the existing arithmetic operations to
ensure the correct result.

PR libstdc++/91788 (partial)
* include/std/variant (variant::index()): Improve codegen for cases
where conversion to size_t already works correctly.

From-SVN: r276056

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/variant

index 545247e3e5378fd364e284b4c9458f01529b08c7..54fe95f1ac965e02ff4c72c0e5d37897d9b504f1 100644 (file)
@@ -1,3 +1,9 @@
+2019-09-23  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/91788 (partial)
+       * include/std/variant (variant::index()): Improve codegen for cases
+       where conversion to size_t already works correctly.
+
 2019-09-23  Andreas Schwab  <schwab@suse.de>
 
        * config/abi/post/riscv64-linux-gnu/baseline_symbols.txt: Update.
index d93ea86ea2960d6383f6ac615d5b4022a576271c..c0043243ec29a0162df46a725440aa573333d975 100644 (file)
@@ -1518,7 +1518,17 @@ namespace __variant
       { return !this->_M_valid(); }
 
       constexpr size_t index() const noexcept
-      { return size_t(typename _Base::__index_type(this->_M_index + 1)) - 1; }
+      {
+       using __index_type = typename _Base::__index_type;
+       if constexpr (is_same_v<__index_type, size_t>)
+         return this->_M_index;
+       else if constexpr (__detail::__variant::__never_valueless<_Types...>())
+         return this->_M_index;
+       else if constexpr (sizeof...(_Types) <= __index_type(-1) / 2)
+         return make_signed_t<__index_type>(this->_M_index);
+       else
+         return size_t(__index_type(this->_M_index + 1)) - 1;
+      }
 
       void
       swap(variant& __rhs)