Commit 25ebb82a by Richard Henderson Committed by Richard Henderson

re PR rtl-optimization/10776 (Large aggregate initializers with a single…

re PR rtl-optimization/10776 (Large aggregate initializers with a single relocated entry causes excessive compile time regression)

        PR opt/10776
        * typeck2.c (split_nonconstant_init_1, split_nonconstant_init): New.
        (store_init_value): Use it.
        * decl.c (check_initializer): Expect full initialization code
        from store_init_value.
        * init.c (expand_aggr_init_1): Likewise.
        * decl2.c (maybe_emit_vtables): Abort if runtime init needed.

From-SVN: r75763
parent 6b692ad7
2004-01-12 Richard Henderson <rth@redhat.com>
PR opt/10776
* typeck2.c (split_nonconstant_init_1, split_nonconstant_init): New.
(store_init_value): Use it.
* decl.c (check_initializer): Expect full initialization code
from store_init_value.
* init.c (expand_aggr_init_1): Likewise.
* decl2.c (maybe_emit_vtables): Abort if runtime init needed.
2004-01-12 Mark Mitchell <mark@codesourcery.com> 2004-01-12 Mark Mitchell <mark@codesourcery.com>
* class.c (layout_class_type): For non-POD class types, also copy * class.c (layout_class_type): For non-POD class types, also copy
......
...@@ -4395,6 +4395,7 @@ static tree ...@@ -4395,6 +4395,7 @@ static tree
check_initializer (tree decl, tree init, int flags, tree *cleanup) check_initializer (tree decl, tree init, int flags, tree *cleanup)
{ {
tree type = TREE_TYPE (decl); tree type = TREE_TYPE (decl);
tree init_code = NULL;
/* If `start_decl' didn't like having an initialization, ignore it now. */ /* If `start_decl' didn't like having an initialization, ignore it now. */
if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE) if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
...@@ -4511,7 +4512,10 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) ...@@ -4511,7 +4512,10 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
{ {
dont_use_constructor: dont_use_constructor:
if (TREE_CODE (init) != TREE_VEC) if (TREE_CODE (init) != TREE_VEC)
init = store_init_value (decl, init); {
init_code = store_init_value (decl, init);
init = NULL;
}
} }
} }
else if (DECL_EXTERNAL (decl)) else if (DECL_EXTERNAL (decl))
...@@ -4534,9 +4538,9 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) ...@@ -4534,9 +4538,9 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
check_for_uninitialized_const_var (decl); check_for_uninitialized_const_var (decl);
if (init && init != error_mark_node) if (init && init != error_mark_node)
init = build (INIT_EXPR, type, decl, init); init_code = build (INIT_EXPR, type, decl, init);
return init; return init_code;
} }
/* If DECL is not a local variable, give it RTL. */ /* If DECL is not a local variable, give it RTL. */
......
...@@ -1605,7 +1605,11 @@ maybe_emit_vtables (tree ctype) ...@@ -1605,7 +1605,11 @@ maybe_emit_vtables (tree ctype)
cgraph_varpool_mark_needed_node (cgraph_varpool_node (vtbl)); cgraph_varpool_mark_needed_node (cgraph_varpool_node (vtbl));
if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0) if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
store_init_value (vtbl, DECL_INITIAL (vtbl)); {
/* It had better be all done at compile-time. */
if (store_init_value (vtbl, DECL_INITIAL (vtbl)))
abort ();
}
if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG) if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
{ {
......
...@@ -1272,8 +1272,9 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags) ...@@ -1272,8 +1272,9 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags)
/* If store_init_value returns NULL_TREE, the INIT has been /* If store_init_value returns NULL_TREE, the INIT has been
record in the DECL_INITIAL for EXP. That means there's record in the DECL_INITIAL for EXP. That means there's
nothing more we have to do. */ nothing more we have to do. */
if (store_init_value (exp, init)) init = store_init_value (exp, init);
finish_expr_stmt (build (INIT_EXPR, type, exp, init)); if (init)
finish_expr_stmt (init);
return; return;
} }
......
...@@ -284,6 +284,108 @@ cxx_incomplete_type_error (tree value, tree type) ...@@ -284,6 +284,108 @@ cxx_incomplete_type_error (tree value, tree type)
} }
/* The recursive part of split_nonconstant_init. DEST is an lvalue
expression to which INIT should be assigned. INIT is a CONSTRUCTOR.
PCODE is a pointer to the tail of a chain of statements being emitted.
The return value is the new tail of that chain after new statements
are generated. */
static tree *
split_nonconstant_init_1 (tree dest, tree init, tree *pcode)
{
tree *pelt, elt, type = TREE_TYPE (dest);
tree sub, code, inner_type = NULL;
bool array_type_p = false;
pelt = &CONSTRUCTOR_ELTS (init);
switch (TREE_CODE (type))
{
case ARRAY_TYPE:
inner_type = TREE_TYPE (type);
array_type_p = true;
/* FALLTHRU */
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
while ((elt = *pelt))
{
tree field_index = TREE_PURPOSE (elt);
tree value = TREE_VALUE (elt);
if (!array_type_p)
inner_type = TREE_TYPE (field_index);
if (TREE_CODE (value) == CONSTRUCTOR)
{
if (array_type_p)
sub = build (ARRAY_REF, inner_type, dest, field_index);
else
sub = build (COMPONENT_REF, inner_type, dest, field_index);
pcode = split_nonconstant_init_1 (sub, value, pcode);
}
else if (!initializer_constant_valid_p (value, inner_type))
{
*pelt = TREE_CHAIN (elt);
if (array_type_p)
sub = build (ARRAY_REF, inner_type, dest, field_index);
else
sub = build (COMPONENT_REF, inner_type, dest, field_index);
code = build (MODIFY_EXPR, inner_type, sub, value);
code = build_stmt (EXPR_STMT, code);
*pcode = code;
pcode = &TREE_CHAIN (code);
continue;
}
pelt = &TREE_CHAIN (elt);
}
break;
case VECTOR_TYPE:
if (!initializer_constant_valid_p (init, type))
{
CONSTRUCTOR_ELTS (init) = NULL;
code = build (MODIFY_EXPR, type, dest, init);
code = build_stmt (EXPR_STMT, code);
pcode = &TREE_CHAIN (code);
}
break;
default:
abort ();
}
return pcode;
}
/* A subroutine of store_init_value. Splits non-constant static
initializer INIT into a constant part and generates code to
perform the non-constant part of the initialization to DEST.
Returns the code for the runtime init. */
static tree
split_nonconstant_init (tree dest, tree init)
{
tree code;
if (TREE_CODE (init) == CONSTRUCTOR)
{
code = build_stmt (COMPOUND_STMT, NULL_TREE);
split_nonconstant_init_1 (dest, init, &COMPOUND_BODY (code));
code = build1 (STMT_EXPR, void_type_node, code);
TREE_SIDE_EFFECTS (code) = 1;
DECL_INITIAL (dest) = init;
}
else
code = build (INIT_EXPR, TREE_TYPE (dest), dest, init);
return code;
}
/* Perform appropriate conversions on the initial value of a variable, /* Perform appropriate conversions on the initial value of a variable,
store it in the declaration DECL, store it in the declaration DECL,
and print any error messages that are appropriate. and print any error messages that are appropriate.
...@@ -299,9 +401,8 @@ cxx_incomplete_type_error (tree value, tree type) ...@@ -299,9 +401,8 @@ cxx_incomplete_type_error (tree value, tree type)
into a CONSTRUCTOR and use standard initialization techniques. into a CONSTRUCTOR and use standard initialization techniques.
Perhaps a warning should be generated? Perhaps a warning should be generated?
Returns value of initializer if initialization could not be Returns code to be executed if initialization could not be performed
performed for static variable. In that case, caller must do for static variable. In that case, caller must emit the code. */
the storing. */
tree tree
store_init_value (tree decl, tree init) store_init_value (tree decl, tree init)
...@@ -356,11 +457,11 @@ store_init_value (tree decl, tree init) ...@@ -356,11 +457,11 @@ store_init_value (tree decl, tree init)
constructing never make it into DECL_INITIAL, and passes 'init' to constructing never make it into DECL_INITIAL, and passes 'init' to
build_aggr_init without checking DECL_INITIAL. So just return. */ build_aggr_init without checking DECL_INITIAL. So just return. */
else if (TYPE_NEEDS_CONSTRUCTING (type)) else if (TYPE_NEEDS_CONSTRUCTING (type))
return value; return build (INIT_EXPR, type, decl, value);
else if (TREE_STATIC (decl) else if (TREE_STATIC (decl)
&& (! TREE_CONSTANT (value) && (! TREE_CONSTANT (value)
|| ! initializer_constant_valid_p (value, TREE_TYPE (value)))) || ! initializer_constant_valid_p (value, TREE_TYPE (value))))
return value; return split_nonconstant_init (decl, value);
/* Store the VALUE in DECL_INITIAL. If we're building a /* Store the VALUE in DECL_INITIAL. If we're building a
statement-tree we will actually expand the initialization later statement-tree we will actually expand the initialization later
......
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