Makefile.in (stupid.o): Update dependencies.
authorBernd Schmidt <crux@pool.informatik.rwth-aachen.de>
Tue, 6 Oct 1998 00:39:23 +0000 (18:39 -0600)
committerJeff Law <law@gcc.gnu.org>
Tue, 6 Oct 1998 00:39:23 +0000 (18:39 -0600)
* Makefile.in (stupid.o): Update dependencies.
(global.o): Likewise.
* global.c: Include reload.h
(reg_becomes_live): New function.
(reg_dies): New function.
(build_insn_chain): New function.
(global_alloc): Call build_insn_chain before calling reload.
* reload.h (struct needs): New structure definition.
(struct insn_chain): Likewise.
(reload_insn_chain): Declare variable.
(new_insn_chain): Declare function.
* reload1.c (reload_startobj): New variable.
(reload_insn_chain): New variable.
(unused_insn_chains): New variable.
(new_insn_chain): New function.
(init_reload): Initialize reload_startobj, not reload_firstobj.
(reload): Initialize reload_firstobj.
Before returning, free everything on the reload_obstack.
* stupid.c: Include insn-config.h, reload.h and basic-block.h.
(reg_where_dead_chain, reg_where_born_exact, reg_where_born_clobber,
current_chain): New variables.
(reg_where_born): Delete variable.
(REG_WHERE_BORN): New macro.
(find_clobbered_regs): New function.
(stupid_life_analysis): Don't allocate/free reg_where_born.
Allocate and free reg_where_born_exact, reg_where_born_clobber,
reg_where_dead_chain.
Use REG_WHERE_BORN instead of reg_where_born.
While processing the insns, build the reload_insn_chain with
information about register lifetimes.
(stupid_reg_compare): Use REG_WHERE_BORN instead of reg_where_born.
(stupid_mark_refs): Replace arg INSN with arg CHAIN.  All callers
changed.
Compute and information about birth and death of pseudo registers in
reg_where_dead_chain, reg_where_born_exact and reg_where_born_clobber.
Delete code to set elements of reg_where_born.

From-SVN: r22862

gcc/ChangeLog
gcc/Makefile.in
gcc/global.c
gcc/reload.h
gcc/reload1.c
gcc/stupid.c

index 6ddce689a54af400d33110839dc0a33fa62af295..e50a261eb31912c0bdde06f50d299f4b7d79fa3d 100644 (file)
@@ -1,3 +1,47 @@
+Tue Oct  6 01:36:00 1998  Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>
+
+       * Makefile.in (stupid.o): Update dependencies.
+       (global.o): Likewise.
+
+       * global.c: Include reload.h
+       (reg_becomes_live): New function.
+       (reg_dies): New function.
+       (build_insn_chain): New function.
+       (global_alloc): Call build_insn_chain before calling reload.
+
+       * reload.h (struct needs): New structure definition.
+       (struct insn_chain): Likewise.
+       (reload_insn_chain): Declare variable.
+       (new_insn_chain): Declare function.
+
+
+       * reload1.c (reload_startobj): New variable.
+       (reload_insn_chain): New variable.
+       (unused_insn_chains): New variable.
+       (new_insn_chain): New function.
+       (init_reload): Initialize reload_startobj, not reload_firstobj.
+       (reload): Initialize reload_firstobj.
+       Before returning, free everything on the reload_obstack.
+
+       * stupid.c: Include insn-config.h, reload.h and basic-block.h.
+       (reg_where_dead_chain, reg_where_born_exact, reg_where_born_clobber,
+       current_chain): New variables.
+       (reg_where_born): Delete variable.
+       (REG_WHERE_BORN): New macro.
+       (find_clobbered_regs): New function.
+       (stupid_life_analysis): Don't allocate/free reg_where_born.
+       Allocate and free reg_where_born_exact, reg_where_born_clobber,
+       reg_where_dead_chain.
+       Use REG_WHERE_BORN instead of reg_where_born.
+       While processing the insns, build the reload_insn_chain with
+       information about register lifetimes.
+       (stupid_reg_compare): Use REG_WHERE_BORN instead of reg_where_born.
+       (stupid_mark_refs): Replace arg INSN with arg CHAIN.  All callers
+       changed.
+       Compute and information about birth and death of pseudo registers in
+       reg_where_dead_chain, reg_where_born_exact and reg_where_born_clobber.
+       Delete code to set elements of reg_where_born.  
+
 Mon Oct  5 22:34:30 1998  Alexandre Petit-Bianco  <apbianco@cygnus.com>
 
        * tree.def (GOTO_EXPR): Modified documentation.
