This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[dataflow]: PATCH: Verification support


Add functions to support verification of existing reference information,
and refactor the existing insn scanning functions to be useable
for verification.

Seongbae

2006-10-28  Seongbae Park <seongbae.park@gmail.com>
       * df.h (df_rescan_blocks): Renamed to df_scan_blocks.
       * df-core.c (df_analyze): Use df_scan_blocks() instead.
       * ifcvt.c (if_convert): Use df_scan_blocks() instead.
       * df-scan.c
       (df_ref_record, df_def_record_1, df_defs_record, df_uses_record):
       They are made side-effect free.
       (df_ref_find_chains, df_ref_add_to_chains, df_refs_add_to_chains,
       df_ref_is_equal, df_ref_chain_find_ref, df_reg_chain_find_ref,
       df_scan_start_block, df_check_and_grow_ref_info,
       df_insn_refs_collect, df_bb_refs_collect,
       df_get_entry_block_defs, df_get_exit_block_uses,
       df_ref_verify, df_refs_verified, df_ref_chain_verify,
       df_reg_chain_clear_verified, df_bb_refs_verify,
       df_exit_block_verify, df_entry_block_verify, df_verify_blocks):
       New functions.
       (df_ref_create_structure): Initializes the fields
       of df_ref and does not connect it to various chains.
       (df_insn_refs_record, df_bb_refs_record, df_record_entry_block_defs,
        df_record_exit_block_uses, df_refs_record):
       Separate side-effects (adding chains and updating regs_ever_live)
       from traversing and finding the refs in the insn/basic block.
       (df_ref_create): Separate calls for creating the ref and add it
       to the chains.
Index: gcc/df-scan.c
===================================================================
--- gcc/df-scan.c	(revision 118108)
+++ gcc/df-scan.c	(working copy)
@@ -82,15 +82,21 @@
 /* Initialize ur_in and ur_out as if all hard registers were partially
    available.  */
 
-static void df_ref_record (struct dataflow *, rtx, rtx *, 
-			   basic_block, rtx, enum df_ref_type,
-			   enum df_ref_flags, bool record_live);
-static void df_def_record_1 (struct dataflow *, rtx, basic_block, rtx,
-			     enum df_ref_flags, bool record_live);
-static void df_defs_record (struct dataflow *, rtx, basic_block, rtx,
-			    enum df_ref_flags);
-static void df_uses_record (struct dataflow *, rtx *, enum df_ref_type,
-			    basic_block, rtx, enum df_ref_flags);
+static struct df_ref * df_ref_record (struct dataflow *, 
+                                      struct df_ref *,
+                                      rtx, rtx *, 
+			              basic_block, rtx, enum df_ref_type, 
+                                      enum df_ref_flags, bool record_live);
+static struct df_ref * df_def_record_1 (struct dataflow *, struct df_ref *,
+                                        rtx, basic_block, rtx,
+			                enum df_ref_flags, bool record_live);
+static struct df_ref * df_defs_record (struct dataflow *,
+                                       struct df_ref *,
+                                       rtx, basic_block, rtx,
+			               enum df_ref_flags);
+static struct df_ref * df_uses_record (struct dataflow *, struct df_ref *,
+                                       rtx *, enum df_ref_type,
+			               basic_block, rtx, enum df_ref_flags);
 
 static void df_bb_refs_record (struct dataflow *, basic_block);
 static void df_refs_record (struct dataflow *, bitmap);
@@ -103,6 +109,33 @@
 static void df_grow_ref_info (struct df_ref_info *, unsigned int);
 static void df_grow_insn_info (struct df *);
 
+/* A structure to hold multiple return values from df_ref_find_chains.  */
+struct df_chains
+{
+  struct df_ref **ref_chain;
+  struct df_reg_info *reg_info;
+  struct df_ref_info *ref_info;
+};
+
+static struct df_chains df_ref_find_chains (struct dataflow *,
+		    			    struct df_ref *);
+static void df_ref_add_to_chains (struct dataflow *, 
+                                  struct df_ref *,
+                                  struct df_mw_hardreg *);
+static void df_refs_add_to_chains (struct dataflow *, rtx insn, struct df_ref *);
+
+#define DEBUG_DF_RESCAN
+#ifdef DEBUG_DF_RESCAN
+typedef bool (*df_ref_compare_func_t)(struct df_ref *, struct df_ref *);
+static bool df_ref_is_equal (struct df_ref *, struct df_ref *);
+static struct df_ref *df_ref_chain_find_ref (struct df_ref *, 
+                                             struct df_ref *, 
+                                             df_ref_compare_func_t);
+static struct df_ref *df_reg_chain_find_ref (struct df_ref *, 
+                                             struct df_ref *,
+                                             df_ref_compare_func_t);
+#endif /* DEBUG_DF_RESCAN */
+
 
 /*----------------------------------------------------------------------------
    SCANNING DATAFLOW PROBLEM
@@ -302,6 +335,7 @@
   free (dflow);
 }
 
+/* Dump the preamble for DF_SCAN dump. */
 static void 
 df_scan_start_dump (struct dataflow *dflow ATTRIBUTE_UNUSED, FILE *file ATTRIBUTE_UNUSED)
 {
@@ -327,6 +361,23 @@
   fprintf (file, "\n");
 }
 
+/* Dump the bb_info for a given basic block. */
+static void 
+df_scan_start_block (struct dataflow *dflow, basic_block bb, FILE *file)
+{
+  struct df_scan_bb_info *bb_info
+    = df_scan_get_bb_info (dflow, bb->index);
+
+  if (bb_info)
+    {
+      fprintf (file, "bb %d artificial_defs: ", bb->index);
+      df_refs_chain_dump (bb_info->artificial_defs, true, file);
+      fprintf (file, "\nbb %d artificial_uses: ", bb->index);
+      df_refs_chain_dump (bb_info->artificial_uses, true, file);
+      fprintf (file, "\n");
+    }
+}
+
 static struct df_problem problem_SCAN =
 {
   DF_SCAN,                    /* Problem id.  */
@@ -343,7 +394,7 @@
   NULL,                       /* Finalize function.  */
   df_scan_free,               /* Free all of the problem information.  */
   df_scan_start_dump,         /* Debugging.  */
-  NULL,                       /* Debugging start block.  */
+  df_scan_start_block,        /* Debugging start block.  */
   NULL,                       /* Debugging end block.  */
   NULL                        /* Dependent problem.  */
 };
@@ -359,6 +410,7 @@
   return df_add_problem (df, &problem_SCAN);
 }
 
+
 /*----------------------------------------------------------------------------
    Storage Allocation Utilities
 ----------------------------------------------------------------------------*/
@@ -434,6 +486,23 @@
 }
 
 
+/* Check and grow the ref information if necessary.
+   This routine guarantees bitmap_size + bitmap_add 
+   amount of entries in refs array.
+   It updates ref_info->refs_size only
+   and does not change ref_info->bitmap_size.  */
+
+static void
+df_check_and_grow_ref_info (struct df_ref_info *ref_info, 
+			    unsigned bitmap_addend)
+{
+  if (ref_info->refs_size < ref_info->bitmap_size + bitmap_addend)
+    {
+      int new_size = ref_info->bitmap_size + ref_info->bitmap_size / 4;
+      df_grow_ref_info (ref_info, new_size);
+    }
+}
+
 /* Grow the ref information.  If the current size is less than the
    number of instructions, grow to 25% more than the number of
    instructions.  */
@@ -464,7 +533,7 @@
    df_set_blocks if BLOCKS is NULL);  */
 
 void
-df_rescan_blocks (struct df *df, bitmap blocks)
+df_scan_blocks (struct df *df, bitmap blocks)
 {
   bitmap local_blocks_to_scan = BITMAP_ALLOC (NULL);
 
@@ -560,6 +629,7 @@
     }
 
   df_refs_record (dflow, local_blocks_to_scan);
+
 #if 0
   bitmap_print (stderr, local_blocks_to_scan, "scanning: ", "\n");
 #endif
@@ -581,6 +651,7 @@
 	       enum df_ref_type ref_type, 
 	       enum df_ref_flags ref_flags)
 {
+  struct df_ref *ref;
   struct dataflow *dflow = df->problems_by_index[DF_SCAN];
   struct df_scan_bb_info *bb_info;
   
@@ -602,7 +673,10 @@
   else
     df->use_info.add_refs_inline = true;
   
-  return df_ref_create_structure (dflow, reg, loc, bb, insn, ref_type, ref_flags);
+  ref = df_ref_create_structure (dflow, reg, loc, bb, insn, ref_type, ref_flags);
+  df_ref_add_to_chains (dflow, ref, NULL);
+
+  return ref;
 }
 
 
@@ -913,6 +987,7 @@
 }
 
 
+
 /* Take build ref table for either the uses or defs from the reg-use
    or reg-def chains.  */ 
 
@@ -927,11 +1002,7 @@
   unsigned int offset = 0;
   unsigned int size = 0;
 
-  if (ref_info->refs_size < ref_info->bitmap_size)
-    {  
-      int new_size = ref_info->bitmap_size + ref_info->bitmap_size / 4;
-      df_grow_ref_info (ref_info, new_size);
-    }
+  df_check_and_grow_ref_info (ref_info, 0);
 
   for (regno = 0; regno < m; regno++)
     {
@@ -1005,14 +1076,255 @@
     df_reorganize_refs (df, &df->def_info, df->def_regs, NULL);
 }
 
+#ifdef DEBUG_DF_RESCAN
+
+
+
+/* Return true if the contents of two df_ref's are identical.  */
+
+static bool
+df_ref_is_equal (struct df_ref *ref1, struct df_ref *ref2)
+{
+  return (ref1 == ref2) ||
+    (DF_REF_REG (ref1) == DF_REF_REG (ref2)
+      && DF_REF_REGNO (ref1) == DF_REF_REGNO (ref2)
+      && DF_REF_LOC (ref1) == DF_REF_LOC (ref2)
+      && DF_REF_INSN (ref1) == DF_REF_INSN (ref2)
+      && DF_REF_TYPE (ref1) == DF_REF_TYPE (ref2)
+      && DF_REF_FLAGS (ref1) == DF_REF_FLAGS (ref2)
+      && DF_REF_BB (ref1) == DF_REF_BB (ref2));
+}
+
+/* Return true if two df_ref pointers are identical. */
+static bool
+df_ref_is_pointer_equal (struct df_ref *ref1, struct df_ref *ref2)
+{
+  return ref1 == ref2;
+}
+
+/* Find a matching df_ref in the ref chain */
+static struct df_ref *
+df_ref_chain_find_ref (struct df_ref *chain, 
+                       struct df_ref *this_ref,
+                       df_ref_compare_func_t func)
+{
+  while (chain) 
+    {
+      if (func (this_ref, chain))
+        return chain;
+      chain = chain->next_ref;
+    }
+
+  return NULL;
+}
+
+/* Find a matching df_ref in the ref chain */
+static struct df_ref *
+df_reg_chain_find_ref (struct df_ref *chain, 
+                       struct df_ref *this_ref, 
+                       df_ref_compare_func_t func)
+{
+  while (chain) 
+    {
+      if (func (this_ref, chain))
+        return chain;
+      chain = chain->next_reg;
+    }
+
+  return NULL;
+}
+#endif /* DEBUG_DF_RESCAN */
+
+
+/* Append a new ref ITEM to the end of existing ref chain LAST_ELEMENT. 
+   LAST_ELEMENT should point to the last element of the existing chain.  */
+
+static struct df_ref *
+df_ref_chain_append (struct df_ref *last_element, struct df_ref *item)
+{
+  last_element->next_ref = item;
+  return item;
+}
+
+/* A convenience macro for chain append.  */
+#define DF_REF_CHAIN_APPEND(last, item) (last = df_ref_chain_append ((last), (item)))
+
 
 /*----------------------------------------------------------------------------
    Hard core instruction scanning code.  No external interfaces here,
    just a lot of routines that look inside insns.
 ----------------------------------------------------------------------------*/
 
