From bb66e2d1a9c19408a43f6648e93f329187716115 Mon Sep 17 00:00:00 2001 From: law Date: Wed, 11 Sep 2013 02:23:48 +0000 Subject: [PATCH] PR tree-optimization/58380 * tree-ssa-threadupdate.c (thread_block): Recognize another case of threading through a buried loop header. * tree-ssa-threadedge.c (thread_around_empty_blocks): Correct return value for single successor case. * g++.dg/torture/pr58380.C: New test. 2013-09-10 Jeff Law git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202489 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 9 ++ gcc/testsuite/ChangeLog | 4 + gcc/testsuite/g++.dg/torture/pr58380.C | 171 +++++++++++++++++++++++++++++++++ gcc/tree-ssa-threadedge.c | 29 ++++-- gcc/tree-ssa-threadupdate.c | 6 +- 5 files changed, 209 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/pr58380.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d4d32e1..21c8538 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2013-09-10 Jeff Law + + PR tree-optimization/58380 + * tree-ssa-threadupdate.c (thread_block): Recognize another case + of threading through a buried loop header. + + * tree-ssa-threadedge.c (thread_around_empty_blocks): Correct + return value for single successor case. + 2013-09-10 Jan Hubicka * ipa-devirt.c (ipa_devirt): Enable with LTO. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8d58e2d..ae9e6e2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2013-09-10 Jeff Law + + * g++.dg/torture/pr58380.C: New test. + 2013-09-10 Jan Hubicka Paolo Carlini diff --git a/gcc/testsuite/g++.dg/torture/pr58380.C b/gcc/testsuite/g++.dg/torture/pr58380.C new file mode 100644 index 0000000..b2c185d --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr58380.C @@ -0,0 +1,171 @@ +// { dg-do compile } +class iplugin_factory; +class idocument_plugin_factory { + virtual idocument_plugin_factory *create_plugin(iplugin_factory &, int &); +}; +template class __normal_iterator { + _Iterator _M_current; + +public: + _Iterator iterator_type; + __normal_iterator(const _Iterator &p1) : _M_current(p1) {} + void operator++(); + _Iterator &base() { return _M_current; } +}; + +template +int operator!=(__normal_iterator<_IteratorL, _Container> &p1, + __normal_iterator<_IteratorR, _Container> &p2) { + return p1.base() != p2.base(); +} + +class new_allocator { +public: + typedef int *const_pointer; + int *allocate(); +}; +template class allocator : public new_allocator {}; + +class basic_string { +public: + basic_string(char *); +}; +struct __uninitialized_copy { + template + static _ForwardIterator __uninit_copy(_InputIterator p1, _InputIterator p2, + _ForwardIterator p3) try { + for (; p1 != p2; ++p1, ++p3) + ; + return p3; + } + catch (...) { + } +}; + +template +_ForwardIterator uninitialized_copy(_InputIterator p1, _InputIterator p2, + _ForwardIterator p3) { + return __uninitialized_copy::__uninit_copy(p1, p2, p3); +} + +template +_ForwardIterator __uninitialized_copy_a(_InputIterator p1, _InputIterator p2, + _ForwardIterator p3, allocator<_Tp> &) { + return uninitialized_copy(p1, p2, p3); +} + +struct _Vector_base { + struct _Vector_impl : allocator { + int *_M_start; + int *_M_finish; + }; + allocator &_M_get_Tp_allocator() {} + _Vector_base() {} + _Vector_base(int p1) { _M_create_storage(p1); } + _Vector_impl _M_impl; + int *_M_allocate(int p1) { p1 ? _M_impl.allocate() : 0; } + void _M_create_storage(int p1) { + this->_M_impl._M_start = this->_M_allocate(p1); + } +}; + +class vector : _Vector_base { + _Vector_base _Base; + +public: + vector() {} + vector(const vector &p1) : _Base(p1.size()) { + this->_M_impl._M_finish = __uninitialized_copy_a( + p1.begin(), p1.end(), this->_M_impl._M_start, _M_get_Tp_allocator()); + } + ~vector(); + __normal_iterator::const_pointer, int> begin() const { + return this->_M_impl._M_start; + } + __normal_iterator::const_pointer, int> end() const { + return this->_M_impl._M_finish; + } + int size() const { return this->_M_impl._M_finish - this->_M_impl._M_start; } +}; +class iplugin_factory { +public: + typedef enum { + STABLE, + EXPERIMENTAL + } quality_t; +}; +class plugin_factory : public iplugin_factory { +public: + plugin_factory(const int &, const basic_string &, const basic_string &, + const basic_string &, quality_t); +}; +template +class document_plugin_factory : plugin_factory, idocument_plugin_factory { +public: + document_plugin_factory(const int &p1, const basic_string &, + const basic_string &, const basic_string &, quality_t) + : plugin_factory(0, 0, 0, 0, STABLE) {} + idocument_plugin_factory *create_plugin(iplugin_factory &p1, int &p2) { + plugin_t(p1, p2); + } +}; + +class container { +public: + template container(init_t &); +}; +template class initializer_t : init_t { +public: + initializer_t(const init_t &p1) : init_t(p1) {} +}; + +class composition_t {}; +template +const initializer_t operator+(const initializer_t &, + const initializer_t &); +template class value_initializer_t { +public: + value_initializer_t(const value_t &p1) : m_value(p1) {} + value_t m_value; +}; + +template +initializer_t > init_value(const value_t &p1) { + initializer_t >( + value_initializer_t(p1)); +} + +class name_t {}; +class label_t {}; +class description_t {}; +class owner_initializer_t {}; +template +initializer_t init_owner(owner_t &); +class set : vector {}; +class node { +public: + node(iplugin_factory &, int &); +}; +initializer_t init_name(); +initializer_t init_label(); +initializer_t init_description(); +template class mesh_selection_sink : base_t { +public: + mesh_selection_sink(iplugin_factory &p1, int &p2) + : base_t(p1, p2), + m_mesh_selection(init_owner(*this) + init_name() + init_label() + + init_description() + init_value(set())) {} + container m_mesh_selection; +}; + +class selection_to_stdout : mesh_selection_sink { +public: + selection_to_stdout(iplugin_factory &p1, int &p2) + : mesh_selection_sink(p1, p2) {} + static iplugin_factory &get_factory() { + document_plugin_factory(0, "", 0, "", + iplugin_factory::EXPERIMENTAL); + } +}; + +void selection_to_stdout_factory() { selection_to_stdout::get_factory(); } diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 14bc4e3..839f185 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -770,7 +770,19 @@ thread_around_empty_blocks (edge taken_edge, gsi = gsi_start_nondebug_bb (bb); /* If the block has no statements, but does have a single successor, then - it's just a forwarding block and we can thread through it trivially. */ + it's just a forwarding block and we can thread through it trivially. + + However, note that just threading through empty blocks with single + successors is not inherently profitable. For the jump thread to + be profitable, we must avoid a runtime conditional. + + By taking the return value from the recursive call, we get the + desired effect of returning TRUE when we found a profitable jump + threading opportunity and FALSE otherwise. + + This is particularly important when this routine is called after + processing a joiner block. Returning TRUE too aggressively in + that case results in pointless duplication of the joiner block. */ if (gsi_end_p (gsi)) { if (single_succ_p (bb)) @@ -781,15 +793,16 @@ thread_around_empty_blocks (edge taken_edge, { bitmap_set_bit (visited, taken_edge->dest->index); path->safe_push (taken_edge); - thread_around_empty_blocks (taken_edge, - dummy_cond, - handle_dominating_asserts, - simplify, - visited, - path); - return true; + return thread_around_empty_blocks (taken_edge, + dummy_cond, + handle_dominating_asserts, + simplify, + visited, + path); } } + + /* We have a block with no statements, but multiple successors? */ return false; } diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c index 3c3d3bc..6d43dc3 100644 --- a/gcc/tree-ssa-threadupdate.c +++ b/gcc/tree-ssa-threadupdate.c @@ -659,8 +659,10 @@ thread_block (basic_block bb, bool noloop_only) threading path. We do not try and thread this elsewhere, so just cancel the jump threading request by clearing the AUX field now. */ - if (bb->loop_father != e2->src->loop_father - && !loop_exit_edge_p (e2->src->loop_father, e2)) + if ((bb->loop_father != e2->src->loop_father + && !loop_exit_edge_p (e2->src->loop_father, e2)) + || (e2->src->loop_father != e2->dest->loop_father + && !loop_exit_edge_p (e2->src->loop_father, e2))) { /* Since this case is not handled by our special code to thread through a loop header, we must explicitly -- 2.7.4