[libcxx-commits] [libcxx] cf92766 - [libc++] Reduces std::to_chars instantiations.

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jun 22 09:47:12 PDT 2022


Author: Mark de Wever
Date: 2022-06-22T18:47:08+02:00
New Revision: cf927669eba9c768bfe3bf1cdebc7c03993831e8

URL: https://github.com/llvm/llvm-project/commit/cf927669eba9c768bfe3bf1cdebc7c03993831e8
DIFF: https://github.com/llvm/llvm-project/commit/cf927669eba9c768bfe3bf1cdebc7c03993831e8.diff

LOG: [libc++] Reduces std::to_chars instantiations.

Instead of instantiating all functions called by std::to_chars for the
integral types only instantiate them for 32 and 64 bit integral types.
This results in a smaller binary when using different types.

In an example using the types: signed char, short, int, long, long long,
unsigned char, unsigned short, unsigned int, unsigned long, and
unsigned long long this saved 2792 bytes of code size. For libc++.so.1
is saves 688 bytes of code size (64-bit Linux).

This was discovered while investigating a solution for #52709.

Reviewed By: #libc, ldionne

Differential Revision: https://reviews.llvm.org/D128215

Added: 
    

Modified: 
    libcxx/include/__type_traits/conditional.h
    libcxx/include/charconv
    libcxx/include/type_traits

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__type_traits/conditional.h b/libcxx/include/__type_traits/conditional.h
index ef182a9ed6550..9988cf7e89e69 100644
--- a/libcxx/include/__type_traits/conditional.h
+++ b/libcxx/include/__type_traits/conditional.h
@@ -26,6 +26,9 @@ template <class _If, class _Then>
 template <bool _Bp, class _If, class _Then> using conditional_t = typename conditional<_Bp, _If, _Then>::type;
 #endif
 
+// Helper so we can use "conditional_t" in all language versions.
+template <bool _Bp, class _If, class _Then> using __conditional_t = typename conditional<_Bp, _If, _Then>::type;
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___TYPE_TRAITS_CONDITIONAL_H

diff  --git a/libcxx/include/charconv b/libcxx/include/charconv
index b88ef46752a33..80aa44d28e81f 100644
--- a/libcxx/include/charconv
+++ b/libcxx/include/charconv
@@ -487,16 +487,21 @@ template <typename _Tp, typename enable_if<is_integral<_Tp>::value, int>::type =
 inline _LIBCPP_HIDE_FROM_ABI to_chars_result
 to_chars(char* __first, char* __last, _Tp __value)
 {
-    return __to_chars_itoa(__first, __last, __value, is_signed<_Tp>());
+  using _Type = __make_32_64_or_128_bit_t<_Tp>;
+  static_assert(!is_same<_Type, void>::value, "unsupported integral type used in to_chars");
+  static_assert(sizeof(_Tp) <= sizeof(int64_t), "128-bit integral support isn't available yet in to_chars");
+  return std::__to_chars_itoa(__first, __last, static_cast<_Type>(__value), is_signed<_Tp>());
 }
 
 template <typename _Tp, typename enable_if<is_integral<_Tp>::value, int>::type = 0>
 inline _LIBCPP_HIDE_FROM_ABI to_chars_result
 to_chars(char* __first, char* __last, _Tp __value, int __base)
 {
-    _LIBCPP_ASSERT(2 <= __base && __base <= 36, "base not in [2, 36]");
-    return __to_chars_integral(__first, __last, __value, __base,
-                               is_signed<_Tp>());
+  _LIBCPP_ASSERT(2 <= __base && __base <= 36, "base not in [2, 36]");
+
+  using _Type = __make_32_64_or_128_bit_t<_Tp>;
+  static_assert(sizeof(_Tp) <= sizeof(int64_t), "128-bit integral support isn't available yet in to_chars");
+  return std::__to_chars_integral(__first, __last, static_cast<_Type>(__value), __base, is_signed<_Tp>());
 }
 
 template <typename _It, typename _Tp, typename _Fn, typename... _Ts>

diff  --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index abd05ae3f013e..7a0c22539015c 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -517,6 +517,7 @@ namespace std
 #include <__type_traits/void_t.h>
 #include <__utility/declval.h>
 #include <cstddef>
+#include <cstdint>
 #include <version>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -1020,6 +1021,29 @@ typename make_unsigned<_Tp>::type __to_unsigned_like(_Tp __x) noexcept {
 }
 #endif
 
+template <class _Tp, class _Up>
+using __copy_unsigned_t = __conditional_t<is_unsigned<_Tp>::value, typename make_unsigned<_Up>::type, _Up>;
+
+/// Helper to promote an integral to smallest 32, 64, or 128 bit representation.
+///
+/// The restriction is the same as the integral version of to_char.
+template <class _Tp>
+#if _LIBCPP_STD_VER > 17
+  requires (is_signed_v<_Tp> || is_unsigned_v<_Tp> || is_same_v<_Tp, char>)
+#endif
+using __make_32_64_or_128_bit_t =
+  __copy_unsigned_t<_Tp,
+    __conditional_t<sizeof(_Tp) <= sizeof(int32_t),    int32_t,
+    __conditional_t<sizeof(_Tp) <= sizeof(int64_t),    int64_t,
+#ifndef _LIBCPP_HAS_NO_INT128
+    __conditional_t<sizeof(_Tp) <= sizeof(__int128_t), __int128_t,
+    /* else */                                         void>
+#else
+    /* else */                                         void
+#endif
+    > >
+  >;
+
 #if _LIBCPP_STD_VER > 17
 // Let COND_RES(X, Y) be:
 template <class _Tp, class _Up>


        


More information about the libcxx-commits mailing list