Mercurial > hg > CbC > CbC_gcc
diff gcc/rtlanal.c @ 132:d34655255c78
update gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 10:21:07 +0900 |
parents | 84e7813d76e9 |
children | 1830386684a0 |
line wrap: on
line diff
--- a/gcc/rtlanal.c Thu Oct 25 08:08:40 2018 +0900 +++ b/gcc/rtlanal.c Thu Oct 25 10:21:07 2018 +0900 @@ -1,5 +1,5 @@ /* 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. @@ -35,6 +35,7 @@ #include "recog.h" #include "addresses.h" #include "rtl-iter.h" +#include "hard-reg-set.h" /* Forward declarations */ static void set_of_1 (rtx, const_rtx, void *); @@ -344,7 +345,7 @@ 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 @@ -352,7 +353,7 @@ 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) @@ -457,16 +458,18 @@ 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)); + poly_int64 const_x1; /* 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 @@ -477,7 +480,7 @@ 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; } @@ -489,14 +492,12 @@ if (!CONSTANT_POOL_ADDRESS_P (x) && !SYMBOL_REF_FUNCTION_P (x)) { tree decl; - HOST_WIDE_INT decl_size; - - if (offset < 0) + poly_int64 decl_size; + + 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. */ @@ -507,9 +508,10 @@ 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))) @@ -517,7 +519,9 @@ 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; @@ -534,17 +538,14 @@ || (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; - - if (size == 0) - size = GET_MODE_SIZE (mode); - if (size == 0) + poly_int64 stack_boundary = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; + poly_int64 low_bound, high_bound; + + if (!known_size_p (size)) return 1; if (x == frame_pointer_rtx) @@ -562,10 +563,10 @@ } 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); @@ -589,7 +590,7 @@ } 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); @@ -629,7 +630,8 @@ #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; } @@ -649,12 +651,12 @@ 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. */ - if (CONST_INT_P (XEXP (x, 1)) - && !rtx_addr_can_trap_p_1 (XEXP (x, 0), offset + INTVAL (XEXP (x, 1)), + if (poly_int_rtx_p (XEXP (x, 1), &const_x1) + && !rtx_addr_can_trap_p_1 (XEXP (x, 0), offset + const_x1, size, mode, unaligned_mems)) return 0; @@ -686,7 +688,7 @@ 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. */ @@ -915,6 +917,37 @@ *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)); +} /* 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. */ @@ -1165,6 +1198,10 @@ return 1; return 0; + case CLOBBER_HIGH: + gcc_assert (REG_P (XEXP (body, 0))); + return 0; + case COND_EXEC: if (reg_overlap_mentioned_p (x, COND_EXEC_TEST (body))) return 1; @@ -1364,13 +1401,15 @@ bool read_modify_subreg_p (const_rtx x) { - unsigned int isize, osize; if (GET_CODE (x) != SUBREG) return false; - isize = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))); - osize = GET_MODE_SIZE (GET_MODE (x)); - return isize > osize - && isize > REGMODE_NATURAL_SIZE (GET_MODE (SUBREG_REG (x))); + 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)); } /* Helper function for set_of. */ @@ -1385,7 +1424,11 @@ { struct set_of_data *const data = (struct set_of_data *) (data1); if (rtx_equal_p (x, data->pat) - || (!MEM_P (x) && reg_overlap_mentioned_p (data->pat, x))) + || (GET_CODE (pat) == CLOBBER_HIGH + && REGNO(data->pat) == REGNO(XEXP (pat, 0)) + && reg_is_clobbered_by_clobber_high (data->pat, XEXP (pat, 0))) + || (GET_CODE (pat) != CLOBBER_HIGH && !MEM_P (x) + && reg_overlap_mentioned_p (data->pat, x))) data->found = pat; } @@ -1474,6 +1517,7 @@ { case USE: case CLOBBER: + case CLOBBER_HIGH: break; case SET: @@ -1564,7 +1608,7 @@ 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); @@ -1580,15 +1624,16 @@ 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; + poly_int64 c0 = rtx_to_poly_int64 (XVECEXP (par, 0, 0)); + poly_int64 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) + if (maybe_ne (rtx_to_poly_int64 (XVECEXP (par, 0, i)), c0 + i)) return 0; return - simplify_subreg_regno (REGNO (src0), GET_MODE (src0), - offset, GET_MODE (dst)) == (int) REGNO (dst); + REG_CAN_CHANGE_MODE_P (REGNO (dst), GET_MODE (src0), GET_MODE (dst)) + && simplify_subreg_regno (REGNO (src0), GET_MODE (src0), + offset, GET_MODE (dst)) == (int) REGNO (dst); } return (REG_P (src) && REG_P (dst) @@ -1627,7 +1672,8 @@ rtx tem = XVECEXP (pat, 0, i); if (GET_CODE (tem) == USE - || GET_CODE (tem) == CLOBBER) + || GET_CODE (tem) == CLOBBER + || GET_CODE (tem) == CLOBBER_HIGH) continue; if (GET_CODE (tem) != SET || ! set_noop_p (tem)) @@ -1769,6 +1815,7 @@ recurse: switch (GET_CODE (x)) { + case CLOBBER: case STRICT_LOW_PART: case ZERO_EXTRACT: case SIGN_EXTRACT: @@ -1859,7 +1906,9 @@ if (GET_CODE (x) == COND_EXEC) x = COND_EXEC_CODE (x); - if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER) + if (GET_CODE (x) == SET + || GET_CODE (x) == CLOBBER + || GET_CODE (x) == CLOBBER_HIGH) { rtx dest = SET_DEST (x); @@ -2082,7 +2131,7 @@ 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) { @@ -2340,6 +2389,15 @@ 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 @@ -2774,7 +2832,7 @@ 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); } @@ -3304,7 +3362,7 @@ 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); @@ -3313,7 +3371,7 @@ 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); @@ -3406,13 +3464,15 @@ /* 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); @@ -3420,13 +3480,15 @@ { 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: @@ -3531,48 +3593,50 @@ 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; + 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 - 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; - else - byte = subreg_byte % UNITS_PER_WORD; - bitpos += byte * BITS_PER_UNIT; - - return bitpos; + { + /* 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 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)), @@ -3585,29 +3649,32 @@ 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 @@ -3636,15 +3703,16 @@ 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, @@ -3653,8 +3721,12 @@ 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); + 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 @@ -3671,9 +3743,9 @@ 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; @@ -3684,8 +3756,12 @@ 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 @@ -3707,29 +3783,34 @@ /* 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 @@ -3737,26 +3818,27 @@ /* ??? 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; @@ -3776,20 +3858,24 @@ 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; } @@ -3816,7 +3902,7 @@ 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); @@ -3832,7 +3918,7 @@ 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); @@ -3849,7 +3935,7 @@ 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; @@ -4124,7 +4210,7 @@ /* 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; @@ -4155,7 +4241,7 @@ /* 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 */ @@ -4359,8 +4445,9 @@ { 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); @@ -4394,16 +4481,16 @@ 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); @@ -4413,7 +4500,6 @@ /* 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: @@ -4448,8 +4534,10 @@ 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); @@ -4663,8 +4751,9 @@ 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); @@ -4680,15 +4769,17 @@ ? 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 @@ -4711,10 +4802,17 @@ 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 @@ -4723,13 +4821,23 @@ 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); } @@ -4917,8 +5025,10 @@ { /* 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 @@ -5007,7 +5117,7 @@ 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); } @@ -5341,8 +5451,14 @@ 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; @@ -5623,7 +5739,11 @@ 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 @@ -5996,8 +6116,9 @@ 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)); + poly_int64 remaining_bits = GET_MODE_PRECISION (mode) - len; + + return known_eq (pos, BITS_BIG_ENDIAN ? remaining_bits : 0); } return false; } @@ -6443,3 +6564,32 @@ return true; return false; } + +/* Return true if reg REGNO with mode REG_MODE would be clobbered by the + clobber_high operand in CLOBBER_HIGH_OP. */ + +bool +reg_is_clobbered_by_clobber_high (unsigned int regno, machine_mode reg_mode, + const_rtx clobber_high_op) +{ + unsigned int clobber_regno = REGNO (clobber_high_op); + machine_mode clobber_mode = GET_MODE (clobber_high_op); + unsigned char regno_nregs = hard_regno_nregs (regno, reg_mode); + + /* Clobber high should always span exactly one register. */ + gcc_assert (REG_NREGS (clobber_high_op) == 1); + + /* Clobber high needs to match with one of the registers in X. */ + if (clobber_regno < regno || clobber_regno >= regno + regno_nregs) + return false; + + gcc_assert (reg_mode != BLKmode && clobber_mode != BLKmode); + + if (reg_mode == VOIDmode) + return clobber_mode != VOIDmode; + + /* Clobber high will clobber if its size might be greater than the size of + register regno. */ + return maybe_gt (exact_div (GET_MODE_SIZE (reg_mode), regno_nregs), + GET_MODE_SIZE (clobber_mode)); +}