[libcxx-commits] [libcxx] [libc++] Instantiate integral to_chars overloads externally (PR #107071)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Sep 3 02:44:24 PDT 2024
https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/107071
None
>From 903c7be557f64681b5ff46d019608068d6f3ddfc Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 3 Sep 2024 11:44:00 +0200
Subject: [PATCH] [libc++] Instantiate integral to_chars overloads externally
---
libcxx/include/__charconv/to_chars_integral.h | 83 ++++++++++++++++++-
libcxx/include/__config | 6 ++
libcxx/include/__configuration/availability.h | 6 ++
libcxx/src/charconv.cpp | 40 ++++++++-
4 files changed, 132 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/__charconv/to_chars_integral.h b/libcxx/include/__charconv/to_chars_integral.h
index 0369f4dfb9bda6..511902f3510489 100644
--- a/libcxx/include/__charconv/to_chars_integral.h
+++ b/libcxx/include/__charconv/to_chars_integral.h
@@ -91,7 +91,7 @@ __to_chars_itoa(char* __first, char* __last, __uint128_t __value, false_type) {
}
# endif
-template <class _Tp>
+template <class _Tp, bool _UseExternalToChars = true>
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
__to_chars_integral(char* __first, char* __last, _Tp __value, int __base, false_type);
@@ -233,12 +233,60 @@ _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_widt
return std::__to_chars_integral_width<_Base>(static_cast<unsigned>(__value));
}
+// Don't return the pointer so we don't capture `__first` or `__last`.
+struct __to_chars_offset_result {
+ int32_t __offset_;
+ errc __ec_;
+};
+
+template <unsigned _Base, class _Tp>
+[[__gnu__::__noinline__]] _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral(_LIBCPP_NOESCAPE char* __first, _LIBCPP_NOESCAPE char* __last, _Tp __value) {
+ auto __result = __itoa::__integral<_Base>::__to_chars(__first, __last, __value);
+ return {static_cast<int32_t>(__result.ptr - __first), __result.ec};
+}
+
template <unsigned _Base, typename _Tp, __enable_if_t<(sizeof(_Tp) >= sizeof(unsigned)), int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
__to_chars_integral(char* __first, char* __last, _Tp __value) {
+ if (!__builtin_constant_p(__value)) {
+ auto __result = std::__external_to_chars_integral<_Base, _Tp>(__first, __last, __value);
+ return {__first + __result.__offset_, __result.__ec_};
+ }
return __itoa::__integral<_Base>::__to_chars(__first, __last, __value);
}
+# if _LIBCPP_AVAILABILITY_HAS_EXTERNAL_TO_CHARS
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<2, uint32_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint32_t);
+
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<8, uint32_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint32_t);
+
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<16, uint32_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint32_t);
+
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<2, uint64_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint64_t);
+
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<8, uint64_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint64_t);
+
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<16, uint64_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint64_t);
+
+# ifndef _LIBCPP_HAS_NO_INT128
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<2, __uint128_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, __uint128_t);
+
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<8, __uint128_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, __uint128_t);
+
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<16, __uint128_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, __uint128_t);
+# endif // _LIBCPP_HAS_NO_INT128
+# endif // _LIBCPP_AVAILABILITY_HAS_EXTERNAL_TO_CHARS
+
template <unsigned _Base, typename _Tp, __enable_if_t<(sizeof(_Tp) < sizeof(unsigned)), int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
__to_chars_integral(char* __first, char* __last, _Tp __value) {
@@ -271,9 +319,35 @@ _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_widt
__libcpp_unreachable();
}
-template <typename _Tp>
+template <class _Tp>
+[[__gnu__::__noinline__]] __to_chars_offset_result
+__external_to_chars_integral(_LIBCPP_NOESCAPE char* __first, _LIBCPP_NOESCAPE char* __last, int __base, _Tp __value) {
+ static_assert(is_unsigned_v<_Tp>);
+ auto __result = std::__to_chars_integral<_Tp, false>(__first, __last, __value, __base, false_type());
+ return {static_cast<int32_t>(__result.ptr - __first), __result.ec};
+}
+
+# if _LIBCPP_AVAILABILITY_HAS_EXTERNAL_TO_CHARS
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<uint32_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, int, uint32_t);
+
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<uint64_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, int, uint64_t);
+
+# ifndef _LIBCPP_HAS_NO_INT128
+extern template _LIBCPP_EXPORTED_FROM_ABI __to_chars_offset_result
+__external_to_chars_integral<__uint128_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, int, __uint128_t);
+# endif
+# endif // _LIBCPP_AVAILABILITY_HAS_EXTERNAL_TO_CHARS
+
+template <typename _Tp, bool _UseExternalToChars>
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
__to_chars_integral(char* __first, char* __last, _Tp __value, int __base, false_type) {
+ if (_UseExternalToChars && !__builtin_constant_p(__base)) {
+ auto __result = std::__external_to_chars_integral(__first, __last, __base, __value);
+ return {__first + __result.__offset_, __result.__ec_};
+ }
+
if (__base == 10) [[likely]]
return std::__to_chars_itoa(__first, __last, __value, false_type());
@@ -286,6 +360,11 @@ __to_chars_integral(char* __first, char* __last, _Tp __value, int __base, false_
return std::__to_chars_integral<16>(__first, __last, __value);
}
+ if (_UseExternalToChars && !__builtin_constant_p(__value)) {
+ auto __result = std::__external_to_chars_integral(__first, __last, __base, __value);
+ return {__first + __result.__offset_, __result.__ec_};
+ }
+
ptrdiff_t __cap = __last - __first;
int __n = std::__to_chars_integral_width(__value, __base);
if (__n > __cap)
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 9dd8d46b48d28f..0fb25aa32d1725 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -1158,6 +1158,12 @@ typedef __char32_t char32_t;
# define _LIBCPP_LIFETIMEBOUND
# endif
+# if __has_cpp_attribute(_Clang::__noescape__)
+# define _LIBCPP_NOESCAPE [[_Clang::__noescape__]]
+# else
+# define _LIBCPP_NOESCAPE
+# endif
+
# if __has_attribute(__nodebug__)
# define _LIBCPP_NODEBUG __attribute__((__nodebug__))
# else
diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h
index ab483a07c9c137..a690afe024123c 100644
--- a/libcxx/include/__configuration/availability.h
+++ b/libcxx/include/__configuration/availability.h
@@ -87,6 +87,9 @@
// in all versions of the library are available.
#if defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
+# define _LIBCPP_INTRODUCED_IN_LLVM_20 1
+# define _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE /* nothing */
+
# define _LIBCPP_INTRODUCED_IN_LLVM_19 1
# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE /* nothing */
@@ -284,6 +287,9 @@
#endif
+// This macro controls whether the external instantiations for integral to_chars are available
+#define _LIBCPP_AVAILABILITY_HAS_EXTERNAL_TO_CHARS _LIBCPP_INTRODUCED_IN_LLVM_20
+
// These macros control the availability of std::bad_optional_access and
// other exception types. These were put in the shared library to prevent
// code bloat from every user program defining the vtable for these exception
diff --git a/libcxx/src/charconv.cpp b/libcxx/src/charconv.cpp
index 4fd7a2c2c0f038..77063e291a1f83 100644
--- a/libcxx/src/charconv.cpp
+++ b/libcxx/src/charconv.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include <charconv>
-#include <string.h>
#include "include/to_chars_floating_point.h"
@@ -74,4 +73,43 @@ to_chars_result to_chars(char* __first, char* __last, long double __value, chars
__first, __last, static_cast<double>(__value), __fmt, __precision);
}
+template __to_chars_offset_result
+__external_to_chars_integral<2, uint32_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint32_t);
+
+template __to_chars_offset_result
+__external_to_chars_integral<8, uint32_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint32_t);
+
+template __to_chars_offset_result
+__external_to_chars_integral<16, uint32_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint32_t);
+
+template __to_chars_offset_result
+__external_to_chars_integral<2, uint64_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint64_t);
+
+template __to_chars_offset_result
+__external_to_chars_integral<8, uint64_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint64_t);
+
+template __to_chars_offset_result
+__external_to_chars_integral<16, uint64_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, uint64_t);
+
+#ifndef _LIBCPP_HAS_NO_INT128
+template __to_chars_offset_result
+__external_to_chars_integral<2, __uint128_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, __uint128_t);
+
+template __to_chars_offset_result
+__external_to_chars_integral<8, __uint128_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, __uint128_t);
+
+template __to_chars_offset_result
+__external_to_chars_integral<16, __uint128_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, __uint128_t);
+#endif // _LIBCPP_HAS_NO_INT128
+
+template __to_chars_offset_result
+__external_to_chars_integral<uint32_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, int, uint32_t);
+
+template __to_chars_offset_result
+__external_to_chars_integral<uint64_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, int, uint64_t);
+
+#ifndef _LIBCPP_HAS_NO_INT128
+template __to_chars_offset_result
+__external_to_chars_integral<__uint128_t>(_LIBCPP_NOESCAPE char*, _LIBCPP_NOESCAPE char*, int, __uint128_t);
+#endif
_LIBCPP_END_NAMESPACE_STD
More information about the libcxx-commits
mailing list