OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index a528641..1f51e12 100644 (file)
@@ -1,12 +1,13 @@
 /* Emit RTL for the GCC expander.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,25 +16,22 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 /* Middle-to-low level generation of rtx code and insns.
 
-   This file contains the functions `gen_rtx', `gen_reg_rtx'
-   and `gen_label_rtx' that are the usual ways of creating rtl
-   expressions for most purposes.
-
-   It also has the functions for creating insns and linking
-   them in the doubly-linked chain.
+   This file contains support functions for creating rtl expressions
+   and manipulating them in the doubly-linked chain of insns.
 
    The patterns of the insns are created by machine-dependent
    routines in insn-emit.c, which is generated automatically from
-   the machine description.  These routines use `gen_rtx' to make
-   the individual rtx's of the pattern; what is machine dependent
-   is the kind of rtx's they make and what arguments they use.  */
+   the machine description.  These routines make the individual rtx's
+   of the pattern with `gen_rtx_fmt_ee' and others in genrtl.[ch],
+   which are automatically generated from rtl.def; what is machine
+   dependent is the kind of rtx's they make and what arguments they
+   use.  */
 
 #include "config.h"
 #include "system.h"
@@ -52,11 +50,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "insn-config.h"
 #include "recog.h"
 #include "real.h"
+#include "fixed-value.h"
 #include "bitmap.h"
 #include "basic-block.h"
 #include "ggc.h"
 #include "debug.h"
 #include "langhooks.h"
+#include "tree-pass.h"
+#include "df.h"
 
 /* Commonly used modes.  */
 
@@ -65,22 +66,21 @@ 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.  */
 
+/* Datastructures maintained for currently processed function in RTL form.  */
 
-/* This is *not* reset after each function.  It gives each CODE_LABEL
-   in the entire compilation a unique label number.  */
-
-static GTY(()) int label_num = 1;
+struct rtl_data x_rtl;
 
-/* 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.  */
+/* Indexed by pseudo register number, gives the rtx for that pseudo.
+   Allocated in parallel with regno_pointer_align.  
+   FIXME: We could put it into emit_status struct, but gengtype is not able to deal
+   with length attribute nested in top level structures.  */
 
-static int last_label_num;
+rtx * regno_reg_rtx;
 
-/* Value label_num had when set_new_first_and_last_label_number was called.
-   If label_num has not changed since then, last_label_num is valid.  */
+/* This is *not* reset after each function.  It gives each CODE_LABEL
+   in the entire compilation a unique label number.  */
 
-static int base_label_num;
+static GTY(()) int label_num = 1;
 
 /* Nonzero means do not generate NOTEs for source line numbers.  */
 
@@ -110,14 +110,12 @@ rtx const_true_rtx;
 REAL_VALUE_TYPE dconst0;
 REAL_VALUE_TYPE dconst1;
 REAL_VALUE_TYPE dconst2;
-REAL_VALUE_TYPE dconst3;
-REAL_VALUE_TYPE dconst10;
 REAL_VALUE_TYPE dconstm1;
-REAL_VALUE_TYPE dconstm2;
 REAL_VALUE_TYPE dconsthalf;
-REAL_VALUE_TYPE dconstthird;
-REAL_VALUE_TYPE dconstpi;
-REAL_VALUE_TYPE dconste;
+
+/* Record fixed-point constant 0 and 1.  */
+FIXED_VALUE_TYPE fconst0[MAX_FCONST0];
+FIXED_VALUE_TYPE fconst1[MAX_FCONST1];
 
 /* All references to the following fixed hard registers go through
    these unique rtl objects.  On machines where the frame-pointer and
@@ -170,35 +168,38 @@ static GTY ((if_marked ("ggc_marked_p"), param_is (struct reg_attrs)))
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
      htab_t const_double_htab;
 
-#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_location (cfun->emit->x_last_location)
-#define first_label_num (cfun->emit->x_first_label_num)
+/* A hash table storing all CONST_FIXEDs.  */
+static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
+     htab_t const_fixed_htab;
+
+#define first_insn (crtl->emit.x_first_insn)
+#define last_insn (crtl->emit.x_last_insn)
+#define cur_insn_uid (crtl->emit.x_cur_insn_uid)
+#define last_location (crtl->emit.x_last_location)
+#define first_label_num (crtl->emit.x_first_label_num)
 
-static rtx make_jump_insn_raw (rtx);
 static rtx make_call_insn_raw (rtx);
-static rtx find_line_note (rtx);
 static rtx change_address_1 (rtx, enum machine_mode, rtx, int);
-static void unshare_all_rtl_1 (rtx);
-static void unshare_all_decls (tree);
-static void reset_used_decls (tree);
+static void set_used_decls (tree);
 static void mark_label_nuses (rtx);
 static hashval_t const_int_htab_hash (const void *);
 static int const_int_htab_eq (const void *, const void *);
 static hashval_t const_double_htab_hash (const void *);
 static int const_double_htab_eq (const void *, const void *);
 static rtx lookup_const_double (rtx);
+static hashval_t const_fixed_htab_hash (const void *);
+static int const_fixed_htab_eq (const void *, const void *);
+static rtx lookup_const_fixed (rtx);
 static hashval_t mem_attrs_htab_hash (const void *);
 static int mem_attrs_htab_eq (const void *, const void *);
-static mem_attrs *get_mem_attrs (HOST_WIDE_INT, tree, rtx, rtx, unsigned int,
+static mem_attrs *get_mem_attrs (alias_set_type, tree, rtx, rtx, unsigned int,
                                 enum machine_mode);
 static hashval_t reg_attrs_htab_hash (const void *);
 static int reg_attrs_htab_eq (const void *, const void *);
 static reg_attrs *get_reg_attrs (tree, int);
 static tree component_ref_for_mem_expr (tree);
-static rtx gen_const_vector_0 (enum machine_mode);
-static rtx gen_complex_constant_part (enum machine_mode, rtx, int);
+static rtx gen_const_vector (enum machine_mode, int);
+static void copy_rtx_if_shared_1 (rtx *orig);
 
 /* Probability of the conditional branch currently proceeded by try_split.
    Set to -1 otherwise.  */
@@ -209,7 +210,7 @@ int split_branch_probability = -1;
 static hashval_t
 const_int_htab_hash (const void *x)
 {
-  return (hashval_t) INTVAL ((rtx) x);
+  return (hashval_t) INTVAL ((const_rtx) x);
 }
 
 /* Returns nonzero if the value represented by X (which is really a
@@ -219,14 +220,14 @@ const_int_htab_hash (const void *x)
 static int
 const_int_htab_eq (const void *x, const void *y)
 {
-  return (INTVAL ((rtx) x) == *((const HOST_WIDE_INT *) y));
+  return (INTVAL ((const_rtx) x) == *((const HOST_WIDE_INT *) y));
 }
 
 /* Returns a hash code for X (which is really a CONST_DOUBLE).  */
 static hashval_t
 const_double_htab_hash (const void *x)
 {
-  rtx value = (rtx) x;
+  const_rtx const value = (const_rtx) x;
   hashval_t h;
 
   if (GET_MODE (value) == VOIDmode)
@@ -245,7 +246,7 @@ const_double_htab_hash (const void *x)
 static int
 const_double_htab_eq (const void *x, const void *y)
 {
-  rtx a = (rtx)x, b = (rtx)y;
+  const_rtx const a = (const_rtx)x, b = (const_rtx)y;
 
   if (GET_MODE (a) != GET_MODE (b))
     return 0;
@@ -257,17 +258,44 @@ const_double_htab_eq (const void *x, const void *y)
                           CONST_DOUBLE_REAL_VALUE (b));
 }
 
+/* Returns a hash code for X (which is really a CONST_FIXED).  */
+
+static hashval_t
+const_fixed_htab_hash (const void *x)
+{
+  const_rtx const value = (const_rtx) x;
+  hashval_t h;
+
+  h = fixed_hash (CONST_FIXED_VALUE (value));
+  /* MODE is used in the comparison, so it should be in the hash.  */
+  h ^= GET_MODE (value);
+  return h;
+}
+
+/* Returns nonzero if the value represented by X (really a ...)
+   is the same as that represented by Y (really a ...).  */
+
+static int
+const_fixed_htab_eq (const void *x, const void *y)
+{
+  const_rtx const a = (const_rtx) x, b = (const_rtx) y;
+
+  if (GET_MODE (a) != GET_MODE (b))
+    return 0;
+  return fixed_identical (CONST_FIXED_VALUE (a), CONST_FIXED_VALUE (b));
+}
+
 /* Returns a hash code for X (which is a really a mem_attrs *).  */
 
 static hashval_t
 mem_attrs_htab_hash (const void *x)
 {
-  mem_attrs *p = (mem_attrs *) x;
+  const mem_attrs *const p = (const mem_attrs *) x;
 
   return (p->alias ^ (p->align * 1000)
          ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000)
          ^ ((p->size ? INTVAL (p->size) : 0) * 2500000)
-         ^ (size_t) p->expr);
+         ^ (size_t) iterative_hash_expr (p->expr, 0));
 }
 
 /* Returns nonzero if the value represented by X (which is really a
@@ -277,11 +305,14 @@ mem_attrs_htab_hash (const void *x)
 static int
 mem_attrs_htab_eq (const void *x, const void *y)
 {
-  mem_attrs *p = (mem_attrs *) x;
-  mem_attrs *q = (mem_attrs *) y;
+  const mem_attrs *const p = (const mem_attrs *) x;
+  const mem_attrs *const q = (const mem_attrs *) y;
 
-  return (p->alias == q->alias && p->expr == q->expr && p->offset == q->offset
-         && p->size == q->size && p->align == q->align);
+  return (p->alias == q->alias && p->offset == q->offset
+         && p->size == q->size && p->align == q->align
+         && (p->expr == q->expr
+             || (p->expr != NULL_TREE && q->expr != NULL_TREE
+                 && operand_equal_p (p->expr, q->expr, 0))));
 }
 
 /* Allocate a new mem_attrs structure and insert it into the hash table if
@@ -289,7 +320,7 @@ mem_attrs_htab_eq (const void *x, const void *y)
    MEM of mode MODE.  */
 
 static mem_attrs *
-get_mem_attrs (HOST_WIDE_INT alias, tree expr, rtx offset, rtx size,
+get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size,
               unsigned int align, enum machine_mode mode)
 {
   mem_attrs attrs;
@@ -318,7 +349,7 @@ get_mem_attrs (HOST_WIDE_INT alias, tree expr, rtx offset, rtx size,
       memcpy (*slot, &attrs, sizeof (mem_attrs));
     }
 
-  return *slot;
+  return (mem_attrs *) *slot;
 }
 
 /* Returns a hash code for X (which is a really a reg_attrs *).  */
@@ -326,7 +357,7 @@ get_mem_attrs (HOST_WIDE_INT alias, tree expr, rtx offset, rtx size,
 static hashval_t
 reg_attrs_htab_hash (const void *x)
 {
-  reg_attrs *p = (reg_attrs *) x;
+  const reg_attrs *const p = (const reg_attrs *) x;
 
   return ((p->offset * 1000) ^ (long) p->decl);
 }
@@ -338,8 +369,8 @@ reg_attrs_htab_hash (const void *x)
 static int
 reg_attrs_htab_eq (const void *x, const void *y)
 {
-  reg_attrs *p = (reg_attrs *) x;
-  reg_attrs *q = (reg_attrs *) y;
+  const reg_attrs *const p = (const reg_attrs *) x;
+  const reg_attrs *const q = (const reg_attrs *) y;
 
   return (p->decl == q->decl && p->offset == q->offset);
 }
@@ -367,8 +398,23 @@ get_reg_attrs (tree decl, int offset)
       memcpy (*slot, &attrs, sizeof (reg_attrs));
     }
 
-  return *slot;
+  return (reg_attrs *) *slot;
+}
+
+
+#if !HAVE_blockage
+/* Generate an empty ASM_INPUT, which is used to block attempts to schedule
+   across this insn. */
+
+rtx
+gen_blockage (void)
+{
+  rtx x = gen_rtx_ASM_INPUT (VOIDmode, "");
+  MEM_VOLATILE_P (x) = true;
+  return x;
 }
+#endif
+
 
 /* Generate a new REG rtx.  Make sure ORIGINAL_REGNO is set properly, and
    don't attempt to share with the various global pieces of rtl (such as
@@ -439,11 +485,39 @@ const_double_from_real_value (REAL_VALUE_TYPE value, enum machine_mode mode)
   rtx real = rtx_alloc (CONST_DOUBLE);
   PUT_MODE (real, mode);
 
-  memcpy (&CONST_DOUBLE_LOW (real), &value, sizeof (REAL_VALUE_TYPE));
+  real->u.rv = value;
 
   return lookup_const_double (real);
 }
 
+/* Determine whether FIXED, a CONST_FIXED, already exists in the
+   hash table.  If so, return its counterpart; otherwise add it
+   to the hash table and return it.  */
+
+static rtx
+lookup_const_fixed (rtx fixed)
+{
+  void **slot = htab_find_slot (const_fixed_htab, fixed, INSERT);
+  if (*slot == 0)
+    *slot = fixed;
+
+  return (rtx) *slot;
+}
+
+/* Return a CONST_FIXED rtx for a fixed-point value specified by
+   VALUE in mode MODE.  */
+
+rtx
+const_fixed_from_fixed_value (FIXED_VALUE_TYPE value, enum machine_mode mode)
+{
+  rtx fixed = rtx_alloc (CONST_FIXED);
+  PUT_MODE (fixed, mode);
+
+  fixed->u.fv = value;
+
+  return lookup_const_fixed (fixed);
+}
+
 /* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair
    of ints: I0 is the low-order word and I1 is the high-order word.
    Do not use this routine for non-integer modes; convert to
@@ -455,64 +529,28 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode)
   rtx value;
   unsigned int i;
 
+  /* There are the following cases (note that there are no modes with
+     HOST_BITS_PER_WIDE_INT < GET_MODE_BITSIZE (mode) < 2 * HOST_BITS_PER_WIDE_INT):
+
+     1) If GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT, then we use
+       gen_int_mode.
+     2) GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT, but the value of
+       the integer fits into HOST_WIDE_INT anyway (i.e., i1 consists only
+       from copies of the sign bit, and sign of i0 and i1 are the same),  then 
+       we return a CONST_INT for i0.
+     3) Otherwise, we create a CONST_DOUBLE for i0 and i1.  */
   if (mode != VOIDmode)
     {
-      int width;
-      if (GET_MODE_CLASS (mode) != MODE_INT
-         && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT
-         /* We can get a 0 for an error mark.  */
-         && GET_MODE_CLASS (mode) != MODE_VECTOR_INT
-         && GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT)
-       abort ();
-
-      /* We clear out all bits that don't belong in 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.  */
-      width = GET_MODE_BITSIZE (mode);
-      if (width < HOST_BITS_PER_WIDE_INT
-         && ((i0 & ((HOST_WIDE_INT) (-1) << (width - 1)))
-             != ((HOST_WIDE_INT) (-1) << (width - 1))))
-       i0 &= ((HOST_WIDE_INT) 1 << width) - 1, i1 = 0;
-      else if (width == HOST_BITS_PER_WIDE_INT
-              && ! (i1 == ~0 && i0 < 0))
-       i1 = 0;
-      else if (width > 2 * HOST_BITS_PER_WIDE_INT)
-       /* We cannot represent this value as a constant.  */
-       abort ();
-
-      /* 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 latter confuses the sparc backend.  */
-
-      if (width < HOST_BITS_PER_WIDE_INT
-         && (i0 & ((HOST_WIDE_INT) 1 << (width - 1))))
-       i0 |= ((HOST_WIDE_INT) (-1) << width);
-
-      /* If MODE fits within HOST_BITS_PER_WIDE_INT, always use a
-        CONST_INT.
-
-        ??? Strictly speaking, this is wrong if we create a CONST_INT for
-        a large unsigned constant with the size of MODE being
-        HOST_BITS_PER_WIDE_INT and later try to interpret that constant
-        in a wider mode.  In that case we will mis-interpret it as a
-        negative number.
-
-        Unfortunately, the only alternative is to make a CONST_DOUBLE for
-        any constant in any mode if it is an unsigned constant larger
-        than the maximum signed integer in an int on the host.  However,
-        doing this will break everyone that always expects to see a
-        CONST_INT for SImode and smaller.
-
-        We have always been making CONST_INTs in this case, so nothing
-        new is being broken.  */
-
-      if (width <= HOST_BITS_PER_WIDE_INT)
-       i1 = (i0 < 0) ? ~(HOST_WIDE_INT) 0 : 0;
+      gcc_assert (GET_MODE_CLASS (mode) == MODE_INT
+                 || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT
+                 /* We can get a 0 for an error mark.  */
+                 || GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+                 || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT);
+
+      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+       return gen_int_mode (i0, mode);
+
+      gcc_assert (GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT);
     }
 
   /* If this integer fits in one word, return a CONST_INT.  */
@@ -609,182 +647,175 @@ gen_rtx_MEM (enum machine_mode mode, rtx addr)
   return rt;
 }
 
+/* Generate a memory referring to non-trapping constant memory.  */
+
 rtx
-gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset)
+gen_const_mem (enum machine_mode mode, rtx addr)
 {
-  /* This is the most common failure type.
-     Catch it early so we can see who does it.  */
-  if ((offset % GET_MODE_SIZE (mode)) != 0)
-    abort ();
-
-  /* This check isn't usable right now because combine will
-     throw arbitrary crap like a CALL into a SUBREG in
-     gen_lowpart_for_combine so we must just eat it.  */
-#if 0
-  /* Check for this too.  */
-  if (offset >= GET_MODE_SIZE (GET_MODE (reg)))
-    abort ();
-#endif
-  return gen_rtx_raw_SUBREG (mode, reg, offset);
+  rtx mem = gen_rtx_MEM (mode, addr);
+  MEM_READONLY_P (mem) = 1;
+  MEM_NOTRAP_P (mem) = 1;
+  return mem;
 }
 
-/* Generate a SUBREG representing the least-significant part of REG if MODE
-   is smaller than mode of REG, otherwise paradoxical SUBREG.  */
+/* Generate a MEM referring to fixed portions of the frame, e.g., register
+   save areas.  */
 
 rtx
-gen_lowpart_SUBREG (enum machine_mode mode, rtx reg)
+gen_frame_mem (enum machine_mode mode, rtx addr)
 {
-  enum machine_mode inmode;
-
-  inmode = GET_MODE (reg);
-  if (inmode == VOIDmode)
-    inmode = mode;
-  return gen_rtx_SUBREG (mode, reg,
-                        subreg_lowpart_offset (mode, inmode));
+  rtx mem = gen_rtx_MEM (mode, addr);
+  MEM_NOTRAP_P (mem) = 1;
+  set_mem_alias_set (mem, get_frame_alias_set ());
+  return mem;
 }
-\f
-/* rtx gen_rtx (code, mode, [element1, ..., elementn])
-**
-**         This routine generates an RTX of the size specified by
-**     <code>, which is an RTX code.   The RTX structure is initialized
-**     from the arguments <element1> through <elementn>, which are
-**     interpreted according to the specific RTX type's format.   The
-**     special machine mode associated with the rtx (if any) is specified
-**     in <mode>.
-**
-**         gen_rtx can be invoked in a way which resembles the lisp-like
-**     rtx it will generate.   For example, the following rtx structure:
-**
-**           (plus:QI (mem:QI (reg:SI 1))
-**                    (mem:QI (plusw:SI (reg:SI 2) (reg:SI 3))))
-**
-**             ...would be generated by the following C code:
-**
-**             gen_rtx (PLUS, QImode,
-**                 gen_rtx (MEM, QImode,
-**                     gen_rtx (REG, SImode, 1)),
-**                 gen_rtx (MEM, QImode,
-**                     gen_rtx (PLUS, SImode,
-**                         gen_rtx (REG, SImode, 2),
-**                         gen_rtx (REG, SImode, 3)))),
-*/
-
-/*VARARGS2*/
+
+/* Generate a MEM referring to a temporary use of the stack, not part
+    of the fixed stack frame.  For example, something which is pushed
+    by a target splitter.  */
 rtx
-gen_rtx (enum rtx_code code, enum machine_mode mode, ...)
+gen_tmp_stack_mem (enum machine_mode mode, rtx addr)
 {
-  int i;               /* Array indices...                     */
-  const char *fmt;     /* Current rtx's format...              */
-  rtx rt_val;          /* RTX to return to caller...           */
-  va_list p;
-
-  va_start (p, mode);
-
-  switch (code)
-    {
-    case CONST_INT:
-      rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT));
-      break;
+  rtx mem = gen_rtx_MEM (mode, addr);
+  MEM_NOTRAP_P (mem) = 1;
+  if (!cfun->calls_alloca)
+    set_mem_alias_set (mem, get_frame_alias_set ());
+  return mem;
+}
 
-    case CONST_DOUBLE:
-      {
-       HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT);
-       HOST_WIDE_INT arg1 = va_arg (p, HOST_WIDE_INT);
+/* We want to create (subreg:OMODE (obj:IMODE) OFFSET).  Return true if
+   this construct would be valid, and false otherwise.  */
 
-       rt_val = immed_double_const (arg0, arg1, mode);
-      }
-      break;
+bool
+validate_subreg (enum machine_mode omode, enum machine_mode imode,
+                const_rtx reg, unsigned int offset)
+{
+  unsigned int isize = GET_MODE_SIZE (imode);
+  unsigned int osize = GET_MODE_SIZE (omode);
 
-    case REG:
-      rt_val = gen_rtx_REG (mode, va_arg (p, int));
-      break;
+  /* All subregs must be aligned.  */
+  if (offset % osize != 0)
+    return false;
 
-    case MEM:
-      rt_val = gen_rtx_MEM (mode, va_arg (p, rtx));
-      break;
+  /* The subreg offset cannot be outside the inner object.  */
+  if (offset >= isize)
+    return false;
 
-    default:
-      rt_val = rtx_alloc (code);       /* Allocate the storage space.  */
-      rt_val->mode = mode;             /* Store the machine mode...  */
+  /* ??? This should not be here.  Temporarily continue to allow word_mode
+     subregs of anything.  The most common offender is (subreg:SI (reg:DF)).
+     Generally, backends are doing something sketchy but it'll take time to
+     fix them all.  */
+  if (omode == word_mode)
+    ;
+  /* ??? Similarly, e.g. with (subreg:DF (reg:TI)).  Though store_bit_field
+     is the culprit here, and not the backends.  */
+  else if (osize >= UNITS_PER_WORD && isize >= osize)
+    ;
+  /* Allow component subregs of complex and vector.  Though given the below
+     extraction rules, it's not always clear what that means.  */
+  else if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode))
+          && GET_MODE_INNER (imode) == omode)
+    ;
+  /* ??? x86 sse code makes heavy use of *paradoxical* vector subregs,
+     i.e. (subreg:V4SF (reg:SF) 0).  This surely isn't the cleanest way to
+     represent this.  It's questionable if this ought to be represented at
+     all -- why can't this all be hidden in post-reload splitters that make
+     arbitrarily mode changes to the registers themselves.  */
+  else if (VECTOR_MODE_P (omode) && GET_MODE_INNER (omode) == imode)
+    ;
+  /* Subregs involving floating point modes are not allowed to
+     change size.  Therefore (subreg:DI (reg:DF) 0) is fine, but
+     (subreg:SI (reg:DF) 0) isn't.  */
+  else if (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode))
+    {
+      if (isize != osize)
+       return false;
+    }
 
-      fmt = GET_RTX_FORMAT (code);     /* Find the right format...  */
-      for (i = 0; i < GET_RTX_LENGTH (code); i++)
-       {
-         switch (*fmt++)
-           {
-           case '0':           /* Field with unknown use.  Zero it.  */
-             X0EXP (rt_val, i) = NULL_RTX;
-             break;
+  /* Paradoxical subregs must have offset zero.  */
+  if (osize > isize)
+    return offset == 0;
 
-           case 'i':           /* An integer?  */
-             XINT (rt_val, i) = va_arg (p, int);
-             break;
+  /* This is a normal subreg.  Verify that the offset is representable.  */
 
-           case 'w':           /* A wide integer? */
-             XWINT (rt_val, i) = va_arg (p, HOST_WIDE_INT);
-             break;
+  /* For hard registers, we already have most of these rules collected in
+     subreg_offset_representable_p.  */
+  if (reg && REG_P (reg) && HARD_REGISTER_P (reg))
+    {
+      unsigned int regno = REGNO (reg);
 
-           case 's':           /* A string?  */
-             XSTR (rt_val, i) = va_arg (p, char *);
-             break;
+#ifdef CANNOT_CHANGE_MODE_CLASS
+      if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode))
+         && GET_MODE_INNER (imode) == omode)
+       ;
+      else if (REG_CANNOT_CHANGE_MODE_P (regno, imode, omode))
+       return false;
+#endif
 
-           case 'e':           /* An expression?  */
-           case 'u':           /* An insn?  Same except when printing.  */
-             XEXP (rt_val, i) = va_arg (p, rtx);
-             break;
+      return subreg_offset_representable_p (regno, imode, offset, omode);
+    }
 
-           case 'E':           /* An RTX vector?  */
-             XVEC (rt_val, i) = va_arg (p, rtvec);
-             break;
+  /* For pseudo registers, we want most of the same checks.  Namely:
+     If the register no larger than a word, the subreg must be lowpart.
+     If the register is larger than a word, the subreg must be the lowpart
+     of a subword.  A subreg does *not* perform arbitrary bit extraction.
+     Given that we've already checked mode/offset alignment, we only have
+     to check subword subregs here.  */
+  if (osize < UNITS_PER_WORD)
+    {
+      enum machine_mode wmode = isize > UNITS_PER_WORD ? word_mode : imode;
+      unsigned int low_off = subreg_lowpart_offset (omode, wmode);
+      if (offset % UNITS_PER_WORD != low_off)
+       return false;
+    }
+  return true;
+}
 
-           case 'b':           /* A bitmap? */
-             XBITMAP (rt_val, i) = va_arg (p, bitmap);
-             break;
+rtx
+gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset)
+{
+  gcc_assert (validate_subreg (mode, GET_MODE (reg), reg, offset));
+  return gen_rtx_raw_SUBREG (mode, reg, offset);
+}
 
-           case 't':           /* A tree? */
-             XTREE (rt_val, i) = va_arg (p, tree);
-             break;
+/* Generate a SUBREG representing the least-significant part of REG if MODE
+   is smaller than mode of REG, otherwise paradoxical SUBREG.  */
 
-           default:
-             abort ();
-           }
-       }
-      break;
-    }
+rtx
+gen_lowpart_SUBREG (enum machine_mode mode, rtx reg)
+{
+  enum machine_mode inmode;
 
-  va_end (p);
-  return rt_val;
+  inmode = GET_MODE (reg);
+  if (inmode == VOIDmode)
+    inmode = mode;
+  return gen_rtx_SUBREG (mode, reg,
+                        subreg_lowpart_offset (mode, inmode));
 }
+\f
 
-/* gen_rtvec (n, [rt1, ..., rtn])
-**
-**         This routine creates an rtvec and stores within it the
-**     pointers to rtx's which are its arguments.
-*/
+/* Create an rtvec and stores within it the RTXen passed in the arguments.  */
 
-/*VARARGS1*/
 rtvec
 gen_rtvec (int n, ...)
 {
-  int i, save_n;
-  rtx *vector;
+  int i;
+  rtvec rt_val;
   va_list p;
 
   va_start (p, n);
 
+  /* Don't allocate an empty rtvec...  */
   if (n == 0)
-    return NULL_RTVEC;         /* Don't allocate an empty rtvec...     */
+    return NULL_RTVEC;
 
-  vector = alloca (n * sizeof (rtx));
+  rt_val = rtvec_alloc (n);
 
   for (i = 0; i < n; i++)
-    vector[i] = va_arg (p, rtx);
+    rt_val->elem[i] = va_arg (p, rtx);
 
-  /* The definition of VA_* in K&R C causes `n' to go out of scope.  */
-  save_n = n;
   va_end (p);
