Hi,

As PR98464 shows, this patch is to make rpo_vn_valueize
consider the definition basic block of name, to sync
with what we do in function eliminate_stmt.

Bootstrapped/regtested on powerpc64le-linux-gnu P9.

Full SPEC2017 build/run passed on P9.

BR,
Kewen

gcc/ChangeLog:

        PR tree-optimization/98464
        * tree-ssa-sccvn.c (rpo_vn_valueize): Use the def basic block
        to keep consistent with eliminate_stmt.

gcc/testsuite/ChangeLog:

        PR tree-optimization/98464
        * g++.dg/tree-ssa/pr98464.C: New test.

---
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr98464.C 
b/gcc/testsuite/g++.dg/tree-ssa/pr98464.C
new file mode 100644
index 00000000000..1cbc4a8ef8d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr98464.C
@@ -0,0 +1,186 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-O3 -fno-tree-dce" } */
+
+/* This case is to check there is no ICE.  */
+
+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 81990fcbd34..eb900642dde 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -6901,9 +6901,16 @@ rpo_vn_valueize (tree name)
            {
              if (TREE_CODE (tem) != SSA_NAME)
                return tem;
+             basic_block bb = vn_context_bb;
+             if (!SSA_NAME_IS_DEFAULT_DEF (name))
+               {
+                 basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (name));
+                 if (def_bb)
+                   bb = def_bb;
+               }
              /* For all values we only valueize to an available leader
                 which means we can use SSA name info without restriction.  */
-             tem = rpo_avail->eliminate_avail (vn_context_bb, tem);
+             tem = rpo_avail->eliminate_avail (bb, tem);
              if (tem)
                return tem;
            }

Reply via email to