From 5ffe23e4f3fa973af7ae24d27aa40acf24a552c2 Mon Sep 17 00:00:00 2001 From: Hendiadyoin1 Date: Wed, 19 May 2021 23:04:48 +0200 Subject: [PATCH] AK+LibX86: Generalize u128/256 to AK::UFixedBigInt Doing these as custom classes might be faster, especially when writing them in SSE, but this would cause a lot of Code duplication and due to the nature of constexprs and the intelligence of the compiler they might be using SSE/MMX either way --- AK/UFixedBigInt.h | 771 ++++++++++++++++++ Tests/AK/CMakeLists.txt | 1 + Tests/AK/TestUFixedBigInt.cpp | 127 +++ Userland/DevTools/UserspaceEmulator/Region.h | 2 +- .../DevTools/UserspaceEmulator/SoftCPU.cpp | 7 +- .../UserspaceEmulator/ValueWithShadow.h | 2 +- Userland/Libraries/LibX86/CMakeLists.txt | 1 - Userland/Libraries/LibX86/Types.h | 10 - Userland/Libraries/LibX86/Types/Formatter.cpp | 113 --- Userland/Libraries/LibX86/Types/u128.h | 268 ------ Userland/Libraries/LibX86/Types/u256.h | 268 ------ 11 files changed, 905 insertions(+), 665 deletions(-) create mode 100644 AK/UFixedBigInt.h create mode 100644 Tests/AK/TestUFixedBigInt.cpp delete mode 100644 Userland/Libraries/LibX86/Types.h delete mode 100644 Userland/Libraries/LibX86/Types/Formatter.cpp delete mode 100644 Userland/Libraries/LibX86/Types/u128.h delete mode 100644 Userland/Libraries/LibX86/Types/u256.h diff --git a/AK/UFixedBigInt.h b/AK/UFixedBigInt.h new file mode 100644 index 0000000000..d1dc13eba9 --- /dev/null +++ b/AK/UFixedBigInt.h @@ -0,0 +1,771 @@ +/* + * Copyright (c) 2021, Leon Albrecht + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AK { + +template +requires(sizeof(T) >= sizeof(u64) && IsUnsigned) class UFixedBigInt; + +// FIXME: This breaks formatting +// template +// constexpr inline bool Detail::IsIntegral> = true; + +template +constexpr inline bool Detail::IsUnsigned> = true; +template +constexpr inline bool Detail::IsSigned> = false; + +template +struct NumericLimits> { + static constexpr UFixedBigInt min() { return 0; } + static constexpr UFixedBigInt max() { return { NumericLimits::max(), NumericLimits::max() }; } + static constexpr bool is_signed() { return false; } +}; + +template +requires(sizeof(T) >= sizeof(u64) && IsUnsigned) class UFixedBigInt { +public: + using R = UFixedBigInt; + + constexpr UFixedBigInt() = default; + template + requires(sizeof(T) >= sizeof(U)) constexpr UFixedBigInt(U low) + : m_low(low) + , m_high(0u) + { + } + template + requires(sizeof(T) >= sizeof(U) && sizeof(T) >= sizeof(U2)) constexpr UFixedBigInt(U low, U2 high) + : m_low(low) + , m_high(high) + { + } + + constexpr T& low() + { + return m_low; + } + constexpr const T& low() const + { + return m_low; + } + constexpr T& high() + { + return m_high; + } + constexpr const T& high() const + { + return m_high; + } + + Span bytes() + { + return Span(reinterpret_cast(this), sizeof(R)); + } + Span bytes() const + { + return Span(reinterpret_cast(this), sizeof(R)); + } + + template + requires(sizeof(T) >= sizeof(U)) explicit operator U() const + { + return static_cast(m_low); + } + + // Utils + constexpr size_t clz() const requires(IsSame) + { + if (m_high) + return __builtin_clzll(m_high); + else + return sizeof(T) * 8 + __builtin_clzll(m_low); + } + constexpr size_t clz() const requires(!IsSame) + { + if (m_high) + return m_high.clz(); + else + return sizeof(T) * 8 + m_low.clz(); + } + constexpr size_t ctz() const requires(IsSame) + { + if (m_low) + return __builtin_ctzll(m_low); + else + return sizeof(T) * 8 + __builtin_ctzll(m_high); + } + constexpr size_t ctz() const requires(!IsSame) + { + if (m_low) + return m_low.ctz(); + else + return sizeof(T) * 8 + m_high.ctz(); + } + constexpr size_t popcnt() const requires(IsSame) + { + return __builtin_popcntll(m_low) + __builtin_popcntll(m_high); + } + constexpr size_t popcnt() const requires(!IsSame) + { + return m_low.popcnt() + m_high.popcnt(); + } + + // Comparison Operations + constexpr bool operator!() const + { + return !m_low && !m_high; + } + constexpr explicit operator bool() const + { + return m_low || m_high; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr bool operator==(const T& other) const + { + return !m_high && m_low == other; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr bool operator!=(const T& other) const + { + return m_high || m_low != other; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr bool operator>(const T& other) const + { + return m_high || m_low > other; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr bool operator<(const T& other) const + { + return !m_high && m_low < other; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr bool operator>=(const T& other) const + { + return *this == other || *this > other; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr bool operator<=(const T& other) const + { + return *this == other || *this < other; + } + + constexpr bool operator==(const R& other) const + { + return m_low == other.low() && m_high == other.high(); + } + constexpr bool operator!=(const R& other) const + { + return m_low != other.low() || m_high != other.high(); + } + constexpr bool operator>(const R& other) const + { + return m_high > other.high() + || (m_high == other.high() && m_low > other.low()); + } + constexpr bool operator<(const R& other) const + { + return m_high < other.high() + || (m_high == other.high() && m_low < other.low()); + } + constexpr bool operator>=(const R& other) const + { + return *this == other || *this > other; + } + constexpr bool operator<=(const R& other) const + { + return *this == other || *this < other; + } + + // Bitwise operations + constexpr R operator~() const + { + return { ~m_low, ~m_high }; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr U operator&(const U& other) const + { + return static_cast(m_low) & other; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr R operator|(const U& other) const + { + return { m_low | other, m_high }; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr R operator^(const U& other) const + { + return { m_low ^ other, m_high }; + } + template + constexpr R operator<<(const U& shift) const + { + if (shift >= sizeof(R) * 8u) + return 0u; + if (shift >= sizeof(T) * 8u) + return R { 0u, m_low << (shift - sizeof(T) * 8u) }; + if (!shift) + return *this; + + T overflow = m_low >> (sizeof(T) * 8u - shift); + return R { m_low << shift, (m_high << shift) | overflow }; + } + template + constexpr R operator>>(const U& shift) const + { + if (shift >= sizeof(R) * 8u) + return 0u; + if (shift >= sizeof(T) * 8u) + return m_high >> (shift - sizeof(T) * 8u); + if (!shift) + return *this; + + T underflow = m_high << (sizeof(T) * 8u - shift); + return R { (m_low >> shift) | underflow, m_high >> shift }; + } + template + constexpr R rol(const U& shift) const + { + return (*this >> sizeof(T) * 8u - shift) | (*this << shift); + } + template + constexpr R ror(const U& shift) const + { + return (*this << sizeof(T) * 8u - shift) | (*this >> shift); + } + + constexpr R operator&(const R& other) const + { + return { m_low & other.low(), m_high & other.high() }; + } + constexpr R operator|(const R& other) const + { + return { m_low | other.low(), m_high | other.high() }; + } + constexpr R operator^(const R& other) const + { + return { m_low ^ other.low(), m_high ^ other.high() }; + } + + // Bitwise assignment + template + requires(sizeof(T) >= sizeof(U)) constexpr R& operator&=(const U& other) + { + m_high = 0u; + m_low &= other; + return *this; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr R& operator|=(const U& other) + { + m_low |= other; + return *this; + } + template + requires(sizeof(T) >= sizeof(U)) constexpr R& operator^=(const U& other) + { + m_low ^= other; + return *this; + } + template + constexpr R& operator>>=(const U& other) + { + *this = *this >> other; + return *this; + } + template + constexpr R& operator<<=(const U& other) + { + *this = *this << other; + return *this; + } + + constexpr R& operator&=(const R& other) + { + m_high &= other.high(); + m_low &= other.low(); + return *this; + } + constexpr R& operator|=(const R& other) + { + m_high |= other.high(); + m_low |= other.low(); + return *this; + } + constexpr R& operator^=(const R& other) + { + m_high ^= other.high(); + m_low ^= other.low(); + return *this; + } + + // Arithmetics + + // implies size of less than u64, so passing references isn't useful + template + requires(sizeof(T) >= sizeof(U) && IsSame) constexpr R addc(const U other, bool& carry) const + { + bool low_carry = Checked::addition_would_overflow(m_low, other); + low_carry |= Checked::addition_would_overflow(m_low, carry); + bool high_carry = Checked::addition_would_overflow(m_high, low_carry); + + T lower = m_low + other + carry; + T higher = m_high + low_carry; + + carry = high_carry; + + return { + lower, + higher + }; + } + template + requires(sizeof(R) > sizeof(U) && sizeof(T) > sizeof(u64)) constexpr R addc(const U& other, bool& carry) const + { + T lower = m_low.addc(other, carry); + T higher = m_high.addc(0u, carry); + + return { + lower, + higher + }; + } + template + requires(IsSame&& IsSame) constexpr R addc(const U& other, bool& carry) const + { + bool low_carry = Checked::addition_would_overflow(m_low, other.low()); + bool high_carry = Checked::addition_would_overflow(m_high, other.high()); + + T lower = m_low + other.low(); + T higher = m_high + other.high(); + low_carry |= Checked::addition_would_overflow(lower, carry); + high_carry |= Checked::addition_would_overflow(higher, low_carry); + + lower += carry; + higher += low_carry; + carry = high_carry; + + return { + lower, + higher + }; + } + template + requires(IsSame && sizeof(T) > sizeof(u64)) constexpr R addc(const U& other, bool& carry) const + { + T lower = m_low.addc(other.low(), carry); + T higher = m_high.addc(other.high(), carry); + + return { + lower, + higher + }; + } + template + requires(sizeof(R) < sizeof(U)) constexpr U addc(const U& other, bool& carry) const + { + return other.addc(*this, carry); + } + + // FIXME: subc for sizeof(T) < sizeof(U) + template + requires(sizeof(T) >= sizeof(U)) constexpr R subc(const U& other, bool& carry) const + { + bool low_carry = (!m_low && carry) || (m_low - carry) < other; + bool high_carry = !m_high && low_carry; + + T lower = m_low - other - carry; + T higher = m_high - low_carry; + carry = high_carry; + + return { lower, higher }; + } + constexpr R subc(const R& other, bool& carry) const + { + bool low_carry = (!m_low && carry) || (m_low - carry) < other.low(); + bool high_carry = (!m_high && low_carry) || (m_high - low_carry) < other.high(); + + T lower = m_low - other.low() - carry; + T higher = m_high - other.high() - low_carry; + carry = high_carry; + + return { lower, higher }; + } + + constexpr R operator+(const bool& other) const + { + bool carry = false; // unused + return addc((u8)other, carry); + } + template + constexpr R operator+(const U& other) const + { + bool carry = false; // unused + return addc(other, carry); + } + + constexpr R operator-(const bool& other) const + { + bool carry = false; // unused + return subc((u8)other, carry); + } + + template + constexpr R operator-(const U& other) const + { + bool carry = false; // unused + return subc(other, carry); + } + + template + constexpr R& operator+=(const U& other) + { + *this = *this + other; + return *this; + } + template + constexpr R& operator-=(const U& other) + { + *this = *this - other; + return *this; + } + + constexpr R operator++() + { + // x++ + auto old = *this; + *this += 1; + return old; + } + constexpr R& operator++(int) + { + // ++x + *this += 1; + return *this; + } + constexpr R operator--() + { + // x-- + auto old = *this; + *this -= 1; + return old; + } + constexpr R& operator--(int) + { + // --x + *this -= 1; + return *this; + } + + // FIXME: no restraints on this + template + requires(sizeof(R) >= sizeof(U)) constexpr R div_mod(const U& divisor, U& remainder) const + { + // FIXME: Is there a better way to raise a division by 0? + // Maybe as a compiletime warning? +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdiv-by-zero" + if (!divisor) { + volatile int x = 1; + volatile int y = 0; + [[maybe_unused]] volatile int z = x / y; + } +#pragma GCC diagnostic pop + + // fastpaths + if (*this < divisor) { + remainder = static_cast(*this); + return 0u; + } + if (*this == divisor) { + remainder = 0u; + return 1u; + } + if (divisor == 1u) { + remainder = 0u; + return *this; + } + + remainder = 0u; + R quotient = 0u; + + for (ssize_t i = sizeof(R) * 8 - clz() - 1; i >= 0; --i) { + remainder <<= 1u; + remainder |= (*this >> (size_t)i) & 1u; + if (remainder >= divisor) { + remainder -= divisor; + quotient |= R { 1u } << (size_t)i; + } + } + + return quotient; + } + + template + constexpr R operator*(U other) const + { + R res = 0u; + R that = *this; + for (; other != 0u; other >>= 1u) { + if (other & 1u) + res += that; + that <<= 1u; + } + return res; + } + + template + constexpr R operator/(const U& other) const + { + U mod { 0u }; // unused + return div_mod(other, mod); + } + template + constexpr U operator%(const U& other) const + { + R res { 0u }; + div_mod(other, res); + return res; + } + + template + constexpr R& operator*=(const U& other) + { + *this = *this * other; + return *this; + } + template + constexpr R& operator/=(const U& other) + { + *this = *this / other; + return *this; + } + template + constexpr R& operator%=(const U& other) + { + *this = *this % other; + return *this; + } + + constexpr R sqrt() const + { + // Bitwise method: https://en.wikipedia.org/wiki/Integer_square_root#Using_bitwise_operations + // the bitwise method seems to be way faster then Newtons: + // https://quick-bench.com/q/eXZwW1DVhZxLE0llumeCXkfOK3Q + if (*this == 1u) + return 1u; + + ssize_t shift = (sizeof(R) * 8 - clz()) & ~1ULL; + // should be equivalent to: + // long shift = 2; + // while ((val >> shift) != 0) + // shift += 2; + + R res = 0u; + while (shift >= 0) { + res = res << 1u; + R large_cand = (res | 1u); + if (*this >> (size_t)shift >= large_cand * large_cand) + res = large_cand; + shift -= 2; + } + return res; + } + + constexpr R pow(u64 exp) + { + // Montgomery's Ladder Technique + // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Montgomery's_ladder_technique + R x1 = *this; + R x2 = *this * *this; + u64 exp_copy = exp; + for (ssize_t i = sizeof(u64) * 8 - __builtin_clzll(exp) - 2; i >= 0; --i) { + if (exp_copy & 1u) { + x2 *= x1; + x1 *= x1; + } else { + x1 *= x2; + x2 *= x2; + } + exp_copy >>= 1u; + } + return x1; + } + template + requires(sizeof(U) > sizeof(u64)) constexpr R pow(U exp) + { + // Montgomery's Ladder Technique + // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Montgomery's_ladder_technique + R x1 = *this; + R x2 = *this * *this; + U exp_copy = exp; + for (ssize_t i = sizeof(U) * 8 - exp().clz() - 2; i >= 0; --i) { + if (exp_copy & 1u) { + x2 *= x1; + x1 *= x1; + } else { + x1 *= x2; + x2 *= x2; + } + exp_copy >>= 1u; + } + return x1; + } + + template + constexpr U pow_mod(u64 exp, U mod) + { + // Left to right binary method: + // https://en.wikipedia.org/wiki/Modular_exponentiation#Left-to-right_binary_method + // FIXME: this is not sidechanel proof + if (!mod) + return 0u; + + U res = 1; + u64 exp_copy = exp; + for (size_t i = sizeof(u64) - __builtin_clzll(exp) - 1u; i < exp; ++i) { + res *= res; + res %= mod; + if (exp_copy & 1u) { + res = (*this * res) % mod; + } + exp_copy >>= 1u; + } + return res; + } + template + requires(sizeof(ExpT) > sizeof(u64)) constexpr U pow_mod(ExpT exp, U mod) + { + // Left to right binary method: + // https://en.wikipedia.org/wiki/Modular_exponentiation#Left-to-right_binary_method + // FIXME: this is not side channel proof + if (!mod) + return 0u; + + U res = 1; + ExpT exp_copy = exp; + for (size_t i = sizeof(ExpT) - exp.clz() - 1u; i < exp; ++i) { + res *= res; + res %= mod; + if (exp_copy & 1u) { + res = (*this * res) % mod; + } + exp_copy >>= 1u; + } + return res; + } + + constexpr size_t log2() + { + // FIXME: propper rounding + return sizeof(R) - clz(); + } + constexpr size_t logn(u64 base) + { + // FIXME: propper rounding + return log2() / (sizeof(u64) - __builtin_clzll(base)); + } + template + requires(sizeof(U) > sizeof(u64)) constexpr size_t logn(U base) + { + // FIXME: propper rounding + return log2() / base.log2(); + } + +private: + T m_low; + T m_high; +}; + +// reverse operators +template +requires(sizeof(U) < sizeof(T) * 2) constexpr bool operator<(const U a, const UFixedBigInt& b) { return b >= a; } +template +requires(sizeof(U) < sizeof(T) * 2) constexpr bool operator>(const U a, const UFixedBigInt& b) { return b <= a; } +template +requires(sizeof(U) < sizeof(T) * 2) constexpr bool operator<=(const U a, const UFixedBigInt& b) { return b > a; } +template +requires(sizeof(U) < sizeof(T) * 2) constexpr bool operator>=(const U a, const UFixedBigInt& b) { return b < a; } + +template +struct Formatter> : StandardFormatter { + Formatter() = default; + explicit Formatter(StandardFormatter formatter) + : StandardFormatter(formatter) + { + } + + void format(FormatBuilder& builder, UFixedBigInt value) + { + if (m_precision.has_value()) + VERIFY_NOT_REACHED(); + + if (m_mode == Mode::Pointer) { + // these are way to big for a pointer + VERIFY_NOT_REACHED(); + } + if (m_mode == Mode::Default) + m_mode = Mode::Hexadecimal; + + if (!value.high()) { + Formatter formatter { *this }; + return formatter.format(builder, value.low()); + } + + u8 base = 0; + if (m_mode == Mode::Binary) { + base = 2; + } else if (m_mode == Mode::BinaryUppercase) { + base = 2; + } else if (m_mode == Mode::Octal) { + TODO(); + } else if (m_mode == Mode::Decimal) { + TODO(); + } else if (m_mode == Mode::Hexadecimal) { + base = 16; + } else if (m_mode == Mode::HexadecimalUppercase) { + base = 16; + } else { + VERIFY_NOT_REACHED(); + } + ssize_t width = m_width.value_or(0); + ssize_t lower_length = ceil_div(sizeof(T) * 8, (ssize_t)base); + Formatter formatter { *this }; + formatter.m_width = max(width - lower_length, (ssize_t)0); + formatter.format(builder, value.high()); + builder.put_literal("'"sv); + formatter.m_zero_pad = true; + formatter.m_alternative_form = false; + formatter.m_width = lower_length; + formatter.format(builder, value.low()); + } +}; +} + +// Nit: Doing these as custom classes might be faster, especially when writing +// then in SSE, but this would cause a lot of Code duplication and due to +// the nature of constexprs and the intelligence of the compiler they might +// be using SSE/MMX either way + +// these sizes should suffice for most usecases +using u128 = AK::UFixedBigInt; +using u256 = AK::UFixedBigInt; +using u512 = AK::UFixedBigInt; +using u1024 = AK::UFixedBigInt; +using u2048 = AK::UFixedBigInt; +using u4096 = AK::UFixedBigInt; diff --git a/Tests/AK/CMakeLists.txt b/Tests/AK/CMakeLists.txt index 4469057dd1..346165afd0 100644 --- a/Tests/AK/CMakeLists.txt +++ b/Tests/AK/CMakeLists.txt @@ -58,6 +58,7 @@ set(AK_TEST_SOURCES TestTuple.cpp TestTypeTraits.cpp TestTypedTransfer.cpp + TestUFixedBigInt.cpp TestURL.cpp TestUtf8.cpp TestVariant.cpp diff --git a/Tests/AK/TestUFixedBigInt.cpp b/Tests/AK/TestUFixedBigInt.cpp new file mode 100644 index 0000000000..76ed5c6e0a --- /dev/null +++ b/Tests/AK/TestUFixedBigInt.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include +#include +#include +#include + +#include + +constexpr int test_iterations = 32; + +TEST_CASE(one_plus_one) +{ + u256 a = 1u; + u256 b = 1u; + EXPECT_EQ(a + b, u256(2u)); +} + +TEST_CASE(identities) +{ + srand(0); + for (int i = 0; i < test_iterations; ++i) { + auto x = get_random(); + if ((x >> 255u) & 1u) { + // ignore numbers that could overflow + --i; + continue; + } + EXPECT_EQ((x << 0u), x); + EXPECT_EQ((x >> 0u), x); + EXPECT_EQ((x / 1u), x); + EXPECT_EQ((x % (x + 1u)), x); + EXPECT_EQ((x << 1u) >> 1u, x); + EXPECT_EQ((x * 2u) / 2u, x); + EXPECT_EQ((x + 2u) - 2u, x); + } +} + +TEST_CASE(sqrt) +{ + srand(0); + for (int i = 0; i < test_iterations; ++i) { + u256 x = get_random(); + EXPECT_EQ((x * x).sqrt(), x); + } +} + +TEST_CASE(add_overflow_propagation) +{ + u256 a = NumericLimits::max(); + u256 b = a + a; + u256 c = a * 2u; + + EXPECT_EQ(b.low(), NumericLimits::max() - 1u); + EXPECT_EQ(b.high(), 1u); + EXPECT_EQ(b, a << 1u); + EXPECT_EQ(b, c); +} + +TEST_CASE(simple_multiplication) +{ + srand(0); + for (int i = 0; i < test_iterations; ++i) { + u256 a = get_random(); + + EXPECT_EQ(a * 0u, 0u); + EXPECT_EQ(a * 1u, a); + EXPECT_EQ(a >> 1u, a / 2u); + if (!(a >> 255u & 1u)) { + EXPECT_EQ(a << 1u, a * 2u); + } + } +} + +TEST_CASE(div_mod) +{ + srand(0); + for (int i = 0; i < test_iterations; ++i) { + u256 a = get_random(); + u256 b = get_random(); + u256 mod; + u256 div = a.div_mod(b, mod); + EXPECT_EQ(a, div * b + mod); + } +} + +TEST_CASE(mod_hardcoded) +{ + EXPECT_EQ(u256(u128 { 0x8a4b08d32f8b8e48ULL, 0x8459322f67b8e26dULL }, u128 { 0xeea82af4312d1931ULL, 0x654fb5cfe82dbd58ULL }) % u256(u128 { 0x40a58652868d5d66ULL, 0x81d674bf7d6d6861ULL }, u128 { 0xa8314900e6188a82ULL, 0xc273ca947237b4aaULL }), u256(u128 { 0x8a4b08d32f8b8e48ULL, 0x8459322f67b8e26dULL }, u128 { 0xeea82af4312d1931ULL, 0x654fb5cfe82dbd58ULL })); + EXPECT_EQ(u256(u128 { 0xda06d295caa75a3bULL, 0xe3ae0d460049948eULL }, u128 { 0x9a89d29a0325f27fULL, 0x1c8d90ebadec5607ULL }) % u256(u128 { 0x38bd4d49ff59fdf8ULL, 0xcba9acf09110de14ULL }, u128 { 0x51a376c68c4702feULL, 0x0d1b59dec8d2338bULL }), u256(u128 { 0x688c3801cbf35e4bULL, 0x4c5ab364de27d866ULL }, u128 { 0xf742e50cea97ec82ULL, 0x0256dd2e1c47eef0ULL })); + EXPECT_EQ(u256(u128 { 0xdfb56d42706bdb28ULL, 0x6c3bd5ea790c7ef5ULL }, u128 { 0xfebec271d7c757baULL, 0x7dbd745d56bc9e0eULL }) % u256(u128 { 0x30a309a58aed2c01ULL, 0x64d58c8b485c113dULL }, u128 { 0xfa01f558732e9b78ULL, 0x5862b502ebb2dbe9ULL }), u256(u128 { 0xaf12639ce57eaf27ULL, 0x0766495f30b06db8ULL }, u128 { 0x04bccd196498bc42ULL, 0x255abf5a6b09c225ULL })); + EXPECT_EQ(u256(u128 { 0x0a8473d84131f420ULL, 0x0471632bb018c1a2ULL }, u128 { 0x22865980ccd1014fULL, 0xcade79df2adf8fdfULL }) % u256(u128 { 0xd7da811f35db7de0ULL, 0x4e3d98062eae954fULL }, u128 { 0x23946cd23d470d7eULL, 0x6645d41afdc1f2e8ULL }), u256(u128 { 0x32a9f2b90b567640ULL, 0xb633cb25816a2c52ULL }, u128 { 0xfef1ecae8f89f3d0ULL, 0x6498a5c42d1d9cf6ULL })); + EXPECT_EQ(u256(u128 { 0x68636d8d1b7ac40bULL, 0xcb04084ddc684d42ULL }, u128 { 0xaa43c0f6e4e0178cULL, 0x49edae817f27c32aULL }) % u256(u128 { 0xbcc52d96070b7046ULL, 0x2f8255f3c6f8d4bdULL }, u128 { 0x2423bb472eced919ULL, 0x2ed9534c1570b7faULL }), u256(u128 { 0xab9e3ff7146f53c5ULL, 0x9b81b25a156f7884ULL }, u128 { 0x862005afb6113e73ULL, 0x1b145b3569b70b30ULL })); + EXPECT_EQ(u256(u128 { 0xad34ce382cd00226ULL, 0x39b1986d56a064afULL }, u128 { 0xa9410bbd86d9ab21ULL, 0x0fb980a5a7d4b99fULL }) % u256(u128 { 0xa7561893be8cd299ULL, 0x9c3cb9184f45878aULL }, u128 { 0x1e066270a27414efULL, 0xe0fbaa0b739890b8ULL }), u256(u128 { 0xad34ce382cd00226ULL, 0x39b1986d56a064afULL }, u128 { 0xa9410bbd86d9ab21ULL, 0x0fb980a5a7d4b99fULL })); + EXPECT_EQ(u256(u128 { 0x69a0ab23d9f81040ULL, 0xf509000f44fcadb3ULL }, u128 { 0x544310cc56ea051aULL, 0x968a003529f513c0ULL }) % u256(u128 { 0xd6db169628ba28edULL, 0xcf2417c98b765531ULL }, u128 { 0x27865ebfca2d945aULL, 0xcbd1257363cb86a1ULL }), u256(u128 { 0x69a0ab23d9f81040ULL, 0xf509000f44fcadb3ULL }, u128 { 0x544310cc56ea051aULL, 0x968a003529f513c0ULL })); + EXPECT_EQ(u256(u128 { 0x5d41bcd96e47dfbdULL, 0x623a7c82c903789bULL }, u128 { 0x57c3723bfcfd7eeeULL, 0x8b1f21a0739fa6a8ULL }) % u256(u128 { 0xf918e7d73771d5c4ULL, 0xdd40e701852f4d68ULL }, u128 { 0x7c4ac424e3836a4dULL, 0xcb7a0bcc58701175ULL }), u256(u128 { 0x5d41bcd96e47dfbdULL, 0x623a7c82c903789bULL }, u128 { 0x57c3723bfcfd7eeeULL, 0x8b1f21a0739fa6a8ULL })); + EXPECT_EQ(u256(u128 { 0xa4394401788e848aULL, 0x8a907db529ba2943ULL }, u128 { 0x4f3c13b9058d17d3ULL, 0xf17f01b5c1898104ULL }) % u256(u128 { 0x214097598f92cebeULL, 0x723b873f1f879305ULL }, u128 { 0x5f9352861d92ff91ULL, 0x527c65978f7d12ebULL }), u256(u128 { 0x61b8154e5968e70eULL, 0xa6196f36eaab0339ULL }, u128 { 0x90156eacca6718b0ULL, 0x4c863686a28f5b2dULL })); + EXPECT_EQ(u256(u128 { 0x324e46a2bd4d9c0dULL, 0xfb8980a6353814a8ULL }, u128 { 0x3605ef999901dc37ULL, 0xcc2493941c934b83ULL }) % u256(u128 { 0x45e1b8552ccd49b1ULL, 0xe61bd62768189e42ULL }, u128 { 0x859e83ed2f92c211ULL, 0xc7713b3893031cbdULL }), u256(u128 { 0xec6c8e4d9080525cULL, 0x156daa7ecd1f7665ULL }, u128 { 0xb0676bac696f1a26ULL, 0x04b3585b89902ec5ULL })); + EXPECT_EQ(u256(u128 { 0x9a3b5f7c879d14f4ULL, 0xc437119868072180ULL }, u128 { 0xea395ae2238ada4eULL, 0x1aa5cc44c4c9deb5ULL }) % u256(u128 { 0x9535e4674b364058ULL, 0xbbf3d10e995c610dULL }, u128 { 0x8fac6f8ae200290aULL, 0x7832f747c56ae6dfULL }), u256(u128 { 0x9a3b5f7c879d14f4ULL, 0xc437119868072180ULL }, u128 { 0xea395ae2238ada4eULL, 0x1aa5cc44c4c9deb5ULL })); + EXPECT_EQ(u256(u128 { 0xf2a2d399b73fd0c2ULL, 0x02b7155ee15525ffULL }, u128 { 0xcaaa7daf39923db6ULL, 0x8ccb6244075bb5bbULL }) % u256(u128 { 0xfc002da6ab396d95ULL, 0xd7d0ebd6242b7119ULL }, u128 { 0x7f2ec32021ce7d32ULL, 0x63cef84255b91414ULL }), u256(u128 { 0xf6a2a5f30c06632dULL, 0x2ae62988bd29b4e5ULL }, u128 { 0x4b7bba8f17c3c083ULL, 0x28fc6a01b1a2a1a7ULL })); + EXPECT_EQ(u256(u128 { 0xfef71dab99335163ULL, 0xd1f1bc5f37570d67ULL }, u128 { 0x34bd2c7372eb8c4cULL, 0x15c0d3f1cc1613beULL }) % u256(u128 { 0x3978824c651c6cceULL, 0x5631f4d483e9f3ffULL }, u128 { 0xfd7c47d688e0d50fULL, 0xb3a9f99c7234d772ULL }), u256(u128 { 0xfef71dab99335163ULL, 0xd1f1bc5f37570d67ULL }, u128 { 0x34bd2c7372eb8c4cULL, 0x15c0d3f1cc1613beULL })); + EXPECT_EQ(u256(u128 { 0x19d69d0229db064eULL, 0x612eea6e8d79807bULL }, u128 { 0xe755c10d2b9e25adULL, 0x6a84d397b8e7da54ULL }) % u256(u128 { 0x9db6a18d292bc65fULL, 0xbdc7ccbcdb4f046cULL }, u128 { 0xd5be95d179cc1aa4ULL, 0x77c81421a604eb66ULL }), u256(u128 { 0x19d69d0229db064eULL, 0x612eea6e8d79807bULL }, u128 { 0xe755c10d2b9e25adULL, 0x6a84d397b8e7da54ULL })); + EXPECT_EQ(u256(u128 { 0xcd6a8ed6185d098fULL, 0xcf17b08e6e3836e5ULL }, u128 { 0x52e187a75426d99dULL, 0x562e1c437b33a29dULL }) % u256(u128 { 0x0c3dd1aa87a4bd96ULL, 0xac333d8636735a23ULL }, u128 { 0x1a30abda1015e674ULL, 0xe968125d96bdc2e9ULL }), u256(u128 { 0xcd6a8ed6185d098fULL, 0xcf17b08e6e3836e5ULL }, u128 { 0x52e187a75426d99dULL, 0x562e1c437b33a29dULL })); + EXPECT_EQ(u256(u128 { 0x60151f3f11782d51ULL, 0xeecbc23fa60bd168ULL }, u128 { 0x825b67c89bce81f2ULL, 0x082fe85ba1a09583ULL }) % u256(u128 { 0x438123a283f8133aULL, 0x7b5936b727339a8eULL }, u128 { 0x36f2bc572018588cULL, 0xbdebe2b4033d3209ULL }), u256(u128 { 0x60151f3f11782d51ULL, 0xeecbc23fa60bd168ULL }, u128 { 0x825b67c89bce81f2ULL, 0x082fe85ba1a09583ULL })); + EXPECT_EQ(u256(u128 { 0x6a98f75458b6c9daULL, 0xbe935c50e782e82fULL }, u128 { 0xf8f7479d9ba56379ULL, 0xfd3cb6194bc5966fULL }) % u256(u128 { 0xc0fb2a97d7368d96ULL, 0x306534301d4eadbeULL }, u128 { 0x30b2c8ff81066af6ULL, 0xd23116ef8d5eacf5ULL }), u256(u128 { 0xa99dccbc81803c44ULL, 0x8e2e2820ca343a70ULL }, u128 { 0xc8447e9e1a9ef883ULL, 0x2b0b9f29be66e97aULL })); + EXPECT_EQ(u256(u128 { 0xf90a6805c45be556ULL, 0x1d4a0c204a2dec7dULL }, u128 { 0x4a8c0d194584da59ULL, 0xcd1ab79a84dfccb6ULL }) % u256(u128 { 0xcedf80ed06c339b1ULL, 0x3a18231b09b21a3cULL }, u128 { 0xef2fedb7c3b237ddULL, 0x01d6223300a1f18aULL }), u256(u128 { 0x4621813fd5b5e197ULL, 0xecd2d36715f48c20ULL }, u128 { 0x94c3fa6b6b3ea16cULL, 0x0141e37d3ea81178ULL })); + EXPECT_EQ(u256(u128 { 0x5cced259ff5b73fdULL, 0x223a2bc9d62d3714ULL }, u128 { 0xf1b7b34b45f3608fULL, 0xce2325cbc0e9734fULL }) % u256(u128 { 0xf5dc56158c242575ULL, 0xb3bf8578c1852fdcULL }, u128 { 0xd97725f998d1d289ULL, 0x053baa680c5abb16ULL }), u256(u128 { 0xe83db511a5d9bf2aULL, 0xc00cd6645ae2ec6aULL }, u128 { 0xd090ea44fdfc4d94ULL, 0x020c2ff1df16f2d4ULL })); + EXPECT_EQ(u256(u128 { 0x6ce28a960af0ceb3ULL, 0x2da9808f962b0c43ULL }, u128 { 0x67cdac05a542bd66ULL, 0x5d3eb81aadf9479aULL }) % u256(u128 { 0x45f549795eab7c6cULL, 0x5643e85f6b4399eeULL }, u128 { 0x3b068fa03cb257dfULL, 0x3b42cfa16517b14cULL }), u256(u128 { 0x26ed411cac455247ULL, 0xd76598302ae77255ULL }, u128 { 0x2cc71c6568906586ULL, 0x21fbe87948e1964eULL })); + EXPECT_EQ(u256(u128 { 0x236f8081c4dc0d2aULL, 0xa7da15c4c15e83f3ULL }, u128 { 0x32c0948d497b78f0ULL, 0xf75ddc710601d2d0ULL }) % u256(u128 { 0x326f376465b287beULL, 0x5e24a7c87a45f4ebULL }, u128 { 0x1fa25aecc5a5a1f2ULL, 0x3490287aca77c399ULL }), u256(u128 { 0x59b2a2f02e11ee32ULL, 0x2f4776a2d846b046ULL }, u128 { 0xb43728da32e4f127ULL, 0x251d3a85dc22c46bULL })); + EXPECT_EQ(u256(u128 { 0xf5af1d760c381629ULL, 0x9f4d904501f9f6d6ULL }, u128 { 0xc23fe8d79d015270ULL, 0x3982c8897a86e837ULL }) % u256(u128 { 0xd3cc875eec2d5032ULL, 0x46e392089468f8cfULL }, u128 { 0x91c6762130826cedULL, 0x9e3b011ba58b4705ULL }), u256(u128 { 0xf5af1d760c381629ULL, 0x9f4d904501f9f6d6ULL }, u128 { 0xc23fe8d79d015270ULL, 0x3982c8897a86e837ULL })); + EXPECT_EQ(u256(u128 { 0x6b60c428cac4f505ULL, 0xeac42ae8d7929fb7ULL }, u128 { 0x59a0ce8a7110df27ULL, 0xc0d5952f55096e15ULL }) % u256(u128 { 0x280419bd2d8fe3e8ULL, 0x13b50ec9c2bb7397ULL }, u128 { 0x8d8ef08f3ac8ce5eULL, 0x8912b53aa9279938ULL }), u256(u128 { 0x435caa6b9d35111dULL, 0xd70f1c1f14d72c20ULL }, u128 { 0xcc11ddfb364810c9ULL, 0x37c2dff4abe1d4dcULL })); + EXPECT_EQ(u256(u128 { 0x8068bf135ceead51ULL, 0xadda5b57797a3a27ULL }, u128 { 0x4c4e3fe186af2698ULL, 0xdfbab959987cb289ULL }) % u256(u128 { 0x93c99cb4fa9f36c0ULL, 0xe107948b8bf301d8ULL }, u128 { 0xab4e7570e6e8e177ULL, 0xdb95d36ef24543daULL }), u256(u128 { 0xec9f225e624f7691ULL, 0xccd2c6cbed87384eULL }, u128 { 0xa0ffca709fc64520ULL, 0x0424e5eaa6376eaeULL })); + EXPECT_EQ(u256(u128 { 0x036b4a64b2ab05bbULL, 0x6be175b3549f7440ULL }, u128 { 0x3c6839ecac5d4634ULL, 0x6a1939f6585dd1ddULL }) % u256(u128 { 0x329f61eaf9c14938ULL, 0x6653276323053388ULL }, u128 { 0x7e511a9611463f4dULL, 0x9898a93910722fd8ULL }), u256(u128 { 0x036b4a64b2ab05bbULL, 0x6be175b3549f7440ULL }, u128 { 0x3c6839ecac5d4634ULL, 0x6a1939f6585dd1ddULL })); + EXPECT_EQ(u256(u128 { 0xe5d0db9190bb01c1ULL, 0x20510645c252e9b1ULL }, u128 { 0x3b673f98db9a3038ULL, 0xbda4406d733b1c6cULL }) % u256(u128 { 0x4d67af71063282f2ULL, 0x594aa60bb2360bbdULL }, u128 { 0x4c2759ff1b2ffbd1ULL, 0xe29a2e0962d9bdbfULL }), u256(u128 { 0xe5d0db9190bb01c1ULL, 0x20510645c252e9b1ULL }, u128 { 0x3b673f98db9a3038ULL, 0xbda4406d733b1c6cULL })); + EXPECT_EQ(u256(u128 { 0x2f833c8cd20c43f9ULL, 0x405bd5f257ac19e1ULL }, u128 { 0xd9873917f32ca4adULL, 0x582dda480fecde28ULL }) % u256(u128 { 0xb56564a5a9dbc163ULL, 0x17b4076b2667c703ULL }, u128 { 0xdf0f26d9a66f513eULL, 0xb34c28d1e1a1953cULL }), u256(u128 { 0x2f833c8cd20c43f9ULL, 0x405bd5f257ac19e1ULL }, u128 { 0xd9873917f32ca4adULL, 0x582dda480fecde28ULL })); + EXPECT_EQ(u256(u128 { 0x79ceb31188bc142bULL, 0xb2c083d1b0d1a172ULL }, u128 { 0x87a465799728fe9fULL, 0xe05c1c98eaa03994ULL }) % u256(u128 { 0x548b4f12f104f995ULL, 0x8d1d554e53ebc210ULL }, u128 { 0x4f5238bde10ce04aULL, 0x33da77cfa817ef7cULL }), u256(u128 { 0x27a176c5c4a82dd7ULL, 0x7e4b2e9861229931ULL }, u128 { 0x4a5b828212f57d75ULL, 0x10f23d5a4a407ba3ULL })); + EXPECT_EQ(u256(u128 { 0xfbcfb8e88417af84ULL, 0xfd35ec5ad38f6f00ULL }, u128 { 0x12d5c3e4e108cc62ULL, 0x09370460a41c637fULL }) % u256(u128 { 0x71faedeee5e0bf52ULL, 0x3d17ff54be8d686fULL }, u128 { 0x02e3ab47712e3d11ULL, 0x64da86270055e5eaULL }), u256(u128 { 0xfbcfb8e88417af84ULL, 0xfd35ec5ad38f6f00ULL }, u128 { 0x12d5c3e4e108cc62ULL, 0x09370460a41c637fULL })); + EXPECT_EQ(u256(u128 { 0x690f9145f7b1f8f8ULL, 0xe790aa66a2e08b63ULL }, u128 { 0x1d6ded50aa11aa3cULL, 0x601ec6f81fd1d57aULL }) % u256(u128 { 0x1256bdca9e0d6066ULL, 0xd19119919b026c0cULL }, u128 { 0x17a17b7df7689c40ULL, 0x97baf68d5f5622ddULL }), u256(u128 { 0x690f9145f7b1f8f8ULL, 0xe790aa66a2e08b63ULL }, u128 { 0x1d6ded50aa11aa3cULL, 0x601ec6f81fd1d57aULL })); + EXPECT_EQ(u256(u128 { 0x7f13e232d82a24c6ULL, 0x23d41447dd7f5bc6ULL }, u128 { 0xd89a3ed8b30527caULL, 0xa98ef2cc01e83685ULL }) % u256(u128 { 0x8d4f5b1983fc1f0eULL, 0xf54102ece15fb0faULL }, u128 { 0x17b8aec68556a16dULL, 0x4e1e5bea70cb9398ULL }), u256(u128 { 0x64752bffd031e6aaULL, 0x39520e6e1abff9d1ULL }, u128 { 0xa928e14ba857e4eeULL, 0x0d523af720510f55ULL })); + EXPECT_EQ(u256(u128 { 0x49750d7f39d61607ULL, 0x58bdef1c3e00d18eULL }, u128 { 0xa651479cd1fd1933ULL, 0xd1834bc3d654b633ULL }) % u256(u128 { 0x1bda34f5ec68ef3bULL, 0x12c65ce5363a7616ULL }, u128 { 0x5a79c4d85da0071aULL, 0xffa6b6284559d1aaULL }), u256(u128 { 0x49750d7f39d61607ULL, 0x58bdef1c3e00d18eULL }, u128 { 0xa651479cd1fd1933ULL, 0xd1834bc3d654b633ULL })); +} diff --git a/Userland/DevTools/UserspaceEmulator/Region.h b/Userland/DevTools/UserspaceEmulator/Region.h index a027ccc553..1701e16ffd 100644 --- a/Userland/DevTools/UserspaceEmulator/Region.h +++ b/Userland/DevTools/UserspaceEmulator/Region.h @@ -10,7 +10,7 @@ #include "ValueWithShadow.h" #include #include -#include +#include namespace UserspaceEmulator { diff --git a/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp b/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp index c4d0c0ae0e..71c0f29f1c 100644 --- a/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp +++ b/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp @@ -1855,9 +1855,10 @@ void SoftCPU::FLD_RM80(const X86::Instruction& insn) // long doubles can be up to 128 bits wide in memory for reasons (alignment) and only uses 80 bits of precision // GCC uses 12 bytes in 32 bit and 16 bytes in 64 bit mode // so in the 32 bit case we read a bit to much, but that shouldn't be an issue. - auto new_f80 = insn.modrm().read128(*this, insn); // FIXME: Respect shadow values - fpu_push(*(long double*)new_f80.value().bytes()); + auto new_f80 = insn.modrm().read128(*this, insn).value(); + + fpu_push(*(long double*)new_f80.bytes().data()); } void SoftCPU::FUCOMI(const X86::Instruction& insn) @@ -1908,7 +1909,7 @@ void SoftCPU::FSTP_RM80(const X86::Instruction& insn) if constexpr (sizeof(long double) == 12) f80 = insn.modrm().read128(*this, insn).value(); - *(long double*)f80.bytes() = fpu_pop(); + *(long double*)f80.bytes().data() = fpu_pop(); insn.modrm().write128(*this, insn, shadow_wrap_as_initialized(f80)); } diff --git a/Userland/DevTools/UserspaceEmulator/ValueWithShadow.h b/Userland/DevTools/UserspaceEmulator/ValueWithShadow.h index e1b65387ee..50e2fb86fb 100644 --- a/Userland/DevTools/UserspaceEmulator/ValueWithShadow.h +++ b/Userland/DevTools/UserspaceEmulator/ValueWithShadow.h @@ -8,7 +8,7 @@ #include #include -#include +#include #include namespace UserspaceEmulator { diff --git a/Userland/Libraries/LibX86/CMakeLists.txt b/Userland/Libraries/LibX86/CMakeLists.txt index 2ac28c1aab..2f5dad9214 100644 --- a/Userland/Libraries/LibX86/CMakeLists.txt +++ b/Userland/Libraries/LibX86/CMakeLists.txt @@ -1,6 +1,5 @@ set(SOURCES Instruction.cpp - Types/Formatter.cpp ) serenity_lib(LibX86 x86) diff --git a/Userland/Libraries/LibX86/Types.h b/Userland/Libraries/LibX86/Types.h deleted file mode 100644 index 3ccb176874..0000000000 --- a/Userland/Libraries/LibX86/Types.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2021, Leon Albrecht - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Types/u128.h" -#include "Types/u256.h" diff --git a/Userland/Libraries/LibX86/Types/Formatter.cpp b/Userland/Libraries/LibX86/Types/Formatter.cpp deleted file mode 100644 index 0e7b5575fe..0000000000 --- a/Userland/Libraries/LibX86/Types/Formatter.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2021, Leon Albrecht - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "u128.h" -#include "u256.h" - -#include -#include -#include -#include -#include - -void AK::Formatter::format(AK::FormatBuilder& builder, u128 value) -{ - if (value.high() == 0) { - AK::Formatter formatter { *this }; - return formatter.format(builder, value.low()); - } - - if (m_precision.has_value()) - VERIFY_NOT_REACHED(); - - if (m_mode == Mode::Pointer) { - // this is way to big for a pointer - VERIFY_NOT_REACHED(); - } - - u8 base = 0; - bool upper_case = false; - if (m_mode == Mode::Binary) { - base = 2; - } else if (m_mode == Mode::BinaryUppercase) { - base = 2; - upper_case = true; - } else if (m_mode == Mode::Octal) { - base = 8; - } else if (m_mode == Mode::Decimal || m_mode == Mode::Default) { - // FIXME: implement this - TODO(); - } else if (m_mode == Mode::Hexadecimal) { - base = 16; - } else if (m_mode == Mode::HexadecimalUppercase) { - base = 16; - upper_case = true; - } else { - VERIFY_NOT_REACHED(); - } - - u16 lower_length = sizeof(u64) * 0xFF / base; - if (m_width.value() > lower_length) { - builder.put_u64(value.high(), base, m_alternative_form, upper_case, m_zero_pad, m_align, m_width.value() - lower_length, m_fill, m_sign_mode); - builder.put_u64(value.low(), base, false, upper_case, m_zero_pad, m_align, m_width.value(), m_fill, m_sign_mode); - } else { - builder.put_u64(value.low(), base, m_alternative_form, upper_case, m_zero_pad, m_align, m_width.value(), m_fill, m_sign_mode); - } -} - -void AK::Formatter::format(AK::FormatBuilder& builder, u256 value) -{ - if (value.high() == 0) { - AK::Formatter formatter { *this }; - return formatter.format(builder, value.low()); - } - - if (m_precision.has_value()) - VERIFY_NOT_REACHED(); - - if (m_mode == Mode::Pointer) { - // this is way to big for a pointer - VERIFY_NOT_REACHED(); - } - - u8 base = 0; - bool upper_case = false; - if (m_mode == Mode::Binary) { - base = 2; - } else if (m_mode == Mode::BinaryUppercase) { - base = 2; - upper_case = true; - } else if (m_mode == Mode::Octal) { - base = 8; - } else if (m_mode == Mode::Decimal || m_mode == Mode::Default) { - // FIXME: implement this - TODO(); - } else if (m_mode == Mode::Hexadecimal) { - base = 16; - } else if (m_mode == Mode::HexadecimalUppercase) { - base = 16; - upper_case = true; - } else { - VERIFY_NOT_REACHED(); - } - - u16 part_length = sizeof(u128) * 0xFF / base; - if (m_width.value() > part_length * 3) { - builder.put_u64(value.high().high(), base, m_alternative_form, upper_case, m_zero_pad, m_align, m_width.value() - part_length * 3, m_fill, m_sign_mode); - builder.put_u64(value.high().low(), base, false, upper_case, m_zero_pad, m_align, part_length, m_fill, m_sign_mode); - builder.put_u64(value.low().high(), base, false, upper_case, m_zero_pad, m_align, part_length, m_fill, m_sign_mode); - builder.put_u64(value.low().low(), base, false, upper_case, m_zero_pad, m_align, part_length, m_fill, m_sign_mode); - } else if (m_width.value() > part_length * 2) { - builder.put_u64(value.high().low(), base, m_alternative_form, upper_case, m_zero_pad, m_align, m_width.value() - part_length * 2, m_fill, m_sign_mode); - builder.put_u64(value.low().high(), base, false, upper_case, m_zero_pad, m_align, part_length, m_fill, m_sign_mode); - builder.put_u64(value.low().low(), base, false, upper_case, m_zero_pad, m_align, part_length, m_fill, m_sign_mode); - } else if (m_width.value() > part_length) { - builder.put_u64(value.low().high(), base, m_alternative_form, upper_case, m_zero_pad, m_align, m_width.value() - part_length, m_fill, m_sign_mode); - builder.put_u64(value.low().low(), base, false, upper_case, m_zero_pad, m_align, part_length, m_fill, m_sign_mode); - } else { - builder.put_u64(value.low().low(), base, m_alternative_form, upper_case, m_zero_pad, m_align, m_width.value(), m_fill, m_sign_mode); - } -} diff --git a/Userland/Libraries/LibX86/Types/u128.h b/Userland/Libraries/LibX86/Types/u128.h deleted file mode 100644 index 92d5b12bd9..0000000000 --- a/Userland/Libraries/LibX86/Types/u128.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2021, Leon Albrecht - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace X86 { - -class u128 { -public: - constexpr u128() = default; - template - constexpr u128(T val) - : m_low(val) - { - } - constexpr u128(u64 val_low, u64 val_high) - : m_low(val_low) - , m_high(val_high) - { - } - - ALWAYS_INLINE u8* bytes() - { - return m_bytes; - } - ALWAYS_INLINE const u8* bytes() const - { - return m_bytes; - } - - ALWAYS_INLINE u16* words() - { - return (u16*)m_bytes; - } - ALWAYS_INLINE const u16* words() const - { - return (const u16*)m_bytes; - } - - ALWAYS_INLINE u32* double_words() - { - return (u32*)m_bytes; - } - ALWAYS_INLINE const u32* double_words() const - { - return (const u32*)m_bytes; - } - - ALWAYS_INLINE constexpr u64& low() - { - return m_low; - } - ALWAYS_INLINE constexpr const u64& low() const - { - return m_low; - } - - ALWAYS_INLINE constexpr u64& high() - { - return m_high; - } - ALWAYS_INLINE constexpr const u64& high() const - { - return m_high; - } - - // conversion - template - ALWAYS_INLINE constexpr operator T() const - { - return m_low; - } - - ALWAYS_INLINE constexpr operator bool() const - { - return m_low || m_high; - } - - // comparisons - template - ALWAYS_INLINE constexpr bool operator==(const T& other) const - { - return (!m_high) && m_low == other; - } - template - ALWAYS_INLINE constexpr bool operator!=(const T& other) const - { - return m_high || m_low != other; - } - template - ALWAYS_INLINE constexpr bool operator>(const T& other) const - { - return m_high || m_low > other; - } - template - ALWAYS_INLINE constexpr bool operator<(const T& other) const - { - return !m_high && m_low < other; - } - template - ALWAYS_INLINE constexpr bool operator>=(const T& other) const - { - return *this == other || *this > other; - } - template - ALWAYS_INLINE constexpr bool operator<=(const T& other) const - { - return *this == other || *this < other; - } - - ALWAYS_INLINE constexpr bool operator==(const u128& other) const - { - return m_low == other.low() && m_high == other.high(); - } - ALWAYS_INLINE constexpr bool operator!=(const u128& other) const - { - return m_low != other.low() || m_high != other.high(); - } - ALWAYS_INLINE constexpr bool operator>(const u128& other) const - { - return m_high > other.high() - || (m_high == other.high() && m_low > other.low()); - } - ALWAYS_INLINE constexpr bool operator<(const u128& other) const - { - return m_high < other.high() - || (m_high == other.high() && m_low < other.low()); - } - ALWAYS_INLINE constexpr bool operator>=(const u128& other) const - { - return *this == other || *this > other; - } - ALWAYS_INLINE constexpr bool operator<=(const u128& other) const - { - return *this == other || *this < other; - } - - // bitwise - template - ALWAYS_INLINE constexpr T operator&(const T& other) const - { - return m_low & other; - } - template - ALWAYS_INLINE constexpr u128 operator|(const T& other) const - { - return { m_low | other, m_high }; - } - template - ALWAYS_INLINE constexpr u128 operator^(const T& other) const - { - return { m_low ^ other, m_high }; - } - template - ALWAYS_INLINE constexpr u128 operator<<(const T& other) const - { - u64 overflow = m_low >> (64 - other); - return { m_low << other, (m_high << other) | overflow }; - } - template - ALWAYS_INLINE constexpr u128 operator>>(const T& other) const - { - u64 underflow = m_high & other; - return { (m_low >> other) | (underflow << (64 - other)), m_high >> other }; - } - - ALWAYS_INLINE constexpr u128 operator&(const u128& other) const - { - return { m_low & other.low(), m_high & other.high() }; - } - ALWAYS_INLINE constexpr u128 operator|(const u128& other) const - { - return { m_low | other.low(), m_high | other.high() }; - } - ALWAYS_INLINE constexpr u128 operator^(const u128& other) const - { - return { m_low ^ other.low(), m_high ^ other.high() }; - } - - // bitwise assign - template - constexpr u128& operator&=(const T& other) - { - m_high = 0; - m_low &= other; - return *this; - } - template - constexpr u128& operator|=(const T& other) - { - m_low |= other; - return *this; - } - template - constexpr u128& operator^=(const T& other) - { - m_low ^= other; - return *this; - } - template - constexpr u128& operator>>=(const T& other) - { - *this = *this >> other; - return *this; - } - template - constexpr u128& operator<<=(const T& other) - { - *this = *this << other; - return *this; - } - - constexpr u128& operator&=(const u128& other) - { - m_high &= other.high(); - m_low &= other.low(); - return *this; - } - constexpr u128& operator|=(const u128& other) - { - m_high |= other.high(); - m_low |= other.low(); - return *this; - } - constexpr u128& operator^=(const u128& other) - { - m_high ^= other.high(); - m_low ^= other.low(); - return *this; - } - -private: - union { - u8 m_bytes[16] = { 0 }; - struct { - u64 m_low; - u64 m_high; - }; - }; -}; - -static_assert(sizeof(u128) == 16); - -template -concept Unsigned_128 = IsUnsigned || IsSame; - -} - -using X86::u128; -using X86::Unsigned_128; - -template<> -struct AK::Formatter : StandardFormatter { - Formatter() = default; - explicit Formatter(StandardFormatter formatter) - : StandardFormatter(formatter) - { - } - - void format(AK::FormatBuilder&, u128); -}; diff --git a/Userland/Libraries/LibX86/Types/u256.h b/Userland/Libraries/LibX86/Types/u256.h deleted file mode 100644 index fc19bd7c28..0000000000 --- a/Userland/Libraries/LibX86/Types/u256.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2021, Leon Albrecht - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "u128.h" - -#include -#include -#include - -namespace X86 { - -class u256 { -public: - constexpr u256() = default; - constexpr u256(u64 val) - : m_low(val) - { - } - constexpr u256(u128 val) - : m_low(val) - { - } - constexpr u256(u128 val_low, u128 val_high) - : m_low(val_low) - , m_high(val_high) - { - } - - ALWAYS_INLINE u8* bytes() - { - return (u8*)this; - } - ALWAYS_INLINE const u8* bytes() const - { - return (const u8*)this; - } - - ALWAYS_INLINE u16* words() - { - return (u16*)this; - } - ALWAYS_INLINE const u16* words() const - { - return (const u16*)this; - } - - ALWAYS_INLINE u32* double_words() - { - return (u32*)this; - } - ALWAYS_INLINE const u32* double_words() const - { - return (const u32*)this; - } - - ALWAYS_INLINE constexpr u128& low() - { - return m_low; - } - ALWAYS_INLINE constexpr const u128& low() const - { - return m_low; - } - - ALWAYS_INLINE constexpr u128& high() - { - return m_high; - } - ALWAYS_INLINE constexpr const u128& high() const - { - return m_high; - } - // conversion - template - ALWAYS_INLINE constexpr operator T() const - { - return m_low; - } - - ALWAYS_INLINE constexpr operator bool() const - { - return m_low || m_high; - } - - // comparisons - template - ALWAYS_INLINE constexpr bool operator==(const T& other) const - { - return !m_high && m_low == other; - } - template - ALWAYS_INLINE constexpr bool operator!=(const T& other) const - { - return m_high || m_low != other; - } - template - ALWAYS_INLINE constexpr bool operator>(const T& other) const - { - return m_high || m_low > other; - } - template - ALWAYS_INLINE constexpr bool operator<(const T& other) const - { - return !m_high && m_low < other; - } - template - ALWAYS_INLINE constexpr bool operator>=(const T& other) const - { - return *this == other || *this > other; - } - template - ALWAYS_INLINE constexpr bool operator<=(const T& other) const - { - return *this == other || *this < other; - } - - ALWAYS_INLINE constexpr bool operator==(const u256& other) const - { - return m_low == other.low() && m_high == other.high(); - } - ALWAYS_INLINE constexpr bool operator!=(const u256& other) const - { - return m_low != other.low() || m_high != other.high(); - } - ALWAYS_INLINE constexpr bool operator>(const u256& other) const - { - return m_high > other.high() - || (m_high == other.high() && m_low > other.low()); - } - ALWAYS_INLINE constexpr bool operator<(const u256& other) const - { - return m_high < other.high() - || (m_high == other.high() && m_low < other.low()); - } - ALWAYS_INLINE constexpr bool operator>=(const u256& other) const - { - return *this == other || *this > other; - } - ALWAYS_INLINE constexpr bool operator<=(const u256& other) const - { - return *this == other || *this < other; - } - - // bitwise - template - ALWAYS_INLINE constexpr T operator&(const T& other) const - { - return m_low & other; - } - template - ALWAYS_INLINE constexpr u256 operator|(const T& other) const - { - return { m_low | other, m_high }; - } - template - ALWAYS_INLINE constexpr u256 operator^(const T& other) const - { - return { m_low ^ other, m_high }; - } - template - ALWAYS_INLINE constexpr u256 operator<<(const T& other) const - { - u128 overflow = m_low >> (128 - other); - return { m_low << other, (m_high << other) | overflow }; - } - template - ALWAYS_INLINE constexpr u256 operator>>(const T& other) const - { - u128 underflow = m_high & other; - return { (m_low >> other) | (underflow << (128 - other)), m_high >> other }; - } - - ALWAYS_INLINE constexpr u256 operator&(const u256& other) const - { - return { m_low & other.low(), m_high & other.high() }; - } - ALWAYS_INLINE constexpr u256 operator|(const u256& other) const - { - return { m_low | other.low(), m_high | other.high() }; - } - ALWAYS_INLINE constexpr u256 operator^(const u256& other) const - { - return { m_low ^ other.low(), m_high ^ other.high() }; - } - - // bitwise assign - template - constexpr u256& operator&=(const T& other) - { - m_high = 0; - m_low &= other; - return *this; - } - template - constexpr u256& operator|=(const T& other) - { - m_low |= other; - return *this; - } - template - constexpr u256& operator^=(const T& other) - { - m_low ^= other; - return *this; - } - template - constexpr u256& operator>>=(const T& other) - { - *this = *this >> other; - return *this; - } - template - constexpr u256& operator<<=(const T& other) - { - *this = *this << other; - return *this; - } - - constexpr u256& operator&=(const u256& other) - { - m_high &= other.high(); - m_low &= other.low(); - return *this; - } - constexpr u256& operator|=(const u256& other) - { - m_high |= other.high(); - m_low |= other.low(); - return *this; - } - constexpr u256& operator^=(const u256& other) - { - m_high ^= other.high(); - m_low ^= other.low(); - return *this; - } - -private: - // FIXME: Somehow make this a union to directly expose the bytes (see u128) - u128 m_low {}; - u128 m_high {}; -}; - -static_assert(sizeof(u256) == 32); - -template -concept Unsigned_256 = IsUnsigned || IsSame || IsSame; - -} - -using X86::u256; -using X86::Unsigned_256; - -template<> -struct AK::Formatter : StandardFormatter { - Formatter() = default; - explicit Formatter(StandardFormatter formatter) - : StandardFormatter(formatter) - { - } - - void format(AK::FormatBuilder&, u256); -};