OSDN Git Service

* gcc.dg/ppc-bitfield1.c: Skip if not LP64, don't specify -m64.
[pf3gnuchains/gcc-fork.git] / gcc / rtl.c
index 44e998b..8dbde14 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 Free Software Foundation, Inc.
+/* RTL utility routines.
+   Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002,
+   2003, 2004 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.  */
+
+/* This file is compiled twice: once for the generator programs
+   once for the compiler.  */
+#ifdef GENERATOR_FILE
+#include "bconfig.h"
+#else
 #include "config.h"
+#endif
+
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "real.h"
-#include "bitmap.h"
+#include "ggc.h"
+#include "errors.h"
 
-#include "obstack.h"
-#define        obstack_chunk_alloc     xmalloc
-#define        obstack_chunk_free      free
-
-/* 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
 /* 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];
-
-/* Indexed by rtx code, gives the name of that kind of rtx, as a C string.  */
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   sizeof FORMAT - 1 ,
 
-#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   NAME ,
-
-char *rtx_name[] = {
-#include "rtl.def"             /* rtl expressions are documented here */
+const unsigned char rtx_length[NUM_RTX_CODE] = {
+#include "rtl.def"
 };
 
 #undef DEF_RTL_EXPR
 
-/* 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,
-
-char *mode_name[(int) MAX_MACHINE_MODE + 1] = {
-#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 length of the mode, in bytes.
-   GET_MODE_CLASS uses this.  */
-
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  CLASS,
-
-enum mode_class mode_class[(int) MAX_MACHINE_MODE] = {
-#include "machmode.def"
-};
-
-#undef DEF_MACHMODE
-
-/* 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,
-
-int mode_size[(int) MAX_MACHINE_MODE] = {
-#include "machmode.def"
-};
-
-#undef DEF_MACHMODE
-
-/* 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,
-
-int mode_unit_size[(int) MAX_MACHINE_MODE] = {
-#include "machmode.def"                /* machine modes are documented here */
-};
-
-#undef DEF_MACHMODE
-
-/* Indexed by machine mode, gives next wider natural mode
-   (QI -> HI -> SI -> DI, etc.)  Widening multiply instructions
-   use this.  */
-
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  \
-  (unsigned char) WIDER,
-
-unsigned char mode_wider_mode[(int) MAX_MACHINE_MODE] = {
-#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,
+/* Indexed by rtx code, gives the name of that kind of rtx, as a C string.  */
 
-/* Indexed by machine mode, gives mask of significant bits in mode.  */
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   NAME ,
 
-unsigned HOST_WIDE_INT mode_mask_array[(int) MAX_MACHINE_MODE] = {
-#include "machmode.def"
+const char * const rtx_name[NUM_RTX_CODE] = {
+#include "rtl.def"             /* rtl expressions are documented here */
 };
 
-/* Indexed by mode class, gives the narrowest mode for each class.  */
-
-enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS];
+#undef DEF_RTL_EXPR
 
 /* 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 +75,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 +86,8 @@ 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. */
+     "B" is a basic block pointer.
+     "t" is a tree pointer.  */
 
 #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   FORMAT ,
 #include "rtl.def"             /* rtl expressions are defined here */
@@ -167,56 +97,71 @@ 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 enum rtx_class 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
 };
 
+/* Indexed by rtx code, gives the size of the rtx in bytes.  */
+
+const unsigned char rtx_size[NUM_RTX_CODE] = {
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)                                \
+  ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE                       \
+   ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT)       \
+   : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)),
+
+#include "rtl.def"
+#undef DEF_RTL_EXPR
+};
+
+/* Make sure all NOTE_INSN_* values are negative.  */
+extern char NOTE_INSN_MAX_isnt_negative_adjust_NOTE_INSN_BIAS
+[NOTE_INSN_MAX < 0 ? 1 : -1];
+
 /* 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" };
-
-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" };
-
-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] =
+{
+  "",
+#define DEF_INSN_NOTE(NAME) #NAME,
+#include "insn-notes.def"
+#undef DEF_INSN_NOTE
+};
+
+const char * const reg_note_name[REG_NOTE_MAX] =
+{
+#define DEF_REG_NOTE(NAME) #NAME,
+#include "reg-notes.def"
+#undef DEF_REG_NOTE
+};
+
+#ifdef GATHER_STATISTICS
+static int rtx_alloc_counts[(int) LAST_AND_UNUSED_RTX_CODE];
+static int rtx_alloc_sizes[(int) LAST_AND_UNUSED_RTX_CODE];
+static int rtvec_alloc_counts;
+static int rtvec_alloc_sizes;
+#endif
+
 \f
 /* Allocate an rtx vector of N elements.
    Store the length, and initialize all elements to zero.  */
 
 rtvec
