OSDN Git Service

Fix comment.
[pf3gnuchains/gcc-fork.git] / gcc / rtl.c
index 1929459..bfe3806 100644 (file)
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -1,5 +1,6 @@
 /* Allocate and read RTL for GNU C Compiler.
-   Copyright (C) 1987, 1988, 1991, 1994, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000
+   Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -24,8 +25,10 @@ Boston, MA 02111-1307, USA.  */
 #include "rtl.h"
 #include "real.h"
 #include "bitmap.h"
-
+#include "ggc.h"
 #include "obstack.h"
+#include "toplev.h"
+
 #define        obstack_chunk_alloc     xmalloc
 #define        obstack_chunk_free      free
 
@@ -37,17 +40,67 @@ Boston, MA 02111-1307, USA.  */
 
 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 e0wwwww, 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
+#elif MAX_LONG_DOUBLE_TYPE_SIZE == 128
+#define REAL_WIDTH     (19*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
+#elif HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
+#define REAL_WIDTH     (7*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
+#endif
+#endif /* REAL_ARITHMETIC */
+
+#ifndef REAL_WIDTH
+#if HOST_BITS_PER_WIDE_INT*2 >= MAX_LONG_DOUBLE_TYPE_SIZE
+#define REAL_WIDTH     2
+#elif HOST_BITS_PER_WIDE_INT*3 >= MAX_LONG_DOUBLE_TYPE_SIZE
+#define REAL_WIDTH     3
+#elif HOST_BITS_PER_WIDE_INT*4 >= MAX_LONG_DOUBLE_TYPE_SIZE
+#define REAL_WIDTH     4
+#endif
+#endif /* REAL_WIDTH */
+
+#if REAL_WIDTH == 1
+#define CONST_DOUBLE_FORMAT    "e0ww"
+#elif REAL_WIDTH == 2
+#define CONST_DOUBLE_FORMAT    "e0ww"
+#elif REAL_WIDTH == 3
+#define CONST_DOUBLE_FORMAT    "e0www"
+#elif REAL_WIDTH == 4
+#define CONST_DOUBLE_FORMAT    "e0wwww"
+#elif REAL_WIDTH == 5
+#define CONST_DOUBLE_FORMAT    "e0wwwww"
+#else
+#define CONST_DOUBLE_FORMAT    /* nothing - will cause syntax error */
+#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).  */
+
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   sizeof FORMAT - 1 ,
 
-int rtx_length[NUM_RTX_CODE + 1];
+const int rtx_length[NUM_RTX_CODE + 1] = {
+#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[] = {
 #include "rtl.def"             /* rtl expressions are documented here */
 };
 
