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 COMMITTED to change the way register infomation is computed.


This patch separates the operations that were done in the
DF_RI_PROBLEM into 3 categories:

1) The calculation of REG_DEAD and REG_UNUSED notes.  This remains as
a dataflow problem, now called DF_NOTE.

2) The calculation of REG_N_SETS and REG_N_REFS.  This was divided
into two cases:

     a) For passes that do incremental dataflow rescanning AND do not
     need to modify these, the calls were replace with calls to
     DF_REG_DEF_COUNT and DF_REG_USE_COUNT.  (Note that calls to
     REG_N_REFS(i) were replaced with DF_REG_DEF_COUNT(i) +
     DF_REG_USE_COUNT(i).

     b) For passes that either needed to modify them or were not doing
     incremental dataflow rescanning, a new datastructure was created.
     This datastructure is initialized by calls to
     regstat_init_n_sets_and_refs and must be freed by calls to
     regstat_free_n_sets_and_refs.  The used of REG_N_DEFS
     (REG_N_REFS) that change the value have been changed to
     SET_REG_N_DEFS (SET_REG_N_REFS) or INC_REG_N_DEFS
     (INC_REG_N_REFS).

3) The calculation of REG_N_DEATHS, REG_LIVE_LENGTH, REG_N_CALLS_CROSSED,
REG_N_THROWING_CALLS_CROSSED and REG_BASIC_BLOCK is now done by
regstat_compute_ri and must be freed by regstat_free_ri.  These
structures are currently only used by the register allocator and
regmove.

There were uses of (3) in the sh, however kaz has determined that
these were adding no value at all to the performance of the generated
code so they have been removed.

There still remains one call to REG_N_CALLS_CROSSED in sched-deps.
This should be removed at the earliest time since it is absolutely
bogus.  There are better ways to compute when an insn cannot cross a
call and virtually every one of them would produce fewer dependencies.
I added regstat_bb_compute_calls_crossed and
regstat_bb_free_calls_crossed to support this use in the meantime.
This avoids the expensive calculation of REG_LIVE_LENGTH in the
regstat_compute_ri and must be freed by regstat_free_ri calls.

This breakup has allowed us to only compute these structures exactly
where they are needed which saves both time and space.  Note the
removal of the calculation of REG_N_DEATHS from combine which
otherwise does not use any of (3).

This cleanup has allowed the removal of allocate_reg_life_data,
allocate_reg_info, and clear_reg_info_regno.  It is now possible, but
not done in this patch to get rid of the no_new_pseudos bogusity.

All of this has made it possible fix the dataflow calls in the
register allocators so that now mimic the information flow of the
mainline.  Not getting this right has been the source of several
performance and correctness regressions.  We now only differ in that
we add the DF_UREC problem at the beginning of local-alloc rather than
computing make_accurate_live_analysis (which does the same thing on
mainline) at the start of global. This allows the information in (3)
to be computed over a more precise model of the program.

This patch has been bootstrapped and regression tested on x86-64,
x86-32, ppc-32 and ia-64.

Kenny


2007-05-08  Kenneth Zadeck <zadeck@naturalbridge.com>

    * regrename.c (regrename_optimize): Renamed df_ri_add_problem to
    df_note_add_problem.
    * auto-inc-dec.c (rest_of_handle_auto_inc_dec): Ditto.
    * sched_ebb.c (schedule_ebbs): Renamed df_ri_add_problem to
    df_note_add_problem.  Added call to regstat_compute_calls_crossed
    and regstat_free_calls_crossed and deleted call to
    allocate_reg_life_data.
    * regstat.c (regstat_init_n_sets_and_refs,
    regstat_free_n_sets_and_refs, regstat_bb_compute_ri,
    regstat_compute_ri, regstat_free_ri,
    regstat_bb_compute_calls_crossed, regstat_compute_calls_crossed,
    regstat_free_calls_crossed): New functions.
    * final.c (rest_of_handle_final): Removed call to free_reg_info.
    * cfg.c (dump_reg_info): Many changes to accomodate new
    implementation of REG_BASIC_BLOCK, REG_N_SETS, REG_N_DEATHS,
    REG_N_CALLS_CROSSED.
    * toplev.c (finalize): Removed call to free_reg_info.
    * regs.h (REG_BASIC_BLOCK, REG_N_SETS, REG_N_REFS, REG_N_DEATHS,
    REG_N_CALLS_CROSSED, REG_FREQ, REG_N_THROWING_CALLS_CROSSED,
    REG_LIVE_LENGTH, REG_BASIC_BLOCK): Changed implementation.
    (allocate_reg_life_data, allocate_reg_info, clear_reg_info_regno):
    Removed.
    * mode-switching.c (optimize_mode_switching): Removed call to
    df_ri_add_problem.
    * modulo-sched.c (sms_schedule): Renamed df_ri_add_problem to
    df_note_add_problem.  Added call to regstat_compute_calls_crossed
    and regstat_free_calls_crossed
    (rest_of_handle_sms): Deleted call to allocate_reg_info.
    * global.c (compute_regsets): Moved all dataflow to local_alloc.
    (rest_of_handle_global_alloc): Call regstat_free_n_sets_and_refs
    and regstat_free_ri.
    * ifcvt.c (dead_or_predicable, if_convert): Removed calls to
    allocate_reg_info.
    * timevar.def (TV_DF_NOTE): New timevar.
    * regmove.c (copy_src_to_dest, regmove_optimize, fixup_match_1):
    Changed calls to REG_N_SETS that changed the value to
    INC_REG_N_SETS.
    (regmove_optimize): Moved calls that compute df and register info
    to after early out for flag_non_call_exceptions.  Added calls to
    regstat_init_n_sets_and_refs, regstat_compute_ri,
    regstat_free_n_sets_and_refs and regstat_free_ri.
    * local_alloc (local_alloc, equiv_init_movable_p): Added
    NUM_FIXED_BLOCKS to tests for REG_BASIC_BLOCK.
    (update_equiv_regs): Added code to update bitvectors when certain
    local allocations are done.  Changed REG_N_SETS to
    DF_REG_DEF_COUNT.  Added NUM_FIXED_BLOCKS to tests for
    REG_BASIC_BLOCK.
    (rest_of_handle_local_alloc): Moved computation of UREC from
    global to here.
    * function.c (regno_clobbered_at_setjmp): Added to test to see if
    regno was valid.  Moved function size test higher in call
    heirarchy.
    (setjmp_args_warning): Added tests to early out of check if
    function is small or there are no setjmps.
    * df.h (DF_RI, df_ri, DF_RI_LIFE, DF_RI_SETJMP, df_ri_add_problem,
    df_ri_get_setjmp_crosses): Deleted.
    (DF_NOTE, df_note, df_note_add_problem): Added.
    * gcse (gcse_main): Removed computation of RI information and
    removed calls to allocate_reg_info.
    * init-regs.c (initialize_uninitialized_regs): Removed call to
    allocate_reg_life_data.
          * regclass.c (reg_info_data, reg_info_head, reg_pref_buffer,
    allocate_reg_life_data, allocate_reg_info, clear_reg_info_regno):
    Deleted.
    (scan_one_insn): Changed some calls to REG_N_SETS and REG_N_REFS
    to INC_REG_N_SETS and INC_REG_N_REFS.
    (regclass): Allocate register information locally.
    (free_reg_info): Changed the structures freed.
    (reg_scan): Removed call to allocate_reg_info and changed call to
    REG_N_SETS to DF_REG_DEF_COUNT.
    * combine (try_combine, remove_death, distribute_notes): Removed
    computation of REG_N_DEATHS.  Changed some references to
    REG_N_SETS to INC_REG_N_SETS.
    (rest_of_handle_combine): Replaced call to df_ri_add_problem with
    call to df_note_add_problem, and added call to
    regstat_init_n_sets_and_refs and regstat_free_n_sets_and_refs.
    * bb-reorder (rest_of_handle_partition_blocks): Removed call to
    allocate_reg_life_data.
    * df-problems.c (reg_n_info, df_ri_problem_p, df_ri_problem_data,
    df_ri_alloc, df_ri_start_dump, df_ri_get_setjmp_crosses): Removed.
    (print_note): Renamed df_print_note.
    (df_kill_notes): Added parameters to save notes rather than just
    let them die and remake them.
    (df_set_note): New function.
    (df_set_unused_notes_for_mw, df_set_dead_notes_for_mw,
    df_create_unused_note, df_ri_bb_compute, df_ri_compute,
    df_ri_free): Removed ri information computations.
    (df_ri_bb_compute): Renamed to df_note_bb_compute.
    (df_ri_compute): Renamed to df_note_compute.
    (df_ri_free): Renamed to df_note_free.
    (problem_RI): Renamed to problem_NOTE
    (df_ri_add_problem): Renamed to df_note_add_problem.
    * (reg-stack.c): Changed call to df_ri_add_problem to
    df_note_add_problem.
    * combine-stack-adj.c (rest_of_handle_stack_adjustments): Ditto.
    * (Makefile.in): Added regstat.o.
    * sched-rgn.c (schedule_insns): Changed call to df_ri_add_problem to
    df_note_add_problem.  Added calls to regstat_compute_calls_crossed
    and regstat_free_calls_crossed.
    * basic_block.h (REG_BLOCK_UNKNOWN, REG_BLOCK_GLOBAL,
    REG_BASIC_BLOCK): Moved to regs.h.
    * config/sparc/sparc.c (sparc_check_64): Changed REG_N_SETS to
    DF_REG_DEF_COUNT.
    * config/sh/sh.c (flow_dependent_p_1): Ditto.
    (sh_md_init): Removed useless attempt to measure pressure on R0.
    * config/m68k/m68k.c (m68k_output_mi_thunk): Removed call to
    allocate_reg_info.
    * reload1.c (delete_output_reload): Added NUM_FIXED_BLOCKS to
    tests for REG_BASIC_BLOCK.



Index: regrename.c
===================================================================
--- regrename.c	(revision 124521)
+++ regrename.c	(working copy)
@@ -195,7 +195,7 @@ regrename_optimize (void)
   char *first_obj;
 
   df_set_flags (DF_LR_RUN_DCE);
-  df_ri_add_problem (0);
+  df_note_add_problem ();
   df_analyze ();
   df_set_flags (DF_NO_INSN_RESCAN);
   
Index: auto-inc-dec.c
===================================================================
--- auto-inc-dec.c	(revision 124521)
+++ auto-inc-dec.c	(working copy)
@@ -1513,7 +1513,7 @@ rest_of_handle_auto_inc_dec (void)
 
   mem_tmp = gen_rtx_MEM (Pmode, NULL_RTX);
 
-  df_ri_add_problem (0);
+  df_note_add_problem ();
   df_analyze ();
 
   reg_next_use = XCNEWVEC (rtx, max_reg);
Index: sched-ebb.c
===================================================================
--- sched-ebb.c	(revision 124521)
+++ sched-ebb.c	(working copy)
@@ -539,9 +539,10 @@ schedule_ebbs (void)
   current_sched_info = &ebb_sched_info;
 
   df_set_flags (DF_LR_RUN_DCE);
-  df_ri_add_problem (DF_RI_LIFE);
+  df_note_add_problem ();
   df_analyze ();
   df_clear_flags (DF_LR_RUN_DCE);
+  regstat_compute_calls_crossed ();
   sched_init ();
 
   compute_bb_for_insn ();
@@ -591,15 +592,13 @@ schedule_ebbs (void)
     }
   bitmap_clear (&dont_calc_deps);
 
-  /* Updating register live information.  */
-  allocate_reg_life_data ();
-
   /* Reposition the prologue and epilogue notes in case we moved the
      prologue/epilogue insns.  */
   if (reload_completed)
     reposition_prologue_and_epilogue_notes ();
 
   sched_finish ();
+  regstat_free_calls_crossed ();
 }
 
 /* INSN has been added to/removed from current ebb.  */