-rtvec_alloc (n)
-     int n;
+rtvec_alloc (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.  */
+  memset (&rt->elem[0], 0, n * sizeof (rtx));
 
-  /* clear out the vector */
   PUT_NUM_ELEM (rt, n);
 
-  for (i = 0; i < n; i++)
-    rt->elem[i].rtwint = 0;
+#ifdef GATHER_STATISTICS
+  rtvec_alloc_counts++;
+  rtvec_alloc_sizes += n * sizeof (rtx);
+#endif
 
   return rt;
 }
@@ -225,81 +170,60 @@ rtvec_alloc (n)
    all the rest is initialized to zero.  */
 
 rtx
-rtx_alloc (code)
-  RTX_CODE code;
+rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
 {
   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;
+  rt = (rtx) ggc_alloc_typed_stat (gt_ggc_e_7rtx_def,
+                                  RTX_SIZE (code) PASS_MEM_STAT);
 
-  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;
-
-  /* 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.  */
-
-  length = (sizeof (struct rtx_def) - sizeof (rtunion) - 1) / sizeof (int);
-  for (; length >= 0; length--)
-    ((int *) rt)[length] = 0;
+  /* 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, RTX_HDR_SIZE);
   PUT_CODE (rt, code);
 
+#ifdef GATHER_STATISTICS
+  rtx_alloc_counts[code]++;
+  rtx_alloc_sizes[code] += RTX_SIZE (code);
+#endif
+
   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,
    except for those few rtx codes that are sharable.  */
 
 rtx
-copy_rtx (orig)
-     register rtx orig;
+copy_rtx (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);
 
   switch (code)
     {
     case REG:
-    case QUEUED:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case CODE_LABEL:
     case PC:
     case CC0:
     case SCRATCH:
       /* SCRATCH must be shared because they represent distinct values.  */
-    case ADDRESSOF:
       return orig;
+    case CLOBBER:
+      if (REG_P (XEXP (orig, 0)) && REGNO (XEXP (orig, 0)) < FIRST_PSEUDO_REGISTER)
+       return orig;
+      break;
 
     case CONST:
       /* CONST can be shared if it contains a SYMBOL_REF.  If it contains
@@ -320,32 +244,37 @@ copy_rtx (orig)
     }
 
   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 the various flags, and other information.  We assume that
+     all fields need copying, and then clear the fields that should
+     not be copied.  That is the sensible default behavior, and forces
+     us to explicitly document why we are *not* copying a flag.  */
+  memcpy (copy, orig, RTX_HDR_SIZE);
+
+  /* We do not copy the USED flag, which is used as a mark bit during
+     walks over the RTL.  */
+  RTX_FLAG (copy, used) = 0;
+
+  /* We do not copy FRAME_RELATED for INSNs.  */
+  if (INSN_P (orig))
+    RTX_FLAG (copy, frame_related) = 0;
+  RTX_FLAG (copy, jump) = RTX_FLAG (orig, jump);
+  RTX_FLAG (copy, call) = RTX_FLAG (orig, call);
+
   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
 
   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
     {
+      copy->u.fld[i] = orig->u.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));
@@ -354,573 +283,254 @@ 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 'B':
+       case '0':
+         /* These are left unchanged.  */
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
   return copy;
 }
 
-/* Similar to `copy_rtx' except that if MAY_SHARE is present, it is
-   placed in the result directly, rather than being copied.  */
+/* Create a new copy of an rtx.  Only copy just one level.  */
 
 rtx
-copy_most_rtx (orig, may_share)
-     register rtx orig;
-     register rtx may_share;
+shallow_copy_rtx_stat (rtx orig MEM_STAT_DECL)
 {
-  register rtx copy;
-  register int i, j;
-  register RTX_CODE code;
-  register char *format_ptr;
+  rtx copy;
 
-  if (orig == may_share)
-    return orig;
+  copy = (rtx) ggc_alloc_typed_stat (gt_ggc_e_7rtx_def,
+                                    RTX_SIZE (GET_CODE (orig)) PASS_MEM_STAT);
+  memcpy (copy, orig, RTX_SIZE (GET_CODE (orig)));
+  return copy;
+}
+\f
+/* Nonzero when we are generating CONCATs.  */
+int generating_concat_p;
 
