]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/df-core.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / df-core.c
index 758e40e8eb74bc43578f0f587d37c90973e12645..b4407eec460123175149dee7f4d755cada84c4bc 100644 (file)
@@ -1,6 +1,5 @@
 /* Allocation for dataflow support routines.
-   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-   2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1999-2021 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)
@@ -182,7 +181,7 @@ There are four ways of doing the incremental scanning:
    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
+   note_stores and rtx iterators 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).
@@ -299,12 +298,12 @@ There are 4 ways to obtain access to refs:
 
    Artificial defs and uses occur both at the beginning and ends of blocks.
 
-     For blocks that area at the destination of eh edges, the
+     For blocks that are at the destination of eh edges, the
      artificial uses and defs occur at the beginning.  The defs relate
      to the registers specified in EH_RETURN_DATA_REGNO and the uses
-     relate to the registers specified in ED_USES.  Logically these
+     relate to the registers specified in EH_USES.  Logically these
      defs and uses should really occur along the eh edge, but there is
-     no convenient way to do this.  Artificial edges that occur at the
+     no convenient way to do this.  Artificial defs that occur at the
      beginning of the block have the DF_REF_AT_TOP flag set.
 
      Artificial uses occur at the end of all blocks.  These arise from
@@ -378,31 +377,25 @@ are write-only operations.
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
 #include "rtl.h"
-#include "tm_p.h"
-#include "insn-config.h"
-#include "recog.h"
-#include "function.h"
-#include "regs.h"
-#include "output.h"
-#include "alloc-pool.h"
-#include "flags.h"
-#include "hard-reg-set.h"
-#include "basic-block.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "timevar.h"
 #include "df.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "cfganal.h"
 #include "tree-pass.h"
-#include "params.h"
+#include "cfgloop.h"
 
 static void *df_get_bb_info (struct dataflow *, unsigned int);
 static void df_set_bb_info (struct dataflow *, unsigned int, void *);
+static void df_clear_bb_info (struct dataflow *, unsigned int);
 #ifdef DF_DEBUG_CFG
 static void df_set_clean_cfg (void);
 #endif
 
+/* The obstack on which regsets are allocated.  */
+struct bitmap_obstack reg_obstack;
+
 /* An obstack for bitmap not related to specific dataflow problems.
    This obstack should e.g. be used for bitmaps with a short life time
    such as temporary bitmaps.  */
@@ -414,12 +407,12 @@ bitmap_obstack df_bitmap_obstack;
   Functions to create, destroy and manipulate an instance of df.
 ----------------------------------------------------------------------------*/
 
-struct df *df;
+class df_d *df;
 
 /* Add PROBLEM (and any dependent problems) to the DF instance.  */
 
 void
-df_add_problem (struct df_problem *problem)
+df_add_problem (const struct df_problem *problem)
 {
   struct dataflow *dflow;
   int i;
@@ -504,7 +497,7 @@ df_set_blocks (bitmap blocks)
          /* This block is called to change the focus from one subset
             to another.  */
          int p;
-         bitmap diff = BITMAP_ALLOC (&df_bitmap_obstack);
+         auto_bitmap diff (&df_bitmap_obstack);
          bitmap_and_compl (diff, df->blocks_to_analyze, blocks);
          for (p = 0; p < df->num_problems_defined; p++)
            {
@@ -518,48 +511,43 @@ df_set_blocks (bitmap blocks)
 
                  EXECUTE_IF_SET_IN_BITMAP (diff, 0, bb_index, bi)
                    {
-                     basic_block bb = BASIC_BLOCK (bb_index);
+                     basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
                      if (bb)
                        {
                          void *bb_info = df_get_bb_info (dflow, bb_index);
-                         if (bb_info)
-                           {
-                             dflow->problem->free_bb_fun (bb, bb_info);
-                             df_set_bb_info (dflow, bb_index, NULL);
-                           }
+                         dflow->problem->free_bb_fun (bb, bb_info);
+                         df_clear_bb_info (dflow, bb_index);
                        }
                    }
                }
            }
-
-         BITMAP_FREE (diff);
        }
       else
        {
          /* This block of code is executed to change the focus from
             the entire function to a subset.  */
-         bitmap blocks_to_reset = NULL;
+         bitmap_head blocks_to_reset;
+         bool initialized = false;
          int p;
          for (p = 0; p < df->num_problems_defined; p++)
            {
              struct dataflow *dflow = df->problems_in_order[p];
              if (dflow->optional_p && dflow->problem->reset_fun)
                {
-                 if (!blocks_to_reset)
+                 if (!initialized)
                    {
                      basic_block bb;
-                     blocks_to_reset =
-                       BITMAP_ALLOC (&df_bitmap_obstack);
-                     FOR_ALL_BB(bb)
+                     bitmap_initialize (&blocks_to_reset, &df_bitmap_obstack);
+                     FOR_ALL_BB_FN (bb, cfun)
                        {
-                         bitmap_set_bit (blocks_to_reset, bb->index);
+                         bitmap_set_bit (&blocks_to_reset, bb->index);
                        }
                    }
-                 dflow->problem->reset_fun (blocks_to_reset);
+                 dflow->problem->reset_fun (&blocks_to_reset);
                }
            }
-         if (blocks_to_reset)
-           BITMAP_FREE (blocks_to_reset);
+         if (initialized)
+           bitmap_clear (&blocks_to_reset);
 
          df->blocks_to_analyze = BITMAP_ALLOC (&df_bitmap_obstack);
        }
@@ -594,7 +582,7 @@ df_set_blocks (bitmap blocks)
 void
 df_remove_problem (struct dataflow *dflow)
 {
-  struct df_problem *problem;
+  const struct df_problem *problem;
   int i;
 
   if (!dflow)
@@ -633,7 +621,6 @@ void
 df_finish_pass (bool verify ATTRIBUTE_UNUSED)
 {
   int i;
-  int removed = 0;
 
 #ifdef ENABLE_DF_CHECKING
   int saved_flags;
@@ -649,21 +636,15 @@ df_finish_pass (bool verify ATTRIBUTE_UNUSED)
   saved_flags = df->changeable_flags;
 #endif
 
-  for (i = 0; i < df->num_problems_defined; i++)
+  /* We iterate over problems by index as each problem removed will
+     lead to problems_in_order to be reordered.  */
+  for (i = 0; i < DF_LAST_PROBLEM_PLUS1; i++)
     {
-      struct dataflow *dflow = df->problems_in_order[i];
-      struct df_problem *problem = dflow->problem;
+      struct dataflow *dflow = df->problems_by_index[i];
 
-      if (dflow->optional_p)
-       {
-         gcc_assert (problem->remove_problem_fun);
-         (problem->remove_problem_fun) ();
-         df->problems_in_order[i] = NULL;
-         df->problems_by_index[problem->id] = NULL;
-         removed++;
-       }
+      if (dflow && dflow->optional_p)
+       df_remove_problem (dflow);
     }
-  df->num_problems_defined -= removed;
 
   /* Clear all of the flags.  */
   df->changeable_flags = 0;
@@ -692,10 +673,8 @@ df_finish_pass (bool verify ATTRIBUTE_UNUSED)
 #endif
 #endif
 
-#ifdef ENABLE_CHECKING
-  if (verify)
+  if (flag_checking && verify)
     df->changeable_flags |= DF_VERIFY_SCHEDULED;
-#endif
 }
 
 
@@ -705,14 +684,14 @@ static unsigned int
 rest_of_handle_df_initialize (void)
 {
   gcc_assert (!df);
-  df = XCNEW (struct df);
+  df = XCNEW (class df_d);
   df->changeable_flags = 0;
 
   bitmap_obstack_initialize (&df_bitmap_obstack);
 
   /* Set this to a conservative value.  Stack_ptr_mod will compute it
      correctly later.  */
-  current_function_sp_is_unchanging = 0;
+  crtl->sp_is_unchanging = 0;
 
   df_scan_add_problem ();
   df_scan_alloc (NULL);
@@ -722,15 +701,12 @@ rest_of_handle_df_initialize (void)
   if (optimize > 1)
     df_live_add_problem ();
 
-  df->postorder = XNEWVEC (int, last_basic_block);
-  df->postorder_inverted = XNEWVEC (int, last_basic_block);
+  df->postorder = XNEWVEC (int, last_basic_block_for_fn (cfun));
   df->n_blocks = post_order_compute (df->postorder, true, true);
-  df->n_blocks_inverted = inverted_post_order_compute (df->postorder_inverted);
-  gcc_assert (df->n_blocks == df->n_blocks_inverted);
+  inverted_post_order_compute (&df->postorder_inverted);
+  gcc_assert ((unsigned) df->n_blocks == df->postorder_inverted.length ());
 
-  df->hard_regs_live_count = XNEWVEC (unsigned int, FIRST_PSEUDO_REGISTER);
-  memset (df->hard_regs_live_count, 0,
-         sizeof (unsigned int) * FIRST_PSEUDO_REGISTER);
+  df->hard_regs_live_count = XCNEWVEC (unsigned int, FIRST_PSEUDO_REGISTER);
 
   df_hard_reg_init ();
   /* After reload, some ports add certain bits to regs_ever_live so
@@ -742,59 +718,85 @@ rest_of_handle_df_initialize (void)
 }
 
 
-static bool
-gate_opt (void)
-{
-  return optimize > 0;
-}
+namespace {
 
-
-struct rtl_opt_pass pass_df_initialize_opt =
+const pass_data pass_data_df_initialize_opt =
 {
- {
-  RTL_PASS,
-  "dfinit",                             /* name */
-  gate_opt,                             /* gate */
-  rest_of_handle_df_initialize,         /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_NONE,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  0                                     /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "dfinit", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_DF_SCAN, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
+class pass_df_initialize_opt : public rtl_opt_pass
+{
+public:
+  pass_df_initialize_opt (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_df_initialize_opt, ctxt)
+  {}
 
-static bool
-gate_no_opt (void)
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return optimize > 0; }
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_handle_df_initialize ();
+    }
+
+}; // class pass_df_initialize_opt
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_df_initialize_opt (gcc::context *ctxt)
 {
-  return optimize == 0;
+  return new pass_df_initialize_opt (ctxt);
 }
 
 
