bitmap.h: Add explanation of sparse set as linked-list bitmap.

* bitmap.h: Add explanation of sparse set as linked-list bitmap.
	* sbitmap.h: Add explanation about non-sparse sets as simple bitmap.
	(TEST_BIT): Make a static inline function for stronger type checking.
	(SET_BIT): Don't handle sbitmaps with popcount.
	(RESET_BIT): Likewise.
	(SET_BIT_WITH_POPCOUNT): New, like SET_BIT but with popcount.
	(RESET_BIT_WITH_POPCOUNT): New, like RESET_BIT but with popcount.
	* ebitmap.c (ebitmap_clear_bit): Use SET_BIT_WITH_POPCOUNT and
	RESET_BIT_WITH_POPCOUNT on wordmask bitmaps.
	(ebitmap_set_bit, ebitmap_and_into, ebitmap_and, ebitmap_ior_into,
	ebitmap_and_compl_into, ebitmap_and_compl): Likewise.
	* sparseset.h: Add explanation of sparse set representation.

From-SVN: r189888
This commit is contained in:
Steven Bosscher 2012-07-26 12:02:54 +00:00
parent 6b4496dbc3
commit 0263463dd1
7 changed files with 317 additions and 53 deletions

View file

@ -1,3 +1,18 @@
2012-07-26 Steven Bosscher <steven@gcc.gnu.org>
* bitmap.h: Add explanation of sparse set as linked-list bitmap.
* sbitmap.h: Add explanation about non-sparse sets as simple bitmap.
(TEST_BIT): Make a static inline function for stronger type checking.
(SET_BIT): Don't handle sbitmaps with popcount.
(RESET_BIT): Likewise.
(SET_BIT_WITH_POPCOUNT): New, like SET_BIT but with popcount.
(RESET_BIT_WITH_POPCOUNT): New, like RESET_BIT but with popcount.
* ebitmap.c (ebitmap_clear_bit): Use SET_BIT_WITH_POPCOUNT and
RESET_BIT_WITH_POPCOUNT on wordmask bitmaps.
(ebitmap_set_bit, ebitmap_and_into, ebitmap_and, ebitmap_ior_into,
ebitmap_and_compl_into, ebitmap_and_compl): Likewise.
* sparseset.h: Add explanation of sparse set representation.
2012-07-26 Richard Guenther <rguenther@suse.de>
PR tree-optimization/54098

View file

@ -1,6 +1,5 @@
/* Functions to support general ended bitmaps.
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Copyright (C) 1997-2012 Free Software Foundation, Inc.
This file is part of GCC.

View file

@ -1,6 +1,5 @@
/* Functions to support general ended bitmaps.
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Copyright (C) 1997-2012 Free Software Foundation, Inc.
This file is part of GCC.
@ -20,6 +19,114 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_BITMAP_H
#define GCC_BITMAP_H
/* Implementation of sparse integer sets as a linked list.
This sparse set representation is suitable for sparse sets with an
unknown (a priori) universe. The set is represented as a double-linked
list of container nodes (struct bitmap_element_def). Each node consists
of an index for the first member that could be held in the container,
a small array of integers that represent the members in the container,
and pointers to the next and previous element in the linked list. The
elements in the list are sorted in ascending order, i.e. the head of
the list holds the element with the smallest member of the set.
For a given member I in the set:
- the element for I will have index is I / (bits per element)
- the position for I within element is I % (bits per element)
This representation is very space-efficient for large sparse sets, and
the size of the set can be changed dynamically without much overhead.
An important parameter is the number of bits per element. In this
implementation, there are 128 bits per element. This results in a
high storage overhead *per element*, but a small overall overhead if
the set is very sparse.
The downside is that many operations are relatively slow because the
linked list has to be traversed to test membership (i.e. member_p/
add_member/remove_member). To improve the performance of this set
representation, the last accessed element and its index are cached.
For membership tests on members close to recently accessed members,
the cached last element improves membership test to a constant-time
operation.
The following operations can always be performed in O(1) time:
* clear : bitmap_clear
* choose_one : (not implemented, but could be
implemented in constant time)
The following operations can be performed in O(E) time worst-case (with
E the number of elements in the linked list), but in O(1) time with a
suitable access patterns:
* member_p : bitmap_bit_p
* add_member : bitmap_set_bit
* remove_member : bitmap_clear_bit
The following operations can be performed in O(E) time:
* cardinality : bitmap_count_bits
* set_size : bitmap_last_set_bit (but this could
in constant time with a pointer to
the last element in the chain)
Additionally, the linked-list sparse set representation supports
enumeration of the members in O(E) time:
* forall : EXECUTE_IF_SET_IN_BITMAP
* set_copy : bitmap_copy
* set_intersection : bitmap_intersect_p /
bitmap_and / bitmap_and_into /
EXECUTE_IF_AND_IN_BITMAP
* set_union : bitmap_ior / bitmap_ior_into
* set_difference : bitmap_intersect_compl_p /
bitmap_and_comp / bitmap_and_comp_into /
EXECUTE_IF_AND_COMPL_IN_BITMAP
* set_disjuction : bitmap_xor_comp / bitmap_xor_comp_into
* set_compare : bitmap_equal_p
Some operations on 3 sets that occur frequently in in data flow problems
are also implemented:
* A | (B & C) : bitmap_ior_and_into
* A | (B & ~C) : bitmap_ior_and_compl /
bitmap_ior_and_compl_into
The storage requirements for linked-list sparse sets are O(E), with E->N
in the worst case (a sparse set with large distances between the values
of the set members).
The linked-list set representation works well for problems involving very
sparse sets. The canonical example in GCC is, of course, the "set of
sets" for some CFG-based data flow problems (liveness analysis, dominance
frontiers, etc.).
This representation also works well for data flow problems where the size
of the set may grow dynamically, but care must be taken that the member_p,
add_member, and remove_member operations occur with a suitable access
pattern.
For random-access sets with a known, relatively small universe size, the
SparseSet or simple bitmap representations may be more efficient than a
linked-list set. For random-access sets of unknown universe, a hash table
or a balanced binary tree representation is likely to be a more suitable
choice.
Traversing linked lists is usually cache-unfriendly, even with the last
accessed element cached.
Cache performance can be improved by keeping the elements in the set
grouped together in memory, using a dedicated obstack for a set (or group
of related sets). Elements allocated on obstacks are released to a
free-list and taken off the free list. If multiple sets are allocated on
the same obstack, elements freed from one set may be re-used for one of
the other sets. This usually helps avoid cache misses.
A single free-list is used for all sets allocated in GGC space. This is
bad for persistent sets, so persistent sets should be allocated on an
obstack whenever possible. */
#include "hashtab.h"
#include "statistics.h"
#include "obstack.h"
@ -130,9 +237,11 @@ extern void bitmap_xor_into (bitmap, const_bitmap);
/* DST = A | (B & C). Return true if DST changes. */
extern bool bitmap_ior_and_into (bitmap DST, const_bitmap B, const_bitmap C);
/* DST = A | (B & ~C). Return true if DST changes. */
extern bool bitmap_ior_and_compl (bitmap DST, const_bitmap A, const_bitmap B, const_bitmap C);
extern bool bitmap_ior_and_compl (bitmap DST, const_bitmap A,
const_bitmap B, const_bitmap C);
/* A |= (B & ~C). Return true if A changes. */
extern bool bitmap_ior_and_compl_into (bitmap DST, const_bitmap B, const_bitmap C);
extern bool bitmap_ior_and_compl_into (bitmap A,
const_bitmap B, const_bitmap C);
/* Clear a single bit in a bitmap. Return true if the bit changed. */
extern bool bitmap_clear_bit (bitmap, int);
@ -328,7 +437,8 @@ bmp_iter_and_init (bitmap_iterator *bi, const_bitmap map1, const_bitmap map2,
*/
static inline void
bmp_iter_and_compl_init (bitmap_iterator *bi, const_bitmap map1, const_bitmap map2,
bmp_iter_and_compl_init (bitmap_iterator *bi,
const_bitmap map1, const_bitmap map2,
unsigned start_bit, unsigned *bit_no)
{
bi->elt1 = map1->first;

View file

@ -1,5 +1,5 @@
/* Sparse array-based bitmaps.
Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Copyright (C) 2007-2012 Free Software Foundation, Inc.
Contributed by Daniel Berlin <dberlin@dberlin.org>
This file is part of GCC.
@ -258,7 +258,7 @@ ebitmap_clear_bit (ebitmap map, unsigned int bit)
map->cache = map->cache - 1;
}
RESET_BIT (map->wordmask, wordindex);
RESET_BIT_WITH_POPCOUNT (map->wordmask, wordindex);
memmove(&map->elts[eltwordindex], &map->elts[eltwordindex + 1],
sizeof (EBITMAP_ELT_TYPE) * (map->numwords - eltwordindex));
@ -293,7 +293,7 @@ ebitmap_set_bit (ebitmap map, unsigned int bit)
unsigned long count;
unsigned int i;
SET_BIT (map->wordmask, wordindex);
SET_BIT_WITH_POPCOUNT (map->wordmask, wordindex);
count = sbitmap_popcount (map->wordmask, wordindex);
gcc_assert (count <= map->numwords);
@ -449,7 +449,7 @@ ebitmap_and_into (ebitmap dst, ebitmap src)
*dstplace = tmpword;
}
else
RESET_BIT (dst->wordmask, i);
RESET_BIT_WITH_POPCOUNT (dst->wordmask, i);
}
#ifdef EBITMAP_DEBUGGING
{
@ -508,7 +508,7 @@ ebitmap_and (ebitmap dst, ebitmap src1, ebitmap src2)
*dstplace = tmpword;
}
else
RESET_BIT (dst->wordmask, i);
RESET_BIT_WITH_POPCOUNT (dst->wordmask, i);
}
else if (src1hasword)
src1eltindex++;
@ -624,7 +624,7 @@ ebitmap_ior_into (ebitmap dst, ebitmap src)
{
newarray [neweltindex++] = ebitmap_array_get (src, srceltindex++);
gcc_assert (i < dst->wordmask->n_bits);
SET_BIT (dst->wordmask, i);
SET_BIT_WITH_POPCOUNT (dst->wordmask, i);
changed |= true;
}
}
@ -825,7 +825,7 @@ ebitmap_and_compl_into (ebitmap dst, ebitmap src)
*dstplace = tmpword;
}
else
RESET_BIT (dst->wordmask, i);
RESET_BIT_WITH_POPCOUNT (dst->wordmask, i);
}
else
{
@ -904,7 +904,7 @@ ebitmap_and_compl (ebitmap dst, ebitmap src1, ebitmap src2)
newarray[neweltindex++] = tmpword;
}
else
RESET_BIT (tempmask, i);
RESET_BIT_WITH_POPCOUNT (tempmask, i);
}
else

View file

@ -1,6 +1,5 @@
/* Simple bitmaps.
Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006, 2007, 2008, 2010
Free Software Foundation, Inc.
Copyright (C) 1999-2012 Free Software Foundation, Inc.
This file is part of GCC.

View file

@ -1,6 +1,5 @@
/* Simple bitmaps.
Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006, 2007, 2008, 2010
Free Software Foundation, Inc.
Copyright (C) 1999-2012 Free Software Foundation, Inc.
This file is part of GCC.
@ -21,9 +20,65 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_SBITMAP_H
#define GCC_SBITMAP_H
/* It's not clear yet whether using bitmap.[ch] will be a win.
It should be straightforward to convert so for now we keep things simple
while more important issues are dealt with. */
/* Implementation of sets using simple bitmap vectors.
This set representation is suitable for non-sparse sets with a known
(a priori) universe. The set is represented as a simple array of the
host's fastest unsigned integer. For a given member I in the set:
- the element for I will be at sbitmap[I / (bits per element)]
- the position for I within element is I % (bits per element)
This representation is very space-efficient for large non-sparse sets
with random access patterns.
The following operations can be performed in O(1) time:
* set_size : SBITMAP_SIZE
* member_p : TEST_BIT
* add_member : SET_BIT
* remove_member : RESET_BIT
Most other operations on this set representation are O(U) where U is
the size of the set universe:
* clear : sbitmap_zero
* cardinality : sbitmap_popcount
* choose_one : sbitmap_first_set_bit /
sbitmap_last_set_bit
* forall : EXECUTE_IF_SET_IN_SBITMAP
* set_copy : sbitmap_copy / sbitmap_copy_n
* set_intersection : sbitmap_a_and_b
* set_union : sbitmap_a_or_b
* set_difference : sbitmap_difference
* set_disjuction : (not implemented)
* set_compare : sbitmap_equal
Some operations on 3 sets that occur frequently in in data flow problems
are also implemented:
* A | (B & C) : sbitmap_a_or_b_and_c
* A | (B & ~C) : sbitmap_union_of_diff
* A & (B | C) : sbitmap_a_and_b_or_c
Most of the set functions have two variants: One that returns non-zero
if members were added or removed from the target set, and one that just
performs the operation without feedback. The former operations are a
bit more expensive but the result can often be used to avoid iterations
on other sets.
Allocating a bitmap is done with sbitmap_alloc, and resizing is
performed with sbitmap_resize.
The storage requirements for simple bitmap sets is O(U) where U is the
size of the set universe (colloquially the number of bits in the bitmap).
This set representation works well for relatively small data flow problems
(there are special routines for that, see sbitmap_vector_*). The set
operations can be vectorized and there is almost no computating overhead,
so that even sparse simple bitmap sets outperform dedicated sparse set
representations like linked-list bitmaps. For larger problems, the size
overhead of simple bitmap sets gets too high and other set representations
have to be used. */
#define SBITMAP_ELT_BITS (HOST_BITS_PER_WIDEST_FAST_INT * 1u)
#define SBITMAP_ELT_TYPE unsigned HOST_WIDEST_FAST_INT
@ -40,42 +95,62 @@ struct simple_bitmap_def
#define SBITMAP_SET_SIZE(N) (((N) + SBITMAP_ELT_BITS - 1) / SBITMAP_ELT_BITS)
#define SBITMAP_SIZE_BYTES(BITMAP) ((BITMAP)->size * sizeof (SBITMAP_ELT_TYPE))
/* Test if bit number bitno in the bitmap is set. */
#define TEST_BIT(BITMAP, BITNO) \
((BITMAP)->elms [(BITNO) / SBITMAP_ELT_BITS] >> (BITNO) % SBITMAP_ELT_BITS & 1)
/* Return the number of bits in BITMAP. */
#define SBITMAP_SIZE(BITMAP) ((BITMAP)->n_bits)
/* Set bit number BITNO in the sbitmap MAP. Updates population count
if this bitmap has one. */
/* Test if bit number bitno in the bitmap is set. */
static inline SBITMAP_ELT_TYPE
TEST_BIT (const_sbitmap map, unsigned int bitno)
{
size_t i = bitno / SBITMAP_ELT_BITS;
unsigned int s = bitno % SBITMAP_ELT_BITS;
return (map->elms[i] >> s) & (SBITMAP_ELT_TYPE) 1;
}
/* Set bit number BITNO in the sbitmap MAP. */
static inline void
SET_BIT (sbitmap map, unsigned int bitno)
{
if (map->popcount)
{
bool oldbit;
oldbit = TEST_BIT (map, bitno);
if (!oldbit)
map->popcount[bitno / SBITMAP_ELT_BITS]++;
}
gcc_checking_assert (! map->popcount);
map->elms[bitno / SBITMAP_ELT_BITS]
|= (SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS;
}
/* Like SET_BIT, but updates population count. */
static inline void
SET_BIT_WITH_POPCOUNT (sbitmap map, unsigned int bitno)
{
bool oldbit;
gcc_checking_assert (map->popcount);
oldbit = TEST_BIT (map, bitno);
if (!oldbit)
map->popcount[bitno / SBITMAP_ELT_BITS]++;
map->elms[bitno / SBITMAP_ELT_BITS]
|= (SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS;
}
/* Reset bit number BITNO in the sbitmap MAP. Updates population
count if this bitmap has one. */
/* Reset bit number BITNO in the sbitmap MAP. */
static inline void
RESET_BIT (sbitmap map, unsigned int bitno)
{
if (map->popcount)
{
bool oldbit;
oldbit = TEST_BIT (map, bitno);
if (oldbit)
map->popcount[bitno / SBITMAP_ELT_BITS]--;
}
gcc_checking_assert (! map->popcount);
map->elms[bitno / SBITMAP_ELT_BITS]
&= ~((SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS);
}
/* Like RESET_BIT, but updates population count. */
static inline void
RESET_BIT_WITH_POPCOUNT (sbitmap map, unsigned int bitno)
{
bool oldbit;
gcc_checking_assert (map->popcount);
oldbit = TEST_BIT (map, bitno);
if (oldbit)
map->popcount[bitno / SBITMAP_ELT_BITS]--;
map->elms[bitno / SBITMAP_ELT_BITS]
&= ~((SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS);
}
@ -211,14 +286,20 @@ extern void sbitmap_ones (sbitmap);
extern void sbitmap_vector_zero (sbitmap *, unsigned int);
extern void sbitmap_vector_ones (sbitmap *, unsigned int);
extern void sbitmap_union_of_diff (sbitmap, const_sbitmap, const_sbitmap, const_sbitmap);
extern bool sbitmap_union_of_diff_cg (sbitmap, const_sbitmap, const_sbitmap, const_sbitmap);
extern void sbitmap_union_of_diff (sbitmap, const_sbitmap,
const_sbitmap, const_sbitmap);
extern bool sbitmap_union_of_diff_cg (sbitmap, const_sbitmap,
const_sbitmap, const_sbitmap);
extern void sbitmap_difference (sbitmap, const_sbitmap, const_sbitmap);
extern void sbitmap_not (sbitmap, const_sbitmap);
extern void sbitmap_a_or_b_and_c (sbitmap, const_sbitmap, const_sbitmap, const_sbitmap);
extern bool sbitmap_a_or_b_and_c_cg (sbitmap, const_sbitmap, const_sbitmap, const_sbitmap);
extern void sbitmap_a_and_b_or_c (sbitmap, const_sbitmap, const_sbitmap, const_sbitmap);
extern bool sbitmap_a_and_b_or_c_cg (sbitmap, const_sbitmap, const_sbitmap, const_sbitmap);
extern void sbitmap_a_or_b_and_c (sbitmap, const_sbitmap,
const_sbitmap, const_sbitmap);
extern bool sbitmap_a_or_b_and_c_cg (sbitmap, const_sbitmap,
const_sbitmap, const_sbitmap);
extern void sbitmap_a_and_b_or_c (sbitmap, const_sbitmap,
const_sbitmap, const_sbitmap);
extern bool sbitmap_a_and_b_or_c_cg (sbitmap, const_sbitmap,
const_sbitmap, const_sbitmap);
extern bool sbitmap_any_common_bits (const_sbitmap, const_sbitmap);
extern void sbitmap_a_and_b (sbitmap, const_sbitmap, const_sbitmap);
extern bool sbitmap_a_and_b_cg (sbitmap, const_sbitmap, const_sbitmap);

View file

@ -1,5 +1,5 @@
/* SparseSet implementation.
Copyright (C) 2007, 2010 Free Software Foundation, Inc.
Copyright (C) 2007-2012 Free Software Foundation, Inc.
Contributed by Peter Bergner <bergner@vnet.ibm.com>
This file is part of GCC.
@ -21,11 +21,71 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_SPARSESET_H
#define GCC_SPARSESET_H
#define SPARSESET_ELT_BITS ((unsigned) HOST_BITS_PER_WIDEST_FAST_INT)
#define SPARSESET_ELT_TYPE unsigned int
/* Implementation of the Briggs and Torczon sparse set representation.
The sparse set representation was first published in:
"An Efficient Representation for Sparse Sets",
ACM LOPLAS, Vol. 2, Nos. 1-4, March-December 1993, Pages 59-69.
The sparse set representation is suitable for integer sets with a
fixed-size universe. Two vectors are used to store the members of
the set. If an element I is in the set, then sparse[I] is the
index of I in the dense vector, and dense[sparse[I]] == I. The dense
vector works like a stack. The size of the stack is the cardinality
of the set.
The following operations can be performed in O(1) time:
* clear : sparseset_clear
* cardinality : sparseset_cardinality
* set_size : sparseset_size
* member_p : sparseset_bit_p
* add_member : sparseset_set_bit
* remove_member : sparseset_clear_bit
* choose_one : sparseset_pop
Additionally, the sparse set representation supports enumeration of
the members in O(N) time, where n is the number of members in the set.
The members of the set are stored cache-friendly in the dense vector.
This makes it a competitive choice for iterating over relatively sparse
sets requiring operations:
* forall : EXECUTE_IF_SET_IN_SPARSESET
* set_copy : sparseset_copy
* set_intersection : sparseset_and
* set_union : sparseset_ior
* set_difference : sparseset_and_compl
* set_disjuction : (not implemented)
* set_compare : sparseset_equal_p
NB: It is OK to use remove_member during EXECUTE_IF_SET_IN_SPARSESET.
The iterator is updated for it.
Based on the efficiency of these operations, this representation of
sparse sets will often be superior to alternatives such as simple
bitmaps, linked-list bitmaps, array bitmaps, balanced binary trees,
hash tables, linked lists, etc., if the set is sufficiently sparse.
In the LOPLAS paper the cut-off point where sparse sets became faster
than simple bitmaps (see sbitmap.h) when N / U < 64 (where U is the
size of the universe of the set).
Because the set universe is fixed, the set cannot be resized. For
sparse sets with initially unknown size, linked-list bitmaps are a
better choice, see bitmap.h.
Sparse sets storage requirements are relatively large: O(U) with a
larger constant than sbitmaps (if the storage requirement for an
sbitmap with universe U is S, then the storage required for a sparse
set for the same universe are 2*HOST_BITS_PER_WIDEST_FAST_INT * S).
Accessing the sparse vector is not very cache-friendly, but iterating
over the members in the set is cache-friendly because only the dense
vector is used. */
/* Data Structure used for the SparseSet representation. */
#define SPARSESET_ELT_BITS ((unsigned) HOST_BITS_PER_WIDEST_FAST_INT)
#define SPARSESET_ELT_TYPE unsigned HOST_WIDEST_FAST_INT
typedef struct sparseset_def
{
SPARSESET_ELT_TYPE *dense; /* Dense array. */
@ -107,7 +167,7 @@ sparseset_set_bit (sparseset s, SPARSESET_ELT_TYPE e)
sparseset_insert_bit (s, e, s->members++);
}
/* Return and remove an arbitrary element from the set S. */
/* Return and remove the last member added to the set S. */
static inline SPARSESET_ELT_TYPE
sparseset_pop (sparseset s)