diff options
author | Richard Sandiford <rsandifo@gcc.gnu.org> | 2011-07-13 11:16:36 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2011-07-13 11:16:36 +0000 |
commit | 953d0c90a2f0a98b6d860ecfbf1bc5672653a588 (patch) | |
tree | b416f9a74ed2aeda3b26a2a7af943a1535790bb3 /gcc/expr.c | |
parent | 9111c715537d8ea0829d6ab7511017ed8658f303 (diff) | |
download | gcc-953d0c90a2f0a98b6d860ecfbf1bc5672653a588.zip gcc-953d0c90a2f0a98b6d860ecfbf1bc5672653a588.tar.gz gcc-953d0c90a2f0a98b6d860ecfbf1bc5672653a588.tar.bz2 |
tree.h (categorize_ctor_elements): Remove comment.
gcc/
* tree.h (categorize_ctor_elements): Remove comment. Fix long line.
(count_type_elements): Delete.
(complete_ctor_at_level_p): Declare.
* expr.c (flexible_array_member_p): New function, split out from...
(count_type_elements): ...here. Make static. Replace allow_flexarr
parameter with for_ctor_p. When for_ctor_p is true, return the
number of elements that should appear in the top-level constructor,
otherwise return an estimate of the number of scalars.
(categorize_ctor_elements): Replace p_must_clear with p_complete.
(categorize_ctor_elements_1): Likewise. Use complete_ctor_at_level_p.
(complete_ctor_at_level_p): New function, borrowing union logic
from old categorize_ctor_elements_1.
(mostly_zeros_p): Return true if the constructor is not complete.
(all_zeros_p): Update call to categorize_ctor_elements.
* gimplify.c (gimplify_init_constructor): Update call to
categorize_ctor_elements. Don't call count_type_elements.
Unconditionally prevent clearing for variable-sized types,
otherwise rely on categorize_ctor_elements to detect
incomplete initializers.
gcc/cp/
* typeck2.c (split_nonconstant_init_1): Pass the initializer directly,
rather than a pointer to it. Return true if the whole of the value
was initialized by the generated statements. Use
complete_ctor_at_level_p instead of count_type_elements.
gcc/testsuite/
2011-07-12 Chung-Lin Tang <cltang@codesourcery.com>
* gcc.target/arm/pr48183.c: New test.
From-SVN: r176228
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 334 |
1 files changed, 178 insertions, 156 deletions
@@ -4846,16 +4846,136 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) return NULL_RTX; } +/* Return true if field F of structure TYPE is a flexible array. */ + +static bool +flexible_array_member_p (const_tree f, const_tree type) +{ + const_tree tf; + + tf = TREE_TYPE (f); + return (DECL_CHAIN (f) == NULL + && TREE_CODE (tf) == ARRAY_TYPE + && TYPE_DOMAIN (tf) + && TYPE_MIN_VALUE (TYPE_DOMAIN (tf)) + && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf))) + && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf)) + && int_size_in_bytes (type) >= 0); +} + +/* If FOR_CTOR_P, return the number of top-level elements that a constructor + must have in order for it to completely initialize a value of type TYPE. + Return -1 if the number isn't known. + + If !FOR_CTOR_P, return an estimate of the number of scalars in TYPE. */ + +static HOST_WIDE_INT +count_type_elements (const_tree type, bool for_ctor_p) +{ + switch (TREE_CODE (type)) + { + case ARRAY_TYPE: + { + tree nelts; + + nelts = array_type_nelts (type); + if (nelts && host_integerp (nelts, 1)) + { + unsigned HOST_WIDE_INT n; + + n = tree_low_cst (nelts, 1) + 1; + if (n == 0 || for_ctor_p) + return n; + else + return n * count_type_elements (TREE_TYPE (type), false); + } + return for_ctor_p ? -1 : 1; + } + + case RECORD_TYPE: + { + unsigned HOST_WIDE_INT n; + tree f; + + n = 0; + for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f)) + if (TREE_CODE (f) == FIELD_DECL) + { + if (!for_ctor_p) + n += count_type_elements (TREE_TYPE (f), false); + else if (!flexible_array_member_p (f, type)) + /* Don't count flexible arrays, which are not supposed + to be initialized. */ + n += 1; + } + + return n; + } + + case UNION_TYPE: + case QUAL_UNION_TYPE: + { + tree f; + HOST_WIDE_INT n, m; + + gcc_assert (!for_ctor_p); + /* Estimate the number of scalars in each field and pick the + maximum. Other estimates would do instead; the idea is simply + to make sure that the estimate is not sensitive to the ordering + of the fields. */ + n = 1; + for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f)) + if (TREE_CODE (f) == FIELD_DECL) + { + m = count_type_elements (TREE_TYPE (f), false); + /* If the field doesn't span the whole union, add an extra + scalar for the rest. */ + if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (f)), + TYPE_SIZE (type)) != 1) + m++; + if (n < m) + n = m; + } + return n; + } + + case COMPLEX_TYPE: + return 2; + + case VECTOR_TYPE: + return TYPE_VECTOR_SUBPARTS (type); + + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case POINTER_TYPE: + case OFFSET_TYPE: + case REFERENCE_TYPE: + return 1; + + case ERROR_MARK: + return 0; + + case VOID_TYPE: + case METHOD_TYPE: + case FUNCTION_TYPE: + case LANG_TYPE: + default: + gcc_unreachable (); + } +} + /* Helper for categorize_ctor_elements. Identical interface. */ static bool categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, - HOST_WIDE_INT *p_elt_count, - bool *p_must_clear) + HOST_WIDE_INT *p_init_elts, bool *p_complete) { unsigned HOST_WIDE_INT idx; - HOST_WIDE_INT nz_elts, elt_count; - tree value, purpose; + HOST_WIDE_INT nz_elts, init_elts, num_fields; + tree value, purpose, elt_type; /* Whether CTOR is a valid constant initializer, in accordance with what initializer_constant_valid_p does. If inferred from the constructor @@ -4864,7 +4984,9 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, bool const_p = const_from_elts_p ? true : TREE_STATIC (ctor); nz_elts = 0; - elt_count = 0; + init_elts = 0; + num_fields = 0; + elt_type = NULL_TREE; FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value) { @@ -4879,6 +5001,8 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, mult = (tree_low_cst (hi_index, 1) - tree_low_cst (lo_index, 1) + 1); } + num_fields += mult; + elt_type = TREE_TYPE (value); switch (TREE_CODE (value)) { @@ -4886,11 +5010,11 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, { HOST_WIDE_INT nz = 0, ic = 0; - bool const_elt_p - = categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear); + bool const_elt_p = categorize_ctor_elements_1 (value, &nz, &ic, + p_complete); nz_elts += mult * nz; - elt_count += mult * ic; + init_elts += mult * ic; if (const_from_elts_p && const_p) const_p = const_elt_p; @@ -4902,12 +5026,12 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, case FIXED_CST: if (!initializer_zerop (value)) nz_elts += mult; - elt_count += mult; + init_elts += mult; break; case STRING_CST: nz_elts += mult * TREE_STRING_LENGTH (value); - elt_count += mult * TREE_STRING_LENGTH (value); + init_elts += mult * TREE_STRING_LENGTH (value); break; case COMPLEX_CST: @@ -4915,7 +5039,7 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, nz_elts += mult; if (!initializer_zerop (TREE_IMAGPART (value))) nz_elts += mult; - elt_count += mult; + init_elts += mult; break; case VECTOR_CST: @@ -4925,65 +5049,31 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, { if (!initializer_zerop (TREE_VALUE (v))) nz_elts += mult; - elt_count += mult; + init_elts += mult; } } break; default: { - HOST_WIDE_INT tc = count_type_elements (TREE_TYPE (value), true); - if (tc < 1) - tc = 1; + HOST_WIDE_INT tc = count_type_elements (elt_type, false); nz_elts += mult * tc; - elt_count += mult * tc; + init_elts += mult * tc; if (const_from_elts_p && const_p) - const_p = initializer_constant_valid_p (value, TREE_TYPE (value)) + const_p = initializer_constant_valid_p (value, elt_type) != NULL_TREE; } break; } } - if (!*p_must_clear - && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE - || TREE_CODE (TREE_TYPE (ctor)) == QUAL_UNION_TYPE)) - { - tree init_sub_type; - bool clear_this = true; - - if (!VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor))) - { - /* We don't expect more than one element of the union to be - initialized. Not sure what we should do otherwise... */ - gcc_assert (VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ctor)) - == 1); - - init_sub_type = TREE_TYPE (VEC_index (constructor_elt, - CONSTRUCTOR_ELTS (ctor), - 0)->value); - - /* ??? We could look at each element of the union, and find the - largest element. Which would avoid comparing the size of the - initialized element against any tail padding in the union. - Doesn't seem worth the effort... */ - if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)), - TYPE_SIZE (init_sub_type)) == 1) - { - /* And now we have to find out if the element itself is fully - constructed. E.g. for union { struct { int a, b; } s; } u - = { .s = { .a = 1 } }. */ - if (elt_count == count_type_elements (init_sub_type, false)) - clear_this = false; - } - } - - *p_must_clear = clear_this; - } + if (*p_complete && !complete_ctor_at_level_p (TREE_TYPE (ctor), + num_fields, elt_type)) + *p_complete = false; *p_nz_elts += nz_elts; - *p_elt_count += elt_count; + *p_init_elts += init_elts; return const_p; } @@ -4993,111 +5083,50 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, and place it in *P_NZ_ELTS; * how many scalar fields in total are in CTOR, and place it in *P_ELT_COUNT. - * if a type is a union, and the initializer from the constructor - is not the largest element in the union, then set *p_must_clear. + * whether the constructor is complete -- in the sense that every + meaningful byte is explicitly given a value -- + and place it in *P_COMPLETE. Return whether or not CTOR is a valid static constant initializer, the same as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0". */ bool categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts, - HOST_WIDE_INT *p_elt_count, - bool *p_must_clear) + HOST_WIDE_INT *p_init_elts, bool *p_complete) { *p_nz_elts = 0; - *p_elt_count = 0; - *p_must_clear = false; + *p_init_elts = 0; + *p_complete = true; - return - categorize_ctor_elements_1 (ctor, p_nz_elts, p_elt_count, p_must_clear); + return categorize_ctor_elements_1 (ctor, p_nz_elts, p_init_elts, p_complete); } -/* Count the number of scalars in TYPE. Return -1 on overflow or - variable-sized. If ALLOW_FLEXARR is true, don't count flexible - array member at the end of the structure. */ +/* TYPE is initialized by a constructor with NUM_ELTS elements, the last + of which had type LAST_TYPE. Each element was itself a complete + initializer, in the sense that every meaningful byte was explicitly + given a value. Return true if the same is true for the constructor + as a whole. */ -HOST_WIDE_INT -count_type_elements (const_tree type, bool allow_flexarr) +bool +complete_ctor_at_level_p (const_tree type, HOST_WIDE_INT num_elts, + const_tree last_type) { - const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1)); - switch (TREE_CODE (type)) + if (TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) { - case ARRAY_TYPE: - { - tree telts = array_type_nelts (type); - if (telts && host_integerp (telts, 1)) - { - HOST_WIDE_INT n = tree_low_cst (telts, 1) + 1; - HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type), false); - if (n == 0) - return 0; - else if (max / n > m) - return n * m; - } - return -1; - } - - case RECORD_TYPE: - { - HOST_WIDE_INT n = 0, t; - tree f; - - for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f)) - if (TREE_CODE (f) == FIELD_DECL) - { - t = count_type_elements (TREE_TYPE (f), false); - if (t < 0) - { - /* Check for structures with flexible array member. */ - tree tf = TREE_TYPE (f); - if (allow_flexarr - && DECL_CHAIN (f) == NULL - && TREE_CODE (tf) == ARRAY_TYPE - && TYPE_DOMAIN (tf) - && TYPE_MIN_VALUE (TYPE_DOMAIN (tf)) - && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf))) - && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf)) - && int_size_in_bytes (type) >= 0) - break; - - return -1; - } - n += t; - } - - return n; - } - - case UNION_TYPE: - case QUAL_UNION_TYPE: - return -1; - - case COMPLEX_TYPE: - return 2; - - case VECTOR_TYPE: - return TYPE_VECTOR_SUBPARTS (type); - - case INTEGER_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - case ENUMERAL_TYPE: - case BOOLEAN_TYPE: - case POINTER_TYPE: - case OFFSET_TYPE: - case REFERENCE_TYPE: - return 1; + if (num_elts == 0) + return false; - case ERROR_MARK: - return 0; + gcc_assert (num_elts == 1 && last_type); - case VOID_TYPE: - case METHOD_TYPE: - case FUNCTION_TYPE: - case LANG_TYPE: - default: - gcc_unreachable (); + /* ??? We could look at each element of the union, and find the + largest element. Which would avoid comparing the size of the + initialized element against any tail padding in the union. + Doesn't seem worth the effort... */ + return simple_cst_equal (TYPE_SIZE (type), TYPE_SIZE (last_type)) == 1; } + + return count_type_elements (type, true) == num_elts; } /* Return 1 if EXP contains mostly (3/4) zeros. */ @@ -5106,18 +5135,12 @@ static int mostly_zeros_p (const_tree exp) { if (TREE_CODE (exp) == CONSTRUCTOR) - { - HOST_WIDE_INT nz_elts, count, elts; - bool must_clear; - - categorize_ctor_elements (exp, &nz_elts, &count, &must_clear); - if (must_clear) - return 1; + HOST_WIDE_INT nz_elts, init_elts; + bool complete_p; - elts = count_type_elements (TREE_TYPE (exp), false); - - return nz_elts < elts / 4; + categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p); + return !complete_p || nz_elts < init_elts / 4; } return initializer_zerop (exp); @@ -5129,13 +5152,12 @@ static int all_zeros_p (const_tree exp) { if (TREE_CODE (exp) == CONSTRUCTOR) - { - HOST_WIDE_INT nz_elts, count; - bool must_clear; + HOST_WIDE_INT nz_elts, init_elts; + bool complete_p; - categorize_ctor_elements (exp, &nz_elts, &count, &must_clear); - return nz_elts == 0; + categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p); + return nz_elts == init_elts; } return initializer_zerop (exp); |