-struct rtl_opt_pass pass_df_initialize_no_opt =
+namespace {
+
+const pass_data pass_data_df_initialize_no_opt =
 {
- {
-  RTL_PASS,
-  "no-opt dfinit",                      /* name */
-  gate_no_opt,                          /* gate */
-  rest_of_handle_df_initialize,         /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_NONE,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  0                                     /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "no-opt dfinit", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_DF_SCAN, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
+class pass_df_initialize_no_opt : public rtl_opt_pass
+{
+public:
+  pass_df_initialize_no_opt (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_df_initialize_no_opt, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return optimize == 0; }
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_handle_df_initialize ();
+    }
+
+}; // class pass_df_initialize_no_opt
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_df_initialize_no_opt (gcc::context *ctxt)
+{
+  return new pass_df_initialize_no_opt (ctxt);
+}
+
 
 /* Free all the dataflow info and the DF structure.  This should be
    called from the df_finish macro which also NULLs the parm.  */
@@ -812,10 +814,8 @@ rest_of_handle_df_finish (void)
       dflow->problem->free_fun ();
     }
 
-  if (df->postorder)
-    free (df->postorder);
-  if (df->postorder_inverted)
-    free (df->postorder_inverted);
+  free (df->postorder);
+  df->postorder_inverted.release ();
   free (df->hard_regs_live_count);
   free (df);
   df = NULL;
@@ -825,25 +825,44 @@ rest_of_handle_df_finish (void)
 }
 
 
-struct rtl_opt_pass pass_df_finish =
-{
- {
-  RTL_PASS,
-  "dfinish",                            /* name */
-  NULL,                                        /* gate */
-  rest_of_handle_df_finish,             /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_NONE,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  0                                     /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_df_finish =
+{
+  RTL_PASS, /* type */
+  "dfinish", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
+class pass_df_finish : public rtl_opt_pass
+{
+public:
+  pass_df_finish (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_df_finish, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_handle_df_finish ();
+    }
+
+}; // class pass_df_finish
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_df_finish (gcc::context *ctxt)
+{
+  return new pass_df_finish (ctxt);
+}
+
 
 
 
@@ -852,35 +871,51 @@ struct rtl_opt_pass pass_df_finish =
    The general data flow analysis engine.
 ----------------------------------------------------------------------------*/
 
-
 /* Helper function for df_worklist_dataflow.
    Propagate the dataflow forward.
    Given a BB_INDEX, do the dataflow propagation
    and set bits on for successors in PENDING
-   if the out set of the dataflow has changed. */
+   if the out set of the dataflow has changed.
 
-static void
+   AGE specify time when BB was visited last time.
+   AGE of 0 means we are visiting for first time and need to
+   compute transfer function to initialize datastructures.
+   Otherwise we re-do transfer function only if something change
+   while computing confluence functions.
+   We need to compute confluence only of basic block that are younger
+   then last visit of the BB.
+
+   Return true if BB info has changed.  This is always the case
+   in the first visit.  */
+
+static bool
 df_worklist_propagate_forward (struct dataflow *dataflow,
                                unsigned bb_index,
                                unsigned *bbindex_to_postorder,
                                bitmap pending,
-                               sbitmap considered)
+                               sbitmap considered,
+                              vec<int> &last_change_age,
+                              int age)
 {
   edge e;
   edge_iterator ei;
-  basic_block bb = BASIC_BLOCK (bb_index);
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
+  bool changed = !age;
 
   /*  Calculate <conf_op> of incoming edges.  */
   if (EDGE_COUNT (bb->preds) > 0)
     FOR_EACH_EDGE (e, ei, bb->preds)
       {
-        if (TEST_BIT (considered, e->src->index))
-          dataflow->problem->con_fun_n (e);
+       if (bbindex_to_postorder[e->src->index] < last_change_age.length ()
+           && age <= last_change_age[bbindex_to_postorder[e->src->index]]
+           && bitmap_bit_p (considered, e->src->index))
+          changed |= dataflow->problem->con_fun_n (e);
       }
   else if (dataflow->problem->con_fun_0)
     dataflow->problem->con_fun_0 (bb);
 
-  if (dataflow->problem->trans_fun (bb_index))
+  if (changed
+      && dataflow->problem->trans_fun (bb_index))
     {
       /* The out set of this block has changed.
          Propagate to the outgoing blocks.  */
@@ -888,38 +923,46 @@ df_worklist_propagate_forward (struct dataflow *dataflow,
         {
           unsigned ob_index = e->dest->index;
 
-          if (TEST_BIT (considered, ob_index))
+          if (bitmap_bit_p (considered, ob_index))
             bitmap_set_bit (pending, bbindex_to_postorder[ob_index]);
         }
+      return true;
     }
+  return false;
 }
 
 
 /* Helper function for df_worklist_dataflow.
    Propagate the dataflow backward.  */
 
-static void
+static bool
 df_worklist_propagate_backward (struct dataflow *dataflow,
                                 unsigned bb_index,
                                 unsigned *bbindex_to_postorder,
                                 bitmap pending,
-                                sbitmap considered)
+                                sbitmap considered,
+                               vec<int> &last_change_age,
+                               int age)
 {
   edge e;
   edge_iterator ei;
-  basic_block bb = BASIC_BLOCK (bb_index);
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
+  bool changed = !age;
 
   /*  Calculate <conf_op> of incoming edges.  */
   if (EDGE_COUNT (bb->succs) > 0)
     FOR_EACH_EDGE (e, ei, bb->succs)
       {
-        if (TEST_BIT (considered, e->dest->index))
-          dataflow->problem->con_fun_n (e);
+       if (bbindex_to_postorder[e->dest->index] < last_change_age.length ()
+           && age <= last_change_age[bbindex_to_postorder[e->dest->index]]
+           && bitmap_bit_p (considered, e->dest->index))
+          changed |= dataflow->problem->con_fun_n (e);
       }
   else if (dataflow->problem->con_fun_0)
     dataflow->problem->con_fun_0 (bb);
 
-  if (dataflow->problem->trans_fun (bb_index))
+  if (changed
+      && dataflow->problem->trans_fun (bb_index))
     {
       /* The out set of this block has changed.
          Propagate to the outgoing blocks.  */
@@ -927,69 +970,101 @@ df_worklist_propagate_backward (struct dataflow *dataflow,
         {
           unsigned ob_index = e->src->index;
 
-          if (TEST_BIT (considered, ob_index))
+          if (bitmap_bit_p (considered, ob_index))
             bitmap_set_bit (pending, bbindex_to_postorder[ob_index]);
         }
+      return true;
     }
+  return false;
 }
 
+/* Main dataflow solver loop.
+
+   DATAFLOW is problem we are solving, PENDING is worklist of basic blocks we
+   need to visit.
+   BLOCK_IN_POSTORDER is array of size N_BLOCKS specifying postorder in BBs and
+   BBINDEX_TO_POSTORDER is array mapping back BB->index to postorder position.
+   PENDING will be freed.
 
+   The worklists are bitmaps indexed by postorder positions.  
 
-/* This will free "pending". */
+   The function implements standard algorithm for dataflow solving with two
+   worklists (we are processing WORKLIST and storing new BBs to visit in
+   PENDING).
+
+   As an optimization we maintain ages when BB was changed (stored in
+   last_change_age) and when it was last visited (stored in last_visit_age).
+   This avoids need to re-do confluence function for edges to basic blocks
+   whose source did not change since destination was visited last time.  */
 
 static void
 df_worklist_dataflow_doublequeue (struct dataflow *dataflow,
                                  bitmap pending,
                                   sbitmap considered,
                                   int *blocks_in_postorder,
-                                 unsigned *bbindex_to_postorder)
+                                 unsigned *bbindex_to_postorder,
+                                 int n_blocks)
 {
   enum df_flow_dir dir = dataflow->problem->dir;
   int dcount = 0;
   bitmap worklist = BITMAP_ALLOC (&df_bitmap_obstack);
+  int age = 0;
+  bool changed;
+  vec<int> last_visit_age = vNULL;
+  vec<int> last_change_age = vNULL;
+  int prev_age;
+
+  last_visit_age.safe_grow_cleared (n_blocks, true);
+  last_change_age.safe_grow_cleared (n_blocks, true);
 
   /* Double-queueing. Worklist is for the current iteration,
      and pending is for the next. */
   while (!bitmap_empty_p (pending))
     {
-      /* Swap pending and worklist. */
-      bitmap temp = worklist;
-      worklist = pending;
-      pending = temp;
+      bitmap_iterator bi;
+      unsigned int index;
+
+      std::swap (pending, worklist);
 
-      do
+      EXECUTE_IF_SET_IN_BITMAP (worklist, 0, index, bi)
        {
-         int index;
          unsigned bb_index;
          dcount++;
 
-         index = bitmap_first_set_bit (worklist);
-         bitmap_clear_bit (worklist, index);
-
+         bitmap_clear_bit (pending, index);
          bb_index = blocks_in_postorder[index];
-
+         prev_age = last_visit_age[index];
          if (dir == DF_FORWARD)
-           df_worklist_propagate_forward (dataflow, bb_index,
-                                          bbindex_to_postorder,
-                                          pending, considered);
+           changed = df_worklist_propagate_forward (dataflow, bb_index,
+                                                    bbindex_to_postorder,
+                                                    pending, considered,
+                                                    last_change_age,
+                                                    prev_age);
          else
-           df_worklist_propagate_backward (dataflow, bb_index,
-                                           bbindex_to_postorder,
-                                           pending, considered);
+           changed = df_worklist_propagate_backward (dataflow, bb_index,
+                                                     bbindex_to_postorder,
+                                                     pending, considered,
+                                                     last_change_age,
+                                                     prev_age);
+         last_visit_age[index] = ++age;
+         if (changed)
+           last_change_age[index] = age;
        }
-      while (!bitmap_empty_p (worklist));
+      bitmap_clear (worklist);
     }
 
   BITMAP_FREE (worklist);
   BITMAP_FREE (pending);
+  last_visit_age.release ();
+  last_change_age.release ();
 
   /* Dump statistics. */
   if (dump_file)
     fprintf (dump_file, "df_worklist_dataflow_doublequeue:"
-            "n_basic_blocks %d n_edges %d"
+            " n_basic_blocks %d n_edges %d"
             " count %d (%5.2g)\n",
-            n_basic_blocks, n_edges,
-            dcount, dcount / (float)n_basic_blocks);
+            n_basic_blocks_for_fn (cfun), n_edges_for_fn (cfun),
+            dcount, dcount / (double)n_basic_blocks_for_fn (cfun));
 }
 
 /* Worklist-based dataflow solver. It uses sbitmap as a worklist,
@@ -1006,7 +1081,6 @@ df_worklist_dataflow (struct dataflow *dataflow,
                       int n_blocks)
 {
   bitmap pending = BITMAP_ALLOC (&df_bitmap_obstack);
-  sbitmap considered = sbitmap_alloc (last_basic_block);
   bitmap_iterator bi;
   unsigned int *bbindex_to_postorder;
   int i;
@@ -1016,18 +1090,19 @@ df_worklist_dataflow (struct dataflow *dataflow,
   gcc_assert (dir != DF_NONE);
 
   /* BBINDEX_TO_POSTORDER maps the bb->index to the reverse postorder.  */
-  bbindex_to_postorder =
-    (unsigned int *)xmalloc (last_basic_block * sizeof (unsigned int));
+  bbindex_to_postorder = XNEWVEC (unsigned int,
+                                 last_basic_block_for_fn (cfun));
 
   /* Initialize the array to an out-of-bound value.  */
-  for (i = 0; i < last_basic_block; i++)
-    bbindex_to_postorder[i] = last_basic_block;
+  for (i = 0; i < last_basic_block_for_fn (cfun); i++)
+    bbindex_to_postorder[i] = last_basic_block_for_fn (cfun);
 
   /* Initialize the considered map.  */
-  sbitmap_zero (considered);
+  auto_sbitmap considered (last_basic_block_for_fn (cfun));
+  bitmap_clear (considered);
   EXECUTE_IF_SET_IN_BITMAP (blocks_to_consider, 0, index, bi)
     {
-      SET_BIT (considered, index);
+      bitmap_set_bit (considered, index);
     }
 
   /* Initialize the mapping of block index to postorder.  */
@@ -1045,9 +1120,8 @@ df_worklist_dataflow (struct dataflow *dataflow,
   /* Solve it.  */
   df_worklist_dataflow_doublequeue (dataflow, pending, considered,
                                    blocks_in_postorder,
-                                   bbindex_to_postorder);
-
-  sbitmap_free (considered);
+                                   bbindex_to_postorder,
+                                   n_blocks);
   free (bbindex_to_postorder);
 }
 
