summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2004-12-19 04:42:14 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2004-12-19 04:42:14 +0000
commit6b2753683815f45f00c27116093b94d6f1c9ed60 (patch)
treef75b535fe61fe21974e49ac55426cc11e7fe84be /gcc
parente5f813af92b96d37f7808f0e3468ac27096f2be5 (diff)
downloadgcc-6b2753683815f45f00c27116093b94d6f1c9ed60.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@92373 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog22
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/c-decl.c7
-rw-r--r--gcc/c-objc-common.c30
-rw-r--r--gcc/c-tree.h5
-rw-r--r--gcc/function.c173
-rw-r--r--gcc/gimplify.c33
-rw-r--r--gcc/tree-gimple.h2
-rw-r--r--gcc/tree-inline.c2
-rw-r--r--gcc/tree.h1
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,5 +1,27 @@
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
structures seen inside functions.
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