summaryrefslogtreecommitdiff
path: root/gnu/egcs/gcc/rtl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/egcs/gcc/rtl.c')
-rw-r--r--gnu/egcs/gcc/rtl.c961
1 files changed, 961 insertions, 0 deletions
diff --git a/gnu/egcs/gcc/rtl.c b/gnu/egcs/gcc/rtl.c
new file mode 100644
index 00000000000..6b04bcd82d5
--- /dev/null
+++ b/gnu/egcs/gcc/rtl.c
@@ -0,0 +1,961 @@
+/* Allocate and read RTL for GNU C Compiler.
+ Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998 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, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "real.h"
+#include "bitmap.h"
+
+#include "obstack.h"
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+/* 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;
+
+/* 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 + 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 machine mode, gives mask of significant bits in mode. */
+
+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. */
+
+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[] = {
+ /* "*" 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'
+ "w" an integer of width HOST_BITS_PER_WIDE_INT
+ prints the integer
+ "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.
+ "b" is a pointer to a bitmap header.
+ "t" is a tree pointer. */
+
+#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[] = { 0 , "NOTE_INSN_DELETED",
+ "NOTE_INSN_BLOCK_BEG", "NOTE_INSN_BLOCK_END",
+ "NOTE_INSN_LOOP_BEG", "NOTE_INSN_LOOP_END",
+ "NOTE_INSN_FUNCTION_END", "NOTE_INSN_SETJMP",
+ "NOTE_INSN_LOOP_CONT", "NOTE_INSN_LOOP_VTOP",
+ "NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG",
+ "NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
+ "NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
+ "NOTE_REPEATED_LINE_NUMBER", "NOTE_INSN_RANGE_START",
+ "NOTE_INSN_RANGE_END", "NOTE_INSN_LIVE",
+ "NOTE_INSN_BASIC_BLOCK" };
+
+char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
+ "REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",
+ "REG_NONNEG", "REG_NO_CONFLICT", "REG_UNUSED",
+ "REG_CC_SETTER", "REG_CC_USER", "REG_LABEL",
+ "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
+ "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA",
+ "REG_BR_PRED", "REG_EH_CONTEXT",
+ "REG_FRAME_RELATED_EXPR", "REG_EH_REGION",
+ "REG_EH_RETHROW" };
+
+static void dump_and_abort PROTO((int, int, FILE *)) ATTRIBUTE_NORETURN;
+static void read_name PROTO((char *, FILE *));
+
+/* 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].rtwint = 0;
+
+ 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;
+
+ /* We want to clear everything up to the FLD array. Normally, this is
+ one int, but we don't want to assume that and it isn't very portable
+ anyway; this is. */
+
+ memset (rt, 0, sizeof (struct rtx_def) - sizeof (rtunion));
+
+ PUT_CODE (rt, code);
+
+ return rt;
+}
+
+/* Free the rtx X and all RTL allocated since X. */
+
+void
+rtx_free (x)
+ rtx x;
+{
+ obstack_free (rtl_obstack, x);
+}
+
+/* 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:
+ case SCRATCH:
+ /* SCRATCH must be shared because they represent distinct values. */
+ case ADDRESSOF:
+ return orig;
+
+ case CONST:
+ /* CONST can be shared if it contains a SYMBOL_REF. If it contains
+ a LABEL_REF, it isn't sharable. */
+ if (GET_CODE (XEXP (orig, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
+ return orig;
+ break;
+
+ /* A MEM with a constant address is not sharable. The problem is that
+ the constant address may need to be reloaded. If the mem is shared,
+ then reloading one copy of this mem will cause all copies to appear
+ to have been reloaded. */
+
+ default:
+ break;
+ }
+
+ copy = rtx_alloc (code);
+
+ /* 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 JUMP, CALL, or FRAME_RELATED for INSNs. */
+ if (GET_RTX_CLASS (code) == 'i')
+ {
+ copy->jump = 0;
+ copy->call = 0;
+ copy->frame_related = 0;
+ }
+
+ 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 '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));
+ for (j = 0; j < XVECLEN (copy, i); j++)
+ XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
+ }
+ 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);
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ 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;
+ 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));
+
+ 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 '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));
+ for (j = 0; j < XVECLEN (copy, i); j++)
+ XVECEXP (copy, i, j)
+ = copy_most_rtx (XVECEXP (orig, i, j), may_share);
+ }
+ break;
+
+ case 'w':
+ XWINT (copy, i) = XWINT (orig, i);
+ break;
+
+ case 'n':
+ case 'i':
+ XINT (copy, i) = XINT (orig, i);
+ break;
+
+ case 's':
+ case 'S':
+ XSTR (copy, i) = XSTR (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 char *format_ptr;
+ 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;
+}
+
+/* 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' && 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;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+#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;
+{
+ 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;
+}
+
+/* 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 ()
+{
+ 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. */
+
+ for (i = 0; i < (int) MAX_MODE_CLASS; i++)
+ min_class_size[i] = 1000;
+
+ 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);
+ }
+ }
+}