The following improves how we find the latest VUSE which definition dominates a PHI in get_continuation_for_phi. Rather than the very simplistic variant that requires one of the PHI args providing this we see if walking from any of the PHI args upwards will get us to such VUSE (with the exception to not handle further PHIs).
In reality somehow caching the "active" VUSE at the end of BBs would be quite helpful. Bootstraped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2017-05-04 Richard Biener <rguent...@suse.de> * tree-ssa-alias.c (get_continuation_for_phi): Improve looking for the last VUSE which def dominates the PHI. Directly call maybe_skip_until. (get_continuation_for_phi_1): Remove. * gcc.dg/tree-ssa/ssa-fre-58.c: New testcase. Index: gcc/tree-ssa-alias.c =================================================================== *** gcc/tree-ssa-alias.c (revision 247581) --- gcc/tree-ssa-alias.c (working copy) *************** maybe_skip_until (gimple *phi, tree targ *** 2663,2732 **** return true; } - /* For two PHI arguments ARG0 and ARG1 try to skip non-aliasing code - until we hit the phi argument definition that dominates the other one. - Return that, or NULL_TREE if there is no such definition. */ - - static tree - get_continuation_for_phi_1 (gimple *phi, tree arg0, tree arg1, - ao_ref *ref, unsigned int *cnt, - bitmap *visited, bool abort_on_visited, - void *(*translate)(ao_ref *, tree, void *, bool *), - void *data) - { - gimple *def0 = SSA_NAME_DEF_STMT (arg0); - gimple *def1 = SSA_NAME_DEF_STMT (arg1); - tree common_vuse; - - if (arg0 == arg1) - return arg0; - else if (gimple_nop_p (def0) - || (!gimple_nop_p (def1) - && dominated_by_p (CDI_DOMINATORS, - gimple_bb (def1), gimple_bb (def0)))) - { - if (maybe_skip_until (phi, arg0, ref, arg1, cnt, - visited, abort_on_visited, translate, data)) - return arg0; - } - else if (gimple_nop_p (def1) - || dominated_by_p (CDI_DOMINATORS, - gimple_bb (def0), gimple_bb (def1))) - { - if (maybe_skip_until (phi, arg1, ref, arg0, cnt, - visited, abort_on_visited, translate, data)) - return arg1; - } - /* Special case of a diamond: - MEM_1 = ... - goto (cond) ? L1 : L2 - L1: store1 = ... #MEM_2 = vuse(MEM_1) - goto L3 - L2: store2 = ... #MEM_3 = vuse(MEM_1) - L3: MEM_4 = PHI<MEM_2, MEM_3> - We were called with the PHI at L3, MEM_2 and MEM_3 don't - dominate each other, but still we can easily skip this PHI node - if we recognize that the vuse MEM operand is the same for both, - and that we can skip both statements (they don't clobber us). - This is still linear. Don't use maybe_skip_until, that might - potentially be slow. */ - else if ((common_vuse = gimple_vuse (def0)) - && common_vuse == gimple_vuse (def1)) - { - bool disambiguate_only = true; - *cnt += 2; - if ((!stmt_may_clobber_ref_p_1 (def0, ref) - || (translate - && (*translate) (ref, arg0, data, &disambiguate_only) == NULL)) - && (!stmt_may_clobber_ref_p_1 (def1, ref) - || (translate - && (*translate) (ref, arg1, data, &disambiguate_only) == NULL))) - return common_vuse; - } - - return NULL_TREE; - } - /* Starting from a PHI node for the virtual operand of the memory reference REF find a continuation virtual operand that allows to continue walking --- 2695,2700 ---- *************** get_continuation_for_phi (gimple *phi, a *** 2749,2792 **** /* For two or more arguments try to pairwise skip non-aliasing code until we hit the phi argument definition that dominates the other one. */ ! else if (nargs >= 2) ! { ! tree arg0, arg1; ! unsigned i; ! /* Find a candidate for the virtual operand which definition ! dominates those of all others. */ ! arg0 = PHI_ARG_DEF (phi, 0); ! if (!SSA_NAME_IS_DEFAULT_DEF (arg0)) ! for (i = 1; i < nargs; ++i) { ! arg1 = PHI_ARG_DEF (phi, i); ! if (SSA_NAME_IS_DEFAULT_DEF (arg1)) { ! arg0 = arg1; ! break; } - if (dominated_by_p (CDI_DOMINATORS, - gimple_bb (SSA_NAME_DEF_STMT (arg0)), - gimple_bb (SSA_NAME_DEF_STMT (arg1)))) - arg0 = arg1; } ! /* Then pairwise reduce against the found candidate. */ ! for (i = 0; i < nargs; ++i) ! { ! arg1 = PHI_ARG_DEF (phi, i); ! arg0 = get_continuation_for_phi_1 (phi, arg0, arg1, ref, ! cnt, visited, abort_on_visited, ! translate, data); ! if (!arg0) ! return NULL_TREE; ! } ! ! return arg0; } ! return NULL_TREE; } /* Based on the memory reference REF and its virtual use VUSE call --- 2717,2786 ---- /* For two or more arguments try to pairwise skip non-aliasing code until we hit the phi argument definition that dominates the other one. */ ! basic_block phi_bb = gimple_bb (phi); ! tree arg0, arg1; ! unsigned i; ! /* Find a candidate for the virtual operand which definition ! dominates those of all others. */ ! /* First look if any of the args themselves satisfy this. */ ! for (i = 0; i < nargs; ++i) ! { ! arg0 = PHI_ARG_DEF (phi, i); ! if (SSA_NAME_IS_DEFAULT_DEF (arg0)) ! break; ! basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (arg0)); ! if (def_bb != phi_bb ! && dominated_by_p (CDI_DOMINATORS, phi_bb, def_bb)) ! break; ! arg0 = NULL_TREE; ! } ! /* If not, look if we can reach such candidate by walking defs ! of a PHI arg without crossing other PHIs. */ ! if (! arg0) ! for (i = 0; i < nargs; ++i) ! { ! arg0 = PHI_ARG_DEF (phi, i); ! gimple *def = SSA_NAME_DEF_STMT (arg0); ! /* Backedges can't work. */ ! if (dominated_by_p (CDI_DOMINATORS, ! gimple_bb (def), phi_bb)) ! continue; ! while (! dominated_by_p (CDI_DOMINATORS, ! phi_bb, gimple_bb (def))) { ! arg0 = gimple_vuse (def); ! if (SSA_NAME_IS_DEFAULT_DEF (arg0)) ! break; ! def = SSA_NAME_DEF_STMT (arg0); ! if (gimple_code (def) == GIMPLE_PHI) { ! /* Do not try to look through arbitrarily complicated ! CFGs. For those looking for the first VUSE starting ! from the end of the immediate dominator of phi_bb ! is likely faster. */ ! arg0 = NULL_TREE; ! goto next; } } + break; + next:; + } + if (! arg0) + return NULL_TREE; ! /* Then check against the found candidate. */ ! for (i = 0; i < nargs; ++i) ! { ! arg1 = PHI_ARG_DEF (phi, i); ! if (arg1 == arg0) ! ; ! else if (! maybe_skip_until (phi, arg0, ref, arg1, cnt, visited, ! abort_on_visited, translate, data)) ! return NULL_TREE; } ! return arg0; } /* Based on the memory reference REF and its virtual use VUSE call Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-58.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-58.c (nonexistent) --- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-58.c (working copy) *************** *** 0 **** --- 1,37 ---- + /* { dg-do run } */ + /* { dg-require-effective-target int32plus } */ + /* { dg-options "-O2 -fdump-tree-fre1" } */ + + long long int a = -465274079317386463LL; + int b = 856872806; + int c = -1940894202; + int d = 1718449211; + int e = -392681565; + unsigned long long int f = 13521452247506316486ULL; + int g = -13194608; + + __attribute__((noinline, noclone)) + void foo () + { + if (!a - a) + c = b = 0; + else + d = 3UL * a == 0; + if (g / a) + e = 0 < -a + 500849970701012771LL + (unsigned long) -a; + else + f = 4081116982543369LL & a; + } + + int + main () + { + asm volatile ("" : : : "memory"); + foo (); + if (f != 2818598057803777LL) + __builtin_abort (); + return 0; + } + + /* Should CSE all loads of a. */ + /* { dg-final { scan-tree-dump-times " = a;" 1 "fre1" } } */