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:
parent
923cbdc322
commit
0d97bf4c2c
@ -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.
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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 (¤t_function_return_value, 1);
|
||||
ggc_add_tree_root (¤t_function_parm_tags, 1);
|
||||
ggc_add_tree_root (&last_function_parms, 1);
|
||||
ggc_add_tree_root (&error_mark_list, 1);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user