-  code = GET_CODE (orig);
+/* Nonzero when we are expanding trees to RTL.  */
+int currently_expanding_to_rtl;
+
+\f
+/* Return 1 if X and Y are identical-looking rtx's.
+   This is the Lisp function EQUAL for rtx arguments.  */
+
+int
+rtx_equal_p (rtx x, rtx y)
+{
+  int i;
+  int j;
+  enum rtx_code code;
+  const char *fmt;
 
+  if (x == y)
+    return 1;
+  if (x == 0 || y == 0)
+    return 0;
+
+  code = GET_CODE (x);
+  /* Rtx's of different codes cannot be equal.  */
+  if (code != GET_CODE (y))
+    return 0;
+
+  /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
+     (REG:SI x) and (REG:HI x) are NOT equivalent.  */
+
+  if (GET_MODE (x) != GET_MODE (y))
+    return 0;
+
+  /* Some RTL can be compared nonrecursively.  */
   switch (code)
     {
     case REG:
-    case QUEUED:
-    case CONST_INT:
-    case CONST_DOUBLE:
+      return (REGNO (x) == REGNO (y));
+
+    case LABEL_REF:
+      return XEXP (x, 0) == XEXP (y, 0);
+
     case SYMBOL_REF:
-    case CODE_LABEL:
-    case PC:
-    case CC0:
-      return orig;
+      return XSTR (x, 0) == XSTR (y, 0);
+
+    case SCRATCH:
+    case CONST_DOUBLE:
+    case CONST_INT:
+    case CONST_VECTOR:
+      return 0;
+
     default:
       break;
     }
 
-  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;
-  
-  format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
+  /* Compare the elements.  If any pair of corresponding elements
+     fail to match, return 0 for the whole thing.  */
 
-  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
-      switch (*format_ptr++)
+      switch (fmt[i])
        {
-       case 'e':
-         XEXP (copy, i) = XEXP (orig, i);
-         if (XEXP (orig, i) != NULL && XEXP (orig, i) != may_share)
-           XEXP (copy, i) = copy_most_rtx (XEXP (orig, i), may_share);
+       case 'w':
+         if (XWINT (x, i) != XWINT (y, i))
+           return 0;
          break;
 
-       case '0':
-       case 'u':
-         XEXP (copy, i) = XEXP (orig, i);
+       case 'n':
+       case 'i':
+         if (XINT (x, i) != XINT (y, i))
+           return 0;
          break;
 
-       case 'E':
        case 'V':
-         XVEC (copy, i) = XVEC (orig, i);
-         if (XVEC (orig, i) != NULL)
-           {
-             XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
-             for (j = 0; j < XVECLEN (copy, i); j++)
-               XVECEXP (copy, i, j)
-                 = copy_most_rtx (XVECEXP (orig, i, j), may_share);
-           }
+       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;
 
-       case 'w':
-         XWINT (copy, i) = XWINT (orig, i);
+       case 'e':
+         if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0)
+           return 0;
          break;
 
-       case 'n':
-       case 'i':
-         XINT (copy, i) = XINT (orig, i);
+       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;
 
-       case 's':
-       case 'S':
-         XSTR (copy, i) = XSTR (orig, i);
+       case 'u':
+         /* These are just backpointers, so they don't matter.  */
+         break;
+
+       case '0':
+       case 't':
          break;
 
+         /* 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 ();
+         gcc_unreachable ();
        }
     }
-  return copy;
+  return 1;
 }
-\f
-/* Subroutines of read_rtx.  */
 
-/* Dump code after printing a message.  Used when read_rtx finds
-   invalid data.  */
-
-static void
-dump_and_abort (expected_c, actual_c, infile)
-     int expected_c, actual_c;
-     FILE *infile;
+void dump_rtx_statistics (void)
 {
-  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++)
+#ifdef GATHER_STATISTICS
+  int i;
+  int total_counts = 0;
+  int total_sizes = 0;
+  fprintf (stderr, "\nRTX Kind               Count      Bytes\n");
+  fprintf (stderr, "---------------------------------------\n");
+  for (i = 0; i < LAST_AND_UNUSED_RTX_CODE; i++)
+    if (rtx_alloc_counts[i])
+      {
+        fprintf (stderr, "%-20s %7d %10d\n", GET_RTX_NAME (i),
+                 rtx_alloc_counts[i], rtx_alloc_sizes[i]);
+        total_counts += rtx_alloc_counts[i];
+        total_sizes += rtx_alloc_sizes[i];
+      }
+  if (rtvec_alloc_counts)
     {
-      c = getc (infile);
-      if (EOF == c) break;
-      putc (c, stderr);
+      fprintf (stderr, "%-20s %7d %10d\n", "rtvec",
+               rtvec_alloc_counts, rtvec_alloc_sizes);
+      total_counts += rtvec_alloc_counts;
+      total_sizes += rtvec_alloc_sizes;
     }
-  fprintf (stderr, "Aborting.\n");
-  abort ();
+  fprintf (stderr, "---------------------------------------\n");
+  fprintf (stderr, "%-20s %7d %10d\n",
+           "Total", total_counts, total_sizes);
+  fprintf (stderr, "---------------------------------------\n");
+#endif  
 }