index 8898140cfc7b9b2780487fe2cefa1ced95310e76..e97246df4ba03d9bb6a5216f7ccd76a8fa44b861 100644 (file)
@@ -1461,7 +1461,7 @@ jump.o : jump.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h $(REGS_H) \
    insn-config.h insn-flags.h $(RECOG_H) $(EXPR_H) real.h except.h \
    toplev.h
 stupid.o : stupid.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h \
-   flags.h toplev.h
+   $(BASIC_BLOCK_H) insn-config.h reload.h flags.h toplev.h
 
 cse.o : cse.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \
    real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h output.h
@@ -1487,7 +1487,7 @@ local-alloc.o : local-alloc.c $(CONFIG_H) system.h $(RTL_H) flags.h \
    insn-attr.h toplev.h
 bitmap.o : bitmap.c $(CONFIG_H) system.h $(RTL_H) flags.h $(BASIC_BLOCK_H) \
    $(REGS_H)
-global.o : global.c $(CONFIG_H) system.h $(RTL_H) flags.h  \
+global.o : global.c $(CONFIG_H) system.h $(RTL_H) flags.h reload.h \
    $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h insn-config.h output.h toplev.h
 varray.o : varray.c $(CONFIG_H) system.h varray.h $(RTL_H) $(TREE_H) bitmap.h
 
index e7edb6d36acae99c7f27c39999be449f7d7e8f5c..04a836c0003b2c9b87b40122b44ad18a6d8fe45c 100644 (file)
@@ -29,6 +29,7 @@ Boston, MA 02111-1307, USA.  */
 #include "basic-block.h"
 #include "regs.h"
 #include "insn-config.h"
+#include "reload.h"
 #include "output.h"
 #include "toplev.h"
 
@@ -268,6 +269,9 @@ static void mark_reg_death  PROTO((rtx));
 static void mark_reg_live_nc   PROTO((int, enum machine_mode));
 static void set_preference     PROTO((rtx, rtx));
 static void dump_conflicts     PROTO((FILE *));
+static void reg_becomes_live   PROTO((rtx, rtx));
+static void reg_dies           PROTO((int, enum machine_mode));
+static void build_insn_chain   PROTO((rtx));
 \f
 /* Perform allocation of pseudo-registers not allocated by local_alloc.
    FILE is a file to output debugging information on,
@@ -573,7 +577,10 @@ global_alloc (file)
         for the sake of debugging information.  */
   if (n_basic_blocks > 0)
 #endif
-    retval = reload (get_insns (), 1, file);
+    {
+      build_insn_chain (get_insns ());
+      retval = reload (get_insns (), 1, file);
+    }
 
   free (conflicts);
   return retval;
@@ -1648,6 +1655,135 @@ mark_elimination (from, to)
       }
 }
 \f
+/* Used for communication between the following functions.  Holds the
+   current life information.  */
+static regset live_relevant_regs;
+
+/* Record in live_relevant_regs that register REG became live.  This
+   is called via note_stores.  */
+static void
+reg_becomes_live (reg, setter)
+     rtx reg;
+     rtx setter ATTRIBUTE_UNUSED;
+{
+  int regno;
+
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+
+  if (GET_CODE (reg) != REG)
+    return;
+  
+  regno = REGNO (reg);
+  if (regno < FIRST_PSEUDO_REGISTER)
+    {
+      int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+      while (nregs-- > 0)
+       SET_REGNO_REG_SET (live_relevant_regs, regno++);
+    }
+  else if (reg_renumber[regno] >= 0)
+    SET_REGNO_REG_SET (live_relevant_regs, regno);
+}
+
+/* Record in live_relevant_regs that register REGNO died.  */
+static void
+reg_dies (regno, mode)
+     int regno;
+     enum machine_mode mode;
+{
+  if (regno < FIRST_PSEUDO_REGISTER)
+    {
+      int nregs = HARD_REGNO_NREGS (regno, mode);
+      while (nregs-- > 0)
+       CLEAR_REGNO_REG_SET (live_relevant_regs, regno++);
+    }
+  else
+    CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
+}
+
+/* Walk the insns of the current function and build reload_insn_chain,
+   and record register life information.  */
+static void
+build_insn_chain (first)
+     rtx first;
+{
+  struct insn_chain **p = &reload_insn_chain;
+  struct insn_chain *prev = 0;
+  int b = 0;
+
+  live_relevant_regs = ALLOCA_REG_SET ();
+
+  for (; first; first = NEXT_INSN (first))
+    {
+      struct insn_chain *c;
+
+      if (first == basic_block_head[b])
+       {
+         int i;
+         CLEAR_REG_SET (live_relevant_regs);
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           if (REGNO_REG_SET_P (basic_block_live_at_start[b], i)
+               && ! TEST_HARD_REG_BIT (eliminable_regset, i))
+             SET_REGNO_REG_SET (live_relevant_regs, i);
+
+         for (; i < max_regno; i++)
+           if (reg_renumber[i] >= 0
+               && REGNO_REG_SET_P (basic_block_live_at_start[b], i))
+             SET_REGNO_REG_SET (live_relevant_regs, i);
+       }
+
+      if (GET_CODE (first) != NOTE && GET_CODE (first) != BARRIER)
+       {
+         c = new_insn_chain ();
+         c->prev = prev;
+         prev = c;
+         *p = c;
+         p = &c->next;
+         c->insn = first;
+         c->block = b;
+
+         COPY_REG_SET (c->live_before, live_relevant_regs);
+
+         if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
+           {
+             rtx link;
+
+             /* Mark the death of everything that dies in this instruction.  */
+
+             for (link = REG_NOTES (first); link; link = XEXP (link, 1))
+               if (REG_NOTE_KIND (link) == REG_DEAD
+                   && GET_CODE (XEXP (link, 0)) == REG)
+                 reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)));
+
+             /* Mark everything born in this instruction as live.  */
+
+             note_stores (PATTERN (first), reg_becomes_live);
+           }
+
+         /* Remember which registers are live at the end of the insn, before
+            killing those with REG_UNUSED notes.  */
+         COPY_REG_SET (c->live_after, live_relevant_regs);
+
+         if (GET_RTX_CLASS (GET_CODE (first)) == 'i')
+           {
+             rtx link;
+
+             /* Mark anything that is set in this insn and then unused as dying.  */
+
+             for (link = REG_NOTES (first); link; link = XEXP (link, 1))
+               if (REG_NOTE_KIND (link) == REG_UNUSED
+                   && GET_CODE (XEXP (link, 0)) == REG)
+                 reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)));
+           }
+       }
+
+      if (first == basic_block_end[b])
+       b++;
+    }
+  FREE_REG_SET (live_relevant_regs);
+  *p = 0;
+}
+\f
 /* Print debugging trace information if -greg switch is given,
    showing the information on which the allocation decisions are based.  */
 
index d99b0c128a5d04b36b8b1cdbd1c1cef1d3e2ae9a..58f6be3a1014e2b211ad0a838bc5380cce699db7 100644 (file)
@@ -142,6 +142,81 @@ extern enum insn_code reload_in_optab[];
 extern enum insn_code reload_out_optab[];
 #endif
 
