OSDN Git Service

Word wrap comment
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 4d9361c..e697d55 100644 (file)
@@ -1,5 +1,6 @@
 /* Emit RTL for the GNU C-Compiler expander.
-   Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -35,45 +36,38 @@ Boston, MA 02111-1307, USA.  */
    is the kind of rtx's they make and what arguments they use.  */
 
 #include "config.h"
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
 #include "system.h"
+#include "toplev.h"
 #include "rtl.h"
 #include "tree.h"
+#include "tm_p.h"
 #include "flags.h"
-#include "except.h"
 #include "function.h"
 #include "expr.h"
 #include "regs.h"
 #include "hard-reg-set.h"
+#include "hashtab.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "real.h"
 #include "obstack.h"
+#include "bitmap.h"
+#include "basic-block.h"
+#include "ggc.h"
 
 /* Commonly used modes.  */
 
 enum machine_mode byte_mode;   /* Mode whose width is BITS_PER_UNIT.  */
 enum machine_mode word_mode;   /* Mode whose width is BITS_PER_WORD.  */
+enum machine_mode double_mode; /* Mode whose width is DOUBLE_TYPE_SIZE.  */
 enum machine_mode ptr_mode;    /* Mode whose width is POINTER_SIZE.  */
 
-/* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function.
-   After rtl generation, it is 1 plus the largest register number used.  */
-
-int reg_rtx_no = LAST_VIRTUAL_REGISTER + 1;
 
 /* This is *not* reset after each function.  It gives each CODE_LABEL
    in the entire compilation a unique label number.  */
 
 static int label_num = 1;
 
-/* Lowest label number in current function.  */
-
-static int first_label_num;
-
 /* Highest label number in current function.
    Zero means use the value of label_num instead.
    This is nonzero only when belatedly compiling an inline function.  */
@@ -94,19 +88,7 @@ static int no_line_numbers;
    All of these except perhaps the floating-point CONST_DOUBLEs
    are unique; no other rtx-object will be equal to any of these.  */
 
-struct _global_rtl global_rtl =
-{
-  {PC, VOIDmode},                      /* pc_rtx */
-  {CC0, VOIDmode},                     /* cc0_rtx */
-  {REG},                               /* stack_pointer_rtx */
-  {REG},                               /* frame_pointer_rtx */
-  {REG},                               /* hard_frame_pointer_rtx */
-  {REG},                               /* arg_pointer_rtx */
-  {REG},                               /* virtual_incoming_args_rtx */
-  {REG},                               /* virtual_stack_vars_rtx */
-  {REG},                               /* virtual_stack_dynamic_rtx */
-  {REG},                               /* virtual_outgoing_args_rtx */
-};
+rtx global_rtl[GR_MAX];
 
 /* We record floating-point CONST_DOUBLEs in each floating-point mode for
    the values of 0, 1, and 2.  For the integer entries and VOIDmode, we
@@ -154,108 +136,157 @@ rtx return_address_pointer_rtx; /* (REG:Pmode RETURN_ADDRESS_POINTER_REGNUM) */
    to save space during the compilation and simplify comparisons of
    integers.  */
 
-struct rtx_def const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
-
-/* The ends of the doubly-linked chain of rtl for the current function.
-   Both are reset to null at the start of rtl generation for the function.
-   
-   start_sequence saves both of these on `sequence_stack' along with
-   `sequence_rtl_expr' and then starts a new, nested sequence of insns.  */
-
-static rtx first_insn = NULL;
-static rtx last_insn = NULL;
-
-/* RTL_EXPR within which the current sequence will be placed.  Use to
-   prevent reuse of any temporaries within the sequence until after the
-   RTL_EXPR is emitted.  */
-
-tree sequence_rtl_expr = NULL;
-
-/* INSN_UID for next insn emitted.
-   Reset to 1 for each function compiled.  */
-
-static int cur_insn_uid = 1;
-
-/* Line number and source file of the last line-number NOTE emitted.
-   This is used to avoid generating duplicates.  */
-
-static int last_linenum = 0;
-static char *last_filename = 0;
-
-/* A vector indexed by pseudo reg number.  The allocated length
-   of this vector is regno_pointer_flag_length.  Since this
-   vector is needed during the expansion phase when the total
-   number of registers in the function is not yet known,
-   it is copied and made bigger when necessary.  */
-
-char *regno_pointer_flag;
-int regno_pointer_flag_length;
+rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
 
-/* Indexed by pseudo register number, if nonzero gives the known alignment
-   for that pseudo (if regno_pointer_flag is set).
-   Allocated in parallel with regno_pointer_flag.  */
-char *regno_pointer_align;
+/* A hash table storing CONST_INTs whose absolute value is greater
+   than MAX_SAVED_CONST_INT.  */
 
-/* Indexed by pseudo register number, gives the rtx for that pseudo.
-   Allocated in parallel with regno_pointer_flag.  */
-
-rtx *regno_reg_rtx;
-
-/* Stack of pending (incomplete) sequences saved by `start_sequence'.
-   Each element describes one pending sequence.
-   The main insn-chain is saved in the last element of the chain,
-   unless the chain is empty.  */
-
-struct sequence_stack *sequence_stack;
+static htab_t const_int_htab;
 
 /* start_sequence and gen_sequence can make a lot of rtx expressions which are
    shortly thrown away.  We use two mechanisms to prevent this waste:
 
-   First, we keep a list of the expressions used to represent the sequence
-   stack in sequence_element_free_list.
-
-   Second, for sizes up to 5 elements, we keep a SEQUENCE and its associated
-   rtvec for use by gen_sequence.  One entry for each size is sufficient
-   because most cases are calls to gen_sequence followed by immediately
-   emitting the SEQUENCE.  Reuse is safe since emitting a sequence is
-   destructive on the insn in it anyway and hence can't be redone.
+   For sizes up to 5 elements, we keep a SEQUENCE and its associated
+   rtvec for use by gen_sequence.  One entry for each size is
+   sufficient because most cases are calls to gen_sequence followed by
+   immediately emitting the SEQUENCE.  Reuse is safe since emitting a
+   sequence is destructive on the insn in it anyway and hence can't be
+   redone.
 
    We do not bother to save this cached data over nested function calls.
    Instead, we just reinitialize them.  */
 
 #define SEQUENCE_RESULT_SIZE 5
 
-static struct sequence_stack *sequence_element_free_list;
 static rtx sequence_result[SEQUENCE_RESULT_SIZE];
 
 /* During RTL generation, we also keep a list of free INSN rtl codes.  */
 static rtx free_insn;
 
-extern int rtx_equal_function_value_matters;
+#define first_insn (cfun->emit->x_first_insn)
+#define last_insn (cfun->emit->x_last_insn)
+#define cur_insn_uid (cfun->emit->x_cur_insn_uid)
+#define last_linenum (cfun->emit->x_last_linenum)
+#define last_filename (cfun->emit->x_last_filename)
+#define first_label_num (cfun->emit->x_first_label_num)
+
+/* This is where the pointer to the obstack being used for RTL is stored.  */
+extern struct obstack *rtl_obstack;
+
+static rtx make_jump_insn_raw          PARAMS ((rtx));
+static rtx make_call_insn_raw          PARAMS ((rtx));
+static rtx find_line_note              PARAMS ((rtx));
+static void mark_sequence_stack         PARAMS ((struct sequence_stack *));
+static void unshare_all_rtl_1          PARAMS ((rtx));
+static hashval_t const_int_htab_hash    PARAMS ((const void *));
+static int const_int_htab_eq            PARAMS ((const void *,
+                                                const void *));
+static int rtx_htab_mark_1              PARAMS ((void **, void *));
+static void rtx_htab_mark               PARAMS ((void *));
 
-/* Filename and line number of last line-number note,
-   whether we actually emitted it or not.  */
-extern char *emit_filename;
-extern int emit_lineno;
-
-static rtx make_jump_insn_raw          PROTO((rtx));
-static rtx make_call_insn_raw          PROTO((rtx));
-static rtx find_line_note              PROTO((rtx));
 \f
+/* Returns a hash code for X (which is a really a CONST_INT).  */
+
+static hashval_t
+const_int_htab_hash (x)
+     const void *x;
+{
+  return (hashval_t) INTVAL ((const struct rtx_def *) x);
+}
+
+/* Returns non-zero if the value represented by X (which is really a
+   CONST_INT) is the same as that given by Y (which is really a
+   HOST_WIDE_INT *).  */
+
+static int
+const_int_htab_eq (x, y)
+     const void *x;
+     const void *y;
+{
+  return (INTVAL ((const struct rtx_def *) x) == *((const HOST_WIDE_INT *) y));
+}
+
+/* Mark the hash-table element X (which is really a pointer to an
+   rtx).  */
+
+static int
+rtx_htab_mark_1 (x, data)
+     void **x;
+     void *data ATTRIBUTE_UNUSED;
+{
+  ggc_mark_rtx (*x);
+  return 1;
+}
+
+/* Mark all the elements of HTAB (which is really an htab_t full of
+   rtxs).  */
+
+static void
+rtx_htab_mark (htab)
+     void *htab;
+{
+  htab_traverse (*((htab_t *) htab), rtx_htab_mark_1, NULL);
+}
+
+/* There are some RTL codes that require special attention; the generation
+   functions do the raw handling.  If you add to this list, modify
+   special_rtx in gengenrtl.c as well.  */
+
 rtx
 gen_rtx_CONST_INT (mode, arg)
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
      HOST_WIDE_INT arg;
 {
+  void **slot;
+
   if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT)
-    return &const_int_rtx[arg + MAX_SAVED_CONST_INT];
+    return const_int_rtx[arg + MAX_SAVED_CONST_INT];
 
 #if STORE_FLAG_VALUE != 1 && STORE_FLAG_VALUE != -1
   if (const_true_rtx && arg == STORE_FLAG_VALUE)
     return const_true_rtx;
 #endif
 
-  return gen_rtx_raw_CONST_INT (mode, arg);
+  /* Look up the CONST_INT in the hash table.  */
+  slot = htab_find_slot_with_hash (const_int_htab, &arg, (hashval_t) arg, 1);
+  if (*slot == 0)
+    {
+      if (!ggc_p)
+       {
+         push_obstacks_nochange ();
+         end_temporary_allocation ();
+         *slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
+         pop_obstacks ();
+       }
+      else
+       *slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
+    }
+
+  return (rtx) *slot;
+}
+
+/* CONST_DOUBLEs needs special handling because their length is known
+   only at run-time.  */
+
+rtx
+gen_rtx_CONST_DOUBLE (mode, arg0, arg1, arg2)
+     enum machine_mode mode;
+     rtx arg0;
+     HOST_WIDE_INT arg1, arg2;
+{
+  rtx r = rtx_alloc (CONST_DOUBLE);
+  int i;
+
+  PUT_MODE (r, mode);
+  XEXP (r, 0) = arg0;
+  X0EXP (r, 1) = NULL_RTX;
+  XWINT (r, 2) = arg1;
+  XWINT (r, 3) = arg2;
+
+  for (i = GET_RTX_LENGTH (CONST_DOUBLE) - 1; i > 3; --i)
+    XWINT (r, i) = 0;
+
+  return r;
 }
 
 rtx
