On Fri, Jan 13, 2017 at 4:36 AM, Jeff Law <l...@redhat.com> wrote: > Per Richi's request, this breaks out the new sbitmap functions into their > own patch. > > This patch should address all the concerns Richi raised in the prior review. > Namely the performance of the range set/clear and bootstrapping with older > or non-GCC C++ compilers and added missing docs. > > The range set/clear functions work by first handling any partial changes in > the first word by building and applying a single bitmask. Then all full > word changes are handled by a call to memset, then finally residuals in the > last word with another bitmask application. > > Internally I tested these by having both implementations and verifying they > gave identical results during a bootstrap and regression test cycle (with > the subsequent DSE patches that utilize the new functions). > > I also tested the old gcc/non-gcc path by forcing it to be used rather than > the builtin popcount paths. Again, this was bootstrapped and regression > tested against the full DSE patches. > > After those tests were complete, I ripped out the debugging/verification > bits and did another bootstrap and regression test of just the sbitmap > changes as well as a bootstrap and regression test of each stage in the > patchkit. > > OK for the trunk?
Ok. Thanks, Richard. > Jeff > > > > PR tree-optimization/33562 > * sbitmap.h (bitmap_count_bits): Prototype. > (bitmap_clear_range, bitmap_set_range): Likewise. > * sbitmap.c (bitmap_clear_range): New function. > (bitmap_set_range, sbitmap_popcount, bitmap_count_bits): Likewise. > > diff --git a/gcc/sbitmap.c b/gcc/sbitmap.c > index c9bcea9..c065d13 100644 > --- a/gcc/sbitmap.c > +++ b/gcc/sbitmap.c > @@ -202,6 +202,170 @@ bitmap_empty_p (const_sbitmap bmap) > return true; > } > > +/* Clear COUNT bits from START in BMAP. */ > + > +void > +bitmap_clear_range (sbitmap bmap, unsigned int start, unsigned int count) > +{ > + if (count == 0) > + return; > + > + unsigned int start_word = start / SBITMAP_ELT_BITS; > + unsigned int start_bitno = start % SBITMAP_ELT_BITS; > + > + /* Clearing less than a full word, starting at the beginning of a word. > */ > + if (start_bitno == 0 && count < SBITMAP_ELT_BITS) > + { > + SBITMAP_ELT_TYPE mask = ((SBITMAP_ELT_TYPE)1 << count) - 1; > + bmap->elms[start_word] &= ~mask; > + return; > + } > + > + unsigned int end_word = (start + count) / SBITMAP_ELT_BITS; > + unsigned int end_bitno = (start + count) % SBITMAP_ELT_BITS; > + > + /* Clearing starts somewhere in the middle of the first word. Clear up > to > + the end of the first word or the end of the requested region, > whichever > + comes first. */ > + if (start_bitno != 0) > + { > + unsigned int nbits = ((start_word == end_word) > + ? end_bitno - start_bitno > + : SBITMAP_ELT_BITS - start_bitno); > + SBITMAP_ELT_TYPE mask = ((SBITMAP_ELT_TYPE)1 << nbits) - 1; > + mask <<= start_bitno; > + bmap->elms[start_word] &= ~mask; > + start_word++; > + count -= nbits; > + } > + > + if (count == 0) > + return; > + > + /* Now clear words at a time until we hit a partial word. */ > + unsigned int nwords = (end_word - start_word); > + if (nwords) > + { > + memset (&bmap->elms[start_word], 0, nwords * sizeof > (SBITMAP_ELT_TYPE)); > + count -= nwords * sizeof (SBITMAP_ELT_TYPE) * BITS_PER_UNIT; > + start_word += nwords; > + } > + > + if (count == 0) > + return; > + > + /* Now handle residuals in the last word. */ > + SBITMAP_ELT_TYPE mask = ((SBITMAP_ELT_TYPE)1 << count) - 1; > + bmap->elms[start_word] &= ~mask; > +} > + > +/* Set COUNT bits from START in BMAP. */ > +void > +bitmap_set_range (sbitmap bmap, unsigned int start, unsigned int count) > +{ > + if (count == 0) > + return; > + > + unsigned int start_word = start / SBITMAP_ELT_BITS; > + unsigned int start_bitno = start % SBITMAP_ELT_BITS; > + > + /* Setting less than a full word, starting at the beginning of a word. > */ > + if (start_bitno == 0 && count < SBITMAP_ELT_BITS) > + { > + SBITMAP_ELT_TYPE mask = ((SBITMAP_ELT_TYPE)1 << count) - 1; > + bmap->elms[start_word] |= mask; > + return; > + } > + > + unsigned int end_word = (start + count) / SBITMAP_ELT_BITS; > + unsigned int end_bitno = (start + count) % SBITMAP_ELT_BITS; > + > + /* Setting starts somewhere in the middle of the first word. Set up to > + the end of the first word or the end of the requested region, > whichever > + comes first. */ > + if (start_bitno != 0) > + { > + unsigned int nbits = ((start_word == end_word) > + ? end_bitno - start_bitno > + : SBITMAP_ELT_BITS - start_bitno); > + SBITMAP_ELT_TYPE mask = ((SBITMAP_ELT_TYPE)1 << nbits) - 1; > + mask <<= start_bitno; > + bmap->elms[start_word] |= mask; > + start_word++; > + count -= nbits; > + } > + > + if (count == 0) > + return; > + > + /* Now set words at a time until we hit a partial word. */ > + unsigned int nwords = (end_word - start_word); > + if (nwords) > + { > + memset (&bmap->elms[start_word], 0xff, > + nwords * sizeof (SBITMAP_ELT_TYPE)); > + count -= nwords * sizeof (SBITMAP_ELT_TYPE) * BITS_PER_UNIT; > + start_word += nwords; > + } > + > + if (count == 0) > + return; > + > + /* Now handle residuals in the last word. */ > + SBITMAP_ELT_TYPE mask = ((SBITMAP_ELT_TYPE)1 << count) - 1; > + bmap->elms[start_word] |= mask; > +} > + > +#if GCC_VERSION < 3400 > +/* Table of number of set bits in a character, indexed by value of char. > */ > +static const unsigned char popcount_table[] = > +{ > + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, > + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, > + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, > + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, > + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, > + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, > + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, > + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, > +}; > + > +static unsigned long > +sbitmap_popcount (SBITMAP_ELT_TYPE a) > +{ > + unsigned long ret = 0; > + unsigned i; > + > + /* Just do this the table way for now */ > + for (i = 0; i < HOST_BITS_PER_WIDEST_FAST_INT; i += 8) > + ret += popcount_table[(a >> i) & 0xff]; > + return ret; > +} > +#endif > + > +/* Count and return the number of bits set in the bitmap BMAP. */ > + > +unsigned int > +bitmap_count_bits (const_sbitmap bmap) > +{ > + unsigned int count = 0; > + for (unsigned int i = 0; i < bmap->size; i++) > + if (bmap->elms[i]) > + { > +#if GCC_VERSION < 3400 > + count += sbitmap_popcount (bmap->elms[i]); > +#else > +# if HOST_BITS_PER_WIDEST_FAST_INT == HOST_BITS_PER_LONG > + count += __builtin_popcountl (bmap->elms[i]); > +# elif HOST_BITS_PER_WIDEST_FAST_INT == HOST_BITS_PER_LONGLONG > + count += __builtin_popcountll (bmap->elms[i]); > +# else > + count += __builtin_popcount (bmap->elms[i]); > +# endif > +#endif > + } > + return count; > +} > > /* Zero all elements in a bitmap. */ > > diff --git a/gcc/sbitmap.h b/gcc/sbitmap.h > index 26fe3db..ce4d27d 100644 > --- a/gcc/sbitmap.h > +++ b/gcc/sbitmap.h > @@ -231,8 +231,11 @@ extern sbitmap *sbitmap_vector_alloc (unsigned int, > unsigned int); > extern sbitmap sbitmap_resize (sbitmap, unsigned int, int); > extern void bitmap_copy (sbitmap, const_sbitmap); > extern int bitmap_equal_p (const_sbitmap, const_sbitmap); > +extern unsigned int bitmap_count_bits (const_sbitmap); > extern bool bitmap_empty_p (const_sbitmap); > extern void bitmap_clear (sbitmap); > +extern void bitmap_clear_range (sbitmap, unsigned, unsigned); > +extern void bitmap_set_range (sbitmap, unsigned, unsigned); > extern void bitmap_ones (sbitmap); > extern void bitmap_vector_clear (sbitmap *, unsigned int); > extern void bitmap_vector_ones (sbitmap *, unsigned int); >