+struct needs
+{
+  /* [0] is normal, [1] is nongroup.  */
+  short regs[2][N_REG_CLASSES];
+  short groups[N_REG_CLASSES];
+};
+
+#if defined SET_HARD_REG_BIT && defined CLEAR_REG_SET
+/* This structure describes instructions which are relevant for reload.
+   Apart from all regular insns, this also includes CODE_LABELs, since they
+   must be examined for register elimination.  */
+struct insn_chain 
+{
+  /* Links to the neighbour instructions.  */
+  struct insn_chain *next, *prev;
+
+  /* Link through a chains set up by calculate_needs_all_insns, containing
+     all insns that need reloading.  */
+  struct insn_chain *next_need_reload;
+
+  /* The basic block this insn is in.  */
+  int block;
+  /* The rtx of the insn.  */
+  rtx insn;
+  /* Register life information: record all live hard registers, and all
+     live pseudos that have a hard register.
+     This information is recorded for the point immediately before the insn
+     (in live_before), and for the point within the insn at which all
+     outputs have just been written to (in live_after).  */
+  regset live_before;
+  regset live_after;
+
+  /* For each class, size of group of consecutive regs
+     that is needed for the reloads of this class.  */
+  char group_size[N_REG_CLASSES];
+  /* For each class, the machine mode which requires consecutive
+     groups of regs of that class.
+     If two different modes ever require groups of one class,
+     they must be the same size and equally restrictive for that class,
+     otherwise we can't handle the complexity.  */
+  enum machine_mode group_mode[N_REG_CLASSES];
+
+  /* Indicates if a register was counted against the need for
+     groups.  0 means it can count against max_nongroup instead.  */
+  HARD_REG_SET counted_for_groups;
+
+  /* Indicates if a register was counted against the need for
+     non-groups.  0 means it can become part of a new group.
+     During choose_reload_regs, 1 here means don't use this reg
+     as part of a group, even if it seems to be otherwise ok.  */
+  HARD_REG_SET counted_for_nongroups;
+
+  /* Indicates which registers have already been used for spills.  */
+  HARD_REG_SET used_spill_regs;
+
+  /* Describe the needs for reload registers of this insn.  */
+  struct needs need;
+
+  /* Nonzero if find_reloads said the insn requires reloading.  */
+  unsigned int need_reload:1;
+  /* Nonzero if eliminate_regs_in_insn said it requires eliminations.  */
+  unsigned int need_elim:1;
+  /* Nonzero if this insn was inserted by perform_caller_saves.  */
+  unsigned int is_caller_save_insn:1;
+};
+
+/* A chain of insn_chain structures to describe all non-note insns in
+   a function.  */
+extern struct insn_chain *reload_insn_chain;
+
+/* Allocate a new insn_chain structure.  */
+extern struct insn_chain *new_insn_chain       PROTO((void));
+
+#endif
+
 /* Functions from reload.c:  */
 
 /* Return a memory location that will be used to copy X in mode MODE.  
index 6b11bb95646987ceddb4a339c5fbbc638c61162b..8b15e0e8e8d04a4f769bf3da7339e0fbd9403a7e 100644 (file)
@@ -32,9 +32,9 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "expr.h"
 #include "regs.h"
+#include "basic-block.h"
 #include "reload.h"
 #include "recog.h"
-#include "basic-block.h"
 #include "output.h"
 #include "real.h"
 #include "toplev.h"
@@ -279,6 +279,13 @@ enum insn_code reload_out_optab[NUM_MACHINE_MODES];
    insn.  */
 
 struct obstack reload_obstack;
+
+/* Points to the beginning of the reload_obstack.  All insn_chain structures
+   are allocated first.  */
+char *reload_startobj;
+
+/* The point after all insn_chain structures.  Used to quickly deallocate
+   memory used while processing one insn.  */
 char *reload_firstobj;
 
 #define obstack_chunk_alloc xmalloc
