From 0d97bf4c2c4e599beee17c3a99f6dfdd8884d09a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 18 Jun 2001 12:15:12 -0400 Subject: [PATCH] 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 --- gcc/ChangeLog | 8 ++++++++ gcc/c-common.h | 7 +++++-- gcc/c-semantics.c | 10 +++++++++- gcc/cp/ChangeLog | 14 ++++++++++++++ gcc/cp/cp-tree.h | 8 +++++++- gcc/cp/decl.c | 10 ---------- gcc/cp/semantics.c | 37 ++++++++++++++++++++++++++++++++++++- gcc/cp/typeck.c | 26 ++++++++++++++++++++++++++ gcc/expr.c | 6 ++++-- 9 files changed, 109 insertions(+), 17 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 51c11e7acc2..d8d0683abcc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2001-06-18 Jason Merrill + + * 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 * unroll.c: Include predict.h. diff --git a/gcc/c-common.h b/gcc/c-common.h index 3f766a7a179..05350c12fa2 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.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. */ diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c index 6a963a9a10e..eca64babe8d 100644 --- a/gcc/c-semantics.c +++ b/gcc/c-semantics.c @@ -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) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 342949eb00e..99643259c51 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2001-06-18 Jason Merrill + + 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 * class.c (dfs_accumulate_vtbl_inits): Just point to the base we're diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 5da11ee3151..99106248b07 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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) \ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index af9de43c559..0968220b2fd 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 9dddf230ddd..0dc392a9a89 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 38deeeecad0..1256b6d1ca1 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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) diff --git a/gcc/expr.c b/gcc/expr.c index 230cf9f1e6e..9b81988521b 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -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 -- 2.30.2