c-decl.c (grokdeclarator): Don't frob current_function_decl around variable_size.

* c-decl.c (grokdeclarator): Don't frob current_function_decl
        around variable_size.
        (set_decl_nonlocal): Remove.
        (store_parm_decls): Add stmts for pending sizes.
        * calls.c (calls_function, calls_function_1): Remove.
        (precompute_arguments): Don't call it.
        * cfgexpand.c (set_save_expr_context): Remove.
        (tree_expand_cfg): Don't call it.
        * dwarf2out.c (add_bound_info): Don't handle SAVE_EXPR.
        (dwarf2out_finish): Likewise.
        * expr.c (emit_block_move): Adjust addresses to BLKmode.
        (store_constructor): Don't pre-evaluate SAVE_EXPR.
        (safe_from_p): Don't queue SAVE_EXPRs.
        (expand_expr_real_1 <case SAVE_EXPR>): Rewrite to expect,
        or build plain VAR_DECLs.
        * fold-const.c (twoval_comparison_p): Don't look at SAVE_EXPR_RTL.
        (fold): Likewise.
        (fold_checksum_tree): Don't special-case SAVE_EXPR.
        * function.c (free_after_compilation): Don't clear x_save_expr_regs.
        (put_var_into_stack): Don't handle SAVE_EXPR.
        (gen_mem_addressof): Likewise.
        * function.h (struct function): Remove x_save_expr_regs.
        (save_expr_regs): Remove.
        * gengtype.c (adjust_field_tree_exp): Don't special-case SAVE_EXPR.
        * print-tree.c (print_node): Don't dump SAVE_EXPR_NOPLACEHOLDER.
        * stor-layout.c (variable_size): Don't set it.
        (force_type_save_exprs, force_type_save_exprs_1): Remove.
        * tree-inline.c (remap_save_expr): Remove fn argument.  Update
        all callers.  Don't set SAVE_EXPR_CONTEXT.
        * tree-inline.h (remap_save_expr): Update decl.
        * tree.c (save_expr): Update build size.
        (first_rtl_op): Don't handle SAVE_EXPR.
        (unsave_expr_1, contains_placeholder_p): Likewise.
        (decl_function_context): Likewise.
        * tree.def (SAVE_EXPR): Remove args 1 and 2.
        * tree.h (SAVE_EXPR_CONTEXT, SAVE_EXPR_RTL): Remove.
        (SAVE_EXPR_NOPLACEHOLDER, SAVE_EXPR_PERSISTENT_P): Remove.
cp/
        * tree.c (cp_unsave_r): Update remap_save_expr call.
java/
        * jcf-write.c (generate_bytecode_insns <case SAVE_EXPR>): Rewrite.

From-SVN: r84036
This commit is contained in:
Richard Henderson 2004-07-02 17:15:50 -07:00 committed by Richard Henderson
parent a7e4cdca85
commit 82c8274320
21 changed files with 160 additions and 662 deletions

View File

@ -1,3 +1,43 @@
2004-07-02 Richard Henderson <rth@redhat.com>
* c-decl.c (grokdeclarator): Don't frob current_function_decl
around variable_size.
(set_decl_nonlocal): Remove.
(store_parm_decls): Add stmts for pending sizes.
* calls.c (calls_function, calls_function_1): Remove.
(precompute_arguments): Don't call it.
* cfgexpand.c (set_save_expr_context): Remove.
(tree_expand_cfg): Don't call it.
* dwarf2out.c (add_bound_info): Don't handle SAVE_EXPR.
(dwarf2out_finish): Likewise.
* expr.c (emit_block_move): Adjust addresses to BLKmode.
(store_constructor): Don't pre-evaluate SAVE_EXPR.
(safe_from_p): Don't queue SAVE_EXPRs.
(expand_expr_real_1 <case SAVE_EXPR>): Rewrite to expect,
or build plain VAR_DECLs.
* fold-const.c (twoval_comparison_p): Don't look at SAVE_EXPR_RTL.
(fold): Likewise.
(fold_checksum_tree): Don't special-case SAVE_EXPR.
* function.c (free_after_compilation): Don't clear x_save_expr_regs.
(put_var_into_stack): Don't handle SAVE_EXPR.
(gen_mem_addressof): Likewise.
* function.h (struct function): Remove x_save_expr_regs.
(save_expr_regs): Remove.
* gengtype.c (adjust_field_tree_exp): Don't special-case SAVE_EXPR.
* print-tree.c (print_node): Don't dump SAVE_EXPR_NOPLACEHOLDER.
* stor-layout.c (variable_size): Don't set it.
(force_type_save_exprs, force_type_save_exprs_1): Remove.
* tree-inline.c (remap_save_expr): Remove fn argument. Update
all callers. Don't set SAVE_EXPR_CONTEXT.
* tree-inline.h (remap_save_expr): Update decl.
* tree.c (save_expr): Update build size.
(first_rtl_op): Don't handle SAVE_EXPR.
(unsave_expr_1, contains_placeholder_p): Likewise.
(decl_function_context): Likewise.
* tree.def (SAVE_EXPR): Remove args 1 and 2.
* tree.h (SAVE_EXPR_CONTEXT, SAVE_EXPR_RTL): Remove.
(SAVE_EXPR_NOPLACEHOLDER, SAVE_EXPR_PERSISTENT_P): Remove.
2004-07-03 Joseph S. Myers <jsm@polyomino.org.uk>
* doc/bugreport.texi, doc/configterms.texi, doc/contrib.texi,

View File

