OSDN Git Service

2002-01-16 H.J. Lu <hjl@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 7a98f20..c3b8ddc 100644 (file)
@@ -1,23 +1,23 @@
 /* Emit RTL for the GNU C-Compiler expander.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; 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 COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 
 /* Middle-to-low level generation of rtx code and insns.
@@ -54,6 +54,8 @@ Boston, MA 02111-1307, USA.  */
 #include "bitmap.h"
 #include "basic-block.h"
 #include "ggc.h"
+#include "debug.h"
+#include "langhooks.h"
 
 /* Commonly used modes.  */
 
@@ -114,7 +116,7 @@ REAL_VALUE_TYPE dconstm1;
 
    When to use frame_pointer_rtx and hard_frame_pointer_rtx is a little
    tricky: until register elimination has taken place hard_frame_pointer_rtx
-   should be used if it is being set, and frame_pointer_rtx otherwise.  After 
+   should be used if it is being set, and frame_pointer_rtx otherwise.  After
    register elimination hard_frame_pointer_rtx should always be used.
    On machines where the two registers are same (most) then these are the
    same.
@@ -143,6 +145,9 @@ rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
 
 static htab_t const_int_htab;
 
+/* A hash table storing memory attribute structures.  */
+static htab_t mem_attrs_htab;
+
 /* start_sequence and gen_sequence can make a lot of rtx expressions which are
    shortly thrown away.  We use two mechanisms to prevent this waste:
 
@@ -174,6 +179,8 @@ static rtx make_jump_insn_raw               PARAMS ((rtx));
 static rtx make_call_insn_raw          PARAMS ((rtx));
 static rtx find_line_note              PARAMS ((rtx));
 static void mark_sequence_stack         PARAMS ((struct sequence_stack *));
+static rtx change_address_1            PARAMS ((rtx, enum machine_mode, rtx,
+                                                int));
 static void unshare_all_rtl_1          PARAMS ((rtx));
 static void unshare_all_decls          PARAMS ((tree));
 static void reset_used_decls           PARAMS ((tree));
@@ -181,9 +188,18 @@ static void mark_label_nuses               PARAMS ((rtx));
 static hashval_t const_int_htab_hash    PARAMS ((const void *));
 static int const_int_htab_eq            PARAMS ((const void *,
                                                 const void *));
-static int rtx_htab_mark_1              PARAMS ((void **, void *));
-static void rtx_htab_mark               PARAMS ((void *));
-
+static hashval_t mem_attrs_htab_hash    PARAMS ((const void *));
+static int mem_attrs_htab_eq            PARAMS ((const void *,
+                                                const void *));
+static void mem_attrs_mark             PARAMS ((const void *));
+static mem_attrs *get_mem_attrs                PARAMS ((HOST_WIDE_INT, tree, rtx,
+                                                rtx, unsigned int,
+                                                enum machine_mode));
+static tree component_ref_for_mem_expr PARAMS ((tree));
+
+/* Probability of the conditional branch currently proceeded by try_split.
+   Set to -1 otherwise.  */
+int split_branch_probability = -1;
 \f
 /* Returns a hash code for X (which is a really a CONST_INT).  */
 
@@ -206,26 +222,93 @@ const_int_htab_eq (x, y)
   return (INTVAL ((const struct rtx_def *) x) == *((const HOST_WIDE_INT *) y));
 }
 
-/* Mark the hash-table element X (which is really a pointer to an
-   rtx).  */
+/* Returns a hash code for X (which is a really a mem_attrs *).  */
+
+static hashval_t
+mem_attrs_htab_hash (x)
+     const void *x;
+{
+  mem_attrs *p = (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);
+}
+
+/* Returns non-zero if the value represented by X (which is really a
+   mem_attrs *) is the same as that given by Y (which is also really a
+   mem_attrs *).  */
 
 static int
-rtx_htab_mark_1 (x, data)
-     void **x;
-     void *data ATTRIBUTE_UNUSED;
+mem_attrs_htab_eq (x, y)
+     const void *x;
+     const void *y;
 {
-  ggc_mark_rtx (*x);
-  return 1;
+  mem_attrs *p = (mem_attrs *) x;
+  mem_attrs *q = (mem_attrs *) y;
+
+  return (p->alias == q->alias && p->expr == q->expr && p->offset == q->offset
+         && p->size == q->size && p->align == q->align);
 }
 
-/* Mark all the elements of HTAB (which is really an htab_t full of
-   rtxs).  */
+/* This routine is called when we determine that we need a mem_attrs entry.
+   It marks the associated decl and RTL as being used, if present.  */
 
 static void
-rtx_htab_mark (htab)
-     void *htab;
+mem_attrs_mark (x)
+     const void *x;
 {
-  htab_traverse (*((htab_t *) htab), rtx_htab_mark_1, NULL);
+  mem_attrs *p = (mem_attrs *) x;
+
+  if (p->expr)
+    ggc_mark_tree (p->expr);
+
+  if (p->offset)
+    ggc_mark_rtx (p->offset);
+
+  if (p->size)
+    ggc_mark_rtx (p->size);
+}
+
+/* Allocate a new mem_attrs structure and insert it into the hash table if
+   one identical to it is not already in the table.  We are doing this for
+   MEM of mode MODE.  */
+
+static mem_attrs *
+get_mem_attrs (alias, expr, offset, size, align, mode)
+     HOST_WIDE_INT alias;
+     tree expr;
+     rtx offset;
+     rtx size;
+     unsigned int align;
+     enum machine_mode mode;
+{
+  mem_attrs attrs;
+  void **slot;
+
+  /* If everything is the default, we can just return zero.  */
+  if (alias == 0 && expr == 0 && offset == 0
+      && (size == 0
+         || (mode != BLKmode && GET_MODE_SIZE (mode) == INTVAL (size)))
+      && (align == BITS_PER_UNIT
+         || (mode != BLKmode && align == GET_MODE_ALIGNMENT (mode))))
+    return 0;
+
+  attrs.alias = alias;
+  attrs.expr = expr;
+  attrs.offset = offset;
+  attrs.size = size;
+  attrs.align = align;
+
+  slot = htab_find_slot (mem_attrs_htab, &attrs, INSERT);
+  if (*slot == 0)
+    {
+      *slot = ggc_alloc (sizeof (mem_attrs));
+      memcpy (*slot, &attrs, sizeof (mem_attrs));
+    }
+
+  return *slot;
 }
 
 /* Generate a new REG rtx.  Make sure ORIGINAL_REGNO is set properly, and
@@ -274,21 +357,19 @@ gen_rtx_CONST_INT (mode, arg)
    only at run-time.  */
 
 rtx
-gen_rtx_CONST_DOUBLE (mode, arg0, arg1, arg2)
+gen_rtx_CONST_DOUBLE (mode, arg0, arg1)
      enum machine_mode mode;
-     rtx arg0;
-     HOST_WIDE_INT arg1, arg2;
+     HOST_WIDE_INT arg0, arg1;
 {
   rtx r = rtx_alloc (CONST_DOUBLE);
   int i;
 
   PUT_MODE (r, mode);
-  XEXP (r, 0) = arg0;
-  X0EXP (r, 1) = NULL_RTX;
+  X0EXP (r, 0) = NULL_RTX;
+  XWINT (r, 1) = arg0;
   XWINT (r, 2) = arg1;
-  XWINT (r, 3) = arg2;
 
-  for (i = GET_RTX_LENGTH (CONST_DOUBLE) - 1; i > 3; --i)
+  for (i = GET_RTX_LENGTH (CONST_DOUBLE) - 1; i > 2; --i)
     XWINT (r, i) = 0;
 
   return r;
@@ -345,7 +426,7 @@ gen_rtx_MEM (mode, addr)
 
   /* This field is not cleared by the mere allocation of the rtx, so
      we clear it here.  */
-  MEM_ALIAS_SET (rt) = 0;
+  MEM_ATTRS (rt) = 0;
 
   return rt;
 }
@@ -372,31 +453,21 @@ gen_rtx_SUBREG (mode, reg, offset)
   return gen_rtx_fmt_ei (SUBREG, mode, reg, offset);
 }
 
-/* Generate a SUBREG representing the least-significant part
- * of REG if MODE is smaller than mode of REG, otherwise
- * paradoxical SUBREG. */
+/* Generate a SUBREG representing the least-significant part of REG if MODE
+   is smaller than mode of REG, otherwise paradoxical SUBREG.  */
+
 rtx
 gen_lowpart_SUBREG (mode, reg)
      enum machine_mode mode;
      rtx reg;
 {
   enum machine_mode inmode;
-  int offset;
 
   inmode = GET_MODE (reg);
   if (inmode == VOIDmode)
     inmode = mode;
-  offset = 0;
-  if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (inmode)
-      && (WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN))
-    {
-      offset = GET_MODE_SIZE (inmode) - GET_MODE_SIZE (mode);
-      if (! BYTES_BIG_ENDIAN)
-       offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD;
-      else if (! WORDS_BIG_ENDIAN)
-       offset %= UNITS_PER_WORD;
-    }
-  return gen_rtx_SUBREG (mode, reg, offset);
+  return gen_rtx_SUBREG (mode, reg,
+                        subreg_lowpart_offset (mode, inmode));
 }
 \f
 /* rtx gen_rtx (code, mode, [element1, ..., elementn])
@@ -416,7 +487,7 @@ gen_lowpart_SUBREG (mode, reg)
 **
 **             ...would be generated by the following C code:
 **
-**             gen_rtx (PLUS, QImode,
+**             gen_rtx (PLUS, QImode,
 **                 gen_rtx (MEM, QImode,
 **                     gen_rtx (REG, SImode, 1)),
 **                 gen_rtx (MEM, QImode,
@@ -429,21 +500,13 @@ gen_lowpart_SUBREG (mode, reg)
 rtx
 gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
 {
-#ifndef ANSI_PROTOTYPES
-  enum rtx_code code;
-  enum machine_mode mode;
-#endif
-  va_list p;
-  register int i;              /* Array indices...                     */
-  register const char *fmt;    /* Current rtx's format...              */
-  register rtx rt_val;         /* RTX to return to caller...           */
-
-  VA_START (p, mode);
+  int i;               /* Array indices...                     */
+  const char *fmt;     /* Current rtx's format...              */
+  rtx rt_val;          /* RTX to return to caller...           */
 
