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
This commit is contained in:
Bob Manson 1999-08-24 22:35:55 +00:00 committed by Richard Henderson
parent 952d33b8db
commit f2a1bc0267
7 changed files with 1128 additions and 689 deletions

View File

@ -1,3 +1,31 @@
Tue Aug 24 11:46:10 1999 Bob Manson <manson@cygnus.com>
Richard Henderson <rth@cygnus.com>
* 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.
Tue Aug 24 13:48:39 1999 Nathan Sidwell <nathan@acm.org>
* expr.c (expand_expr): Cope with COND_EXPRs with one

1049
gcc/flow.c

File diff suppressed because it is too large Load Diff

View File

@ -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. */

View File

@ -132,6 +132,7 @@ extern void find_basic_blocks PROTO((rtx, int, FILE *, int));
extern void free_basic_block_vars PROTO((int));
extern void set_block_num PROTO((rtx, int));
extern void life_analysis PROTO((rtx, int, FILE *, int));
extern void update_life_info PROTO((rtx, rtx, rtx, rtx, rtx));
#endif
/* Functions in varasm.c. */

View File

@ -2669,7 +2669,7 @@ split_block_insns (b, do_split)
/* try_split returns the NOTE that INSN became. */
first = NEXT_INSN (first);
#ifdef INSN_SCHEDULING
update_flow_info (notes, first, last, insn);
update_life_info (notes, first, last, insn, insn);
#endif
PUT_CODE (insn, NOTE);
NOTE_SOURCE_FILE (insn) = 0;

View File

@ -1264,14 +1264,33 @@ find_free_register (current_insn, class_str, mode, reg_set)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
int success = 1;
int regno;
int success;
if (! TEST_HARD_REG_BIT (reg_class_contents[class], i))
#ifdef REG_ALLOC_ORDER
regno = reg_alloc_order [i];
#else
regno = i;
#endif
/* Don't allocate fixed registers. */
if (fixed_regs[regno])
continue;
for (j = HARD_REGNO_NREGS (i, mode) - 1; j >= 0; j--)
/* Make sure the register is of the right class. */
if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno))
continue;
/* And can support the mode we need. */
if (! HARD_REGNO_MODE_OK (regno, mode))
continue;
/* And that we don't create an extra save/restore. */
if (! call_used_regs[regno] && ! regs_ever_live[regno])
continue;
success = 1;
for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
{
if (TEST_HARD_REG_BIT (*reg_set, i + j)
|| TEST_HARD_REG_BIT (used.regs, i + j))
if (TEST_HARD_REG_BIT (*reg_set, regno + j)
|| TEST_HARD_REG_BIT (used.regs, regno + j))
{
success = 0;
break;
@ -1279,12 +1298,33 @@ find_free_register (current_insn, class_str, mode, reg_set)
}
if (success)
{
for (j = HARD_REGNO_NREGS (i, mode) - 1; j >= 0; j--)
for (j = HARD_REGNO_NREGS (regno, mode) - 1; j >= 0; j--)
{
SET_HARD_REG_BIT (*reg_set, i + j);
SET_HARD_REG_BIT (*reg_set, regno + j);
}
return gen_rtx_REG (mode, i);
return gen_rtx_REG (mode, regno);
}
}
return NULL_RTX;
}
/* Return true if REG is dead at CURRENT_INSN. */
int
reg_dead_p (current_insn, reg)
rtx current_insn, reg;
{
struct resources used;
int regno, j;
mark_target_live_regs (get_insns (), current_insn, &used);
regno = REGNO (reg);
for (j = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1; j >= 0; j--)
{
if (TEST_HARD_REG_BIT (used.regs, regno + j))
return 0;
}
return 1;
}

View File

@ -1412,6 +1412,7 @@ extern void recompute_reg_usage PROTO ((rtx, int));
extern void dump_flow_info PROTO ((FILE *));
#endif
extern void free_bb_mem PROTO ((void));
extern void replace_insns PROTO ((rtx, rtx, rtx, rtx));
/* In expmed.c */
extern void init_expmed PROTO ((void));