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++)
+       ;
+     }
+ }

Reply via email to