[PATCH] PR libstdc++/91788 improve codegen for std::variant<T...>::index()
Jonathan Wakely
jwakely@redhat.com
Mon Sep 23 15:54:00 GMT 2019
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.
Tested x86_64-linux, committed to trunk.
-------------- next part --------------
commit 6ef8d9750c46e3d781c4d8cf169f66a13e0d0827
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Mon Sep 23 16:07:54 2019 +0100
PR libstdc++/91788 improve codegen for std::variant<T...>::index()
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.
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index d93ea86ea29..c0043243ec2 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -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)
More information about the Libstdc++
mailing list