[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 19:01:39 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: None (higher-performance)
<details>
<summary>Changes</summary>
`std::visit` on my machine costs roughly **10 milliseconds per unique invocation** to compile, measurable as follows:
```
#include <variant>
int main(int argc, char* argv[]) {
std::variant<char, unsigned char, int> v;
int n = 0;
#define X(V) \
++n; \
std::visit([](int) {}, V)
#ifdef NEW_VERSION
// clang-format off
X(v); X(v); X(v); X(v); X(v); X(v); X(v); X(v);
X(v); X(v); X(v); X(v); X(v); X(v); X(v); X(v);
X(v); X(v); X(v); X(v); X(v); X(v); X(v); X(v);
X(v); X(v); X(v); X(v); X(v); X(v); X(v); X(v);
X(v); X(v); X(v); X(v); X(v); X(v); X(v); X(v);
X(v); X(v); X(v); X(v); X(v); X(v); X(v); X(v);
X(v); X(v); X(v); X(v); X(v); X(v); X(v); X(v);
X(v); X(v); X(v); X(v); X(v); X(v); X(v); X(v);
// clang-format on
#else
(void)v;
#endif
#undef X
return n;
}
```
This PR hard-codes common cases to speed up compilation by roughly **~8x** for them.
---
Full diff: https://github.com/llvm/llvm-project/pull/164196.diff
1 Files Affected:
- (modified) libcxx/include/variant (+42-5)
``````````diff
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 9beef146f203c..ef5bca4c2fda0 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1578,11 +1578,48 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __throw_if_valueless(_Vs&&... __vs) {
}
}
-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)...);
+template <class _Visitor, class... _Vs, typename>
+_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(_Visitor&& __visitor,
+ _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) {
+ if constexpr (variant_size<__remove_cvref_t<_Vs>...>::value <=
+ _XDispatchMax) {
+ using __variant_detail::__access::__variant;
+ using __variant_size = variant_size<__remove_cvref_t<_Vs>...>;
+ 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<__remove_cvref_t<_Vs>...>::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
``````````
</details>
https://github.com/llvm/llvm-project/pull/164196
More information about the libcxx-commits
mailing list