aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2021-01-03 21:40:04 +0100
committerThomas Koenig <tkoenig@gcc.gnu.org>2021-01-03 21:40:04 +0100
commitafae4a55ccaa0de95ea11e5f634084db6ab2f444 (patch)
treed632cc867d10410ba9fb750523be790b86846ac4 /gcc/expr.c
parent9d9a82ec8478ff52c7a9d61f58cd2a7b6295b5f9 (diff)
parentd2eb616a0f7bea78164912aa438c29fe1ef5774a (diff)
downloadgcc-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.c222
1 files changed, 74 insertions, 148 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index 9d951e8..33934d6 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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)