@ -3990,20 +3990,7 @@ grokdeclarator (tree declarator, tree declspecs,
}
if (size_varies)
{
/* We must be able to distinguish the
SAVE_EXPR_CONTEXT for the variably-sized type
so that we can set it correctly in
set_save_expr_context. The convention is
that all SAVE_EXPRs that need to be reset
have NULL_TREE for their SAVE_EXPR_CONTEXT. */
tree cfd = current_function_decl;
if (decl_context == PARM)
current_function_decl = NULL_TREE;
itype = variable_size (itype);
if (decl_context == PARM)
current_function_decl = cfd;
}
itype = variable_size (itype);
itype = build_index_type (itype);
}
}
@ -6065,25 +6052,6 @@ store_parm_decls_oldstyle (tree fndecl, tree arg_info)
}
}
/* A subroutine of store_parm_decls called via walk_tree. Mark all
decls non-local. */
static tree
set_decl_nonlocal (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
{
tree t = *tp;
if (DECL_P (t))
{
DECL_NONLOCAL (t) = 1;
*walk_subtrees = 0;
}
else if (TYPE_P (t))
*walk_subtrees = 0;
return NULL;
}
/* Store the parameter declarations into the current function declaration.
This is called after parsing the parameter declarations, before
digesting the body of the function.
@ -6096,9 +6064,6 @@ store_parm_decls (void)
{
tree fndecl = current_function_decl;
/* The function containing FNDECL, if any. */
tree context = decl_function_context (fndecl);
/* The argument information block for FNDECL. */
tree arg_info = DECL_ARGUMENTS (fndecl);
@ -6129,27 +6094,14 @@ store_parm_decls (void)
/* Begin the statement tree for this function. */
DECL_SAVED_TREE (fndecl) = push_stmt_list ();
/* If this is a nested function, save away the sizes of any
variable-size types so that we can expand them when generating
RTL. */
if (context)
{
tree t;
DECL_LANG_SPECIFIC (fndecl)->pending_sizes
= nreverse (get_pending_sizes ());
for (t = DECL_LANG_SPECIFIC (fndecl)->pending_sizes;
t;
t = TREE_CHAIN (t))
{
/* We will have a nonlocal use of whatever variables are
buried inside here. */
walk_tree (&TREE_OPERAND (TREE_VALUE (t), 0),
set_decl_nonlocal, NULL, NULL);
SAVE_EXPR_CONTEXT (TREE_VALUE (t)) = context;
}
}
/* ??? Insert the contents of the pending sizes list into the function
to be evaluated. This just changes mis-behaviour until assign_parms
phase ordering problems are resolved. */
{
tree t;
for (t = nreverse (get_pending_sizes ()); t ; t = TREE_CHAIN (t))
add_stmt (TREE_VALUE (t));
}
/* Even though we're inside a function body, we still don't want to
call expand_expr to calculate the size of a variable-sized array.

View File

@ -117,9 +117,6 @@ static sbitmap stored_args_map;
argument list for the constructor call. */
int stack_arg_under_construction;
static int calls_function (tree, int);
static int calls_function_1 (tree, int);
static void emit_call_1 (rtx, tree, tree, tree, HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, rtx, rtx, int, rtx, int,
CUMULATIVE_ARGS *);
@ -155,123 +152,6 @@ static rtx save_fixed_argument_area (int, rtx, int *, int *);
static void restore_fixed_argument_area (rtx, rtx, int, int);
#endif
/* If WHICH is 1, return 1 if EXP contains a call to the built-in function
`alloca'.
If WHICH is 0, return 1 if EXP contains a call to any function.
Actually, we only need return 1 if evaluating EXP would require pushing
arguments on the stack, but that is too difficult to compute, so we just
assume any function call might require the stack. */
static tree calls_function_save_exprs;
static int
calls_function (tree exp, int which)
{
int val;
calls_function_save_exprs = 0;
val = calls_function_1 (exp, which);
calls_function_save_exprs = 0;
return val;
}
/* Recursive function to do the work of above function. */
static int
calls_function_1 (tree exp, int which)
{
int i;
enum tree_code code = TREE_CODE (exp);
int class = TREE_CODE_CLASS (code);
int length = first_rtl_op (code);
/* If this code is language-specific, we don't know what it will do. */
if ((int) code >= NUM_TREE_CODES)
return 1;
switch (code)
{
case CALL_EXPR:
if (which == 0)
return 1;
else if ((TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== FUNCTION_TYPE)
&& (TYPE_RETURNS_STACK_DEPRESSED
(TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))))
return 1;
else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
== FUNCTION_DECL)
&& (special_function_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
0)
& ECF_MAY_BE_ALLOCA))
return 1;
break;
case CONSTRUCTOR:
{
tree tem;
for (tem = CONSTRUCTOR_ELTS (exp); tem != 0; tem = TREE_CHAIN (tem))
if (calls_function_1 (TREE_VALUE (tem), which))
return 1;
}
return 0;
case SAVE_EXPR:
if (SAVE_EXPR_RTL (exp) != 0)
return 0;
if (value_member (exp, calls_function_save_exprs))
return 0;
calls_function_save_exprs = tree_cons (NULL_TREE, exp,
calls_function_save_exprs);
return (TREE_OPERAND (exp, 0) != 0
&& calls_function_1 (TREE_OPERAND (exp, 0), which));
case BLOCK:
{
tree local;
tree subblock;
for (local = BLOCK_VARS (exp); local; local = TREE_CHAIN (local))
if (DECL_INITIAL (local) != 0
&& calls_function_1 (DECL_INITIAL (local), which))
return 1;
for (subblock = BLOCK_SUBBLOCKS (exp);
subblock;
subblock = TREE_CHAIN (subblock))
if (calls_function_1 (subblock, which))
return 1;
}
return 0;
case TREE_LIST:
for (; exp != 0; exp = TREE_CHAIN (exp))
if (calls_function_1 (TREE_VALUE (exp), which))
return 1;
return 0;
default:
break;
}
/* Only expressions and blocks can contain calls.
Blocks were handled above. */
if (! IS_EXPR_CODE_CLASS (class))
return 0;
for (i = 0; i < length; i++)
if (TREE_OPERAND (exp, i) != 0
&& calls_function_1 (TREE_OPERAND (exp, i), which))
return 1;
return 0;
}
/* Force FUNEXP into a form suitable for the address of a CALL,
and return that as an rtx. Also load the static chain register
if FNDECL is a nested function.
@ -1372,58 +1252,50 @@ precompute_arguments (int flags, int num_actuals, struct arg_data *args)
int i;
/* If this is a libcall, then precompute all arguments so that we do not
get extraneous instructions emitted as part of the libcall sequence.
If this target defines ACCUMULATE_OUTGOING_ARGS to true, then we must
precompute all arguments that contain function calls. Otherwise,
computing arguments for a subcall may clobber arguments for this call.
If this target defines ACCUMULATE_OUTGOING_ARGS to false, then we only
need to precompute arguments that change the stack pointer, such as calls
to alloca, and calls that do not pop all of their arguments. */
get extraneous instructions emitted as part of the libcall sequence. */
if ((flags & ECF_LIBCALL_BLOCK) == 0)
return;
for (i = 0; i < num_actuals; i++)
if ((flags & ECF_LIBCALL_BLOCK)
|| calls_function (args[i].tree_value, !ACCUMULATE_OUTGOING_ARGS))
{
enum machine_mode mode;
{
enum machine_mode mode;
/* If this is an addressable type, we cannot pre-evaluate it. */
if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))
abort ();
/* If this is an addressable type, we cannot pre-evaluate it. */
if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))
abort ();
args[i].value
= expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);
args[i].value
= expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);
/* ANSI doesn't require a sequence point here,
but PCC has one, so this will avoid some problems. */
emit_queue ();
/* ANSI doesn't require a sequence point here,
but PCC has one, so this will avoid some problems. */
emit_queue ();
args[i].initial_value = args[i].value
= protect_from_queue (args[i].value, 0);
args[i].initial_value = args[i].value
= protect_from_queue (args[i].value, 0);
mode = TYPE_MODE (TREE_TYPE (args[i].tree_value));
if (mode != args[i].mode)
{
args[i].value
= convert_modes (args[i].mode, mode,
args[i].value, args[i].unsignedp);
mode = TYPE_MODE (TREE_TYPE (args[i].tree_value));
if (mode != args[i].mode)
{
args[i].value
= convert_modes (args[i].mode, mode,
args[i].value, args[i].unsignedp);
#if defined(PROMOTE_FUNCTION_MODE) && !defined(PROMOTE_MODE)
/* CSE will replace this only if it contains args[i].value
pseudo, so convert it down to the declared mode using
a SUBREG. */
if (REG_P (args[i].value)
&& GET_MODE_CLASS (args[i].mode) == MODE_INT)
{
args[i].initial_value
= gen_lowpart_SUBREG (mode, args[i].value);
SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1;
SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value,
args[i].unsignedp);
}
/* CSE will replace this only if it contains args[i].value
pseudo, so convert it down to the declared mode using
a SUBREG. */
if (REG_P (args[i].value)
&& GET_MODE_CLASS (args[i].mode) == MODE_INT)
{
args[i].initial_value
= gen_lowpart_SUBREG (mode, args[i].value);
SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1;
SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value,
args[i].unsignedp);
}
#endif
}
}
}
}
}
/* Given the current state of MUST_PREALLOCATE and information about

View File

@ -360,26 +360,6 @@ construct_exit_block (void)
update_bb_for_insn (exit_block);
}
/* Called to move the SAVE_EXPRs for parameter declarations in a
nested function into the nested function. DATA is really the
nested FUNCTION_DECL. */
static tree
set_save_expr_context (tree *tp,
int *walk_subtrees,
void *data)
{
if (TREE_CODE (*tp) == SAVE_EXPR && !SAVE_EXPR_CONTEXT (*tp))
SAVE_EXPR_CONTEXT (*tp) = (tree) data;
/* Do not walk back into the SAVE_EXPR_CONTEXT; that will cause
circularity. */
else if (DECL_P (*tp))
*walk_subtrees = 0;
return NULL;
}
/* Translate the intermediate representation contained in the CFG
from GIMPLE trees to RTL.
@ -403,15 +383,6 @@ tree_expand_cfg (void)
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
}
/* If the function has a variably modified type, there may be
SAVE_EXPRs in the parameter types. Their context must be set to
refer to this function; they cannot be expanded in the containing
function. */
if (decl_function_context (current_function_decl) == current_function_decl
&& variably_modified_type_p (TREE_TYPE (current_function_decl)))
walk_tree (&TREE_TYPE (current_function_decl), set_save_expr_context,
current_function_decl, NULL);
/* Prepare the rtl middle end to start recording block changes. */
reset_block_changes ();