@@ -300,6 +331,20 @@ gen_rtx_REG (mode, regno)
   return gen_rtx_raw_REG (mode, regno);
 }
 
+rtx
+gen_rtx_MEM (mode, addr)
+     enum machine_mode mode;
+     rtx addr;
+{
+  rtx rt = gen_rtx_raw_MEM (mode, addr);
+
+  /* This field is not cleared by the mere allocation of the rtx, so
+     we clear it here.  */
+  MEM_ALIAS_SET (rt) = 0;
+
+  return rt;
+}
+\f
 /* rtx gen_rtx (code, mode, [element1, ..., elementn])
 **
 **         This routine generates an RTX of the size specified by
@@ -328,30 +373,48 @@ gen_rtx_REG (mode, regno)
 
 /*VARARGS2*/
 rtx
-gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...))
+gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum rtx_code code;
   enum machine_mode mode;
 #endif
   va_list p;
   register int i;              /* Array indices...                     */
-  register char *fmt;          /* Current rtx's format...              */
+  register const char *fmt;    /* Current rtx's format...              */
   register rtx rt_val;         /* RTX to return to caller...           */
 
   VA_START (p, mode);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   code = va_arg (p, enum rtx_code);
   mode = va_arg (p, enum machine_mode);
 #endif
 
-  if (code == CONST_INT)
-    rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT));
-  else if (code == REG)
-    rt_val = gen_rtx_REG (mode, va_arg (p, int));
-  else
+  switch (code)
     {
+    case CONST_INT:
+      rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT));
+      break;
+
+    case CONST_DOUBLE:
+      {
+       rtx arg0 = va_arg (p, rtx);
+       HOST_WIDE_INT arg1 = va_arg (p, HOST_WIDE_INT);
+       HOST_WIDE_INT arg2 = va_arg (p, HOST_WIDE_INT);
+        rt_val = gen_rtx_CONST_DOUBLE (mode, arg0, arg1, arg2);
+      }
+      break;
+
+    case REG:
+      rt_val = gen_rtx_REG (mode, va_arg (p, int));
+      break;
+
+    case MEM:
+      rt_val = gen_rtx_MEM (mode, va_arg (p, rtx));
+      break;
+
+    default:
       rt_val = rtx_alloc (code);       /* Allocate the storage space.  */
       rt_val->mode = mode;             /* Store the machine mode...  */
 
@@ -384,13 +447,23 @@ gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...))
              XVEC (rt_val, i) = va_arg (p, rtvec);
              break;
 
+           case 'b':           /* A bitmap? */
+             XBITMAP (rt_val, i) = va_arg (p, bitmap);
+             break;
+
+           case 't':           /* A tree? */
+             XTREE (rt_val, i) = va_arg (p, tree);
+             break;
+
            default:
              abort ();
            }
        }
+      break;
     }
+
   va_end (p);
-  return rt_val;               /* Return the new RTX...                */
+  return rt_val;
 }
 
 /* gen_rtvec (n, [rt1, ..., rtn])
@@ -401,9 +474,9 @@ gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...))
 
 /*VARARGS1*/
 rtvec
-gen_rtvec VPROTO((int n, ...))
+gen_rtvec VPARAMS ((int n, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   int n;
 #endif
   int i;
@@ -412,7 +485,7 @@ gen_rtvec VPROTO((int n, ...))
 
   VA_START (p, n);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   n = va_arg (p, int);
 #endif
 
@@ -442,29 +515,11 @@ gen_rtvec_v (n, argp)
   rt_val = rtvec_alloc (n);    /* Allocate an rtvec...                 */
 
   for (i = 0; i < n; i++)
-    rt_val->elem[i].rtx = *argp++;
+    rt_val->elem[i] = *argp++;
 
   return rt_val;
 }
 
-rtvec
-gen_rtvec_vv (n, argp)
-     int n;
-     rtunion *argp;
-{
-  register int i;
-  register rtvec rt_val;
-
-  if (n == 0)
-    return NULL_RTVEC;         /* Don't allocate an empty rtvec...     */
-
-  rt_val = rtvec_alloc (n);    /* Allocate an rtvec...                 */
-
-  for (i = 0; i < n; i++)
-    rt_val->elem[i].rtx = (argp++)->rtx;
-
-  return rt_val;
-}
 \f
 /* Generate a REG rtx for a new pseudo register of mode MODE.
    This pseudo is assigned the next sequential register number.  */
@@ -473,13 +528,12 @@ rtx
 gen_reg_rtx (mode)
      enum machine_mode mode;
 {
+  struct function *f = cfun;
   register rtx val;
 
-  /* Don't let anything called by or after reload create new registers
-     (actually, registers can't be created after flow, but this is a good
-     approximation).  */
-
-  if (reload_in_progress || reload_completed)
+  /* Don't let anything called after initial flow analysis create new
+     registers.  */
+  if (no_new_pseudos)
     abort ();
 
   if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
@@ -506,28 +560,25 @@ gen_reg_rtx (mode)
   /* Make sure regno_pointer_flag and regno_reg_rtx are large
      enough to have an element for this pseudo reg number.  */
 
-  if (reg_rtx_no == regno_pointer_flag_length)
+  if (reg_rtx_no == f->emit->regno_pointer_flag_length)
     {
+      int old_size = f->emit->regno_pointer_flag_length;
       rtx *new1;
-      char *new =
-       (char *) savealloc (regno_pointer_flag_length * 2);
-      bcopy (regno_pointer_flag, new, regno_pointer_flag_length);
-      bzero (&new[regno_pointer_flag_length], regno_pointer_flag_length);
-      regno_pointer_flag = new;
-
-      new = (char *) savealloc (regno_pointer_flag_length * 2);
-      bcopy (regno_pointer_align, new, regno_pointer_flag_length);
-      bzero (&new[regno_pointer_flag_length], regno_pointer_flag_length);
-      regno_pointer_align = new;
-
-      new1 = (rtx *) savealloc (regno_pointer_flag_length * 2 * sizeof (rtx));
-      bcopy ((char *) regno_reg_rtx, (char *) new1,
-            regno_pointer_flag_length * sizeof (rtx));
-      bzero ((char *) &new1[regno_pointer_flag_length],
-            regno_pointer_flag_length * sizeof (rtx));
+      char *new;
+      new = xrealloc (f->emit->regno_pointer_flag, old_size * 2);
+      memset (new + old_size, 0, old_size);
+      f->emit->regno_pointer_flag = new;
+
+      new = xrealloc (f->emit->regno_pointer_align, old_size * 2);
+      memset (new + old_size, 0, old_size);
+      f->emit->regno_pointer_align = new;
+
+      new1 = (rtx *) xrealloc (f->emit->x_regno_reg_rtx,
+                              old_size * 2 * sizeof (rtx));
+      memset (new1 + old_size, 0, old_size * sizeof (rtx));
       regno_reg_rtx = new1;
 
-      regno_pointer_flag_length *= 2;
+      f->emit->regno_pointer_flag_length = old_size * 2;
     }
 
   val = gen_rtx_raw_REG (mode, reg_rtx_no);
@@ -560,9 +611,15 @@ mark_reg_pointer (reg, align)
      rtx reg;
      int align;
 {
-  REGNO_POINTER_FLAG (REGNO (reg)) = 1;
+  if (! REGNO_POINTER_FLAG (REGNO (reg)))
+    {
+      REGNO_POINTER_FLAG (REGNO (reg)) = 1;
 
-  if (align)
+      if (align)
+       REGNO_POINTER_ALIGN (REGNO (reg)) = align;
+    }
+  else if (align && align < REGNO_POINTER_ALIGN (REGNO (reg)))
+    /* We can no-longer be sure just how aligned this pointer is */
     REGNO_POINTER_ALIGN (REGNO (reg)) = align;
 }
 
@@ -720,14 +777,13 @@ gen_lowpart_common (mode, x)
                : GEN_INT (CONST_DOUBLE_LOW (x)));
       else
        {
-         /* MODE must be narrower than HOST_BITS_PER_INT.  */
+         /* MODE must be narrower than HOST_BITS_PER_WIDE_INT.  */
          int width = GET_MODE_BITSIZE (mode);
          HOST_WIDE_INT val = (GET_CODE (x) == CONST_INT ? INTVAL (x)
                               : CONST_DOUBLE_LOW (x));
 
-         if (((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-              != ((HOST_WIDE_INT) (-1) << (width - 1))))
-           val &= ((HOST_WIDE_INT) 1 << width) - 1;
+         /* Sign extend to HOST_WIDE_INT.  */
+         val = val << (HOST_BITS_PER_WIDE_INT - width) >> (HOST_BITS_PER_WIDE_INT - width);
 
          return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x
                  : GEN_INT (val));
@@ -827,6 +883,22 @@ gen_lowpart_common (mode, x)
       r = REAL_VALUE_FROM_TARGET_SINGLE (i);
       return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
     }
+  else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
+            && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
+           || flag_pretend_float)
+          && GET_MODE_CLASS (mode) == MODE_FLOAT
+          && GET_MODE_SIZE (mode) == UNITS_PER_WORD
+          && GET_CODE (x) == CONST_INT
+          && (sizeof (double) * HOST_BITS_PER_CHAR
+              == HOST_BITS_PER_WIDE_INT))
+    {
+      REAL_VALUE_TYPE r;
+      HOST_WIDE_INT i;
+
+      i = INTVAL (x);
+      r = REAL_VALUE_FROM_TARGET_DOUBLE (&i);
+      return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
+    }
 #endif
 
   /* Similarly, if this is converting a floating-point value into a
@@ -881,6 +953,11 @@ gen_realpart (mode, x)
 {
   if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode)
     return XEXP (x, 0);
+  else if (WORDS_BIG_ENDIAN
+          && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
+          && REG_P (x)
+          && REGNO (x) < FIRST_PSEUDO_REGISTER)
+    fatal ("Unable to access real part of complex value in a hard register on this target");
   else if (WORDS_BIG_ENDIAN)
     return gen_highpart (mode, x);
   else
@@ -899,6 +976,11 @@ gen_imagpart (mode, x)
     return XEXP (x, 1);
   else if (WORDS_BIG_ENDIAN)
     return gen_lowpart (mode, x);
+  else if (!WORDS_BIG_ENDIAN
+          && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
+          && REG_P (x)
+          && REGNO (x) < FIRST_PSEUDO_REGISTER)
+    fatal ("Unable to access imaginary part of complex value in a hard register on this target");
   else
     return gen_highpart (mode, x);
 }
@@ -915,7 +997,8 @@ subreg_realpart_p (x)
   if (GET_CODE (x) != SUBREG)
     abort ();
 
-  return SUBREG_WORD (x) == 0;
+  return ((unsigned int) SUBREG_WORD (x) * UNITS_PER_WORD
+         < GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x))));
 }
 \f
 /* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a value,
@@ -984,7 +1067,11 @@ gen_highpart (mode, x)
       )
     return GEN_INT (CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode));
   else if (GET_CODE (x) == CONST_INT)
-    return const0_rtx;
+    {
+      if (HOST_BITS_PER_WIDE_INT <= BITS_PER_WORD)
+       return const0_rtx;
+      return GEN_INT (INTVAL (x) >> (HOST_BITS_PER_WIDE_INT - BITS_PER_WORD));
+    }
   else if (GET_CODE (x) == MEM)
     {
       register int offset = 0;
@@ -1011,18 +1098,24 @@ gen_highpart (mode, x)
     }
   else if (GET_CODE (x) == REG)
     {
-      int word = 0;
+      int word;
 
       /* Let the backend decide how many registers to skip.  This is needed
          in particular for sparc64 where fp regs are smaller than a word.  */
       /* ??? Note that subregs are now ambiguous, in that those against
-        pseudos are sized by the Word Size, while those against hard
+        pseudos are sized by the word size, while those against hard
         regs are sized by the underlying register size.  Better would be
         to always interpret the subreg offset parameter as bytes or bits.  */
 
