OSDN Git Service

Add new test - do not warn about (non-)redundant friend declaration.
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index d9a6c65..3452a68 100644 (file)
@@ -1,6 +1,6 @@
 /* Emit RTL for the GNU C-Compiler expander.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -170,9 +170,6 @@ static rtx free_insn;
 #define last_filename (cfun->emit->x_last_filename)
 #define first_label_num (cfun->emit->x_first_label_num)
 
-/* This is where the pointer to the obstack being used for RTL is stored.  */
-extern struct obstack *rtl_obstack;
-
 static rtx make_jump_insn_raw          PARAMS ((rtx));
 static rtx make_call_insn_raw          PARAMS ((rtx));
 static rtx find_line_note              PARAMS ((rtx));
@@ -180,6 +177,7 @@ 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 *));
@@ -230,6 +228,20 @@ rtx_htab_mark (htab)
   htab_traverse (*((htab_t *) htab), rtx_htab_mark_1, NULL);
 }
 
+/* Generate a new REG rtx.  Make sure ORIGINAL_REGNO is set properly, and
+   don't attempt to share with the various global pieces of rtl (such as
+   frame_pointer_rtx).  */
+
+rtx
+gen_raw_REG (mode, regno)
+     enum machine_mode mode;
+     int regno;
+{
+  rtx x = gen_rtx_raw_REG (mode, regno);
+  ORIGINAL_REGNO (x) = regno;
+  return x;
+}
+
 /* There are some RTL codes that require special attention; the generation
    functions do the raw handling.  If you add to this list, modify
    special_rtx in gengenrtl.c as well.  */
@@ -253,17 +265,7 @@ gen_rtx_CONST_INT (mode, arg)
   slot = htab_find_slot_with_hash (const_int_htab, &arg,
                                   (hashval_t) arg, INSERT);
   if (*slot == 0)
-    {
-      if (!ggc_p)
-       {
-         push_obstacks_nochange ();
-         end_temporary_allocation ();
-         *slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
-         pop_obstacks ();
-       }
-      else
-       *slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
-    }
+    *slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
 
   return (rtx) *slot;
 }
@@ -331,7 +333,7 @@ gen_rtx_REG (mode, regno)
        return stack_pointer_rtx;
     }
 
-  return gen_rtx_raw_REG (mode, regno);
+  return gen_raw_REG (mode, regno);
 }
 
 rtx
@@ -347,6 +349,55 @@ gen_rtx_MEM (mode, addr)
 
   return rt;
 }
+
+rtx
+gen_rtx_SUBREG (mode, reg, offset)
+     enum machine_mode mode;
+     rtx reg;
+     int offset;
+{
+  /* This is the most common failure type.
+     Catch it early so we can see who does it.  */
+  if ((offset % GET_MODE_SIZE (mode)) != 0)
+    abort ();
+
+  /* This check isn't usable right now because combine will
+     throw arbitrary crap like a CALL into a SUBREG in
+     gen_lowpart_for_combine so we must just eat it.  */
+#if 0
+  /* Check for this too.  */
+  if (offset >= GET_MODE_SIZE (GET_MODE (reg)))
+    abort ();
+#endif
+  return gen_rtx_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. */
+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);
+}
 \f
 /* rtx gen_rtx (code, mode, [element1, ..., elementn])
 **
@@ -539,8 +590,9 @@ gen_reg_rtx (mode)
   if (no_new_pseudos)
     abort ();
 
-  if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-      || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
+  if (generating_concat_p
+      && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+         || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT))
     {
       /* For complex modes, don't make a single pseudo.
         Instead, make a CONCAT of two pseudos.
@@ -560,18 +612,14 @@ gen_reg_rtx (mode)
       return gen_rtx_CONCAT (mode, realpart, imagpart);
     }
 
-  /* Make sure regno_pointer_flag and regno_reg_rtx are large
-     enough to have an element for this pseudo reg number.  */
+  /* Make sure regno_pointer_align and regno_reg_rtx are large enough
+     to have an element for this pseudo reg number.  */
 
-  if (reg_rtx_no == f->emit->regno_pointer_flag_length)
+  if (reg_rtx_no == f->emit->regno_pointer_align_length)
     {
-      int old_size = f->emit->regno_pointer_flag_length;
+      int old_size = f->emit->regno_pointer_align_length;
       rtx *new1;
       char *new;
-      new = xrealloc (f->emit->regno_pointer_flag, old_size * 2);
-      memset (new + old_size, 0, old_size);
-      f->emit->regno_pointer_flag = new;
-
       new = xrealloc (f->emit->regno_pointer_align, old_size * 2);
       memset (new + old_size, 0, old_size);
       f->emit->regno_pointer_align = (unsigned char *) new;
@@ -581,10 +629,10 @@ gen_reg_rtx (mode)
       memset (new1 + old_size, 0, old_size * sizeof (rtx));
       regno_reg_rtx = new1;
 
-      f->emit->regno_pointer_flag_length = old_size * 2;
+      f->emit->regno_pointer_align_length = old_size * 2;
     }
 
-  val = gen_rtx_raw_REG (mode, reg_rtx_no);
+  val = gen_raw_REG (mode, reg_rtx_no);
   regno_reg_rtx[reg_rtx_no++] = val;
   return val;
 }
@@ -614,9 +662,9 @@ mark_reg_pointer (reg, align)
      rtx reg;
      int align;
 {
-  if (! REGNO_POINTER_FLAG (REGNO (reg)))
+  if (! REG_POINTER (reg))
     {
-      REGNO_POINTER_FLAG (REGNO (reg)) = 1;
+      REG_POINTER (reg) = 1;
 
       if (align)
        REGNO_POINTER_ALIGN (REGNO (reg)) = align;
@@ -652,6 +700,38 @@ get_first_label_num ()
   return first_label_num;
 }
 \f
+/* Return the final regno of X, which is a SUBREG of a hard
+   register.  */
+int
+subreg_hard_regno (x, check_mode)
+     register rtx x;
+     int check_mode;
+{
+  enum machine_mode mode = GET_MODE (x);
+  unsigned int byte_offset, base_regno, final_regno;
+  rtx reg = SUBREG_REG (x);
+
+  /* This is where we attempt to catch illegal subregs
+     created by the compiler.  */
+  if (GET_CODE (x) != SUBREG
+      || GET_CODE (reg) != REG)
+    abort ();
+  base_regno = REGNO (reg);
+  if (base_regno >= FIRST_PSEUDO_REGISTER)
+    abort ();
+  if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
+    abort ();
+
+  /* Catch non-congruent offsets too.  */
+  byte_offset = SUBREG_BYTE (x);
+  if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
+    abort ();
+
+  final_regno = subreg_regno (x);
+
+  return final_regno;
+}
+
 /* 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 
@@ -668,22 +748,29 @@ gen_lowpart_common (mode, x)
      enum machine_mode mode;
      register rtx x;
 {
-  int word = 0;
+  int msize = GET_MODE_SIZE (mode);
+  int xsize = GET_MODE_SIZE (GET_MODE (x));
+  int offset = 0;
 
   if (GET_MODE (x) == mode)
     return x;
 
   /* MODE must occupy no more words than the mode of X.  */
   if (GET_MODE (x) != VOIDmode
-      && ((GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD
-         > ((GET_MODE_SIZE (GET_MODE (x)) + (UNITS_PER_WORD - 1))
-            / UNITS_PER_WORD)))
+      && ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD
+         > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
     return 0;
 
-  if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
-    word = ((GET_MODE_SIZE (GET_MODE (x))
-            - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
-           / UNITS_PER_WORD);
+  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;
+    }
 
   if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
       && (GET_MODE_CLASS (mode) == MODE_INT
@@ -707,42 +794,45 @@ gen_lowpart_common (mode, x)
   else if (GET_CODE (x) == SUBREG
           && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
               || GET_MODE_SIZE (mode) == GET_MODE_UNIT_SIZE (GET_MODE (x))))
-    return (GET_MODE (SUBREG_REG (x)) == mode && SUBREG_WORD (x) == 0
-           ? SUBREG_REG (x)
-           : gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + word));
+    {
+      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)
     {
-      /* Let the backend decide how many registers to skip.  This is needed
-         in particular for Sparc64 where fp regs are smaller than a word.  */
-      /* ??? Note that subregs are now ambiguous, in that those against
-        pseudos are sized by the Word Size, while those against hard
-        regs are sized by the underlying register size.  Better would be
-        to always interpret the subreg offset parameter as bytes or bits.  */
-
-      if (WORDS_BIG_ENDIAN && REGNO (x) < FIRST_PSEUDO_REGISTER)
-       word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x))
-               - HARD_REGNO_NREGS (REGNO (x), 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.  
-        But we do do this if the current REG is not valid for its
-        mode.  This latter is a kludge, but is required due to the
-        way that parameters are passed on some machines, most
-        notably Sparc.  */
-      if (REGNO (x) < FIRST_PSEUDO_REGISTER
-         && ! HARD_REGNO_MODE_OK (REGNO (x) + word, mode)
-         && HARD_REGNO_MODE_OK (REGNO (x), GET_MODE (x)))
-       return 0;
-      else if (REGNO (x) < FIRST_PSEUDO_REGISTER
+      /* 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. */
-              && (! REG_FUNCTION_VALUE_P (x)
+         if ((! REG_FUNCTION_VALUE_P (x)
                   || ! rtx_equal_function_value_matters)
-#ifdef CLASS_CANNOT_CHANGE_SIZE
-              && ! (GET_MODE_SIZE (mode) != GET_MODE_SIZE (GET_MODE (x))
+#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_SIZE],
+                        (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
                          REGNO (x))))
 #endif
               /* We want to keep the stack, frame, and arg pointers
@@ -752,9 +842,9 @@ gen_lowpart_common (mode, x)
               && x != arg_pointer_rtx
 #endif
               && x != stack_pointer_rtx)
-       return gen_rtx_REG (mode, REGNO (x) + word);
-      else
-       return gen_rtx_SUBREG (mode, x, word);
+           return gen_rtx_REG (mode, final_regno);
+         }
+      return gen_rtx_SUBREG (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.  */
@@ -765,11 +855,7 @@ gen_lowpart_common (mode, x)
     {
       /* If MODE is twice the host word size, X is already the desired
         representation.  Otherwise, if MODE is wider than a word, we can't
-        do this.  If MODE is exactly a word, return just one CONST_INT.
-        If MODE is smaller than a word, clear the bits that don't belong
-        in our mode, unless they and our sign bit are all one.  So we get
-        either a reasonable negative value or a reasonable unsigned value
-        for this mode.  */
+        do this.  If MODE is exactly a word, return just one CONST_INT.  */
 
       if (GET_MODE_BITSIZE (mode) >= 2 * HOST_BITS_PER_WIDE_INT)
        return x;
@@ -781,18 +867,18 @@ gen_lowpart_common (mode, x)
       else
        {
          /* MODE must be narrower than HOST_BITS_PER_WIDE_INT.  */
-         int width = GET_MODE_BITSIZE (mode);
          HOST_WIDE_INT val = (GET_CODE (x) == CONST_INT ? INTVAL (x)
                               : CONST_DOUBLE_LOW (x));
 
          /* Sign extend to HOST_WIDE_INT.  */
-         val = val << (HOST_BITS_PER_WIDE_INT - width) >> (HOST_BITS_PER_WIDE_INT - width);
+         val = trunc_int_for_mode (val, mode);
 
          return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x
                  : GEN_INT (val));
        }
     }
 
+#ifndef REAL_ARITHMETIC
   /* 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
@@ -806,23 +892,12 @@ gen_lowpart_common (mode, x)
           && GET_MODE_SIZE (mode) == UNITS_PER_WORD
           && GET_CODE (x) == CONST_INT
           && sizeof (float) * HOST_BITS_PER_CHAR == HOST_BITS_PER_WIDE_INT)
-#ifdef REAL_ARITHMETIC
-    {
-      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
     {
       union {HOST_WIDE_INT i; float d; } u;
 
       u.i = INTVAL (x);
       return CONST_DOUBLE_FROM_REAL_VALUE (u.d, mode);
     }
-#endif
   else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
             && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
            || flag_pretend_float)
@@ -832,28 +907,6 @@ gen_lowpart_common (mode, x)
           && GET_MODE (x) == VOIDmode
           && (sizeof (double) * HOST_BITS_PER_CHAR
               == 2 * HOST_BITS_PER_WIDE_INT))
-#ifdef REAL_ARITHMETIC
-    {
-      REAL_VALUE_TYPE r;
-      HOST_WIDE_INT i[2];
-      HOST_WIDE_INT low, high;
-
-      if (GET_CODE (x) == CONST_INT)
-       low = INTVAL (x), high = low >> (HOST_BITS_PER_WIDE_INT -1);
-      else
-       low = CONST_DOUBLE_LOW (x), high = CONST_DOUBLE_HIGH (x);
-
-      /* REAL_VALUE_TARGET_DOUBLE takes the addressing order of the
-        target machine.  */
-      if (WORDS_BIG_ENDIAN)
-       i[0] = high, i[1] = low;
-      else
-       i[0] = low, i[1] = high;
-
-      r = REAL_VALUE_FROM_TARGET_DOUBLE (i);
-      return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
-    }
-#else
     {
       union {HOST_WIDE_INT i[2]; double d; } u;
       HOST_WIDE_INT low, high;
@@ -871,38 +924,6 @@ gen_lowpart_common (mode, x)
 
       return CONST_DOUBLE_FROM_REAL_VALUE (u.d, mode);
     }
-#endif
-
-  /* We need an extra case for machines where HOST_BITS_PER_WIDE_INT is the
-     same as sizeof (double) or when sizeof (float) is larger than the
-     size of a word on the target machine.  */
-#ifdef REAL_ARITHMETIC
-  else if (mode == SFmode && 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 (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
-            && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
-           || flag_pretend_float)
-          && GET_MODE_CLASS (mode) == MODE_FLOAT
-          && GET_MODE_SIZE (mode) == UNITS_PER_WORD
-          && GET_CODE (x) == CONST_INT
-          && (sizeof (double) * HOST_BITS_PER_CHAR
-              == HOST_BITS_PER_WIDE_INT))
-    {
-      REAL_VALUE_TYPE r;
-      HOST_WIDE_INT i;
-
-      i = INTVAL (x);
-      r = REAL_VALUE_FROM_TARGET_DOUBLE (&i);
-      return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
-    }
-#endif
 
   /* Similarly, if this is converting a floating-point value into a
      single-word integer.  Only do this is the host and target parameters are
@@ -916,7 +937,7 @@ gen_lowpart_common (mode, x)
           && GET_CODE (x) == CONST_DOUBLE
           && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT
           && GET_MODE_BITSIZE (mode) == BITS_PER_WORD)
-    return operand_subword (x, word, 0, GET_MODE (x));
+    return constant_subword (x, (offset / UNITS_PER_WORD), GET_MODE (x));
 
   /* Similarly, if this is converting a floating-point value into a
      two-word integer, we can do this one word at a time and make an
@@ -932,15 +953,128 @@ gen_lowpart_common (mode, x)
           && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT
           && GET_MODE_BITSIZE (mode) == 2 * BITS_PER_WORD)
     {
-      rtx lowpart
-       = operand_subword (x, word + WORDS_BIG_ENDIAN, 0, GET_MODE (x));
-      rtx highpart
-       = operand_subword (x, word + ! WORDS_BIG_ENDIAN, 0, GET_MODE (x));
-
+      rtx lowpart, highpart;
+
+      lowpart = constant_subword (x,
+                                 (offset / UNITS_PER_WORD) + WORDS_BIG_ENDIAN,
+                                 GET_MODE (x));
+      highpart = constant_subword (x,
+                                  (offset / UNITS_PER_WORD) + (! WORDS_BIG_ENDIAN),
+                                  GET_MODE (x));
       if (lowpart && GET_CODE (lowpart) == CONST_INT
          && highpart && GET_CODE (highpart) == CONST_INT)
        return immed_double_const (INTVAL (lowpart), INTVAL (highpart), mode);
     }
+#else /* ifndef REAL_ARITHMETIC */
+
+  /* When we have a FP emulator, we can handle all conversions between
+     FP and integer operands.  This simplifies reload because it
+     doesn't have to deal with constructs like (subreg:DI
+     (const_double:SF ...)) or (subreg:DF (const_int ...)).  */
+
+  else if (mode == SFmode
+          && 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
+          && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
+          && GET_MODE (x) == VOIDmode)
+    {
+      REAL_VALUE_TYPE r;
+      HOST_WIDE_INT i[2];
+      HOST_WIDE_INT low, high;
+
+      if (GET_CODE (x) == CONST_INT)
+       {
+         low = INTVAL (x);
+         high = low >> (HOST_BITS_PER_WIDE_INT - 1);
+       }
+      else
+       {
+         low = CONST_DOUBLE_LOW (x); 
+         high = CONST_DOUBLE_HIGH (x);
+       }
+
+      /* REAL_VALUE_TARGET_DOUBLE takes the addressing order of the
+        target machine.  */
+      if (WORDS_BIG_ENDIAN)
+       i[0] = high, i[1] = low;
+      else
+       i[0] = low, i[1] = high;
+
+      r = REAL_VALUE_FROM_TARGET_DOUBLE (i);
+      return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
+    }
+  else if ((GET_MODE_CLASS (mode) == MODE_INT
+           || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+          && GET_CODE (x) == CONST_DOUBLE
+          && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+    {
+      REAL_VALUE_TYPE r;
+      long i[4];  /* Only the low 32 bits of each 'long' are used.  */
+      int endian = WORDS_BIG_ENDIAN ? 1 : 0;
+
+      REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+      switch (GET_MODE (x))
+       {
+       case SFmode:
+         REAL_VALUE_TO_TARGET_SINGLE (r, i[endian]);
+         i[1 - endian] = 0;
+         break;
+       case DFmode:
+         REAL_VALUE_TO_TARGET_DOUBLE (r, i);
+         break;
+#if LONG_DOUBLE_TYPE_SIZE == 96
+       case XFmode:
+         REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i + endian);
+         i[3-3*endian] = 0;
+#else
+       case TFmode:
+         REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i);
+#endif
+         break;
+       default:
+         abort ();
+       }
+
+      /* Now, pack the 32-bit elements of the array into a CONST_DOUBLE
+        and return it.  */
+#if HOST_BITS_PER_WIDE_INT == 32
+      return immed_double_const (i[endian], i[1 - endian], mode);
+#else
+      {
+       int c;
+
+       if (HOST_BITS_PER_WIDE_INT != 64)
+         abort ();
+
+       for (c = 0; c < 4; c++)
+         i[c] &= ~ (0L);
+
+       switch (GET_MODE (x))
+         {
+         case SFmode:
+         case DFmode:
+           return immed_double_const (((unsigned long) i[endian]) |
+                                      (((HOST_WIDE_INT) i[1-endian]) << 32),
+                                      0, mode);
+         default:
+           return immed_double_const (((unsigned long) i[endian*3]) |
+                                      (((HOST_WIDE_INT) i[1+endian]) << 32),
+                                      ((unsigned long) i[2-endian]) |
+                                      (((HOST_WIDE_INT) i[3-endian*3]) << 32),
+                                      mode);
+         }
+      }
+#endif
+    }
+#endif /* ifndef REAL_ARITHMETIC */
 
   /* Otherwise, we can't do this.  */
   return 0;
@@ -960,7 +1094,8 @@ gen_realpart (mode, x)
           && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
           && REG_P (x)
           && REGNO (x) < FIRST_PSEUDO_REGISTER)
-    fatal ("Unable to access real part of complex value in a hard register on this target");
+    internal_error
+      ("Can't access real part of complex value in hard register");
   else if (WORDS_BIG_ENDIAN)
     return gen_highpart (mode, x);
   else
@@ -979,11 +1114,12 @@ gen_imagpart (mode, x)
     return XEXP (x, 1);
   else if (WORDS_BIG_ENDIAN)
     return gen_lowpart (mode, x);
-  else if (!WORDS_BIG_ENDIAN
+  else if (! WORDS_BIG_ENDIAN
           && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
           && REG_P (x)
           && REGNO (x) < FIRST_PSEUDO_REGISTER)
-    fatal ("Unable to access imaginary part of complex value in a hard register on this target");
+    internal_error
+      ("can't access imaginary part of complex value in hard register");
   else
     return gen_highpart (mode, x);
 }
@@ -1000,7 +1136,7 @@ subreg_realpart_p (x)
   if (GET_CODE (x) != SUBREG)
     abort ();
 
-  return ((unsigned int) SUBREG_WORD (x) * UNITS_PER_WORD
+  return ((unsigned int) SUBREG_BYTE (x)
          < GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x))));
 }
 \f
@@ -1058,10 +1194,13 @@ gen_highpart (mode, x)
      enum machine_mode mode;
      register rtx x;
 {
+  unsigned int msize = GET_MODE_SIZE (mode);
+  unsigned int xsize = GET_MODE_SIZE (GET_MODE (x));
+
   /* This case loses if X is a subreg.  To catch bugs early,
      complain if an invalid MODE is used even in other cases.  */
-  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
-      && GET_MODE_SIZE (mode) != GET_MODE_UNIT_SIZE (GET_MODE (x)))
+  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))
@@ -1078,15 +1217,14 @@ gen_highpart (mode, x)
   else if (GET_CODE (x) == MEM)
     {
       register int offset = 0;
+
       if (! WORDS_BIG_ENDIAN)
-       offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
-                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
+       offset = (MAX (xsize, UNITS_PER_WORD)
+                 - MAX (msize, UNITS_PER_WORD));
 
       if (! BYTES_BIG_ENDIAN
-         && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
-       offset -= (GET_MODE_SIZE (mode)
-                  - MIN (UNITS_PER_WORD,
-                         GET_MODE_SIZE (GET_MODE (x))));
+         && msize < UNITS_PER_WORD)
+       offset -= (msize - MIN (UNITS_PER_WORD, xsize));
 
       return change_address (x, mode, plus_constant (XEXP (x, 0), offset));
     }
@@ -1095,44 +1233,47 @@ gen_highpart (mode, x)
       /* 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_WORD (x) != 0)
+      if (SUBREG_BYTE (x) != 0)
        abort ();
       return gen_highpart (mode, SUBREG_REG (x));
     }
   else if (GET_CODE (x) == REG)
     {
-      int word;
+      int offset = 0;
 
-      /* Let the backend decide how many registers to skip.  This is needed
-         in particular for sparc64 where fp regs are smaller than a word.  */
-      /* ??? Note that subregs are now ambiguous, in that those against
-        pseudos are sized by the word size, while those against hard
-        regs are sized by the underlying register size.  Better would be
-        to always interpret the subreg offset parameter as bytes or bits.  */
+      if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
+       abort ();
 
-      if (WORDS_BIG_ENDIAN)
-       word = 0;
-      else if (REGNO (x) < FIRST_PSEUDO_REGISTER)
-       word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x))
-               - HARD_REGNO_NREGS (REGNO (x), mode));
-      else
-       word = ((GET_MODE_SIZE (GET_MODE (x))
-                - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
-               / UNITS_PER_WORD);
-
-      if (REGNO (x) < FIRST_PSEUDO_REGISTER
-         /* integrate.c can't handle parts of a return value register.  */
-         && (! REG_FUNCTION_VALUE_P (x)
-             || ! rtx_equal_function_value_matters)
+      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;
+       }
+      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
+             && 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, REGNO (x) + word);
-      else
-       return gen_rtx_SUBREG (mode, x, word);
+             && x != stack_pointer_rtx)
+           return gen_rtx_REG (mode, final_regno);
+       }
+      /* Just generate a normal SUBREG.  */
+      return gen_rtx_SUBREG (mode, x, offset); 
     }
   else
     abort ();
@@ -1146,154 +1287,44 @@ 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 (WORDS_BIG_ENDIAN
-      && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD)
-    return (SUBREG_WORD (x)
-           == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
-                - MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD))
-               / UNITS_PER_WORD));
+  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_WORD (x) == 0;
+  return SUBREG_BYTE (x) == offset;
 }
 \f
-/* Return subword I of operand OP.
-   The word number, I, is interpreted as the word number starting at the
-   low-order address.  Word 0 is the low-order word if not WORDS_BIG_ENDIAN,
-   otherwise it is the high-order word.
 
-   If we cannot extract the required word, we return zero.  Otherwise, an
-   rtx corresponding to the requested word will be returned.
-
-   VALIDATE_ADDRESS is nonzero if the address should be validated.  Before
-   reload has completed, a valid address will always be returned.  After
-   reload, if a valid address cannot be returned, we return zero.
-
-   If VALIDATE_ADDRESS is zero, we simply form the required address; validating
-   it is the responsibility of the caller.
-
-   MODE is the mode of OP in case it is a CONST_INT.  */
+/* Helper routine for all the constant cases of operand_subword.
+   Some places invoke this directly.  */
 
 rtx
-operand_subword (op, i, validate_address, mode)
+constant_subword (op, offset, mode)
      rtx op;
-     unsigned int i;
-     int validate_address;
+     int offset;
      enum machine_mode mode;
 {
-  HOST_WIDE_INT val;
   int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD;
-
-  if (mode == VOIDmode)
-    mode = GET_MODE (op);
-
-  if (mode == VOIDmode)
-    abort ();
-
-  /* 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 (mode != BLKmode
-      && (i + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode))
-    return const0_rtx;
+  HOST_WIDE_INT val;
 
   /* If OP is already an integer word, return it.  */
   if (GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_SIZE (mode) == UNITS_PER_WORD)
     return op;
 
-  /* If OP is a REG or SUBREG, we can handle it very simply.  */
-  if (GET_CODE (op) == REG)
-    {
-      /* ??? There is a potential problem with this code.  It does not
-        properly handle extractions of a subword from a hard register
-        that is larger than word_mode.  Presumably the check for
-        HARD_REGNO_MODE_OK catches these most of these cases.  */
-
-      /* If OP is a hard register, but OP + I is not a hard register,
-        then extracting a subword is impossible.
-
-        For example, consider if OP is the last hard register and it is
-        larger than word_mode.  If we wanted word N (for N > 0) because a
-        part of that hard register was known to contain a useful value,
-        then OP + I would refer to a pseudo, not the hard register we
-        actually wanted.  */
-      if (REGNO (op) < FIRST_PSEUDO_REGISTER
-         && REGNO (op) + i >= FIRST_PSEUDO_REGISTER)
-       return 0;
-
-      /* If the register is not valid for MODE, return 0.  Note we
-        have to check both OP and OP + I since they may refer to
-        different parts of the register file.
-
-        Consider if OP refers to the last 96bit FP register and we want
-        subword 3 because that subword is known to contain a value we
-        needed.  */
-      if (REGNO (op) < FIRST_PSEUDO_REGISTER
-         && (! HARD_REGNO_MODE_OK (REGNO (op), word_mode)
-             || ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode)))
-       return 0;
-      else if (REGNO (op) >= FIRST_PSEUDO_REGISTER
-              || (REG_FUNCTION_VALUE_P (op)
-                  && rtx_equal_function_value_matters)
-              /* 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_SUBREG (word_mode, op, i);
-      else
-       return gen_rtx_REG (word_mode, REGNO (op) + i);
-    }
-  else if (GET_CODE (op) == SUBREG)
-    return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
-  else if (GET_CODE (op) == CONCAT)
-    {
-      unsigned int partwords
-       = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;
-
-      if (i < partwords)
-       return operand_subword (XEXP (op, 0), i, validate_address, mode);
-      return operand_subword (XEXP (op, 1), i - partwords,
-                             validate_address, mode);
-    }
-
-  /* Form a new MEM at the requested address.  */
-  if (GET_CODE (op) == MEM)
-    {
-      rtx addr = plus_constant (XEXP (op, 0), i * UNITS_PER_WORD);
-      rtx new;
-
-      if (validate_address)
-       {
-         if (reload_completed)
-           {
-             if (! strict_memory_address_p (word_mode, addr))
-               return 0;
-           }
-         else
-           addr = memory_address (word_mode, addr);
-       }
-
-      new = gen_rtx_MEM (word_mode, addr);
-      MEM_COPY_ATTRIBUTES (new, op);
-      return new;
-    }
-
-  /* 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.  */
 #ifdef REAL_ARITHMETIC
   /* The output is some bits, the width of the target machine's word.
      A wider-word host can surely hold them in a CONST_INT. A narrower-word
@@ -1320,12 +1351,12 @@ operand_subword (op, i, validate_address, mode)
         So we explicitly mask and sign-extend as necessary.  */
       if (BITS_PER_WORD == 32)
        {
-         val = k[i];
+         val = k[offset];
          val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
          return GEN_INT (val);
        }
 #if HOST_BITS_PER_WIDE_INT >= 64
-      else if (BITS_PER_WORD >= 64 && i == 0)
+      else if (BITS_PER_WORD >= 64 && offset == 0)
        {
          val = k[! WORDS_BIG_ENDIAN];
          val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
@@ -1335,10 +1366,10 @@ operand_subword (op, i, validate_address, mode)
 #endif
       else if (BITS_PER_WORD == 16)
        {
-         val = k[i >> 1];
-         if ((i & 1) == !WORDS_BIG_ENDIAN)
+         val = k[offset >> 1];
+         if ((offset & 1) == ! WORDS_BIG_ENDIAN)
            val >>= 16;
-         val &= 0xffff;
+         val = ((val & 0xffff) ^ 0x8000) - 0x8000;
          return GEN_INT (val);
        }
       else
@@ -1357,16 +1388,16 @@ operand_subword (op, i, validate_address, mode)
 
       if (BITS_PER_WORD == 32)
        {
-         val = k[i];
+         val = k[offset];
          val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
          return GEN_INT (val);
        }
 #if HOST_BITS_PER_WIDE_INT >= 64
-      else if (BITS_PER_WORD >= 64 && i <= 1)
+      else if (BITS_PER_WORD >= 64 && offset <= 1)
        {
-         val = k[i*2 + ! WORDS_BIG_ENDIAN];
+         val = k[offset * 2 + ! WORDS_BIG_ENDIAN];
          val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
-         val |= (HOST_WIDE_INT) k[i*2 + WORDS_BIG_ENDIAN] & 0xffffffff;
+         val |= (HOST_WIDE_INT) k[offset * 2 + WORDS_BIG_ENDIAN] & 0xffffffff;
          return GEN_INT (val);
        }
 #endif
@@ -1386,10 +1417,10 @@ operand_subword (op, i, validate_address, mode)
         compilers don't like a conditional inside macro args, so we have two
         copies of the return.  */
 #ifdef HOST_WORDS_BIG_ENDIAN
-      return GEN_INT (i == WORDS_BIG_ENDIAN
+      return GEN_INT (offset == WORDS_BIG_ENDIAN
                      ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));
 #else
-      return GEN_INT (i != WORDS_BIG_ENDIAN
+      return GEN_INT (offset != WORDS_BIG_ENDIAN
                      ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));
 #endif
     }
@@ -1415,9 +1446,9 @@ operand_subword (op, i, validate_address, mode)
 
       if (BITS_PER_WORD == 16)
        {
-         if ((i & 1) == !WORDS_BIG_ENDIAN)
+         if ((offset & 1) == ! WORDS_BIG_ENDIAN)
            val >>= 16;
-         val &= 0xffff;
+         val = ((val & 0xffff) ^ 0x8000) - 0x8000;
        }
 
       return GEN_INT (val);
@@ -1459,7 +1490,7 @@ operand_subword (op, i, validate_address, mode)
       
   /* The only remaining cases that we can handle are integers.
      Convert to proper endianness now since these cases need it.
-     At this point, i == 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
@@ -1474,39 +1505,184 @@ operand_subword (op, i, validate_address, mode)
     return 0;
 
   if (WORDS_BIG_ENDIAN)
-    i = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - i;
+    offset = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - offset;
 
   /* Find out which word on the host machine this value is in and get
      it from the constant.  */
-  val = (i / size_ratio == 0
+  val = (offset / size_ratio == 0
         ? (GET_CODE (op) == CONST_INT ? INTVAL (op) : CONST_DOUBLE_LOW (op))
         : (GET_CODE (op) == CONST_INT
            ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op)));
 
   /* Get the value we want into the low bits of val.  */
   if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT)
-    val = ((val >> ((i % size_ratio) * BITS_PER_WORD)));
+    val = ((val >> ((offset % size_ratio) * BITS_PER_WORD)));
 
   val = trunc_int_for_mode (val, word_mode);
 
   return GEN_INT (val);
 }
 
+/* Return subword OFFSET of operand OP.
+   The word number, OFFSET, is interpreted as the word number starting
+   at the low-order address.  OFFSET 0 is the low-order word if not
+   WORDS_BIG_ENDIAN, otherwise it is the high-order word.
+
+   If we cannot extract the required word, we return zero.  Otherwise,
+   an rtx corresponding to the requested word will be returned.
+
+   VALIDATE_ADDRESS is nonzero if the address should be validated.  Before
+   reload has completed, a valid address will always be returned.  After
+   reload, if a valid address cannot be returned, we return zero.
+
+   If VALIDATE_ADDRESS is zero, we simply form the required address; validating
+   it is the responsibility of the caller.
+
+   MODE is the mode of OP in case it is a CONST_INT.
+
+   ??? 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.  */
+
+rtx
+operand_subword (op, offset, validate_address, mode)
+     rtx op;
+     unsigned int offset;
+     int validate_address;
+     enum machine_mode mode;
+{
+  if (mode == VOIDmode)
+    mode = GET_MODE (op);
+
+  if (mode == VOIDmode)
+    abort ();
+
+  /* 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 (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;
+
+      if (validate_address)
+       {
+         if (reload_completed)
+           {
+             if (! strict_memory_address_p (word_mode, addr))
+               return 0;
+           }
+         else
+           addr = memory_address (word_mode, addr);
+       }
+
+      new = gen_rtx_MEM (word_mode, addr);
+      MEM_COPY_ATTRIBUTES (new, op);
+      return new;
+    }
+
+  /* Unreachable... (famous last words) */
+  abort ();
+}
+
 /* 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.  It is not valid
-   to call this function after reload; it is mostly meant for RTL
-   generation. 
+   abort.  We always validate the address in this case.  
 
    MODE is the mode of OP, in case it is CONST_INT.  */
 
 rtx
-operand_subword_force (op, i, mode)
+operand_subword_force (op, offset, mode)
      rtx op;
-     unsigned int i;
+     unsigned int offset;
      enum machine_mode mode;
 {
-  rtx result = operand_subword (op, i, 1, mode);
+  rtx result = operand_subword (op, offset, 1, mode);
 
   if (result)
     return result;
@@ -1521,7 +1697,7 @@ operand_subword_force (op, i, mode)
        op = force_reg (mode, op);
     }
 
-  result = operand_subword (op, i, 1, mode);
+  result = operand_subword (op, offset, 1, mode);
   if (result == 0)
     abort ();
 
@@ -1607,7 +1783,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;
@@ -1679,7 +1855,6 @@ free_emit_status (f)
      struct function *f;
 {
   free (f->emit->x_regno_reg_rtx);
-  free (f->emit->regno_pointer_flag);
   free (f->emit->regno_pointer_align);
   free (f->emit);
   f->emit = NULL;
@@ -1697,7 +1872,7 @@ unshare_all_rtl (fndecl, insn)
 
   /* Make sure that virtual parameters are not shared.  */
   for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
-    DECL_RTL (decl) = copy_rtx_if_shared (DECL_RTL (decl));
+    SET_DECL_RTL (decl, copy_rtx_if_shared (DECL_RTL (decl)));
 
   /* Make sure that virtual stack slots are not shared.  */
   unshare_all_decls (DECL_INITIAL (fndecl));
@@ -1727,7 +1902,7 @@ unshare_all_rtl_again (insn)
   tree decl;
 
   for (p = insn; p; p = NEXT_INSN (p))
-    if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
+    if (INSN_P (p))
       {
        reset_used_flags (PATTERN (p));
        reset_used_flags (REG_NOTES (p));
@@ -1754,7 +1929,7 @@ unshare_all_rtl_1 (insn)
      rtx insn;
 {
   for (; insn; insn = NEXT_INSN (insn))
-    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+    if (INSN_P (insn))
       {
        PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
        REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn));
@@ -1772,7 +1947,8 @@ unshare_all_decls (blk)
 
   /* Copy shared decls.  */
   for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t))
