diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ba840404f19..c83917e39f3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2007-02-15 Paolo Bonzini + + * jump.c (get_label_after): Delete. + (get_label_before, delete_computation, delete_jump, + delete_prior_computation, follow_jumps): Move... + * reorg.c (delete_computation, delete_prior_computation): ... here... + (get_label_before, delete_jump): ... making these static ... + (follow_jumps): ... and simplifying this since it only runs after + reload. + * rtl.h (get_label_after, get_label_before, delete_jump, + follow_jumps): Delete prototypes. + 2007-02-15 Paolo Bonzini * caller-save.c (save_call_clobbered_regs): Do not process sibcalls. diff --git a/gcc/jump.c b/gcc/jump.c index d2a905bbbee..a82d407b6cc 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -285,48 +285,6 @@ squeeze_notes (rtx* startp, rtx* endp) return false; } -/* Return the label before INSN, or put a new label there. */ - -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; -} - -/* Return the label after INSN, or put a new label there. */ - -rtx -get_label_after (rtx insn) -{ - rtx label; - - /* Find an existing label at this point - or make a new one if there is none. */ - label = next_nonnote_insn (insn); - - if (label == 0 || !LABEL_P (label)) - { - label = gen_label_rtx (); - emit_label_after (label, insn); - LABEL_NUSES (label) = 0; - } - return label; -} - /* Given a comparison (CODE ARG0 ARG1), inside an insn, INSN, return a code of reversed comparison if it is possible to do so. Otherwise return UNKNOWN. UNKNOWN may be returned in case we are having CC_MODE compare and we don't @@ -1000,61 +958,6 @@ sets_cc0_p (rtx x) return 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. - - If RELOAD_COMPLETED is 0, we do not chain across a USE or CLOBBER. */ - -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 (!reload_completed && flag_test_coverage) - { - /* ??? Optional. Disables some optimizations, but makes - gcov output more accurate with -O. */ - for (tem = value; tem != insn; tem = NEXT_INSN (tem)) - if (NOTE_P (tem) && NOTE_LINE_NUMBER (tem) > 0) - return value; - } - - /* 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; -} - /* Find all CODE_LABELs referred to in X, and increment their use counts. If INSN is a JUMP_INSN and there is at least one CODE_LABEL referenced @@ -1169,192 +1072,6 @@ mark_jump_label (rtx x, rtx insn, int in_mem) } } -/* 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. */ - -void -delete_jump (rtx insn) -{ - rtx set = single_set (insn); - - if (set && GET_CODE (SET_DEST (set)) == PC) - delete_computation (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) - && (! 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. 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 - = (dest_regno - + (dest_regno < FIRST_PSEUDO_REGISTER - ? 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)); - - 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; - - REG_NOTES (our_prev) - = gen_rtx_EXPR_LIST (REG_UNUSED, reg, - REG_NOTES (our_prev)); - - 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. */ - REG_NOTES (prev) = gen_rtx_EXPR_LIST (REG_UNUSED, - cc0_rtx, REG_NOTES (prev)); - } - } -#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); -} /* Delete insn INSN from the chain of insns and update label ref counts and delete insns now unreachable. diff --git a/gcc/reorg.c b/gcc/reorg.c index 8c097dca412..e4655d2ad3d 100644 --- a/gcc/reorg.c +++ b/gcc/reorg.c @@ -1972,6 +1972,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. @@ -2468,6 +2490,50 @@ fill_simple_delay_slots (int non_jumps_p) #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 @@ -3036,6 +3102,196 @@ fill_eager_delay_slots (void) note_delay_statistics (slots_filled, 1); } } + +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) + && (! 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. 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 + = (dest_regno + + (dest_regno < FIRST_PSEUDO_REGISTER + ? 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)); + + 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; + + REG_NOTES (our_prev) + = gen_rtx_EXPR_LIST (REG_UNUSED, reg, + REG_NOTES (our_prev)); + + 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. */ + REG_NOTES (prev) = gen_rtx_EXPR_LIST (REG_UNUSED, + cc0_rtx, REG_NOTES (prev)); + } + } +#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 diff --git a/gcc/rtl.h b/gcc/rtl.h index 80c3114c5e7..fdd582d5fd2 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1598,10 +1598,6 @@ extern unsigned int cleanup_barriers (void); /* In jump.c */ extern bool squeeze_notes (rtx *, rtx *); extern rtx delete_related_insns (rtx); -extern void delete_jump (rtx); -extern rtx get_label_before (rtx); -extern rtx get_label_after (rtx); -extern rtx follow_jumps (rtx); /* In recog.c */ extern rtx *find_constant_term_loc (rtx *);