/* Analyze RTL for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011 Free Software Foundation, Inc.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "diagnostic-core.h"
-#include "rtl.h"
#include "hard-reg-set.h"
+#include "rtl.h"
#include "insn-config.h"
#include "recog.h"
#include "target.h"
note_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
return data.found;
}
+
+/* This function, called through note_stores, collects sets and
+ clobbers of hard registers in a HARD_REG_SET, which is pointed to
+ by DATA. */
+void
+record_hard_reg_sets (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
+{
+ HARD_REG_SET *pset = (HARD_REG_SET *)data;
+ if (REG_P (x) && HARD_REGISTER_P (x))
+ add_to_hard_reg_set (pset, GET_MODE (x), REGNO (x));
+}
+
+/* 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)
+{
+ 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);
+ 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);
+}
\f
/* Given an INSN, return a SET expression if this insn has only a single SET.
It may also have CLOBBERs, USEs, or SET whose output
case REG_CC_USER:
case REG_LABEL_TARGET:
case REG_LABEL_OPERAND:
+ case REG_TM:
/* These types of register notes use an INSN_LIST rather than an
EXPR_LIST, so that copying is done right and dumps look
better. */
code_changed
|| !MEM_NOTRAP_P (x))
{
- HOST_WIDE_INT size = MEM_SIZE (x) ? INTVAL (MEM_SIZE (x)) : 0;
+ HOST_WIDE_INT size = MEM_SIZE_KNOWN_P (x) ? MEM_SIZE (x) : 0;
return rtx_addr_can_trap_p_1 (XEXP (x, 0), 0, size,
GET_MODE (x), code_changed);
}
{
rtx label, table;
- if (JUMP_P (insn)
- && (label = JUMP_LABEL (insn)) != NULL_RTX
+ 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
&& JUMP_TABLE_DATA_P (table))
{
return a negative offset so that we find the proper highpart
of the register. */
if (GET_MODE_SIZE (ymode) > UNITS_PER_WORD
- ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN)
+ ? REG_WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN)
info->offset = nregs_xmode - nregs_ymode;
else
info->offset = 0;
gcc_assert ((GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)) == 0);
gcc_assert ((nregs_xmode % nregs_ymode) == 0);
+ if (WORDS_BIG_ENDIAN != REG_WORDS_BIG_ENDIAN
+ && GET_MODE_SIZE (xmode) > UNITS_PER_WORD)
+ {
+ HOST_WIDE_INT xsize = GET_MODE_SIZE (xmode);
+ HOST_WIDE_INT ysize = GET_MODE_SIZE (ymode);
+ HOST_WIDE_INT off_low = offset & (ysize - 1);
+ HOST_WIDE_INT off_high = offset & ~(ysize - 1);
+ offset = (xsize - ysize - off_high) | off_low;
+ }
/* The XMODE value can be seen as a vector of NREGS_XMODE
values. The subreg must represent a lowpart of given field.
Compute what field it is. */
Another is in rtl generation, to pick the cheapest way to multiply.
Other uses like the latter are expected in the future.
- SPEED parameter specify whether costs optimized for speed or size should
+ X appears as operand OPNO in an expression with code OUTER_CODE.
+ SPEED specifies whether costs optimized for speed or size should
be returned. */
int
-rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED, bool speed)
+rtx_cost (rtx x, enum rtx_code outer_code, int opno, bool speed)
{
int i, j;
enum rtx_code code;
break;
default:
- if (targetm.rtx_costs (x, code, outer_code, &total, speed))
+ if (targetm.rtx_costs (x, code, outer_code, opno, &total, speed))
return total;
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
- total += rtx_cost (XEXP (x, i), code, speed);
+ total += rtx_cost (XEXP (x, i), code, i, speed);
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
- total += rtx_cost (XVECEXP (x, i, j), code, speed);
+ total += rtx_cost (XVECEXP (x, i, j), code, i, speed);
return total;
}
/* Fill in the structure C with information about both speed and size rtx
- costs for X, with outer code OUTER. */
+ costs for X, which is operand OPNO in an expression with code OUTER. */
void
-get_full_rtx_cost (rtx x, enum rtx_code outer, struct full_rtx_costs *c)
+get_full_rtx_cost (rtx x, enum rtx_code outer, int opno,
+ struct full_rtx_costs *c)
{
- c->speed = rtx_cost (x, outer, true);
- c->size = rtx_cost (x, outer, false);
+ c->speed = rtx_cost (x, outer, opno, true);
+ c->size = rtx_cost (x, outer, opno, false);
}
\f
int
default_address_cost (rtx x, bool speed)
{
- return rtx_cost (x, MEM, speed);
+ return rtx_cost (x, MEM, 0, speed);
}
\f
nonzero = 1;
#endif
- if (GET_MODE_SIZE (GET_MODE (x)) < mode_width)
+ if (GET_MODE_PRECISION (GET_MODE (x)) < mode_width)
nonzero |= (GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x)));
break;
nonzero = -1;
break;
+ case CLRSB:
+ /* This is at most the number of bits in the mode minus 1. */
+ nonzero = ((unsigned HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1;
+ break;
+
case PARITY:
nonzero = 1;
break;
else
return 0;
- cost = rtx_cost (SET_SRC (set), SET, speed);
+ cost = set_src_cost (SET_SRC (set), speed);
return cost > 0 ? cost : COSTS_N_INSNS (1);
}