diff options
author | steven <steven@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-12-20 11:26:47 +0000 |
---|---|---|
committer | steven <steven@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-12-20 11:26:47 +0000 |
commit | 42b746980785a6cc298a04f4308c63b4ec34bacb (patch) | |
tree | 9c25a2d0ac01a41629a94a7371f5c14a2e9e6fe0 /gcc/gimplify.c | |
parent | cf55bc95ba3e9544729d48d834f5316cbee679a5 (diff) | |
download | gcc-42b746980785a6cc298a04f4308c63b4ec34bacb.tar.gz |
gcc/
PR middle-end/18191
PR middle-end/18965
PR middle-end/18999
* expr.c (categorize_ctor_elements_1): Count the total number
of elements in the constructor.
(categorize_ctor_elements): Return it in a new argument.
* tree.h (categorize_ctor_elements): Adjust prototype.
* gimplify.c (gimplify_init_ctor_eval_range): New.
(gimplify_init_ctor_eval): Gimplify RANGE_EXPR.
(gimplify_init_constructor): Block clear the object if the
constructor has fewer elements than the object type. Only try
to add assignments to individual elements when we have to.
testsuite/
* gcc.dg/20041219-1.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@92415 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r-- | gcc/gimplify.c | 168 |
1 files changed, 135 insertions, 33 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 55889ea9dcc..34b22cc6781 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2367,6 +2367,95 @@ gimplify_init_ctor_preeval (tree *expr_p, tree *pre_p, tree *post_p, *expr_p = get_formal_tmp_var (*expr_p, pre_p); } +/* A subroutine of gimplify_init_ctor_eval. Create a loop for + a RANGE_EXPR in a CONSTRUCTOR for an array. + + var = lower; + loop_entry: + object[var] = value; + if (var == upper) + goto loop_exit; + var = var + 1; + goto loop_entry; + loop_exit: + + We increment var _after_ the loop exit check because we might otherwise + fail if upper == TYPE_MAX_VALUE (type for upper). + + Note that we never have to deal with SAVE_EXPRs here, because this has + already been taken care of for us, in gimplify_init_ctor_preeval(). */ + +static void gimplify_init_ctor_eval (tree, tree, tree *, bool); + +static void +gimplify_init_ctor_eval_range (tree object, tree lower, tree upper, + tree value, tree array_elt_type, + tree *pre_p, bool cleared) +{ + tree loop_entry_label, loop_exit_label; + tree var, var_type, cref; + + loop_entry_label = create_artificial_label (); + loop_exit_label = create_artificial_label (); + + /* Create and initialize the index variable. */ + var_type = TREE_TYPE (upper); + var = create_tmp_var (var_type, NULL); + append_to_statement_list (build2 (MODIFY_EXPR, var_type, var, lower), pre_p); + + /* Add the loop entry label. */ + append_to_statement_list (build1 (LABEL_EXPR, + void_type_node, + loop_entry_label), + pre_p); + + /* Build the reference. */ + cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object), + var, NULL_TREE, NULL_TREE); + + /* If we are a constructor, just call gimplify_init_ctor_eval to do + the store. Otherwise just assign value to the reference. */ + + if (TREE_CODE (value) == CONSTRUCTOR) + /* NB we might have to call ourself recursively through + gimplify_init_ctor_eval if the value is a constructor. */ + gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value), + pre_p, cleared); + else + append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (cref), + cref, value), + pre_p); + + /* We exit the loop when the index var is equal to the upper bound. */ + gimplify_and_add (build3 (COND_EXPR, void_type_node, + build2 (EQ_EXPR, boolean_type_node, + var, upper), + build1 (GOTO_EXPR, + void_type_node, + loop_exit_label), + NULL_TREE), + pre_p); + + /* Otherwise, increment the index var... */ + append_to_statement_list (build2 (MODIFY_EXPR, var_type, var, + build2 (PLUS_EXPR, var_type, var, + fold_convert (var_type, + integer_one_node))), + pre_p); + + /* ...and jump back to the loop entry. */ + append_to_statement_list (build1 (GOTO_EXPR, + void_type_node, + loop_entry_label), + pre_p); + + /* Add the loop exit label. */ + append_to_statement_list (build1 (LABEL_EXPR, + void_type_node, + loop_exit_label), + pre_p); +} + /* A subroutine of gimplify_init_constructor. Generate individual MODIFY_EXPRs for a CONSTRUCTOR. OBJECT is the LHS against which the assignments should happen. LIST is the CONSTRUCTOR_ELTS of the @@ -2395,14 +2484,31 @@ gimplify_init_ctor_eval (tree object, tree list, tree *pre_p, bool cleared) if (cleared && initializer_zerop (value)) continue; - if (array_elt_type) + /* ??? Here's to hoping the front end fills in all of the indices, + so we don't have to figure out what's missing ourselves. */ + gcc_assert (purpose); + + /* If we have a RANGE_EXPR, we have to build a loop to assign the + whole range. */ + if (TREE_CODE (purpose) == RANGE_EXPR) { - /* ??? Here's to hoping the front end fills in all of the indicies, - so we don't have to figure out what's missing ourselves. */ - gcc_assert (purpose); - /* ??? Need to handle this. */ - gcc_assert (TREE_CODE (purpose) != RANGE_EXPR); + tree lower = TREE_OPERAND (purpose, 0); + tree upper = TREE_OPERAND (purpose, 1); + + /* If the lower bound is equal to upper, just treat it as if + upper was the index. */ + if (simple_cst_equal (lower, upper)) + purpose = upper; + else + { + gimplify_init_ctor_eval_range (object, lower, upper, value, + array_elt_type, pre_p, cleared); + continue; + } + } + if (array_elt_type) + { cref = build (ARRAY_REF, array_elt_type, unshare_expr (object), purpose, NULL_TREE, NULL_TREE); } @@ -2458,8 +2564,8 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, case ARRAY_TYPE: { struct gimplify_init_ctor_preeval_data preeval_data; - HOST_WIDE_INT num_elements, num_nonzero_elements; - HOST_WIDE_INT num_nonconstant_elements; + HOST_WIDE_INT num_type_elements, num_ctor_elements; + HOST_WIDE_INT num_nonzero_elements, num_nonconstant_elements; bool cleared; /* Aggregate types must lower constructors to initialization of @@ -2469,7 +2575,8 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, break; categorize_ctor_elements (ctor, &num_nonzero_elements, - &num_nonconstant_elements); + &num_nonconstant_elements, + &num_ctor_elements); /* If a const aggregate variable is being initialized, then it should never be a lose to promote the variable to be static. */ @@ -2552,12 +2659,12 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, parts in, then generate code for the non-constant parts. */ /* TODO. There's code in cp/typeck.c to do this. */ - num_elements = count_type_elements (TREE_TYPE (ctor)); + num_type_elements = count_type_elements (TREE_TYPE (ctor)); /* If there are "lots" of zeros, then block clear the object first. */ cleared = false; - if (num_elements - num_nonzero_elements > CLEAR_RATIO - && num_nonzero_elements < num_elements/4) + if (num_type_elements - num_nonzero_elements > CLEAR_RATIO + && num_nonzero_elements < num_type_elements/4) cleared = true; /* ??? This bit ought not be needed. For any element not present @@ -2565,19 +2672,8 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, 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 - { - HOST_WIDE_INT len = list_length (elt_list); - if (TREE_CODE (type) == ARRAY_TYPE) - { - tree nelts = array_type_nelts (type); - if (!host_integerp (nelts, 1) - || tree_low_cst (nelts, 1) + 1 != len) - cleared = true; - } - else if (len != fields_length (type)) - cleared = true; - } + else if (num_ctor_elements < num_type_elements) + cleared = true; if (cleared) { @@ -2590,14 +2686,20 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, append_to_statement_list (*expr_p, pre_p); } - preeval_data.lhs_base_decl = get_base_address (object); - if (!DECL_P (preeval_data.lhs_base_decl)) - preeval_data.lhs_base_decl = NULL; - preeval_data.lhs_alias_set = get_alias_set (object); - - gimplify_init_ctor_preeval (&TREE_OPERAND (*expr_p, 1), - pre_p, post_p, &preeval_data); - gimplify_init_ctor_eval (object, elt_list, pre_p, cleared); + /* If we have not block cleared the object, or if there are nonzero + elements in the constructor, add assignments to the individual + scalar fields of the object. */ + if (!cleared || num_nonzero_elements > 0) + { + preeval_data.lhs_base_decl = get_base_address (object); + if (!DECL_P (preeval_data.lhs_base_decl)) + preeval_data.lhs_base_decl = NULL; + preeval_data.lhs_alias_set = get_alias_set (object); + + gimplify_init_ctor_preeval (&TREE_OPERAND (*expr_p, 1), + pre_p, post_p, &preeval_data); + gimplify_init_ctor_eval (object, elt_list, pre_p, cleared); + } *expr_p = NULL_TREE; } |