-      if (! WORDS_BIG_ENDIAN && REGNO (x) < FIRST_PSEUDO_REGISTER)
+      if (WORDS_BIG_ENDIAN)
+       word = 0;
+      else if (REGNO (x) < FIRST_PSEUDO_REGISTER)
        word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x))
                - HARD_REGNO_NREGS (REGNO (x), mode));
+      else
+       word = ((GET_MODE_SIZE (GET_MODE (x))
+                - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+               / UNITS_PER_WORD);
 
       if (REGNO (x) < FIRST_PSEUDO_REGISTER
          /* integrate.c can't handle parts of a return value register.  */
@@ -1085,13 +1178,12 @@ subreg_lowpart_p (x)
 rtx
 operand_subword (op, i, validate_address, mode)
      rtx op;
-     int i;
+     unsigned int i;
      int validate_address;
      enum machine_mode mode;
 {
   HOST_WIDE_INT val;
   int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD;
-  int bits_per_word = BITS_PER_WORD;
 
   if (mode == VOIDmode)
     mode = GET_MODE (op);
@@ -1099,12 +1191,16 @@ operand_subword (op, i, validate_address, mode)
   if (mode == VOIDmode)
     abort ();
 
-  /* If OP is narrower than a word or if we want a word outside OP, fail.  */
+  /* If OP is narrower than a word, fail. */
   if (mode != BLKmode
-      && (GET_MODE_SIZE (mode) < UNITS_PER_WORD
-         || (i + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode)))
+      && (GET_MODE_SIZE (mode) < UNITS_PER_WORD))
     return 0;
 
+  /* If we want a word outside OP, return zero. */
+  if (mode != BLKmode
+      && (i + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode))
+    return const0_rtx;
+
   /* If OP is already an integer word, return it.  */
   if (GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_SIZE (mode) == UNITS_PER_WORD)
@@ -1113,10 +1209,33 @@ operand_subword (op, i, validate_address, mode)
   /* If OP is a REG or SUBREG, we can handle it very simply.  */
   if (GET_CODE (op) == REG)
     {
-      /* If the register is not valid for MODE, return 0.  If we don't
-        do this, there is no way to fix up the resulting REG later.  */
+      /* ??? There is a potential problem with this code.  It does not
+        properly handle extractions of a subword from a hard register
+        that is larger than word_mode.  Presumably the check for
+        HARD_REGNO_MODE_OK catches these most of these cases.  */
+
+      /* If OP is a hard register, but OP + I is not a hard register,
+        then extracting a subword is impossible.
+
+        For example, consider if OP is the last hard register and it is
+        larger than word_mode.  If we wanted word N (for N > 0) because a
+        part of that hard register was known to contain a useful value,
+        then OP + I would refer to a pseudo, not the hard register we
+        actually wanted.  */
+      if (REGNO (op) < FIRST_PSEUDO_REGISTER
+         && REGNO (op) + i >= FIRST_PSEUDO_REGISTER)
+       return 0;
+
+      /* If the register is not valid for MODE, return 0.  Note we
+        have to check both OP and OP + I since they may refer to
+        different parts of the register file.
+
+        Consider if OP refers to the last 96bit FP register and we want
+        subword 3 because that subword is known to contain a value we
+        needed.  */
       if (REGNO (op) < FIRST_PSEUDO_REGISTER
-         && ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode))
+         && (! HARD_REGNO_MODE_OK (REGNO (op), word_mode)
+             || ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode)))
        return 0;
       else if (REGNO (op) >= FIRST_PSEUDO_REGISTER
               || (REG_FUNCTION_VALUE_P (op)
@@ -1136,7 +1255,9 @@ operand_subword (op, i, validate_address, mode)
     return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
   else if (GET_CODE (op) == CONCAT)
     {
-      int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;
+      unsigned int partwords
+       = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;
+
       if (i < partwords)
        return operand_subword (XEXP (op, 0), i, validate_address, mode);
       return operand_subword (XEXP (op, 1), i - partwords,
@@ -1162,9 +1283,9 @@ operand_subword (op, i, validate_address, mode)
 
       new = gen_rtx_MEM (word_mode, addr);
 
-      MEM_VOLATILE_P (new) = MEM_VOLATILE_P (op);
-      MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (op);
+      MEM_COPY_ATTRIBUTES (new, op);
       RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (op);
+      MEM_ALIAS_SET (new) = MEM_ALIAS_SET (op);
 
       return new;
     }
@@ -1175,9 +1296,9 @@ operand_subword (op, i, validate_address, mode)
      are defined as returning one or two 32 bit values, respectively,
      and not values of BITS_PER_WORD bits.  */
 #ifdef REAL_ARITHMETIC
-/*  The output is some bits, the width of the target machine's word.
-    A wider-word host can surely hold them in a CONST_INT. A narrower-word
-    host can't.  */
+  /* The output is some bits, the width of the target machine's word.
+     A wider-word host can surely hold them in a CONST_INT. A narrower-word
+     host can't.  */
   if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
       && GET_MODE_CLASS (mode) == MODE_FLOAT
       && GET_MODE_BITSIZE (mode) == 64
@@ -1191,24 +1312,35 @@ operand_subword (op, i, validate_address, mode)
 
       /* We handle 32-bit and >= 64-bit words here.  Note that the order in
         which the words are written depends on the word endianness.
-
         ??? This is a potential portability problem and should
-        be fixed at some point.  */
+        be fixed at some point.
+
+        We must excercise caution with the sign bit.  By definition there
+        are 32 significant bits in K; there may be more in a HOST_WIDE_INT.
+        Consider a host with a 32-bit long and a 64-bit HOST_WIDE_INT.
+        So we explicitly mask and sign-extend as necessary.  */
       if (BITS_PER_WORD == 32)
-       return GEN_INT ((HOST_WIDE_INT) k[i]);
-#if HOST_BITS_PER_WIDE_INT > 32
+       {
+         val = k[i];
+         val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
+         return GEN_INT (val);
+       }
+#if HOST_BITS_PER_WIDE_INT >= 64
       else if (BITS_PER_WORD >= 64 && i == 0)
-       return GEN_INT ((((HOST_WIDE_INT) k[! WORDS_BIG_ENDIAN]) << 32)
-                       | (HOST_WIDE_INT) k[WORDS_BIG_ENDIAN]);
+       {
+         val = k[! WORDS_BIG_ENDIAN];
+         val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
+         val |= (HOST_WIDE_INT) k[WORDS_BIG_ENDIAN] & 0xffffffff;
+         return GEN_INT (val);
+       }
 #endif
       else if (BITS_PER_WORD == 16)
        {
-         long value;
-         value = k[i >> 1];
-         if ((i & 0x1) == !WORDS_BIG_ENDIAN)
-           value >>= 16;
-         value &= 0xffff;
-         return GEN_INT ((HOST_WIDE_INT) value);
+         val = k[i >> 1];
+         if ((i & 1) == !WORDS_BIG_ENDIAN)
+           val >>= 16;
+         val &= 0xffff;
+         return GEN_INT (val);
        }
       else
        abort ();
@@ -1217,16 +1349,31 @@ operand_subword (op, i, validate_address, mode)
           && GET_MODE_CLASS (mode) == MODE_FLOAT
           && GET_MODE_BITSIZE (mode) > 64
           && GET_CODE (op) == CONST_DOUBLE)
-  {
-    long k[4];
-    REAL_VALUE_TYPE rv;
+    {
+      long k[4];
+      REAL_VALUE_TYPE rv;
 
-    REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-    REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
 
-    if (BITS_PER_WORD == 32)
-      return GEN_INT ((HOST_WIDE_INT) k[i]);
-  }
+      if (BITS_PER_WORD == 32)
+       {
+         val = k[i];
+         val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
+         return GEN_INT (val);
+       }
+#if HOST_BITS_PER_WIDE_INT >= 64
+      else if (BITS_PER_WORD >= 64 && i <= 1)
+       {
+         val = k[i*2 + ! WORDS_BIG_ENDIAN];
+         val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
+         val |= (HOST_WIDE_INT) k[i*2 + WORDS_BIG_ENDIAN] & 0xffffffff;
+         return GEN_INT (val);
+       }
+#endif
+      else
+       abort ();
+    }
 #else /* no REAL_ARITHMETIC */
   if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
        && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
@@ -1263,13 +1410,18 @@ operand_subword (op, i, validate_address, mode)
       REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
       REAL_VALUE_TO_TARGET_SINGLE (rv, l);
 
+      /* Sign extend from known 32-bit value to HOST_WIDE_INT.  */
+      val = l;
+      val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
+
       if (BITS_PER_WORD == 16)
        {
-         if ((i & 0x1) == !WORDS_BIG_ENDIAN)
-           l >>= 16;
-         l &= 0xffff;
+         if ((i & 1) == !WORDS_BIG_ENDIAN)
+           val >>= 16;
+         val &= 0xffff;
        }
-      return GEN_INT ((HOST_WIDE_INT) l);
+
+      return GEN_INT (val);
     }
 #else
   if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
@@ -1336,26 +1488,7 @@ operand_subword (op, i, validate_address, mode)
   if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT)
     val = ((val >> ((i % size_ratio) * BITS_PER_WORD)));
 
