diff options
author | Thomas Koenig <tkoenig@gcc.gnu.org> | 2021-01-03 21:40:04 +0100 |
---|---|---|
committer | Thomas Koenig <tkoenig@gcc.gnu.org> | 2021-01-03 21:40:04 +0100 |
commit | afae4a55ccaa0de95ea11e5f634084db6ab2f444 (patch) | |
tree | d632cc867d10410ba9fb750523be790b86846ac4 /gcc/expr.c | |
parent | 9d9a82ec8478ff52c7a9d61f58cd2a7b6295b5f9 (diff) | |
parent | d2eb616a0f7bea78164912aa438c29fe1ef5774a (diff) | |
download | gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.zip gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.tar.gz gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.tar.bz2 |
Merge branch 'master' into devel/coarray_native
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 222 |
1 files changed, 74 insertions, 148 deletions
@@ -29,8 +29,8 @@ along with GCC; see the file COPYING3. If not see #include "memmodel.h" #include "tm_p.h" #include "ssa.h" -#include "expmed.h" #include "optabs.h" +#include "expmed.h" #include "regs.h" #include "emit-rtl.h" #include "recog.h" @@ -96,7 +96,6 @@ static void emit_single_push_insn (machine_mode, rtx, tree); static void do_tablejump (rtx, machine_mode, rtx, rtx, rtx, profile_probability); static rtx const_vector_from_tree (tree); -static rtx const_scalar_mask_from_tree (scalar_int_mode, tree); static tree tree_expr_size (const_tree); static HOST_WIDE_INT int_expr_size (tree); static void convert_mode_scalar (rtx, rtx, int); @@ -5452,6 +5451,30 @@ expand_assignment (tree to, tree from, bool nontemporal) mode1, to_rtx, to, from, reversep)) result = NULL; + else if (SUBREG_P (to_rtx) + && SUBREG_PROMOTED_VAR_P (to_rtx)) + { + /* If to_rtx is a promoted subreg, we need to zero or sign + extend the value afterwards. */ + if (TREE_CODE (to) == MEM_REF + && !REF_REVERSE_STORAGE_ORDER (to) + && known_eq (bitpos, 0) + && known_eq (bitsize, GET_MODE_BITSIZE (GET_MODE (to_rtx)))) + result = store_expr (from, to_rtx, 0, nontemporal, false); + else + { + rtx to_rtx1 + = lowpart_subreg (subreg_unpromoted_mode (to_rtx), + SUBREG_REG (to_rtx), + subreg_promoted_mode (to_rtx)); + result = store_field (to_rtx1, bitsize, bitpos, + bitregion_start, bitregion_end, + mode1, from, get_alias_set (to), + nontemporal, reversep); + convert_move (SUBREG_REG (to_rtx), to_rtx1, + SUBREG_PROMOTED_SIGN (to_rtx)); + } + } else result = store_field (to_rtx, bitsize, bitpos, bitregion_start, bitregion_end, @@ -6172,6 +6195,7 @@ count_type_elements (const_tree type, bool for_ctor_p) return 0; case VOID_TYPE: + case OPAQUE_TYPE: case METHOD_TYPE: case FUNCTION_TYPE: case LANG_TYPE: @@ -9035,6 +9059,8 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, target, unsignedp); return target; + case WIDEN_PLUS_EXPR: + case WIDEN_MINUS_EXPR: case WIDEN_MULT_EXPR: /* If first operand is constant, swap them. Thus the following special case checks need only @@ -9755,6 +9781,10 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, return temp; } + case VEC_WIDEN_PLUS_HI_EXPR: + case VEC_WIDEN_PLUS_LO_EXPR: + case VEC_WIDEN_MINUS_HI_EXPR: + case VEC_WIDEN_MINUS_LO_EXPR: case VEC_WIDEN_MULT_HI_EXPR: case VEC_WIDEN_MULT_LO_EXPR: case VEC_WIDEN_MULT_EVEN_EXPR: @@ -10356,16 +10386,10 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, scalar_int_mode int_mode; if (is_int_mode (mode, &int_mode)) { - if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (exp))) - return const_scalar_mask_from_tree (int_mode, exp); - else - { - tree type_for_mode - = lang_hooks.types.type_for_mode (int_mode, 1); - if (type_for_mode) - tmp = fold_unary_loc (loc, VIEW_CONVERT_EXPR, - type_for_mode, exp); - } + tree type_for_mode = lang_hooks.types.type_for_mode (int_mode, 1); + if (type_for_mode) + tmp = fold_unary_loc (loc, VIEW_CONVERT_EXPR, + type_for_mode, exp); } if (!tmp) { @@ -11607,111 +11631,6 @@ is_aligning_offset (const_tree offset, const_tree exp) return TREE_CODE (offset) == ADDR_EXPR && TREE_OPERAND (offset, 0) == exp; } -/* If EXPR is a constant initializer (either an expression or CONSTRUCTOR), - attempt to obtain its native representation as an array of nonzero BYTES. - Return true on success and false on failure (the latter without modifying - BYTES). */ - -static bool -convert_to_bytes (tree type, tree expr, vec<unsigned char> *bytes) -{ - if (TREE_CODE (expr) == CONSTRUCTOR) - { - /* Set to the size of the CONSTRUCTOR elements. */ - unsigned HOST_WIDE_INT ctor_size = bytes->length (); - - if (TREE_CODE (type) == ARRAY_TYPE) - { - tree val, idx; - tree eltype = TREE_TYPE (type); - unsigned HOST_WIDE_INT elsize = - tree_to_uhwi (TYPE_SIZE_UNIT (eltype)); - - /* Jump through hoops to determine the lower bound for languages - like Ada that can set it to an (almost) arbitrary value. */ - tree dom = TYPE_DOMAIN (type); - if (!dom) - return false; - tree min = TYPE_MIN_VALUE (dom); - if (!min || !tree_fits_uhwi_p (min)) - return false; - unsigned HOST_WIDE_INT i, last_idx = tree_to_uhwi (min) - 1; - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, idx, val) - { - /* Append zeros for elements with no initializers. */ - if (!tree_fits_uhwi_p (idx)) - return false; - unsigned HOST_WIDE_INT cur_idx = tree_to_uhwi (idx); - if (unsigned HOST_WIDE_INT size = cur_idx - (last_idx + 1)) - { - size = size * elsize + bytes->length (); - bytes->safe_grow_cleared (size, true); - } - - if (!convert_to_bytes (eltype, val, bytes)) - return false; - - last_idx = cur_idx; - } - } - else if (TREE_CODE (type) == RECORD_TYPE) - { - tree val, fld; - unsigned HOST_WIDE_INT i; - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, fld, val) - { - /* Append zeros for members with no initializers and - any padding. */ - unsigned HOST_WIDE_INT cur_off = int_byte_position (fld); - if (bytes->length () < cur_off) - bytes->safe_grow_cleared (cur_off, true); - - if (!convert_to_bytes (TREE_TYPE (val), val, bytes)) - return false; - } - } - else - return false; - - /* Compute the size of the COSNTRUCTOR elements. */ - ctor_size = bytes->length () - ctor_size; - - /* Append zeros to the byte vector to the full size of the type. - The type size can be less than the size of the CONSTRUCTOR - if the latter contains initializers for a flexible array - member. */ - tree size = TYPE_SIZE_UNIT (type); - unsigned HOST_WIDE_INT type_size = tree_to_uhwi (size); - if (ctor_size < type_size) - if (unsigned HOST_WIDE_INT size_grow = type_size - ctor_size) - bytes->safe_grow_cleared (bytes->length () + size_grow, true); - - return true; - } - - /* Except for RECORD_TYPE which may have an initialized flexible array - member, the size of a type is the same as the size of the initializer - (including any implicitly zeroed out members and padding). Allocate - just enough for that many bytes. */ - tree expr_size = TYPE_SIZE_UNIT (TREE_TYPE (expr)); - if (!expr_size || !tree_fits_uhwi_p (expr_size)) - return false; - const unsigned HOST_WIDE_INT expr_bytes = tree_to_uhwi (expr_size); - const unsigned bytes_sofar = bytes->length (); - /* native_encode_expr can convert at most INT_MAX bytes. vec is limited - to at most UINT_MAX. */ - if (bytes_sofar + expr_bytes > INT_MAX) - return false; - - /* Unlike for RECORD_TYPE, there is no need to clear the memory since - it's completely overwritten by native_encode_expr. */ - bytes->safe_grow (bytes_sofar + expr_bytes, true); - unsigned char *pnext = bytes->begin () + bytes_sofar; - int nbytes = native_encode_expr (expr, pnext, expr_bytes, 0); - /* NBYTES is zero on failure. Otherwise it should equal EXPR_BYTES. */ - return (unsigned HOST_WIDE_INT) nbytes == expr_bytes; -} - /* Return a STRING_CST corresponding to ARG's constant initializer either if it's a string constant, or, when VALREP is set, any other constant, or null otherwise. @@ -11724,7 +11643,7 @@ static tree constant_byte_string (tree arg, tree *ptr_offset, tree *mem_size, tree *decl, bool valrep = false) { - tree dummy = NULL_TREE;; + tree dummy = NULL_TREE; if (!mem_size) mem_size = &dummy; @@ -11879,18 +11798,42 @@ constant_byte_string (tree arg, tree *ptr_offset, tree *mem_size, tree *decl, if (!base_off.is_constant (&cstoff)) return NULL_TREE; + /* Check that the host and target are sane. */ + if (CHAR_BIT != 8 || BITS_PER_UNIT != 8) + return NULL_TREE; + + HOST_WIDE_INT typesz = int_size_in_bytes (TREE_TYPE (init)); + if (typesz <= 0 || (int) typesz != typesz) + return NULL_TREE; + + HOST_WIDE_INT size = typesz; + if (VAR_P (array) + && DECL_SIZE_UNIT (array) + && tree_fits_shwi_p (DECL_SIZE_UNIT (array))) + { + size = tree_to_shwi (DECL_SIZE_UNIT (array)); + gcc_checking_assert (size >= typesz); + } + /* If value representation was requested convert the initializer for the whole array or object into a string of bytes forming its value representation and return it. */ - auto_vec<unsigned char> bytes; - if (!convert_to_bytes (TREE_TYPE (init), init, &bytes)) - return NULL_TREE; + unsigned char *bytes = XNEWVEC (unsigned char, size); + int r = native_encode_initializer (init, bytes, size); + if (r < typesz) + { + XDELETEVEC (bytes); + return NULL_TREE; + } + + if (r < size) + memset (bytes + r, '\0', size - r); - unsigned n = bytes.length (); - const char *p = reinterpret_cast<const char *>(bytes.address ()); - init = build_string_literal (n, p, char_type_node); + const char *p = reinterpret_cast<const char *>(bytes); + init = build_string_literal (size, p, char_type_node); init = TREE_OPERAND (init, 0); init = TREE_OPERAND (init, 0); + XDELETE (bytes); *mem_size = size_int (TREE_STRING_LENGTH (init)); *ptr_offset = wide_int_to_tree (ssizetype, base_off); @@ -11941,6 +11884,10 @@ constant_byte_string (tree arg, tree *ptr_offset, tree *mem_size, tree *decl, && (TREE_CODE (TREE_TYPE (array)) == INTEGER_TYPE || TYPE_MAIN_VARIANT (inittype) == char_type_node)) { + /* Check that the host and target are sane. */ + if (CHAR_BIT != 8 || BITS_PER_UNIT != 8) + return NULL_TREE; + /* For a reference to (address of) a single constant character, store the native representation of the character in CHARBUF. If the reference is to an element of an array or a member @@ -11983,6 +11930,9 @@ constant_byte_string (tree arg, tree *ptr_offset, tree *mem_size, tree *decl, initsize = integer_zero_node; unsigned HOST_WIDE_INT size = tree_to_uhwi (initsize); + if (size > (unsigned HOST_WIDE_INT) INT_MAX) + return NULL_TREE; + init = build_string_literal (size, NULL, chartype, size); init = TREE_OPERAND (init, 0); init = TREE_OPERAND (init, 0); @@ -12739,30 +12689,6 @@ const_vector_mask_from_tree (tree exp) return builder.build (); } -/* EXP is a VECTOR_CST in which each element is either all-zeros or all-ones. - Return a constant scalar rtx of mode MODE in which bit X is set if element - X of EXP is nonzero. */ -static rtx -const_scalar_mask_from_tree (scalar_int_mode mode, tree exp) -{ - wide_int res = wi::zero (GET_MODE_PRECISION (mode)); - tree elt; - - /* The result has a fixed number of bits so the input must too. */ - unsigned int nunits = VECTOR_CST_NELTS (exp).to_constant (); - for (unsigned int i = 0; i < nunits; ++i) - { - elt = VECTOR_CST_ELT (exp, i); - gcc_assert (TREE_CODE (elt) == INTEGER_CST); - if (integer_all_onesp (elt)) - res = wi::set_bit (res, i); - else - gcc_assert (integer_zerop (elt)); - } - - return immed_wide_int_const (res, mode); -} - /* Return a CONST_VECTOR rtx for a VECTOR_CST tree. */ static rtx const_vector_from_tree (tree exp) |