Index: regstat.c
===================================================================
--- regstat.c	(revision 0)
+++ regstat.c	(revision 0)
@@ -0,0 +1,504 @@
+/* Scanning of rtl for dataflow analysis.
+   Copyright (C) 2007
+   Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck (zadeck@naturalbridge.com).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+*/
+
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "flags.h"
+#include "regs.h"
+#include "output.h"
+#include "except.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "timevar.h"
+#include "df.h"
+
+
+struct regstat_n_sets_and_refs_t *regstat_n_sets_and_refs;
+struct regstat_n_sets_and_refs_t *regstat_n_sets_and_refs;
+
+/*----------------------------------------------------------------------------
+   REG_N_SETS and REG_N_REFS.  
+   ----------------------------------------------------------------------------*/
+
+/* If a pass need to change these values in some magical way or or the
+   pass needs to have accurate values for these and is not using
+   incremental df scanning, then it should use REG_N_SETS and
+   REG_N_USES.  If the pass is doing incremental scanning then it
+   should be getting the info from DF_REG_DEF_COUNT and
+   DF_REG_USE_COUNT.  */
+
+void
+regstat_init_n_sets_and_refs (void)
+{
+  unsigned int i;
+  unsigned int max_regno = max_reg_num ();
+
+  df_grow_reg_info ();
+  gcc_assert (!regstat_n_sets_and_refs);
+
+  regstat_n_sets_and_refs = xmalloc (max_regno * sizeof (struct regstat_n_sets_and_refs_t));
+
+  for (i = 0; i < max_regno; i++)
+    {
+      SET_REG_N_SETS (i, DF_REG_DEF_COUNT (i));
+      SET_REG_N_REFS (i, DF_REG_USE_COUNT (i) + REG_N_SETS (i));
+    }
+}
+
+
+/* Free the array that holds the REG_N_SETS and REG_N_REFS.  */
+
+void
+regstat_free_n_sets_and_refs (void)
+{
+  gcc_assert (regstat_n_sets_and_refs);
+  free (regstat_n_sets_and_refs);
+  regstat_n_sets_and_refs = NULL;
+}
+
+
+/*----------------------------------------------------------------------------
+   REGISTER INFORMATION
+
+   Process REG_N_DEATHS, REG_LIVE_LENGTH, REG_N_CALLS_CROSSED,
+   REG_N_THROWING_CALLS_CROSSED and REG_BASIC_BLOCK.
+
+   ----------------------------------------------------------------------------*/
+
+static bitmap setjmp_crosses;
+struct reg_info_t *reg_info_p;
+
+/* The number allocated elements of reg_info_p.  */
+size_t reg_info_p_size;
+
+/* Compute register info: lifetime, bb, and number of defs and uses
+   for basic block BB.  The three bitvectors are scratch regs used
+   here.  */
+
+static void
+regstat_bb_compute_ri (unsigned int bb_index, 
+		       bitmap live, bitmap do_not_gen, bitmap artificial_uses,
+		       bitmap local_live, bitmap local_processed)
+{
+  basic_block bb = BASIC_BLOCK (bb_index);
+  rtx insn;
+  struct df_ref **def_rec;
+  struct df_ref **use_rec;
+  int luid = 0;
+  bitmap_iterator bi;
+  unsigned int regno;
+
+  bitmap_copy (live, df_get_live_out (bb));
+  bitmap_clear (artificial_uses);
+
+  /* Process the regs live at the end of the block.  Mark them as
+     not local to any one basic block.  */
+  EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
+    REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
+
+  /* Process the artificial defs and uses at the bottom of the block
+     to begin processing.  */
+  for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
+    {
+      struct df_ref *def = *def_rec;
+      if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0)
+	bitmap_clear_bit (live, DF_REF_REGNO (def));
+    }
+
+  for (use_rec = df_get_artificial_uses (bb_index); *use_rec; use_rec++)
+    {
+      struct df_ref *use = *use_rec;
+      if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == 0)
+	{
+	  regno = DF_REF_REGNO (use);
+	  bitmap_set_bit (live, regno);
+	  bitmap_set_bit (artificial_uses, regno);
+	}
+    }
+  
+  FOR_BB_INSNS_REVERSE (bb, insn)
+    {
+      unsigned int uid = INSN_UID (insn);
+      unsigned int regno;
+      bitmap_iterator bi;
+      struct df_mw_hardreg **mws_rec;
+      rtx link;
+ 
+      if (!INSN_P (insn))
+	continue;
+
+      /* Increment the live_length for all of the registers that
+	 are are referenced in this block and live at this
+	 particular point.  */
+      EXECUTE_IF_SET_IN_BITMAP (local_live, 0, regno, bi)
+	{
+	  REG_LIVE_LENGTH (regno)++;
+	}
+      luid++;
+  
+      bitmap_clear (do_not_gen);
+
+      link = REG_NOTES (insn);
+      while (link)
+	{
+	  if (REG_NOTE_KIND (link) == REG_DEAD)
+	    REG_N_DEATHS(REGNO (XEXP (link, 0)))++;
+	  link = XEXP (link, 1);
+	}
+
+      /* Process the defs.  */
+      if (CALL_P (insn))
+	{
+	  bool can_throw = can_throw_internal (insn); 
+	  bool set_jump = (find_reg_note (insn, REG_SETJMP, NULL) != NULL);
+	  EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
+	    {
+	      REG_N_CALLS_CROSSED (regno)++;
+	      if (can_throw)
+		REG_N_THROWING_CALLS_CROSSED (regno)++;
+	      
+	      /* We have a problem with any pseudoreg that lives
+		 across the setjmp.  ANSI says that if a user variable
+		 does not change in value between the setjmp and the
+		 longjmp, then the longjmp preserves it.  This
+		 includes longjmp from a place where the pseudo
+		 appears dead.  (In principle, the value still exists
+		 if it is in scope.)  If the pseudo goes in a hard
+		 reg, some other value may occupy that hard reg where
+		 this pseudo is dead, thus clobbering the pseudo.
+		 Conclusion: such a pseudo must not go in a hard
+		 reg.  */
+	      if (set_jump)
+		bitmap_set_bit (setjmp_crosses, regno);
+	    }
+	}
+	  
+      /* We only care about real sets for calls.  Clobbers only
+	 may clobbers cannot be depended on.  */
+      for (mws_rec = DF_INSN_UID_MWS (uid); *mws_rec; mws_rec++)
+	{
+	  struct df_mw_hardreg *mws = *mws_rec; 
+	  if (mws->type == DF_REF_REG_DEF) 
+	    {
+	      bool all_dead = true;
+	      unsigned int r;
+	      
+	      for (r=mws->start_regno; r <= mws->end_regno; r++)
+		if ((bitmap_bit_p (live, r))
+		    || bitmap_bit_p (artificial_uses, r))
+		  {
+		    all_dead = false;
+		    break;
+		  }
+	      
+	      if (all_dead)
+		{
+		  unsigned int regno = mws->start_regno;
+		  bitmap_set_bit (do_not_gen, regno);
+		  /* Only do this if the value is totally dead.  */
+		  REG_LIVE_LENGTH (regno)++;
+		}
+	    }
+	}
+      
+      /* All of the defs except the return value are some sort of
+	 clobber.  This code is for the return.  */
+      for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+	{
+	  struct df_ref *def = *def_rec;
+	  if ((!CALL_P (insn))
+	      || (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))))
+	    {
+	      unsigned int dregno = DF_REF_REGNO (def);
+	      
+	      if (bitmap_bit_p (live, dregno))
+		{
+		  /* If we have seen this regno, then it has already been
+		     processed correctly with the per insn increment.  If we
+		     have not seen it we need to add the length from here to
+		     the end of the block to the live length.  */
+		  if (bitmap_bit_p (local_processed, dregno))
+		    {
+		      if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
+			bitmap_clear_bit (local_live, dregno);
+		    }
+		  else
+		    {
+		      bitmap_set_bit (local_processed, dregno);
+		      REG_LIVE_LENGTH (dregno) += luid;
+		    }
+		}
+	      else if ((!(DF_REF_FLAGS (def) & DF_REF_MW_HARDREG))
+		       && (!bitmap_bit_p (artificial_uses, dregno)))
+		{
+		  REG_LIVE_LENGTH (dregno)++;
+		}
+	      
+	      if (dregno >= FIRST_PSEUDO_REGISTER)
+		{
+		  REG_FREQ (dregno) += REG_FREQ_FROM_BB (bb);
+		  if (REG_BASIC_BLOCK (dregno) == REG_BLOCK_UNKNOWN)
+		    REG_BASIC_BLOCK (dregno) = bb->index;
+		  else if (REG_BASIC_BLOCK (dregno) != bb->index)
+		    REG_BASIC_BLOCK (dregno) = REG_BLOCK_GLOBAL;
+		}
+	      
+	      if (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER + DF_REF_MAY_CLOBBER)))
+		bitmap_set_bit (do_not_gen, dregno);
+	      
+	      /* Kill this register if it is not a subreg store or conditional store.  */
+	      if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
+		bitmap_clear_bit (live, dregno);
+	    }
+	}
+      
+      for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
+	{
+	  struct df_ref *use = *use_rec;
+	  unsigned int uregno = DF_REF_REGNO (use);
+
+	  if (uregno >= FIRST_PSEUDO_REGISTER)
+	    {
+	      REG_FREQ (uregno) += REG_FREQ_FROM_BB (bb);
+	      if (REG_BASIC_BLOCK (uregno) == REG_BLOCK_UNKNOWN)
+		REG_BASIC_BLOCK (uregno) = bb->index;
+	      else if (REG_BASIC_BLOCK (uregno) != bb->index)
+		REG_BASIC_BLOCK (uregno) = REG_BLOCK_GLOBAL;
+	    }
+	  
+	  if (!bitmap_bit_p (live, uregno))
+	    {
+	      /* This register is now live.  */
+	      bitmap_set_bit (live, uregno);
+
+	      /* If we have seen this regno, then it has already been
+		 processed correctly with the per insn increment.  If
+		 we have not seen it we set the bit so that begins to
+		 get processed locally.  Note that we don't even get
+		 here if the variable was live at the end of the block
+		 since just a ref inside the block does not effect the
+		 calculations.  */
+	      REG_LIVE_LENGTH (uregno) ++;
+	      bitmap_set_bit (local_live, uregno);
+	      bitmap_set_bit (local_processed, uregno);
+	    }
+	}
+    }
+  
+  /* Add the length of the block to all of the registers that were not
+     referenced, but still live in this block.  */
+  bitmap_and_compl_into (live, local_processed);
+  EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
+    REG_LIVE_LENGTH (regno) += luid;
+
+  bitmap_clear (local_processed);
+  bitmap_clear (local_live);
+}
+
+
+/* Compute register info: lifetime, bb, and number of defs and uses.  */
+void
+regstat_compute_ri (void)
+{
+  basic_block bb;
+  bitmap live = BITMAP_ALLOC (&df_bitmap_obstack);
+  bitmap do_not_gen = BITMAP_ALLOC (&df_bitmap_obstack);
+  bitmap artificial_uses = BITMAP_ALLOC (&df_bitmap_obstack);
+  bitmap local_live = BITMAP_ALLOC (&df_bitmap_obstack);
+  bitmap local_processed = BITMAP_ALLOC (&df_bitmap_obstack);
+  unsigned int regno;
+  bitmap_iterator bi;
+
+  /* Initialize everything.  */
+
+  gcc_assert (!reg_info_p);
+
+  setjmp_crosses = BITMAP_ALLOC (&df_bitmap_obstack);
+  max_regno = max_reg_num ();
+  reg_info_p_size = max_regno;
+  reg_info_p = xcalloc (max_regno, sizeof (struct reg_info_t));
+
+  FOR_EACH_BB (bb)
+    {
+      regstat_bb_compute_ri (bb->index, live, do_not_gen, artificial_uses,
+			     local_live, local_processed);
+    }
+
+  BITMAP_FREE (live);
+  BITMAP_FREE (do_not_gen);
+  BITMAP_FREE (artificial_uses);
+
+  /* See the setjmp comment in regstat_ri_bb_compute.  */
+  EXECUTE_IF_SET_IN_BITMAP (setjmp_crosses, FIRST_PSEUDO_REGISTER, regno, bi)
+    {
+      REG_BASIC_BLOCK (regno) = REG_BLOCK_UNKNOWN;
+      REG_LIVE_LENGTH (regno) = -1;
+    }	  
+  
+  BITMAP_FREE (local_live);
+  BITMAP_FREE (local_processed);
+}
+
+
+/* Free all storage associated with the problem.  */
+
+void
+regstat_free_ri (void)
+{
+  gcc_assert (reg_info_p);
+  reg_info_p_size = 0;
+  free (reg_info_p); 
+  reg_info_p = NULL;
+
+  BITMAP_FREE (setjmp_crosses);
+}
+
+
+/* Return a bitmap containing the set of registers that cross a setjmp.  
+   The client should not change or delete this bitmap.  */
+
+bitmap
+regstat_get_setjmp_crosses (void)
+{
+  return setjmp_crosses;
+}
+
+/*----------------------------------------------------------------------------
+   Process REG_N_CALLS_CROSSED.  
+
+   This is used by sched_deps.  A good implementation of sched-deps
+   would really process the blocks directly rather than going thur
+   lists of insns.  If it did this, it could use the exact regs that
+   cross an individual call rather than using this info that merges
+   the info for all calls.
+
+   ----------------------------------------------------------------------------*/
+
+
+
+/* Compute callse crossed for BB. Live is a scratch bitvector.  */
+
+static void
+regstat_bb_compute_calls_crossed (unsigned int bb_index, bitmap live)
+{
+  basic_block bb = BASIC_BLOCK (bb_index);
+  rtx insn;
+  struct df_ref **def_rec;
+  struct df_ref **use_rec;
+
+  bitmap_copy (live, df_get_live_out (bb));
+
+  /* Process the artificial defs and uses at the bottom of the block
+     to begin processing.  */
+  for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
+    {
+      struct df_ref *def = *def_rec;
+      if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0)
+	bitmap_clear_bit (live, DF_REF_REGNO (def));
+    }
+
+  for (use_rec = df_get_artificial_uses (bb_index); *use_rec; use_rec++)
+    {
+      struct df_ref *use = *use_rec;
+      if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == 0)
+	bitmap_set_bit (live, DF_REF_REGNO (use));
+    }
+  
+  FOR_BB_INSNS_REVERSE (bb, insn)
+    {
+      unsigned int uid = INSN_UID (insn);
+      unsigned int regno;
+ 
+      if (!INSN_P (insn))
+	continue;
+
+      /* Process the defs.  */
+      if (CALL_P (insn))
+	{
+	  bitmap_iterator bi;
+	  EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
+	    REG_N_CALLS_CROSSED (regno)++;
+	}
+	  
+      /* All of the defs except the return value are some sort of
+	 clobber.  This code is for the return.  */
+      for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+	{
+	  struct df_ref *def = *def_rec;
+	  if ((!CALL_P (insn))
+	      || (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))))
+	    {
+	      /* Kill this register if it is not a subreg store or conditional store.  */
+	      if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
+		bitmap_clear_bit (live, DF_REF_REGNO (def));
+	    }
+	}
+      
+      for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
+	{
+	  struct df_ref *use = *use_rec;
+	  bitmap_set_bit (live, DF_REF_REGNO (use));
+	}
+    }
+}
+
+
+/* Compute register info: lifetime, bb, and number of defs and uses.  */
+void
+regstat_compute_calls_crossed (void)
+{
+  basic_block bb;
+  bitmap live = BITMAP_ALLOC (&df_bitmap_obstack);
+
+  /* Initialize everything.  */
+  gcc_assert (!reg_info_p);
+
+  max_regno = max_reg_num ();
+  reg_info_p_size = max_regno;
+  reg_info_p = xcalloc (max_regno, sizeof (struct reg_info_t));
+
+  FOR_EACH_BB (bb)
+    {
+      regstat_bb_compute_calls_crossed (bb->index, live);
+    }
+
+  BITMAP_FREE (live);
+}
+
+
+/* Free all storage associated with the problem.  */
+
+void
+regstat_free_calls_crossed (void)
+{
+  gcc_assert (reg_info_p);
+  reg_info_p_size = 0;
+  free (reg_info_p); 
+  reg_info_p = NULL;
+}
+
Index: final.c
===================================================================
--- final.c	(revision 124521)
+++ final.c	(working copy)
@@ -4018,6 +4018,9 @@ rest_of_handle_final (void)
 
   user_defined_section_attribute = false;
 
+  /* Free up reg info memory.  */
+  free_reg_info ();
+
   if (! quiet_flag)
     fflush (asm_out_file);
 
