/* 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