X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fjump.c;h=8cfe3b9bcfd556eced267f8648b44797483a016e;hb=60e21b9a40e681203f50eb0a47a0074e5cb5610e;hp=f32b831c6dfb1c22dca59559bd19f4c625e20762;hpb=8f8dcce4abc08b582f0124d0b5a053bf36a34db0;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/jump.c b/gcc/jump.c index f32b831c6df..8cfe3b9bcfd 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -1,6 +1,7 @@ /* 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, 2005 + Free Software Foundation, Inc. This file is part of GCC. @@ -31,11 +32,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 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" @@ -48,9 +51,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #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. */ @@ -59,29 +64,24 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 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 invert_exp_1 (rtx, rtx); +static int returnjump_p_1 (rtx *, void *); +static void delete_prior_computation (rtx, rtx); /* 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 @@ -89,8 +89,9 @@ rebuild_jump_labels (f) count doesn't drop to zero. */ for (insn = forced_labels; insn; insn = XEXP (insn, 1)) - if (GET_CODE (XEXP (insn, 0)) == CODE_LABEL) + if (LABEL_P (XEXP (insn, 0))) LABEL_NUSES (XEXP (insn, 0))++; + timevar_pop (TV_REBUILD_JUMP); } /* Some old code expects exactly one BARRIER as the NEXT_INSN of a @@ -102,56 +103,25 @@ rebuild_jump_labels (f) old code is happy. */ void -cleanup_barriers () +cleanup_barriers (void) { rtx insn, next, prev; for (insn = get_insns (); insn; insn = next) { next = NEXT_INSN (insn); - if (GET_CODE (insn) == BARRIER) + if (BARRIER_P (insn)) { prev = prev_nonnote_insn (insn); - if (GET_CODE (prev) == BARRIER) - delete_barrier (insn); + if (BARRIER_P (prev)) + delete_insn (insn); else if (prev != PREV_INSN (insn)) reorder_insns (insn, insn, prev); } } } - -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; @@ -161,7 +131,7 @@ purge_line_number_notes (f) even if it became empty. */ for (insn = f; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == NOTE) + if (NOTE_P (insn)) { if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) /* Any previous line note was for the prologue; gdb wants a new @@ -171,8 +141,13 @@ purge_line_number_notes (f) { /* Delete this note if it is identical to previous note. */ if (last_note +#ifdef USE_MAPPED_LOCATION + && NOTE_SOURCE_LOCATION (insn) == NOTE_SOURCE_LOCATION (last_note) +#else && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last_note) - && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last_note)) + && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last_note) +#endif +) { delete_related_insns (insn); continue; @@ -186,72 +161,43 @@ purge_line_number_notes (f) /* 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 (LABEL_P (insn)) + LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0); + else if (JUMP_P (insn)) + JUMP_LABEL (insn) = 0; + else if (NONJUMP_INSN_P (insn) || CALL_P (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) + if (! INSN_DELETED_P (insn) && JUMP_P (insn)) { /* When we know the LABEL_REF contained in a REG used in an indirect jump, we'll have a REG_LABEL note so that @@ -263,7 +209,7 @@ mark_all_labels (f) { /* But a LABEL_REF around the REG_LABEL note, so that we can canonicalize it. */ - rtx label_ref = gen_rtx_LABEL_REF (VOIDmode, + rtx label_ref = gen_rtx_LABEL_REF (Pmode, XEXP (label_note, 0)); mark_jump_label (label_ref, insn, 0); @@ -274,261 +220,6 @@ mark_all_labels (f) } } } - -/* 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; -} /* 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 @@ -537,9 +228,7 @@ duplicate_loop_exit_test (loop_start) 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; @@ -552,14 +241,16 @@ squeeze_notes (startp, endp) for (insn = start; insn != past_end; insn = next) { next = NEXT_INSN (insn); - if (GET_CODE (insn) == NOTE + if (NOTE_P (insn) && (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 @@ -591,8 +282,7 @@ squeeze_notes (startp, 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; @@ -600,7 +290,7 @@ get_label_before (insn) or make a new one if there is none. */ label = prev_nonnote_insn (insn); - if (label == 0 || GET_CODE (label) != CODE_LABEL) + if (label == 0 || !LABEL_P (label)) { rtx prev = PREV_INSN (insn); @@ -614,8 +304,7 @@ get_label_before (insn) /* 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; @@ -623,7 +312,7 @@ get_label_after (insn) or make a new one if there is none. */ label = next_nonnote_insn (insn); - if (label == 0 || GET_CODE (label) != CODE_LABEL) + if (label == 0 || !LABEL_P (label)) { label = gen_label_rtx (); emit_label_after (label, insn); @@ -639,24 +328,22 @@ get_label_after (insn) 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)) { @@ -665,7 +352,6 @@ reversed_comparison_code_parts (code, arg0, arg1, insn) #endif return reverse_condition (code); } -#endif /* Try a few special cases based on the comparison code. */ switch (code) @@ -677,7 +363,7 @@ reversed_comparison_code_parts (code, arg0, arg1, insn) 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: @@ -697,11 +383,7 @@ reversed_comparison_code_parts (code, arg0, arg1, insn) 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. @@ -712,7 +394,7 @@ reversed_comparison_code_parts (code, arg0, arg1, insn) return UNKNOWN; for (prev = prev_nonnote_insn (insn); - prev != 0 && GET_CODE (prev) != CODE_LABEL; + prev != 0 && !LABEL_P (prev); prev = prev_nonnote_insn (prev)) { rtx set = set_of (arg0, prev); @@ -756,18 +438,31 @@ reversed_comparison_code_parts (code, arg0, arg1, insn) 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), 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)); +} + /* Given an rtx-code for a comparison, return the code for the negated comparison. If no such code exists, return UNKNOWN. @@ -778,8 +473,7 @@ reversed_comparison_code (comparison, insn) Use reversed_comparison_code instead. */ enum rtx_code -reverse_condition (code) - enum rtx_code code; +reverse_condition (enum rtx_code code) { switch (code) { @@ -817,7 +511,7 @@ reverse_condition (code) return UNKNOWN; default: - abort (); + gcc_unreachable (); } } @@ -826,8 +520,7 @@ reverse_condition (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) { @@ -861,7 +554,7 @@ reverse_condition_maybe_unordered (code) return LTGT; default: - abort (); + gcc_unreachable (); } } @@ -869,8 +562,7 @@ reverse_condition_maybe_unordered (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) { @@ -908,7 +600,7 @@ swap_condition (code) return UNLE; default: - abort (); + gcc_unreachable (); } } @@ -917,8 +609,7 @@ swap_condition (code) CODE is returned. */ enum rtx_code -unsigned_condition (code) - enum rtx_code code; +unsigned_condition (enum rtx_code code) { switch (code) { @@ -940,15 +631,14 @@ unsigned_condition (code) return LEU; default: - abort (); + gcc_unreachable (); } } /* 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) { @@ -970,16 +660,15 @@ signed_condition (code) return LE; default: - abort (); + gcc_unreachable (); } } -/* 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. @@ -1060,10 +749,9 @@ comparison_dominates_p (code1, code2) /* 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 + return (JUMP_P (insn) && GET_CODE (PATTERN (insn)) == SET && GET_CODE (SET_DEST (PATTERN (insn))) == PC && GET_CODE (SET_SRC (PATTERN (insn))) == LABEL_REF); @@ -1072,12 +760,11 @@ simplejump_p (insn) /* 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); @@ -1096,8 +783,6 @@ condjump_p (insn) || (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 @@ -1107,8 +792,7 @@ condjump_p (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); @@ -1139,11 +823,10 @@ condjump_in_parallel_p (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) + if (!JUMP_P (insn)) return NULL_RTX; pat = PATTERN (insn); @@ -1161,14 +844,15 @@ pc_set (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; } @@ -1180,8 +864,7 @@ any_uncondjump_p (insn) 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; @@ -1201,8 +884,7 @@ any_condjump_p (insn) /* Return the label of a conditional jump. */ rtx -condjump_label (insn) - rtx insn; +condjump_label (rtx insn) { rtx x = pc_set (insn); @@ -1223,9 +905,7 @@ condjump_label (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; @@ -1234,10 +914,9 @@ returnjump_p_1 (loc, data) } int -returnjump_p (insn) - rtx insn; +returnjump_p (rtx insn) { - if (GET_CODE (insn) != JUMP_INSN) + if (!JUMP_P (insn)) return 0; return for_each_rtx (&PATTERN (insn), returnjump_p_1, NULL); } @@ -1246,12 +925,11 @@ returnjump_p (insn) nothing more. */ int -onlyjump_p (insn) - rtx insn; +onlyjump_p (rtx insn) { rtx set; - if (GET_CODE (insn) != JUMP_INSN) + if (!JUMP_P (insn)) return 0; set = single_set (insn); @@ -1267,14 +945,12 @@ onlyjump_p (insn) #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; @@ -1290,10 +966,8 @@ only_sets_cc0_p (x) but also does other things. */ int -sets_cc0_p (x) - rtx x; +sets_cc0_p (rtx x) { - if (! x) return 0; @@ -1323,6 +997,7 @@ sets_cc0_p (x) /* 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. @@ -1331,8 +1006,7 @@ sets_cc0_p (x) a USE or CLOBBER. */ rtx -follow_jumps (label) - rtx label; +follow_jumps (rtx label) { rtx insn; rtx next; @@ -1342,12 +1016,12 @@ follow_jumps (label) for (depth = 0; (depth < 10 && (insn = next_active_insn (value)) != 0 - && GET_CODE (insn) == JUMP_INSN + && JUMP_P (insn) && ((JUMP_LABEL (insn) != 0 && any_uncondjump_p (insn) && onlyjump_p (insn)) || GET_CODE (PATTERN (insn)) == RETURN) && (next = NEXT_INSN (insn)) - && GET_CODE (next) == BARRIER); + && BARRIER_P (next)); depth++) { /* Don't chain through the insn that jumps into a loop @@ -1357,7 +1031,7 @@ follow_jumps (label) rtx tem; if (!reload_completed) for (tem = value; tem != insn; tem = NEXT_INSN (tem)) - if (GET_CODE (tem) == NOTE + if (NOTE_P (tem) && (NOTE_LINE_NUMBER (tem) == NOTE_INSN_LOOP_BEG /* ??? Optional. Disables some optimizations, but makes gcov output more accurate with -O. */ @@ -1395,10 +1069,7 @@ follow_jumps (label) 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; @@ -1409,7 +1080,6 @@ mark_jump_label (x, insn, in_mem) case PC: case CC0: case REG: - case SUBREG: case CONST_INT: case CONST_DOUBLE: case CLOBBER: @@ -1435,12 +1105,11 @@ mark_jump_label (x, insn, in_mem) /* Ignore remaining references to unreachable labels that have been deleted. */ - if (GET_CODE (label) == NOTE + if (NOTE_P (label) && NOTE_LINE_NUMBER (label) == NOTE_INSN_DELETED_LABEL) break; - if (GET_CODE (label) != CODE_LABEL) - abort (); + gcc_assert (LABEL_P (label)); /* Ignore references to labels of containing functions. */ if (LABEL_REF_NONLOCAL_P (x)) @@ -1452,7 +1121,7 @@ mark_jump_label (x, insn, in_mem) if (insn) { - if (GET_CODE (insn) == JUMP_INSN) + if (JUMP_P (insn)) JUMP_LABEL (insn) = label; else { @@ -1504,8 +1173,7 @@ mark_jump_label (x, insn, in_mem) if that's what the previous thing was. */ void -delete_jump (insn) - rtx insn; +delete_jump (rtx insn) { rtx set = single_set (insn); @@ -1513,58 +1181,46 @@ delete_jump (insn) delete_computation (insn); } -/* Verify INSN is a BARRIER and delete it. */ - -void -delete_barrier (insn) - rtx insn; -{ - if (GET_CODE (insn) != BARRIER) - 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. */ 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); for (our_prev = prev_nonnote_insn (insn); - our_prev && (GET_CODE (our_prev) == INSN - || GET_CODE (our_prev) == CALL_INSN); + our_prev && (NONJUMP_INSN_P (our_prev) + || CALL_P (our_prev)); our_prev = prev_nonnote_insn (our_prev)) { rtx pat = PATTERN (our_prev); /* 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 + if (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; if (GET_CODE (pat) == USE - && GET_CODE (XEXP (pat, 0)) == INSN) + && NONJUMP_INSN_P (XEXP (pat, 0))) /* reorg creates USEs that look like this. We leave them alone because reorg needs them for its own purposes. */ break; if (reg_set_p (reg, pat)) { - if (side_effects_p (pat) && GET_CODE (our_prev) != CALL_INSN) + if (side_effects_p (pat) && !CALL_P (our_prev)) break; if (GET_CODE (pat) == PARALLEL) @@ -1587,19 +1243,19 @@ delete_prior_computation (note, insn) delete_computation (our_prev); } else if (GET_CODE (pat) == SET - && GET_CODE (SET_DEST (pat)) == REG) + && REG_P (SET_DEST (pat))) { int dest_regno = REGNO (SET_DEST (pat)); 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) @@ -1656,8 +1312,7 @@ delete_prior_computation (note, insn) delete the insn that set it. */ static void -delete_computation (insn) - rtx insn; +delete_computation (rtx insn) { rtx note, next; @@ -1671,7 +1326,7 @@ delete_computation (insn) will use them. So if the previous insn exists to set the CC's, delete it (unless it performs auto-increments, etc.). */ - if (prev && GET_CODE (prev) == INSN + if (prev && NONJUMP_INSN_P (prev) && sets_cc0_p (PATTERN (prev))) { if (sets_cc0_p (PATTERN (prev)) > 0 @@ -1691,7 +1346,7 @@ delete_computation (insn) if (REG_NOTE_KIND (note) != REG_DEAD /* Verify that the REG_NOTE is legitimate. */ - || GET_CODE (XEXP (note, 0)) != REG) + || !REG_P (XEXP (note, 0))) continue; delete_prior_computation (note, insn); @@ -1701,18 +1356,17 @@ delete_computation (insn) } /* 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); + int was_code_label = (LABEL_P (insn)); rtx note; rtx next = NEXT_INSN (insn), prev = PREV_INSN (insn); @@ -1728,13 +1382,13 @@ delete_related_insns (insn) /* If instruction is followed by a barrier, delete the barrier too. */ - if (next != 0 && GET_CODE (next) == BARRIER) + if (next != 0 && BARRIER_P (next)) delete_insn (next); /* If deleting a jump, decrement the count of the label, and delete the label if it is now unused. */ - if (GET_CODE (insn) == JUMP_INSN && JUMP_LABEL (insn)) + if (JUMP_P (insn) && JUMP_LABEL (insn)) { rtx lab = JUMP_LABEL (insn), lab_next; @@ -1753,10 +1407,7 @@ delete_related_insns (insn) 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 @@ -1768,7 +1419,7 @@ delete_related_insns (insn) /* Likewise if we're deleting a dispatch table. */ - if (GET_CODE (insn) == JUMP_INSN + if (JUMP_P (insn) && (GET_CODE (PATTERN (insn)) == ADDR_VEC || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)) { @@ -1785,15 +1436,15 @@ delete_related_insns (insn) } /* Likewise for an ordinary INSN / CALL_INSN with a REG_LABEL note. */ - if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN) + if (NONJUMP_INSN_P (insn) || CALL_P (insn)) for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) if (REG_NOTE_KIND (note) == REG_LABEL /* This could also be a NOTE_INSN_DELETED_LABEL note. */ - && GET_CODE (XEXP (note, 0)) == CODE_LABEL) + && LABEL_P (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)) + while (prev && (INSN_DELETED_P (prev) || NOTE_P (prev))) prev = PREV_INSN (prev); /* If INSN was a label and a dispatch table follows it, @@ -1802,50 +1453,38 @@ delete_related_insns (insn) if (was_code_label && NEXT_INSN (insn) != 0 - && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN + && JUMP_P (NEXT_INSN (insn)) && (GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_VEC || GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC)) 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) + if (was_code_label && prev && BARRIER_P (prev)) { - 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; -} /* Delete a range of insns from FROM to TO, inclusive. This is for the sake of peephole optimization, so assume @@ -1853,8 +1492,7 @@ next_nondeleted_insn (insn) 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; @@ -1863,7 +1501,7 @@ delete_for_peephole (from, to) rtx next = NEXT_INSN (insn); rtx prev = PREV_INSN (insn); - if (GET_CODE (insn) != NOTE) + if (!NOTE_P (insn)) { INSN_DELETED_P (insn) = 1; @@ -1888,67 +1526,11 @@ delete_for_peephole (from, to) is also an unconditional jump in that case. */ } -/* 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"); -} - /* 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); @@ -1961,7 +1543,7 @@ redirect_exp_1 (loc, olabel, nlabel, insn) { rtx n; if (nlabel) - n = gen_rtx_LABEL_REF (VOIDmode, nlabel); + n = gen_rtx_LABEL_REF (Pmode, nlabel); else n = gen_rtx_RETURN (VOIDmode); @@ -1971,7 +1553,10 @@ redirect_exp_1 (loc, olabel, nlabel, insn) } else if (code == RETURN && olabel == 0) { - x = gen_rtx_LABEL_REF (VOIDmode, nlabel); + if (nlabel) + x = gen_rtx_LABEL_REF (Pmode, 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); @@ -2000,34 +1585,12 @@ redirect_exp_1 (loc, 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; -{ - 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. */ int -redirect_jump_1 (jump, nlabel) - rtx jump, nlabel; +redirect_jump_1 (rtx jump, rtx nlabel) { int ochanges = num_validated_changes (); rtx *loc; @@ -2052,53 +1615,70 @@ redirect_jump_1 (jump, nlabel) (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); 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 || (invert && !invert_exp_1 (XEXP (note, 0), jump))) + remove_note (jump, note); + else + { + redirect_exp_1 (&XEXP (note, 0), olabel, nlabel, jump); + confirm_change_group (); + } + } + /* 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 && NEXT_INSN (olabel) - && GET_CODE (NEXT_INSN (olabel)) == NOTE - && NOTE_LINE_NUMBER (NEXT_INSN (olabel)) == NOTE_INSN_FUNCTION_END) + && NOTE_P (NEXT_INSN (olabel)) + && 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 (insn) - 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) { @@ -2120,31 +1700,16 @@ invert_exp_1 (insn) 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 (insn) - 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 @@ -2153,46 +1718,39 @@ invert_exp (insn) inversion and redirection. */ int -invert_jump_1 (jump, nlabel) - rtx jump, nlabel; +invert_jump_1 (rtx jump, rtx nlabel) { + rtx x = pc_set (jump); int ochanges; + int ok; ochanges = num_validated_changes (); - invert_exp_1 (jump); + gcc_assert (x); + ok = invert_exp_1 (SET_SRC (x), jump); + gcc_assert (ok); + 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 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 - 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 ()) { - 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; } @@ -2211,19 +1769,18 @@ invert_jump (jump, nlabel, delete_unused) 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) return 1; - if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG)) - && (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG - && GET_CODE (SUBREG_REG (y)) == REG))) + if ((code == REG || (code == SUBREG && REG_P (SUBREG_REG (x)))) + && (REG_P (y) || (GET_CODE (y) == SUBREG + && REG_P (SUBREG_REG (y))))) { int reg_x = -1, reg_y = -1; int byte_x = 0, byte_y = 0; @@ -2292,10 +1849,8 @@ rtx_renumbered_equal_p (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. */ @@ -2327,16 +1882,15 @@ rtx_renumbered_equal_p (x, y) 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 @@ -2376,7 +1930,7 @@ rtx_renumbered_equal_p (x, y) case 'u': if (XEXP (x, i) != XEXP (y, i)) return 0; - /* fall through. */ + /* Fall through. */ case '0': break; @@ -2389,7 +1943,7 @@ rtx_renumbered_equal_p (x, y) break; default: - abort (); + gcc_unreachable (); } } return 1; @@ -2401,10 +1955,9 @@ rtx_renumbered_equal_p (x, y) return -1. Any rtx is valid for X. */ int -true_regnum (x) - rtx x; +true_regnum (rtx x) { - if (GET_CODE (x) == REG) + if (REG_P (x)) { if (REGNO (x) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (x)] >= 0) return reg_renumber[REGNO (x)]; @@ -2420,3 +1973,13 @@ true_regnum (x) } return -1; } + +/* Return regno of the register REG and handle subregs too. */ +unsigned int +reg_or_subregno (rtx reg) +{ + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + gcc_assert (REG_P (reg)); + return REGNO (reg); +}