/* 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.
/* 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"
subreg_lowpart_offset (mode, inmode));
}
\f
-/* rtx gen_rtx (code, mode, [element1, ..., elementn])
-**
-** This routine generates an RTX of the size specified by
-** <code>, which is an RTX code. The RTX structure is initialized
-** from the arguments <element1> through <elementn>, which are
-** interpreted according to the specific RTX type's format. The
-** special machine mode associated with the rtx (if any) is specified
-** in <mode>.
-**
-** 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
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;
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)
{
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)));
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))
}
}
+/* 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
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 ();
{
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);
+}
\f
/* Return the final regno of X, which is a SUBREG of a hard
register. */
/* 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)
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 (GET_MODE (x) == mode)
+ if (innermode == VOIDmode || innermode == BLKmode)
+ abort ();
+
+ 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
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;
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))));
-}
\f
-/* 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)
{
== SUBREG_BYTE (x));
}
\f
-
-/* 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
{
/* 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);
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;
TREE_OPERAND (ref, 1));
}
+/* 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
corresponding to REF, set the memory attributes. OBJECTP is nonzero
if we are making a new object of this type. BITPOS is nonzero if
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_READONLY (type) || (t != type && TREE_READONLY (t))))
|| (! TYPE_P (t) && TREE_CONSTANT (t)));
+ MEM_POINTER (ref) = POINTER_TYPE_P (type);
/* 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. */
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);
-
+ /* If the index has a self-referential type, instantiate it;
+ likewise for the component size. */
+ index = SUBSTITUTE_PLACEHOLDER_IN_EXPR (index, t2);
+ unit_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (unit_size, array);
off_tree
= fold (build (PLUS_EXPR, sizetype,
fold (build (MULT_EXPR, sizetype,
- index,
- unit_size)),
+ index, unit_size)),
off_tree));
t2 = TREE_OPERAND (t2, 0);
}
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)
{
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;
}
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. */
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)
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)
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
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));
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
done:
if ((GET_CODE (other) == MEM
&& ! 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))))
{
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;
}
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;
}
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;
+}
\f
#ifdef HAVE_cc0
/* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER
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);
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
{
rtx last = emit_insn_after (pattern, after);
+ if (pattern == NULL_RTX)
+ return last;
+
after = NEXT_INSN (after);
while (1)
{
{
rtx last = emit_jump_insn_after (pattern, after);
+ if (pattern == NULL_RTX)
+ return last;
+
after = NEXT_INSN (after);
while (1)
{
{
rtx last = emit_call_insn_after (pattern, after);
+ if (pattern == NULL_RTX)
+ return last;
+
after = NEXT_INSN (after);
while (1)
{
rtx first = PREV_INSN (before);
rtx last = emit_insn_before (pattern, before);
+ if (pattern == NULL_RTX)
+ return last;
+
first = NEXT_INSN (first);
while (1)
{
}
\f
/* 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
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
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++)
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;
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)
/* 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] =
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);
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"