X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgimplify.c;h=bc576a0ca00227911601688f11ae021d81cb4fac;hb=86428198399ac6d5ef641dea05cb43a5ee6ff344;hp=efe6b96dcdf6205648d32a48e466457956ee8f22;hpb=35cc02b5c80ac6738c1a3362a822e3d7e4d0c587;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/gimplify.c b/gcc/gimplify.c index efe6b96dcdf..bc576a0ca00 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1,6 +1,7 @@ /* Tree lowering pass. This pass converts the GENERIC functions-as-trees tree representation into the GIMPLE form. - Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. Major work done by Sebastian Pop , Diego Novillo and Jason Merrill . @@ -8,7 +9,7 @@ This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -17,9 +18,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #include "config.h" #include "system.h" @@ -48,6 +48,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "target.h" #include "optabs.h" #include "pointer-set.h" +#include "splay-tree.h" enum gimplify_omp_var_data @@ -93,6 +94,7 @@ struct gimplify_ctx int conditions; bool save_stack; bool into_ssa; + bool allow_rhs_cond_expr; }; static struct gimplify_ctx *gimplify_ctxp; @@ -111,10 +113,18 @@ typedef struct gimple_temp_hash_elt /* Forward declarations. */ static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool); -#ifdef ENABLE_CHECKING -static bool cpt_same_type (tree a, tree b); -#endif +/* Mark X addressable. Unlike the langhook we expect X to be in gimple + form and we don't do any syntax checking. */ +static 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) + return ; + TREE_ADDRESSABLE (x) = 1; +} /* Return a hash value for a formal temporary table entry. */ @@ -496,9 +506,9 @@ create_tmp_var (tree type, const char *prefix) I.E. given = &A, return A. */ const char * -get_name (tree t) +get_name (const_tree t) { - tree stripped_decl; + const_tree stripped_decl; stripped_decl = t; STRIP_NOPS (stripped_decl); @@ -606,8 +616,9 @@ internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal) } } - if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE) - DECL_COMPLEX_GIMPLE_REG_P (t) = 1; + if (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)); @@ -751,7 +762,7 @@ gimple_add_tmp_var (tree tmp) /* Determines whether to assign a locus to the statement STMT. */ static bool -should_carry_locus_p (tree stmt) +should_carry_locus_p (const_tree stmt) { /* Don't emit a line note for a label. We particularly don't want to emit one for the break label, since it doesn't actually correspond @@ -1012,8 +1023,9 @@ voidify_wrapper_expr (tree wrapper, tree temp) /* The wrapper is on the RHS of an assignment that we're pushing down. */ gcc_assert (TREE_CODE (temp) == INIT_EXPR + || TREE_CODE (temp) == GIMPLE_MODIFY_STMT || TREE_CODE (temp) == MODIFY_EXPR); - TREE_OPERAND (temp, 1) = *p; + GENERIC_TREE_OPERAND (temp, 1) = *p; *p = temp; } else @@ -1037,14 +1049,13 @@ build_stack_save_restore (tree *save, tree *restore) tree save_call, tmp_var; save_call = - build_function_call_expr (implicit_built_in_decls[BUILT_IN_STACK_SAVE], - NULL_TREE); + build_call_expr (implicit_built_in_decls[BUILT_IN_STACK_SAVE], 0); tmp_var = create_tmp_var (ptr_type_node, "saved_stack"); - *save = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, tmp_var, save_call); + *save = build_gimple_modify_stmt (tmp_var, save_call); *restore = - build_function_call_expr (implicit_built_in_decls[BUILT_IN_STACK_RESTORE], - tree_cons (NULL_TREE, tmp_var, NULL_TREE)); + build_call_expr (implicit_built_in_decls[BUILT_IN_STACK_RESTORE], + 1, tmp_var); } /* Gimplify a BIND_EXPR. Just voidify and recurse. */ @@ -1078,11 +1089,12 @@ gimplify_bind_expr (tree *expr_p, tree *pre_p) /* 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 + if ((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)) - DECL_COMPLEX_GIMPLE_REG_P (t) = 1; + DECL_GIMPLE_REG_P (t) = 1; } gimple_push_bind_expr (bind_expr); @@ -1169,6 +1181,9 @@ gimplify_return_expr (tree stmt, tree *pre_p) 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; /* ??? With complex control flow (usually involving abnormal edges), we can wind up warning about an uninitialized value for this. Due @@ -1191,13 +1206,47 @@ gimplify_return_expr (tree stmt, tree *pre_p) if (result == result_decl) ret_expr = result; else - ret_expr = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (result), result_decl, - result); + ret_expr = build_gimple_modify_stmt (result_decl, result); TREE_OPERAND (stmt, 0) = ret_expr; return GS_ALL_DONE; } +static void +gimplify_vla_decl (tree decl, tree *stmt_p) +{ + /* This is a variable-sized decl. Simplify its size and mark it + for deferred expansion. Note that mudflap depends on the format + of the emitted code: see mx_register_decls(). */ + tree t, addr, ptr_type; + + gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p); + gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p); + + /* All occurrences of this decl in final gimplified code will be + replaced by indirection. Setting DECL_VALUE_EXPR does two + things: First, it lets the rest of the gimplifier know what + replacement to use. Second, it lets the debug info know + where to find the value. */ + ptr_type = build_pointer_type (TREE_TYPE (decl)); + addr = create_tmp_var (ptr_type, get_name (decl)); + DECL_IGNORED_P (addr) = 0; + t = build_fold_indirect_ref (addr); + SET_DECL_VALUE_EXPR (decl, t); + DECL_HAS_VALUE_EXPR_P (decl) = 1; + + t = built_in_decls[BUILT_IN_ALLOCA]; + t = build_call_expr (t, 1, DECL_SIZE_UNIT (decl)); + t = fold_convert (ptr_type, t); + t = build_gimple_modify_stmt (addr, t); + + gimplify_and_add (t, stmt_p); + + /* Indicate that we need to restore the stack level when the + enclosing BIND_EXPR is exited. */ + gimplify_ctxp->save_stack = true; +} + /* Gimplifies a DECL_EXPR node *STMT_P by making any necessary allocation and initialization explicit. */ @@ -1222,39 +1271,7 @@ gimplify_decl_expr (tree *stmt_p) tree init = DECL_INITIAL (decl); if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) - { - /* This is a variable-sized decl. Simplify its size and mark it - for deferred expansion. Note that mudflap depends on the format - of the emitted code: see mx_register_decls(). */ - tree t, args, addr, ptr_type; - - gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p); - gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p); - - /* All occurrences of this decl in final gimplified code will be - replaced by indirection. Setting DECL_VALUE_EXPR does two - things: First, it lets the rest of the gimplifier know what - replacement to use. Second, it lets the debug info know - where to find the value. */ - ptr_type = build_pointer_type (TREE_TYPE (decl)); - addr = create_tmp_var (ptr_type, get_name (decl)); - DECL_IGNORED_P (addr) = 0; - t = build_fold_indirect_ref (addr); - SET_DECL_VALUE_EXPR (decl, t); - DECL_HAS_VALUE_EXPR_P (decl) = 1; - - args = tree_cons (NULL, DECL_SIZE_UNIT (decl), NULL); - t = built_in_decls[BUILT_IN_ALLOCA]; - t = build_function_call_expr (t, args); - t = fold_convert (ptr_type, t); - t = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, t); - - gimplify_and_add (t, stmt_p); - - /* Indicate that we need to restore the stack level when the - enclosing BIND_EXPR is exited. */ - gimplify_ctxp->save_stack = true; - } + gimplify_vla_decl (decl, stmt_p); if (init && init != error_mark_node) { @@ -1319,8 +1336,8 @@ gimplify_loop_expr (tree *expr_p, tree *pre_p) static int compare_case_labels (const void *p1, const void *p2) { - tree case1 = *(tree *)p1; - tree case2 = *(tree *)p2; + const_tree const case1 = *(const_tree const*)p1; + const_tree const case2 = *(const_tree const*)p2; return tree_int_cst_compare (CASE_LOW (case1), CASE_LOW (case2)); } @@ -1397,7 +1414,7 @@ gimplify_switch_expr (tree *expr_p, tree *pre_p) { /* Discard empty ranges. */ tree high = CASE_HIGH (elt); - if (high && INT_CST_LT (high, low)) + if (high && tree_int_cst_lt (high, low)) remove_element = TRUE; } else @@ -1539,17 +1556,31 @@ canonicalize_component_ref (tree *expr_p) else type = TREE_TYPE (TREE_OPERAND (expr, 1)); + /* One could argue that all the stuff below is not necessary for + the non-bitfield case and declare it a FE error if type + adjustment would be needed. */ if (TREE_TYPE (expr) != type) { +#ifdef ENABLE_TYPES_CHECKING tree old_type = TREE_TYPE (expr); +#endif + int type_quals; + + /* We need to preserve qualifiers and propagate them from + operand 0. */ + type_quals = TYPE_QUALS (type) + | TYPE_QUALS (TREE_TYPE (TREE_OPERAND (expr, 0))); + if (TYPE_QUALS (type) != type_quals) + type = build_qualified_type (TYPE_MAIN_VARIANT (type), type_quals); /* Set the type of the COMPONENT_REF to the underlying type. */ TREE_TYPE (expr) = type; - /* And wrap the whole thing inside a NOP_EXPR. */ - expr = build1 (NOP_EXPR, old_type, expr); - - *expr_p = expr; +#ifdef ENABLE_TYPES_CHECKING + /* It is now a FE error, if the conversion from the canonical + type to the original expression type is not useless. */ + gcc_assert (useless_type_conversion_p (old_type, type)); +#endif } } @@ -1560,52 +1591,46 @@ canonicalize_component_ref (tree *expr_p) ==> &array[L] where L is the lower bound. For simplicity, only do this for constant - lower bound. */ + lower bound. + The constraint is that the type of &array[L] is trivially convertible + to T *. */ static void canonicalize_addr_expr (tree *expr_p) { tree expr = *expr_p; - tree ctype = TREE_TYPE (expr); tree addr_expr = TREE_OPERAND (expr, 0); - tree atype = TREE_TYPE (addr_expr); - tree dctype, datype, ddatype, otype, obj_expr; + tree datype, ddatype, pddatype; - /* Both cast and addr_expr types should be pointers. */ - if (!POINTER_TYPE_P (ctype) || !POINTER_TYPE_P (atype)) + /* We simplify only conversions from an ADDR_EXPR to a pointer type. */ + if (!POINTER_TYPE_P (TREE_TYPE (expr)) + || TREE_CODE (addr_expr) != ADDR_EXPR) return; /* The addr_expr type should be a pointer to an array. */ - datype = TREE_TYPE (atype); + datype = TREE_TYPE (TREE_TYPE (addr_expr)); if (TREE_CODE (datype) != ARRAY_TYPE) return; - /* Both cast and addr_expr types should address the same object type. */ - dctype = TREE_TYPE (ctype); + /* The pointer to element type shall be trivially convertible to + the expression pointer type. */ ddatype = TREE_TYPE (datype); - if (!lang_hooks.types_compatible_p (ddatype, dctype)) - return; - - /* The addr_expr and the object type should match. */ - obj_expr = TREE_OPERAND (addr_expr, 0); - otype = TREE_TYPE (obj_expr); - if (!lang_hooks.types_compatible_p (otype, datype)) + pddatype = build_pointer_type (ddatype); + if (!useless_type_conversion_p (pddatype, ddatype)) return; /* The lower bound and element sizes must be constant. */ - if (!TYPE_SIZE_UNIT (dctype) - || TREE_CODE (TYPE_SIZE_UNIT (dctype)) != INTEGER_CST + if (!TYPE_SIZE_UNIT (ddatype) + || TREE_CODE (TYPE_SIZE_UNIT (ddatype)) != INTEGER_CST || !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype)) || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST) return; /* All checks succeeded. Build a new node to merge the cast. */ - *expr_p = build4 (ARRAY_REF, dctype, obj_expr, - TYPE_MIN_VALUE (TYPE_DOMAIN (datype)), + *expr_p = build4 (ARRAY_REF, ddatype, TREE_OPERAND (addr_expr, 0), TYPE_MIN_VALUE (TYPE_DOMAIN (datype)), - size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (dctype), - size_int (TYPE_ALIGN_UNIT (dctype)))); - *expr_p = build1 (ADDR_EXPR, ctype, *expr_p); + NULL_TREE, NULL_TREE); + *expr_p = build1 (ADDR_EXPR, pddatype, *expr_p); } /* *EXPR_P is a NOP_EXPR or CONVERT_EXPR. Remove it and/or other conversions @@ -1614,6 +1639,7 @@ canonicalize_addr_expr (tree *expr_p) static enum gimplify_status gimplify_conversion (tree *expr_p) { + tree tem; gcc_assert (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR); @@ -1624,6 +1650,21 @@ gimplify_conversion (tree *expr_p) if (tree_ssa_useless_type_conversion (*expr_p)) *expr_p = TREE_OPERAND (*expr_p, 0); + /* 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 + && 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); + } + /* If we still have a conversion at the toplevel, then canonicalize some constructs. */ if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR) @@ -1945,8 +1986,17 @@ gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p, return ret; } + /* For POINTERs increment, use POINTER_PLUS_EXPR. */ + if (POINTER_TYPE_P (TREE_TYPE (lhs))) + { + rhs = fold_convert (sizetype, rhs); + if (arith_code == MINUS_EXPR) + rhs = fold_build1 (NEGATE_EXPR, TREE_TYPE (rhs), rhs); + arith_code = POINTER_PLUS_EXPR; + } + t1 = build2 (arith_code, TREE_TYPE (*expr_p), lhs, rhs); - t1 = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (lvalue), lvalue, t1); + t1 = build_gimple_modify_stmt (lvalue, t1); if (postfix) { @@ -2023,9 +2073,9 @@ gimplify_arg (tree *expr_p, tree *pre_p) static enum gimplify_status gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value) { - tree decl; - tree arglist; + tree decl, parms, p; enum gimplify_status ret; + int i, nargs; gcc_assert (TREE_CODE (*expr_p) == CALL_EXPR); @@ -2049,8 +2099,7 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value) decl = get_callee_fndecl (*expr_p); if (decl && DECL_BUILT_IN (decl)) { - tree arglist = TREE_OPERAND (*expr_p, 1); - tree new = fold_builtin (decl, arglist, !want_value); + tree new = fold_call_expr (*expr_p, !want_value); if (new && new != *expr_p) { @@ -2064,62 +2113,152 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value) if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL && DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START) { - if (!arglist || !TREE_CHAIN (arglist)) + if (call_expr_nargs (*expr_p) < 2) { error ("too few arguments to function %"); *expr_p = build_empty_stmt (); return GS_OK; } - if (fold_builtin_next_arg (TREE_CHAIN (arglist))) + if (fold_builtin_next_arg (*expr_p, true)) { *expr_p = build_empty_stmt (); return GS_OK; } /* Avoid gimplifying the second argument to va_start, which needs to be the plain PARM_DECL. */ - return gimplify_arg (&TREE_VALUE (TREE_OPERAND (*expr_p, 1)), pre_p); + return gimplify_arg (&CALL_EXPR_ARG (*expr_p, 0), pre_p); } } /* There is a sequence point before the call, so any side effects in the calling expression must occur before the actual call. Force gimplify_expr to use an internal post queue. */ - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, NULL, + ret = gimplify_expr (&CALL_EXPR_FN (*expr_p), pre_p, NULL, is_gimple_call_addr, fb_rvalue); - if (PUSH_ARGS_REVERSED) - TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1)); - for (arglist = TREE_OPERAND (*expr_p, 1); arglist; - arglist = TREE_CHAIN (arglist)) + nargs = call_expr_nargs (*expr_p); + + /* Get argument types for verification. */ + decl = get_callee_fndecl (*expr_p); + parms = NULL_TREE; + if (decl) + parms = TYPE_ARG_TYPES (TREE_TYPE (decl)); + 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 (decl && DECL_ARGUMENTS (decl)) + { + for (i = 0, p = DECL_ARGUMENTS (decl); 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; + } + } + } + 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; + } + } + } + else + { + if (nargs != 0) + CALL_CANNOT_INLINE_P (*expr_p) = 1; + i = 0; + p = NULL_TREE; + } + + /* If the last argument is __builtin_va_arg_pack () and it is not + passed as a named argument, decrease the number of CALL_EXPR + arguments and set instead the CALL_EXPR_VA_ARG_PACK flag. */ + if (!p + && i < nargs + && TREE_CODE (CALL_EXPR_ARG (*expr_p, nargs - 1)) == CALL_EXPR) + { + tree last_arg = CALL_EXPR_ARG (*expr_p, nargs - 1); + tree last_arg_fndecl = get_callee_fndecl (last_arg); + + if (last_arg_fndecl + && TREE_CODE (last_arg_fndecl) == FUNCTION_DECL + && DECL_BUILT_IN_CLASS (last_arg_fndecl) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (last_arg_fndecl) == BUILT_IN_VA_ARG_PACK) + { + tree call = *expr_p; + + --nargs; + *expr_p = build_call_array (TREE_TYPE (call), CALL_EXPR_FN (call), + nargs, CALL_EXPR_ARGP (call)); + /* Copy all CALL_EXPR flags, locus and block, except + CALL_EXPR_VA_ARG_PACK flag. */ + CALL_EXPR_STATIC_CHAIN (*expr_p) = CALL_EXPR_STATIC_CHAIN (call); + CALL_EXPR_TAILCALL (*expr_p) = CALL_EXPR_TAILCALL (call); + CALL_EXPR_RETURN_SLOT_OPT (*expr_p) + = 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); + TREE_NOTHROW (*expr_p) = TREE_NOTHROW (call); + SET_EXPR_LOCUS (*expr_p, EXPR_LOCUS (call)); + TREE_BLOCK (*expr_p) = TREE_BLOCK (call); + /* Set CALL_EXPR_VA_ARG_PACK. */ + CALL_EXPR_VA_ARG_PACK (*expr_p) = 1; + } + } + + /* Finally, gimplify the function arguments. */ + for (i = (PUSH_ARGS_REVERSED ? nargs - 1 : 0); + PUSH_ARGS_REVERSED ? i >= 0 : i < nargs; + PUSH_ARGS_REVERSED ? i-- : i++) { enum gimplify_status t; - t = gimplify_arg (&TREE_VALUE (arglist), pre_p); + t = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p); if (t == GS_ERROR) ret = GS_ERROR; } - if (PUSH_ARGS_REVERSED) - TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1)); /* Try this again in case gimplification exposed something. */ if (ret != GS_ERROR) { - decl = get_callee_fndecl (*expr_p); - if (decl && DECL_BUILT_IN (decl)) - { - tree arglist = TREE_OPERAND (*expr_p, 1); - tree new = fold_builtin (decl, arglist, !want_value); + tree new = fold_call_expr (*expr_p, !want_value); - if (new && new != *expr_p) - { - /* There was a transformation of this call which computes the - same value, but in a more efficient way. Return and try - again. */ - *expr_p = new; - return GS_OK; - } + if (new && new != *expr_p) + { + /* There was a transformation of this call which computes the + same value, but in a more efficient way. Return and try + again. */ + *expr_p = new; + return GS_OK; } } @@ -2408,6 +2547,61 @@ gimple_boolify (tree expr) } } +/* Given a conditional expression *EXPR_P without side effects, gimplify + its operands. New statements are inserted to PRE_P. */ + +static enum gimplify_status +gimplify_pure_cond_expr (tree *expr_p, tree *pre_p) +{ + tree expr = *expr_p, cond; + enum gimplify_status ret, tret; + enum tree_code code; + + cond = gimple_boolify (COND_EXPR_COND (expr)); + + /* We need to handle && and || specially, as their gimplification + creates pure cond_expr, thus leading to an infinite cycle otherwise. */ + code = TREE_CODE (cond); + if (code == TRUTH_ANDIF_EXPR) + TREE_SET_CODE (cond, TRUTH_AND_EXPR); + else if (code == TRUTH_ORIF_EXPR) + TREE_SET_CODE (cond, TRUTH_OR_EXPR); + ret = gimplify_expr (&cond, pre_p, NULL, + is_gimple_condexpr, fb_rvalue); + COND_EXPR_COND (*expr_p) = cond; + + tret = gimplify_expr (&COND_EXPR_THEN (expr), pre_p, NULL, + is_gimple_val, fb_rvalue); + ret = MIN (ret, tret); + tret = gimplify_expr (&COND_EXPR_ELSE (expr), pre_p, NULL, + is_gimple_val, fb_rvalue); + + return MIN (ret, tret); +} + +/* Returns true if evaluating EXPR could trap. + EXPR is GENERIC, while tree_could_trap_p can be called + only on GIMPLE. */ + +static bool +generic_expr_could_trap_p (tree expr) +{ + unsigned i, n; + + if (!expr || is_gimple_val (expr)) + return false; + + if (!EXPR_P (expr) || tree_could_trap_p (expr)) + return true; + + n = TREE_OPERAND_LENGTH (expr); + for (i = 0; i < n; i++) + if (generic_expr_could_trap_p (TREE_OPERAND (expr, i))) + return true; + + return false; +} + /* Convert the conditional expression pointed to by EXPR_P '(p) ? a : b;' into @@ -2439,8 +2633,21 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, fallback_t fallback) { tree result; - if ((fallback & fb_lvalue) == 0) + /* If an rvalue is ok or we do not require an lvalue, avoid creating + an addressable temporary. */ + 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))) + return gimplify_pure_cond_expr (expr_p, pre_p); + result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp"); ret = GS_ALL_DONE; } @@ -2455,7 +2662,7 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, fallback_t fallback) if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node) TREE_OPERAND (expr, 2) = build_fold_addr_expr (TREE_OPERAND (expr, 2)); - + tmp2 = tmp = create_tmp_var (type, "iftmp"); expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0), @@ -2469,14 +2676,12 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, fallback_t fallback) 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 (GIMPLE_MODIFY_STMT, void_type_node, tmp, - TREE_OPERAND (expr, 1)); + = build_gimple_modify_stmt (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 (GIMPLE_MODIFY_STMT, void_type_node, tmp2, - TREE_OPERAND (expr, 2)); + = build_gimple_modify_stmt (tmp2, TREE_OPERAND (expr, 2)); TREE_TYPE (expr) = void_type_node; recalculate_side_effects (expr); @@ -2554,20 +2759,16 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, fallback_t fallback) static enum gimplify_status gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value) { - tree args, t, to, to_ptr, from; + tree t, to, to_ptr, from, from_ptr; to = GENERIC_TREE_OPERAND (*expr_p, 0); from = GENERIC_TREE_OPERAND (*expr_p, 1); - args = tree_cons (NULL, size, NULL); - - t = build_fold_addr_expr (from); - args = tree_cons (NULL, t, args); + from_ptr = build_fold_addr_expr (from); to_ptr = build_fold_addr_expr (to); - args = tree_cons (NULL, to_ptr, args); t = implicit_built_in_decls[BUILT_IN_MEMCPY]; - t = build_function_call_expr (t, args); + t = build_call_expr (t, 3, to_ptr, from_ptr, size); if (want_value) { @@ -2586,18 +2787,13 @@ gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value) static enum gimplify_status gimplify_modify_expr_to_memset (tree *expr_p, tree size, bool want_value) { - tree args, t, to, to_ptr; + tree t, to, to_ptr; to = GENERIC_TREE_OPERAND (*expr_p, 0); - args = tree_cons (NULL, size, NULL); - - args = tree_cons (NULL, integer_zero_node, args); - to_ptr = build_fold_addr_expr (to); - args = tree_cons (NULL, to_ptr, args); t = implicit_built_in_decls[BUILT_IN_MEMSET]; - t = build_function_call_expr (t, args); + t = build_call_expr (t, 3, to_ptr, integer_zero_node, size); if (want_value) { @@ -2620,7 +2816,7 @@ struct gimplify_init_ctor_preeval_data tree lhs_base_decl; /* The alias set of the lhs object. */ - int lhs_alias_set; + alias_set_type lhs_alias_set; }; static tree @@ -2642,6 +2838,21 @@ gimplify_init_ctor_preeval_1 (tree *tp, int *walk_subtrees, void *xdata) && alias_sets_conflict_p (data->lhs_alias_set, get_alias_set (t))) return t; + /* If the constructor component is a call, determine if it can hide a + potential overlap with the lhs through an INDIRECT_REF like above. */ + if (TREE_CODE (t) == CALL_EXPR) + { + tree type, fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (t))); + + for (type = TYPE_ARG_TYPES (fntype); type; type = TREE_CHAIN (type)) + if (POINTER_TYPE_P (TREE_VALUE (type)) + && (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl)) + && alias_sets_conflict_p (data->lhs_alias_set, + get_alias_set + (TREE_TYPE (TREE_VALUE (type))))) + return t; + } + if (IS_TYPE_OR_DECL_P (t)) *walk_subtrees = 0; return NULL; @@ -2743,7 +2954,7 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper, tree *pre_p, bool cleared) { tree loop_entry_label, loop_exit_label; - tree var, var_type, cref; + tree var, var_type, cref, tmp; loop_entry_label = create_artificial_label (); loop_exit_label = create_artificial_label (); @@ -2751,8 +2962,7 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper, /* Create and initialize the index variable. */ var_type = TREE_TYPE (upper); var = create_tmp_var (var_type, NULL); - append_to_statement_list (build2 (GIMPLE_MODIFY_STMT, var_type, var, lower), - pre_p); + append_to_statement_list (build_gimple_modify_stmt (var, lower), pre_p); /* Add the loop entry label. */ append_to_statement_list (build1 (LABEL_EXPR, @@ -2773,9 +2983,7 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper, gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value), pre_p, cleared); else - append_to_statement_list (build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (cref), - cref, value), - pre_p); + append_to_statement_list (build_gimple_modify_stmt (cref, value), pre_p); /* We exit the loop when the index var is equal to the upper bound. */ gimplify_and_add (build3 (COND_EXPR, void_type_node, @@ -2788,11 +2996,9 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper, pre_p); /* Otherwise, increment the index var... */ - append_to_statement_list (build2 (GIMPLE_MODIFY_STMT, var_type, var, - build2 (PLUS_EXPR, var_type, var, - fold_convert (var_type, - integer_one_node))), - pre_p); + tmp = build2 (PLUS_EXPR, var_type, var, + fold_convert (var_type, integer_one_node)); + append_to_statement_list (build_gimple_modify_stmt (var, tmp), pre_p); /* ...and jump back to the loop entry. */ append_to_statement_list (build1 (GOTO_EXPR, @@ -2810,7 +3016,7 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper, /* Return true if FDECL is accessing a field that is zero sized. */ static bool -zero_sized_field_decl (tree fdecl) +zero_sized_field_decl (const_tree fdecl) { if (TREE_CODE (fdecl) == FIELD_DECL && DECL_SIZE (fdecl) && integer_zerop (DECL_SIZE (fdecl))) @@ -2821,7 +3027,7 @@ zero_sized_field_decl (tree fdecl) /* Return true if TYPE is zero sized. */ static bool -zero_sized_type (tree type) +zero_sized_type (const_tree type) { if (AGGREGATE_TYPE_P (type) && TYPE_SIZE (type) && integer_zerop (TYPE_SIZE (type))) @@ -2890,6 +3096,10 @@ gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts, if (array_elt_type) { + /* Do not use bitsizetype for ARRAY_REF indices. */ + if (TYPE_DOMAIN (TREE_TYPE (object))) + purpose = fold_convert (TREE_TYPE (TYPE_DOMAIN (TREE_TYPE (object))), + purpose); cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object), purpose, NULL_TREE, NULL_TREE); } @@ -2917,11 +3127,18 @@ gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts, Note that we still need to clear any elements that don't have explicit initializers, so if not all elements are initialized we keep the - original MODIFY_EXPR, we just remove all of the constructor elements. */ + original MODIFY_EXPR, we just remove all of the constructor elements. + + If NOTIFY_TEMP_CREATION is true, do not gimplify, just return + GS_ERROR if we would have to create a temporary when gimplifying + this constructor. Otherwise, return GS_OK. + + If NOTIFY_TEMP_CREATION is false, just do the gimplification. */ static enum gimplify_status gimplify_init_constructor (tree *expr_p, tree *pre_p, - tree *post_p, bool want_value) + tree *post_p, bool want_value, + bool notify_temp_creation) { tree object; tree ctor = GENERIC_TREE_OPERAND (*expr_p, 1); @@ -2932,10 +3149,13 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, if (TREE_CODE (ctor) != CONSTRUCTOR) return GS_UNHANDLED; - ret = gimplify_expr (&GENERIC_TREE_OPERAND (*expr_p, 0), pre_p, post_p, - is_gimple_lvalue, fb_lvalue); - if (ret == GS_ERROR) - return ret; + if (!notify_temp_creation) + { + ret = gimplify_expr (&GENERIC_TREE_OPERAND (*expr_p, 0), pre_p, post_p, + is_gimple_lvalue, fb_lvalue); + if (ret == GS_ERROR) + return ret; + } object = GENERIC_TREE_OPERAND (*expr_p, 0); elts = CONSTRUCTOR_ELTS (ctor); @@ -2957,7 +3177,11 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, individual elements. The exception is that a CONSTRUCTOR node with no elements indicates zero-initialization of the whole. */ if (VEC_empty (constructor_elt, elts)) - break; + { + if (notify_temp_creation) + return GS_OK; + break; + } /* Fetch information about the constructor to direct later processing. We might want to make static versions of it in various cases, and @@ -2973,6 +3197,8 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, && TREE_READONLY (object) && TREE_CODE (object) == VAR_DECL) { + if (notify_temp_creation) + return GS_ERROR; DECL_INITIAL (object) = ctor; TREE_STATIC (object) = 1; if (!DECL_NAME (object)) @@ -3049,7 +3275,12 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, if (size > 0 && !can_move_by_pieces (size, align)) { - tree new = create_tmp_var_raw (type, "C"); + tree new; + + if (notify_temp_creation) + return GS_ERROR; + + new = create_tmp_var_raw (type, "C"); gimple_add_tmp_var (new); TREE_STATIC (new) = 1; @@ -3071,6 +3302,9 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, } } + 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. */ @@ -3110,6 +3344,9 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, { tree r, i; + if (notify_temp_creation) + return GS_OK; + /* Extract the real and imaginary parts out of the ctor. */ gcc_assert (VEC_length (constructor_elt, elts) == 2); r = VEC_index (constructor_elt, elts, 0)->value; @@ -3146,6 +3383,9 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, unsigned HOST_WIDE_INT ix; constructor_elt *ce; + if (notify_temp_creation) + return GS_OK; + /* Go ahead and simplify constant constructors to VECTOR_CST. */ if (TREE_CONSTANT (ctor)) { @@ -3153,8 +3393,9 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, tree value; /* Even when ctor is constant, it might contain non-*_CST - elements (e.g. { 1.0/0.0 - 1.0/0.0, 0.0 }) and those don't - belong into VECTOR_CST nodes. */ + elements, such as addresses or trapping values like + 1.0/0.0 - 1.0/0.0. Such expressions don't belong + in VECTOR_CST nodes. */ FOR_EACH_CONSTRUCTOR_VALUE (elts, ix, value) if (!CONSTANT_CLASS_P (value)) { @@ -3168,10 +3409,14 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, break; } - /* Don't reduce a TREE_CONSTANT vector ctor even if we can't + /* Don't reduce an initializer constant even if we can't make a VECTOR_CST. It won't do anything for us, and it'll prevent us from representing it as a single constant. */ - break; + if (initializer_constant_valid_p (ctor, type)) + break; + + TREE_CONSTANT (ctor) = 0; + TREE_INVARIANT (ctor) = 0; } /* Vector types use CONSTRUCTOR all the way through gimple @@ -3184,6 +3429,8 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, if (tret == GS_ERROR) ret = GS_ERROR; } + if (!is_gimple_reg (GENERIC_TREE_OPERAND (*expr_p, 0))) + GENERIC_TREE_OPERAND (*expr_p, 1) = get_formal_tmp_var (ctor, pre_p); } break; @@ -3206,13 +3453,12 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p, /* Given a pointer value OP0, return a simplified version of an indirection through OP0, or NULL_TREE if no simplification is - possible. This may only be applied to a rhs of an expression. - Note that the resulting type may be different from the type pointed - to in the sense that it is still compatible from the langhooks - point of view. */ + possible. Note that the resulting type may be different from + the type pointed to in the sense that it is still compatible + from the langhooks point of view. */ -static tree -fold_indirect_ref_rhs (tree t) +tree +gimple_fold_indirect_ref (tree t) { tree type = TREE_TYPE (TREE_TYPE (t)); tree sub = t; @@ -3228,11 +3474,12 @@ fold_indirect_ref_rhs (tree t) tree op = TREE_OPERAND (sub, 0); tree optype = TREE_TYPE (op); /* *&p => p */ - if (lang_hooks.types_compatible_p (type, optype)) + if (useless_type_conversion_p (type, optype)) return op; + /* *(foo *)&fooarray => fooarray[0] */ - else if (TREE_CODE (optype) == ARRAY_TYPE - && lang_hooks.types_compatible_p (type, TREE_TYPE (optype))) + if (TREE_CODE (optype) == ARRAY_TYPE + && useless_type_conversion_p (type, TREE_TYPE (optype))) { tree type_domain = TYPE_DOMAIN (optype); tree min_val = size_zero_node; @@ -3244,12 +3491,12 @@ fold_indirect_ref_rhs (tree t) /* *(foo *)fooarrptr => (*fooarrptr)[0] */ if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE - && lang_hooks.types_compatible_p (type, TREE_TYPE (TREE_TYPE (subtype)))) + && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (subtype)))) { tree type_domain; tree min_val = size_zero_node; tree osub = sub; - sub = fold_indirect_ref_rhs (sub); + sub = gimple_fold_indirect_ref (sub); if (! sub) sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), osub); type_domain = TYPE_DOMAIN (TREE_TYPE (sub)); @@ -3261,8 +3508,22 @@ fold_indirect_ref_rhs (tree t) return NULL_TREE; } -/* Subroutine of gimplify_modify_expr to do simplifications of MODIFY_EXPRs - based on the code of the RHS. We loop for as long as something changes. */ +/* Given a pointer value OP0, return a simplified version of an + indirection through OP0, or NULL_TREE if no simplification is + possible. This may only be applied to a rhs of an expression. + Note that the resulting type may be different from the type pointed + to in the sense that it is still compatible from the langhooks + point of view. */ + +static tree +gimple_fold_indirect_ref_rhs (tree t) +{ + return gimple_fold_indirect_ref (t); +} + +/* Subroutine of gimplify_modify_expr to do simplifications of + MODIFY_EXPRs based on the code of the RHS. We loop for as long as + something changes. */ static enum gimplify_status gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p, @@ -3273,6 +3534,35 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p, while (ret != GS_UNHANDLED) 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 (DECL_INITIAL (*from_p) + && TYPE_READONLY (TREE_TYPE (*from_p)) + && !TREE_THIS_VOLATILE (*from_p) + && TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR) + { + 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 @@ -3284,7 +3574,7 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p, 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 = fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0)); + tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0)); if (t) { *from_p = t; @@ -3329,7 +3619,8 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p, 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); + 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 @@ -3416,7 +3707,7 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p, if (use_target) { CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1; - lang_hooks.mark_addressable (*to_p); + mark_addressable (*to_p); } } @@ -3458,46 +3749,6 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p, return ret; } -/* Promote partial stores to COMPLEX variables to total stores. *EXPR_P is - a MODIFY_EXPR with a lhs of a REAL/IMAGPART_EXPR of a variable with - DECL_COMPLEX_GIMPLE_REG_P set. */ - -static enum gimplify_status -gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value) -{ - enum tree_code code, ocode; - tree lhs, rhs, new_rhs, other, realpart, imagpart; - - lhs = GENERIC_TREE_OPERAND (*expr_p, 0); - rhs = GENERIC_TREE_OPERAND (*expr_p, 1); - code = TREE_CODE (lhs); - lhs = TREE_OPERAND (lhs, 0); - - ocode = code == REALPART_EXPR ? IMAGPART_EXPR : REALPART_EXPR; - other = build1 (ocode, TREE_TYPE (rhs), lhs); - other = get_formal_tmp_var (other, pre_p); - - realpart = code == REALPART_EXPR ? rhs : other; - imagpart = code == REALPART_EXPR ? other : rhs; - - if (TREE_CONSTANT (realpart) && TREE_CONSTANT (imagpart)) - new_rhs = build_complex (TREE_TYPE (lhs), realpart, imagpart); - else - new_rhs = build2 (COMPLEX_EXPR, TREE_TYPE (lhs), realpart, imagpart); - - GENERIC_TREE_OPERAND (*expr_p, 0) = lhs; - GENERIC_TREE_OPERAND (*expr_p, 1) = new_rhs; - - if (want_value) - { - append_to_statement_list (*expr_p, pre_p); - *expr_p = rhs; - } - - return GS_ALL_DONE; -} - - /* Destructively convert the TREE pointer in TP into a gimple tuple if appropriate. */ @@ -3526,7 +3777,7 @@ tree_to_gimple_tuple (tree *tp) /* The set to base above overwrites the CODE. */ TREE_SET_CODE ((tree) gs, GIMPLE_MODIFY_STMT); - gs->locus = EXPR_LOCUS (*tp); + SET_EXPR_LOCUS ((tree) gs, EXPR_LOCUS (*tp)); gs->operands[0] = TREE_OPERAND (*tp, 0); gs->operands[1] = TREE_OPERAND (*tp, 1); gs->block = TREE_BLOCK (*tp); @@ -3544,6 +3795,55 @@ tree_to_gimple_tuple (tree *tp) } } +/* Promote partial stores to COMPLEX variables to total stores. *EXPR_P is + a MODIFY_EXPR with a lhs of a REAL/IMAGPART_EXPR of a variable with + DECL_GIMPLE_REG_P set. + + IMPORTANT NOTE: This promotion is performed by introducing a load of the + other, unmodified part of the complex object just before the total store. + As a consequence, if the object is still uninitialized, an undefined value + will be loaded into a register, which may result in a spurious exception + if the register is floating-point and the value happens to be a signaling + NaN for example. Then the fully-fledged complex operations lowering pass + followed by a DCE pass are necessary in order to fix things up. */ + +static enum gimplify_status +gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value) +{ + enum tree_code code, ocode; + tree lhs, rhs, new_rhs, other, realpart, imagpart; + + lhs = GENERIC_TREE_OPERAND (*expr_p, 0); + rhs = GENERIC_TREE_OPERAND (*expr_p, 1); + code = TREE_CODE (lhs); + lhs = TREE_OPERAND (lhs, 0); + + ocode = code == REALPART_EXPR ? IMAGPART_EXPR : REALPART_EXPR; + other = build1 (ocode, TREE_TYPE (rhs), lhs); + other = get_formal_tmp_var (other, pre_p); + + realpart = code == REALPART_EXPR ? rhs : other; + imagpart = code == REALPART_EXPR ? other : rhs; + + if (TREE_CONSTANT (realpart) && TREE_CONSTANT (imagpart)) + new_rhs = build_complex (TREE_TYPE (lhs), realpart, imagpart); + else + new_rhs = build2 (COMPLEX_EXPR, TREE_TYPE (lhs), realpart, imagpart); + + GENERIC_TREE_OPERAND (*expr_p, 0) = lhs; + GENERIC_TREE_OPERAND (*expr_p, 1) = new_rhs; + + if (want_value) + { + tree_to_gimple_tuple (expr_p); + + append_to_statement_list (*expr_p, pre_p); + *expr_p = rhs; + } + + return GS_ALL_DONE; +} + /* Gimplify the MODIFY_EXPR node pointed to by EXPR_P. modify_expr @@ -3570,8 +3870,16 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value) || TREE_CODE (*expr_p) == GIMPLE_MODIFY_STMT || TREE_CODE (*expr_p) == INIT_EXPR); - /* For zero sized types only gimplify the left hand side and right hand side - as statements and throw away the assignment. */ + /* See if any simplifications can be done based on what the RHS is. */ + ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p, + want_value); + if (ret != GS_UNHANDLED) + return ret; + + /* For zero sized types only gimplify the left hand side and right hand + side as statements and throw away the assignment. Do this after + gimplify_modify_expr_rhs so we handle TARGET_EXPRs of addressable + types properly. */ if (zero_sized_type (TREE_TYPE (*from_p))) { gimplify_stmt (from_p); @@ -3582,12 +3890,6 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value) return GS_ALL_DONE; } - /* See if any simplifications can be done based on what the RHS is. */ - ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p, - want_value); - if (ret != GS_UNHANDLED) - return ret; - /* If the value being copied is of variable width, compute the length of the copy into a WITH_SIZE_EXPR. Note that we need to do this before gimplifying any of the operands so that we can resolve any @@ -3644,6 +3946,19 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value) *to_p = make_ssa_name (*to_p, *expr_p); } + /* Try to alleviate the effects of the gimplification creating artificial + temporaries (see for example is_gimple_reg_rhs) on the debug info. */ + if (!gimplify_ctxp->into_ssa + && DECL_P (*from_p) && DECL_IGNORED_P (*from_p) + && DECL_P (*to_p) && !DECL_IGNORED_P (*to_p)) + { + if (!DECL_NAME (*from_p) && DECL_NAME (*to_p)) + DECL_NAME (*from_p) + = create_tmp_var_name (IDENTIFIER_POINTER (DECL_NAME (*to_p))); + DECL_DEBUG_EXPR_IS_FROM (*from_p) = 1; + SET_DECL_DEBUG_EXPR (*from_p, *to_p); + } + if (want_value) { tree_to_gimple_tuple (expr_p); @@ -3664,18 +3979,15 @@ gimplify_variable_sized_compare (tree *expr_p) { tree op0 = TREE_OPERAND (*expr_p, 0); tree op1 = TREE_OPERAND (*expr_p, 1); - tree args, t, dest; - - t = TYPE_SIZE_UNIT (TREE_TYPE (op0)); - t = unshare_expr (t); - t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, op0); - args = tree_cons (NULL, t, NULL); - t = build_fold_addr_expr (op1); - args = tree_cons (NULL, t, args); + tree t, arg, dest, src; + + 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); - args = tree_cons (NULL, dest, args); t = implicit_built_in_decls[BUILT_IN_MEMCMP]; - t = build_function_call_expr (t, args); + t = build_call_expr (t, 3, dest, src, arg); *expr_p = build2 (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), t, integer_zero_node); @@ -3887,19 +4199,8 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p) tree t_expr = TREE_TYPE (expr); tree t_op00 = TREE_TYPE (op00); - if (!lang_hooks.types_compatible_p (t_expr, t_op00)) - { -#ifdef ENABLE_CHECKING - tree t_op0 = TREE_TYPE (op0); - gcc_assert (POINTER_TYPE_P (t_expr) - && cpt_same_type (TREE_CODE (t_op0) == ARRAY_TYPE - ? TREE_TYPE (t_op0) : t_op0, - TREE_TYPE (t_expr)) - && POINTER_TYPE_P (t_op00) - && cpt_same_type (t_op0, TREE_TYPE (t_op00))); -#endif - op00 = fold_convert (TREE_TYPE (expr), op00); - } + if (!useless_type_conversion_p (t_expr, t_op00)) + op00 = fold_convert (TREE_TYPE (expr), op00); *expr_p = op00; ret = GS_OK; } @@ -3928,6 +4229,8 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p) the address of a call that returns a struct; see gcc.dg/c99-array-lval-1.c. The gimplifier will correctly make the implied temporary explicit. */ + + /* Mark the RHS addressable. */ ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p, is_gimple_addressable, fb_either); if (ret != GS_ERROR) @@ -3943,8 +4246,7 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p) is set properly. */ recompute_tree_invariant_for_addr_expr (expr); - /* Mark the RHS addressable. */ - lang_hooks.mark_addressable (TREE_OPERAND (expr, 0)); + mark_addressable (TREE_OPERAND (expr, 0)); } break; } @@ -3982,7 +4284,7 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p) &allows_mem, &allows_reg, &is_inout); if (!allows_reg && allows_mem) - lang_hooks.mark_addressable (TREE_VALUE (link)); + mark_addressable (TREE_VALUE (link)); tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p, is_inout ? is_gimple_min_lval : is_gimple_lvalue, @@ -4093,12 +4395,25 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p) parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints, &allows_mem, &allows_reg); + /* If we can't make copies, we can only accept memory. */ + if (TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (link)))) + { + if (allows_mem) + allows_reg = 0; + else + { + error ("impossible constraint in %"); + error ("non-memory input %d must stay in memory", i); + return GS_ERROR; + } + } + /* If the operand is a memory input, it should be an lvalue. */ if (!allows_reg && allows_mem) { tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p, is_gimple_lvalue, fb_lvalue | fb_mayfail); - lang_hooks.mark_addressable (TREE_VALUE (link)); + mark_addressable (TREE_VALUE (link)); if (tret == GS_ERROR) { error ("memory input %d is not directly addressable", i); @@ -4238,10 +4553,8 @@ gimple_push_cleanup (tree var, tree cleanup, bool eh_only, tree *pre_p) */ tree flag = create_tmp_var (boolean_type_node, "cleanup"); - tree ffalse = build2 (GIMPLE_MODIFY_STMT, void_type_node, flag, - boolean_false_node); - tree ftrue = build2 (GIMPLE_MODIFY_STMT, void_type_node, flag, - boolean_true_node); + tree ffalse = build_gimple_modify_stmt (flag, boolean_false_node); + tree ftrue = build_gimple_modify_stmt (flag, boolean_true_node); cleanup = build3 (COND_EXPR, void_type_node, flag, cleanup, NULL); wce = build1 (WITH_CLEANUP_EXPR, void_type_node, cleanup); append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups); @@ -4276,8 +4589,15 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p) if (init) { /* TARGET_EXPR temps aren't part of the enclosing block, so add it - to the temps list. */ - gimple_add_tmp_var (temp); + to the temps list. Handle also variable length TARGET_EXPRs. */ + if (TREE_CODE (DECL_SIZE (temp)) != INTEGER_CST) + { + if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (temp))) + gimplify_type_sizes (TREE_TYPE (temp), pre_p); + gimplify_vla_decl (temp, pre_p); + } + else + gimple_add_tmp_var (temp); /* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the expression is supposed to initialize the slot. */ @@ -4290,7 +4610,11 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p) fb_none); } if (ret == GS_ERROR) - return GS_ERROR; + { + /* PR c++/28266 Make sure this is expanded only once. */ + TARGET_EXPR_INITIAL (targ) = NULL_TREE; + return GS_ERROR; + } append_to_statement_list (init, pre_p); /* If needed, push the cleanup for the temp. */ @@ -4389,6 +4713,7 @@ omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *ctx, tree type) case ENUMERAL_TYPE: case BOOLEAN_TYPE: case REAL_TYPE: + case FIXED_POINT_TYPE: omp_firstprivatize_variable (ctx, TYPE_MIN_VALUE (type)); omp_firstprivatize_variable (ctx, TYPE_MAX_VALUE (type)); break; @@ -4495,8 +4820,11 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) /* We're going to make use of the TYPE_SIZE_UNIT at least in the alloca statement we generate for the variable, so make sure it is available. This isn't automatically needed for the SHARED - case, since we won't be allocating local storage then. */ - else + case, since we won't be allocating local storage then. + For local variables TYPE_SIZE_UNIT might not be gimplified yet, + in this case omp_notice_variable will be called later + on when it is gimplified. */ + else if (! (flags & GOVD_LOCAL)) omp_notice_variable (ctx, TYPE_SIZE_UNIT (TREE_TYPE (decl)), true); } else if (lang_hooks.decls.omp_privatize_by_reference (decl)) @@ -4654,6 +4982,31 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl) return !is_global_var (decl); } +/* Return true if DECL is private within a parallel region + that binds to the current construct's context or in parallel + region's REDUCTION clause. */ + +static bool +omp_check_private (struct gimplify_omp_ctx *ctx, tree decl) +{ + splay_tree_node n; + + do + { + ctx = ctx->outer_context; + if (ctx == NULL) + return !(is_global_var (decl) + /* References might be private, but might be shared too. */ + || lang_hooks.decls.omp_privatize_by_reference (decl)); + + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + if (n != NULL) + return (n->value & GOVD_SHARED) == 0; + } + while (!ctx->is_parallel); + return false; +} + /* Scan the OpenMP clauses in *LIST_P, installing mappings into a new and previous omp contexts. */ @@ -4672,6 +5025,7 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel, enum gimplify_status gs; bool remove = false; bool notice_outer = true; + const char *check_non_private = NULL; unsigned int flags; tree decl; @@ -4686,12 +5040,15 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel, goto do_add; case OMP_CLAUSE_FIRSTPRIVATE: flags = GOVD_FIRSTPRIVATE | GOVD_EXPLICIT; + check_non_private = "firstprivate"; goto do_add; case OMP_CLAUSE_LASTPRIVATE: flags = GOVD_LASTPRIVATE | GOVD_SEEN | GOVD_EXPLICIT; + check_non_private = "lastprivate"; goto do_add; case OMP_CLAUSE_REDUCTION: flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT; + check_non_private = "reduction"; goto do_add; do_add: @@ -4701,11 +5058,6 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel, remove = true; break; } - /* Handle NRV results passed by reference. */ - if (TREE_CODE (decl) == INDIRECT_REF - && TREE_CODE (TREE_OPERAND (decl, 0)) == RESULT_DECL - && DECL_BY_REFERENCE (TREE_OPERAND (decl, 0))) - OMP_CLAUSE_DECL (c) = decl = TREE_OPERAND (decl, 0); omp_add_variable (ctx, decl, flags); if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) @@ -4733,14 +5085,17 @@ gimplify_scan_omp_clauses (tree *list_p, tree *pre_p, bool in_parallel, remove = true; break; } - /* Handle NRV results passed by reference. */ - if (TREE_CODE (decl) == INDIRECT_REF - && TREE_CODE (TREE_OPERAND (decl, 0)) == RESULT_DECL - && DECL_BY_REFERENCE (TREE_OPERAND (decl, 0))) - OMP_CLAUSE_DECL (c) = decl = TREE_OPERAND (decl, 0); do_notice: if (outer_ctx) omp_notice_variable (outer_ctx, decl, true); + if (check_non_private + && !in_parallel + && omp_check_private (ctx, decl)) + { + error ("%s variable %qs is private in outer context", + check_non_private, IDENTIFIER_POINTER (DECL_NAME (decl))); + remove = true; + } break; case OMP_CLAUSE_IF: @@ -4808,7 +5163,20 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) else if (flags & GOVD_SHARED) { if (is_global_var (decl)) - return 0; + { + struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp->outer_context; + while (ctx != NULL) + { + splay_tree_node on + = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + if (on && (on->value & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE + | GOVD_PRIVATE | GOVD_REDUCTION)) != 0) + break; + ctx = ctx->outer_context; + } + if (ctx == NULL) + return 0; + } code = OMP_CLAUSE_SHARED; } else if (flags & GOVD_PRIVATE) @@ -4931,8 +5299,9 @@ gimplify_omp_parallel (tree *expr_p, tree *pre_p) static enum gimplify_status gimplify_omp_for (tree *expr_p, tree *pre_p) { - tree for_stmt, decl, t; + tree for_stmt, decl, var, t; enum gimplify_status ret = GS_OK; + tree body, init_decl = NULL_TREE; for_stmt = *expr_p; @@ -4951,6 +5320,24 @@ gimplify_omp_for (tree *expr_p, tree *pre_p) else omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN); + /* If DECL is not a gimple register, create a temporary variable to act as an + iteration counter. This is valid, since DECL cannot be modified in the + body of the loop. */ + if (!is_gimple_reg (decl)) + { + var = create_tmp_var (TREE_TYPE (decl), get_name (decl)); + GENERIC_TREE_OPERAND (t, 0) = var; + + init_decl = build_gimple_modify_stmt (decl, var); + omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN); + } + else + var = decl; + + /* If OMP_FOR is re-gimplified, ensure all variables in pre-body + are noticed. */ + gimplify_stmt (&OMP_FOR_PRE_BODY (for_stmt)); + ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1), &OMP_FOR_PRE_BODY (for_stmt), NULL, is_gimple_val, fb_rvalue); @@ -4960,6 +5347,7 @@ gimplify_omp_for (tree *expr_p, tree *pre_p) t = OMP_FOR_COND (for_stmt); gcc_assert (COMPARISON_CLASS_P (t)); gcc_assert (GENERIC_TREE_OPERAND (t, 0) == decl); + TREE_OPERAND (t, 0) = var; ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1), &OMP_FOR_PRE_BODY (for_stmt), @@ -4972,19 +5360,23 @@ gimplify_omp_for (tree *expr_p, tree *pre_p) case PREINCREMENT_EXPR: case POSTINCREMENT_EXPR: t = build_int_cst (TREE_TYPE (decl), 1); - goto build_modify; + t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t); + t = build_gimple_modify_stmt (var, t); + OMP_FOR_INCR (for_stmt) = t; + break; + case PREDECREMENT_EXPR: case POSTDECREMENT_EXPR: t = build_int_cst (TREE_TYPE (decl), -1); - goto build_modify; - build_modify: - t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t); - t = build2 (GIMPLE_MODIFY_STMT, void_type_node, decl, t); + t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t); + t = build_gimple_modify_stmt (var, t); OMP_FOR_INCR (for_stmt) = t; break; case GIMPLE_MODIFY_STMT: gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == decl); + GIMPLE_STMT_OPERAND (t, 0) = var; + t = GIMPLE_STMT_OPERAND (t, 1); switch (TREE_CODE (t)) { @@ -4992,11 +5384,14 @@ gimplify_omp_for (tree *expr_p, tree *pre_p) if (TREE_OPERAND (t, 1) == decl) { TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0); - TREE_OPERAND (t, 0) = decl; + TREE_OPERAND (t, 0) = var; break; } + + /* Fallthru. */ case MINUS_EXPR: gcc_assert (TREE_OPERAND (t, 0) == decl); + TREE_OPERAND (t, 0) = var; break; default: gcc_unreachable (); @@ -5010,7 +5405,13 @@ gimplify_omp_for (tree *expr_p, tree *pre_p) gcc_unreachable (); } - gimplify_to_stmt_list (&OMP_FOR_BODY (for_stmt)); + body = OMP_FOR_BODY (for_stmt); + gimplify_to_stmt_list (&body); + t = alloc_stmt_list (); + if (init_decl) + append_to_statement_list (init_decl, &t); + append_to_statement_list (body, &t); + OMP_FOR_BODY (for_stmt) = t; gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt)); return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR; @@ -5049,74 +5450,28 @@ goa_lhs_expr_p (tree expr, tree addr) == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (expr, 0))))) expr = TREE_OPERAND (expr, 0); - if (TREE_CODE (expr) == INDIRECT_REF && TREE_OPERAND (expr, 0) == addr) - return true; + if (TREE_CODE (expr) == INDIRECT_REF) + { + expr = TREE_OPERAND (expr, 0); + while (expr != addr + && (TREE_CODE (expr) == NOP_EXPR + || TREE_CODE (expr) == CONVERT_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))) + { + expr = TREE_OPERAND (expr, 0); + addr = TREE_OPERAND (addr, 0); + } + return expr == addr; + } if (TREE_CODE (addr) == ADDR_EXPR && expr == TREE_OPERAND (addr, 0)) return true; return false; } -/* A subroutine of gimplify_omp_atomic. Attempt to implement the atomic - operation as a __sync_fetch_and_op builtin. INDEX is log2 of the - size of the data type, and thus usable to find the index of the builtin - decl. Returns GS_UNHANDLED if the expression is not of the proper form. */ - -static enum gimplify_status -gimplify_omp_atomic_fetch_op (tree *expr_p, tree addr, tree rhs, int index) -{ - enum built_in_function base; - tree decl, args, itype; - enum insn_code *optab; - - /* Check for one of the supported fetch-op operations. */ - switch (TREE_CODE (rhs)) - { - case PLUS_EXPR: - base = BUILT_IN_FETCH_AND_ADD_N; - optab = sync_add_optab; - break; - case MINUS_EXPR: - base = BUILT_IN_FETCH_AND_SUB_N; - optab = sync_add_optab; - break; - case BIT_AND_EXPR: - base = BUILT_IN_FETCH_AND_AND_N; - optab = sync_and_optab; - break; - case BIT_IOR_EXPR: - base = BUILT_IN_FETCH_AND_OR_N; - optab = sync_ior_optab; - break; - case BIT_XOR_EXPR: - base = BUILT_IN_FETCH_AND_XOR_N; - optab = sync_xor_optab; - break; - default: - return GS_UNHANDLED; - } - - /* Make sure the expression is of the proper form. */ - if (goa_lhs_expr_p (TREE_OPERAND (rhs, 0), addr)) - rhs = TREE_OPERAND (rhs, 1); - else if (commutative_tree_code (TREE_CODE (rhs)) - && goa_lhs_expr_p (TREE_OPERAND (rhs, 1), addr)) - rhs = TREE_OPERAND (rhs, 0); - else - return GS_UNHANDLED; - - decl = built_in_decls[base + index + 1]; - itype = TREE_TYPE (TREE_TYPE (decl)); - - if (optab[TYPE_MODE (itype)] == CODE_FOR_nothing) - return GS_UNHANDLED; - - args = tree_cons (NULL, fold_convert (itype, rhs), NULL); - args = tree_cons (NULL, addr, args); - *expr_p = build_function_call_expr (decl, args); - return GS_OK; -} - -/* A subroutine of gimplify_omp_atomic_pipeline. Walk *EXPR_P and replace +/* Walk *EXPR_P and replace appearances of *LHS_ADDR with LHS_VAR. If an expression does not involve the lhs, evaluate it into a temporary. Return 1 if the lhs appeared as a subexpression, 0 if it did not, or -1 if an error was encountered. */ @@ -5160,146 +5515,6 @@ goa_stabilize_expr (tree *expr_p, tree *pre_p, tree lhs_addr, tree lhs_var) return saw_lhs; } -/* A subroutine of gimplify_omp_atomic. Implement the atomic operation as: - - oldval = *addr; - repeat: - newval = rhs; // with oldval replacing *addr in rhs - oldval = __sync_val_compare_and_swap (addr, oldval, newval); - if (oldval != newval) - goto repeat; - - INDEX is log2 of the size of the data type, and thus usable to find the - index of the builtin decl. */ - -static enum gimplify_status -gimplify_omp_atomic_pipeline (tree *expr_p, tree *pre_p, tree addr, - tree rhs, int index) -{ - tree oldval, oldival, oldival2, newval, newival, label; - tree type, itype, cmpxchg, args, x, iaddr; - - cmpxchg = built_in_decls[BUILT_IN_VAL_COMPARE_AND_SWAP_N + index + 1]; - type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr))); - itype = TREE_TYPE (TREE_TYPE (cmpxchg)); - - if (sync_compare_and_swap[TYPE_MODE (itype)] == CODE_FOR_nothing) - return GS_UNHANDLED; - - oldval = create_tmp_var (type, NULL); - newval = create_tmp_var (type, NULL); - - /* Precompute as much of RHS as possible. In the same walk, replace - occurrences of the lhs value with our temporary. */ - if (goa_stabilize_expr (&rhs, pre_p, addr, oldval) < 0) - return GS_ERROR; - - x = build_fold_indirect_ref (addr); - x = build2 (GIMPLE_MODIFY_STMT, void_type_node, oldval, x); - gimplify_and_add (x, pre_p); - - /* For floating-point values, we'll need to view-convert them to integers - so that we can perform the atomic compare and swap. Simplify the - following code by always setting up the "i"ntegral variables. */ - if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)) - { - oldival = oldval; - newival = newval; - iaddr = addr; - } - else - { - oldival = create_tmp_var (itype, NULL); - newival = create_tmp_var (itype, NULL); - - x = build1 (VIEW_CONVERT_EXPR, itype, oldval); - x = build2 (GIMPLE_MODIFY_STMT, void_type_node, oldival, x); - gimplify_and_add (x, pre_p); - iaddr = fold_convert (build_pointer_type (itype), addr); - } - - oldival2 = create_tmp_var (itype, NULL); - - label = create_artificial_label (); - x = build1 (LABEL_EXPR, void_type_node, label); - gimplify_and_add (x, pre_p); - - x = build2 (GIMPLE_MODIFY_STMT, void_type_node, newval, rhs); - gimplify_and_add (x, pre_p); - - if (newval != newival) - { - x = build1 (VIEW_CONVERT_EXPR, itype, newval); - x = build2 (GIMPLE_MODIFY_STMT, void_type_node, newival, x); - gimplify_and_add (x, pre_p); - } - - x = build2 (GIMPLE_MODIFY_STMT, void_type_node, oldival2, - fold_convert (itype, oldival)); - gimplify_and_add (x, pre_p); - - args = tree_cons (NULL, fold_convert (itype, newival), NULL); - args = tree_cons (NULL, fold_convert (itype, oldival), args); - args = tree_cons (NULL, iaddr, args); - x = build_function_call_expr (cmpxchg, args); - if (oldval == oldival) - x = fold_convert (type, x); - x = build2 (GIMPLE_MODIFY_STMT, void_type_node, oldival, x); - gimplify_and_add (x, pre_p); - - /* For floating point, be prepared for the loop backedge. */ - if (oldval != oldival) - { - x = build1 (VIEW_CONVERT_EXPR, type, oldival); - x = build2 (GIMPLE_MODIFY_STMT, void_type_node, oldval, x); - gimplify_and_add (x, pre_p); - } - - /* Note that we always perform the comparison as an integer, even for - floating point. This allows the atomic operation to properly - succeed even with NaNs and -0.0. */ - x = build3 (COND_EXPR, void_type_node, - build2 (NE_EXPR, boolean_type_node, oldival, oldival2), - build1 (GOTO_EXPR, void_type_node, label), NULL); - gimplify_and_add (x, pre_p); - - *expr_p = NULL; - return GS_ALL_DONE; -} - -/* A subroutine of gimplify_omp_atomic. Implement the atomic operation as: - - GOMP_atomic_start (); - *addr = rhs; - GOMP_atomic_end (); - - The result is not globally atomic, but works so long as all parallel - references are within #pragma omp atomic directives. According to - responses received from omp@openmp.org, appears to be within spec. - Which makes sense, since that's how several other compilers handle - this situation as well. */ - -static enum gimplify_status -gimplify_omp_atomic_mutex (tree *expr_p, tree *pre_p, tree addr, tree rhs) -{ - tree t; - - t = built_in_decls[BUILT_IN_GOMP_ATOMIC_START]; - t = build_function_call_expr (t, NULL); - gimplify_and_add (t, pre_p); - - t = build_fold_indirect_ref (addr); - t = build2 (GIMPLE_MODIFY_STMT, void_type_node, t, rhs); - gimplify_and_add (t, pre_p); - - t = built_in_decls[BUILT_IN_GOMP_ATOMIC_END]; - t = build_function_call_expr (t, NULL); - gimplify_and_add (t, pre_p); - - *expr_p = NULL; - return GS_ALL_DONE; -} - /* Gimplify an OMP_ATOMIC statement. */ static enum gimplify_status @@ -5308,46 +5523,26 @@ gimplify_omp_atomic (tree *expr_p, tree *pre_p) tree addr = TREE_OPERAND (*expr_p, 0); tree rhs = TREE_OPERAND (*expr_p, 1); tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr))); - HOST_WIDE_INT index; + tree tmp_load, load, store; - /* Make sure the type is one of the supported sizes. */ - index = tree_low_cst (TYPE_SIZE_UNIT (type), 1); - index = exact_log2 (index); - if (index >= 0 && index <= 4) - { - enum gimplify_status gs; - unsigned int align; - - if (DECL_P (TREE_OPERAND (addr, 0))) - align = DECL_ALIGN_UNIT (TREE_OPERAND (addr, 0)); - else if (TREE_CODE (TREE_OPERAND (addr, 0)) == COMPONENT_REF - && TREE_CODE (TREE_OPERAND (TREE_OPERAND (addr, 0), 1)) - == FIELD_DECL) - align = DECL_ALIGN_UNIT (TREE_OPERAND (TREE_OPERAND (addr, 0), 1)); - else - align = TYPE_ALIGN_UNIT (type); + tmp_load = create_tmp_var (type, NULL); + if (goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0) + return GS_ERROR; - /* __sync builtins require strict data alignment. */ - if (exact_log2 (align) >= index) - { - /* When possible, use specialized atomic update functions. */ - if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)) - { - gs = gimplify_omp_atomic_fetch_op (expr_p, addr, rhs, index); - if (gs != GS_UNHANDLED) - return gs; - } + if (gimplify_expr (&addr, pre_p, NULL, is_gimple_val, fb_rvalue) + != GS_ALL_DONE) + return GS_ERROR; - /* If we don't have specialized __sync builtins, try and implement - as a compare and swap loop. */ - gs = gimplify_omp_atomic_pipeline (expr_p, pre_p, addr, rhs, index); - if (gs != GS_UNHANDLED) - return gs; - } - } + load = build2 (OMP_ATOMIC_LOAD, void_type_node, tmp_load, addr); + append_to_statement_list (load, pre_p); + if (gimplify_expr (&rhs, pre_p, NULL, is_gimple_val, fb_rvalue) + != GS_ALL_DONE) + return GS_ERROR; + store = build1 (OMP_ATOMIC_STORE, void_type_node, rhs); + *expr_p = store; + + return GS_ALL_DONE; - /* The ultimate fallback is wrapping the operation in a mutex. */ - return gimplify_omp_atomic_mutex (expr_p, pre_p, addr, rhs); } /* Gimplifies the expression tree pointed to by EXPR_P. Return 0 if @@ -5476,7 +5671,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, if (fallback == fb_lvalue) { *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); - lang_hooks.mark_addressable (*expr_p); + mark_addressable (*expr_p); } break; @@ -5489,7 +5684,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, if (fallback == fb_lvalue) { *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); - lang_hooks.mark_addressable (*expr_p); + mark_addressable (*expr_p); } break; @@ -5587,6 +5782,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, /* Constants need not be gimplified. */ case INTEGER_CST: case REAL_CST: + case FIXED_CST: case STRING_CST: case COMPLEX_CST: case VECTOR_CST: @@ -5677,7 +5873,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, else if (fallback == fb_lvalue) { *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); - lang_hooks.mark_addressable (*expr_p); + mark_addressable (*expr_p); } else ret = GS_ALL_DONE; @@ -5741,6 +5937,11 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, ret = GS_ALL_DONE; break; + case CHANGE_DYNAMIC_TYPE_EXPR: + ret = gimplify_expr (&CHANGE_DYNAMIC_TYPE_LOCATION (*expr_p), + pre_p, post_p, is_gimple_reg, fb_lvalue); + break; + case OBJ_TYPE_REF: { enum gimplify_status r0, r1; @@ -5817,9 +6018,45 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, case OMP_RETURN: case OMP_CONTINUE: + case OMP_ATOMIC_LOAD: + case OMP_ATOMIC_STORE: + ret = GS_ALL_DONE; break; + case POINTER_PLUS_EXPR: + /* Convert ((type *)A)+offset into &A->field_of_type_and_offset. + 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; + } + } + /* 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 = build_fold_addr_expr (tmp); + *expr_p = fold_convert (TREE_TYPE (*expr_p), tmp); + break; + } + /* FALLTHRU */ default: switch (TREE_CODE_CLASS (TREE_CODE (*expr_p))) { @@ -5957,7 +6194,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, given a TREE_ADDRESSABLE type. */ tree tmp = create_tmp_var_raw (type, "vol"); gimple_add_tmp_var (tmp); - *expr_p = build2 (GIMPLE_MODIFY_STMT, type, tmp, *expr_p); + *expr_p = build_gimple_modify_stmt (tmp, *expr_p); } else /* We can't do anything useful with a volatile reference to @@ -6092,6 +6329,7 @@ gimplify_type_sizes (tree type, tree *list_p) case ENUMERAL_TYPE: case BOOLEAN_TYPE: case REAL_TYPE: + case FIXED_POINT_TYPE: gimplify_one_sizepos (&TYPE_MIN_VALUE (type), list_p); gimplify_one_sizepos (&TYPE_MAX_VALUE (type), list_p); @@ -6189,7 +6427,7 @@ gimplify_one_sizepos (tree *expr_p, tree *stmt_p) *expr_p = create_tmp_var (type, NULL); tmp = build1 (NOP_EXPR, type, expr); - tmp = build2 (GIMPLE_MODIFY_STMT, type, *expr_p, tmp); + tmp = build_gimple_modify_stmt (*expr_p, tmp); if (EXPR_HAS_LOCATION (expr)) SET_EXPR_LOCUS (tmp, EXPR_LOCUS (expr)); else @@ -6199,84 +6437,6 @@ gimplify_one_sizepos (tree *expr_p, tree *stmt_p) } } -#ifdef ENABLE_CHECKING -/* Compare types A and B for a "close enough" match. */ - -static bool -cpt_same_type (tree a, tree b) -{ - if (lang_hooks.types_compatible_p (a, b)) - return true; - - /* ??? The C++ FE decomposes METHOD_TYPES to FUNCTION_TYPES and doesn't - link them together. This routine is intended to catch type errors - that will affect the optimizers, and the optimizers don't add new - dereferences of function pointers, so ignore it. */ - if ((TREE_CODE (a) == FUNCTION_TYPE || TREE_CODE (a) == METHOD_TYPE) - && (TREE_CODE (b) == FUNCTION_TYPE || TREE_CODE (b) == METHOD_TYPE)) - return true; - - /* ??? The C FE pushes type qualifiers after the fact into the type of - the element from the type of the array. See build_unary_op's handling - of ADDR_EXPR. This seems wrong -- if we were going to do this, we - should have done it when creating the variable in the first place. - Alternately, why aren't the two array types made variants? */ - if (TREE_CODE (a) == ARRAY_TYPE && TREE_CODE (b) == ARRAY_TYPE) - return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b)); - - /* And because of those, we have to recurse down through pointers. */ - if (POINTER_TYPE_P (a) && POINTER_TYPE_P (b)) - return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b)); - - return false; -} - -/* Check for some cases of the front end missing cast expressions. - The type of a dereference should correspond to the pointer type; - similarly the type of an address should match its object. */ - -static tree -check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - tree t = *tp; - tree ptype, otype, dtype; - - switch (TREE_CODE (t)) - { - case INDIRECT_REF: - case ARRAY_REF: - otype = TREE_TYPE (t); - ptype = TREE_TYPE (TREE_OPERAND (t, 0)); - dtype = TREE_TYPE (ptype); - gcc_assert (cpt_same_type (otype, dtype)); - break; - - case ADDR_EXPR: - ptype = TREE_TYPE (t); - otype = TREE_TYPE (TREE_OPERAND (t, 0)); - dtype = TREE_TYPE (ptype); - if (!cpt_same_type (otype, dtype)) - { - /* &array is allowed to produce a pointer to the element, rather than - a pointer to the array type. We must allow this in order to - properly represent assigning the address of an array in C into - pointer to the element type. */ - gcc_assert (TREE_CODE (otype) == ARRAY_TYPE - && POINTER_TYPE_P (ptype) - && cpt_same_type (TREE_TYPE (otype), dtype)); - break; - } - break; - - default: - return NULL_TREE; - } - - - return NULL_TREE; -} -#endif /* Gimplify the body of statements pointed to by BODY_P. FNDECL is the function decl containing BODY. */ @@ -6345,8 +6505,9 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms) pop_gimplify_context (body); gcc_assert (gimplify_ctxp == NULL); -#ifdef ENABLE_CHECKING - walk_tree (body_p, check_pointer_types_r, NULL, NULL); +#ifdef ENABLE_TYPES_CHECKING + if (!errorcount && !sorrycount) + verify_gimple_1 (BIND_EXPR_BODY (*body_p)); #endif timevar_pop (TV_TREE_GIMPLIFY); @@ -6363,25 +6524,28 @@ gimplify_function_tree (tree fndecl) oldfn = current_function_decl; current_function_decl = fndecl; - cfun = DECL_STRUCT_FUNCTION (fndecl); - if (cfun == NULL) - allocate_struct_function (fndecl); + if (DECL_STRUCT_FUNCTION (fndecl)) + push_cfun (DECL_STRUCT_FUNCTION (fndecl)); + else + push_struct_function (fndecl); for (parm = DECL_ARGUMENTS (fndecl); parm ; parm = TREE_CHAIN (parm)) { /* 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 (parm)) == COMPLEX_TYPE + if ((TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE + || TREE_CODE (TREE_TYPE (parm)) == VECTOR_TYPE) && !TREE_THIS_VOLATILE (parm) && !needs_to_live_in_memory (parm)) - DECL_COMPLEX_GIMPLE_REG_P (parm) = 1; + DECL_GIMPLE_REG_P (parm) = 1; } ret = DECL_RESULT (fndecl); - if (TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE + if ((TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE + || TREE_CODE (TREE_TYPE (ret)) == VECTOR_TYPE) && !needs_to_live_in_memory (ret)) - DECL_COMPLEX_GIMPLE_REG_P (ret) = 1; + DECL_GIMPLE_REG_P (ret) = 1; gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl, true); @@ -6390,7 +6554,8 @@ gimplify_function_tree (tree fndecl) catch the exit hook. */ /* ??? Add some way to ignore exceptions for this TFE. */ if (flag_instrument_function_entry_exit - && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl)) + && !DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) + && !flag_instrument_functions_exclude_p (fndecl)) { tree tf, x, bind; @@ -6399,13 +6564,13 @@ gimplify_function_tree (tree fndecl) x = DECL_SAVED_TREE (fndecl); append_to_statement_list (x, &TREE_OPERAND (tf, 0)); x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_EXIT]; - x = build_function_call_expr (x, NULL); + x = build_call_expr (x, 0); append_to_statement_list (x, &TREE_OPERAND (tf, 1)); bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); TREE_SIDE_EFFECTS (bind) = 1; x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_ENTER]; - x = build_function_call_expr (x, NULL); + x = build_call_expr (x, 0); append_to_statement_list (x, &BIND_EXPR_BODY (bind)); append_to_statement_list (tf, &BIND_EXPR_BODY (bind)); @@ -6414,7 +6579,7 @@ gimplify_function_tree (tree fndecl) cfun->gimplified = true; current_function_decl = oldfn; - cfun = oldfn ? DECL_STRUCT_FUNCTION (oldfn) : NULL; + pop_cfun (); } /* Expands EXPR to list of gimple statements STMTS. If SIMPLE is true, @@ -6438,13 +6603,23 @@ force_gimple_operand (tree expr, tree *stmts, bool simple, tree var) push_gimplify_context (); gimplify_ctxp->into_ssa = gimple_in_ssa_p (cfun); + gimplify_ctxp->allow_rhs_cond_expr = true; if (var) - expr = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), var, expr); + expr = build_gimple_modify_stmt (var, expr); - ret = gimplify_expr (&expr, stmts, NULL, - gimple_test_f, fb_rvalue); - gcc_assert (ret != GS_ERROR); + if (TREE_CODE (expr) != GIMPLE_MODIFY_STMT + && TREE_TYPE (expr) == void_type_node) + { + gimplify_and_add (expr, stmts); + expr = NULL_TREE; + } + else + { + ret = gimplify_expr (&expr, stmts, NULL, + gimple_test_f, fb_rvalue); + gcc_assert (ret != GS_ERROR); + } if (gimple_referenced_vars (cfun)) { @@ -6454,21 +6629,38 @@ force_gimple_operand (tree expr, tree *stmts, bool simple, tree var) pop_gimplify_context (NULL); + if (*stmts && gimple_in_ssa_p (cfun)) + { + tree_stmt_iterator tsi; + + for (tsi = tsi_start (*stmts); !tsi_end_p (tsi); tsi_next (&tsi)) + mark_symbols_for_renaming (tsi_stmt (tsi)); + } + return expr; } /* Invokes force_gimple_operand for EXPR with parameters SIMPLE_P and VAR. If - some statements are produced, emits them before BSI. */ + some statements are produced, emits them at BSI. If BEFORE is true. + the statements are appended before BSI, otherwise they are appended after + it. M specifies the way BSI moves after insertion (BSI_SAME_STMT or + BSI_CONTINUE_LINKING are the usual values). */ tree force_gimple_operand_bsi (block_stmt_iterator *bsi, tree expr, - bool simple_p, tree var) + bool simple_p, tree var, bool before, + enum bsi_iterator_update m) { tree stmts; expr = force_gimple_operand (expr, &stmts, simple_p, var); if (stmts) - bsi_insert_before (bsi, stmts, BSI_SAME_STMT); + { + if (before) + bsi_insert_before (bsi, stmts, m); + else + bsi_insert_after (bsi, stmts, m); + } return expr; }