ra-conflict.c: Include "sparseset.h".
* ra-conflict.c: Include "sparseset.h". (conflicts): Change to HOST_WIDEST_FAST_INT. (allocnos_live): Redefine variable as a sparseset. (SET_ALLOCNO_LIVE, CLEAR_ALLOCNO_LIVE, GET_ALLOCNO_LIVE): Delete macros. (allocno_row_words): Removed global variable. (partial_bitnum, max_bitnum, adjacency_pool, adjacency): New variables. (CONFLICT_BITNUM, CONFLICT_BITNUM_FAST): New defines. (conflict_p, set_conflict_p, set_conflicts_p): New functions. (record_one_conflict_between_regnos): Cache allocno values and reuse. Use set_conflict_p. (record_one_conflict): Update uses of allocnos_live to use the sparseset routines. Use set_conflicts_p. (mark_reg_store): Likewise. (set_reg_in_live): Likewise. (global_conflicts): Update uses of allocnos_live. Use the new adjacency list to visit an allocno's neighbors rather than iterating over all possible allocnos. Call set_conflicts_p to setup conflicts rather than adding them manually. * global.c: Comments updated. (CONFLICTP): Delete define. (regno_compare): New function. Add prototype. (global_alloc): Sort the allocno to regno mapping according to which basic blocks the regnos are referenced in. Modify the conflict bit matrix to a compressed triangular bitmatrix. Only allocate the conflict bit matrix and adjacency lists if we are actually going to allocate something. (expand_preferences): Use conflict_p. Update uses of allocnos_live. (prune_preferences): Use the FOR_EACH_CONFLICT macro to visit an allocno's neighbors rather than iterating over all possible allocnos. (mirror_conflicts): Removed function. (dump_conflicts): Iterate over regnos rather than allocnos so that all dump output will be sorted by regno number. Use the FOR_EACH_CONFLICT macro. * ra.h: Comments updated. (conflicts): Update prototype to HOST_WIDEST_FAST_INT. (partial_bitnum, max_bitnum, adjacency, adjacency_pool): Add prototypes. (ADJACENCY_VEC_LENGTH, FOR_EACH_CONFLICT): New defines. (adjacency_list_d, adjacency_iterator_d): New types. (add_neighbor, adjacency_iter_init, adjacency_iter_done, adjacency_iter_next, regno_basic_block): New static inline functions. (EXECUTE_IF_SET_IN_ALLOCNO_SET): Removed define. (conflict_p): Add function prototype. * sparseset.h, sparseset.c: New files. * Makefile.in (OBJS-common): Add sparseset.o. (sparseset.o): New rule. From-SVN: r129037
This commit is contained in:
parent
6aa12f4ffb
commit
b4da855a9e
@ -1,3 +1,52 @@
|
||||
2007-10-05 Peter Bergner <bergner@vnet.ibm.com>
|
||||
|
||||
* ra-conflict.c: Include "sparseset.h".
|
||||
(conflicts): Change to HOST_WIDEST_FAST_INT.
|
||||
(allocnos_live): Redefine variable as a sparseset.
|
||||
(SET_ALLOCNO_LIVE, CLEAR_ALLOCNO_LIVE, GET_ALLOCNO_LIVE): Delete macros.
|
||||
(allocno_row_words): Removed global variable.
|
||||
(partial_bitnum, max_bitnum, adjacency_pool, adjacency): New variables.
|
||||
(CONFLICT_BITNUM, CONFLICT_BITNUM_FAST): New defines.
|
||||
(conflict_p, set_conflict_p, set_conflicts_p): New functions.
|
||||
(record_one_conflict_between_regnos): Cache allocno values and reuse.
|
||||
Use set_conflict_p.
|
||||
(record_one_conflict): Update uses of allocnos_live to use
|
||||
the sparseset routines. Use set_conflicts_p.
|
||||
(mark_reg_store): Likewise.
|
||||
(set_reg_in_live): Likewise.
|
||||
(global_conflicts): Update uses of allocnos_live.
|
||||
Use the new adjacency list to visit an allocno's neighbors
|
||||
rather than iterating over all possible allocnos.
|
||||
Call set_conflicts_p to setup conflicts rather than adding
|
||||
them manually.
|
||||
* global.c: Comments updated.
|
||||
(CONFLICTP): Delete define.
|
||||
(regno_compare): New function. Add prototype.
|
||||
(global_alloc): Sort the allocno to regno mapping according to
|
||||
which basic blocks the regnos are referenced in. Modify the
|
||||
conflict bit matrix to a compressed triangular bitmatrix.
|
||||
Only allocate the conflict bit matrix and adjacency lists if
|
||||
we are actually going to allocate something.
|
||||
(expand_preferences): Use conflict_p. Update uses of allocnos_live.
|
||||
(prune_preferences): Use the FOR_EACH_CONFLICT macro to visit an
|
||||
allocno's neighbors rather than iterating over all possible allocnos.
|
||||
(mirror_conflicts): Removed function.
|
||||
(dump_conflicts): Iterate over regnos rather than allocnos so
|
||||
that all dump output will be sorted by regno number.
|
||||
Use the FOR_EACH_CONFLICT macro.
|
||||
* ra.h: Comments updated.
|
||||
(conflicts): Update prototype to HOST_WIDEST_FAST_INT.
|
||||
(partial_bitnum, max_bitnum, adjacency, adjacency_pool): Add prototypes.
|
||||
(ADJACENCY_VEC_LENGTH, FOR_EACH_CONFLICT): New defines.
|
||||
(adjacency_list_d, adjacency_iterator_d): New types.
|
||||
(add_neighbor, adjacency_iter_init, adjacency_iter_done,
|
||||
adjacency_iter_next, regno_basic_block): New static inline functions.
|
||||
(EXECUTE_IF_SET_IN_ALLOCNO_SET): Removed define.
|
||||
(conflict_p): Add function prototype.
|
||||
* sparseset.h, sparseset.c: New files.
|
||||
* Makefile.in (OBJS-common): Add sparseset.o.
|
||||
(sparseset.o): New rule.
|
||||
|
||||
2007-10-05 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR middle-end/33666
|
||||
|
@ -1126,6 +1126,7 @@ OBJS-common = \
|
||||
sdbout.o \
|
||||
see.o \
|
||||
simplify-rtx.o \
|
||||
sparseset.o \
|
||||
sreal.o \
|
||||
stack-ptr-mod.o \
|
||||
stmt.o \
|
||||
@ -1765,6 +1766,7 @@ sbitmap.o: sbitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
$(FLAGS_H) hard-reg-set.h $(BASIC_BLOCK_H) $(OBSTACK_H)
|
||||
ebitmap.o: ebitmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
|
||||
$(EBITMAP_H)
|
||||
sparseset.o: sparseset.c $(SYSTEM_H) sparseset.h
|
||||
|
||||
COLLECT2_OBJS = collect2.o tlink.o intl.o version.o
|
||||
COLLECT2_LIBS = @COLLECT2_LIBS@
|
||||
|
329
gcc/global.c
329
gcc/global.c
@ -63,26 +63,41 @@ along with GCC; see the file COPYING3. If not see
|
||||
reg numbers to allocnos and vice versa.
|
||||
max_allocno gets the number of allocnos in use.
|
||||
|
||||
2. Allocate a max_allocno by max_allocno conflict bit matrix and
|
||||
clear it. This is called "conflict".
|
||||
2. Allocate a max_allocno by max_allocno compressed triangular conflict
|
||||
bit matrix (a triangular bit matrix with portions removed for which we
|
||||
can guarantee there are no conflicts, example: two local pseudos that
|
||||
live in different basic blocks) and clear it. This is called "conflict".
|
||||
Note that for triangular bit matrices, there are two possible equations
|
||||
for computing the bit number for two allocnos: LOW and HIGH (LOW < HIGH):
|
||||
|
||||
1) BITNUM = f(HIGH) + LOW, where
|
||||
f(HIGH) = (HIGH * (HIGH - 1)) / 2
|
||||
|
||||
2) BITNUM = f(LOW) + HIGH, where
|
||||
f(LOW) = LOW * (max_allocno - LOW) + (LOW * (LOW - 1)) / 2 - LOW - 1
|
||||
|
||||
We use the second (and less common) equation as this gives us better
|
||||
cache locality for local allocnos that are live within the same basic
|
||||
block. Also note that f(HIGH) and f(LOW) can be precalculated for all
|
||||
values of HIGH and LOW, so all that is necessary to compute the bit
|
||||
number for two allocnos LOW and HIGH is a load followed by an addition.
|
||||
|
||||
Allocate a max_allocno by FIRST_PSEUDO_REGISTER conflict matrix for
|
||||
conflicts between allocnos and explicit hard register use (which
|
||||
includes use of pseudo-registers allocated by local_alloc). This
|
||||
is the hard_reg_conflicts inside each allocno.
|
||||
|
||||
3. For each basic block
|
||||
walk forward through the block, recording which
|
||||
pseudo-registers and which hardware registers are live.
|
||||
Build the conflict matrix between the pseudo-registers
|
||||
and another of pseudo-registers versus hardware registers.
|
||||
Also record the preferred hardware registers
|
||||
for each pseudo-register.
|
||||
3. For each basic block, walk backward through the block, recording
|
||||
which pseudo-registers and which hardware registers are live.
|
||||
Build the conflict matrix between the pseudo-registers and another of
|
||||
pseudo-registers versus hardware registers.
|
||||
|
||||
4. Sort a table of the allocnos into order of
|
||||
desirability of the variables.
|
||||
4. For each basic block, walk backward through the block, recording
|
||||
the preferred hardware registers for each pseudo-register.
|
||||
|
||||
5. Allocate the variables in that order; each if possible into
|
||||
5. Sort a table of the allocnos into order of desirability of the variables.
|
||||
|
||||
6. Allocate the variables in that order; each if possible into
|
||||
a preferred register, else into another register. */
|
||||
|
||||
/* A vector of the integers from 0 to max_allocno-1,
|
||||
@ -90,12 +105,6 @@ along with GCC; see the file COPYING3. If not see
|
||||
|
||||
static int *allocno_order;
|
||||
|
||||
/* Two macros to test or store 1 in an element of `conflicts'. */
|
||||
|
||||
#define CONFLICTP(I, J) \
|
||||
(conflicts[(I) * allocno_row_words + (unsigned) (J) / HOST_BITS_PER_WIDE_INT] \
|
||||
& ((HOST_WIDE_INT) 1 << ((unsigned) (J) % HOST_BITS_PER_WIDE_INT)))
|
||||
|
||||
/* Set of registers that global-alloc isn't supposed to use. */
|
||||
|
||||
static HARD_REG_SET no_global_alloc_regs;
|
||||
@ -206,8 +215,8 @@ compute_regs_asm_clobbered (char *regs_asm_clobbered)
|
||||
|
||||
static HARD_REG_SET eliminable_regset;
|
||||
|
||||
static int regno_compare (const void *, const void *);
|
||||
static int allocno_compare (const void *, const void *);
|
||||
static void mirror_conflicts (void);
|
||||
static void expand_preferences (void);
|
||||
static void prune_preferences (void);
|
||||
static void set_preferences (void);
|
||||
@ -315,6 +324,8 @@ global_alloc (void)
|
||||
{
|
||||
int retval;
|
||||
size_t i;
|
||||
int max_blk;
|
||||
int *num_allocnos_per_blk;
|
||||
|
||||
compute_regsets (&eliminable_regset, &no_global_alloc_regs);
|
||||
|
||||
@ -357,9 +368,8 @@ global_alloc (void)
|
||||
|
||||
reg_allocno = XNEWVEC (int, max_regno);
|
||||
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
reg_allocno[i] = -1;
|
||||
|
||||
/* Initially fill the reg_allocno array with regno's... */
|
||||
max_blk = 0;
|
||||
max_allocno = 0;
|
||||
for (i = FIRST_PSEUDO_REGISTER; i < (size_t) max_regno; i++)
|
||||
/* Note that reg_live_length[i] < 0 indicates a "constant" reg
|
||||
@ -371,28 +381,88 @@ global_alloc (void)
|
||||
&& (! current_function_has_nonlocal_label
|
||||
|| REG_N_CALLS_CROSSED (i) == 0))
|
||||
{
|
||||
reg_allocno[i] = max_allocno++;
|
||||
int blk = regno_basic_block (i);
|
||||
reg_allocno[max_allocno++] = i;
|
||||
if (blk > max_blk)
|
||||
max_blk = blk;
|
||||
gcc_assert (REG_LIVE_LENGTH (i));
|
||||
}
|
||||
else
|
||||
reg_allocno[i] = -1;
|
||||
|
||||
allocno = XCNEWVEC (struct allocno, max_allocno);
|
||||
partial_bitnum = XNEWVEC (int, max_allocno);
|
||||
num_allocnos_per_blk = XCNEWVEC (int, max_blk + 1);
|
||||
|
||||
for (i = FIRST_PSEUDO_REGISTER; i < (size_t) max_regno; i++)
|
||||
if (reg_allocno[i] >= 0)
|
||||
{
|
||||
int num = reg_allocno[i];
|
||||
allocno[num].reg = i;
|
||||
allocno[num].size = PSEUDO_REGNO_SIZE (i);
|
||||
allocno[num].calls_crossed += REG_N_CALLS_CROSSED (i);
|
||||
allocno[num].throwing_calls_crossed
|
||||
+= REG_N_THROWING_CALLS_CROSSED (i);
|
||||
allocno[num].n_refs += REG_N_REFS (i);
|
||||
allocno[num].freq += REG_FREQ (i);
|
||||
if (allocno[num].live_length < REG_LIVE_LENGTH (i))
|
||||
allocno[num].live_length = REG_LIVE_LENGTH (i);
|
||||
}
|
||||
/* ...so we can sort them in the order we want them to receive
|
||||
their allocnos. */
|
||||
qsort (reg_allocno, max_allocno, sizeof (int), regno_compare);
|
||||
|
||||
for (i = 0; i < (size_t) max_allocno; i++)
|
||||
{
|
||||
int regno = reg_allocno[i];
|
||||
int blk = regno_basic_block (regno);
|
||||
num_allocnos_per_blk[blk]++;
|
||||
allocno[i].reg = regno;
|
||||
allocno[i].size = PSEUDO_REGNO_SIZE (regno);
|
||||
allocno[i].calls_crossed += REG_N_CALLS_CROSSED (regno);
|
||||
allocno[i].throwing_calls_crossed
|
||||
+= REG_N_THROWING_CALLS_CROSSED (regno);
|
||||
allocno[i].n_refs += REG_N_REFS (regno);
|
||||
allocno[i].freq += REG_FREQ (regno);
|
||||
if (allocno[i].live_length < REG_LIVE_LENGTH (regno))
|
||||
allocno[i].live_length = REG_LIVE_LENGTH (regno);
|
||||
}
|
||||
|
||||
/* The "global" block must contain all allocnos. */
|
||||
num_allocnos_per_blk[0] = max_allocno;
|
||||
|
||||
/* Now reinitialize the reg_allocno array in terms of the
|
||||
optimized regno to allocno mapping we created above. */
|
||||
for (i = 0; i < (size_t) max_regno; i++)
|
||||
reg_allocno[i] = -1;
|
||||
|
||||
max_bitnum = 0;
|
||||
for (i = 0; i < (size_t) max_allocno; i++)
|
||||
{
|
||||
int regno = allocno[i].reg;
|
||||
int blk = regno_basic_block (regno);
|
||||
int row_size = --num_allocnos_per_blk[blk];
|
||||
reg_allocno[regno] = (int) i;
|
||||
partial_bitnum[i] = (row_size > 0) ? max_bitnum - ((int) i + 1) : -1;
|
||||
max_bitnum += row_size;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (max_bitnum <= ((max_allocno * (max_allocno - 1)) / 2));
|
||||
#endif
|
||||
|
||||
if (dump_file)
|
||||
{
|
||||
int num_bits, num_bytes, actual_bytes;
|
||||
|
||||
fprintf (dump_file, "## max_blk: %d\n", max_blk);
|
||||
fprintf (dump_file, "## max_regno: %d\n", max_regno);
|
||||
fprintf (dump_file, "## max_allocno: %d\n", max_allocno);
|
||||
|
||||
num_bits = max_bitnum;
|
||||
num_bytes = CEIL (num_bits, 8);
|
||||
actual_bytes = num_bytes;
|
||||
fprintf (dump_file, "## Compressed triangular bitmatrix size: ");
|
||||
fprintf (dump_file, "%d bits, %d bytes\n", num_bits, num_bytes);
|
||||
|
||||
num_bits = (max_allocno * (max_allocno - 1)) / 2;
|
||||
num_bytes = CEIL (num_bits, 8);
|
||||
fprintf (dump_file, "## Standard triangular bitmatrix size: ");
|
||||
fprintf (dump_file, "%d bits, %d bytes [%.2f%%]\n",
|
||||
num_bits, num_bytes,
|
||||
100.0 * ((double) actual_bytes / (double) num_bytes));
|
||||
|
||||
num_bits = max_allocno * max_allocno;
|
||||
num_bytes = CEIL (num_bits, 8);
|
||||
fprintf (dump_file, "## Square bitmatrix size: ");
|
||||
fprintf (dump_file, "%d bits, %d bytes [%.2f%%]\n",
|
||||
num_bits, num_bytes,
|
||||
100.0 * ((double) actual_bytes / (double) num_bytes));
|
||||
}
|
||||
|
||||
/* Calculate amount of usage of each hard reg by pseudos
|
||||
allocated by local-alloc. This is to see if we want to
|
||||
@ -433,18 +503,26 @@ global_alloc (void)
|
||||
fprintf (dump_file, " %d", (int)i);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
allocno_row_words = (max_allocno + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT;
|
||||
|
||||
/* We used to use alloca here, but the size of what it would try to
|
||||
allocate would occasionally cause it to exceed the stack limit and
|
||||
cause unpredictable core dumps. Some examples were > 2Mb in size. */
|
||||
conflicts = XCNEWVEC (HOST_WIDE_INT, max_allocno * allocno_row_words);
|
||||
conflicts = NULL;
|
||||
adjacency = NULL;
|
||||
adjacency_pool = NULL;
|
||||
|
||||
/* If there is work to be done (at least one reg to allocate),
|
||||
perform global conflict analysis and allocate the regs. */
|
||||
|
||||
if (max_allocno > 0)
|
||||
{
|
||||
/* We used to use alloca here, but the size of what it would try to
|
||||
allocate would occasionally cause it to exceed the stack limit and
|
||||
cause unpredictable core dumps. Some examples were > 2Mb in size. */
|
||||
conflicts = XCNEWVEC (HOST_WIDEST_FAST_INT,
|
||||
CEIL(max_bitnum, HOST_BITS_PER_WIDEST_FAST_INT));
|
||||
|
||||
adjacency = XCNEWVEC (adjacency_t *, max_allocno);
|
||||
adjacency_pool = create_alloc_pool ("global_alloc adjacency list pool",
|
||||
sizeof (adjacency_t), 1024);
|
||||
|
||||
/* Scan all the insns and compute the conflicts among allocnos
|
||||
and between allocnos and hard regs. */
|
||||
|
||||
@ -460,8 +538,6 @@ global_alloc (void)
|
||||
global_conflicts. */
|
||||
df_set_flags (DF_NO_INSN_RESCAN);
|
||||
|
||||
mirror_conflicts ();
|
||||
|
||||
/* Eliminate conflicts between pseudos and eliminable registers. If
|
||||
the register is not eliminated, the pseudo won't really be able to
|
||||
live in the eliminable register, so the conflict doesn't matter.
|
||||
@ -536,6 +612,7 @@ global_alloc (void)
|
||||
}
|
||||
|
||||
free (allocno_order);
|
||||
free (conflicts);
|
||||
}
|
||||
|
||||
/* Do the reloads now while the allocno data still exists, so that we can
|
||||
@ -552,12 +629,44 @@ global_alloc (void)
|
||||
|
||||
/* Clean up. */
|
||||
free (reg_allocno);
|
||||
free (num_allocnos_per_blk);
|
||||
free (partial_bitnum);
|
||||
free (allocno);
|
||||
free (conflicts);
|
||||
if (adjacency != NULL)
|
||||
{
|
||||
free_alloc_pool (adjacency_pool);
|
||||
free (adjacency);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Sort predicate for ordering the regnos. We want the regno to allocno
|
||||
mapping to have the property that all "global" regnos (ie, regnos that
|
||||
are referenced in more than one basic block) have smaller allocno values
|
||||
than "local" regnos (ie, regnos referenced in only one basic block).
|
||||
In addition, for two basic blocks "i" and "j" with i < j, all regnos
|
||||
local to basic block i should have smaller allocno values than regnos
|
||||
local to basic block j.
|
||||
Returns -1 (1) if *v1p should be allocated before (after) *v2p. */
|
||||
|
||||
static int
|
||||
regno_compare (const void *v1p, const void *v2p)
|
||||
{
|
||||
int regno1 = *(const int *)v1p;
|
||||
int regno2 = *(const int *)v2p;
|
||||
int blk1 = REG_BASIC_BLOCK (regno1);
|
||||
int blk2 = REG_BASIC_BLOCK (regno2);
|
||||
|
||||
/* Prefer lower numbered basic blocks. Note that global and unknown
|
||||
blocks have negative values, giving them high precedence. */
|
||||
if (blk1 - blk2)
|
||||
return blk1 - blk2;
|
||||
|
||||
/* If both regs are referenced from the same block, sort by regno. */
|
||||
return regno1 - regno2;
|
||||
}
|
||||
|
||||
/* Sort predicate for ordering the allocnos.
|
||||
Returns -1 (1) if *v1 should be allocated before (after) *v2. */
|
||||
|
||||
@ -609,8 +718,8 @@ expand_preferences (void)
|
||||
if (REG_NOTE_KIND (link) == REG_DEAD
|
||||
&& REG_P (XEXP (link, 0))
|
||||
&& reg_allocno[REGNO (XEXP (link, 0))] >= 0
|
||||
&& ! CONFLICTP (reg_allocno[REGNO (SET_DEST (set))],
|
||||
reg_allocno[REGNO (XEXP (link, 0))]))
|
||||
&& ! conflict_p (reg_allocno[REGNO (SET_DEST (set))],
|
||||
reg_allocno[REGNO (XEXP (link, 0))]))
|
||||
{
|
||||
int a1 = reg_allocno[REGNO (SET_DEST (set))];
|
||||
int a2 = reg_allocno[REGNO (XEXP (link, 0))];
|
||||
@ -828,14 +937,14 @@ prune_preferences (void)
|
||||
these registers). */
|
||||
HARD_REG_SET temp, temp2;
|
||||
int allocno2;
|
||||
adjacency_iter ai;
|
||||
|
||||
num = allocno_order[i];
|
||||
|
||||
CLEAR_HARD_REG_SET (temp);
|
||||
CLEAR_HARD_REG_SET (temp2);
|
||||
|
||||
EXECUTE_IF_SET_IN_ALLOCNO_SET (conflicts + num * allocno_row_words,
|
||||
allocno2,
|
||||
FOR_EACH_CONFLICT (num, allocno2, ai)
|
||||
{
|
||||
if (allocno_to_order[allocno2] > i)
|
||||
{
|
||||
@ -846,7 +955,7 @@ prune_preferences (void)
|
||||
IOR_HARD_REG_SET (temp2,
|
||||
allocno[allocno2].hard_reg_full_preferences);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AND_COMPL_HARD_REG_SET (temp, allocno[num].hard_reg_full_preferences);
|
||||
IOR_HARD_REG_SET (temp, temp2);
|
||||
@ -1167,6 +1276,7 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
|
||||
{
|
||||
int lim, j;
|
||||
HARD_REG_SET this_reg;
|
||||
adjacency_iter ai;
|
||||
|
||||
/* Yes. Record it as the hard register of this pseudo-reg. */
|
||||
reg_renumber[allocno[num].reg] = best_reg;
|
||||
@ -1184,11 +1294,10 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
|
||||
}
|
||||
/* For each other pseudo-reg conflicting with this one,
|
||||
mark it as conflicting with the hard regs this one occupies. */
|
||||
lim = num;
|
||||
EXECUTE_IF_SET_IN_ALLOCNO_SET (conflicts + lim * allocno_row_words, j,
|
||||
FOR_EACH_CONFLICT (num, j, ai)
|
||||
{
|
||||
IOR_HARD_REG_SET (allocno[j].hard_reg_conflicts, this_reg);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1224,38 +1333,6 @@ retry_global_alloc (int regno, HARD_REG_SET forbidden_regs)
|
||||
}
|
||||
}
|
||||
|
||||
/* If CONFLICTP (i, j) is true, make sure CONFLICTP (j, i) is also true. */
|
||||
static void
|
||||
mirror_conflicts (void)
|
||||
{
|
||||
int i, j;
|
||||
int rw = allocno_row_words;
|
||||
int rwb = rw * HOST_BITS_PER_WIDE_INT;
|
||||
HOST_WIDE_INT *p = conflicts;
|
||||
HOST_WIDE_INT *q0 = conflicts, *q1, *q2;
|
||||
unsigned HOST_WIDE_INT mask;
|
||||
|
||||
for (i = max_allocno - 1, mask = 1; i >= 0; i--, mask <<= 1)
|
||||
{
|
||||
if (! mask)
|
||||
{
|
||||
mask = 1;
|
||||
q0++;
|
||||
}
|
||||
for (j = allocno_row_words - 1, q1 = q0; j >= 0; j--, q1 += rwb)
|
||||
{
|
||||
unsigned HOST_WIDE_INT word;
|
||||
|
||||
for (word = (unsigned HOST_WIDE_INT) *p++, q2 = q1; word;
|
||||
word >>= 1, q2 += rw)
|
||||
{
|
||||
if (word & 1)
|
||||
*q2 |= mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Indicate that hard register number FROM was eliminated and replaced with
|
||||
an offset from hard register number TO. The status of hard registers live
|
||||
at the start of a basic block is updated by replacing a use of FROM with
|
||||
@ -1519,6 +1596,7 @@ static void
|
||||
dump_conflicts (FILE *file)
|
||||
{
|
||||
int i;
|
||||
int regno;
|
||||
int has_preferences;
|
||||
int nregs;
|
||||
nregs = 0;
|
||||
@ -1529,46 +1607,51 @@ dump_conflicts (FILE *file)
|
||||
nregs++;
|
||||
}
|
||||
fprintf (file, ";; %d regs to allocate:", nregs);
|
||||
for (i = 0; i < max_allocno; i++)
|
||||
{
|
||||
int j;
|
||||
if (reg_renumber[allocno[allocno_order[i]].reg] >= 0)
|
||||
continue;
|
||||
fprintf (file, " %d", allocno[allocno_order[i]].reg);
|
||||
for (j = 0; j < max_regno; j++)
|
||||
if (reg_allocno[j] == allocno_order[i]
|
||||
&& j != allocno[allocno_order[i]].reg)
|
||||
fprintf (file, "+%d", j);
|
||||
if (allocno[allocno_order[i]].size != 1)
|
||||
fprintf (file, " (%d)", allocno[allocno_order[i]].size);
|
||||
}
|
||||
for (regno = 0; regno < max_regno; regno++)
|
||||
if ((i = reg_allocno[regno]) >= 0)
|
||||
{
|
||||
int j;
|
||||
if (reg_renumber[allocno[allocno_order[i]].reg] >= 0)
|
||||
continue;
|
||||
fprintf (file, " %d", allocno[allocno_order[i]].reg);
|
||||
for (j = 0; j < max_regno; j++)
|
||||
if (reg_allocno[j] == allocno_order[i]
|
||||
&& j != allocno[allocno_order[i]].reg)
|
||||
fprintf (file, "+%d", j);
|
||||
if (allocno[allocno_order[i]].size != 1)
|
||||
fprintf (file, " (%d)", allocno[allocno_order[i]].size);
|
||||
}
|
||||
fprintf (file, "\n");
|
||||
|
||||
for (i = 0; i < max_allocno; i++)
|
||||
{
|
||||
int j;
|
||||
fprintf (file, ";; %d conflicts:", allocno[i].reg);
|
||||
for (j = 0; j < max_allocno; j++)
|
||||
if (CONFLICTP (j, i))
|
||||
fprintf (file, " %d", allocno[j].reg);
|
||||
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
|
||||
if (TEST_HARD_REG_BIT (allocno[i].hard_reg_conflicts, j) && ! fixed_regs[j])
|
||||
fprintf (file, " %d", j);
|
||||
fprintf (file, "\n");
|
||||
for (regno = 0; regno < max_regno; regno++)
|
||||
if ((i = reg_allocno[regno]) >= 0)
|
||||
{
|
||||
int j;
|
||||
adjacency_iter ai;
|
||||
fprintf (file, ";; %d conflicts:", allocno[i].reg);
|
||||
FOR_EACH_CONFLICT (i, j, ai)
|
||||
{
|
||||
fprintf (file, " %d", allocno[j].reg);
|
||||
}
|
||||
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
|
||||
if (TEST_HARD_REG_BIT (allocno[i].hard_reg_conflicts, j)
|
||||
&& !fixed_regs[j])
|
||||
fprintf (file, " %d", j);
|
||||
fprintf (file, "\n");
|
||||
|
||||
has_preferences = 0;
|
||||
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
|
||||
if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
|
||||
has_preferences = 1;
|
||||
has_preferences = 0;
|
||||
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
|
||||
if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
|
||||
has_preferences = 1;
|
||||
|
||||
if (! has_preferences)
|
||||
continue;
|
||||
fprintf (file, ";; %d preferences:", allocno[i].reg);
|
||||
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
|
||||
if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
|
||||
fprintf (file, " %d", j);
|
||||
fprintf (file, "\n");
|
||||
}
|
||||
if (!has_preferences)
|
||||
continue;
|
||||
fprintf (file, ";; %d preferences:", allocno[i].reg);
|
||||
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
|
||||
if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
|
||||
fprintf (file, " %d", j);
|
||||
fprintf (file, "\n");
|
||||
}
|
||||
fprintf (file, "\n");
|
||||
}
|
||||
|
||||
|
@ -41,63 +41,174 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "vecprim.h"
|
||||
#include "ra.h"
|
||||
#include "sbitmap.h"
|
||||
|
||||
/* Test, set or clear bit number I in allocnos_live,
|
||||
a bit vector indexed by allocno. */
|
||||
|
||||
#define SET_ALLOCNO_LIVE(A, I) \
|
||||
((A)[(unsigned) (I) / HOST_BITS_PER_WIDE_INT] \
|
||||
|= ((HOST_WIDE_INT) 1 << ((unsigned) (I) % HOST_BITS_PER_WIDE_INT)))
|
||||
|
||||
#define CLEAR_ALLOCNO_LIVE(A, I) \
|
||||
((A)[(unsigned) (I) / HOST_BITS_PER_WIDE_INT] \
|
||||
&= ~((HOST_WIDE_INT) 1 << ((unsigned) (I) % HOST_BITS_PER_WIDE_INT)))
|
||||
|
||||
#define GET_ALLOCNO_LIVE(A, I) \
|
||||
((A)[(unsigned) (I) / HOST_BITS_PER_WIDE_INT] \
|
||||
& ((HOST_WIDE_INT) 1 << ((unsigned) (I) % HOST_BITS_PER_WIDE_INT)))
|
||||
#include "sparseset.h"
|
||||
|
||||
/* Externs defined in regs.h. */
|
||||
|
||||
int max_allocno;
|
||||
struct allocno *allocno;
|
||||
HOST_WIDE_INT *conflicts;
|
||||
int allocno_row_words;
|
||||
HOST_WIDEST_FAST_INT *conflicts;
|
||||
int *reg_allocno;
|
||||
int *partial_bitnum;
|
||||
int max_bitnum;
|
||||
alloc_pool adjacency_pool;
|
||||
adjacency_t **adjacency;
|
||||
|
||||
typedef struct df_ref * df_ref_t;
|
||||
DEF_VEC_P(df_ref_t);
|
||||
DEF_VEC_ALLOC_P(df_ref_t,heap);
|
||||
|
||||
/* Macros to determine the bit number within the triangular bit matrix for
|
||||
the two allocnos Low and HIGH, with LOW strictly less than HIGH. */
|
||||
|
||||
#define CONFLICT_BITNUM(I, J) \
|
||||
(((I) < (J)) ? (partial_bitnum[I] + (J)) : (partial_bitnum[J] + (I)))
|
||||
|
||||
#define CONFLICT_BITNUM_FAST(I, I_PARTIAL_BITNUM, J) \
|
||||
(((I) < (J)) ? ((I_PARTIAL_BITNUM) + (J)) : (partial_bitnum[J] + (I)))
|
||||
|
||||
bool
|
||||
conflict_p (int allocno1, int allocno2)
|
||||
{
|
||||
int bitnum;
|
||||
HOST_WIDEST_FAST_INT word, mask;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
int blk1, blk2;
|
||||
|
||||
gcc_assert (allocno1 >= 0 && allocno1 < max_allocno);
|
||||
gcc_assert (allocno2 >= 0 && allocno2 < max_allocno);
|
||||
|
||||
blk1 = regno_basic_block (allocno[allocno1].reg);
|
||||
blk2 = regno_basic_block (allocno[allocno2].reg);
|
||||
gcc_assert (blk1 == 0 || blk2 == 0 || blk1 == blk2);
|
||||
#endif
|
||||
|
||||
if (allocno1 == allocno2)
|
||||
/* By definition, an allocno does not conflict with itself. */
|
||||
return 0;
|
||||
|
||||
bitnum = CONFLICT_BITNUM (allocno1, allocno2);
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (bitnum >= 0 && bitnum < max_bitnum);
|
||||
#endif
|
||||
|
||||
word = conflicts[bitnum / HOST_BITS_PER_WIDEST_FAST_INT];
|
||||
mask = (HOST_WIDEST_FAST_INT) 1 << (bitnum % HOST_BITS_PER_WIDEST_FAST_INT);
|
||||
return (word & mask) != 0;
|
||||
}
|
||||
|
||||
/* Add conflict edges between ALLOCNO1 and ALLOCNO2. */
|
||||
|
||||
static void
|
||||
set_conflict (int allocno1, int allocno2)
|
||||
{
|
||||
int bitnum, index;
|
||||
HOST_WIDEST_FAST_INT word, mask;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
int blk1, blk2;
|
||||
|
||||
gcc_assert (allocno1 >= 0 && allocno1 < max_allocno);
|
||||
gcc_assert (allocno2 >= 0 && allocno2 < max_allocno);
|
||||
|
||||
blk1 = regno_basic_block (allocno[allocno1].reg);
|
||||
blk2 = regno_basic_block (allocno[allocno2].reg);
|
||||
gcc_assert (blk1 == 0 || blk2 == 0 || blk1 == blk2);
|
||||
#endif
|
||||
|
||||
/* By definition, an allocno does not conflict with itself. */
|
||||
if (allocno1 == allocno2)
|
||||
return;
|
||||
|
||||
bitnum = CONFLICT_BITNUM (allocno1, allocno2);
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (bitnum >= 0 && bitnum < max_bitnum);
|
||||
#endif
|
||||
|
||||
index = bitnum / HOST_BITS_PER_WIDEST_FAST_INT;
|
||||
word = conflicts[index];
|
||||
mask = (HOST_WIDEST_FAST_INT) 1 << (bitnum % HOST_BITS_PER_WIDEST_FAST_INT);
|
||||
|
||||
if ((word & mask) == 0)
|
||||
{
|
||||
conflicts[index] = word | mask;
|
||||
add_neighbor (allocno1, allocno2);
|
||||
add_neighbor (allocno2, allocno1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add conflict edges between ALLOCNO1 and all allocnos currently live. */
|
||||
|
||||
static void
|
||||
set_conflicts (int allocno1, sparseset live)
|
||||
{
|
||||
int i;
|
||||
int bitnum, index;
|
||||
HOST_WIDEST_FAST_INT word, mask;
|
||||
int partial_bitnum_allocno1;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (allocno1 >= 0 && allocno1 < max_allocno);
|
||||
#endif
|
||||
|
||||
partial_bitnum_allocno1 = partial_bitnum[allocno1];
|
||||
|
||||
EXECUTE_IF_SET_IN_SPARSESET (live, i)
|
||||
{
|
||||
/* By definition, an allocno does not conflict with itself. */
|
||||
if (allocno1 == i)
|
||||
continue;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (i >= 0 && i < max_allocno);
|
||||
#endif
|
||||
|
||||
bitnum = CONFLICT_BITNUM_FAST (allocno1, partial_bitnum_allocno1, i);
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (bitnum >= 0 && bitnum < max_bitnum);
|
||||
#endif
|
||||
|
||||
index = bitnum / HOST_BITS_PER_WIDEST_FAST_INT;
|
||||
word = conflicts[index];
|
||||
mask = (HOST_WIDEST_FAST_INT) 1 << (bitnum % HOST_BITS_PER_WIDEST_FAST_INT);
|
||||
|
||||
if ((word & mask) == 0)
|
||||
{
|
||||
conflicts[index] = word | mask;
|
||||
add_neighbor (allocno1, i);
|
||||
add_neighbor (i, allocno1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Add a conflict between R1 and R2. */
|
||||
|
||||
static void
|
||||
record_one_conflict_between_regnos (enum machine_mode mode1, int r1,
|
||||
enum machine_mode mode2, int r2)
|
||||
{
|
||||
int allocno1 = reg_allocno[r1];
|
||||
int allocno2 = reg_allocno[r2];
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " rocbr adding %d<=>%d\n", r1, r2);
|
||||
if (reg_allocno[r1] >= 0 && reg_allocno[r2] >= 0)
|
||||
{
|
||||
int tr1 = reg_allocno[r1];
|
||||
int tr2 = reg_allocno[r2];
|
||||
int ialloc_prod = tr1 * allocno_row_words;
|
||||
|
||||
SET_ALLOCNO_LIVE ((&conflicts[ialloc_prod]), tr2);
|
||||
}
|
||||
else if (reg_allocno[r1] >= 0)
|
||||
if (allocno1 >= 0 && allocno2 >= 0)
|
||||
set_conflict (allocno1, allocno2);
|
||||
else if (allocno1 >= 0)
|
||||
{
|
||||
int tr1 = reg_allocno[r1];
|
||||
|
||||
if (r2 < FIRST_PSEUDO_REGISTER)
|
||||
add_to_hard_reg_set (&allocno[tr1].hard_reg_conflicts, mode2, r2);
|
||||
add_to_hard_reg_set (&allocno[allocno1].hard_reg_conflicts, mode2, r2);
|
||||
}
|
||||
else if (reg_allocno[r2] >= 0)
|
||||
else if (allocno2 >= 0)
|
||||
{
|
||||
int tr2 = reg_allocno[r2];
|
||||
|
||||
if (r1 < FIRST_PSEUDO_REGISTER)
|
||||
add_to_hard_reg_set (&allocno[tr2].hard_reg_conflicts, mode1, r1);
|
||||
add_to_hard_reg_set (&allocno[allocno2].hard_reg_conflicts, mode1, r1);
|
||||
}
|
||||
|
||||
/* Now, recursively handle the reg_renumber cases. */
|
||||
@ -115,7 +226,7 @@ record_one_conflict_between_regnos (enum machine_mode mode1, int r1,
|
||||
before calling here. */
|
||||
|
||||
static void
|
||||
record_one_conflict (HOST_WIDE_INT *allocnos_live,
|
||||
record_one_conflict (sparseset allocnos_live,
|
||||
HARD_REG_SET *hard_regs_live, int regno)
|
||||
{
|
||||
int i;
|
||||
@ -123,18 +234,17 @@ record_one_conflict (HOST_WIDE_INT *allocnos_live,
|
||||
if (regno < FIRST_PSEUDO_REGISTER)
|
||||
/* When a hard register becomes live, record conflicts with live
|
||||
pseudo regs. */
|
||||
EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, i,
|
||||
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
|
||||
{
|
||||
SET_HARD_REG_BIT (allocno[i].hard_reg_conflicts, regno);
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " roc adding %d<=>%d\n", allocno[i].reg, regno);
|
||||
});
|
||||
}
|
||||
else
|
||||
/* When a pseudo-register becomes live, record conflicts first
|
||||
with hard regs, then with other pseudo regs. */
|
||||
{
|
||||
int ialloc = reg_allocno[regno];
|
||||
int ialloc_prod = ialloc * allocno_row_words;
|
||||
|
||||
if (dump_file)
|
||||
{
|
||||
@ -144,18 +254,16 @@ record_one_conflict (HOST_WIDE_INT *allocnos_live,
|
||||
&& !TEST_HARD_REG_BIT (allocno[ialloc].hard_reg_conflicts, i))
|
||||
fprintf (dump_file, "%d ", i);
|
||||
|
||||
EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, i,
|
||||
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
|
||||
{
|
||||
if (!GET_ALLOCNO_LIVE (&conflicts[ialloc_prod], i))
|
||||
if (!conflict_p (ialloc, i))
|
||||
fprintf (dump_file, "%d ", allocno[i].reg);
|
||||
});
|
||||
}
|
||||
fprintf (dump_file, ")\n");
|
||||
}
|
||||
|
||||
IOR_HARD_REG_SET (allocno[ialloc].hard_reg_conflicts, *hard_regs_live);
|
||||
|
||||
for (i = allocno_row_words - 1; i >= 0; i--)
|
||||
conflicts[ialloc_prod + i] |= allocnos_live[i];
|
||||
set_conflicts (ialloc, allocnos_live);
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +276,7 @@ record_one_conflict (HOST_WIDE_INT *allocnos_live,
|
||||
nothing. */
|
||||
|
||||
static void
|
||||
mark_reg_store (HOST_WIDE_INT *allocnos_live,
|
||||
mark_reg_store (sparseset allocnos_live,
|
||||
HARD_REG_SET *hard_regs_live,
|
||||
struct df_ref *ref)
|
||||
{
|
||||
@ -340,7 +448,7 @@ ra_init_live_subregs (bool init_value,
|
||||
set not live even if REG is a subreg. */
|
||||
|
||||
inline static void
|
||||
clear_reg_in_live (HOST_WIDE_INT *allocnos_live,
|
||||
clear_reg_in_live (sparseset allocnos_live,
|
||||
sbitmap *live_subregs,
|
||||
int *live_subregs_used,
|
||||
HARD_REG_SET *hard_regs_live,
|
||||
@ -359,7 +467,7 @@ clear_reg_in_live (HOST_WIDE_INT *allocnos_live,
|
||||
unsigned int start = SUBREG_BYTE (reg);
|
||||
unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
|
||||
|
||||
ra_init_live_subregs (GET_ALLOCNO_LIVE (allocnos_live, allocnum) != 0,
|
||||
ra_init_live_subregs (sparseset_bit_p (allocnos_live, allocnum),
|
||||
live_subregs, live_subregs_used, allocnum, reg);
|
||||
|
||||
/* Ignore the paradoxical bits. */
|
||||
@ -375,19 +483,19 @@ clear_reg_in_live (HOST_WIDE_INT *allocnos_live,
|
||||
if (sbitmap_empty_p (live_subregs[allocnum]))
|
||||
{
|
||||
live_subregs_used[allocnum] = 0;
|
||||
CLEAR_ALLOCNO_LIVE (allocnos_live, allocnum);
|
||||
sparseset_clear_bit (allocnos_live, allocnum);
|
||||
}
|
||||
else
|
||||
/* Set the allocnos live here because that bit has to be
|
||||
true to get us to look at the live_subregs fields. */
|
||||
SET_ALLOCNO_LIVE (allocnos_live, allocnum);
|
||||
sparseset_set_bit (allocnos_live, allocnum);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Resetting the live_subregs_used is effectively saying do not use the
|
||||
subregs because we are writing the whole pseudo. */
|
||||
live_subregs_used[allocnum] = 0;
|
||||
CLEAR_ALLOCNO_LIVE (allocnos_live, allocnum);
|
||||
sparseset_clear_bit (allocnos_live, allocnum);
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,7 +531,7 @@ clear_reg_in_live (HOST_WIDE_INT *allocnos_live,
|
||||
set live even if REG is a subreg. */
|
||||
|
||||
inline static void
|
||||
set_reg_in_live (HOST_WIDE_INT *allocnos_live,
|
||||
set_reg_in_live (sparseset allocnos_live,
|
||||
sbitmap *live_subregs,
|
||||
int *live_subregs_used,
|
||||
HARD_REG_SET *hard_regs_live,
|
||||
@ -441,7 +549,7 @@ set_reg_in_live (HOST_WIDE_INT *allocnos_live,
|
||||
unsigned int start = SUBREG_BYTE (reg);
|
||||
unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
|
||||
|
||||
ra_init_live_subregs (GET_ALLOCNO_LIVE (allocnos_live, allocnum) != 0,
|
||||
ra_init_live_subregs (sparseset_bit_p (allocnos_live, allocnum),
|
||||
live_subregs, live_subregs_used, allocnum, reg);
|
||||
|
||||
/* Ignore the paradoxical bits. */
|
||||
@ -459,7 +567,7 @@ set_reg_in_live (HOST_WIDE_INT *allocnos_live,
|
||||
subregs because we are writing the whole pseudo. */
|
||||
live_subregs_used[allocnum] = 0;
|
||||
|
||||
SET_ALLOCNO_LIVE (allocnos_live, allocnum);
|
||||
sparseset_set_bit (allocnos_live, allocnum);
|
||||
}
|
||||
|
||||
if (regno >= FIRST_PSEUDO_REGISTER)
|
||||
@ -630,7 +738,7 @@ global_conflicts (void)
|
||||
|
||||
HARD_REG_SET hard_regs_live;
|
||||
HARD_REG_SET renumbers_live;
|
||||
HOST_WIDE_INT *allocnos_live;
|
||||
sparseset allocnos_live;
|
||||
bitmap live = BITMAP_ALLOC (NULL);
|
||||
VEC (df_ref_t, heap) *clobbers = NULL;
|
||||
VEC (df_ref_t, heap) *dying_regs = NULL;
|
||||
@ -654,7 +762,7 @@ global_conflicts (void)
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
|
||||
allocnos_live = XNEWVEC (HOST_WIDE_INT, allocno_row_words);
|
||||
allocnos_live = sparseset_alloc (max_allocno);
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
@ -663,7 +771,7 @@ global_conflicts (void)
|
||||
bitmap_copy (live, DF_LIVE_OUT (bb));
|
||||
df_simulate_artificial_refs_at_end (bb, live);
|
||||
|
||||
memset (allocnos_live, 0, allocno_row_words * sizeof (HOST_WIDE_INT));
|
||||
sparseset_clear (allocnos_live);
|
||||
memset (live_subregs_used, 0, max_allocno * sizeof (int));
|
||||
CLEAR_HARD_REG_SET (hard_regs_live);
|
||||
CLEAR_HARD_REG_SET (renumbers_live);
|
||||
@ -720,11 +828,11 @@ global_conflicts (void)
|
||||
fprintf (dump_file, "%d ", i);
|
||||
|
||||
fprintf (dump_file, "] pseudos [");
|
||||
EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, i,
|
||||
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
|
||||
{
|
||||
dump_ref (dump_file, " ", "", regno_reg_rtx[allocno[i].reg],
|
||||
allocno[i].reg, live_subregs, live_subregs_used);
|
||||
});
|
||||
}
|
||||
fprintf (dump_file, "]\n");
|
||||
}
|
||||
|
||||
@ -803,7 +911,7 @@ global_conflicts (void)
|
||||
cannot not want to kill the renumbers from the other
|
||||
pseudos. */
|
||||
CLEAR_HARD_REG_SET (renumbers_live);
|
||||
EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, i,
|
||||
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
|
||||
{
|
||||
unsigned int regno = allocno[i].reg;
|
||||
int renumber = reg_renumber[regno];
|
||||
@ -811,7 +919,7 @@ global_conflicts (void)
|
||||
if (renumber >= 0 && renumber < FIRST_PSEUDO_REGISTER)
|
||||
set_renumbers_live (&renumbers_live, live_subregs, live_subregs_used,
|
||||
i, renumber);
|
||||
});
|
||||
}
|
||||
|
||||
/* Add the uses to the live sets. Keep track of the regs
|
||||
that are dying inside the insn, this set will be useful
|
||||
@ -850,7 +958,7 @@ global_conflicts (void)
|
||||
unsigned int start = SUBREG_BYTE (reg);
|
||||
unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
|
||||
|
||||
ra_init_live_subregs (GET_ALLOCNO_LIVE (allocnos_live, allocnum) != 0,
|
||||
ra_init_live_subregs (sparseset_bit_p (allocnos_live, allocnum),
|
||||
live_subregs, live_subregs_used, allocnum, reg);
|
||||
|
||||
/* Ignore the paradoxical bits. */
|
||||
@ -870,13 +978,13 @@ global_conflicts (void)
|
||||
start++;
|
||||
}
|
||||
|
||||
SET_ALLOCNO_LIVE (allocnos_live, allocnum);
|
||||
sparseset_set_bit (allocnos_live, allocnum);
|
||||
if (renumber >= 0 && renumber < FIRST_PSEUDO_REGISTER)
|
||||
set_renumbers_live (&renumbers_live, live_subregs, live_subregs_used,
|
||||
allocnum, renumber);
|
||||
}
|
||||
|
||||
else if (GET_ALLOCNO_LIVE (allocnos_live, allocnum) == 0)
|
||||
else if (!sparseset_bit_p (allocnos_live, allocnum))
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " dying pseudo\n");
|
||||
@ -885,7 +993,7 @@ global_conflicts (void)
|
||||
effectively saying do not use the subregs
|
||||
because we are reading the whole pseudo. */
|
||||
live_subregs_used[allocnum] = 0;
|
||||
SET_ALLOCNO_LIVE (allocnos_live, allocnum);
|
||||
sparseset_set_bit (allocnos_live, allocnum);
|
||||
if (renumber >= 0 && renumber < FIRST_PSEUDO_REGISTER)
|
||||
set_renumbers_live (&renumbers_live, live_subregs, live_subregs_used,
|
||||
allocnum, renumber);
|
||||
@ -1087,10 +1195,10 @@ global_conflicts (void)
|
||||
because caller-save, fixup_abnormal_edges and possibly the table
|
||||
driven EH machinery are not quite ready to handle such regs live
|
||||
across such edges. */
|
||||
EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, i,
|
||||
{
|
||||
allocno[i].no_stack_reg = 1;
|
||||
});
|
||||
EXECUTE_IF_SET_IN_SPARSESET (allocnos_live, i)
|
||||
{
|
||||
allocno[i].no_stack_reg = 1;
|
||||
}
|
||||
|
||||
for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
|
||||
record_one_conflict (allocnos_live, &hard_regs_live, i);
|
||||
|
152
gcc/ra.h
152
gcc/ra.h
@ -85,49 +85,139 @@ extern struct allocno *allocno;
|
||||
|
||||
extern int max_allocno;
|
||||
|
||||
/* max_allocno by max_allocno array of bits, recording whether two
|
||||
allocno's conflict (can't go in the same hardware register).
|
||||
/* max_allocno by max_allocno compressed triangular bit matrix,
|
||||
recording whether two allocnos conflict (can't go in the same
|
||||
hardware register). */
|
||||
|
||||
`conflicts' is symmetric after the call to mirror_conflicts. */
|
||||
|
||||
extern HOST_WIDE_INT *conflicts;
|
||||
|
||||
/* Number of ints required to hold max_allocno bits.
|
||||
This is the length of a row in `conflicts'. */
|
||||
|
||||
extern int allocno_row_words;
|
||||
extern HOST_WIDEST_FAST_INT *conflicts;
|
||||
|
||||
/* Indexed by (pseudo) reg number, gives the allocno, or -1
|
||||
for pseudo registers which are not to be allocated. */
|
||||
|
||||
extern int *reg_allocno;
|
||||
|
||||
/* Precalculated partial bit number in the compressed triangular bit matrix.
|
||||
For two allocnos, the final bit number is: partial_bitnum[LOW] + HIGH. */
|
||||
|
||||
extern int *partial_bitnum;
|
||||
|
||||
/* Size in bits of the compressed triangular bit matrix. */
|
||||
|
||||
extern int max_bitnum;
|
||||
|
||||
/* The pool to allocate the adjacency list elements from. */
|
||||
|
||||
extern alloc_pool adjacency_pool;
|
||||
|
||||
/* The maximum number of neighbors stored in the neighbors vector before
|
||||
we have to chain in another vector. */
|
||||
|
||||
#define ADJACENCY_VEC_LENGTH 30
|
||||
|
||||
/* Conflict graph adjacency list. */
|
||||
|
||||
typedef struct adjacency_list_d
|
||||
{
|
||||
int neighbors[ADJACENCY_VEC_LENGTH];
|
||||
unsigned int index;
|
||||
struct adjacency_list_d *next;
|
||||
} adjacency_t;
|
||||
|
||||
extern adjacency_t **adjacency;
|
||||
|
||||
/* Add NEIGHBOR to ALLOC_NO's adjacency list. It is assumed the caller
|
||||
has already determined that NEIGHBOR is not already neighbor by
|
||||
checking the conflict bit matrix. */
|
||||
|
||||
static inline void
|
||||
add_neighbor (int alloc_no, int neighbor)
|
||||
{
|
||||
adjacency_t *adjlist = adjacency[alloc_no];
|
||||
|
||||
if (adjlist == NULL || adjlist->index == ADJACENCY_VEC_LENGTH)
|
||||
{
|
||||
adjacency_t *new = pool_alloc (adjacency_pool);
|
||||
new->index = 0;
|
||||
new->next = adjlist;
|
||||
adjlist = new;
|
||||
adjacency[alloc_no] = adjlist;
|
||||
}
|
||||
|
||||
adjlist->neighbors[adjlist->index++] = neighbor;
|
||||
}
|
||||
|
||||
/* Iterator for adjacency lists. */
|
||||
|
||||
typedef struct adjacency_iterator_d
|
||||
{
|
||||
adjacency_t *vec;
|
||||
unsigned int idx;
|
||||
} adjacency_iter;
|
||||
|
||||
/* Initialize a single adjacency list iterator. */
|
||||
|
||||
static inline int
|
||||
adjacency_iter_init (adjacency_iter *ai, int allocno1)
|
||||
{
|
||||
ai->vec = adjacency[allocno1];
|
||||
ai->idx = 0;
|
||||
return ai->vec != NULL;
|
||||
}
|
||||
|
||||
/* Test whether we have visited all of the neighbors. */
|
||||
|
||||
static inline int
|
||||
adjacency_iter_done (adjacency_iter *ai)
|
||||
{
|
||||
return ai->idx > ai->vec->index;
|
||||
}
|
||||
|
||||
/* Advance to the next neighbor in AI. */
|
||||
|
||||
static inline int
|
||||
adjacency_iter_next (adjacency_iter *ai)
|
||||
{
|
||||
unsigned int idx = ai->idx;
|
||||
int neighbor = ai->vec->neighbors[idx++];
|
||||
if (idx >= ai->vec->index && ai->vec->next != NULL)
|
||||
{
|
||||
ai->vec = ai->vec->next;
|
||||
ai->idx = 0;
|
||||
}
|
||||
else
|
||||
ai->idx = idx;
|
||||
return neighbor;
|
||||
}
|
||||
|
||||
/* Return the one basic block regno is used in. If regno is used
|
||||
in more than one basic block or if it is unknown which block it
|
||||
is used in, return 0. */
|
||||
|
||||
static inline int
|
||||
regno_basic_block (int regno)
|
||||
{
|
||||
int block = REG_BASIC_BLOCK (regno);
|
||||
if (block < 0)
|
||||
block = 0;
|
||||
return block;
|
||||
}
|
||||
|
||||
extern void global_conflicts (void);
|
||||
|
||||
/* In global.c */
|
||||
|
||||
/* For any allocno set in ALLOCNO_SET, set ALLOCNO to that allocno,
|
||||
and execute CODE. */
|
||||
#define EXECUTE_IF_SET_IN_ALLOCNO_SET(ALLOCNO_SET, ALLOCNO, CODE) \
|
||||
do { \
|
||||
int i_; \
|
||||
int allocno_; \
|
||||
HOST_WIDE_INT *p_ = (ALLOCNO_SET); \
|
||||
\
|
||||
for (i_ = allocno_row_words - 1, allocno_ = 0; i_ >= 0; \
|
||||
i_--, allocno_ += HOST_BITS_PER_WIDE_INT) \
|
||||
{ \
|
||||
unsigned HOST_WIDE_INT word_ = (unsigned HOST_WIDE_INT) *p_++; \
|
||||
\
|
||||
for ((ALLOCNO) = allocno_; word_; word_ >>= 1, (ALLOCNO)++) \
|
||||
{ \
|
||||
if (word_ & 1) \
|
||||
{CODE;} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
/* Macro to visit all of IN_ALLOCNO's neighbors. Neighbors are
|
||||
returned in OUT_ALLOCNO for each iteration of the loop. */
|
||||
|
||||
extern void ra_init_live_subregs (bool, sbitmap *, int *, int, rtx reg);
|
||||
#define FOR_EACH_CONFLICT(IN_ALLOCNO, OUT_ALLOCNO, ITER) \
|
||||
if (!adjacency || !adjacency_iter_init (&(ITER), (IN_ALLOCNO))) \
|
||||
; \
|
||||
else \
|
||||
for ((OUT_ALLOCNO) = adjacency_iter_next (&(ITER)); \
|
||||
!adjacency_iter_done (&(ITER)); \
|
||||
(OUT_ALLOCNO) = adjacency_iter_next (&(ITER)))
|
||||
|
||||
extern void ra_init_live_subregs (bool, sbitmap *, int *, int, rtx);
|
||||
extern bool conflict_p (int, int);
|
||||
|
||||
#endif /* GCC_RA_H */
|
||||
|
232
gcc/sparseset.c
Normal file
232
gcc/sparseset.c
Normal file
@ -0,0 +1,232 @@
|
||||
/* SparseSet implementation.
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
Contributed by Peter Bergner <bergner@vnet.ibm.com>
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "libiberty.h"
|
||||
#include "sparseset.h"
|
||||
|
||||
|
||||
/* Allocate and clear a n_elms SparseSet. */
|
||||
|
||||
sparseset
|
||||
sparseset_alloc (SPARSESET_ELT_TYPE n_elms)
|
||||
{
|
||||
unsigned int n_bytes = sizeof (struct sparseset_def)
|
||||
+ ((n_elms - 1) * 2 * sizeof (SPARSESET_ELT_TYPE));
|
||||
|
||||
sparseset set = (sparseset) xmalloc (n_bytes);
|
||||
set->dense = &(set->elms[0]);
|
||||
set->sparse = &(set->elms[n_elms]);
|
||||
set->size = n_elms;
|
||||
sparseset_clear (set);
|
||||
return set;
|
||||
}
|
||||
|
||||
/* Low level routine not meant for use outside of sparseset.[ch].
|
||||
Assumes idx1 < s->members and idx2 < s->members. */
|
||||
|
||||
static inline void
|
||||
sparseset_swap (sparseset s, SPARSESET_ELT_TYPE idx1, SPARSESET_ELT_TYPE idx2)
|
||||
{
|
||||
SPARSESET_ELT_TYPE tmp = s->dense[idx2];
|
||||
sparseset_insert_bit (s, s->dense[idx1], idx2);
|
||||
sparseset_insert_bit (s, tmp, idx1);
|
||||
}
|
||||
|
||||
/* Operation: S = S - {e}
|
||||
Delete e from the set S if it is a member of S. */
|
||||
|
||||
void
|
||||
sparseset_clear_bit (sparseset s, SPARSESET_ELT_TYPE e)
|
||||
{
|
||||
if (sparseset_bit_p (s, e))
|
||||
{
|
||||
SPARSESET_ELT_TYPE idx = s->sparse[e];
|
||||
SPARSESET_ELT_TYPE iter = s->iter;
|
||||
SPARSESET_ELT_TYPE mem = s->members - 1;
|
||||
|
||||
/* If we are iterating over this set and we want to delete a
|
||||
member we've already visited, then we swap the element we
|
||||
want to delete with the element at the current iteration
|
||||
index so that it plays well together with the code below
|
||||
that actually removes the element. */
|
||||
if (s->iterating && idx <= iter)
|
||||
{
|
||||
if (idx < iter)
|
||||
{
|
||||
sparseset_swap (s, idx, iter);
|
||||
idx = iter;
|
||||
}
|
||||
s->iter_inc = 0;
|
||||
}
|
||||
|
||||
/* Replace the element we want to delete with the last element
|
||||
in the dense array and then decrement s->members, effectively
|
||||
removing the element we want to delete. */
|
||||
sparseset_insert_bit (s, s->dense[mem], idx);
|
||||
s->members = mem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Operation: D = S
|
||||
Restrictions: none. */
|
||||
|
||||
void
|
||||
sparseset_copy (sparseset d, sparseset s)
|
||||
{
|
||||
SPARSESET_ELT_TYPE i;
|
||||
|
||||
if (d == s)
|
||||
return;
|
||||
|
||||
sparseset_clear (d);
|
||||
for (i = 0; i < s->members; i++)
|
||||
sparseset_insert_bit (d, s->dense[i], i);
|
||||
d->members = s->members;
|
||||
}
|
||||
|
||||
/* Operation: D = A & B.
|
||||
Restrictions: none. */
|
||||
|
||||
void
|
||||
sparseset_and (sparseset d, sparseset a, sparseset b)
|
||||
{
|
||||
SPARSESET_ELT_TYPE e;
|
||||
|
||||
if (a == b)
|
||||
{
|
||||
if (d != a)
|
||||
sparseset_copy (d, a);
|
||||
return;
|
||||
}
|
||||
|
||||
if (d == a || d == b)
|
||||
{
|
||||
sparseset s = (d == a) ? b : a;
|
||||
|
||||
EXECUTE_IF_SET_IN_SPARSESET (d, e)
|
||||
if (!sparseset_bit_p (s, e))
|
||||
sparseset_clear_bit (d, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
sparseset sml, lrg;
|
||||
|
||||
if (sparseset_cardinality (a) < sparseset_cardinality (b))
|
||||
{
|
||||
sml = a;
|
||||
lrg = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
sml = b;
|
||||
lrg = a;
|
||||
}
|
||||
|
||||
sparseset_clear (d);
|
||||
EXECUTE_IF_SET_IN_SPARSESET (sml, e)
|
||||
if (sparseset_bit_p (lrg, e))
|
||||
sparseset_set_bit (d, e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Operation: D = A & ~B.
|
||||
Restrictions: D != B, unless D == A == B. */
|
||||
|
||||
void
|
||||
sparseset_and_compl (sparseset d, sparseset a, sparseset b)
|
||||
{
|
||||
SPARSESET_ELT_TYPE e;
|
||||
|
||||
if (a == b)
|
||||
{
|
||||
sparseset_clear (d);
|
||||
return;
|
||||
}
|
||||
|
||||
gcc_assert (d != b);
|
||||
|
||||
if (d == a)
|
||||
{
|
||||
if (sparseset_cardinality (d) < sparseset_cardinality (b))
|
||||
{
|
||||
EXECUTE_IF_SET_IN_SPARSESET (d, e)
|
||||
if (sparseset_bit_p (b, e))
|
||||
sparseset_clear_bit (d, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
EXECUTE_IF_SET_IN_SPARSESET (b, e)
|
||||
sparseset_clear_bit (d, e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sparseset_clear (d);
|
||||
EXECUTE_IF_SET_IN_SPARSESET (a, e)
|
||||
if (!sparseset_bit_p (b, e))
|
||||
sparseset_set_bit (d, e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Operation: D = A | B.
|
||||
Restrictions: none. */
|
||||
|
||||
void
|
||||
sparseset_ior (sparseset d, sparseset a, sparseset b)
|
||||
{
|
||||
SPARSESET_ELT_TYPE e;
|
||||
|
||||
if (a == b)
|
||||
sparseset_copy (d, a);
|
||||
else if (d == b)
|
||||
{
|
||||
EXECUTE_IF_SET_IN_SPARSESET (a, e)
|
||||
sparseset_set_bit (d, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (d != a)
|
||||
sparseset_copy (d, a);
|
||||
EXECUTE_IF_SET_IN_SPARSESET (b, e)
|
||||
sparseset_set_bit (d, e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Operation: A == B
|
||||
Restrictions: none. */
|
||||
|
||||
bool
|
||||
sparseset_equal_p (sparseset a, sparseset b)
|
||||
{
|
||||
SPARSESET_ELT_TYPE e;
|
||||
|
||||
if (a == b)
|
||||
return true;
|
||||
|
||||
if (sparseset_cardinality (a) != sparseset_cardinality (b))
|
||||
return false;
|
||||
|
||||
EXECUTE_IF_SET_IN_SPARSESET (a, e)
|
||||
if (!sparseset_bit_p (b, e))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
162
gcc/sparseset.h
Normal file
162
gcc/sparseset.h
Normal file
@ -0,0 +1,162 @@
|
||||
/* SparseSet implementation.
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
Contributed by Peter Bergner <bergner@vnet.ibm.com>
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GCC_SPARSESET_H
|
||||
#define GCC_SPARSESET_H
|
||||
|
||||
#include "system.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define SPARSESET_ELT_BITS ((unsigned) HOST_BITS_PER_WIDEST_FAST_INT)
|
||||
#define SPARSESET_ELT_TYPE unsigned int
|
||||
|
||||
/* Data Structure used for the SparseSet representation. */
|
||||
|
||||
typedef struct sparseset_def
|
||||
{
|
||||
SPARSESET_ELT_TYPE *dense; /* Dense array. */
|
||||
SPARSESET_ELT_TYPE *sparse; /* Sparse array. */
|
||||
SPARSESET_ELT_TYPE members; /* Number of elements. */
|
||||
SPARSESET_ELT_TYPE size; /* Maximum number of elements. */
|
||||
SPARSESET_ELT_TYPE iter; /* Iterator index. */
|
||||
unsigned char iter_inc; /* Iteration increment amount. */
|
||||
bool iterating;
|
||||
SPARSESET_ELT_TYPE elms[2]; /* Combined dense and sparse arrays. */
|
||||
} *sparseset;
|
||||
|
||||
#define sparseset_free(MAP) free(MAP)
|
||||
extern sparseset sparseset_alloc (SPARSESET_ELT_TYPE n_elms);
|
||||
extern void sparseset_clear_bit (sparseset, SPARSESET_ELT_TYPE);
|
||||
extern void sparseset_copy (sparseset, sparseset);
|
||||
extern void sparseset_and (sparseset, sparseset, sparseset);
|
||||
extern void sparseset_and_compl (sparseset, sparseset, sparseset);
|
||||
extern void sparseset_ior (sparseset, sparseset, sparseset);
|
||||
extern bool sparseset_equal_p (sparseset, sparseset);
|
||||
|
||||
/* Operation: S = {}
|
||||
Clear the set of all elements. */
|
||||
|
||||
static inline void
|
||||
sparseset_clear (sparseset s)
|
||||
{
|
||||
s->members = 0;
|
||||
s->iterating = false;
|
||||
}
|
||||
|
||||
/* Return the number of elements currently in the set. */
|
||||
|
||||
static inline SPARSESET_ELT_TYPE
|
||||
sparseset_cardinality (sparseset s)
|
||||
{
|
||||
return s->members;
|
||||
}
|
||||
|
||||
/* Return the maximum number of elements this set can hold. */
|
||||
|
||||
static inline SPARSESET_ELT_TYPE
|
||||
sparseset_size (sparseset s)
|
||||
{
|
||||
return s->size;
|
||||
}
|
||||
|
||||
/* Return true if e is a member of the set S, otherwise return false. */
|
||||
|
||||
static inline bool
|
||||
sparseset_bit_p (sparseset s, SPARSESET_ELT_TYPE e)
|
||||
{
|
||||
SPARSESET_ELT_TYPE idx;
|
||||
|
||||
gcc_assert (e < s->size);
|
||||
|
||||
idx = s->sparse[e];
|
||||
|
||||
return idx < s->members && s->dense[idx] == e;
|
||||
}
|
||||
|
||||
/* Low level insertion routine not meant for use outside of sparseset.[ch].
|
||||
Assumes E is valid and not already a member of the set S. */
|
||||
|
||||
static inline void
|
||||
sparseset_insert_bit (sparseset s, SPARSESET_ELT_TYPE e, SPARSESET_ELT_TYPE idx)
|
||||
{
|
||||
s->sparse[e] = idx;
|
||||
s->dense[idx] = e;
|
||||
}
|
||||
|
||||
/* Operation: S = S + {e}
|
||||
Insert E into the set S, if it isn't already a member. */
|
||||
|
||||
static inline void
|
||||
sparseset_set_bit (sparseset s, SPARSESET_ELT_TYPE e)
|
||||
{
|
||||
if (!sparseset_bit_p (s, e))
|
||||
sparseset_insert_bit (s, e, s->members++);
|
||||
}
|
||||
|
||||
/* Return and remove an arbitrary element from the set S. */
|
||||
|
||||
static inline SPARSESET_ELT_TYPE
|
||||
sparseset_pop (sparseset s)
|
||||
{
|
||||
SPARSESET_ELT_TYPE mem = s->members;
|
||||
|
||||
gcc_assert (mem != 0);
|
||||
|
||||
s->members = mem - 1;
|
||||
return s->dense[mem];
|
||||
}
|
||||
|
||||
static inline void
|
||||
sparseset_iter_init (sparseset s)
|
||||
{
|
||||
s->iter = 0;
|
||||
s->iter_inc = 1;
|
||||
s->iterating = true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
sparseset_iter_p (sparseset s)
|
||||
{
|
||||
if (s->iterating && s->iter < s->members)
|
||||
return true;
|
||||
else
|
||||
return s->iterating = false;
|
||||
}
|
||||
|
||||
static inline SPARSESET_ELT_TYPE
|
||||
sparseset_iter_elm (sparseset s)
|
||||
{
|
||||
return s->dense[s->iter];
|
||||
}
|
||||
|
||||
static inline void
|
||||
sparseset_iter_next (sparseset s)
|
||||
{
|
||||
s->iter += s->iter_inc;
|
||||
s->iter_inc = 1;
|
||||
}
|
||||
|
||||
#define EXECUTE_IF_SET_IN_SPARSESET(SPARSESET, ITER) \
|
||||
for (sparseset_iter_init (SPARSESET); \
|
||||
sparseset_iter_p (SPARSESET) \
|
||||
&& (((ITER) = sparseset_iter_elm (SPARSESET)) || 1); \
|
||||
sparseset_iter_next (SPARSESET))
|
||||
|
||||
#endif /* GCC_SPARSESET_H */
|
Loading…
Reference in New Issue
Block a user