/* 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, 2004 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
/* This is the pathetic reminder of old fame of the jump-optimization pass
of the compiler. Now it contains basically set of utility function to
formerly used them. The JUMP_LABEL info is sometimes looked
at by later passes.
- The subroutines delete_insn, redirect_jump, and invert_jump are used
+ The subroutines redirect_jump and invert_jump are used
from other passes as well. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "tm_p.h"
#include "flags.h"
#include "expr.h"
#include "real.h"
#include "except.h"
+#include "diagnostic.h"
#include "toplev.h"
#include "reload.h"
#include "predict.h"
+#include "timevar.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 void mark_all_labels PARAMS ((rtx));
-static int duplicate_loop_exit_test PARAMS ((rtx));
-static void delete_computation PARAMS ((rtx));
-static void redirect_exp_1 PARAMS ((rtx *, rtx, rtx, rtx));
-static int redirect_exp PARAMS ((rtx, rtx, rtx));
-static void invert_exp_1 PARAMS ((rtx));
-static int invert_exp PARAMS ((rtx));
-static int returnjump_p_1 PARAMS ((rtx *, void *));
-static void delete_prior_computation PARAMS ((rtx, rtx));
-static void mark_modified_reg PARAMS ((rtx, rtx, void *));
+static rtx next_nonnote_insn_in_loop (rtx);
+static void init_label_info (rtx);
+static void mark_all_labels (rtx);
+static int duplicate_loop_exit_test (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 returnjump_p_1 (rtx *, void *);
+static void delete_prior_computation (rtx, rtx);
\f
/* Alternate entry into the jump optimizer. This entry point only rebuilds
the JUMP_LABEL field in jumping insns and REG_LABEL notes in non-jumping
instructions. */
void
-rebuild_jump_labels (f)
- rtx f;
+rebuild_jump_labels (rtx f)
{
- register rtx insn;
- int max_uid = 0;
-
- max_uid = init_label_info (f) + 1;
+ rtx insn;
+ 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
old code is happy.
*/
void
-cleanup_barriers ()
+cleanup_barriers (void)
{
rtx insn, next, prev;
for (insn = get_insns (); insn; insn = next)
}
}
\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 (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;
+copy_loop_headers (rtx f)
{
- register rtx insn, next;
+ rtx insn, next;
/* Now iterate optimizing jumps until nothing changes over one pass. */
for (insn = f; insn; insn = next)
{
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);
}
void
-purge_line_number_notes (f)
- rtx f;
+purge_line_number_notes (rtx f)
{
rtx last_note = 0;
rtx insn;
&& NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last_note)
&& NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last_note))
{
- delete_insn (insn);
+ delete_related_insns (insn);
continue;
}
/* 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
-init_label_info (f)
- rtx f;
+static void
+init_label_info (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.
Combine consecutive labels, and count uses of labels. */
static void
-mark_all_labels (f)
- rtx f;
+mark_all_labels (rtx f)
{
rtx insn;
values of regno_first_uid and regno_last_uid. */
static int
-duplicate_loop_exit_test (loop_start)
- rtx loop_start;
+duplicate_loop_exit_test (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 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
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))
/* 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_map = xcalloc (max_reg, sizeof (rtx));
REG_LOOP_TEST_P (reg) = 1;
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);
/* 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));
+ delete_related_insns (next_nonnote_insn (loop_start));
/* Clean up. */
if (reg_map)
}
\f
/* Move all block-beg, block-end, loop-beg, loop-cont, loop-vtop, loop-end,
- notes between START and END out before START. Assume that END is not
- such a note. START may be such a note. Returns the value of the new
- starting insn, which may be different if the original start was such a
- note. */
+ notes between START and END out before START. START and END may be such
+ notes. Returns the values of the new starting and ending insns, which
+ may be different if the original ones were such notes.
+ Return true if there were only such notes and no real instructions. */
-rtx
-squeeze_notes (start, end)
- rtx start, end;
+bool
+squeeze_notes (rtx* startp, rtx* endp)
{
+ rtx start = *startp;
+ rtx end = *endp;
+
rtx insn;
rtx next;
+ rtx last = NULL;
+ rtx past_end = NEXT_INSN (end);
- for (insn = start; insn != end; insn = next)
+ for (insn = start; insn != past_end; insn = next)
{
next = NEXT_INSN (insn);
if (GET_CODE (insn) == NOTE
PREV_INSN (next) = prev;
}
}
+ else
+ last = insn;
}
- return start;
+ /* There were no real instructions. */
+ if (start == past_end)
+ return true;
+
+ end = last;
+
+ *startp = start;
+ *endp = end;
+ return false;
}
\f
/* Return the label before INSN, or put a new label there. */
rtx
-get_label_before (insn)
- rtx insn;
+get_label_before (rtx insn)
{
rtx label;
/* Return the label after INSN, or put a new label there. */
rtx
-get_label_after (insn)
- rtx insn;
+get_label_after (rtx insn)
{
rtx label;
description should define REVERSIBLE_CC_MODE and REVERSE_CONDITION macros
to help this function avoid overhead in these cases. */
enum rtx_code
-reversed_comparison_code_parts (code, arg0, arg1, insn)
- rtx insn, arg0, arg1;
- enum rtx_code code;
+reversed_comparison_code_parts (enum rtx_code code, rtx arg0, rtx arg1, rtx insn)
{
enum machine_mode mode;
&& REVERSIBLE_CC_MODE (mode))
{
#ifdef REVERSE_CONDITION
- return REVERSE_CONDITION (code, mode);
+ return REVERSE_CONDITION (code, mode);
#endif
- return reverse_condition (code);
- }
+ return reverse_condition (code);
+ }
#endif
/* Try a few special cases based on the comparison code. */
switch (code)
{
- case GEU:
- case GTU:
- case LEU:
- case LTU:
- case NE:
- case EQ:
- /* It is always safe to reverse EQ and NE, even for the floating
- point. Similary the unsigned comparisons are never used for
- floating point so we can reverse them in the default way. */
- return reverse_condition (code);
- case ORDERED:
- case UNORDERED:
- case LTGT:
- case UNEQ:
- /* In case we already see unordered comparison, we can be sure to
- be dealing with floating point so we don't need any more tests. */
- return reverse_condition_maybe_unordered (code);
- case UNLT:
- case UNLE:
- case UNGT:
- case UNGE:
- /* We don't have safe way to reverse these yet. */
- return UNKNOWN;
- default:
- break;
+ case GEU:
+ case GTU:
+ case LEU:
+ case LTU:
+ case NE:
+ case EQ:
+ /* It is always safe to reverse EQ and NE, even for the floating
+ point. Similarly the unsigned comparisons are never used for
+ floating point so we can reverse them in the default way. */
+ return reverse_condition (code);
+ case ORDERED:
+ case UNORDERED:
+ case LTGT:
+ case UNEQ:
+ /* In case we already see unordered comparison, we can be sure to
+ be dealing with floating point so we don't need any more tests. */
+ return reverse_condition_maybe_unordered (code);
+ case UNLT:
+ case UNLE:
+ case UNGT:
+ case UNGE:
+ /* We don't have safe way to reverse these yet. */
+ return UNKNOWN;
+ default:
+ 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.
mode = GET_MODE (XEXP (comparison, 1));
break;
}
- /* We can get past reg-reg moves. This may be usefull for model
+ /* We can get past reg-reg moves. This may be useful for model
of i387 comparisons that first move flag registers around. */
if (REG_P (src))
{
}
}
- /* 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;
}
-/* An wrapper around the previous function to take COMPARISON as rtx
+/* A wrapper around the previous function to take COMPARISON as rtx
expression. This simplifies many callers. */
enum rtx_code
-reversed_comparison_code (comparison, insn)
- rtx comparison, insn;
+reversed_comparison_code (rtx comparison, rtx insn)
{
if (GET_RTX_CLASS (GET_CODE (comparison)) != '<')
return UNKNOWN;
Use reversed_comparison_code instead. */
enum rtx_code
-reverse_condition (code)
- enum rtx_code code;
+reverse_condition (enum rtx_code code)
{
switch (code)
{
that the target will support them too... */
enum rtx_code
-reverse_condition_maybe_unordered (code)
- enum rtx_code code;
+reverse_condition_maybe_unordered (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:
This IS safe for IEEE floating-point. */
enum rtx_code
-swap_condition (code)
- enum rtx_code code;
+swap_condition (enum rtx_code code)
{
switch (code)
{
CODE is returned. */
enum rtx_code
-unsigned_condition (code)
- enum rtx_code code;
+unsigned_condition (enum rtx_code code)
{
switch (code)
{
/* Similarly, return the signed version of a comparison. */
enum rtx_code
-signed_condition (code)
- enum rtx_code code;
+signed_condition (enum rtx_code code)
{
switch (code)
{
}
}
\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
-comparison_dominates_p (code1, code2)
- enum rtx_code code1, code2;
+comparison_dominates_p (enum rtx_code code1, enum rtx_code code2)
{
/* UNKNOWN comparison codes can happen as a result of trying to revert
comparison codes.
/* Return 1 if INSN is an unconditional jump and nothing else. */
int
-simplejump_p (insn)
- rtx insn;
+simplejump_p (rtx insn)
{
return (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) == SET
/* Return nonzero if INSN is a (possibly) conditional jump
and nothing more.
- Use this function is deprecated, since we need to support combined
+ Use of this function is deprecated, since we need to support combined
branch and compare insns. Use any_condjump_p instead whenever possible. */
int
-condjump_p (insn)
- rtx insn;
+condjump_p (rtx insn)
{
- register rtx x = PATTERN (insn);
+ rtx x = PATTERN (insn);
if (GET_CODE (x) != SET
|| GET_CODE (SET_DEST (x)) != PC)
branch and compare insns. Use any_condjump_p instead whenever possible. */
int
-condjump_in_parallel_p (insn)
- rtx insn;
+condjump_in_parallel_p (rtx insn)
{
- register rtx x = PATTERN (insn);
+ rtx x = PATTERN (insn);
if (GET_CODE (x) != PARALLEL)
return 0;
/* Return set of PC, otherwise NULL. */
rtx
-pc_set (insn)
- rtx insn;
+pc_set (rtx insn)
{
rtx pat;
if (GET_CODE (insn) != JUMP_INSN)
possibly bundled inside a PARALLEL. */
int
-any_uncondjump_p (insn)
- rtx insn;
+any_uncondjump_p (rtx insn)
{
rtx x = pc_set (insn);
if (!x)
Note that unlike condjump_p it returns false for unconditional jumps. */
int
-any_condjump_p (insn)
- rtx insn;
+any_condjump_p (rtx insn)
{
rtx x = pc_set (insn);
enum rtx_code a, b;
/* Return the label of a conditional jump. */
rtx
-condjump_label (insn)
- rtx insn;
+condjump_label (rtx insn)
{
rtx x = pc_set (insn);
/* Return true if INSN is a (possibly conditional) return insn. */
static int
-returnjump_p_1 (loc, data)
- rtx *loc;
- void *data ATTRIBUTE_UNUSED;
+returnjump_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
{
rtx x = *loc;
- return x && GET_CODE (x) == RETURN;
+
+ return x && (GET_CODE (x) == RETURN
+ || (GET_CODE (x) == SET && SET_IS_RETURN_P (x)));
}
int
-returnjump_p (insn)
- rtx insn;
+returnjump_p (rtx insn)
{
if (GET_CODE (insn) != JUMP_INSN)
return 0;
nothing more. */
int
-onlyjump_p (insn)
- rtx insn;
+onlyjump_p (rtx insn)
{
rtx set;
#ifdef HAVE_cc0
+/* Return nonzero if X is an RTX that only sets the condition codes
+ and has no side effects. */
+
+int
+only_sets_cc0_p (rtx x)
+{
+ if (! x)
+ return 0;
+
+ if (INSN_P (x))
+ x = PATTERN (x);
+
+ return sets_cc0_p (x) == 1 && ! side_effects_p (x);
+}
+
/* Return 1 if X is an RTX that does nothing but set the condition codes
and CLOBBER or USE registers.
Return -1 if X does explicitly set the condition codes,
but also does other things. */
int
-sets_cc0_p (x)
- rtx x ATTRIBUTE_UNUSED;
+sets_cc0_p (rtx x)
{
+ if (! x)
+ return 0;
+
+ if (INSN_P (x))
+ x = PATTERN (x);
+
if (GET_CODE (x) == SET && SET_DEST (x) == cc0_rtx)
return 1;
if (GET_CODE (x) == PARALLEL)
a USE or CLOBBER. */
rtx
-follow_jumps (label)
- rtx label;
+follow_jumps (rtx label)
{
- register rtx insn;
- register rtx next;
- register rtx value = label;
- register int depth;
+ rtx insn;
+ rtx next;
+ rtx value = label;
+ int depth;
for (depth = 0;
(depth < 10
that loop-optimization is done with. */
void
-mark_jump_label (x, insn, in_mem)
- register rtx x;
- rtx insn;
- int in_mem;
+mark_jump_label (rtx x, rtx insn, int in_mem)
{
- register RTX_CODE code = GET_CODE (x);
- register int i;
- register const char *fmt;
+ RTX_CODE code = GET_CODE (x);
+ int i;
+ const char *fmt;
switch (code)
{
case PC:
case CC0:
case REG:
- case SUBREG:
case CONST_INT:
case CONST_DOUBLE:
case CLOBBER:
mark_jump_label (XEXP (x, i), insn, in_mem);
else if (fmt[i] == 'E')
{
- register int j;
+ int j;
for (j = 0; j < XVECLEN (x, i); j++)
mark_jump_label (XVECEXP (x, i, j), insn, in_mem);
}
if that's what the previous thing was. */
void
-delete_jump (insn)
- rtx insn;
+delete_jump (rtx insn)
{
- register rtx set = single_set (insn);
+ rtx set = single_set (insn);
if (set && GET_CODE (SET_DEST (set)) == PC)
delete_computation (insn);
/* Verify INSN is a BARRIER and delete it. */
void
-delete_barrier (insn)
- rtx insn;
+delete_barrier (rtx insn)
{
if (GET_CODE (insn) != BARRIER)
abort ();
which is a REG_DEAD note associated with INSN. */
static void
-delete_prior_computation (note, insn)
- rtx note;
- rtx insn;
+delete_prior_computation (rtx note, rtx insn)
{
rtx our_prev;
rtx reg = XEXP (note, 0);
/* If we reach a CALL which is not calling a const function
or the callee pops the arguments, then give up. */
if (GET_CODE (our_prev) == CALL_INSN
- && (! CONST_CALL_P (our_prev)
+ && (! CONST_OR_PURE_CALL_P (our_prev)
|| GET_CODE (pat) != SET || GET_CODE (SET_SRC (pat)) != CALL))
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;
int dest_endregno
= (dest_regno
+ (dest_regno < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (dest_regno,
- GET_MODE (SET_DEST (pat))) : 1));
+ ? hard_regno_nregs[dest_regno]
+ [GET_MODE (SET_DEST (pat))] : 1));
int regno = REGNO (reg);
int endregno
= (regno
+ (regno < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (regno, GET_MODE (reg)) : 1));
+ ? hard_regno_nregs[regno][GET_MODE (reg)] : 1));
if (dest_regno >= regno
&& dest_endregno <= endregno)
delete the insn that set it. */
static void
-delete_computation (insn)
- rtx insn;
+delete_computation (rtx insn)
{
rtx note, next;
delete_prior_computation (note, insn);
}
- delete_insn (insn);
+ delete_related_insns (insn);
}
\f
-/* Delete insn INSN from the chain of insns and update label ref counts.
- May delete some following insns as a consequence; may even delete
- a label elsewhere and insns that follow it.
+/* Delete insn INSN from the chain of insns and update label ref counts
+ 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. */
rtx
-delete_insn (insn)
- register rtx insn;
+delete_related_insns (rtx insn)
{
- register rtx next = NEXT_INSN (insn);
- register rtx prev = PREV_INSN (insn);
- register int was_code_label = (GET_CODE (insn) == CODE_LABEL);
- register int dont_really_delete = 0;
+ int was_code_label = (GET_CODE (insn) == CODE_LABEL);
rtx note;
+ rtx next = NEXT_INSN (insn), prev = PREV_INSN (insn);
while (next && INSN_DELETED_P (next))
next = NEXT_INSN (next);
if (INSN_DELETED_P (insn))
return next;
- if (was_code_label)
- remove_node_from_expr_list (insn, &nonlocal_goto_handler_labels);
-
- /* Don't delete user-declared labels. When optimizing, convert them
- to special NOTEs instead. When not optimizing, leave them alone. */
- if (was_code_label && LABEL_NAME (insn) != 0)
- {
- if (optimize)
- {
- const char *name = LABEL_NAME (insn);
- PUT_CODE (insn, NOTE);
- NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED_LABEL;
- NOTE_SOURCE_FILE (insn) = name;
- }
-
- dont_really_delete = 1;
- }
- else
- /* Mark this insn as deleted. */
- INSN_DELETED_P (insn) = 1;
+ delete_insn (insn);
/* If instruction is followed by a barrier,
delete the barrier too. */
if (next != 0 && GET_CODE (next) == BARRIER)
- {
- INSN_DELETED_P (next) = 1;
- next = NEXT_INSN (next);
- }
-
- /* Patch out INSN (and the barrier if any) */
-
- if (! dont_really_delete)
- {
- if (prev)
- {
- NEXT_INSN (prev) = next;
- if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
- NEXT_INSN (XVECEXP (PATTERN (prev), 0,
- XVECLEN (PATTERN (prev), 0) - 1)) = next;
- }
-
- if (next)
- {
- PREV_INSN (next) = prev;
- if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE)
- PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = prev;
- }
-
- if (prev && NEXT_INSN (prev) == 0)
- set_last_insn (prev);
- }
+ delete_insn (next);
/* If deleting a jump, decrement the count of the label,
and delete the label if it is now unused. */
{
rtx lab = JUMP_LABEL (insn), lab_next;
- if (--LABEL_NUSES (lab) == 0)
+ if (LABEL_NUSES (lab) == 0)
{
/* This can delete NEXT or PREV,
either directly if NEXT is JUMP_LABEL (INSN),
or indirectly through more levels of jumps. */
- delete_insn (lab);
+ delete_related_insns (lab);
/* I feel a little doubtful about this loop,
but I see no clean and sure alternative way
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 preceeding
+ We may not be able to kill the label immediately preceding
just yet, as it might be referenced in code leading up to
the tablejump. */
- delete_insn (lab_next);
+ delete_related_insns (lab_next);
}
}
int len = XVECLEN (pat, diff_vec_p);
for (i = 0; i < len; i++)
- if (--LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0)) == 0)
- delete_insn (XEXP (XVECEXP (pat, diff_vec_p, i), 0));
+ if (LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0)) == 0)
+ delete_related_insns (XEXP (XVECEXP (pat, diff_vec_p, i), 0));
while (next && INSN_DELETED_P (next))
next = NEXT_INSN (next);
return next;
if (REG_NOTE_KIND (note) == REG_LABEL
/* This could also be a NOTE_INSN_DELETED_LABEL note. */
&& GET_CODE (XEXP (note, 0)) == CODE_LABEL)
- if (--LABEL_NUSES (XEXP (note, 0)) == 0)
- delete_insn (XEXP (note, 0));
+ if (LABEL_NUSES (XEXP (note, 0)) == 0)
+ delete_related_insns (XEXP (note, 0));
while (prev && (INSN_DELETED_P (prev) || GET_CODE (prev) == NOTE))
prev = PREV_INSN (prev);
&& GET_CODE (NEXT_INSN (insn)) == JUMP_INSN
&& (GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_VEC
|| GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC))
- next = delete_insn (NEXT_INSN (insn));
+ next = delete_related_insns (NEXT_INSN (insn));
/* If INSN was a label, delete insns following it if now unreachable. */
if (was_code_label && prev && GET_CODE (prev) == BARRIER)
{
- register RTX_CODE code;
+ RTX_CODE code;
while (next != 0
&& (GET_RTX_CLASS (code = GET_CODE (next)) == 'i'
|| code == NOTE || code == BARRIER
deletion of unreachable code, after a different label.
As long as the value from this recursive call is correct,
this invocation functions correctly. */
- next = delete_insn (next);
+ next = delete_related_insns (next);
}
}
return next;
}
-
-/* Advance from INSN till reaching something not deleted
- then return that. May return INSN itself. */
-
-rtx
-next_nondeleted_insn (insn)
- rtx insn;
-{
- while (INSN_DELETED_P (insn))
- insn = NEXT_INSN (insn);
- return insn;
-}
\f
/* Delete a range of insns from FROM to TO, inclusive.
This is for the sake of peephole optimization, so assume
peephole insn that will replace them. */
void
-delete_for_peephole (from, to)
- register rtx from, to;
+delete_for_peephole (rtx from, rtx to)
{
- register rtx insn = from;
+ rtx insn = from;
while (1)
{
- register rtx next = NEXT_INSN (insn);
- register rtx prev = PREV_INSN (insn);
+ rtx next = NEXT_INSN (insn);
+ rtx prev = PREV_INSN (insn);
if (GET_CODE (insn) != NOTE)
{
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)
- rtx avoided_insn;
+never_reached_warning (rtx avoided_insn, rtx finish)
{
rtx insn;
rtx a_line_note = NULL;
- int two_avoided_lines = 0;
- int contains_insn = 0;
+ 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 (GET_CODE (insn) == CODE_LABEL)
+ if ((finish == NULL && GET_CODE (insn) == CODE_LABEL)
+ || GET_CODE (insn) == BARRIER)
break;
- else if (GET_CODE (insn) == NOTE /* A line number note? */
- && NOTE_LINE_NUMBER (insn) >= 0)
+
+ if (GET_CODE (insn) == NOTE /* A line number note? */
+ && NOTE_LINE_NUMBER (insn) >= 0)
{
if (a_line_note == NULL)
a_line_note = insn;
!= NOTE_LINE_NUMBER (insn));
}
else if (INSN_P (insn))
- contains_insn = 1;
+ {
+ if (reached_end)
+ break;
+ contains_insn = 1;
+ }
+
+ if (insn == finish)
+ 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
NLABEL as a return. Accrue modifications into the change group. */
static void
-redirect_exp_1 (loc, olabel, nlabel, insn)
- rtx *loc;
- rtx olabel, nlabel;
- rtx insn;
+redirect_exp_1 (rtx *loc, rtx olabel, rtx nlabel, rtx insn)
{
- register rtx x = *loc;
- register RTX_CODE code = GET_CODE (x);
- register int i;
- register const char *fmt;
+ rtx x = *loc;
+ RTX_CODE code = GET_CODE (x);
+ int i;
+ const char *fmt;
if (code == LABEL_REF)
{
redirect_exp_1 (&XEXP (x, i), olabel, nlabel, insn);
else if (fmt[i] == 'E')
{
- register int j;
+ int j;
for (j = 0; j < XVECLEN (x, i); j++)
redirect_exp_1 (&XVECEXP (x, i, j), olabel, nlabel, insn);
}
/* Similar, but apply the change group and report success or failure. */
static int
-redirect_exp (olabel, nlabel, insn)
- rtx olabel, nlabel;
- rtx insn;
+redirect_exp (rtx olabel, rtx nlabel, rtx insn)
{
rtx *loc;
not see how to do that. */
int
-redirect_jump_1 (jump, nlabel)
- rtx jump, nlabel;
+redirect_jump_1 (rtx jump, rtx nlabel)
{
int ochanges = num_validated_changes ();
rtx *loc;
(this can only occur for NLABEL == 0). */
int
-redirect_jump (jump, nlabel, delete_unused)
- rtx jump, nlabel;
- int delete_unused;
+redirect_jump (rtx jump, rtx nlabel, int delete_unused)
{
- register rtx olabel = JUMP_LABEL (jump);
+ 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
&& NOTE_LINE_NUMBER (NEXT_INSN (olabel)) == NOTE_INSN_FUNCTION_END)
emit_note_after (NOTE_INSN_FUNCTION_END, nlabel);
- if (olabel && --LABEL_NUSES (olabel) == 0 && delete_unused)
- delete_insn (olabel);
+ if (olabel && --LABEL_NUSES (olabel) == 0 && delete_unused
+ /* Undefined labels will remain outside the insn stream. */
+ && INSN_UID (olabel))
+ delete_related_insns (olabel);
return 1;
}
Accrue the modifications into the change group. */
static void
-invert_exp_1 (insn)
- rtx insn;
+invert_exp_1 (rtx insn)
{
- register RTX_CODE code;
+ RTX_CODE code;
rtx x = pc_set (insn);
if (!x)
if (code == IF_THEN_ELSE)
{
- register rtx comp = XEXP (x, 0);
- register rtx tem;
+ rtx comp = XEXP (x, 0);
+ rtx tem;
enum rtx_code reversed_code;
/* We can do this in two ways: The preferable way, which can only
matches a pattern. */
static int
-invert_exp (insn)
- rtx insn;
+invert_exp (rtx insn)
{
invert_exp_1 (insn);
if (num_validated_changes () == 0)
inversion and redirection. */
int
-invert_jump_1 (jump, nlabel)
- rtx jump, nlabel;
+invert_jump_1 (rtx jump, rtx nlabel)
{
int ochanges;
NLABEL instead of where it jumps now. Return true if successful. */
int
-invert_jump (jump, nlabel, delete_unused)
- rtx jump, nlabel;
- int delete_unused;
+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
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;
case when the PLUS is inside a MEM. */
int
-rtx_renumbered_equal_p (x, y)
- rtx x, y;
+rtx_renumbered_equal_p (rtx x, rtx y)
{
- register int i;
- register RTX_CODE code = GET_CODE (x);
- register const char *fmt;
+ int i;
+ RTX_CODE code = GET_CODE (x);
+ const char *fmt;
if (x == y)
return 1;
case CC0:
case ADDR_VEC:
case ADDR_DIFF_VEC:
- return 0;
-
case CONST_INT:
- return INTVAL (x) == INTVAL (y);
+ return 0;
case LABEL_REF:
/* We can't assume nonlocal labels have their following insns yet. */
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
- register int j;
+ int j;
switch (fmt[i])
{
case 'w':
case 'u':
if (XEXP (x, i) != XEXP (y, i))
return 0;
- /* fall through. */
+ /* Fall through. */
case '0':
break;
return -1. Any rtx is valid for X. */
int
-true_regnum (x)
- rtx x;
+true_regnum (rtx x)
{
if (GET_CODE (x) == REG)
{
}
return -1;
}
-\f
-/* Optimize code of the form:
-
- for (x = a[i]; x; ...)
- ...
- for (x = a[i]; x; ...)
- ...
- foo:
-
- Loop optimize will change the above code into
-
- if (x = a[i])
- for (;;)
- { ...; if (! (x = ...)) break; }
- if (x = a[i])
- for (;;)
- { ...; if (! (x = ...)) break; }
- foo:
-
- In general, if the first test fails, the program can branch
- directly to `foo' and skip the second try which is doomed to fail.
- We run this after loop optimization and before flow analysis. */
-
-/* When comparing the insn patterns, we track the fact that different
- pseudo-register numbers may have been used in each computation.
- The following array stores an equivalence -- same_regs[I] == J means
- that pseudo register I was used in the first set of tests in a context
- where J was used in the second set. We also count the number of such
- pending equivalences. If nonzero, the expressions really aren't the
- same. */
-
-static int *same_regs;
-
-static int num_same_regs;
-
-/* Track any registers modified between the target of the first jump and
- the second jump. They never compare equal. */
-
-static char *modified_regs;
-
-/* Record if memory was modified. */
-
-static int modified_mem;
-
-/* Called via note_stores on each insn between the target of the first
- branch and the second branch. It marks any changed registers. */
-
-static void
-mark_modified_reg (dest, x, data)
- rtx dest;
- rtx x;
- void *data ATTRIBUTE_UNUSED;
-{
- int regno;
- unsigned int i;
-
- if (GET_CODE (dest) == SUBREG)
- dest = SUBREG_REG (dest);
-
- if (GET_CODE (dest) == MEM)
- modified_mem = 1;
-
- if (GET_CODE (dest) != REG)
- return;
-
- regno = REGNO (dest);
- if (regno >= FIRST_PSEUDO_REGISTER)
- modified_regs[regno] = 1;
- /* Don't consider a hard condition code register as modified,
- if it is only being set. thread_jumps will check if it is set
- to the same value. */
- else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC
- || GET_CODE (x) != SET
- || ! rtx_equal_p (dest, SET_DEST (x))
- || HARD_REGNO_NREGS (regno, GET_MODE (dest)) != 1)
- for (i = 0; i < HARD_REGNO_NREGS (regno, GET_MODE (dest)); i++)
- modified_regs[regno + i] = 1;
-}
-
-/* F is the first insn in the chain of insns. */
-void
-thread_jumps (f, max_reg, flag_before_loop)
- rtx f;
- int max_reg;
- int flag_before_loop;
+/* Return regno of the register REG and handle subregs too. */
+unsigned int
+reg_or_subregno (rtx reg)
{
- /* Basic algorithm is to find a conditional branch,
- the label it may branch to, and the branch after
- that label. If the two branches test the same condition,
- walk back from both branch paths until the insn patterns
- differ, or code labels are hit. If we make it back to
- the target of the first branch, then we know that the first branch
- will either always succeed or always fail depending on the relative
- senses of the two branches. So adjust the first branch accordingly
- in this case. */
-
- rtx label, b1, b2, t1, t2;
- enum rtx_code code1, code2;
- rtx b1op0, b1op1, b2op0, b2op1;
- int changed = 1;
- int i;
- int *all_reset;
- enum rtx_code reversed_code1, reversed_code2;
-
- /* Allocate register tables and quick-reset table. */
- modified_regs = (char *) xmalloc (max_reg * sizeof (char));
- same_regs = (int *) xmalloc (max_reg * sizeof (int));
- all_reset = (int *) xmalloc (max_reg * sizeof (int));
- for (i = 0; i < max_reg; i++)
- all_reset[i] = -1;
-
- while (changed)
- {
- changed = 0;
-
- for (b1 = f; b1; b1 = NEXT_INSN (b1))
- {
- rtx set;
- rtx set2;
-
- /* Get to a candidate branch insn. */
- if (GET_CODE (b1) != JUMP_INSN
- || ! any_condjump_p (b1) || JUMP_LABEL (b1) == 0)
- continue;
-
- memset (modified_regs, 0, max_reg * sizeof (char));
- modified_mem = 0;
-
- memcpy (same_regs, all_reset, max_reg * sizeof (int));
- num_same_regs = 0;
-
- label = JUMP_LABEL (b1);
-
- /* Look for a branch after the target. Record any registers and
- memory modified between the target and the branch. Stop when we
- get to a label since we can't know what was changed there. */
- for (b2 = NEXT_INSN (label); b2; b2 = NEXT_INSN (b2))
- {
- if (GET_CODE (b2) == CODE_LABEL)
- break;
-
- else if (GET_CODE (b2) == JUMP_INSN)
- {
- /* If this is an unconditional jump and is the only use of
- its target label, we can follow it. */
- if (any_uncondjump_p (b2)
- && onlyjump_p (b2)
- && JUMP_LABEL (b2) != 0
- && LABEL_NUSES (JUMP_LABEL (b2)) == 1)
- {
- b2 = JUMP_LABEL (b2);
- continue;
- }
- else
- break;
- }
-
- if (GET_CODE (b2) != CALL_INSN && GET_CODE (b2) != INSN)
- continue;
-
- if (GET_CODE (b2) == CALL_INSN)
- {
- modified_mem = 1;
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (call_used_regs[i] && ! fixed_regs[i]
- && i != STACK_POINTER_REGNUM
- && i != FRAME_POINTER_REGNUM
- && i != HARD_FRAME_POINTER_REGNUM
- && i != ARG_POINTER_REGNUM)
- modified_regs[i] = 1;
- }
-
- note_stores (PATTERN (b2), mark_modified_reg, NULL);
- }
-
- /* Check the next candidate branch insn from the label
- of the first. */
- if (b2 == 0
- || GET_CODE (b2) != JUMP_INSN
- || b2 == b1
- || !any_condjump_p (b2)
- || !onlyjump_p (b2))
- continue;
- set = pc_set (b1);
- set2 = pc_set (b2);
-
- /* Get the comparison codes and operands, reversing the
- codes if appropriate. If we don't have comparison codes,
- we can't do anything. */
- b1op0 = XEXP (XEXP (SET_SRC (set), 0), 0);
- b1op1 = XEXP (XEXP (SET_SRC (set), 0), 1);
- code1 = GET_CODE (XEXP (SET_SRC (set), 0));
- reversed_code1 = code1;
- if (XEXP (SET_SRC (set), 1) == pc_rtx)
- code1 = reversed_comparison_code (XEXP (SET_SRC (set), 0), b1);
- else
- reversed_code1 = reversed_comparison_code (XEXP (SET_SRC (set), 0), b1);
-
- b2op0 = XEXP (XEXP (SET_SRC (set2), 0), 0);
- b2op1 = XEXP (XEXP (SET_SRC (set2), 0), 1);
- code2 = GET_CODE (XEXP (SET_SRC (set2), 0));
- reversed_code2 = code2;
- if (XEXP (SET_SRC (set2), 1) == pc_rtx)
- code2 = reversed_comparison_code (XEXP (SET_SRC (set2), 0), b2);
- else
- reversed_code2 = reversed_comparison_code (XEXP (SET_SRC (set2), 0), b2);
-
- /* If they test the same things and knowing that B1 branches
- tells us whether or not B2 branches, check if we
- can thread the branch. */
- if (rtx_equal_for_thread_p (b1op0, b2op0, b2)
- && rtx_equal_for_thread_p (b1op1, b2op1, b2)
- && (comparison_dominates_p (code1, code2)
- || comparison_dominates_p (code1, reversed_code2)))
-
- {
- t1 = prev_nonnote_insn (b1);
- t2 = prev_nonnote_insn (b2);
-
- while (t1 != 0 && t2 != 0)
- {
- if (t2 == label)
- {
- /* We have reached the target of the first branch.
- If there are no pending register equivalents,
- we know that this branch will either always
- succeed (if the senses of the two branches are
- the same) or always fail (if not). */
- rtx new_label;
-
- if (num_same_regs != 0)
- break;
-
- if (comparison_dominates_p (code1, code2))
- new_label = JUMP_LABEL (b2);
- else
- new_label = get_label_after (b2);
-
- if (JUMP_LABEL (b1) != new_label)
- {
- rtx prev = PREV_INSN (new_label);
-
- if (flag_before_loop
- && GET_CODE (prev) == NOTE
- && NOTE_LINE_NUMBER (prev) == NOTE_INSN_LOOP_BEG)
- {
- /* Don't thread to the loop label. If a loop
- label is reused, loop optimization will
- be disabled for that loop. */
- new_label = gen_label_rtx ();
- emit_label_after (new_label, PREV_INSN (prev));
- }
- changed |= redirect_jump (b1, new_label, 1);
- }
- break;
- }
-
- /* If either of these is not a normal insn (it might be
- a JUMP_INSN, CALL_INSN, or CODE_LABEL) we fail. (NOTEs
- have already been skipped above.) Similarly, fail
- if the insns are different. */
- if (GET_CODE (t1) != INSN || GET_CODE (t2) != INSN
- || recog_memoized (t1) != recog_memoized (t2)
- || ! rtx_equal_for_thread_p (PATTERN (t1),
- PATTERN (t2), t2))
- break;
-
- t1 = prev_nonnote_insn (t1);
- t2 = prev_nonnote_insn (t2);
- }
- }
- }
- }
-
- /* Clean up. */
- free (modified_regs);
- free (same_regs);
- free (all_reset);
-}
-\f
-/* This is like RTX_EQUAL_P except that it knows about our handling of
- possibly equivalent registers and knows to consider volatile and
- modified objects as not equal.
-
- YINSN is the insn containing Y. */
-
-int
-rtx_equal_for_thread_p (x, y, yinsn)
- rtx x, y;
- rtx yinsn;
-{
- register int i;
- register int j;
- register enum rtx_code code;
- register const char *fmt;
-
- code = GET_CODE (x);
- /* Rtx's of different codes cannot be equal. */
- if (code != GET_CODE (y))
- return 0;
-
- /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
- (REG:SI x) and (REG:HI x) are NOT equivalent. */
-
- if (GET_MODE (x) != GET_MODE (y))
- return 0;
-
- /* For floating-point, consider everything unequal. This is a bit
- pessimistic, but this pass would only rarely do anything for FP
- anyway. */
- if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
- && FLOAT_MODE_P (GET_MODE (x)) && ! flag_unsafe_math_optimizations)
- return 0;
-
- /* For commutative operations, the RTX match if the operand match in any
- order. Also handle the simple binary and unary cases without a loop. */
- if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
- return ((rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn)
- && rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 1), yinsn))
- || (rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 1), yinsn)
- && rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 0), yinsn)));
- else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
- return (rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn)
- && rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 1), yinsn));
- else if (GET_RTX_CLASS (code) == '1')
- return rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn);
-
- /* Handle special-cases first. */
- switch (code)
- {
- case REG:
- if (REGNO (x) == REGNO (y) && ! modified_regs[REGNO (x)])
- return 1;
-
- /* If neither is user variable or hard register, check for possible
- equivalence. */
- if (REG_USERVAR_P (x) || REG_USERVAR_P (y)
- || REGNO (x) < FIRST_PSEUDO_REGISTER
- || REGNO (y) < FIRST_PSEUDO_REGISTER)
- return 0;
-
- if (same_regs[REGNO (x)] == -1)
- {
- same_regs[REGNO (x)] = REGNO (y);
- num_same_regs++;
-
- /* If this is the first time we are seeing a register on the `Y'
- side, see if it is the last use. If not, we can't thread the
- jump, so mark it as not equivalent. */
- if (REGNO_LAST_UID (REGNO (y)) != INSN_UID (yinsn))
- return 0;
-
- return 1;
- }
- else
- return (same_regs[REGNO (x)] == (int) REGNO (y));
-
- break;
-
- case MEM:
- /* If memory modified or either volatile, not equivalent.
- Else, check address. */
- if (modified_mem || MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
- return 0;
-
- return rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn);
-
- case ASM_INPUT:
- if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
- return 0;
-
- break;
-
- case SET:
- /* Cancel a pending `same_regs' if setting equivalenced registers.
- Then process source. */
- if (GET_CODE (SET_DEST (x)) == REG
- && GET_CODE (SET_DEST (y)) == REG)
- {
- if (same_regs[REGNO (SET_DEST (x))] == (int) REGNO (SET_DEST (y)))
- {
- same_regs[REGNO (SET_DEST (x))] = -1;
- num_same_regs--;
- }
- else if (REGNO (SET_DEST (x)) != REGNO (SET_DEST (y)))
- return 0;
- }
- else
- {
- if (rtx_equal_for_thread_p (SET_DEST (x), SET_DEST (y), yinsn) == 0)
- return 0;
- }
-
- return rtx_equal_for_thread_p (SET_SRC (x), SET_SRC (y), yinsn);
-
- case LABEL_REF:
- return XEXP (x, 0) == XEXP (y, 0);
-
- case SYMBOL_REF:
- return XSTR (x, 0) == XSTR (y, 0);
-
- default:
- break;
- }
-
- if (x == y)
- return 1;
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- switch (fmt[i])
- {
- case 'w':
- if (XWINT (x, i) != XWINT (y, i))
- return 0;
- break;
-
- case 'n':
- case 'i':
- if (XINT (x, i) != XINT (y, i))
- return 0;
- break;
-
- case 'V':
- case 'E':
- /* Two vectors must have the same length. */
- if (XVECLEN (x, i) != XVECLEN (y, i))
- return 0;
-
- /* And the corresponding elements must match. */
- for (j = 0; j < XVECLEN (x, i); j++)
- if (rtx_equal_for_thread_p (XVECEXP (x, i, j),
- XVECEXP (y, i, j), yinsn) == 0)
- return 0;
- break;
-
- case 'e':
- if (rtx_equal_for_thread_p (XEXP (x, i), XEXP (y, i), yinsn) == 0)
- return 0;
- break;
-
- case 'S':
- case 's':
- if (strcmp (XSTR (x, i), XSTR (y, i)))
- return 0;
- break;
-
- case 'u':
- /* These are just backpointers, so they don't matter. */
- break;
-
- case '0':
- case 't':
- break;
-
- /* It is believed that rtx's at this level will never
- contain anything but integers and other rtx's,
- except for within LABEL_REFs and SYMBOL_REFs. */
- default:
- abort ();
- }
- }
- return 1;
+ if (REG_P (reg))
+ return REGNO (reg);
+ if (GET_CODE (reg) == SUBREG)
+ return REGNO (SUBREG_REG (reg));
+ abort ();
}