From 6fa91b48742a376c845ecbd1676d887dc3829c9d Mon Sep 17 00:00:00 2001 From: Steven Bosscher Date: Mon, 20 Dec 2004 11:26:47 +0000 Subject: [PATCH] re PR middle-end/18191 (Struct member is not getting default-initialized) 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. Co-Authored-By: Andrew Pinski From-SVN: r92415 --- gcc/ChangeLog | 16 ++++ gcc/expr.c | 43 +++++++--- gcc/gimplify.c | 168 ++++++++++++++++++++++++++++++-------- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.dg/20041219-1.c | 47 +++++++++++ gcc/tree.h | 3 +- 6 files changed, 234 insertions(+), 47 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/20041219-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c3ff588..b8876af 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2004-12-20 Steven Bosscher + Andrew Pinski + + 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. + 2004-12-20 Richard Henderson * config/i386/i386.c (ix86_init_mmx_sse_builtins): Use diff --git a/gcc/expr.c b/gcc/expr.c index 2581c15..de11afff 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -4220,19 +4220,25 @@ store_expr (tree exp, rtx target, int call_param_p) return NULL_RTX; } -/* Examine CTOR. Discover how many scalar fields are set to nonzero - values and place it in *P_NZ_ELTS. Discover how many scalar fields - are set to non-constant values and place it in *P_NC_ELTS. */ +/* Examine CTOR to discover: + * how many scalar fields are set to nonzero values, + and place it in *P_NZ_ELTS; + * how many scalar fields are set to non-constant values, + and place it in *P_NC_ELTS; and + * how many scalar fields in total are in CTOR, + and place it in *P_ELT_COUNT. */ static void categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, - HOST_WIDE_INT *p_nc_elts) + HOST_WIDE_INT *p_nc_elts, + HOST_WIDE_INT *p_elt_count) { - HOST_WIDE_INT nz_elts, nc_elts; + HOST_WIDE_INT nz_elts, nc_elts, elt_count; tree list; nz_elts = 0; nc_elts = 0; + elt_count = 0; for (list = CONSTRUCTOR_ELTS (ctor); list; list = TREE_CHAIN (list)) { @@ -4255,10 +4261,11 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, { case CONSTRUCTOR: { - HOST_WIDE_INT nz = 0, nc = 0; - categorize_ctor_elements_1 (value, &nz, &nc); + HOST_WIDE_INT nz = 0, nc = 0, count = 0; + categorize_ctor_elements_1 (value, &nz, &nc, &count); nz_elts += mult * nz; nc_elts += mult * nc; + elt_count += mult * count; } break; @@ -4266,10 +4273,12 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, case REAL_CST: if (!initializer_zerop (value)) nz_elts += mult; + elt_count += mult; break; case STRING_CST: nz_elts += mult * TREE_STRING_LENGTH (value); + elt_count += mult * TREE_STRING_LENGTH (value); break; case COMPLEX_CST: @@ -4277,19 +4286,24 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, nz_elts += mult; if (!initializer_zerop (TREE_IMAGPART (value))) nz_elts += mult; + elt_count += mult; break; case VECTOR_CST: { tree v; for (v = TREE_VECTOR_CST_ELTS (value); v; v = TREE_CHAIN (v)) - if (!initializer_zerop (TREE_VALUE (v))) - nz_elts += mult; + { + if (!initializer_zerop (TREE_VALUE (v))) + nz_elts += mult; + elt_count += mult; + } } break; default: nz_elts += mult; + elt_count += mult; if (!initializer_constant_valid_p (value, TREE_TYPE (value))) nc_elts += mult; break; @@ -4298,15 +4312,18 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, *p_nz_elts += nz_elts; *p_nc_elts += nc_elts; + *p_elt_count += elt_count; } void categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts, - HOST_WIDE_INT *p_nc_elts) + HOST_WIDE_INT *p_nc_elts, + HOST_WIDE_INT *p_elt_count) { *p_nz_elts = 0; *p_nc_elts = 0; - categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts); + *p_elt_count = 0; + categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count); } /* Count the number of scalars in TYPE. Return -1 on overflow or @@ -4395,9 +4412,9 @@ mostly_zeros_p (tree exp) if (TREE_CODE (exp) == CONSTRUCTOR) { - HOST_WIDE_INT nz_elts, nc_elts, elts; + HOST_WIDE_INT nz_elts, nc_elts, count, elts; - categorize_ctor_elements (exp, &nz_elts, &nc_elts); + categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count); elts = count_type_elements (TREE_TYPE (exp)); return nz_elts < elts / 4; diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 55889ea..34b22cc 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; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2de4305..c1c21c4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-12-20 Steven Bosscher + + * gcc.dg/20041219-1.c: New test. + 2004-12-19 Roger Sayle PR middle-end/19068 diff --git a/gcc/testsuite/gcc.dg/20041219-1.c b/gcc/testsuite/gcc.dg/20041219-1.c new file mode 100644 index 0000000..4fdc954 --- /dev/null +++ b/gcc/testsuite/gcc.dg/20041219-1.c @@ -0,0 +1,47 @@ +/* PR18191 Struct member is not getting default-initialized. + Origin: Grigory Zagorodnev */ + +/* { dg-do run } */ + +extern int printf (__const char *__restrict __format, ...); + +typedef struct S { + const char* s; + int i; +} S; + +void +foo (void) +{ + S dummy[2]; + unsigned i; + + /* Put some garbage on the stack. */ + for (i = 0; i < sizeof(dummy); i++) + ((char *)&dummy)[i] = -1; +} + +int +bar (void) +{ + /* Allocate object on the stack. */ + S obj[2] = { {"m0"}, {"m1"} }; + + /* Assume fields those not explicitly initialized + are default initialized to 0 [8.5.1/7 and 8.5/5]. */ + if (obj[0].i == 0) + return 0; + else + { + printf("Failed: obj[0].i == '%d', expecting '0'\n", obj[0].i); + return 1; + } +} + +int +main (void) +{ + foo(); + return bar(); +} + diff --git a/gcc/tree.h b/gcc/tree.h index fa328be..90d17e5 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3226,7 +3226,8 @@ extern int fields_length (tree); extern bool initializer_zerop (tree); -extern void categorize_ctor_elements (tree, HOST_WIDE_INT *, HOST_WIDE_INT *); +extern void categorize_ctor_elements (tree, HOST_WIDE_INT *, + HOST_WIDE_INT *, HOST_WIDE_INT *); extern HOST_WIDE_INT count_type_elements (tree); /* add_var_to_bind_expr (bind_expr, var) binds var to bind_expr. */ -- 2.7.4