-/* Allocate and read RTL for GNU C Compiler.
- Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
+/* RTL utility routines.
+ Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002,
+ 2003, 2004 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+/* This file is compiled twice: once for the generator programs
+ once for the compiler. */
+#ifdef GENERATOR_FILE
+#include "bconfig.h"
+#else
#include "config.h"
-#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. */
+#endif
-extern struct obstack *rtl_obstack;
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "real.h"
+#include "ggc.h"
+#include "errors.h"
-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. */
+ Does NOT include rtx header data (code and links). */
-int rtx_length[NUM_RTX_CODE + 1];
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) sizeof FORMAT - 1 ,
-/* 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 */
+const unsigned char rtx_length[NUM_RTX_CODE] = {
+#include "rtl.def"
};
#undef DEF_RTL_EXPR
-/* Indexed by machine mode, gives the name of that machine mode.
- This name does not include the letters "mode". */
-
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) NAME,
-
-char *mode_name[(int) MAX_MACHINE_MODE] = {
-#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. */
+/* Indexed by rtx code, gives the name of that kind of rtx, as a C string. */
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \
- (enum machine_mode) WIDER,
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) NAME ,
-enum machine_mode mode_wider_mode[(int) MAX_MACHINE_MODE] = {
-#include "machmode.def" /* machine modes are documented here */
+const char * const rtx_name[NUM_RTX_CODE] = {
+#include "rtl.def" /* rtl expressions are documented here */
};
-#undef DEF_MACHMODE
-
-/* Indexed by mode class, gives the narrowest mode for each class. */
-
-enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS];
-
-/* Commonly used modes. */
-
-enum machine_mode byte_mode; /* Mode whose width is BITS_PER_UNIT */
-enum machine_mode word_mode; /* Mode whose width is BITS_PER_WORD */
+#undef DEF_RTL_EXPR
/* Indexed by rtx code, gives a sequence of operand-types for
rtx's of that code. The sequence is a C string in which
each character describes one operand. */
-char *rtx_format[] = {
+const char * const rtx_format[NUM_RTX_CODE] = {
/* "*" undefined.
can cause a warning message
"0" field is unused (or used in a phase-dependent manner)
"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
+ "T" like "s", but treated specially by the RTL reader;
+ only found in machine description patterns.
"e" a pointer to an rtl expression
prints the expression
"E" a pointer to a vector that points to a number of rtl expressions
"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. */
+ prints the uid of the insn.
+ "b" is a pointer to a bitmap header.
+ "B" is a basic block pointer.
+ "t" is a tree pointer. */
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) FORMAT ,
#include "rtl.def" /* rtl expressions are defined here */
/* Indexed by rtx code, gives a character representing the "class" of
that rtx code. See rtl.def for documentation on the defined classes. */
-char rtx_class[] = {
-#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) CLASS,
+const enum rtx_class rtx_class[NUM_RTX_CODE] = {
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) CLASS,
#include "rtl.def" /* rtl expressions are defined here */
#undef DEF_RTL_EXPR
};
+/* Indexed by rtx code, gives the size of the rtx in bytes. */
+
+const unsigned char rtx_size[NUM_RTX_CODE] = {
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) \
+ ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE \
+ ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT) \
+ : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)),
+
+#include "rtl.def"
+#undef DEF_RTL_EXPR
+};
+
+/* Make sure all NOTE_INSN_* values are negative. */
+extern char NOTE_INSN_MAX_isnt_negative_adjust_NOTE_INSN_BIAS
+[NOTE_INSN_MAX < 0 ? 1 : -1];
+
/* Names for kinds of NOTEs and REG_NOTEs. */
-char *note_insn_name[] = { "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" };
+const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS] =
+{
+ "",
+#define DEF_INSN_NOTE(NAME) #NAME,
+#include "insn-notes.def"
+#undef DEF_INSN_NOTE
+};
+
+const char * const reg_note_name[REG_NOTE_MAX] =
+{
+#define DEF_REG_NOTE(NAME) #NAME,
+#include "reg-notes.def"
+#undef DEF_REG_NOTE
+};
-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" };
+#ifdef GATHER_STATISTICS
+static int rtx_alloc_counts[(int) LAST_AND_UNUSED_RTX_CODE];
+static int rtx_alloc_sizes[(int) LAST_AND_UNUSED_RTX_CODE];
+static int rtvec_alloc_counts;
+static int rtvec_alloc_sizes;
+#endif
+\f
/* Allocate an rtx vector of N elements.
Store the length, and initialize all elements to zero. */
rtvec
-rtvec_alloc (n)
- int n;
+rtvec_alloc (int n)
{
rtvec rt;
- int i;
- rt = (rtvec) obstack_alloc (rtl_obstack,
- sizeof (struct rtvec_def)
- + (( n - 1) * sizeof (rtunion)));
+ rt = ggc_alloc_rtvec (n);
+ /* Clear out the vector. */
+ memset (&rt->elem[0], 0, n * sizeof (rtx));
- /* clear out the vector */
- PUT_NUM_ELEM(rt, n);
- for (i=0; i < n; i++)
- rt->elem[i].rtvec = NULL; /* @@ not portable due to rtunion */
+ PUT_NUM_ELEM (rt, n);
+
+#ifdef GATHER_STATISTICS
+ rtvec_alloc_counts++;
+ rtvec_alloc_sizes += n * sizeof (rtx);
+#endif
return rt;
}
all the rest is initialized to zero. */
rtx
-rtx_alloc (code)
- RTX_CODE code;
+rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
{
rtx rt;
- register struct obstack *ob = rtl_obstack;
- register int nelts = GET_RTX_LENGTH (code);
- register int length = sizeof (struct rtx_def)
- + (nelts - 1) * sizeof (rtunion);
-
- /* This function is called more than any other in GCC,
- so we manipulate the obstack directly.
- Even though rtx objects are word aligned, we may be sharing an obstack
- with tree nodes, which may have to be double-word aligned. So align
- our length to the alignment mask in the obstack. */
+ rt = (rtx) ggc_alloc_typed_stat (gt_ggc_e_7rtx_def,
+ RTX_SIZE (code) PASS_MEM_STAT);
- 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;
-
- * (int *) rt = 0;
+ memset (rt, 0, RTX_HDR_SIZE);
PUT_CODE (rt, code);
+#ifdef GATHER_STATISTICS
+ rtx_alloc_counts[code]++;
+ rtx_alloc_sizes[code] += RTX_SIZE (code);
+#endif
+
return rt;
}
+
\f
/* Create a new copy of an rtx.
Recursively copies the operands of the rtx,
except for those few rtx codes that are sharable. */
rtx
-copy_rtx (orig)
- register rtx orig;
+copy_rtx (rtx orig)
{
- register rtx copy;
- register int i, j;
- register RTX_CODE code;
- register char *format_ptr;
+ rtx copy;
+ int i, j;
+ RTX_CODE code;
+ const char *format_ptr;
code = GET_CODE (orig);
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
+ case SCRATCH:
+ /* SCRATCH must be shared because they represent distinct values. */
return orig;
+ case CLOBBER:
+ if (REG_P (XEXP (orig, 0)) && REGNO (XEXP (orig, 0)) < FIRST_PSEUDO_REGISTER)
+ return orig;
+ break;
+
+ case CONST:
+ /* CONST can be shared if it contains a SYMBOL_REF. If it contains
+ 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);
- PUT_MODE (copy, GET_MODE (orig));
- copy->in_struct = orig->in_struct;
- copy->volatil = orig->volatil;
- copy->unchanging = orig->unchanging;
- copy->integrated = orig->integrated;
-
+
+ /* Copy the various flags, and other information. We assume that
+ all fields need copying, and then clear the fields that should
+ not be copied. That is the sensible default behavior, and forces
+ us to explicitly document why we are *not* copying a flag. */
+ memcpy (copy, orig, RTX_HDR_SIZE);
+
+ /* We do not copy the USED flag, which is used as a mark bit during
+ walks over the RTL. */
+ RTX_FLAG (copy, used) = 0;
+
+ /* We do not copy FRAME_RELATED for INSNs. */
+ if (INSN_P (orig))
+ RTX_FLAG (copy, frame_related) = 0;
+ RTX_FLAG (copy, jump) = RTX_FLAG (orig, jump);
+ RTX_FLAG (copy, call) = RTX_FLAG (orig, call);
+
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
+ copy->u.fld[i] = orig->u.fld[i];
switch (*format_ptr++)
{
case 'e':
- XEXP (copy, i) = XEXP (orig, i);
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = copy_rtx (XEXP (orig, i));
break;
- case '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));
}
break;
- default:
- XINT (copy, i) = XINT (orig, i);
+ case 't':
+ case 'w':
+ case 'i':
+ case 's':
+ case 'S':
+ case 'T':
+ case 'u':
+ case 'B':
+ case '0':
+ /* These are left unchanged. */
break;
+
+ default:
+ gcc_unreachable ();
}
}
return copy;
}
-/* Similar to `copy_rtx' except that if MAY_SHARE is present, it is
- placed in the result directly, rather than being copied. */
+/* Create a new copy of an rtx. Only copy just one level. */
rtx
-copy_most_rtx (orig, may_share)
- register rtx orig;
- register rtx may_share;
+shallow_copy_rtx_stat (rtx orig MEM_STAT_DECL)
{
- register rtx copy;
- register int i, j;
- register RTX_CODE code;
- register char *format_ptr;
-
- 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;
- }
+ rtx copy;
- 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 '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;
-
- default:
- XINT (copy, i) = XINT (orig, i);
- break;
- }
- }
+ copy = (rtx) ggc_alloc_typed_stat (gt_ggc_e_7rtx_def,
+ RTX_SIZE (GET_CODE (orig)) PASS_MEM_STAT);
+ memcpy (copy, orig, RTX_SIZE (GET_CODE (orig)));
return copy;
}
\f
-/* Subroutines of read_rtx. */
-
-/* Dump code after printing a message. Used when read_rtx finds
- invalid data. */
+/* Nonzero when we are generating CONCATs. */
+int generating_concat_p;
-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 ();
-}
+/* Nonzero when we are expanding trees to RTL. */
+int currently_expanding_to_rtl;
-/* 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. */
+\f
+/* Return 1 if X and Y are identical-looking rtx's.
+ This is the Lisp function EQUAL for rtx arguments. */
int
-read_skip_spaces (infile)
- FILE *infile;
+rtx_equal_p (rtx x, rtx y)
{
- register int c;
- while (c = getc (infile))
- {
- if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
- ;
- else if (c == ';')
- {
- while ((c = getc (infile)) && c != '\n') ;
- }
- 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. */
+ int i;
+ int j;
+ enum rtx_code code;
+ const char *fmt;
-static void
-read_name (str, infile)
- char *str;
- FILE *infile;
-{
- register char *p;
- register int c;
+ if (x == y)
+ return 1;
+ if (x == 0 || y == 0)
+ return 0;
- c = read_skip_spaces(infile);
+ code = GET_CODE (x);
+ /* Rtx's of different codes cannot be equal. */
+ if (code != GET_CODE (y))
+ return 0;
- 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);
- }
+ /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
+ (REG:SI x) and (REG:HI x) are NOT equivalent. */
- *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. */
+ if (GET_MODE (x) != GET_MODE (y))
+ return 0;
-rtx
-read_rtx (infile)
- FILE *infile;
-{
- register int i, j, list_counter;
- RTX_CODE tmp_code;
- register char *format_ptr;
- /* tmp_char is a buffer used for reading decimal integers
- and names of rtx types and machine modes.
- Therefore, 256 must be enough. */
- char tmp_char[256];
- rtx return_rtx;
- register int c;
- int tmp_int;
-
- /* Linked list structure for making RTXs: */
- struct rtx_list
+ /* Some RTL can be compared nonrecursively. */
+ switch (code)
{
- 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);
+ case REG:
+ return (REGNO (x) == REGNO (y));
- read_name (tmp_char, infile);
+ case LABEL_REF:
+ return XEXP (x, 0) == XEXP (y, 0);
- tmp_code = UNKNOWN;
+ case SYMBOL_REF:
+ return XSTR (x, 0) == XSTR (y, 0);
- 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 != ')');
+ case SCRATCH:
+ case CONST_DOUBLE:
+ case CONST_INT:
+ case CONST_VECTOR:
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));
+ default:
+ break;
+ }
- /* If what follows is `: mode ', read it and
- store the mode in the rtx. */
+ /* Compare the elements. If any pair of corresponding elements
+ fail to match, return 0 for the whole thing. */
- i = read_skip_spaces (infile);
- if (i == ':')
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; 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))
+ switch (fmt[i])
+ {
+ case 'w':
+ if (XWINT (x, i) != XWINT (y, i))
+ return 0;
break;
- PUT_MODE (return_rtx, (enum machine_mode) k );
- }
- else
- ungetc (i, infile);
-
- for (i = 0; i < GET_RTX_LENGTH (GET_CODE (return_rtx)); i++)
- switch (*format_ptr++)
- {
- /* 0 means a field for internal use only.
- Don't expect it to be present in the input. */
- case '0':
- break;
-
- case 'e':
- case 'u':
- XEXP (return_rtx, i) = read_rtx (infile);
- break;
-
- case 'V':
- /* 'V' is an optional vector: if a closeparen follows,
- just store NULL for this element. */
- c = read_skip_spaces (infile);
- ungetc (c, infile);
- if (c == ')')
- {
- XVEC (return_rtx, i) = 0;
- break;
- }
- /* Now process the vector. */
-
- case 'E':
- {
- register struct rtx_list *next_rtx, *rtx_list_link;
- struct rtx_list *list_rtx;
+ case 'n':
+ case 'i':
+ if (XINT (x, i) != XINT (y, i))
+ return 0;
+ break;
- c = read_skip_spaces (infile);
- if (c != '[')
- dump_and_abort ('[', c, infile);
+ case 'V':
+ case 'E':
+ /* Two vectors must have the same length. */
+ if (XVECLEN (x, i) != XVECLEN (y, i))
+ return 0;
+
+ /* And the corresponding elements must match. */
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (rtx_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0)
+ return 0;
+ break;
- /* add expressions to a list, while keeping a count */
- next_rtx = NULL;
- list_counter = 0;
- while ((c = read_skip_spaces (infile)) && c != ']')
- {
- ungetc (c, infile);
- list_counter++;
- rtx_list_link = (struct rtx_list *)
- alloca (sizeof (struct rtx_list));
- rtx_list_link->value = read_rtx (infile);
- if (next_rtx == 0)
- list_rtx = rtx_list_link;
- else
- next_rtx->next = rtx_list_link;
- next_rtx = rtx_list_link;
- rtx_list_link->next = 0;
- }
- /* get vector length and allocate it */
- XVEC (return_rtx, i) = (list_counter
- ? rtvec_alloc (list_counter)
- : (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;
+ case 'e':
+ if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0)
+ return 0;
+ break;
- c = read_skip_spaces (infile);
- if (c == '(')
- {
- saw_paren = 1;
- c = read_skip_spaces (infile);
- }
- if (c != '"')
- dump_and_abort ('"', c, infile);
+ case 'S':
+ case 's':
+ if ((XSTR (x, i) || XSTR (y, i))
+ && (! XSTR (x, i) || ! XSTR (y, i)
+ || strcmp (XSTR (x, i), XSTR (y, i))))
+ return 0;
+ break;
- while (1)
- {
- c = getc (infile); /* Read the string */
- if (c == '\\')
- {
- c = getc (infile); /* Read the string */
- /* \; makes stuff for a C string constant containing
- newline and tab. */
- if (c == ';')
- {
- obstack_grow (rtl_obstack, "\\n\\t", 4);
- continue;
- }
- }
- else if (c == '"')
- break;
-
- obstack_1grow (rtl_obstack, c);
- }
+ case 'u':
+ /* These are just backpointers, so they don't matter. */
+ break;
- obstack_1grow (rtl_obstack, 0);
- stringbuf = (char *) obstack_finish (rtl_obstack);
+ case '0':
+ case 't':
+ break;
- if (saw_paren)
- {
- c = read_skip_spaces (infile);
- if (c != ')')
- dump_and_abort (')', c, infile);
- }
- XSTR (return_rtx, i) = stringbuf;
+ /* It is believed that rtx's at this level will never
+ contain anything but integers and other rtx's,
+ except for within LABEL_REFs and SYMBOL_REFs. */
+ default:
+ gcc_unreachable ();
}
- break;
-
- case 'i':
- case 'n':
- read_name (tmp_char, infile);
- tmp_int = atoi (tmp_char);
- XINT (return_rtx, i) = tmp_int;
- break;
-
- default:
- fprintf (stderr,
- "switch format wrong in rtl.read_rtx(). format was: %c.\n",
- format_ptr[-1]);
- fprintf (stderr, "\tfile position: %ld\n", ftell (infile));
- abort ();
- }
-
- c = read_skip_spaces (infile);
- if (c != ')')
- dump_and_abort (')', c, infile);
-
- return return_rtx;
+ }
+ return 1;
}
-\f
-/* This is called once per compilation, before any rtx's are constructed.
- It initializes the vector `rtx_length', the extra CC modes, if any,
- and computes certain commonly-used modes. */
-void
-init_rtl ()
+void dump_rtx_statistics (void)
{
- int min_class_size[(int) MAX_MODE_CLASS];
- enum machine_mode mode;
+#ifdef GATHER_STATISTICS
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)
+ int total_counts = 0;
+ int total_sizes = 0;
+ fprintf (stderr, "\nRTX Kind Count Bytes\n");
+ fprintf (stderr, "---------------------------------------\n");
+ for (i = 0; i < LAST_AND_UNUSED_RTX_CODE; i++)
+ if (rtx_alloc_counts[i])
+ {
+ fprintf (stderr, "%-20s %7d %10d\n", GET_RTX_NAME (i),
+ rtx_alloc_counts[i], rtx_alloc_sizes[i]);
+ total_counts += rtx_alloc_counts[i];
+ total_sizes += rtx_alloc_sizes[i];
+ }
+ if (rtvec_alloc_counts)
{
- 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;
+ fprintf (stderr, "%-20s %7d %10d\n", "rtvec",
+ rtvec_alloc_counts, rtvec_alloc_sizes);
+ total_counts += rtvec_alloc_counts;
+ total_sizes += rtvec_alloc_sizes;
}
-#endif
+ fprintf (stderr, "---------------------------------------\n");
+ fprintf (stderr, "%-20s %7d %10d\n",
+ "Total", total_counts, total_sizes);
+ fprintf (stderr, "---------------------------------------\n");
+#endif
+}
+\f
+#if defined ENABLE_RTL_CHECKING && (GCC_VERSION >= 2007)
+void
+rtl_check_failed_bounds (rtx r, int n, const char *file, int line,
+ const char *func)
+{
+ internal_error
+ ("RTL check: access of elt %d of '%s' with last elt %d in %s, at %s:%d",
+ n, GET_RTX_NAME (GET_CODE (r)), GET_RTX_LENGTH (GET_CODE (r)) - 1,
+ func, trim_filename (file), line);
+}
-#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
+void
+rtl_check_failed_type1 (rtx r, int n, int c1, const char *file, int line,
+ const char *func)
+{
+ internal_error
+ ("RTL check: expected elt %d type '%c', have '%c' (rtx %s) in %s, at %s:%d",
+ n, c1, GET_RTX_FORMAT (GET_CODE (r))[n], GET_RTX_NAME (GET_CODE (r)),
+ func, trim_filename (file), line);
+}
- /* Find the narrowest mode for each class and compute the word and byte
- modes. */
+void
+rtl_check_failed_type2 (rtx r, int n, int c1, int c2, const char *file,
+ int line, const char *func)
+{
+ internal_error
+ ("RTL check: expected elt %d type '%c' or '%c', have '%c' (rtx %s) in %s, at %s:%d",
+ n, c1, c2, GET_RTX_FORMAT (GET_CODE (r))[n], GET_RTX_NAME (GET_CODE (r)),
+ func, trim_filename (file), line);
+}
- for (i = 0; i < (int) MAX_MODE_CLASS; i++)
- min_class_size[i] = 1000;
+void
+rtl_check_failed_code1 (rtx r, enum rtx_code code, const char *file,
+ int line, const char *func)
+{
+ internal_error ("RTL check: expected code '%s', have '%s' in %s, at %s:%d",
+ GET_RTX_NAME (code), GET_RTX_NAME (GET_CODE (r)), func,
+ trim_filename (file), line);
+}
- byte_mode = VOIDmode;
- word_mode = VOIDmode;
+void
+rtl_check_failed_code2 (rtx r, enum rtx_code code1, enum rtx_code code2,
+ const char *file, int line, const char *func)
+{
+ internal_error
+ ("RTL check: expected code '%s' or '%s', have '%s' in %s, at %s:%d",
+ GET_RTX_NAME (code1), GET_RTX_NAME (code2), GET_RTX_NAME (GET_CODE (r)),
+ func, trim_filename (file), line);
+}
- for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
- mode = (enum machine_mode) ((int) mode + 1))
- {
- if (GET_MODE_SIZE (mode) < min_class_size[(int) GET_MODE_CLASS (mode)])
- {
- class_narrowest_mode[(int) GET_MODE_CLASS (mode)] = mode;
- min_class_size[(int) GET_MODE_CLASS (mode)] = GET_MODE_SIZE (mode);
- }
- if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_BITSIZE (mode) == BITS_PER_UNIT
- && byte_mode == VOIDmode)
- byte_mode = mode;
-
- if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_BITSIZE (mode) == BITS_PER_WORD
- && word_mode == VOIDmode)
- word_mode = mode;
- }
+/* XXX Maybe print the vector? */
+void
+rtvec_check_failed_bounds (rtvec r, int n, const char *file, int line,
+ const char *func)
+{
+ internal_error
+ ("RTL check: access of elt %d of vector with last elt %d in %s, at %s:%d",
+ n, GET_NUM_ELEM (r) - 1, func, trim_filename (file), line);
}
-\f
-#ifdef memset
-gcc_memset (dest, value, len)
- char *dest;
- int value;
- int len;
+#endif /* ENABLE_RTL_CHECKING */
+
+#if defined ENABLE_RTL_FLAG_CHECKING
+void
+rtl_check_failed_flag (const char *name, rtx r, const char *file,
+ int line, const char *func)
{
- while (len-- > 0)
- *dest++ = value;
+ internal_error
+ ("RTL flag check: %s used with unexpected rtx code '%s' in %s, at %s:%d",
+ name, GET_RTX_NAME (GET_CODE (r)), func, trim_filename (file), line);
}
-#endif /* memset */
+#endif /* ENABLE_RTL_FLAG_CHECKING */