OSDN Git Service

* gcc-interface/trans.c (Call_to_gnu): Robustify test for function case
[pf3gnuchains/gcc-fork.git] / gcc / tree-loop-distribution.c
index b603209..06dd14d 100644 (file)
@@ -1,5 +1,5 @@
 /* Loop distribution.
-   Copyright (C) 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Georges-Andre Silber <Georges-Andre.Silber@ensmp.fr>
    and Sebastian Pop <sebastian.pop@amd.com>.
@@ -45,20 +45,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
-#include "basic-block.h"
 #include "tree-flow.h"
-#include "tree-dump.h"
-#include "timevar.h"
 #include "cfgloop.h"
 #include "tree-chrec.h"
 #include "tree-data-ref.h"
 #include "tree-scalar-evolution.h"
 #include "tree-pass.h"
-#include "lambda.h"
-#include "langhooks.h"
-#include "tree-vectorizer.h"
 
 /* If bit I is not set, it means that this node represents an
    operation that has already been performed, and that should not be
@@ -71,6 +63,51 @@ static bitmap remaining_stmts;
    predecessor a node that writes to memory.  */
 static bitmap upstream_mem_writes;
 
+/* Returns true when DEF is an SSA_NAME defined in LOOP and used after
+   the LOOP.  */
+
+static bool
+ssa_name_has_uses_outside_loop_p (tree def, loop_p loop)
+{
+  imm_use_iterator imm_iter;
+  use_operand_p use_p;
+
+  FOR_EACH_IMM_USE_FAST (use_p, imm_iter, def)
+    if (loop != loop_containing_stmt (USE_STMT (use_p)))
+      return true;
+
+  return false;
+}
+
+/* Returns true when STMT defines a scalar variable used after the
+   loop.  */
+
+static bool
+stmt_has_scalar_dependences_outside_loop (gimple stmt)
+{
+  tree name;
+
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_CALL:
+    case GIMPLE_ASSIGN:
+      name = gimple_get_lhs (stmt);
+      break;
+
+    case GIMPLE_PHI:
+      name = gimple_phi_result (stmt);
+      break;
+
+    default:
+      return false;
+    }
+
+  return (name
+         && TREE_CODE (name) == SSA_NAME
+         && ssa_name_has_uses_outside_loop_p (name,
+                                              loop_containing_stmt (stmt)));
+}
+
 /* Update the PHI nodes of NEW_LOOP.  NEW_LOOP is a duplicate of
    ORIG_LOOP.  */
 
@@ -189,6 +226,25 @@ generate_loops_for_partition (struct loop *loop, bitmap partition, bool copy_p)
      stmts_from_loop.  */
   bbs = get_loop_body_in_dom_order (loop);
 
