diff mbox series

[committed,PR,tree-optimization/92788] Check right edge flags when suppressing jump threading

Message ID cdea60ce5f5c17a3f9762185b388d84ffe823fe3.camel@redhat.com
State New
Headers show
Series [committed,PR,tree-optimization/92788] Check right edge flags when suppressing jump threading | expand

Commit Message

Jeff Law Jan. 24, 2020, 10:52 p.m. UTC
When we thread through the successor of a joiner block we make a clone
of the joiner block and redirect its outgoing edges.  Of course if
there's cases where we can't redirect an edge, then bad things will
happen.

The code already checked for EDGE_ABNORMAL to suppress threading in
that case.  But it really should have been checking EDGE_COMPLEX which
includes ABNORMAL_CALL, EH and PRESERVE.

This patch fixes that oversight and resolves the BZ.  Bootstrapped and
regression tested on x86_64.  Committed to the trunk.

jeff
commit 98181563dc4c65c9d23eaa99134e18876b6ec671
Author: Jeff Law <law@torsion.usersys.redhat.com>
Date:   Fri Jan 24 17:44:10 2020 -0500

    Fix ICE due to invalid jump threading request
    
            PR tree-optimization/92788
            * tree-ssa-threadedge.c (thread_across_edge): Check EDGE_COMPLEX
            not EDGE_ABNORMAL.
    
            PR tree-optimization/92788
            * g++.dg/pr92788.C: New test.

Comments

Jakub Jelinek Jan. 25, 2020, 11:36 p.m. UTC | #1
On Fri, Jan 24, 2020 at 03:52:51PM -0700, Jeff Law wrote:
> When we thread through the successor of a joiner block we make a clone
> of the joiner block and redirect its outgoing edges.  Of course if
> there's cases where we can't redirect an edge, then bad things will
> happen.
> 
> The code already checked for EDGE_ABNORMAL to suppress threading in
> that case.  But it really should have been checking EDGE_COMPLEX which
> includes ABNORMAL_CALL, EH and PRESERVE.
> 
> This patch fixes that oversight and resolves the BZ.  Bootstrapped and
> regression tested on x86_64.  Committed to the trunk.

The test FAILs on i686-linux, operator new's first parameter needs to be
size_t, which for ia32 is not unsigned long, but unsigned int.

Also, I think we shouldn't be adding tests to g++.dg/ directly, for
optimization test it might be better in g++.dg/opt/, but as it is x86
guarded, I've moved it to g++.dg/target/i386/ instead.

Tested on x86_64-linux -m32/-m64, committed to trunk as obvious.

2020-01-26  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/92788
	* g++.dg/pr92788.C: Move to ...
	* g++.target/i386/pr92788.C: ... here.  Remove target from dg-do line.
	Change type of operator new's first parameter to __SIZE_TYPE__.

diff --git a/gcc/testsuite/g++.dg/pr92788.C b/gcc/testsuite/g++.target/i386/pr92788.C
similarity index 98%
rename from gcc/testsuite/g++.dg/pr92788.C
rename to gcc/testsuite/g++.target/i386/pr92788.C
index b92ae38f7aa..048bbd1b9b8 100644
--- a/gcc/testsuite/g++.dg/pr92788.C
+++ b/gcc/testsuite/g++.target/i386/pr92788.C
@@ -1,4 +1,4 @@
-/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-do compile } */
 /* { dg-require-effective-target c++11 } */
 /* { dg-options "-O3 -fnon-call-exceptions -ftracer -march=k8 -Wno-return-type" } */
 
@@ -17,7 +17,7 @@ struct is_same : integral_constant<true> {};
 
 template <bool, typename _Tp> using __enable_if_t = _Tp;
 
