aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2021-01-04 13:02:24 +0100
committerRichard Biener <rguenther@suse.de>2021-01-04 13:51:56 +0100
commit39bd65faee3bafe2dc067e5fedb5079896551a8a (patch)
tree9da1da01aeca091cfad6664b0490ed8c03da488c
parent7f2b73175666f678adbf007907c7aa2661284bd3 (diff)
downloadgcc-39bd65faee3bafe2dc067e5fedb5079896551a8a.zip
gcc-39bd65faee3bafe2dc067e5fedb5079896551a8a.tar.gz
gcc-39bd65faee3bafe2dc067e5fedb5079896551a8a.tar.bz2
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 <rguenther@suse.de> 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.
-rw-r--r--gcc/testsuite/g++.dg/opt/pr98464.C155
-rw-r--r--gcc/tree-ssa-sccvn.c23
2 files changed, 172 insertions, 6 deletions
diff --git a/gcc/testsuite/g++.dg/opt/pr98464.C b/gcc/testsuite/g++.dg/opt/pr98464.C
new file mode 100644
index 0000000..38d0c1b
--- /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 19defc0..1701685 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. */