OSDN Git Service

* lex.c (lang_init_options): New function.
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 2804e0d..854b989 100644 (file)
@@ -1,5 +1,5 @@
 /* Emit RTL for the GNU C-Compiler expander.
-   Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* Middle-to-low level generation of rtx code and insns.
@@ -34,15 +35,31 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    is the kind of rtx's they make and what arguments they use.  */
 
 #include "config.h"
-#include "gvarargs.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
 #include "rtl.h"
+#include "tree.h"
 #include "flags.h"
+#include "except.h"
 #include "function.h"
 #include "expr.h"
 #include "regs.h"
+#include "hard-reg-set.h"
 #include "insn-config.h"
+#include "recog.h"
 #include "real.h"
-#include <stdio.h>
+#include "obstack.h"
+#include "bitmap.h"
+
+/* Commonly used modes.  */
+
+enum machine_mode byte_mode;   /* Mode whose width is BITS_PER_UNIT.  */
+enum machine_mode word_mode;   /* Mode whose width is BITS_PER_WORD.  */
+enum machine_mode ptr_mode;    /* Mode whose width is POINTER_SIZE.  */
 
 /* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function.
    After rtl generation, it is 1 plus the largest register number used.  */
@@ -78,14 +95,19 @@ static int no_line_numbers;
    All of these except perhaps the floating-point CONST_DOUBLEs
    are unique; no other rtx-object will be equal to any of these.  */
 
-rtx pc_rtx;                    /* (PC) */
-rtx cc0_rtx;                   /* (CC0) */
-rtx cc1_rtx;                   /* (CC1) (not actually used nowadays) */
-rtx const0_rtx;                        /* (CONST_INT 0) */
-rtx const1_rtx;                        /* (CONST_INT 1) */
-rtx const2_rtx;                        /* (CONST_INT 2) */
-rtx constm1_rtx;               /* (CONST_INT -1) */
-rtx const_true_rtx;            /* (CONST_INT STORE_FLAG_VALUE) */
+struct _global_rtl global_rtl =
+{
+  {PC, VOIDmode},                      /* pc_rtx */
+  {CC0, VOIDmode},                     /* cc0_rtx */
+  {REG},                               /* stack_pointer_rtx */
+  {REG},                               /* frame_pointer_rtx */
+  {REG},                               /* hard_frame_pointer_rtx */
+  {REG},                               /* arg_pointer_rtx */
+  {REG},                               /* virtual_incoming_args_rtx */
+  {REG},                               /* virtual_stack_vars_rtx */
+  {REG},                               /* virtual_stack_dynamic_rtx */
+  {REG},                               /* virtual_outgoing_args_rtx */
+};
 
 /* We record floating-point CONST_DOUBLEs in each floating-point mode for
    the values of 0, 1, and 2.  For the integer entries and VOIDmode, we
@@ -93,6 +115,8 @@ rtx const_true_rtx;          /* (CONST_INT STORE_FLAG_VALUE) */
 
 rtx const_tiny_rtx[3][(int) MAX_MACHINE_MODE];
 
+rtx const_true_rtx;
+
 REAL_VALUE_TYPE dconst0;
 REAL_VALUE_TYPE dconst1;
 REAL_VALUE_TYPE dconst2;
@@ -107,40 +131,47 @@ REAL_VALUE_TYPE dconstm1;
    But references that were originally to the frame-pointer can be
    distinguished from the others because they contain frame_pointer_rtx.
 
+   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 
+   register elimination hard_frame_pointer_rtx should always be used.
+   On machines where the two registers are same (most) then these are the
+   same.
+
    In an inline procedure, the stack and frame pointer rtxs may not be
    used for anything else.  */
-rtx stack_pointer_rtx;         /* (REG:Pmode STACK_POINTER_REGNUM) */
-rtx frame_pointer_rtx;         /* (REG:Pmode FRAME_POINTER_REGNUM) */
-rtx arg_pointer_rtx;           /* (REG:Pmode ARG_POINTER_REGNUM) */
 rtx struct_value_rtx;          /* (REG:Pmode STRUCT_VALUE_REGNUM) */
 rtx struct_value_incoming_rtx; /* (REG:Pmode STRUCT_VALUE_INCOMING_REGNUM) */
 rtx static_chain_rtx;          /* (REG:Pmode STATIC_CHAIN_REGNUM) */
 rtx static_chain_incoming_rtx; /* (REG:Pmode STATIC_CHAIN_INCOMING_REGNUM) */
 rtx pic_offset_table_rtx;      /* (REG:Pmode PIC_OFFSET_TABLE_REGNUM) */
 
-rtx virtual_incoming_args_rtx; /* (REG:Pmode VIRTUAL_INCOMING_ARGS_REGNUM) */
-rtx virtual_stack_vars_rtx;    /* (REG:Pmode VIRTUAL_STACK_VARS_REGNUM) */
-rtx virtual_stack_dynamic_rtx; /* (REG:Pmode VIRTUAL_STACK_DYNAMIC_REGNUM) */
-rtx virtual_outgoing_args_rtx; /* (REG:Pmode VIRTUAL_OUTGOING_ARGS_REGNUM) */
+/* This is used to implement __builtin_return_address for some machines.
+   See for instance the MIPS port.  */
+rtx return_address_pointer_rtx;        /* (REG:Pmode RETURN_ADDRESS_POINTER_REGNUM) */
 
 /* We make one copy of (const_int C) where C is in
    [- MAX_SAVED_CONST_INT, MAX_SAVED_CONST_INT]
    to save space during the compilation and simplify comparisons of
    integers.  */
 
-#define MAX_SAVED_CONST_INT 64
-
-static rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
+struct rtx_def const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
 
 /* The ends of the doubly-linked chain of rtl for the current function.
    Both are reset to null at the start of rtl generation for the function.
    
-   start_sequence saves both of these on `sequence_stack' and then
-   starts a new, nested sequence of insns.  */
+   start_sequence saves both of these on `sequence_stack' along with
+   `sequence_rtl_expr' and then starts a new, nested sequence of insns.  */
 
 static rtx first_insn = NULL;
 static rtx last_insn = NULL;
 
+/* RTL_EXPR within which the current sequence will be placed.  Use to
+   prevent reuse of any temporaries within the sequence until after the
+   RTL_EXPR is emitted.  */
+
+tree sequence_rtl_expr = NULL;
+
 /* INSN_UID for next insn emitted.
    Reset to 1 for each function compiled.  */
 
@@ -161,6 +192,11 @@ static char *last_filename = 0;
 char *regno_pointer_flag;
 int regno_pointer_flag_length;
 
+/* Indexed by pseudo register number, if nonzero gives the known alignment
+   for that pseudo (if regno_pointer_flag is set).
+   Allocated in parallel with regno_pointer_flag.  */
+char *regno_pointer_align;
+
 /* Indexed by pseudo register number, gives the rtx for that pseudo.
    Allocated in parallel with regno_pointer_flag.  */
 
@@ -193,6 +229,9 @@ struct sequence_stack *sequence_stack;
 static struct sequence_stack *sequence_element_free_list;
 static rtx sequence_result[SEQUENCE_RESULT_SIZE];
 
+/* During RTL generation, we also keep a list of free INSN rtl codes.  */
+static rtx free_insn;
+
 extern int rtx_equal_function_value_matters;
 
 /* Filename and line number of last line-number note,
@@ -200,9 +239,68 @@ extern int rtx_equal_function_value_matters;
 extern char *emit_filename;
 extern int emit_lineno;
 
-rtx change_address ();
-void init_emit ();
+static rtx make_jump_insn_raw          PROTO((rtx));
+static rtx make_call_insn_raw          PROTO((rtx));
+static rtx find_line_note              PROTO((rtx));
 \f
+rtx
+gen_rtx_CONST_INT (mode, arg)
+     enum machine_mode mode;
+     HOST_WIDE_INT arg;
+{
+  if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT)
+    return &const_int_rtx[arg + MAX_SAVED_CONST_INT];
+
+#if STORE_FLAG_VALUE != 1 && STORE_FLAG_VALUE != -1
+  if (const_true_rtx && arg == STORE_FLAG_VALUE)
+    return const_true_rtx;
+#endif
+
+  return gen_rtx_raw_CONST_INT (mode, arg);
+}
+
+rtx
+gen_rtx_REG (mode, regno)
+     enum machine_mode mode;
+     int regno;
+{
+  /* In case the MD file explicitly references the frame pointer, have
+     all such references point to the same frame pointer.  This is
+     used during frame pointer elimination to distinguish the explicit
+     references to these registers from pseudos that happened to be
+     assigned to them.
+
+     If we have eliminated the frame pointer or arg pointer, we will
+     be using it as a normal register, for example as a spill
+     register.  In such cases, we might be accessing it in a mode that
+     is not Pmode and therefore cannot use the pre-allocated rtx.
+
+     Also don't do this when we are making new REGs in reload, since
+     we don't want to get confused with the real pointers.  */
+
+  if (mode == Pmode && !reload_in_progress)
+    {
+      if (regno == FRAME_POINTER_REGNUM)
+       return frame_pointer_rtx;
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+      if (regno == HARD_FRAME_POINTER_REGNUM)
+       return hard_frame_pointer_rtx;
+#endif
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+      if (regno == ARG_POINTER_REGNUM)
+       return arg_pointer_rtx;
+#endif
+#ifdef RETURN_ADDRESS_POINTER_REGNUM
+      if (regno == RETURN_ADDRESS_POINTER_REGNUM)
+       return return_address_pointer_rtx;
+#endif
+      if (regno == STACK_POINTER_REGNUM)
+       return stack_pointer_rtx;
+    }
+
+  return gen_rtx_raw_REG (mode, regno);
+}
+
 /* rtx gen_rtx (code, mode, [element1, ..., elementn])
 **
 **         This routine generates an RTX of the size specified by
@@ -212,7 +310,7 @@ void init_emit ();
 **     special machine mode associated with the rtx (if any) is specified
 **     in <mode>.
 **
-**         gen_rtx() can be invoked in a way which resembles the lisp-like
+**         gen_rtx can be invoked in a way which resembles the lisp-like
 **     rtx it will generate.   For example, the following rtx structure:
 **
 **           (plus:QI (mem:QI (reg:SI 1))
@@ -231,70 +329,28 @@ void init_emit ();
 
 /*VARARGS2*/
 rtx
-gen_rtx (va_alist)
-     va_dcl
+gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...))
 {
-  va_list p;
+#ifndef __STDC__
   enum rtx_code code;
   enum machine_mode mode;
+#endif
+  va_list p;
   register int i;              /* Array indices...                     */
   register char *fmt;          /* Current rtx's format...              */
   register rtx rt_val;         /* RTX to return to caller...           */
 
-  va_start (p);
+  VA_START (p, mode);
+
+#ifndef __STDC__
   code = va_arg (p, enum rtx_code);
   mode = va_arg (p, enum machine_mode);
+#endif
 
   if (code == CONST_INT)
-    {
-      HOST_WIDE_INT arg = va_arg (p, HOST_WIDE_INT);
-
-      if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT)
-       return const_int_rtx[arg + MAX_SAVED_CONST_INT];
-
-      if (const_true_rtx && arg == STORE_FLAG_VALUE)
-       return const_true_rtx;
-
-      rt_val = rtx_alloc (code);
-      INTVAL (rt_val) = arg;
-    }
+    rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT));
   else if (code == REG)
-    {
-      int regno = va_arg (p, int);
-
-      /* In case the MD file explicitly references the frame pointer, have
-        all such references point to the same frame pointer.  This is used
-        during frame pointer elimination to distinguish the explicit
-        references to these registers from pseudos that happened to be
-        assigned to them.
-
-        If we have eliminated the frame pointer or arg pointer, we will
-        be using it as a normal register, for example as a spill register.
-        In such cases, we might be accessing it in a mode that is not
-        Pmode and therefore cannot use the pre-allocated rtx.
-
-        Also don't do this when we are making new REGs in reload,
-        since we don't want to get confused with the real pointers.  */
-
-      if (frame_pointer_rtx && regno == FRAME_POINTER_REGNUM && mode == Pmode
-         && ! reload_in_progress)
-       return frame_pointer_rtx;
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-      if (arg_pointer_rtx && regno == ARG_POINTER_REGNUM && mode == Pmode
-         && ! reload_in_progress)
-       return arg_pointer_rtx;
-#endif
-      if (stack_pointer_rtx && regno == STACK_POINTER_REGNUM && mode == Pmode
-         && ! reload_in_progress)
-       return stack_pointer_rtx;
-      else
-       {
-         rt_val = rtx_alloc (code);
-         rt_val->mode = mode;
-         REGNO (rt_val) = regno;
-         return rt_val;
-       }
-    }
+    rt_val = gen_rtx_REG (mode, va_arg (p, int));
   else
     {
       rt_val = rtx_alloc (code);       /* Allocate the storage space.  */
@@ -329,8 +385,16 @@ gen_rtx (va_alist)
              XVEC (rt_val, i) = va_arg (p, rtvec);
              break;
 
+           case 'b':           /* A bitmap? */
+             XBITMAP (rt_val, i) = va_arg (p, bitmap);
+             break;
+
+           case 't':           /* A tree? */
+             XTREE (rt_val, i) = va_arg (p, tree);
+             break;
+
            default:
-             abort();
+             abort ();
            }
        }
     }
@@ -346,20 +410,26 @@ gen_rtx (va_alist)
 
 /*VARARGS1*/
 rtvec
-gen_rtvec (va_alist)
-     va_dcl
+gen_rtvec VPROTO((int n, ...))
 {
-  int n, i;
+#ifndef __STDC__
+  int n;
+#endif
+  int i;
   va_list p;
   rtx *vector;
 
-  va_start (p);
+  VA_START (p, n);
+
+#ifndef __STDC__
   n = va_arg (p, int);
+#endif
 
   if (n == 0)
     return NULL_RTVEC;         /* Don't allocate an empty rtvec...     */
 
   vector = (rtx *) alloca (n * sizeof (rtx));
+
   for (i = 0; i < n; i++)
     vector[i] = va_arg (p, rtx);
   va_end (p);
@@ -385,6 +455,25 @@ gen_rtvec_v (n, argp)
 
   return rt_val;
 }
+
+rtvec
+gen_rtvec_vv (n, argp)
+     int n;
+     rtunion *argp;
+{
+  register int i;
+  register rtvec rt_val;
+
+  if (n == 0)
+    return NULL_RTVEC;         /* Don't allocate an empty rtvec...     */
+
+  rt_val = rtvec_alloc (n);    /* Allocate an rtvec...                 */
+
+  for (i = 0; i < n; i++)
+    rt_val->elem[i].rtx = (argp++)->rtx;
+
+  return rt_val;
+}
 \f
 /* Generate a REG rtx for a new pseudo register of mode MODE.
    This pseudo is assigned the next sequential register number.  */
@@ -402,6 +491,27 @@ gen_reg_rtx (mode)
   if (reload_in_progress || reload_completed)
     abort ();
 
+  if (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.
+        This allows noncontiguous allocation of the real and imaginary parts,
+        which makes much better code.  Besides, allocating DCmode
+        pseudos overstrains reload on some machines like the 386.  */
+      rtx realpart, imagpart;
+      int size = GET_MODE_UNIT_SIZE (mode);
+      enum machine_mode partmode
+       = mode_for_size (size * BITS_PER_UNIT,
+                        (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+                         ? MODE_FLOAT : MODE_INT),
+                        0);
+
+      realpart = gen_reg_rtx (partmode);
+      imagpart = gen_reg_rtx (partmode);
+      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.  */
 
@@ -409,31 +519,60 @@ gen_reg_rtx (mode)
     {
       rtx *new1;
       char *new =
-       (char *) oballoc (regno_pointer_flag_length * 2);
-      bzero (new, regno_pointer_flag_length * 2);
+       (char *) savealloc (regno_pointer_flag_length * 2);
       bcopy (regno_pointer_flag, new, regno_pointer_flag_length);
+      bzero (&new[regno_pointer_flag_length], regno_pointer_flag_length);
       regno_pointer_flag = new;
 
-      new1 = (rtx *) oballoc (regno_pointer_flag_length * 2 * sizeof (rtx));
-      bzero (new1, regno_pointer_flag_length * 2 * sizeof (rtx));
-      bcopy (regno_reg_rtx, new1, regno_pointer_flag_length * sizeof (rtx));
+      new = (char *) savealloc (regno_pointer_flag_length * 2);
+      bcopy (regno_pointer_align, new, regno_pointer_flag_length);
+      bzero (&new[regno_pointer_flag_length], regno_pointer_flag_length);
+      regno_pointer_align = new;
+
+      new1 = (rtx *) savealloc (regno_pointer_flag_length * 2 * sizeof (rtx));
+      bcopy ((char *) regno_reg_rtx, (char *) new1,
+            regno_pointer_flag_length * sizeof (rtx));
+      bzero ((char *) &new1[regno_pointer_flag_length],
+            regno_pointer_flag_length * sizeof (rtx));
       regno_reg_rtx = new1;
 
       regno_pointer_flag_length *= 2;
     }
 
-  val = gen_rtx (REG, mode, reg_rtx_no);
+  val = gen_rtx_raw_REG (mode, reg_rtx_no);
   regno_reg_rtx[reg_rtx_no++] = val;
   return val;
 }
 
-/* Identify REG as a probable pointer register.  */
+/* Identify REG (which may be a CONCAT) as a user register.  */
+
+void
+mark_user_reg (reg)
+     rtx reg;
+{
+  if (GET_CODE (reg) == CONCAT)
+    {
+      REG_USERVAR_P (XEXP (reg, 0)) = 1;
+      REG_USERVAR_P (XEXP (reg, 1)) = 1;
+    }
+  else if (GET_CODE (reg) == REG)
+    REG_USERVAR_P (reg) = 1;
+  else
+    abort ();
+}
+
+/* Identify REG as a probable pointer register and show its alignment
+   as ALIGN, if nonzero.  */
 
 void
-mark_reg_pointer (reg)
+mark_reg_pointer (reg, align)
      rtx reg;
+     int align;
 {
   REGNO_POINTER_FLAG (REGNO (reg)) = 1;
+
+  if (align)
+    REGNO_POINTER_ALIGN (REGNO (reg)) = align;
 }
 
 /* Return 1 plus largest pseudo reg number used in the current function.  */
@@ -512,37 +651,60 @@ gen_lowpart_common (mode, x)
       else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (XEXP (x, 0))))
        return gen_lowpart_common (mode, XEXP (x, 0));
       else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x)))
-       return gen_rtx (GET_CODE (x), mode, XEXP (x, 0));
+       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))))
     return (GET_MODE (SUBREG_REG (x)) == mode && SUBREG_WORD (x) == 0
            ? SUBREG_REG (x)
-           : gen_rtx (SUBREG, mode, SUBREG_REG (x), SUBREG_WORD (x)));
+           : gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + word));
   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.  */
+        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) + word, mode)
+         && HARD_REGNO_MODE_OK (REGNO (x), GET_MODE (x)))
        return 0;
       else 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)
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+              && ! (GET_MODE_SIZE (mode) != GET_MODE_SIZE (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],
+                         REGNO (x))))
+#endif
               /* We want to keep the stack, frame, and arg pointers
                  special.  */
-              && REGNO (x) != FRAME_POINTER_REGNUM
+              && x != frame_pointer_rtx
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-              && REGNO (x) != ARG_POINTER_REGNUM
+              && x != arg_pointer_rtx
 #endif
-              && REGNO (x) != STACK_POINTER_REGNUM)
-       return gen_rtx (REG, mode, REGNO (x) + word);
+              && x != stack_pointer_rtx)
+       return gen_rtx_REG (mode, REGNO (x) + word);
       else
-       return gen_rtx (SUBREG, mode, x, word);
+       return gen_rtx_SUBREG (mode, x, word);
     }
-
   /* 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
@@ -558,7 +720,7 @@ gen_lowpart_common (mode, x)
         either a reasonable negative value or a reasonable unsigned value
         for this mode.  */
 
-      if (GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT)
+      if (GET_MODE_BITSIZE (mode) >= 2 * HOST_BITS_PER_WIDE_INT)
        return x;
       else if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
        return 0;
@@ -567,14 +729,13 @@ gen_lowpart_common (mode, x)
                : GEN_INT (CONST_DOUBLE_LOW (x)));
       else
        {
-         /* MODE must be narrower than HOST_BITS_PER_INT.  */
+         /* 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));
 
-         if (((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-              != ((HOST_WIDE_INT) (-1) << (width - 1))))
-           val &= ((HOST_WIDE_INT) 1 << width) - 1;
+         /* Sign extend to HOST_WIDE_INT.  */
+         val = val << (HOST_BITS_PER_WIDE_INT - width) >> (HOST_BITS_PER_WIDE_INT - width);
 
          return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x
                  : GEN_INT (val));
@@ -594,13 +755,23 @@ 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 immed_real_const_1 (u.d, mode);
+      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)
@@ -610,6 +781,28 @@ 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;
@@ -625,8 +818,24 @@ gen_lowpart_common (mode, x)
       u.i[0] = low, u.i[1] = high;
 #endif
 
-      return immed_real_const_1 (u.d, mode);
+      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);
+    }
+#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
@@ -640,7 +849,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, 0, 0, GET_MODE (x));
+    return operand_subword (x, word, 0, 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
@@ -656,8 +865,10 @@ 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, WORDS_BIG_ENDIAN, 0, GET_MODE (x));
-      rtx highpart = operand_subword (x, ! WORDS_BIG_ENDIAN, 0, GET_MODE (x));
+      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));
 
       if (lowpart && GET_CODE (lowpart) == CONST_INT
          && highpart && GET_CODE (highpart) == CONST_INT)
@@ -676,7 +887,9 @@ gen_realpart (mode, x)
      enum machine_mode mode;
      register rtx x;
 {
-  if (WORDS_BIG_ENDIAN)
+  if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode)
+    return XEXP (x, 0);
+  else if (WORDS_BIG_ENDIAN)
     return gen_highpart (mode, x);
   else
     return gen_lowpart (mode, x);
@@ -690,11 +903,28 @@ gen_imagpart (mode, x)
      enum machine_mode mode;
      register rtx x;
 {
-  if (WORDS_BIG_ENDIAN)
+  if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode)
+    return XEXP (x, 1);
+  else if (WORDS_BIG_ENDIAN)
     return gen_lowpart (mode, x);
   else
     return gen_highpart (mode, x);
 }
+
+/* Return 1 iff X, assumed to be a SUBREG,
+   refers to the real part of the complex value in its containing reg.
+   Complex values are always stored with the real part in the first word,
+   regardless of WORDS_BIG_ENDIAN.  */
+
+int
+subreg_realpart_p (x)
+     rtx x;
+{
+  if (GET_CODE (x) != SUBREG)
+    abort ();
+
+  return SUBREG_WORD (x) == 0;
+}
 \f
 /* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a value,
    return an rtx (MEM, SUBREG, or CONST_INT) that refers to the
@@ -712,6 +942,14 @@ gen_lowpart (mode, x)
 
   if (result)
     return result;
+  else if (GET_CODE (x) == REG)
+    {
+      /* Must be a hard reg that's not valid in MODE.  */
+      result = gen_lowpart_common (mode, copy_to_reg (x));
+      if (result == 0)
+       abort ();
+      return result;
+    }
   else if (GET_CODE (x) == MEM)
     {
       /* The only additional case we can do is MEM.  */
@@ -728,6 +966,8 @@ gen_lowpart (mode, x)
 
       return change_address (x, mode, plus_constant (XEXP (x, 0), offset));
     }
+  else if (GET_CODE (x) == ADDRESSOF)
+    return gen_lowpart (mode, force_reg (GET_MODE (x), x));
   else
     abort ();
 }
@@ -746,27 +986,30 @@ gen_highpart (mode, x)
       && GET_MODE_SIZE (mode) != 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))
+#if !(TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT || defined (REAL_IS_NOT_DOUBLE))
       && GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT
 #endif
       )
-    return gen_rtx (CONST_INT, VOIDmode,
-                   CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode));
+    return GEN_INT (CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode));
   else if (GET_CODE (x) == CONST_INT)
-    return const0_rtx;
+    {
+      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 (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
-               - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
-#endif
-#if !BYTES_BIG_ENDIAN
-      if (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+      if (! WORDS_BIG_ENDIAN)
+       offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
+                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
+
+      if (! BYTES_BIG_ENDIAN
+         && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        offset -= (GET_MODE_SIZE (mode)
                   - MIN (UNITS_PER_WORD,
                          GET_MODE_SIZE (GET_MODE (x))));
-#endif
+
       return change_address (x, mode, plus_constant (XEXP (x, 0), offset));
     }
   else if (GET_CODE (x) == SUBREG)
@@ -780,24 +1023,38 @@ gen_highpart (mode, x)
     }
   else if (GET_CODE (x) == REG)
     {
-      int word = 0;
+      int word;
+
+      /* 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
-      if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
+      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);
-#endif
+
       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)
          /* We want to keep the stack, frame, and arg pointers special.  */
-         && REGNO (x) != FRAME_POINTER_REGNUM
+         && x != frame_pointer_rtx
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-         && REGNO (x) != ARG_POINTER_REGNUM
+         && x != arg_pointer_rtx
 #endif
-         && REGNO (x) != STACK_POINTER_REGNUM)
-       return gen_rtx (REG, mode, REGNO (x) + word);
+         && x != stack_pointer_rtx)
+       return gen_rtx_REG (mode, REGNO (x) + word);
       else
-       return gen_rtx (SUBREG, mode, x, word);
+       return gen_rtx_SUBREG (mode, x, word);
     }
   else
     abort ();
@@ -813,6 +1070,8 @@ subreg_lowpart_p (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)
@@ -850,6 +1109,7 @@ operand_subword (op, i, validate_address, mode)
 {
   HOST_WIDE_INT val;
   int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD;
+  int bits_per_word = BITS_PER_WORD;
 
   if (mode == VOIDmode)
     mode = GET_MODE (op);
@@ -881,17 +1141,25 @@ operand_subword (op, i, validate_address, mode)
                   && rtx_equal_function_value_matters)
               /* We want to keep the stack, frame, and arg pointers
                  special.  */
-              || REGNO (op) == FRAME_POINTER_REGNUM
+              || op == frame_pointer_rtx
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-              || REGNO (op) == ARG_POINTER_REGNUM
+              || op == arg_pointer_rtx
 #endif
-              || REGNO (op) == STACK_POINTER_REGNUM)
-       return gen_rtx (SUBREG, word_mode, op, i);
+              || op == stack_pointer_rtx)
+       return gen_rtx_SUBREG (word_mode, op, i);
       else
-       return gen_rtx (REG, word_mode, REGNO (op) + i);
+       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));
+    return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
+  else if (GET_CODE (op) == CONCAT)
+    {
+      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)
@@ -910,7 +1178,7 @@ operand_subword (op, i, validate_address, mode)
            addr = memory_address (word_mode, addr);
        }
 
-      new = gen_rtx (MEM, word_mode, addr);
+      new = gen_rtx_MEM (word_mode, addr);
 
       MEM_VOLATILE_P (new) = MEM_VOLATILE_P (op);
       MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (op);
@@ -921,7 +1189,63 @@ operand_subword (op, i, validate_address, mode)
 
   /* 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.  */
+     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
+    host can't.  */
+  if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
+      && GET_MODE_CLASS (mode) == MODE_FLOAT
+      && GET_MODE_BITSIZE (mode) == 64
+      && GET_CODE (op) == CONST_DOUBLE)
+    {
+      long k[2];
+      REAL_VALUE_TYPE rv;
+
+      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
+
+      /* We handle 32-bit and >= 64-bit words here.  Note that the order in
+        which the words are written depends on the word endianness.
+
+        ??? This is a potential portability problem and should
+        be fixed at some point.  */
+      if (BITS_PER_WORD == 32)
+       return GEN_INT ((HOST_WIDE_INT) k[i]);
+#if HOST_BITS_PER_WIDE_INT > 32
+      else if (BITS_PER_WORD >= 64 && i == 0)
+       return GEN_INT ((((HOST_WIDE_INT) k[! WORDS_BIG_ENDIAN]) << 32)
+                       | (HOST_WIDE_INT) k[WORDS_BIG_ENDIAN]);
+#endif
+      else if (BITS_PER_WORD == 16)
+       {
+         long value;
+         value = k[i >> 1];
+         if ((i & 0x1) == !WORDS_BIG_ENDIAN)
+           value >>= 16;
+         value &= 0xffff;
+         return GEN_INT ((HOST_WIDE_INT) value);
+       }
+      else
+       abort ();
+    }
+  else if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
+          && GET_MODE_CLASS (mode) == MODE_FLOAT
+          && GET_MODE_BITSIZE (mode) > 64
+          && GET_CODE (op) == CONST_DOUBLE)
+  {
+    long k[4];
+    REAL_VALUE_TYPE rv;
+
+    REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+    REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+
+    if (BITS_PER_WORD == 32)
+      return GEN_INT ((HOST_WIDE_INT) k[i]);
+  }
+#else /* no REAL_ARITHMETIC */
   if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
        && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
        || flag_pretend_float)
@@ -941,13 +1265,35 @@ operand_subword (op, i, validate_address, mode)
                      ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));
 #endif
     }
+#endif /* no REAL_ARITHMETIC */
 
   /* Single word float is a little harder, since single- and double-word
      values often do not have the same high-order bits.  We have already
      verified that we want the only defined word of the single-word value.  */
+#ifdef REAL_ARITHMETIC
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT
+      && GET_MODE_BITSIZE (mode) == 32
+      && GET_CODE (op) == CONST_DOUBLE)
+    {
+      long l;
+      REAL_VALUE_TYPE rv;
+
+      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+
+      if (BITS_PER_WORD == 16)
+       {
+         if ((i & 0x1) == !WORDS_BIG_ENDIAN)
+           l >>= 16;
+         l &= 0xffff;
+       }
+      return GEN_INT ((HOST_WIDE_INT) l);
+    }
+#else
   if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
        && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
        || flag_pretend_float)
+      && sizeof (float) * 8 == HOST_BITS_PER_WIDE_INT
       && GET_MODE_CLASS (mode) == MODE_FLOAT
       && GET_MODE_SIZE (mode) == UNITS_PER_WORD
       && GET_CODE (op) == CONST_DOUBLE)
@@ -960,20 +1306,38 @@ operand_subword (op, i, validate_address, mode)
       u.f = d;
       return GEN_INT (u.i);
     }
+  if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
+       && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
+       || flag_pretend_float)
+      && sizeof (double) * 8 == HOST_BITS_PER_WIDE_INT
+      && GET_MODE_CLASS (mode) == MODE_FLOAT
+      && GET_MODE_SIZE (mode) == UNITS_PER_WORD
+      && GET_CODE (op) == CONST_DOUBLE)
+    {
+      double d;
+      union {double d; HOST_WIDE_INT i; } u;
+
+      REAL_VALUE_FROM_CONST_DOUBLE (d, op);
+
+      u.d = d;
+      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, i == 0 means the low-order word.  
 
-     Note that it must be that BITS_PER_WORD <= HOST_BITS_PER_INT.
-     This is because if it were greater, it could only have been two
-     times greater since we do not support making wider constants.  In
-     that case, it MODE would have already been the proper size and
-     it would have been handled above.  This means we do not have to
-     worry about the case where we would be returning a CONST_DOUBLE.  */
+     We do not want to handle the case when BITS_PER_WORD <= HOST_BITS_PER_INT
+     in general.  However, if OP is (const_int 0), we can just return
+     it for any word.  */
+
+  if (op == const0_rtx)
+    return op;
 
   if (GET_MODE_CLASS (mode) != MODE_INT
-      || (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE))
+      || (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE)
+      || BITS_PER_WORD > HOST_BITS_PER_WIDE_INT)
     return 0;
 
   if (WORDS_BIG_ENDIAN)
@@ -986,11 +1350,30 @@ operand_subword (op, i, validate_address, mode)
         : (GET_CODE (op) == CONST_INT
            ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op)));
 
-  /* If BITS_PER_WORD is smaller than an int, get the appropriate bits.  */
+  /* 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))
-          & (((HOST_WIDE_INT) 1
-              << (BITS_PER_WORD % HOST_BITS_PER_WIDE_INT)) - 1));
+    val = ((val >> ((i % size_ratio) * BITS_PER_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.  */
+  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
+      && ((val & ((HOST_WIDE_INT) (-1) << (bits_per_word - 1)))
+          != ((HOST_WIDE_INT) (-1) << (bits_per_word - 1))))
+    val &= ((HOST_WIDE_INT) 1 << bits_per_word) - 1;
+
+  /* If this would be an entire word for the target, but is not for
+     the host, then sign-extend on the host so that the number will look
+     the same way on the host that it would on the target.
+
+     For example, when building a 64 bit alpha hosted 32 bit sparc
+     targeted compiler, then we want the 32 bit unsigned value -1 to be
+     represented as a 64 bit value -1, and not as 0x00000000ffffffff.
+     The later confuses the sparc backend.  */
+
+  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
+      && (val & ((HOST_WIDE_INT) 1 << (bits_per_word - 1))))
+    val |= ((HOST_WIDE_INT) (-1) << bits_per_word);
 
   return GEN_INT (val);
 }
@@ -1015,7 +1398,14 @@ operand_subword_force (op, i, mode)
     return result;
 
   if (mode != BLKmode && mode != VOIDmode)
-    op = force_reg (mode, op);
+    {
+      /* If this is a register which can not be accessed by words, copy it
+        to a pseudo register.  */
+      if (GET_CODE (op) == REG)
+       op = copy_to_reg (op);
+      else
+       op = force_reg (mode, op);
+    }
 
   result = operand_subword (op, i, 1, mode);
   if (result == 0)
@@ -1048,8 +1438,7 @@ reverse_comparison (insn)
     }
   else
     {
-      rtx new = gen_rtx (COMPARE, VOIDmode,
-                        CONST0_RTX (GET_MODE (comp)), comp);
+      rtx new = gen_rtx_COMPARE (VOIDmode, CONST0_RTX (GET_MODE (comp)), comp);
       if (GET_CODE (body) == SET)
        SET_SRC (body) = new;
       else
@@ -1087,7 +1476,10 @@ change_address (memref, mode, addr)
   else
     addr = memory_address (mode, addr);
        
-  new = gen_rtx (MEM, mode, addr);
+  if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref))
+    return memref;
+
+  new = gen_rtx_MEM (mode, addr);
   MEM_VOLATILE_P (new) = MEM_VOLATILE_P (memref);
   RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (memref);
   MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (memref);
@@ -1099,8 +1491,11 @@ change_address (memref, mode, addr)
 rtx
 gen_label_rtx ()
 {
-  register rtx label = gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0,
-                               label_num++, NULL_PTR);
+  register rtx label;
+
+  label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX,
+                             NULL_RTX, label_num++, NULL_PTR);
+
   LABEL_NUSES (label) = 0;
   return label;
 }
@@ -1113,37 +1508,56 @@ gen_label_rtx ()
 rtx
 gen_inline_header_rtx (first_insn, first_parm_insn, first_labelno,
                       last_labelno, max_parm_regnum, max_regnum, args_size,
-                      pops_args, stack_slots, function_flags,
+                      pops_args, stack_slots, forced_labels, function_flags,
                       outgoing_args_size, original_arg_vector,
-                      original_decl_initial)
+                      original_decl_initial, regno_rtx, regno_flag,
+                      regno_align, parm_reg_stack_loc)
      rtx first_insn, first_parm_insn;
      int first_labelno, last_labelno, max_parm_regnum, max_regnum, args_size;
      int pops_args;
      rtx stack_slots;
+     rtx forced_labels;
      int function_flags;
      int outgoing_args_size;
      rtvec original_arg_vector;
      rtx original_decl_initial;
-{
-  rtx header = gen_rtx (INLINE_HEADER, VOIDmode,
-                       cur_insn_uid++, NULL_RTX,
-                       first_insn, first_parm_insn,
-                       first_labelno, last_labelno,
-                       max_parm_regnum, max_regnum, args_size, pops_args,
-                       stack_slots, function_flags, outgoing_args_size,
-                       original_arg_vector, original_decl_initial);
+     rtvec regno_rtx;
+     char *regno_flag;
+     char *regno_align;
+     rtvec parm_reg_stack_loc;
+{
+  rtx header = gen_rtx_INLINE_HEADER (VOIDmode,
+                                     cur_insn_uid++, NULL_RTX,
+                                     first_insn, first_parm_insn,
+                                     first_labelno, last_labelno,
+                                     max_parm_regnum, max_regnum, args_size,
+                                     pops_args, stack_slots, forced_labels,
+                                     function_flags, outgoing_args_size,
+                                     original_arg_vector,
+                                     original_decl_initial,
+                                     regno_rtx, regno_flag, regno_align,
+                                     parm_reg_stack_loc);
   return header;
 }
 
 /* Install new pointers to the first and last insns in the chain.
+   Also, set cur_insn_uid to one higher than the last in use.
    Used for an inline-procedure after copying the insn chain.  */
 
 void
 set_new_first_and_last_insn (first, last)
      rtx first, last;
 {
+  rtx insn;
+
   first_insn = first;
   last_insn = last;
+  cur_insn_uid = 0;
+
+  for (insn = first; insn; insn = NEXT_INSN (insn))
+    cur_insn_uid = MAX (cur_insn_uid, INSN_UID (insn));
+
+  cur_insn_uid++;
 }
 
 /* Set the range of label numbers found in the current function.
@@ -1169,11 +1583,13 @@ save_emit_status (p)
   p->first_label_num = first_label_num;
   p->first_insn = first_insn;
   p->last_insn = last_insn;
+  p->sequence_rtl_expr = sequence_rtl_expr;
   p->sequence_stack = sequence_stack;
   p->cur_insn_uid = cur_insn_uid;
   p->last_linenum = last_linenum;
   p->last_filename = last_filename;
   p->regno_pointer_flag = regno_pointer_flag;
+  p->regno_pointer_align = regno_pointer_align;
   p->regno_pointer_flag_length = regno_pointer_flag_length;
   p->regno_reg_rtx = regno_reg_rtx;
 }
@@ -1189,20 +1605,26 @@ restore_emit_status (p)
 
   reg_rtx_no = p->reg_rtx_no;
   first_label_num = p->first_label_num;
+  last_label_num = 0;
   first_insn = p->first_insn;
   last_insn = p->last_insn;
+  sequence_rtl_expr = p->sequence_rtl_expr;
   sequence_stack = p->sequence_stack;
   cur_insn_uid = p->cur_insn_uid;
   last_linenum = p->last_linenum;
   last_filename = p->last_filename;
   regno_pointer_flag = p->regno_pointer_flag;
+  regno_pointer_align = p->regno_pointer_align;
   regno_pointer_flag_length = p->regno_pointer_flag_length;
   regno_reg_rtx = p->regno_reg_rtx;
 
-  /* Clear our cache of rtx expressions for start_sequence and gen_sequence. */
+  /* Clear our cache of rtx expressions for start_sequence and
+     gen_sequence.  */
   sequence_element_free_list = 0;
   for (i = 0; i < SEQUENCE_RESULT_SIZE; i++)
     sequence_result[i] = 0;
+
+  free_insn = 0;
 }
 \f
 /* Go through all the RTL insn bodies and copy any invalid shared structure.
@@ -1264,7 +1686,7 @@ copy_rtx_if_shared (orig)
     case PC:
     case CC0:
     case SCRATCH:
-      /* SCRATCH must be shared because they represent distinct values. */
+      /* SCRATCH must be shared because they represent distinct values.  */
       return x;
 
     case CONST:
@@ -1280,7 +1702,6 @@ copy_rtx_if_shared (orig)
     case JUMP_INSN:
     case CALL_INSN:
     case NOTE:
-    case LABEL_REF:
     case BARRIER:
       /* The chain of insns is not being copied.  */
       return x;
@@ -1305,6 +1726,10 @@ copy_rtx_if_shared (orig)
          x->used = 1;
          return x;
        }
+      break;
+
+    default:
+      break;
     }
 
   /* This rtx may not be shared.  If it has already been seen,
@@ -1315,8 +1740,9 @@ copy_rtx_if_shared (orig)
       register rtx copy;
 
       copy = rtx_alloc (code);
-      bcopy (x, copy, (sizeof (*copy) - sizeof (copy->fld)
-                      + sizeof (copy->fld[0]) * GET_RTX_LENGTH (code)));
+      bcopy ((char *) x, (char *) copy,
+            (sizeof (*copy) - sizeof (copy->fld)
+             + sizeof (copy->fld[0]) * GET_RTX_LENGTH (code)));
       x = copy;
       copied = 1;
     }
@@ -1341,12 +1767,12 @@ copy_rtx_if_shared (orig)
          if (XVEC (x, i) != NULL)
            {
              register int j;
+             int len = XVECLEN (x, i);
 
-             if (copied)
-               XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0));
-             for (j = 0; j < XVECLEN (x, i); j++)
-               XVECEXP (x, i, j)
-                 = copy_rtx_if_shared (XVECEXP (x, i, j));
+             if (copied && len > 0)
+               XVEC (x, i) = gen_rtvec_vv (len, XVEC (x, i)->elem);
+             for (j = 0; j < len; j++)
+               XVECEXP (x, i, j) = copy_rtx_if_shared (XVECEXP (x, i, j));
            }
          break;
        }
@@ -1364,14 +1790,13 @@ reset_used_flags (x)
   register int i, j;
   register enum rtx_code code;
   register char *format_ptr;
-  int copied = 0;
 
   if (x == 0)
     return;
 
   code = GET_CODE (x);
 
-  /* These types may be freely shared so we needn't do any reseting
+  /* These types may be freely shared so we needn't do any resetting
      for them.  */
 
   switch (code)
@@ -1394,6 +1819,9 @@ reset_used_flags (x)
     case BARRIER:
       /* The chain of insns is not being copied.  */
       return;
+      
+    default:
+      break;
     }
 
   x->used = 0;
@@ -1576,7 +2004,7 @@ prev_nonnote_insn (insn)
 
 /* Return the next INSN, CALL_INSN or JUMP_INSN after INSN;
    or 0, if there is none.  This routine does not look inside
-   SEQUENCEs. */
+   SEQUENCEs.  */
 
 rtx
 next_real_insn (insn)
@@ -1703,9 +2131,8 @@ link_cc0_insns (insn)
   if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE)
     user = XVECEXP (PATTERN (user), 0, 0);
 
-  REG_NOTES (user) = gen_rtx (INSN_LIST, REG_CC_SETTER, insn,
-                             REG_NOTES (user));
-  REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_CC_USER, user, REG_NOTES (insn));
+  REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn, REG_NOTES (user));
+  REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn));
 }
 
 /* Return the next insn that uses CC0 after INSN, which is assumed to
@@ -1745,7 +2172,6 @@ prev_cc0_setter (insn)
      rtx insn;
 {
   rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
-  rtx link;
 
   if (note)
     return XEXP (note, 0);
@@ -1761,16 +2187,16 @@ prev_cc0_setter (insn)
 /* Try splitting insns that can be split for better scheduling.
    PAT is the pattern which might split.
    TRIAL is the insn providing PAT.
-   BACKWARDS is non-zero if we are scanning insns from last to first.
+   LAST is non-zero if we should return the last insn of the sequence produced.
 
    If this routine succeeds in splitting, it returns the first or last
-   replacement insn depending on the value of BACKWARDS.  Otherwise, it
+   replacement insn depending on the value of LAST.  Otherwise, it
    returns TRIAL.  If the insn to be returned can be split, it will be.  */
 
 rtx
-try_split (pat, trial, backwards)
+try_split (pat, trial, last)
      rtx pat, trial;
-     int backwards;
+     int last;
 {
   rtx before = PREV_INSN (trial);
   rtx after = NEXT_INSN (trial);
@@ -1813,6 +2239,16 @@ try_split (pat, trial, backwards)
          delete_insn (trial);
          if (has_barrier)
            emit_barrier_after (tem);
+
+         /* Recursively call try_split for each new insn created; by the
+            time control returns here that insn will be fully split, so
+            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))
+             tem = try_split (PATTERN (tem), tem, 1);
        }
       /* Avoid infinite loop if the result matches the original pattern.  */
       else if (rtx_equal_p (seq, pat))
@@ -1821,11 +2257,12 @@ try_split (pat, trial, backwards)
        {
          PATTERN (trial) = seq;
          INSN_CODE (trial) = -1;
+         try_split (seq, trial, last);
        }
 
-      /* Set TEM to the insn we should return.  */
-      tem = backwards ? prev_active_insn (after) : next_active_insn (before);
-      return try_split (PATTERN (tem), tem, backwards);
+      /* Return either the first or the last insn, depending on which was
+        requested.  */
+      return last ? prev_active_insn (after) : next_active_insn (before);
     }
 
   return trial;
@@ -1840,13 +2277,21 @@ make_insn_raw (pattern)
 {
   register rtx insn;
 
-  insn = rtx_alloc(INSN);
-  INSN_UID(insn) = cur_insn_uid++;
+  /* If in RTL generation phase, see if FREE_INSN can be used.  */
+  if (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_UID (insn) = cur_insn_uid++;
   PATTERN (insn) = pattern;
   INSN_CODE (insn) = -1;
-  LOG_LINKS(insn) = NULL;
-  REG_NOTES(insn) = NULL;
+  LOG_LINKS (insn) = NULL;
+  REG_NOTES (insn) = NULL;
 
   return insn;
 }
@@ -1860,13 +2305,33 @@ make_jump_insn_raw (pattern)
   register rtx insn;
 
   insn = rtx_alloc (JUMP_INSN);
-  INSN_UID(insn) = cur_insn_uid++;
+  INSN_UID (insn) = cur_insn_uid++;
 
   PATTERN (insn) = pattern;
   INSN_CODE (insn) = -1;
-  LOG_LINKS(insn) = NULL;
-  REG_NOTES(insn) = NULL;
-  JUMP_LABEL(insn) = NULL;
+  LOG_LINKS (insn) = NULL;
+  REG_NOTES (insn) = NULL;
+  JUMP_LABEL (insn) = NULL;
+
+  return insn;
+}
+
+/* Like `make_insn' but make a CALL_INSN instead of an insn.  */
+
+static rtx
+make_call_insn_raw (pattern)
+     rtx pattern;
+{
+  register rtx insn;
+
+  insn = rtx_alloc (CALL_INSN);
+  INSN_UID (insn) = cur_insn_uid++;
+
+  PATTERN (insn) = pattern;
+  INSN_CODE (insn) = -1;
+  LOG_LINKS (insn) = NULL;
+  REG_NOTES (insn) = NULL;
+  CALL_INSN_FUNCTION_USAGE (insn) = NULL;
 
   return insn;
 }
@@ -1890,9 +2355,10 @@ add_insn (insn)
   last_insn = insn;
 }
 
-/* Add INSN into the doubly-linked list after insn AFTER.  This should be the
-   only function called to insert an insn once delay slots have been filled
-   since only it knows how to update a SEQUENCE.  */
+/* Add INSN into the doubly-linked list after insn AFTER.  This and
+   the next should be the only functions called to insert an insn once
+   delay slots have been filled since only they know how to update a
+   SEQUENCE.  */
 
 void
 add_insn_after (insn, after)
@@ -1900,6 +2366,9 @@ add_insn_after (insn, after)
 {
   rtx next = NEXT_INSN (after);
 
+  if (optimize && INSN_DELETED_P (after))
+    abort ();
+
   NEXT_INSN (insn) = next;
   PREV_INSN (insn) = after;
 
@@ -1917,7 +2386,13 @@ add_insn_after (insn, after)
       /* Scan all pending sequences too.  */
       for (; stack; stack = stack->next)
        if (after == stack->last)
-         stack->last = insn;
+         {
+           stack->last = insn;
+           break;
+         }
+
+      if (stack == 0)
+       abort ();
     }
 
   NEXT_INSN (after) = insn;
@@ -1928,6 +2403,54 @@ add_insn_after (insn, after)
     }
 }
 
+/* Add INSN into the doubly-linked list before insn BEFORE.  This and
+   the previous should be the only functions called to insert an insn once
+   delay slots have been filled since only they know how to update a
+   SEQUENCE.  */
+
+void
+add_insn_before (insn, before)
+     rtx insn, before;
+{
+  rtx prev = PREV_INSN (before);
+
+  if (optimize && INSN_DELETED_P (before))
+    abort ();
+
+  PREV_INSN (insn) = prev;
+  NEXT_INSN (insn) = before;
+
+  if (prev)
+    {
+      NEXT_INSN (prev) = insn;
+      if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
+       {
+         rtx sequence = PATTERN (prev);
+         NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn;
+       }
+    }
+  else if (first_insn == before)
+    first_insn = insn;
+  else
+    {
+      struct sequence_stack *stack = sequence_stack;
+      /* Scan all pending sequences too.  */
+      for (; stack; stack = stack->next)
+       if (before == stack->first)
+         {
+           stack->first = insn;
+           break;
+         }
+
+      if (stack == 0)
+       abort ();
+    }
+
+  PREV_INSN (before) = insn;
+  if (GET_CODE (before) == INSN && GET_CODE (PATTERN (before)) == SEQUENCE)
+    PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn;
+}
+
 /* Delete all insns made since FROM.
    FROM becomes the new last instruction.  */
 
@@ -1942,7 +2465,9 @@ delete_insns_since (from)
   last_insn = from;
 }
 
-/* Move a consecutive bunch of insns to a different place in the chain.
+/* This function is deprecated, please use sequences instead.
+
+   Move a consecutive bunch of insns to a different place in the chain.
    The insns to be moved are those between FROM and TO.
    They are moved to a new position after the insn AFTER.
    AFTER must not be FROM or TO or any insn in between.
@@ -2037,7 +2562,7 @@ emit_insn_before (pattern, before)
       for (i = 0; i < XVECLEN (pattern, 0); i++)
        {
          insn = XVECEXP (pattern, 0, i);
-         add_insn_after (insn, PREV_INSN (before));
+         add_insn_before (insn, before);
        }
       if (XVECLEN (pattern, 0) < SEQUENCE_RESULT_SIZE)
        sequence_result[XVECLEN (pattern, 0)] = pattern;
@@ -2045,7 +2570,7 @@ emit_insn_before (pattern, before)
   else
     {
       insn = make_insn_raw (pattern);
-      add_insn_after (insn, PREV_INSN (before));
+      add_insn_before (insn, before);
     }
 
   return insn;
@@ -2065,7 +2590,7 @@ emit_jump_insn_before (pattern, before)
   else
     {
       insn = make_jump_insn_raw (pattern);
-      add_insn_after (insn, PREV_INSN (before));
+      add_insn_before (insn, before);
     }
 
   return insn;
@@ -2078,8 +2603,17 @@ rtx
 emit_call_insn_before (pattern, before)
      register rtx pattern, before;
 {
-  rtx insn = emit_insn_before (pattern, before);
-  PUT_CODE (insn, CALL_INSN);
+  register rtx insn;
+
+  if (GET_CODE (pattern) == SEQUENCE)
+    insn = emit_insn_before (pattern, before);
+  else
+    {
+      insn = make_call_insn_raw (pattern);
+      add_insn_before (insn, before);
+      PUT_CODE (insn, CALL_INSN);
+    }
+
   return insn;
 }
 
@@ -2094,7 +2628,7 @@ emit_barrier_before (before)
 
   INSN_UID (insn) = cur_insn_uid++;
 
-  add_insn_after (insn, PREV_INSN (before));
+  add_insn_before (insn, before);
   return insn;
 }
 
@@ -2110,7 +2644,7 @@ emit_note_before (subtype, before)
   NOTE_SOURCE_FILE (note) = 0;
   NOTE_LINE_NUMBER (note) = subtype;
 
-  add_insn_after (note, PREV_INSN (before));
+  add_insn_before (note, before);
   return note;
 }
 \f
@@ -2326,7 +2860,7 @@ emit_insns_before (insn, before)
   while (insn)
     {
       rtx next = NEXT_INSN (insn);
-      add_insn_after (insn, PREV_INSN (before));
+      add_insn_before (insn, before);
       last = insn;
       insn = next;
     }
@@ -2395,7 +2929,7 @@ emit_call_insn (pattern)
     return emit_insn (pattern);
   else
     {
-      register rtx insn = make_insn_raw (pattern);
+      register rtx insn = make_call_insn_raw (pattern);
       add_insn (insn);
       PUT_CODE (insn, CALL_INSN);
       return insn;
@@ -2590,6 +3124,7 @@ start_sequence ()
   tem->next = sequence_stack;
   tem->first = first_insn;
   tem->last = last_insn;
+  tem->sequence_rtl_expr = sequence_rtl_expr;
 
   sequence_stack = tem;
 
@@ -2597,6 +3132,18 @@ start_sequence ()
   last_insn = 0;
 }
 
+/* Similarly, but indicate that this sequence will be placed in 
+   T, an RTL_EXPR.  */
+
+void
+start_sequence_for_rtl_expr (t)
+     tree t;
+{
+  start_sequence ();
+
+  sequence_rtl_expr = t;
+}
+
 /* Set up the insn chain starting with FIRST
    as the current sequence, saving the previously current one.  */
 
@@ -2614,6 +3161,42 @@ push_to_sequence (first)
   last_insn = last;
 }
 