-/* Create a ref and add it to the reg-def or reg-use chains.  */
 
+/* Return the appropriate chains this_ref belongs to. */
+
+static struct df_chains
+df_ref_find_chains (struct dataflow *dflow,
+		    struct df_ref *this_ref)
+{
+  struct df_chains chains;
+
+  struct df *df = dflow->df;
+  enum df_ref_type ref_type = DF_REF_TYPE (this_ref);
+  int regno = DF_REF_REGNO (this_ref);
+  rtx insn = DF_REF_INSN (this_ref);
+  basic_block bb = DF_REF_BB (this_ref);
+  bool is_artificial = DF_REF_FLAGS (this_ref) & DF_REF_ARTIFICIAL;
+  bool is_eq_use = DF_REF_FLAGS (this_ref) & DF_REF_IN_NOTE;
+  struct df_scan_bb_info *bb_info
+      = df_scan_get_bb_info (dflow, bb->index);
+
+  /* Find the appropriate ref_chain/reg_info/ref_info 
+     that this ref belongs to. */
+  switch (ref_type) 
+    {
+    case DF_REF_REG_DEF:
+        chains.ref_chain = (is_artificial) 
+            ? & bb_info->artificial_defs 
+            : & DF_INSN_DEFS (df, insn);
+        chains.reg_info = DF_REG_DEF_GET (df, regno);
+        chains.ref_info = & df->def_info;
+        break;
+    case DF_REF_REG_MEM_LOAD:
+    case DF_REF_REG_MEM_STORE:
+    case DF_REF_REG_USE:
+        chains.ref_chain = (is_artificial) 
+            ? & bb_info->artificial_uses 
+            : (is_eq_use) 
+	    ? & DF_INSN_EQ_USES (df, insn)
+	    : & DF_INSN_USES (df, insn);
+        chains.reg_info = (is_eq_use) 
+	  ? DF_REG_EQ_USE_GET (df, regno)
+	  : DF_REG_USE_GET (df, regno);
+        chains.ref_info = & df->use_info;
+        break;
+    default:
+        gcc_unreachable ();
+    }
+
+  return chains;
+}
+
+
+/* Add the new df_ref to appropriate ref/reg_info/ref_info chains.  */
+
+static void
+df_ref_add_to_chains (struct dataflow *dflow,
+                      struct df_ref *this_ref,
+                      struct df_mw_hardreg *hardreg)
+{
+  struct df_chains chains = df_ref_find_chains (dflow, this_ref);
+
+  struct df_ref **ref_chain = chains.ref_chain;
+  struct df_reg_info *reg_info = chains.reg_info;
+  struct df_ref_info *ref_info = chains.ref_info;
+
+  unsigned int regno;
+
+  /* Add to the ref chain */
+  this_ref->next_ref = *ref_chain;
+  *ref_chain = this_ref;
+
+  /* Add the ref to the reg_{def,use} chain.  */
+  reg_info->n_refs++;
+  df_reg_chain_create (reg_info, this_ref);
+
+  /* Add this_ref to the df->{use,def}_info */
+  DF_REF_ID (this_ref) = ref_info->bitmap_size;
+  if (ref_info->add_refs_inline)
+    {
+      df_check_and_grow_ref_info (ref_info, 1);
+
+      /* Add the ref to the big array of defs.  */
+      ref_info->refs[ref_info->bitmap_size] = this_ref;
+      ref_info->refs_organized_alone = false;
+      ref_info->refs_organized_with_eq_uses = false;
+    }
+  ref_info->bitmap_size++;
+
+  /* Update regs_ever_live if necessary. */
+  regno = ORIGINAL_REGNO (DF_REF_REG (this_ref));
+  if (regno < FIRST_PSEUDO_REGISTER)
+    {
+      if (DF_REF_TYPE (this_ref) == DF_REF_REG_DEF 
+          && DF_REF_FLAGS_IS_SET (this_ref, DF_REF_RECORD_LIVE))
+        regs_ever_live[regno] = 1;
+      else if ((DF_REF_TYPE (this_ref) == DF_REF_REG_USE 
+               || DF_REF_TYPE (this_ref) == DF_REF_REG_MEM_STORE
+               || DF_REF_TYPE (this_ref) == DF_REF_REG_MEM_LOAD)
+               && !DF_REF_FLAGS_IS_SET (this_ref, DF_REF_ARTIFICIAL))
+        {
+          /* Set regs_ever_live on uses of non-eliminable frame
+             pointers and arg pointers.  */
+          if (!(TEST_HARD_REG_BIT (elim_reg_set, regno)
+                 && (regno == FRAME_POINTER_REGNUM 
+                     || regno == ARG_POINTER_REGNUM)))
+            regs_ever_live[regno] = 1;
+        }
+    }
+
+  /* mw_hardreg has to be added to the hardreg chain as well. */
+  if (DF_REF_INSN (this_ref) && DF_REF_FLAGS_IS_SET (this_ref, DF_REF_MW_HARDREG))
+    {
+      struct df_scan_problem_data *problem_data
+        = (struct df_scan_problem_data *) dflow->problem_data;
+      struct df_link *link = pool_alloc (problem_data->mw_link_pool);
+
+      gcc_assert (hardreg);
+
+      link->next = hardreg->regs;
+      link->ref = this_ref;
+      hardreg->regs = link;
+    }
+}
+
+
+/* Add a chain of df_refs to appropriate ref chain/reg_info/ref_info chains
+   and update other necessary information */
+
+static void
+df_refs_add_to_chains (struct dataflow *dflow,
+                       rtx insn,
+                       struct df_ref *ref)
+{
+  struct df *df = dflow->df;
+  struct df_mw_hardreg *hardreg = NULL;
+  struct df_scan_problem_data *problem_data
+    = (struct df_scan_problem_data *) dflow->problem_data;
+
+  while (ref)
+    {
+      struct df_ref *nref = ref->next_ref;
+
+      if (DF_REF_FLAGS_IS_SET (ref, DF_REF_MW_HARDREG_GROUP)) 
+        {
+          /* A beginning of a group of mw hardregs */
+          struct df_insn_info *insn_info = DF_INSN_GET (df, insn);
+
+          hardreg = pool_alloc (problem_data->mw_reg_pool);
+          hardreg->next = insn_info->mw_hardregs;
+          insn_info->mw_hardregs = hardreg;
+          hardreg->type = DF_REF_TYPE (ref);
+          hardreg->flags = DF_REF_FLAGS (ref) & ~DF_REF_MW_HARDREG_GROUP;
+          hardreg->mw_reg = DF_REF_REG (ref);
+          hardreg->regs = NULL;
+
+          /* MW_HARDREG_GROUP ref is just a placeholder, so free the memory. */
+          pool_free (problem_data->ref_pool, ref);
+        }
+      else 
+        {
+          ref->next_ref = NULL;
+          df_ref_add_to_chains (dflow, ref, hardreg);
+        }
+
+      ref = nref;
+    }
+}
+
+
+/* Allocate a ref and initialize its fields. */
+
 static struct df_ref *
 df_ref_create_structure (struct dataflow *dflow, rtx reg, rtx *loc,
 			 basic_block bb, rtx insn, 
@@ -1020,7 +1332,6 @@
 			 enum df_ref_flags ref_flags)
 {
   struct df_ref *this_ref;
-  struct df *df = dflow->df;
   int regno = REGNO (GET_CODE (reg) == SUBREG ? SUBREG_REG (reg) : reg);
   struct df_scan_problem_data *problem_data
     = (struct df_scan_problem_data *) dflow->problem_data;
@@ -1035,107 +1346,8 @@
   DF_REF_FLAGS (this_ref) = ref_flags;
   DF_REF_DATA (this_ref) = NULL;
   DF_REF_BB (this_ref) = bb;
+  DF_REF_NEXT_REF (this_ref) = NULL;
 
-  /* Link the ref into the reg_def and reg_use chains and keep a count
-     of the instances.  */
-  switch (ref_type)
-    {
-    case DF_REF_REG_DEF:
-      {
-	struct df_reg_info *reg_info = DF_REG_DEF_GET (df, regno);
-	reg_info->n_refs++;
-	
-	/* Add the ref to the reg_def chain.  */
-	df_reg_chain_create (reg_info, this_ref);
-
-	DF_REF_ID (this_ref) = DF_DEFS_SIZE (df);
-	if (df->def_info.add_refs_inline)
-	  {
-	    if (DF_DEFS_SIZE (df) >= df->def_info.refs_size)
-	      {
-		int new_size = DF_DEFS_SIZE (df) 
-		  + DF_DEFS_SIZE (df) / 4;
-		df_grow_ref_info (&df->def_info, new_size);
-	      }
-	    /* Add the ref to the big array of defs.  */
-	    DF_DEFS_SET (df, DF_DEFS_SIZE (df), this_ref);
-	    df->def_info.refs_organized_alone = false;
-	  }
-	
-	DF_DEFS_SIZE (df)++;
-	
-	if (DF_REF_FLAGS (this_ref) & DF_REF_ARTIFICIAL)
-	  {
-	    struct df_scan_bb_info *bb_info 
-	      = df_scan_get_bb_info (dflow, bb->index);
-	    this_ref->next_ref = bb_info->artificial_defs;
-	    bb_info->artificial_defs = this_ref;
-	  }
-	else
-	  {
-	    this_ref->next_ref = DF_INSN_DEFS (df, insn);
-	    DF_INSN_DEFS (df, insn) = this_ref;
-	  }
-      }
-      break;
-
-    case DF_REF_REG_MEM_LOAD:
-    case DF_REF_REG_MEM_STORE:
-    case DF_REF_REG_USE:
-      {
-	struct df_reg_info *reg_info;
-	if (DF_REF_FLAGS (this_ref) & DF_REF_IN_NOTE)
-	  reg_info = DF_REG_EQ_USE_GET (df, regno);
-	else
-	  reg_info = DF_REG_USE_GET (df, regno);
-
-	reg_info->n_refs++;
-	/* Add the ref to the reg_use chain.  */
-	df_reg_chain_create (reg_info, this_ref);
-
-	DF_REF_ID (this_ref) = DF_USES_SIZE (df);
-	if (df->use_info.add_refs_inline)
-	  {
-	    if (DF_USES_SIZE (df) >= df->use_info.refs_size)
-	      {
-		int new_size = DF_USES_SIZE (df) 
-		  + DF_USES_SIZE (df) / 4;
-		df_grow_ref_info (&df->use_info, new_size);
-	      }
-	    /* Add the ref to the big array of defs.  */
-	    DF_USES_SET (df, DF_USES_SIZE (df), this_ref);
-	    df->use_info.refs_organized_with_eq_uses = false;
-	    df->use_info.refs_organized_alone = false;
-	  }
-	
-	DF_USES_SIZE (df)++;
-	if (DF_REF_FLAGS (this_ref) & DF_REF_ARTIFICIAL)
-	  {
-	    struct df_scan_bb_info *bb_info 
-	      = df_scan_get_bb_info (dflow, bb->index);
-	    this_ref->next_ref = bb_info->artificial_uses;
-	    bb_info->artificial_uses = this_ref;
-	  }
-	else
-	  {
-	    if (DF_REF_FLAGS (this_ref) & DF_REF_IN_NOTE)
-	      {
-		this_ref->next_ref = DF_INSN_EQ_USES (df, insn);
-		DF_INSN_EQ_USES (df, insn) = this_ref;
-	      }
-	    else
-	      {
-		this_ref->next_ref = DF_INSN_USES (df, insn);
-		DF_INSN_USES (df, insn) = this_ref;
-	      }
-	  }
-      }
-      break;
-
-    default:
-      gcc_unreachable ();
-
-    }
   return this_ref;
 }
 
@@ -1143,27 +1355,29 @@
 /* Create new references of type DF_REF_TYPE for each part of register REG
    at address LOC within INSN of BB.  */
 
-static void
-df_ref_record (struct dataflow *dflow, rtx reg, rtx *loc, 
+static struct df_ref *
+df_ref_record (struct dataflow *dflow,
+               struct df_ref *insn_refs,
+               rtx reg, rtx *loc, 
 	       basic_block bb, rtx insn, 
 	       enum df_ref_type ref_type, 
 	       enum df_ref_flags ref_flags, 
 	       bool record_live)
 {
-  struct df *df = dflow->df;
   rtx oldreg = reg;
   unsigned int regno;
 
   gcc_assert (REG_P (reg) || GET_CODE (reg) == SUBREG);
 
+  if (record_live)
+    ref_flags |= DF_REF_RECORD_LIVE;
+
   regno = REGNO (GET_CODE (reg) == SUBREG ? SUBREG_REG (reg) : reg);
   if (regno < FIRST_PSEUDO_REGISTER)
     {
       unsigned int i;
       unsigned int endregno;
-      struct df_mw_hardreg *hardreg = NULL;
-      struct df_scan_problem_data *problem_data
-	= (struct df_scan_problem_data *) dflow->problem_data;
+      struct df_ref *ref;
 
       /* GET_MODE (reg) is correct here.  We do not want to go into a SUBREG
          for the mode, because we only want to add references to regs, which
@@ -1180,60 +1394,37 @@
 	  will enable us to easily build REG_DEAD and REG_UNUSED notes.  */
       if ((endregno != regno + 1) && insn)
 	{
-	  struct df_insn_info *insn_info = DF_INSN_GET (df, insn);
 	  /* Sets to a subreg of a multiword register are partial. 
 	     Sets to a non-subreg of a multiword register are not.  */
 	  if (GET_CODE (oldreg) == SUBREG)
 	    ref_flags |= DF_REF_PARTIAL;
 	  ref_flags |= DF_REF_MW_HARDREG;
-	  hardreg = pool_alloc (problem_data->mw_reg_pool);
-	  hardreg->next = insn_info->mw_hardregs;
-	  insn_info->mw_hardregs = hardreg;
-	  hardreg->type = ref_type;
-	  hardreg->flags = ref_flags;
-	  hardreg->mw_reg = reg;
-	  hardreg->regs = NULL;
 
+          /* This is a placeholder for grouping mw_hardreg sequence. */
+          ref = df_ref_create_structure (dflow, reg, loc,
+                                         bb, insn, ref_type, 
+                                         ref_flags | DF_REF_MW_HARDREG_GROUP);
+          DF_REF_REGNO (ref) = regno;
+          DF_REF_CHAIN_APPEND (insn_refs, ref);
 	}
 
       for (i = regno; i < endregno; i++)
 	{
-	  struct df_ref *ref;
-
-	  /* Calls are handled at call site because regs_ever_live
-	     doesn't include clobbered regs, only used ones.  */
-	  if (ref_type == DF_REF_REG_DEF && record_live)
-	    regs_ever_live[i] = 1;
-	  else if ((ref_type == DF_REF_REG_USE 
-		   || ref_type == DF_REF_REG_MEM_STORE
-		   || ref_type == DF_REF_REG_MEM_LOAD)
-		   && ((ref_flags & DF_REF_ARTIFICIAL) == 0))
-	    {
-	      /* Set regs_ever_live on uses of non-eliminable frame
-		 pointers and arg pointers.  */
-	      if (!(TEST_HARD_REG_BIT (elim_reg_set, regno)
-		     && (regno == FRAME_POINTER_REGNUM 
-			 || regno == ARG_POINTER_REGNUM)))
-		regs_ever_live[i] = 1;
-	    }
-
 	  ref = df_ref_create_structure (dflow, regno_reg_rtx[i], loc, 
 					 bb, insn, ref_type, ref_flags);
-	  if (hardreg)
-	    {
-	      struct df_link *link = pool_alloc (problem_data->mw_link_pool);
-
-	      link->next = hardreg->regs;
-	      link->ref = ref;
-	      hardreg->regs = link;
-	    }
+          gcc_assert ( ORIGINAL_REGNO (DF_REF_REG (ref)) == i);
+          DF_REF_CHAIN_APPEND (insn_refs, ref);
 	}
     }
   else
     {
-      df_ref_create_structure (dflow, reg, loc, 
-			       bb, insn, ref_type, ref_flags);
+      struct df_ref *ref;
+      ref = df_ref_create_structure (dflow, reg, loc, bb, insn, 
+                                     ref_type, ref_flags);
+      DF_REF_CHAIN_APPEND (insn_refs, ref);
     }
+
+  return insn_refs;
 }
 
 
@@ -1258,9 +1449,9 @@
    Autoincrement/decrement definitions will be picked up by
    df_uses_record.  */
 
-static void
-df_def_record_1 (struct dataflow *dflow, rtx x, 
-		 basic_block bb, rtx insn, 
+static struct df_ref *
+df_def_record_1 (struct dataflow *dflow, struct df_ref *insn_refs,
+                 rtx x, basic_block bb, rtx insn, 
 		 enum df_ref_flags flags, bool record_live)
 {
   rtx *loc;
@@ -1285,12 +1476,13 @@
 	  rtx temp = XVECEXP (dst, 0, i);
 	  if (GET_CODE (temp) == EXPR_LIST || GET_CODE (temp) == CLOBBER
 	      || GET_CODE (temp) == SET)
-	    df_def_record_1 (dflow, temp, bb, insn, 
+	    insn_refs = df_def_record_1 (dflow, insn_refs,
+                             temp, bb, insn, 
 			     GET_CODE (temp) == CLOBBER 
 			     ? flags | DF_REF_MUST_CLOBBER : flags, 
 			     record_live);
 	}
-      return;
+      return insn_refs;
     }
 
   /* Maybe, we should flag the use of STRICT_LOW_PART somehow.  It might
@@ -1325,30 +1517,34 @@
     
   if (REG_P (dst)
       || (GET_CODE (dst) == SUBREG && REG_P (SUBREG_REG (dst))))
-    df_ref_record (dflow, dst, loc, bb, insn, 
-		   DF_REF_REG_DEF, flags, record_live);
+    insn_refs = df_ref_record (dflow, insn_refs, 
+                   dst, loc, bb, insn, DF_REF_REG_DEF, flags, record_live);
+
+  return insn_refs;
 }
 
 
 /* Process all the registers defined in the pattern rtx, X.  */
 
-static void
-df_defs_record (struct dataflow *dflow, rtx x, basic_block bb, rtx insn,
-		enum df_ref_flags flags)
+static struct df_ref *
+df_defs_record (struct dataflow *dflow, struct df_ref *insn_refs, 
+                rtx x, basic_block bb, rtx insn, enum df_ref_flags flags)
 {
   RTX_CODE code = GET_CODE (x);
 
   if (code == SET || code == CLOBBER)
     {
       /* Mark the single def within the pattern.  */
-      df_def_record_1 (dflow, x, bb, insn, 
-		       code == CLOBBER ? DF_REF_MUST_CLOBBER | flags : flags, 
-		       true);
+      enum df_ref_flags clobber_flags = flags;
+      clobber_flags |= (code == CLOBBER) ? DF_REF_MUST_CLOBBER : 0;
+      insn_refs = df_def_record_1 (dflow, insn_refs, 
+                                   x, bb, insn, clobber_flags, true);
     }
   else if (code == COND_EXEC)
     {
-      df_defs_record  (dflow, COND_EXEC_CODE (x), bb, insn, 
-		       DF_REF_CONDITIONAL);
+      insn_refs = df_defs_record  (dflow, insn_refs, 
+                                   COND_EXEC_CODE (x), 
+                                   bb, insn, DF_REF_CONDITIONAL);
     }
   else if (code == PARALLEL)
     {
@@ -1356,16 +1552,20 @@
 
       /* Mark the multiple defs within the pattern.  */
       for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
-	 df_defs_record (dflow, XVECEXP (x, 0, i), bb, insn,
-			 flags);
+	 insn_refs = df_defs_record (dflow, insn_refs, 
+                                     XVECEXP (x, 0, i), 
+                                     bb, insn, flags);
     }
+
+  return insn_refs;
 }
 
 
 /* Process all the registers used in the rtx at address LOC.  */
 
-static void
-df_uses_record (struct dataflow *dflow, rtx *loc, enum df_ref_type ref_type,
+static struct df_ref *
+df_uses_record (struct dataflow *dflow, struct df_ref *insn_refs,
+                rtx *loc, enum df_ref_type ref_type,
 		basic_block bb, rtx insn, enum df_ref_flags flags)
 {
   RTX_CODE code;
@@ -1373,7 +1573,7 @@
  retry:
   x = *loc;
   if (!x)
-    return;
+    return insn_refs;
   code = GET_CODE (x);
   switch (code)
     {
@@ -1387,22 +1587,23 @@
     case CC0:
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
-      return;
+      return insn_refs;
 
     case CLOBBER:
       /* If we are clobbering a MEM, mark any registers inside the address
 	 as being used.  */
       if (MEM_P (XEXP (x, 0)))
-	df_uses_record (dflow, &XEXP (XEXP (x, 0), 0),
-			DF_REF_REG_MEM_STORE, bb, insn, flags);
+	insn_refs = df_uses_record (dflow, insn_refs,
+                                    &XEXP (XEXP (x, 0), 0),
+			            DF_REF_REG_MEM_STORE, bb, insn, flags);
 
       /* If we're clobbering a REG then we have a def so ignore.  */
-      return;
+      return insn_refs;
 
     case MEM:
-      df_uses_record (dflow, &XEXP (x, 0), DF_REF_REG_MEM_LOAD, bb, insn,
-		      flags & DF_REF_IN_NOTE);
-      return;
+      return df_uses_record (dflow, insn_refs,
+                             &XEXP (x, 0), DF_REF_REG_MEM_LOAD, 
+                             bb, insn, flags & DF_REF_IN_NOTE);
 
     case SUBREG:
       /* While we're here, optimize this case.  */
@@ -1411,29 +1612,32 @@
       if (!REG_P (SUBREG_REG (x)))
 	{
 	  loc = &SUBREG_REG (x);
-	  df_uses_record (dflow, loc, ref_type, bb, insn, flags);
-	  return;
+	  return df_uses_record (dflow, insn_refs, 
+                                 loc, ref_type, bb, insn, flags);
 	}
       /* ... Fall through ...  */
 
     case REG:
-      df_ref_record (dflow, x, loc, bb, insn, ref_type, flags, true);
-      return;
+      return df_ref_record (dflow, insn_refs, 
+                            x, loc, bb, insn, ref_type, flags, true);
 
     case SET:
       {
 	rtx dst = SET_DEST (x);
 	gcc_assert (!(flags & DF_REF_IN_NOTE));
-	df_uses_record (dflow, &SET_SRC (x), DF_REF_REG_USE, bb, insn, flags);
+	insn_refs = df_uses_record (dflow, insn_refs,
+                                    &SET_SRC (x), DF_REF_REG_USE, 
+                                    bb, insn, flags);
 
 	switch (GET_CODE (dst))
 	  {
 	    case SUBREG:
 	      if (df_read_modify_subreg_p (dst))
 		{
-		  df_uses_record (dflow, &SUBREG_REG (dst), 
-				  DF_REF_REG_USE, bb,
-				  insn, flags | DF_REF_READ_WRITE);
+		  insn_refs = df_uses_record (dflow, insn_refs,
+                                              &SUBREG_REG (dst), 
+				              DF_REF_REG_USE, bb, insn, 
+                                              flags | DF_REF_READ_WRITE);
 		  break;
 		}
 	      /* Fall through.  */
@@ -1444,9 +1648,10 @@
 	    case CC0:
 		break;
 	    case MEM:
-	      df_uses_record (dflow, &XEXP (dst, 0),
-			      DF_REF_REG_MEM_STORE,
-			      bb, insn, flags);
+	      insn_refs = df_uses_record (dflow, insn_refs, 
+                                          &XEXP (dst, 0),
+			                  DF_REF_REG_MEM_STORE,
+			                  bb, insn, flags);
 	      break;
 	    case STRICT_LOW_PART:
 	      {
@@ -1454,28 +1659,31 @@
 		/* A strict_low_part uses the whole REG and not just the
 		 SUBREG.  */
 		dst = XEXP (dst, 0);
-		df_uses_record (dflow, 
-				(GET_CODE (dst) == SUBREG) 
-				? &SUBREG_REG (dst) : temp, 
-				DF_REF_REG_USE, bb,
-				insn, DF_REF_READ_WRITE);
+		insn_refs = df_uses_record (dflow, insn_refs,
+				            (GET_CODE (dst) == SUBREG) 
+				             ? &SUBREG_REG (dst) : temp, 
+				            DF_REF_REG_USE, bb,
+				            insn, DF_REF_READ_WRITE);
 	      }
 	      break;
 	    case ZERO_EXTRACT:
 	    case SIGN_EXTRACT:
-	      df_uses_record (dflow, &XEXP (dst, 0), 
+	      insn_refs = df_uses_record (dflow, insn_refs,
+                              &XEXP (dst, 0), 
 			      DF_REF_REG_USE, bb, insn,
 			      DF_REF_READ_WRITE);
-	      df_uses_record (dflow, &XEXP (dst, 1), 
+	      insn_refs = df_uses_record (dflow, insn_refs,
+                              &XEXP (dst, 1), 
 			      DF_REF_REG_USE, bb, insn, flags);
-	      df_uses_record (dflow, &XEXP (dst, 2), 
+	      insn_refs = df_uses_record (dflow, insn_refs,
+                              &XEXP (dst, 2), 
 			      DF_REF_REG_USE, bb, insn, flags);
 	      dst = XEXP (dst, 0);
 	      break;
 	    default:
 	      gcc_unreachable ();
 	  }
-	return;
+	return insn_refs;
       }
 
     case RETURN:
@@ -1518,9 +1726,10 @@
 	    int j;
 
 	    for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
-	      df_uses_record (dflow, &ASM_OPERANDS_INPUT (x, j),
-			      DF_REF_REG_USE, bb, insn, flags);
-	    return;
+	      insn_refs = df_uses_record (dflow, insn_refs,
+                                          &ASM_OPERANDS_INPUT (x, j),
+			                  DF_REF_REG_USE, bb, insn, flags);
+	    return insn_refs;
 	  }
 	break;
       }
@@ -1533,8 +1742,9 @@
     case POST_MODIFY:
       /* Catch the def of the register being modified.  */
       flags |= DF_REF_READ_WRITE | DF_REF_PRE_POST_MODIFY;
-      df_ref_record (dflow, XEXP (x, 0), &XEXP (x, 0), bb, insn, 
-		     DF_REF_REG_DEF, flags, true);
+      insn_refs = df_ref_record (dflow, insn_refs,
+                                 XEXP (x, 0), &XEXP (x, 0), bb, insn, 
+		                 DF_REF_REG_DEF, flags, true);
 
       /* ... Fall through to handle uses ...  */
 
@@ -1557,17 +1767,21 @@
 		loc = &XEXP (x, 0);
 		goto retry;
 	      }
-	    df_uses_record (dflow, &XEXP (x, i), ref_type, bb, insn, flags);
+	    insn_refs = df_uses_record (dflow, insn_refs, 
+                                        &XEXP (x, i), ref_type, bb, insn, flags);
 	  }
 	else if (fmt[i] == 'E')
 	  {
 	    int j;
 	    for (j = 0; j < XVECLEN (x, i); j++)
-	      df_uses_record (dflow, &XVECEXP (x, i, j), ref_type,
-			      bb, insn, flags);
+	      insn_refs = df_uses_record (dflow, insn_refs,
+                                          &XVECEXP (x, i, j), ref_type,
+			                  bb, insn, flags);
 	  }
       }
   }
+
+  return insn_refs;
 }
 
 /* Return true if *LOC contains an asm.  */
@@ -1592,96 +1806,137 @@
 }
 
 
