OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ddg.c
index b28bdfd..a515882 100644 (file)
--- a/gcc/ddg.c
+++ b/gcc/ddg.c
@@ -1,5 +1,5 @@
 /* DDG - Data Dependence Graph implementation.
-   Copyright (C) 2004, 2005, 2006, 2007
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Ayal Zaks and Mustafa Hagog <zaks,mustafa@il.ibm.com>
 
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "hard-reg-set.h"
@@ -44,6 +44,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "bitmap.h"
 #include "ddg.h"
 
+#ifdef INSN_SCHEDULING
+
 /* A flag indicating that a ddg edge belongs to an SCC or not.  */
 enum edge_flag {NOT_IN_SCC = 0, IN_SCC};
 
@@ -51,7 +53,8 @@ enum edge_flag {NOT_IN_SCC = 0, IN_SCC};
 static void add_backarc_to_ddg (ddg_ptr, ddg_edge_ptr);
 static void add_backarc_to_scc (ddg_scc_ptr, ddg_edge_ptr);
 static void add_scc_to_ddg (ddg_all_sccs_ptr, ddg_scc_ptr);
-static void create_ddg_dependence (ddg_ptr, ddg_node_ptr, ddg_node_ptr, dep_t);
+static void create_ddg_dep_from_intra_loop_link (ddg_ptr, ddg_node_ptr,
+                                                 ddg_node_ptr, dep_t);
 static void create_ddg_dep_no_link (ddg_ptr, ddg_node_ptr, ddg_node_ptr,
                                    dep_type, dep_data_type, int);
 static ddg_edge_ptr create_ddg_edge (ddg_node_ptr, ddg_node_ptr, dep_type,
@@ -142,53 +145,106 @@ mem_access_insn_p (rtx insn)
   return rtx_mem_access_p (PATTERN (insn));
 }
 
+/* Return true if DEF_INSN contains address being auto-inc or auto-dec
+   which is used in USE_INSN.  Otherwise return false.  The result is
+   being used to decide whether to remove the edge between def_insn and
+   use_insn when -fmodulo-sched-allow-regmoves is set.  This function
+   doesn't need to consider the specific address register; no reg_moves
+   will be allowed for any life range defined by def_insn and used
+   by use_insn, if use_insn uses an address register auto-inc'ed by
+   def_insn.  */
+bool
+autoinc_var_is_used_p (rtx def_insn, rtx use_insn)
+{
+  rtx note;
+
+  for (note = REG_NOTES (def_insn); note; note = XEXP (note, 1))
+    if (REG_NOTE_KIND (note) == REG_INC
+       && reg_referenced_p (XEXP (note, 0), PATTERN (use_insn)))
+      return true;
+
+  return false;
+}
+
+/* Return true if one of the definitions in INSN has MODE_CC.  Otherwise
+   return false.  */
+static bool
+def_has_ccmode_p (rtx insn)
+{
+  df_ref *def;
+
+  for (def = DF_INSN_DEFS (insn); *def; def++)
+    {
+      enum machine_mode mode = GET_MODE (DF_REF_REG (*def));
+
+      if (GET_MODE_CLASS (mode) == MODE_CC)
+       return true;
+    }
+
+  return false;
+}
+
 /* Computes the dependence parameters (latency, distance etc.), creates
    a ddg_edge and adds it to the given DDG.  */
 static void