Index: cfg.c
===================================================================
--- cfg.c	(revision 124521)
+++ cfg.c	(working copy)
@@ -574,52 +574,59 @@ dump_reg_info (FILE *file)
   if (reload_completed)
     return;
 
-  if (VEC_length (reg_info_p, reg_n_info) < max)
-    max = VEC_length (reg_info_p, reg_n_info);
+  if (reg_info_p_size < max)
+    max = reg_info_p_size;
 
   fprintf (file, "%d registers.\n", max);
   for (i = FIRST_PSEUDO_REGISTER; i < max; i++)
-    if (VEC_index (reg_info_p, reg_n_info, i) && REG_N_REFS (i))
-      {
-	enum reg_class class, altclass;
-	
+    {
+      enum reg_class class, altclass;
+      
+      if (regstat_n_sets_and_refs)
 	fprintf (file, "\nRegister %d used %d times across %d insns",
 		 i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
-	if (REG_BASIC_BLOCK (i) >= 0)
-	  fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
-	if (REG_N_SETS (i))
-	  fprintf (file, "; set %d time%s", REG_N_SETS (i),
-		   (REG_N_SETS (i) == 1) ? "" : "s");
-	if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i]))
-	  fprintf (file, "; user var");
-	if (REG_N_DEATHS (i) != 1)
-	  fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
-	if (REG_N_CALLS_CROSSED (i) == 1)
-	  fprintf (file, "; crosses 1 call");
-	else if (REG_N_CALLS_CROSSED (i))
-	  fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
-	if (regno_reg_rtx[i] != NULL
-	    && PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
-	  fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
-	
-	class = reg_preferred_class (i);
-	altclass = reg_alternate_class (i);
-	if (class != GENERAL_REGS || altclass != ALL_REGS)
-	  {
-	    if (altclass == ALL_REGS || class == ALL_REGS)
-	      fprintf (file, "; pref %s", reg_class_names[(int) class]);
-	    else if (altclass == NO_REGS)
-	      fprintf (file, "; %s or none", reg_class_names[(int) class]);
-	    else
-	      fprintf (file, "; pref %s, else %s",
-		       reg_class_names[(int) class],
-		       reg_class_names[(int) altclass]);
-	  }
-	
-	if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i]))
-	  fprintf (file, "; pointer");
-	fprintf (file, ".\n");
-      }
+      else if (df)
+	fprintf (file, "\nRegister %d used %d times across %d insns",
+		 i, DF_REG_USE_COUNT (i) + DF_REG_DEF_COUNT (i), REG_LIVE_LENGTH (i));
+      
+      if (REG_BASIC_BLOCK (i) >= NUM_FIXED_BLOCKS)
+	fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
+      if (regstat_n_sets_and_refs)
+	fprintf (file, "; set %d time%s", REG_N_SETS (i),
+		 (REG_N_SETS (i) == 1) ? "" : "s");
+      else if (df)
+	fprintf (file, "; set %d time%s", DF_REG_DEF_COUNT (i),
+		 (DF_REG_DEF_COUNT (i) == 1) ? "" : "s");
+      if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i]))
+	fprintf (file, "; user var");
+      if (REG_N_DEATHS (i) != 1)
+	fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
+      if (REG_N_CALLS_CROSSED (i) == 1)
+	fprintf (file, "; crosses 1 call");
+      else if (REG_N_CALLS_CROSSED (i))
+	fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
+      if (regno_reg_rtx[i] != NULL
+	  && PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
+	fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
+      
+      class = reg_preferred_class (i);
+      altclass = reg_alternate_class (i);
+      if (class != GENERAL_REGS || altclass != ALL_REGS)
+	{
+	  if (altclass == ALL_REGS || class == ALL_REGS)
+	    fprintf (file, "; pref %s", reg_class_names[(int) class]);
+	  else if (altclass == NO_REGS)
+	    fprintf (file, "; %s or none", reg_class_names[(int) class]);
+	  else
+	    fprintf (file, "; pref %s, else %s",
+		     reg_class_names[(int) class],
+		     reg_class_names[(int) altclass]);
+	}
+      
+      if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i]))
+	fprintf (file, "; pointer");
+      fprintf (file, ".\n");
+    }
 }
 
 
@@ -629,7 +636,7 @@ dump_flow_info (FILE *file, int flags)
   basic_block bb;
 
   /* There are no pseudo registers after reload.  Don't dump them.  */
-  if (reg_n_info && (flags & TDF_DETAILS) != 0)
+  if (reg_info_p_size && (flags & TDF_DETAILS) != 0)
     dump_reg_info (file);
 
   fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges);
Index: toplev.c
===================================================================
--- toplev.c	(revision 124521)
+++ toplev.c	(working copy)
@@ -2089,9 +2089,6 @@ finalize (void)
   if (mem_report)
     dump_memory_report (true);
 
-  /* Free up memory for the benefit of leak detectors.  */
-  free_reg_info ();
-
   /* Language-specific end of compilation actions.  */
   lang_hooks.finish ();
 }
Index: regs.h
===================================================================
--- regs.h	(revision 124521)
+++ regs.h	(working copy)
@@ -46,35 +46,88 @@ Software Foundation, 51 Franklin Street,
 
 extern int max_regno;
 
-/* Register information indexed by register number */
-typedef struct reg_info_def
-{				/* fields set by reg_scan & flow_analysis */
-  int sets;			/* # of times (REG n) is set */
+/* REG_N_REFS and REG_N_SETS are initialized by a call to
+   regstat_init_n_sets_and_refs from the current values of
+   DF_REG_DEF_COUNT and DF_REG_USE_COUNT.  REG_N_REFS and REG_N_SETS
+   should only be used if a pass need to change these values in some
+   magical way or or the pass needs to have accurate values for these
+   and is not using incremental df scanning.
+
+   At the end of a pass that uses REG_N_REFS and REG_N_SETS, a call
+   should be made to regstat_free_n_sets_and_refs.  
+
+   Local alloc seems to play pretty loose with these values.
+   REG_N_REFS is set to 0 if the register is used in an asm.
+   Furthermore, local_alloc calls regclass to hack both REG_N_REFS and
+   REG_N_SETS for three address insns.  Other passes seem to have
+   other special values.  */
+
+
+
+/* Structure to hold values for REG_N_SETS (i) and REG_N_REFS (i). */
 
-				/* fields set by flow_analysis */
+struct regstat_n_sets_and_refs_t
+{
+  int sets;			/* # of times (REG n) is set */
   int refs;			/* # of times (REG n) is used or set */
+};
+
+extern struct regstat_n_sets_and_refs_t *regstat_n_sets_and_refs;
+
+/* Indexed by n, gives number of times (REG n) is used or set.  */
+static inline int
+REG_N_REFS(int regno)
+{
+  return regstat_n_sets_and_refs[regno].refs;
+}
+
+/* Indexed by n, gives number of times (REG n) is used or set.  */
+#define SET_REG_N_REFS(N,V) (regstat_n_sets_and_refs[N].refs = V)
+#define INC_REG_N_REFS(N,V) (regstat_n_sets_and_refs[N].refs += V)
+
+/* Indexed by n, gives number of times (REG n) is set.  */
+static inline int
+REG_N_SETS (int regno)
+{
+  return regstat_n_sets_and_refs[regno].sets;
+}
+
+/* Indexed by n, gives number of times (REG n) is set.  */
+#define SET_REG_N_SETS(N,V) (regstat_n_sets_and_refs[N].sets = V)
+#define INC_REG_N_SETS(N,V) (regstat_n_sets_and_refs[N].sets += V)
+
+
+/* Functions defined in reg-stat.c.  */
+extern void regstat_init_n_sets_and_refs (void);
+extern void regstat_free_n_sets_and_refs (void);
+extern void regstat_compute_ri (void);
+extern void regstat_free_ri (void);
+extern bitmap regstat_get_setjmp_crosses (void);
+extern void regstat_compute_calls_crossed (void);
+extern void regstat_free_calls_crossed (void);
+
+
+/* Register information indexed by register number.  This structure is
+   initialized by calling regstat_compute_ri and is destroyed by
+   calling regstat_free_ri.  */
+struct reg_info_t
+{
   int freq;			/* # estimated frequency (REG n) is used or set */
   int deaths;			/* # of times (REG n) dies */
   int live_length;		/* # of instructions (REG n) is live */
   int calls_crossed;		/* # of calls (REG n) is live across */
   int throw_calls_crossed;	/* # of calls that may throw (REG n) is live across */
   int basic_block;		/* # of basic blocks (REG n) is used in */
-} reg_info;
-
-typedef reg_info *reg_info_p;
-
-DEF_VEC_P(reg_info_p);
-DEF_VEC_ALLOC_P(reg_info_p,heap);
+};
 
-extern VEC(reg_info_p,heap) *reg_n_info;
+extern struct reg_info_t *reg_info_p;
 
-/* Indexed by n, gives number of times (REG n) is used or set.  */
-
-#define REG_N_REFS(N) (VEC_index (reg_info_p, reg_n_info, N)->refs)
+/* The number allocated elements of reg_info_p.  */
+extern size_t reg_info_p_size;
 
 /* Estimate frequency of references to register N.  */
 
-#define REG_FREQ(N) (VEC_index (reg_info_p, reg_n_info, N)->freq)
+#define REG_FREQ(N) (reg_info_p[N].freq)
 
 /* The weights for each insn varries from 0 to REG_FREQ_BASE.
    This constant does not need to be high, as in infrequently executed
@@ -94,19 +147,13 @@ extern VEC(reg_info_p,heap) *reg_n_info;
 			      ? ((bb)->frequency * REG_FREQ_MAX / BB_FREQ_MAX)\
 			      : 1)
 
-/* Indexed by n, gives number of times (REG n) is set.
-   ??? both regscan and flow allocate space for this.  We should settle
-   on just copy.  */
-
-#define REG_N_SETS(N) (VEC_index (reg_info_p, reg_n_info, N)->sets)
-
 /* Indexed by N, gives number of insns in which register N dies.
    Note that if register N is live around loops, it can die
    in transitions between basic blocks, and that is not counted here.
    So this is only a reliable indicator of how many regions of life there are
    for registers that are contained in one basic block.  */
 
-#define REG_N_DEATHS(N) (VEC_index (reg_info_p, reg_n_info, N)->deaths)
+#define REG_N_DEATHS(N) (reg_info_p[N].deaths)
 
 /* Get the number of consecutive words required to hold pseudo-reg N.  */
 
@@ -125,14 +172,12 @@ extern VEC(reg_info_p,heap) *reg_n_info;
 
 /* Indexed by N, gives number of CALL_INSNS across which (REG n) is live.  */
 
-#define REG_N_CALLS_CROSSED(N)					\
-  (VEC_index (reg_info_p, reg_n_info, N)->calls_crossed)
+#define REG_N_CALLS_CROSSED(N)  (reg_info_p[N].calls_crossed)
 
 /* Indexed by N, gives number of CALL_INSNS that may throw, across which
    (REG n) is live.  */
 
-#define REG_N_THROWING_CALLS_CROSSED(N) \
-  (VEC_index (reg_info_p, reg_n_info, N)->throw_calls_crossed)
+#define REG_N_THROWING_CALLS_CROSSED(N) (reg_info_p[N].throw_calls_crossed)
 
 /* Total number of instructions at which (REG n) is live.  The larger
    this is, the less priority (REG n) gets for allocation in a hard
@@ -150,8 +195,19 @@ extern VEC(reg_info_p,heap) *reg_n_info;
    is not required.  global.c makes an allocno for this but does
    not try to assign a hard register to it.  */
 
-#define REG_LIVE_LENGTH(N)				\
-  (VEC_index (reg_info_p, reg_n_info, N)->live_length)
+#define REG_LIVE_LENGTH(N)  (reg_info_p[N].live_length)
+
+/* Indexed by n, gives number of basic block that  (REG n) is used in.
+   If the value is REG_BLOCK_GLOBAL (-1),
+   it means (REG n) is used in more than one basic block.
+   REG_BLOCK_UNKNOWN (0) means it hasn't been seen yet so we don't know.
+   This information remains valid for the rest of the compilation
+   of the current function; it is used to control register allocation.  */
+
+#define REG_BLOCK_UNKNOWN 0
+#define REG_BLOCK_GLOBAL -1
+
+#define REG_BASIC_BLOCK(N) (reg_info_p[N].basic_block)
 
 /* Vector of substitutions of register numbers,
    used to map pseudo regs into hardware regs.
@@ -204,13 +260,6 @@ extern int caller_save_needed;
 #define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) 0
 #endif
 
-/* Allocate reg_n_info tables */
-extern void allocate_reg_life_data (void);
-extern void allocate_reg_info (size_t, int, int);
-
-/* Clear the register information for regno.  */
-extern void clear_reg_info_regno (unsigned int);
-
 /* Specify number of hard registers given machine mode occupy.  */
 extern unsigned char hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
 
Index: df-core.c
===================================================================
--- df-core.c	(revision 124521)
+++ df-core.c	(working copy)
@@ -1540,7 +1540,7 @@ df_compact_blocks (void)
   int i, p;
   basic_block bb;
   void **problem_temps;
-  int size = last_basic_block *sizeof (void *);
+  int size = last_basic_block * sizeof (void *);
   bitmap tmp = BITMAP_ALLOC (&df_bitmap_obstack);
   problem_temps = xmalloc (size);
 
Index: mode-switching.c
===================================================================
--- mode-switching.c	(revision 124521)
+++ mode-switching.c	(working copy)
@@ -452,7 +452,6 @@ optimize_mode_switching (void)
   pre_exit = create_pre_exit (n_entities, entity_map, num_modes);
 #endif
 
-  df_ri_add_problem (0);
   df_analyze ();
 
   /* Create the bitmap vectors.  */
Index: modulo-sched.c
===================================================================
--- modulo-sched.c	(revision 124521)
+++ modulo-sched.c	(working copy)
@@ -910,9 +910,10 @@ sms_schedule (void)
   df_set_flags (DF_LR_RUN_DCE);
   df_rd_add_problem ();
   df_ru_add_problem ();
-  df_ri_add_problem (DF_RI_LIFE);
+  df_note_add_problem ();
   df_chain_add_problem (DF_DU_CHAIN + DF_UD_CHAIN);
   df_analyze ();
