Mercurial > hg > CbC > CbC_gcc
diff gcc/gimplify.c @ 63:b7f97abdc517 gcc-4.6-20100522
update gcc from gcc-4.5.0 to gcc-4.6
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 24 May 2010 12:47:05 +0900 |
parents | 77e2b8dfacca |
children | f6334be47118 |
line wrap: on
line diff
--- a/gcc/gimplify.c Fri Feb 12 23:41:23 2010 +0900 +++ b/gcc/gimplify.c Mon May 24 12:47:05 2010 +0900 @@ -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, 2009 + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Major work done by Sebastian Pop <s.pop@laposte.net>, Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>. @@ -27,11 +27,11 @@ #include "tm.h" #include "tree.h" #include "rtl.h" -#include "varray.h" #include "gimple.h" #include "tree-iterator.h" #include "tree-inline.h" #include "diagnostic.h" +#include "tree-pretty-print.h" #include "langhooks.h" #include "langhooks-def.h" #include "tree-flow.h" @@ -40,7 +40,6 @@ #include "except.h" #include "hashtab.h" #include "flags.h" -#include "real.h" #include "function.h" #include "output.h" #include "expr.h" @@ -75,9 +74,10 @@ enum omp_region_type { ORT_WORKSHARE = 0, - ORT_TASK = 1, ORT_PARALLEL = 2, - ORT_COMBINED_PARALLEL = 3 + ORT_COMBINED_PARALLEL = 3, + ORT_TASK = 4, + ORT_UNTIED_TASK = 5 }; struct gimplify_omp_ctx @@ -158,7 +158,7 @@ During gimplification, we need to manipulate statement sequences before the def/use vectors have been constructed. */ -static void +void gimplify_seq_add_stmt (gimple_seq *seq_p, gimple gs) { gimple_stmt_iterator si; @@ -319,7 +319,7 @@ c->privatized_types = pointer_set_create (); c->location = input_location; c->region_type = region_type; - if (region_type != ORT_TASK) + if ((region_type & ORT_TASK) == 0) c->default_kind = OMP_CLAUSE_DEFAULT_SHARED; else c->default_kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; @@ -340,47 +340,6 @@ static void omp_add_variable (struct gimplify_omp_ctx *, tree, unsigned int); static bool omp_notice_variable (struct gimplify_omp_ctx *, tree, bool); -/* A subroutine of append_to_statement_list{,_force}. T is not NULL. */ - -static void -append_to_statement_list_1 (tree t, tree *list_p) -{ - tree list = *list_p; - tree_stmt_iterator i; - - if (!list) - { - if (t && TREE_CODE (t) == STATEMENT_LIST) - { - *list_p = t; - return; - } - *list_p = list = alloc_stmt_list (); - } - - i = tsi_last (list); - tsi_link_after (&i, t, TSI_CONTINUE_LINKING); -} - -/* Add T to the end of the list container pointed to by LIST_P. - If T is an expression with no effects, it is ignored. */ - -void -append_to_statement_list (tree t, tree *list_p) -{ - if (t && TREE_SIDE_EFFECTS (t)) - append_to_statement_list_1 (t, list_p); -} - -/* Similar, but the statement is always added, regardless of side effects. */ - -void -append_to_statement_list_force (tree t, tree *list_p) -{ - if (t != NULL_TREE) - append_to_statement_list_1 (t, list_p); -} - /* Both gimplify the statement T and append it to *SEQ_P. This function behaves exactly as gimplify_stmt, but you don't have to pass T as a reference. */ @@ -508,6 +467,23 @@ return tmp_var; } +/* Create a new temporary variable declaration of type TYPE by calling + create_tmp_var and if TYPE is a vector or a complex number, mark the new + temporary as gimple register. */ + +tree +create_tmp_reg (tree type, const char *prefix) +{ + tree tmp; + + tmp = create_tmp_var (type, prefix); + if (TREE_CODE (type) == COMPLEX_TYPE + || TREE_CODE (type) == VECTOR_TYPE) + DECL_GIMPLE_REG_P (tmp) = 1; + + return tmp; +} + /* Create a temporary with a name derived from VAL. Subroutine of lookup_tmp_var; nobody else should call this function. */ @@ -844,9 +820,44 @@ annotate_one_with_location (gs, location); } } - - -/* Similar to copy_tree_r() but do not copy SAVE_EXPR or TARGET_EXPR nodes. + +/* This page contains routines to unshare tree nodes, i.e. to duplicate tree + nodes that are referenced more than once in GENERIC functions. This is + necessary because gimplification (translation into GIMPLE) is performed + by modifying tree nodes in-place, so gimplication of a shared node in a + first context could generate an invalid GIMPLE form in a second context. + + This is achieved with a simple mark/copy/unmark algorithm that walks the + GENERIC representation top-down, marks nodes with TREE_VISITED the first + time it encounters them, duplicates them if they already have TREE_VISITED + set, and finally removes the TREE_VISITED marks it has set. + + The algorithm works only at the function level, i.e. it generates a GENERIC + representation of a function with no nodes shared within the function when + passed a GENERIC function (except for nodes that are allowed to be shared). + + At the global level, it is also necessary to unshare tree nodes that are + referenced in more than one function, for the same aforementioned reason. + This requires some cooperation from the front-end. There are 2 strategies: + + 1. Manual unsharing. The front-end needs to call unshare_expr on every + expression that might end up being shared across functions. + + 2. Deep unsharing. This is an extension of regular unsharing. Instead + of calling unshare_expr on expressions that might be shared across + functions, the front-end pre-marks them with TREE_VISITED. This will + ensure that they are unshared on the first reference within functions + when the regular unsharing algorithm runs. The counterpart is that + this algorithm must look deeper than for manual unsharing, which is + specified by LANG_HOOKS_DEEP_UNSHARING. + + If there are only few specific cases of node sharing across functions, it is + probably easier for a front-end to unshare the expressions manually. On the + contrary, if the expressions generated at the global level are as widespread + as expressions generated within functions, deep unsharing is very likely the + way to go. */ + +/* Similar to copy_tree_r but do not copy SAVE_EXPR or TARGET_EXPR nodes. These nodes model computations that should only be done once. If we were to unshare something like SAVE_EXPR(i++), the gimplification process would create wrong code. */ @@ -854,21 +865,39 @@ static tree mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data) { - enum tree_code code = TREE_CODE (*tp); - /* Don't unshare types, decls, constants and SAVE_EXPR nodes. */ - if (TREE_CODE_CLASS (code) == tcc_type - || TREE_CODE_CLASS (code) == tcc_declaration - || TREE_CODE_CLASS (code) == tcc_constant - || code == SAVE_EXPR || code == TARGET_EXPR - /* We can't do anything sensible with a BLOCK used as an expression, - but we also can't just die when we see it because of non-expression - uses. So just avert our eyes and cross our fingers. Silly Java. */ - || code == BLOCK) + tree t = *tp; + enum tree_code code = TREE_CODE (t); + + /* Do not copy SAVE_EXPR or TARGET_EXPR nodes themselves, but copy + their subtrees if we can make sure to do it only once. */ + if (code == SAVE_EXPR || code == TARGET_EXPR) + { + if (data && !pointer_set_insert ((struct pointer_set_t *)data, t)) + ; + else + *walk_subtrees = 0; + } + + /* Stop at types, decls, constants like copy_tree_r. */ + else if (TREE_CODE_CLASS (code) == tcc_type + || TREE_CODE_CLASS (code) == tcc_declaration + || TREE_CODE_CLASS (code) == tcc_constant + /* We can't do anything sensible with a BLOCK used as an + expression, but we also can't just die when we see it + because of non-expression uses. So we avert our eyes + and cross our fingers. Silly Java. */ + || code == BLOCK) *walk_subtrees = 0; + + /* Cope with the statement expression extension. */ + else if (code == STATEMENT_LIST) + ; + + /* Leave the bulk of the work to copy_tree_r itself. */ else { gcc_assert (code != BIND_EXPR); - copy_tree_r (tp, walk_subtrees, data); + copy_tree_r (tp, walk_subtrees, NULL); } return NULL_TREE; @@ -876,16 +905,10 @@ /* Callback for walk_tree to unshare most of the shared trees rooted at *TP. If *TP has been visited already (i.e., TREE_VISITED (*TP) == 1), - then *TP is deep copied by calling copy_tree_r. - - This unshares the same trees as copy_tree_r with the exception of - SAVE_EXPR nodes. These nodes model computations that should only be - done once. If we were to unshare something like SAVE_EXPR(i++), the - gimplification process would create wrong code. */ + then *TP is deep copied by calling mostly_copy_tree_r. */ static tree -copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) +copy_if_shared_r (tree *tp, int *walk_subtrees, void *data) { tree t = *tp; enum tree_code code = TREE_CODE (t); @@ -908,27 +931,29 @@ any deeper. */ else if (TREE_VISITED (t)) { - walk_tree (tp, mostly_copy_tree_r, NULL, NULL); + walk_tree (tp, mostly_copy_tree_r, data, NULL); *walk_subtrees = 0; } - /* Otherwise, mark the tree as visited and keep looking. */ + /* Otherwise, mark the node as visited and keep looking. */ else TREE_VISITED (t) = 1; return NULL_TREE; } -static tree -unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - if (TREE_VISITED (*tp)) - TREE_VISITED (*tp) = 0; - else - *walk_subtrees = 0; - - return NULL_TREE; +/* Unshare most of the shared trees rooted at *TP. */ + +static inline void +copy_if_shared (tree *tp) +{ + /* If the language requires deep unsharing, we need a pointer set to make + sure we don't repeatedly unshare subtrees of unshareable nodes. */ + struct pointer_set_t *visited + = lang_hooks.deep_unsharing ? pointer_set_create () : NULL; + walk_tree (tp, copy_if_shared_r, visited, NULL); + if (visited) + pointer_set_destroy (visited); } /* Unshare all the trees in BODY_P, a pointer into the body of FNDECL, and the @@ -940,12 +965,40 @@ { struct cgraph_node *cgn = cgraph_node (fndecl); - walk_tree (body_p, copy_if_shared_r, NULL, NULL); + copy_if_shared (body_p); + if (body_p == &DECL_SAVED_TREE (fndecl)) for (cgn = cgn->nested; cgn; cgn = cgn->next_nested) unshare_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl); } +/* Callback for walk_tree to unmark the visited trees rooted at *TP. + Subtrees are walked until the first unvisited node is encountered. */ + +static tree +unmark_visited_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) +{ + tree t = *tp; + + /* If this node has been visited, unmark it and keep looking. */ + if (TREE_VISITED (t)) + TREE_VISITED (t) = 0; + + /* Otherwise, don't look any deeper. */ + else + *walk_subtrees = 0; + + return NULL_TREE; +} + +/* Unmark the visited trees rooted at *TP. */ + +static inline void +unmark_visited (tree *tp) +{ + walk_tree (tp, unmark_visited_r, NULL, NULL); +} + /* Likewise, but mark all trees as not visited. */ static void @@ -953,7 +1006,8 @@ { struct cgraph_node *cgn = cgraph_node (fndecl); - walk_tree (body_p, unmark_visited_r, NULL, NULL); + unmark_visited (body_p); + if (body_p == &DECL_SAVED_TREE (fndecl)) for (cgn = cgn->nested; cgn; cgn = cgn->next_nested) unvisit_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl); @@ -1212,17 +1266,27 @@ hard_function_value generates a PARALLEL, we'll die during normal expansion of structure assignments; there's special code in expand_return to handle this case that does not exist in expand_expr. */ - if (!result_decl - || aggregate_value_p (result_decl, TREE_TYPE (current_function_decl))) - result = result_decl; + if (!result_decl) + result = NULL_TREE; + else if (aggregate_value_p (result_decl, TREE_TYPE (current_function_decl))) + { + if (TREE_CODE (DECL_SIZE (result_decl)) != INTEGER_CST) + { + if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (result_decl))) + gimplify_type_sizes (TREE_TYPE (result_decl), pre_p); + /* Note that we don't use gimplify_vla_decl because the RESULT_DECL + should be effectively allocated by the caller, i.e. all calls to + this function must be subject to the Return Slot Optimization. */ + gimplify_one_sizepos (&DECL_SIZE (result_decl), pre_p); + gimplify_one_sizepos (&DECL_SIZE_UNIT (result_decl), pre_p); + } + result = result_decl; + } else if (gimplify_ctxp->return_temp) result = gimplify_ctxp->return_temp; else { - result = create_tmp_var (TREE_TYPE (result_decl), NULL); - if (TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE - || TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE) - DECL_GIMPLE_REG_P (result) = 1; + result = create_tmp_reg (TREE_TYPE (result_decl), NULL); /* ??? With complex control flow (usually involving abnormal edges), we can wind up warning about an uninitialized value for this. Due @@ -1888,9 +1952,10 @@ { tree *p; VEC(tree,heap) *stack; - enum gimplify_status ret = GS_OK, tret; + enum gimplify_status ret = GS_ALL_DONE, tret; int i; location_t loc = EXPR_LOCATION (*expr_p); + tree expr = *expr_p; /* Create a stack of the subexpressions so later we can walk them in order from inner to outer. */ @@ -2044,11 +2109,12 @@ if ((fallback & fb_rvalue) && TREE_CODE (*expr_p) == COMPONENT_REF) { canonicalize_component_ref (expr_p); - ret = MIN (ret, GS_OK); } VEC_free (tree, heap, stack); + gcc_assert (*expr_p == expr || ret != GS_ALL_DONE); + return ret; } @@ -2720,6 +2786,36 @@ tree type = TREE_TYPE (expr); location_t loc = EXPR_LOCATION (expr); + if (TREE_CODE (expr) == NE_EXPR + && TREE_CODE (TREE_OPERAND (expr, 0)) == CALL_EXPR + && integer_zerop (TREE_OPERAND (expr, 1))) + { + tree call = TREE_OPERAND (expr, 0); + tree fn = get_callee_fndecl (call); + + /* For __builtin_expect ((long) (x), y) recurse into x as well + if x is truth_value_p. */ + if (fn + && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (fn) == BUILT_IN_EXPECT + && call_expr_nargs (call) == 2) + { + tree arg = CALL_EXPR_ARG (call, 0); + if (arg) + { + if (TREE_CODE (arg) == NOP_EXPR + && TREE_TYPE (arg) == TREE_TYPE (call)) + arg = TREE_OPERAND (arg, 0); + if (truth_value_p (TREE_CODE (arg))) + { + arg = gimple_boolify (arg); + CALL_EXPR_ARG (call, 0) + = fold_convert_loc (loc, TREE_TYPE (call), arg); + } + } + } + } + if (TREE_CODE (type) == BOOLEAN_TYPE) return expr; @@ -2823,71 +2919,67 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback) { tree expr = *expr_p; - tree tmp, type, arm1, arm2; + tree type = TREE_TYPE (expr); + location_t loc = EXPR_LOCATION (expr); + tree tmp, arm1, arm2; enum gimplify_status ret; tree label_true, label_false, label_cont; bool have_then_clause_p, have_else_clause_p; gimple gimple_cond; enum tree_code pred_code; gimple_seq seq = NULL; - location_t loc = EXPR_LOCATION (*expr_p); - - type = TREE_TYPE (expr); /* If this COND_EXPR has a value, copy the values into a temporary within the arms. */ - if (! VOID_TYPE_P (type)) - { + if (!VOID_TYPE_P (type)) + { + tree then_ = TREE_OPERAND (expr, 1), else_ = TREE_OPERAND (expr, 2); tree result; - /* If an rvalue is ok or we do not require an lvalue, avoid creating - an addressable temporary. */ - if (((fallback & fb_rvalue) - || !(fallback & fb_lvalue)) + /* If either an rvalue is ok or we do not require an lvalue, create the + temporary. But we cannot do that if the type is addressable. */ + if (((fallback & fb_rvalue) || !(fallback & fb_lvalue)) && !TREE_ADDRESSABLE (type)) { if (gimplify_ctxp->allow_rhs_cond_expr /* If either branch has side effects or could trap, it can't be evaluated unconditionally. */ - && !TREE_SIDE_EFFECTS (TREE_OPERAND (*expr_p, 1)) - && !generic_expr_could_trap_p (TREE_OPERAND (*expr_p, 1)) - && !TREE_SIDE_EFFECTS (TREE_OPERAND (*expr_p, 2)) - && !generic_expr_could_trap_p (TREE_OPERAND (*expr_p, 2))) + && !TREE_SIDE_EFFECTS (then_) + && !generic_expr_could_trap_p (then_) + && !TREE_SIDE_EFFECTS (else_) + && !generic_expr_could_trap_p (else_)) return gimplify_pure_cond_expr (expr_p, pre_p); - result = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp"); - ret = GS_ALL_DONE; + tmp = create_tmp_var (type, "iftmp"); + result = tmp; } + + /* Otherwise, only create and copy references to the values. */ else { - tree type = build_pointer_type (TREE_TYPE (expr)); - - if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node) - 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_loc (loc, TREE_OPERAND (expr, 2)); + type = build_pointer_type (type); + + if (!VOID_TYPE_P (TREE_TYPE (then_))) + then_ = build_fold_addr_expr_loc (loc, then_); + + if (!VOID_TYPE_P (TREE_TYPE (else_))) + else_ = build_fold_addr_expr_loc (loc, else_); + + expr + = build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), then_, else_); 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_loc (loc, tmp); } - /* Build the then clause, 't1 = a;'. But don't build an assignment - if this branch is void; in C++ it can be, if it's a throw. */ - if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node) - TREE_OPERAND (expr, 1) - = build2 (MODIFY_EXPR, TREE_TYPE (tmp), tmp, TREE_OPERAND (expr, 1)); - - /* Build the else clause, 't1 = b;'. */ - if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node) - TREE_OPERAND (expr, 2) - = build2 (MODIFY_EXPR, TREE_TYPE (tmp), tmp, TREE_OPERAND (expr, 2)); + /* Build the new then clause, `tmp = then_;'. But don't build the + assignment if the value is void; in C++ it can be if it's a throw. */ + if (!VOID_TYPE_P (TREE_TYPE (then_))) + TREE_OPERAND (expr, 1) = build2 (MODIFY_EXPR, type, tmp, then_); + + /* Similarly, build the new else clause, `tmp = else_;'. */ + if (!VOID_TYPE_P (TREE_TYPE (else_))) + TREE_OPERAND (expr, 2) = build2 (MODIFY_EXPR, type, tmp, else_); TREE_TYPE (expr) = void_type_node; recalculate_side_effects (expr); @@ -3718,25 +3810,14 @@ && num_nonzero_elements > 1 && !can_move_by_pieces (size, align)) { - tree new_tree; - if (notify_temp_creation) return GS_ERROR; - new_tree = create_tmp_var_raw (type, "C"); - - gimple_add_tmp_var (new_tree); - TREE_STATIC (new_tree) = 1; - TREE_READONLY (new_tree) = 1; - DECL_INITIAL (new_tree) = ctor; - if (align > DECL_ALIGN (new_tree)) - { - DECL_ALIGN (new_tree) = align; - DECL_USER_ALIGN (new_tree) = 1; - } - walk_tree (&DECL_INITIAL (new_tree), force_labels_r, NULL, NULL); - - TREE_OPERAND (*expr_p, 1) = new_tree; + walk_tree (&ctor, force_labels_r, NULL, NULL); + ctor = tree_output_constant_def (ctor); + if (!useless_type_conversion_p (type, TREE_TYPE (ctor))) + ctor = build1 (VIEW_CONVERT_EXPR, type, ctor); + TREE_OPERAND (*expr_p, 1) = ctor; /* This is no longer an assignment of a CONSTRUCTOR, but we still may have processing to do on the LHS. So @@ -3745,13 +3826,28 @@ } } + /* If the target is volatile and we have non-zero elements + initialize the target from a temporary. */ + if (TREE_THIS_VOLATILE (object) + && !TREE_ADDRESSABLE (type) + && num_nonzero_elements > 0) + { + tree temp = create_tmp_var (TYPE_MAIN_VARIANT (type), NULL); + TREE_OPERAND (*expr_p, 0) = temp; + *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p), + *expr_p, + build2 (MODIFY_EXPR, void_type_node, + object, temp)); + return GS_OK; + } + if (notify_temp_creation) return GS_OK; - /* If there are nonzero elements, pre-evaluate to capture elements - overlapping with the lhs into temporaries. We must do this before - clearing to fetch the values before they are zeroed-out. */ - if (num_nonzero_elements > 0) + /* If there are nonzero elements and if needed, pre-evaluate to capture + elements overlapping with the lhs into temporaries. We must do this + before clearing to fetch the values before they are zeroed-out. */ + if (num_nonzero_elements > 0 && TREE_CODE (*expr_p) != INIT_EXPR) { preeval_data.lhs_base_decl = get_base_address (object); if (!DECL_P (preeval_data.lhs_base_decl)) @@ -3920,7 +4016,7 @@ tree sub = t; tree subtype; - STRIP_USELESS_TYPE_CONVERSION (sub); + STRIP_NOPS (sub); subtype = TREE_TYPE (sub); if (!POINTER_TYPE_P (subtype)) return NULL_TREE; @@ -3935,18 +4031,80 @@ /* *(foo *)&fooarray => fooarray[0] */ if (TREE_CODE (optype) == ARRAY_TYPE + && TREE_CODE (TYPE_SIZE (TREE_TYPE (optype))) == INTEGER_CST && useless_type_conversion_p (type, TREE_TYPE (optype))) { tree type_domain = TYPE_DOMAIN (optype); tree min_val = size_zero_node; if (type_domain && TYPE_MIN_VALUE (type_domain)) min_val = TYPE_MIN_VALUE (type_domain); - return build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE); + if (TREE_CODE (min_val) == INTEGER_CST) + return build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE); } + /* *(foo *)&complexfoo => __real__ complexfoo */ + else if (TREE_CODE (optype) == COMPLEX_TYPE + && useless_type_conversion_p (type, TREE_TYPE (optype))) + return fold_build1 (REALPART_EXPR, type, op); + /* *(foo *)&vectorfoo => BIT_FIELD_REF<vectorfoo,...> */ + else if (TREE_CODE (optype) == VECTOR_TYPE + && useless_type_conversion_p (type, TREE_TYPE (optype))) + { + tree part_width = TYPE_SIZE (type); + tree index = bitsize_int (0); + return fold_build3 (BIT_FIELD_REF, type, op, part_width, index); + } + } + + /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */ + if (TREE_CODE (sub) == POINTER_PLUS_EXPR + && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST) + { + tree op00 = TREE_OPERAND (sub, 0); + tree op01 = TREE_OPERAND (sub, 1); + tree op00type; + + STRIP_NOPS (op00); + op00type = TREE_TYPE (op00); + if (TREE_CODE (op00) == ADDR_EXPR + && TREE_CODE (TREE_TYPE (op00type)) == VECTOR_TYPE + && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (op00type)))) + { + HOST_WIDE_INT offset = tree_low_cst (op01, 0); + tree part_width = TYPE_SIZE (type); + unsigned HOST_WIDE_INT part_widthi + = tree_low_cst (part_width, 0) / BITS_PER_UNIT; + unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT; + tree index = bitsize_int (indexi); + if (offset / part_widthi + <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (op00type))) + return fold_build3 (BIT_FIELD_REF, type, TREE_OPERAND (op00, 0), + part_width, index); + } + } + + /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ + if (TREE_CODE (sub) == POINTER_PLUS_EXPR + && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST) + { + tree op00 = TREE_OPERAND (sub, 0); + tree op01 = TREE_OPERAND (sub, 1); + tree op00type; + + STRIP_NOPS (op00); + op00type = TREE_TYPE (op00); + if (TREE_CODE (op00) == ADDR_EXPR + && TREE_CODE (TREE_TYPE (op00type)) == COMPLEX_TYPE + && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (op00type)))) + { + tree size = TYPE_SIZE_UNIT (type); + if (tree_int_cst_equal (size, op01)) + return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (op00, 0)); + } } /* *(foo *)fooarrptr => (*fooarrptr)[0] */ if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE + && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (subtype)))) == INTEGER_CST && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (subtype)))) { tree type_domain; @@ -3958,7 +4116,8 @@ type_domain = TYPE_DOMAIN (TREE_TYPE (sub)); if (type_domain && TYPE_MIN_VALUE (type_domain)) min_val = TYPE_MIN_VALUE (type_domain); - return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE); + if (TREE_CODE (min_val) == INTEGER_CST) + return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE); } return NULL_TREE; @@ -3986,241 +4145,255 @@ gimple_seq *pre_p, gimple_seq *post_p, bool want_value) { - enum gimplify_status ret = GS_OK; - - while (ret != GS_UNHANDLED) - switch (TREE_CODE (*from_p)) - { - case VAR_DECL: - /* 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) - && TREE_READONLY (*from_p) - && !TREE_THIS_VOLATILE (*from_p) - && !TREE_THIS_VOLATILE (*to_p) - && TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR) + enum gimplify_status ret = GS_UNHANDLED; + bool changed; + + do + { + changed = false; + switch (TREE_CODE (*from_p)) + { + case VAR_DECL: + /* 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) + && 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; + enum gimplify_status subret; + + /* Move the constructor into the RHS. */ + *from_p = unshare_expr (DECL_INITIAL (*from_p)); + + /* Let's see if gimplify_init_constructor will need to put + it in memory. */ + subret = gimplify_init_constructor (expr_p, NULL, NULL, + false, true); + if (subret == GS_ERROR) + { + /* If so, revert the change. */ + *from_p = old_from; + } + else + { + ret = GS_OK; + changed = true; + } + } + break; + case INDIRECT_REF: { - tree old_from = *from_p; - - /* Move the constructor into the RHS. */ - *from_p = unshare_expr (DECL_INITIAL (*from_p)); - - /* Let's see if gimplify_init_constructor will need to put - it in memory. If so, revert the change. */ - ret = gimplify_init_constructor (expr_p, NULL, NULL, false, true); - if (ret == GS_ERROR) - { - *from_p = old_from; - /* Fall through. */ - } - else - { - ret = GS_OK; - break; - } - } - ret = GS_UNHANDLED; - break; - case INDIRECT_REF: - { - /* If we have code like - - *(const A*)(A*)&x + /* If we have code like + + *(const A*)(A*)&x where the type of "x" is a (possibly cv-qualified variant of "A"), treat the entire expression as identical to "x". This kind of code arises in C++ when an object is bound to a const reference, and if "x" is a TARGET_EXPR we want to take advantage of the optimization below. */ - tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0)); - if (t) - { - *from_p = t; - ret = GS_OK; - } - else - ret = GS_UNHANDLED; + tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0)); + if (t) + { + *from_p = t; + ret = GS_OK; + changed = true; + } + break; + } + + case TARGET_EXPR: + { + /* If we are initializing something from a TARGET_EXPR, strip the + TARGET_EXPR and initialize it directly, if possible. This can't + be done if the initializer is void, since that implies that the + temporary is set in some non-trivial way. + + ??? What about code that pulls out the temp and uses it + elsewhere? I think that such code never uses the TARGET_EXPR as + an initializer. If I'm wrong, we'll die because the temp won't + have any RTL. In that case, I guess we'll need to replace + references somehow. */ + tree init = TARGET_EXPR_INITIAL (*from_p); + + if (init + && !VOID_TYPE_P (TREE_TYPE (init))) + { + *from_p = init; + ret = GS_OK; + changed = true; + } + } + break; + + case COMPOUND_EXPR: + /* Remove any COMPOUND_EXPR in the RHS so the following cases will be + caught. */ + gimplify_compound_expr (from_p, pre_p, true); + ret = GS_OK; + changed = true; break; - } - - case TARGET_EXPR: - { - /* If we are initializing something from a TARGET_EXPR, strip the - TARGET_EXPR and initialize it directly, if possible. This can't - be done if the initializer is void, since that implies that the - temporary is set in some non-trivial way. - - ??? What about code that pulls out the temp and uses it - elsewhere? I think that such code never uses the TARGET_EXPR as - an initializer. If I'm wrong, we'll die because the temp won't - have any RTL. In that case, I guess we'll need to replace - references somehow. */ - tree init = TARGET_EXPR_INITIAL (*from_p); - - if (init - && !VOID_TYPE_P (TREE_TYPE (init))) + + case CONSTRUCTOR: + /* If we're initializing from a CONSTRUCTOR, break this into + individual MODIFY_EXPRs. */ + return gimplify_init_constructor (expr_p, pre_p, post_p, want_value, + false); + + case COND_EXPR: + /* If we're assigning to a non-register type, push the assignment + down into the branches. This is mandatory for ADDRESSABLE types, + since we cannot generate temporaries for such, but it saves a + copy in other cases as well. */ + if (!is_gimple_reg_type (TREE_TYPE (*from_p))) { - *from_p = init; - ret = GS_OK; + /* This code should mirror the code in gimplify_cond_expr. */ + enum tree_code code = TREE_CODE (*expr_p); + tree cond = *from_p; + tree result = *to_p; + + ret = gimplify_expr (&result, pre_p, post_p, + is_gimple_lvalue, fb_lvalue); + if (ret != GS_ERROR) + ret = GS_OK; + + if (TREE_TYPE (TREE_OPERAND (cond, 1)) != void_type_node) + TREE_OPERAND (cond, 1) + = build2 (code, void_type_node, result, + TREE_OPERAND (cond, 1)); + if (TREE_TYPE (TREE_OPERAND (cond, 2)) != void_type_node) + TREE_OPERAND (cond, 2) + = build2 (code, void_type_node, unshare_expr (result), + TREE_OPERAND (cond, 2)); + + TREE_TYPE (cond) = void_type_node; + recalculate_side_effects (cond); + + if (want_value) + { + gimplify_and_add (cond, pre_p); + *expr_p = unshare_expr (result); + } + else + *expr_p = cond; + return ret; } - else - ret = GS_UNHANDLED; - } - break; - - case COMPOUND_EXPR: - /* Remove any COMPOUND_EXPR in the RHS so the following cases will be - caught. */ - gimplify_compound_expr (from_p, pre_p, true); - ret = GS_OK; - break; - - case CONSTRUCTOR: - /* If we're initializing from a CONSTRUCTOR, break this into - individual MODIFY_EXPRs. */ - return gimplify_init_constructor (expr_p, pre_p, post_p, want_value, - false); - - case COND_EXPR: - /* If we're assigning to a non-register type, push the assignment - down into the branches. This is mandatory for ADDRESSABLE types, - since we cannot generate temporaries for such, but it saves a - copy in other cases as well. */ - if (!is_gimple_reg_type (TREE_TYPE (*from_p))) + break; + + case CALL_EXPR: + /* For calls that return in memory, give *to_p as the CALL_EXPR's + return slot so that we don't generate a temporary. */ + if (!CALL_EXPR_RETURN_SLOT_OPT (*from_p) + && aggregate_value_p (*from_p, *from_p)) + { + bool use_target; + + if (!(rhs_predicate_for (*to_p))(*from_p)) + /* If we need a temporary, *to_p isn't accurate. */ + use_target = false; + else if (TREE_CODE (*to_p) == RESULT_DECL + && DECL_NAME (*to_p) == NULL_TREE + && needs_to_live_in_memory (*to_p)) + /* It's OK to use the return slot directly unless it's an NRV. */ + use_target = true; + else if (is_gimple_reg_type (TREE_TYPE (*to_p)) + || (DECL_P (*to_p) && DECL_REGISTER (*to_p))) + /* Don't force regs into memory. */ + use_target = false; + else if (TREE_CODE (*expr_p) == INIT_EXPR) + /* It's OK to use the target directly if it's being + initialized. */ + use_target = true; + else if (!is_gimple_non_addressable (*to_p)) + /* Don't use the original target if it's already addressable; + if its address escapes, and the called function uses the + NRV optimization, a conforming program could see *to_p + change before the called function returns; see c++/19317. + When optimizing, the return_slot pass marks more functions + as safe after we have escape info. */ + use_target = false; + else + use_target = true; + + if (use_target) + { + CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1; + mark_addressable (*to_p); + } + } + break; + + case WITH_SIZE_EXPR: + /* Likewise for calls that return an aggregate of non-constant size, + since we would not be able to generate a temporary at all. */ + if (TREE_CODE (TREE_OPERAND (*from_p, 0)) == CALL_EXPR) + { + *from_p = TREE_OPERAND (*from_p, 0); + /* We don't change ret in this case because the + WITH_SIZE_EXPR might have been added in + gimplify_modify_expr, so returning GS_OK would lead to an + infinite loop. */ + changed = true; + } + break; + + /* If we're initializing from a container, push the initialization + inside it. */ + case CLEANUP_POINT_EXPR: + case BIND_EXPR: + case STATEMENT_LIST: { - /* This code should mirror the code in gimplify_cond_expr. */ - enum tree_code code = TREE_CODE (*expr_p); - tree cond = *from_p; - tree result = *to_p; - - ret = gimplify_expr (&result, pre_p, post_p, - is_gimple_lvalue, fb_lvalue); + tree wrap = *from_p; + tree t; + + ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_min_lval, + fb_lvalue); if (ret != GS_ERROR) ret = GS_OK; - if (TREE_TYPE (TREE_OPERAND (cond, 1)) != void_type_node) - TREE_OPERAND (cond, 1) - = build2 (code, void_type_node, result, - TREE_OPERAND (cond, 1)); - if (TREE_TYPE (TREE_OPERAND (cond, 2)) != void_type_node) - TREE_OPERAND (cond, 2) - = build2 (code, void_type_node, unshare_expr (result), - TREE_OPERAND (cond, 2)); - - TREE_TYPE (cond) = void_type_node; - recalculate_side_effects (cond); + t = voidify_wrapper_expr (wrap, *expr_p); + gcc_assert (t == *expr_p); if (want_value) { - gimplify_and_add (cond, pre_p); - *expr_p = unshare_expr (result); + gimplify_and_add (wrap, pre_p); + *expr_p = unshare_expr (*to_p); } else - *expr_p = cond; - return ret; + *expr_p = wrap; + return GS_OK; } - else - ret = GS_UNHANDLED; - break; - - case CALL_EXPR: - /* For calls that return in memory, give *to_p as the CALL_EXPR's - return slot so that we don't generate a temporary. */ - if (!CALL_EXPR_RETURN_SLOT_OPT (*from_p) - && aggregate_value_p (*from_p, *from_p)) + + case COMPOUND_LITERAL_EXPR: { - bool use_target; - - if (!(rhs_predicate_for (*to_p))(*from_p)) - /* If we need a temporary, *to_p isn't accurate. */ - use_target = false; - else if (TREE_CODE (*to_p) == RESULT_DECL - && DECL_NAME (*to_p) == NULL_TREE - && needs_to_live_in_memory (*to_p)) - /* It's OK to use the return slot directly unless it's an NRV. */ - use_target = true; - else if (is_gimple_reg_type (TREE_TYPE (*to_p)) - || (DECL_P (*to_p) && DECL_REGISTER (*to_p))) - /* Don't force regs into memory. */ - use_target = false; - else if (TREE_CODE (*expr_p) == INIT_EXPR) - /* It's OK to use the target directly if it's being - initialized. */ - use_target = true; - else if (!is_gimple_non_addressable (*to_p)) - /* Don't use the original target if it's already addressable; - if its address escapes, and the called function uses the - NRV optimization, a conforming program could see *to_p - change before the called function returns; see c++/19317. - When optimizing, the return_slot pass marks more functions - as safe after we have escape info. */ - use_target = false; - else - use_target = true; - - if (use_target) + 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) { - CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1; - mark_addressable (*to_p); + *expr_p = copy_node (*expr_p); + TREE_OPERAND (*expr_p, 1) = init; + return GS_OK; } } - ret = GS_UNHANDLED; - break; - - /* If we're initializing from a container, push the initialization - inside it. */ - case CLEANUP_POINT_EXPR: - case BIND_EXPR: - case STATEMENT_LIST: - { - tree wrap = *from_p; - tree t; - - ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_min_lval, - fb_lvalue); - if (ret != GS_ERROR) - ret = GS_OK; - - t = voidify_wrapper_expr (wrap, *expr_p); - gcc_assert (t == *expr_p); - - if (want_value) - { - gimplify_and_add (wrap, pre_p); - *expr_p = unshare_expr (*to_p); - } - else - *expr_p = wrap; - return GS_OK; + default: + break; } - - 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; - } + } + while (changed); return ret; } @@ -4407,7 +4580,8 @@ /* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL instead of a GIMPLE_ASSIGN. */ assign = gimple_build_call_from_tree (*from_p); - gimple_call_set_lhs (assign, *to_p); + if (!gimple_call_noreturn_p (assign)) + gimple_call_set_lhs (assign, *to_p); } else { @@ -5337,6 +5511,31 @@ splay_tree_insert (ctx->variables, (splay_tree_key)decl, flags); } +/* Notice a threadprivate variable DECL used in OpenMP context CTX. + This just prints out diagnostics about threadprivate variable uses + in untied tasks. If DECL2 is non-NULL, prevent this warning + on that variable. */ + +static bool +omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl, + tree decl2) +{ + splay_tree_node n; + + if (ctx->region_type != ORT_UNTIED_TASK) + return false; + n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); + if (n == NULL) + { + error ("threadprivate variable %qE used in untied task", DECL_NAME (decl)); + error_at (ctx->location, "enclosing task"); + splay_tree_insert (ctx->variables, (splay_tree_key)decl, 0); + } + if (decl2) + splay_tree_insert (ctx->variables, (splay_tree_key)decl2, 0); + return false; +} + /* Record the fact that DECL was used within the OpenMP context CTX. IN_CODE is true when real code uses DECL, and false when we should merely emit default(none) errors. Return true if DECL is going to @@ -5357,14 +5556,14 @@ if (is_global_var (decl)) { if (DECL_THREAD_LOCAL_P (decl)) - return false; + return omp_notice_threadprivate_variable (ctx, decl, NULL_TREE); if (DECL_HAS_VALUE_EXPR_P (decl)) { tree value = get_base_address (DECL_VALUE_EXPR (decl)); if (value && DECL_P (value) && DECL_THREAD_LOCAL_P (value)) - return false; + return omp_notice_threadprivate_variable (ctx, decl, value); } } @@ -5390,7 +5589,10 @@ case OMP_CLAUSE_DEFAULT_NONE: error ("%qE not specified in enclosing parallel", DECL_NAME (decl)); - error_at (ctx->location, "enclosing parallel"); + if ((ctx->region_type & ORT_TASK) != 0) + error_at (ctx->location, "enclosing task"); + else + error_at (ctx->location, "enclosing parallel"); /* FALLTHRU */ case OMP_CLAUSE_DEFAULT_SHARED: flags |= GOVD_SHARED; @@ -5403,7 +5605,7 @@ break; case OMP_CLAUSE_DEFAULT_UNSPECIFIED: /* decl will be either GOVD_FIRSTPRIVATE or GOVD_SHARED. */ - gcc_assert (ctx->region_type == ORT_TASK); + gcc_assert ((ctx->region_type & ORT_TASK) != 0); if (ctx->outer_context) omp_notice_variable (ctx->outer_context, decl, in_code); for (octx = ctx->outer_context; octx; octx = octx->outer_context) @@ -5906,7 +6108,10 @@ gimple_seq body = NULL; struct gimplify_ctx gctx; - gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, ORT_TASK); + gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, + find_omp_clause (OMP_TASK_CLAUSES (expr), + OMP_CLAUSE_UNTIED) + ? ORT_UNTIED_TASK : ORT_TASK); push_gimplify_context (&gctx); @@ -6230,9 +6435,7 @@ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr))); tree tmp_load; - tmp_load = create_tmp_var (type, NULL); - if (TREE_CODE (type) == COMPLEX_TYPE || TREE_CODE (type) == VECTOR_TYPE) - DECL_GIMPLE_REG_P (tmp_load) = 1; + tmp_load = create_tmp_reg (type, NULL); if (goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0) return GS_ERROR; @@ -6438,7 +6641,8 @@ else if (ret != GS_UNHANDLED) break; - ret = GS_OK; + /* Make sure that all the cases set 'ret' appropriately. */ + ret = GS_UNHANDLED; switch (TREE_CODE (*expr_p)) { /* First deal with the special cases. */ @@ -6472,6 +6676,7 @@ { *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); mark_addressable (*expr_p); + ret = GS_OK; } break; @@ -6486,6 +6691,7 @@ { *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); mark_addressable (*expr_p); + ret = GS_OK; } break; @@ -6547,6 +6753,7 @@ /* Just strip a conversion to void (or in void context) and try again. */ *expr_p = TREE_OPERAND (*expr_p, 0); + ret = GS_OK; break; } @@ -6567,7 +6774,10 @@ case INDIRECT_REF: *expr_p = fold_indirect_ref_loc (input_location, *expr_p); if (*expr_p != save_expr) - break; + { + ret = GS_OK; + break; + } /* else fall through. */ case ALIGN_INDIRECT_REF: case MISALIGNED_INDIRECT_REF: @@ -6594,7 +6804,10 @@ if (fallback & fb_lvalue) ret = GS_ALL_DONE; else - *expr_p = DECL_INITIAL (*expr_p); + { + *expr_p = DECL_INITIAL (*expr_p); + ret = GS_OK; + } break; case DECL_EXPR: @@ -6629,6 +6842,7 @@ } gimplify_seq_add_stmt (pre_p, gimple_build_goto (GOTO_DESTINATION (*expr_p))); + ret = GS_ALL_DONE; break; case PREDICT_EXPR: @@ -6671,7 +6885,7 @@ append_to_statement_list (ce->value, &temp); *expr_p = temp; - ret = GS_OK; + ret = temp ? GS_OK : GS_ALL_DONE; } /* C99 code may assign to an array in a constructed structure or union, and this has undefined behavior only @@ -6681,6 +6895,7 @@ { *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); mark_addressable (*expr_p); + ret = GS_OK; } else ret = GS_ALL_DONE; @@ -6828,6 +7043,7 @@ gimple_test_f, fallback); gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, is_gimple_val, fb_rvalue); + ret = GS_ALL_DONE; } break; @@ -6915,6 +7131,7 @@ TREE_TYPE (*expr_p)))) { *expr_p = tmp; + ret = GS_OK; break; } /* Convert (void *)&a + 4 into (void *)&a[1]. */ @@ -6930,6 +7147,7 @@ 0))))) { *expr_p = fold_convert (TREE_TYPE (*expr_p), tmp); + ret = GS_OK; break; } /* FALLTHRU */ @@ -6999,9 +7217,7 @@ break; } - /* If we replaced *expr_p, gimplify again. */ - if (ret == GS_OK && (*expr_p == NULL || *expr_p == save_expr)) - ret = GS_ALL_DONE; + gcc_assert (*expr_p || ret != GS_OK); } while (ret == GS_OK); @@ -7262,9 +7478,10 @@ /* 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) + /* Ensure VLA bounds aren't removed, for -O0 they should be variables + with assigned stack slots, for -O1+ -g they should be tracked + by VTA. */ + if (TYPE_DOMAIN (type) && INTEGRAL_TYPE_P (TYPE_DOMAIN (type))) { t = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); @@ -7429,11 +7646,21 @@ *body_p = NULL_TREE; /* If we had callee-copies statements, insert them at the beginning - of the function. */ + of the function and clear DECL_VALUE_EXPR_P on the parameters. */ if (!gimple_seq_empty_p (parm_stmts)) { + tree parm; + gimplify_seq_add_seq (&parm_stmts, gimple_bind_body (outer_bind)); gimple_bind_set_body (outer_bind, parm_stmts); + + for (parm = DECL_ARGUMENTS (current_function_decl); + parm; parm = TREE_CHAIN (parm)) + if (DECL_HAS_VALUE_EXPR_P (parm)) + { + DECL_HAS_VALUE_EXPR_P (parm) = 0; + DECL_IGNORED_P (parm) = 0; + } } if (nonlocal_vlas) @@ -7696,11 +7923,8 @@ } if (need_temp) { - tree temp = create_tmp_var (TREE_TYPE (lhs), NULL); - - if (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE - || TREE_CODE (TREE_TYPE (lhs)) == VECTOR_TYPE) - DECL_GIMPLE_REG_P (temp) = 1; + tree temp = create_tmp_reg (TREE_TYPE (lhs), NULL); + if (TREE_CODE (orig_lhs) == SSA_NAME) orig_lhs = SSA_NAME_VAR (orig_lhs);