-create_ddg_dependence (ddg_ptr g, ddg_node_ptr src_node,
-                      ddg_node_ptr dest_node, dep_t link)
+create_ddg_dep_from_intra_loop_link (ddg_ptr g, ddg_node_ptr src_node,
+                                     ddg_node_ptr dest_node, dep_t link)
 {
   ddg_edge_ptr e;
   int latency, distance = 0;
-  int interloop = (src_node->cuid >= dest_node->cuid);
   dep_type t = TRUE_DEP;
   dep_data_type dt = (mem_access_insn_p (src_node->insn)
                      && mem_access_insn_p (dest_node->insn) ? MEM_DEP
                                                             : REG_DEP);
-
-  /* For now we don't have an exact calculation of the distance,
-     so assume 1 conservatively.  */
-  if (interloop)
-     distance = 1;
-
+  gcc_assert (src_node->cuid < dest_node->cuid);
   gcc_assert (link);
 
   /* Note: REG_DEP_ANTI applies to MEM ANTI_DEP as well!!  */
-  if (DEP_KIND (link) == REG_DEP_ANTI)
+  if (DEP_TYPE (link) == REG_DEP_ANTI)
     t = ANTI_DEP;
-  else if (DEP_KIND (link) == REG_DEP_OUTPUT)
+  else if (DEP_TYPE (link) == REG_DEP_OUTPUT)
     t = OUTPUT_DEP;
-  latency = dep_cost (link);
 
-  e = create_ddg_edge (src_node, dest_node, t, dt, latency, distance);
-
-  if (interloop)
+  gcc_assert (!DEBUG_INSN_P (dest_node->insn) || t == ANTI_DEP);
+  gcc_assert (!DEBUG_INSN_P (src_node->insn) || t == ANTI_DEP);
+
+  /* We currently choose not to create certain anti-deps edges and
+     compensate for that by generating reg-moves based on the life-range
+     analysis.  The anti-deps that will be deleted are the ones which
+     have true-deps edges in the opposite direction (in other words
+     the kernel has only one def of the relevant register).
+     If the address that is being auto-inc or auto-dec in DEST_NODE
+     is used in SRC_NODE then do not remove the edge to make sure
+     reg-moves will not be created for this address.  
+     TODO: support the removal of all anti-deps edges, i.e. including those
+     whose register has multiple defs in the loop.  */
+  if (flag_modulo_sched_allow_regmoves 
+      && (t == ANTI_DEP && dt == REG_DEP)
+      && !def_has_ccmode_p (dest_node->insn)
+      && !autoinc_var_is_used_p (dest_node->insn, src_node->insn))
     {
-      /* Some interloop dependencies are relaxed:
-        1. Every insn is output dependent on itself; ignore such deps.
-        2. Every true/flow dependence is an anti dependence in the
-        opposite direction with distance 1; such register deps
-        will be removed by renaming if broken --- ignore them.  */
-      if (!(t == OUTPUT_DEP && src_node == dest_node)
-         && !(t == ANTI_DEP && dt == REG_DEP))
-       add_backarc_to_ddg (g, e);
-      else
-       free (e);
+      rtx set;
+
+      set = single_set (dest_node->insn);
+      /* TODO: Handle registers that REG_P is not true for them, i.e.
+         subregs and special registers.  */
+      if (set && REG_P (SET_DEST (set)))
+        {
+          int regno = REGNO (SET_DEST (set));
+          df_ref first_def;
+          struct df_rd_bb_info *bb_info = DF_RD_BB_INFO (g->bb);
+
+          first_def = df_bb_regno_first_def_find (g->bb, regno);
+          gcc_assert (first_def);
+
+          if (bitmap_bit_p (&bb_info->gen, DF_REF_ID (first_def)))
+            return;
+        }
     }
-  else if (t == ANTI_DEP && dt == REG_DEP)
-    free (e);  /* We can fix broken anti register deps using reg-moves.  */
-  else
-    add_edge_to_ddg (g, e);
+
+   latency = dep_cost (link);
+   e = create_ddg_edge (src_node, dest_node, t, dt, latency, distance);
+   add_edge_to_ddg (g, e);
 }
 
 /* The same as the above function, but it doesn't require a link parameter.  */