+  regstat_compute_calls_crossed ();
   sched_init ();
 
   /* Allocate memory to hold the DDG array one entry for each loop.
@@ -1215,6 +1216,7 @@ sms_schedule (void)
       free_ddg (g);
     }
 
+  regstat_free_calls_crossed ();
   free (g_arr);
 
   /* Release scheduler data, needed until now because of DFA.  */
@@ -2470,7 +2472,6 @@ rest_of_handle_sms (void)
 
   /* Update the life information, because we add pseudos.  */
   max_regno = max_reg_num ();
-  allocate_reg_info (max_regno, FALSE, FALSE);
   no_new_pseudos = 1;
 
   /* Finalize layout changes.  */
Index: global.c
===================================================================
--- global.c	(revision 124521)
+++ global.c	(working copy)
@@ -398,17 +398,6 @@ compute_regsets (HARD_REG_SET *elim_set,
   compact_blocks ();
 
   max_allocno = 0;
-  /* Do not recompute the register info.  Local_alloc has played with
-     this in a way that global expects.  */
-  /* Create a new version of df that has the special version of UR if
-     we are doing optimization.  */
-  if (optimize)
-    {
-      df_remove_problem (df_live);
-      df_urec_add_problem ();
-    }
-  df_analyze ();
-  df_set_flags (DF_NO_INSN_RESCAN);
 
   /* A machine may have certain hard registers that
      are safe to use only within a basic block.  */
@@ -2140,6 +2129,9 @@ rest_of_handle_global_alloc (void)
 
   if (optimize)
     df_analyze ();
+
+  regstat_free_n_sets_and_refs ();
+  regstat_free_ri ();
   return 0;
 }
 
Index: ifcvt.c
===================================================================
--- ifcvt.c	(revision 124521)
+++ ifcvt.c	(working copy)
@@ -3802,10 +3802,7 @@ dead_or_predicable (basic_block test_bb,
 	 expander called from noce_emit_cmove), we must resize the
 	 array first.  */
       if (max_regno < max_reg_num ())
-	{
-	  max_regno = max_reg_num ();
-	  allocate_reg_info (max_regno, FALSE, FALSE);
-	}
+	max_regno = max_reg_num ();
 
       FOR_BB_INSNS (merge_bb, insn)
 	{
@@ -4034,10 +4031,7 @@ if_convert (void)
 
   /* If we allocated new pseudos, we must resize the array for sched1.  */
   if (max_regno < max_reg_num ())
-    {
-      max_regno = max_reg_num ();
-      allocate_reg_info (max_regno, FALSE, FALSE);
-    }
+    max_regno = max_reg_num ();
 
   /* Write the final stats.  */
   if (dump_file && num_possible_if_blocks > 0)
Index: timevar.def
===================================================================
--- timevar.def	(revision 124521)
+++ timevar.def	(working copy)
@@ -65,6 +65,7 @@ DEFTIMEVAR (TV_DF_LR		     , "df live re
 DEFTIMEVAR (TV_DF_LIVE		     , "df live&initialized regs")
 DEFTIMEVAR (TV_DF_UREC		     , "df uninitialized regs 2")
 DEFTIMEVAR (TV_DF_CHAIN		     , "df use-def / def-use chains")
+DEFTIMEVAR (TV_DF_NOTE		     , "df reg dead/unused notes")
 DEFTIMEVAR (TV_DF_RI		     , "df register information")
 
 DEFTIMEVAR (TV_ALIAS_ANALYSIS	     , "alias analysis")
Index: regmove.c
===================================================================
--- regmove.c	(revision 124521)
+++ regmove.c	(working copy)
@@ -869,7 +869,7 @@ copy_src_to_dest (rtx insn, rtx src, rtx
 
       /* Update the various register tables.  */
       dest_regno = REGNO (dest);
-      REG_N_SETS (dest_regno) ++;
+      INC_REG_N_SETS (dest_regno, 1);
       REG_LIVE_LENGTH (dest_regno)++;
       src_regno = REGNO (src);
       if (! find_reg_note (move_insn, REG_DEAD, src))
@@ -1080,14 +1080,17 @@ regmove_optimize (rtx f, int nregs)
   int i;
   rtx copy_src, copy_dst;
 
-  df_ri_add_problem (DF_RI_LIFE);
-  df_analyze ();
-
   /* ??? Hack.  Regmove doesn't examine the CFG, and gets mightily
      confused by non-call exceptions ending blocks.  */
   if (flag_non_call_exceptions)
     return;
 
+  df_note_add_problem ();
+  df_analyze ();
+
+  regstat_init_n_sets_and_refs ();
+  regstat_compute_ri ();
+
   /* Find out where a potential flags register is live, and so that we
      can suppress some optimizations in those zones.  */
   mark_flags_life_zones (discover_flags_reg ());
@@ -1489,8 +1492,8 @@ regmove_optimize (rtx f, int nregs)
 		  dstno = REGNO (dst);
 		  srcno = REGNO (src);
 
-		  REG_N_SETS (dstno)++;
-		  REG_N_SETS (srcno)--;
+		  INC_REG_N_SETS (dstno, 1);
+		  INC_REG_N_SETS (srcno, -1);
 
 		  REG_N_CALLS_CROSSED (dstno) += num_calls;
 		  REG_N_CALLS_CROSSED (srcno) -= num_calls;
@@ -1530,6 +1533,8 @@ regmove_optimize (rtx f, int nregs)
       free (reg_set_in_bb);
       reg_set_in_bb = NULL;
     }
+  regstat_free_n_sets_and_refs ();
+  regstat_free_ri ();
 }
 
 /* Returns nonzero if INSN's pattern has matching constraints for any operand.
@@ -1884,7 +1889,7 @@ fixup_match_1 (rtx insn, rtx set, rtx sr
 	  && try_auto_increment (search_end, post_inc, 0, src, newconst, 1))
 	post_inc = 0;
       validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (insn_const), 0);
-      REG_N_SETS (REGNO (src))++;
+      INC_REG_N_SETS (REGNO (src), 1);
       REG_LIVE_LENGTH (REGNO (src))++;
     }
   if (overlap)
@@ -1951,7 +1956,7 @@ fixup_match_1 (rtx insn, rtx set, rtx sr
 	      && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0))
 	    {
 	      delete_insn (q);
-	      REG_N_SETS (REGNO (src))--;
+	      INC_REG_N_SETS (REGNO (src), -1);
 	      REG_N_CALLS_CROSSED (REGNO (src)) -= num_calls2;
 	      REG_LIVE_LENGTH (REGNO (src)) -= s_length2;
 	      insn_const = 0;
@@ -2023,8 +2028,8 @@ fixup_match_1 (rtx insn, rtx set, rtx sr
       REG_N_CALLS_CROSSED (REGNO (src)) += s_num_calls;
     }
 
-  REG_N_SETS (REGNO (src))++;
-  REG_N_SETS (REGNO (dst))--;
+  INC_REG_N_SETS (REGNO (src), 1);
+  INC_REG_N_SETS (REGNO (dst), -1);
 
   REG_N_CALLS_CROSSED (REGNO (dst)) -= num_calls;
 
Index: local-alloc.c
===================================================================
--- local-alloc.c	(revision 124521)
+++ local-alloc.c	(working copy)
@@ -391,7 +391,7 @@ local_alloc (void)
 
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     {
-      if (REG_BASIC_BLOCK (i) >= 0 && REG_N_DEATHS (i) == 1)
+      if (REG_BASIC_BLOCK (i) >= NUM_FIXED_BLOCKS && REG_N_DEATHS (i) == 1)
 	reg_qty[i] = -2;
       else
 	reg_qty[i] = -1;
@@ -607,7 +607,7 @@ equiv_init_movable_p (rtx x, int regno)
     case REG:
       return (reg_equiv[REGNO (x)].loop_depth >= reg_equiv[regno].loop_depth
 	      && reg_equiv[REGNO (x)].replace)
-	     || (REG_BASIC_BLOCK (REGNO (x)) < 0 && ! rtx_varies_p (x, 0));
+	     || (REG_BASIC_BLOCK (REGNO (x)) < NUM_FIXED_BLOCKS && ! rtx_varies_p (x, 0));
 
     case UNSPEC_VOLATILE:
       return 0;
@@ -799,7 +799,8 @@ update_equiv_regs (void)
   rtx insn;
   basic_block bb;
   int loop_depth;
-
+  bitmap cleared_regs;
+  
   reg_equiv = XCNEWVEC (struct equivalence, max_regno);
   reg_equiv_init = ggc_alloc_cleared (max_regno * sizeof (rtx));
   reg_equiv_init_size = max_regno;
@@ -914,7 +915,7 @@ update_equiv_regs (void)
 	  if (note && GET_CODE (XEXP (note, 0)) == EXPR_LIST)
 	    note = NULL_RTX;
 
-	  if (REG_N_SETS (regno) != 1
+	  if (DF_REG_DEF_COUNT (regno) != 1
 	      && (! note
 		  || rtx_varies_p (XEXP (note, 0), 0)
 		  || (reg_equiv[regno].replacement
@@ -930,7 +931,7 @@ update_equiv_regs (void)
 
 	  /* If this register is known to be equal to a constant, record that
 	     it is always equivalent to the constant.  */
-	  if (REG_N_SETS (regno) == 1
+	  if (DF_REG_DEF_COUNT (regno) == 1
 	      && note && ! rtx_varies_p (XEXP (note, 0), 0))
 	    {
 	      rtx note_value = XEXP (note, 0);
@@ -955,7 +956,7 @@ update_equiv_regs (void)
 
 	  note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
 
-	  if (note == 0 && REG_BASIC_BLOCK (regno) >= 0
+	  if (note == 0 && REG_BASIC_BLOCK (regno) >= NUM_FIXED_BLOCKS
 	      && MEM_P (SET_SRC (set))
 	      && validate_equiv_mem (insn, dest, SET_SRC (set)))
 	    note = set_unique_reg_note (insn, REG_EQUIV, copy_rtx (SET_SRC (set)));
@@ -1052,8 +1053,8 @@ update_equiv_regs (void)
 
       if (MEM_P (dest) && REG_P (src)
 	  && (regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
-	  && REG_BASIC_BLOCK (regno) >= 0
-	  && REG_N_SETS (regno) == 1
+	  && REG_BASIC_BLOCK (regno) >= NUM_FIXED_BLOCKS
+	  && DF_REG_DEF_COUNT (regno) == 1
 	  && reg_equiv[regno].init_insns != 0
 	  && reg_equiv[regno].init_insns != const0_rtx
 	  && ! find_reg_note (XEXP (reg_equiv[regno].init_insns, 0),
@@ -1076,6 +1077,7 @@ update_equiv_regs (void)
 	}
     }
 
+  cleared_regs = BITMAP_ALLOC (NULL);
   /* Now scan all regs killed in an insn to see if any of them are
      registers only used that once.  If so, see if we can replace the
      reference with the equivalent form.  If we can, delete the
@@ -1158,7 +1160,7 @@ update_equiv_regs (void)
 			}
 
 		      remove_death (regno, insn);
-		      REG_N_REFS (regno) = 0;
+		      SET_REG_N_REFS (regno, 0);
 		      REG_FREQ (regno) = 0;
 		      delete_insn (equiv_insn);
 
@@ -1166,6 +1168,7 @@ update_equiv_regs (void)
 			= XEXP (reg_equiv[regno].init_insns, 1);
 
 		      reg_equiv_init[regno] = NULL_RTX;
+		      bitmap_set_bit (cleared_regs, regno);
 		    }
 		  /* Move the initialization of the register to just before
 		     INSN.  Update the flow information.  */
@@ -1196,15 +1199,31 @@ update_equiv_regs (void)
 
 		      reg_equiv_init[regno]
 			= gen_rtx_INSN_LIST (VOIDmode, new_insn, NULL_RTX);
+		      bitmap_set_bit (cleared_regs, regno);
 		    }
 		}
 	    }
 	}
     }
 
+  if (!bitmap_empty_p (cleared_regs))
+    FOR_EACH_BB (bb)
+      {
+	bitmap_and_compl_into (DF_RA_LIVE_IN (bb), cleared_regs);
+	if (DF_RA_LIVE_TOP (bb))
+	  bitmap_and_compl_into (DF_RA_LIVE_TOP (bb), cleared_regs);
+	bitmap_and_compl_into (DF_RA_LIVE_OUT (bb), cleared_regs);
+	bitmap_and_compl_into (DF_LR_IN (bb), cleared_regs);
+	if (DF_LR_TOP (bb))
+	  bitmap_and_compl_into (DF_LR_TOP (bb), cleared_regs);
+	bitmap_and_compl_into (DF_LR_OUT (bb), cleared_regs);
+      }
+
+  BITMAP_FREE (cleared_regs);
 
   out:
   /* Clean up.  */
+
   end_alias_analysis ();
   free (reg_equiv);
 }
@@ -2496,18 +2515,24 @@ rest_of_handle_local_alloc (void)
   int rebuild_notes;
   int max_regno = max_reg_num ();
 
-  /* Allocate the reg_renumber array.  For non-optimizing compilation,
-     allocate the register info array too, because we have not
-     run neither dataflow nor regscan so far.  */
-  allocate_reg_info (max_regno, !optimize, TRUE);
+  df_note_add_problem ();
+  if (optimize)
+    {
+      /* Create a new version of df that has the special version of UR
+	 if we are doing optimization.  */
+      df_remove_problem (df_live);
+      df_urec_add_problem ();
+    }
+  df_analyze ();
+  regstat_init_n_sets_and_refs ();
+  regstat_compute_ri ();
 
-  df_ri_add_problem (DF_RI_LIFE + DF_RI_SETJMP);
   /* There is just too much going on in the register allocators to
      keep things up to date.  At the end we have to rescan anyway
      because things change when the reload_completed flag is set.  
      So we just turn off scanning and we will rescan by hand.  */
