1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
#ifndef __BITOPS_H__
#define __BITOPS_H__
#include <stdint.h>
#include "util.h"
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE 8
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#define DECLARE_BITMAP(name, bits) \
unsigned long name[BITS_TO_LONGS(bits)]
#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long))
#define BITS_PER_UINT64 (BITS_PER_BYTE * sizeof(uint64_t))
#define __ffs(x) (x ? __builtin_ffsl(x) - 1 : 0)
#define ffz(x) __ffs(~(x))
#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
/*
* Iterate over a bitmap
*
* @nr: the bit number to use as a loop cursor
* @addr: the bitmap you iterate over
* @bits: the number of bits this bitmap contains
*/
#define FOR_EACH_BIT(nr, addr, bits) \
for (nr = find_next_bit((addr), (bits), 0); \
nr < (bits); \
nr = find_next_bit((addr), (bits), nr + 1))
/*
* Change the size of allocated bitmap
*
* This doesn't change the contents of the old bitmap pointed to by `ptr`, and
* initializes the newly allocated area with zeros.
*/
static inline unsigned long *alloc_bitmap(unsigned long *old_bmap,
size_t old_bits, size_t new_bits)
{
size_t old_size = BITS_TO_LONGS(old_bits) * sizeof(long);
size_t new_size = BITS_TO_LONGS(new_bits) * sizeof(long);
unsigned long *new_bmap = xrealloc(old_bmap, new_size);
if (old_bits < new_bits)
memset((char *)new_bmap + old_size, 0, new_size - old_size);
return new_bmap;
}
static inline unsigned long find_next_zero_bit(const unsigned long *addr,
unsigned long size,
unsigned long offset)
{
const unsigned long *p = addr + BITOP_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
offset %= BITS_PER_LONG;
if (offset) {
tmp = *(p++);
tmp |= ~0UL >> (BITS_PER_LONG - offset);
if (size < BITS_PER_LONG)
goto found_first;
if (~tmp)
goto found_middle;
size -= BITS_PER_LONG;
result += BITS_PER_LONG;
}
while (size & ~(BITS_PER_LONG-1)) {
tmp = *(p++);
if (~tmp)
goto found_middle;
result += BITS_PER_LONG;
size -= BITS_PER_LONG;
}
if (!size)
return result;
tmp = *p;
found_first:
tmp |= ~0UL << size;
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found_middle:
return result + ffz(tmp);
}
static inline unsigned long find_next_bit(const unsigned long *addr,
unsigned long size,
unsigned long offset)
{
const unsigned long *p = addr + BITOP_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
offset %= BITS_PER_LONG;
if (offset) {
tmp = *(p++);
tmp &= (~0UL << offset);
if (size < BITS_PER_LONG)
goto found_first;
if (tmp)
goto found_middle;
size -= BITS_PER_LONG;
result += BITS_PER_LONG;
}
while (size & ~(BITS_PER_LONG-1)) {
tmp = *(p++);
if (tmp)
goto found_middle;
result += BITS_PER_LONG;
size -= BITS_PER_LONG;
}
if (!size)
return result;
tmp = *p;
found_first:
tmp &= (~0UL >> (BITS_PER_LONG - size));
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found_middle:
return result + __ffs(tmp);
}
static inline void set_bit(int nr, unsigned long *addr)
{
addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
}
static inline void set_bit_64(int nr, uint64_t *addr)
{
addr[nr / BITS_PER_UINT64] |= 1ULL << (nr % BITS_PER_UINT64);
}
static inline void atomic_set_bit(int nr, unsigned long *addr)
{
uatomic_or(addr + nr / BITS_PER_LONG, 1UL << (nr % BITS_PER_LONG));
}
static inline int test_bit(unsigned int nr, const unsigned long *addr)
{
return ((1UL << (nr % BITS_PER_LONG)) &
(((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
}
static inline void clear_bit(unsigned int nr, unsigned long *addr)
{
addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
}
/*
* fls64 - find last set bit in a 64-bit word
* @x: the word to search
*
* This is defined in a similar way as the libc and compiler builtin
* ffsll, but returns the position of the most significant set bit.
*
* fls64(value) returns 0 if value is 0 or the position of the last
* set bit if value is nonzero. The last (most significant) bit is
* at position 64.
*/
#if SIZEOF_LONG == 4
static __always_inline int fls64(uint64_t x)
{
uint32_t h = x >> 32;
if (x == 0)
return 0;
if (h)
return 64 - __builtin_clzl(h);
return 32 - __builtin_clzl(x);
}
#elif SIZEOF_LONG == 8
static __always_inline int fls64(uint64_t x)
{
if (x == 0)
return 0;
return 64 - __builtin_clzl(x);
}
#else
#error SIZEOF_LONG not 4 or 8
#endif
#endif /* __BITOPS_H__ */
|