The following fixes a latent issue in loop distribution catched by the fake edge placement adjustment.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied. Richard. 2016-05-17 Richard Biener <rguent...@suse.de> PR tree-optimization/71132 * tree-loop-distribution.c (create_rdg_cd_edges): Pass in loop. Only add control dependences for blocks in the loop. (build_rdg): Adjust. (generate_code_for_partition): Return whether loop should be destroyed and delay that. (distribute_loop): Likewise. (pass_loop_distribution::execute): Record loops to be destroyed and perform delayed destroying of loops. * gcc.dg/torture/pr71132.c: New testcase. Index: gcc/tree-loop-distribution.c =================================================================== *** gcc/tree-loop-distribution.c (revision 236309) --- gcc/tree-loop-distribution.c (working copy) *************** create_rdg_flow_edges (struct graph *rdg *** 312,318 **** /* Creates the edges of the reduced dependence graph RDG. */ static void ! create_rdg_cd_edges (struct graph *rdg, control_dependences *cd) { int i; --- 315,321 ---- /* Creates the edges of the reduced dependence graph RDG. */ static void ! create_rdg_cd_edges (struct graph *rdg, control_dependences *cd, loop_p loop) { int i; *************** create_rdg_cd_edges (struct graph *rdg, *** 324,329 **** --- 327,333 ---- edge_iterator ei; edge e; FOR_EACH_EDGE (e, ei, gimple_bb (stmt)->preds) + if (flow_bb_inside_loop_p (loop, e->src)) create_edge_for_control_dependence (rdg, e->src, i, cd); } else *************** build_rdg (vec<loop_p> loop_nest, contro *** 455,461 **** create_rdg_flow_edges (rdg); if (cd) ! create_rdg_cd_edges (rdg, cd); datarefs.release (); --- 459,465 ---- create_rdg_flow_edges (rdg); if (cd) ! create_rdg_cd_edges (rdg, cd, loop_nest[0]); datarefs.release (); *************** destroy_loop (struct loop *loop) *** 917,925 **** recompute_dominator (CDI_DOMINATORS, dest)); } ! /* Generates code for PARTITION. */ ! static void generate_code_for_partition (struct loop *loop, partition *partition, bool copy_p) { --- 921,929 ---- recompute_dominator (CDI_DOMINATORS, dest)); } ! /* Generates code for PARTITION. Return whether LOOP needs to be destroyed. */ ! static bool generate_code_for_partition (struct loop *loop, partition *partition, bool copy_p) { *************** generate_code_for_partition (struct loop *** 930,936 **** gcc_assert (!partition_reduction_p (partition) || !copy_p); generate_loops_for_partition (loop, partition, copy_p); ! return; case PKIND_MEMSET: generate_memset_builtin (loop, partition); --- 934,940 ---- gcc_assert (!partition_reduction_p (partition) || !copy_p); generate_loops_for_partition (loop, partition, copy_p); ! return false; case PKIND_MEMSET: generate_memset_builtin (loop, partition); *************** generate_code_for_partition (struct loop *** 947,953 **** /* Common tail for partitions we turn into a call. If this was the last partition for which we generate code, we have to destroy the loop. */ if (!copy_p) ! destroy_loop (loop); } --- 951,958 ---- /* Common tail for partitions we turn into a call. If this was the last partition for which we generate code, we have to destroy the loop. */ if (!copy_p) ! return true; ! return false; } *************** pgcmp (const void *v1_, const void *v2_) *** 1397,1407 **** /* Distributes the code from LOOP in such a way that producer statements are placed before consumer statements. Tries to separate only the statements from STMTS into separate loops. ! Returns the number of distributed loops. */ static int distribute_loop (struct loop *loop, vec<gimple *> stmts, ! control_dependences *cd, int *nb_calls) { struct graph *rdg; partition *partition; --- 1412,1423 ---- /* Distributes the code from LOOP in such a way that producer statements are placed before consumer statements. Tries to separate only the statements from STMTS into separate loops. ! Returns the number of distributed loops. Set *DESTROY_P to whether ! LOOP needs to be destroyed. */ static int distribute_loop (struct loop *loop, vec<gimple *> stmts, ! control_dependences *cd, int *nb_calls, bool *destroy_p) { struct graph *rdg; partition *partition; *************** distribute_loop (struct loop *loop, vec< *** 1644,1654 **** if (dump_file && (dump_flags & TDF_DETAILS)) dump_rdg_partitions (dump_file, partitions); FOR_EACH_VEC_ELT (partitions, i, partition) { if (partition_builtin_p (partition)) (*nb_calls)++; ! generate_code_for_partition (loop, partition, i < nbp - 1); } ldist_done: --- 1660,1671 ---- if (dump_file && (dump_flags & TDF_DETAILS)) dump_rdg_partitions (dump_file, partitions); + *destroy_p = false; FOR_EACH_VEC_ELT (partitions, i, partition) { if (partition_builtin_p (partition)) (*nb_calls)++; ! *destroy_p |= generate_code_for_partition (loop, partition, i < nbp - 1); } ldist_done: *************** pass_loop_distribution::execute (functio *** 1702,1707 **** --- 1719,1725 ---- bool changed = false; basic_block bb; control_dependences *cd = NULL; + auto_vec<loop_p> loops_to_be_destroyed; FOR_ALL_BB_FN (bb, fun) { *************** out: *** 1787,1794 **** cd = new control_dependences (create_edge_list ()); free_dominance_info (CDI_POST_DOMINATORS); } nb_generated_loops = distribute_loop (loop, work_list, cd, ! &nb_generated_calls); } if (nb_generated_loops + nb_generated_calls > 0) --- 1805,1816 ---- cd = new control_dependences (create_edge_list ()); free_dominance_info (CDI_POST_DOMINATORS); } + bool destroy_p; nb_generated_loops = distribute_loop (loop, work_list, cd, ! &nb_generated_calls, ! &destroy_p); ! if (destroy_p) ! loops_to_be_destroyed.safe_push (loop); } if (nb_generated_loops + nb_generated_calls > 0) *************** out: *** 1806,1811 **** --- 1828,1839 ---- if (cd) delete cd; + /* Destroy loop bodies that could not be reused. Do this late as we + otherwise can end up refering to stale data in control dependences. */ + unsigned i; + FOR_EACH_VEC_ELT (loops_to_be_destroyed, i, loop) + destroy_loop (loop); + if (changed) { /* Cached scalar evolutions now may refer to wrong or non-existing Index: gcc/testsuite/gcc.dg/torture/pr71132.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr71132.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr71132.c (working copy) *************** *** 0 **** --- 1,24 ---- + /* { dg-do compile } */ + + typedef unsigned size_t; + struct { + unsigned char buf[sizeof(long)]; + } a; + size_t b; + int main() + { + size_t c, i; + unsigned char *d; + for (; c < sizeof(long);) + { + d = a.buf; + b = 0; + for (; b < i; b++) + *d++ = '\0'; + for (; c < b; c++) + *d++ = 'a'; + c = 0; + for (; i < sizeof(long); i++) + ; + } + }