OSDN Git Service

* function.c (keep_stack_depressed): Don't use delete_insn.
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index e1e26df..eeb5128 100644 (file)
@@ -2,22 +2,22 @@
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001 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,7 @@ Boston, MA 02111-1307, USA.  */
 #include "bitmap.h"
 #include "basic-block.h"
 #include "ggc.h"
+#include "debug.h"
 
 /* Commonly used modes.  */
 
@@ -114,7 +115,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 +144,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:
 
@@ -181,9 +185,16 @@ 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));
 
+/* 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 +217,83 @@ 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)
+         ^ (long) p->decl);
+}
+
+/* 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->decl == q->decl && 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;
+{
+  mem_attrs *p = (mem_attrs *) x;
+
+  if (p->decl)
+    ggc_mark_tree (p->decl);
+
+  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.  */
+
+static mem_attrs *
+get_mem_attrs (alias, decl, offset, size, align)
+     HOST_WIDE_INT alias;
+     tree decl;
+     rtx offset;
+     rtx size;
+     unsigned int align;
 {
-  htab_traverse (*((htab_t *) htab), rtx_htab_mark_1, NULL);
+  mem_attrs attrs;
+  void **slot;
+
+  attrs.alias = alias;
+  attrs.decl = decl;
+  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
@@ -345,7 +413,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 +440,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 +474,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 +487,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);
-
-#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)
     {
@@ -516,7 +566,7 @@ gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
       break;
     }
 
-  va_end (p);
+  VA_CLOSE (p);
   return rt_val;
 }
 
@@ -530,18 +580,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 +593,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
@@ -573,7 +619,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.  */
@@ -734,7 +779,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,
@@ -761,16 +806,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 +827,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 +866,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 +955,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 +985,7 @@ gen_lowpart_common (mode, x)
        }
       else
        {
-         low = CONST_DOUBLE_LOW (x); 
+         low = CONST_DOUBLE_LOW (x);
          high = CONST_DOUBLE_HIGH (x);
        }
 
@@ -1021,23 +1009,21 @@ gen_lowpart_common (mode, x)
       int endian = WORDS_BIG_ENDIAN ? 1 : 0;
 
       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
-      switch (GET_MODE (x))
+      switch (GET_MODE_BITSIZE (GET_MODE (x)))
        {
-       case SFmode:
+       case 32:
          REAL_VALUE_TO_TARGET_SINGLE (r, i[endian]);
          i[1 - endian] = 0;
          break;
-       case DFmode:
+       case 64:
          REAL_VALUE_TO_TARGET_DOUBLE (r, i);
          break;
-#if LONG_DOUBLE_TYPE_SIZE == 96
-       case XFmode:
+       case 96:
          REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i + endian);
          i[3-3*endian] = 0;
-#else
-       case TFmode:
+         break;
+       case 128:
          REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i);
-#endif
          break;
        default:
          abort ();
@@ -1057,19 +1043,22 @@ gen_lowpart_common (mode, x)
        for (c = 0; c < 4; c++)
          i[c] &= ~ (0L);
 
-       switch (GET_MODE (x))
+       switch (GET_MODE_BITSIZE (GET_MODE (x)))
          {
-         case SFmode:
-         case DFmode:
+         case 32:
+         case 64:
            return immed_double_const (((unsigned long) i[endian]) |
                                       (((HOST_WIDE_INT) i[1-endian]) << 32),
                                       0, mode);
-         default:
+         case 96:
+         case 128:
            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);
+         default:
+           abort ();
          }
       }
 #endif
@@ -1088,12 +1077,10 @@ gen_realpart (mode, x)
      enum machine_mode mode;
      register 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");
   else if (WORDS_BIG_ENDIAN)
@@ -1110,9 +1097,7 @@ gen_imagpart (mode, x)
      enum machine_mode mode;
      register 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
@@ -1178,7 +1163,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,7 +1171,7 @@ 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
@@ -1195,109 +1180,86 @@ gen_highpart (mode, x)
      register 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 (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 +1275,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
 
@@ -1497,10 +1459,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 +1515,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 +1533,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)
+      if (! validate_address)
+       return new;
+
+      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 +1631,116 @@ reverse_comparison (insn)
     }
 }
 \f