-#ifndef ANSI_PROTOTYPES
-  code = va_arg (p, enum rtx_code);
-  mode = va_arg (p, enum machine_mode);
-#endif
+  VA_OPEN (p, mode);
+  VA_FIXEDARG (p, enum rtx_code, code);
+  VA_FIXEDARG (p, enum machine_mode, mode);
 
   switch (code)
     {
@@ -453,10 +516,10 @@ gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
 
     case CONST_DOUBLE:
       {
-       rtx arg0 = va_arg (p, rtx);
+       HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT);
        HOST_WIDE_INT arg1 = va_arg (p, HOST_WIDE_INT);
-       HOST_WIDE_INT arg2 = va_arg (p, HOST_WIDE_INT);
-        rt_val = gen_rtx_CONST_DOUBLE (mode, arg0, arg1, arg2);
+
+        rt_val = gen_rtx_CONST_DOUBLE (mode, arg0, arg1);
       }
       break;
 
@@ -516,7 +579,7 @@ gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
       break;
     }
 
-  va_end (p);
+  VA_CLOSE (p);
   return rt_val;
 }
 
@@ -530,18 +593,11 @@ gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
 rtvec
 gen_rtvec VPARAMS ((int n, ...))
 {
-#ifndef ANSI_PROTOTYPES
-  int n;
-#endif
-  int i;
-  va_list p;
+  int i, save_n;
   rtx *vector;
 
-  VA_START (p, n);
-
-#ifndef ANSI_PROTOTYPES
-  n = va_arg (p, int);
-#endif
+  VA_OPEN (p, n);
+  VA_FIXEDARG (p, int, n);
 
   if (n == 0)
     return NULL_RTVEC;         /* Don't allocate an empty rtvec...     */
@@ -550,9 +606,12 @@ gen_rtvec VPARAMS ((int n, ...))
 
   for (i = 0; i < n; i++)
     vector[i] = va_arg (p, rtx);
-  va_end (p);
 
-  return gen_rtvec_v (n, vector);
+  /* The definition of VA_* in K&R C causes `n' to go out of scope.  */
+  save_n = n;
+  VA_CLOSE (p);
+
+  return gen_rtvec_v (save_n, vector);
 }
 
 rtvec
@@ -560,8 +619,8 @@ gen_rtvec_v (n, argp)
      int n;
      rtx *argp;
 {
-  register int i;
-  register rtvec rt_val;
+  int i;
+  rtvec rt_val;
 
   if (n == 0)
     return NULL_RTVEC;         /* Don't allocate an empty rtvec...     */
@@ -573,7 +632,6 @@ gen_rtvec_v (n, argp)
 
   return rt_val;
 }
-
 \f
 /* Generate a REG rtx for a new pseudo register of mode MODE.
    This pseudo is assigned the next sequential register number.  */
@@ -583,7 +641,7 @@ gen_reg_rtx (mode)
      enum machine_mode mode;
 {
   struct function *f = cfun;
-  register rtx val;
+  rtx val;
 
   /* Don't let anything called after initial flow analysis create new
      registers.  */
@@ -612,14 +670,16 @@ gen_reg_rtx (mode)
       return gen_rtx_CONCAT (mode, realpart, imagpart);
     }
 
-  /* Make sure regno_pointer_align and regno_reg_rtx are large enough
-     to have an element for this pseudo reg number.  */
+  /* Make sure regno_pointer_align, regno_decl, 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)
     {
       int old_size = f->emit->regno_pointer_align_length;
-      rtx *new1;
       char *new;
+      rtx *new1;
+      tree *new2;
+
       new = xrealloc (f->emit->regno_pointer_align, old_size * 2);
       memset (new + old_size, 0, old_size);
       f->emit->regno_pointer_align = (unsigned char *) new;
@@ -629,6 +689,11 @@ gen_reg_rtx (mode)
       memset (new1 + old_size, 0, old_size * sizeof (rtx));
       regno_reg_rtx = new1;
 
+      new2 = (tree *) xrealloc (f->emit->regno_decl,
+                               old_size * 2 * sizeof (tree));
+      memset (new2 + old_size, 0, old_size * sizeof (tree));
+      f->emit->regno_decl = new2;
+
       f->emit->regno_pointer_align_length = old_size * 2;
     }
 
@@ -704,7 +769,7 @@ get_first_label_num ()
    register.  */
 int
 subreg_hard_regno (x, check_mode)
-     register rtx x;
+     rtx x;
      int check_mode;
 {
   enum machine_mode mode = GET_MODE (x);
@@ -734,7 +799,7 @@ subreg_hard_regno (x, check_mode)
 
 /* 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 
+   between floating-point and fixed-point values, rather, the bit
    representation is returned.
 
    This function handles the cases in common between gen_lowpart, below,
@@ -746,7 +811,7 @@ subreg_hard_regno (x, check_mode)
 rtx
 gen_lowpart_common (mode, x)
      enum machine_mode mode;
-     register rtx x;
+     rtx x;
 {
   int msize = GET_MODE_SIZE (mode);
   int xsize = GET_MODE_SIZE (GET_MODE (x));
@@ -761,16 +826,7 @@ gen_lowpart_common (mode, x)
          > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
     return 0;
 
-  if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
-      && xsize > msize)
-    {
-      int difference = xsize - msize;
-
-      if (WORDS_BIG_ENDIAN)
-       offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
-      if (BYTES_BIG_ENDIAN)
-       offset += difference % UNITS_PER_WORD;
-    }
+  offset = subreg_lowpart_offset (mode, GET_MODE (x));
 
   if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
       && (GET_MODE_CLASS (mode) == MODE_INT
@@ -791,61 +847,9 @@ gen_lowpart_common (mode, x)
       else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x)))
        return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0));
     }
-  else if (GET_CODE (x) == SUBREG
-          && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
-              || GET_MODE_SIZE (mode) == GET_MODE_UNIT_SIZE (GET_MODE (x))))
-    {
-      int final_offset;
-
-      if (GET_MODE (SUBREG_REG (x)) == mode && subreg_lowpart_p (x))
-       return SUBREG_REG (x);
-
-      /* When working with SUBREGs the rule is that the byte
-        offset must be a multiple of the SUBREG's mode.  */
-      final_offset = SUBREG_BYTE (x) + offset;
-      final_offset = (final_offset / GET_MODE_SIZE (mode));
-      final_offset = (final_offset * GET_MODE_SIZE (mode));
-      return gen_rtx_SUBREG (mode, SUBREG_REG (x), final_offset);   
-    }
-  else if (GET_CODE (x) == REG)
-    {
-      /* Hard registers are done specially in certain cases.  */  
-      if (REGNO (x) < FIRST_PSEUDO_REGISTER)
-        {
-         int final_regno = REGNO (x) +
-                           subreg_regno_offset (REGNO (x), GET_MODE (x), 
-                                                offset, mode);
-
-         /* If the final regno is not valid for MODE, punt.  */
-         /* ??? We do allow it if the current REG is not valid for
-            ??? it's mode.  It is a kludge to work around how float/complex
-            ??? arguments are passed on 32-bit Sparc and should be fixed.  */
-         if (! HARD_REGNO_MODE_OK (final_regno, mode)
-             && HARD_REGNO_MODE_OK (REGNO (x), GET_MODE (x)))
-           return 0;
-
-              /* integrate.c can't handle parts of a return value register. */
-         if ((! REG_FUNCTION_VALUE_P (x)
-                  || ! rtx_equal_function_value_matters)
-#ifdef CLASS_CANNOT_CHANGE_MODE
-              && ! (CLASS_CANNOT_CHANGE_MODE_P (mode, GET_MODE (x))
-                    && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_INT
-                    && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_FLOAT
-                    && (TEST_HARD_REG_BIT
-                        (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
-                         REGNO (x))))
-#endif
-              /* We want to keep the stack, frame, and arg pointers
-                 special.  */
-              && x != frame_pointer_rtx
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-              && x != arg_pointer_rtx
-#endif
-              && x != stack_pointer_rtx)
-           return gen_rtx_REG (mode, final_regno);
-         }
-      return gen_rtx_SUBREG (mode, x, offset);
-    }
+  else if (GET_CODE (x) == SUBREG || GET_CODE (x) == REG
+          || GET_CODE (x) == CONCAT)
+    return simplify_gen_subreg (mode, x, GET_MODE (x), 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
@@ -882,7 +886,7 @@ gen_lowpart_common (mode, x)
   /* If X is an integral constant but we want it in floating-point, it
      must be the case that we have a union of an integer and a floating-point
      value.  If the machine-parameters allow it, simulate that union here
-     and return the result.  The two-word and single-word cases are 
+     and return the result.  The two-word and single-word cases are
      different.  */
 
   else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
@@ -971,18 +975,22 @@ gen_lowpart_common (mode, x)
      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.  */
 
-  else if (mode == SFmode
+  else if (GET_MODE_CLASS (mode) == MODE_FLOAT
+          && GET_MODE_BITSIZE (mode) == 32
           && GET_CODE (x) == CONST_INT)
-    {
+  {
       REAL_VALUE_TYPE r;
       HOST_WIDE_INT i;
 
       i = INTVAL (x);
       r = REAL_VALUE_FROM_TARGET_SINGLE (i);
       return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
-    }
-  else if (mode == DFmode
+  }
+  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)
     {
@@ -997,7 +1005,7 @@ gen_lowpart_common (mode, x)
        }
       else
        {
-         low = CONST_DOUBLE_LOW (x); 
+         low = CONST_DOUBLE_LOW (x);
          high = CONST_DOUBLE_HIGH (x);
        }
 
@@ -1020,58 +1028,45 @@ gen_lowpart_common (mode, x)
       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 (x))
+      switch (GET_MODE_BITSIZE (GET_MODE (x)))
        {
-       case SFmode:
-         REAL_VALUE_TO_TARGET_SINGLE (r, i[endian]);
-         i[1 - endian] = 0;
-         break;
-       case DFmode:
-         REAL_VALUE_TO_TARGET_DOUBLE (r, i);
-         break;
-#if LONG_DOUBLE_TYPE_SIZE == 96
-       case XFmode:
+       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;
-#else
-       case TFmode:
+         i[3 - 3 * endian] = 0;
+         break;
+       case 128:
          REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i);
-#endif
          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[endian], i[1 - endian], mode);
