#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
+/* The contents of the current function definition are allocated
+ in this obstack, and all are freed at the end of the function.
+ For top-level functions, this is temporary_obstack.
+ Separate obstacks are made for nested functions. */
+
+extern struct obstack *function_obstack;
+
/* List of labels that must never be deleted. */
extern rtx forced_labels;
static int num_scratch;
-/* Indexed by n, gives number of basic block that (REG n) is used in.
- If the value is REG_BLOCK_GLOBAL (-2),
- it means (REG n) is used in more than one basic block.
- REG_BLOCK_UNKNOWN (-1) means it hasn't been seen yet so we don't know.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation. */
-
-int *reg_basic_block;
-
-/* Indexed by n, gives number of times (REG n) is used or set, each
- weighted by its loop-depth.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation. */
-
-int *reg_n_refs;
-
-/* Indexed by N; says whether a pseudo register N was ever used
- within a SUBREG that changes the size of the reg. Some machines prohibit
- such objects to be in certain (usually floating-point) registers. */
-
-char *reg_changes_size;
-
-/* Indexed by N, gives number of places register N dies.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation. */
-
-short *reg_n_deaths;
-
-/* Indexed by N, gives 1 if that reg is live across any CALL_INSNs.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation. */
+/* Indexed by n, giving various register information */
-int *reg_n_calls_crossed;
-
-/* Total number of instructions at which (REG n) is live.
- The larger this is, the less priority (REG n) gets for
- allocation in a real register.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation.
-
- local-alloc.c may alter this number to change the priority.
-
- Negative values are special.
- -1 is used to mark a pseudo reg which has a constant or memory equivalent
- and is used infrequently enough that it should not get a hard register.
- -2 is used to mark a pseudo reg for a parameter, when a frame pointer
- is not required. global.c makes an allocno for this but does
- not try to assign a hard register to it. */
-
-int *reg_live_length;
+reg_info *reg_n_info;
/* Element N is the next insn that uses (hard or pseudo) register number N
within the current basic block; or zero, if there is no such insn.
static void mark_label_ref PROTO((rtx, rtx, int));
static void life_analysis PROTO((rtx, int));
void allocate_for_life_analysis PROTO((void));
-static void init_regset_vector PROTO((regset *, regset, int, int));
+static void init_regset_vector PROTO((regset *, int, int, struct obstack *));
static void propagate_block PROTO((regset, rtx, rtx, int,
regset, int));
static rtx flow_delete_insn PROTO((rtx));
/* List of label_refs to all labels whose addresses are taken
and used as data. */
rtx label_value_list;
+ int label_value_list_marked_live;
rtx x, note;
enum rtx_code prev_code, code;
int depth, pass;
restart:
label_value_list = 0;
+ label_value_list_marked_live = 0;
block_live_static = block_live;
bzero (block_live, n_basic_blocks);
bzero (block_marked, n_basic_blocks);
abort ();
n_basic_blocks = i + 1;
- /* Don't delete the labels (in this function)
- that are referenced by non-jump instructions. */
-
- for (x = label_value_list; x; x = XEXP (x, 1))
- if (! LABEL_REF_NONLOCAL_P (x))
- block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
-
for (x = forced_labels; x; x = XEXP (x, 1))
if (! LABEL_REF_NONLOCAL_P (x))
block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
if (computed_jump)
{
+ if (label_value_list_marked_live == 0)
+ {
+ label_value_list_marked_live = 1;
+
+ /* This could be made smarter by only considering
+ these live, if the computed goto is live. */
+
+ /* Don't delete the labels (in this function) that
+ are referenced by non-jump instructions. */
+
+ for (x = label_value_list; x; x = XEXP (x, 1))
+ if (! LABEL_REF_NONLOCAL_P (x))
+ block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
+ }
+
for (x = label_value_list; x; x = XEXP (x, 1))
mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
insn, 0);
gotos. */
}
+ /* All blocks associated with labels in label_value_list are
+ trivially considered as marked live, if the list is empty.
+ We do this to speed up the below code. */
+
+ if (label_value_list == 0)
+ label_value_list_marked_live = 1;
+
/* Pass over all blocks, marking each block that is reachable
and has not yet been marked.
Keep doing this until, in one pass, no blocks have been marked.
insn = basic_block_end[i];
if (GET_CODE (insn) == JUMP_INSN)
mark_label_ref (PATTERN (insn), insn, 0);
+
+ if (label_value_list_marked_live == 0)
+ /* Now that we know that this block is live, mark as
+ live, all the blocks that we might be able to get
+ to as live. */
+
+ for (insn = basic_block_head[i];
+ insn != NEXT_INSN (basic_block_end[i]);
+ insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ for (note = REG_NOTES (insn);
+ note;
+ note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_LABEL)
+ {
+ x = XEXP (note, 0);
+ block_live[BLOCK_NUM (x)] = 1;
+ }
+ }
+ }
}
}
rtx f;
int nregs;
{
- register regset tem;
int first_pass;
int changed;
/* For each basic block, a bitmask of regs
if there isn't enough space.
Don't use oballoc since we may need to allocate other things during
this function on the temporary obstack. */
- tem = (regset) obstack_alloc (&flow_obstack, n_basic_blocks * regset_bytes);
- bzero ((char *) tem, n_basic_blocks * regset_bytes);
- init_regset_vector (basic_block_live_at_end, tem,
- n_basic_blocks, regset_bytes);
+ init_regset_vector (basic_block_live_at_end, n_basic_blocks, regset_bytes,
+ &flow_obstack);
basic_block_new_live_at_end
= (regset *) alloca (n_basic_blocks * sizeof (regset));
- tem = (regset) obstack_alloc (&flow_obstack, n_basic_blocks * regset_bytes);
- bzero ((char *) tem, n_basic_blocks * regset_bytes);
- init_regset_vector (basic_block_new_live_at_end, tem,
- n_basic_blocks, regset_bytes);
+ init_regset_vector (basic_block_new_live_at_end, n_basic_blocks, regset_bytes,
+ &flow_obstack);
basic_block_significant
= (regset *) alloca (n_basic_blocks * sizeof (regset));
- tem = (regset) obstack_alloc (&flow_obstack, n_basic_blocks * regset_bytes);
- bzero ((char *) tem, n_basic_blocks * regset_bytes);
- init_regset_vector (basic_block_significant, tem,
- n_basic_blocks, regset_bytes);
+ init_regset_vector (basic_block_significant, n_basic_blocks, regset_bytes,
+ &flow_obstack);
/* Record which insns refer to any volatile memory
or for any reason can't be deleted just because they are dead stores.
{
/* If exiting needs the right stack value,
consider the stack pointer live at the end of the function. */
- basic_block_live_at_end[n_basic_blocks - 1]
- [STACK_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS);
- basic_block_new_live_at_end[n_basic_blocks - 1]
- [STACK_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1],
+ STACK_POINTER_REGNUM);
+ SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1],
+ STACK_POINTER_REGNUM);
}
/* Mark the frame pointer is needed at the end of the function. If
if (n_basic_blocks > 0)
{
- basic_block_live_at_end[n_basic_blocks - 1]
- [FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (FRAME_POINTER_REGNUM % REGSET_ELT_BITS);
- basic_block_new_live_at_end[n_basic_blocks - 1]
- [FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (FRAME_POINTER_REGNUM % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1],
+ FRAME_POINTER_REGNUM);
+ SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1],
+ FRAME_POINTER_REGNUM);
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
/* If they are different, also mark the hard frame pointer as live */
- basic_block_live_at_end[n_basic_blocks - 1]
- [HARD_FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (HARD_FRAME_POINTER_REGNUM
- % REGSET_ELT_BITS);
- basic_block_new_live_at_end[n_basic_blocks - 1]
- [HARD_FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (HARD_FRAME_POINTER_REGNUM
- % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1],
+ HARD_FRAME_POINTER_REGNUM);
+ SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1],
+ HARD_FRAME_POINTER_REGNUM);
#endif
}
#endif
)
{
- basic_block_live_at_end[n_basic_blocks - 1]
- [i / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
- basic_block_new_live_at_end[n_basic_blocks - 1]
- [i / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1], i);
+ SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1], i);
}
/* Propagate life info through the basic blocks
reg that is live at the end now but was not live there before
is one of the significant regs of this basic block). */
- for (j = 0; j < regset_size; j++)
- {
- register REGSET_ELT_TYPE x
- = (basic_block_new_live_at_end[i][j]
- & ~basic_block_live_at_end[i][j]);
- if (x)
- consider = 1;
- if (x & basic_block_significant[i][j])
- {
- must_rescan = 1;
- consider = 1;
- break;
- }
- }
-
+ EXECUTE_IF_AND_COMPL_IN_REG_SET (basic_block_new_live_at_end[i],
+ basic_block_live_at_end[i],
+ 0, j,
+ {
+ consider = 1;
+ if (REGNO_REG_SET_P (basic_block_significant[i], j))
+ {
+ must_rescan = 1;
+ goto done;
+ }
+ });
+ done:
if (! consider)
continue;
}
/* No complete rescan needed;
just record those variables newly known live at end
as live at start as well. */
- for (j = 0; j < regset_size; j++)
- {
- register REGSET_ELT_TYPE x
- = (basic_block_new_live_at_end[i][j]
- & ~basic_block_live_at_end[i][j]);
- basic_block_live_at_start[i][j] |= x;
- basic_block_live_at_end[i][j] |= x;
- }
+ IOR_AND_COMPL_REG_SET (basic_block_live_at_start[i],
+ basic_block_new_live_at_end[i],
+ basic_block_live_at_end[i]);
+
+ IOR_AND_COMPL_REG_SET (basic_block_live_at_end[i],
+ basic_block_new_live_at_end[i],
+ basic_block_live_at_end[i]);
}
else
{
/* Update the basic_block_live_at_start
by propagation backwards through the block. */
- bcopy ((char *) basic_block_new_live_at_end[i],
- (char *) basic_block_live_at_end[i], regset_bytes);
- bcopy ((char *) basic_block_live_at_end[i],
- (char *) basic_block_live_at_start[i], regset_bytes);
+ COPY_REG_SET (basic_block_live_at_end[i],
+ basic_block_new_live_at_end[i]);
+ COPY_REG_SET (basic_block_live_at_start[i],
+ basic_block_live_at_end[i]);
propagate_block (basic_block_live_at_start[i],
basic_block_head[i], basic_block_end[i], 0,
first_pass ? basic_block_significant[i]
that falls through into this one (if any). */
head = basic_block_head[i];
if (basic_block_drops_in[i])
- {
- register int j;
- for (j = 0; j < regset_size; j++)
- basic_block_new_live_at_end[i-1][j]
- |= basic_block_live_at_start[i][j];
- }
+ IOR_REG_SET (basic_block_new_live_at_end[i-1],
+ basic_block_live_at_start[i]);
/* Update the basic_block_new_live_at_end's of
all the blocks that jump to this one. */
jump = LABEL_NEXTREF (jump))
{
register int from_block = BLOCK_NUM (CONTAINING_INSN (jump));
- register int j;
- for (j = 0; j < regset_size; j++)
- basic_block_new_live_at_end[from_block][j]
- |= basic_block_live_at_start[i][j];
+ IOR_REG_SET (basic_block_new_live_at_end[from_block],
+ basic_block_live_at_start[i]);
}
}
#ifdef USE_C_ALLOCA
one basic block. */
if (n_basic_blocks > 0)
- for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (basic_block_live_at_start[0][i / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS)))
- reg_basic_block[i] = REG_BLOCK_GLOBAL;
+ EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[0],
+ FIRST_PSEUDO_REGISTER, i,
+ {
+ REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL;
+ });
/* Now the life information is accurate.
Make one more pass over each basic block
But we don't need to do this for the user's variables, since
ANSI says only volatile variables need this. */
#ifdef LONGJMP_RESTORE_FROM_STACK
- for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
- if (regs_live_at_setjmp[i / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS))
- && regno_reg_rtx[i] != 0 && ! REG_USERVAR_P (regno_reg_rtx[i]))
- {
- reg_live_length[i] = -1;
- reg_basic_block[i] = -1;
- }
+ EXECUTE_IF_SET_IN_REG_SET (regs_live_at_setjmp,
+ FIRST_PSEUDO_REGISTER, i,
+ {
+ if (regno_reg_rtx[i] != 0
+ && ! REG_USERVAR_P (regno_reg_rtx[i]))
+ {
+ REG_LIVE_LENGTH (i) = -1;
+ REG_BASIC_BLOCK (i) = -1;
+ }
+ });
#endif
#endif
If the pseudo goes in a hard reg, some other value may occupy
that hard reg where this pseudo is dead, thus clobbering the pseudo.
Conclusion: such a pseudo must not go in a hard reg. */
- for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
- if ((regs_live_at_setjmp[i / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS)))
- && regno_reg_rtx[i] != 0)
- {
- reg_live_length[i] = -1;
- reg_basic_block[i] = -1;
- }
+ EXECUTE_IF_SET_IN_REG_SET (regs_live_at_setjmp,
+ FIRST_PSEUDO_REGISTER, i,
+ {
+ if (regno_reg_rtx[i] != 0)
+ {
+ REG_LIVE_LENGTH (i) = -1;
+ REG_BASIC_BLOCK (i) = -1;
+ }
+ });
obstack_free (&flow_obstack, NULL_PTR);
}
allocate_for_life_analysis ()
{
register int i;
- register regset tem;
regset_size = ((max_regno + REGSET_ELT_BITS - 1) / REGSET_ELT_BITS);
regset_bytes = regset_size * sizeof (*(regset) 0);
- reg_n_refs = (int *) oballoc (max_regno * sizeof (int));
- bzero ((char *) reg_n_refs, max_regno * sizeof (int));
-
- reg_n_sets = (short *) oballoc (max_regno * sizeof (short));
- bzero ((char *) reg_n_sets, max_regno * sizeof (short));
-
- reg_n_deaths = (short *) oballoc (max_regno * sizeof (short));
- bzero ((char *) reg_n_deaths, max_regno * sizeof (short));
+ /* Because both reg_scan and flow_analysis want to set up the REG_N_SETS
+ information, explicitly reset it here. The allocation should have
+ already happened on the previous reg_scan pass. Make sure in case
+ some more registers were allocated. */
+ allocate_reg_info (max_regno, FALSE, FALSE);
- reg_changes_size = (char *) oballoc (max_regno * sizeof (char));
- bzero (reg_changes_size, max_regno * sizeof (char));;
-
- reg_live_length = (int *) oballoc (max_regno * sizeof (int));
- bzero ((char *) reg_live_length, max_regno * sizeof (int));
-
- reg_n_calls_crossed = (int *) oballoc (max_regno * sizeof (int));
- bzero ((char *) reg_n_calls_crossed, max_regno * sizeof (int));
-
- reg_basic_block = (int *) oballoc (max_regno * sizeof (int));
for (i = 0; i < max_regno; i++)
- reg_basic_block[i] = REG_BLOCK_UNKNOWN;
+ REG_N_SETS (i) = 0;
basic_block_live_at_start
= (regset *) oballoc (n_basic_blocks * sizeof (regset));
- tem = (regset) oballoc (n_basic_blocks * regset_bytes);
- bzero ((char *) tem, n_basic_blocks * regset_bytes);
- init_regset_vector (basic_block_live_at_start, tem,
- n_basic_blocks, regset_bytes);
+ init_regset_vector (basic_block_live_at_start, n_basic_blocks, regset_bytes,
+ function_obstack);
- regs_live_at_setjmp = (regset) oballoc (regset_bytes);
- bzero ((char *) regs_live_at_setjmp, regset_bytes);
+ regs_live_at_setjmp = OBSTACK_ALLOC_REG_SET (function_obstack);
+ CLEAR_REG_SET (regs_live_at_setjmp);
}
/* Make each element of VECTOR point at a regset,
BYTES_PER_ELT is the number of bytes in one regset. */
static void
-init_regset_vector (vector, space, nelts, bytes_per_elt)
+init_regset_vector (vector, nelts, bytes_per_elt, alloc_obstack)
regset *vector;
- regset space;
int nelts;
int bytes_per_elt;
+ struct obstack *alloc_obstack;
{
register int i;
- register regset p = space;
for (i = 0; i < nelts; i++)
{
- vector[i] = p;
- p += bytes_per_elt / sizeof (*p);
+ vector[i] = OBSTACK_ALLOC_REG_SET (alloc_obstack);
+ CLEAR_REG_SET (vector[i]);
}
}
/* The following variables are used only if FINAL is nonzero. */
/* This vector gets one element for each reg that has been live
at any point in the basic block that has been scanned so far.
- SOMETIMES_MAX says how many elements are in use so far.
- In each element, OFFSET is the byte-number within a regset
- for the register described by the element, and BIT is a mask
- for that register's bit within the byte. */
- register struct sometimes { short offset; short bit; } *regs_sometimes_live;
+ SOMETIMES_MAX says how many elements are in use so far. */
+ register int *regs_sometimes_live;
int sometimes_max = 0;
/* This regset has 1 for each reg that we have seen live so far.
It and REGS_SOMETIMES_LIVE are updated together. */
current basic block, and adjust as we pass ends and starts of loops. */
loop_depth = basic_block_loop_depth[bnum];
- dead = (regset) alloca (regset_bytes);
- live = (regset) alloca (regset_bytes);
+ dead = ALLOCA_REG_SET ();
+ live = ALLOCA_REG_SET ();
cc0_live = 0;
last_mem_set = 0;
if (final)
{
- register int i, offset;
- REGSET_ELT_TYPE bit;
+ register int i;
num_scratch = 0;
- maxlive = (regset) alloca (regset_bytes);
- bcopy ((char *) old, (char *) maxlive, regset_bytes);
- regs_sometimes_live
- = (struct sometimes *) alloca (max_regno * sizeof (struct sometimes));
+ maxlive = ALLOCA_REG_SET ();
+ COPY_REG_SET (maxlive, old);
+ regs_sometimes_live = (int *) alloca (max_regno * sizeof (int));
/* Process the regs live at the end of the block.
Enter them in MAXLIVE and REGS_SOMETIMES_LIVE.
- Also mark them as not local to any one basic block. */
-
- for (offset = 0, i = 0; offset < regset_size; offset++)
- for (bit = 1; bit; bit <<= 1, i++)
- {
- if (i == max_regno)
- break;
- if (old[offset] & bit)
- {
- reg_basic_block[i] = REG_BLOCK_GLOBAL;
- regs_sometimes_live[sometimes_max].offset = offset;
- regs_sometimes_live[sometimes_max].bit = i % REGSET_ELT_BITS;
- sometimes_max++;
- }
- }
+ Also mark them as not local to any one basic block. */
+ EXECUTE_IF_SET_IN_REG_SET (old, 0, i,
+ {
+ REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL;
+ regs_sometimes_live[sometimes_max] = i;
+ sometimes_max++;
+ });
}
/* Scan the block an insn at a time from end to beginning. */
warn if any non-volatile datum is live. */
if (final && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
- {
- int i;
- for (i = 0; i < regset_size; i++)
- regs_live_at_setjmp[i] |= old[i];
- }
+ IOR_REG_SET (regs_live_at_setjmp, old);
}
/* Update the life-status of regs for this insn.
goto flushed;
}
- for (i = 0; i < regset_size; i++)
- {
- dead[i] = 0; /* Faster than bzero here */
- live[i] = 0; /* since regset_size is usually small */
- }
+ CLEAR_REG_SET (dead);
+ CLEAR_REG_SET (live);
/* See if this is an increment or decrement that can be
merged into a following memory address. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (call_used_regs[i] && ! global_regs[i]
&& ! fixed_regs[i])
- dead[i / REGSET_ELT_BITS]
- |= ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS));
+ SET_REGNO_REG_SET (dead, i);
/* The stack ptr is used (honorarily) by a CALL insn. */
- live[STACK_POINTER_REGNUM / REGSET_ELT_BITS]
- |= ((REGSET_ELT_TYPE) 1
- << (STACK_POINTER_REGNUM % REGSET_ELT_BITS));
+ SET_REGNO_REG_SET (live, STACK_POINTER_REGNUM);
/* Calls may also reference any of the global registers,
so they are made live. */
}
/* Update OLD for the registers used or set. */
- for (i = 0; i < regset_size; i++)
- {
- old[i] &= ~dead[i];
- old[i] |= live[i];
- }
+ AND_COMPL_REG_SET (old, dead);
+ IOR_REG_SET (old, live);
if (GET_CODE (insn) == CALL_INSN && final)
{
must not go in a register clobbered by calls.
Find all regs now live and record this for them. */
- register struct sometimes *p = regs_sometimes_live;
+ register int *p = regs_sometimes_live;
for (i = 0; i < sometimes_max; i++, p++)
- if (old[p->offset] & ((REGSET_ELT_TYPE) 1 << p->bit))
- reg_n_calls_crossed[p->offset * REGSET_ELT_BITS + p->bit]+= 1;
+ if (REGNO_REG_SET_P (old, *p))
+ REG_N_CALLS_CROSSED (*p)++;
}
}
if (final)
{
- for (i = 0; i < regset_size; i++)
- {
- register REGSET_ELT_TYPE diff = live[i] & ~maxlive[i];
+ register int regno;
+ register int *p;
- if (diff)
- {
- register int regno;
- maxlive[i] |= diff;
- for (regno = 0; diff && regno < REGSET_ELT_BITS; regno++)
- if (diff & ((REGSET_ELT_TYPE) 1 << regno))
- {
- regs_sometimes_live[sometimes_max].offset = i;
- regs_sometimes_live[sometimes_max].bit = regno;
- diff &= ~ ((REGSET_ELT_TYPE) 1 << regno);
- sometimes_max++;
- }
- }
- }
+ EXECUTE_IF_AND_COMPL_IN_REG_SET (live, maxlive, 0, regno,
+ {
+ regs_sometimes_live[sometimes_max++] = regno;
+ SET_REGNO_REG_SET (maxlive, regno);
+ });
- {
- register struct sometimes *p = regs_sometimes_live;
- for (i = 0; i < sometimes_max; i++, p++)
- {
- if (old[p->offset] & ((REGSET_ELT_TYPE) 1 << p->bit))
- reg_live_length[p->offset * REGSET_ELT_BITS + p->bit]++;
- }
- }
+ p = regs_sometimes_live;
+ for (i = 0; i < sometimes_max; i++)
+ {
+ regno = *p++;
+ if (REGNO_REG_SET_P (old, regno))
+ REG_LIVE_LENGTH (regno)++;
+ }
}
}
flushed: ;
if (GET_CODE (r) == REG)
{
register int regno = REGNO (r);
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
/* Don't delete insns to set global regs. */
if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
it, so we can treat it normally). */
|| (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
#endif
- || (needed[offset] & bit) != 0)
+ || REGNO_REG_SET_P (needed, regno))
return 0;
/* If this is a hard register, verify that subsequent words are
int n = HARD_REGNO_NREGS (regno, GET_MODE (r));
while (--n > 0)
- if ((needed[(regno + n) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno + n) % REGSET_ELT_BITS))) != 0)
+ if (REGNO_REG_SET_P (needed, regno+n))
return 0;
}
&& (global_regs[regno] || FUNCTION_ARG_REGNO_P (regno))))
return 0;
- return (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS)));
+ return REGNO_REG_SET_P (basic_block_live_at_start[0], regno);
}
/* 1 if register REGNO was alive at a place where `setjmp' was called
if (n_basic_blocks == 0)
return 0;
- return ((reg_n_sets[regno] > 1
- || (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))))
- && (regs_live_at_setjmp[regno / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))));
+ return ((REG_N_SETS (regno) > 1
+ || REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
+ && REGNO_REG_SET_P (regs_live_at_setjmp, regno));
}
\f
/* Process the registers that are set within X.
&& ! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]))
/* && regno != STACK_POINTER_REGNUM) -- let's try without this. */
{
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
- REGSET_ELT_TYPE some_needed = (needed[offset] & bit);
- REGSET_ELT_TYPE some_not_needed = (~ needed[offset]) & bit;
+ int some_needed = REGNO_REG_SET_P (needed, regno);
+ int some_not_needed = ! some_needed;
/* Mark it as a significant register for this basic block. */
if (significant)
- significant[offset] |= bit;
+ SET_REGNO_REG_SET (significant, regno);
/* Mark it as as dead before this insn. */
- dead[offset] |= bit;
+ SET_REGNO_REG_SET (dead, regno);
/* A hard reg in a wide mode may really be multiple registers.
If so, mark all of them just like the first. */
n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (--n > 0)
{
- REGSET_ELT_TYPE n_bit
- = (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS);
-
+ int regno_n = regno + n;
+ int needed_regno = REGNO_REG_SET_P (needed, regno_n);
if (significant)
- significant[(regno + n) / REGSET_ELT_BITS] |= n_bit;
+ SET_REGNO_REG_SET (significant, regno_n);
- dead[(regno + n) / REGSET_ELT_BITS] |= n_bit;
- some_needed
- |= (needed[(regno + n) / REGSET_ELT_BITS] & n_bit);
- some_not_needed
- |= ((~ needed[(regno + n) / REGSET_ELT_BITS]) & n_bit);
+ SET_REGNO_REG_SET (dead, regno_n);
+ some_needed |= needed_regno;
+ some_not_needed |= ! needed_regno;
}
}
/* Additional data to record if this is the final pass. */
reg_next_use[i] = 0;
regs_ever_live[i] = 1;
- reg_n_sets[i]++;
+ REG_N_SETS (i)++;
}
}
else
/* Keep track of which basic blocks each reg appears in. */
- if (reg_basic_block[regno] == REG_BLOCK_UNKNOWN)
- reg_basic_block[regno] = blocknum;
- else if (reg_basic_block[regno] != blocknum)
- reg_basic_block[regno] = REG_BLOCK_GLOBAL;
+ if (REG_BASIC_BLOCK (regno) == REG_BLOCK_UNKNOWN)
+ REG_BASIC_BLOCK (regno) = blocknum;
+ else if (REG_BASIC_BLOCK (regno) != blocknum)
+ REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
/* Count (weighted) references, stores, etc. This counts a
register twice if it is modified, but that is correct. */
- reg_n_sets[regno]++;
+ REG_N_SETS (regno)++;
- reg_n_refs[regno] += loop_depth;
+ REG_N_REFS (regno) += loop_depth;
/* The insns where a reg is live are normally counted
elsewhere, but we want the count to include the insn
where the reg is set, and the normal counting mechanism
would not count it. */
- reg_live_length[regno]++;
+ REG_LIVE_LENGTH (regno)++;
}
if (! some_not_needed)
Indicate this by marking the reg being set as dying here. */
REG_NOTES (insn)
= gen_rtx (EXPR_LIST, REG_UNUSED, reg, REG_NOTES (insn));
- reg_n_deaths[REGNO (reg)]++;
+ REG_N_DEATHS (REGNO (reg))++;
}
else
{
for (i = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
i >= 0; i--)
- if ((needed[(regno + i) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno + i) % REGSET_ELT_BITS))) == 0)
+ if (!REGNO_REG_SET_P (needed, regno + i))
REG_NOTES (insn)
= gen_rtx (EXPR_LIST, REG_UNUSED,
gen_rtx (REG, reg_raw_mode[regno + i],
it previously wasn't live here. If we don't mark
it as needed, we'll put a REG_DEAD note for it
on this insn, which is incorrect. */
- needed[regno / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (needed, regno);
/* If there are any calls between INSN and INCR, show
that REGNO now crosses them. */
for (temp = insn; temp != incr; temp = NEXT_INSN (temp))
if (GET_CODE (temp) == CALL_INSN)
- reg_n_calls_crossed[regno]++;
+ REG_N_CALLS_CROSSED (regno)++;
}
else
return;
/* Count an extra reference to the reg. When a reg is
incremented, spilling it is worse, so we want to make
that less likely. */
- reg_n_refs[regno] += loop_depth;
+ REG_N_REFS (regno) += loop_depth;
/* Count the increment as a setting of the register,
even though it isn't a SET in rtl. */
- reg_n_sets[regno]++;
+ REG_N_SETS (regno)++;
}
}
}
return;
case MEM:
- /* Invalidate the data for the last MEM stored. We could do this only
- if the addresses conflict, but this doesn't seem worthwhile. */
- last_mem_set = 0;
+ /* CYGNUS LOCAL dje/8176 */
+ /* Invalidate the data for the last MEM stored, but only if MEM is
+ something that can be stored into. */
+ if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
+ ; /* needn't clear last_mem_set */
+ else
+ last_mem_set = 0;
+ /* END CYGNUS LOCAL */
#ifdef AUTO_INC_DEC
if (final)
&& REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (x))
!= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
- reg_changes_size[REGNO (SUBREG_REG (x))] = 1;
+ REG_CHANGES_SIZE (REGNO (SUBREG_REG (x))) = 1;
/* While we're here, optimize this case. */
x = SUBREG_REG (x);
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 some_needed = needed[offset] & bit;
- REGSET_ELT_TYPE some_not_needed = (~ needed[offset]) & bit;
+ REGSET_ELT_TYPE some_needed = REGNO_REG_SET_P (needed, regno);
+ REGSET_ELT_TYPE some_not_needed = ! some_needed;
- live[offset] |= bit;
+ SET_REGNO_REG_SET (live, regno);
/* A hard reg in a wide mode may really be multiple registers.
If so, mark all of them just like the first. */
n = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--n > 0)
{
- REGSET_ELT_TYPE n_bit
- = (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS);
+ int regno_n = regno + n;
+ int needed_regno = REGNO_REG_SET_P (needed, regno_n);
- live[(regno + n) / REGSET_ELT_BITS] |= n_bit;
- some_needed |= (needed[(regno + n) / REGSET_ELT_BITS] & n_bit);
- some_not_needed
- |= ((~ needed[(regno + n) / REGSET_ELT_BITS]) & n_bit);
+ SET_REGNO_REG_SET (live, regno_n);
+ some_needed |= needed_regno;
+ some_not_needed |= ! needed_regno;
}
}
if (final)
register int blocknum = BLOCK_NUM (insn);
- if (reg_basic_block[regno] == REG_BLOCK_UNKNOWN)
- reg_basic_block[regno] = blocknum;
- else if (reg_basic_block[regno] != blocknum)
- reg_basic_block[regno] = REG_BLOCK_GLOBAL;
+ if (REG_BASIC_BLOCK (regno) == REG_BLOCK_UNKNOWN)
+ REG_BASIC_BLOCK (regno) = blocknum;
+ else if (REG_BASIC_BLOCK (regno) != blocknum)
+ REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
/* Count (weighted) number of uses of each reg. */
- reg_n_refs[regno] += loop_depth;
+ REG_N_REFS (regno) += loop_depth;
}
/* Record and count the insns in which a reg dies.
{
REG_NOTES (insn)
= gen_rtx (EXPR_LIST, REG_DEAD, x, REG_NOTES (insn));
- reg_n_deaths[regno]++;
+ REG_N_DEATHS (regno)++;
}
else
{
for (i = HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1;
i >= 0; i--)
- if ((needed[(regno + i) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno + i) % REGSET_ELT_BITS))) == 0
+ if (!REGNO_REG_SET_P (needed, regno + i)
&& ! dead_or_set_regno_p (insn, regno + i))
REG_NOTES (insn)
= gen_rtx (EXPR_LIST, REG_DEAD,
&& REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (testreg))
!= GET_MODE_SIZE (GET_MODE (SUBREG_REG (testreg)))))
- reg_changes_size[REGNO (SUBREG_REG (testreg))] = 1;
+ REG_CHANGES_SIZE (REGNO (SUBREG_REG (testreg))) = 1;
/* Modifying a single register in an alternate mode
does not use any of the old value. But these other
if (! EXIT_IGNORE_STACK
|| (! FRAME_POINTER_REQUIRED && flag_omit_frame_pointer))
#endif
- live[STACK_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (live, STACK_POINTER_REGNUM);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i]
|| EPILOGUE_USES (i)
#endif
)
- live[i / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (live, i);
break;
}
less likely. */
if (regno >= FIRST_PSEUDO_REGISTER)
{
- reg_n_refs[regno] += loop_depth;
- reg_n_sets[regno]++;
+ REG_N_REFS (regno) += loop_depth;
+ REG_N_SETS (regno)++;
}
return 1;
}
fprintf (file, "%d registers.\n", max_regno);
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_n_refs[i])
+ if (REG_N_REFS (i))
{
enum reg_class class, altclass;
fprintf (file, "\nRegister %d used %d times across %d insns",
- i, reg_n_refs[i], reg_live_length[i]);
- if (reg_basic_block[i] >= 0)
- fprintf (file, " in block %d", reg_basic_block[i]);
- if (reg_n_deaths[i] != 1)
- fprintf (file, "; dies in %d places", reg_n_deaths[i]);
- if (reg_n_calls_crossed[i] == 1)
+ i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
+ if (REG_BASIC_BLOCK (i) >= 0)
+ fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
+ if (REG_N_DEATHS (i) != 1)
+ fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
+ if (REG_N_CALLS_CROSSED (i) == 1)
fprintf (file, "; crosses 1 call");
- else if (reg_n_calls_crossed[i])
- fprintf (file, "; crosses %d calls", reg_n_calls_crossed[i]);
+ else if (REG_N_CALLS_CROSSED (i))
+ fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
if (PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
class = reg_preferred_class (i);
}
fprintf (file, "\nRegisters live at start:");
for (regno = 0; regno < max_regno; regno++)
- {
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
- if (basic_block_live_at_start[i][offset] & bit)
- fprintf (file, " %d", regno);
- }
+ if (REGNO_REG_SET_P (basic_block_live_at_start[i], regno))
+ fprintf (file, " %d", regno);
fprintf (file, "\n");
}
fprintf (file, "\n");