-    DECL_RTL (t) = copy_rtx_if_shared (DECL_RTL (t));
+    if (DECL_RTL_SET_P (t))
+      SET_DECL_RTL (t, copy_rtx_if_shared (DECL_RTL (t)));
 
   /* Now process sub-blocks.  */
   for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t))
@@ -1789,7 +1965,8 @@ reset_used_decls (blk)
 
   /* Mark decls.  */
   for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t))
-    reset_used_flags (DECL_RTL (t));
+    if (DECL_RTL_SET_P (t))
+      reset_used_flags (DECL_RTL (t));
 
   /* Now process sub-blocks.  */
   for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t))
@@ -1873,7 +2050,7 @@ copy_rtx_if_shared (orig)
       register rtx copy;
 
       copy = rtx_alloc (code);
-      bcopy ((char *) x, (char *) copy,
+      memcpy (copy, x,
             (sizeof (*copy) - sizeof (copy->fld)
              + sizeof (copy->fld[0]) * GET_RTX_LENGTH (code)));
       x = copy;
@@ -2320,8 +2497,7 @@ next_cc0_user (insn)
   if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
     insn = XVECEXP (PATTERN (insn), 0, 0);
 
-  if (insn && GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-      && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
+  if (insn && INSN_P (insn) && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
     return insn;
 
   return 0;
@@ -2346,6 +2522,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.
@@ -2383,7 +2585,8 @@ try_split (pat, trial, last)
       if (GET_CODE (seq) == SEQUENCE)
        {
          int i;
-
+         rtx eh_note;
+         
          /* Avoid infinite loop if any insn of the result matches 
             the original pattern.  */
          for (i = 0; i < XVECLEN (seq, 0); i++)
@@ -2391,19 +2594,39 @@ try_split (pat, trial, last)
                && rtx_equal_p (PATTERN (XVECEXP (seq, 0, i)), pat))
              return trial;
 
-         /* If we are splitting a JUMP_INSN, look for the JUMP_INSN in
-            SEQ and copy our JUMP_LABEL to it.  If JUMP_LABEL is non-zero,
-            increment the usage count so we don't delete the label.  */
+         /* 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);
 
-         if (GET_CODE (trial) == JUMP_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)
            for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
-             if (GET_CODE (XVECEXP (seq, 0, i)) == JUMP_INSN)
-               {
-                 JUMP_LABEL (XVECEXP (seq, 0, i)) = JUMP_LABEL (trial);
-
-                 if (JUMP_LABEL (trial))
-                   LABEL_NUSES (JUMP_LABEL (trial))++;
-               }
+             if (GET_CODE (XVECEXP (seq, 0, i)) == CALL_INSN)
+               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);
 
@@ -2416,10 +2639,8 @@ try_split (pat, trial, last)
             set LAST and continue from the insn after the one returned.
             We can't use next_active_insn here since AFTER may be a note.
             Ignore deleted insns, which can be occur if not optimizing.  */
-         for (tem = NEXT_INSN (before); tem != after;
-              tem = NEXT_INSN (tem))
-           if (! INSN_DELETED_P (tem)
-               && GET_RTX_CLASS (GET_CODE (tem)) == 'i')
+         for (tem = NEXT_INSN (before); tem != after; tem = NEXT_INSN (tem))
+           if (! INSN_DELETED_P (tem) && INSN_P (tem))
              tem = try_split (PATTERN (tem), tem, 1);
        }
       /* Avoid infinite loop if the result matches the original pattern.  */
@@ -2451,15 +2672,7 @@ make_insn_raw (pattern)
 {
   register rtx insn;
 
-  /* If in RTL generation phase, see if FREE_INSN can be used.  */
-  if (!ggc_p && free_insn != 0 && rtx_equal_function_value_matters)
-    {
-      insn = free_insn;
-      free_insn = NEXT_INSN (free_insn);
-      PUT_CODE (insn, INSN);
-    }
-  else
-    insn = rtx_alloc (INSN);
+  insn = rtx_alloc (INSN);
 
   INSN_UID (insn) = cur_insn_uid++;
   PATTERN (insn) = pattern;
@@ -2469,7 +2682,7 @@ make_insn_raw (pattern)
 
 #ifdef ENABLE_RTL_CHECKING
   if (insn
-      && GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+      && INSN_P (insn)
       && (returnjump_p (insn)
          || (GET_CODE (insn) == SET
              && SET_DEST (insn) == pc_rtx)))
@@ -2792,8 +3005,11 @@ reorder_insns_with_line_notes (from, to, after)
 void
 remove_unnecessary_notes ()
 {
+  rtx block_stack = NULL_RTX;
+  rtx eh_stack = NULL_RTX;
   rtx insn;
   rtx next;
+  rtx tmp;
 
   /* We must not remove the first instruction in the function because
      the compiler depends on the first instruction being a note.  */
@@ -2806,54 +3022,77 @@ remove_unnecessary_notes ()
       if (GET_CODE (insn) != NOTE)
        continue;
 
-      /* By now, all notes indicating lexical blocks should have
-        NOTE_BLOCK filled in.  */
-      if ((NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
-          || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
-         && NOTE_BLOCK (insn) == NULL_TREE)
-       abort ();
-
-      /* Remove NOTE_INSN_DELETED notes.  */
-      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
-       remove_insn (insn);
-      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
+      switch (NOTE_LINE_NUMBER (insn))
        {
+       case NOTE_INSN_DELETED:
+         remove_insn (insn);
+         break;
+
+       case NOTE_INSN_EH_REGION_BEG:
+         eh_stack = alloc_INSN_LIST (insn, eh_stack);
+         break;
+
+       case NOTE_INSN_EH_REGION_END:
+         /* Too many end notes.  */
+         if (eh_stack == NULL_RTX)
+           abort ();
+         /* Mismatched nesting.  */
+         if (NOTE_EH_HANDLER (XEXP (eh_stack, 0)) != NOTE_EH_HANDLER (insn))
+           abort ();
+         tmp = eh_stack;
+         eh_stack = XEXP (eh_stack, 1);
+         free_INSN_LIST_node (tmp);
+         break;
+
+       case NOTE_INSN_BLOCK_BEG:
+         /* By now, all notes indicating lexical blocks should have
+            NOTE_BLOCK filled in.  */
+         if (NOTE_BLOCK (insn) == NULL_TREE)
+           abort ();
+         block_stack = alloc_INSN_LIST (insn, block_stack);
+         break;
+
+       case NOTE_INSN_BLOCK_END:
+         /* Too many end notes.  */
+         if (block_stack == NULL_RTX)
+           abort ();
+         /* Mismatched nesting.  */
+         if (NOTE_BLOCK (XEXP (block_stack, 0)) != NOTE_BLOCK (insn))
+           abort ();
+         tmp = block_stack;
+         block_stack = XEXP (block_stack, 1);
+         free_INSN_LIST_node (tmp);
+
          /* Scan back to see if there are any non-note instructions
             between INSN and the beginning of this block.  If not,
             then there is no PC range in the generated code that will
             actually be in this block, so there's no point in
             remembering the existence of the block.  */
-         rtx prev;
-
-         for (prev = PREV_INSN (insn); prev; prev = PREV_INSN (prev))
+         for (tmp = PREV_INSN (insn); tmp ; tmp = PREV_INSN (tmp))
            {
              /* This block contains a real instruction.  Note that we
                 don't include labels; if the only thing in the block
                 is a label, then there are still no PC values that
                 lie within the block.  */
-             if (GET_RTX_CLASS (GET_CODE (prev)) == 'i')
+             if (INSN_P (tmp))
                break;
 
              /* We're only interested in NOTEs.  */
-             if (GET_CODE (prev) != NOTE)
+             if (GET_CODE (tmp) != NOTE)
                continue;
 
-             if (NOTE_LINE_NUMBER (prev) == NOTE_INSN_BLOCK_BEG)
+             if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_BEG)
                {
-                 /* If the BLOCKs referred to by these notes don't
-                    match, then something is wrong with our BLOCK
-                    nesting structure.  */
-                 if (NOTE_BLOCK (prev) != NOTE_BLOCK (insn))
-                   abort ();
-
+                 /* We just verified that this BLOCK matches us
+                    with the block_stack check above.  */
                  if (debug_ignore_block (NOTE_BLOCK (insn)))
                    {
-                     remove_insn (prev);
+                     remove_insn (tmp);
                      remove_insn (insn);
                    }
                  break;
                }
-             else if (NOTE_LINE_NUMBER (prev) == NOTE_INSN_BLOCK_END)
+             else if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_END)
                /* There's a nested block.  We need to leave the
                   current block in place since otherwise the debugger
                   wouldn't be able to show symbols from our block in
@@ -2862,6 +3101,10 @@ remove_unnecessary_notes ()
            }
        }
     }
+
+  /* Too many begin notes.  */
+  if (block_stack || eh_stack)
+    abort ();
 }
 
 \f
@@ -2886,8 +3129,6 @@ emit_insn_before (pattern, before)
          insn = XVECEXP (pattern, 0, i);
          add_insn_before (insn, before);
        }
-      if (!ggc_p && XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
-       sequence_result[XVECLEN (pattern, 0)] = pattern;
     }
   else
     {
@@ -3020,8 +3261,6 @@ emit_insn_after (pattern, after)
          add_insn_after (insn, after);
          after = insn;
        }
-      if (!ggc_p && XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
-       sequence_result[XVECLEN (pattern, 0)] = pattern;
     }
   else
     {
@@ -3181,8 +3420,6 @@ emit_insn (pattern)
          insn = XVECEXP (pattern, 0, i);
          add_insn (insn);
        }
-      if (!ggc_p && XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
-       sequence_result[XVECLEN (pattern, 0)] = pattern;
     }
   else
     {
@@ -3494,7 +3731,7 @@ emit (x)
    pops have previously been deferred; see INHIBIT_DEFER_POP for more
    details), use do_pending_stack_adjust before calling this function.
    That will ensure that the deferred pops are not accidentally
-   emitted in the middel of this sequence.  */
+   emitted in the middle of this sequence.  */
 
 void
 start_sequence ()
@@ -3670,29 +3907,9 @@ gen_sequence ()
       && GET_CODE (first_insn) == INSN
       /* Don't throw away any reg notes. */
       && REG_NOTES (first_insn) == 0)
-    {
-      if (!ggc_p)
-       {
-         NEXT_INSN (first_insn) = free_insn;
-         free_insn = first_insn;
-       }
-      return PATTERN (first_insn);
-    }
+    return PATTERN (first_insn);
 
-  /* Put them in a vector.  See if we already have a SEQUENCE of the
-     appropriate length around.  */
-  if (!ggc_p && len < SEQUENCE_RESULT_SIZE 
-      && (result = sequence_result[len]) != 0)
-    sequence_result[len] = 0;
-  else
-    {
-      /* Ensure that this rtl goes in saveable_obstack, since we may
-        cache it.  */
-      push_obstacks_nochange ();
-      rtl_in_saveable_obstack ();
-      result = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (len));
-      pop_obstacks ();
-    }
+  result = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (len));
 
   for (i = 0, tem = first_insn; tem; tem = NEXT_INSN (tem), i++)
     XVECEXP (result, 0, i) = tem;