+/* Set up the outer-level insn chain
+   as the current sequence, saving the previously current one.  */
+
+void
+push_topmost_sequence ()
+{
+  struct sequence_stack *stack, *top = NULL;
+
+  start_sequence ();
+
+  for (stack = sequence_stack; stack; stack = stack->next)
+    top = stack;
+
+  first_insn = top->first;
+  last_insn = top->last;
+  sequence_rtl_expr = top->sequence_rtl_expr;
+}
+
+/* After emitting to the outer-level insn chain, update the outer-level
+   insn chain, and restore the previous saved state.  */
+
+void
+pop_topmost_sequence ()
+{
+  struct sequence_stack *stack, *top = NULL;
+
+  for (stack = sequence_stack; stack; stack = stack->next)
+    top = stack;
+
+  top->first = first_insn;
+  top->last = last_insn;
+  /* ??? Why don't we save sequence_rtl_expr here?  */
+
+  end_sequence ();
+}
+
 /* After emitting to a sequence, restore previous saved state.
 
    To get the contents of the sequence just made,
@@ -2626,6 +3209,7 @@ end_sequence ()
 
   first_insn = tem->first;
   last_insn = tem->last;
+  sequence_rtl_expr = tem->sequence_rtl_expr;
   sequence_stack = tem->next;
 
   tem->next = sequence_element_free_list;
@@ -2651,7 +3235,6 @@ gen_sequence ()
 {
   rtx result;
   rtx tem;
-  rtvec newvec;
   int i;
   int len;
 
@@ -2664,10 +3247,17 @@ gen_sequence ()
      (Now that we cache SEQUENCE expressions, it isn't worth special-casing
      the case of an empty list.)  */
   if (len == 1
+      && ! RTX_FRAME_RELATED_P (first_insn)
       && (GET_CODE (first_insn) == INSN
          || GET_CODE (first_insn) == JUMP_INSN
-         || GET_CODE (first_insn) == CALL_INSN))
-    return PATTERN (first_insn);
+         /* Don't discard the call usage field.  */
+         || (GET_CODE (first_insn) == CALL_INSN
+             && CALL_INSN_FUNCTION_USAGE (first_insn) == NULL_RTX)))
+    {
+      NEXT_INSN (first_insn) = free_insn;
+      free_insn = first_insn;
+      return PATTERN (first_insn);
+    }
 
   /* Put them in a vector.  See if we already have a SEQUENCE of the
      appropriate length around.  */
@@ -2675,11 +3265,11 @@ gen_sequence ()
     sequence_result[len] = 0;
   else
     {
-      /* Ensure that this rtl goes in saveable_obstack, since we may be
-        caching it.  */
+      /* 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));
+      result = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (len));
       pop_obstacks ();
     }
 
@@ -2689,144 +3279,6 @@ gen_sequence ()
   return result;
 }
 \f
-/* Set up regno_reg_rtx, reg_rtx_no and regno_pointer_flag
-   according to the chain of insns starting with FIRST.
-
-   Also set cur_insn_uid to exceed the largest uid in that chain.
-
-   This is used when an inline function's rtl is saved
-   and passed to rest_of_compilation later.  */
-
-static void restore_reg_data_1 ();
-
-void
-restore_reg_data (first)
-     rtx first;
-{
-  register rtx insn;
-  int i;
-  register int max_uid = 0;
-
-  for (insn = first; insn; insn = NEXT_INSN (insn))
-    {
-      if (INSN_UID (insn) >= max_uid)
-       max_uid = INSN_UID (insn);
-
-      switch (GET_CODE (insn))
-       {
-       case NOTE:
-       case CODE_LABEL:
-       case BARRIER:
-         break;
-
-       case JUMP_INSN:
-       case CALL_INSN:
-       case INSN:
-         restore_reg_data_1 (PATTERN (insn));
-         break;
-       }
-    }
-
-  /* Don't duplicate the uids already in use.  */
-  cur_insn_uid = max_uid + 1;
-
-  /* If any regs are missing, make them up.  
-
-     ??? word_mode is not necessarily the right mode.  Most likely these REGs
-     are never used.  At some point this should be checked.  */
-
-  for (i = FIRST_PSEUDO_REGISTER; i < reg_rtx_no; i++)
-    if (regno_reg_rtx[i] == 0)
-      regno_reg_rtx[i] = gen_rtx (REG, word_mode, i);
-}
-
-static void
-restore_reg_data_1 (orig)
-     rtx orig;
-{
-  register rtx x = orig;
-  register int i;
-  register enum rtx_code code;
-  register char *format_ptr;
-
-  code = GET_CODE (x);
-
-  switch (code)
-    {
-    case QUEUED:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case SYMBOL_REF:
-    case CODE_LABEL:
-    case PC:
-    case CC0:
-    case LABEL_REF:
-      return;
-
-    case REG:
-      if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
-       {
-         /* Make sure regno_pointer_flag and regno_reg_rtx are large
-            enough to have an element for this pseudo reg number.  */
-         if (REGNO (x) >= reg_rtx_no)
-           {
-             reg_rtx_no = REGNO (x);
-
-             if (reg_rtx_no >= regno_pointer_flag_length)
-               {
-                 int newlen = MAX (regno_pointer_flag_length * 2,
-                                   reg_rtx_no + 30);
-                 rtx *new1;
-                 char *new = (char *) oballoc (newlen);
-                 bzero (new, newlen);
-                 bcopy (regno_pointer_flag, new, regno_pointer_flag_length);
-
-                 new1 = (rtx *) oballoc (newlen * sizeof (rtx));
-                 bzero (new1, newlen * sizeof (rtx));
-                 bcopy (regno_reg_rtx, new1, regno_pointer_flag_length * sizeof (rtx));
-
-                 regno_pointer_flag = new;
-                 regno_reg_rtx = new1;
-                 regno_pointer_flag_length = newlen;
-               }
-             reg_rtx_no ++;
-           }
-         regno_reg_rtx[REGNO (x)] = x;
-       }
-      return;
-
-    case MEM:
-      if (GET_CODE (XEXP (x, 0)) == REG)
-       mark_reg_pointer (XEXP (x, 0));
-      restore_reg_data_1 (XEXP (x, 0));
-      return;
-    }
-
-  /* Now scan the subexpressions recursively.  */
-
-  format_ptr = GET_RTX_FORMAT (code);
-
-  for (i = 0; i < GET_RTX_LENGTH (code); i++)
-    {
-      switch (*format_ptr++)
-       {
-       case 'e':
-         restore_reg_data_1 (XEXP (x, i));
-         break;
-
-       case 'E':
-         if (XVEC (x, i) != NULL)
-           {
-             register int j;
-
-             for (j = 0; j < XVECLEN (x, i); j++)
-               restore_reg_data_1 (XVECEXP (x, i, j));
-           }
-         break;
-       }
-    }
-}
-\f
 /* Initialize data structures and variables in this file
    before generating rtl for each function.  */
 
@@ -2837,29 +3289,36 @@ init_emit ()
 
   first_insn = NULL;
   last_insn = NULL;
+  sequence_rtl_expr = NULL;
   cur_insn_uid = 1;
   reg_rtx_no = LAST_VIRTUAL_REGISTER + 1;
   last_linenum = 0;
   last_filename = 0;
   first_label_num = label_num;
   last_label_num = 0;
+  sequence_stack = NULL;
 
   /* Clear the start_sequence/gen_sequence cache.  */
   sequence_element_free_list = 0;
   for (i = 0; i < SEQUENCE_RESULT_SIZE; i++)
     sequence_result[i] = 0;
+  free_insn = 0;
 
   /* Init the tables that describe all the pseudo regs.  */
 
   regno_pointer_flag_length = LAST_VIRTUAL_REGISTER + 101;
 
   regno_pointer_flag 
-    = (char *) oballoc (regno_pointer_flag_length);
+    = (char *) savealloc (regno_pointer_flag_length);
   bzero (regno_pointer_flag, regno_pointer_flag_length);
 
+  regno_pointer_align
+    = (char *) savealloc (regno_pointer_flag_length);
+  bzero (regno_pointer_align, regno_pointer_flag_length);
+
   regno_reg_rtx 
-    = (rtx *) oballoc (regno_pointer_flag_length * sizeof (rtx));
-  bzero (regno_reg_rtx, regno_pointer_flag_length * sizeof (rtx));
+    = (rtx *) savealloc (regno_pointer_flag_length * sizeof (rtx));
+  bzero ((char *) regno_reg_rtx, regno_pointer_flag_length * sizeof (rtx));
 
   /* Put copies of all the virtual register rtx into regno_reg_rtx.  */
   regno_reg_rtx[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;
@@ -2871,12 +3330,34 @@ init_emit ()
      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;
 
   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;
+
+#ifdef STACK_BOUNDARY
+  REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
+  REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
+  REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM)
+    = STACK_BOUNDARY / BITS_PER_UNIT;
+  REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
+
+  REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM)
+    = STACK_BOUNDARY / BITS_PER_UNIT;
+  REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM)
+    = STACK_BOUNDARY / BITS_PER_UNIT;
+  REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM)
+    = STACK_BOUNDARY / BITS_PER_UNIT;
+  REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM)
+    = STACK_BOUNDARY / BITS_PER_UNIT;
+#endif
+
+#ifdef INIT_EXPANDERS
+  INIT_EXPANDERS;
+#endif
 }
 
 /* Create some permanent unique rtl objects shared between all functions.
@@ -2893,33 +3374,44 @@ init_emit_once (line_numbers)
 
   sequence_stack = NULL;
 
-  /* Create the unique rtx's for certain rtx codes and operand values.  */
+  /* Compute the word and byte modes.  */
 
