From: Richard Henderson Date: Thu, 12 Aug 2004 03:54:11 +0000 (-0700) Subject: gimplify.c (struct gimplify_init_ctor_preeval_data): New. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=57d1dd8704212031da1e646aa672720262aa4352;p=gcc.git gimplify.c (struct gimplify_init_ctor_preeval_data): New. * gimplify.c (struct gimplify_init_ctor_preeval_data): New. (gimplify_init_ctor_preeval_1): New. (gimplify_init_ctor_preeval): New. (gimplify_init_ctor_eval): New. (gimplify_init_constructor): Use them. Always gimplify the LHS object first. From-SVN: r85845 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2a85e9c37bf..2ab0e90305d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2004-08-12 Richard Henderson + + * gimplify.c (struct gimplify_init_ctor_preeval_data): New. + (gimplify_init_ctor_preeval_1): New. + (gimplify_init_ctor_preeval): New. + (gimplify_init_ctor_eval): New. + (gimplify_init_constructor): Use them. Always gimplify the LHS + object first. + 2004-08-12 Ziemowit Laski (This patch is part of merge of objc-improvements-branch diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 8a8679b54de..21d8f453e22 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2363,6 +2363,167 @@ gimplify_modify_expr_to_memset (tree *expr_p, tree size, bool want_value) return GS_OK; } +/* A subroutine of gimplify_init_ctor_preeval. Called via walk_tree, + determine, cautiously, if a CONSTRUCTOR overlaps the lhs of an + assignment. Returns non-null if we detect a potential overlap. */ + +struct gimplify_init_ctor_preeval_data +{ + /* The base decl of the lhs object. May be NULL, in which case we + have to assume the lhs is indirect. */ + tree lhs_base_decl; + + /* The alias set of the lhs object. */ + int lhs_alias_set; +}; + +static tree +gimplify_init_ctor_preeval_1 (tree *tp, int *walk_subtrees, void *xdata) +{ + struct gimplify_init_ctor_preeval_data *data + = (struct gimplify_init_ctor_preeval_data *) xdata; + tree t = *tp; + + /* If we find the base object, obviously we have overlap. */ + if (data->lhs_base_decl == t) + return t; + + /* If the constructor component is indirect, determine if we have a + potential overlap with the lhs. The only bits of information we + have to go on at this point are addressability and alias sets. */ + if (TREE_CODE (t) == INDIRECT_REF + && (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl)) + && alias_sets_conflict_p (data->lhs_alias_set, get_alias_set (t))) + return t; + + if (DECL_P (t) || TYPE_P (t)) + *walk_subtrees = 0; + return NULL; +} + +/* A subroutine of gimplify_init_constructor. Pre-evaluate *EXPR_P, + force values that overlap with the lhs (as described by *DATA) + into temporaries. */ + +static void +gimplify_init_ctor_preeval (tree *expr_p, tree *pre_p, tree *post_p, + struct gimplify_init_ctor_preeval_data *data) +{ + enum gimplify_status one; + + /* If the value is invariant, then there's nothing to pre-evaluate. + But ensure it doesn't have any side-effects since a SAVE_EXPR is + invariant but has side effects and might contain a reference to + the object we're initializing. */ + if (TREE_INVARIANT (*expr_p) && !TREE_SIDE_EFFECTS (*expr_p)) + return; + + /* If the type has non-trivial constructors, we can't pre-evaluate. */ + if (TREE_ADDRESSABLE (TREE_TYPE (*expr_p))) + return; + + /* Recurse for nested constructors. */ + if (TREE_CODE (*expr_p) == CONSTRUCTOR) + { + tree list; + for (list = CONSTRUCTOR_ELTS (*expr_p); list ; list = TREE_CHAIN (list)) + gimplify_init_ctor_preeval (&TREE_VALUE (list), pre_p, post_p, data); + return; + } + + /* We can't preevaluate if the type contains a placeholder. */ + if (type_contains_placeholder_p (TREE_TYPE (*expr_p))) + return; + + /* Gimplify the constructor element to something appropriate for the rhs + of a MODIFY_EXPR. Given that we know the lhs is an aggregate, we know + the gimplifier will consider this a store to memory. Doing this + gimplification now means that we won't have to deal with complicated + language-specific trees, nor trees like SAVE_EXPR that can induce + exponential search behaviour. */ + one = gimplify_expr (expr_p, pre_p, post_p, is_gimple_mem_rhs, fb_rvalue); + if (one == GS_ERROR) + { + *expr_p = NULL; + return; + } + + /* If we gimplified to a bare decl, we can be sure that it doesn't overlap + with the lhs, since "a = { .x=a }" doesn't make sense. This will + always be true for all scalars, since is_gimple_mem_rhs insists on a + temporary variable for them. */ + if (DECL_P (*expr_p)) + return; + + /* If this is of variable size, we have no choice but to assume it doesn't + overlap since we can't make a temporary for it. */ + if (!TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (*expr_p)))) + return; + + /* Otherwise, we must search for overlap ... */ + if (!walk_tree (expr_p, gimplify_init_ctor_preeval_1, data, NULL)) + return; + + /* ... and if found, force the value into a temporary. */ + *expr_p = get_formal_tmp_var (*expr_p, 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 + CONSTRUCTOR. CLEARED is true if the entire LHS object has been + zeroed first. */ + +static void +gimplify_init_ctor_eval (tree object, tree list, tree *pre_p, bool cleared) +{ + tree array_elt_type = NULL; + + if (TREE_CODE (TREE_TYPE (object)) == ARRAY_TYPE) + array_elt_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object))); + + for (; list; list = TREE_CHAIN (list)) + { + tree purpose, value, cref, init; + + purpose = TREE_PURPOSE (list); + value = TREE_VALUE (list); + + /* NULL values are created above for gimplification errors. */ + if (value == NULL) + continue; + + if (cleared && initializer_zerop (value)) + continue; + + if (array_elt_type) + { + /* ??? 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. */ + if (!purpose) + abort (); + /* ??? Need to handle this. */ + if (TREE_CODE (purpose) == RANGE_EXPR) + abort (); + + cref = build (ARRAY_REF, array_elt_type, unshare_expr (object), + purpose, NULL_TREE, NULL_TREE); + } + else + cref = build (COMPONENT_REF, TREE_TYPE (purpose), + unshare_expr (object), purpose, NULL_TREE); + + if (TREE_CODE (value) == CONSTRUCTOR) + gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value), + pre_p, cleared); + else + { + init = build (MODIFY_EXPR, TREE_TYPE (cref), cref, value); + gimplify_and_add (init, pre_p); + } + } +} + /* A subroutine of gimplify_modify_expr. Break out elements of a CONSTRUCTOR used as an initializer into separate MODIFY_EXPRs. @@ -2374,7 +2535,7 @@ static enum gimplify_status gimplify_init_constructor (tree *expr_p, tree *pre_p, tree *post_p, bool want_value) { - tree object = TREE_OPERAND (*expr_p, 0); + tree object; tree ctor = TREE_OPERAND (*expr_p, 1); tree type = TREE_TYPE (ctor); enum gimplify_status ret; @@ -2383,6 +2544,12 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, if (TREE_CODE (ctor) != CONSTRUCTOR) return GS_UNHANDLED; + ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, + is_gimple_lvalue, fb_lvalue); + if (ret == GS_ERROR) + return ret; + object = TREE_OPERAND (*expr_p, 0); + elt_list = CONSTRUCTOR_ELTS (ctor); ret = GS_ALL_DONE; @@ -2393,7 +2560,8 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, case QUAL_UNION_TYPE: case ARRAY_TYPE: { - HOST_WIDE_INT i, num_elements, num_nonzero_elements; + struct gimplify_init_ctor_preeval_data preeval_data; + HOST_WIDE_INT num_elements, num_nonzero_elements; HOST_WIDE_INT num_nonconstant_elements; bool cleared; @@ -2401,19 +2569,10 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, individual elements. The exception is that a CONSTRUCTOR node with no elements indicates zero-initialization of the whole. */ if (elt_list == NULL) - { - if (want_value) - { - *expr_p = object; - return GS_OK; - } - else - return GS_UNHANDLED; - } + break; categorize_ctor_elements (ctor, &num_nonzero_elements, &num_nonconstant_elements); - num_elements = count_type_elements (TREE_TYPE (ctor)); /* If a const aggregate variable is being initialized, then it should never be a lose to promote the variable to be static. */ @@ -2468,6 +2627,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, if (size > 0 && !can_move_by_pieces (size, align)) { tree new = create_tmp_var_raw (type, "C"); + gimple_add_tmp_var (new); TREE_STATIC (new) = 1; TREE_READONLY (new) = 1; @@ -2480,7 +2640,11 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL); TREE_OPERAND (*expr_p, 1) = new; - break; + + /* This is no longer an assignment of a CONSTRUCTOR, but + we still may have processing to do on the LHS. So + pretend we didn't do anything here to let that happen. */ + return GS_UNHANDLED; } } @@ -2491,6 +2655,8 @@ 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)); + /* If there are "lots" of zeros, then block clear the object first. */ cleared = false; if (num_elements - num_nonzero_elements > CLEAR_RATIO @@ -2510,60 +2676,31 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, tree nelts = array_type_nelts (type); if (!host_integerp (nelts, 1) || tree_low_cst (nelts, 1) + 1 != len) - cleared = 1;; + cleared = true; } else if (len != fields_length (type)) - cleared = 1; + cleared = true; } if (cleared) { /* Zap the CONSTRUCTOR element list, which simplifies this case. Note that we still have to gimplify, in order to handle the - case of variable sized types. Make an unshared copy of - OBJECT before that so we can match a PLACEHOLDER_EXPR to it - later, if needed. */ + case of variable sized types. Avoid shared tree structures. */ CONSTRUCTOR_ELTS (ctor) = NULL_TREE; - object = unshare_expr (TREE_OPERAND (*expr_p, 0)); + object = unshare_expr (object); gimplify_stmt (expr_p); append_to_statement_list (*expr_p, pre_p); } - for (i = 0; elt_list; i++, elt_list = TREE_CHAIN (elt_list)) - { - tree purpose, value, cref, init; - - purpose = TREE_PURPOSE (elt_list); - value = TREE_VALUE (elt_list); - - if (cleared && initializer_zerop (value)) - continue; + 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); - if (TREE_CODE (type) == ARRAY_TYPE) - { - tree t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object))); - - /* ??? 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. */ - if (!purpose) - abort (); - /* ??? Need to handle this. */ - if (TREE_CODE (purpose) == RANGE_EXPR) - abort (); - - cref = build (ARRAY_REF, t, unshare_expr (object), purpose, - NULL_TREE, NULL_TREE); - } - else - cref = build (COMPONENT_REF, TREE_TYPE (purpose), - unshare_expr (object), purpose, NULL_TREE); - - init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value); - - /* Each member initialization is a full-expression. */ - gimplify_and_add (init, pre_p); - } + 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; }