tree-loop-distribution.c (enum partition_kind): New enum.
authorRichard Guenther <rguenther@suse.de>
Fri, 1 Jun 2012 08:55:04 +0000 (08:55 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 1 Jun 2012 08:55:04 +0000 (08:55 +0000)
2012-06-01  Richard Guenther  <rguenther@suse.de>

* tree-loop-distribution.c (enum partition_kind): New enum.
(struct partition_s): Add kind and main_stmt members.
(partition_alloc): Initialize kind to PKIND_NORMAL.
(partition_builtin_p): New function.
(copy_loop_before): Remove failure path and assert instead.
(generate_loops_for_partition): Likewise.
(generate_memset_zero): Fold into ...
(generate_memset_builtin): ... this.
(classify_partition): New function with code from
can_generate_builtin and generate_builtin.
(generate_builtin): Remove.
(can_generate_builtin): Likewise.
(fuse_partitions_with_similar_memory_accesses): Call
partition_builtin_p instead of can_generate_builtin.
(rdg_build_partitions): Do not call
fuse_partitions_with_similar_memory_accesses here...
(ldist_gen): ... but here after classifying all partitions.
Remove failure path of generate_code_for_partition.
(generate_code_for_partition): Generate code according
to partition classification.

From-SVN: r188104

gcc/ChangeLog
gcc/tree-loop-distribution.c

index 1b9b7a7..c7a6565 100644 (file)
@@ -1,3 +1,26 @@
+2012-06-01  Richard Guenther  <rguenther@suse.de>
+
+       * tree-loop-distribution.c (enum partition_kind): New enum.
+       (struct partition_s): Add kind and main_stmt members.
+       (partition_alloc): Initialize kind to PKIND_NORMAL.
+       (partition_builtin_p): New function.
+       (copy_loop_before): Remove failure path and assert instead.
+       (generate_loops_for_partition): Likewise.
+       (generate_memset_zero): Fold into ...
+       (generate_memset_builtin): ... this.
+       (classify_partition): New function with code from
+       can_generate_builtin and generate_builtin.
+       (generate_builtin): Remove.
+       (can_generate_builtin): Likewise.
+       (fuse_partitions_with_similar_memory_accesses): Call
+       partition_builtin_p instead of can_generate_builtin.
+       (rdg_build_partitions): Do not call
+       fuse_partitions_with_similar_memory_accesses here...
+       (ldist_gen): ... but here after classifying all partitions.
+       Remove failure path of generate_code_for_partition.
+       (generate_code_for_partition): Generate code according
+       to partition classification.
+
 2012-06-01  Manuel López-Ibáñez  <manu@gcc.gnu.org>
             Jonathan Wakely  <jwakely.gcc@gmail.com>
 
index 3802467..84a8717 100644 (file)
@@ -52,9 +52,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-scalar-evolution.h"
 #include "tree-pass.h"
 
+enum partition_kind { PKIND_NORMAL, PKIND_MEMSET };
+
 typedef struct partition_s
 {
   bitmap stmts;
+  enum partition_kind kind;
+  /* Main statement a kind != PKIND_NORMAL partition is about.  */
+  gimple main_stmt;
 } *partition_t;
 
 DEF_VEC_P (partition_t);
@@ -67,6 +72,7 @@ partition_alloc (bitmap stmts)
 {
   partition_t partition = XCNEW (struct partition_s);
   partition->stmts = stmts ? stmts : BITMAP_ALLOC (NULL);
+  partition->kind = PKIND_NORMAL;
   return partition;
 }
 
@@ -79,6 +85,13 @@ partition_free (partition_t partition)
   free (partition);
 }
 
+/* Returns true if the partition can be generated as a builtin.  */
+
+static bool
+partition_builtin_p (partition_t partition)
+{
+  return partition->kind != PKIND_NORMAL;
+}
 
 /* If bit I is not set, it means that this node represents an
    operation that has already been performed, and that should not be
@@ -183,16 +196,11 @@ copy_loop_before (struct loop *loop)
   struct loop *res;
   edge preheader = loop_preheader_edge (loop);
 
-  if (!single_exit (loop))
-    return NULL;
-
   initialize_original_copy_tables ();
   res = slpeel_tree_duplicate_loop_to_edge_cfg (loop, preheader);
+  gcc_assert (res != NULL);
   free_original_copy_tables ();
 
-  if (!res)
-    return NULL;
-
   update_phis_for_loop_copy (loop, res);
   rename_variables_in_loop (res);
 
@@ -216,10 +224,9 @@ create_bb_after_loop (struct loop *loop)
    copied when COPY_P is true.  All the statements not flagged in the
    PARTITION bitmap are removed from the loop or from its copy.  The
    statements are indexed in sequence inside a basic block, and the
-   basic blocks of a loop are taken in dom order.  Returns true when
-   the code gen succeeded. */
+   basic blocks of a loop are taken in dom order.  */
 