-
-/* 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.  */
-
-int
-read_skip_spaces (infile)
-     FILE *infile;
+\f
+#if defined ENABLE_RTL_CHECKING && (GCC_VERSION >= 2007)
+void
+rtl_check_failed_bounds (rtx r, int n, const char *file, int line,
+                        const char *func)
 {
-  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;
+  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);
 }
 
-/* Read an rtx code name into the buffer STR[].
-   It is terminated by any of the punctuation chars of rtx printed syntax.  */
-
-static void
-read_name (str, infile)
-     char *str;
-     FILE *infile;
+void
+rtl_check_failed_type1 (rtx r, int n, int c1, const char *file, int line,
+                       const char *func)
 {
-  register char *p;
-  register int c;
-
-  c = read_skip_spaces(infile);
-
-  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);
-    }
-
-  *p = 0;
+  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);
 }
-\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))
-    {
-      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;
+void
+rtl_check_failed_type2 (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);
 }
-#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.  */
 
-rtx
-read_rtx (infile)
-     FILE *infile;
+void
+rtl_check_failed_code1 (rtx r, enum rtx_code code, const char *file,
+                       int line, const char *func)
 {
-  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...                */
-    };
-
-  c = read_skip_spaces (infile); /* Should be open paren.  */
-  if (c != '(')
-    dump_and_abort ('(', c, infile);
-
-  read_name (tmp_char, infile);
-
-  tmp_code = UNKNOWN;
-
-  for (i=0; i < NUM_RTX_CODE; i++) /* @@ might speed this search up */
-    {
-      if (!(strcmp (tmp_char, GET_RTX_NAME (i))))
-       {
-         tmp_code = (RTX_CODE) i;      /* get value for name */
-         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))
-         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);
-
-         /* 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;
-
-         c = read_skip_spaces (infile);
-         if (c == '(')
-           {
-             saw_paren = 1;
-             c = read_skip_spaces (infile);
-           }
-         if (c != '"')
-           dump_and_abort ('"', c, infile);
-
-         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);
-           }
-
-         obstack_1grow (rtl_obstack, 0);
-         stringbuf = (char *) obstack_finish (rtl_obstack);
-
-         if (saw_paren)
-           {
-             c = read_skip_spaces (infile);
-             if (c != ')')
-               dump_and_abort (')', c, infile);
-           }
-         XSTR (return_rtx, i) = stringbuf;
-       }
-       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;
+  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);
 }
-\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.  */
 
 void
-init_rtl ()
+rtl_check_failed_code2 (rtx r, enum rtx_code code1, enum rtx_code code2,
+                       const char *file, int line, const char *func)
 {
-  int min_class_size[(int) MAX_MODE_CLASS];
-  enum machine_mode mode;
-  int i;
-
-  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
-
-#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
-
-  /* Find the narrowest mode for each class.  */
+  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 (i = 0; i < (int) MAX_MODE_CLASS; i++)
-    min_class_size[i] = 1000;
+/* XXX Maybe print the vector?  */
+void
+rtvec_check_failed_bounds (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 */
 
-  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);
-       }
-    }
+#if defined ENABLE_RTL_FLAG_CHECKING
+void
+rtl_check_failed_flag (const char *name, rtx r, const char *file,
+                      int line, const char *func)
+{
+  internal_error
+    ("RTL flag check: %s used with unexpected rtx code '%s' in %s, at %s:%d",
+     name, GET_RTX_NAME (GET_CODE (r)), func, trim_filename (file), line);
 }
+#endif /* ENABLE_RTL_FLAG_CHECKING */