X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Frtl.c;h=edf393f29d2e661d8f6f96a2a1dbc28c2bac6944;hp=3a5a4876c5bdc2b69c3268767d1a54c2c8127b07;hb=c262fafbaed44fb47ad6f89686305e9f38aa2369;hpb=a194077bf91f85c40331e00ec89f691becb6c2d3 diff --git a/gcc/rtl.c b/gcc/rtl.c index 3a5a4876c5b..edf393f29d2 100644 --- a/gcc/rtl.c +++ b/gcc/rtl.c @@ -1,109 +1,50 @@ -/* Allocate and read RTL for GNU C Compiler. - Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000 - Free Software Foundation, Inc. +/* RTL utility routines. + Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2006, 2007 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 3, 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, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - +along with GCC; see the file COPYING3. If not see +. */ +/* This file is compiled twice: once for the generator programs + once for the compiler. */ +#ifdef GENERATOR_FILE +#include "bconfig.h" +#else #include "config.h" +#endif + #include "system.h" +#include "coretypes.h" +#include "tm.h" #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 - - -/* 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" +#ifdef GENERATOR_FILE +# include "errors.h" #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 +# include "toplev.h" #endif + /* Indexed by rtx code, gives number of operands for an rtx with that code. Does NOT include rtx header data (code and links). */ #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) sizeof FORMAT - 1 , -const int rtx_length[NUM_RTX_CODE + 1] = { +const unsigned char rtx_length[NUM_RTX_CODE] = { #include "rtl.def" }; @@ -113,118 +54,17 @@ const int rtx_length[NUM_RTX_CODE + 1] = { #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) NAME , -const char * const rtx_name[] = { +const char * const rtx_name[NUM_RTX_CODE] = { #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, BITSIZE, SIZE, UNIT, WIDER) NAME, - -const char * const mode_name[(int) MAX_MACHINE_MODE + 1] = { -#include "machmode.def" - /* 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 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, BITSIZE, SIZE, UNIT, WIDER) BITSIZE, - -const unsigned int mode_bitsize[(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, BITSIZE, SIZE, UNIT, WIDER) SIZE, - -const unsigned 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, BITSIZE, SIZE, UNIT, WIDER) UNIT, - -const unsigned 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, BITSIZE, SIZE, UNIT, WIDER) \ - (unsigned char) WIDER, - -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, 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. */ - -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. - 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 -}; - - /* 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. */ -const char * const 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) @@ -238,6 +78,8 @@ const char * const rtx_format[] = { 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 @@ -247,7 +89,8 @@ const char * const rtx_format[] = { "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. */ + "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 */ @@ -257,127 +100,156 @@ const char * const rtx_format[] = { /* Indexed by rtx code, gives a character representing the "class" of that rtx code. See rtl.def for documentation on the defined classes. */ -const char rtx_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_code_size[NUM_RTX_CODE] = { +#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) \ + ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE || (ENUM) == CONST_FIXED\ + ? 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 +}; + /* Names for kinds of NOTEs and REG_NOTEs. */ -const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS] = +const char * const note_insn_name[NOTE_INSN_MAX] = { - "", "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" +#define DEF_INSN_NOTE(NAME) #NAME, +#include "insn-notes.def" +#undef DEF_INSN_NOTE }; -const char * const reg_note_name[] = +const char * const reg_note_name[REG_NOTE_MAX] = { - "", "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" +#define DEF_REG_NOTE(NAME) #NAME, +#include "reg-notes.def" +#undef DEF_REG_NOTE }; -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 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)); +#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 /* 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; rt = ggc_alloc_rtvec (n); - /* clear out the vector */ + /* Clear out the vector. */ memset (&rt->elem[0], 0, n * sizeof (rtx)); PUT_NUM_ELEM (rt, n); + +#ifdef GATHER_STATISTICS + rtvec_alloc_counts++; + rtvec_alloc_sizes += n * sizeof (rtx); +#endif + return rt; } +/* Return the number of bytes occupied by rtx value X. */ + +unsigned int +rtx_size (const_rtx x) +{ + if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_HAS_BLOCK_INFO_P (x)) + return RTX_HDR_SIZE + sizeof (struct block_symbol); + return RTX_CODE_SIZE (GET_CODE (x)); +} + /* 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_alloc_stat (RTX_CODE code MEM_STAT_DECL) { rtx rt; - int n = GET_RTX_LENGTH (code); - rt = ggc_alloc_rtx (n); + rt = (rtx) ggc_alloc_zone_pass_stat (RTX_CODE_SIZE (code), &rtl_zone); /* 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)); + memset (rt, 0, RTX_HDR_SIZE); PUT_CODE (rt, code); + +#ifdef GATHER_STATISTICS + rtx_alloc_counts[code]++; + rtx_alloc_sizes[code] += RTX_CODE_SIZE (code); +#endif + return rt; } +/* Return true if ORIG is a sharable CONST. */ + +bool +shared_const_p (const_rtx orig) +{ + gcc_assert (GET_CODE (orig) == CONST); + + /* CONST can be shared if it contains a SYMBOL_REF. If it contains + a LABEL_REF, it isn't sharable. */ + return (GET_CODE (XEXP (orig, 0)) == PLUS + && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF + && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT); +} + + /* 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 const 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_FIXED: + case CONST_VECTOR: 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 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) + if (shared_const_p (orig)) return orig; break; @@ -390,201 +262,87 @@ copy_rtx (orig) 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 + /* Copy the various flags, fields, 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)); + copy = shallow_copy_rtx (orig); /* We do not copy the USED flag, which is used as a mark bit during walks over the RTL. */ - copy->used = 0; + RTX_FLAG (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': - if (XEXP (orig, i) != NULL) - XEXP (copy, i) = copy_rtx (XEXP (orig, i)); - break; - - case 'E': - case 'V': - 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 't': - case 'w': - case 'i': - case 's': - case 'S': - case 'u': - case '0': - /* These are left unchanged. */ - 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 const 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; - copy->frame_related = orig->frame_related; + 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++) - { - 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; - - case 'w': - XWINT (copy, i) = XWINT (orig, i); - break; - - case 'n': - case 'i': - XINT (copy, i) = XINT (orig, i); - break; - - case 't': - XTREE (copy, i) = XTREE (orig, i); - break; + switch (*format_ptr++) + { + case 'e': + if (XEXP (orig, i) != NULL) + XEXP (copy, i) = copy_rtx (XEXP (orig, i)); + break; - case 's': - case 'S': - XSTR (copy, i) = XSTR (orig, i); - break; + case 'E': + case 'V': + 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 '0': - /* Copy this through the wide int field; that's safest. */ - X0WINT (copy, i) = X0WINT (orig, i); - break; + case 't': + case 'w': + case 'i': + case 's': + case 'S': + case 'T': + case 'u': + case 'B': + case '0': + /* These are left unchanged. */ + break; - default: - abort (); - } - } + default: + gcc_unreachable (); + } return copy; } /* Create a new copy of an rtx. Only copy just one level. */ + rtx -shallow_copy_rtx (orig) - rtx orig; +shallow_copy_rtx_stat (const_rtx orig MEM_STAT_DECL) { - 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; + const unsigned int size = rtx_size (orig); + rtx const copy = (rtx) ggc_alloc_zone_pass_stat (size, &rtl_zone); + return memcpy (copy, orig, size); } -/* 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; + +/* Nonzero when we are expanding trees to RTL. */ +int currently_expanding_to_rtl; + /* 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; +rtx_equal_p (const_rtx x, const_rtx y) { - register int i; - register int j; - register enum rtx_code code; - register const char *fmt; + int i; + int j; + enum rtx_code code; + const char *fmt; if (x == y) return 1; @@ -606,13 +364,7 @@ rtx_equal_p (x, y) 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))); + return (REGNO (x) == REGNO (y)); case LABEL_REF: return XEXP (x, 0) == XEXP (y, 0); @@ -623,6 +375,7 @@ rtx_equal_p (x, y) case SCRATCH: case CONST_DOUBLE: case CONST_INT: + case CONST_FIXED: return 0; default: @@ -630,7 +383,7 @@ rtx_equal_p (x, y) } /* Compare the elements. If any pair of corresponding elements - fail to match, return 0 for the whole things. */ + fail to match, return 0 for the whole thing. */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) @@ -667,7 +420,9 @@ rtx_equal_p (x, y) case 'S': case 's': - if (strcmp (XSTR (x, i), XSTR (y, i))) + if ((XSTR (x, i) || XSTR (y, i)) + && (! XSTR (x, i) || ! XSTR (y, i) + || strcmp (XSTR (x, i), XSTR (y, i)))) return 0; break; @@ -683,622 +438,57 @@ rtx_equal_p (x, y) contain anything but integers and other rtx's, except for within LABEL_REFs and SYMBOL_REFs. */ default: - abort (); + gcc_unreachable (); } } return 1; } - -/* Subroutines of read_rtx. */ - -/* 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 = ""; - -static void -fatal_with_file_and_line VPARAMS ((FILE *infile, const char *msg, ...)) -{ -#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 (c == EOF) - break; - if (c == '\r' || c == '\n') - break; - context[i] = c; - } - 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 - 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 (1) - { - c = getc (infile); - switch (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; - } - } -} - -/* 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) - 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); - } -} - -/* 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 - -/* 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 - the utilities gen*.c that construct C code from machine descriptions. */ - -rtx -read_rtx (infile) - FILE *infile; +dump_rtx_statistics (void) { - register int i, j, list_counter; - RTX_CODE tmp_code; - 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. */ - char tmp_char[256]; - rtx return_rtx; - register int c; - 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. */ - }; - - 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 != '(') - fatal_expected_char (infile, '(', c); - - read_name (tmp_char, infile); - - tmp_code = UNKNOWN; - - if (! strcmp (tmp_char, "define_constants")) - { - read_constants (infile, tmp_char); - goto again; - } - for (i = 0; i < NUM_RTX_CODE; i++) - if (! strcmp (tmp_char, GET_RTX_NAME (i))) +#ifdef GATHER_STATISTICS + int 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]) { - tmp_code = (RTX_CODE) i; /* get value for name */ - break; + 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 (tmp_code == UNKNOWN) - 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 != ')') - ; - - return 0; - } - - /* 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 - store the mode in the rtx. */ - - i = read_skip_spaces (infile); - if (i == ':') + if (rtvec_alloc_counts) { - read_name (tmp_char, infile); - for (j = 0; j < NUM_MACHINE_MODES; j++) - if (! strcmp (GET_MODE_NAME (j), tmp_char)) - break; - - if (j == MAX_MACHINE_MODE) - fatal_with_file_and_line (infile, "unknown mode `%s'", tmp_char); - - PUT_MODE (return_rtx, (enum machine_mode) j); + fprintf (stderr, "%-20s %7d %10d\n", "rtvec", + rtvec_alloc_counts, rtvec_alloc_sizes); + total_counts += rtvec_alloc_counts; + total_sizes += rtvec_alloc_sizes; } - 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 != '[') - fatal_expected_char (infile, '[', c); - - /* 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; - int saw_anything = 0; - - c = read_skip_spaces (infile); - if (c == '(') - { - saw_paren = 1; - c = read_skip_spaces (infile); - } - if (c != '"') - fatal_expected_char (infile, '"', c); - - while (1) - { - c = getc (infile); /* Read the string */ - if (c == '\n') - read_rtx_lineno++; - if (c == '\\') - { - c = getc (infile); /* Read the string */ - /* \; makes stuff for a C string constant containing - newline and tab. */ - if (c == ';') - { - obstack_grow (&rtl_obstack, "\\n\\t", 4); - continue; - } - if (c == '\n') - read_rtx_lineno++; - } - else if (c == '"') - break; - - obstack_1grow (&rtl_obstack, c); - saw_anything = 1; - } - - /* 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 (!saw_anything - && i == 0 - && (GET_CODE (return_rtx) == DEFINE_INSN - || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT)) - { - 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)); - } - - obstack_1grow (&rtl_obstack, 0); - stringbuf = (char *) obstack_finish (&rtl_obstack); - - if (saw_paren) - { - c = read_skip_spaces (infile); - if (c != ')') - fatal_expected_char (infile, ')', c); - } - 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 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); -#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 != ')') - fatal_expected_char (infile, ')', c); - - return return_rtx; + fprintf (stderr, "---------------------------------------\n"); + fprintf (stderr, "%-20s %7d %10d\n", + "Total", total_counts, total_sizes); + fprintf (stderr, "---------------------------------------\n"); +#endif } - + #if defined ENABLE_RTL_CHECKING && (GCC_VERSION >= 2007) void -rtl_check_failed_bounds (r, n, file, line, func) - rtx r; - int n; - const char *file; - int line; - const char *func; +rtl_check_failed_bounds (const_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", + ("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); } 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; +rtl_check_failed_type1 (const_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", @@ -1307,14 +497,8 @@ rtl_check_failed_type1 (r, n, c1, file, line, func) } 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; +rtl_check_failed_type2 (const_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", @@ -1323,43 +507,68 @@ rtl_check_failed_type2 (r, n, c1, c2, file, line, func) } void -rtl_check_failed_code1 (r, code, file, line, func) - rtx r; - enum rtx_code code; - const char *file; - int line; - const char *func; +rtl_check_failed_code1 (const_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", + 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); } 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; +rtl_check_failed_code2 (const_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", + ("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); } +void +rtl_check_failed_code_mode (const_rtx r, enum rtx_code code, enum machine_mode mode, + bool not_mode, const char *file, int line, + const char *func) +{ + internal_error ((not_mode + ? ("RTL check: expected code '%s' and not mode '%s', " + "have code '%s' and mode '%s' in %s, at %s:%d") + : ("RTL check: expected code '%s' and mode '%s', " + "have code '%s' and mode '%s' in %s, at %s:%d")), + GET_RTX_NAME (code), GET_MODE_NAME (mode), + GET_RTX_NAME (GET_CODE (r)), GET_MODE_NAME (GET_MODE (r)), + func, trim_filename (file), line); +} + +/* Report that line LINE of FILE tried to access the block symbol fields + of a non-block symbol. FUNC is the function that contains the line. */ + +void +rtl_check_failed_block_symbol (const char *file, int line, const char *func) +{ + internal_error + ("RTL check: attempt to treat non-block symbol as a block symbol " + "in %s, at %s:%d", func, trim_filename (file), line); +} + /* 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; +rtvec_check_failed_bounds (const_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 */ + +#if defined ENABLE_RTL_FLAG_CHECKING +void +rtl_check_failed_flag (const char *name, const_rtx r, const char *file, + int line, const char *func) +{ + 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 /* ENABLE_RTL_FLAG_CHECKING */