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

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Oct 19 20:16:48 PDT 2025


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

>From a64925576b00bb46fe45db9aead3adda8984760a Mon Sep 17 00:00:00 2001
From: higher-performance <higher.performance.github at gmail.com>
Date: Sun, 19 Oct 2025 21:52:40 -0400
Subject: [PATCH] Speed up compilation of std::visit() by ~8x by hard-coding
 the most common cases

---
 libcxx/include/variant | 42 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 38 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/variant b/libcxx/include/variant
index 9beef146f203c..497350d401d0b 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1325,6 +1325,9 @@ private:
   friend struct __variant_detail::__visitation::__variant;
 };
 
+template <class... _Types>
+variant<_Types...> __upcast_to_variant(const volatile variant<_Types...>&);
+
 template <size_t _Ip, class... _Types>
 _LIBCPP_HIDE_FROM_ABI constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept {
   return __v.index() == _Ip;
@@ -1578,11 +1581,42 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __throw_if_valueless(_Vs&&... __vs) {
   }
 }
 
-template < class _Visitor, class... _Vs, typename>
+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)...);
+#    define _XDispatchIndex(_I)                                                                                        \
+    case _I:                                                                                                           \
+      if constexpr (__variant_size::value > _I) {                                                                      \
+        return __visitor(__variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value);                                \
+      }                                                                                                                \
+      [[__fallthrough__]]
+#    define _XDispatchMax 7 // Speed up compilation for the common cases
+  if constexpr (sizeof...(_Vs) == 1) {
+    using __variant_size = variant_size<decltype(std::__upcast_to_variant(declval<_Vs>()...))>;
+    if constexpr (__variant_size::value <= _XDispatchMax) {
+      using __variant_detail::__access::__variant;
+      const size_t __indexes[] = {__vs.index()...};
+      switch (__indexes[0]) {
+        _XDispatchIndex(_XDispatchMax - 7);
+        _XDispatchIndex(_XDispatchMax - 6);
+        _XDispatchIndex(_XDispatchMax - 5);
+        _XDispatchIndex(_XDispatchMax - 4);
+        _XDispatchIndex(_XDispatchMax - 3);
+        _XDispatchIndex(_XDispatchMax - 2);
+        _XDispatchIndex(_XDispatchMax - 1);
+        _XDispatchIndex(_XDispatchMax - 0);
+      default:
+        __throw_bad_variant_access();
+      }
+    } else {
+      static_assert(__variant_size::value > _XDispatchMax, "forgot to add dispatch case");
+    }
+  } 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)...);
+  }
+#    undef _XDispatchMax
+#    undef _XDispatchIndex
 }
 
 #    if _LIBCPP_STD_VER >= 20



More information about the libcxx-commits mailing list