[gcc r15-2356] libstdc++: Remove __find_if unrolling for random access iterators
https://gcc.gnu.org/g:e69456ff9a54ba3e9c93842b05757b7d8fff6d9d commit r15-2356-ge69456ff9a54ba3e9c93842b05757b7d8fff6d9d Author: Jonathan Wakely Date: Thu Jul 4 12:01:29 2024 +0100 libstdc++: Remove __find_if unrolling for random access iterators As the numbers in PR libstdc++/88545 show, the manual loop unrolling in std::__find_if doesn't actually help these days, and it prevents the compiler from auto-vectorizing. Remove the dispatching on iterator_category and just use the simple loop for all iterator categories. libstdc++-v3/ChangeLog: * include/bits/stl_algobase.h (__find_if): Remove overloads for dispatching on iterator_category. Do not unroll loop manually. * include/bits/stl_algo.h (__find_if_not): Remove iterator_category argument from __find_if call. Diff: --- libstdc++-v3/include/bits/stl_algo.h | 3 +- libstdc++-v3/include/bits/stl_algobase.h | 70 ++-- 2 files changed, 5 insertions(+), 68 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index d250b2e04d4d..541f53b2 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -110,8 +110,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Predicate __pred) { return std::__find_if(__first, __last, - __gnu_cxx::__ops::__negate(__pred), - std::__iterator_category(__first)); + __gnu_cxx::__ops::__negate(__pred)); } /// Like find_if_not(), but uses and updates a count of the diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index dec1e4c79d86..27f6c377ad6f 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -2098,77 +2098,15 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO _GLIBCXX_END_NAMESPACE_ALGO - /// This is an overload used by find algos for the Input Iterator case. - template -_GLIBCXX20_CONSTEXPR -inline _InputIterator -__find_if(_InputIterator __first, _InputIterator __last, - _Predicate __pred, input_iterator_tag) -{ - while (__first != __last && !__pred(__first)) - ++__first; - return __first; -} - - /// This is an overload used by find algos for the RAI case. - template -_GLIBCXX20_CONSTEXPR -_RandomAccessIterator -__find_if(_RandomAccessIterator __first, _RandomAccessIterator __last, - _Predicate __pred, random_access_iterator_tag) -{ - typename iterator_traits<_RandomAccessIterator>::difference_type - __trip_count = (__last - __first) >> 2; - - for (; __trip_count > 0; --__trip_count) - { - if (__pred(__first)) - return __first; - ++__first; - - if (__pred(__first)) - return __first; - ++__first; - - if (__pred(__first)) - return __first; - ++__first; - - if (__pred(__first)) - return __first; - ++__first; - } - - switch (__last - __first) - { - case 3: - if (__pred(__first)) - return __first; - ++__first; - // FALLTHRU - case 2: - if (__pred(__first)) - return __first; - ++__first; - // FALLTHRU - case 1: - if (__pred(__first)) - return __first; - ++__first; - // FALLTHRU - case 0: - default: - return __last; - } -} - + // Implementation of std::find_if, also used in std::remove_if and others. template _GLIBCXX20_CONSTEXPR inline _Iterator __find_if(_Iterator __first, _Iterator __last, _Predicate __pred) { - return __find_if(__first, __last, __pred, - std::__iterator_category(__first)); + while (__first != __last && !__pred(__first)) + ++__first; + return __first; } template
[gcc r15-2357] libstdc++: Add comment noting LWG 3617 support
https://gcc.gnu.org/g:2da38b6a8896bff08db78e6587d6142b898c8730 commit r15-2357-g2da38b6a8896bff08db78e6587d6142b898c8730 Author: Jonathan Wakely Date: Thu Jul 25 18:38:46 2024 +0100 libstdc++: Add comment noting LWG 3617 support The resolution was implemented in r14-8752-g6f75149488b74a but I didn't add the usual _GLIBCXX_RESOLVE_LIB_DEFECTS comment. libstdc++-v3/ChangeLog: * include/bits/std_function.h: Add comment about LWG 3617 being supported. Diff: --- libstdc++-v3/include/bits/std_function.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libstdc++-v3/include/bits/std_function.h b/libstdc++-v3/include/bits/std_function.h index 79b59466fe9d..bb8d8b9306cd 100644 --- a/libstdc++-v3/include/bits/std_function.h +++ b/libstdc++-v3/include/bits/std_function.h @@ -698,6 +698,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { using type = _Res(_Args...); }; #if __cpp_explicit_this_parameter >= 202110L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3617. function/packaged_task deduction guides and deducing this template struct __function_guide_helper<_Res (*) (_Tp, _Args...) noexcept(_Nx)> { using type = _Res(_Args...); };
[gcc r15-2358] libstdc++: Fix -Wsign-compare warning in
https://gcc.gnu.org/g:f793be787135ce7c52b169bf053af225b4828945 commit r15-2358-gf793be787135ce7c52b169bf053af225b4828945 Author: Jonathan Wakely Date: Fri Jul 26 17:23:03 2024 +0100 libstdc++: Fix -Wsign-compare warning in Cast ptrdiff_t to size_t to avoid a -Wsign-compare warning. We can check in __to_chars_i that the ptrdiff_t won't be negative, so that we know the cast is safe. libstdc++-v3/ChangeLog: * include/std/charconv (__to_chars_16, __to_chars_10) (__to_chars_8, __to_chars_2, __to_chars): Cast ptrdiff_t to size_t for comparison. (__to_chars_i): Check for first >= last instead of first == last for initial sanity check. Diff: --- libstdc++-v3/include/std/charconv | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv index e516e3b2da86..00c4f206922a 100644 --- a/libstdc++-v3/include/std/charconv +++ b/libstdc++-v3/include/std/charconv @@ -126,7 +126,7 @@ namespace __detail const unsigned __len = __to_chars_len(__val, __base); - if (__builtin_expect((__last - __first) < __len, 0)) + if (__builtin_expect(size_t(__last - __first) < __len, 0)) { __res.ptr = __last; __res.ec = errc::value_too_large; @@ -166,7 +166,7 @@ namespace __detail const unsigned __len = (__to_chars_len_2(__val) + 3) / 4; - if (__builtin_expect((__last - __first) < __len, 0)) + if (__builtin_expect(size_t(__last - __first) < __len, 0)) { __res.ptr = __last; __res.ec = errc::value_too_large; @@ -212,7 +212,7 @@ namespace __detail const unsigned __len = __to_chars_len(__val, 10); - if (__builtin_expect((__last - __first) < __len, 0)) + if (__builtin_expect(size_t(__last - __first) < __len, 0)) { __res.ptr = __last; __res.ec = errc::value_too_large; @@ -246,7 +246,7 @@ namespace __detail else __len = (__to_chars_len_2(__val) + 2) / 3; - if (__builtin_expect((__last - __first) < __len, 0)) + if (__builtin_expect(size_t(__last - __first) < __len, 0)) { __res.ptr = __last; __res.ec = errc::value_too_large; @@ -288,7 +288,7 @@ namespace __detail const unsigned __len = __to_chars_len_2(__val); - if (__builtin_expect((__last - __first) < __len, 0)) + if (__builtin_expect(size_t(__last - __first) < __len, 0)) { __res.ptr = __last; __res.ec = errc::value_too_large; @@ -323,7 +323,7 @@ namespace __detail using _Up = __detail::__unsigned_least_t<_Tp>; _Up __unsigned_val = __value; - if (__first == __last) [[__unlikely__]] + if (__first >= __last) [[__unlikely__]] return { __last, errc::value_too_large }; if (__value == 0)
[gcc r15-2359] Fold ctz(-x) and ctz(abs(x)) as ctz(x) in match.pd.
https://gcc.gnu.org/g:928116e94a5a8a995dffd926af58abfa7286e78e commit r15-2359-g928116e94a5a8a995dffd926af58abfa7286e78e Author: Roger Sayle Date: Sat Jul 27 15:16:19 2024 +0100 Fold ctz(-x) and ctz(abs(x)) as ctz(x) in match.pd. The subject line pretty much says it all; the count-trailing-zeros function of -X and abs(X) produce the same result as count-trailing-zeros of X. This transformation eliminates a negation which may potentially overflow with an equivalent expression that doesn't [much like the analogous abs(-X) simplification in match.pd]. I'd noticed this -X equivalence, which isn't mentioned in Hacker's Delight, investigating whether ranger's non_zero_bits can help determine whether an integer variable may be converted to a floating point type exactly (without raising FE_INEXACT), but it turns out this observation isn't novel, as (disappointingly) LLVM already performs this same folding. 2024-07-27 Roger Sayle Andrew Pinski gcc/ChangeLog * match.pd (ctz (-X) => ctz (X)): New simplification. (ctz (abs (X)) => ctz (X)): Likewise. gcc/testsuite/ChangeLog * gcc.dg/fold-ctz-1.c: New test case. * gcc.dg/fold-ctz-2.c: Likewise. Diff: --- gcc/match.pd | 6 ++ gcc/testsuite/gcc.dg/fold-ctz-1.c | 9 + gcc/testsuite/gcc.dg/fold-ctz-2.c | 9 + 3 files changed, 24 insertions(+) diff --git a/gcc/match.pd b/gcc/match.pd index b2e7d61790df..1c8601229e3d 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -9102,6 +9102,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* CTZ simplifications. */ (for ctz (CTZ) + /* ctz (-X) => ctz (X). ctz (abs (X)) => ctz (X). */ + (for op (negate abs) + (simplify + (ctz (nop_convert?@0 (op @1))) +(with { tree t = TREE_TYPE (@0); } + (ctz (convert:t @1) (for op (ge gt le lt) cmp (eq eq ne ne) (simplify diff --git a/gcc/testsuite/gcc.dg/fold-ctz-1.c b/gcc/testsuite/gcc.dg/fold-ctz-1.c new file mode 100644 index ..dcc444cbbb6b --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-ctz-1.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +int foo(int x) +{ + return __builtin_ctz (-x); +} + +/* { dg-final { scan-tree-dump-not "-x_" "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/fold-ctz-2.c b/gcc/testsuite/gcc.dg/fold-ctz-2.c new file mode 100644 index ..c685698f31e5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-ctz-2.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +int foo(int x) +{ + return __builtin_ctz (__builtin_abs (x)); +} + +/* { dg-final { scan-tree-dump-not "ABS_EXPR" "optimized"} } */
[gcc r15-2361] c++: ICE with concept, local class, and lambda [PR115561]
https://gcc.gnu.org/g:3129a2ed6a764c0687efaca9eba53dcf12d1d8a0 commit r15-2361-g3129a2ed6a764c0687efaca9eba53dcf12d1d8a0 Author: Jason Merrill Date: Fri Jul 26 16:53:03 2024 -0400 c++: ICE with concept, local class, and lambda [PR115561] Here when we want to synthesize methods for foo()::B maybe_push_to_top_level calls push_function_context, which sets cfun to a dummy value; later finish_call_expr tries to set something in cp_function_chain (i.e. cfun->language), which isn't set. Many places in the compiler check cfun && cp_function_chain to avoid this problem; here we also want to check !cp_unevaluated_operand, like set_flags_from_callee does. PR c++/115561 gcc/cp/ChangeLog: * semantics.cc (finish_call_expr): Check cp_unevaluated_operand. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-lambda21.C: New test. Diff: --- gcc/cp/semantics.cc| 2 +- gcc/testsuite/g++.dg/cpp2a/concepts-lambda21.C | 69 ++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 0f122b839c5f..a9abf32e01ff 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -2968,7 +2968,7 @@ finish_call_expr (tree fn, vec **args, bool disallow_virtual, -Wredundant-move warning. */ suppress_warning (result, OPT_Wpessimizing_move); - if (cfun) + if (cfun && cp_function_chain && !cp_unevaluated_operand) { bool abnormal = true; for (lkp_iterator iter (maybe_get_fns (fn)); iter; ++iter) diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda21.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda21.C new file mode 100644 index ..8d701cd4bbc4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda21.C @@ -0,0 +1,69 @@ +// PR c++/115561 +// { dg-do compile { target c++20 } } + +template +auto declval() noexcept -> _Tp&&; + +template +struct enable_if +{ }; + +template +struct enable_if +{ using type = _Tp; }; + +template +using enable_if_t = typename enable_if<_Cond, _Tp>::type; + +template +struct is_void +{ static constexpr bool value = false; }; + +template +using invoke_result_t = +decltype(declval()(declval()...)); + +template +using iter_reference_t = decltype(*declval()); + +struct iter_move_fn +{ +template +constexpr +auto operator() (I &&i) -> void; +} iter_move; + +template +using iter_rvalue_reference_t = decltype(iter_move(declval())); + +template +concept same_as = true; + +template +concept readable_concept_ = +same_as, iter_rvalue_reference_t>; + +template +concept indirectly_readable = +readable_concept_>; + +template +using indirect_result_t = +enable_if_t, +invoke_result_t>>; + +template +concept transformable = + (!is_void>::value); + +template +requires transformable +constexpr void transform(I, Fun) +{ +} + +void foo() +{ +struct B {}; +(void) transform((B*)nullptr, [](B) {return 0; }); +}
[gcc r15-2360] c++: improve C++ testsuite default versions
https://gcc.gnu.org/g:dab0f35fcb4dd3ba584422013096c4ebc6bff90d commit r15-2360-gdab0f35fcb4dd3ba584422013096c4ebc6bff90d Author: Jason Merrill Date: Fri Jul 26 15:10:50 2024 -0400 c++: improve C++ testsuite default versions I wanted to add more cases to the setting of std_list in g++-dg.exp, but didn't want to do a full scan through the file for each case. So this patch improves that in two ways: first, by extracting all interesting lines on a single pass; second, by generating the list more flexibly: now we test every version mentioned explicitly in the testcase, plus a few more if fewer than three are mentioned. This also lowers changes from testing four to three versions for most testcases: the current default and the earliest and latest versions. This will reduce testing of C++14 and C++20 modes, and increase testing of C++26 mode. C++ front-end developers are encouraged to set the GXX_TESTSUITE_STDS environment variable to test more modes. gcc/testsuite/ChangeLog: * lib/gcc-dg.exp (get_matching_lines): New. * lib/g++-dg.exp: Improve std_list selection. Diff: --- gcc/testsuite/lib/g++-dg.exp | 45 ++-- gcc/testsuite/lib/gcc-dg.exp | 13 + 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/gcc/testsuite/lib/g++-dg.exp b/gcc/testsuite/lib/g++-dg.exp index 52fba75c4a32..991be4d38677 100644 --- a/gcc/testsuite/lib/g++-dg.exp +++ b/gcc/testsuite/lib/g++-dg.exp @@ -53,21 +53,38 @@ proc g++-dg-runtest { testcases flags default-extra-flags } { if { [llength $gpp_std_list] > 0 } { set std_list $gpp_std_list } else { - # If the test requires a newer C++ version than which - # is tested by default, use that C++ version for that - # single test. Or if a test checks behavior specifically for - # one C++ version, include that version in the default list. - # These should be adjusted whenever the default std_list is - # updated or newer C++ effective target is added. - if [search_for $test "\{ dg-do * \{ target c++23"] { - set std_list { 23 26 } - } elseif [search_for $test "\{ dg-do * \{ target c++26"] { - set std_list { 26 } - } elseif [search_for $test "c++11_only"] { - set std_list { 98 11 14 20 } - } else { - set std_list { 98 14 17 20 } + # If the test mentions specific C++ versions, test those. + set lines [get_matching_lines $test {\{ dg* c++[0-9][0-9]}] + set std_list {} + set low 0 + foreach line $lines { + regexp {c\+\+([0-9][0-9])} $line -> ver + lappend std_list $ver + + if { $ver == 98 } { + # Leave low alone. + } elseif { [regexp {dg-do|dg-require-effective-target} $line] } { + set low $ver + } } + #verbose "low: $low" 1 + + set std_list [lsort -unique $std_list] + + # If fewer than 3 specific versions are mentioned, add more. + # The order of this list is significant: first $cxx_default, + # then the oldest and newest, then others in rough order of + # importance based on test coverage and usage. + foreach ver { 17 98 26 11 20 14 23 } { + set cmpver $ver + if { $ver == 98 } { set cmpver 03 } + if { [llength $std_list] < 3 +&& $ver ni $std_list +&& $cmpver > $low } { + lappend std_list $ver + } + } + verbose "std_list: $std_list" 1 } set option_list { } foreach x $std_list { diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp index 228c21d12071..992062103c12 100644 --- a/gcc/testsuite/lib/gcc-dg.exp +++ b/gcc/testsuite/lib/gcc-dg.exp @@ -574,6 +574,19 @@ proc search_for { file pattern } { return 0 } +# get_matching_lines -- return a list of matching lines in file +proc get_matching_lines { file pattern } { +set lines {} +set fd [open $file r] +while { [gets $fd cur_line]>=0 } { + if [string match "*$pattern*" $cur_line] then { + lappend lines $cur_line + } +} +close $fd +return $lines +} + # Modified dg-runtest that can cycle through a list of optimization options # as c-torture does. proc gcc-dg-runtest { testcases flags default-extra-flags } {
[gcc r15-2362] c++: consteval propagation and templates [PR115986]
https://gcc.gnu.org/g:a9e9f772c7488ac0c09dd92f28890bdab939771a commit r15-2362-ga9e9f772c7488ac0c09dd92f28890bdab939771a Author: Jason Merrill Date: Fri Jul 26 17:20:18 2024 -0400 c++: consteval propagation and templates [PR115986] Here the call to e() makes us decide to check d() for escalation at EOF, but while checking it we try to fold_immediate 0_c, and get confused by the template trees. Let's not mess with escalation for function templates. PR c++/115986 gcc/cp/ChangeLog: * cp-gimplify.cc (remember_escalating_expr): Skip function templates. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/consteval-prop21.C: New test. Diff: --- gcc/cp/cp-gimplify.cc | 4 gcc/testsuite/g++.dg/cpp2a/consteval-prop21.C | 17 + 2 files changed, 21 insertions(+) diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index e6629dea5fdc..6a5e4cf62ca1 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -53,6 +53,10 @@ static GTY(()) hash_set *deferred_escalating_exprs; static void remember_escalating_expr (tree t) { + if (uses_template_parms (t)) +/* Templates don't escalate, and cp_fold_immediate can get confused by + other template trees in the function body (c++/115986). */ +return; if (!deferred_escalating_exprs) deferred_escalating_exprs = hash_set::create_ggc (37); deferred_escalating_exprs->add (t); diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop21.C b/gcc/testsuite/g++.dg/cpp2a/consteval-prop21.C new file mode 100644 index ..debbda4f4259 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop21.C @@ -0,0 +1,17 @@ +// PR c++/115986 +// { dg-do compile { target c++20 } } + +template +constexpr int b(T) { + return 0; +} +consteval __uint128_t operator"" _c(const char*) { return 0; } +constexpr char e() { + long f = true ? 0 : b(long(1)); + return b(f); +} +template +void d() { + 0_c; + static_assert(e()); +}