/* Instruction scheduling pass.
- Copyright (C) 1992, 93-95, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93-96, 1997 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
Enhanced by, and currently maintained by, Jim Wilson (wilson@cygnus.com)
reg_n_calls_crossed, and reg_live_length. Also, basic_block_head,
basic_block_end.
- The information in the line number notes is carefully retained by this
- pass. All other NOTE insns are grouped in their same relative order at
- the beginning of basic blocks that have been scheduled. */
+ The information in the line number notes is carefully retained by
+ this pass. Notes that refer to the starting and ending of
+ exception regions are also carefully retained by this pass. All
+ other NOTE insns are grouped in their same relative order at the
+ beginning of basic blocks that have been scheduled. */
\f
#include <stdio.h>
#include "config.h"
Values of these arrays are copied at the end of this pass into the
arrays set up by flow analysis. */
-static short *sched_reg_n_deaths;
static int *sched_reg_n_calls_crossed;
static int *sched_reg_live_length;
struct sometimes
{
- short offset; short bit;
- short live_length; short calls_crossed;
+ int regno;
+ int live_length;
+ int calls_crossed;
};
/* Forward declarations. */
static void attach_deaths PROTO((rtx, rtx, int));
static void attach_deaths_insn PROTO((rtx));
static rtx unlink_notes PROTO((rtx, rtx));
-static int new_sometimes_live PROTO((struct sometimes *, int, int,
- int));
+static int new_sometimes_live PROTO((struct sometimes *, int, int));
static void finish_sometimes_live PROTO((struct sometimes *, int));
static rtx reemit_notes PROTO((rtx, rtx));
static void schedule_block PROTO((int, FILE *));
&& GET_CODE (SET_DEST (set)) == REG
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
&& (((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
- && reg_n_sets[REGNO (SET_DEST (set))] == 1)
+ && REG_N_SETS (REGNO (SET_DEST (set))) == 1)
|| (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
&& GET_CODE (XEXP (note, 0)) != EXPR_LIST)
{
y = canon_rtx (y);
if (rtx_equal_for_memref_p (x, y))
- return (xsize == 0 || ysize == 0 ||
- (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
+ return (xsize == 0 || ysize == 0
+ || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
if (y == frame_pointer_rtx || y == hard_frame_pointer_rtx
|| y == stack_pointer_rtx)
changed. A volatile and non-volatile reference can be interchanged
though.
- A MEM_IN_STRUCT reference at a non-QImode varying address can never
+ A MEM_IN_STRUCT reference at a non-QImode non-AND varying address can never
conflict with a non-MEM_IN_STRUCT reference at a fixed address. We must
allow QImode aliasing because the ANSI C standard allows character
pointers to alias anything. We are assuming that characters are
- always QImode here. */
+ always QImode here. We also must allow AND addresses, because they may
+ generate accesses outside the object being referenced. This is used to
+ generate aligned addresses from unaligned addresses, for instance, the
+ alpha storeqi_unaligned pattern. */
/* Read dependence: X is read after read in MEM takes place. There can
only be a dependence here if both reads are volatile. */
SIZE_FOR_MODE (x), XEXP (x, 0), 0)
&& ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
&& GET_MODE (mem) != QImode
+ && GET_CODE (XEXP (mem, 0)) != AND
&& ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
&& ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
&& GET_MODE (x) != QImode
+ && GET_CODE (XEXP (x, 0)) != AND
&& ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem))));
}
SIZE_FOR_MODE (x), XEXP (x, 0), 0)
&& ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
&& GET_MODE (mem) != QImode
+ && GET_CODE (XEXP (mem, 0)) != AND
&& ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
&& ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
&& GET_MODE (x) != QImode
+ && GET_CODE (XEXP (x, 0)) != AND
&& ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem))));
}
SIZE_FOR_MODE (x), XEXP (x, 0), 0)
&& ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
&& GET_MODE (mem) != QImode
+ && GET_CODE (XEXP (mem, 0)) != AND
&& ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
&& ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
&& GET_MODE (x) != QImode
+ && GET_CODE (XEXP (x, 0)) != AND
&& ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem))));
}
\f
if (reg_last_sets[regno + i])
add_dependence (insn, reg_last_sets[regno + i],
REG_DEP_OUTPUT);
- reg_pending_sets[(regno + i) / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << ((regno + i) % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (reg_pending_sets, regno + i);
if ((call_used_regs[i] || global_regs[i])
&& last_function_call)
/* Function calls clobber all call_used regs. */
reg_last_uses[regno] = 0;
if (reg_last_sets[regno])
add_dependence (insn, reg_last_sets[regno], REG_DEP_OUTPUT);
- reg_pending_sets[regno / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (reg_pending_sets, regno);
/* Pseudos that are REG_EQUIV to something may be replaced
by that during reloading. We need only add dependencies for
/* Don't let it cross a call after scheduling if it doesn't
already cross one. */
- if (reg_n_calls_crossed[regno] == 0 && last_function_call)
+ if (REG_N_CALLS_CROSSED (regno) == 0 && last_function_call)
add_dependence (insn, last_function_call, REG_DEP_ANTI);
}
}
/* If the register does not already cross any calls, then add this
insn to the sched_before_next_call list so that it will still
not cross calls after scheduling. */
- if (reg_n_calls_crossed[regno] == 0)
+ if (REG_N_CALLS_CROSSED (regno) == 0)
add_dependence (sched_before_next_call, insn, REG_DEP_ANTI);
}
return;
sched_analyze_2 (XEXP (link, 0), insn);
}
- /* If there is a LOOP_{BEG,END} note in the middle of a basic block, then
+ /* If there is a {LOOP,EHREGION}_{BEG,END} note in the middle of a basic block, then
we must be sure that no instructions are scheduled across it.
Otherwise, the reg_n_refs info (which depends on loop_depth) would
become incorrect. */
sched_analyze_2 (XEXP (note, 0), insn);
}
- for (i = 0; i < regset_size; i++)
- {
- REGSET_ELT_TYPE sets = reg_pending_sets[i];
- if (sets)
- {
- register int bit;
- for (bit = 0; bit < REGSET_ELT_BITS; bit++)
- if (sets & ((REGSET_ELT_TYPE) 1 << bit))
- reg_last_sets[i * REGSET_ELT_BITS + bit] = insn;
- reg_pending_sets[i] = 0;
- }
- }
+ EXECUTE_IF_SET_AND_RESET_IN_REG_SET (reg_pending_sets, 0, i,
+ {
+ reg_last_sets[i] = insn;
+ });
+
if (reg_pending_sets_all)
{
for (i = 0; i < maxreg; i++)
}
reg_pending_sets_all = 1;
- /* Add a fake REG_NOTE which we will later convert
- back into a NOTE_INSN_SETJMP note. */
+ /* Add a pair of fake REG_NOTEs which we will later
+ convert back into a NOTE_INSN_SETJMP note. See
+ reemit_notes for why we use a pair of of NOTEs. */
+
+ REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
+ GEN_INT (0),
+ REG_NOTES (insn));
REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
GEN_INT (NOTE_INSN_SETJMP),
REG_NOTES (insn));
reg_last_uses[i] = 0;
if (reg_last_sets[i])
add_dependence (insn, reg_last_sets[i], REG_DEP_ANTI);
- reg_pending_sets[i / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (reg_pending_sets, i);
}
}
last_function_call = insn;
n_insns += 1;
}
+
+ /* See comments on reemit_notes as to why we do this. */
else if (GET_CODE (insn) == NOTE
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
|| (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP
&& GET_CODE (PREV_INSN (insn)) != CALL_INSN)))
{
loop_notes = gen_rtx (EXPR_LIST, REG_DEAD,
+ GEN_INT (NOTE_BLOCK_NUMBER (insn)), loop_notes);
+ loop_notes = gen_rtx (EXPR_LIST, REG_DEAD,
GEN_INT (NOTE_LINE_NUMBER (insn)), loop_notes);
CONST_CALL_P (loop_notes) = CONST_CALL_P (insn);
}
regno = REGNO (reg);
if (regno >= FIRST_PSEUDO_REGISTER || ! global_regs[regno])
{
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
-
if (death)
{
/* If we only set part of the register, then this set does not
int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (--j >= 0)
{
- offset = (regno + j) / REGSET_ELT_BITS;
- bit = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
+ SET_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+ SET_REGNO_REG_SET (bb_dead_regs, regno);
}
}
else
int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (--j >= 0)
{
- offset = (regno + j) / REGSET_ELT_BITS;
- bit = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-
- bb_live_regs[offset] |= bit;
- bb_dead_regs[offset] &= ~bit;
+ SET_REGNO_REG_SET (bb_live_regs, regno + j);
+ CLEAR_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
- bb_live_regs[offset] |= bit;
- bb_dead_regs[offset] &= ~bit;
+ SET_REGNO_REG_SET (bb_live_regs, regno);
+ CLEAR_REGNO_REG_SET (bb_dead_regs, regno);
}
}
}
{
rtx dest = SET_DEST (pat);
int i = REGNO (dest);
- int offset = i / REGSET_ELT_BITS;
- REGSET_ELT_TYPE bit = (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
/* It would be more accurate to use refers_to_regno_p or
reg_mentioned_p to determine when the dest is not live before this
insn. */
- if (bb_live_regs[offset] & bit)
- return (reg_n_sets[i] == 1);
+ if (REGNO_REG_SET_P (bb_live_regs, i))
+ return (REG_N_SETS (i) == 1);
return 0;
}
/* This code is very similar to mark_used_1 (if set_p is false)
and mark_set_1 (if set_p is true) in flow.c. */
- register int regno = REGNO (x);
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
- REGSET_ELT_TYPE all_needed = (old_live_regs[offset] & bit);
- REGSET_ELT_TYPE some_needed = (old_live_regs[offset] & bit);
+ register int regno;
+ int some_needed;
+ int all_needed;
if (set_p)
return;
+ regno = REGNO (x);
+ all_needed = some_needed = REGNO_REG_SET_P (old_live_regs, regno);
if (regno < FIRST_PSEUDO_REGISTER)
{
int n;
n = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--n > 0)
{
- some_needed |= (old_live_regs[(regno + n) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno + n) % REGSET_ELT_BITS)));
- all_needed &= (old_live_regs[(regno + n) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno + n) % REGSET_ELT_BITS)));
+ int needed = (REGNO_REG_SET_P (old_live_regs, regno + n));
+ some_needed |= needed;
+ all_needed &= needed;
}
}
register that is set in the insn. */
for (i = HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1;
i >= 0; i--)
- if ((old_live_regs[(regno + i) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno +i) % REGSET_ELT_BITS))) == 0
+ if (! REGNO_REG_SET_P (old_live_regs, regno + i)
&& ! dead_or_set_regno_p (insn, regno + i))
create_reg_dead_note (gen_rtx (REG,
reg_raw_mode[regno + i],
int j = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--j >= 0)
{
- offset = (regno + j) / REGSET_ELT_BITS;
- bit
- = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-
- bb_dead_regs[offset] &= ~bit;
- bb_live_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_dead_regs, regno + j);
+ SET_REGNO_REG_SET (bb_live_regs, regno + j);
}
}
else
{
- bb_dead_regs[offset] &= ~bit;
- bb_live_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_dead_regs, regno);
+ SET_REGNO_REG_SET (bb_live_regs, regno);
}
}
return;
/* Don't save away NOTE_INSN_SETJMPs, because they must remain
immediately after the call they follow. We use a fake
(REG_DEAD (const_int -1)) note to remember them.
- Likewise with NOTE_INSN_LOOP_BEG and NOTE_INSN_LOOP_END. */
+ Likewise with NOTE_INSN_{LOOP,EHREGION}_{BEG, END}. */
else if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
- && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END)
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
{
/* Insert the note at the end of the notes list. */
PREV_INSN (insn) = note_list;
/* Constructor for `sometimes' data structure. */
static int
-new_sometimes_live (regs_sometimes_live, offset, bit, sometimes_max)
+new_sometimes_live (regs_sometimes_live, regno, sometimes_max)
struct sometimes *regs_sometimes_live;
- int offset, bit;
+ int regno;
int sometimes_max;
{
register struct sometimes *p;
- register int regno = offset * REGSET_ELT_BITS + bit;
/* There should never be a register greater than max_regno here. If there
is, it means that a define_split has created a new pseudo reg. This
abort ();
p = ®s_sometimes_live[sometimes_max];
- p->offset = offset;
- p->bit = bit;
+ p->regno = regno;
p->live_length = 0;
p->calls_crossed = 0;
sometimes_max++;
for (i = 0; i < sometimes_max; i++)
{
register struct sometimes *p = ®s_sometimes_live[i];
- int regno;
-
- regno = p->offset * REGSET_ELT_BITS + p->bit;
+ int regno = p->regno;
sched_reg_live_length[regno] += p->live_length;
sched_reg_n_calls_crossed[regno] += p->calls_crossed;
}
}
-/* Search INSN for fake REG_DEAD notes for NOTE_INSN_SETJMP,
- NOTE_INSN_LOOP_BEG, and NOTE_INSN_LOOP_END; and convert them back
- into NOTEs. LAST is the last instruction output by the instruction
- scheduler. Return the new value of LAST. */
+/* Search INSN for fake REG_DEAD note pairs for NOTE_INSN_SETJMP,
+ NOTE_INSN_{LOOP,EHREGION}_{BEG,END}; and convert them back into
+ NOTEs. The REG_DEAD note following first one is contains the saved
+ value for NOTE_BLOCK_NUMBER which is useful for
+ NOTE_INSN_EH_REGION_{BEG,END} NOTEs. LAST is the last instruction
+ output by the instruction scheduler. Return the new value of LAST. */
static rtx
reemit_notes (insn, last)
&& GET_CODE (XEXP (note, 0)) == CONST_INT)
{
if (INTVAL (XEXP (note, 0)) == NOTE_INSN_SETJMP)
- CONST_CALL_P (emit_note_after (INTVAL (XEXP (note, 0)), insn))
- = CONST_CALL_P (note);
+ {
+ CONST_CALL_P (emit_note_after (INTVAL (XEXP (note, 0)), insn))
+ = CONST_CALL_P (note);
+ remove_note (insn, note);
+ note = XEXP (note, 1);
+ }
else
- last = emit_note_before (INTVAL (XEXP (note, 0)), last);
+ {
+ last = emit_note_before (INTVAL (XEXP (note, 0)), last);
+ remove_note (insn, note);
+ note = XEXP (note, 1);
+ NOTE_BLOCK_NUMBER (last) = INTVAL (XEXP (note, 0));
+ }
remove_note (insn, note);
}
}
bzero ((char *) reg_last_uses, i * sizeof (rtx));
reg_last_sets = (rtx *) alloca (i * sizeof (rtx));
bzero ((char *) reg_last_sets, i * sizeof (rtx));
- reg_pending_sets = (regset) alloca (regset_bytes);
- bzero ((char *) reg_pending_sets, regset_bytes);
+ reg_pending_sets = ALLOCA_REG_SET ();
+ CLEAR_REG_SET (reg_pending_sets);
reg_pending_sets_all = 0;
clear_units ();
sched_note_set (b, XVECEXP (PATTERN (insn), 0, j), 0);
}
+ /* Each call clobbers (makes live) all call-clobbered regs
+ that are not global or fixed. Note that the function-value
+ reg is a call_clobbered reg. */
+
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ int j;
+ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+ if (call_used_regs[j] && ! global_regs[j]
+ && ! fixed_regs[j])
+ {
+ SET_REGNO_REG_SET (bb_live_regs, j);
+ CLEAR_REGNO_REG_SET (bb_dead_regs, j);
+ }
+ }
+
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
{
if ((REG_NOTE_KIND (link) == REG_DEAD
&& GET_CODE (XEXP (link, 0)) == REG)
{
register int regno = REGNO (XEXP (link, 0));
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
if (regno < FIRST_PSEUDO_REGISTER)
{
GET_MODE (XEXP (link, 0)));
while (--j >= 0)
{
- offset = (regno + j) / REGSET_ELT_BITS;
- bit = ((REGSET_ELT_TYPE) 1
- << ((regno + j) % REGSET_ELT_BITS));
-
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
+ SET_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+ SET_REGNO_REG_SET (bb_dead_regs, regno);
}
}
}
sched_note_set (b, XVECEXP (PATTERN (insn), 0, j), 0);
}
+ /* Each call clobbers (makes live) all call-clobbered regs that are
+ not global or fixed. Note that the function-value reg is a
+ call_clobbered reg. */
+
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ int j;
+ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+ if (call_used_regs[j] && ! global_regs[j]
+ && ! fixed_regs[j])
+ {
+ SET_REGNO_REG_SET (bb_live_regs, j);
+ CLEAR_REGNO_REG_SET (bb_dead_regs, j);
+ }
+ }
+
/* Need to know what registers this insn kills. */
for (prev = 0, link = REG_NOTES (insn); link; link = next)
{
&& GET_CODE (XEXP (link, 0)) == REG)
{
register int regno = REGNO (XEXP (link, 0));
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
/* Only unlink REG_DEAD notes; leave REG_UNUSED notes
alone. */
GET_MODE (XEXP (link, 0)));
while (--j >= 0)
{
- offset = (regno + j) / REGSET_ELT_BITS;
- bit = ((REGSET_ELT_TYPE) 1
- << ((regno + j) % REGSET_ELT_BITS));
-
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
+ SET_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+ SET_REGNO_REG_SET (bb_dead_regs, regno);
}
}
else
if (reload_completed == 0)
{
/* Keep track of register lives. */
- old_live_regs = (regset) alloca (regset_bytes);
+ old_live_regs = ALLOCA_REG_SET ();
regs_sometimes_live
= (struct sometimes *) alloca (max_regno * sizeof (struct sometimes));
sometimes_max = 0;
/* Start with registers live at end. */
- for (j = 0; j < regset_size; j++)
- {
- REGSET_ELT_TYPE live = bb_live_regs[j];
- old_live_regs[j] = live;
- if (live)
- {
- register int bit;
- for (bit = 0; bit < REGSET_ELT_BITS; bit++)
- if (live & ((REGSET_ELT_TYPE) 1 << bit))
- sometimes_max = new_sometimes_live (regs_sometimes_live, j,
- bit, sometimes_max);
- }
- }
+ COPY_REG_SET (old_live_regs, bb_live_regs);
+ EXECUTE_IF_SET_IN_REG_SET (bb_live_regs, 0, j,
+ {
+ sometimes_max
+ = new_sometimes_live (regs_sometimes_live,
+ j, sometimes_max);
+ });
}
SCHED_SORT (ready, n_ready, 1);
{
register struct sometimes *p;
- /* A call kills all call used and global registers, except
- for those mentioned in the call pattern which will be
- made live again later. */
+ /* A call kills all call used registers that are not
+ global or fixed, except for those mentioned in the call
+ pattern which will be made live again later. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if ((call_used_regs[i] && ! fixed_regs[i])
- || global_regs[i])
+ if (call_used_regs[i] && ! global_regs[i]
+ && ! fixed_regs[i])
{
- register int offset = i / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
-
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, i);
+ SET_REGNO_REG_SET (bb_dead_regs, i);
}
/* Regs live at the time of a call instruction must not
(below). */
p = regs_sometimes_live;
for (i = 0; i < sometimes_max; i++, p++)
- if (bb_live_regs[p->offset]
- & ((REGSET_ELT_TYPE) 1 << p->bit))
+ if (REGNO_REG_SET_P (bb_live_regs, p->regno))
p->calls_crossed += 1;
}
attach_deaths_insn (insn);
/* Find registers now made live by that instruction. */
- for (i = 0; i < regset_size; i++)
- {
- REGSET_ELT_TYPE diff = bb_live_regs[i] & ~old_live_regs[i];
- if (diff)
- {
- register int bit;
- old_live_regs[i] |= diff;
- for (bit = 0; bit < REGSET_ELT_BITS; bit++)
- if (diff & ((REGSET_ELT_TYPE) 1 << bit))
- sometimes_max
- = new_sometimes_live (regs_sometimes_live, i, bit,
- sometimes_max);
- }
- }
+ EXECUTE_IF_AND_COMPL_IN_REG_SET (bb_live_regs, old_live_regs, 0, i,
+ {
+ sometimes_max
+ = new_sometimes_live (regs_sometimes_live,
+ i, sometimes_max);
+ });
+ IOR_REG_SET (old_live_regs, bb_live_regs);
/* Count lengths of all regs we are worrying about now,
and handle registers no longer live. */
for (i = 0; i < sometimes_max; i++)
{
register struct sometimes *p = ®s_sometimes_live[i];
- int regno = p->offset*REGSET_ELT_BITS + p->bit;
+ int regno = p->regno;
p->live_length += 1;
- if ((bb_live_regs[p->offset]
- & ((REGSET_ELT_TYPE) 1 << p->bit)) == 0)
+ if (!REGNO_REG_SET_P (bb_live_regs, p->regno))
{
/* This is the end of one of this register's lifetime
segments. Save the lifetime info collected so far,
and clear its bit in the old_live_regs entry. */
sched_reg_live_length[regno] += p->live_length;
sched_reg_n_calls_crossed[regno] += p->calls_crossed;
- old_live_regs[p->offset]
- &= ~((REGSET_ELT_TYPE) 1 << p->bit);
+ CLEAR_REGNO_REG_SET (old_live_regs, p->regno);
/* Delete the reg_sometimes_live entry for this reg by
copying the last entry over top of it. */
}
}
- /* Put back NOTE_INSN_SETJMP, NOTE_INSN_LOOP_BEGIN, and
- NOTE_INSN_LOOP_END notes. */
+ /* Put back NOTE_INSN_SETJMP,
+ NOTE_INSN_{LOOP,EHREGION}_{BEGIN,END} notes. */
/* To prime the loop. We need to handle INSN and all the insns in the
sched group. */
int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (dest));
for (i = regno; i < endregno; i++)
- reg_n_sets[i] += inc;
+ REG_N_SETS (i) += inc;
}
else
- reg_n_sets[regno] += inc;
+ REG_N_SETS (regno) += inc;
}
}
pattern, so we can safely ignore it. */
if (insn == first)
{
+ /* After reload, REG_DEAD notes come sometimes an
+ instruction after the register actually dies. */
+ if (reload_completed && REG_NOTE_KIND (note) == REG_DEAD)
+ {
+ XEXP (note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = note;
+ break;
+ }
+
if (REG_NOTE_KIND (note) != REG_UNUSED)
abort ();
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)
/* The original dest must still be set someplace. Abort if we
couldn't find it. */
if (insn == first)
- abort ();
+ {
+ /* 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) > MOVE_MAX)
+ break;
+ abort ();
+ }
}
break;
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. */
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))
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 ();
/* 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.
-
- There is no new REG_DEAD note needed if the last insn uses the register
- that it is setting. */
+ insn because it was used and set within one insn. */
set = single_set (last);
if (set)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG
- && ! reg_overlap_mentioned_p (dest, SET_SRC (set)))
+ /* Global registers are always live, so the code below does not
+ apply to them. */
+ && (REGNO (dest) >= FIRST_PSEUDO_REGISTER
+ || ! global_regs[REGNO (dest)]))
{
- for (insn = PREV_INSN (last); ; insn = PREV_INSN (insn))
+ 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))
break;
}
}
- if (insn == first)
- break;
}
}
}
{
int max_uid = MAX_INSNS_PER_SPLIT * (get_max_uid () + 1);
int b;
+ int i;
rtx insn;
/* Taking care of this degenerate case makes the rest of
if (reload_completed == 0)
{
- sched_reg_n_deaths = (short *) alloca (max_regno * sizeof (short));
sched_reg_n_calls_crossed = (int *) alloca (max_regno * sizeof (int));
sched_reg_live_length = (int *) alloca (max_regno * sizeof (int));
- bb_dead_regs = (regset) alloca (regset_bytes);
- bb_live_regs = (regset) alloca (regset_bytes);
+ bb_dead_regs = ALLOCA_REG_SET ();
+ bb_live_regs = ALLOCA_REG_SET ();
bzero ((char *) sched_reg_n_calls_crossed, max_regno * sizeof (int));
bzero ((char *) sched_reg_live_length, max_regno * sizeof (int));
- bcopy ((char *) reg_n_deaths, (char *) sched_reg_n_deaths,
- max_regno * sizeof (short));
init_alias_analysis ();
}
else
{
- sched_reg_n_deaths = 0;
sched_reg_n_calls_crossed = 0;
sched_reg_live_length = 0;
bb_dead_regs = 0;
/* Split insns here to get max fine-grain parallelism. */
prev = PREV_INSN (insn);
- if (reload_completed == 0)
+ /* It is probably not worthwhile to try to split again in the
+ second pass. However, if flag_schedule_insns is not set,
+ the first and only (if any) scheduling pass is after reload. */
+ if (reload_completed == 0 || ! flag_schedule_insns)
{
rtx last, first = PREV_INSN (insn);
rtx notes = REG_NOTES (insn);
{
if (dump_file)
{
- if (reg_live_length[regno] > sched_reg_live_length[regno])
+ if (REG_LIVE_LENGTH (regno) > sched_reg_live_length[regno])
fprintf (dump_file,
";; register %d life shortened from %d to %d\n",
- regno, reg_live_length[regno],
+ regno, REG_LIVE_LENGTH (regno),
sched_reg_live_length[regno]);
/* Negative values are special; don't overwrite the current
reg_live_length value if it is negative. */
- else if (reg_live_length[regno] < sched_reg_live_length[regno]
- && reg_live_length[regno] >= 0)
+ else if (REG_LIVE_LENGTH (regno) < sched_reg_live_length[regno]
+ && REG_LIVE_LENGTH (regno) >= 0)
fprintf (dump_file,
";; register %d life extended from %d to %d\n",
- regno, reg_live_length[regno],
+ regno, REG_LIVE_LENGTH (regno),
sched_reg_live_length[regno]);
- if (! reg_n_calls_crossed[regno]
+ if (! REG_N_CALLS_CROSSED (regno)
&& sched_reg_n_calls_crossed[regno])
fprintf (dump_file,
";; register %d now crosses calls\n", regno);
- else if (reg_n_calls_crossed[regno]
+ else if (REG_N_CALLS_CROSSED (regno)
&& ! sched_reg_n_calls_crossed[regno]
- && reg_basic_block[regno] != REG_BLOCK_GLOBAL)
+ && REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL)
fprintf (dump_file,
";; register %d no longer crosses calls\n", regno);
}
/* Negative values are special; don't overwrite the current
reg_live_length value if it is negative. */
- if (reg_live_length[regno] >= 0)
- reg_live_length[regno] = sched_reg_live_length[regno];
+ if (REG_LIVE_LENGTH (regno) >= 0)
+ REG_LIVE_LENGTH (regno) = sched_reg_live_length[regno];
/* We can't change the value of reg_n_calls_crossed to zero for
pseudos which are live in more than one block.
Alternatively, we could try to correctly update basic block live
at start here in sched, but that seems complicated. */
if (sched_reg_n_calls_crossed[regno]
- || reg_basic_block[regno] != REG_BLOCK_GLOBAL)
- reg_n_calls_crossed[regno] = sched_reg_n_calls_crossed[regno];
+ || REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL)
+ REG_N_CALLS_CROSSED (regno) = sched_reg_n_calls_crossed[regno];
}
}
}