15a93b10fSEmil Tsalapatis // SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
25a93b10fSEmil Tsalapatis /*
35a93b10fSEmil Tsalapatis * Copyright (c) 2025-2026 Meta Platforms, Inc. and affiliates.
45a93b10fSEmil Tsalapatis * Copyright (c) 2025-2026 Emil Tsalapatis <emil@etsalapatis.com>
55a93b10fSEmil Tsalapatis */
65a93b10fSEmil Tsalapatis
75a93b10fSEmil Tsalapatis #include <libarena/common.h>
85a93b10fSEmil Tsalapatis
95a93b10fSEmil Tsalapatis #include <libarena/asan.h>
105a93b10fSEmil Tsalapatis #include <libarena/bitmap.h>
115a93b10fSEmil Tsalapatis
125a93b10fSEmil Tsalapatis __weak
bmp_alloc(size_t bits)13*ee1bcf82SYonghong Song struct arena_bitmap __arena *bmp_alloc(size_t bits)
145a93b10fSEmil Tsalapatis {
15*ee1bcf82SYonghong Song struct arena_bitmap __arena *bmp;
165a93b10fSEmil Tsalapatis size_t size = BITS_TO_LONG_LONGS(bits) * sizeof(bmp->bits[0]);
175a93b10fSEmil Tsalapatis
185a93b10fSEmil Tsalapatis /* Assume long-aligned masks. */
195a93b10fSEmil Tsalapatis if (bits % BITS_PER_LONG_LONG)
205a93b10fSEmil Tsalapatis return NULL;
215a93b10fSEmil Tsalapatis
22*ee1bcf82SYonghong Song bmp = (struct arena_bitmap __arena *)arena_malloc(size);
235a93b10fSEmil Tsalapatis if (!bmp)
245a93b10fSEmil Tsalapatis return NULL;
255a93b10fSEmil Tsalapatis
265a93b10fSEmil Tsalapatis bmp_clear(bits, bmp);
275a93b10fSEmil Tsalapatis
285a93b10fSEmil Tsalapatis return bmp;
295a93b10fSEmil Tsalapatis }
305a93b10fSEmil Tsalapatis
315a93b10fSEmil Tsalapatis __weak
bmp_free(struct arena_bitmap __arena * bmp)32*ee1bcf82SYonghong Song void bmp_free(struct arena_bitmap __arena *bmp)
335a93b10fSEmil Tsalapatis {
345a93b10fSEmil Tsalapatis arena_free(bmp);
355a93b10fSEmil Tsalapatis }
365a93b10fSEmil Tsalapatis
375a93b10fSEmil Tsalapatis __weak
__bmp_set_bit(u32 bit,struct arena_bitmap __arena * bmp)38*ee1bcf82SYonghong Song void __bmp_set_bit(u32 bit, struct arena_bitmap __arena *bmp)
395a93b10fSEmil Tsalapatis {
405a93b10fSEmil Tsalapatis bmp->bits[BIT_WORD(bit)] |= BIT_MASK(bit);
415a93b10fSEmil Tsalapatis }
425a93b10fSEmil Tsalapatis
435a93b10fSEmil Tsalapatis __weak
__bmp_clear_bit(u32 bit,struct arena_bitmap __arena * bmp)44*ee1bcf82SYonghong Song void __bmp_clear_bit(u32 bit, struct arena_bitmap __arena *bmp)
455a93b10fSEmil Tsalapatis {
465a93b10fSEmil Tsalapatis bmp->bits[BIT_WORD(bit)] &= ~BIT_MASK(bit);
475a93b10fSEmil Tsalapatis }
485a93b10fSEmil Tsalapatis
495a93b10fSEmil Tsalapatis __weak
bmp_test_bit(u32 bit,struct arena_bitmap __arena * bmp)50*ee1bcf82SYonghong Song bool bmp_test_bit(u32 bit, struct arena_bitmap __arena *bmp)
515a93b10fSEmil Tsalapatis {
525a93b10fSEmil Tsalapatis return bmp->bits[BIT_WORD(bit)] & BIT_MASK(bit);
535a93b10fSEmil Tsalapatis }
545a93b10fSEmil Tsalapatis
555a93b10fSEmil Tsalapatis __weak
bmp_test_and_clear_bit(u32 bit,struct arena_bitmap __arena * bmp)56*ee1bcf82SYonghong Song bool bmp_test_and_clear_bit(u32 bit, struct arena_bitmap __arena *bmp)
575a93b10fSEmil Tsalapatis {
585a93b10fSEmil Tsalapatis u64 val = BIT_MASK(bit);
595a93b10fSEmil Tsalapatis u32 idx = BIT_WORD(bit);
605a93b10fSEmil Tsalapatis u64 old, new, actual;
615a93b10fSEmil Tsalapatis
625a93b10fSEmil Tsalapatis do {
635a93b10fSEmil Tsalapatis old = bmp->bits[idx];
645a93b10fSEmil Tsalapatis
655a93b10fSEmil Tsalapatis if (!(old & val))
665a93b10fSEmil Tsalapatis return false;
675a93b10fSEmil Tsalapatis
685a93b10fSEmil Tsalapatis new = old & ~val;
695a93b10fSEmil Tsalapatis actual = cmpxchg(&bmp->bits[idx], old, new);
705a93b10fSEmil Tsalapatis
715a93b10fSEmil Tsalapatis if (actual == old)
725a93b10fSEmil Tsalapatis return true;
735a93b10fSEmil Tsalapatis
745a93b10fSEmil Tsalapatis } while (can_loop);
755a93b10fSEmil Tsalapatis
765a93b10fSEmil Tsalapatis return false;
775a93b10fSEmil Tsalapatis }
785a93b10fSEmil Tsalapatis
795a93b10fSEmil Tsalapatis __weak
bmp_test_and_set_bit(u32 bit,struct arena_bitmap __arena * bmp)80*ee1bcf82SYonghong Song bool bmp_test_and_set_bit(u32 bit, struct arena_bitmap __arena *bmp)
815a93b10fSEmil Tsalapatis {
825a93b10fSEmil Tsalapatis u64 val = BIT_MASK(bit);
835a93b10fSEmil Tsalapatis u32 idx = BIT_WORD(bit);
845a93b10fSEmil Tsalapatis u64 old, new, actual;
855a93b10fSEmil Tsalapatis
865a93b10fSEmil Tsalapatis do {
875a93b10fSEmil Tsalapatis old = bmp->bits[idx];
885a93b10fSEmil Tsalapatis
895a93b10fSEmil Tsalapatis if ((old & val))
905a93b10fSEmil Tsalapatis return true;
915a93b10fSEmil Tsalapatis
925a93b10fSEmil Tsalapatis new = old | val;
935a93b10fSEmil Tsalapatis actual = cmpxchg(&bmp->bits[idx], old, new);
945a93b10fSEmil Tsalapatis
955a93b10fSEmil Tsalapatis if (actual == old)
965a93b10fSEmil Tsalapatis return false;
975a93b10fSEmil Tsalapatis
985a93b10fSEmil Tsalapatis } while (can_loop);
995a93b10fSEmil Tsalapatis
1005a93b10fSEmil Tsalapatis return false;
1015a93b10fSEmil Tsalapatis }
1025a93b10fSEmil Tsalapatis
1035a93b10fSEmil Tsalapatis __weak
bmp_clear_bit(u32 bit,struct arena_bitmap __arena * bmp)104*ee1bcf82SYonghong Song void bmp_clear_bit(u32 bit, struct arena_bitmap __arena *bmp)
1055a93b10fSEmil Tsalapatis {
1065a93b10fSEmil Tsalapatis u64 val = BIT_MASK(bit);
1075a93b10fSEmil Tsalapatis u32 idx = BIT_WORD(bit);
1085a93b10fSEmil Tsalapatis u64 old, new, actual;
1095a93b10fSEmil Tsalapatis
1105a93b10fSEmil Tsalapatis do {
1115a93b10fSEmil Tsalapatis old = bmp->bits[idx];
1125a93b10fSEmil Tsalapatis new = old & ~val;
1135a93b10fSEmil Tsalapatis actual = cmpxchg(&bmp->bits[idx], old, new);
1145a93b10fSEmil Tsalapatis
1155a93b10fSEmil Tsalapatis } while (actual != old && can_loop);
1165a93b10fSEmil Tsalapatis }
1175a93b10fSEmil Tsalapatis
1185a93b10fSEmil Tsalapatis __weak
bmp_set_bit(u32 bit,struct arena_bitmap __arena * bmp)119*ee1bcf82SYonghong Song void bmp_set_bit(u32 bit, struct arena_bitmap __arena *bmp)
1205a93b10fSEmil Tsalapatis {
1215a93b10fSEmil Tsalapatis u64 val = BIT_MASK(bit);
1225a93b10fSEmil Tsalapatis u32 idx = BIT_WORD(bit);
1235a93b10fSEmil Tsalapatis u64 old, new, actual;
1245a93b10fSEmil Tsalapatis
1255a93b10fSEmil Tsalapatis do {
1265a93b10fSEmil Tsalapatis old = bmp->bits[idx];
1275a93b10fSEmil Tsalapatis new = old | val;
1285a93b10fSEmil Tsalapatis actual = cmpxchg(&bmp->bits[idx], old, new);
1295a93b10fSEmil Tsalapatis
1305a93b10fSEmil Tsalapatis } while (actual != old && can_loop);
1315a93b10fSEmil Tsalapatis }
1325a93b10fSEmil Tsalapatis
1335a93b10fSEmil Tsalapatis __weak
bmp_clear(size_t bits,struct arena_bitmap __arena * bmp)134*ee1bcf82SYonghong Song void bmp_clear(size_t bits, struct arena_bitmap __arena *bmp)
1355a93b10fSEmil Tsalapatis {
1365a93b10fSEmil Tsalapatis size_t nwords = BITS_TO_LONG_LONGS(bits);
1375a93b10fSEmil Tsalapatis volatile u32 i;
1385a93b10fSEmil Tsalapatis
1395a93b10fSEmil Tsalapatis for (i = zero; i < nwords && can_loop; i++)
1405a93b10fSEmil Tsalapatis bmp->bits[i] = 0;
1415a93b10fSEmil Tsalapatis }
1425a93b10fSEmil Tsalapatis
bmp_last_word_mask(size_t bits)1435a93b10fSEmil Tsalapatis static __always_inline u64 bmp_last_word_mask(size_t bits)
1445a93b10fSEmil Tsalapatis {
1455a93b10fSEmil Tsalapatis u32 rem = bits % BITS_PER_LONG_LONG;
1465a93b10fSEmil Tsalapatis
1475a93b10fSEmil Tsalapatis return rem ? (1ULL << rem) - 1 : ~0ULL;
1485a93b10fSEmil Tsalapatis }
1495a93b10fSEmil Tsalapatis
1505a93b10fSEmil Tsalapatis __weak
bmp_and(size_t bits,struct arena_bitmap __arena * dst,struct arena_bitmap __arena * src1,struct arena_bitmap __arena * src2)151*ee1bcf82SYonghong Song void bmp_and(size_t bits, struct arena_bitmap __arena *dst, struct arena_bitmap __arena *src1, struct arena_bitmap __arena *src2)
1525a93b10fSEmil Tsalapatis {
1535a93b10fSEmil Tsalapatis size_t nwords = BITS_TO_LONG_LONGS(bits);
1545a93b10fSEmil Tsalapatis volatile u32 i;
1555a93b10fSEmil Tsalapatis
1565a93b10fSEmil Tsalapatis for (i = zero; i < nwords && can_loop; i++)
1575a93b10fSEmil Tsalapatis dst->bits[i] = src1->bits[i] & src2->bits[i];
1585a93b10fSEmil Tsalapatis
1595a93b10fSEmil Tsalapatis if (nwords && bits % BITS_PER_LONG_LONG)
1605a93b10fSEmil Tsalapatis dst->bits[nwords - 1] &= bmp_last_word_mask(bits);
1615a93b10fSEmil Tsalapatis }
1625a93b10fSEmil Tsalapatis
1635a93b10fSEmil Tsalapatis __weak
bmp_or(size_t bits,struct arena_bitmap __arena * dst,struct arena_bitmap __arena * src1,struct arena_bitmap __arena * src2)164*ee1bcf82SYonghong Song void bmp_or(size_t bits, struct arena_bitmap __arena *dst, struct arena_bitmap __arena *src1, struct arena_bitmap __arena *src2)
1655a93b10fSEmil Tsalapatis {
1665a93b10fSEmil Tsalapatis size_t nwords = BITS_TO_LONG_LONGS(bits);
1675a93b10fSEmil Tsalapatis volatile u32 i;
1685a93b10fSEmil Tsalapatis
1695a93b10fSEmil Tsalapatis for (i = zero; i < nwords && can_loop; i++)
1705a93b10fSEmil Tsalapatis dst->bits[i] = src1->bits[i] | src2->bits[i];
1715a93b10fSEmil Tsalapatis
1725a93b10fSEmil Tsalapatis if (nwords && bits % BITS_PER_LONG_LONG)
1735a93b10fSEmil Tsalapatis dst->bits[nwords - 1] &= bmp_last_word_mask(bits);
1745a93b10fSEmil Tsalapatis }
1755a93b10fSEmil Tsalapatis
1765a93b10fSEmil Tsalapatis __weak
bmp_empty(size_t bits,struct arena_bitmap __arena * bmp)177*ee1bcf82SYonghong Song bool bmp_empty(size_t bits, struct arena_bitmap __arena *bmp)
1785a93b10fSEmil Tsalapatis {
1795a93b10fSEmil Tsalapatis size_t nwords = BITS_TO_LONG_LONGS(bits);
1805a93b10fSEmil Tsalapatis volatile u32 i;
1815a93b10fSEmil Tsalapatis
1825a93b10fSEmil Tsalapatis for (i = zero; i < nwords && can_loop; i++) {
1835a93b10fSEmil Tsalapatis u64 mask = (i == nwords - 1) ? bmp_last_word_mask(bits) : ~0ULL;
1845a93b10fSEmil Tsalapatis
1855a93b10fSEmil Tsalapatis if (bmp->bits[i] & mask)
1865a93b10fSEmil Tsalapatis return false;
1875a93b10fSEmil Tsalapatis }
1885a93b10fSEmil Tsalapatis
1895a93b10fSEmil Tsalapatis return true;
1905a93b10fSEmil Tsalapatis }
1915a93b10fSEmil Tsalapatis
1925a93b10fSEmil Tsalapatis __weak
bmp_copy(size_t bits,struct arena_bitmap __arena * dst,struct arena_bitmap __arena * src)193*ee1bcf82SYonghong Song void bmp_copy(size_t bits, struct arena_bitmap __arena *dst, struct arena_bitmap __arena *src)
1945a93b10fSEmil Tsalapatis {
1955a93b10fSEmil Tsalapatis size_t nwords = BITS_TO_LONG_LONGS(bits);
1965a93b10fSEmil Tsalapatis volatile u32 i;
1975a93b10fSEmil Tsalapatis
1985a93b10fSEmil Tsalapatis for (i = zero; i < nwords && can_loop; i++)
1995a93b10fSEmil Tsalapatis dst->bits[i] = src->bits[i];
2005a93b10fSEmil Tsalapatis
2015a93b10fSEmil Tsalapatis if (nwords && bits % BITS_PER_LONG_LONG)
2025a93b10fSEmil Tsalapatis dst->bits[nwords - 1] &= bmp_last_word_mask(bits);
2035a93b10fSEmil Tsalapatis }
2045a93b10fSEmil Tsalapatis
2055a93b10fSEmil Tsalapatis __weak
bmp_subset(size_t bits,struct arena_bitmap __arena * big,struct arena_bitmap __arena * small)206*ee1bcf82SYonghong Song bool bmp_subset(size_t bits, struct arena_bitmap __arena *big, struct arena_bitmap __arena *small)
2075a93b10fSEmil Tsalapatis {
2085a93b10fSEmil Tsalapatis size_t nwords = BITS_TO_LONG_LONGS(bits);
2095a93b10fSEmil Tsalapatis volatile u32 i;
2105a93b10fSEmil Tsalapatis
2115a93b10fSEmil Tsalapatis for (i = zero; i < nwords && can_loop; i++) {
2125a93b10fSEmil Tsalapatis u64 mask = (i == nwords - 1) ? bmp_last_word_mask(bits) : ~0ULL;
2135a93b10fSEmil Tsalapatis
2145a93b10fSEmil Tsalapatis if (~big->bits[i] & small->bits[i] & mask)
2155a93b10fSEmil Tsalapatis return false;
2165a93b10fSEmil Tsalapatis }
2175a93b10fSEmil Tsalapatis
2185a93b10fSEmil Tsalapatis return true;
2195a93b10fSEmil Tsalapatis }
2205a93b10fSEmil Tsalapatis
2215a93b10fSEmil Tsalapatis __weak
bmp_intersects(size_t bits,struct arena_bitmap __arena * arg1,struct arena_bitmap __arena * arg2)222*ee1bcf82SYonghong Song bool bmp_intersects(size_t bits, struct arena_bitmap __arena *arg1, struct arena_bitmap __arena *arg2)
2235a93b10fSEmil Tsalapatis {
2245a93b10fSEmil Tsalapatis size_t nwords = BITS_TO_LONG_LONGS(bits);
2255a93b10fSEmil Tsalapatis volatile u32 i;
2265a93b10fSEmil Tsalapatis
2275a93b10fSEmil Tsalapatis for (i = zero; i < nwords && can_loop; i++) {
2285a93b10fSEmil Tsalapatis u64 mask = (i == nwords - 1) ? bmp_last_word_mask(bits) : ~0ULL;
2295a93b10fSEmil Tsalapatis
2305a93b10fSEmil Tsalapatis if (arg1->bits[i] & arg2->bits[i] & mask)
2315a93b10fSEmil Tsalapatis return true;
2325a93b10fSEmil Tsalapatis }
2335a93b10fSEmil Tsalapatis
2345a93b10fSEmil Tsalapatis return false;
2355a93b10fSEmil Tsalapatis }
2365a93b10fSEmil Tsalapatis
2375a93b10fSEmil Tsalapatis __weak
bmp_print(size_t bits,struct arena_bitmap __arena * bmp)238*ee1bcf82SYonghong Song void bmp_print(size_t bits, struct arena_bitmap __arena *bmp)
2395a93b10fSEmil Tsalapatis {
2405a93b10fSEmil Tsalapatis size_t nwords = BITS_TO_LONG_LONGS(bits);
2415a93b10fSEmil Tsalapatis volatile u32 i;
2425a93b10fSEmil Tsalapatis
2435a93b10fSEmil Tsalapatis for (i = zero; i < nwords && can_loop; i++)
2445a93b10fSEmil Tsalapatis arena_stderr("%016llx ", bmp->bits[i]);
2455a93b10fSEmil Tsalapatis }
246