tree-optimization/98464 - replace loop info with avail at uses
authorRichard Biener <rguenther@suse.de>
Mon, 4 Jan 2021 12:02:24 +0000 (13:02 +0100)
committerRichard Biener <rguenther@suse.de>
Mon, 4 Jan 2021 12:51:56 +0000 (13:51 +0100)
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.

gcc/testsuite/g++.dg/opt/pr98464.C [new file with mode: 0644]
gcc/tree-ssa-sccvn.c

diff --git a/gcc/testsuite/g++.dg/opt/pr98464.C b/gcc/testsuite/g++.dg/opt/pr98464.C
new file mode 100644 (file)
index 0000000..38d0c1b
--- /dev/null
@@ -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();
+    }
index 19defc0cccc35eaf9b6e0a0a0fc75739a529accc..17016853a34994ed787f64e550bb2a061872e375 100644 (file)
@@ -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.  */