Commit 953d0c90 by Richard Sandiford

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
parent 9111c715
2011-07-13 Richard Sandiford <richard.sandiford@linaro.org>
* 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.
2011-07-13 Richard Guenther <rguenther@suse.de> 2011-07-13 Richard Guenther <rguenther@suse.de>
* tree-vrp.c (simplify_conversion_using_ranges): Make sure * tree-vrp.c (simplify_conversion_using_ranges): Make sure
......
2011-07-13 Richard Sandiford <richard.sandiford@linaro.org>
* 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.
2011-07-12 Diego Novillo <dnovillo@google.com> 2011-07-12 Diego Novillo <dnovillo@google.com>
* name-lookup.h (cp_binding_level): Rename from cxx_scope. * name-lookup.h (cp_binding_level): Rename from cxx_scope.
......
...@@ -481,18 +481,20 @@ cxx_incomplete_type_error (const_tree value, const_tree type) ...@@ -481,18 +481,20 @@ cxx_incomplete_type_error (const_tree value, const_tree type)
/* The recursive part of split_nonconstant_init. DEST is an lvalue /* The recursive part of split_nonconstant_init. DEST is an lvalue
expression to which INIT should be assigned. INIT is a CONSTRUCTOR. */ expression to which INIT should be assigned. INIT is a CONSTRUCTOR.
Return true if the whole of the value was initialized by the
generated statements. */
static void static bool
split_nonconstant_init_1 (tree dest, tree *initp) split_nonconstant_init_1 (tree dest, tree init)
{ {
unsigned HOST_WIDE_INT idx; unsigned HOST_WIDE_INT idx;
tree init = *initp;
tree field_index, value; tree field_index, value;
tree type = TREE_TYPE (dest); tree type = TREE_TYPE (dest);
tree inner_type = NULL; tree inner_type = NULL;
bool array_type_p = false; bool array_type_p = false;
HOST_WIDE_INT num_type_elements, num_initialized_elements; bool complete_p = true;
HOST_WIDE_INT num_split_elts = 0;
switch (TREE_CODE (type)) switch (TREE_CODE (type))
{ {
...@@ -504,7 +506,6 @@ split_nonconstant_init_1 (tree dest, tree *initp) ...@@ -504,7 +506,6 @@ split_nonconstant_init_1 (tree dest, tree *initp)
case RECORD_TYPE: case RECORD_TYPE:
case UNION_TYPE: case UNION_TYPE:
case QUAL_UNION_TYPE: case QUAL_UNION_TYPE:
num_initialized_elements = 0;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx,
field_index, value) field_index, value)
{ {
...@@ -527,13 +528,14 @@ split_nonconstant_init_1 (tree dest, tree *initp) ...@@ -527,13 +528,14 @@ split_nonconstant_init_1 (tree dest, tree *initp)
sub = build3 (COMPONENT_REF, inner_type, dest, field_index, sub = build3 (COMPONENT_REF, inner_type, dest, field_index,
NULL_TREE); NULL_TREE);
split_nonconstant_init_1 (sub, &value); if (!split_nonconstant_init_1 (sub, value))
complete_p = false;
num_split_elts++;
} }
else if (!initializer_constant_valid_p (value, inner_type)) else if (!initializer_constant_valid_p (value, inner_type))
{ {
tree code; tree code;
tree sub; tree sub;
HOST_WIDE_INT inner_elements;
/* FIXME: Ordered removal is O(1) so the whole function is /* FIXME: Ordered removal is O(1) so the whole function is
worst-case quadratic. This could be fixed using an aside worst-case quadratic. This could be fixed using an aside
...@@ -557,21 +559,9 @@ split_nonconstant_init_1 (tree dest, tree *initp) ...@@ -557,21 +559,9 @@ split_nonconstant_init_1 (tree dest, tree *initp)
code = build_stmt (input_location, EXPR_STMT, code); code = build_stmt (input_location, EXPR_STMT, code);
add_stmt (code); add_stmt (code);
inner_elements = count_type_elements (inner_type, true); num_split_elts++;
if (inner_elements < 0)
num_initialized_elements = -1;
else if (num_initialized_elements >= 0)
num_initialized_elements += inner_elements;
continue;
} }
} }
num_type_elements = count_type_elements (type, true);
/* If all elements of the initializer are non-constant and
have been split out, we don't need the empty CONSTRUCTOR. */
if (num_type_elements > 0
&& num_type_elements == num_initialized_elements)
*initp = NULL;
break; break;
case VECTOR_TYPE: case VECTOR_TYPE:
...@@ -583,6 +573,7 @@ split_nonconstant_init_1 (tree dest, tree *initp) ...@@ -583,6 +573,7 @@ split_nonconstant_init_1 (tree dest, tree *initp)
code = build2 (MODIFY_EXPR, type, dest, cons); code = build2 (MODIFY_EXPR, type, dest, cons);
code = build_stmt (input_location, EXPR_STMT, code); code = build_stmt (input_location, EXPR_STMT, code);
add_stmt (code); add_stmt (code);
num_split_elts += CONSTRUCTOR_NELTS (init);
} }
break; break;
...@@ -592,6 +583,8 @@ split_nonconstant_init_1 (tree dest, tree *initp) ...@@ -592,6 +583,8 @@ split_nonconstant_init_1 (tree dest, tree *initp)
/* The rest of the initializer is now a constant. */ /* The rest of the initializer is now a constant. */
TREE_CONSTANT (init) = 1; TREE_CONSTANT (init) = 1;
return complete_p && complete_ctor_at_level_p (TREE_TYPE (init),
num_split_elts, inner_type);
} }
/* A subroutine of store_init_value. Splits non-constant static /* A subroutine of store_init_value. Splits non-constant static
...@@ -607,7 +600,8 @@ split_nonconstant_init (tree dest, tree init) ...@@ -607,7 +600,8 @@ split_nonconstant_init (tree dest, tree init)
if (TREE_CODE (init) == CONSTRUCTOR) if (TREE_CODE (init) == CONSTRUCTOR)
{ {
code = push_stmt_list (); code = push_stmt_list ();
split_nonconstant_init_1 (dest, &init); if (split_nonconstant_init_1 (dest, init))
init = NULL_TREE;
code = pop_stmt_list (code); code = pop_stmt_list (code);
DECL_INITIAL (dest) = init; DECL_INITIAL (dest) = init;
TREE_READONLY (dest) = 0; TREE_READONLY (dest) = 0;
......
...@@ -4846,16 +4846,136 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) ...@@ -4846,16 +4846,136 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
return NULL_RTX; 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. */ /* Helper for categorize_ctor_elements. Identical interface. */
static bool static bool
categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
HOST_WIDE_INT *p_elt_count, HOST_WIDE_INT *p_init_elts, bool *p_complete)
bool *p_must_clear)
{ {
unsigned HOST_WIDE_INT idx; unsigned HOST_WIDE_INT idx;
HOST_WIDE_INT nz_elts, elt_count; HOST_WIDE_INT nz_elts, init_elts, num_fields;
tree value, purpose; tree value, purpose, elt_type;
/* Whether CTOR is a valid constant initializer, in accordance with what /* Whether CTOR is a valid constant initializer, in accordance with what
initializer_constant_valid_p does. If inferred from the constructor 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, ...@@ -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); bool const_p = const_from_elts_p ? true : TREE_STATIC (ctor);
nz_elts = 0; 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) 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, ...@@ -4879,6 +5001,8 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
mult = (tree_low_cst (hi_index, 1) mult = (tree_low_cst (hi_index, 1)
- tree_low_cst (lo_index, 1) + 1); - tree_low_cst (lo_index, 1) + 1);
} }
num_fields += mult;
elt_type = TREE_TYPE (value);
switch (TREE_CODE (value)) switch (TREE_CODE (value))
{ {
...@@ -4886,11 +5010,11 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, ...@@ -4886,11 +5010,11 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
{ {
HOST_WIDE_INT nz = 0, ic = 0; HOST_WIDE_INT nz = 0, ic = 0;
bool const_elt_p bool const_elt_p = categorize_ctor_elements_1 (value, &nz, &ic,
= categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear); p_complete);
nz_elts += mult * nz; nz_elts += mult * nz;
elt_count += mult * ic; init_elts += mult * ic;
if (const_from_elts_p && const_p) if (const_from_elts_p && const_p)
const_p = const_elt_p; const_p = const_elt_p;
...@@ -4902,12 +5026,12 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, ...@@ -4902,12 +5026,12 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
case FIXED_CST: case FIXED_CST:
if (!initializer_zerop (value)) if (!initializer_zerop (value))
nz_elts += mult; nz_elts += mult;
elt_count += mult; init_elts += mult;
break; break;
case STRING_CST: case STRING_CST:
nz_elts += mult * TREE_STRING_LENGTH (value); nz_elts += mult * TREE_STRING_LENGTH (value);
elt_count += mult * TREE_STRING_LENGTH (value); init_elts += mult * TREE_STRING_LENGTH (value);
break; break;
case COMPLEX_CST: case COMPLEX_CST:
...@@ -4915,7 +5039,7 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, ...@@ -4915,7 +5039,7 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
nz_elts += mult; nz_elts += mult;
if (!initializer_zerop (TREE_IMAGPART (value))) if (!initializer_zerop (TREE_IMAGPART (value)))
nz_elts += mult; nz_elts += mult;
elt_count += mult; init_elts += mult;
break; break;
case VECTOR_CST: case VECTOR_CST:
...@@ -4925,65 +5049,31 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, ...@@ -4925,65 +5049,31 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
{ {
if (!initializer_zerop (TREE_VALUE (v))) if (!initializer_zerop (TREE_VALUE (v)))
nz_elts += mult; nz_elts += mult;
elt_count += mult; init_elts += mult;
} }
} }
break; break;
default: default:
{ {
HOST_WIDE_INT tc = count_type_elements (TREE_TYPE (value), true); HOST_WIDE_INT tc = count_type_elements (elt_type, false);
if (tc < 1)
tc = 1;
nz_elts += mult * tc; nz_elts += mult * tc;
elt_count += mult * tc; init_elts += mult * tc;
if (const_from_elts_p && const_p) 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; != NULL_TREE;
} }
break; break;
} }
} }
if (!*p_must_clear if (*p_complete && !complete_ctor_at_level_p (TREE_TYPE (ctor),
&& (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE num_fields, elt_type))
|| TREE_CODE (TREE_TYPE (ctor)) == QUAL_UNION_TYPE)) *p_complete = false;
{
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;
}
*p_nz_elts += nz_elts; *p_nz_elts += nz_elts;
*p_elt_count += elt_count; *p_init_elts += init_elts;
return const_p; return const_p;
} }
...@@ -4993,111 +5083,50 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts, ...@@ -4993,111 +5083,50 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
and place it in *P_NZ_ELTS; and place it in *P_NZ_ELTS;
* how many scalar fields in total are in CTOR, * how many scalar fields in total are in CTOR,
and place it in *P_ELT_COUNT. and place it in *P_ELT_COUNT.
* if a type is a union, and the initializer from the constructor * whether the constructor is complete -- in the sense that every
is not the largest element in the union, then set *p_must_clear. 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 Return whether or not CTOR is a valid static constant initializer, the same
as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0". */ as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0". */
bool bool
categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts, categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
HOST_WIDE_INT *p_elt_count, HOST_WIDE_INT *p_init_elts, bool *p_complete)
bool *p_must_clear)
{ {
*p_nz_elts = 0; *p_nz_elts = 0;
*p_elt_count = 0; *p_init_elts = 0;
*p_must_clear = false; *p_complete = true;
return return categorize_ctor_elements_1 (ctor, p_nz_elts, p_init_elts, p_complete);
categorize_ctor_elements_1 (ctor, p_nz_elts, p_elt_count, p_must_clear);
} }
/* Count the number of scalars in TYPE. Return -1 on overflow or /* TYPE is initialized by a constructor with NUM_ELTS elements, the last
variable-sized. If ALLOW_FLEXARR is true, don't count flexible of which had type LAST_TYPE. Each element was itself a complete
array member at the end of the structure. */ 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 bool
count_type_elements (const_tree type, bool allow_flexarr) 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)); if (TREE_CODE (type) == UNION_TYPE
switch (TREE_CODE (type)) || TREE_CODE (type) == QUAL_UNION_TYPE)
{ {
case ARRAY_TYPE: if (num_elts == 0)
{ return false;
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;
case ERROR_MARK: gcc_assert (num_elts == 1 && last_type);
return 0;
case VOID_TYPE: /* ??? We could look at each element of the union, and find the
case METHOD_TYPE: largest element. Which would avoid comparing the size of the
case FUNCTION_TYPE: initialized element against any tail padding in the union.
case LANG_TYPE: Doesn't seem worth the effort... */
default: return simple_cst_equal (TYPE_SIZE (type), TYPE_SIZE (last_type)) == 1;
gcc_unreachable ();
} }
return count_type_elements (type, true) == num_elts;
} }
/* Return 1 if EXP contains mostly (3/4) zeros. */ /* Return 1 if EXP contains mostly (3/4) zeros. */
...@@ -5106,18 +5135,12 @@ static int ...@@ -5106,18 +5135,12 @@ static int
mostly_zeros_p (const_tree exp) mostly_zeros_p (const_tree exp)
{ {
if (TREE_CODE (exp) == CONSTRUCTOR) if (TREE_CODE (exp) == CONSTRUCTOR)
{ {
HOST_WIDE_INT nz_elts, count, elts; HOST_WIDE_INT nz_elts, init_elts;
bool must_clear; bool complete_p;
categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
if (must_clear)
return 1;
elts = count_type_elements (TREE_TYPE (exp), false); categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p);
return !complete_p || nz_elts < init_elts / 4;
return nz_elts < elts / 4;
} }
return initializer_zerop (exp); return initializer_zerop (exp);
...@@ -5129,13 +5152,12 @@ static int ...@@ -5129,13 +5152,12 @@ static int
all_zeros_p (const_tree exp) all_zeros_p (const_tree exp)
{ {
if (TREE_CODE (exp) == CONSTRUCTOR) if (TREE_CODE (exp) == CONSTRUCTOR)
{ {
HOST_WIDE_INT nz_elts, count; HOST_WIDE_INT nz_elts, init_elts;
bool must_clear; bool complete_p;
categorize_ctor_elements (exp, &nz_elts, &count, &must_clear); categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p);
return nz_elts == 0; return nz_elts == init_elts;
} }
return initializer_zerop (exp); return initializer_zerop (exp);
......
...@@ -3731,9 +3731,8 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ...@@ -3731,9 +3731,8 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
case ARRAY_TYPE: case ARRAY_TYPE:
{ {
struct gimplify_init_ctor_preeval_data preeval_data; struct gimplify_init_ctor_preeval_data preeval_data;
HOST_WIDE_INT num_type_elements, num_ctor_elements; HOST_WIDE_INT num_ctor_elements, num_nonzero_elements;
HOST_WIDE_INT num_nonzero_elements; bool cleared, complete_p, valid_const_initializer;
bool cleared, valid_const_initializer;
/* Aggregate types must lower constructors to initialization of /* Aggregate types must lower constructors to initialization of
individual elements. The exception is that a CONSTRUCTOR node individual elements. The exception is that a CONSTRUCTOR node
...@@ -3750,7 +3749,7 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ...@@ -3750,7 +3749,7 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
can only do so if it known to be a valid constant initializer. */ can only do so if it known to be a valid constant initializer. */
valid_const_initializer valid_const_initializer
= categorize_ctor_elements (ctor, &num_nonzero_elements, = categorize_ctor_elements (ctor, &num_nonzero_elements,
&num_ctor_elements, &cleared); &num_ctor_elements, &complete_p);
/* If a const aggregate variable is being initialized, then it /* If a const aggregate variable is being initialized, then it
should never be a lose to promote the variable to be static. */ should never be a lose to promote the variable to be static. */
...@@ -3788,26 +3787,29 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ...@@ -3788,26 +3787,29 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
parts in, then generate code for the non-constant parts. */ parts in, then generate code for the non-constant parts. */
/* TODO. There's code in cp/typeck.c to do this. */ /* TODO. There's code in cp/typeck.c to do this. */
num_type_elements = count_type_elements (type, true); if (int_size_in_bytes (TREE_TYPE (ctor)) < 0)
/* store_constructor will ignore the clearing of variable-sized
/* If count_type_elements could not determine number of type elements objects. Initializers for such objects must explicitly set
for a constant-sized object, assume clearing is needed. every field that needs to be set. */
Don't do this for variable-sized objects, as store_constructor cleared = false;
will ignore the clearing of variable-sized objects. */ else if (!complete_p)
if (num_type_elements < 0 && int_size_in_bytes (type) >= 0) /* If the constructor isn't complete, clear the whole object
beforehand.
??? This ought not to be needed. For any element not present
in the initializer, we should simply set them to zero. Except
we'd need to *find* the elements that are not present, and that
requires trickery to avoid quadratic compile-time behavior in
large cases or excessive memory use in small cases. */
cleared = true; cleared = true;
/* If there are "lots" of zeros, then block clear the object first. */ else if (num_ctor_elements - num_nonzero_elements
else if (num_type_elements - num_nonzero_elements
> CLEAR_RATIO (optimize_function_for_speed_p (cfun)) > CLEAR_RATIO (optimize_function_for_speed_p (cfun))
&& num_nonzero_elements < num_type_elements/4) && num_nonzero_elements < num_ctor_elements / 4)
cleared = true; /* If there are "lots" of zeros, it's more efficient to clear
/* ??? This bit ought not be needed. For any element not present the memory and then set the nonzero elements. */
in the initializer, we should simply set them to zero. Except
we'd need to *find* the elements that are not present, and that
requires trickery to avoid quadratic compile-time behavior in
large cases or excessive memory use in small cases. */
else if (num_ctor_elements < num_type_elements)
cleared = true; cleared = true;
else
cleared = false;
/* If there are "lots" of initialized elements, and all of them /* If there are "lots" of initialized elements, and all of them
are valid address constants, then the entire initializer can are valid address constants, then the entire initializer can
......
2011-07-13 Chung-Lin Tang <cltang@codesourcery.com>
* gcc.target/arm/pr48183.c: New test.
2011-07-13 Richard Guenther <rguenther@suse.de> 2011-07-13 Richard Guenther <rguenther@suse.de>
* gcc.dg/torture/20110713-1.c: New testcase. * gcc.dg/torture/20110713-1.c: New testcase.
......
/* testsuite/gcc.target/arm/pr48183.c */
/* { dg-do compile } */
/* { dg-require-effective-target arm_neon_ok } */
/* { dg-options "-O -g" } */
/* { dg-add-options arm_neon } */
#include <arm_neon.h>
void move_16bit_to_32bit (int32_t *dst, const short *src, unsigned n)
{
unsigned i;
int16x4x2_t input;
int32x4x2_t mid;
int32x4x2_t output;
for (i = 0; i < n/2; i += 8) {
input = vld2_s16(src + i);
mid.val[0] = vmovl_s16(input.val[0]);
mid.val[1] = vmovl_s16(input.val[1]);
output.val[0] = vshlq_n_s32(mid.val[0], 8);
output.val[1] = vshlq_n_s32(mid.val[1], 8);
vst2q_s32((int32_t *)dst + i, output);
}
}
...@@ -4804,21 +4804,10 @@ extern bool initializer_zerop (const_tree); ...@@ -4804,21 +4804,10 @@ extern bool initializer_zerop (const_tree);
extern VEC(tree,gc) *ctor_to_vec (tree); extern VEC(tree,gc) *ctor_to_vec (tree);
/* Examine CTOR to discover: extern bool categorize_ctor_elements (const_tree, HOST_WIDE_INT *,
* how many scalar fields are set to nonzero values, HOST_WIDE_INT *, bool *);
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.
Return whether or not CTOR is a valid static constant initializer, the same extern bool complete_ctor_at_level_p (const_tree, HOST_WIDE_INT, const_tree);
as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0". */
extern bool categorize_ctor_elements (const_tree, HOST_WIDE_INT *, HOST_WIDE_INT *,
bool *);
extern HOST_WIDE_INT count_type_elements (const_tree, bool);
/* integer_zerop (tree x) is nonzero if X is an integer constant of value 0. */ /* integer_zerop (tree x) is nonzero if X is an integer constant of value 0. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment