/* C-compiler utilities for types and variables storage layout
- Copyright (C) 1987-2018 Free Software Foundation, Inc.
+ Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GCC.
#include "gimplify.h"
#include "attribs.h"
#include "debug.h"
+#include "calls.h"
/* Data type for the expressions representing sizes of data types.
It is the first integer type laid out. */
case MODE_VECTOR_ACCUM:
case MODE_VECTOR_UFRACT:
case MODE_VECTOR_UACCUM:
- case MODE_POINTER_BOUNDS:
return int_mode_for_size (GET_MODE_BITSIZE (mode), 0);
+ case MODE_OPAQUE:
+ return opt_scalar_int_mode ();
+
case MODE_RANDOM:
if (mode == BLKmode)
return opt_scalar_int_mode ();
return opt_machine_mode ();
}
-/* Return the mode for a vector that has NUNITS integer elements of
- INT_BITS bits each, if such a mode exists. The mode can be either
- an integer mode or a vector mode. */
+/* If a piece of code is using vector mode VECTOR_MODE and also wants
+ to operate on elements of mode ELEMENT_MODE, return the vector mode
+ it should use for those elements. If NUNITS is nonzero, ensure that
+ the mode has exactly NUNITS elements, otherwise pick whichever vector
+ size pairs the most naturally with VECTOR_MODE; this may mean choosing
+ a mode with a different size and/or number of elements, depending on
+ what the target prefers. Return an empty opt_machine_mode if there
+ is no supported vector mode with the required properties.
+
+ Unlike mode_for_vector. any returned mode is guaranteed to satisfy
+ both VECTOR_MODE_P and targetm.vector_mode_supported_p. */
+
+opt_machine_mode
+related_vector_mode (machine_mode vector_mode, scalar_mode element_mode,
+ poly_uint64 nunits)
+{
+ gcc_assert (VECTOR_MODE_P (vector_mode));
+ return targetm.vectorize.related_mode (vector_mode, element_mode, nunits);
+}
+
+/* If a piece of code is using vector mode VECTOR_MODE and also wants
+ to operate on integer vectors with the same element size and number
+ of elements, return the vector mode it should use. Return an empty
+ opt_machine_mode if there is no supported vector mode with the
+ required properties.
+
+ Unlike mode_for_vector. any returned mode is guaranteed to satisfy
+ both VECTOR_MODE_P and targetm.vector_mode_supported_p. */
opt_machine_mode
-mode_for_int_vector (unsigned int int_bits, poly_uint64 nunits)
+related_int_vector_mode (machine_mode vector_mode)
{
+ gcc_assert (VECTOR_MODE_P (vector_mode));
scalar_int_mode int_mode;
- machine_mode vec_mode;
- if (int_mode_for_size (int_bits, 0).exists (&int_mode)
- && mode_for_vector (int_mode, nunits).exists (&vec_mode))
- return vec_mode;
+ if (int_mode_for_mode (GET_MODE_INNER (vector_mode)).exists (&int_mode))
+ return related_vector_mode (vector_mode, int_mode,
+ GET_MODE_NUNITS (vector_mode));
return opt_machine_mode ();
}
DECL_SIZE_UNIT (decl) = variable_size (DECL_SIZE_UNIT (decl));
/* If requested, warn about definitions of large data objects. */
- if (warn_larger_than
- && (code == VAR_DECL || code == PARM_DECL)
- && ! DECL_EXTERNAL (decl))
+ if ((code == PARM_DECL || (code == VAR_DECL && !DECL_NONLOCAL_FRAME (decl)))
+ && !DECL_EXTERNAL (decl))
{
tree size = DECL_SIZE_UNIT (decl);
- if (size != 0 && TREE_CODE (size) == INTEGER_CST
- && compare_tree_int (size, larger_than_size) > 0)
+ if (size != 0 && TREE_CODE (size) == INTEGER_CST)
{
- int size_as_int = TREE_INT_CST_LOW (size);
-
- if (compare_tree_int (size, size_as_int) == 0)
- warning (OPT_Wlarger_than_, "size of %q+D is %d bytes", decl, size_as_int);
- else
- warning (OPT_Wlarger_than_, "size of %q+D is larger than %wd bytes",
- decl, larger_than_size);
+ /* -Wlarger-than= argument of HOST_WIDE_INT_MAX is treated
+ as if PTRDIFF_MAX had been specified, with the value
+ being that on the target rather than the host. */
+ unsigned HOST_WIDE_INT max_size = warn_larger_than_size;
+ if (max_size == HOST_WIDE_INT_MAX)
+ max_size = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node));
+
+ if (compare_tree_int (size, max_size) > 0)
+ warning (OPT_Wlarger_than_, "size of %q+D %E bytes exceeds "
+ "maximum object size %wu",
+ decl, size, max_size);
}
}
Bump the cumulative size to multiple of field alignment. */
if (!targetm.ms_bitfield_layout_p (rli->t)
- && DECL_SOURCE_LOCATION (field) != BUILTINS_LOCATION)
+ && DECL_SOURCE_LOCATION (field) != BUILTINS_LOCATION
+ && !TYPE_ARTIFICIAL (rli->t))
warning (OPT_Wpadded, "padding struct to align %q+D", field);
/* If the alignment is still within offset_align, just align
{
rli->bitpos = size_binop (PLUS_EXPR, rli->bitpos, DECL_SIZE (field));
- /* If we ended a bitfield before the full length of the type then
- pad the struct out to the full length of the last type. */
- if ((DECL_CHAIN (field) == NULL
- || TREE_CODE (DECL_CHAIN (field)) != FIELD_DECL)
- && DECL_BIT_FIELD_TYPE (field)
+ /* If FIELD is the last field and doesn't end at the full length
+ of the type then pad the struct out to the full length of the
+ last type. */
+ if (DECL_BIT_FIELD_TYPE (field)
&& !integer_zerop (DECL_SIZE (field)))
- rli->bitpos = size_binop (PLUS_EXPR, rli->bitpos,
- bitsize_int (rli->remaining_in_alignment));
+ {
+ /* We have to scan, because non-field DECLS are also here. */
+ tree probe = field;
+ while ((probe = DECL_CHAIN (probe)))
+ if (TREE_CODE (probe) == FIELD_DECL)
+ break;
+ if (!probe)
+ rli->bitpos = size_binop (PLUS_EXPR, rli->bitpos,
+ bitsize_int (rli->remaining_in_alignment));
+ }
normalize_rli (rli);
}
if (TREE_CONSTANT (unpadded_size)
&& simple_cst_equal (unpadded_size, TYPE_SIZE (rli->t)) == 0
- && input_location != BUILTINS_LOCATION)
+ && input_location != BUILTINS_LOCATION
+ && !TYPE_ARTIFICIAL (rli->t))
warning (OPT_Wpadded, "padding struct size to alignment boundary");
if (warn_packed && TREE_CODE (rli->t) == RECORD_TYPE
line. */
SET_TYPE_MODE (type, BLKmode);
- if (! tree_fits_uhwi_p (TYPE_SIZE (type)))
+ poly_uint64 type_size;
+ if (!poly_int_tree_p (TYPE_SIZE (type), &type_size))
return;
/* A record which has any BLKmode members must itself be
if (TREE_CODE (field) != FIELD_DECL)
continue;
+ poly_uint64 field_size;
if (TREE_CODE (TREE_TYPE (field)) == ERROR_MARK
|| (TYPE_MODE (TREE_TYPE (field)) == BLKmode
&& ! TYPE_NO_FORCE_BLK (TREE_TYPE (field))
&& !(TYPE_SIZE (TREE_TYPE (field)) != 0
&& integer_zerop (TYPE_SIZE (TREE_TYPE (field)))))
- || ! tree_fits_uhwi_p (bit_position (field))
+ || !tree_fits_poly_uint64_p (bit_position (field))
|| DECL_SIZE (field) == 0
- || ! tree_fits_uhwi_p (DECL_SIZE (field)))
+ || !poly_int_tree_p (DECL_SIZE (field), &field_size))
return;
/* If this field is the whole struct, remember its mode so
that, say, we can put a double in a class into a DF
register instead of forcing it to live in the stack. */
- if (simple_cst_equal (TYPE_SIZE (type), DECL_SIZE (field)))
+ if (known_eq (field_size, type_size)
+ /* Partial int types (e.g. __int20) may have TYPE_SIZE equal to
+ wider types (e.g. int32), despite precision being less. Ensure
+ that the TYPE_MODE of the struct does not get set to the partial
+ int mode if there is a wider type also in the struct. */
+ && known_gt (GET_MODE_PRECISION (DECL_MODE (field)),
+ GET_MODE_PRECISION (mode)))
mode = DECL_MODE (field);
/* With some targets, it is sub-optimal to access an aligned
}
/* If we only have one real field; use its mode if that mode's size
- matches the type's size. This only applies to RECORD_TYPE. This
- does not apply to unions. */
- poly_uint64 type_size;
- if (TREE_CODE (type) == RECORD_TYPE
+ matches the type's size. This generally only applies to RECORD_TYPE.
+ For UNION_TYPE, if the widest field is MODE_INT then use that mode.
+ If the widest field is MODE_PARTIAL_INT, and the union will be passed
+ by reference, then use that mode. */
+ if ((TREE_CODE (type) == RECORD_TYPE
+ || (TREE_CODE (type) == UNION_TYPE
+ && (GET_MODE_CLASS (mode) == MODE_INT
+ || (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT
+ && (targetm.calls.pass_by_reference
+ (pack_cumulative_args (0),
+ function_arg_info (type, mode, /*named=*/false)))))))
&& mode != VOIDmode
- && poly_int_tree_p (TYPE_SIZE (type), &type_size)
&& known_eq (GET_MODE_BITSIZE (mode), type_size))
;
else
/* If TYPE_SIZE_UNIT overflowed, then it is certainly larger than
TYPE_ALIGN_UNIT. */
&& !TREE_OVERFLOW (TYPE_SIZE_UNIT (element))
- && !integer_zerop (TYPE_SIZE_UNIT (element))
- && compare_tree_int (TYPE_SIZE_UNIT (element),
- TYPE_ALIGN_UNIT (element)) < 0)
- error ("alignment of array elements is greater than element size");
+ && !integer_zerop (TYPE_SIZE_UNIT (element)))
+ {
+ if (compare_tree_int (TYPE_SIZE_UNIT (element),
+ TYPE_ALIGN_UNIT (element)) < 0)
+ error ("alignment of array elements is greater than "
+ "element size");
+ else if (TYPE_ALIGN_UNIT (element) > 1
+ && (wi::zext (wi::to_wide (TYPE_SIZE_UNIT (element)),
+ ffs_hwi (TYPE_ALIGN_UNIT (element)) - 1)
+ != 0))
+ error ("size of array element is not a multiple of its "
+ "alignment");
+ }
break;
}
for (i = 0; i < NUM_INT_N_ENTS; i++)
if (int_n_enabled_p[i])
{
- char name[50];
+ char name[50], altname[50];
sprintf (name, "__int%d unsigned", int_n_data[i].bitsize);
+ sprintf (altname, "__int%d__ unsigned", int_n_data[i].bitsize);
- if (strcmp (name, SIZETYPE) == 0)
+ if (strcmp (name, SIZETYPE) == 0
+ || strcmp (altname, SIZETYPE) == 0)
{
precision = int_n_data[i].bitsize;
}