+      return immed_double_const (i[3 * endian], i[1 + endian], mode);
 #else
-      {
-       int c;
-
-       if (HOST_BITS_PER_WIDE_INT != 64)
-         abort ();
-
-       for (c = 0; c < 4; c++)
-         i[c] &= ~ (0L);
+      if (HOST_BITS_PER_WIDE_INT != 64)
+       abort ();
 
-       switch (GET_MODE (x))
-         {
-         case SFmode:
-         case DFmode:
-           return immed_double_const (((unsigned long) i[endian]) |
-                                      (((HOST_WIDE_INT) i[1-endian]) << 32),
-                                      0, mode);
-         default:
-           return immed_double_const (((unsigned long) i[endian*3]) |
-                                      (((HOST_WIDE_INT) i[1+endian]) << 32),
-                                      ((unsigned long) i[2-endian]) |
-                                      (((HOST_WIDE_INT) i[3-endian*3]) << 32),
-                                      mode);
-         }
-      }
+      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
     }
 #endif /* ifndef REAL_ARITHMETIC */
@@ -1086,16 +1081,14 @@ gen_lowpart_common (mode, x)
 rtx
 gen_realpart (mode, x)
      enum machine_mode mode;
-     register rtx x;
+     rtx x;
 {
-  if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode)
-    return XEXP (x, 0);
-  else if (WORDS_BIG_ENDIAN
-          && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
-          && REG_P (x)
-          && REGNO (x) < FIRST_PSEUDO_REGISTER)
+  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");
+      ("can't access real part of complex value in hard register");
   else if (WORDS_BIG_ENDIAN)
     return gen_highpart (mode, x);
   else
@@ -1108,11 +1101,9 @@ gen_realpart (mode, x)
 rtx
 gen_imagpart (mode, x)
      enum machine_mode mode;
-     register rtx x;
+     rtx x;
 {
-  if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode)
-    return XEXP (x, 1);
-  else if (WORDS_BIG_ENDIAN)
+  if (WORDS_BIG_ENDIAN)
     return gen_lowpart (mode, x);
   else if (! WORDS_BIG_ENDIAN
           && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
@@ -1150,7 +1141,7 @@ subreg_realpart_p (x)
 rtx
 gen_lowpart (mode, x)
      enum machine_mode mode;
-     register rtx x;
+     rtx x;
 {
   rtx result = gen_lowpart_common (mode, x);
 
@@ -1167,7 +1158,7 @@ gen_lowpart (mode, x)
   else if (GET_CODE (x) == MEM)
     {
       /* The only additional case we can do is MEM.  */
-      register int offset = 0;
+      int offset = 0;
       if (WORDS_BIG_ENDIAN)
        offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
                  - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
@@ -1178,7 +1169,7 @@ gen_lowpart (mode, x)
        offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
                   - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
 
-      return change_address (x, mode, plus_constant (XEXP (x, 0), offset));
+      return adjust_address (x, mode, offset);
     }
   else if (GET_CODE (x) == ADDRESSOF)
     return gen_lowpart (mode, force_reg (GET_MODE (x), x));
@@ -1186,118 +1177,95 @@ gen_lowpart (mode, x)
     abort ();
 }
 
-/* Like `gen_lowpart', but refer to the most significant part. 
+/* 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 (mode, x)
      enum machine_mode mode;
-     register rtx x;
+     rtx x;
 {
   unsigned int msize = GET_MODE_SIZE (mode);
-  unsigned int xsize = GET_MODE_SIZE (GET_MODE (x));
+  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 ();
-  if (GET_CODE (x) == CONST_DOUBLE
-#if !(TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT || defined (REAL_IS_NOT_DOUBLE))
-      && GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT
-#endif
-      )
-    return GEN_INT (CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode));
-  else if (GET_CODE (x) == CONST_INT)
-    {
-      if (HOST_BITS_PER_WIDE_INT <= BITS_PER_WORD)
-       return const0_rtx;
-      return GEN_INT (INTVAL (x) >> (HOST_BITS_PER_WIDE_INT - BITS_PER_WORD));
-    }
-  else if (GET_CODE (x) == MEM)
-    {
-      register int offset = 0;
 
-      if (! WORDS_BIG_ENDIAN)
-       offset = (MAX (xsize, UNITS_PER_WORD)
-                 - MAX (msize, UNITS_PER_WORD));
+  result = simplify_gen_subreg (mode, x, GET_MODE (x),
+                               subreg_highpart_offset (mode, GET_MODE (x)));
 
-      if (! BYTES_BIG_ENDIAN
-         && msize < UNITS_PER_WORD)
-       offset -= (msize - MIN (UNITS_PER_WORD, xsize));
+  /* 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);
 
-      return change_address (x, mode, plus_constant (XEXP (x, 0), offset));
-    }
-  else if (GET_CODE (x) == SUBREG)
+  if (!result)
+    abort ();
+  return result;
+}
+
+/* Like gen_highpart_mode, but accept mode of EXP operand in case EXP can
+   be VOIDmode constant.  */
+rtx
+gen_highpart_mode (outermode, innermode, exp)
+    enum machine_mode outermode, innermode;
+    rtx exp;
+{
+  if (GET_MODE (exp) != VOIDmode)
     {
-      /* The only time this should occur is when we are looking at a
-        multi-word item with a SUBREG whose mode is the same as that of the
-        item.  It isn't clear what we would do if it wasn't.  */
-      if (SUBREG_BYTE (x) != 0)
+      if (GET_MODE (exp) != innermode)
        abort ();
-      return gen_highpart (mode, SUBREG_REG (x));
+      return gen_highpart (outermode, exp);
     }
-  else if (GET_CODE (x) == REG)
-    {
-      int offset = 0;
-
-      if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
-       abort ();
+  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.  */
 
-      if ((! WORDS_BIG_ENDIAN || ! BYTES_BIG_ENDIAN)
-         && xsize > msize)
-       {
-         int difference = xsize - msize;
+unsigned int
+subreg_lowpart_offset (outermode, innermode)
+     enum machine_mode outermode, innermode;
+{
+  unsigned int offset = 0;
+  int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
 
-         if (! WORDS_BIG_ENDIAN)
-           offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
-         if (! BYTES_BIG_ENDIAN)
-           offset += difference % UNITS_PER_WORD;
-       }
-      if (REGNO (x) < FIRST_PSEUDO_REGISTER)
-       {
-         int final_regno = REGNO (x) +
-           subreg_regno_offset (REGNO (x), GET_MODE (x), offset, mode);
-
-         /* integrate.c can't handle parts of a return value register.
-            ??? Then integrate.c should be fixed!
-            ??? What about CLASS_CANNOT_CHANGE_SIZE?  */
-         if ((! REG_FUNCTION_VALUE_P (x)
-              || ! rtx_equal_function_value_matters)
-         /* We want to keep the stack, frame, and arg pointers special.  */
-             && x != frame_pointer_rtx
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM 
-             && x != arg_pointer_rtx
-#endif
-             && x != stack_pointer_rtx)
-           return gen_rtx_REG (mode, final_regno);
-       }
-      /* Just generate a normal SUBREG.  */
-      return gen_rtx_SUBREG (mode, x, offset); 
+  if (difference > 0)
+    {
+      if (WORDS_BIG_ENDIAN)
+       offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+      if (BYTES_BIG_ENDIAN)
+       offset += difference % UNITS_PER_WORD;
     }
-  else
-    abort ();
+
+  return offset;
 }
-/* Return 1 iff (SUBREG:outermode (OP:innermode) byte)
-   refers to the least significant part of its containing reg.  */
 
-int
-subreg_lowpart_parts_p (outermode, innermode, byte)
+/* Return offset in bytes to get OUTERMODE high part
+   of the value in mode INNERMODE stored in memory in target format.  */
+unsigned int
+subreg_highpart_offset (outermode, innermode)
      enum machine_mode outermode, innermode;
-     unsigned int byte;
 {
   unsigned int offset = 0;
   int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
 
+  if (GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
+     abort ();
+
   if (difference > 0)
     {
-      if (WORDS_BIG_ENDIAN)
+      if (WORDS_BIG_ENDIAN)
        offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
-      if (BYTES_BIG_ENDIAN)
+      if (BYTES_BIG_ENDIAN)
        offset += difference % UNITS_PER_WORD;
     }
 
-  return byte == offset;
+  return offset;
 }
 
 /* Return 1 iff X, assumed to be a SUBREG,
@@ -1313,8 +1281,8 @@ subreg_lowpart_p (x)
   else if (GET_MODE (SUBREG_REG (x)) == VOIDmode)
     return 0;
 
-  return subreg_lowpart_parts_p (GET_MODE (x), GET_MODE (SUBREG_REG (x)),
-                                SUBREG_BYTE (x));
+  return (subreg_lowpart_offset (GET_MODE (x), GET_MODE (SUBREG_REG (x)))
+         == SUBREG_BYTE (x));
 }
 \f
 
@@ -1355,7 +1323,7 @@ constant_subword (op, offset, mode)
         ??? This is a potential portability problem and should
         be fixed at some point.
 
-        We must excercise caution with the sign bit.  By definition there
+        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.  */
@@ -1497,10 +1465,10 @@ constant_subword (op, offset, mode)
       return GEN_INT (u.i);
     }
 #endif /* no REAL_ARITHMETIC */
-      
+
   /* 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.  
+     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
@@ -1553,7 +1521,10 @@ constant_subword (op, offset, mode)
    ??? This is still rather broken for some cases.  The problem for the
    moment is that all callers of this thing provide no 'goal mode' to
    tell us to work with.  This exists because all callers were written
-   in a word based SUBREG world.  */
+   in a word based SUBREG world.
+   Now use of this function can be deprecated by simplify_subreg in most
+   cases.
+ */
 
 rtx
 operand_subword (op, offset, validate_address, mode)
@@ -1568,121 +1539,40 @@ operand_subword (op, offset, validate_address, mode)
   if (mode == VOIDmode)
     abort ();
 
-  /* If OP is narrower than a word, fail. */
+  /* If OP is narrower than a word, fail.  */
   if (mode != BLKmode
       && (GET_MODE_SIZE (mode) < UNITS_PER_WORD))
     return 0;
 
-  /* If we want a word outside OP, return zero. */
+  /* If we want a word outside OP, return zero.  */
   if (mode != BLKmode
       && (offset + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode))
     return const0_rtx;
 
-  switch (GET_CODE (op))
-    {
-    case REG:
-    case SUBREG:
-    case CONCAT:
-    case MEM:
-      break;
-
-    default:
-      /* The only remaining cases are when OP is a constant.  If the host and
-        target floating formats are the same, handling two-word floating
-        constants are easy.  Note that REAL_VALUE_TO_TARGET_{SINGLE,DOUBLE}
-        are defined as returning one or two 32 bit values, respectively,
-        and not values of BITS_PER_WORD bits.  */
-      return constant_subword (op, offset, mode);
-    }
-
-  /* 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;
-
-  /* If OP is a REG or SUBREG, we can handle it very simply.  */
-  if (GET_CODE (op) == REG)
-    {
-      if (REGNO (op) < FIRST_PSEUDO_REGISTER)
-       {
-         int final_regno = REGNO (op) +
-           subreg_regno_offset (REGNO (op), GET_MODE (op),
-                               offset * UNITS_PER_WORD,
-                               word_mode);
-
-         /* If the register is not valid for MODE, return 0.  If we don't
-            do this, there is no way to fix up the resulting REG later.  */
-         if (! HARD_REGNO_MODE_OK (final_regno, word_mode))
-           return 0;
-
-         /* integrate.c can't handle parts of a return value register.
-            ??? Then integrate.c should be fixed!
-            ??? What about CLASS_CANNOT_CHANGE_SIZE?  */
-         if ((! REG_FUNCTION_VALUE_P (op)
-              || ! rtx_equal_function_value_matters)
-             /* ??? What about CLASS_CANNOT_CHANGE_SIZE?  */
-             /* We want to keep the stack, frame, and arg pointers
-                special.  */
-             && op != frame_pointer_rtx
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-             && op != arg_pointer_rtx
-#endif
-             && op != stack_pointer_rtx)
-           return gen_rtx_REG (word_mode, final_regno);
-       }
-
-      /* Just return a normal SUBREG.  */
-      return gen_rtx_SUBREG (word_mode, op,
-                            (offset * UNITS_PER_WORD));
-    }
-  else if (GET_CODE (op) == SUBREG)
-    {
-      int final_offset = ((offset * UNITS_PER_WORD) + SUBREG_BYTE (op));
-
-      /* When working with SUBREGs the rule is that the byte
-        offset must be a multiple of the SUBREG's mode.  */
-      final_offset = (final_offset / GET_MODE_SIZE (word_mode));
-      final_offset = (final_offset * GET_MODE_SIZE (word_mode));
-      return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), final_offset);
-    }
-  else if (GET_CODE (op) == CONCAT)
-    {
-      unsigned int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;
-      if (offset < partwords)
-       return operand_subword (XEXP (op, 0), offset, validate_address, mode);
-      return operand_subword (XEXP (op, 1), offset - partwords,
-                             validate_address, mode);
-    }
-
   /* Form a new MEM at the requested address.  */
   if (GET_CODE (op) == MEM)
     {
-      rtx addr = plus_constant (XEXP (op, 0), (offset * UNITS_PER_WORD));
-      rtx new;
+      rtx new = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD);
+
+      if (! validate_address)
+       return new;
 
-      if (validate_address)
+      else if (reload_completed)
        {
-         if (reload_completed)
-           {
-             if (! strict_memory_address_p (word_mode, addr))
-               return 0;
-           }
-         else
-           addr = memory_address (word_mode, addr);
+         if (! strict_memory_address_p (word_mode, XEXP (new, 0)))
+           return 0;
        }
-
-      new = gen_rtx_MEM (word_mode, addr);
-      MEM_COPY_ATTRIBUTES (new, op);
-      return new;
+      else
+       return replace_equiv_address (new, XEXP (new, 0));
     }
 
