[common] rework BitField and BitUtil, use concepts whenever possible (#4076)

test no regressions especially on Liiinux

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4076
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
This commit is contained in:
lizzie
2026-07-09 03:47:04 +02:00
committed by crueter
parent c2e74a9380
commit 41762940d6
31 changed files with 529 additions and 757 deletions
@@ -85,8 +85,8 @@ public:
/// @brief Code emitter: Calls the function
template<typename F>
requires std::is_pointer_v<F> && std::is_function_v<std::remove_pointer_t<F>>
void CallFunction(F fn) {
static_assert(std::is_pointer_v<F> && std::is_function_v<std::remove_pointer_t<F>>, "Supplied type must be a pointer to a function");
::Common::X64::CallFarFunction(*this, fn);
}
@@ -5076,9 +5076,8 @@ void EmitX64::EmitVectorSignedSaturatedNeg64(EmitContext& ctx, IR::Inst* inst) {
# pragma clang diagnostic ignored "-Wunused-lambda-capture"
#endif
template<typename T, typename U = std::make_unsigned_t<T>>
requires std::is_signed_v<T>
static bool VectorSignedSaturatedShiftLeft(VectorArray<T>& dst, const VectorArray<T>& data, const VectorArray<T>& shift_values) {
static_assert(std::is_signed_v<T>, "T must be signed.");
bool qc_flag = false;
constexpr size_t bit_size_minus_one = mcl::bitsizeof<T> - 1;
@@ -5134,9 +5133,9 @@ void EmitX64::EmitVectorSignedSaturatedShiftLeft64(EmitContext& ctx, IR::Inst* i
}
template<typename T>
requires std::is_signed_v<T>
static bool VectorSignedSaturatedShiftLeftUnsigned(VectorArray<T>& dst, const VectorArray<T>& data, u8 shift_amount) {
using U = std::make_unsigned_t<T>;
static_assert(std::is_signed_v<T>, "T must be signed.");
bool qc_flag = false;
for (size_t i = 0; i < dst.size(); i++) {
auto const element = data[i];
@@ -6030,17 +6029,15 @@ void EmitX64::EmitVectorUnsignedRecipSqrtEstimate(EmitContext& ctx, IR::Inst* in
// Simple generic case for 8, 16, and 32-bit values. 64-bit values
// will need to be special-cased as we can't simply use a larger integral size.
template<typename T, typename U = std::make_unsigned_t<T>>
requires std::is_signed_v<T>
static bool EmitVectorUnsignedSaturatedAccumulateSigned(VectorArray<U>& result, const VectorArray<T>& lhs, const VectorArray<T>& rhs) {
static_assert(std::is_signed_v<T>, "T must be signed.");
static_assert(mcl::bitsizeof<T> < 64, "T must be less than 64 bits in size.");
bool qc_flag = false;
for (size_t i = 0; i < result.size(); i++) {
// We treat rhs' members as unsigned, so cast to unsigned before signed to inhibit sign-extension.
// We use the unsigned equivalent of T, as we want zero-extension to occur, rather than a plain move.
const s64 x = s64{lhs[i]};
const s64 y = static_cast<s64>(static_cast<std::make_unsigned_t<U>>(rhs[i]));
const s64 y = s64(std::make_unsigned_t<U>(rhs[i]));
const s64 sum = x + y;
if (sum > (std::numeric_limits<U>::max)()) {
@@ -6050,10 +6047,9 @@ static bool EmitVectorUnsignedSaturatedAccumulateSigned(VectorArray<U>& result,
result[i] = (std::numeric_limits<U>::min)();
qc_flag = true;
} else {
result[i] = static_cast<U>(sum);
result[i] = U(sum);
}
}
return qc_flag;
}
@@ -6134,29 +6130,23 @@ void EmitX64::EmitVectorUnsignedSaturatedNarrow64(EmitContext& ctx, IR::Inst* in
}
template<typename T, typename S = std::make_signed_t<T>>
requires std::is_unsigned_v<T>
static bool VectorUnsignedSaturatedShiftLeft(VectorArray<T>& dst, const VectorArray<T>& data, const VectorArray<T>& shift_values) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned type.");
bool qc_flag = false;
constexpr size_t bit_size = mcl::bitsizeof<T>;
constexpr S negative_bit_size = -static_cast<S>(bit_size);
constexpr S negative_bit_size = -S(bit_size);
for (size_t i = 0; i < dst.size(); i++) {
const T element = data[i];
const S shift = std::clamp(static_cast<S>(mcl::bit::sign_extend<8>(static_cast<T>(shift_values[i] & 0xFF))),
negative_bit_size, (std::numeric_limits<S>::max)());
const S shift = std::clamp(S(mcl::bit::sign_extend<8>(T(shift_values[i] & 0xFF))), negative_bit_size, (std::numeric_limits<S>::max)());
if (element == 0 || shift <= negative_bit_size) {
dst[i] = 0;
} else if (shift < 0) {
dst[i] = static_cast<T>(element >> -shift);
} else if (shift >= static_cast<S>(bit_size)) {
dst[i] = T(element >> -shift);
} else if (shift >= S(bit_size)) {
dst[i] = (std::numeric_limits<T>::max)();
qc_flag = true;
} else {
const T shifted = element << shift;
if ((shifted >> shift) != element) {
dst[i] = (std::numeric_limits<T>::max)();
qc_flag = true;
+18 -46
View File
@@ -28,18 +28,11 @@ T ArithmeticShiftRight(T value, int shift_amount);
template<typename T>
T LogicalShiftLeft(T value, int shift_amount) {
static_assert(std::is_integral_v<T>);
if (shift_amount >= static_cast<int>(mcl::bitsizeof<T>)) {
if (shift_amount >= int(mcl::bitsizeof<T>))
return 0;
}
if (shift_amount < 0) {
return LogicalShiftRight(value, -shift_amount);
}
auto unsigned_value = static_cast<std::make_unsigned_t<T>>(value);
return static_cast<T>(unsigned_value << shift_amount);
return shift_amount < 0
? LogicalShiftRight(value, -shift_amount)
: T(std::make_unsigned_t<T>(value) << shift_amount);
}
template<>
@@ -49,18 +42,11 @@ inline u128 LogicalShiftLeft(u128 value, int shift_amount) {
template<typename T>
T LogicalShiftRight(T value, int shift_amount) {
static_assert(std::is_integral_v<T>);
if (shift_amount >= static_cast<int>(mcl::bitsizeof<T>)) {
if (shift_amount >= int(mcl::bitsizeof<T>))
return 0;
}
if (shift_amount < 0) {
return LogicalShiftLeft(value, -shift_amount);
}
auto unsigned_value = static_cast<std::make_unsigned_t<T>>(value);
return static_cast<T>(unsigned_value >> shift_amount);
return shift_amount < 0
? LogicalShiftLeft(value, -shift_amount)
: T(std::make_unsigned_t<T>(value) >> shift_amount);
}
template<>
@@ -75,34 +61,20 @@ T LogicalShiftRightDouble(T top, T bottom, int shift_amount) {
template<typename T>
T ArithmeticShiftLeft(T value, int shift_amount) {
static_assert(std::is_integral_v<T>);
if (shift_amount >= static_cast<int>(mcl::bitsizeof<T>)) {
if (shift_amount >= int(mcl::bitsizeof<T>))
return 0;
}
if (shift_amount < 0) {
return ArithmeticShiftRight(value, -shift_amount);
}
auto unsigned_value = static_cast<std::make_unsigned_t<T>>(value);
return static_cast<T>(unsigned_value << shift_amount);
return shift_amount < 0
? ArithmeticShiftRight(value, -shift_amount)
: T(std::make_unsigned_t<T>(value) << shift_amount);
}
template<typename T>
T ArithmeticShiftRight(T value, int shift_amount) {
static_assert(std::is_integral_v<T>);
if (shift_amount >= static_cast<int>(mcl::bitsizeof<T>)) {
return mcl::bit::most_significant_bit(value) ? ~static_cast<T>(0) : 0;
}
if (shift_amount < 0) {
return ArithmeticShiftLeft(value, -shift_amount);
}
auto signed_value = static_cast<std::make_signed_t<T>>(value);
return static_cast<T>(signed_value >> shift_amount);
if (shift_amount >= int(mcl::bitsizeof<T>))
return mcl::bit::most_significant_bit(value) ? ~T(0) : 0;
return shift_amount < 0
? ArithmeticShiftLeft(value, -shift_amount)
: T(std::make_signed_t<T>(value) >> shift_amount);
}
template<typename T>
@@ -112,7 +84,7 @@ T ArithmeticShiftRightDouble(T top, T bottom, int shift_amount) {
template<typename T>
T Negate(T value) {
return static_cast<T>(~static_cast<std::uintmax_t>(value) + 1);
return T(~std::uintmax_t(value) + 1);
}
} // namespace Dynarmic::Safe
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -47,8 +50,8 @@ public:
/// the exclusive state for processors if their exclusive region(s)
/// contain [address, address+size).
template<typename T, typename Function>
requires std::is_trivially_copyable_v<T>
bool DoExclusiveOperation(size_t processor_id, VAddr address, Function op) {
static_assert(std::is_trivially_copyable_v<T>);
if (!CheckAndClear(processor_id, address)) {
return false;
}
+5 -4
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2020 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -17,11 +20,9 @@ inline std::mt19937 g_rand_int_generator = [] {
} // namespace detail
template<typename T>
requires std::is_integral_v<T>
&& (!std::is_same_v<T, signed char> && !std::is_same_v<T, unsigned char>)
T RandInt(T min, T max) {
static_assert(std::is_integral_v<T>, "T must be an integral type.");
static_assert(!std::is_same_v<T, signed char> && !std::is_same_v<T, unsigned char>,
"Using char with uniform_int_distribution is undefined behavior.");
std::uniform_int_distribution<T> rand(min, max);
return rand(detail::g_rand_int_generator);
}