@@ -286,6 +293,10 @@ char *reload_firstobj;
 
 /* List of labels that must never be deleted.  */
 extern rtx forced_labels;
+
+/* List of insn_chain instructions, one for every insn that reload needs to
+   examine.  */
+struct insn_chain *reload_insn_chain;
 \f
 /* This structure is used to record information about register eliminations.
    Each array entry describes one possible way of eliminating a register
@@ -461,7 +472,7 @@ init_reload ()
 
   /* Initialize obstack for our rtl allocation.  */
   gcc_obstack_init (&reload_obstack);
-  reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+  reload_startobj = (char *) obstack_alloc (&reload_obstack, 0);
 
   /* Decide which register class should be used when reloading
      addresses.  If we are using SMALL_REGISTER_CLASSES, and any
@@ -522,6 +533,32 @@ init_reload ()
     }
 }
 
+/* List of insn chains that are currently unused.  */
+static struct insn_chain *unused_insn_chains = 0;
+
+/* Allocate an empty insn_chain structure.  */
+struct insn_chain *
+new_insn_chain ()
+{
+  struct insn_chain *c;
+
+  if (unused_insn_chains == 0)
+    {
+      c = obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
+      c->live_before = OBSTACK_ALLOC_REG_SET (&reload_obstack);
+      c->live_after = OBSTACK_ALLOC_REG_SET (&reload_obstack);
+    }
+  else
+    {
+      c = unused_insn_chains;
+      unused_insn_chains = c->next;
+    }
+  c->is_caller_save_insn = 0;
+  c->need_reload = 0;
+  c->need_elim = 0;
+  return c;
+}
+
 /* Global variables used by reload and its subroutines.  */
 
 /* Set during calculate_needs if an insn needs reloading.  */
@@ -605,6 +642,8 @@ reload (first, global, dumpfile)
 
   failure = 0;
 
+  reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+
   /* Enable find_equiv_reg to distinguish insns made by reload.  */
   reload_first_uid = get_max_uid ();
 
@@ -1217,7 +1256,9 @@ reload (first, global, dumpfile)
       if (size > STACK_CHECK_MAX_FRAME_SIZE)
        warning ("frame size too large for reliable stack checking");
     }
-       
+
+  obstack_free (&reload_obstack, reload_startobj);
+
   /* Indicate that we no longer have known memory locations or constants.  */
   reg_equiv_constant = 0;
   reg_equiv_memory_loc = 0;
index dbb0ffeccc97e46f74119bae138ddfb7b734a945..cd1329f83d7e4b4223f9c26da3edc658c3128af3 100644 (file)
@@ -47,7 +47,10 @@ Boston, MA 02111-1307, USA.  */
 
 #include "rtl.h"
 #include "hard-reg-set.h"
+#include "basic-block.h"
 #include "regs.h"
+#include "insn-config.h"
+#include "reload.h"
 #include "flags.h"
 #include "toplev.h"
 \f
@@ -77,9 +80,21 @@ static int last_setjmp_suid;
 
 static int *reg_where_dead;
 
+/* Likewise, but point to the insn_chain structure of the insn at which
+   the reg dies.  */
+static struct insn_chain **reg_where_dead_chain;
+
 /* Element N is suid of insn where life span of pseudo reg N begins.  */
+static int *reg_where_born_exact;
+
+/* Element N is 1 if the birth of pseudo reg N is due to a CLOBBER, 
+   0 otherwise.  */
+static int *reg_where_born_clobber;
 
-static int *reg_where_born;
+/* Return the suid of the insn where the register is born, or the suid
+   of the insn before if the birth is due to a CLOBBER.  */
+#define REG_WHERE_BORN(N) \
+  (reg_where_born_exact[(N)] - reg_where_born_clobber[(N)])
 
 /* Numbers of pseudo-regs to be allocated, highest priority first.  */
 
