{
tree lo_index = TREE_OPERAND (index, 0);
tree hi_index = TREE_OPERAND (index, 1);
- rtx index_r, pos_rtx, loop_end;
- struct nesting *loop;
+ rtx index_r, pos_rtx;
HOST_WIDE_INT lo, hi, count;
tree position;
}
else
{
- expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
- loop_end = gen_label_rtx ();
+ rtx loop_start = gen_label_rtx ();
+ rtx loop_end = gen_label_rtx ();
+ tree exit_cond;
+ expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
unsignedp = TYPE_UNSIGNED (domain);
index = build_decl (VAR_DECL, NULL_TREE, domain);
emit_queue ();
}
store_expr (lo_index, index_r, 0);
- loop = expand_start_loop (0);
+
+ /* Build the head of the loop. */
+ do_pending_stack_adjust ();
+ emit_queue ();
+ emit_label (loop_start);
/* Assign value to element index. */
position
else
store_expr (value, xtarget, 0);
- expand_exit_loop_if_false (loop,
- build (LT_EXPR, integer_type_node,
- index, hi_index));
+ /* Generate a conditional jump to exit the loop. */
+ exit_cond = build (LT_EXPR, integer_type_node,
+ index, hi_index);
+ jumpif (exit_cond, loop_end);
+ /* Update the loop counter, and jump to the head of
+ the loop. */
expand_increment (build (PREINCREMENT_EXPR,
TREE_TYPE (index),
index, integer_one_node), 0, 0);
- expand_end_loop ();
+ emit_jump (loop_start);
+
+ /* Build the end of the loop. */
emit_label (loop_end);
}
}
expand_computed_goto (TREE_OPERAND (exp, 0));
return const0_rtx;
+ /* These are lowered during gimplification, so we should never ever
+ see them here. */
+ case LOOP_EXPR:
case EXIT_EXPR:
- expand_exit_loop_if_false (NULL,
- invert_truthvalue (TREE_OPERAND (exp, 0)));
- return const0_rtx;
+ abort ();
case LABELED_BLOCK_EXPR:
if (LABELED_BLOCK_BODY (exp))
expand_goto (LABELED_BLOCK_LABEL (EXIT_BLOCK_LABELED_BLOCK (exp)));
return const0_rtx;
- case LOOP_EXPR:
- push_temp_slots ();
- expand_start_loop (1);
- expand_expr_stmt_value (TREE_OPERAND (exp, 0), 0, 1);
- expand_end_loop ();
- pop_temp_slots ();
-
- return const0_rtx;
-
case BIND_EXPR:
{
tree block = BIND_EXPR_BLOCK (exp);
The position of an entry on `nesting_stack' is in its `depth' field.
Each type of construct has its own individual stack.
- For example, loops have `loop_stack'. Each object points to the
+ For example, loops have `cond_stack'. Each object points to the
next object of the same type through the `next' field.
Some constructs are visible to `break' exit-statements and others
rtx exit_label;
enum nesting_desc {
COND_NESTING,
- LOOP_NESTING,
BLOCK_NESTING,
CASE_NESTING
} desc;
This may be the end of the if or the next else/elseif. */
rtx next_label;
} GTY ((tag ("COND_NESTING"))) cond;
- /* For loops. */
- struct nesting_loop
- {
- /* Label at the top of the loop; place to loop back to. */
- rtx start_label;
- /* Label at the end of the whole construct. */
- rtx end_label;
- /* Label for `continue' statement to jump to;
- this is in front of the stepper of the loop. */
- rtx continue_label;
- } GTY ((tag ("LOOP_NESTING"))) loop;
/* For variable binding contours. */
struct nesting_block
{
do { struct nesting *target = STACK; \
struct nesting *this; \
do { this = nesting_stack; \
- if (loop_stack == this) \
- loop_stack = loop_stack->next; \
if (cond_stack == this) \
cond_stack = cond_stack->next; \
if (block_stack == this) \
/* Chain of all pending conditional statements. */
struct nesting * x_cond_stack;
- /* Chain of all pending loops. */
- struct nesting * x_loop_stack;
-
/* Chain of all pending case or switch statements. */
struct nesting * x_case_stack;
#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 loop_stack (cfun->stmt->x_loop_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)
&& (rtl_label == cond_stack->data.cond.endif_label
|| rtl_label == cond_stack->data.cond.next_label))
end_block = cond_stack;
- /* If we are in a loop, recognize certain labels which
- are likely targets. This reduces the number of fixups
- we need to create. */
- else if (loop_stack
- && (rtl_label == loop_stack->data.loop.start_label
- || rtl_label == loop_stack->data.loop.end_label
- || rtl_label == loop_stack->data.loop.continue_label))
- end_block = loop_stack;
else
end_block = 0;
`SUPERBLOCK') of any other BLOCK nodes which we might create
later on when we are expanding the fixup code.
- Note that optimization passes (including expand_end_loop)
- might move the *_BLOCK notes away, so we use a NOTE_INSN_DELETED
- as a placeholder. */
+ Note that optimization passes might move the *_BLOCK notes away,
+ so we use a NOTE_INSN_DELETED as a placeholder. */
{
rtx original_before_jump
clear_last_expr ();
}
\f
-/* Generate RTL for the start of a loop. EXIT_FLAG is nonzero if this
- loop should be exited by `exit_something'. This is a loop for which
- `expand_continue' will jump to the top of the loop.
-
- Make an entry on loop_stack to record the labels associated with
- this loop. */
-
-struct nesting *
-expand_start_loop (int exit_flag)
-{
- struct nesting *thisloop = ALLOC_NESTING ();
-
- /* Make an entry on loop_stack for the loop we are entering. */
-
- thisloop->desc = LOOP_NESTING;
- thisloop->next = loop_stack;
- thisloop->all = nesting_stack;
- thisloop->depth = ++nesting_depth;
- thisloop->data.loop.start_label = gen_label_rtx ();
- thisloop->data.loop.end_label = gen_label_rtx ();
- thisloop->data.loop.continue_label = thisloop->data.loop.start_label;
- thisloop->exit_label = exit_flag ? thisloop->data.loop.end_label : 0;
- loop_stack = thisloop;
- nesting_stack = thisloop;
-
- do_pending_stack_adjust ();
- emit_queue ();
- emit_label (thisloop->data.loop.start_label);
-
- return thisloop;
-}
-
-/* Like expand_start_loop but for a loop where the continuation point
- (for expand_continue_loop) will be specified explicitly. */
-
-struct nesting *
-expand_start_loop_continue_elsewhere (int exit_flag)
-{
- struct nesting *thisloop = expand_start_loop (exit_flag);
- loop_stack->data.loop.continue_label = gen_label_rtx ();
- return thisloop;
-}
-
-/* Begin a null, aka do { } while (0) "loop". But since the contents
- of said loop can still contain a break, we must frob the loop nest. */
-
-struct nesting *
-expand_start_null_loop (void)
-{
- struct nesting *thisloop = ALLOC_NESTING ();
-
- /* Make an entry on loop_stack for the loop we are entering. */
-
- thisloop->desc = LOOP_NESTING;
- thisloop->next = loop_stack;
- thisloop->all = nesting_stack;
- thisloop->depth = ++nesting_depth;
- thisloop->data.loop.start_label = emit_note (NOTE_INSN_DELETED);
- thisloop->data.loop.end_label = gen_label_rtx ();
- thisloop->data.loop.continue_label = thisloop->data.loop.end_label;
- thisloop->exit_label = thisloop->data.loop.end_label;
- loop_stack = thisloop;
- nesting_stack = thisloop;
-
- return thisloop;
-}
-
-/* Specify the continuation point for a loop started with
- expand_start_loop_continue_elsewhere.
- Use this at the point in the code to which a continue statement
- should jump. */
-
-void
-expand_loop_continue_here (void)
-{
- do_pending_stack_adjust ();
- emit_label (loop_stack->data.loop.continue_label);
-}
-
-/* Finish a loop. Generate a jump back to the top and the loop-exit label.
- Pop the block off of loop_stack. */
-
-void
-expand_end_loop (void)
-{
- rtx start_label = loop_stack->data.loop.start_label;
- rtx etc_note;
- int eh_regions, debug_blocks;
- bool empty_test;
-
- do_pending_stack_adjust ();
-
- /* If the loop starts with a loop exit, roll that to the end where
- it will optimize together with the jump back.
-
- If the loop presently looks like this (in pseudo-C):
-
- start_label:
- if (test) goto end_label;
- LOOP_END_TOP_COND
- body;
- goto start_label;
- end_label:
-
- transform it to look like:
-
- goto start_label;
- top_label:
- body;
- start_label:
- if (test) goto end_label;
- goto top_label;
- end_label:
-
- We rely on the presence of NOTE_INSN_LOOP_END_TOP_COND to mark
- the end of the entry conditional. Without this, our lexical scan
- can't tell the difference between an entry conditional and a
- body conditional that exits the loop. Mistaking the two means
- that we can misplace the NOTE_INSN_LOOP_CONT note, which can
- screw up loop unrolling.
-
- Things will be oh so much better when loop optimization is done
- off of a proper control flow graph... */
-
- /* Scan insns from the top of the loop looking for the END_TOP_COND note. */
-
- empty_test = true;
- eh_regions = debug_blocks = 0;
- for (etc_note = start_label; etc_note ; etc_note = NEXT_INSN (etc_note))
- if (GET_CODE (etc_note) == NOTE)
- {
- if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_END_TOP_COND)
- break;
-
- if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_BEG)
- abort ();
-
- /* At the same time, scan for EH region notes, as we don't want
- to scrog region nesting. This shouldn't happen, but... */
- if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_BEG)
- eh_regions++;
- else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_END)
- {
- if (--eh_regions < 0)
- /* We've come to the end of an EH region, but never saw the
- beginning of that region. That means that an EH region
- begins before the top of the loop, and ends in the middle
- of it. The existence of such a situation violates a basic
- assumption in this code, since that would imply that even
- when EH_REGIONS is zero, we might move code out of an
- exception region. */
- abort ();
- }
-
- /* Likewise for debug scopes. In this case we'll either (1) move
- all of the notes if they are properly nested or (2) leave the
- notes alone and only rotate the loop at high optimization
- levels when we expect to scrog debug info. */
- else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_BEG)
- debug_blocks++;
- else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_BLOCK_END)
- debug_blocks--;
- }
- else if (INSN_P (etc_note))
- empty_test = false;
-
- if (etc_note
- && optimize
- && ! empty_test
- && eh_regions == 0
- && (debug_blocks == 0 || optimize >= 2)
- && NEXT_INSN (etc_note) != NULL_RTX
- && ! any_condjump_p (get_last_insn ()))
- {
- /* We found one. Move everything from START to ETC to the end
- of the loop, and add a jump from the top of the loop. */
- rtx top_label = gen_label_rtx ();
- rtx start_move = start_label;
-
- emit_label_before (top_label, start_move);
-
- /* Actually move the insns. If the debug scopes are nested, we
- can move everything at once. Otherwise we have to move them
- one by one and squeeze out the block notes. */
- if (debug_blocks == 0)
- reorder_insns (start_move, etc_note, get_last_insn ());
- else
- {
- rtx insn, next_insn;
- for (insn = start_move; insn; insn = next_insn)
- {
- /* Figure out which insn comes after this one. We have
- to do this before we move INSN. */
- next_insn = (insn == etc_note ? NULL : NEXT_INSN (insn));
-
- if (GET_CODE (insn) == NOTE
- && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
- continue;
-
- reorder_insns (insn, insn, get_last_insn ());
- }
- }
-
- /* Add the jump from the top of the loop. */
- emit_jump_insn_before (gen_jump (start_label), top_label);
- emit_barrier_before (top_label);
- start_label = top_label;
- }
-
- if (etc_note)
- delete_insn (etc_note);
-
- emit_jump (start_label);
- emit_label (loop_stack->data.loop.end_label);
-
- POPSTACK (loop_stack);
-
- clear_last_expr ();
-}
-
-/* Finish a null loop, aka do { } while (0). */
-
-void
-expand_end_null_loop (void)
-{
- do_pending_stack_adjust ();
- emit_label (loop_stack->data.loop.end_label);
-
- POPSTACK (loop_stack);
-
- clear_last_expr ();
-}
-
-/* Generate a jump to the current loop's continue-point.
- This is usually the top of the loop, but may be specified
- explicitly elsewhere. If not currently inside a loop,
- return 0 and do nothing; caller will print an error message. */
-
-int
-expand_continue_loop (struct nesting *whichloop)
-{
- /* Emit information for branch prediction. */
- rtx note;
-
- if (flag_guess_branch_prob)
- {
- note = emit_note (NOTE_INSN_PREDICTION);
- NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_CONTINUE, IS_TAKEN);
- }
- clear_last_expr ();
- if (whichloop == 0)
- whichloop = loop_stack;
- if (whichloop == 0)
- return 0;
- expand_goto_internal (NULL_TREE, whichloop->data.loop.continue_label,
- NULL_RTX);
- return 1;
-}
-
-/* Generate a jump to exit the current loop. If not currently inside a loop,
- return 0 and do nothing; caller will print an error message. */
-
-int
-expand_exit_loop (struct nesting *whichloop)
-{
- clear_last_expr ();
- if (whichloop == 0)
- whichloop = loop_stack;
- if (whichloop == 0)
- return 0;
- expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label, NULL_RTX);
- return 1;
-}
-
-/* Generate a conditional jump to exit the current loop if COND
- evaluates to zero. If not currently inside a loop,
- return 0 and do nothing; caller will print an error message. */
-
-int
-expand_exit_loop_if_false (struct nesting *whichloop, tree cond)
-{
- rtx label;
- clear_last_expr ();
-
- if (whichloop == 0)
- whichloop = loop_stack;
- if (whichloop == 0)
- return 0;
-
- if (integer_nonzerop (cond))
- return 1;
- if (integer_zerop (cond))
- return expand_exit_loop (whichloop);
-
- /* Check if we definitely won't need a fixup. */
- if (whichloop == nesting_stack)
- {
- jumpifnot (cond, whichloop->data.loop.end_label);
- return 1;
- }
-
- /* In order to handle fixups, we actually create a conditional jump
- around an unconditional branch to exit the loop. If fixups are
- necessary, they go before the unconditional branch. */
-
- label = gen_label_rtx ();
- jumpif (cond, label);
- expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label,
- NULL_RTX);
- emit_label (label);
-
- return 1;
-}
-
-/* Like expand_exit_loop_if_false except also emit a note marking
- the end of the conditional. Should only be used immediately
- after expand_loop_start. */
-
-int
-expand_exit_loop_top_cond (struct nesting *whichloop, tree cond)
-{
- if (! expand_exit_loop_if_false (whichloop, cond))
- return 0;
-
- emit_note (NOTE_INSN_LOOP_END_TOP_COND);
- return 1;
-}
-
/* Return nonzero if we should preserve sub-expressions as separate
pseudos. We never do so if we aren't optimizing. We always do so
- if -fexpensive-optimizations.
-
- Otherwise, we only do so if we are in the "early" part of a loop. I.e.,
- the loop may still be a small one. */
+ if -fexpensive-optimizations. */
int
preserve_subexpressions_p (void)
{
- rtx insn;
-
if (flag_expensive_optimizations)
return 1;
- if (optimize == 0 || cfun == 0 || cfun->stmt == 0 || loop_stack == 0)
+ if (optimize == 0 || cfun == 0 || cfun->stmt == 0)
return 0;
- insn = get_last_insn_anywhere ();
-
- return (insn
- && (INSN_UID (insn) - INSN_UID (loop_stack->data.loop.start_label)
- < n_non_fixed_regs * 3));
-
+ return 1;
}
-/* Generate a jump to exit the current loop, conditional, binding contour
- or case statement. Not all such constructs are visible to this function,
- only those started with EXIT_FLAG nonzero. Individual languages use
- the EXIT_FLAG parameter to control which kinds of constructs you can
- exit this way.
-
- If not currently inside anything that can be exited,
- return 0 and do nothing; caller will print an error message. */
-
-int
-expand_exit_something (void)
-{
- struct nesting *n;
- clear_last_expr ();
- for (n = nesting_stack; n; n = n->all)
- if (n->exit_label != 0)
- {
- expand_goto_internal (NULL_TREE, n->exit_label, NULL_RTX);
- return 1;
- }
-
- return 0;
-}
\f
/* Generate RTL to return from the current function, with no value.
(That is, we do not do anything about returning any value.) */