View File

@ -1,3 +1,7 @@
2004-07-02 Richard Henderson <rth@redhat.com>
* tree.c (cp_unsave_r): Update remap_save_expr call.
2004-07-02 Mark Mitchell <mark@codesourcery.com>
PR c++/16240

View File

@ -2256,7 +2256,7 @@ cp_unsave_r (tree* tp,
*tp = (tree) n->value;
}
else if (TREE_CODE (*tp) == SAVE_EXPR)
remap_save_expr (tp, st, current_function_decl, walk_subtrees);
remap_save_expr (tp, st, walk_subtrees);
else
{
copy_tree_r (tp, walk_subtrees, NULL);

View File

@ -10249,53 +10249,6 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
break;
case SAVE_EXPR:
/* If optimization is turned on, the SAVE_EXPRs that describe how to
access the upper bound values may be bogus. If they refer to a
register, they may only describe how to get at these values at the
points in the generated code right after they have just been
computed. Worse yet, in the typical case, the upper bound values
will not even *be* computed in the optimized code (though the
number of elements will), so these SAVE_EXPRs are entirely
bogus. In order to compensate for this fact, we check here to see
if optimization is enabled, and if so, we don't add an attribute
for the (unknown and unknowable) upper bound. This should not
cause too much trouble for existing (stupid?) debuggers because
they have to deal with empty upper bounds location descriptions
anyway in order to be able to deal with incomplete array types.
Of course an intelligent debugger (GDB?) should be able to
comprehend that a missing upper bound specification in an array
type used for a storage class `auto' local array variable
indicates that the upper bound is both unknown (at compile- time)
and unknowable (at run-time) due to optimization.
We assume that a MEM rtx is safe because gcc wouldn't put the
value there unless it was going to be used repeatedly in the
function, i.e. for cleanups. */
if (SAVE_EXPR_RTL (bound)
&& (! optimize || MEM_P (SAVE_EXPR_RTL (bound))))
{
dw_die_ref ctx = lookup_decl_die (current_function_decl);
dw_die_ref decl_die = new_die (DW_TAG_variable, ctx, bound);
rtx loc = SAVE_EXPR_RTL (bound);
/* If the RTL for the SAVE_EXPR is memory, handle the case where
it references an outer function's frame. */
if (MEM_P (loc))
{
rtx new_addr = fix_lexical_addr (XEXP (loc, 0), bound);
if (XEXP (loc, 0) != new_addr)
loc = gen_rtx_MEM (GET_MODE (loc), new_addr);
}
add_AT_flag (decl_die, DW_AT_artificial, 1);
add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
add_AT_location_description (decl_die, DW_AT_location,
loc_descriptor (loc, true));
add_AT_die_ref (subrange_die, bound_attr, decl_die);
}
/* Else leave out the attribute. */
break;
case VAR_DECL:
@ -10331,15 +10284,6 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
else
ctx = lookup_decl_die (current_function_decl);
/* If we weren't able to find a context, it's most likely the case
that we are processing the return type of the function. So
make a SAVE_EXPR to point to it and have the limbo DIE code
find the proper die. The save_expr function doesn't always
make a SAVE_EXPR, so do it ourselves. */
if (ctx == 0)
bound = build (SAVE_EXPR, TREE_TYPE (bound), bound,
current_function_decl, NULL_TREE);
decl_die = new_die (DW_TAG_variable, ctx, bound);
add_AT_flag (decl_die, DW_AT_artificial, 1);
add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
@ -13735,15 +13679,6 @@ dwarf2out_finish (const char *filename)
add_child_die (origin->die_parent, die);
else if (die == comp_unit_die)
;
/* If this was an expression for a bound involved in a function
return type, it may be a SAVE_EXPR for which we weren't able
to find a DIE previously. So try now. */
else if (node->created_for
&& TREE_CODE (node->created_for) == SAVE_EXPR
&& 0 != (origin = (lookup_decl_die
(SAVE_EXPR_CONTEXT
(node->created_for)))))
add_child_die (origin, die);
else if (errorcount > 0 || sorrycount > 0)
/* It's OK to be confused by errors in the input. */
add_child_die (comp_unit_die, die);

View File

@ -1349,11 +1349,6 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
if (GET_MODE (x) != BLKmode)
abort ();
if (GET_MODE (y) != BLKmode)
abort ();
x = protect_from_queue (x, 1);
y = protect_from_queue (y, 0);
size = protect_from_queue (size, 0);
@ -1365,6 +1360,11 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
if (size == 0)
abort ();
/* Make sure we've got BLKmode addresses; store_one_arg can decide that
block copy is more efficient for other large modes, e.g. DCmode. */
x = adjust_address (x, BLKmode, 0);
y = adjust_address (y, BLKmode, 0);
/* Set MEM_SIZE as appropriate for this block copy. The main place this
can be incorrect is coming from __builtin_memcpy. */
if (GET_CODE (size) == CONST_INT)
@ -5090,14 +5090,6 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
= gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
&unsignedp, 0));
SET_DECL_RTL (index, index_r);
if (TREE_CODE (value) == SAVE_EXPR
&& SAVE_EXPR_RTL (value) == 0)
{
/* Make sure value gets expanded once before the
loop. */
expand_expr (value, const0_rtx, VOIDmode, 0);
emit_queue ();
}
store_expr (lo_index, index_r, 0);
/* Build the head of the loop. */
@ -5986,7 +5978,6 @@ safe_from_p (rtx x, tree exp, int top_p)
{
rtx exp_rtl = 0;
int i, nops;
static tree save_expr_list;
if (x == 0
/* If EXP has varying size, we MUST use a target since we currently
@ -6018,30 +6009,6 @@ safe_from_p (rtx x, tree exp, int top_p)
return 0;
}
/* A SAVE_EXPR might appear many times in the expression passed to the
top-level safe_from_p call, and if it has a complex subexpression,
examining it multiple times could result in a combinatorial explosion.
E.g. on an Alpha running at least 200MHz, a Fortran testcase compiled
with optimization took about 28 minutes to compile -- even though it was
only a few lines long. So we mark each SAVE_EXPR we see with TREE_PRIVATE
and turn that off when we are done. We keep a list of the SAVE_EXPRs
we have processed. Note that the only test of top_p was above. */
if (top_p)
{
int rtn;
tree t;
save_expr_list = 0;
rtn = safe_from_p (x, exp, 0);
for (t = save_expr_list; t != 0; t = TREE_CHAIN (t))
TREE_PRIVATE (TREE_PURPOSE (t)) = 0;
return rtn;
}
/* Now look at our tree code and possibly recurse. */
switch (TREE_CODE_CLASS (TREE_CODE (exp)))
{
@ -6139,28 +6106,8 @@ safe_from_p (rtx x, tree exp, int top_p)
break;
case CLEANUP_POINT_EXPR:
return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
case SAVE_EXPR:
exp_rtl = SAVE_EXPR_RTL (exp);
if (exp_rtl)
break;
/* If we've already scanned this, don't do it again. Otherwise,
show we've scanned it and record for clearing the flag if we're
going on. */
if (TREE_PRIVATE (exp))
return 1;
TREE_PRIVATE (exp) = 1;
if (! safe_from_p (x, TREE_OPERAND (exp, 0), 0))
{
TREE_PRIVATE (exp) = 0;
return 0;
}
save_expr_list = tree_cons (exp, NULL_TREE, save_expr_list);
return 1;
return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
case BIND_EXPR:
/* The only operand we look at is operand 1. The rest aren't
@ -6841,88 +6788,30 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
return temp;
case SAVE_EXPR:
context = decl_function_context (exp);
{
tree val = TREE_OPERAND (exp, 0);
rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
/* If this SAVE_EXPR was at global context, assume we are an
initialization function and move it into our context. */
if (context == 0)
SAVE_EXPR_CONTEXT (exp) = current_function_decl;
if (TREE_CODE (val) != VAR_DECL || !DECL_ARTIFICIAL (val))
{
/* We can indeed still hit this case, typically via builtin
expanders calling save_expr immediately before expanding
something. Assume this means that we only have to deal
with non-BLKmode values. */
if (GET_MODE (ret) == BLKmode)
abort ();
if (context == current_function_decl)
context = 0;
val = build_decl (VAR_DECL, NULL, TREE_TYPE (exp));
DECL_ARTIFICIAL (val) = 1;
TREE_OPERAND (exp, 0) = val;
/* If this is non-local, handle it. */
if (context)
{
/* The following call just exists to abort if the context is
not of a containing function. */
find_function_data (context);
if (!CONSTANT_P (ret))
ret = copy_to_reg (ret);
SET_DECL_RTL (val, ret);
}
temp = SAVE_EXPR_RTL (exp);
if (temp && REG_P (temp))
{
put_var_into_stack (exp, /*rescan=*/true);
temp = SAVE_EXPR_RTL (exp);
}
if (temp == 0 || !MEM_P (temp))
abort ();
return
replace_equiv_address (temp,
fix_lexical_addr (XEXP (temp, 0), exp));
}
if (SAVE_EXPR_RTL (exp) == 0)
{
if (mode == VOIDmode)
temp = const0_rtx;
else
temp = assign_temp (build_qualified_type (type,
(TYPE_QUALS (type)
| TYPE_QUAL_CONST)),
3, 0, 0);
SAVE_EXPR_RTL (exp) = temp;
if (!optimize && REG_P (temp))
save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, temp,
save_expr_regs);
/* If the mode of TEMP does not match that of the expression, it
must be a promoted value. We pass store_expr a SUBREG of the
wanted mode but mark it so that we know that it was already
extended. */
if (REG_P (temp) && GET_MODE (temp) != mode)
{
temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
promote_mode (type, mode, &unsignedp, 0);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
}
if (temp == const0_rtx)
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
else
store_expr (TREE_OPERAND (exp, 0), temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
TREE_USED (exp) = 1;
}
/* If the mode of SAVE_EXPR_RTL does not match that of the expression, it
must be a promoted value. We return a SUBREG of the wanted mode,
but mark it so that we know that it was already extended. */
if (REG_P (SAVE_EXPR_RTL (exp))
&& GET_MODE (SAVE_EXPR_RTL (exp)) != mode)
{
/* Compute the signedness and make the proper SUBREG. */
promote_mode (type, mode, &unsignedp, 0);
temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
return temp;
}
return SAVE_EXPR_RTL (exp);
return ret;
}
case UNSAVE_EXPR:
{
@ -7301,25 +7190,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
&& (offset != 0
|| (code == ARRAY_RANGE_REF && mode == BLKmode)))
{
/* If the operand is a SAVE_EXPR, we can deal with this by
forcing the SAVE_EXPR into memory. */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
{
put_var_into_stack (TREE_OPERAND (exp, 0),
/*rescan=*/true);
op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
}
else
{
tree nt
= build_qualified_type (TREE_TYPE (tem),
(TYPE_QUALS (TREE_TYPE (tem))
| TYPE_QUAL_CONST));
rtx memloc = assign_temp (nt, 1, 1, 1);
tree nt = build_qualified_type (TREE_TYPE (tem),
(TYPE_QUALS (TREE_TYPE (tem))
| TYPE_QUAL_CONST));
rtx memloc = assign_temp (nt, 1, 1, 1);
emit_move_insn (memloc, op0);
op0 = memloc;
}
emit_move_insn (memloc, op0);
op0 = memloc;
}
if (offset != 0)
@ -9045,31 +8922,20 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF
|| GET_CODE (op0) == PARALLEL || GET_CODE (op0) == LO_SUM)
{
/* If the operand is a SAVE_EXPR, we can deal with this by
forcing the SAVE_EXPR into memory. */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
{
put_var_into_stack (TREE_OPERAND (exp, 0),
/*rescan=*/true);
op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
}
/* If this object is in a register, it can't be BLKmode. */
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
rtx memloc = assign_temp (inner_type, 1, 1, 1);
if (GET_CODE (op0) == PARALLEL)
/* Handle calls that pass values in multiple
non-contiguous locations. The Irix 6 ABI has examples
of this. */
emit_group_store (memloc, op0, inner_type,
int_size_in_bytes (inner_type));
else
{
/* If this object is in a register, it can't be BLKmode. */
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
rtx memloc = assign_temp (inner_type, 1, 1, 1);
emit_move_insn (memloc, op0);
if (GET_CODE (op0) == PARALLEL)
/* Handle calls that pass values in multiple
non-contiguous locations. The Irix 6 ABI has examples
of this. */
emit_group_store (memloc, op0, inner_type,
int_size_in_bytes (inner_type));
else
emit_move_insn (memloc, op0);
op0 = memloc;
}
op0 = memloc;
}
if (!MEM_P (op0))

View File

@ -2661,7 +2661,7 @@ twoval_comparison_p (tree arg, tree *cval1, tree *cval2, int *save_p)
|| code == COMPOUND_EXPR))
class = '2';
else if (class == 'e' && code == SAVE_EXPR && SAVE_EXPR_RTL (arg) == 0
else if (class == 'e' && code == SAVE_EXPR
&& ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0)))
{
/* If we've already found a CVAL1 or CVAL2, this expression is
@ -5971,10 +5971,6 @@ fold (tree expr)
if all operands are constant. */
int wins = 1;
/* Don't try to process an SAVE_EXPR that's already been evaluated. */
if (code == SAVE_EXPR && SAVE_EXPR_RTL (t) != 0)
return t;
/* Return right away if a constant. */
if (kind == 'c')
return t;
@ -8985,14 +8981,7 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
return;
*slot = expr;
code = TREE_CODE (expr);
if (code == SAVE_EXPR && SAVE_EXPR_NOPLACEHOLDER (expr))
{
/* Allow SAVE_EXPR_NOPLACEHOLDER flag to be modified. */
memcpy (buf, expr, tree_size (expr));
expr = (tree) buf;
SAVE_EXPR_NOPLACEHOLDER (expr) = 0;
}
else if (TREE_CODE_CLASS (code) == 'd' && DECL_ASSEMBLER_NAME_SET_P (expr))
if (TREE_CODE_CLASS (code) == 'd' && DECL_ASSEMBLER_NAME_SET_P (expr))
{
/* Allow DECL_ASSEMBLER_NAME to be modified. */
memcpy (buf, expr, tree_size (expr));
@ -9051,7 +9040,6 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
case 'e':
switch (code)
{
case SAVE_EXPR: len = 2; break;
case GOTO_SUBROUTINE_EXPR: len = 0; break;
case WITH_CLEANUP_EXPR: len = 2; break;
default: break;

View File

@ -436,7 +436,6 @@ free_after_compilation (struct function *f)
f->x_nonlocal_goto_handler_labels = NULL;
f->x_return_label = NULL;
f->x_naked_return_label = NULL;
f->x_save_expr_regs = NULL;
f->x_stack_slot_list = NULL;
f->x_tail_recursion_reentry = NULL;
f->x_arg_pointer_save_area = NULL;
@ -1305,9 +1304,7 @@ put_var_into_stack (tree decl, int rescan)
context = decl_function_context (decl);
/* Get the current rtl used for this object and its original mode. */
orig_reg = reg = (TREE_CODE (decl) == SAVE_EXPR
? SAVE_EXPR_RTL (decl)
: DECL_RTL_IF_SET (decl));
orig_reg = reg = DECL_RTL_IF_SET (decl);
/* No need to do anything if decl has no rtx yet
since in that case caller is setting TREE_ADDRESSABLE
@ -2824,10 +2821,8 @@ gen_mem_addressof (rtx reg, tree decl, int rescan)
if (decl)
{
tree type = TREE_TYPE (decl);
enum machine_mode decl_mode
= (DECL_P (decl) ? DECL_MODE (decl) : TYPE_MODE (TREE_TYPE (decl)));
rtx decl_rtl = (TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl)
: DECL_RTL_IF_SET (decl));
enum machine_mode decl_mode = DECL_MODE (decl);
rtx decl_rtl = DECL_RTL_IF_SET (decl);
PUT_MODE (reg, decl_mode);

View File

@ -243,10 +243,6 @@ struct function GTY(())
on machines which require execution of the epilogue on all returns. */
rtx x_naked_return_label;
/* List (chain of EXPR_LISTs) of pseudo-regs of SAVE_EXPRs.
So we can mark them all live at the end of the function, if nonopt. */
rtx x_save_expr_regs;
/* List (chain of EXPR_LISTs) of all stack slots in this function.
Made for the sake of unshare_all_rtl. */
rtx x_stack_slot_list;
@ -506,7 +502,6 @@ extern int trampolines_created;
#define parm_reg_stack_loc (cfun->x_parm_reg_stack_loc)
#define return_label (cfun->x_return_label)
#define naked_return_label (cfun->x_naked_return_label)
#define save_expr_regs (cfun->x_save_expr_regs)
#define stack_slot_list (cfun->x_stack_slot_list)
#define parm_birth_insn (cfun->x_parm_birth_insn)
#define frame_offset (cfun->x_frame_offset)

View File

@ -650,7 +650,6 @@ adjust_field_tree_exp (type_p t, options_p opt ATTRIBUTE_UNUSED)
int first_rtl;
int num_rtl;
} data[] = {
{ "SAVE_EXPR", 2, 1 },
{ "GOTO_SUBROUTINE_EXPR", 0, 2 },
{ "WITH_CLEANUP_EXPR", 2, 1 },
};

View File

@ -1,3 +1,7 @@
2004-07-02 Richard Henderson <rth@redhat.com>
* jcf-write.c (generate_bytecode_insns <case SAVE_EXPR>): Rewrite.
2004-07-01 Richard Henderson <rth@redhat.com>
* class.c (registerClass_libfunc): Remove.

View File

@ -2197,35 +2197,24 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state)
}
break;
case SAVE_EXPR:
/* Because the state associated with a SAVE_EXPR tree node must
be a RTL expression, we use it to store the DECL_LOCAL_INDEX
of a temporary variable in a CONST_INT. */
if (! SAVE_EXPR_RTL (exp))
/* The first time through, the argument of the SAVE_EXPR will be
something complex. Evaluate it, and replace the argument with
a VAR_DECL that holds the result. */
arg = TREE_OPERAND (exp, 0);
if (TREE_CODE (arg) != VAR_DECL || DECL_NAME (arg))
{
tree type = TREE_TYPE (exp);
tree decl = build_decl (VAR_DECL, NULL_TREE, type);
generate_bytecode_insns (TREE_OPERAND (exp, 0),
STACK_TARGET, state);
generate_bytecode_insns (arg, STACK_TARGET, state);
localvar_alloc (decl, state);
SAVE_EXPR_RTL (exp) = GEN_INT (DECL_LOCAL_INDEX (decl));
TREE_OPERAND (exp, 0) = decl;
emit_dup (TYPE_IS_WIDE (type) ? 2 : 1, 0, state);
emit_store (decl, state);
}
else
{
/* The following code avoids creating a temporary DECL just
to pass to emit_load. This code could be factored with
the similar implementation in emit_load_or_store. */
tree type = TREE_TYPE (exp);
int kind = adjust_typed_op (type, 4);
int index = (int) INTVAL (SAVE_EXPR_RTL (exp));
if (index <= 3)
{
RESERVE (1); /* [ilfda]load_[0123] */
OP1 (OPCODE_iload + 5 + 4*kind + index);
}
else /* [ilfda]load */
maybe_wide (OPCODE_iload + kind, index, state);
emit_load (arg, state);
NOTE_PUSH (TYPE_IS_WIDE (type) ? 2 : 1);
}
break;

