OSDN Git Service

2002-01-16 H.J. Lu <hjl@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / rtl.c
index 6b04bcd..39b7ddb 100644 (file)
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
-/* Allocate and read RTL for GNU C Compiler.
-   Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998 Free Software Foundation, Inc.
+/* RTL utility routines.
+   Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
 #include "rtl.h"
 #include "real.h"
-#include "bitmap.h"
-
-#include "obstack.h"
-#define        obstack_chunk_alloc     xmalloc
-#define        obstack_chunk_free      free
+#include "ggc.h"
+#include "errors.h"
 
-/* Obstack used for allocating RTL objects.
-   Between functions, this is the permanent_obstack.
-   While parsing and expanding a function, this is maybepermanent_obstack
-   so we can save it if it is an inline function.
-   During optimization and output, this is function_obstack.  */
-
-extern struct obstack *rtl_obstack;
 \f
+/* Calculate the format for CONST_DOUBLE.  This depends on the relative
+   widths of HOST_WIDE_INT and REAL_VALUE_TYPE.
+
+   We need to go out to 0wwwww, since REAL_ARITHMETIC assumes 16-bits
+   per element in REAL_VALUE_TYPE.
+
+   This is duplicated in gengenrtl.c.
+
+   A number of places assume that there are always at least two 'w'
+   slots in a CONST_DOUBLE, so we provide them even if one would suffice.  */
+
+#ifdef REAL_ARITHMETIC
+# if MAX_LONG_DOUBLE_TYPE_SIZE == 96
+#  define REAL_WIDTH   \
+     (11*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
+# else
+#  if MAX_LONG_DOUBLE_TYPE_SIZE == 128
+#   define REAL_WIDTH  \
+      (19*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
+#  else
+#   if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
+#    define REAL_WIDTH \
+       (7*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
+#   endif
+#  endif
+# endif
+#endif /* REAL_ARITHMETIC */
+
+#ifndef REAL_WIDTH
+# if HOST_BITS_PER_WIDE_INT*2 >= MAX_LONG_DOUBLE_TYPE_SIZE
+#  define REAL_WIDTH   2
+# else
+#  if HOST_BITS_PER_WIDE_INT*3 >= MAX_LONG_DOUBLE_TYPE_SIZE
+#   define REAL_WIDTH  3
+#  else
+#   if HOST_BITS_PER_WIDE_INT*4 >= MAX_LONG_DOUBLE_TYPE_SIZE
+#    define REAL_WIDTH 4
+#   endif
+#  endif
+# endif
+#endif /* REAL_WIDTH */
+
+#if REAL_WIDTH == 1
+# define CONST_DOUBLE_FORMAT   "0ww"
+#else
+# if REAL_WIDTH == 2
+#  define CONST_DOUBLE_FORMAT  "0ww"
+# else
+#  if REAL_WIDTH == 3
+#   define CONST_DOUBLE_FORMAT "0www"
+#  else
+#   if REAL_WIDTH == 4
+#    define CONST_DOUBLE_FORMAT        "0wwww"
+#   else
+#    if REAL_WIDTH == 5
+#     define CONST_DOUBLE_FORMAT       "0wwwww"
+#    else
+#     define CONST_DOUBLE_FORMAT       /* nothing - will cause syntax error */
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
 /* Indexed by rtx code, gives number of operands for an rtx with that code.
-   Does NOT include rtx header data (code and links).
-   This array is initialized in init_rtl.  */
+   Does NOT include rtx header data (code and links).  */
 
-int rtx_length[NUM_RTX_CODE + 1];
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   sizeof FORMAT - 1 ,
+
+const unsigned char rtx_length[NUM_RTX_CODE] = {
+#include "rtl.def"
+};
+
+#undef DEF_RTL_EXPR
 
 /* Indexed by rtx code, gives the name of that kind of rtx, as a C string.  */
 
 #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   NAME ,
 
-char *rtx_name[] = {
+const char * const rtx_name[NUM_RTX_CODE] = {
 #include "rtl.def"             /* rtl expressions are documented here */
 };
 
@@ -56,27 +115,30 @@ char *rtx_name[] = {
 /* Indexed by machine mode, gives the name of that machine mode.
    This name does not include the letters "mode".  */
 
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  NAME,
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER)  NAME,
 
-char *mode_name[(int) MAX_MACHINE_MODE + 1] = {
+const char * const mode_name[NUM_MACHINE_MODES] = {
 #include "machmode.def"
+};
 
-#ifdef EXTRA_CC_MODES
-  EXTRA_CC_NAMES,
-#endif
-  /* Add an extra field to avoid a core dump if someone tries to convert
-     MAX_MACHINE_MODE to a string.   */
-  ""
+#undef DEF_MACHMODE
+
+/* Indexed by machine mode, gives the class mode for GET_MODE_CLASS.  */
+
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER)  CLASS,
+
+const enum mode_class mode_class[NUM_MACHINE_MODES] = {
+#include "machmode.def"
 };
 
 #undef DEF_MACHMODE
 
-/* Indexed by machine mode, gives the length of the mode, in bytes.
-   GET_MODE_CLASS uses this.  */
+/* Indexed by machine mode, gives the length of the mode, in bits.
+   GET_MODE_BITSIZE uses this.  */
 
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  CLASS,
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER)  BITSIZE,
 
-enum mode_class mode_class[(int) MAX_MACHINE_MODE] = {
+const unsigned short mode_bitsize[NUM_MACHINE_MODES] = {
 #include "machmode.def"
 };
 
@@ -85,9 +147,9 @@ enum mode_class mode_class[(int) MAX_MACHINE_MODE] = {
 /* Indexed by machine mode, gives the length of the mode, in bytes.
    GET_MODE_SIZE uses this.  */
 
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  SIZE,
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER)  SIZE,
 
-int mode_size[(int) MAX_MACHINE_MODE] = {
+const unsigned char mode_size[NUM_MACHINE_MODES] = {
 #include "machmode.def"
 };
 
@@ -96,9 +158,9 @@ int mode_size[(int) MAX_MACHINE_MODE] = {
 /* Indexed by machine mode, gives the length of the mode's subunit.
    GET_MODE_UNIT_SIZE uses this.  */
 
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  UNIT,
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER)  UNIT,
 
-int mode_unit_size[(int) MAX_MACHINE_MODE] = {
+const unsigned char mode_unit_size[NUM_MACHINE_MODES] = {
 #include "machmode.def"                /* machine modes are documented here */
 };
 
@@ -108,33 +170,51 @@ int mode_unit_size[(int) MAX_MACHINE_MODE] = {
    (QI -> HI -> SI -> DI, etc.)  Widening multiply instructions
    use this.  */
 
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  \
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER)  \
   (unsigned char) WIDER,
 
-unsigned char mode_wider_mode[(int) MAX_MACHINE_MODE] = {
+const unsigned char mode_wider_mode[NUM_MACHINE_MODES] = {
 #include "machmode.def"                /* machine modes are documented here */
 };
 
 #undef DEF_MACHMODE
 
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  \
-  ((SIZE) * BITS_PER_UNIT >= HOST_BITS_PER_WIDE_INT) ? ~(unsigned HOST_WIDE_INT)0 : ((unsigned HOST_WIDE_INT) 1 << (SIZE) * BITS_PER_UNIT) - 1,
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER)  \
+  ((BITSIZE) >= HOST_BITS_PER_WIDE_INT) ? ~(unsigned HOST_WIDE_INT) 0 : ((unsigned HOST_WIDE_INT) 1 << (BITSIZE)) - 1,
 
 /* Indexed by machine mode, gives mask of significant bits in mode.  */
 
-unsigned HOST_WIDE_INT mode_mask_array[(int) MAX_MACHINE_MODE] = {
+const unsigned HOST_WIDE_INT mode_mask_array[NUM_MACHINE_MODES] = {
 #include "machmode.def"
 };
 
-/* Indexed by mode class, gives the narrowest mode for each class.  */
+/* Indexed by mode class, gives the narrowest mode for each class.
+   The Q modes are always of width 1 (2 for complex) - it is impossible
+   for any mode to be narrower.
+
+   Note that we use QImode instead of BImode for MODE_INT, since
+   otherwise the middle end will try to use it for bitfields in
+   structures and the like, which we do not want.  Only the target
+   md file should generate BImode widgets.  */
+
+const enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS] = {
+    /* MODE_RANDOM */          VOIDmode,
+    /* MODE_INT */             QImode,
+    /* MODE_FLOAT */           QFmode,
+    /* MODE_PARTIAL_INT */     PQImode,
+    /* MODE_CC */              CCmode,
+    /* MODE_COMPLEX_INT */     CQImode,
+    /* MODE_COMPLEX_FLOAT */   QCmode,
+    /* MODE_VECTOR_INT */      V2QImode,
+    /* MODE_VECTOR_FLOAT */    V2SFmode
+};
 
-enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS];
 
 /* Indexed by rtx code, gives a sequence of operand-types for
    rtx's of that code.  The sequence is a C string in which
    each character describes one operand.  */
 
-char *rtx_format[] = {
+const char * const rtx_format[NUM_RTX_CODE] = {
   /* "*" undefined.
          can cause a warning message
      "0" field is unused (or used in a phase-dependent manner)
@@ -148,6 +228,8 @@ char *rtx_format[] = {
          prints the string
      "S" like "s", but optional:
         the containing rtx may end before this operand
+     "T" like "s", but treated specially by the RTL reader;
+         only found in machine description patterns.
      "e" a pointer to an rtl expression
          prints the expression
      "E" a pointer to a vector that points to a number of rtl expressions
@@ -157,7 +239,7 @@ char *rtx_format[] = {
      "u" a pointer to another insn
          prints the uid of the insn.
      "b" is a pointer to a bitmap header.
-     "t" is a tree pointer. */
+     "t" is a tree pointer.  */
 
 #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   FORMAT ,
 #include "rtl.def"             /* rtl expressions are defined here */
@@ -167,38 +249,42 @@ char *rtx_format[] = {
 /* Indexed by rtx code, gives a character representing the "class" of
    that rtx code.  See rtl.def for documentation on the defined classes.  */
 
-char rtx_class[] = {
-#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   CLASS, 
+const char rtx_class[NUM_RTX_CODE] = {
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   CLASS,
 #include "rtl.def"             /* rtl expressions are defined here */
 #undef DEF_RTL_EXPR
 };
 
 /* Names for kinds of NOTEs and REG_NOTEs.  */
 
-char *note_insn_name[] = { 0                    , "NOTE_INSN_DELETED",
-                          "NOTE_INSN_BLOCK_BEG", "NOTE_INSN_BLOCK_END",
-                          "NOTE_INSN_LOOP_BEG", "NOTE_INSN_LOOP_END",
-                          "NOTE_INSN_FUNCTION_END", "NOTE_INSN_SETJMP",
-                          "NOTE_INSN_LOOP_CONT", "NOTE_INSN_LOOP_VTOP",
-                          "NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG",
-                          "NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
-                          "NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
-                          "NOTE_REPEATED_LINE_NUMBER", "NOTE_INSN_RANGE_START",
-                          "NOTE_INSN_RANGE_END", "NOTE_INSN_LIVE",
-                          "NOTE_INSN_BASIC_BLOCK" };
-
-char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
-                         "REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",
-                         "REG_NONNEG", "REG_NO_CONFLICT", "REG_UNUSED",
-                         "REG_CC_SETTER", "REG_CC_USER", "REG_LABEL",
-                         "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
-                         "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA",
-                         "REG_BR_PRED", "REG_EH_CONTEXT",
-                         "REG_FRAME_RELATED_EXPR", "REG_EH_REGION",
-                         "REG_EH_RETHROW" };
-
-static void dump_and_abort     PROTO((int, int, FILE *)) ATTRIBUTE_NORETURN;
-static void read_name          PROTO((char *, FILE *));
+const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS] =
+{
+  "", "NOTE_INSN_DELETED",
+  "NOTE_INSN_BLOCK_BEG", "NOTE_INSN_BLOCK_END",
+  "NOTE_INSN_LOOP_BEG", "NOTE_INSN_LOOP_END",
+  "NOTE_INSN_LOOP_CONT", "NOTE_INSN_LOOP_VTOP",
+  "NOTE_INSN_FUNCTION_END",
+  "NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG",
+  "NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
+  "NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
+  "NOTE_INSN_REPEATED_LINE_NUMBER", "NOTE_INSN_RANGE_BEG",
+  "NOTE_INSN_RANGE_END", "NOTE_INSN_LIVE",
+  "NOTE_INSN_BASIC_BLOCK", "NOTE_INSN_EXPECTED_VALUE"
+};
+
+const char * const reg_note_name[] =
+{
+  "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_EQUAL",
+  "REG_WAS_0", "REG_RETVAL", "REG_LIBCALL", "REG_NONNEG",
+  "REG_NO_CONFLICT", "REG_UNUSED", "REG_CC_SETTER", "REG_CC_USER",
+  "REG_LABEL", "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
+  "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA", "REG_BR_PRED",
+  "REG_FRAME_RELATED_EXPR", "REG_EH_CONTEXT", "REG_EH_REGION",
+  "REG_SAVE_NOTE", "REG_MAYBE_DEAD", "REG_NORETURN",
+  "REG_NON_LOCAL_GOTO", "REG_SETJMP", "REG_ALWAYS_RETURN",
+  "REG_VTABLE_REF"
+};
+
 \f
 /* Allocate an rtx vector of N elements.
    Store the length, and initialize all elements to zero.  */
@@ -208,18 +294,12 @@ rtvec_alloc (n)
      int n;
 {
   rtvec rt;
-  int i;
-
-  rt = (rtvec) obstack_alloc (rtl_obstack,
-                             sizeof (struct rtvec_def)
-                             + (( n - 1) * sizeof (rtunion)));
 
+  rt = ggc_alloc_rtvec (n);
   /* clear out the vector */
-  PUT_NUM_ELEM (rt, n);
-
-  for (i = 0; i < n; i++)
-    rt->elem[i].rtwint = 0;
+  memset (&rt->elem[0], 0, n * sizeof (rtx));
 
+  PUT_NUM_ELEM (rt, n);
   return rt;
 }
 
@@ -231,45 +311,19 @@ rtx_alloc (code)
   RTX_CODE code;
 {
   rtx rt;
-  register struct obstack *ob = rtl_obstack;
-  register int nelts = GET_RTX_LENGTH (code);
-  register int length = sizeof (struct rtx_def)
-    + (nelts - 1) * sizeof (rtunion);
-
-  /* This function is called more than any other in GCC,
-     so we manipulate the obstack directly.
-
-     Even though rtx objects are word aligned, we may be sharing an obstack
-     with tree nodes, which may have to be double-word aligned.  So align
-     our length to the alignment mask in the obstack.  */
-
-  length = (length + ob->alignment_mask) & ~ ob->alignment_mask;
+  int n = GET_RTX_LENGTH (code);
 
-  if (ob->chunk_limit - ob->next_free < length)
-    _obstack_newchunk (ob, length);
-  rt = (rtx)ob->object_base;
-  ob->next_free += length;
-  ob->object_base = ob->next_free;
+  rt = ggc_alloc_rtx (n);
 
-  /* We want to clear everything up to the FLD array.  Normally, this is
-     one int, but we don't want to assume that and it isn't very portable
-     anyway; this is.  */
+  /* We want to clear everything up to the FLD array.  Normally, this
+     is one int, but we don't want to assume that and it isn't very
+     portable anyway; this is.  */
 
   memset (rt, 0, sizeof (struct rtx_def) - sizeof (rtunion));
-
   PUT_CODE (rt, code);
-
   return rt;
 }
 
-/* Free the rtx X and all RTL allocated since X.  */
-
-void
-rtx_free (x)
-     rtx x;
-{
-  obstack_free (rtl_obstack, x);
-}
 \f
 /* Create a new copy of an rtx.
    Recursively copies the operands of the rtx,
@@ -277,12 +331,12 @@ rtx_free (x)
 
 rtx
 copy_rtx (orig)
-     register rtx orig;
+     rtx orig;
 {
-  register rtx copy;
-  register int i, j;
-  register RTX_CODE code;
-  register char *format_ptr;
+  rtx copy;
+  int i, j;
+  RTX_CODE code;
+  const char *format_ptr;
 
   code = GET_CODE (orig);
 
@@ -331,34 +385,26 @@ copy_rtx (orig)
      walks over the RTL.  */
   copy->used = 0;
 
-  /* We do not copy JUMP, CALL, or FRAME_RELATED for INSNs.  */
+  /* We do not copy FRAME_RELATED for INSNs.  */
   if (GET_RTX_CLASS (code) == 'i')
-    {
-      copy->jump = 0;
-      copy->call = 0;
-      copy->frame_related = 0;
-    }
-  
+    copy->frame_related = 0;
+  copy->jump = orig->jump;
+  copy->call = orig->call;
+
   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
 
   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
     {
+      copy->fld[i] = orig->fld[i];
       switch (*format_ptr++)
        {
        case 'e':
-         XEXP (copy, i) = XEXP (orig, i);
          if (XEXP (orig, i) != NULL)
            XEXP (copy, i) = copy_rtx (XEXP (orig, i));
          break;
 
-       case '0':
-       case 'u':
-         XEXP (copy, i) = XEXP (orig, i);
-         break;
-
        case 'E':
        case 'V':
-         XVEC (copy, i) = XVEC (orig, i);
          if (XVEC (orig, i) != NULL)
            {
              XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
@@ -367,29 +413,15 @@ copy_rtx (orig)
            }
          break;
 
-       case 'b':
-         {
-           bitmap new_bits = BITMAP_OBSTACK_ALLOC (rtl_obstack);
-           bitmap_copy (new_bits, XBITMAP (orig, i));
-           XBITMAP (copy, i) = new_bits;
-           break;
-         }
-
        case 't':
-         XTREE (copy, i) = XTREE (orig, i);
-         break;
-
        case 'w':
-         XWINT (copy, i) = XWINT (orig, i);
-         break;
-
        case 'i':
-         XINT (copy, i) = XINT (orig, i);
-         break;
-
        case 's':
        case 'S':
-         XSTR (copy, i) = XSTR (orig, i);
+       case 'T':
+       case 'u':
+       case '0':
+         /* These are left unchanged.  */
          break;
 
        default:
@@ -404,13 +436,13 @@ copy_rtx (orig)
 
 rtx
 copy_most_rtx (orig, may_share)
-     register rtx orig;
-     register rtx may_share;
+     rtx orig;
+     rtx may_share;
 {
-  register rtx copy;
-  register int i, j;
-  register RTX_CODE code;
-  register char *format_ptr;
+  rtx copy;
+  int i, j;
+  RTX_CODE code;
+  const char *format_ptr;
 
   if (orig == may_share)
     return orig;
@@ -438,7 +470,8 @@ copy_most_rtx (orig, may_share)
   copy->volatil = orig->volatil;
   copy->unchanging = orig->unchanging;
   copy->integrated = orig->integrated;
-  
+  copy->frame_related = orig->frame_related;
+
   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
 
   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
@@ -451,7 +484,6 @@ copy_most_rtx (orig, may_share)
            XEXP (copy, i) = copy_most_rtx (XEXP (orig, i), may_share);
          break;
 
-       case '0':
        case 'u':
          XEXP (copy, i) = XEXP (orig, i);
          break;
@@ -477,11 +509,20 @@ copy_most_rtx (orig, may_share)
          XINT (copy, i) = XINT (orig, i);
          break;
 
+       case 't':
+         XTREE (copy, i) = XTREE (orig, i);
+         break;
+
        case 's':
        case 'S':
          XSTR (copy, i) = XSTR (orig, i);
          break;
 
+       case '0':
+         /* Copy this through the wide int field; that's safest.  */
+         X0WINT (copy, i) = X0WINT (orig, i);
+         break;
+
        default:
          abort ();
        }
@@ -490,472 +531,253 @@ copy_most_rtx (orig, may_share)
 }
 
 /* Create a new copy of an rtx.  Only copy just one level.  */
+
 rtx
 shallow_copy_rtx (orig)
      rtx orig;
 {
-  register int i;
-  register char *format_ptr;
-  register RTX_CODE code = GET_CODE (orig);
-  register rtx copy = rtx_alloc (code);
+  int i;
+  RTX_CODE code = GET_CODE (orig);
+  rtx copy = rtx_alloc (code);
 
   PUT_MODE (copy, GET_MODE (orig));
   copy->in_struct = orig->in_struct;
   copy->volatil = orig->volatil;
   copy->unchanging = orig->unchanging;
   copy->integrated = orig->integrated;
+  copy->frame_related = orig->frame_related;
 
   for (i = 0; i < GET_RTX_LENGTH (code); i++)
     copy->fld[i] = orig->fld[i];
 
   return copy;
 }
-\f
-/* Subroutines of read_rtx.  */
 
-/* Dump code after printing a message.  Used when read_rtx finds
-   invalid data.  */
+/* Return the alignment of MODE. This will be bounded by 1 and
+   BIGGEST_ALIGNMENT.  */
 
-static void
-dump_and_abort (expected_c, actual_c, infile)
-     int expected_c, actual_c;
-     FILE *infile;
+unsigned int
+get_mode_alignment (mode)
+     enum machine_mode mode;
 {
-  int c, i;
-
-  if (expected_c >= 0)
-    fprintf (stderr,
-            "Expected character %c.  Found character %c.",
-            expected_c, actual_c);
-  fprintf (stderr, "  At file position: %ld\n", ftell (infile));
-  fprintf (stderr, "Following characters are:\n\t");
-  for (i = 0; i < 200; i++)
-    {
-      c = getc (infile);
-      if (EOF == c) break;
-      putc (c, stderr);
-    }
-  fprintf (stderr, "Aborting.\n");
-  abort ();
+  unsigned int alignment = GET_MODE_UNIT_SIZE (mode);
+  
+  /* Extract the LSB of the size.  */
+  alignment = alignment & -alignment;
+  alignment *= BITS_PER_UNIT;
+
+  alignment = MIN (BIGGEST_ALIGNMENT, MAX (1, alignment));
+  return alignment;
 }
+\f
+/* This is 1 until after the rtl generation pass.  */
+int rtx_equal_function_value_matters;
 
-/* Read chars from INFILE until a non-whitespace char
-   and return that.  Comments, both Lisp style and C style,
-   are treated as whitespace.
-   Tools such as genflags use this function.  */
+/* Nonzero when we are generating CONCATs.  */
+int generating_concat_p;
+\f
+/* Return 1 if X and Y are identical-looking rtx's.
+   This is the Lisp function EQUAL for rtx arguments.  */
 
 int
-read_skip_spaces (infile)
-     FILE *infile;
+rtx_equal_p (x, y)
+     rtx x, y;
 {
-  register int c;
-  while ((c = getc (infile)))
-    {
-      if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
-       ;
-      else if (c == ';')
-       {
-         while ((c = getc (infile)) && c != '\n' && c != EOF)
-           ;
-       }
-      else if (c == '/')
-       {
-         register int prevc;
-         c = getc (infile);
-         if (c != '*')
-           dump_and_abort ('*', c, infile);
-         
-         prevc = 0;
-         while ((c = getc (infile)) && c != EOF)
-           {
-             if (prevc == '*' && c == '/')
-               break;
-             prevc = c;
-           }
-       }
-      else break;
-    }
-  return c;
-}
+  int i;
+  int j;
+  enum rtx_code code;
+  const char *fmt;
 
-/* Read an rtx code name into the buffer STR[].
-   It is terminated by any of the punctuation chars of rtx printed syntax.  */
+  if (x == y)
+    return 1;
+  if (x == 0 || y == 0)
+    return 0;
 
-static void
-read_name (str, infile)
-     char *str;
-     FILE *infile;
-{
-  register char *p;
-  register int c;
+  code = GET_CODE (x);
+  /* Rtx's of different codes cannot be equal.  */
+  if (code != GET_CODE (y))
+    return 0;
 
-  c = read_skip_spaces(infile);
+  /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
+     (REG:SI x) and (REG:HI x) are NOT equivalent.  */
 
-  p = str;
-  while (1)
-    {
-      if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
-       break;
-      if (c == ':' || c == ')' || c == ']' || c == '"' || c == '/'
-         || c == '(' || c == '[')
-       {
-         ungetc (c, infile);
-         break;
-       }
-      *p++ = c;
-      c = getc (infile);
-    }
-  if (p == str)
-    {
-      fprintf (stderr, "missing name or number");
-      dump_and_abort (-1, -1, infile);
-    }
+  if (GET_MODE (x) != GET_MODE (y))
+    return 0;
 
-  *p = 0;
-}
-\f
-/* Provide a version of a function to read a long long if the system does
-   not provide one.  */
-#if HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_LONG && !defined(HAVE_ATOLL) && !defined(HAVE_ATOQ)
-HOST_WIDE_INT
-atoll(p)
-    const char *p;
-{
-  int neg = 0;
-  HOST_WIDE_INT tmp_wide;
-
-  while (ISSPACE(*p))
-    p++;
-  if (*p == '-')
-    neg = 1, p++;
-  else if (*p == '+')
-    p++;
-
-  tmp_wide = 0;
-  while (ISDIGIT(*p))
+  /* Some RTL can be compared nonrecursively.  */
+  switch (code)
     {
-      HOST_WIDE_INT new_wide = tmp_wide*10 + (*p - '0');
-      if (new_wide < tmp_wide)
-       {
-         /* Return INT_MAX equiv on overflow.  */
-         tmp_wide = (~(unsigned HOST_WIDE_INT)0) >> 1;
-         break;
-       }
-      tmp_wide = new_wide;
-      p++;
-    }
-
-  if (neg)
-    tmp_wide = -tmp_wide;
-  return tmp_wide;
-}
-#endif
-
-/* Read an rtx in printed representation from INFILE
-   and return an actual rtx in core constructed accordingly.
-   read_rtx is not used in the compiler proper, but rather in
-   the utilities gen*.c that construct C code from machine descriptions.  */
+    case REG:
+      /* Until rtl generation is complete, don't consider a reference
+        to the return register of the current function the same as
+        the return from a called function.  This eases the job of
+        function integration.  Once the distinction is no longer
+        needed, they can be considered equivalent.  */
+      return (REGNO (x) == REGNO (y)
+             && (! rtx_equal_function_value_matters
+                 || REG_FUNCTION_VALUE_P (x) == REG_FUNCTION_VALUE_P (y)));
+
+    case LABEL_REF:
+      return XEXP (x, 0) == XEXP (y, 0);
 
-rtx
-read_rtx (infile)
-     FILE *infile;
-{
-  register int i, j, list_counter;
-  RTX_CODE tmp_code;
-  register char *format_ptr;
-  /* tmp_char is a buffer used for reading decimal integers
-     and names of rtx types and machine modes.
-     Therefore, 256 must be enough.  */
-  char tmp_char[256];
-  rtx return_rtx;
-  register int c;
-  int tmp_int;
-  HOST_WIDE_INT tmp_wide;
-
-  /* Linked list structure for making RTXs: */
-  struct rtx_list
-    {
-      struct rtx_list *next;
-      rtx value;               /* Value of this node...                */
-    };
+    case SYMBOL_REF:
+      return XSTR (x, 0) == XSTR (y, 0);
 
-  c = read_skip_spaces (infile); /* Should be open paren.  */
-  if (c != '(')
-    dump_and_abort ('(', c, infile);
+    case SCRATCH:
+    case CONST_DOUBLE:
+    case CONST_INT:
+      return 0;
 
-  read_name (tmp_char, infile);
+    default:
+      break;
+    }
 
-  tmp_code = UNKNOWN;
+  /* Compare the elements.  If any pair of corresponding elements
+     fail to match, return 0 for the whole things.  */
 
-  for (i=0; i < NUM_RTX_CODE; i++) /* @@ might speed this search up */
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
-      if (!(strcmp (tmp_char, GET_RTX_NAME (i))))
+      switch (fmt[i])
        {
-         tmp_code = (RTX_CODE) i;      /* get value for name */
+       case 'w':
+         if (XWINT (x, i) != XWINT (y, i))
+           return 0;
          break;
-       }
-    }
-  if (tmp_code == UNKNOWN)
-    {
-      fprintf (stderr,
-              "Unknown rtx read in rtl.read_rtx(). Code name was %s .",
-              tmp_char);
-    }
-  /* (NIL) stands for an expression that isn't there.  */
-  if (tmp_code == NIL)
-    {
-      /* Discard the closeparen.  */
-      while ((c = getc (infile)) && c != ')');
-      return 0;
-    }
-
-  return_rtx = rtx_alloc (tmp_code); /* if we end up with an insn expression
-                                      then we free this space below.  */
-  format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx));
 
-  /* If what follows is `: mode ', read it and
-     store the mode in the rtx.  */
-
-  i = read_skip_spaces (infile);
-  if (i == ':')
-    {
-      register int k;
-      read_name (tmp_char, infile);
-      for (k = 0; k < NUM_MACHINE_MODES; k++)
-       if (!strcmp (GET_MODE_NAME (k), tmp_char))
+       case 'n':
+       case 'i':
+         if (XINT (x, i) != XINT (y, i))
+           return 0;
          break;
 
-      PUT_MODE (return_rtx, (enum machine_mode) k );
-    }
-  else
-    ungetc (i, infile);
-
-  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (return_rtx)); i++)
-    switch (*format_ptr++)
-      {
-       /* 0 means a field for internal use only.
-          Don't expect it to be present in the input.  */
-      case '0':
-       break;
-
-      case 'e':
-      case 'u':
-       XEXP (return_rtx, i) = read_rtx (infile);
-       break;
-
-      case 'V':
-       /* 'V' is an optional vector: if a closeparen follows,
-          just store NULL for this element.  */
-       c = read_skip_spaces (infile);
-       ungetc (c, infile);
-       if (c == ')')
-         {
-           XVEC (return_rtx, i) = 0;
-           break;
-         }
-       /* Now process the vector.  */
-  
-      case 'E':
-       {
-         register struct rtx_list *next_rtx, *rtx_list_link;
-         struct rtx_list *list_rtx = NULL;
-
-         c = read_skip_spaces (infile);
-         if (c != '[')
-           dump_and_abort ('[', c, infile);
+       case 'V':
+       case 'E':
+         /* Two vectors must have the same length.  */
+         if (XVECLEN (x, i) != XVECLEN (y, i))
+           return 0;
+
+         /* And the corresponding elements must match.  */
+         for (j = 0; j < XVECLEN (x, i); j++)
+           if (rtx_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0)
+             return 0;
+         break;
 
-         /* add expressions to a list, while keeping a count */
-         next_rtx = NULL;
-         list_counter = 0;
-         while ((c = read_skip_spaces (infile)) && c != ']')
-           {
-             ungetc (c, infile);
-             list_counter++;
-             rtx_list_link = (struct rtx_list *)
-               alloca (sizeof (struct rtx_list));
-             rtx_list_link->value = read_rtx (infile);
-             if (next_rtx == 0)
-               list_rtx = rtx_list_link;
-             else
-               next_rtx->next = rtx_list_link;
-             next_rtx = rtx_list_link;
-             rtx_list_link->next = 0;
-           }
-         /* get vector length and allocate it */
-         XVEC (return_rtx, i) = (list_counter
-                                 ? rtvec_alloc (list_counter) : NULL_RTVEC);
-         if (list_counter > 0)
-           {
-             next_rtx = list_rtx;
-             for (j = 0; j < list_counter; j++,
-                  next_rtx = next_rtx->next)
-               XVECEXP (return_rtx, i, j) = next_rtx->value;
-           }
-         /* close bracket gotten */
-       }
-       break;
-
-      case 'S':
-       /* 'S' is an optional string: if a closeparen follows,
-          just store NULL for this element.  */
-       c = read_skip_spaces (infile);
-       ungetc (c, infile);
-       if (c == ')')
-         {
-           XSTR (return_rtx, i) = 0;
-           break;
-         }
-
-      case 's':
-       {
-         int saw_paren = 0;
-         register char *stringbuf;
+       case 'e':
+         if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0)
+           return 0;
+         break;
 
-         c = read_skip_spaces (infile);
-         if (c == '(')
-           {
-             saw_paren = 1;
-             c = read_skip_spaces (infile);
-           }
-         if (c != '"')
-           dump_and_abort ('"', c, infile);
+       case 'S':
+       case 's':
+         if ((XSTR (x, i) || XSTR (y, i))
+             && (! XSTR (x, i) || ! XSTR (y, i)
+                 || strcmp (XSTR (x, i), XSTR (y, i))))
+           return 0;
+         break;
 
-         while (1)
-           {
-             c = getc (infile); /* Read the string  */
-             if (c == '\\')
-               {
-                 c = getc (infile);    /* Read the string  */
-                 /* \; makes stuff for a C string constant containing
-                    newline and tab.  */
-                 if (c == ';')
-                   {
-                     obstack_grow (rtl_obstack, "\\n\\t", 4);
-                     continue;
-                   }
-               }
-             else if (c == '"')
-               break;
-
-             obstack_1grow (rtl_obstack, c);
-           }
+       case 'u':
+         /* These are just backpointers, so they don't matter.  */
+         break;
 
-         obstack_1grow (rtl_obstack, 0);
-         stringbuf = (char *) obstack_finish (rtl_obstack);
+       case '0':
+       case 't':
+         break;
 
-         if (saw_paren)
-           {
-             c = read_skip_spaces (infile);
-             if (c != ')')
-               dump_and_abort (')', c, infile);
-           }
-         XSTR (return_rtx, i) = stringbuf;
+         /* It is believed that rtx's at this level will never
+            contain anything but integers and other rtx's,
+            except for within LABEL_REFs and SYMBOL_REFs.  */
+       default:
+         abort ();
        }
-       break;
-
-      case 'w':
-       read_name (tmp_char, infile);
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-       tmp_wide = atoi (tmp_char);
-#else
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
-       tmp_wide = atol (tmp_char);
-#else
-       /* Prefer atoll over atoq, since the former is in the ISO C9X draft. 
-          But prefer not to use our hand-rolled function above either.  */
-#if defined(HAVE_ATOLL) || !defined(HAVE_ATOQ)
-       tmp_wide = atoll (tmp_char);
-#else
-       tmp_wide = atoq (tmp_char);
-#endif
-#endif
-#endif
-       XWINT (return_rtx, i) = tmp_wide;
-       break;
-
-      case 'i':
-      case 'n':
-       read_name (tmp_char, infile);
-       tmp_int = atoi (tmp_char);
-       XINT (return_rtx, i) = tmp_int;
-       break;
-
-      default:
-       fprintf (stderr,
-                "switch format wrong in rtl.read_rtx(). format was: %c.\n",
-                format_ptr[-1]);
-       fprintf (stderr, "\tfile position: %ld\n", ftell (infile));
-       abort ();
-      }
-
-  c = read_skip_spaces (infile);
-  if (c != ')')
-    dump_and_abort (')', c, infile);
-
-  return return_rtx;
+    }
+  return 1;
 }
 \f
