OSDN Git Service

* cppinit.c (cpp_start_read): Free the imacros list as we
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 7b715c6..d04e3d2 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.
@@ -177,12 +178,17 @@ static void mark_sequence_stack         PARAMS ((struct sequence_stack *));
 static void unshare_all_rtl_1          PARAMS ((rtx));
 static void unshare_all_decls          PARAMS ((tree));
 static void reset_used_decls           PARAMS ((tree));
+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 *));
 
+/* 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).  */
 
@@ -373,29 +379,19 @@ gen_rtx_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. */
+ * 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])
@@ -415,7 +411,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,
@@ -428,21 +424,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)
     {
@@ -515,7 +503,7 @@ gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
       break;
     }
 
-  va_end (p);
+  VA_CLOSE (p);
   return rt_val;
 }
 
@@ -529,18 +517,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...     */
@@ -549,9 +530,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
@@ -718,7 +702,7 @@ subreg_hard_regno (x, check_mode)
   base_regno = REGNO (reg);
   if (base_regno >= FIRST_PSEUDO_REGISTER)
     abort ();
-  if (! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
+  if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
     abort ();
 
   /* Catch non-congruent offsets too.  */
@@ -733,7 +717,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,
@@ -760,16 +744,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
@@ -790,61 +765,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
@@ -881,7 +804,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
@@ -970,18 +893,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)
     {
@@ -996,7 +923,7 @@ gen_lowpart_common (mode, x)
        }
       else
        {
-         low = CONST_DOUBLE_LOW (x); 
+         low = CONST_DOUBLE_LOW (x);
          high = CONST_DOUBLE_HIGH (x);
        }
 
@@ -1020,23 +947,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 ();
@@ -1056,19 +981,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
@@ -1087,12 +1015,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)
@@ -1109,9 +1035,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
@@ -1177,7 +1101,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));
@@ -1185,7 +1109,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
@@ -1194,88 +1118,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)
+  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.  */
+
+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 (difference > 0)
     {
-      int offset = 0;
+      if (WORDS_BIG_ENDIAN)
+       offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+      if (BYTES_BIG_ENDIAN)
+       offset += difference % UNITS_PER_WORD;
+    }
 
-      if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
-       abort ();
+  return offset;
+}
 
-      if ((! WORDS_BIG_ENDIAN || ! BYTES_BIG_ENDIAN)
-         && xsize > msize)
-       {
-         int difference = xsize - msize;
+/* 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 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 (GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
+     abort ();
+
+  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 X, assumed to be a SUBREG,
@@ -1286,24 +1208,13 @@ int
 subreg_lowpart_p (x)
      rtx x;
 {
-  unsigned int offset = 0;
-  int difference = (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
-                   - GET_MODE_SIZE (GET_MODE (x)));
-
   if (GET_CODE (x) != SUBREG)
     return 1;
   else if (GET_MODE (SUBREG_REG (x)) == VOIDmode)
     return 0;
 
-  if (difference > 0)
-    {
-      if (WORDS_BIG_ENDIAN)
-       offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
-      if (BYTES_BIG_ENDIAN)
-       offset += difference % UNITS_PER_WORD;
-    }
-
-  return SUBREG_BYTE (x) == offset;
+  return (subreg_lowpart_offset (GET_MODE (x), GET_MODE (SUBREG_REG (x)))
+         == SUBREG_BYTE (x));
 }
 \f
 
@@ -1368,7 +1279,7 @@ constant_subword (op, offset, mode)
          val = k[offset >> 1];
          if ((offset & 1) == ! WORDS_BIG_ENDIAN)
            val >>= 16;
-         val &= 0xffff;
+         val = ((val & 0xffff) ^ 0x8000) - 0x8000;
          return GEN_INT (val);
        }
       else
@@ -1447,7 +1358,7 @@ constant_subword (op, offset, mode)
        {
          if ((offset & 1) == ! WORDS_BIG_ENDIAN)
            val >>= 16;
-         val &= 0xffff;
+         val = ((val & 0xffff) ^ 0x8000) - 0x8000;
        }
 
       return GEN_INT (val);
@@ -1486,10 +1397,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
@@ -1542,7 +1453,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)
@@ -1557,121 +1471,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.  */
 
@@ -1739,13 +1572,16 @@ reverse_comparison (insn)
 /* 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;
 
@@ -1756,16 +1592,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;
 
@@ -1773,6 +1610,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 (mode, 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.  */
 
@@ -1782,7 +1701,7 @@ gen_label_rtx ()
   register rtx label;
 
   label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX,
-                             NULL_RTX, label_num++, NULL_PTR, NULL_PTR);
+                             NULL_RTX, label_num++, NULL, NULL);
 
   LABEL_NUSES (label) = 0;
   LABEL_ALTERNATE_NAME (label) = NULL;
