From: Richard Biener Date: Mon, 4 Jan 2021 12:02:24 +0000 (+0100) Subject: tree-optimization/98464 - replace loop info with avail at uses X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=39bd65faee3bafe2dc067e5fedb5079896551a8a;p=gcc.git tree-optimization/98464 - replace loop info with avail at uses This does VN replacement in loop nb_iterations consistent with the rest of the IL by using availability at the definition site of uses. 2021-01-04 Richard Biener PR tree-optimization/98464 * tree-ssa-sccvn.c (vn_valueize_for_srt): Rename from ... (vn_valueize_wrapper): ... this. Temporarily adjust vn_context_bb. (process_bb): Adjust. * g++.dg/opt/pr98464.C: New testcase. --- diff --git a/gcc/testsuite/g++.dg/opt/pr98464.C b/gcc/testsuite/g++.dg/opt/pr98464.C new file mode 100644 index 00000000000..38d0c1b1f7c --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr98464.C @@ -0,0 +1,155 @@ +// { dg-do compile } +// { dg-require-effective-target c++11 } +// { dg-options "-O3 -fno-tree-dce" } + +template < typename, typename, template < typename > class _Op, typename... _Args > struct __detector { + using type = _Op< _Args... >; + }; + template < typename _Default, template < typename > class _Op, typename... _Args > using __detected_or = __detector< _Default, void, _Op, _Args... >; + template < typename _Default, template < typename > class _Op, typename... _Args > using __detected_or_t = typename __detected_or< _Default, _Op, _Args... >::type; + template < typename, typename > struct __replace_first_arg; + template < template < typename > class _Template, typename _Up, typename _Tp, typename... _Types > struct __replace_first_arg< _Template< _Tp, _Types... >, _Up > { + using type = _Template< _Up >; + }; + template < class > class min_pointer; + class MoveOnly; + struct pointer_traits { + template < typename _Up > using rebind = typename __replace_first_arg< min_pointer< int >, _Up >::type; + }; + template < typename _Iterator > class __normal_iterator { + public: __normal_iterator(_Iterator); + }; + struct __allocator_traits_base { + template < typename _Tp > using __pointer = typename _Tp::pointer; + }; + template < typename _Alloc > struct allocator_traits : __allocator_traits_base { + typedef typename _Alloc::value_type value_type; + using pointer = __detected_or_t< value_type, __pointer, _Alloc >; + template < typename _Tp > struct _Ptr { + using type = pointer_traits::rebind< _Tp >; + }; + using const_pointer = typename _Ptr< value_type >::type; + using size_type = int; + static pointer allocate(_Alloc __a, size_type __n) { + return __a.allocate(__n); + } + }; + template < typename _ForwardIterator, typename _Allocator > void _Destroy(_ForwardIterator __first, _ForwardIterator __last, _Allocator) { + for (; + __first != __last; + ++__first) ; + } + template < typename _InputIterator, typename _ForwardIterator, typename _Allocator > _ForwardIterator __uninitialized_copy_a(_InputIterator, _ForwardIterator, _Allocator); + template < typename _InputIterator, typename _ForwardIterator, typename _Allocator > _ForwardIterator __uninitialized_move_if_noexcept_a(_InputIterator __last, _ForwardIterator __result, _Allocator __alloc) { + return __uninitialized_copy_a(__last, __result, __alloc); + } + template < typename _ForwardIterator, typename _Size, typename _Allocator > _ForwardIterator __uninitialized_default_n_a(_ForwardIterator __first, _Size __n, _Allocator) { + for (; + __n; + --__n, ++__first) ; + return __first; + } + template < typename _Alloc > struct _Vector_base { + typedef _Alloc _Tp_alloc_type; + typedef typename _Tp_alloc_type ::pointer pointer; + struct _Vector_impl_data { + pointer _M_start; + pointer _M_finish; + pointer _M_end_of_storage; + }; + struct _Vector_impl : _Tp_alloc_type, _Vector_impl_data { + _Vector_impl(_Tp_alloc_type) { + } + }; + _Vector_base(long __n, _Alloc __a) : _M_impl(__a) { + _M_impl._M_end_of_storage = _M_impl._M_start + __n; + } + _Vector_impl _M_impl; + pointer _M_allocate(long __n) { + return __n ? allocator_traits< _Tp_alloc_type >::allocate(_M_impl, __n) : pointer(); + } + }; + template < typename, typename _Alloc > class vector : _Vector_base< _Alloc > { + public: typedef typename _Alloc::pointer pointer; + typedef __normal_iterator< typename allocator_traits< _Alloc >::const_pointer > const_iterator; + typedef _Alloc allocator_type; + vector(long __n, allocator_type __a = allocator_type()) : _Vector_base< _Alloc >(__n, __a) { + this->_M_impl._M_finish = __uninitialized_default_n_a(this->_M_impl._M_start, __n, 0); + } + ~vector() { + _Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, 0); + } + const_iterator cbegin() { + return this->_M_impl._M_start; + } + typename _Alloc::value_type operator[](long) { + return *this->_M_impl._M_start; + } + void insert(const_iterator, MoveOnly &&) { + if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) ; + else _M_realloc_insert(); + } + template < typename... > void _M_realloc_insert(); + }; + template < typename _Tp, typename _Alloc > template < typename... > void vector< _Tp, _Alloc >::_M_realloc_insert() { + long __trans_tmp_6 = this->_M_impl._M_finish - this->_M_impl._M_start; + pointer __old_start = this->_M_impl._M_start; + pointer __old_finish = this->_M_impl._M_finish; + pointer __new_start(this->_M_allocate(__trans_tmp_6)); + pointer __new_finish = __uninitialized_move_if_noexcept_a(__old_finish, __new_finish, 0); + _Destroy(__old_start, __old_finish, 0); + this->_M_impl._M_start = __new_start; + this->_M_impl._M_finish = __new_finish; + } + class MoveOnly { + int data_; + public: bool operator==(MoveOnly) { + return data_; + } + }; + void __assert_fail(); + template < class T > class min_pointer { + T *ptr_; + min_pointer(T *p) : ptr_(p) { + } + public: min_pointer() = default; + T operator*() { + return *ptr_; + } + void operator++() { + ++ptr_; + } + void operator+=(long n) { + ptr_ += n; + } + min_pointer operator+(long n) { + min_pointer tmp(*this); + tmp += n; + return tmp; + } + friend long operator-(min_pointer x, min_pointer y) { + return x.ptr_ - y.ptr_; + } + friend bool operator==(min_pointer x, min_pointer y) { + return x.ptr_ == y.ptr_; + } + friend bool operator!=(min_pointer x, min_pointer y) { + return !(x == y); + } + friend class min_allocator; + }; + class min_allocator { + public: typedef MoveOnly value_type; + typedef min_pointer< MoveOnly > pointer; + pointer allocate(long) { + return static_cast< MoveOnly * >(operator new(sizeof(MoveOnly))); + } + }; + int main() { + vector< int, min_allocator > v(100); + v.insert(v.cbegin(), MoveOnly()); + int j = 0; + for (; + j < 10; + ++j) v[j] == MoveOnly() ? void() : __assert_fail(); + } diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index 19defc0cccc..17016853a34 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -304,12 +304,23 @@ static vn_nary_op_t last_inserted_nary; static vn_tables_t valid_info; -/* Valueization hook. Valueize NAME if it is an SSA name, otherwise - just return it. */ +/* Valueization hook for simplify_replace_tree. Valueize NAME if it is + an SSA name, otherwise just return it. */ tree (*vn_valueize) (tree); -tree vn_valueize_wrapper (tree t, void* context ATTRIBUTE_UNUSED) -{ - return vn_valueize (t); +static tree +vn_valueize_for_srt (tree t, void* context ATTRIBUTE_UNUSED) +{ + basic_block saved_vn_context_bb = vn_context_bb; + /* Look for sth available at the definition block of the argument. + This avoids inconsistencies between availability there which + decides if the stmt can be removed and availability at the + use site. The SSA property ensures that things available + at the definition are also available at uses. */ + if (!SSA_NAME_IS_DEFAULT_DEF (t)) + vn_context_bb = gimple_bb (SSA_NAME_DEF_STMT (t)); + tree res = vn_valueize (t); + vn_context_bb = saved_vn_context_bb; + return res; } @@ -6995,7 +7006,7 @@ process_bb (rpo_elim &avail, basic_block bb, if (bb->loop_father->nb_iterations) bb->loop_father->nb_iterations = simplify_replace_tree (bb->loop_father->nb_iterations, - NULL_TREE, NULL_TREE, &vn_valueize_wrapper); + NULL_TREE, NULL_TREE, &vn_valueize_for_srt); } /* Value-number all defs in the basic-block. */