/* Analyze RTL for GNU compiler.
- Copyright (C) 1987-2013 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "flags.h"
#include "regs.h"
#include "function.h"
+#include "predict.h"
+#include "basic-block.h"
#include "df.h"
+#include "symtab.h"
#include "tree.h"
#include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */
#include "addresses.h"
+#include "rtl-iter.h"
/* Forward declarations */
static void set_of_1 (rtx, const_rtx, void *);
static bool covers_regno_p (const_rtx, unsigned int);
static bool covers_regno_no_parallel_p (const_rtx, unsigned int);
-static int rtx_referenced_p_1 (rtx *, void *);
static int computed_jump_p_1 (const_rtx);
static void parms_set (rtx, const_rtx, void *);
-static unsigned HOST_WIDE_INT cached_nonzero_bits (const_rtx, enum machine_mode,
- const_rtx, enum machine_mode,
+static unsigned HOST_WIDE_INT cached_nonzero_bits (const_rtx, machine_mode,
+ const_rtx, machine_mode,
unsigned HOST_WIDE_INT);
-static unsigned HOST_WIDE_INT nonzero_bits1 (const_rtx, enum machine_mode,
- const_rtx, enum machine_mode,
+static unsigned HOST_WIDE_INT nonzero_bits1 (const_rtx, machine_mode,
+ const_rtx, machine_mode,
unsigned HOST_WIDE_INT);
-static unsigned int cached_num_sign_bit_copies (const_rtx, enum machine_mode, const_rtx,
- enum machine_mode,
+static unsigned int cached_num_sign_bit_copies (const_rtx, machine_mode, const_rtx,
+ machine_mode,
unsigned int);
-static unsigned int num_sign_bit_copies1 (const_rtx, enum machine_mode, const_rtx,
- enum machine_mode, unsigned int);
+static unsigned int num_sign_bit_copies1 (const_rtx, machine_mode, const_rtx,
+ machine_mode, unsigned int);
-/* Offset of the first 'e', 'E' or 'V' operand for each rtx code, or
- -1 if a code has no such operand. */
-static int non_rtx_starting_operands[NUM_RTX_CODE];
+rtx_subrtx_bound_info rtx_all_subrtx_bounds[NUM_RTX_CODE];
+rtx_subrtx_bound_info rtx_nonconst_subrtx_bounds[NUM_RTX_CODE];
/* Truncation narrows the mode from SOURCE mode to DESTINATION mode.
If TARGET_MODE_REP_EXTENDED (DESTINATION, DESTINATION_REP) is
static unsigned int
num_sign_bit_copies_in_rep[MAX_MODE_INT + 1][MAX_MODE_INT + 1];
\f
+/* Store X into index I of ARRAY. ARRAY is known to have at least I
+ elements. Return the new base of ARRAY. */
+
+template <typename T>
+typename T::value_type *
+generic_subrtx_iterator <T>::add_single_to_queue (array_type &array,
+ value_type *base,
+ size_t i, value_type x)
+{
+ if (base == array.stack)
+ {
+ if (i < LOCAL_ELEMS)
+ {
+ base[i] = x;
+ return base;
+ }
+ gcc_checking_assert (i == LOCAL_ELEMS);
+ /* A previous iteration might also have moved from the stack to the
+ heap, in which case the heap array will already be big enough. */
+ if (vec_safe_length (array.heap) <= i)
+ vec_safe_grow (array.heap, i + 1);
+ base = array.heap->address ();
+ memcpy (base, array.stack, sizeof (array.stack));
+ base[LOCAL_ELEMS] = x;
+ return base;
+ }
+ unsigned int length = array.heap->length ();
+ if (length > i)
+ {
+ gcc_checking_assert (base == array.heap->address ());
+ base[i] = x;
+ return base;
+ }
+ else
+ {
+ gcc_checking_assert (i == length);
+ vec_safe_push (array.heap, x);
+ return array.heap->address ();
+ }
+}
+
+/* Add the subrtxes of X to worklist ARRAY, starting at END. Return the
+ number of elements added to the worklist. */
+
+template <typename T>
+size_t
+generic_subrtx_iterator <T>::add_subrtxes_to_queue (array_type &array,
+ value_type *base,
+ size_t end, rtx_type x)
+{
+ enum rtx_code code = GET_CODE (x);
+ const char *format = GET_RTX_FORMAT (code);
+ size_t orig_end = end;
+ if (__builtin_expect (INSN_P (x), false))
+ {
+ /* Put the pattern at the top of the queue, since that's what
+ we're likely to want most. It also allows for the SEQUENCE
+ code below. */
+ for (int i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; --i)
+ if (format[i] == 'e')
+ {
+ value_type subx = T::get_value (x->u.fld[i].rt_rtx);
+ if (__builtin_expect (end < LOCAL_ELEMS, true))
+ base[end++] = subx;
+ else
+ base = add_single_to_queue (array, base, end++, subx);
+ }
+ }
+ else
+ for (int i = 0; format[i]; ++i)
+ if (format[i] == 'e')
+ {
+ value_type subx = T::get_value (x->u.fld[i].rt_rtx);
+ if (__builtin_expect (end < LOCAL_ELEMS, true))
+ base[end++] = subx;
+ else
+ base = add_single_to_queue (array, base, end++, subx);
+ }
+ else if (format[i] == 'E')
+ {
+ unsigned int length = GET_NUM_ELEM (x->u.fld[i].rt_rtvec);
+ rtx *vec = x->u.fld[i].rt_rtvec->elem;
+ if (__builtin_expect (end + length <= LOCAL_ELEMS, true))
+ for (unsigned int j = 0; j < length; j++)
+ base[end++] = T::get_value (vec[j]);
+ else
+ for (unsigned int j = 0; j < length; j++)
+ base = add_single_to_queue (array, base, end++,
+ T::get_value (vec[j]));
+ if (code == SEQUENCE && end == length)
+ /* If the subrtxes of the sequence fill the entire array then
+ we know that no other parts of a containing insn are queued.
+ The caller is therefore iterating over the sequence as a
+ PATTERN (...), so we also want the patterns of the
+ subinstructions. */
+ for (unsigned int j = 0; j < length; j++)
+ {
+ typename T::rtx_type x = T::get_rtx (base[j]);
+ if (INSN_P (x))
+ base[j] = T::get_value (PATTERN (x));
+ }
+ }
+ return end - orig_end;
+}
+
+template <typename T>
+void
+generic_subrtx_iterator <T>::free_array (array_type &array)
+{
+ vec_free (array.heap);
+}
+
+template <typename T>
+const size_t generic_subrtx_iterator <T>::LOCAL_ELEMS;
+
+template class generic_subrtx_iterator <const_rtx_accessor>;
+template class generic_subrtx_iterator <rtx_var_accessor>;
+template class generic_subrtx_iterator <rtx_ptr_accessor>;
+
/* Return 1 if the value of X is unstable
(would be different at a different point in the program).
The frame pointer, arg pointer, etc. are considered stable
return 0;
}
-/* Return nonzero if the use of X as an address in a MEM can cause a trap.
- MODE is the mode of the MEM (not that of X) and UNALIGNED_MEMS controls
- whether nonzero is returned for unaligned memory accesses on strict
- alignment machines. */
+/* Return nonzero if the use of X+OFFSET as an address in a MEM with SIZE
+ bytes can cause a trap. MODE is the mode of the MEM (not that of X) and
+ UNALIGNED_MEMS controls whether nonzero is returned for unaligned memory
+ references on strict alignment machines. */
static int
rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
- enum machine_mode mode, bool unaligned_mems)
+ machine_mode mode, bool unaligned_mems)
{
enum rtx_code code = GET_CODE (x);
- if (STRICT_ALIGNMENT
- && unaligned_mems
- && GET_MODE_SIZE (mode) != 0)
+ /* The offset must be a multiple of the mode size if we are considering
+ unaligned memory references on strict alignment machines. */
+ if (STRICT_ALIGNMENT && unaligned_mems && GET_MODE_SIZE (mode) != 0)
{
HOST_WIDE_INT actual_offset = offset;
+
#ifdef SPARC_STACK_BOUNDARY_HACK
/* ??? The SPARC port may claim a STACK_BOUNDARY higher than
the real alignment of %sp. However, when it does this, the
if (!decl)
decl_size = -1;
else if (DECL_P (decl) && DECL_SIZE_UNIT (decl))
- decl_size = (host_integerp (DECL_SIZE_UNIT (decl), 0)
- ? tree_low_cst (DECL_SIZE_UNIT (decl), 0)
+ decl_size = (tree_fits_shwi_p (DECL_SIZE_UNIT (decl))
+ ? tree_to_shwi (DECL_SIZE_UNIT (decl))
: -1);
else if (TREE_CODE (decl) == STRING_CST)
decl_size = TREE_STRING_LENGTH (decl);
return 0;
case REG:
- /* As in rtx_varies_p, we have to use the actual rtx, not reg number. */
- if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
+ /* Stack references are assumed not to trap, but we need to deal with
+ nonsensical offsets. */
+ if (x == frame_pointer_rtx)
+ {
+ HOST_WIDE_INT adj_offset = offset - STARTING_FRAME_OFFSET;
+ if (size == 0)
+ size = GET_MODE_SIZE (mode);
+ if (FRAME_GROWS_DOWNWARD)
+ {
+ if (adj_offset < frame_offset || adj_offset + size - 1 >= 0)
+ return 1;
+ }
+ else
+ {
+ if (adj_offset < 0 || adj_offset + size - 1 >= frame_offset)
+ return 1;
+ }
+ return 0;
+ }
+ /* ??? Need to add a similar guard for nonsensical offsets. */
+ if (x == hard_frame_pointer_rtx
|| x == stack_pointer_rtx
/* The arg pointer varies if it is not a fixed register. */
|| (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
if (XEXP (x, 0) == pic_offset_table_rtx && CONSTANT_P (XEXP (x, 1)))
return 0;
- /* - or it is an address that can't trap plus a constant integer,
- with the proper remainder modulo the mode size if we are
- considering unaligned memory references. */
+ /* - or it is an address that can't trap plus a constant integer. */
if (CONST_INT_P (XEXP (x, 1))
&& !rtx_addr_can_trap_p_1 (XEXP (x, 0), offset + INTVAL (XEXP (x, 1)),
size, mode, unaligned_mems))
return true;
if (GET_CODE (op) == SUBREG
- && SUBREG_PROMOTED_UNSIGNED_P (op))
+ && SUBREG_PROMOTED_SIGN (op))
return true;
return false;
return 1;
if (GET_CODE (in) == LABEL_REF)
- return reg == XEXP (in, 0);
+ return reg == LABEL_REF_LABEL (in);
code = GET_CODE (in);
no CODE_LABEL insn. */
int
-no_labels_between_p (const_rtx beg, const_rtx end)
+no_labels_between_p (const rtx_insn *beg, const rtx_insn *end)
{
- rtx p;
+ rtx_insn *p;
if (beg == end)
return 0;
for (p = NEXT_INSN (beg); p != end; p = NEXT_INSN (p))
FROM_INSN and TO_INSN (exclusive of those two). */
int
-reg_used_between_p (const_rtx reg, const_rtx from_insn, const_rtx to_insn)
+reg_used_between_p (const_rtx reg, const rtx_insn *from_insn,
+ const rtx_insn *to_insn)
{
- rtx insn;
+ rtx_insn *insn;
if (from_insn == to_insn)
return 0;
FROM_INSN and TO_INSN (exclusive of those two). */
int
-reg_set_between_p (const_rtx reg, const_rtx from_insn, const_rtx to_insn)
+reg_set_between_p (const_rtx reg, const rtx_insn *from_insn,
+ const rtx_insn *to_insn)
{
- const_rtx insn;
+ const rtx_insn *insn;
if (from_insn == to_insn)
return 0;
int
reg_set_p (const_rtx reg, const_rtx insn)
{
+ /* After delay slot handling, call and branch insns might be in a
+ sequence. Check all the elements there. */
+ if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
+ {
+ for (int i = 0; i < XVECLEN (PATTERN (insn), 0); ++i)
+ if (reg_set_p (reg, XVECEXP (PATTERN (insn), 0, i)))
+ return true;
+
+ return false;
+ }
+
/* We can be passed an insn or part of one. If we are passed an insn,
check if a side-effect of the insn clobbers REG. */
if (INSN_P (insn)
GET_MODE (reg), REGNO (reg)))
|| MEM_P (reg)
|| find_reg_fusage (insn, CLOBBER, reg)))))
- return 1;
+ return true;
return set_of (reg, insn) != NULL_RTX;
}
X contains a MEM; this routine does use memory aliasing. */
int
-modified_between_p (const_rtx x, const_rtx start, const_rtx end)
+modified_between_p (const_rtx x, const rtx_insn *start, const rtx_insn *end)
{
const enum rtx_code code = GET_CODE (x);
const char *fmt;
int i, j;
- rtx insn;
+ rtx_insn *insn;
if (start == end)
return 0;
return data.found;
}
+/* Add all hard register in X to *PSET. */
+void
+find_all_hard_regs (const_rtx x, HARD_REG_SET *pset)
+{
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, x, NONCONST)
+ {
+ const_rtx x = *iter;
+ if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ add_to_hard_reg_set (pset, GET_MODE (x), REGNO (x));
+ }
+}
+
/* This function, called through note_stores, collects sets and
clobbers of hard registers in a HARD_REG_SET, which is pointed to
by DATA. */
/* Examine INSN, and compute the set of hard registers written by it.
Store it in *PSET. Should only be called after reload. */
void
-find_all_hard_reg_sets (const_rtx insn, HARD_REG_SET *pset)
+find_all_hard_reg_sets (const rtx_insn *insn, HARD_REG_SET *pset, bool implicit)
{
rtx link;
CLEAR_HARD_REG_SET (*pset);
note_stores (PATTERN (insn), record_hard_reg_sets, pset);
if (CALL_P (insn))
- IOR_HARD_REG_SET (*pset, call_used_reg_set);
+ {
+ if (implicit)
+ IOR_HARD_REG_SET (*pset, call_used_reg_set);
+
+ for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+ record_hard_reg_sets (XEXP (link, 0), NULL, pset);
+ }
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_INC)
record_hard_reg_sets (XEXP (link, 0), NULL, pset);
}
-/* A for_each_rtx subroutine of record_hard_reg_uses. */
-static int
-record_hard_reg_uses_1 (rtx *px, void *data)
-{
- rtx x = *px;
- HARD_REG_SET *pused = (HARD_REG_SET *)data;
-
- if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
- {
- int nregs = hard_regno_nregs[REGNO (x)][GET_MODE (x)];
- while (nregs-- > 0)
- SET_HARD_REG_BIT (*pused, REGNO (x) + nregs);
- }
- return 0;
-}
-
/* Like record_hard_reg_sets, but called through note_uses. */
void
record_hard_reg_uses (rtx *px, void *data)
{
- for_each_rtx (px, record_hard_reg_uses_1, data);
+ find_all_hard_regs (*px, (HARD_REG_SET *) data);
}
\f
/* Given an INSN, return a SET expression if this insn has only a single SET.
will not be used, which we ignore. */
rtx
-single_set_2 (const_rtx insn, const_rtx pat)
+single_set_2 (const rtx_insn *insn, const_rtx pat)
{
rtx set = NULL;
int set_verified = 1;
dst = SUBREG_REG (dst);
}
+ /* It is a NOOP if destination overlaps with selected src vector
+ elements. */
+ if (GET_CODE (src) == VEC_SELECT
+ && REG_P (XEXP (src, 0)) && REG_P (dst)
+ && HARD_REGISTER_P (XEXP (src, 0))
+ && HARD_REGISTER_P (dst))
+ {
+ int i;
+ rtx par = XEXP (src, 1);
+ rtx src0 = XEXP (src, 0);
+ int c0 = INTVAL (XVECEXP (par, 0, 0));
+ HOST_WIDE_INT offset = GET_MODE_UNIT_SIZE (GET_MODE (src0)) * c0;
+
+ for (i = 1; i < XVECLEN (par, 0); i++)
+ if (INTVAL (XVECEXP (par, 0, i)) != c0 + i)
+ return 0;
+ return
+ simplify_subreg_regno (REGNO (src0), GET_MODE (src0),
+ offset, GET_MODE (dst)) == (int) REGNO (dst);
+ }
+
return (REG_P (src) && REG_P (dst)
&& REGNO (src) == REGNO (dst));
}
value to itself. */
int
-noop_move_p (const_rtx insn)
+noop_move_p (const rtx_insn *insn)
{
rtx pat = PATTERN (insn);
if (find_reg_note (insn, REG_EQUAL, NULL_RTX))
return 0;
+ /* Check the code to be executed for COND_EXEC. */
+ if (GET_CODE (pat) == COND_EXEC)
+ pat = COND_EXEC_CODE (pat);
+
if (GET_CODE (pat) == SET && set_noop_p (pat))
return 1;
}
\f
-/* Return the last thing that X was assigned from before *PINSN. If VALID_TO
- is not NULL_RTX then verify that the object is not modified up to VALID_TO.
- If the object was modified, if we hit a partial assignment to X, or hit a
- CODE_LABEL first, return X. If we found an assignment, update *PINSN to
- point to it. ALLOW_HWREG is set to 1 if hardware registers are allowed to
- be the src. */
-
-rtx
-find_last_value (rtx x, rtx *pinsn, rtx valid_to, int allow_hwreg)
-{
- rtx p;
-
- for (p = PREV_INSN (*pinsn); p && !LABEL_P (p);
- p = PREV_INSN (p))
- if (INSN_P (p))
- {
- rtx set = single_set (p);
- rtx note = find_reg_note (p, REG_EQUAL, NULL_RTX);
-
- if (set && rtx_equal_p (x, SET_DEST (set)))
- {
- rtx src = SET_SRC (set);
-
- if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST)
- src = XEXP (note, 0);
-
- if ((valid_to == NULL_RTX
- || ! modified_between_p (src, PREV_INSN (p), valid_to))
- /* Reject hard registers because we don't usually want
- to use them; we'd rather use a pseudo. */
- && (! (REG_P (src)
- && REGNO (src) < FIRST_PSEUDO_REGISTER) || allow_hwreg))
- {
- *pinsn = p;
- return src;
- }
- }
-
- /* If set in non-simple way, we don't have a value. */
- if (reg_set_p (x, p))
- break;
- }
-
- return x;
-}
-\f
/* Return nonzero if register in range [REGNO, ENDREGNO)
appears either explicitly or implicitly in X
other than being stored into.
References contained within the substructure at LOC do not count.
LOC may be zero, meaning don't ignore anything. */
-int
+bool
refers_to_regno_p (unsigned int regno, unsigned int endregno, const_rtx x,
rtx *loc)
{
/* The contents of a REG_NONNEG note is always zero, so we must come here
upon repeat in case the last REG_NOTE is a REG_NONNEG note. */
if (x == 0)
- return 0;
+ return false;
code = GET_CODE (x);
clobber a virtual register. In fact, we could be more precise,
but it isn't worth it. */
if ((x_regno == STACK_POINTER_REGNUM
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
- || x_regno == ARG_POINTER_REGNUM
-#endif
+ || (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ && x_regno == ARG_POINTER_REGNUM)
|| x_regno == FRAME_POINTER_REGNUM)
&& regno >= FIRST_VIRTUAL_REGISTER && regno <= LAST_VIRTUAL_REGISTER)
- return 1;
+ return true;
return endregno > x_regno && regno < END_REGNO (x);
SUBREG_REG (SET_DEST (x)), loc))
|| (!REG_P (SET_DEST (x))
&& refers_to_regno_p (regno, endregno, SET_DEST (x), loc))))
- return 1;
+ return true;
if (code == CLOBBER || loc == &SET_SRC (x))
- return 0;
+ return false;
x = SET_SRC (x);
goto repeat;
}
else
if (refers_to_regno_p (regno, endregno, XEXP (x, i), loc))
- return 1;
+ return true;
}
else if (fmt[i] == 'E')
{
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (loc != &XVECEXP (x, i, j)
&& refers_to_regno_p (regno, endregno, XVECEXP (x, i, j), loc))
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
/* Nonzero if modifying X will affect IN. If X is a register or a SUBREG,
return null. */
rtx
-find_constant_src (const_rtx insn)
+find_constant_src (const rtx_insn *insn)
{
rtx note, set, x;
if (regno < FIRST_PSEUDO_REGISTER)
{
- unsigned int end_regno = END_HARD_REGNO (datum);
+ unsigned int end_regno = END_REGNO (datum);
unsigned int i;
for (i = regno; i < end_regno; i++)
if (GET_CODE (op = XEXP (link, 0)) == code
&& REG_P (reg = XEXP (op, 0))
&& REGNO (reg) <= regno
- && END_HARD_REGNO (reg) > regno)
+ && END_REGNO (reg) > regno)
return 1;
}
}
\f
+/* Return true if KIND is an integer REG_NOTE. */
+
+static bool
+int_reg_note_p (enum reg_note kind)
+{
+ return kind == REG_BR_PROB;
+}
+
/* Allocate a register note with kind KIND and datum DATUM. LIST is
stored as the pointer to the next register note. */
{
rtx note;
+ gcc_checking_assert (!int_reg_note_p (kind));
switch (kind)
{
case REG_CC_SETTER:
REG_NOTES (insn) = alloc_reg_note (kind, datum, REG_NOTES (insn));
}
+/* Add an integer register note with kind KIND and datum DATUM to INSN. */
+
+void
+add_int_reg_note (rtx insn, enum reg_note kind, int datum)
+{
+ gcc_checking_assert (int_reg_note_p (kind));
+ REG_NOTES (insn) = gen_rtx_INT_LIST ((machine_mode) kind,
+ datum, REG_NOTES (insn));
+}
+
+/* Add a register note like NOTE to INSN. */
+
+void
+add_shallow_copy_of_reg_note (rtx_insn *insn, rtx note)
+{
+ if (GET_CODE (note) == INT_LIST)
+ add_int_reg_note (insn, REG_NOTE_KIND (note), XINT (note, 0));
+ else
+ add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
+}
+
/* Remove register note NOTE from the REG_NOTES of INSN. */
void
{
case REG_EQUAL:
case REG_EQUIV:
- df_notes_rescan (insn);
+ df_notes_rescan (as_a <rtx_insn *> (insn));
break;
default:
break;
/* Remove REG_EQUAL and/or REG_EQUIV notes if INSN has such notes. */
void
-remove_reg_equal_equiv_notes (rtx insn)
+remove_reg_equal_equiv_notes (rtx_insn *insn)
{
rtx *loc;
over the head. We plan to drain the list anyway. */
while ((eq_use = DF_REG_EQ_USE_CHAIN (regno)) != NULL)
{
- rtx insn = DF_REF_INSN (eq_use);
+ rtx_insn *insn = DF_REF_INSN (eq_use);
rtx note = find_reg_equal_equiv_note (insn);
/* This assert is generally triggered when someone deletes a REG_EQUAL
return 1 if it is found. A simple equality test is used to determine if
NODE matches. */
-int
-in_expr_list_p (const_rtx listp, const_rtx node)
+bool
+in_insn_list_p (const rtx_insn_list *listp, const rtx_insn *node)
{
const_rtx x;
for (x = listp; x; x = XEXP (x, 1))
if (node == XEXP (x, 0))
- return 1;
+ return true;
- return 0;
+ return false;
}
/* Search LISTP (an EXPR_LIST) for an entry whose first operand is NODE and
A simple equality test is used to determine if NODE matches. */
void
-remove_node_from_expr_list (const_rtx node, rtx *listp)
+remove_node_from_expr_list (const_rtx node, rtx_expr_list **listp)
+{
+ rtx_expr_list *temp = *listp;
+ rtx_expr_list *prev = NULL;
+
+ while (temp)
+ {
+ if (node == temp->element ())
+ {
+ /* Splice the node out of the list. */
+ if (prev)
+ XEXP (prev, 1) = temp->next ();
+ else
+ *listp = temp->next ();
+
+ return;
+ }
+
+ prev = temp;
+ temp = temp->next ();
+ }
+}
+
+/* Search LISTP (an INSN_LIST) for an entry whose first operand is NODE and
+ remove that entry from the list if it is found.
+
+ A simple equality test is used to determine if NODE matches. */
+
+void
+remove_node_from_insn_list (const rtx_insn *node, rtx_insn_list **listp)
{
- rtx temp = *listp;
- rtx prev = NULL_RTX;
+ rtx_insn_list *temp = *listp;
+ rtx_insn_list *prev = NULL;
while (temp)
{
- if (node == XEXP (temp, 0))
+ if (node == temp->insn ())
{
/* Splice the node out of the list. */
if (prev)
- XEXP (prev, 1) = XEXP (temp, 1);
+ XEXP (prev, 1) = temp->next ();
else
- *listp = XEXP (temp, 1);
+ *listp = temp->next ();
return;
}
prev = temp;
- temp = XEXP (temp, 1);
+ temp = temp->next ();
}
}
\f
case MOD:
case UDIV:
case UMOD:
- if (HONOR_SNANS (GET_MODE (x)))
+ if (HONOR_SNANS (x))
return 1;
if (SCALAR_FLOAT_MODE_P (GET_MODE (x)))
return flag_trapping_math;
when COMPARE is used, though many targets do make this distinction.
For instance, sparc uses CCFPE for compares which generate exceptions
and CCFP for compares which do not generate exceptions. */
- if (HONOR_NANS (GET_MODE (x)))
+ if (HONOR_NANS (x))
return 1;
/* But often the compare has some CC mode, so check operand
modes as well. */
- if (HONOR_NANS (GET_MODE (XEXP (x, 0)))
- || HONOR_NANS (GET_MODE (XEXP (x, 1))))
+ if (HONOR_NANS (XEXP (x, 0))
+ || HONOR_NANS (XEXP (x, 1)))
return 1;
break;
case EQ:
case NE:
- if (HONOR_SNANS (GET_MODE (x)))
+ if (HONOR_SNANS (x))
return 1;
/* Often comparison is CC mode, so check operand modes. */
- if (HONOR_SNANS (GET_MODE (XEXP (x, 0)))
- || HONOR_SNANS (GET_MODE (XEXP (x, 1))))
+ if (HONOR_SNANS (XEXP (x, 0))
+ || HONOR_SNANS (XEXP (x, 1)))
return 1;
break;
case FIX:
/* Conversion of floating point might trap. */
- if (flag_trapping_math && HONOR_NANS (GET_MODE (XEXP (x, 0))))
+ if (flag_trapping_math && HONOR_NANS (XEXP (x, 0)))
return 1;
break;
return x;
}
\f
-/* Replace occurrences of the old label in *X with the new one.
- DATA is a REPLACE_LABEL_DATA containing the old and new labels. */
+/* Replace occurrences of the OLD_LABEL in *LOC with NEW_LABEL. Also track
+ the change in LABEL_NUSES if UPDATE_LABEL_NUSES. */
-int
-replace_label (rtx *x, void *data)
+void
+replace_label (rtx *loc, rtx old_label, rtx new_label, bool update_label_nuses)
{
- rtx l = *x;
- rtx old_label = ((replace_label_data *) data)->r1;
- rtx new_label = ((replace_label_data *) data)->r2;
- bool update_label_nuses = ((replace_label_data *) data)->update_label_nuses;
-
- if (l == NULL_RTX)
- return 0;
-
- if (GET_CODE (l) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (l))
+ /* Handle jump tables specially, since ADDR_{DIFF_,}VECs can be long. */
+ rtx x = *loc;
+ if (JUMP_TABLE_DATA_P (x))
{
- rtx c = get_pool_constant (l);
- if (rtx_referenced_p (old_label, c))
+ x = PATTERN (x);
+ rtvec vec = XVEC (x, GET_CODE (x) == ADDR_DIFF_VEC);
+ int len = GET_NUM_ELEM (vec);
+ for (int i = 0; i < len; ++i)
{
- rtx new_c, new_l;
- replace_label_data *d = (replace_label_data *) data;
-
- /* Create a copy of constant C; replace the label inside
- but do not update LABEL_NUSES because uses in constant pool
- are not counted. */
- new_c = copy_rtx (c);
- d->update_label_nuses = false;
- for_each_rtx (&new_c, replace_label, data);
- d->update_label_nuses = update_label_nuses;
-
- /* Add the new constant NEW_C to constant pool and replace
- the old reference to constant by new reference. */
- new_l = XEXP (force_const_mem (get_pool_mode (l), new_c), 0);
- *x = replace_rtx (l, l, new_l);
+ rtx ref = RTVEC_ELT (vec, i);
+ if (XEXP (ref, 0) == old_label)
+ {
+ XEXP (ref, 0) = new_label;
+ if (update_label_nuses)
+ {
+ ++LABEL_NUSES (new_label);
+ --LABEL_NUSES (old_label);
+ }
+ }
}
- return 0;
+ return;
}
/* If this is a JUMP_INSN, then we also need to fix the JUMP_LABEL
- field. This is not handled by for_each_rtx because it doesn't
+ field. This is not handled by the iterator because it doesn't
handle unprinted ('0') fields. */
- if (JUMP_P (l) && JUMP_LABEL (l) == old_label)
- JUMP_LABEL (l) = new_label;
+ if (JUMP_P (x) && JUMP_LABEL (x) == old_label)
+ JUMP_LABEL (x) = new_label;
- if ((GET_CODE (l) == LABEL_REF
- || GET_CODE (l) == INSN_LIST)
- && XEXP (l, 0) == old_label)
+ subrtx_ptr_iterator::array_type array;
+ FOR_EACH_SUBRTX_PTR (iter, array, loc, ALL)
{
- XEXP (l, 0) = new_label;
- if (update_label_nuses)
+ rtx *loc = *iter;
+ if (rtx x = *loc)
{
- ++LABEL_NUSES (new_label);
- --LABEL_NUSES (old_label);
+ if (GET_CODE (x) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (x))
+ {
+ rtx c = get_pool_constant (x);
+ if (rtx_referenced_p (old_label, c))
+ {
+ /* Create a copy of constant C; replace the label inside
+ but do not update LABEL_NUSES because uses in constant pool
+ are not counted. */
+ rtx new_c = copy_rtx (c);
+ replace_label (&new_c, old_label, new_label, false);
+
+ /* Add the new constant NEW_C to constant pool and replace
+ the old reference to constant by new reference. */
+ rtx new_mem = force_const_mem (get_pool_mode (x), new_c);
+ *loc = replace_rtx (x, x, XEXP (new_mem, 0));
+ }
+ }
+
+ if ((GET_CODE (x) == LABEL_REF
+ || GET_CODE (x) == INSN_LIST)
+ && XEXP (x, 0) == old_label)
+ {
+ XEXP (x, 0) = new_label;
+ if (update_label_nuses)
+ {
+ ++LABEL_NUSES (new_label);
+ --LABEL_NUSES (old_label);
+ }
+ }
}
- return 0;
}
-
- return 0;
}
-/* When *BODY is equal to X or X is directly referenced by *BODY
- return nonzero, thus FOR_EACH_RTX stops traversing and returns nonzero
- too, otherwise FOR_EACH_RTX continues traversing *BODY. */
-
-static int
-rtx_referenced_p_1 (rtx *body, void *x)
+void
+replace_label_in_insn (rtx_insn *insn, rtx old_label, rtx new_label,
+ bool update_label_nuses)
{
- rtx y = (rtx) x;
-
- if (*body == NULL_RTX)
- return y == NULL_RTX;
-
- /* Return true if a label_ref *BODY refers to label Y. */
- if (GET_CODE (*body) == LABEL_REF && LABEL_P (y))
- return XEXP (*body, 0) == y;
-
- /* If *BODY is a reference to pool constant traverse the constant. */
- if (GET_CODE (*body) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (*body))
- return rtx_referenced_p (y, get_pool_constant (*body));
-
- /* By default, compare the RTL expressions. */
- return rtx_equal_p (*body, y);
+ rtx insn_as_rtx = insn;
+ replace_label (&insn_as_rtx, old_label, new_label, update_label_nuses);
+ gcc_checking_assert (insn_as_rtx == insn);
}
/* Return true if X is referenced in BODY. */
-int
-rtx_referenced_p (rtx x, rtx body)
+bool
+rtx_referenced_p (const_rtx x, const_rtx body)
{
- return for_each_rtx (&body, rtx_referenced_p_1, x);
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, body, ALL)
+ if (const_rtx y = *iter)
+ {
+ /* Check if a label_ref Y refers to label X. */
+ if (GET_CODE (y) == LABEL_REF
+ && LABEL_P (x)
+ && LABEL_REF_LABEL (y) == x)
+ return true;
+
+ if (rtx_equal_p (x, y))
+ return true;
+
+ /* If Y is a reference to pool constant traverse the constant. */
+ if (GET_CODE (y) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (y))
+ iter.substitute (get_pool_constant (y));
+ }
+ return false;
}
/* If INSN is a tablejump return true and store the label (before jump table) to
*LABELP and the jump table to *TABLEP. LABELP and TABLEP may be NULL. */
bool
-tablejump_p (const_rtx insn, rtx *labelp, rtx *tablep)
+tablejump_p (const rtx_insn *insn, rtx *labelp, rtx_jump_table_data **tablep)
{
- rtx label, table;
+ rtx label;
+ rtx_insn *table;
if (!JUMP_P (insn))
return false;
label = JUMP_LABEL (insn);
if (label != NULL_RTX && !ANY_RETURN_P (label)
- && (table = next_active_insn (label)) != NULL_RTX
+ && (table = NEXT_INSN (as_a <rtx_insn *> (label))) != NULL_RTX
&& JUMP_TABLE_DATA_P (table))
{
- gcc_assert (table == NEXT_INSN (label));
if (labelp)
*labelp = label;
if (tablep)
- *tablep = table;
+ *tablep = as_a <rtx_jump_table_data *> (table);
return true;
}
return false;
we can recognize them by a (use (label_ref)). */
int
-computed_jump_p (const_rtx insn)
+computed_jump_p (const rtx_insn *insn)
{
int i;
if (JUMP_P (insn))
if (GET_CODE (XVECEXP (pat, 0, i)) == USE
&& (GET_CODE (XEXP (XVECEXP (pat, 0, i), 0))
== LABEL_REF))
- has_use_labelref = 1;
+ {
+ has_use_labelref = 1;
+ break;
+ }
if (! has_use_labelref)
for (i = len - 1; i >= 0; i--)
return 0;
}
-/* Optimized loop of for_each_rtx, trying to avoid useless recursive
- calls. Processes the subexpressions of EXP and passes them to F. */
-static int
-for_each_rtx_1 (rtx exp, int n, rtx_function f, void *data)
-{
- int result, i, j;
- const char *format = GET_RTX_FORMAT (GET_CODE (exp));
- rtx *x;
-
- for (; format[n] != '\0'; n++)
- {
- switch (format[n])
- {
- case 'e':
- /* Call F on X. */
- x = &XEXP (exp, n);
- result = (*f) (x, data);
- if (result == -1)
- /* Do not traverse sub-expressions. */
- continue;
- else if (result != 0)
- /* Stop the traversal. */
- return result;
-
- if (*x == NULL_RTX)
- /* There are no sub-expressions. */
- continue;
-
- i = non_rtx_starting_operands[GET_CODE (*x)];
- if (i >= 0)
- {
- result = for_each_rtx_1 (*x, i, f, data);
- if (result != 0)
- return result;
- }
- break;
-
- case 'V':
- case 'E':
- if (XVEC (exp, n) == 0)
- continue;
- for (j = 0; j < XVECLEN (exp, n); ++j)
- {
- /* Call F on X. */
- x = &XVECEXP (exp, n, j);
- result = (*f) (x, data);
- if (result == -1)
- /* Do not traverse sub-expressions. */
- continue;
- else if (result != 0)
- /* Stop the traversal. */
- return result;
-
- if (*x == NULL_RTX)
- /* There are no sub-expressions. */
- continue;
-
- i = non_rtx_starting_operands[GET_CODE (*x)];
- if (i >= 0)
- {
- result = for_each_rtx_1 (*x, i, f, data);
- if (result != 0)
- return result;
- }
- }
- break;
-
- default:
- /* Nothing to do. */
- break;
- }
- }
-
- return 0;
-}
-
-/* Traverse X via depth-first search, calling F for each
- sub-expression (including X itself). F is also passed the DATA.
- If F returns -1, do not traverse sub-expressions, but continue
- traversing the rest of the tree. If F ever returns any other
- nonzero value, stop the traversal, and return the value returned
- by F. Otherwise, return 0. This function does not traverse inside
- tree structure that contains RTX_EXPRs, or into sub-expressions
- whose format code is `0' since it is not known whether or not those
- codes are actually RTL.
-
- This routine is very general, and could (should?) be used to
- implement many of the other routines in this file. */
-
-int
-for_each_rtx (rtx *x, rtx_function f, void *data)
-{
- int result;
- int i;
-
- /* Call F on X. */
- result = (*f) (x, data);
- if (result == -1)
- /* Do not traverse sub-expressions. */
- return 0;
- else if (result != 0)
- /* Stop the traversal. */
- return result;
-
- if (*x == NULL_RTX)
- /* There are no sub-expressions. */
- return 0;
-
- i = non_rtx_starting_operands[GET_CODE (*x)];
- if (i < 0)
- return 0;
-
- return for_each_rtx_1 (*x, i, f, data);
-}
-
\f
-/* Data structure that holds the internal state communicated between
- for_each_inc_dec, for_each_inc_dec_find_mem and
- for_each_inc_dec_find_inc_dec. */
-
-struct for_each_inc_dec_ops {
- /* The function to be called for each autoinc operation found. */
- for_each_inc_dec_fn fn;
- /* The opaque argument to be passed to it. */
- void *arg;
- /* The MEM we're visiting, if any. */
- rtx mem;
-};
-
-static int for_each_inc_dec_find_mem (rtx *r, void *d);
-
-/* Find PRE/POST-INC/DEC/MODIFY operations within *R, extract the
- operands of the equivalent add insn and pass the result to the
- operator specified by *D. */
+/* MEM has a PRE/POST-INC/DEC/MODIFY address X. Extract the operands of
+ the equivalent add insn and pass the result to FN, using DATA as the
+ final argument. */
static int
-for_each_inc_dec_find_inc_dec (rtx *r, void *d)
+for_each_inc_dec_find_inc_dec (rtx mem, for_each_inc_dec_fn fn, void *data)
{
- rtx x = *r;
- struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *)d;
-
+ rtx x = XEXP (mem, 0);
switch (GET_CODE (x))
{
case PRE_INC:
case POST_INC:
{
- int size = GET_MODE_SIZE (GET_MODE (data->mem));
+ int size = GET_MODE_SIZE (GET_MODE (mem));
rtx r1 = XEXP (x, 0);
rtx c = gen_int_mode (size, GET_MODE (r1));
- return data->fn (data->mem, x, r1, r1, c, data->arg);
+ return fn (mem, x, r1, r1, c, data);
}
case PRE_DEC:
case POST_DEC:
{
- int size = GET_MODE_SIZE (GET_MODE (data->mem));
+ int size = GET_MODE_SIZE (GET_MODE (mem));
rtx r1 = XEXP (x, 0);
rtx c = gen_int_mode (-size, GET_MODE (r1));
- return data->fn (data->mem, x, r1, r1, c, data->arg);
+ return fn (mem, x, r1, r1, c, data);
}
case PRE_MODIFY:
{
rtx r1 = XEXP (x, 0);
rtx add = XEXP (x, 1);
- return data->fn (data->mem, x, r1, add, NULL, data->arg);
- }
-
- case MEM:
- {
- rtx save = data->mem;
- int ret = for_each_inc_dec_find_mem (r, d);
- data->mem = save;
- return ret;
+ return fn (mem, x, r1, add, NULL, data);
}
default:
- return 0;
+ gcc_unreachable ();
}
}
-/* If *R is a MEM, find PRE/POST-INC/DEC/MODIFY operations within its
- address, extract the operands of the equivalent add insn and pass
- the result to the operator specified by *D. */
-
-static int
-for_each_inc_dec_find_mem (rtx *r, void *d)
-{
- rtx x = *r;
- if (x != NULL_RTX && MEM_P (x))
- {
- struct for_each_inc_dec_ops *data = (struct for_each_inc_dec_ops *) d;
- int result;
-
- data->mem = x;
-
- result = for_each_rtx (&XEXP (x, 0), for_each_inc_dec_find_inc_dec,
- data);
- if (result)
- return result;
-
- return -1;
- }
- return 0;
-}
-
-/* Traverse *X looking for MEMs, and for autoinc operations within
- them. For each such autoinc operation found, call FN, passing it
+/* Traverse *LOC looking for MEMs that have autoinc addresses.
+ For each such autoinc operation found, call FN, passing it
the innermost enclosing MEM, the operation itself, the RTX modified
by the operation, two RTXs (the second may be NULL) that, once
added, represent the value to be held by the modified RTX
- afterwards, and ARG. FN is to return -1 to skip looking for other
- autoinc operations within the visited operation, 0 to continue the
- traversal, or any other value to have it returned to the caller of
+ afterwards, and DATA. FN is to return 0 to continue the
+ traversal or any other value to have it returned to the caller of
for_each_inc_dec. */
int
-for_each_inc_dec (rtx *x,
+for_each_inc_dec (rtx x,
for_each_inc_dec_fn fn,
- void *arg)
+ void *data)
{
- struct for_each_inc_dec_ops data;
-
- data.fn = fn;
- data.arg = arg;
- data.mem = NULL;
-
- return for_each_rtx (x, for_each_inc_dec_find_mem, &data);
+ subrtx_var_iterator::array_type array;
+ FOR_EACH_SUBRTX_VAR (iter, array, x, NONCONST)
+ {
+ rtx mem = *iter;
+ if (mem
+ && MEM_P (mem)
+ && GET_RTX_CLASS (GET_CODE (XEXP (mem, 0))) == RTX_AUTOINC)
+ {
+ int res = for_each_inc_dec_find_inc_dec (mem, fn, data);
+ if (res != 0)
+ return res;
+ iter.skip_subrtxes ();
+ }
+ }
+ return 0;
}
\f
}
/* Return a value indicating whether OP, an operand of a commutative
- operation, is preferred as the first or second operand. The higher
- the value, the stronger the preference for being the first operand.
- We use negative values to indicate a preference for the first operand
- and positive values for the second operand. */
+ operation, is preferred as the first or second operand. The more
+ positive the value, the stronger the preference for being the first
+ operand. */
int
commutative_operand_precedence (rtx op)
{
enum rtx_code code = GET_CODE (op);
- /* Constants always come the second operand. Prefer "nice" constants. */
+ /* Constants always become the second operand. Prefer "nice" constants. */
if (code == CONST_INT)
return -8;
+ if (code == CONST_WIDE_INT)
+ return -8;
if (code == CONST_DOUBLE)
return -7;
if (code == CONST_FIXED)
case RTX_CONST_OBJ:
if (code == CONST_INT)
return -6;
+ if (code == CONST_WIDE_INT)
+ return -6;
if (code == CONST_DOUBLE)
return -5;
if (code == CONST_FIXED)
(counting from the least significant bit of the operand). */
unsigned int
-subreg_lsb_1 (enum machine_mode outer_mode,
- enum machine_mode inner_mode,
+subreg_lsb_1 (machine_mode outer_mode,
+ machine_mode inner_mode,
unsigned int subreg_byte)
{
unsigned int bitpos;
xmode - The mode of xregno.
offset - The byte offset.
ymode - The mode of a top level SUBREG (or what may become one).
- info - Pointer to structure to fill in. */
+ info - Pointer to structure to fill in.
+
+ Rather than considering one particular inner register (and thus one
+ particular "outer" register) in isolation, this function really uses
+ XREGNO as a model for a sequence of isomorphic hard registers. Thus the
+ function does not check whether adding INFO->offset to XREGNO gives
+ a valid hard register; even if INFO->offset + XREGNO is out of range,
+ there might be another register of the same type that is in range.
+ Likewise it doesn't check whether HARD_REGNO_MODE_OK accepts the new
+ register, since that can depend on things like whether the final
+ register number is even or odd. Callers that want to check whether
+ this particular subreg can be replaced by a simple (reg ...) should
+ use simplify_subreg_regno. */
+
void
-subreg_get_info (unsigned int xregno, enum machine_mode xmode,
- unsigned int offset, enum machine_mode ymode,
+subreg_get_info (unsigned int xregno, machine_mode xmode,
+ unsigned int offset, machine_mode ymode,
struct subreg_info *info)
{
int nregs_xmode, nregs_ymode;
that it is made up of its units concatenated together. */
if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode))
{
- enum machine_mode xmode_unit;
+ machine_mode xmode_unit;
nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode);
if (GET_MODE_INNER (xmode) == VOIDmode)
info->offset = offset / regsize_xmode;
return;
}
+ /* Quick exit for the simple and common case of extracting whole
+ subregisters from a multiregister value. */
+ /* ??? It would be better to integrate this into the code below,
+ if we can generalize the concept enough and figure out how
+ odd-sized modes can coexist with the other weird cases we support. */
+ if (!rknown
+ && WORDS_BIG_ENDIAN == REG_WORDS_BIG_ENDIAN
+ && regsize_xmode == regsize_ymode
+ && (offset % regsize_ymode) == 0)
+ {
+ info->representable_p = true;
+ info->nregs = nregs_ymode;
+ info->offset = offset / regsize_ymode;
+ gcc_assert (info->offset + info->nregs <= nregs_xmode);
+ return;
+ }
}
/* Lowpart subregs are otherwise valid. */
ymode - The mode of a top level SUBREG (or what may become one).
RETURN - The regno offset which would be used. */
unsigned int
-subreg_regno_offset (unsigned int xregno, enum machine_mode xmode,
- unsigned int offset, enum machine_mode ymode)
+subreg_regno_offset (unsigned int xregno, machine_mode xmode,
+ unsigned int offset, machine_mode ymode)
{
struct subreg_info info;
subreg_get_info (xregno, xmode, offset, ymode, &info);
ymode - The mode of a top level SUBREG (or what may become one).
RETURN - Whether the offset is representable. */
bool
-subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode,
- unsigned int offset, enum machine_mode ymode)
+subreg_offset_representable_p (unsigned int xregno, machine_mode xmode,
+ unsigned int offset, machine_mode ymode)
{
struct subreg_info info;
subreg_get_info (xregno, xmode, offset, ymode, &info);
XREGNO is a hard register number. */
int
-simplify_subreg_regno (unsigned int xregno, enum machine_mode xmode,
- unsigned int offset, enum machine_mode ymode)
+simplify_subreg_regno (unsigned int xregno, machine_mode xmode,
+ unsigned int offset, machine_mode ymode)
{
struct subreg_info info;
unsigned int yregno;
found if CSE has eliminated some of them (e.g., an argument
to the outer function is passed down as a parameter).
Do not skip BOUNDARY. */
-rtx
-find_first_parameter_load (rtx call_insn, rtx boundary)
+rtx_insn *
+find_first_parameter_load (rtx_insn *call_insn, rtx_insn *boundary)
{
struct parms_set_data parm;
- rtx p, before, first_set;
+ rtx p;
+ rtx_insn *before, *first_set;
/* Since different machines initialize their parameter registers
in different orders, assume nothing. Collect the set of all
call instruction. */
bool
-keep_with_call_p (const_rtx insn)
+keep_with_call_p (const rtx_insn *insn)
{
rtx set;
/* This CONST_CAST is okay because next_nonnote_insn just
returns its argument and we assign it to a const_rtx
variable. */
- const_rtx i2 = next_nonnote_insn (CONST_CAST_RTX(insn));
+ const rtx_insn *i2
+ = next_nonnote_insn (const_cast<rtx_insn *> (insn));
if (i2 && keep_with_call_p (i2))
return true;
}
not apply to the fallthru case of a conditional jump. */
bool
-label_is_jump_target_p (const_rtx label, const_rtx jump_insn)
+label_is_jump_target_p (const_rtx label, const rtx_insn *jump_insn)
{
rtx tmp = JUMP_LABEL (jump_insn);
+ rtx_jump_table_data *table;
if (label == tmp)
return true;
- if (tablejump_p (jump_insn, NULL, &tmp))
+ if (tablejump_p (jump_insn, NULL, &table))
{
- rtvec vec = XVEC (PATTERN (tmp),
- GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC);
+ rtvec vec = table->get_labels ();
int i, veclen = GET_NUM_ELEM (vec);
for (i = 0; i < veclen; ++i)
be returned. */
int
-address_cost (rtx x, enum machine_mode mode, addr_space_t as, bool speed)
+address_cost (rtx x, machine_mode mode, addr_space_t as, bool speed)
{
/* We may be asked for cost of various unusual addresses, such as operands
of push instruction. It is not worthwhile to complicate writing
/* If the target doesn't override, compute the cost as with arithmetic. */
int
-default_address_cost (rtx x, enum machine_mode, addr_space_t, bool speed)
+default_address_cost (rtx x, machine_mode, addr_space_t, bool speed)
{
return rtx_cost (x, MEM, 0, speed);
}
\f
unsigned HOST_WIDE_INT
-nonzero_bits (const_rtx x, enum machine_mode mode)
+nonzero_bits (const_rtx x, machine_mode mode)
{
return cached_nonzero_bits (x, mode, NULL_RTX, VOIDmode, 0);
}
unsigned int
-num_sign_bit_copies (const_rtx x, enum machine_mode mode)
+num_sign_bit_copies (const_rtx x, machine_mode mode)
{
return cached_num_sign_bit_copies (x, mode, NULL_RTX, VOIDmode, 0);
}
identical subexpressions on the first or the second level. */
static unsigned HOST_WIDE_INT
-cached_nonzero_bits (const_rtx x, enum machine_mode mode, const_rtx known_x,
- enum machine_mode known_mode,
+cached_nonzero_bits (const_rtx x, machine_mode mode, const_rtx known_x,
+ machine_mode known_mode,
unsigned HOST_WIDE_INT known_ret)
{
if (x == known_x && mode == known_mode)
an arithmetic operation, we can do better. */
static unsigned HOST_WIDE_INT
-nonzero_bits1 (const_rtx x, enum machine_mode mode, const_rtx known_x,
- enum machine_mode known_mode,
+nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
+ machine_mode known_mode,
unsigned HOST_WIDE_INT known_ret)
{
unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
unsigned HOST_WIDE_INT inner_nz;
enum rtx_code code;
- enum machine_mode inner_mode;
+ machine_mode inner_mode;
unsigned int mode_width = GET_MODE_PRECISION (mode);
/* For floating-point and vector values, assume all bits are needed. */
&& mode_width < BITS_PER_WORD
&& (UINTVAL (x) & ((unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
!= 0)
- return UINTVAL (x) | ((unsigned HOST_WIDE_INT) (-1) << mode_width);
+ return UINTVAL (x) | (HOST_WIDE_INT_M1U << mode_width);
#endif
return UINTVAL (x);
been zero-extended, we know that at least the high-order bits
are zero, though others might be too. */
- if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x) > 0)
+ if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x))
nonzero = GET_MODE_MASK (GET_MODE (x))
& cached_nonzero_bits (SUBREG_REG (x), GET_MODE (x),
known_x, known_mode, known_ret);
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
&& INTVAL (XEXP (x, 1)) < GET_MODE_PRECISION (GET_MODE (x)))
{
- enum machine_mode inner_mode = GET_MODE (x);
+ machine_mode inner_mode = GET_MODE (x);
unsigned int width = GET_MODE_PRECISION (inner_mode);
int count = INTVAL (XEXP (x, 1));
unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (inner_mode);
first or the second level. */
static unsigned int
-cached_num_sign_bit_copies (const_rtx x, enum machine_mode mode, const_rtx known_x,
- enum machine_mode known_mode,
+cached_num_sign_bit_copies (const_rtx x, machine_mode mode, const_rtx known_x,
+ machine_mode known_mode,
unsigned int known_ret)
{
if (x == known_x && mode == known_mode)
be between 1 and the number of bits in MODE. */
static unsigned int
-num_sign_bit_copies1 (const_rtx x, enum machine_mode mode, const_rtx known_x,
- enum machine_mode known_mode,
+num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
+ machine_mode known_mode,
unsigned int known_ret)
{
enum rtx_code code = GET_CODE (x);
and we are looking at it in a wider mode, we know that at least the
high-order bits are known to be sign bit copies. */
- if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x))
+ if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_SIGNED_P (x))
{
num0 = cached_num_sign_bit_copies (SUBREG_REG (x), mode,
known_x, known_mode, known_ret);
return cost > 0 ? cost : COSTS_N_INSNS (1);
}
+/* Returns estimate on cost of computing SEQ. */
+
+unsigned
+seq_cost (const rtx_insn *seq, bool speed)
+{
+ unsigned cost = 0;
+ rtx set;
+
+ for (; seq; seq = NEXT_INSN (seq))
+ {
+ set = single_set (seq);
+ if (set)
+ cost += set_rtx_cost (set, speed);
+ else
+ cost++;
+ }
+
+ return cost;
+}
+
/* Given an insn INSN and condition COND, return the condition in a
canonical form to simplify testing by callers. Specifically:
and at INSN. */
rtx
-canonicalize_condition (rtx insn, rtx cond, int reverse, rtx *earliest,
+canonicalize_condition (rtx_insn *insn, rtx cond, int reverse,
+ rtx_insn **earliest,
rtx want_reg, int allow_cc_mode, int valid_at_insn_p)
{
enum rtx_code code;
- rtx prev = insn;
+ rtx_insn *prev = insn;
const_rtx set;
rtx tem;
rtx op0, op1;
int reverse_code = 0;
- enum machine_mode mode;
+ machine_mode mode;
basic_block bb = BLOCK_FOR_INSN (insn);
code = GET_CODE (cond);
/* Set nonzero when we find something of interest. */
rtx x = 0;
-#ifdef HAVE_cc0
/* If comparison with cc0, import actual comparison from compare
insn. */
if (op0 == cc0_rtx)
if (earliest)
*earliest = prev;
}
-#endif
/* If this is a COMPARE, pick up the two things being compared. */
if (GET_CODE (op0) == COMPARE)
relevant. */
if (set)
{
- enum machine_mode inner_mode = GET_MODE (SET_DEST (set));
+ machine_mode inner_mode = GET_MODE (SET_DEST (set));
#ifdef FLOAT_STORE_FLAG_VALUE
REAL_VALUE_TYPE fsfv;
#endif
??? This mode check should perhaps look more like the mode check
in simplify_comparison in combine. */
-
- if ((GET_CODE (SET_SRC (set)) == COMPARE
- || (((code == NE
- || (code == LT
- && val_signbit_known_set_p (inner_mode,
- STORE_FLAG_VALUE))
+ if (((GET_MODE_CLASS (mode) == MODE_CC)
+ != (GET_MODE_CLASS (inner_mode) == MODE_CC))
+ && mode != VOIDmode
+ && inner_mode != VOIDmode)
+ break;
+ if (GET_CODE (SET_SRC (set)) == COMPARE
+ || (((code == NE
+ || (code == LT
+ && val_signbit_known_set_p (inner_mode,
+ STORE_FLAG_VALUE))
#ifdef FLOAT_STORE_FLAG_VALUE
- || (code == LT
- && SCALAR_FLOAT_MODE_P (inner_mode)
- && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
- REAL_VALUE_NEGATIVE (fsfv)))
+ || (code == LT
+ && SCALAR_FLOAT_MODE_P (inner_mode)
+ && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
+ REAL_VALUE_NEGATIVE (fsfv)))
#endif
- ))
- && COMPARISON_P (SET_SRC (set))))
- && (((GET_MODE_CLASS (mode) == MODE_CC)
- == (GET_MODE_CLASS (inner_mode) == MODE_CC))
- || mode == VOIDmode || inner_mode == VOIDmode))
+ ))
+ && COMPARISON_P (SET_SRC (set))))
x = SET_SRC (set);
else if (((code == EQ
|| (code == GE
REAL_VALUE_NEGATIVE (fsfv)))
#endif
))
- && COMPARISON_P (SET_SRC (set))
- && (((GET_MODE_CLASS (mode) == MODE_CC)
- == (GET_MODE_CLASS (inner_mode) == MODE_CC))
- || mode == VOIDmode || inner_mode == VOIDmode))
-
+ && COMPARISON_P (SET_SRC (set)))
{
reverse_code = 1;
x = SET_SRC (set);
}
+ else if ((code == EQ || code == NE)
+ && GET_CODE (SET_SRC (set)) == XOR)
+ /* Handle sequences like:
+
+ (set op0 (xor X Y))
+ ...(eq|ne op0 (const_int 0))...
+
+ in which case:
+
+ (eq op0 (const_int 0)) reduces to (eq X Y)
+ (ne op0 (const_int 0)) reduces to (ne X Y)
+
+ This is the form used by MIPS16, for example. */
+ x = SET_SRC (set);
else
break;
}
VALID_AT_INSN_P is the same as for canonicalize_condition. */
rtx
-get_condition (rtx jump, rtx *earliest, int allow_cc_mode, int valid_at_insn_p)
+get_condition (rtx_insn *jump, rtx_insn **earliest, int allow_cc_mode,
+ int valid_at_insn_p)
{
rtx cond;
int reverse;
the condition. */
reverse
= GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
- && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump);
+ && LABEL_REF_LABEL (XEXP (SET_SRC (set), 2)) == JUMP_LABEL (jump);
return canonicalize_condition (jump, cond, reverse, earliest, NULL_RTX,
allow_cc_mode, valid_at_insn_p);
static void
init_num_sign_bit_copies_in_rep (void)
{
- enum machine_mode mode, in_mode;
+ machine_mode mode, in_mode;
for (in_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); in_mode != VOIDmode;
in_mode = GET_MODE_WIDER_MODE (mode))
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != in_mode;
mode = GET_MODE_WIDER_MODE (mode))
{
- enum machine_mode i;
+ machine_mode i;
/* Currently, it is assumed that TARGET_MODE_REP_EXTENDED
extends to the next widest mode. */
have to be copies of the sign-bit. */
for (i = mode; i != in_mode; i = GET_MODE_WIDER_MODE (i))
{
- enum machine_mode wider = GET_MODE_WIDER_MODE (i);
+ machine_mode wider = GET_MODE_WIDER_MODE (i);
if (targetm.mode_rep_extended (i, wider) == SIGN_EXTEND
/* We can only check sign-bit copies starting from the
assume it already contains a truncated value of MODE. */
bool
-truncated_to_mode (enum machine_mode mode, const_rtx x)
+truncated_to_mode (machine_mode mode, const_rtx x)
{
/* This register has already been used in MODE without explicit
truncation. */
return false;
}
\f
-/* Initialize non_rtx_starting_operands, which is used to speed up
- for_each_rtx. */
+/* Return true if RTX code CODE has a single sequence of zero or more
+ "e" operands and no rtvec operands. Initialize its rtx_all_subrtx_bounds
+ entry in that case. */
+
+static bool
+setup_reg_subrtx_bounds (unsigned int code)
+{
+ const char *format = GET_RTX_FORMAT ((enum rtx_code) code);
+ unsigned int i = 0;
+ for (; format[i] != 'e'; ++i)
+ {
+ if (!format[i])
+ /* No subrtxes. Leave start and count as 0. */
+ return true;
+ if (format[i] == 'E' || format[i] == 'V')
+ return false;
+ }
+
+ /* Record the sequence of 'e's. */
+ rtx_all_subrtx_bounds[code].start = i;
+ do
+ ++i;
+ while (format[i] == 'e');
+ rtx_all_subrtx_bounds[code].count = i - rtx_all_subrtx_bounds[code].start;
+ /* rtl-iter.h relies on this. */
+ gcc_checking_assert (rtx_all_subrtx_bounds[code].count <= 3);
+
+ for (; format[i]; ++i)
+ if (format[i] == 'E' || format[i] == 'V' || format[i] == 'e')
+ return false;
+
+ return true;
+}
+
+/* Initialize rtx_all_subrtx_bounds. */
void
init_rtlanal (void)
{
int i;
for (i = 0; i < NUM_RTX_CODE; i++)
{
- const char *format = GET_RTX_FORMAT (i);
- const char *first = strpbrk (format, "eEV");
- non_rtx_starting_operands[i] = first ? first - format : -1;
+ if (!setup_reg_subrtx_bounds (i))
+ rtx_all_subrtx_bounds[i].count = UCHAR_MAX;
+ if (GET_RTX_CLASS (i) != RTX_CONST_OBJ)
+ rtx_nonconst_subrtx_bounds[i] = rtx_all_subrtx_bounds[i];
}
init_num_sign_bit_copies_in_rep ();
M is used in machine mode MODE. */
int
-low_bitmask_len (enum machine_mode mode, unsigned HOST_WIDE_INT m)
+low_bitmask_len (machine_mode mode, unsigned HOST_WIDE_INT m)
{
if (mode != VOIDmode)
{
/* Return the mode of MEM's address. */
-enum machine_mode
+machine_mode
get_address_mode (rtx mem)
{
- enum machine_mode mode;
+ machine_mode mode;
gcc_assert (MEM_P (mem));
mode = GET_MODE (XEXP (mem, 0));
/* Split up a CONST_DOUBLE or integer constant rtx
into two rtx's for single words,
storing in *FIRST the word that comes first in memory in the target
- and in *SECOND the other. */
+ and in *SECOND the other.
+
+ TODO: This function needs to be rewritten to work on any size
+ integer. */
void
split_double (rtx value, rtx *first, rtx *second)
}
}
}
+ else if (GET_CODE (value) == CONST_WIDE_INT)
+ {
+ /* All of this is scary code and needs to be converted to
+ properly work with any size integer. */
+ gcc_assert (CONST_WIDE_INT_NUNITS (value) == 2);
+ if (WORDS_BIG_ENDIAN)
+ {
+ *first = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+ *second = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+ }
+ else
+ {
+ *first = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+ *second = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+ }
+ }
else if (!CONST_DOUBLE_P (value))
{
if (WORDS_BIG_ENDIAN)
}
}
+/* Return true if X is a sign_extract or zero_extract from the least
+ significant bit. */
+
+static bool
+lsb_bitfield_op_p (rtx x)
+{
+ if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
+ {
+ machine_mode mode = GET_MODE (XEXP (x, 0));
+ HOST_WIDE_INT len = INTVAL (XEXP (x, 1));
+ HOST_WIDE_INT pos = INTVAL (XEXP (x, 2));
+
+ return (pos == (BITS_BIG_ENDIAN ? GET_MODE_PRECISION (mode) - len : 0));
+ }
+ return false;
+}
+
/* Strip outer address "mutations" from LOC and return a pointer to the
inner value. If OUTER_CODE is nonnull, store the code of the innermost
stripped expression there.
"Mutations" either convert between modes or apply some kind of
- alignment. */
+ extension, truncation or alignment. */
rtx *
strip_address_mutations (rtx *loc, enum rtx_code *outer_code)
/* Things like SIGN_EXTEND, ZERO_EXTEND and TRUNCATE can be
used to convert between pointer sizes. */
loc = &XEXP (*loc, 0);
+ else if (lsb_bitfield_op_p (*loc))
+ /* A [SIGN|ZERO]_EXTRACT from the least significant bit effectively
+ acts as a combined truncation and extension. */
+ loc = &XEXP (*loc, 0);
else if (code == AND && CONST_INT_P (XEXP (*loc, 1)))
/* (and ... (const_int -X)) is used to align to X bytes. */
loc = &XEXP (*loc, 0);
}
}
-/* Return true if X must be a base rather than an index. */
+/* Return true if CODE applies some kind of scale. The scaled value is
+ is the first operand and the scale is the second. */
static bool
-must_be_base_p (rtx x)
+binary_scale_code_p (enum rtx_code code)
{
- return GET_CODE (x) == LO_SUM;
+ return (code == MULT
+ || code == ASHIFT
+ /* Needed by ARM targets. */
+ || code == ASHIFTRT
+ || code == LSHIFTRT
+ || code == ROTATE
+ || code == ROTATERT);
}
-/* Return true if X must be an index rather than a base. */
+/* If *INNER can be interpreted as a base, return a pointer to the inner term
+ (see address_info). Return null otherwise. */
-static bool
-must_be_index_p (rtx x)
+static rtx *
+get_base_term (rtx *inner)
+{
+ if (GET_CODE (*inner) == LO_SUM)
+ inner = strip_address_mutations (&XEXP (*inner, 0));
+ if (REG_P (*inner)
+ || MEM_P (*inner)
+ || GET_CODE (*inner) == SUBREG
+ || GET_CODE (*inner) == SCRATCH)
+ return inner;
+ return 0;
+}
+
+/* If *INNER can be interpreted as an index, return a pointer to the inner term
+ (see address_info). Return null otherwise. */
+
+static rtx *
+get_index_term (rtx *inner)
{
- return GET_CODE (x) == MULT || GET_CODE (x) == ASHIFT;
+ /* At present, only constant scales are allowed. */
+ if (binary_scale_code_p (GET_CODE (*inner)) && CONSTANT_P (XEXP (*inner, 1)))
+ inner = strip_address_mutations (&XEXP (*inner, 0));
+ if (REG_P (*inner)
+ || MEM_P (*inner)
+ || GET_CODE (*inner) == SUBREG
+ || GET_CODE (*inner) == SCRATCH)
+ return inner;
+ return 0;
}
/* Set the segment part of address INFO to LOC, given that INNER is the
static void
set_address_segment (struct address_info *info, rtx *loc, rtx *inner)
{
- gcc_checking_assert (GET_CODE (*inner) == UNSPEC);
-
gcc_assert (!info->segment);
info->segment = loc;
info->segment_term = inner;
static void
set_address_base (struct address_info *info, rtx *loc, rtx *inner)
{
- if (GET_CODE (*inner) == LO_SUM)
- inner = strip_address_mutations (&XEXP (*inner, 0));
- gcc_checking_assert (REG_P (*inner)
- || MEM_P (*inner)
- || GET_CODE (*inner) == SUBREG);
-
gcc_assert (!info->base);
info->base = loc;
info->base_term = inner;
static void
set_address_index (struct address_info *info, rtx *loc, rtx *inner)
{
- if ((GET_CODE (*inner) == MULT || GET_CODE (*inner) == ASHIFT)
- && CONSTANT_P (XEXP (*inner, 1)))
- inner = strip_address_mutations (&XEXP (*inner, 0));
- gcc_checking_assert (REG_P (*inner)
- || MEM_P (*inner)
- || GET_CODE (*inner) == SUBREG);
-
gcc_assert (!info->index);
info->index = loc;
info->index_term = inner;
static void
set_address_disp (struct address_info *info, rtx *loc, rtx *inner)
{
- gcc_checking_assert (CONSTANT_P (*inner));
-
gcc_assert (!info->disp);
info->disp = loc;
info->disp_term = inner;
MODE, AS, OUTER_CODE and INDEX_CODE are as for ok_for_base_p_1. */
static int
-baseness (rtx x, enum machine_mode mode, addr_space_t as,
+baseness (rtx x, machine_mode mode, addr_space_t as,
enum rtx_code outer_code, enum rtx_code index_code)
{
- /* See whether we can be certain. */
- if (must_be_base_p (x))
- return 3;
- if (must_be_index_p (x))
- return -3;
-
/* Believe *_POINTER unless the address shape requires otherwise. */
if (REG_P (x) && REG_POINTER (x))
return 2;
if (n_ops > 1)
info->base_outer_code = PLUS;
- /* Separate the parts that contain a REG or MEM from those that don't.
- Record the latter in INFO and leave the former in OPS. */
+ /* Try to classify each sum operand now. Leave those that could be
+ either a base or an index in OPS. */
rtx *inner_ops[4];
size_t out = 0;
for (size_t in = 0; in < n_ops; ++in)
set_address_segment (info, loc, inner);
else
{
- ops[out] = loc;
- inner_ops[out] = inner;
- ++out;
+ /* The only other possibilities are a base or an index. */
+ rtx *base_term = get_base_term (inner);
+ rtx *index_term = get_index_term (inner);
+ gcc_assert (base_term || index_term);
+ if (!base_term)
+ set_address_index (info, loc, index_term);
+ else if (!index_term)
+ set_address_base (info, loc, base_term);
+ else
+ {
+ gcc_assert (base_term == index_term);
+ ops[out] = loc;
+ inner_ops[out] = base_term;
+ ++out;
+ }
}
}
/* Classify the remaining OPS members as bases and indexes. */
if (out == 1)
{
- /* Assume that the remaining value is a base unless the shape
- requires otherwise. */
- if (!must_be_index_p (*inner_ops[0]))
+ /* If we haven't seen a base or an index yet, assume that this is
+ the base. If we were confident that another term was the base
+ or index, treat the remaining operand as the other kind. */
+ if (!info->base)
set_address_base (info, ops[0], inner_ops[0]);
else
set_address_index (info, ops[0], inner_ops[0]);
OUTER_CODE is MEM if *LOC is a MEM address and ADDRESS otherwise. */
void
-decompose_address (struct address_info *info, rtx *loc, enum machine_mode mode,
+decompose_address (struct address_info *info, rtx *loc, machine_mode mode,
addr_space_t as, enum rtx_code outer_code)
{
memset (info, 0, sizeof (*info));
return SCRATCH;
}
+
+/* Return true if X contains a thread-local symbol. */
+
+bool
+tls_referenced_p (const_rtx x)
+{
+ if (!targetm.have_tls)
+ return false;
+
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, x, ALL)
+ if (GET_CODE (*iter) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (*iter) != 0)
+ return true;
+ return false;
+}