-  df_set_flags (DF_DEFER_INSN_RESCAN);
-  df_analyze ();
+  df_set_flags (DF_NO_INSN_RESCAN);
+
 
   /* If we are not optimizing, then this is the only place before
      register allocation where dataflow is done.  And that is needed
Index: function.c
===================================================================
--- function.c	(revision 124521)
+++ function.c	(working copy)
@@ -3482,8 +3482,10 @@ pad_below (struct args_size *offset_ptr,
 static bool
 regno_clobbered_at_setjmp (bitmap setjmp_crosses, int regno)
 {
-  if (n_basic_blocks == NUM_FIXED_BLOCKS)
-    return 0;
+  /* There appear to be cases where some local vars never reach the
+     backend but have bogus regnos.  */
+  if (regno >= max_reg_num ())
+    return false;
 
   return ((REG_N_SETS (regno) > 1
 	   || REGNO_REG_SET_P (df_get_live_out (ENTRY_BLOCK_PTR), regno))
@@ -3537,7 +3539,11 @@ setjmp_args_warning (bitmap setjmp_cross
 void 
 generate_setjmp_warnings (void)
 {
-  bitmap setjmp_crosses = df_ri_get_setjmp_crosses ();
+  bitmap setjmp_crosses = regstat_get_setjmp_crosses ();
+
+  if (n_basic_blocks == NUM_FIXED_BLOCKS
+      || bitmap_empty_p (setjmp_crosses))
+    return;
 
   setjmp_vars_warning (setjmp_crosses, DECL_INITIAL (current_function_decl));
   setjmp_args_warning (setjmp_crosses);
Index: df.h
===================================================================
--- df.h	(revision 124521)
+++ df.h	(working copy)
@@ -49,9 +49,9 @@ struct df_link;
 #define DF_RD    4      /* Reaching Defs. */
 #define DF_UREC  5      /* Uninitialized Registers with Early Clobber. */
 #define DF_CHAIN 6      /* Def-Use and/or Use-Def Chains. */
-#define DF_RI    7      /* Register Info. */
+#define DF_NOTE  7      /* REG_DEF and REG_UNUSED notes. */
 
-#define DF_LAST_PROBLEM_PLUS1 (DF_RI + 1)
+#define DF_LAST_PROBLEM_PLUS1 (DF_NOTE + 1)
 #define DF_FIRST_OPTIONAL_PROBLEM DF_RU
 
 /* Dataflow direction.  */
@@ -376,13 +376,6 @@ enum df_chain_flags
   DF_UD_CHAIN      =  2  /* Build UD chains.  */
 };
 
-enum df_ri_flags
-{
-  /* Flag to control the building of register info.  */
-  DF_RI_LIFE       =  1, /* Build register info.  */
-  DF_RI_SETJMP     =  2  /* Build pseudos that cross setjmp info.  */
-};
-
 enum df_changeable_flags 
 {
   /* Scanning flags.  */
@@ -805,7 +798,7 @@ extern struct df *df;
 #define df_live  (df->problems_by_index[DF_LIVE])
 #define df_urec  (df->problems_by_index[DF_UREC])
 #define df_chain (df->problems_by_index[DF_CHAIN])
-#define df_ri    (df->problems_by_index[DF_RI])
+#define df_note  (df->problems_by_index[DF_NOTE])
 
 /* This symbol turns on checking that each modfication of the cfg has
   been identified to the appropriate df routines.  It is not part of
@@ -818,6 +811,7 @@ extern struct df *df;
 #define DF_DEBUG_CFG
 #endif
 
+
 /* Functions defined in df-core.c.  */
 
 extern void df_add_problem (struct df_problem *);
@@ -893,8 +887,7 @@ extern void df_live_verify_transfer_func
 extern void df_live_add_problem (void);
 extern void df_urec_add_problem (void);
 extern void df_chain_add_problem (enum df_chain_flags);
-extern void df_ri_add_problem (enum df_ri_flags);
-extern bitmap df_ri_get_setjmp_crosses (void);
+extern void df_note_add_problem (void);
 
 /* Functions defined in df-scan.c.  */
 
@@ -1025,5 +1018,4 @@ extern void union_defs (struct df_ref *,
                         struct web_entry *, struct web_entry *,
 			bool (*fun) (struct web_entry *, struct web_entry *));
 
-
 #endif /* GCC_DF_H */
Index: gcse.c
===================================================================
--- gcse.c	(revision 124521)
+++ gcse.c	(working copy)
@@ -675,7 +675,7 @@ gcse_main (rtx f ATTRIBUTE_UNUSED)
      successors and predecessors.  */
   max_gcse_regno = max_reg_num ();
 
-  df_ri_add_problem (DF_RI_LIFE);
+  df_note_add_problem ();
   df_analyze ();
 
   if (dump_file)
@@ -811,7 +811,6 @@ gcse_main (rtx f ATTRIBUTE_UNUSED)
 
   /* We are finished with alias.  */
   end_alias_analysis ();
-  allocate_reg_info (max_reg_num (), FALSE, FALSE);
 
   if (!optimize_size && flag_gcse_sm)
     {
@@ -6611,7 +6610,6 @@ bypass_jumps (void)
 
   /* We are finished with alias.  */
   end_alias_analysis ();
-  allocate_reg_info (max_reg_num (), FALSE, FALSE);
 
   return changed;
 }
Index: init-regs.c
===================================================================
--- init-regs.c	(revision 124521)
+++ init-regs.c	(working copy)
@@ -51,7 +51,6 @@ static void
 initialize_uninitialized_regs (void)
 {
   basic_block bb;
-  bool did_something = false;
   bitmap already_genned = BITMAP_ALLOC (NULL);
 
   df_analyze ();
@@ -103,7 +102,6 @@ initialize_uninitialized_regs (void)
 		  move_insn = get_insns ();
 		  end_sequence ();
 		  add_insn_before (move_insn, insn, bb);
-		  did_something = true;
 		  if (dump_file)
 		    fprintf (dump_file, 
 			     "adding initialization in %s of reg %d at in block %d for insn %d.\n", 
@@ -114,8 +112,6 @@ initialize_uninitialized_regs (void)
     }
 
   BITMAP_FREE (already_genned);
-  if (did_something)
-    allocate_reg_life_data ();
 }
 
 static bool
Index: regclass.c
===================================================================
--- regclass.c	(revision 124521)
+++ regclass.c	(working copy)
@@ -247,20 +247,6 @@ static char *in_inc_dec;
 
 static GTY(()) rtx top_of_stack[MAX_MACHINE_MODE];
 
-/* Linked list of reg_info structures allocated for reg_n_info array.
-   Grouping all of the allocated structures together in one lump
-   means only one call to bzero to clear them, rather than n smaller
-   calls.  */
-struct reg_info_data {
-  struct reg_info_data *next;	/* next set of reg_info structures */
-  size_t min_index;		/* minimum index # */
-  size_t max_index;		/* maximum index # */
-  char used_p;			/* nonzero if this has been used previously */
-  reg_info data[1];		/* beginning of the reg_info data */
-};
-
-static struct reg_info_data *reg_info_head;
-
 /* No more global register variables may be declared; true once
    regclass has been initialized.  */
 
@@ -864,10 +850,6 @@ static struct costs init_cost;
 
 static struct reg_pref *reg_pref;
 
-/* Allocated buffers for reg_pref.  */
-
-static struct reg_pref *reg_pref_buffer;
-
 /* Frequency of executions of current insn.  */
 
 static int frequency;
@@ -1162,18 +1144,18 @@ scan_one_insn (rtx insn, int pass ATTRIB
 	}
 
       /* This makes one more setting of new insns's dest.  */
-      REG_N_SETS (REGNO (recog_data.operand[0]))++;
-      REG_N_REFS (REGNO (recog_data.operand[0]))++;
+      INC_REG_N_SETS (REGNO (recog_data.operand[0]), 1);
+      INC_REG_N_REFS (REGNO (recog_data.operand[0]), 1);
       REG_FREQ (REGNO (recog_data.operand[0])) += frequency;
 
       *recog_data.operand_loc[1] = recog_data.operand[0];
-      REG_N_REFS (REGNO (recog_data.operand[0]))++;
+      INC_REG_N_REFS (REGNO (recog_data.operand[0]), 1);
       REG_FREQ (REGNO (recog_data.operand[0])) += frequency;
       for (i = recog_data.n_dups - 1; i >= 0; i--)
 	if (recog_data.dup_num[i] == 1)
 	  {
 	    *recog_data.dup_loc[i] = recog_data.operand[0];
-	    REG_N_REFS (REGNO (recog_data.operand[0]))++;
+	    INC_REG_N_REFS (REGNO (recog_data.operand[0]), 1);
 	    REG_FREQ (REGNO (recog_data.operand[0])) += frequency;
 	  }
 
@@ -1261,9 +1243,14 @@ regclass (rtx f, int nregs)
   rtx insn;
   int i;
   int pass;
+  max_regno = max_reg_num ();
 
   init_recog ();
 
+  reg_renumber = xmalloc (max_regno * sizeof (short));
+  reg_pref = XCNEWVEC (struct reg_pref, max_regno);
+  memset (reg_renumber, -1, max_regno * sizeof (short));
+
   costs = XNEWVEC (struct costs, nregs);
 
 #ifdef FORBIDDEN_INC_DEC_CLASSES
@@ -1321,9 +1308,6 @@ regclass (rtx f, int nregs)
 	 `prefclass'.  Record in `altclass' the largest register
 	 class any of whose registers is better than memory.  */
 
-      if (pass == 0)
-	reg_pref = reg_pref_buffer;
-
       if (dump_file)
 	{
 	  dump_regclass (dump_file);
@@ -2199,184 +2183,35 @@ auto_inc_dec_reg_p (rtx reg, enum machin
 }
 #endif
 
-static short *renumber;
-static size_t regno_allocated;
-static unsigned int reg_n_max;
-
-void
-allocate_reg_life_data (void)
-{
-  /* Recalculate the register space, in case it has grown.  Old style
-     vector oriented regsets would set regset_{size,bytes} here also.  */
-  allocate_reg_info (max_regno, FALSE, FALSE);
-}
-
-/* Allocate enough space to hold NUM_REGS registers for the tables used for
-   reg_scan and flow_analysis that are indexed by the register number.  If
-   NEW_P is nonzero, initialize all of the registers, otherwise only
-   initialize the new registers allocated.  The same table is kept from
-   function to function, only reallocating it when we need more room.  If
-   RENUMBER_P is nonzero, allocate the reg_renumber array also.  */
-
-void
-allocate_reg_info (size_t num_regs, int new_p, int renumber_p)
-{
-  size_t size_info;
-  size_t size_renumber;
-  size_t min = (new_p) ? 0 : reg_n_max;
-  struct reg_info_data *reg_data;
-
-  max_regno = max_reg_num ();
-  if (num_regs > regno_allocated)
-    {
-      size_t old_allocated = regno_allocated;
-
-      regno_allocated = num_regs + (num_regs / 20);	/* Add some slop space.  */
-      size_renumber = regno_allocated * sizeof (short);
-
-      if (!reg_n_info)
-	{
-	  reg_n_info = VEC_alloc (reg_info_p, heap, regno_allocated);
-	  VEC_safe_grow_cleared (reg_info_p, heap, reg_n_info,
-				 regno_allocated);
-	  renumber = xmalloc (size_renumber);
-	  reg_pref_buffer = XNEWVEC (struct reg_pref, regno_allocated);
-	}
-      else
-	{
-	  size_t old_length = VEC_length (reg_info_p, reg_n_info);
-	  if (old_length < regno_allocated)
-	    {
-	      VEC_safe_grow_cleared (reg_info_p, heap, reg_n_info,
-				     regno_allocated);
-	    }
-	  else if (regno_allocated < old_length)
-	    {
-	      VEC_truncate (reg_info_p, reg_n_info, regno_allocated);
-	    }
-
-	  if (new_p)		/* If we're zapping everything, no need to realloc.  */
-	    {
-	      free ((char *) renumber);
-	      free ((char *) reg_pref);
-	      renumber = xmalloc (size_renumber);
-	      reg_pref_buffer = XNEWVEC (struct reg_pref, regno_allocated);
-	    }
-
-	  else
-	    {
-	      renumber = xrealloc (renumber, size_renumber);
-	      reg_pref_buffer = (struct reg_pref *) xrealloc (reg_pref_buffer,
-					  regno_allocated
-					  * sizeof (struct reg_pref));
-	    }
-	}
-
-      size_info = (regno_allocated - old_allocated) * sizeof (reg_info)
-	+ sizeof (struct reg_info_data) - sizeof (reg_info);
-      reg_data = xcalloc (size_info, 1);
-      reg_data->min_index = old_allocated;
-      reg_data->max_index = regno_allocated - 1;
-      reg_data->next = reg_info_head;
-      reg_info_head = reg_data;
-    }
-
-  reg_n_max = num_regs;
-  if (min < num_regs)
-    {
-      /* Loop through each of the segments allocated for the actual
-	 reg_info pages, and set up the pointers, zero the pages, etc.  */
-      for (reg_data = reg_info_head;
-	   reg_data && reg_data->max_index >= min;
-	   reg_data = reg_data->next)
-	{
-	  size_t min_index = reg_data->min_index;
-	  size_t max_index = reg_data->max_index;
-	  size_t max = MIN (max_index, num_regs);
-	  size_t local_min = min - min_index;
-	  size_t i;
-
-	  if (reg_data->min_index > num_regs)
-	    continue;
-
-	  if (min < min_index)
-	    local_min = 0;
-	  if (!reg_data->used_p)	/* page just allocated with calloc */
-	    reg_data->used_p = 1;	/* no need to zero */
-	  else
-	    memset (&reg_data->data[local_min], 0,
-		    sizeof (reg_info) * (max - min_index - local_min + 1));
-
-	  for (i = min_index+local_min; i <= max; i++)
-	    {
-	      VEC_replace (reg_info_p, reg_n_info, i,
-			   &reg_data->data[i-min_index]);
-	      REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
-	      renumber[i] = -1;
-	      reg_pref_buffer[i].prefclass = (char) NO_REGS;
-	      reg_pref_buffer[i].altclass = (char) NO_REGS;
-	    }
-	}
-    }
-
-  /* If {pref,alt}class have already been allocated, update the pointers to
-     the newly realloced ones.  */
-  if (reg_pref)
-    reg_pref = reg_pref_buffer;
-
-  if (renumber_p)
-    reg_renumber = renumber;
-}
-
 /* Free up the space allocated by allocate_reg_info.  */
 void
 free_reg_info (void)
 {
-  if (reg_n_info)
+  if (reg_pref)
     {
-      struct reg_info_data *reg_data;
-      struct reg_info_data *reg_next;
-
-      VEC_free (reg_info_p, heap, reg_n_info);
-      for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
-	{
-	  reg_next = reg_data->next;
-	  free ((char *) reg_data);
-	}
+      free (reg_pref);
+      reg_pref = NULL;
+    }
 
-      free (reg_pref_buffer);
-      reg_pref_buffer = (struct reg_pref *) 0;
-      reg_info_head = (struct reg_info_data *) 0;
-      renumber = (short *) 0;
+  if (reg_renumber)
+    {
+      free (reg_renumber);
+      reg_renumber = NULL;
     }
-  regno_allocated = 0;
-  reg_n_max = 0;
 }
 
-/* Clear the information stored for REGNO.  */
-void
-clear_reg_info_regno (unsigned int regno)
-{
-  if (regno < regno_allocated)
-    memset (VEC_index (reg_info_p, reg_n_info, regno), 0, sizeof (reg_info));
-}
 
-/* This is the `regscan' pass of the compiler, run just before cse
-   and again just before loop.
-
-   It finds the first and last use of each pseudo-register
-   and counts the number of sets in the vector reg_n_sets.
-
-   REPEAT is nonzero the second time this is called.  */
+/* This is the `regscan' pass of the compiler, run just before cse and
+   again just before loop.  It finds the first and last use of each
+   pseudo-register.  */
 
 void
-reg_scan (rtx f, unsigned int nregs)
+reg_scan (rtx f, unsigned int nregs ATTRIBUTE_UNUSED)
 {
   rtx insn;
 
   timevar_push (TV_REG_SCAN);
 
-  allocate_reg_info (nregs, TRUE, FALSE);
   for (insn = f; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn))
       {
@@ -2465,7 +2300,7 @@ reg_scan_mark_refs (rtx x, rtx insn)
 	     union in two threads of control in the presence of global
 	     optimizations).  So only set REG_POINTER on the destination
 	     pseudo if this is the only set of that pseudo.  */
-	  && REG_N_SETS (REGNO (SET_DEST (x))) == 1
+	  && DF_REG_DEF_COUNT (REGNO (SET_DEST (x))) == 1
 	  && ! REG_USERVAR_P (SET_DEST (x))
 	  && ! REG_POINTER (SET_DEST (x))
 	  && ((REG_P (SET_SRC (x))
Index: combine.c
===================================================================
--- combine.c	(revision 124521)
+++ combine.c	(working copy)
@@ -2997,7 +2997,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 	      if (REG_P (new_i3_dest)
 		  && REG_P (new_i2_dest)
 		  && REGNO (new_i3_dest) == REGNO (new_i2_dest))
-		REG_N_SETS (REGNO (new_i2_dest))++;
+		INC_REG_N_SETS (REGNO (new_i2_dest), 1);
 	    }
 	}
 
@@ -3317,18 +3317,9 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 
 	  if (REG_NOTE_KIND (note) == REG_UNUSED
 	      && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
-	    {
-	      if (REG_P (XEXP (note, 0)))
-		REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
-
-	      remove_note (undobuf.other_insn, note);
-	    }
+	    remove_note (undobuf.other_insn, note);
 	}
 
-      for (note = new_other_notes; note; note = XEXP (note, 1))
-	if (REG_P (XEXP (note, 0)))
-	  REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
-
       distribute_notes (new_other_notes, undobuf.other_insn,
 			undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
     }
@@ -3555,26 +3546,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 
     /* Distribute any notes added to I2 or I3 by recog_for_combine.  We
        know these are REG_UNUSED and want them to go to the desired insn,
-       so we always pass it as i3.  We have not counted the notes in
-       reg_n_deaths yet, so we need to do so now.  */
+       so we always pass it as i3.  */
 
     if (newi2pat && new_i2_notes)
-      {
-	for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
-	  if (REG_P (XEXP (temp, 0)))
-	    REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
-
-	distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
-      }
-
+      distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
+    
     if (new_i3_notes)
-      {
-	for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
-	  if (REG_P (XEXP (temp, 0)))
-	    REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
-
-	distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
-      }
+      distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
 
     /* If I3DEST was used in I3SRC, it really died in I3.  We may need to
        put a REG_DEAD note for it somewhere.  If NEWI2PAT exists and sets
@@ -3585,9 +3563,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 
     if (i3dest_killed)
       {
-	if (REG_P (i3dest_killed))
-	  REG_N_DEATHS (REGNO (i3dest_killed))++;
-
 	if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
 	  distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
 					       NULL_RTX),
@@ -3601,9 +3576,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 
     if (i2dest_in_i2src)
       {
-	if (REG_P (i2dest))
-	  REG_N_DEATHS (REGNO (i2dest))++;
-
 	if (newi2pat && reg_set_p (i2dest, newi2pat))
 	  distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
 			    NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
@@ -3615,9 +3587,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 
     if (i1dest_in_i1src)
       {
-	if (REG_P (i1dest))
-	  REG_N_DEATHS (REGNO (i1dest))++;
-
 	if (newi2pat && reg_set_p (i1dest, newi2pat))
 	  distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
 			    NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
@@ -3658,7 +3627,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 	    && ! i2dest_in_i2src)
 	  {
 	    regno = REGNO (i2dest);
-	    REG_N_SETS (regno)--;
+	    INC_REG_N_SETS (regno, -1);
 	  }
       }
 
@@ -3676,7 +3645,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 
 	regno = REGNO (i1dest);
 	if (! added_sets_1 && ! i1dest_in_i1src)
-	  REG_N_SETS (regno)--;
+	  INC_REG_N_SETS (regno, -1);
       }
 
     /* Update reg_stat[].nonzero_bits et al for any changes that may have
@@ -12001,10 +11970,7 @@ remove_death (unsigned int regno, rtx in
   rtx note = find_regno_note (insn, REG_DEAD, regno);
 
   if (note)
-    {
-      REG_N_DEATHS (regno)--;
-      remove_note (insn, note);
-    }
+    remove_note (insn, note);
 
   return note;
 }
@@ -12106,8 +12072,6 @@ move_deaths (rtx x, rtx maybe_kill_insn,
 	    }
 	  else
 	    *pnotes = gen_rtx_EXPR_LIST (REG_DEAD, x, *pnotes);
-
-	  REG_N_DEATHS (regno)++;
 	}
 
       return;
@@ -12774,23 +12738,11 @@ distribute_notes (rtx notes, rtx from_in
 	  XEXP (note, 1) = REG_NOTES (place);
 	  REG_NOTES (place) = note;
 	}
-      else if ((REG_NOTE_KIND (note) == REG_DEAD
-		|| REG_NOTE_KIND (note) == REG_UNUSED)
-	       && REG_P (XEXP (note, 0)))
-	REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
 
       if (place2)
-	{
-	  if ((REG_NOTE_KIND (note) == REG_DEAD
-	       || REG_NOTE_KIND (note) == REG_UNUSED)
-	      && REG_P (XEXP (note, 0)))
-	    REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
-
-	  REG_NOTES (place2) = gen_rtx_fmt_ee (GET_CODE (note),
-					       REG_NOTE_KIND (note),
-					       XEXP (note, 0),
-					       REG_NOTES (place2));
-	}
+	REG_NOTES (place2) 
+	  = gen_rtx_fmt_ee (GET_CODE (note), REG_NOTE_KIND (note),
+			    XEXP (note, 0), REG_NOTES (place2));
     }
 }
 
@@ -12943,9 +12895,11 @@ rest_of_handle_combine (void)
   int rebuild_jump_labels_after_combine;
 
   df_set_flags (DF_LR_RUN_DCE + DF_DEFER_INSN_RESCAN);
-  df_ri_add_problem (DF_RI_LIFE);
+  df_note_add_problem ();
   df_analyze ();
 
+  regstat_init_n_sets_and_refs ();
+
   rebuild_jump_labels_after_combine
     = combine_instructions (get_insns (), max_reg_num ());
 
@@ -12960,6 +12914,7 @@ rest_of_handle_combine (void)
       timevar_pop (TV_JUMP);
     }
 
+  regstat_free_n_sets_and_refs ();
   return 0;
 }
 
Index: bb-reorder.c
===================================================================
--- bb-reorder.c	(revision 124521)
+++ bb-reorder.c	(working copy)
@@ -2258,7 +2258,6 @@ rest_of_handle_partition_blocks (void)
 {
   no_new_pseudos = 0;
   partition_hot_cold_basic_blocks ();
-  allocate_reg_life_data ();
   no_new_pseudos = 1;
   return 0;
 }
Index: df-problems.c
===================================================================
--- df-problems.c	(revision 124521)
+++ df-problems.c	(working copy)
@@ -3629,10 +3629,6 @@ static struct df_problem problem_CHAIN =
 };
 
 
-/* Indexed by n, giving various register information */
-
-VEC(reg_info_p,heap) *reg_n_info;
-
 /* Create a new DATAFLOW instance and add it to an existing instance
    of DF.  The returned structure is what is used to get at the
    solution.  */
@@ -3647,31 +3643,14 @@ df_chain_add_problem (enum df_chain_flag
 
 #undef df_chain_problem_p
 
-
 
 /*----------------------------------------------------------------------------
-   REGISTER INFORMATION
-
-   This pass properly computes REG_DEAD and REG_UNUSED notes.
-
-   If the DF_RI_LIFE flag is set the following vectors containing
-   information about register usage are properly set: REG_N_REFS,
-   REG_N_DEATHS, REG_N_SETS, REG_LIVE_LENGTH, REG_N_CALLS_CROSSED,
-   REG_N_THROWING_CALLS_CROSSED and REG_BASIC_BLOCK.
-
+   This pass computes REG_DEAD and REG_UNUSED notes.
    ----------------------------------------------------------------------------*/
 
-#define df_ri_problem_p(FLAG) (((enum df_ri_flags)df_ri->local_flags)&(FLAG))
-
-struct df_ri_problem_data
-{
-  bitmap setjmp_crosses;
-};
-
-
 #ifdef REG_DEAD_DEBUGGING
 static void 
-print_note (const char *prefix, rtx insn, rtx note)
+df_print_note (const char *prefix, rtx insn, rtx note)
 {
   if (dump_file)
     {
@@ -3683,53 +3662,6 @@ print_note (const char *prefix, rtx insn
 #endif
 
 
-/* Allocate the lifetime information.  */
-
-static void 
-df_ri_alloc (bitmap all_blocks ATTRIBUTE_UNUSED)
-{
-  int i;
-  struct df_ri_problem_data *problem_data =
-    (struct df_ri_problem_data *) df_ri->problem_data;
-
-  df_grow_reg_info ();
-
-  if (!df_ri->problem_data)
-    {
-      problem_data = XNEW (struct df_ri_problem_data);
-      df_ri->problem_data = problem_data;
-      problem_data->setjmp_crosses = NULL;
-    }
-
-  if (df_ri_problem_p (DF_RI_SETJMP))
-    {
-      if (problem_data->setjmp_crosses)
-	bitmap_clear (problem_data->setjmp_crosses);
-      else 
-	problem_data->setjmp_crosses = BITMAP_ALLOC (&df_bitmap_obstack);
-    }
-
-  if (df_ri_problem_p (DF_RI_LIFE))
-    {
-      max_regno = max_reg_num ();
-      allocate_reg_info (max_regno, FALSE, FALSE);
-      
-      /* Reset all the data we'll collect.  */
-      for (i = 0; i < max_regno; i++)
-	{
-	  REG_N_SETS (i) = DF_REG_DEF_COUNT (i);
-	  REG_N_REFS (i) = DF_REG_USE_COUNT (i) + REG_N_SETS (i);
-	  REG_N_DEATHS (i) = 0;
-	  REG_N_CALLS_CROSSED (i) = 0;
-	  REG_N_THROWING_CALLS_CROSSED (i) = 0;
-	  REG_LIVE_LENGTH (i) = 0;
-	  REG_FREQ (i) = 0;
-	  REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
-	}
-    }
-}
-
-
 /* After reg-stack, the x86 floating point stack regs are difficult to
    analyze because of all of the pushes, pops and rotations.  Thus, we
    just leave the notes alone. */
@@ -3754,8 +3686,7 @@ df_ignore_stack_reg (int regno ATTRIBUTE
    them to OLD_DEAD_NOTES and OLD_UNUSED_NOTES.  */
 
 static void
-df_kill_notes (rtx insn, rtx *old_dead_notes, rtx *old_unused_notes,
-	       enum df_ri_flags flags)
+df_kill_notes (rtx insn, rtx *old_dead_notes, rtx *old_unused_notes)
 {
   rtx *pprev = &REG_NOTES (insn);
   rtx link = *pprev;
@@ -3771,8 +3702,6 @@ df_kill_notes (rtx insn, rtx *old_dead_n
 	     for the stack registers.  */
 	  if (df_ignore_stack_reg (REGNO (XEXP (link, 0))))
 	    {
-	      if (flags & DF_RI_LIFE)
-		REG_N_DEATHS (REGNO (XEXP (link, 0)))++;
 	      pprev = &XEXP (link, 1);
 	      link = *pprev;
 	    }
@@ -3780,7 +3709,7 @@ df_kill_notes (rtx insn, rtx *old_dead_n
 	    {
 	      rtx next = XEXP (link, 1);
 #ifdef REG_DEAD_DEBUGGING
-	      print_note ("deleting: ", insn, link);
+	      df_print_note ("deleting: ", insn, link);
 #endif
 	      XEXP (link, 1) = dead;
 	      dead = link;
@@ -3800,7 +3729,7 @@ df_kill_notes (rtx insn, rtx *old_dead_n
 	    {
 	      rtx next = XEXP (link, 1);
 #ifdef REG_DEAD_DEBUGGING
-	      print_note ("deleting: ", insn, link);
+	      df_print_note ("deleting: ", insn, link);
 #endif
 	      XEXP (link, 1) = unused;
 	      unused = link;
@@ -3823,7 +3752,7 @@ df_kill_notes (rtx insn, rtx *old_dead_n
 /* Set a NOTE_TYPE note for REG in INSN.  Try to pull it from the OLD
    list, otherwise create a new one.  */
 
-static rtx
+static inline rtx
 df_set_note (enum reg_note note_type, rtx insn, rtx old, rtx reg)
 {
   rtx this = old;
@@ -3861,7 +3790,7 @@ df_set_note (enum reg_note note_type, rt
 static rtx
 df_set_unused_notes_for_mw (rtx insn, rtx old, struct df_mw_hardreg *mws,
 			    bitmap live, bitmap do_not_gen, 
-			    bitmap artificial_uses, enum df_ri_flags flags)
+			    bitmap artificial_uses)
 {
   bool all_dead = true;
   unsigned int r;
@@ -3885,15 +3814,10 @@ df_set_unused_notes_for_mw (rtx insn, rt
       old = df_set_note (REG_UNUSED, insn, old, *(mws->loc));
 
 #ifdef REG_DEAD_DEBUGGING
-      print_note ("adding 1: ", insn, REG_NOTES (insn));
+      df_print_note ("adding 1: ", insn, REG_NOTES (insn));
 #endif
       bitmap_set_bit (do_not_gen, regno);
       /* Only do this if the value is totally dead.  */
-      if (flags & DF_RI_LIFE)
-	{
-	  REG_N_DEATHS (regno) ++;
-	  REG_LIVE_LENGTH (regno)++;
-	}
     }
   else
     for (r=mws->start_regno; r <= mws->end_regno; r++)
@@ -3904,7 +3828,7 @@ df_set_unused_notes_for_mw (rtx insn, rt
 	  {
 	    old = df_set_note (REG_UNUSED, insn, old, regno_reg_rtx[r]);
 #ifdef REG_DEAD_DEBUGGING
-	    print_note ("adding 2: ", insn, REG_NOTES (insn));
+	    df_print_note ("adding 2: ", insn, REG_NOTES (insn));
 #endif
 	  }
 	bitmap_set_bit (do_not_gen, r);
@@ -3921,7 +3845,7 @@ df_set_unused_notes_for_mw (rtx insn, rt
 static rtx
 df_set_dead_notes_for_mw (rtx insn, rtx old, struct df_mw_hardreg *mws,
 			  bitmap live, bitmap do_not_gen,
-			  bitmap artificial_uses, enum df_ri_flags flags)
+			  bitmap artificial_uses)
 {
   bool all_dead = true;
   unsigned int r;
@@ -3955,12 +3879,8 @@ df_set_dead_notes_for_mw (rtx insn, rtx 
 	  /* Add a dead note for the entire multi word register.  */
 	  old = df_set_note (REG_DEAD, insn, old, *(mws->loc));
 #ifdef REG_DEAD_DEBUGGING
-	  print_note ("adding 1: ", insn, REG_NOTES (insn));
+	  df_print_note ("adding 1: ", insn, REG_NOTES (insn));
 #endif
-
-	  if (flags & DF_RI_LIFE)
-	    for (r = mws->start_regno; r <= mws->end_regno; r++)
-	      REG_N_DEATHS (r)++;
 	}
     }
   else
@@ -3972,10 +3892,8 @@ df_set_dead_notes_for_mw (rtx insn, rtx 
 	      && (!bitmap_bit_p (do_not_gen, r)))
 	    {
 	      old = df_set_note (REG_DEAD, insn, old, regno_reg_rtx[r]);
-	      if (flags & DF_RI_LIFE)
-		REG_N_DEATHS (r)++;
 #ifdef REG_DEAD_DEBUGGING
-	      print_note ("adding 2: ", insn, REG_NOTES (insn));
+	      df_print_note ("adding 2: ", insn, REG_NOTES (insn));
 #endif
 	    }
 	}
@@ -3989,10 +3907,8 @@ df_set_dead_notes_for_mw (rtx insn, rtx 
    uses.  */
 
 static rtx
-df_create_unused_note (basic_block bb, rtx insn, rtx old, struct df_ref *def, 
-		       bitmap live, bitmap do_not_gen, bitmap artificial_uses, 
-		       bitmap local_live, bitmap local_processed, 
-		       enum df_ri_flags flags, int luid)
+df_create_unused_note (rtx insn, rtx old, struct df_ref *def, 
+		       bitmap live, bitmap do_not_gen, bitmap artificial_uses)
 {
   unsigned int dregno = DF_REF_REGNO (def);
   
@@ -4004,52 +3920,19 @@ df_create_unused_note (basic_block bb, r
     }
 #endif
 
-  if (bitmap_bit_p (live, dregno))
-    {
-      if (flags & DF_RI_LIFE)
-	{
-	  /* If we have seen this regno, then it has already been
-	     processed correctly with the per insn increment.  If we
-	     have not seen it we need to add the length from here to
-	     the end of the block to the live length.  */
-	  if (bitmap_bit_p (local_processed, dregno))
-	    {
-	      if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
-		bitmap_clear_bit (local_live, dregno);
-	    }
-	  else
-	    {
-	      bitmap_set_bit (local_processed, dregno);
-	      REG_LIVE_LENGTH (dregno) += luid;
-	    }
-	}
-    }
-  else if ((!(DF_REF_FLAGS (def) & DF_REF_MW_HARDREG))
-	    && (!bitmap_bit_p (artificial_uses, dregno)) 
-	    && (!df_ignore_stack_reg (dregno)))
+  if (!(bitmap_bit_p (live, dregno)
+	|| (DF_REF_FLAGS (def) & DF_REF_MW_HARDREG)
+	|| bitmap_bit_p (artificial_uses, dregno)
+	|| df_ignore_stack_reg (dregno)))
     {
       rtx reg = (DF_REF_LOC (def)) 
                 ? *DF_REF_REAL_LOC (def): DF_REF_REG (def);
       old = df_set_note (REG_UNUSED, insn, old, reg);
 #ifdef REG_DEAD_DEBUGGING
-      print_note ("adding 3: ", insn, REG_NOTES (insn));
+      df_print_note ("adding 3: ", insn, REG_NOTES (insn));
 #endif
-      if (flags & DF_RI_LIFE)
-	{
-	  REG_N_DEATHS (dregno) ++;
-	  REG_LIVE_LENGTH (dregno)++;
-	}
     }
   
-  if ((flags & DF_RI_LIFE) && (dregno >= FIRST_PSEUDO_REGISTER))
-    {
-      REG_FREQ (dregno) += REG_FREQ_FROM_BB (bb);
-      if (REG_BASIC_BLOCK (dregno) == REG_BLOCK_UNKNOWN)
-	REG_BASIC_BLOCK (dregno) = bb->index;
-      else if (REG_BASIC_BLOCK (dregno) != bb->index)
-	REG_BASIC_BLOCK (dregno) = REG_BLOCK_GLOBAL;
-    }
-
   if (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER + DF_REF_MAY_CLOBBER)))
     bitmap_set_bit (do_not_gen, dregno);
   
@@ -4065,15 +3948,13 @@ df_create_unused_note (basic_block bb, r
    BB.  The three bitvectors are scratch regs used here.  */
 
 static void
-df_ri_bb_compute (unsigned int bb_index, 
-		  bitmap live, bitmap do_not_gen, bitmap artificial_uses,
-		  bitmap local_live, bitmap local_processed, bitmap setjmp_crosses)
+df_note_bb_compute (unsigned int bb_index, 
+		  bitmap live, bitmap do_not_gen, bitmap artificial_uses)
 {
   basic_block bb = BASIC_BLOCK (bb_index);
   rtx insn;
   struct df_ref **def_rec;
   struct df_ref **use_rec;
-  int luid = 0;
 
   bitmap_copy (live, df_get_live_out (bb));
   bitmap_clear (artificial_uses);
@@ -4086,16 +3967,6 @@ df_ri_bb_compute (unsigned int bb_index,
     }
 #endif
 
-  if (df_ri_problem_p (DF_RI_LIFE))
-    {
-      /* Process the regs live at the end of the block.  Mark them as
-	 not local to any one basic block.  */
-      bitmap_iterator bi;
-      unsigned int regno;
-      EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
-	REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
-    }
-
   /* Process the artificial defs and uses at the bottom of the block
      to begin processing.  */
   for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
@@ -4133,8 +4004,6 @@ df_ri_bb_compute (unsigned int bb_index,
   FOR_BB_INSNS_REVERSE (bb, insn)
     {
       unsigned int uid = INSN_UID (insn);
-      unsigned int regno;
-      bitmap_iterator bi;
       struct df_mw_hardreg **mws_rec;
       rtx old_dead_notes;
       rtx old_unused_notes;
@@ -4142,23 +4011,8 @@ df_ri_bb_compute (unsigned int bb_index,
       if (!INSN_P (insn))
 	continue;
 
-      if (df_ri_problem_p (DF_RI_LIFE))
-	{
-	  /* Increment the live_length for all of the registers that
-	     are are referenced in this block and live at this
-	     particular point.  */
-	  bitmap_iterator bi;
-	  unsigned int regno;
-	  EXECUTE_IF_SET_IN_BITMAP (local_live, 0, regno, bi)
-	    {
-	      REG_LIVE_LENGTH (regno)++;
-	    }
-	  luid++;
-	}
-
       bitmap_clear (do_not_gen);
-      df_kill_notes (insn, &old_dead_notes, &old_unused_notes, 
-		     (enum df_ri_flags)df_ri->local_flags);
+      df_kill_notes (insn, &old_dead_notes, &old_unused_notes);
 
       /* Process the defs.  */
       if (CALL_P (insn))
@@ -4170,34 +4024,6 @@ df_ri_bb_compute (unsigned int bb_index,
 	      df_print_regset (dump_file, live);
 	    }
 #endif
-	  if (df_ri_problem_p (DF_RI_LIFE | DF_RI_SETJMP))
-	    {
-	      bool can_throw = can_throw_internal (insn); 
-	      bool set_jump = (find_reg_note (insn, REG_SETJMP, NULL) != NULL);
-	      EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
-		{
-		  if (df_ri_problem_p (DF_RI_LIFE))
-		    {
-		      REG_N_CALLS_CROSSED (regno)++;
-		      if (can_throw)
-			REG_N_THROWING_CALLS_CROSSED (regno)++;
-		    }
-		  /* We have a problem with any pseudoreg that lives
-		     across the setjmp.  ANSI says that if a user
-		     variable does not change in value between the
-		     setjmp and the longjmp, then the longjmp
-		     preserves it.  This includes longjmp from a place
-		     where the pseudo appears dead.  (In principle,
-		     the value still exists if it is in scope.)  If
-		     the pseudo goes in a hard reg, some other value
-		     may occupy that hard reg where this pseudo is
-		     dead, thus clobbering the pseudo.  Conclusion:
-		     such a pseudo must not go in a hard reg.  */
-		  if (set_jump)
-		    bitmap_set_bit (setjmp_crosses, regno);
-		}
-	    }
-	  
 	  /* We only care about real sets for calls.  Clobbers only
 	     may clobbers cannot be depended on.  */
 	  mws_rec = DF_INSN_UID_MWS (uid);
@@ -4209,8 +4035,7 @@ df_ri_bb_compute (unsigned int bb_index,
 		old_unused_notes 
 		  = df_set_unused_notes_for_mw (insn, old_unused_notes, 
 						mws, live, do_not_gen, 
-						artificial_uses, 
-						(enum df_ri_flags)df_ri->local_flags);
+						artificial_uses);
 	      mws_rec++;
 	    }
 
@@ -4221,11 +4046,9 @@ df_ri_bb_compute (unsigned int bb_index,
 	      struct df_ref *def = *def_rec;
 	      if (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER)))
 		old_unused_notes
-		  = df_create_unused_note (bb, insn, old_unused_notes, 
+		  = df_create_unused_note (insn, old_unused_notes, 
 					   def, live, do_not_gen, 
-					   artificial_uses, local_live, 
-					   local_processed, 
-					   (enum df_ri_flags)df_ri->local_flags, luid);
+					   artificial_uses);
 	    }
 	}
       else
@@ -4239,8 +4062,7 @@ df_ri_bb_compute (unsigned int bb_index,
 		old_unused_notes
 		  = df_set_unused_notes_for_mw (insn, old_unused_notes, 
 						mws, live, do_not_gen, 
-						artificial_uses, 
-						(enum df_ri_flags)df_ri->local_flags);
+						artificial_uses);
 	      mws_rec++;
 	    }
 
@@ -4248,11 +4070,9 @@ df_ri_bb_compute (unsigned int bb_index,
 	    {
 	      struct df_ref *def = *def_rec;
 	      old_unused_notes
-		= df_create_unused_note (bb, insn, old_unused_notes, 
+		= df_create_unused_note (insn, old_unused_notes, 
 					 def, live, do_not_gen, 
-					 artificial_uses, local_live, 
-					 local_processed, 
-					 (enum df_ri_flags)df_ri->local_flags, luid);
+					 artificial_uses);
 	    }
 	}
       
@@ -4266,8 +4086,7 @@ df_ri_bb_compute (unsigned int bb_index,
 	    old_dead_notes
 	      = df_set_dead_notes_for_mw (insn, old_dead_notes, 
 					  mws, live, do_not_gen,
-					  artificial_uses, 
-					  (enum df_ri_flags)df_ri->local_flags);
+					  artificial_uses);
 	  mws_rec++;
 	}
 
@@ -4276,15 +4095,6 @@ df_ri_bb_compute (unsigned int bb_index,
 	  struct df_ref *use = *use_rec;
 	  unsigned int uregno = DF_REF_REGNO (use);
 
-	  if (df_ri_problem_p (DF_RI_LIFE) && (uregno >= FIRST_PSEUDO_REGISTER))
-	    {
-	      REG_FREQ (uregno) += REG_FREQ_FROM_BB (bb);
-	      if (REG_BASIC_BLOCK (uregno) == REG_BLOCK_UNKNOWN)
-		REG_BASIC_BLOCK (uregno) = bb->index;
-	      else if (REG_BASIC_BLOCK (uregno) != bb->index)
-		REG_BASIC_BLOCK (uregno) = REG_BLOCK_GLOBAL;
-	    }
-	  
 #ifdef REG_DEAD_DEBUGGING
 	  if (dump_file)
 	    {
@@ -4303,30 +4113,13 @@ df_ri_bb_compute (unsigned int bb_index,
 		  rtx reg = (DF_REF_LOC (use)) 
                             ? *DF_REF_REAL_LOC (use) : DF_REF_REG (use);
 		  old_dead_notes = df_set_note (REG_DEAD, insn, old_dead_notes, reg);
-		  if (df_ri_problem_p (DF_RI_LIFE))
-		    REG_N_DEATHS (uregno)++;
 
 #ifdef REG_DEAD_DEBUGGING
-		  print_note ("adding 4: ", insn, REG_NOTES (insn));
+		  df_print_note ("adding 4: ", insn, REG_NOTES (insn));
 #endif
 		}
 	      /* This register is now live.  */
 	      bitmap_set_bit (live, uregno);
-
-	      if (df_ri_problem_p (DF_RI_LIFE))
-		{
-		  /* If we have seen this regno, then it has already
-		     been processed correctly with the per insn
-		     increment.  If we have not seen it we set the bit
-		     so that begins to get processed locally.  Note
-		     that we don't even get here if the variable was
-		     live at the end of the block since just a ref
-		     inside the block does not effect the
-		     calculations.  */
-		  REG_LIVE_LENGTH (uregno) ++;
-		  bitmap_set_bit (local_live, uregno);
-		  bitmap_set_bit (local_processed, uregno);
-		}
 	    }
 	}
 
@@ -4343,51 +4136,18 @@ df_ri_bb_compute (unsigned int bb_index,
 	  old_dead_notes = next;
 	}
     }
-  
-  if (df_ri_problem_p (DF_RI_LIFE))
-    {
-      /* Add the length of the block to all of the registers that were
-	 not referenced, but still live in this block.  */
-      bitmap_iterator bi;
-      unsigned int regno;
-      bitmap_and_compl_into (live, local_processed);
-      EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
-	{
-	  REG_LIVE_LENGTH (regno) += luid;
-	}
-      bitmap_clear (local_processed);
-      bitmap_clear (local_live);
-    }
 }
 
 
 /* Compute register info: lifetime, bb, and number of defs and uses.  */
 static void
-df_ri_compute (bitmap all_blocks)
+df_note_compute (bitmap all_blocks)
 {
   unsigned int bb_index;
   bitmap_iterator bi;
   bitmap live = BITMAP_ALLOC (&df_bitmap_obstack);
   bitmap do_not_gen = BITMAP_ALLOC (&df_bitmap_obstack);
   bitmap artificial_uses = BITMAP_ALLOC (&df_bitmap_obstack);
-  bitmap local_live = NULL;
-  bitmap local_processed = NULL;
-  bitmap setjmp_crosses = NULL;
-  struct df_ri_problem_data *problem_data =
-    (struct df_ri_problem_data *) df_ri->problem_data;
-
-  if (df_ri_problem_p (DF_RI_LIFE))
-    {
-      local_live = BITMAP_ALLOC (&df_bitmap_obstack);
-      local_processed = BITMAP_ALLOC (&df_bitmap_obstack);
-      if (df_ri_problem_p (DF_RI_SETJMP))
-	setjmp_crosses = problem_data->setjmp_crosses;
-      else
-	setjmp_crosses = BITMAP_ALLOC (&df_bitmap_obstack);
-    }
-  else if (df_ri_problem_p (DF_RI_SETJMP))
-    setjmp_crosses = problem_data->setjmp_crosses;
-
 
 #ifdef REG_DEAD_DEBUGGING
   if (dump_file)
@@ -4396,80 +4156,43 @@ df_ri_compute (bitmap all_blocks)
 
   EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
   {
-    df_ri_bb_compute (bb_index, live, do_not_gen, artificial_uses,
-		      local_live, local_processed, setjmp_crosses);
+    df_note_bb_compute (bb_index, live, do_not_gen, artificial_uses);
   }
 
   BITMAP_FREE (live);
   BITMAP_FREE (do_not_gen);
   BITMAP_FREE (artificial_uses);
-  if (df_ri_problem_p (DF_RI_LIFE))
-    {
-      bitmap_iterator bi;
-      unsigned int regno;
-      /* See the setjmp comment in df_ri_bb_compute.  */
-      EXECUTE_IF_SET_IN_BITMAP (setjmp_crosses, FIRST_PSEUDO_REGISTER, 
-				regno, bi)
-	{
-	  REG_BASIC_BLOCK (regno) = REG_BLOCK_UNKNOWN;
-	  REG_LIVE_LENGTH (regno) = -1;
-	}	  
-
-      BITMAP_FREE (local_live);
-      BITMAP_FREE (local_processed);
-      if (!df_ri_problem_p (DF_RI_SETJMP))
-	BITMAP_FREE (setjmp_crosses);
-    }
 }
 
 
 /* Free all storage associated with the problem.  */
 
 static void
-df_ri_free (void)
+df_note_free (void)
 {
-  struct df_ri_problem_data *problem_data =
-    (struct df_ri_problem_data *) df_ri->problem_data;
-
-  if (df_ri_problem_p (DF_RI_SETJMP))
-    BITMAP_FREE (problem_data->setjmp_crosses);
-
-  free (df_ri->problem_data);
-  free (df_ri);
+  free (df_note);
 }
 
 
-/* Debugging info.  */
-
-static void
-df_ri_start_dump (FILE *file)
-{
-  if (df_ri_problem_p (DF_RI_LIFE))
-    {
-      fprintf (file, ";; Register info:\n");
-      dump_reg_info (file);
-    }
-}
-
 /* All of the information associated every instance of the problem.  */
 
-static struct df_problem problem_RI =
+static struct df_problem problem_NOTE =
 {
-  DF_RI,                      /* Problem id.  */
+  DF_NOTE,                    /* Problem id.  */
   DF_NONE,                    /* Direction.  */
-  df_ri_alloc,                /* Allocate the problem specific data.  */
+  NULL,                       /* Allocate the problem specific data.  */
   NULL,                       /* Reset global information.  */
   NULL,                       /* Free basic block info.  */
-  df_ri_compute,              /* Local compute function.  */
+  df_note_compute,            /* Local compute function.  */
   NULL,                       /* Init the solution specific data.  */
   NULL,                       /* Iterative solver.  */
   NULL,                       /* Confluence operator 0.  */ 
   NULL,                       /* Confluence operator n.  */ 
   NULL,                       /* Transfer function.  */
   NULL,                       /* Finalize function.  */
-  df_ri_free,                 /* Free all of the problem information.  */
-  df_ri_free,                 /* Remove this problem from the stack of dataflow problems.  */
-  df_ri_start_dump,           /* Debugging.  */
+  df_note_free,               /* Free all of the problem information.  */
+  df_note_free,               /* Remove this problem from the stack of dataflow problems.  */
+  NULL,                       /* Debugging.  */
   NULL,                       /* Debugging start block.  */
   NULL,                       /* Debugging end block.  */
   NULL,                       /* Incremental solution verify start.  */
@@ -4479,7 +4202,7 @@ static struct df_problem problem_RI =
      but it will produce information if built one of uninitialized
      register problems (UR, UREC) is also run.  */
   &problem_LR,                /* Dependent problem.  */
-  TV_DF_RI                    /* Timing variable.  */ 
+  TV_DF_NOTE                  /* Timing variable.  */ 
 };
 
 
@@ -4488,23 +4211,9 @@ static struct df_problem problem_RI =
    solution.  */
 
 void
-df_ri_add_problem (enum df_ri_flags flags)
+df_note_add_problem (void)
 {
-  df_add_problem (&problem_RI);
-  df_ri->local_flags = (unsigned int)flags;
+  df_add_problem (&problem_NOTE);
 }
 
 
-/* Return a bitmap containing the set of registers that cross a setjmp.  
-   The client should not change or delete this bitmap.  */
-
-bitmap
-df_ri_get_setjmp_crosses (void)
-{
-  struct df_ri_problem_data *problem_data =
-    (struct df_ri_problem_data *) df_ri->problem_data;
-
-  return problem_data->setjmp_crosses;
-}
-
-#undef df_ri_problem_p
Index: reg-stack.c
===================================================================
--- reg-stack.c	(revision 124521)
+++ reg-stack.c	(working copy)
@@ -3125,7 +3125,7 @@ reg_to_stack (void)
   if (i > LAST_STACK_REG)
     return false;
 
-  df_ri_add_problem (0);
+  df_note_add_problem ();
   df_analyze ();
 
   mark_dfs_back_edges ();
Index: combine-stack-adj.c
===================================================================
--- combine-stack-adj.c	(revision 124521)
+++ combine-stack-adj.c	(working copy)
@@ -465,7 +465,7 @@ rest_of_handle_stack_adjustments (void)
   if (!ACCUMULATE_OUTGOING_ARGS)
 #endif
     {
-      df_ri_add_problem (0);
+      df_note_add_problem ();
       df_analyze ();
       combine_stack_adjustments ();
     }
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 124521)
+++ Makefile.in	(working copy)
@@ -1060,6 +1060,7 @@ OBJS-common = \
 	regclass.o \
 	regmove.o \
 	regrename.o \
+	regstat.o \
 	reload.o \
 	reload1.o \
 	reorg.o \
@@ -2499,6 +2500,9 @@ df-scan.o : df-scan.c $(CONFIG_H) $(SYST
    insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h \
    hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) bitmap.h sbitmap.h $(TM_P_H) \
    $(FLAGS_H) $(TARGET_H) $(TARGET_DEF_H) $(TREE_H) output.h tree-pass.h
+regstat.o : regstat.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
+   $(TM_P_H) $(FLAGS_H) $(REGS_H) output.h except.h hard-reg-set.h \
+   $(BASIC_BLOCK_H) $(TIMEVAR_H) $(DF_H)
 var-tracking.o : var-tracking.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(RTL_H) $(TREE_H) hard-reg-set.h insn-config.h reload.h $(FLAGS_H) \
    $(BASIC_BLOCK_H) output.h sbitmap.h alloc-pool.h $(FIBHEAP_H) $(HASHTAB_H) \
Index: sched-rgn.c
===================================================================
--- sched-rgn.c	(revision 124521)
+++ sched-rgn.c	(working copy)
@@ -2887,8 +2887,9 @@ schedule_insns (void)
   current_sched_info = &region_sched_info;
 
   df_set_flags (DF_LR_RUN_DCE);
-  df_ri_add_problem (DF_RI_LIFE);
+  df_note_add_problem ();
   df_analyze ();
+  regstat_compute_calls_crossed ();
 
   sched_init ();
 
@@ -2934,6 +2935,8 @@ schedule_insns (void)
   free (block_to_bb);
   free (containing_rgn);
 
+  regstat_free_calls_crossed ();
+
   bitmap_clear (&not_in_df);
 
   sched_finish ();
Index: basic-block.h
===================================================================
--- basic-block.h	(revision 124521)
+++ basic-block.h	(working copy)
@@ -464,18 +464,6 @@ struct control_flow_graph GTY(())
 
 extern bitmap_obstack reg_obstack;
 
-/* Indexed by n, gives number of basic block that  (REG n) is used in.
-   If the value is REG_BLOCK_GLOBAL (-2),
-   it means (REG n) is used in more than one basic block.
-   REG_BLOCK_UNKNOWN (-1) means it hasn't been seen yet so we don't know.
-   This information remains valid for the rest of the compilation
-   of the current function; it is used to control register allocation.  */
-
-#define REG_BLOCK_UNKNOWN -1
-#define REG_BLOCK_GLOBAL -2
-
-#define REG_BASIC_BLOCK(N)				\
-  (VEC_index (reg_info_p, reg_n_info, N)->basic_block)
 
 /* Stuff for recording basic block info.  */
 
Index: config/sparc/sparc.c
===================================================================
--- config/sparc/sparc.c	(revision 124521)
+++ config/sparc/sparc.c	(working copy)
@@ -7632,7 +7632,7 @@ sparc_check_64 (rtx x, rtx insn)
     y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
 
   if (flag_expensive_optimizations
-      && REG_N_SETS (REGNO (y)) == 1)
+      && DF_REG_DEF_COUNT (REGNO (y)) == 1)
     set_once = 1;
 
   if (insn == 0)
Index: config/sh/sh.c
===================================================================
--- config/sh/sh.c	(revision 124521)
+++ config/sh/sh.c	(working copy)
@@ -9042,7 +9042,7 @@ flow_dependent_p_1 (rtx x, rtx pat ATTRI
 static int
 sh_pr_n_sets (void)
 {
-  return REG_N_SETS (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG);
+  return DF_REG_DEF_COUNT (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG);
 }
 
 /* Return where to allocate pseudo for a given hard register initial
@@ -9293,12 +9293,6 @@ sh_md_init (FILE *dump ATTRIBUTE_UNUSED,
 static short
 high_pressure (enum machine_mode mode)
 {
-  /* Pressure on register r0 can lead to spill failures. so avoid sched1 for
-     functions that already have high pressure on r0. */
-  if ((REG_N_SETS (0) - REG_N_DEATHS (0)) >= R0_MAX_LIFE_REGIONS
-      && REG_LIVE_LENGTH (0) >= R0_MAX_LIVE_LENGTH)
-    return 1;
-
   if (mode == SFmode)
     return (CURR_REGMODE_PRESSURE (SFmode) > SFMODE_MAX_WEIGHT);
   else
Index: config/m68k/m68k.c
===================================================================
--- config/m68k/m68k.c	(revision 124521)
+++ config/m68k/m68k.c	(working copy)
@@ -4112,7 +4112,6 @@ m68k_output_mi_thunk (FILE *file, tree t
   /* Pretend to be a post-reload pass while generating rtl.  */
   no_new_pseudos = 1;
   reload_completed = 1;
-  allocate_reg_info (FIRST_PSEUDO_REGISTER, true, true);
 
   /* The "this" pointer is stored at 4(%sp).  */
   this_slot = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx, 4));
Index: reload1.c
===================================================================
--- reload1.c	(revision 124521)
+++ reload1.c	(working copy)
@@ -8112,7 +8112,7 @@ delete_output_reload (rtx insn, int j, i
   if (rld[j].out != rld[j].in
       && REG_N_DEATHS (REGNO (reg)) == 1
       && REG_N_SETS (REGNO (reg)) == 1
-      && REG_BASIC_BLOCK (REGNO (reg)) >= 0
+      && REG_BASIC_BLOCK (REGNO (reg)) >= NUM_FIXED_BLOCKS
       && find_regno_note (insn, REG_DEAD, REGNO (reg)))
     {
       rtx i2;


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