- struct nesting *thiscond = ALLOC_NESTING ();
-
- /* Make an entry on cond_stack for the cond we are entering. */
-
- thiscond->desc = COND_NESTING;
- thiscond->next = cond_stack;
- thiscond->all = nesting_stack;
- thiscond->depth = ++nesting_depth;
- thiscond->data.cond.next_label = gen_label_rtx ();
- /* Before we encounter an `else', we don't need a separate exit label
- unless there are supposed to be exit statements
- to exit this conditional. */
- thiscond->exit_label = exitflag ? gen_label_rtx () : 0;
- thiscond->data.cond.endif_label = thiscond->exit_label;
- cond_stack = thiscond;
- nesting_stack = thiscond;
-
- do_jump (cond, thiscond->data.cond.next_label, NULL_RTX);
-}
-
-/* Generate RTL between then-clause and the elseif-clause
- of an if-then-elseif-.... */
-
-void
-expand_start_elseif (tree cond)
-{
- if (cond_stack->data.cond.endif_label == 0)
- cond_stack->data.cond.endif_label = gen_label_rtx ();
- emit_jump (cond_stack->data.cond.endif_label);
- emit_label (cond_stack->data.cond.next_label);
- cond_stack->data.cond.next_label = gen_label_rtx ();
- do_jump (cond, cond_stack->data.cond.next_label, NULL_RTX);
-}
-
-/* Generate RTL between the then-clause and the else-clause
- of an if-then-else. */
-
-void
-expand_start_else (void)
-{
- if (cond_stack->data.cond.endif_label == 0)
- cond_stack->data.cond.endif_label = gen_label_rtx ();
-
- emit_jump (cond_stack->data.cond.endif_label);
- emit_label (cond_stack->data.cond.next_label);
- cond_stack->data.cond.next_label = 0; /* No more _else or _elseif calls. */
-}
-
-/* After calling expand_start_else, turn this "else" into an "else if"
- by providing another condition. */
-
-void
-expand_elseif (tree cond)
-{
- cond_stack->data.cond.next_label = gen_label_rtx ();
- do_jump (cond, cond_stack->data.cond.next_label, NULL_RTX);
-}
-
-/* Generate RTL for the end of an if-then.
- Pop the record for it off of cond_stack. */
-
-void
-expand_end_cond (void)
-{
- struct nesting *thiscond = cond_stack;
-
- do_pending_stack_adjust ();
- if (thiscond->data.cond.next_label)
- emit_label (thiscond->data.cond.next_label);
- if (thiscond->data.cond.endif_label)
- emit_label (thiscond->data.cond.endif_label);
-
- POPSTACK (cond_stack);
- 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. */
-
-int
-preserve_subexpressions_p (void)
-{
- rtx insn;
-
- if (flag_expensive_optimizations)
- return 1;
-
- if (optimize == 0 || cfun == 0 || cfun->stmt == 0 || loop_stack == 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));
-
-}
-
-/* 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.) */
-
-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);
-}
-
-/* Generate RTL to return directly from the current function.
- (That is, we bypass any return value.) */
-
-void
-expand_naked_return (void)
-{
- rtx last_insn, end_label;
-
- last_insn = get_last_insn ();
- end_label = naked_return_label;
-
- clear_pending_stack_adjust ();
- do_pending_stack_adjust ();
- clear_last_expr ();
-
- if (end_label == 0)
- end_label = naked_return_label = gen_label_rtx ();
- expand_goto_internal (NULL_TREE, end_label, last_insn);
-}
-
-/* Try to guess whether the value of return means error code. */
-static enum br_predictor
-return_prediction (rtx val)
-{
- /* Different heuristics for pointers and scalars. */
- if (POINTER_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
- {
- /* NULL is usually not returned. */
- if (val == const0_rtx)
- return PRED_NULL_RETURN;
- }
- else
- {
- /* Negative return values are often used to indicate
- errors. */
- if (GET_CODE (val) == CONST_INT
- && INTVAL (val) < 0)
- return PRED_NEGATIVE_RETURN;
- /* Constant return values are also usually erors,
- zero/one often mean booleans so exclude them from the
- heuristics. */
- if (CONSTANT_P (val)
- && (val != const0_rtx && val != const1_rtx))
- return PRED_CONST_RETURN;
- }
- return PRED_NO_PREDICTION;
-}
-
-
-/* If the current function returns values in the most significant part
- of a register, shift return value VAL appropriately. The mode of
- the function's return type is known not to be BLKmode. */
-
-static rtx
-shift_return_value (rtx val)
-{
- tree type;
-
- type = TREE_TYPE (DECL_RESULT (current_function_decl));
- if (targetm.calls.return_in_msb (type))
- {
- rtx target;
- HOST_WIDE_INT shift;
-
- target = DECL_RTL (DECL_RESULT (current_function_decl));
- 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,
- gen_lowpart (GET_MODE (target), val),
- GEN_INT (shift), target, 1, OPTAB_WIDEN);
- }
- return val;
-}
-
-
-/* Generate RTL to return from the current function, with value VAL. */
-
-static void
-expand_value_return (rtx val)
-{
- rtx last_insn;
- rtx return_reg;
- enum br_predictor pred;
-
- if (flag_guess_branch_prob
- && (pred = return_prediction (val)) != PRED_NO_PREDICTION)
- {
- /* Emit information for branch prediction. */
- rtx note;
-
- note = emit_note (NOTE_INSN_PREDICTION);
-
- NOTE_PREDICTION (note) = NOTE_PREDICT (pred, NOT_TAKEN);
-
- }
-
- last_insn = get_last_insn ();
- return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
-
- /* Copy the value to the return location
- unless it's already there. */
-
- if (return_reg != val)
- {
- tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
- if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
- {
- int unsignedp = TYPE_UNSIGNED (type);
- enum machine_mode old_mode
- = DECL_MODE (DECL_RESULT (current_function_decl));
- enum machine_mode mode
- = promote_mode (type, old_mode, &unsignedp, 1);
-
- if (mode != old_mode)
- val = convert_modes (mode, old_mode, val, unsignedp);
- }
- if (GET_CODE (return_reg) == PARALLEL)
- emit_group_load (return_reg, val, type, int_size_in_bytes (type));
- else
- emit_move_insn (return_reg, val);
- }
-
- expand_null_return_1 (last_insn);
-}
-
-/* Output a return with no value. If LAST_INSN is nonzero,
- pretend that the return takes place after LAST_INSN. */
-
-static void
-expand_null_return_1 (rtx last_insn)
-{
- rtx end_label = cleanup_label ? cleanup_label : return_label;
-