aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2001-06-18 12:15:12 -0400
committerJason Merrill <jason@gcc.gnu.org>2001-06-18 12:15:12 -0400
commit0d97bf4c2c4e599beee17c3a99f6dfdd8884d09a (patch)
tree70263e15f7a28d4f44a057ee1783e8a0095c5f9a
parent923cbdc322ee080c02b94a95eece0618a2a78b47 (diff)
downloadgcc-0d97bf4c2c4e599beee17c3a99f6dfdd8884d09a.zip
gcc-0d97bf4c2c4e599beee17c3a99f6dfdd8884d09a.tar.gz
gcc-0d97bf4c2c4e599beee17c3a99f6dfdd8884d09a.tar.bz2
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
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/c-common.h7
-rw-r--r--gcc/c-semantics.c10
-rw-r--r--gcc/cp/ChangeLog14
-rw-r--r--gcc/cp/cp-tree.h8
-rw-r--r--gcc/cp/decl.c10
-rw-r--r--gcc/cp/semantics.c37
-rw-r--r--gcc/cp/typeck.c26
-rw-r--r--gcc/expr.c6
9 files changed, 109 insertions, 17 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 51c11e7..d8d0683 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 3f766a7..05350c1 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 6a963a9..eca64ba 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 342949e..9964325 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 5da11ee..9910624 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 af9de43..0968220 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 (&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);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 9dddf23..0dc392a 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 38deeee..1256b6d 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 230cf9f..9b81988 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