diff options
| author | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-06-18 16:15:12 +0000 |
|---|---|---|
| committer | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-06-18 16:15:12 +0000 |
| commit | 80ac742d926c6c87d9eb1648f4a501a34a3ac70a (patch) | |
| tree | 70263e15f7a28d4f44a057ee1783e8a0095c5f9a /gcc/cp | |
| parent | f6664feec514b2e3b3f36fb59c9b1b14dc5a52fc (diff) | |
| download | ppe42-gcc-80ac742d926c6c87d9eb1648f4a501a34a3ac70a.tar.gz ppe42-gcc-80ac742d926c6c87d9eb1648f4a501a34a3ac70a.zip | |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@43445 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp')
| -rw-r--r-- | gcc/cp/ChangeLog | 14 | ||||
| -rw-r--r-- | gcc/cp/cp-tree.h | 8 | ||||
| -rw-r--r-- | gcc/cp/decl.c | 10 | ||||
| -rw-r--r-- | gcc/cp/semantics.c | 37 | ||||
| -rw-r--r-- | gcc/cp/typeck.c | 26 |
5 files changed, 83 insertions, 12 deletions
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 <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 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) |