-
-  return gen_rtvec_v (save_n, vector);
+  return rt_val;
 }
 
 rtvec
@@ -793,10 +824,11 @@ gen_rtvec_v (int n, rtx *argp)
   int i;
   rtvec rt_val;
 
+  /* Don't allocate an empty rtvec...  */
   if (n == 0)
-    return NULL_RTVEC;         /* Don't allocate an empty rtvec...     */
+    return NULL_RTVEC;
 
-  rt_val = rtvec_alloc (n);    /* Allocate an rtvec...                 */
+  rt_val = rtvec_alloc (n);
 
   for (i = 0; i < n; i++)
     rt_val->elem[i] = *argp++;
@@ -804,19 +836,40 @@ gen_rtvec_v (int n, rtx *argp)
   return rt_val;
 }
 \f
+/* Return the number of bytes between the start of an OUTER_MODE
+   in-memory value and the start of an INNER_MODE in-memory value,
+   given that the former is a lowpart of the latter.  It may be a
+   paradoxical lowpart, in which case the offset will be negative
+   on big-endian targets.  */
+
+int
+byte_lowpart_offset (enum machine_mode outer_mode,
+                    enum machine_mode inner_mode)
+{
+  if (GET_MODE_SIZE (outer_mode) < GET_MODE_SIZE (inner_mode))
+    return subreg_lowpart_offset (outer_mode, inner_mode);
+  else
+    return -subreg_lowpart_offset (inner_mode, outer_mode);
+}
+\f
 /* Generate a REG rtx for a new pseudo register of mode MODE.
    This pseudo is assigned the next sequential register number.  */
 
 rtx
 gen_reg_rtx (enum machine_mode mode)
 {
-  struct function *f = cfun;
   rtx val;
+  unsigned int align = GET_MODE_ALIGNMENT (mode);
 
-  /* Don't let anything called after initial flow analysis create new
-     registers.  */
-  if (no_new_pseudos)
-    abort ();
+  gcc_assert (can_create_pseudo_p ());
+
+  /* If a virtual register with bigger mode alignment is generated,
+     increase stack alignment estimation because it might be spilled
+     to stack later.  */
+  if (SUPPORTS_STACK_ALIGNMENT 
+      && crtl->stack_alignment_estimated < align
+      && !crtl->stack_realign_processed)
+    crtl->stack_alignment_estimated = align;
 
   if (generating_concat_p
       && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
@@ -838,22 +891,21 @@ gen_reg_rtx (enum machine_mode mode)
   /* Make sure regno_pointer_align, and regno_reg_rtx are large
      enough to have an element for this pseudo reg number.  */
 
-  if (reg_rtx_no == f->emit->regno_pointer_align_length)
+  if (reg_rtx_no == crtl->emit.regno_pointer_align_length)
     {
-      int old_size = f->emit->regno_pointer_align_length;
-      char *new;
+      int old_size = crtl->emit.regno_pointer_align_length;
+      char *tmp;
       rtx *new1;
 
-      new = ggc_realloc (f->emit->regno_pointer_align, old_size * 2);
-      memset (new + old_size, 0, old_size);
-      f->emit->regno_pointer_align = (unsigned char *) new;
+      tmp = XRESIZEVEC (char, crtl->emit.regno_pointer_align, old_size * 2);
+      memset (tmp + old_size, 0, old_size);
+      crtl->emit.regno_pointer_align = (unsigned char *) tmp;
 
-      new1 = ggc_realloc (f->emit->x_regno_reg_rtx,
-                         old_size * 2 * sizeof (rtx));
+      new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, old_size * 2);
       memset (new1 + old_size, 0, old_size * sizeof (rtx));
       regno_reg_rtx = new1;
 
-      f->emit->regno_pointer_align_length = old_size * 2;
+      crtl->emit.regno_pointer_align_length = old_size * 2;
     }
 
   val = gen_raw_REG (mode, reg_rtx_no);
@@ -861,26 +913,92 @@ gen_reg_rtx (enum machine_mode mode)
   return val;
 }
 
-/* Generate a register with same attributes as REG,
-   but offsetted by OFFSET.  */
+/* Update NEW with the same attributes as REG, but with OFFSET added
+   to the REG_OFFSET.  */
 
-rtx
-gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, int offset)
+static void
+update_reg_offset (rtx new_rtx, rtx reg, int offset)
 {
-  rtx new = gen_rtx_REG (mode, regno);
-  REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg),
+  REG_ATTRS (new_rtx) = get_reg_attrs (REG_EXPR (reg),
                                   REG_OFFSET (reg) + offset);
-  return new;
 }
 
-/* Set the decl for MEM to DECL.  */
+/* Generate a register with same attributes as REG, but with OFFSET
+   added to the REG_OFFSET.  */
+
+rtx
+gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno,
+                   int offset)
+{
+  rtx new_rtx = gen_rtx_REG (mode, regno);
+
+  update_reg_offset (new_rtx, reg, offset);
+  return new_rtx;
+}
+
+/* Generate a new pseudo-register with the same attributes as REG, but
+   with OFFSET added to the REG_OFFSET.  */
+
+rtx
+gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset)
+{
+  rtx new_rtx = gen_reg_rtx (mode);
+
+  update_reg_offset (new_rtx, reg, offset);
+  return new_rtx;
+}
+
+/* Adjust REG in-place so that it has mode MODE.  It is assumed that the
+   new register is a (possibly paradoxical) lowpart of the old one.  */
+
+void
+adjust_reg_mode (rtx reg, enum machine_mode mode)
+{
+  update_reg_offset (reg, reg, byte_lowpart_offset (mode, GET_MODE (reg)));
+  PUT_MODE (reg, mode);
+}
+
+/* Copy REG's attributes from X, if X has any attributes.  If REG and X
+   have different modes, REG is a (possibly paradoxical) lowpart of X.  */
 
 void
-set_reg_attrs_from_mem (rtx reg, rtx mem)
+set_reg_attrs_from_value (rtx reg, rtx x)
+{
+  int offset;
+
+  /* Hard registers can be reused for multiple purposes within the same
+     function, so setting REG_ATTRS, REG_POINTER and REG_POINTER_ALIGN
+     on them is wrong.  */
+  if (HARD_REGISTER_P (reg))
+    return;
+
+  offset = byte_lowpart_offset (GET_MODE (reg), GET_MODE (x));
+  if (MEM_P (x))
+    {
+      if (MEM_OFFSET (x) && GET_CODE (MEM_OFFSET (x)) == CONST_INT)
+       REG_ATTRS (reg)
+         = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset);
+      if (MEM_POINTER (x))
+       mark_reg_pointer (reg, 0);
+    }
+  else if (REG_P (x))
+    {
+      if (REG_ATTRS (x))
+       update_reg_offset (reg, x, offset);
+      if (REG_POINTER (x))
+       mark_reg_pointer (reg, REGNO_POINTER_ALIGN (REGNO (x)));
+    }
+}
+
+/* Generate a REG rtx for a new pseudo register, copying the mode
+   and attributes from X.  */
+
+rtx
+gen_reg_rtx_and_attrs (rtx x)
 {
-  if (MEM_OFFSET (mem) && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
-    REG_ATTRS (reg)
-      = get_reg_attrs (MEM_EXPR (mem), INTVAL (MEM_OFFSET (mem)));
+  rtx reg = gen_reg_rtx (GET_MODE (x));
+  set_reg_attrs_from_value (reg, x);
+  return reg;
 }
 
 /* Set the register attributes for registers contained in PARM_RTX.
@@ -889,8 +1007,8 @@ set_reg_attrs_from_mem (rtx reg, rtx mem)
 void
 set_reg_attrs_for_parm (rtx parm_rtx, rtx mem)
 {
-  if (GET_CODE (parm_rtx) == REG)
-    set_reg_attrs_from_mem (parm_rtx, mem);
+  if (REG_P (parm_rtx))
+    set_reg_attrs_from_value (parm_rtx, mem);
   else if (GET_CODE (parm_rtx) == PARALLEL)
     {
       /* Check for a NULL entry in the first slot, used to indicate that the
@@ -899,7 +1017,7 @@ set_reg_attrs_for_parm (rtx parm_rtx, rtx mem)
       for (; i < XVECLEN (parm_rtx, 0); i++)
        {
          rtx x = XVECEXP (parm_rtx, 0, i);
-         if (GET_CODE (XEXP (x, 0)) == REG)
+         if (REG_P (XEXP (x, 0)))
            REG_ATTRS (XEXP (x, 0))
              = get_reg_attrs (MEM_EXPR (mem),
                               INTVAL (XEXP (x, 1)));
@@ -907,20 +1025,21 @@ set_reg_attrs_for_parm (rtx parm_rtx, rtx mem)
     }
 }
 
-/* Assign the RTX X to declaration T.  */
-void
-set_decl_rtl (tree t, rtx x)
-{
-  DECL_CHECK (t)->decl.rtl = x;
+/* Set the REG_ATTRS for registers in value X, given that X represents
+   decl T.  */
 
-  if (!x)
-    return;
-  /* For register, we maintain the reverse information too.  */
-  if (GET_CODE (x) == REG)
-    REG_ATTRS (x) = get_reg_attrs (t, 0);
-  else if (GET_CODE (x) == SUBREG)
-    REG_ATTRS (SUBREG_REG (x))
-      = get_reg_attrs (t, -SUBREG_BYTE (x));
+static void
+set_reg_attrs_for_decl_rtl (tree t, rtx x)
+{
+  if (GET_CODE (x) == SUBREG)
+    {
+      gcc_assert (subreg_lowpart_p (x));
+      x = SUBREG_REG (x);
+    }
+  if (REG_P (x))
+    REG_ATTRS (x)
+      = get_reg_attrs (t, byte_lowpart_offset (GET_MODE (x),
+                                              DECL_MODE (t)));
   if (GET_CODE (x) == CONCAT)
     {
       if (REG_P (XEXP (x, 0)))
@@ -931,8 +1050,16 @@ set_decl_rtl (tree t, rtx x)
     }
   if (GET_CODE (x) == PARALLEL)
     {
-      int i;
-      for (i = 0; i < XVECLEN (x, 0); i++)
+      int i, start;
+
+      /* Check for a NULL entry, used to indicate that the parameter goes
+        both on the stack and in registers.  */
+      if (XEXP (XVECEXP (x, 0, 0), 0))
+       start = 0;
+      else
+       start = 1;
+
+      for (i = start; i < XVECLEN (x, 0); i++)
        {
          rtx y = XVECEXP (x, 0, i);
          if (REG_P (XEXP (y, 0)))
@@ -941,6 +1068,27 @@ set_decl_rtl (tree t, rtx x)
     }
 }
 
+/* Assign the RTX X to declaration T.  */
+
+void
+set_decl_rtl (tree t, rtx x)
+{
+  DECL_WRTL_CHECK (t)->decl_with_rtl.rtl = x;
+  if (x)
+    set_reg_attrs_for_decl_rtl (t, x);
+}
+
+/* Assign the RTX X to parameter declaration T.  BY_REFERENCE_P is true
+   if the ABI requires the parameter to be passed by reference.  */
+
+void
+set_decl_incoming_rtl (tree t, rtx x, bool by_reference_p)
+{
+  DECL_INCOMING_RTL (t) = x;
+  if (x && !by_reference_p)
+    set_reg_attrs_for_decl_rtl (t, x);
+}
+
 /* Identify REG (which may be a CONCAT) as a user register.  */
 
 void
@@ -951,10 +1099,11 @@ mark_user_reg (rtx reg)
       REG_USERVAR_P (XEXP (reg, 0)) = 1;
       REG_USERVAR_P (XEXP (reg, 1)) = 1;
     }
-  else if (GET_CODE (reg) == REG)
-    REG_USERVAR_P (reg) = 1;
   else
-    abort ();
+    {
+      gcc_assert (REG_P (reg));
+      REG_USERVAR_P (reg) = 1;
+    }
 }
 
 /* Identify REG as a probable pointer register and show its alignment
@@ -971,7 +1120,7 @@ mark_reg_pointer (rtx reg, int 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 */
+    /* We can no-longer be sure just how aligned this pointer is */
     REGNO_POINTER_ALIGN (REGNO (reg)) = align;
 }
 
@@ -988,8 +1137,6 @@ max_reg_num (void)
 int
 max_label_num (void)
 {
-  if (last_label_num && label_num == base_label_num)
-    return last_label_num;
   return label_num;
 }
 
@@ -1000,41 +1147,18 @@ get_first_label_num (void)
 {
   return first_label_num;
 }
-\f
-/* Return the final regno of X, which is a SUBREG of a hard
-   register.  */
-int
-subreg_hard_regno (rtx x, int check_mode)
-{
-  enum machine_mode mode = GET_MODE (x);
-  unsigned int byte_offset, base_regno, final_regno;
-  rtx reg = SUBREG_REG (x);
-
-  /* This is where we attempt to catch illegal subregs
-     created by the compiler.  */
-  if (GET_CODE (x) != SUBREG
-      || GET_CODE (reg) != REG)
-    abort ();
-  base_regno = REGNO (reg);
-  if (base_regno >= FIRST_PSEUDO_REGISTER)
-    abort ();
-  if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
-    abort ();
-#ifdef ENABLE_CHECKING
-  if (!subreg_offset_representable_p (REGNO (reg), GET_MODE (reg),
-                                     SUBREG_BYTE (x), mode))
-    abort ();
-#endif
-  /* Catch non-congruent offsets too.  */
-  byte_offset = SUBREG_BYTE (x);
-  if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
-    abort ();
 
-  final_regno = subreg_regno (x);
+/* If the rtx for label was created during the expansion of a nested
+   function, then first_label_num won't include this label number.
+   Fix this now so that array indices work later.  */
 
-  return final_regno;
+void
+maybe_set_first_label_num (rtx x)
+{
+  if (CODE_LABEL_NUMBER (x) < first_label_num)
+    first_label_num = CODE_LABEL_NUMBER (x);
 }
-
+\f
 /* Return a value representing some low-order bits of X, where the number
    of low-order bits is given by MODE.  Note that no conversion is done
    between floating-point and fixed-point values, rather, the bit
@@ -1050,24 +1174,36 @@ rtx
 gen_lowpart_common (enum machine_mode mode, rtx x)
 {
   int msize = GET_MODE_SIZE (mode);
-  int xsize = GET_MODE_SIZE (GET_MODE (x));
+  int xsize;
   int offset = 0;
+  enum machine_mode innermode;
+
+  /* Unfortunately, this routine doesn't take a parameter for the mode of X,
+     so we have to make one up.  Yuk.  */
+  innermode = GET_MODE (x);
+  if (GET_CODE (x) == CONST_INT
+      && msize * BITS_PER_UNIT <= HOST_BITS_PER_WIDE_INT)
+    innermode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
+  else if (innermode == VOIDmode)
+    innermode = mode_for_size (HOST_BITS_PER_WIDE_INT * 2, MODE_INT, 0);
+  
+  xsize = GET_MODE_SIZE (innermode);
+
+  gcc_assert (innermode != VOIDmode && innermode != BLKmode);
 
-  if (GET_MODE (x) == mode)
+  if (innermode == mode)
     return x;
 
   /* MODE must occupy no more words than the mode of X.  */
-  if (GET_MODE (x) != VOIDmode
-      && ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD
-         > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
+  if ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD
+      > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
     return 0;
 
   /* Don't allow generating paradoxical FLOAT_MODE subregs.  */
-  if (GET_MODE_CLASS (mode) == MODE_FLOAT
-      && GET_MODE (x) != VOIDmode && msize > xsize)
+  if (SCALAR_FLOAT_MODE_P (mode) && msize > xsize)
     return 0;
 
-  offset = subreg_lowpart_offset (mode, GET_MODE (x));
+  offset = subreg_lowpart_offset (mode, innermode);
 
   if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
       && (GET_MODE_CLASS (mode) == MODE_INT
@@ -1083,348 +1219,62 @@ gen_lowpart_common (enum machine_mode mode, rtx x)
 
       if (GET_MODE (XEXP (x, 0)) == mode)
        return XEXP (x, 0);
-      else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (XEXP (x, 0))))
+      else if (msize < GET_MODE_SIZE (GET_MODE (XEXP (x, 0))))
        return gen_lowpart_common (mode, XEXP (x, 0));
-      else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x)))
+      else if (msize < xsize)
        return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0));
     }
-  else if (GET_CODE (x) == SUBREG || GET_CODE (x) == REG
-          || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR)
-    return simplify_gen_subreg (mode, x, GET_MODE (x), offset);
-  else if (VECTOR_MODE_P (mode) && GET_MODE (x) == VOIDmode)
-    return simplify_gen_subreg (mode, x, int_mode_for_mode (mode), offset);
-  /* If X is a CONST_INT or a CONST_DOUBLE, extract the appropriate bits
-     from the low-order part of the constant.  */
-  else if ((GET_MODE_CLASS (mode) == MODE_INT
-           || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
-          && GET_MODE (x) == VOIDmode
-          && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
-    {
-      /* If MODE is twice the host word size, X is already the desired
-        representation.  Otherwise, if MODE is wider than a word, we can't
-        do this.  If MODE is exactly a word, return just one CONST_INT.  */
-
-      if (GET_MODE_BITSIZE (mode) >= 2 * HOST_BITS_PER_WIDE_INT)
-       return x;
-      else if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
-       return 0;
-      else if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT)
-       return (GET_CODE (x) == CONST_INT ? x
-               : GEN_INT (CONST_DOUBLE_LOW (x)));
-      else
-       {
-         /* MODE must be narrower than HOST_BITS_PER_WIDE_INT.  */
-         HOST_WIDE_INT val = (GET_CODE (x) == CONST_INT ? INTVAL (x)
-                              : CONST_DOUBLE_LOW (x));
+  else if (GET_CODE (x) == SUBREG || REG_P (x)
+          || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR
+          || GET_CODE (x) == CONST_DOUBLE || GET_CODE (x) == CONST_INT)
+    return simplify_gen_subreg (mode, x, innermode, offset);
 
-         /* Sign extend to HOST_WIDE_INT.  */
-         val = trunc_int_for_mode (val, mode);
-
-         return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x
-                 : GEN_INT (val));
-       }
-    }
+  /* Otherwise, we can't do this.  */
+  return 0;
+}
+\f
+rtx
+gen_highpart (enum machine_mode mode, rtx x)
+{
+  unsigned int msize = GET_MODE_SIZE (mode);
+  rtx result;
 
-  /* The floating-point emulator can handle all conversions between
-     FP and integer operands.  This simplifies reload because it
-     doesn't have to deal with constructs like (subreg:DI
-     (const_double:SF ...)) or (subreg:DF (const_int ...)).  */
-  /* Single-precision floats are always 32-bits and double-precision
-     floats are always 64-bits.  */
+  /* This case loses if X is a subreg.  To catch bugs early,
+     complain if an invalid MODE is used even in other cases.  */
+  gcc_assert (msize <= UNITS_PER_WORD
+             || msize == (unsigned int) GET_MODE_UNIT_SIZE (GET_MODE (x)));
 
-  else if (GET_MODE_CLASS (mode) == MODE_FLOAT
-          && GET_MODE_BITSIZE (mode) == 32
-          && GET_CODE (x) == CONST_INT)
+  result = simplify_gen_subreg (mode, x, GET_MODE (x),
+                               subreg_highpart_offset (mode, GET_MODE (x)));
+  gcc_assert (result);
+  
+  /* simplify_gen_subreg is not guaranteed to return a valid operand for
+     the target if we have a MEM.  gen_highpart must return a valid operand,
+     emitting code if necessary to do so.  */
+  if (MEM_P (result))
     {
-      REAL_VALUE_TYPE r;
-      long i = INTVAL (x);
-
-      real_from_target (&r, &i, mode);
-      return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
+      result = validize_mem (result);
+      gcc_assert (result);
     }
-  else if (GET_MODE_CLASS (mode) == MODE_FLOAT
-          && GET_MODE_BITSIZE (mode) == 64
-          && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
-          && GET_MODE (x) == VOIDmode)
+  
+  return result;
+}
+
+/* Like gen_highpart, but accept mode of EXP operand in case EXP can
+   be VOIDmode constant.  */
+rtx
+gen_highpart_mode (enum machine_mode outermode, enum machine_mode innermode, rtx exp)
+{
+  if (GET_MODE (exp) != VOIDmode)
     {
-      REAL_VALUE_TYPE r;
-      HOST_WIDE_INT low, high;
-      long i[2];
+      gcc_assert (GET_MODE (exp) == innermode);
+      return gen_highpart (outermode, exp);
+    }
+  return simplify_gen_subreg (outermode, exp, innermode,
+                             subreg_highpart_offset (outermode, innermode));
+}
 