@@ -201,6 +257,9 @@ create_ddg_dep_no_link (ddg_ptr g, ddg_node_ptr from, ddg_node_ptr to,
   enum reg_note dep_kind;
   struct _dep _dep, *dep = &_dep;
 
+  gcc_assert (!DEBUG_INSN_P (to->insn) || d_t == ANTI_DEP);
+  gcc_assert (!DEBUG_INSN_P (from->insn) || d_t == ANTI_DEP);
+
   if (d_t == ANTI_DEP)
     dep_kind = REG_DEP_ANTI;
   else if (d_t == OUTPUT_DEP)
@@ -231,7 +290,7 @@ create_ddg_dep_no_link (ddg_ptr g, ddg_node_ptr from, ddg_node_ptr to,
    and anti-dependences from its uses in the current iteration to the
    first definition in the next iteration.  */
 static void
-add_cross_iteration_register_deps (ddg_ptr g, struct df_ref *last_def)
+add_cross_iteration_register_deps (ddg_ptr g, df_ref last_def)
 {
   int regno = DF_REF_REGNO (last_def);
   struct df_link *r_use;
@@ -242,11 +301,17 @@ add_cross_iteration_register_deps (ddg_ptr g, struct df_ref *last_def)
 #ifdef ENABLE_CHECKING
   struct df_rd_bb_info *bb_info = DF_RD_BB_INFO (g->bb);
 #endif
-  struct df_ref *first_def = df_bb_regno_first_def_find (g->bb, regno);
+  df_ref first_def = df_bb_regno_first_def_find (g->bb, regno);
 
   gcc_assert (last_def_node);
   gcc_assert (first_def);
 
+#ifdef ENABLE_CHECKING
+  if (DF_REF_ID (last_def) != DF_REF_ID (first_def))
+    gcc_assert (!bitmap_bit_p (&bb_info->gen,
+                              DF_REF_ID (first_def)));
+#endif
+
   /* Create inter-loop true dependences and anti dependences.  */
   for (r_use = DF_REF_CHAIN (last_def); r_use != NULL; r_use = r_use->next)
     {
@@ -264,10 +329,11 @@ add_cross_iteration_register_deps (ddg_ptr g, struct df_ref *last_def)
          /* Add true deps from last_def to it's uses in the next
             iteration.  Any such upwards exposed use appears before
             the last_def def.  */
-         create_ddg_dep_no_link (g, last_def_node, use_node, TRUE_DEP,
+         create_ddg_dep_no_link (g, last_def_node, use_node,
+                                 DEBUG_INSN_P (use_insn) ? ANTI_DEP : TRUE_DEP,
                                  REG_DEP, 1);
        }
-      else
+      else if (!DEBUG_INSN_P (use_insn))
        {
          /* Add anti deps from last_def's uses in the current iteration
             to the first def in the next iteration.  We do not add ANTI
@@ -276,18 +342,23 @@ add_cross_iteration_register_deps (ddg_ptr g, struct df_ref *last_def)
             deps when broken.  If the first_def reaches the USE then
             there is such a dep.  */
          ddg_node_ptr first_def_node = get_node_of_insn (g,
-                                                         first_def->insn);
+                                                         DF_REF_INSN (first_def));
 
          gcc_assert (first_def_node);
 
-          if (last_def->id != first_def->id)
-            {
-#ifdef ENABLE_CHECKING
-              gcc_assert (!bitmap_bit_p (bb_info->gen, first_def->id));
-#endif
-              create_ddg_dep_no_link (g, use_node, first_def_node, ANTI_DEP,
-                                      REG_DEP, 1);
-            }
+         /* Always create the edge if the use node is a branch in
+            order to prevent the creation of reg-moves.  
+            If the address that is being auto-inc or auto-dec in LAST_DEF
+            is used in USE_INSN then do not remove the edge to make sure
+            reg-moves will not be created for that address.  */
+          if (DF_REF_ID (last_def) != DF_REF_ID (first_def)
+              || !flag_modulo_sched_allow_regmoves
+             || JUMP_P (use_node->insn)
+              || autoinc_var_is_used_p (DF_REF_INSN (last_def), use_insn)
+             || def_has_ccmode_p (DF_REF_INSN (last_def)))
+            create_ddg_dep_no_link (g, use_node, first_def_node, ANTI_DEP,
+                                    REG_DEP, 1);
+
        }
     }
   /* Create an inter-loop output dependence between LAST_DEF (which is the
@@ -301,10 +372,10 @@ add_cross_iteration_register_deps (ddg_ptr g, struct df_ref *last_def)
     {
       ddg_node_ptr dest_node;
 
-      if (last_def->id == first_def->id)
+      if (DF_REF_ID (last_def) == DF_REF_ID (first_def))
        return;
 
-      dest_node = get_node_of_insn (g, first_def->insn);
+      dest_node = get_node_of_insn (g, DF_REF_INSN (first_def));
       gcc_assert (dest_node);
       create_ddg_dep_no_link (g, last_def_node, dest_node,
                              OUTPUT_DEP, REG_DEP, 1);
@@ -321,26 +392,98 @@ build_inter_loop_deps (ddg_ptr g)
   rd_bb_info = DF_RD_BB_INFO (g->bb);
 
   /* Find inter-loop register output, true and anti deps.  */
-  EXECUTE_IF_SET_IN_BITMAP (rd_bb_info->gen, 0, rd_num, bi)
+  EXECUTE_IF_SET_IN_BITMAP (&rd_bb_info->gen, 0, rd_num, bi)
   {
-    struct df_ref *rd = DF_DEFS_GET (rd_num);
+    df_ref rd = DF_DEFS_GET (rd_num);
 
     add_cross_iteration_register_deps (g, rd);
   }
 }
 
 
+static int
+walk_mems_2 (rtx *x, rtx mem)
+{
+  if (MEM_P (*x))
+    {
+      if (may_alias_p (*x, mem))
+        return 1;
+
+      return -1;
+    }
+  return 0;
+}
+
+static int
+walk_mems_1 (rtx *x, rtx *pat)
+{
+  if (MEM_P (*x))
+    {
+      /* Visit all MEMs in *PAT and check indepedence.  */
+      if (for_each_rtx (pat, (rtx_function) walk_mems_2, *x))
+        /* Indicate that dependence was determined and stop traversal.  */
+        return 1;
+
+      return -1;
+    }
+  return 0;
+}
+
+/* Return 1 if two specified instructions have mem expr with conflict alias sets*/
+static int
+insns_may_alias_p (rtx insn1, rtx insn2)
+{
+  /* For each pair of MEMs in INSN1 and INSN2 check their independence.  */
+  return  for_each_rtx (&PATTERN (insn1), (rtx_function) walk_mems_1,
+                        &PATTERN (insn2));
+}
+
+/* Given two nodes, analyze their RTL insns and add intra-loop mem deps
+   to ddg G.  */
+static void
+add_intra_loop_mem_dep (ddg_ptr g, ddg_node_ptr from, ddg_node_ptr to)
+{
+
+  if ((from->cuid == to->cuid)
+      || !insns_may_alias_p (from->insn, to->insn))
+    /* Do not create edge if memory references have disjoint alias sets
+       or 'to' and 'from' are the same instruction.  */
+    return;
+
+  if (mem_write_insn_p (from->insn))
+    {
+      if (mem_read_insn_p (to->insn))
+       create_ddg_dep_no_link (g, from, to,
+                               DEBUG_INSN_P (to->insn)
+                               ? ANTI_DEP : TRUE_DEP, MEM_DEP, 0);
+      else
+       create_ddg_dep_no_link (g, from, to,
+                               DEBUG_INSN_P (to->insn)
+                               ? ANTI_DEP : OUTPUT_DEP, MEM_DEP, 0);
+    }
+  else if (!mem_read_insn_p (to->insn))
+    create_ddg_dep_no_link (g, from, to, ANTI_DEP, MEM_DEP, 0);
+}
+
 /* Given two nodes, analyze their RTL insns and add inter-loop mem deps
    to ddg G.  */
 static void
 add_inter_loop_mem_dep (ddg_ptr g, ddg_node_ptr from, ddg_node_ptr to)
 {
+  if (!insns_may_alias_p (from->insn, to->insn))
+    /* Do not create edge if memory references have disjoint alias sets.  */
+    return;
+
   if (mem_write_insn_p (from->insn))
     {
       if (mem_read_insn_p (to->insn))
-       create_ddg_dep_no_link (g, from, to, TRUE_DEP, MEM_DEP, 1);
+       create_ddg_dep_no_link (g, from, to,
+                               DEBUG_INSN_P (to->insn)
+                               ? ANTI_DEP : TRUE_DEP, MEM_DEP, 1);
       else if (from->cuid != to->cuid)
-       create_ddg_dep_no_link (g, from, to, OUTPUT_DEP, MEM_DEP, 1);
+       create_ddg_dep_no_link (g, from, to,
+                               DEBUG_INSN_P (to->insn)
+                               ? ANTI_DEP : OUTPUT_DEP, MEM_DEP, 1);
     }
   else
     {
@@ -348,8 +491,11 @@ add_inter_loop_mem_dep (ddg_ptr g, ddg_node_ptr from, ddg_node_ptr to)
        return;
       else if (from->cuid != to->cuid)
        {
-         create_ddg_dep_no_link (g, from, to, ANTI_DEP, MEM_DEP, 1);
-         create_ddg_dep_no_link (g, to, from, TRUE_DEP, MEM_DEP, 1);
+         create_ddg_dep_no_link (g, from, to, ANTI_DEP, MEM_DEP, 1);
+         if (DEBUG_INSN_P (from->insn) || DEBUG_INSN_P (to->insn))
+           create_ddg_dep_no_link (g, to, from, ANTI_DEP, MEM_DEP, 1);
+         else
+           create_ddg_dep_no_link (g, to, from, TRUE_DEP, MEM_DEP, 1);
        }
     }
 
@@ -362,13 +508,12 @@ build_intra_loop_deps (ddg_ptr g)
 {
   int i;
   /* Hold the dependency analysis state during dependency calculations.  */
-  struct deps tmp_deps;
+  struct deps_desc tmp_deps;
   rtx head, tail;
-  dep_link_t link;
 
   /* Build the dependence information, using the sched_analyze function.  */
   init_deps_global ();
-  init_deps (&tmp_deps);
+  init_deps (&tmp_deps, false);
 
   /* Do the intra-block data dependence analysis for the given block.  */
   get_ebb_head_tail (g->bb, g->bb, &head, &tail);
@@ -379,20 +524,20 @@ build_intra_loop_deps (ddg_ptr g)
   for (i = 0; i < g->num_nodes; i++)
     {
       ddg_node_ptr dest_node = &g->nodes[i];
+      sd_iterator_def sd_it;
+      dep_t dep;
 
       if (! INSN_P (dest_node->insn))
        continue;
 
-      FOR_EACH_DEP_LINK (link, INSN_BACK_DEPS (dest_node->insn))
+      FOR_EACH_DEP (dest_node->insn, SD_LIST_BACK, sd_it, dep)
        {
-         dep_t dep = DEP_LINK_DEP (link);
          ddg_node_ptr src_node = get_node_of_insn (g, DEP_PRO (dep));
 
          if (!src_node)
            continue;
 
-         add_forw_dep (link);
-         create_ddg_dependence (g, src_node, dest_node, dep);
+         create_ddg_dep_from_intra_loop_link (g, src_node, dest_node, dep);
        }
 
       /* If this insn modifies memory, add an edge to all insns that access
@@ -404,11 +549,25 @@ build_intra_loop_deps (ddg_ptr g)
          for (j = 0; j <= i; j++)
            {
              ddg_node_ptr j_node = &g->nodes[j];
+             if (DEBUG_INSN_P (j_node->insn))
+               continue;
              if (mem_access_insn_p (j_node->insn))
-               /* Don't bother calculating inter-loop dep if an intra-loop dep
-                  already exists.  */
+               {
+                 /* Don't bother calculating inter-loop dep if an intra-loop dep
+                    already exists.  */
                  if (! TEST_BIT (dest_node->successors, j))
                    add_inter_loop_mem_dep (g, dest_node, j_node);
+                 /* If -fmodulo-sched-allow-regmoves
+                    is set certain anti-dep edges are not created.
+                    It might be that these anti-dep edges are on the
+                    path from one memory instruction to another such that
+                    removing these edges could cause a violation of the
+                    memory dependencies.  Thus we add intra edges between
+                    every two memory instructions in this case.  */
+                 if (flag_modulo_sched_allow_regmoves
+                     && !TEST_BIT (dest_node->predecessors, j))
+                   add_intra_loop_mem_dep (g, j_node, dest_node);
+               }
             }
         }
     }
@@ -416,6 +575,9 @@ build_intra_loop_deps (ddg_ptr g)
   /* Free the INSN_LISTs.  */
   finish_deps_global ();
   free_deps (&tmp_deps);
+
+  /* Free dependencies.  */
+  sched_free_deps (head, tail, false);
 }
 
 
