Implement the Named Return Value optimization.

* c-common.h (RETURN_NULLIFIED_P): New macro.
        * c-semantics.c (genrtl_return_stmt): Check it.
        * cp-tree.h (struct cp_language_function): Add x_return_value.
        (current_function_return_value): Now a macro.
        * decl.c: Don't define it.
        (define_label, finish_case_label): Don't clear it.
        (init_decl_processing): Don't register it with GC.
        * semantics.c (genrtl_finish_function): Don't check it for
        no_return_label.  Copy the RTL from the return value to
        current_function_return_value and walk, calling...
        (nullify_returns_r): ...this new fn.
        * typeck.c (check_return_expr): Set current_function_return_value.

        * expr.c (clear_storage): Set TREE_NOTHROW on the decl for memset.
        (emit_block_move): Likewise.

From-SVN: r43445
This commit is contained in:
Jason Merrill 2001-06-18 12:15:12 -04:00 committed by Jason Merrill
parent 923cbdc322
commit 0d97bf4c2c
9 changed files with 109 additions and 17 deletions

View File

@ -1,3 +1,11 @@
2001-06-18 Jason Merrill <jason_merrill@redhat.com>
* c-common.h (RETURN_NULLIFIED_P): New macro.
* c-semantics.c (genrtl_return_stmt): Check it.
* expr.c (clear_storage): Set TREE_NOTHROW on the decl for memset.
(emit_block_move): Likewise.
Mon Jun 18 17:27:24 CEST 2001 Jan Hubicka <jh@suse.cz>
* unroll.c: Include predict.h.

View File

@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */
SCOPE_BEGIN_P (in SCOPE_STMT)
DECL_PRETTY_FUNCTION_P (in VAR_DECL)
NEW_FOR_SCOPE_P (in FOR_STMT)
RETURN_NULLIFIED_P (in RETURN_STMT)
ASM_INPUT_P (in ASM_STMT)
1: C_DECLARED_LABEL_FLAG (in LABEL_DECL)
STMT_IS_FULL_EXPR_P (in _STMT)
@ -561,9 +562,11 @@ extern tree strip_array_types PARAMS ((tree));
#define DO_COND(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 0)
#define DO_BODY(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 1)
/* RETURN_STMT accessor. This gives the expression associated with a
return statement. */
/* RETURN_STMT accessors. These give the expression associated with a
return statement, and whether it should be ignored when expanding
(as opposed to inlining). */
#define RETURN_EXPR(NODE) TREE_OPERAND (RETURN_STMT_CHECK (NODE), 0)
#define RETURN_NULLIFIED_P(NODE) TREE_LANG_FLAG_0 (RETURN_STMT_CHECK (NODE))
/* EXPR_STMT accessor. This gives the expression associated with an
expression statement. */

View File

@ -460,7 +460,15 @@ void
genrtl_return_stmt (stmt)
tree stmt;
{
tree expr = RETURN_EXPR (stmt);
tree expr;
/* If RETURN_NULLIFIED_P is set, the frontend has arranged to set up
the return value separately, so just return the return value
itself. This is used for the C++ named return value optimization. */
if (RETURN_NULLIFIED_P (stmt))
expr = DECL_RESULT (current_function_decl);
else
expr = RETURN_EXPR (stmt);
emit_line_note (input_filename, lineno);
if (!expr)

View File

@ -1,3 +1,17 @@
2001-06-18 Jason Merrill <jason_merrill@redhat.com>
Implement the Named Return Value optimization.
* cp-tree.h (struct cp_language_function): Add x_return_value.
(current_function_return_value): Now a macro.
* decl.c: Don't define it.
(define_label, finish_case_label): Don't clear it.
(init_decl_processing): Don't register it with GC.
* semantics.c (genrtl_finish_function): Don't check it for
no_return_label. Copy the RTL from the return value to
current_function_return_value and walk, calling...
(nullify_returns_r): ...this new fn.
* typeck.c (check_return_expr): Set current_function_return_value.
2001-06-15 Jason Merrill <jason_merrill@redhat.com>
* class.c (dfs_accumulate_vtbl_inits): Just point to the base we're

View File

@ -863,6 +863,7 @@ struct cp_language_function
tree x_eh_spec_block;
tree x_in_charge_parm;
tree x_vtt_parm;
tree x_return_value;
tree *x_vcalls_possible_p;
@ -953,7 +954,12 @@ struct cp_language_function
#define in_function_try_handler cp_function_chain->in_function_try_handler
extern tree current_function_return_value;
/* Expression always returned from function, or error_mark_node
otherwise, for use by the automatic named return value optimization. */
#define current_function_return_value \
(cp_function_chain->x_return_value)
extern tree global_namespace;
#define ansi_opname(CODE) \

View File

@ -285,13 +285,6 @@ struct named_label_list
#define named_labels cp_function_chain->x_named_labels
/* Set to 0 at beginning of a function definition, and whenever
a label (case or named) is defined. Set to value of expression
returned from function when that value can be transformed into
a named return value. */
tree current_function_return_value;
/* Nonzero means use the ISO C94 dialect of C. */
int flag_isoc94;
@ -5153,7 +5146,6 @@ define_label (filename, line, name)
ent->binding_level = current_binding_level;
}
check_previous_gotos (decl);
current_function_return_value = NULL_TREE;
return decl;
}
}
@ -5255,7 +5247,6 @@ finish_case_label (low_value, high_value)
own new (temporary) binding contour. */
for (p = current_binding_level; !(p->parm_flag); p = p->level_chain)
p->more_cleanups_ok = 0;
current_function_return_value = NULL_TREE;
return r;
}
@ -6624,7 +6615,6 @@ init_decl_processing ()
ggc_add_tree_root (&lastiddecl, 1);
ggc_add_tree_root (&last_function_parm_tags, 1);
ggc_add_tree_root (&current_function_return_value, 1);
ggc_add_tree_root (&current_function_parm_tags, 1);
ggc_add_tree_root (&last_function_parms, 1);
ggc_add_tree_root (&error_mark_list, 1);