-      if (GET_CODE (x) == CONST_INT)
-       {
-         low = INTVAL (x);
-         high = low >> (HOST_BITS_PER_WIDE_INT - 1);
-       }
-      else
-       {
-         low = CONST_DOUBLE_LOW (x);
-         high = CONST_DOUBLE_HIGH (x);
-       }
-
-      if (HOST_BITS_PER_WIDE_INT > 32)
-       high = low >> 31 >> 1;
-
-      /* REAL_VALUE_TARGET_DOUBLE takes the addressing order of the
-        target machine.  */
-      if (WORDS_BIG_ENDIAN)
-       i[0] = high, i[1] = low;
-      else
-       i[0] = low, i[1] = high;
-
-      real_from_target (&r, i, mode);
-      return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
-    }
-  else if ((GET_MODE_CLASS (mode) == MODE_INT
-           || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
-          && GET_CODE (x) == CONST_DOUBLE
-          && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
-    {
-      REAL_VALUE_TYPE r;
-      long i[4];  /* Only the low 32 bits of each 'long' are used.  */
-      int endian = WORDS_BIG_ENDIAN ? 1 : 0;
-
-      /* Convert 'r' into an array of four 32-bit words in target word
-         order.  */
-      REAL_VALUE_FROM_CONST_DOUBLE (r, x);
-      switch (GET_MODE_BITSIZE (GET_MODE (x)))
-       {
-       case 32:
-         REAL_VALUE_TO_TARGET_SINGLE (r, i[3 * endian]);
-         i[1] = 0;
-         i[2] = 0;
-         i[3 - 3 * endian] = 0;
-         break;
-       case 64:
-         REAL_VALUE_TO_TARGET_DOUBLE (r, i + 2 * endian);
-         i[2 - 2 * endian] = 0;
-         i[3 - 2 * endian] = 0;
-         break;
-       case 96:
-         REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i + endian);
-         i[3 - 3 * endian] = 0;
-         break;
-       case 128:
-         REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i);
-         break;
-       default:
-         abort ();
-       }
-      /* Now, pack the 32-bit elements of the array into a CONST_DOUBLE
-        and return it.  */
-#if HOST_BITS_PER_WIDE_INT == 32
-      return immed_double_const (i[3 * endian], i[1 + endian], mode);
-#else
-      if (HOST_BITS_PER_WIDE_INT != 64)
-       abort ();
-
-      return immed_double_const ((((unsigned long) i[3 * endian])
-                                 | ((HOST_WIDE_INT) i[1 + endian] << 32)),
-                                (((unsigned long) i[2 - endian])
-                                 | ((HOST_WIDE_INT) i[3 - 3 * endian] << 32)),
-                                mode);
-#endif
-    }
-  /* If MODE is a condition code and X is a CONST_INT, the value of X
-     must already have been "recognized" by the back-end, and we can
-     assume that it is valid for this mode.  */
-  else if (GET_MODE_CLASS (mode) == MODE_CC
-          && GET_CODE (x) == CONST_INT)
-    return x;
-
-  /* Otherwise, we can't do this.  */
-  return 0;
-}
-\f
-/* Return the constant real or imaginary part (which has mode MODE)
-   of a complex value X.  The IMAGPART_P argument determines whether
-   the real or complex component should be returned.  This function
-   returns NULL_RTX if the component isn't a constant.  */
-
-static rtx
-gen_complex_constant_part (enum machine_mode mode, rtx x, int imagpart_p)
-{
-  tree decl, part;
-
-  if (GET_CODE (x) == MEM
-      && GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
-    {
-      decl = SYMBOL_REF_DECL (XEXP (x, 0));
-      if (decl != NULL_TREE && TREE_CODE (decl) == COMPLEX_CST)
-       {
-         part = imagpart_p ? TREE_IMAGPART (decl) : TREE_REALPART (decl);
-         if (TREE_CODE (part) == REAL_CST
-             || TREE_CODE (part) == INTEGER_CST)
-           return expand_expr (part, NULL_RTX, mode, 0);
-       }
-    }
-  return NULL_RTX;
-}
-
-/* Return the real part (which has mode MODE) of a complex value X.
-   This always comes at the low address in memory.  */
-
-rtx
-gen_realpart (enum machine_mode mode, rtx x)
-{
-  rtx part;
-
-  /* Handle complex constants.  */
-  part = gen_complex_constant_part (mode, x, 0);
-  if (part != NULL_RTX)
-    return part;
-
-  if (WORDS_BIG_ENDIAN
-      && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
-      && REG_P (x)
-      && REGNO (x) < FIRST_PSEUDO_REGISTER)
-    internal_error
-      ("can't access real part of complex value in hard register");
-  else if (WORDS_BIG_ENDIAN)
-    return gen_highpart (mode, x);
-  else
-    return gen_lowpart (mode, x);
-}
-
-/* Return the imaginary part (which has mode MODE) of a complex value X.
-   This always comes at the high address in memory.  */
-
-rtx
-gen_imagpart (enum machine_mode mode, rtx x)
-{
-  rtx part;
-
-  /* Handle complex constants.  */
-  part = gen_complex_constant_part (mode, x, 1);
-  if (part != NULL_RTX)
-    return part;
-
-  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)
-    internal_error
-      ("can't access imaginary part of complex value in hard register");
-  else
-    return gen_highpart (mode, x);
-}
-
-/* Return 1 iff X, assumed to be a SUBREG,
-   refers to the real part of the complex value in its containing reg.
-   Complex values are always stored with the real part in the first word,
-   regardless of WORDS_BIG_ENDIAN.  */
-
-int
-subreg_realpart_p (rtx x)
-{
-  if (GET_CODE (x) != SUBREG)
-    abort ();
-
-  return ((unsigned int) SUBREG_BYTE (x)
-         < 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,
-   return an rtx (MEM, SUBREG, or CONST_INT) that refers to the
-   least-significant part of X.
-   MODE specifies how big a part of X to return;
-   it usually should not be larger than a word.
-   If X is a MEM whose address is a QUEUED, the value may be so also.  */
-
-rtx
-gen_lowpart (enum machine_mode mode, rtx x)
-{
-  rtx result = gen_lowpart_common (mode, x);
-
-  if (result)
-    return result;
-  else if (GET_CODE (x) == REG)
-    {
-      /* Must be a hard reg that's not valid in MODE.  */
-      result = gen_lowpart_common (mode, copy_to_reg (x));
-      if (result == 0)
-       abort ();
-      return result;
-    }
-  else if (GET_CODE (x) == MEM)
-    {
-      /* The only additional case we can do is MEM.  */
-      int offset = 0;
-
-      /* The following exposes the use of "x" to CSE.  */
-      if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
-         && SCALAR_INT_MODE_P (GET_MODE (x))
-         && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
-                                   GET_MODE_BITSIZE (GET_MODE (x)))
-         && ! no_new_pseudos)
-       return gen_lowpart (mode, force_reg (GET_MODE (x), x));
-
-      if (WORDS_BIG_ENDIAN)
-       offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
-                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
-
-      if (BYTES_BIG_ENDIAN)
-       /* Adjust the address so that the address-after-the-data
-          is unchanged.  */
-       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
-                  - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
-
-      return adjust_address (x, mode, offset);
-    }
-  else if (GET_CODE (x) == ADDRESSOF)
-    return gen_lowpart (mode, force_reg (GET_MODE (x), x));
-  else
-    abort ();
-}
-
-/* Like `gen_lowpart', but refer to the most significant part.
-   This is used to access the imaginary part of a complex number.  */
-
-rtx
-gen_highpart (enum machine_mode mode, rtx x)
-{
-  unsigned int msize = GET_MODE_SIZE (mode);
-  rtx result;
-
-  /* This case loses if X is a subreg.  To catch bugs early,
-     complain if an invalid MODE is used even in other cases.  */
-  if (msize > UNITS_PER_WORD
-      && msize != GET_MODE_UNIT_SIZE (GET_MODE (x)))
-    abort ();
-
-  result = simplify_gen_subreg (mode, x, GET_MODE (x),
-                               subreg_highpart_offset (mode, GET_MODE (x)));
-
-  /* simplify_gen_subreg is not guaranteed to return a valid operand for
-     the target if we have a MEM.  gen_highpart must return a valid operand,
-     emitting code if necessary to do so.  */
-  if (result != NULL_RTX && GET_CODE (result) == MEM)
-    result = validize_mem (result);
-
-  if (!result)
-    abort ();
-  return result;
-}
-
-/* Like gen_highpart, but accept mode of EXP operand in case EXP can
-   be VOIDmode constant.  */
-rtx
-gen_highpart_mode (enum machine_mode outermode, enum machine_mode innermode, rtx exp)
-{
-  if (GET_MODE (exp) != VOIDmode)
-    {
-      if (GET_MODE (exp) != innermode)
-       abort ();
-      return gen_highpart (outermode, exp);
-    }
-  return simplify_gen_subreg (outermode, exp, innermode,
-                             subreg_highpart_offset (outermode, innermode));
-}
-
-/* Return offset in bytes to get OUTERMODE low part
-   of the value in mode INNERMODE stored in memory in target format.  */
+/* Return the SUBREG_BYTE for an OUTERMODE lowpart of an INNERMODE value.  */
 
 unsigned int
 subreg_lowpart_offset (enum machine_mode outermode, enum machine_mode innermode)
@@ -1451,8 +1301,7 @@ subreg_highpart_offset (enum machine_mode outermode, enum machine_mode innermode
   unsigned int offset = 0;
   int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
 
-  if (GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
-    abort ();
+  gcc_assert (GET_MODE_SIZE (innermode) >= GET_MODE_SIZE (outermode));
 
   if (difference > 0)
     {
@@ -1470,7 +1319,7 @@ subreg_highpart_offset (enum machine_mode outermode, enum machine_mode innermode
    If X is not a SUBREG, always return 1 (it is its own low part!).  */
 
 int
-subreg_lowpart_p (rtx x)
+subreg_lowpart_p (const_rtx x)
 {
   if (GET_CODE (x) != SUBREG)
     return 1;
@@ -1481,162 +1330,6 @@ subreg_lowpart_p (rtx x)
          == SUBREG_BYTE (x));
 }
 \f
-
-/* Helper routine for all the constant cases of operand_subword.
-   Some places invoke this directly.  */
-
-rtx
-constant_subword (rtx op, int offset, enum machine_mode mode)
-{
-  int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD;
-  HOST_WIDE_INT val;
-
-  /* If OP is already an integer word, return it.  */
-  if (GET_MODE_CLASS (mode) == MODE_INT
-      && GET_MODE_SIZE (mode) == UNITS_PER_WORD)
-    return op;
-
-  /* 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
-      && GET_CODE (op) == CONST_DOUBLE)
-    {
-      long k[2];
-      REAL_VALUE_TYPE rv;
-
-      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
-
-      /* 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.
-
-        We must exercise 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)
-       {
-         val = k[offset];
-         val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
-         return GEN_INT (val);
-       }
-#if HOST_BITS_PER_WIDE_INT >= 64
-      else if (BITS_PER_WORD >= 64 && offset == 0)
-       {
-         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)
-       {
-         val = k[offset >> 1];
-         if ((offset & 1) == ! WORDS_BIG_ENDIAN)
-           val >>= 16;
-         val = ((val & 0xffff) ^ 0x8000) - 0x8000;
-         return GEN_INT (val);
-       }
-      else
-       abort ();
-    }
-  else if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
-          && GET_MODE_CLASS (mode) == MODE_FLOAT
-          && GET_MODE_BITSIZE (mode) > 64
-          && GET_CODE (op) == CONST_DOUBLE)
-    {
-      long k[4];
-      REAL_VALUE_TYPE rv;
-
-      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
-
-      if (BITS_PER_WORD == 32)
-       {
-         val = k[offset];
-         val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
-         return GEN_INT (val);
-       }
-#if HOST_BITS_PER_WIDE_INT >= 64
-      else if (BITS_PER_WORD >= 64 && offset <= 1)
-       {
-         val = k[offset * 2 + ! WORDS_BIG_ENDIAN];
-         val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
-         val |= (HOST_WIDE_INT) k[offset * 2 + WORDS_BIG_ENDIAN] & 0xffffffff;
-         return GEN_INT (val);
-       }
-#endif
-      else
-       abort ();
-    }
-
-  /* Single word float is a little harder, since single- and double-word
-     values often do not have the same high-order bits.  We have already
-     verified that we want the only defined word of the single-word value.  */
-  if (GET_MODE_CLASS (mode) == MODE_FLOAT
-      && GET_MODE_BITSIZE (mode) == 32
-      && GET_CODE (op) == CONST_DOUBLE)
-    {
-      long l;
-      REAL_VALUE_TYPE rv;
-
-      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 ((offset & 1) == ! WORDS_BIG_ENDIAN)
-           val >>= 16;
-         val = ((val & 0xffff) ^ 0x8000) - 0x8000;
-       }
-
-      return GEN_INT (val);
-    }
-
-  /* The only remaining cases that we can handle are integers.
-     Convert to proper endianness now since these cases need it.
-     At this point, offset == 0 means the low-order word.
-
-     We do not want to handle the case when BITS_PER_WORD <= HOST_BITS_PER_INT
-     in general.  However, if OP is (const_int 0), we can just return
-     it for any word.  */
-
-  if (op == const0_rtx)
-    return op;
-
-  if (GET_MODE_CLASS (mode) != MODE_INT
-      || (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE)
-      || BITS_PER_WORD > HOST_BITS_PER_WIDE_INT)
-    return 0;
-
-  if (WORDS_BIG_ENDIAN)
-    offset = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - offset;
-
-  /* Find out which word on the host machine this value is in and get
-     it from the constant.  */
-  val = (offset / size_ratio == 0
-        ? (GET_CODE (op) == CONST_INT ? INTVAL (op) : CONST_DOUBLE_LOW (op))
-        : (GET_CODE (op) == CONST_INT
-           ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op)));
-
-  /* Get the value we want into the low bits of val.  */
-  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT)
-    val = ((val >> ((offset % size_ratio) * BITS_PER_WORD)));
-
-  val = trunc_int_for_mode (val, word_mode);
-
-  return GEN_INT (val);
-}
-
 /* Return subword OFFSET of operand OP.
    The word number, OFFSET, is interpreted as the word number starting
    at the low-order address.  OFFSET 0 is the low-order word if not
@@ -1668,8 +1361,7 @@ operand_subword (rtx op, unsigned int offset, int validate_address, enum machine
   if (mode == VOIDmode)
     mode = GET_MODE (op);
 
-  if (mode == VOIDmode)
-    abort ();
+  gcc_assert (mode != VOIDmode);
 
   /* If OP is narrower than a word, fail.  */
   if (mode != BLKmode
@@ -1682,29 +1374,30 @@ operand_subword (rtx op, unsigned int offset, int validate_address, enum machine
     return const0_rtx;
 
   /* Form a new MEM at the requested address.  */
-  if (GET_CODE (op) == MEM)
+  if (MEM_P (op))
     {
-      rtx new = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD);
+      rtx new_rtx = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD);
 
       if (! validate_address)
-       return new;
+       return new_rtx;
 
       else if (reload_completed)
        {
-         if (! strict_memory_address_p (word_mode, XEXP (new, 0)))
+         if (! strict_memory_address_p (word_mode, XEXP (new_rtx, 0)))
            return 0;
        }
       else
-       return replace_equiv_address (new, XEXP (new, 0));
+       return replace_equiv_address (new_rtx, XEXP (new_rtx, 0));
     }
 
   /* Rest can be handled by simplify_subreg.  */
   return simplify_gen_subreg (word_mode, op, mode, (offset * UNITS_PER_WORD));
 }
 
-/* Similar to `operand_subword', but never return 0.  If we can't extract
-   the required subword, put OP into a register and try again.  If that fails,
-   abort.  We always validate the address in this case.
+/* Similar to `operand_subword', but never return 0.  If we can't
+   extract the required subword, put OP into a register and try again.
+   The second attempt must succeed.  We always validate the address in
+   this case.
 
    MODE is the mode of OP, in case it is CONST_INT.  */
 
@@ -1720,51 +1413,18 @@ operand_subword_force (rtx op, unsigned int offset, enum machine_mode mode)
     {
       /* If this is a register which can not be accessed by words, copy it
         to a pseudo register.  */
-      if (GET_CODE (op) == REG)
+      if (REG_P (op))
        op = copy_to_reg (op);
       else
        op = force_reg (mode, op);
     }
 
   result = operand_subword (op, offset, 1, mode);
-  if (result == 0)
-    abort ();
+  gcc_assert (result);
 
   return result;
 }
 \f
-/* Given a compare instruction, swap the operands.
-   A test instruction is changed into a compare of 0 against the operand.  */
-
-void
-reverse_comparison (rtx insn)
-{
-  rtx body = PATTERN (insn);
-  rtx comp;
-
-  if (GET_CODE (body) == SET)
-    comp = SET_SRC (body);
-  else
-    comp = SET_SRC (XVECEXP (body, 0, 0));
-
-  if (GET_CODE (comp) == COMPARE)
-    {
-      rtx op0 = XEXP (comp, 0);
-      rtx op1 = XEXP (comp, 1);
-      XEXP (comp, 0) = op1;
-      XEXP (comp, 1) = op0;
-    }
-  else
-    {
-      rtx new = gen_rtx_COMPARE (VOIDmode,
-                                CONST0_RTX (GET_MODE (comp)), comp);
-      if (GET_CODE (body) == SET)
-       SET_SRC (body) = new;
-      else
-       SET_SRC (XVECEXP (body, 0, 0)) = new;
-    }
-}
-\f
 /* Within a MEM_EXPR, we care about either (1) a component ref of a decl,
    or (2) a component ref of something variable.  Represent the later with
    a NULL expression.  */
@@ -1778,19 +1438,12 @@ component_ref_for_mem_expr (tree ref)
     inner = component_ref_for_mem_expr (inner);
   else
     {
-      tree placeholder_ptr = 0;
-
       /* Now remove any conversions: they don't change what the underlying
-        object is.  Likewise for SAVE_EXPR.  Also handle PLACEHOLDER_EXPR.  */
-      while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR
-            || TREE_CODE (inner) == NON_LVALUE_EXPR
+        object is.  Likewise for SAVE_EXPR.  */
+      while (CONVERT_EXPR_P (inner)
             || TREE_CODE (inner) == VIEW_CONVERT_EXPR
-            || TREE_CODE (inner) == SAVE_EXPR
-            || TREE_CODE (inner) == PLACEHOLDER_EXPR)
-       if (TREE_CODE (inner) == PLACEHOLDER_EXPR)
-         inner = find_placeholder (inner, &placeholder_ptr);
-       else
-         inner = TREE_OPERAND (inner, 0);
+            || TREE_CODE (inner) == SAVE_EXPR)
+       inner = TREE_OPERAND (inner, 0);
 
       if (! DECL_P (inner))
        inner = NULL_TREE;
@@ -1799,11 +1452,129 @@ component_ref_for_mem_expr (tree ref)
   if (inner == TREE_OPERAND (ref, 0))
     return ref;
   else
-    return build (COMPONENT_REF, TREE_TYPE (ref), inner,
-                 TREE_OPERAND (ref, 1));
+    return build3 (COMPONENT_REF, TREE_TYPE (ref), inner,
+                  TREE_OPERAND (ref, 1), NULL_TREE);
+}
+
+/* Returns 1 if both MEM_EXPR can be considered equal
+   and 0 otherwise.  */
+
+int
+mem_expr_equal_p (const_tree expr1, const_tree expr2)
+{
+  if (expr1 == expr2)
+    return 1;
+
+  if (! expr1 || ! expr2)
+    return 0;
+
+  if (TREE_CODE (expr1) != TREE_CODE (expr2))
+    return 0;
+
+  if (TREE_CODE (expr1) == COMPONENT_REF)
+    return 
+      mem_expr_equal_p (TREE_OPERAND (expr1, 0),
+                       TREE_OPERAND (expr2, 0))
+      && mem_expr_equal_p (TREE_OPERAND (expr1, 1), /* field decl */
+                          TREE_OPERAND (expr2, 1));
+  
+  if (INDIRECT_REF_P (expr1))
+    return mem_expr_equal_p (TREE_OPERAND (expr1, 0),
+                            TREE_OPERAND (expr2, 0));
+
+  /* ARRAY_REFs, ARRAY_RANGE_REFs and BIT_FIELD_REFs should already
+             have been resolved here.  */
+  gcc_assert (DECL_P (expr1));
+  
+  /* Decls with different pointers can't be equal.  */
+  return 0;
+}
+
+/* Return OFFSET if XEXP (MEM, 0) - OFFSET is known to be ALIGN
+   bits aligned for 0 <= OFFSET < ALIGN / BITS_PER_UNIT, or
+   -1 if not known.  */
+
+int
+get_mem_align_offset (rtx mem, unsigned int align)
+{
+  tree expr;
+  unsigned HOST_WIDE_INT offset;
+
+  /* This function can't use
+     if (!MEM_EXPR (mem) || !MEM_OFFSET (mem)
+        || !CONST_INT_P (MEM_OFFSET (mem))
+        || (get_object_alignment (MEM_EXPR (mem), MEM_ALIGN (mem), align)
+            < align))
+       return -1;
+     else
+       return (- INTVAL (MEM_OFFSET (mem))) & (align / BITS_PER_UNIT - 1);
+     for two reasons:
+     - COMPONENT_REFs in MEM_EXPR can have NULL first operand,
+       for <variable>.  get_inner_reference doesn't handle it and
+       even if it did, the alignment in that case needs to be determined
+       from DECL_FIELD_CONTEXT's TYPE_ALIGN.
+     - it would do suboptimal job for COMPONENT_REFs, even if MEM_EXPR
+       isn't sufficiently aligned, the object it is in might be.  */
+  gcc_assert (MEM_P (mem));
+  expr = MEM_EXPR (mem);
+  if (expr == NULL_TREE
+      || MEM_OFFSET (mem) == NULL_RTX
+      || !CONST_INT_P (MEM_OFFSET (mem)))
+    return -1;
+
+  offset = INTVAL (MEM_OFFSET (mem));
+  if (DECL_P (expr))
+    {
+      if (DECL_ALIGN (expr) < align)
+       return -1;
+    }
+  else if (INDIRECT_REF_P (expr))
+    {
+      if (TYPE_ALIGN (TREE_TYPE (expr)) < (unsigned int) align)
+       return -1;
+    }
+  else if (TREE_CODE (expr) == COMPONENT_REF)
+    {
+      while (1)
+       {
+         tree inner = TREE_OPERAND (expr, 0);
+         tree field = TREE_OPERAND (expr, 1);
+         tree byte_offset = component_ref_field_offset (expr);
+         tree bit_offset = DECL_FIELD_BIT_OFFSET (field);
+
+         if (!byte_offset
+             || !host_integerp (byte_offset, 1)
+             || !host_integerp (bit_offset, 1))
+           return -1;
+
+         offset += tree_low_cst (byte_offset, 1);
+         offset += tree_low_cst (bit_offset, 1) / BITS_PER_UNIT;
+
+         if (inner == NULL_TREE)
+           {
+             if (TYPE_ALIGN (DECL_FIELD_CONTEXT (field))
+                 < (unsigned int) align)
+               return -1;
+             break;
+           }
+         else if (DECL_P (inner))
+           {
+             if (DECL_ALIGN (inner) < align)
+               return -1;
+             break;
+           }
+         else if (TREE_CODE (inner) != COMPONENT_REF)
+           return -1;
+         expr = inner;
+       }
+    }
+  else
+    return -1;
+
+  return offset & ((align / BITS_PER_UNIT) - 1);
 }
 
-/* Given REF, a MEM, and T, either the type of X or the expression
+/* Given REF (a MEM) and T, either the type of X or the expression
    corresponding to REF, set the memory attributes.  OBJECTP is nonzero
    if we are making a new object of this type.  BITPOS is nonzero if
    there is an offset outstanding on T that will be applied later.  */
@@ -1812,7 +1583,7 @@ void
 set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
                                 HOST_WIDE_INT bitpos)
 {
-  HOST_WIDE_INT alias = MEM_ALIAS_SET (ref);
+  alias_set_type alias = MEM_ALIAS_SET (ref);
   tree expr = MEM_EXPR (ref);
   rtx offset = MEM_OFFSET (ref);
   rtx size = MEM_SIZE (ref);
@@ -1827,34 +1598,46 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
     return;
 
   type = TYPE_P (t) ? t : TREE_TYPE (t);
+  if (type == error_mark_node)
+    return;
 
   /* If we have already set DECL_RTL = ref, get_alias_set will get the
      wrong answer, as it assumes that DECL_RTL already has the right alias
      info.  Callers should not set DECL_RTL until after the call to
      set_mem_attributes.  */
-  if (DECL_P (t) && ref == DECL_RTL_IF_SET (t))
-    abort ();
+  gcc_assert (!DECL_P (t) || ref != DECL_RTL_IF_SET (t));
 
   /* Get the alias set from the expression or type (perhaps using a
      front-end routine) and use it.  */
   alias = get_alias_set (t);
 
-  MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type);
-  MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type);
-  RTX_UNCHANGING_P (ref)
-    |= ((lang_hooks.honor_readonly
-        && (TYPE_READONLY (type) || TREE_READONLY (t)))
-       || (! TYPE_P (t) && TREE_CONSTANT (t)));
+  MEM_VOLATILE_P (ref) |= TYPE_VOLATILE (type);
+  MEM_IN_STRUCT_P (ref)
+    = AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE;
+  MEM_POINTER (ref) = POINTER_TYPE_P (type);
 
   /* If we are making an object of this type, or if this is a DECL, we know
      that it is a scalar if the type is not an aggregate.  */
