From patchwork Mon Aug 26 13:53:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Biener X-Patchwork-Id: 1976850 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=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=N03AWHor; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=UbSt7OPG; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=N03AWHor; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=UbSt7OPG; 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 4WsscG1vpQz1yYl for ; Mon, 26 Aug 2024 23:54:38 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5BCD4385DDD8 for ; Mon, 26 Aug 2024 13:54:36 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.223.131]) by sourceware.org (Postfix) with ESMTPS id 25157385DC1E for ; Mon, 26 Aug 2024 13:53:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 25157385DC1E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=suse.de ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 25157385DC1E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=195.135.223.131 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724680431; cv=none; b=ZX27uP/aRwNm5ZkWcOugyht4sm8mQ3Q+8ZiH7nAFFX6u5WQWp/FOAsKEJXcAM7CEkeCyVeHKZi6A7IgXudc4FwDXthOLXdYk0cXaP6YgIUILa8/8rfN4iUCP7e3Lah52VfPBT0+xk2dlnK+70r/ZHZalcwJhuLllI8b7Ga7eSZA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724680431; c=relaxed/simple; bh=N2ISLDhdKnCJqOil1VECAEdQ/bAHKIvmip7uS8zthR4=; h=DKIM-Signature:DKIM-Signature:DKIM-Signature:DKIM-Signature:Date: From:To:Subject:MIME-Version; b=ObbDk9NxCSb6L2fQ1cZtzS+OCSl1cs1jcrLw+or6yFL2l5fouvD/1ZwXg69T6ptPwRpolGxgP6TTpDclW18uVRGKtskkRO4PlM3NcwAXrFeAPDFiL30dgHsJbOaj/ToJeqMnPpQQ8as81NytdNIpFUajX78aEySlzXjMwOrmV04= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from murzim.nue2.suse.org (unknown [10.168.4.243]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 1FCBD1F88C for ; Mon, 26 Aug 2024 13:53:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1724680424; h=from:from:reply-to:date:date:to:to:cc:mime-version:mime-version: content-type:content-type; bh=nirkF6TgWxCAJ+eA1WmSbXuNnjWERzz0eFT3cx6N79s=; b=N03AWHorUwCyDQvPOj8StLU8YioZ5dIe+VXSJwTXOE2S5s2P4Gi2Evp3UfvyMvx79z4769 BSkKs13ZzfB+wf/4Pi+MuBwNcP7s2RAjLkMjVbJmTSMZp2+vkyyPFDDZsn/XebXEhIt7si vx5Bii1OK+dbr4mYIkj0Bd/GV96HjAU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1724680424; h=from:from:reply-to:date:date:to:to:cc:mime-version:mime-version: content-type:content-type; bh=nirkF6TgWxCAJ+eA1WmSbXuNnjWERzz0eFT3cx6N79s=; b=UbSt7OPGF/QtqXxgxf2K0LyfZvkGVkzKCTYsgpSEb18MO+EELmz+LyKZFbLNA8qhutqYhh c6XaOvY7CceaU5DQ== Authentication-Results: smtp-out2.suse.de; none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1724680424; h=from:from:reply-to:date:date:to:to:cc:mime-version:mime-version: content-type:content-type; bh=nirkF6TgWxCAJ+eA1WmSbXuNnjWERzz0eFT3cx6N79s=; b=N03AWHorUwCyDQvPOj8StLU8YioZ5dIe+VXSJwTXOE2S5s2P4Gi2Evp3UfvyMvx79z4769 BSkKs13ZzfB+wf/4Pi+MuBwNcP7s2RAjLkMjVbJmTSMZp2+vkyyPFDDZsn/XebXEhIt7si vx5Bii1OK+dbr4mYIkj0Bd/GV96HjAU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1724680424; h=from:from:reply-to:date:date:to:to:cc:mime-version:mime-version: content-type:content-type; bh=nirkF6TgWxCAJ+eA1WmSbXuNnjWERzz0eFT3cx6N79s=; b=UbSt7OPGF/QtqXxgxf2K0LyfZvkGVkzKCTYsgpSEb18MO+EELmz+LyKZFbLNA8qhutqYhh c6XaOvY7CceaU5DQ== Date: Mon, 26 Aug 2024 15:53:44 +0200 (CEST) From: Richard Biener To: gcc-patches@gcc.gnu.org Subject: [PATCH] tree-optimization/116460 - ICE with DCE in forwprop MIME-Version: 1.0 X-Spam-Level: X-Spamd-Result: default: False [-1.12 / 50.00]; BAYES_HAM(-3.00)[99.99%]; MISSING_MID(2.50)[]; NEURAL_HAM_LONG(-0.32)[-0.324]; NEURAL_HAM_SHORT(-0.20)[-0.991]; MIME_GOOD(-0.10)[text/plain]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; ARC_NA(0.00)[]; RCPT_COUNT_ONE(0.00)[1]; FUZZY_BLOCKED(0.00)[rspamd.com]; TO_MATCH_ENVRCPT_ALL(0.00)[]; FROM_HAS_DN(0.00)[]; RCVD_COUNT_ZERO(0.00)[0]; MISSING_XM_UA(0.00)[]; FROM_EQ_ENVFROM(0.00)[]; TO_DN_NONE(0.00)[]; MIME_TRACE(0.00)[0:+] X-Spam-Score: -1.12 X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, MISSING_MID, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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 Message-Id: <20240826135436.5BCD4385DDD8@sourceware.org> The following avoids removing stmts with defs that might still have uses in the IL before calling simple_dce_from_worklist which might remove those as that will wreck debug stmt generation. Instead first perform use-based DCE and then remove stmts which may have uses in code that CFG cleanup will remove. This requires tracking stmts in to_remove by their SSA def so we can check whether it was removed before without running into the issue that PHIs can be ggc_free()d upon removal. So this adds to_remove_defs in addition to to_remove which has to stay to track GIMPLE_NOPs we want to elide. Bootstrapped on x86_64-unknown-linux-gnu (on trunk and 14 branch), testing in progress. Richard. PR tree-optimization/116460 * tree-ssa-forwprop.cc (pass_forwprop::execute): First do simple_dce_from_worklist and then remove stmts in to_remove. Track defs to be removed in to_remove_defs. * g++.dg/torture/pr116460.C: New testcase. --- gcc/testsuite/g++.dg/torture/pr116460.C | 609 ++++++++++++++++++++++++ gcc/tree-ssa-forwprop.cc | 38 +- 2 files changed, 637 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/pr116460.C diff --git a/gcc/testsuite/g++.dg/torture/pr116460.C b/gcc/testsuite/g++.dg/torture/pr116460.C new file mode 100644 index 00000000000..3c7d6372fba --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr116460.C @@ -0,0 +1,609 @@ +// { dg-do compile } +// { dg-additional-options "-g" } + +namespace std { +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; +void __throw_length_error(const char *) __attribute__((__noreturn__, __cold__)); +} +extern "C++" { +namespace std __attribute__((__visibility__("default"))) { + template struct __is_integer { + enum { __value = 1 }; + }; + template struct __is_nonvolatile_trivially_copyable { + enum { __value = __is_trivially_copyable(_Tp) }; + }; + template struct __memcpyable {}; + template + struct __memcpyable<_Tp *, _Tp *> : __is_nonvolatile_trivially_copyable<_Tp> { + }; + template + struct __memcpyable<_Tp *, const _Tp *> + : __is_nonvolatile_trivially_copyable<_Tp> {}; + template struct __is_move_iterator { + enum { __value = 0 }; + }; + template inline _Iterator __miter_base(_Iterator __it) { + return __it; + } +} // namespace ) +} +namespace __gnu_cxx __attribute__((__visibility__("default"))) { + template + struct __is_integer_nonstrict : public std::__is_integer<_Tp> { + using std::__is_integer<_Tp>::__value; + enum { __width = __value ? sizeof(_Tp) * 8 : 0 }; + }; + template struct __numeric_traits_integer { + static const bool __is_signed = (_Value)(-1) < 0; + static const int __digits = + __is_integer_nonstrict<_Value>::__width - __is_signed; + static const _Value __max = + __is_signed ? (((((_Value)1 << (__digits - 1)) - 1) << 1) + 1) + : ~(_Value)0; + }; + template + struct __numeric_traits : public __numeric_traits_integer<_Value> {}; +} // namespace ) +namespace std __attribute__((__visibility__("default"))) { + template struct integral_constant { + static constexpr _Tp value = __v; + using type = integral_constant<_Tp, __v>; + }; + template using __bool_constant = integral_constant; + using true_type = __bool_constant; + using false_type = __bool_constant; + template struct enable_if {}; + template struct enable_if { using type = _Tp; }; + template + using __enable_if_t = typename enable_if<_Cond, _Tp>::type; + template struct __conditional { + template using type = _Tp; + }; + template + using __conditional_t = + typename __conditional<_Cond>::template type<_If, _Else>; + namespace __detail { + template auto __and_fn(...) -> false_type; + } + template + struct __and_ : decltype(__detail::__and_fn<_Bn...>(0)) {}; + template struct __not_ : __bool_constant {}; + template using __void_t = void; + template + struct is_trivial : public __bool_constant<__is_trivial(_Tp)> {}; + template _Up __declval(int); + template auto declval() noexcept->decltype(__declval<_Tp>(0)); + template + using __is_constructible_impl = + __bool_constant<__is_constructible(_Tp, _Args...)>; + template + struct __add_lvalue_reference_helper { + using type = _Tp &; + }; + template + using __add_lval_ref_t = typename __add_lvalue_reference_helper<_Tp>::type; + template + struct is_copy_constructible + : public __is_constructible_impl<_Tp, __add_lval_ref_t> {}; + template + struct __add_rvalue_reference_helper { + using type = _Tp; + }; + template + using __add_rval_ref_t = typename __add_rvalue_reference_helper<_Tp>::type; + template + struct is_move_constructible + : public __is_constructible_impl<_Tp, __add_rval_ref_t<_Tp>> {}; + template + using __is_nothrow_constructible_impl = + __bool_constant<__is_nothrow_constructible(_Tp, _Args...)>; + template + struct is_nothrow_default_constructible + : public __is_nothrow_constructible_impl<_Tp> {}; + template + struct is_nothrow_copy_constructible + : public __is_nothrow_constructible_impl<_Tp, + __add_lval_ref_t> {}; + template + struct is_nothrow_move_constructible + : public __is_nothrow_constructible_impl<_Tp, __add_rval_ref_t<_Tp>> {}; + template struct remove_reference { + using type = __remove_reference(_Tp); + }; + template + [[__nodiscard__]] constexpr _Tp &&forward( + typename std::remove_reference<_Tp>::type & __t) noexcept { + return static_cast<_Tp &&>(__t); + } + template + [[__nodiscard__]] constexpr typename std::remove_reference<_Tp>::type &&move( + _Tp && __t) noexcept { + return static_cast::type &&>(__t); + } + template + struct __move_if_noexcept_cond + : public __and_<__not_>, + is_copy_constructible<_Tp>>::type {}; + struct input_iterator_tag {}; + struct forward_iterator_tag : public input_iterator_tag {}; + struct bidirectional_iterator_tag : public forward_iterator_tag {}; + struct random_access_iterator_tag : public bidirectional_iterator_tag {}; + template > + struct __iterator_traits { + typedef typename _Iterator::value_type value_type; + }; + template + struct iterator_traits : public __iterator_traits<_Iterator> {}; + template struct iterator_traits<_Tp *> { + typedef random_access_iterator_tag iterator_category; + typedef _Tp value_type; + typedef ptrdiff_t difference_type; + typedef _Tp &reference; + }; + template + typename iterator_traits<_Iter>::iterator_category __iterator_category( + const _Iter &) { + return typename iterator_traits<_Iter>::iterator_category(); + } + template + typename iterator_traits<_RandomAccessIterator>::difference_type __distance( + _RandomAccessIterator __first, _RandomAccessIterator __last, + random_access_iterator_tag) { + return __last - __first; + } + template + typename iterator_traits<_InputIterator>::difference_type distance( + _InputIterator __first, _InputIterator __last) { + return std::__distance(__first, __last, std::__iterator_category(__first)); + } +} // namespace ) +namespace __gnu_cxx __attribute__((__visibility__("default"))) { + template class __normal_iterator { + _Iterator _M_current; + typedef std::iterator_traits<_Iterator> __traits_type; + public: + typedef typename __traits_type::value_type value_type; + typedef typename __traits_type::difference_type difference_type; + typedef typename __traits_type::reference reference; + explicit __normal_iterator(const _Iterator &__i) noexcept + : _M_current(__i) {} + reference operator*() const noexcept { return *_M_current; } + __normal_iterator &operator++() noexcept { + ++_M_current; + return *this; + } + __normal_iterator &operator--() noexcept { + --_M_current; + return *this; + } + __normal_iterator operator+(difference_type __n) const noexcept { + return __normal_iterator(_M_current + __n); + } + __normal_iterator operator-(difference_type __n) const noexcept { + return __normal_iterator(_M_current - __n); + } + const _Iterator &base() const noexcept { return _M_current; } + }; + template + [[__nodiscard__]] inline bool operator!=( + const __normal_iterator<_IteratorL, _Container> &__lhs, + const __normal_iterator<_IteratorR, _Container> &__rhs) noexcept { + return __lhs.base() != __rhs.base(); + } + template + typename __normal_iterator<_Iterator, _Container>::difference_type operator-( + const __normal_iterator<_Iterator, _Container> &__lhs, + const __normal_iterator<_Iterator, _Container> &__rhs) noexcept { + return __lhs.base() - __rhs.base(); + } +} // namespace ) +namespace std __attribute__((__visibility__("default"))) { +} // namespace ) +namespace __gnu_cxx { +namespace __ops { +template struct _Iter_comp_iter { + _Compare _M_comp; + explicit constexpr _Iter_comp_iter(_Compare __comp) + : _M_comp(std::move(__comp)) {} + template + constexpr bool operator()(_Iterator1 __it1, _Iterator2 __it2) { + return bool(_M_comp(*__it1, *__it2)); + } +}; +template +constexpr inline _Iter_comp_iter<_Compare> __iter_comp_iter(_Compare __comp) { + return _Iter_comp_iter<_Compare>(std::move(__comp)); +} +template struct _Val_comp_iter { + _Compare _M_comp; + explicit _Val_comp_iter(const _Iter_comp_iter<_Compare> &__comp) + : _M_comp(std::move(__comp._M_comp)) {} + template + bool operator()(_Value &__val, _Iterator __it) { + return bool(_M_comp(__val, *__it)); + } +}; +template +inline _Val_comp_iter<_Compare> +__val_comp_iter(_Iter_comp_iter<_Compare> __comp) { + return _Val_comp_iter<_Compare>(std::move(__comp)); +} +} // namespace __ops +} // namespace __gnu_cxx +namespace std __attribute__((__visibility__("default"))) { + template + [[__nodiscard__]] constexpr inline const _Tp &min(const _Tp &__a, + const _Tp &__b) { + return __a; + } + template + [[__nodiscard__]] constexpr inline const _Tp &max(const _Tp &__a, + const _Tp &__b) { + return __b; + } + template + inline _Iterator __niter_base(_Iterator __it) noexcept( + std::is_nothrow_copy_constructible<_Iterator>::value) { + return __it; + } + template + inline _Iterator __niter_wrap(const _Iterator &, _Iterator __res) { + return __res; + } + template + struct __copy_move { + template + static _Up *__copy_m(_Tp *__first, _Tp *__last, _Up *__result) { + const ptrdiff_t _Num = __last - __first; + return __result + _Num; + } + }; + template + inline _OI __copy_move_a2(_II __first, _II __last, _OI __result) { + typedef typename iterator_traits<_II>::iterator_category _Category; + return std::__copy_move<_IsMove, __memcpyable<_OI, _II>::__value, + _Category>::__copy_m(__first, __last, __result); + } + template + inline _OI __copy_move_a1(_II __first, _II __last, _OI __result) { + return std::__copy_move_a2<_IsMove>(__first, __last, __result); + } + template + inline _OI __copy_move_a(_II __first, _II __last, _OI __result) { + return std::__niter_wrap( + __result, std::__copy_move_a1<_IsMove>(std::__niter_base(__first), + std::__niter_base(__last), + std::__niter_base(__result))); + } + template + inline _OI copy(_II __first, _II __last, _OI __result) { + return std::__copy_move_a<__is_move_iterator<_II>::__value>( + std::__miter_base(__first), std::__miter_base(__last), __result); + } + template class __new_allocator { + public: + typedef _Tp value_type; + typedef std::size_t size_type; + __attribute__((__always_inline__)) [[__nodiscard__]] _Tp * + allocate(size_type __n, const void * = static_cast(0)) { + return static_cast<_Tp *>(::operator new(__n * sizeof(_Tp))); + } + __attribute__((__always_inline__)) size_type max_size() const noexcept { + return _M_max_size(); + } + __attribute__((__always_inline__)) constexpr size_type + _M_max_size() const noexcept { + return std::size_t(0x7fffffffffffffffL) / sizeof(_Tp); + } + }; + template using __allocator_base = __new_allocator<_Tp>; + template struct allocator_traits; + template class allocator : public __allocator_base<_Tp> {}; + template struct allocator_traits> { + using allocator_type = allocator<_Tp>; + using value_type = _Tp; + using pointer = _Tp *; + using size_type = std::size_t; + template using rebind_alloc = allocator<_Up>; + [[__nodiscard__, __gnu__::__always_inline__]] static pointer + allocate(allocator_type &__a, size_type __n) { + return __a.allocate(__n); + } + [[__gnu__::__always_inline__]] static size_type + max_size(const allocator_type &__a __attribute__((__unused__))) noexcept { + return __a.max_size(); + } + }; + template + struct __is_alloc_insertable_impl : false_type {}; + template + struct __is_move_insertable + : __is_alloc_insertable_impl<_Alloc, typename _Alloc::value_type>::type { + }; + template + struct __is_move_insertable> : is_move_constructible<_Tp> {}; +} // namespace ) +namespace __gnu_cxx __attribute__((__visibility__("default"))) { + template + struct __alloc_traits : std::allocator_traits<_Alloc> { + typedef std::allocator_traits<_Alloc> _Base_type; + typedef typename _Base_type::value_type value_type; + typedef value_type &reference; + template struct rebind { + typedef typename _Base_type::template rebind_alloc<_Tp> other; + }; + }; +} // namespace ) +namespace std __attribute__((__visibility__("default"))) { + template + constexpr bool __check_constructible() { + return true; + } + template struct __uninitialized_copy { + template + static _ForwardIterator __uninit_copy(_InputIterator __first, + _InputIterator __last, + _ForwardIterator __result) { + return std::copy(__first, __last, __result); + } + }; + template + inline _ForwardIterator uninitialized_copy(_InputIterator __first, + _InputIterator __last, + _ForwardIterator __result) { + typedef typename iterator_traits<_InputIterator>::value_type _ValueType1; + typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType2; + const bool __can_memmove = __is_trivial(_ValueType1); + using _From = decltype(*__first); + const bool __assignable = __is_trivial(_ValueType2) && + std::__check_constructible<_ValueType2, _From>(); + return std::__uninitialized_copy < __can_memmove && + __assignable > ::__uninit_copy(__first, __last, __result); + } + template + inline _ForwardIterator __uninitialized_copy_a( + _InputIterator __first, _InputIterator __last, _ForwardIterator __result, + allocator<_Tp> &) { + return std::uninitialized_copy(__first, __last, __result); + } + template + inline _ForwardIterator __uninitialized_move_if_noexcept_a( + _InputIterator __first, _InputIterator __last, _ForwardIterator __result, + _Allocator & __alloc) { + return std::__uninitialized_copy_a( + __first, + __last, __result, __alloc); + } + template + struct __is_bitwise_relocatable : is_trivial<_Tp> {}; + template + inline __enable_if_t::value, _Tp *> + __relocate_a_1(_Tp * __first, _Tp * __last, _Tp * __result, + [[__maybe_unused__]] allocator<_Up> & __alloc) noexcept {} + template + inline _ForwardIterator __relocate_a( + _InputIterator __first, _InputIterator __last, _ForwardIterator __result, + _Allocator & + __alloc) noexcept(noexcept(__relocate_a_1(std::__niter_base(__first), + std::__niter_base(__last), + std::__niter_base(__result), + __alloc))) {} + template class initializer_list { + typedef size_t size_type; + typedef const _E *iterator; + typedef const _E *const_iterator; + iterator _M_array; + size_type _M_len; + public: + constexpr size_type size() const noexcept { return _M_len; } + constexpr const_iterator begin() const noexcept { return _M_array; } + constexpr const_iterator end() const noexcept { return begin() + size(); } + }; + template struct _Vector_base { + typedef + typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other + _Tp_alloc_type; + typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer pointer; + struct _Vector_impl_data { + pointer _M_start; + pointer _M_finish; + pointer _M_end_of_storage; + _Vector_impl_data() noexcept + : _M_start(), _M_finish(), _M_end_of_storage() {} + }; + struct _Vector_impl : public _Tp_alloc_type, public _Vector_impl_data { + _Vector_impl() noexcept( + is_nothrow_default_constructible<_Tp_alloc_type>::value) + : _Tp_alloc_type() {} + _Vector_impl(_Tp_alloc_type const &__a) noexcept : _Tp_alloc_type(__a) {} + _Vector_impl(_Tp_alloc_type &&__a, _Vector_impl &&__rv) noexcept + : _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv)) { + } + }; + typedef _Alloc allocator_type; + _Tp_alloc_type &_M_get_Tp_allocator() noexcept { return this->_M_impl; } + const _Tp_alloc_type &_M_get_Tp_allocator() const noexcept { + return this->_M_impl; + } + _Vector_base() = default; + _Vector_base(const allocator_type &__a) noexcept : _M_impl(__a) {} + _Vector_impl _M_impl; + pointer _M_allocate(size_t __n) { + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr; + return __n != 0 ? _Tr::allocate(_M_impl, __n) : pointer(); + } + }; + template > + class vector : protected _Vector_base<_Tp, _Alloc> { + typedef _Vector_base<_Tp, _Alloc> _Base; + typedef typename _Base::_Tp_alloc_type _Tp_alloc_type; + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Alloc_traits; + typedef _Tp value_type; + typedef typename _Base::pointer pointer; + typedef typename _Alloc_traits::reference reference; + typedef __gnu_cxx::__normal_iterator iterator; + typedef size_t size_type; + typedef _Alloc allocator_type; + static constexpr bool _S_nothrow_relocate(true_type) { + return noexcept(std::__relocate_a( + std::declval(), std::declval(), + std::declval(), std::declval<_Tp_alloc_type &>())); + } + static constexpr bool _S_use_relocate() { + return _S_nothrow_relocate(__is_move_insertable<_Tp_alloc_type>{}); + } + using _Base::_M_get_Tp_allocator; + public: + vector() = default; + vector(initializer_list __l, + const allocator_type &__a = allocator_type()) + : _Base(__a) { + _M_range_initialize(__l.begin(), __l.end(), random_access_iterator_tag()); + } + [[__nodiscard__]] iterator begin() noexcept { + return iterator(this->_M_impl._M_start); + } + [[__nodiscard__]] iterator end() noexcept { + return iterator(this->_M_impl._M_finish); + } + [[__nodiscard__]] size_type size() const noexcept { + return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); + } + [[__nodiscard__]] size_type max_size() const noexcept { + return _S_max_size(_M_get_Tp_allocator()); + } + [[__nodiscard__]] reference back() noexcept { return *(end() - 1); } + void push_back(value_type &&__x) { emplace_back(std::move(__x)); } + template reference emplace_back(_Args &&...__args); + template + void _M_range_initialize(_ForwardIterator __first, _ForwardIterator __last, + std::forward_iterator_tag) { + const size_type __n = std::distance(__first, __last); + this->_M_allocate(_S_check_init_len(__n, _M_get_Tp_allocator())); + this->_M_impl._M_finish = std::__uninitialized_copy_a( + __first, __last, this->_M_impl._M_start, _M_get_Tp_allocator()); + } + template void _M_realloc_append(_Args &&...__args); + size_type _M_check_len(size_type __n, const char *__s) const { + const size_type __len = size() + (std::max)(size(), __n); + return (__len < size() || __len > max_size()) ? max_size() : __len; + } + static size_type _S_check_init_len(size_type __n, + const allocator_type &__a) { + if (__n > _S_max_size(_Tp_alloc_type(__a))) + __throw_length_error( + ("cannot create std::vector larger than max_size()")); + return __n; + } + static size_type _S_max_size(const _Tp_alloc_type &__a) noexcept { + const size_t __diffmax = + __gnu_cxx::__numeric_traits::__max / sizeof(_Tp); + return __diffmax; + } + }; + + template + struct greater { + constexpr bool operator()(const _Tp &__x, const _Tp &__y) const { + return __x > __y; + } + }; + template + template + typename vector<_Tp, _Alloc>::reference vector<_Tp, _Alloc>::emplace_back( + _Args && ...__args) { + if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) { + ++this->_M_impl._M_finish; + } else + _M_realloc_append(std::forward<_Args>(__args)...); + return back(); + } + template + template + void vector<_Tp, _Alloc>::_M_realloc_append(_Args && ...__args) { + const size_type __len = _M_check_len(1u, "vector::_M_realloc_append"); + pointer __old_start = this->_M_impl._M_start; + pointer __old_finish = this->_M_impl._M_finish; + pointer __new_start(this->_M_allocate(__len)); + pointer __new_finish(__new_start); + { + if constexpr (_S_use_relocate()) { + __new_finish = std::__uninitialized_move_if_noexcept_a( + __old_start, __old_finish, __new_start, _M_get_Tp_allocator()); + } + } + this->_M_impl._M_start = __new_start; + this->_M_impl._M_finish = __new_finish; + this->_M_impl._M_end_of_storage = __new_start + __len; + } + template + void __unguarded_linear_insert(_RandomAccessIterator __last, + _Compare __comp) { + typename iterator_traits<_RandomAccessIterator>::value_type __val = + std::move(*__last); + _RandomAccessIterator __next = __last; + --__next; + while (__comp(__val, __next)) { + *__last = std::move(*__next); + __last = __next; + } + } + template + void __insertion_sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, _Compare __comp) { + for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) { + std::__unguarded_linear_insert(__i, + __gnu_cxx::__ops::__val_comp_iter(__comp)); + } + } + template + inline void __unguarded_insertion_sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _Compare __comp) { + for (_RandomAccessIterator __i = __first; __i != __last; ++__i) + std::__unguarded_linear_insert(__i, + __gnu_cxx::__ops::__val_comp_iter(__comp)); + } + enum { _S_threshold = 16 }; + template + void __final_insertion_sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, _Compare __comp) { + if (__last - __first > int(_S_threshold)) { + std::__insertion_sort(__first, __first + int(_S_threshold), __comp); + std::__unguarded_insertion_sort(__first + int(_S_threshold), __last, + __comp); + } + } + template + inline void __sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, _Compare __comp) { + if (__first != __last) { + std::__final_insertion_sort(__first, __last, __comp); + } + } + template + inline void sort(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) { + std::__sort(__first, __last, __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } +} + + +void g(); + +void f(int nBands, double maxZErr) { + for (int iBand = 0; iBand < nBands; iBand++) + { + g(); + std::vector noDataCandVec; + std::vector distCandVec = {0, 1, 10, 100, 5, 6}; + for (signed char dist : distCandVec) + noDataCandVec.push_back(1); + std::sort(noDataCandVec.begin(), noDataCandVec.end(), + std::greater()); + } +} diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc index 2964420ad1a..766eaf0e4e7 100644 --- a/gcc/tree-ssa-forwprop.cc +++ b/gcc/tree-ssa-forwprop.cc @@ -3520,6 +3520,7 @@ pass_forwprop::execute (function *fun) |= EDGE_EXECUTABLE; auto_vec to_fixup; auto_vec to_remove; + auto_vec to_remove_defs; auto_vec, 10> edges_to_remove; auto_bitmap simple_dce_worklist; auto_bitmap need_ab_cleanup; @@ -3596,7 +3597,7 @@ pass_forwprop::execute (function *fun) if (all_same) { if (may_propagate_copy (res, first)) - to_remove.safe_push (phi); + to_remove_defs.safe_push (SSA_NAME_VERSION (res)); fwprop_set_lattice_val (res, first); } } @@ -4088,7 +4089,7 @@ pass_forwprop::execute (function *fun) stmt for removal. */ if (val != lhs && may_propagate_copy (lhs, val)) - to_remove.safe_push (stmt); + to_remove_defs.safe_push (SSA_NAME_VERSION (lhs)); fwprop_set_lattice_val (lhs, val); } } @@ -4130,14 +4131,11 @@ pass_forwprop::execute (function *fun) free (bb_to_rpo); lattice.release (); - /* Remove stmts in reverse order to make debug stmt creation possible. */ - while (!to_remove.is_empty()) + /* First remove chains of stmts where we check no uses remain. */ + simple_dce_from_worklist (simple_dce_worklist, to_purge); + + auto remove = [](gimple *stmt) { - gimple *stmt = to_remove.pop (); - /* For example remove_prop_source_from_use can remove stmts queued - for removal. Deal with this gracefully. */ - if (!gimple_bb (stmt)) - continue; if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Removing dead stmt "); @@ -4153,8 +4151,28 @@ pass_forwprop::execute (function *fun) gsi_remove (&gsi, true); release_defs (stmt); } + }; + + /* Then remove stmts we know we can remove even though we did not + substitute in dead code regions, so uses can remain. Do so in reverse + order to make debug stmt creation possible. */ + while (!to_remove_defs.is_empty()) + { + tree def = ssa_name (to_remove_defs.pop ()); + /* For example remove_prop_source_from_use can remove stmts queued + for removal. Deal with this gracefully. */ + if (!def) + continue; + gimple *stmt = SSA_NAME_DEF_STMT (def); + remove (stmt); + } + + /* Wipe other queued stmts that do not have SSA defs. */ + while (!to_remove.is_empty()) + { + gimple *stmt = to_remove.pop (); + remove (stmt); } - simple_dce_from_worklist (simple_dce_worklist, to_purge); /* Fixup stmts that became noreturn calls. This may require splitting blocks and thus isn't possible during the walk. Do this