Skip to content

[libc++][NFC] Use __constexpr_memmove instead of copy_n in <__string/char_traits.h> #85920

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

philnik777
Copy link
Contributor

copy_n has been used to allow constant evaluation of char_traits. We now have __constexpr_memmove, which copy_n just forwards to. We can call __constexpr_memmove directly, avoiding a bunch of instantiations. This reduces the time it takes to include <string> from 321ms to 285ms.

@philnik777 philnik777 marked this pull request as ready for review March 20, 2024 16:41
@philnik777 philnik777 requested a review from a team as a code owner March 20, 2024 16:41
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Mar 20, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 20, 2024

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

copy_n has been used to allow constant evaluation of char_traits. We now have __constexpr_memmove, which copy_n just forwards to. We can call __constexpr_memmove directly, avoiding a bunch of instantiations. This reduces the time it takes to include &lt;string&gt; from 321ms to 285ms.


Full diff: https://github.com/llvm/llvm-project/pull/85920.diff

1 Files Affected:

  • (modified) libcxx/include/__string/char_traits.h (+5-6)
diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h
index 5880d3a22db2e7..47ed1057caaab1 100644
--- a/libcxx/include/__string/char_traits.h
+++ b/libcxx/include/__string/char_traits.h
@@ -9,7 +9,6 @@
 #ifndef _LIBCPP___STRING_CHAR_TRAITS_H
 #define _LIBCPP___STRING_CHAR_TRAITS_H
 
-#include <__algorithm/copy_n.h>
 #include <__algorithm/fill_n.h>
 #include <__algorithm/find_end.h>
 #include <__algorithm/find_first_of.h>
@@ -144,7 +143,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char> {
   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
                                           "char_traits::copy: source and destination ranges overlap");
-    std::copy_n(__s2, __n, __s1);
+    std::__constexpr_memmove(__s1, __s2, __element_count(__n));
     return __s1;
   }
 
@@ -221,7 +220,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<wchar_t> {
   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
                                           "char_traits::copy: source and destination ranges overlap");
-    std::copy_n(__s2, __n, __s1);
+    std::__constexpr_memmove(__s1, __s2, __element_count(__n));
     return __s1;
   }
 
@@ -287,7 +286,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t> {
   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
                                           "char_traits::copy: source and destination ranges overlap");
-    std::copy_n(__s2, __n, __s1);
+    std::__constexpr_memmove(__s1, __s2, __element_count(__n));
     return __s1;
   }
 
@@ -366,7 +365,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char16_t> {
   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
     _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2),
                                           "char_traits::copy: source and destination ranges overlap");
-    std::copy_n(__s2, __n, __s1);
+    std::__constexpr_memmove(__s1, __s2, __element_count(__n));
     return __s1;
   }
 
@@ -454,7 +453,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t> {
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type*
   copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
-    std::copy_n(__s2, __n, __s1);
+    std::__constexpr_memmove(__s1, __s2, __element_count(__n));
     return __s1;
   }
 

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. However, generally speaking I would be careful about not blindly removing useful layers of abstraction just to reduce compilation times. I'm not saying that's what this patch is doing, just warning that it might be easy to fall in that trap.

Copy link
Member

@mordante mordante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! +1 to what Louis said.

@philnik777
Copy link
Contributor Author

LGTM. However, generally speaking I would be careful about not blindly removing useful layers of abstraction just to reduce compilation times. I'm not saying that's what this patch is doing, just warning that it might be easy to fall in that trap.

I absolutely agree. I've been thinking about whether this is worth it for a while. If __constexpr_memmove didn't already exist and have almost the same API as copy_n I almost certainly wouldn't have considered this. In most cases it's also not that much of a concern, since most of our code is templated and thus doesn't instantiate its dependencies unconditionally.

@philnik777 philnik777 merged commit 2096f37 into llvm:main Mar 21, 2024
@philnik777 philnik777 deleted the use_constexpr_memmove_in_char_traits branch March 21, 2024 10:57
chencha3 pushed a commit to chencha3/llvm-project that referenced this pull request Mar 23, 2024
…char_traits.h> (llvm#85920)

`copy_n` has been used to allow constant evaluation of `char_traits`. We
now have `__constexpr_memmove`, which `copy_n` just forwards to. We can
call `__constexpr_memmove` directly, avoiding a bunch of instantiations.
This reduces the time it takes to include `<string>` from 321ms to
285ms.
qiaojbao pushed a commit to GPUOpen-Drivers/llvm-project that referenced this pull request May 15, 2024
…697e17e46

Local branch amd-gfx 1d3697e Merged main:35a66f965c0ea3b806b2b1736bfe4e6eb61d3613 into amd-gfx:93a2536cb084
Remote branch main 2096f37 [libc++][NFC] Use __constexpr_memmove instead of copy_n in <__string/char_traits.h> (llvm#85920)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants