OSDN Git Service

* lex.c (lang_init_options): New function.
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 3afcccb..854b989 100644 (file)
@@ -1,5 +1,5 @@
 /* Emit RTL for the GNU C-Compiler expander.
-   Copyright (C) 1987, 1988, 1992, 1993, 1994 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.
@@ -39,41 +40,26 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #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 "obstack.h"
-
-#include "bytecode.h"
-#include "machmode.h"
-#include "bc-opcode.h"
-#include "bc-typecd.h"
-#include "bc-optab.h"
-#include "bc-emit.h"
-
-#include <stdio.h>
-
-
-/* Opcode names */
-#ifdef BCDEBUG_PRINT_CODE
-char *opcode_name[] =
-{
-#include "bc-opname.h"
-
-"***END***"
-};
-#endif
-
+#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 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.  */
@@ -109,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
@@ -124,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;
@@ -147,29 +140,22 @@ REAL_VALUE_TYPE dconstm1;
 
    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 hard_frame_pointer_rtx;    /* (REG:Pmode HARD_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.
@@ -206,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.  */
 
@@ -238,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,
@@ -245,14 +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
-extern struct obstack *rtl_obstack;
+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);
+}
 
-extern int stack_depth;
-extern int max_stack_depth;
-\f
 /* rtx gen_rtx (code, mode, [element1, ..., elementn])
 **
 **         This routine generates an RTX of the size specified by
@@ -300,60 +348,9 @@ gen_rtx VPROTO((enum rtx_code code, enum machine_mode 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 != HARD_FRAME_POINTER_REGNUM
-      if (hard_frame_pointer_rtx && regno == HARD_FRAME_POINTER_REGNUM
-         && mode == Pmode && ! reload_in_progress)
-       return hard_frame_pointer_rtx;
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_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.  */
@@ -388,6 +385,14 @@ gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...))
              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 ();
            }
@@ -450,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.  */
@@ -485,7 +509,7 @@ gen_reg_rtx (mode)
 
       realpart = gen_reg_rtx (partmode);
       imagpart = gen_reg_rtx (partmode);
-      return gen_rtx (CONCAT, mode, realpart, imagpart);
+      return gen_rtx_CONCAT (mode, realpart, imagpart);
     }
 
   /* Make sure regno_pointer_flag and regno_reg_rtx are large
@@ -495,12 +519,17 @@ gen_reg_rtx (mode)
     {
       rtx *new1;
       char *new =
-       (char *) oballoc (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));
+      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],
@@ -510,18 +539,40 @@ gen_reg_rtx (mode)
       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.  */
@@ -600,16 +651,27 @@ 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.  
         But we do do this if the current REG is not valid for its
@@ -624,6 +686,14 @@ gen_lowpart_common (mode, x)
               /* 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.  */
               && x != frame_pointer_rtx
@@ -631,9 +701,9 @@ gen_lowpart_common (mode, x)
               && x != arg_pointer_rtx
 #endif
               && x != stack_pointer_rtx)
-       return gen_rtx (REG, mode, REGNO (x) + word);
+       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.  */
@@ -650,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;
@@ -659,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));
@@ -724,7 +793,7 @@ gen_lowpart_common (mode, x)
        low = CONST_DOUBLE_LOW (x), high = CONST_DOUBLE_HIGH (x);
 
       /* REAL_VALUE_TARGET_DOUBLE takes the addressing order of the
-        target machine. */
+        target machine.  */
       if (WORDS_BIG_ENDIAN)
        i[0] = high, i[1] = low;
       else
@@ -752,6 +821,22 @@ 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);
+    }
+#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
      compatible.  */
@@ -764,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
@@ -780,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)
@@ -855,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.  */
@@ -871,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 ();
 }
@@ -893,10 +990,13 @@ gen_highpart (mode, x)
       && 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;
@@ -923,16 +1023,27 @@ gen_highpart (mode, x)
     }
   else if (GET_CODE (x) == REG)
     {
-      int word = 0;
+      int word;
 
-      if (! WORDS_BIG_ENDIAN
-         && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_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)
+       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. */
+         /* 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.  */
@@ -941,9 +1052,9 @@ gen_highpart (mode, x)
          && x != arg_pointer_rtx
 #endif
          && x != stack_pointer_rtx)
-       return gen_rtx (REG, mode, REGNO (x) + word);
+       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 ();
@@ -959,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)
@@ -996,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);
@@ -1032,12 +1146,12 @@ operand_subword (op, i, validate_address, mode)
               || op == arg_pointer_rtx
 #endif
               || op == stack_pointer_rtx)
-       return gen_rtx (SUBREG, word_mode, op, i);
+       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;
@@ -1064,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);
@@ -1105,9 +1219,32 @@ operand_subword (op, i, validate_address, mode)
        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)
@@ -1143,12 +1280,20 @@ operand_subword (op, i, validate_address, mode)
 
       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)
