110abdbc68
* config/i386/i386.c, config/pa/pa.c, config/spu/spu.c, df-problems.c, df-scan.c, domwalk.c, ebitmap.c, ebitmap.h, fold-const.c, gcc.c, ipa-type-escape.c, omega.c, omega.h, tree-ssa-coalesce.c, tree-ssa-live.c, tree-ssa-structalias.c, tree-vrp.c: Fix comment typos. Follow spelling conventions. * doc/tm.texi: Follow spelling conventions. From-SVN: r125090
1020 lines
26 KiB
C
1020 lines
26 KiB
C
/* Sparse array-based bitmaps.
|
|
Copyright (C) 2007 Free Software Foundation, Inc.
|
|
Contributed by Daniel Berlin <dberlin@dberlin.org>
|
|
|
|
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 2, 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 COPYING. If not, write to the Free
|
|
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301, USA. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "tm.h"
|
|
#include "rtl.h"
|
|
#include "flags.h"
|
|
#include "obstack.h"
|
|
#include "ebitmap.h"
|
|
|
|
/* The ebitmap data structure is a sparse bitmap structure that works
|
|
by having two pieces:
|
|
1. An array of all nonzero words in the structures, organized as
|
|
an array of HOST_WIDE_INT's.
|
|
2. A non-sparse bitmap saying which bitmap words are present in the
|
|
array.
|
|
|
|
As a consequence of this representation, testing whether a bit
|
|
exists in the bitmap is faster than linked-list bitmaps. For bits
|
|
in words that are all zero, the time to test is O(1). For bits in
|
|
words that exist, it requires O(n/sizeof(word)) time to perform the
|
|
test (ignoring the one element cache). It also has much better
|
|
locality than linked-list bitmaps.
|
|
|
|
To test whether a bit exists, we do the following:
|
|
1. Test whether the word the bit would appear in exists in the
|
|
bitmap (O(1) check of the mask). If not, fail.
|
|
|
|
2. Population count the mask up to the word containing the bit, to
|
|
find the place in the array the word would be (popcount is cached,
|
|
but this is just as slow as the linked-list bitmap)
|
|
3. Test the word to see if the bit exists.
|
|
|
|
Just like linked-list bitmaps, we cache the last element that has
|
|
been tested in order to speed up common access patterns.
|
|
|
|
Most of the other speedups are simply due to better locality of the
|
|
single contiguous array.
|
|
|
|
As would be expected in a structure like this, insertion into an
|
|
empty word in the middle requires moving bits to make room for the
|
|
new word. As most operations that perform sets perform them in
|
|
order, this is rarely a problem. We also take advantage of the
|
|
same element cache to make repeated sets to the same word O(1).
|
|
|
|
Operations on the entire bitmap are also more efficient than linked
|
|
list bitmaps, as they are all operating on contiguous memory, and
|
|
can be easily vectorized. They are all O(number of words) +
|
|
O(number of bits that may end up in the destination), as the
|
|
appropriate operation is first performed on the word mask, and then
|
|
only those elements that may generate results are touched.
|
|
|
|
Memory wise, the ebitmap starts out using less memory than the
|
|
linked-list bitmap, but its size in memory is technically bounded
|
|
by ((index of the highest bit set) / (size of a word) + (index of
|
|
the highest bit set) / ((size of a word) * (size of a word))) This
|
|
is because the mask is non-sparse. The mask could be transformed
|
|
into a sparse bitmap at the cost of making bit testing
|
|
*theoretically* slower (real world numbers have not been computed
|
|
yet as to whether it matters or not). */
|
|
|
|
/* #define EBITMAP_DEBUGGING */
|
|
|
|
/* Find the last set bit in ebitmap MAP. */
|
|
|
|
int
|
|
ebitmap_last_set_bit (ebitmap map)
|
|
{
|
|
unsigned int i = 0;
|
|
ebitmap_iterator ebi;
|
|
bool foundbit = false;
|
|
|
|
/* This is not the fastest way to do this, we could simply look for
|
|
the popcount, and start there, but this function is not used
|
|
anywhere speed critical. */
|
|
EXECUTE_IF_SET_IN_EBITMAP (map, 0, i, ebi)
|
|
{
|
|
foundbit = true;
|
|
}
|
|
|
|
|
|
if (foundbit)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
/* Grow or shrink the internal word array for MAP to NEWSIZE
|
|
elements. */
|
|
|
|
static inline void
|
|
ebitmap_array_grow (ebitmap map, unsigned int newsize)
|
|
{
|
|
if (newsize <= map->n_elts)
|
|
{
|
|
map->n_elts = newsize;
|
|
return;
|
|
}
|
|
|
|
newsize += newsize / 4;
|
|
|
|
map->n_elts = newsize;
|
|
map->elts = xrealloc (map->elts, sizeof (EBITMAP_ELT_TYPE) * newsize);
|
|
}
|
|
|
|
/* Grow the internal word array for MAP so it is at least SIZE
|
|
elements. Will not shrink the array if it is already big
|
|
enough. */
|
|
|
|
static inline void
|
|
ebitmap_array_maybe_grow (ebitmap map, unsigned int size)
|
|
{
|
|
if (size >= map->n_elts)
|
|
ebitmap_array_grow (map, size + 1);
|
|
}
|
|
|
|
/* Retrieve the IDX'th element from the word array for MAP. */
|
|
|
|
static inline EBITMAP_ELT_TYPE
|
|
ebitmap_array_get (ebitmap map, unsigned int idx)
|
|
{
|
|
gcc_assert (idx < map->n_elts);
|
|
return map->elts[idx];
|
|
}
|
|
|
|
/* Retrieve a pointer to the IDX'th element from the word array for
|
|
MAP. If the element index is greater than the size of the array,
|
|
the array will be grown to the correct size. */
|
|
|
|
static inline EBITMAP_ELT_TYPE *
|
|
ebitmap_array_grow_get (ebitmap map, unsigned int idx)
|
|
{
|
|
if (idx >= map->n_elts)
|
|
ebitmap_array_grow (map, idx + 1);
|
|
return &map->elts[idx];
|
|
}
|
|
|
|
/* Initialize the internal word array for MAP, so that it is SIZE
|
|
elements. */
|
|
|
|
static inline void
|
|
ebitmap_array_init (ebitmap map, unsigned int size)
|
|
{
|
|
if (size > 0)
|
|
{
|
|
map->elts = xmalloc (sizeof (EBITMAP_ELT_TYPE) * size);
|
|
map->n_elts = size;
|
|
}
|
|
else
|
|
{
|
|
map->n_elts = 0;
|
|
map->elts = NULL;
|
|
}
|
|
}
|
|
|
|
/* Free the internal word array for MAP. */
|
|
|
|
static inline void
|
|
ebitmap_array_clear (ebitmap map)
|
|
{
|
|
if (map->elts)
|
|
{
|
|
free (map->elts);
|
|
map->elts = NULL;
|
|
}
|
|
map->n_elts = 0;
|
|
}
|
|
|
|
/* Clear ebitmap MAP. */
|
|
|
|
void
|
|
ebitmap_clear (ebitmap map)
|
|
{
|
|
ebitmap_array_clear (map);
|
|
sbitmap_zero (map->wordmask);
|
|
map->wordmask = sbitmap_resize (map->wordmask, 1, 0);
|
|
map->numwords = 0;
|
|
map->cache = NULL;
|
|
map->cacheindex = 0;
|
|
}
|
|
|
|
/* Allocate an ebitmap with enough room for SIZE bits to start out. */
|
|
|
|
ebitmap
|
|
ebitmap_alloc (unsigned int size)
|
|
{
|
|
ebitmap ret = xmalloc (sizeof (struct ebitmap_def));
|
|
if (size == 0)
|
|
size = EBITMAP_ELT_BITS;
|
|
ebitmap_array_init (ret, (size + EBITMAP_ELT_BITS - 1) / EBITMAP_ELT_BITS);
|
|
ret->wordmask = sbitmap_alloc_with_popcount (size);
|
|
sbitmap_zero (ret->wordmask);
|
|
ret->numwords = 0;
|
|
ret->cache = NULL;
|
|
ret->cacheindex = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Clear BIT from ebitmap MAP. */
|
|
|
|
void
|
|
ebitmap_clear_bit (ebitmap map, unsigned int bit)
|
|
{
|
|
unsigned int wordindex = bit / EBITMAP_ELT_BITS;
|
|
unsigned int eltwordindex = 0;
|
|
unsigned int bitindex, shift;
|
|
bool have_eltwordindex = false;
|
|
EBITMAP_ELT_TYPE *elt_ptr;
|
|
|
|
/* If the bit can't exist in our bitmap, just return. */
|
|
if (map->numwords == 0)
|
|
return;
|
|
|
|
if (wordindex >= map->wordmask->n_bits
|
|
|| !TEST_BIT (map->wordmask, wordindex))
|
|
return;
|
|
|
|
if (map->cache != NULL && map->cacheindex == wordindex)
|
|
elt_ptr = map->cache;
|
|
else
|
|
{
|
|
eltwordindex = sbitmap_popcount (map->wordmask, wordindex);
|
|
elt_ptr = &map->elts[eltwordindex];
|
|
have_eltwordindex = true;
|
|
}
|
|
|
|
bitindex = bit % EBITMAP_ELT_BITS;
|
|
shift = bitindex;
|
|
|
|
*(elt_ptr) &= ~(((EBITMAP_ELT_TYPE)1) << shift);
|
|
|
|
/* Clear out the empty words. */
|
|
if (*(elt_ptr) == 0)
|
|
{
|
|
if (!have_eltwordindex)
|
|
eltwordindex = sbitmap_popcount (map->wordmask, wordindex);
|
|
|
|
if (map->cache != NULL && map->cacheindex == eltwordindex)
|
|
map->cache = NULL;
|
|
|
|
RESET_BIT (map->wordmask, wordindex);
|
|
|
|
memmove(&map->elts[eltwordindex], &map->elts[eltwordindex + 1],
|
|
sizeof (EBITMAP_ELT_TYPE) * (map->numwords - eltwordindex));
|
|
map->numwords--;
|
|
}
|
|
}
|
|
|
|
/* Set BIT in ebitmap MAP. */
|
|
|
|
void
|
|
ebitmap_set_bit (ebitmap map, unsigned int bit)
|
|
{
|
|
unsigned int wordindex = bit / EBITMAP_ELT_BITS;
|
|
unsigned int eltwordindex;
|
|
unsigned int bitindex = bit % EBITMAP_ELT_BITS;
|
|
|
|
/* If we have this element cached, just set the bit in it. */
|
|
if (map->cache && map->cacheindex == wordindex)
|
|
{
|
|
(*map->cache) |= (EBITMAP_ELT_TYPE)1 << bitindex;
|
|
return;
|
|
}
|
|
|
|
/* Resize the wordmask if necessary. */
|
|
if (wordindex >= map->wordmask->n_bits)
|
|
map->wordmask = sbitmap_resize (map->wordmask, wordindex + 1, 0);
|
|
|
|
/* Allocate a new word in the array and move whatever is in it's
|
|
place, if necessary. */
|
|
if (!TEST_BIT (map->wordmask, wordindex))
|
|
{
|
|
unsigned long count;
|
|
unsigned int i;
|
|
|
|
SET_BIT (map->wordmask, wordindex);
|
|
count = sbitmap_popcount (map->wordmask, wordindex);
|
|
gcc_assert (count <= map->numwords);
|
|
|
|
for (i = map->numwords; i > count; i--)
|
|
{
|
|
EBITMAP_ELT_TYPE *newelt;
|
|
newelt = ebitmap_array_grow_get (map, i);
|
|
*newelt = ebitmap_array_get (map, i - 1);
|
|
}
|
|
map->numwords++;
|
|
eltwordindex = count;
|
|
ebitmap_array_maybe_grow (map, eltwordindex);
|
|
map->elts[eltwordindex] = 0;
|
|
}
|
|
else
|
|
{
|
|
eltwordindex = sbitmap_popcount (map->wordmask, wordindex);
|
|
}
|
|
|
|
/* Set the actual bit. */
|
|
bitindex = bit % EBITMAP_ELT_BITS;
|
|
|
|
map->elts[eltwordindex] |= (EBITMAP_ELT_TYPE)1 << bitindex;
|
|
map->cache = &map->elts[eltwordindex];
|
|
map->cacheindex = wordindex;
|
|
}
|
|
|
|
|
|
/* Return true if MAP contains BIT. */
|
|
|
|
bool
|
|
ebitmap_bit_p (ebitmap map, unsigned int bit)
|
|
{
|
|
unsigned int wordindex = bit / EBITMAP_ELT_BITS;
|
|
unsigned int bitindex= bit % EBITMAP_ELT_BITS;
|
|
|
|
/* Trivial empty ebitmap case. */
|
|
if (map->numwords == 0)
|
|
return false;
|
|
|
|
if (map->cache && map->cacheindex == wordindex)
|
|
return ((*map->cache) >> bitindex) & 1;
|
|
|
|
/* If the wordindex is greater than the size of the wordmask, *or*
|
|
it's not set in the wordmask, this bit can't exist in our
|
|
ebitmap. */
|
|
if (wordindex >= map->wordmask->n_bits
|
|
|| !TEST_BIT (map->wordmask, wordindex))
|
|
return false;
|
|
|
|
/* Find the bit and test it. */
|
|
map->cacheindex = wordindex;
|
|
wordindex = sbitmap_popcount (map->wordmask, wordindex);
|
|
map->cache = &map->elts[wordindex];
|
|
|
|
return (map->elts[wordindex] >> bitindex) & 1;
|
|
}
|
|
|
|
/* Copy ebitmap SRC to DST. */
|
|
|
|
void
|
|
ebitmap_copy (ebitmap dst, ebitmap src)
|
|
{
|
|
/* Blow away any existing wordmask, and copy the new one. */
|
|
sbitmap_free (dst->wordmask);
|
|
dst->wordmask = sbitmap_alloc_with_popcount (src->wordmask->n_bits);
|
|
sbitmap_copy (dst->wordmask, src->wordmask);
|
|
|
|
/* Make sure our destination array is big enough, and then copy the
|
|
actual words. */
|
|
ebitmap_array_grow (dst, src->numwords);
|
|
memcpy (dst->elts, src->elts,
|
|
src->numwords * sizeof (EBITMAP_ELT_TYPE));
|
|
dst->numwords = src->numwords;
|
|
dst->cache = NULL;
|
|
}
|
|
|
|
/* Dump ebitmap BMAP to FILE. */
|
|
|
|
void
|
|
dump_ebitmap (FILE *file, ebitmap bmap)
|
|
{
|
|
unsigned int pos;
|
|
unsigned int i;
|
|
int res;
|
|
unsigned int size;
|
|
|
|
res = sbitmap_last_set_bit (bmap->wordmask);
|
|
if (res == -1)
|
|
size = 0;
|
|
else
|
|
size = (res + 1) * EBITMAP_ELT_BITS;
|
|
|
|
fprintf (file, "n_words = %d, set = {", bmap->numwords);
|
|
|
|
for (pos = 30, i = 0; i < size; i++)
|
|
if (ebitmap_bit_p (bmap, i))
|
|
{
|
|
if (pos > 70)
|
|
{
|
|
fprintf (file, "\n ");
|
|
pos = 0;
|
|
}
|
|
|
|
pos += fprintf (file, "%d ", i);
|
|
}
|
|
|
|
fprintf (file, "}\n");
|
|
}
|
|
|
|
/* Dump ebitmap BMAP to stderr. */
|
|
|
|
void
|
|
debug_ebitmap (ebitmap bmap)
|
|
{
|
|
dump_ebitmap (stderr, bmap);
|
|
}
|
|
|
|
/* Perform the operation DST &= SRC. */
|
|
|
|
void
|
|
ebitmap_and_into (ebitmap dst, ebitmap src)
|
|
{
|
|
sbitmap_iterator sbi;
|
|
unsigned int i;
|
|
unsigned int neweltindex = 0;
|
|
unsigned int dsteltindex = 0;
|
|
unsigned int srceltindex = 0;
|
|
|
|
gcc_assert (dst != src);
|
|
|
|
dst->cache = NULL;
|
|
|
|
/* Short circuit the empty bitmap cases. */
|
|
if (src->numwords == 0 || dst->numwords == 0)
|
|
{
|
|
ebitmap_clear (dst);
|
|
return;
|
|
}
|
|
|
|
/* AND the masks, then walk the words that may actually appear in
|
|
the result, AND'ing them. */
|
|
sbitmap_a_and_b (dst->wordmask, dst->wordmask, src->wordmask);
|
|
|
|
EXECUTE_IF_SET_IN_SBITMAP (dst->wordmask, 0, i, sbi)
|
|
{
|
|
EBITMAP_ELT_TYPE tmpword = ebitmap_array_get (src, srceltindex++);
|
|
tmpword &= ebitmap_array_get (dst, dsteltindex++);
|
|
if (tmpword != 0)
|
|
{
|
|
EBITMAP_ELT_TYPE *dstplace;
|
|
dstplace = ebitmap_array_grow_get (dst, neweltindex++);
|
|
*dstplace = tmpword;
|
|
}
|
|
else
|
|
RESET_BIT (dst->wordmask, i);
|
|
}
|
|
#ifdef EBITMAP_DEBUGGING
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < dst->numwords; i++)
|
|
gcc_assert (dst->elts[i] != 0);
|
|
|
|
verify_popcount (dst->wordmask);
|
|
gcc_assert (sbitmap_popcount (dst->wordmask,
|
|
dst->wordmask->n_bits) == dst->numwords);
|
|
}
|
|
#endif
|
|
dst->numwords = neweltindex;
|
|
}
|
|
|
|
/* Perform the operation DST = SRC1 & SRC2. */
|
|
|
|
void
|
|
ebitmap_and (ebitmap dst, ebitmap src1, ebitmap src2)
|
|
{
|
|
sbitmap_iterator sbi;
|
|
unsigned int i;
|
|
unsigned int neweltindex = 0;
|
|
unsigned int src1eltindex = 0;
|
|
unsigned int src2eltindex = 0;
|
|
|
|
dst->cache = NULL;
|
|
if (src1->numwords == 0 || src2->numwords == 0)
|
|
{
|
|
ebitmap_clear (dst);
|
|
return;
|
|
}
|
|
|
|
dst->wordmask
|
|
= sbitmap_resize (dst->wordmask,
|
|
MIN (src1->wordmask->n_bits, src2->wordmask->n_bits),
|
|
0);
|
|
sbitmap_a_and_b (dst->wordmask, src1->wordmask, src2->wordmask);
|
|
|
|
EXECUTE_IF_SET_IN_SBITMAP (dst->wordmask, 0, i, sbi)
|
|
{
|
|
bool src1hasword, src2hasword;
|
|
|
|
src1hasword = TEST_BIT (src1->wordmask, i);
|
|
src2hasword = TEST_BIT (src2->wordmask, i);
|
|
|
|
if (src1hasword && src2hasword)
|
|
{
|
|
EBITMAP_ELT_TYPE tmpword = ebitmap_array_get (src1, src1eltindex++);
|
|
tmpword &= ebitmap_array_get (src2, src2eltindex++);
|
|
if (tmpword != 0)
|
|
{
|
|
EBITMAP_ELT_TYPE *dstplace;
|
|
dstplace = ebitmap_array_grow_get (dst, neweltindex++);
|
|
*dstplace = tmpword;
|
|
}
|
|
else
|
|
RESET_BIT (dst->wordmask, i);
|
|
}
|
|
else if (src1hasword)
|
|
src1eltindex++;
|
|
else
|
|
src2eltindex++;
|
|
}
|
|
#ifdef EBITMAP_DEBUGGING
|
|
{
|
|
ebitmap_iterator ebi;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < dst->numwords; i++)
|
|
gcc_assert (dst->elts[i] != 0);
|
|
|
|
EXECUTE_IF_SET_IN_EBITMAP (src1, 0, i, ebi)
|
|
if (ebitmap_bit_p (src2, i))
|
|
gcc_assert (ebitmap_bit_p (dst, i));
|
|
|
|
for (i = 0; i < dst->numwords; i++)
|
|
gcc_assert (dst->elts[i] != 0);
|
|
|
|
verify_popcount (dst->wordmask);
|
|
gcc_assert (sbitmap_popcount (dst->wordmask,
|
|
dst->wordmask->n_bits) == dst->numwords);
|
|
}
|
|
#endif
|
|
dst->numwords = neweltindex;
|
|
}
|
|
|
|
/* Perform the operation DST |= SRC. Return true if any bits in DST
|
|
changed. */
|
|
|
|
bool
|
|
ebitmap_ior_into (ebitmap dst, ebitmap src)
|
|
{
|
|
unsigned int dstsize = dst->wordmask->n_bits;
|
|
unsigned int srcsize = src->wordmask->n_bits;
|
|
sbitmap_iterator sbi;
|
|
unsigned int i;
|
|
sbitmap tempmask;
|
|
unsigned int neweltindex = 0;
|
|
unsigned int dsteltindex = 0;
|
|
unsigned int srceltindex = 0;
|
|
bool changed = false;
|
|
EBITMAP_ELT_TYPE *newarray;
|
|
unsigned int newarraysize;
|
|
#ifdef EBITMAP_DEBUGGING
|
|
ebitmap dstcopy = ebitmap_alloc (1);
|
|
ebitmap_copy (dstcopy, dst);
|
|
#endif
|
|
|
|
dst->cache = NULL;
|
|
if (dst == src)
|
|
return false;
|
|
|
|
if (dst->numwords == 0 && src->numwords != 0)
|
|
{
|
|
ebitmap_copy (dst, src);
|
|
return true;
|
|
}
|
|
else if (src->numwords == 0)
|
|
return false;
|
|
|
|
/* We can do without the temp mask if it's faster, but it would mean
|
|
touching more words in the actual dense vector. */
|
|
tempmask = sbitmap_alloc (MAX (srcsize, dstsize));
|
|
sbitmap_zero (tempmask);
|
|
if (srcsize == dstsize)
|
|
{
|
|
sbitmap_a_or_b (tempmask, dst->wordmask, src->wordmask);
|
|
}
|
|
else
|
|
{
|
|
dst->wordmask = sbitmap_resize (dst->wordmask, MAX (srcsize, dstsize),
|
|
0);
|
|
if (srcsize >= dstsize)
|
|
{
|
|
sbitmap_copy_n (tempmask, dst->wordmask, dst->wordmask->size);
|
|
sbitmap_a_or_b (tempmask, tempmask, src->wordmask);
|
|
}
|
|
else
|
|
{
|
|
sbitmap_copy_n (tempmask, src->wordmask, src->wordmask->size);
|
|
sbitmap_a_or_b (tempmask, tempmask, dst->wordmask);
|
|
}
|
|
}
|
|
newarraysize = src->numwords + dst->numwords;
|
|
newarray = xmalloc (newarraysize * sizeof (EBITMAP_ELT_TYPE));
|
|
|
|
EXECUTE_IF_SET_IN_SBITMAP (tempmask, 0, i, sbi)
|
|
{
|
|
bool dsthasword, srchasword;
|
|
|
|
dsthasword = (i < dst->wordmask->n_bits
|
|
&& TEST_BIT (dst->wordmask, i));
|
|
srchasword = (i < src->wordmask->n_bits
|
|
&& TEST_BIT (src->wordmask, i));
|
|
|
|
if (dsthasword && srchasword)
|
|
{
|
|
EBITMAP_ELT_TYPE tmpword = ebitmap_array_get (src, srceltindex++);
|
|
tmpword |= ebitmap_array_get (dst, dsteltindex);
|
|
if (!changed)
|
|
changed |= tmpword != ebitmap_array_get (dst, dsteltindex);
|
|
dsteltindex++;
|
|
newarray[neweltindex++] = tmpword;
|
|
}
|
|
else if (dsthasword)
|
|
{
|
|
newarray [neweltindex++] = ebitmap_array_get (dst, dsteltindex++);
|
|
}
|
|
else
|
|
{
|
|
newarray [neweltindex++] = ebitmap_array_get (src, srceltindex++);
|
|
gcc_assert (i < dst->wordmask->n_bits);
|
|
SET_BIT (dst->wordmask, i);
|
|
changed |= true;
|
|
}
|
|
}
|
|
|
|
sbitmap_free (tempmask);
|
|
if (changed)
|
|
{
|
|
dst->numwords = neweltindex;
|
|
free (dst->elts);
|
|
dst->elts = newarray;
|
|
dst->n_elts = newarraysize;
|
|
}
|
|
else
|
|
free (newarray);
|
|
|
|
#ifdef EBITMAP_DEBUGGING
|
|
{
|
|
ebitmap_iterator ebi;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < dst->numwords; i++)
|
|
gcc_assert (dst->elts[i] != 0);
|
|
|
|
EXECUTE_IF_SET_IN_EBITMAP (src, 0, i, ebi)
|
|
gcc_assert (ebitmap_bit_p (dst, i));
|
|
EXECUTE_IF_SET_IN_EBITMAP (dstcopy, 0, i, ebi)
|
|
gcc_assert (ebitmap_bit_p (dst, i));
|
|
|
|
verify_popcount (dst->wordmask);
|
|
gcc_assert (changed == !ebitmap_equal_p (dst, dstcopy));
|
|
gcc_assert (sbitmap_popcount (dst->wordmask,
|
|
dst->wordmask->n_bits) == dst->numwords);
|
|
}
|
|
#endif
|
|
return changed;
|
|
}
|
|
|
|
/* Perform the operation DST = SRC1 | SRC2. Return true if any bit
|
|
in DST has changed. */
|
|
|
|
bool
|
|
ebitmap_ior (ebitmap dst, ebitmap src1, ebitmap src2)
|
|
{
|
|
unsigned int src1size = src1->wordmask->n_bits;
|
|
unsigned int src2size = src2->wordmask->n_bits;
|
|
sbitmap_iterator sbi;
|
|
unsigned int i;
|
|
sbitmap tempmask;
|
|
unsigned int neweltindex = 0;
|
|
unsigned int src1eltindex = 0;
|
|
unsigned int src2eltindex = 0;
|
|
bool changed = false;
|
|
EBITMAP_ELT_TYPE *newarray;
|
|
unsigned int newarraysize;
|
|
#ifdef EBITMAP_DEBUGGING
|
|
ebitmap dstcopy = ebitmap_alloc (1);
|
|
ebitmap_copy (dstcopy, dst);
|
|
#endif
|
|
|
|
dst->cache = NULL;
|
|
tempmask = sbitmap_alloc_with_popcount (MAX (src1size, src2size));
|
|
sbitmap_zero (tempmask);
|
|
if (src1size == src2size)
|
|
{
|
|
sbitmap_a_or_b (tempmask, src1->wordmask, src2->wordmask);
|
|
}
|
|
else
|
|
{
|
|
if (src1size >= src2size)
|
|
{
|
|
sbitmap_copy_n (tempmask, src2->wordmask, src2->wordmask->size);
|
|
sbitmap_a_or_b (tempmask, tempmask, src1->wordmask);
|
|
}
|
|
else
|
|
{
|
|
sbitmap_copy_n (tempmask, src1->wordmask, src1->wordmask->size);
|
|
sbitmap_a_or_b (tempmask, tempmask, src2->wordmask);
|
|
}
|
|
}
|
|
newarraysize = src1->numwords + src2->numwords;
|
|
newarray = xmalloc (newarraysize * sizeof (EBITMAP_ELT_TYPE));
|
|
|
|
EXECUTE_IF_SET_IN_SBITMAP (tempmask, 0, i, sbi)
|
|
{
|
|
bool src1hasword, src2hasword;
|
|
EBITMAP_ELT_TYPE tmpword;
|
|
src1hasword = (i < src1->wordmask->n_bits
|
|
&& TEST_BIT (src1->wordmask, i));
|
|
src2hasword = (i < src2->wordmask->n_bits
|
|
&& TEST_BIT (src2->wordmask, i));
|
|
|
|
if (src1hasword && src2hasword)
|
|
{
|
|
tmpword = (ebitmap_array_get (src1, src1eltindex++)
|
|
| ebitmap_array_get (src2, src2eltindex++));
|
|
newarray[neweltindex++] = tmpword;
|
|
}
|
|
else if (src1hasword)
|
|
{
|
|
tmpword = ebitmap_array_get (src1, src1eltindex++);
|
|
newarray [neweltindex++] = tmpword;
|
|
}
|
|
else
|
|
{
|
|
tmpword = ebitmap_array_get (src2, src2eltindex++);
|
|
newarray [neweltindex++] = tmpword;
|
|
}
|
|
|
|
if (i >= dst->wordmask->n_bits || !TEST_BIT (dst->wordmask, i))
|
|
{
|
|
changed = true;
|
|
}
|
|
else if (!changed)
|
|
{
|
|
unsigned int count = sbitmap_popcount (dst->wordmask, i);
|
|
changed |= ebitmap_array_get (dst, count) != tmpword;
|
|
}
|
|
}
|
|
|
|
if (changed)
|
|
{
|
|
sbitmap_free (dst->wordmask);
|
|
dst->wordmask = tempmask;
|
|
dst->numwords = neweltindex;
|
|
free (dst->elts);
|
|
dst->elts = newarray;
|
|
dst->n_elts = newarraysize;
|
|
}
|
|
else
|
|
{
|
|
sbitmap_free (tempmask);
|
|
free (newarray);
|
|
}
|
|
|
|
#ifdef EBITMAP_DEBUGGING
|
|
{
|
|
ebitmap_iterator ebi;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < dst->numwords; i++)
|
|
gcc_assert (dst->elts[i] != 0);
|
|
|
|
EXECUTE_IF_SET_IN_EBITMAP (src1, 0, i, ebi)
|
|
gcc_assert (ebitmap_bit_p (dst, i));
|
|
|
|
EXECUTE_IF_SET_IN_EBITMAP (src2, 0, i, ebi)
|
|
gcc_assert (ebitmap_bit_p (dst, i));
|
|
}
|
|
verify_popcount (dst->wordmask);
|
|
gcc_assert (changed == !ebitmap_equal_p (dst, dstcopy));
|
|
gcc_assert (sbitmap_popcount (dst->wordmask,
|
|
dst->wordmask->n_bits) == dst->numwords);
|
|
#endif
|
|
|
|
return changed;
|
|
}
|
|
|
|
/* Perform the operation DST &= ~SRC. Return true if any bit in DST
|
|
has changed. */
|
|
|
|
bool
|
|
ebitmap_and_compl_into (ebitmap dst, ebitmap src)
|
|
{
|
|
bool changed = false;
|
|
unsigned int i;
|
|
unsigned int neweltindex = 0;
|
|
unsigned int dsteltindex = 0;
|
|
sbitmap_iterator sbi;
|
|
#ifdef EBITMAP_DEBUGGING
|
|
ebitmap dstcopy = ebitmap_alloc (1);
|
|
ebitmap_copy (dstcopy, dst);
|
|
#endif
|
|
|
|
gcc_assert (dst != src);
|
|
dst->cache = NULL;
|
|
if (src->numwords == 0)
|
|
return false;
|
|
|
|
EXECUTE_IF_SET_IN_SBITMAP (dst->wordmask, 0, i, sbi)
|
|
{
|
|
bool srchasword;
|
|
|
|
srchasword = (i < src->wordmask->n_bits
|
|
&& TEST_BIT (src->wordmask, i));
|
|
|
|
if (srchasword)
|
|
{
|
|
unsigned int srccount = sbitmap_popcount (src->wordmask, i);
|
|
EBITMAP_ELT_TYPE tmpword = ebitmap_array_get (dst, dsteltindex);
|
|
tmpword &= ~(ebitmap_array_get (src, srccount));
|
|
if (!changed)
|
|
changed |= ebitmap_array_get (dst, dsteltindex) != tmpword;
|
|
dsteltindex++;
|
|
if (tmpword != 0)
|
|
{
|
|
EBITMAP_ELT_TYPE *dstplace;
|
|
dstplace = ebitmap_array_grow_get (dst, neweltindex++);
|
|
*dstplace = tmpword;
|
|
}
|
|
else
|
|
RESET_BIT (dst->wordmask, i);
|
|
}
|
|
else
|
|
{
|
|
dsteltindex++;
|
|
neweltindex++;
|
|
}
|
|
}
|
|
#ifdef EBITMAP_DEBUGGING
|
|
{
|
|
unsigned int i;
|
|
ebitmap_iterator ebi;
|
|
|
|
EXECUTE_IF_SET_IN_EBITMAP (dstcopy, 0, i, ebi)
|
|
{
|
|
if (!ebitmap_bit_p (src, i))
|
|
gcc_assert (ebitmap_bit_p (dst, i));
|
|
}
|
|
|
|
for (i = 0; i < dst->numwords; i++)
|
|
gcc_assert (dst->elts[i] != 0);
|
|
|
|
gcc_assert (sbitmap_popcount (dst->wordmask,
|
|
dst->wordmask->n_bits) == neweltindex);
|
|
verify_popcount (dst->wordmask);
|
|
gcc_assert (changed == !ebitmap_equal_p (dst, dstcopy));
|
|
gcc_assert (sbitmap_popcount (dst->wordmask,
|
|
dst->wordmask->n_bits) == dst->numwords);
|
|
}
|
|
#endif
|
|
dst->numwords = neweltindex;
|
|
/* sbitmap_popcount (dst->wordmask, -1); */
|
|
|
|
return changed;
|
|
}
|
|
|
|
/* Perform the operation DST = SRC1 & ~SRC2. Return true if any bit
|
|
in DST has changed. */
|
|
|
|
bool
|
|
ebitmap_and_compl (ebitmap dst, ebitmap src1, ebitmap src2)
|
|
{
|
|
unsigned int src1size = src1->wordmask->n_bits;
|
|
sbitmap_iterator sbi;
|
|
unsigned int i;
|
|
sbitmap tempmask;
|
|
unsigned int neweltindex = 0;
|
|
unsigned int src1eltindex = 0;
|
|
bool changed = false;
|
|
EBITMAP_ELT_TYPE *newarray;
|
|
unsigned int newarraysize;
|
|
|
|
/* XXX: Optimize like the into version. */
|
|
dst->cache = NULL;
|
|
tempmask = sbitmap_alloc_with_popcount (src1size);
|
|
sbitmap_zero (tempmask);
|
|
sbitmap_copy (tempmask, src1->wordmask);
|
|
|
|
newarraysize = src1->numwords;
|
|
newarray = xmalloc (newarraysize * sizeof (EBITMAP_ELT_TYPE));
|
|
|
|
EXECUTE_IF_SET_IN_SBITMAP (src1->wordmask, 0, i, sbi)
|
|
{
|
|
bool src2hasword;
|
|
EBITMAP_ELT_TYPE tmpword;
|
|
|
|
src2hasword = (i < src2->wordmask->n_bits
|
|
&& TEST_BIT (src2->wordmask, i));
|
|
|
|
if (src2hasword)
|
|
{
|
|
unsigned int src2count = sbitmap_popcount (src2->wordmask, i);
|
|
tmpword = ebitmap_array_get (src1, src1eltindex++)
|
|
& ~(ebitmap_array_get (src2, src2count));
|
|
if (tmpword)
|
|
{
|
|
newarray[neweltindex++] = tmpword;
|
|
}
|
|
else
|
|
RESET_BIT (tempmask, i);
|
|
|
|
}
|
|
else
|
|
{
|
|
tmpword = ebitmap_array_get (src1, src1eltindex++);
|
|
gcc_assert (tmpword != 0);
|
|
newarray[neweltindex++] = tmpword;
|
|
}
|
|
|
|
if (i >= dst->wordmask->n_bits || !TEST_BIT (dst->wordmask, i))
|
|
{
|
|
changed = true;
|
|
}
|
|
else if (!changed)
|
|
{
|
|
unsigned int count = sbitmap_popcount (dst->wordmask, i);
|
|
changed |= ebitmap_array_get (dst, count) != tmpword;
|
|
}
|
|
}
|
|
if (changed)
|
|
{
|
|
sbitmap_free (dst->wordmask);
|
|
dst->wordmask = tempmask;
|
|
dst->numwords = neweltindex;
|
|
free (dst->elts);
|
|
dst->elts = newarray;
|
|
dst->n_elts = newarraysize;
|
|
}
|
|
else
|
|
{
|
|
free (tempmask);
|
|
free (newarray);
|
|
}
|
|
#ifdef EBITMAP_DEBUGGING
|
|
{
|
|
unsigned int i;
|
|
ebitmap_iterator ebi;
|
|
|
|
EXECUTE_IF_SET_IN_EBITMAP (src1, 0, i, ebi)
|
|
{
|
|
if (!ebitmap_bit_p (src2, i))
|
|
gcc_assert (ebitmap_bit_p (dst, i));
|
|
}
|
|
for (i = 0; i < dst->numwords; i++)
|
|
gcc_assert (dst->elts[i] != 0);
|
|
|
|
verify_popcount (dst->wordmask);
|
|
gcc_assert (sbitmap_popcount (dst->wordmask,
|
|
dst->wordmask->n_bits) == dst->numwords);
|
|
}
|
|
#endif
|
|
return changed;
|
|
}
|
|
|
|
/* Perform the operation DST = A | (B & ~C). */
|
|
|
|
bool
|
|
ebitmap_ior_and_compl (ebitmap dst, ebitmap a, ebitmap b, ebitmap c)
|
|
{
|
|
bool changed;
|
|
ebitmap temp = ebitmap_alloc (1);
|
|
#ifdef EBITMAP_DEBUGGING
|
|
ebitmap dstcopy = ebitmap_alloc (1);
|
|
ebitmap_copy (dstcopy, dst);
|
|
#endif
|
|
|
|
dst->cache = NULL;
|
|
ebitmap_and_compl (temp, b, c);
|
|
changed = ebitmap_ior (dst, a, temp);
|
|
#ifdef EBITMAP_DEBUGGING
|
|
{
|
|
ebitmap_iterator ebi;
|
|
unsigned int i;
|
|
|
|
EXECUTE_IF_SET_IN_EBITMAP (a, 0, i, ebi)
|
|
gcc_assert (ebitmap_bit_p (dst, i));
|
|
|
|
EXECUTE_IF_SET_IN_EBITMAP (b, 0, i, ebi)
|
|
if (!ebitmap_bit_p (c, i))
|
|
gcc_assert (ebitmap_bit_p (dst, i));
|
|
gcc_assert (changed == !ebitmap_equal_p (dst, dstcopy));
|
|
}
|
|
#endif
|
|
ebitmap_free (temp);
|
|
|
|
return changed;
|
|
}
|
|
|
|
/* Return true if ebitmap DST is equal to ebitmap SRC. */
|
|
|
|
bool
|
|
ebitmap_equal_p (ebitmap dst, ebitmap src)
|
|
{
|
|
unsigned int which = MIN (dst->wordmask->size, src->wordmask->size);
|
|
|
|
if (dst->numwords != src->numwords)
|
|
return false;
|
|
|
|
/* sbitmap_equal compares up to the size of the first argument, so
|
|
if the two sbitmaps are not equally sized, we need to pass the
|
|
smaller one as the first argument, or it will crash. */
|
|
if (which == dst->wordmask->size
|
|
&& !sbitmap_equal (dst->wordmask, src->wordmask))
|
|
return false;
|
|
else if (which == src->wordmask->size
|
|
&& !sbitmap_equal (src->wordmask, dst->wordmask))
|
|
return false;
|
|
|
|
return memcmp (dst->elts, src->elts,
|
|
dst->numwords * sizeof (EBITMAP_ELT_TYPE)) == 0;
|
|
return true;
|
|
}
|