@@ -58,12 +111,8 @@ char *rtx_name[] = {
 
 #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  NAME,
 
-char *mode_name[(int) MAX_MACHINE_MODE + 1] = {
+const char * const 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.   */
   ""
@@ -76,7 +125,7 @@ char *mode_name[(int) MAX_MACHINE_MODE + 1] = {
 
 #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  CLASS,
 
-enum mode_class mode_class[(int) MAX_MACHINE_MODE] = {
+const enum mode_class mode_class[(int) MAX_MACHINE_MODE] = {
 #include "machmode.def"
 };
 
@@ -87,7 +136,7 @@ enum mode_class mode_class[(int) MAX_MACHINE_MODE] = {
 
 #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  SIZE,
 
-int mode_size[(int) MAX_MACHINE_MODE] = {
+const unsigned int mode_size[(int) MAX_MACHINE_MODE] = {
 #include "machmode.def"
 };
 
@@ -98,7 +147,7 @@ int mode_size[(int) MAX_MACHINE_MODE] = {
 
 #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  UNIT,
 
-int mode_unit_size[(int) MAX_MACHINE_MODE] = {
+const unsigned int mode_unit_size[(int) MAX_MACHINE_MODE] = {
 #include "machmode.def"                /* machine modes are documented here */
 };
 
@@ -111,7 +160,7 @@ int mode_unit_size[(int) MAX_MACHINE_MODE] = {
 #define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER)  \
   (unsigned char) WIDER,
 
-unsigned char mode_wider_mode[(int) MAX_MACHINE_MODE] = {
+const unsigned char mode_wider_mode[(int) MAX_MACHINE_MODE] = {
 #include "machmode.def"                /* machine modes are documented here */
 };
 
@@ -126,15 +175,26 @@ const unsigned HOST_WIDE_INT mode_mask_array[(int) MAX_MACHINE_MODE] = {
 #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.  */
+
+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
+};
 
-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[] = {
   /* "*" undefined.
          can cause a warning message
      "0" field is unused (or used in a phase-dependent manner)
@@ -167,36 +227,45 @@ 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[] = {
+#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" };
-
-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 *));
-static void read_name          PROTO((char *, FILE *));
+const char * const 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"
+};
+
+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_EH_RETHROW", "REG_SAVE_NOTE"
+};
+
+static void fatal_with_file_and_line PARAMS ((FILE *, const char *, ...))
+  ATTRIBUTE_PRINTF_2 ATTRIBUTE_NORETURN;
+static void fatal_expected_char PARAMS ((FILE *, int, int)) ATTRIBUTE_NORETURN;
+static void read_name          PARAMS ((char *, FILE *));
+static const char *trim_filename PARAMS ((const char *));
 \f
 /* Allocate an rtx vector of N elements.
    Store the length, and initialize all elements to zero.  */
@@ -206,18 +275,23 @@ rtvec_alloc (n)
      int n;
 {
   rtvec rt;
-  int i;
 
-  rt = (rtvec) obstack_alloc (rtl_obstack,
-                             sizeof (struct rtvec_def)
-                             + (( n - 1) * sizeof (rtunion)));
+  if (ggc_p)
+    rt = ggc_alloc_rtvec (n);
+  else
+    {
+      int i;
 
-  /* clear out the vector */
-  PUT_NUM_ELEM (rt, n);
+      rt = (rtvec) obstack_alloc (rtl_obstack,
+                                 sizeof (struct rtvec_def)
+                                 + (( n - 1) * sizeof (rtx)));
 
-  for (i = 0; i < n; i++)
-    rt->elem[i].rtwint = 0;
+      /* clear out the vector */
+      for (i = 0; i < n; i++)
+       rt->elem[i] = 0;
+    }
 
+  PUT_NUM_ELEM (rt, n);
   return rt;
 }
 
@@ -229,36 +303,40 @@ 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.
+  if (ggc_p)
+    rt = ggc_alloc_rtx (GET_RTX_LENGTH (code));
+  else
+    {
+      register struct obstack *ob = rtl_obstack;
+      register int nelts = GET_RTX_LENGTH (code);
+      register int length = sizeof (struct rtx_def)
+       + (nelts - 1) * sizeof (rtunion);
 
-     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.  */
+      /* This function is called more than any other in GCC, so we
+        manipulate the obstack directly.
 
-  length = (length + ob->alignment_mask) & ~ ob->alignment_mask;
+        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.  */
 
-  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;
+      length = (length + ob->alignment_mask) & ~ ob->alignment_mask;
 
-  /* 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.  */
+      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;
 
-  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.  */
 
-  PUT_CODE (rt, code);
+      memset (rt, 0, sizeof (struct rtx_def) - sizeof (rtunion));
+    }
 
+  PUT_CODE (rt, code);
   return rt;
 }
 
@@ -268,7 +346,8 @@ void
 rtx_free (x)
      rtx x;
 {
-  obstack_free (rtl_obstack, x);
+  if (!ggc_p)
+    obstack_free (rtl_obstack, x);
 }
 \f
 /* Create a new copy of an rtx.
@@ -282,7 +361,7 @@ copy_rtx (orig)
   register rtx copy;
   register int i, j;
   register RTX_CODE code;
-  register char *format_ptr;
+  register const char *format_ptr;
 
   code = GET_CODE (orig);
 
@@ -320,32 +399,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, sizeof (struct rtx_def) - sizeof (rtunion));
+
+  /* We do not copy the USED flag, which is used as a mark bit during
+     walks over the RTL.  */
+  copy->used = 0;
+
+  /* We do not copy FRAME_RELATED for INSNs.  */
+  if (GET_RTX_CLASS (code) == 'i')
+    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));
@@ -363,20 +447,13 @@ copy_rtx (orig)
          }
 
        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 'u':
+       case '0':
+         /* These are left unchanged.  */
          break;
 
        default:
@@ -397,7 +474,7 @@ copy_most_rtx (orig, may_share)
   register rtx copy;
   register int i, j;
   register RTX_CODE code;
-  register char *format_ptr;
+  register const char *format_ptr;
 
   if (orig == may_share)
     return orig;
@@ -425,7 +502,7 @@ copy_most_rtx (orig, may_share)
   copy->volatil = orig->volatil;
   copy->unchanging = orig->unchanging;
   copy->integrated = orig->integrated;
-  
+
   format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
 
   for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
@@ -438,7 +515,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;
@@ -464,44 +540,226 @@ 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 ();
        }
     }
   return copy;
 }
+
+/* Create a new copy of an rtx.  Only copy just one level.  */
+rtx
+shallow_copy_rtx (orig)
+     rtx orig;
+{
+  register int i;
+  register RTX_CODE code = GET_CODE (orig);
+  register 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;
+
+  for (i = 0; i < GET_RTX_LENGTH (code); i++)
+    copy->fld[i] = orig->fld[i];
+
+  return copy;
+}
+\f
+/* This is 1 until after the rtl generation pass.  */
+int rtx_equal_function_value_matters;
+\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 (x, y)
+     rtx x, y;
+{
+  register int i;
+  register int j;
+  register enum rtx_code code;
+  register 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:
+      /* 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);
+
+    case SYMBOL_REF:
+      return XSTR (x, 0) == XSTR (y, 0);
+
+    case SCRATCH:
+    case CONST_DOUBLE:
+    case CONST_INT:
+      return 0;
+
+    default:
+      break;
+    }
+
+  /* Compare the elements.  If any pair of corresponding elements
+     fail to match, return 0 for the whole things.  */
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      switch (fmt[i])
+       {
+       case 'w':
+         if (XWINT (x, i) != XWINT (y, i))
+           return 0;
+         break;
+
+       case 'n':
+       case 'i':
+         if (XINT (x, i) != XINT (y, i))
+           return 0;
+         break;
+
+       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;
+
+       case 'e':
+         if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0)
+           return 0;
+         break;
+
+       case 'S':
+       case 's':
+         if (strcmp (XSTR (x, i), XSTR (y, i)))
+           return 0;
+         break;
+
+       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 ();
+       }
+    }
+  return 1;
+}
 \f
 /* Subroutines of read_rtx.  */
 
-/* Dump code after printing a message.  Used when read_rtx finds
-   invalid data.  */
+/* The current line number for the file.  */
+int read_rtx_lineno = 1;
+
+/* The filename for aborting with file and line.  */
+const char *read_rtx_filename = "<unknown>";
 
 static void
-dump_and_abort (expected_c, actual_c, infile)
-     int expected_c, actual_c;
-     FILE *infile;
+fatal_with_file_and_line VPARAMS ((FILE *infile, const char *msg, ...))
 {
-  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++)
+#ifndef ANSI_PROTOTYPES
+  FILE *infile;
+  const char *msg;
+#endif
+  va_list ap;
+  char context[64];
+  size_t i;
+  int c;
+
+  VA_START (ap, msg);
+
+#ifndef ANSI_PROTOTYPES
+  infile = va_arg (ap, FILE *);
+  msg = va_arg (ap, const char *);
+#endif
+
+  fprintf (stderr, "%s:%d: ", read_rtx_filename, read_rtx_lineno);
+  vfprintf (stderr, msg, ap);
+  putc ('\n', stderr);
+
+  /* Gather some following context.  */
+  for (i = 0; i < sizeof(context)-1; ++i)
     {
       c = getc (infile);
-      if (EOF == c) break;
-      putc (c, stderr);
+      if (c == EOF)
+       break;
+      if (c == '\r' || c == '\n')
+       break;
+      context[i] = c;
     }
-  fprintf (stderr, "Aborting.\n");
-  abort ();
+  context[i] = '\0';
+
+  fprintf (stderr, "%s:%d: following context is `%s'\n",
+          read_rtx_filename, read_rtx_lineno, context);
+
+  va_end (ap);
+  exit (1);
+}
+
+/* Dump code after printing a message.  Used when read_rtx finds
+   invalid data.  */
+
+static void
+fatal_expected_char (infile, expected_c, actual_c)
+     FILE *infile;
+     int expected_c, actual_c;
+{
+  fatal_with_file_and_line (infile, "expected character `%c', found `%c'",
+                           expected_c, actual_c);
 }
 
 /* Read chars from INFILE until a non-whitespace char
@@ -514,33 +772,48 @@ read_skip_spaces (infile)
      FILE *infile;
 {
   register int c;
-  while ((c = getc (infile)))
+  while (1)
     {
-      if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
-       ;
-      else if (c == ';')
-       {
-         while ((c = getc (infile)) && c != '\n' && c != EOF)
-           ;
-       }
-      else if (c == '/')
+      c = getc (infile);
+      switch (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;
-           }
+       case '\n':
+         read_rtx_lineno++;
+         break;
+
+       case ' ': case '\t': case '\f': case '\r':
+         break;
+
+       case ';':
+         do
+           c = getc (infile);
+         while (c != '\n' && c != EOF);
+         read_rtx_lineno++;
+         break;
+
+       case '/':
+         {
+           register int prevc;
+           c = getc (infile);
+           if (c != '*')
+             fatal_expected_char (infile, '*', c);
+
+           prevc = 0;
+           while ((c = getc (infile)) && c != EOF)
+             {
+               if (c == '\n')
+                  read_rtx_lineno++;
+               else if (prevc == '*' && c == '/')
+                 break;
+               prevc = c;
+             }
+         }
+         break;
+
+       default:
+         return c;
        }
-      else break;
     }
-  return c;
 }
 
 /* Read an rtx code name into the buffer STR[].
@@ -571,10 +844,9 @@ read_name (str, infile)
       c = getc (infile);
     }
   if (p == str)
-    {
-      fprintf (stderr, "missing name or number");
-      dump_and_abort (-1, -1, infile);
-    }
+    fatal_with_file_and_line (infile, "missing name or number");
+  if (c == '\n')
+    read_rtx_lineno++;
 
   *p = 0;
 }
@@ -627,7 +899,7 @@ read_rtx (infile)
 {
   register int i, j, list_counter;
   RTX_CODE tmp_code;
-  register char *format_ptr;
+  register const 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.  */
@@ -641,41 +913,39 @@ read_rtx (infile)
   struct rtx_list
     {
       struct rtx_list *next;
-      rtx value;               /* Value of this node...                */
+      rtx value;               /* Value of this node.  */
     };
 
   c = read_skip_spaces (infile); /* Should be open paren.  */
   if (c != '(')
-    dump_and_abort ('(', c, infile);
+    fatal_expected_char (infile, '(', c);
 
   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;
-       }
-    }
+  for (i = 0; i < NUM_RTX_CODE; i++)
+    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);
-    }
+    fatal_with_file_and_line (infile, "unknown rtx code `%s'", tmp_char);
+
   /* (NIL) stands for an expression that isn't there.  */
   if (tmp_code == NIL)
     {
       /* Discard the closeparen.  */
-      while ((c = getc (infile)) && c != ')');
+      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.  */
+  /* If we end up with an insn expression then we free this space below.  */
+  return_rtx = rtx_alloc (tmp_code);
   format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx));
 
   /* If what follows is `: mode ', read it and
@@ -684,13 +954,15 @@ read_rtx (infile)
   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))
+      for (j = 0; j < NUM_MACHINE_MODES; j++)
+       if (! strcmp (GET_MODE_NAME (j), tmp_char))
          break;
 
-      PUT_MODE (return_rtx, (enum machine_mode) k );
+      if (j == MAX_MACHINE_MODE)
+       fatal_with_file_and_line (infile, "unknown mode `%s'", tmp_char);
+
+      PUT_MODE (return_rtx, (enum machine_mode) j);
     }
   else
     ungetc (i, infile);
@@ -719,7 +991,7 @@ read_rtx (infile)
            break;
          }
        /* Now process the vector.  */