-/* This is called once per compilation, before any rtx's are constructed.
-   It initializes the vector `rtx_length', the extra CC modes, if any,
-   and computes certain commonly-used modes.  */
-
+#if defined ENABLE_RTL_CHECKING && (GCC_VERSION >= 2007)
 void
-init_rtl ()
+rtl_check_failed_bounds (r, n, file, line, func)
+    rtx r;
+    int n;
+    const char *file;
+    int line;
+    const char *func;
 {
-  int min_class_size[(int) MAX_MODE_CLASS];
-  enum machine_mode mode;
-  int i;
+  internal_error
+    ("RTL check: access of elt %d of `%s' with last elt %d in %s, at %s:%d",
+     n, GET_RTX_NAME (GET_CODE (r)), GET_RTX_LENGTH (GET_CODE (r)) - 1,
+     func, trim_filename (file), line);
+}
 
-  for (i = 0; i < NUM_RTX_CODE; i++)
-    rtx_length[i] = strlen (rtx_format[i]);
-
-  /* Make CONST_DOUBLE bigger, if real values are bigger than
-     it normally expects to have room for.
-     Note that REAL_VALUE_TYPE is not defined by default,
-     since tree.h is not included.  But the default dfn as `double'
-     would do no harm.  */
-#ifdef REAL_VALUE_TYPE
-  i = sizeof (REAL_VALUE_TYPE) / sizeof (rtunion) + 2;
-  if (rtx_length[(int) CONST_DOUBLE] < i)
-    {
-      char *s = (char *) xmalloc (i + 1);
-      rtx_length[(int) CONST_DOUBLE] = i;
-      rtx_format[(int) CONST_DOUBLE] = s;
-      *s++ = 'e';
-      *s++ = '0';
-      /* Set the GET_RTX_FORMAT of CONST_DOUBLE to a string
-        of as many `w's as we now have elements.  Subtract two from
-        the size to account for the 'e' and the '0'.  */
-      for (i = 2; i < rtx_length[(int) CONST_DOUBLE]; i++)
-       *s++ = 'w';
-      *s++ = 0;
-    }
-#endif
+void
+rtl_check_failed_type1 (r, n, c1, file, line, func)
+    rtx r;
+    int n;
+    int c1;
+    const char *file;
+    int line;
+    const char *func;
+{
+  internal_error
+    ("RTL check: expected elt %d type '%c', have '%c' (rtx %s) in %s, at %s:%d",
+     n, c1, GET_RTX_FORMAT (GET_CODE (r))[n], GET_RTX_NAME (GET_CODE (r)),
+     func, trim_filename (file), line);
+}
 