@@ -111,7 +126,43 @@ static HARD_REG_SET *after_insn_hard_regs;
 static int stupid_reg_compare  PROTO((const GENERIC_PTR,const GENERIC_PTR));
 static int stupid_find_reg     PROTO((int, enum reg_class, enum machine_mode,
                                       int, int, int));
-static void stupid_mark_refs   PROTO((rtx, rtx));
+static void stupid_mark_refs   PROTO((rtx, struct insn_chain *));
+static void find_clobbered_regs        PROTO((rtx, rtx));
+\f
+/* For communication between stupid_life_analysis and find_clobbered_regs.  */
+static struct insn_chain *current_chain;
+
+/* This function, called via note_stores, marks any hard registers that are
+   clobbered in an insn as being live in the live_after and live_before fields
+   of the appropriate insn_chain structure.  */
+
+static void
+find_clobbered_regs (reg, setter)
+     rtx reg, setter;
+{
+  int regno, nregs;
+  if (setter == 0 || GET_CODE (setter) != CLOBBER)
+    return;
+
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+
+  if (GET_CODE (reg) != REG)
+    return;
+  regno = REGNO (reg);
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    return;
+
+  if (GET_MODE (reg) == VOIDmode)
+    abort ();
+  else
+    nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+  while (nregs-- > 0)
+    {
+      SET_REGNO_REG_SET (current_chain->live_after, regno);
+      SET_REGNO_REG_SET (current_chain->live_before, regno++);
+    }
+}
 \f
 /* Stupid life analysis is for the case where only variables declared
    `register' go in registers.  For this case, we mark all
@@ -171,9 +222,15 @@ stupid_life_analysis (f, nregs, file)
   reg_where_dead = (int *) xmalloc (nregs * sizeof (int));
   bzero ((char *) reg_where_dead, nregs * sizeof (int));
 
-  reg_where_born = (int *) xmalloc (nregs * sizeof (int));
-  bzero ((char *) reg_where_born, nregs * sizeof (int));
+  reg_where_born_exact = (int *) xmalloc (nregs * sizeof (int));
+  bzero ((char *) reg_where_born_exact, nregs * sizeof (int));
 
+  reg_where_born_clobber = (int *) xmalloc (nregs * sizeof (int));
+  bzero ((char *) reg_where_born_clobber, nregs * sizeof (int));
+
+  reg_where_dead_chain = (struct insn_chain **) xmalloc (nregs * sizeof (struct insn_chain *));
+  bzero ((char *) reg_where_dead_chain, nregs * sizeof (struct insn_chain *));
   reg_order = (int *) xmalloc (nregs * sizeof (int));
   bzero ((char *) reg_order, nregs * sizeof (int));
 
@@ -210,11 +267,15 @@ stupid_life_analysis (f, nregs, file)
      Also find where each hard register is live
      and record that info in after_insn_hard_regs.
      regs_live[I] is 1 if hard reg I is live
-     at the current point in the scan.  */
+     at the current point in the scan.  
+   
+     Build reload_insn_chain while we're walking the insns.  */
 
