* 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
+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.
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)
#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. */
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)
+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
tree x_eh_spec_block;
tree x_in_charge_parm;
tree x_vtt_parm;
+ tree x_return_value;
tree *x_vcalls_possible_p;
#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) \
#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;
ent->binding_level = current_binding_level;
}
check_previous_gotos (decl);
- current_function_return_value = NULL_TREE;
return decl;
}
}
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;
}
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);
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));
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
/* 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. */
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);
&& 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)
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
+ TREE_NOTHROW (fn) = 1;
make_decl_rtl (fn, NULL);
assemble_external (fn);
}
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. */
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
+ TREE_NOTHROW (fn) = 1;
make_decl_rtl (fn, NULL);
assemble_external (fn);
}
/* 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