+
+/* 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))
+ && !TYPE_SIZES_GIMPLIFIED (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);
+
+ SET_DECL_VALUE_EXPR (parm, local);
+ DECL_HAS_VALUE_EXPR_P (parm) = 1;
+ }
+ }
+ }
+
+ return stmts;
+}