-  if ((objectp || DECL_P (t)) && ! AGGREGATE_TYPE_P (type))
+  if ((objectp || DECL_P (t))
+      && ! AGGREGATE_TYPE_P (type)
+      && TREE_CODE (type) != COMPLEX_TYPE)
     MEM_SCALAR_P (ref) = 1;
 
   /* We can set the alignment from the type if we are making an object,
      this is an INDIRECT_REF, or if TYPE_ALIGN_OK.  */
-  if (objectp || TREE_CODE (t) == INDIRECT_REF || TYPE_ALIGN_OK (type))
+  if (objectp || TREE_CODE (t) == INDIRECT_REF 
+      || TREE_CODE (t) == ALIGN_INDIRECT_REF 
+      || TYPE_ALIGN_OK (type))
     align = MAX (align, TYPE_ALIGN (type));
+  else 
+    if (TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
+      {
+       if (integer_zerop (TREE_OPERAND (t, 1)))
+         /* We don't know anything about the alignment.  */
+         align = BITS_PER_UNIT;
+       else
+         align = tree_low_cst (TREE_OPERAND (t, 1), 1);
+      }
 
   /* If the size is known, we can set that.  */
   if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))
@@ -1864,21 +1647,52 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
      the expression.  */
   if (! TYPE_P (t))
     {
-      maybe_set_unchanging (ref, t);
+      tree base;
+      bool align_computed = false;
+
       if (TREE_THIS_VOLATILE (t))
        MEM_VOLATILE_P (ref) = 1;
 
       /* Now remove any conversions: they don't change what the underlying
         object is.  Likewise for SAVE_EXPR.  */
-      while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
-            || TREE_CODE (t) == NON_LVALUE_EXPR
+      while (CONVERT_EXPR_P (t)
             || TREE_CODE (t) == VIEW_CONVERT_EXPR
             || TREE_CODE (t) == SAVE_EXPR)
        t = TREE_OPERAND (t, 0);
 
-      /* If this expression can't be addressed (e.g., it contains a reference
-        to a non-addressable field), show we don't change its alias set.  */
-      if (! can_address_p (t))
+      /* We may look through structure-like accesses for the purposes of
+        examining TREE_THIS_NOTRAP, but not array-like accesses.  */
+      base = t;
+      while (TREE_CODE (base) == COMPONENT_REF
+            || TREE_CODE (base) == REALPART_EXPR
+            || TREE_CODE (base) == IMAGPART_EXPR
+            || TREE_CODE (base) == BIT_FIELD_REF)
+       base = TREE_OPERAND (base, 0);
+
+      if (DECL_P (base))
+       {
+         if (CODE_CONTAINS_STRUCT (TREE_CODE (base), TS_DECL_WITH_VIS))
+           MEM_NOTRAP_P (ref) = !DECL_WEAK (base);
+         else
+           MEM_NOTRAP_P (ref) = 1;
+       }
+      else
+       MEM_NOTRAP_P (ref) = TREE_THIS_NOTRAP (base);
+
+      base = get_base_address (base);
+      if (base && DECL_P (base)
+         && TREE_READONLY (base)
+         && (TREE_STATIC (base) || DECL_EXTERNAL (base)))
+       {
+         tree base_type = TREE_TYPE (base);
+         gcc_assert (!(base_type && TYPE_NEEDS_CONSTRUCTING (base_type))
+                     || DECL_ARTIFICIAL (base));
+         MEM_READONLY_P (ref) = 1;
+       }
+
+      /* If this expression uses it's parent's alias set, mark it such
+        that we won't change it.  */
+      if (component_uses_parent_alias_set (t))
        MEM_KEEP_ALIAS_SET_P (ref) = 1;
 
       /* If this is a decl, set the attributes of the MEM from it.  */
@@ -1891,19 +1705,21 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
                  && host_integerp (DECL_SIZE_UNIT (t), 1)
                  ? GEN_INT (tree_low_cst (DECL_SIZE_UNIT (t), 1)) : 0);
          align = DECL_ALIGN (t);
+         align_computed = true;
        }
 
       /* If this is a constant, we know the alignment.  */
-      else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
+      else if (CONSTANT_CLASS_P (t))
        {
          align = TYPE_ALIGN (type);
 #ifdef CONSTANT_ALIGNMENT
          align = CONSTANT_ALIGNMENT (t, align);
 #endif
+         align_computed = true;
        }
 
       /* If this is a field reference and not a bit-field, record it.  */
-      /* ??? There is some information that can be gleened from bit-fields,
+      /* ??? There is some information that can be gleaned from bit-fields,
         such as the word offset in the structure that might be modified.
         But skip it for now.  */
       else if (TREE_CODE (t) == COMPONENT_REF
@@ -1927,34 +1743,23 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
          do
            {
              tree index = TREE_OPERAND (t2, 1);
-             tree array = TREE_OPERAND (t2, 0);
-             tree domain = TYPE_DOMAIN (TREE_TYPE (array));
-             tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
-             tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
+             tree low_bound = array_ref_low_bound (t2);
+             tree unit_size = array_ref_element_size (t2);
 
              /* We assume all arrays have sizes that are a multiple of a byte.
                 First subtract the lower bound, if any, in the type of the
-                index, then convert to sizetype and multiply by the size of the
-                array element.  */
-             if (low_bound != 0 && ! integer_zerop (low_bound))
-               index = fold (build (MINUS_EXPR, TREE_TYPE (index),
-                                    index, low_bound));
-
-             /* If the index has a self-referential type, pass it to a
-                WITH_RECORD_EXPR; if the component size is, pass our
-                component to one.  */
-             if (CONTAINS_PLACEHOLDER_P (index))
-               index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, t2);
-             if (CONTAINS_PLACEHOLDER_P (unit_size))
-               unit_size = build (WITH_RECORD_EXPR, sizetype,
-                                  unit_size, array);
-
-             off_tree
-               = fold (build (PLUS_EXPR, sizetype,
-                              fold (build (MULT_EXPR, sizetype,
-                                           index,
-                                           unit_size)),
-                              off_tree));
+                index, then convert to sizetype and multiply by the size of
+                the array element.  */
+             if (! integer_zerop (low_bound))
+               index = fold_build2 (MINUS_EXPR, TREE_TYPE (index),
+                                    index, low_bound);
+
+             off_tree = size_binop (PLUS_EXPR,
+                                    size_binop (MULT_EXPR,
+                                                fold_convert (sizetype,
+                                                              index),
+                                                unit_size),
+                                    off_tree);
              t2 = TREE_OPERAND (t2, 0);
            }
          while (TREE_CODE (t2) == ARRAY_REF);
@@ -1970,6 +1775,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
                  align = DECL_ALIGN (t2);
                  if (aoff && (unsigned HOST_WIDE_INT) aoff < align)
                    align = aoff;
+                 align_computed = true;
                  offset = GEN_INT (ioff);
                  apply_bitpos = bitpos;
                }
@@ -1986,7 +1792,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
                 the size we got from the type?  */
            }
          else if (flag_argument_noalias > 1
-                  && TREE_CODE (t2) == INDIRECT_REF
+                  && (INDIRECT_REF_P (t2))
                   && TREE_CODE (TREE_OPERAND (t2, 0)) == PARM_DECL)
            {
              expr = t2;
@@ -1997,12 +1803,19 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
       /* If this is a Fortran indirect argument reference, record the
         parameter decl.  */
       else if (flag_argument_noalias > 1
-              && TREE_CODE (t) == INDIRECT_REF
+              && (INDIRECT_REF_P (t))
               && TREE_CODE (TREE_OPERAND (t, 0)) == PARM_DECL)
        {
          expr = t;
          offset = NULL;
        }
+
+      if (!align_computed && !INDIRECT_REF_P (t))
+       {
+         unsigned int obj_align
+           = get_object_alignment (t, align, BIGGEST_ALIGNMENT);
+         align = MAX (align, obj_align);
+       }
     }
 
   /* If we modified OFFSET based on T, then subtract the outstanding
@@ -2015,6 +1828,14 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
        size = plus_constant (size, apply_bitpos / BITS_PER_UNIT);
     }
 
+  if (TREE_CODE (t) == ALIGN_INDIRECT_REF)
+    {
+      /* Force EXPR and OFFSET to NULL, since we don't know exactly what
+        we're overlapping.  */
+      offset = NULL;
+      expr = NULL;
+    }
+
   /* Now set the attributes we computed above.  */
   MEM_ATTRS (ref)
     = get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref));
@@ -2037,7 +1858,7 @@ set_mem_attributes (rtx ref, tree t, int objectp)
   set_mem_attributes_minus_bitpos (ref, t, objectp, 0);
 }
 
-/* Set the decl for MEM to DECL.  */
+/* Set MEM to the decl that REG refers to.  */
 
 void
 set_mem_attrs_from_reg (rtx mem, rtx reg)
@@ -2051,12 +1872,11 @@ set_mem_attrs_from_reg (rtx mem, rtx reg)
 /* Set the alias set of MEM to SET.  */
 
 void
-set_mem_alias_set (rtx mem, HOST_WIDE_INT set)
+set_mem_alias_set (rtx mem, alias_set_type set)
 {
 #ifdef ENABLE_CHECKING
   /* If the new and old alias sets don't conflict, something is wrong.  */
-  if (!alias_sets_conflict_p (set, MEM_ALIAS_SET (mem)))
-    abort ();
+  gcc_assert (alias_sets_conflict_p (set, MEM_ALIAS_SET (mem)));
 #endif
 
   MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem),
@@ -2113,22 +1933,21 @@ set_mem_size (rtx mem, rtx size)
 static rtx
 change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate)
 {
-  rtx new;
+  rtx new_rtx;
 
-  if (GET_CODE (memref) != MEM)
-    abort ();
+  gcc_assert (MEM_P (memref));
   if (mode == VOIDmode)
     mode = GET_MODE (memref);
   if (addr == 0)
     addr = XEXP (memref, 0);
+  if (mode == GET_MODE (memref) && addr == XEXP (memref, 0)
+      && (!validate || memory_address_p (mode, addr)))
+    return memref;
 
   if (validate)
     {
       if (reload_in_progress || reload_completed)
-       {
-         if (! memory_address_p (mode, addr))
-           abort ();
-       }
+       gcc_assert (memory_address_p (mode, addr));
       else
        addr = memory_address (mode, addr);
     }
@@ -2136,9 +1955,9 @@ change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate)
   if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref))
     return memref;
 
-  new = gen_rtx_MEM (mode, addr);
-  MEM_COPY_ATTRIBUTES (new, memref);
-  return new;
+  new_rtx = gen_rtx_MEM (mode, addr);
+  MEM_COPY_ATTRIBUTES (new_rtx, memref);
+  return new_rtx;
 }
 
 /* Like change_address_1 with VALIDATE nonzero, but we are not saying in what
@@ -2147,17 +1966,31 @@ change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate)
 rtx
 change_address (rtx memref, enum machine_mode mode, rtx addr)
 {
-  rtx new = change_address_1 (memref, mode, addr, 1);
-  enum machine_mode mmode = GET_MODE (new);
+  rtx new_rtx = change_address_1 (memref, mode, addr, 1), size;
+  enum machine_mode mmode = GET_MODE (new_rtx);
+  unsigned int align;
 
-  MEM_ATTRS (new)
-    = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0,
-                    mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode)),
-                    (mmode == BLKmode ? BITS_PER_UNIT
-                     : GET_MODE_ALIGNMENT (mmode)),
-                    mmode);
+  size = mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode));
+  align = mmode == BLKmode ? BITS_PER_UNIT : GET_MODE_ALIGNMENT (mmode);
 
-  return new;
+  /* If there are no changes, just return the original memory reference.  */
+  if (new_rtx == memref)
+    {
+      if (MEM_ATTRS (memref) == 0
+         || (MEM_EXPR (memref) == NULL
+             && MEM_OFFSET (memref) == NULL
+             && MEM_SIZE (memref) == size
+             && MEM_ALIGN (memref) == align))
+       return new_rtx;
+
+      new_rtx = gen_rtx_MEM (mmode, XEXP (memref, 0));
+      MEM_COPY_ATTRIBUTES (new_rtx, memref);
+    }
+
+  MEM_ATTRS (new_rtx)
+    = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, mmode);
+
+  return new_rtx;
 }
 
 /* Return a memory reference like MEMREF, but with its mode changed
@@ -2171,16 +2004,32 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
                  int validate, int adjust)
 {
   rtx addr = XEXP (memref, 0);
-  rtx new;
+  rtx new_rtx;
   rtx memoffset = MEM_OFFSET (memref);
   rtx size = 0;
   unsigned int memalign = MEM_ALIGN (memref);
+  int pbits;
+
+  /* If there are no changes, just return the original memory reference.  */
+  if (mode == GET_MODE (memref) && !offset
+      && (!validate || memory_address_p (mode, addr)))
+    return memref;
 
   /* ??? Prefer to create garbage instead of creating shared rtl.
      This may happen even if offset is nonzero -- consider
      (plus (plus reg reg) const_int) -- so do this always.  */
   addr = copy_rtx (addr);
 
+  /* Convert a possibly large offset to a signed value within the
+     range of the target address space.  */
+  pbits = GET_MODE_BITSIZE (Pmode);
+  if (HOST_BITS_PER_WIDE_INT > pbits)
+    {
+      int shift = HOST_BITS_PER_WIDE_INT - pbits;
+      offset = (((HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) offset << shift))
+               >> shift);
+    }
+
   if (adjust)
     {
       /* If MEMREF is a LO_SUM and the offset is within the alignment of the
@@ -2195,7 +2044,12 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
        addr = plus_constant (addr, offset);
     }
 
-  new = change_address_1 (memref, mode, addr, validate);
+  new_rtx = change_address_1 (memref, mode, addr, validate);
+
+  /* If the address is a REG, change_address_1 rightfully returns memref,
+     but this would destroy memref's MEM_ATTRS.  */
+  if (new_rtx == memref && offset != 0)
+    new_rtx = copy_rtx (new_rtx);
 
   /* Compute the new values of the memory attributes due to this adjustment.
      We add the offsets and update the alignment.  */
@@ -2211,22 +2065,22 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
             (unsigned HOST_WIDE_INT) (offset & -offset) * BITS_PER_UNIT);
 
   /* We can compute the size in a number of ways.  */
-  if (GET_MODE (new) != BLKmode)
-    size = GEN_INT (GET_MODE_SIZE (GET_MODE (new)));
+  if (GET_MODE (new_rtx) != BLKmode)
+    size = GEN_INT (GET_MODE_SIZE (GET_MODE (new_rtx)));
   else if (MEM_SIZE (memref))
     size = plus_constant (MEM_SIZE (memref), -offset);
 
-  MEM_ATTRS (new) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref),
-                                  memoffset, size, memalign, GET_MODE (new));
+  MEM_ATTRS (new_rtx) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref),
+                                  memoffset, size, memalign, GET_MODE (new_rtx));
 
   /* At some point, we should validate that this offset is within the object,
      if all the appropriate values are known.  */
-  return new;
+  return new_rtx;
 }
 
 /* Return a memory reference like MEMREF, but with its mode changed
    to MODE and its address changed to ADDR, which is assumed to be
-   MEMREF offseted by OFFSET bytes.  If VALIDATE is
+   MEMREF offset by OFFSET bytes.  If VALIDATE is
    nonzero, the memory address is forced to be valid.  */
 
 rtx
@@ -2244,9 +2098,9 @@ adjust_automodify_address_1 (rtx memref, enum machine_mode mode, rtx addr,
 rtx
 offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2)
 {
-  rtx new, addr = XEXP (memref, 0);
+  rtx new_rtx, addr = XEXP (memref, 0);
 
-  new = simplify_gen_binary (PLUS, Pmode, addr, offset);
+  new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset);
 
   /* At this point we don't know _why_ the address is invalid.  It
      could have secondary memory references, multiplies or anything.
@@ -2255,24 +2109,28 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2)
      being able to recognize the magic around pic_offset_table_rtx.
      This stuff is fragile, and is yet another example of why it is
      bad to expose PIC machinery too early.  */
-  if (! memory_address_p (GET_MODE (memref), new)
+  if (! memory_address_p (GET_MODE (memref), new_rtx)
       && GET_CODE (addr) == PLUS
       && XEXP (addr, 0) == pic_offset_table_rtx)
     {
       addr = force_reg (GET_MODE (addr), addr);
-      new = simplify_gen_binary (PLUS, Pmode, addr, offset);
+      new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset);
     }
 
-  update_temp_slot_address (XEXP (memref, 0), new);
-  new = change_address_1 (memref, VOIDmode, new, 1);
+  update_temp_slot_address (XEXP (memref, 0), new_rtx);
+  new_rtx = change_address_1 (memref, VOIDmode, new_rtx, 1);
+
+  /* If there are no changes, just return the original memory reference.  */
+  if (new_rtx == memref)
+    return new_rtx;
 
   /* Update the alignment to reflect the offset.  Reset the offset, which
      we don't know.  */
-  MEM_ATTRS (new)
+  MEM_ATTRS (new_rtx)
     = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), 0, 0,
                     MIN (MEM_ALIGN (memref), pow2 * BITS_PER_UNIT),
-                    GET_MODE (new));
-  return new;
+                    GET_MODE (new_rtx));
+  return new_rtx;
 }
 
 /* Return a memory reference like MEMREF, but with its address changed to
@@ -2305,11 +2163,15 @@ replace_equiv_address_nv (rtx memref, rtx addr)
 rtx
 widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
 {
-  rtx new = adjust_address_1 (memref, mode, offset, 1, 1);
-  tree expr = MEM_EXPR (new);
-  rtx memoffset = MEM_OFFSET (new);
+  rtx new_rtx = adjust_address_1 (memref, mode, offset, 1, 1);
+  tree expr = MEM_EXPR (new_rtx);
+  rtx memoffset = MEM_OFFSET (new_rtx);
   unsigned int size = GET_MODE_SIZE (mode);
 
+  /* If there are no changes, just return the original memory reference.  */
+  if (new_rtx == memref)
+    return new_rtx;
+
   /* If we don't know what offset we were at within the expression, then
      we can't know if we've overstepped the bounds.  */
   if (! memoffset)
@@ -2320,6 +2182,7 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
       if (TREE_CODE (expr) == COMPONENT_REF)
        {
          tree field = TREE_OPERAND (expr, 1);
+         tree offset = component_ref_field_offset (expr);
 
          if (! DECL_SIZE_UNIT (field))
            {
@@ -2334,17 +2197,18 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
              && INTVAL (memoffset) >= 0)
            break;
 
-         if (! host_integerp (DECL_FIELD_OFFSET (field), 1))
+         if (! host_integerp (offset, 1))
            {
              expr = NULL_TREE;
              break;
            }
 
          expr = TREE_OPERAND (expr, 0);
-         memoffset = (GEN_INT (INTVAL (memoffset)
-                      + tree_low_cst (DECL_FIELD_OFFSET (field), 1)
-                      + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
-                         / BITS_PER_UNIT)));
+         memoffset
+           = (GEN_INT (INTVAL (memoffset)
+                       + tree_low_cst (offset, 1)
+                       + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+                          / BITS_PER_UNIT)));
        }
       /* Similarly for the decl.  */
       else if (DECL_P (expr)
@@ -2368,89 +2232,109 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
   /* The widened memory may alias other stuff, so zap the alias set.  */
   /* ??? Maybe use get_alias_set on any remaining expression.  */
 
-  MEM_ATTRS (new) = get_mem_attrs (0, expr, memoffset, GEN_INT (size),
-                                  MEM_ALIGN (new), mode);
+  MEM_ATTRS (new_rtx) = get_mem_attrs (0, expr, memoffset, GEN_INT (size),
+                                  MEM_ALIGN (new_rtx), mode);
 
-  return new;
+  return new_rtx;
 }
 \f
-/* Return a newly created CODE_LABEL rtx with a unique label number.  */
+/* A fake decl that is used as the MEM_EXPR of spill slots.  */
+static GTY(()) tree spill_slot_decl;
 
-rtx
-gen_label_rtx (void)
+tree
+get_spill_slot_decl (bool force_build_p)
 {
-  return gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX, NULL_RTX,
-                            NULL, label_num++, NULL);
-}
-\f
-/* For procedure integration.  */
+  tree d = spill_slot_decl;
+  rtx rd;
 
-/* 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.  */
+  if (d || !force_build_p)
+    return d;
 
-void
-set_new_first_and_last_insn (rtx first, rtx last)
-{
-  rtx insn;
-
-  first_insn = first;
-  last_insn = last;
-  cur_insn_uid = 0;
+  d = build_decl (VAR_DECL, get_identifier ("%sfp"), void_type_node);
+  DECL_ARTIFICIAL (d) = 1;
+  DECL_IGNORED_P (d) = 1;
+  TREE_USED (d) = 1;
+  TREE_THIS_NOTRAP (d) = 1;
+  spill_slot_decl = d;
 
-  for (insn = first; insn; insn = NEXT_INSN (insn))
-    cur_insn_uid = MAX (cur_insn_uid, INSN_UID (insn));
+  rd = gen_rtx_MEM (BLKmode, frame_pointer_rtx);
+  MEM_NOTRAP_P (rd) = 1;
+  MEM_ATTRS (rd) = get_mem_attrs (new_alias_set (), d, const0_rtx,
+                                 NULL_RTX, 0, BLKmode);
+  SET_DECL_RTL (d, rd);
 
-  cur_insn_uid++;
+  return d;
 }
 
-/* Set the range of label numbers found in the current function.
-   This is used when belatedly compiling an inline function.  */
+/* Given MEM, a result from assign_stack_local, fill in the memory
+   attributes as appropriate for a register allocator spill slot.
+   These slots are not aliasable by other memory.  We arrange for
+   them all to use a single MEM_EXPR, so that the aliasing code can
+   work properly in the case of shared spill slots.  */
 
 void
-set_new_first_and_last_label_num (int first, int last)
+set_mem_attrs_for_spill (rtx mem)
 {
-  base_label_num = label_num;
-  first_label_num = first;
-  last_label_num = last;
-}
+  alias_set_type alias;
+  rtx addr, offset;
+  tree expr;
 
-/* Set the last label number found in the current function.
-   This is used when belatedly compiling an inline function.  */
+  expr = get_spill_slot_decl (true);
+  alias = MEM_ALIAS_SET (DECL_RTL (expr));
 
-void
-set_new_last_label_num (int last)
-{
-  base_label_num = label_num;
-  last_label_num = last;
+  /* We expect the incoming memory to be of the form:
+       (mem:MODE (plus (reg sfp) (const_int offset)))
+     with perhaps the plus missing for offset = 0.  */
+  addr = XEXP (mem, 0);
+  offset = const0_rtx;
+  if (GET_CODE (addr) == PLUS
+      && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+    offset = XEXP (addr, 1);
+
+  MEM_ATTRS (mem) = get_mem_attrs (alias, expr, offset,
+                                  MEM_SIZE (mem), MEM_ALIGN (mem),
+                                  GET_MODE (mem));
+  MEM_NOTRAP_P (mem) = 1;
 }
 \f
-/* Restore all variables describing the current status from the structure *P.
-   This is used after a nested function.  */
+/* Return a newly created CODE_LABEL rtx with a unique label number.  */
 
-void
-restore_emit_status (struct function *p ATTRIBUTE_UNUSED)
+rtx
+gen_label_rtx (void)
 {
-  last_label_num = 0;
+  return gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX, NULL_RTX,
+                            NULL, label_num++, NULL);
 }
 \f
-/* Go through all the RTL insn bodies and copy any invalid shared
-   structure.  This routine should only be called once.  */
+/* For procedure integration.  */
+
+/* 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.  */
 
 void
-unshare_all_rtl (tree fndecl, rtx insn)
+set_new_first_and_last_insn (rtx first, rtx last)
 {
-  tree decl;
+  rtx insn;
 
-  /* Make sure that virtual parameters are not shared.  */
-  for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
-    SET_DECL_RTL (decl, copy_rtx_if_shared (DECL_RTL (decl)));
+  first_insn = first;
+  last_insn = last;
+  cur_insn_uid = 0;
 
-  /* Make sure that virtual stack slots are not shared.  */
-  unshare_all_decls (DECL_INITIAL (fndecl));
+  for (insn = first; insn; insn = NEXT_INSN (insn))
+    cur_insn_uid = MAX (cur_insn_uid, INSN_UID (insn));
+
+  cur_insn_uid++;
+}
+\f
+/* Go through all the RTL insn bodies and copy any invalid shared
+   structure.  This routine should only be called once.  */
 
