/* Sequence number of this binding contour within the function,
in order of entry. */
int block_start_count;
- /* Nonzero => value to restore stack to on exit. */
- rtx stack_level;
/* The NOTE that starts this contour.
Used by expand_goto to check whether the destination
is within each contour or not. */
rtx first_insn;
- /* Innermost containing binding contour that has a stack level. */
- struct nesting *innermost_stack_block;
- /* List of cleanups to be run on exit from this contour.
- This is a list of expressions to be evaluated.
- The TREE_PURPOSE of each link is the ..._DECL node
- which the cleanup pertains to. */
- tree cleanups;
- /* List of cleanup-lists of blocks containing this block,
- as they were at the locus where this block appears.
- There is an element for each containing block,
- ordered innermost containing block first.
- The tail of this list can be 0,
- if all remaining elements would be empty lists.
- The element's TREE_VALUE is the cleanup-list of that block,
- which may be null. */
- tree outer_cleanups;
- /* Chain of labels defined inside this binding contour.
- For contours that have stack levels or cleanups. */
- struct label_chain *label_chain;
- /* Nonzero if this is associated with an EH region. */
- int exception_region;
/* The saved target_temp_slot_level from our outer block.
We may reset target_temp_slot_level to be the level of
this block, if that is done, target_temp_slot_level
cond_stack = cond_stack->next; \
if (block_stack == this) \
block_stack = block_stack->next; \
- if (stack_block_stack == this) \
- stack_block_stack = stack_block_stack->next; \
if (case_stack == this) \
case_stack = case_stack->next; \
nesting_depth = nesting_stack->depth - 1; \
/* Number of binding contours started in current function
before the label reference. */
int block_start_count;
- /* The outermost stack level that should be restored for this jump.
- Each time a binding contour that resets the stack is exited,
- if the target label is *not* yet defined, this slot is updated. */
- rtx stack_level;
- /* List of lists of cleanup expressions to be run by this goto.
- There is one element for each block that this goto is within.
- The tail of this list can be 0,
- if all remaining elements would be empty.
- The TREE_VALUE contains the cleanup list of that block as of the
- time this goto was seen.
- The TREE_ADDRESSABLE flag is 1 for a block that has been exited. */
- tree cleanup_list_list;
-};
-
-/* Within any binding contour that must restore a stack level,
- all labels are recorded with a chain of these structures. */
-
-struct label_chain GTY(())
-{
- /* Points to following fixup. */
- struct label_chain *next;
- tree label;
};
struct stmt_status GTY(())
/* If any new stacks are added here, add them to POPSTACKS too. */
- /* Chain of all pending binding contours that restore stack levels
- or have cleanups. */
- struct nesting * x_stack_block_stack;
-
/* Chain of all pending conditional statements. */
struct nesting * x_cond_stack;
/* Number of binding contours started so far in this function. */
int x_block_start_count;
- /* Each time we expand an expression-statement,
- record the expr's type and its RTL value here. */
- tree x_last_expr_type;
- rtx x_last_expr_value;
- rtx x_last_expr_alt_rtl;
-
- /* Nonzero if within a ({...}) grouping, in which case we must
- always compute a value for each expr-stmt in case it is the last one. */
- int x_expr_stmts_for_value;
-
/* Location of last line-number note, whether we actually
emitted it or not. */
location_t x_emit_locus;
};
#define block_stack (cfun->stmt->x_block_stack)
-#define stack_block_stack (cfun->stmt->x_stack_block_stack)
#define cond_stack (cfun->stmt->x_cond_stack)
#define case_stack (cfun->stmt->x_case_stack)
#define nesting_stack (cfun->stmt->x_nesting_stack)
#define nesting_depth (cfun->stmt->x_nesting_depth)
#define current_block_start_count (cfun->stmt->x_block_start_count)
-#define last_expr_type (cfun->stmt->x_last_expr_type)
-#define last_expr_value (cfun->stmt->x_last_expr_value)
-#define last_expr_alt_rtl (cfun->stmt->x_last_expr_alt_rtl)
-#define expr_stmts_for_value (cfun->stmt->x_expr_stmts_for_value)
#define emit_locus (cfun->stmt->x_emit_locus)
#define goto_fixup_chain (cfun->stmt->x_goto_fixup_chain)
static int n_occurrences (int, const char *);
static bool decl_conflicts_with_clobbers_p (tree, const HARD_REG_SET);
-static void expand_goto_internal (tree, rtx, rtx);
-static int expand_fixup (tree, rtx, rtx);
static void expand_nl_goto_receiver (void);
-static void fixup_gotos (struct nesting *, rtx, tree, rtx, int);
static bool check_operand_nalternatives (tree, tree);
static bool check_unique_operand_names (tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree);
-static void expand_null_return_1 (rtx);
+static void expand_null_return_1 (void);
static enum br_predictor return_prediction (rtx);
static rtx shift_return_value (rtx);
static void expand_value_return (rtx);
-static int tail_recursion_args (tree, tree);
-static void expand_cleanups (tree, int, int);
-static void check_seenlabel (void);
static void do_jump_if_equal (rtx, rtx, rtx, int);
static int estimate_case_costs (case_node_ptr);
static bool same_case_target_p (rtx, rtx);
last_insn = get_last_insn ();
if (!optimize
- && (GET_CODE (last_insn) == CODE_LABEL
- || (GET_CODE (last_insn) == NOTE
+ && (LABEL_P (last_insn)
+ || (NOTE_P (last_insn)
&& prev_real_insn (last_insn) == 0)))
emit_insn (gen_nop ());
}
x = convert_memory_address (Pmode, x);
- emit_queue ();
-
- if (! cfun->computed_goto_common_label)
- {
- cfun->computed_goto_common_reg = copy_to_mode_reg (Pmode, x);
- cfun->computed_goto_common_label = gen_label_rtx ();
-
- do_pending_stack_adjust ();
- emit_label (cfun->computed_goto_common_label);
- emit_indirect_jump (cfun->computed_goto_common_reg);
-
- current_function_has_computed_jump = 1;
- }
- else
- {
- emit_move_insn (cfun->computed_goto_common_reg, x);
- emit_jump (cfun->computed_goto_common_label);
- }
+ do_pending_stack_adjust ();
+ emit_indirect_jump (x);
}
\f
/* Handle goto statements and the labels that they can go to. */
void
expand_label (tree label)
{
- struct label_chain *p;
rtx label_r = label_rtx (label);
do_pending_stack_adjust ();
if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
maybe_set_first_label_num (label_r);
-
- if (stack_block_stack != 0)
- {
- p = ggc_alloc (sizeof (struct label_chain));
- p->next = stack_block_stack->data.block.label_chain;
- stack_block_stack->data.block.label_chain = p;
- p->label = label;
- }
}
/* Generate RTL code for a `goto' statement with target label LABEL.
abort ();
#endif
- expand_goto_internal (label, label_rtx (label), NULL_RTX);
-}
-
-/* Generate RTL code for a `goto' statement with target label BODY.
- LABEL should be a LABEL_REF.
- LAST_INSN, if non-0, is the rtx we should consider as the last
- insn emitted (for the purposes of cleaning up a return). */
-
-static void
-expand_goto_internal (tree body, rtx label, rtx last_insn)
-{
- struct nesting *block;
- rtx stack_level = 0;
-
- if (GET_CODE (label) != CODE_LABEL)
- abort ();
-
- /* If label has already been defined, we can tell now
- whether and how we must alter the stack level. */
-
- if (PREV_INSN (label) != 0)
- {
- /* Find the innermost pending block that contains the label.
- (Check containment by comparing insn-uids.)
- Then restore the outermost stack level within that block,
- and do cleanups of all blocks contained in it. */
- for (block = block_stack; block; block = block->next)
- {
- if (INSN_UID (block->data.block.first_insn) < INSN_UID (label))
- break;
- if (block->data.block.stack_level != 0)
- stack_level = block->data.block.stack_level;
- /* Execute the cleanups for blocks we are exiting. */
- if (block->data.block.cleanups != 0)
- {
- expand_cleanups (block->data.block.cleanups, 1, 1);
- do_pending_stack_adjust ();
- }
- }
-
- if (stack_level)
- {
- /* Ensure stack adjust isn't done by emit_jump, as this
- would clobber the stack pointer. This one should be
- deleted as dead by flow. */
- clear_pending_stack_adjust ();
- do_pending_stack_adjust ();
-
- /* Don't do this adjust if it's to the end label and this function
- is to return with a depressed stack pointer. */
- if (label == return_label
- && (((TREE_CODE (TREE_TYPE (current_function_decl))
- == FUNCTION_TYPE)
- && (TYPE_RETURNS_STACK_DEPRESSED
- (TREE_TYPE (current_function_decl))))))
- ;
- else
- emit_stack_restore (SAVE_BLOCK, stack_level, NULL_RTX);
- }
-
- if (body != 0 && DECL_TOO_LATE (body))
- error ("jump to `%s' invalidly jumps into binding contour",
- IDENTIFIER_POINTER (DECL_NAME (body)));
- }
- /* Label not yet defined: may need to put this goto
- on the fixup list. */
- else if (! expand_fixup (body, label, last_insn))
- {
- /* No fixup needed. Record that the label is the target
- of at least one goto that has no fixup. */
- if (body != 0)
- TREE_ADDRESSABLE (body) = 1;
- }
-
- emit_jump (label);
-}
-\f
-/* Generate if necessary a fixup for a goto
- whose target label in tree structure (if any) is TREE_LABEL
- and whose target in rtl is RTL_LABEL.
-
- If LAST_INSN is nonzero, we pretend that the jump appears
- after insn LAST_INSN instead of at the current point in the insn stream.
-
- The fixup will be used later to insert insns just before the goto.
- Those insns will restore the stack level as appropriate for the
- target label, and will (in the case of C++) also invoke any object
- destructors which have to be invoked when we exit the scopes which
- are exited by the goto.
-
- Value is nonzero if a fixup is made. */
-
-static int
-expand_fixup (tree tree_label, rtx rtl_label, rtx last_insn)
-{
- struct nesting *block, *end_block;
-
- /* See if we can recognize which block the label will be output in.
- This is possible in some very common cases.
- If we succeed, set END_BLOCK to that block.
- Otherwise, set it to 0. */
-
- if (cond_stack
- && (rtl_label == cond_stack->data.cond.endif_label
- || rtl_label == cond_stack->data.cond.next_label))
- end_block = cond_stack;
- else
- end_block = 0;
-
- /* Now set END_BLOCK to the binding level to which we will return. */
-
- if (end_block)
- {
- struct nesting *next_block = end_block->all;
- block = block_stack;
-
- /* First see if the END_BLOCK is inside the innermost binding level.
- If so, then no cleanups or stack levels are relevant. */
- while (next_block && next_block != block)
- next_block = next_block->all;
-
- if (next_block)
- return 0;
-
- /* Otherwise, set END_BLOCK to the innermost binding level
- which is outside the relevant control-structure nesting. */
- next_block = block_stack->next;
- for (block = block_stack; block != end_block; block = block->all)
- if (block == next_block)
- next_block = next_block->next;
- end_block = next_block;
- }
-
- /* Does any containing block have a stack level or cleanups?
- If not, no fixup is needed, and that is the normal case
- (the only case, for standard C). */
- for (block = block_stack; block != end_block; block = block->next)
- if (block->data.block.stack_level != 0
- || block->data.block.cleanups != 0)
- break;
-
- if (block != end_block)
- {
- /* Ok, a fixup is needed. Add a fixup to the list of such. */
- struct goto_fixup *fixup = ggc_alloc (sizeof (struct goto_fixup));
- /* In case an old stack level is restored, make sure that comes
- after any pending stack adjust. */
- /* ?? If the fixup isn't to come at the present position,
- doing the stack adjust here isn't useful. Doing it with our
- settings at that location isn't useful either. Let's hope
- someone does it! */
- if (last_insn == 0)
- do_pending_stack_adjust ();
- fixup->target = tree_label;
- fixup->target_rtl = rtl_label;
-
- /* Create a BLOCK node and a corresponding matched set of
- NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes at
- this point. The notes will encapsulate any and all fixup
- code which we might later insert at this point in the insn
- stream. Also, the BLOCK node will be the parent (i.e. the
- `SUPERBLOCK') of any other BLOCK nodes which we might create
- later on when we are expanding the fixup code.
-
- Note that optimization passes might move the *_BLOCK notes away,
- so we use a NOTE_INSN_DELETED as a placeholder. */
-
- {
- rtx original_before_jump
- = last_insn ? last_insn : get_last_insn ();
- rtx start;
- rtx end;
- tree block;
-
- block = make_node (BLOCK);
- TREE_USED (block) = 1;
-
- if (!cfun->x_whole_function_mode_p)
- lang_hooks.decls.insert_block (block);
- else
- {
- BLOCK_CHAIN (block)
- = BLOCK_CHAIN (DECL_INITIAL (current_function_decl));
- BLOCK_CHAIN (DECL_INITIAL (current_function_decl))
- = block;
- }
-
- start_sequence ();
- start = emit_note (NOTE_INSN_BLOCK_BEG);
- if (cfun->x_whole_function_mode_p)
- NOTE_BLOCK (start) = block;
- fixup->before_jump = emit_note (NOTE_INSN_DELETED);
- end = emit_note (NOTE_INSN_BLOCK_END);
- if (cfun->x_whole_function_mode_p)
- NOTE_BLOCK (end) = block;
- fixup->context = block;
- end_sequence ();
- emit_insn_after (start, original_before_jump);
- }
-
- fixup->block_start_count = current_block_start_count;
- fixup->stack_level = 0;
- fixup->cleanup_list_list
- = ((block->data.block.outer_cleanups
- || block->data.block.cleanups)
- ? tree_cons (NULL_TREE, block->data.block.cleanups,
- block->data.block.outer_cleanups)
- : 0);
- fixup->next = goto_fixup_chain;
- goto_fixup_chain = fixup;
- }
-
- return block != 0;
-}
-\f
-/* Expand any needed fixups in the outputmost binding level of the
- function. FIRST_INSN is the first insn in the function. */
-
-void
-expand_fixups (rtx first_insn)
-{
- fixup_gotos (NULL, NULL_RTX, NULL_TREE, first_insn, 0);
-}
-
-/* When exiting a binding contour, process all pending gotos requiring fixups.
- THISBLOCK is the structure that describes the block being exited.
- STACK_LEVEL is the rtx for the stack level to restore exiting this contour.
- CLEANUP_LIST is a list of expressions to evaluate on exiting this contour.
- FIRST_INSN is the insn that began this contour.
-
- Gotos that jump out of this contour must restore the
- stack level and do the cleanups before actually jumping.
-
- DONT_JUMP_IN positive means report error if there is a jump into this
- contour from before the beginning of the contour. This is also done if
- STACK_LEVEL is nonzero unless DONT_JUMP_IN is negative. */
-
-static void
-fixup_gotos (struct nesting *thisblock, rtx stack_level,
- tree cleanup_list, rtx first_insn, int dont_jump_in)
-{
- struct goto_fixup *f, *prev;
-
- /* F is the fixup we are considering; PREV is the previous one. */
- /* We run this loop in two passes so that cleanups of exited blocks
- are run first, and blocks that are exited are marked so
- afterwards. */
-
- for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
- {
- /* Test for a fixup that is inactive because it is already handled. */
- if (f->before_jump == 0)
- {
- /* Delete inactive fixup from the chain, if that is easy to do. */
- if (prev != 0)
- prev->next = f->next;
- }
- /* Has this fixup's target label been defined?
- If so, we can finalize it. */
- else if (PREV_INSN (f->target_rtl) != 0)
- {
- rtx cleanup_insns;
-
- /* If this fixup jumped into this contour from before the beginning
- of this contour, report an error. This code used to use
- the first non-label insn after f->target_rtl, but that's
- wrong since such can be added, by things like put_var_into_stack
- and have INSN_UIDs that are out of the range of the block. */
- /* ??? Bug: this does not detect jumping in through intermediate
- blocks that have stack levels or cleanups.
- It detects only a problem with the innermost block
- around the label. */
- if (f->target != 0
- && (dont_jump_in > 0 || (dont_jump_in == 0 && stack_level)
- || cleanup_list)
- && INSN_UID (first_insn) < INSN_UID (f->target_rtl)
- && INSN_UID (first_insn) > INSN_UID (f->before_jump)
- && ! DECL_ERROR_ISSUED (f->target))
- {
- error ("%Jlabel '%D' used before containing binding contour",
- f->target, f->target);
- /* Prevent multiple errors for one label. */
- DECL_ERROR_ISSUED (f->target) = 1;
- }
-
- /* We will expand the cleanups into a sequence of their own and
- then later on we will attach this new sequence to the insn
- stream just ahead of the actual jump insn. */
-
- start_sequence ();
-
- /* Temporarily restore the lexical context where we will
- logically be inserting the fixup code. We do this for the
- sake of getting the debugging information right. */
-
- lang_hooks.decls.pushlevel (0);
- lang_hooks.decls.set_block (f->context);
-
- /* Expand the cleanups for blocks this jump exits. */
- if (f->cleanup_list_list)
- {
- tree lists;
- for (lists = f->cleanup_list_list; lists; lists = TREE_CHAIN (lists))
- /* Marked elements correspond to blocks that have been closed.
- Do their cleanups. */
- if (TREE_ADDRESSABLE (lists)
- && TREE_VALUE (lists) != 0)
- {
- expand_cleanups (TREE_VALUE (lists), 1, 1);
- /* Pop any pushes done in the cleanups,
- in case function is about to return. */
- do_pending_stack_adjust ();
- }
- }
-
- /* Restore stack level for the biggest contour that this
- jump jumps out of. */
- if (f->stack_level
- && ! (f->target_rtl == return_label
- && ((TREE_CODE (TREE_TYPE (current_function_decl))
- == FUNCTION_TYPE)
- && (TYPE_RETURNS_STACK_DEPRESSED
- (TREE_TYPE (current_function_decl))))))
- emit_stack_restore (SAVE_BLOCK, f->stack_level, f->before_jump);
-
- /* Finish up the sequence containing the insns which implement the
- necessary cleanups, and then attach that whole sequence to the
- insn stream just ahead of the actual jump insn. Attaching it
- at that point insures that any cleanups which are in fact
- implicit C++ object destructions (which must be executed upon
- leaving the block) appear (to the debugger) to be taking place
- in an area of the generated code where the object(s) being
- destructed are still "in scope". */
-
- cleanup_insns = get_insns ();
- lang_hooks.decls.poplevel (1, 0, 0);
-
- end_sequence ();
- emit_insn_after (cleanup_insns, f->before_jump);
-
- f->before_jump = 0;
- }
- }
-
- /* For any still-undefined labels, do the cleanups for this block now.
- We must do this now since items in the cleanup list may go out
- of scope when the block ends. */
- for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
- if (f->before_jump != 0
- && PREV_INSN (f->target_rtl) == 0
- /* Label has still not appeared. If we are exiting a block with
- a stack level to restore, that started before the fixup,
- mark this stack level as needing restoration
- when the fixup is later finalized. */
- && thisblock != 0
- /* Note: if THISBLOCK == 0 and we have a label that hasn't appeared, it
- means the label is undefined. That's erroneous, but possible. */
- && (thisblock->data.block.block_start_count
- <= f->block_start_count))
- {
- tree lists = f->cleanup_list_list;
- rtx cleanup_insns;
-
- for (; lists; lists = TREE_CHAIN (lists))
- /* If the following elt. corresponds to our containing block
- then the elt. must be for this block. */
- if (TREE_CHAIN (lists) == thisblock->data.block.outer_cleanups)
- {
- start_sequence ();
- lang_hooks.decls.pushlevel (0);
- lang_hooks.decls.set_block (f->context);
- expand_cleanups (TREE_VALUE (lists), 1, 1);
- do_pending_stack_adjust ();
- cleanup_insns = get_insns ();
- lang_hooks.decls.poplevel (1, 0, 0);
- end_sequence ();
- if (cleanup_insns != 0)
- f->before_jump
- = emit_insn_after (cleanup_insns, f->before_jump);
-
- f->cleanup_list_list = TREE_CHAIN (lists);
- }
-
- if (stack_level)
- f->stack_level = stack_level;
- }
+ emit_jump (label_rtx (label));
}
\f
/* Return the number of times character C occurs in string S. */
MEM_VOLATILE_P (body) = vol;
emit_insn (body);
-
- clear_last_expr ();
}
/* Parse the output constraint pointed to by *CONSTRAINT_P. It is the
}
}
- clear_last_expr ();
-
/* First pass over inputs and outputs checks validity and sets
mark_addressable if needed. */
&& (allows_mem
|| is_inout
|| (DECL_P (val)
- && GET_CODE (DECL_RTL (val)) == REG
+ && REG_P (DECL_RTL (val))
&& GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))))
lang_hooks.mark_addressable (val);
if ((TREE_CODE (val) == INDIRECT_REF
&& allows_mem)
|| (DECL_P (val)
- && (allows_mem || GET_CODE (DECL_RTL (val)) == REG)
- && ! (GET_CODE (DECL_RTL (val)) == REG
+ && (allows_mem || REG_P (DECL_RTL (val)))
+ && ! (REG_P (DECL_RTL (val))
&& GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
|| ! allows_reg
|| is_inout)
{
op = expand_expr (val, NULL_RTX, VOIDmode, EXPAND_WRITE);
- if (GET_CODE (op) == MEM)
+ if (MEM_P (op))
op = validize_mem (op);
- if (! allows_reg && GET_CODE (op) != MEM)
+ if (! allows_reg && !MEM_P (op))
error ("output number %d not directly addressable", i);
- if ((! allows_mem && GET_CODE (op) == MEM)
+ if ((! allows_mem && MEM_P (op))
|| GET_CODE (op) == CONCAT)
{
- real_output_rtx[i] = protect_from_queue (op, 1);
+ real_output_rtx[i] = op;
op = gen_reg_rtx (GET_MODE (op));
if (is_inout)
emit_move_insn (op, real_output_rtx[i]);
: GET_MODE (output_rtx[0])),
TREE_STRING_POINTER (string),
empty_string, 0, argvec, constraintvec,
- locus.file, locus.line);
+ locus);
MEM_VOLATILE_P (body) = vol;
/* Never pass a CONCAT to an ASM. */
if (GET_CODE (op) == CONCAT)
op = force_reg (GET_MODE (op), op);
- else if (GET_CODE (op) == MEM)
+ else if (MEM_P (op))
op = validize_mem (op);
if (asm_operand_ok (op, constraint) <= 0)
else if (!allows_mem)
warning ("asm operand %d probably doesn't match constraints",
i + noutputs);
- else if (GET_CODE (op) == MEM)
+ else if (MEM_P (op))
{
/* We won't recognize either volatile memory or memory
with a queued address as available a memory_operand
else
op = force_reg (TYPE_MODE (type), op);
}
- if (GET_CODE (op) == REG
+ if (REG_P (op)
|| GET_CODE (op) == SUBREG
- || GET_CODE (op) == ADDRESSOF
|| GET_CODE (op) == CONCAT)
{
tree qual_type = build_qualified_type (type,
generating_concat_p = 0;
- for (i = 0; i < ninputs - ninout; i++)
- ASM_OPERANDS_INPUT (body, i)
- = protect_from_queue (ASM_OPERANDS_INPUT (body, i), 0);
-
- for (i = 0; i < noutputs; i++)
- output_rtx[i] = protect_from_queue (output_rtx[i], 1);
-
/* For in-out operands, copy output rtx to input rtx. */
for (i = 0; i < ninout; i++)
{
(GET_MODE (output_rtx[i]),
TREE_STRING_POINTER (string),
constraints[i], i, argvec, constraintvec,
- locus.file, locus.line));
+ locus));
MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
}
TREE_VALUE (tail) = o[i];
}
}
-
- /* Those MODIFY_EXPRs could do autoincrements. */
- emit_queue ();
}
/* A subroutine of expand_asm_operands. Check that all operands have
return p;
}
\f
-/* Generate RTL to evaluate the expression EXP
- and remember it in case this is the VALUE in a ({... VALUE; }) constr.
- Provided just for backward-compatibility. expand_expr_stmt_value()
- should be used for new code. */
+/* Generate RTL to evaluate the expression EXP. */
void
expand_expr_stmt (tree exp)
{
- expand_expr_stmt_value (exp, -1, 1);
-}
-
-/* Generate RTL to evaluate the expression EXP. WANT_VALUE tells
- whether to (1) save the value of the expression, (0) discard it or
- (-1) use expr_stmts_for_value to tell. The use of -1 is
- deprecated, and retained only for backward compatibility. */
-
-void
-expand_expr_stmt_value (tree exp, int want_value, int maybe_last)
-{
rtx value;
tree type;
- rtx alt_rtl = NULL;
-
- if (want_value == -1)
- want_value = expr_stmts_for_value != 0;
-
- /* If -Wextra, warn about statements with no side effects,
- except for an explicit cast to void (e.g. for assert()), and
- except for last statement in ({...}) where they may be useful. */
- if (! want_value
- && (expr_stmts_for_value == 0 || ! maybe_last)
- && exp != error_mark_node
- && warn_unused_value)
- {
- if (TREE_SIDE_EFFECTS (exp))
- warn_if_unused_value (exp);
- else if (!VOID_TYPE_P (TREE_TYPE (exp)) && !TREE_NO_WARNING (exp))
- warning ("%Hstatement with no effect", &emit_locus);
- }
-
- /* If EXP is of function type and we are expanding statements for
- value, convert it to pointer-to-function. */
- if (want_value && TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE)
- exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
- /* The call to `expand_expr' could cause last_expr_type and
- last_expr_value to get reset. Therefore, we set last_expr_value
- and last_expr_type *after* calling expand_expr. */
- value = expand_expr_real (exp, want_value ? NULL_RTX : const0_rtx,
- VOIDmode, 0, &alt_rtl);
+ value = expand_expr (exp, const0_rtx, VOIDmode, 0);
type = TREE_TYPE (exp);
/* If all we do is reference a volatile value in memory,
copy it to a register to be sure it is actually touched. */
- if (value && GET_CODE (value) == MEM && TREE_THIS_VOLATILE (exp))
+ if (value && MEM_P (value) && TREE_THIS_VOLATILE (exp))
{
if (TYPE_MODE (type) == VOIDmode)
;
}
}
- /* If this expression is part of a ({...}) and is in memory, we may have
- to preserve temporaries. */
- preserve_temp_slots (value);
-
- /* Free any temporaries used to evaluate this expression. Any temporary
- used as a result of this expression will already have been preserved
- above. */
+ /* Free any temporaries used to evaluate this expression. */
free_temp_slots ();
-
- if (want_value)
- {
- last_expr_value = value;
- last_expr_alt_rtl = alt_rtl;
- last_expr_type = type;
- }
-
- emit_queue ();
}
/* Warn if EXP contains any computations whose results are not used.
- Return 1 if a warning is printed; 0 otherwise. */
+ Return 1 if a warning is printed; 0 otherwise. LOCUS is the
+ (potential) location of the expression. */
int
-warn_if_unused_value (tree exp)
+warn_if_unused_value (tree exp, location_t locus)
{
+ restart:
if (TREE_USED (exp))
return 0;
if (VOID_TYPE_P (TREE_TYPE (exp)))
return 0;
+ if (EXPR_HAS_LOCATION (exp))
+ locus = EXPR_LOCATION (exp);
+
switch (TREE_CODE (exp))
{
case PREINCREMENT_EXPR:
case INIT_EXPR:
case TARGET_EXPR:
case CALL_EXPR:
- case RTL_EXPR:
case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
case EXIT_EXPR:
case BIND_EXPR:
/* For a binding, warn if no side effect within it. */
- return warn_if_unused_value (TREE_OPERAND (exp, 1));
+ exp = BIND_EXPR_BODY (exp);
+ goto restart;
case SAVE_EXPR:
- return warn_if_unused_value (TREE_OPERAND (exp, 0));
+ exp = TREE_OPERAND (exp, 0);
+ goto restart;
case TRUTH_ORIF_EXPR:
case TRUTH_ANDIF_EXPR:
/* In && or ||, warn if 2nd operand has no side effect. */
- return warn_if_unused_value (TREE_OPERAND (exp, 1));
+ exp = TREE_OPERAND (exp, 1);
+ goto restart;
case COMPOUND_EXPR:
if (TREE_NO_WARNING (exp))
return 0;
- if (warn_if_unused_value (TREE_OPERAND (exp, 0)))
+ if (warn_if_unused_value (TREE_OPERAND (exp, 0), locus))
return 1;
/* Let people do `(foo (), 0)' without a warning. */
if (TREE_CONSTANT (TREE_OPERAND (exp, 1)))
return 0;
- return warn_if_unused_value (TREE_OPERAND (exp, 1));
+ exp = TREE_OPERAND (exp, 1);
+ goto restart;
case NOP_EXPR:
case CONVERT_EXPR:
/* Don't warn about automatic dereferencing of references, since
the user cannot control it. */
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
- return warn_if_unused_value (TREE_OPERAND (exp, 0));
+ {
+ exp = TREE_OPERAND (exp, 0);
+ goto restart;
+ }
/* Fall through. */
default:
if (TREE_SIDE_EFFECTS (exp))
return 0;
- warning ("%Hvalue computed is not used", &emit_locus);
+ warning ("%Hvalue computed is not used", &locus);
return 1;
}
}
-
-/* Clear out the memory of the last expression evaluated. */
-
-void
-clear_last_expr (void)
-{
- last_expr_type = NULL_TREE;
- last_expr_value = NULL_RTX;
- last_expr_alt_rtl = NULL_RTX;
-}
-
-/* Begin a statement-expression, i.e., a series of statements which
- may return a value. Return the RTL_EXPR for this statement expr.
- The caller must save that value and pass it to
- expand_end_stmt_expr. If HAS_SCOPE is nonzero, temporaries created
- in the statement-expression are deallocated at the end of the
- expression. */
-
-tree
-expand_start_stmt_expr (int has_scope)
-{
- tree t;
-
- /* Make the RTL_EXPR node temporary, not momentary,
- so that rtl_expr_chain doesn't become garbage. */
- t = make_node (RTL_EXPR);
- do_pending_stack_adjust ();
- if (has_scope)
- start_sequence_for_rtl_expr (t);
- else
- start_sequence ();
- NO_DEFER_POP;
- expr_stmts_for_value++;
- return t;
-}
-
-/* Restore the previous state at the end of a statement that returns a value.
- Returns a tree node representing the statement's value and the
- insns to compute the value.
-
- The nodes of that expression have been freed by now, so we cannot use them.
- But we don't want to do that anyway; the expression has already been
- evaluated and now we just want to use the value. So generate a RTL_EXPR
- with the proper type and RTL value.
-
- If the last substatement was not an expression,
- return something with type `void'. */
-
-tree
-expand_end_stmt_expr (tree t)
-{
- OK_DEFER_POP;
-
- if (! last_expr_value || ! last_expr_type)
- {
- last_expr_value = const0_rtx;
- last_expr_alt_rtl = NULL_RTX;
- last_expr_type = void_type_node;
- }
- else if (GET_CODE (last_expr_value) != REG && ! CONSTANT_P (last_expr_value))
- /* Remove any possible QUEUED. */
- last_expr_value = protect_from_queue (last_expr_value, 0);
-
- emit_queue ();
-
- TREE_TYPE (t) = last_expr_type;
- RTL_EXPR_RTL (t) = last_expr_value;
- RTL_EXPR_ALT_RTL (t) = last_expr_alt_rtl;
- RTL_EXPR_SEQUENCE (t) = get_insns ();
-
- rtl_expr_chain = tree_cons (NULL_TREE, t, rtl_expr_chain);
-
- end_sequence ();
-
- /* Don't consider deleting this expr or containing exprs at tree level. */
- TREE_SIDE_EFFECTS (t) = 1;
- /* Propagate volatility of the actual RTL expr. */
- TREE_THIS_VOLATILE (t) = volatile_refs_p (last_expr_value);
-
- clear_last_expr ();
- expr_stmts_for_value--;
-
- return t;
-}
\f
/* Generate RTL for the start of an if-then. COND is the expression
whose truth should be tested.
emit_label (thiscond->data.cond.endif_label);
POPSTACK (cond_stack);
- clear_last_expr ();
}
\f
/* Return nonzero if we should preserve sub-expressions as separate
void
expand_null_return (void)
{
- rtx last_insn;
-
- last_insn = get_last_insn ();
-
/* If this function was declared to return a value, but we
didn't, clobber the return registers so that they are not
propagated live to the rest of the function. */
clobber_return_register ();
- expand_null_return_1 (last_insn);
+ expand_null_return_1 ();
}
/* Generate RTL to return directly from the current function.
void
expand_naked_return (void)
{
- rtx last_insn, end_label;
-
- last_insn = get_last_insn ();
- end_label = naked_return_label;
+ rtx end_label;
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
- clear_last_expr ();
+ end_label = naked_return_label;
if (end_label == 0)
end_label = naked_return_label = gen_label_rtx ();
- expand_goto_internal (NULL_TREE, end_label, last_insn);
+
+ emit_jump (end_label);
}
/* Try to guess whether the value of return means error code. */
shift = (GET_MODE_BITSIZE (GET_MODE (target))
- BITS_PER_UNIT * int_size_in_bytes (type));
if (shift > 0)
- val = expand_binop (GET_MODE (target), ashl_optab,
+ val = expand_shift (LSHIFT_EXPR, GET_MODE (target),
gen_lowpart (GET_MODE (target), val),
- GEN_INT (shift), target, 1, OPTAB_WIDEN);
+ build_int_2 (shift, 0), target, 1);
}
return val;
}
static void
expand_value_return (rtx val)
{
- rtx last_insn;
rtx return_reg;
enum br_predictor pred;
}
- last_insn = get_last_insn ();
return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
/* Copy the value to the return location
emit_move_insn (return_reg, val);
}
- expand_null_return_1 (last_insn);
+ expand_null_return_1 ();
}
-/* Output a return with no value. If LAST_INSN is nonzero,
- pretend that the return takes place after LAST_INSN. */
+/* Output a return with no value. */
static void
-expand_null_return_1 (rtx last_insn)
+expand_null_return_1 (void)
{
- rtx end_label = cleanup_label ? cleanup_label : return_label;
+ rtx end_label;
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
- clear_last_expr ();
+ end_label = return_label;
if (end_label == 0)
end_label = return_label = gen_label_rtx ();
- expand_goto_internal (NULL_TREE, end_label, last_insn);
+ emit_jump (end_label);
}
\f
/* Generate RTL to evaluate the expression RETVAL and return it
void
expand_return (tree retval)
{
- /* If there are any cleanups to be performed, then they will
- be inserted following LAST_INSN. It is desirable
- that the last_insn, for such purposes, should be the
- last insn before computing the return value. Otherwise, cleanups
- which call functions can clobber the return value. */
- /* ??? rms: I think that is erroneous, because in C++ it would
- run destructors on variables that might be used in the subsequent
- computation of the return value. */
- rtx last_insn = 0;
rtx result_rtl;
rtx val = 0;
tree retval_rhs;
if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE)
{
expand_expr (retval, NULL_RTX, VOIDmode, 0);
- emit_queue ();
expand_null_return ();
return;
}
}
else if (TREE_CODE (retval) == RESULT_DECL)
retval_rhs = retval;
- else if ((TREE_CODE (retval) == MODIFY_EXPR || TREE_CODE (retval) == INIT_EXPR)
+ else if ((TREE_CODE (retval) == MODIFY_EXPR
+ || TREE_CODE (retval) == INIT_EXPR)
&& TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
retval_rhs = TREE_OPERAND (retval, 1);
else
retval_rhs = retval;
- last_insn = get_last_insn ();
-
- /* Distribute return down conditional expr if either of the sides
- may involve tail recursion (see test below). This enhances the number
- of tail recursions we see. Don't do this always since it can produce
- sub-optimal code in some cases and we distribute assignments into
- conditional expressions when it would help. */
-
- if (optimize && retval_rhs != 0
- && frame_offset == 0
- && TREE_CODE (retval_rhs) == COND_EXPR
- && (TREE_CODE (TREE_OPERAND (retval_rhs, 1)) == CALL_EXPR
- || TREE_CODE (TREE_OPERAND (retval_rhs, 2)) == CALL_EXPR))
- {
- rtx label = gen_label_rtx ();
- tree expr;
-
- do_jump (TREE_OPERAND (retval_rhs, 0), label, NULL_RTX);
- start_cleanup_deferral ();
- expr = build (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (current_function_decl)),
- DECL_RESULT (current_function_decl),
- TREE_OPERAND (retval_rhs, 1));
- TREE_SIDE_EFFECTS (expr) = 1;
- expand_return (expr);
- emit_label (label);
-
- expr = build (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (current_function_decl)),
- DECL_RESULT (current_function_decl),
- TREE_OPERAND (retval_rhs, 2));
- TREE_SIDE_EFFECTS (expr) = 1;
- expand_return (expr);
- end_cleanup_deferral ();
- return;
- }
-
result_rtl = DECL_RTL (DECL_RESULT (current_function_decl));
/* If the result is an aggregate that is being returned in one (or more)
copying a BLKmode value into registers. We could put this code in a
more general area (for use by everyone instead of just function
call/return), but until this feature is generally usable it is kept here
- (and in expand_call). The value must go into a pseudo in case there
- are cleanups that will clobber the real return register. */
+ (and in expand_call). */
if (retval_rhs != 0
&& TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode
- && GET_CODE (result_rtl) == REG)
+ && REG_P (result_rtl))
{
int i;
unsigned HOST_WIDE_INT bitpos, xbitpos;
store_bit_field (dst, bitsize, xbitpos % BITS_PER_WORD, word_mode,
extract_bit_field (src, bitsize,
bitpos % BITS_PER_WORD, 1,
- NULL_RTX, word_mode, word_mode,
- BITS_PER_WORD),
- BITS_PER_WORD);
+ NULL_RTX, word_mode, word_mode));
}
tmpmode = GET_MODE (result_rtl);
result_reg_mode = tmpmode;
result_reg = gen_reg_rtx (result_reg_mode);
- emit_queue ();
for (i = 0; i < n_regs; i++)
emit_move_insn (operand_subword (result_reg, i, 0, result_reg_mode),
result_pseudos[i]);
}
else if (retval_rhs != 0
&& !VOID_TYPE_P (TREE_TYPE (retval_rhs))
- && (GET_CODE (result_rtl) == REG
+ && (REG_P (result_rtl)
|| (GET_CODE (result_rtl) == PARALLEL)))
{
/* Calculate the return value into a temporary (usually a pseudo
val = assign_temp (nt, 0, 0, 1);
val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
val = force_not_mem (val);
- emit_queue ();
- /* Return the calculated value, doing cleanups first. */
+ /* Return the calculated value. */
expand_value_return (shift_return_value (val));
}
else
{
- /* No cleanups or no hard reg used;
- calculate value into hard return reg. */
+ /* No hard reg used; calculate value into hard return reg. */
expand_expr (retval, const0_rtx, VOIDmode, 0);
- emit_queue ();
expand_value_return (result_rtl);
}
}
\f
-/* Attempt to optimize a potential tail recursion call into a goto.
- ARGUMENTS are the arguments to a CALL_EXPR; LAST_INSN indicates
- where to place the jump to the tail recursion label.
-
- Return TRUE if the call was optimized into a goto. */
-
-int
-optimize_tail_recursion (tree arguments, rtx last_insn)
-{
- /* Finish checking validity, and if valid emit code to set the
- argument variables for the new call. */
- if (tail_recursion_args (arguments, DECL_ARGUMENTS (current_function_decl)))
- {
- if (tail_recursion_label == 0)
- {
- tail_recursion_label = gen_label_rtx ();
- emit_label_after (tail_recursion_label,
- tail_recursion_reentry);
- }
- emit_queue ();
- expand_goto_internal (NULL_TREE, tail_recursion_label, last_insn);
- emit_barrier ();
- return 1;
- }
- return 0;
-}
-
-/* Emit code to alter this function's formal parms for a tail-recursive call.
- ACTUALS is a list of actual parameter expressions (chain of TREE_LISTs).
- FORMALS is the chain of decls of formals.
- Return 1 if this can be done;
- otherwise return 0 and do not emit any code. */
-
-static int
-tail_recursion_args (tree actuals, tree formals)
-{
- tree a = actuals, f = formals;
- int i;
- rtx *argvec;
-
- /* Check that number and types of actuals are compatible
- with the formals. This is not always true in valid C code.
- Also check that no formal needs to be addressable
- and that all formals are scalars. */
-
- /* Also count the args. */
-
- for (a = actuals, f = formals, i = 0; a && f; a = TREE_CHAIN (a), f = TREE_CHAIN (f), i++)
- {
- if (!lang_hooks.types_compatible_p (TREE_TYPE (TREE_VALUE (a)),
- TREE_TYPE (f)))
- return 0;
- if (GET_CODE (DECL_RTL (f)) != REG || DECL_MODE (f) == BLKmode)
- return 0;
- }
- if (a != 0 || f != 0)
- return 0;
-
- /* Compute all the actuals. */
-
- argvec = alloca (i * sizeof (rtx));
-
- for (a = actuals, i = 0; a; a = TREE_CHAIN (a), i++)
- argvec[i] = expand_expr (TREE_VALUE (a), NULL_RTX, VOIDmode, 0);
-
- /* Find which actual values refer to current values of previous formals.
- Copy each of them now, before any formal is changed. */
-
- for (a = actuals, i = 0; a; a = TREE_CHAIN (a), i++)
- {
- int copy = 0;
- int j;
- for (f = formals, j = 0; j < i; f = TREE_CHAIN (f), j++)
- if (reg_mentioned_p (DECL_RTL (f), argvec[i]))
- {
- copy = 1;
- break;
- }
- if (copy)
- argvec[i] = copy_to_reg (argvec[i]);
- }
-
- /* Store the values of the actuals into the formals. */
-
- for (f = formals, a = actuals, i = 0; f;
- f = TREE_CHAIN (f), a = TREE_CHAIN (a), i++)
- {
- if (GET_MODE (DECL_RTL (f)) == GET_MODE (argvec[i]))
- emit_move_insn (DECL_RTL (f), argvec[i]);
- else
- {
- rtx tmp = argvec[i];
- int unsignedp = TYPE_UNSIGNED (TREE_TYPE (TREE_VALUE (a)));
- promote_mode(TREE_TYPE (TREE_VALUE (a)), GET_MODE (tmp),
- &unsignedp, 0);
- if (DECL_MODE (f) != GET_MODE (DECL_RTL (f)))
- {
- tmp = gen_reg_rtx (DECL_MODE (f));
- convert_move (tmp, argvec[i], unsignedp);
- }
- convert_move (DECL_RTL (f), tmp, unsignedp);
- }
- }
-
- free_temp_slots ();
- return 1;
-}
-\f
/* Generate the RTL code for entering a binding contour.
The variables are declared one by one, by calls to `expand_decl'.
abort ();
/* Create a note to mark the beginning of the block. */
- if (block_flag && !cfun->dont_emit_block_notes)
- {
- note = emit_note (NOTE_INSN_BLOCK_BEG);
- NOTE_BLOCK (note) = block;
- }
- else
- note = emit_note (NOTE_INSN_DELETED);
+ note = emit_note (NOTE_INSN_DELETED);
/* Make an entry on block_stack for the block we are entering. */
thisblock->next = block_stack;
thisblock->all = nesting_stack;
thisblock->depth = ++nesting_depth;
- thisblock->data.block.stack_level = 0;
- thisblock->data.block.cleanups = 0;
- thisblock->data.block.exception_region = 0;
thisblock->data.block.block_target_temp_slot_level = target_temp_slot_level;
thisblock->data.block.conditional_code = 0;
never the last instruction. */
emit_note (NOTE_INSN_DELETED);
- if (block_stack
- && !(block_stack->data.block.cleanups == NULL_TREE
- && block_stack->data.block.outer_cleanups == NULL_TREE))
- thisblock->data.block.outer_cleanups
- = tree_cons (NULL_TREE, block_stack->data.block.cleanups,
- block_stack->data.block.outer_cleanups);
- else
- thisblock->data.block.outer_cleanups = 0;
- thisblock->data.block.label_chain = 0;
- thisblock->data.block.innermost_stack_block = stack_block_stack;
thisblock->data.block.first_insn = note;
thisblock->data.block.block_start_count = ++current_block_start_count;
thisblock->exit_label = exit_flag ? gen_label_rtx () : 0;
return 0;
}
-/* True if we are currently emitting insns in an area of output code
- that is controlled by a conditional expression. This is used by
- the cleanup handling code to generate conditional cleanup actions. */
-
-int
-conditional_context (void)
-{
- return block_stack && block_stack->data.block.conditional_code;
-}
-
/* Return an opaque pointer to the current nesting level, so frontend code
can check its own sanity. */
labels (because the front end does that). */
void
-expand_end_bindings (tree vars, int mark_ends, int dont_jump_in)
+expand_end_bindings (tree vars, int mark_ends ATTRIBUTE_UNUSED,
+ int dont_jump_in ATTRIBUTE_UNUSED)
{
struct nesting *thisblock = block_stack;
emit_label (thisblock->exit_label);
}
- /* Don't allow jumping into a block that has a stack level.
- Cleanups are allowed, though. */
- if (dont_jump_in > 0
- || (dont_jump_in == 0 && thisblock->data.block.stack_level != 0))
- {
- struct label_chain *chain;
+ /* Mark the beginning and end of the scope if requested. */
- /* Any labels in this block are no longer valid to go to.
- Mark them to cause an error message. */
- for (chain = thisblock->data.block.label_chain; chain; chain = chain->next)
- {
- DECL_TOO_LATE (chain->label) = 1;
- /* If any goto without a fixup came to this label,
- that must be an error, because gotos without fixups
- come from outside all saved stack-levels. */
- if (TREE_ADDRESSABLE (chain->label))
- error ("%Jlabel '%D' used before containing binding contour",
- chain->label, chain->label);
- }
- }
-
- /* Restore stack level in effect before the block
- (only if variable-size objects allocated). */
- /* Perform any cleanups associated with the block. */
-
- if (thisblock->data.block.stack_level != 0
- || thisblock->data.block.cleanups != 0)
- {
- int reachable;
- rtx insn;
-
- /* Don't let cleanups affect ({...}) constructs. */
- int old_expr_stmts_for_value = expr_stmts_for_value;
- rtx old_last_expr_value = last_expr_value;
- rtx old_last_expr_alt_rtl = last_expr_alt_rtl;
- tree old_last_expr_type = last_expr_type;
- expr_stmts_for_value = 0;
-
- /* Only clean up here if this point can actually be reached. */
- insn = get_last_insn ();
- if (GET_CODE (insn) == NOTE)
- insn = prev_nonnote_insn (insn);
- reachable = (! insn || GET_CODE (insn) != BARRIER);
-
- /* Do the cleanups. */
- expand_cleanups (thisblock->data.block.cleanups, 0, reachable);
- if (reachable)
- do_pending_stack_adjust ();
-
- expr_stmts_for_value = old_expr_stmts_for_value;
- last_expr_value = old_last_expr_value;
- last_expr_alt_rtl = old_last_expr_alt_rtl;
- last_expr_type = old_last_expr_type;
-
- /* Restore the stack level. */
-
- if (reachable && thisblock->data.block.stack_level != 0)
- {
- emit_stack_restore (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
- thisblock->data.block.stack_level, NULL_RTX);
- if (cfun->nonlocal_goto_save_area)
- update_nonlocal_goto_save_area ();
- }
-
- /* Any gotos out of this block must also do these things.
- Also report any gotos with fixups that came to labels in this
- level. */
- fixup_gotos (thisblock,
- thisblock->data.block.stack_level,
- thisblock->data.block.cleanups,
- thisblock->data.block.first_insn,
- dont_jump_in);
- }
-
- /* Mark the beginning and end of the scope if requested.
- We do this now, after running cleanups on the variables
- just going out of scope, so they are in scope for their cleanups. */
-
- if (mark_ends && !cfun->dont_emit_block_notes)
- {
- rtx note = emit_note (NOTE_INSN_BLOCK_END);
- NOTE_BLOCK (note) = NOTE_BLOCK (thisblock->data.block.first_insn);
- }
- else
- /* Get rid of the beginning-mark if we don't make an end-mark. */
- NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED;
+ /* Get rid of the beginning-mark if we don't make an end-mark. */
+ NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED;
/* Restore the temporary level of TARGET_EXPRs. */
target_temp_slot_level = thisblock->data.block.block_target_temp_slot_level;
/* Restore block_stack level for containing block. */
- stack_block_stack = thisblock->data.block.innermost_stack_block;
POPSTACK (block_stack);
/* Pop the stack slot nesting and free any slots at this level. */
pop_temp_slots ();
}
\f
-/* Generate code to save the stack pointer at the start of the current block
- and set up to restore it on exit. */
-
-void
-save_stack_pointer (void)
-{
- struct nesting *thisblock = block_stack;
-
- if (thisblock->data.block.stack_level == 0)
- {
- emit_stack_save (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
- &thisblock->data.block.stack_level,
- thisblock->data.block.first_insn);
- stack_block_stack = thisblock;
- }
-}
-\f
/* Generate RTL for the automatic variable declaration DECL.
(Other kinds of declarations are simply ignored if seen here.) */
set_mem_attributes (x, decl, 1);
SET_DECL_RTL (decl, x);
}
- else if (DECL_MODE (decl) != BLKmode
- /* If -ffloat-store, don't put explicit float vars
- into regs. */
- && !(flag_float_store
- && TREE_CODE (type) == REAL_TYPE)
- && ! TREE_THIS_VOLATILE (decl)
- && ! DECL_NONLOCAL (decl)
- && (DECL_REGISTER (decl) || DECL_ARTIFICIAL (decl) || optimize))
+ else if (use_register_for_decl (decl))
{
/* Automatic variable that can go in a register. */
int unsignedp = TYPE_UNSIGNED (type);
}
maybe_set_unchanging (DECL_RTL (decl), decl);
-
- /* If something wants our address, try to use ADDRESSOF. */
- if (TREE_ADDRESSABLE (decl))
- put_var_into_stack (decl, /*rescan=*/false);
}
else if (TREE_CODE (DECL_SIZE_UNIT (decl)) == INTEGER_CST
to the proper address. */
if (DECL_RTL_SET_P (decl))
{
- if (GET_CODE (DECL_RTL (decl)) != MEM
- || GET_CODE (XEXP (DECL_RTL (decl), 0)) != REG)
+ if (!MEM_P (DECL_RTL (decl))
+ || !REG_P (XEXP (DECL_RTL (decl), 0)))
abort ();
oldaddr = XEXP (DECL_RTL (decl), 0);
}
/* Record the stack pointer on entry to block, if have
not already done so. */
do_pending_stack_adjust ();
- save_stack_pointer ();
/* Compute the variable's size, in bytes. This will expand any
needed SAVE_EXPRs for the first time. */
type = TREE_TYPE (var);
- /* In function-at-a-time mode, variable_size doesn't expand this,
- so do it now. */
- if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
- expand_expr (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
- const0_rtx, VOIDmode, 0);
-
/* Compute the variable's size, in bytes. */
size = expand_expr (t_size, NULL_RTX, VOIDmode, 0);
free_temp_slots ();
|| code == POINTER_TYPE || code == REFERENCE_TYPE)
expand_assignment (decl, convert (TREE_TYPE (decl), integer_zero_node),
0);
- emit_queue ();
}
else if (DECL_INITIAL (decl) && TREE_CODE (DECL_INITIAL (decl)) != TREE_LIST)
{
emit_line_note (DECL_SOURCE_LOCATION (decl));
expand_assignment (decl, DECL_INITIAL (decl), 0);
- emit_queue ();
}
/* Don't let the initialization count as "using" the variable. */
pop_temp_slots ();
}
-/* CLEANUP is an expression to be executed at exit from this binding contour;
- for example, in C++, it might call the destructor for this variable.
-
- We wrap CLEANUP in an UNSAVE_EXPR node, so that we can expand the
- CLEANUP multiple times, and have the correct semantics. This
- happens in exception handling, for gotos, returns, breaks that
- leave the current scope.
-
- If CLEANUP is nonzero and DECL is zero, we record a cleanup
- that is not associated with any particular variable. */
-
-int
-expand_decl_cleanup (tree decl, tree cleanup)
-{
- struct nesting *thisblock;
-
- /* Error if we are not in any block. */
- if (cfun == 0 || block_stack == 0)
- return 0;
-
- thisblock = block_stack;
-
- /* Record the cleanup if there is one. */
-
- if (cleanup != 0)
- {
- tree t;
- rtx seq;
- tree *cleanups = &thisblock->data.block.cleanups;
- int cond_context = conditional_context ();
-
- if (cond_context)
- {
- rtx flag = gen_reg_rtx (word_mode);
- rtx set_flag_0;
- tree cond;
-
- start_sequence ();
- emit_move_insn (flag, const0_rtx);
- set_flag_0 = get_insns ();
- end_sequence ();
-
- thisblock->data.block.last_unconditional_cleanup
- = emit_insn_after (set_flag_0,
- thisblock->data.block.last_unconditional_cleanup);
-
- emit_move_insn (flag, const1_rtx);
-
- cond = build_decl (VAR_DECL, NULL_TREE,
- lang_hooks.types.type_for_mode (word_mode, 1));
- SET_DECL_RTL (cond, flag);
-
- /* Conditionalize the cleanup. */
- cleanup = build (COND_EXPR, void_type_node,
- lang_hooks.truthvalue_conversion (cond),
- cleanup, integer_zero_node);
- cleanup = fold (cleanup);
-
- cleanups = &thisblock->data.block.cleanups;
- }
-
- cleanup = unsave_expr (cleanup);
-
- t = *cleanups = tree_cons (decl, cleanup, *cleanups);
-
- if (! cond_context)
- /* If this block has a cleanup, it belongs in stack_block_stack. */
- stack_block_stack = thisblock;
-
- if (cond_context)
- {
- start_sequence ();
- }
-
- if (! using_eh_for_cleanups_p)
- TREE_ADDRESSABLE (t) = 1;
- else
- expand_eh_region_start ();
-
- if (cond_context)
- {
- seq = get_insns ();
- end_sequence ();
- if (seq)
- thisblock->data.block.last_unconditional_cleanup
- = emit_insn_after (seq,
- thisblock->data.block.last_unconditional_cleanup);
- }
- else
- {
- thisblock->data.block.last_unconditional_cleanup
- = get_last_insn ();
- /* When we insert instructions after the last unconditional cleanup,
- we don't adjust last_insn. That means that a later add_insn will
- clobber the instructions we've just added. The easiest way to
- fix this is to just insert another instruction here, so that the
- instructions inserted after the last unconditional cleanup are
- never the last instruction. */
- emit_note (NOTE_INSN_DELETED);
- }
- }
- return 1;
-}
-
-/* Like expand_decl_cleanup, but maybe only run the cleanup if an exception
- is thrown. */
-
-int
-expand_decl_cleanup_eh (tree decl, tree cleanup, int eh_only)
-{
- int ret = expand_decl_cleanup (decl, cleanup);
- if (cleanup && ret)
- {
- tree node = block_stack->data.block.cleanups;
- CLEANUP_EH_ONLY (node) = eh_only;
- }
- return ret;
-}
\f
/* DECL is an anonymous union. CLEANUP is a cleanup for DECL.
DECL_ELTS is the list of elements that belong to DECL's type.
In each, the TREE_VALUE is a VAR_DECL, and the TREE_PURPOSE a cleanup. */
void
-expand_anon_union_decl (tree decl, tree cleanup, tree decl_elts)
+expand_anon_union_decl (tree decl, tree cleanup ATTRIBUTE_UNUSED,
+ tree decl_elts)
{
- struct nesting *thisblock = cfun == 0 ? 0 : block_stack;
rtx x;
tree t;
}
expand_decl (decl);
- expand_decl_cleanup (decl, cleanup);
x = DECL_RTL (decl);
/* Go through the elements, assigning RTL to each. */
for (t = decl_elts; t; t = TREE_CHAIN (t))
{
tree decl_elt = TREE_VALUE (t);
- tree cleanup_elt = TREE_PURPOSE (t);
enum machine_mode mode = TYPE_MODE (TREE_TYPE (decl_elt));
/* If any of the elements are addressable, so is the entire
/* (SUBREG (MEM ...)) at RTL generation time is invalid, so we
instead create a new MEM rtx with the proper mode. */
- if (GET_CODE (x) == MEM)
+ if (MEM_P (x))
{
if (mode == GET_MODE (x))
SET_DECL_RTL (decl_elt, x);
else
SET_DECL_RTL (decl_elt, adjust_address_nv (x, mode, 0));
}
- else if (GET_CODE (x) == REG)
+ else if (REG_P (x))
{
if (mode == GET_MODE (x))
SET_DECL_RTL (decl_elt, x);
}
else
abort ();
-
- /* Record the cleanup if there is one. */
-
- if (cleanup != 0)
- thisblock->data.block.cleanups
- = tree_cons (decl_elt, cleanup_elt,
- thisblock->data.block.cleanups);
}
}
\f
-/* Expand a list of cleanups LIST.
- Elements may be expressions or may be nested lists.
-
- If IN_FIXUP is nonzero, we are generating this cleanup for a fixup
- goto and handle protection regions specially in that case.
-
- If REACHABLE, we emit code, otherwise just inform the exception handling
- code about this finalization. */
-
-static void
-expand_cleanups (tree list, int in_fixup, int reachable)
-{
- tree tail;
- for (tail = list; tail; tail = TREE_CHAIN (tail))
- if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
- expand_cleanups (TREE_VALUE (tail), in_fixup, reachable);
- else
- {
- if (! in_fixup && using_eh_for_cleanups_p)
- expand_eh_region_end_cleanup (TREE_VALUE (tail));
-
- if (reachable && !CLEANUP_EH_ONLY (tail))
- {
- /* Cleanups may be run multiple times. For example,
- when exiting a binding contour, we expand the
- cleanups associated with that contour. When a goto
- within that binding contour has a target outside that
- contour, it will expand all cleanups from its scope to
- the target. Though the cleanups are expanded multiple
- times, the control paths are non-overlapping so the
- cleanups will not be executed twice. */
-
- /* We may need to protect from outer cleanups. */
- if (in_fixup && using_eh_for_cleanups_p)
- {
- expand_eh_region_start ();
-
- expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
-
- expand_eh_region_end_fixup (TREE_VALUE (tail));
- }
- else
- expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
-
- free_temp_slots ();
- }
- }
-}
-
-/* Mark when the context we are emitting RTL for as a conditional
- context, so that any cleanup actions we register with
- expand_decl_init will be properly conditionalized when those
- cleanup actions are later performed. Must be called before any
- expression (tree) is expanded that is within a conditional context. */
-
-void
-start_cleanup_deferral (void)
-{
- /* block_stack can be NULL if we are inside the parameter list. It is
- OK to do nothing, because cleanups aren't possible here. */
- if (block_stack)
- ++block_stack->data.block.conditional_code;
-}
-
-/* Mark the end of a conditional region of code. Because cleanup
- deferrals may be nested, we may still be in a conditional region
- after we end the currently deferred cleanups, only after we end all
- deferred cleanups, are we back in unconditional code. */
-
-void
-end_cleanup_deferral (void)
-{
- /* block_stack can be NULL if we are inside the parameter list. It is
- OK to do nothing, because cleanups aren't possible here. */
- if (block_stack)
- --block_stack->data.block.conditional_code;
-}
-
-tree
-last_cleanup_this_contour (void)
-{
- if (block_stack == 0)
- return 0;
-
- return block_stack->data.block.cleanups;
-}
-
-
-/* Return nonzero if any containing block has a stack level or
- cleanups. */
-
-int
-containing_blocks_have_cleanups_or_stack_level (void)
-{
- struct nesting *block;
-
- for (block = block_stack; block; block = block->next)
- if (block->data.block.stack_level != 0
- || block->data.block.cleanups != 0)
- return 1;
-
- return 0;
-}
-
-/* Return 1 if there are any pending cleanups at this point.
- Check the current contour as well as contours that enclose
- the current contour. */
-
-int
-any_pending_cleanups (void)
-{
- struct nesting *block;
-
- if (cfun == NULL || cfun->stmt == NULL || block_stack == 0)
- return 0;
-
- if (block_stack->data.block.cleanups != NULL)
- return 1;
-
- if (block_stack->data.block.outer_cleanups == 0)
- return 0;
-
- for (block = block_stack->next; block; block = block->next)
- if (block->data.block.cleanups != 0)
- return 1;
-
- return 0;
-}
-\f
/* Enter a case (Pascal) or switch (C) statement.
Push a block onto case_stack and nesting_stack
to accumulate the case-labels that are seen
nesting_stack = thiscase;
do_pending_stack_adjust ();
- emit_queue ();
/* Make sure case_stmt.start points to something that won't
need any transformation before expand_end_case. */
- if (GET_CODE (get_last_insn ()) != NOTE)
+ if (!NOTE_P (get_last_insn ()))
emit_note (NOTE_INSN_DELETED);
thiscase->data.case_stmt.start = get_last_insn ();
-
- start_cleanup_deferral ();
-}
-\f
-static void
-check_seenlabel (void)
-{
- /* If this is the first label, warn if any insns have been emitted. */
- if (case_stack->data.case_stmt.line_number_status >= 0)
- {
- rtx insn;
-
- restore_line_number_status
- (case_stack->data.case_stmt.line_number_status);
- case_stack->data.case_stmt.line_number_status = -1;
-
- for (insn = case_stack->data.case_stmt.start;
- insn;
- insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == CODE_LABEL)
- break;
- if (GET_CODE (insn) != NOTE
- && (GET_CODE (insn) != INSN || GET_CODE (PATTERN (insn)) != USE))
- {
- do
- insn = PREV_INSN (insn);
- while (insn && (GET_CODE (insn) != NOTE || NOTE_LINE_NUMBER (insn) < 0));
-
- /* If insn is zero, then there must have been a syntax error. */
- if (insn)
- {
- location_t locus;
- locus.file = NOTE_SOURCE_FILE (insn);
- locus.line = NOTE_LINE_NUMBER (insn);
- warning ("%Hunreachable code at beginning of %s", &locus,
- case_stack->data.case_stmt.printname);
- }
- break;
- }
- }
- }
}
/* Accumulate one case or default label inside a case or switch statement.
If VALUE is a duplicate or overlaps, return 2 and do nothing
except store the (first) duplicate node in *DUPLICATE.
If VALUE is out of range, return 3 and do nothing.
- If we are jumping into the scope of a cleanup or var-sized array, return 5.
Return 0 on success.
Extended to handle range statements. */
if (! (case_stack && case_stack->data.case_stmt.start))
return 1;
- if (stack_block_stack
- && stack_block_stack->depth > case_stack->depth)
- return 5;
-
index_type = TREE_TYPE (case_stack->data.case_stmt.index_expr);
nominal_type = case_stack->data.case_stmt.nominal_type;
if (value != 0)
value = (*converter) (nominal_type, value);
- check_seenlabel ();
-
/* Fail if this value is out of range for the actual type of the index
(which may be narrower than NOMINAL_TYPE). */
if (value != 0
if (! (case_stack && case_stack->data.case_stmt.start))
return 1;
- if (stack_block_stack
- && stack_block_stack->depth > case_stack->depth)
- return 5;
-
index_type = TREE_TYPE (case_stack->data.case_stmt.index_expr);
nominal_type = case_stack->data.case_stmt.nominal_type;
if (index_type == error_mark_node)
return 0;
- check_seenlabel ();
-
/* Convert VALUEs to type in which the comparisons are nominally done
and replace any unspecified value with the corresponding bound. */
if (value1 == 0)
convert (index_type, index_expr),
convert (index_type, minval)));
index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
- emit_queue ();
- index = protect_from_queue (index, 0);
do_pending_stack_adjust ();
mode = TYPE_MODE (index_type);
do_pending_stack_adjust ();
- /* This might get a spurious warning in the presence of a syntax error;
- it could be fixed by moving the call to check_seenlabel after the
- check for error_mark_node, and copying the code of check_seenlabel that
- deals with case_stack->data.case_stmt.line_number_status /
- restore_line_number_status in front of the call to end_cleanup_deferral;
- However, this might miss some useful warnings in the presence of
- non-syntax errors. */
- check_seenlabel ();
-
/* An ERROR_MARK occurs for various reasons including invalid data type. */
if (index_type != error_mark_node)
{
if (count != 0)
range = fold (build (MINUS_EXPR, index_type, maxval, minval));
- end_cleanup_deferral ();
-
if (count == 0)
{
expand_expr (index_expr, const0_rtx, VOIDmode, 0);
- emit_queue ();
emit_jump (default_label);
}
}
}
- emit_queue ();
do_pending_stack_adjust ();
- index = protect_from_queue (index, 0);
- if (GET_CODE (index) == MEM)
+ if (MEM_P (index))
index = copy_to_reg (index);
if (GET_CODE (index) == CONST_INT
|| TREE_CODE (index_expr) == INTEGER_CST)
reorder_insns (before_case, end,
thiscase->data.case_stmt.start);
}
- else
- end_cleanup_deferral ();
if (thiscase->exit_label && !exit_done)
emit_label (thiscase->exit_label);
static void
emit_jump_if_reachable (rtx label)
{
- if (GET_CODE (get_last_insn ()) != BARRIER)
+ if (!BARRIER_P (get_last_insn ()))
emit_jump (label);
}
\f