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:
parent
ca6af4f857
commit
4744afba0f
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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:
|
||||
|
@ -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. */
|
||||
|
173
gcc/function.c
173
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 ();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user