1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 12:47:35 +00:00

LibX86: Add basic u128 and u256 constainers

These support all bitwise operations
This commit is contained in:
Hendiadyoin1 2021-04-10 23:25:23 +02:00 committed by Andreas Kling
parent fa59d02692
commit a99812633b
5 changed files with 660 additions and 0 deletions

View file

@ -1,5 +1,6 @@
set(SOURCES
Instruction.cpp
Types/Formatter.cpp
)
serenity_lib(LibX86 x86)

View file

@ -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"

View file

@ -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);
}
}

View file

@ -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);
};

View file

@ -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);
};