+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,
}
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);
}
}
}
}
-/* 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.
{
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);
/* 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.
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 *);
static void restore_fixed_argument_area (rtx, rtx, int, int);
#endif
\f
-/* 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;
-}
-\f
/* 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.
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
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.
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 ();
+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
*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);
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:
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);
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);
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);
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)
= 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. */
{
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
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)))
{
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
return temp;
case SAVE_EXPR:
- context = decl_function_context (exp);
-
- /* 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 (context == current_function_decl)
- context = 0;
-
- /* 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);
-
- 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 val = TREE_OPERAND (exp, 0);
+ rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
- TREE_USED (exp) = 1;
- }
+ 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 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. */
+ val = build_decl (VAR_DECL, NULL, TREE_TYPE (exp));
+ DECL_ARTIFICIAL (val) = 1;
+ TREE_OPERAND (exp, 0) = val;
- 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;
- }
+ if (!CONSTANT_P (ret))
+ ret = copy_to_reg (ret);
+ SET_DECL_RTL (val, ret);
+ }
- return SAVE_EXPR_RTL (exp);
+ return ret;
+ }
case UNSAVE_EXPR:
{
&& (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)
|| 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);
-
- 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);
+ emit_move_insn (memloc, op0);
- op0 = memloc;
- }
+ op0 = memloc;
}
if (!MEM_P (op0))
|| 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
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;
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));
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;
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;
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
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);
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;
#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)
int first_rtl;
int num_rtl;
} data[] = {
- { "SAVE_EXPR", 2, 1 },
{ "GOTO_SUBROUTINE_EXPR", 0, 2 },
{ "WITH_CLEANUP_EXPR", 2, 1 },
};
+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.
}
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;
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);
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);
\f
/* SAVE_EXPRs for sizes of types and decls, waiting to be expanded. */
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
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);
-}
\f
#ifndef MAX_FIXED_MODE_SIZE
#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (DImode)
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 ();
/* 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;
{
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. */
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);
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.
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
{
switch (code)
{
- case SAVE_EXPR:
- return 2;
case GOTO_SUBROUTINE_EXPR:
return 0;
case WITH_CLEANUP_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
contains_placeholder_p (tree exp)
{
enum tree_code code;
- int result;
if (!exp)
return 0;
|| 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;
}
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'.
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,
all decls
BIT_FIELD_REF_UNSIGNED in
BIT_FIELD_REF
- SAVE_EXPR_NOPLACEHOLDER in
- SAVE_EXPR
asm_written_flag:
&& 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)
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. */