This fixes a bogus warning by performing MIN_EXPR detection on memory which avoids bogus threading and isolating of a path with a bogus memcpy.
I've gone back in time and at some point we had no MAX_STORES_TO_SINK param but handled just the last_and_only_stmt case of sinking two stores. The param got added when the code was extended to handle an arbitrary number of stores and thus did dependence checking which eventually was thought to be too expensive to do without vectorization or if-conversion enabled. So this restores this ability even when MAX_STORES_TO_SINK is zero and also generalizes it a bit to not only handle last_and_only_stmt but the case where each BB has a single store without any following loads. In that case we can elide the dependence checking and perform the desired transform (for the testcase one BB has another stmt so last_and_only_stmt wouldn't have worked). I've had to disable cselim on three testcases, one being a unit test for PRE and two being unit tests (?!) for my very special friend path splitting. Bootstrapped and tested on x86_64-unknown-linux-gnu, ok? Thanks, Richard. 2018-03-16 Richard Biener <rguent...@suse.de> PR tree-optimization/84859 * tree-ssa-phiopt.c (single_trailing_store_in_bb): New function. (cond_if_else_store_replacement): Perform sinking operation on single-store BBs regardless of MAX_STORES_TO_SINK setting. Generalize what a BB with a single eligible store is. * gcc.dg/tree-ssa/pr84859.c: New testcase. * gcc.dg/tree-ssa/pr35286.c: Disable cselim. * gcc.dg/tree-ssa/split-path-6.c: Likewise. * gcc.dg/tree-ssa/split-path-7.c: Likewise. Index: gcc/tree-ssa-phiopt.c =================================================================== --- gcc/tree-ssa-phiopt.c (revision 258584) +++ gcc/tree-ssa-phiopt.c (working copy) @@ -2035,6 +2035,36 @@ cond_if_else_store_replacement_1 (basic_ return true; } +/* Return the single store in BB with VDEF or NULL if there are + other stores in the BB or loads following the store. */ + +static gimple * +single_trailing_store_in_bb (basic_block bb, tree vdef) +{ + if (SSA_NAME_IS_DEFAULT_DEF (vdef)) + return NULL; + gimple *store = SSA_NAME_DEF_STMT (vdef); + if (gimple_bb (store) != bb + || gimple_code (store) == GIMPLE_PHI) + return NULL; + + /* Verify there is no other store in this BB. */ + if (!SSA_NAME_IS_DEFAULT_DEF (gimple_vuse (store)) + && gimple_bb (SSA_NAME_DEF_STMT (gimple_vuse (store))) == bb + && gimple_code (SSA_NAME_DEF_STMT (gimple_vuse (store))) != GIMPLE_PHI) + return NULL; + + /* Verify there is no load or store after the store. */ + use_operand_p use_p; + imm_use_iterator imm_iter; + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, gimple_vdef (store)) + if (USE_STMT (use_p) != store + && gimple_bb (USE_STMT (use_p)) == bb) + return NULL; + + return store; +} + /* Conditional store replacement. We already know that the recognized pattern looks like so: @@ -2061,8 +2091,6 @@ static bool cond_if_else_store_replacement (basic_block then_bb, basic_block else_bb, basic_block join_bb) { - gimple *then_assign = last_and_only_stmt (then_bb); - gimple *else_assign = last_and_only_stmt (else_bb); vec<data_reference_p> then_datarefs, else_datarefs; vec<ddr_p> then_ddrs, else_ddrs; gimple *then_store, *else_store; @@ -2073,13 +2101,32 @@ cond_if_else_store_replacement (basic_bl tree then_lhs, else_lhs; basic_block blocks[3]; - if (MAX_STORES_TO_SINK == 0) + /* Handle the case with single store in THEN_BB and ELSE_BB. That is + cheap enough to always handle as it allows us to elide dependence + checking. */ + gphi *vphi = NULL; + for (gphi_iterator si = gsi_start_phis (join_bb); !gsi_end_p (si); + gsi_next (&si)) + if (virtual_operand_p (gimple_phi_result (si.phi ()))) + { + vphi = si.phi (); + break; + } + if (!vphi) return false; + tree then_vdef = PHI_ARG_DEF_FROM_EDGE (vphi, single_succ_edge (then_bb)); + tree else_vdef = PHI_ARG_DEF_FROM_EDGE (vphi, single_succ_edge (else_bb)); + gimple *then_assign = single_trailing_store_in_bb (then_bb, then_vdef); + if (then_assign) + { + gimple *else_assign = single_trailing_store_in_bb (else_bb, else_vdef); + if (else_assign) + return cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb, + then_assign, else_assign); + } - /* Handle the case with single statement in THEN_BB and ELSE_BB. */ - if (then_assign && else_assign) - return cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb, - then_assign, else_assign); + if (MAX_STORES_TO_SINK == 0) + return false; /* Find data references. */ then_datarefs.create (1); Index: gcc/testsuite/gcc.dg/tree-ssa/pr35286.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/pr35286.c (revision 258584) +++ gcc/testsuite/gcc.dg/tree-ssa/pr35286.c (working copy) @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fno-code-hoisting -fdump-tree-pre-stats" } */ +/* { dg-options "-O2 -fno-code-hoisting -fno-tree-cselim -fdump-tree-pre-stats" } */ int g2; struct A { int a; int b; Index: gcc/testsuite/gcc.dg/tree-ssa/split-path-6.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/split-path-6.c (revision 258584) +++ gcc/testsuite/gcc.dg/tree-ssa/split-path-6.c (working copy) @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fsplit-paths -fdump-tree-split-paths-details -w" } */ +/* { dg-options "-O2 -fsplit-paths -fno-tree-cselim -fdump-tree-split-paths-details -w" } */ struct __sFILE { Index: gcc/testsuite/gcc.dg/tree-ssa/split-path-7.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/split-path-7.c (revision 258584) +++ gcc/testsuite/gcc.dg/tree-ssa/split-path-7.c (working copy) @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fsplit-paths -fdump-tree-split-paths-details -w" } */ +/* { dg-options "-O2 -fsplit-paths -fno-tree-cselim -fdump-tree-split-paths-details -w" } */ struct _reent Index: gcc/testsuite/gcc.dg/tree-ssa/pr84859.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/pr84859.c (nonexistent) +++ gcc/testsuite/gcc.dg/tree-ssa/pr84859.c (working copy) @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Warray-bounds -fdump-tree-phiopt1" } */ + +void +h (const void *p, unsigned n) +{ + unsigned char a[8]; + if (n > sizeof a) + return; + + for (; n > 0; n -= *a) + { + if (n > 255) + *a = 255; + else + *a = n; + + __builtin_memcpy (a, p, *a); /* { dg-bogus "bounds" } */ + } +} + +/* { dg-final { scan-tree-dump "MIN_EXPR" "phiopt1" } } */