diff options
author | Bob Manson <manson@cygnus.com> | 1999-08-24 22:35:55 +0000 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 1999-08-24 15:35:55 -0700 |
commit | f2a1bc02679df06d8461df03f48ebaafe5e4307e (patch) | |
tree | e86a9635ca292ea67589cef742a73eea422d2d19 /gcc/haifa-sched.c | |
parent | 952d33b8db3341dd48dc4e73186720f33a8525db (diff) | |
download | gcc-f2a1bc02679df06d8461df03f48ebaafe5e4307e.zip gcc-f2a1bc02679df06d8461df03f48ebaafe5e4307e.tar.gz gcc-f2a1bc02679df06d8461df03f48ebaafe5e4307e.tar.bz2 |
haifa-sched.c (split_hard_reg_notes): Move to flow.c
* haifa-sched.c (split_hard_reg_notes): Move to flow.c
(new_insn_dead_notes): Likewise.
(update_n_sets): Likewise.
(update_flow_info): Move to flow.c, renamed to update_life_info;
extend to handle multiple source insns.
* flow.c: Include resource.h
(unlink_insn_chain): New.
(split_hard_reg_notes): New.
(maybe_add_dead_note): New.
(maybe_add_dead_note_use): New.
(find_insn_with_note): New.
(new_insn_dead_notes): New.
(update_n_sets): New.
(sets_reg_or_subreg_1, sets_reg_or_subreg): New.
(maybe_remove_dead_notes): New.
(update_life_info): New.
(prepend_reg_notes): New.
(replace_insns): New.
* output.h (update_life_info): Declare.
* recog.c (split_block_insns): Use update_life_info.
* resource.c (find_free_register): Use reg_alloc_order, don't use
fixed regs, make sure the mode is supported, don't use new regs.
(reg_dead_p): New.
* rtl.h (replace_insns): Declare.
Co-Authored-By: Richard Henderson <rth@cygnus.com>
From-SVN: r28828
Diffstat (limited to 'gcc/haifa-sched.c')
-rw-r--r-- | gcc/haifa-sched.c | 680 |
1 files changed, 0 insertions, 680 deletions
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index 3a5a64a..d63e04c 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -452,9 +452,6 @@ static void attach_deaths_insn PROTO ((rtx)); static int new_sometimes_live PROTO ((struct sometimes *, int, int)); static void finish_sometimes_live PROTO ((struct sometimes *, int)); static int schedule_block PROTO ((int, int)); -static void split_hard_reg_notes PROTO ((rtx, rtx, rtx)); -static void new_insn_dead_notes PROTO ((rtx, rtx, rtx, rtx)); -static void update_n_sets PROTO ((rtx, int)); static char *safe_concat PROTO ((char *, char *, const char *)); static int insn_issue_delay PROTO ((rtx)); static int birthing_insn_p PROTO ((rtx)); @@ -7775,683 +7772,6 @@ schedule_region (rgn) FREE_REG_SET (reg_pending_clobbers); } -/* Subroutine of update_flow_info. Determines whether any new REG_NOTEs are - needed for the hard register mentioned in the note. This can happen - if the reference to the hard register in the original insn was split into - several smaller hard register references in the split insns. */ - -static void -split_hard_reg_notes (note, first, last) - rtx note, first, last; -{ - rtx reg, temp, link; - int n_regs, i, new_reg; - rtx insn; - - /* Assume that this is a REG_DEAD note. */ - if (REG_NOTE_KIND (note) != REG_DEAD) - abort (); - - reg = XEXP (note, 0); - - n_regs = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)); - - for (i = 0; i < n_regs; i++) - { - new_reg = REGNO (reg) + i; - - /* Check for references to new_reg in the split insns. */ - for (insn = last;; insn = PREV_INSN (insn)) - { - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' - && (temp = regno_use_in (new_reg, PATTERN (insn)))) - { - /* Create a new reg dead note ere. */ - link = alloc_EXPR_LIST (REG_DEAD, temp, REG_NOTES (insn)); - REG_NOTES (insn) = link; - - /* If killed multiple registers here, then add in the excess. */ - i += HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) - 1; - - break; - } - /* It isn't mentioned anywhere, so no new reg note is needed for - this register. */ - if (insn == first) - break; - } - } -} - -/* Subroutine of update_flow_info. Determines whether a SET or CLOBBER in an - insn created by splitting needs a REG_DEAD or REG_UNUSED note added. */ - -static void -new_insn_dead_notes (pat, insn, last, orig_insn) - rtx pat, insn, last, orig_insn; -{ - rtx dest, tem, set; - - /* PAT is either a CLOBBER or a SET here. */ - dest = XEXP (pat, 0); - - while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG - || GET_CODE (dest) == STRICT_LOW_PART - || GET_CODE (dest) == SIGN_EXTRACT) - dest = XEXP (dest, 0); - - if (GET_CODE (dest) == REG) - { - /* If the original insn already used this register, we may not add new - notes for it. One example for a split that needs this test is - when a multi-word memory access with register-indirect addressing - is split into multiple memory accesses with auto-increment and - one adjusting add instruction for the address register. */ - if (reg_referenced_p (dest, PATTERN (orig_insn))) - return; - for (tem = last; tem != insn; tem = PREV_INSN (tem)) - { - if (GET_RTX_CLASS (GET_CODE (tem)) == 'i' - && reg_overlap_mentioned_p (dest, PATTERN (tem)) - && (set = single_set (tem))) - { - rtx tem_dest = SET_DEST (set); - - while (GET_CODE (tem_dest) == ZERO_EXTRACT - || GET_CODE (tem_dest) == SUBREG - || GET_CODE (tem_dest) == STRICT_LOW_PART - || GET_CODE (tem_dest) == SIGN_EXTRACT) - tem_dest = XEXP (tem_dest, 0); - - if (!rtx_equal_p (tem_dest, dest)) - { - /* Use the same scheme as combine.c, don't put both REG_DEAD - and REG_UNUSED notes on the same insn. */ - if (!find_regno_note (tem, REG_UNUSED, REGNO (dest)) - && !find_regno_note (tem, REG_DEAD, REGNO (dest))) - { - rtx note = alloc_EXPR_LIST (REG_DEAD, dest, - REG_NOTES (tem)); - REG_NOTES (tem) = note; - } - /* The reg only dies in one insn, the last one that uses - it. */ - break; - } - else if (reg_overlap_mentioned_p (dest, SET_SRC (set))) - /* We found an instruction that both uses the register, - and sets it, so no new REG_NOTE is needed for this set. */ - break; - } - } - /* If this is a set, it must die somewhere, unless it is the dest of - the original insn, and hence is live after the original insn. Abort - if it isn't supposed to be live after the original insn. - - If this is a clobber, then just add a REG_UNUSED note. */ - if (tem == insn) - { - int live_after_orig_insn = 0; - rtx pattern = PATTERN (orig_insn); - int i; - - if (GET_CODE (pat) == CLOBBER) - { - rtx note = alloc_EXPR_LIST (REG_UNUSED, dest, REG_NOTES (insn)); - REG_NOTES (insn) = note; - return; - } - - /* The original insn could have multiple sets, so search the - insn for all sets. */ - if (GET_CODE (pattern) == SET) - { - if (reg_overlap_mentioned_p (dest, SET_DEST (pattern))) - live_after_orig_insn = 1; - } - else if (GET_CODE (pattern) == PARALLEL) - { - for (i = 0; i < XVECLEN (pattern, 0); i++) - if (GET_CODE (XVECEXP (pattern, 0, i)) == SET - && reg_overlap_mentioned_p (dest, - SET_DEST (XVECEXP (pattern, - 0, i)))) - live_after_orig_insn = 1; - } - - if (!live_after_orig_insn) - abort (); - } - } -} - -/* Subroutine of update_flow_info. Update the value of reg_n_sets for all - registers modified by X. INC is -1 if the containing insn is being deleted, - and is 1 if the containing insn is a newly generated insn. */ - -static void -update_n_sets (x, inc) - rtx x; - int inc; -{ - rtx dest = SET_DEST (x); - - while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG - || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT) - dest = SUBREG_REG (dest); - - if (GET_CODE (dest) == REG) - { - int regno = REGNO (dest); - - if (regno < FIRST_PSEUDO_REGISTER) - { - register int i; - int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (dest)); - - for (i = regno; i < endregno; i++) - REG_N_SETS (i) += inc; - } - else - REG_N_SETS (regno) += inc; - } -} - -/* Updates all flow-analysis related quantities (including REG_NOTES) for - the insns from FIRST to LAST inclusive that were created by splitting - ORIG_INSN. NOTES are the original REG_NOTES. */ - -void -update_flow_info (notes, first, last, orig_insn) - rtx notes; - rtx first, last; - rtx orig_insn; -{ - rtx insn, note; - rtx next; - rtx orig_dest, temp; - rtx set; - - /* Get and save the destination set by the original insn. */ - - orig_dest = single_set (orig_insn); - if (orig_dest) - orig_dest = SET_DEST (orig_dest); - - /* Move REG_NOTES from the original insn to where they now belong. */ - - for (note = notes; note; note = next) - { - next = XEXP (note, 1); - switch (REG_NOTE_KIND (note)) - { - case REG_DEAD: - case REG_UNUSED: - /* Move these notes from the original insn to the last new insn where - the register is now set. */ - - for (insn = last;; insn = PREV_INSN (insn)) - { - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' - && reg_mentioned_p (XEXP (note, 0), PATTERN (insn))) - { - /* If this note refers to a multiple word hard register, it - may have been split into several smaller hard register - references, so handle it specially. */ - temp = XEXP (note, 0); - if (REG_NOTE_KIND (note) == REG_DEAD - && GET_CODE (temp) == REG - && REGNO (temp) < FIRST_PSEUDO_REGISTER - && HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) > 1) - split_hard_reg_notes (note, first, last); - else - { - XEXP (note, 1) = REG_NOTES (insn); - REG_NOTES (insn) = note; - } - - /* Sometimes need to convert REG_UNUSED notes to REG_DEAD - notes. */ - /* ??? This won't handle multiple word registers correctly, - but should be good enough for now. */ - if (REG_NOTE_KIND (note) == REG_UNUSED - && GET_CODE (XEXP (note, 0)) != SCRATCH - && !dead_or_set_p (insn, XEXP (note, 0))) - PUT_REG_NOTE_KIND (note, REG_DEAD); - - /* The reg only dies in one insn, the last one that uses - it. */ - break; - } - /* It must die somewhere, fail it we couldn't find where it died. - - If this is a REG_UNUSED note, then it must be a temporary - register that was not needed by this instantiation of the - pattern, so we can safely ignore it. */ - if (insn == first) - { - if (REG_NOTE_KIND (note) != REG_UNUSED) - abort (); - - break; - } - } - break; - - case REG_WAS_0: - /* If the insn that set the register to 0 was deleted, this - note cannot be relied on any longer. The destination might - even have been moved to memory. - This was observed for SH4 with execute/920501-6.c compilation, - -O2 -fomit-frame-pointer -finline-functions . */ - if (GET_CODE (XEXP (note, 0)) == NOTE - || INSN_DELETED_P (XEXP (note, 0))) - break; - /* This note applies to the dest of the original insn. Find the - first new insn that now has the same dest, and move the note - there. */ - - if (!orig_dest) - abort (); - - for (insn = first;; insn = NEXT_INSN (insn)) - { - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' - && (temp = single_set (insn)) - && rtx_equal_p (SET_DEST (temp), orig_dest)) - { - XEXP (note, 1) = REG_NOTES (insn); - REG_NOTES (insn) = note; - /* The reg is only zero before one insn, the first that - uses it. */ - break; - } - /* If this note refers to a multiple word hard - register, it may have been split into several smaller - hard register references. We could split the notes, - but simply dropping them is good enough. */ - if (GET_CODE (orig_dest) == REG - && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER - && HARD_REGNO_NREGS (REGNO (orig_dest), - GET_MODE (orig_dest)) > 1) - break; - /* It must be set somewhere, fail if we couldn't find where it - was set. */ - if (insn == last) - abort (); - } - break; - - case REG_EQUAL: - case REG_EQUIV: - /* A REG_EQUIV or REG_EQUAL note on an insn with more than one - set is meaningless. Just drop the note. */ - if (!orig_dest) - break; - - case REG_NO_CONFLICT: - /* These notes apply to the dest of the original insn. Find the last - new insn that now has the same dest, and move the note there. */ - - if (!orig_dest) - abort (); - - for (insn = last;; insn = PREV_INSN (insn)) - { - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' - && (temp = single_set (insn)) - && rtx_equal_p (SET_DEST (temp), orig_dest)) - { - XEXP (note, 1) = REG_NOTES (insn); - REG_NOTES (insn) = note; - /* Only put this note on one of the new insns. */ - break; - } - - /* The original dest must still be set someplace. Abort if we - couldn't find it. */ - if (insn == first) - { - /* However, if this note refers to a multiple word hard - register, it may have been split into several smaller - hard register references. We could split the notes, - but simply dropping them is good enough. */ - if (GET_CODE (orig_dest) == REG - && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER - && HARD_REGNO_NREGS (REGNO (orig_dest), - GET_MODE (orig_dest)) > 1) - break; - /* Likewise for multi-word memory references. */ - if (GET_CODE (orig_dest) == MEM - && SIZE_FOR_MODE (orig_dest) > UNITS_PER_WORD) - break; - abort (); - } - } - break; - - case REG_LIBCALL: - /* Move a REG_LIBCALL note to the first insn created, and update - the corresponding REG_RETVAL note. */ - XEXP (note, 1) = REG_NOTES (first); - REG_NOTES (first) = note; - - insn = XEXP (note, 0); - note = find_reg_note (insn, REG_RETVAL, NULL_RTX); - if (note) - XEXP (note, 0) = first; - break; - - case REG_EXEC_COUNT: - /* Move a REG_EXEC_COUNT note to the first insn created. */ - XEXP (note, 1) = REG_NOTES (first); - REG_NOTES (first) = note; - break; - - case REG_RETVAL: - /* Move a REG_RETVAL note to the last insn created, and update - the corresponding REG_LIBCALL note. */ - XEXP (note, 1) = REG_NOTES (last); - REG_NOTES (last) = note; - - insn = XEXP (note, 0); - note = find_reg_note (insn, REG_LIBCALL, NULL_RTX); - if (note) - XEXP (note, 0) = last; - break; - - case REG_NONNEG: - case REG_BR_PROB: - /* This should be moved to whichever instruction is a JUMP_INSN. */ - - for (insn = last;; insn = PREV_INSN (insn)) - { - if (GET_CODE (insn) == JUMP_INSN) - { - XEXP (note, 1) = REG_NOTES (insn); - REG_NOTES (insn) = note; - /* Only put this note on one of the new insns. */ - break; - } - /* Fail if we couldn't find a JUMP_INSN. */ - if (insn == first) - abort (); - } - break; - - case REG_INC: - /* reload sometimes leaves obsolete REG_INC notes around. */ - if (reload_completed) - break; - /* This should be moved to whichever instruction now has the - increment operation. */ - abort (); - - case REG_LABEL: - /* Should be moved to the new insn(s) which use the label. */ - for (insn = first; insn != NEXT_INSN (last); insn = NEXT_INSN (insn)) - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' - && reg_mentioned_p (XEXP (note, 0), PATTERN (insn))) - { - REG_NOTES (insn) = alloc_EXPR_LIST (REG_LABEL, - XEXP (note, 0), - REG_NOTES (insn)); - } - break; - - case REG_CC_SETTER: - case REG_CC_USER: - /* These two notes will never appear until after reorg, so we don't - have to handle them here. */ - default: - abort (); - } - } - - /* Each new insn created, except the last, has a new set. If the destination - is a register, then this reg is now live across several insns, whereas - previously the dest reg was born and died within the same insn. To - reflect this, we now need a REG_DEAD note on the insn where this - dest reg dies. - - Similarly, the new insns may have clobbers that need REG_UNUSED notes. */ - - for (insn = first; insn != last; insn = NEXT_INSN (insn)) - { - rtx pat; - int i; - - pat = PATTERN (insn); - if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER) - new_insn_dead_notes (pat, insn, last, orig_insn); - else if (GET_CODE (pat) == PARALLEL) - { - for (i = 0; i < XVECLEN (pat, 0); i++) - if (GET_CODE (XVECEXP (pat, 0, i)) == SET - || GET_CODE (XVECEXP (pat, 0, i)) == CLOBBER) - new_insn_dead_notes (XVECEXP (pat, 0, i), insn, last, orig_insn); - } - } - - /* If any insn, except the last, uses the register set by the last insn, - then we need a new REG_DEAD note on that insn. In this case, there - would not have been a REG_DEAD note for this register in the original - insn because it was used and set within one insn. */ - - set = single_set (last); - if (set) - { - rtx dest = SET_DEST (set); - - while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG - || GET_CODE (dest) == STRICT_LOW_PART - || GET_CODE (dest) == SIGN_EXTRACT) - dest = XEXP (dest, 0); - - if (GET_CODE (dest) == REG - /* Global registers are always live, so the code below does not - apply to them. */ - && (REGNO (dest) >= FIRST_PSEUDO_REGISTER - || ! global_regs[REGNO (dest)])) - { - rtx stop_insn = PREV_INSN (first); - - /* If the last insn uses the register that it is setting, then - we don't want to put a REG_DEAD note there. Search backwards - to find the first insn that sets but does not use DEST. */ - - insn = last; - if (reg_overlap_mentioned_p (dest, SET_SRC (set))) - { - for (insn = PREV_INSN (insn); insn != first; - insn = PREV_INSN (insn)) - { - if ((set = single_set (insn)) - && reg_mentioned_p (dest, SET_DEST (set)) - && ! reg_overlap_mentioned_p (dest, SET_SRC (set))) - break; - } - } - - /* Now find the first insn that uses but does not set DEST. */ - - for (insn = PREV_INSN (insn); insn != stop_insn; - insn = PREV_INSN (insn)) - { - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' - && reg_mentioned_p (dest, PATTERN (insn)) - && (set = single_set (insn))) - { - rtx insn_dest = SET_DEST (set); - - while (GET_CODE (insn_dest) == ZERO_EXTRACT - || GET_CODE (insn_dest) == SUBREG - || GET_CODE (insn_dest) == STRICT_LOW_PART - || GET_CODE (insn_dest) == SIGN_EXTRACT) - insn_dest = XEXP (insn_dest, 0); - - if (insn_dest != dest) - { - note = alloc_EXPR_LIST (REG_DEAD, dest, REG_NOTES (insn)); - REG_NOTES (insn) = note; - /* The reg only dies in one insn, the last one - that uses it. */ - break; - } - } - } - } - } - - /* If the original dest is modifying a multiple register target, and the - original instruction was split such that the original dest is now set - by two or more SUBREG sets, then the split insns no longer kill the - destination of the original insn. - - In this case, if there exists an instruction in the same basic block, - before the split insn, which uses the original dest, and this use is - killed by the original insn, then we must remove the REG_DEAD note on - this insn, because it is now superfluous. - - This does not apply when a hard register gets split, because the code - knows how to handle overlapping hard registers properly. */ - if (orig_dest && GET_CODE (orig_dest) == REG) - { - int found_orig_dest = 0; - int found_split_dest = 0; - - for (insn = first;; insn = NEXT_INSN (insn)) - { - rtx pat; - int i; - - /* I'm not sure if this can happen, but let's be safe. */ - if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') - continue; - - pat = PATTERN (insn); - i = GET_CODE (pat) == PARALLEL ? XVECLEN (pat, 0) : 0; - set = pat; - - for (;;) - { - if (GET_CODE (set) == SET) - { - if (GET_CODE (SET_DEST (set)) == REG - && REGNO (SET_DEST (set)) == REGNO (orig_dest)) - { - found_orig_dest = 1; - break; - } - else if (GET_CODE (SET_DEST (set)) == SUBREG - && SUBREG_REG (SET_DEST (set)) == orig_dest) - { - found_split_dest = 1; - break; - } - } - if (--i < 0) - break; - set = XVECEXP (pat, 0, i); - } - - if (insn == last) - break; - } - - if (found_split_dest) - { - /* Search backwards from FIRST, looking for the first insn that uses - the original dest. Stop if we pass a CODE_LABEL or a JUMP_INSN. - If we find an insn, and it has a REG_DEAD note, then delete the - note. */ - - for (insn = first; insn; insn = PREV_INSN (insn)) - { - if (GET_CODE (insn) == CODE_LABEL - || GET_CODE (insn) == JUMP_INSN) - break; - else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' - && reg_mentioned_p (orig_dest, insn)) - { - note = find_regno_note (insn, REG_DEAD, REGNO (orig_dest)); - if (note) - remove_note (insn, note); - } - } - } - else if (!found_orig_dest) - { - int i, regno; - - /* Should never reach here for a pseudo reg. */ - if (REGNO (orig_dest) >= FIRST_PSEUDO_REGISTER) - abort (); - - /* This can happen for a hard register, if the splitter - does not bother to emit instructions which would be no-ops. - We try to verify that this is the case by checking to see if - the original instruction uses all of the registers that it - set. This case is OK, because deleting a no-op can not affect - REG_DEAD notes on other insns. If this is not the case, then - abort. */ - - regno = REGNO (orig_dest); - for (i = HARD_REGNO_NREGS (regno, GET_MODE (orig_dest)) - 1; - i >= 0; i--) - if (! refers_to_regno_p (regno + i, regno + i + 1, orig_insn, - NULL_PTR)) - break; - if (i >= 0) - abort (); - } - } - - /* Update reg_n_sets. This is necessary to prevent local alloc from - converting REG_EQUAL notes to REG_EQUIV when splitting has modified - a reg from set once to set multiple times. */ - - { - rtx x = PATTERN (orig_insn); - RTX_CODE code = GET_CODE (x); - - if (code == SET || code == CLOBBER) - update_n_sets (x, -1); - else if (code == PARALLEL) - { - int i; - for (i = XVECLEN (x, 0) - 1; i >= 0; i--) - { - code = GET_CODE (XVECEXP (x, 0, i)); - if (code == SET || code == CLOBBER) - update_n_sets (XVECEXP (x, 0, i), -1); - } - } - - for (insn = first;; insn = NEXT_INSN (insn)) - { - x = PATTERN (insn); - code = GET_CODE (x); - - if (code == SET || code == CLOBBER) - update_n_sets (x, 1); - else if (code == PARALLEL) - { - int i; - for (i = XVECLEN (x, 0) - 1; i >= 0; i--) - { - code = GET_CODE (XVECEXP (x, 0, i)); - if (code == SET || code == CLOBBER) - update_n_sets (XVECEXP (x, 0, i), 1); - } - } - - if (insn == last) - break; - } - } -} - /* The one entry point in this file. DUMP_FILE is the dump file for this pass. */ |