/* C-compiler utilities for types and variables storage layout
- Copyright (C) 1987-2014 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "stor-layout.h"
#include "stringpool.h"
#include "varasm.h"
#include "rtl.h"
#include "tm_p.h"
#include "flags.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
#include "hard-reg-set.h"
-#include "input.h"
#include "function.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
#include "expr.h"
#include "diagnostic-core.h"
#include "target.h"
static void finalize_record_size (record_layout_info);
static void finalize_type_size (tree);
static void place_union_field (record_layout_info, tree);
-#if defined (PCC_BITFIELD_TYPE_MATTERS) || defined (BITFIELD_NBYTES_LIMITED)
static int excess_unit_span (HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, tree);
-#endif
extern void debug_rli (record_layout_info);
\f
/* Show that REFERENCE_TYPES are internal and should use address_mode.
/* An array of functions used for self-referential size computation. */
static GTY(()) vec<tree, va_gc> *size_functions;
+/* Return true if T is a self-referential component reference. */
+
+static bool
+self_referential_component_ref_p (tree t)
+{
+ if (TREE_CODE (t) != COMPONENT_REF)
+ return false;
+
+ while (REFERENCE_CLASS_P (t))
+ t = TREE_OPERAND (t, 0);
+
+ return (TREE_CODE (t) == PLACEHOLDER_EXPR);
+}
+
/* Similar to copy_tree_r but do not copy component references involving
PLACEHOLDER_EXPRs. These nodes are spotted in find_placeholder_in_expr
and substituted in substitute_in_expr. */
}
/* Default case: the component reference. */
- else if (code == COMPONENT_REF)
+ else if (self_referential_component_ref_p (*tp))
{
- tree inner;
- for (inner = TREE_OPERAND (*tp, 0);
- REFERENCE_CLASS_P (inner);
- inner = TREE_OPERAND (inner, 0))
- ;
-
- if (TREE_CODE (inner) == PLACEHOLDER_EXPR)
- {
- *walk_subtrees = 0;
- return NULL_TREE;
- }
+ *walk_subtrees = 0;
+ return NULL_TREE;
}
/* We're not supposed to have them in self-referential size trees
/* Do not factor out simple operations. */
t = skip_simple_constant_arithmetic (size);
- if (TREE_CODE (t) == CALL_EXPR)
+ if (TREE_CODE (t) == CALL_EXPR || self_referential_component_ref_p (t))
return size;
/* Collect the list of self-references in the expression. */
fntype = build_function_type (return_type, param_type_list);
/* Build the function declaration. */
- sprintf (buf, "SZ"HOST_WIDE_INT_PRINT_UNSIGNED, fnno++);
+ sprintf (buf, "SZ" HOST_WIDE_INT_PRINT_UNSIGNED, fnno++);
fnname = get_file_function_name (buf);
fndecl = build_decl (input_location, FUNCTION_DECL, fnname, fntype);
for (t = param_decl_list; t; t = DECL_CHAIN (t))
set_cfun (NULL);
dump_function (TDI_original, fndecl);
gimplify_function_tree (fndecl);
- dump_function (TDI_generic, fndecl);
cgraph_node::finalize_function (fndecl, false);
}
it may have padding as well. If LIMIT is nonzero, modes of wider
than MAX_FIXED_MODE_SIZE will not be used. */
-enum machine_mode
+machine_mode
mode_for_size (unsigned int size, enum mode_class mclass, int limit)
{
- enum machine_mode mode;
+ machine_mode mode;
int i;
if (limit && size > MAX_FIXED_MODE_SIZE)
/* Similar, except passed a tree node. */
-enum machine_mode
+machine_mode
mode_for_size_tree (const_tree size, enum mode_class mclass, int limit)
{
unsigned HOST_WIDE_INT uhwi;
/* Similar, but never return BLKmode; return the narrowest mode that
contains at least the requested number of value bits. */
-enum machine_mode
+machine_mode
smallest_mode_for_size (unsigned int size, enum mode_class mclass)
{
- enum machine_mode mode = VOIDmode;
+ machine_mode mode = VOIDmode;
int i;
/* Get the first mode which has at least this size, in the
/* Find an integer mode of the exact same size, or BLKmode on failure. */
-enum machine_mode
-int_mode_for_mode (enum machine_mode mode)
+machine_mode
+int_mode_for_mode (machine_mode mode)
{
switch (GET_MODE_CLASS (mode))
{
case MODE_VECTOR_ACCUM:
case MODE_VECTOR_UFRACT:
case MODE_VECTOR_UACCUM:
+ case MODE_POINTER_BOUNDS:
mode = mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 0);
break;
/* Find a mode that can be used for efficient bitwise operations on MODE.
Return BLKmode if no such mode exists. */
-enum machine_mode
-bitwise_mode_for_mode (enum machine_mode mode)
+machine_mode
+bitwise_mode_for_mode (machine_mode mode)
{
/* Quick exit if we already have a suitable mode. */
unsigned int bitsize = GET_MODE_BITSIZE (mode);
care whether there is a register for the inner mode. */
if (COMPLEX_MODE_P (mode))
{
- enum machine_mode trial = mode;
+ machine_mode trial = mode;
if (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT)
trial = mode_for_size (bitsize, MODE_COMPLEX_INT, false);
if (trial != BLKmode
modes if an integer mode would be too big. */
if (VECTOR_MODE_P (mode) || bitsize > MAX_FIXED_MODE_SIZE)
{
- enum machine_mode trial = mode;
+ machine_mode trial = mode;
if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
trial = mode_for_size (bitsize, MODE_VECTOR_INT, 0);
if (trial != BLKmode
Return null if no such mode exists. */
tree
-bitwise_type_for_mode (enum machine_mode mode)
+bitwise_type_for_mode (machine_mode mode)
{
mode = bitwise_mode_for_mode (mode);
if (mode == BLKmode)
NUNITS elements of mode INNERMODE. Returns BLKmode if there
is no suitable mode. */
-enum machine_mode
-mode_for_vector (enum machine_mode innermode, unsigned nunits)
+machine_mode
+mode_for_vector (machine_mode innermode, unsigned nunits)
{
- enum machine_mode mode;
+ machine_mode mode;
/* First, look for a supported vector type. */
if (SCALAR_FLOAT_MODE_P (innermode))
BIGGEST_ALIGNMENT. */
unsigned int
-get_mode_alignment (enum machine_mode mode)
+get_mode_alignment (machine_mode mode)
{
return MIN (BIGGEST_ALIGNMENT, MAX (1, mode_base_align[mode]*BITS_PER_UNIT));
}
precision of the mode of its elements. */
unsigned int
-element_precision (enum machine_mode mode)
+element_precision (machine_mode mode)
{
if (COMPLEX_MODE_P (mode) || VECTOR_MODE_P (mode))
mode = GET_MODE_INNER (mode);
/* Return the natural mode of an array, given that it is SIZE bytes in
total and has elements of type ELEM_TYPE. */
-static enum machine_mode
+static machine_mode
mode_for_array (tree elem_type, tree size)
{
tree elem_size;
{
zero_bitfield = true;
packed_p = false;
-#ifdef PCC_BITFIELD_TYPE_MATTERS
if (PCC_BITFIELD_TYPE_MATTERS)
do_type_align (type, decl);
else
-#endif
{
#ifdef EMPTY_FIELD_BOUNDARY
if (EMPTY_FIELD_BOUNDARY > DECL_ALIGN (decl))
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
&& GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT)
{
- enum machine_mode xmode
+ machine_mode xmode
= mode_for_size_tree (DECL_SIZE (decl), MODE_INT, 1);
unsigned int xalign = GET_MODE_ALIGNMENT (xmode);
rli->unpacked_align = MAX (rli->unpacked_align, TYPE_ALIGN (type));
}
}
-#ifdef PCC_BITFIELD_TYPE_MATTERS
else if (is_bitfield && PCC_BITFIELD_TYPE_MATTERS)
{
/* Named bit-fields cause the entire structure to have the
user_align |= TYPE_USER_ALIGN (type);
}
}
-#endif
else
{
rli->record_align = MAX (rli->record_align, desired_align);
DECL_SIZE_UNIT (field), rli->offset);
}
-#if defined (PCC_BITFIELD_TYPE_MATTERS) || defined (BITFIELD_NBYTES_LIMITED)
/* A bitfield of SIZE with a required access alignment of ALIGN is allocated
at BYTE_OFFSET / BIT_OFFSET. Return nonzero if the field would span more
units of alignment than the underlying TYPE. */
return ((offset + size + align - 1) / align
> tree_to_uhwi (TYPE_SIZE (type)) / align);
}
-#endif
/* RLI contains information about the layout of a RECORD_TYPE. FIELD
is a FIELD_DECL to be added after those fields already present in
/* Handle compatibility with PCC. Note that if the record has any
variable-sized fields, we need not worry about compatibility. */
-#ifdef PCC_BITFIELD_TYPE_MATTERS
if (PCC_BITFIELD_TYPE_MATTERS
&& ! targetm.ms_bitfield_layout_p (rli->t)
&& TREE_CODE (field) == FIELD_DECL
if (! DECL_PACKED (field))
TYPE_USER_ALIGN (rli->t) |= TYPE_USER_ALIGN (type);
}
-#endif
#ifdef BITFIELD_NBYTES_LIMITED
if (BITFIELD_NBYTES_LIMITED
unpadded_size_unit
= size_binop (PLUS_EXPR, unpadded_size_unit, size_one_node);
- if (TREE_CODE (unpadded_size_unit) == INTEGER_CST
- && !TREE_OVERFLOW (unpadded_size_unit)
- && !valid_constant_size_p (unpadded_size_unit))
- error ("type %qT is too large", rli->t);
-
/* Round the size up to be a multiple of the required alignment. */
TYPE_SIZE (rli->t) = round_up (unpadded_size, TYPE_ALIGN (rli->t));
TYPE_SIZE_UNIT (rli->t)
compute_record_mode (tree type)
{
tree field;
- enum machine_mode mode = VOIDmode;
+ machine_mode mode = VOIDmode;
/* Most RECORD_TYPEs have BLKmode, so we start off assuming that.
However, if possible, we use a mode that fits in a register
However, where strict alignment is not required, avoid
over-aligning structures, since most compilers do not do this
alignment. */
-
- if (TYPE_MODE (type) != BLKmode && TYPE_MODE (type) != VOIDmode
- && (STRICT_ALIGNMENT
- || (TREE_CODE (type) != RECORD_TYPE && TREE_CODE (type) != UNION_TYPE
- && TREE_CODE (type) != QUAL_UNION_TYPE
- && TREE_CODE (type) != ARRAY_TYPE)))
+ if (TYPE_MODE (type) != BLKmode
+ && TYPE_MODE (type) != VOIDmode
+ && (STRICT_ALIGNMENT || !AGGREGATE_TYPE_P (type)))
{
unsigned mode_align = GET_MODE_ALIGNMENT (TYPE_MODE (type));
unsigned int align = TYPE_ALIGN (type);
unsigned int precision = TYPE_PRECISION (type);
unsigned int user_align = TYPE_USER_ALIGN (type);
- enum machine_mode mode = TYPE_MODE (type);
+ machine_mode mode = TYPE_MODE (type);
/* Copy it into all variants. */
for (variant = TYPE_MAIN_VARIANT (type);
{
TYPE_SIZE (variant) = size;
TYPE_SIZE_UNIT (variant) = size_unit;
- TYPE_ALIGN (variant) = align;
+ unsigned valign = align;
+ if (TYPE_USER_ALIGN (variant))
+ valign = MAX (valign, TYPE_ALIGN (variant));
+ else
+ TYPE_USER_ALIGN (variant) = user_align;
+ TYPE_ALIGN (variant) = valign;
TYPE_PRECISION (variant) = precision;
- TYPE_USER_ALIGN (variant) = user_align;
SET_TYPE_MODE (variant, mode);
}
}
finish_bitfield_representative (tree repr, tree field)
{
unsigned HOST_WIDE_INT bitsize, maxbitsize;
- enum machine_mode mode;
+ machine_mode mode;
tree nextf, size;
size = size_diffop (DECL_FIELD_OFFSET (field),
if (type == error_mark_node)
return;
+ /* We don't want finalize_type_size to copy an alignment attribute to
+ variants that don't have it. */
+ type = TYPE_MAIN_VARIANT (type);
+
/* Do nothing if type has been laid out before. */
if (TYPE_SIZE (type))
return;
SET_TYPE_MODE (type, VOIDmode);
break;
+ case POINTER_BOUNDS_TYPE:
+ TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
+ TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
+ break;
+
case OFFSET_TYPE:
TYPE_SIZE (type) = bitsize_int (POINTER_SIZE);
TYPE_SIZE_UNIT (type) = size_int (POINTER_SIZE_UNITS);
case POINTER_TYPE:
case REFERENCE_TYPE:
{
- enum machine_mode mode = TYPE_MODE (type);
+ machine_mode mode = TYPE_MODE (type);
if (TREE_CODE (type) == REFERENCE_TYPE && reference_types_internal)
{
addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type));
/* Now round the alignment and size,
using machine-dependent criteria if any. */
+ unsigned align = TYPE_ALIGN (element);
+ if (TYPE_USER_ALIGN (type))
+ align = MAX (align, TYPE_ALIGN (type));
+ else
+ TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (element);
#ifdef ROUND_TYPE_ALIGN
- TYPE_ALIGN (type)
- = ROUND_TYPE_ALIGN (type, TYPE_ALIGN (element), BITS_PER_UNIT);
+ align = ROUND_TYPE_ALIGN (type, align, BITS_PER_UNIT);
#else
- TYPE_ALIGN (type) = MAX (TYPE_ALIGN (element), BITS_PER_UNIT);
+ align = MAX (align, BITS_PER_UNIT);
#endif
- TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (element);
+ TYPE_ALIGN (type) = align;
SET_TYPE_MODE (type, BLKmode);
if (TYPE_SIZE (type) != 0
&& ! targetm.member_type_forces_blk (type, VOIDmode)
/* Compute the final TYPE_SIZE, TYPE_ALIGN, etc. for TYPE. For
records and unions, finish_record_layout already called this
function. */
- if (TREE_CODE (type) != RECORD_TYPE
- && TREE_CODE (type) != UNION_TYPE
- && TREE_CODE (type) != QUAL_UNION_TYPE)
+ if (!RECORD_OR_UNION_TYPE_P (type))
finalize_type_size (type);
/* We should never see alias sets on incomplete aggregates. And we
min_align_of_type (tree type)
{
unsigned int align = TYPE_ALIGN (type);
- align = MIN (align, BIGGEST_ALIGNMENT);
if (!TYPE_USER_ALIGN (type))
{
+ align = MIN (align, BIGGEST_ALIGNMENT);
#ifdef BIGGEST_FIELD_ALIGNMENT
align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
#endif
referenced by a function and re-compute the TYPE_MODE once, rather
than make the TYPE_MODE macro call a function. */
-enum machine_mode
+machine_mode
vector_type_mode (const_tree t)
{
- enum machine_mode mode;
+ machine_mode mode;
gcc_assert (TREE_CODE (t) == VECTOR_TYPE);
&& (!targetm.vector_mode_supported_p (mode)
|| !have_regs_of_mode[mode]))
{
- enum machine_mode innermode = TREE_TYPE (t)->type_common.mode;
+ machine_mode innermode = TREE_TYPE (t)->type_common.mode;
/* For integers, try mapping it to a same-sized scalar mode. */
if (GET_MODE_CLASS (innermode) == MODE_INT)
available, storing it in *OUT_MODE if so. */
bool
-bit_field_mode_iterator::next_mode (enum machine_mode *out_mode)
+bit_field_mode_iterator::next_mode (machine_mode *out_mode)
{
for (; m_mode != VOIDmode; m_mode = GET_MODE_WIDER_MODE (m_mode))
{
If VOLATILEP is true the narrow_volatile_bitfields target hook is used to
decide which of the above modes should be used. */
-enum machine_mode
+machine_mode
get_best_mode (int bitsize, int bitpos,
unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end,
unsigned int align,
- enum machine_mode largest_mode, bool volatilep)
+ machine_mode largest_mode, bool volatilep)
{
bit_field_mode_iterator iter (bitsize, bitpos, bitregion_start,
bitregion_end, align, volatilep);
- enum machine_mode widest_mode = VOIDmode;
- enum machine_mode mode;
+ machine_mode widest_mode = VOIDmode;
+ machine_mode mode;
while (iter.next_mode (&mode)
/* ??? For historical reasons, reject modes that would normally
receive greater alignment, even if unaligned accesses are
SIGN). The returned constants are made to be usable in TARGET_MODE. */
void
-get_mode_bounds (enum machine_mode mode, int sign,
- enum machine_mode target_mode,
+get_mode_bounds (machine_mode mode, int sign,
+ machine_mode target_mode,
rtx *mmin, rtx *mmax)
{
unsigned size = GET_MODE_PRECISION (mode);