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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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