X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Femit-rtl.c;h=4d40705d1bcf85f4abae9f2233fa1917a39e549d;hb=34d2ae7f01a3522bde5149aef4a883795eb60004;hp=6558fa73fe95030cf20d15ab6f4516780769f293;hpb=7ba6ce7a6ab4d6fa5dd7fa5e86d69a461036ebb5;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 6558fa73fe9..4d40705d1bc 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -1,6 +1,6 @@ /* Emit RTL for the GCC expander. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -22,18 +22,16 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* Middle-to-low level generation of rtx code and insns. - This file contains the functions `gen_rtx', `gen_reg_rtx' - and `gen_label_rtx' that are the usual ways of creating rtl - expressions for most purposes. - - It also has the functions for creating insns and linking - them in the doubly-linked chain. + This file contains support functions for creating rtl expressions + and manipulating them in the doubly-linked chain of insns. The patterns of the insns are created by machine-dependent routines in insn-emit.c, which is generated automatically from - the machine description. These routines use `gen_rtx' to make - the individual rtx's of the pattern; what is machine dependent - is the kind of rtx's they make and what arguments they use. */ + the machine description. These routines make the individual rtx's + of the pattern with `gen_rtx_fmt_ee' and others in genrtl.[ch], + which are automatically generated from rtl.def; what is machine + dependent is the kind of rtx's they make and what arguments they + use. */ #include "config.h" #include "system.h" @@ -609,6 +607,17 @@ gen_rtx_MEM (enum machine_mode mode, rtx addr) return rt; } +/* Generate a memory referring to non-trapping constant memory. */ + +rtx +gen_const_mem (enum machine_mode mode, rtx addr) +{ + rtx mem = gen_rtx_MEM (mode, addr); + MEM_READONLY_P (mem) = 1; + MEM_NOTRAP_P (mem) = 1; + return mem; +} + rtx gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset) { @@ -643,119 +652,6 @@ gen_lowpart_SUBREG (enum machine_mode mode, rtx reg) subreg_lowpart_offset (mode, inmode)); } -/* rtx gen_rtx (code, mode, [element1, ..., elementn]) -** -** This routine generates an RTX of the size specified by -** , which is an RTX code. The RTX structure is initialized -** from the arguments through , which are -** interpreted according to the specific RTX type's format. The -** special machine mode associated with the rtx (if any) is specified -** in . -** -** gen_rtx can be invoked in a way which resembles the lisp-like -** rtx it will generate. For example, the following rtx structure: -** -** (plus:QI (mem:QI (reg:SI 1)) -** (mem:QI (plusw:SI (reg:SI 2) (reg:SI 3)))) -** -** ...would be generated by the following C code: -** -** gen_rtx (PLUS, QImode, -** gen_rtx (MEM, QImode, -** gen_rtx (REG, SImode, 1)), -** gen_rtx (MEM, QImode, -** gen_rtx (PLUS, SImode, -** gen_rtx (REG, SImode, 2), -** gen_rtx (REG, SImode, 3)))), -*/ - -/*VARARGS2*/ -rtx -gen_rtx (enum rtx_code code, enum machine_mode mode, ...) -{ - int i; /* Array indices... */ - const char *fmt; /* Current rtx's format... */ - rtx rt_val; /* RTX to return to caller... */ - va_list p; - - va_start (p, mode); - - switch (code) - { - case CONST_INT: - rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT)); - break; - - case CONST_DOUBLE: - { - HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT); - HOST_WIDE_INT arg1 = va_arg (p, HOST_WIDE_INT); - - rt_val = immed_double_const (arg0, arg1, mode); - } - break; - - case REG: - rt_val = gen_rtx_REG (mode, va_arg (p, int)); - break; - - case MEM: - rt_val = gen_rtx_MEM (mode, va_arg (p, rtx)); - break; - - default: - rt_val = rtx_alloc (code); /* Allocate the storage space. */ - rt_val->mode = mode; /* Store the machine mode... */ - - fmt = GET_RTX_FORMAT (code); /* Find the right format... */ - for (i = 0; i < GET_RTX_LENGTH (code); i++) - { - switch (*fmt++) - { - case '0': /* Field with unknown use. Zero it. */ - X0EXP (rt_val, i) = NULL_RTX; - break; - - case 'i': /* An integer? */ - XINT (rt_val, i) = va_arg (p, int); - break; - - case 'w': /* A wide integer? */ - XWINT (rt_val, i) = va_arg (p, HOST_WIDE_INT); - break; - - case 's': /* A string? */ - XSTR (rt_val, i) = va_arg (p, char *); - break; - - case 'e': /* An expression? */ - case 'u': /* An insn? Same except when printing. */ - XEXP (rt_val, i) = va_arg (p, rtx); - break; - - case 'E': /* An RTX vector? */ - XVEC (rt_val, i) = va_arg (p, rtvec); - break; - - case 'b': /* A bitmap? */ - XBITMAP (rt_val, i) = va_arg (p, bitmap); - break; - - case 't': /* A tree? */ - XTREE (rt_val, i) = va_arg (p, tree); - break; - - default: - abort (); - } - } - break; - } - - va_end (p); - return rt_val; -} - /* gen_rtvec (n, [rt1, ..., rtn]) ** ** This routine creates an rtvec and stores within it the @@ -861,13 +757,96 @@ gen_reg_rtx (enum machine_mode mode) return val; } -/* Generate a register with same attributes as REG, - but offsetted by OFFSET. */ +/* Generate a register with same attributes as REG, but offsetted by OFFSET. + Do the big endian correction if needed. */ rtx gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, int offset) { rtx new = gen_rtx_REG (mode, regno); + tree decl; + HOST_WIDE_INT var_size; + + /* PR middle-end/14084 + The problem appears when a variable is stored in a larger register + and later it is used in the original mode or some mode in between + or some part of variable is accessed. + + On little endian machines there is no problem because + the REG_OFFSET of the start of the variable is the same when + accessed in any mode (it is 0). + + However, this is not true on big endian machines. + The offset of the start of the variable is different when accessed + in different modes. + When we are taking a part of the REG we have to change the OFFSET + from offset WRT size of mode of REG to offset WRT size of variable. + + If we would not do the big endian correction the resulting REG_OFFSET + would be larger than the size of the DECL. + + Examples of correction, for BYTES_BIG_ENDIAN WORDS_BIG_ENDIAN machine: + + REG.mode MODE DECL size old offset new offset description + DI SI 4 4 0 int32 in SImode + DI SI 1 4 0 char in SImode + DI QI 1 7 0 char in QImode + DI QI 4 5 1 1st element in QImode + of char[4] + DI HI 4 6 2 1st element in HImode + of int16[2] + + If the size of DECL is equal or greater than the size of REG + we can't do this correction because the register holds the + whole variable or a part of the variable and thus the REG_OFFSET + is already correct. */ + + decl = REG_EXPR (reg); + if ((BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN) + && decl != NULL + && offset > 0 + && GET_MODE_SIZE (GET_MODE (reg)) > GET_MODE_SIZE (mode) + && ((var_size = int_size_in_bytes (TREE_TYPE (decl))) > 0 + && var_size < GET_MODE_SIZE (GET_MODE (reg)))) + { + int offset_le; + + /* Convert machine endian to little endian WRT size of mode of REG. */ + if (WORDS_BIG_ENDIAN) + offset_le = ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset) + / UNITS_PER_WORD) * UNITS_PER_WORD; + else + offset_le = (offset / UNITS_PER_WORD) * UNITS_PER_WORD; + + if (BYTES_BIG_ENDIAN) + offset_le += ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset) + % UNITS_PER_WORD); + else + offset_le += offset % UNITS_PER_WORD; + + if (offset_le >= var_size) + { + /* MODE is wider than the variable so the new reg will cover + the whole variable so the resulting OFFSET should be 0. */ + offset = 0; + } + else + { + /* Convert little endian to machine endian WRT size of variable. */ + if (WORDS_BIG_ENDIAN) + offset = ((var_size - 1 - offset_le) + / UNITS_PER_WORD) * UNITS_PER_WORD; + else + offset = (offset_le / UNITS_PER_WORD) * UNITS_PER_WORD; + + if (BYTES_BIG_ENDIAN) + offset += ((var_size - 1 - offset_le) + % UNITS_PER_WORD); + else + offset += offset_le % UNITS_PER_WORD; + } + } + REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg), REG_OFFSET (reg) + offset); return new; @@ -889,7 +868,7 @@ set_reg_attrs_from_mem (rtx reg, rtx mem) void set_reg_attrs_for_parm (rtx parm_rtx, rtx mem) { - if (GET_CODE (parm_rtx) == REG) + if (REG_P (parm_rtx)) set_reg_attrs_from_mem (parm_rtx, mem); else if (GET_CODE (parm_rtx) == PARALLEL) { @@ -899,7 +878,7 @@ set_reg_attrs_for_parm (rtx parm_rtx, rtx mem) for (; i < XVECLEN (parm_rtx, 0); i++) { rtx x = XVECEXP (parm_rtx, 0, i); - if (GET_CODE (XEXP (x, 0)) == REG) + if (REG_P (XEXP (x, 0))) REG_ATTRS (XEXP (x, 0)) = get_reg_attrs (MEM_EXPR (mem), INTVAL (XEXP (x, 1))); @@ -916,7 +895,7 @@ set_decl_rtl (tree t, rtx x) if (!x) return; /* For register, we maintain the reverse information too. */ - if (GET_CODE (x) == REG) + if (REG_P (x)) REG_ATTRS (x) = get_reg_attrs (t, 0); else if (GET_CODE (x) == SUBREG) REG_ATTRS (SUBREG_REG (x)) @@ -941,6 +920,48 @@ set_decl_rtl (tree t, rtx x) } } +/* Assign the RTX X to parameter declaration T. */ +void +set_decl_incoming_rtl (tree t, rtx x) +{ + DECL_INCOMING_RTL (t) = x; + + if (!x) + return; + /* For register, we maintain the reverse information too. */ + if (REG_P (x)) + REG_ATTRS (x) = get_reg_attrs (t, 0); + else if (GET_CODE (x) == SUBREG) + REG_ATTRS (SUBREG_REG (x)) + = get_reg_attrs (t, -SUBREG_BYTE (x)); + if (GET_CODE (x) == CONCAT) + { + if (REG_P (XEXP (x, 0))) + REG_ATTRS (XEXP (x, 0)) = get_reg_attrs (t, 0); + if (REG_P (XEXP (x, 1))) + REG_ATTRS (XEXP (x, 1)) + = get_reg_attrs (t, GET_MODE_UNIT_SIZE (GET_MODE (XEXP (x, 0)))); + } + if (GET_CODE (x) == PARALLEL) + { + int i, start; + + /* Check for a NULL entry, used to indicate that the parameter goes + both on the stack and in registers. */ + if (XEXP (XVECEXP (x, 0, 0), 0)) + start = 0; + else + start = 1; + + for (i = start; i < XVECLEN (x, 0); i++) + { + rtx y = XVECEXP (x, 0, i); + if (REG_P (XEXP (y, 0))) + REG_ATTRS (XEXP (y, 0)) = get_reg_attrs (t, INTVAL (XEXP (y, 1))); + } + } +} + /* Identify REG (which may be a CONCAT) as a user register. */ void @@ -951,7 +972,7 @@ mark_user_reg (rtx reg) REG_USERVAR_P (XEXP (reg, 0)) = 1; REG_USERVAR_P (XEXP (reg, 1)) = 1; } - else if (GET_CODE (reg) == REG) + else if (REG_P (reg)) REG_USERVAR_P (reg) = 1; else abort (); @@ -1000,6 +1021,17 @@ get_first_label_num (void) { return first_label_num; } + +/* If the rtx for label was created during the expansion of a nested + function, then first_label_num won't include this label number. + Fix this now so that array indicies work later. */ + +void +maybe_set_first_label_num (rtx x) +{ + if (CODE_LABEL_NUMBER (x) < first_label_num) + first_label_num = CODE_LABEL_NUMBER (x); +} /* Return the final regno of X, which is a SUBREG of a hard register. */ @@ -1013,7 +1045,7 @@ subreg_hard_regno (rtx x, int check_mode) /* This is where we attempt to catch illegal subregs created by the compiler. */ if (GET_CODE (x) != SUBREG - || GET_CODE (reg) != REG) + || !REG_P (reg)) abort (); base_regno = REGNO (reg); if (base_regno >= FIRST_PSEUDO_REGISTER) @@ -1050,24 +1082,36 @@ rtx gen_lowpart_common (enum machine_mode mode, rtx x) { int msize = GET_MODE_SIZE (mode); - int xsize = GET_MODE_SIZE (GET_MODE (x)); + int xsize; int offset = 0; + enum machine_mode innermode; + + /* Unfortunately, this routine doesn't take a parameter for the mode of X, + so we have to make one up. Yuk. */ + innermode = GET_MODE (x); + if (GET_CODE (x) == CONST_INT && msize <= HOST_BITS_PER_WIDE_INT) + innermode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0); + else if (innermode == VOIDmode) + innermode = mode_for_size (HOST_BITS_PER_WIDE_INT * 2, MODE_INT, 0); + + xsize = GET_MODE_SIZE (innermode); + + if (innermode == VOIDmode || innermode == BLKmode) + abort (); - if (GET_MODE (x) == mode) + if (innermode == mode) return x; /* MODE must occupy no more words than the mode of X. */ - if (GET_MODE (x) != VOIDmode - && ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD - > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))) + if ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD + > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)) return 0; /* Don't allow generating paradoxical FLOAT_MODE subregs. */ - if (GET_MODE_CLASS (mode) == MODE_FLOAT - && GET_MODE (x) != VOIDmode && msize > xsize) + if (GET_MODE_CLASS (mode) == MODE_FLOAT && msize > xsize) return 0; - offset = subreg_lowpart_offset (mode, GET_MODE (x)); + offset = subreg_lowpart_offset (mode, innermode); if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND) && (GET_MODE_CLASS (mode) == MODE_INT @@ -1083,154 +1127,15 @@ gen_lowpart_common (enum machine_mode mode, rtx x) if (GET_MODE (XEXP (x, 0)) == mode) return XEXP (x, 0); - else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))) + else if (msize < GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))) return gen_lowpart_common (mode, XEXP (x, 0)); - else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))) + else if (msize < xsize) return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0)); } - else if (GET_CODE (x) == SUBREG || GET_CODE (x) == REG - || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR) - return simplify_gen_subreg (mode, x, GET_MODE (x), offset); - else if (VECTOR_MODE_P (mode) && GET_MODE (x) == VOIDmode) - return simplify_gen_subreg (mode, x, int_mode_for_mode (mode), offset); - /* If X is a CONST_INT or a CONST_DOUBLE, extract the appropriate bits - from the low-order part of the constant. */ - else if ((GET_MODE_CLASS (mode) == MODE_INT - || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) - && GET_MODE (x) == VOIDmode - && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)) - { - /* If MODE is twice the host word size, X is already the desired - representation. Otherwise, if MODE is wider than a word, we can't - do this. If MODE is exactly a word, return just one CONST_INT. */ - - if (GET_MODE_BITSIZE (mode) >= 2 * HOST_BITS_PER_WIDE_INT) - return x; - else if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT) - return 0; - else if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT) - return (GET_CODE (x) == CONST_INT ? x - : GEN_INT (CONST_DOUBLE_LOW (x))); - else - { - /* MODE must be narrower than HOST_BITS_PER_WIDE_INT. */ - HOST_WIDE_INT val = (GET_CODE (x) == CONST_INT ? INTVAL (x) - : CONST_DOUBLE_LOW (x)); - - /* Sign extend to HOST_WIDE_INT. */ - val = trunc_int_for_mode (val, mode); - - return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x - : GEN_INT (val)); - } - } - - /* The floating-point emulator can handle all conversions between - FP and integer operands. This simplifies reload because it - doesn't have to deal with constructs like (subreg:DI - (const_double:SF ...)) or (subreg:DF (const_int ...)). */ - /* Single-precision floats are always 32-bits and double-precision - floats are always 64-bits. */ - - else if (GET_MODE_CLASS (mode) == MODE_FLOAT - && GET_MODE_BITSIZE (mode) == 32 - && GET_CODE (x) == CONST_INT) - { - REAL_VALUE_TYPE r; - long i = INTVAL (x); - - real_from_target (&r, &i, mode); - return CONST_DOUBLE_FROM_REAL_VALUE (r, mode); - } - else if (GET_MODE_CLASS (mode) == MODE_FLOAT - && GET_MODE_BITSIZE (mode) == 64 - && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) - && GET_MODE (x) == VOIDmode) - { - REAL_VALUE_TYPE r; - HOST_WIDE_INT low, high; - long i[2]; - - if (GET_CODE (x) == CONST_INT) - { - low = INTVAL (x); - high = low >> (HOST_BITS_PER_WIDE_INT - 1); - } - else - { - low = CONST_DOUBLE_LOW (x); - high = CONST_DOUBLE_HIGH (x); - } - - if (HOST_BITS_PER_WIDE_INT > 32) - high = low >> 31 >> 1; - - /* REAL_VALUE_TARGET_DOUBLE takes the addressing order of the - target machine. */ - if (WORDS_BIG_ENDIAN) - i[0] = high, i[1] = low; - else - i[0] = low, i[1] = high; - - real_from_target (&r, i, mode); - return CONST_DOUBLE_FROM_REAL_VALUE (r, mode); - } - else if ((GET_MODE_CLASS (mode) == MODE_INT - || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) - && GET_CODE (x) == CONST_DOUBLE - && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) - { - REAL_VALUE_TYPE r; - long i[4]; /* Only the low 32 bits of each 'long' are used. */ - int endian = WORDS_BIG_ENDIAN ? 1 : 0; - - /* Convert 'r' into an array of four 32-bit words in target word - order. */ - REAL_VALUE_FROM_CONST_DOUBLE (r, x); - switch (GET_MODE_BITSIZE (GET_MODE (x))) - { - case 32: - REAL_VALUE_TO_TARGET_SINGLE (r, i[3 * endian]); - i[1] = 0; - i[2] = 0; - i[3 - 3 * endian] = 0; - break; - case 64: - REAL_VALUE_TO_TARGET_DOUBLE (r, i + 2 * endian); - i[2 - 2 * endian] = 0; - i[3 - 2 * endian] = 0; - break; - case 96: - REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i + endian); - i[3 - 3 * endian] = 0; - break; - case 128: - REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i); - break; - default: - abort (); - } - /* Now, pack the 32-bit elements of the array into a CONST_DOUBLE - and return it. */ -#if HOST_BITS_PER_WIDE_INT == 32 - return immed_double_const (i[3 * endian], i[1 + endian], mode); -#else - if (HOST_BITS_PER_WIDE_INT != 64) - abort (); - - return immed_double_const ((((unsigned long) i[3 * endian]) - | ((HOST_WIDE_INT) i[1 + endian] << 32)), - (((unsigned long) i[2 - endian]) - | ((HOST_WIDE_INT) i[3 - 3 * endian] << 32)), - mode); -#endif - } - /* If MODE is a condition code and X is a CONST_INT, the value of X - must already have been "recognized" by the back-end, and we can - assume that it is valid for this mode. */ - else if (GET_MODE_CLASS (mode) == MODE_CC - && GET_CODE (x) == CONST_INT) - return x; + else if (GET_CODE (x) == SUBREG || REG_P (x) + || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR + || GET_CODE (x) == CONST_DOUBLE || GET_CODE (x) == CONST_INT) + return simplify_gen_subreg (mode, x, innermode, offset); /* Otherwise, we can't do this. */ return 0; @@ -1246,7 +1151,7 @@ gen_complex_constant_part (enum machine_mode mode, rtx x, int imagpart_p) { tree decl, part; - if (GET_CODE (x) == MEM + if (MEM_P (x) && GET_CODE (XEXP (x, 0)) == SYMBOL_REF) { decl = SYMBOL_REF_DECL (XEXP (x, 0)); @@ -1310,78 +1215,7 @@ gen_imagpart (enum machine_mode mode, rtx x) else return gen_highpart (mode, x); } - -/* Return 1 iff X, assumed to be a SUBREG, - refers to the real part of the complex value in its containing reg. - Complex values are always stored with the real part in the first word, - regardless of WORDS_BIG_ENDIAN. */ - -int -subreg_realpart_p (rtx x) -{ - if (GET_CODE (x) != SUBREG) - abort (); - - return ((unsigned int) SUBREG_BYTE (x) - < (unsigned int) GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x)))); -} -/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a value, - return an rtx (MEM, SUBREG, or CONST_INT) that refers to the - least-significant part of X. - MODE specifies how big a part of X to return; - it usually should not be larger than a word. - If X is a MEM whose address is a QUEUED, the value may be so also. */ - -rtx -gen_lowpart (enum machine_mode mode, rtx x) -{ - rtx result = gen_lowpart_common (mode, x); - - if (result) - return result; - else if (GET_CODE (x) == REG) - { - /* Must be a hard reg that's not valid in MODE. */ - result = gen_lowpart_common (mode, copy_to_reg (x)); - if (result == 0) - abort (); - return result; - } - else if (GET_CODE (x) == MEM) - { - /* The only additional case we can do is MEM. */ - int offset = 0; - - /* The following exposes the use of "x" to CSE. */ - if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD - && SCALAR_INT_MODE_P (GET_MODE (x)) - && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode), - GET_MODE_BITSIZE (GET_MODE (x))) - && ! no_new_pseudos) - return gen_lowpart (mode, force_reg (GET_MODE (x), x)); - - if (WORDS_BIG_ENDIAN) - offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) - - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); - - if (BYTES_BIG_ENDIAN) - /* Adjust the address so that the address-after-the-data - is unchanged. */ - offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) - - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); - - return adjust_address (x, mode, offset); - } - else if (GET_CODE (x) == ADDRESSOF) - return gen_lowpart (mode, force_reg (GET_MODE (x), x)); - else - abort (); -} - -/* Like `gen_lowpart', but refer to the most significant part. - This is used to access the imaginary part of a complex number. */ - rtx gen_highpart (enum machine_mode mode, rtx x) { @@ -1400,7 +1234,7 @@ gen_highpart (enum machine_mode mode, rtx x) /* simplify_gen_subreg is not guaranteed to return a valid operand for the target if we have a MEM. gen_highpart must return a valid operand, emitting code if necessary to do so. */ - if (result != NULL_RTX && GET_CODE (result) == MEM) + if (result != NULL_RTX && MEM_P (result)) result = validize_mem (result); if (!result) @@ -1481,162 +1315,6 @@ subreg_lowpart_p (rtx x) == SUBREG_BYTE (x)); } - -/* Helper routine for all the constant cases of operand_subword. - Some places invoke this directly. */ - -rtx -constant_subword (rtx op, int offset, enum machine_mode mode) -{ - int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD; - HOST_WIDE_INT val; - - /* If OP is already an integer word, return it. */ - if (GET_MODE_CLASS (mode) == MODE_INT - && GET_MODE_SIZE (mode) == UNITS_PER_WORD) - return op; - - /* The output is some bits, the width of the target machine's word. - A wider-word host can surely hold them in a CONST_INT. A narrower-word - host can't. */ - if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD - && GET_MODE_CLASS (mode) == MODE_FLOAT - && GET_MODE_BITSIZE (mode) == 64 - && GET_CODE (op) == CONST_DOUBLE) - { - long k[2]; - REAL_VALUE_TYPE rv; - - REAL_VALUE_FROM_CONST_DOUBLE (rv, op); - REAL_VALUE_TO_TARGET_DOUBLE (rv, k); - - /* We handle 32-bit and >= 64-bit words here. Note that the order in - which the words are written depends on the word endianness. - ??? This is a potential portability problem and should - be fixed at some point. - - We must exercise caution with the sign bit. By definition there - are 32 significant bits in K; there may be more in a HOST_WIDE_INT. - Consider a host with a 32-bit long and a 64-bit HOST_WIDE_INT. - So we explicitly mask and sign-extend as necessary. */ - if (BITS_PER_WORD == 32) - { - val = k[offset]; - val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; - return GEN_INT (val); - } -#if HOST_BITS_PER_WIDE_INT >= 64 - else if (BITS_PER_WORD >= 64 && offset == 0) - { - val = k[! WORDS_BIG_ENDIAN]; - val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32; - val |= (HOST_WIDE_INT) k[WORDS_BIG_ENDIAN] & 0xffffffff; - return GEN_INT (val); - } -#endif - else if (BITS_PER_WORD == 16) - { - val = k[offset >> 1]; - if ((offset & 1) == ! WORDS_BIG_ENDIAN) - val >>= 16; - val = ((val & 0xffff) ^ 0x8000) - 0x8000; - return GEN_INT (val); - } - else - abort (); - } - else if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD - && GET_MODE_CLASS (mode) == MODE_FLOAT - && GET_MODE_BITSIZE (mode) > 64 - && GET_CODE (op) == CONST_DOUBLE) - { - long k[4]; - REAL_VALUE_TYPE rv; - - REAL_VALUE_FROM_CONST_DOUBLE (rv, op); - REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k); - - if (BITS_PER_WORD == 32) - { - val = k[offset]; - val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; - return GEN_INT (val); - } -#if HOST_BITS_PER_WIDE_INT >= 64 - else if (BITS_PER_WORD >= 64 && offset <= 1) - { - val = k[offset * 2 + ! WORDS_BIG_ENDIAN]; - val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32; - val |= (HOST_WIDE_INT) k[offset * 2 + WORDS_BIG_ENDIAN] & 0xffffffff; - return GEN_INT (val); - } -#endif - else - abort (); - } - - /* Single word float is a little harder, since single- and double-word - values often do not have the same high-order bits. We have already - verified that we want the only defined word of the single-word value. */ - if (GET_MODE_CLASS (mode) == MODE_FLOAT - && GET_MODE_BITSIZE (mode) == 32 - && GET_CODE (op) == CONST_DOUBLE) - { - long l; - REAL_VALUE_TYPE rv; - - REAL_VALUE_FROM_CONST_DOUBLE (rv, op); - REAL_VALUE_TO_TARGET_SINGLE (rv, l); - - /* Sign extend from known 32-bit value to HOST_WIDE_INT. */ - val = l; - val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; - - if (BITS_PER_WORD == 16) - { - if ((offset & 1) == ! WORDS_BIG_ENDIAN) - val >>= 16; - val = ((val & 0xffff) ^ 0x8000) - 0x8000; - } - - return GEN_INT (val); - } - - /* The only remaining cases that we can handle are integers. - Convert to proper endianness now since these cases need it. - At this point, offset == 0 means the low-order word. - - We do not want to handle the case when BITS_PER_WORD <= HOST_BITS_PER_INT - in general. However, if OP is (const_int 0), we can just return - it for any word. */ - - if (op == const0_rtx) - return op; - - if (GET_MODE_CLASS (mode) != MODE_INT - || (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE) - || BITS_PER_WORD > HOST_BITS_PER_WIDE_INT) - return 0; - - if (WORDS_BIG_ENDIAN) - offset = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - offset; - - /* Find out which word on the host machine this value is in and get - it from the constant. */ - val = (offset / size_ratio == 0 - ? (GET_CODE (op) == CONST_INT ? INTVAL (op) : CONST_DOUBLE_LOW (op)) - : (GET_CODE (op) == CONST_INT - ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op))); - - /* Get the value we want into the low bits of val. */ - if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT) - val = ((val >> ((offset % size_ratio) * BITS_PER_WORD))); - - val = trunc_int_for_mode (val, word_mode); - - return GEN_INT (val); -} - /* Return subword OFFSET of operand OP. The word number, OFFSET, is interpreted as the word number starting at the low-order address. OFFSET 0 is the low-order word if not @@ -1682,7 +1360,7 @@ operand_subword (rtx op, unsigned int offset, int validate_address, enum machine return const0_rtx; /* Form a new MEM at the requested address. */ - if (GET_CODE (op) == MEM) + if (MEM_P (op)) { rtx new = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD); @@ -1720,7 +1398,7 @@ operand_subword_force (rtx op, unsigned int offset, enum machine_mode mode) { /* If this is a register which can not be accessed by words, copy it to a pseudo register. */ - if (GET_CODE (op) == REG) + if (REG_P (op)) op = copy_to_reg (op); else op = force_reg (mode, op); @@ -1778,19 +1456,13 @@ component_ref_for_mem_expr (tree ref) inner = component_ref_for_mem_expr (inner); else { - tree placeholder_ptr = 0; - /* Now remove any conversions: they don't change what the underlying - object is. Likewise for SAVE_EXPR. Also handle PLACEHOLDER_EXPR. */ + object is. Likewise for SAVE_EXPR. */ while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR || TREE_CODE (inner) == NON_LVALUE_EXPR || TREE_CODE (inner) == VIEW_CONVERT_EXPR - || TREE_CODE (inner) == SAVE_EXPR - || TREE_CODE (inner) == PLACEHOLDER_EXPR) - if (TREE_CODE (inner) == PLACEHOLDER_EXPR) - inner = find_placeholder (inner, &placeholder_ptr); - else - inner = TREE_OPERAND (inner, 0); + || TREE_CODE (inner) == SAVE_EXPR) + inner = TREE_OPERAND (inner, 0); if (! DECL_P (inner)) inner = NULL_TREE; @@ -1799,8 +1471,42 @@ component_ref_for_mem_expr (tree ref) if (inner == TREE_OPERAND (ref, 0)) return ref; else - return build (COMPONENT_REF, TREE_TYPE (ref), inner, - TREE_OPERAND (ref, 1)); + return build3 (COMPONENT_REF, TREE_TYPE (ref), inner, + TREE_OPERAND (ref, 1), NULL_TREE); +} + +/* Returns 1 if both MEM_EXPR can be considered equal + and 0 otherwise. */ + +int +mem_expr_equal_p (tree expr1, tree expr2) +{ + if (expr1 == expr2) + return 1; + + if (! expr1 || ! expr2) + return 0; + + if (TREE_CODE (expr1) != TREE_CODE (expr2)) + return 0; + + if (TREE_CODE (expr1) == COMPONENT_REF) + return + mem_expr_equal_p (TREE_OPERAND (expr1, 0), + TREE_OPERAND (expr2, 0)) + && mem_expr_equal_p (TREE_OPERAND (expr1, 1), /* field decl */ + TREE_OPERAND (expr2, 1)); + + if (TREE_CODE (expr1) == INDIRECT_REF) + return mem_expr_equal_p (TREE_OPERAND (expr1, 0), + TREE_OPERAND (expr2, 0)); + + /* Decls with different pointers can't be equal. */ + if (DECL_P (expr1)) + return 0; + + abort(); /* ARRAY_REFs, ARRAY_RANGE_REFs and BIT_FIELD_REFs should already + have been resolved here. */ } /* Given REF, a MEM, and T, either the type of X or the expression @@ -1841,12 +1547,10 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, front-end routine) and use it. */ alias = get_alias_set (t); - MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type); + MEM_VOLATILE_P (ref) |= TYPE_VOLATILE (type); MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type); - RTX_UNCHANGING_P (ref) - |= ((lang_hooks.honor_readonly - && (TYPE_READONLY (type) || TREE_READONLY (t))) - || (! TYPE_P (t) && TREE_CONSTANT (t))); + MEM_POINTER (ref) = POINTER_TYPE_P (type); + MEM_NOTRAP_P (ref) = TREE_THIS_NOTRAP (t); /* If we are making an object of this type, or if this is a DECL, we know that it is a scalar if the type is not an aggregate. */ @@ -1866,7 +1570,12 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, the expression. */ if (! TYPE_P (t)) { - maybe_set_unchanging (ref, t); + tree base = get_base_address (t); + if (base && DECL_P (base) + && TREE_READONLY (base) + && (TREE_STATIC (base) || DECL_EXTERNAL (base))) + MEM_READONLY_P (ref) = 1; + if (TREE_THIS_VOLATILE (t)) MEM_VOLATILE_P (ref) = 1; @@ -1929,34 +1638,22 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, do { tree index = TREE_OPERAND (t2, 1); - tree array = TREE_OPERAND (t2, 0); - tree domain = TYPE_DOMAIN (TREE_TYPE (array)); - tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0); - tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array))); + tree low_bound = array_ref_low_bound (t2); + tree unit_size = array_ref_element_size (t2); /* We assume all arrays have sizes that are a multiple of a byte. First subtract the lower bound, if any, in the type of the - index, then convert to sizetype and multiply by the size of the - array element. */ - if (low_bound != 0 && ! integer_zerop (low_bound)) - index = fold (build (MINUS_EXPR, TREE_TYPE (index), - index, low_bound)); - - /* If the index has a self-referential type, pass it to a - WITH_RECORD_EXPR; if the component size is, pass our - component to one. */ - if (CONTAINS_PLACEHOLDER_P (index)) - index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, t2); - if (CONTAINS_PLACEHOLDER_P (unit_size)) - unit_size = build (WITH_RECORD_EXPR, sizetype, - unit_size, array); - - off_tree - = fold (build (PLUS_EXPR, sizetype, - fold (build (MULT_EXPR, sizetype, - index, - unit_size)), - off_tree)); + index, then convert to sizetype and multiply by the size of + the array element. */ + if (! integer_zerop (low_bound)) + index = fold (build2 (MINUS_EXPR, TREE_TYPE (index), + index, low_bound)); + + off_tree = size_binop (PLUS_EXPR, + size_binop (MULT_EXPR, convert (sizetype, + index), + unit_size), + off_tree); t2 = TREE_OPERAND (t2, 0); } while (TREE_CODE (t2) == ARRAY_REF); @@ -2117,12 +1814,15 @@ change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) { rtx new; - if (GET_CODE (memref) != MEM) + if (!MEM_P (memref)) abort (); if (mode == VOIDmode) mode = GET_MODE (memref); if (addr == 0) addr = XEXP (memref, 0); + if (mode == GET_MODE (memref) && addr == XEXP (memref, 0) + && (!validate || memory_address_p (mode, addr))) + return memref; if (validate) { @@ -2149,15 +1849,29 @@ change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) rtx change_address (rtx memref, enum machine_mode mode, rtx addr) { - rtx new = change_address_1 (memref, mode, addr, 1); + rtx new = change_address_1 (memref, mode, addr, 1), size; enum machine_mode mmode = GET_MODE (new); + unsigned int align; + + size = mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode)); + align = mmode == BLKmode ? BITS_PER_UNIT : GET_MODE_ALIGNMENT (mmode); + + /* If there are no changes, just return the original memory reference. */ + if (new == memref) + { + if (MEM_ATTRS (memref) == 0 + || (MEM_EXPR (memref) == NULL + && MEM_OFFSET (memref) == NULL + && MEM_SIZE (memref) == size + && MEM_ALIGN (memref) == align)) + return new; + + new = gen_rtx_MEM (mmode, XEXP (memref, 0)); + MEM_COPY_ATTRIBUTES (new, memref); + } MEM_ATTRS (new) - = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, - mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode)), - (mmode == BLKmode ? BITS_PER_UNIT - : GET_MODE_ALIGNMENT (mmode)), - mmode); + = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, mmode); return new; } @@ -2178,6 +1892,11 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, rtx size = 0; unsigned int memalign = MEM_ALIGN (memref); + /* If there are no changes, just return the original memory reference. */ + if (mode == GET_MODE (memref) && !offset + && (!validate || memory_address_p (mode, addr))) + return memref; + /* ??? Prefer to create garbage instead of creating shared rtl. This may happen even if offset is nonzero -- consider (plus (plus reg reg) const_int) -- so do this always. */ @@ -2268,6 +1987,10 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2) update_temp_slot_address (XEXP (memref, 0), new); new = change_address_1 (memref, VOIDmode, new, 1); + /* If there are no changes, just return the original memory reference. */ + if (new == memref) + return new; + /* Update the alignment to reflect the offset. Reset the offset, which we don't know. */ MEM_ATTRS (new) @@ -2312,6 +2035,10 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset) rtx memoffset = MEM_OFFSET (new); unsigned int size = GET_MODE_SIZE (mode); + /* If there are no changes, just return the original memory reference. */ + if (new == memref) + return new; + /* If we don't know what offset we were at within the expression, then we can't know if we've overstepped the bounds. */ if (! memoffset) @@ -2322,6 +2049,7 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset) if (TREE_CODE (expr) == COMPONENT_REF) { tree field = TREE_OPERAND (expr, 1); + tree offset = component_ref_field_offset (expr); if (! DECL_SIZE_UNIT (field)) { @@ -2336,17 +2064,18 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset) && INTVAL (memoffset) >= 0) break; - if (! host_integerp (DECL_FIELD_OFFSET (field), 1)) + if (! host_integerp (offset, 1)) { expr = NULL_TREE; break; } expr = TREE_OPERAND (expr, 0); - memoffset = (GEN_INT (INTVAL (memoffset) - + tree_low_cst (DECL_FIELD_OFFSET (field), 1) - + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1) - / BITS_PER_UNIT))); + memoffset + = (GEN_INT (INTVAL (memoffset) + + tree_low_cst (offset, 1) + + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1) + / BITS_PER_UNIT))); } /* Similarly for the decl. */ else if (DECL_P (expr) @@ -2428,8 +2157,8 @@ restore_emit_status (struct function *p ATTRIBUTE_UNUSED) /* Go through all the RTL insn bodies and copy any invalid shared structure. This routine should only be called once. */ -void -unshare_all_rtl (tree fndecl, rtx insn) +static void +unshare_all_rtl_1 (tree fndecl, rtx insn) { tree decl; @@ -2480,7 +2209,13 @@ unshare_all_rtl_again (rtx insn) reset_used_flags (stack_slot_list); - unshare_all_rtl (cfun->decl, insn); + unshare_all_rtl_1 (cfun->decl, insn); +} + +void +unshare_all_rtl (void) +{ + unshare_all_rtl_1 (current_function_decl, get_insns ()); } /* Check that ORIG is not marked when it should not be and mark ORIG as in use, @@ -2504,7 +2239,6 @@ verify_rtx_sharing (rtx orig, rtx insn) switch (code) { case REG: - case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -2514,8 +2248,12 @@ verify_rtx_sharing (rtx orig, rtx insn) case PC: case CC0: case SCRATCH: - /* SCRATCH must be shared because they represent distinct values. */ return; + /* SCRATCH must be shared because they represent distinct values. */ + case CLOBBER: + if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER) + return; + break; case CONST: /* CONST can be shared if it contains a SYMBOL_REF. If it contains @@ -2681,7 +2419,6 @@ copy_most_rtx (rtx orig, rtx may_share) switch (code) { case REG: - case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -2699,8 +2436,8 @@ copy_most_rtx (rtx orig, rtx may_share) RTX_FLAG (copy, in_struct) = RTX_FLAG (orig, in_struct); RTX_FLAG (copy, volatil) = RTX_FLAG (orig, volatil); RTX_FLAG (copy, unchanging) = RTX_FLAG (orig, unchanging); - RTX_FLAG (copy, integrated) = RTX_FLAG (orig, integrated); RTX_FLAG (copy, frame_related) = RTX_FLAG (orig, frame_related); + RTX_FLAG (copy, return_val) = RTX_FLAG (orig, return_val); format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); @@ -2798,7 +2535,6 @@ repeat: switch (code) { case REG: - case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -2810,6 +2546,10 @@ repeat: case SCRATCH: /* SCRATCH must be shared because they represent distinct values. */ return; + case CLOBBER: + if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER) + return; + break; case CONST: /* CONST can be shared if it contains a SYMBOL_REF. If it contains @@ -2876,7 +2616,7 @@ repeat: if (copied && len > 0) XVEC (x, i) = gen_rtvec_v (len, XVEC (x, i)->elem); - /* Call recsusively on all inside the vector. */ + /* Call recursively on all inside the vector. */ for (j = 0; j < len; j++) { if (last_ptr) @@ -2920,7 +2660,6 @@ repeat: switch (code) { case REG: - case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -2990,7 +2729,6 @@ set_used_flags (rtx x) switch (code) { case REG: - case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -3054,11 +2792,11 @@ make_safe_from (rtx x, rtx other) goto done; } done: - if ((GET_CODE (other) == MEM + if ((MEM_P (other) && ! CONSTANT_P (x) - && GET_CODE (x) != REG + && !REG_P (x) && GET_CODE (x) != SUBREG) - || (GET_CODE (other) == REG + || (REG_P (other) && (REGNO (other) < FIRST_PSEUDO_REGISTER || reg_mentioned_p (other, x)))) { @@ -3132,7 +2870,7 @@ get_first_nonnote_insn (void) while (insn) { insn = next_insn (insn); - if (insn == 0 || GET_CODE (insn) != NOTE) + if (insn == 0 || !NOTE_P (insn)) break; } @@ -3150,7 +2888,7 @@ get_last_nonnote_insn (void) while (insn) { insn = previous_insn (insn); - if (insn == 0 || GET_CODE (insn) != NOTE) + if (insn == 0 || !NOTE_P (insn)) break; } @@ -3201,7 +2939,7 @@ next_insn (rtx insn) if (insn) { insn = NEXT_INSN (insn); - if (insn && GET_CODE (insn) == INSN + if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) insn = XVECEXP (PATTERN (insn), 0, 0); } @@ -3218,7 +2956,7 @@ previous_insn (rtx insn) if (insn) { insn = PREV_INSN (insn); - if (insn && GET_CODE (insn) == INSN + if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) insn = XVECEXP (PATTERN (insn), 0, XVECLEN (PATTERN (insn), 0) - 1); } @@ -3235,7 +2973,7 @@ next_nonnote_insn (rtx insn) while (insn) { insn = NEXT_INSN (insn); - if (insn == 0 || GET_CODE (insn) != NOTE) + if (insn == 0 || !NOTE_P (insn)) break; } @@ -3251,7 +2989,7 @@ prev_nonnote_insn (rtx insn) while (insn) { insn = PREV_INSN (insn); - if (insn == 0 || GET_CODE (insn) != NOTE) + if (insn == 0 || !NOTE_P (insn)) break; } @@ -3268,8 +3006,7 @@ next_real_insn (rtx insn) while (insn) { insn = NEXT_INSN (insn); - if (insn == 0 || GET_CODE (insn) == INSN - || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) + if (insn == 0 || INSN_P (insn)) break; } @@ -3286,8 +3023,7 @@ prev_real_insn (rtx insn) while (insn) { insn = PREV_INSN (insn); - if (insn == 0 || GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN - || GET_CODE (insn) == JUMP_INSN) + if (insn == 0 || INSN_P (insn)) break; } @@ -3303,7 +3039,7 @@ last_call_insn (void) rtx insn; for (insn = get_last_insn (); - insn && GET_CODE (insn) != CALL_INSN; + insn && !CALL_P (insn); insn = PREV_INSN (insn)) ; @@ -3317,8 +3053,8 @@ last_call_insn (void) int active_insn_p (rtx insn) { - return (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN - || (GET_CODE (insn) == INSN + return (CALL_P (insn) || JUMP_P (insn) + || (NONJUMP_INSN_P (insn) && (! reload_completed || (GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)))); @@ -3362,7 +3098,7 @@ next_label (rtx insn) while (insn) { insn = NEXT_INSN (insn); - if (insn == 0 || GET_CODE (insn) == CODE_LABEL) + if (insn == 0 || LABEL_P (insn)) break; } @@ -3377,12 +3113,27 @@ prev_label (rtx insn) while (insn) { insn = PREV_INSN (insn); - if (insn == 0 || GET_CODE (insn) == CODE_LABEL) + if (insn == 0 || LABEL_P (insn)) break; } return insn; } + +/* Return the last label to mark the same position as LABEL. Return null + if LABEL itself is null. */ + +rtx +skip_consecutive_labels (rtx label) +{ + rtx insn; + + for (insn = label; insn != 0 && !INSN_P (insn); insn = NEXT_INSN (insn)) + if (LABEL_P (insn)) + label = insn; + + return label; +} #ifdef HAVE_cc0 /* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER @@ -3393,7 +3144,7 @@ link_cc0_insns (rtx insn) { rtx user = next_nonnote_insn (insn); - if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE) + if (NONJUMP_INSN_P (user) && GET_CODE (PATTERN (user)) == SEQUENCE) user = XVECEXP (PATTERN (user), 0, 0); REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn, @@ -3419,7 +3170,7 @@ next_cc0_user (rtx insn) return XEXP (note, 0); insn = next_nonnote_insn (insn); - if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) + if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) insn = XVECEXP (PATTERN (insn), 0, 0); if (insn && INSN_P (insn) && reg_mentioned_p (cc0_rtx, PATTERN (insn))) @@ -3457,7 +3208,7 @@ mark_label_nuses (rtx x) const char *fmt; code = GET_CODE (x); - if (code == LABEL_REF) + if (code == LABEL_REF && LABEL_P (XEXP (x, 0))) LABEL_NUSES (XEXP (x, 0))++; fmt = GET_RTX_FORMAT (code); @@ -3504,7 +3255,7 @@ try_split (rtx pat, rtx trial, int last) /* If we are splitting a JUMP_INSN, it might be followed by a BARRIER. We may need to handle this specially. */ - if (after && GET_CODE (after) == BARRIER) + if (after && BARRIER_P (after)) { has_barrier = 1; after = NEXT_INSN (after); @@ -3529,7 +3280,7 @@ try_split (rtx pat, rtx trial, int last) /* Mark labels. */ for (insn = insn_last; insn ; insn = PREV_INSN (insn)) { - if (GET_CODE (insn) == JUMP_INSN) + if (JUMP_P (insn)) { mark_jump_label (PATTERN (insn), insn, 0); njumps++; @@ -3553,10 +3304,10 @@ try_split (rtx pat, rtx trial, int last) /* If we are splitting a CALL_INSN, look for the CALL_INSN in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it. */ - if (GET_CODE (trial) == CALL_INSN) + if (CALL_P (trial)) { for (insn = insn_last; insn ; insn = PREV_INSN (insn)) - if (GET_CODE (insn) == CALL_INSN) + if (CALL_P (insn)) { rtx *p = &CALL_INSN_FUNCTION_USAGE (insn); while (*p) @@ -3575,7 +3326,7 @@ try_split (rtx pat, rtx trial, int last) insn = insn_last; while (insn != NULL_RTX) { - if (GET_CODE (insn) == CALL_INSN + if (CALL_P (insn) || (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))) REG_NOTES (insn) @@ -3592,7 +3343,7 @@ try_split (rtx pat, rtx trial, int last) insn = insn_last; while (insn != NULL_RTX) { - if (GET_CODE (insn) == CALL_INSN) + if (CALL_P (insn)) REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note), XEXP (note, 0), @@ -3605,7 +3356,7 @@ try_split (rtx pat, rtx trial, int last) insn = insn_last; while (insn != NULL_RTX) { - if (GET_CODE (insn) == JUMP_INSN) + if (JUMP_P (insn)) REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note), XEXP (note, 0), @@ -3621,12 +3372,12 @@ try_split (rtx pat, rtx trial, int last) /* If there are LABELS inside the split insns increment the usage count so we don't delete the label. */ - if (GET_CODE (trial) == INSN) + if (NONJUMP_INSN_P (trial)) { insn = insn_last; while (insn != NULL_RTX) { - if (GET_CODE (insn) == INSN) + if (NONJUMP_INSN_P (insn)) mark_label_nuses (PATTERN (insn)); insn = PREV_INSN (insn); @@ -3768,7 +3519,7 @@ add_insn_after (rtx insn, rtx after) if (next) { PREV_INSN (next) = insn; - if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE) + if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE) PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = insn; } else if (last_insn == after) @@ -3788,8 +3539,8 @@ add_insn_after (rtx insn, rtx after) abort (); } - if (GET_CODE (after) != BARRIER - && GET_CODE (insn) != BARRIER + if (!BARRIER_P (after) + && !BARRIER_P (insn) && (bb = BLOCK_FOR_INSN (after))) { set_block_for_insn (insn, bb); @@ -3799,14 +3550,14 @@ add_insn_after (rtx insn, rtx after) either NOTE or LABEL. */ if (BB_END (bb) == after /* Avoid clobbering of structure when creating new BB. */ - && GET_CODE (insn) != BARRIER - && (GET_CODE (insn) != NOTE + && !BARRIER_P (insn) + && (!NOTE_P (insn) || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)) BB_END (bb) = insn; } NEXT_INSN (after) = insn; - if (GET_CODE (after) == INSN && GET_CODE (PATTERN (after)) == SEQUENCE) + if (NONJUMP_INSN_P (after) && GET_CODE (PATTERN (after)) == SEQUENCE) { rtx sequence = PATTERN (after); NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn; @@ -3833,7 +3584,7 @@ add_insn_before (rtx insn, rtx before) if (prev) { NEXT_INSN (prev) = insn; - if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE) + if (NONJUMP_INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE) { rtx sequence = PATTERN (prev); NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn; @@ -3856,8 +3607,8 @@ add_insn_before (rtx insn, rtx before) abort (); } - if (GET_CODE (before) != BARRIER - && GET_CODE (insn) != BARRIER + if (!BARRIER_P (before) + && !BARRIER_P (insn) && (bb = BLOCK_FOR_INSN (before))) { set_block_for_insn (insn, bb); @@ -3867,14 +3618,14 @@ add_insn_before (rtx insn, rtx before) either NOTE or LABEl. */ if (BB_HEAD (bb) == insn /* Avoid clobbering of structure when creating new BB. */ - && GET_CODE (insn) != BARRIER - && (GET_CODE (insn) != NOTE + && !BARRIER_P (insn) + && (!NOTE_P (insn) || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)) abort (); } PREV_INSN (before) = insn; - if (GET_CODE (before) == INSN && GET_CODE (PATTERN (before)) == SEQUENCE) + if (NONJUMP_INSN_P (before) && GET_CODE (PATTERN (before)) == SEQUENCE) PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn; } @@ -3890,7 +3641,7 @@ remove_insn (rtx insn) if (prev) { NEXT_INSN (prev) = next; - if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE) + if (NONJUMP_INSN_P (prev) && GET_CODE (PATTERN (prev)) == SEQUENCE) { rtx sequence = PATTERN (prev); NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = next; @@ -3916,7 +3667,7 @@ remove_insn (rtx insn) if (next) { PREV_INSN (next) = prev; - if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE) + if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE) PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = prev; } else if (last_insn == insn) @@ -3935,7 +3686,7 @@ remove_insn (rtx insn) if (stack == 0) abort (); } - if (GET_CODE (insn) != BARRIER + if (!BARRIER_P (insn) && (bb = BLOCK_FOR_INSN (insn))) { if (INSN_P (insn)) @@ -3944,7 +3695,7 @@ remove_insn (rtx insn) { /* Never ever delete the basic block note without deleting whole basic block. */ - if (GET_CODE (insn) == NOTE) + if (NOTE_P (insn)) abort (); BB_HEAD (bb) = next; } @@ -3958,7 +3709,7 @@ remove_insn (rtx insn) void add_function_usage_to (rtx call_insn, rtx call_fusage) { - if (! call_insn || GET_CODE (call_insn) != CALL_INSN) + if (! call_insn || !CALL_P (call_insn)) abort (); /* Put the register usage information on the CALL. If there is already @@ -4033,13 +3784,13 @@ reorder_insns (rtx from, rtx to, rtx after) reorder_insns_nobb (from, to, after); - if (GET_CODE (after) != BARRIER + if (!BARRIER_P (after) && (bb = BLOCK_FOR_INSN (after))) { rtx x; bb->flags |= BB_DIRTY; - if (GET_CODE (from) != BARRIER + if (!BARRIER_P (from) && (bb2 = BLOCK_FOR_INSN (from))) { if (BB_END (bb2) == to) @@ -4051,7 +3802,8 @@ reorder_insns (rtx from, rtx to, rtx after) BB_END (bb) = to; for (x = from; x != NEXT_INSN (to); x = NEXT_INSN (x)) - set_block_for_insn (x, bb); + if (!BARRIER_P (x)) + set_block_for_insn (x, bb); } } @@ -4064,34 +3816,13 @@ find_line_note (rtx insn) return 0; for (; insn; insn = PREV_INSN (insn)) - if (GET_CODE (insn) == NOTE + if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) >= 0) break; return insn; } -/* Like reorder_insns, but inserts line notes to preserve the line numbers - of the moved insns when debugging. This may insert a note between AFTER - and FROM, and another one after TO. */ - -void -reorder_insns_with_line_notes (rtx from, rtx to, rtx after) -{ - rtx from_line = find_line_note (from); - rtx after_line = find_line_note (after); - - reorder_insns (from, to, after); - - if (from_line == after_line) - return; - - if (from_line) - emit_note_copy_after (from_line, after); - if (after_line) - emit_note_copy_after (after_line, to); -} - /* Remove unnecessary notes from the instruction stream. */ void @@ -4111,13 +3842,12 @@ remove_unnecessary_notes (void) next = NEXT_INSN (insn); /* We're only interested in notes. */ - if (GET_CODE (insn) != NOTE) + if (!NOTE_P (insn)) continue; switch (NOTE_LINE_NUMBER (insn)) { case NOTE_INSN_DELETED: - case NOTE_INSN_LOOP_END_TOP_COND: remove_insn (insn); break; @@ -4171,7 +3901,7 @@ remove_unnecessary_notes (void) break; /* We're only interested in NOTEs. */ - if (GET_CODE (tmp) != NOTE) + if (!NOTE_P (tmp)) continue; if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_BEG) @@ -4408,7 +4138,9 @@ emit_note_before (int subtype, rtx before) { rtx note = rtx_alloc (NOTE); INSN_UID (note) = cur_insn_uid++; +#ifndef USE_MAPPED_LOCATION NOTE_SOURCE_FILE (note) = 0; +#endif NOTE_LINE_NUMBER (note) = subtype; BLOCK_FOR_INSN (note) = NULL; @@ -4428,14 +4160,14 @@ emit_insn_after_1 (rtx first, rtx after) rtx after_after; basic_block bb; - if (GET_CODE (after) != BARRIER + if (!BARRIER_P (after) && (bb = BLOCK_FOR_INSN (after))) { bb->flags |= BB_DIRTY; for (last = first; NEXT_INSN (last); last = NEXT_INSN (last)) - if (GET_CODE (last) != BARRIER) + if (!BARRIER_P (last)) set_block_for_insn (last, bb); - if (GET_CODE (last) != BARRIER) + if (!BARRIER_P (last)) set_block_for_insn (last, bb); if (BB_END (bb) == after) BB_END (bb) = last; @@ -4631,7 +4363,9 @@ emit_note_after (int subtype, rtx after) { rtx note = rtx_alloc (NOTE); INSN_UID (note) = cur_insn_uid++; +#ifndef USE_MAPPED_LOCATION NOTE_SOURCE_FILE (note) = 0; +#endif NOTE_LINE_NUMBER (note) = subtype; BLOCK_FOR_INSN (note) = NULL; add_insn_after (note, after); @@ -4666,6 +4400,9 @@ emit_insn_after_setloc (rtx pattern, rtx after, int loc) { rtx last = emit_insn_after (pattern, after); + if (pattern == NULL_RTX) + return last; + after = NEXT_INSN (after); while (1) { @@ -4684,6 +4421,9 @@ emit_jump_insn_after_setloc (rtx pattern, rtx after, int loc) { rtx last = emit_jump_insn_after (pattern, after); + if (pattern == NULL_RTX) + return last; + after = NEXT_INSN (after); while (1) { @@ -4702,6 +4442,9 @@ emit_call_insn_after_setloc (rtx pattern, rtx after, int loc) { rtx last = emit_call_insn_after (pattern, after); + if (pattern == NULL_RTX) + return last; + after = NEXT_INSN (after); while (1) { @@ -4721,6 +4464,9 @@ emit_insn_before_setloc (rtx pattern, rtx before, int loc) rtx first = PREV_INSN (before); rtx last = emit_insn_before (pattern, before); + if (pattern == NULL_RTX) + return last; + first = NEXT_INSN (first); while (1) { @@ -4892,12 +4638,15 @@ emit_line_note (location_t location) { rtx note; - set_file_and_line_for_stmt (location); - +#ifdef USE_MAPPED_LOCATION + if (location == last_location) + return NULL_RTX; +#else if (location.file && last_location.file && !strcmp (location.file, last_location.file) && location.line == last_location.line) return NULL_RTX; +#endif last_location = location; if (no_line_numbers) @@ -4906,8 +4655,12 @@ emit_line_note (location_t location) return NULL_RTX; } +#ifdef USE_MAPPED_LOCATION + note = emit_note ((int) location); +#else note = emit_note (location.line); NOTE_SOURCE_FILE (note) = location.file; +#endif return note; } @@ -4959,7 +4712,11 @@ emit_note (int note_no) void force_next_line_note (void) { +#ifdef USE_MAPPED_LOCATION + last_location = -1; +#else last_location.line = -1; +#endif } /* Place a note of KIND on insn INSN with DATUM as the datum. If a @@ -5011,7 +4768,7 @@ set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum) enum rtx_code classify_insn (rtx x) { - if (GET_CODE (x) == CODE_LABEL) + if (LABEL_P (x)) return CODE_LABEL; if (GET_CODE (x) == CALL) return CALL_INSN; @@ -5068,15 +4825,14 @@ emit (rtx x) } /* Space for free sequence stack entries. */ -static GTY ((deletable (""))) struct sequence_stack *free_sequence_stack; +static GTY ((deletable)) struct sequence_stack *free_sequence_stack; -/* Begin emitting insns to a sequence which can be packaged in an - RTL_EXPR. If this sequence will contain something that might cause - the compiler to pop arguments to function calls (because those - pops have previously been deferred; see INHIBIT_DEFER_POP for more - details), use do_pending_stack_adjust before calling this function. - That will ensure that the deferred pops are not accidentally - emitted in the middle of this sequence. */ +/* Begin emitting insns to a sequence. If this sequence will contain + something that might cause the compiler to pop arguments to function + calls (because those pops have previously been deferred; see + INHIBIT_DEFER_POP for more details), use do_pending_stack_adjust + before calling this function. That will ensure that the deferred + pops are not accidentally emitted in the middle of this sequence. */ void start_sequence (void) @@ -5094,7 +4850,6 @@ start_sequence (void) tem->next = seq_stack; tem->first = first_insn; tem->last = last_insn; - tem->sequence_rtl_expr = seq_rtl_expr; seq_stack = tem; @@ -5102,18 +4857,6 @@ start_sequence (void) last_insn = 0; } -/* Similarly, but indicate that this sequence will be placed in T, an - RTL_EXPR. See the documentation for start_sequence for more - information about how to use this function. */ - -void -start_sequence_for_rtl_expr (tree t) -{ - start_sequence (); - - seq_rtl_expr = t; -} - /* Set up the insn chain starting with FIRST as the current sequence, saving the previously current one. See the documentation for start_sequence for more information about how to use this function. */ @@ -5159,7 +4902,6 @@ push_topmost_sequence (void) first_insn = top->first; last_insn = top->last; - seq_rtl_expr = top->sequence_rtl_expr; } /* After emitting to the outer-level insn chain, update the outer-level @@ -5175,7 +4917,6 @@ pop_topmost_sequence (void) top->first = first_insn; top->last = last_insn; - /* ??? Why don't we save seq_rtl_expr here? */ end_sequence (); } @@ -5200,7 +4941,6 @@ end_sequence (void) first_insn = tem->first; last_insn = tem->last; - seq_rtl_expr = tem->sequence_rtl_expr; seq_stack = tem->next; memset (tem, 0, sizeof (*tem)); @@ -5208,17 +4948,6 @@ end_sequence (void) free_sequence_stack = tem; } -/* This works like end_sequence, but records the old sequence in FIRST - and LAST. */ - -void -end_full_sequence (rtx *first, rtx *last) -{ - *first = first_insn; - *last = last_insn; - end_sequence (); -} - /* Return 1 if currently emitting into a sequence. */ int @@ -5281,7 +5010,6 @@ copy_insn_1 (rtx orig) switch (code) { case REG: - case QUEUED: case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -5289,8 +5017,11 @@ copy_insn_1 (rtx orig) case CODE_LABEL: case PC: case CC0: - case ADDRESSOF: return orig; + case CLOBBER: + if (REG_P (XEXP (orig, 0)) && REGNO (XEXP (orig, 0)) < FIRST_PSEUDO_REGISTER) + return orig; + break; case SCRATCH: for (i = 0; i < copy_insn_n_scratches; i++) @@ -5329,7 +5060,7 @@ copy_insn_1 (rtx orig) RTX_FLAG (copy, used) = 0; /* We do not copy JUMP, CALL, or FRAME_RELATED for INSNs. */ - if (GET_RTX_CLASS (code) == 'i') + if (INSN_P (orig)) { RTX_FLAG (copy, jump) = 0; RTX_FLAG (copy, call) = 0; @@ -5423,11 +5154,9 @@ init_emit (void) f->emit = ggc_alloc (sizeof (struct emit_status)); first_insn = NULL; last_insn = NULL; - seq_rtl_expr = NULL; cur_insn_uid = 1; reg_rtx_no = LAST_VIRTUAL_REGISTER + 1; - last_location.line = 0; - last_location.file = 0; + last_location = UNKNOWN_LOCATION; first_label_num = label_num; last_label_num = 0; seq_stack = NULL; @@ -5582,8 +5311,8 @@ init_emit_once (int line_numbers) This must be done at runtime because the register number field is in a union and some compilers can't initialize unions. */ - pc_rtx = gen_rtx (PC, VOIDmode); - cc0_rtx = gen_rtx (CC0, VOIDmode); + pc_rtx = gen_rtx_PC (VOIDmode); + cc0_rtx = gen_rtx_CC0 (VOIDmode); stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM); frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM); if (hard_frame_pointer_rtx == 0) @@ -5616,7 +5345,7 @@ init_emit_once (int line_numbers) /* Create the unique rtx's for certain rtx codes and operand values. */ - /* Don't use gen_rtx here since gen_rtx in this case + /* Don't use gen_rtx_CONST_INT here since gen_rtx_CONST_INT in this case tries to use these variables. */ for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++) const_int_rtx[i + MAX_SAVED_CONST_INT] = @@ -5637,7 +5366,7 @@ init_emit_once (int line_numbers) REAL_VALUE_FROM_INT (dconstm2, -2, -1, double_mode); dconsthalf = dconst1; - dconsthalf.exp--; + SET_REAL_EXP (&dconsthalf, REAL_EXP (&dconsthalf) - 1); real_arithmetic (&dconstthird, RDIV_EXPR, &dconst1, &dconst3); @@ -5719,27 +5448,6 @@ init_emit_once (int line_numbers) pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); } -/* Query and clear/ restore no_line_numbers. This is used by the - switch / case handling in stmt.c to give proper line numbers in - warnings about unreachable code. */ - -int -force_line_numbers (void) -{ - int old = no_line_numbers; - - no_line_numbers = 0; - if (old) - force_next_line_note (); - return old; -} - -void -restore_line_number_status (int old_value) -{ - no_line_numbers = old_value; -} - /* Produce exact duplicate of insn INSN after AFTER. Care updating of libcall regions if present. */ @@ -5807,4 +5515,15 @@ emit_copy_of_insn_after (rtx insn, rtx after) return new; } +static GTY((deletable)) rtx hard_reg_clobbers [NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER]; +rtx +gen_hard_reg_clobber (enum machine_mode mode, unsigned int regno) +{ + if (hard_reg_clobbers[mode][regno]) + return hard_reg_clobbers[mode][regno]; + else + return (hard_reg_clobbers[mode][regno] = + gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (mode, regno))); +} + #include "gt-emit-rtl.h"