-  /* Unreachable... (famous last words) */
-  abort ();
+  /* 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.  
+   abort.  We always validate the address in this case.
 
    MODE is the mode of OP, in case it is CONST_INT.  */
 
@@ -1747,16 +1637,265 @@ reverse_comparison (insn)
     }
 }
 \f
-/* Return a memory reference like MEMREF, but with its mode changed
-   to MODE and its address changed to ADDR.
-   (VOIDmode means don't change the mode.
-   NULL for ADDR means don't change the address.)  */
+/* 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.  */
 
-rtx
-change_address (memref, mode, addr)
+static tree
+component_ref_for_mem_expr (ref)
+     tree ref;
+{
+  tree inner = TREE_OPERAND (ref, 0);
+
+  if (TREE_CODE (inner) == COMPONENT_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
+            || 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);
+
+      if (! DECL_P (inner))
+       inner = NULL_TREE;
+    }
+
+  if (inner == TREE_OPERAND (ref, 0))
+    return ref;
+  else
+    return build (COMPONENT_REF, TREE_TYPE (ref), inner,
+                 TREE_OPERAND (ref, 1));
+}
+
+/* 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.  */
+
+void
+set_mem_attributes (ref, t, objectp)
+     rtx ref;
+     tree t;
+     int objectp;
+{
+  HOST_WIDE_INT alias = MEM_ALIAS_SET (ref);
+  tree expr = MEM_EXPR (ref);
+  rtx offset = MEM_OFFSET (ref);
+  rtx size = MEM_SIZE (ref);
+  unsigned int align = MEM_ALIGN (ref);
+  tree type;
+
+  /* It can happen that type_for_mode was given a mode for which there
+     is no language-level type.  In which case it returns NULL, which
+     we can see here.  */
+  if (t == NULL_TREE)
+    return;
+
+  type = TYPE_P (t) ? t : TREE_TYPE (t);
+
+  /* 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 ();
+
+  /* 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)));
+
+  /* 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))
+    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))
+    align = MAX (align, TYPE_ALIGN (type));
+
+  /* If the size is known, we can set that.  */
+  if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))
+    size = GEN_INT (tree_low_cst (TYPE_SIZE_UNIT (type), 1));
+
+  /* If T is not a type, we may be able to deduce some more information about
+     the expression.  */
+  if (! TYPE_P (t))
+    {
+      maybe_set_unchanging (ref, t);
+      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
+            || 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))
+       MEM_KEEP_ALIAS_SET_P (ref) = 1;
+
+      /* If this is a decl, set the attributes of the MEM from it.  */
+      if (DECL_P (t))
+       {
+         expr = t;
+         offset = const0_rtx;
+         size = (DECL_SIZE_UNIT (t)
+                 && host_integerp (DECL_SIZE_UNIT (t), 1)
+                 ? GEN_INT (tree_low_cst (DECL_SIZE_UNIT (t), 1)) : 0);
+         align =  DECL_ALIGN (t);
+       }
+
+      /* If this is a constant, we know the alignment.  */
+      else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
+       {
+         align = TYPE_ALIGN (type);
+#ifdef CONSTANT_ALIGNMENT
+         align = CONSTANT_ALIGNMENT (t, align);
+#endif
+       }
+
+      /* If this is a field reference and not a bit-field, record it.  */
+      /* ??? There is some information that can be gleened 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
+              && ! DECL_BIT_FIELD (TREE_OPERAND (t, 1)))
+       {
+         expr = component_ref_for_mem_expr (t);
+         offset = const0_rtx;
+         /* ??? Any reason the field size would be different than
+            the size we got from the type?  */
+       }
+
+      /* If this is an array reference, look for an outer field reference.  */
+      else if (TREE_CODE (t) == ARRAY_REF)
+       {
+         tree off_tree = size_zero_node;
+
+         do
+           {
+             off_tree
+               = fold (build (PLUS_EXPR, sizetype,
+                              fold (build (MULT_EXPR, sizetype,
+                                           TREE_OPERAND (t, 1),
+                                           TYPE_SIZE_UNIT (TREE_TYPE (t)))),
+                              off_tree));
+             t = TREE_OPERAND (t, 0);
+           }
+         while (TREE_CODE (t) == ARRAY_REF);
+
+         if (TREE_CODE (t) == COMPONENT_REF)
+           {
+             expr = component_ref_for_mem_expr (t);
+             if (host_integerp (off_tree, 1))
+               offset = GEN_INT (tree_low_cst (off_tree, 1));
+             /* ??? Any reason the field size would be different than
+                the size we got from the type?  */
+           }
+       }
+    }
+
+  /* Now set the attributes we computed above.  */
+  MEM_ATTRS (ref)
+    = get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref));
+
+  /* If this is already known to be a scalar or aggregate, we are done.  */
+  if (MEM_IN_STRUCT_P (ref) || MEM_SCALAR_P (ref))
+    return;
+
+  /* If it is a reference into an aggregate, this is part of an aggregate.
+     Otherwise we don't know.  */
+  else if (TREE_CODE (t) == COMPONENT_REF || TREE_CODE (t) == ARRAY_REF
+          || TREE_CODE (t) == ARRAY_RANGE_REF
+          || TREE_CODE (t) == BIT_FIELD_REF)
+    MEM_IN_STRUCT_P (ref) = 1;
+}
+
+/* Set the alias set of MEM to SET.  */
+
+void
+set_mem_alias_set (mem, set)
+     rtx mem;
+     HOST_WIDE_INT 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 ();
+#endif
+
+  MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem),
+                                  MEM_SIZE (mem), MEM_ALIGN (mem),
+                                  GET_MODE (mem));
+}
+
+/* Set the alignment of MEM to ALIGN bits.  */
+
+void
+set_mem_align (mem, align)
+     rtx mem;
+     unsigned int align;
+{
+  MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
+                                  MEM_OFFSET (mem), MEM_SIZE (mem), align,
+                                  GET_MODE (mem));
+}
+
+/* Set the expr for MEM to EXPR.  */
+
+void
+set_mem_expr (mem, expr)
+     rtx mem;
+     tree expr;
+{
+  MEM_ATTRS (mem)
+    = get_mem_attrs (MEM_ALIAS_SET (mem), expr, MEM_OFFSET (mem),
+                    MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem));
+}
+
+/* Set the offset of MEM to OFFSET.  */
+
+void
+set_mem_offset (mem, offset)
+     rtx mem, offset;
+{
+  MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
+                                  offset, MEM_SIZE (mem), MEM_ALIGN (mem),
+                                  GET_MODE (mem));
+}
+\f
+/* Return a memory reference like MEMREF, but with its mode changed to MODE
+   and its address changed to ADDR.  (VOIDmode means don't change the mode.
+   NULL for ADDR means don't change the address.)  VALIDATE is nonzero if the
+   returned memory location is required to be valid.  The memory
+   attributes are not changed.  */
+
+static rtx
+change_address_1 (memref, mode, addr, validate)
      rtx memref;
      enum machine_mode mode;
      rtx addr;
