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.
This commit is contained in:
parent
7f2b731756
commit
39bd65faee
155
gcc/testsuite/g++.dg/opt/pr98464.C
Normal file
155
gcc/testsuite/g++.dg/opt/pr98464.C
Normal file
@ -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();
|
||||
}
|
||||
@ -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)
|
||||
static tree
|
||||
vn_valueize_for_srt (tree t, void* context ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return vn_valueize (t);
|
||||
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. */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user