2011-08-29 14:38:47 +10:00
|
|
|
/*
|
2018-08-04 15:14:06 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2011-08-29 14:38:47 +10:00
|
|
|
*
|
2018-03-20 13:34:19 +11:00
|
|
|
* Copyright 2011-2018 Danny Robson <danny@nerdcruft.net>
|
2011-08-29 14:38:47 +10:00
|
|
|
*/
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
#pragma once
|
2018-03-20 13:34:19 +11:00
|
|
|
|
2019-05-17 12:26:08 +10:00
|
|
|
#include "debug/assert.hpp"
|
2011-08-29 14:38:47 +10:00
|
|
|
|
2021-01-20 15:18:25 +11:00
|
|
|
#include <tuple>
|
2016-10-11 23:47:57 +11:00
|
|
|
#include <type_traits>
|
2021-01-20 15:18:25 +11:00
|
|
|
|
2011-08-29 14:38:47 +10:00
|
|
|
#include <cstdint>
|
|
|
|
|
2012-01-04 17:06:57 +11:00
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
namespace cruft {
|
2016-10-11 23:47:57 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2018-12-15 15:36:28 +11:00
|
|
|
/// Rotate `value` left by `magnitude` bits.
|
|
|
|
///
|
|
|
|
/// `magnitude` must not be greater than the bit count of `value`.
|
2016-10-11 23:47:57 +11:00
|
|
|
template <typename T>
|
|
|
|
constexpr T
|
|
|
|
rotatel [[gnu::pure]] (const T value, std::size_t magnitude)
|
|
|
|
{
|
2019-04-26 10:27:22 +10:00
|
|
|
CHECK_LT (magnitude, sizeof (value) * 8u);
|
2018-12-15 15:36:28 +11:00
|
|
|
|
2018-03-27 20:16:32 +11:00
|
|
|
return (value << magnitude) | (value >> (sizeof (value) * 8 - magnitude));
|
2016-10-11 23:47:57 +11:00
|
|
|
}
|
2012-01-04 17:06:57 +11:00
|
|
|
|
2014-04-16 19:15:54 +10:00
|
|
|
|
2018-12-15 15:36:28 +11:00
|
|
|
///------------------------------------------------------------------------
|
|
|
|
/// Rotate `value` right by `magnitude` bits.
|
|
|
|
///
|
|
|
|
/// `magnitude` must not be greater than the bit count of `value`.
|
2016-10-11 23:47:57 +11:00
|
|
|
template <typename T>
|
|
|
|
constexpr T
|
|
|
|
rotater [[gnu::pure]] (const T value, std::size_t magnitude)
|
|
|
|
{
|
2019-04-26 10:27:22 +10:00
|
|
|
CHECK_LT (magnitude, sizeof (value) * 8);
|
2018-12-15 15:36:28 +11:00
|
|
|
|
2018-03-27 20:16:32 +11:00
|
|
|
return (value >> magnitude) | (value << (sizeof (value) * 8 - magnitude));
|
2016-10-11 23:47:57 +11:00
|
|
|
}
|
2014-04-16 19:15:54 +10:00
|
|
|
|
2015-11-25 13:46:13 +11:00
|
|
|
|
2016-10-11 23:47:57 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2018-12-15 15:36:28 +11:00
|
|
|
/// Reverse the order of bits in the supplied value.
|
|
|
|
///
|
|
|
|
/// Adapted from 'bit twiddling hacks'
|
2016-10-11 23:47:57 +11:00
|
|
|
template <typename T>
|
2017-02-13 17:14:30 +11:00
|
|
|
constexpr
|
|
|
|
std::enable_if_t<std::is_integral<T>::value, T>
|
|
|
|
reverse (T src)
|
|
|
|
{
|
|
|
|
T dst = src; // dst will be reversed bits of v; first get LSB of v
|
|
|
|
|
|
|
|
int bits = sizeof (src) * 8 - 1; // extra shift needed at end
|
|
|
|
for (src >>= 1; src; src >>= 1) {
|
|
|
|
dst <<= 1;
|
|
|
|
dst |= src & 1;
|
|
|
|
bits--;
|
2016-10-11 23:47:57 +11:00
|
|
|
}
|
2014-07-15 19:49:29 +10:00
|
|
|
|
2017-02-13 17:14:30 +11:00
|
|
|
dst <<= bits; // shift when src's highest bits are zero
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2018-12-15 15:36:28 +11:00
|
|
|
/// Reverse the order of bits in the supplied value.
|
|
|
|
///
|
|
|
|
/// Adapted from 'bit twiddling hacks'
|
2017-02-13 17:14:30 +11:00
|
|
|
template <>
|
|
|
|
constexpr
|
|
|
|
uint8_t
|
|
|
|
reverse (uint8_t val)
|
|
|
|
{
|
|
|
|
return ((val * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
|
2016-10-11 23:47:57 +11:00
|
|
|
}
|
2014-07-15 19:49:29 +10:00
|
|
|
|
2015-11-25 13:46:13 +11:00
|
|
|
|
2016-10-11 23:47:57 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2018-12-15 15:36:28 +11:00
|
|
|
/// Calculates the number of bits that are set.
|
2018-12-06 15:56:37 +11:00
|
|
|
constexpr unsigned
|
2019-09-11 07:41:09 +10:00
|
|
|
popcount (unsigned char t)
|
|
|
|
{
|
|
|
|
return __builtin_popcount (t);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
|
|
/// Calculates the number of bits that are set.
|
|
|
|
constexpr unsigned
|
|
|
|
popcount (unsigned short t)
|
|
|
|
{
|
|
|
|
return __builtin_popcount (t);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///------------------------------------------------------------------------
|
|
|
|
/// Calculates the number of bits that are set.
|
|
|
|
constexpr unsigned
|
2018-12-06 15:56:37 +11:00
|
|
|
popcount (unsigned t)
|
2016-10-11 23:47:57 +11:00
|
|
|
{
|
|
|
|
return __builtin_popcount (t);
|
|
|
|
}
|
2018-03-20 13:34:19 +11:00
|
|
|
|
|
|
|
|
2018-12-15 15:36:28 +11:00
|
|
|
///------------------------------------------------------------------------
|
|
|
|
/// Calculates the number of bits that are set.
|
2018-12-06 15:56:37 +11:00
|
|
|
constexpr unsigned long
|
|
|
|
popcount (unsigned long t)
|
|
|
|
{
|
|
|
|
return __builtin_popcountl (t);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-15 15:36:28 +11:00
|
|
|
///------------------------------------------------------------------------
|
|
|
|
/// Calculates the number of bits that are set.
|
2018-12-06 15:56:37 +11:00
|
|
|
constexpr unsigned long long
|
|
|
|
popcount (unsigned long long t)
|
|
|
|
{
|
|
|
|
return __builtin_popcountll (t);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-24 13:25:44 +10:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
/// Count trailing zeroes
|
|
|
|
constexpr unsigned int
|
|
|
|
ctz (unsigned int x) noexcept
|
|
|
|
{
|
|
|
|
return __builtin_ctz (x);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
constexpr unsigned long
|
|
|
|
ctz (unsigned long x) noexcept
|
|
|
|
{
|
|
|
|
return __builtin_ctzl (x);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
constexpr unsigned long long
|
|
|
|
ctz (unsigned long long x) noexcept
|
|
|
|
{
|
|
|
|
return __builtin_ctzll (x);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-03 16:32:47 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace bits {
|
|
|
|
inline constexpr std::tuple<u32, u32> halve (u64 val)
|
|
|
|
{
|
|
|
|
return { val >> 32, val & 0xffffffff };
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
inline constexpr std::tuple<u16, u16> halve (u32 val)
|
|
|
|
{
|
|
|
|
return { val >> 16, val & 0xffff };
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
inline constexpr std::tuple<u08, u08> halve (u16 val)
|
|
|
|
{
|
|
|
|
return { val >> 8, val & 0xff };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-20 13:34:19 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
/// returns the integral value composed of the bits from `val' in the
|
|
|
|
/// inclusive range [lo, hi].
|
|
|
|
template <typename ValueT, typename IndexT>
|
|
|
|
constexpr ValueT
|
|
|
|
from_bits (ValueT val, IndexT hi, IndexT lo)
|
|
|
|
{
|
|
|
|
CHECK_LT (hi, IndexT (sizeof (ValueT) * 8));
|
|
|
|
CHECK_LT (lo, IndexT (sizeof (ValueT) * 8));
|
|
|
|
CHECK_GE (hi, 0);
|
|
|
|
CHECK_GE (lo, 1);
|
|
|
|
CHECK_GE (hi, lo);
|
|
|
|
|
|
|
|
ValueT zero = 0;
|
|
|
|
ValueT ones = ~zero;
|
|
|
|
|
|
|
|
return (val >> lo) & (ones >> (sizeof (ValueT) * 8 - (hi - lo + 1)));
|
|
|
|
}
|
2018-12-15 15:36:51 +11:00
|
|
|
|
|
|
|
|
2018-12-26 15:10:21 +11:00
|
|
|
/// A convenience wrapper that provides access to a range of bits in an
|
|
|
|
/// underlying integral value.
|
|
|
|
///
|
|
|
|
/// This class is most useful as part of a union where each has differing
|
|
|
|
/// offsets and sizes that cover the underlying type.
|
|
|
|
///
|
|
|
|
/// A conversion operator is supplied for accessing the bit value.
|
|
|
|
///
|
|
|
|
/// ValueT must support bit shifting and bitwise operators (primarily
|
|
|
|
/// bitwise and).
|
|
|
|
///
|
|
|
|
/// \tparam ValueT the underlying integral type
|
|
|
|
/// \tparam OffsetV the index of the first bit of the range (where 0 is
|
2019-02-03 13:52:56 +11:00
|
|
|
/// least significant)
|
2018-12-26 15:10:21 +11:00
|
|
|
/// \tparam SizeV the number of bits in the range. Must be strictly
|
|
|
|
/// positive.
|
2018-12-15 15:36:51 +11:00
|
|
|
template <
|
|
|
|
typename ValueT,
|
|
|
|
size_t OffsetV,
|
|
|
|
size_t SizeV
|
|
|
|
>
|
2019-02-03 13:52:56 +11:00
|
|
|
class [[gnu::packed]] bitfield {
|
2018-12-15 15:36:51 +11:00
|
|
|
public:
|
|
|
|
static_assert (SizeV > 0);
|
|
|
|
static_assert (OffsetV + SizeV <= sizeof (ValueT) * 8);
|
|
|
|
|
2019-02-03 14:16:58 +11:00
|
|
|
constexpr ValueT get (void) const
|
2018-12-15 15:36:51 +11:00
|
|
|
{
|
2019-02-03 14:16:58 +11:00
|
|
|
auto const MASK = ~(~0u << SizeV);
|
2019-02-03 16:38:40 +11:00
|
|
|
ValueT shifted = value >> OffsetV;
|
|
|
|
ValueT masked = shifted & MASK;
|
|
|
|
return masked;
|
2018-12-15 15:36:51 +11:00
|
|
|
}
|
|
|
|
|
2019-02-03 16:38:40 +11:00
|
|
|
operator ValueT () const { return get (); }
|
2019-02-03 14:16:58 +11:00
|
|
|
|
2019-02-03 16:38:40 +11:00
|
|
|
auto operator+ () const { return +get (); }
|
2019-02-03 14:16:58 +11:00
|
|
|
|
2018-12-15 15:36:51 +11:00
|
|
|
ValueT value;
|
|
|
|
};
|
|
|
|
|
2019-02-03 16:38:40 +11:00
|
|
|
template <typename OperandT, typename BitfieldT, size_t OffsetV, size_t SizeV>
|
|
|
|
bool operator== (bitfield<BitfieldT,OffsetV,SizeV> const &a, OperandT const &b)
|
|
|
|
{
|
|
|
|
return a.get () == b;
|
|
|
|
}
|
|
|
|
|
2018-12-15 15:36:51 +11:00
|
|
|
|
|
|
|
template <typename ValueT, size_t Offset, size_t Size>
|
|
|
|
std::ostream& operator<< (std::ostream &os, bitfield<ValueT,Offset,Size> const &val)
|
|
|
|
{
|
|
|
|
return os << +ValueT(val);
|
|
|
|
}
|
2018-12-26 15:10:21 +11:00
|
|
|
}
|