+  reload_insn_chain = 0;
   for (insn = last; insn; insn = PREV_INSN (insn))
     {
       register HARD_REG_SET *p = after_insn_hard_regs + INSN_SUID (insn);
+      struct insn_chain *chain;
 
       /* Copy the info in regs_live into the element of after_insn_hard_regs
         for the current position in the rtl code.  */
@@ -223,12 +284,27 @@ stupid_life_analysis (f, nregs, file)
        if (regs_live[i])
          SET_HARD_REG_BIT (*p, i);
 
+      if (GET_CODE (insn) != NOTE && GET_CODE (insn) != BARRIER)
+       {
+         chain = new_insn_chain ();
+         if (reload_insn_chain)
+           reload_insn_chain->prev = chain;
+         chain->next = reload_insn_chain;
+         chain->prev = 0;
+         reload_insn_chain = chain;
+         chain->block = 0;
+         chain->insn = insn;
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           if (regs_live[i])
+             SET_REGNO_REG_SET (chain->live_before, i);
+       }
+
       /* Update which hard regs are currently live
         and also the birth and death suids of pseudo regs
         based on the pattern of this insn.  */
 
       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
-       stupid_mark_refs (PATTERN (insn), insn);
+       stupid_mark_refs (PATTERN (insn), chain);
 
       if (GET_CODE (insn) == NOTE
          && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
@@ -266,8 +342,23 @@ stupid_life_analysis (f, nregs, file)
          /* It is important that this be done after processing the insn's
             pattern because we want the function result register to still
             be live if it's also used to pass arguments.  */
-         stupid_mark_refs (CALL_INSN_FUNCTION_USAGE (insn), insn);
+         stupid_mark_refs (CALL_INSN_FUNCTION_USAGE (insn), chain);
        }
+
+      if (GET_CODE (insn) != NOTE && GET_CODE (insn) != BARRIER)
+       {         
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           if (regs_live[i])
+             SET_REGNO_REG_SET (chain->live_after, i);
+
+         /* The regs_live array doesn't say anything about hard registers
+            clobbered by this insn.  So we need an extra pass over the
+            pattern.  */
+         current_chain = chain;
+         if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+           note_stores (PATTERN (insn), find_clobbered_regs);
+       }
+
       if (GET_CODE (insn) == JUMP_INSN && computed_jump_p (insn))
        current_function_has_computed_jump = 1;
     }
@@ -289,8 +380,10 @@ stupid_life_analysis (f, nregs, file)
 
       /* Some regnos disappear from the rtl.  Ignore them to avoid crash. 
         Also don't allocate registers that cross a setjmp, or live across
-        a call if this function receives a nonlocal goto.  */
+        a call if this function receives a nonlocal goto.
+        Also ignore registers we didn't see during the scan.  */
       if (regno_reg_rtx[r] == 0 || regs_crosses_setjmp[r]
+         || (reg_where_born_exact[r] == 0 && reg_where_dead[r] == 0)
          || (REG_N_CALLS_CROSSED (r) > 0 
              && current_function_has_nonlocal_label))
        continue;
@@ -300,7 +393,7 @@ stupid_life_analysis (f, nregs, file)
        reg_renumber[r] = stupid_find_reg (REG_N_CALLS_CROSSED (r), 
                                           reg_preferred_class (r),
                                           PSEUDO_REGNO_MODE (r),
-                                          reg_where_born[r],
+                                          REG_WHERE_BORN (r),
                                           reg_where_dead[r],
                                           regs_change_size[r]);
 
@@ -309,18 +402,48 @@ stupid_life_analysis (f, nregs, file)
        reg_renumber[r] = stupid_find_reg (REG_N_CALLS_CROSSED (r),
                                           reg_alternate_class (r),
                                           PSEUDO_REGNO_MODE (r),
-                                          reg_where_born[r],
+                                          REG_WHERE_BORN (r),
                                           reg_where_dead[r],
                                           regs_change_size[r]);
     }
 
+  /* Fill in the pseudo reg life information into the insn chain.  */
+  for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
+    {
+      struct insn_chain *chain;
+      int regno;
+
+      regno = reg_renumber[i];
+      if (regno < 0)
+       continue;
+
+      chain = reg_where_dead_chain[i];
+      if (reg_where_dead[i] > INSN_SUID (chain->insn))
+       SET_REGNO_REG_SET (chain->live_after, i);
+
+      while (INSN_SUID (chain->insn) > reg_where_born_exact[i])
+       {
+         SET_REGNO_REG_SET (chain->live_before, i);
+         chain = chain->prev;
+         if (!chain)
+           break;
+         SET_REGNO_REG_SET (chain->live_after, i);
+       }
+
+      if (INSN_SUID (chain->insn) == reg_where_born_exact[i]
+         && reg_where_born_clobber[i])
+       SET_REGNO_REG_SET (chain->live_before, i);
+    }
+
   if (file)
     dump_flow_info (file);
 
   free (regs_live);
   free (uid_suid);
   free (reg_where_dead);
