/* Optimize jump instructions, for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997
- 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
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 init_label_info (rtx);
+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 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)
{
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))++;
+ 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
-void
-copy_loop_headers (f)
- rtx f;
-{
- rtx insn, next;
- /* Now iterate optimizing jumps until nothing changes over one pass. */
- for (insn = f; insn; insn = next)
- {
- rtx temp, temp1;
-
- next = NEXT_INSN (insn);
-
- /* See if this is a NOTE_INSN_LOOP_BEG followed by an unconditional
- jump. Try to optimize by duplicating the loop exit test if so.
- This is only safe immediately after regscan, because it uses
- 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
- && any_uncondjump_p (temp1) && onlyjump_p (temp1))
- {
- temp = PREV_INSN (insn);
- if (duplicate_loop_exit_test (insn))
- {
- next = NEXT_INSN (temp);
- }
- }
- }
-}
void
-purge_line_number_notes (f)
- rtx f;
+purge_line_number_notes (rtx f)
{
rtx last_note = 0;
rtx 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
-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;
for (insn = f; insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
- if (GET_CODE (insn) == CALL_INSN
- && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
- {
- mark_all_labels (XEXP (PATTERN (insn), 0));
- mark_all_labels (XEXP (PATTERN (insn), 1));
- mark_all_labels (XEXP (PATTERN (insn), 2));
-
- /* Canonicalize the tail recursion label attached to the
- CALL_PLACEHOLDER insn. */
- if (XEXP (PATTERN (insn), 3))
- {
- rtx label_ref = gen_rtx_LABEL_REF (VOIDmode,
- XEXP (PATTERN (insn), 3));
- mark_jump_label (label_ref, insn, 0);
- XEXP (PATTERN (insn), 3) = XEXP (label_ref, 0);
- }
-
- continue;
- }
-
mark_jump_label (PATTERN (insn), insn, 0);
if (! INSN_DELETED_P (insn) && GET_CODE (insn) == JUMP_INSN)
{
}
}
}
-
-/* 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;
- rtx loop_pre_header_label;
-
- /* 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));
- }
- }
- loop_pre_header_label = gen_label_rtx ();
-
- /* 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_nonnote_insn (prev_nonnote_insn (label))
- == next_nonnote_insn (loop_start)))
- {
- predict_insn_def (copy, PRED_LOOP_HEADER, TAKEN);
- /* To keep pre-header, we need to redirect all loop
- entrances before the LOOP_BEG note. */
- redirect_jump (copy, loop_pre_header_label, 0);
- }
- else
- predict_insn_def (copy, PRED_LOOP_HEADER, NOT_TAKEN);
- }
- }
- 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);
- emit_barrier_before (loop_start);
- }
-
- emit_label_before (loop_pre_header_label, 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_related_insns (next_nonnote_insn (loop_start));
-
- /* Clean up. */
- if (reg_map)
- free (reg_map);
-
- return 1;
-}
\f
/* Move all block-beg, block-end, loop-beg, loop-cont, loop-vtop, loop-end,
notes between START and END out before START. START and END may be such
Return true if there were only such notes and no real instructions. */
bool
-squeeze_notes (startp, endp)
- rtx* startp;
- rtx* endp;
+squeeze_notes (rtx* startp, rtx* endp)
{
rtx start = *startp;
rtx end = *endp;
/* 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;
/* If this is not actually a comparison, we can't reverse it. */
- if (GET_RTX_CLASS (code) != '<')
+ if (GET_RTX_CLASS (code) != RTX_COMPARE
+ && GET_RTX_CLASS (code) != RTX_COMM_COMPARE)
return UNKNOWN;
mode = GET_MODE (arg0);
if (mode == VOIDmode)
mode = GET_MODE (arg1);
- /* First see if machine description supply us way to reverse the comparison.
- Give it priority over everything else to allow machine description to do
- tricks. */
-#ifdef REVERSIBLE_CC_MODE
+ /* First see if machine description supplies us way to reverse the
+ comparison. Give it priority over everything else to allow
+ machine description to do tricks. */
if (GET_MODE_CLASS (mode) == MODE_CC
&& REVERSIBLE_CC_MODE (mode))
{
#endif
return reverse_condition (code);
}
-#endif
/* Try a few special cases based on the comparison code. */
switch (code)
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
+ 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:
break;
}
- 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.
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)) != '<')
+ if (!COMPARISON_P (comparison))
return UNKNOWN;
return reversed_comparison_code_parts (GET_CODE (comparison),
XEXP (comparison, 0),
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)
{
switch (code)
{
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)
{
rtx x = PATTERN (insn);
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)
{
rtx x = PATTERN (insn);
/* 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)
return 0;
if (GET_CODE (SET_SRC (x)) != LABEL_REF)
return 0;
+ if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
+ return 0;
return 1;
}
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;
}
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 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;
+only_sets_cc0_p (rtx x)
{
-
if (! x)
return 0;
but also does other things. */
int
-sets_cc0_p (x)
- rtx x;
+sets_cc0_p (rtx x)
{
-
if (! x)
return 0;
\f
/* Follow any unconditional jump at LABEL;
return the ultimate label reached by any such chain of jumps.
+ Return null if the chain ultimately leads to a return instruction.
If LABEL is not followed by a jump, return LABEL.
If the chain loops or we can't find end, return LABEL,
since that tells caller to avoid changing the insn.
a USE or CLOBBER. */
rtx
-follow_jumps (label)
- rtx label;
+follow_jumps (rtx label)
{
rtx insn;
rtx next;
that loop-optimization is done with. */
void
-mark_jump_label (x, insn, in_mem)
- rtx x;
- rtx insn;
- int in_mem;
+mark_jump_label (rtx x, rtx insn, int in_mem)
{
RTX_CODE code = GET_CODE (x);
int i;
case PC:
case CC0:
case REG:
- case SUBREG:
case CONST_INT:
case CONST_DOUBLE:
case CLOBBER:
if that's what the previous thing was. */
void
-delete_jump (insn)
- rtx insn;
+delete_jump (rtx insn)
{
rtx set = single_set (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);
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;
}
\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. */
rtx
-delete_related_insns (insn)
- rtx insn;
+delete_related_insns (rtx insn)
{
int was_code_label = (GET_CODE (insn) == CODE_LABEL);
rtx note;
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
if (was_code_label && prev && GET_CODE (prev) == BARRIER)
{
- RTX_CODE code;
- while (next != 0
- && (GET_RTX_CLASS (code = GET_CODE (next)) == 'i'
- || code == NOTE || code == BARRIER
- || (code == CODE_LABEL && INSN_DELETED_P (next))))
+ enum rtx_code code;
+ while (next)
{
+ code = GET_CODE (next);
if (code == NOTE
&& NOTE_LINE_NUMBER (next) != NOTE_INSN_FUNCTION_END)
next = NEXT_INSN (next);
/* Keep going past other deleted labels to delete what follows. */
else if (code == CODE_LABEL && INSN_DELETED_P (next))
next = NEXT_INSN (next);
- else
+ else if (code == BARRIER || INSN_P (next))
/* Note: if this deletes a jump, it can cause more
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_related_insns (next);
+ else
+ break;
}
}
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)
- rtx from, to;
+delete_for_peephole (rtx from, rtx to)
{
rtx insn = from;
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.
-
- 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. */
-
-void
-never_reached_warning (avoided_insn, finish)
- rtx avoided_insn, finish;
-{
- rtx insn;
- rtx a_line_note = NULL;
- int two_avoided_lines = 0, contains_insn = 0, reached_end = 0;
-
- if (! warn_notreached)
- return;
-
- /* Scan forwards, looking at LINE_NUMBER notes, until
- we hit a LABEL or we run out of insns. */
-
- for (insn = avoided_insn; insn != NULL; insn = NEXT_INSN (insn))
- {
- if (finish == NULL && GET_CODE (insn) == CODE_LABEL)
- break;
-
- if (GET_CODE (insn) == NOTE /* A line number note? */
- && NOTE_LINE_NUMBER (insn) >= 0)
- {
- if (a_line_note == NULL)
- a_line_note = insn;
- else
- two_avoided_lines |= (NOTE_LINE_NUMBER (a_line_note)
- != NOTE_LINE_NUMBER (insn));
- }
- else if (INSN_P (insn))
- {
- 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");
-}
-\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)
{
rtx x = *loc;
RTX_CODE code = GET_CODE (x);
/* 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)
{
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
Accrue the modifications into the change group. */
static void
-invert_exp_1 (insn)
- rtx insn;
+invert_exp_1 (rtx insn)
{
RTX_CODE code;
rtx x = pc_set (insn);
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)
{
int i;
- RTX_CODE code = GET_CODE (x);
+ enum rtx_code code = GET_CODE (x);
const char *fmt;
if (x == y)
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. */
order. Also handle the simple binary and unary cases without a loop.
??? Don't consider PLUS a commutative operator; see comments above. */
- if ((code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
- && code != PLUS)
+ if (COMMUTATIVE_P (x) && code != PLUS)
return ((rtx_renumbered_equal_p (XEXP (x, 0), XEXP (y, 0))
&& rtx_renumbered_equal_p (XEXP (x, 1), XEXP (y, 1)))
|| (rtx_renumbered_equal_p (XEXP (x, 0), XEXP (y, 1))
&& rtx_renumbered_equal_p (XEXP (x, 1), XEXP (y, 0))));
- else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
+ else if (NON_COMMUTATIVE_P (x))
return (rtx_renumbered_equal_p (XEXP (x, 0), XEXP (y, 0))
&& rtx_renumbered_equal_p (XEXP (x, 1), XEXP (y, 1)));
- else if (GET_RTX_CLASS (code) == '1')
+ else if (UNARY_P (x))
return rtx_renumbered_equal_p (XEXP (x, 0), XEXP (y, 0));
/* Compare the elements. If any pair of corresponding elements
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;
}
+
+/* Return regno of the register REG and handle subregs too. */
+unsigned int
+reg_or_subregno (rtx reg)
+{
+ if (REG_P (reg))
+ return REGNO (reg);
+ if (GET_CODE (reg) == SUBREG)
+ return REGNO (SUBREG_REG (reg));
+ abort ();
+}