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> 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 * dump.c (dequeue_and_dump): Abbreviate `class' as `cls', not
`csl'. `csl'.
......
...@@ -5973,10 +5973,8 @@ init_decl_processing () ...@@ -5973,10 +5973,8 @@ init_decl_processing ()
flag_strict_prototype = pedantic; flag_strict_prototype = pedantic;
if (! flag_permissive && ! pedantic) if (! flag_permissive && ! pedantic)
flag_pedantic_errors = 1; flag_pedantic_errors = 1;
#if 0
if (!flag_no_inline) if (!flag_no_inline)
flag_inline_trees = 1; flag_inline_trees = 1;
#endif
strict_prototypes_lang_c = flag_strict_prototype; strict_prototypes_lang_c = flag_strict_prototype;
...@@ -13669,7 +13667,6 @@ finish_function (lineno, flags) ...@@ -13669,7 +13667,6 @@ finish_function (lineno, flags)
if (!expanding_p && !processing_template_decl) if (!expanding_p && !processing_template_decl)
save_function_data (fndecl); save_function_data (fndecl);
#if 0
/* If this function calls `setjmp' it cannot be inlined. When /* If this function calls `setjmp' it cannot be inlined. When
`longjmp' is called it is not guaranteed to restore the value of `longjmp' is called it is not guaranteed to restore the value of
local variables that have been modified since the call to local variables that have been modified since the call to
...@@ -13681,7 +13678,6 @@ finish_function (lineno, flags) ...@@ -13681,7 +13678,6 @@ finish_function (lineno, flags)
function.) */ function.) */
if (!expanding_p && !processing_template_decl && calls_setjmp_p (fndecl)) if (!expanding_p && !processing_template_decl && calls_setjmp_p (fndecl))
DECL_UNINLINABLE (fndecl) = 1; DECL_UNINLINABLE (fndecl) = 1;
#endif
if (expand_p) if (expand_p)
{ {
......
...@@ -120,102 +120,6 @@ cplus_expand_expr (exp, target, tmode, modifier) ...@@ -120,102 +120,6 @@ cplus_expand_expr (exp, target, tmode, modifier)
switch (code) 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: case PTRMEM_CST:
return expand_expr (cplus_expand_constant (exp), return expand_expr (cplus_expand_constant (exp),
target, tmode, modifier); target, tmode, modifier);
......
...@@ -2547,6 +2547,81 @@ expand_stmt (t) ...@@ -2547,6 +2547,81 @@ expand_stmt (t)
return rval; 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. */ /* Generate RTL for FN. */
void void
...@@ -2574,6 +2649,9 @@ expand_body (fn) ...@@ -2574,6 +2649,9 @@ expand_body (fn)
return; 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 /* There's no reason to do any of the work here if we're only doing
semantic analysis; this code just generates RTL. */ semantic analysis; this code just generates RTL. */
if (flag_syntax_only) if (flag_syntax_only)
......
...@@ -1626,8 +1626,18 @@ walk_tree (tp, func, data) ...@@ -1626,8 +1626,18 @@ walk_tree (tp, func, data)
int i; int i;
/* Walk over all the sub-trees of this operand. */ /* 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;
WALK_SUBTREE (TREE_OPERAND (*tp, i)); /* 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 /* For statements, we also walk the chain so that we cover the
entire statement tree. */ 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