/* Allocate and read RTL for GNU C Compiler.
- Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000
+ Free Software Foundation, Inc.
This file is part of GNU CC.
#include "rtl.h"
#include "real.h"
#include "bitmap.h"
-
+#include "ggc.h"
#include "obstack.h"
+#include "toplev.h"
+#include "hashtab.h"
+
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-/* Obstack used for allocating RTL objects.
- Between functions, this is the permanent_obstack.
- While parsing and expanding a function, this is maybepermanent_obstack
- so we can save it if it is an inline function.
- During optimization and output, this is function_obstack. */
-
-extern struct obstack *rtl_obstack;
\f
+/* Calculate the format for CONST_DOUBLE. This depends on the relative
+ widths of HOST_WIDE_INT and REAL_VALUE_TYPE.
+
+ We need to go out to e0wwwww, since REAL_ARITHMETIC assumes 16-bits
+ per element in REAL_VALUE_TYPE.
+
+ This is duplicated in gengenrtl.c.
+
+ A number of places assume that there are always at least two 'w'
+ slots in a CONST_DOUBLE, so we provide them even if one would suffice. */
+
+#ifdef REAL_ARITHMETIC
+# if MAX_LONG_DOUBLE_TYPE_SIZE == 96
+# define REAL_WIDTH \
+ (11*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
+# else
+# if MAX_LONG_DOUBLE_TYPE_SIZE == 128
+# define REAL_WIDTH \
+ (19*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
+# else
+# if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
+# define REAL_WIDTH \
+ (7*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
+# endif
+# endif
+# endif
+#endif /* REAL_ARITHMETIC */
+
+#ifndef REAL_WIDTH
+# if HOST_BITS_PER_WIDE_INT*2 >= MAX_LONG_DOUBLE_TYPE_SIZE
+# define REAL_WIDTH 2
+# else
+# if HOST_BITS_PER_WIDE_INT*3 >= MAX_LONG_DOUBLE_TYPE_SIZE
+# define REAL_WIDTH 3
+# else
+# if HOST_BITS_PER_WIDE_INT*4 >= MAX_LONG_DOUBLE_TYPE_SIZE
+# define REAL_WIDTH 4
+# endif
+# endif
+# endif
+#endif /* REAL_WIDTH */
+
+#if REAL_WIDTH == 1
+# define CONST_DOUBLE_FORMAT "e0ww"
+#else
+# if REAL_WIDTH == 2
+# define CONST_DOUBLE_FORMAT "e0ww"
+# else
+# if REAL_WIDTH == 3
+# define CONST_DOUBLE_FORMAT "e0www"
+# else
+# if REAL_WIDTH == 4
+# define CONST_DOUBLE_FORMAT "e0wwww"
+# else
+# if REAL_WIDTH == 5
+# define CONST_DOUBLE_FORMAT "e0wwwww"
+# else
+# define CONST_DOUBLE_FORMAT /* nothing - will cause syntax error */
+# endif
+# endif
+# endif
+# endif
+#endif
+
/* Indexed by rtx code, gives number of operands for an rtx with that code.
- Does NOT include rtx header data (code and links).
- This array is initialized in init_rtl. */
+ Does NOT include rtx header data (code and links). */
+
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) sizeof FORMAT - 1 ,
-int rtx_length[NUM_RTX_CODE + 1];
+const int rtx_length[NUM_RTX_CODE + 1] = {
+#include "rtl.def"
+};
+
+#undef DEF_RTL_EXPR
/* Indexed by rtx code, gives the name of that kind of rtx, as a C string. */
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) NAME ,
-char *rtx_name[] = {
+const char * const rtx_name[] = {
#include "rtl.def" /* rtl expressions are documented here */
};
/* 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,
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER) NAME,
-char *mode_name[(int) MAX_MACHINE_MODE + 1] = {
+const char * const mode_name[(int) MAX_MACHINE_MODE + 1] = {
#include "machmode.def"
-
-#ifdef EXTRA_CC_MODES
- EXTRA_CC_NAMES,
-#endif
/* Add an extra field to avoid a core dump if someone tries to convert
MAX_MACHINE_MODE to a string. */
""
#undef DEF_MACHMODE
-/* Indexed by machine mode, gives the length of the mode, in bytes.
- GET_MODE_CLASS uses this. */
+/* Indexed by machine mode, gives the class mode for GET_MODE_CLASS. */
+
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER) CLASS,
+
+const 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 bits.
+ GET_MODE_BITSIZE uses this. */
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) CLASS,
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER) BITSIZE,
-enum mode_class mode_class[(int) MAX_MACHINE_MODE] = {
+const unsigned int mode_bitsize[(int) MAX_MACHINE_MODE] = {
#include "machmode.def"
};
/* 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,
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER) SIZE,
-int mode_size[(int) MAX_MACHINE_MODE] = {
+const unsigned int mode_size[(int) MAX_MACHINE_MODE] = {
#include "machmode.def"
};
/* 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,
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER) UNIT,
-int mode_unit_size[(int) MAX_MACHINE_MODE] = {
+const unsigned int mode_unit_size[(int) MAX_MACHINE_MODE] = {
#include "machmode.def" /* machine modes are documented here */
};
(QI -> HI -> SI -> DI, etc.) Widening multiply instructions
use this. */
-#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER) \
(unsigned char) WIDER,
-unsigned char mode_wider_mode[(int) MAX_MACHINE_MODE] = {
+const unsigned char mode_wider_mode[(int) MAX_MACHINE_MODE] = {
#include "machmode.def" /* machine modes are documented here */
};
#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,
+#define DEF_MACHMODE(SYM, NAME, CLASS, BITSIZE, SIZE, UNIT, WIDER) \
+ ((BITSIZE) >= HOST_BITS_PER_WIDE_INT) ? ~(unsigned HOST_WIDE_INT)0 : ((unsigned HOST_WIDE_INT) 1 << (BITSIZE)) - 1,
/* Indexed by machine mode, gives mask of significant bits in mode. */
-unsigned HOST_WIDE_INT mode_mask_array[(int) MAX_MACHINE_MODE] = {
+const unsigned HOST_WIDE_INT mode_mask_array[(int) MAX_MACHINE_MODE] = {
#include "machmode.def"
};
-/* Indexed by mode class, gives the narrowest mode for each class. */
+/* Indexed by mode class, gives the narrowest mode for each class.
+ The Q modes are always of width 1 (2 for complex) - it is impossible
+ for any mode to be narrower.
+
+ Note that we use QImode instead of BImode for MODE_INT, since
+ otherwise the middle end will try to use it for bitfields in
+ structures and the like, which we do not want. Only the target
+ md file should generate BImode widgets. */
+
+const enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS] = {
+ /* MODE_RANDOM */ VOIDmode,
+ /* MODE_INT */ QImode,
+ /* MODE_FLOAT */ QFmode,
+ /* MODE_PARTIAL_INT */ PQImode,
+ /* MODE_CC */ CCmode,
+ /* MODE_COMPLEX_INT */ CQImode,
+ /* MODE_COMPLEX_FLOAT */ QCmode,
+ /* MODE_VECTOR_INT */ V2QImode,
+ /* MODE_VECTOR_FLOAT */ V2SFmode
+};
-enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS];
/* Indexed by rtx code, gives a sequence of operand-types for
rtx's of that code. The sequence is a C string in which
each character describes one operand. */
-char *rtx_format[] = {
+const char * const rtx_format[] = {
/* "*" undefined.
can cause a warning message
"0" field is unused (or used in a phase-dependent manner)
/* Indexed by rtx code, gives a character representing the "class" of
that rtx code. See rtl.def for documentation on the defined classes. */
-char rtx_class[] = {
-#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) CLASS,
+const char rtx_class[] = {
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) CLASS,
#include "rtl.def" /* rtl expressions are defined here */
#undef DEF_RTL_EXPR
};
/* Names for kinds of NOTEs and REG_NOTEs. */
-char *note_insn_name[] = { 0 , "NOTE_INSN_DELETED",
- "NOTE_INSN_BLOCK_BEG", "NOTE_INSN_BLOCK_END",
- "NOTE_INSN_LOOP_BEG", "NOTE_INSN_LOOP_END",
- "NOTE_INSN_FUNCTION_END", "NOTE_INSN_SETJMP",
- "NOTE_INSN_LOOP_CONT", "NOTE_INSN_LOOP_VTOP",
- "NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG",
- "NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
- "NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
- "NOTE_REPEATED_LINE_NUMBER", "NOTE_INSN_RANGE_START",
- "NOTE_INSN_RANGE_END", "NOTE_INSN_LIVE" };
-
-char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
- "REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",
- "REG_NONNEG", "REG_NO_CONFLICT", "REG_UNUSED",
- "REG_CC_SETTER", "REG_CC_USER", "REG_LABEL",
- "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
- "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA",
- "REG_BR_PRED", "REG_EH_CONTEXT",
- "REG_FRAME_RELATED_EXPR", "REG_EH_REGION",
- "REG_EH_RETHROW" };
-
-static void dump_and_abort PROTO((int, int, FILE *)) ATTRIBUTE_NORETURN;
-static void read_name PROTO((char *, FILE *));
+const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS] =
+{
+ "", "NOTE_INSN_DELETED",
+ "NOTE_INSN_BLOCK_BEG", "NOTE_INSN_BLOCK_END",
+ "NOTE_INSN_LOOP_BEG", "NOTE_INSN_LOOP_END",
+ "NOTE_INSN_LOOP_CONT", "NOTE_INSN_LOOP_VTOP",
+ "NOTE_INSN_FUNCTION_END", "NOTE_INSN_SETJMP",
+ "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_INSN_REPEATED_LINE_NUMBER", "NOTE_INSN_RANGE_BEG",
+ "NOTE_INSN_RANGE_END", "NOTE_INSN_LIVE",
+ "NOTE_INSN_BASIC_BLOCK", "NOTE_INSN_EXPECTED_VALUE"
+};
+
+const char * const reg_note_name[] =
+{
+ "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_EQUAL",
+ "REG_WAS_0", "REG_RETVAL", "REG_LIBCALL", "REG_NONNEG",
+ "REG_NO_CONFLICT", "REG_UNUSED", "REG_CC_SETTER", "REG_CC_USER",
+ "REG_LABEL", "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
+ "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA", "REG_BR_PRED",
+ "REG_FRAME_RELATED_EXPR", "REG_EH_CONTEXT", "REG_EH_REGION",
+ "REG_EH_RETHROW", "REG_SAVE_NOTE", "REG_MAYBE_DEAD", "REG_NORETURN",
+ "REG_NON_LOCAL_GOTO"
+};
+
+static htab_t md_constants;
+
+static void fatal_with_file_and_line PARAMS ((FILE *, const char *, ...))
+ ATTRIBUTE_PRINTF_2 ATTRIBUTE_NORETURN;
+static void fatal_expected_char PARAMS ((FILE *, int, int)) ATTRIBUTE_NORETURN;
+static void read_name PARAMS ((char *, FILE *));
+static char *read_string PARAMS ((struct obstack *, FILE *));
+static unsigned def_hash PARAMS ((const void *));
+static int def_name_eq_p PARAMS ((const void *, const void *));
+static void read_constants PARAMS ((FILE *infile, char *tmp_char));
+
\f
/* Allocate an rtx vector of N elements.
Store the length, and initialize all elements to zero. */
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 */
- PUT_NUM_ELEM (rt, n);
-
- for (i = 0; i < n; i++)
- rt->elem[i].rtwint = 0;
+ memset (&rt->elem[0], 0, n * sizeof (rtx));
+ PUT_NUM_ELEM (rt, n);
return rt;
}
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. */
+ int n = GET_RTX_LENGTH (code);
- length = (length + ob->alignment_mask) & ~ ob->alignment_mask;
+ rt = ggc_alloc_rtx (n);
- if (ob->chunk_limit - ob->next_free < length)
- _obstack_newchunk (ob, length);
- rt = (rtx)ob->object_base;
- ob->next_free += length;
- ob->object_base = ob->next_free;
-
- /* We want to clear everything up to the FLD array. Normally, this is
- one int, but we don't want to assume that and it isn't very portable
- anyway; this is. */
-
- length = (sizeof (struct rtx_def) - sizeof (rtunion) - 1) / sizeof (int);
- for (; length >= 0; length--)
- ((int *) rt)[length] = 0;
+ /* We want to clear everything up to the FLD array. Normally, this
+ is one int, but we don't want to assume that and it isn't very
+ portable anyway; this is. */
+ memset (rt, 0, 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);
-}
\f
/* Create a new copy of an rtx.
Recursively copies the operands of the rtx,
register rtx copy;
register int i, j;
register RTX_CODE code;
- register char *format_ptr;
+ register const char *format_ptr;
code = GET_CODE (orig);
}
copy = rtx_alloc (code);
- PUT_MODE (copy, GET_MODE (orig));
- copy->in_struct = orig->in_struct;
- copy->volatil = orig->volatil;
- copy->unchanging = orig->unchanging;
- copy->integrated = orig->integrated;
-
+
+ /* Copy the various flags, and other information. We assume that
+ all fields need copying, and then clear the fields that should
+ not be copied. That is the sensible default behavior, and forces
+ us to explicitly document why we are *not* copying a flag. */
+ memcpy (copy, orig, sizeof (struct rtx_def) - sizeof (rtunion));
+
+ /* We do not copy the USED flag, which is used as a mark bit during
+ walks over the RTL. */
+ copy->used = 0;
+
+ /* We do not copy FRAME_RELATED for INSNs. */
+ if (GET_RTX_CLASS (code) == 'i')
+ copy->frame_related = 0;
+ copy->jump = orig->jump;
+ copy->call = orig->call;
+
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
+ copy->fld[i] = orig->fld[i];
switch (*format_ptr++)
{
case 'e':
- XEXP (copy, i) = XEXP (orig, i);
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = copy_rtx (XEXP (orig, i));
break;
- case '0':
- case 'u':
- XEXP (copy, i) = XEXP (orig, i);
- break;
-
case 'E':
case 'V':
- XVEC (copy, i) = XVEC (orig, i);
if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
}
break;
- case 'b':
- {
- bitmap new_bits = BITMAP_OBSTACK_ALLOC (rtl_obstack);
- bitmap_copy (new_bits, XBITMAP (orig, i));
- XBITMAP (copy, i) = new_bits;
- break;
- }
-
case 't':
- XTREE (copy, i) = XTREE (orig, i);
- break;
-
case 'w':
- XWINT (copy, i) = XWINT (orig, i);
- break;
-
case 'i':
- XINT (copy, i) = XINT (orig, i);
- break;
-
case 's':
case 'S':
- XSTR (copy, i) = XSTR (orig, i);
+ case 'u':
+ case '0':
+ /* These are left unchanged. */
break;
default:
register rtx copy;
register int i, j;
register RTX_CODE code;
- register char *format_ptr;
+ register const char *format_ptr;
if (orig == may_share)
return orig;
copy->volatil = orig->volatil;
copy->unchanging = orig->unchanging;
copy->integrated = orig->integrated;
-
+ copy->frame_related = orig->frame_related;
+
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
XEXP (copy, i) = copy_most_rtx (XEXP (orig, i), may_share);
break;
- case '0':
case 'u':
XEXP (copy, i) = XEXP (orig, i);
break;
XINT (copy, i) = XINT (orig, i);
break;
+ case 't':
+ XTREE (copy, i) = XTREE (orig, i);
+ break;
+
case 's':
case 'S':
XSTR (copy, i) = XSTR (orig, i);
break;
+ case '0':
+ /* Copy this through the wide int field; that's safest. */
+ X0WINT (copy, i) = X0WINT (orig, i);
+ break;
+
default:
abort ();
}
}
return copy;
}
+
+/* Create a new copy of an rtx. Only copy just one level. */
+rtx
+shallow_copy_rtx (orig)
+ rtx orig;
+{
+ register int i;
+ register RTX_CODE code = GET_CODE (orig);
+ register rtx copy = rtx_alloc (code);
+
+ PUT_MODE (copy, GET_MODE (orig));
+ copy->in_struct = orig->in_struct;
+ copy->volatil = orig->volatil;
+ copy->unchanging = orig->unchanging;
+ copy->integrated = orig->integrated;
+ copy->frame_related = orig->frame_related;
+
+ for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ copy->fld[i] = orig->fld[i];
+
+ return copy;
+}
+\f
+/* This is 1 until after the rtl generation pass. */
+int rtx_equal_function_value_matters;
+
+/* Nonzero when we are generating CONCATs. */
+int generating_concat_p;
+\f
+/* Return 1 if X and Y are identical-looking rtx's.
+ This is the Lisp function EQUAL for rtx arguments. */
+
+int
+rtx_equal_p (x, y)
+ rtx x, y;
+{
+ register int i;
+ register int j;
+ register enum rtx_code code;
+ register const char *fmt;
+
+ if (x == y)
+ return 1;
+ if (x == 0 || y == 0)
+ return 0;
+
+ code = GET_CODE (x);
+ /* Rtx's of different codes cannot be equal. */
+ if (code != GET_CODE (y))
+ return 0;
+
+ /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
+ (REG:SI x) and (REG:HI x) are NOT equivalent. */
+
+ if (GET_MODE (x) != GET_MODE (y))
+ return 0;
+
+ /* Some RTL can be compared nonrecursively. */
+ switch (code)
+ {
+ case REG:
+ /* Until rtl generation is complete, don't consider a reference to the
+ return register of the current function the same as the return from a
+ called function. This eases the job of function integration. Once the
+ distinction is no longer needed, they can be considered equivalent. */
+ return (REGNO (x) == REGNO (y)
+ && (! rtx_equal_function_value_matters
+ || REG_FUNCTION_VALUE_P (x) == REG_FUNCTION_VALUE_P (y)));
+
+ case LABEL_REF:
+ return XEXP (x, 0) == XEXP (y, 0);
+
+ case SYMBOL_REF:
+ return XSTR (x, 0) == XSTR (y, 0);
+
+ case SCRATCH:
+ case CONST_DOUBLE:
+ case CONST_INT:
+ return 0;
+
+ default:
+ break;
+ }
+
+ /* Compare the elements. If any pair of corresponding elements
+ fail to match, return 0 for the whole things. */
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ switch (fmt[i])
+ {
+ case 'w':
+ if (XWINT (x, i) != XWINT (y, i))
+ return 0;
+ break;
+
+ case 'n':
+ case 'i':
+ if (XINT (x, i) != XINT (y, i))
+ return 0;
+ break;
+
+ case 'V':
+ case 'E':
+ /* Two vectors must have the same length. */
+ if (XVECLEN (x, i) != XVECLEN (y, i))
+ return 0;
+
+ /* And the corresponding elements must match. */
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (rtx_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0)
+ return 0;
+ break;
+
+ case 'e':
+ if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0)
+ return 0;
+ break;
+
+ case 'S':
+ case 's':
+ if (strcmp (XSTR (x, i), XSTR (y, i)))
+ return 0;
+ break;
+
+ case 'u':
+ /* These are just backpointers, so they don't matter. */
+ break;
+
+ case '0':
+ case 't':
+ break;
+
+ /* It is believed that rtx's at this level will never
+ contain anything but integers and other rtx's,
+ except for within LABEL_REFs and SYMBOL_REFs. */
+ default:
+ abort ();
+ }
+ }
+ return 1;
+}
\f
/* Subroutines of read_rtx. */
-/* Dump code after printing a message. Used when read_rtx finds
- invalid data. */
+/* The current line number for the file. */
+int read_rtx_lineno = 1;
+
+/* The filename for aborting with file and line. */
+const char *read_rtx_filename = "<unknown>";
static void
-dump_and_abort (expected_c, actual_c, infile)
- int expected_c, actual_c;
- FILE *infile;
+fatal_with_file_and_line VPARAMS ((FILE *infile, const char *msg, ...))
{
- int c, i;
-
- if (expected_c >= 0)
- fprintf (stderr,
- "Expected character %c. Found character %c.",
- expected_c, actual_c);
- fprintf (stderr, " At file position: %ld\n", ftell (infile));
- fprintf (stderr, "Following characters are:\n\t");
- for (i = 0; i < 200; i++)
+#ifndef ANSI_PROTOTYPES
+ FILE *infile;
+ const char *msg;
+#endif
+ va_list ap;
+ char context[64];
+ size_t i;
+ int c;
+
+ VA_START (ap, msg);
+
+#ifndef ANSI_PROTOTYPES
+ infile = va_arg (ap, FILE *);
+ msg = va_arg (ap, const char *);
+#endif
+
+ fprintf (stderr, "%s:%d: ", read_rtx_filename, read_rtx_lineno);
+ vfprintf (stderr, msg, ap);
+ putc ('\n', stderr);
+
+ /* Gather some following context. */
+ for (i = 0; i < sizeof(context)-1; ++i)
{
c = getc (infile);
- if (EOF == c) break;
- putc (c, stderr);
+ if (c == EOF)
+ break;
+ if (c == '\r' || c == '\n')
+ break;
+ context[i] = c;
}
- fprintf (stderr, "Aborting.\n");
- abort ();
+ context[i] = '\0';
+
+ fprintf (stderr, "%s:%d: following context is `%s'\n",
+ read_rtx_filename, read_rtx_lineno, context);
+
+ va_end (ap);
+ exit (1);
+}
+
+/* Dump code after printing a message. Used when read_rtx finds
+ invalid data. */
+
+static void
+fatal_expected_char (infile, expected_c, actual_c)
+ FILE *infile;
+ int expected_c, actual_c;
+{
+ fatal_with_file_and_line (infile, "expected character `%c', found `%c'",
+ expected_c, actual_c);
}
/* Read chars from INFILE until a non-whitespace char
FILE *infile;
{
register int c;
- while ((c = getc (infile)))
+ while (1)
{
- if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
- ;
- else if (c == ';')
- {
- while ((c = getc (infile)) && c != '\n' && c != EOF)
- ;
- }
- else if (c == '/')
+ c = getc (infile);
+ switch (c)
{
- register int prevc;
- c = getc (infile);
- if (c != '*')
- dump_and_abort ('*', c, infile);
-
- prevc = 0;
- while ((c = getc (infile)) && c != EOF)
- {
- if (prevc == '*' && c == '/')
- break;
- prevc = c;
- }
+ case '\n':
+ read_rtx_lineno++;
+ break;
+
+ case ' ': case '\t': case '\f': case '\r':
+ break;
+
+ case ';':
+ do
+ c = getc (infile);
+ while (c != '\n' && c != EOF);
+ read_rtx_lineno++;
+ break;
+
+ case '/':
+ {
+ register int prevc;
+ c = getc (infile);
+ if (c != '*')
+ fatal_expected_char (infile, '*', c);
+
+ prevc = 0;
+ while ((c = getc (infile)) && c != EOF)
+ {
+ if (c == '\n')
+ read_rtx_lineno++;
+ else if (prevc == '*' && c == '/')
+ break;
+ prevc = c;
+ }
+ }
+ break;
+
+ default:
+ return c;
}
- else break;
}
- return c;
}
/* Read an rtx code name into the buffer STR[].
c = getc (infile);
}
if (p == str)
+ fatal_with_file_and_line (infile, "missing name or number");
+ if (c == '\n')
+ read_rtx_lineno++;
+
+ *p = 0;
+
+ if (md_constants)
+ {
+ /* Do constant expansion. */
+ struct md_constant *def;
+
+ p = str;
+ do
+ {
+ struct md_constant tmp_def;
+
+ tmp_def.name = p;
+ def = htab_find (md_constants, &tmp_def);
+ if (def)
+ p = def->value;
+ } while (def);
+ if (p != str)
+ strcpy (str, p);
+ }
+}
+
+/* Read a double-quoted string onto the obstack. */
+
+static char *
+read_string (ob, infile)
+ struct obstack *ob;
+ FILE *infile;
+{
+ char *stringbuf;
+ int saw_paren = 0;
+ int c;
+
+ c = read_skip_spaces (infile);
+ if (c == '(')
{
- fprintf (stderr, "missing name or number");
- dump_and_abort (-1, -1, infile);
+ saw_paren = 1;
+ c = read_skip_spaces (infile);
}
+ if (c != '"')
+ fatal_expected_char (infile, '"', c);
- *p = 0;
+ while (1)
+ {
+ c = getc (infile); /* Read the string */
+ if (c == '\n')
+ read_rtx_lineno++;
+ else if (c == '\\')
+ {
+ c = getc (infile); /* Read the string */
+ /* \; makes stuff for a C string constant containing
+ newline and tab. */
+ if (c == ';')
+ {
+ obstack_grow (ob, "\\n\\t", 4);
+ continue;
+ }
+ if (c == '\n')
+ read_rtx_lineno++;
+ }
+ else if (c == '"')
+ break;
+
+ obstack_1grow (ob, c);
+ }
+
+ obstack_1grow (ob, 0);
+ stringbuf = (char *) obstack_finish (ob);
+
+ if (saw_paren)
+ {
+ c = read_skip_spaces (infile);
+ if (c != ')')
+ fatal_expected_char (infile, ')', c);
+ }
+
+ return stringbuf;
}
\f
/* Provide a version of a function to read a long long if the system does
}
#endif
+/* Given a constant definition, return a hash code for its name. */
+static unsigned
+def_hash (def)
+ const void *def;
+{
+ unsigned result, i;
+ const char *string = ((const struct md_constant *)def)->name;
+
+ for (result = i = 0;*string++ != '\0'; i++)
+ result += ((unsigned char) *string << (i % CHAR_BIT));
+ return result;
+}
+
+/* Given two constant definitions, return true if they have the same name. */
+static int
+def_name_eq_p (def1, def2)
+ const void *def1, *def2;
+{
+ return ! strcmp (((const struct md_constant *)def1)->name,
+ ((const struct md_constant *)def2)->name);
+}
+
+/* INFILE is a FILE pointer to read text from. TMP_CHAR is a buffer suitable
+ to read a name or number into. Process a define_constants directive,
+ starting with the optional space after the "define_constants". */
+static void
+read_constants (infile, tmp_char)
+ FILE *infile;
+ char *tmp_char;
+{
+ int c;
+ htab_t defs;
+
+ c = read_skip_spaces (infile);
+ if (c != '[')
+ fatal_expected_char (infile, '[', c);
+ defs = md_constants;
+ if (! defs)
+ defs = htab_create (32, def_hash, def_name_eq_p, (htab_del) 0);
+ /* Disable constant expansion during definition processing. */
+ md_constants = 0;
+ while ( (c = read_skip_spaces (infile)) != ']')
+ {
+ struct md_constant *def;
+ void **entry_ptr;
+
+ if (c != '(')
+ fatal_expected_char (infile, '(', c);
+ def = xmalloc (sizeof (struct md_constant));
+ def->name = tmp_char;
+ read_name (tmp_char, infile);
+ entry_ptr = htab_find_slot (defs, def, TRUE);
+ if (! *entry_ptr)
+ def->name = xstrdup (tmp_char);
+ c = read_skip_spaces (infile);
+ ungetc (c, infile);
+ read_name (tmp_char, infile);
+ if (! *entry_ptr)
+ {
+ def->value = xstrdup (tmp_char);
+ *entry_ptr = def;
+ }
+ else
+ {
+ def = *entry_ptr;
+ if (strcmp (def->value, tmp_char))
+ fatal_with_file_and_line (infile,
+ "redefinition of %s, was %s, now %s",
+ def->name, def->value, tmp_char);
+ }
+ c = read_skip_spaces (infile);
+ if (c != ')')
+ fatal_expected_char (infile, ')', c);
+ }
+ md_constants = defs;
+ c = read_skip_spaces (infile);
+ if (c != ')')
+ fatal_expected_char (infile, ')', c);
+}
+
+/* For every constant definition, call CALLBACK with two arguments:
+ a pointer a pointer to the constant definition and INFO.
+ Stops when CALLBACK returns zero. */
+void
+traverse_md_constants (callback, info)
+ htab_trav callback;
+ void *info;
+{
+ if (md_constants)
+ htab_traverse (md_constants, callback, info);
+}
+
/* 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
read_rtx (infile)
FILE *infile;
{
- register int i, j, list_counter;
+ register int i, j;
RTX_CODE tmp_code;
- register char *format_ptr;
+ register const char *format_ptr;
/* tmp_char is a buffer used for reading decimal integers
and names of rtx types and machine modes.
Therefore, 256 must be enough. */
int tmp_int;
HOST_WIDE_INT tmp_wide;
+ /* Obstack used for allocating RTL objects. */
+ static struct obstack rtl_obstack;
+ static int initialized;
+
/* Linked list structure for making RTXs: */
struct rtx_list
{
struct rtx_list *next;
- rtx value; /* Value of this node... */
+ rtx value; /* Value of this node. */
};
+ if (!initialized) {
+ _obstack_begin (&rtl_obstack,0, 0,
+ (void *(*) PARAMS ((long))) xmalloc,
+ (void (*) PARAMS ((void *))) free);
+ initialized = 1;
+ }
+
+again:
c = read_skip_spaces (infile); /* Should be open paren. */
if (c != '(')
- dump_and_abort ('(', c, infile);
+ fatal_expected_char (infile, '(', c);
read_name (tmp_char, infile);
tmp_code = UNKNOWN;
- for (i=0; i < NUM_RTX_CODE; i++) /* @@ might speed this search up */
+ if (! strcmp (tmp_char, "define_constants"))
{
- if (!(strcmp (tmp_char, GET_RTX_NAME (i))))
- {
- tmp_code = (RTX_CODE) i; /* get value for name */
- break;
- }
+ read_constants (infile, tmp_char);
+ goto again;
}
+ for (i = 0; i < NUM_RTX_CODE; i++)
+ if (! strcmp (tmp_char, GET_RTX_NAME (i)))
+ {
+ tmp_code = (RTX_CODE) i; /* get value for name */
+ break;
+ }
+
if (tmp_code == UNKNOWN)
- {
- fprintf (stderr,
- "Unknown rtx read in rtl.read_rtx(). Code name was %s .",
- tmp_char);
- }
+ fatal_with_file_and_line (infile, "unknown rtx code `%s'", tmp_char);
+
/* (NIL) stands for an expression that isn't there. */
if (tmp_code == NIL)
{
/* Discard the closeparen. */
- while ((c = getc (infile)) && c != ')');
+ while ((c = getc (infile)) && c != ')')
+ ;
+
return 0;
}
- return_rtx = rtx_alloc (tmp_code); /* if we end up with an insn expression
- then we free this space below. */
+ /* If we end up with an insn expression then we free this space below. */
+ return_rtx = rtx_alloc (tmp_code);
format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx));
/* If what follows is `: mode ', read it and
i = read_skip_spaces (infile);
if (i == ':')
{
- register int k;
read_name (tmp_char, infile);
- for (k = 0; k < NUM_MACHINE_MODES; k++)
- if (!strcmp (GET_MODE_NAME (k), tmp_char))
+ for (j = 0; j < NUM_MACHINE_MODES; j++)
+ if (! strcmp (GET_MODE_NAME (j), tmp_char))
break;
- PUT_MODE (return_rtx, (enum machine_mode) k );
+ if (j == MAX_MACHINE_MODE)
+ fatal_with_file_and_line (infile, "unknown mode `%s'", tmp_char);
+
+ PUT_MODE (return_rtx, (enum machine_mode) j);
}
else
ungetc (i, infile);
break;
}
/* Now process the vector. */
-
+
case 'E':
{
- register struct rtx_list *next_rtx, *rtx_list_link;
- struct rtx_list *list_rtx = NULL;
+ /* Obstack to store scratch vector in. */
+ struct obstack vector_stack;
+ int list_counter = 0;
+ rtvec return_vec = NULL_RTVEC;
c = read_skip_spaces (infile);
if (c != '[')
- dump_and_abort ('[', c, infile);
+ fatal_expected_char (infile, '[', c);
/* add expressions to a list, while keeping a count */
- next_rtx = NULL;
- list_counter = 0;
+ obstack_init (&vector_stack);
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;
+ obstack_ptr_grow (&vector_stack, (PTR) read_rtx (infile));
}
- /* 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;
+ return_vec = rtvec_alloc (list_counter);
+ memcpy (&return_vec->elem[0], obstack_finish (&vector_stack),
+ list_counter * sizeof (rtx));
}
+ XVEC (return_rtx, i) = return_vec;
+ obstack_free (&vector_stack, NULL);
/* close bracket gotten */
}
break;
case 's':
{
- int saw_paren = 0;
- register char *stringbuf;
-
- c = read_skip_spaces (infile);
- if (c == '(')
+ char *stringbuf;
+
+ stringbuf = read_string (&rtl_obstack, infile);
+
+ /* For insn patterns, we want to provide a default name
+ based on the file and line, like "*foo.md:12", if the
+ given name is blank. These are only for define_insn and
+ define_insn_and_split, to aid debugging. */
+ if (*stringbuf == '\0'
+ && i == 0
+ && (GET_CODE (return_rtx) == DEFINE_INSN
+ || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
{
- saw_paren = 1;
- c = read_skip_spaces (infile);
+ char line_name[20];
+ const char *fn = (read_rtx_filename ? read_rtx_filename : "rtx");
+ const char *slash;
+ for (slash = fn; *slash; slash ++)
+ if (*slash == '/' || *slash == '\\' || *slash == ':')
+ fn = slash + 1;
+ obstack_1grow (&rtl_obstack, '*');
+ obstack_grow (&rtl_obstack, fn, strlen (fn));
+ sprintf (line_name, ":%d", read_rtx_lineno);
+ obstack_grow (&rtl_obstack, line_name, strlen (line_name)+1);
+ stringbuf = (char *) obstack_finish (&rtl_obstack);
}
- 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;
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
tmp_wide = atol (tmp_char);
#else
- /* Prefer atoll over atoq, since the former is in the ISO C9X draft.
+ /* Prefer atoll over atoq, since the former is in the ISO C99 standard.
But prefer not to use our hand-rolled function above either. */
#if defined(HAVE_ATOLL) || !defined(HAVE_ATOQ)
tmp_wide = atoll (tmp_char);
c = read_skip_spaces (infile);
if (c != ')')
- dump_and_abort (')', c, infile);
+ fatal_expected_char (infile, ')', c);
return return_rtx;
}
-\f
-/* This is called once per compilation, before any rtx's are constructed.
- It initializes the vector `rtx_length', the extra CC modes, if any,
- and computes certain commonly-used modes. */
+#if defined ENABLE_RTL_CHECKING && (GCC_VERSION >= 2007)
void
-init_rtl ()
+rtl_check_failed_bounds (r, n, file, line, func)
+ rtx r;
+ int n;
+ const char *file;
+ int line;
+ const char *func;
{
- int min_class_size[(int) MAX_MODE_CLASS];
- enum machine_mode mode;
- int i;
+ 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);
+}
- for (i = 0; i < NUM_RTX_CODE; i++)
- rtx_length[i] = strlen (rtx_format[i]);
-
- /* Make CONST_DOUBLE bigger, if real values are bigger than
- it normally expects to have room for.
- Note that REAL_VALUE_TYPE is not defined by default,
- since tree.h is not included. But the default dfn as `double'
- would do no harm. */
-#ifdef REAL_VALUE_TYPE
- i = sizeof (REAL_VALUE_TYPE) / sizeof (rtunion) + 2;
- if (rtx_length[(int) CONST_DOUBLE] < i)
- {
- char *s = (char *) xmalloc (i + 1);
- rtx_length[(int) CONST_DOUBLE] = i;
- rtx_format[(int) CONST_DOUBLE] = s;
- *s++ = 'e';
- *s++ = '0';
- /* Set the GET_RTX_FORMAT of CONST_DOUBLE to a string
- of as many `w's as we now have elements. Subtract two from
- the size to account for the 'e' and the '0'. */
- for (i = 2; i < rtx_length[(int) CONST_DOUBLE]; i++)
- *s++ = 'w';
- *s++ = 0;
- }
-#endif
+void
+rtl_check_failed_type1 (r, n, c1, file, line, func)
+ rtx r;
+ int n;
+ int c1;
+ const char *file;
+ int line;
+ const char *func;
+{
+ 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);
+}
-#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
+void
+rtl_check_failed_type2 (r, n, c1, c2, file, line, func)
+ rtx r;
+ int n;
+ int c1;
+ int c2;
+ const char *file;
+ int line;
+ const char *func;
+{
+ 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);
+}
- /* Find the narrowest mode for each class. */
+void
+rtl_check_failed_code1 (r, code, file, line, func)
+ 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);
+}
- for (i = 0; i < (int) MAX_MODE_CLASS; i++)
- min_class_size[i] = 1000;
+void
+rtl_check_failed_code2 (r, code1, code2, file, line, func)
+ rtx r;
+ enum rtx_code code1, code2;
+ const char *file;
+ int line;
+ const char *func;
+{
+ 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);
- }
- }
+/* XXX Maybe print the vector? */
+void
+rtvec_check_failed_bounds (r, n, file, line, func)
+ rtvec r;
+ int n;
+ const char *file;
+ int line;
+ const char *func;
+{
+ internal_error
+ ("RTL check: access of elt %d of vector with last elt %d in %s, at %s:%d",
+ n, GET_NUM_ELEM (r) - 1, func, trim_filename (file), line);
}
+#endif /* ENABLE_RTL_CHECKING */