re PR middle-end/57107 (tree check fail in unlink_stmt_vdef)
authorRichard Biener <rguenther@suse.de>
Tue, 30 Apr 2013 13:54:14 +0000 (13:54 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Tue, 30 Apr 2013 13:54:14 +0000 (13:54 +0000)
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

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/torture/pr57107.C [new file with mode: 0644]
gcc/tree-eh.c

index cde1dec35785adca80d0fadaa9abda79dcb32816..bb86d6e8e303b446602e9011402fbe216a06271b 100644 (file)
@@ -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
index 00576eec6a32bc43348fbcfab814ef591e17e35d..0d5705a60ed28eaf4acb06645fa0d82ce760dfbc 100644 (file)
@@ -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 (file)
index 0000000..516dec1
--- /dev/null
@@ -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)))))  {
+    }
+}
index 56132e15702a4cf8e5bd3e355960f7788e6dee99..c90094986a07388285c33094e110ec2fadbecf9a 100644 (file)
@@ -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