+static void
+unshare_all_rtl_1 (rtx insn)
+{
   /* Unshare just about everything else.  */
-  unshare_all_rtl_1 (insn);
+  unshare_all_rtl_in_chain (insn);
 
   /* Make sure the addresses of stack slots found outside the insn chain
      (such as, in DECL_RTL of a variable) are not shared
@@ -2477,184 +2361,260 @@ unshare_all_rtl_again (rtx insn)
       {
        reset_used_flags (PATTERN (p));
        reset_used_flags (REG_NOTES (p));
-       reset_used_flags (LOG_LINKS (p));
       }
 
   /* Make sure that virtual stack slots are not shared.  */
-  reset_used_decls (DECL_INITIAL (cfun->decl));
+  set_used_decls (DECL_INITIAL (cfun->decl));
 
   /* Make sure that virtual parameters are not shared.  */
   for (decl = DECL_ARGUMENTS (cfun->decl); decl; decl = TREE_CHAIN (decl))
-    reset_used_flags (DECL_RTL (decl));
+    set_used_flags (DECL_RTL (decl));
 
   reset_used_flags (stack_slot_list);
 
-  unshare_all_rtl (cfun->decl, insn);
+  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 (rtx insn)
+unsigned int
+unshare_all_rtl (void)
 {
-  for (; insn; insn = NEXT_INSN (insn))
-    if (INSN_P (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));
-      }
+  unshare_all_rtl_1 (get_insns ());
+  return 0;
 }
 
-/* Go through all virtual stack slots of a function and copy any
-   shared structure.  */
-static void
-unshare_all_decls (tree blk)
+struct rtl_opt_pass pass_unshare_all_rtl =
 {
-  tree t;
+ {
+  RTL_PASS,
+  "unshare",                            /* name */
+  NULL,                                 /* gate */
+  unshare_all_rtl,                      /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  0,                                    /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func | TODO_verify_rtl_sharing /* todo_flags_finish */
+ }
+};
 
-  /* Copy shared decls.  */
-  for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t))
-    if (DECL_RTL_SET_P (t))
-      SET_DECL_RTL (t, copy_rtx_if_shared (DECL_RTL (t)));
 
-  /* Now process sub-blocks.  */
-  for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t))
-    unshare_all_decls (t);
-}
+/* Check that ORIG is not marked when it should not be and mark ORIG as in use,
+   Recursively does the same for subexpressions.  */
 
-/* Go through all virtual stack slots of a function and mark them as
-   not shared.  */
 static void
-reset_used_decls (tree blk)
+verify_rtx_sharing (rtx orig, rtx insn)
 {
-  tree t;
-
-  /* Mark decls.  */
-  for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t))
-    if (DECL_RTL_SET_P (t))
-      reset_used_flags (DECL_RTL (t));
-
-  /* Now process sub-blocks.  */
-  for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t))
-    reset_used_decls (t);
-}
-
-/* Similar to `copy_rtx' except that if MAY_SHARE is present, it is
-   placed in the result directly, rather than being copied.  MAY_SHARE is
-   either a MEM of an EXPR_LIST of MEMs.  */
-
-rtx
-copy_most_rtx (rtx orig, rtx may_share)
-{
-  rtx copy;
-  int i, j;
-  RTX_CODE code;
+  rtx x = orig;
+  int i;
+  enum rtx_code code;
   const char *format_ptr;
 
-  if (orig == may_share
-      || (GET_CODE (may_share) == EXPR_LIST
-         && in_expr_list_p (may_share, orig)))
-    return orig;
+  if (x == 0)
+    return;
 
-  code = GET_CODE (orig);
+  code = GET_CODE (x);
+
+  /* These types may be freely shared.  */
 
   switch (code)
     {
     case REG:
-    case QUEUED:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
+    case LABEL_REF:
     case CODE_LABEL:
     case PC:
     case CC0:
-      return orig;
+    case SCRATCH:
+      return;
+      /* SCRATCH must be shared because they represent distinct values.  */
+    case CLOBBER:
+      if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
+       return;
+      break;
+
+    case CONST:
+      if (shared_const_p (orig))
+       return;
+      break;
+
+    case MEM:
+      /* A MEM is allowed to be shared if its address is constant.  */
+      if (CONSTANT_ADDRESS_P (XEXP (x, 0))
+         || reload_completed || reload_in_progress)
+       return;
+
+      break;
+
     default:
       break;
     }
 
-  copy = rtx_alloc (code);
-  PUT_MODE (copy, GET_MODE (orig));
-  RTX_FLAG (copy, in_struct) = RTX_FLAG (orig, in_struct);
-  RTX_FLAG (copy, volatil) = RTX_FLAG (orig, volatil);
-  RTX_FLAG (copy, unchanging) = RTX_FLAG (orig, unchanging);
-  RTX_FLAG (copy, integrated) = RTX_FLAG (orig, integrated);
-  RTX_FLAG (copy, frame_related) = RTX_FLAG (orig, frame_related);
+  /* This rtx may not be shared.  If it has already been seen,
+     replace it with a copy of itself.  */
+#ifdef ENABLE_CHECKING
+  if (RTX_FLAG (x, used))
+    {
+      error ("invalid rtl sharing found in the insn");
+      debug_rtx (insn);
+      error ("shared rtx");
+      debug_rtx (x);
+      internal_error ("internal consistency failure");
+    }
+#endif
+  gcc_assert (!RTX_FLAG (x, used));
+  
+  RTX_FLAG (x, used) = 1;
+
+  /* Now scan the subexpressions recursively.  */
 
-  format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
+  format_ptr = GET_RTX_FORMAT (code);
 
-  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
+  for (i = 0; i < GET_RTX_LENGTH (code); i++)
     {
       switch (*format_ptr++)
        {
        case 'e':
-         XEXP (copy, i) = XEXP (orig, i);
-         if (XEXP (orig, i) != NULL && XEXP (orig, i) != may_share)
-           XEXP (copy, i) = copy_most_rtx (XEXP (orig, i), may_share);
-         break;
-
-       case 'u':
-         XEXP (copy, i) = XEXP (orig, i);
+         verify_rtx_sharing (XEXP (x, i), insn);
          break;
 
        case 'E':
-       case 'V':
-         XVEC (copy, i) = XVEC (orig, i);
-         if (XVEC (orig, i) != NULL)
+         if (XVEC (x, i) != NULL)
            {
-             XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
-             for (j = 0; j < XVECLEN (copy, i); j++)
-               XVECEXP (copy, i, j)
-                 = copy_most_rtx (XVECEXP (orig, i, j), may_share);
+             int j;
+             int len = XVECLEN (x, i);
+
+             for (j = 0; j < len; j++)
+               {
+                 /* We allow sharing of ASM_OPERANDS inside single
+                    instruction.  */
+                 if (j && GET_CODE (XVECEXP (x, i, j)) == SET
+                     && (GET_CODE (SET_SRC (XVECEXP (x, i, j)))
+                         == ASM_OPERANDS))
+                   verify_rtx_sharing (SET_DEST (XVECEXP (x, i, j)), insn);
+                 else
+                   verify_rtx_sharing (XVECEXP (x, i, j), insn);
+               }
            }
          break;
+       }
+    }
+  return;
+}
 
-       case 'w':
-         XWINT (copy, i) = XWINT (orig, i);
-         break;
+/* Go through all the RTL insn bodies and check that there is no unexpected
+   sharing in between the subexpressions.  */
 
-       case 'n':
-       case 'i':
-         XINT (copy, i) = XINT (orig, i);
-         break;
+void
+verify_rtl_sharing (void)
+{
+  rtx p;
 
-       case 't':
-         XTREE (copy, i) = XTREE (orig, i);
-         break;
+  for (p = get_insns (); p; p = NEXT_INSN (p))
+    if (INSN_P (p))
+      {
+       reset_used_flags (PATTERN (p));
+       reset_used_flags (REG_NOTES (p));
+       if (GET_CODE (PATTERN (p)) == SEQUENCE)
+         {
+           int i;
+           rtx q, sequence = PATTERN (p);
+
+           for (i = 0; i < XVECLEN (sequence, 0); i++)
+             {
+               q = XVECEXP (sequence, 0, i);
+               gcc_assert (INSN_P (q));
+               reset_used_flags (PATTERN (q));
+               reset_used_flags (REG_NOTES (q));
+             }
+         }
+      }
 
-       case 's':
-       case 'S':
-         XSTR (copy, i) = XSTR (orig, i);
-         break;
+  for (p = get_insns (); p; p = NEXT_INSN (p))
+    if (INSN_P (p))
+      {
+       verify_rtx_sharing (PATTERN (p), p);
+       verify_rtx_sharing (REG_NOTES (p), p);
+      }
+}
 
-       case '0':
-         X0ANY (copy, i) = X0ANY (orig, i);
-         break;
+/* Go through all the RTL insn bodies and copy any invalid shared structure.
+   Assumes the mark bits are cleared at entry.  */
 
-       default:
-         abort ();
-       }
-    }
-  return copy;
+void
+unshare_all_rtl_in_chain (rtx insn)
+{
+  for (; insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      {
+       PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
+       REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn));
+      }
+}
+
+/* Go through all virtual stack slots of a function and mark them as
+   shared.  We never replace the DECL_RTLs themselves with a copy,
+   but expressions mentioned into a DECL_RTL cannot be shared with
+   expressions in the instruction stream.
+
+   Note that reload may convert pseudo registers into memories in-place.
+   Pseudo registers are always shared, but MEMs never are.  Thus if we
+   reset the used flags on MEMs in the instruction stream, we must set
+   them again on MEMs that appear in DECL_RTLs.  */
+
+static void
+set_used_decls (tree blk)
+{
+  tree t;
+
+  /* Mark decls.  */
+  for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t))
+    if (DECL_RTL_SET_P (t))
+      set_used_flags (DECL_RTL (t));
+
+  /* Now process sub-blocks.  */
+  for (t = BLOCK_SUBBLOCKS (blk); t; t = BLOCK_CHAIN (t))
+    set_used_decls (t);
 }
 
 /* Mark ORIG as in use, and return a copy of it if it was already in use.
-   Recursively does the same for subexpressions.  */
+   Recursively does the same for subexpressions.  Uses
+   copy_rtx_if_shared_1 to reduce stack space.  */
 
 rtx
 copy_rtx_if_shared (rtx orig)
 {
-  rtx x = orig;
+  copy_rtx_if_shared_1 (&orig);
+  return orig;
+}
+
+/* Mark *ORIG1 as in use, and set it to a copy of it if it was already in
+   use.  Recursively does the same for subexpressions.  */
+
+static void
+copy_rtx_if_shared_1 (rtx *orig1)
+{
+  rtx x;
   int i;
   enum rtx_code code;
+  rtx *last_ptr;
   const char *format_ptr;
   int copied = 0;
+  int length;
+
+  /* Repeat is used to turn tail-recursion into iteration.  */
+repeat:
+  x = *orig1;
 
   if (x == 0)
-    return 0;
+    return;
 
   code = GET_CODE (x);
 
@@ -2663,25 +2623,26 @@ copy_rtx_if_shared (rtx orig)
   switch (code)
     {
     case REG:
-    case QUEUED:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
+    case LABEL_REF:
     case CODE_LABEL:
     case PC:
     case CC0:
     case SCRATCH:
       /* SCRATCH must be shared because they represent distinct values.  */
-      return x;
+      return;
+    case CLOBBER:
+      if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
+       return;
+      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 (x, 0)) == PLUS
-         && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
-         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
-       return x;
+      if (shared_const_p (x))
+       return;
       break;
 
     case INSN:
@@ -2690,7 +2651,7 @@ copy_rtx_if_shared (rtx orig)
     case NOTE:
     case BARRIER:
       /* The chain of insns is not being copied.  */
-      return x;
+      return;
 
     default:
       break;
@@ -2701,11 +2662,7 @@ copy_rtx_if_shared (rtx orig)
 
   if (RTX_FLAG (x, used))
     {
-      rtx copy;
-
-      copy = rtx_alloc (code);
-      memcpy (copy, x, RTX_SIZE (code));
-      x = copy;
+      x = shallow_copy_rtx (x);
       copied = 1;
     }
   RTX_FLAG (x, used) = 1;
@@ -2716,13 +2673,17 @@ copy_rtx_if_shared (rtx orig)
      must be copied if X was copied.  */
 
   format_ptr = GET_RTX_FORMAT (code);
-
-  for (i = 0; i < GET_RTX_LENGTH (code); i++)
+  length = GET_RTX_LENGTH (code);
+  last_ptr = NULL;
+  
+  for (i = 0; i < length; i++)
     {
       switch (*format_ptr++)
        {
        case 'e':
-         XEXP (x, i) = copy_rtx_if_shared (XEXP (x, i));
+          if (last_ptr)
+            copy_rtx_if_shared_1 (last_ptr);
+         last_ptr = &XEXP (x, i);
          break;
 
        case 'E':
@@ -2730,16 +2691,30 @@ copy_rtx_if_shared (rtx orig)
            {
              int j;
              int len = XVECLEN (x, i);
-
+              
+              /* Copy the vector iff I copied the rtx and the length
+                is nonzero.  */
              if (copied && len > 0)
                XVEC (x, i) = gen_rtvec_v (len, XVEC (x, i)->elem);
+              
+              /* Call recursively on all inside the vector.  */
              for (j = 0; j < len; j++)
-               XVECEXP (x, i, j) = copy_rtx_if_shared (XVECEXP (x, i, j));
+                {
+                 if (last_ptr)
+                   copy_rtx_if_shared_1 (last_ptr);
+                  last_ptr = &XVECEXP (x, i, j);
+                }
            }
          break;
        }
     }
-  return x;
+  *orig1 = x;
+  if (last_ptr)
+    {
+      orig1 = last_ptr;
+      goto repeat;
+    }
+  return;
 }
 
 /* Clear all the USED bits in X to allow copy_rtx_if_shared to be used
@@ -2751,7 +2726,10 @@ reset_used_flags (rtx x)
   int i, j;
   enum rtx_code code;
   const char *format_ptr;
+  int length;
 
+  /* Repeat is used to turn tail-recursion into iteration.  */
+repeat:
   if (x == 0)
     return;
 
@@ -2763,9 +2741,9 @@ reset_used_flags (rtx x)
   switch (code)
     {
     case REG:
-    case QUEUED:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case CODE_LABEL:
@@ -2789,11 +2767,18 @@ reset_used_flags (rtx x)
   RTX_FLAG (x, used) = 0;
 
   format_ptr = GET_RTX_FORMAT (code);
-  for (i = 0; i < GET_RTX_LENGTH (code); i++)
+  length = GET_RTX_LENGTH (code);
+  
+  for (i = 0; i < length; i++)
     {
       switch (*format_ptr++)
        {
        case 'e':
+          if (i == length-1)
+            {
+              x = XEXP (x, i);
+             goto repeat;
+            }
          reset_used_flags (XEXP (x, i));
          break;
 
@@ -2804,6 +2789,69 @@ reset_used_flags (rtx x)
        }
     }
 }