View File

@ -49,6 +49,7 @@
static tree maybe_convert_cond PARAMS ((tree));
static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
static tree nullify_returns_r PARAMS ((tree *, int *, void *));
static void deferred_type_access_control PARAMS ((void));
static void emit_associated_thunks PARAMS ((tree));
static void genrtl_try_block PARAMS ((tree));
@ -2464,6 +2465,25 @@ expand_body (fn)
timevar_pop (TV_EXPAND);
}
/* Helper function for walk_tree, used by genrtl_start_function to override
all the RETURN_STMTs for the named return value optimization. */
static tree
nullify_returns_r (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees;
void *data ATTRIBUTE_UNUSED;
{
/* No need to walk into types. */
if (TYPE_P (*tp))
*walk_subtrees = 0;
else if (TREE_CODE (*tp) == RETURN_STMT)
RETURN_NULLIFIED_P (*tp) = 1;
/* Keep iterating. */
return NULL_TREE;
}
/* Start generating the RTL for FN. */
static void
@ -2541,6 +2561,22 @@ genrtl_start_function (fn)
/* Create a binding contour which can be used to catch
cleanup-generated temporaries. */
expand_start_bindings (2);
/* Set up the named return value optimization, if we can. */
if (current_function_return_value
&& current_function_return_value != error_mark_node)
{
tree r = current_function_return_value;
/* This is only worth doing for fns that return in memory--and
simpler, since we don't have to worry about promoted modes. */
if (aggregate_value_p (TREE_TYPE (TREE_TYPE (fn))))
{
COPY_DECL_RTL (DECL_RESULT (fn), r);
DECL_ALIGN (r) = DECL_ALIGN (DECL_RESULT (fn));
walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
nullify_returns_r, NULL_TREE);
}
}
}
/* Finish generating the RTL for FN. */
@ -2579,7 +2615,6 @@ genrtl_finish_function (fn)
if (!dtor_label && !DECL_CONSTRUCTOR_P (fn)
&& return_label != NULL_RTX
&& current_function_return_value == NULL_TREE
&& ! DECL_NAME (DECL_RESULT (current_function_decl)))
no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);

View File

@ -6679,6 +6679,32 @@ check_return_expr (retval)
&& retval != current_class_ref)
cp_warning ("`operator=' should return a reference to `*this'");
/* The fabled Named Return Value optimization: If this is a
value-returning function that always returns the same local
variable, remember it.
It might be nice to be more flexible, and choose the first suitable
variable even if the function sometimes returns something else, but
then we run the risk of clobbering the variable we chose if the other
returned expression uses the chosen variable somehow. And people expect
this restriction, anyway. (jason 2000-11-19) */
if (fn_returns_value_p && optimize)
{
if (retval != NULL_TREE
&& (current_function_return_value == NULL_TREE
|| current_function_return_value == retval)
&& TREE_CODE (retval) == VAR_DECL
&& DECL_CONTEXT (retval) == current_function_decl
&& ! TREE_STATIC (retval)
&& ! DECL_USER_ALIGN (retval)
&& same_type_p (TREE_TYPE (retval),
TREE_TYPE (TREE_TYPE (current_function_decl))))
current_function_return_value = retval;
else
current_function_return_value = error_mark_node;
}
/* We don't need to do any conversions when there's nothing being
returned. */
if (!retval || retval == error_mark_node)

View File

@ -1773,6 +1773,7 @@ emit_block_move (x, y, size, align)
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
TREE_NOTHROW (fn) = 1;
make_decl_rtl (fn, NULL);
assemble_external (fn);
}
@ -2659,7 +2660,7 @@ clear_storage (object, size, align)
For targets where libcalls and normal calls have different
conventions for returning pointers, we could end up generating
incorrect code.
incorrect code.
So instead of using a libcall sequence we build up a suitable
CALL_EXPR and expand the call in the normal fashion. */
@ -2677,6 +2678,7 @@ clear_storage (object, size, align)
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
TREE_NOTHROW (fn) = 1;
make_decl_rtl (fn, NULL);
assemble_external (fn);
}
@ -4547,7 +4549,7 @@ store_constructor (exp, target, align, cleared, size)
/* If the constructor has fewer fields than the structure
or if we are initializing the structure to mostly zeros,
clear the whole structure first. Don't do this is TARGET is
clear the whole structure first. Don't do this if TARGET is a
register whose mode size isn't equal to SIZE since clear_storage
can't handle this case. */
else if (size > 0