+     int validate;
 {
   rtx new;
 
@@ -1767,16 +1906,17 @@ change_address (memref, mode, addr)
   if (addr == 0)
     addr = XEXP (memref, 0);
 
-  /* If reload is in progress or has completed, ADDR must be valid.
-     Otherwise, we can call memory_address to make it valid.  */
-  if (reload_completed || reload_in_progress)
+  if (validate)
     {
-      if (! memory_address_p (mode, addr))
-       abort ();
+      if (reload_in_progress || reload_completed)
+       {
+         if (! memory_address_p (mode, addr))
+           abort ();
+       }
+      else
+       addr = memory_address (mode, addr);
     }
-  else
-    addr = memory_address (mode, addr);
-       
+
   if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref))
     return memref;
 
@@ -1784,13 +1924,247 @@ change_address (memref, mode, addr)
   MEM_COPY_ATTRIBUTES (new, memref);
   return new;
 }
+
+/* Like change_address_1 with VALIDATE nonzero, but we are not saying in what
+   way we are changing MEMREF, so we only preserve the alias set.  */
+
+rtx
+change_address (memref, mode, addr)
+     rtx memref;
+     enum machine_mode mode;
+     rtx addr;
+{
+  rtx new = change_address_1 (memref, mode, addr, 1);
+  enum machine_mode mmode = GET_MODE (new);
+
+  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);
+
+  return new;
+}
+
+/* Return a memory reference like MEMREF, but with its mode changed
+   to MODE and its address offset by OFFSET bytes.  If VALIDATE is
+   nonzero, the memory address is forced to be valid.
+   If ADJUST is zero, OFFSET is only used to update MEM_ATTRS
+   and caller is responsible for adjusting MEMREF base register.  */
+
+rtx
+adjust_address_1 (memref, mode, offset, validate, adjust)
+     rtx memref;
+     enum machine_mode mode;
+     HOST_WIDE_INT offset;
+     int validate, adjust;
+{
+  rtx addr = XEXP (memref, 0);
+  rtx new;
+  rtx memoffset = MEM_OFFSET (memref);
+  rtx size = 0;
+  unsigned int memalign = MEM_ALIGN (memref);
+
+  /* ??? Prefer to create garbage instead of creating shared rtl.
+     This may happen even if offset is non-zero -- consider
+     (plus (plus reg reg) const_int) -- so do this always.  */
+  addr = copy_rtx (addr);
+
+  if (adjust)
+    {
+      /* If MEMREF is a LO_SUM and the offset is within the alignment of the
+        object, we can merge it into the LO_SUM.  */
+      if (GET_MODE (memref) != BLKmode && GET_CODE (addr) == LO_SUM
+         && offset >= 0
+         && (unsigned HOST_WIDE_INT) offset
+             < GET_MODE_ALIGNMENT (GET_MODE (memref)) / BITS_PER_UNIT)
+       addr = gen_rtx_LO_SUM (Pmode, XEXP (addr, 0),
+                              plus_constant (XEXP (addr, 1), offset));
+      else
+       addr = plus_constant (addr, offset);
+    }
+
+  new = change_address_1 (memref, mode, addr, validate);
+
+  /* Compute the new values of the memory attributes due to this adjustment.
+     We add the offsets and update the alignment.  */
+  if (memoffset)
+    memoffset = GEN_INT (offset + INTVAL (memoffset));
+
+  /* Compute the new alignment by taking the MIN of the alignment and the
+     lowest-order set bit in OFFSET, but don't change the alignment if OFFSET
+     if zero.  */
+  if (offset != 0)
+    memalign = MIN (memalign,
+                   (unsigned 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)));
+  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));
+
+  /* At some point, we should validate that this offset is within the object,
+     if all the appropriate values are known.  */
+  return new;
+}
+
+/* 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
+   nonzero, the memory address is forced to be valid.  */
+
+rtx
+adjust_automodify_address_1 (memref, mode, addr, offset, validate)
+     rtx memref;
+     enum machine_mode mode;
+     rtx addr;
+     HOST_WIDE_INT offset;
+     int validate;
+{
+  memref = change_address_1 (memref, VOIDmode, addr, validate);
+  return adjust_address_1 (memref, mode, offset, validate, 0);
+}
+
+/* Return a memory reference like MEMREF, but whose address is changed by
+   adding OFFSET, an RTX, to it.  POW2 is the highest power of two factor
+   known to be in OFFSET (possibly 1).  */
+
+rtx
+offset_address (memref, offset, pow2)
+     rtx memref;
+     rtx offset;
+     HOST_WIDE_INT pow2;
+{
+  rtx new = change_address_1 (memref, VOIDmode,
+                             gen_rtx_PLUS (Pmode, XEXP (memref, 0),
+                                           force_reg (Pmode, offset)), 1);
+
+  /* Update the alignment to reflect the offset.  Reset the offset, which
+     we don't know.  */
+  MEM_ATTRS (new)
+    = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), 0, 0,
+                    MIN (MEM_ALIGN (memref),
+                         (unsigned int) pow2 * BITS_PER_UNIT),
+                    GET_MODE (new));
+  return new;
+}
+  
+/* Return a memory reference like MEMREF, but with its address changed to
+   ADDR.  The caller is asserting that the actual piece of memory pointed
+   to is the same, just the form of the address is being changed, such as
+   by putting something into a register.  */
+
+rtx
+replace_equiv_address (memref, addr)
+     rtx memref;
+     rtx addr;
+{
+  /* change_address_1 copies the memory attribute structure without change
+     and that's exactly what we want here.  */
+  update_temp_slot_address (XEXP (memref, 0), addr);
+  return change_address_1 (memref, VOIDmode, addr, 1);
+}
+
+/* Likewise, but the reference is not required to be valid.  */
+
+rtx
+replace_equiv_address_nv (memref, addr)
+     rtx memref;
+     rtx addr;
+{
+  return change_address_1 (memref, VOIDmode, addr, 0);
+}
+
+/* Return a memory reference like MEMREF, but with its mode widened to
+   MODE and offset by OFFSET.  This would be used by targets that e.g.
+   cannot issue QImode memory operations and have to use SImode memory
+   operations plus masking logic.  */
+
+rtx
+widen_memory_access (memref, mode, offset)
+     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);
+  unsigned int size = GET_MODE_SIZE (mode);
+
+  /* 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 && offset != 0)
+    expr = NULL_TREE;
+
+  while (expr)
+    {
+      if (TREE_CODE (expr) == COMPONENT_REF)
+       {
+         tree field = TREE_OPERAND (expr, 1);
+
+         if (! DECL_SIZE_UNIT (field))
+           {
+             expr = NULL_TREE;
+             break;
+           }
+
+         /* Is the field at least as large as the access?  If so, ok,
+            otherwise strip back to the containing structure.  */
+         if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST
+             && compare_tree_int (DECL_SIZE_UNIT (field), size) >= 0
+             && INTVAL (memoffset) >= 0)
+           break;
+
+         if (! host_integerp (DECL_FIELD_OFFSET (field), 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)));
+       }
+      /* Similarly for the decl.  */
+      else if (DECL_P (expr)
+              && DECL_SIZE_UNIT (expr)
+              && compare_tree_int (DECL_SIZE_UNIT (expr), size) >= 0
+              && (! memoffset || INTVAL (memoffset) >= 0))
+       break;
+      else
+       {
+         /* The widened memory access overflows the expression, which means
+            that it could alias another expression.  Zap it.  */
+         expr = NULL_TREE;
+         break;
+       }
+    }
+
+  if (! expr)
+    memoffset = NULL_RTX;
+
+  /* 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);
+
+  return new;
+}
 \f
 /* Return a newly created CODE_LABEL rtx with a unique label number.  */
 
 rtx
 gen_label_rtx ()
 {
-  register rtx label;
+  rtx label;
 
   label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX,
                              NULL_RTX, label_num++, NULL, NULL);
@@ -1866,11 +2240,12 @@ free_emit_status (f)
 {
   free (f->emit->x_regno_reg_rtx);
   free (f->emit->regno_pointer_align);
+  free (f->emit->regno_decl);
   free (f->emit);
   f->emit = NULL;
 }
 \f
