mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-20 09:00:37 +08:00
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:
parent
a7e4cdca85
commit
82c8274320
@ -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,
|
||||
|
66
gcc/c-decl.c
66
gcc/c-decl.c
@ -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.
|
||||
|
200
gcc/calls.c
200
gcc/calls.c
@ -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
|
||||
|
@ -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 ();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
222
gcc/expr.c
222
gcc/expr.c
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 },
|
||||
};
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
27
gcc/tree.c
27
gcc/tree.c
@ -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'.
|
||||
|
@ -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,
|
||||
|
20
gcc/tree.h
20
gcc/tree.h
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user