+
+/* 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;
+{
+  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);
+
+  /* Get the alias set from the expression or type (perhaps using a
+     front-end routine) and then copy bits from the type.  */
+
+  /* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY (type)
+     here, because, in C and C++, the fact that a location is accessed
+     through a const expression does not mean that the value there can
+     never change.  */
+
+  /* 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 ();
+
+  set_mem_alias_set (ref, get_alias_set (t));
+
+  MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type);
+  MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type);
+
+  /* If we are making an object of this type, we know that it is a scalar if
+     the type is not an aggregate.  */
+  if (objectp && ! AGGREGATE_TYPE_P (type))
+    MEM_SCALAR_P (ref) = 1;
+
+  /* If T is a type, this is all we can do.  Otherwise, we may be able
+     to deduce some more information about the expression.  */
+  if (TYPE_P (t))
+    return;
+
+  maybe_set_unchanging (ref, t);
+  if (TREE_THIS_VOLATILE (t))
+    MEM_VOLATILE_P (ref) = 1;
+
+  /* Now see if we can say more about whether it's an aggregate or
+     scalar.  If we already know it's an aggregate, don't bother.  */
+  if (MEM_IN_STRUCT_P (ref))
+    return;
+
+  /* Now remove any NOPs: 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) == SAVE_EXPR)
+    t = TREE_OPERAND (t, 0);
+
+  /* Since we already know the type isn't an aggregate, if this is a decl,
+     it must be a scalar.  Or if it is a reference into an aggregate,
+     this is part of an aggregate.   Otherwise we don't know.  */
+  if (DECL_P (t))
+    MEM_SCALAR_P (ref) = 1;
+  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;
+{
+  /* It would be nice to enable this check, but we can't quite yet.  */
+#if 0
+#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
+#endif
+
+  MEM_ATTRS (mem) = get_mem_attrs (set, MEM_DECL (mem), MEM_OFFSET (mem),
+                                  MEM_SIZE (mem), MEM_ALIGN (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.)  */
+   NULL for ADDR means don't change the address.)
+   VALIDATE is nonzero if the returned memory location is required to be
+   valid.  */
 
 rtx
-change_address (memref, mode, addr)
+change_address_1 (memref, mode, addr, validate)
      rtx memref;
      enum machine_mode mode;
      rtx addr;
+     int validate;
 {
   rtx new;
 
@@ -1767,16 +1751,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,6 +1769,88 @@ change_address (memref, mode, addr)
   MEM_COPY_ATTRIBUTES (new, memref);
   return new;
 }
+
+/* Return a memory reference like MEMREF, but with its mode changed
+   to MODE and its address offset by OFFSET bytes.  */
+
+rtx
+adjust_address (memref, mode, offset)
+     rtx memref;
+     enum machine_mode mode;
+     HOST_WIDE_INT offset;
+{
+  /* For now, this is just a wrapper for change_address, but eventually
+     will do memref tracking.  */
+  rtx addr = XEXP (memref, 0);
+
+  /* ??? Prefer to create garbage instead of creating shared rtl.  */
+  addr = copy_rtx (addr);
+
+  /* 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);
+
+  return change_address (memref, mode, addr);
+}
+
+/* Likewise, but the reference is not required to be valid.  */
+
+rtx
+adjust_address_nv (memref, mode, offset)
+     rtx memref;
+     enum machine_mode mode;
+     HOST_WIDE_INT offset;
+{
+  /* For now, this is just a wrapper for change_address, but eventually
+     will do memref tracking.  */
+  rtx addr = XEXP (memref, 0);
+
+  /* If MEMREF is a LO_SUM and the offset is within the size 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 (mode, XEXP (addr, 0),
+                          plus_constant (XEXP (addr, 1), offset));
+  else
+    addr = plus_constant (addr, offset);
+
+  return change_address_1 (memref, mode, addr, 0);
+}
+
+/* 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;
+{
+  /* For now, this is just a wrapper for change_address, but eventually
+     will do memref tracking.  */
+  return change_address (memref, VOIDmode, addr);
+}
+/* Likewise, but the reference is not required to be valid.  */
+
+rtx
+replace_equiv_address_nv (memref, addr)
+     rtx memref;
+     rtx addr;
+{
+  /* For now, this is just a wrapper for change_address, but eventually
+     will do memref tracking.  */
+  return change_address_1 (memref, VOIDmode, addr, 0);
+}
 \f
 /* Return a newly created CODE_LABEL rtx with a unique label number.  */
 
@@ -1870,7 +1937,7 @@ free_emit_status (f)
   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 +1956,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 +1967,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 +2033,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;
@@ -2037,7 +2104,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
@@ -2139,7 +2206,7 @@ reset_used_flags (x)
     case BARRIER:
       /* The chain of insns is not being copied.  */
       return;
-      
+
     default:
       break;
     }
@@ -2274,7 +2341,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++;
     }
@@ -2575,9 +2642,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 +2671,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 machinde 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 +2713,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 +2770,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 +2797,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;
@@ -2701,7 +2833,7 @@ make_insn_raw (pattern)
       debug_rtx (insn);
     }
 #endif
-  
+
   return insn;
 }
 
@@ -2774,6 +2906,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 +2937,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
+        eigther 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 +2970,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 +3004,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
+        eigther 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 +3032,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 +3082,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 +3124,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 +3148,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 +3306,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);
@@ -3149,20 +3366,6 @@ 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.  */
 
@@ -3303,19 +3506,6 @@ 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.  */
 
@@ -3491,15 +3681,27 @@ emit_insns_after (first, after)
 {
   register rtx last;
   register 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);
 
@@ -3654,9 +3856,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 
+void
 set_unique_reg_note (insn, kind, datum)
      rtx insn;
      enum reg_note kind;
@@ -3665,7 +3867,7 @@ 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) 
+  if (note)
     remove_note (insn, note);
 
   REG_NOTES (insn) = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
@@ -3845,7 +4047,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 +4111,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);
 
@@ -4017,7 +4219,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 +4248,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,7 +4356,7 @@ init_emit ()
     = (unsigned char *) xcalloc (f->emit->regno_pointer_align_length,
                                 sizeof (unsigned char));
 
-  regno_reg_rtx 
+  regno_reg_rtx
     = (rtx *) xcalloc (f->emit->regno_pointer_align_length * sizeof (rtx),
                       sizeof (rtx));
 
@@ -4238,11 +4440,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 +4488,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.  */
@@ -4313,7 +4518,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);
 
@@ -4336,9 +4541,16 @@ init_emit_once (line_numbers)
          rtx tem = rtx_alloc (CONST_DOUBLE);
          union real_extract u;
 
-         memset ((char *) &u, 0, sizeof u);  /* Zero any holes in a structure.  */
+         /* Zero any holes in a structure.  */
+         memset ((char *) &u, 0, sizeof u);
          u.d = i == 0 ? dconst0 : i == 1 ? dconst1 : dconst2;
 
+         /* Avoid trailing garbage in the rtx.  */
+         if (sizeof (u) < sizeof (HOST_WIDE_INT))
+           CONST_DOUBLE_LOW (tem) = 0;
+         if (sizeof (u) < 2 * sizeof (HOST_WIDE_INT))
+           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;