-/* Go through all the RTL insn bodies and copy any invalid shared 
+/* Go through all the RTL insn bodies and copy any invalid shared
    structure.  This routine should only be called once.  */
 
 void
@@ -1889,7 +2264,7 @@ unshare_all_rtl (fndecl, insn)
 
   /* Unshare just about everything else.  */
   unshare_all_rtl_1 (insn);
-  
+
   /* Make sure the addresses of stack slots found outside the insn chain
      (such as, in DECL_RTL of a variable) are not shared
      with the insn chain.
@@ -1900,7 +2275,7 @@ unshare_all_rtl (fndecl, insn)
   stack_slot_list = copy_rtx_if_shared (stack_slot_list);
 }
 
-/* Go through all the RTL insn bodies and copy any invalid shared 
+/* Go through all the RTL insn bodies and copy any invalid shared
    structure, again.  This is a fairly expensive thing to do so it
    should be done sparingly.  */
 
@@ -1966,7 +2341,7 @@ unshare_all_decls (blk)
 }
 
 /* Go through all virtual stack slots of a function and mark them as
-   not shared. */
+   not shared.  */
 static void
 reset_used_decls (blk)
      tree blk;
@@ -1990,10 +2365,10 @@ rtx
 copy_rtx_if_shared (orig)
      rtx orig;
 {
-  register rtx x = orig;
-  register int i;
-  register enum rtx_code code;
-  register const char *format_ptr;
+  rtx x = orig;
+  int i;
+  enum rtx_code code;
+  const char *format_ptr;
   int copied = 0;
 
   if (x == 0)
@@ -2037,7 +2412,7 @@ copy_rtx_if_shared (orig)
     case MEM:
       /* A MEM is allowed to be shared if its address is constant.
 
-        We used to allow sharing of MEMs which referenced 
+        We used to allow sharing of MEMs which referenced
         virtual_stack_vars_rtx or virtual_incoming_args_rtx, but
         that can lose.  instantiate_virtual_regs will not unshare
         the MEMs, and combine may change the structure of the address
@@ -2057,7 +2432,7 @@ copy_rtx_if_shared (orig)
 
   if (x->used)
     {
-      register rtx copy;
+      rtx copy;
 
       copy = rtx_alloc (code);
       memcpy (copy, x,
@@ -2086,7 +2461,7 @@ copy_rtx_if_shared (orig)
        case 'E':
          if (XVEC (x, i) != NULL)
            {
-             register int j;
+             int j;
              int len = XVECLEN (x, i);
 
              if (copied && len > 0)
@@ -2107,9 +2482,9 @@ void
 reset_used_flags (x)
      rtx x;
 {
-  register int i, j;
-  register enum rtx_code code;
-  register const char *format_ptr;
+  int i, j;
+  enum rtx_code code;
+  const char *format_ptr;
 
   if (x == 0)
     return;
@@ -2139,7 +2514,7 @@ reset_used_flags (x)
     case BARRIER:
       /* The chain of insns is not being copied.  */
       return;
-      
+
     default:
       break;
     }
@@ -2274,7 +2649,7 @@ renumber_insns (stream)
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
       if (stream)
-       fprintf (stream, "Renumbering insn %d to %d\n", 
+       fprintf (stream, "Renumbering insn %d to %d\n",
                 INSN_UID (insn), cur_insn_uid);
       INSN_UID (insn) = cur_insn_uid++;
     }