-  pc_rtx = gen_rtx (PC, VOIDmode);
-  cc0_rtx = gen_rtx (CC0, VOIDmode);
+  byte_mode = VOIDmode;
+  word_mode = VOIDmode;
 
-  /* 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++)
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
     {
-      const_int_rtx[i + MAX_SAVED_CONST_INT] = rtx_alloc (CONST_INT);
-      PUT_MODE (const_int_rtx[i + MAX_SAVED_CONST_INT], VOIDmode);
-      INTVAL (const_int_rtx[i + MAX_SAVED_CONST_INT]) = i;
+      if (GET_MODE_BITSIZE (mode) == BITS_PER_UNIT
+         && byte_mode == VOIDmode)
+       byte_mode = mode;
+
+      if (GET_MODE_BITSIZE (mode) == BITS_PER_WORD
+         && word_mode == VOIDmode)
+       word_mode = mode;
     }
 
-  /* These four calls obtain some of the rtx expressions made above.  */
-  const0_rtx = GEN_INT (0);
-  const1_rtx = GEN_INT (1);
-  const2_rtx = GEN_INT (2);
-  constm1_rtx = GEN_INT (-1);
+  ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0);
 
-  /* This will usually be one of the above constants, but may be a new rtx.  */
-  const_true_rtx = GEN_INT (STORE_FLAG_VALUE);
+  /* Create the unique rtx's for certain rtx codes and operand values.  */
 
-  dconst0 = REAL_VALUE_ATOF ("0");
-  dconst1 = REAL_VALUE_ATOF ("1");
-  dconst2 = REAL_VALUE_ATOF ("2");
-  dconstm1 = REAL_VALUE_ATOF ("-1");
+  for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
+    {
+      PUT_CODE (&const_int_rtx[i + MAX_SAVED_CONST_INT], CONST_INT);
+      PUT_MODE (&const_int_rtx[i + MAX_SAVED_CONST_INT], VOIDmode);
+      INTVAL (&const_int_rtx[i + MAX_SAVED_CONST_INT]) = i;
+    }
+
+  if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT
+      && STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT)
+    const_true_rtx = &const_int_rtx[STORE_FLAG_VALUE + MAX_SAVED_CONST_INT];
+  else
+    const_true_rtx = gen_rtx_CONST_INT (VOIDmode, STORE_FLAG_VALUE);
+
+  dconst0 = REAL_VALUE_ATOF ("0", DFmode);
+  dconst1 = REAL_VALUE_ATOF ("1", DFmode);
+  dconst2 = REAL_VALUE_ATOF ("2", DFmode);
+  dconstm1 = REAL_VALUE_ATOF ("-1", DFmode);
 
   for (i = 0; i <= 2; i++)
     {
@@ -2929,10 +3421,10 @@ init_emit_once (line_numbers)
          rtx tem = rtx_alloc (CONST_DOUBLE);
          union real_extract u;
 
-         bzero (&u, sizeof u);  /* Zero any holes in a structure.  */
+         bzero ((char *) &u, sizeof u);  /* Zero any holes in a structure.  */
          u.d = i == 0 ? dconst0 : i == 1 ? dconst1 : dconst2;
 
-         bcopy (&u, &CONST_DOUBLE_LOW (tem), sizeof u);
+         bcopy ((char *) &u, (char *) &CONST_DOUBLE_LOW (tem), sizeof u);
          CONST_DOUBLE_MEM (tem) = cc0_rtx;
          PUT_MODE (tem, mode);
 
@@ -2955,32 +3447,42 @@ init_emit_once (line_numbers)
        mode = GET_MODE_WIDER_MODE (mode))
     const_tiny_rtx[0][(int) mode] = const0_rtx;
 
-  stack_pointer_rtx = gen_rtx (REG, Pmode, STACK_POINTER_REGNUM);
-  frame_pointer_rtx = gen_rtx (REG, Pmode, FRAME_POINTER_REGNUM);
 
-  if (FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM)
-    arg_pointer_rtx = frame_pointer_rtx;
-  else if (STACK_POINTER_REGNUM == ARG_POINTER_REGNUM)
-    arg_pointer_rtx = stack_pointer_rtx;
-  else
-    arg_pointer_rtx = gen_rtx (REG, Pmode, ARG_POINTER_REGNUM);
+  /* Assign register numbers to the globally defined register rtx.
+     This must be done at runtime because the register number field
+     is in a union and some compilers can't initialize unions.  */
 
-  /* Create the virtual registers.  Do so here since the following objects
-     might reference them.  */
+  REGNO (stack_pointer_rtx) = STACK_POINTER_REGNUM;
+  PUT_MODE (stack_pointer_rtx, Pmode);
+  REGNO (frame_pointer_rtx) = FRAME_POINTER_REGNUM;
+  PUT_MODE (frame_pointer_rtx, Pmode);
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+  REGNO (hard_frame_pointer_rtx) = HARD_FRAME_POINTER_REGNUM;
+  PUT_MODE (hard_frame_pointer_rtx, Pmode);
+#endif
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+  REGNO (arg_pointer_rtx) = ARG_POINTER_REGNUM;
+  PUT_MODE (arg_pointer_rtx, Pmode);
+#endif
 
-  virtual_incoming_args_rtx = gen_rtx (REG, Pmode,
-                                      VIRTUAL_INCOMING_ARGS_REGNUM);
-  virtual_stack_vars_rtx = gen_rtx (REG, Pmode,
-                                   VIRTUAL_STACK_VARS_REGNUM);
-  virtual_stack_dynamic_rtx = gen_rtx (REG, Pmode,
-                                      VIRTUAL_STACK_DYNAMIC_REGNUM);
-  virtual_outgoing_args_rtx = gen_rtx (REG, Pmode,
-                                      VIRTUAL_OUTGOING_ARGS_REGNUM);
+  REGNO (virtual_incoming_args_rtx) = VIRTUAL_INCOMING_ARGS_REGNUM;
+  PUT_MODE (virtual_incoming_args_rtx, Pmode);
+  REGNO (virtual_stack_vars_rtx) = VIRTUAL_STACK_VARS_REGNUM;
+  PUT_MODE (virtual_stack_vars_rtx, Pmode);
+  REGNO (virtual_stack_dynamic_rtx) = VIRTUAL_STACK_DYNAMIC_REGNUM;
+  PUT_MODE (virtual_stack_dynamic_rtx, Pmode);
+  REGNO (virtual_outgoing_args_rtx) = VIRTUAL_OUTGOING_ARGS_REGNUM;
+  PUT_MODE (virtual_outgoing_args_rtx, Pmode);
+
+#ifdef RETURN_ADDRESS_POINTER_REGNUM
+  return_address_pointer_rtx
+    = gen_rtx_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
+#endif
 
 #ifdef STRUCT_VALUE
   struct_value_rtx = STRUCT_VALUE;
 #else
-  struct_value_rtx = gen_rtx (REG, Pmode, STRUCT_VALUE_REGNUM);
+  struct_value_rtx = gen_rtx_REG (Pmode, STRUCT_VALUE_REGNUM);
 #endif
 
 #ifdef STRUCT_VALUE_INCOMING
@@ -2988,18 +3490,18 @@ init_emit_once (line_numbers)
 #else
 #ifdef STRUCT_VALUE_INCOMING_REGNUM
   struct_value_incoming_rtx
-    = gen_rtx (REG, Pmode, STRUCT_VALUE_INCOMING_REGNUM);
+    = gen_rtx_REG (Pmode, STRUCT_VALUE_INCOMING_REGNUM);
 #else
   struct_value_incoming_rtx = struct_value_rtx;
 #endif
 #endif
 
 #ifdef STATIC_CHAIN_REGNUM
-  static_chain_rtx = gen_rtx (REG, Pmode, STATIC_CHAIN_REGNUM);
+  static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
 
 #ifdef STATIC_CHAIN_INCOMING_REGNUM
   if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM)
-    static_chain_incoming_rtx = gen_rtx (REG, Pmode, STATIC_CHAIN_INCOMING_REGNUM);
+    static_chain_incoming_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
   else
 #endif
     static_chain_incoming_rtx = static_chain_rtx;
@@ -3016,6 +3518,28 @@ init_emit_once (line_numbers)
 #endif
 
 #ifdef PIC_OFFSET_TABLE_REGNUM
-  pic_offset_table_rtx = gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM);
+  pic_offset_table_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
 #endif
 }
+\f
+/* Query and clear/ restore no_line_numbers.  This is used by the
+   switch / case handling in stmt.c to give proper line numbers in
+   warnings about unreachable code.  */
+
+int
+force_line_numbers ()
+{
+  int old = no_line_numbers;
+
+  no_line_numbers = 0;
+  if (old)
+    force_next_line_note ();
+  return old;
+}
+
+void
+restore_line_number_status (old_value)
+     int old_value;
+{
+  no_line_numbers = old_value;
+}