-static bool
+static void
 generate_loops_for_partition (struct loop *loop, partition_t partition,
                              bool copy_p)
 {
@@ -230,13 +237,11 @@ generate_loops_for_partition (struct loop *loop, partition_t partition,
   if (copy_p)
     {
       loop = copy_loop_before (loop);
+      gcc_assert (loop != NULL);
       create_preheader (loop, CP_SIMPLE_PREHEADERS);
       create_bb_after_loop (loop);
     }
 
-  if (loop == NULL)
-    return false;
-
   /* Remove stmts not in the PARTITION bitmap.  The order in which we
      visit the phi nodes and the statements is exactly as in
      stmts_from_loop.  */
@@ -293,7 +298,6 @@ generate_loops_for_partition (struct loop *loop, partition_t partition,
     }
 
   free (bbs);
-  return true;
 }
 
 /* Build the size argument for a memset call.  */
@@ -313,19 +317,29 @@ build_size_arg_loc (location_t loc, tree nb_iter, tree op,
   return x;
 }
 
-/* Generate a call to memset.  Return true when the operation succeeded.  */
+/* Generate a call to memset for PARTITION in LOOP.  */
 
 static void
-generate_memset_zero (gimple stmt, tree op0, tree nb_iter,
-                     gimple_stmt_iterator bsi)
+generate_memset_builtin (struct loop *loop, partition_t partition)
 {
-  tree addr_base, nb_bytes;
-  bool res = false;
+  gimple_stmt_iterator gsi;
+  gimple stmt, fn_call;
+  tree op0, nb_iter, mem, fn, addr_base, nb_bytes;
   gimple_seq stmt_list = NULL, stmts;
-  gimple fn_call;
-  tree mem, fn;
   struct data_reference *dr = XCNEW (struct data_reference);
-  location_t loc = gimple_location (stmt);
+  location_t loc;
+  bool res;
+
+  stmt = partition->main_stmt;
+  loc = gimple_location (stmt);
+  op0 = gimple_assign_lhs (stmt);
+  if (gimple_bb (stmt) == loop->latch)
+    nb_iter = number_of_latch_executions (loop);
+  else
+    nb_iter = number_of_exit_cond_executions (loop);
+
+  /* The new statements will be placed before LOOP.  */
+  gsi = gsi_last_bb (loop_preheader_edge (loop)->src);
 
   DR_STMT (dr) = stmt;
   DR_REF (dr) = op0;
@@ -353,7 +367,7 @@ generate_memset_zero (gimple stmt, tree op0, tree nb_iter,
   fn = build_fold_addr_expr (builtin_decl_implicit (BUILT_IN_MEMSET));
   fn_call = gimple_build_call (fn, 3, mem, integer_zero_node, nb_bytes);
   gimple_seq_add_stmt (&stmt_list, fn_call);
-  gsi_insert_seq_after (&bsi, stmt_list, GSI_CONTINUE_LINKING);
+  gsi_insert_seq_after (&gsi, stmt_list, GSI_CONTINUE_LINKING);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "generated memset zero\n");
@@ -361,113 +375,56 @@ generate_memset_zero (gimple stmt, tree op0, tree nb_iter,
   free_data_ref (dr);
 }
 
-/* Tries to generate a builtin function for the instructions of LOOP
-   pointed to by the bits set in PARTITION.  Returns true when the
-   operation succeeded.  */
+/* Remove and destroy the loop LOOP.  */
 
-static bool
-generate_builtin (struct loop *loop, partition_t partition, bool copy_p)
+static void
+destroy_loop (struct loop *loop)
 {
-  bool res = false;
-  unsigned i, x = 0;
+  unsigned nbbs = loop->num_nodes;
+  edge exit = single_exit (loop);
+  basic_block src = loop_preheader_edge (loop)->src, dest = exit->dest;
   basic_block *bbs;
-  gimple write = NULL;
-  gimple_stmt_iterator bsi;
-  tree nb_iter = number_of_exit_cond_executions (loop);
-
-  if (!nb_iter || nb_iter == chrec_dont_know)
-    return false;
+  unsigned i;
 
   bbs = get_loop_body_in_dom_order (loop);
 
-  for (i = 0; i < loop->num_nodes; i++)
-    {
-      basic_block bb = bbs[i];
-
-      for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
-       x++;
-
-      for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
-       {
-         gimple stmt = gsi_stmt (bsi);
-
-         if (gimple_code (stmt) == GIMPLE_LABEL
-             || is_gimple_debug (stmt))
-           continue;
-
-         if (!bitmap_bit_p (partition->stmts, x++))
-           continue;
-
-         /* If the stmt has uses outside of the loop fail.
-            ???  If the stmt is generated in another partition that
-            is not created as builtin we can ignore this.  */
-         if (stmt_has_scalar_dependences_outside_loop (loop, stmt))
-           {
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               fprintf (dump_file, "not generating builtin, partition has "
-                        "scalar uses outside of the loop\n");
-             goto end;
-           }
-
-         if (is_gimple_assign (stmt)
-             && !is_gimple_reg (gimple_assign_lhs (stmt)))
-           {
-             /* Don't generate the builtins when there are more than
-                one memory write.  */
-             if (write != NULL)
-               goto end;
-
-             write = stmt;
-             if (bb == loop->latch)
-               nb_iter = number_of_latch_executions (loop);
-           }
-       }
-    }
-
-  if (!stmt_with_adjacent_zero_store_dr_p (write))
-    goto end;
-
-  /* The new statements will be placed before LOOP.  */
-  bsi = gsi_last_bb (loop_preheader_edge (loop)->src);
-  generate_memset_zero (write, gimple_assign_lhs (write), nb_iter, bsi);
-  res = true;
-
-  /* If this is the last partition for which we generate code, we have
-     to destroy the loop.  */
-  if (!copy_p)
-    {
-      unsigned nbbs = loop->num_nodes;
-      edge exit = single_exit (loop);
-      basic_block src = loop_preheader_edge (loop)->src, dest = exit->dest;
-      redirect_edge_pred (exit, src);
-      exit->flags &= ~(EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
-      exit->flags |= EDGE_FALLTHRU;
-      cancel_loop_tree (loop);
-      rescan_loop_exit (exit, false, true);
-
-      for (i = 0; i < nbbs; i++)
-       delete_basic_block (bbs[i]);
-
-      set_immediate_dominator (CDI_DOMINATORS, dest,
-                              recompute_dominator (CDI_DOMINATORS, dest));
-    }
+  redirect_edge_pred (exit, src);
+  exit->flags &= ~(EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
+  exit->flags |= EDGE_FALLTHRU;
+  cancel_loop_tree (loop);
+  rescan_loop_exit (exit, false, true);
 
- end:
+  for (i = 0; i < nbbs; i++)
+    delete_basic_block (bbs[i]);
   free (bbs);
-  return res;
+
+  set_immediate_dominator (CDI_DOMINATORS, dest,
+                          recompute_dominator (CDI_DOMINATORS, dest));
 }
 
-/* Generates code for PARTITION.  For simple loops, this function can
-   generate a built-in.  */
+/* Generates code for PARTITION.  */
 
-static bool
+static void
 generate_code_for_partition (struct loop *loop, partition_t partition,
                             bool copy_p)
 {
-  if (generate_builtin (loop, partition, copy_p))
-    return true;
-
-  return generate_loops_for_partition (loop, partition, copy_p);
+  switch (partition->kind)
+    {
+    case PKIND_MEMSET:
+      generate_memset_builtin (loop, partition);
+      /* If this is the last partition for which we generate code, we have
+        to destroy the loop.  */
+      if (!copy_p)
+       destroy_loop (loop);
+      break;
+
+    case PKIND_NORMAL:
+      generate_loops_for_partition (loop, partition, copy_p);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
 }
 
 
@@ -828,32 +785,71 @@ rdg_build_components (struct graph *rdg, VEC (int, heap) *starting_vertices,
   BITMAP_FREE (saved_components);
 }
 
-/* Returns true when it is possible to generate a builtin pattern for
-   the PARTITION of RDG.  For the moment we detect only the memset
-   zero pattern.  */
+/* Classifies the builtin kind we can generate for PARTITION of RDG and LOOP.
+   For the moment we detect only the memset zero pattern.  */
 
-static bool
-can_generate_builtin (struct graph *rdg, partition_t partition)
+static void
+classify_partition (loop_p loop, struct graph *rdg, partition_t partition)
 {
-  unsigned i;
   bitmap_iterator bi;
-  int nb_reads = 0;
-  int nb_writes = 0;
-  int stores_zero = 0;
+  unsigned i;
+  tree nb_iter;
+
+  partition->kind = PKIND_NORMAL;
+  partition->main_stmt = NULL;
+
+  /* Perform general partition disqualification for builtins.  */
+  nb_iter = number_of_exit_cond_executions (loop);
+  if (!nb_iter || nb_iter == chrec_dont_know)
+    return;
 
   EXECUTE_IF_SET_IN_BITMAP (partition->stmts, 0, i, bi)
-    if (RDG_MEM_READS_STMT (rdg, i))
-      nb_reads++;
-    else if (RDG_MEM_WRITE_STMT (rdg, i))
-      {
-       gimple stmt = RDG_STMT (rdg, i);
-       nb_writes++;
-       if (!gimple_has_volatile_ops (stmt)
-           && stmt_with_adjacent_zero_store_dr_p (stmt))
-         stores_zero++;
-      }
+    {
+      gimple stmt = RDG_STMT (rdg, i);
+
+      if (gimple_has_volatile_ops (stmt))
+       return;
 
-  return stores_zero == 1 && nb_writes == 1 && nb_reads == 0;
+      /* If the stmt has uses outside of the loop fail.
+        ???  If the stmt is generated in another partition that
+        is not created as builtin we can ignore this.  */
+      if (gimple_code (stmt) != GIMPLE_PHI
+         && stmt_has_scalar_dependences_outside_loop (loop, stmt))
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file, "not generating builtin, partition has "
+                    "scalar uses outside of the loop\n");
+         return;
+       }
+    }
+
+  /* Detect memset.  */
+  EXECUTE_IF_SET_IN_BITMAP (partition->stmts, 0, i, bi)
+    {
+      gimple stmt = RDG_STMT (rdg, i);
+
+      if (gimple_code (stmt) == GIMPLE_PHI)
+       continue;
+
+      /* Any scalar stmts are ok.  */
+      if (!gimple_vuse (stmt))
+       continue;
+
+      /* Exactly one store.  */
+      if (gimple_assign_single_p (stmt)
+         && !is_gimple_reg (gimple_assign_lhs (stmt)))
+       {
+         if (partition->main_stmt != NULL)
+           return;
+         partition->main_stmt = stmt;
+       }
+      else
+       return;
+    }
+
+  if (partition->main_stmt != NULL
+      && stmt_with_adjacent_zero_store_dr_p (partition->main_stmt))
+    partition->kind = PKIND_MEMSET;
 }
 
 /* Returns true when PARTITION1 and PARTITION2 have similar memory
@@ -891,10 +887,10 @@ fuse_partitions_with_similar_memory_accesses (struct graph *rdg,
   partition_t partition1, partition2;
 
   FOR_EACH_VEC_ELT (partition_t, *partitions, p1, partition1)
-    if (!can_generate_builtin (rdg, partition1))
+    if (!partition_builtin_p (partition1))
       FOR_EACH_VEC_ELT (partition_t, *partitions, p2, partition2)
        if (p1 != p2
-           && !can_generate_builtin (rdg, partition2)
+           && !partition_builtin_p (partition2)
            && similar_memory_accesses (rdg, partition1, partition2))
          {
            bitmap_ior_into (partition1->stmts, partition2->stmts);
@@ -971,8 +967,6 @@ rdg_build_partitions (struct graph *rdg, VEC (rdgc, heap) *components,
     VEC_safe_push (partition_t, heap, *partitions, partition);
   else
     partition_free (partition);
-
-  fuse_partitions_with_similar_memory_accesses (rdg, partitions);
 }
 
 /* Dump to FILE the PARTITIONS.  */
@@ -1101,11 +1095,15 @@ ldist_gen (struct loop *loop, struct graph *rdg,
                        processed);
   BITMAP_FREE (processed);
 
+  FOR_EACH_VEC_ELT (partition_t, partitions, i, partition)
+    classify_partition (loop, rdg, partition);
+
+  fuse_partitions_with_similar_memory_accesses (rdg, &partitions);
+
   nbp = VEC_length (partition_t, partitions);
   if (nbp == 0
       || (nbp == 1
-         && !can_generate_builtin (rdg,
-                                   VEC_index (partition_t, partitions, 0)))
+         && !partition_builtin_p (VEC_index (partition_t, partitions, 0)))
       || (nbp > 1
          && partition_contains_all_rw (rdg, partitions)))
     goto ldist_done;
@@ -1114,8 +1112,7 @@ ldist_gen (struct loop *loop, struct graph *rdg,
     dump_rdg_partitions (dump_file, partitions);
 
   FOR_EACH_VEC_ELT (partition_t, partitions, i, partition)
-    if (!generate_code_for_partition (loop, partition, i < nbp - 1))
-      goto ldist_done;
+    generate_code_for_partition (loop, partition, i < nbp - 1);
 
   rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
   mark_sym_for_renaming (gimple_vop (cfun));