OSDN Git Service

PR target/39942
[pf3gnuchains/gcc-fork.git] / gcc / df-core.c
index 8e6a4e1..c42b20f 100644 (file)
@@ -1,6 +1,6 @@
 /* Allocation for dataflow support routines.
    Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-   2008 Free Software Foundation, Inc.
+   2008, 2009 Free Software Foundation, Inc.
    Originally contributed by Michael P. Hayes 
              (m.hayes@elec.canterbury.ac.nz, mhayes@redhat.com)
    Major rewrite contributed by Danny Berlin (dberlin@dberlin.org)
@@ -170,11 +170,6 @@ There are four ways of doing the incremental scanning:
    d) If the pass modifies all of the insns, as does register
       allocation, it is simply better to rescan the entire function.
 
-   e) If the pass uses either non-standard or ancient techniques to
-      modify insns, automatic detection of the insns that need to be
-      rescanned may be impractical.  Cse and regrename fall into this
-      category.
-
 2) Deferred rescanning - Calls to df_insn_rescan, df_notes_rescan, and
    df_insn_delete do not immediately change the insn but instead make
    a note that the insn needs to be rescanned.  The next call to
@@ -182,27 +177,25 @@ There are four ways of doing the incremental scanning:
    cause all of the pending rescans to be processed.
 
    This is the technique of choice if either 1a, 1b, or 1c are issues
-   in the pass.  In the case of 1a or 1b, a call to df_remove_problem
-   (df_chain) should be made before the next call to df_analyze or
-   df_process_deferred_rescans.
+   in the pass.  In the case of 1a or 1b, a call to df_finish_pass
+   (either manually or via TODO_df_finish) should be made before the
+   next call to df_analyze or df_process_deferred_rescans.
+
+   This mode is also used by a few passes that still rely on note_uses,
+   note_stores and for_each_rtx instead of using the DF data.  This
+   can be said to fall under case 1c.
 
    To enable this mode, call df_set_flags (DF_DEFER_INSN_RESCAN).
    (This mode can be cleared by calling df_clear_flags
    (DF_DEFER_INSN_RESCAN) but this does not cause the deferred insns to
    be rescanned.
 
-   3) Total rescanning - In this mode the rescanning is disabled.
-   However, the df information associated with deleted insn is delete
-   at the time the insn is deleted.  At the end of the pass, a call
-   must be made to df_insn_rescan_all.  This method is used by the
-   register allocator since it generally changes each insn multiple
-   times (once for each ref) and does not need to make use of the
-   updated scanning information.
-
-   It is also currently used by two older passes (cse, and regrename)
-   which change insns in hard to track ways.  It is hoped that this
-   will be fixed soon since this it is expensive to rescan all of the
-   insns when only a small number of them have really changed.
+3) Total rescanning - In this mode the rescanning is disabled.
+   Only when insns are deleted is the df information associated with
+   it also deleted.  At the end of the pass, a call must be made to
+   df_insn_rescan_all.  This method is used by the register allocator
+   since it generally changes each insn multiple times (once for each ref)
+   and does not need to make use of the updated scanning information.
 
 4) Do it yourself - In this mechanism, the pass updates the insns
    itself using the low level df primitives.  Currently no pass does
@@ -474,10 +467,10 @@ df_add_problem (struct df_problem *problem)
 /* Set the MASK flags in the DFLOW problem.  The old flags are
    returned.  If a flag is not allowed to be changed this will fail if
    checking is enabled.  */
-enum df_changeable_flags
-df_set_flags (enum df_changeable_flags changeable_flags)
+int
+df_set_flags (int changeable_flags)
 {
-  enum df_changeable_flags old_flags = df->changeable_flags;
+  int old_flags = df->changeable_flags;
   df->changeable_flags |= changeable_flags;
   return old_flags;
 }
@@ -486,10 +479,10 @@ df_set_flags (enum df_changeable_flags changeable_flags)
 /* Clear the MASK flags in the DFLOW problem.  The old flags are
    returned.  If a flag is not allowed to be changed this will fail if
    checking is enabled.  */