@@ -1161,6 +1306,22 @@ 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.
@@ -1176,7 +1337,7 @@ operand_subword (op, i, validate_address, mode)
 
   if (GET_MODE_CLASS (mode) != MODE_INT
       || (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE)
-      || BITS_PER_WORD > HOST_BITS_PER_INT)
+      || BITS_PER_WORD > HOST_BITS_PER_WIDE_INT)
     return 0;
 
   if (WORDS_BIG_ENDIAN)
@@ -1189,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);
 }
@@ -1218,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)
@@ -1251,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
@@ -1290,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);
@@ -1304,9 +1493,8 @@ gen_label_rtx ()
 {
   register rtx label;
 
-  label = (output_bytecode
-          ? gen_rtx (CODE_LABEL, VOIDmode, NULL, bc_get_bytecode_label ())
-          : gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0, label_num++, NULL_PTR));
+  label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX,
+                             NULL_RTX, label_num++, NULL_PTR);
 
   LABEL_NUSES (label) = 0;
   return label;
@@ -1320,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.
@@ -1382,6 +1589,7 @@ save_emit_status (p)
   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;
 }
@@ -1406,13 +1614,17 @@ restore_emit_status (p)
   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.
@@ -1474,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:
@@ -1514,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,
@@ -1554,7 +1770,7 @@ copy_rtx_if_shared (orig)
              int len = XVECLEN (x, i);
 
              if (copied && len > 0)
-               XVEC (x, i) = gen_rtvec_v (len, &XVECEXP (x, i, 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));
            }
@@ -1580,7 +1796,7 @@ reset_used_flags (x)
 
   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)
@@ -1603,6 +1819,9 @@ reset_used_flags (x)
     case BARRIER:
       /* The chain of insns is not being copied.  */
       return;
+      
+    default:
+      break;
     }
 
   x->used = 0;
@@ -1785,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)
@@ -1912,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
@@ -1954,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);
@@ -2060,9 +2277,17 @@ 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;
@@ -2130,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)
@@ -2140,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;
 
@@ -2157,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;
@@ -2168,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.  */
 
@@ -2279,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;
@@ -2287,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;
@@ -2307,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;
@@ -2327,7 +2610,7 @@ emit_call_insn_before (pattern, before)
   else
     {
       insn = make_call_insn_raw (pattern);
-      add_insn_after (insn, PREV_INSN (before));
+      add_insn_before (insn, before);
       PUT_CODE (insn, CALL_INSN);
     }
 
@@ -2345,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;
 }
 
@@ -2361,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
@@ -2577,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;
     }
@@ -2692,13 +2975,6 @@ emit_line_note (file, line)
      char *file;
      int line;
 {
-  if (output_bytecode)
-    {
-      /* FIXME: for now we do nothing, but eventually we will have to deal with
-        debugging information.  */
-      return 0;
-    }
-
   emit_filename = file;
   emit_lineno = line;
 
@@ -2891,7 +3167,7 @@ push_to_sequence (first)
 void
 push_topmost_sequence ()
 {
-  struct sequence_stack *stack, *top;
+  struct sequence_stack *stack, *top = NULL;
 
   start_sequence ();
 
@@ -2909,7 +3185,7 @@ push_topmost_sequence ()
 void
 pop_topmost_sequence ()
 {
-  struct sequence_stack *stack, *top;
+  struct sequence_stack *stack, *top = NULL;
 
   for (stack = sequence_stack; stack; stack = stack->next)
     top = stack;
@@ -2971,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.  */
@@ -2982,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 ();
     }
 
@@ -2996,145 +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 ((char *) new1, newlen * sizeof (rtx));
-                 bcopy ((char *) regno_reg_rtx, (char *) 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.  */
 
@@ -3158,17 +3302,22 @@ init_emit ()
   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));
+    = (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.  */
@@ -3181,6 +3330,7 @@ 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;
@@ -3188,6 +3338,23 @@ init_emit ()
   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
@@ -3224,28 +3391,22 @@ init_emit_once (line_numbers)
        word_mode = mode;
     }
 
-  /* Create the unique rtx's for certain rtx codes and operand values.  */
+  ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0);
 
-  pc_rtx = gen_rtx (PC, VOIDmode);
-  cc0_rtx = gen_rtx (CC0, VOIDmode);
+  /* Create the unique rtx's for certain rtx codes and operand values.  */
 
-  /* Don't use gen_rtx here since gen_rtx in this case
-     tries to use these variables.  */
   for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
     {
-      const_int_rtx[i + MAX_SAVED_CONST_INT] = 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;
+      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;
     }
 
-  /* 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);
-
-  /* This will usually be one of the above constants, but may be a new rtx.  */
-  const_true_rtx = GEN_INT (STORE_FLAG_VALUE);
+  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);
@@ -3286,39 +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 (HARD_FRAME_POINTER_REGNUM == FRAME_POINTER_REGNUM)
-    hard_frame_pointer_rtx = frame_pointer_rtx;
-  else
-    hard_frame_pointer_rtx = gen_rtx (REG, Pmode, HARD_FRAME_POINTER_REGNUM);
-  
-  if (FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM)
-    arg_pointer_rtx = frame_pointer_rtx;
-  else if (HARD_FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM)
-    arg_pointer_rtx = hard_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
@@ -3326,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;
@@ -3354,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;
+}