From 4744afba0fa727eb34cc673ce51f17648a5731e3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Dec 2004 20:42:14 -0800 Subject: [PATCH] re PR middle-end/16417 (crappy code (gcc.c-torture/compile/20020210-1.c) in arguments causes ICE) PR middle-end/16417 * c-decl.c (store_parm_decls): Clarify get_pending_sizes insertion comment. * c-objc-common.c (c_cannot_inline_tree_fn): Remove pending sizes checks. * c-tree.h (struct lang_decl): Remove pending_sizes. * function.c: Include tree-gimple.h (assign_parm_setup_reg): Remove callee-copies code. (gimplify_parm_type, gimplify_parameters): New functions. (expand_pending_sizes): Remove. (expand_function_start): Don't call it. * gimplify.c (gimplify_expr): Examine DECL_VALUE_EXPR for PARM_DECL. (gimplify_body): Add do_parms argument. Use gimplify_parameters. (gimplify_function_tree): Setup cfun. Update gimplify_body call. * tree-gimple.h (gimplify_body): Update decl. * tree-inline.c (initialize_inlined_parameters): Update gimplify_body call. * tree.h (gimplify_parameters): Declare. * Makefile.in (function.o): Depend on TREE_GIMPLE_H. From-SVN: r92373 --- gcc/ChangeLog | 22 ++++++ gcc/Makefile.in | 2 +- gcc/c-decl.c | 7 +- gcc/c-objc-common.c | 30 -------- gcc/c-tree.h | 5 +- gcc/function.c | 173 ++++++++++++++++++++++++++++---------------- gcc/gimplify.c | 33 +++++++-- gcc/tree-gimple.h | 2 +- gcc/tree-inline.c | 2 +- gcc/tree.h | 1 + 10 files changed, 169 insertions(+), 108 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f9a9b5628bc..60b90b06b8c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,25 @@ +2004-12-18 Richard Henderson + + PR middle-end/16417 + * c-decl.c (store_parm_decls): Clarify get_pending_sizes insertion + comment. + * c-objc-common.c (c_cannot_inline_tree_fn): Remove pending sizes + checks. + * c-tree.h (struct lang_decl): Remove pending_sizes. + * function.c: Include tree-gimple.h + (assign_parm_setup_reg): Remove callee-copies code. + (gimplify_parm_type, gimplify_parameters): New functions. + (expand_pending_sizes): Remove. + (expand_function_start): Don't call it. + * gimplify.c (gimplify_expr): Examine DECL_VALUE_EXPR for PARM_DECL. + (gimplify_body): Add do_parms argument. Use gimplify_parameters. + (gimplify_function_tree): Setup cfun. Update gimplify_body call. + * tree-gimple.h (gimplify_body): Update decl. + * tree-inline.c (initialize_inlined_parameters): Update gimplify_body + call. + * tree.h (gimplify_parameters): Declare. + * Makefile.in (function.o): Depend on TREE_GIMPLE_H. + 2004-12-18 Richard Henderson * c-decl.c (finish_struct): Add DECL_EXPR for variable sized diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 801e231642b..c73562b6c3c 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1843,7 +1843,7 @@ varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_ output.h $(C_PRAGMA_H) toplev.h xcoffout.h debug.h $(GGC_H) $(TM_P_H) \ $(HASHTAB_H) $(TARGET_H) langhooks.h gt-varasm.h real.h function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ - $(TREE_H) $(CFGLAYOUT_H) \ + $(TREE_H) $(CFGLAYOUT_H) $(TREE_GIMPLE_H) \ $(FLAGS_H) function.h $(EXPR_H) $(OPTABS_H) libfuncs.h $(REGS_H) hard-reg-set.h \ insn-config.h $(RECOG_H) output.h toplev.h except.h $(HASHTAB_H) $(GGC_H) \ $(TM_P_H) langhooks.h gt-function.h $(TARGET_H) basic-block.h diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 26caa2c47b3..e6b4cba7912 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -6235,8 +6235,11 @@ store_parm_decls (void) DECL_SAVED_TREE (fndecl) = push_stmt_list (); /* ??? Insert the contents of the pending sizes list into the function - to be evaluated. This just changes mis-behavior until assign_parms - phase ordering problems are resolved. */ + to be evaluated. The only reason left to have this is + void foo(int n, int array[n++]) + because we throw away the array type in favor of a pointer type, and + thus won't naturally see the SAVE_EXPR containing the increment. All + other pending sizes would be handled by gimplify_parameters. */ { tree t; for (t = nreverse (get_pending_sizes ()); t ; t = TREE_CHAIN (t)) diff --git a/gcc/c-objc-common.c b/gcc/c-objc-common.c index d9e8b93e481..35bcf9e3275 100644 --- a/gcc/c-objc-common.c +++ b/gcc/c-objc-common.c @@ -68,7 +68,6 @@ int c_cannot_inline_tree_fn (tree *fnp) { tree fn = *fnp; - tree t; bool do_warning = (warn_inline && DECL_INLINE (fn) && DECL_DECLARED_INLINE_P (fn) @@ -101,35 +100,6 @@ c_cannot_inline_tree_fn (tree *fnp) goto cannot_inline; } - /* If a function has pending sizes, we must not defer its - compilation, and we can't inline it as a tree. */ - if (fn == current_function_decl) - { - t = get_pending_sizes (); - put_pending_sizes (t); - - if (t) - { - if (do_warning) - warning ("%Jfunction %qF can never be inlined because it has " - "pending sizes", fn, fn); - goto cannot_inline; - } - } - - if (!DECL_FILE_SCOPE_P (fn)) - { - /* If a nested function has pending sizes, we may have already - saved them. */ - if (DECL_LANG_SPECIFIC (fn)->pending_sizes) - { - if (do_warning) - warning ("%Jnested function %qF can never be inlined because it " - "has possibly saved pending sizes", fn, fn); - goto cannot_inline; - } - } - return 0; cannot_inline: diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 5415ee079b6..43001ca0aa5 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -41,10 +41,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA struct lang_decl GTY(()) { - /* The return types and parameter types may have variable size. - This is a list of any SAVE_EXPRs that need to be evaluated to - compute those sizes. */ - tree pending_sizes; + char dummy; }; /* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is read-only. */ diff --git a/gcc/function.c b/gcc/function.c index 046a4adda6d..9251071d6f8 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -59,6 +59,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "langhooks.h" #include "target.h" #include "cfglayout.h" +#include "tree-gimple.h" #ifndef LOCAL_ALIGNMENT #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT @@ -2804,50 +2805,6 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm, data->stack_parm = NULL; } - /* If we are passed an arg by reference and it is our responsibility - to make a copy, do it now. - PASSED_TYPE and PASSED mode now refer to the pointer, not the - original argument, so we must recreate them in the call to - FUNCTION_ARG_CALLEE_COPIES. */ - /* ??? Later add code to handle the case that if the argument isn't - modified, don't do the copy. */ - - else if (data->passed_pointer) - { - tree type = TREE_TYPE (data->passed_type); - - if (reference_callee_copied (&all->args_so_far, TYPE_MODE (type), - type, data->named_arg)) - { - rtx copy; - - /* This sequence may involve a library call perhaps clobbering - registers that haven't been copied to pseudos yet. */ - - push_to_sequence (all->conversion_insns); - - if (!COMPLETE_TYPE_P (type) - || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) - { - /* This is a variable sized object. */ - copy = allocate_dynamic_stack_space (expr_size (parm), NULL_RTX, - TYPE_ALIGN (type)); - copy = gen_rtx_MEM (BLKmode, copy); - } - else - copy = assign_stack_temp (TYPE_MODE (type), - int_size_in_bytes (type), 1); - set_mem_attributes (copy, parm, 1); - - store_expr (parm, copy, 0); - emit_move_insn (parmreg, XEXP (copy, 0)); - all->conversion_insns = get_insns (); - end_sequence (); - - did_conversion = true; - } - } - /* Mark the register as eliminable if we did no conversion and it was copied from memory at a fixed offset, and the arg pointer was not copied to a pseudo-reg. If the arg pointer is a pseudo reg or the @@ -3202,6 +3159,115 @@ assign_parms (tree fndecl) } } } + +/* A subroutine of gimplify_parameters, invoked via walk_tree. + For all seen types, gimplify their sizes. */ + +static tree +gimplify_parm_type (tree *tp, int *walk_subtrees, void *data) +{ + tree t = *tp; + + *walk_subtrees = 0; + if (TYPE_P (t)) + { + if (POINTER_TYPE_P (t)) + *walk_subtrees = 1; + else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))) + { + gimplify_type_sizes (t, (tree *) data); + *walk_subtrees = 1; + } + } + + return NULL; +} + +/* Gimplify the parameter list for current_function_decl. This involves + evaluating SAVE_EXPRs of variable sized parameters and generating code + to implement callee-copies reference parameters. Returns a list of + statements to add to the beginning of the function, or NULL if nothing + to do. */ + +tree +gimplify_parameters (void) +{ + struct assign_parm_data_all all; + tree fnargs, parm, stmts = NULL; + + assign_parms_initialize_all (&all); + fnargs = assign_parms_augmented_arg_list (&all); + + for (parm = fnargs; parm; parm = TREE_CHAIN (parm)) + { + struct assign_parm_data_one data; + + /* Extract the type of PARM; adjust it according to ABI. */ + assign_parm_find_data_types (&all, parm, &data); + + /* Early out for errors and void parameters. */ + if (data.passed_mode == VOIDmode || DECL_SIZE (parm) == NULL) + continue; + + /* Update info on where next arg arrives in registers. */ + FUNCTION_ARG_ADVANCE (all.args_so_far, data.promoted_mode, + data.passed_type, data.named_arg); + + /* ??? Once upon a time variable_size stuffed parameter list + SAVE_EXPRs (amongst others) onto a pending sizes list. This + turned out to be less than manageable in the gimple world. + Now we have to hunt them down ourselves. */ + walk_tree_without_duplicates (&data.passed_type, + gimplify_parm_type, &stmts); + + if (!TREE_CONSTANT (DECL_SIZE (parm))) + { + gimplify_one_sizepos (&DECL_SIZE (parm), &stmts); + gimplify_one_sizepos (&DECL_SIZE_UNIT (parm), &stmts); + } + + if (data.passed_pointer) + { + tree type = TREE_TYPE (data.passed_type); + if (reference_callee_copied (&all.args_so_far, TYPE_MODE (type), + type, data.named_arg)) + { + tree local, t; + + /* For constant sized objects, this is trivial; for + variable-sized objects, we have to play games. */ + if (TREE_CONSTANT (DECL_SIZE (parm))) + { + local = create_tmp_var (type, get_name (parm)); + DECL_IGNORED_P (local) = 0; + } + else + { + tree ptr_type, addr, args; + + ptr_type = build_pointer_type (type); + addr = create_tmp_var (ptr_type, get_name (parm)); + DECL_IGNORED_P (addr) = 0; + local = build_fold_indirect_ref (addr); + + args = tree_cons (NULL, DECL_SIZE_UNIT (parm), NULL); + t = built_in_decls[BUILT_IN_ALLOCA]; + t = build_function_call_expr (t, args); + t = fold_convert (ptr_type, t); + t = build2 (MODIFY_EXPR, void_type_node, addr, t); + gimplify_and_add (t, &stmts); + } + + t = build2 (MODIFY_EXPR, void_type_node, local, parm); + gimplify_and_add (t, &stmts); + + DECL_VALUE_EXPR (parm) = local; + } + } + } + + return stmts; +} /* Indicate whether REGNO is an incoming argument to the current function that was promoted to a wider mode. If so, return the RTX for the @@ -3972,22 +4038,6 @@ expand_main_function (void) #endif } -/* The PENDING_SIZES represent the sizes of variable-sized types. - Create RTL for the various sizes now (using temporary variables), - so that we can refer to the sizes from the RTL we are generating - for the current function. The PENDING_SIZES are a TREE_LIST. The - TREE_VALUE of each node is a SAVE_EXPR. */ - -static void -expand_pending_sizes (tree pending_sizes) -{ - tree tem; - - /* Evaluate now the sizes of any types declared among the arguments. */ - for (tem = pending_sizes; tem; tem = TREE_CHAIN (tem)) - expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0); -} - /* Start the RTL for a new function, and set variables used for emitting RTL. SUBR is the FUNCTION_DECL node. @@ -4152,9 +4202,6 @@ expand_function_start (tree subr) since some things (like trampolines) get placed before this. */ tail_recursion_reentry = emit_note (NOTE_INSN_DELETED); - /* Evaluate now the sizes of any types declared among the arguments. */ - expand_pending_sizes (nreverse (get_pending_sizes ())); - /* Make sure there is a line number after the function entry setup code. */ force_next_line_note (); } diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 0b83d78fd43..55889ea9dcc 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -3832,6 +3832,10 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, ret = GS_ERROR; break; } + /* FALLTHRU */ + + case PARM_DECL: + tmp = *expr_p; /* If this is a local variable sized decl, it must be accessed indirectly. Perform that substitution. */ @@ -4213,10 +4217,10 @@ check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, function decl containing BODY. */ void -gimplify_body (tree *body_p, tree fndecl) +gimplify_body (tree *body_p, tree fndecl, bool do_parms) { location_t saved_location = input_location; - tree body; + tree body, parm_stmts; timevar_push (TV_TREE_GIMPLIFY); push_gimplify_context (); @@ -4231,13 +4235,14 @@ gimplify_body (tree *body_p, tree fndecl) /* Make sure input_location isn't set to something wierd. */ input_location = DECL_SOURCE_LOCATION (fndecl); + /* Resolve callee-copies. This has to be done before processing + the body so that DECL_VALUE_EXPR gets processed correctly. */ + parm_stmts = do_parms ? gimplify_parameters () : NULL; + /* Gimplify the function's body. */ gimplify_stmt (body_p); body = *body_p; - /* Unshare again, in case gimplification was sloppy. */ - unshare_all_trees (body); - if (!body) body = alloc_stmt_list (); else if (TREE_CODE (body) == STATEMENT_LIST) @@ -4256,6 +4261,18 @@ gimplify_body (tree *body_p, tree fndecl) append_to_statement_list_force (body, &BIND_EXPR_BODY (b)); body = b; } + + /* If we had callee-copies statements, insert them at the beginning + of the function. */ + if (parm_stmts) + { + append_to_statement_list_force (BIND_EXPR_BODY (body), &parm_stmts); + BIND_EXPR_BODY (body) = parm_stmts; + } + + /* Unshare again, in case gimplification was sloppy. */ + unshare_all_trees (body); + *body_p = body; pop_gimplify_context (body); @@ -4278,8 +4295,11 @@ 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); - gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl); + gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl, true); /* If we're instrumenting function entry/exit, then prepend the call to the entry hook and wrap the whole function in a TRY_FINALLY_EXPR to @@ -4309,6 +4329,7 @@ gimplify_function_tree (tree fndecl) } current_function_decl = oldfn; + cfun = oldfn ? DECL_STRUCT_FUNCTION (oldfn) : NULL; } diff --git a/gcc/tree-gimple.h b/gcc/tree-gimple.h index 0f05d6a7f55..de62d29a5f3 100644 --- a/gcc/tree-gimple.h +++ b/gcc/tree-gimple.h @@ -113,7 +113,7 @@ extern void gimplify_type_sizes (tree, tree *); extern void gimplify_one_sizepos (tree *, tree *); extern void gimplify_stmt (tree *); extern void gimplify_to_stmt_list (tree *); -extern void gimplify_body (tree *, tree); +extern void gimplify_body (tree *, tree, bool); extern void push_gimplify_context (void); extern void pop_gimplify_context (tree); extern void gimplify_and_add (tree, tree *); diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 61fe66dbb08..53a16133a6a 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -819,7 +819,7 @@ initialize_inlined_parameters (inline_data *id, tree args, tree static_chain, } if (gimplify_init_stmts_p) - gimplify_body (&init_stmts, current_function_decl); + gimplify_body (&init_stmts, current_function_decl, false); declare_inline_vars (bind_expr, vars); return init_stmts; diff --git a/gcc/tree.h b/gcc/tree.h index 457d72cd12f..fa328bedad2 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3602,6 +3602,7 @@ extern void push_function_context (void); extern void pop_function_context (void); extern void push_function_context_to (tree); extern void pop_function_context_from (tree); +extern tree gimplify_parameters (void); /* In print-rtl.c */ #ifdef BUFSIZ -- 2.30.2