@@ -1083,15 +1157,15 @@ df_analyze_problem (struct dataflow *dflow,
 {
   timevar_push (dflow->problem->tv_id);
 
+  /* (Re)Allocate the datastructures necessary to solve the problem.  */
+  if (dflow->problem->alloc_fun)
+    dflow->problem->alloc_fun (blocks_to_consider);
+
 #ifdef ENABLE_DF_CHECKING
   if (dflow->problem->verify_start_fun)
     dflow->problem->verify_start_fun ();
 #endif
 
-  /* (Re)Allocate the datastructures necessary to solve the problem.  */
-  if (dflow->problem->alloc_fun)
-    dflow->problem->alloc_fun (blocks_to_consider);
-
   /* Set up the problem and compute the local information.  */
   if (dflow->problem->local_compute_fun)
     dflow->problem->local_compute_fun (blocks_to_consider);
@@ -1116,27 +1190,15 @@ df_analyze_problem (struct dataflow *dflow,
 }
 
 
-/* Analyze dataflow info for the basic blocks specified by the bitmap
-   BLOCKS, or for the whole CFG if BLOCKS is zero.  */
+/* Analyze dataflow info.  */
 
-void
-df_analyze (void)
+static void
+df_analyze_1 (void)
 {
-  bitmap current_all_blocks = BITMAP_ALLOC (&df_bitmap_obstack);
-  bool everything;
   int i;
 
-  if (df->postorder)
-    free (df->postorder);
-  if (df->postorder_inverted)
-    free (df->postorder_inverted);
-  df->postorder = XNEWVEC (int, last_basic_block);
-  df->postorder_inverted = XNEWVEC (int, last_basic_block);
-  df->n_blocks = post_order_compute (df->postorder, true, true);
-  df->n_blocks_inverted = inverted_post_order_compute (df->postorder_inverted);
-
   /* These should be the same.  */
-  gcc_assert (df->n_blocks == df->n_blocks_inverted);
+  gcc_assert ((unsigned) df->n_blocks == df->postorder_inverted.length ());
 
   /* We need to do this before the df_verify_all because this is
      not kept incrementally up to date.  */
@@ -1151,36 +1213,6 @@ df_analyze (void)
 #endif
     df_verify ();
 
-  for (i = 0; i < df->n_blocks; i++)
-    bitmap_set_bit (current_all_blocks, df->postorder[i]);
-
-#ifdef ENABLE_CHECKING
-  /* Verify that POSTORDER_INVERTED only contains blocks reachable from
-     the ENTRY block.  */
-  for (i = 0; i < df->n_blocks_inverted; i++)
-    gcc_assert (bitmap_bit_p (current_all_blocks, df->postorder_inverted[i]));
-#endif
-
-  /* Make sure that we have pruned any unreachable blocks from these
-     sets.  */
-  if (df->analyze_subset)
-    {
-      everything = false;
-      bitmap_and_into (df->blocks_to_analyze, current_all_blocks);
-      df->n_blocks = df_prune_to_subcfg (df->postorder,
-                                        df->n_blocks, df->blocks_to_analyze);
-      df->n_blocks_inverted = df_prune_to_subcfg (df->postorder_inverted,
-                                                 df->n_blocks_inverted,
-                                                  df->blocks_to_analyze);
-      BITMAP_FREE (current_all_blocks);
-    }
-  else
-    {
-      everything = true;
-      df->blocks_to_analyze = current_all_blocks;
-      current_all_blocks = NULL;
-    }
-
   /* Skip over the DF_SCAN problem. */
   for (i = 1; i < df->num_problems_defined; i++)
     {
@@ -1190,8 +1222,8 @@ df_analyze (void)
           if (dflow->problem->dir == DF_FORWARD)
             df_analyze_problem (dflow,
                                 df->blocks_to_analyze,
-                                df->postorder_inverted,
-                                df->n_blocks_inverted);
+                               df->postorder_inverted.address (),
+                               df->postorder_inverted.length ());
           else
             df_analyze_problem (dflow,
                                 df->blocks_to_analyze,
@@ -1200,7 +1232,7 @@ df_analyze (void)
         }
     }
 
-  if (everything)
+  if (!df->analyze_subset)
     {
       BITMAP_FREE (df->blocks_to_analyze);
       df->blocks_to_analyze = NULL;
@@ -1211,6 +1243,203 @@ df_analyze (void)
 #endif
 }
 
+/* Analyze dataflow info.  */
+
+void
+df_analyze (void)
+{
+  bitmap current_all_blocks = BITMAP_ALLOC (&df_bitmap_obstack);
+
+  free (df->postorder);
+  df->postorder = XNEWVEC (int, last_basic_block_for_fn (cfun));
+  df->n_blocks = post_order_compute (df->postorder, true, true);
+  df->postorder_inverted.truncate (0);
+  inverted_post_order_compute (&df->postorder_inverted);
+
+  for (int i = 0; i < df->n_blocks; i++)
+    bitmap_set_bit (current_all_blocks, df->postorder[i]);
+
+  if (flag_checking)
+    {
+      /* Verify that POSTORDER_INVERTED only contains blocks reachable from
+        the ENTRY block.  */
+      for (unsigned int i = 0; i < df->postorder_inverted.length (); i++)
+       gcc_assert (bitmap_bit_p (current_all_blocks,
+                                 df->postorder_inverted[i]));
+    }
+
+  /* Make sure that we have pruned any unreachable blocks from these
+     sets.  */
+  if (df->analyze_subset)
+    {
+      bitmap_and_into (df->blocks_to_analyze, current_all_blocks);
+      df->n_blocks = df_prune_to_subcfg (df->postorder,
+                                        df->n_blocks, df->blocks_to_analyze);
+      unsigned int newlen = df_prune_to_subcfg (df->postorder_inverted.address (),
+                                               df->postorder_inverted.length (),
+                                                 df->blocks_to_analyze);
+      df->postorder_inverted.truncate (newlen);
+      BITMAP_FREE (current_all_blocks);
+    }
+  else
+    {
+      df->blocks_to_analyze = current_all_blocks;
+      current_all_blocks = NULL;
+    }
+
+  df_analyze_1 ();
+}
+
+/* Compute the reverse top sort order of the sub-CFG specified by LOOP.
+   Returns the number of blocks which is always loop->num_nodes.  */
+
+static int
+loop_post_order_compute (int *post_order, class loop *loop)
+{
+  edge_iterator *stack;
+  int sp;
+  int post_order_num = 0;
+
+  /* Allocate stack for back-tracking up CFG.  */
+  stack = XNEWVEC (edge_iterator, loop->num_nodes + 1);
+  sp = 0;
+
+  /* Allocate bitmap to track nodes that have been visited.  */
+  auto_bitmap visited;
+
+  /* Push the first edge on to the stack.  */
+  stack[sp++] = ei_start (loop_preheader_edge (loop)->src->succs);
+
+  while (sp)
+    {
+      edge_iterator ei;
+      basic_block src;
+      basic_block dest;
+
+      /* Look at the edge on the top of the stack.  */
+      ei = stack[sp - 1];
+      src = ei_edge (ei)->src;
+      dest = ei_edge (ei)->dest;
+
+      /* Check if the edge destination has been visited yet and mark it
+         if not so.  */
+      if (flow_bb_inside_loop_p (loop, dest)
+         && bitmap_set_bit (visited, dest->index))
+       {
+         if (EDGE_COUNT (dest->succs) > 0)
+           /* Since the DEST node has been visited for the first
+              time, check its successors.  */
+           stack[sp++] = ei_start (dest->succs);
+         else
+           post_order[post_order_num++] = dest->index;
+       }
+      else
+       {
+         if (ei_one_before_end_p (ei)
+             && src != loop_preheader_edge (loop)->src)
+           post_order[post_order_num++] = src->index;
+
+         if (!ei_one_before_end_p (ei))
+           ei_next (&stack[sp - 1]);
+         else
+           sp--;
+       }
+    }
+
+  free (stack);
+
+  return post_order_num;
+}
+
+/* Compute the reverse top sort order of the inverted sub-CFG specified
+   by LOOP.  Returns the number of blocks which is always loop->num_nodes.  */
+
+static void
+loop_inverted_post_order_compute (vec<int> *post_order, class loop *loop)
+{
+  basic_block bb;
+  edge_iterator *stack;
+  int sp;
+
+  post_order->reserve_exact (loop->num_nodes);
+
+  /* Allocate stack for back-tracking up CFG.  */
+  stack = XNEWVEC (edge_iterator, loop->num_nodes + 1);
+  sp = 0;
+
+  /* Allocate bitmap to track nodes that have been visited.  */
+  auto_bitmap visited;
+
+  /* Put all latches into the initial work list.  In theory we'd want
+     to start from loop exits but then we'd have the special case of
+     endless loops.  It doesn't really matter for DF iteration order and
+     handling latches last is probably even better.  */
+  stack[sp++] = ei_start (loop->header->preds);
+  bitmap_set_bit (visited, loop->header->index);
+
+  /* The inverted traversal loop. */
+  while (sp)
+    {
+      edge_iterator ei;
+      basic_block pred;
+
+      /* Look at the edge on the top of the stack.  */
+      ei = stack[sp - 1];
+      bb = ei_edge (ei)->dest;
+      pred = ei_edge (ei)->src;
+
+      /* Check if the predecessor has been visited yet and mark it
+        if not so.  */
+      if (flow_bb_inside_loop_p (loop, pred)
+         && bitmap_set_bit (visited, pred->index))
+       {
+         if (EDGE_COUNT (pred->preds) > 0)
+           /* Since the predecessor node has been visited for the first
+              time, check its predecessors.  */
+           stack[sp++] = ei_start (pred->preds);
+         else
+           post_order->quick_push (pred->index);
+       }
+      else
+       {
+         if (flow_bb_inside_loop_p (loop, bb)
+             && ei_one_before_end_p (ei))
+           post_order->quick_push (bb->index);
+
+         if (!ei_one_before_end_p (ei))
+           ei_next (&stack[sp - 1]);
+         else
+           sp--;
+       }
+    }
+
+  free (stack);
+}
+
+
+/* Analyze dataflow info for the basic blocks contained in LOOP.  */
+
+void
+df_analyze_loop (class loop *loop)
+{
+  free (df->postorder);
+
+  df->postorder = XNEWVEC (int, loop->num_nodes);
+  df->postorder_inverted.truncate (0);
+  df->n_blocks = loop_post_order_compute (df->postorder, loop);
+    loop_inverted_post_order_compute (&df->postorder_inverted, loop);
+  gcc_assert ((unsigned) df->n_blocks == loop->num_nodes);
+  gcc_assert (df->postorder_inverted.length () == loop->num_nodes);
+
+  bitmap blocks = BITMAP_ALLOC (&df_bitmap_obstack);
+  for (int i = 0; i < df->n_blocks; ++i)
+    bitmap_set_bit (blocks, df->postorder[i]);
+  df_set_blocks (blocks);
+  BITMAP_FREE (blocks);
+
+  df_analyze_1 ();
+}
+
 
 /* Return the number of basic blocks from the last call to df_analyze.  */
 
@@ -1221,8 +1450,8 @@ df_get_n_blocks (enum df_flow_dir dir)
 
   if (dir == DF_FORWARD)
     {
-      gcc_assert (df->postorder_inverted);
-      return df->n_blocks_inverted;
+      gcc_assert (df->postorder_inverted.length ());
+      return df->postorder_inverted.length ();
     }
 
   gcc_assert (df->postorder);
@@ -1241,8 +1470,8 @@ df_get_postorder (enum df_flow_dir dir)
 
   if (dir == DF_FORWARD)
     {
-      gcc_assert (df->postorder_inverted);
-      return df->postorder_inverted;
+      gcc_assert (df->postorder_inverted.length ());
+      return df->postorder_inverted.address ();
     }
   gcc_assert (df->postorder);
   return df->postorder;
@@ -1293,7 +1522,8 @@ df_get_bb_info (struct dataflow *dflow, unsigned int index)
     return NULL;
   if (index >= dflow->block_info_size)
     return NULL;
-  return (struct df_scan_bb_info *) dflow->block_info[index];
+  return (void *)((char *)dflow->block_info
+                 + index * dflow->problem->block_info_elt_size);
 }
 
 
@@ -1304,7 +1534,22 @@ df_set_bb_info (struct dataflow *dflow, unsigned int index,
                void *bb_info)
 {
   gcc_assert (dflow->block_info);
-  dflow->block_info[index] = bb_info;
+  memcpy ((char *)dflow->block_info
+         + index * dflow->problem->block_info_elt_size,
+         bb_info, dflow->problem->block_info_elt_size);
+}
+
+
+/* Clear basic block info.  */
+
+static void
+df_clear_bb_info (struct dataflow *dflow, unsigned int index)
+{
+  gcc_assert (dflow->block_info);
+  gcc_assert (dflow->block_info_size > index);
+  memset ((char *)dflow->block_info
+         + index * dflow->problem->block_info_elt_size,
+         0, dflow->problem->block_info_elt_size);
 }
 
 
@@ -1327,10 +1572,9 @@ df_mark_solutions_dirty (void)
 bool
 df_get_bb_dirty (basic_block bb)
 {
-  if (df && df_live)
-    return bitmap_bit_p (df_live->out_of_date_transfer_functions, bb->index);
-  else
-    return false;
+  return bitmap_bit_p ((df_live
+                       ? df_live : df_lr)->out_of_date_transfer_functions,
+                      bb->index);
 }
 
 
@@ -1340,6 +1584,7 @@ df_get_bb_dirty (basic_block bb)
 void
 df_set_bb_dirty (basic_block bb)
 {
+  bb->flags |= BB_MODIFIED;
   if (df)
     {
       int p;
@@ -1354,26 +1599,26 @@ df_set_bb_dirty (basic_block bb)
 }
 
 
-/* Mark BB as needing it's transfer functions as being out of
-   date, except for LR problem.  Used when analyzing DEBUG_INSNs,
-   as LR problem can trigger DCE, and DEBUG_INSNs shouldn't ever
-   shorten or enlarge lifetime of regs.  */
+/* Grow the bb_info array.  */
 
 void
-df_set_bb_dirty_nonlr (basic_block bb)
+df_grow_bb_info (struct dataflow *dflow)
 {
-  if (df)
+  unsigned int new_size = last_basic_block_for_fn (cfun) + 1;
+  if (dflow->block_info_size < new_size)
     {
-      int p;
-      for (p = 1; p < df->num_problems_defined; p++)
-       {
-         struct dataflow *dflow = df->problems_in_order[p];
-         if (dflow == df_lr)
-           continue;
-         if (dflow->out_of_date_transfer_functions)
-           bitmap_set_bit (dflow->out_of_date_transfer_functions, bb->index);
-         dflow->solutions_dirty = true;
-       }
+      new_size += new_size / 4;
+      dflow->block_info
+         = (void *)XRESIZEVEC (char, (char *)dflow->block_info,
+                              new_size
+                              * dflow->problem->block_info_elt_size);
+      memset ((char *)dflow->block_info
+             + dflow->block_info_size
+             * dflow->problem->block_info_elt_size,
+             0,
+             (new_size - dflow->block_info_size)
+             * dflow->problem->block_info_elt_size);
+      dflow->block_info_size = new_size;
     }
 }
 
@@ -1391,6 +1636,7 @@ df_clear_bb_dirty (basic_block bb)
        bitmap_clear_bit (dflow->out_of_date_transfer_functions, bb->index);
     }
 }