@@ -2539,9 +2914,9 @@ static void
 mark_label_nuses(x)
     rtx x;
 {
-  register enum rtx_code code;
-  register int i, j;
-  register const char *fmt;
+  enum rtx_code code;
+  int i, j;
+  const char *fmt;
 
   code = GET_CODE (x);
   if (code == LABEL_REF)
@@ -2575,9 +2950,19 @@ try_split (pat, trial, last)
 {
   rtx before = PREV_INSN (trial);
   rtx after = NEXT_INSN (trial);
-  rtx seq = split_insns (pat, trial);
   int has_barrier = 0;
   rtx tem;
+  rtx note, seq;
+  int probability;
+
+  if (any_condjump_p (trial)
+      && (note = find_reg_note (trial, REG_BR_PROB, 0)))
+    split_branch_probability = INTVAL (XEXP (note, 0));
+  probability = split_branch_probability;
+
+  seq = split_insns (pat, trial);
+
+  split_branch_probability = -1;
 
   /* If we are splitting a JUMP_INSN, it might be followed by a BARRIER.
      We may need to handle this specially.  */
@@ -2594,21 +2979,39 @@ try_split (pat, trial, last)
         it, in turn, will be split (SFmode on the 29k is an example).  */
       if (GET_CODE (seq) == SEQUENCE)
        {
-         int i;
-         rtx eh_note;
-         
-         /* Avoid infinite loop if any insn of the result matches 
+         int i, njumps = 0;
+
+         /* Avoid infinite loop if any insn of the result matches
             the original pattern.  */
          for (i = 0; i < XVECLEN (seq, 0); i++)
-           if (GET_CODE (XVECEXP (seq, 0, i)) == INSN 
+           if (GET_CODE (XVECEXP (seq, 0, i)) == INSN
                && rtx_equal_p (PATTERN (XVECEXP (seq, 0, i)), pat))
-             return trial;
+             return trial;
 
          /* Mark labels.  */
          for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
            if (GET_CODE (XVECEXP (seq, 0, i)) == JUMP_INSN)
-             mark_jump_label (PATTERN (XVECEXP (seq, 0, i)),
-                              XVECEXP (seq, 0, i), 0, 0);
+             {
+               rtx insn = XVECEXP (seq, 0, i);
+               mark_jump_label (PATTERN (insn),
+                                XVECEXP (seq, 0, i), 0);
+               njumps++;
+               if (probability != -1
+                   && any_condjump_p (insn)
+                   && !find_reg_note (insn, REG_BR_PROB, 0))
+                 {
+                   /* We can preserve the REG_BR_PROB notes only if exactly
+                      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));
+                 }
+             }
 
          /* If we are splitting a CALL_INSN, look for the CALL_INSN
             in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it.  */
@@ -2618,18 +3021,55 @@ try_split (pat, trial, last)
                CALL_INSN_FUNCTION_USAGE (XVECEXP (seq, 0, i))
                  = CALL_INSN_FUNCTION_USAGE (trial);
 
-         /* Copy EH notes.  */
-         if ((eh_note = find_reg_note (trial, REG_EH_REGION, NULL_RTX)))
-           for (i = 0; i < XVECLEN (seq, 0); i++)
-             {
-               rtx insn = XVECEXP (seq, 0, i);
-               if (GET_CODE (insn) == CALL_INSN
-                   || (flag_non_call_exceptions 
-                       && may_trap_p (PATTERN (insn))))
-                 REG_NOTES (insn) 
-                   = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (eh_note, 0),
-                                        REG_NOTES (insn));
-             }
+         /* Copy notes, particularly those related to the CFG.  */
+         for (note = REG_NOTES (trial); note ; note = XEXP (note, 1))
+           {
+             switch (REG_NOTE_KIND (note))
+               {
+               case REG_EH_REGION:
+                 for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
+                   {
+                     rtx insn = XVECEXP (seq, 0, i);
+                     if (GET_CODE (insn) == CALL_INSN
+                         || (flag_non_call_exceptions
+                             && may_trap_p (PATTERN (insn))))
+                       REG_NOTES (insn)
+                         = gen_rtx_EXPR_LIST (REG_EH_REGION,
+                                              XEXP (note, 0),
+                                              REG_NOTES (insn));
+                   }
+                 break;
+
+               case REG_NORETURN:
+               case REG_SETJMP:
+               case REG_ALWAYS_RETURN:
+                 for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
+                   {
+                     rtx insn = XVECEXP (seq, 0, i);
+                     if (GET_CODE (insn) == CALL_INSN)
+                       REG_NOTES (insn)
+                         = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
+                                              XEXP (note, 0),
+                                              REG_NOTES (insn));
+                   }
+                 break;
+
+               case REG_NON_LOCAL_GOTO:
+                 for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
+                   {
+                     rtx insn = XVECEXP (seq, 0, i);
+                     if (GET_CODE (insn) == JUMP_INSN)
+                       REG_NOTES (insn)
+                         = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
+                                              XEXP (note, 0),
+                                              REG_NOTES (insn));
+                   }
+                 break;
+
+               default:
+                 break;
+               }
+           }
 
          /* If there are LABELS inside the split insns increment the
             usage count so we don't delete the label.  */
@@ -2638,9 +3078,9 @@ try_split (pat, trial, last)
              if (GET_CODE (XVECEXP (seq, 0, i)) == INSN)
                mark_label_nuses (PATTERN (XVECEXP (seq, 0, i)));
 
-         tem = emit_insn_after (seq, before);
+         tem = emit_insn_after (seq, trial);
 
-         delete_insn (trial);
+         delete_related_insns (trial);
          if (has_barrier)
            emit_barrier_after (tem);
 
@@ -2665,9 +3105,9 @@ try_split (pat, trial, last)
 
       /* Return either the first or the last insn, depending on which was
         requested.  */
-      return last 
-               ? (after ? prev_active_insn (after) : last_insn) 
-               : next_active_insn (before);
+      return last
+               ? (after ? PREV_INSN (after) : last_insn)
+               : NEXT_INSN (before);
     }
 
   return trial;
@@ -2680,7 +3120,7 @@ rtx
 make_insn_raw (pattern)
      rtx pattern;
 {
-  register rtx insn;
+  rtx insn;
 
   insn = rtx_alloc (INSN);
 
@@ -2701,7 +3141,7 @@ make_insn_raw (pattern)
       debug_rtx (insn);
     }
 #endif
-  
+
   return insn;
 }
 
@@ -2711,7 +3151,7 @@ static rtx
 make_jump_insn_raw (pattern)
      rtx pattern;
 {
-  register rtx insn;
+  rtx insn;
 
   insn = rtx_alloc (JUMP_INSN);
   INSN_UID (insn) = cur_insn_uid++;
@@ -2731,7 +3171,7 @@ static rtx
 make_call_insn_raw (pattern)
      rtx pattern;
 {
-  register rtx insn;
+  rtx insn;
 
   insn = rtx_alloc (CALL_INSN);
   INSN_UID (insn) = cur_insn_uid++;
@@ -2750,7 +3190,7 @@ make_call_insn_raw (pattern)
 
 void
 add_insn (insn)
-     register rtx insn;
+     rtx insn;
 {
   PREV_INSN (insn) = last_insn;
   NEXT_INSN (insn) = 0;
@@ -2774,6 +3214,7 @@ add_insn_after (insn, after)
      rtx insn, after;
 {
   rtx next = NEXT_INSN (after);
+  basic_block bb;
 
   if (optimize && INSN_DELETED_P (after))
     abort ();
@@ -2804,6 +3245,21 @@ add_insn_after (insn, after)
        abort ();
     }
 
+  if (basic_block_for_insn
+      && (unsigned int)INSN_UID (after) < basic_block_for_insn->num_elements
+      && (bb = BLOCK_FOR_INSN (after)))
+    {
+      set_block_for_insn (insn, bb);
+      /* Should not happen as first in the BB is always
+        either NOTE or LABEL.  */
+      if (bb->end == 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;
+    }
+
   NEXT_INSN (after) = insn;
   if (GET_CODE (after) == INSN && GET_CODE (PATTERN (after)) == SEQUENCE)
     {
@@ -2822,6 +3278,7 @@ add_insn_before (insn, before)
      rtx insn, before;
 {
   rtx prev = PREV_INSN (before);
+  basic_block bb;
 
   if (optimize && INSN_DELETED_P (before))
     abort ();
@@ -2855,6 +3312,21 @@ add_insn_before (insn, before)
        abort ();
     }
 
+  if (basic_block_for_insn
+      && (unsigned int)INSN_UID (before) < basic_block_for_insn->num_elements
+      && (bb = BLOCK_FOR_INSN (before)))
+    {
+      set_block_for_insn (insn, bb);
+      /* 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 ();
+    }
+
   PREV_INSN (before) = insn;
   if (GET_CODE (before) == INSN && GET_CODE (PATTERN (before)) == SEQUENCE)
     PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn;
@@ -2868,6 +3340,8 @@ remove_insn (insn)
 {
   rtx next = NEXT_INSN (insn);
   rtx prev = PREV_INSN (insn);
+  basic_block bb;
+
   if (prev)
     {
       NEXT_INSN (prev) = next;
@@ -2916,6 +3390,21 @@ remove_insn (insn)
       if (stack == 0)
        abort ();
     }
+  if (basic_block_for_insn
+      && (unsigned int)INSN_UID (insn) < basic_block_for_insn->num_elements
+      && (bb = BLOCK_FOR_INSN (insn)))
+    {
+      if (bb->head == insn)
+       {
+         /* Never ever delete the basic block note without deleting whole basic
+            block.  */
+         if (GET_CODE (insn) == NOTE)
+           abort ();
+         bb->head = next;
+       }
+      if (bb->end == insn)
+       bb->end = prev;
+    }
 }
 
 /* Delete all insns made since FROM.
@@ -2943,7 +3432,7 @@ delete_insns_since (from)
    called after delay-slot filling has been done.  */
 
 void
-reorder_insns (from, to, after)
+reorder_insns_nobb (from, to, after)
      rtx from, to, after;
 {
   /* Splice this bunch out of where it is now.  */
@@ -2967,6 +3456,38 @@ reorder_insns (from, to, after)
     last_insn = to;
 }
 
+/* Same as function above, but take care to update BB boundaries.  */
+void
+reorder_insns (from, to, after)
+     rtx from, to, after;
+{
+  rtx prev = PREV_INSN (from);
+  basic_block bb, bb2;
+
+  reorder_insns_nobb (from, to, after);
+
+  if (basic_block_for_insn
+      && (unsigned int)INSN_UID (after) < basic_block_for_insn->num_elements
+      && (bb = BLOCK_FOR_INSN (after)))
+    {
+      rtx x;
+      if (basic_block_for_insn
+         && (unsigned int)INSN_UID (from) < basic_block_for_insn->num_elements
+         && (bb2 = BLOCK_FOR_INSN (from)))
+       {
+         if (bb2->end == to)
+           bb2->end = prev;
+       }
+
+      if (bb->end == after)
+       bb->end = 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
@@ -3093,9 +3614,13 @@ remove_unnecessary_notes ()
 
              if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_BEG)
                {
-                 /* We just verified that this BLOCK matches us
-                    with the block_stack check above.  */
-                 if (debug_ignore_block (NOTE_BLOCK (insn)))
+                 /* 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);
@@ -3126,13 +3651,13 @@ remove_unnecessary_notes ()
 
 rtx
 emit_insn_before (pattern, before)
-     register rtx pattern, before;
+     rtx pattern, before;
 {
-  register rtx insn = before;
+  rtx insn = before;
 
   if (GET_CODE (pattern) == SEQUENCE)
     {
-      register int i;
+      int i;
 
       for (i = 0; i < XVECLEN (pattern, 0); i++)
        {
@@ -3149,28 +3674,14 @@ emit_insn_before (pattern, before)
   return insn;
 }
 
-/* Similar to emit_insn_before, but update basic block boundaries as well.  */
-
-rtx
-emit_block_insn_before (pattern, before, block)
-     rtx pattern, before;
-     basic_block block;
-{
-  rtx prev = PREV_INSN (before);
-  rtx r = emit_insn_before (pattern, before);
-  if (block && block->head == before)
-    block->head = NEXT_INSN (prev);
-  return r;
-}
-
 /* Make an instruction with body PATTERN and code JUMP_INSN
    and output it before the instruction BEFORE.  */
 
 rtx
 emit_jump_insn_before (pattern, before)
-     register rtx pattern, before;
+     rtx pattern, before;
 {
-  register rtx insn;
+  rtx insn;
 
   if (GET_CODE (pattern) == SEQUENCE)
     insn = emit_insn_before (pattern, before);
@@ -3188,9 +3699,9 @@ emit_jump_insn_before (pattern, before)
 
 rtx
 emit_call_insn_before (pattern, before)
-     register rtx pattern, before;
+     rtx pattern, before;
 {
-  register rtx insn;
+  rtx insn;
 
   if (GET_CODE (pattern) == SEQUENCE)
     insn = emit_insn_before (pattern, before);
@@ -3209,9 +3720,9 @@ emit_call_insn_before (pattern, before)
 
 rtx
 emit_barrier_before (before)
-     register rtx before;
+     rtx before;
 {
-  register rtx insn = rtx_alloc (BARRIER);
+  rtx insn = rtx_alloc (BARRIER);
 
   INSN_UID (insn) = cur_insn_uid++;
 
@@ -3243,7 +3754,7 @@ emit_note_before (subtype, before)
      int subtype;
      rtx before;
 {
-  register rtx note = rtx_alloc (NOTE);
+  rtx note = rtx_alloc (NOTE);
   INSN_UID (note) = cur_insn_uid++;
   NOTE_SOURCE_FILE (note) = 0;
   NOTE_LINE_NUMBER (note) = subtype;
@@ -3257,13 +3768,13 @@ emit_note_before (subtype, before)
 
 rtx
 emit_insn_after (pattern, after)
-     register rtx pattern, after;
+     rtx pattern, after;
 {
-  register rtx insn = after;
+  rtx insn = after;
 
   if (GET_CODE (pattern) == SEQUENCE)
     {
-      register int i;
+      int i;
 
       for (i = 0; i < XVECLEN (pattern, 0); i++)
        {
@@ -3303,27 +3814,14 @@ emit_insn_after_with_line_notes (pattern, after, from)
                          insn);
 }
 
-/* Similar to emit_insn_after, but update basic block boundaries as well.  */
-
-rtx
-emit_block_insn_after (pattern, after, block)
-     rtx pattern, after;
-     basic_block block;
-{
-  rtx r = emit_insn_after (pattern, after);
-  if (block && block->end == after)
-    block->end = r;
-  return r;
-}
-
 /* Make an insn of code JUMP_INSN with body PATTERN
    and output it after the insn AFTER.  */
 
 rtx
 emit_jump_insn_after (pattern, after)
-     register rtx pattern, after;
+     rtx pattern, after;
 {
-  register rtx insn;
+  rtx insn;
 
   if (GET_CODE (pattern) == SEQUENCE)
     insn = emit_insn_after (pattern, after);
@@ -3341,9 +3839,9 @@ emit_jump_insn_after (pattern, after)
 
 rtx
 emit_barrier_after (after)
-     register rtx after;
+     rtx after;
 {
-  register rtx insn = rtx_alloc (BARRIER);
+  rtx insn = rtx_alloc (BARRIER);
 
   INSN_UID (insn) = cur_insn_uid++;
 
@@ -3376,7 +3874,7 @@ emit_note_after (subtype, after)
      int subtype;
      rtx after;
 {
-  register rtx note = rtx_alloc (NOTE);
+  rtx note = rtx_alloc (NOTE);
   INSN_UID (note) = cur_insn_uid++;
   NOTE_SOURCE_FILE (note) = 0;
   NOTE_LINE_NUMBER (note) = subtype;
@@ -3392,7 +3890,7 @@ emit_line_note_after (file, line, after)
      int line;
      rtx after;
 {
-  register rtx note;
+  rtx note;
 
   if (no_line_numbers && line > 0)
     {
@@ -3423,7 +3921,7 @@ emit_insn (pattern)
 
   if (GET_CODE (pattern) == SEQUENCE)
     {
-      register int i;
+      int i;
 
       for (i = 0; i < XVECLEN (pattern, 0); i++)
        {
@@ -3486,20 +3984,32 @@ emit_insns_before (insn, before)
 
 rtx
 emit_insns_after (first, after)
-     register rtx first;
-     register rtx after;
+     rtx first;
+     rtx after;
 {
-  register rtx last;
-  register rtx after_after;
+  rtx last;
+  rtx after_after;
+  basic_block bb;
 
   if (!after)
     abort ();
 
   if (!first)
-    return first;
+    return after;
 
-  for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
-    continue;
+  if (basic_block_for_insn
+      && (unsigned int)INSN_UID (after) < basic_block_for_insn->num_elements
+      && (bb = BLOCK_FOR_INSN (after)))
+    {
+      for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
+       set_block_for_insn (last, bb);
+      set_block_for_insn (last, bb);
+      if (bb->end == after)
+       bb->end = last;
+    }
+  else
+    for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
+      continue;
 
   after_after = NEXT_INSN (after);
 
@@ -3525,7 +4035,7 @@ emit_jump_insn (pattern)
     return emit_insn (pattern);
   else
     {
-      register rtx insn = make_jump_insn_raw (pattern);
+      rtx insn = make_jump_insn_raw (pattern);
       add_insn (insn);
       return insn;
     }
@@ -3542,7 +4052,7 @@ emit_call_insn (pattern)
     return emit_insn (pattern);
   else
     {
-      register rtx insn = make_call_insn_raw (pattern);
+      rtx insn = make_call_insn_raw (pattern);
       add_insn (insn);
       PUT_CODE (insn, CALL_INSN);
       return insn;
@@ -3572,7 +4082,7 @@ emit_label (label)
 rtx
 emit_barrier ()
 {
-  register rtx barrier = rtx_alloc (BARRIER);
+  rtx barrier = rtx_alloc (BARRIER);
   INSN_UID (barrier) = cur_insn_uid++;
   add_insn (barrier);
   return barrier;
@@ -3608,7 +4118,7 @@ emit_note (file, line)
      const char *file;
      int line;
 {
-  register rtx note;
+  rtx note;
 
   if (line > 0)
     {
@@ -3654,9 +4164,9 @@ force_next_line_note ()
 }
 
 /* Place a note of KIND on insn INSN with DATUM as the datum. If a
-   note of this type already exists, remove it first. */
+   note of this type already exists, remove it first.  */
 
-void 
+rtx
 set_unique_reg_note (insn, kind, datum)
      rtx insn;
      enum reg_note kind;
@@ -3664,11 +4174,39 @@ set_unique_reg_note (insn, kind, datum)
 {
   rtx note = find_reg_note (insn, kind, NULL_RTX);
 
-  /* First remove the note if there already is one.  */
-  if (note) 
-    remove_note (insn, note);
+  switch (kind)
+    {
+    case REG_EQUAL:
+    case REG_EQUIV:
+      /* Don't add REG_EQUAL/REG_EQUIV notes if the insn
+        has multiple sets (some callers assume single_set
+        means the insn only has one set, when in fact it
+        means the insn only has one * useful * set).  */
+      if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn))
+       {
+         if (note)
+           abort ();
+         return NULL_RTX;
+       }
+
+      /* Don't add ASM_OPERAND REG_EQUAL/REG_EQUIV notes.
+        It serves no useful purpose and breaks eliminate_regs.  */
+      if (GET_CODE (datum) == ASM_OPERANDS)
+       return NULL_RTX;
+      break;
+
+    default:
+      break;
+    }
+
+  if (note)
+    {
+      XEXP (note, 0) = datum;
+      return note;
+    }
 
   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.
@@ -3695,7 +4233,7 @@ classify_insn (x)
     }
   if (GET_CODE (x) == PARALLEL)
     {
-      register int j;
+      int j;
       for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
        if (GET_CODE (XVECEXP (x, 0, j)) == CALL)
          return CALL_INSN;
@@ -3724,7 +4262,7 @@ emit (x)
     return emit_insn (x);
   else if (code == JUMP_INSN)
     {
-      register rtx insn = emit_jump_insn (x);
+      rtx insn = emit_jump_insn (x);
       if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN)
        return emit_barrier ();
       return insn;
@@ -3845,7 +4383,7 @@ pop_topmost_sequence ()
 /* After emitting to a sequence, restore previous saved state.
 
    To get the contents of the sequence just made, you must call
-   `gen_sequence' *before* calling here.  
+   `gen_sequence' *before* calling here.
 
    If the compiler might have deferred popping arguments while
    generating this sequence, and this sequence will not be immediately
@@ -3909,13 +4447,13 @@ gen_sequence ()
 
   /* If only one insn, return it rather than a SEQUENCE.
      (Now that we cache SEQUENCE expressions, it isn't worth special-casing
-     the case of an empty list.)     
+     the case of an empty list.)
      We only return the pattern of an insn if its code is INSN and it
      has no notes.  This ensures that no information gets lost.  */
   if (len == 1
       && ! RTX_FRAME_RELATED_P (first_insn)
       && GET_CODE (first_insn) == INSN
-      /* Don't throw away any reg notes. */
+      /* Don't throw away any reg notes.  */
       && REG_NOTES (first_insn) == 0)
     return PATTERN (first_insn);
 
@@ -3981,12 +4519,12 @@ static rtvec copy_asm_constraints_vector;
 
 rtx
 copy_insn_1 (orig)
-     register rtx orig;
+     rtx orig;
 {
-  register rtx copy;
-  register int i, j;
-  register RTX_CODE code;
-  register const char *format_ptr;
+  rtx copy;
+  int i, j;
+  RTX_CODE code;
+  const char *format_ptr;
 
   code = GET_CODE (orig);
 
@@ -4017,7 +4555,7 @@ copy_insn_1 (orig)
          && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
        return orig;
       break;
-      
+
       /* A MEM with a constant address is not sharable.  The problem is that
         the constant address may need to be reloaded.  If the mem is shared,
         then reloading one copy of this mem will cause all copies to appear
@@ -4046,7 +4584,7 @@ copy_insn_1 (orig)
       copy->call = 0;
       copy->frame_related = 0;
     }
-  
+
   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
 
   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
@@ -4154,9 +4692,11 @@ init_emit ()
     = (unsigned char *) xcalloc (f->emit->regno_pointer_align_length,
                                 sizeof (unsigned char));
 
-  regno_reg_rtx 
-    = (rtx *) xcalloc (f->emit->regno_pointer_align_length * sizeof (rtx),
-                      sizeof (rtx));
+  regno_reg_rtx
+    = (rtx *) xcalloc (f->emit->regno_pointer_align_length, sizeof (rtx));
+
+  f->emit->regno_decl
+    = (tree *) xcalloc (f->emit->regno_pointer_align_length, sizeof (tree));
 
   /* Put copies of all the virtual register rtx into regno_reg_rtx.  */
   init_virtual_regs (f->emit);
@@ -4213,14 +4753,19 @@ mark_emit_status (es)
      struct emit_status *es;
 {
   rtx *r;
+  tree *t;
   int i;
 
   if (es == 0)
     return;
 
-  for (i = es->regno_pointer_align_length, r = es->x_regno_reg_rtx;
-       i > 0; --i, ++r)
-    ggc_mark_rtx (*r);
+  for (i = es->regno_pointer_align_length, r = es->x_regno_reg_rtx,
+       t = es->regno_decl;
+       i > 0; --i, ++r, ++t)
+    {
+      ggc_mark_rtx (*r);
+      ggc_mark_tree (*t);
+    }
 
   mark_sequence_stack (es->sequence_stack);
   ggc_mark_tree (es->sequence_rtl_expr);
@@ -4238,11 +4783,14 @@ init_emit_once (line_numbers)
   enum machine_mode mode;
   enum machine_mode double_mode;
 
-  /* Initialize the CONST_INT hash table.  */
-  const_int_htab = htab_create (37, const_int_htab_hash, 
+  /* Initialize the CONST_INT and memory attribute hash tables.  */
+  const_int_htab = htab_create (37, const_int_htab_hash,
                                const_int_htab_eq, NULL);
-  ggc_add_root (&const_int_htab, 1, sizeof (const_int_htab), 
-               rtx_htab_mark);
+  ggc_add_deletable_htab (const_int_htab, 0, 0);
+
+  mem_attrs_htab = htab_create (37, mem_attrs_htab_hash,
+                               mem_attrs_htab_eq, NULL);
+  ggc_add_deletable_htab (mem_attrs_htab, 0, mem_attrs_mark);
 
   no_line_numbers = ! line_numbers;
 
@@ -4283,18 +4831,18 @@ init_emit_once (line_numbers)
   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_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 = 
+  virtual_incoming_args_rtx =
     gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
-  virtual_stack_vars_rtx = 
+  virtual_stack_vars_rtx =
     gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
-  virtual_stack_dynamic_rtx = 
+  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_outgoing_args_rtx =
+    gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);
   virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
 
   /* These rtx must be roots if GC is enabled.  */
@@ -4303,7 +4851,7 @@ init_emit_once (line_numbers)
 #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
-     end which calls push_function_context_to before the first cal to
+     end which calls push_function_context_to before the first call to
      init_function_start.  */
   INIT_EXPANDERS;
 #endif
@@ -4313,7 +4861,7 @@ init_emit_once (line_numbers)
   /* Don't use gen_rtx here since gen_rtx in this case
      tries to use these variables.  */
   for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
-    const_int_rtx[i + MAX_SAVED_CONST_INT] = 
+    const_int_rtx[i + MAX_SAVED_CONST_INT] =
       gen_rtx_raw_CONST_INT (VOIDmode, i);
   ggc_add_rtx_root (const_int_rtx, 2 * MAX_SAVED_CONST_INT + 1);
 
@@ -4347,7 +4895,6 @@ init_emit_once (line_numbers)
            CONST_DOUBLE_HIGH (tem) = 0;
 
          memcpy (&CONST_DOUBLE_LOW (tem), &u, sizeof u);
-         CONST_DOUBLE_MEM (tem) = cc0_rtx;
          CONST_DOUBLE_CHAIN (tem) = NULL_RTX;
          PUT_MODE (tem, mode);