summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHendiadyoin1 <leon2002.la@gmail.com>2021-04-10 23:25:23 +0200
committerAndreas Kling <kling@serenityos.org>2021-04-23 22:50:53 +0200
commita99812633bc0791c4f7bda99fc24240f9062ad55 (patch)
tree235254ef2b1e3cca4d5eb44137f51b3f4d5f6d29
parentfa59d02692426d2122a2b197ce17ccd01d725299 (diff)
downloadserenity-a99812633bc0791c4f7bda99fc24240f9062ad55.zip
LibX86: Add basic u128 and u256 constainers
These support all bitwise operations
-rw-r--r--Userland/Libraries/LibX86/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibX86/Types.h10
-rw-r--r--Userland/Libraries/LibX86/Types/Formatter.cpp113
-rw-r--r--Userland/Libraries/LibX86/Types/u128.h268
-rw-r--r--Userland/Libraries/LibX86/Types/u256.h268
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);
+};