/// @file dpf/uint256_t.hpp /// @brief Leaf arithmetic for `uint256_t` and the 128-bit SIMD lanes. /// @copyright Copyright (c) 2019-2026 Ryan Henry and [others](@ref authors) /// @license Released under a GNU General Public v2.0 (GPLv2) license. #ifndef LIBDPF_INCLUDE_DPF_UINT256_T_HPP__ #define LIBDPF_INCLUDE_DPF_UINT256_T_HPP__ #include "hedley/hedley.h" #include #include #include "uint256_t/uint256_t.hpp" #include "dpf/utils.hpp" #include "dpf/leaf_arithmetic.hpp" namespace dpf { namespace leaf_arithmetic { HEDLEY_PRAGMA(GCC diagnostic push) HEDLEY_PRAGMA(GCC diagnostic ignored "-Wignored-attributes") template <> struct add_t final { auto operator()(const simde__m128i & lhs, const simde__m128i & rhs) const { simde__m128i ret; uint128_t lhs_, rhs_; std::memcpy(&lhs_, &lhs, sizeof(uint128_t)); std::memcpy(&rhs_, &rhs, sizeof(uint128_t)); uint128_t sum = lhs_ + rhs_; std::memcpy(&ret, &sum, sizeof(simde__m128i)); return ret; } }; template <> struct add_t final { auto operator()(const simde__m256i & lhs, const simde__m256i & rhs) const { simde__m256i ret; uint128_t lhs_[2], rhs_[2]; std::memcpy(&lhs_, &lhs, sizeof(uint128_t) * 2); std::memcpy(&rhs_, &rhs, sizeof(uint128_t) * 2); uint128_t sum[2] = { lhs_[0] + rhs_[0], lhs_[1] + rhs_[1] }; std::memcpy(&ret, &sum, sizeof(simde__m256i)); return ret; } }; template <> struct add_t final { auto operator()(const simde__m256i & lhs, const simde__m256i & rhs) const { simde__m256i ret; uint256_t lhs_, rhs_; std::memcpy(&lhs_, &lhs, sizeof(uint256_t)); std::memcpy(&rhs_, &rhs, sizeof(uint256_t)); uint256_t sum = lhs_ + rhs_; std::memcpy(&ret, &sum, sizeof(simde__m256i)); return ret; } }; template <> struct add_t> final { HEDLEY_ALWAYS_INLINE HEDLEY_NO_THROW HEDLEY_PURE auto operator()(const std::array & a, const std::array & b) const noexcept { std::array c; uint256_t a_, b_; std::memcpy(&a_, std::data(a), sizeof(uint256_t)); std::memcpy(&b_, std::data(b), sizeof(uint256_t)); uint256_t c_ = a_ + b_; std::memcpy(std::data(c), &c_, sizeof(std::array)); return c; } }; template <> struct subtract_t final { auto operator()(const simde__m128i & lhs, const simde__m128i & rhs) const { simde__m128i ret; uint128_t lhs_, rhs_; std::memcpy(&lhs_, &lhs, sizeof(uint128_t)); std::memcpy(&rhs_, &rhs, sizeof(uint128_t)); uint128_t sum = lhs_ - rhs_; std::memcpy(&ret, &sum, sizeof(simde__m128i)); return ret; } }; template <> struct subtract_t final { auto operator()(const simde__m256i & lhs, const simde__m256i & rhs) const { simde__m256i ret; uint128_t lhs_[2], rhs_[2]; std::memcpy(&lhs_, &lhs, sizeof(simde_uint128) * 2); std::memcpy(&rhs_, &rhs, sizeof(simde_uint128) * 2); uint128_t sum[2] = { lhs_[0] - rhs_[0], lhs_[1] - rhs_[1] }; std::memcpy(&ret, &sum, sizeof(simde__m256i)); return ret; } }; template <> struct subtract_t final { auto operator()(const simde__m256i & lhs, const simde__m256i & rhs) const { simde__m256i ret; uint256_t lhs_, rhs_; std::memcpy(&lhs_, &lhs, sizeof(uint256_t)); std::memcpy(&rhs_, &rhs, sizeof(uint256_t)); uint256_t sum = lhs_ - rhs_; std::memcpy(&ret, &sum, sizeof(simde__m256i)); return ret; } }; template <> struct subtract_t> final { auto operator()(const std::array & a, const std::array & b) const { std::array c; uint256_t a_, b_; std::memcpy(&a_, std::data(a), sizeof(uint256_t)); std::memcpy(&b_, std::data(b), sizeof(uint256_t)); uint256_t c_ = a_ - b_; std::memcpy(std::data(c), &c_, sizeof(std::array)); return c; } }; template <> struct multiply_t final { auto operator()(const simde__m128i & a, uint128_t b) const { uint128_t a_; simde__m128i c; std::memcpy(&a_, &a, sizeof(uint128_t)); uint128_t c_ = a_ * b; std::memcpy(&c, &c_, sizeof(simde__m128i)); return c; } }; template <> struct multiply_t> final { auto operator()(const std::array & a, uint256_t b) const { uint256_t a_; std::memcpy(&a_, &a, sizeof(uint256_t)); uint256_t c_ = a_ * b; std::array c; std::memcpy(&c, &c_, sizeof(std::array)); return c; } }; template <> struct multiply_t final { auto operator()(const simde__m256i & a, uint128_t b) const { uint256_t a_; simde__m256i c; std::memcpy(&a_, &a, sizeof(uint256_t)); uint256_t c_{a_.upper() * b, a_.lower() * b}; std::memcpy(&c, &c_, sizeof(simde__m256i)); return c; } }; template <> struct multiply_t final { auto operator()(const simde__m256i & a, uint256_t b) const { uint256_t a_; simde__m256i c; std::memcpy(&a_, &a, sizeof(uint256_t)); uint256_t c_ = a_ * b; std::memcpy(&c, &c_, sizeof(simde__m256i)); return c; } }; HEDLEY_PRAGMA(GCC diagnostic pop) } // namespace leaf_arithmetic namespace utils { template <> struct msb_of { constexpr static uint128_t value{1ul << 63, 0ul}; }; template <> struct msb_of { constexpr static uint256_t value{uint128_t{1ul << 63, 0ul}, uint128_t{0ul, 0ul}}; }; template <> struct mod_pow_2 { HEDLEY_NO_THROW std::size_t operator()(uint128_t val, std::size_t n) const noexcept { return mod_pow_2{}(static_cast(val.lower()), n); } }; template <> struct mod_pow_2 { HEDLEY_NO_THROW std::size_t operator()(uint256_t val, std::size_t n) const noexcept { return mod_pow_2{}(val.lower(), n); } }; template <> struct to_integral_type : to_integral_type_base { using parent = to_integral_type_base; using typename parent::integral_type; HEDLEY_NO_THROW constexpr integral_type operator()(uint128_t val) const noexcept { return (simde_uint128(val.upper()) << 64) | simde_uint128(val.lower()); } }; template <> struct to_integral_type : to_integral_type_base { using parent = to_integral_type_base; using typename parent::integral_type; HEDLEY_NO_THROW constexpr integral_type operator()(uint256_t val) const noexcept { return val; } }; } // namespace dpf::utils } // namespace dpf #endif // LIBDPF_INCLUDE_DPF_UINT256_T_HPP__