+
+/* Set all the USED bits in X to allow copy_rtx_if_shared to be used
+   to look for shared sub-parts.  */
+
+void
+set_used_flags (rtx x)
+{
+  int i, j;
+  enum rtx_code code;
+  const char *format_ptr;
+
+  if (x == 0)
+    return;
+
+  code = GET_CODE (x);
+
+  /* These types may be freely shared so we needn't do any resetting
+     for them.  */
+
+  switch (code)
+    {
+    case REG:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONST_FIXED:
+    case CONST_VECTOR:
+    case SYMBOL_REF:
+    case CODE_LABEL:
+    case PC:
+    case CC0:
+      return;
+
+    case INSN:
+    case JUMP_INSN:
+    case CALL_INSN:
+    case NOTE:
+    case LABEL_REF:
+    case BARRIER:
+      /* The chain of insns is not being copied.  */
+      return;
+
+    default:
+      break;
+    }
+
+  RTX_FLAG (x, used) = 1;
+
+  format_ptr = GET_RTX_FORMAT (code);
+  for (i = 0; i < GET_RTX_LENGTH (code); i++)
+    {
+      switch (*format_ptr++)
+       {
+       case 'e':
+         set_used_flags (XEXP (x, i));
+         break;
+
+       case 'E':
+         for (j = 0; j < XVECLEN (x, i); j++)
+           set_used_flags (XVECEXP (x, i, j));
+         break;
+       }
+    }
+}
 \f
 /* Copy X if necessary so that it won't be altered by changes in OTHER.
    Return X or the rtx for the pseudo reg the value of X was copied into.
@@ -2827,11 +2875,11 @@ make_safe_from (rtx x, rtx other)
        goto done;
       }
  done:
-  if ((GET_CODE (other) == MEM
+  if ((MEM_P (other)
        && ! CONSTANT_P (x)
-       && GET_CODE (x) != REG
+       && !REG_P (x)
        && GET_CODE (x) != SUBREG)
-      || (GET_CODE (other) == REG
+      || (REG_P (other)
          && (REGNO (other) < FIRST_PSEUDO_REGISTER
              || reg_mentioned_p (other, x))))
     {
@@ -2857,8 +2905,7 @@ get_insns (void)
 void
 set_first_insn (rtx insn)
 {
-  if (PREV_INSN (insn) != 0)
-    abort ();
+  gcc_assert (!PREV_INSN (insn));
   first_insn = insn;
 }
 
@@ -2875,8 +2922,7 @@ get_last_insn (void)
 void
 set_last_insn (rtx insn)
 {
-  if (NEXT_INSN (insn) != 0)
-    abort ();
+  gcc_assert (!NEXT_INSN (insn));
   last_insn = insn;
 }
 
@@ -2902,11 +2948,19 @@ get_first_nonnote_insn (void)
 {
   rtx insn = first_insn;
 
-  while (insn)
+  if (insn)
     {
-      insn = next_insn (insn);
-      if (insn == 0 || GET_CODE (insn) != NOTE)
-       break;
+      if (NOTE_P (insn))
+       for (insn = next_insn (insn);
+            insn && NOTE_P (insn);
+            insn = next_insn (insn))
+         continue;
+      else
+       {
+         if (NONJUMP_INSN_P (insn)
+             && GET_CODE (PATTERN (insn)) == SEQUENCE)
+           insn = XVECEXP (PATTERN (insn), 0, 0);
+       }
     }
 
   return insn;
@@ -2920,11 +2974,20 @@ get_last_nonnote_insn (void)
 {
   rtx insn = last_insn;
 
-  while (insn)
+  if (insn)
     {
-      insn = previous_insn (insn);
-      if (insn == 0 || GET_CODE (insn) != NOTE)
-       break;
+      if (NOTE_P (insn))
+       for (insn = previous_insn (insn);
+            insn && NOTE_P (insn);
+            insn = previous_insn (insn))
+         continue;
+      else
+       {
+         if (NONJUMP_INSN_P (insn)
+             && GET_CODE (PATTERN (insn)) == SEQUENCE)
+           insn = XVECEXP (PATTERN (insn), 0,
+                           XVECLEN (PATTERN (insn), 0) - 1);
+       }
     }
 
   return insn;
@@ -2937,33 +3000,6 @@ get_max_uid (void)
 {
   return cur_insn_uid;
 }
-
-/* Renumber instructions so that no instruction UIDs are wasted.  */
-
-void
-renumber_insns (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.  */
@@ -2974,7 +3010,7 @@ next_insn (rtx insn)
   if (insn)
     {
       insn = NEXT_INSN (insn);
-      if (insn && GET_CODE (insn) == INSN
+      if (insn && NONJUMP_INSN_P (insn)
          && GET_CODE (PATTERN (insn)) == SEQUENCE)
        insn = XVECEXP (PATTERN (insn), 0, 0);
     }
@@ -2991,7 +3027,7 @@ previous_insn (rtx insn)
   if (insn)
     {
       insn = PREV_INSN (insn);
-      if (insn && GET_CODE (insn) == INSN
+      if (insn && NONJUMP_INSN_P (insn)
          && GET_CODE (PATTERN (insn)) == SEQUENCE)
        insn = XVECEXP (PATTERN (insn), 0, XVECLEN (PATTERN (insn), 0) - 1);
     }
@@ -3008,7 +3044,7 @@ next_nonnote_insn (rtx insn)
   while (insn)
     {
       insn = NEXT_INSN (insn);
-      if (insn == 0 || GET_CODE (insn) != NOTE)
+      if (insn == 0 || !NOTE_P (insn))
        break;
     }
 
@@ -3024,7 +3060,7 @@ prev_nonnote_insn (rtx insn)
   while (insn)
     {
       insn = PREV_INSN (insn);
-      if (insn == 0 || GET_CODE (insn) != NOTE)
+      if (insn == 0 || !NOTE_P (insn))
        break;
     }
 
@@ -3041,8 +3077,7 @@ next_real_insn (rtx insn)
   while (insn)
     {
       insn = NEXT_INSN (insn);
-      if (insn == 0 || GET_CODE (insn) == INSN
-         || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
+      if (insn == 0 || INSN_P (insn))
        break;
     }
 
@@ -3059,8 +3094,7 @@ prev_real_insn (rtx insn)
   while (insn)
     {
       insn = PREV_INSN (insn);
-      if (insn == 0 || GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
-         || GET_CODE (insn) == JUMP_INSN)
+      if (insn == 0 || INSN_P (insn))
        break;
     }
 
@@ -3076,7 +3110,7 @@ last_call_insn (void)
   rtx insn;
 
   for (insn = get_last_insn ();
-       insn && GET_CODE (insn) != CALL_INSN;
+       insn && !CALL_P (insn);
        insn = PREV_INSN (insn))
     ;
 
@@ -3088,10 +3122,10 @@ last_call_insn (void)
    same as next_real_insn.  */
 
 int
-active_insn_p (rtx insn)
+active_insn_p (const_rtx insn)
 {
-  return (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
-         || (GET_CODE (insn) == INSN
+  return (CALL_P (insn) || JUMP_P (insn)
+         || (NONJUMP_INSN_P (insn)
              && (! reload_completed
                  || (GET_CODE (PATTERN (insn)) != USE
                      && GET_CODE (PATTERN (insn)) != CLOBBER))));
@@ -3135,7 +3169,7 @@ next_label (rtx insn)
   while (insn)
     {
       insn = NEXT_INSN (insn);
-      if (insn == 0 || GET_CODE (insn) == CODE_LABEL)
+      if (insn == 0 || LABEL_P (insn))
        break;
     }
 
@@ -3150,11 +3184,26 @@ prev_label (rtx insn)
   while (insn)
     {
       insn = PREV_INSN (insn);
-      if (insn == 0 || GET_CODE (insn) == CODE_LABEL)
+      if (insn == 0 || LABEL_P (insn))
        break;
     }
 
-  return insn;
+  return insn;
+}
+
+/* Return the last label to mark the same position as LABEL.  Return null
+   if LABEL itself is null.  */
+
+rtx
+skip_consecutive_labels (rtx label)
+{
+  rtx insn;
+
+  for (insn = label; insn != 0 && !INSN_P (insn); insn = NEXT_INSN (insn))
+    if (LABEL_P (insn))
+      label = insn;
+
+  return label;
 }
 \f
 #ifdef HAVE_cc0
@@ -3166,12 +3215,11 @@ link_cc0_insns (rtx insn)
 {
   rtx user = next_nonnote_insn (insn);
 
-  if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE)
+  if (NONJUMP_INSN_P (user) && 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 (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn));
+  add_reg_note (user, REG_CC_SETTER, insn);
+  add_reg_note (insn, REG_CC_USER, user);
 }
 
 /* Return the next insn that uses CC0 after INSN, which is assumed to
@@ -3192,7 +3240,7 @@ next_cc0_user (rtx insn)
     return XEXP (note, 0);
 
   insn = next_nonnote_insn (insn);
-  if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
+  if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
     insn = XVECEXP (PATTERN (insn), 0, 0);
 
   if (insn && INSN_P (insn) && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
@@ -3213,13 +3261,43 @@ prev_cc0_setter (rtx insn)
     return XEXP (note, 0);
 
   insn = prev_nonnote_insn (insn);
-  if (! sets_cc0_p (PATTERN (insn)))
-    abort ();
+  gcc_assert (sets_cc0_p (PATTERN (insn)));
 
   return insn;
 }
 #endif
 
+#ifdef AUTO_INC_DEC
+/* Find a RTX_AUTOINC class rtx which matches DATA.  */
+
+static int
+find_auto_inc (rtx *xp, void *data)
+{
+  rtx x = *xp;
+  rtx reg = (rtx) data;
+
+  if (GET_RTX_CLASS (GET_CODE (x)) != RTX_AUTOINC)
+    return 0;
+
+  switch (GET_CODE (x))
+    {
+      case PRE_DEC:
+      case PRE_INC:
+      case POST_DEC:
+      case POST_INC:
+      case PRE_MODIFY:
+      case POST_MODIFY:
+       if (rtx_equal_p (reg, XEXP (x, 0)))
+         return 1;
+       break;
+
+      default:
+       gcc_unreachable ();
+    }
+  return -1;
+}
+#endif
+
 /* Increment the label uses for all labels present in rtx.  */
 
 static void
@@ -3230,7 +3308,7 @@ mark_label_nuses (rtx x)
   const char *fmt;
 
   code = GET_CODE (x);
-  if (code == LABEL_REF)
+  if (code == LABEL_REF && LABEL_P (XEXP (x, 0)))
     LABEL_NUSES (XEXP (x, 0))++;
 
   fmt = GET_RTX_FORMAT (code);
@@ -3260,8 +3338,7 @@ try_split (rtx pat, rtx trial, int last)
   rtx before = PREV_INSN (trial);
   rtx after = NEXT_INSN (trial);
   int has_barrier = 0;
-  rtx tem;
-  rtx note, seq;
+  rtx note, seq, tem;
   int probability;
   rtx insn_last, insn;
   int njumps = 0;
@@ -3277,7 +3354,7 @@ try_split (rtx pat, rtx trial, int last)
 
   /* If we are splitting a JUMP_INSN, it might be followed by a BARRIER.
      We may need to handle this specially.  */
-  if (after && GET_CODE (after) == BARRIER)
+  if (after && BARRIER_P (after))
     {
       has_barrier = 1;
       after = NEXT_INSN (after);
@@ -3299,10 +3376,14 @@ try_split (rtx pat, rtx trial, int last)
       insn_last = NEXT_INSN (insn_last);
     }
 
+  /* We will be adding the new sequence to the function.  The splitters
+     may have introduced invalid RTL sharing, so unshare the sequence now.  */
+  unshare_all_rtl_in_chain (seq);
+
   /* Mark labels.  */
   for (insn = insn_last; insn ; insn = PREV_INSN (insn))
     {
-      if (GET_CODE (insn) == JUMP_INSN)
+      if (JUMP_P (insn))
        {
          mark_jump_label (PATTERN (insn), insn, 0);
          njumps++;
@@ -3314,22 +3395,18 @@ try_split (rtx pat, rtx trial, int last)
                 one jump is created, otherwise the machine description
                 is responsible for this step using
                 split_branch_probability variable.  */
-             if (njumps != 1)
-               abort ();
-             REG_NOTES (insn)
-               = gen_rtx_EXPR_LIST (REG_BR_PROB,
-                                    GEN_INT (probability),
-                                    REG_NOTES (insn));
+             gcc_assert (njumps == 1);
+             add_reg_note (insn, REG_BR_PROB, GEN_INT (probability));
            }
        }
     }
 
   /* If we are splitting a CALL_INSN, look for the CALL_INSN
      in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it.  */
-  if (GET_CODE (trial) == CALL_INSN)
+  if (CALL_P (trial))
     {
       for (insn = insn_last; insn ; insn = PREV_INSN (insn))
-       if (GET_CODE (insn) == CALL_INSN)
+       if (CALL_P (insn))
          {
            rtx *p = &CALL_INSN_FUNCTION_USAGE (insn);
            while (*p)
@@ -3345,47 +3422,43 @@ try_split (rtx pat, rtx trial, int last)
       switch (REG_NOTE_KIND (note))
        {
        case REG_EH_REGION:
-         insn = insn_last;
-         while (insn != NULL_RTX)
+         for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
            {
-             if (GET_CODE (insn) == CALL_INSN
-                 || (flag_non_call_exceptions
+             if (CALL_P (insn)
+                 || (flag_non_call_exceptions && INSN_P (insn)
                      && may_trap_p (PATTERN (insn))))
-               REG_NOTES (insn)
-                 = gen_rtx_EXPR_LIST (REG_EH_REGION,
-                                      XEXP (note, 0),
-                                      REG_NOTES (insn));
-             insn = PREV_INSN (insn);
+               add_reg_note (insn, REG_EH_REGION, XEXP (note, 0));
            }
          break;
 
        case REG_NORETURN:
        case REG_SETJMP:
-       case REG_ALWAYS_RETURN:
-         insn = insn_last;
-         while (insn != NULL_RTX)
+         for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
            {
-             if (GET_CODE (insn) == CALL_INSN)
-               REG_NOTES (insn)
-                 = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
-                                      XEXP (note, 0),
-                                      REG_NOTES (insn));
-             insn = PREV_INSN (insn);
+             if (CALL_P (insn))
+               add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
            }
          break;
 
        case REG_NON_LOCAL_GOTO:
-         insn = insn_last;
-         while (insn != NULL_RTX)
+         for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
+           {
+             if (JUMP_P (insn))
+               add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
+           }
+         break;
+
+#ifdef AUTO_INC_DEC
+       case REG_INC:
+         for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
            {
-             if (GET_CODE (insn) == JUMP_INSN)
-               REG_NOTES (insn)
-                 = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
-                                      XEXP (note, 0),
-                                      REG_NOTES (insn));
-             insn = PREV_INSN (insn);
+             rtx reg = XEXP (note, 0);
+             if (!FIND_REG_INC_NOTE (insn, reg)
+                 && for_each_rtx (&PATTERN (insn), find_auto_inc, reg) > 0)
+               add_reg_note (insn, REG_INC, reg);
            }
          break;
+#endif
 
        default:
          break;
@@ -3394,12 +3467,13 @@ try_split (rtx pat, rtx trial, int last)
 
   /* If there are LABELS inside the split insns increment the
      usage count so we don't delete the label.  */
-  if (GET_CODE (trial) == INSN)
+  if (INSN_P (trial))
     {
       insn = insn_last;
       while (insn != NULL_RTX)
        {
-         if (GET_CODE (insn) == INSN)
+         /* JUMP_P insns have already been "marked" above.  */
+         if (NONJUMP_INSN_P (insn))
            mark_label_nuses (PATTERN (insn));
 
          insn = PREV_INSN (insn);
@@ -3441,9 +3515,8 @@ make_insn_raw (rtx pattern)
   INSN_UID (insn) = cur_insn_uid++;
   PATTERN (insn) = pattern;
   INSN_CODE (insn) = -1;
-  LOG_LINKS (insn) = NULL;
   REG_NOTES (insn) = NULL;
-  INSN_LOCATOR (insn) = 0;
+  INSN_LOCATOR (insn) = curr_insn_locator ();
   BLOCK_FOR_INSN (insn) = NULL;
 
 #ifdef ENABLE_RTL_CHECKING
@@ -3453,7 +3526,7 @@ make_insn_raw (rtx pattern)
          || (GET_CODE (insn) == SET
              && SET_DEST (insn) == pc_rtx)))
     {
-      warning ("ICE: emit_insn used where emit_jump_insn needed:\n");
+      warning (0, "ICE: emit_insn used where emit_jump_insn needed:\n");
       debug_rtx (insn);
     }
 #endif
@@ -3463,7 +3536,7 @@ make_insn_raw (rtx pattern)
 
 /* Like `make_insn_raw' but make a JUMP_INSN instead of an insn.  */
 
-static rtx
+rtx
 make_jump_insn_raw (rtx pattern)
 {
   rtx insn;
@@ -3473,10 +3546,9 @@ make_jump_insn_raw (rtx pattern)
 
   PATTERN (insn) = pattern;
   INSN_CODE (insn) = -1;
-  LOG_LINKS (insn) = NULL;
   REG_NOTES (insn) = NULL;
   JUMP_LABEL (insn) = NULL;
-  INSN_LOCATOR (insn) = 0;
+  INSN_LOCATOR (insn) = curr_insn_locator ();
   BLOCK_FOR_INSN (insn) = NULL;
 
   return insn;
@@ -3494,10 +3566,9 @@ make_call_insn_raw (rtx pattern)
 
   PATTERN (insn) = pattern;
   INSN_CODE (insn) = -1;
-  LOG_LINKS (insn) = NULL;
   REG_NOTES (insn) = NULL;
   CALL_INSN_FUNCTION_USAGE (insn) = NULL;
-  INSN_LOCATOR (insn) = 0;
+  INSN_LOCATOR (insn) = curr_insn_locator ();
   BLOCK_FOR_INSN (insn) = NULL;
 
   return insn;
@@ -3527,13 +3598,11 @@ add_insn (rtx insn)
    SEQUENCE.  */
 
 void
-add_insn_after (rtx insn, rtx after)
+add_insn_after (rtx insn, rtx after, basic_block bb)
 {
   rtx next = NEXT_INSN (after);
-  basic_block bb;
 
-  if (optimize && INSN_DELETED_P (after))
-    abort ();
+  gcc_assert (!optimize || !INSN_DELETED_P (after));
 
   NEXT_INSN (insn) = next;
   PREV_INSN (insn) = after;
@@ -3541,7 +3610,7 @@ add_insn_after (rtx insn, rtx after)
   if (next)
     {
       PREV_INSN (next) = insn;
-      if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE)
+      if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
        PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = insn;
     }
   else if (last_insn == after)
@@ -3557,29 +3626,27 @@ add_insn_after (rtx insn, rtx after)
            break;
          }
 
-      if (stack == 0)
-       abort ();
+      gcc_assert (stack);
     }
 
-  if (GET_CODE (after) != BARRIER
-      && GET_CODE (insn) != BARRIER
+  if (!BARRIER_P (after)
+      && !BARRIER_P (insn)
       && (bb = BLOCK_FOR_INSN (after)))
     {
       set_block_for_insn (insn, bb);
       if (INSN_P (insn))
-       bb->flags |= BB_DIRTY;
+       df_insn_rescan (insn);
       /* Should not happen as first in the BB is always
         either NOTE or LABEL.  */
-      if (bb->end == after
+      if (BB_END (bb) == after
          /* Avoid clobbering of structure when creating new BB.  */
-         && GET_CODE (insn) != BARRIER
-         && (GET_CODE (insn) != NOTE
-             || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK))
-       bb->end = insn;
+         && !BARRIER_P (insn)
+         && !NOTE_INSN_BASIC_BLOCK_P (insn))
+       BB_END (bb) = insn;
     }
 
   NEXT_INSN (after) = insn;
-  if (GET_CODE (after) == INSN && GET_CODE (PATTERN (after)) == SEQUENCE)
+  if (NONJUMP_INSN_P (after) && GET_CODE (PATTERN (after)) == SEQUENCE)
     {
       rtx sequence = PATTERN (after);
       NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn;
@@ -3587,18 +3654,17 @@ add_insn_after (rtx insn, rtx after)
 }
 
 /* Add INSN into the doubly-linked list before insn BEFORE.  This and
-   the previous should be the only functions called to insert an insn once
-   delay slots have been filled since only they know how to update a
-   SEQUENCE.  */
+   the previous should be the only functions called to insert an insn
+   once delay slots have been filled since only they know how to
+   update a SEQUENCE.  If BB is NULL, an attempt is made to infer the
+   bb from before.  */
 
 void
-add_insn_before (rtx insn, rtx before)
+add_insn_before (rtx insn, rtx before, basic_block bb)
 {
   rtx prev = PREV_INSN (before);
-  basic_block bb;
 
-  if (optimize && INSN_DELETED_P (before))
-    abort ();
+  gcc_assert (!optimize || !INSN_DELETED_P (before));
 
   PREV_INSN (insn) = prev;
   NEXT_INSN (insn) = before;
@@ -3606,7 +3672,7 @@ add_insn_before (rtx insn, rtx before)
   if (prev)
     {
       NEXT_INSN (prev) = insn;
-      if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
+      if (NONJUMP_INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE)
        {
          rtx sequence = PATTERN (prev);
          NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn;
@@ -3625,32 +3691,44 @@ add_insn_before (rtx insn, rtx before)
            break;
          }
 
-      if (stack == 0)
-       abort ();
+      gcc_assert (stack);
     }
 
-  if (GET_CODE (before) != BARRIER
-      && GET_CODE (insn) != BARRIER
-      && (bb = BLOCK_FOR_INSN (before)))
+  if (!bb 
+      && !BARRIER_P (before)
+      && !BARRIER_P (insn))
+    bb = BLOCK_FOR_INSN (before);
+
+  if (bb)
     {
       set_block_for_insn (insn, bb);
       if (INSN_P (insn))
-       bb->flags |= BB_DIRTY;
-      /* Should not happen as first in the BB is always
-        either NOTE or LABEl.  */
-      if (bb->head == insn
-         /* Avoid clobbering of structure when creating new BB.  */
-         && GET_CODE (insn) != BARRIER
-         && (GET_CODE (insn) != NOTE
-             || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK))
-       abort ();
+       df_insn_rescan (insn);
+      /* Should not happen as first in the BB is always either NOTE or
+        LABEL.  */
+      gcc_assert (BB_HEAD (bb) != insn
+                 /* Avoid clobbering of structure when creating new BB.  */
+                 || BARRIER_P (insn)
+                 || NOTE_INSN_BASIC_BLOCK_P (insn));
     }
 
   PREV_INSN (before) = insn;
-  if (GET_CODE (before) == INSN && GET_CODE (PATTERN (before)) == SEQUENCE)
+  if (NONJUMP_INSN_P (before) && GET_CODE (PATTERN (before)) == SEQUENCE)
     PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn;
 }
 
+
+/* Replace insn with an deleted instruction note.  */
+
+void
+set_insn_deleted (rtx insn)
+{
+  df_insn_delete (BLOCK_FOR_INSN (insn), INSN_UID (insn));
+  PUT_CODE (insn, NOTE);
+  NOTE_KIND (insn) = NOTE_INSN_DELETED;
+}
+
+
 /* Remove an insn from its doubly-linked list.  This function knows how
    to handle sequences.  */
 void
@@ -3660,10 +3738,13 @@ remove_insn (rtx insn)
   rtx prev = PREV_INSN (insn);
   basic_block bb;
 
+  /* Later in the code, the block will be marked dirty.  */
+  df_insn_delete (NULL, INSN_UID (insn));
+
   if (prev)
     {
       NEXT_INSN (prev) = next;
-      if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
+      if (NONJUMP_INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE)
        {
          rtx sequence = PATTERN (prev);
          NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = next;
@@ -3682,14 +3763,13 @@ remove_insn (rtx insn)
            break;
          }
 
-      if (stack == 0)
-       abort ();
+      gcc_assert (stack);
     }
 
   if (next)
     {
       PREV_INSN (next) = prev;
-      if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE)
+      if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
        PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = prev;
     }
   else if (last_insn == insn)
@@ -3705,24 +3785,22 @@ remove_insn (rtx insn)
            break;
          }
 
-      if (stack == 0)
-       abort ();
+      gcc_assert (stack);
     }
-  if (GET_CODE (insn) != BARRIER
+  if (!BARRIER_P (insn)
       && (bb = BLOCK_FOR_INSN (insn)))
     {
       if (INSN_P (insn))
-       bb->flags |= BB_DIRTY;
-      if (bb->head == insn)
+       df_set_bb_dirty (bb);
+      if (BB_HEAD (bb) == insn)
        {
          /* Never ever delete the basic block note without deleting whole
             basic block.  */
-         if (GET_CODE (insn) == NOTE)
-           abort ();
-         bb->head = next;
+         gcc_assert (!NOTE_P (insn));
+         BB_HEAD (bb) = next;
        }
-      if (bb->end == insn)
-       bb->end = prev;
+      if (BB_END (bb) == insn)
+       BB_END (bb) = prev;
     }
 }
 
@@ -3731,8 +3809,7 @@ remove_insn (rtx insn)
 void
 add_function_usage_to (rtx call_insn, rtx call_fusage)
 {
-  if (! call_insn || GET_CODE (call_insn) != CALL_INSN)
-    abort ();
+  gcc_assert (call_insn && CALL_P (call_insn));
 
   /* Put the register usage information on the CALL.  If there is already
      some usage information, put ours at the end.  */
@@ -3806,175 +3883,27 @@ reorder_insns (rtx from, rtx to, rtx after)
 
   reorder_insns_nobb (from, to, after);
 
-  if (GET_CODE (after) != BARRIER
+  if (!BARRIER_P (after)
       && (bb = BLOCK_FOR_INSN (after)))
     {
       rtx x;
-      bb->flags |= BB_DIRTY;
+      df_set_bb_dirty (bb);
 
-      if (GET_CODE (from) != BARRIER
+      if (!BARRIER_P (from)
          && (bb2 = BLOCK_FOR_INSN (from)))
        {
-         if (bb2->end == to)
-           bb2->end = prev;
-         bb2->flags |= BB_DIRTY;
+         if (BB_END (bb2) == to)
+           BB_END (bb2) = prev;
+         df_set_bb_dirty (bb2);
        }
 
-      if (bb->end == after)
-       bb->end = to;
+      if (BB_END (bb) == after)
+       BB_END (bb) = to;
 
       for (x = from; x != NEXT_INSN (to); x = NEXT_INSN (x))
-       set_block_for_insn (x, bb);
-    }
-}
-
-/* Return the line note insn preceding INSN.  */
-
-static rtx
-find_line_note (rtx insn)
-{
-  if (no_line_numbers)
-    return 0;
-
-  for (; insn; insn = PREV_INSN (insn))
-    if (GET_CODE (insn) == NOTE
-       && NOTE_LINE_NUMBER (insn) >= 0)
-      break;
-
-  return insn;
-}
-
-/* Like reorder_insns, but inserts line notes to preserve the line numbers
-   of the moved insns when debugging.  This may insert a note between AFTER
-   and FROM, and another one after TO.  */
-
-void
-reorder_insns_with_line_notes (rtx from, rtx to, rtx after)
-{
-  rtx from_line = find_line_note (from);
-  rtx after_line = find_line_note (after);
-
-  reorder_insns (from, to, after);
-
-  if (from_line == after_line)
-    return;
-
-  if (from_line)
-    emit_note_copy_after (from_line, after);
-  if (after_line)
-    emit_note_copy_after (after_line, to);
-}
-
-/* Remove unnecessary notes from the instruction stream.  */
-
-void
-remove_unnecessary_notes (void)
-{
-  rtx block_stack = NULL_RTX;
-  rtx eh_stack = NULL_RTX;
-  rtx insn;
-  rtx next;
-  rtx tmp;
-
-  /* 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;
-
-      switch (NOTE_LINE_NUMBER (insn))
-       {
-       case NOTE_INSN_DELETED:
-       case NOTE_INSN_LOOP_END_TOP_COND:
-         remove_insn (insn);
-         break;
-
-       case NOTE_INSN_EH_REGION_BEG:
-         eh_stack = alloc_INSN_LIST (insn, eh_stack);
-         break;
-
-       case NOTE_INSN_EH_REGION_END:
-         /* Too many end notes.  */
-         if (eh_stack == NULL_RTX)
-           abort ();
-         /* Mismatched nesting.  */
-         if (NOTE_EH_HANDLER (XEXP (eh_stack, 0)) != NOTE_EH_HANDLER (insn))
-           abort ();
-         tmp = eh_stack;
-         eh_stack = XEXP (eh_stack, 1);
-         free_INSN_LIST_node (tmp);
-         break;
-
-       case NOTE_INSN_BLOCK_BEG:
-         /* By now, all notes indicating lexical blocks should have
-            NOTE_BLOCK filled in.  */
-         if (NOTE_BLOCK (insn) == NULL_TREE)
-           abort ();
-         block_stack = alloc_INSN_LIST (insn, block_stack);
-         break;
-
-       case NOTE_INSN_BLOCK_END:
-         /* Too many end notes.  */
-         if (block_stack == NULL_RTX)
-           abort ();
-         /* Mismatched nesting.  */
-         if (NOTE_BLOCK (XEXP (block_stack, 0)) != NOTE_BLOCK (insn))
-           abort ();
-         tmp = block_stack;
-         block_stack = XEXP (block_stack, 1);
-         free_INSN_LIST_node (tmp);
-
-         /* 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.  */
-         for (tmp = PREV_INSN (insn); tmp; tmp = PREV_INSN (tmp))
-           {
-             /* 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 (INSN_P (tmp))
-               break;
-
-             /* We're only interested in NOTEs.  */
-             if (GET_CODE (tmp) != NOTE)
-               continue;
-
-             if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_BEG)
-               {
-                 /* We just verified that this BLOCK matches us with
-                    the block_stack check above.  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_hooks->ignore_block) (NOTE_BLOCK (insn)))
-                   {
-                     remove_insn (tmp);
-                     remove_insn (insn);
-                   }
-                 break;
-               }
-             else if (NOTE_LINE_NUMBER (tmp) == 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;
-           }
-       }
+       if (!BARRIER_P (x))
+         df_insn_change_bb (x, bb);
     }
-
-  /* Too many begin notes.  */
-  if (block_stack || eh_stack)
-    abort ();
 }
 
 \f
@@ -4006,15 +3935,12 @@ remove_unnecessary_notes (void)
 /* Make X be output before the instruction BEFORE.  */
 
 rtx
-emit_insn_before (rtx x, rtx before)
+emit_insn_before_noloc (rtx x, rtx before, basic_block bb)
 {
   rtx last = before;
   rtx insn;
 
-#ifdef ENABLE_RTL_CHECKING
-  if (before == NULL_RTX)
-    abort ();
-#endif
+  gcc_assert (before);
 
   if (x == NULL_RTX)
     return last;
@@ -4031,7 +3957,7 @@ emit_insn_before (rtx x, rtx before)
       while (insn)
        {
          rtx next = NEXT_INSN (insn);
-         add_insn_before (insn, before);
+         add_insn_before (insn, before, bb);
          last = insn;
          insn = next;
        }
@@ -4039,13 +3965,13 @@ emit_insn_before (rtx x, rtx before)
 
 #ifdef ENABLE_RTL_CHECKING
     case SEQUENCE:
-      abort ();
+      gcc_unreachable ();
       break;
 #endif
 
     default:
       last = make_insn_raw (x);
-      add_insn_before (last, before);
+      add_insn_before (last, before, bb);
       break;
     }
 
@@ -4056,14 +3982,11 @@ emit_insn_before (rtx x, rtx before)
    and output it before the instruction BEFORE.  */
 
 rtx
-emit_jump_insn_before (rtx x, rtx before)
+emit_jump_insn_before_noloc (rtx x, rtx before)
 {
   rtx insn, last = NULL_RTX;
 
-#ifdef ENABLE_RTL_CHECKING
-  if (before == NULL_RTX)
-    abort ();
-#endif
+  gcc_assert (before);
 
   switch (GET_CODE (x))
     {
@@ -4077,7 +4000,7 @@ emit_jump_insn_before (rtx x, rtx before)
       while (insn)
        {
          rtx next = NEXT_INSN (insn);
-         add_insn_before (insn, before);
+         add_insn_before (insn, before, NULL);
          last = insn;
          insn = next;
        }
@@ -4085,13 +4008,13 @@ emit_jump_insn_before (rtx x, rtx before)
 
 #ifdef ENABLE_RTL_CHECKING
     case SEQUENCE:
-      abort ();
+      gcc_unreachable ();
       break;
 #endif
 
     default:
       last = make_jump_insn_raw (x);
-      add_insn_before (last, before);
+      add_insn_before (last, before, NULL);
       break;
     }
 
@@ -4102,14 +4025,11 @@ emit_jump_insn_before (rtx x, rtx before)
    and output it before the instruction BEFORE.  */
 
 rtx
-emit_call_insn_before (rtx x, rtx before)
+emit_call_insn_before_noloc (rtx x, rtx before)
 {
   rtx last = NULL_RTX, insn;
 
-#ifdef ENABLE_RTL_CHECKING
-  if (before == NULL_RTX)
-    abort ();
-#endif
+  gcc_assert (before);
 
   switch (GET_CODE (x))
     {
@@ -4123,7 +4043,7 @@ emit_call_insn_before (rtx x, rtx before)
       while (insn)
        {
          rtx next = NEXT_INSN (insn);
-         add_insn_before (insn, before);
+         add_insn_before (insn, before, NULL);
          last = insn;
          insn = next;
        }
@@ -4131,13 +4051,13 @@ emit_call_insn_before (rtx x, rtx before)
 
 #ifdef ENABLE_RTL_CHECKING
     case SEQUENCE:
-      abort ();
+      gcc_unreachable ();
       break;
 #endif
 
     default:
       last = make_call_insn_raw (x);
-      add_insn_before (last, before);
+      add_insn_before (last, before, NULL);
       break;
     }
 
@@ -4154,7 +4074,7 @@ emit_barrier_before (rtx before)
 
   INSN_UID (insn) = cur_insn_uid++;
 
-  add_insn_before (insn, before);
+  add_insn_before (insn, before, NULL);
   return insn;
 }
 
@@ -4168,7 +4088,7 @@ emit_label_before (rtx label, rtx before)
   if (INSN_UID (label) == 0)
     {
       INSN_UID (label) = cur_insn_uid++;
-      add_insn_before (label, before);
+      add_insn_before (label, before, NULL);
     }
 
   return label;
@@ -4177,41 +4097,45 @@ emit_label_before (rtx label, rtx before)
 /* Emit a note of subtype SUBTYPE before the insn BEFORE.  */
 
 rtx
-emit_note_before (int subtype, rtx before)
+emit_note_before (enum insn_note subtype, rtx before)
 {
   rtx note = rtx_alloc (NOTE);
   INSN_UID (note) = cur_insn_uid++;
-  NOTE_SOURCE_FILE (note) = 0;
-  NOTE_LINE_NUMBER (note) = subtype;
+  NOTE_KIND (note) = subtype;
   BLOCK_FOR_INSN (note) = NULL;
+  memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note)));
 
-  add_insn_before (note, before);
+  add_insn_before (note, before, NULL);
   return note;
 }
 \f
 /* Helper for emit_insn_after, handles lists of instructions
    efficiently.  */
 
-static rtx emit_insn_after_1 (rtx, rtx);
-
 static rtx
-emit_insn_after_1 (rtx first, rtx after)
+emit_insn_after_1 (rtx first, rtx after, basic_block bb)
 {
   rtx last;
   rtx after_after;
-  basic_block bb;
+  if (!bb && !BARRIER_P (after))
+    bb = BLOCK_FOR_INSN (after);
 
-  if (GET_CODE (after) != BARRIER
-      && (bb = BLOCK_FOR_INSN (after)))
+  if (bb)
     {
-      bb->flags |= BB_DIRTY;
+      df_set_bb_dirty (bb);
       for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
-       if (GET_CODE (last) != BARRIER)
+       if (!BARRIER_P (last))
+         {
+           set_block_for_insn (last, bb);
+           df_insn_rescan (last);
+         }
+      if (!BARRIER_P (last))
+       {
          set_block_for_insn (last, bb);
-      if (GET_CODE (last) != BARRIER)
-       set_block_for_insn (last, bb);
-      if (bb->end == after)
-       bb->end = last;
+         df_insn_rescan (last);
+       }
+      if (BB_END (bb) == after)
+       BB_END (bb) = last;
     }
   else
     for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
@@ -4227,20 +4151,19 @@ emit_insn_after_1 (rtx first, rtx after)
 
   if (after == last_insn)
     last_insn = last;
+
   return last;
 }
 
-/* Make X be output after the insn AFTER.  */
+/* Make X be output after the insn AFTER and set the BB of insn.  If
+   BB is NULL, an attempt is made to infer the BB from AFTER.  */
 
 rtx
-emit_insn_after (rtx x, rtx after)
+emit_insn_after_noloc (rtx x, rtx after, basic_block bb)
 {
   rtx last = after;
 
-#ifdef ENABLE_RTL_CHECKING
-  if (after == NULL_RTX)
-    abort ();
-#endif
+  gcc_assert (after);
 
   if (x == NULL_RTX)
     return last;
@@ -4253,53 +4176,34 @@ emit_insn_after (rtx x, rtx after)
     case CODE_LABEL:
     case BARRIER:
     case NOTE:
-      last = emit_insn_after_1 (x, after);
+      last = emit_insn_after_1 (x, after, bb);
       break;
 
 #ifdef ENABLE_RTL_CHECKING
     case SEQUENCE:
-      abort ();
+      gcc_unreachable ();
       break;
 #endif
 
     default:
       last = make_insn_raw (x);
-      add_insn_after (last, after);
+      add_insn_after (last, after, bb);
       break;
     }
 
   return last;
 }
 
-/* Similar to emit_insn_after, except that line notes are to be inserted so
-   as to act as if this insn were at FROM.  */
-
-void
-emit_insn_after_with_line_notes (rtx x, rtx after, rtx from)
-{
-  rtx from_line = find_line_note (from);
-  rtx after_line = find_line_note (after);
-  rtx insn = emit_insn_after (x, after);
-
-  if (from_line)
-    emit_note_copy_after (from_line, after);
-
-  if (after_line)
-    emit_note_copy_after (after_line, insn);
-}
 
 /* Make an insn of code JUMP_INSN with body X
    and output it after the insn AFTER.  */
 
 rtx
-emit_jump_insn_after (rtx x, rtx after)
+emit_jump_insn_after_noloc (rtx x, rtx after)
 {
   rtx last;
 
-#ifdef ENABLE_RTL_CHECKING
-  if (after == NULL_RTX)
-    abort ();
-#endif
+  gcc_assert (after);
 
   switch (GET_CODE (x))
     {
@@ -4309,18 +4213,18 @@ emit_jump_insn_after (rtx x, rtx after)
     case CODE_LABEL:
     case BARRIER:
     case NOTE:
-      last = emit_insn_after_1 (x, after);
+      last = emit_insn_after_1 (x, after, NULL);
       break;
 
 #ifdef ENABLE_RTL_CHECKING
     case SEQUENCE:
-      abort ();
+      gcc_unreachable ();
       break;
 #endif
 
     default:
       last = make_jump_insn_raw (x);
-      add_insn_after (last, after);
+      add_insn_after (last, after, NULL);
       break;
     }
 
@@ -4331,14 +4235,11 @@ emit_jump_insn_after (rtx x, rtx after)
    and output it after the instruction AFTER.  */
 
 rtx
-emit_call_insn_after (rtx x, rtx after)
+emit_call_insn_after_noloc (rtx x, rtx after)
 {
   rtx last;
 
-#ifdef ENABLE_RTL_CHECKING
-  if (after == NULL_RTX)
-    abort ();
-#endif
+  gcc_assert (after);
 
   switch (GET_CODE (x))
     {
@@ -4348,18 +4249,18 @@ emit_call_insn_after (rtx x, rtx after)
     case CODE_LABEL:
     case BARRIER:
     case NOTE:
-      last = emit_insn_after_1 (x, after);
+      last = emit_insn_after_1 (x, after, NULL);
       break;
 
 #ifdef ENABLE_RTL_CHECKING
     case SEQUENCE:
-      abort ();
+      gcc_unreachable ();
       break;
 #endif
 
     default:
       last = make_call_insn_raw (x);
-      add_insn_after (last, after);
+      add_insn_after (last, after, NULL);
       break;
     }
 
@@ -4376,7 +4277,7 @@ emit_barrier_after (rtx after)
 
   INSN_UID (insn) = cur_insn_uid++;
 
-  add_insn_after (insn, after);
+  add_insn_after (insn, after, NULL);
   return insn;
 }
 
@@ -4391,7 +4292,7 @@ emit_label_after (rtx label, rtx after)
   if (INSN_UID (label) == 0)
     {
       INSN_UID (label) = cur_insn_uid++;
-      add_insn_after (label, after);
+      add_insn_after (label, after, NULL);
     }
 
   return label;
@@ -4400,49 +4301,30 @@ emit_label_after (rtx label, rtx after)
 /* Emit a note of subtype SUBTYPE after the insn AFTER.  */
 
 rtx
-emit_note_after (int subtype, rtx after)
+emit_note_after (enum insn_note subtype, rtx after)
 {
   rtx note = rtx_alloc (NOTE);
   INSN_UID (note) = cur_insn_uid++;
-  NOTE_SOURCE_FILE (note) = 0;
-  NOTE_LINE_NUMBER (note) = subtype;
-  BLOCK_FOR_INSN (note) = NULL;
-  add_insn_after (note, after);
-  return note;
-}
-
-/* Emit a copy of note ORIG after the insn AFTER.  */
-
-rtx
-emit_note_copy_after (rtx orig, rtx after)
-{
-  rtx note;
-
-  if (NOTE_LINE_NUMBER (orig) >= 0 && no_line_numbers)
-    {
-      cur_insn_uid++;
-      return 0;
-    }
-
-  note = rtx_alloc (NOTE);
-  INSN_UID (note) = cur_insn_uid++;
-  NOTE_LINE_NUMBER (note) = NOTE_LINE_NUMBER (orig);
-  NOTE_DATA (note) = NOTE_DATA (orig);
+  NOTE_KIND (note) = subtype;
   BLOCK_FOR_INSN (note) = NULL;
-  add_insn_after (note, after);
+  memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note)));
+  add_insn_after (note, after, NULL);
   return note;
 }
 \f
-/* Like emit_insn_after, but set INSN_LOCATOR according to SCOPE.  */
+/* Like emit_insn_after_noloc, but set INSN_LOCATOR according to SCOPE.  */
 rtx
 emit_insn_after_setloc (rtx pattern, rtx after, int loc)
 {
-  rtx last = emit_insn_after (pattern, after);
+  rtx last = emit_insn_after_noloc (pattern, after, NULL);
+
+  if (pattern == NULL_RTX || !loc)
+    return last;
 
   after = NEXT_INSN (after);
   while (1)
     {
-      if (active_insn_p (after))
+      if (active_insn_p (after) && !INSN_LOCATOR (after))
        INSN_LOCATOR (after) = loc;
       if (after == last)
        break;
@@ -4451,16 +4333,29 @@ emit_insn_after_setloc (rtx pattern, rtx after, int loc)
   return last;
 }
 
-/* Like emit_jump_insn_after, but set INSN_LOCATOR according to SCOPE.  */
+/* Like emit_insn_after_noloc, but set INSN_LOCATOR according to AFTER.  */
+rtx
+emit_insn_after (rtx pattern, rtx after)
+{
+  if (INSN_P (after))
+    return emit_insn_after_setloc (pattern, after, INSN_LOCATOR (after));
+  else
+    return emit_insn_after_noloc (pattern, after, NULL);
+}
+
+/* Like emit_jump_insn_after_noloc, but set INSN_LOCATOR according to SCOPE.  */
 rtx
 emit_jump_insn_after_setloc (rtx pattern, rtx after, int loc)
 {
-  rtx last = emit_jump_insn_after (pattern, after);
+  rtx last = emit_jump_insn_after_noloc (pattern, after);
+
+  if (pattern == NULL_RTX || !loc)
+    return last;
 
   after = NEXT_INSN (after);
   while (1)
     {
-      if (active_insn_p (after))
+      if (active_insn_p (after) && !INSN_LOCATOR (after))
        INSN_LOCATOR (after) = loc;
       if (after == last)
        break;
@@ -4469,16 +4364,29 @@ emit_jump_insn_after_setloc (rtx pattern, rtx after, int loc)
   return last;
 }
 
-/* Like emit_call_insn_after, but set INSN_LOCATOR according to SCOPE.  */
+/* Like emit_jump_insn_after_noloc, but set INSN_LOCATOR according to AFTER.  */
+rtx
+emit_jump_insn_after (rtx pattern, rtx after)
+{
+  if (INSN_P (after))
+    return emit_jump_insn_after_setloc (pattern, after, INSN_LOCATOR (after));
+  else
+    return emit_jump_insn_after_noloc (pattern, after);
+}
+
+/* Like emit_call_insn_after_noloc, but set INSN_LOCATOR according to SCOPE.  */
 rtx
 emit_call_insn_after_setloc (rtx pattern, rtx after, int loc)
 {
-  rtx last = emit_call_insn_after (pattern, after);
+  rtx last = emit_call_insn_after_noloc (pattern, after);
+
+  if (pattern == NULL_RTX || !loc)
+    return last;
 
   after = NEXT_INSN (after);
   while (1)
     {
-      if (active_insn_p (after))
+      if (active_insn_p (after) && !INSN_LOCATOR (after))
        INSN_LOCATOR (after) = loc;
       if (after == last)
        break;
@@ -4487,17 +4395,97 @@ emit_call_insn_after_setloc (rtx pattern, rtx after, int loc)
   return last;
 }
 
-/* Like emit_insn_before, but set INSN_LOCATOR according to SCOPE.  */
+/* Like emit_call_insn_after_noloc, but set INSN_LOCATOR according to AFTER.  */
+rtx
+emit_call_insn_after (rtx pattern, rtx after)
+{
+  if (INSN_P (after))
+    return emit_call_insn_after_setloc (pattern, after, INSN_LOCATOR (after));
+  else
+    return emit_call_insn_after_noloc (pattern, after);
+}
+
+/* Like emit_insn_before_noloc, but set INSN_LOCATOR according to SCOPE.  */
 rtx
 emit_insn_before_setloc (rtx pattern, rtx before, int loc)
 {
   rtx first = PREV_INSN (before);
-  rtx last = emit_insn_before (pattern, before);
+  rtx last = emit_insn_before_noloc (pattern, before, NULL);
+
+  if (pattern == NULL_RTX || !loc)
+    return last;
+
+  if (!first)
+    first = get_insns ();
+  else
+    first = NEXT_INSN (first);
+  while (1)
+    {
+      if (active_insn_p (first) && !INSN_LOCATOR (first))
+       INSN_LOCATOR (first) = loc;
+      if (first == last)
+       break;
+      first = NEXT_INSN (first);
+    }
+  return last;
+}
+
+/* Like emit_insn_before_noloc, but set INSN_LOCATOR according to BEFORE.  */
+rtx
+emit_insn_before (rtx pattern, rtx before)
+{
+  if (INSN_P (before))
+    return emit_insn_before_setloc (pattern, before, INSN_LOCATOR (before));
+  else
+    return emit_insn_before_noloc (pattern, before, NULL);
+}
+
+/* like emit_insn_before_noloc, but set insn_locator according to scope.  */
+rtx
+emit_jump_insn_before_setloc (rtx pattern, rtx before, int loc)
+{
+  rtx first = PREV_INSN (before);
+  rtx last = emit_jump_insn_before_noloc (pattern, before);
+
+  if (pattern == NULL_RTX)
+    return last;
+
+  first = NEXT_INSN (first);
+  while (1)
+    {
+      if (active_insn_p (first) && !INSN_LOCATOR (first))
+       INSN_LOCATOR (first) = loc;
+      if (first == last)
+       break;
+      first = NEXT_INSN (first);
+    }
+  return last;
+}
+
+/* Like emit_jump_insn_before_noloc, but set INSN_LOCATOR according to BEFORE.  */
+rtx
+emit_jump_insn_before (rtx pattern, rtx before)
+{
+  if (INSN_P (before))
+    return emit_jump_insn_before_setloc (pattern, before, INSN_LOCATOR (before));
+  else
+    return emit_jump_insn_before_noloc (pattern, before);
+}
+
+/* like emit_insn_before_noloc, but set insn_locator according to scope.  */
+rtx
+emit_call_insn_before_setloc (rtx pattern, rtx before, int loc)
+{
+  rtx first = PREV_INSN (before);
+  rtx last = emit_call_insn_before_noloc (pattern, before);
+
+  if (pattern == NULL_RTX)
+    return last;
 
   first = NEXT_INSN (first);
   while (1)
     {
-      if (active_insn_p (first))
+      if (active_insn_p (first) && !INSN_LOCATOR (first))
        INSN_LOCATOR (first) = loc;
       if (first == last)
        break;
@@ -4505,6 +4493,17 @@ emit_insn_before_setloc (rtx pattern, rtx before, int loc)
     }
   return last;
 }
+
+/* like emit_call_insn_before_noloc,
+   but set insn_locator according to before.  */
+rtx
+emit_call_insn_before (rtx pattern, rtx before)
+{
+  if (INSN_P (before))
+    return emit_call_insn_before_setloc (pattern, before, INSN_LOCATOR (before));
+  else
+    return emit_call_insn_before_noloc (pattern, before);
+}
 \f
 /* Take X and emit it at the end of the doubly-linked
    INSN list.
@@ -4540,7 +4539,7 @@ emit_insn (rtx x)
 
 #ifdef ENABLE_RTL_CHECKING
     case SEQUENCE:
-      abort ();
+      gcc_unreachable ();
       break;
 #endif
 
@@ -4581,7 +4580,7 @@ emit_jump_insn (rtx x)
 
 #ifdef ENABLE_RTL_CHECKING
     case SEQUENCE:
-      abort ();
+      gcc_unreachable ();
       break;
 #endif
 
@@ -4615,7 +4614,7 @@ emit_call_insn (rtx x)
 
 #ifdef ENABLE_RTL_CHECKING
     case SEQUENCE:
-      abort ();
+      gcc_unreachable ();
       break;
 #endif
 
@@ -4656,35 +4655,6 @@ emit_barrier (void)
   return barrier;
 }
 
-/* Make line numbering NOTE insn for LOCATION add it to the end
-   of the doubly-linked list, but only if line-numbers are desired for
-   debugging info and it doesn't match the previous one.  */
-
-rtx
-emit_line_note (location_t location)
-{
-  rtx note;
-  
-  set_file_and_line_for_stmt (location);
-  
-  if (location.file && last_location.file
-      && !strcmp (location.file, last_location.file)
-      && location.line == last_location.line)
-    return NULL_RTX;
-  last_location = location;
-  
-  if (no_line_numbers)
-    {
-      cur_insn_uid++;
-      return NULL_RTX;
-    }
-
-  note = emit_note (location.line);
-  NOTE_SOURCE_FILE (note) = location.file;
-  
-  return note;
-}
-
 /* Emit a copy of note ORIG.  */
 
 rtx
@@ -4692,17 +4662,11 @@ emit_note_copy (rtx orig)
 {
   rtx note;
   
-  if (NOTE_LINE_NUMBER (orig) >= 0 && no_line_numbers)
-    {
-      cur_insn_uid++;
-      return NULL_RTX;
-    }
-  
   note = rtx_alloc (NOTE);
   
   INSN_UID (note) = cur_insn_uid++;
   NOTE_DATA (note) = NOTE_DATA (orig);
-  NOTE_LINE_NUMBER (note) = NOTE_LINE_NUMBER (orig);
+  NOTE_KIND (note) = NOTE_KIND (orig);
   BLOCK_FOR_INSN (note) = NULL;
   add_insn (note);
   
@@ -4713,26 +4677,82 @@ emit_note_copy (rtx orig)
    and add it to the end of the doubly-linked list.  */
 
 rtx
-emit_note (int note_no)
+emit_note (enum insn_note kind)
 {
   rtx note;
 
   note = rtx_alloc (NOTE);
   INSN_UID (note) = cur_insn_uid++;
-  NOTE_LINE_NUMBER (note) = note_no;
+  NOTE_KIND (note) = kind;
   memset (&NOTE_DATA (note), 0, sizeof (NOTE_DATA (note)));
   BLOCK_FOR_INSN (note) = NULL;
   add_insn (note);
   return note;
 }
 
+/* Emit a clobber of lvalue X.  */
+
+rtx
+emit_clobber (rtx x)
+{
+  /* CONCATs should not appear in the insn stream.  */
+  if (GET_CODE (x) == CONCAT)
+    {
+      emit_clobber (XEXP (x, 0));
+      return emit_clobber (XEXP (x, 1));
+    }
+  return emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+}
+
+/* Return a sequence of insns to clobber lvalue X.  */
+
+rtx
+gen_clobber (rtx x)
+{
+  rtx seq;
+
+  start_sequence ();
+  emit_clobber (x);
+  seq = get_insns ();
+  end_sequence ();
+  return seq;
+}
+
+/* Emit a use of rvalue X.  */
+
+rtx
+emit_use (rtx x)
+{
+  /* CONCATs should not appear in the insn stream.  */
+  if (GET_CODE (x) == CONCAT)
+    {
+      emit_use (XEXP (x, 0));
+      return emit_use (XEXP (x, 1));
+    }
+  return emit_insn (gen_rtx_USE (VOIDmode, x));
+}
+
+/* Return a sequence of insns to use rvalue X.  */
+
+rtx
+gen_use (rtx x)
+{
+  rtx seq;
+
+  start_sequence ();
+  emit_use (x);
+  seq = get_insns ();
+  end_sequence ();
+  return seq;
+}
+
 /* Cause next statement to emit a line note even if the line number
    has not changed.  */
 
 void
 force_next_line_note (void)
 {
-  last_location.line = -1;
+  last_location = -1;
 }
 
 /* Place a note of KIND on insn INSN with DATUM as the datum. If a
@@ -4753,8 +4773,7 @@ set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum)
         means the insn only has one * useful * set).  */
       if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn))
        {
-         if (note)
-           abort ();
+         gcc_assert (!note);
          return NULL_RTX;
        }
 
@@ -4762,29 +4781,46 @@ set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum)
         It serves no useful purpose and breaks eliminate_regs.  */
       if (GET_CODE (datum) == ASM_OPERANDS)
        return NULL_RTX;
+
+      if (note)
+       {
+         XEXP (note, 0) = datum;
+         df_notes_rescan (insn);
+         return note;
+       }
       break;
 
     default:
+      if (note)
+       {
+         XEXP (note, 0) = datum;
+         return note;
+       }
       break;
     }
 
-  if (note)
+  add_reg_note (insn, kind, datum);
+
+  switch (kind)
     {
-      XEXP (note, 0) = datum;
-      return note;
+    case REG_EQUAL:
+    case REG_EQUIV:
+      df_notes_rescan (insn);
+      break;
+    default:
+      break;
     }
 
-  REG_NOTES (insn) = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
   return 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.  */
 
-enum rtx_code
+static enum rtx_code
 classify_insn (rtx x)
 {
-  if (GET_CODE (x) == CODE_LABEL)
+  if (LABEL_P (x))
     return CODE_LABEL;
   if (GET_CODE (x) == CALL)
     return CALL_INSN;
@@ -4823,33 +4859,35 @@ emit (rtx x)
 {
   enum rtx_code code = classify_insn (x);
 
-  if (code == CODE_LABEL)
-    return emit_label (x);
-  else if (code == INSN)
-    return emit_insn (x);
-  else if (code == JUMP_INSN)
+  switch (code)
     {
-      rtx insn = emit_jump_insn (x);
-      if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN)
-       return emit_barrier ();
-      return insn;
+    case CODE_LABEL:
+      return emit_label (x);
+    case INSN:
+      return emit_insn (x);
+    case  JUMP_INSN:
+      {
+       rtx insn = emit_jump_insn (x);
+       if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN)
+         return emit_barrier ();
+       return insn;
+      }
+    case CALL_INSN:
+      return emit_call_insn (x);
+    default:
+      gcc_unreachable ();
     }
-  else if (code == CALL_INSN)
-    return emit_call_insn (x);
-  else
-    abort ();
 }
 \f
 /* Space for free sequence stack entries.  */
-static GTY ((deletable (""))) struct sequence_stack *free_sequence_stack;
+static GTY ((deletable)) struct sequence_stack *free_sequence_stack;
 
-/* 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 middle of this sequence.  */
+/* Begin emitting insns to a sequence.  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 middle of this sequence.  */
 
 void
 start_sequence (void)
@@ -4862,12 +4900,11 @@ start_sequence (void)
       free_sequence_stack = tem->next;
     }
   else