+/* Collect all refs in the INSN. 
+   This function is free of any side-effect - 
+   it will create and return a list of df_ref's (chained through next_ref) 
+   without putting those refs into existing ref chains and reg chains. */
 
-/* Record all the refs for DF within INSN of basic block BB.  */
-
-void
-df_insn_refs_record (struct dataflow *dflow, basic_block bb, rtx insn)
+static struct df_ref *
+df_insn_refs_collect (struct dataflow *dflow, basic_block bb, rtx insn) 
 {
-  struct df *df = dflow->df;
-  int i;
+  struct df_ref dummy;
+  struct df_ref *insn_refs = &dummy;
+  rtx note;
+  unsigned int i;
 
-  if (INSN_P (insn))
+  DF_REF_NEXT_REF (insn_refs) = NULL;
+  
+  /* Record register defs.  */
+  insn_refs = df_defs_record (dflow, insn_refs, PATTERN (insn), bb, insn, 0);
+
+  /* Process REG_EQUIV/REG_EQUAL notes */
+  for (note = REG_NOTES (insn); note;
+       note = XEXP (note, 1))
     {
+      switch (REG_NOTE_KIND (note))
+        {
+        case REG_EQUIV:
+        case REG_EQUAL:
+          insn_refs = df_uses_record (dflow, insn_refs,
+                                      &XEXP (note, 0), DF_REF_REG_USE,
+                                      bb, insn, DF_REF_IN_NOTE);
+        default:
+          break;
+        }
+    }
+
+  if (CALL_P (insn))
+    {
       rtx note;
+      bitmap_iterator bi;
+      unsigned int ui;
 
-      if (df_insn_contains_asm (insn))
-	DF_INSN_CONTAINS_ASM (df, insn) = true;
-      
-      /* Record register defs.  */
-      df_defs_record (dflow, PATTERN (insn), bb, insn, 0);
+      /* Record the registers used to pass arguments, and explicitly
+         noted as clobbered.  */
+      for (note = CALL_INSN_FUNCTION_USAGE (insn); note;
+           note = XEXP (note, 1))
+        {
+          if (GET_CODE (XEXP (note, 0)) == USE)
+            insn_refs = df_uses_record (dflow, insn_refs,
+                                        &XEXP (XEXP (note, 0), 0),
+                                        DF_REF_REG_USE,
+                                        bb, insn, 0);
+          else if (GET_CODE (XEXP (note, 0)) == CLOBBER)
+            insn_refs = df_defs_record (dflow, insn_refs,
+                                        XEXP (note, 0), bb, insn, 0);
+        }
 
-      for (note = REG_NOTES (insn); note;
-	   note = XEXP (note, 1))
-	{
-	  switch (REG_NOTE_KIND (note))
-	    {
-	    case REG_EQUIV:
-	    case REG_EQUAL:
-	      df_uses_record (dflow, &XEXP (note, 0), DF_REF_REG_USE,
-			      bb, insn, DF_REF_IN_NOTE);
-	    default:
-	      break;
-	    }
-	}
+      /* The stack ptr is used (honorarily) by a CALL insn.  */
+      insn_refs = df_uses_record (dflow, insn_refs,
+                                  &regno_reg_rtx[STACK_POINTER_REGNUM],
+                                  DF_REF_REG_USE, bb, insn, 
+                                  DF_REF_CALL_STACK_USAGE);
 
-      if (CALL_P (insn))
-	{
-	  rtx note;
-	  bitmap_iterator bi;
-	  unsigned int ui;
+      /* Calls may also reference any of the global registers,
+         so they are recorded as used.  */
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+        if (global_regs[i])
+          insn_refs = df_uses_record (dflow, insn_refs,
+                                      &regno_reg_rtx[i],
+                                      DF_REF_REG_USE, bb, insn, 0);
+      EXECUTE_IF_SET_IN_BITMAP (df_invalidated_by_call, 0, ui, bi)
+        insn_refs = df_ref_record (dflow, insn_refs,
+                                   regno_reg_rtx[ui], &regno_reg_rtx[ui], 
+                                   bb, insn, DF_REF_REG_DEF, 
+                                   DF_REF_MAY_CLOBBER, false);
+    }
 
-	  /* Record the registers used to pass arguments, and explicitly
-	     noted as clobbered.  */
-	  for (note = CALL_INSN_FUNCTION_USAGE (insn); note;
-	       note = XEXP (note, 1))
-	    {
-	      if (GET_CODE (XEXP (note, 0)) == USE)
-		df_uses_record (dflow, &XEXP (XEXP (note, 0), 0), 
-				DF_REF_REG_USE,
-				bb, insn, 0);
-              else if (GET_CODE (XEXP (note, 0)) == CLOBBER)
-		{
-		  df_defs_record (dflow, XEXP (note, 0), bb, insn, 0);
-		  if (REG_P (XEXP (XEXP (note, 0), 0)))
-		    {
-		      rtx reg = XEXP (XEXP (note, 0), 0);
-		      int regno_last;
-		      int regno_first;
-		      int i;
-		
-		      regno_last = regno_first = REGNO (reg);
-		      if (regno_first < FIRST_PSEUDO_REGISTER)
-			regno_last 
-			  += hard_regno_nregs[regno_first][GET_MODE (reg)] - 1;
-		      for (i = regno_first; i <= regno_last; i++)
-			regs_ever_live[i] = 1;
-		    }
-		}
-	    }
+  /* Record the register uses.  */
+  insn_refs = df_uses_record (dflow, insn_refs,
+                              &PATTERN (insn), DF_REF_REG_USE, bb, insn, 0);
 
-	  /* The stack ptr is used (honorarily) by a CALL insn.  */
-	  df_uses_record (dflow, &regno_reg_rtx[STACK_POINTER_REGNUM],
-			  DF_REF_REG_USE, bb, insn, 
-			  DF_REF_CALL_STACK_USAGE);
+  return DF_REF_NEXT_REF (&dummy);
+}
 
-	  /* Calls may also reference any of the global registers,
-	     so they are recorded as used.  */
-	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-	    if (global_regs[i])
-	      df_uses_record (dflow, &regno_reg_rtx[i],
-			      DF_REF_REG_USE, bb, insn, 
-			      0);
-	  EXECUTE_IF_SET_IN_BITMAP (df_invalidated_by_call, 0, ui, bi)
-	    df_ref_record (dflow, regno_reg_rtx[ui], &regno_reg_rtx[ui], bb, 
-			   insn, DF_REF_REG_DEF, DF_REF_MAY_CLOBBER, false);
-	}
 
