/* Analyze RTL for GNU compiler.
- Copyright (C) 1987-2014 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"
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);
-
-/* 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];
+static unsigned int num_sign_bit_copies1 (const_rtx, machine_mode, const_rtx,
+ machine_mode, unsigned int);
rtx_subrtx_bound_info rtx_all_subrtx_bounds[NUM_RTX_CODE];
rtx_subrtx_bound_info rtx_nonconst_subrtx_bounds[NUM_RTX_CODE];
return base;
}
gcc_checking_assert (i == LOCAL_ELEMS);
- vec_safe_grow (array.heap, i + 1);
+ /* 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;
value_type *base,
size_t end, rtx_type x)
{
- const char *format = GET_RTX_FORMAT (GET_CODE (x));
+ enum rtx_code code = GET_CODE (x);
+ const char *format = GET_RTX_FORMAT (code);
size_t orig_end = end;
- 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')
- {
- 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 (int j = 0; j < length; j++)
- base[end++] = T::get_value (vec[j]);
- else
- for (int j = 0; j < length; j++)
- base = add_single_to_queue (array, base, end++,
- T::get_value (vec[j]));
- }
+ 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;
}
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);
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 *insn;
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 *insn;
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;
/* 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, bool implicit)
+find_all_hard_reg_sets (const rtx_insn *insn, HARD_REG_SET *pset, bool implicit)
{
rtx link;
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;
value to itself. */
int
-noop_move_p (const_rtx insn)
+noop_move_p (const rtx_insn *insn)
{
rtx pat = PATTERN (insn);
}
\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;
}
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 ((enum machine_mode) 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, rtx note)
+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));
/* 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;
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
remove_node_from_expr_list (const_rtx node, rtx_expr_list **listp)
{
rtx_expr_list *temp = *listp;
- rtx prev = NULL_RTX;
+ rtx_expr_list *prev = NULL;
while (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_insn_list *temp = *listp;
+ rtx_insn_list *prev = NULL;
+
+ while (temp)
+ {
+ if (node == temp->insn ())
+ {
+ /* Splice the node out of the list. */
+ if (prev)
+ XEXP (prev, 1) = temp->next ();
+ else
+ *listp = temp->next ();
+
+ return;
+ }
+
+ prev = temp;
+ temp = temp->next ();
+ }
+}
\f
/* Nonzero if X contains any volatile instructions. These are instructions
which may cause unpredictable machine state instructions, and thus no
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;
if (const_rtx y = *iter)
{
/* Check if a label_ref Y refers to label X. */
- if (GET_CODE (y) == LABEL_REF && LABEL_P (y) && XEXP (y, 0) == x)
+ if (GET_CODE (y) == LABEL_REF
+ && LABEL_P (x)
+ && LABEL_REF_LABEL (y) == x)
return true;
if (rtx_equal_p (x, y))
*LABELP and the jump table to *TABLEP. LABELP and TABLEP may be NULL. */
bool
-tablejump_p (const_rtx insn, rtx *labelp, rtx_jump_table_data **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_INSN (label)) != NULL_RTX
+ && (table = NEXT_INSN (as_a <rtx_insn *> (label))) != NULL_RTX
&& JUMP_TABLE_DATA_P (table))
{
if (labelp)
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))
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);
-}
-
-/* Like "for_each_rtx", but for calling on an rtx_insn **. */
-
-int
-for_each_rtx_in_insn (rtx_insn **insn, rtx_function f, void *data)
-{
- rtx insn_as_rtx = *insn;
- int result;
-
- result = for_each_rtx (&insn_as_rtx, f, data);
-
- if (insn_as_rtx != *insn)
- *insn = safe_as_a <rtx_insn *> (insn_as_rtx);
-
- return result;
-}
-
\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 *INSN 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_insn **insn,
+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_in_insn (insn, 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)
(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;
to the outer function is passed down as a parameter).
Do not skip BOUNDARY. */
rtx_insn *
-find_first_parameter_load (rtx call_insn, rtx boundary)
+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
break;
}
}
- return safe_as_a <rtx_insn *> (first_set);
+ return first_set;
}
/* Return true if we should avoid inserting code between INSN and preceding
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_insn *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;
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. */
&& 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);
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:
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
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 true;
}
-/* Initialize non_rtx_starting_operands, which is used to speed up
- for_each_rtx, and rtx_all_subrtx_bounds. */
+/* 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)
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));
{
if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
{
- enum machine_mode mode = GET_MODE (XEXP (x, 0));
+ machine_mode mode = GET_MODE (XEXP (x, 0));
HOST_WIDE_INT len = INTVAL (XEXP (x, 1));
HOST_WIDE_INT pos = INTVAL (XEXP (x, 2));
inner = strip_address_mutations (&XEXP (*inner, 0));
if (REG_P (*inner)
|| MEM_P (*inner)
- || GET_CODE (*inner) == SUBREG)
+ || GET_CODE (*inner) == SUBREG
+ || GET_CODE (*inner) == SCRATCH)
return inner;
return 0;
}
inner = strip_address_mutations (&XEXP (*inner, 0));
if (REG_P (*inner)
|| MEM_P (*inner)
- || GET_CODE (*inner) == SUBREG)
+ || GET_CODE (*inner) == SUBREG
+ || GET_CODE (*inner) == SCRATCH)
return inner;
return 0;
}
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)
{
/* Believe *_POINTER unless the address shape requires otherwise. */
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 1 if *X is a thread-local symbol. */
-
-static int
-tls_referenced_p_1 (rtx *x, void *)
-{
- return GET_CODE (*x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (*x) != 0;
-}
-
/* Return true if X contains a thread-local symbol. */
bool
-tls_referenced_p (rtx x)
+tls_referenced_p (const_rtx x)
{
if (!targetm.have_tls)
return false;
- return for_each_rtx (&x, &tls_referenced_p_1, 0);
+ 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;
}