Andrew Carlotti <andrew.carlo...@arm.com> writes: > This class provides a constant-size bitmap that can be used as almost a > drop-in replacement for bitmaps stored in integer types. The > implementation is entirely within the header file and uses recursive > templated operations to support effective optimisation and usage in > constexpr expressions. > > This initial implementation hardcodes the choice of uint64_t elements > for storage and initialisation, but this could instead be specified via > a second template parameter. > > gcc/ChangeLog: > > * bbitmap.h: New file. > > > diff --git a/gcc/bbitmap.h b/gcc/bbitmap.h > new file mode 100644 > index > 0000000000000000000000000000000000000000..108ac1bf9e6042f5ae16988bc1688fe0045a3293 > --- /dev/null > +++ b/gcc/bbitmap.h > @@ -0,0 +1,238 @@ > +/* Functions to support fixed-length bitmaps. > + Copyright (C) 2024 Free Software Foundation, Inc. > + > +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_BBITMAP_H > +#define GCC_BBITMAP_H > + > +/* Implementation of bounded (fixed length) bitmaps. > + > + This provides a drop-in replacement for bitmaps that have outgrown the > + storage capacity of a single integer. > + > + Sets are stored as a fixed length array of uint64_t elements. The length > of > + this array is given as a template parameter. */ > + > +template<int M> > +struct bbitmap_operators > +{
I think some comments would help here. Suggestions below: /* Return a Result that maps binary operator OP to elements [0, M) of X and Y and takes the remaining elements from REST. */ > + template<typename Result, typename Operator, typename Arg, typename > ...Rest> > + static constexpr Result binary(Operator op, const Arg &x, const Arg &y, > + Rest ...rest) > + { > + return bbitmap_operators<M - 1>::template binary<Result, Operator, Arg> > + (op, x, y, op (x.val[M - 1], y.val[M - 1]), rest...); > + } > + > + template<typename Operator, typename Arg, typename ...Rest> > + static void compound(Operator op, Arg &x, const Arg &y) > + { > + bbitmap_operators<M - 1>::template compound<Operator, Arg> (op, x, y); > + x.val[M - 1] = op (x.val[M - 1], y.val[M - 1]); > + } I'm not sure this one is worth having, since it isn't needed to create a constexpr. Seems easier to use a loop in the caller instead. > + /* Return a Result that contains the bitwise inverse of elements [0, M) of X and takes the remaining elements from REST. */ > + template<typename Result, typename Arg, typename ...Rest> > + static constexpr Result bit_not(const Arg &x, Rest ...rest) > + { > + return bbitmap_operators<M - 1>::template bit_not<Result, Arg> > + (x, ~(x.val[M - 1]), rest...); > + } > + /* Return true if any element [0, M) of X is nonzero. */ > + template<typename Arg> > + static constexpr bool non_zero(const Arg &x) > + { > + return (bool) x.val[M - 1] > + || bbitmap_operators<M - 1>::template non_zero<Arg> (x); > + } > + /* Return true if elements [0, M) of X are equal to the corresponding elements of Y. */ > + template<typename Arg> > + static constexpr bool equal(const Arg &x, const Arg &y) > + { > + return x.val[M - 1] == y.val[M - 1] > + && bbitmap_operators<M - 1>::template equal<Arg> (x, y); > + } > + > +#define SUB_INDEX(i) (i - (M - 1) * 64) > +#define IN_SUB_RANGE(i) (SUB_INDEX (i) >= 0 && SUB_INDEX (i) < 64) > + This is the one that motivated the ask for comments :) /* If bit index INDEX selects a bit in the first M elements, return a Result with that bit set and the other bits of the leading M elements clear. Clear the leading M elements otherwise. Take the remaining elements of the Result from REST. */ > + template<typename Result, typename ...Rest> > + static constexpr Result from_index(int index, Rest ...rest) > + { > + return bbitmap_operators<M - 1>::template from_index<Result> > + (index, > + (IN_SUB_RANGE (index) > + ? (uint64_t (1) << (IN_SUB_RANGE (index) ? SUB_INDEX (index) : 0)) > + : uint64_t (0)), FWIW, a perhaps overly cutesy way of writing this would be: uint64_t ((index & 63) == (index - (M - 1) * 64)) << (index & 63), which at least avoids the macros. > + rest...); > + } > + > +#undef IN_SUB_RANGE > +#undef SUB_INDEX > + > +}; > + > +template<> > +struct bbitmap_operators<0> > +{ > + template<typename Result, typename Operator, typename Arg, typename > ...Rest> > + static constexpr Result binary(Operator, const Arg, const Arg, > + Rest ...rest) > + { > + return Result { rest... }; > + } > + > + template<typename Operator, typename Arg, typename ...Rest> > + static void compound(Operator, Arg, const Arg) > + { > + return; > + } > + > + template<typename Result, typename Arg, typename ...Rest> > + static constexpr Result bit_not(const Arg, Rest ...rest) > + { > + return Result { rest... }; > + } > + > + template<typename Arg> > + static constexpr bool non_zero(const Arg) > + { > + return false; > + } > + > + template<typename Arg> > + static constexpr bool equal(const Arg, const Arg) > + { > + return true; > + } > + > + template<typename Result, typename ...Rest> > + static constexpr Result from_index(int, Rest ...rest) > + { > + return Result { rest... }; > + } > +}; > + > +template<typename T> > +constexpr T bbitmap_element_or(T x, T y) { return x | y;} > + > +template<typename T> > +constexpr T bbitmap_element_and(T x, T y) { return x & y;} > + > +template<typename T> > +constexpr T bbitmap_element_xor(T x, T y) { return x ^ y;} > + > + > + > +template <int N> > +class GTY((user)) bbitmap > +{ > +public: > + uint64_t val[N]; > + > + template<typename... Rest> > + constexpr bbitmap(Rest ...rest) : val{(uint64_t) rest...} {} > + > + constexpr bbitmap<N> operator|(const bbitmap<N> other) const > + { > + return bbitmap_operators<N>::template > binary<bbitmap<N>>(bbitmap_element_or<uint64_t>, > + *this, other); > + } Very minor nit, but the formatting in the earlier classes is AIUI correct, with no extra indentation on the "{" and "}" relative to the function declaration. Also, the lines are too long: constexpr bbitmap<N> operator|(const bbitmap<N> other) const { return bbitmap_operators<N>::template binary<bbitmap<N>> (bbitmap_element_or<uint64_t>, *this, other); } Same for the others. > + > + bbitmap<N> operator|=(const bbitmap<N> other) > + { > + bbitmap_operators<N>::template compound (bbitmap_element_or<uint64_t>, > + *this, other); > + return this; > + } > + > + constexpr bbitmap<N> operator&(const bbitmap<N> other) const > + { > + return bbitmap_operators<N>::template > binary<bbitmap<N>>(bbitmap_element_and<uint64_t>, > + *this, other); > + } > + > + bbitmap<N> operator&=(const bbitmap<N> other) > + { > + bbitmap_operators<N>::template compound (bbitmap_element_and<uint64_t>, > + *this, other); > + return this; > + } > + > + constexpr bbitmap<N> operator^(const bbitmap<N> other) const > + { > + return bbitmap_operators<N>::template > binary<bbitmap<N>>(bbitmap_element_xor<uint64_t>, > + *this, other); > + } > + > + bbitmap<N> operator^=(const bbitmap<N> other) > + { > + bbitmap_operators<N>::template compound (bbitmap_element_xor<uint64_t>, > + *this, other); > + return this; > + } > + > + constexpr bbitmap<N> operator~() const > + { > + return bbitmap_operators<N>::template bit_not<bbitmap<N>>(*this); > + } > + > + constexpr bool operator!() const > + { > + return !(bbitmap_operators<N>::template non_zero<bbitmap<N>>(*this)); > + } > + > + constexpr explicit operator bool() const > + { > + return bbitmap_operators<N>::template non_zero<bbitmap<N>>(*this); > + } > + > + constexpr bool operator==(const bbitmap<N> other) const > + { > + return bbitmap_operators<N>::template equal<bbitmap<N>>(*this, other); > + } > + > + constexpr bool operator!=(const bbitmap<N> other) const > + { > + return !(bbitmap_operators<N>::template equal<bbitmap<N>>(*this, > other)); > + } > + /* Return a bitmap with bit INDEX set and all other bits clear. */ > + static constexpr bbitmap<N> from_index (int index) > + { > + return bbitmap_operators<N>::template from_index<bbitmap<N>> (index); > + } OK with those changes, thanks. Richard > +}; > + > +template<int N> > +void > +gt_ggc_mx (bbitmap<N> *) > +{ > +} > + > +template<int N> > +void > +gt_pch_nx (bbitmap<N> *) > +{ > +} > + > +template<int N> > +void > +gt_pch_nx (bbitmap<N> *, gt_pointer_operator, void *) > +{ > +} > + > +#endif