diff options
author | Hendiadyoin1 <leon2002.la@gmail.com> | 2021-04-10 23:25:23 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-04-23 22:50:53 +0200 |
commit | a99812633bc0791c4f7bda99fc24240f9062ad55 (patch) | |
tree | 235254ef2b1e3cca4d5eb44137f51b3f4d5f6d29 | |
parent | fa59d02692426d2122a2b197ce17ccd01d725299 (diff) | |
download | serenity-a99812633bc0791c4f7bda99fc24240f9062ad55.zip |
LibX86: Add basic u128 and u256 constainers
These support all bitwise operations
-rw-r--r-- | Userland/Libraries/LibX86/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibX86/Types.h | 10 | ||||
-rw-r--r-- | Userland/Libraries/LibX86/Types/Formatter.cpp | 113 | ||||
-rw-r--r-- | Userland/Libraries/LibX86/Types/u128.h | 268 | ||||
-rw-r--r-- | Userland/Libraries/LibX86/Types/u256.h | 268 |
5 files changed, 660 insertions, 0 deletions
diff --git a/Userland/Libraries/LibX86/CMakeLists.txt b/Userland/Libraries/LibX86/CMakeLists.txt index 2f5dad9214..2ac28c1aab 100644 --- a/Userland/Libraries/LibX86/CMakeLists.txt +++ b/Userland/Libraries/LibX86/CMakeLists.txt @@ -1,5 +1,6 @@ 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 new file mode 100644 index 0000000000..3ccb176874 --- /dev/null +++ b/Userland/Libraries/LibX86/Types.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com> + * + * 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 new file mode 100644 index 0000000000..0e7b5575fe --- /dev/null +++ b/Userland/Libraries/LibX86/Types/Formatter.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "u128.h" +#include "u256.h" + +#include <AK/Format.h> +#include <AK/String.h> +#include <AK/StringBuilder.h> +#include <serenity.h> +#include <stdio.h> + +void AK::Formatter<u128>::format(AK::FormatBuilder& builder, u128 value) +{ + if (value.high() == 0) { + AK::Formatter<u64> 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<u256>::format(AK::FormatBuilder& builder, u256 value) +{ + if (value.high() == 0) { + AK::Formatter<u128> 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 new file mode 100644 index 0000000000..92d5b12bd9 --- /dev/null +++ b/Userland/Libraries/LibX86/Types/u128.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Concepts.h> +#include <AK/Format.h> +#include <AK/Types.h> + +namespace X86 { + +class u128 { +public: + constexpr u128() = default; + template<Unsigned T> + 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<Unsigned T> + ALWAYS_INLINE constexpr operator T() const + { + return m_low; + } + + ALWAYS_INLINE constexpr operator bool() const + { + return m_low || m_high; + } + + // comparisons + template<Unsigned T> + ALWAYS_INLINE constexpr bool operator==(const T& other) const + { + return (!m_high) && m_low == other; + } + template<Unsigned T> + ALWAYS_INLINE constexpr bool operator!=(const T& other) const + { + return m_high || m_low != other; + } + template<Unsigned T> + ALWAYS_INLINE constexpr bool operator>(const T& other) const + { + return m_high || m_low > other; + } + template<Unsigned T> + ALWAYS_INLINE constexpr bool operator<(const T& other) const + { + return !m_high && m_low < other; + } + template<Unsigned T> + ALWAYS_INLINE constexpr bool operator>=(const T& other) const + { + return *this == other || *this > other; + } + template<Unsigned T> + 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<Unsigned T> + ALWAYS_INLINE constexpr T operator&(const T& other) const + { + return m_low & other; + } + template<Unsigned T> + ALWAYS_INLINE constexpr u128 operator|(const T& other) const + { + return { m_low | other, m_high }; + } + template<Unsigned T> + ALWAYS_INLINE constexpr u128 operator^(const T& other) const + { + return { m_low ^ other, m_high }; + } + template<Unsigned T> + ALWAYS_INLINE constexpr u128 operator<<(const T& other) const + { + u64 overflow = m_low >> (64 - other); + return { m_low << other, (m_high << other) | overflow }; + } + template<Unsigned T> + 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<Unsigned T> + constexpr u128& operator&=(const T& other) + { + m_high = 0; + m_low &= other; + return *this; + } + template<Unsigned T> + constexpr u128& operator|=(const T& other) + { + m_low |= other; + return *this; + } + template<Unsigned T> + constexpr u128& operator^=(const T& other) + { + m_low ^= other; + return *this; + } + template<Unsigned T> + constexpr u128& operator>>=(const T& other) + { + *this = *this >> other; + return *this; + } + template<Unsigned T> + 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<typename T> +concept Unsigned_128 = IsUnsigned<T> || IsSame<T, u128>; + +} + +using X86::u128; +using X86::Unsigned_128; + +template<> +struct AK::Formatter<u128> : 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 new file mode 100644 index 0000000000..fc19bd7c28 --- /dev/null +++ b/Userland/Libraries/LibX86/Types/u256.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include "u128.h" + +#include <AK/Concepts.h> +#include <AK/Format.h> +#include <AK/Types.h> + +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<Unsigned_128 T> + ALWAYS_INLINE constexpr operator T() const + { + return m_low; + } + + ALWAYS_INLINE constexpr operator bool() const + { + return m_low || m_high; + } + + // comparisons + template<Unsigned_128 T> + ALWAYS_INLINE constexpr bool operator==(const T& other) const + { + return !m_high && m_low == other; + } + template<Unsigned_128 T> + ALWAYS_INLINE constexpr bool operator!=(const T& other) const + { + return m_high || m_low != other; + } + template<Unsigned_128 T> + ALWAYS_INLINE constexpr bool operator>(const T& other) const + { + return m_high || m_low > other; + } + template<Unsigned_128 T> + ALWAYS_INLINE constexpr bool operator<(const T& other) const + { + return !m_high && m_low < other; + } + template<Unsigned_128 T> + ALWAYS_INLINE constexpr bool operator>=(const T& other) const + { + return *this == other || *this > other; + } + template<Unsigned_128 T> + 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<Unsigned_128 T> + ALWAYS_INLINE constexpr T operator&(const T& other) const + { + return m_low & other; + } + template<Unsigned_128 T> + ALWAYS_INLINE constexpr u256 operator|(const T& other) const + { + return { m_low | other, m_high }; + } + template<Unsigned_128 T> + ALWAYS_INLINE constexpr u256 operator^(const T& other) const + { + return { m_low ^ other, m_high }; + } + template<Unsigned_128 T> + ALWAYS_INLINE constexpr u256 operator<<(const T& other) const + { + u128 overflow = m_low >> (128 - other); + return { m_low << other, (m_high << other) | overflow }; + } + template<Unsigned_128 T> + 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<Unsigned_128 T> + constexpr u256& operator&=(const T& other) + { + m_high = 0; + m_low &= other; + return *this; + } + template<Unsigned_128 T> + constexpr u256& operator|=(const T& other) + { + m_low |= other; + return *this; + } + template<Unsigned_128 T> + constexpr u256& operator^=(const T& other) + { + m_low ^= other; + return *this; + } + template<Unsigned_128 T> + constexpr u256& operator>>=(const T& other) + { + *this = *this >> other; + return *this; + } + template<Unsigned_128 T> + 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<typename T> +concept Unsigned_256 = IsUnsigned<T> || IsSame<T, u128> || IsSame<T, u256>; + +} + +using X86::u256; +using X86::Unsigned_256; + +template<> +struct AK::Formatter<u256> : StandardFormatter { + Formatter() = default; + explicit Formatter(StandardFormatter formatter) + : StandardFormatter(formatter) + { + } + + void format(AK::FormatBuilder&, u256); +}; |