@@ -3846,14 +4063,6 @@ copy_insn_1 (orig)
            }
          break;
 
-       case 'b':
-         {
-           bitmap new_bits = BITMAP_OBSTACK_ALLOC (rtl_obstack);
-           bitmap_copy (new_bits, XBITMAP (orig, i));
-           XBITMAP (copy, i) = new_bits;
-           break;
-         }
-
        case 't':
        case 'w':
        case 'i':
@@ -3879,10 +4088,10 @@ copy_insn_1 (orig)
     }
   else if (code == ASM_OPERANDS)
     {
-      orig_asm_operands_vector = XVEC (orig, 3);
-      copy_asm_operands_vector = XVEC (copy, 3);
-      orig_asm_constraints_vector = XVEC (orig, 4);
-      copy_asm_constraints_vector = XVEC (copy, 4);
+      orig_asm_operands_vector = ASM_OPERANDS_INPUT_VEC (orig);
+      copy_asm_operands_vector = ASM_OPERANDS_INPUT_VEC (copy);
+      orig_asm_constraints_vector = ASM_OPERANDS_INPUT_CONSTRAINT_VEC (orig);
+      copy_asm_constraints_vector = ASM_OPERANDS_INPUT_CONSTRAINT_VEC (copy);
     }
 
   return copy;
@@ -3929,17 +4138,14 @@ init_emit ()
 
   /* Init the tables that describe all the pseudo regs.  */
 
-  f->emit->regno_pointer_flag_length = LAST_VIRTUAL_REGISTER + 101;
-
-  f->emit->regno_pointer_flag 
-    = (char *) xcalloc (f->emit->regno_pointer_flag_length, sizeof (char));
+  f->emit->regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
 
   f->emit->regno_pointer_align
