/* Analyze RTL for GNU compiler.
- Copyright (C) 1987-2017 Free Software Foundation, Inc.
+ Copyright (C) 1987-2018 Free Software Foundation, Inc.
This file is part of GCC.
FROM and TO for the current function, as it was at the start
of the routine. */
-static HOST_WIDE_INT
+static poly_int64
get_initial_register_offset (int from, int to)
{
static const struct elim_table_t
const int from;
const int to;
} table[] = ELIMINABLE_REGS;
- HOST_WIDE_INT offset1, offset2;
+ poly_int64 offset1, offset2;
unsigned int i, j;
if (to == from)
references on strict alignment machines. */
static int
-rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
+rtx_addr_can_trap_p_1 (const_rtx x, poly_int64 offset, poly_int64 size,
machine_mode mode, bool unaligned_mems)
{
enum rtx_code code = GET_CODE (x);
+ gcc_checking_assert (mode == BLKmode || known_size_p (size));
/* 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)
+ if (STRICT_ALIGNMENT && unaligned_mems && mode != BLKmode)
{
- HOST_WIDE_INT actual_offset = offset;
+ poly_int64 actual_offset = offset;
#ifdef SPARC_STACK_BOUNDARY_HACK
/* ??? The SPARC port may claim a STACK_BOUNDARY higher than
actual_offset -= STACK_POINTER_OFFSET;
#endif
- if (actual_offset % GET_MODE_SIZE (mode) != 0)
+ if (!multiple_p (actual_offset, GET_MODE_SIZE (mode)))
return 1;
}
if (!CONSTANT_POOL_ADDRESS_P (x) && !SYMBOL_REF_FUNCTION_P (x))
{
tree decl;
- HOST_WIDE_INT decl_size;
+ poly_int64 decl_size;
- if (offset < 0)
+ if (maybe_lt (offset, 0))
return 1;
- if (size == 0)
- size = GET_MODE_SIZE (mode);
- if (size == 0)
- return offset != 0;
+ if (!known_size_p (size))
+ return maybe_ne (offset, 0);
/* If the size of the access or of the symbol is unknown,
assume the worst. */
if (!decl)
decl_size = -1;
else if (DECL_P (decl) && DECL_SIZE_UNIT (decl))
- decl_size = (tree_fits_shwi_p (DECL_SIZE_UNIT (decl))
- ? tree_to_shwi (DECL_SIZE_UNIT (decl))
- : -1);
+ {
+ if (!poly_int_tree_p (DECL_SIZE_UNIT (decl), &decl_size))
+ decl_size = -1;
+ }
else if (TREE_CODE (decl) == STRING_CST)
decl_size = TREE_STRING_LENGTH (decl);
else if (TYPE_SIZE_UNIT (TREE_TYPE (decl)))
else
decl_size = -1;
- return (decl_size <= 0 ? offset != 0 : offset + size > decl_size);
+ return (!known_size_p (decl_size) || known_eq (decl_size, 0)
+ ? maybe_ne (offset, 0)
+ : maybe_gt (offset + size, decl_size));
}
return 0;
|| (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
{
#ifdef RED_ZONE_SIZE
- HOST_WIDE_INT red_zone_size = RED_ZONE_SIZE;
+ poly_int64 red_zone_size = RED_ZONE_SIZE;
#else
- HOST_WIDE_INT red_zone_size = 0;
+ poly_int64 red_zone_size = 0;
#endif
- HOST_WIDE_INT stack_boundary = PREFERRED_STACK_BOUNDARY
- / BITS_PER_UNIT;
- HOST_WIDE_INT low_bound, high_bound;
+ poly_int64 stack_boundary = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+ poly_int64 low_bound, high_bound;
- if (size == 0)
- size = GET_MODE_SIZE (mode);
- if (size == 0)
+ if (!known_size_p (size))
return 1;
if (x == frame_pointer_rtx)
{
if (FRAME_GROWS_DOWNWARD)
{
- high_bound = STARTING_FRAME_OFFSET;
+ high_bound = targetm.starting_frame_offset ();
low_bound = high_bound - get_frame_size ();
}
else
{
- low_bound = STARTING_FRAME_OFFSET;
+ low_bound = targetm.starting_frame_offset ();
high_bound = low_bound + get_frame_size ();
}
}
else if (x == hard_frame_pointer_rtx)
{
- HOST_WIDE_INT sp_offset
+ poly_int64 sp_offset
= get_initial_register_offset (STACK_POINTER_REGNUM,
HARD_FRAME_POINTER_REGNUM);
- HOST_WIDE_INT ap_offset
+ poly_int64 ap_offset
= get_initial_register_offset (ARG_POINTER_REGNUM,
HARD_FRAME_POINTER_REGNUM);
}
else if (x == stack_pointer_rtx)
{
- HOST_WIDE_INT ap_offset
+ poly_int64 ap_offset
= get_initial_register_offset (ARG_POINTER_REGNUM,
STACK_POINTER_REGNUM);
#endif
}
- if (offset >= low_bound && offset <= high_bound - size)
+ if (known_ge (offset, low_bound)
+ && known_le (offset, high_bound - size))
return 0;
return 1;
}
if (XEXP (x, 0) == pic_offset_table_rtx
&& GET_CODE (XEXP (x, 1)) == CONST
&& GET_CODE (XEXP (XEXP (x, 1), 0)) == UNSPEC
- && offset == 0)
+ && known_eq (offset, 0))
return 0;
/* - or it is an address that can't trap plus a constant integer. */
int
rtx_addr_can_trap_p (const_rtx x)
{
- return rtx_addr_can_trap_p_1 (x, 0, 0, VOIDmode, false);
+ return rtx_addr_can_trap_p_1 (x, 0, -1, BLKmode, false);
}
/* Return true if X contains a MEM subrtx. */
*base_out = x;
*offset_out = const0_rtx;
}
+
+/* Express integer value X as some value Y plus a polynomial offset,
+ where Y is either const0_rtx, X or something within X (as opposed
+ to a new rtx). Return the Y and store the offset in *OFFSET_OUT. */
+
+rtx
+strip_offset (rtx x, poly_int64_pod *offset_out)
+{
+ rtx base = const0_rtx;
+ rtx test = x;
+ if (GET_CODE (test) == CONST)
+ test = XEXP (test, 0);
+ if (GET_CODE (test) == PLUS)
+ {
+ base = XEXP (test, 0);
+ test = XEXP (test, 1);
+ }
+ if (poly_int_rtx_p (test, offset_out))
+ return base;
+ *offset_out = 0;
+ return x;
+}
+
+/* Return the argument size in REG_ARGS_SIZE note X. */
+
+poly_int64
+get_args_size (const_rtx x)
+{
+ gcc_checking_assert (REG_NOTE_KIND (x) == REG_ARGS_SIZE);
+ return rtx_to_poly_int64 (XEXP (x, 0));
+}
\f
/* Return the number of places FIND appears within X. If COUNT_DEST is
zero, we do not count occurrences inside the destination of a SET. */
&& !REG_P (SET_DEST (body))
&& ! (GET_CODE (SET_DEST (body)) == SUBREG
&& REG_P (SUBREG_REG (SET_DEST (body)))
- && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (body))))
- + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
- == ((GET_MODE_SIZE (GET_MODE (SET_DEST (body)))
- + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
+ && !read_modify_subreg_p (SET_DEST (body)))
&& reg_overlap_mentioned_p (x, SET_DEST (body)))
return 1;
return 0;
return 0;
}
+
+/* Return true if X is a SUBREG and if storing a value to X would
+ preserve some of its SUBREG_REG. For example, on a normal 32-bit
+ target, using a SUBREG to store to one half of a DImode REG would
+ preserve the other half. */
+
+bool
+read_modify_subreg_p (const_rtx x)
+{
+ if (GET_CODE (x) != SUBREG)
+ return false;
+ poly_uint64 isize = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
+ poly_uint64 osize = GET_MODE_SIZE (GET_MODE (x));
+ poly_uint64 regsize = REGMODE_NATURAL_SIZE (GET_MODE (SUBREG_REG (x)));
+ /* The inner and outer modes of a subreg must be ordered, so that we
+ can tell whether they're paradoxical or partial. */
+ gcc_checking_assert (ordered_p (isize, osize));
+ return (maybe_gt (isize, osize) && maybe_gt (isize, regsize));
+}
\f
/* Helper function for set_of. */
struct set_of_data
if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG)
{
- if (SUBREG_BYTE (src) != SUBREG_BYTE (dst))
+ if (maybe_ne (SUBREG_BYTE (src), SUBREG_BYTE (dst)))
return 0;
src = SUBREG_REG (src);
dst = SUBREG_REG (dst);
return 1;
}
-/* Return TRUE iff DEST is a register or subreg of a register and
- doesn't change the number of words of the inner register, and any
- part of the register is TEST_REGNO. */
+/* Return TRUE iff DEST is a register or subreg of a register, is a
+ complete rather than read-modify-write destination, and contains
+ register TEST_REGNO. */
static bool
covers_regno_no_parallel_p (const_rtx dest, unsigned int test_regno)
{
unsigned int regno, endregno;
- if (GET_CODE (dest) == SUBREG
- && (((GET_MODE_SIZE (GET_MODE (dest))
- + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
- == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
- + UNITS_PER_WORD - 1) / UNITS_PER_WORD)))
+ if (GET_CODE (dest) == SUBREG && !read_modify_subreg_p (dest))
dest = SUBREG_REG (dest);
if (!REG_P (dest))
if (GET_CODE (pattern) == COND_EXEC)
return 0;
- if (GET_CODE (pattern) == SET)
+ if (GET_CODE (pattern) == SET || GET_CODE (pattern) == CLOBBER)
return covers_regno_p (SET_DEST (pattern), test_regno);
else if (GET_CODE (pattern) == PARALLEL)
{
datum, REG_NOTES (insn));
}
+/* Add a REG_ARGS_SIZE note to INSN with value VALUE. */
+
+void
+add_args_size_note (rtx_insn *insn, poly_int64 value)
+{
+ gcc_checking_assert (!find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX));
+ add_reg_note (insn, REG_ARGS_SIZE, gen_int_mode (value, Pmode));
+}
+
/* Add a register note like NOTE to INSN. */
void
code_changed
|| !MEM_NOTRAP_P (x))
{
- HOST_WIDE_INT size = MEM_SIZE_KNOWN_P (x) ? MEM_SIZE (x) : 0;
+ poly_int64 size = MEM_SIZE_KNOWN_P (x) ? MEM_SIZE (x) : -1;
return rtx_addr_can_trap_p_1 (XEXP (x, 0), 0, size,
GET_MODE (x), code_changed);
}
case PRE_INC:
case POST_INC:
{
- int size = GET_MODE_SIZE (GET_MODE (mem));
+ poly_int64 size = GET_MODE_SIZE (GET_MODE (mem));
rtx r1 = XEXP (x, 0);
rtx c = gen_int_mode (size, GET_MODE (r1));
return fn (mem, x, r1, r1, c, data);
case PRE_DEC:
case POST_DEC:
{
- int size = GET_MODE_SIZE (GET_MODE (mem));
+ poly_int64 size = GET_MODE_SIZE (GET_MODE (mem));
rtx r1 = XEXP (x, 0);
rtx c = gen_int_mode (-size, GET_MODE (r1));
return fn (mem, x, r1, r1, c, data);
/* Constants always become the second operand. Prefer "nice" constants. */
if (code == CONST_INT)
- return -8;
+ return -10;
if (code == CONST_WIDE_INT)
- return -7;
+ return -9;
+ if (code == CONST_POLY_INT)
+ return -8;
if (code == CONST_DOUBLE)
- return -7;
+ return -8;
if (code == CONST_FIXED)
- return -7;
+ return -8;
op = avoid_constant_pool_reference (op);
code = GET_CODE (op);
{
case RTX_CONST_OBJ:
if (code == CONST_INT)
- return -6;
+ return -7;
if (code == CONST_WIDE_INT)
- return -6;
+ return -6;
+ if (code == CONST_POLY_INT)
+ return -5;
if (code == CONST_DOUBLE)
- return -5;
+ return -5;
if (code == CONST_FIXED)
- return -5;
+ return -5;
return -4;
case RTX_EXTRA:
and SUBREG_BYTE, return the bit offset where the subreg begins
(counting from the least significant bit of the operand). */
-unsigned int
+poly_uint64
subreg_lsb_1 (machine_mode outer_mode,
machine_mode inner_mode,
- unsigned int subreg_byte)
+ poly_uint64 subreg_byte)
{
- unsigned int bitpos;
- unsigned int byte;
- unsigned int word;
+ poly_uint64 subreg_end, trailing_bytes, byte_pos;
/* A paradoxical subreg begins at bit position 0. */
if (paradoxical_subreg_p (outer_mode, inner_mode))
return 0;
- if (WORDS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
- /* If the subreg crosses a word boundary ensure that
- it also begins and ends on a word boundary. */
- gcc_assert (!((subreg_byte % UNITS_PER_WORD
- + GET_MODE_SIZE (outer_mode)) > UNITS_PER_WORD
- && (subreg_byte % UNITS_PER_WORD
- || GET_MODE_SIZE (outer_mode) % UNITS_PER_WORD)));
-
- if (WORDS_BIG_ENDIAN)
- word = (GET_MODE_SIZE (inner_mode)
- - (subreg_byte + GET_MODE_SIZE (outer_mode))) / UNITS_PER_WORD;
- else
- word = subreg_byte / UNITS_PER_WORD;
- bitpos = word * BITS_PER_WORD;
-
- if (BYTES_BIG_ENDIAN)
- byte = (GET_MODE_SIZE (inner_mode)
- - (subreg_byte + GET_MODE_SIZE (outer_mode))) % UNITS_PER_WORD;
+ subreg_end = subreg_byte + GET_MODE_SIZE (outer_mode);
+ trailing_bytes = GET_MODE_SIZE (inner_mode) - subreg_end;
+ if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
+ byte_pos = trailing_bytes;
+ else if (!WORDS_BIG_ENDIAN && !BYTES_BIG_ENDIAN)
+ byte_pos = subreg_byte;
else
- byte = subreg_byte % UNITS_PER_WORD;
- bitpos += byte * BITS_PER_UNIT;
+ {
+ /* When bytes and words have opposite endianness, we must be able
+ to split offsets into words and bytes at compile time. */
+ poly_uint64 leading_word_part
+ = force_align_down (subreg_byte, UNITS_PER_WORD);
+ poly_uint64 trailing_word_part
+ = force_align_down (trailing_bytes, UNITS_PER_WORD);
+ /* If the subreg crosses a word boundary ensure that
+ it also begins and ends on a word boundary. */
+ gcc_assert (known_le (subreg_end - leading_word_part,
+ (unsigned int) UNITS_PER_WORD)
+ || (known_eq (leading_word_part, subreg_byte)
+ && known_eq (trailing_word_part, trailing_bytes)));
+ if (WORDS_BIG_ENDIAN)
+ byte_pos = trailing_word_part + (subreg_byte - leading_word_part);
+ else
+ byte_pos = leading_word_part + (trailing_bytes - trailing_word_part);
+ }
- return bitpos;
+ return byte_pos * BITS_PER_UNIT;
}
/* Given a subreg X, return the bit offset where the subreg begins
(counting from the least significant bit of the reg). */
-unsigned int
+poly_uint64
subreg_lsb (const_rtx x)
{
return subreg_lsb_1 (GET_MODE (x), GET_MODE (SUBREG_REG (x)),
lsb of the inner value. This is the inverse of the calculation
performed by subreg_lsb_1 (which converts byte offsets to bit shifts). */
-unsigned int
-subreg_size_offset_from_lsb (unsigned int outer_bytes,
- unsigned int inner_bytes,
- unsigned int lsb_shift)
+poly_uint64
+subreg_size_offset_from_lsb (poly_uint64 outer_bytes, poly_uint64 inner_bytes,
+ poly_uint64 lsb_shift)
{
/* A paradoxical subreg begins at bit position 0. */
- if (outer_bytes > inner_bytes)
+ gcc_checking_assert (ordered_p (outer_bytes, inner_bytes));
+ if (maybe_gt (outer_bytes, inner_bytes))
{
- gcc_checking_assert (lsb_shift == 0);
+ gcc_checking_assert (known_eq (lsb_shift, 0U));
return 0;
}
- gcc_assert (lsb_shift % BITS_PER_UNIT == 0);
- unsigned int lower_bytes = lsb_shift / BITS_PER_UNIT;
- unsigned int upper_bytes = inner_bytes - (lower_bytes + outer_bytes);
+ poly_uint64 lower_bytes = exact_div (lsb_shift, BITS_PER_UNIT);
+ poly_uint64 upper_bytes = inner_bytes - (lower_bytes + outer_bytes);
if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
return upper_bytes;
else if (!WORDS_BIG_ENDIAN && !BYTES_BIG_ENDIAN)
return lower_bytes;
else
{
- unsigned int lower_word_part = lower_bytes & -UNITS_PER_WORD;
- unsigned int upper_word_part = upper_bytes & -UNITS_PER_WORD;
+ /* When bytes and words have opposite endianness, we must be able
+ to split offsets into words and bytes at compile time. */
+ poly_uint64 lower_word_part = force_align_down (lower_bytes,
+ UNITS_PER_WORD);
+ poly_uint64 upper_word_part = force_align_down (upper_bytes,
+ UNITS_PER_WORD);
if (WORDS_BIG_ENDIAN)
return upper_word_part + (lower_bytes - lower_word_part);
else
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
+ Likewise it doesn't check whether targetm.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, machine_mode xmode,
- unsigned int offset, machine_mode ymode,
+ poly_uint64 offset, machine_mode ymode,
struct subreg_info *info)
{
unsigned int nregs_xmode, nregs_ymode;
gcc_assert (xregno < FIRST_PSEUDO_REGISTER);
- unsigned int xsize = GET_MODE_SIZE (xmode);
- unsigned int ysize = GET_MODE_SIZE (ymode);
+ poly_uint64 xsize = GET_MODE_SIZE (xmode);
+ poly_uint64 ysize = GET_MODE_SIZE (ymode);
+
bool rknown = false;
/* If the register representation of a non-scalar mode has holes in it,
at least one register. */
if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode))
{
+ /* As a consequence, we must be dealing with a constant number of
+ scalars, and thus a constant offset and number of units. */
+ HOST_WIDE_INT coffset = offset.to_constant ();
+ HOST_WIDE_INT cysize = ysize.to_constant ();
nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode);
- unsigned int nunits = GET_MODE_NUNITS (xmode);
- machine_mode xmode_unit = GET_MODE_INNER (xmode);
+ unsigned int nunits = GET_MODE_NUNITS (xmode).to_constant ();
+ scalar_mode xmode_unit = GET_MODE_INNER (xmode);
gcc_assert (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode_unit));
gcc_assert (nregs_xmode
== (nunits
* HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode_unit)));
- gcc_assert (hard_regno_nregs[xregno][xmode]
- == hard_regno_nregs[xregno][xmode_unit] * nunits);
+ gcc_assert (hard_regno_nregs (xregno, xmode)
+ == hard_regno_nregs (xregno, xmode_unit) * nunits);
/* You can only ask for a SUBREG of a value with holes in the middle
if you don't cross the holes. (Such a SUBREG should be done by
3 for each part, but in memory it's two 128-bit parts.
Padding is assumed to be at the end (not necessarily the 'high part')
of each unit. */
- if ((offset / GET_MODE_SIZE (xmode_unit) + 1 < nunits)
- && (offset / GET_MODE_SIZE (xmode_unit)
- != ((offset + ysize - 1) / GET_MODE_SIZE (xmode_unit))))
+ if ((coffset / GET_MODE_SIZE (xmode_unit) + 1 < nunits)
+ && (coffset / GET_MODE_SIZE (xmode_unit)
+ != ((coffset + cysize - 1) / GET_MODE_SIZE (xmode_unit))))
{
info->representable_p = false;
rknown = true;
}
}
else
- nregs_xmode = hard_regno_nregs[xregno][xmode];
+ nregs_xmode = hard_regno_nregs (xregno, xmode);
- nregs_ymode = hard_regno_nregs[xregno][ymode];
+ nregs_ymode = hard_regno_nregs (xregno, ymode);
+
+ /* Subreg sizes must be ordered, so that we can tell whether they are
+ partial, paradoxical or complete. */
+ gcc_checking_assert (ordered_p (xsize, ysize));
/* Paradoxical subregs are otherwise valid. */
- if (!rknown && offset == 0 && ysize > xsize)
+ if (!rknown && known_eq (offset, 0U) && maybe_gt (ysize, xsize))
{
info->representable_p = true;
/* If this is a big endian paradoxical subreg, which uses more
/* If registers store different numbers of bits in the different
modes, we cannot generally form this subreg. */
+ poly_uint64 regsize_xmode, regsize_ymode;
if (!HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)
&& !HARD_REGNO_NREGS_HAS_PADDING (xregno, ymode)
- && (xsize % nregs_xmode) == 0
- && (ysize % nregs_ymode) == 0)
+ && multiple_p (xsize, nregs_xmode, ®size_xmode)
+ && multiple_p (ysize, nregs_ymode, ®size_ymode))
{
- int regsize_xmode = xsize / nregs_xmode;
- int regsize_ymode = ysize / nregs_ymode;
if (!rknown
- && ((nregs_ymode > 1 && regsize_xmode > regsize_ymode)
- || (nregs_xmode > 1 && regsize_ymode > regsize_xmode)))
+ && ((nregs_ymode > 1 && maybe_gt (regsize_xmode, regsize_ymode))
+ || (nregs_xmode > 1 && maybe_gt (regsize_ymode, regsize_xmode))))
{
info->representable_p = false;
- info->nregs = CEIL (ysize, regsize_xmode);
- info->offset = offset / regsize_xmode;
+ if (!can_div_away_from_zero_p (ysize, regsize_xmode, &info->nregs)
+ || !can_div_trunc_p (offset, regsize_xmode, &info->offset))
+ /* Checked by validate_subreg. We must know at compile time
+ which inner registers are being accessed. */
+ gcc_unreachable ();
return;
}
/* It's not valid to extract a subreg of mode YMODE at OFFSET that
would go outside of XMODE. */
- if (!rknown && ysize + offset > xsize)
+ if (!rknown && maybe_gt (ysize + offset, xsize))
{
info->representable_p = false;
info->nregs = nregs_ymode;
- info->offset = offset / regsize_xmode;
+ if (!can_div_trunc_p (offset, regsize_xmode, &info->offset))
+ /* Checked by validate_subreg. We must know at compile time
+ which inner registers are being accessed. */
+ gcc_unreachable ();
return;
}
/* Quick exit for the simple and common case of extracting whole
/* ??? 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. */
+ HOST_WIDE_INT count;
if (!rknown
&& WORDS_BIG_ENDIAN == REG_WORDS_BIG_ENDIAN
- && regsize_xmode == regsize_ymode
- && (offset % regsize_ymode) == 0)
+ && known_eq (regsize_xmode, regsize_ymode)
+ && constant_multiple_p (offset, regsize_ymode, &count))
{
info->representable_p = true;
info->nregs = nregs_ymode;
- info->offset = offset / regsize_ymode;
+ info->offset = count;
gcc_assert (info->offset + info->nregs <= (int) nregs_xmode);
return;
}
}
/* Lowpart subregs are otherwise valid. */
- if (!rknown && offset == subreg_lowpart_offset (ymode, xmode))
+ if (!rknown && known_eq (offset, subreg_lowpart_offset (ymode, xmode)))
{
info->representable_p = true;
rknown = true;
- if (offset == 0 || nregs_xmode == nregs_ymode)
+ if (known_eq (offset, 0U) || nregs_xmode == nregs_ymode)
{
info->offset = 0;
info->nregs = nregs_ymode;
be exact, otherwise we don't know how to verify the constraint.
These conditions may be relaxed but subreg_regno_offset would
need to be redesigned. */
- gcc_assert ((xsize % num_blocks) == 0);
- unsigned int bytes_per_block = xsize / num_blocks;
+ poly_uint64 bytes_per_block = exact_div (xsize, num_blocks);
/* Get the number of the first block that contains the subreg and the byte
offset of the subreg from the start of that block. */
- unsigned int block_number = offset / bytes_per_block;
- unsigned int subblock_offset = offset % bytes_per_block;
+ unsigned int block_number;
+ poly_uint64 subblock_offset;
+ if (!can_div_trunc_p (offset, bytes_per_block, &block_number,
+ &subblock_offset))
+ /* Checked by validate_subreg. We must know at compile time which
+ inner registers are being accessed. */
+ gcc_unreachable ();
if (!rknown)
{
/* Only the lowpart of each block is representable. */
info->representable_p
- = (subblock_offset
- == subreg_size_lowpart_offset (ysize, bytes_per_block));
+ = known_eq (subblock_offset,
+ subreg_size_lowpart_offset (ysize, bytes_per_block));
rknown = true;
}
RETURN - The regno offset which would be used. */
unsigned int
subreg_regno_offset (unsigned int xregno, machine_mode xmode,
- unsigned int offset, machine_mode ymode)
+ poly_uint64 offset, machine_mode ymode)
{
struct subreg_info info;
subreg_get_info (xregno, xmode, offset, ymode, &info);
RETURN - Whether the offset is representable. */
bool
subreg_offset_representable_p (unsigned int xregno, machine_mode xmode,
- unsigned int offset, machine_mode ymode)
+ poly_uint64 offset, machine_mode ymode)
{
struct subreg_info info;
subreg_get_info (xregno, xmode, offset, ymode, &info);
int
simplify_subreg_regno (unsigned int xregno, machine_mode xmode,
- unsigned int offset, machine_mode ymode)
+ poly_uint64 offset, machine_mode ymode)
{
struct subreg_info info;
unsigned int yregno;
-#ifdef CANNOT_CHANGE_MODE_CLASS
/* Give the backend a chance to disallow the mode change. */
if (GET_MODE_CLASS (xmode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (xmode) != MODE_COMPLEX_FLOAT
- && REG_CANNOT_CHANGE_MODE_P (xregno, xmode, ymode)
+ && !REG_CAN_CHANGE_MODE_P (xregno, xmode, ymode)
/* We can use mode change in LRA for some transformations. */
&& ! lra_in_progress)
return -1;
-#endif
/* We shouldn't simplify stack-related registers. */
if ((!reload_completed || frame_pointer_needed)
??? We allow invalid registers if (reg:XMODE XREGNO) is also invalid.
This is a kludge to work around how complex FP arguments are passed
on IA-64 and should be fixed. See PR target/49226. */
- if (!HARD_REGNO_MODE_OK (yregno, ymode)
- && HARD_REGNO_MODE_OK (xregno, xmode))
+ if (!targetm.hard_regno_mode_ok (yregno, ymode)
+ && targetm.hard_regno_mode_ok (xregno, xmode))
return -1;
return (int) yregno;
/* A size N times larger than UNITS_PER_WORD likely needs N times as
many insns, taking N times as long. */
- factor = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
+ factor = estimated_poly_value (GET_MODE_SIZE (mode)) / UNITS_PER_WORD;
if (factor == 0)
factor = 1;
/* A SET doesn't have a mode, so let's look at the SET_DEST to get
the mode for the factor. */
mode = GET_MODE (SET_DEST (x));
- factor = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
+ factor = estimated_poly_value (GET_MODE_SIZE (mode)) / UNITS_PER_WORD;
if (factor == 0)
factor = 1;
/* FALLTHRU */
total = 0;
/* If we can't tie these modes, make this expensive. The larger
the mode, the more expensive it is. */
- if (! MODES_TIEABLE_P (mode, GET_MODE (SUBREG_REG (x))))
+ if (!targetm.modes_tieable_p (mode, GET_MODE (SUBREG_REG (x))))
return COSTS_N_INSNS (2 + factor);
break;
case TRUNCATE:
- if (MODES_TIEABLE_P (mode, GET_MODE (XEXP (x, 0))))
+ if (targetm.modes_tieable_p (mode, GET_MODE (XEXP (x, 0))))
{
total = 0;
break;
{
unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
unsigned HOST_WIDE_INT inner_nz;
- enum rtx_code code;
+ enum rtx_code code = GET_CODE (x);
machine_mode inner_mode;
+ unsigned int inner_width;
scalar_int_mode xmode;
unsigned int mode_width = GET_MODE_PRECISION (mode);
return nonzero;
/* If MODE is wider than X, but both are a single word for both the host
- and target machines, we can compute this from which bits of the
- object might be nonzero in its own mode, taking into account the fact
- that on many CISC machines, accessing an object in a wider mode
- causes the high-order bits to become undefined. So they are
- not known to be zero. */
-
- if (!WORD_REGISTER_OPERATIONS
- && mode_width > xmode_width
+ and target machines, we can compute this from which bits of the object
+ might be nonzero in its own mode, taking into account the fact that, on
+ CISC machines, accessing an object in a wider mode generally causes the
+ high-order bits to become undefined, so they are not known to be zero.
+ We extend this reasoning to RISC machines for rotate operations since the
+ semantics of the operations in the larger mode is not well defined. */
+ if (mode_width > xmode_width
&& xmode_width <= BITS_PER_WORD
- && xmode_width <= HOST_BITS_PER_WIDE_INT)
+ && xmode_width <= HOST_BITS_PER_WIDE_INT
+ && (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT))
{
nonzero &= cached_nonzero_bits (x, xmode,
known_x, known_mode, known_ret);
/* Please keep nonzero_bits_binary_arith_p above in sync with
the code in the switch below. */
- code = GET_CODE (x);
switch (code)
{
case REG:
stack to be momentarily aligned only to that amount,
so we pick the least alignment. */
if (x == stack_pointer_rtx && PUSH_ARGS)
- alignment = MIN ((unsigned HOST_WIDE_INT) PUSH_ROUNDING (1),
- alignment);
+ {
+ poly_uint64 rounded_1 = PUSH_ROUNDING (poly_int64 (1));
+ alignment = MIN (known_alignment (rounded_1), alignment);
+ }
#endif
nonzero &= ~(alignment - 1);
machines, we can compute this from which bits of the inner
object might be nonzero. */
inner_mode = GET_MODE (SUBREG_REG (x));
- if (GET_MODE_PRECISION (inner_mode) <= BITS_PER_WORD
- && GET_MODE_PRECISION (inner_mode) <= HOST_BITS_PER_WIDE_INT)
+ if (GET_MODE_PRECISION (inner_mode).is_constant (&inner_width)
+ && inner_width <= BITS_PER_WORD
+ && inner_width <= HOST_BITS_PER_WIDE_INT)
{
nonzero &= cached_nonzero_bits (SUBREG_REG (x), mode,
known_x, known_mode, known_ret);
? val_signbit_known_set_p (inner_mode, nonzero)
: extend_op != ZERO_EXTEND)
|| (!MEM_P (SUBREG_REG (x)) && !REG_P (SUBREG_REG (x))))
- && xmode_width > GET_MODE_PRECISION (inner_mode))
- nonzero |= (GET_MODE_MASK (xmode) & ~GET_MODE_MASK (inner_mode));
+ && xmode_width > inner_width)
+ nonzero
+ |= (GET_MODE_MASK (GET_MODE (x)) & ~GET_MODE_MASK (inner_mode));
}
break;
+ case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
- case ASHIFT:
case ROTATE:
+ case ROTATERT:
/* The nonzero bits are in two classes: any bits within MODE
that aren't in xmode are always significant. The rest of the
nonzero bits are those that are significant in the operand of
if (mode_width > xmode_width)
outer = (op_nonzero & nonzero & ~mode_mask);
- if (code == LSHIFTRT)
- inner >>= count;
- else if (code == ASHIFTRT)
+ switch (code)
{
+ case ASHIFT:
+ inner <<= count;
+ break;
+
+ case LSHIFTRT:
+ inner >>= count;
+ break;
+
+ case ASHIFTRT:
inner >>= count;
/* If the sign bit may have been nonzero before the shift, we
if (inner & (HOST_WIDE_INT_1U << (xmode_width - 1 - count)))
inner |= (((HOST_WIDE_INT_1U << count) - 1)
<< (xmode_width - count));
+ break;
+
+ case ROTATE:
+ inner = (inner << (count % xmode_width)
+ | (inner >> (xmode_width - (count % xmode_width))))
+ & mode_mask;
+ break;
+
+ case ROTATERT:
+ inner = (inner >> (count % xmode_width)
+ | (inner << (xmode_width - (count % xmode_width))))
+ & mode_mask;
+ break;
+
+ default:
+ gcc_unreachable ();
}
- else if (code == ASHIFT)
- inner <<= count;
- else
- inner = ((inner << (count % xmode_width)
- | (inner >> (xmode_width - (count % xmode_width))))
- & mode_mask);
nonzero &= (outer | inner);
}
{
/* If this machine does not do all register operations on the entire
register and MODE is wider than the mode of X, we can say nothing
- at all about the high-order bits. */
- if (!WORD_REGISTER_OPERATIONS)
+ at all about the high-order bits. We extend this reasoning to every
+ machine for rotate operations since the semantics of the operations
+ in the larger mode is not well defined. */
+ if (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT)
return 1;
/* Likewise on machines that do, if the mode of the object is smaller
if (WORD_REGISTER_OPERATIONS
&& load_extend_op (inner_mode) == SIGN_EXTEND
&& paradoxical_subreg_p (x)
- && (MEM_P (SUBREG_REG (x)) || REG_P (SUBREG_REG (x))))
+ && MEM_P (SUBREG_REG (x)))
return cached_num_sign_bit_copies (SUBREG_REG (x), mode,
known_x, known_mode, known_ret);
}
? 1 : bitwidth - floor_log2 (nonzero) - 1;
}
-/* Calculate the rtx_cost of a single instruction. A return value of
+/* Calculate the rtx_cost of a single instruction pattern. A return value of
zero indicates an instruction pattern without a known cost. */
int
-insn_rtx_cost (rtx pat, bool speed)
+pattern_cost (rtx pat, bool speed)
{
int i, cost;
rtx set;
return cost > 0 ? cost : COSTS_N_INSNS (1);
}
+/* Calculate the cost of a single instruction. A return value of zero
+ indicates an instruction pattern without a known cost. */
+
+int
+insn_cost (rtx_insn *insn, bool speed)
+{
+ if (targetm.insn_cost)
+ return targetm.insn_cost (insn, speed);
+
+ return pattern_cost (PATTERN (insn), speed);
+}
+
/* Returns estimate on cost of computing SEQ. */
unsigned
set = single_set (seq);
if (set)
cost += set_rtx_cost (set, speed);
- else
- cost++;
+ else if (NONDEBUG_INSN_P (seq))
+ {
+ int this_cost = insn_cost (CONST_CAST_RTX_INSN (seq), speed);
+ if (this_cost > 0)
+ cost += this_cost;
+ else
+ cost++;
+ }
}
return cost;
if (CC0_P (op0))
return 0;
- return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
+ /* We promised to return a comparison. */
+ rtx ret = gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
+ if (COMPARISON_P (ret))
+ return ret;
+ return 0;
}
/* Given a jump insn JUMP, return the condition that will cause it to branch
static void
init_num_sign_bit_copies_in_rep (void)
{
- machine_mode mode, in_mode;
+ opt_scalar_int_mode in_mode_iter;
+ scalar_int_mode mode;
- FOR_EACH_MODE_IN_CLASS (in_mode, MODE_INT)
- FOR_EACH_MODE_UNTIL (mode, in_mode)
+ FOR_EACH_MODE_IN_CLASS (in_mode_iter, MODE_INT)
+ FOR_EACH_MODE_UNTIL (mode, in_mode_iter.require ())
{
- machine_mode i;
+ scalar_int_mode in_mode = in_mode_iter.require ();
+ scalar_int_mode i;
/* Currently, it is assumed that TARGET_MODE_REP_EXTENDED
extends to the next widest mode. */
{
/* This must always exist (for the last iteration it will be
IN_MODE). */
- machine_mode wider = GET_MODE_WIDER_MODE (i).require ();
+ scalar_int_mode wider = GET_MODE_WIDER_MODE (i).require ();
if (targetm.mode_rep_extended (i, wider) == SIGN_EXTEND
/* We can only check sign-bit copies starting from the
{
if (mode != VOIDmode)
{
- if (GET_MODE_PRECISION (mode) > HOST_BITS_PER_WIDE_INT)
+ if (!HWI_COMPUTABLE_MODE_P (mode))
return -1;
m &= GET_MODE_MASK (mode);
}
/* Return the mode of MEM's address. */
-machine_mode
+scalar_int_mode
get_address_mode (rtx mem)
{
machine_mode mode;
machine_mode mode = GET_MODE (XEXP (x, 0));
HOST_WIDE_INT len = INTVAL (XEXP (x, 1));
HOST_WIDE_INT pos = INTVAL (XEXP (x, 2));
+ poly_int64 remaining_bits = GET_MODE_PRECISION (mode) - len;
- return (pos == (BITS_BIG_ENDIAN ? GET_MODE_PRECISION (mode) - len : 0));
+ return known_eq (pos, BITS_BIG_ENDIAN ? remaining_bits : 0);
}
return false;
}