-      /* Record the register uses.  */
-      df_uses_record (dflow, &PATTERN (insn),
-		      DF_REF_REG_USE, bb, insn, 0);
+/* Record all the refs for DF within INSN of basic block BB.  */
 
+void
+df_insn_refs_record (struct dataflow *dflow, basic_block bb, rtx insn)
+{
+  struct df *df = dflow->df;
+  struct df_ref *insn_refs;
+
+  if (!INSN_P (insn))
+    return;
+
+  /* Collect all the refs in the insn */
+  insn_refs = df_insn_refs_collect (dflow, bb, insn);
+
+  /* Process the collected insn_refs chain here */
+  if (insn_refs)
+    df_refs_add_to_chains (dflow, insn, insn_refs);
+
+  /* Update reg_ever_live for call insn */
+  if (CALL_P (insn))
+    {
+      rtx note;
+
+      /* Record the registers used to pass arguments, and explicitly
+         noted as clobbered.  */
+      for (note = CALL_INSN_FUNCTION_USAGE (insn); note;
+           note = XEXP (note, 1))
+        {
+          rtx exp0 = XEXP (note, 0);
+          if (GET_CODE (exp0) == CLOBBER && REG_P (XEXP (exp0, 0)))
+            {
+              int regno_last;
+              int regno_first;
+              int i;
+              rtx reg = XEXP (exp0, 0);
+        
+              regno_last = regno_first = REGNO (reg);
+              if (regno_first < FIRST_PSEUDO_REGISTER)
+                regno_last 
+                  += hard_regno_nregs[regno_first][GET_MODE (reg)] - 1;
+              for (i = regno_first; i <= regno_last; i++)
+                regs_ever_live[i] = 1;
+            }
+        }
     }
+
+  if (df_insn_contains_asm (insn))
+    DF_INSN_CONTAINS_ASM (df, insn) = true;
 }
 
 
@@ -1721,39 +1976,18 @@
     }
 }
 
+/* Collect all artificial refs at the block level
+   and return them as a newly created ref chain.  */
 
-/* Record all the refs within the basic block BB.  */
-
-static void
-df_bb_refs_record (struct dataflow *dflow, basic_block bb)
+static struct df_ref *
+df_bb_refs_collect (struct dataflow *dflow, basic_block bb)
 {
   struct df *df = dflow->df;
-  rtx insn;
-  int luid = 0;
-  struct df_scan_bb_info *bb_info = df_scan_get_bb_info (dflow, bb->index);
+  struct df_ref dummy;
+  struct df_ref *bb_refs = &dummy;
 
-  /* Need to make sure that there is a record in the basic block info. */  
-  if (!bb_info)
-    {
-      bb_info = (struct df_scan_bb_info *) pool_alloc (dflow->block_pool);
-      df_scan_set_bb_info (dflow, bb->index, bb_info);
-      bb_info->artificial_defs = NULL;
-      bb_info->artificial_uses = NULL;
-    }
+  DF_REF_NEXT_REF (bb_refs) = NULL;
 
-  /* Scan the block an insn at a time from beginning to end.  */
-  FOR_BB_INSNS (bb, insn)
-    {
-      df_insn_create_insn_record (dflow, insn);
-      if (INSN_P (insn))
-	{
-	  /* Record defs within INSN.  */
-	  DF_INSN_LUID (df, insn) = luid++;
-	  df_insn_refs_record (dflow, bb, insn);
-	}
-      DF_INSN_LUID (df, insn) = luid;
-    }
-
 #ifdef EH_RETURN_DATA_REGNO
   if (df_has_eh_preds (bb))
     {
@@ -1764,10 +1998,11 @@
 	  unsigned regno = EH_RETURN_DATA_REGNO (i);
 	  if (regno == INVALID_REGNUM)
 	    break;
-	  df_ref_record (dflow, regno_reg_rtx[regno], &regno_reg_rtx[regno],
-			 bb, NULL,
-			 DF_REF_REG_DEF, DF_REF_ARTIFICIAL | DF_REF_AT_TOP,
-			 false);
+	  bb_refs = df_ref_record (dflow, bb_refs,
+                                   regno_reg_rtx[regno], &regno_reg_rtx[regno],
+			           bb, NULL,
+			           DF_REF_REG_DEF, DF_REF_ARTIFICIAL | DF_REF_AT_TOP,
+			           false);
 	}
     }
 #endif
@@ -1790,9 +2025,10 @@
          eh-receiver for all of the edges at once. */
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	if (EH_USES (i))
-	  df_uses_record (dflow, &regno_reg_rtx[i], 
-			  DF_REF_REG_USE, bb, NULL,
-			  DF_REF_ARTIFICIAL | DF_REF_AT_TOP);
+	  bb_refs = df_uses_record (dflow, bb_refs,
+                                    &regno_reg_rtx[i], 
+			            DF_REF_REG_USE, bb, NULL,
+			            DF_REF_ARTIFICIAL | DF_REF_AT_TOP);
     }
 #endif
 
@@ -1806,44 +2042,66 @@
 
       EXECUTE_IF_SET_IN_BITMAP (au, 0, regno, bi)
 	{
-	  df_uses_record (dflow, &regno_reg_rtx[regno],
-			  DF_REF_REG_USE, bb, NULL, DF_REF_ARTIFICIAL);
+	  bb_refs = df_uses_record (dflow, bb_refs,
+                                    &regno_reg_rtx[regno],
+                                    DF_REF_REG_USE, bb, NULL,
+                                    DF_REF_ARTIFICIAL);
 	}
     }
+
+  return DF_REF_NEXT_REF (&dummy);
 }
 
 
-/* Record all the refs in the basic blocks specified by BLOCKS.  */
+/* Record all the refs within the basic block BB.  */
 
 static void
-df_refs_record (struct dataflow *dflow, bitmap blocks)
+df_bb_refs_record (struct dataflow *dflow, basic_block bb)
 {
-  unsigned int bb_index;
-  bitmap_iterator bi;
   struct df *df = dflow->df;
+  rtx insn;
+  int luid = 0;
+  struct df_scan_bb_info *bb_info = df_scan_get_bb_info (dflow, bb->index);
+  struct df_ref *bb_refs;
 
-  bitmap_clear (df->regular_block_artificial_uses);
-  bitmap_clear (df->eh_block_artificial_uses);
+  /* Need to make sure that there is a record in the basic block info. */  
+  if (!bb_info)
+    {
+      bb_info = (struct df_scan_bb_info *) pool_alloc (dflow->block_pool);
+      df_scan_set_bb_info (dflow, bb->index, bb_info);
+      bb_info->artificial_defs = NULL;
+      bb_info->artificial_uses = NULL;
+    }
 
-  /* The following code (down thru the arg_pointer seting APPEARS
-     to be necessary because there is nothing that actually
-     describes what the exception handling code may actually need
-     to keep alive.  */
-  if (reload_completed)
+  /* Scan the block an insn at a time from beginning to end.  */
+  FOR_BB_INSNS (bb, insn)
     {
-      if (frame_pointer_needed)
+      df_insn_create_insn_record (dflow, insn);
+      if (INSN_P (insn))
 	{
-	  bitmap_set_bit (df->eh_block_artificial_uses, FRAME_POINTER_REGNUM);
-#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-	  bitmap_set_bit (df->eh_block_artificial_uses, HARD_FRAME_POINTER_REGNUM);
-#endif
+	  /* Record refs within INSN.  */
+	  DF_INSN_LUID (df, insn) = luid++;
+	  df_insn_refs_record (dflow, bb, insn);
 	}
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-      if (fixed_regs[ARG_POINTER_REGNUM])
-	bitmap_set_bit (df->eh_block_artificial_uses, ARG_POINTER_REGNUM);
-#endif
+      DF_INSN_LUID (df, insn) = luid;
     }
-  
+
+  /* Other block level artificial refs */
+  bb_refs = df_bb_refs_collect (dflow, bb);
+
+  if (bb_refs)
+    df_refs_add_to_chains (dflow, NULL, bb_refs);
+}
+
+
+/* Get the artificial use set for 
+   a regular (i.e. non-exit/non-entry) block. */
+
+static void
+df_get_regular_block_artificial_uses (bitmap regular_block_artificial_uses)
+{
+  bitmap_clear (regular_block_artificial_uses);
+
   /* Before reload, there are a few registers that must be forced
      live everywhere -- which might not already be the case for
      blocks within infinite loops.  */
@@ -1851,33 +2109,77 @@
     {
       /* Any reference to any pseudo before reload is a potential
 	 reference of the frame pointer.  */
-      bitmap_set_bit (df->regular_block_artificial_uses, FRAME_POINTER_REGNUM);
+      bitmap_set_bit (regular_block_artificial_uses, FRAME_POINTER_REGNUM);
       
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
       /* Pseudos with argument area equivalences may require
 	 reloading via the argument pointer.  */
       if (fixed_regs[ARG_POINTER_REGNUM])
-	bitmap_set_bit (df->regular_block_artificial_uses, ARG_POINTER_REGNUM);
+	bitmap_set_bit (regular_block_artificial_uses, ARG_POINTER_REGNUM);
 #endif
       
       /* Any constant, or pseudo with constant equivalences, may
 	 require reloading from memory using the pic register.  */
       if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
 	  && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
-	bitmap_set_bit (df->regular_block_artificial_uses, PIC_OFFSET_TABLE_REGNUM);
+	bitmap_set_bit (regular_block_artificial_uses, PIC_OFFSET_TABLE_REGNUM);
     }
   /* The all-important stack pointer must always be live.  */
-  bitmap_set_bit (df->regular_block_artificial_uses, STACK_POINTER_REGNUM);
+  bitmap_set_bit (regular_block_artificial_uses, STACK_POINTER_REGNUM);
+}
 
