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
This commit is contained in:
Richard Henderson 2004-12-18 20:42:14 -08:00 committed by Richard Henderson
parent ca6af4f857
commit 4744afba0f
10 changed files with 169 additions and 108 deletions

View File

@ -1,3 +1,25 @@
2004-12-18 Richard Henderson <rth@redhat.com>
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 <rth@redhat.com>
* c-decl.c (finish_struct): Add DECL_EXPR for variable sized

View File

@ -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

View File

@ -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))

View File

@ -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:

View File

@ -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. */

View File

@ -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 ();
}

View File

@ -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;
}

View File

@ -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 *);

View File

@ -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;

View File

@ -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