From patchwork Tue Oct 15 14:20:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1997505 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=DSXthYNe; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XSc1W010Yz1xv6 for ; Wed, 16 Oct 2024 01:29:34 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 27AE63858283 for ; Tue, 15 Oct 2024 14:29:33 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 2B9A33858D21 for ; Tue, 15 Oct 2024 14:26:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2B9A33858D21 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2B9A33858D21 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002407; cv=none; b=CLm4RCPRHMzfWLxZ1JmpjsDFJMzJ20Utm2Nsc6WqjxZW+UVOxTXaycaagDQLvbxcqdiColnhGIFJGsWHzct+tmKRYETYb3qpMbFS2zBFM1WEO29B5t3kQsLGpuYVVT2v44YIrlLVOUqD7+v518JxhgVqNSisARWQo+5VTkSpXKw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002407; c=relaxed/simple; bh=aqtgLg1wnUbOEKXBEOyJu6Oc0hSGun6OTlgiEy9Zj0M=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=LjgTk0JaMWQcXfl10Z5ydOMQhqzxIwMgKXyd/0vivxuZLECCCK0206UDEJ8CcLXh9dLTPOf41HrdUBhrQYwV2OaSsv0Aftxmgz5BDbG3hGKb92yV8zPiXl7P+yJrjGY3PAsfqQm6sF0L9Lou2XcH0lwXo1zvJFYfyawLK14enTk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1729002396; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=A/pebyHlD+qT2LP+YcC2I4vb73aAMw8Wa5+Md48iaQo=; b=DSXthYNeRpLHsimjCZCbWCiA8XVF1e+M1IZ8ClC1ffJnWDvrTjePCcRJWPce4olhhXenq5 IaYBdIBTYfOJIpZi316c6Hukh1xh2aRuEtwNk3p85gxk2UTDMzziia7rntKeYhA1NuHZdy 3tlEvRyJpp+OeHGhb+PRhbwY1SYFG3I= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-31-6QNQNJBvPcKbvoQhBwqrpw-1; Tue, 15 Oct 2024 10:26:33 -0400 X-MC-Unique: 6QNQNJBvPcKbvoQhBwqrpw-1 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C29AD1955F07; Tue, 15 Oct 2024 14:26:32 +0000 (UTC) Received: from localhost (unknown [10.42.28.16]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 95AAC19560A2; Tue, 15 Oct 2024 14:26:31 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 1/7] libstdc++: Refactor std::uninitialized_{copy, fill, fill_n} algos [PR68350] Date: Tue, 15 Oct 2024 15:20:11 +0100 Message-ID: <20241015142630.2148792-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP, URIBL_DBL_SPAM autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org This is v2 of https://gcc.gnu.org/pipermail/gcc-patches/2024-October/665246.html fixing some thinkos in uninitialized_{fill,fill_n}. We don't need to worry about overwriting tail-padding in those algos, because we only use memset for 1-byte integer types. So they have no tail padding that can be reused anyway! So this changes __n > 1 to __n > 0 in a few places (which fixes the problem that it was not actually filling anything for the n==1 cases). Also simplify std::__to_address(__result++) to just __result++ because we already have a pointer, and use std::to_address(result++) for a C++20 std::contiguous_iterator case, instead of addressof(*result++). Tested x86_64-linux. -- >8 -- This refactors the std::uninitialized_copy, std::uninitialized_fill and std::uninitialized_fill_n algorithms to directly perform memcpy/memset optimizations instead of dispatching to std::copy/std::fill/std::fill_n. The reasons for this are: - Use 'if constexpr' to simplify and optimize compilation throughput, so dispatching to specialized class templates is only needed for C++98 mode. - Relax the conditions for using memcpy/memset, because the C++20 rules on implicit-lifetime types mean that we can rely on memcpy to begin lifetimes of trivially copyable types. We don't need to require trivially default constructible, so don't need to limit the optimization to trivial types. See PR 68350 for more details. - The conditions on non-overlapping ranges are stronger for std::uninitialized_copy than for std::copy so we can use memcpy instead of memmove, which might be a minor optimization. - Avoid including in . It only needs some iterator utilities from that file now, which belong in anyway, so this moves them there. Several tests need changes to the diagnostics matched by dg-error because we no longer use the __constructible() function that had a static assert in. Now we just get straightforward errors for attempting to use a deleted constructor. Two tests needed more signficant changes to the actual expected results of executing the tests, because they were checking for old behaviour which was incorrect according to the standard. 20_util/specialized_algorithms/uninitialized_copy/64476.cc was expecting std::copy to be used for a call to std::uninitialized_copy involving two trivially copyable types. That was incorrect behaviour, because a non-trivial constructor should have been used, but using std::copy used trivial default initialization followed by assignment. 20_util/specialized_algorithms/uninitialized_fill_n/sizes.cc was testing the behaviour with a non-integral Size passed to uninitialized_fill_n, but I wrote the test looking at the requirements of uninitialized_copy_n which are not the same as uninitialized_fill_n. The former uses --n and tests n > 0, but the latter just tests n-- (which will never be false for a floating-point value with a fractional part). libstdc++-v3/ChangeLog: PR libstdc++/68350 PR libstdc++/93059 * include/bits/stl_algobase.h (__niter_base, __niter_wrap): Move to ... * include/bits/stl_iterator.h: ... here. * include/bits/stl_uninitialized.h (__check_constructible) (_GLIBCXX_USE_ASSIGN_FOR_INIT): Remove. [C++98] (__unwrappable_niter): New trait. (__uninitialized_copy): Replace use of std::copy. (uninitialized_copy): Fix Doxygen comments. Open-code memcpy optimization for C++11 and later. (__uninitialized_fill): Replace use of std::fill. (uninitialized_fill): Fix Doxygen comments. Open-code memset optimization for C++11 and later. (__uninitialized_fill_n): Replace use of std::fill_n. (uninitialized_fill_n): Fix Doxygen comments. Open-code memset optimization for C++11 and later. * testsuite/20_util/specialized_algorithms/uninitialized_copy/64476.cc: Adjust expected behaviour to match what the standard specifies. * testsuite/20_util/specialized_algorithms/uninitialized_fill_n/sizes.cc: Likewise. * testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc: Adjust dg-error directives. * testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc: Likewise. * testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc: Likewise. * testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc: Likewise. * testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc: Likewise. * testsuite/23_containers/vector/cons/89164.cc: Likewise. * testsuite/23_containers/vector/cons/89164_c++17.cc: Likewise. --- libstdc++-v3/include/bits/stl_algobase.h | 45 -- libstdc++-v3/include/bits/stl_iterator.h | 54 +++ libstdc++-v3/include/bits/stl_uninitialized.h | 385 +++++++++++++----- .../uninitialized_copy/1.cc | 3 +- .../uninitialized_copy/64476.cc | 6 +- .../uninitialized_copy/89164.cc | 3 +- .../uninitialized_copy_n/89164.cc | 3 +- .../uninitialized_fill/89164.cc | 3 +- .../uninitialized_fill_n/89164.cc | 3 +- .../uninitialized_fill_n/sizes.cc | 22 +- .../23_containers/vector/cons/89164.cc | 5 +- .../23_containers/vector/cons/89164_c++17.cc | 3 +- 12 files changed, 383 insertions(+), 152 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 384e5fdcdc9..751b7ad119b 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -308,51 +308,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __a; } - // Fallback implementation of the function in bits/stl_iterator.h used to - // remove the __normal_iterator wrapper. See copy, fill, ... - template - _GLIBCXX20_CONSTEXPR - inline _Iterator - __niter_base(_Iterator __it) - _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value) - { return __it; } - -#if __cplusplus < 201103L - template - _Ite - __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, - std::random_access_iterator_tag>&); - - template - _Ite - __niter_base(const ::__gnu_debug::_Safe_iterator< - ::__gnu_cxx::__normal_iterator<_Ite, _Cont>, _Seq, - std::random_access_iterator_tag>&); -#else - template - _GLIBCXX20_CONSTEXPR - decltype(std::__niter_base(std::declval<_Ite>())) - __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, - std::random_access_iterator_tag>&) - noexcept(std::is_nothrow_copy_constructible<_Ite>::value); -#endif - - // Reverse the __niter_base transformation to get a - // __normal_iterator back again (this assumes that __normal_iterator - // is only used to wrap random access iterators, like pointers). - template - _GLIBCXX20_CONSTEXPR - inline _From - __niter_wrap(_From __from, _To __res) - { return __from + (std::__niter_base(__res) - std::__niter_base(__from)); } - - // No need to wrap, iterator already has the right type. - template - _GLIBCXX20_CONSTEXPR - inline _Iterator - __niter_wrap(const _Iterator&, _Iterator __res) - { return __res; } - // All of these auxiliary structs serve two purposes. (1) Replace // calls to copy with memmove whenever possible. (Memmove, not memcpy, // because the input and output ranges are permitted to overlap.) diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 28a600c81cb..85b98ffff61 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -1338,10 +1338,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace +namespace __gnu_debug +{ + template + class _Safe_iterator; +} + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION + // Unwrap a __normal_iterator to get the underlying iterator + // (usually a pointer) template _GLIBCXX20_CONSTEXPR _Iterator @@ -1349,6 +1357,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value) { return __it.base(); } + // Fallback implementation of the function in bits/stl_iterator.h used to + // remove the __normal_iterator wrapper. See std::copy, std::fill, etc. + template + _GLIBCXX20_CONSTEXPR + inline _Iterator + __niter_base(_Iterator __it) + _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value) + { return __it; } + + // Overload for _Safe_iterator needs to be declared before __niter_base uses. +#if __cplusplus < 201103L + template + _Ite + __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, + std::random_access_iterator_tag>&); + + template + _Ite + __niter_base(const ::__gnu_debug::_Safe_iterator< + ::__gnu_cxx::__normal_iterator<_Ite, _Cont>, _Seq, + std::random_access_iterator_tag>&); +#else + template + _GLIBCXX20_CONSTEXPR + decltype(std::__niter_base(std::declval<_Ite>())) + __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, + std::random_access_iterator_tag>&) + noexcept(std::is_nothrow_copy_constructible<_Ite>::value); +#endif + + // Reverse the __niter_base transformation to get a + // __normal_iterator back again (this assumes that __normal_iterator + // is only used to wrap random access iterators, like pointers). + template + _GLIBCXX20_CONSTEXPR + inline _From + __niter_wrap(_From __from, _To __res) + { return __from + (std::__niter_base(__res) - std::__niter_base(__from)); } + + // No need to wrap, iterator already has the right type. + template + _GLIBCXX20_CONSTEXPR + inline _Iterator + __niter_wrap(const _Iterator&, _Iterator __res) + { return __res; } + #if __cplusplus >= 201103L && __cplusplus <= 201703L // Need to overload __to_address because the pointer_traits primary template // will deduce element_type of __normal_iterator as T* rather than T. diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h index f663057b1a1..ec980d66ccf 100644 --- a/libstdc++-v3/include/bits/stl_uninitialized.h +++ b/libstdc++-v3/include/bits/stl_uninitialized.h @@ -57,16 +57,16 @@ #define _STL_UNINITIALIZED_H 1 #if __cplusplus >= 201103L -#include +# include +# include // __to_address +# include // pair #endif -#include // copy +#include // __is_pointer +#include // distance, advance +#include // __niter_base #include // __alloc_traits -#if __cplusplus >= 201703L -#include -#endif - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -77,36 +77,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @cond undocumented -#if __cplusplus >= 201103L - template - constexpr bool - __check_constructible() - { - // Trivial types can have deleted constructors, but std::copy etc. - // only use assignment (or memmove) not construction, so we need an - // explicit check that construction from _Tp is actually valid, - // otherwise some ill-formed uses of std::uninitialized_xxx would - // compile without errors. This gives a nice clear error message. - static_assert(is_constructible<_ValueType, _Tp>::value, - "result type must be constructible from input type"); - - return true; - } - -// If the type is trivial we don't need to construct it, just assign to it. -// But trivial types can still have deleted or inaccessible assignment, -// so don't try to use std::copy or std::fill etc. if we can't assign. -# define _GLIBCXX_USE_ASSIGN_FOR_INIT(T, U) \ - __is_trivial(T) && __is_assignable(T&, U) \ - && std::__check_constructible() -#else -// No need to check if is_constructible for C++98. Trivial types have -// no user-declared constructors, so if the assignment is valid, construction -// should be too. -# define _GLIBCXX_USE_ASSIGN_FOR_INIT(T, U) \ - __is_trivial(T) && __is_assignable(T&, U) -#endif - template struct _UninitDestroyGuard { @@ -160,6 +130,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _UninitDestroyGuard(const _UninitDestroyGuard&); }; + // This is the default implementation of std::uninitialized_copy. template _GLIBCXX20_CONSTEXPR _ForwardIterator @@ -173,7 +144,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __result; } - template +#if __cplusplus < 201103L + + // True if we can unwrap _Iter to get a pointer by using std::__niter_base. + template + struct __unwrappable_niter + { + template struct __is_ptr { enum { __value = 0 }; }; + template struct __is_ptr<_Tp*> { enum { __value = 1 }; }; + + typedef __decltype(std::__niter_base(*(_Iter*)0)) _Base; + + enum { __value = __is_ptr<_Base>::__value }; + }; + + // Use template specialization for C++98 when 'if constexpr' can't be used. + template struct __uninitialized_copy { template @@ -186,53 +172,150 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<> struct __uninitialized_copy { + // Overload for generic iterators. template static _ForwardIterator __uninit_copy(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) - { return std::copy(__first, __last, __result); } - }; + { + if (__unwrappable_niter<_InputIterator>::__value + && __unwrappable_niter<_ForwardIterator>::__value) + { + __uninit_copy(std::__niter_base(__first), + std::__niter_base(__last), + std::__niter_base(__result)); + std::advance(__result, std::distance(__first, __last)); + return __result; + } + else + return std::__do_uninit_copy(__first, __last, __result); + } + // Overload for pointers. + template + static _Up* + __uninit_copy(_Tp* __first, _Tp* __last, _Up* __result) + { + // Ensure that we don't successfully memcpy in cases that should be + // ill-formed because is_constructible<_Up, _Tp&> is false. + typedef __typeof__(static_cast<_Up>(*__first)) __check + __attribute__((__unused__)); + + if (const ptrdiff_t __n = __last - __first) + { + __builtin_memcpy(__result, __first, __n * sizeof(_Tp)); + __result += __n; + } + return __result; + } + }; +#endif /// @endcond +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" /** * @brief Copies the range [first,last) into result. * @param __first An input iterator. * @param __last An input iterator. - * @param __result An output iterator. - * @return __result + (__first - __last) + * @param __result A forward iterator. + * @return __result + (__last - __first) * - * Like copy(), but does not require an initialized output range. + * Like std::copy, but does not require an initialized output range. */ template inline _ForwardIterator uninitialized_copy(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) { + // We can use memcpy to copy the ranges under these conditions: + // + // _ForwardIterator and _InputIterator are both contiguous iterators, + // so that we can turn them into pointers to pass to memcpy. + // Before C++20 we can't detect all contiguous iterators, so we only + // handle built-in pointers and __normal_iterator types. + // + // The value types of both iterators are trivially-copyable types, + // so that memcpy is not undefined and can begin the lifetime of + // new objects in the output range. + // + // Finally, memcpy from the source type, S, to the destination type, D, + // must give the same value as initialization of D from S would give. + // We require is_trivially_constructible to be true, but that is + // not sufficient. Some cases of trivial initialization are not just a + // bitwise copy, even when sizeof(D) == sizeof(S), + // e.g. bit_cast(1.0f) != 1u because the corresponding bits + // of the value representations do not have the same meaning. + // We cannot tell when this condition is true in general, + // so we rely on the __memcpyable trait. + +#if __cplusplus >= 201103L + using _Dest = decltype(std::__niter_base(__result)); + using _Src = decltype(std::__niter_base(__first)); + using _ValT = typename iterator_traits<_ForwardIterator>::value_type; + + if constexpr (!__is_trivially_constructible(_ValT, decltype(*__first))) + return std::__do_uninit_copy(__first, __last, __result); + else if constexpr (__memcpyable<_Dest, _Src>::__value) + { + ptrdiff_t __n = __last - __first; + if (__builtin_expect(__n > 1, true)) + { + using _ValT = typename remove_pointer<_Src>::type; + __builtin_memcpy(std::__niter_base(__result), + std::__niter_base(__first), + __n * sizeof(_ValT)); + __result += __n; + } + else if (__n == 1) // memcpy could overwrite tail padding + std::_Construct(__result++, *__first); + return __result; + } +#if __cpp_lib_concepts + else if constexpr (contiguous_iterator<_ForwardIterator> + && contiguous_iterator<_InputIterator>) + { + using _DestPtr = decltype(std::to_address(__result)); + using _SrcPtr = decltype(std::to_address(__first)); + if constexpr (__memcpyable<_DestPtr, _SrcPtr>::__value) + { + if (auto __n = __last - __first; __n > 1) [[likely]] + { + void* __dest = std::to_address(__result); + const void* __src = std::to_address(__first); + size_t __nbytes = __n * sizeof(remove_pointer_t<_DestPtr>); + __builtin_memmove(__dest, __src, __nbytes); + __result += __n; + } + else if (__n == 1) // memcpy could overwrite tail padding + std::construct_at(std::to_address(__result++), *__first); + return __result; + } + else + return std::__do_uninit_copy(__first, __last, __result); + } +#endif + else + return std::__do_uninit_copy(__first, __last, __result); +#else // C++98 typedef typename iterator_traits<_InputIterator>::value_type _ValueType1; typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType2; - // _ValueType1 must be trivially-copyable to use memmove, so don't - // bother optimizing to std::copy if it isn't. - // XXX Unnecessary because std::copy would check it anyway? - const bool __can_memmove = __is_trivial(_ValueType1); + const bool __can_memcpy + = __memcpyable<_ValueType1*, _ValueType2*>::__value + && __is_trivially_constructible(_ValueType2, __decltype(*__first)); -#if __cplusplus < 201103L - typedef typename iterator_traits<_InputIterator>::reference _From; -#else - using _From = decltype(*__first); + return __uninitialized_copy<__can_memcpy>:: + __uninit_copy(__first, __last, __result); #endif - const bool __assignable - = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType2, _From); - - return std::__uninitialized_copy<__can_memmove && __assignable>:: - __uninit_copy(__first, __last, __result); } +#pragma GCC diagnostic pop /// @cond undocumented + // This is the default implementation of std::uninitialized_fill. template _GLIBCXX20_CONSTEXPR void __do_uninit_fill(_ForwardIterator __first, _ForwardIterator __last, @@ -244,12 +327,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __guard.release(); } - template +#if __cplusplus < 201103L + // Use template specialization for C++98 when 'if constexpr' can't be used. + template struct __uninitialized_fill { template - static void - __uninit_fill(_ForwardIterator __first, _ForwardIterator __last, + static void + __uninit_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) { std::__do_uninit_fill(__first, __last, __x); } }; @@ -257,56 +342,129 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<> struct __uninitialized_fill { + // Overload for generic iterators. template - static void - __uninit_fill(_ForwardIterator __first, _ForwardIterator __last, + static void + __uninit_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) - { std::fill(__first, __last, __x); } - }; + { + if (__unwrappable_niter<_ForwardIterator>::__value) + __uninit_fill(std::__niter_base(__first), + std::__niter_base(__last), + __x); + else + std::__do_uninit_copy(__first, __last, __x); + } + // Overload for pointers. + template + static void + __uninit_fill(_Up* __first, _Up* __last, const _Tp& __x) + { + // Ensure that we don't successfully memset in cases that should be + // ill-formed because is_constructible<_Up, const _Tp&> is false. + typedef __typeof__(static_cast<_Up>(__x)) __check + __attribute__((__unused__)); + + if (__first != __last) + __builtin_memset(__first, (int)__x, __last - __first); + } + }; +#endif /// @endcond /** * @brief Copies the value x into the range [first,last). - * @param __first An input iterator. - * @param __last An input iterator. + * @param __first A forward iterator. + * @param __last A forward iterator. * @param __x The source value. * @return Nothing. * - * Like fill(), but does not require an initialized output range. + * Like std::fill, but does not require an initialized output range. */ template inline void uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) { + // We would like to use memset to optimize this loop when possible. + // As for std::uninitialized_copy, the optimization requires + // contiguous iterators and trivially copyable value types, + // with the additional requirement that sizeof(_Tp) == 1 because + // memset only writes single bytes. + + // FIXME: We could additionally enable this for 1-byte enums. + // Maybe any 1-byte Val if is_trivially_constructible? + typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; - // Trivial types do not need a constructor to begin their lifetime, - // so try to use std::fill to benefit from its memset optimization. - const bool __can_fill - = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType, const _Tp&); +#if __cplusplus >= 201103L +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" + if constexpr (__is_byte<_ValueType>::__value) + if constexpr (is_same<_ValueType, _Tp>::value + || is_integral<_Tp>::value) + { + using _BasePtr = decltype(std::__niter_base(__first)); + if constexpr (is_pointer<_BasePtr>::value) + { + void* __dest = std::__niter_base(__first); + ptrdiff_t __n = __last - __first; + if (__builtin_expect(__n > 0, true)) + __builtin_memset(__dest, (unsigned char)__x, __n); + return; + } +#if __cpp_lib_concepts + else if constexpr (contiguous_iterator<_ForwardIterator>) + { + auto __dest = std::__to_address(__first); + auto __n = __last - __first; + if (__builtin_expect(__n > 0, true)) + __builtin_memset(__dest, (unsigned char)__x, __n); + return; + } +#endif + } + std::__do_uninit_fill(__first, __last, __x); +#pragma GCC diagnostic pop +#else // C++98 + const bool __can_memset = __is_byte<_ValueType>::__value + && __is_integer<_Tp>::__value; - std::__uninitialized_fill<__can_fill>:: - __uninit_fill(__first, __last, __x); + __uninitialized_fill<__can_memset>::__uninit_fill(__first, __last, __x); +#endif } /// @cond undocumented + // This is the default implementation of std::uninitialized_fill_n. template _GLIBCXX20_CONSTEXPR _ForwardIterator __do_uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { _UninitDestroyGuard<_ForwardIterator> __guard(__first); - for (; __n > 0; --__n, (void) ++__first) +#if __cplusplus >= 201103L +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" + if constexpr (is_integral<_Size>::value) + // Loop will never terminate if __n is negative. + __glibcxx_assert(__n >= 0); + else if constexpr (is_floating_point<_Size>::value) + // Loop will never terminate if __n is not an integer. + __glibcxx_assert(__n >= 0 && static_cast(__n) == __n); +#pragma GCC diagnostic pop +#endif + for (; __n--; ++__first) std::_Construct(std::__addressof(*__first), __x); __guard.release(); return __first; } - template +#if __cplusplus < 201103L + // Use template specialization for C++98 when 'if constexpr' can't be used. + template struct __uninitialized_fill_n { template @@ -319,47 +477,92 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<> struct __uninitialized_fill_n { + // Overload for generic iterators. template static _ForwardIterator __uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) - { return std::fill_n(__first, __n, __x); } + { + if (__unwrappable_niter<_ForwardIterator>::__value) + { + _ForwardIterator __last = __first; + std::advance(__last, __n); + __uninitialized_fill::__uninit_fill(__first, __last, __x); + return __last; + } + else + return std::__do_uninit_fill_n(__first, __n, __x); + } }; - +#endif /// @endcond +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 1339. uninitialized_fill_n should return the end of its range /** * @brief Copies the value x into the range [first,first+n). - * @param __first An input iterator. + * @param __first A forward iterator. * @param __n The number of copies to make. * @param __x The source value. - * @return Nothing. + * @return __first + __n. * - * Like fill_n(), but does not require an initialized output range. + * Like std::fill_n, but does not require an initialized output range. */ template inline _ForwardIterator uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { + // See uninitialized_fill conditions. We also require _Size to be + // an integer. The standard only requires _Size to be decrementable + // and contextually convertible to bool, so don't assume first+n works. + + // FIXME: We could additionally enable this for 1-byte enums. + typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType; - // Trivial types do not need a constructor to begin their lifetime, - // so try to use std::fill_n to benefit from its optimizations. - const bool __can_fill - = _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType, const _Tp&) - // For arbitrary class types and floating point types we can't assume - // that __n > 0 and std::__size_to_integer(__n) > 0 are equivalent, - // so only use std::fill_n when _Size is already an integral type. - && __is_integer<_Size>::__value; +#if __cplusplus >= 201103L + if constexpr (__is_byte<_ValueType>::__value) + if constexpr (is_integral<_Tp>::value) + if constexpr (is_integral<_Size>::value) + { + using _BasePtr = decltype(std::__niter_base(__first)); + if constexpr (is_pointer<_BasePtr>::value) + { + void* __dest = std::__niter_base(__first); + if (__builtin_expect(__n > 0, true)) + { + __builtin_memset(__dest, (unsigned char)__x, __n); + __first += __n; + } + return __first; + } +#if __cpp_lib_concepts + else if constexpr (contiguous_iterator<_ForwardIterator>) + { + auto __dest = std::__to_address(__first); + if (__builtin_expect(__n > 0, true)) + { + __builtin_memset(__dest, (unsigned char)__x, __n); + __first += __n; + } + return __first; + } +#endif + } + return std::__do_uninit_fill_n(__first, __n, __x); +#else // C++98 + const bool __can_memset = __is_byte<_ValueType>::__value + && __is_integer<_Tp>::__value + && __is_integer<_Size>::__value; - return __uninitialized_fill_n<__can_fill>:: + return __uninitialized_fill_n<__can_memset>:: __uninit_fill_n(__first, __n, __x); +#endif } - -#undef _GLIBCXX_USE_ASSIGN_FOR_INIT +#pragma GCC diagnostic pop /// @cond undocumented @@ -619,7 +822,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = std::__addressof(*__first); std::_Construct(__val); if (++__first != __last) - std::fill(__first, __last, *__val); + std::uninitialized_fill(__first, __last, *__val); } }; @@ -653,7 +856,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = std::__addressof(*__first); std::_Construct(__val); ++__first; - __first = std::fill_n(__first, __n - 1, *__val); + __first = std::uninitialized_fill_n(__first, __n - 1, *__val); } return __first; } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc index 398d8690b56..27b3100d362 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc @@ -34,4 +34,5 @@ test01(T* result) T t[1]; std::uninitialized_copy(t, t+1, result); // { dg-error "here" } } -// { dg-error "must be constructible from input type" "" { target *-*-* } 0 } +// { dg-error "no matching function" "construct_at" { target c++20 } 0 } +// { dg-error "use of deleted function" "T::T(const T&)" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/64476.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/64476.cc index 2f7dda3417d..e99338dff39 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/64476.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/64476.cc @@ -54,8 +54,10 @@ test01() std::uninitialized_copy(a, a+10, b); - VERIFY(constructed == 0); - VERIFY(assigned == 10); + // In GCC 14 and older std::uninitialized_copy was optimized to std::copy + // and so used assignments not construction, but that was non-conforming. + VERIFY(constructed == 10); + VERIFY(assigned == 0); } int diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc index 48c16da4d32..6e978a7e36c 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc @@ -35,4 +35,5 @@ void test01() std::uninitialized_copy(x, x+1, p); // { dg-error "here" } } -// { dg-error "must be constructible" "" { target *-*-* } 0 } +// { dg-error "no matching function" "construct_at" { target c++20 } 0 } +// { dg-error "use of deleted function" "X(const X&)" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc index 4e8fb0f4af2..96156208372 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc @@ -32,4 +32,5 @@ void test01() std::uninitialized_copy_n(x, 1, p); // { dg-error "here" } } -// { dg-error "must be constructible" "" { target *-*-* } 0 } +// { dg-error "no matching function" "construct_at" { target c++20 } 0 } +// { dg-error "use of deleted function" "X(const X&)" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc index 8353b5882f0..0dcaa1aa9c3 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc @@ -32,4 +32,5 @@ void f() std::uninitialized_fill(p, p+1, x); // { dg-error "here" } } -// { dg-error "must be constructible" "" { target *-*-* } 0 } +// { dg-error "no matching function" "construct_at" { target c++20 } 0 } +// { dg-error "use of deleted function" "X(const X&)" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc index 4b38c673d32..9b61157b934 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc @@ -32,4 +32,5 @@ void test01() std::uninitialized_fill_n(p, 1, x); // { dg-error "here" } } -// { dg-error "must be constructible" "" { target *-*-* } 0 } +// { dg-error "no matching function" "construct_at" { target c++20 } 0 } +// { dg-error "use of deleted function" "X(const X&)" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/sizes.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/sizes.cc index e2ba9355c56..876ec5443fb 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/sizes.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/sizes.cc @@ -24,21 +24,35 @@ void test01() { int i[4] = { }; - std::uninitialized_fill_n(i, 2.0001, 0xabcd); + // Floating-point n should work, but only if it's an integer value. + std::uninitialized_fill_n(i, 3.0, 0xabcd); VERIFY( i[0] == 0xabcd ); VERIFY( i[1] == 0xabcd ); VERIFY( i[2] == 0xabcd ); VERIFY( i[3] == 0 ); } -// The standard only requires that n>0 and --n are valid expressions. +// The standard only requires that `if (n--)` is a valid expression. struct Size { int value; - void operator--() { --value; } + struct testable + { +#if __cplusplus >= 201103L + explicit +#endif + operator bool() const { return nonzero; } - int operator>(void*) { return value != 0; } + bool nonzero; + }; + + testable operator--(int) + { + testable t = { value != 0 }; + --value; + return t; + } }; void diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc index 106963ecbb9..36907dc508e 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc @@ -32,7 +32,7 @@ void test01() X x[1]; // Should not be able to create vector using uninitialized_copy: std::vector v1{x, x+1}; // { dg-error "here" "" { target c++17_down } } - // { dg-error "deleted function 'X::X" "" { target c++20 } 0 } + // { dg-error "deleted function 'X::X" "" { target *-*-* } 0 } } void test02() @@ -41,8 +41,7 @@ void test02() // Should not be able to create vector using uninitialized_fill_n: std::vector v2{2u, Y{}}; // { dg-error "here" "" { target c++17_down } } - // { dg-error "deleted function .*Y::Y" "" { target c++20 } 0 } + // { dg-error "deleted function .*Y::Y" "" { target *-*-* } 0 } } -// { dg-error "must be constructible from input type" "" { target *-*-* } 0 } // { dg-prune-output "construct_at" } diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc index 09d3dc6f93d..07d4bab9117 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc @@ -32,8 +32,7 @@ void test03() // Can create initializer_list with C++17 guaranteed copy elision, // but shouldn't be able to copy from it with uninitialized_copy: std::vector v3{X{}, X{}, X{}}; // { dg-error "here" "" { target c++17_only } } - // { dg-error "deleted function .*X::X" "" { target c++20 } 0 } + // { dg-error "deleted function .*X::X" "" { target *-*-* } 0 } } -// { dg-error "must be constructible from input type" "" { target *-*-* } 0 } // { dg-prune-output "construct_at" } From patchwork Tue Oct 15 14:20:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1997504 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=FPU4oz76; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XSc0C48LJz1xv6 for ; Wed, 16 Oct 2024 01:28:23 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D8B3D3858C48 for ; Tue, 15 Oct 2024 14:28:19 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 3F1943858D28 for ; Tue, 15 Oct 2024 14:26:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3F1943858D28 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3F1943858D28 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002403; cv=none; b=A0X9ifnP4sVsiD9y69Dz+6D7CBaJkP/BAM0Rd05cwcmcil0UZ8WH67hqkKlm/svv5MvTHEjQYatz+yKDwWghX47n3cOWkqGKoqbb7cCuDq70M/2IYf/dY20h+nNlTMhspykxcSZ+7vbUlJO2lHBxpma/saFMrKk9x2wHvtE0qMY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002403; c=relaxed/simple; bh=TFm7/PoroHw/MVqSSEVUqC8OrN2arPBA4PpH3kINHkU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=hQGDbvQgQhblfIGCHFeIfIJBSuEZ2neIREfQWhBgUnT9kVlTYtClZQXmKQ9dYNl21d3MpP0lCOna3QdmU5VlkdhspSX1oiTSrnC8eFTimnfeo88vbFJKxWHCPRMo/8Zu1LS4fZwNBIHu3kV6cP0bk16AWW5UNU5cE8xhUSuEx3g= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1729002400; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lpLMV/d4A4KIbQ0ktEFPSiWX9D4f+3bc93Aomh4S6uE=; b=FPU4oz76+TCdcfJjn4K4b48izj3YwdsO0flae8m5x5kWINP7qd4lECAAdOiW0X1iMtrTsQ xQFqYY1ESr/IdbPu///e7IUbXeDbeTcHVPslq5iWoU8vq90qrOUzAlNFxoWsUPRK0XZM5m 25TgfMCgl4DmlS6ksmbbLGoHhiwHF2o= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-661-FyNDlEi0OVanAru7VKz9WA-1; Tue, 15 Oct 2024 10:26:36 -0400 X-MC-Unique: FyNDlEi0OVanAru7VKz9WA-1 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id BAEAE1955D92; Tue, 15 Oct 2024 14:26:35 +0000 (UTC) Received: from localhost (unknown [10.42.28.16]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 176111956056; Tue, 15 Oct 2024 14:26:34 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 2/7] libstdc++: Make __normal_iterator constexpr, always_inline, nodiscard Date: Tue, 15 Oct 2024 15:20:12 +0100 Message-ID: <20241015142630.2148792-2-jwakely@redhat.com> In-Reply-To: <20241015142630.2148792-1-jwakely@redhat.com> References: <20241015142630.2148792-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Tested x86_64-linux. -- >8 -- The __gnu_cxx::__normal_iterator type we use for std::vector::iterator is not specified by the standard, it's an implementation detail. This means it's not constrained by the rule that forbids strengthening constexpr. We can make it meet the constexpr iterator requirements for older standards, not only when it's required to be for C++20. For the non-const member functions they can't be constexpr in C++11, so use _GLIBCXX14_CONSTEXPR for those. For all constructors, const members and non-member operator overloads, use _GLIBCXX_CONSTEXPR or just constexpr. We can also liberally add [[nodiscard]] and [[gnu::always_inline]] attributes to those functions. Also change some internal helpers for std::move_iterator which can be unconditionally constexpr and marked nodiscard. libstdc++-v3/ChangeLog: * include/bits/stl_iterator.h (__normal_iterator): Make all members and overloaded operators constexpr before C++20. (__niter_base, __niter_wrap, __to_address): Add nodiscard and always_inline attributes. (__make_move_if_noexcept_iterator, __miter_base): Add nodiscard and make unconditionally constexpr. --- libstdc++-v3/include/bits/stl_iterator.h | 125 ++++++++++++++--------- 1 file changed, 76 insertions(+), 49 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 85b98ffff61..3cc10a160bd 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -656,7 +656,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template _GLIBCXX20_CONSTEXPR - auto + inline auto __niter_base(reverse_iterator<_Iterator> __it) -> decltype(__make_reverse_iterator(__niter_base(__it.base()))) { return __make_reverse_iterator(__niter_base(__it.base())); } @@ -668,7 +668,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template _GLIBCXX20_CONSTEXPR - auto + inline auto __miter_base(reverse_iterator<_Iterator> __it) -> decltype(__make_reverse_iterator(__miter_base(__it.base()))) { return __make_reverse_iterator(__miter_base(__it.base())); } @@ -1060,23 +1060,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using iterator_concept = std::__detail::__iter_concept<_Iterator>; #endif - _GLIBCXX_CONSTEXPR __normal_iterator() _GLIBCXX_NOEXCEPT - : _M_current(_Iterator()) { } + __attribute__((__always_inline__)) + _GLIBCXX_CONSTEXPR + __normal_iterator() _GLIBCXX_NOEXCEPT + : _M_current() { } - explicit _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) + explicit _GLIBCXX_CONSTEXPR __normal_iterator(const _Iterator& __i) _GLIBCXX_NOEXCEPT : _M_current(__i) { } // Allow iterator to const_iterator conversion #if __cplusplus >= 201103L template> - _GLIBCXX20_CONSTEXPR + [[__gnu__::__always_inline__]] + constexpr __normal_iterator(const __normal_iterator<_Iter, _Container>& __i) noexcept #else // N.B. _Container::pointer is not actually in container requirements, // but is present in std::vector and std::basic_string. template + __attribute__((__always_inline__)) __normal_iterator(const __normal_iterator<_Iter, typename __enable_if< (std::__are_same<_Iter, typename _Container::pointer>::__value), @@ -1085,17 +1090,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_current(__i.base()) { } // Forward iterator requirements - _GLIBCXX20_CONSTEXPR + + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD + _GLIBCXX_CONSTEXPR reference operator*() const _GLIBCXX_NOEXCEPT { return *_M_current; } - _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD + _GLIBCXX_CONSTEXPR pointer operator->() const _GLIBCXX_NOEXCEPT { return _M_current; } - _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) + _GLIBCXX14_CONSTEXPR __normal_iterator& operator++() _GLIBCXX_NOEXCEPT { @@ -1103,13 +1112,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) + _GLIBCXX14_CONSTEXPR __normal_iterator operator++(int) _GLIBCXX_NOEXCEPT { return __normal_iterator(_M_current++); } // Bidirectional iterator requirements - _GLIBCXX20_CONSTEXPR + + __attribute__((__always_inline__)) + _GLIBCXX14_CONSTEXPR __normal_iterator& operator--() _GLIBCXX_NOEXCEPT { @@ -1117,38 +1129,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) + _GLIBCXX14_CONSTEXPR __normal_iterator operator--(int) _GLIBCXX_NOEXCEPT { return __normal_iterator(_M_current--); } // Random access iterator requirements - _GLIBCXX20_CONSTEXPR + + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD + _GLIBCXX_CONSTEXPR reference operator[](difference_type __n) const _GLIBCXX_NOEXCEPT { return _M_current[__n]; } - _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) + _GLIBCXX14_CONSTEXPR __normal_iterator& operator+=(difference_type __n) _GLIBCXX_NOEXCEPT { _M_current += __n; return *this; } - _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD + _GLIBCXX_CONSTEXPR __normal_iterator operator+(difference_type __n) const _GLIBCXX_NOEXCEPT { return __normal_iterator(_M_current + __n); } - _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) + _GLIBCXX14_CONSTEXPR __normal_iterator& operator-=(difference_type __n) _GLIBCXX_NOEXCEPT { _M_current -= __n; return *this; } - _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD + _GLIBCXX_CONSTEXPR __normal_iterator operator-(difference_type __n) const _GLIBCXX_NOEXCEPT { return __normal_iterator(_M_current - __n); } - _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD + _GLIBCXX_CONSTEXPR const _Iterator& base() const _GLIBCXX_NOEXCEPT { return _M_current; } @@ -1164,7 +1184,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cpp_lib_three_way_comparison template - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr bool operator==(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) @@ -1175,7 +1195,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() == __rhs.base(); } template - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr std::__detail::__synth3way_t<_IteratorR, _IteratorL> operator<=>(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) @@ -1183,7 +1203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); } template - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr bool operator==(const __normal_iterator<_Iterator, _Container>& __lhs, const __normal_iterator<_Iterator, _Container>& __rhs) @@ -1194,7 +1214,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() == __rhs.base(); } template - [[nodiscard]] + [[nodiscard, __gnu__::__always_inline__]] constexpr std::__detail::__synth3way_t<_Iterator> operator<=>(const __normal_iterator<_Iterator, _Container>& __lhs, const __normal_iterator<_Iterator, _Container>& __rhs) @@ -1203,7 +1223,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #else // Forward iterator requirements template - _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator==(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) @@ -1211,7 +1231,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() == __rhs.base(); } template - _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator==(const __normal_iterator<_Iterator, _Container>& __lhs, const __normal_iterator<_Iterator, _Container>& __rhs) @@ -1219,7 +1239,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() == __rhs.base(); } template - _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator!=(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) @@ -1227,7 +1247,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() != __rhs.base(); } template - _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator!=(const __normal_iterator<_Iterator, _Container>& __lhs, const __normal_iterator<_Iterator, _Container>& __rhs) @@ -1236,7 +1256,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Random access iterator requirements template - _GLIBCXX_NODISCARD + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator<(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) @@ -1244,7 +1264,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() < __rhs.base(); } template - _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR inline bool operator<(const __normal_iterator<_Iterator, _Container>& __lhs, const __normal_iterator<_Iterator, _Container>& __rhs) @@ -1252,7 +1272,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() < __rhs.base(); } template - _GLIBCXX_NODISCARD + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator>(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) @@ -1260,7 +1280,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() > __rhs.base(); } template - _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator>(const __normal_iterator<_Iterator, _Container>& __lhs, const __normal_iterator<_Iterator, _Container>& __rhs) @@ -1268,7 +1288,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() > __rhs.base(); } template - _GLIBCXX_NODISCARD + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) @@ -1276,7 +1296,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() <= __rhs.base(); } template - _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator<=(const __normal_iterator<_Iterator, _Container>& __lhs, const __normal_iterator<_Iterator, _Container>& __rhs) @@ -1284,7 +1304,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() <= __rhs.base(); } template - _GLIBCXX_NODISCARD + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) @@ -1292,7 +1312,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() >= __rhs.base(); } template - _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline bool operator>=(const __normal_iterator<_Iterator, _Container>& __lhs, const __normal_iterator<_Iterator, _Container>& __rhs) @@ -1307,8 +1327,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template #if __cplusplus >= 201103L // DR 685. - [[__nodiscard__]] _GLIBCXX20_CONSTEXPR - inline auto + [[__nodiscard__, __gnu__::__always_inline__]] + constexpr auto operator-(const __normal_iterator<_IteratorL, _Container>& __lhs, const __normal_iterator<_IteratorR, _Container>& __rhs) noexcept -> decltype(__lhs.base() - __rhs.base()) @@ -1320,7 +1340,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() - __rhs.base(); } template - _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline typename __normal_iterator<_Iterator, _Container>::difference_type operator-(const __normal_iterator<_Iterator, _Container>& __lhs, const __normal_iterator<_Iterator, _Container>& __rhs) @@ -1328,7 +1348,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __lhs.base() - __rhs.base(); } template - _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR inline __normal_iterator<_Iterator, _Container> operator+(typename __normal_iterator<_Iterator, _Container>::difference_type __n, const __normal_iterator<_Iterator, _Container>& __i) @@ -1349,24 +1369,26 @@ namespace std _GLIBCXX_VISIBILITY(default) _GLIBCXX_BEGIN_NAMESPACE_VERSION // Unwrap a __normal_iterator to get the underlying iterator - // (usually a pointer) + // (usually a pointer). See uses in std::copy, std::fill, etc. template + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR - _Iterator + inline _Iterator __niter_base(__gnu_cxx::__normal_iterator<_Iterator, _Container> __it) _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value) { return __it.base(); } - // Fallback implementation of the function in bits/stl_iterator.h used to - // remove the __normal_iterator wrapper. See std::copy, std::fill, etc. + // Fallback implementation used for iterators that can't be unwrapped. template + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR inline _Iterator __niter_base(_Iterator __it) _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value) { return __it; } - // Overload for _Safe_iterator needs to be declared before __niter_base uses. + // Overload for _Safe_iterator needs to be declared before uses of + // std::__niter_base because we call it qualified so isn't found by ADL. #if __cplusplus < 201103L template _Ite @@ -1391,6 +1413,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // __normal_iterator back again (this assumes that __normal_iterator // is only used to wrap random access iterators, like pointers). template + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR inline _From __niter_wrap(_From __from, _To __res) @@ -1398,6 +1421,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // No need to wrap, iterator already has the right type. template + __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR inline _Iterator __niter_wrap(const _Iterator&, _Iterator __res) @@ -1407,6 +1431,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Need to overload __to_address because the pointer_traits primary template // will deduce element_type of __normal_iterator as T* rather than T. template + [[__gnu__::__always_inline__]] _GLIBCXX_NODISCARD constexpr auto __to_address(const __gnu_cxx::__normal_iterator<_Iterator, _Container>& __it) noexcept @@ -1861,7 +1886,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = __conditional_t<__move_if_noexcept_cond ::value_type>::value, _Iterator, move_iterator<_Iterator>>> - inline _GLIBCXX17_CONSTEXPR _ReturnType + [[__nodiscard__]] + constexpr _ReturnType __make_move_if_noexcept_iterator(_Iterator __i) { return _ReturnType(__i); } @@ -1870,13 +1896,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template::value, const _Tp*, move_iterator<_Tp*>>> - inline _GLIBCXX17_CONSTEXPR _ReturnType + [[__nodiscard__]] + constexpr _ReturnType __make_move_if_noexcept_iterator(_Tp* __i) { return _ReturnType(__i); } template - _GLIBCXX20_CONSTEXPR - auto + [[__nodiscard__]] + constexpr auto __niter_base(move_iterator<_Iterator> __it) -> decltype(make_move_iterator(__niter_base(__it.base()))) { return make_move_iterator(__niter_base(__it.base())); } @@ -1889,8 +1916,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; template - _GLIBCXX20_CONSTEXPR - auto + [[__nodiscard__]] + constexpr auto __miter_base(move_iterator<_Iterator> __it) -> decltype(__miter_base(__it.base())) { return __miter_base(__it.base()); } From patchwork Tue Oct 15 14:20:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1997506 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=KMcWyHDR; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XSc2j0Jvvz1xvK for ; Wed, 16 Oct 2024 01:30:37 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 339AF3858031 for ; Tue, 15 Oct 2024 14:30:35 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 845983858C42 for ; Tue, 15 Oct 2024 14:26:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 845983858C42 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 845983858C42 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002411; cv=none; b=cZUTqRsUv5E72UVTfV7jl50jWd/iNP0zRR3qrxexLoIMA2DG9HmCgF9FjBuFtU4QPj40k36pfXkP70/fFtgvt5HWuNmL4VlyIljwR/ay9wP8FfSAd0x9RwiysCPvLaS1STiKC7dsCVrDPA1YyKCPTc4dWFivGqkLLgK9FD/XurI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002411; c=relaxed/simple; bh=H+rORfBFiY9OmXUIOrFOETDtHzSERnxf9Axgc3BA6Gs=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=IRw0EI0kYTo0+/oSsIR/IT49n96aLeIGTqLsU0WxtjOWeBNCDwv3qVG//g0ehbcVcumANeDYF8HaoNuQKagHlv0VRGwFFEWx9uVx2PHjQRXWhPSsvqOliI2nkNx4W87UC+m1puYi1e2AEE4V4aAhEIYhk1Na/OFm1hXnPSTgTI8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1729002403; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hxi7CrBxq5NSRyqcPWjb+ucn/MTH+uVfoc7nYuFZxXs=; b=KMcWyHDRJTRGqYJpap9nc4sdgcyRUpSmvyWYOtcmVfJLgUKUKb0hy7DZpfQhg0F0gWkXaZ 6T0g16GbEySyjhdCIC4/adh0LKWY2fwoezT3ZntKoTmGubAjd+TYWGzv23T7BDg/D7hZ1Q 0N7QgS3mn0AXmxiwF5566xpFUuSiGBc= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-675-96YjydfZNa-dzdABM6i7Vg-1; Tue, 15 Oct 2024 10:26:40 -0400 X-MC-Unique: 96YjydfZNa-dzdABM6i7Vg-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6E52219560BE; Tue, 15 Oct 2024 14:26:39 +0000 (UTC) Received: from localhost (unknown [10.42.28.16]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B732930001A7; Tue, 15 Oct 2024 14:26:37 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 3/7] libstdc++: Inline memmove optimizations for std::copy etc. [PR115444] Date: Tue, 15 Oct 2024 15:20:13 +0100 Message-ID: <20241015142630.2148792-3-jwakely@redhat.com> In-Reply-To: <20241015142630.2148792-1-jwakely@redhat.com> References: <20241015142630.2148792-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP, URI_HEX autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org This is a slightly different approach to C++98 compatibility than used in patch 1/1 of this series for the uninitialized algos. It worked out a bit cleaner this way for these algos, I think. Tested x86_64-linux. -- >8 -- This removes all the __copy_move class template specializations that decide how to optimize std::copy and std::copy_n. We can inline those optimizations into the algorithms, using if-constexpr (and macros for C++98 compatibility) and remove the code dispatching to the various class template specializations. Doing this means we implement the optimization directly for std::copy_n instead of deferring to std::copy, That avoids the unwanted consequence of advancing the iterator in copy_n only to take the difference later to get back to the length that we already had in copy_n originally (as described in PR 115444). With the new flattened implementations, we can also lower contiguous iterators to pointers in std::copy/std::copy_n/std::copy_backwards, so that they benefit from the same memmove optimizations as pointers. There's a subtlety though: contiguous iterators can potentially throw exceptions to exit the algorithm early. So we can only transform the loop to memmove if dereferencing the iterator is noexcept. We don't check that incrementing the iterator is noexcept because we advance the contiguous iterators before using memmove, so that if incrementing would throw, that happens first. I am writing a proposal (P3249R0) which would make this unnecessary, so I hope we can drop the nothrow requirements later. This change also solves PR 114817 by checking is_trivially_assignable before optimizing copy/copy_n etc. to memmove. It's not enough to check that the types are trivially copyable (a precondition for using memmove at all), we also need to check that the specific assignment that would be performed by the algorithm is also trivial. Replacing a non-trivial assignment with memmove would be observable, so not allowed. libstdc++-v3/ChangeLog: PR libstdc++/115444 PR libstdc++/114817 * include/bits/stl_algo.h (__copy_n): Remove generic overload and overload for random access iterators. (copy_n): Inline generic version of __copy_n here. Do not defer to std::copy for random access iterators. * include/bits/stl_algobase.h (__copy_move): Remove. (__nothrow_contiguous_iterator, __memcpyable_iterators): New concepts. (__assign_one, _GLIBCXX_TO_ADDR, _GLIBCXX_ADVANCE): New helpers. (__copy_move_a2): Inline __copy_move logic and conditional memmove optimization into the most generic overload. (__copy_n_a): Likewise. (__copy_move_backward): Remove. (__copy_move_backward_a2): Inline __copy_move_backward logic and memmove optimization into the most generic overload. * testsuite/20_util/specialized_algorithms/uninitialized_copy/114817.cc: New test. * testsuite/20_util/specialized_algorithms/uninitialized_copy_n/114817.cc: New test. * testsuite/25_algorithms/copy/114817.cc: New test. * testsuite/25_algorithms/copy/115444.cc: New test. * testsuite/25_algorithms/copy_n/114817.cc: New test. --- libstdc++-v3/include/bits/stl_algo.h | 24 +- libstdc++-v3/include/bits/stl_algobase.h | 426 +++++++++--------- .../uninitialized_copy/114817.cc | 39 ++ .../uninitialized_copy_n/114817.cc | 39 ++ .../testsuite/25_algorithms/copy/114817.cc | 38 ++ .../testsuite/25_algorithms/copy/115444.cc | 93 ++++ .../testsuite/25_algorithms/copy_n/114817.cc | 38 ++ 7 files changed, 469 insertions(+), 228 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/114817.cc create mode 100644 libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/114817.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/copy/114817.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/copy/115444.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/copy_n/114817.cc diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index a1ef665506d..489ce7e14d2 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -665,25 +665,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __result; } - template - _GLIBCXX20_CONSTEXPR - _OutputIterator - __copy_n(_InputIterator __first, _Size __n, - _OutputIterator __result, input_iterator_tag) - { - return std::__niter_wrap(__result, - __copy_n_a(__first, __n, - std::__niter_base(__result), true)); - } - - template - _GLIBCXX20_CONSTEXPR - inline _OutputIterator - __copy_n(_RandomAccessIterator __first, _Size __n, - _OutputIterator __result, random_access_iterator_tag) - { return std::copy(__first, __first + __n, __result); } - /** * @brief Copies the range [first,first+n) into [result,result+n). * @ingroup mutating_algorithms @@ -714,8 +695,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __glibcxx_requires_can_increment(__first, __n2); __glibcxx_requires_can_increment(__result, __n2); - return std::__copy_n(__first, __n2, __result, - std::__iterator_category(__first)); + auto __res = std::__copy_n_a(std::__niter_base(__first), __n2, + std::__niter_base(__result), true); + return std::__niter_wrap(__result, std::move(__res)); } /** diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 751b7ad119b..5f77b00be9b 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -77,6 +77,7 @@ #endif #if __cplusplus >= 202002L # include +# include // std::to_address #endif namespace std _GLIBCXX_VISIBILITY(default) @@ -308,110 +309,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __a; } - // All of these auxiliary structs serve two purposes. (1) Replace - // calls to copy with memmove whenever possible. (Memmove, not memcpy, - // because the input and output ranges are permitted to overlap.) - // (2) If we're using random access iterators, then write the loop as - // a for loop with an explicit count. - - template - struct __copy_move - { - template - _GLIBCXX20_CONSTEXPR - static _OI - __copy_m(_II __first, _II __last, _OI __result) - { - for (; __first != __last; ++__result, (void)++__first) - *__result = *__first; - return __result; - } - }; - -#if __cplusplus >= 201103L - template - struct __copy_move - { - template - _GLIBCXX20_CONSTEXPR - static _OI - __copy_m(_II __first, _II __last, _OI __result) - { - for (; __first != __last; ++__result, (void)++__first) - *__result = std::move(*__first); - return __result; - } - }; -#endif - - template<> - struct __copy_move - { - template - _GLIBCXX20_CONSTEXPR - static _OI - __copy_m(_II __first, _II __last, _OI __result) - { - typedef typename iterator_traits<_II>::difference_type _Distance; - for(_Distance __n = __last - __first; __n > 0; --__n) - { - *__result = *__first; - ++__first; - ++__result; - } - return __result; - } - - template - static void - __assign_one(_Tp* __to, _Up* __from) - { *__to = *__from; } - }; - -#if __cplusplus >= 201103L - template<> - struct __copy_move - { - template - _GLIBCXX20_CONSTEXPR - static _OI - __copy_m(_II __first, _II __last, _OI __result) - { - typedef typename iterator_traits<_II>::difference_type _Distance; - for(_Distance __n = __last - __first; __n > 0; --__n) - { - *__result = std::move(*__first); - ++__first; - ++__result; - } - return __result; - } - - template - static void - __assign_one(_Tp* __to, _Up* __from) - { *__to = std::move(*__from); } - }; -#endif - - template - struct __copy_move<_IsMove, true, random_access_iterator_tag> - { - template - _GLIBCXX20_CONSTEXPR - static _Up* - __copy_m(_Tp* __first, _Tp* __last, _Up* __result) - { - const ptrdiff_t _Num = __last - __first; - if (__builtin_expect(_Num > 1, true)) - __builtin_memmove(__result, __first, sizeof(_Tp) * _Num); - else if (_Num == 1) - std::__copy_move<_IsMove, false, random_access_iterator_tag>:: - __assign_one(__result, __first); - return __result + _Num; - } - }; - _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template @@ -461,21 +358,127 @@ _GLIBCXX_END_NAMESPACE_CONTAINER _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*>); #endif // HOSTED - template - _GLIBCXX20_CONSTEXPR - inline _OI - __copy_move_a2(_II __first, _II __last, _OI __result) - { - typedef typename iterator_traits<_II>::iterator_category _Category; -#ifdef __cpp_lib_is_constant_evaluated - if (std::is_constant_evaluated()) - return std::__copy_move<_IsMove, false, _Category>:: - __copy_m(__first, __last, __result); +#if __cpp_lib_concepts + // N.B. this is not the same as nothrow-forward-iterator, which doesn't + // require noexcept operations, it just says it's undefined if they throw. + // Here we require them to be actually noexcept. + template + concept __nothrow_contiguous_iterator + = contiguous_iterator<_Iter> && requires (_Iter __i) { + // If this operation can throw then the iterator could cause + // the algorithm to exit early via an exception, in which case + // we can't use memcpy. + { *__i } noexcept; + }; + + template + concept __memcpyable_iterators + = __nothrow_contiguous_iterator<_OutIter> + && __nothrow_contiguous_iterator<_InIter> + && sized_sentinel_for<_Sent, _InIter> + && requires (_OutIter __o, _InIter __i, _Sent __s) { + requires !!__memcpyable::__value; + { __i != __s } noexcept; + }; #endif - return std::__copy_move<_IsMove, __memcpyable<_OI, _II>::__value, - _Category>::__copy_m(__first, __last, __result); + +#if __cplusplus < 201103L + // Used by __copy_move_a2, __copy_n_a and __copy_move_backward_a2 to + // get raw pointers so that calls to __builtin_memmove will compile, + // because C++98 can't use 'if constexpr' so statements that use memmove + // with pointer arguments need to also compile for arbitrary iterator types. + template __attribute__((__always_inline__)) + inline void* __ptr_or_null(_Iter) { return 0; } + template __attribute__((__always_inline__)) + inline void* __ptr_or_null(_Tp* __p) { return (void*)__p; } +# define _GLIBCXX_TO_ADDR(P) std::__ptr_or_null(P) + // Used to advance output iterators (std::advance requires InputIterator). + template __attribute__((__always_inline__)) + inline void __ptr_advance(_Iter&, ptrdiff_t) { } + template __attribute__((__always_inline__)) + inline void __ptr_advance(_Tp*& __p, ptrdiff_t __n) { __p += __n; } +# define _GLIBCXX_ADVANCE(P, N) std::__ptr_advance(P, N) +#else + // For C++11 mode the __builtin_memmove calls are guarded by 'if constexpr' + // so we know the iterators used with memmove are guaranteed to be pointers. +# define _GLIBCXX_TO_ADDR(P) P +# define _GLIBCXX_ADVANCE(P, N) P += N +#endif + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" + template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR + inline void + __assign_one(_OutIter& __out, _InIter& __in) + { +#if __cplusplus >= 201103L + if constexpr (_IsMove) + *__out = std::move(*__in); + else +#endif + *__out = *__in; } + template + _GLIBCXX20_CONSTEXPR + inline _OutIter + __copy_move_a2(_InIter __first, _Sent __last, _OutIter __result) + { + typedef __decltype(*__first) _InRef; + typedef __decltype(*__result) _OutRef; + if _GLIBCXX_CONSTEXPR (!__is_trivially_assignable(_OutRef, _InRef)) + { } /* Skip the optimizations and use the loop at the end. */ +#ifdef __cpp_lib_is_constant_evaluated + else if (std::is_constant_evaluated()) + { } /* Skip the optimizations and use the loop at the end. */ +#endif + else if _GLIBCXX_CONSTEXPR (__memcpyable<_OutIter, _InIter>::__value) + { + ptrdiff_t __n = std::distance(__first, __last); + if (__builtin_expect(__n > 1, true)) + { + __builtin_memmove(_GLIBCXX_TO_ADDR(__result), + _GLIBCXX_TO_ADDR(__first), + __n * sizeof(*__first)); + _GLIBCXX_ADVANCE(__result, __n); + } + else if (__n == 1) + { + std::__assign_one<_IsMove>(__result, __first); + ++__result; + } + return __result; + } +#if __cpp_lib_concepts + else if constexpr (__memcpyable_iterators<_OutIter, _InIter, _Sent>) + { + if (auto __n = __last - __first; __n > 1) [[likely]] + { + void* __dest = std::to_address(__result); + const void* __src = std::to_address(__first); + size_t __nbytes = __n * sizeof(iter_value_t<_InIter>); + // Advance the iterators first, in case doing so throws. + __result += __n; + __first += __n; + __builtin_memmove(__dest, __src, __nbytes); + } + else if (__n == 1) + { + std::__assign_one<_IsMove>(__result, __first); + ++__result; + } + return __result; + } +#endif + + for (; __first != __last; ++__result, (void)++__first) + std::__assign_one<_IsMove>(__result, __first); + return __result; + } +#pragma GCC diagnostic pop + template _OI @@ -537,12 +540,56 @@ _GLIBCXX_END_NAMESPACE_CONTAINER const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&, const ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>&); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // for if-constexpr template _GLIBCXX20_CONSTEXPR _OutputIterator __copy_n_a(_InputIterator __first, _Size __n, _OutputIterator __result, bool) { + typedef __decltype(*__first) _InRef; + typedef __decltype(*__result) _OutRef; + if _GLIBCXX_CONSTEXPR (!__is_trivially_assignable(_OutRef, _InRef)) + { } /* Skip the optimizations and use the loop at the end. */ +#ifdef __cpp_lib_is_constant_evaluated + else if (std::is_constant_evaluated()) + { } /* Skip the optimizations and use the loop at the end. */ +#endif + else if _GLIBCXX_CONSTEXPR (__memcpyable<_OutputIterator, + _InputIterator>::__value) + { + if (__builtin_expect(__n > 1, true)) + { + __builtin_memmove(_GLIBCXX_TO_ADDR(__result), + _GLIBCXX_TO_ADDR(__first), + __n * sizeof(*__first)); + _GLIBCXX_ADVANCE(__result, __n); + } + else if (__n == 1) + *__result++ = *__first; + return __result; + } +#if __cpp_lib_concepts + else if constexpr (__memcpyable_iterators<_OutputIterator, + _InputIterator>) + { + if (__n > 1) [[likely]] + { + void* __dest = std::to_address(__result); + const void* __src = std::to_address(__first); + size_t __nbytes = __n * sizeof(iter_value_t<_InputIterator>); + // Advance the iterators first, in case doing so throws. + __result += __n; + __first += __n; + __builtin_memmove(__dest, __src, __nbytes); + } + else if (__n == 1) + *__result++ = *__first; + return __result; + } +#endif + if (__n > 0) { while (true) @@ -557,6 +604,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER } return __result; } +#pragma GCC diagnostic pop #if _GLIBCXX_HOSTED template @@ -644,105 +692,69 @@ _GLIBCXX_END_NAMESPACE_CONTAINER #define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::copy(_Tp, _Up, _Vp) #endif - template - struct __copy_move_backward - { - template - _GLIBCXX20_CONSTEXPR - static _BI2 - __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) - { - while (__first != __last) - *--__result = *--__last; - return __result; - } - }; - -#if __cplusplus >= 201103L - template - struct __copy_move_backward - { - template - _GLIBCXX20_CONSTEXPR - static _BI2 - __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) - { - while (__first != __last) - *--__result = std::move(*--__last); - return __result; - } - }; -#endif - - template<> - struct __copy_move_backward - { - template - _GLIBCXX20_CONSTEXPR - static _BI2 - __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) - { - typename iterator_traits<_BI1>::difference_type - __n = __last - __first; - for (; __n > 0; --__n) - *--__result = *--__last; - return __result; - } - }; - -#if __cplusplus >= 201103L - template<> - struct __copy_move_backward - { - template - _GLIBCXX20_CONSTEXPR - static _BI2 - __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) - { - typename iterator_traits<_BI1>::difference_type - __n = __last - __first; - for (; __n > 0; --__n) - *--__result = std::move(*--__last); - return __result; - } - }; -#endif - - template - struct __copy_move_backward<_IsMove, true, random_access_iterator_tag> - { - template - _GLIBCXX20_CONSTEXPR - static _Up* - __copy_move_b(_Tp* __first, _Tp* __last, _Up* __result) - { - const ptrdiff_t _Num = __last - __first; - if (__builtin_expect(_Num > 1, true)) - __builtin_memmove(__result - _Num, __first, sizeof(_Tp) * _Num); - else if (_Num == 1) - std::__copy_move<_IsMove, false, random_access_iterator_tag>:: - __assign_one(__result - 1, __first); - return __result - _Num; - } - }; - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" template _GLIBCXX20_CONSTEXPR inline _BI2 __copy_move_backward_a2(_BI1 __first, _BI1 __last, _BI2 __result) { - typedef typename iterator_traits<_BI1>::iterator_category _Category; + typedef __decltype(*__first) _InRef; + typedef __decltype(*__result) _OutRef; + if _GLIBCXX_CONSTEXPR (!__is_trivially_assignable(_OutRef, _InRef)) + { } /* Skip the optimizations and use the loop at the end. */ #ifdef __cpp_lib_is_constant_evaluated - if (std::is_constant_evaluated()) - return std::__copy_move_backward<_IsMove, false, _Category>:: - __copy_move_b(__first, __last, __result); + else if (std::is_constant_evaluated()) + { } /* Skip the optimizations and use the loop at the end. */ #endif - return std::__copy_move_backward<_IsMove, - __memcpyable<_BI2, _BI1>::__value, - _Category>::__copy_move_b(__first, - __last, - __result); + else if _GLIBCXX_CONSTEXPR (__memcpyable<_BI2, _BI1>::__value) + { + ptrdiff_t __n = std::distance(__first, __last); + std::advance(__result, -__n); + if (__builtin_expect(__n > 1, true)) + { + __builtin_memmove(_GLIBCXX_TO_ADDR(__result), + _GLIBCXX_TO_ADDR(__first), + __n * sizeof(*__first)); + } + else if (__n == 1) + std::__assign_one<_IsMove>(__result, __first); + return __result; + } +#if __cpp_lib_concepts + else if constexpr (__memcpyable_iterators<_BI2, _BI1>) + { + if (auto __n = __last - __first; __n > 1) [[likely]] + { + const void* __src = std::to_address(__first); + // Advance the iterators first, in case doing so throws. + __result -= __n; + __first += __n; + void* __dest = std::to_address(__result); + size_t __nbytes = __n * sizeof(iter_value_t<_BI1>); + __builtin_memmove(__dest, __src, __nbytes); + } + else if (__n == 1) + { + --__result; + std::__assign_one<_IsMove>(__result, __first); + } + return __result; + } +#endif + + while (__first != __last) + { + --__last; + --__result; + std::__assign_one<_IsMove>(__result, __last); + } + return __result; } +#pragma GCC diagnostic pop + +#undef _GLIBCXX_TO_ADDR +#undef _GLIBCXX_ADVANCE template _GLIBCXX20_CONSTEXPR diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/114817.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/114817.cc new file mode 100644 index 00000000000..531b863e143 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/114817.cc @@ -0,0 +1,39 @@ +// { dg-do run { target c++11 } } + +// Bug libstdc++/114817 - Wrong codegen for std::copy of +// "trivially copyable but not trivially assignable" type + +#include +#include + +int constructions = 0; + +struct NonTrivialCons +{ + NonTrivialCons() = default; + NonTrivialCons(int v) : val(v) { } + NonTrivialCons(const volatile NonTrivialCons&) = delete; + template + NonTrivialCons(const NonTrivialCons& o) + : val(o.val) + { + ++constructions; + } + + int val; +}; + +static_assert(std::is_trivially_copyable::value); + +int main() +{ + NonTrivialCons src[2]{1, 2}; + NonTrivialCons dst[2]; +#if __cplusplus < 201703L + constructions = 0; +#endif + std::uninitialized_copy(src, src+2, dst); + VERIFY( constructions == 2 ); + VERIFY( dst[0].val == src[0].val ); + VERIFY( dst[1].val == src[1].val ); +} diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/114817.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/114817.cc new file mode 100644 index 00000000000..531b863e143 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/114817.cc @@ -0,0 +1,39 @@ +// { dg-do run { target c++11 } } + +// Bug libstdc++/114817 - Wrong codegen for std::copy of +// "trivially copyable but not trivially assignable" type + +#include +#include + +int constructions = 0; + +struct NonTrivialCons +{ + NonTrivialCons() = default; + NonTrivialCons(int v) : val(v) { } + NonTrivialCons(const volatile NonTrivialCons&) = delete; + template + NonTrivialCons(const NonTrivialCons& o) + : val(o.val) + { + ++constructions; + } + + int val; +}; + +static_assert(std::is_trivially_copyable::value); + +int main() +{ + NonTrivialCons src[2]{1, 2}; + NonTrivialCons dst[2]; +#if __cplusplus < 201703L + constructions = 0; +#endif + std::uninitialized_copy(src, src+2, dst); + VERIFY( constructions == 2 ); + VERIFY( dst[0].val == src[0].val ); + VERIFY( dst[1].val == src[1].val ); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/114817.cc b/libstdc++-v3/testsuite/25_algorithms/copy/114817.cc new file mode 100644 index 00000000000..b5fcc6bb037 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy/114817.cc @@ -0,0 +1,38 @@ +// { dg-do run { target c++11 } } + +// Bug libstdc++/114817 - Wrong codegen for std::copy of +// "trivially copyable but not trivially assignable" type + +#include +#include + +int assignments = 0; + +struct NonTrivialAssignment +{ + NonTrivialAssignment(int v) : val(v) { } + NonTrivialAssignment(const NonTrivialAssignment&) = default; + void operator=(const volatile NonTrivialAssignment&) = delete; + template + NonTrivialAssignment& + operator=(const NonTrivialAssignment& o) + { + ++assignments; + val = o.val; + return *this; + } + + int val; +}; + +static_assert(std::is_trivially_copyable::value); + +int main() +{ + NonTrivialAssignment src[2]{1, 2}; + NonTrivialAssignment dst[2]{3, 4}; + std::copy(src, src+2, dst); + VERIFY( assignments == 2 ); + VERIFY( dst[0].val == src[0].val ); + VERIFY( dst[1].val == src[1].val ); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/115444.cc b/libstdc++-v3/testsuite/25_algorithms/copy/115444.cc new file mode 100644 index 00000000000..fa629abea5f --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy/115444.cc @@ -0,0 +1,93 @@ +// { dg-do run } +// { dg-require-normal-mode "debug mode checks use operator-(Iter, Iter)" } + +#include +#include +#include + +const int g = 0; + +struct Iter { + typedef long difference_type; + typedef int value_type; + typedef const int& reference; + typedef const int* pointer; +#if __cpp_lib_concepts + using iterator_category = std::contiguous_iterator_tag; +#else + typedef std::random_access_iterator_tag iterator_category; +#endif + + Iter(const int* p = 0, const int* limit = 0) : ptr(p), limit(limit) { } + + const int& operator*() const { +#ifdef __cpp_exceptions + if (ptr == limit) + throw 1; +#endif + return *ptr; + } + const int* operator->() const { return ptr; } + const int& operator[](long n) const { return ptr[n]; } + + Iter& operator++() { ++ptr; return *this; } + Iter operator++(int) { Iter tmp = *this; ++ptr; return tmp; } + Iter& operator--() { --ptr; return *this; } + Iter operator--(int) { Iter tmp = *this; --ptr; return tmp; } + + Iter& operator+=(int n) { ptr += n; return *this; } + Iter& operator-=(int n) { ptr -= n; return *this; } + + friend Iter operator+(int n, Iter it) { return it += n; } + friend Iter operator+(Iter it, int n) { return it += n; } + friend Iter operator-(Iter it, int n) { return it -= n; } + + bool operator==(const Iter& it) const { return ptr == it.ptr; } + bool operator!=(const Iter& it) const { return ptr != it.ptr; } + bool operator<(const Iter& it) const { return ptr < it.ptr; } + bool operator>(const Iter& it) const { return ptr > it.ptr; } + bool operator<=(const Iter& it) const { return ptr <= it.ptr; } + bool operator>=(const Iter& it) const { return ptr >= it.ptr; } + + // std::copy should not need to take the difference between two iterators: + friend int operator-(Iter, Iter) { VERIFY( ! "operator- called" ); } + +private: + const int* ptr; + const int* limit; +}; + +void +test_pr115444_no_difference() +{ + int from = 1; + int to = 0; + Iter iter(&from); + // This should not use operator-(Iter, Iter) + std::copy(iter, iter+1, &to); +} + +void +test_pr115444_exceptional() +{ +#if __cpp_exceptions + int from[3] = { 1, 2, 3 }; + int to[3] = { -1, -1, -1 }; + Iter iter(from, from+2); + try { + std::copy(iter, iter + 3, to); + } catch (int) { + } + // std::copy should exit via exception on third dereference. + // This precludes using memcpy or memmove to optimize the copying. + VERIFY( to[0] == 1 ); + VERIFY( to[1] == 2 ); + VERIFY( to[2] == -1 ); +#endif +} + +int main() +{ + test_pr115444_no_difference(); + test_pr115444_exceptional(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_n/114817.cc b/libstdc++-v3/testsuite/25_algorithms/copy_n/114817.cc new file mode 100644 index 00000000000..09e181f3fd0 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/114817.cc @@ -0,0 +1,38 @@ +// { dg-do run { target c++11 } } + +// Bug libstdc++/114817 - Wrong codegen for std::copy of +// "trivially copyable but not trivially assignable" type + +#include +#include + +int assignments = 0; + +struct NonTrivialAssignment +{ + NonTrivialAssignment(int v) : val(v) { } + NonTrivialAssignment(const NonTrivialAssignment&) = default; + void operator=(const volatile NonTrivialAssignment&) = delete; + template + NonTrivialAssignment& + operator=(const NonTrivialAssignment& o) + { + ++assignments; + val = o.val; + return *this; + } + + int val; +}; + +static_assert(std::is_trivially_copyable::value); + +int main() +{ + NonTrivialAssignment src[2]{1, 2}; + NonTrivialAssignment dst[2]{3, 4}; + std::copy_n(src, 2, dst); + VERIFY( assignments == 2 ); + VERIFY( dst[0].val == src[0].val ); + VERIFY( dst[1].val == src[1].val ); +} From patchwork Tue Oct 15 14:20:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1997503 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=aW8XJdcl; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XSbzy5HfTz1xv6 for ; Wed, 16 Oct 2024 01:28:13 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 79A7D385780F for ; Tue, 15 Oct 2024 14:28:11 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 2CF203858C98 for ; Tue, 15 Oct 2024 14:26:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2CF203858C98 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2CF203858C98 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002414; cv=none; b=MDH5xVnQreI808DyRkJoopm5uSQyVS41Lj4eIN6/Ozd2ZnrjGRwUniaoZbjLy2fa5qYT3cPIEk434TR5H2U6wcLR7S9Se3qY7s/QQ1ZHhuR2DeviikYlawhKRQ8V/IHZ5YCreWWaVrOOEVBeDOiz5b9ApZE/dh7h1JXOojqFhMQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002414; c=relaxed/simple; bh=Xw7yCwRkMAm71kB/wmgViw3/rYue+SmyWzJ3ucent2U=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=SWd01OpI2E3pwa6PwOKc5d7zNylynNNamHIOCfX/I0v/5rCXVAaUslQm1v3QTNqvDREvjBN3dH8OIN8lB+7tRC8zjWhZECd1yXmVoRlwG5hXIw3tirJHY+mFyRrMdlM/WrRAKsnbWRbJON0AAJA7NtRDbt+WYSDva1mJb4FOsa0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1729002405; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=D1Hs62SgOLgganQZAV4txTM6LSZ9Xp33xcxWQ0XiALo=; b=aW8XJdclLuYh6S7GbQ8WLJ8QKrf2vqIUaJV21FQhbxgN7pAi6twUMSPhZzWyJcvZGeTrcS AkAyZuijT7RslgvNVqVcwdruItAw1Ig5TrL3CWbEFtZdjbuyTwcVwZd4SszEw+gevMlawE Fxq0Nl5O1n07riA4aVfJFP27pGVoc8A= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-378-IhsnpzqdMuWd3iYjFxBhXg-1; Tue, 15 Oct 2024 10:26:42 -0400 X-MC-Unique: IhsnpzqdMuWd3iYjFxBhXg-1 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id AE3D61955EA5; Tue, 15 Oct 2024 14:26:41 +0000 (UTC) Received: from localhost (unknown [10.42.28.16]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2E7711956089; Tue, 15 Oct 2024 14:26:40 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 4/7] libstdc++: Remove indirection to __find_if in std::find etc. Date: Tue, 15 Oct 2024 15:20:14 +0100 Message-ID: <20241015142630.2148792-4-jwakely@redhat.com> In-Reply-To: <20241015142630.2148792-1-jwakely@redhat.com> References: <20241015142630.2148792-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Tested x86_64-linux. -- >8 -- There doesn't seem to be a lot of benefit in reusing __find_if with __gnu_cxx::__ops predicates, since they aren't going to actually instantiate any less code if we use different predicates every time (e.g. __ops::__negate, or __ops::__iter_equals_val, or __ops::__pred_iter). And now that std::find no longer calls __find_if (because it just does a loop directly), we can make the _Iter_equals_val case of __find_if call std::find, to take advantage of its memchr optimization. This benefits other algos like search_n which use __find_if with _Iter_equals_val. libstdc++-v3/ChangeLog: * include/bits/stl_algo.h (__find_if_not): Do loop here instead of using __find_if with __gnu_cxx::__ops predicate. (find_if): Likewise. (find): Move to ... * include/bits/stl_algobase.h (find): ... here. (__find_if): Overload for _Iter_equals_val predicate. --- libstdc++-v3/include/bits/stl_algo.h | 63 +++--------------------- libstdc++-v3/include/bits/stl_algobase.h | 61 +++++++++++++++++++++++ 2 files changed, 68 insertions(+), 56 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index 489ce7e14d2..05c1dbd07b6 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -105,15 +105,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::iter_swap(__result, __b); } - /// Provided for stable_partition to use. + // Used by std::find_if_not and __stable_partition. template _GLIBCXX20_CONSTEXPR inline _InputIterator __find_if_not(_InputIterator __first, _InputIterator __last, _Predicate __pred) { - return std::__find_if(__first, __last, - __gnu_cxx::__ops::__negate(__pred)); + while (__first != __last && __pred(__first)) + ++__first; + return __first; } /// Like find_if_not(), but uses and updates a count of the @@ -3810,57 +3811,6 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } #endif // C++17 - /** - * @brief Find the first occurrence of a value in a sequence. - * @ingroup non_mutating_algorithms - * @param __first An input iterator. - * @param __last An input iterator. - * @param __val The value to find. - * @return The first iterator @c i in the range @p [__first,__last) - * such that @c *i == @p __val, or @p __last if no such iterator exists. - */ - template - _GLIBCXX20_CONSTEXPR - inline _InputIterator - find(_InputIterator __first, _InputIterator __last, const _Tp& __val) - { - // concept requirements - __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) - __glibcxx_function_requires(_EqualOpConcept< - typename iterator_traits<_InputIterator>::value_type, _Tp>) - __glibcxx_requires_valid_range(__first, __last); - -#if __cpp_if_constexpr && __glibcxx_type_trait_variable_templates - using _ValT = typename iterator_traits<_InputIterator>::value_type; - if constexpr (__can_use_memchr_for_find<_ValT, _Tp>) - if constexpr (is_pointer_v -#if __cpp_lib_concepts - || contiguous_iterator<_InputIterator> -#endif - ) - { - // If conversion to the 1-byte value_type alters the value, - // it would not be found by std::find using equality comparison. - // We need to check this here, because otherwise something like - // memchr("a", 'a'+256, 1) would give a false positive match. - if (!(static_cast<_ValT>(__val) == __val)) - return __last; - else if (!__is_constant_evaluated()) - { - const void* __p0 = std::__to_address(__first); - const int __ival = static_cast(__val); - if (auto __n = std::distance(__first, __last); __n > 0) - if (auto __p1 = __builtin_memchr(__p0, __ival, __n)) - return __first + ((const char*)__p1 - (const char*)__p0); - return __last; - } - } -#endif - - return std::__find_if(__first, __last, - __gnu_cxx::__ops::__iter_equals_val(__val)); - } - /** * @brief Find the first element in a sequence for which a * predicate is true. @@ -3883,8 +3833,9 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO typename iterator_traits<_InputIterator>::value_type>) __glibcxx_requires_valid_range(__first, __last); - return std::__find_if(__first, __last, - __gnu_cxx::__ops::__pred_iter(__pred)); + while (__first != __last && !__pred(*__first)) + ++__first; + return __first; } /** diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 5f77b00be9b..34e1cf7322f 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -2077,6 +2077,58 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO } #endif + /** + * @brief Find the first occurrence of a value in a sequence. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __val The value to find. + * @return The first iterator @c i in the range @p [__first,__last) + * such that @c *i == @p __val, or @p __last if no such iterator exists. + */ + template + _GLIBCXX20_CONSTEXPR + inline _InputIterator + find(_InputIterator __first, _InputIterator __last, const _Tp& __val) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_InputIterator>::value_type, _Tp>) + __glibcxx_requires_valid_range(__first, __last); + +#if __cpp_if_constexpr && __glibcxx_type_trait_variable_templates + using _ValT = typename iterator_traits<_InputIterator>::value_type; + if constexpr (__can_use_memchr_for_find<_ValT, _Tp>) + if constexpr (is_pointer_v +#if __cpp_lib_concepts + || contiguous_iterator<_InputIterator> +#endif + ) + { + // If conversion to the 1-byte value_type alters the value, + // it would not be found by std::find using equality comparison. + // We need to check this here, because otherwise something like + // memchr("a", 'a'+256, 1) would give a false positive match. + if (!(static_cast<_ValT>(__val) == __val)) + return __last; + else if (!__is_constant_evaluated()) + { + const void* __p0 = std::__to_address(__first); + const int __ival = static_cast(__val); + if (auto __n = std::distance(__first, __last); __n > 0) + if (auto __p1 = __builtin_memchr(__p0, __ival, __n)) + return __first + ((const char*)__p1 - (const char*)__p0); + return __last; + } + } +#endif + + while (__first != __last && !(*__first == __val)) + ++__first; + return __first; + } + _GLIBCXX_END_NAMESPACE_ALGO // Implementation of std::find_if, also used in std::remove_if and others. @@ -2091,6 +2143,15 @@ _GLIBCXX_END_NAMESPACE_ALGO return __first; } + // When the predicate is just comparing to a value we can use std::find, + // which is optimized to memchr for some types. + template + _GLIBCXX20_CONSTEXPR + inline _Iterator + __find_if(_Iterator __first, _Iterator __last, + __gnu_cxx::__ops::_Iter_equals_val<_Value> __pred) + { return _GLIBCXX_STD_A::find(__first, __last, __pred._M_value); } + template _GLIBCXX20_CONSTEXPR typename iterator_traits<_InputIterator>::difference_type From patchwork Tue Oct 15 14:20:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1997501 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=OTatYWdM; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XSbzc2Phtz1xv6 for ; Wed, 16 Oct 2024 01:27:55 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A9CC93858C53 for ; Tue, 15 Oct 2024 14:27:52 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 6A0703858C51 for ; Tue, 15 Oct 2024 14:26:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6A0703858C51 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6A0703858C51 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002415; cv=none; b=ELwS1BSGf679uI+kztedJtTIVNJ52Mvg9x/1o8p0arGUr/eBRYBhCLadSJ29HcKAchLRSL1MixAnUD7JEA4YEBuRLuWPYFHo7cJxJhELpN+dmx9kBgwrxBd9B7S4qeTbO6go+nd6LEvCnQyIFWS6gjo/nfe8t6IbhB/vOImUNWc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002415; c=relaxed/simple; bh=+Jea2MESp+NCgX7MAyxLtRf7urtJA49qTb7A66xNaU4=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=TEXY37DQhFESkuq7GVgefVUzl2J00lqx3xxjlCPLfTSskSSI8JDS/XKo2asYNSRh41BQPdqglCbOynizEutS86oPU6phU31xWSwi8WlTwNb7irPnvz5gteaxTkUF6LKZp5a53hfGgfuk4bW25OnU0KsY/o3uhIBAq09CXF1O0hg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1729002406; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GTtivYDWocmgMIWnE+nQa1lKVzDd/AZFIWqaEVQSWno=; b=OTatYWdM8Fx4K8IyZX1Gd+ReP76LKttQt5iWGfKm4+accCCj2tBEZiUgHkjiOdaIovVKLD 4UaRNrq0uAiZCdpuxdbX7jiliIs46qHYnfEgrdo+PKkbtnM7NYJE4PR5d5x5kA9UR/gSPK aeTgE6CYHoKT+O+SN+otjxQ32O7KbnI= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-569-bMujs257P4W4g-dbQJpYlg-1; Tue, 15 Oct 2024 10:26:44 -0400 X-MC-Unique: bMujs257P4W4g-dbQJpYlg-1 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C8F621955F28; Tue, 15 Oct 2024 14:26:43 +0000 (UTC) Received: from localhost (unknown [10.42.28.16]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 342AA1956089; Tue, 15 Oct 2024 14:26:43 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 5/7] libstdc++: Add nodiscard to std::find Date: Tue, 15 Oct 2024 15:20:15 +0100 Message-ID: <20241015142630.2148792-5-jwakely@redhat.com> In-Reply-To: <20241015142630.2148792-1-jwakely@redhat.com> References: <20241015142630.2148792-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Tested x86_64-linux. -- >8 -- libstdc++-v3/ChangeLog: * include/bits/stl_algobase.h (find): Add nodiscard. --- libstdc++-v3/include/bits/stl_algobase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 34e1cf7322f..d9d1d00b113 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -2087,7 +2087,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO * such that @c *i == @p __val, or @p __last if no such iterator exists. */ template - _GLIBCXX20_CONSTEXPR + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR inline _InputIterator find(_InputIterator __first, _InputIterator __last, const _Tp& __val) { From patchwork Tue Oct 15 14:20:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1997507 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=V3ZnVHKQ; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XSc4j5sZDz1xvK for ; Wed, 16 Oct 2024 01:32:21 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 08F3E3858C98 for ; Tue, 15 Oct 2024 14:32:20 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 28B7A385801B for ; Tue, 15 Oct 2024 14:26:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 28B7A385801B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 28B7A385801B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002420; cv=none; b=P3l4FzhYtCuWgeOWviBt8PYWQSXaPIsppNrJaq/nMtRhUjGk0wNexspKaVyOc1NTAFK9A/1R07EOFV/EiwQVN+/qxajTNS5UYW1v4aWxGcsWhn/JjLC42yNF+OeETEDWdTPi3onWE9q1t99rQNGyfoTrtt6Q2WVQpwfYHsn4JPo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002420; c=relaxed/simple; bh=MsnN9tuArAGuobkbuJcwtJJ3CPJhjFxtIns1gw7zEYU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=kPJWOmFZ5MzuS+MCU5SWirfHHTH4tlY0yVLoWDpj2Zh/w2txLrlkTjW9k2H8EHYy7+eIEyD5tgwcUnkpexBUV2NFxqr+IkYyIZ+ZpVvwbn70A2tshczxFHoI29cx4Xsh/bCxDe0px75VNmBQSrceHi5GIIIfxFAnbHL8AHDMMLU= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1729002409; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HQRowgmm+mT3ZQ3eBlHRKE3kj4jZhplrRJHjA8pimqU=; b=V3ZnVHKQEAqgnHujfqMJjmszXjuBx9aSE2zKJucvAhMqWSQOZNd5QVUqkjb8CqNH/57ASz XzXbaSEgqvLxVIBKzqKPH0PuKFOG7rEc9WKjWQb2JXC8VBvJroNtg913anAKtNTj6jN6pO JmHP4gjpQsxZsQLeDzUxxdbogcAHLUw= Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-451-hMWyFLOPO8WfQYZG8fRs9A-1; Tue, 15 Oct 2024 10:26:47 -0400 X-MC-Unique: hMWyFLOPO8WfQYZG8fRs9A-1 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 316AD19560B5; Tue, 15 Oct 2024 14:26:46 +0000 (UTC) Received: from localhost (unknown [10.42.28.16]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 8BA951956089; Tue, 15 Oct 2024 14:26:45 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 6/7] libstdc++: Add always_inline to some one-liners in Date: Tue, 15 Oct 2024 15:20:16 +0100 Message-ID: <20241015142630.2148792-6-jwakely@redhat.com> In-Reply-To: <20241015142630.2148792-1-jwakely@redhat.com> References: <20241015142630.2148792-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Tested x86_64-linux. -- >8 -- We implement std::copy, std::fill etc. as a series of calls to other overloads which incrementally peel off layers of iterator wrappers. This adds a high abstraction penalty for -O0 and potentially even -O1. Add the always_inline attribute to several functions that are just a single return statement (and maybe a static_assert, or some concept-checking assertions which are disabled by default). libstdc++-v3/ChangeLog: * include/bits/stl_algobase.h (__copy_move_a1, __copy_move_a) (__copy_move_backward_a1, __copy_move_backward_a, move_backward) (__fill_a1, __fill_a, fill, __fill_n_a, fill_n, __equal_aux): Add always_inline attribute to one-line forwarding functions. --- libstdc++-v3/include/bits/stl_algobase.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index d9d1d00b113..b2f5b96d46e 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -500,12 +500,14 @@ _GLIBCXX_END_NAMESPACE_CONTAINER __copy_move_a1(_II, _II, _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*>); template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline _OI __copy_move_a1(_II __first, _II __last, _OI __result) { return std::__copy_move_a2<_IsMove>(__first, __last, __result); } template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline _OI __copy_move_a(_II __first, _II __last, _OI __result) @@ -757,6 +759,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER #undef _GLIBCXX_ADVANCE template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline _BI2 __copy_move_backward_a1(_BI1 __first, _BI1 __last, _BI2 __result) @@ -785,6 +788,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*>); template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline _OI __copy_move_backward_a(_II __first, _II __last, _OI __result) @@ -840,6 +844,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER * that the start of the output range may overlap [first,last). */ template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline _BI2 copy_backward(_BI1 __first, _BI1 __last, _BI2 __result) @@ -875,6 +880,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER * that the start of the output range may overlap [first,last). */ template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline _BI2 move_backward(_BI1 __first, _BI1 __last, _BI2 __result) @@ -958,6 +964,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER } template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline void __fill_a1(::__gnu_cxx::__normal_iterator<_Ite, _Cont> __first, @@ -977,6 +984,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER const bool&); template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline void __fill_a(_FIte __first, _FIte __last, const _Tp& __value) @@ -1002,6 +1010,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER * to @c memset or @c wmemset. */ template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline void fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) @@ -1108,6 +1117,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER std::input_iterator_tag); template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline _OutputIterator __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value, @@ -1120,6 +1130,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER } template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline _OutputIterator __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value, @@ -1132,6 +1143,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER } template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline _OutputIterator __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value, @@ -1167,6 +1179,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER // DR 865. More algorithms that throw away information // DR 426. search_n(), fill_n(), and generate_n() with negative n template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline _OI fill_n(_OI __first, _Size __n, const _Tp& __value) @@ -1246,6 +1259,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER } template + __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR inline bool __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2) From patchwork Tue Oct 15 14:20:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1997502 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=d3pLjLln; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XSbzn2268z1xv6 for ; Wed, 16 Oct 2024 01:28:04 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CB2943858C3A for ; Tue, 15 Oct 2024 14:28:02 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 7602D3858420 for ; Tue, 15 Oct 2024 14:26:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7602D3858420 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 7602D3858420 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002426; cv=none; b=GmHenbUPnqI5+WCyQI3RUQxnBxXEP76xYjZn1uF87t+QtbHS73t+G5ypr1FFtzBCHneHwHQErSI/ySLZtIHRkdPD16Dd1TAi173zMyhPtpvoWZ3FteR+zEpnwK1VcEMwAzWJP+JhSo2Oz+RBZm6YlnfxXVZ7dRICZqZuLPzLDaI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729002426; c=relaxed/simple; bh=lTBMDEXDfU4qLA3aDJCIbdCKElcLOvGwrQykemivvrE=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Nq/9DeL6Ti5lcFvgy/sdv3a6ADHrbQZq9XWFCfMWYhey5e0i6uQ98bMisM8SbkF7gTMKz+wxlmUmp+TfQat4Qu2uiH9axF02DPKDxCMSpsv1b5bPOE4KECftfDpzVhaOQYW3uwIXr7fcePkBFJLC+zqowBEbS2cC623WCUWzfOs= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1729002412; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8Y11V1boPbBe6pzjseIr2cJXFJ87xCz+0sIpYErqUiw=; b=d3pLjLlnUoERzbIpv53MRlDpIQwNj/9S/nfmsxyhgEabX8HAxqbJMMDWkQcqOibbuQFR5G QzwBuviDq4nXGJOYzTuHYCYxQ5V3CQWGKZx6878wRoFTrCdInpFtcUysCMbAK9abr+0ZCw JaTQJ1S76BaQ34VJyDC74+Cuf+gsyK8= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-638-SyebHiCvOPONogJRs4P54A-1; Tue, 15 Oct 2024 10:26:49 -0400 X-MC-Unique: SyebHiCvOPONogJRs4P54A-1 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 57CD11955F3E; Tue, 15 Oct 2024 14:26:48 +0000 (UTC) Received: from localhost (unknown [10.42.28.16]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id C7BB61955E8F; Tue, 15 Oct 2024 14:26:47 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH 7/7] libstdc++: Reuse std::__assign_one in Date: Tue, 15 Oct 2024 15:20:17 +0100 Message-ID: <20241015142630.2148792-7-jwakely@redhat.com> In-Reply-To: <20241015142630.2148792-1-jwakely@redhat.com> References: <20241015142630.2148792-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Tested x86_64-linux. -- >8 -- Use std::__assign_one instead of ranges::__assign_one. Adjust the uses, because std::__assign_one has the arguments in the opposite order (the same order as an assignment expression). libstdc++-v3/ChangeLog: * include/bits/ranges_algobase.h (ranges::__assign_one): Remove. (__copy_or_move, __copy_or_move_backward): Use std::__assign_one instead of ranges::__assign_one. --- libstdc++-v3/include/bits/ranges_algobase.h | 22 ++++++--------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h index 0345ea850a4..df4e770e7a6 100644 --- a/libstdc++-v3/include/bits/ranges_algobase.h +++ b/libstdc++-v3/include/bits/ranges_algobase.h @@ -225,16 +225,6 @@ namespace ranges copy_backward_result<_Iter, _Out>> __copy_or_move_backward(_Iter __first, _Sent __last, _Out __result); - template - constexpr void - __assign_one(_Iter& __iter, _Out& __result) - { - if constexpr (_IsMove) - *__result = std::move(*__iter); - else - *__result = *__iter; - } - template _Sent, weakly_incrementable _Out> @@ -294,14 +284,14 @@ namespace ranges __builtin_memmove(__result, __first, sizeof(_ValueTypeI) * __num); else if (__num == 1) - ranges::__assign_one<_IsMove>(__first, __result); + std::__assign_one<_IsMove>(__result, __first); return {__first + __num, __result + __num}; } } for (auto __n = __last - __first; __n > 0; --__n) { - ranges::__assign_one<_IsMove>(__first, __result); + std::__assign_one<_IsMove>(__result, __first); ++__first; ++__result; } @@ -311,7 +301,7 @@ namespace ranges { while (__first != __last) { - ranges::__assign_one<_IsMove>(__first, __result); + std::__assign_one<_IsMove>(__result, __first); ++__first; ++__result; } @@ -423,7 +413,7 @@ namespace ranges __builtin_memmove(__result, __first, sizeof(_ValueTypeI) * __num); else if (__num == 1) - ranges::__assign_one<_IsMove>(__first, __result); + std::__assign_one<_IsMove>(__result, __first); return {__first + __num, __result}; } } @@ -435,7 +425,7 @@ namespace ranges { --__tail; --__result; - ranges::__assign_one<_IsMove>(__tail, __result); + std::__assign_one<_IsMove>(__result, __tail); } return {std::move(__lasti), std::move(__result)}; } @@ -448,7 +438,7 @@ namespace ranges { --__tail; --__result; - ranges::__assign_one<_IsMove>(__tail, __result); + std::__assign_one<_IsMove>(__result, __tail); } return {std::move(__lasti), std::move(__result)}; }