-    tem = ggc_alloc (sizeof (struct sequence_stack));
+    tem = GGC_NEW (struct sequence_stack);
 
   tem->next = seq_stack;
   tem->first = first_insn;
   tem->last = last_insn;
-  tem->sequence_rtl_expr = seq_rtl_expr;
 
   seq_stack = tem;
 
@@ -4875,18 +4912,6 @@ start_sequence (void)
   last_insn = 0;
 }
 
-/* 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 (tree t)
-{
-  start_sequence ();
-
-  seq_rtl_expr = t;
-}
-
 /* 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.  */
@@ -4904,17 +4929,16 @@ push_to_sequence (rtx first)
   last_insn = last;
 }
 
-/* Set up the insn chain from a chain stort in FIRST to LAST.  */
+/* Like push_to_sequence, but take the last insn as an argument to avoid
+   looping through the list.  */
 
 void
-push_to_full_sequence (rtx first, rtx last)
+push_to_sequence2 (rtx first, rtx 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
@@ -4932,7 +4956,6 @@ push_topmost_sequence (void)
 
   first_insn = top->first;
   last_insn = top->last;
-  seq_rtl_expr = top->sequence_rtl_expr;
 }
 
 /* After emitting to the outer-level insn chain, update the outer-level
@@ -4948,7 +4971,6 @@ pop_topmost_sequence (void)
 
   top->first = first_insn;
   top->last = last_insn;
-  /* ??? Why don't we save seq_rtl_expr here?  */
 
   end_sequence ();
 }