-  
+
       case 'E':
        {
          register struct rtx_list *next_rtx, *rtx_list_link;
@@ -727,7 +999,7 @@ read_rtx (infile)
 
          c = read_skip_spaces (infile);
          if (c != '[')
-           dump_and_abort ('[', c, infile);
+           fatal_expected_char (infile, '[', c);
 
          /* add expressions to a list, while keeping a count */
          next_rtx = NULL;
@@ -783,11 +1055,13 @@ read_rtx (infile)
              c = read_skip_spaces (infile);
            }
          if (c != '"')
-           dump_and_abort ('"', c, infile);
+           fatal_expected_char (infile, '"', c);
 
          while (1)
            {
              c = getc (infile); /* Read the string  */
+             if (c == '\n')
+               read_rtx_lineno++;
              if (c == '\\')
                {
                  c = getc (infile);    /* Read the string  */
@@ -798,6 +1072,8 @@ read_rtx (infile)
                      obstack_grow (rtl_obstack, "\\n\\t", 4);
                      continue;
                    }
+                 if (c == '\n')
+                   read_rtx_lineno++;
                }
              else if (c == '"')
                break;
@@ -812,7 +1088,7 @@ read_rtx (infile)
            {
              c = read_skip_spaces (infile);
              if (c != ')')
-               dump_and_abort (')', c, infile);
+               fatal_expected_char (infile, ')', c);
            }
          XSTR (return_rtx, i) = stringbuf;
        }
