/* 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"
static int reg_attrs_htab_eq (const void *, const void *);
static reg_attrs *get_reg_attrs (tree, int);
static tree component_ref_for_mem_expr (tree);
-static rtx gen_const_vector_0 (enum machine_mode);
+static rtx gen_const_vector (enum machine_mode, int);
static rtx gen_complex_constant_part (enum machine_mode, rtx, int);
static void copy_rtx_if_shared_1 (rtx *orig);
if (mode != VOIDmode)
{
int width;
- if (GET_MODE_CLASS (mode) != MODE_INT
- && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT
- /* We can get a 0 for an error mark. */
- && GET_MODE_CLASS (mode) != MODE_VECTOR_INT
- && GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT)
- abort ();
+
+ gcc_assert (GET_MODE_CLASS (mode) == MODE_INT
+ || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT
+ /* We can get a 0 for an error mark. */
+ || GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+ || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT);
/* We clear out all bits that don't belong in MODE, unless they and
our sign bit are all one. So we get either a reasonable negative
else if (width == HOST_BITS_PER_WIDE_INT
&& ! (i1 == ~0 && i0 < 0))
i1 = 0;
- else if (width > 2 * HOST_BITS_PER_WIDE_INT)
- /* We cannot represent this value as a constant. */
- abort ();
+ else
+ /* We should be able to represent this value as a constant. */
+ gcc_assert (width <= 2 * HOST_BITS_PER_WIDE_INT);
/* If this would be an entire word for the target, but is not for
the host, then sign-extend on the host so that the number will
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)
{
/* This is the most common failure type.
Catch it early so we can see who does it. */
- if ((offset % GET_MODE_SIZE (mode)) != 0)
- abort ();
+ gcc_assert (!(offset % GET_MODE_SIZE (mode)));
/* This check isn't usable right now because combine will
throw arbitrary crap like a CALL into a SUBREG in
gen_lowpart_for_combine so we must just eat it. */
#if 0
/* Check for this too. */
- if (offset >= GET_MODE_SIZE (GET_MODE (reg)))
- abort ();
+ gcc_assert (offset < GET_MODE_SIZE (GET_MODE (reg)));
#endif
return gen_rtx_raw_SUBREG (mode, reg, offset);
}
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
/* Don't let anything called after initial flow analysis create new
registers. */
- if (no_new_pseudos)
- abort ();
+ gcc_assert (!no_new_pseudos);
if (generating_concat_p
&& (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
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)
- REG_USERVAR_P (reg) = 1;
else
- abort ();
+ {
+ gcc_assert (REG_P (reg));
+ REG_USERVAR_P (reg) = 1;
+ }
}
/* Identify REG as a probable pointer register and show its alignment
{
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)
- abort ();
+ gcc_assert (GET_CODE (x) == SUBREG && REG_P (reg));
base_regno = REGNO (reg);
- if (base_regno >= FIRST_PSEUDO_REGISTER)
- abort ();
- if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
- abort ();
+ gcc_assert (base_regno < FIRST_PSEUDO_REGISTER);
+ gcc_assert (!check_mode || HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)));
#ifdef ENABLE_CHECKING
- if (!subreg_offset_representable_p (REGNO (reg), GET_MODE (reg),
- SUBREG_BYTE (x), mode))
- abort ();
+ gcc_assert (subreg_offset_representable_p (REGNO (reg), GET_MODE (reg),
+ SUBREG_BYTE (x), mode));
#endif
/* Catch non-congruent offsets too. */
byte_offset = SUBREG_BYTE (x);
- if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
- abort ();
+ gcc_assert (!(byte_offset % GET_MODE_SIZE (mode)));
final_regno = subreg_regno (x);
xsize = GET_MODE_SIZE (innermode);
- if (innermode == VOIDmode || innermode == BLKmode)
- abort ();
+ gcc_assert (innermode != VOIDmode && innermode != BLKmode);
if (innermode == mode)
return 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
+ 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);
{
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));
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)
{
/* This case loses if X is a subreg. To catch bugs early,
complain if an invalid MODE is used even in other cases. */
- if (msize > UNITS_PER_WORD
- && msize != (unsigned int) GET_MODE_UNIT_SIZE (GET_MODE (x)))
- abort ();
+ gcc_assert (msize <= UNITS_PER_WORD
+ || msize == (unsigned int) GET_MODE_UNIT_SIZE (GET_MODE (x)));
result = simplify_gen_subreg (mode, x, GET_MODE (x),
subreg_highpart_offset (mode, GET_MODE (x)));
-
+ gcc_assert (result);
+
/* 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)
- result = validize_mem (result);
-
- if (!result)
- abort ();
+ if (MEM_P (result))
+ {
+ result = validize_mem (result);
+ gcc_assert (result);
+ }
+
return result;
}
{
if (GET_MODE (exp) != VOIDmode)
{
- if (GET_MODE (exp) != innermode)
- abort ();
+ gcc_assert (GET_MODE (exp) == innermode);
return gen_highpart (outermode, exp);
}
return simplify_gen_subreg (outermode, exp, innermode,
unsigned int offset = 0;
int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
- if (GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
- abort ();
+ gcc_assert (GET_MODE_SIZE (innermode) >= GET_MODE_SIZE (outermode));
if (difference > 0)
{
if (mode == VOIDmode)
mode = GET_MODE (op);
- if (mode == VOIDmode)
- abort ();
+ gcc_assert (mode != VOIDmode);
/* If OP is narrower than a word, fail. */
if (mode != BLKmode
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);
{
/* 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);
}
result = operand_subword (op, offset, 1, mode);
- if (result == 0)
- abort ();
+ gcc_assert (result);
return result;
}
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;
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 (INDIRECT_REF_P (expr1))
+ return mem_expr_equal_p (TREE_OPERAND (expr1, 0),
+ TREE_OPERAND (expr2, 0));
+
+ /* ARRAY_REFs, ARRAY_RANGE_REFs and BIT_FIELD_REFs should already
+ have been resolved here. */
+ gcc_assert (DECL_P (expr1));
+
+ /* Decls with different pointers can't be equal. */
+ return 0;
}
/* Given REF, a MEM, and T, either the type of X or the expression
wrong answer, as it assumes that DECL_RTL already has the right alias
info. Callers should not set DECL_RTL until after the call to
set_mem_attributes. */
- if (DECL_P (t) && ref == DECL_RTL_IF_SET (t))
- abort ();
+ gcc_assert (!DECL_P (t) || ref != DECL_RTL_IF_SET (t));
/* Get the alias set from the expression or type (perhaps using a
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. */
/* We can set the alignment from the type if we are making an object,
this is an INDIRECT_REF, or if TYPE_ALIGN_OK. */
- if (objectp || TREE_CODE (t) == INDIRECT_REF || TYPE_ALIGN_OK (type))
+ if (objectp || TREE_CODE (t) == INDIRECT_REF
+ || TREE_CODE (t) == ALIGN_INDIRECT_REF
+ || TYPE_ALIGN_OK (type))
align = MAX (align, TYPE_ALIGN (type));
+ else
+ if (TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
+ {
+ if (integer_zerop (TREE_OPERAND (t, 1)))
+ /* We don't know anything about the alignment. */
+ align = BITS_PER_UNIT;
+ else
+ align = tree_low_cst (TREE_OPERAND (t, 1), 1);
+ }
/* If the size is known, we can set that. */
if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))
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;
}
/* If this is a constant, we know the alignment. */
- else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
+ else if (CONSTANT_CLASS_P (t))
{
align = TYPE_ALIGN (type);
#ifdef CONSTANT_ALIGNMENT
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);
the size we got from the type? */
}
else if (flag_argument_noalias > 1
- && TREE_CODE (t2) == INDIRECT_REF
+ && (INDIRECT_REF_P (t2))
&& TREE_CODE (TREE_OPERAND (t2, 0)) == PARM_DECL)
{
expr = t2;
/* If this is a Fortran indirect argument reference, record the
parameter decl. */
else if (flag_argument_noalias > 1
- && TREE_CODE (t) == INDIRECT_REF
+ && (INDIRECT_REF_P (t))
&& TREE_CODE (TREE_OPERAND (t, 0)) == PARM_DECL)
{
expr = t;
size = plus_constant (size, apply_bitpos / BITS_PER_UNIT);
}
+ if (TREE_CODE (t) == ALIGN_INDIRECT_REF)
+ {
+ /* Force EXPR and OFFSE to NULL, since we don't know exactly what
+ we're overlapping. */
+ offset = NULL;
+ expr = NULL;
+ }
+
/* Now set the attributes we computed above. */
MEM_ATTRS (ref)
= get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref));
{
#ifdef ENABLE_CHECKING
/* If the new and old alias sets don't conflict, something is wrong. */
- if (!alias_sets_conflict_p (set, MEM_ALIAS_SET (mem)))
- abort ();
+ gcc_assert (alias_sets_conflict_p (set, MEM_ALIAS_SET (mem)));
#endif
MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem),
{
rtx new;
- if (GET_CODE (memref) != MEM)
- abort ();
+ gcc_assert (MEM_P (memref));
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)
{
if (reload_in_progress || reload_completed)
- {
- if (! memory_address_p (mode, addr))
- abort ();
- }
+ gcc_assert (memory_address_p (mode, addr));
else
addr = memory_address (mode, addr);
}
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)
if (TREE_CODE (expr) == COMPONENT_REF)
{
tree field = TREE_OPERAND (expr, 1);
+ tree offset = component_ref_field_offset (expr);
if (! DECL_SIZE_UNIT (field))
{
&& 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)
/* 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;
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,
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
/* This rtx may not be shared. If it has already been seen,
replace it with a copy of itself. */
-
+#ifdef ENABLE_CHECKING
if (RTX_FLAG (x, used))
{
error ("Invalid rtl sharing found in the insn");
debug_rtx (insn);
error ("Shared rtx");
debug_rtx (x);
- abort ();
+ internal_error ("Internal consistency failure");
}
+#endif
+ gcc_assert (!RTX_FLAG (x, used));
+
RTX_FLAG (x, used) = 1;
/* Now scan the subexpressions recursively. */
for (j = 0; j < len; j++)
{
- /* We allow sharing of ASM_OPERANDS inside single instruction. */
+ /* We allow sharing of ASM_OPERANDS inside single
+ instruction. */
if (j && GET_CODE (XVECEXP (x, i, j)) == SET
- && GET_CODE (SET_SRC (XVECEXP (x, i, j))) == ASM_OPERANDS)
+ && (GET_CODE (SET_SRC (XVECEXP (x, i, j)))
+ == ASM_OPERANDS))
verify_rtx_sharing (SET_DEST (XVECEXP (x, i, j)), insn);
else
verify_rtx_sharing (XVECEXP (x, i, j), insn);
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
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));
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
return copy;
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
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))))
{
void
set_first_insn (rtx insn)
{
- if (PREV_INSN (insn) != 0)
- abort ();
+ gcc_assert (!PREV_INSN (insn));
first_insn = insn;
}
void
set_last_insn (rtx insn)
{
- if (NEXT_INSN (insn) != 0)
- abort ();
+ gcc_assert (!NEXT_INSN (insn));
last_insn = insn;
}
while (insn)
{
insn = next_insn (insn);
- if (insn == 0 || GET_CODE (insn) != NOTE)
+ if (insn == 0 || !NOTE_P (insn))
break;
}
while (insn)
{
insn = previous_insn (insn);
- if (insn == 0 || GET_CODE (insn) != NOTE)
+ if (insn == 0 || !NOTE_P (insn))
break;
}
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);
}
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);
}
while (insn)
{
insn = NEXT_INSN (insn);
- if (insn == 0 || GET_CODE (insn) != NOTE)
+ if (insn == 0 || !NOTE_P (insn))
break;
}
while (insn)
{
insn = PREV_INSN (insn);
- if (insn == 0 || GET_CODE (insn) != NOTE)
+ if (insn == 0 || !NOTE_P (insn))
break;
}
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;
}
rtx insn;
for (insn = get_last_insn ();
- insn && GET_CODE (insn) != CALL_INSN;
+ insn && !CALL_P (insn);
insn = PREV_INSN (insn))
;
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))));
while (insn)
{
insn = NEXT_INSN (insn);
- if (insn == 0 || GET_CODE (insn) == CODE_LABEL)
+ if (insn == 0 || LABEL_P (insn))
break;
}
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;
+}
\f
#ifdef HAVE_cc0
/* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER
{
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,
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)))
return XEXP (note, 0);
insn = prev_nonnote_insn (insn);
- if (! sets_cc0_p (PATTERN (insn)))
- abort ();
+ gcc_assert (sets_cc0_p (PATTERN (insn)));
return insn;
}
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);
/* 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);
/* 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++;
one jump is created, otherwise the machine description
is responsible for this step using
split_branch_probability variable. */
- if (njumps != 1)
- abort ();
+ gcc_assert (njumps == 1);
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_BR_PROB,
GEN_INT (probability),
/* 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)
insn = insn_last;
while (insn != NULL_RTX)
{
- if (GET_CODE (insn) == CALL_INSN
- || (flag_non_call_exceptions
+ if (CALL_P (insn)
+ || (flag_non_call_exceptions && INSN_P (insn)
&& may_trap_p (PATTERN (insn))))
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_EH_REGION,
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),
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),
/* 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);
rtx next = NEXT_INSN (after);
basic_block bb;
- if (optimize && INSN_DELETED_P (after))
- abort ();
+ gcc_assert (!optimize || !INSN_DELETED_P (after));
NEXT_INSN (insn) = next;
PREV_INSN (insn) = 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)
break;
}
- if (stack == 0)
- abort ();
+ gcc_assert (stack);
}
- 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);
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;
rtx prev = PREV_INSN (before);
basic_block bb;
- if (optimize && INSN_DELETED_P (before))
- abort ();
+ gcc_assert (!optimize || !INSN_DELETED_P (before));
PREV_INSN (insn) = prev;
NEXT_INSN (insn) = 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;
break;
}
- if (stack == 0)
- abort ();
+ gcc_assert (stack);
}
- 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);
if (INSN_P (insn))
bb->flags |= BB_DIRTY;
- /* Should not happen as first in the BB is always
- 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
- || NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK))
- abort ();
+ /* Should not happen as first in the BB is always either NOTE or
+ LABEl. */
+ gcc_assert (BB_HEAD (bb) != insn
+ /* Avoid clobbering of structure when creating new BB. */
+ || BARRIER_P (insn)
+ || (NOTE_P (insn)
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK));
}
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;
}
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;
break;
}
- if (stack == 0)
- abort ();
+ gcc_assert (stack);
}
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)
break;
}
- if (stack == 0)
- abort ();
+ gcc_assert (stack);
}
- if (GET_CODE (insn) != BARRIER
+ if (!BARRIER_P (insn)
&& (bb = BLOCK_FOR_INSN (insn)))
{
if (INSN_P (insn))
{
/* Never ever delete the basic block note without deleting whole
basic block. */
- if (GET_CODE (insn) == NOTE)
- abort ();
+ gcc_assert (!NOTE_P (insn));
BB_HEAD (bb) = next;
}
if (BB_END (bb) == insn)
void
add_function_usage_to (rtx call_insn, rtx call_fusage)
{
- if (! call_insn || GET_CODE (call_insn) != CALL_INSN)
- abort ();
+ gcc_assert (call_insn && CALL_P (call_insn));
/* Put the register usage information on the CALL. If there is already
some usage information, put ours at the end. */
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)
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);
}
}
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
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;
case NOTE_INSN_EH_REGION_END:
/* Too many end notes. */
- if (eh_stack == NULL_RTX)
- abort ();
+ gcc_assert (eh_stack);
/* Mismatched nesting. */
- if (NOTE_EH_HANDLER (XEXP (eh_stack, 0)) != NOTE_EH_HANDLER (insn))
- abort ();
+ gcc_assert (NOTE_EH_HANDLER (XEXP (eh_stack, 0))
+ == NOTE_EH_HANDLER (insn));
tmp = eh_stack;
eh_stack = XEXP (eh_stack, 1);
free_INSN_LIST_node (tmp);
case NOTE_INSN_BLOCK_BEG:
/* By now, all notes indicating lexical blocks should have
NOTE_BLOCK filled in. */
- if (NOTE_BLOCK (insn) == NULL_TREE)
- abort ();
+ gcc_assert (NOTE_BLOCK (insn));
block_stack = alloc_INSN_LIST (insn, block_stack);
break;
case NOTE_INSN_BLOCK_END:
/* Too many end notes. */
- if (block_stack == NULL_RTX)
- abort ();
+ gcc_assert (block_stack);
/* Mismatched nesting. */
- if (NOTE_BLOCK (XEXP (block_stack, 0)) != NOTE_BLOCK (insn))
- abort ();
+ gcc_assert (NOTE_BLOCK (XEXP (block_stack, 0)) == NOTE_BLOCK (insn));
tmp = block_stack;
block_stack = XEXP (block_stack, 1);
free_INSN_LIST_node (tmp);
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)
}
/* Too many begin notes. */
- if (block_stack || eh_stack)
- abort ();
+ gcc_assert (!block_stack && !eh_stack);
}
\f
/* Make X be output before the instruction BEFORE. */
rtx
-emit_insn_before (rtx x, rtx before)
+emit_insn_before_noloc (rtx x, rtx before)
{
rtx last = before;
rtx insn;
-#ifdef ENABLE_RTL_CHECKING
- if (before == NULL_RTX)
- abort ();
-#endif
+ gcc_assert (before);
if (x == NULL_RTX)
return last;
#ifdef ENABLE_RTL_CHECKING
case SEQUENCE:
- abort ();
+ gcc_unreachable ();
break;
#endif
and output it before the instruction BEFORE. */
rtx
-emit_jump_insn_before (rtx x, rtx before)
+emit_jump_insn_before_noloc (rtx x, rtx before)
{
rtx insn, last = NULL_RTX;
-#ifdef ENABLE_RTL_CHECKING
- if (before == NULL_RTX)
- abort ();
-#endif
+ gcc_assert (before);
switch (GET_CODE (x))
{
#ifdef ENABLE_RTL_CHECKING
case SEQUENCE:
- abort ();
+ gcc_unreachable ();
break;
#endif
and output it before the instruction BEFORE. */
rtx
-emit_call_insn_before (rtx x, rtx before)
+emit_call_insn_before_noloc (rtx x, rtx before)
{
rtx last = NULL_RTX, insn;
-#ifdef ENABLE_RTL_CHECKING
- if (before == NULL_RTX)
- abort ();
-#endif
+ gcc_assert (before);
switch (GET_CODE (x))
{
#ifdef ENABLE_RTL_CHECKING
case SEQUENCE:
- abort ();
+ gcc_unreachable ();
break;
#endif
{
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;
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;
/* Make X be output after the insn AFTER. */
rtx
-emit_insn_after (rtx x, rtx after)
+emit_insn_after_noloc (rtx x, rtx after)
{
rtx last = after;
-#ifdef ENABLE_RTL_CHECKING
- if (after == NULL_RTX)
- abort ();
-#endif
+ gcc_assert (after);
if (x == NULL_RTX)
return last;
#ifdef ENABLE_RTL_CHECKING
case SEQUENCE:
- abort ();
+ gcc_unreachable ();
break;
#endif
and output it after the insn AFTER. */
rtx
-emit_jump_insn_after (rtx x, rtx after)
+emit_jump_insn_after_noloc (rtx x, rtx after)
{
rtx last;
-#ifdef ENABLE_RTL_CHECKING
- if (after == NULL_RTX)
- abort ();
-#endif
+ gcc_assert (after);
switch (GET_CODE (x))
{
#ifdef ENABLE_RTL_CHECKING
case SEQUENCE:
- abort ();
+ gcc_unreachable ();
break;
#endif
and output it after the instruction AFTER. */
rtx
-emit_call_insn_after (rtx x, rtx after)
+emit_call_insn_after_noloc (rtx x, rtx after)
{
rtx last;
-#ifdef ENABLE_RTL_CHECKING
- if (after == NULL_RTX)
- abort ();
-#endif
+ gcc_assert (after);
switch (GET_CODE (x))
{
#ifdef ENABLE_RTL_CHECKING
case SEQUENCE:
- abort ();
+ gcc_unreachable ();
break;
#endif
{
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);
return note;
}
\f
-/* Like emit_insn_after, but set INSN_LOCATOR according to SCOPE. */
+/* Like emit_insn_after_noloc, but set INSN_LOCATOR according to SCOPE. */
rtx
emit_insn_after_setloc (rtx pattern, rtx after, int loc)
{
- rtx last = emit_insn_after (pattern, after);
+ rtx last = emit_insn_after_noloc (pattern, after);
- if (pattern == NULL_RTX)
+ if (pattern == NULL_RTX || !loc)
return last;
after = NEXT_INSN (after);
while (1)
{
- if (active_insn_p (after))
+ if (active_insn_p (after) && !INSN_LOCATOR (after))
INSN_LOCATOR (after) = loc;
if (after == last)
break;
return last;
}
-/* Like emit_jump_insn_after, but set INSN_LOCATOR according to SCOPE. */
+/* Like emit_insn_after_noloc, but set INSN_LOCATOR according to AFTER. */
+rtx
+emit_insn_after (rtx pattern, rtx after)
+{
+ if (INSN_P (after))
+ return emit_insn_after_setloc (pattern, after, INSN_LOCATOR (after));
+ else
+ return emit_insn_after_noloc (pattern, after);
+}
+
+/* Like emit_jump_insn_after_noloc, but set INSN_LOCATOR according to SCOPE. */
rtx
emit_jump_insn_after_setloc (rtx pattern, rtx after, int loc)
{
- rtx last = emit_jump_insn_after (pattern, after);
+ rtx last = emit_jump_insn_after_noloc (pattern, after);
- if (pattern == NULL_RTX)
+ if (pattern == NULL_RTX || !loc)
return last;
after = NEXT_INSN (after);
while (1)
{
- if (active_insn_p (after))
+ if (active_insn_p (after) && !INSN_LOCATOR (after))
INSN_LOCATOR (after) = loc;
if (after == last)
break;
return last;
}
-/* Like emit_call_insn_after, but set INSN_LOCATOR according to SCOPE. */
+/* Like emit_jump_insn_after_noloc, but set INSN_LOCATOR according to AFTER. */
+rtx
+emit_jump_insn_after (rtx pattern, rtx after)
+{
+ if (INSN_P (after))
+ return emit_jump_insn_after_setloc (pattern, after, INSN_LOCATOR (after));
+ else
+ return emit_jump_insn_after_noloc (pattern, after);
+}
+
+/* Like emit_call_insn_after_noloc, but set INSN_LOCATOR according to SCOPE. */
rtx
emit_call_insn_after_setloc (rtx pattern, rtx after, int loc)
{
- rtx last = emit_call_insn_after (pattern, after);
+ rtx last = emit_call_insn_after_noloc (pattern, after);
- if (pattern == NULL_RTX)
+ if (pattern == NULL_RTX || !loc)
return last;
after = NEXT_INSN (after);
while (1)
{
- if (active_insn_p (after))
+ if (active_insn_p (after) && !INSN_LOCATOR (after))
INSN_LOCATOR (after) = loc;
if (after == last)
break;
return last;
}
-/* Like emit_insn_before, but set INSN_LOCATOR according to SCOPE. */
+/* Like emit_call_insn_after_noloc, but set INSN_LOCATOR according to AFTER. */
+rtx
+emit_call_insn_after (rtx pattern, rtx after)
+{
+ if (INSN_P (after))
+ return emit_call_insn_after_setloc (pattern, after, INSN_LOCATOR (after));
+ else
+ return emit_call_insn_after_noloc (pattern, after);
+}
+
+/* Like emit_insn_before_noloc, but set INSN_LOCATOR according to SCOPE. */
rtx
emit_insn_before_setloc (rtx pattern, rtx before, int loc)
{
rtx first = PREV_INSN (before);
- rtx last = emit_insn_before (pattern, before);
+ rtx last = emit_insn_before_noloc (pattern, before);
+
+ if (pattern == NULL_RTX || !loc)
+ return last;
+
+ first = NEXT_INSN (first);
+ while (1)
+ {
+ if (active_insn_p (first) && !INSN_LOCATOR (first))
+ INSN_LOCATOR (first) = loc;
+ if (first == last)
+ break;
+ first = NEXT_INSN (first);
+ }
+ return last;
+}
+
+/* Like emit_insn_before_noloc, but set INSN_LOCATOR according to BEFORE. */
+rtx
+emit_insn_before (rtx pattern, rtx before)
+{
+ if (INSN_P (before))
+ return emit_insn_before_setloc (pattern, before, INSN_LOCATOR (before));
+ else
+ return emit_insn_before_noloc (pattern, before);
+}
+
+/* like emit_insn_before_noloc, but set insn_locator according to scope. */
+rtx
+emit_jump_insn_before_setloc (rtx pattern, rtx before, int loc)
+{
+ rtx first = PREV_INSN (before);
+ rtx last = emit_jump_insn_before_noloc (pattern, before);
if (pattern == NULL_RTX)
return last;
first = NEXT_INSN (first);
while (1)
{
- if (active_insn_p (first))
+ if (active_insn_p (first) && !INSN_LOCATOR (first))
INSN_LOCATOR (first) = loc;
if (first == last)
break;
}
return last;
}
+
+/* Like emit_jump_insn_before_noloc, but set INSN_LOCATOR according to BEFORE. */
+rtx
+emit_jump_insn_before (rtx pattern, rtx before)
+{
+ if (INSN_P (before))
+ return emit_jump_insn_before_setloc (pattern, before, INSN_LOCATOR (before));
+ else
+ return emit_jump_insn_before_noloc (pattern, before);
+}
+
+/* like emit_insn_before_noloc, but set insn_locator according to scope. */
+rtx
+emit_call_insn_before_setloc (rtx pattern, rtx before, int loc)
+{
+ rtx first = PREV_INSN (before);
+ rtx last = emit_call_insn_before_noloc (pattern, before);
+
+ if (pattern == NULL_RTX)
+ return last;
+
+ first = NEXT_INSN (first);
+ while (1)
+ {
+ if (active_insn_p (first) && !INSN_LOCATOR (first))
+ INSN_LOCATOR (first) = loc;
+ if (first == last)
+ break;
+ first = NEXT_INSN (first);
+ }
+ return last;
+}
+
+/* like emit_call_insn_before_noloc,
+ but set insn_locator according to before. */
+rtx
+emit_call_insn_before (rtx pattern, rtx before)
+{
+ if (INSN_P (before))
+ return emit_call_insn_before_setloc (pattern, before, INSN_LOCATOR (before));
+ else
+ return emit_call_insn_before_noloc (pattern, before);
+}
\f
/* Take X and emit it at the end of the doubly-linked
INSN list.
#ifdef ENABLE_RTL_CHECKING
case SEQUENCE:
- abort ();
+ gcc_unreachable ();
break;
#endif
#ifdef ENABLE_RTL_CHECKING
case SEQUENCE:
- abort ();
+ gcc_unreachable ();
break;
#endif
#ifdef ENABLE_RTL_CHECKING
case SEQUENCE:
- abort ();
+ gcc_unreachable ();
break;
#endif
{
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)
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;
}
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
means the insn only has one * useful * set). */
if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn))
{
- if (note)
- abort ();
+ gcc_assert (!note);
return NULL_RTX;
}
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;
{
enum rtx_code code = classify_insn (x);
- if (code == CODE_LABEL)
- return emit_label (x);
- else if (code == INSN)
- return emit_insn (x);
- else if (code == JUMP_INSN)
+ switch (code)
{
- rtx insn = emit_jump_insn (x);
- if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN)
- return emit_barrier ();
- return insn;
+ case CODE_LABEL:
+ return emit_label (x);
+ case INSN:
+ return emit_insn (x);
+ case JUMP_INSN:
+ {
+ rtx insn = emit_jump_insn (x);
+ if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN)
+ return emit_barrier ();
+ return insn;
+ }
+ case CALL_INSN:
+ return emit_call_insn (x);
+ default:
+ gcc_unreachable ();
}
- else if (code == CALL_INSN)
- return emit_call_insn (x);
- else
- abort ();
}
\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
- 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)
tem->next = seq_stack;
tem->first = first_insn;
tem->last = last_insn;
- tem->sequence_rtl_expr = seq_rtl_expr;
seq_stack = tem;
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. */
first_insn = first;
last_insn = last;
/* We really should have the end of the insn chain here. */
- if (last && NEXT_INSN (last))
- abort ();
+ gcc_assert (!last || !NEXT_INSN (last));
}
/* Set up the outer-level insn chain
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
top->first = first_insn;
top->last = last_insn;
- /* ??? Why don't we save seq_rtl_expr here? */
end_sequence ();
}
first_insn = tem->first;
last_insn = tem->last;
- seq_rtl_expr = tem->sequence_rtl_expr;
seq_stack = tem->next;
memset (tem, 0, sizeof (*tem));
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
switch (code)
{
case REG:
- case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
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)
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;
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
if (code == SCRATCH)
{
i = copy_insn_n_scratches++;
- if (i >= MAX_RECOG_OPERANDS)
- abort ();
+ gcc_assert (i < MAX_RECOG_OPERANDS);
copy_insn_scratch_in[i] = orig;
copy_insn_scratch_out[i] = copy;
}
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;
#endif
}
-/* Generate the constant 0. */
+/* Generate a vector constant for mode MODE and constant value CONSTANT. */
static rtx
-gen_const_vector_0 (enum machine_mode mode)
+gen_const_vector (enum machine_mode mode, int constant)
{
rtx tem;
rtvec v;
v = rtvec_alloc (units);
- /* We need to call this function after we to set CONST0_RTX first. */
- if (!CONST0_RTX (inner))
- abort ();
+ /* We need to call this function after we set the scalar const_tiny_rtx
+ entries. */
+ gcc_assert (const_tiny_rtx[constant][(int) inner]);
for (i = 0; i < units; ++i)
- RTVEC_ELT (v, i) = CONST0_RTX (inner);
+ RTVEC_ELT (v, i) = const_tiny_rtx[constant][(int) inner];
tem = gen_rtx_raw_CONST_VECTOR (mode, v);
return tem;
}
/* Generate a vector like gen_rtx_raw_CONST_VEC, but use the zero vector when
- all elements are zero. */
+ all elements are zero, and the one vector when all elements are one. */
rtx
gen_rtx_CONST_VECTOR (enum machine_mode mode, rtvec v)
{
- rtx inner_zero = CONST0_RTX (GET_MODE_INNER (mode));
+ enum machine_mode inner = GET_MODE_INNER (mode);
+ int nunits = GET_MODE_NUNITS (mode);
+ rtx x;
int i;
- for (i = GET_MODE_NUNITS (mode) - 1; i >= 0; i--)
- if (RTVEC_ELT (v, i) != inner_zero)
- return gen_rtx_raw_CONST_VECTOR (mode, v);
- return CONST0_RTX (mode);
+ /* Check to see if all of the elements have the same value. */
+ x = RTVEC_ELT (v, nunits - 1);
+ for (i = nunits - 2; i >= 0; i--)
+ if (RTVEC_ELT (v, i) != x)
+ break;
+
+ /* If the values are all the same, check to see if we can use one of the
+ standard constant vectors. */
+ if (i == -1)
+ {
+ if (x == CONST0_RTX (inner))
+ return CONST0_RTX (mode);
+ else if (x == CONST1_RTX (inner))
+ return CONST1_RTX (mode);
+ }
+
+ return gen_rtx_raw_CONST_VECTOR (mode, v);
}
/* Create some permanent unique rtl objects shared between all functions.
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);
for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
- const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode);
+ {
+ const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+ const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1);
+ }
for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
- const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode);
+ {
+ const_tiny_rtx[0][(int) mode] = gen_const_vector (mode, 0);
+ const_tiny_rtx[1][(int) mode] = gen_const_vector (mode, 1);
+ }
for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i)
if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC)
pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
}
\f
-/* 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. */
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* Update LABEL_NUSES. */
return new;
}
-static GTY((deletable(""))) rtx hard_reg_clobbers [NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];
+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)
{