aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2013-04-30 13:54:14 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2013-04-30 13:54:14 +0000
commit4c1aff1ce430fdf4b46caa632fd44b4d0f557720 (patch)
treeb5bca3706a64ea2adc3ab07083628f891afef77b
parent54b8379a261d1b36958aecbca568ef6475a8e1ca (diff)
downloadgcc-4c1aff1ce430fdf4b46caa632fd44b4d0f557720.zip
gcc-4c1aff1ce430fdf4b46caa632fd44b4d0f557720.tar.gz
gcc-4c1aff1ce430fdf4b46caa632fd44b4d0f557720.tar.bz2
re PR middle-end/57107 (tree check fail in unlink_stmt_vdef)
2013-04-30 Richard Biener <rguenther@suse.de> PR middle-end/57107 * tree-eh.c (sink_clobbers): Preserve virtual SSA form. * g++.dg/torture/pr57107.C: New testcase. From-SVN: r198454
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/torture/pr57107.C193
-rw-r--r--gcc/tree-eh.c48
4 files changed, 241 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cde1dec..bb86d6e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2013-04-30 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/57107
+ * tree-eh.c (sink_clobbers): Preserve virtual SSA form.
+
2013-04-30 Andrey Belevantsev <abel@ispras.ru>
PR rtl-optimization/56957
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 00576ee..0d5705a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2013-04-30 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/57107
+ * g++.dg/torture/pr57107.C: New testcase.
+
2013-04-30 Andrey Belevantsev <abel@ispras.ru>
PR rtl-optimization/57105
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
new file mode 100644
index 0000000..516dec1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -0,0 +1,193 @@
+// { dg-do compile }
+
+typedef long unsigned int size_t;
+namespace std {
+}
+namespace std __attribute__ ((__visibility__ ("default"))) {
+ template<class _Sp, class _Tp> struct __traitor {
+ enum {
+ __value = bool(_Sp::__value) || bool(_Tp::__value) };
+ };
+ template<typename _Tp> struct __is_integer {
+ enum {
+ __value = 0 };
+ };
+ template<typename _Tp> struct __is_floating {
+ enum {
+ __value = 0 };
+ };
+ template<typename _Tp> struct __is_pointer {
+ enum {
+ __value = 0 };
+ };
+ template<typename _Tp> struct __is_normal_iterator {
+ enum {
+ __value = 0 };
+ };
+ template<typename _Tp> struct __is_arithmetic : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> > {
+ };
+ template<typename _Tp> struct __is_scalar : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> > {
+ };
+}
+namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
+ template<bool, typename> struct __enable_if {
+ };
+ template<typename _Tp> struct __enable_if<true, _Tp> {
+ typedef _Tp __type;
+ };
+}
+namespace std __attribute__ ((__visibility__ ("default"))) {
+ template<typename _Iterator> struct iterator_traits {
+ };
+ template<typename _Tp> struct iterator_traits<_Tp*> {
+ typedef _Tp value_type;
+ };
+ template<typename _Iterator, bool _HasBase> struct _Iter_base {
+ typedef _Iterator iterator_type;
+ };
+}
+namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
+}
+namespace std __attribute__ ((__visibility__ ("default"))) {
+ template<typename _Iterator> struct _Niter_base : _Iter_base<_Iterator, __is_normal_iterator<_Iterator>::__value> {
+ };
+ template<typename _Iterator> inline typename _Niter_base<_Iterator>::iterator_type __niter_base(_Iterator __it) {
+ }
+ template<typename _OutputIterator, typename _Size, typename _Tp> inline typename __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value) {
+ for (__decltype(__n + 0) __niter = __n;
+ __niter > 0;
+ --__niter, ++__first) *__first = __value;
+ }
+ template<typename _OI, typename _Size, typename _Tp> inline _OI fill_n(_OI __first, _Size __n, const _Tp& __value) {
+ return _OI(std::__fill_n_a(std::__niter_base(__first), __n, __value));
+ }
+}
+namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
+ template<typename _Tp> class new_allocator {
+ public:
+ typedef size_t size_type;
+ typedef _Tp* pointer;
+ ~new_allocator() throw() {
+ }
+ pointer allocate(size_type __n, const void* = 0) {
+ return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
+ }
+ };
+}
+namespace std __attribute__ ((__visibility__ ("default"))) {
+ template<typename _Tp> class allocator: public __gnu_cxx::new_allocator<_Tp> {
+ public:
+ template<typename _Tp1> struct rebind {
+ typedef allocator<_Tp1> other;
+ };
+ };
+}
+namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
+ template<typename _Alloc> struct __alloc_traits {
+ typedef typename _Alloc::pointer pointer;
+ template<typename _Tp> struct rebind {
+ typedef typename _Alloc::template rebind<_Tp>::other other;
+ };
+ };
+}
+class QString {
+public:
+ bool isEmpty() const;
+};
+class QObject {
+};
+namespace std __attribute__ ((__visibility__ ("default"))) {
+ template<bool _TrivialValueType> struct __uninitialized_fill_n {
+ template<typename _ForwardIterator, typename _Size, typename _Tp> static void __uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) {
+ std::fill_n(__first, __n, __x);
+ }
+ };
+ template<typename _ForwardIterator, typename _Size, typename _Tp> inline void uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) {
+ typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
+ std::__uninitialized_fill_n<__is_trivial(_ValueType)>:: __uninit_fill_n(__first, __n, __x);
+ }
+ template<typename _ForwardIterator, typename _Size, typename _Tp, typename _Tp2> inline void __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n, const _Tp& __x, allocator<_Tp2>&) {
+ std::uninitialized_fill_n(__first, __n, __x);
+ }
+ template<typename _Tp, typename _Alloc> struct _Vector_base {
+ typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;
+ typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer pointer;
+ struct _Vector_impl : public _Tp_alloc_type {
+ pointer _M_start;
+ pointer _M_finish;
+ pointer _M_end_of_storage;
+ _Vector_impl(_Tp_alloc_type const& __a) : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0) {
+ }
+ };
+ typedef _Alloc allocator_type;
+ _Tp_alloc_type& _M_get_Tp_allocator() {
+ }
+ _Vector_base(size_t __n, const allocator_type& __a) : _M_impl(__a) {
+ _M_create_storage(__n);
+ }
+ _Vector_impl _M_impl;
+ pointer _M_allocate(size_t __n) {
+ return __n != 0 ? _M_impl.allocate(__n) : 0;
+ }
+ void _M_create_storage(size_t __n) {
+ this->_M_impl._M_start = this->_M_allocate(__n);
+ this->_M_impl._M_finish = this->_M_impl._M_start;
+ }
+ };
+ template<typename _Tp, typename _Alloc = std::allocator<_Tp> > class vector : protected _Vector_base<_Tp, _Alloc> {
+ typedef _Vector_base<_Tp, _Alloc> _Base;
+ typedef _Tp value_type;
+ typedef size_t size_type;
+ typedef _Alloc allocator_type;
+ using _Base::_M_get_Tp_allocator;
+ public:
+ explicit vector(size_type __n, const value_type& __value = value_type(), const allocator_type& __a = allocator_type()) : _Base(__n, __a) {
+ _M_fill_initialize(__n, __value);
+ }
+ void _M_fill_initialize(size_type __n, const value_type& __value) {
+ std::__uninitialized_fill_n_a(this->_M_impl._M_start, __n, __value, _M_get_Tp_allocator());
+ }
+ };
+};
+class QPaintDevice {
+public:
+ int width() const {
+ }
+ int height() const {
+ }
+};
+class QImage : public QPaintDevice {
+};
+extern "C" {
+ struct __jmp_buf_tag {
+ };
+ typedef struct __jmp_buf_tag jmp_buf[1];
+ extern int _setjmp (struct __jmp_buf_tag __env[1]) throw ();
+ extern void longjmp (struct __jmp_buf_tag __env[1], int __val) throw () __attribute__ ((__noreturn__));
+}
+typedef unsigned int png_uint_32;
+typedef void * png_voidp;
+typedef const char * png_const_charp;
+extern "C" {
+ typedef struct png_struct_def png_struct;
+ typedef png_struct * png_structp;
+ typedef void ( *png_error_ptr) (png_structp, png_const_charp);
+ typedef void ( *png_longjmp_ptr) (jmp_buf, int);
+ extern __attribute__((__malloc__)) png_structp ( png_create_write_struct) (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn) ;
+ extern jmp_buf* ( png_set_longjmp_fn) (png_structp png_ptr, png_longjmp_ptr longjmp_fn, size_t jmp_buf_size) ;
+}
+class PngWriter : public QObject {
+ const QImage *m_out_qimage;
+ QString m_fname;
+ bool writeQImageToPng();
+};
+bool PngWriter::writeQImageToPng() {
+ png_uint_32 width = m_out_qimage->width();
+ png_uint_32 height = m_out_qimage->height();
+ if ( !m_fname.isEmpty() ) {
+ std::vector<char> t(width * height * 4 + (width * height * 4) * 0.1);
+ }
+ png_structp png_ptr = png_create_write_struct ("1.5.13", __null, __null, __null);
+ if (_setjmp ((*png_set_longjmp_fn((png_ptr), longjmp, sizeof (jmp_buf))))) {
+ }
+}
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 56132e1..c900949 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -3342,7 +3342,24 @@ sink_clobbers (basic_block bb)
if (!any_clobbers)
return 0;
- succbb = single_succ (bb);
+ edge succe = single_succ_edge (bb);
+ succbb = succe->dest;
+
+ /* See if there is a virtual PHI node to take an updated virtual
+ operand from. */
+ gimple vphi = NULL;
+ tree vuse = NULL_TREE;
+ for (gsi = gsi_start_phis (succbb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ tree res = gimple_phi_result (gsi_stmt (gsi));
+ if (virtual_operand_p (res))
+ {
+ vphi = gsi_stmt (gsi);
+ vuse = res;
+ break;
+ }
+ }
+
dgsi = gsi_after_labels (succbb);
gsi = gsi_last_bb (bb);
for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
@@ -3353,7 +3370,6 @@ sink_clobbers (basic_block bb)
continue;
if (gimple_code (stmt) == GIMPLE_LABEL)
break;
- unlink_stmt_vdef (stmt);
lhs = gimple_assign_lhs (stmt);
/* Unfortunately we don't have dominance info updated at this
point, so checking if
@@ -3365,21 +3381,33 @@ sink_clobbers (basic_block bb)
&& TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME
&& !SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (lhs, 0)))
{
+ unlink_stmt_vdef (stmt);
gsi_remove (&gsi, true);
release_defs (stmt);
continue;
}
+
+ /* As we do not change stmt order when sinking across a
+ forwarder edge we can keep virtual operands in place. */
gsi_remove (&gsi, false);
- /* Trigger the operand scanner to cause renaming for virtual
- operands for this statement.
- ??? Given the simple structure of this code manually
- figuring out the reaching definition should not be too hard. */
- if (gimple_vuse (stmt))
- gimple_set_vuse (stmt, NULL_TREE);
- gsi_insert_before (&dgsi, stmt, GSI_SAME_STMT);
+ gsi_insert_before (&dgsi, stmt, GSI_NEW_STMT);
+
+ /* But adjust virtual operands if we sunk across a PHI node. */
+ if (vuse)
+ {
+ gimple use_stmt;
+ imm_use_iterator iter;
+ use_operand_p use_p;
+ FOR_EACH_IMM_USE_STMT (use_stmt, iter, vuse)
+ FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+ SET_USE (use_p, gimple_vdef (stmt));
+ /* Adjust the incoming virtual operand. */
+ SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (vphi, succe), gimple_vuse (stmt));
+ SET_USE (gimple_vuse_op (stmt), vuse);
+ }
}
- return TODO_update_ssa_only_virtuals;
+ return 0;
}
/* At the end of inlining, we can lower EH_DISPATCH. Return true when