-void *operator new(unsigned long, void *__p) { return __p; }
+void *operator new(__SIZE_TYPE__, void *__p) { return __p; }
 
 template <typename _Iterator, typename> class __normal_iterator {
 


	Jakub
diff mbox series

Patch

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b1b46326306..0f19fc44212 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@ 
+2020-01-24  Jeff Law  <law@redhat.com>
+
+	PR tree-optimization/92788
+	* tree-ssa-threadedge.c (thread_across_edge): Check EDGE_COMPLEX
+	not EDGE_ABNORMAL.
+
 2020-01-24  Jakub Jelinek  <jakub@redhat.com>
 
 	PR target/93395
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1fc95b334a8..a8d517ad8a3 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@ 
+2020-01-24  Jeff Law  <law@redhat.com
+
+	PR tree-optimization/92788
+	* g++.dg/pr92788.C: New test.
+
 2020-01-24  Jakub Jelinek  <jakub@redhat.com>
 
 	PR target/93395
diff --git a/gcc/testsuite/g++.dg/pr92788.C b/gcc/testsuite/g++.dg/pr92788.C
new file mode 100644
index 00000000000..b92ae38f7aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr92788.C
@@ -0,0 +1,470 @@ 
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-require-effective-target c++11 } */
+/* { dg-options "-O3 -fnon-call-exceptions -ftracer -march=k8 -Wno-return-type" } */
+
+
+template <int __v> struct integral_constant {
+
+  static constexpr int value = __v;
+
+};
+
+template <bool __v> using __bool_constant = integral_constant<__v>;
+
+template <typename _Tp, typename _Up>
+
+struct is_same : integral_constant<true> {};
+
+template <bool, typename _Tp> using __enable_if_t = _Tp;
+
+void *operator new(unsigned long, void *__p) { return __p; }
+
+template <typename _Iterator, typename> class __normal_iterator {
+
+  _Iterator _M_current;
+
+
+
+public:
+
+  __normal_iterator(_Iterator) {}
+
+  void operator++() { ++_M_current; }
+
+  _Iterator base() { return _M_current; }
+
+};
+
+template <typename _IteratorL, typename _IteratorR, typename _Container>
+
+bool operator!=(__normal_iterator<_IteratorL, _Container> __lhs,
+
+  __normal_iterator<_IteratorR, _Container> __rhs) {
+
+  return __lhs.base() != __rhs.base();
+
+}
+
+template <typename _Tp> void construct_at(_Tp *__location) noexcept {
+
+  new (__location) _Tp;
+
+}
+
+template <typename _Tp> void _Construct(_Tp __p) { construct_at(__p); }
+
+struct _Any_data {
+
+  template <typename _Tp> _Tp _M_access();
+
+};
+
+enum _Manager_operation {};
+
+template <typename> class function;
+
+class _Function_base {
+
+public:
+
+  template <typename _Functor> class _Base_manager {
+
+public:
+
+    static bool _M_manager(_Any_data, _Any_data __source, _Manager_operation) {
+
+      _Functor(*__source._M_access<_Functor *>());
+
+      return true;
+
+    }
+
+  };
+
+  typedef bool (*_Manager_type)(_Any_data &, const _Any_data &,
+
+    _Manager_operation);
+
+  _Manager_type _M_manager;
+
+};
+
+template <typename, typename> class _Function_handler;
+
+template <typename _Res, typename _Functor, typename... _ArgTypes>
+
+class _Function_handler<_Res(_ArgTypes...), _Functor> : _Function_base {
+
+public:
+
+  static bool _M_manager(_Any_data &__dest, const _Any_data &__source,
+
+    _Manager_operation __op) {
+
+    _Base_manager<_Functor>::_M_manager(__dest, __source, __op);
+
+  }
+
+};
+
+template <typename _Res, typename... _ArgTypes>
+
+class function<_Res(_ArgTypes...)> : _Function_base {
+
+  template <typename, typename _Tp> using _Requires = _Tp;
+
+
+
+public:
+
+  template <typename _Functor,
+
+            typename = _Requires<__bool_constant<!bool()>, void>,
+
+            typename = _Requires<_Functor, void>>
+
+  function(_Functor);
+
+};
+
+template <typename _Res, typename... _ArgTypes>
+
+template <typename _Functor, typename, typename>
+
+function<_Res(_ArgTypes...)>::function(_Functor) {
+
+  _M_manager = _Function_handler<_Res(), _Functor>::_M_manager;
+
+}
+
+template <typename _Tp> class new_allocator {
+
+public:
+
+  _Tp *allocate(long) { return static_cast<_Tp *>(operator new(sizeof(_Tp))); }
+
+};
+
+namespace std {
+
+  template <typename> struct allocator_traits;
+
+  template <typename _Tp> struct allocator_traits<new_allocator<_Tp>> {
+
+    using allocator_type = new_allocator<_Tp>;
+
+    using pointer = _Tp *;
+
+    using const_pointer = _Tp *;
+
+    using size_type = long;
+
+    template <typename _Up> using rebind_alloc = new_allocator<_Up>;
+
+    static pointer allocate(allocator_type __a, size_type __n) {
+
+      return __a.allocate(__n);
+
+    }
+
+    static void deallocate(allocator_type, pointer, size_type);
+
+  };
+
+}
+
+template <typename _Alloc>
+
+struct __alloc_traits : std::allocator_traits<_Alloc> {
+
+  template <typename _Tp> struct rebind {
+
+    typedef typename std::allocator_traits<_Alloc>::template rebind_alloc<_Tp> other;
+
+  };
+
+};
+
+namespace std {
+
+  struct __uninitialized_copy {
+
+    template <typename _InputIterator, typename _ForwardIterator>
+
+    static _ForwardIterator __uninit_copy(_InputIterator __first,
+
+      _InputIterator __last,
+
+      _ForwardIterator __result) {
+
+      for (; __first != __last; ++__first, ++__result)
+
+        _Construct(__result);
+
+      return __result;
+
+    }
+
+  };
+
+  template <typename _InputIterator, typename _ForwardIterator>
+
+  _ForwardIterator uninitialized_copy(_InputIterator __first,
+
+    _InputIterator __last,
+
+    _ForwardIterator __result) {
+
+    return __uninitialized_copy::__uninit_copy(__first, __last, __result);
+
+  }
+
+  template <typename _InputIterator, typename _ForwardIterator, typename _Tp>
+
+  _ForwardIterator __uninitialized_copy_a(_InputIterator __first,
+
+    _InputIterator __last,
+
+    _ForwardIterator __result, _Tp) {
+
+    return uninitialized_copy(__first, __last, __result);
+
+  }
+
+  template <typename _Tp, typename _Alloc> struct _Vector_base {
+
+    typedef typename __alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;
+
+    typedef typename __alloc_traits<_Tp_alloc_type>::pointer pointer;
+
+    struct _Vector_impl_data {
+
+      pointer _M_start;
+
+      pointer _M_finish;
+
+    };
+
+    struct _Vector_impl : _Tp_alloc_type, _Vector_impl_data {};
+
+    _Tp_alloc_type _M_get_Tp_allocator();
+
+    _Vector_base(long, _Alloc) {
+
+      _M_impl._M_start = _M_allocate();
+
+      _M_impl._M_finish = _M_impl._M_start;
+
+    }
+
+    ~_Vector_base() { _M_deallocate(_M_impl._M_start); }
+
+    _Vector_impl _M_impl;
+
+    long _M_allocate___n;
+
+    pointer _M_allocate() {
+
+      typedef __alloc_traits<_Tp_alloc_type> _Tr;
+
+      return _M_allocate___n ? _Tr::allocate(_M_impl, _M_allocate___n)
+
+        : pointer();
+
+    }
+
+    long _M_deallocate___n;
+
+    void _M_deallocate(pointer __p) {
+
+      typedef __alloc_traits<_Tp_alloc_type> _Tr;
+
+      if (__p)
+
+        _Tr::deallocate(_M_impl, __p, _M_deallocate___n);
+
+    }
+
+  };
+
+  template <typename _Tp, typename _Alloc = new_allocator<_Tp>>
+
+  class vector : _Vector_base<_Tp, _Alloc> {
+
+    typedef _Vector_base<_Tp, _Alloc> _Base;
+
+    typedef __normal_iterator<
+
+      typename __alloc_traits<typename _Base::_Tp_alloc_type>::const_pointer,
+
+      int>
+
+    const_iterator;
+
+    using _Base::_M_get_Tp_allocator;
+
+
+
+public:
+
+    vector();
+
+    vector(vector &__x) : _Base(0, _M_get_Tp_allocator()) {
+
+      this->_M_impl._M_finish = __uninitialized_copy_a(__x.begin(), __x.end(),
+
+        this->_M_impl._M_start, 0);
+
+    }
+
+    const_iterator begin() noexcept { return this->_M_impl._M_start; }
+
+    const_iterator end() noexcept { return this->_M_impl._M_finish; }
+
+  };
+
+  template <typename _Tp> class __shared_ptr_access {
+
+public:
+
+    using element_type = _Tp;
+
+    element_type *operator->();
+
+  };
+
+  enum syntax_option_type : int;
+
+  template <typename> using _Matcher = function<bool()>;
+
+  struct _NFA {
+
+    void _M_insert_matcher(_Matcher<int>);
+
+  };
+
+  template <typename _TraitsT> class _Compiler {
+
+public:
+
+    typedef typename _TraitsT::char_type *_IterT;
+
+    _Compiler(_IterT, _IterT, const typename _TraitsT::locale_type &, syntax_option_type);
+
+    template <bool> void _M_insert_character_class_matcher();
+
+    syntax_option_type _M_flags;
+
+    __shared_ptr_access<_NFA> _M_nfa;
+
+    _TraitsT _M_traits;
+
+  };
+
+  template <typename, typename>
+
+  using __enable_if_contiguous_iter =
+
+    __enable_if_t<integral_constant<false>::value,
+
+                  __shared_ptr_access<_NFA>>;
+
+  syntax_option_type __compile_nfa___flags;
+
+  struct Trans_NS___cxx11_regex_traits {
+
+    typedef char char_type;
+
+    typedef int locale_type;
+
+    struct _RegexMask {
+
+      short _M_base;
+
+      char _M_extended;
+
+      _RegexMask() : _M_extended() {}
+
+    } typedef char_class_type;
+
+  };
+
+  template <typename _FwdIter>
+
+  __enable_if_contiguous_iter<_FwdIter, char> __compile_nfa(_FwdIter) {
+
+    auto __cfirst = nullptr;
+
+    using _Cmplr = _Compiler<Trans_NS___cxx11_regex_traits>;
+
+    _Cmplr(__cfirst, __cfirst, 0, __compile_nfa___flags);
+
+  }
+
+  class _RegexTranslatorBase {
+
+public:
+
+    _RegexTranslatorBase(Trans_NS___cxx11_regex_traits);
+
+  };
+
+  class _RegexTranslator : _RegexTranslatorBase {
+
+    typedef _RegexTranslatorBase _Base;
+
+    using _Base::_Base;
+
+  };
+
+  template <typename _TraitsT, int> struct _BracketMatcher {
+
+    _BracketMatcher(bool, _TraitsT __traits) : _M_translator(__traits) {}
+
+    vector<typename _TraitsT::char_class_type> _M_neg_class_set;
+
+    _RegexTranslator _M_translator;
+
+  };
+
+  template <typename _TraitsT>
+
+  _Compiler<_TraitsT>::_Compiler(_IterT __b, _IterT __e,
+
+    const typename _TraitsT::locale_type &__loc,
+
+    syntax_option_type) {
+
+    _M_insert_character_class_matcher<false>();
+
+    _M_insert_character_class_matcher<true>();
+
+  }
+
+  template <typename _TraitsT>
+
+  template <bool __collate>
+
+  void _Compiler<_TraitsT>::_M_insert_character_class_matcher() {
+
+    _BracketMatcher<_TraitsT, __collate> __matcher(0, _M_traits);
+
+    _M_nfa->_M_insert_matcher(__matcher);
+
+  }
+
+  class Trans_NS___cxx11_basic_regex {
+
+public:
+
+    char Trans_NS___cxx11_basic_regex___last;
+
+    Trans_NS___cxx11_basic_regex()
+
+      : _M_automaton(__compile_nfa(Trans_NS___cxx11_basic_regex___last)) {}  /* { dg-error } */
+
+    __shared_ptr_access<_NFA> _M_automaton;
+
+  } regex_sanity_check___f;
+
+}
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 35440b020cc..c7c08213f9a 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -1323,7 +1323,7 @@  thread_across_edge (gcond *dummy_cond,
     /* If E->dest has abnormal outgoing edges, then there's no guarantee
        we can safely redirect any of the edges.  Just punt those cases.  */
     FOR_EACH_EDGE (taken_edge, ei, e->dest->succs)
-      if (taken_edge->flags & EDGE_ABNORMAL)
+      if (taken_edge->flags & EDGE_COMPLEX)
 	{
 	  const_and_copies->pop_to_marker ();
           avail_exprs_stack->pop_to_marker ();