[libcxx-commits] [libcxx] Speed up compilation of common uses of std::visit() (PR #164196)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Nov 29 03:58:19 PST 2025


https://github.com/higher-performance updated https://github.com/llvm/llvm-project/pull/164196

>From 570d7e39afb62aef382df0e45f7e4d8ba4e9ae8e Mon Sep 17 00:00:00 2001
From: higher-performance <higher.performance.github at gmail.com>
Date: Fri, 28 Nov 2025 10:48:16 -0500
Subject: [PATCH] Speed up compilation of std::visit() by hard-coding the most
 common cases

---
 libcxx/include/variant | 75 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 69 insertions(+), 6 deletions(-)

diff --git a/libcxx/include/variant b/libcxx/include/variant
index df587ccf23843..0dc2360909ec4 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1323,6 +1323,10 @@ private:
   friend struct __variant_detail::__visitation::__variant;
 };
 
+template <class... _Types>
+variant<_Types...> __upcast_to_variant(const volatile variant<_Types...>*);
+void __upcast_to_variant(...);
+
 template <size_t _Ip, class... _Types>
 _LIBCPP_HIDE_FROM_ABI constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept {
   return __v.index() == _Ip;
@@ -1576,22 +1580,81 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __throw_if_valueless(_Vs&&... __vs) {
   }
 }
 
+#    define _LIBCPP_VARIANT_DISPATCH_COUNT 8 // Speed up compilation for the common cases
+#    define _LIBCPP_VARIANT_DISPATCH_INDEX(_I)                                                                                        \
+    case _I:                                                                                                                          \
+      if constexpr (__variant_size::value > _I) {                                                                                     \
+        return std::__invoke(std::forward<_Visitor>(__visitor), __variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value);        \
+      }                                                                                                                               \
+      [[__fallthrough__]]
+
 template < class _Visitor, class... _Vs, typename>
 _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
-  using __variant_detail::__visitation::__variant;
-  std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
-  return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
+  using __variant_size = variant_size<decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()...))>;
+  if constexpr (sizeof...(_Vs) == 1 &&
+                conditional_t<is_same_v<variant_size<void>, __variant_size>,
+                              std::integral_constant<size_t, variant_npos>,
+                              __variant_size>::value < _LIBCPP_VARIANT_DISPATCH_COUNT) {
+    using __variant_detail::__access::__variant;
+    const size_t __indices[] = {
+        __vs.decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()))::index()...};
+    switch (__indices[0]) {
+      enum : size_t { _I0 = __LINE__ + 1 };           // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      static_assert(__LINE__ - _I0 == _LIBCPP_VARIANT_DISPATCH_COUNT, "index count mismatch");
+    default:
+      std::__throw_bad_variant_access();
+    }
+  } else {
+    using __variant_detail::__visitation::__variant;
+    std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
+    return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
+  }
 }
 
 #    if _LIBCPP_STD_VER >= 20
 template < class _Rp, class _Visitor, class... _Vs, typename>
 _LIBCPP_HIDE_FROM_ABI constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) {
-  using __variant_detail::__visitation::__variant;
-  std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
-  return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
+  using __variant_size = variant_size<decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()...))>;
+  if constexpr (sizeof...(_Vs) == 1 &&
+                conditional_t<is_same_v<variant_size<void>, __variant_size>,
+                              std::integral_constant<size_t, variant_npos>,
+                              __variant_size>::value < _LIBCPP_VARIANT_DISPATCH_COUNT) {
+    using __variant_detail::__access::__variant;
+    const size_t __indices[] = {
+        __vs.decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()))::index()...};
+    switch (__indices[0]) {
+      enum : size_t { _I0 = __LINE__ + 1 };           // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+      static_assert(__LINE__ - _I0 == _LIBCPP_VARIANT_DISPATCH_COUNT, "index count mismatch");
+    default:
+      std::__throw_bad_variant_access();
+    }
+  } else {
+    using __variant_detail::__visitation::__variant;
+    std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
+    return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
+  }
 }
 #    endif
 
+#    undef _LIBCPP_VARIANT_DISPATCH_INDEX
+#    undef _LIBCPP_VARIANT_DISPATCH_COUNT
+
 template <class... _Types>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 auto
 swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) noexcept(noexcept(__lhs.swap(__rhs)))



More information about the libcxx-commits mailing list