@@ -826,7 +1102,7 @@ read_rtx (infile)
 #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. 
+       /* 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);
@@ -855,71 +1131,138 @@ read_rtx (infile)
 
   c = read_skip_spaces (infile);
   if (c != ')')
-    dump_and_abort (')', c, infile);
+    fatal_expected_char (infile, ')', c);
 
   return return_rtx;
 }
-\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;
+  error ("RTL check: access of elt %d of `%s' with last elt %d",
+        n, GET_RTX_NAME (GET_CODE (r)), GET_RTX_LENGTH (GET_CODE (r))-1);
+  fancy_abort (file, line, func);
+}
 
-  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;
+{
+  error ("RTL check: expected elt %d type '%c', have '%c' (rtx %s)",
+        n, c1, GET_RTX_FORMAT (GET_CODE (r))[n], GET_RTX_NAME (GET_CODE (r)));
+  fancy_abort (file, line, func);
+}
 
-#ifdef EXTRA_CC_MODES
-  for (i = (int) CCmode + 1; i < (int) MAX_MACHINE_MODE; i++)
-    {
-      mode_class[i] = MODE_CC;
-      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;
-    }
+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;
+{
+  error ("RTL check: expected elt %d type '%c' or '%c', have '%c' (rtx %s)",
+        n, c1, c2,
+        GET_RTX_FORMAT (GET_CODE (r))[n], GET_RTX_NAME (GET_CODE(r)));
+  fancy_abort (file, line, func);
+}
+
+void
+rtl_check_failed_code1 (r, code, file, line, func)
+    rtx r;
+    enum rtx_code code;
+    const char *file;
+    int line;
+    const char *func;
+{
+  error ("RTL check: expected code `%s', have `%s'",
+        GET_RTX_NAME (code), GET_RTX_NAME (GET_CODE (r)));
+  fancy_abort (file, line, func);
+}
+
+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;
+{
+  error ("RTL check: expected code `%s' or `%s', have `%s'",
+        GET_RTX_NAME (code1), GET_RTX_NAME (code2),
+        GET_RTX_NAME (GET_CODE (r)));
+  fancy_abort (file, line, func);
+}
+
+/* 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;
+{
+  error ("RTL check: access of elt %d of vector with last elt %d",
+        n, GET_NUM_ELEM (r)-1);
+  fancy_abort (file, line, func);
+}
+#endif /* ENABLE_RTL_CHECKING */
+
+/* These are utility functions used by fatal-error functions all over the
+   code.  rtl.c happens to be linked by all the programs that need them,
+   so these are here.  In the future we want to break out all error handling
+   to its own module.  */
+
+/* Given a partial pathname as input, return another pathname that
+   shares no directory elements with the pathname of __FILE__.  This
+   is used by fancy_abort() to print `Internal compiler error in expr.c'
+   instead of `Internal compiler error in ../../egcs/gcc/expr.c'.  */
+static const char *
+trim_filename (name)
+     const char *name;
+{
+  static const char this_file[] = __FILE__;
+  const char *p = name, *q = this_file;
+
+  while (*p == *q && *p != 0 && *q != 0) p++, q++;
+  while (p > name && p[-1] != DIR_SEPARATOR
+#ifdef DIR_SEPARATOR_2
+        && p[-1] != DIR_SEPARATOR_2
 #endif
+        )
+    p--;
 
-  /* Find the narrowest mode for each class.  */
+  return p;
+}
 
-  for (i = 0; i < (int) MAX_MODE_CLASS; i++)
-    min_class_size[i] = 1000;
+/* Report an internal compiler error in a friendly manner and without
+   dumping core.  */
 
-  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);
-       }
-    }
+void
+fancy_abort (file, line, function)
+     const char *file;
+     int line;
+     const char *function;
+{
+  if (function == NULL)
+    function = "?";
+  fatal (
+"Internal compiler error in `%s', at %s:%d\n\
+Please submit a full bug report.\n\
+See %s for instructions.",
+        function, trim_filename (file), line, GCCBUGURL);
 }