View File

@ -578,8 +578,6 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
case 's':
if (TREE_CODE (node) == BIT_FIELD_REF && BIT_FIELD_REF_UNSIGNED (node))
fputs (" unsigned", file);
else if (TREE_CODE (node) == SAVE_EXPR && SAVE_EXPR_NOPLACEHOLDER (node))
fputs (" noplaceholder", file);
if (TREE_CODE (node) == BIND_EXPR)
{
print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4);

View File

@ -66,7 +66,6 @@ static void place_union_field (record_layout_info, tree);
static int excess_unit_span (HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, tree);
#endif
static void force_type_save_exprs_1 (tree);
extern void debug_rli (record_layout_info);
/* SAVE_EXPRs for sizes of types and decls, waiting to be expanded. */
@ -146,8 +145,6 @@ variable_size (tree size)
not wish to do that here; the array-size is the same in both
places. */
save = skip_simple_arithmetic (size);
if (TREE_CODE (save) == SAVE_EXPR)
SAVE_EXPR_PERSISTENT_P (save) = 1;
if (cfun && cfun->x_dont_save_pending_sizes_p)
/* The front-end doesn't want us to keep a list of the expressions
@ -168,60 +165,6 @@ variable_size (tree size)
return size;
}
/* Given a type T, force elaboration of any SAVE_EXPRs used in the definition
of that type. */
void
force_type_save_exprs (tree t)
{
tree field;
switch (TREE_CODE (t))
{
case ERROR_MARK:
return;
case ARRAY_TYPE:
case SET_TYPE:
case VECTOR_TYPE:
/* It's probably overly-conservative to force elaboration of bounds and
also the sizes, but it's better to be safe than sorry. */
force_type_save_exprs_1 (TYPE_MIN_VALUE (TYPE_DOMAIN (t)));
force_type_save_exprs_1 (TYPE_MAX_VALUE (TYPE_DOMAIN (t)));
break;
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
{
force_type_save_exprs (TREE_TYPE (field));
force_type_save_exprs_1 (DECL_FIELD_OFFSET (field));
}
break;
default:
break;
}
force_type_save_exprs_1 (TYPE_SIZE (t));
force_type_save_exprs_1 (TYPE_SIZE_UNIT (t));
}
/* Utility routine of above, to verify that SIZE has been elaborated and
do so it it is a SAVE_EXPR and has not been. */
static void
force_type_save_exprs_1 (tree size)
{
if (size
&& (size = skip_simple_arithmetic (size))
&& TREE_CODE (size) == SAVE_EXPR
&& !SAVE_EXPR_RTL (size))
expand_expr (size, NULL_RTX, VOIDmode, 0);
}
#ifndef MAX_FIXED_MODE_SIZE
#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (DImode)