@@ -4973,7 +4995,6 @@ end_sequence (void)
 
   first_insn = tem->first;
   last_insn = tem->last;
-  seq_rtl_expr = tem->sequence_rtl_expr;
   seq_stack = tem->next;
 
   memset (tem, 0, sizeof (*tem));
@@ -4981,17 +5002,6 @@ end_sequence (void)
   free_sequence_stack = tem;
 }
 
-/* This works like end_sequence, but records the old sequence in FIRST
-   and LAST.  */
-
-void
-end_full_sequence (rtx *first, rtx *last)
-{
-  *first = first_insn;
-  *last = last_insn;
-  end_sequence ();
-}
-
 /* Return 1 if currently emitting into a sequence.  */
 
 int
@@ -5002,15 +5012,14 @@ in_sequence_p (void)
 \f
 /* Put the various virtual registers into REGNO_REG_RTX.  */
 
-void
-init_virtual_regs (struct emit_status *es)
+static void
+init_virtual_regs (void)
 {
-  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;
+  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;
+  regno_reg_rtx[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx;
 }
 
 \f
@@ -5054,16 +5063,19 @@ copy_insn_1 (rtx orig)
   switch (code)
     {
     case REG:
-    case QUEUED:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case CODE_LABEL:
     case PC:
     case CC0:
-    case ADDRESSOF:
       return orig;
+    case CLOBBER:
+      if (REG_P (XEXP (orig, 0)) && REGNO (XEXP (orig, 0)) < FIRST_PSEUDO_REGISTER)
+       return orig;
+      break;
 
     case SCRATCH:
       for (i = 0; i < copy_insn_n_scratches; i++)
@@ -5072,11 +5084,7 @@ copy_insn_1 (rtx orig)
       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)
+      if (shared_const_p (orig))
        return orig;
       break;
 
@@ -5089,20 +5097,18 @@ copy_insn_1 (rtx orig)
       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
+  /* Copy the various flags, fields, 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, RTX_HDR_SIZE);
+  copy = shallow_copy_rtx (orig);
 
   /* We do not copy the USED flag, which is used as a mark bit during
      walks over the RTL.  */
   RTX_FLAG (copy, used) = 0;
 
   /* We do not copy JUMP, CALL, or FRAME_RELATED for INSNs.  */
-  if (GET_RTX_CLASS (code) == 'i')
+  if (INSN_P (orig))
     {
       RTX_FLAG (copy, jump) = 0;
       RTX_FLAG (copy, call) = 0;
@@ -5112,49 +5118,45 @@ copy_insn_1 (rtx orig)
   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
 
   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
-    {
-      copy->u.fld[i] = orig->u.fld[i];
-      switch (*format_ptr++)
-       {
-       case 'e':
-         if (XEXP (orig, i) != NULL)
-           XEXP (copy, i) = copy_insn_1 (XEXP (orig, i));
-         break;
+    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 '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 't':
-       case 'w':
-       case 'i':
-       case 's':
-       case 'S':
-       case 'u':
-       case '0':
-         /* These are left unchanged.  */
-         break;
+      case 't':
+      case 'w':
+      case 'i':
+      case 's':
+      case 'S':
+      case 'u':
+      case '0':
+       /* These are left unchanged.  */
+       break;
 
-       default:
-         abort ();
-       }
-    }
+      default:
+       gcc_unreachable ();
+      }
 
   if (code == SCRATCH)
     {
       i = copy_insn_n_scratches++;
-      if (i >= MAX_RECOG_OPERANDS)
-       abort ();
+      gcc_assert (i < MAX_RECOG_OPERANDS);
       copy_insn_scratch_in[i] = orig;
       copy_insn_scratch_out[i] = copy;
     }
@@ -5191,30 +5193,23 @@ copy_insn (rtx insn)
 void
 init_emit (void)
 {
-  struct function *f = cfun;
-
-  f->emit = ggc_alloc (sizeof (struct emit_status));
   first_insn = NULL;
   last_insn = NULL;
-  seq_rtl_expr = NULL;
   cur_insn_uid = 1;
   reg_rtx_no = LAST_VIRTUAL_REGISTER + 1;
-  last_location.line = 0;
-  last_location.file = 0;
+  last_location = UNKNOWN_LOCATION;
   first_label_num = label_num;
-  last_label_num = 0;
   seq_stack = NULL;
 
   /* Init the tables that describe all the pseudo regs.  */
 
-  f->emit->regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
+  crtl->emit.regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
 
-  f->emit->regno_pointer_align
-    = ggc_alloc_cleared (f->emit->regno_pointer_align_length
-                        * sizeof (unsigned char));
+  crtl->emit.regno_pointer_align
+    = XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length);
 
   regno_reg_rtx
-    = ggc_alloc (f->emit->regno_pointer_align_length * sizeof (rtx));
+    = GGC_NEWVEC (rtx, crtl->emit.regno_pointer_align_length);
 
   /* Put copies of all the hard registers into regno_reg_rtx.  */
   memcpy (regno_reg_rtx,
@@ -5222,7 +5217,7 @@ init_emit (void)
          FIRST_PSEUDO_REGISTER * sizeof (rtx));
 
   /* Put copies of all the virtual register rtx into regno_reg_rtx.  */
-  init_virtual_regs (f->emit);
+  init_virtual_regs ();
 
   /* Indicate that the virtual registers and stack locations are
      all pointers.  */
@@ -5255,10 +5250,10 @@ init_emit (void)
 #endif
 }
 
-/* Generate the constant 0.  */
+/* Generate a vector constant for mode MODE and constant value CONSTANT.  */
 
 static rtx
-gen_const_vector_0 (enum machine_mode mode)
+gen_const_vector (enum machine_mode mode, int constant)
 {
   rtx tem;
   rtvec v;
@@ -5268,31 +5263,116 @@ gen_const_vector_0 (enum machine_mode mode)
   units = GET_MODE_NUNITS (mode);
   inner = GET_MODE_INNER (mode);
 
+  gcc_assert (!DECIMAL_FLOAT_MODE_P (inner));
+
   v = rtvec_alloc (units);
 
-  /* We need to call this function after we to set CONST0_RTX first.  */
-  if (!CONST0_RTX (inner))
-    abort ();
+  /* We need to call this function after we set the scalar const_tiny_rtx
+     entries.  */
+  gcc_assert (const_tiny_rtx[constant][(int) inner]);
 
   for (i = 0; i < units; ++i)
-    RTVEC_ELT (v, i) = CONST0_RTX (inner);
+    RTVEC_ELT (v, i) = const_tiny_rtx[constant][(int) inner];
 
   tem = gen_rtx_raw_CONST_VECTOR (mode, v);
   return tem;
 }
 
 /* Generate a vector like gen_rtx_raw_CONST_VEC, but use the zero vector when
-   all elements are zero.  */
+   all elements are zero, and the one vector when all elements are one.  */
 rtx
 gen_rtx_CONST_VECTOR (enum machine_mode mode, rtvec v)
 {
-  rtx inner_zero = CONST0_RTX (GET_MODE_INNER (mode));
+  enum machine_mode inner = GET_MODE_INNER (mode);
+  int nunits = GET_MODE_NUNITS (mode);
+  rtx x;
+  int i;
+
+  /* Check to see if all of the elements have the same value.  */
+  x = RTVEC_ELT (v, nunits - 1);
+  for (i = nunits - 2; i >= 0; i--)
+    if (RTVEC_ELT (v, i) != x)
+      break;
+
+  /* If the values are all the same, check to see if we can use one of the
+     standard constant vectors.  */
+  if (i == -1)
+    {
+      if (x == CONST0_RTX (inner))
+       return CONST0_RTX (mode);
+      else if (x == CONST1_RTX (inner))
+       return CONST1_RTX (mode);
+    }
+
+  return gen_rtx_raw_CONST_VECTOR (mode, v);
+}
+
+/* Initialise global register information required by all functions.  */
+
+void
+init_emit_regs (void)
+{
   int i;
 
-  for (i = GET_MODE_NUNITS (mode) - 1; i >= 0; i--)
-    if (RTVEC_ELT (v, i) != inner_zero)
-      return gen_rtx_raw_CONST_VECTOR (mode, v);
-  return CONST0_RTX (mode);
+  /* Reset register attributes */
+  htab_empty (reg_attrs_htab);
+
+  /* We need reg_raw_mode, so initialize the modes now.  */
+  init_reg_modes_target ();
+
+  /* Assign register numbers to the globally defined register rtx.  */
+  pc_rtx = gen_rtx_PC (VOIDmode);
+  cc0_rtx = gen_rtx_CC0 (VOIDmode);
+  stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM);
+  frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);
+  hard_frame_pointer_rtx = gen_raw_REG (Pmode, HARD_FRAME_POINTER_REGNUM);
+  arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM);
+  virtual_incoming_args_rtx =
+    gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
+  virtual_stack_vars_rtx =
+    gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
+  virtual_stack_dynamic_rtx =
+    gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);
+  virtual_outgoing_args_rtx =
+    gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);
+  virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
+
+  /* Initialize RTL for commonly used hard registers.  These are
+     copied into regno_reg_rtx as we begin to compile each function.  */
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    static_regno_reg_rtx[i] = gen_raw_REG (reg_raw_mode[i], i);
+
+#ifdef RETURN_ADDRESS_POINTER_REGNUM
+  return_address_pointer_rtx
+    = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
+#endif
+
+#ifdef STATIC_CHAIN_REGNUM
+  static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+
+#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);
+  else
+#endif
+    static_chain_incoming_rtx = static_chain_rtx;
+#endif
+
+#ifdef STATIC_CHAIN
+  static_chain_rtx = STATIC_CHAIN;
+
+#ifdef STATIC_CHAIN_INCOMING
+  static_chain_incoming_rtx = STATIC_CHAIN_INCOMING;
+#else
+  static_chain_incoming_rtx = static_chain_rtx;
+#endif
+#endif
+
+  if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
+    pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
+  else
+    pic_offset_table_rtx = NULL_RTX;
 }
 
 /* Create some permanent unique rtl objects shared between all functions.
@@ -5305,17 +5385,17 @@ init_emit_once (int line_numbers)
   enum machine_mode mode;
   enum machine_mode double_mode;
 
-  /* We need reg_raw_mode, so initialize the modes now.  */
-  init_reg_modes_once ();
-
-  /* Initialize the CONST_INT, CONST_DOUBLE, and memory attribute hash
-     tables.  */
+  /* Initialize the CONST_INT, CONST_DOUBLE, CONST_FIXED, and memory attribute
+     hash tables.  */
   const_int_htab = htab_create_ggc (37, const_int_htab_hash,
                                    const_int_htab_eq, NULL);
 
   const_double_htab = htab_create_ggc (37, const_double_htab_hash,
                                       const_double_htab_eq, NULL);
 
+  const_fixed_htab = htab_create_ggc (37, const_fixed_htab_hash,
+                                     const_fixed_htab_eq, NULL);
+
   mem_attrs_htab = htab_create_ggc (37, mem_attrs_htab_hash,
                                    mem_attrs_htab_eq, NULL);
   reg_attrs_htab = htab_create_ggc (37, reg_attrs_htab_hash,
@@ -5329,7 +5409,8 @@ init_emit_once (int line_numbers)
   word_mode = VOIDmode;
   double_mode = VOIDmode;
 
-  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+       mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
       if (GET_MODE_BITSIZE (mode) == BITS_PER_UNIT
@@ -5341,7 +5422,8 @@ init_emit_once (int line_numbers)
        word_mode = mode;
     }
 
-  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+       mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
       if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE
@@ -5351,34 +5433,6 @@ init_emit_once (int line_numbers)
 
   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_raw_REG (Pmode, STACK_POINTER_REGNUM);
-  frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);
-  if (hard_frame_pointer_rtx == 0)
-    hard_frame_pointer_rtx = gen_raw_REG (Pmode,
-                                         HARD_FRAME_POINTER_REGNUM);
-  if (arg_pointer_rtx == 0)
-    arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM);
-  virtual_incoming_args_rtx =
-    gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
-  virtual_stack_vars_rtx =
-    gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
-  virtual_stack_dynamic_rtx =
-    gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);
-  virtual_outgoing_args_rtx =
-    gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);
-  virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
-
-  /* Initialize RTL for commonly used hard registers.  These are
-     copied into regno_reg_rtx as we begin to compile each function.  */
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    static_regno_reg_rtx[i] = gen_raw_REG (reg_raw_mode[i], i);
-
 #ifdef INIT_EXPANDERS
   /* This is to initialize {init|mark|free}_machine_status before the first
      call to push_function_context_to.  This is needed by the Chill front
@@ -5389,7 +5443,7 @@ init_emit_once (int line_numbers)
 
   /* Create the unique rtx's for certain rtx codes and operand values.  */
 
-  /* Don't use gen_rtx here since gen_rtx in this case
+  /* Don't use gen_rtx_CONST_INT here since gen_rtx_CONST_INT in this case
      tries to use these variables.  */
   for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
     const_int_rtx[i + MAX_SAVED_CONST_INT] =
@@ -5404,36 +5458,34 @@ init_emit_once (int line_numbers)
   REAL_VALUE_FROM_INT (dconst0,   0,  0, double_mode);
   REAL_VALUE_FROM_INT (dconst1,   1,  0, double_mode);
   REAL_VALUE_FROM_INT (dconst2,   2,  0, double_mode);
-  REAL_VALUE_FROM_INT (dconst3,   3,  0, double_mode);
-  REAL_VALUE_FROM_INT (dconst10, 10,  0, double_mode);
-  REAL_VALUE_FROM_INT (dconstm1, -1, -1, double_mode);
-  REAL_VALUE_FROM_INT (dconstm2, -2, -1, double_mode);
-
-  dconsthalf = dconst1;
-  dconsthalf.exp--;
 
-  real_arithmetic (&dconstthird, RDIV_EXPR, &dconst1, &dconst3);
+  dconstm1 = dconst1;
+  dconstm1.sign = 1;
 
-  /* Initialize mathematical constants for constant folding builtins.
-     These constants need to be given to at least 160 bits precision.  */
-  real_from_string (&dconstpi,
-    "3.1415926535897932384626433832795028841971693993751058209749445923078");
-  real_from_string (&dconste,
-    "2.7182818284590452353602874713526624977572470936999595749669676277241");
+  dconsthalf = dconst1;
+  SET_REAL_EXP (&dconsthalf, REAL_EXP (&dconsthalf) - 1);
 
   for (i = 0; i < (int) ARRAY_SIZE (const_tiny_rtx); i++)
     {
-      REAL_VALUE_TYPE *r =
+      const REAL_VALUE_TYPE *const r =
        (i == 0 ? &dconst0 : i == 1 ? &dconst1 : &dconst2);
 
-      for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+      for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+          mode != VOIDmode;
+          mode = GET_MODE_WIDER_MODE (mode))
+       const_tiny_rtx[i][(int) mode] =
+         CONST_DOUBLE_FROM_REAL_VALUE (*r, mode);
+
+      for (mode = GET_CLASS_NARROWEST_MODE (MODE_DECIMAL_FLOAT);
+          mode != VOIDmode;
           mode = GET_MODE_WIDER_MODE (mode))
        const_tiny_rtx[i][(int) mode] =
          CONST_DOUBLE_FROM_REAL_VALUE (*r, mode);
 
       const_tiny_rtx[i][(int) VOIDmode] = GEN_INT (i);
 
-      for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+      for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+          mode != VOIDmode;
           mode = GET_MODE_WIDER_MODE (mode))
        const_tiny_rtx[i][(int) mode] = GEN_INT (i);
 
@@ -5443,141 +5495,215 @@ init_emit_once (int line_numbers)
        const_tiny_rtx[i][(int) mode] = GEN_INT (i);
     }
 
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_INT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)];
+      const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner);
+    }
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      rtx inner = const_tiny_rtx[0][(int)GET_MODE_INNER (mode)];
+      const_tiny_rtx[0][(int) mode] = gen_rtx_CONCAT (mode, inner, inner);
+    }
+
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
        mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
-    const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode);
+    {
+      const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+      const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1);
+    }
 
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
        mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
-    const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode);
-
-  for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i)
-    if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC)
-      const_tiny_rtx[0][i] = const0_rtx;
+    {
+      const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+      const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1);
+    }
 
-  const_tiny_rtx[0][(int) BImode] = const0_rtx;
-  if (STORE_FLAG_VALUE == 1)
-    const_tiny_rtx[1][(int) BImode] = const1_rtx;
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FRACT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      FCONST0(mode).data.high = 0;
+      FCONST0(mode).data.low = 0;
+      FCONST0(mode).mode = mode;
+      const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+                                     FCONST0 (mode), mode);
+    }
 
-#ifdef RETURN_ADDRESS_POINTER_REGNUM
-  return_address_pointer_rtx
-    = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
-#endif
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_UFRACT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      FCONST0(mode).data.high = 0;
+      FCONST0(mode).data.low = 0;
+      FCONST0(mode).mode = mode;
+      const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+                                     FCONST0 (mode), mode);
+    }
 
-#ifdef STATIC_CHAIN_REGNUM
-  static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_ACCUM);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      FCONST0(mode).data.high = 0;
+      FCONST0(mode).data.low = 0;
+      FCONST0(mode).mode = mode;
+      const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+                                     FCONST0 (mode), mode);
+
+      /* We store the value 1.  */
+      FCONST1(mode).data.high = 0;
+      FCONST1(mode).data.low = 0;
+      FCONST1(mode).mode = mode;
+      lshift_double (1, 0, GET_MODE_FBIT (mode),
+                     2 * HOST_BITS_PER_WIDE_INT,
+                     &FCONST1(mode).data.low,
+                    &FCONST1(mode).data.high,
+                     SIGNED_FIXED_POINT_MODE_P (mode));
+      const_tiny_rtx[1][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+                                     FCONST1 (mode), mode);
+    }
 
-#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);
-  else
-#endif
-    static_chain_incoming_rtx = static_chain_rtx;
-#endif
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_UACCUM);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      FCONST0(mode).data.high = 0;
+      FCONST0(mode).data.low = 0;
+      FCONST0(mode).mode = mode;
+      const_tiny_rtx[0][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+                                     FCONST0 (mode), mode);
+
+      /* We store the value 1.  */
+      FCONST1(mode).data.high = 0;
+      FCONST1(mode).data.low = 0;
+      FCONST1(mode).mode = mode;
+      lshift_double (1, 0, GET_MODE_FBIT (mode),
+                     2 * HOST_BITS_PER_WIDE_INT,
+                     &FCONST1(mode).data.low,
+                    &FCONST1(mode).data.high,
+                     SIGNED_FIXED_POINT_MODE_P (mode));
+      const_tiny_rtx[1][(int) mode] = CONST_FIXED_FROM_FIXED_VALUE (
+                                     FCONST1 (mode), mode);
+    }
 
-#ifdef STATIC_CHAIN
-  static_chain_rtx = STATIC_CHAIN;
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FRACT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+    }
 
-#ifdef STATIC_CHAIN_INCOMING
-  static_chain_incoming_rtx = STATIC_CHAIN_INCOMING;
-#else
-  static_chain_incoming_rtx = static_chain_rtx;
-#endif
-#endif
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_UFRACT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+    }
 
-  if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
-    pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
-}
-\f
-/* Query and clear/ restore no_line_numbers.  This is used by the
-   switch / case handling in stmt.c to give proper line numbers in
-   warnings about unreachable code.  */
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_ACCUM);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+      const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1);
+    }
 
-int
-force_line_numbers (void)
-{
-  int old = no_line_numbers;
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_UACCUM);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    {
+      const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+      const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1);
+    }
 
-  no_line_numbers = 0;
-  if (old)
-    force_next_line_note ();
-  return old;
-}
+  for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i)
+    if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC)
+      const_tiny_rtx[0][i] = const0_rtx;
 
-void
-restore_line_number_status (int old_value)
-{
-  no_line_numbers = old_value;
+  const_tiny_rtx[0][(int) BImode] = const0_rtx;
+  if (STORE_FLAG_VALUE == 1)
+    const_tiny_rtx[1][(int) BImode] = const1_rtx;
 }
-
+\f
 /* Produce exact duplicate of insn INSN after AFTER.
    Care updating of libcall regions if present.  */
 
 rtx
 emit_copy_of_insn_after (rtx insn, rtx after)
 {
-  rtx new;
-  rtx note1, note2, link;
+  rtx new_rtx, link;
 
   switch (GET_CODE (insn))
     {
     case INSN:
-      new = emit_insn_after (copy_insn (PATTERN (insn)), after);
+      new_rtx = emit_insn_after (copy_insn (PATTERN (insn)), after);
       break;
 
     case JUMP_INSN:
-      new = emit_jump_insn_after (copy_insn (PATTERN (insn)), after);
+      new_rtx = emit_jump_insn_after (copy_insn (PATTERN (insn)), after);
       break;
 
     case CALL_INSN:
-      new = emit_call_insn_after (copy_insn (PATTERN (insn)), after);
+      new_rtx = emit_call_insn_after (copy_insn (PATTERN (insn)), after);
       if (CALL_INSN_FUNCTION_USAGE (insn))
-       CALL_INSN_FUNCTION_USAGE (new)
+       CALL_INSN_FUNCTION_USAGE (new_rtx)
          = copy_insn (CALL_INSN_FUNCTION_USAGE (insn));
-      SIBLING_CALL_P (new) = SIBLING_CALL_P (insn);
-      CONST_OR_PURE_CALL_P (new) = CONST_OR_PURE_CALL_P (insn);
+      SIBLING_CALL_P (new_rtx) = SIBLING_CALL_P (insn);
+      RTL_CONST_CALL_P (new_rtx) = RTL_CONST_CALL_P (insn);
+      RTL_PURE_CALL_P (new_rtx) = RTL_PURE_CALL_P (insn);
+      RTL_LOOPING_CONST_OR_PURE_CALL_P (new_rtx) 
+       = RTL_LOOPING_CONST_OR_PURE_CALL_P (insn);
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   /* Update LABEL_NUSES.  */
-  mark_jump_label (PATTERN (new), new, 0);
+  mark_jump_label (PATTERN (new_rtx), new_rtx, 0);
 
-  INSN_LOCATOR (new) = INSN_LOCATOR (insn);
+  INSN_LOCATOR (new_rtx) = INSN_LOCATOR (insn);
 
-  /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
-     make them.  */
+  /* If the old insn is frame related, then so is the new one.  This is
+     primarily needed for IA-64 unwind info which marks epilogue insns,
+     which may be duplicated by the basic block reordering code.  */
+  RTX_FRAME_RELATED_P (new_rtx) = RTX_FRAME_RELATED_P (insn);
+
+  /* Copy all REG_NOTES except REG_LABEL_OPERAND since mark_jump_label
+     will make them.  REG_LABEL_TARGETs are created there too, but are
+     supposed to be sticky, so we copy them.  */
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-    if (REG_NOTE_KIND (link) != REG_LABEL)
+    if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND)
       {
        if (GET_CODE (link) == EXPR_LIST)
-         REG_NOTES (new)
-           = copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
-                                             XEXP (link, 0),
-                                             REG_NOTES (new)));
+         add_reg_note (new_rtx, REG_NOTE_KIND (link),
+                       copy_insn_1 (XEXP (link, 0)));
        else
-         REG_NOTES (new)
-           = copy_insn_1 (gen_rtx_INSN_LIST (REG_NOTE_KIND (link),
-                                             XEXP (link, 0),
-                                             REG_NOTES (new)));
+         add_reg_note (new_rtx, REG_NOTE_KIND (link), XEXP (link, 0));
       }
 
-  /* Fix the libcall sequences.  */
-  if ((note1 = find_reg_note (new, REG_RETVAL, NULL_RTX)) != NULL)
-    {
-      rtx p = new;
-      while ((note2 = find_reg_note (p, REG_LIBCALL, NULL_RTX)) == NULL)
-       p = PREV_INSN (p);
-      XEXP (note1, 0) = p;
-      XEXP (note2, 0) = new;
-    }
-  INSN_CODE (new) = INSN_CODE (insn);
-  return new;
+  INSN_CODE (new_rtx) = INSN_CODE (insn);
+  return new_rtx;
+}
+
+static GTY((deletable)) rtx hard_reg_clobbers [NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];
+rtx
+gen_hard_reg_clobber (enum machine_mode mode, unsigned int regno)
+{
+  if (hard_reg_clobbers[mode][regno])
+    return hard_reg_clobbers[mode][regno];
+  else
+    return (hard_reg_clobbers[mode][regno] =
+           gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (mode, regno)));
 }
 
 #include "gt-emit-rtl.h"