-  /* Clear the bits that don't belong in our mode, unless they and our sign
-     bit are all one.  So we get either a reasonable negative value or a
-     reasonable unsigned value for this mode.  */
-  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
-      && ((val & ((HOST_WIDE_INT) (-1) << (bits_per_word - 1)))
-          != ((HOST_WIDE_INT) (-1) << (bits_per_word - 1))))
-    val &= ((HOST_WIDE_INT) 1 << bits_per_word) - 1;
-
-  /* If this would be an entire word for the target, but is not for
-     the host, then sign-extend on the host so that the number will look
-     the same way on the host that it would on the target.
-
-     For example, when building a 64 bit alpha hosted 32 bit sparc
-     targeted compiler, then we want the 32 bit unsigned value -1 to be
-     represented as a 64 bit value -1, and not as 0x00000000ffffffff.
-     The later confuses the sparc backend.  */
-
-  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
-      && (val & ((HOST_WIDE_INT) 1 << (bits_per_word - 1))))
-    val |= ((HOST_WIDE_INT) (-1) << bits_per_word);
+  val = trunc_int_for_mode (val, word_mode);
 
   return GEN_INT (val);
 }
@@ -1371,7 +1504,7 @@ operand_subword (op, i, validate_address, mode)
 rtx
 operand_subword_force (op, i, mode)
      rtx op;
-     int i;
+     unsigned int i;
      enum machine_mode mode;
 {
   rtx result = operand_subword (op, i, 1, mode);
@@ -1380,7 +1513,14 @@ operand_subword_force (op, i, mode)
     return result;
 
   if (mode != BLKmode && mode != VOIDmode)
-    op = force_reg (mode, op);
+    {
+      /* If this is a register which can not be accessed by words, copy it
+        to a pseudo register.  */
+      if (GET_CODE (op) == REG)
+       op = copy_to_reg (op);
+      else
+       op = force_reg (mode, op);
+    }
 
   result = operand_subword (op, i, 1, mode);
   if (result == 0)
@@ -1413,7 +1553,8 @@ reverse_comparison (insn)
     }
   else
     {
-      rtx new = gen_rtx_COMPARE (VOIDmode, CONST0_RTX (GET_MODE (comp)), comp);
+      rtx new = gen_rtx_COMPARE (VOIDmode,
+                                CONST0_RTX (GET_MODE (comp)), comp);
       if (GET_CODE (body) == SET)
        SET_SRC (body) = new;
       else
@@ -1455,9 +1596,9 @@ change_address (memref, mode, addr)
     return memref;
 
   new = gen_rtx_MEM (mode, addr);
-  MEM_VOLATILE_P (new) = MEM_VOLATILE_P (memref);
   RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (memref);
-  MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (memref);
+  MEM_COPY_ATTRIBUTES (new, memref);
+  MEM_ALIAS_SET (new) = MEM_ALIAS_SET (memref);
   return new;
 }
 \f
@@ -1469,52 +1610,15 @@ gen_label_rtx ()
   register rtx label;
 
   label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX,
-                             NULL_RTX, label_num++, NULL_PTR);
+                             NULL_RTX, label_num++, NULL_PTR, NULL_PTR);
 
   LABEL_NUSES (label) = 0;
+  LABEL_ALTERNATE_NAME (label) = NULL;
   return label;
 }
 \f
 /* For procedure integration.  */
 
-/* Return a newly created INLINE_HEADER rtx.  Should allocate this
-   from a permanent obstack when the opportunity arises.  */
-
-rtx
-gen_inline_header_rtx (first_insn, first_parm_insn, first_labelno,
-                      last_labelno, max_parm_regnum, max_regnum, args_size,
-                      pops_args, stack_slots, forced_labels, function_flags,
-                      outgoing_args_size, original_arg_vector,
-                      original_decl_initial, regno_rtx, regno_flag,
-                      regno_align, parm_reg_stack_loc)
-     rtx first_insn, first_parm_insn;
-     int first_labelno, last_labelno, max_parm_regnum, max_regnum, args_size;
-     int pops_args;
-     rtx stack_slots;
-     rtx forced_labels;
-     int function_flags;
-     int outgoing_args_size;
-     rtvec original_arg_vector;
-     rtx original_decl_initial;
-     rtvec regno_rtx;
-     char *regno_flag;
-     char *regno_align;
-     rtvec parm_reg_stack_loc;
-{
-  rtx header = gen_rtx_INLINE_HEADER (VOIDmode,
-                                     cur_insn_uid++, NULL_RTX,
-                                     first_insn, first_parm_insn,
-                                     first_labelno, last_labelno,
-                                     max_parm_regnum, max_regnum, args_size,
-                                     pops_args, stack_slots, forced_labels,
-                                     function_flags, outgoing_args_size,
-                                     original_arg_vector,
-                                     original_decl_initial,
-                                     regno_rtx, regno_flag, regno_align,
-                                     parm_reg_stack_loc);
-  return header;
-}
-
 /* Install new pointers to the first and last insns in the chain.
    Also, set cur_insn_uid to one higher than the last in use.
    Used for an inline-procedure after copying the insn chain.  */
@@ -1546,79 +1650,61 @@ set_new_first_and_last_label_num (first, last)
   first_label_num = first;
   last_label_num = last;
 }
-\f
-/* Save all variables describing the current status into the structure *P.
-   This is used before starting a nested function.  */
+
+/* Set the last label number found in the current function.
+   This is used when belatedly compiling an inline function.  */
 
 void
-save_emit_status (p)
-     struct function *p;
-{
-  p->reg_rtx_no = reg_rtx_no;
-  p->first_label_num = first_label_num;
-  p->first_insn = first_insn;
-  p->last_insn = last_insn;
-  p->sequence_rtl_expr = sequence_rtl_expr;
-  p->sequence_stack = sequence_stack;
-  p->cur_insn_uid = cur_insn_uid;
-  p->last_linenum = last_linenum;
-  p->last_filename = last_filename;
-  p->regno_pointer_flag = regno_pointer_flag;
-  p->regno_pointer_align = regno_pointer_align;
-  p->regno_pointer_flag_length = regno_pointer_flag_length;
-  p->regno_reg_rtx = regno_reg_rtx;
+set_new_last_label_num (last)
+     int last;
+{
+  base_label_num = label_num;
+  last_label_num = last;
 }
-
+\f
 /* Restore all variables describing the current status from the structure *P.
    This is used after a nested function.  */
 
 void
 restore_emit_status (p)
-     struct function *p;
+     struct function *p ATTRIBUTE_UNUSED;
 {
-  int i;
-
-  reg_rtx_no = p->reg_rtx_no;
-  first_label_num = p->first_label_num;
   last_label_num = 0;
-  first_insn = p->first_insn;
-  last_insn = p->last_insn;
-  sequence_rtl_expr = p->sequence_rtl_expr;
-  sequence_stack = p->sequence_stack;
-  cur_insn_uid = p->cur_insn_uid;
-  last_linenum = p->last_linenum;
-  last_filename = p->last_filename;
-  regno_pointer_flag = p->regno_pointer_flag;
-  regno_pointer_align = p->regno_pointer_align;
-  regno_pointer_flag_length = p->regno_pointer_flag_length;
-  regno_reg_rtx = p->regno_reg_rtx;
-
-  /* Clear our cache of rtx expressions for start_sequence and
-     gen_sequence.  */
-  sequence_element_free_list = 0;
-  for (i = 0; i < SEQUENCE_RESULT_SIZE; i++)
-    sequence_result[i] = 0;
+  clear_emit_caches ();
+}
 
-  free_insn = 0;
+/* Clear out all parts of the state in F that can safely be discarded
+   after the function has been compiled, to let garbage collection
+   reclaim the memory.  */
+
+void
+free_emit_status (f)
+     struct function *f;
+{
+  free (f->emit->x_regno_reg_rtx);
+  free (f->emit->regno_pointer_flag);
+  free (f->emit->regno_pointer_align);
+  free (f->emit);
+  f->emit = NULL;
 }
 \f
-/* Go through all the RTL insn bodies and copy any invalid shared structure.
-   It does not work to do this twice, because the mark bits set here
-   are not cleared afterwards.  */
+/* Go through all the RTL insn bodies and copy any invalid shared 
+   structure.  This routine should only be called once.  */
 
 void
-unshare_all_rtl (insn)
-     register rtx insn;
+unshare_all_rtl (fndecl, insn)
+     tree fndecl;
+     rtx insn;
 {
-  for (; insn; insn = NEXT_INSN (insn))
-    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
-       || GET_CODE (insn) == CALL_INSN)
-      {
-       PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
-       REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn));
-       LOG_LINKS (insn) = copy_rtx_if_shared (LOG_LINKS (insn));
-      }
+  tree decl;
+
+  /* Make sure that virtual parameters are not shared.  */
+  for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
+    copy_rtx_if_shared (DECL_RTL (decl));
 
+  /* Unshare just about everything else.  */
+  unshare_all_rtl_1 (insn);
+  
   /* Make sure the addresses of stack slots found outside the insn chain
      (such as, in DECL_RTL of a variable) are not shared
      with the insn chain.
@@ -1626,10 +1712,44 @@ unshare_all_rtl (insn)
      This special care is necessary when the stack slot MEM does not
      actually appear in the insn chain.  If it does appear, its address
      is unshared from all else at that point.  */
-
   copy_rtx_if_shared (stack_slot_list);
 }
 
+/* Go through all the RTL insn bodies and copy any invalid shared 
+   structure, again.  This is a fairly expensive thing to do so it
+   should be done sparingly.  */
+
+void
+unshare_all_rtl_again (insn)
+     rtx insn;
+{
+  rtx p;
+  for (p = insn; p; p = NEXT_INSN (p))
+    if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
+      {
+       reset_used_flags (PATTERN (p));
+       reset_used_flags (REG_NOTES (p));
+       reset_used_flags (LOG_LINKS (p));
+      }
+  unshare_all_rtl_1 (insn);
+}
+
+/* Go through all the RTL insn bodies and copy any invalid shared structure.
+   Assumes the mark bits are cleared at entry.  */
+
+static void
+unshare_all_rtl_1 (insn)
+     rtx insn;
+{
+  for (; insn; insn = NEXT_INSN (insn))
+    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      {
+       PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
+       REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn));
+       LOG_LINKS (insn) = copy_rtx_if_shared (LOG_LINKS (insn));
+      }
+}
+
 /* Mark ORIG as in use, and return a copy of it if it was already in use.
    Recursively does the same for subexpressions.  */
 
@@ -1640,7 +1760,7 @@ copy_rtx_if_shared (orig)
   register rtx x = orig;
   register int i;
   register enum rtx_code code;
-  register char *format_ptr;
+  register const char *format_ptr;
   int copied = 0;
 
   if (x == 0)
@@ -1682,25 +1802,17 @@ copy_rtx_if_shared (orig)
       return x;
 
     case MEM:
-      /* A MEM is allowed to be shared if its address is constant
-        or is a constant plus one of the special registers.  */
-      if (CONSTANT_ADDRESS_P (XEXP (x, 0))
-         || XEXP (x, 0) == virtual_stack_vars_rtx
-         || XEXP (x, 0) == virtual_incoming_args_rtx)
+      /* A MEM is allowed to be shared if its address is constant.
+
+        We used to allow sharing of MEMs which referenced 
+        virtual_stack_vars_rtx or virtual_incoming_args_rtx, but
+        that can lose.  instantiate_virtual_regs will not unshare
+        the MEMs, and combine may change the structure of the address
+        because it looks safe and profitable in one context, but
+        in some other context it creates unrecognizable RTL.  */
+      if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
        return x;
 
-      if (GET_CODE (XEXP (x, 0)) == PLUS
-         && (XEXP (XEXP (x, 0), 0) == virtual_stack_vars_rtx
-             || XEXP (XEXP (x, 0), 0) == virtual_incoming_args_rtx)
-         && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
-       {
-         /* This MEM can appear in more than one place,
-            but its address better not be shared with anything else.  */
-         if (! x->used)
-           XEXP (x, 0) = copy_rtx_if_shared (XEXP (x, 0));
-         x->used = 1;
-         return x;
-       }
       break;
 
     default:
@@ -1745,7 +1857,7 @@ copy_rtx_if_shared (orig)
              int len = XVECLEN (x, i);
 
              if (copied && len > 0)
-               XVEC (x, i) = gen_rtvec_vv (len, XVEC (x, i)->elem);
+               XVEC (x, i) = gen_rtvec_v (len, XVEC (x, i)->elem);
              for (j = 0; j < len; j++)
                XVECEXP (x, i, j) = copy_rtx_if_shared (XVECEXP (x, i, j));
            }
@@ -1764,7 +1876,7 @@ reset_used_flags (x)
 {
   register int i, j;
   register enum rtx_code code;
-  register char *format_ptr;
+  register const char *format_ptr;
 
   if (x == 0)
     return;
@@ -1893,7 +2005,7 @@ get_last_insn_anywhere ()
   struct sequence_stack *stack;
   if (last_insn)
     return last_insn;
-  for (stack = sequence_stack; stack; stack = stack->next)
+  for (stack = seq_stack; stack; stack = stack->next)
     if (stack->last != 0)
       return stack->last;
   return 0;
@@ -1906,6 +2018,34 @@ get_max_uid ()
 {
   return cur_insn_uid;
 }
+
+/* Renumber instructions so that no instruction UIDs are wasted.  */
+
+void
+renumber_insns (stream)
+     FILE *stream;
+{
+  rtx insn;
+
+  /* If we're not supposed to renumber instructions, don't.  */
+  if (!flag_renumber_insns)
+    return;
+
+  /* If there aren't that many instructions, then it's not really
+     worth renumbering them.  */
+  if (flag_renumber_insns == 1 && get_max_uid () < 25000)
+    return;
+
+  cur_insn_uid = 1;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (stream)
+       fprintf (stream, "Renumbering insn %d to %d\n", 
+                INSN_UID (insn), cur_insn_uid);
+      INSN_UID (insn) = cur_insn_uid++;
+    }
+}
 \f
 /* Return the next insn.  If it is a SEQUENCE, return the first insn
    of the sequence.  */
@@ -2019,6 +2159,17 @@ prev_real_insn (insn)
    does not look inside SEQUENCEs.  Until reload has completed, this is the
    same as next_real_insn.  */
 
+int
+active_insn_p (insn)
+     rtx insn;
+{
+  return (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
+         || (GET_CODE (insn) == INSN
+             && (! reload_completed
+                 || (GET_CODE (PATTERN (insn)) != USE
+                     && GET_CODE (PATTERN (insn)) != CLOBBER))));
+}
+
 rtx
 next_active_insn (insn)
      rtx insn;
@@ -2026,12 +2177,7 @@ next_active_insn (insn)
   while (insn)
     {
       insn = NEXT_INSN (insn);
-      if (insn == 0
-         || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
-         || (GET_CODE (insn) == INSN
-             && (! reload_completed
-                 || (GET_CODE (PATTERN (insn)) != USE
-                     && GET_CODE (PATTERN (insn)) != CLOBBER))))
+      if (insn == 0 || active_insn_p (insn))
        break;
     }
 
@@ -2049,12 +2195,7 @@ prev_active_insn (insn)
   while (insn)
     {
       insn = PREV_INSN (insn);
-      if (insn == 0
-         || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
-         || (GET_CODE (insn) == INSN
-             && (! reload_completed
-                 || (GET_CODE (PATTERN (insn)) != USE
-                     && GET_CODE (PATTERN (insn)) != CLOBBER))))
+      if (insn == 0 || active_insn_p (insn))
        break;
     }
 
@@ -2106,7 +2247,8 @@ link_cc0_insns (insn)
   if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE)
     user = XVECEXP (PATTERN (user), 0, 0);
 
-  REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn, REG_NOTES (user));
+  REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn,
+                                       REG_NOTES (user));
   REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn));
 }
 
@@ -2222,7 +2364,8 @@ try_split (pat, trial, last)
             Ignore deleted insns, which can be occur if not optimizing.  */
          for (tem = NEXT_INSN (before); tem != after;
               tem = NEXT_INSN (tem))
-           if (! INSN_DELETED_P (tem))
+           if (! INSN_DELETED_P (tem)
+               && GET_RTX_CLASS (GET_CODE (tem)) == 'i')
              tem = try_split (PATTERN (tem), tem, 1);
        }
       /* Avoid infinite loop if the result matches the original pattern.  */
@@ -2237,7 +2380,9 @@ try_split (pat, trial, last)
 
       /* Return either the first or the last insn, depending on which was
         requested.  */
-      return last ? prev_active_insn (after) : next_active_insn (before);
+      return last 
+               ? (after ? prev_active_insn (after) : last_insn) 
+               : next_active_insn (before);
     }
 
   return trial;
@@ -2253,7 +2398,7 @@ make_insn_raw (pattern)
   register rtx insn;
 
   /* If in RTL generation phase, see if FREE_INSN can be used.  */
-  if (free_insn != 0 && rtx_equal_function_value_matters)
+  if (!ggc_p && free_insn != 0 && rtx_equal_function_value_matters)
     {
       insn = free_insn;
       free_insn = NEXT_INSN (free_insn);
@@ -2268,6 +2413,18 @@ make_insn_raw (pattern)
   LOG_LINKS (insn) = NULL;
   REG_NOTES (insn) = NULL;
 
+#ifdef ENABLE_RTL_CHECKING
+  if (insn
+      && GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+      && (returnjump_p (insn)
+         || (GET_CODE (insn) == SET
+             && SET_DEST (insn) == pc_rtx)))
+    {
+      warning ("ICE: emit_insn used where emit_jump_insn needed:\n");
+      debug_rtx (insn);
+    }
+#endif
+  
   return insn;
 }
 
@@ -2357,7 +2514,7 @@ add_insn_after (insn, after)
     last_insn = insn;
   else
     {
-      struct sequence_stack *stack = sequence_stack;
+      struct sequence_stack *stack = seq_stack;
       /* Scan all pending sequences too.  */
       for (; stack; stack = stack->next)
        if (after == stack->last)
@@ -2408,7 +2565,7 @@ add_insn_before (insn, before)
     first_insn = insn;
   else
     {
-      struct sequence_stack *stack = sequence_stack;
+      struct sequence_stack *stack = seq_stack;
       /* Scan all pending sequences too.  */
       for (; stack; stack = stack->next)
        if (before == stack->first)
@@ -2426,6 +2583,64 @@ add_insn_before (insn, before)
     PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn;
 }
 
+/* Remove an insn from its doubly-linked list.  This function knows how
+   to handle sequences.  */
+void
+remove_insn (insn)
+     rtx insn;
+{
+  rtx next = NEXT_INSN (insn);
+  rtx prev = PREV_INSN (insn);
+  if (prev)
+    {
+      NEXT_INSN (prev) = next;
+      if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
+       {
+         rtx sequence = PATTERN (prev);
+         NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = next;
+       }
+    }
+  else if (first_insn == insn)
+    first_insn = next;
+  else
+    {
+      struct sequence_stack *stack = seq_stack;
+      /* Scan all pending sequences too.  */
+      for (; stack; stack = stack->next)
+       if (insn == stack->first)
+         {
+           stack->first = next;
+           break;
+         }
+
+      if (stack == 0)
+       abort ();
+    }
+
+  if (next)
+    {
+      PREV_INSN (next) = prev;
+      if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE)
+       PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = prev;
+    }
+  else if (last_insn == insn)
+    last_insn = prev;
+  else
+    {
+      struct sequence_stack *stack = seq_stack;
+      /* Scan all pending sequences too.  */
+      for (; stack; stack = stack->next)
+       if (insn == stack->last)
+         {
+           stack->last = prev;
+           break;
+         }
+
+      if (stack == 0)
+       abort ();
+    }
+}
+
 /* Delete all insns made since FROM.
    FROM becomes the new last instruction.  */
 
@@ -2517,6 +2732,89 @@ reorder_insns_with_line_notes (from, to, after)
                          NOTE_LINE_NUMBER (after_line),
                          to);
 }
+
+/* Remove unncessary notes from the instruction stream.  */
+
+void
+remove_unncessary_notes ()
+{
+  rtx insn;
+  rtx next;
+
+  /* We must not remove the first instruction in the function because
+     the compiler depends on the first instruction being a note.  */
+  for (insn = NEXT_INSN (get_insns ()); insn; insn = next)
+    {
+      /* Remember what's next.  */
+      next = NEXT_INSN (insn);
+
+      /* We're only interested in notes.  */
+      if (GET_CODE (insn) != NOTE)
+       continue;
+
+      /* By now, all notes indicating lexical blocks should have
+        NOTE_BLOCK filled in.  */
+      if ((NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
+          || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
+         && NOTE_BLOCK (insn) == NULL_TREE)
+       abort ();
+
+      /* Remove NOTE_INSN_DELETED notes.  */
+      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
+       remove_insn (insn);
+      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
+       {
+         /* Scan back to see if there are any non-note instructions
+            between INSN and the beginning of this block.  If not,
+            then there is no PC range in the generated code that will
+            actually be in this block, so there's no point in
+            remembering the existence of the block.  */
+         rtx prev;
+
+         for (prev = PREV_INSN (insn); prev; prev = PREV_INSN (prev))
+           {
+             /* This block contains a real instruction.  Note that we
+                don't include labels; if the only thing in the block
+                is a label, then there are still no PC values that
+                lie within the block.  */
+             if (GET_RTX_CLASS (GET_CODE (prev)) == 'i')
+               break;
+
+             /* We're only interested in NOTEs.  */
+             if (GET_CODE (prev) != NOTE)
+               continue;
+
+             if (NOTE_LINE_NUMBER (prev) == NOTE_INSN_BLOCK_BEG)
+               {
+                 /* If the BLOCKs referred to by these notes don't
+                    match, then something is wrong with our BLOCK
+                    nesting structure.  */
+                 if (NOTE_BLOCK (prev) != NOTE_BLOCK (insn))
+                   abort ();
+
+                 /* Never delete the BLOCK for the outermost scope
+                    of the function; we can refer to names from
+                    that scope even if the block notes are messed up.  */
+                 if (! is_body_block (NOTE_BLOCK (insn)))
+                   {
+                     debug_ignore_block (NOTE_BLOCK (insn));
+
+                     remove_insn (prev);
+                     remove_insn (insn);
+                   }
+                 break;
+               }
+             else if (NOTE_LINE_NUMBER (prev) == NOTE_INSN_BLOCK_END)
+               /* There's a nested block.  We need to leave the
+                  current block in place since otherwise the debugger
+                  wouldn't be able to show symbols from our block in
+                  the nested block.  */
+               break;
+           }
+       }
+    }
+}
+
 \f
 /* Emit an insn of given code and pattern
    at a specified place within the doubly-linked list.  */
@@ -2539,7 +2837,7 @@ emit_insn_before (pattern, before)
          insn = XVECEXP (pattern, 0, i);
          add_insn_before (insn, before);
        }
-      if (XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
+      if (!ggc_p && XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
        sequence_result[XVECLEN (pattern, 0)] = pattern;
     }
   else
@@ -2551,6 +2849,20 @@ emit_insn_before (pattern, before)
   return insn;
 }
 
+/* Similar to emit_insn_before, but update basic block boundaries as well.  */
+
+rtx
+emit_block_insn_before (pattern, before, block)
+     rtx pattern, before;
+     basic_block block;
+{
+  rtx prev = PREV_INSN (before);
+  rtx r = emit_insn_before (pattern, before);
+  if (block && block->head == before)
+    block->head = NEXT_INSN (prev);
+  return r;
+}
+
 /* Make an instruction with body PATTERN and code JUMP_INSN
    and output it before the instruction BEFORE.  */
 
@@ -2593,7 +2905,7 @@ emit_call_insn_before (pattern, before)
 }
 
 /* Make an insn of code BARRIER
-   and output it before the insn AFTER.  */
+   and output it before the insn BEFORE.  */
 
 rtx
 emit_barrier_before (before)
@@ -2607,6 +2919,23 @@ emit_barrier_before (before)
   return insn;
 }
 
+/* Emit the label LABEL before the insn BEFORE.  */
+
+rtx
+emit_label_before (label, before)
+     rtx label, before;
+{
+  /* This can be called twice for the same label as a result of the
+     confusion that follows a syntax error!  So make it harmless.  */
+  if (INSN_UID (label) == 0)
+    {
+      INSN_UID (label) = cur_insn_uid++;
+      add_insn_before (label, before);
+    }
+
+  return label;
+}
+
 /* Emit a note of subtype SUBTYPE before the insn BEFORE.  */
 
 rtx
@@ -2642,7 +2971,7 @@ emit_insn_after (pattern, after)
          add_insn_after (insn, after);
          after = insn;
        }
-      if (XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
+      if (!ggc_p && XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
        sequence_result[XVECLEN (pattern, 0)] = pattern;
     }
   else
@@ -2676,6 +3005,19 @@ emit_insn_after_with_line_notes (pattern, after, from)
                          insn);
 }
 
+/* Similar to emit_insn_after, but update basic block boundaries as well.  */
+
+rtx
+emit_block_insn_after (pattern, after, block)
+     rtx pattern, after;
+     basic_block block;
+{
+  rtx r = emit_insn_after (pattern, after);
+  if (block && block->end == after)
+    block->end = r;
+  return r;
+}
+
 /* Make an insn of code JUMP_INSN with body PATTERN
    and output it after the insn AFTER.  */
 
@@ -2748,7 +3090,7 @@ emit_note_after (subtype, after)
 
 rtx
 emit_line_note_after (file, line, after)
-     char *file;
+     const char *file;
      int line;
      rtx after;
 {
@@ -2790,7 +3132,7 @@ emit_insn (pattern)
          insn = XVECEXP (pattern, 0, i);
          add_insn (insn);
        }