@@ -1859,7 +1778,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
@@ -1878,7 +1797,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.
@@ -1889,7 +1808,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.  */
 
@@ -1955,7 +1874,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;
@@ -2026,7 +1945,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
@@ -2128,7 +2047,7 @@ reset_used_flags (x)
     case BARRIER:
       /* The chain of insns is not being copied.  */
       return;
-      
+
     default:
       break;
     }
@@ -2263,7 +2182,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++;
     }
@@ -2521,6 +2440,32 @@ prev_cc0_setter (insn)
   return insn;
 }
 #endif
+
+/* Increment the label uses for all labels present in rtx.  */
+
+static void
+mark_label_nuses(x)
+    rtx x;
+{
+  register enum rtx_code code;
+  register int i, j;
+  register const char *fmt;
+
+  code = GET_CODE (x);
+  if (code == LABEL_REF)
+    LABEL_NUSES (XEXP (x, 0))++;
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+        mark_label_nuses (XEXP (x, i));
+      else if (fmt[i] == 'E')
+        for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         mark_label_nuses (XVECEXP (x, i, j));
+    }
+}
+
 \f
 /* Try splitting insns that can be split for better scheduling.
    PAT is the pattern which might split.
@@ -2538,9 +2483,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.  */
@@ -2557,21 +2512,40 @@ 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;
+         int i, njumps = 0;
+         rtx eh_note;
 
-         /* Avoid infinite loop if any insn of the result matches 
+         /* 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.  */
          if (GET_CODE (trial) == CALL_INSN)
@@ -2580,6 +2554,26 @@ 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));
+             }
+
+         /* If there are LABELS inside the split insns increment the
+            usage count so we don't delete the label.  */
+         if (GET_CODE (trial) == INSN)
+           for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
+             if (GET_CODE (XVECEXP (seq, 0, i)) == INSN)
+               mark_label_nuses (PATTERN (XVECEXP (seq, 0, i)));
+
          tem = emit_insn_after (seq, before);
 
          delete_insn (trial);
@@ -2607,9 +2601,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;
@@ -2643,7 +2637,7 @@ make_insn_raw (pattern)
       debug_rtx (insn);
     }
 #endif
-  
+
   return insn;
 }
 
@@ -3035,9 +3029,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);
@@ -3596,9 +3594,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;
@@ -3607,7 +3605,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));
@@ -3787,7 +3785,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
@@ -3851,13 +3849,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);
 
@@ -3959,7 +3957,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
@@ -3988,7 +3986,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++)
@@ -4096,7 +4094,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));
 
@@ -4181,9 +4179,9 @@ init_emit_once (line_numbers)
   enum machine_mode double_mode;
 
   /* Initialize the CONST_INT hash table.  */
-  const_int_htab = htab_create (37, const_int_htab_hash, 
+  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), 
+  ggc_add_root (&const_int_htab, 1, sizeof (const_int_htab),
                rtx_htab_mark);
 
   no_line_numbers = ! line_numbers;
@@ -4225,18 +4223,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.  */
@@ -4255,7 +4253,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);
 
@@ -4278,9 +4276,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;