On December 29, 2021 11:11:18 AM GMT+01:00, Jakub Jelinek <ja...@redhat.com> wrote: >Hi! > >make_forwarders_with_degenerate_phis causes a -fcompare-debug failure on the >following testcase. >The problem is that on: > # iftmp.4_8 = PHI <&D.2582(6), &D.2583(4), &D.2582(7), &D.2583(5)> >the exact DECL_UIDs are different between -g and -g0 (which is ok, with -g >the decls can have larger gaps in between the uids), which means >iterative_hash_expr is different and because there are 2 pairs of edges >with matching phi arguments, the function processes them in different >orders. >The following patch fixes it by using the iterative_hash_expr order >only to determine which arguments are the same, then replaces the hashes >with the minimum dest_idx in the set of matching arguments and qsorts >again (which makes it stable for -fcompare-debug) and only splits edges etc. >on that stable order. >As a small optimization, if no arguments are equal, it doesn't do the >second qsort and continues, and if all arguments of the PHI are >constants or SSA_NAMEs (I think that is a pretty common case for many >PHIs), then it doesn't do the second qsort either, because in that case >the hash values will be stable, only computed from the constant values or >SSA_NAME_VERSIONs. > >Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Ok. Thanks, Richard. >2021-12-28 Jakub Jelinek <ja...@redhat.com> > > PR debug/103742 > * tree-ssa-dce.c (make_forwarders_with_degenerate_phis): If any phi > argument is not CONSTANT_CLASS_P or SSA_NAME and any arguments are > equal, change second from hash value to lowest dest_idx from the > edges which have equal argument and resort to ensure -fcompare-debug > stability. > > * g++.dg/opt/pr103742.C: New test. > >--- gcc/tree-ssa-dce.c.jj 2021-11-29 14:24:14.120633762 +0100 >+++ gcc/tree-ssa-dce.c 2021-12-28 17:30:19.983056815 +0100 >@@ -1671,6 +1671,7 @@ make_forwarders_with_degenerate_phis (fu > continue; > gphi *phi = gsi.phi (); > auto_vec<std::pair<edge, hashval_t>, 8> args; >+ bool need_resort = false; > for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i) > { > edge e = gimple_phi_arg_edge (phi, i); >@@ -1682,12 +1683,42 @@ make_forwarders_with_degenerate_phis (fu > if (loops_state_satisfies_p (LOOP_CLOSED_SSA) > && loop_exit_edge_p (e->src->loop_father, e)) > continue; >- args.safe_push (std::make_pair (e, iterative_hash_expr >- (gimple_phi_arg_def (phi, i), 0))); >+ >+ tree arg = gimple_phi_arg_def (phi, i); >+ if (!CONSTANT_CLASS_P (arg) && TREE_CODE (arg) != SSA_NAME) >+ need_resort = true; >+ args.safe_push (std::make_pair (e, iterative_hash_expr (arg, 0))); > } > if (args.length () < 2) > continue; > args.qsort (sort_phi_args); >+ /* The above sorting can be different between -g and -g0, as e.g. decls >+ can have different uids (-g could have bigger gaps in between them). >+ So, only use that to determine which args are equal, then change >+ second from hash value to smallest dest_idx of the edges which have >+ equal argument and sort again. If all the phi arguments are >+ constants or SSA_NAME, there is no need for the second sort, the hash >+ values are stable in that case. */ >+ hashval_t hash = args[0].second; >+ args[0].second = args[0].first->dest_idx; >+ bool any_equal = false; >+ for (unsigned i = 1; i < args.length (); ++i) >+ if (hash == args[i].second >+ && operand_equal_p (PHI_ARG_DEF_FROM_EDGE (phi, args[i - 1].first), >+ PHI_ARG_DEF_FROM_EDGE (phi, args[i].first))) >+ { >+ args[i].second = args[i - 1].second; >+ any_equal = true; >+ } >+ else >+ { >+ hash = args[i].second; >+ args[i].second = args[i].first->dest_idx; >+ } >+ if (!any_equal) >+ continue; >+ if (need_resort) >+ args.qsort (sort_phi_args); > > /* From the candidates vector now verify true candidates for > forwarders and create them. */ >@@ -1697,8 +1728,7 @@ make_forwarders_with_degenerate_phis (fu > { > unsigned i; > for (i = start + 1; i < args.length (); ++i) >- if (!operand_equal_p (PHI_ARG_DEF_FROM_EDGE (phi, >args[start].first), >- PHI_ARG_DEF_FROM_EDGE (phi, args[i].first))) >+ if (args[start].second != args[i].second) > break; > /* args[start]..args[i-1] are equal. */ > if (start != i - 1) >--- gcc/testsuite/g++.dg/opt/pr103742.C.jj 2021-12-28 17:30:35.788837099 >+0100 >+++ gcc/testsuite/g++.dg/opt/pr103742.C 2021-12-28 17:31:22.719184723 >+0100 >@@ -0,0 +1,36 @@ >+// PR debug/103742 >+// { dg-do compile { target c++17 } } >+// { dg-options "-O2 -fnon-call-exceptions --param=early-inlining-insns=82 >-fcompare-debug" } >+ >+template <typename T> T max(T a, T b) { return a >= b ? a : b; } >+template <typename T> T abs(T); >+template <int T, int U> struct A { >+ long a; >+ A(A &x) { a = x.a; } >+ A(long); >+ A foo(A) { >+ if (abs(a) && a == a) >+ a = a ? U : T; >+ else >+ a += a; >+ return *this; >+ } >+ bool operator>=(A) { return a; } >+}; >+struct B {}; >+struct C { >+ A<2147483647, 0> c; >+}; >+struct D { >+ A<2147483647, 0> d; >+ C e[]; >+}; >+struct E : D{} * f; >+A<2147483647, 0> bar() { >+ A<2147483647, 0> g = g.foo(f->d); >+ return max(g, (A<2147483647, 0>)1); >+} >+E *h; >+void baz() { >+ h->e[0].c = bar(); >+} > > Jakub >