-  free (reg_where_born);
+  free (reg_where_born_exact);
+  free (reg_where_born_clobber);
+  free (reg_where_dead_chain);
   free (reg_order);
   free (regs_change_size);
   free (regs_crosses_setjmp);
@@ -336,8 +459,8 @@ stupid_reg_compare (r1p, r2p)
      const GENERIC_PTR r2p;
 {
   register int r1 = *(int *)r1p, r2 = *(int *)r2p;
-  register int len1 = reg_where_dead[r1] - reg_where_born[r1];
-  register int len2 = reg_where_dead[r2] - reg_where_born[r2];
+  register int len1 = reg_where_dead[r1] - REG_WHERE_BORN (r1);
+  register int len2 = reg_where_dead[r2] - REG_WHERE_BORN (r2);
   int tem;
 
   tem = len2 - len1;
@@ -470,12 +593,14 @@ stupid_find_reg (call_preserved, class, mode,
    INSN is the current insn, supplied so we can find its suid.  */
 
 static void
-stupid_mark_refs (x, insn)
-     rtx x, insn;
+stupid_mark_refs (x, chain)
+     rtx x;
+     struct insn_chain *chain;
 {
   register RTX_CODE code;
   register char *fmt;
   register int regno, i;
+  rtx insn = chain->insn;
 
   if (x == 0)
     return;
@@ -530,7 +655,11 @@ stupid_mark_refs (x, insn)
                 the clobbering insn.  When setting, just after.  */
              int where_born = INSN_SUID (insn) - (code == CLOBBER);
 
-             reg_where_born[regno] = where_born;
+             reg_where_born_exact[regno] = INSN_SUID (insn);
+             reg_where_born_clobber[regno] = (code == CLOBBER);
+
+             if (reg_where_dead_chain[regno] == 0)
+               reg_where_dead_chain[regno] = chain;
 
              /* The reg must live at least one insn even
                 in it is never again used--because it has to go
@@ -573,9 +702,9 @@ stupid_mark_refs (x, insn)
         If setting a SUBREG, we treat the entire reg as *used*.  */
       if (code == SET)
        {
-         stupid_mark_refs (SET_SRC (x), insn);
+         stupid_mark_refs (SET_SRC (x), chain);
          if (GET_CODE (SET_DEST (x)) != REG)
-           stupid_mark_refs (SET_DEST (x), insn);
+           stupid_mark_refs (SET_DEST (x), chain);
        }
       return;
     }
@@ -608,12 +737,14 @@ stupid_mark_refs (x, insn)
        {
          /* Pseudo reg: record first use, last use and number of uses.  */
 
-         reg_where_born[regno] = INSN_SUID (insn);
+         reg_where_born_exact[regno] = INSN_SUID (insn);
+         reg_where_born_clobber[regno] = 0;
          REG_N_REFS (regno)++;
          if (regs_live[regno] == 0)
            {
              regs_live[regno] = 1;
              reg_where_dead[regno] = INSN_SUID (insn);
+             reg_where_dead_chain[regno] = chain;
            }
        }
       return;
@@ -625,12 +756,12 @@ stupid_mark_refs (x, insn)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       stupid_mark_refs (XEXP (x, i), insn);
+       stupid_mark_refs (XEXP (x, i), chain);
       if (fmt[i] == 'E')
        {
          register int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           stupid_mark_refs (XVECEXP (x, i, j), insn);
+           stupid_mark_refs (XVECEXP (x, i, j), chain);
        }
     }
 }