-#ifdef EXTRA_CC_MODES
-  for (i = (int) CCmode + 1; i < (int) MAX_MACHINE_MODE; i++)
-    {
-      mode_class[i] = MODE_CC;
-      mode_mask_array[i] = mode_mask_array[(int) CCmode];
-      mode_size[i] = mode_size[(int) CCmode];
-      mode_unit_size[i] = mode_unit_size[(int) CCmode];
-      mode_wider_mode[i - 1] = i;
-      mode_wider_mode[i] = (unsigned char)VOIDmode;
-    }
-#endif
+void
+rtl_check_failed_type2 (r, n, c1, c2, file, line, func)
+    rtx r;
+    int n;
+    int c1;
+    int c2;
+    const char *file;
+    int line;
+    const char *func;
+{
+  internal_error
+    ("RTL check: expected elt %d type '%c' or '%c', have '%c' (rtx %s) in %s, at %s:%d",
+     n, c1, c2, GET_RTX_FORMAT (GET_CODE (r))[n], GET_RTX_NAME (GET_CODE (r)),
+     func, trim_filename (file), line);
+}
 
-  /* Find the narrowest mode for each class.  */
+void
+rtl_check_failed_code1 (r, code, file, line, func)
+    rtx r;
+    enum rtx_code code;
+    const char *file;
+    int line;
+    const char *func;
+{
+  internal_error ("RTL check: expected code `%s', have `%s' in %s, at %s:%d",
+                 GET_RTX_NAME (code), GET_RTX_NAME (GET_CODE (r)), func,
+                 trim_filename (file), line);
+}
 
