Commit 3eb24f73 by Mark Mitchell Committed by Mark Mitchell

decl.c (init_decl_processing): Reenable inlining on trees.

	* decl.c (init_decl_processing): Reenable inlining on trees.
	(finish_function): Likewise.
	* expr.c (cplus_expand_expr): Don't handle AGGR_INIT_EXPR here.
	* semantics.c (simplify_aggr_init_exprs): New function.
	(expand_body): Use it.
	* tree.c (walk_tree): Special-case TARGET_EXPRs since they
	sometimes present the same sub-tree twice.

From-SVN: r30849
parent 1e54d32b
1999-12-09 Mark Mitchell <mark@codesourcery.com>
* decl.c (init_decl_processing): Reenable inlining on trees.
(finish_function): Likewise.
* expr.c (cplus_expand_expr): Don't handle AGGR_INIT_EXPR here.
* semantics.c (simplify_aggr_init_exprs): New function.
(expand_body): Use it.
* tree.c (walk_tree): Special-case TARGET_EXPRs since they
sometimes present the same sub-tree twice.
* dump.c (dequeue_and_dump): Abbreviate `class' as `cls', not
`csl'.
......
......@@ -5973,10 +5973,8 @@ init_decl_processing ()
flag_strict_prototype = pedantic;
if (! flag_permissive && ! pedantic)
flag_pedantic_errors = 1;
#if 0
if (!flag_no_inline)
flag_inline_trees = 1;
#endif
strict_prototypes_lang_c = flag_strict_prototype;
......@@ -13669,7 +13667,6 @@ finish_function (lineno, flags)
if (!expanding_p && !processing_template_decl)
save_function_data (fndecl);
#if 0
/* If this function calls `setjmp' it cannot be inlined. When
`longjmp' is called it is not guaranteed to restore the value of
local variables that have been modified since the call to
......@@ -13681,7 +13678,6 @@ finish_function (lineno, flags)
function.) */
if (!expanding_p && !processing_template_decl && calls_setjmp_p (fndecl))
DECL_UNINLINABLE (fndecl) = 1;
#endif
if (expand_p)
{
......
......@@ -120,102 +120,6 @@ cplus_expand_expr (exp, target, tmode, modifier)
switch (code)
{
case AGGR_INIT_EXPR:
{
/* Something needs to be initialized, but we didn't know
where that thing was when building the tree. For example,
it could be the return value of a function, or a parameter
to a function which lays down in the stack, or a temporary
variable which must be passed by reference.
Cleanups are handled in a language-specific way: they
might be run by the called function (true in GNU C++
for parameters with cleanups), or they might be
run by the caller, after the call (true in GNU C++
for other cleanup needs). */
tree func = TREE_OPERAND (exp, 0);
tree args = TREE_OPERAND (exp, 1);
tree type = TREE_TYPE (exp), slot;
tree call_exp;
rtx call_target, return_target;
int pcc_struct_return = 0;
/* The expression `init' wants to initialize what
`target' represents. SLOT holds the slot for TARGET. */
slot = TREE_OPERAND (exp, 2);
/* Should always be called with a target. */
my_friendly_assert (target != NULL_RTX, 205);
/* The target the initializer will initialize (CALL_TARGET)
must now be directed to initialize the target we are
supposed to initialize (TARGET). The semantics for
choosing what CALL_TARGET is is language-specific,
as is building the call which will perform the
initialization. It is left here to show the choices that
exist for C++. */
if (AGGR_INIT_VIA_CTOR_P (exp))
{
type = build_pointer_type (type);
mark_addressable (slot);
args = tree_cons (NULL_TREE,
build1 (ADDR_EXPR, type, slot),
TREE_CHAIN (args));
call_target = 0;
}
else
{
call_target = target;
#ifdef PCC_STATIC_STRUCT_RETURN
if (aggregate_value_p (type))
{
pcc_struct_return = 1;
call_target = 0;
}
#endif
}
call_exp = build (CALL_EXPR, type, func, args, NULL_TREE);
TREE_SIDE_EFFECTS (call_exp) = 1;
return_target = expand_call (call_exp, call_target, ignore);
if (call_target)
/* Trust that the right thing has been done; it's too hard to
verify. */
return return_target;
/* If we're suffering under the ancient PCC_STATIC_STRUCT_RETURN
calling convention, we need to copy the return value out of
the static return buffer into slot. */
if (pcc_struct_return)
{
extern int flag_access_control;
int old_ac = flag_access_control;
tree init = build_decl (VAR_DECL, NULL_TREE,
build_reference_type (type));
DECL_RTL (init) = XEXP (return_target, 0);
init = convert_from_reference (init);
flag_access_control = 0;
expand_expr (build_aggr_init (slot, init,
LOOKUP_ONLYCONVERTING),
target, tmode, EXPAND_NORMAL);
flag_access_control = old_ac;
if (TYPE_NEEDS_DESTRUCTOR (type))
{
init = maybe_build_cleanup (init);
if (init != NULL_TREE)
expand_expr (init, const0_rtx, VOIDmode, 0);
}
}
return DECL_RTL (slot);
}
case PTRMEM_CST:
return expand_expr (cplus_expand_constant (exp),
target, tmode, modifier);
......
......@@ -2547,6 +2547,81 @@ expand_stmt (t)
return rval;
}
/* Called from expand_body via walk_tree. Replace all AGGR_INIT_EXPRs
will equivalent CALL_EXPRs. */
static tree
simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
tree *tp;
int *walk_subtrees ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
{
tree aggr_init_expr;
tree call_expr;
tree fn;
tree args;
tree slot;
tree type;
tree call_type;
int copy_from_buffer_p;
/* Only AGGR_INIT_EXPRs are interesting. */
aggr_init_expr = *tp;
if (TREE_CODE (aggr_init_expr) != AGGR_INIT_EXPR)
return NULL_TREE;
/* Form an appropriate CALL_EXPR. */
fn = TREE_OPERAND (aggr_init_expr, 0);
args = TREE_OPERAND (aggr_init_expr, 1);
slot = TREE_OPERAND (aggr_init_expr, 2);
type = TREE_TYPE (aggr_init_expr);
call_type = type;
if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr))
{
/* Replace the first argument with the address of the third
argument to the AGGR_INIT_EXPR. */
call_type = build_pointer_type (type);
mark_addressable (slot);
args = tree_cons (NULL_TREE, build1 (ADDR_EXPR, call_type, slot),
TREE_CHAIN (args));
}
call_expr = build (CALL_EXPR, call_type, fn, args, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
/* If we're using the non-reentrant PCC calling convention, then we
need to copy the returned value out of the static buffer into the
SLOT. */
copy_from_buffer_p = 0;
#ifdef PCC_STATIC_STRUCT_RETURN
if (!AGGR_INIT_VIA_CTOR_P (aggr_init_expr) && aggregate_value_p (type))
{
int old_ac;
flag_access_control = 0;
call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING);
flag_access_control = old_ac;
copy_from_buffer_p = 1;
}
#endif
/* If this AGGR_INIT_EXPR indicates the value returned by a
function, then we want to use the value of the initialized
location as the result. */
if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr) || copy_from_buffer_p)
{
call_expr = build (COMPOUND_EXPR, type,
call_expr, slot);
TREE_SIDE_EFFECTS (call_expr) = 1;
}
/* Replace the AGGR_INIT_EXPR with the CALL_EXPR. */
TREE_CHAIN (call_expr) = TREE_CHAIN (aggr_init_expr);
*tp = call_expr;
/* Keep iterating. */
return NULL_TREE;
}
/* Generate RTL for FN. */
void
......@@ -2574,6 +2649,9 @@ expand_body (fn)
return;
}
/* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs. */
walk_tree (&DECL_SAVED_TREE (fn), simplify_aggr_init_exprs_r, NULL);
/* There's no reason to do any of the work here if we're only doing
semantic analysis; this code just generates RTL. */
if (flag_syntax_only)
......
......@@ -1626,8 +1626,18 @@ walk_tree (tp, func, data)
int i;
/* Walk over all the sub-trees of this operand. */
for (i = first_rtl_op (code) - 1; i >= 0; --i)
i = first_rtl_op (code) - 1;
/* TARGET_EXPRs are peculiar: operands 1 and 3 can be the same.
But, we only want to walk once. */
if (code == TARGET_EXPR
&& TREE_OPERAND (*tp, 3) == TREE_OPERAND (*tp, 1))
--i;
/* Go through the subtrees. */
while (i >= 0)
{
WALK_SUBTREE (TREE_OPERAND (*tp, i));
--i;
}
/* For statements, we also walk the chain so that we cover the
entire statement tree. */
......
// Build don't link:
// Origin: Martin Reinecke <martin@MPA-Garching.MPG.DE>
// Special g++ Options: -O2 -Winline
class foo
{
public:
float x;
foo (float xval)
: x (xval) {}
foo operator+ (const foo &foo2) const
{ return foo (x+foo2.x); }
};
int main()
{
foo f=foo(1)+foo(2);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment