Commit b4da855a by Peter Bergner Committed by Peter Bergner

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
parent 6aa12f4f
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@
......
......@@ -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)
extern void ra_init_live_subregs (bool, sbitmap *, int *, int, rtx reg);
/* Macro to visit all of IN_ALLOCNO's neighbors. Neighbors are
returned in OUT_ALLOCNO for each iteration of the loop. */
#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 */
/* 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;
}
/* 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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment