Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 27 additions & 37 deletions src/ds/bits.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,9 @@ namespace snmalloc
* Map large range of strictly positive integers
* into an exponent and mantissa pair.
*
* The reverse mapping is given as:
* The reverse mapping is given by first adding one to the value, and then
* extracting the bottom MANTISSA bits as m, and the rest as e.
* Then each value maps as:
*
* e | m | value
* ---------------------------------
Expand All @@ -391,70 +393,58 @@ namespace snmalloc
* smallest exponent and mantissa with a
* reverse mapping not less than the value.
*
* The e and m in the forward mapping and reverse are not the same, and the
* initial increment in from_exp_mant and the decrement in to_exp_mant
* handle the different ways it is calculating and using the split.
* This is due to the rounding of bits below the mantissa in the
* representation, which is confusing but leads to the fastest code.
*
* Does not work for value=0.
***********************************************/
template<size_t MANTISSA_BITS, size_t LOW_BITS = 0>
static size_t to_exp_mant(size_t value)
{
value += ((size_t)1 << (LOW_BITS)) - 1;
value >>= LOW_BITS;

if (MANTISSA_BITS > 0)
{
size_t LEADING_BIT = ((size_t)1 << MANTISSA_BITS) >> 1;
size_t MANTISSA_MASK = ((size_t)1 << MANTISSA_BITS) - 1;
size_t LEADING_BIT = ((size_t)1 << (MANTISSA_BITS + LOW_BITS)) >> 1;
size_t MANTISSA_MASK = ((size_t)1 << MANTISSA_BITS) - 1;

value = value - 1;
value = value - 1;

size_t e = (bits::BITS - clz(value | LEADING_BIT)) - MANTISSA_BITS;
size_t shift_e = (e == 0) ? 0 : e - 1;
size_t m = (value >> shift_e) & MANTISSA_MASK;
size_t e =
bits::BITS - MANTISSA_BITS - LOW_BITS - clz(value | LEADING_BIT);
size_t b = (e == 0) ? 0 : 1;
size_t m = (value >> (LOW_BITS + e - b)) & MANTISSA_MASK;

return (e << MANTISSA_BITS) + m;
}
else
{
return bits::next_pow2_bits(value);
}
return (e << MANTISSA_BITS) + m;
}

template<size_t MANTISSA_BITS, size_t LOW_BITS = 0>
constexpr static size_t to_exp_mant_const(size_t value)
{
value += ((size_t)1 << LOW_BITS) - 1;
value >>= LOW_BITS;
size_t LEADING_BIT = ((size_t)1 << (MANTISSA_BITS + LOW_BITS)) >> 1;
size_t MANTISSA_MASK = ((size_t)1 << MANTISSA_BITS) - 1;

if (MANTISSA_BITS > 0)
{
size_t LEADING_BIT = (size_t)1 << (MANTISSA_BITS - 1);
size_t MANTISSA_MASK = ((size_t)1 << MANTISSA_BITS) - 1;

value = value - 1;
value = value - 1;

size_t e =
(bits::BITS - clz_const(value | LEADING_BIT)) - MANTISSA_BITS;
size_t shift_e = (e == 0) ? 0 : e - 1;
size_t m = (value >> shift_e) & MANTISSA_MASK;
size_t e =
bits::BITS - MANTISSA_BITS - LOW_BITS - clz_const(value | LEADING_BIT);
size_t b = (e == 0) ? 0 : 1;
size_t m = (value >> (LOW_BITS + e - b)) & MANTISSA_MASK;

return (e << MANTISSA_BITS) + m;
}
else
{
return bits::next_pow2_bits_const(value);
}
return (e << MANTISSA_BITS) + m;
}

template<size_t MANTISSA_BITS, size_t LOW_BITS = 0>
constexpr static size_t from_exp_mant(size_t m_e)
{
if (MANTISSA_BITS > 0)
{
m_e = m_e + 1;
size_t MANTISSA_MASK = ((size_t)1 << MANTISSA_BITS) - 1;
size_t m = m_e & MANTISSA_MASK;
size_t e = m_e >> MANTISSA_BITS;
size_t b = e == 0 ? 0 : 1;
size_t shifted_e = e - b;
size_t extended_m = (m + ((size_t)b << MANTISSA_BITS)) + 1;
size_t extended_m = (m + ((size_t)b << MANTISSA_BITS));
return extended_m << (shifted_e + LOW_BITS);
}
else
Expand Down
53 changes: 53 additions & 0 deletions src/test/func/sizeclass/sizeclass.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include <iostream>
#include <snmalloc.h>

NOINLINE
uint8_t size_to_sizeclass(size_t size)
{
return snmalloc::size_to_sizeclass(size);
}

int main(int, char**)
{
bool failed = false;
size_t size_low = 0;

std::cout << "0 has sizeclass: " << (size_t)snmalloc::size_to_sizeclass(0)
<< std::endl;

std::cout << "sizeclass |-> [size_low, size_high] " << std::endl;

for (uint8_t sz = 0; sz < snmalloc::NUM_SIZECLASSES; sz++)
{
// Separate printing for small and medium sizeclasses
if (sz == snmalloc::NUM_SMALL_CLASSES)
std::cout << std::endl;

size_t size = snmalloc::sizeclass_to_size(sz);
std::cout << (size_t)sz << " |-> "
<< "[" << size_low + 1 << ", " << size << "]" << std::endl;

if (size < size_low)
{
std::cout << "Sizeclass " << (size_t)sz << " is " << size
<< " which is less than " << size_low << std::endl;
failed = true;
}

for (size_t i = size_low + 1; i <= size; i++)
{
if (size_to_sizeclass(i) != sz)
{
std::cout << "Size " << i << " has sizeclass "
<< (size_t)size_to_sizeclass(i) << " but expected sizeclass "
<< (size_t)sz << std::endl;
failed = true;
}
}

size_low = size;
}

if (failed)
abort();
}