X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Freorg.c;h=4871b0e8c29b22f9a341ca866a9594fe6100dd1d;hp=dd9737b506fb336c19c3df2d4115f4443e47227f;hb=fef144401409894f6457aae538e0b4c5e3a72c4c;hpb=a85234d1efc4ca822934b9fc295069bb8fe7b084 diff --git a/gcc/reorg.c b/gcc/reorg.c index dd9737b506f..4871b0e8c29 100644 --- a/gcc/reorg.c +++ b/gcc/reorg.c @@ -1,6 +1,7 @@ /* Perform instruction reorganizations for delay slot filling. - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Free Software Foundation, Inc. Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu). Hacked by Michael Tiemann (tiemann@cygnus.com). @@ -8,7 +9,7 @@ This file is part of GCC. 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 +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -17,9 +18,8 @@ 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 GCC; 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 COPYING3. If not see +. */ /* Instruction reorganization pass. @@ -133,6 +133,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "resource.h" #include "except.h" #include "params.h" +#include "timevar.h" +#include "target.h" +#include "tree-pass.h" #ifdef DELAY_SLOTS @@ -170,8 +173,8 @@ static int max_uid; static int stop_search_p (rtx, int); static int resource_conflicts_p (struct resources *, struct resources *); -static int insn_references_resource_p (rtx, struct resources *, int); -static int insn_sets_resource_p (rtx, struct resources *, int); +static int insn_references_resource_p (rtx, struct resources *, bool); +static int insn_sets_resource_p (rtx, struct resources *, bool); static rtx find_end_label (void); static rtx emit_delay_sequence (rtx, rtx, int); static rtx add_to_delay_list (rtx, rtx); @@ -208,7 +211,8 @@ static void update_reg_dead_notes (rtx, rtx); static void fix_reg_dead_note (rtx, rtx); static void update_reg_unused_notes (rtx, rtx); static void fill_simple_delay_slots (int); -static rtx fill_slots_from_thread (rtx, rtx, rtx, rtx, int, int, int, int, +static rtx fill_slots_from_thread (rtx, rtx, rtx, rtx, + int, int, int, int, int *, rtx); static void fill_eager_delay_slots (void); static void relax_delay_slots (rtx); @@ -253,7 +257,7 @@ stop_search_p (rtx insn, int labels_p) || asm_noperands (PATTERN (insn)) >= 0); default: - abort (); + gcc_unreachable (); } } @@ -293,7 +297,7 @@ resource_conflicts_p (struct resources *res1, struct resources *res2) static int insn_references_resource_p (rtx insn, struct resources *res, - int include_delayed_effects) + bool include_delayed_effects) { struct resources insn_res; @@ -309,17 +313,36 @@ insn_references_resource_p (rtx insn, struct resources *res, static int insn_sets_resource_p (rtx insn, struct resources *res, - int include_delayed_effects) + bool include_delayed_effects) { struct resources insn_sets; CLEAR_RESOURCE (&insn_sets); - mark_set_resources (insn, &insn_sets, 0, include_delayed_effects); + mark_set_resources (insn, &insn_sets, 0, + (include_delayed_effects + ? MARK_SRC_DEST_CALL + : MARK_SRC_DEST)); return resource_conflicts_p (&insn_sets, res); } -/* Find a label at the end of the function or before a RETURN. If there is - none, make one. */ +/* Find a label at the end of the function or before a RETURN. If there + is none, try to make one. If that fails, returns 0. + + The property of such a label is that it is placed just before the + epilogue or a bare RETURN insn, so that another bare RETURN can be + turned into a jump to the label unconditionally. In particular, the + label cannot be placed before a RETURN insn with a filled delay slot. + + ??? There may be a problem with the current implementation. Suppose + we start with a bare RETURN insn and call find_end_label. It may set + end_of_function_label just before the RETURN. Suppose the machinery + is able to fill the delay slot of the RETURN insn afterwards. Then + end_of_function_label is no longer valid according to the property + described above and find_end_label will still return it unmodified. + Note that this is probably mitigated by the following observation: + once end_of_function_label is made, it is very likely the target of + a jump, so filling the delay slot of the RETURN will be much more + difficult. */ static rtx find_end_label (void) @@ -335,8 +358,8 @@ find_end_label (void) label and we don't have to do anything else. */ insn = get_last_insn (); - while (GET_CODE (insn) == NOTE - || (GET_CODE (insn) == INSN + while (NOTE_P (insn) + || (NONJUMP_INSN_P (insn) && (GET_CODE (PATTERN (insn)) == USE || GET_CODE (PATTERN (insn)) == CLOBBER))) insn = PREV_INSN (insn); @@ -344,22 +367,22 @@ find_end_label (void) /* When a target threads its epilogue we might already have a suitable return insn. If so put a label before it for the end_of_function_label. */ - if (GET_CODE (insn) == BARRIER - && GET_CODE (PREV_INSN (insn)) == JUMP_INSN + if (BARRIER_P (insn) + && JUMP_P (PREV_INSN (insn)) && GET_CODE (PATTERN (PREV_INSN (insn))) == RETURN) { rtx temp = PREV_INSN (PREV_INSN (insn)); end_of_function_label = gen_label_rtx (); LABEL_NUSES (end_of_function_label) = 0; - /* Put the label before an USE insns that may proceed the RETURN insn. */ + /* Put the label before an USE insns that may precede the RETURN insn. */ while (GET_CODE (temp) == USE) temp = PREV_INSN (temp); emit_label_after (end_of_function_label, temp); } - else if (GET_CODE (insn) == CODE_LABEL) + else if (LABEL_P (insn)) end_of_function_label = insn; else { @@ -368,7 +391,7 @@ find_end_label (void) /* If the basic block reorder pass moves the return insn to some other place try to locate it again and put our end_of_function_label there. */ - while (insn && ! (GET_CODE (insn) == JUMP_INSN + while (insn && ! (JUMP_P (insn) && (GET_CODE (PATTERN (insn)) == RETURN))) insn = PREV_INSN (insn); if (insn) @@ -384,11 +407,32 @@ find_end_label (void) } else { +#ifdef HAVE_epilogue + if (HAVE_epilogue +#ifdef HAVE_return + && ! HAVE_return +#endif + ) + { + /* The RETURN insn has its delay slot filled so we cannot + emit the label just before it. Since we already have + an epilogue and cannot emit a new RETURN, we cannot + emit the label at all. */ + end_of_function_label = NULL_RTX; + return end_of_function_label; + } +#endif /* HAVE_epilogue */ + /* Otherwise, make a new label and emit a RETURN and BARRIER, if needed. */ emit_label (end_of_function_label); #ifdef HAVE_return - if (HAVE_return) + /* We don't bother trying to create a return insn if the + epilogue has filled delay-slots; we would have to try and + move the delay-slot fillers to the delay-slots for the new + return insn or in front of the new return insn. */ + if (crtl->epilogue_delay_list == NULL + && HAVE_return) { /* The return we make may have delay slots too. */ rtx insn = gen_return (); @@ -438,7 +482,7 @@ emit_delay_sequence (rtx insn, rtx list, int length) /* If INSN is followed by a BARRIER, delete the BARRIER since it will only confuse further processing. Update LAST in case it was the last insn. We will put the BARRIER back in later. */ - if (NEXT_INSN (insn) && GET_CODE (NEXT_INSN (insn)) == BARRIER) + if (NEXT_INSN (insn) && BARRIER_P (NEXT_INSN (insn))) { delete_related_insns (NEXT_INSN (insn)); last = get_last_insn (); @@ -471,6 +515,8 @@ emit_delay_sequence (rtx insn, rtx list, int length) INSN_DELETED_P (delay_insn) = 0; PREV_INSN (delay_insn) = PREV_INSN (seq_insn); + INSN_LOCATOR (seq_insn) = INSN_LOCATOR (delay_insn); + for (li = list; li; li = XEXP (li, 1), i++) { rtx tem = XEXP (li, 0); @@ -500,9 +546,10 @@ emit_delay_sequence (rtx insn, rtx list, int length) remove_note (tem, note); break; - case REG_LABEL: + case REG_LABEL_OPERAND: + case REG_LABEL_TARGET: /* Keep the label reference count up to date. */ - if (GET_CODE (XEXP (note, 0)) == CODE_LABEL) + if (LABEL_P (XEXP (note, 0))) LABEL_NUSES (XEXP (note, 0)) ++; break; @@ -518,13 +565,13 @@ emit_delay_sequence (rtx insn, rtx list, int length) last insn in that SEQUENCE to point to us. Similarly for the first insn in the following insn if it is a SEQUENCE. */ - if (PREV_INSN (seq_insn) && GET_CODE (PREV_INSN (seq_insn)) == INSN + if (PREV_INSN (seq_insn) && NONJUMP_INSN_P (PREV_INSN (seq_insn)) && GET_CODE (PATTERN (PREV_INSN (seq_insn))) == SEQUENCE) NEXT_INSN (XVECEXP (PATTERN (PREV_INSN (seq_insn)), 0, XVECLEN (PATTERN (PREV_INSN (seq_insn)), 0) - 1)) = seq_insn; - if (NEXT_INSN (seq_insn) && GET_CODE (NEXT_INSN (seq_insn)) == INSN + if (NEXT_INSN (seq_insn) && NONJUMP_INSN_P (NEXT_INSN (seq_insn)) && GET_CODE (PATTERN (NEXT_INSN (seq_insn))) == SEQUENCE) PREV_INSN (XVECEXP (PATTERN (NEXT_INSN (seq_insn)), 0, 0)) = seq_insn; @@ -532,8 +579,7 @@ emit_delay_sequence (rtx insn, rtx list, int length) if (had_barrier) emit_barrier_after (seq_insn); - if (i != length + 1) - abort (); + gcc_assert (i == length + 1); return seq_insn; } @@ -584,7 +630,7 @@ delete_from_delay_slot (rtx insn) seq_insn = PREV_INSN (NEXT_INSN (trial)); seq = PATTERN (seq_insn); - if (NEXT_INSN (seq_insn) && GET_CODE (NEXT_INSN (seq_insn)) == BARRIER) + if (NEXT_INSN (seq_insn) && BARRIER_P (NEXT_INSN (seq_insn))) had_barrier = 1; /* Create a delay list consisting of all the insns other than the one @@ -599,7 +645,7 @@ delete_from_delay_slot (rtx insn) prev = PREV_INSN (seq_insn); trial = XVECEXP (seq, 0, 0); delete_related_insns (seq_insn); - add_insn_after (trial, prev); + add_insn_after (trial, prev, NULL); /* If there was a barrier after the old SEQUENCE, remit it. */ if (had_barrier) @@ -609,9 +655,7 @@ delete_from_delay_slot (rtx insn) annul flag. */ if (delay_list) trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2); - else if (GET_CODE (trial) == JUMP_INSN - || GET_CODE (trial) == CALL_INSN - || GET_CODE (trial) == INSN) + else if (INSN_P (trial)) INSN_ANNULLED_BRANCH_P (trial) = 0; INSN_FROM_TARGET_P (insn) = 0; @@ -654,7 +698,7 @@ delete_scheduled_jump (rtx insn) a delay slot. It will be the last insn in the delay slot, if it is. */ rtx trial = previous_insn (insn); - if (GET_CODE (trial) == NOTE) + if (NOTE_P (trial)) trial = prev_nonnote_insn (trial); if (sets_cc0_p (PATTERN (trial)) != 1 || FIND_REG_INC_NOTE (trial, NULL_RTX)) @@ -731,13 +775,12 @@ optimize_skip (rtx insn) rtx trial = next_nonnote_insn (insn); rtx next_trial = next_active_insn (trial); rtx delay_list = 0; - rtx target_label; int flags; flags = get_jump_flags (insn, JUMP_LABEL (insn)); if (trial == 0 - || GET_CODE (trial) != INSN + || !NONJUMP_INSN_P (trial) || GET_CODE (PATTERN (trial)) == SEQUENCE || recog_memoized (trial) < 0 || (! eligible_for_annul_false (insn, 0, trial, flags) @@ -752,9 +795,9 @@ optimize_skip (rtx insn) In both of these cases, inverting the jump and annulling the delay slot give the same effect in fewer insns. */ if ((next_trial == next_active_insn (JUMP_LABEL (insn)) - && ! (next_trial == 0 && current_function_epilogue_delay_list != 0)) + && ! (next_trial == 0 && crtl->epilogue_delay_list != 0)) || (next_trial != 0 - && GET_CODE (next_trial) == JUMP_INSN + && JUMP_P (next_trial) && JUMP_LABEL (insn) == JUMP_LABEL (next_trial) && (simplejump_p (next_trial) || GET_CODE (PATTERN (next_trial)) == RETURN))) @@ -776,21 +819,24 @@ optimize_skip (rtx insn) branch, thread our jump to the target of that branch. Don't change this into a RETURN here, because it may not accept what we have in the delay slot. We'll fix this up later. */ - if (next_trial && GET_CODE (next_trial) == JUMP_INSN + if (next_trial && JUMP_P (next_trial) && (simplejump_p (next_trial) || GET_CODE (PATTERN (next_trial)) == RETURN)) { - target_label = JUMP_LABEL (next_trial); + rtx target_label = JUMP_LABEL (next_trial); if (target_label == 0) target_label = find_end_label (); - /* Recompute the flags based on TARGET_LABEL since threading - the jump to TARGET_LABEL may change the direction of the - jump (which may change the circumstances in which the - delay slot is nullified). */ - flags = get_jump_flags (insn, target_label); - if (eligible_for_annul_true (insn, 0, trial, flags)) - reorg_redirect_jump (insn, target_label); + if (target_label) + { + /* Recompute the flags based on TARGET_LABEL since threading + the jump to TARGET_LABEL may change the direction of the + jump (which may change the circumstances in which the + delay slot is nullified). */ + flags = get_jump_flags (insn, target_label); + if (eligible_for_annul_true (insn, 0, trial, flags)) + reorg_redirect_jump (insn, target_label); + } } INSN_ANNULLED_BRANCH_P (insn) = 1; @@ -817,7 +863,7 @@ get_jump_flags (rtx insn, rtx label) If LABEL is zero, then there is no way to determine the branch direction. */ - if (GET_CODE (insn) == JUMP_INSN + if (JUMP_P (insn) && (condjump_p (insn) || condjump_in_parallel_p (insn)) && INSN_UID (insn) <= max_uid && label != 0 @@ -833,7 +879,7 @@ get_jump_flags (rtx insn, rtx label) determine the branch prediction. Non conditional branches are predicted as very likely taken. */ - if (GET_CODE (insn) == JUMP_INSN + if (JUMP_P (insn) && (condjump_p (insn) || condjump_in_parallel_p (insn))) { int prediction; @@ -855,7 +901,7 @@ get_jump_flags (rtx insn, rtx label) break; default: - abort (); + gcc_unreachable (); } } else @@ -877,7 +923,7 @@ rare_destination (rtx insn) for (; insn; insn = next) { - if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) + if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) insn = XVECEXP (PATTERN (insn), 0, 0); next = NEXT_INSN (insn); @@ -924,9 +970,8 @@ static int mostly_true_jump (rtx jump_insn, rtx condition) { rtx target_label = JUMP_LABEL (jump_insn); - rtx insn, note; - int rare_dest = rare_destination (target_label); - int rare_fallthrough = rare_destination (NEXT_INSN (jump_insn)); + rtx note; + int rare_dest, rare_fallthrough; /* If branch probabilities are available, then use that number since it always gives a correct answer. */ @@ -945,42 +990,10 @@ mostly_true_jump (rtx jump_insn, rtx condition) return -1; } - /* ??? Ought to use estimate_probability instead. */ - - /* If this is a branch outside a loop, it is highly unlikely. */ - if (GET_CODE (PATTERN (jump_insn)) == SET - && GET_CODE (SET_SRC (PATTERN (jump_insn))) == IF_THEN_ELSE - && ((GET_CODE (XEXP (SET_SRC (PATTERN (jump_insn)), 1)) == LABEL_REF - && LABEL_OUTSIDE_LOOP_P (XEXP (SET_SRC (PATTERN (jump_insn)), 1))) - || (GET_CODE (XEXP (SET_SRC (PATTERN (jump_insn)), 2)) == LABEL_REF - && LABEL_OUTSIDE_LOOP_P (XEXP (SET_SRC (PATTERN (jump_insn)), 2))))) - return -1; - - if (target_label) - { - /* If this is the test of a loop, it is very likely true. We scan - backwards from the target label. If we find a NOTE_INSN_LOOP_BEG - before the next real insn, we assume the branch is to the top of - the loop. */ - for (insn = PREV_INSN (target_label); - insn && GET_CODE (insn) == NOTE; - insn = PREV_INSN (insn)) - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) - return 2; - - /* If this is a jump to the test of a loop, it is likely true. We scan - forwards from the target label. If we find a NOTE_INSN_LOOP_VTOP - before the next real insn, we assume the branch is to the loop branch - test. */ - for (insn = NEXT_INSN (target_label); - insn && GET_CODE (insn) == NOTE; - insn = PREV_INSN (insn)) - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_VTOP) - return 1; - } - /* Look at the relative rarities of the fallthrough and destination. If they differ, we can predict the branch that way. */ + rare_dest = rare_destination (target_label); + rare_fallthrough = rare_destination (NEXT_INSN (jump_insn)); switch (rare_fallthrough - rare_dest) { @@ -1001,33 +1014,6 @@ mostly_true_jump (rtx jump_insn, rtx condition) if (condition == 0) return 0; - /* EQ tests are usually false and NE tests are usually true. Also, - most quantities are positive, so we can make the appropriate guesses - about signed comparisons against zero. */ - switch (GET_CODE (condition)) - { - case CONST_INT: - /* Unconditional branch. */ - return 1; - case EQ: - return 0; - case NE: - return 1; - case LE: - case LT: - if (XEXP (condition, 1) == const0_rtx) - return 0; - break; - case GE: - case GT: - if (XEXP (condition, 1) == const0_rtx) - return 1; - break; - - default: - break; - } - /* Predict backward branches usually take, forward branches usually not. If we don't know whether this is forward or backward, assume the branch will be taken, since most are. */ @@ -1260,7 +1246,7 @@ steal_delay_list_from_target (rtx insn, rtx condition, rtx seq, rtx trial = XEXP (temp, 0); mark_set_resources (trial, &cc_set, 0, MARK_SRC_DEST_CALL); - if (insn_references_resource_p (XVECEXP (seq , 0, 0), &cc_set, 0)) + if (insn_references_resource_p (XVECEXP (seq , 0, 0), &cc_set, false)) return delay_list; } @@ -1282,9 +1268,9 @@ steal_delay_list_from_target (rtx insn, rtx condition, rtx seq, rtx trial = XVECEXP (seq, 0, i); int flags; - if (insn_references_resource_p (trial, sets, 0) - || insn_sets_resource_p (trial, needed, 0) - || insn_sets_resource_p (trial, sets, 0) + if (insn_references_resource_p (trial, sets, false) + || insn_sets_resource_p (trial, needed, false) + || insn_sets_resource_p (trial, sets, false) #ifdef HAVE_cc0 /* If TRIAL sets CC0, we can't copy it, so we can't steal this delay list. */ @@ -1307,8 +1293,8 @@ steal_delay_list_from_target (rtx insn, rtx condition, rtx seq, if (! must_annul && ((condition == const_true_rtx - || (! insn_sets_resource_p (trial, other_needed, 0) - && ! may_trap_p (PATTERN (trial))))) + || (! insn_sets_resource_p (trial, other_needed, false) + && ! may_trap_or_fault_p (PATTERN (trial))))) ? eligible_for_delay (insn, total_slots_filled, trial, flags) : (must_annul || (delay_list == NULL && new_delay_list == NULL)) && (must_annul = 1, @@ -1382,9 +1368,9 @@ steal_delay_list_from_fallthrough (rtx insn, rtx condition, rtx seq, /* If TRIAL sets CC0, stealing it will move it too far from the use of CC0. */ - if (insn_references_resource_p (trial, sets, 0) - || insn_sets_resource_p (trial, needed, 0) - || insn_sets_resource_p (trial, sets, 0) + if (insn_references_resource_p (trial, sets, false) + || insn_sets_resource_p (trial, needed, false) + || insn_sets_resource_p (trial, sets, false) #ifdef HAVE_cc0 || sets_cc0_p (PATTERN (trial)) #endif @@ -1401,8 +1387,8 @@ steal_delay_list_from_fallthrough (rtx insn, rtx condition, rtx seq, if (! must_annul && ((condition == const_true_rtx - || (! insn_sets_resource_p (trial, other_needed, 0) - && ! may_trap_p (PATTERN (trial))))) + || (! insn_sets_resource_p (trial, other_needed, false) + && ! may_trap_or_fault_p (PATTERN (trial))))) ? eligible_for_delay (insn, *pslots_filled, trial, flags) : (must_annul || delay_list == NULL) && (must_annul = 1, check_annul_list_true_false (1, delay_list) @@ -1462,7 +1448,8 @@ try_merge_delay_insns (rtx insn, rtx thread) if (! annul_p) for (i = 1 ; i < num_slots; i++) if (XVECEXP (PATTERN (insn), 0, i)) - mark_referenced_resources (XVECEXP (PATTERN (insn), 0, i), &needed, 1); + mark_referenced_resources (XVECEXP (PATTERN (insn), 0, i), &needed, + true); for (trial = thread; !stop_search_p (trial, 1); trial = next_trial) { @@ -1472,7 +1459,7 @@ try_merge_delay_insns (rtx insn, rtx thread) next_trial = next_nonnote_insn (trial); /* TRIAL must be a CALL_INSN or INSN. Skip USE and CLOBBER. */ - if (GET_CODE (trial) == INSN + if (NONJUMP_INSN_P (trial) && (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)) continue; @@ -1481,9 +1468,9 @@ try_merge_delay_insns (rtx insn, rtx thread) /* We can't share an insn that sets cc0. */ && ! sets_cc0_p (pat) #endif - && ! insn_references_resource_p (trial, &set, 1) - && ! insn_sets_resource_p (trial, &set, 1) - && ! insn_sets_resource_p (trial, &needed, 1) + && ! insn_references_resource_p (trial, &set, true) + && ! insn_sets_resource_p (trial, &set, true) + && ! insn_sets_resource_p (trial, &needed, true) && (trial = try_split (pat, trial, 0)) != 0 /* Update next_trial, in case try_split succeeded. */ && (next_trial = next_nonnote_insn (trial)) @@ -1514,13 +1501,13 @@ try_merge_delay_insns (rtx insn, rtx thread) } mark_set_resources (trial, &set, 0, MARK_SRC_DEST_CALL); - mark_referenced_resources (trial, &needed, 1); + mark_referenced_resources (trial, &needed, true); } /* See if we stopped on a filled insn. If we did, try to see if its delay slots match. */ if (slot_number != num_slots - && trial && GET_CODE (trial) == INSN + && trial && NONJUMP_INSN_P (trial) && GET_CODE (PATTERN (trial)) == SEQUENCE && ! INSN_ANNULLED_BRANCH_P (XVECEXP (PATTERN (trial), 0, 0))) { @@ -1529,15 +1516,15 @@ try_merge_delay_insns (rtx insn, rtx thread) /* Account for resources set/needed by the filled insn. */ mark_set_resources (filled_insn, &set, 0, MARK_SRC_DEST_CALL); - mark_referenced_resources (filled_insn, &needed, 1); + mark_referenced_resources (filled_insn, &needed, true); for (i = 1; i < XVECLEN (pat, 0); i++) { rtx dtrial = XVECEXP (pat, 0, i); - if (! insn_references_resource_p (dtrial, &set, 1) - && ! insn_sets_resource_p (dtrial, &set, 1) - && ! insn_sets_resource_p (dtrial, &needed, 1) + if (! insn_references_resource_p (dtrial, &set, true) + && ! insn_sets_resource_p (dtrial, &set, true) + && ! insn_sets_resource_p (dtrial, &needed, true) #ifdef HAVE_cc0 && ! sets_cc0_p (PATTERN (dtrial)) #endif @@ -1546,12 +1533,12 @@ try_merge_delay_insns (rtx insn, rtx thread) { if (! annul_p) { - rtx new; + rtx new_rtx; update_block (dtrial, thread); - new = delete_from_delay_slot (dtrial); + new_rtx = delete_from_delay_slot (dtrial); if (INSN_DELETED_P (thread)) - thread = new; + thread = new_rtx; INSN_FROM_TARGET_P (next_to_match) = 0; } else @@ -1568,7 +1555,7 @@ try_merge_delay_insns (rtx insn, rtx thread) /* Keep track of the set/referenced resources for the delay slots of any trial insns we encounter. */ mark_set_resources (dtrial, &set, 0, MARK_SRC_DEST_CALL); - mark_referenced_resources (dtrial, &needed, 1); + mark_referenced_resources (dtrial, &needed, true); } } } @@ -1584,12 +1571,12 @@ try_merge_delay_insns (rtx insn, rtx thread) { if (GET_MODE (merged_insns) == SImode) { - rtx new; + rtx new_rtx; update_block (XEXP (merged_insns, 0), thread); - new = delete_from_delay_slot (XEXP (merged_insns, 0)); + new_rtx = delete_from_delay_slot (XEXP (merged_insns, 0)); if (INSN_DELETED_P (thread)) - thread = new; + thread = new_rtx; } else { @@ -1643,13 +1630,14 @@ redundant_insn (rtx insn, rtx target, rtx delay_list) for (trial = PREV_INSN (target), insns_to_search = MAX_DELAY_SLOT_INSN_SEARCH; trial && insns_to_search > 0; - trial = PREV_INSN (trial), --insns_to_search) + trial = PREV_INSN (trial)) { - if (GET_CODE (trial) == CODE_LABEL) + if (LABEL_P (trial)) return 0; - if (! INSN_P (trial)) + if (!NONDEBUG_INSN_P (trial)) continue; + --insns_to_search; pat = PATTERN (trial); if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) @@ -1659,7 +1647,7 @@ redundant_insn (rtx insn, rtx target, rtx delay_list) { /* Stop for a CALL and its delay slots because it is difficult to track its resource needs correctly. */ - if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL_INSN) + if (CALL_P (XVECEXP (pat, 0, 0))) return 0; /* Stop for an INSN or JUMP_INSN with delayed effects and its delay @@ -1704,10 +1692,10 @@ redundant_insn (rtx insn, rtx target, rtx delay_list) CLEAR_RESOURCE (&needed); CLEAR_RESOURCE (&set); mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL); - mark_referenced_resources (insn, &needed, 1); + mark_referenced_resources (insn, &needed, true); /* If TARGET is a SEQUENCE, get the main insn. */ - if (GET_CODE (target) == INSN && GET_CODE (PATTERN (target)) == SEQUENCE) + if (NONJUMP_INSN_P (target) && GET_CODE (PATTERN (target)) == SEQUENCE) target_main = XVECEXP (PATTERN (target), 0, 0); if (resource_conflicts_p (&needed, &set) @@ -1716,8 +1704,8 @@ redundant_insn (rtx insn, rtx target, rtx delay_list) #endif /* The insn requiring the delay may not set anything needed or set by INSN. */ - || insn_sets_resource_p (target_main, &needed, 1) - || insn_sets_resource_p (target_main, &set, 1)) + || insn_sets_resource_p (target_main, &needed, true) + || insn_sets_resource_p (target_main, &set, true)) return 0; /* Insns we pass may not set either NEEDED or SET, so merge them for @@ -1731,14 +1719,15 @@ redundant_insn (rtx insn, rtx target, rtx delay_list) while (delay_list) { - if (insn_sets_resource_p (XEXP (delay_list, 0), &needed, 1)) + if (insn_sets_resource_p (XEXP (delay_list, 0), &needed, true)) return 0; delay_list = XEXP (delay_list, 1); } - if (GET_CODE (target) == INSN && GET_CODE (PATTERN (target)) == SEQUENCE) + if (NONJUMP_INSN_P (target) && GET_CODE (PATTERN (target)) == SEQUENCE) for (i = 1; i < XVECLEN (PATTERN (target), 0); i++) - if (insn_sets_resource_p (XVECEXP (PATTERN (target), 0, i), &needed, 1)) + if (insn_sets_resource_p (XVECEXP (PATTERN (target), 0, i), &needed, + true)) return 0; /* Scan backwards until we reach a label or an insn that uses something @@ -1746,12 +1735,12 @@ redundant_insn (rtx insn, rtx target, rtx delay_list) for (trial = PREV_INSN (target), insns_to_search = MAX_DELAY_SLOT_INSN_SEARCH; - trial && GET_CODE (trial) != CODE_LABEL && insns_to_search > 0; - trial = PREV_INSN (trial), --insns_to_search) + trial && !LABEL_P (trial) && insns_to_search > 0; + trial = PREV_INSN (trial)) { - if (GET_CODE (trial) != INSN && GET_CODE (trial) != CALL_INSN - && GET_CODE (trial) != JUMP_INSN) + if (!NONDEBUG_INSN_P (trial)) continue; + --insns_to_search; pat = PATTERN (trial); if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) @@ -1761,7 +1750,7 @@ redundant_insn (rtx insn, rtx target, rtx delay_list) { /* If this is a CALL_INSN and its delay slots, it is hard to track the resource needs properly, so give up. */ - if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL_INSN) + if (CALL_P (XVECEXP (pat, 0, 0))) return 0; /* If this is an INSN or JUMP_INSN with delayed effects, it @@ -1798,13 +1787,13 @@ redundant_insn (rtx insn, rtx target, rtx delay_list) we must stop if it sets anything needed or set by INSN. */ if ((! INSN_ANNULLED_BRANCH_P (XVECEXP (pat, 0, 0)) || ! INSN_FROM_TARGET_P (candidate)) - && insn_sets_resource_p (candidate, &needed, 1)) + && insn_sets_resource_p (candidate, &needed, true)) return 0; } /* If the insn requiring the delay slot conflicts with INSN, we must stop. */ - if (insn_sets_resource_p (XVECEXP (pat, 0, 0), &needed, 1)) + if (insn_sets_resource_p (XVECEXP (pat, 0, 0), &needed, true)) return 0; } else @@ -1815,7 +1804,7 @@ redundant_insn (rtx insn, rtx target, rtx delay_list) return trial; /* Can't go any further if TRIAL conflicts with INSN. */ - if (insn_sets_resource_p (trial, &needed, 1)) + if (insn_sets_resource_p (trial, &needed, true)) return 0; } } @@ -1845,7 +1834,7 @@ own_thread_p (rtx thread, rtx label, int allow_fallthrough) active_insn = next_active_insn (PREV_INSN (thread)); for (insn = thread; insn != active_insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CODE_LABEL + if (LABEL_P (insn) && (insn != label || LABEL_NUSES (insn) != 1)) return 0; @@ -1854,11 +1843,11 @@ own_thread_p (rtx thread, rtx label, int allow_fallthrough) /* Ensure that we reach a BARRIER before any insn or label. */ for (insn = prev_nonnote_insn (thread); - insn == 0 || GET_CODE (insn) != BARRIER; + insn == 0 || !BARRIER_P (insn); insn = prev_nonnote_insn (insn)) if (insn == 0 - || GET_CODE (insn) == CODE_LABEL - || (GET_CODE (insn) == INSN + || LABEL_P (insn) + || (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)) return 0; @@ -1906,7 +1895,7 @@ reorg_redirect_jump (rtx jump, rtx nlabel) that reference values used in INSN. If we find one, then we move the REG_DEAD note to INSN. - This is needed to handle the case where an later insn (after INSN) has a + This is needed to handle the case where a later insn (after INSN) has a REG_DEAD note for a register used by INSN, and this later insn subsequently gets moved before a CODE_LABEL because it is a redundant insn. In this case, mark_target_live_regs may be confused into thinking the register @@ -1924,7 +1913,7 @@ update_reg_dead_notes (rtx insn, rtx delayed_insn) next = XEXP (link, 1); if (REG_NOTE_KIND (link) != REG_DEAD - || GET_CODE (XEXP (link, 0)) != REG) + || !REG_P (XEXP (link, 0))) continue; if (reg_referenced_p (XEXP (link, 0), PATTERN (insn))) @@ -1957,7 +1946,7 @@ fix_reg_dead_note (rtx start_insn, rtx stop_insn) next = XEXP (link, 1); if (REG_NOTE_KIND (link) != REG_DEAD - || GET_CODE (XEXP (link, 0)) != REG) + || !REG_P (XEXP (link, 0))) continue; if (reg_set_p (XEXP (link, 0), PATTERN (start_insn))) @@ -1985,7 +1974,7 @@ update_reg_unused_notes (rtx insn, rtx redundant_insn) next = XEXP (link, 1); if (REG_NOTE_KIND (link) != REG_UNUSED - || GET_CODE (XEXP (link, 0)) != REG) + || !REG_P (XEXP (link, 0))) continue; if (! find_regno_note (redundant_insn, REG_UNUSED, @@ -1994,6 +1983,28 @@ update_reg_unused_notes (rtx insn, rtx redundant_insn) } } +/* Return the label before INSN, or put a new label there. */ + +static rtx +get_label_before (rtx insn) +{ + rtx label; + + /* Find an existing label at this point + or make a new one if there is none. */ + label = prev_nonnote_insn (insn); + + if (label == 0 || !LABEL_P (label)) + { + rtx prev = PREV_INSN (insn); + + label = gen_label_rtx (); + emit_label_after (label, prev); + LABEL_NUSES (label) = 0; + } + return label; +} + /* Scan a function looking for insns that need a delay slot and find insns to put into the delay slot. @@ -2027,10 +2038,10 @@ fill_simple_delay_slots (int non_jumps_p) insn = unfilled_slots_base[i]; if (insn == 0 || INSN_DELETED_P (insn) - || (GET_CODE (insn) == INSN + || (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) - || (GET_CODE (insn) == JUMP_INSN && non_jumps_p) - || (GET_CODE (insn) != JUMP_INSN && ! non_jumps_p)) + || (JUMP_P (insn) && non_jumps_p) + || (!JUMP_P (insn) && ! non_jumps_p)) continue; /* It may have been that this insn used to need delay slots, but @@ -2074,13 +2085,13 @@ fill_simple_delay_slots (int non_jumps_p) slots_filled = 0; delay_list = 0; - if (GET_CODE (insn) == JUMP_INSN) + if (JUMP_P (insn)) flags = get_jump_flags (insn, JUMP_LABEL (insn)); else flags = get_jump_flags (insn, NULL_RTX); if ((trial = next_active_insn (insn)) - && GET_CODE (trial) == JUMP_INSN + && JUMP_P (trial) && simplejump_p (trial) && eligible_for_delay (insn, slots_filled, trial, flags) && no_labels_between_p (insn, trial) @@ -2131,7 +2142,7 @@ fill_simple_delay_slots (int non_jumps_p) CLEAR_RESOURCE (&needed); CLEAR_RESOURCE (&set); mark_set_resources (insn, &set, 0, MARK_SRC_DEST); - mark_referenced_resources (insn, &needed, 0); + mark_referenced_resources (insn, &needed, false); for (trial = prev_nonnote_insn (insn); ! stop_search_p (trial, 1); trial = next_trial) @@ -2147,9 +2158,9 @@ fill_simple_delay_slots (int non_jumps_p) /* Check for resource conflict first, to avoid unnecessary splitting. */ - if (! insn_references_resource_p (trial, &set, 1) - && ! insn_sets_resource_p (trial, &set, 1) - && ! insn_sets_resource_p (trial, &needed, 1) + if (! insn_references_resource_p (trial, &set, true) + && ! insn_sets_resource_p (trial, &set, true) + && ! insn_sets_resource_p (trial, &needed, true) #ifdef HAVE_cc0 /* Can't separate set of cc0 from its use. */ && ! (reg_mentioned_p (cc0_rtx, pat) && ! sets_cc0_p (pat)) @@ -2177,7 +2188,7 @@ fill_simple_delay_slots (int non_jumps_p) } mark_set_resources (trial, &set, 0, MARK_SRC_DEST_CALL); - mark_referenced_resources (trial, &needed, 1); + mark_referenced_resources (trial, &needed, true); } } @@ -2187,7 +2198,7 @@ fill_simple_delay_slots (int non_jumps_p) #if defined(ANNUL_IFFALSE_SLOTS) || defined(ANNUL_IFTRUE_SLOTS) if (slots_filled != slots_to_fill && delay_list == 0 - && GET_CODE (insn) == JUMP_INSN + && JUMP_P (insn) && (condjump_p (insn) || condjump_in_parallel_p (insn))) { delay_list = optimize_skip (insn); @@ -2231,7 +2242,7 @@ fill_simple_delay_slots (int non_jumps_p) Presumably, we should also check to see if we could get back to this function via `setjmp'. */ && ! can_throw_internal (insn) - && (GET_CODE (insn) != JUMP_INSN + && (!JUMP_P (insn) || ((condjump_p (insn) || condjump_in_parallel_p (insn)) && ! simplejump_p (insn) && JUMP_LABEL (insn) != 0))) @@ -2245,17 +2256,17 @@ fill_simple_delay_slots (int non_jumps_p) CLEAR_RESOURCE (&needed); CLEAR_RESOURCE (&set); - if (GET_CODE (insn) == CALL_INSN) + if (CALL_P (insn)) { mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL); - mark_referenced_resources (insn, &needed, 1); + mark_referenced_resources (insn, &needed, true); maybe_never = 1; } else { mark_set_resources (insn, &set, 0, MARK_SRC_DEST_CALL); - mark_referenced_resources (insn, &needed, 1); - if (GET_CODE (insn) == JUMP_INSN) + mark_referenced_resources (insn, &needed, true); + if (JUMP_P (insn)) target = JUMP_LABEL (insn); } @@ -2264,8 +2275,8 @@ fill_simple_delay_slots (int non_jumps_p) { next_trial = next_nonnote_insn (trial); - if (GET_CODE (trial) == CODE_LABEL - || GET_CODE (trial) == BARRIER) + if (LABEL_P (trial) + || BARRIER_P (trial)) break; /* We must have an INSN, JUMP_INSN, or CALL_INSN. */ @@ -2283,19 +2294,19 @@ fill_simple_delay_slots (int non_jumps_p) trial_delay = trial; /* Stop our search when seeing an unconditional jump. */ - if (GET_CODE (trial_delay) == JUMP_INSN) + if (JUMP_P (trial_delay)) break; /* See if we have a resource problem before we try to split. */ if (GET_CODE (pat) != SEQUENCE - && ! insn_references_resource_p (trial, &set, 1) - && ! insn_sets_resource_p (trial, &set, 1) - && ! insn_sets_resource_p (trial, &needed, 1) + && ! insn_references_resource_p (trial, &set, true) + && ! insn_sets_resource_p (trial, &set, true) + && ! insn_sets_resource_p (trial, &needed, true) #ifdef HAVE_cc0 && ! (reg_mentioned_p (cc0_rtx, pat) && ! sets_cc0_p (pat)) #endif - && ! (maybe_never && may_trap_p (pat)) + && ! (maybe_never && may_trap_or_fault_p (pat)) && (trial = try_split (pat, trial, 0)) && eligible_for_delay (insn, slots_filled, trial, flags) && ! can_throw_internal(trial)) @@ -2315,7 +2326,7 @@ fill_simple_delay_slots (int non_jumps_p) } mark_set_resources (trial, &set, 0, MARK_SRC_DEST_CALL); - mark_referenced_resources (trial, &needed, 1); + mark_referenced_resources (trial, &needed, true); /* Ensure we don't put insns between the setting of cc and the comparison by moving a setting of cc into an earlier delay @@ -2323,8 +2334,8 @@ fill_simple_delay_slots (int non_jumps_p) set.cc = 1; /* If this is a call or jump, we might not get here. */ - if (GET_CODE (trial_delay) == CALL_INSN - || GET_CODE (trial_delay) == JUMP_INSN) + if (CALL_P (trial_delay) + || JUMP_P (trial_delay)) maybe_never = 1; } @@ -2335,20 +2346,20 @@ fill_simple_delay_slots (int non_jumps_p) Don't do this if the insn at the branch target is a branch. */ if (slots_to_fill != slots_filled && trial - && GET_CODE (trial) == JUMP_INSN + && JUMP_P (trial) && simplejump_p (trial) && (target == 0 || JUMP_LABEL (trial) == target) && (next_trial = next_active_insn (JUMP_LABEL (trial))) != 0 - && ! (GET_CODE (next_trial) == INSN + && ! (NONJUMP_INSN_P (next_trial) && GET_CODE (PATTERN (next_trial)) == SEQUENCE) - && GET_CODE (next_trial) != JUMP_INSN - && ! insn_references_resource_p (next_trial, &set, 1) - && ! insn_sets_resource_p (next_trial, &set, 1) - && ! insn_sets_resource_p (next_trial, &needed, 1) + && !JUMP_P (next_trial) + && ! insn_references_resource_p (next_trial, &set, true) + && ! insn_sets_resource_p (next_trial, &set, true) + && ! insn_sets_resource_p (next_trial, &needed, true) #ifdef HAVE_cc0 && ! reg_mentioned_p (cc0_rtx, PATTERN (next_trial)) #endif - && ! (maybe_never && may_trap_p (PATTERN (next_trial))) + && ! (maybe_never && may_trap_or_fault_p (PATTERN (next_trial))) && (next_trial = try_split (PATTERN (next_trial), next_trial, 0)) && eligible_for_delay (insn, slots_filled, next_trial, flags) && ! can_throw_internal (trial)) @@ -2362,21 +2373,24 @@ fill_simple_delay_slots (int non_jumps_p) else new_label = find_end_label (); - delay_list - = add_to_delay_list (copy_rtx (next_trial), delay_list); - slots_filled++; - reorg_redirect_jump (trial, new_label); - - /* If we merged because we both jumped to the same place, - redirect the original insn also. */ - if (target) - reorg_redirect_jump (insn, new_label); + if (new_label) + { + delay_list + = add_to_delay_list (copy_rtx (next_trial), delay_list); + slots_filled++; + reorg_redirect_jump (trial, new_label); + + /* If we merged because we both jumped to the same place, + redirect the original insn also. */ + if (target) + reorg_redirect_jump (insn, new_label); + } } } /* If this is an unconditional jump, then try to get insns from the target of the jump. */ - if (GET_CODE (insn) == JUMP_INSN + if (JUMP_P (insn) && simplejump_p (insn) && slots_filled != slots_to_fill) delay_list @@ -2403,7 +2417,7 @@ fill_simple_delay_slots (int non_jumps_p) The only thing we can do is scan backwards from the end of the function. If we did this in a previous pass, it is incorrect to do it again. */ - if (current_function_epilogue_delay_list) + if (crtl->epilogue_delay_list) return; slots_to_fill = DELAY_SLOTS_FOR_EPILOGUE; @@ -2442,15 +2456,15 @@ fill_simple_delay_slots (int non_jumps_p) for (trial = get_last_insn (); ! stop_search_p (trial, 1); trial = PREV_INSN (trial)) { - if (GET_CODE (trial) == NOTE) + if (NOTE_P (trial)) continue; pat = PATTERN (trial); if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER) continue; - if (! insn_references_resource_p (trial, &set, 1) - && ! insn_sets_resource_p (trial, &needed, 1) - && ! insn_sets_resource_p (trial, &set, 1) + if (! insn_references_resource_p (trial, &set, true) + && ! insn_sets_resource_p (trial, &needed, true) + && ! insn_sets_resource_p (trial, &set, true) #ifdef HAVE_cc0 /* Don't want to mess with cc0 here. */ && ! reg_mentioned_p (cc0_rtx, pat) @@ -2463,10 +2477,10 @@ fill_simple_delay_slots (int non_jumps_p) /* Here as well we are searching backward, so put the insns we find on the head of the list. */ - current_function_epilogue_delay_list + crtl->epilogue_delay_list = gen_rtx_INSN_LIST (VOIDmode, trial, - current_function_epilogue_delay_list); - mark_end_of_function_resources (trial, 1); + crtl->epilogue_delay_list); + mark_end_of_function_resources (trial, true); update_block (trial, trial); delete_related_insns (trial); @@ -2480,13 +2494,57 @@ fill_simple_delay_slots (int non_jumps_p) } mark_set_resources (trial, &set, 0, MARK_SRC_DEST_CALL); - mark_referenced_resources (trial, &needed, 1); + mark_referenced_resources (trial, &needed, true); } note_delay_statistics (slots_filled, 0); #endif } +/* 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. */ + +static rtx +follow_jumps (rtx label) +{ + rtx insn; + rtx next; + rtx value = label; + int depth; + + for (depth = 0; + (depth < 10 + && (insn = next_active_insn (value)) != 0 + && JUMP_P (insn) + && ((JUMP_LABEL (insn) != 0 && any_uncondjump_p (insn) + && onlyjump_p (insn)) + || GET_CODE (PATTERN (insn)) == RETURN) + && (next = NEXT_INSN (insn)) + && BARRIER_P (next)); + depth++) + { + rtx tem; + + /* If we have found a cycle, make the insn jump to itself. */ + if (JUMP_LABEL (insn) == label) + return label; + + tem = next_active_insn (JUMP_LABEL (insn)); + if (tem && (GET_CODE (PATTERN (tem)) == ADDR_VEC + || GET_CODE (PATTERN (tem)) == ADDR_DIFF_VEC)) + break; + + value = JUMP_LABEL (insn); + } + if (depth == 10) + return label; + return value; +} + /* Try to find insns to place in delay slots. INSN is the jump needing SLOTS_TO_FILL delay slots. It tests CONDITION @@ -2525,9 +2583,8 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, int flags; /* Validate our arguments. */ - if ((condition == const_true_rtx && ! thread_if_true) - || (! own_thread && ! thread_if_true)) - abort (); + gcc_assert(condition != const_true_rtx || thread_if_true); + gcc_assert(own_thread || thread_if_true); flags = get_jump_flags (insn, JUMP_LABEL (insn)); @@ -2570,7 +2627,7 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, rtx pat, old_trial; /* If we have passed a label, we no longer own this thread. */ - if (GET_CODE (trial) == CODE_LABEL) + if (LABEL_P (trial)) { own_thread = 0; continue; @@ -2582,9 +2639,9 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, /* If TRIAL conflicts with the insns ahead of it, we lose. Also, don't separate or copy insns that set and use CC0. */ - if (! insn_references_resource_p (trial, &set, 1) - && ! insn_sets_resource_p (trial, &set, 1) - && ! insn_sets_resource_p (trial, &needed, 1) + if (! insn_references_resource_p (trial, &set, true) + && ! insn_sets_resource_p (trial, &set, true) + && ! insn_sets_resource_p (trial, &needed, true) #ifdef HAVE_cc0 && ! (reg_mentioned_p (cc0_rtx, pat) && (! own_thread || ! sets_cc0_p (pat))) @@ -2625,8 +2682,8 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, go into an annulled delay slot. */ if (!must_annul && (condition == const_true_rtx - || (! insn_sets_resource_p (trial, &opposite_needed, 1) - && ! may_trap_p (pat)))) + || (! insn_sets_resource_p (trial, &opposite_needed, true) + && ! may_trap_or_fault_p (pat)))) { old_trial = trial; trial = try_split (pat, trial, 0); @@ -2689,15 +2746,41 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, /* We are moving this insn, not deleting it. We must temporarily increment the use count on any referenced label lest it be deleted by delete_related_insns. */ - note = find_reg_note (trial, REG_LABEL, 0); - /* REG_LABEL could be NOTE_INSN_DELETED_LABEL too. */ - if (note && GET_CODE (XEXP (note, 0)) == CODE_LABEL) - LABEL_NUSES (XEXP (note, 0))++; + for (note = REG_NOTES (trial); + note != NULL_RTX; + note = XEXP (note, 1)) + if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND + || REG_NOTE_KIND (note) == REG_LABEL_TARGET) + { + /* REG_LABEL_OPERAND could be + NOTE_INSN_DELETED_LABEL too. */ + if (LABEL_P (XEXP (note, 0))) + LABEL_NUSES (XEXP (note, 0))++; + else + gcc_assert (REG_NOTE_KIND (note) + == REG_LABEL_OPERAND); + } + if (JUMP_P (trial) && JUMP_LABEL (trial)) + LABEL_NUSES (JUMP_LABEL (trial))++; delete_related_insns (trial); - if (note && GET_CODE (XEXP (note, 0)) == CODE_LABEL) - LABEL_NUSES (XEXP (note, 0))--; + for (note = REG_NOTES (trial); + note != NULL_RTX; + note = XEXP (note, 1)) + if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND + || REG_NOTE_KIND (note) == REG_LABEL_TARGET) + { + /* REG_LABEL_OPERAND could be + NOTE_INSN_DELETED_LABEL too. */ + if (LABEL_P (XEXP (note, 0))) + LABEL_NUSES (XEXP (note, 0))--; + else + gcc_assert (REG_NOTE_KIND (note) + == REG_LABEL_OPERAND); + } + if (JUMP_P (trial) && JUMP_LABEL (trial)) + LABEL_NUSES (JUMP_LABEL (trial))--; } else new_thread = next_active_insn (trial); @@ -2714,10 +2797,11 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, may be branching to a location that has a redundant insn. Skip any if so. */ while (new_thread && ! own_thread - && ! insn_sets_resource_p (new_thread, &set, 1) - && ! insn_sets_resource_p (new_thread, &needed, 1) + && ! insn_sets_resource_p (new_thread, &set, true) + && ! insn_sets_resource_p (new_thread, &needed, + true) && ! insn_references_resource_p (new_thread, - &set, 1) + &set, true) && (prior_insn = redundant_insn (new_thread, insn, delay_list))) @@ -2739,7 +2823,7 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, /* This insn can't go into a delay slot. */ lose = 1; mark_set_resources (trial, &set, 0, MARK_SRC_DEST_CALL); - mark_referenced_resources (trial, &needed, 1); + mark_referenced_resources (trial, &needed, true); /* Ensure we don't put insns between the setting of cc and the comparison by moving a setting of cc into an earlier delay slot since these insns @@ -2763,14 +2847,14 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, a PRE_INC. We also can't do this if there's overlap of source and destination. Overlap may happen for larger-than-register-size modes. */ - if (GET_CODE (trial) == INSN && GET_CODE (pat) == SET - && GET_CODE (SET_SRC (pat)) == REG - && GET_CODE (SET_DEST (pat)) == REG + if (NONJUMP_INSN_P (trial) && GET_CODE (pat) == SET + && REG_P (SET_SRC (pat)) + && REG_P (SET_DEST (pat)) && !reg_overlap_mentioned_p (SET_DEST (pat), SET_SRC (pat))) { rtx next = next_nonnote_insn (trial); - if (next && GET_CODE (next) == INSN + if (next && NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) != USE && ! reg_set_p (SET_DEST (pat), next) && ! reg_set_p (SET_SRC (pat), next) @@ -2782,9 +2866,9 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, /* If we stopped on a branch insn that has delay slots, see if we can steal some of the insns in those slots. */ - if (trial && GET_CODE (trial) == INSN + if (trial && NONJUMP_INSN_P (trial) && GET_CODE (PATTERN (trial)) == SEQUENCE - && GET_CODE (XVECEXP (PATTERN (trial), 0, 0)) == JUMP_INSN) + && JUMP_P (XVECEXP (PATTERN (trial), 0, 0))) { /* If this is the `true' thread, we will want to follow the jump, so we can only do this if we have taken everything up to here. */ @@ -2817,7 +2901,7 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, arithmetic insn after the jump insn and put the arithmetic insn in the delay slot. If we can't do this, return. */ if (delay_list == 0 && likely && new_thread - && GET_CODE (new_thread) == INSN + && NONJUMP_INSN_P (new_thread) && GET_CODE (PATTERN (new_thread)) != ASM_INPUT && asm_noperands (PATTERN (new_thread)) < 0) { @@ -2828,7 +2912,7 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, trial = new_thread; pat = PATTERN (trial); - if (GET_CODE (trial) != INSN + if (!NONJUMP_INSN_P (trial) || GET_CODE (pat) != SET || ! eligible_for_delay (insn, 0, trial, flags) || can_throw_internal (trial)) @@ -2837,6 +2921,8 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, dest = SET_DEST (pat), src = SET_SRC (pat); if ((GET_CODE (src) == PLUS || GET_CODE (src) == MINUS) && rtx_equal_p (XEXP (src, 0), dest) + && (!FLOAT_MODE_P (GET_MODE (src)) + || flag_unsafe_math_optimizations) && ! reg_overlap_mentioned_p (dest, XEXP (src, 1)) && ! side_effects_p (pat)) { @@ -2847,7 +2933,7 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, /* If this is a constant adjustment, use the same code with the negated constant. Otherwise, reverse the sense of the arithmetic. */ - if (GET_CODE (other) == CONST_INT) + if (CONST_INT_P (other)) new_arith = gen_rtx_fmt_ee (GET_CODE (src), GET_MODE (src), dest, negate_rtx (GET_MODE (src), other)); else @@ -2897,10 +2983,9 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, { rtx label; - if (! thread_if_true) - abort (); + gcc_assert (thread_if_true); - if (new_thread && GET_CODE (new_thread) == JUMP_INSN + if (new_thread && JUMP_P (new_thread) && (simplejump_p (new_thread) || GET_CODE (PATTERN (new_thread)) == RETURN) && redirect_with_delay_list_safe_p (insn, @@ -2910,12 +2995,13 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread, if (new_thread == 0) label = find_end_label (); - else if (GET_CODE (new_thread) == CODE_LABEL) + else if (LABEL_P (new_thread)) label = new_thread; else label = get_label_before (new_thread); - reorg_redirect_jump (insn, label); + if (label) + reorg_redirect_jump (insn, label); } return delay_list; @@ -2950,7 +3036,7 @@ fill_eager_delay_slots (void) insn = unfilled_slots_base[i]; if (insn == 0 || INSN_DELETED_P (insn) - || GET_CODE (insn) != JUMP_INSN + || !JUMP_P (insn) || ! (condjump_p (insn) || condjump_in_parallel_p (insn))) continue; @@ -3055,6 +3141,186 @@ fill_eager_delay_slots (void) } } +static void delete_computation (rtx 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 (rtx note, rtx insn) +{ + rtx our_prev; + rtx reg = XEXP (note, 0); + + for (our_prev = prev_nonnote_insn (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 (CALL_P (our_prev) + && (! RTL_CONST_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. 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 + && 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) && !CALL_P (our_prev)) + break; + + if (GET_CODE (pat) == PARALLEL) + { + /* If we find a SET of something else, we can't + delete the insn. */ + + int i; + + for (i = 0; i < XVECLEN (pat, 0); i++) + { + rtx part = XVECEXP (pat, 0, i); + + if (GET_CODE (part) == SET + && SET_DEST (part) != reg) + break; + } + + if (i == XVECLEN (pat, 0)) + delete_computation (our_prev); + } + else if (GET_CODE (pat) == SET + && REG_P (SET_DEST (pat))) + { + int dest_regno = REGNO (SET_DEST (pat)); + int dest_endregno = END_REGNO (SET_DEST (pat)); + int regno = REGNO (reg); + int endregno = END_REGNO (reg); + + if (dest_regno >= regno + && dest_endregno <= endregno) + delete_computation (our_prev); + + /* We may have a multi-word hard register and some, but not + all, of the words of the register are needed in subsequent + insns. Write REG_UNUSED notes for those parts that were not + needed. */ + else if (dest_regno <= regno + && dest_endregno >= endregno) + { + int i; + + add_reg_note (our_prev, REG_UNUSED, reg); + + for (i = dest_regno; i < dest_endregno; i++) + if (! find_regno_note (our_prev, REG_UNUSED, i)) + break; + + if (i == dest_endregno) + delete_computation (our_prev); + } + } + + break; + } + + /* If PAT references the register that dies here, it is an + additional use. Hence any prior SET isn't dead. However, this + insn becomes the new place for the REG_DEAD note. */ + if (reg_overlap_mentioned_p (reg, pat)) + { + XEXP (note, 1) = REG_NOTES (our_prev); + REG_NOTES (our_prev) = note; + break; + } + } +} + +/* Delete INSN and recursively delete insns that compute values used only + by INSN. This uses the REG_DEAD notes computed during flow analysis. + If we are running before flow.c, we need do nothing since flow.c will + delete dead code. We also can't know if the registers being used are + dead or not at this point. + + Otherwise, look at all our REG_DEAD notes. If a previous insn does + nothing other than set a register that dies in this insn, we can delete + that insn as well. + + On machines with CC0, if CC0 is used in this insn, we may be able to + delete the insn that set it. */ + +static void +delete_computation (rtx insn) +{ + rtx note, next; + +#ifdef HAVE_cc0 + if (reg_referenced_p (cc0_rtx, PATTERN (insn))) + { + rtx prev = prev_nonnote_insn (insn); + /* We assume that at this stage + CC's are always set explicitly + and always immediately before the jump that + will use them. So if the previous insn + exists to set the CC's, delete it + (unless it performs auto-increments, etc.). */ + if (prev && NONJUMP_INSN_P (prev) + && sets_cc0_p (PATTERN (prev))) + { + if (sets_cc0_p (PATTERN (prev)) > 0 + && ! side_effects_p (PATTERN (prev))) + delete_computation (prev); + else + /* Otherwise, show that cc0 won't be used. */ + add_reg_note (prev, REG_UNUSED, cc0_rtx); + } + } +#endif + + for (note = REG_NOTES (insn); note; note = next) + { + next = XEXP (note, 1); + + if (REG_NOTE_KIND (note) != REG_DEAD + /* Verify that the REG_NOTE is legitimate. */ + || !REG_P (XEXP (note, 0))) + continue; + + delete_prior_computation (note, insn); + } + + delete_related_insns (insn); +} + +/* If all INSN does is set the pc, delete it, + and delete the insn that set the condition codes for it + if that's what the previous thing was. */ + +static void +delete_jump (rtx insn) +{ + rtx set = single_set (insn); + + if (set && GET_CODE (SET_DEST (set)) == PC) + delete_computation (insn); +} + + /* Once we have tried two ways to fill a delay slot, make a pass over the code to try to improve the results and to do such things as more jump threading. */ @@ -3075,33 +3341,31 @@ relax_delay_slots (rtx first) /* If this is a jump insn, see if it now jumps to a jump, jumps to the next insn, or jumps to a label that is not the last of a group of consecutive labels. */ - if (GET_CODE (insn) == JUMP_INSN + if (JUMP_P (insn) && (condjump_p (insn) || condjump_in_parallel_p (insn)) && (target_label = JUMP_LABEL (insn)) != 0) { - target_label = follow_jumps (target_label); - /* See comment further down why we must use next_real_insn here, - instead of next_active_insn. */ - target_label = prev_label (next_real_insn (target_label)); - + target_label = skip_consecutive_labels (follow_jumps (target_label)); if (target_label == 0) target_label = find_end_label (); - if (next_active_insn (target_label) == next + if (target_label && next_active_insn (target_label) == next && ! condjump_in_parallel_p (insn)) { delete_jump (insn); continue; } - if (target_label != JUMP_LABEL (insn)) + if (target_label && target_label != JUMP_LABEL (insn)) reorg_redirect_jump (insn, target_label); - /* See if this jump branches around an unconditional jump. - If so, invert this jump and point it to the target of the + /* See if this jump conditionally branches around an unconditional + jump. If so, invert this jump and point it to the target of the second jump. */ - if (next && GET_CODE (next) == JUMP_INSN + if (next && JUMP_P (next) + && any_condjump_p (insn) && (simplejump_p (next) || GET_CODE (PATTERN (next)) == RETURN) + && target_label && next_active_insn (target_label) == next_active_insn (next) && no_labels_between_p (insn, next)) { @@ -3142,10 +3406,10 @@ relax_delay_slots (rtx first) Don't do this if we expect the conditional branch to be true, because we would then be making the more common case longer. */ - if (GET_CODE (insn) == JUMP_INSN + if (JUMP_P (insn) && (simplejump_p (insn) || GET_CODE (PATTERN (insn)) == RETURN) && (other = prev_active_insn (insn)) != 0 - && (condjump_p (other) || condjump_in_parallel_p (other)) + && any_condjump_p (other) && no_labels_between_p (other, insn) && 0 > mostly_true_jump (other, get_branch_condition (other, @@ -3159,7 +3423,7 @@ relax_delay_slots (rtx first) } /* Now look only at cases where we have filled a delay slot. */ - if (GET_CODE (insn) != INSN + if (!NONJUMP_INSN_P (insn) || GET_CODE (PATTERN (insn)) != SEQUENCE) continue; @@ -3183,10 +3447,10 @@ relax_delay_slots (rtx first) Only do so if optimizing for size since this results in slower, but smaller code. */ - if (optimize_size + if (optimize_function_for_size_p (cfun) && GET_CODE (PATTERN (delay_insn)) == RETURN && next - && GET_CODE (next) == JUMP_INSN + && JUMP_P (next) && GET_CODE (PATTERN (next)) == RETURN) { rtx after; @@ -3206,13 +3470,12 @@ relax_delay_slots (rtx first) trial = PREV_INSN (insn); delete_related_insns (insn); - if (GET_CODE (pat) != SEQUENCE) - abort (); + gcc_assert (GET_CODE (pat) == SEQUENCE); after = trial; for (i = 0; i < XVECLEN (pat, 0); i++) { rtx this_insn = XVECEXP (pat, 0, i); - add_insn_after (this_insn, after); + add_insn_after (this_insn, after, NULL); after = this_insn; } delete_scheduled_jump (delay_insn); @@ -3220,7 +3483,7 @@ relax_delay_slots (rtx first) } /* Now look only at the cases where we have a filled JUMP_INSN. */ - if (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) != JUMP_INSN + if (!JUMP_P (XVECEXP (PATTERN (insn), 0, 0)) || ! (condjump_p (XVECEXP (PATTERN (insn), 0, 0)) || condjump_in_parallel_p (XVECEXP (PATTERN (insn), 0, 0)))) continue; @@ -3231,17 +3494,11 @@ relax_delay_slots (rtx first) { /* If this jump goes to another unconditional jump, thread it, but don't convert a jump into a RETURN here. */ - trial = follow_jumps (target_label); - /* We use next_real_insn instead of next_active_insn, so that - the special USE insns emitted by reorg won't be ignored. - If they are ignored, then they will get deleted if target_label - is now unreachable, and that would cause mark_target_live_regs - to fail. */ - trial = prev_label (next_real_insn (trial)); - if (trial == 0 && target_label != 0) + trial = skip_consecutive_labels (follow_jumps (target_label)); + if (trial == 0) trial = find_end_label (); - if (trial != target_label + if (trial && trial != target_label && redirect_with_delay_slots_safe_p (delay_insn, trial, insn)) { reorg_redirect_jump (delay_insn, trial); @@ -3255,30 +3512,31 @@ relax_delay_slots (rtx first) && redundant_insn (trial, insn, 0) && ! can_throw_internal (trial)) { - rtx tmp; - /* Figure out where to emit the special USE insn so we don't later incorrectly compute register live/death info. */ - tmp = next_active_insn (trial); + rtx tmp = next_active_insn (trial); if (tmp == 0) tmp = find_end_label (); - /* Insert the special USE insn and update dataflow info. */ - update_block (trial, tmp); + if (tmp) + { + /* Insert the special USE insn and update dataflow info. */ + update_block (trial, tmp); - /* Now emit a label before the special USE insn, and - redirect our jump to the new label. */ - target_label = get_label_before (PREV_INSN (tmp)); - reorg_redirect_jump (delay_insn, target_label); - next = insn; - continue; + /* Now emit a label before the special USE insn, and + redirect our jump to the new label. */ + target_label = get_label_before (PREV_INSN (tmp)); + reorg_redirect_jump (delay_insn, target_label); + next = insn; + continue; + } } /* Similarly, if it is an unconditional jump with one insn in its delay list and that insn is redundant, thread the jump. */ if (trial && GET_CODE (PATTERN (trial)) == SEQUENCE && XVECLEN (PATTERN (trial), 0) == 2 - && GET_CODE (XVECEXP (PATTERN (trial), 0, 0)) == JUMP_INSN + && JUMP_P (XVECEXP (PATTERN (trial), 0, 0)) && (simplejump_p (XVECEXP (PATTERN (trial), 0, 0)) || GET_CODE (PATTERN (XVECEXP (PATTERN (trial), 0, 0))) == RETURN) && redundant_insn (XVECEXP (PATTERN (trial), 0, 1), insn, 0)) @@ -3287,8 +3545,9 @@ relax_delay_slots (rtx first) if (target_label == 0) target_label = find_end_label (); - if (redirect_with_delay_slots_safe_p (delay_insn, target_label, - insn)) + if (target_label + && redirect_with_delay_slots_safe_p (delay_insn, target_label, + insn)) { reorg_redirect_jump (delay_insn, target_label); next = insn; @@ -3329,13 +3588,12 @@ relax_delay_slots (rtx first) trial = PREV_INSN (insn); delete_related_insns (insn); - if (GET_CODE (pat) != SEQUENCE) - abort (); + gcc_assert (GET_CODE (pat) == SEQUENCE); after = trial; for (i = 0; i < XVECLEN (pat, 0); i++) { rtx this_insn = XVECEXP (pat, 0, i); - add_insn_after (this_insn, after); + add_insn_after (this_insn, after, NULL); after = this_insn; } delete_scheduled_jump (delay_insn); @@ -3345,7 +3603,7 @@ relax_delay_slots (rtx first) /* See if this is an unconditional jump around a single insn which is identical to the one in its delay slot. In this case, we can just delete the branch and the insn in its delay slot. */ - if (next && GET_CODE (next) == INSN + if (next && NONJUMP_INSN_P (next) && prev_label (next_active_insn (next)) == target_label && simplejump_p (insn) && XVECLEN (pat, 0) == 2 @@ -3355,13 +3613,14 @@ relax_delay_slots (rtx first) continue; } - /* See if this jump (with its delay slots) branches around another - jump (without delay slots). If so, invert this jump and point - it to the target of the second jump. We cannot do this for - annulled jumps, though. Again, don't convert a jump to a RETURN - here. */ + /* See if this jump (with its delay slots) conditionally branches + around an unconditional jump (without delay slots). If so, invert + this jump and point it to the target of the second jump. We cannot + do this for annulled jumps, though. Again, don't convert a jump to + a RETURN here. */ if (! INSN_ANNULLED_BRANCH_P (delay_insn) - && next && GET_CODE (next) == JUMP_INSN + && any_condjump_p (delay_insn) + && next && JUMP_P (next) && (simplejump_p (next) || GET_CODE (PATTERN (next)) == RETURN) && next_active_insn (target_label) == next_active_insn (next) && no_labels_between_p (insn, next)) @@ -3373,7 +3632,8 @@ relax_delay_slots (rtx first) label = find_end_label (); /* find_end_label can generate a new label. Check this first. */ - if (no_labels_between_p (insn, next) + if (label + && no_labels_between_p (insn, next) && redirect_with_delay_slots_safe_p (delay_insn, label, insn)) { /* Be careful how we do this to avoid deleting code or labels @@ -3440,7 +3700,7 @@ make_return_insns (rtx first) delay slot filler insns. It is also unknown whether such a transformation would actually be profitable. Note that the existing code only cares for branches with (some) filled delay slots. */ - if (current_function_epilogue_delay_list != NULL) + if (crtl->epilogue_delay_list != NULL) return; #endif @@ -3448,7 +3708,7 @@ make_return_insns (rtx first) made for END_OF_FUNCTION_LABEL. If so, set up anything we can't change into a RETURN to jump to it. */ for (insn = first; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == RETURN) + if (JUMP_P (insn) && GET_CODE (PATTERN (insn)) == RETURN) { real_return_label = get_label_before (insn); break; @@ -3467,9 +3727,9 @@ make_return_insns (rtx first) /* Only look at filled JUMP_INSNs that go to the end of function label. */ - if (GET_CODE (insn) != INSN + if (!NONJUMP_INSN_P (insn) || GET_CODE (PATTERN (insn)) != SEQUENCE - || GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) != JUMP_INSN + || !JUMP_P (XVECEXP (PATTERN (insn), 0, 0)) || JUMP_LABEL (XVECEXP (PATTERN (insn), 0, 0)) != end_of_function_label) continue; @@ -3558,25 +3818,14 @@ make_return_insns (rtx first) /* Try to find insns to place in delay slots. */ void -dbr_schedule (rtx first, FILE *file) +dbr_schedule (rtx first) { rtx insn, next, epilogue_insn = 0; int i; -#if 0 - int old_flag_no_peephole = flag_no_peephole; - - /* Execute `final' once in prescan mode to delete any insns that won't be - used. Don't let final try to do any peephole optimization--it will - ruin dataflow information for this pass. */ - - flag_no_peephole = 1; - final (first, 0, NO_DEBUG, 1, 1); - flag_no_peephole = old_flag_no_peephole; -#endif /* If the current function has no insns other than the prologue and epilogue, then do not try to fill any delay slots. */ - if (n_basic_blocks == 0) + if (n_basic_blocks == NUM_FIXED_BLOCKS) return; /* Find the highest INSN_UID and allocate and initialize our map from @@ -3585,12 +3834,12 @@ dbr_schedule (rtx first, FILE *file) { if (INSN_UID (insn) > max_uid) max_uid = INSN_UID (insn); - if (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG) + if (NOTE_P (insn) + && NOTE_KIND (insn) == NOTE_INSN_EPILOGUE_BEG) epilogue_insn = insn; } - uid_to_ruid = xmalloc ((max_uid + 1) * sizeof (int)); + uid_to_ruid = XNEWVEC (int, max_uid + 1); for (i = 0, insn = first; insn; i++, insn = NEXT_INSN (insn)) uid_to_ruid[INSN_UID (insn)] = i; @@ -3598,7 +3847,7 @@ dbr_schedule (rtx first, FILE *file) if (unfilled_firstobj == 0) { gcc_obstack_init (&unfilled_slots_obstack); - unfilled_firstobj = obstack_alloc (&unfilled_slots_obstack, 0); + unfilled_firstobj = XOBNEWVAR (&unfilled_slots_obstack, rtx, 0); } for (insn = next_active_insn (first); insn; insn = next_active_insn (insn)) @@ -3609,19 +3858,17 @@ dbr_schedule (rtx first, FILE *file) INSN_FROM_TARGET_P (insn) = 0; /* Skip vector tables. We can't get attributes for them. */ - if (GET_CODE (insn) == JUMP_INSN - && (GET_CODE (PATTERN (insn)) == ADDR_VEC - || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)) + if (JUMP_TABLE_DATA_P (insn)) continue; if (num_delay_slots (insn) > 0) obstack_ptr_grow (&unfilled_slots_obstack, insn); /* Ensure all jumps go to the last of a set of consecutive labels. */ - if (GET_CODE (insn) == JUMP_INSN + if (JUMP_P (insn) && (condjump_p (insn) || condjump_in_parallel_p (insn)) && JUMP_LABEL (insn) != 0 - && ((target = prev_label (next_active_insn (JUMP_LABEL (insn)))) + && ((target = skip_consecutive_labels (JUMP_LABEL (insn))) != JUMP_LABEL (insn))) redirect_jump (insn, target, 1); } @@ -3648,17 +3895,6 @@ dbr_schedule (rtx first, FILE *file) relax_delay_slots (first); } - /* Delete any USE insns made by update_block; subsequent passes don't need - them or know how to deal with them. */ - for (insn = first; insn; insn = next) - { - next = NEXT_INSN (insn); - - if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE - && INSN_P (XEXP (PATTERN (insn), 0))) - next = delete_related_insns (insn); - } - /* If we made an end of function label, indicate that it is now safe to delete it by undoing our prior adjustment to LABEL_NUSES. If it is now unused, delete it. */ @@ -3670,12 +3906,23 @@ dbr_schedule (rtx first, FILE *file) make_return_insns (first); #endif + /* Delete any USE insns made by update_block; subsequent passes don't need + them or know how to deal with them. */ + for (insn = first; insn; insn = next) + { + next = NEXT_INSN (insn); + + if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE + && INSN_P (XEXP (PATTERN (insn), 0))) + next = delete_related_insns (insn); + } + obstack_free (&unfilled_slots_obstack, unfilled_firstobj); /* It is not clear why the line below is needed, but it does seem to be. */ - unfilled_firstobj = obstack_alloc (&unfilled_slots_obstack, 0); + unfilled_firstobj = XOBNEWVAR (&unfilled_slots_obstack, rtx, 0); - if (file) + if (dump_file) { int i, j, need_comma; int total_delay_slots[MAX_DELAY_HISTOGRAM + 1]; @@ -3685,25 +3932,25 @@ dbr_schedule (rtx first, FILE *file) reorg_pass_number < MAX_REORG_PASSES; reorg_pass_number++) { - fprintf (file, ";; Reorg pass #%d:\n", reorg_pass_number + 1); + fprintf (dump_file, ";; Reorg pass #%d:\n", reorg_pass_number + 1); for (i = 0; i < NUM_REORG_FUNCTIONS; i++) { need_comma = 0; - fprintf (file, ";; Reorg function #%d\n", i); + fprintf (dump_file, ";; Reorg function #%d\n", i); - fprintf (file, ";; %d insns needing delay slots\n;; ", + fprintf (dump_file, ";; %d insns needing delay slots\n;; ", num_insns_needing_delays[i][reorg_pass_number]); for (j = 0; j < MAX_DELAY_HISTOGRAM + 1; j++) if (num_filled_delays[i][j][reorg_pass_number]) { if (need_comma) - fprintf (file, ", "); + fprintf (dump_file, ", "); need_comma = 1; - fprintf (file, "%d got %d delays", + fprintf (dump_file, "%d got %d delays", num_filled_delays[i][j][reorg_pass_number], j); } - fprintf (file, "\n"); + fprintf (dump_file, "\n"); } } memset (total_delay_slots, 0, sizeof total_delay_slots); @@ -3711,7 +3958,7 @@ dbr_schedule (rtx first, FILE *file) for (insn = first; insn; insn = NEXT_INSN (insn)) { if (! INSN_DELETED_P (insn) - && GET_CODE (insn) == INSN + && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER) { @@ -3729,35 +3976,35 @@ dbr_schedule (rtx first, FILE *file) total_delay_slots[0]++; } } - fprintf (file, ";; Reorg totals: "); + fprintf (dump_file, ";; Reorg totals: "); need_comma = 0; for (j = 0; j < MAX_DELAY_HISTOGRAM + 1; j++) { if (total_delay_slots[j]) { if (need_comma) - fprintf (file, ", "); + fprintf (dump_file, ", "); need_comma = 1; - fprintf (file, "%d got %d delays", total_delay_slots[j], j); + fprintf (dump_file, "%d got %d delays", total_delay_slots[j], j); } } - fprintf (file, "\n"); + fprintf (dump_file, "\n"); #if defined (ANNUL_IFTRUE_SLOTS) || defined (ANNUL_IFFALSE_SLOTS) - fprintf (file, ";; Reorg annuls: "); + fprintf (dump_file, ";; Reorg annuls: "); need_comma = 0; for (j = 0; j < MAX_DELAY_HISTOGRAM + 1; j++) { if (total_annul_slots[j]) { if (need_comma) - fprintf (file, ", "); + fprintf (dump_file, ", "); need_comma = 1; - fprintf (file, "%d got %d delays", total_annul_slots[j], j); + fprintf (dump_file, "%d got %d delays", total_annul_slots[j], j); } } - fprintf (file, "\n"); + fprintf (dump_file, "\n"); #endif - fprintf (file, "\n"); + fprintf (dump_file, "\n"); } /* For all JUMP insns, fill in branch prediction notes, so that during @@ -3769,20 +4016,18 @@ dbr_schedule (rtx first, FILE *file) { int pred_flags; - if (GET_CODE (insn) == INSN) + if (NONJUMP_INSN_P (insn)) { rtx pat = PATTERN (insn); if (GET_CODE (pat) == SEQUENCE) insn = XVECEXP (pat, 0, 0); } - if (GET_CODE (insn) != JUMP_INSN) + if (!JUMP_P (insn)) continue; pred_flags = get_jump_flags (insn, JUMP_LABEL (insn)); - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_BR_PRED, - GEN_INT (pred_flags), - REG_NOTES (insn)); + add_reg_note (insn, REG_BR_PRED, GEN_INT (pred_flags)); } free_resource_info (); free (uid_to_ruid); @@ -3792,11 +4037,89 @@ dbr_schedule (rtx first, FILE *file) { rtx link; - for (link = current_function_epilogue_delay_list; + for (link = crtl->epilogue_delay_list; link; link = XEXP (link, 1)) INSN_LOCATOR (XEXP (link, 0)) = 0; } + #endif + crtl->dbr_scheduled_p = true; } #endif /* DELAY_SLOTS */ + +static bool +gate_handle_delay_slots (void) +{ +#ifdef DELAY_SLOTS + /* At -O0 dataflow info isn't updated after RA. */ + return optimize > 0 && flag_delayed_branch && !crtl->dbr_scheduled_p; +#else + return 0; +#endif +} + +/* Run delay slot optimization. */ +static unsigned int +rest_of_handle_delay_slots (void) +{ +#ifdef DELAY_SLOTS + dbr_schedule (get_insns ()); +#endif + return 0; +} + +struct rtl_opt_pass pass_delay_slots = +{ + { + RTL_PASS, + "dbr", /* name */ + gate_handle_delay_slots, /* gate */ + rest_of_handle_delay_slots, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_DBR_SCHED, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | + TODO_ggc_collect /* todo_flags_finish */ + } +}; + +/* Machine dependent reorg pass. */ +static bool +gate_handle_machine_reorg (void) +{ + return targetm.machine_dependent_reorg != 0; +} + + +static unsigned int +rest_of_handle_machine_reorg (void) +{ + targetm.machine_dependent_reorg (); + return 0; +} + +struct rtl_opt_pass pass_machine_reorg = +{ + { + RTL_PASS, + "mach", /* name */ + gate_handle_machine_reorg, /* gate */ + rest_of_handle_machine_reorg, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_MACH_DEP, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | + TODO_ggc_collect /* todo_flags_finish */ + } +};