-      if (XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
+      if (!ggc_p && XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
        sequence_result[XVECLEN (pattern, 0)] = pattern;
     }
   else
@@ -2947,11 +3289,10 @@ emit_barrier ()
 
 rtx
 emit_line_note (file, line)
-     char *file;
+     const char *file;
      int line;
 {
-  emit_filename = file;
-  emit_lineno = line;
+  set_file_and_line_for_stmt (file, line);
 
 #if 0
   if (no_line_numbers)
@@ -2968,7 +3309,7 @@ emit_line_note (file, line)
 
 rtx
 emit_note (file, line)
-     char *file;
+     const char *file;
      int line;
 {
   register rtx note;
@@ -2996,11 +3337,11 @@ emit_note (file, line)
   return note;
 }
 
-/* Emit a NOTE, and don't omit it even if LINE it the previous note.  */
+/* Emit a NOTE, and don't omit it even if LINE is the previous note.  */
 
 rtx
 emit_line_note_force (file, line)
-     char *file;
+     const char *file;
      int line;
 {
   last_linenum = -1;
@@ -3015,6 +3356,24 @@ force_next_line_note ()
 {
   last_linenum = -1;
 }
+
+/* Place a note of KIND on insn INSN with DATUM as the datum. If a
+   note of this type already exists, remove it first. */
+
+void 
+set_unique_reg_note (insn, kind, datum)
+     rtx insn;
+     enum reg_note kind;
+     rtx datum;
+{
+  rtx note = find_reg_note (insn, kind, NULL_RTX);
+
+  /* First remove the note if there already is one.  */
+  if (note) 
+    remove_note (insn, note);
+
+  REG_NOTES (insn) = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
+}
 \f
 /* Return an indication of which type of insn should have X as a body.
    The value is CODE_LABEL, INSN, CALL_INSN or JUMP_INSN.  */
@@ -3080,35 +3439,35 @@ emit (x)
     abort ();
 }
 \f
-/* Begin emitting insns to a sequence which can be packaged in an RTL_EXPR.  */
+/* Begin emitting insns to a sequence which can be packaged in an
+   RTL_EXPR.  If this sequence will contain something that might cause
+   the compiler to pop arguments to function calls (because those
+   pops have previously been deferred; see INHIBIT_DEFER_POP for more
+   details), use do_pending_stack_adjust before calling this function.
+   That will ensure that the deferred pops are not accidentally
+   emitted in the middel of this sequence.  */
 
 void
 start_sequence ()
 {
   struct sequence_stack *tem;
 
-  if (sequence_element_free_list)
-    {
-      /* Reuse a previously-saved struct sequence_stack.  */
-      tem = sequence_element_free_list;
-      sequence_element_free_list = tem->next;
-    }
-  else
-    tem = (struct sequence_stack *) permalloc (sizeof (struct sequence_stack));
+  tem = (struct sequence_stack *) xmalloc (sizeof (struct sequence_stack));
 
-  tem->next = sequence_stack;
+  tem->next = seq_stack;
   tem->first = first_insn;
   tem->last = last_insn;
-  tem->sequence_rtl_expr = sequence_rtl_expr;
+  tem->sequence_rtl_expr = seq_rtl_expr;
 
-  sequence_stack = tem;
+  seq_stack = tem;
 
   first_insn = 0;
   last_insn = 0;
 }
 
-/* Similarly, but indicate that this sequence will be placed in 
-   T, an RTL_EXPR.  */
+/* Similarly, but indicate that this sequence will be placed in T, an
+   RTL_EXPR.  See the documentation for start_sequence for more
+   information about how to use this function.  */
 
 void
 start_sequence_for_rtl_expr (t)
@@ -3116,11 +3475,12 @@ start_sequence_for_rtl_expr (t)
 {
   start_sequence ();
 
-  sequence_rtl_expr = t;
+  seq_rtl_expr = t;
 }
 
-/* Set up the insn chain starting with FIRST
-   as the current sequence, saving the previously current one.  */
+/* Set up the insn chain starting with FIRST as the current sequence,
+   saving the previously current one.  See the documentation for
+   start_sequence for more information about how to use this function.  */
 
 void
 push_to_sequence (first)
@@ -3136,6 +3496,20 @@ push_to_sequence (first)
   last_insn = last;
 }
 
+/* Set up the insn chain from a chain stort in FIRST to LAST.  */
+
+void
+push_to_full_sequence (first, last)
+     rtx first, last;
+{
+  start_sequence ();
+  first_insn = first;
+  last_insn = last;
+  /* We really should have the end of the insn chain here.  */
+  if (last && NEXT_INSN (last))
+    abort ();
+}
+
 /* Set up the outer-level insn chain
    as the current sequence, saving the previously current one.  */
 
@@ -3146,12 +3520,12 @@ push_topmost_sequence ()
 
   start_sequence ();
 
-  for (stack = sequence_stack; stack; stack = stack->next)
+  for (stack = seq_stack; stack; stack = stack->next)
     top = stack;
 
   first_insn = top->first;
   last_insn = top->last;
-  sequence_rtl_expr = top->sequence_rtl_expr;
+  seq_rtl_expr = top->sequence_rtl_expr;
 }
 
 /* After emitting to the outer-level insn chain, update the outer-level
@@ -3162,33 +3536,52 @@ pop_topmost_sequence ()
 {
   struct sequence_stack *stack, *top = NULL;
 
-  for (stack = sequence_stack; stack; stack = stack->next)
+  for (stack = seq_stack; stack; stack = stack->next)
     top = stack;
 
   top->first = first_insn;
   top->last = last_insn;
-  /* ??? Why don't we save sequence_rtl_expr here?  */
+  /* ??? Why don't we save seq_rtl_expr here?  */
 
   end_sequence ();
 }
 
 /* After emitting to a sequence, restore previous saved state.
 
-   To get the contents of the sequence just made,
-   you must call `gen_sequence' *before* calling here.  */
+   To get the contents of the sequence just made, you must call
+   `gen_sequence' *before* calling here.  
+
+   If the compiler might have deferred popping arguments while
+   generating this sequence, and this sequence will not be immediately
+   inserted into the instruction stream, use do_pending_stack_adjust
+   before calling gen_sequence.  That will ensure that the deferred
+   pops are inserted into this sequence, and not into some random
+   location in the instruction stream.  See INHIBIT_DEFER_POP for more
+   information about deferred popping of arguments.  */
 
 void
 end_sequence ()
 {
-  struct sequence_stack *tem = sequence_stack;
+  struct sequence_stack *tem = seq_stack;
 
   first_insn = tem->first;
   last_insn = tem->last;
-  sequence_rtl_expr = tem->sequence_rtl_expr;
-  sequence_stack = tem->next;
+  seq_rtl_expr = tem->sequence_rtl_expr;
+  seq_stack = tem->next;
 
-  tem->next = sequence_element_free_list;
-  sequence_element_free_list = tem;
+  free (tem);
+}
+
+/* This works like end_sequence, but records the old sequence in FIRST
+   and LAST.  */
+
+void
+end_full_sequence (first, last)
+     rtx *first, *last;
+{
+  *first = first_insn;
+  *last = last_insn;
+  end_sequence();
 }
 
 /* Return 1 if currently emitting into a sequence.  */
@@ -3196,7 +3589,7 @@ end_sequence ()
 int
 in_sequence_p ()
 {
-  return sequence_stack != 0;
+  return seq_stack != 0;
 }
 
 /* Generate a SEQUENCE rtx containing the insns already emitted
@@ -3218,25 +3611,29 @@ gen_sequence ()
   for (tem = first_insn; tem; tem = NEXT_INSN (tem))
     len++;
 
-  /* If only one insn, return its pattern rather than a SEQUENCE.
+  /* If only one insn, return it rather than a SEQUENCE.
      (Now that we cache SEQUENCE expressions, it isn't worth special-casing
-     the case of an empty list.)  */
+     the case of an empty list.)     
+     We only return the pattern of an insn if its code is INSN and it
+     has no notes.  This ensures that no information gets lost.  */
   if (len == 1
       && ! RTX_FRAME_RELATED_P (first_insn)
-      && (GET_CODE (first_insn) == INSN
-         || GET_CODE (first_insn) == JUMP_INSN
-         /* Don't discard the call usage field.  */
-         || (GET_CODE (first_insn) == CALL_INSN
-             && CALL_INSN_FUNCTION_USAGE (first_insn) == NULL_RTX)))
-    {
-      NEXT_INSN (first_insn) = free_insn;
-      free_insn = first_insn;
+      && GET_CODE (first_insn) == INSN
+      /* Don't throw away any reg notes. */
+      && REG_NOTES (first_insn) == 0)
+    {
+      if (!ggc_p)
+       {
+         NEXT_INSN (first_insn) = free_insn;
+         free_insn = first_insn;
+       }
       return PATTERN (first_insn);
     }
 
   /* Put them in a vector.  See if we already have a SEQUENCE of the
      appropriate length around.  */
-  if (len < SEQUENCE_RESULT_SIZE && (result = sequence_result[len]) != 0)
+  if (!ggc_p && len < SEQUENCE_RESULT_SIZE 
+      && (result = sequence_result[len]) != 0)
     sequence_result[len] = 0;
   else
     {
@@ -3254,52 +3651,250 @@ gen_sequence ()
   return result;
 }
 \f
+/* Put the various virtual registers into REGNO_REG_RTX.  */
+
+void
+init_virtual_regs (es)
+     struct emit_status *es;
+{
+  rtx *ptr = es->x_regno_reg_rtx;
+  ptr[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;
+  ptr[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;
+  ptr[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
+  ptr[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
+  ptr[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx;
+}
+
+void
+clear_emit_caches ()
+{
+  int i;
+
+  /* Clear the start_sequence/gen_sequence cache.  */
+  for (i = 0; i < SEQUENCE_RESULT_SIZE; i++)
+    sequence_result[i] = 0;
+  free_insn = 0;
+}
+\f
+/* Used by copy_insn_1 to avoid copying SCRATCHes more than once.  */
+static rtx copy_insn_scratch_in[MAX_RECOG_OPERANDS];
+static rtx copy_insn_scratch_out[MAX_RECOG_OPERANDS];
+static int copy_insn_n_scratches;
+
+/* When an insn is being copied by copy_insn_1, this is nonzero if we have
+   copied an ASM_OPERANDS.
+   In that case, it is the original input-operand vector.  */
+static rtvec orig_asm_operands_vector;
+
+/* When an insn is being copied by copy_insn_1, this is nonzero if we have
+   copied an ASM_OPERANDS.
+   In that case, it is the copied input-operand vector.  */
+static rtvec copy_asm_operands_vector;
+
+/* Likewise for the constraints vector.  */
+static rtvec orig_asm_constraints_vector;
+static rtvec copy_asm_constraints_vector;
+
+/* Recursively create a new copy of an rtx for copy_insn.
+   This function differs from copy_rtx in that it handles SCRATCHes and
+   ASM_OPERANDs properly.
+   Normally, this function is not used directly; use copy_insn as front end.
+   However, you could first copy an insn pattern with copy_insn and then use
+   this function afterwards to properly copy any REG_NOTEs containing
+   SCRATCHes.  */
+
+rtx
+copy_insn_1 (orig)
+     register rtx orig;
+{
+  register rtx copy;
+  register int i, j;
+  register RTX_CODE code;
+  register const char *format_ptr;
+
+  code = GET_CODE (orig);
+
+  switch (code)
+    {
+    case REG:
+    case QUEUED:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+    case CODE_LABEL:
+    case PC:
+    case CC0:
+    case ADDRESSOF:
+      return orig;
+
+    case SCRATCH:
+      for (i = 0; i < copy_insn_n_scratches; i++)
+       if (copy_insn_scratch_in[i] == orig)
+         return copy_insn_scratch_out[i];
+      break;
+
+    case CONST:
+      /* CONST can be shared if it contains a SYMBOL_REF.  If it contains
+        a LABEL_REF, it isn't sharable.  */
+      if (GET_CODE (XEXP (orig, 0)) == PLUS
+         && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
+         && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
+       return orig;
+      break;
+      
+      /* A MEM with a constant address is not sharable.  The problem is that
+        the constant address may need to be reloaded.  If the mem is shared,
+        then reloading one copy of this mem will cause all copies to appear
+        to have been reloaded.  */
+
+    default:
+      break;
+    }
+
+  copy = rtx_alloc (code);
+
+  /* Copy the various flags, and other information.  We assume that
+     all fields need copying, and then clear the fields that should
+     not be copied.  That is the sensible default behavior, and forces
+     us to explicitly document why we are *not* copying a flag.  */
+  memcpy (copy, orig, sizeof (struct rtx_def) - sizeof (rtunion));
+
+  /* We do not copy the USED flag, which is used as a mark bit during
+     walks over the RTL.  */
+  copy->used = 0;
+
+  /* We do not copy JUMP, CALL, or FRAME_RELATED for INSNs.  */
+  if (GET_RTX_CLASS (code) == 'i')
+    {
+      copy->jump = 0;
+      copy->call = 0;
+      copy->frame_related = 0;
+    }
+  
+  format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
+
+  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
+    {
+      copy->fld[i] = orig->fld[i];
+      switch (*format_ptr++)
+       {
+       case 'e':
+         if (XEXP (orig, i) != NULL)
+           XEXP (copy, i) = copy_insn_1 (XEXP (orig, i));
+         break;
+
+       case 'E':
+       case 'V':
+         if (XVEC (orig, i) == orig_asm_constraints_vector)
+           XVEC (copy, i) = copy_asm_constraints_vector;
+         else if (XVEC (orig, i) == orig_asm_operands_vector)
+           XVEC (copy, i) = copy_asm_operands_vector;
+         else if (XVEC (orig, i) != NULL)
+           {
+             XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
+             for (j = 0; j < XVECLEN (copy, i); j++)
+               XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j));
+           }
+         break;
+
+       case 'b':
+         {
+           bitmap new_bits = BITMAP_OBSTACK_ALLOC (rtl_obstack);
+           bitmap_copy (new_bits, XBITMAP (orig, i));
+           XBITMAP (copy, i) = new_bits;
+           break;
+         }
+
+       case 't':
+       case 'w':
+       case 'i':
+       case 's':
+       case 'S':
+       case 'u':
+       case '0':
+         /* These are left unchanged.  */
+         break;
+
+       default:
+         abort ();
+       }
+    }
+
+  if (code == SCRATCH)
+    {
+      i = copy_insn_n_scratches++;
+      if (i >= MAX_RECOG_OPERANDS)
+       abort ();
+      copy_insn_scratch_in[i] = orig;
+      copy_insn_scratch_out[i] = copy;
+    }
+  else if (code == ASM_OPERANDS)
+    {
+      orig_asm_operands_vector = XVEC (orig, 3);
+      copy_asm_operands_vector = XVEC (copy, 3);
+      orig_asm_constraints_vector = XVEC (orig, 4);
+      copy_asm_constraints_vector = XVEC (copy, 4);
+    }
+
+  return copy;
+}
+
+/* Create a new copy of an rtx.
+   This function differs from copy_rtx in that it handles SCRATCHes and
+   ASM_OPERANDs properly.
+   INSN doesn't really have to be a full INSN; it could be just the
+   pattern.  */
+rtx
+copy_insn (insn)
+     rtx insn;
+{
+  copy_insn_n_scratches = 0;
+  orig_asm_operands_vector = 0;
+  orig_asm_constraints_vector = 0;
+  copy_asm_operands_vector = 0;
+  copy_asm_constraints_vector = 0;
+  return copy_insn_1 (insn);
+}
+
 /* Initialize data structures and variables in this file
    before generating rtl for each function.  */
 
 void
 init_emit ()
 {
-  int i;
+  struct function *f = cfun;
 
+  f->emit = (struct emit_status *) xmalloc (sizeof (struct emit_status));
   first_insn = NULL;
   last_insn = NULL;
-  sequence_rtl_expr = NULL;
+  seq_rtl_expr = NULL;
   cur_insn_uid = 1;
   reg_rtx_no = LAST_VIRTUAL_REGISTER + 1;
   last_linenum = 0;
   last_filename = 0;
   first_label_num = label_num;
   last_label_num = 0;
-  sequence_stack = NULL;
+  seq_stack = NULL;
 
-  /* Clear the start_sequence/gen_sequence cache.  */
-  sequence_element_free_list = 0;
-  for (i = 0; i < SEQUENCE_RESULT_SIZE; i++)
-    sequence_result[i] = 0;
-  free_insn = 0;
+  clear_emit_caches ();
 
   /* Init the tables that describe all the pseudo regs.  */
 
-  regno_pointer_flag_length = LAST_VIRTUAL_REGISTER + 101;
+  f->emit->regno_pointer_flag_length = LAST_VIRTUAL_REGISTER + 101;
 
-  regno_pointer_flag 
-    = (char *) savealloc (regno_pointer_flag_length);
-  bzero (regno_pointer_flag, regno_pointer_flag_length);
+  f->emit->regno_pointer_flag 
+    = (char *) xcalloc (f->emit->regno_pointer_flag_length, sizeof (char));
 
-  regno_pointer_align
-    = (char *) savealloc (regno_pointer_flag_length);
-  bzero (regno_pointer_align, regno_pointer_flag_length);
+  f->emit->regno_pointer_align
+    = (char *) xcalloc (f->emit->regno_pointer_flag_length,
+                       sizeof (char));
 
   regno_reg_rtx 
-    = (rtx *) savealloc (regno_pointer_flag_length * sizeof (rtx));
-  bzero ((char *) regno_reg_rtx, regno_pointer_flag_length * sizeof (rtx));
+    = (rtx *) xcalloc (f->emit->regno_pointer_flag_length * sizeof (rtx),
+                      sizeof (rtx));
 
   /* Put copies of all the virtual register rtx into regno_reg_rtx.  */
-  regno_reg_rtx[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;
-  regno_reg_rtx[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;
-  regno_reg_rtx[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
-  regno_reg_rtx[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
+  init_virtual_regs (f->emit);
 
   /* Indicate that the virtual registers and stack locations are
      all pointers.  */
@@ -3312,22 +3907,19 @@ init_emit ()
   REGNO_POINTER_FLAG (VIRTUAL_STACK_VARS_REGNUM) = 1;
   REGNO_POINTER_FLAG (VIRTUAL_STACK_DYNAMIC_REGNUM) = 1;
   REGNO_POINTER_FLAG (VIRTUAL_OUTGOING_ARGS_REGNUM) = 1;
+  REGNO_POINTER_FLAG (VIRTUAL_CFA_REGNUM) = 1;
 
 #ifdef STACK_BOUNDARY
-  REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM)
-    = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
-
-  REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM)
-    = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM)
-    = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM)
-    = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM)
-    = STACK_BOUNDARY / BITS_PER_UNIT;
+  REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY;
+
+  REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (VIRTUAL_CFA_REGNUM) = BITS_PER_WORD;
 #endif
 
 #ifdef INIT_EXPANDERS
@@ -3335,6 +3927,41 @@ init_emit ()
 #endif
 }
 
+/* Mark SS for GC.  */
+
+static void
+mark_sequence_stack (ss)
+     struct sequence_stack *ss;
+{
+  while (ss)
+    {
+      ggc_mark_rtx (ss->first);
+      ggc_mark_tree (ss->sequence_rtl_expr);
+      ss = ss->next;
+    }
+}
+
+/* Mark ES for GC.  */
+
+void
+mark_emit_status (es)
+     struct emit_status *es;
+{
+  rtx *r;
+  int i;
+
+  if (es == 0)
+    return;
+
+  for (i = es->regno_pointer_flag_length, r = es->x_regno_reg_rtx;
+       i > 0; --i, ++r)
+    ggc_mark_rtx (*r);
+
+  mark_sequence_stack (es->sequence_stack);
+  ggc_mark_tree (es->sequence_rtl_expr);
+  ggc_mark_rtx (es->x_first_insn);
+}
+
 /* Create some permanent unique rtl objects shared between all functions.
    LINE_NUMBERS is nonzero if line numbers are to be generated.  */
 
@@ -3344,15 +3971,15 @@ init_emit_once (line_numbers)
 {
   int i;
   enum machine_mode mode;
+  enum machine_mode double_mode;
 
   no_line_numbers = ! line_numbers;
 
-  sequence_stack = NULL;
-
   /* Compute the word and byte modes.  */
 
   byte_mode = VOIDmode;
   word_mode = VOIDmode;
+  double_mode = VOIDmode;
 
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
@@ -3366,27 +3993,75 @@ init_emit_once (line_numbers)
        word_mode = mode;
     }
 
+#ifndef DOUBLE_TYPE_SIZE
+#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE
+         && double_mode == VOIDmode)
+       double_mode = mode;
+    }
+
   ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0);
 
+  /* Assign register numbers to the globally defined register rtx.
+     This must be done at runtime because the register number field
+     is in a union and some compilers can't initialize unions.  */
+
+  pc_rtx = gen_rtx (PC, VOIDmode);
+  cc0_rtx = gen_rtx (CC0, VOIDmode);
+  stack_pointer_rtx = gen_rtx_raw_REG (Pmode, STACK_POINTER_REGNUM);
+  frame_pointer_rtx = gen_rtx_raw_REG (Pmode, FRAME_POINTER_REGNUM);
+  if (hard_frame_pointer_rtx == 0)
+    hard_frame_pointer_rtx = gen_rtx_raw_REG (Pmode, 
+                                             HARD_FRAME_POINTER_REGNUM);
+  if (arg_pointer_rtx == 0)
+    arg_pointer_rtx = gen_rtx_raw_REG (Pmode, ARG_POINTER_REGNUM);
+  virtual_incoming_args_rtx = 
+    gen_rtx_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
+  virtual_stack_vars_rtx = 
+    gen_rtx_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
+  virtual_stack_dynamic_rtx = 
+    gen_rtx_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);
+  virtual_outgoing_args_rtx = 
+    gen_rtx_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM); 
+  virtual_cfa_rtx = gen_rtx_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
+
+  /* These rtx must be roots if GC is enabled.  */
+  if (ggc_p)
+    ggc_add_rtx_root (global_rtl, GR_MAX);
+
+#ifdef INIT_EXPANDERS
+  /* This is to initialize save_machine_status and restore_machine_status before
+     the first call to push_function_context_to.  This is needed by the Chill
+     front end which calls push_function_context_to before the first cal to
+     init_function_start.  */
+  INIT_EXPANDERS;
+#endif
+
   /* Create the unique rtx's for certain rtx codes and operand values.  */
 
+  /* Don't use gen_rtx here since gen_rtx in this case
+     tries to use these variables.  */
   for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
-    {
-      PUT_CODE (&const_int_rtx[i + MAX_SAVED_CONST_INT], CONST_INT);
-      PUT_MODE (&const_int_rtx[i + MAX_SAVED_CONST_INT], VOIDmode);
-      INTVAL (&const_int_rtx[i + MAX_SAVED_CONST_INT]) = i;
-    }
+    const_int_rtx[i + MAX_SAVED_CONST_INT] = 
+      gen_rtx_raw_CONST_INT (VOIDmode, i);
+  if (ggc_p)
+    ggc_add_rtx_root (const_int_rtx, 2 * MAX_SAVED_CONST_INT + 1);
 
   if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT
       && STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT)
-    const_true_rtx = &const_int_rtx[STORE_FLAG_VALUE + MAX_SAVED_CONST_INT];
+    const_true_rtx = const_int_rtx[STORE_FLAG_VALUE + MAX_SAVED_CONST_INT];
   else
     const_true_rtx = gen_rtx_CONST_INT (VOIDmode, STORE_FLAG_VALUE);
 
-  dconst0 = REAL_VALUE_ATOF ("0", DFmode);
-  dconst1 = REAL_VALUE_ATOF ("1", DFmode);
-  dconst2 = REAL_VALUE_ATOF ("2", DFmode);
-  dconstm1 = REAL_VALUE_ATOF ("-1", DFmode);
+  dconst0 = REAL_VALUE_ATOF ("0", double_mode);
+  dconst1 = REAL_VALUE_ATOF ("1", double_mode);
+  dconst2 = REAL_VALUE_ATOF ("2", double_mode);
+  dconstm1 = REAL_VALUE_ATOF ("-1", double_mode);
 
   for (i = 0; i <= 2; i++)
     {
@@ -3418,36 +4093,12 @@ init_emit_once (line_numbers)
        const_tiny_rtx[i][(int) mode] = GEN_INT (i);
     }
 
-  for (mode = GET_CLASS_NARROWEST_MODE (MODE_CC); mode != VOIDmode;
-       mode = GET_MODE_WIDER_MODE (mode))
-    const_tiny_rtx[0][(int) mode] = const0_rtx;
+  for (mode = CCmode; mode < MAX_MACHINE_MODE; ++mode)
+    if (GET_MODE_CLASS (mode) == MODE_CC)
+      const_tiny_rtx[0][(int) mode] = const0_rtx;
 
-
-  /* Assign register numbers to the globally defined register rtx.
-     This must be done at runtime because the register number field
-     is in a union and some compilers can't initialize unions.  */
-
-  REGNO (stack_pointer_rtx) = STACK_POINTER_REGNUM;
-  PUT_MODE (stack_pointer_rtx, Pmode);
-  REGNO (frame_pointer_rtx) = FRAME_POINTER_REGNUM;
-  PUT_MODE (frame_pointer_rtx, Pmode);
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-  REGNO (hard_frame_pointer_rtx) = HARD_FRAME_POINTER_REGNUM;
-  PUT_MODE (hard_frame_pointer_rtx, Pmode);
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-  REGNO (arg_pointer_rtx) = ARG_POINTER_REGNUM;
-  PUT_MODE (arg_pointer_rtx, Pmode);
-#endif
-
-  REGNO (virtual_incoming_args_rtx) = VIRTUAL_INCOMING_ARGS_REGNUM;
-  PUT_MODE (virtual_incoming_args_rtx, Pmode);
-  REGNO (virtual_stack_vars_rtx) = VIRTUAL_STACK_VARS_REGNUM;
-  PUT_MODE (virtual_stack_vars_rtx, Pmode);
-  REGNO (virtual_stack_dynamic_rtx) = VIRTUAL_STACK_DYNAMIC_REGNUM;
-  PUT_MODE (virtual_stack_dynamic_rtx, Pmode);
-  REGNO (virtual_outgoing_args_rtx) = VIRTUAL_OUTGOING_ARGS_REGNUM;
-  PUT_MODE (virtual_outgoing_args_rtx, Pmode);
+  ggc_add_rtx_root (&const_tiny_rtx[0][0], sizeof(const_tiny_rtx)/sizeof(rtx));
+  ggc_add_rtx_root (&const_true_rtx, 1);
 
 #ifdef RETURN_ADDRESS_POINTER_REGNUM
   return_address_pointer_rtx
@@ -3476,7 +4127,8 @@ init_emit_once (line_numbers)
 
 #ifdef STATIC_CHAIN_INCOMING_REGNUM
   if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM)
-    static_chain_incoming_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
+    static_chain_incoming_rtx
+      = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
   else
 #endif
     static_chain_incoming_rtx = static_chain_rtx;
@@ -3495,6 +4147,19 @@ init_emit_once (line_numbers)
 #ifdef PIC_OFFSET_TABLE_REGNUM
   pic_offset_table_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
 #endif
+
+  ggc_add_rtx_root (&pic_offset_table_rtx, 1);
+  ggc_add_rtx_root (&struct_value_rtx, 1);
+  ggc_add_rtx_root (&struct_value_incoming_rtx, 1);
+  ggc_add_rtx_root (&static_chain_rtx, 1);
+  ggc_add_rtx_root (&static_chain_incoming_rtx, 1);
+  ggc_add_rtx_root (&return_address_pointer_rtx, 1);
+
+  /* Initialize the CONST_INT hash table.  */
+  const_int_htab = htab_create (37, const_int_htab_hash, 
+                               const_int_htab_eq, NULL);
+  ggc_add_root (&const_int_htab, 1, sizeof (const_int_htab), 
+               rtx_htab_mark);
 }
 \f
 /* Query and clear/ restore no_line_numbers.  This is used by the