-    = (unsigned char *) xcalloc (f->emit->regno_pointer_flag_length,
+    = (unsigned char *) xcalloc (f->emit->regno_pointer_align_length,
                                 sizeof (unsigned char));
 
   regno_reg_rtx 
-    = (rtx *) xcalloc (f->emit->regno_pointer_flag_length * sizeof (rtx),
+    = (rtx *) xcalloc (f->emit->regno_pointer_align_length * sizeof (rtx),
                       sizeof (rtx));
 
   /* Put copies of all the virtual register rtx into regno_reg_rtx.  */
@@ -3947,16 +4153,16 @@ init_emit ()
 
   /* Indicate that the virtual registers and stack locations are
      all pointers.  */
-  REGNO_POINTER_FLAG (STACK_POINTER_REGNUM) = 1;
-  REGNO_POINTER_FLAG (FRAME_POINTER_REGNUM) = 1;
-  REGNO_POINTER_FLAG (HARD_FRAME_POINTER_REGNUM) = 1;
-  REGNO_POINTER_FLAG (ARG_POINTER_REGNUM) = 1;
+  REG_POINTER (stack_pointer_rtx) = 1;
+  REG_POINTER (frame_pointer_rtx) = 1;
+  REG_POINTER (hard_frame_pointer_rtx) = 1;
+  REG_POINTER (arg_pointer_rtx) = 1;
 
-  REGNO_POINTER_FLAG (VIRTUAL_INCOMING_ARGS_REGNUM) = 1;
-  REGNO_POINTER_FLAG (VIRTUAL_STACK_VARS_REGNUM) = 1;
-  REGNO_POINTER_FLAG (VIRTUAL_STACK_DYNAMIC_REGNUM) = 1;
-  REGNO_POINTER_FLAG (VIRTUAL_OUTGOING_ARGS_REGNUM) = 1;
-  REGNO_POINTER_FLAG (VIRTUAL_CFA_REGNUM) = 1;
+  REG_POINTER (virtual_incoming_args_rtx) = 1;
+  REG_POINTER (virtual_stack_vars_rtx) = 1;
+  REG_POINTER (virtual_stack_dynamic_rtx) = 1;
+  REG_POINTER (virtual_outgoing_args_rtx) = 1;
+  REG_POINTER (virtual_cfa_rtx) = 1;
 
 #ifdef STACK_BOUNDARY
   REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY;
@@ -4002,7 +4208,7 @@ mark_emit_status (es)
   if (es == 0)
     return;
 
-  for (i = es->regno_pointer_flag_length, r = es->x_regno_reg_rtx;
+  for (i = es->regno_pointer_align_length, r = es->x_regno_reg_rtx;
        i > 0; --i, ++r)
     ggc_mark_rtx (*r);
 
@@ -4022,6 +4228,12 @@ 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, 
+                               const_int_htab_eq, NULL);
+  ggc_add_root (&const_int_htab, 1, sizeof (const_int_htab), 
+               rtx_htab_mark);
+
   no_line_numbers = ! line_numbers;
 
   /* Compute the word and byte modes.  */
@@ -4042,10 +4254,6 @@ init_emit_once (line_numbers)
        word_mode = mode;
     }
 
-#ifndef DOUBLE_TYPE_SIZE
-#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
-
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
@@ -4062,31 +4270,30 @@ init_emit_once (line_numbers)
 
   pc_rtx = gen_rtx (PC, VOIDmode);
   cc0_rtx = gen_rtx (CC0, VOIDmode);
-  stack_pointer_rtx = gen_rtx_raw_REG (Pmode, STACK_POINTER_REGNUM);
-  frame_pointer_rtx = gen_rtx_raw_REG (Pmode, FRAME_POINTER_REGNUM);
+  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_rtx_raw_REG (Pmode, 
-                                             HARD_FRAME_POINTER_REGNUM);
+    hard_frame_pointer_rtx = gen_raw_REG (Pmode, 
+                                         HARD_FRAME_POINTER_REGNUM);
   if (arg_pointer_rtx == 0)
-    arg_pointer_rtx = gen_rtx_raw_REG (Pmode, ARG_POINTER_REGNUM);
+    arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM);
   virtual_incoming_args_rtx = 
-    gen_rtx_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
+    gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
   virtual_stack_vars_rtx = 
-    gen_rtx_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
+    gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
   virtual_stack_dynamic_rtx = 
-    gen_rtx_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);
+    gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);
   virtual_outgoing_args_rtx = 
-    gen_rtx_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM); 
-  virtual_cfa_rtx = gen_rtx_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
+    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.  */
-  if (ggc_p)
-    ggc_add_rtx_root (global_rtl, GR_MAX);
+  ggc_add_rtx_root (global_rtl, GR_MAX);
 
 #ifdef INIT_EXPANDERS
-  /* This is to initialize save_machine_status and restore_machine_status before
-     the first call to push_function_context_to.  This is needed by the Chill
-     front end which calls push_function_context_to before the first cal to
+  /* This is to initialize {init|mark|free}_machine_status before the first
+     call to push_function_context_to.  This is needed by the Chill front
+     end which calls push_function_context_to before the first cal to
      init_function_start.  */
   INIT_EXPANDERS;
 #endif
@@ -4098,8 +4305,7 @@ init_emit_once (line_numbers)
   for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
     const_int_rtx[i + MAX_SAVED_CONST_INT] = 
       gen_rtx_raw_CONST_INT (VOIDmode, i);
-  if (ggc_p)
-    ggc_add_rtx_root (const_int_rtx, 2 * MAX_SAVED_CONST_INT + 1);
+  ggc_add_rtx_root (const_int_rtx, 2 * MAX_SAVED_CONST_INT + 1);
 
   if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT
       && STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT)
@@ -4120,11 +4326,12 @@ init_emit_once (line_numbers)
          rtx tem = rtx_alloc (CONST_DOUBLE);
          union real_extract u;
 
-         bzero ((char *) &u, sizeof u);  /* Zero any holes in a structure.  */
+         memset ((char *) &u, 0, sizeof u);  /* Zero any holes in a structure.  */
          u.d = i == 0 ? dconst0 : i == 1 ? dconst1 : dconst2;
 
-         bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (tem), sizeof u);
+         memcpy (&CONST_DOUBLE_LOW (tem), &u, sizeof u);
          CONST_DOUBLE_MEM (tem) = cc0_rtx;
+         CONST_DOUBLE_CHAIN (tem) = NULL_RTX;
          PUT_MODE (tem, mode);
 
          const_tiny_rtx[i][(int) mode] = tem;
@@ -4142,16 +4349,23 @@ init_emit_once (line_numbers)
        const_tiny_rtx[i][(int) mode] = GEN_INT (i);
     }
 
-  for (mode = CCmode; mode < MAX_MACHINE_MODE; ++mode)
-    if (GET_MODE_CLASS (mode) == MODE_CC)
-      const_tiny_rtx[0][(int) mode] = const0_rtx;
+  for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i)
+    if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC)
+      const_tiny_rtx[0][i] = const0_rtx;
+
+  const_tiny_rtx[0][(int) BImode] = const0_rtx;
+  if (STORE_FLAG_VALUE == 1)
+    const_tiny_rtx[1][(int) BImode] = const1_rtx;
 
-  ggc_add_rtx_root (&const_tiny_rtx[0][0], sizeof(const_tiny_rtx)/sizeof(rtx));
+  /* For bounded pointers, `&const_tiny_rtx[0][0]' is not the same as
+     `(rtx *) const_tiny_rtx'.  The former has bounds that only cover
+     `const_tiny_rtx[0]', whereas the latter has bounds that cover all.  */
+  ggc_add_rtx_root ((rtx *) const_tiny_rtx, sizeof const_tiny_rtx / sizeof (rtx));
   ggc_add_rtx_root (&const_true_rtx, 1);
 
 #ifdef RETURN_ADDRESS_POINTER_REGNUM
   return_address_pointer_rtx
-    = gen_rtx_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
+    = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
 #endif
 
 #ifdef STRUCT_VALUE
@@ -4193,9 +4407,8 @@ init_emit_once (line_numbers)
 #endif
 #endif
 
-#ifdef PIC_OFFSET_TABLE_REGNUM
-  pic_offset_table_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
-#endif
+  if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
+    pic_offset_table_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
 
   ggc_add_rtx_root (&pic_offset_table_rtx, 1);
   ggc_add_rtx_root (&struct_value_rtx, 1);
@@ -4203,12 +4416,6 @@ init_emit_once (line_numbers)
   ggc_add_rtx_root (&static_chain_rtx, 1);
   ggc_add_rtx_root (&static_chain_incoming_rtx, 1);
   ggc_add_rtx_root (&return_address_pointer_rtx, 1);
-
-  /* Initialize the CONST_INT hash table.  */
-  const_int_htab = htab_create (37, const_int_htab_hash, 
-                               const_int_htab_eq, NULL);
-  ggc_add_root (&const_int_htab, 1, sizeof (const_int_htab), 
-               rtx_htab_mark);
 }
 \f
 /* Query and clear/ restore no_line_numbers.  This is used by the