diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0fa66d10..5807525a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ add_library(dynarmic common/memory_pool.cpp common/memory_pool.h common/mp.h + common/safe_ops.h common/scope_exit.h common/sm4.cpp common/sm4.h diff --git a/src/common/safe_ops.h b/src/common/safe_ops.h new file mode 100644 index 00000000..bc6d7b88 --- /dev/null +++ b/src/common/safe_ops.h @@ -0,0 +1,109 @@ +/* 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 + +#include "common/bit_util.h" +#include "common/common_types.h" +#include "common/u128.h" + +namespace Dynarmic::Safe { + +template T LogicalShiftLeft(T value, int shift_amount); +template T LogicalShiftRight(T value, int shift_amount); +template T ArithmeticShiftLeft(T value, int shift_amount); +template T ArithmeticShiftRight(T value, int shift_amount); + +template +T LogicalShiftLeft(T value, int shift_amount) { + static_assert(std::is_integral_v); + + if (shift_amount >= static_cast(Common::BitSize())) { + return 0; + } + + if (shift_amount < 0) { + return LogicalShiftRight(value, -shift_amount); + } + + auto unsigned_value = static_cast>(value); + return static_cast(unsigned_value << shift_amount); +} + +template<> +inline u128 LogicalShiftLeft(u128 value, int shift_amount) { + return value << shift_amount; +} + +template +T LogicalShiftRight(T value, int shift_amount) { + static_assert(std::is_integral_v); + + if (shift_amount >= static_cast(Common::BitSize())) { + return 0; + } + + if (shift_amount < 0) { + return LogicalShiftLeft(value, -shift_amount); + } + + auto unsigned_value = static_cast>(value); + return static_cast(unsigned_value >> shift_amount); +} + +template<> +inline u128 LogicalShiftRight(u128 value, int shift_amount) { + return value >> shift_amount; +} + +template +T LogicalShiftRightDouble(T top, T bottom, int shift_amount) { + return LogicalShiftLeft(top, int(Common::BitSize()) - shift_amount) | LogicalShiftRight(bottom, shift_amount); +} + +template +T ArithmeticShiftLeft(T value, int shift_amount) { + static_assert(std::is_integral_v); + + if (shift_amount >= static_cast(Common::BitSize())) { + return 0; + } + + if (shift_amount < 0) { + return ArithmeticShiftRight(value, -shift_amount); + } + + auto signed_value = static_cast>(value); + return static_cast(signed_value << shift_amount); +} + +template +T ArithmeticShiftRight(T value, int shift_amount) { + static_assert(std::is_integral_v); + + if (shift_amount >= static_cast(Common::BitSize())) { + return Common::MostSignificantBit(value) ? ~static_cast(0) : 0; + } + + if (shift_amount < 0) { + return ArithmeticShiftLeft(value, -shift_amount); + } + + auto signed_value = static_cast>(value); + return static_cast(signed_value >> shift_amount); +} + +template +T ArithmeticShiftRightDouble(T top, T bottom, int shift_amount) { + return ArithmeticShiftLeft(top, int(Common::BitSize()) - shift_amount) | LogicalShiftRight(bottom, shift_amount); +} + +template +T Negate(T value) { + return static_cast(-static_cast>(value)); +} + +} // namespace Dynarmic::Safe