View File

@ -528,8 +528,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
else if (TREE_CODE (*tp) == STATEMENT_LIST)
copy_statement_list (tp);
else if (TREE_CODE (*tp) == SAVE_EXPR)
remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0),
walk_subtrees);
remap_save_expr (tp, id->decl_map, walk_subtrees);
else if (TREE_CODE (*tp) == UNSAVE_EXPR)
/* UNSAVE_EXPRs should not be generated until expansion time. */
abort ();
@ -2318,11 +2317,10 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
/* The SAVE_EXPR pointed to by TP is being copied. If ST contains
information indicating to what new SAVE_EXPR this one should be mapped,
use that one. Otherwise, create a new node and enter it in ST. FN is the
function into which the copy will be placed. */
use that one. Otherwise, create a new node and enter it in ST. */
void
remap_save_expr (tree *tp, void *st_, tree fn, int *walk_subtrees)
remap_save_expr (tree *tp, void *st_, int *walk_subtrees)
{
splay_tree st = (splay_tree) st_;
splay_tree_node n;
@ -2336,11 +2334,6 @@ remap_save_expr (tree *tp, void *st_, tree fn, int *walk_subtrees)
{
t = copy_node (*tp);
/* The SAVE_EXPR is now part of the function into which we
are inlining this body. */
SAVE_EXPR_CONTEXT (t) = fn;
/* And we haven't evaluated it yet. */
SAVE_EXPR_RTL (t) = NULL_RTX;
/* Remember this SAVE_EXPR. */
splay_tree_insert (st, (splay_tree_key) *tp, (splay_tree_value) t);
/* Make sure we don't remap an already-remapped SAVE_EXPR. */
@ -2412,7 +2405,7 @@ unsave_r (tree *tp, int *walk_subtrees, void *data)
else if (TREE_CODE (*tp) == BIND_EXPR)
copy_bind_expr (tp, walk_subtrees, id);
else if (TREE_CODE (*tp) == SAVE_EXPR)
remap_save_expr (tp, st, current_function_decl, walk_subtrees);
remap_save_expr (tp, st, walk_subtrees);
else
{
copy_tree_r (tp, walk_subtrees, NULL);

View File

@ -29,7 +29,7 @@ bool tree_inlinable_function_p (tree);
tree copy_tree_r (tree*, int*, void*);
void clone_body (tree, tree, void*);
tree save_body (tree, tree *);
void remap_save_expr (tree*, void*, tree, int*);
void remap_save_expr (tree*, void*, int*);
int estimate_num_insns (tree expr);
/* 0 if we should not perform inlining.

View File

@ -1375,8 +1375,7 @@ save_expr (tree expr)
if (contains_placeholder_p (inner))
return t;
t = build3 (SAVE_EXPR, TREE_TYPE (expr), t, current_function_decl,
NULL_TREE);
t = build1 (SAVE_EXPR, TREE_TYPE (expr), t);
/* This expression might be placed ahead of a jump to ensure that the
value was computed on both sides of the jump. So make sure it isn't
@ -1451,8 +1450,6 @@ first_rtl_op (enum tree_code code)
{
switch (code)
{
case SAVE_EXPR:
return 2;
case GOTO_SUBROUTINE_EXPR:
return 0;
case WITH_CLEANUP_EXPR:
@ -1511,11 +1508,6 @@ unsave_expr_1 (tree expr)
{
switch (TREE_CODE (expr))
{
case SAVE_EXPR:
if (! SAVE_EXPR_PERSISTENT_P (expr))
SAVE_EXPR_RTL (expr) = 0;
break;
case TARGET_EXPR:
/* Don't mess with a TARGET_EXPR that hasn't been expanded.
It's OK for this to happen if it was part of a subtree that
@ -1640,7 +1632,6 @@ bool
contains_placeholder_p (tree exp)
{
enum tree_code code;
int result;
if (!exp)
return 0;
@ -1678,19 +1669,6 @@ contains_placeholder_p (tree exp)
|| CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1))
|| CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 2)));
case SAVE_EXPR:
/* If we already know this doesn't have a placeholder, don't
check again. */
if (SAVE_EXPR_NOPLACEHOLDER (exp) || SAVE_EXPR_RTL (exp) != 0)
return 0;
SAVE_EXPR_NOPLACEHOLDER (exp) = 1;
result = CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
if (result)
SAVE_EXPR_NOPLACEHOLDER (exp) = 0;
return result;
default:
break;
}
@ -4781,9 +4759,6 @@ decl_function_context (tree decl)
if (TREE_CODE (decl) == ERROR_MARK)
return 0;
if (TREE_CODE (decl) == SAVE_EXPR)
context = SAVE_EXPR_CONTEXT (decl);
/* C++ virtual functions use DECL_CONTEXT for the class of the vtable
where we look up the function at runtime. Such functions always take
a first argument of type 'pointer to real context'.

View File

@ -723,10 +723,9 @@ DEFTREECODE (NON_LVALUE_EXPR, "non_lvalue_expr", '1', 1)
DEFTREECODE (VIEW_CONVERT_EXPR, "view_convert_expr", '1', 1)
/* Represents something we computed once and will use multiple times.
First operand is that expression. Second is the function decl
in which the SAVE_EXPR was created. The third operand is the RTL,
nonzero only after the expression has been computed. */
DEFTREECODE (SAVE_EXPR, "save_expr", 'e', 3)
First operand is that expression. After it is evaluated once, it
will be replaced by the temporary variable that holds the value. */
DEFTREECODE (SAVE_EXPR, "save_expr", 'e', 1)
/* For a UNSAVE_EXPR, operand 0 is the value to unsave. By unsave, we
mean that all _EXPRs such as TARGET_EXPRs, SAVE_EXPRs, CALL_EXPRs,

View File

@ -282,8 +282,6 @@ struct tree_common GTY(())
all decls
BIT_FIELD_REF_UNSIGNED in
BIT_FIELD_REF
SAVE_EXPR_NOPLACEHOLDER in
SAVE_EXPR
asm_written_flag:
@ -1030,19 +1028,6 @@ struct tree_vec GTY(())
&& VOID_TYPE_P (TREE_TYPE (NODE)) \
&& integer_zerop (TREE_OPERAND (NODE, 0)))
/* In a SAVE_EXPR node. */
#define SAVE_EXPR_CONTEXT(NODE) TREE_OPERAND_CHECK_CODE (NODE, SAVE_EXPR, 1)
#define SAVE_EXPR_RTL(NODE) TREE_RTL_OPERAND_CHECK (NODE, SAVE_EXPR, 2)
#define SAVE_EXPR_NOPLACEHOLDER(NODE) \
(SAVE_EXPR_CHECK (NODE)->common.unsigned_flag)
/* Nonzero if the SAVE_EXPRs value should be kept, even if it occurs
both in normal code and in a handler. (Normally, in a handler, all
SAVE_EXPRs are unsaved, meaning that their values are
recalculated.) */
#define SAVE_EXPR_PERSISTENT_P(NODE) TREE_ASM_WRITTEN (SAVE_EXPR_CHECK (NODE))
/* In a WITH_CLEANUP_EXPR node. */
#define WITH_CLEANUP_EXPR_RTL(NODE) \
TREE_RTL_OPERAND_CHECK (NODE, WITH_CLEANUP_EXPR, 2)
@ -3210,11 +3195,6 @@ extern tree substitute_placeholder_in_expr (tree, tree);
extern tree variable_size (tree);
/* Given a type T, force elaboration of any SAVE_EXPRs used in the definition
of that type. */
extern void force_type_save_exprs (tree);
/* stabilize_reference (EXP) returns a reference equivalent to EXP
but it can be used multiple times
and only evaluate the subexpressions once. */