@@ -442,15 +604,20 @@ create_ddg (basic_block bb, int closing_branch_deps)
       if (! INSN_P (insn) || GET_CODE (PATTERN (insn)) == USE)
        continue;
 
-      if (mem_read_insn_p (insn))
-       g->num_loads++;
-      if (mem_write_insn_p (insn))
-       g->num_stores++;
+      if (DEBUG_INSN_P (insn))
+       g->num_debug++;
+      else
+       {
+         if (mem_read_insn_p (insn))
+           g->num_loads++;
+         if (mem_write_insn_p (insn))
+           g->num_stores++;
+       }
       num_nodes++;
     }
 
   /* There is nothing to do for this BB.  */
-  if (num_nodes <= 1)
+  if ((num_nodes - g->num_debug) <= 1)
     {
       free (g);
       return NULL;
@@ -493,10 +660,10 @@ create_ddg (basic_block bb, int closing_branch_deps)
       g->nodes[i++].insn = insn;
       first_note = NULL_RTX;
     }
-  
+
   /* We must have found a branch in DDG.  */
   gcc_assert (g->closing_branch);
-  
+
 
   /* Build the data dependency graph.  */
   build_intra_loop_deps (g);
@@ -564,6 +731,7 @@ print_ddg (FILE *file, ddg_ptr g)
     {
       ddg_edge_ptr e;
 
+      fprintf (file, "Node num: %d\n", g->nodes[i].cuid);
       print_rtl_single (file, g->nodes[i].insn);
       fprintf (file, "OUT ARCS: ");
       for (e = g->nodes[i].out; e; e = e->next_out)
@@ -838,9 +1006,9 @@ static int
 compare_sccs (const void *s1, const void *s2)
 {
   const int rec_l1 = (*(const ddg_scc_ptr *)s1)->recurrence_length;
-  const int rec_l2 = (*(const ddg_scc_ptr *)s2)->recurrence_length; 
+  const int rec_l2 = (*(const ddg_scc_ptr *)s2)->recurrence_length;
   return ((rec_l2 > rec_l1) - (rec_l2 < rec_l1));
-         
+
 }
 
 /* Order the backarcs in descending recMII order using compare_sccs.  */
@@ -935,6 +1103,7 @@ free_ddg_all_sccs (ddg_all_sccs_ptr all_sccs)
   for (i = 0; i < all_sccs->num_sccs; i++)
     free_scc (all_sccs->sccs[i]);
 
+  free (all_sccs->sccs);
   free (all_sccs);
 }
 
@@ -1093,3 +1262,5 @@ longest_simple_path (struct ddg * g, int src, int dest, sbitmap nodes)
   sbitmap_free (tmp);
   return result;
 }
+
+#endif /* INSN_SCHEDULING */