-  for (i = 0; i < (int) MAX_MODE_CLASS; i++)
-    min_class_size[i] = 1000;
+void
+rtl_check_failed_code2 (r, code1, code2, file, line, func)
+    rtx r;
+    enum rtx_code code1, code2;
+    const char *file;
+    int line;
+    const char *func;
+{
+  internal_error
+    ("RTL check: expected code `%s' or `%s', have `%s' in %s, at %s:%d",
+     GET_RTX_NAME (code1), GET_RTX_NAME (code2), GET_RTX_NAME (GET_CODE (r)),
+     func, trim_filename (file), line);
+}
 
-  for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
-       mode = (enum machine_mode) ((int) mode + 1))
-    {
-      if (GET_MODE_SIZE (mode) < min_class_size[(int) GET_MODE_CLASS (mode)])
-       {
-         class_narrowest_mode[(int) GET_MODE_CLASS (mode)] = mode;
-         min_class_size[(int) GET_MODE_CLASS (mode)] = GET_MODE_SIZE (mode);
-       }
-    }
+/* XXX Maybe print the vector?  */
+void
+rtvec_check_failed_bounds (r, n, file, line, func)
+    rtvec r;
+    int n;
+    const char *file;
+    int line;
+    const char *func;
+{
+  internal_error
+    ("RTL check: access of elt %d of vector with last elt %d in %s, at %s:%d",
+     n, GET_NUM_ELEM (r) - 1, func, trim_filename (file), line);
 }
+#endif /* ENABLE_RTL_CHECKING */