+
+/* Get the artificial use set for an eh block. */
+
+static void
+df_get_eh_block_artificial_uses (bitmap eh_block_artificial_uses)
+{
+  bitmap_clear (eh_block_artificial_uses);
+
+  /* The following code (down thru the arg_pointer seting APPEARS
+     to be necessary because there is nothing that actually
+     describes what the exception handling code may actually need
+     to keep alive.  */
+  if (reload_completed)
+    {
+      if (frame_pointer_needed)
+	{
+	  bitmap_set_bit (eh_block_artificial_uses, FRAME_POINTER_REGNUM);
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+	  bitmap_set_bit (eh_block_artificial_uses, HARD_FRAME_POINTER_REGNUM);
+#endif
+	}
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+      if (fixed_regs[ARG_POINTER_REGNUM])
+	bitmap_set_bit (eh_block_artificial_uses, ARG_POINTER_REGNUM);
+#endif
+    }
+}
+
+
+/* Record all the refs in the basic blocks specified by BLOCKS.  */
+
+static void
+df_refs_record (struct dataflow *dflow, bitmap blocks)
+{
+  unsigned int bb_index;
+  bitmap_iterator bi;
+  struct df *df = dflow->df;
+
+  df_get_regular_block_artificial_uses (df->regular_block_artificial_uses);
+  df_get_eh_block_artificial_uses (df->eh_block_artificial_uses);
+
   bitmap_ior_into (df->eh_block_artificial_uses, 
 		   df->regular_block_artificial_uses);
 
+  /* Regular blocks */
   EXECUTE_IF_SET_IN_BITMAP (blocks, 0, bb_index, bi)
     {
       basic_block bb = BASIC_BLOCK (bb_index);
       df_bb_refs_record (dflow, bb);
     }
 
+  /* ENTRY and EXIT blocks have special defs/uses.  */
   if (bitmap_bit_p (blocks, EXIT_BLOCK))
     df_record_exit_block_uses (dflow);
 
@@ -1886,10 +2188,12 @@
 }
 
 
+
 /*----------------------------------------------------------------------------
    Specialized hard register scanning functions.
 ----------------------------------------------------------------------------*/
 
+
 /* Mark a register in SET.  Hard registers in large modes get all
    of their component registers set as well.  */
 
@@ -1911,26 +2215,23 @@
 }
 
 
-/* Record the (conservative) set of hard registers that are defined on
-   entry to the function.  */
+/* Set the bit for regs that are considered being defined at the entry. */
 
 static void
-df_record_entry_block_defs (struct dataflow *dflow)
+df_get_entry_block_defs (bitmap entry_block_defs)
 {
-  unsigned int i; 
-  bitmap_iterator bi;
   rtx r;
-  struct df *df = dflow->df;
+  int i;
 
-  bitmap_clear (df->entry_block_defs);
+  bitmap_clear (entry_block_defs);
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
       if (FUNCTION_ARG_REGNO_P (i))
 #ifdef INCOMING_REGNO
-	bitmap_set_bit (df->entry_block_defs, INCOMING_REGNO (i));
+	bitmap_set_bit (entry_block_defs, INCOMING_REGNO (i));
 #else
-	bitmap_set_bit (df->entry_block_defs, i);
+	bitmap_set_bit (entry_block_defs, i);
 #endif
     }
       
@@ -1942,43 +2243,43 @@
 	 pushes have some defining location.  */
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	if ((call_used_regs[i] == 0) && (regs_ever_live[i]))
-	  bitmap_set_bit (df->entry_block_defs, i);
+	  bitmap_set_bit (entry_block_defs, i);
     }
   else
     {
       /* The always important stack pointer.  */
-      bitmap_set_bit (df->entry_block_defs, STACK_POINTER_REGNUM);
+      bitmap_set_bit (entry_block_defs, STACK_POINTER_REGNUM);
 
 #ifdef INCOMING_RETURN_ADDR_RTX
       if (REG_P (INCOMING_RETURN_ADDR_RTX))
-	bitmap_set_bit (df->entry_block_defs, REGNO (INCOMING_RETURN_ADDR_RTX));
+	bitmap_set_bit (entry_block_defs, REGNO (INCOMING_RETURN_ADDR_RTX));
 #endif
             
       /* If STATIC_CHAIN_INCOMING_REGNUM == STATIC_CHAIN_REGNUM
 	 only STATIC_CHAIN_REGNUM is defined.  If they are different,
 	 we only care about the STATIC_CHAIN_INCOMING_REGNUM.  */
 #ifdef STATIC_CHAIN_INCOMING_REGNUM
-      bitmap_set_bit (df->entry_block_defs, STATIC_CHAIN_INCOMING_REGNUM);
+      bitmap_set_bit (entry_block_defs, STATIC_CHAIN_INCOMING_REGNUM);
 #else 
 #ifdef STATIC_CHAIN_REGNUM
-      bitmap_set_bit (df->entry_block_defs, STATIC_CHAIN_REGNUM);
+      bitmap_set_bit (entry_block_defs, STATIC_CHAIN_REGNUM);
 #endif
 #endif
       
       r = TARGET_STRUCT_VALUE_RTX (current_function_decl, true);
       if (r && REG_P (r))
-	bitmap_set_bit (df->entry_block_defs, REGNO (r));
+	bitmap_set_bit (entry_block_defs, REGNO (r));
     }
 
   if ((!reload_completed) || frame_pointer_needed)
     {
       /* Any reference to any pseudo before reload is a potential
 	 reference of the frame pointer.  */
-      bitmap_set_bit (df->entry_block_defs, FRAME_POINTER_REGNUM);
+      bitmap_set_bit (entry_block_defs, FRAME_POINTER_REGNUM);
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
       /* If they are different, also mark the hard frame pointer as live.  */
       if (!LOCAL_REGNO (HARD_FRAME_POINTER_REGNUM))
-	bitmap_set_bit (df->entry_block_defs, HARD_FRAME_POINTER_REGNUM);
+	bitmap_set_bit (entry_block_defs, HARD_FRAME_POINTER_REGNUM);
 #endif
     }
 
@@ -1991,7 +2292,7 @@
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	if (EH_USES (i))
 	  {
-	    bitmap_set_bit (df->entry_block_defs, i);
+	    bitmap_set_bit (entry_block_defs, i);
 	  }
 #endif
       
@@ -1999,7 +2300,7 @@
       /* Pseudos with argument area equivalences may require
 	 reloading via the argument pointer.  */
       if (fixed_regs[ARG_POINTER_REGNUM])
-	bitmap_set_bit (df->entry_block_defs, ARG_POINTER_REGNUM);
+	bitmap_set_bit (entry_block_defs, ARG_POINTER_REGNUM);
 #endif
 	  
 #ifdef PIC_OFFSET_TABLE_REGNUM
@@ -2007,31 +2308,51 @@
 	 require reloading from memory using the pic register.  */
       if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
 	  && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
-	bitmap_set_bit (df->entry_block_defs, PIC_OFFSET_TABLE_REGNUM);
+	bitmap_set_bit (entry_block_defs, PIC_OFFSET_TABLE_REGNUM);
 #endif
     }
 
-  targetm.live_on_entry (df->entry_block_defs);
+  targetm.live_on_entry (entry_block_defs);
+}
 
+
+/* Record the (conservative) set of hard registers that are defined on
+   entry to the function.  */
+
+static void
+df_record_entry_block_defs (struct dataflow *dflow)
+{
+  unsigned int i; 
+  bitmap_iterator bi;
+  struct df *df = dflow->df;
+  struct df_ref dummy;
+  struct df_ref *bb_refs = &dummy;
+
+  DF_REF_NEXT_REF (bb_refs) = NULL;
+
+  df_get_entry_block_defs (df->entry_block_defs);
+
   EXECUTE_IF_SET_IN_BITMAP (df->entry_block_defs, 0, i, bi)
     {
-      df_ref_record (dflow, regno_reg_rtx[i], &regno_reg_rtx[i], 
-		     ENTRY_BLOCK_PTR, NULL, 
-		     DF_REF_REG_DEF, DF_REF_ARTIFICIAL , false);
+      bb_refs = df_ref_record (dflow, bb_refs, 
+                               regno_reg_rtx[i], &regno_reg_rtx[i], 
+                               ENTRY_BLOCK_PTR, NULL, 
+                               DF_REF_REG_DEF, DF_REF_ARTIFICIAL , false);
     }
+
+  /* Process bb_refs chain */
+  df_refs_add_to_chains (dflow, NULL, DF_REF_NEXT_REF (&dummy));
 }
 
 
-/* Record the set of hard registers that are used in the exit block.  */
+/* Set the bit for regs that are considered being used at the exit. */
 
 static void
-df_record_exit_block_uses (struct dataflow *dflow)
+df_get_exit_block_uses (bitmap exit_block_uses)
 {
   unsigned int i; 
-  bitmap_iterator bi;
-  struct df *df = dflow->df;
 
-  bitmap_clear (df->exit_block_uses);
+  bitmap_clear (exit_block_uses);
   
   /* If exiting needs the right stack value, consider the stack
      pointer live at the end of the function.  */
@@ -2042,7 +2363,7 @@
 	  && flag_omit_frame_pointer)
       || current_function_sp_is_unchanging)
     {
-      bitmap_set_bit (df->exit_block_uses, STACK_POINTER_REGNUM);
+      bitmap_set_bit (exit_block_uses, STACK_POINTER_REGNUM);
     }
   
   /* Mark the frame pointer if needed at the end of the function.
@@ -2051,24 +2372,14 @@
   
   if ((!reload_completed) || frame_pointer_needed)
     {
-      bitmap_set_bit (df->exit_block_uses, FRAME_POINTER_REGNUM);
+      bitmap_set_bit (exit_block_uses, FRAME_POINTER_REGNUM);
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
       /* If they are different, also mark the hard frame pointer as live.  */
       if (!LOCAL_REGNO (HARD_FRAME_POINTER_REGNUM))
-	bitmap_set_bit (df->exit_block_uses, HARD_FRAME_POINTER_REGNUM);
+	bitmap_set_bit (exit_block_uses, HARD_FRAME_POINTER_REGNUM);
 #endif
     }
 
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-  /* It is deliberate that this is not put in the exit block uses but
-     I do not know why.  */
-  if (reload_completed 
-      && df_has_eh_preds (EXIT_BLOCK_PTR)
-      && fixed_regs[ARG_POINTER_REGNUM])
-    df_uses_record (dflow, &regno_reg_rtx[ARG_POINTER_REGNUM], 
-		    DF_REF_REG_USE, EXIT_BLOCK_PTR, NULL,
-		    DF_REF_ARTIFICIAL);
-#endif
 
 
 #ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