+
 /* Called from the rtl_compact_blocks to reorganize the problems basic
    block info.  */
 
@@ -1399,11 +1645,9 @@ df_compact_blocks (void)
 {
   int i, p;
   basic_block bb;
-  void **problem_temps;
-  int size = last_basic_block * sizeof (void *);
-  bitmap tmp = BITMAP_ALLOC (&df_bitmap_obstack);
-  problem_temps = XNEWVAR (void *, size);
+  void *problem_temps;
 
+  auto_bitmap tmp (&df_bitmap_obstack);
   for (p = 0; p < df->num_problems_defined; p++)
     {
       struct dataflow *dflow = df->problems_in_order[p];
@@ -1420,7 +1664,7 @@ df_compact_blocks (void)
            bitmap_set_bit (dflow->out_of_date_transfer_functions, EXIT_BLOCK);
 
          i = NUM_FIXED_BLOCKS;
-         FOR_EACH_BB (bb)
+         FOR_EACH_BB_FN (bb, cfun)
            {
              if (bitmap_bit_p (tmp, bb->index))
                bitmap_set_bit (dflow->out_of_date_transfer_functions, i);
@@ -1431,6 +1675,9 @@ df_compact_blocks (void)
       /* Now shuffle the block info for the problem.  */
       if (dflow->problem->free_bb_fun)
        {
+         int size = (last_basic_block_for_fn (cfun)
+                     * dflow->problem->block_info_elt_size);
+         problem_temps = XNEWVAR (char, size);
          df_grow_bb_info (dflow);
          memcpy (problem_temps, dflow->block_info, size);
 
@@ -1438,24 +1685,18 @@ df_compact_blocks (void)
             place in the block_info vector.  Null out the copied
             item.  The entry and exit blocks never move.  */
          i = NUM_FIXED_BLOCKS;
-         FOR_EACH_BB (bb)
+         FOR_EACH_BB_FN (bb, cfun)
            {
-             df_set_bb_info (dflow, i, problem_temps[bb->index]);
-             problem_temps[bb->index] = NULL;
+             df_set_bb_info (dflow, i,
+                             (char *)problem_temps
+                             + bb->index * dflow->problem->block_info_elt_size);
              i++;
            }
-         memset (dflow->block_info + i, 0,
-                 (last_basic_block - i) *sizeof (void *));
-
-         /* Free any block infos that were not copied (and NULLed).
-            These are from orphaned blocks.  */
-         for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
-           {
-             basic_block bb = BASIC_BLOCK (i);
-             if (problem_temps[i] && bb)
-               dflow->problem->free_bb_fun
-                 (bb, problem_temps[i]);
-           }
+         memset ((char *)dflow->block_info
+                 + i * dflow->problem->block_info_elt_size, 0,
+                 (last_basic_block_for_fn (cfun) - i)
+                 * dflow->problem->block_info_elt_size);
+         free (problem_temps);
        }
     }
 
@@ -1470,7 +1711,7 @@ df_compact_blocks (void)
       bitmap_copy (tmp, df->blocks_to_analyze);
       bitmap_clear (df->blocks_to_analyze);
       i = NUM_FIXED_BLOCKS;
-      FOR_EACH_BB (bb)
+      FOR_EACH_BB_FN (bb, cfun)
        {
          if (bitmap_bit_p (tmp, bb->index))
            bitmap_set_bit (df->blocks_to_analyze, i);
@@ -1478,22 +1719,18 @@ df_compact_blocks (void)
        }
     }
 
-  BITMAP_FREE (tmp);
-
-  free (problem_temps);
-
   i = NUM_FIXED_BLOCKS;
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
-      SET_BASIC_BLOCK (i, bb);
+      SET_BASIC_BLOCK_FOR_FN (cfun, i, bb);
       bb->index = i;
       i++;
     }
 
