/* Optimize jump instructions, for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997
- 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "tm_p.h"
#include "flags.h"
#include "toplev.h"
#include "reload.h"
#include "predict.h"
+#include "timevar.h"
+#include "diagnostic.h"
/* Optimize jump y; x: ... y: jumpif... x?
Don't know if it is worth bothering with. */
or even change what is live at any point.
So perhaps let combiner do it. */
-static int init_label_info PARAMS ((rtx));
+static rtx next_nonnote_insn_in_loop PARAMS ((rtx));
+static void init_label_info PARAMS ((rtx));
static void mark_all_labels PARAMS ((rtx));
static int duplicate_loop_exit_test PARAMS ((rtx));
static void delete_computation PARAMS ((rtx));
rtx f;
{
rtx insn;
- int max_uid = 0;
-
- max_uid = init_label_info (f) + 1;
+ timevar_push (TV_REBUILD_JUMP);
+ init_label_info (f);
mark_all_labels (f);
/* Keep track of labels used from static data; we don't track them
for (insn = forced_labels; insn; insn = XEXP (insn, 1))
if (GET_CODE (XEXP (insn, 0)) == CODE_LABEL)
LABEL_NUSES (XEXP (insn, 0))++;
-
- /* Keep track of labels used for marking handlers for exception
- regions; they cannot usually be deleted. */
-
- for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
- if (GET_CODE (XEXP (insn, 0)) == CODE_LABEL)
- LABEL_NUSES (XEXP (insn, 0))++;
+ timevar_pop (TV_REBUILD_JUMP);
}
\f
/* Some old code expects exactly one BARRIER as the NEXT_INSN of a
}
}
\f
+/* Return the next insn after INSN that is not a NOTE and is in the loop,
+ i.e. when there is no such INSN before NOTE_INSN_LOOP_END return NULL_RTX.
+ This routine does not look inside SEQUENCEs. */
+
+static rtx
+next_nonnote_insn_in_loop (insn)
+ rtx insn;
+{
+ while (insn)
+ {
+ insn = NEXT_INSN (insn);
+ if (insn == 0 || GET_CODE (insn) != NOTE)
+ break;
+ if (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+ return NULL_RTX;
+ }
+
+ return insn;
+}
+
void
copy_loop_headers (f)
rtx f;
the values of regno_first_uid and regno_last_uid. */
if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
- && (temp1 = next_nonnote_insn (insn)) != 0
+ && (temp1 = next_nonnote_insn_in_loop (insn)) != 0
&& any_uncondjump_p (temp1) && onlyjump_p (temp1))
{
temp = PREV_INSN (insn);
/* Initialize LABEL_NUSES and JUMP_LABEL fields. Delete any REG_LABEL
notes whose labels don't occur in the insn any more. Returns the
largest INSN_UID found. */
-static int
+static void
init_label_info (f)
rtx f;
{
- int largest_uid = 0;
rtx insn;
for (insn = f; insn; insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == CODE_LABEL)
- LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
- else if (GET_CODE (insn) == JUMP_INSN)
- JUMP_LABEL (insn) = 0;
- else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
- {
- rtx note, next;
-
- for (note = REG_NOTES (insn); note; note = next)
- {
- next = XEXP (note, 1);
- if (REG_NOTE_KIND (note) == REG_LABEL
- && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
- remove_note (insn, note);
- }
- }
- if (INSN_UID (insn) > largest_uid)
- largest_uid = INSN_UID (insn);
- }
+ if (GET_CODE (insn) == CODE_LABEL)
+ LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
+ else if (GET_CODE (insn) == JUMP_INSN)
+ JUMP_LABEL (insn) = 0;
+ else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+ {
+ rtx note, next;
- return largest_uid;
+ for (note = REG_NOTES (insn); note; note = next)
+ {
+ next = XEXP (note, 1);
+ if (REG_NOTE_KIND (note) == REG_LABEL
+ && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+ remove_note (insn, note);
+ }
+ }
}
/* Mark the label each jump jumps to.
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 exitcode
+ = NEXT_INSN (JUMP_LABEL (next_nonnote_insn_in_loop (loop_start)));
rtx lastexit;
int max_reg = max_reg_num ();
rtx *reg_map = 0;
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
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
replace_regs (PATTERN (copy), reg_map, max_reg, 1);
mark_jump_label (PATTERN (copy), copy, 0);
+ INSN_LOCATOR (copy) = INSN_LOCATOR (insn);
/* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
make them. */
case JUMP_INSN:
copy = emit_jump_insn_before (copy_insn (PATTERN (insn)),
loop_start);
+ INSN_LOCATOR (copy) = INSN_LOCATOR (insn);
if (reg_map)
replace_regs (PATTERN (copy), reg_map, max_reg, 1);
mark_jump_label (PATTERN (copy), copy, 0);
break;
}
- /* In case we give up IEEE compatibility, all comparisons are reversible. */
- if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || flag_unsafe_math_optimizations)
- return reverse_condition (code);
-
- if (GET_MODE_CLASS (mode) == MODE_CC
-#ifdef HAVE_cc0
- || arg0 == cc0_rtx
-#endif
- )
+ if (GET_MODE_CLASS (mode) == MODE_CC || CC0_P (arg0))
{
rtx prev;
/* Try to search for the comparison to determine the real mode.
}
}
- /* An integer condition. */
+ /* Test for an integer condition, or a floating-point comparison
+ in which NaNs can be ignored. */
if (GET_CODE (arg0) == CONST_INT
|| (GET_MODE (arg0) != VOIDmode
&& GET_MODE_CLASS (mode) != MODE_CC
- && ! FLOAT_MODE_P (mode)))
+ && !HONOR_NANS (mode)))
return reverse_condition (code);
return UNKNOWN;
reverse_condition_maybe_unordered (code)
enum rtx_code code;
{
- /* Non-IEEE formats don't have unordered conditions. */
- if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
- return reverse_condition (code);
-
switch (code)
{
case EQ:
}
}
\f
-/* Return non-zero if CODE1 is more strict than CODE2, i.e., if the
+/* Return nonzero if CODE1 is more strict than CODE2, i.e., if the
truth of CODE1 implies the truth of CODE2. */
int
#ifdef HAVE_cc0
-/* Return non-zero if X is an RTX that only sets the condition codes
+/* Return nonzero if X is an RTX that only sets the condition codes
and has no side effects. */
int
only_sets_cc0_p (x)
rtx x;
{
-
if (! x)
return 0;
sets_cc0_p (x)
rtx x;
{
-
if (! x)
return 0;
case PC:
case CC0:
case REG:
- case SUBREG:
case CONST_INT:
case CONST_DOUBLE:
case CLOBBER:
break;
/* If we reach a SEQUENCE, it is too complex to try to
- do anything with it, so give up. */
+ do anything with it, so give up. We can be run during
+ and after reorg, so SEQUENCE rtl can legitimately show
+ up here. */
if (GET_CODE (pat) == SEQUENCE)
break;
}
\f
/* Delete insn INSN from the chain of insns and update label ref counts
- and delete insns now unreachable.
+ and delete insns now unreachable.
- Returns the first insn after INSN that was not deleted.
+ Returns the first insn after INSN that was not deleted.
Usage of this instruction is deprecated. Use delete_insn instead and
subsequent cfg_cleanup pass to delete unreachable code if needed. */
next = NEXT_INSN (next);
return next;
}
- else if ((lab_next = next_nonnote_insn (lab)) != NULL
- && GET_CODE (lab_next) == JUMP_INSN
- && (GET_CODE (PATTERN (lab_next)) == ADDR_VEC
- || GET_CODE (PATTERN (lab_next)) == ADDR_DIFF_VEC))
+ else if (tablejump_p (insn, NULL, &lab_next))
{
/* If we're deleting the tablejump, delete the dispatch table.
We may not be able to kill the label immediately preceding
is also an unconditional jump in that case. */
}
\f
-/* We have determined that INSN is never reached, and are about to
- delete it. Print a warning if the user asked for one.
+/* We have determined that AVOIDED_INSN is never reached, and are
+ about to delete it. If the insn chain between AVOIDED_INSN and
+ FINISH contains more than one line from the current function, and
+ contains at least one operation, print a warning if the user asked
+ for it. If FINISH is NULL, look between AVOIDED_INSN and a LABEL.
- To try to make this warning more useful, this should only be called
- once per basic block not reached, and it only warns when the basic
- block contains more than one line from the current function, and
- contains at least one operation. CSE and inlining can duplicate insns,
- so it's possible to get spurious warnings from this. */
+ CSE and inlining can duplicate insns, so it's possible to get
+ spurious warnings from this. */
void
never_reached_warning (avoided_insn, finish)
rtx a_line_note = NULL;
int two_avoided_lines = 0, contains_insn = 0, reached_end = 0;
- if (! warn_notreached)
+ if (!warn_notreached)
return;
- /* Scan forwards, looking at LINE_NUMBER notes, until
- we hit a LABEL or we run out of insns. */
+ /* Back up to the first of any NOTEs preceding avoided_insn; flow passes
+ us the head of a block, a NOTE_INSN_BASIC_BLOCK, which often follows
+ the line note. */
+ insn = avoided_insn;
+ while (1)
+ {
+ rtx prev = PREV_INSN (insn);
+ if (prev == NULL_RTX
+ || GET_CODE (prev) != NOTE)
+ break;
+ insn = prev;
+ }
+
+ /* Scan forwards, looking at LINE_NUMBER notes, until we hit a LABEL
+ in case FINISH is NULL, otherwise until we run out of insns. */
- for (insn = avoided_insn; insn != NULL; insn = NEXT_INSN (insn))
+ for (; insn != NULL; insn = NEXT_INSN (insn))
{
- if (finish == NULL && GET_CODE (insn) == CODE_LABEL)
+ if ((finish == NULL && GET_CODE (insn) == CODE_LABEL)
+ || GET_CODE (insn) == BARRIER)
break;
if (GET_CODE (insn) == NOTE /* A line number note? */
reached_end = 1;
}
if (two_avoided_lines && contains_insn)
- warning_with_file_and_line (NOTE_SOURCE_FILE (a_line_note),
- NOTE_LINE_NUMBER (a_line_note),
- "will never be executed");
+ {
+ location_t locus;
+ locus.file = NOTE_SOURCE_FILE (a_line_note);
+ locus.line = NOTE_LINE_NUMBER (a_line_note);
+ warning ("%Hwill never be executed", &locus);
+ }
}
\f
/* Throughout LOC, redirect OLABEL to NLABEL. Treat null OLABEL or
int delete_unused;
{
rtx olabel = JUMP_LABEL (jump);
+ rtx note;
if (nlabel == olabel)
return 1;
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)
+ {
+ 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);
+ }
+ else
+ remove_note (jump, note);
+ }
+
/* If we're eliding the jump over exception cleanups at the end of a
function, move the function end note so that -Wreturn-type works. */
if (olabel && nlabel
if (redirect_jump (jump, nlabel, delete_unused))
{
+ /* 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);
return 1;
}
return -1;
}
+
+/* Return regno of the register REG and handle subregs too. */
+unsigned int
+reg_or_subregno (reg)
+ rtx reg;
+{
+ if (REG_P (reg))
+ return REGNO (reg);
+ if (GET_CODE (reg) == SUBREG)
+ return REGNO (SUBREG_REG (reg));
+ abort ();
+}