Hi! On the following testcase, the peephole2s merge @stack_protect_set_1_<mode> with not the expected *mov{si,di}_internal, but *lea<mode> instead - which looks like a mov, but uses address_no_seg_operand predicate/Ts constraint. The peephole2s check that operand with several smaller predicates, as we do not want to match anything not matched by the constraints used in the *stack_protect_set_{2_<mode>,3} patterns, and I thought those predicates together are subset of general_operand, which is used as the predicate in those patterns, but apparently that is not the case. So this patch also verifies the operand is general_operand.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2020-01-07 Jakub Jelinek <ja...@redhat.com> PR target/93187 * config/i386/i386.md (*stack_protect_set_2_<mode> peephole2, *stack_protect_set_3 peephole2): Also check that the second insns source is general_operand. * g++.dg/opt/pr93187.C: New test. --- gcc/config/i386/i386.md.jj 2020-01-07 18:12:48.043555173 +0100 +++ gcc/config/i386/i386.md 2020-01-07 20:18:27.666952849 +0100 @@ -20084,6 +20084,7 @@ (define_peephole2 (set (match_operand:SI 3 "general_reg_operand") (match_operand:SI 4))] "REGNO (operands[2]) == REGNO (operands[3]) + && general_operand (operands[4], SImode) && (general_reg_operand (operands[4], SImode) || memory_operand (operands[4], SImode) || immediate_operand (operands[4], SImode)) @@ -20128,6 +20129,7 @@ (define_peephole2 (clobber (reg:CC FLAGS_REG))]) (set (match_dup 2) (match_operand:DI 3))] "TARGET_64BIT + && general_operand (operands[3], DImode) && (general_reg_operand (operands[3], DImode) || memory_operand (operands[3], DImode) || x86_64_zext_immediate_operand (operands[3], DImode) --- gcc/testsuite/g++.dg/opt/pr93187.C.jj 2020-01-07 20:20:29.467117172 +0100 +++ gcc/testsuite/g++.dg/opt/pr93187.C 2020-01-07 20:21:40.459047146 +0100 @@ -0,0 +1,77 @@ +// PR target/93187 +// { dg-do compile { target c++11 } } +// { dg-options "-O2" } +// { dg-additional-options "-fstack-protector-strong" { target fstack_protector } } +// { dg-additional-options "-fpie" { target pie } } + +struct A; +struct B; +struct C { int operator () (B, const B &); }; +struct D { typedef int *d; }; +struct E { C g; }; +struct F { F (D::d); friend bool operator==(F &, const int &); }; +template <typename T, typename> struct H { + typedef D *I; + E l; + I foo (); + T t; + F bar (I, const T &); + F baz (const T &); +}; +template <typename T, typename U> +F +H<T, U>::bar (I n, const T &o) +{ + while (n) + if (l.g (t, o)) + n = 0; + return 0; +} +template <typename T, typename U> +F +H<T, U>::baz (const T &n) +{ + D *r = foo (); + F p = bar (r, n); + return p == 0 ? 0 : p; +} +template <typename, typename U> struct J { + H<B, U> h; + B &q; + void baz () { h.baz (q); } +}; +enum K { L }; +template <typename, K = L> struct M; +template <int> struct G { + using N = J<int, A>; + N *operator->(); +}; +template <typename, K T> struct M : public G<T> { + using N = J<int, A>; + N *foo () { return n; } + N *n; + int o; +}; +template <int N> +inline typename G<N>::N * +G<N>::operator-> () +{ + N *n = static_cast<M<J<int, A>> *>(this)->foo (); + return n; +} +struct B { bool qux (); }; +struct O { + struct P { M<int> p; }; + static thread_local P o; + int baz () const; +}; +thread_local O::P O::o; +B be; +int +O::baz () const +{ + do + o.p->baz (); + while (be.qux ()); + __builtin_unreachable (); +} Jakub