-
-/* Delete all labels already not referenced.
- Also find and return the last insn. */
-
-static rtx
-delete_unreferenced_labels (f)
- rtx f;
-{
- rtx final = NULL_RTX;
- rtx insn;
-
- for (insn = f; insn;)
- {
- if (GET_CODE (insn) == CODE_LABEL
- && LABEL_NUSES (insn) == 0
- && LABEL_ALTERNATE_NAME (insn) == NULL)
- insn = delete_insn (insn);
- else
- {
- final = insn;
- insn = NEXT_INSN (insn);
- }
- }
-
- return final;
-}
-
-/* Delete various simple forms of moves which have no necessary
- side effect. */
-
-static void
-delete_noop_moves (f)
- rtx f;
-{
- rtx insn, next;
-
- for (insn = f; insn;)
- {
- next = NEXT_INSN (insn);
-
- if (GET_CODE (insn) == INSN)
- {
- register rtx body = PATTERN (insn);
-
- /* Detect and delete no-op move instructions
- resulting from not allocating a parameter in a register. */
-
- if (GET_CODE (body) == SET && set_noop_p (body))
- delete_computation (insn);
-
- /* Detect and ignore no-op move instructions
- resulting from smart or fortuitous register allocation. */
-
- else if (GET_CODE (body) == SET)
- {
- int sreg = true_regnum (SET_SRC (body));
- int dreg = true_regnum (SET_DEST (body));
-
- if (sreg == dreg && sreg >= 0)
- delete_insn (insn);
- else if (sreg >= 0 && dreg >= 0)
- {
- rtx trial;
- rtx tem = find_equiv_reg (NULL_RTX, insn, 0,
- sreg, NULL, dreg,
- GET_MODE (SET_SRC (body)));
-
- if (tem != 0
- && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
- {
- /* DREG may have been the target of a REG_DEAD note in
- the insn which makes INSN redundant. If so, reorg
- would still think it is dead. So search for such a
- note and delete it if we find it. */
- if (! find_regno_note (insn, REG_UNUSED, dreg))
- for (trial = prev_nonnote_insn (insn);
- trial && GET_CODE (trial) != CODE_LABEL;
- trial = prev_nonnote_insn (trial))
- if (find_regno_note (trial, REG_DEAD, dreg))
- {
- remove_death (dreg, trial);
- break;
- }
-
- /* Deleting insn could lose a death-note for SREG. */
- if ((trial = find_regno_note (insn, REG_DEAD, sreg)))
- {
- /* Change this into a USE so that we won't emit
- code for it, but still can keep the note. */
- PATTERN (insn)
- = gen_rtx_USE (VOIDmode, XEXP (trial, 0));
- INSN_CODE (insn) = -1;
- /* Remove all reg notes but the REG_DEAD one. */
- REG_NOTES (insn) = trial;
- XEXP (trial, 1) = NULL_RTX;
- }
- else
- delete_insn (insn);
- }
- }
- else if (dreg >= 0 && CONSTANT_P (SET_SRC (body))
- && find_equiv_reg (SET_SRC (body), insn, 0, dreg,
- NULL, 0, GET_MODE (SET_DEST (body))))
- {
- /* This handles the case where we have two consecutive
- assignments of the same constant to pseudos that didn't
- get a hard reg. Each SET from the constant will be
- converted into a SET of the spill register and an
- output reload will be made following it. This produces
- two loads of the same constant into the same spill
- register. */
-
- rtx in_insn = insn;
-
- /* Look back for a death note for the first reg.
- If there is one, it is no longer accurate. */
- while (in_insn && GET_CODE (in_insn) != CODE_LABEL)
- {
- if ((GET_CODE (in_insn) == INSN
- || GET_CODE (in_insn) == JUMP_INSN)
- && find_regno_note (in_insn, REG_DEAD, dreg))
- {
- remove_death (dreg, in_insn);
- break;
- }
- in_insn = PREV_INSN (in_insn);
- }
-
- /* Delete the second load of the value. */
- delete_insn (insn);
- }
- }
- else if (GET_CODE (body) == PARALLEL)
- {
- /* If each part is a set between two identical registers or
- a USE or CLOBBER, delete the insn. */
- int i, sreg, dreg;
- rtx tem;
-
- for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
- {
- tem = XVECEXP (body, 0, i);
- if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER)
- continue;
-
- if (GET_CODE (tem) != SET
- || (sreg = true_regnum (SET_SRC (tem))) < 0
- || (dreg = true_regnum (SET_DEST (tem))) < 0
- || dreg != sreg)
- break;
- }
-
- if (i < 0)
- delete_insn (insn);
- }
- }
- insn = next;
- }
-}
-
-/* LOOP_START is a NOTE_INSN_LOOP_BEG note that is followed by an unconditional
- jump. Assume that this unconditional jump is to the exit test code. If
- the code is sufficiently simple, make a copy of it before INSN,
- followed by a jump to the exit of the loop. Then delete the unconditional
- jump after INSN.
-
- Return 1 if we made the change, else 0.
-
- This is only safe immediately after a regscan pass because it uses the
- values of regno_first_uid and regno_last_uid. */
-
-static int
-duplicate_loop_exit_test (loop_start)
- rtx loop_start;
-{
- rtx insn, set, reg, p, link;
- rtx copy = 0, first_copy = 0;
- int num_insns = 0;
- rtx exitcode = NEXT_INSN (JUMP_LABEL (next_nonnote_insn (loop_start)));
- rtx lastexit;
- int max_reg = max_reg_num ();
- rtx *reg_map = 0;
-
- /* Scan the exit code. We do not perform this optimization if any insn:
-
- is a CALL_INSN
- is a CODE_LABEL
- has a REG_RETVAL or REG_LIBCALL note (hard to adjust)
- is a NOTE_INSN_LOOP_BEG because this means we have a nested loop
- is a NOTE_INSN_BLOCK_{BEG,END} because duplicating these notes
- is not valid.
-
- We also do not do this if we find an insn with ASM_OPERANDS. While
- this restriction should not be necessary, copying an insn with
- ASM_OPERANDS can confuse asm_noperands in some cases.
-
- Also, don't do this if the exit code is more than 20 insns. */
-
- for (insn = exitcode;
- insn
- && ! (GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END);
- insn = NEXT_INSN (insn))
- {
- switch (GET_CODE (insn))
- {
- case CODE_LABEL:
- case CALL_INSN:
- return 0;
- case NOTE:
- /* We could be in front of the wrong NOTE_INSN_LOOP_END if there is
- a jump immediately after the loop start that branches outside
- the loop but within an outer loop, near the exit test.
- If we copied this exit test and created a phony
- NOTE_INSN_LOOP_VTOP, this could make instructions immediately
- before the exit test look like these could be safely moved
- out of the loop even if they actually may be never executed.
- This can be avoided by checking here for NOTE_INSN_LOOP_CONT. */
-
- if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)
- return 0;
-
- if (optimize < 2
- && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
- /* If we were to duplicate this code, we would not move
- the BLOCK notes, and so debugging the moved code would
- be difficult. Thus, we only move the code with -O2 or
- higher. */
- return 0;
-
- break;
- case JUMP_INSN:
- case INSN:
- /* The code below would grossly mishandle REG_WAS_0 notes,
- so get rid of them here. */
- while ((p = find_reg_note (insn, REG_WAS_0, NULL_RTX)) != 0)
- remove_note (insn, p);
- if (++num_insns > 20
- || find_reg_note (insn, REG_RETVAL, NULL_RTX)
- || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
- return 0;
- break;
- default:
- break;
- }
- }
-
- /* Unless INSN is zero, we can do the optimization. */
- if (insn == 0)
- return 0;
-
- lastexit = insn;
-
- /* See if any insn sets a register only used in the loop exit code and
- not a user variable. If so, replace it with a new register. */
- for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == INSN
- && (set = single_set (insn)) != 0
- && ((reg = SET_DEST (set), GET_CODE (reg) == REG)
- || (GET_CODE (reg) == SUBREG
- && (reg = SUBREG_REG (reg), GET_CODE (reg) == REG)))
- && REGNO (reg) >= FIRST_PSEUDO_REGISTER
- && REGNO_FIRST_UID (REGNO (reg)) == INSN_UID (insn))
- {
- for (p = NEXT_INSN (insn); p != lastexit; p = NEXT_INSN (p))
- if (REGNO_LAST_UID (REGNO (reg)) == INSN_UID (p))
- break;
-
- if (p != lastexit)
- {
- /* We can do the replacement. Allocate reg_map if this is the
- first replacement we found. */
- if (reg_map == 0)
- reg_map = (rtx *) xcalloc (max_reg, sizeof (rtx));
-
- REG_LOOP_TEST_P (reg) = 1;
-
- reg_map[REGNO (reg)] = gen_reg_rtx (GET_MODE (reg));
- }
- }
-
- /* Now copy each insn. */
- for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))
- {
- switch (GET_CODE (insn))
- {
- case BARRIER:
- copy = emit_barrier_before (loop_start);
- break;
- case NOTE:
- /* Only copy line-number notes. */
- if (NOTE_LINE_NUMBER (insn) >= 0)
- {
- copy = emit_note_before (NOTE_LINE_NUMBER (insn), loop_start);
- NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);
- }
- break;
-
- case INSN:
- copy = emit_insn_before (copy_insn (PATTERN (insn)), loop_start);
- if (reg_map)
- replace_regs (PATTERN (copy), reg_map, max_reg, 1);
-
- mark_jump_label (PATTERN (copy), copy, 0);
-
- /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
- make them. */
- for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
- if (REG_NOTE_KIND (link) != REG_LABEL)
- {
- if (GET_CODE (link) == EXPR_LIST)
- REG_NOTES (copy)
- = copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
- XEXP (link, 0),
- REG_NOTES (copy)));
- else
- REG_NOTES (copy)
- = copy_insn_1 (gen_rtx_INSN_LIST (REG_NOTE_KIND (link),
- XEXP (link, 0),
- REG_NOTES (copy)));
- }
-
- if (reg_map && REG_NOTES (copy))
- replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
- break;
-
- case JUMP_INSN:
- copy = emit_jump_insn_before (copy_insn (PATTERN (insn)),
- loop_start);
- if (reg_map)
- replace_regs (PATTERN (copy), reg_map, max_reg, 1);
- mark_jump_label (PATTERN (copy), copy, 0);
- if (REG_NOTES (insn))
- {
- REG_NOTES (copy) = copy_insn_1 (REG_NOTES (insn));
- if (reg_map)
- replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
- }
-
- /* Predict conditional jump that do make loop looping as taken.
- Other jumps are probably exit conditions, so predict
- them as untaken. */
- if (any_condjump_p (copy))
- {
- rtx label = JUMP_LABEL (copy);
- if (label)
- {
- /* The jump_insn after loop_start should be followed
- by barrier and loopback label. */
- if (prev_nonnote_insn (label)
- && (PREV_INSN (prev_nonnote_insn (label))
- == NEXT_INSN (loop_start)))
- predict_insn_def (copy, PRED_LOOP_HEADER, TAKEN);
- else
- predict_insn_def (copy, PRED_LOOP_HEADER, NOT_TAKEN);
- }
- }
- /* If this is a simple jump, add it to the jump chain. */
-
- if (INSN_UID (copy) < max_jump_chain && JUMP_LABEL (copy)
- && simplejump_p (copy))
- {
- jump_chain[INSN_UID (copy)]
- = jump_chain[INSN_UID (JUMP_LABEL (copy))];
- jump_chain[INSN_UID (JUMP_LABEL (copy))] = copy;
- }
- break;
-
- default:
- abort ();
- }
-
- /* Record the first insn we copied. We need it so that we can
- scan the copied insns for new pseudo registers. */
- if (! first_copy)
- first_copy = copy;
- }
-
- /* Now clean up by emitting a jump to the end label and deleting the jump
- at the start of the loop. */
- if (! copy || GET_CODE (copy) != BARRIER)
- {
- copy = emit_jump_insn_before (gen_jump (get_label_after (insn)),
- loop_start);
-
- /* Record the first insn we copied. We need it so that we can
- scan the copied insns for new pseudo registers. This may not
- be strictly necessary since we should have copied at least one
- insn above. But I am going to be safe. */
- if (! first_copy)
- first_copy = copy;
-
- mark_jump_label (PATTERN (copy), copy, 0);
- if (INSN_UID (copy) < max_jump_chain
- && INSN_UID (JUMP_LABEL (copy)) < max_jump_chain)
- {
- jump_chain[INSN_UID (copy)]
- = jump_chain[INSN_UID (JUMP_LABEL (copy))];
- jump_chain[INSN_UID (JUMP_LABEL (copy))] = copy;
- }
- emit_barrier_before (loop_start);
- }
-
- /* Now scan from the first insn we copied to the last insn we copied
- (copy) for new pseudo registers. Do this after the code to jump to
- the end label since that might create a new pseudo too. */
- reg_scan_update (first_copy, copy, max_reg);
-
- /* Mark the exit code as the virtual top of the converted loop. */
- emit_note_before (NOTE_INSN_LOOP_VTOP, exitcode);
-
- delete_insn (next_nonnote_insn (loop_start));
-
- /* Clean up. */
- if (reg_map)
- free (reg_map);
-
- return 1;
-}