@@ -2077,7 +2388,7 @@
      other means, if it is not fixed.  */
   if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
       && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
-    bitmap_set_bit (df->exit_block_uses, PIC_OFFSET_TABLE_REGNUM);
+    bitmap_set_bit (exit_block_uses, PIC_OFFSET_TABLE_REGNUM);
 #endif
   
   /* Mark all global registers, and all registers used by the
@@ -2085,7 +2396,7 @@
      may be referenced by our caller.  */
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (global_regs[i] || EPILOGUE_USES (i))
-      bitmap_set_bit (df->exit_block_uses, i);
+      bitmap_set_bit (exit_block_uses, i);
   
   if (HAVE_epilogue && epilogue_completed)
     {
@@ -2093,7 +2404,7 @@
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	if (regs_ever_live[i] && !LOCAL_REGNO (i)
 	    && !TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
-	  bitmap_set_bit (df->exit_block_uses, i);
+	  bitmap_set_bit (exit_block_uses, i);
     }
   
 #ifdef EH_RETURN_DATA_REGNO
@@ -2104,7 +2415,7 @@
 	unsigned regno = EH_RETURN_DATA_REGNO (i);
 	if (regno == INVALID_REGNUM)
 	  break;
-	bitmap_set_bit (df->exit_block_uses, regno);
+	bitmap_set_bit (exit_block_uses, regno);
       }
 #endif
 
@@ -2114,7 +2425,7 @@
     {
       rtx tmp = EH_RETURN_STACKADJ_RTX;
       if (tmp && REG_P (tmp))
-	df_mark_reg (tmp, df->exit_block_uses);
+	df_mark_reg (tmp, exit_block_uses);
     }
 #endif
 
@@ -2124,21 +2435,53 @@
     {
       rtx tmp = EH_RETURN_HANDLER_RTX;
       if (tmp && REG_P (tmp))
-	df_mark_reg (tmp, df->exit_block_uses);
+	df_mark_reg (tmp, exit_block_uses);
     }
 #endif 
   
   /* Mark function return value.  */
-  diddle_return_value (df_mark_reg, (void*) df->exit_block_uses);
+  diddle_return_value (df_mark_reg, (void*) exit_block_uses);
+}
 
+
+/* Record the set of hard registers that are used in the exit block.  */
+
+static void
+df_record_exit_block_uses (struct dataflow *dflow)
+{
+  unsigned int i; 
+  bitmap_iterator bi;
+  struct df *df = dflow->df;
+  struct df_ref dummy;
+  struct df_ref *bb_refs = &dummy;
+  DF_REF_NEXT_REF (bb_refs) = NULL;
+
+  df_get_exit_block_uses (df->exit_block_uses);
+
   EXECUTE_IF_SET_IN_BITMAP (df->exit_block_uses, 0, i, bi)
-    df_uses_record (dflow, &regno_reg_rtx[i], 
-		    DF_REF_REG_USE, EXIT_BLOCK_PTR, NULL,
-		    DF_REF_ARTIFICIAL);
+    bb_refs = df_uses_record (dflow, bb_refs, &regno_reg_rtx[i], 
+                              DF_REF_REG_USE, EXIT_BLOCK_PTR, NULL,
+                              DF_REF_ARTIFICIAL);
+
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+  /* It is deliberate that this is not put in the exit block uses but
+     I do not know why.  */
+  if (reload_completed 
+      && df_has_eh_preds (EXIT_BLOCK_PTR)
+      && fixed_regs[ARG_POINTER_REGNUM])
+    bb_refs = df_uses_record (dflow, bb_refs,
+                              &regno_reg_rtx[ARG_POINTER_REGNUM], 
+                              DF_REF_REG_USE, EXIT_BLOCK_PTR, NULL,
+                              DF_REF_ARTIFICIAL);
+#endif
+
+  /* Process bb_refs chain */
+  df_refs_add_to_chains (dflow, NULL, DF_REF_NEXT_REF (&dummy));
 }
 
 static bool initialized = false;
 
+
 /* Initialize some platform specific structures.  */
 
 void 
@@ -2180,3 +2523,304 @@
   
   initialized = true;
 }
+
+
+/*----------------------------------------------------------------------------
+  Dataflow ref information verification functions.
+----------------------------------------------------------------------------*/
+
+
+/* Find the matching identical ref in the existing ref chain,
+   and return it if it is in various other chains/places that 
+   it's supposed to be in. Otherwise return NULL.   */
+
+static struct df_ref *
+df_ref_verify (struct dataflow *dflow,
+               struct df_ref *this_ref)
+{
+  struct df_chains chains = df_ref_find_chains (dflow, this_ref);
+
+  struct df_ref **ref_chain = chains.ref_chain;
+  struct df_reg_info *reg_info = chains.reg_info;
+  struct df_ref_info *ref_info = chains.ref_info;
+
+  struct df_ref *old_ref;
+
+  /* Verify the ref chain.  */
+  old_ref = df_ref_chain_find_ref (*ref_chain, this_ref, df_ref_is_equal);
+  if (!old_ref) 
+    return NULL;
+
+  /* Verify the reg chain.  */
+  old_ref = df_reg_chain_find_ref (reg_info->reg_chain, 
+                                   old_ref, df_ref_is_pointer_equal);
+  if (!old_ref) 
+    return NULL;
+
+  /* Verify ref_info->refs array.  */
+  if (ref_info->add_refs_inline
+      && (DF_REF_ID (old_ref) >= ref_info->refs_size
+          || ref_info->refs[DF_REF_ID (old_ref)] != old_ref))
+    return NULL;
+
+  return old_ref;
+}
+
+
+/* Returns true if all refs in the chain is marked as verified.  */
+
+static bool
+df_refs_verified (struct df_ref *ref)
+{
+  for (; ref; ref = DF_REF_NEXT_REF (ref))
+    if (!DF_REF_FLAGS_IS_SET (ref, DF_REF_VERIFIED))
+      return false;
+
+  return true;
+}
+
+
+/* Returns true if the refs of the insn hasn't changed. 
+   It will set DF_REF_VERIFIED for all verified refs.  */
+
+static bool
+df_ref_chain_verify (struct dataflow *dflow, struct df_ref *ref)
+{
+  for (; ref; ref = DF_REF_NEXT_REF (ref))
+    {
+      struct df_ref *oref = df_ref_verify (dflow, ref);
+      if (!oref)
+        return false;
+      /* Mark the found ref as VERIFIED.
+         This causes the OREF not to be matched again,
+         since newly created REF won't have VERIFIED bit set.  
+         That's exactly what we want to happen
+         to handle duplicate entries.  */
+      DF_REF_FLAGS_SET (oref, DF_REF_VERIFIED);
+    }
+
+  return true;
+}
+
+
+/* Return true if all refs of the insn are marked verified. 
+   Clear DF_REF_VERIFIED bit for *all* refs in the chain
+   regardless of the return value. */
+
+static bool
+df_reg_chain_clear_verified (struct df_ref *ref_chain)
+{
+  bool ret = true;
+  struct df_ref *ref;
+  for (ref = ref_chain; ref; ref = DF_REF_NEXT_REG (ref))
+    {
+      if (!DF_REF_FLAGS_IS_SET (ref, DF_REF_VERIFIED))
+        ret = false;
+      DF_REF_FLAGS (ref) &= ~DF_REF_VERIFIED;
+    }
+
+  return ret;
+}
+
+
+/* Return true if all refs in the basic block are correct and complete.
+   Due to df_ref_chain_verify, it will cause all refs
+   that are verified to have DF_REF_VERIFIED bit set.  */
+
+static bool
+df_bb_refs_verify (struct dataflow *dflow, basic_block bb)
+{
+  rtx insn;
+  struct df_scan_bb_info *bb_info = df_scan_get_bb_info (dflow, bb->index);
+  struct df_ref *refs;
+
+  if (!bb_info)
+    return false;
+
+  /* Scan the block an insn at a time from beginning to end.  */
+  FOR_BB_INSNS (bb, insn)
+    {
+      if (!INSN_P (insn))
+        continue;
+      refs = df_insn_refs_collect (dflow, bb, insn);
+      if (!df_ref_chain_verify (dflow, refs))
+        return false;
+    }
+
+  /* Block level refs */
+  refs = df_bb_refs_collect (dflow, bb);
+  if (!df_ref_chain_verify (dflow, refs))
+    return false;
+
+
+  if (!df_refs_verified (bb_info->artificial_defs)
+      || !df_refs_verified (bb_info->artificial_uses))
+    return false;
+
+  return true;
+}
+
+
+/* Returns true if the exit block has correct and complete df_ref.  */
+
+static bool
+df_exit_block_verify (struct dataflow *dflow)
+{
+  unsigned int i;
+  bitmap_iterator bi;
+  struct df *df = dflow->df;
+  struct df_ref dummy;
+  struct df_ref *bb_refs = &dummy;
+  bitmap exit_block_uses = BITMAP_ALLOC (NULL);
+  bool is_eq;
+  struct df_scan_bb_info *bb_info;
+
+  DF_REF_NEXT_REF (bb_refs) = NULL;
+
+  df_get_exit_block_uses (exit_block_uses);
+
+  is_eq = bitmap_equal_p (exit_block_uses, df->exit_block_uses);
+  BITMAP_FREE (exit_block_uses);
+
+  if (!is_eq)
+    return false;
+
+  EXECUTE_IF_SET_IN_BITMAP (df->exit_block_uses, 0, i, bi)
+    bb_refs = df_uses_record (dflow, bb_refs, &regno_reg_rtx[i], 
+                              DF_REF_REG_USE, EXIT_BLOCK_PTR, NULL,
+                              DF_REF_ARTIFICIAL);
+
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+  /* It is deliberate that this is not put in the exit block uses but
+     I do not know why.  */
+  if (reload_completed 
+      && df_has_eh_preds (EXIT_BLOCK_PTR)
+      && fixed_regs[ARG_POINTER_REGNUM])
+    bb_refs = df_uses_record (dflow, bb_refs,
+                              &regno_reg_rtx[ARG_POINTER_REGNUM], 
+                              DF_REF_REG_USE, EXIT_BLOCK_PTR, NULL,
+                              DF_REF_ARTIFICIAL);
+#endif
+
+  if (!df_ref_chain_verify (dflow, bb_refs))
+    return false;
+
+  bb_info = df_scan_get_bb_info (dflow, EXIT_BLOCK);
+  if (!df_refs_verified (bb_info->artificial_defs)
+      || !df_refs_verified (bb_info->artificial_uses))
+    return false;
+
+  return true;
+}
+
+
+/* Returns true if the entry block has correct and complete df_ref.  */
+
+static bool
+df_entry_block_verify (struct dataflow *dflow)
+{
+  unsigned int i; 
+  bitmap_iterator bi;
+  struct df *df = dflow->df;
+  struct df_ref dummy;
+  struct df_ref *bb_refs = &dummy;
+  bitmap entry_block_defs = BITMAP_ALLOC (NULL);
+  bool is_eq;
+  struct df_scan_bb_info *bb_info;
+
+  DF_REF_NEXT_REF (bb_refs) = NULL;
+
+  df_get_entry_block_defs (entry_block_defs);
+
+  is_eq = bitmap_equal_p (entry_block_defs, df->entry_block_defs);
+  BITMAP_FREE (entry_block_defs);
+
+  if (!is_eq)
+    return false;
+
+  EXECUTE_IF_SET_IN_BITMAP (df->entry_block_defs, 0, i, bi)
+    {
+      bb_refs = df_ref_record (dflow, bb_refs, 
+                               regno_reg_rtx[i], &regno_reg_rtx[i], 
+                               ENTRY_BLOCK_PTR, NULL, 
+                               DF_REF_REG_DEF, DF_REF_ARTIFICIAL , false);
+    }
+
+  if (!df_ref_chain_verify (dflow, bb_refs))
+    return false;
+
+  bb_info = df_scan_get_bb_info (dflow, ENTRY_BLOCK);
+  if (!df_refs_verified (bb_info->artificial_defs)
+      || !df_refs_verified (bb_info->artificial_uses))
+    return false;
+
+  return true;
+}
+
+
+/* Return true if df_ref information for all insns 
+   in all blocks are correct and complete.  */
+
+bool
+df_verify_blocks (struct dataflow *dflow)
+{
+  unsigned int i;
+  basic_block bb;
+  struct df *df = dflow->df;
+  bitmap regular_block_artificial_uses = BITMAP_ALLOC (NULL);
+  bitmap eh_block_artificial_uses = BITMAP_ALLOC (NULL);
+  bool is_eq;
+  bool retval = true;
+
+  df_get_regular_block_artificial_uses (regular_block_artificial_uses);
+  df_get_eh_block_artificial_uses (eh_block_artificial_uses);
+
+  bitmap_ior_into (eh_block_artificial_uses, 
+		   regular_block_artificial_uses);
+
+  /* Check artificial_uses bitmaps didn't change. */
+  is_eq = bitmap_equal_p (regular_block_artificial_uses, 
+                          df->regular_block_artificial_uses);
+  BITMAP_FREE (regular_block_artificial_uses);
+  BITMAP_FREE (eh_block_artificial_uses);
+
+  if (!is_eq)
+    return false;
+
+  /* Verify each basic block. */
+  FOR_ALL_BB (bb)
+    {
+      retval = (retval && !df_bb_refs_verify (dflow, bb));
+      if (!retval)
+        break;
+    }
+
+  /* Verify exit block. */
+  retval = (retval && df_exit_block_verify (dflow));
+
+  /* Verify entry block. */
+  retval = (retval && df_entry_block_verify (dflow));
+
+  /* See if all reg chains are verified,
+     and also clear the DF_REF_VERIFIED bit. */
+
+  for (i = 0; i < DF_REG_SIZE (df); i++)
+    {
+      struct df_ref *ref;
+      
+      /* Note the order of operands of &&. 
+         We need to call reg_chain_clear_verified() *always*,
+         to make sure DF_REF_VERIFIED bit is cleared for all refs. */
+
+      ref = DF_REG_DEF_CHAIN (df, i);
+      retval = (df_reg_chain_clear_verified (ref) && retval);
+
+      ref = DF_REG_USE_CHAIN (df, i);
+      retval = (df_reg_chain_clear_verified (ref) && retval);
+
+      ref = DF_REG_EQ_USE_CHAIN (df, i);
+      retval = (df_reg_chain_clear_verified (ref) && retval);
+    }
+
+  return retval;
+}
Index: gcc/df-core.c
===================================================================
--- gcc/df-core.c	(revision 118108)
+++ gcc/df-core.c	(working copy)
@@ -49,7 +49,7 @@
 
       df_set_blocks (df, blocks);
 
-      df_rescan_blocks (df, blocks);
+      df_scan_blocks (df, blocks);
 
       df_analyze (df);
 
@@ -104,7 +104,7 @@
 
 DF_ANALYZE causes all of the defined problems to be (re)solved.  It
 does not cause blocks to be (re)scanned at the rtl level unless no
-prior call is made to df_rescan_blocks.  When DF_ANALYZE is completes,
+prior call is made to df_scan_blocks.  When DF_ANALYZE is completes,
 the IN and OUT sets for each basic block contain the computer
 information.  The DF_*_BB_INFO macros can be used to access these
 bitvectors.
@@ -815,9 +815,9 @@
   for (i = 0; i < df->n_blocks; i++)
     bitmap_set_bit (current_all_blocks, df->postorder[i]);
 
-  /* No one called df_rescan_blocks, so do it.  */
+  /* No one called df_scan_blocks, so do it.  */
   if (!df->blocks_to_scan)
-    df_rescan_blocks (df, NULL);
+    df_scan_blocks (df, NULL);
 
   /* Make sure that we have pruned any unreachable blocks from these
      sets.  */
Index: gcc/ifcvt.c
===================================================================
--- gcc/ifcvt.c	(revision 118108)
+++ gcc/ifcvt.c	(working copy)
@@ -3902,7 +3902,7 @@
 	{
 	  /* If we are going to go around again, rescan the blocks
 	     that have changed.  */
-	  df_rescan_blocks (df, modified);
+	  df_scan_blocks (df, modified);
 	  bitmap_clear (modified);
 	}
 
Index: gcc/df.h
===================================================================
--- gcc/df.h	(revision 118108)
+++ gcc/df.h	(working copy)
@@ -74,28 +74,28 @@
     /* Read-modify-write refs generate both a use and a def and
        these are marked with this flag to show that they are not
        independent.  */
-    DF_REF_READ_WRITE = 1,
+    DF_REF_READ_WRITE = 1 << 0,
 
     /* If this flag is set, this is not a real definition/use, but an
        artificial one created to model always live registers, eh uses, etc.  */
-    DF_REF_ARTIFICIAL = 4,
+    DF_REF_ARTIFICIAL = 1 << 1,
 
     /* If this flag is set for an artificial use or def, that ref
        logically happens at the top of the block.  If it is not set
        for an artificial use or def, that ref logically happens at the
        bottom of the block.  This is never set for regular refs.  */
-    DF_REF_AT_TOP = 8,
+    DF_REF_AT_TOP = 1 << 2,
 
     /* This flag is set if the use is inside a REG_EQUAL or REG_EQUIV
        note.  */
-    DF_REF_IN_NOTE = 16,
+    DF_REF_IN_NOTE = 1 << 3,
 
     /* This flag is set if this ref, generally a def, may clobber the
        referenced register.  This is generally only set for hard
        registers that cross a call site.  With better information
        about calls, some of these could be changed in the future to
        DF_REF_MUST_CLOBBER.  */
-    DF_REF_MAY_CLOBBER = 32,
+    DF_REF_MAY_CLOBBER = 1 << 4,
 
     /* This flag is set if this ref, generally a def, is a real
        clobber. This is not currently set for registers live across a
@@ -106,25 +106,37 @@
        clobber is to a subreg.  So in order to tell if the clobber
        wipes out the entire register, it is necessary to also check
        the DF_REF_PARTIAL flag.  */
-    DF_REF_MUST_CLOBBER = 64,
+    DF_REF_MUST_CLOBBER = 1 << 5,
 
     /* This bit is true if this ref is part of a multiword hardreg.  */
-    DF_REF_MW_HARDREG = 128,
+    DF_REF_MW_HARDREG = 1 << 6,
 
     /* This flag is set if this ref is a partial use or def of the
        associated register.  */
-    DF_REF_PARTIAL = 256,
+    DF_REF_PARTIAL = 1 << 7,
     
     /* This flag is set if this ref occurs inside of a conditional
        execution instruction.  */
-    DF_REF_CONDITIONAL = 512,
+    DF_REF_CONDITIONAL = 1 << 8,
 
     /* This flag is set if this ref is inside a pre/post modify.  */
-    DF_REF_PRE_POST_MODIFY = 1024,
+    DF_REF_PRE_POST_MODIFY = 1 << 9,
 
     /* This flag is set if this ref is a usage of the stack pointer by
        a function call.  */
-    DF_REF_CALL_STACK_USAGE = 2048
+    DF_REF_CALL_STACK_USAGE = 1 << 10,
+
+    /* This flag is set when this ref is verified.
+       Used for verifying existing refs. */
+    DF_REF_VERIFIED = 1 << 11,
+
+    /* This flag is set when the ref should be 
+       recorded in regs_ever_live[] array. */
+    DF_REF_RECORD_LIVE = 1 << 12,
+
+    /* This flag is used internally to group
+       the hardregs. */
+    DF_REF_MW_HARDREG_GROUP = 1 << 13
   };
 
 
@@ -454,8 +466,8 @@
 #define DF_REF_REAL_REG(REF) (GET_CODE ((REF)->reg) == SUBREG \
 				? SUBREG_REG ((REF)->reg) : ((REF)->reg))
 #define DF_REF_REGNO(REF) ((REF)->regno)
-#define DF_REF_REAL_LOC(REF) (GET_CODE ((REF)->reg) == SUBREG \
-			        ? &SUBREG_REG ((REF)->reg) : ((REF)->loc))
+#define DF_REF_REAL_LOC(REF) (GET_CODE (*((REF)->loc)) == SUBREG \
+                               ? &SUBREG_REG (*((REF)->loc)) : ((REF)->loc))
 #define DF_REF_REG(REF) ((REF)->reg)
 #define DF_REF_LOC(REF) ((REF)->loc)
 #define DF_REF_BB(REF) ((REF)->bb)
@@ -466,6 +478,8 @@
 #define DF_REF_CHAIN(REF) ((REF)->chain)
 #define DF_REF_ID(REF) ((REF)->id)
 #define DF_REF_FLAGS(REF) ((REF)->flags)
+#define DF_REF_FLAGS_IS_SET(REF, v) ((DF_REF_FLAGS(REF) & (v)) != 0)
+#define DF_REF_FLAGS_SET(REF, v) (DF_REF_FLAGS(REF) |= (v))
 #define DF_REF_NEXT_REG(REF) ((REF)->next_reg)
 #define DF_REF_PREV_REG(REF) ((REF)->prev_reg)
 #define DF_REF_NEXT_REF(REF) ((REF)->next_ref)
@@ -725,7 +739,7 @@
 
 extern struct df_scan_bb_info *df_scan_get_bb_info (struct dataflow *, unsigned int);
 extern struct dataflow *df_scan_add_problem (struct df *);
-extern void df_rescan_blocks (struct df *, bitmap);
+extern void df_scan_blocks (struct df *, bitmap);
 extern struct df_ref *df_ref_create (struct df *, rtx, rtx *, rtx,basic_block,enum df_ref_type, enum df_ref_flags);
 extern struct df_ref *df_get_artificial_defs (struct df *, unsigned int);
 extern struct df_ref *df_get_artificial_uses (struct df *, unsigned int);
@@ -743,6 +757,7 @@
 extern void df_maybe_reorganize_def_refs (struct df *);
 extern void df_hard_reg_init (void);
 extern bool df_read_modify_subreg_p (rtx);
+extern bool df_verify_blocks (struct dataflow *);
 
 
 /* web */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]