aboutsummaryrefslogtreecommitdiff
path: root/gcc/function.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/function.c')
-rw-r--r--gcc/function.c173
1 files changed, 110 insertions, 63 deletions
diff --git a/gcc/function.c b/gcc/function.c
index 046a4ad..9251071 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 ();
}