From: Gabriel Dos Reis Date: Fri, 12 Mar 2004 20:53:57 +0000 (+0000) Subject: backport: re PR rtl-optimization/10776 (Large aggregate initializers with a single... X-Git-Tag: releases/gcc-3.3.4~174 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f223df3d25af4d53846cee0eb1447894cf1f48e;p=thirdparty%2Fgcc.git backport: re PR rtl-optimization/10776 (Large aggregate initializers with a single relocated entry causes excessive compile time regression) Backport: 2004-01-12 Richard Henderson 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: r79406 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e428b1095832..3025fdd3e5e5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2004-03-12 Gabriel Dos Reis + + Backport: + 2004-01-12 Richard Henderson + 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-03-09 Giovanni Bajo PR c++/14409 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 364f4aada8ce..2862ee5fc8ac 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -8428,6 +8428,7 @@ static tree check_initializer (tree decl, tree init, int flags, tree *cleanup) { tree type = TREE_TYPE (decl); + tree init_code = NULL; /* If `start_decl' didn't like having an initialization, ignore it now. */ if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE) @@ -8538,7 +8539,10 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) { dont_use_constructor: 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)) @@ -8561,9 +8565,9 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) check_for_uninitialized_const_var (decl); 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. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 55613700d3bc..50bb3e2fa79f 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1851,7 +1851,11 @@ maybe_emit_vtables (tree ctype) import_export_vtable (vtbl, ctype, 1); mark_vtable_entries (vtbl); 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) { diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 1090f556bc69..70085280290b 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1286,8 +1286,9 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags) /* If store_init_value returns NULL_TREE, the INIT has been record in the DECL_INITIAL for EXP. That means there's nothing more we have to do. */ - if (store_init_value (exp, init)) - finish_expr_stmt (build (INIT_EXPR, type, exp, init)); + init = store_init_value (exp, init); + if (init) + finish_expr_stmt (init); return; } diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index b063f42a9f98..d80463213a0f 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -296,6 +296,108 @@ cxx_incomplete_type_error (value, 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, store it in the declaration DECL, and print any error messages that are appropriate. @@ -311,9 +413,8 @@ cxx_incomplete_type_error (value, type) into a CONSTRUCTOR and use standard initialization techniques. Perhaps a warning should be generated? - Returns value of initializer if initialization could not be - performed for static variable. In that case, caller must do - the storing. */ + Returns code to be executed if initialization could not be performed + for static variable. In that case, caller must emit the code. */ tree store_init_value (decl, init) @@ -385,11 +486,11 @@ store_init_value (decl, init) constructing never make it into DECL_INITIAL, and passes 'init' to build_aggr_init without checking DECL_INITIAL. So just return. */ else if (TYPE_NEEDS_CONSTRUCTING (type)) - return value; + return build (INIT_EXPR, type, decl, value); else if (TREE_STATIC (decl) && (! TREE_CONSTANT (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 statement-tree we will actually expand the initialization later