-  gcc_assert (i == n_basic_blocks);
+  gcc_assert (i == n_basic_blocks_for_fn (cfun));
 
-  for (; i < last_basic_block; i++)
-    SET_BASIC_BLOCK (i, NULL);
+  for (; i < last_basic_block_for_fn (cfun); i++)
+    SET_BASIC_BLOCK_FOR_FN (cfun, i, NULL);
 
 #ifdef DF_DEBUG_CFG
   if (!df_lr->solutions_dirty)
@@ -1515,7 +1752,7 @@ df_bb_replace (int old_index, basic_block new_block)
     fprintf (dump_file, "shoving block %d into %d\n", new_block_index, old_index);
 
   gcc_assert (df);
-  gcc_assert (BASIC_BLOCK (old_index) == NULL);
+  gcc_assert (BASIC_BLOCK_FOR_FN (cfun, old_index) == NULL);
 
   for (p = 0; p < df->num_problems_defined; p++)
     {
@@ -1523,17 +1760,16 @@ df_bb_replace (int old_index, basic_block new_block)
       if (dflow->block_info)
        {
          df_grow_bb_info (dflow);
-         gcc_assert (df_get_bb_info (dflow, old_index) == NULL);
          df_set_bb_info (dflow, old_index,
                          df_get_bb_info (dflow, new_block_index));
        }
     }
 
   df_clear_bb_dirty (new_block);
-  SET_BASIC_BLOCK (old_index, new_block);
+  SET_BASIC_BLOCK_FOR_FN (cfun, old_index, new_block);
   new_block->index = old_index;
-  df_set_bb_dirty (BASIC_BLOCK (old_index));
-  SET_BASIC_BLOCK (new_block_index, NULL);
+  df_set_bb_dirty (BASIC_BLOCK_FOR_FN (cfun, old_index));
+  SET_BASIC_BLOCK_FOR_FN (cfun, new_block_index, NULL);
 }
 
 
@@ -1544,7 +1780,7 @@ df_bb_replace (int old_index, basic_block new_block)
 void
 df_bb_delete (int bb_index)
 {
-  basic_block bb = BASIC_BLOCK (bb_index);
+  basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
   int i;
 
   if (!df)
@@ -1559,7 +1795,7 @@ df_bb_delete (int bb_index)
          if (bb_info)
            {
              dflow->problem->free_bb_fun (bb, bb_info);
-             df_set_bb_info (dflow, bb_index, NULL);
+             df_clear_bb_info (dflow, bb_index);
            }
        }
     }
@@ -1585,6 +1821,7 @@ df_verify (void)
   if (df_live)
     df_live_verify_transfer_functions ();
 #endif
+  df->changeable_flags &= ~DF_VERIFY_SCHEDULED;
 }
 
 #ifdef DF_DEBUG_CFG
@@ -1599,11 +1836,11 @@ static int *
 df_compute_cfg_image (void)
 {
   basic_block bb;
-  int size = 2 + (2 * n_basic_blocks);
+  int size = 2 + (2 * n_basic_blocks_for_fn (cfun));
   int i;
   int * map;
 
-  FOR_ALL_BB (bb)
+  FOR_ALL_BB_FN (bb, cfun)
     {
       size += EDGE_COUNT (bb->succs);
     }
@@ -1611,7 +1848,7 @@ df_compute_cfg_image (void)
   map = XNEWVEC (int, size);
   map[0] = size;
   i = 1;
-  FOR_ALL_BB (bb)
+  FOR_ALL_BB_FN (bb, cfun)
     {
       edge_iterator ei;
       edge e;
@@ -1659,8 +1896,7 @@ df_check_cfg_clean (void)
 static void
 df_set_clean_cfg (void)
 {
-  if (saved_cfg)
-    free (saved_cfg);
+  free (saved_cfg);
   saved_cfg = df_compute_cfg_image ();
 }
 
@@ -1675,22 +1911,17 @@ df_set_clean_cfg (void)
 df_ref
 df_bb_regno_first_def_find (basic_block bb, unsigned int regno)
 {
-  rtx insn;
-  df_ref *def_rec;
-  unsigned int uid;
+  rtx_insn *insn;
+  df_ref def;
 
   FOR_BB_INSNS (bb, insn)
     {
       if (!INSN_P (insn))
        continue;
 
-      uid = INSN_UID (insn);
-      for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
-       {
-         df_ref def = *def_rec;
-         if (DF_REF_REGNO (def) == regno)
-           return def;
-       }
+      FOR_EACH_INSN_DEF (def, insn)
+       if (DF_REF_REGNO (def) == regno)
+         return def;
     }
   return NULL;
 }
@@ -1701,22 +1932,17 @@ df_bb_regno_first_def_find (basic_block bb, unsigned int regno)
 df_ref
 df_bb_regno_last_def_find (basic_block bb, unsigned int regno)
 {
-  rtx insn;
-  df_ref *def_rec;
-  unsigned int uid;
+  rtx_insn *insn;
+  df_ref def;
 
   FOR_BB_INSNS_REVERSE (bb, insn)
     {
       if (!INSN_P (insn))
        continue;
 
-      uid = INSN_UID (insn);
-      for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
-       {
-         df_ref def = *def_rec;
-         if (DF_REF_REGNO (def) == regno)
-           return def;
-       }
+      FOR_EACH_INSN_DEF (def, insn)
+       if (DF_REF_REGNO (def) == regno)
+         return def;
     }
 
   return NULL;
@@ -1726,22 +1952,17 @@ df_bb_regno_last_def_find (basic_block bb, unsigned int regno)
    DF is the dataflow object.  */
 
 df_ref
-df_find_def (rtx insn, rtx reg)
+df_find_def (rtx_insn *insn, rtx reg)
 {
-  unsigned int uid;
-  df_ref *def_rec;
+  df_ref def;
 
   if (GET_CODE (reg) == SUBREG)
     reg = SUBREG_REG (reg);
   gcc_assert (REG_P (reg));
 
-  uid = INSN_UID (insn);
-  for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
-    {
-      df_ref def = *def_rec;
-      if (rtx_equal_p (DF_REF_REAL_REG (def), reg))
-       return def;
-    }
+  FOR_EACH_INSN_DEF (def, insn)
+    if (DF_REF_REGNO (def) == REGNO (reg))
+      return def;
 
   return NULL;
 }
@@ -1750,7 +1971,7 @@ df_find_def (rtx insn, rtx reg)
 /* Return true if REG is defined in INSN, zero otherwise.  */
 
 bool
-df_reg_defined (rtx insn, rtx reg)
+df_reg_defined (rtx_insn *insn, rtx reg)
 {
   return df_find_def (insn, reg) != NULL;
 }
@@ -1760,29 +1981,22 @@ df_reg_defined (rtx insn, rtx reg)
    DF is the dataflow object.  */
 
 df_ref
-df_find_use (rtx insn, rtx reg)
+df_find_use (rtx_insn *insn, rtx reg)
 {
-  unsigned int uid;
-  df_ref *use_rec;
+  df_ref use;
 
   if (GET_CODE (reg) == SUBREG)
     reg = SUBREG_REG (reg);
   gcc_assert (REG_P (reg));
 
-  uid = INSN_UID (insn);
-  for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
-    {
-      df_ref use = *use_rec;
-      if (rtx_equal_p (DF_REF_REAL_REG (use), reg))
-       return use;
-    }
+  df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
+  FOR_EACH_INSN_INFO_USE (use, insn_info)
+    if (DF_REF_REGNO (use) == REGNO (reg))
+      return use;
   if (df->changeable_flags & DF_EQ_NOTES)
-    for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
-      {
-       df_ref use = *use_rec;
-       if (rtx_equal_p (DF_REF_REAL_REG (use), reg))
-         return use;
-      }
+    FOR_EACH_INSN_INFO_EQ_USE (use, insn_info)
+      if (DF_REF_REGNO (use) == REGNO (reg))
+       return use;
   return NULL;
 }
 
@@ -1790,7 +2004,7 @@ df_find_use (rtx insn, rtx reg)
 /* Return true if REG is referenced in INSN, zero otherwise.  */
 
 bool
-df_reg_used (rtx insn, rtx reg)
+df_reg_used (rtx_insn *insn, rtx reg)
 {
   return df_find_use (insn, reg) != NULL;
 }
@@ -1800,12 +2014,46 @@ df_reg_used (rtx insn, rtx reg)
    Debugging and printing functions.
 ----------------------------------------------------------------------------*/
 
+/* Write information about registers and basic blocks into FILE.
+   This is part of making a debugging dump.  */
+
+void
+dump_regset (regset r, FILE *outf)
+{
+  unsigned i;
+  reg_set_iterator rsi;
+
+  if (r == NULL)
+    {
+      fputs (" (nil)", outf);
+      return;
+    }
+
+  EXECUTE_IF_SET_IN_REG_SET (r, 0, i, rsi)
+    {
+      fprintf (outf, " %d", i);
+      if (i < FIRST_PSEUDO_REGISTER)
+       fprintf (outf, " [%s]",
+                reg_names[i]);
+    }
+}
+
+/* Print a human-readable representation of R on the standard error
+   stream.  This function is designed to be used from within the
+   debugger.  */
+extern void debug_regset (regset);
+DEBUG_FUNCTION void
+debug_regset (regset r)
+{
+  dump_regset (r, stderr);
+  putc ('\n', stderr);
+}
 
 /* Write information about registers and basic blocks into FILE.
    This is part of making a debugging dump.  */
 
 void
-df_print_regset (FILE *file, bitmap r)
+df_print_regset (FILE *file, const_bitmap r)
 {
   unsigned int i;
   bitmap_iterator bi;
@@ -1830,58 +2078,33 @@ df_print_regset (FILE *file, bitmap r)
    debugging dump.  */
 
 void
-df_print_byte_regset (FILE *file, bitmap r)
+df_print_word_regset (FILE *file, const_bitmap r)
 {
   unsigned int max_reg = max_reg_num ();
-  bitmap_iterator bi;
 
   if (r == NULL)
     fputs (" (nil)", file);
   else
     {
       unsigned int i;
-      for (i = 0; i < max_reg; i++)
+      for (i = FIRST_PSEUDO_REGISTER; i < max_reg; i++)
        {
-         unsigned int first = df_byte_lr_get_regno_start (i);
-         unsigned int len = df_byte_lr_get_regno_len (i);
-
-         if (len > 1)
-           {
-             bool found = false;
-             unsigned int j;
-
-             EXECUTE_IF_SET_IN_BITMAP (r, first, j, bi)
-               {
-                 found = j < first + len;
-                 break;
-               }
-             if (found)
-               {
-                 const char * sep = "";
-                 fprintf (file, " %d", i);
-                 if (i < FIRST_PSEUDO_REGISTER)
-                   fprintf (file, " [%s]", reg_names[i]);
-                 fprintf (file, "(");
-                 EXECUTE_IF_SET_IN_BITMAP (r, first, j, bi)
-                   {
-                     if (j > first + len - 1)
-                       break;
-                     fprintf (file, "%s%d", sep, j-first);
-                     sep = ", ";
-                   }
-                 fprintf (file, ")");
-               }
-           }
-         else
+         bool found = (bitmap_bit_p (r, 2 * i)
+                       || bitmap_bit_p (r, 2 * i + 1));
+         if (found)
            {
-             if (bitmap_bit_p (r, first))
-               {
-                 fprintf (file, " %d", i);
-                 if (i < FIRST_PSEUDO_REGISTER)
-                   fprintf (file, " [%s]", reg_names[i]);
-               }
+             int word;
+             const char * sep = "";
+             fprintf (file, " %d", i);
+             fprintf (file, "(");
+             for (word = 0; word < 2; word++)
+               if (bitmap_bit_p (r, 2 * i + word))
+                 {
+                   fprintf (file, "%s%d", sep, word);
+                   sep = ", ";
+                 }
+             fprintf (file, ")");
            }
-
        }
     }
   fprintf (file, "\n");
@@ -1896,7 +2119,7 @@ df_dump (FILE *file)
   basic_block bb;
   df_dump_start (file);
 
-  FOR_ALL_BB (bb)
+  FOR_ALL_BB_FN (bb, cfun)
     {
       df_print_bb_index (bb, file);
       df_dump_top (bb, file);
@@ -1922,11 +2145,8 @@ df_dump_region (FILE *file)
 
       EXECUTE_IF_SET_IN_BITMAP (df->blocks_to_analyze, 0, bb_index, bi)
        {
-         basic_block bb = BASIC_BLOCK (bb_index);
-
-         df_print_bb_index (bb, file);
-         df_dump_top (bb, file);
-         df_dump_bottom (bb, file);
+         basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
+         dump_bb (file, bb, 0, TDF_DETAILS);
        }
       fprintf (file, "\n");
     }
@@ -1958,16 +2178,15 @@ df_dump_start (FILE *file)
        {
          df_dump_problem_function fun = dflow->problem->dump_start_fun;
          if (fun)
-           fun(file);
+           fun (file);
        }
     }
 }
 
 
-/* Dump the top of the block information for BB.  */
-
-void
-df_dump_top (basic_block bb, FILE *file)
+/* Dump the top or bottom of the block information for BB.  */
+static void
+df_dump_bb_problem_data (basic_block bb, FILE *file, bool top)
 {
   int i;
 
@@ -1979,18 +2198,39 @@ df_dump_top (basic_block bb, FILE *file)
       struct dataflow *dflow = df->problems_in_order[i];
       if (dflow->computed)
        {
-         df_dump_bb_problem_function bbfun = dflow->problem->dump_top_fun;
+         df_dump_bb_problem_function bbfun;
+
+         if (top)
+           bbfun = dflow->problem->dump_top_fun;
+         else
+           bbfun = dflow->problem->dump_bottom_fun;
+
          if (bbfun)
            bbfun (bb, file);
        }
     }
 }
 
+/* Dump the top of the block information for BB.  */
+
+void
+df_dump_top (basic_block bb, FILE *file)
+{
+  df_dump_bb_problem_data (bb, file, /*top=*/true);
+}
 
 /* Dump the bottom of the block information for BB.  */
 
 void
 df_dump_bottom (basic_block bb, FILE *file)
+{
+  df_dump_bb_problem_data (bb, file, /*top=*/false);
+}
+
+
+/* Dump information about INSN just before or after dumping INSN itself.  */
+static void
+df_dump_insn_problem_data (const rtx_insn *insn, FILE *file, bool top)
 {
   int i;
 
@@ -2002,28 +2242,56 @@ df_dump_bottom (basic_block bb, FILE *file)
       struct dataflow *dflow = df->problems_in_order[i];
       if (dflow->computed)
        {
-         df_dump_bb_problem_function bbfun = dflow->problem->dump_bottom_fun;
-         if (bbfun)
-           bbfun (bb, file);
+         df_dump_insn_problem_function insnfun;
+
+         if (top)
+           insnfun = dflow->problem->dump_insn_top_fun;
+         else
+           insnfun = dflow->problem->dump_insn_bottom_fun;
+
+         if (insnfun)
+           insnfun (insn, file);
        }
     }
 }
 
+/* Dump information about INSN before dumping INSN itself.  */
+
+void
+df_dump_insn_top (const rtx_insn *insn, FILE *file)
+{
+  df_dump_insn_problem_data (insn,  file, /*top=*/true);
+}
+
+/* Dump information about INSN after dumping INSN itself.  */
+
+void
+df_dump_insn_bottom (const rtx_insn *insn, FILE *file)
+{
+  df_dump_insn_problem_data (insn,  file, /*top=*/false);
+}
+
+
+static void
+df_ref_dump (df_ref ref, FILE *file)
+{
+  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),
+          DF_REF_REGNO (ref));
+}
 
 void
-df_refs_chain_dump (df_ref *ref_rec, bool follow_chain, FILE *file)
+df_refs_chain_dump (df_ref ref, bool follow_chain, FILE *file)
 {
   fprintf (file, "{ ");
-  while (*ref_rec)
+  for (; ref; ref = DF_REF_NEXT_LOC (ref))
     {
-      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),
-              DF_REF_REGNO (ref));
+      df_ref_dump (ref, file);
       if (follow_chain)
        df_chain_dump (DF_REF_CHAIN (ref), file);
-      ref_rec++;
     }
   fprintf (file, "}");
 }
@@ -2037,10 +2305,7 @@ df_regs_chain_dump (df_ref ref,  FILE *file)
   fprintf (file, "{ ");
   while (ref)
     {
-      fprintf (file, "%c%d(%d) ",
-              DF_REF_REG_DEF_P (ref) ? 'd' : 'u',
-              DF_REF_ID (ref),
-              DF_REF_REGNO (ref));
+      df_ref_dump (ref, file);
       ref = DF_REF_NEXT_REG (ref);
     }
   fprintf (file, "}");
@@ -2048,15 +2313,12 @@ df_regs_chain_dump (df_ref ref,  FILE *file)
 
 
 static void
-df_mws_dump (struct df_mw_hardreg **mws, FILE *file)
+df_mws_dump (struct df_mw_hardreg *mws, FILE *file)
 {
-  while (*mws)
-    {
-      fprintf (file, "mw %c r[%d..%d]\n",
-              (DF_MWS_REG_DEF_P (*mws)) ? 'd' : 'u',
-              (*mws)->start_regno, (*mws)->end_regno);
-      mws++;
-    }
+  for (; mws; mws = DF_MWS_NEXT (mws))
+    fprintf (file, "mw %c r[%d..%d]\n",
+            DF_MWS_REG_DEF_P (mws) ? 'd' : 'u',
+            mws->start_regno, mws->end_regno);
 }
 
 
@@ -2094,14 +2356,14 @@ df_insn_uid_debug (unsigned int uid,
 }
 
 
-void
-df_insn_debug (rtx insn, bool follow_chain, FILE *file)
+DEBUG_FUNCTION void
+df_insn_debug (rtx_insn *insn, bool follow_chain, FILE *file)
 {
   df_insn_uid_debug (INSN_UID (insn), follow_chain, file);
 }
 
-void
-df_insn_debug_regno (rtx insn, FILE *file)
+DEBUG_FUNCTION void
+df_insn_debug_regno (rtx_insn *insn, FILE *file)
 {
   struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
 
@@ -2118,7 +2380,7 @@ df_insn_debug_regno (rtx insn, FILE *file)
   fprintf (file, "\n");
 }
 
-void
+DEBUG_FUNCTION void
 df_regno_debug (unsigned int regno, FILE *file)
 {
   fprintf (file, "reg %d defs ", regno);
@@ -2131,7 +2393,7 @@ df_regno_debug (unsigned int regno, FILE *file)
 }
 
 
-void
+DEBUG_FUNCTION void
 df_ref_debug (df_ref ref, FILE *file)
 {
   fprintf (file, "%c%d ",
@@ -2159,50 +2421,50 @@ df_ref_debug (df_ref ref, FILE *file)
 \f
 /* Functions for debugging from GDB.  */
 
-void
-debug_df_insn (rtx insn)
+DEBUG_FUNCTION void
+debug_df_insn (rtx_insn *insn)
 {
   df_insn_debug (insn, true, stderr);
   debug_rtx (insn);
 }
 
 
-void
+DEBUG_FUNCTION void
 debug_df_reg (rtx reg)
 {
   df_regno_debug (REGNO (reg), stderr);
 }
 
 
-void
+DEBUG_FUNCTION void
 debug_df_regno (unsigned int regno)
 {
   df_regno_debug (regno, stderr);
 }
 
 
-void
+DEBUG_FUNCTION void
 debug_df_ref (df_ref ref)
 {
   df_ref_debug (ref, stderr);
 }
 
 
-void
+DEBUG_FUNCTION void
 debug_df_defno (unsigned int defno)
 {
   df_ref_debug (DF_DEFS_GET (defno), stderr);
 }
 
 
-void
+DEBUG_FUNCTION void
 debug_df_useno (unsigned int defno)
 {
   df_ref_debug (DF_USES_GET (defno), stderr);
 }
 
 
-void
+DEBUG_FUNCTION void
 debug_df_chain (struct df_link *link)
 {
   df_chain_dump (link, stderr);