diff options
author | David S. Miller <davem@pierdol.cobaltmicro.com> | 1998-11-05 06:20:37 +0000 |
---|---|---|
committer | David S. Miller <davem@gcc.gnu.org> | 1998-11-04 22:20:37 -0800 |
commit | 269ef46c05e0e1f97ac82e6bf075332a4ee8b96d (patch) | |
tree | 3891a8892562a3a0ef0922c8f099e512f202c6c7 /gcc | |
parent | b37f006bf09e6f219c27810c2910ec8a95fa7043 (diff) | |
download | gcc-269ef46c05e0e1f97ac82e6bf075332a4ee8b96d.zip gcc-269ef46c05e0e1f97ac82e6bf075332a4ee8b96d.tar.gz gcc-269ef46c05e0e1f97ac82e6bf075332a4ee8b96d.tar.bz2 |
Begin cleaning up jump.c
Begin cleaning up jump.c
* jump.c (init_label_info, delete_barrier_successors,
mark_all_labels, delete_unreferenced_labels,
delete_noop_moves, calculate_can_reach_end): New functions broken
out of jump_optimize.
(jump_optimize): Use them.
From-SVN: r23539
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/jump.c | 828 |
2 files changed, 457 insertions, 379 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 431f4b6..20138d4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +Thu Nov 5 07:59:05 1998 David S. Miller <davem@pierdol.cobaltmicro.com> + + * jump.c (init_label_info, delete_barrier_successors, + mark_all_labels, delete_unreferenced_labels, + delete_noop_moves, calculate_can_reach_end): New functions broken + out of jump_optimize. + (jump_optimize): Use them. + Thu Nov 5 07:57:45 EST 1998 Andrew MacLeod <amacleod@cygnus.com> * except.c (expand_fixup_region_end): Make sure outer context labels @@ -108,6 +108,12 @@ int can_reach_end; static int cross_jump_death_matters = 0; +static int init_label_info PROTO((rtx)); +static void delete_barrier_successors PROTO((rtx)); +static void mark_all_labels PROTO((rtx, int)); +static rtx delete_unreferenced_labels PROTO((rtx)); +static void delete_noop_moves PROTO((rtx)); +static int calculate_can_reach_end PROTO((rtx, int, int)); static int duplicate_loop_exit_test PROTO((rtx)); static void find_cross_jump PROTO((rtx, rtx, int, rtx *, rtx *)); static void do_cross_jump PROTO((rtx, rtx, rtx)); @@ -157,30 +163,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) rtx last_insn; cross_jump_death_matters = (cross_jump == 2); - - /* Initialize LABEL_NUSES and JUMP_LABEL fields. Delete any REG_LABEL - notes whose labels don't occur in the insn any more. */ - - 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) - 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) > max_uid) - max_uid = INSN_UID (insn); - } - - max_uid++; + max_uid = init_label_info (f) + 1; /* If we are performing cross jump optimizations, then initialize tables mapping UIDs to EH regions to avoid incorrect movement @@ -188,26 +171,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) if (flag_exceptions && cross_jump) init_insn_eh_region (f, max_uid); - /* Delete insns following barriers, up to next label. */ - - for (insn = f; insn;) - { - if (GET_CODE (insn) == BARRIER) - { - insn = NEXT_INSN (insn); - while (insn != 0 && GET_CODE (insn) != CODE_LABEL) - { - if (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END) - insn = NEXT_INSN (insn); - else - insn = delete_insn (insn); - } - /* INSN is now the code_label. */ - } - else - insn = NEXT_INSN (insn); - } + delete_barrier_successors (f); /* Leave some extra room for labels and duplicate exit test insns we make. */ @@ -215,32 +179,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) jump_chain = (rtx *) alloca (max_jump_chain * sizeof (rtx)); bzero ((char *) jump_chain, max_jump_chain * sizeof (rtx)); - /* Mark the label each jump jumps to. - Combine consecutive labels, and count uses of labels. - - For each label, make a chain (using `jump_chain') - of all the *unconditional* jumps that jump to it; - also make a chain of all returns. */ - - for (insn = f; insn; insn = NEXT_INSN (insn)) - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') - { - mark_jump_label (PATTERN (insn), insn, cross_jump); - if (! INSN_DELETED_P (insn) && GET_CODE (insn) == JUMP_INSN) - { - if (JUMP_LABEL (insn) != 0 && simplejump_p (insn)) - { - jump_chain[INSN_UID (insn)] - = jump_chain[INSN_UID (JUMP_LABEL (insn))]; - jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn; - } - if (GET_CODE (PATTERN (insn)) == RETURN) - { - jump_chain[INSN_UID (insn)] = jump_chain[0]; - jump_chain[0] = insn; - } - } - } + mark_all_labels (f, cross_jump); /* Keep track of labels used from static data; they cannot ever be deleted. */ @@ -258,51 +197,11 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) exception_optimize (); - /* Delete all labels already not referenced. - Also find the last insn. */ - - last_insn = 0; - for (insn = f; insn; ) - { - if (GET_CODE (insn) == CODE_LABEL && LABEL_NUSES (insn) == 0) - insn = delete_insn (insn); - else - { - last_insn = insn; - insn = NEXT_INSN (insn); - } - } + last_insn = delete_unreferenced_labels (f); if (!optimize) { - /* See if there is still a NOTE_INSN_FUNCTION_END in this function. - If so record that this function can drop off the end. */ - - insn = last_insn; - { - int n_labels = 1; - while (insn - /* One label can follow the end-note: the return label. */ - && ((GET_CODE (insn) == CODE_LABEL && n_labels-- > 0) - /* Ordinary insns can follow it if returning a structure. */ - || GET_CODE (insn) == INSN - /* If machine uses explicit RETURN insns, no epilogue, - then one of them follows the note. */ - || (GET_CODE (insn) == JUMP_INSN - && GET_CODE (PATTERN (insn)) == RETURN) - /* A barrier can follow the return insn. */ - || GET_CODE (insn) == BARRIER - /* Other kinds of notes can follow also. */ - || (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END))) - insn = PREV_INSN (insn); - } - - /* Report if control can fall through at the end of the function. */ - if (insn && GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END - && ! INSN_DELETED_P (insn)) - can_reach_end = 1; + can_reach_end = calculate_can_reach_end (last_insn, 1, 0); /* Zero the "deleted" flag of all the "deleted" insns. */ for (insn = f; insn; insn = NEXT_INSN (insn)) @@ -333,245 +232,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) #endif if (noop_moves) - for (insn = f; insn; ) - { - next = NEXT_INSN (insn); - - if (GET_CODE (insn) == INSN) - { - register rtx body = PATTERN (insn); - -/* Combine stack_adjusts with following push_insns. */ -#ifdef PUSH_ROUNDING - if (GET_CODE (body) == SET - && SET_DEST (body) == stack_pointer_rtx - && GET_CODE (SET_SRC (body)) == PLUS - && XEXP (SET_SRC (body), 0) == stack_pointer_rtx - && GET_CODE (XEXP (SET_SRC (body), 1)) == CONST_INT - && INTVAL (XEXP (SET_SRC (body), 1)) > 0) - { - rtx p; - rtx stack_adjust_insn = insn; - int stack_adjust_amount = INTVAL (XEXP (SET_SRC (body), 1)); - int total_pushed = 0; - int pushes = 0; - - /* Find all successive push insns. */ - p = insn; - /* Don't convert more than three pushes; - that starts adding too many displaced addresses - and the whole thing starts becoming a losing - proposition. */ - while (pushes < 3) - { - rtx pbody, dest; - p = next_nonnote_insn (p); - if (p == 0 || GET_CODE (p) != INSN) - break; - pbody = PATTERN (p); - if (GET_CODE (pbody) != SET) - break; - dest = SET_DEST (pbody); - /* Allow a no-op move between the adjust and the push. */ - if (GET_CODE (dest) == REG - && GET_CODE (SET_SRC (pbody)) == REG - && REGNO (dest) == REGNO (SET_SRC (pbody))) - continue; - if (! (GET_CODE (dest) == MEM - && GET_CODE (XEXP (dest, 0)) == POST_INC - && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)) - break; - pushes++; - if (total_pushed + GET_MODE_SIZE (GET_MODE (SET_DEST (pbody))) - > stack_adjust_amount) - break; - total_pushed += GET_MODE_SIZE (GET_MODE (SET_DEST (pbody))); - } - - /* Discard the amount pushed from the stack adjust; - maybe eliminate it entirely. */ - if (total_pushed >= stack_adjust_amount) - { - delete_computation (stack_adjust_insn); - total_pushed = stack_adjust_amount; - } - else - XEXP (SET_SRC (PATTERN (stack_adjust_insn)), 1) - = GEN_INT (stack_adjust_amount - total_pushed); - - /* Change the appropriate push insns to ordinary stores. */ - p = insn; - while (total_pushed > 0) - { - rtx pbody, dest; - p = next_nonnote_insn (p); - if (GET_CODE (p) != INSN) - break; - pbody = PATTERN (p); - if (GET_CODE (pbody) != SET) - break; - dest = SET_DEST (pbody); - /* Allow a no-op move between the adjust and the push. */ - if (GET_CODE (dest) == REG - && GET_CODE (SET_SRC (pbody)) == REG - && REGNO (dest) == REGNO (SET_SRC (pbody))) - continue; - if (! (GET_CODE (dest) == MEM - && GET_CODE (XEXP (dest, 0)) == POST_INC - && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)) - break; - total_pushed -= GET_MODE_SIZE (GET_MODE (SET_DEST (pbody))); - /* If this push doesn't fully fit in the space - of the stack adjust that we deleted, - make another stack adjust here for what we - didn't use up. There should be peepholes - to recognize the resulting sequence of insns. */ - if (total_pushed < 0) - { - emit_insn_before (gen_add2_insn (stack_pointer_rtx, - GEN_INT (- total_pushed)), - p); - break; - } - XEXP (dest, 0) - = plus_constant (stack_pointer_rtx, total_pushed); - } - } -#endif - - /* Detect and delete no-op move instructions - resulting from not allocating a parameter in a register. */ - - if (GET_CODE (body) == SET - && (SET_DEST (body) == SET_SRC (body) - || (GET_CODE (SET_DEST (body)) == MEM - && GET_CODE (SET_SRC (body)) == MEM - && rtx_equal_p (SET_SRC (body), SET_DEST (body)))) - && ! (GET_CODE (SET_DEST (body)) == MEM - && MEM_VOLATILE_P (SET_DEST (body))) - && ! (GET_CODE (SET_SRC (body)) == MEM - && MEM_VOLATILE_P (SET_SRC (body)))) - delete_computation (insn); - - /* Detect and ignore no-op move instructions - resulting from smart or fortuitous register allocation. */ - - else if (GET_CODE (body) == SET) - { - int sreg = true_regnum (SET_SRC (body)); - int dreg = true_regnum (SET_DEST (body)); - - if (sreg == dreg && sreg >= 0) - delete_insn (insn); - else if (sreg >= 0 && dreg >= 0) - { - rtx trial; - rtx tem = find_equiv_reg (NULL_RTX, insn, 0, - sreg, NULL_PTR, dreg, - GET_MODE (SET_SRC (body))); - - if (tem != 0 - && GET_MODE (tem) == GET_MODE (SET_DEST (body))) - { - /* DREG may have been the target of a REG_DEAD note in - the insn which makes INSN redundant. If so, reorg - would still think it is dead. So search for such a - note and delete it if we find it. */ - if (! find_regno_note (insn, REG_UNUSED, dreg)) - for (trial = prev_nonnote_insn (insn); - trial && GET_CODE (trial) != CODE_LABEL; - trial = prev_nonnote_insn (trial)) - if (find_regno_note (trial, REG_DEAD, dreg)) - { - remove_death (dreg, trial); - break; - } - - /* Deleting insn could lose a death-note for SREG. */ - if ((trial = find_regno_note (insn, REG_DEAD, sreg))) - { - /* Change this into a USE so that we won't emit - code for it, but still can keep the note. */ - PATTERN (insn) - = gen_rtx_USE (VOIDmode, XEXP (trial, 0)); - INSN_CODE (insn) = -1; - /* Remove all reg notes but the REG_DEAD one. */ - REG_NOTES (insn) = trial; - XEXP (trial, 1) = NULL_RTX; - } - else - delete_insn (insn); - } - } - else if (dreg >= 0 && CONSTANT_P (SET_SRC (body)) - && find_equiv_reg (SET_SRC (body), insn, 0, dreg, - NULL_PTR, 0, - GET_MODE (SET_DEST (body)))) - { - /* This handles the case where we have two consecutive - assignments of the same constant to pseudos that didn't - get a hard reg. Each SET from the constant will be - converted into a SET of the spill register and an - output reload will be made following it. This produces - two loads of the same constant into the same spill - register. */ - - rtx in_insn = insn; - - /* Look back for a death note for the first reg. - If there is one, it is no longer accurate. */ - while (in_insn && GET_CODE (in_insn) != CODE_LABEL) - { - if ((GET_CODE (in_insn) == INSN - || GET_CODE (in_insn) == JUMP_INSN) - && find_regno_note (in_insn, REG_DEAD, dreg)) - { - remove_death (dreg, in_insn); - break; - } - in_insn = PREV_INSN (in_insn); - } - - /* Delete the second load of the value. */ - delete_insn (insn); - } - } - else if (GET_CODE (body) == PARALLEL) - { - /* If each part is a set between two identical registers or - a USE or CLOBBER, delete the insn. */ - int i, sreg, dreg; - rtx tem; - - for (i = XVECLEN (body, 0) - 1; i >= 0; i--) - { - tem = XVECEXP (body, 0, i); - if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER) - continue; - - if (GET_CODE (tem) != SET - || (sreg = true_regnum (SET_SRC (tem))) < 0 - || (dreg = true_regnum (SET_DEST (tem))) < 0 - || dreg != sreg) - break; - } - - if (i < 0) - delete_insn (insn); - } - /* Also delete insns to store bit fields if they are no-ops. */ - /* Not worth the hair to detect this in the big-endian case. */ - else if (! BYTES_BIG_ENDIAN - && GET_CODE (body) == SET - && GET_CODE (SET_DEST (body)) == ZERO_EXTRACT - && XEXP (SET_DEST (body), 2) == const0_rtx - && XEXP (SET_DEST (body), 0) == SET_SRC (body) - && ! (GET_CODE (SET_SRC (body)) == MEM - && MEM_VOLATILE_P (SET_SRC (body)))) - delete_insn (insn); - } - insn = next; - } + delete_noop_moves (f); /* If we haven't yet gotten to reload and we have just run regscan, delete any insn that sets a register that isn't used elsewhere. @@ -2371,41 +2032,450 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) } #endif - /* See if there is still a NOTE_INSN_FUNCTION_END in this function. - If so, delete it, and record that this function can drop off the end. */ + can_reach_end = calculate_can_reach_end (last_insn, 0, 1); + + /* Show JUMP_CHAIN no longer valid. */ + jump_chain = 0; +} + +/* 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; +{ + 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); + } + + return largest_uid; +} + +/* Delete insns following barriers, up to next label. */ +static void +delete_barrier_successors (f) + rtx f; +{ + rtx insn; + + for (insn = f; insn;) + { + if (GET_CODE (insn) == BARRIER) + { + insn = NEXT_INSN (insn); + while (insn != 0 && GET_CODE (insn) != CODE_LABEL) + { + if (GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END) + insn = NEXT_INSN (insn); + else + insn = delete_insn (insn); + } + /* INSN is now the code_label. */ + } + else + insn = NEXT_INSN (insn); + } +} + +/* Mark the label each jump jumps to. + Combine consecutive labels, and count uses of labels. + + For each label, make a chain (using `jump_chain') + of all the *unconditional* jumps that jump to it; + also make a chain of all returns. + + CROSS_JUMP indicates whether we are doing cross jumping + and if we are whether we will be paying attention to + death notes or not. */ + +static void +mark_all_labels (f, cross_jump) + rtx f; + int cross_jump; +{ + rtx insn; + + for (insn = f; insn; insn = NEXT_INSN (insn)) + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + { + mark_jump_label (PATTERN (insn), insn, cross_jump); + if (! INSN_DELETED_P (insn) && GET_CODE (insn) == JUMP_INSN) + { + if (JUMP_LABEL (insn) != 0 && simplejump_p (insn)) + { + jump_chain[INSN_UID (insn)] + = jump_chain[INSN_UID (JUMP_LABEL (insn))]; + jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn; + } + if (GET_CODE (PATTERN (insn)) == RETURN) + { + jump_chain[INSN_UID (insn)] = jump_chain[0]; + jump_chain[0] = insn; + } + } + } +} + +/* Delete all labels already not referenced. + Also find and return the last insn. */ + +static rtx +delete_unreferenced_labels (f) + rtx f; +{ + rtx final = NULL_RTX; + rtx insn; + + for (insn = f; insn; ) + { + if (GET_CODE (insn) == CODE_LABEL && LABEL_NUSES (insn) == 0) + insn = delete_insn (insn); + else + { + final = insn; + insn = NEXT_INSN (insn); + } + } + + return final; +} + +/* Delete various simple forms of moves which have no necessary + side effect. */ + +static void +delete_noop_moves (f) + rtx f; +{ + rtx insn, next; + + for (insn = f; insn; ) + { + next = NEXT_INSN (insn); + + if (GET_CODE (insn) == INSN) + { + register rtx body = PATTERN (insn); + +/* Combine stack_adjusts with following push_insns. */ +#ifdef PUSH_ROUNDING + if (GET_CODE (body) == SET + && SET_DEST (body) == stack_pointer_rtx + && GET_CODE (SET_SRC (body)) == PLUS + && XEXP (SET_SRC (body), 0) == stack_pointer_rtx + && GET_CODE (XEXP (SET_SRC (body), 1)) == CONST_INT + && INTVAL (XEXP (SET_SRC (body), 1)) > 0) + { + rtx p; + rtx stack_adjust_insn = insn; + int stack_adjust_amount = INTVAL (XEXP (SET_SRC (body), 1)); + int total_pushed = 0; + int pushes = 0; + + /* Find all successive push insns. */ + p = insn; + /* Don't convert more than three pushes; + that starts adding too many displaced addresses + and the whole thing starts becoming a losing + proposition. */ + while (pushes < 3) + { + rtx pbody, dest; + p = next_nonnote_insn (p); + if (p == 0 || GET_CODE (p) != INSN) + break; + pbody = PATTERN (p); + if (GET_CODE (pbody) != SET) + break; + dest = SET_DEST (pbody); + /* Allow a no-op move between the adjust and the push. */ + if (GET_CODE (dest) == REG + && GET_CODE (SET_SRC (pbody)) == REG + && REGNO (dest) == REGNO (SET_SRC (pbody))) + continue; + if (! (GET_CODE (dest) == MEM + && GET_CODE (XEXP (dest, 0)) == POST_INC + && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)) + break; + pushes++; + if (total_pushed + GET_MODE_SIZE (GET_MODE (SET_DEST (pbody))) + > stack_adjust_amount) + break; + total_pushed += GET_MODE_SIZE (GET_MODE (SET_DEST (pbody))); + } + + /* Discard the amount pushed from the stack adjust; + maybe eliminate it entirely. */ + if (total_pushed >= stack_adjust_amount) + { + delete_computation (stack_adjust_insn); + total_pushed = stack_adjust_amount; + } + else + XEXP (SET_SRC (PATTERN (stack_adjust_insn)), 1) + = GEN_INT (stack_adjust_amount - total_pushed); + + /* Change the appropriate push insns to ordinary stores. */ + p = insn; + while (total_pushed > 0) + { + rtx pbody, dest; + p = next_nonnote_insn (p); + if (GET_CODE (p) != INSN) + break; + pbody = PATTERN (p); + if (GET_CODE (pbody) != SET) + break; + dest = SET_DEST (pbody); + /* Allow a no-op move between the adjust and the push. */ + if (GET_CODE (dest) == REG + && GET_CODE (SET_SRC (pbody)) == REG + && REGNO (dest) == REGNO (SET_SRC (pbody))) + continue; + if (! (GET_CODE (dest) == MEM + && GET_CODE (XEXP (dest, 0)) == POST_INC + && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)) + break; + total_pushed -= GET_MODE_SIZE (GET_MODE (SET_DEST (pbody))); + /* If this push doesn't fully fit in the space + of the stack adjust that we deleted, + make another stack adjust here for what we + didn't use up. There should be peepholes + to recognize the resulting sequence of insns. */ + if (total_pushed < 0) + { + emit_insn_before (gen_add2_insn (stack_pointer_rtx, + GEN_INT (- total_pushed)), + p); + break; + } + XEXP (dest, 0) + = plus_constant (stack_pointer_rtx, total_pushed); + } + } +#endif + + /* Detect and delete no-op move instructions + resulting from not allocating a parameter in a register. */ + + if (GET_CODE (body) == SET + && (SET_DEST (body) == SET_SRC (body) + || (GET_CODE (SET_DEST (body)) == MEM + && GET_CODE (SET_SRC (body)) == MEM + && rtx_equal_p (SET_SRC (body), SET_DEST (body)))) + && ! (GET_CODE (SET_DEST (body)) == MEM + && MEM_VOLATILE_P (SET_DEST (body))) + && ! (GET_CODE (SET_SRC (body)) == MEM + && MEM_VOLATILE_P (SET_SRC (body)))) + delete_computation (insn); + + /* Detect and ignore no-op move instructions + resulting from smart or fortuitous register allocation. */ + + else if (GET_CODE (body) == SET) + { + int sreg = true_regnum (SET_SRC (body)); + int dreg = true_regnum (SET_DEST (body)); + + if (sreg == dreg && sreg >= 0) + delete_insn (insn); + else if (sreg >= 0 && dreg >= 0) + { + rtx trial; + rtx tem = find_equiv_reg (NULL_RTX, insn, 0, + sreg, NULL_PTR, dreg, + GET_MODE (SET_SRC (body))); + + if (tem != 0 + && GET_MODE (tem) == GET_MODE (SET_DEST (body))) + { + /* DREG may have been the target of a REG_DEAD note in + the insn which makes INSN redundant. If so, reorg + would still think it is dead. So search for such a + note and delete it if we find it. */ + if (! find_regno_note (insn, REG_UNUSED, dreg)) + for (trial = prev_nonnote_insn (insn); + trial && GET_CODE (trial) != CODE_LABEL; + trial = prev_nonnote_insn (trial)) + if (find_regno_note (trial, REG_DEAD, dreg)) + { + remove_death (dreg, trial); + break; + } + + /* Deleting insn could lose a death-note for SREG. */ + if ((trial = find_regno_note (insn, REG_DEAD, sreg))) + { + /* Change this into a USE so that we won't emit + code for it, but still can keep the note. */ + PATTERN (insn) + = gen_rtx_USE (VOIDmode, XEXP (trial, 0)); + INSN_CODE (insn) = -1; + /* Remove all reg notes but the REG_DEAD one. */ + REG_NOTES (insn) = trial; + XEXP (trial, 1) = NULL_RTX; + } + else + delete_insn (insn); + } + } + else if (dreg >= 0 && CONSTANT_P (SET_SRC (body)) + && find_equiv_reg (SET_SRC (body), insn, 0, dreg, + NULL_PTR, 0, + GET_MODE (SET_DEST (body)))) + { + /* This handles the case where we have two consecutive + assignments of the same constant to pseudos that didn't + get a hard reg. Each SET from the constant will be + converted into a SET of the spill register and an + output reload will be made following it. This produces + two loads of the same constant into the same spill + register. */ + + rtx in_insn = insn; + + /* Look back for a death note for the first reg. + If there is one, it is no longer accurate. */ + while (in_insn && GET_CODE (in_insn) != CODE_LABEL) + { + if ((GET_CODE (in_insn) == INSN + || GET_CODE (in_insn) == JUMP_INSN) + && find_regno_note (in_insn, REG_DEAD, dreg)) + { + remove_death (dreg, in_insn); + break; + } + in_insn = PREV_INSN (in_insn); + } + + /* Delete the second load of the value. */ + delete_insn (insn); + } + } + else if (GET_CODE (body) == PARALLEL) + { + /* If each part is a set between two identical registers or + a USE or CLOBBER, delete the insn. */ + int i, sreg, dreg; + rtx tem; + + for (i = XVECLEN (body, 0) - 1; i >= 0; i--) + { + tem = XVECEXP (body, 0, i); + if (GET_CODE (tem) == USE || GET_CODE (tem) == CLOBBER) + continue; + + if (GET_CODE (tem) != SET + || (sreg = true_regnum (SET_SRC (tem))) < 0 + || (dreg = true_regnum (SET_DEST (tem))) < 0 + || dreg != sreg) + break; + } + + if (i < 0) + delete_insn (insn); + } + /* Also delete insns to store bit fields if they are no-ops. */ + /* Not worth the hair to detect this in the big-endian case. */ + else if (! BYTES_BIG_ENDIAN + && GET_CODE (body) == SET + && GET_CODE (SET_DEST (body)) == ZERO_EXTRACT + && XEXP (SET_DEST (body), 2) == const0_rtx + && XEXP (SET_DEST (body), 0) == SET_SRC (body) + && ! (GET_CODE (SET_SRC (body)) == MEM + && MEM_VOLATILE_P (SET_SRC (body)))) + delete_insn (insn); + } + insn = next; + } +} + +/* See if there is still a NOTE_INSN_FUNCTION_END in this function. + If so indicate that this function can drop off the end by returning + 1, else return 0. + + CHECK_DELETED indicates whether we must check if the note being + searched for has the deleted flag set. + + DELETE_FINAL_NOTE indicates whether we should delete the note + if we find it. */ + +static int +calculate_can_reach_end (last, check_deleted, delete_final_note) + rtx last; + int check_deleted; + int delete_final_note; +{ + rtx insn = last; + int n_labels = 1; + + while (insn != NULL_RTX) + { + int ok = 0; + + /* One label can follow the end-note: the return label. */ + if (GET_CODE (insn) == CODE_LABEL && n_labels-- > 0) + ok = 1; + /* Ordinary insns can follow it if returning a structure. */ + else if (GET_CODE (insn) == INSN) + ok = 1; + /* If machine uses explicit RETURN insns, no epilogue, + then one of them follows the note. */ + else if (GET_CODE (insn) == JUMP_INSN + && GET_CODE (PATTERN (insn)) == RETURN) + ok = 1; + /* A barrier can follow the return insn. */ + else if (GET_CODE (insn) == BARRIER) + ok = 1; + /* Other kinds of notes can follow also. */ + else if (GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END) + ok = 1; + + if (ok != 1) + break; - insn = last_insn; - { - int n_labels = 1; - while (insn - /* One label can follow the end-note: the return label. */ - && ((GET_CODE (insn) == CODE_LABEL && n_labels-- > 0) - /* Ordinary insns can follow it if returning a structure. */ - || GET_CODE (insn) == INSN - /* If machine uses explicit RETURN insns, no epilogue, - then one of them follows the note. */ - || (GET_CODE (insn) == JUMP_INSN - && GET_CODE (PATTERN (insn)) == RETURN) - /* A barrier can follow the return insn. */ - || GET_CODE (insn) == BARRIER - /* Other kinds of notes can follow also. */ - || (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END))) insn = PREV_INSN (insn); - } + } - /* Report if control can fall through at the end of the function. */ - if (insn && GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END) + /* See if we backed up to the appropriate type of note. */ + if (insn != NULL_RTX + && GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END + && (check_deleted != 0 + && ! INSN_DELETED_P (insn))) { - can_reach_end = 1; - delete_insn (insn); + if (delete_final_note) + delete_insn (insn); + return 1; } - /* Show JUMP_CHAIN no longer valid. */ - jump_chain = 0; + return 0; } - + /* 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, |