mirror of
https://github.com/azahar-emu/dynarmic
synced 2025-11-08 16:10:05 +01:00
For example, say the converted signed type is s64, shifting left by 63 bits would be undefined behavior. However, given an ASL is essentially the same behavior as an LSL we can just use an unsigned type instead of converting to a signed type.
110 lines
3.1 KiB
C++
110 lines
3.1 KiB
C++
/* This file is part of the dynarmic project.
|
|
* Copyright (c) 2018 MerryMage
|
|
* This software may be used and distributed according to the terms of the GNU
|
|
* General Public License version 2 or any later version.
|
|
*/
|
|
|
|
#include <type_traits>
|
|
|
|
#include "common/bit_util.h"
|
|
#include "common/common_types.h"
|
|
#include "common/u128.h"
|
|
|
|
namespace Dynarmic::Safe {
|
|
|
|
template<typename T> T LogicalShiftLeft(T value, int shift_amount);
|
|
template<typename T> T LogicalShiftRight(T value, int shift_amount);
|
|
template<typename T> T ArithmeticShiftLeft(T value, int shift_amount);
|
|
template<typename T> 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>(Common::BitSize<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);
|
|
}
|
|
|
|
template<>
|
|
inline u128 LogicalShiftLeft(u128 value, int shift_amount) {
|
|
return value << 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>(Common::BitSize<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);
|
|
}
|
|
|
|
template<>
|
|
inline u128 LogicalShiftRight(u128 value, int shift_amount) {
|
|
return value >> shift_amount;
|
|
}
|
|
|
|
template<typename T>
|
|
T LogicalShiftRightDouble(T top, T bottom, int shift_amount) {
|
|
return LogicalShiftLeft(top, int(Common::BitSize<T>()) - shift_amount) | LogicalShiftRight(bottom, 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>(Common::BitSize<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);
|
|
}
|
|
|
|
template<typename T>
|
|
T ArithmeticShiftRight(T value, int shift_amount) {
|
|
static_assert(std::is_integral_v<T>);
|
|
|
|
if (shift_amount >= static_cast<int>(Common::BitSize<T>())) {
|
|
return Common::MostSignificantBit(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);
|
|
}
|
|
|
|
template<typename T>
|
|
T ArithmeticShiftRightDouble(T top, T bottom, int shift_amount) {
|
|
return ArithmeticShiftLeft(top, int(Common::BitSize<T>()) - shift_amount) | LogicalShiftRight(bottom, shift_amount);
|
|
}
|
|
|
|
template<typename T>
|
|
T Negate(T value) {
|
|
return static_cast<T>(~static_cast<std::uintmax_t>(value) + 1);
|
|
}
|
|
|
|
} // namespace Dynarmic::Safe
|