/* Optimize jump instructions, for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997
- 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
This file is part of GCC.
static void mark_all_labels (rtx);
static void delete_computation (rtx);
static void redirect_exp_1 (rtx *, rtx, rtx, rtx);
-static int redirect_exp (rtx, rtx, rtx);
-static void invert_exp_1 (rtx);
-static int invert_exp (rtx);
+static int invert_exp_1 (rtx, rtx);
static int returnjump_p_1 (rtx *, void *);
static void delete_prior_computation (rtx, rtx);
\f
{
prev = prev_nonnote_insn (insn);
if (BARRIER_P (prev))
- delete_barrier (insn);
+ delete_insn (insn);
else if (prev != PREV_INSN (insn))
reorder_insns (insn, insn, prev);
}
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_VTOP))
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END))
{
+ /* BLOCK_BEG or BLOCK_END notes only exist in the `final' pass. */
+ gcc_assert (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_BEG
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_END);
+
if (insn == start)
start = next;
else
XEXP (comparison, 0),
XEXP (comparison, 1), insn);
}
+
+/* Return comparison with reversed code of EXP.
+ Return NULL_RTX in case we fail to do the reversal. */
+rtx
+reversed_comparison (rtx exp, enum machine_mode mode)
+{
+ enum rtx_code reversed_code = reversed_comparison_code (exp, NULL_RTX);
+ if (reversed_code == UNKNOWN)
+ return NULL_RTX;
+ else
+ return simplify_gen_relational (reversed_code, mode, VOIDmode,
+ XEXP (exp, 0), XEXP (exp, 1));
+}
+
\f
/* Given an rtx-code for a comparison, return the code for the negated
comparison. If no such code exists, return UNKNOWN.
|| (GET_CODE (XEXP (x, 1)) == PC
&& (GET_CODE (XEXP (x, 2)) == LABEL_REF
|| GET_CODE (XEXP (x, 2)) == RETURN))));
-
- return 0;
}
/* Return nonzero if INSN is a (possibly) conditional jump inside a
delete_computation (insn);
}
-/* Verify INSN is a BARRIER and delete it. */
-
-void
-delete_barrier (rtx insn)
-{
- if (!BARRIER_P (insn))
- abort ();
-
- delete_insn (insn);
-}
-
/* Recursively delete prior insns that compute the value (used only by INSN
which the caller is deleting) stored in the register mentioned by NOTE
which is a REG_DEAD note associated with INSN. */
}
else if (code == RETURN && olabel == 0)
{
- x = gen_rtx_LABEL_REF (VOIDmode, nlabel);
+ if (nlabel)
+ x = gen_rtx_LABEL_REF (VOIDmode, nlabel);
+ else
+ x = gen_rtx_RETURN (VOIDmode);
if (loc == &PATTERN (insn))
x = gen_rtx_SET (VOIDmode, pc_rtx, x);
validate_change (insn, loc, x, 1);
}
}
-/* Similar, but apply the change group and report success or failure. */
-
-static int
-redirect_exp (rtx olabel, rtx nlabel, rtx insn)
-{
- rtx *loc;
-
- if (GET_CODE (PATTERN (insn)) == PARALLEL)
- loc = &XVECEXP (PATTERN (insn), 0, 0);
- else
- loc = &PATTERN (insn);
-
- redirect_exp_1 (loc, olabel, nlabel, insn);
- if (num_validated_changes () == 0)
- return 0;
-
- return apply_change_group ();
-}
-
/* Make JUMP go to NLABEL instead of where it jumps now. Accrue
the modifications into the change group. Return false if we did
not see how to do that. */
redirect_jump (rtx jump, rtx nlabel, int delete_unused)
{
rtx olabel = JUMP_LABEL (jump);
- rtx note;
if (nlabel == olabel)
return 1;
- if (! redirect_exp (olabel, nlabel, jump))
+ if (! redirect_jump_1 (jump, nlabel) || ! apply_change_group ())
return 0;
+ redirect_jump_2 (jump, olabel, nlabel, delete_unused, 0);
+ return 1;
+}
+
+/* Fix up JUMP_LABEL and label ref counts after OLABEL has been replaced with
+ NLABEL in JUMP. If DELETE_UNUSED is non-negative, copy a
+ NOTE_INSN_FUNCTION_END found after OLABEL to the place after NLABEL.
+ If DELETE_UNUSED is positive, delete related insn to OLABEL if its ref
+ count has dropped to zero. */
+void
+redirect_jump_2 (rtx jump, rtx olabel, rtx nlabel, int delete_unused,
+ int invert)
+{
+ rtx note;
+
JUMP_LABEL (jump) = nlabel;
if (nlabel)
++LABEL_NUSES (nlabel);
/* Update labels in any REG_EQUAL note. */
if ((note = find_reg_note (jump, REG_EQUAL, NULL_RTX)) != NULL_RTX)
{
- if (nlabel && olabel)
+ if (!nlabel || (invert && !invert_exp_1 (XEXP (note, 0), jump)))
+ remove_note (jump, note);
+ else
{
- rtx dest = XEXP (note, 0);
-
- if (GET_CODE (dest) == IF_THEN_ELSE)
- {
- if (GET_CODE (XEXP (dest, 1)) == LABEL_REF
- && XEXP (XEXP (dest, 1), 0) == olabel)
- XEXP (XEXP (dest, 1), 0) = nlabel;
- if (GET_CODE (XEXP (dest, 2)) == LABEL_REF
- && XEXP (XEXP (dest, 2), 0) == olabel)
- XEXP (XEXP (dest, 2), 0) = nlabel;
- }
- else
- remove_note (jump, note);
+ redirect_exp_1 (&XEXP (note, 0), olabel, nlabel, jump);
+ confirm_change_group ();
}
- else
- remove_note (jump, note);
}
/* If we're eliding the jump over exception cleanups at the end of a
if (olabel && nlabel
&& NEXT_INSN (olabel)
&& NOTE_P (NEXT_INSN (olabel))
- && NOTE_LINE_NUMBER (NEXT_INSN (olabel)) == NOTE_INSN_FUNCTION_END)
+ && NOTE_LINE_NUMBER (NEXT_INSN (olabel)) == NOTE_INSN_FUNCTION_END
+ && delete_unused >= 0)
emit_note_after (NOTE_INSN_FUNCTION_END, nlabel);
- if (olabel && --LABEL_NUSES (olabel) == 0 && delete_unused
+ if (olabel && --LABEL_NUSES (olabel) == 0 && delete_unused > 0
/* Undefined labels will remain outside the insn stream. */
&& INSN_UID (olabel))
delete_related_insns (olabel);
-
- return 1;
+ if (invert)
+ invert_br_probabilities (jump);
}
-/* Invert the jump condition of rtx X contained in jump insn, INSN.
- Accrue the modifications into the change group. */
-
-static void
-invert_exp_1 (rtx insn)
+/* Invert the jump condition X contained in jump insn INSN. Accrue the
+ modifications into the change group. Return nonzero for success. */
+static int
+invert_exp_1 (rtx x, rtx insn)
{
- RTX_CODE code;
- rtx x = pc_set (insn);
-
- if (!x)
- abort ();
- x = SET_SRC (x);
-
- code = GET_CODE (x);
+ RTX_CODE code = GET_CODE (x);
if (code == IF_THEN_ELSE)
{
GET_MODE (comp), XEXP (comp, 0),
XEXP (comp, 1)),
1);
- return;
+ return 1;
}
tem = XEXP (x, 1);
validate_change (insn, &XEXP (x, 1), XEXP (x, 2), 1);
validate_change (insn, &XEXP (x, 2), tem, 1);
+ return 1;
}
else
- abort ();
-}
-
-/* Invert the jump condition of conditional jump insn, INSN.
-
- Return 1 if we can do so, 0 if we cannot find a way to do so that
- matches a pattern. */
-
-static int
-invert_exp (rtx insn)
-{
- invert_exp_1 (insn);
- if (num_validated_changes () == 0)
return 0;
-
- return apply_change_group ();
}
/* Invert the condition of the jump JUMP, and make it jump to label
int
invert_jump_1 (rtx jump, rtx nlabel)
{
+ rtx x = pc_set (jump);
int ochanges;
ochanges = num_validated_changes ();
- invert_exp_1 (jump);
+ if (!x || !invert_exp_1 (SET_SRC (x), jump))
+ abort ();
if (num_validated_changes () == ochanges)
return 0;
- return redirect_jump_1 (jump, nlabel);
+ /* redirect_jump_1 will fail of nlabel == olabel, and the current use is
+ in Pmode, so checking this is not merely an optimization. */
+ return nlabel == JUMP_LABEL (jump) || redirect_jump_1 (jump, nlabel);
}
/* Invert the condition of the jump JUMP, and make it jump to label
int
invert_jump (rtx jump, rtx nlabel, int delete_unused)
{
- /* We have to either invert the condition and change the label or
- do neither. Either operation could fail. We first try to invert
- the jump. If that succeeds, we try changing the label. If that fails,
- we invert the jump back to what it was. */
-
- if (! invert_exp (jump))
- return 0;
+ rtx olabel = JUMP_LABEL (jump);
- if (redirect_jump (jump, nlabel, delete_unused))
+ if (invert_jump_1 (jump, nlabel) && apply_change_group ())
{
- /* Remove REG_EQUAL note if we have one. */
- rtx note = find_reg_note (jump, REG_EQUAL, NULL_RTX);
- if (note)
- remove_note (jump, note);
-
- invert_br_probabilities (jump);
-
+ redirect_jump_2 (jump, olabel, nlabel, delete_unused, 1);
return 1;
}
-
- if (! invert_exp (jump))
- /* This should just be putting it back the way it was. */
- abort ();
-
+ cancel_changes (0);
return 0;
}