diff options
author | Giuliano Belinassi <giuliano.belinassi@usp.br> | 2020-08-22 17:43:43 -0300 |
---|---|---|
committer | Giuliano Belinassi <giuliano.belinassi@usp.br> | 2020-08-22 17:43:43 -0300 |
commit | a926878ddbd5a98b272c22171ce58663fc04c3e0 (patch) | |
tree | 86af256e5d9a9c06263c00adc90e5fe348008c43 /gcc/fold-const.c | |
parent | 542730f087133690b47e036dfd43eb0db8a650ce (diff) | |
parent | 07cbaed8ba7d1b6e4ab3a9f44175502a4e1ecdb1 (diff) | |
download | gcc-devel/autopar_devel.zip gcc-devel/autopar_devel.tar.gz gcc-devel/autopar_devel.tar.bz2 |
Merge branch 'autopar_rebase2' into autopar_develdevel/autopar_devel
Quickly commit changes in the rebase branch.
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 248 |
1 files changed, 200 insertions, 48 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index f054871..9fc4c2a 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -5770,8 +5770,22 @@ fold_cond_expr_with_comparison (location_t loc, tree type, case LT_EXPR: if (TYPE_UNSIGNED (TREE_TYPE (arg1))) break; - tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); - return negate_expr (fold_convert_loc (loc, type, tem)); + if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg1)) + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1))) + { + /* A <= 0 ? A : -A for A INT_MIN is valid, but -abs(INT_MIN) + is not, invokes UB both in abs and in the negation of it. + So, use ABSU_EXPR instead. */ + tree utype = unsigned_type_for (TREE_TYPE (arg1)); + tem = fold_build1_loc (loc, ABSU_EXPR, utype, arg1); + tem = negate_expr (tem); + return fold_convert_loc (loc, type, tem); + } + else + { + tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); + return negate_expr (fold_convert_loc (loc, type, tem)); + } default: gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison); break; @@ -5917,6 +5931,13 @@ fold_range_test (location_t loc, enum tree_code code, tree type, return 0; lhs = make_range (op0, &in0_p, &low0, &high0, &strict_overflow_p); + /* If op0 is known true or false and this is a short-circuiting + operation we must not merge with op1 since that makes side-effects + unconditional. So special-case this. */ + if (!lhs + && ((code == TRUTH_ORIF_EXPR && in0_p) + || (code == TRUTH_ANDIF_EXPR && !in0_p))) + return op0; rhs = make_range (op1, &in1_p, &low1, &high1, &strict_overflow_p); /* If this is an OR operation, invert both sides; we will invert @@ -8033,6 +8054,7 @@ native_encode_initializer (tree init, unsigned char *ptr, int len, tree field = ce->index; tree val = ce->value; HOST_WIDE_INT pos, fieldsize; + unsigned HOST_WIDE_INT bpos = 0, epos = 0; if (field == NULL_TREE) return 0; @@ -8052,15 +8074,122 @@ native_encode_initializer (tree init, unsigned char *ptr, int len, if (fieldsize == 0) continue; + if (DECL_BIT_FIELD (field)) + { + if (!tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (field))) + return 0; + fieldsize = TYPE_PRECISION (TREE_TYPE (field)); + bpos = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field)); + if (bpos % BITS_PER_UNIT) + bpos %= BITS_PER_UNIT; + else + bpos = 0; + fieldsize += bpos; + epos = fieldsize % BITS_PER_UNIT; + fieldsize += BITS_PER_UNIT - 1; + fieldsize /= BITS_PER_UNIT; + } + if (off != -1 && pos + fieldsize <= off) continue; - if (DECL_BIT_FIELD (field)) - return 0; - if (val == NULL_TREE) continue; + if (DECL_BIT_FIELD (field)) + { + /* FIXME: Handle PDP endian. */ + if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) + return 0; + + tree repr = DECL_BIT_FIELD_REPRESENTATIVE (field); + if (repr == NULL_TREE + || TREE_CODE (val) != INTEGER_CST + || !INTEGRAL_TYPE_P (TREE_TYPE (repr))) + return 0; + + HOST_WIDE_INT rpos = int_byte_position (repr); + if (rpos > pos) + return 0; + wide_int w = wi::to_wide (val, + TYPE_PRECISION (TREE_TYPE (repr))); + int diff = (TYPE_PRECISION (TREE_TYPE (repr)) + - TYPE_PRECISION (TREE_TYPE (field))); + HOST_WIDE_INT bitoff = (pos - rpos) * BITS_PER_UNIT + bpos; + if (!BYTES_BIG_ENDIAN) + w = wi::lshift (w, bitoff); + else + w = wi::lshift (w, diff - bitoff); + val = wide_int_to_tree (TREE_TYPE (repr), w); + + unsigned char buf[MAX_BITSIZE_MODE_ANY_INT + / BITS_PER_UNIT + 1]; + int l = native_encode_int (val, buf, sizeof buf, 0); + if (l * BITS_PER_UNIT != TYPE_PRECISION (TREE_TYPE (repr))) + return 0; + + if (ptr == NULL) + continue; + + /* If the bitfield does not start at byte boundary, handle + the partial byte at the start. */ + if (bpos + && (off == -1 || (pos >= off && len >= 1))) + { + if (!BYTES_BIG_ENDIAN) + { + int mask = (1 << bpos) - 1; + buf[pos - rpos] &= ~mask; + buf[pos - rpos] |= ptr[pos - o] & mask; + } + else + { + int mask = (1 << (BITS_PER_UNIT - bpos)) - 1; + buf[pos - rpos] &= mask; + buf[pos - rpos] |= ptr[pos - o] & ~mask; + } + } + /* If the bitfield does not end at byte boundary, handle + the partial byte at the end. */ + if (epos + && (off == -1 + || pos + fieldsize <= (HOST_WIDE_INT) off + len)) + { + if (!BYTES_BIG_ENDIAN) + { + int mask = (1 << epos) - 1; + buf[pos - rpos + fieldsize - 1] &= mask; + buf[pos - rpos + fieldsize - 1] + |= ptr[pos + fieldsize - 1 - o] & ~mask; + } + else + { + int mask = (1 << (BITS_PER_UNIT - epos)) - 1; + buf[pos - rpos + fieldsize - 1] &= ~mask; + buf[pos - rpos + fieldsize - 1] + |= ptr[pos + fieldsize - 1 - o] & mask; + } + } + if (off == -1 + || (pos >= off + && (pos + fieldsize <= (HOST_WIDE_INT) off + len))) + memcpy (ptr + pos - o, buf + (pos - rpos), fieldsize); + else + { + /* Partial overlap. */ + HOST_WIDE_INT fsz = fieldsize; + if (pos < off) + { + fsz -= (off - pos); + pos = off; + } + if (pos + fsz > (HOST_WIDE_INT) off + len) + fsz = (HOST_WIDE_INT) off + len - pos; + memcpy (ptr + pos - off, buf + (pos - rpos), fsz); + } + continue; + } + if (off == -1 || (pos >= off && (pos + fieldsize <= (HOST_WIDE_INT) off + len))) @@ -10065,8 +10194,7 @@ tree_expr_nonzero_p (tree t) bool expr_not_equal_to (tree t, const wide_int &w) { - wide_int min, max, nz; - value_range_kind rtype; + value_range vr; switch (TREE_CODE (t)) { case INTEGER_CST: @@ -10075,17 +10203,9 @@ expr_not_equal_to (tree t, const wide_int &w) case SSA_NAME: if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) return false; - rtype = get_range_info (t, &min, &max); - if (rtype == VR_RANGE) - { - if (wi::lt_p (max, w, TYPE_SIGN (TREE_TYPE (t)))) - return true; - if (wi::lt_p (w, min, TYPE_SIGN (TREE_TYPE (t)))) - return true; - } - else if (rtype == VR_ANTI_RANGE - && wi::le_p (min, w, TYPE_SIGN (TREE_TYPE (t))) - && wi::le_p (w, max, TYPE_SIGN (TREE_TYPE (t)))) + get_range_info (t, vr); + if (!vr.undefined_p () + && !vr.contains_p (wide_int_to_tree (TREE_TYPE (t), w))) return true; /* If T has some known zero bits and W has any of those bits set, then T is known not to be equal to W. */ @@ -13794,8 +13914,10 @@ tree_call_nonnegative_warnv_p (tree type, combined_fn fn, tree arg0, tree arg1, CASE_CFN_POPCOUNT: CASE_CFN_CLZ: CASE_CFN_CLRSB: + case CFN_BUILT_IN_BSWAP16: case CFN_BUILT_IN_BSWAP32: case CFN_BUILT_IN_BSWAP64: + case CFN_BUILT_IN_BSWAP128: /* Always true. */ return true; @@ -15363,24 +15485,32 @@ fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE_INT off) ptr, size_int (off)); } -/* Return a pointer P to a NUL-terminated string representing the sequence - of constant characters referred to by SRC (or a subsequence of such - characters within it if SRC is a reference to a string plus some - constant offset). If STRLEN is non-null, store the number of bytes - in the string constant including the terminating NUL char. *STRLEN is - typically strlen(P) + 1 in the absence of embedded NUL characters. */ +/* Return a pointer to a NUL-terminated string containing the sequence + of bytes corresponding to the representation of the object referred to + by SRC (or a subsequence of such bytes within it if SRC is a reference + to an initialized constant array plus some constant offset). + Set *STRSIZE the number of bytes in the constant sequence including + the terminating NUL byte. *STRSIZE is equal to sizeof(A) - OFFSET + where A is the array that stores the constant sequence that SRC points + to and OFFSET is the byte offset of SRC from the beginning of A. SRC + need not point to a string or even an array of characters but may point + to an object of any type. */ const char * -c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */) +getbyterep (tree src, unsigned HOST_WIDE_INT *strsize) { + /* The offset into the array A storing the string, and A's byte size. */ tree offset_node; tree mem_size; - if (strlen) - *strlen = 0; + if (strsize) + *strsize = 0; - src = string_constant (src, &offset_node, &mem_size, NULL); - if (src == 0) + if (strsize) + src = byte_representation (src, &offset_node, &mem_size, NULL); + else + src = string_constant (src, &offset_node, &mem_size, NULL); + if (!src) return NULL; unsigned HOST_WIDE_INT offset = 0; @@ -15395,34 +15525,44 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */) if (!tree_fits_uhwi_p (mem_size)) return NULL; - /* STRING_LENGTH is the size of the string literal, including any - embedded NULs. STRING_SIZE is the size of the array the string - literal is stored in. */ - unsigned HOST_WIDE_INT string_length = TREE_STRING_LENGTH (src); - unsigned HOST_WIDE_INT string_size = tree_to_uhwi (mem_size); + /* ARRAY_SIZE is the byte size of the array the constant sequence + is stored in and equal to sizeof A. INIT_BYTES is the number + of bytes in the constant sequence used to initialize the array, + including any embedded NULs as well as the terminating NUL (for + strings), but not including any trailing zeros/NULs past + the terminating one appended implicitly to a string literal to + zero out the remainder of the array it's stored in. For example, + given: + const char a[7] = "abc\0d"; + n = strlen (a + 1); + ARRAY_SIZE is 7, INIT_BYTES is 6, and OFFSET is 1. For a valid + (i.e., nul-terminated) string with no embedded nuls, INIT_BYTES + is equal to strlen (A) + 1. */ + const unsigned HOST_WIDE_INT array_size = tree_to_uhwi (mem_size); + unsigned HOST_WIDE_INT init_bytes = TREE_STRING_LENGTH (src); /* Ideally this would turn into a gcc_checking_assert over time. */ - if (string_length > string_size) - string_length = string_size; + if (init_bytes > array_size) + init_bytes = array_size; const char *string = TREE_STRING_POINTER (src); /* Ideally this would turn into a gcc_checking_assert over time. */ - if (string_length > string_size) - string_length = string_size; + if (init_bytes > array_size) + init_bytes = array_size; - if (string_length == 0 - || offset >= string_size) + if (init_bytes == 0 || offset >= array_size) return NULL; - if (strlen) + if (strsize) { - /* Compute and store the length of the substring at OFFSET. - All offsets past the initial length refer to null strings. */ - if (offset < string_length) - *strlen = string_length - offset; + /* Compute and store the number of characters from the beginning + of the substring at OFFSET to the end, including the terminating + nul. Offsets past the initial length refer to null strings. */ + if (offset < init_bytes) + *strsize = init_bytes - offset; else - *strlen = 1; + *strsize = 1; } else { @@ -15430,11 +15570,23 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */) /* Support only properly NUL-terminated single byte strings. */ if (tree_to_uhwi (TYPE_SIZE_UNIT (eltype)) != 1) return NULL; - if (string[string_length - 1] != '\0') + if (string[init_bytes - 1] != '\0') return NULL; } - return offset < string_length ? string + offset : ""; + return offset < init_bytes ? string + offset : ""; +} + +/* Return a pointer to a NUL-terminated string corresponding to + the expression STR referencing a constant string, possibly + involving a constant offset. Return null if STR either doesn't + reference a constant string or if it involves a nonconstant + offset. */ + +const char * +c_getstr (tree str) +{ + return getbyterep (str, NULL); } /* Given a tree T, compute which bits in T may be nonzero. */ |