-enum df_changeable_flags
-df_clear_flags (enum df_changeable_flags changeable_flags)
+int
+df_clear_flags (int changeable_flags)
 {
-  enum df_changeable_flags old_flags = df->changeable_flags;
+  int old_flags = df->changeable_flags;
   df->changeable_flags &= ~changeable_flags;
   return old_flags;
 }
@@ -622,7 +615,7 @@ df_remove_problem (struct dataflow *dflow)
        int j;
        for (j = i + 1; j < df->num_problems_defined; j++)
          df->problems_in_order[j-1] = df->problems_in_order[j];
-       df->problems_in_order[j] = NULL;
+       df->problems_in_order[j-1] = NULL;
        df->num_problems_defined--;
        break;
       }
@@ -766,7 +759,7 @@ struct rtl_opt_pass pass_df_initialize_opt =
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
@@ -793,7 +786,7 @@ struct rtl_opt_pass pass_df_initialize_no_opt =
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
@@ -842,7 +835,7 @@ struct rtl_opt_pass pass_df_finish =
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
@@ -943,47 +936,6 @@ df_worklist_propagate_backward (struct dataflow *dataflow,
 
 
 /* This will free "pending". */
-static void 
-df_worklist_dataflow_overeager (struct dataflow *dataflow,
-                               bitmap pending,
-                                sbitmap considered,
-                                int *blocks_in_postorder,
-                               unsigned *bbindex_to_postorder)
-{
-  enum df_flow_dir dir = dataflow->problem->dir;
-  int count = 0;
-
-  while (!bitmap_empty_p (pending))
-    {
-      unsigned bb_index;
-      int index;
-      count++;
-
-      index = bitmap_first_set_bit (pending);
-      bitmap_clear_bit (pending, index);
-
-      bb_index = blocks_in_postorder[index];
-
-      if (dir == DF_FORWARD)
-       df_worklist_propagate_forward (dataflow, bb_index,
-                                      bbindex_to_postorder,
-                                      pending, considered);
-      else 
-       df_worklist_propagate_backward (dataflow, bb_index,
-                                       bbindex_to_postorder,
-                                       pending, considered);
-    }
-
-  BITMAP_FREE (pending);
-
-  /* Dump statistics. */
-  if (dump_file)
-    fprintf (dump_file, "df_worklist_dataflow_overeager:"
-            "n_basic_blocks %d n_edges %d"
-            " count %d (%5.2g)\n",
-            n_basic_blocks, n_edges,
-            count, count / (float)n_basic_blocks);
-}
 
 static void 
 df_worklist_dataflow_doublequeue (struct dataflow *dataflow,
@@ -1042,23 +994,10 @@ df_worklist_dataflow_doublequeue (struct dataflow *dataflow,
 
 /* Worklist-based dataflow solver. It uses sbitmap as a worklist,
    with "n"-th bit representing the n-th block in the reverse-postorder order. 
-   This is so-called over-eager algorithm where it propagates
-   changes on demand. This algorithm may visit blocks more than
-   iterative method if there are deeply nested loops. 
-   Worklist algorithm works better than iterative algorithm
-   for CFGs with no nested loops.
-   In practice, the measurement shows worklist algorithm beats 
-   iterative algorithm by some margin overall.  
-   Note that this is slightly different from the traditional textbook worklist solver,
-   in that the worklist is effectively sorted by the reverse postorder.
-   For CFGs with no nested loops, this is optimal. 
-   
-   The overeager algorithm while works well for typical inputs,
-   it could degenerate into excessive iterations given CFGs with high loop nests
-   and unstructured loops. To cap the excessive iteration on such case,
-   we switch to double-queueing when the original algorithm seems to 
-   get into such.
-   */
+   The solver is a double-queue algorithm similar to the "double stack" solver
+   from Cooper, Harvey and Kennedy, "Iterative data-flow analysis, Revisited".
+   The only significant difference is that the worklist in this implementation
+   is always sorted in RPO of the CFG visiting direction.  */
 
 void 
 df_worklist_dataflow (struct dataflow *dataflow,
@@ -1103,26 +1042,10 @@ df_worklist_dataflow (struct dataflow *dataflow,
   if (dataflow->problem->init_fun)
     dataflow->problem->init_fun (blocks_to_consider);
 
-  /* Solve it. Determine the solving algorithm
-     based on a simple heuristic. */
-  if (n_edges > PARAM_VALUE (PARAM_DF_DOUBLE_QUEUE_THRESHOLD_FACTOR)
-      * n_basic_blocks)
-    {
-      /* High average connectivity, meaning dense graph
-         with more likely deep nested loops
-        or unstructured loops. */
-      df_worklist_dataflow_doublequeue (dataflow, pending, considered,
-                                       blocks_in_postorder,
-                                       bbindex_to_postorder);
-    }
-  else 
-    {
-      /* Most inputs fall into this case
-        with relatively flat or structured CFG. */
-      df_worklist_dataflow_overeager (dataflow, pending, considered,
-                                     blocks_in_postorder,
-                                     bbindex_to_postorder);
-    }
+  /* Solve it.  */
+  df_worklist_dataflow_doublequeue (dataflow, pending, considered,
+                                   blocks_in_postorder,
+                                   bbindex_to_postorder);
 
   sbitmap_free (considered);
   free (bbindex_to_postorder);
@@ -1725,11 +1648,11 @@ df_set_clean_cfg (void)
 
 /* Return first def of REGNO within BB.  */
 
-struct df_ref *
+df_ref 
 df_bb_regno_first_def_find (basic_block bb, unsigned int regno)
 {
   rtx insn;
-  struct df_ref **def_rec;
+  df_ref *def_rec;
   unsigned int uid;
 
   FOR_BB_INSNS (bb, insn)
@@ -1740,7 +1663,7 @@ df_bb_regno_first_def_find (basic_block bb, unsigned int regno)
       uid = INSN_UID (insn);
       for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
        {
-         struct df_ref *def = *def_rec;
+         df_ref def = *def_rec;
          if (DF_REF_REGNO (def) == regno)
            return def;
        }
@@ -1751,11 +1674,11 @@ df_bb_regno_first_def_find (basic_block bb, unsigned int regno)
 
 /* Return last def of REGNO within BB.  */
 
-struct df_ref *
+df_ref 
 df_bb_regno_last_def_find (basic_block bb, unsigned int regno)
 {
   rtx insn;
-  struct df_ref **def_rec;
+  df_ref *def_rec;
   unsigned int uid;
 
   FOR_BB_INSNS_REVERSE (bb, insn)
@@ -1766,7 +1689,7 @@ df_bb_regno_last_def_find (basic_block bb, unsigned int regno)
       uid = INSN_UID (insn);
       for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
        {
-         struct df_ref *def = *def_rec;
+         df_ref def = *def_rec;
          if (DF_REF_REGNO (def) == regno)
            return def;
        }
@@ -1778,11 +1701,11 @@ df_bb_regno_last_def_find (basic_block bb, unsigned int regno)
 /* Finds the reference corresponding to the definition of REG in INSN.
    DF is the dataflow object.  */
 
-struct df_ref *
+df_ref 
 df_find_def (rtx insn, rtx reg)
 {
   unsigned int uid;
-  struct df_ref **def_rec;
+  df_ref *def_rec;
 
   if (GET_CODE (reg) == SUBREG)
     reg = SUBREG_REG (reg);
@@ -1791,7 +1714,7 @@ df_find_def (rtx insn, rtx reg)
   uid = INSN_UID (insn);
   for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
     {
-      struct df_ref *def = *def_rec;
+      df_ref def = *def_rec;
       if (rtx_equal_p (DF_REF_REAL_REG (def), reg))
        return def;
     }
@@ -1812,11 +1735,11 @@ df_reg_defined (rtx insn, rtx reg)
 /* Finds the reference corresponding to the use of REG in INSN.
    DF is the dataflow object.  */
   
-struct df_ref *
+df_ref 
 df_find_use (rtx insn, rtx reg)
 {
   unsigned int uid;
-  struct df_ref **use_rec;
+  df_ref *use_rec;
 
   if (GET_CODE (reg) == SUBREG)
     reg = SUBREG_REG (reg);
@@ -1825,14 +1748,14 @@ df_find_use (rtx insn, rtx reg)
   uid = INSN_UID (insn);
   for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
     {
-      struct df_ref *use = *use_rec;
+      df_ref use = *use_rec;
       if (rtx_equal_p (DF_REF_REAL_REG (use), reg))
        return use;
     } 
   if (df->changeable_flags & DF_EQ_NOTES)
     for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
       {
-       struct df_ref *use = *use_rec;
+       df_ref use = *use_rec;
        if (rtx_equal_p (DF_REF_REAL_REG (use), reg))
          return use; 
       }
@@ -2064,12 +1987,12 @@ df_dump_bottom (basic_block bb, FILE *file)
 
 
 void
-df_refs_chain_dump (struct df_ref **ref_rec, bool follow_chain, FILE *file)
+df_refs_chain_dump (df_ref *ref_rec, bool follow_chain, FILE *file)
 {
   fprintf (file, "{ ");
   while (*ref_rec)
     {
-      struct df_ref *ref = *ref_rec;
+      df_ref ref = *ref_rec;
       fprintf (file, "%c%d(%d)",
               DF_REF_REG_DEF_P (ref) ? 'd' : (DF_REF_FLAGS (ref) & DF_REF_IN_NOTE) ? 'e' : 'u',
               DF_REF_ID (ref),
@@ -2085,7 +2008,7 @@ df_refs_chain_dump (struct df_ref **ref_rec, bool follow_chain, FILE *file)
 /* Dump either a ref-def or reg-use chain.  */
 
 void
-df_regs_chain_dump (struct df_ref *ref,  FILE *file)
+df_regs_chain_dump (df_ref ref,  FILE *file)
 {
   fprintf (file, "{ ");
   while (ref)
@@ -2094,7 +2017,7 @@ df_regs_chain_dump (struct df_ref *ref,  FILE *file)
               DF_REF_REG_DEF_P (ref) ? 'd' : 'u',
               DF_REF_ID (ref),
               DF_REF_REGNO (ref));
-      ref = ref->next_reg;
+      ref = DF_REF_NEXT_REG (ref);
     }
   fprintf (file, "}");
 }
@@ -2106,7 +2029,7 @@ df_mws_dump (struct df_mw_hardreg **mws, FILE *file)
   while (*mws)
     {
       fprintf (file, "mw %c r[%d..%d]\n", 
-              ((*mws)->type == DF_REF_REG_DEF) ? 'd' : 'u',
+              (DF_MWS_REG_DEF_P (*mws)) ? 'd' : 'u',
               (*mws)->start_regno, (*mws)->end_regno);
       mws++;
     }
@@ -2185,7 +2108,7 @@ df_regno_debug (unsigned int regno, FILE *file)
 
 
 void
-df_ref_debug (struct df_ref *ref, FILE *file)
+df_ref_debug (df_ref ref, FILE *file)
 {
   fprintf (file, "%c%d ",
           DF_REF_REG_DEF_P (ref) ? 'd' : 'u',
@@ -2193,7 +2116,7 @@ df_ref_debug (struct df_ref *ref, FILE *file)
   fprintf (file, "reg %d bb %d insn %d flag 0x%x type 0x%x ",
           DF_REF_REGNO (ref),
           DF_REF_BBNO (ref),
-          DF_REF_INSN_INFO (ref) ? INSN_UID (DF_REF_INSN (ref)) : -1,
+          DF_REF_IS_ARTIFICIAL (ref) ? -1 : DF_REF_INSN_UID (ref),
           DF_REF_FLAGS (ref),
           DF_REF_TYPE (ref));
   if (DF_REF_LOC (ref))
@@ -2229,7 +2152,7 @@ debug_df_regno (unsigned int regno)
 
 
 void
-debug_df_ref (struct df_ref *ref)
+debug_df_ref (df_ref ref)
 {
   df_ref_debug (ref, stderr);
 }