Initial revision
authorJim Wilson <wilson@gcc.gnu.org>
Fri, 6 Dec 1991 21:00:31 +0000 (13:00 -0800)
committerJim Wilson <wilson@gcc.gnu.org>
Fri, 6 Dec 1991 21:00:31 +0000 (13:00 -0800)
From-SVN: r104

gcc/rtl.c [new file with mode: 0644]
gcc/rtl.h [new file with mode: 0644]

diff --git a/gcc/rtl.c b/gcc/rtl.c
new file mode 100644 (file)
index 0000000..e623f63
--- /dev/null
+++ b/gcc/rtl.c
@@ -0,0 +1,819 @@
+/* Allocate and read RTL for GNU C Compiler.
+   Copyright (C) 1987-1991 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+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.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#include "config.h"
+#include <ctype.h>
+#include <stdio.h>
+#include "rtl.h"
+
+#include "obstack.h"
+#define        obstack_chunk_alloc     xmalloc
+#define        obstack_chunk_free      free
+extern int xmalloc ();
+extern void 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;
+
+extern long ftell();
+\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.  */
+
+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)   NAME ,
+
+char *rtx_name[] = {
+#include "rtl.def"             /* rtl expressions are documented here */
+};
+
+#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] = {
+#include "machmode.def"
+
+#ifdef EXTRA_CC_MODES
+  EXTRA_CC_NAMES
+#endif
+
+};
+
+#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)  \
+  (enum machine_mode) WIDER,
+
+enum machine_mode mode_wider_mode[(int) MAX_MACHINE_MODE] = {
+#include "machmode.def"                /* machine modes are documented here */
+};
+
+#undef DEF_MACHMODE
+
+/* 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 charcter describes one operand.  */
+
+char *rtx_format[] = {
+  /* "*" undefined.
+         can cause a warning message
+     "0" field is unused (or used in a phase-dependent manner)
+         prints nothing
+     "i" an integer
+         prints the integer
+     "n" like "i", but prints entries from `note_insn_name'
+     "s" a pointer to a string
+         prints the string
+     "S" like "s", but optional:
+        the containing rtx may end before this operand
+     "e" a pointer to an rtl expression
+         prints the expression
+     "E" a pointer to a vector that points to a number of rtl expressions
+         prints a list of the rtl expressions
+     "V" like "E", but optional:
+        the containing rtx may end before this operand
+     "u" a pointer to another insn
+         prints the uid of the insn.  */
+
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   FORMAT ,
+#include "rtl.def"             /* rtl expressions are defined here */
+#undef DEF_RTL_EXPR
+};
+
+/* 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, 
+#include "rtl.def"             /* rtl expressions are defined here */
+#undef DEF_RTL_EXPR
+};
+
+/* Names for kinds of NOTEs and REG_NOTEs.  */
+
+char *note_insn_name[] = { "NOTE_INSN_FUNCTION_BEG", "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" };
+
+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" };
+
+/* Allocate an rtx vector of N elements.
+   Store the length, and initialize all elements to zero.  */
+
+rtvec
+rtvec_alloc (n)
+     int n;
+{
+  rtvec rt;
+  int i;
+
+  rt = (rtvec) obstack_alloc (rtl_obstack,
+                             sizeof (struct rtvec_def)
+                             + (( n - 1) * sizeof (rtunion)));
+
+  /* clear out the vector */
+  PUT_NUM_ELEM(rt, n);
+  for (i=0; i < n; i++)
+    rt->elem[i].rtvec = NULL;  /* @@ not portable due to rtunion */
+
+  return rt;
+}
+
+/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
+   all the rest is initialized to zero.  */
+
+rtx
+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;
+
+  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;
+
+  * (int *) rt = 0;
+  PUT_CODE (rt, code);
+
+  return rt;
+}
+\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;
+{
+  register rtx copy;
+  register int i, j;
+  register RTX_CODE code;
+  register char *format_ptr;
+
+  code = GET_CODE (orig);
+
+  switch (code)
+    {
+    case REG:
+    case QUEUED:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+    case CODE_LABEL:
+    case PC:
+    case CC0:
+      return 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;
+  
+  format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
+
+  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); 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 '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_rtx (XVECEXP (orig, i, j));
+           }
+         break;
+
+       default:
+         XINT (copy, i) = XINT (orig, i);
+         break;
+       }
+    }
+  return copy;
+}
+
+/* Similar to `copy_rtx' except that if MAY_SHARE is present, it is
+   placed in the result directly, rather than being copied.  */
+
+rtx
+copy_most_rtx (orig, may_share)
+     register rtx orig;
+     register rtx may_share;
+{
+  register rtx copy;
+  register int i, j;
+  register RTX_CODE code;
+  register char *format_ptr;
+
+  if (orig == may_share)
+    return orig;
+
+  code = GET_CODE (orig);
+
+  switch (code)
+    {
+    case REG:
+    case QUEUED:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+    case CODE_LABEL:
+    case PC:
+    case CC0:
+      return 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;
+  
+  format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
+
+  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
+    {
+      switch (*format_ptr++)
+       {
+       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);
+         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);
+           }
+         break;
+
+       default:
+         XINT (copy, i) = XINT (orig, i);
+         break;
+       }
+    }
+  return copy;
+}
+\f
+/* Helper functions for instruction scheduling.  */
+
+/* Add ELEM wrapped in an INSN_LIST with reg note kind DEP_TYPE to the
+   LOG_LINKS of INSN, if not already there.  DEP_TYPE indicates the type
+   of dependence that this link represents.  */
+
+void
+add_dependence (insn, elem, dep_type)
+     rtx insn;
+     rtx elem;
+     enum reg_note dep_type;
+{
+  rtx link;
+
+  /* Don't depend an insn on itself.  */
+  if (insn == elem)
+    return;
+
+  /* If elem is part of a sequence that must be scheduled together, then
+     make the dependence point to the last insn of the sequence.  */
+  if (NEXT_INSN (elem) && SCHED_GROUP_P (NEXT_INSN (elem)))
+    {
+      while (NEXT_INSN (elem) && SCHED_GROUP_P (NEXT_INSN (elem)))
+       elem = NEXT_INSN (elem);
+      /* Again, don't depend an insn of itself.  */
+      if (insn == elem)
+       return;
+    }
+
+  /* Check that we don't already have this dependence.  */
+  for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
+    if (XEXP (link, 0) == elem)
+      {
+       /* If this is a more restrictive type of dependence than the existing
+          one, then change the existing dependence to this type.  */
+       if (dep_type < REG_NOTE_KIND (link))
+         PUT_REG_NOTE_KIND (link, dep_type);
+       return;
+      }
+  /* Might want to check one level of transitivity to save conses.  */
+
+  link = rtx_alloc (INSN_LIST);
+  /* Insn dependency, not data dependency.  */
+  PUT_REG_NOTE_KIND (link, dep_type);
+  XEXP (link, 0) = elem;
+  XEXP (link, 1) = LOG_LINKS (insn);
+  LOG_LINKS (insn) = link;
+}
+
+/* Remove ELEM wrapped in an INSN_LIST from the LOG_LINKS
+   of INSN.  Abort if not found.  */
+void
+remove_dependence (insn, elem)
+     rtx insn;
+     rtx elem;
+{
+  rtx prev, link;
+  int found = 0;
+
+  for (prev = 0, link = LOG_LINKS (insn); link;
+       prev = link, link = XEXP (link, 1))
+    {
+      if (XEXP (link, 0) == elem)
+       {
+         if (prev)
+           XEXP (prev, 1) = XEXP (link, 1);
+         else
+           LOG_LINKS (insn) = XEXP (link, 1);
+         found = 1;
+       }
+    }
+
+  if (! found)
+    abort ();
+  return;
+}
+\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;
+{
+  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 ();
+}
+
+/* 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;
+{
+  register int c;
+  while (c = getc (infile))
+    {
+      if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
+       ;
+      else if (c == ';')
+       {
+         while ((c = getc (infile)) && c != '\n') ;
+       }
+      else if (c == '/')
+       {
+         register int prevc;
+         c = getc (infile);
+         if (c != '*')
+           dump_and_abort ('*', c, infile);
+         
+         prevc = 0;
+         while (c = getc (infile))
+           {
+             if (prevc == '*' && c == '/')
+               break;
+             prevc = c;
+           }
+       }
+      else break;
+    }
+  return c;
+}
+
+/* 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;
+{
+  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;
+}
+\f
+/* 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;
+{
+  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;
+
+  /* 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;
+
+         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)
+                                 : (struct rtvec_def *) NULL);
+         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;
+         int stringbufsize;
+
+         c = read_skip_spaces (infile);
+         if (c == '(')
+           {
+             saw_paren = 1;
+             c = read_skip_spaces (infile);
+           }
+         if (c != '"')
+           dump_and_abort ('"', c, infile);
+         j = 0;
+         stringbufsize = 10;
+         stringbuf = (char *) xmalloc (stringbufsize + 1);
+
+         while (1)
+           {
+             if (j >= stringbufsize - 4)
+               {
+                 stringbufsize *= 2;
+                 stringbuf = (char *) xrealloc (stringbuf, stringbufsize + 1);
+               }
+             stringbuf[j] = getc (infile); /* Read the string  */
+             if (stringbuf[j] == '\\')
+               {
+                 stringbuf[j] = getc (infile); /* Read the string  */
+                 /* \; makes stuff for a C string constant containing
+                    newline and tab.  */
+                 if (stringbuf[j] == ';')
+                   {
+                     strcpy (&stringbuf[j], "\\n\\t");
+                     j += 3;
+                   }
+               }
+             else if (stringbuf[j] == '"')
+               break;
+             j++;
+           }
+
+         stringbuf[j] = 0;     /* NUL terminate the string  */
+         stringbuf = (char *) xrealloc (stringbuf, j + 1);
+
+         if (saw_paren)
+           {
+             c = read_skip_spaces (infile);
+             if (c != ')')
+               dump_and_abort (')', c, infile);
+           }
+         XSTR (return_rtx, i) = stringbuf;
+       }
+       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;
+}
+\f
+/* This is called once per compilation, before any rtx's are constructed.
+   It initializes the vector `rtx_length' and the extra CC modes, if any.  */
+
+void
+init_rtl ()
+{
+  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 `i's as we now have elements.  */
+      for (i = 0; i < rtx_length[(int) CONST_DOUBLE]; i++)
+       *s++ = 'i';
+      *s++ = 0;
+    }
+#endif
+
+#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] = (enum machine_mode) i;
+      mode_wider_mode[i] = VOIDmode;
+    }
+#endif
+}
diff --git a/gcc/rtl.h b/gcc/rtl.h
new file mode 100644 (file)
index 0000000..fb5a14a
--- /dev/null
+++ b/gcc/rtl.h
@@ -0,0 +1,748 @@
+/* Register Transfer Language (RTL) definitions for GNU C-Compiler
+   Copyright (C) 1987-1991 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+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.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#include "machmode.h"
+
+#undef FFS  /* Some systems predefine this symbol; don't let it interfere.  */
+
+/* Register Transfer Language EXPRESSIONS CODES */
+
+#define RTX_CODE       enum rtx_code
+enum rtx_code  {
+
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   ENUM ,
+#include "rtl.def"             /* rtl expressions are documented here */
+#undef DEF_RTL_EXPR
+
+  LAST_AND_UNUSED_RTX_CODE};   /* A convienent way to get a value for
+                                  NUM_RTX_CODE.
+                                  Assumes default enum value assignement.  */
+
+#define NUM_RTX_CODE ((int)LAST_AND_UNUSED_RTX_CODE)
+                               /* The cast here, saves many elsewhere.  */
+
+extern int rtx_length[];
+#define GET_RTX_LENGTH(CODE)           (rtx_length[(int)(CODE)])
+
+extern char *rtx_name[];
+#define GET_RTX_NAME(CODE)             (rtx_name[(int)(CODE)])
+
+extern char *rtx_format[];
+#define GET_RTX_FORMAT(CODE)           (rtx_format[(int)(CODE)])
+
+extern char rtx_class[];
+#define GET_RTX_CLASS(CODE)            (rtx_class[(int)(CODE)])
+\f
+/* Common union for an element of an rtx.  */
+
+typedef union rtunion_def
+{
+  int rtint;
+  char *rtstr;
+  struct rtx_def *rtx;
+  struct rtvec_def *rtvec;
+  enum machine_mode rttype;
+} rtunion;
+
+/* RTL expression ("rtx").  */
+
+typedef struct rtx_def
+{
+#ifdef ONLY_INT_FIELDS
+  unsigned short code;
+#else
+  /* The kind of expression this is.  */
+  enum rtx_code code : 16;
+#endif
+  /* The kind of value the expression has.  */
+#ifdef ONLY_INT_FIELDS
+  int mode : 8;
+#else
+  enum machine_mode mode : 8;
+#endif
+  /* 1 in an INSN if it can alter flow of control
+     within this function.  Not yet used!  */
+  unsigned int jump : 1;
+  /* 1 in an INSN if it can call another function.  Not yet used!  */
+  unsigned int call : 1;
+  /* 1 in a MEM or REG if value of this expression will never change
+     during the current function, even though it is not
+     manifestly constant.
+     1 in a SYMBOL_REF if it addresses something in the per-function
+     constants pool.
+     1 in a CALL_INSN if it is a const call.
+     1 in a JUMP_INSN if it is a branch that should be annulled.  Valid from
+     reorg until end of compilation; cleared before used.  */
+  unsigned int unchanging : 1;
+  /* 1 in a MEM expression if contents of memory are volatile.
+     1 in an INSN, CALL_INSN, JUMP_INSN, CODE_LABEL or BARRIER
+     if it is deleted.
+     1 in a REG expression if corresponds to a variable declared by the user.
+     0 for an internally generated temporary.
+     In a SYMBOL_REF, this flag is used for machine-specific purposes.  */
+  unsigned int volatil : 1;
+  /* 1 in a MEM referring to a field of a structure (not a union!).
+     0 if the MEM was a variable or the result of a * operator in C;
+     1 if it was the result of a . or -> operator (on a struct) in C.
+     1 in a REG if the register is used only in exit code a loop.
+     1 in a CODE_LABEL if the label is used for nonlocal gotos
+     and must not be deleted even if its count is zero.
+     1 in a LABEL_REF if this is a reference to a label outside the
+     current loop.
+     1 in an INSN, JUMP_INSN, or CALL_INSN if this insn must be scheduled
+     together with the preceeding insn.  Valid only within sched.
+     1 in an INSN, JUMP_INSN, or CALL_INSN if insn is in a delay slot and
+     from the target of a branch.  Valid from reorg until end of compilation;
+     cleared before used.  */
+  unsigned int in_struct : 1;
+  /* 1 if this rtx is used.  This is used for copying shared structure.
+     See `unshare_all_rtl'.
+     In a REG, this is not needed for that purpose, and used instead 
+     in `leaf_renumber_regs_insn'.
+     In a SYMBOL_REF, means that emit_library_call
+     has used it as the function.  */
+  unsigned int used : 1;
+  /* Nonzero if this rtx came from procedure integration.
+     In a REG, nonzero means this reg refers to the return value
+     of the current function.  */
+  unsigned integrated : 1;
+  /* The first element of the operands of this rtx.
+     The number of operands and their types are controlled
+     by the `code' field, according to rtl.def.  */
+  rtunion fld[1];
+} *rtx;
+
+#define NULL_RTX (rtx) 0
+
+/* Define macros to access the `code' field of the rtx.  */
+
+#ifdef SHORT_ENUM_BUG
+#define GET_CODE(RTX)          ((enum rtx_code) ((RTX)->code))
+#define PUT_CODE(RTX, CODE)    ((RTX)->code = ((short) (CODE)))
+#else
+#define GET_CODE(RTX)          ((RTX)->code)
+#define PUT_CODE(RTX, CODE)    ((RTX)->code = (CODE))
+#endif
+
+#define GET_MODE(RTX)          ((RTX)->mode)
+#define PUT_MODE(RTX, MODE)    ((RTX)->mode = (MODE))
+
+#define RTX_INTEGRATED_P(RTX) ((RTX)->integrated)
+#define RTX_UNCHANGING_P(RTX) ((RTX)->unchanging)
+
+/* RTL vector.  These appear inside RTX's when there is a need
+   for a variable number of things.  The principle use is inside
+   PARALLEL expressions.  */
+
+typedef struct rtvec_def{
+  unsigned num_elem;           /* number of elements */
+  rtunion elem[1];
+} *rtvec;
+
+#define NULL_RTVEC (rtvec) 0
+
+#define GET_NUM_ELEM(RTVEC)            ((RTVEC)->num_elem)
+#define PUT_NUM_ELEM(RTVEC, NUM)       ((RTVEC)->num_elem = (unsigned) NUM)
+
+#define RTVEC_ELT(RTVEC, I)  ((RTVEC)->elem[(I)].rtx)
+
+/* 1 if X is a REG.  */
+
+#define REG_P(X) (GET_CODE (X) == REG)
+
+/* 1 if X is a constant value that is an integer.  */
+
+#define CONSTANT_P(X)   \
+  (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF             \
+   || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE                \
+   || GET_CODE (X) == CONST || GET_CODE (X) == HIGH)
+
+/* General accessor macros for accessing the fields of an rtx.  */
+
+#define XEXP(RTX, N)   ((RTX)->fld[N].rtx)
+#define XINT(RTX, N)   ((RTX)->fld[N].rtint)
+#define XSTR(RTX, N)   ((RTX)->fld[N].rtstr)
+#define XVEC(RTX, N)   ((RTX)->fld[N].rtvec)
+#define XVECLEN(RTX, N)        ((RTX)->fld[N].rtvec->num_elem)
+#define XVECEXP(RTX,N,M)((RTX)->fld[N].rtvec->elem[M].rtx)
+\f
+/* ACCESS MACROS for particular fields of insns.  */
+
+/* Holds a unique number for each insn.
+   These are not necessarily sequentially increasing.  */
+#define INSN_UID(INSN) ((INSN)->fld[0].rtint)
+
+/* Chain insns together in sequence.  */
+#define PREV_INSN(INSN)        ((INSN)->fld[1].rtx)
+#define NEXT_INSN(INSN)        ((INSN)->fld[2].rtx)
+
+/* The body of an insn.  */
+#define PATTERN(INSN)  ((INSN)->fld[3].rtx)
+
+/* Code number of instruction, from when it was recognized.
+   -1 means this instruction has not been recognized yet.  */
+#define INSN_CODE(INSN) ((INSN)->fld[4].rtint)
+
+/* Set up in flow.c; empty before then.
+   Holds a chain of INSN_LIST rtx's whose first operands point at
+   previous insns with direct data-flow connections to this one.
+   That means that those insns set variables whose next use is in this insn.
+   They are always in the same basic block as this insn.  */
+#define LOG_LINKS(INSN)                ((INSN)->fld[5].rtx)
+
+/* 1 if insn has been deleted.  */
+#define INSN_DELETED_P(INSN) ((INSN)->volatil)
+
+/* 1 if insn is a call to a const function.  */
+#define CONST_CALL_P(INSN) ((INSN)->unchanging)
+
+/* 1 if insn is a branch that should not unconditionally execute its
+   delay slots, i.e., it is an annulled branch.   */
+#define INSN_ANNULLED_BRANCH_P(INSN) ((INSN)->unchanging)
+
+/* 1 if insn is in a delay slot and is from the target of the branch.  If
+   the branch insn has INSN_ANULLED_BRANCH_P set, this insn should only be
+   executed if the branch is taken.  For annulled branches with this bit
+   clear, the insn should be executed only if the branch is not taken.  */
+#define INSN_FROM_TARGET_P(INSN) ((INSN)->in_struct)
+
+/* Holds a list of notes on what this insn does to various REGs.
+   It is a chain of EXPR_LIST rtx's, where the second operand
+   is the chain pointer and the first operand is the REG being described.
+   The mode field of the EXPR_LIST contains not a real machine mode
+   but a value that says what this note says about the REG:
+     REG_DEAD means that the value in REG dies in this insn (i.e., it is
+   not needed past this insn).  If REG is set in this insn, the REG_DEAD
+   note may, but need not, be omitted.
+     REG_INC means that the REG is autoincremented or autodecremented.
+     REG_EQUIV describes the insn as a whole; it says that the
+   insn sets a register to a constant value or to be equivalent to
+   a memory address.  If the
+   register is spilled to the stack then the constant value
+   should be substituted for it.  The contents of the REG_EQUIV
+   is the constant value or memory address, which may be different
+   from the source of the SET although it has the same value. 
+     REG_EQUAL is like REG_EQUIV except that the destination
+   is only momentarily equal to the specified rtx.  Therefore, it
+   cannot be used for substitution; but it can be used for cse.
+     REG_RETVAL means that this insn copies the return-value of
+   a library call out of the hard reg for return values.  This note
+   is actually an INSN_LIST and it points to the first insn involved
+   in setting up arguments for the call.  flow.c uses this to delete
+   the entire library call when its result is dead.
+     REG_LIBCALL is the inverse of REG_RETVAL: it goes on the first insn
+   of the library call and points at the one that has the REG_RETVAL.
+     REG_WAS_0 says that the register set in this insn held 0 before the insn.
+   The contents of the note is the insn that stored the 0.
+   If that insn is deleted or patched to a NOTE, the REG_WAS_0 is inoperative.
+   The REG_WAS_0 note is actually an INSN_LIST, not an EXPR_LIST.
+     REG_NONNEG means that the register is always nonnegative during
+   the containing loop.  This is used in branches so that decrement and
+   branch instructions terminating on zero can be matched.  There must be
+   an insn pattern in the md file named `decrement_and_branch_until_zero'
+   or else this will never be added to any instructions.
+     REG_NO_CONFLICT means there is no conflict *after this insn*
+   between the register in the note and the destination of this insn.
+     REG_UNUSED identifies a register set in this insn and never used.
+     REG_CC_SETTER and REG_CC_USER link a pair of insns that set and use
+   CC0, respectively.  Normally, these are required to be consecutive insns,
+   but we permit putting a cc0-setting insn in the delay slot of a branch
+   as long as only one copy of the insn exists.  In that case, these notes
+   point from one to the other to allow code generation to determine what
+   any require information and to properly update CC_STATUS.
+     REG_LABEL points to a CODE_LABEL.  Used by non-JUMP_INSNs to
+   say that the CODE_LABEL contained in the REG_LABEL note is used
+   by the insn.
+    REG_DEP_ANTI is used in LOG_LINKS which represent anti (write after read)
+   dependencies.  REG_DEP_OUTPUT is used in LOG_LINKS which represent output
+   (write after write) dependencies.  Data dependencies, which are the only
+   type of LOG_LINK created by flow, are represented by a 0 reg note kind.  */
+
+#define REG_NOTES(INSN)        ((INSN)->fld[6].rtx)
+
+/* Don't forget to change reg_note_name in rtl.c.  */
+enum reg_note { REG_DEAD = 1, REG_INC = 2, REG_EQUIV = 3, REG_WAS_0 = 4,
+               REG_EQUAL = 5, REG_RETVAL = 6, REG_LIBCALL = 7,
+               REG_NONNEG = 8, REG_NO_CONFLICT = 9, REG_UNUSED = 10,
+               REG_CC_SETTER = 11, REG_CC_USER = 12, REG_LABEL = 13,
+               REG_DEP_ANTI = 14, REG_DEP_OUTPUT = 15 };
+
+/* Define macros to extract and insert the reg-note kind in an EXPR_LIST.  */
+#define REG_NOTE_KIND(LINK) ((enum reg_note) GET_MODE (LINK))
+#define PUT_REG_NOTE_KIND(LINK,KIND) PUT_MODE(LINK, (enum machine_mode) (KIND))
+
+/* Names for REG_NOTE's in EXPR_LIST insn's.  */
+
+extern char *reg_note_name[];
+#define GET_REG_NOTE_NAME(MODE) (reg_note_name[(int)(MODE)])
+
+/* The label-number of a code-label.  The assembler label
+   is made from `L' and the label-number printed in decimal.
+   Label numbers are unique in a compilation.  */
+#define CODE_LABEL_NUMBER(INSN)        ((INSN)->fld[3].rtint)
+
+#define LINE_NUMBER NOTE
+
+/* In a NOTE that is a line number, this is a string for the file name
+   that the line is in.  */
+
+#define NOTE_SOURCE_FILE(INSN)  ((INSN)->fld[3].rtstr)
+
+/* In a NOTE that is a line number, this is the line number.
+   Other kinds of NOTEs are identified by negative numbers here.  */
+#define NOTE_LINE_NUMBER(INSN) ((INSN)->fld[4].rtint)
+
+/* Codes that appear in the NOTE_LINE_NUMBER field
+   for kinds of notes that are not line numbers.  */
+
+/* This note indicates the end of the real body of the function,
+   after moving the parms into their homes, etc.  */
+#define NOTE_INSN_FUNCTION_BEG 0
+
+/* This note is used to get rid of an insn
+   when it isn't safe to patch the insn out of the chain.  */
+#define NOTE_INSN_DELETED -1
+#define NOTE_INSN_BLOCK_BEG -2
+#define NOTE_INSN_BLOCK_END -3
+#define NOTE_INSN_LOOP_BEG -4
+#define NOTE_INSN_LOOP_END -5
+/* This kind of note is generated at the end of the function body,
+   just before the return insn or return label.
+   In an optimizing compilation it is deleted by the first jump optimization,
+   after enabling that optimizer to determine whether control can fall
+   off the end of the function body without a return statement.  */
+#define NOTE_INSN_FUNCTION_END -6
+/* This kind of note is generated just after each call to `setjmp', et al.  */
+#define NOTE_INSN_SETJMP -7
+/* Generated at the place in a loop that `continue' jumps to.  */
+#define NOTE_INSN_LOOP_CONT -8
+/* Generated at the start of a duplicated exit test.  */
+#define NOTE_INSN_LOOP_VTOP -9
+/* Don't forget to change note_insn_name in rtl.c.  */
+
+#define NOTE_DECL_NAME(INSN) ((INSN)->fld[3].rtstr)
+#define NOTE_DECL_CODE(INSN) ((INSN)->fld[4].rtint)
+#define NOTE_DECL_RTL(INSN) ((INSN)->fld[5].rtx)
+#define NOTE_DECL_IDENTIFIER(INSN) ((INSN)->fld[6].rtint)
+#define NOTE_DECL_TYPE(INSN) ((INSN)->fld[7].rtint)
+
+/* Names for NOTE insn's other than line numbers.  */
+
+extern char *note_insn_name[];
+#define GET_NOTE_INSN_NAME(NOTE_CODE) (note_insn_name[-(NOTE_CODE)])
+
+/* The name of a label, in case it corresponds to an explicit label
+   in the input source code.  */
+#define LABEL_NAME(LABEL) ((LABEL)->fld[4].rtstr)
+
+/* In jump.c, each label contains a count of the number
+   of LABEL_REFs that point at it, so unused labels can be deleted.  */
+#define LABEL_NUSES(LABEL) ((LABEL)->fld[5].rtint)
+
+/* In jump.c, each JUMP_INSN can point to a label that it can jump to,
+   so that if the JUMP_INSN is deleted, the label's LABEL_NUSES can
+   be decremented and possibly the label can be deleted.  */
+#define JUMP_LABEL(INSN)   ((INSN)->fld[7].rtx)
+
+/* Once basic blocks are found in flow.c,
+   each CODE_LABEL starts a chain that goes through
+   all the LABEL_REFs that jump to that label.
+   The chain eventually winds up at the CODE_LABEL; it is circular.  */
+#define LABEL_REFS(LABEL) ((LABEL)->fld[5].rtx)
+\f
+/* This is the field in the LABEL_REF through which the circular chain
+   of references to a particular label is linked.
+   This chain is set up in flow.c.  */
+
+#define LABEL_NEXTREF(REF) ((REF)->fld[1].rtx)
+
+/* Once basic blocks are found in flow.c,
+   Each LABEL_REF points to its containing instruction with this field.  */
+
+#define CONTAINING_INSN(RTX) ((RTX)->fld[2].rtx)
+
+/* For a REG rtx, REGNO extracts the register number.  */
+
+#define REGNO(RTX) ((RTX)->fld[0].rtint)
+
+/* For a REG rtx, REG_FUNCTION_VALUE_P is nonzero if the reg
+   is the current function's return value.  */
+
+#define REG_FUNCTION_VALUE_P(RTX) ((RTX)->integrated)
+
+/* 1 in a REG rtx if it corresponds to a variable declared by the user.  */
+#define REG_USERVAR_P(RTX) ((RTX)->volatil)
+
+/* For a CONST_INT rtx, INTVAL extracts the integer.  */
+
+#define INTVAL(RTX) ((RTX)->fld[0].rtint)
+
+/* For a SUBREG rtx, SUBREG_REG extracts the value we want a subreg of.
+   SUBREG_WORD extracts the word-number.  */
+
+#define SUBREG_REG(RTX) ((RTX)->fld[0].rtx)
+#define SUBREG_WORD(RTX) ((RTX)->fld[1].rtint)
+
+/* Access various components of an ASM_OPERANDS rtx.  */
+
+#define ASM_OPERANDS_TEMPLATE(RTX) XSTR ((RTX), 0)
+#define ASM_OPERANDS_OUTPUT_CONSTRAINT(RTX) XSTR ((RTX), 1)
+#define ASM_OPERANDS_OUTPUT_IDX(RTX) XINT ((RTX), 2)
+#define ASM_OPERANDS_INPUT_VEC(RTX) XVEC ((RTX), 3)
+#define ASM_OPERANDS_INPUT_CONSTRAINT_VEC(RTX) XVEC ((RTX), 4)
+#define ASM_OPERANDS_INPUT(RTX, N) XVECEXP ((RTX), 3, (N))
+#define ASM_OPERANDS_INPUT_LENGTH(RTX) XVECLEN ((RTX), 3)
+#define ASM_OPERANDS_INPUT_CONSTRAINT(RTX, N) XSTR (XVECEXP ((RTX), 4, (N)), 0)
+#define ASM_OPERANDS_INPUT_MODE(RTX, N) GET_MODE (XVECEXP ((RTX), 4, (N)))
+#define ASM_OPERANDS_SOURCE_FILE(RTX) XSTR ((RTX), 5)
+#define ASM_OPERANDS_SOURCE_LINE(RTX) XINT ((RTX), 6)
+
+/* For a MEM rtx, 1 if it's a volatile reference.
+   Also in an ASM_OPERANDS rtx.  */
+#define MEM_VOLATILE_P(RTX) ((RTX)->volatil)
+
+/* For a MEM rtx, 1 if it refers to a structure or union component.  */
+#define MEM_IN_STRUCT_P(RTX) ((RTX)->in_struct)
+
+/* For a LABEL_REF, 1 means that this reference is to a label outside the
+   loop containing the reference.  */
+#define LABEL_OUTSIDE_LOOP_P(RTX) ((RTX)->in_struct)
+
+/* For a CODE_LABEL, 1 means always consider this label to be needed.  */
+#define LABEL_PRESERVE_P(RTX) ((RTX)->in_struct)
+
+/* For a REG, 1 means the register is used only in an exit test of a loop.  */
+#define REG_LOOP_TEST_P(RTX) ((RTX)->in_struct)
+
+/* During sched, for an insn, 1 means that the insn must be scheduled together
+   with the preceeding insn.  */
+#define SCHED_GROUP_P(INSN) ((INSN)->in_struct)
+
+/* For a SET rtx, SET_DEST is the place that is set
+   and SET_SRC is the value it is set to.  */
+#define SET_DEST(RTX) ((RTX)->fld[0].rtx)
+#define SET_SRC(RTX) ((RTX)->fld[1].rtx)
+
+/* For a TRAP_IF rtx, TRAP_CONDITION is an expression.  */
+#define TRAP_CONDITION(RTX) ((RTX)->fld[0].rtx)
+
+/* 1 in a SYMBOL_REF if it addresses this function's constants pool.  */
+#define CONSTANT_POOL_ADDRESS_P(RTX) ((RTX)->unchanging)
+
+/* Flag in a SYMBOL_REF for machine-specific purposes.  */
+#define SYMBOL_REF_FLAG(RTX) ((RTX)->volatil)
+
+/* 1 means a SYMBOL_REF has been the library function in emit_library_call.  */
+#define SYMBOL_REF_USED(RTX) ((RTX)->used)
+
+/* For an INLINE_HEADER rtx, FIRST_FUNCTION_INSN is the first insn
+   of the function that is not involved in copying parameters to
+   pseudo-registers.  FIRST_PARM_INSN is the very first insn of
+   the function, including the parameter copying.
+   We keep this around in case we must splice
+   this function into the assembly code at the end of the file.
+   FIRST_LABELNO is the first label number used by the function (inclusive).
+   LAST_LABELNO is the last label used by the function (exclusive).
+   MAX_REGNUM is the largest pseudo-register used by that function.
+   FUNCTION_ARGS_SIZE is the size of the argument block in the stack.
+   POPS_ARGS is the number of bytes of input arguments popped by the function
+   STACK_SLOT_LIST is the list of stack slots.
+   FUNCTION_FLAGS are where single-bit flags are saved.
+   OUTGOING_ARGS_SIZE is the size of the largest outgoing stack parameter list.
+   ORIGINAL_ARG_VECTOR is a vector of the original DECL_RTX values
+    for the function arguments.
+   ORIGINAL_DECL_INITIAL is a pointer to the original DECL_INITIAL for the
+    function.
+
+   We want this to lay down like an INSN.  The PREV_INSN field
+   is always NULL.  The NEXT_INSN field always points to the
+   first function insn of the function being squirreled away.  */
+
+#define FIRST_FUNCTION_INSN(RTX) ((RTX)->fld[2].rtx)
+#define FIRST_PARM_INSN(RTX) ((RTX)->fld[3].rtx)
+#define FIRST_LABELNO(RTX) ((RTX)->fld[4].rtint)
+#define LAST_LABELNO(RTX) ((RTX)->fld[5].rtint)
+#define MAX_PARMREG(RTX) ((RTX)->fld[6].rtint)
+#define MAX_REGNUM(RTX) ((RTX)->fld[7].rtint)
+#define FUNCTION_ARGS_SIZE(RTX) ((RTX)->fld[8].rtint)
+#define POPS_ARGS(RTX) ((RTX)->fld[9].rtint)
+#define STACK_SLOT_LIST(RTX) ((RTX)->fld[10].rtx)
+#define FUNCTION_FLAGS(RTX) ((RTX)->fld[11].rtint)
+#define OUTGOING_ARGS_SIZE(RTX) ((RTX)->fld[12].rtint)
+#define ORIGINAL_ARG_VECTOR(RTX) ((RTX)->fld[13].rtvec)
+#define ORIGINAL_DECL_INITIAL(RTX) ((RTX)->fld[14].rtx)
+
+/* In FUNCTION_FLAGS we save some variables computed when emitting the code
+   for the function and which must be `or'ed into the current flag values when
+   insns from that function are being inlined.  */
+
+/* These ought to be an enum, but non-ANSI compilers don't like that.  */
+#define FUNCTION_FLAGS_CALLS_ALLOCA 01
+#define FUNCTION_FLAGS_CALLS_SETJMP 02
+#define FUNCTION_FLAGS_RETURNS_STRUCT 04
+#define FUNCTION_FLAGS_RETURNS_PCC_STRUCT 010
+#define FUNCTION_FLAGS_NEEDS_CONTEXT 020
+#define FUNCTION_FLAGS_HAS_NONLOCAL_LABEL 040
+#define FUNCTION_FLAGS_RETURNS_POINTER 0100
+#define FUNCTION_FLAGS_USES_CONST_POOL 0200
+#define FUNCTION_FLAGS_CALLS_LONGJMP 0400
+#define FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE 01000
+
+/* Define a macro to look for REG_INC notes,
+   but save time on machines where they never exist.  */
+
+#if (defined (HAVE_PRE_INCREMENT) || defined (HAVE_PRE_DECREMENT) \
+     || defined (HAVE_POST_INCREMENT) || defined (HAVE_POST_DECREMENT))
+#define FIND_REG_INC_NOTE(insn, reg) (find_reg_note ((insn), REG_INC, (reg)))
+#else
+#define FIND_REG_INC_NOTE(insn, reg) 0
+#endif
+
+/* Indicate whether the machine has any sort of auto increment addressing.
+   If not, we can avoid checking for REG_INC notes.  */
+
+#if (defined (HAVE_PRE_INCREMENT) || defined (HAVE_PRE_DECREMENT) \
+     || defined (HAVE_POST_INCREMENT) || defined (HAVE_POST_DECREMENT))
+#define AUTO_INC_DEC
+#endif
+\f
+/* Generally useful functions.  */
+
+extern rtx rtx_alloc ();
+extern rtvec rtvec_alloc ();
+extern rtx find_reg_note ();
+extern rtx find_regno_note ();
+extern int get_integer_term ();
+extern rtx get_related_value ();
+extern rtx single_set ();
+extern rtx find_last_value ();
+extern rtx gen_rtx ();
+extern rtx copy_rtx ();
+extern rtx copy_rtx_if_shared ();
+extern rtx copy_most_rtx ();
+extern rtx replace_rtx ();
+extern rtvec gen_rtvec ();
+extern rtvec gen_rtvec_v ();
+extern rtx gen_reg_rtx ();
+extern rtx gen_label_rtx ();
+extern rtx gen_inline_header_rtx ();
+extern rtx gen_lowpart_common ();
+extern rtx gen_lowpart ();
+extern rtx gen_lowpart_if_possible ();
+extern rtx operand_subword ();
+extern rtx operand_subword_force ();
+extern int subreg_lowpart_p ();
+extern rtx make_safe_from ();
+extern rtx memory_address ();
+extern rtx get_insns ();
+extern rtx get_last_insn ();
+extern rtx get_last_insn_anywhere ();
+extern void start_sequence ();
+extern void push_to_sequence ();
+extern void end_sequence ();
+extern rtx gen_sequence ();
+extern rtx expand_expr ();
+extern rtx output_constant_def ();
+extern rtx immed_real_const ();
+extern rtx immed_real_const_1 ();
+extern rtx immed_double_const ();
+extern rtx force_const_mem ();
+extern rtx get_pool_constant ();
+extern enum machine_mode get_pool_mode ();
+extern int get_pool_offset ();
+extern rtx get_parm_real_loc ();
+extern rtx assign_stack_local ();
+extern rtx assign_stack_temp ();
+extern rtx protect_from_queue ();
+extern void emit_queue ();
+extern rtx emit_move_insn ();
+extern rtx emit_insn_before ();
+extern rtx emit_jump_insn_before ();
+extern rtx emit_call_insn_before ();
+extern rtx emit_barrier_before ();
+extern rtx emit_note_before ();
+extern rtx emit_insn_after ();
+extern rtx emit_jump_insn_after ();
+extern rtx emit_barrier_after ();
+extern rtx emit_label_after ();
+extern rtx emit_note_after ();
+extern rtx emit_line_note_after ();
+extern rtx emit_insn ();
+extern rtx emit_insns ();
+extern rtx emit_insns_before ();
+extern rtx emit_jump_insn ();
+extern rtx emit_call_insn ();
+extern rtx emit_label ();
+extern rtx emit_barrier ();
+extern rtx emit_line_note ();
+extern rtx emit_note ();
+extern rtx emit_line_note_force ();
+extern rtx make_insn_raw ();
+extern rtx previous_insn ();
+extern rtx next_insn ();
+extern rtx prev_nonnote_insn ();
+extern rtx next_nonnote_insn ();
+extern rtx prev_real_insn ();
+extern rtx next_real_insn ();
+extern rtx prev_active_insn ();
+extern rtx next_active_insn ();
+extern rtx prev_label ();
+extern rtx next_label ();
+extern rtx next_cc0_user ();
+extern rtx prev_cc0_setter ();
+extern rtx reg_set_last ();
+extern rtx next_nondeleted_insn ();
+extern enum rtx_code reverse_condition ();
+extern enum rtx_code swap_condition ();
+extern enum rtx_code unsigned_condition ();
+extern enum rtx_code signed_condition ();
+extern rtx plus_constant (), plus_constant_for_output ();
+extern rtx find_equiv_reg ();
+extern rtx delete_insn ();
+extern void delete_jump ();
+extern rtx get_label_before ();
+extern rtx get_label_after ();
+extern rtx follow_jumps ();
+extern rtx adj_offsettable_operand ();
+extern rtx try_split ();
+extern rtx split_insns ();
+extern rtx simplify_unary_operation (), simplify_binary_operation ();
+extern rtx simplify_ternary_operation (), simplify_relational_operation ();
+
+/* Maximum number of parallel sets and clobbers in any insn in this fn.
+   Always at least 3, since the combiner could put that many togetherm
+   and we want this to remain correct for all the remaining passes.  */
+
+extern int max_parallel;
+
+extern int asm_noperands ();
+extern char *decode_asm_operands ();
+
+#ifdef BITS_PER_WORD
+/* Conditional is to detect when config.h has been included.  */
+extern enum reg_class reg_preferred_class ();
+#endif
+
+extern rtx get_first_nonparm_insn ();
+
+/* Standard pieces of rtx, to be substituted directly into things.  */
+extern rtx pc_rtx;
+extern rtx cc0_rtx;
+extern rtx const0_rtx;
+extern rtx const1_rtx;
+extern rtx constm1_rtx;
+extern rtx const_true_rtx;
+extern rtx fconst0_rtx;
+extern rtx fconst1_rtx;
+extern rtx dconst0_rtx;
+extern rtx dconst1_rtx;
+
+/* Returns a constant 0 rtx in mode MODE.  */
+
+#define CONST0_RTX(MODE) \
+ ((MODE == SFmode) ? fconst0_rtx                       \
+  : ((MODE == DFmode) ? dconst0_rtx                    \
+     : ((GET_MODE_CLASS (MODE) == MODE_INT) ? const0_rtx       \
+        : (abort (), NULL_RTX))))
+
+/* All references to certain hard regs, except those created
+   by allocating pseudo regs into them (when that's possible),
+   go through these unique rtx objects.  */
+extern rtx stack_pointer_rtx;
+extern rtx frame_pointer_rtx;
+extern rtx arg_pointer_rtx;
+extern rtx pic_offset_table_rtx;
+extern rtx struct_value_rtx;
+extern rtx struct_value_incoming_rtx;
+extern rtx static_chain_rtx;
+extern rtx static_chain_incoming_rtx;
+
+/* Virtual registers are used during RTL generation to refer to locations into
+   the stack frame when the actual location isn't known until RTL generation
+   is complete.  The routine instantiate_virtual_regs replaces these with
+   the proper value, which is normally {frame,arg,stack}_pointer_rtx plus
+   a constant.  */
+
+#define FIRST_VIRTUAL_REGISTER (FIRST_PSEUDO_REGISTER)
+
+/* This points to the first word of the incoming arguments passed on the stack,
+   either by the caller or by the callee when pretending it was passed by the
+   caller.  */
+
+extern rtx virtual_incoming_args_rtx;
+
+#define VIRTUAL_INCOMING_ARGS_REGNUM   (FIRST_VIRTUAL_REGISTER)
+
+/* If FRAME_GROWS_DOWNWARDS, this points to immediately above the first
+   variable on the stack.  Otherwise, it points to the first variable on
+   the stack.  */
+
+extern rtx virtual_stack_vars_rtx;
+
+#define VIRTUAL_STACK_VARS_REGNUM      ((FIRST_VIRTUAL_REGISTER) + 1)
+
+/* This points to the location of dynamically-allocated memory on the stack
+   immediately after the stack pointer has been adjusted by the amount
+   desired.  */
+
+extern rtx virtual_stack_dynamic_rtx;
+
+#define VIRTUAL_STACK_DYNAMIC_REGNUM   ((FIRST_VIRTUAL_REGISTER) + 2)
+
+/* This points to the location in the stack at which outgoing arguments should
+   be written when the stack is pre-pushed (arguments pushed using push
+   insns always use sp).  */
+
+extern rtx virtual_outgoing_args_rtx;
+
+#define VIRTUAL_OUTGOING_ARGS_REGNUM   ((FIRST_VIRTUAL_REGISTER) + 3)
+
+#define LAST_VIRTUAL_REGISTER  ((FIRST_VIRTUAL_REGISTER) + 3)
+
+extern rtx find_next_ref ();
+extern rtx *find_single_use ();
+
+/* Define a default value for STORE_FLAG_VALUE.  */
+
+#ifndef STORE_FLAG_VALUE
+#define STORE_FLAG_VALUE 1
+#endif
+
+/* Nonzero after end of reload pass.
+   Set to 1 or 0 by toplev.c.  */
+
+extern int reload_completed;
+
+/* Set to 1 while reload_as_needed is operating.
+   Required by some machines to handle any generated moves differently.  */
+
+extern int reload_in_progress;
+
+/* If this is nonzero, we do not bother generating VOLATILE
+   around volatile memory references, and we are willing to
+   output indirect addresses.  If cse is to follow, we reject
+   indirect addresses so a useful potential cse is generated;
+   if it is used only once, instruction combination will produce
+   the same indirect address eventually.  */
+extern int cse_not_expected;
+
+/* Indexed by pseudo register number, gives the rtx for that pseudo.
+   Allocated in parallel with regno_pointer_flag.  */
+extern rtx *regno_reg_rtx;