+  if (MAY_HAVE_DEBUG_STMTS)
+    for (x = 0, 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))
+         if (!bitmap_bit_p (partition, x++))
+           reset_debug_uses (gsi_stmt (bsi));
+
+       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)
+               && !bitmap_bit_p (partition, x++))
+             reset_debug_uses (stmt);
+         }
+      }
+
   for (x = 0, i = 0; i < loop->num_nodes; i++)
     {
       basic_block bb = bbs[i];
@@ -207,7 +263,8 @@ generate_loops_for_partition (struct loop *loop, bitmap partition, bool copy_p)
       for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi);)
        {
          gimple stmt = gsi_stmt (bsi);
-         if (gimple_code (gsi_stmt (bsi)) != GIMPLE_LABEL
+         if (gimple_code (stmt) != GIMPLE_LABEL
+             && !is_gimple_debug (stmt)
              && !bitmap_bit_p (partition, x++))
            {
              unlink_stmt_vdef (stmt);
@@ -230,9 +287,10 @@ build_size_arg_loc (location_t loc, tree nb_iter, tree op,
                    gimple_seq *stmt_list)
 {
   gimple_seq stmts;
-  tree x = size_binop_loc (loc, MULT_EXPR,
-                          fold_convert_loc (loc, sizetype, nb_iter),
-                          TYPE_SIZE_UNIT (TREE_TYPE (op)));
+  tree x = fold_build2_loc (loc, MULT_EXPR, size_type_node,
+                           fold_convert_loc (loc, size_type_node, nb_iter),
+                           fold_convert_loc (loc, size_type_node,
+                                             TYPE_SIZE_UNIT (TREE_TYPE (op))));
   x = force_gimple_operand (x, &stmts, true, NULL);
   gimple_seq_add_seq (stmt_list, stmts);
 
@@ -255,7 +313,7 @@ generate_memset_zero (gimple stmt, tree op0, tree nb_iter,
 
   DR_STMT (dr) = stmt;
   DR_REF (dr) = op0;
-  res = dr_analyze_innermost (dr);
+  res = dr_analyze_innermost (dr, loop_containing_stmt (stmt));
   gcc_assert (res && stride_of_unit_type_p (DR_STEP (dr), TREE_TYPE (op0)));
 
   nb_bytes = build_size_arg_loc (loc, nb_iter, op0, &stmt_list);
@@ -263,9 +321,7 @@ generate_memset_zero (gimple stmt, tree op0, tree nb_iter,
   addr_base = fold_convert_loc (loc, sizetype, addr_base);
 
   /* Test for a negative stride, iterating over every element.  */
-  if (integer_zerop (size_binop (PLUS_EXPR,
-                                TYPE_SIZE_UNIT (TREE_TYPE (op0)),
-                                fold_convert (sizetype, DR_STEP (dr)))))
+  if (tree_int_cst_sgn (DR_STEP (dr)) == -1)
     {
       addr_base = size_binop_loc (loc, MINUS_EXPR, addr_base,
                                  fold_convert_loc (loc, sizetype, nb_bytes));
@@ -273,13 +329,12 @@ generate_memset_zero (gimple stmt, tree op0, tree nb_iter,
                                  TYPE_SIZE_UNIT (TREE_TYPE (op0)));
     }
 
-  addr_base = fold_build2_loc (loc, POINTER_PLUS_EXPR,
-                              TREE_TYPE (DR_BASE_ADDRESS (dr)),
-                              DR_BASE_ADDRESS (dr), addr_base);
+  addr_base = fold_build_pointer_plus_loc (loc,
+                                          DR_BASE_ADDRESS (dr), addr_base);
   mem = force_gimple_operand (addr_base, &stmts, true, NULL);
   gimple_seq_add_seq (&stmt_list, stmts);
 
-  fn = build_fold_addr_expr (implicit_built_in_decls [BUILT_IN_MEMSET]);
+  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);
@@ -320,8 +375,18 @@ generate_builtin (struct loop *loop, bitmap partition, bool copy_p)
        {
          gimple stmt = gsi_stmt (bsi);
 
-         if (bitmap_bit_p (partition, x++)
-             && is_gimple_assign (stmt)
+         if (gimple_code (stmt) == GIMPLE_LABEL
+             || is_gimple_debug (stmt))
+           continue;
+
+         if (!bitmap_bit_p (partition, x++))
+           continue;
+
+         /* If the stmt has uses outside of the loop fail.  */
+         if (stmt_has_scalar_dependences_outside_loop (stmt))
+           goto end;
+
+         if (is_gimple_assign (stmt)
              && !is_gimple_reg (gimple_assign_lhs (stmt)))
            {
              /* Don't generate the builtins when there are more than
@@ -653,6 +718,8 @@ rdg_flag_loop_exits (struct graph *rdg, bitmap loops, bitmap partition,
 
       BITMAP_FREE (new_loops);
     }
+
+  VEC_free (gimple, heap, conds);
 }
 
 /* Returns a bitmap in which all the statements needed for computing
@@ -693,6 +760,8 @@ free_rdg_components (VEC (rdgc, heap) *components)
       VEC_free (int, heap, x->vertices);
       free (x);
     }
+
+  VEC_free (rdgc, heap, components);
 }
 
 /* Build the COMPONENTS vector with the strongly connected components
@@ -808,6 +877,60 @@ fuse_partitions_with_similar_memory_accesses (struct graph *rdg,
          }
 }
 
+/* Returns true when STMT will be code generated in a partition of RDG
+   different than PART and that will not be code generated as a
+   builtin.  */
+
+static bool
+stmt_generated_in_another_partition (struct graph *rdg, gimple stmt, int part,
+                                    VEC (bitmap, heap) *partitions)
+{
+  int p;
+  bitmap pp;
+  unsigned i;
+  bitmap_iterator bi;
+
+  FOR_EACH_VEC_ELT (bitmap, partitions, p, pp)
+    if (p != part
+       && !can_generate_builtin (rdg, pp))
+      EXECUTE_IF_SET_IN_BITMAP (pp, 0, i, bi)
+       if (stmt == RDG_STMT (rdg, i))
+         return true;
+
+  return false;
+}
+
+/* For each partition in PARTITIONS that will be code generated using
+   a builtin, add its scalar computations used after the loop to
+   PARTITION.  */
+
+static void
+add_scalar_computations_to_partition (struct graph *rdg,
+                                     VEC (bitmap, heap) *partitions,
+                                     bitmap partition)
+{
+  int p;
+  bitmap pp;
+  unsigned i;
+  bitmap_iterator bi;
+  bitmap l = BITMAP_ALLOC (NULL);
+  bitmap pr = BITMAP_ALLOC (NULL);
+  bool f = false;
+
+  FOR_EACH_VEC_ELT (bitmap, partitions, p, pp)
+    if (can_generate_builtin (rdg, pp))
+      EXECUTE_IF_SET_IN_BITMAP (pp, 0, i, bi)
+       if (stmt_has_scalar_dependences_outside_loop (RDG_STMT (rdg, i))
+           && !stmt_generated_in_another_partition (rdg, RDG_STMT (rdg, i), p,
+                                                    partitions))
+         rdg_flag_vertex_and_dependent (rdg, i, partition, l, pr, &f);
+
+  rdg_flag_loop_exits (rdg, l, partition, pr, &f);
+
+  BITMAP_FREE (pr);
+  BITMAP_FREE (l);
+}
+
 /* Aggregate several components into a useful partition that is
    registered in the PARTITIONS vector.  Partitions will be
    distributed in different loops.  */
@@ -871,6 +994,8 @@ rdg_build_partitions (struct graph *rdg, VEC (rdgc, heap) *components,
       free_rdg_components (comps);
     }
 
+  add_scalar_computations_to_partition (rdg, *partitions, partition);
+
   /* If there is something left in the last partition, save it.  */
   if (bitmap_count_bits (partition) > 0)
     VEC_safe_push (bitmap, heap, *partitions, partition);
@@ -1018,7 +1143,8 @@ ldist_gen (struct loop *loop, struct graph *rdg,
       goto ldist_done;
 
   rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
-  update_ssa (TODO_update_ssa_only_virtuals | TODO_update_ssa);
+  mark_sym_for_renaming (gimple_vop (cfun));
+  update_ssa (TODO_update_ssa_only_virtuals);
 
  ldist_done:
 
@@ -1048,6 +1174,9 @@ distribute_loop (struct loop *loop, VEC (gimple, heap) *stmts)
   gimple s;
   unsigned i;
   VEC (int, heap) *vertices;
+  VEC (ddr_p, heap) *dependence_relations;
+  VEC (data_reference_p, heap) *datarefs;
+  VEC (loop_p, heap) *loop_nest;
 
   if (loop->num_nodes > 2)
     {
@@ -1059,7 +1188,10 @@ distribute_loop (struct loop *loop, VEC (gimple, heap) *stmts)
       return res;
     }
 
-  rdg = build_rdg (loop);
+  datarefs = VEC_alloc (data_reference_p, heap, 10);
+  dependence_relations = VEC_alloc (ddr_p, heap, 100);
+  loop_nest = VEC_alloc (loop_p, heap, 3);
+  rdg = build_rdg (loop, &loop_nest, &dependence_relations, &datarefs);
 
   if (!rdg)
     {
@@ -1068,6 +1200,9 @@ distribute_loop (struct loop *loop, VEC (gimple, heap) *stmts)
                 "FIXME: Loop %d not distributed: failed to build the RDG.\n",
                 loop->num);
 
+      free_dependence_relations (dependence_relations);
+      free_data_refs (datarefs);
+      VEC_free (loop_p, heap, loop_nest);
       return res;
     }
 
@@ -1093,7 +1228,9 @@ distribute_loop (struct loop *loop, VEC (gimple, heap) *stmts)
   res = ldist_gen (loop, rdg, vertices);
   VEC_free (int, heap, vertices);
   free_rdg (rdg);
-
+  free_dependence_relations (dependence_relations);
+  free_data_refs (datarefs);
+  VEC_free (loop_p, heap, loop_nest);
   return res;
 }
 
@@ -1109,6 +1246,7 @@ tree_loop_distribution (void)
   FOR_EACH_LOOP (li, loop, 0)
     {
       VEC (gimple, heap) *work_list = NULL;
+      int num = loop->num;
 
       /* If the loop doesn't have a single exit we will fail anyway,
         so do that early.  */
@@ -1150,9 +1288,9 @@ tree_loop_distribution (void)
        {
          if (nb_generated_loops > 1)
            fprintf (dump_file, "Loop %d distributed: split to %d loops.\n",
-                    loop->num, nb_generated_loops);
+                    num, nb_generated_loops);
          else
-           fprintf (dump_file, "Loop %d is the same.\n", loop->num);
+           fprintf (dump_file, "Loop %d is the same.\n", num);
        }
 
       verify_loop_structure ();
@@ -1185,6 +1323,7 @@ struct gimple_opt_pass pass_loop_distribution =
   0,                           /* properties_provided */
   0,                           /* properties_destroyed */
   0,                           /* todo_flags_start */
-  TODO_dump_func                /* todo_flags_finish */
+  TODO_ggc_collect
+  | TODO_verify_ssa             /* todo_flags_finish */
  }
 };