X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgimplify.c;h=7f1dc4ae94bd861215bea72cdc54c2689d794b2b;hb=2978fc3d522d2d14db5efcd27786401469012e52;hp=f22111d4cd7fff803d5f0bebbc6aa89615e844e0;hpb=f4e36c337a3d5f2c1f558538fd2a489fd207938f;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/gimplify.c b/gcc/gimplify.c index f22111d4cd7..7f1dc4ae94b 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1,6 +1,6 @@ /* Tree lowering pass. This pass converts the GENERIC functions-as-trees tree representation into the GIMPLE form. - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Major work done by Sebastian Pop , Diego Novillo and Jason Merrill . @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see #include "splay-tree.h" #include "vec.h" #include "gimple.h" +#include "tree-pass.h" enum gimplify_omp_var_data @@ -107,12 +108,14 @@ static enum gimplify_status gimplify_compound_expr (tree *, gimple_seq *, bool); /* Mark X addressable. Unlike the langhook we expect X to be in gimple form and we don't do any syntax checking. */ -static void +void mark_addressable (tree x) { while (handled_component_p (x)) x = TREE_OPERAND (x, 0); - if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL) + if (TREE_CODE (x) != VAR_DECL + && TREE_CODE (x) != PARM_DECL + && TREE_CODE (x) != RESULT_DECL) return ; TREE_ADDRESSABLE (x) = 1; } @@ -212,15 +215,12 @@ void pop_gimplify_context (gimple body) { struct gimplify_ctx *c = gimplify_ctxp; - tree t; gcc_assert (c && (c->bind_expr_stack == NULL || VEC_empty (gimple, c->bind_expr_stack))); + VEC_free (gimple, heap, c->bind_expr_stack); gimplify_ctxp = c->prev_context; - for (t = c->temps; t ; t = TREE_CHAIN (t)) - DECL_GIMPLE_FORMAL_TEMP_P (t) = 0; - if (body) declare_vars (c->temps, body, false); else @@ -431,57 +431,6 @@ remove_suffix (char *name, int len) } } -/* Subroutine for find_single_pointer_decl. */ - -static tree -find_single_pointer_decl_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, - void *data) -{ - tree *pdecl = (tree *) data; - - /* We are only looking for pointers at the same level as the - original tree; we must not look through any indirections. - Returning anything other than NULL_TREE will cause the caller to - not find a base. */ - if (REFERENCE_CLASS_P (*tp)) - return *tp; - - if (DECL_P (*tp) && POINTER_TYPE_P (TREE_TYPE (*tp))) - { - if (*pdecl) - { - /* We already found a pointer decl; return anything other - than NULL_TREE to unwind from walk_tree signalling that - we have a duplicate. */ - return *tp; - } - *pdecl = *tp; - } - - return NULL_TREE; -} - -/* Find the single DECL of pointer type in the tree T, used directly - rather than via an indirection, and return it. If there are zero - or more than one such DECLs, return NULL. */ - -static tree -find_single_pointer_decl (tree t) -{ - tree decl = NULL_TREE; - - if (walk_tree (&t, find_single_pointer_decl_1, &decl, NULL)) - { - /* find_single_pointer_decl_1 returns a nonzero value, causing - walk_tree to return a nonzero value, to indicate that it - found more than one pointer DECL or that it found an - indirection. */ - return NULL_TREE; - } - - return decl; -} - /* Create a new temporary name with PREFIX. Returns an identifier. */ static GTY(()) unsigned int tmp_var_id_num; @@ -517,7 +466,8 @@ create_tmp_var_raw (tree type, const char *prefix) new_type = build_type_variant (type, 0, 0); TYPE_ATTRIBUTES (new_type) = TYPE_ATTRIBUTES (type); - tmp_var = build_decl (VAR_DECL, prefix ? create_tmp_var_name (prefix) : NULL, + tmp_var = build_decl (input_location, + VAR_DECL, prefix ? create_tmp_var_name (prefix) : NULL, type); /* The variable was declared by the compiler. */ @@ -564,7 +514,7 @@ create_tmp_var (tree type, const char *prefix) static inline tree create_tmp_from_val (tree val) { - return create_tmp_var (TYPE_MAIN_VARIANT (TREE_TYPE (val)), get_name (val)); + return create_tmp_var (TREE_TYPE (val), get_name (val)); } /* Create a temporary to hold the value of VAL. If IS_FORMAL, try to reuse @@ -606,9 +556,6 @@ lookup_tmp_var (tree val, bool is_formal) } } - if (is_formal) - DECL_GIMPLE_FORMAL_TEMP_P (ret) = 1; - return ret; } @@ -619,32 +566,10 @@ lookup_tmp_var (tree val, bool is_formal) gimplify_modify_expr. */ static bool -is_gimple_formal_tmp_or_call_rhs (tree t) +is_gimple_reg_rhs_or_call (tree t) { - return TREE_CODE (t) == CALL_EXPR || is_gimple_formal_tmp_rhs (t); -} - -/* Returns true iff T is a valid RHS for an assignment to a renamed - user -- or front-end generated artificial -- variable. */ - -static bool -is_gimple_reg_or_call_rhs (tree t) -{ - /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto - and the LHS is a user variable, then we need to introduce a formal - temporary. This way the optimizers can determine that the user - variable is only modified if evaluation of the RHS does not throw. - - Don't force a temp of a non-renamable type; the copy could be - arbitrarily expensive. Instead we will generate a VDEF for - the assignment. */ - - if (is_gimple_reg_type (TREE_TYPE (t)) - && ((TREE_CODE (t) == CALL_EXPR && TREE_SIDE_EFFECTS (t)) - || tree_could_throw_p (t))) - return false; - - return is_gimple_formal_tmp_or_call_rhs (t); + return (get_gimple_rhs_class (TREE_CODE (t)) != GIMPLE_INVALID_RHS + || TREE_CODE (t) == CALL_EXPR); } /* Return true if T is a valid memory RHS or a CALL_EXPR. Note that @@ -652,33 +577,18 @@ is_gimple_reg_or_call_rhs (tree t) rationale for this in gimplify_modify_expr. */ static bool -is_gimple_mem_or_call_rhs (tree t) +is_gimple_mem_rhs_or_call (tree t) { /* If we're dealing with a renamable type, either source or dest must be - a renamed variable. Also force a temporary if the type doesn't need - to be stored in memory, since it's cheap and prevents erroneous - tailcalls (PR 17526). */ - if (is_gimple_reg_type (TREE_TYPE (t)) - || (TYPE_MODE (TREE_TYPE (t)) != BLKmode - && (TREE_CODE (t) != CALL_EXPR - || ! aggregate_value_p (t, t)))) + a renamed variable. */ + if (is_gimple_reg_type (TREE_TYPE (t))) return is_gimple_val (t); else - return is_gimple_formal_tmp_or_call_rhs (t); + return (is_gimple_val (t) || is_gimple_lvalue (t) + || TREE_CODE (t) == CALL_EXPR); } - -/* Returns a formal temporary variable initialized with VAL. PRE_P is as - in gimplify_expr. Only use this function if: - - 1) The value of the unfactored expression represented by VAL will not - change between the initialization and use of the temporary, and - 2) The temporary will not be otherwise modified. - - For instance, #1 means that this is inappropriate for SAVE_EXPR temps, - and #2 means it is inappropriate for && temps. - - For other cases, use get_initialized_tmp_var instead. */ +/* Helper for get_formal_tmp_var and get_initialized_tmp_var. */ static tree internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p, @@ -688,37 +598,20 @@ internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p, /* Notice that we explicitly allow VAL to be a CALL_EXPR so that we can create an INIT_EXPR and convert it into a GIMPLE_CALL below. */ - gimplify_expr (&val, pre_p, post_p, is_gimple_formal_tmp_or_call_rhs, + gimplify_expr (&val, pre_p, post_p, is_gimple_reg_rhs_or_call, fb_rvalue); t = lookup_tmp_var (val, is_formal); - if (is_formal) - { - tree u = find_single_pointer_decl (val); - - if (u && TREE_CODE (u) == VAR_DECL && DECL_BASED_ON_RESTRICT_P (u)) - u = DECL_GET_RESTRICT_BASE (u); - if (u && TYPE_RESTRICT (TREE_TYPE (u))) - { - if (DECL_BASED_ON_RESTRICT_P (t)) - gcc_assert (u == DECL_GET_RESTRICT_BASE (t)); - else - { - DECL_BASED_ON_RESTRICT_P (t) = 1; - SET_DECL_RESTRICT_BASE (t, u); - } - } - } - - if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE - || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) + if (is_formal + && (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE + || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)) DECL_GIMPLE_REG_P (t) = 1; mod = build2 (INIT_EXPR, TREE_TYPE (t), t, unshare_expr (val)); if (EXPR_HAS_LOCATION (val)) - SET_EXPR_LOCUS (mod, EXPR_LOCUS (val)); + SET_EXPR_LOCATION (mod, EXPR_LOCATION (val)); else SET_EXPR_LOCATION (mod, input_location); @@ -737,9 +630,17 @@ internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p, return t; } -/* Returns a formal temporary variable initialized with VAL. PRE_P - points to a sequence where side-effects needed to compute VAL should be - stored. */ +/* Returns a formal temporary variable initialized with VAL. PRE_P is as + in gimplify_expr. Only use this function if: + + 1) The value of the unfactored expression represented by VAL will not + change between the initialization and use of the temporary, and + 2) The temporary will not be otherwise modified. + + For instance, #1 means that this is inappropriate for SAVE_EXPR temps, + and #2 means it is inappropriate for && temps. + + For other cases, use get_initialized_tmp_var instead. */ tree get_formal_tmp_var (tree val, gimple_seq *pre_p) @@ -771,7 +672,7 @@ declare_vars (tree vars, gimple scope, bool debug_info) temps = nreverse (last); - block = gimple_block (scope); + block = gimple_bind_block (scope); gcc_assert (!block || TREE_CODE (block) == BLOCK); if (!block || !debug_info) { @@ -914,7 +815,7 @@ gimple_set_do_not_emit_location (gimple g) gimple_set_plf (g, GF_PLF_1, true); } -/* Set the location for gimple statement GS to LOCUS. */ +/* Set the location for gimple statement GS to LOCATION. */ static void annotate_one_with_location (gimple gs, location_t location) @@ -954,7 +855,7 @@ annotate_all_with_location_after (gimple_seq seq, gimple_stmt_iterator gsi, } -/* Set the location for all the statements in a sequence STMT_P to LOCUS. */ +/* Set the location for all the statements in a sequence STMT_P to LOCATION. */ void annotate_all_with_location (gimple_seq stmt_p, location_t location) @@ -1244,13 +1145,21 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p) omp_add_variable (gimplify_omp_ctxp, t, GOVD_LOCAL | GOVD_SEEN); DECL_SEEN_IN_BIND_EXPR_P (t) = 1; + + if (DECL_HARD_REGISTER (t) && !is_global_var (t) && cfun) + cfun->has_local_explicit_reg_vars = true; } /* Preliminarily mark non-addressed complex variables as eligible for promotion to gimple registers. We'll transform their uses - as we find them. */ - if ((TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE - || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) + as we find them. + We exclude complex types if not optimizing because they can be + subject to partial stores in GNU C by means of the __real__ and + __imag__ operators and we cannot promote them to total stores + (see gimplify_modify_expr_complex_part). */ + if (optimize + && (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE + || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) && !TREE_THIS_VOLATILE (t) && (TREE_CODE (t) == VAR_DECL && !DECL_HARD_REGISTER (t)) && !needs_to_live_in_memory (t)) @@ -1447,7 +1356,11 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p) { tree init = DECL_INITIAL (decl); - if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) + if (TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST + || (!TREE_STATIC (decl) + && flag_stack_check == GENERIC_STACK_CHECK + && compare_tree_int (DECL_SIZE_UNIT (decl), + STACK_CHECK_MAX_VAR_SIZE) > 0)) gimplify_vla_decl (decl, seq_p); if (init && init != error_mark_node) @@ -1485,7 +1398,7 @@ static enum gimplify_status gimplify_loop_expr (tree *expr_p, gimple_seq *pre_p) { tree saved_label = gimplify_ctxp->exit_label; - tree start_label = create_artificial_label (); + tree start_label = create_artificial_label (UNKNOWN_LOCATION); gimplify_seq_add_stmt (pre_p, gimple_build_label (start_label)); @@ -1625,20 +1538,64 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) } len = i; + if (!VEC_empty (tree, labels)) + sort_case_labels (labels); + if (!default_case) { - gimple new_default; + tree type = TREE_TYPE (switch_expr); /* If the switch has no default label, add one, so that we jump - around the switch body. */ - default_case = build3 (CASE_LABEL_EXPR, void_type_node, NULL_TREE, - NULL_TREE, create_artificial_label ()); - new_default = gimple_build_label (CASE_LABEL (default_case)); - gimplify_seq_add_stmt (&switch_body_seq, new_default); - } + around the switch body. If the labels already cover the whole + range of type, add the default label pointing to one of the + existing labels. */ + if (type == void_type_node) + type = TREE_TYPE (SWITCH_COND (switch_expr)); + if (len + && INTEGRAL_TYPE_P (type) + && TYPE_MIN_VALUE (type) + && TYPE_MAX_VALUE (type) + && tree_int_cst_equal (CASE_LOW (VEC_index (tree, labels, 0)), + TYPE_MIN_VALUE (type))) + { + tree low, high = CASE_HIGH (VEC_index (tree, labels, len - 1)); + if (!high) + high = CASE_LOW (VEC_index (tree, labels, len - 1)); + if (tree_int_cst_equal (high, TYPE_MAX_VALUE (type))) + { + for (i = 1; i < len; i++) + { + high = CASE_LOW (VEC_index (tree, labels, i)); + low = CASE_HIGH (VEC_index (tree, labels, i - 1)); + if (!low) + low = CASE_LOW (VEC_index (tree, labels, i - 1)); + if ((TREE_INT_CST_LOW (low) + 1 + != TREE_INT_CST_LOW (high)) + || (TREE_INT_CST_HIGH (low) + + (TREE_INT_CST_LOW (high) == 0) + != TREE_INT_CST_HIGH (high))) + break; + } + if (i == len) + default_case = build3 (CASE_LABEL_EXPR, void_type_node, + NULL_TREE, NULL_TREE, + CASE_LABEL (VEC_index (tree, + labels, 0))); + } + } - if (!VEC_empty (tree, labels)) - sort_case_labels (labels); + if (!default_case) + { + gimple new_default; + + default_case + = build3 (CASE_LABEL_EXPR, void_type_node, + NULL_TREE, NULL_TREE, + create_artificial_label (UNKNOWN_LOCATION)); + new_default = gimple_build_label (CASE_LABEL (default_case)); + gimplify_seq_add_stmt (&switch_body_seq, new_default); + } + } gimple_switch = gimple_build_switch_vec (SWITCH_COND (switch_expr), default_case, labels); @@ -1685,7 +1642,7 @@ build_and_jump (tree *label_p) if (*label_p == NULL_TREE) { - tree label = create_artificial_label (); + tree label = create_artificial_label (UNKNOWN_LOCATION); *label_p = label; } @@ -1806,7 +1763,8 @@ canonicalize_addr_expr (tree *expr_p) the expression pointer type. */ ddatype = TREE_TYPE (datype); pddatype = build_pointer_type (ddatype); - if (!useless_type_conversion_p (pddatype, ddatype)) + if (!useless_type_conversion_p (TYPE_MAIN_VARIANT (TREE_TYPE (expr)), + pddatype)) return; /* The lower bound and element sizes must be constant. */ @@ -1821,6 +1779,10 @@ canonicalize_addr_expr (tree *expr_p) TYPE_MIN_VALUE (TYPE_DOMAIN (datype)), NULL_TREE, NULL_TREE); *expr_p = build1 (ADDR_EXPR, pddatype, *expr_p); + + /* We can have stripped a required restrict qualifier above. */ + if (!useless_type_conversion_p (TREE_TYPE (expr), TREE_TYPE (*expr_p))) + *expr_p = fold_convert (TREE_TYPE (expr), *expr_p); } /* *EXPR_P is a NOP_EXPR or CONVERT_EXPR. Remove it and/or other conversions @@ -1830,8 +1792,9 @@ static enum gimplify_status gimplify_conversion (tree *expr_p) { tree tem; + location_t loc = EXPR_LOCATION (*expr_p); gcc_assert (CONVERT_EXPR_P (*expr_p)); - + /* Then strip away all but the outermost conversion. */ STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0)); @@ -1842,17 +1805,13 @@ gimplify_conversion (tree *expr_p) /* Attempt to avoid NOP_EXPR by producing reference to a subtype. For example this fold (subclass *)&A into &A->subclass avoiding a need for statement. */ - if (TREE_CODE (*expr_p) == NOP_EXPR + if (CONVERT_EXPR_P (*expr_p) && POINTER_TYPE_P (TREE_TYPE (*expr_p)) && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0))) - && (tem = maybe_fold_offset_to_reference - (TREE_OPERAND (*expr_p, 0), - integer_zero_node, TREE_TYPE (TREE_TYPE (*expr_p))))) - { - tree ptr_type = build_pointer_type (TREE_TYPE (tem)); - if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type)) - *expr_p = build_fold_addr_expr_with_type (tem, ptr_type); - } + && (tem = maybe_fold_offset_to_address + (EXPR_LOCATION (*expr_p), TREE_OPERAND (*expr_p, 0), + integer_zero_node, TREE_TYPE (*expr_p))) != NULL_TREE) + *expr_p = tem; /* If we still have a conversion at the toplevel, then canonicalize some constructs. */ @@ -1872,9 +1831,18 @@ gimplify_conversion (tree *expr_p) canonicalize_addr_expr (expr_p); } + /* If we have a conversion to a non-register type force the + use of a VIEW_CONVERT_EXPR instead. */ + if (CONVERT_EXPR_P (*expr_p) && !is_gimple_reg_type (TREE_TYPE (*expr_p))) + *expr_p = fold_build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (*expr_p), + TREE_OPERAND (*expr_p, 0)); + return GS_OK; } +/* Nonlocal VLAs seen in the current function. */ +static struct pointer_set_t *nonlocal_vlas; + /* Gimplify a VAR_DECL or PARM_DECL. Returns GS_OK if we expanded a DECL_VALUE_EXPR, and it's worth re-examining things. */ @@ -1905,7 +1873,36 @@ gimplify_var_or_parm_decl (tree *expr_p) /* If the decl is an alias for another expression, substitute it now. */ if (DECL_HAS_VALUE_EXPR_P (decl)) { - *expr_p = unshare_expr (DECL_VALUE_EXPR (decl)); + tree value_expr = DECL_VALUE_EXPR (decl); + + /* For referenced nonlocal VLAs add a decl for debugging purposes + to the current function. */ + if (TREE_CODE (decl) == VAR_DECL + && TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST + && nonlocal_vlas != NULL + && TREE_CODE (value_expr) == INDIRECT_REF + && TREE_CODE (TREE_OPERAND (value_expr, 0)) == VAR_DECL + && decl_function_context (decl) != current_function_decl) + { + struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; + while (ctx && ctx->region_type == ORT_WORKSHARE) + ctx = ctx->outer_context; + if (!ctx && !pointer_set_insert (nonlocal_vlas, decl)) + { + tree copy = copy_node (decl), block; + + lang_hooks.dup_lang_specific_decl (copy); + SET_DECL_RTL (copy, NULL_RTX); + TREE_USED (copy) = 1; + block = DECL_INITIAL (current_function_decl); + TREE_CHAIN (copy) = BLOCK_VARS (block); + BLOCK_VARS (block) = copy; + SET_DECL_VALUE_EXPR (copy, unshare_expr (value_expr)); + DECL_HAS_VALUE_EXPR_P (copy) = 1; + } + } + + *expr_p = unshare_expr (value_expr); return GS_OK; } @@ -1943,6 +1940,7 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, VEC(tree,heap) *stack; enum gimplify_status ret = GS_OK, tret; int i; + location_t loc = EXPR_LOCATION (*expr_p); /* Create a stack of the subexpressions so later we can walk them in order from inner to outer. */ @@ -1954,7 +1952,7 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, restart: /* Fold INDIRECT_REFs now to turn them into ARRAY_REFs. */ if (TREE_CODE (*p) == INDIRECT_REF) - *p = fold_indirect_ref (*p); + *p = fold_indirect_ref_loc (loc, *p); if (handled_component_p (*p)) ; @@ -1999,7 +1997,7 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, { TREE_OPERAND (t, 2) = low; tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, - post_p, is_gimple_formal_tmp_reg, + post_p, is_gimple_reg, fb_rvalue); ret = MIN (ret, tret); } @@ -2013,13 +2011,13 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, /* Divide the element size by the alignment of the element type (above). */ - elmt_size = size_binop (EXACT_DIV_EXPR, elmt_size, factor); + elmt_size = size_binop_loc (loc, EXACT_DIV_EXPR, elmt_size, factor); if (!is_gimple_min_invariant (elmt_size)) { TREE_OPERAND (t, 3) = elmt_size; tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, - post_p, is_gimple_formal_tmp_reg, + post_p, is_gimple_reg, fb_rvalue); ret = MIN (ret, tret); } @@ -2036,13 +2034,13 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, = size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT); /* Divide the offset by its alignment. */ - offset = size_binop (EXACT_DIV_EXPR, offset, factor); + offset = size_binop_loc (loc, EXACT_DIV_EXPR, offset, factor); if (!is_gimple_min_invariant (offset)) { TREE_OPERAND (t, 2) = offset; tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, - post_p, is_gimple_formal_tmp_reg, + post_p, is_gimple_reg, fb_rvalue); ret = MIN (ret, tret); } @@ -2065,19 +2063,11 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF) { - /* Gimplify the dimension. - Temporary fix for gcc.c-torture/execute/20040313-1.c. - Gimplify non-constant array indices into a temporary - variable. - FIXME - The real fix is to gimplify post-modify - expressions into a minimal gimple lvalue. However, that - exposes bugs in alias analysis. The alias analyzer does - not handle &PTR->FIELD very well. Will fix after the - branch is merged into mainline (dnovillo 2004-05-03). */ + /* Gimplify the dimension. */ if (!is_gimple_min_invariant (TREE_OPERAND (t, 1))) { tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p, - is_gimple_formal_tmp_reg, fb_rvalue); + is_gimple_val, fb_rvalue); ret = MIN (ret, tret); } } @@ -2134,6 +2124,7 @@ gimplify_self_mod_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, bool postfix; enum tree_code arith_code; enum gimplify_status ret; + location_t loc = EXPR_LOCATION (*expr_p); code = TREE_CODE (*expr_p); @@ -2169,9 +2160,18 @@ gimplify_self_mod_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, rhs = TREE_OPERAND (*expr_p, 1); /* For postfix operator, we evaluate the LHS to an rvalue and then use - that as the result value and in the postqueue operation. */ + that as the result value and in the postqueue operation. We also + make sure to make lvalue a minimal lval, see + gcc.c-torture/execute/20040313-1.c for an example where this matters. */ if (postfix) { + if (!is_gimple_min_lval (lvalue)) + { + mark_addressable (lvalue); + lvalue = build_fold_addr_expr_loc (input_location, lvalue); + gimplify_expr (&lvalue, pre_p, post_p, is_gimple_val, fb_rvalue); + lvalue = build_fold_indirect_ref_loc (input_location, lvalue); + } ret = gimplify_expr (&lhs, pre_p, post_p, is_gimple_val, fb_rvalue); if (ret == GS_ERROR) return ret; @@ -2180,9 +2180,9 @@ gimplify_self_mod_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, /* For POINTERs increment, use POINTER_PLUS_EXPR. */ if (POINTER_TYPE_P (TREE_TYPE (lhs))) { - rhs = fold_convert (sizetype, rhs); + rhs = fold_convert_loc (loc, sizetype, rhs); if (arith_code == MINUS_EXPR) - rhs = fold_build1 (NEGATE_EXPR, TREE_TYPE (rhs), rhs); + rhs = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (rhs), rhs); arith_code = POINTER_PLUS_EXPR; } @@ -2231,10 +2231,11 @@ maybe_with_size_expr (tree *expr_p) /* Helper for gimplify_call_expr. Gimplify a single argument *ARG_P - Store any side-effects in PRE_P. */ + Store any side-effects in PRE_P. CALL_LOCATION is the location of + the CALL_EXPR. */ static enum gimplify_status -gimplify_arg (tree *arg_p, gimple_seq *pre_p) +gimplify_arg (tree *arg_p, gimple_seq *pre_p, location_t call_location) { bool (*test) (tree); fallback_t fb; @@ -2252,6 +2253,11 @@ gimplify_arg (tree *arg_p, gimple_seq *pre_p) /* If this is a variable sized type, we must remember the size. */ maybe_with_size_expr (arg_p); + /* FIXME diagnostics: This will mess up gcc.dg/Warray-bounds.c. */ + /* Make sure arguments have the same location as the function call + itself. */ + protected_set_expr_location (*arg_p, call_location); + /* There is a sequence point before a function call. Side effects in the argument list must occur before the actual call. So, when gimplifying arguments, force gimplify_expr to use an internal @@ -2271,6 +2277,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) int i, nargs; gimple call; bool builtin_va_start_p = FALSE; + location_t loc = EXPR_LOCATION (*expr_p); gcc_assert (TREE_CODE (*expr_p) == CALL_EXPR); @@ -2294,7 +2301,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) fndecl = get_callee_fndecl (*expr_p); if (fndecl && DECL_BUILT_IN (fndecl)) { - tree new_tree = fold_call_expr (*expr_p, !want_value); + tree new_tree = fold_call_expr (input_location, *expr_p, !want_value); if (new_tree && new_tree != *expr_p) { @@ -2312,13 +2319,13 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) if (call_expr_nargs (*expr_p) < 2) { error ("too few arguments to function %"); - *expr_p = build_empty_stmt (); + *expr_p = build_empty_stmt (EXPR_LOCATION (*expr_p)); return GS_OK; } if (fold_builtin_next_arg (*expr_p, true)) { - *expr_p = build_empty_stmt (); + *expr_p = build_empty_stmt (EXPR_LOCATION (*expr_p)); return GS_OK; } } @@ -2340,56 +2347,14 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) else if (POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_FN (*expr_p)))) parms = TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (*expr_p)))); - /* Verify if the type of the argument matches that of the function - declaration. If we cannot verify this or there is a mismatch, - mark the call expression so it doesn't get inlined later. */ if (fndecl && DECL_ARGUMENTS (fndecl)) - { - for (i = 0, p = DECL_ARGUMENTS (fndecl); - i < nargs; - i++, p = TREE_CHAIN (p)) - { - /* We cannot distinguish a varargs function from the case - of excess parameters, still deferring the inlining decision - to the callee is possible. */ - if (!p) - break; - if (p == error_mark_node - || CALL_EXPR_ARG (*expr_p, i) == error_mark_node - || !fold_convertible_p (DECL_ARG_TYPE (p), - CALL_EXPR_ARG (*expr_p, i))) - { - CALL_CANNOT_INLINE_P (*expr_p) = 1; - break; - } - } - } + p = DECL_ARGUMENTS (fndecl); else if (parms) - { - for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p)) - { - /* If this is a varargs function defer inlining decision - to callee. */ - if (!p) - break; - if (TREE_VALUE (p) == error_mark_node - || CALL_EXPR_ARG (*expr_p, i) == error_mark_node - || TREE_CODE (TREE_VALUE (p)) == VOID_TYPE - || !fold_convertible_p (TREE_VALUE (p), - CALL_EXPR_ARG (*expr_p, i))) - { - CALL_CANNOT_INLINE_P (*expr_p) = 1; - break; - } - } - } + p = parms; else - { - if (nargs != 0) - CALL_CANNOT_INLINE_P (*expr_p) = 1; - i = 0; - p = NULL_TREE; - } + p = NULL_TREE; + for (i = 0; i < nargs && p; i++, p = TREE_CHAIN (p)) + ; /* If the last argument is __builtin_va_arg_pack () and it is not passed as a named argument, decrease the number of CALL_EXPR @@ -2409,8 +2374,9 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) tree call = *expr_p; --nargs; - *expr_p = build_call_array (TREE_TYPE (call), CALL_EXPR_FN (call), - nargs, CALL_EXPR_ARGP (call)); + *expr_p = build_call_array_loc (loc, TREE_TYPE (call), + CALL_EXPR_FN (call), + nargs, CALL_EXPR_ARGP (call)); /* Copy all CALL_EXPR flags, location and block, except CALL_EXPR_VA_ARG_PACK flag. */ @@ -2420,7 +2386,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) = CALL_EXPR_RETURN_SLOT_OPT (call); CALL_FROM_THUNK_P (*expr_p) = CALL_FROM_THUNK_P (call); CALL_CANNOT_INLINE_P (*expr_p) = CALL_CANNOT_INLINE_P (call); - SET_EXPR_LOCUS (*expr_p, EXPR_LOCUS (call)); + SET_EXPR_LOCATION (*expr_p, EXPR_LOCATION (call)); TREE_BLOCK (*expr_p) = TREE_BLOCK (call); /* Set CALL_EXPR_VA_ARG_PACK. */ @@ -2441,7 +2407,8 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) be the plain PARM_DECL. */ if ((i != 1) || !builtin_va_start_p) { - t = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p); + t = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, + EXPR_LOCATION (*expr_p)); if (t == GS_ERROR) ret = GS_ERROR; @@ -2449,10 +2416,18 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) } } + /* Verify the function result. */ + if (want_value && fndecl + && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl)))) + { + error_at (loc, "using result of function returning %"); + ret = GS_ERROR; + } + /* Try this again in case gimplification exposed something. */ if (ret != GS_ERROR) { - tree new_tree = fold_call_expr (*expr_p, !want_value); + tree new_tree = fold_call_expr (input_location, *expr_p, !want_value); if (new_tree && new_tree != *expr_p) { @@ -2508,12 +2483,15 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) condition is true or false, respectively. If null, we should generate our own to skip over the evaluation of this specific expression. + LOCUS is the source location of the COND_EXPR. + This function is the tree equivalent of do_jump. shortcut_cond_r should only be called by shortcut_cond_expr. */ static tree -shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p) +shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p, + location_t locus) { tree local_label = NULL_TREE; tree t, expr = NULL; @@ -2523,6 +2501,8 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p) shortcut_cond_expr will append the real blocks later. */ if (TREE_CODE (pred) == TRUTH_ANDIF_EXPR) { + location_t new_locus; + /* Turn if (a && b) into if (a); else goto no; @@ -2532,15 +2512,20 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p) if (false_label_p == NULL) false_label_p = &local_label; - t = shortcut_cond_r (TREE_OPERAND (pred, 0), NULL, false_label_p); + /* Keep the original source location on the first 'if'. */ + t = shortcut_cond_r (TREE_OPERAND (pred, 0), NULL, false_label_p, locus); append_to_statement_list (t, &expr); - t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, - false_label_p); + /* Set the source location of the && on the second 'if'. */ + new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus; + t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p, + new_locus); append_to_statement_list (t, &expr); } else if (TREE_CODE (pred) == TRUTH_ORIF_EXPR) { + location_t new_locus; + /* Turn if (a || b) into if (a) goto yes; @@ -2550,31 +2535,41 @@ shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p) if (true_label_p == NULL) true_label_p = &local_label; - t = shortcut_cond_r (TREE_OPERAND (pred, 0), true_label_p, NULL); + /* Keep the original source location on the first 'if'. */ + t = shortcut_cond_r (TREE_OPERAND (pred, 0), true_label_p, NULL, locus); append_to_statement_list (t, &expr); - t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, - false_label_p); + /* Set the source location of the || on the second 'if'. */ + new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus; + t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, false_label_p, + new_locus); append_to_statement_list (t, &expr); } else if (TREE_CODE (pred) == COND_EXPR) { + location_t new_locus; + /* As long as we're messing with gotos, turn if (a ? b : c) into if (a) if (b) goto yes; else goto no; else if (c) goto yes; else goto no; */ + + /* Keep the original source location on the first 'if'. Set the source + location of the ? on the second 'if'. */ + new_locus = EXPR_HAS_LOCATION (pred) ? EXPR_LOCATION (pred) : locus; expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0), shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, - false_label_p), + false_label_p, locus), shortcut_cond_r (TREE_OPERAND (pred, 2), true_label_p, - false_label_p)); + false_label_p, new_locus)); } else { expr = build3 (COND_EXPR, void_type_node, pred, build_and_jump (true_label_p), build_and_jump (false_label_p)); + SET_EXPR_LOCATION (expr, locus); } if (local_label) @@ -2606,14 +2601,24 @@ shortcut_cond_expr (tree expr) /* First do simple transformations. */ if (!else_se) { - /* If there is no 'else', turn (a && b) into if (a) if (b). */ + /* If there is no 'else', turn + if (a && b) then c + into + if (a) if (b) then c. */ while (TREE_CODE (pred) == TRUTH_ANDIF_EXPR) { + /* Keep the original source location on the first 'if'. */ + location_t locus = EXPR_HAS_LOCATION (expr) + ? EXPR_LOCATION (expr) : input_location; TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1); + /* Set the source location of the && on the second 'if'. */ + if (EXPR_HAS_LOCATION (pred)) + SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred)); then_ = shortcut_cond_expr (expr); then_se = then_ && TREE_SIDE_EFFECTS (then_); pred = TREE_OPERAND (pred, 0); expr = build3 (COND_EXPR, void_type_node, pred, then_, NULL_TREE); + SET_EXPR_LOCATION (expr, locus); } } @@ -2625,11 +2630,18 @@ shortcut_cond_expr (tree expr) if (a); else if (b); else d. */ while (TREE_CODE (pred) == TRUTH_ORIF_EXPR) { + /* Keep the original source location on the first 'if'. */ + location_t locus = EXPR_HAS_LOCATION (expr) + ? EXPR_LOCATION (expr) : input_location; TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1); + /* Set the source location of the || on the second 'if'. */ + if (EXPR_HAS_LOCATION (pred)) + SET_EXPR_LOCATION (expr, EXPR_LOCATION (pred)); else_ = shortcut_cond_expr (expr); else_se = else_ && TREE_SIDE_EFFECTS (else_); pred = TREE_OPERAND (pred, 0); expr = build3 (COND_EXPR, void_type_node, pred, NULL_TREE, else_); + SET_EXPR_LOCATION (expr, locus); } } @@ -2683,17 +2695,19 @@ shortcut_cond_expr (tree expr) /* If there was nothing else in our arms, just forward the label(s). */ if (!then_se && !else_se) - return shortcut_cond_r (pred, true_label_p, false_label_p); + return shortcut_cond_r (pred, true_label_p, false_label_p, + EXPR_HAS_LOCATION (expr) + ? EXPR_LOCATION (expr) : input_location); /* If our last subexpression already has a terminal label, reuse it. */ if (else_se) - expr = expr_last (else_); + t = expr_last (else_); else if (then_se) - expr = expr_last (then_); + t = expr_last (then_); else - expr = NULL; - if (expr && TREE_CODE (expr) == LABEL_EXPR) - end_label = LABEL_EXPR_LABEL (expr); + t = NULL; + if (t && TREE_CODE (t) == LABEL_EXPR) + end_label = LABEL_EXPR_LABEL (t); /* If we don't care about jumping to the 'else' branch, jump to the end if the condition is false. */ @@ -2714,7 +2728,9 @@ shortcut_cond_expr (tree expr) non-void function. */ jump_over_else = block_may_fallthru (then_); - pred = shortcut_cond_r (pred, true_label_p, false_label_p); + pred = shortcut_cond_r (pred, true_label_p, false_label_p, + EXPR_HAS_LOCATION (expr) + ? EXPR_LOCATION (expr) : input_location); expr = NULL; append_to_statement_list (pred, &expr); @@ -2724,7 +2740,10 @@ shortcut_cond_expr (tree expr) { if (jump_over_else) { + tree last = expr_last (expr); t = build_and_jump (&end_label); + if (EXPR_HAS_LOCATION (last)) + SET_EXPR_LOCATION (t, EXPR_LOCATION (last)); append_to_statement_list (t, &expr); } if (emit_false) @@ -2749,6 +2768,7 @@ tree gimple_boolify (tree expr) { tree type = TREE_TYPE (expr); + location_t loc = EXPR_LOCATION (expr); if (TREE_CODE (type) == BOOLEAN_TYPE) return expr; @@ -2777,7 +2797,7 @@ gimple_boolify (tree expr) default: /* Other expressions that get here must have boolean values, but might need to be converted to the appropriate mode. */ - return fold_convert (boolean_type_node, expr); + return fold_convert_loc (loc, boolean_type_node, expr); } } @@ -2860,6 +2880,7 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback) gimple gimple_cond; enum tree_code pred_code; gimple_seq seq = NULL; + location_t loc = EXPR_LOCATION (*expr_p); type = TREE_TYPE (expr); @@ -2893,18 +2914,18 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback) if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node) TREE_OPERAND (expr, 1) = - build_fold_addr_expr (TREE_OPERAND (expr, 1)); + build_fold_addr_expr_loc (loc, TREE_OPERAND (expr, 1)); if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node) TREE_OPERAND (expr, 2) = - build_fold_addr_expr (TREE_OPERAND (expr, 2)); + build_fold_addr_expr_loc (loc, TREE_OPERAND (expr, 2)); tmp = create_tmp_var (type, "iftmp"); expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2)); - result = build_fold_indirect_ref (tmp); + result = build_fold_indirect_ref_loc (loc, tmp); } /* Build the then clause, 't1 = a;'. But don't build an assignment @@ -2983,7 +3004,7 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback) have_then_clause_p = true; } else - label_true = create_artificial_label (); + label_true = create_artificial_label (UNKNOWN_LOCATION); if (TREE_OPERAND (expr, 2) != NULL && TREE_CODE (TREE_OPERAND (expr, 2)) == GOTO_EXPR && TREE_CODE (GOTO_DESTINATION (TREE_OPERAND (expr, 2))) == LABEL_DECL @@ -3001,7 +3022,7 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback) have_else_clause_p = true; } else - label_false = create_artificial_label (); + label_false = create_artificial_label (UNKNOWN_LOCATION); gimple_cond_get_ops_from_tree (COND_EXPR_COND (expr), &pred_code, &arm1, &arm2); @@ -3032,7 +3053,7 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback) && gimple_seq_may_fallthru (seq)) { gimple g; - label_cont = create_artificial_label (); + label_cont = create_artificial_label (UNKNOWN_LOCATION); g = gimple_build_goto (label_cont); @@ -3074,6 +3095,25 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback) return ret; } +/* Prepare the node pointed to by EXPR_P, an is_gimple_addressable expression, + to be marked addressable. + + We cannot rely on such an expression being directly markable if a temporary + has been created by the gimplification. In this case, we create another + temporary and initialize it with a copy, which will become a store after we + mark it addressable. This can happen if the front-end passed us something + that it could not mark addressable yet, like a Fortran pass-by-reference + parameter (int) floatvar. */ + +static void +prepare_gimple_addressable (tree *expr_p, gimple_seq *seq_p) +{ + while (handled_component_p (*expr_p)) + expr_p = &TREE_OPERAND (*expr_p, 0); + if (is_gimple_reg (*expr_p)) + *expr_p = get_initialized_tmp_var (*expr_p, seq_p, NULL); +} + /* A subroutine of gimplify_modify_expr. Replace a MODIFY_EXPR with a call to __builtin_memcpy. */ @@ -3083,15 +3123,22 @@ gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value, { tree t, to, to_ptr, from, from_ptr; gimple gs; + location_t loc = EXPR_LOCATION (*expr_p); to = TREE_OPERAND (*expr_p, 0); from = TREE_OPERAND (*expr_p, 1); - from_ptr = build_fold_addr_expr (from); - gimplify_arg (&from_ptr, seq_p); + /* Mark the RHS addressable. Beware that it may not be possible to do so + directly if a temporary has been created by the gimplification. */ + prepare_gimple_addressable (&from, seq_p); + + mark_addressable (from); + from_ptr = build_fold_addr_expr_loc (loc, from); + gimplify_arg (&from_ptr, seq_p, loc); - to_ptr = build_fold_addr_expr (to); - gimplify_arg (&to_ptr, seq_p); + mark_addressable (to); + to_ptr = build_fold_addr_expr_loc (loc, to); + gimplify_arg (&to_ptr, seq_p, loc); t = implicit_built_in_decls[BUILT_IN_MEMCPY]; @@ -3123,6 +3170,7 @@ gimplify_modify_expr_to_memset (tree *expr_p, tree size, bool want_value, { tree t, from, to, to_ptr; gimple gs; + location_t loc = EXPR_LOCATION (*expr_p); /* Assert our assumptions, to abort instead of producing wrong code silently if they are not met. Beware that the RHS CONSTRUCTOR might @@ -3137,8 +3185,8 @@ gimplify_modify_expr_to_memset (tree *expr_p, tree size, bool want_value, /* Now proceed. */ to = TREE_OPERAND (*expr_p, 0); - to_ptr = build_fold_addr_expr (to); - gimplify_arg (&to_ptr, seq_p); + to_ptr = build_fold_addr_expr_loc (loc, to); + gimplify_arg (&to_ptr, seq_p, loc); t = implicit_built_in_decls[BUILT_IN_MEMSET]; gs = gimple_build_call (t, 3, to_ptr, integer_zero_node, size); @@ -3313,9 +3361,9 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper, tree loop_entry_label, loop_exit_label, fall_thru_label; tree var, var_type, cref, tmp; - loop_entry_label = create_artificial_label (); - loop_exit_label = create_artificial_label (); - fall_thru_label = create_artificial_label (); + loop_entry_label = create_artificial_label (UNKNOWN_LOCATION); + loop_exit_label = create_artificial_label (UNKNOWN_LOCATION); + fall_thru_label = create_artificial_label (UNKNOWN_LOCATION); /* Create and initialize the index variable. */ var_type = TREE_TYPE (upper); @@ -3475,14 +3523,89 @@ gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts, gimple_predicate rhs_predicate_for (tree lhs) { - if (is_gimple_formal_tmp_var (lhs)) - return is_gimple_formal_tmp_or_call_rhs; - else if (is_gimple_reg (lhs)) - return is_gimple_reg_or_call_rhs; + if (is_gimple_reg (lhs)) + return is_gimple_reg_rhs_or_call; else - return is_gimple_mem_or_call_rhs; + return is_gimple_mem_rhs_or_call; } +/* Gimplify a C99 compound literal expression. This just means adding + the DECL_EXPR before the current statement and using its anonymous + decl instead. */ + +static enum gimplify_status +gimplify_compound_literal_expr (tree *expr_p, gimple_seq *pre_p) +{ + tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (*expr_p); + tree decl = DECL_EXPR_DECL (decl_s); + /* Mark the decl as addressable if the compound literal + expression is addressable now, otherwise it is marked too late + after we gimplify the initialization expression. */ + if (TREE_ADDRESSABLE (*expr_p)) + TREE_ADDRESSABLE (decl) = 1; + + /* Preliminarily mark non-addressed complex variables as eligible + for promotion to gimple registers. We'll transform their uses + as we find them. */ + if ((TREE_CODE (TREE_TYPE (decl)) == COMPLEX_TYPE + || TREE_CODE (TREE_TYPE (decl)) == VECTOR_TYPE) + && !TREE_THIS_VOLATILE (decl) + && !needs_to_live_in_memory (decl)) + DECL_GIMPLE_REG_P (decl) = 1; + + /* This decl isn't mentioned in the enclosing block, so add it to the + list of temps. FIXME it seems a bit of a kludge to say that + anonymous artificial vars aren't pushed, but everything else is. */ + if (DECL_NAME (decl) == NULL_TREE && !DECL_SEEN_IN_BIND_EXPR_P (decl)) + gimple_add_tmp_var (decl); + + gimplify_and_add (decl_s, pre_p); + *expr_p = decl; + return GS_OK; +} + +/* Optimize embedded COMPOUND_LITERAL_EXPRs within a CONSTRUCTOR, + return a new CONSTRUCTOR if something changed. */ + +static tree +optimize_compound_literals_in_ctor (tree orig_ctor) +{ + tree ctor = orig_ctor; + VEC(constructor_elt,gc) *elts = CONSTRUCTOR_ELTS (ctor); + unsigned int idx, num = VEC_length (constructor_elt, elts); + + for (idx = 0; idx < num; idx++) + { + tree value = VEC_index (constructor_elt, elts, idx)->value; + tree newval = value; + if (TREE_CODE (value) == CONSTRUCTOR) + newval = optimize_compound_literals_in_ctor (value); + else if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR) + { + tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (value); + tree decl = DECL_EXPR_DECL (decl_s); + tree init = DECL_INITIAL (decl); + + if (!TREE_ADDRESSABLE (value) + && !TREE_ADDRESSABLE (decl) + && init) + newval = optimize_compound_literals_in_ctor (init); + } + if (newval == value) + continue; + + if (ctor == orig_ctor) + { + ctor = copy_node (orig_ctor); + CONSTRUCTOR_ELTS (ctor) = VEC_copy (constructor_elt, gc, elts); + elts = CONSTRUCTOR_ELTS (ctor); + } + VEC_index (constructor_elt, elts, idx)->value = newval; + } + return ctor; +} + + /* A subroutine of gimplify_modify_expr. Break out elements of a CONSTRUCTOR used as an initializer into separate MODIFY_EXPRs. @@ -3501,14 +3624,11 @@ static enum gimplify_status gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, bool want_value, bool notify_temp_creation) { - tree object; - tree ctor = TREE_OPERAND (*expr_p, 1); - tree type = TREE_TYPE (ctor); + tree object, ctor, type; enum gimplify_status ret; VEC(constructor_elt,gc) *elts; - if (TREE_CODE (ctor) != CONSTRUCTOR) - return GS_UNHANDLED; + gcc_assert (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == CONSTRUCTOR); if (!notify_temp_creation) { @@ -3519,6 +3639,9 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, } object = TREE_OPERAND (*expr_p, 0); + ctor = TREE_OPERAND (*expr_p, 1) = + optimize_compound_literals_in_ctor (TREE_OPERAND (*expr_p, 1)); + type = TREE_TYPE (ctor); elts = CONSTRUCTOR_ELTS (ctor); ret = GS_ALL_DONE; @@ -3556,7 +3679,8 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, if (valid_const_initializer && num_nonzero_elements > 1 && TREE_READONLY (object) - && TREE_CODE (object) == VAR_DECL) + && TREE_CODE (object) == VAR_DECL + && (flag_merge_constants >= 2 || !TREE_ADDRESSABLE (object))) { if (notify_temp_creation) return GS_ERROR; @@ -3595,7 +3719,8 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, if (num_type_elements < 0 && int_size_in_bytes (type) >= 0) cleared = true; /* If there are "lots" of zeros, then block clear the object first. */ - else if (num_type_elements - num_nonzero_elements > CLEAR_RATIO + else if (num_type_elements - num_nonzero_elements + > CLEAR_RATIO (optimize_function_for_speed_p (cfun)) && num_nonzero_elements < num_type_elements/4) cleared = true; /* ??? This bit ought not be needed. For any element not present @@ -3611,8 +3736,13 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, be dropped to memory, and then memcpy'd out. Don't do this for sparse arrays, though, as it's more efficient to follow the standard CONSTRUCTOR behavior of memset followed by - individual element initialization. */ - if (valid_const_initializer && !cleared) + individual element initialization. Also don't do this for small + all-zero initializers (which aren't big enough to merit + clearing), and don't try to make bitwise copies of + TREE_ADDRESSABLE types. */ + if (valid_const_initializer + && !(cleared || num_nonzero_elements == 0) + && !TREE_ADDRESSABLE (type)) { HOST_WIDE_INT size = int_size_in_bytes (type); unsigned int align; @@ -3634,7 +3764,9 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, else align = TYPE_ALIGN (type); - if (size > 0 && !can_move_by_pieces (size, align)) + if (size > 0 + && num_nonzero_elements > 1 + && !can_move_by_pieces (size, align)) { tree new_tree; @@ -3910,11 +4042,14 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, switch (TREE_CODE (*from_p)) { case VAR_DECL: - /* If we're assigning from a constant constructor, move the - constructor expression to the RHS of the MODIFY_EXPR. */ + /* If we're assigning from a read-only variable initialized with + a constructor, do the direct assignment from the constructor, + but only if neither source nor target are volatile since this + latter assignment might end up being done on a per-field basis. */ if (DECL_INITIAL (*from_p) - && TYPE_READONLY (TREE_TYPE (*from_p)) + && TREE_READONLY (*from_p) && !TREE_THIS_VOLATILE (*from_p) + && !TREE_THIS_VOLATILE (*to_p) && TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR) { tree old_from = *from_p; @@ -4060,11 +4195,6 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, || (DECL_P (*to_p) && DECL_REGISTER (*to_p))) /* Don't force regs into memory. */ use_target = false; - else if (TREE_CODE (*to_p) == VAR_DECL - && DECL_GIMPLE_FORMAL_TEMP_P (*to_p)) - /* Don't use the original target if it's a formal temp; we - don't want to take their addresses. */ - use_target = false; else if (TREE_CODE (*expr_p) == INIT_EXPR) /* It's OK to use the target directly if it's being initialized. */ @@ -4117,6 +4247,26 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, return GS_OK; } + case COMPOUND_LITERAL_EXPR: + { + tree complit = TREE_OPERAND (*expr_p, 1); + tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (complit); + tree decl = DECL_EXPR_DECL (decl_s); + tree init = DECL_INITIAL (decl); + + /* struct T x = (struct T) { 0, 1, 2 } can be optimized + into struct T x = { 0, 1, 2 } if the address of the + compound literal has never been taken. */ + if (!TREE_ADDRESSABLE (complit) + && !TREE_ADDRESSABLE (decl) + && init) + { + *expr_p = copy_node (*expr_p); + TREE_OPERAND (*expr_p, 1) = init; + return GS_OK; + } + } + default: ret = GS_UNHANDLED; break; @@ -4192,6 +4342,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, tree *to_p = &TREE_OPERAND (*expr_p, 0); enum gimplify_status ret = GS_UNHANDLED; gimple assign; + location_t loc = EXPR_LOCATION (*expr_p); gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR || TREE_CODE (*expr_p) == INIT_EXPR); @@ -4199,12 +4350,11 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, /* Insert pointer conversions required by the middle-end that are not required by the frontend. This fixes middle-end type checking for for example gcc.dg/redecl-6.c. */ - if (POINTER_TYPE_P (TREE_TYPE (*to_p)) - && lang_hooks.types_compatible_p (TREE_TYPE (*to_p), TREE_TYPE (*from_p))) + if (POINTER_TYPE_P (TREE_TYPE (*to_p))) { STRIP_USELESS_TYPE_CONVERSION (*from_p); if (!useless_type_conversion_p (TREE_TYPE (*to_p), TREE_TYPE (*from_p))) - *from_p = fold_convert (TREE_TYPE (*to_p), *from_p); + *from_p = fold_convert_loc (loc, TREE_TYPE (*to_p), *from_p); } /* See if any simplifications can be done based on what the RHS is. */ @@ -4310,7 +4460,10 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, gimple_call_set_lhs (assign, *to_p); } else - assign = gimple_build_assign (*to_p, *from_p); + { + assign = gimple_build_assign (*to_p, *from_p); + gimple_set_location (assign, EXPR_LOCATION (*expr_p)); + } gimplify_seq_add_stmt (pre_p, assign); @@ -4343,14 +4496,15 @@ gimplify_variable_sized_compare (tree *expr_p) tree op0 = TREE_OPERAND (*expr_p, 0); tree op1 = TREE_OPERAND (*expr_p, 1); tree t, arg, dest, src; + location_t loc = EXPR_LOCATION (*expr_p); arg = TYPE_SIZE_UNIT (TREE_TYPE (op0)); arg = unshare_expr (arg); arg = SUBSTITUTE_PLACEHOLDER_IN_EXPR (arg, op0); - src = build_fold_addr_expr (op1); - dest = build_fold_addr_expr (op0); + src = build_fold_addr_expr_loc (loc, op1); + dest = build_fold_addr_expr_loc (loc, op0); t = implicit_built_in_decls[BUILT_IN_MEMCMP]; - t = build_call_expr (t, 3, dest, src, arg); + t = build_call_expr_loc (loc, t, 3, dest, src, arg); *expr_p = build2 (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), t, integer_zero_node); @@ -4363,17 +4517,18 @@ gimplify_variable_sized_compare (tree *expr_p) static enum gimplify_status gimplify_scalar_mode_aggregate_compare (tree *expr_p) { + location_t loc = EXPR_LOCATION (*expr_p); tree op0 = TREE_OPERAND (*expr_p, 0); tree op1 = TREE_OPERAND (*expr_p, 1); tree type = TREE_TYPE (op0); tree scalar_type = lang_hooks.types.type_for_mode (TYPE_MODE (type), 1); - op0 = fold_build1 (VIEW_CONVERT_EXPR, scalar_type, op0); - op1 = fold_build1 (VIEW_CONVERT_EXPR, scalar_type, op1); + op0 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, scalar_type, op0); + op1 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, scalar_type, op1); *expr_p - = fold_build2 (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), op0, op1); + = fold_build2_loc (loc, TREE_CODE (*expr_p), TREE_TYPE (*expr_p), op0, op1); return GS_OK; } @@ -4385,20 +4540,20 @@ gimplify_scalar_mode_aggregate_compare (tree *expr_p) a && b ? true : false - gimplify_cond_expr will do the rest. - - PRE_P points to the list where side effects that must happen before - *EXPR_P should be stored. */ + LOCUS is the source location to be put on the generated COND_EXPR. + gimplify_cond_expr will do the rest. */ static enum gimplify_status -gimplify_boolean_expr (tree *expr_p) +gimplify_boolean_expr (tree *expr_p, location_t locus) { /* Preserve the original type of the expression. */ tree type = TREE_TYPE (*expr_p); *expr_p = build3 (COND_EXPR, type, *expr_p, - fold_convert (type, boolean_true_node), - fold_convert (type, boolean_false_node)); + fold_convert_loc (locus, type, boolean_true_node), + fold_convert_loc (locus, type, boolean_false_node)); + + SET_EXPR_LOCATION (*expr_p, locus); return GS_OK; } @@ -4500,6 +4655,7 @@ gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) tree expr = *expr_p; tree op0 = TREE_OPERAND (expr, 0); enum gimplify_status ret; + location_t loc = EXPR_LOCATION (*expr_p); switch (TREE_CODE (op0)) { @@ -4521,7 +4677,7 @@ gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) tree t_op00 = TREE_TYPE (op00); if (!useless_type_conversion_p (t_expr, t_op00)) - op00 = fold_convert (TREE_TYPE (expr), op00); + op00 = fold_convert_loc (loc, TREE_TYPE (expr), op00); *expr_p = op00; ret = GS_OK; } @@ -4540,8 +4696,9 @@ gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) if (tree_ssa_useless_type_conversion (TREE_OPERAND (op0, 0))) op0 = TREE_OPERAND (op0, 0); - *expr_p = fold_convert (TREE_TYPE (expr), - build_fold_addr_expr (TREE_OPERAND (op0, 0))); + *expr_p = fold_convert_loc (loc, TREE_TYPE (expr), + build_fold_addr_expr_loc (loc, + TREE_OPERAND (op0, 0))); ret = GS_OK; break; @@ -4551,23 +4708,39 @@ gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) gcc.dg/c99-array-lval-1.c. The gimplifier will correctly make the implied temporary explicit. */ - /* Mark the RHS addressable. */ + /* Make the operand addressable. */ ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p, is_gimple_addressable, fb_either); - if (ret != GS_ERROR) - { - op0 = TREE_OPERAND (expr, 0); + if (ret == GS_ERROR) + break; - /* For various reasons, the gimplification of the expression - may have made a new INDIRECT_REF. */ - if (TREE_CODE (op0) == INDIRECT_REF) - goto do_indirect_ref; + /* Then mark it. Beware that it may not be possible to do so directly + if a temporary has been created by the gimplification. */ + prepare_gimple_addressable (&TREE_OPERAND (expr, 0), pre_p); - /* Make sure TREE_CONSTANT and TREE_SIDE_EFFECTS are set properly. */ - recompute_tree_invariant_for_addr_expr (expr); + op0 = TREE_OPERAND (expr, 0); + + /* For various reasons, the gimplification of the expression + may have made a new INDIRECT_REF. */ + if (TREE_CODE (op0) == INDIRECT_REF) + goto do_indirect_ref; + + mark_addressable (TREE_OPERAND (expr, 0)); + + /* The FEs may end up building ADDR_EXPRs early on a decl with + an incomplete type. Re-build ADDR_EXPRs in canonical form + here. */ + if (!types_compatible_p (TREE_TYPE (op0), TREE_TYPE (TREE_TYPE (expr)))) + *expr_p = build_fold_addr_expr (op0); + + /* Make sure TREE_CONSTANT and TREE_SIDE_EFFECTS are set properly. */ + recompute_tree_invariant_for_addr_expr (*expr_p); + + /* If we re-built the ADDR_EXPR add a conversion to the original type + if required. */ + if (!useless_type_conversion_p (TREE_TYPE (expr), TREE_TYPE (*expr_p))) + *expr_p = fold_convert (TREE_TYPE (expr), *expr_p); - mark_addressable (TREE_OPERAND (expr, 0)); - } break; } @@ -4761,6 +4934,8 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) mark_addressable (TREE_VALUE (link)); if (tret == GS_ERROR) { + if (EXPR_HAS_LOCATION (TREE_VALUE (link))) + input_location = EXPR_LOCATION (TREE_VALUE (link)); error ("memory input %d is not directly addressable", i); ret = tret; } @@ -4779,14 +4954,18 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) for (link = ASM_CLOBBERS (expr); link; ++i, link = TREE_CHAIN (link)) VEC_safe_push (tree, gc, clobbers, link); - - stmt = gimple_build_asm_vec (TREE_STRING_POINTER (ASM_STRING (expr)), - inputs, outputs, clobbers); - gimple_asm_set_volatile (stmt, ASM_VOLATILE_P (expr)); - gimple_asm_set_input (stmt, ASM_INPUT_P (expr)); + /* Do not add ASMs with errors to the gimple IL stream. */ + if (ret != GS_ERROR) + { + stmt = gimple_build_asm_vec (TREE_STRING_POINTER (ASM_STRING (expr)), + inputs, outputs, clobbers); - gimplify_seq_add_stmt (pre_p, stmt); + gimple_asm_set_volatile (stmt, ASM_VOLATILE_P (expr)); + gimple_asm_set_input (stmt, ASM_INPUT_P (expr)); + + gimplify_seq_add_stmt (pre_p, stmt); + } return ret; } @@ -5255,9 +5434,9 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) switch (default_kind) { case OMP_CLAUSE_DEFAULT_NONE: - error ("%qs not specified in enclosing parallel", - IDENTIFIER_POINTER (DECL_NAME (decl))); - error ("%Henclosing parallel", &ctx->location); + error ("%qE not specified in enclosing parallel", + DECL_NAME (decl)); + error_at (ctx->location, "enclosing parallel"); /* FALLTHRU */ case OMP_CLAUSE_DEFAULT_SHARED: flags |= GOVD_SHARED; @@ -5313,6 +5492,20 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) goto do_outer; } + if ((n->value & (GOVD_SEEN | GOVD_LOCAL)) == 0 + && (flags & (GOVD_SEEN | GOVD_LOCAL)) == GOVD_SEEN + && DECL_SIZE (decl) + && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) + { + splay_tree_node n2; + tree t = DECL_VALUE_EXPR (decl); + gcc_assert (TREE_CODE (t) == INDIRECT_REF); + t = TREE_OPERAND (t, 0); + gcc_assert (DECL_P (t)); + n2 = splay_tree_lookup (ctx->variables, (splay_tree_key) t); + n2->value |= GOVD_SEEN; + } + shared = ((flags | n->value) & GOVD_SHARED) != 0; ret = lang_hooks.decls.omp_disregard_value_expr (decl, shared); @@ -5348,8 +5541,8 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl) { if (ctx == gimplify_omp_ctxp) { - error ("iteration variable %qs should be private", - IDENTIFIER_POINTER (DECL_NAME (decl))); + error ("iteration variable %qE should be private", + DECL_NAME (decl)); n->value = GOVD_PRIVATE; return true; } @@ -5362,11 +5555,11 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl) && gimplify_omp_ctxp->outer_context == ctx))) { if ((n->value & GOVD_FIRSTPRIVATE) != 0) - error ("iteration variable %qs should not be firstprivate", - IDENTIFIER_POINTER (DECL_NAME (decl))); + error ("iteration variable %qE should not be firstprivate", + DECL_NAME (decl)); else if ((n->value & GOVD_REDUCTION) != 0) - error ("iteration variable %qs should not be reduction", - IDENTIFIER_POINTER (DECL_NAME (decl))); + error ("iteration variable %qE should not be reduction", + DECL_NAME (decl)); } return (ctx == gimplify_omp_ctxp || (ctx->region_type == ORT_COMBINED_PARALLEL @@ -5528,8 +5721,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, && region_type == ORT_WORKSHARE && omp_check_private (ctx, decl)) { - error ("%s variable %qs is private in outer context", - check_non_private, IDENTIFIER_POINTER (DECL_NAME (decl))); + error ("%s variable %qE is private in outer context", + check_non_private, DECL_NAME (decl)); remove = true; } break; @@ -5623,7 +5816,7 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) else gcc_unreachable (); - clause = build_omp_clause (code); + clause = build_omp_clause (input_location, code); OMP_CLAUSE_DECL (clause) = decl; OMP_CLAUSE_CHAIN (clause) = *list_p; if (private_debug) @@ -5785,7 +5978,8 @@ static enum gimplify_status gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { tree for_stmt, decl, var, t; - enum gimplify_status ret = GS_OK; + enum gimplify_status ret = GS_ALL_DONE; + enum gimplify_status tret; gimple gfor; gimple_seq for_body, for_pre_body; int i; @@ -5835,8 +6029,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) else var = decl; - ret |= gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, + tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, is_gimple_val, fb_rvalue); + ret = MIN (ret, tret); if (ret == GS_ERROR) return ret; @@ -5845,8 +6040,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gcc_assert (COMPARISON_CLASS_P (t)); gcc_assert (TREE_OPERAND (t, 0) == decl); - ret |= gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, + tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, is_gimple_val, fb_rvalue); + ret = MIN (ret, tret); /* Handle OMP_FOR_INCR. */ t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); @@ -5893,8 +6089,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gcc_unreachable (); } - ret |= gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, + tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL, is_gimple_val, fb_rvalue); + ret = MIN (ret, tret); break; default: @@ -5983,12 +6180,7 @@ goa_lhs_expr_p (tree expr, tree addr) /* Also include casts to other type variants. The C front end is fond of adding these for e.g. volatile variables. This is like STRIP_TYPE_NOPS but includes the main variant lookup. */ - while ((CONVERT_EXPR_P (expr) - || TREE_CODE (expr) == NON_LVALUE_EXPR) - && TREE_OPERAND (expr, 0) != error_mark_node - && (TYPE_MAIN_VARIANT (TREE_TYPE (expr)) - == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (expr, 0))))) - expr = TREE_OPERAND (expr, 0); + STRIP_USELESS_TYPE_CONVERSION (expr); if (TREE_CODE (expr) == INDIRECT_REF) { @@ -5997,8 +6189,7 @@ goa_lhs_expr_p (tree expr, tree addr) && (CONVERT_EXPR_P (expr) || TREE_CODE (expr) == NON_LVALUE_EXPR) && TREE_CODE (expr) == TREE_CODE (addr) - && TYPE_MAIN_VARIANT (TREE_TYPE (expr)) - == TYPE_MAIN_VARIANT (TREE_TYPE (addr))) + && types_compatible_p (TREE_TYPE (expr), TREE_TYPE (addr))) { expr = TREE_OPERAND (expr, 0); addr = TREE_OPERAND (addr, 0); @@ -6038,12 +6229,27 @@ goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr, switch (TREE_CODE_CLASS (TREE_CODE (expr))) { case tcc_binary: + case tcc_comparison: saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, lhs_addr, lhs_var); case tcc_unary: saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, lhs_addr, lhs_var); break; + case tcc_expression: + switch (TREE_CODE (expr)) + { + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, + lhs_addr, lhs_var); + saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, + lhs_addr, lhs_var); + break; + default: + break; + } + break; default: break; } @@ -6194,16 +6400,12 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, if (gimple_test_f == is_gimple_reg) gcc_assert (fallback & (fb_rvalue | fb_lvalue)); else if (gimple_test_f == is_gimple_val - || gimple_test_f == is_gimple_formal_tmp_rhs - || gimple_test_f == is_gimple_formal_tmp_or_call_rhs - || gimple_test_f == is_gimple_formal_tmp_reg - || gimple_test_f == is_gimple_formal_tmp_var || gimple_test_f == is_gimple_call_addr || gimple_test_f == is_gimple_condexpr || gimple_test_f == is_gimple_mem_rhs - || gimple_test_f == is_gimple_mem_or_call_rhs + || gimple_test_f == is_gimple_mem_rhs_or_call || gimple_test_f == is_gimple_reg_rhs - || gimple_test_f == is_gimple_reg_or_call_rhs + || gimple_test_f == is_gimple_reg_rhs_or_call || gimple_test_f == is_gimple_asm_val) gcc_assert (fallback & fb_rvalue); else if (gimple_test_f == is_gimple_min_lval @@ -6268,7 +6470,8 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, } /* Do any language-specific gimplification. */ - ret = lang_hooks.gimplify_expr (expr_p, pre_p, post_p); + ret = ((enum gimplify_status) + lang_hooks.gimplify_expr (expr_p, pre_p, post_p)); if (ret == GS_OK) { if (*expr_p == NULL_TREE) @@ -6337,6 +6540,10 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none); break; + case COMPOUND_LITERAL_EXPR: + ret = gimplify_compound_literal_expr (expr_p, pre_p); + break; + case MODIFY_EXPR: case INIT_EXPR: ret = gimplify_modify_expr (expr_p, pre_p, post_p, @@ -6345,7 +6552,8 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: - ret = gimplify_boolean_expr (expr_p); + /* Pass the source location of the outer expression. */ + ret = gimplify_boolean_expr (expr_p, saved_location); break; case TRUTH_NOT_EXPR: @@ -6401,7 +6609,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, break; case INDIRECT_REF: - *expr_p = fold_indirect_ref (*expr_p); + *expr_p = fold_indirect_ref_loc (input_location, *expr_p); if (*expr_p != save_expr) break; /* else fall through. */ @@ -6462,8 +6670,12 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, /* If the target is not LABEL, then it is a computed jump and the target needs to be gimplified. */ if (TREE_CODE (GOTO_DESTINATION (*expr_p)) != LABEL_DECL) - ret = gimplify_expr (&GOTO_DESTINATION (*expr_p), pre_p, - NULL, is_gimple_val, fb_rvalue); + { + ret = gimplify_expr (&GOTO_DESTINATION (*expr_p), pre_p, + NULL, is_gimple_val, fb_rvalue); + if (ret == GS_ERROR) + break; + } gimplify_seq_add_stmt (pre_p, gimple_build_goto (GOTO_DESTINATION (*expr_p))); break; @@ -6548,6 +6760,24 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, } break; + case TARGET_MEM_REF: + { + enum gimplify_status r0 = GS_ALL_DONE, r1 = GS_ALL_DONE; + + if (TMR_SYMBOL (*expr_p)) + r0 = gimplify_expr (&TMR_SYMBOL (*expr_p), pre_p, + post_p, is_gimple_lvalue, fb_either); + else if (TMR_BASE (*expr_p)) + r0 = gimplify_expr (&TMR_BASE (*expr_p), pre_p, + post_p, is_gimple_val, fb_either); + if (TMR_INDEX (*expr_p)) + r1 = gimplify_expr (&TMR_INDEX (*expr_p), pre_p, + post_p, is_gimple_val, fb_rvalue); + /* TMR_STEP and TMR_OFFSET are always integer constants. */ + ret = MIN (r0, r1); + } + break; + case NON_LVALUE_EXPR: /* This should have been stripped above. */ gcc_unreachable (); @@ -6565,6 +6795,13 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, eval = cleanup = NULL; gimplify_and_add (TREE_OPERAND (*expr_p, 0), &eval); gimplify_and_add (TREE_OPERAND (*expr_p, 1), &cleanup); + /* Don't create bogus GIMPLE_TRY with empty cleanup. */ + if (gimple_seq_empty_p (cleanup)) + { + gimple_seq_add_seq (pre_p, eval); + ret = GS_ALL_DONE; + break; + } try_ = gimple_build_try (eval, cleanup, TREE_CODE (*expr_p) == TRY_FINALLY_EXPR ? GIMPLE_TRY_FINALLY @@ -6603,6 +6840,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, gimplify_and_add (EH_FILTER_FAILURE (*expr_p), &failure); ehf = gimple_build_eh_filter (EH_FILTER_TYPES (*expr_p), failure); + gimple_set_no_warning (ehf, TREE_NO_WARNING (*expr_p)); gimple_eh_filter_set_must_not_throw (ehf, EH_FILTER_MUST_NOT_THROW (*expr_p)); gimplify_seq_add_stmt (pre_p, ehf); @@ -6610,19 +6848,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, break; } - case CHANGE_DYNAMIC_TYPE_EXPR: - { - gimple cdt; - - ret = gimplify_expr (&CHANGE_DYNAMIC_TYPE_LOCATION (*expr_p), - pre_p, post_p, is_gimple_reg, fb_lvalue); - cdt = gimple_build_cdt (CHANGE_DYNAMIC_TYPE_NEW_TYPE (*expr_p), - CHANGE_DYNAMIC_TYPE_LOCATION (*expr_p)); - gimplify_seq_add_stmt (pre_p, cdt); - ret = GS_ALL_DONE; - } - break; - case OBJ_TYPE_REF: { enum gimplify_status r0, r1; @@ -6735,30 +6960,26 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, The second is gimple immediate saving a need for extra statement. */ if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST - && (tmp = maybe_fold_offset_to_reference - (TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1), - TREE_TYPE (TREE_TYPE (*expr_p))))) - { - tree ptr_type = build_pointer_type (TREE_TYPE (tmp)); - if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type)) - { - *expr_p = build_fold_addr_expr_with_type (tmp, ptr_type); - break; - } - } + && (tmp = maybe_fold_offset_to_address + (EXPR_LOCATION (*expr_p), + TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1), + TREE_TYPE (*expr_p)))) + { + *expr_p = tmp; + break; + } /* Convert (void *)&a + 4 into (void *)&a[1]. */ if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == NOP_EXPR && TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p, 0),0))) - && (tmp = maybe_fold_offset_to_reference - (TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0), - TREE_OPERAND (*expr_p, 1), - TREE_TYPE (TREE_TYPE - (TREE_OPERAND (TREE_OPERAND (*expr_p, 0), - 0)))))) + && (tmp = maybe_fold_offset_to_address + (EXPR_LOCATION (*expr_p), + TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0), + TREE_OPERAND (*expr_p, 1), + TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p, 0), + 0))))) { - tmp = build_fold_addr_expr (tmp); *expr_p = fold_convert (TREE_TYPE (*expr_p), tmp); break; } @@ -6952,7 +7173,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, && code != ASM_EXPR && code != BIND_EXPR && code != CATCH_EXPR - && code != COND_EXPR + && (code != COND_EXPR || gimplify_ctxp->allow_rhs_cond_expr) && code != EH_FILTER_EXPR && code != GOTO_EXPR && code != LABEL_EXPR @@ -6993,11 +7214,11 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, /* An lvalue will do. Take the address of the expression, store it in a temporary, and replace the expression with an INDIRECT_REF of that temporary. */ - tmp = build_fold_addr_expr (*expr_p); + tmp = build_fold_addr_expr_loc (input_location, *expr_p); gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue); *expr_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (tmp)), tmp); } - else if ((fallback & fb_rvalue) && is_gimple_formal_tmp_or_call_rhs (*expr_p)) + else if ((fallback & fb_rvalue) && is_gimple_reg_rhs_or_call (*expr_p)) { /* An rvalue will do. Assign the gimplified expression into a new temporary TMP and replace the original expression with @@ -7009,12 +7230,14 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, /* The postqueue might change the value of the expression between the initialization and use of the temporary, so we can't use a formal temp. FIXME do we care? */ - *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); + { + *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); + if (TREE_CODE (TREE_TYPE (*expr_p)) == COMPLEX_TYPE + || TREE_CODE (TREE_TYPE (*expr_p)) == VECTOR_TYPE) + DECL_GIMPLE_REG_P (*expr_p) = 1; + } else *expr_p = get_formal_tmp_var (*expr_p, pre_p); - - if (TREE_CODE (*expr_p) != SSA_NAME) - DECL_GIMPLE_FORMAL_TEMP_P (*expr_p) = 1; } else { @@ -7091,6 +7314,18 @@ gimplify_type_sizes (tree type, gimple_seq *list_p) /* These types may not have declarations, so handle them here. */ gimplify_type_sizes (TREE_TYPE (type), list_p); gimplify_type_sizes (TYPE_DOMAIN (type), list_p); + /* When not optimizing, ensure VLA bounds aren't removed. */ + if (!optimize + && TYPE_DOMAIN (type) + && INTEGRAL_TYPE_P (TYPE_DOMAIN (type))) + { + t = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); + if (t && TREE_CODE (t) == VAR_DECL && DECL_ARTIFICIAL (t)) + DECL_IGNORED_P (t) = 0; + t = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + if (t && TREE_CODE (t) == VAR_DECL && DECL_ARTIFICIAL (t)) + DECL_IGNORED_P (t) = 0; + } break; case RECORD_TYPE: @@ -7100,6 +7335,8 @@ gimplify_type_sizes (tree type, gimple_seq *list_p) if (TREE_CODE (field) == FIELD_DECL) { gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), list_p); + gimplify_one_sizepos (&DECL_SIZE (field), list_p); + gimplify_one_sizepos (&DECL_SIZE_UNIT (field), list_p); gimplify_type_sizes (TREE_TYPE (field), list_p); } break; @@ -7177,7 +7414,7 @@ gimplify_one_sizepos (tree *expr_p, gimple_seq *stmt_p) tmp = build1 (NOP_EXPR, type, expr); stmt = gimplify_assign (*expr_p, tmp, stmt_p); if (EXPR_HAS_LOCATION (expr)) - gimple_set_location (stmt, *EXPR_LOCUS (expr)); + gimple_set_location (stmt, EXPR_LOCATION (expr)); else gimple_set_location (stmt, input_location); } @@ -7199,6 +7436,10 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms) timevar_push (TV_TREE_GIMPLIFY); + /* Initialize for optimize_insn_for_s{ize,peed}_p possibly called during + gimplification. */ + default_rtl_profile (); + gcc_assert (gimplify_ctxp == NULL); push_gimplify_context (&gctx); @@ -7209,6 +7450,9 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms) unshare_body (body_p, fndecl); unvisit_body (body_p, fndecl); + if (cgraph_node (fndecl)->origin) + nonlocal_vlas = pointer_set_create (); + /* Make sure input_location isn't set to something weird. */ input_location = DECL_SOURCE_LOCATION (fndecl); @@ -7244,6 +7488,12 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms) gimple_bind_set_body (outer_bind, parm_stmts); } + if (nonlocal_vlas) + { + pointer_set_destroy (nonlocal_vlas); + nonlocal_vlas = NULL; + } + pop_gimplify_context (outer_bind); gcc_assert (gimplify_ctxp == NULL); @@ -7271,6 +7521,8 @@ gimplify_function_tree (tree fndecl) gimple_seq seq; gimple bind; + gcc_assert (!gimple_body (fndecl)); + oldfn = current_function_decl; current_function_decl = fndecl; if (DECL_STRUCT_FUNCTION (fndecl)) @@ -7324,10 +7576,10 @@ gimplify_function_tree (tree fndecl) x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_ENTER]; gimplify_seq_add_stmt (&body, gimple_build_call (x, 0)); gimplify_seq_add_stmt (&body, tf); - new_bind = gimple_build_bind (NULL, body, gimple_block (bind)); + new_bind = gimple_build_bind (NULL, body, gimple_bind_block (bind)); /* Clear the block for BIND, since it is no longer directly inside the function, but within a try block. */ - gimple_set_block (bind, NULL); + gimple_bind_set_block (bind, NULL); /* Replace the current function body with the body wrapped in the try/finally TF. */ @@ -7337,6 +7589,7 @@ gimplify_function_tree (tree fndecl) } DECL_SAVED_TREE (fndecl) = NULL_TREE; + cfun->curr_properties = PROP_gimple_any; current_function_decl = oldfn; pop_cfun (); @@ -7368,6 +7621,10 @@ gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p) gimplify_expr (gimple_cond_rhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); break; + case GIMPLE_SWITCH: + gimplify_expr (gimple_switch_index_ptr (stmt), &pre, NULL, + is_gimple_val, fb_rvalue); + break; case GIMPLE_OMP_ATOMIC_LOAD: gimplify_expr (gimple_omp_atomic_load_rhs_ptr (stmt), &pre, NULL, is_gimple_val, fb_rvalue); @@ -7442,9 +7699,9 @@ gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p) } lhs = gimple_get_lhs (stmt); - /* If regimplification of the LHS changed it in a way that requires - a simple RHS, create temporary. */ - if (orig_lhs != lhs && !is_gimple_formal_tmp_var (lhs)) + /* If the LHS changed it in a way that requires a simple RHS, + create temporary. */ + if (lhs && !is_gimple_reg (lhs)) { bool need_temp = false; @@ -7493,19 +7750,11 @@ gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p) { tree temp = create_tmp_var (TREE_TYPE (lhs), NULL); - DECL_GIMPLE_FORMAL_TEMP_P (temp) = 1; if (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE || TREE_CODE (TREE_TYPE (lhs)) == VECTOR_TYPE) DECL_GIMPLE_REG_P (temp) = 1; if (TREE_CODE (orig_lhs) == SSA_NAME) orig_lhs = SSA_NAME_VAR (orig_lhs); - if (TREE_CODE (orig_lhs) == VAR_DECL - && DECL_BASED_ON_RESTRICT_P (orig_lhs)) - { - DECL_BASED_ON_RESTRICT_P (temp) = 1; - SET_DECL_RESTRICT_BASE (temp, - DECL_GET_RESTRICT_BASE (orig_lhs)); - } if (gimple_in_ssa_p (cfun)) temp = make_ssa_name (temp, NULL); @@ -7518,6 +7767,10 @@ gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p) break; } + if (gimple_referenced_vars (cfun)) + for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t)) + add_referenced_var (t); + if (!gimple_seq_empty_p (pre)) { if (gimple_in_ssa_p (cfun)) @@ -7532,10 +7785,6 @@ gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p) if (post_stmt) gsi_insert_after (gsi_p, post_stmt, GSI_NEW_STMT); - if (gimple_referenced_vars (cfun)) - for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t)) - add_referenced_var (t); - pop_gimplify_context (NULL); }