diff options
Diffstat (limited to 'src/common')
52 files changed, 4132 insertions, 3417 deletions
diff --git a/src/common/assert.h b/src/common/assert.h index cd9b819a9..04e80c87a 100644 --- a/src/common/assert.h +++ b/src/common/assert.h | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstdlib> | 7 | #include <cstdlib> |
| 8 | |||
| 9 | #include "common/common_funcs.h" | 8 | #include "common/common_funcs.h" |
| 10 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 11 | 10 | ||
| @@ -18,25 +17,29 @@ | |||
| 18 | // enough for our purposes. | 17 | // enough for our purposes. |
| 19 | template <typename Fn> | 18 | template <typename Fn> |
| 20 | #if defined(_MSC_VER) | 19 | #if defined(_MSC_VER) |
| 21 | __declspec(noinline, noreturn) | 20 | __declspec(noinline, noreturn) |
| 22 | #elif defined(__GNUC__) | 21 | #elif defined(__GNUC__) |
| 23 | __attribute__((noinline, noreturn, cold)) | 22 | __attribute__((noinline, noreturn, cold)) |
| 24 | #endif | 23 | #endif |
| 25 | static void assert_noinline_call(const Fn& fn) { | 24 | static void assert_noinline_call(const Fn& fn) { |
| 26 | fn(); | 25 | fn(); |
| 27 | Crash(); | 26 | Crash(); |
| 28 | exit(1); // Keeps GCC's mouth shut about this actually returning | 27 | exit(1); // Keeps GCC's mouth shut about this actually returning |
| 29 | } | 28 | } |
| 30 | 29 | ||
| 31 | #define ASSERT(_a_) \ | 30 | #define ASSERT(_a_) \ |
| 32 | do if (!(_a_)) { assert_noinline_call([] { \ | 31 | do \ |
| 33 | LOG_CRITICAL(Debug, "Assertion Failed!"); \ | 32 | if (!(_a_)) { \ |
| 34 | }); } while (0) | 33 | assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \ |
| 34 | } \ | ||
| 35 | while (0) | ||
| 35 | 36 | ||
| 36 | #define ASSERT_MSG(_a_, ...) \ | 37 | #define ASSERT_MSG(_a_, ...) \ |
| 37 | do if (!(_a_)) { assert_noinline_call([&] { \ | 38 | do \ |
| 38 | LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \ | 39 | if (!(_a_)) { \ |
| 39 | }); } while (0) | 40 | assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \ |
| 41 | } \ | ||
| 42 | while (0) | ||
| 40 | 43 | ||
| 41 | #define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!") | 44 | #define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!") |
| 42 | #define UNREACHABLE_MSG(...) ASSERT_MSG(false, __VA_ARGS__) | 45 | #define UNREACHABLE_MSG(...) ASSERT_MSG(false, __VA_ARGS__) |
| @@ -50,4 +53,4 @@ static void assert_noinline_call(const Fn& fn) { | |||
| 50 | #endif | 53 | #endif |
| 51 | 54 | ||
| 52 | #define UNIMPLEMENTED() DEBUG_ASSERT_MSG(false, "Unimplemented code!") | 55 | #define UNIMPLEMENTED() DEBUG_ASSERT_MSG(false, "Unimplemented code!") |
| 53 | #define UNIMPLEMENTED_MSG(_a_, ...) ASSERT_MSG(false, _a_, __VA_ARGS__) \ No newline at end of file | 56 | #define UNIMPLEMENTED_MSG(_a_, ...) ASSERT_MSG(false, _a_, __VA_ARGS__) |
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 4748999ed..030f7caeb 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | // Licensed under GPLv2 or any later version | 1 | // Licensed under GPLv2 or any later version |
| 2 | // Refer to the license.txt file included. | 2 | // Refer to the license.txt file included. |
| 3 | 3 | ||
| 4 | |||
| 5 | // Copyright 2014 Tony Wasserka | 4 | // Copyright 2014 Tony Wasserka |
| 6 | // All rights reserved. | 5 | // All rights reserved. |
| 7 | // | 6 | // |
| @@ -29,13 +28,11 @@ | |||
| 29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 | 30 | ||
| 32 | |||
| 33 | #pragma once | 31 | #pragma once |
| 34 | 32 | ||
| 35 | #include <cstddef> | 33 | #include <cstddef> |
| 36 | #include <limits> | 34 | #include <limits> |
| 37 | #include <type_traits> | 35 | #include <type_traits> |
| 38 | |||
| 39 | #include "common/common_funcs.h" | 36 | #include "common/common_funcs.h" |
| 40 | 37 | ||
| 41 | /* | 38 | /* |
| @@ -111,9 +108,8 @@ | |||
| 111 | * symptoms. | 108 | * symptoms. |
| 112 | */ | 109 | */ |
| 113 | #pragma pack(1) | 110 | #pragma pack(1) |
| 114 | template<std::size_t position, std::size_t bits, typename T> | 111 | template <std::size_t position, std::size_t bits, typename T> |
| 115 | struct BitField | 112 | struct BitField { |
| 116 | { | ||
| 117 | private: | 113 | private: |
| 118 | // We hide the copy assigment operator here, because the default copy | 114 | // We hide the copy assigment operator here, because the default copy |
| 119 | // assignment would copy the full storage value, rather than just the bits | 115 | // assignment would copy the full storage value, rather than just the bits |
| @@ -141,13 +137,10 @@ public: | |||
| 141 | } | 137 | } |
| 142 | 138 | ||
| 143 | FORCE_INLINE T Value() const { | 139 | FORCE_INLINE T Value() const { |
| 144 | if (std::numeric_limits<T>::is_signed) | 140 | if (std::numeric_limits<T>::is_signed) { |
| 145 | { | 141 | std::size_t shift = 8 * sizeof(T) - bits; |
| 146 | std::size_t shift = 8 * sizeof(T)-bits; | ||
| 147 | return (T)((storage << (shift - position)) >> shift); | 142 | return (T)((storage << (shift - position)) >> shift); |
| 148 | } | 143 | } else { |
| 149 | else | ||
| 150 | { | ||
| 151 | return (T)((storage & GetMask()) >> position); | 144 | return (T)((storage & GetMask()) >> position); |
| 152 | } | 145 | } |
| 153 | } | 146 | } |
| @@ -162,15 +155,14 @@ private: | |||
| 162 | // T is an enumeration. Note that T is wrapped within an enable_if in the | 155 | // T is an enumeration. Note that T is wrapped within an enable_if in the |
| 163 | // former case to workaround compile errors which arise when using | 156 | // former case to workaround compile errors which arise when using |
| 164 | // std::underlying_type<T>::type directly. | 157 | // std::underlying_type<T>::type directly. |
| 165 | typedef typename std::conditional < std::is_enum<T>::value, | 158 | typedef typename std::conditional<std::is_enum<T>::value, std::underlying_type<T>, |
| 166 | std::underlying_type<T>, | 159 | std::enable_if<true, T>>::type::type StorageType; |
| 167 | std::enable_if < true, T >> ::type::type StorageType; | ||
| 168 | 160 | ||
| 169 | // Unsigned version of StorageType | 161 | // Unsigned version of StorageType |
| 170 | typedef typename std::make_unsigned<StorageType>::type StorageTypeU; | 162 | typedef typename std::make_unsigned<StorageType>::type StorageTypeU; |
| 171 | 163 | ||
| 172 | FORCE_INLINE StorageType GetMask() const { | 164 | FORCE_INLINE StorageType GetMask() const { |
| 173 | return (((StorageTypeU)~0) >> (8 * sizeof(T)-bits)) << position; | 165 | return (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; |
| 174 | } | 166 | } |
| 175 | 167 | ||
| 176 | StorageType storage; | 168 | StorageType storage; |
| @@ -186,5 +178,6 @@ private: | |||
| 186 | #pragma pack() | 178 | #pragma pack() |
| 187 | 179 | ||
| 188 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) | 180 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) |
| 189 | static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, "BitField must be trivially copyable"); | 181 | static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, |
| 182 | "BitField must be trivially copyable"); | ||
| 190 | #endif | 183 | #endif |
diff --git a/src/common/bit_set.h b/src/common/bit_set.h index 7f5de8df2..c48b3b769 100644 --- a/src/common/bit_set.h +++ b/src/common/bit_set.h | |||
| @@ -18,49 +18,60 @@ namespace Common { | |||
| 18 | 18 | ||
| 19 | #ifdef _WIN32 | 19 | #ifdef _WIN32 |
| 20 | template <typename T> | 20 | template <typename T> |
| 21 | static inline int CountSetBits(T v) | 21 | static inline int CountSetBits(T v) { |
| 22 | { | ||
| 23 | // from https://graphics.stanford.edu/~seander/bithacks.html | 22 | // from https://graphics.stanford.edu/~seander/bithacks.html |
| 24 | // GCC has this built in, but MSVC's intrinsic will only emit the actual | 23 | // GCC has this built in, but MSVC's intrinsic will only emit the actual |
| 25 | // POPCNT instruction, which we're not depending on | 24 | // POPCNT instruction, which we're not depending on |
| 26 | v = v - ((v >> 1) & (T)~(T)0/3); | 25 | v = v - ((v >> 1) & (T) ~(T)0 / 3); |
| 27 | v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); | 26 | v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3); |
| 28 | v = (v + (v >> 4)) & (T)~(T)0/255*15; | 27 | v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15; |
| 29 | return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * 8; | 28 | return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8; |
| 30 | } | 29 | } |
| 31 | static inline int LeastSignificantSetBit(u8 val) | 30 | static inline int LeastSignificantSetBit(u8 val) { |
| 32 | { | ||
| 33 | unsigned long index; | 31 | unsigned long index; |
| 34 | _BitScanForward(&index, val); | 32 | _BitScanForward(&index, val); |
| 35 | return (int)index; | 33 | return (int)index; |
| 36 | } | 34 | } |
| 37 | static inline int LeastSignificantSetBit(u16 val) | 35 | static inline int LeastSignificantSetBit(u16 val) { |
| 38 | { | ||
| 39 | unsigned long index; | 36 | unsigned long index; |
| 40 | _BitScanForward(&index, val); | 37 | _BitScanForward(&index, val); |
| 41 | return (int)index; | 38 | return (int)index; |
| 42 | } | 39 | } |
| 43 | static inline int LeastSignificantSetBit(u32 val) | 40 | static inline int LeastSignificantSetBit(u32 val) { |
| 44 | { | ||
| 45 | unsigned long index; | 41 | unsigned long index; |
| 46 | _BitScanForward(&index, val); | 42 | _BitScanForward(&index, val); |
| 47 | return (int)index; | 43 | return (int)index; |
| 48 | } | 44 | } |
| 49 | static inline int LeastSignificantSetBit(u64 val) | 45 | static inline int LeastSignificantSetBit(u64 val) { |
| 50 | { | ||
| 51 | unsigned long index; | 46 | unsigned long index; |
| 52 | _BitScanForward64(&index, val); | 47 | _BitScanForward64(&index, val); |
| 53 | return (int)index; | 48 | return (int)index; |
| 54 | } | 49 | } |
| 55 | #else | 50 | #else |
| 56 | static inline int CountSetBits(u8 val) { return __builtin_popcount(val); } | 51 | static inline int CountSetBits(u8 val) { |
| 57 | static inline int CountSetBits(u16 val) { return __builtin_popcount(val); } | 52 | return __builtin_popcount(val); |
| 58 | static inline int CountSetBits(u32 val) { return __builtin_popcount(val); } | 53 | } |
| 59 | static inline int CountSetBits(u64 val) { return __builtin_popcountll(val); } | 54 | static inline int CountSetBits(u16 val) { |
| 60 | static inline int LeastSignificantSetBit(u8 val) { return __builtin_ctz(val); } | 55 | return __builtin_popcount(val); |
| 61 | static inline int LeastSignificantSetBit(u16 val) { return __builtin_ctz(val); } | 56 | } |
| 62 | static inline int LeastSignificantSetBit(u32 val) { return __builtin_ctz(val); } | 57 | static inline int CountSetBits(u32 val) { |
| 63 | static inline int LeastSignificantSetBit(u64 val) { return __builtin_ctzll(val); } | 58 | return __builtin_popcount(val); |
| 59 | } | ||
| 60 | static inline int CountSetBits(u64 val) { | ||
| 61 | return __builtin_popcountll(val); | ||
| 62 | } | ||
| 63 | static inline int LeastSignificantSetBit(u8 val) { | ||
| 64 | return __builtin_ctz(val); | ||
| 65 | } | ||
| 66 | static inline int LeastSignificantSetBit(u16 val) { | ||
| 67 | return __builtin_ctz(val); | ||
| 68 | } | ||
| 69 | static inline int LeastSignificantSetBit(u32 val) { | ||
| 70 | return __builtin_ctz(val); | ||
| 71 | } | ||
| 72 | static inline int LeastSignificantSetBit(u64 val) { | ||
| 73 | return __builtin_ctzll(val); | ||
| 74 | } | ||
| 64 | #endif | 75 | #endif |
| 65 | 76 | ||
| 66 | // Similar to std::bitset, this is a class which encapsulates a bitset, i.e. | 77 | // Similar to std::bitset, this is a class which encapsulates a bitset, i.e. |
| @@ -84,57 +95,62 @@ static inline int LeastSignificantSetBit(u64 val) { return __builtin_ctzll(val); | |||
| 84 | // TODO: use constexpr when MSVC gets out of the Dark Ages | 95 | // TODO: use constexpr when MSVC gets out of the Dark Ages |
| 85 | 96 | ||
| 86 | template <typename IntTy> | 97 | template <typename IntTy> |
| 87 | class BitSet | 98 | class BitSet { |
| 88 | { | ||
| 89 | static_assert(!std::is_signed<IntTy>::value, "BitSet should not be used with signed types"); | 99 | static_assert(!std::is_signed<IntTy>::value, "BitSet should not be used with signed types"); |
| 100 | |||
| 90 | public: | 101 | public: |
| 91 | // A reference to a particular bit, returned from operator[]. | 102 | // A reference to a particular bit, returned from operator[]. |
| 92 | class Ref | 103 | class Ref { |
| 93 | { | ||
| 94 | public: | 104 | public: |
| 95 | Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {} | 105 | Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {} |
| 96 | Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {} | 106 | Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {} |
| 97 | operator bool() const { return (m_bs->m_val & m_mask) != 0; } | 107 | operator bool() const { |
| 98 | bool operator=(bool set) | 108 | return (m_bs->m_val & m_mask) != 0; |
| 99 | { | 109 | } |
| 110 | bool operator=(bool set) { | ||
| 100 | m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0); | 111 | m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0); |
| 101 | return set; | 112 | return set; |
| 102 | } | 113 | } |
| 114 | |||
| 103 | private: | 115 | private: |
| 104 | BitSet* m_bs; | 116 | BitSet* m_bs; |
| 105 | IntTy m_mask; | 117 | IntTy m_mask; |
| 106 | }; | 118 | }; |
| 107 | 119 | ||
| 108 | // A STL-like iterator is required to be able to use range-based for loops. | 120 | // A STL-like iterator is required to be able to use range-based for loops. |
| 109 | class Iterator | 121 | class Iterator { |
| 110 | { | ||
| 111 | public: | 122 | public: |
| 112 | Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {} | 123 | Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {} |
| 113 | Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) {} | 124 | Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) {} |
| 114 | Iterator& operator=(Iterator other) { new (this) Iterator(other); return *this; } | 125 | Iterator& operator=(Iterator other) { |
| 115 | int operator*() { return m_bit; } | 126 | new (this) Iterator(other); |
| 116 | Iterator& operator++() | 127 | return *this; |
| 117 | { | 128 | } |
| 118 | if (m_val == 0) | 129 | int operator*() { |
| 119 | { | 130 | return m_bit; |
| 131 | } | ||
| 132 | Iterator& operator++() { | ||
| 133 | if (m_val == 0) { | ||
| 120 | m_bit = -1; | 134 | m_bit = -1; |
| 121 | } | 135 | } else { |
| 122 | else | ||
| 123 | { | ||
| 124 | int bit = LeastSignificantSetBit(m_val); | 136 | int bit = LeastSignificantSetBit(m_val); |
| 125 | m_val &= ~(1 << bit); | 137 | m_val &= ~(1 << bit); |
| 126 | m_bit = bit; | 138 | m_bit = bit; |
| 127 | } | 139 | } |
| 128 | return *this; | 140 | return *this; |
| 129 | } | 141 | } |
| 130 | Iterator operator++(int _) | 142 | Iterator operator++(int _) { |
| 131 | { | ||
| 132 | Iterator other(*this); | 143 | Iterator other(*this); |
| 133 | ++*this; | 144 | ++*this; |
| 134 | return other; | 145 | return other; |
| 135 | } | 146 | } |
| 136 | bool operator==(Iterator other) const { return m_bit == other.m_bit; } | 147 | bool operator==(Iterator other) const { |
| 137 | bool operator!=(Iterator other) const { return m_bit != other.m_bit; } | 148 | return m_bit == other.m_bit; |
| 149 | } | ||
| 150 | bool operator!=(Iterator other) const { | ||
| 151 | return m_bit != other.m_bit; | ||
| 152 | } | ||
| 153 | |||
| 138 | private: | 154 | private: |
| 139 | IntTy m_val; | 155 | IntTy m_val; |
| 140 | int m_bit; | 156 | int m_bit; |
| @@ -142,42 +158,75 @@ public: | |||
| 142 | 158 | ||
| 143 | BitSet() : m_val(0) {} | 159 | BitSet() : m_val(0) {} |
| 144 | explicit BitSet(IntTy val) : m_val(val) {} | 160 | explicit BitSet(IntTy val) : m_val(val) {} |
| 145 | BitSet(std::initializer_list<int> init) | 161 | BitSet(std::initializer_list<int> init) { |
| 146 | { | ||
| 147 | m_val = 0; | 162 | m_val = 0; |
| 148 | for (int bit : init) | 163 | for (int bit : init) |
| 149 | m_val |= (IntTy)1 << bit; | 164 | m_val |= (IntTy)1 << bit; |
| 150 | } | 165 | } |
| 151 | 166 | ||
| 152 | static BitSet AllTrue(size_t count) | 167 | static BitSet AllTrue(size_t count) { |
| 153 | { | 168 | return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); |
| 154 | return BitSet(count == sizeof(IntTy)*8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); | 169 | } |
| 155 | } | 170 | |
| 156 | 171 | Ref operator[](size_t bit) { | |
| 157 | Ref operator[](size_t bit) { return Ref(this, (IntTy)1 << bit); } | 172 | return Ref(this, (IntTy)1 << bit); |
| 158 | const Ref operator[](size_t bit) const { return (*const_cast<BitSet*>(this))[bit]; } | 173 | } |
| 159 | bool operator==(BitSet other) const { return m_val == other.m_val; } | 174 | const Ref operator[](size_t bit) const { |
| 160 | bool operator!=(BitSet other) const { return m_val != other.m_val; } | 175 | return (*const_cast<BitSet*>(this))[bit]; |
| 161 | bool operator<(BitSet other) const { return m_val < other.m_val; } | 176 | } |
| 162 | bool operator>(BitSet other) const { return m_val > other.m_val; } | 177 | bool operator==(BitSet other) const { |
| 163 | BitSet operator|(BitSet other) const { return BitSet(m_val | other.m_val); } | 178 | return m_val == other.m_val; |
| 164 | BitSet operator&(BitSet other) const { return BitSet(m_val & other.m_val); } | 179 | } |
| 165 | BitSet operator^(BitSet other) const { return BitSet(m_val ^ other.m_val); } | 180 | bool operator!=(BitSet other) const { |
| 166 | BitSet operator~() const { return BitSet(~m_val); } | 181 | return m_val != other.m_val; |
| 167 | BitSet& operator|=(BitSet other) { return *this = *this | other; } | 182 | } |
| 168 | BitSet& operator&=(BitSet other) { return *this = *this & other; } | 183 | bool operator<(BitSet other) const { |
| 169 | BitSet& operator^=(BitSet other) { return *this = *this ^ other; } | 184 | return m_val < other.m_val; |
| 185 | } | ||
| 186 | bool operator>(BitSet other) const { | ||
| 187 | return m_val > other.m_val; | ||
| 188 | } | ||
| 189 | BitSet operator|(BitSet other) const { | ||
| 190 | return BitSet(m_val | other.m_val); | ||
| 191 | } | ||
| 192 | BitSet operator&(BitSet other) const { | ||
| 193 | return BitSet(m_val & other.m_val); | ||
| 194 | } | ||
| 195 | BitSet operator^(BitSet other) const { | ||
| 196 | return BitSet(m_val ^ other.m_val); | ||
| 197 | } | ||
| 198 | BitSet operator~() const { | ||
| 199 | return BitSet(~m_val); | ||
| 200 | } | ||
| 201 | BitSet& operator|=(BitSet other) { | ||
| 202 | return *this = *this | other; | ||
| 203 | } | ||
| 204 | BitSet& operator&=(BitSet other) { | ||
| 205 | return *this = *this & other; | ||
| 206 | } | ||
| 207 | BitSet& operator^=(BitSet other) { | ||
| 208 | return *this = *this ^ other; | ||
| 209 | } | ||
| 170 | operator u32() = delete; | 210 | operator u32() = delete; |
| 171 | operator bool() { return m_val != 0; } | 211 | operator bool() { |
| 212 | return m_val != 0; | ||
| 213 | } | ||
| 172 | 214 | ||
| 173 | // Warning: Even though on modern CPUs this is a single fast instruction, | 215 | // Warning: Even though on modern CPUs this is a single fast instruction, |
| 174 | // Dolphin's official builds do not currently assume POPCNT support on x86, | 216 | // Dolphin's official builds do not currently assume POPCNT support on x86, |
| 175 | // so slower explicit bit twiddling is generated. Still should generally | 217 | // so slower explicit bit twiddling is generated. Still should generally |
| 176 | // be faster than a loop. | 218 | // be faster than a loop. |
| 177 | unsigned int Count() const { return CountSetBits(m_val); } | 219 | unsigned int Count() const { |
| 220 | return CountSetBits(m_val); | ||
| 221 | } | ||
| 178 | 222 | ||
| 179 | Iterator begin() const { Iterator it(m_val, 0); return ++it; } | 223 | Iterator begin() const { |
| 180 | Iterator end() const { return Iterator(m_val, -1); } | 224 | Iterator it(m_val, 0); |
| 225 | return ++it; | ||
| 226 | } | ||
| 227 | Iterator end() const { | ||
| 228 | return Iterator(m_val, -1); | ||
| 229 | } | ||
| 181 | 230 | ||
| 182 | IntTy m_val; | 231 | IntTy m_val; |
| 183 | }; | 232 | }; |
diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp index e7d0d3e43..03a19acba 100644 --- a/src/common/break_points.cpp +++ b/src/common/break_points.cpp | |||
| @@ -2,33 +2,29 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 6 | #include <sstream> | ||
| 5 | #include "common/break_points.h" | 7 | #include "common/break_points.h" |
| 6 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 7 | 9 | ||
| 8 | #include <sstream> | 10 | bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const { |
| 9 | #include <algorithm> | ||
| 10 | |||
| 11 | bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const | ||
| 12 | { | ||
| 13 | auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; }; | 11 | auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; }; |
| 14 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); | 12 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); |
| 15 | return it != m_BreakPoints.end(); | 13 | return it != m_BreakPoints.end(); |
| 16 | } | 14 | } |
| 17 | 15 | ||
| 18 | bool BreakPoints::IsTempBreakPoint(u32 iAddress) const | 16 | bool BreakPoints::IsTempBreakPoint(u32 iAddress) const { |
| 19 | { | 17 | auto cond = [&iAddress](const TBreakPoint& bp) { |
| 20 | auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress && bp.bTemporary; }; | 18 | return bp.iAddress == iAddress && bp.bTemporary; |
| 21 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); | 19 | }; |
| 20 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); | ||
| 22 | return it != m_BreakPoints.end(); | 21 | return it != m_BreakPoints.end(); |
| 23 | } | 22 | } |
| 24 | 23 | ||
| 25 | BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const | 24 | BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const { |
| 26 | { | ||
| 27 | TBreakPointsStr bps; | 25 | TBreakPointsStr bps; |
| 28 | for (auto breakpoint : m_BreakPoints) | 26 | for (auto breakpoint : m_BreakPoints) { |
| 29 | { | 27 | if (!breakpoint.bTemporary) { |
| 30 | if (!breakpoint.bTemporary) | ||
| 31 | { | ||
| 32 | std::stringstream bp; | 28 | std::stringstream bp; |
| 33 | bp << std::hex << breakpoint.iAddress << " " << (breakpoint.bOn ? "n" : ""); | 29 | bp << std::hex << breakpoint.iAddress << " " << (breakpoint.bOn ? "n" : ""); |
| 34 | bps.push_back(bp.str()); | 30 | bps.push_back(bp.str()); |
| @@ -38,10 +34,8 @@ BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const | |||
| 38 | return bps; | 34 | return bps; |
| 39 | } | 35 | } |
| 40 | 36 | ||
| 41 | void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) | 37 | void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) { |
| 42 | { | 38 | for (auto bps_item : bps) { |
| 43 | for (auto bps_item : bps) | ||
| 44 | { | ||
| 45 | TBreakPoint bp; | 39 | TBreakPoint bp; |
| 46 | std::stringstream bpstr; | 40 | std::stringstream bpstr; |
| 47 | bpstr << std::hex << bps_item; | 41 | bpstr << std::hex << bps_item; |
| @@ -52,18 +46,15 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) | |||
| 52 | } | 46 | } |
| 53 | } | 47 | } |
| 54 | 48 | ||
| 55 | void BreakPoints::Add(const TBreakPoint& bp) | 49 | void BreakPoints::Add(const TBreakPoint& bp) { |
| 56 | { | 50 | if (!IsAddressBreakPoint(bp.iAddress)) { |
| 57 | if (!IsAddressBreakPoint(bp.iAddress)) | ||
| 58 | { | ||
| 59 | m_BreakPoints.push_back(bp); | 51 | m_BreakPoints.push_back(bp); |
| 60 | //if (jit) | 52 | // if (jit) |
| 61 | // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); | 53 | // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); |
| 62 | } | 54 | } |
| 63 | } | 55 | } |
| 64 | 56 | ||
| 65 | void BreakPoints::Add(u32 em_address, bool temp) | 57 | void BreakPoints::Add(u32 em_address, bool temp) { |
| 66 | { | ||
| 67 | if (!IsAddressBreakPoint(em_address)) // only add new addresses | 58 | if (!IsAddressBreakPoint(em_address)) // only add new addresses |
| 68 | { | 59 | { |
| 69 | TBreakPoint pt; // breakpoint settings | 60 | TBreakPoint pt; // breakpoint settings |
| @@ -73,22 +64,20 @@ void BreakPoints::Add(u32 em_address, bool temp) | |||
| 73 | 64 | ||
| 74 | m_BreakPoints.push_back(pt); | 65 | m_BreakPoints.push_back(pt); |
| 75 | 66 | ||
| 76 | //if (jit) | 67 | // if (jit) |
| 77 | // jit->GetBlockCache()->InvalidateICache(em_address, 4); | 68 | // jit->GetBlockCache()->InvalidateICache(em_address, 4); |
| 78 | } | 69 | } |
| 79 | } | 70 | } |
| 80 | 71 | ||
| 81 | void BreakPoints::Remove(u32 em_address) | 72 | void BreakPoints::Remove(u32 em_address) { |
| 82 | { | ||
| 83 | auto cond = [&em_address](const TBreakPoint& bp) { return bp.iAddress == em_address; }; | 73 | auto cond = [&em_address](const TBreakPoint& bp) { return bp.iAddress == em_address; }; |
| 84 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); | 74 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); |
| 85 | if (it != m_BreakPoints.end()) | 75 | if (it != m_BreakPoints.end()) |
| 86 | m_BreakPoints.erase(it); | 76 | m_BreakPoints.erase(it); |
| 87 | } | 77 | } |
| 88 | 78 | ||
| 89 | void BreakPoints::Clear() | 79 | void BreakPoints::Clear() { |
| 90 | { | 80 | // if (jit) |
| 91 | //if (jit) | ||
| 92 | //{ | 81 | //{ |
| 93 | // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(), | 82 | // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(), |
| 94 | // [](const TBreakPoint& bp) | 83 | // [](const TBreakPoint& bp) |
diff --git a/src/common/break_points.h b/src/common/break_points.h index b0629df37..e15b9f842 100644 --- a/src/common/break_points.h +++ b/src/common/break_points.h | |||
| @@ -4,28 +4,27 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | ||
| 8 | #include <string> | 7 | #include <string> |
| 9 | 8 | #include <vector> | |
| 10 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 11 | 10 | ||
| 12 | class DebugInterface; | 11 | class DebugInterface; |
| 13 | 12 | ||
| 14 | struct TBreakPoint | 13 | struct TBreakPoint { |
| 15 | { | 14 | u32 iAddress; |
| 16 | u32 iAddress; | ||
| 17 | bool bOn; | 15 | bool bOn; |
| 18 | bool bTemporary; | 16 | bool bTemporary; |
| 19 | }; | 17 | }; |
| 20 | 18 | ||
| 21 | // Code breakpoints. | 19 | // Code breakpoints. |
| 22 | class BreakPoints | 20 | class BreakPoints { |
| 23 | { | ||
| 24 | public: | 21 | public: |
| 25 | typedef std::vector<TBreakPoint> TBreakPoints; | 22 | typedef std::vector<TBreakPoint> TBreakPoints; |
| 26 | typedef std::vector<std::string> TBreakPointsStr; | 23 | typedef std::vector<std::string> TBreakPointsStr; |
| 27 | 24 | ||
| 28 | const TBreakPoints& GetBreakPoints() { return m_BreakPoints; } | 25 | const TBreakPoints& GetBreakPoints() { |
| 26 | return m_BreakPoints; | ||
| 27 | } | ||
| 29 | 28 | ||
| 30 | TBreakPointsStr GetStrings() const; | 29 | TBreakPointsStr GetStrings() const; |
| 31 | void AddFromStrings(const TBreakPointsStr& bps); | 30 | void AddFromStrings(const TBreakPointsStr& bps); |
| @@ -35,7 +34,7 @@ public: | |||
| 35 | bool IsTempBreakPoint(u32 iAddress) const; | 34 | bool IsTempBreakPoint(u32 iAddress) const; |
| 36 | 35 | ||
| 37 | // Add BreakPoint | 36 | // Add BreakPoint |
| 38 | void Add(u32 em_address, bool temp=false); | 37 | void Add(u32 em_address, bool temp = false); |
| 39 | void Add(const TBreakPoint& bp); | 38 | void Add(const TBreakPoint& bp); |
| 40 | 39 | ||
| 41 | // Remove Breakpoint | 40 | // Remove Breakpoint |
| @@ -46,5 +45,5 @@ public: | |||
| 46 | 45 | ||
| 47 | private: | 46 | private: |
| 48 | TBreakPoints m_BreakPoints; | 47 | TBreakPoints m_BreakPoints; |
| 49 | u32 m_iBreakOnCount; | 48 | u32 m_iBreakOnCount; |
| 50 | }; | 49 | }; |
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h index 1e1bcff31..5145a3657 100644 --- a/src/common/chunk_file.h +++ b/src/common/chunk_file.h | |||
| @@ -35,87 +35,90 @@ | |||
| 35 | #include <type_traits> | 35 | #include <type_traits> |
| 36 | #include <utility> | 36 | #include <utility> |
| 37 | #include <vector> | 37 | #include <vector> |
| 38 | |||
| 39 | #include "common/assert.h" | 38 | #include "common/assert.h" |
| 40 | #include "common/common_types.h" | 39 | #include "common/common_types.h" |
| 41 | #include "common/logging/log.h" | 40 | #include "common/logging/log.h" |
| 42 | 41 | ||
| 43 | template <class T> | 42 | template <class T> |
| 44 | struct LinkedListItem : public T | 43 | struct LinkedListItem : public T { |
| 45 | { | 44 | LinkedListItem<T>* next; |
| 46 | LinkedListItem<T> *next; | ||
| 47 | }; | 45 | }; |
| 48 | 46 | ||
| 49 | class PointerWrap; | 47 | class PointerWrap; |
| 50 | 48 | ||
| 51 | class PointerWrapSection | 49 | class PointerWrapSection { |
| 52 | { | ||
| 53 | public: | 50 | public: |
| 54 | PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { | 51 | PointerWrapSection(PointerWrap& p, int ver, const char* title) |
| 55 | } | 52 | : p_(p), ver_(ver), title_(title) {} |
| 56 | ~PointerWrapSection(); | 53 | ~PointerWrapSection(); |
| 57 | 54 | ||
| 58 | bool operator == (const int &v) const { return ver_ == v; } | 55 | bool operator==(const int& v) const { |
| 59 | bool operator != (const int &v) const { return ver_ != v; } | 56 | return ver_ == v; |
| 60 | bool operator <= (const int &v) const { return ver_ <= v; } | 57 | } |
| 61 | bool operator >= (const int &v) const { return ver_ >= v; } | 58 | bool operator!=(const int& v) const { |
| 62 | bool operator < (const int &v) const { return ver_ < v; } | 59 | return ver_ != v; |
| 63 | bool operator > (const int &v) const { return ver_ > v; } | 60 | } |
| 61 | bool operator<=(const int& v) const { | ||
| 62 | return ver_ <= v; | ||
| 63 | } | ||
| 64 | bool operator>=(const int& v) const { | ||
| 65 | return ver_ >= v; | ||
| 66 | } | ||
| 67 | bool operator<(const int& v) const { | ||
| 68 | return ver_ < v; | ||
| 69 | } | ||
| 70 | bool operator>(const int& v) const { | ||
| 71 | return ver_ > v; | ||
| 72 | } | ||
| 64 | 73 | ||
| 65 | operator bool() const { | 74 | operator bool() const { |
| 66 | return ver_ > 0; | 75 | return ver_ > 0; |
| 67 | } | 76 | } |
| 68 | 77 | ||
| 69 | private: | 78 | private: |
| 70 | PointerWrap &p_; | 79 | PointerWrap& p_; |
| 71 | int ver_; | 80 | int ver_; |
| 72 | const char *title_; | 81 | const char* title_; |
| 73 | }; | 82 | }; |
| 74 | 83 | ||
| 75 | // Wrapper class | 84 | // Wrapper class |
| 76 | class PointerWrap | 85 | class PointerWrap { |
| 77 | { | 86 | // This makes it a compile error if you forget to define DoState() on non-POD. |
| 78 | // This makes it a compile error if you forget to define DoState() on non-POD. | 87 | // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... |
| 79 | // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... | ||
| 80 | #ifdef _MSC_VER | 88 | #ifdef _MSC_VER |
| 81 | template<typename T, bool isPOD = std::is_pod<T>::value, bool isPointer = std::is_pointer<T>::value> | 89 | template <typename T, bool isPOD = std::is_pod<T>::value, |
| 90 | bool isPointer = std::is_pointer<T>::value> | ||
| 82 | #else | 91 | #else |
| 83 | template<typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value> | 92 | template <typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value> |
| 84 | #endif | 93 | #endif |
| 85 | struct DoHelper | 94 | struct DoHelper { |
| 86 | { | 95 | static void DoArray(PointerWrap* p, T* x, int count) { |
| 87 | static void DoArray(PointerWrap *p, T *x, int count) | ||
| 88 | { | ||
| 89 | for (int i = 0; i < count; ++i) | 96 | for (int i = 0; i < count; ++i) |
| 90 | p->Do(x[i]); | 97 | p->Do(x[i]); |
| 91 | } | 98 | } |
| 92 | 99 | ||
| 93 | static void Do(PointerWrap *p, T &x) | 100 | static void Do(PointerWrap* p, T& x) { |
| 94 | { | ||
| 95 | p->DoClass(x); | 101 | p->DoClass(x); |
| 96 | } | 102 | } |
| 97 | }; | 103 | }; |
| 98 | 104 | ||
| 99 | template<typename T> | 105 | template <typename T> |
| 100 | struct DoHelper<T, true, false> | 106 | struct DoHelper<T, true, false> { |
| 101 | { | 107 | static void DoArray(PointerWrap* p, T* x, int count) { |
| 102 | static void DoArray(PointerWrap *p, T *x, int count) | 108 | p->DoVoid((void*)x, sizeof(T) * count); |
| 103 | { | ||
| 104 | p->DoVoid((void *)x, sizeof(T) * count); | ||
| 105 | } | 109 | } |
| 106 | 110 | ||
| 107 | static void Do(PointerWrap *p, T &x) | 111 | static void Do(PointerWrap* p, T& x) { |
| 108 | { | 112 | p->DoVoid((void*)&x, sizeof(x)); |
| 109 | p->DoVoid((void *)&x, sizeof(x)); | ||
| 110 | } | 113 | } |
| 111 | }; | 114 | }; |
| 112 | 115 | ||
| 113 | public: | 116 | public: |
| 114 | enum Mode { | 117 | enum Mode { |
| 115 | MODE_READ = 1, // load | 118 | MODE_READ = 1, // load |
| 116 | MODE_WRITE, // save | 119 | MODE_WRITE, // save |
| 117 | MODE_MEASURE, // calculate size | 120 | MODE_MEASURE, // calculate size |
| 118 | MODE_VERIFY, // compare | 121 | MODE_VERIFY, // compare |
| 119 | }; | 122 | }; |
| 120 | 123 | ||
| 121 | enum Error { | 124 | enum Error { |
| @@ -124,247 +127,237 @@ public: | |||
| 124 | ERROR_FAILURE = 2, | 127 | ERROR_FAILURE = 2, |
| 125 | }; | 128 | }; |
| 126 | 129 | ||
| 127 | u8 **ptr; | 130 | u8** ptr; |
| 128 | Mode mode; | 131 | Mode mode; |
| 129 | Error error; | 132 | Error error; |
| 130 | 133 | ||
| 131 | public: | 134 | public: |
| 132 | PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} | 135 | PointerWrap(u8** ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} |
| 133 | PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} | 136 | PointerWrap(unsigned char** ptr_, int mode_) |
| 137 | : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} | ||
| 134 | 138 | ||
| 135 | PointerWrapSection Section(const char *title, int ver) { | 139 | PointerWrapSection Section(const char* title, int ver) { |
| 136 | return Section(title, ver, ver); | 140 | return Section(title, ver, ver); |
| 137 | } | 141 | } |
| 138 | 142 | ||
| 139 | // The returned object can be compared against the version that was loaded. | 143 | // The returned object can be compared against the version that was loaded. |
| 140 | // This can be used to support versions as old as minVer. | 144 | // This can be used to support versions as old as minVer. |
| 141 | // Version = 0 means the section was not found. | 145 | // Version = 0 means the section was not found. |
| 142 | PointerWrapSection Section(const char *title, int minVer, int ver) { | 146 | PointerWrapSection Section(const char* title, int minVer, int ver) { |
| 143 | char marker[16] = {0}; | 147 | char marker[16] = {0}; |
| 144 | int foundVersion = ver; | 148 | int foundVersion = ver; |
| 145 | 149 | ||
| 146 | strncpy(marker, title, sizeof(marker)); | 150 | strncpy(marker, title, sizeof(marker)); |
| 147 | if (!ExpectVoid(marker, sizeof(marker))) | 151 | if (!ExpectVoid(marker, sizeof(marker))) { |
| 148 | { | ||
| 149 | // Might be before we added name markers for safety. | 152 | // Might be before we added name markers for safety. |
| 150 | if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) | 153 | if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) |
| 151 | DoMarker(title); | 154 | DoMarker(title); |
| 152 | // Wasn't found, but maybe we can still load the state. | 155 | // Wasn't found, but maybe we can still load the state. |
| 153 | else | 156 | else |
| 154 | foundVersion = 0; | 157 | foundVersion = 0; |
| 155 | } | 158 | } else |
| 156 | else | ||
| 157 | Do(foundVersion); | 159 | Do(foundVersion); |
| 158 | 160 | ||
| 159 | if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { | 161 | if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { |
| 160 | LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion, title); | 162 | LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion, |
| 163 | title); | ||
| 161 | SetError(ERROR_FAILURE); | 164 | SetError(ERROR_FAILURE); |
| 162 | return PointerWrapSection(*this, -1, title); | 165 | return PointerWrapSection(*this, -1, title); |
| 163 | } | 166 | } |
| 164 | return PointerWrapSection(*this, foundVersion, title); | 167 | return PointerWrapSection(*this, foundVersion, title); |
| 165 | } | 168 | } |
| 166 | 169 | ||
| 167 | void SetMode(Mode mode_) {mode = mode_;} | 170 | void SetMode(Mode mode_) { |
| 168 | Mode GetMode() const {return mode;} | 171 | mode = mode_; |
| 169 | u8 **GetPPtr() {return ptr;} | 172 | } |
| 170 | void SetError(Error error_) | 173 | Mode GetMode() const { |
| 171 | { | 174 | return mode; |
| 175 | } | ||
| 176 | u8** GetPPtr() { | ||
| 177 | return ptr; | ||
| 178 | } | ||
| 179 | void SetError(Error error_) { | ||
| 172 | if (error < error_) | 180 | if (error < error_) |
| 173 | error = error_; | 181 | error = error_; |
| 174 | if (error > ERROR_WARNING) | 182 | if (error > ERROR_WARNING) |
| 175 | mode = PointerWrap::MODE_MEASURE; | 183 | mode = PointerWrap::MODE_MEASURE; |
| 176 | } | 184 | } |
| 177 | 185 | ||
| 178 | bool ExpectVoid(void *data, int size) | 186 | bool ExpectVoid(void* data, int size) { |
| 179 | { | ||
| 180 | switch (mode) { | 187 | switch (mode) { |
| 181 | case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break; | 188 | case MODE_READ: |
| 182 | case MODE_WRITE: memcpy(*ptr, data, size); break; | 189 | if (memcmp(data, *ptr, size) != 0) |
| 183 | case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything | 190 | return false; |
| 191 | break; | ||
| 192 | case MODE_WRITE: | ||
| 193 | memcpy(*ptr, data, size); | ||
| 194 | break; | ||
| 195 | case MODE_MEASURE: | ||
| 196 | break; // MODE_MEASURE - don't need to do anything | ||
| 184 | case MODE_VERIFY: | 197 | case MODE_VERIFY: |
| 185 | for (int i = 0; i < size; i++) { | 198 | for (int i = 0; i < size; i++) { |
| 186 | DEBUG_ASSERT_MSG(((u8*)data)[i] == (*ptr)[i], | 199 | DEBUG_ASSERT_MSG( |
| 200 | ((u8*)data)[i] == (*ptr)[i], | ||
| 187 | "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", | 201 | "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", |
| 188 | ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], | 202 | ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], |
| 189 | (*ptr)[i], (*ptr)[i], &(*ptr)[i]); | 203 | &(*ptr)[i]); |
| 190 | } | 204 | } |
| 191 | break; | 205 | break; |
| 192 | default: break; // throw an error? | 206 | default: |
| 207 | break; // throw an error? | ||
| 193 | } | 208 | } |
| 194 | (*ptr) += size; | 209 | (*ptr) += size; |
| 195 | return true; | 210 | return true; |
| 196 | } | 211 | } |
| 197 | 212 | ||
| 198 | void DoVoid(void *data, int size) | 213 | void DoVoid(void* data, int size) { |
| 199 | { | ||
| 200 | switch (mode) { | 214 | switch (mode) { |
| 201 | case MODE_READ: memcpy(data, *ptr, size); break; | 215 | case MODE_READ: |
| 202 | case MODE_WRITE: memcpy(*ptr, data, size); break; | 216 | memcpy(data, *ptr, size); |
| 203 | case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything | 217 | break; |
| 218 | case MODE_WRITE: | ||
| 219 | memcpy(*ptr, data, size); | ||
| 220 | break; | ||
| 221 | case MODE_MEASURE: | ||
| 222 | break; // MODE_MEASURE - don't need to do anything | ||
| 204 | case MODE_VERIFY: | 223 | case MODE_VERIFY: |
| 205 | for (int i = 0; i < size; i++) { | 224 | for (int i = 0; i < size; i++) { |
| 206 | DEBUG_ASSERT_MSG(((u8*)data)[i] == (*ptr)[i], | 225 | DEBUG_ASSERT_MSG( |
| 226 | ((u8*)data)[i] == (*ptr)[i], | ||
| 207 | "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", | 227 | "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", |
| 208 | ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], | 228 | ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], |
| 209 | (*ptr)[i], (*ptr)[i], &(*ptr)[i]); | 229 | &(*ptr)[i]); |
| 210 | } | 230 | } |
| 211 | break; | 231 | break; |
| 212 | default: break; // throw an error? | 232 | default: |
| 233 | break; // throw an error? | ||
| 213 | } | 234 | } |
| 214 | (*ptr) += size; | 235 | (*ptr) += size; |
| 215 | } | 236 | } |
| 216 | 237 | ||
| 217 | template<class K, class T> | 238 | template <class K, class T> |
| 218 | void Do(std::map<K, T *> &x) | 239 | void Do(std::map<K, T*>& x) { |
| 219 | { | 240 | if (mode == MODE_READ) { |
| 220 | if (mode == MODE_READ) | 241 | for (auto it = x.begin(), end = x.end(); it != end; ++it) { |
| 221 | { | ||
| 222 | for (auto it = x.begin(), end = x.end(); it != end; ++it) | ||
| 223 | { | ||
| 224 | if (it->second != nullptr) | 242 | if (it->second != nullptr) |
| 225 | delete it->second; | 243 | delete it->second; |
| 226 | } | 244 | } |
| 227 | } | 245 | } |
| 228 | T *dv = nullptr; | 246 | T* dv = nullptr; |
| 229 | DoMap(x, dv); | 247 | DoMap(x, dv); |
| 230 | } | 248 | } |
| 231 | 249 | ||
| 232 | template<class K, class T> | 250 | template <class K, class T> |
| 233 | void Do(std::map<K, T> &x) | 251 | void Do(std::map<K, T>& x) { |
| 234 | { | ||
| 235 | T dv = T(); | 252 | T dv = T(); |
| 236 | DoMap(x, dv); | 253 | DoMap(x, dv); |
| 237 | } | 254 | } |
| 238 | 255 | ||
| 239 | template<class K, class T> | 256 | template <class K, class T> |
| 240 | void DoMap(std::map<K, T> &x, T &default_val) | 257 | void DoMap(std::map<K, T>& x, T& default_val) { |
| 241 | { | ||
| 242 | unsigned int number = (unsigned int)x.size(); | 258 | unsigned int number = (unsigned int)x.size(); |
| 243 | Do(number); | 259 | Do(number); |
| 244 | switch (mode) { | 260 | switch (mode) { |
| 245 | case MODE_READ: | 261 | case MODE_READ: { |
| 246 | { | 262 | x.clear(); |
| 247 | x.clear(); | 263 | while (number > 0) { |
| 248 | while (number > 0) | 264 | K first = K(); |
| 249 | { | 265 | Do(first); |
| 250 | K first = K(); | 266 | T second = default_val; |
| 251 | Do(first); | 267 | Do(second); |
| 252 | T second = default_val; | 268 | x[first] = second; |
| 253 | Do(second); | 269 | --number; |
| 254 | x[first] = second; | ||
| 255 | --number; | ||
| 256 | } | ||
| 257 | } | 270 | } |
| 258 | break; | 271 | } break; |
| 259 | case MODE_WRITE: | 272 | case MODE_WRITE: |
| 260 | case MODE_MEASURE: | 273 | case MODE_MEASURE: |
| 261 | case MODE_VERIFY: | 274 | case MODE_VERIFY: { |
| 262 | { | 275 | typename std::map<K, T>::iterator itr = x.begin(); |
| 263 | typename std::map<K, T>::iterator itr = x.begin(); | 276 | while (number > 0) { |
| 264 | while (number > 0) | 277 | K first = itr->first; |
| 265 | { | 278 | Do(first); |
| 266 | K first = itr->first; | 279 | Do(itr->second); |
| 267 | Do(first); | 280 | --number; |
| 268 | Do(itr->second); | 281 | ++itr; |
| 269 | --number; | ||
| 270 | ++itr; | ||
| 271 | } | ||
| 272 | } | 282 | } |
| 273 | break; | 283 | } break; |
| 274 | } | 284 | } |
| 275 | } | 285 | } |
| 276 | 286 | ||
| 277 | template<class K, class T> | 287 | template <class K, class T> |
| 278 | void Do(std::multimap<K, T *> &x) | 288 | void Do(std::multimap<K, T*>& x) { |
| 279 | { | 289 | if (mode == MODE_READ) { |
| 280 | if (mode == MODE_READ) | 290 | for (auto it = x.begin(), end = x.end(); it != end; ++it) { |
| 281 | { | ||
| 282 | for (auto it = x.begin(), end = x.end(); it != end; ++it) | ||
| 283 | { | ||
| 284 | if (it->second != nullptr) | 291 | if (it->second != nullptr) |
| 285 | delete it->second; | 292 | delete it->second; |
| 286 | } | 293 | } |
| 287 | } | 294 | } |
| 288 | T *dv = nullptr; | 295 | T* dv = nullptr; |
| 289 | DoMultimap(x, dv); | 296 | DoMultimap(x, dv); |
| 290 | } | 297 | } |
| 291 | 298 | ||
| 292 | template<class K, class T> | 299 | template <class K, class T> |
| 293 | void Do(std::multimap<K, T> &x) | 300 | void Do(std::multimap<K, T>& x) { |
| 294 | { | ||
| 295 | T dv = T(); | 301 | T dv = T(); |
| 296 | DoMultimap(x, dv); | 302 | DoMultimap(x, dv); |
| 297 | } | 303 | } |
| 298 | 304 | ||
| 299 | template<class K, class T> | 305 | template <class K, class T> |
| 300 | void DoMultimap(std::multimap<K, T> &x, T &default_val) | 306 | void DoMultimap(std::multimap<K, T>& x, T& default_val) { |
| 301 | { | ||
| 302 | unsigned int number = (unsigned int)x.size(); | 307 | unsigned int number = (unsigned int)x.size(); |
| 303 | Do(number); | 308 | Do(number); |
| 304 | switch (mode) { | 309 | switch (mode) { |
| 305 | case MODE_READ: | 310 | case MODE_READ: { |
| 306 | { | 311 | x.clear(); |
| 307 | x.clear(); | 312 | while (number > 0) { |
| 308 | while (number > 0) | 313 | K first = K(); |
| 309 | { | 314 | Do(first); |
| 310 | K first = K(); | 315 | T second = default_val; |
| 311 | Do(first); | 316 | Do(second); |
| 312 | T second = default_val; | 317 | x.insert(std::make_pair(first, second)); |
| 313 | Do(second); | 318 | --number; |
| 314 | x.insert(std::make_pair(first, second)); | ||
| 315 | --number; | ||
| 316 | } | ||
| 317 | } | 319 | } |
| 318 | break; | 320 | } break; |
| 319 | case MODE_WRITE: | 321 | case MODE_WRITE: |
| 320 | case MODE_MEASURE: | 322 | case MODE_MEASURE: |
| 321 | case MODE_VERIFY: | 323 | case MODE_VERIFY: { |
| 322 | { | 324 | typename std::multimap<K, T>::iterator itr = x.begin(); |
| 323 | typename std::multimap<K, T>::iterator itr = x.begin(); | 325 | while (number > 0) { |
| 324 | while (number > 0) | 326 | Do(itr->first); |
| 325 | { | 327 | Do(itr->second); |
| 326 | Do(itr->first); | 328 | --number; |
| 327 | Do(itr->second); | 329 | ++itr; |
| 328 | --number; | ||
| 329 | ++itr; | ||
| 330 | } | ||
| 331 | } | 330 | } |
| 332 | break; | 331 | } break; |
| 333 | } | 332 | } |
| 334 | } | 333 | } |
| 335 | 334 | ||
| 336 | // Store vectors. | 335 | // Store vectors. |
| 337 | template<class T> | 336 | template <class T> |
| 338 | void Do(std::vector<T *> &x) | 337 | void Do(std::vector<T*>& x) { |
| 339 | { | 338 | T* dv = nullptr; |
| 340 | T *dv = nullptr; | ||
| 341 | DoVector(x, dv); | 339 | DoVector(x, dv); |
| 342 | } | 340 | } |
| 343 | 341 | ||
| 344 | template<class T> | 342 | template <class T> |
| 345 | void Do(std::vector<T> &x) | 343 | void Do(std::vector<T>& x) { |
| 346 | { | ||
| 347 | T dv = T(); | 344 | T dv = T(); |
| 348 | DoVector(x, dv); | 345 | DoVector(x, dv); |
| 349 | } | 346 | } |
| 350 | 347 | ||
| 351 | 348 | template <class T> | |
| 352 | template<class T> | 349 | void DoPOD(std::vector<T>& x) { |
| 353 | void DoPOD(std::vector<T> &x) | ||
| 354 | { | ||
| 355 | T dv = T(); | 350 | T dv = T(); |
| 356 | DoVectorPOD(x, dv); | 351 | DoVectorPOD(x, dv); |
| 357 | } | 352 | } |
| 358 | 353 | ||
| 359 | template<class T> | 354 | template <class T> |
| 360 | void Do(std::vector<T> &x, T &default_val) | 355 | void Do(std::vector<T>& x, T& default_val) { |
| 361 | { | ||
| 362 | DoVector(x, default_val); | 356 | DoVector(x, default_val); |
| 363 | } | 357 | } |
| 364 | 358 | ||
| 365 | template<class T> | 359 | template <class T> |
| 366 | void DoVector(std::vector<T> &x, T &default_val) | 360 | void DoVector(std::vector<T>& x, T& default_val) { |
| 367 | { | ||
| 368 | u32 vec_size = (u32)x.size(); | 361 | u32 vec_size = (u32)x.size(); |
| 369 | Do(vec_size); | 362 | Do(vec_size); |
| 370 | x.resize(vec_size, default_val); | 363 | x.resize(vec_size, default_val); |
| @@ -372,9 +365,8 @@ public: | |||
| 372 | DoArray(&x[0], vec_size); | 365 | DoArray(&x[0], vec_size); |
| 373 | } | 366 | } |
| 374 | 367 | ||
| 375 | template<class T> | 368 | template <class T> |
| 376 | void DoVectorPOD(std::vector<T> &x, T &default_val) | 369 | void DoVectorPOD(std::vector<T>& x, T& default_val) { |
| 377 | { | ||
| 378 | u32 vec_size = (u32)x.size(); | 370 | u32 vec_size = (u32)x.size(); |
| 379 | Do(vec_size); | 371 | Do(vec_size); |
| 380 | x.resize(vec_size, default_val); | 372 | x.resize(vec_size, default_val); |
| @@ -383,55 +375,48 @@ public: | |||
| 383 | } | 375 | } |
| 384 | 376 | ||
| 385 | // Store deques. | 377 | // Store deques. |
| 386 | template<class T> | 378 | template <class T> |
| 387 | void Do(std::deque<T *> &x) | 379 | void Do(std::deque<T*>& x) { |
| 388 | { | 380 | T* dv = nullptr; |
| 389 | T *dv = nullptr; | ||
| 390 | DoDeque(x, dv); | 381 | DoDeque(x, dv); |
| 391 | } | 382 | } |
| 392 | 383 | ||
| 393 | template<class T> | 384 | template <class T> |
| 394 | void Do(std::deque<T> &x) | 385 | void Do(std::deque<T>& x) { |
| 395 | { | ||
| 396 | T dv = T(); | 386 | T dv = T(); |
| 397 | DoDeque(x, dv); | 387 | DoDeque(x, dv); |
| 398 | } | 388 | } |
| 399 | 389 | ||
| 400 | template<class T> | 390 | template <class T> |
| 401 | void DoDeque(std::deque<T> &x, T &default_val) | 391 | void DoDeque(std::deque<T>& x, T& default_val) { |
| 402 | { | ||
| 403 | u32 deq_size = (u32)x.size(); | 392 | u32 deq_size = (u32)x.size(); |
| 404 | Do(deq_size); | 393 | Do(deq_size); |
| 405 | x.resize(deq_size, default_val); | 394 | x.resize(deq_size, default_val); |
| 406 | u32 i; | 395 | u32 i; |
| 407 | for(i = 0; i < deq_size; i++) | 396 | for (i = 0; i < deq_size; i++) |
| 408 | Do(x[i]); | 397 | Do(x[i]); |
| 409 | } | 398 | } |
| 410 | 399 | ||
| 411 | // Store STL lists. | 400 | // Store STL lists. |
| 412 | template<class T> | 401 | template <class T> |
| 413 | void Do(std::list<T *> &x) | 402 | void Do(std::list<T*>& x) { |
| 414 | { | 403 | T* dv = nullptr; |
| 415 | T *dv = nullptr; | ||
| 416 | Do(x, dv); | 404 | Do(x, dv); |
| 417 | } | 405 | } |
| 418 | 406 | ||
| 419 | template<class T> | 407 | template <class T> |
| 420 | void Do(std::list<T> &x) | 408 | void Do(std::list<T>& x) { |
| 421 | { | ||
| 422 | T dv = T(); | 409 | T dv = T(); |
| 423 | DoList(x, dv); | 410 | DoList(x, dv); |
| 424 | } | 411 | } |
| 425 | 412 | ||
| 426 | template<class T> | 413 | template <class T> |
| 427 | void Do(std::list<T> &x, T &default_val) | 414 | void Do(std::list<T>& x, T& default_val) { |
| 428 | { | ||
| 429 | DoList(x, default_val); | 415 | DoList(x, default_val); |
| 430 | } | 416 | } |
| 431 | 417 | ||
| 432 | template<class T> | 418 | template <class T> |
| 433 | void DoList(std::list<T> &x, T &default_val) | 419 | void DoList(std::list<T>& x, T& default_val) { |
| 434 | { | ||
| 435 | u32 list_size = (u32)x.size(); | 420 | u32 list_size = (u32)x.size(); |
| 436 | Do(list_size); | 421 | Do(list_size); |
| 437 | x.resize(list_size, default_val); | 422 | x.resize(list_size, default_val); |
| @@ -441,15 +426,11 @@ public: | |||
| 441 | Do(*itr); | 426 | Do(*itr); |
| 442 | } | 427 | } |
| 443 | 428 | ||
| 444 | |||
| 445 | // Store STL sets. | 429 | // Store STL sets. |
| 446 | template <class T> | 430 | template <class T> |
| 447 | void Do(std::set<T *> &x) | 431 | void Do(std::set<T*>& x) { |
| 448 | { | 432 | if (mode == MODE_READ) { |
| 449 | if (mode == MODE_READ) | 433 | for (auto it = x.begin(), end = x.end(); it != end; ++it) { |
| 450 | { | ||
| 451 | for (auto it = x.begin(), end = x.end(); it != end; ++it) | ||
| 452 | { | ||
| 453 | if (*it != nullptr) | 434 | if (*it != nullptr) |
| 454 | delete *it; | 435 | delete *it; |
| 455 | } | 436 | } |
| @@ -458,39 +439,31 @@ public: | |||
| 458 | } | 439 | } |
| 459 | 440 | ||
| 460 | template <class T> | 441 | template <class T> |
| 461 | void Do(std::set<T> &x) | 442 | void Do(std::set<T>& x) { |
| 462 | { | ||
| 463 | DoSet(x); | 443 | DoSet(x); |
| 464 | } | 444 | } |
| 465 | 445 | ||
| 466 | template <class T> | 446 | template <class T> |
| 467 | void DoSet(std::set<T> &x) | 447 | void DoSet(std::set<T>& x) { |
| 468 | { | ||
| 469 | unsigned int number = (unsigned int)x.size(); | 448 | unsigned int number = (unsigned int)x.size(); |
| 470 | Do(number); | 449 | Do(number); |
| 471 | 450 | ||
| 472 | switch (mode) | 451 | switch (mode) { |
| 473 | { | 452 | case MODE_READ: { |
| 474 | case MODE_READ: | 453 | x.clear(); |
| 475 | { | 454 | while (number-- > 0) { |
| 476 | x.clear(); | 455 | T it = T(); |
| 477 | while (number-- > 0) | 456 | Do(it); |
| 478 | { | 457 | x.insert(it); |
| 479 | T it = T(); | ||
| 480 | Do(it); | ||
| 481 | x.insert(it); | ||
| 482 | } | ||
| 483 | } | 458 | } |
| 484 | break; | 459 | } break; |
| 485 | case MODE_WRITE: | 460 | case MODE_WRITE: |
| 486 | case MODE_MEASURE: | 461 | case MODE_MEASURE: |
| 487 | case MODE_VERIFY: | 462 | case MODE_VERIFY: { |
| 488 | { | 463 | typename std::set<T>::iterator itr = x.begin(); |
| 489 | typename std::set<T>::iterator itr = x.begin(); | 464 | while (number-- > 0) |
| 490 | while (number-- > 0) | 465 | Do(*itr++); |
| 491 | Do(*itr++); | 466 | } break; |
| 492 | } | ||
| 493 | break; | ||
| 494 | 467 | ||
| 495 | default: | 468 | default: |
| 496 | LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode); | 469 | LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode); |
| @@ -498,51 +471,58 @@ public: | |||
| 498 | } | 471 | } |
| 499 | 472 | ||
| 500 | // Store strings. | 473 | // Store strings. |
| 501 | void Do(std::string &x) | 474 | void Do(std::string& x) { |
| 502 | { | ||
| 503 | int stringLen = (int)x.length() + 1; | 475 | int stringLen = (int)x.length() + 1; |
| 504 | Do(stringLen); | 476 | Do(stringLen); |
| 505 | 477 | ||
| 506 | switch (mode) { | 478 | switch (mode) { |
| 507 | case MODE_READ: x = (char*)*ptr; break; | 479 | case MODE_READ: |
| 508 | case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; | 480 | x = (char*)*ptr; |
| 509 | case MODE_MEASURE: break; | 481 | break; |
| 482 | case MODE_WRITE: | ||
| 483 | memcpy(*ptr, x.c_str(), stringLen); | ||
| 484 | break; | ||
| 485 | case MODE_MEASURE: | ||
| 486 | break; | ||
| 510 | case MODE_VERIFY: | 487 | case MODE_VERIFY: |
| 511 | DEBUG_ASSERT_MSG((x == (char*)*ptr), | 488 | DEBUG_ASSERT_MSG((x == (char*)*ptr), |
| 512 | "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", | 489 | "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", |
| 513 | x.c_str(), (char*)*ptr, ptr); | 490 | x.c_str(), (char*)*ptr, ptr); |
| 514 | break; | 491 | break; |
| 515 | } | 492 | } |
| 516 | (*ptr) += stringLen; | 493 | (*ptr) += stringLen; |
| 517 | } | 494 | } |
| 518 | 495 | ||
| 519 | void Do(std::wstring &x) | 496 | void Do(std::wstring& x) { |
| 520 | { | 497 | int stringLen = sizeof(wchar_t) * ((int)x.length() + 1); |
| 521 | int stringLen = sizeof(wchar_t)*((int)x.length() + 1); | ||
| 522 | Do(stringLen); | 498 | Do(stringLen); |
| 523 | 499 | ||
| 524 | switch (mode) { | 500 | switch (mode) { |
| 525 | case MODE_READ: x = (wchar_t*)*ptr; break; | 501 | case MODE_READ: |
| 526 | case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; | 502 | x = (wchar_t*)*ptr; |
| 527 | case MODE_MEASURE: break; | 503 | break; |
| 504 | case MODE_WRITE: | ||
| 505 | memcpy(*ptr, x.c_str(), stringLen); | ||
| 506 | break; | ||
| 507 | case MODE_MEASURE: | ||
| 508 | break; | ||
| 528 | case MODE_VERIFY: | 509 | case MODE_VERIFY: |
| 529 | DEBUG_ASSERT_MSG((x == (wchar_t*)*ptr), | 510 | DEBUG_ASSERT_MSG((x == (wchar_t*)*ptr), |
| 530 | "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", | 511 | "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", |
| 531 | x.c_str(), (wchar_t*)*ptr, ptr); | 512 | x.c_str(), (wchar_t*)*ptr, ptr); |
| 532 | break; | 513 | break; |
| 533 | } | 514 | } |
| 534 | (*ptr) += stringLen; | 515 | (*ptr) += stringLen; |
| 535 | } | 516 | } |
| 536 | 517 | ||
| 537 | template<class T> | 518 | template <class T> |
| 538 | void DoClass(T &x) { | 519 | void DoClass(T& x) { |
| 539 | x.DoState(*this); | 520 | x.DoState(*this); |
| 540 | } | 521 | } |
| 541 | 522 | ||
| 542 | template<class T> | 523 | template <class T> |
| 543 | void DoClass(T *&x) { | 524 | void DoClass(T*& x) { |
| 544 | if (mode == MODE_READ) | 525 | if (mode == MODE_READ) { |
| 545 | { | ||
| 546 | if (x != nullptr) | 526 | if (x != nullptr) |
| 547 | delete x; | 527 | delete x; |
| 548 | x = new T(); | 528 | x = new T(); |
| @@ -550,81 +530,70 @@ public: | |||
| 550 | x->DoState(*this); | 530 | x->DoState(*this); |
| 551 | } | 531 | } |
| 552 | 532 | ||
| 553 | template<class T> | 533 | template <class T> |
| 554 | void DoArray(T *x, int count) { | 534 | void DoArray(T* x, int count) { |
| 555 | DoHelper<T>::DoArray(this, x, count); | 535 | DoHelper<T>::DoArray(this, x, count); |
| 556 | } | 536 | } |
| 557 | 537 | ||
| 558 | template<class T> | 538 | template <class T> |
| 559 | void Do(T &x) { | 539 | void Do(T& x) { |
| 560 | DoHelper<T>::Do(this, x); | 540 | DoHelper<T>::Do(this, x); |
| 561 | } | 541 | } |
| 562 | 542 | ||
| 563 | template<class T> | 543 | template <class T> |
| 564 | void DoPOD(T &x) { | 544 | void DoPOD(T& x) { |
| 565 | DoHelper<T>::Do(this, x); | 545 | DoHelper<T>::Do(this, x); |
| 566 | } | 546 | } |
| 567 | 547 | ||
| 568 | template<class T> | 548 | template <class T> |
| 569 | void DoPointer(T* &x, T*const base) { | 549 | void DoPointer(T*& x, T* const base) { |
| 570 | // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range | 550 | // pointers can be more than 2^31 apart, but you're using this function wrong if you need |
| 551 | // that much range | ||
| 571 | s32 offset = x - base; | 552 | s32 offset = x - base; |
| 572 | Do(offset); | 553 | Do(offset); |
| 573 | if (mode == MODE_READ) | 554 | if (mode == MODE_READ) |
| 574 | x = base + offset; | 555 | x = base + offset; |
| 575 | } | 556 | } |
| 576 | 557 | ||
| 577 | template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)> | 558 | template <class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), |
| 578 | void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr) | 559 | void (*TDo)(PointerWrap&, T*)> |
| 579 | { | 560 | void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr) { |
| 580 | LinkedListItem<T>* list_cur = list_start; | 561 | LinkedListItem<T>* list_cur = list_start; |
| 581 | LinkedListItem<T>* prev = nullptr; | 562 | LinkedListItem<T>* prev = nullptr; |
| 582 | 563 | ||
| 583 | while (true) | 564 | while (true) { |
| 584 | { | ||
| 585 | u8 shouldExist = (list_cur ? 1 : 0); | 565 | u8 shouldExist = (list_cur ? 1 : 0); |
| 586 | Do(shouldExist); | 566 | Do(shouldExist); |
| 587 | if (shouldExist == 1) | 567 | if (shouldExist == 1) { |
| 588 | { | ||
| 589 | LinkedListItem<T>* cur = list_cur ? list_cur : TNew(); | 568 | LinkedListItem<T>* cur = list_cur ? list_cur : TNew(); |
| 590 | TDo(*this, (T*)cur); | 569 | TDo(*this, (T*)cur); |
| 591 | if (!list_cur) | 570 | if (!list_cur) { |
| 592 | { | 571 | if (mode == MODE_READ) { |
| 593 | if (mode == MODE_READ) | ||
| 594 | { | ||
| 595 | cur->next = nullptr; | 572 | cur->next = nullptr; |
| 596 | list_cur = cur; | 573 | list_cur = cur; |
| 597 | if (prev) | 574 | if (prev) |
| 598 | prev->next = cur; | 575 | prev->next = cur; |
| 599 | else | 576 | else |
| 600 | list_start = cur; | 577 | list_start = cur; |
| 601 | } | 578 | } else { |
| 602 | else | ||
| 603 | { | ||
| 604 | TFree(cur); | 579 | TFree(cur); |
| 605 | continue; | 580 | continue; |
| 606 | } | 581 | } |
| 607 | } | 582 | } |
| 608 | } | 583 | } else { |
| 609 | else | 584 | if (mode == MODE_READ) { |
| 610 | { | ||
| 611 | if (mode == MODE_READ) | ||
| 612 | { | ||
| 613 | if (prev) | 585 | if (prev) |
| 614 | prev->next = nullptr; | 586 | prev->next = nullptr; |
| 615 | if (list_end) | 587 | if (list_end) |
| 616 | *list_end = prev; | 588 | *list_end = prev; |
| 617 | if (list_cur) | 589 | if (list_cur) { |
| 618 | { | ||
| 619 | if (list_start == list_cur) | 590 | if (list_start == list_cur) |
| 620 | list_start = nullptr; | 591 | list_start = nullptr; |
| 621 | do | 592 | do { |
| 622 | { | ||
| 623 | LinkedListItem<T>* next = list_cur->next; | 593 | LinkedListItem<T>* next = list_cur->next; |
| 624 | TFree(list_cur); | 594 | TFree(list_cur); |
| 625 | list_cur = next; | 595 | list_cur = next; |
| 626 | } | 596 | } while (list_cur); |
| 627 | while (list_cur); | ||
| 628 | } | 597 | } |
| 629 | } | 598 | } |
| 630 | break; | 599 | break; |
| @@ -634,13 +603,13 @@ public: | |||
| 634 | } | 603 | } |
| 635 | } | 604 | } |
| 636 | 605 | ||
| 637 | void DoMarker(const char* prevName, u32 arbitraryNumber=0x42) | 606 | void DoMarker(const char* prevName, u32 arbitraryNumber = 0x42) { |
| 638 | { | ||
| 639 | u32 cookie = arbitraryNumber; | 607 | u32 cookie = arbitraryNumber; |
| 640 | Do(cookie); | 608 | Do(cookie); |
| 641 | if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) | 609 | if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) { |
| 642 | { | 610 | LOG_ERROR(Common, "After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). " |
| 643 | LOG_ERROR(Common, "After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); | 611 | "Aborting savestate load...", |
| 612 | prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); | ||
| 644 | SetError(ERROR_FAILURE); | 613 | SetError(ERROR_FAILURE); |
| 645 | } | 614 | } |
| 646 | } | 615 | } |
diff --git a/src/common/code_block.h b/src/common/code_block.h index 2fa4a0090..6a55a8e30 100644 --- a/src/common/code_block.h +++ b/src/common/code_block.h | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | |||
| 9 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 10 | #include "common/memory_util.h" | 9 | #include "common/memory_util.h" |
| 11 | 10 | ||
| @@ -14,24 +13,27 @@ | |||
| 14 | // having to prefix them with gen-> or something similar. | 13 | // having to prefix them with gen-> or something similar. |
| 15 | // Example implementation: | 14 | // Example implementation: |
| 16 | // class JIT : public CodeBlock<ARMXEmitter> {} | 15 | // class JIT : public CodeBlock<ARMXEmitter> {} |
| 17 | template<class T> class CodeBlock : public T, NonCopyable | 16 | template <class T> |
| 18 | { | 17 | class CodeBlock : public T, NonCopyable { |
| 19 | private: | 18 | private: |
| 20 | // A privately used function to set the executable RAM space to something invalid. | 19 | // A privately used function to set the executable RAM space to something invalid. |
| 21 | // For debugging usefulness it should be used to set the RAM to a host specific breakpoint instruction | 20 | // For debugging usefulness it should be used to set the RAM to a host specific breakpoint |
| 21 | // instruction | ||
| 22 | virtual void PoisonMemory() = 0; | 22 | virtual void PoisonMemory() = 0; |
| 23 | 23 | ||
| 24 | protected: | 24 | protected: |
| 25 | u8 *region; | 25 | u8* region; |
| 26 | size_t region_size; | 26 | size_t region_size; |
| 27 | 27 | ||
| 28 | public: | 28 | public: |
| 29 | CodeBlock() : region(nullptr), region_size(0) {} | 29 | CodeBlock() : region(nullptr), region_size(0) {} |
| 30 | virtual ~CodeBlock() { if (region) FreeCodeSpace(); } | 30 | virtual ~CodeBlock() { |
| 31 | if (region) | ||
| 32 | FreeCodeSpace(); | ||
| 33 | } | ||
| 31 | 34 | ||
| 32 | // Call this before you generate any code. | 35 | // Call this before you generate any code. |
| 33 | void AllocCodeSpace(int size) | 36 | void AllocCodeSpace(int size) { |
| 34 | { | ||
| 35 | region_size = size; | 37 | region_size = size; |
| 36 | region = (u8*)AllocateExecutableMemory(region_size); | 38 | region = (u8*)AllocateExecutableMemory(region_size); |
| 37 | T::SetCodePtr(region); | 39 | T::SetCodePtr(region); |
| @@ -39,15 +41,13 @@ public: | |||
| 39 | 41 | ||
| 40 | // Always clear code space with breakpoints, so that if someone accidentally executes | 42 | // Always clear code space with breakpoints, so that if someone accidentally executes |
| 41 | // uninitialized, it just breaks into the debugger. | 43 | // uninitialized, it just breaks into the debugger. |
| 42 | void ClearCodeSpace() | 44 | void ClearCodeSpace() { |
| 43 | { | ||
| 44 | PoisonMemory(); | 45 | PoisonMemory(); |
| 45 | ResetCodePtr(); | 46 | ResetCodePtr(); |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. | 49 | // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. |
| 49 | void FreeCodeSpace() | 50 | void FreeCodeSpace() { |
| 50 | { | ||
| 51 | #ifdef __SYMBIAN32__ | 51 | #ifdef __SYMBIAN32__ |
| 52 | ResetExecutableMemory(region); | 52 | ResetExecutableMemory(region); |
| 53 | #else | 53 | #else |
| @@ -57,33 +57,29 @@ public: | |||
| 57 | region_size = 0; | 57 | region_size = 0; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | bool IsInSpace(const u8 *ptr) | 60 | bool IsInSpace(const u8* ptr) { |
| 61 | { | ||
| 62 | return (ptr >= region) && (ptr < (region + region_size)); | 61 | return (ptr >= region) && (ptr < (region + region_size)); |
| 63 | } | 62 | } |
| 64 | 63 | ||
| 65 | // Cannot currently be undone. Will write protect the entire code region. | 64 | // Cannot currently be undone. Will write protect the entire code region. |
| 66 | // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). | 65 | // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). |
| 67 | void WriteProtect() | 66 | void WriteProtect() { |
| 68 | { | ||
| 69 | WriteProtectMemory(region, region_size, true); | 67 | WriteProtectMemory(region, region_size, true); |
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | void ResetCodePtr() | 70 | void ResetCodePtr() { |
| 73 | { | ||
| 74 | T::SetCodePtr(region); | 71 | T::SetCodePtr(region); |
| 75 | } | 72 | } |
| 76 | 73 | ||
| 77 | size_t GetSpaceLeft() const | 74 | size_t GetSpaceLeft() const { |
| 78 | { | ||
| 79 | return region_size - (T::GetCodePtr() - region); | 75 | return region_size - (T::GetCodePtr() - region); |
| 80 | } | 76 | } |
| 81 | 77 | ||
| 82 | u8 *GetBasePtr() { | 78 | u8* GetBasePtr() { |
| 83 | return region; | 79 | return region; |
| 84 | } | 80 | } |
| 85 | 81 | ||
| 86 | size_t GetOffset(const u8 *ptr) const { | 82 | size_t GetOffset(const u8* ptr) const { |
| 87 | return ptr - region; | 83 | return ptr - region; |
| 88 | } | 84 | } |
| 89 | }; | 85 | }; |
diff --git a/src/common/color.h b/src/common/color.h index 908879ea6..4ebd4f3d0 100644 --- a/src/common/color.h +++ b/src/common/color.h | |||
| @@ -56,7 +56,7 @@ constexpr u8 Convert8To6(u8 value) { | |||
| 56 | * @return Result color decoded as Math::Vec4<u8> | 56 | * @return Result color decoded as Math::Vec4<u8> |
| 57 | */ | 57 | */ |
| 58 | inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) { | 58 | inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) { |
| 59 | return { bytes[3], bytes[2], bytes[1], bytes[0] }; | 59 | return {bytes[3], bytes[2], bytes[1], bytes[0]}; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | /** | 62 | /** |
| @@ -65,7 +65,7 @@ inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) { | |||
| 65 | * @return Result color decoded as Math::Vec4<u8> | 65 | * @return Result color decoded as Math::Vec4<u8> |
| 66 | */ | 66 | */ |
| 67 | inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) { | 67 | inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) { |
| 68 | return { bytes[2], bytes[1], bytes[0], 255 }; | 68 | return {bytes[2], bytes[1], bytes[0], 255}; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | /** | 71 | /** |
| @@ -74,7 +74,7 @@ inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) { | |||
| 74 | * @return Result color decoded as Math::Vec4<u8> | 74 | * @return Result color decoded as Math::Vec4<u8> |
| 75 | */ | 75 | */ |
| 76 | inline const Math::Vec4<u8> DecodeRG8(const u8* bytes) { | 76 | inline const Math::Vec4<u8> DecodeRG8(const u8* bytes) { |
| 77 | return { bytes[1], bytes[0], 0, 255 }; | 77 | return {bytes[1], bytes[0], 0, 255}; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | /** | 80 | /** |
| @@ -84,8 +84,8 @@ inline const Math::Vec4<u8> DecodeRG8(const u8* bytes) { | |||
| 84 | */ | 84 | */ |
| 85 | inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) { | 85 | inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) { |
| 86 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); | 86 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); |
| 87 | return { Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), | 87 | return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), |
| 88 | Convert5To8(pixel & 0x1F), 255 }; | 88 | Convert5To8(pixel & 0x1F), 255}; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | /** | 91 | /** |
| @@ -95,8 +95,8 @@ inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) { | |||
| 95 | */ | 95 | */ |
| 96 | inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { | 96 | inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { |
| 97 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); | 97 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); |
| 98 | return { Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), | 98 | return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), |
| 99 | Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1) }; | 99 | Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1)}; |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | /** | 102 | /** |
| @@ -106,8 +106,8 @@ inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { | |||
| 106 | */ | 106 | */ |
| 107 | inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) { | 107 | inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) { |
| 108 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); | 108 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); |
| 109 | return { Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), | 109 | return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), |
| 110 | Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF) }; | 110 | Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)}; |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | /** | 113 | /** |
| @@ -134,7 +134,7 @@ inline u32 DecodeD24(const u8* bytes) { | |||
| 134 | * @return Resulting values stored as a Math::Vec2 | 134 | * @return Resulting values stored as a Math::Vec2 |
| 135 | */ | 135 | */ |
| 136 | inline const Math::Vec2<u32> DecodeD24S8(const u8* bytes) { | 136 | inline const Math::Vec2<u32> DecodeD24S8(const u8* bytes) { |
| 137 | return { static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3] }; | 137 | return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]}; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | /** | 140 | /** |
| @@ -175,8 +175,8 @@ inline void EncodeRG8(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 175 | * @param bytes Destination pointer to store encoded color | 175 | * @param bytes Destination pointer to store encoded color |
| 176 | */ | 176 | */ |
| 177 | inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { | 177 | inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { |
| 178 | *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) | | 178 | *reinterpret_cast<u16_le*>(bytes) = |
| 179 | (Convert8To6(color.g()) << 5) | Convert8To5(color.b()); | 179 | (Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b()); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | /** | 182 | /** |
| @@ -186,7 +186,8 @@ inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 186 | */ | 186 | */ |
| 187 | inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { | 187 | inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { |
| 188 | *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) | | 188 | *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) | |
| 189 | (Convert8To5(color.g()) << 6) | (Convert8To5(color.b()) << 1) | Convert8To1(color.a()); | 189 | (Convert8To5(color.g()) << 6) | |
| 190 | (Convert8To5(color.b()) << 1) | Convert8To1(color.a()); | ||
| 190 | } | 191 | } |
| 191 | 192 | ||
| 192 | /** | 193 | /** |
| @@ -196,7 +197,8 @@ inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 196 | */ | 197 | */ |
| 197 | inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) { | 198 | inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) { |
| 198 | *reinterpret_cast<u16_le*>(bytes) = (Convert8To4(color.r()) << 12) | | 199 | *reinterpret_cast<u16_le*>(bytes) = (Convert8To4(color.r()) << 12) | |
| 199 | (Convert8To4(color.g()) << 8) | (Convert8To4(color.b()) << 4) | Convert8To4(color.a()); | 200 | (Convert8To4(color.g()) << 8) | |
| 201 | (Convert8To4(color.b()) << 4) | Convert8To4(color.a()); | ||
| 200 | } | 202 | } |
| 201 | 203 | ||
| 202 | /** | 204 | /** |
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 4633897ce..b141e79ed 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h | |||
| @@ -7,14 +7,13 @@ | |||
| 7 | #if !defined(ARCHITECTURE_x86_64) && !defined(_M_ARM) | 7 | #if !defined(ARCHITECTURE_x86_64) && !defined(_M_ARM) |
| 8 | #include <cstdlib> // for exit | 8 | #include <cstdlib> // for exit |
| 9 | #endif | 9 | #endif |
| 10 | |||
| 11 | #include "common_types.h" | 10 | #include "common_types.h" |
| 12 | 11 | ||
| 13 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) | 12 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) |
| 14 | 13 | ||
| 15 | /// Textually concatenates two tokens. The double-expansion is required by the C preprocessor. | 14 | /// Textually concatenates two tokens. The double-expansion is required by the C preprocessor. |
| 16 | #define CONCAT2(x, y) DO_CONCAT2(x, y) | 15 | #define CONCAT2(x, y) DO_CONCAT2(x, y) |
| 17 | #define DO_CONCAT2(x, y) x ## y | 16 | #define DO_CONCAT2(x, y) x##y |
| 18 | 17 | ||
| 19 | // helper macro to properly align structure members. | 18 | // helper macro to properly align structure members. |
| 20 | // Calling INSERT_PADDING_BYTES will add a new member variable with a name like "pad121", | 19 | // Calling INSERT_PADDING_BYTES will add a new member variable with a name like "pad121", |
| @@ -24,9 +23,9 @@ | |||
| 24 | 23 | ||
| 25 | // Inlining | 24 | // Inlining |
| 26 | #ifdef _WIN32 | 25 | #ifdef _WIN32 |
| 27 | #define FORCE_INLINE __forceinline | 26 | #define FORCE_INLINE __forceinline |
| 28 | #else | 27 | #else |
| 29 | #define FORCE_INLINE inline __attribute__((always_inline)) | 28 | #define FORCE_INLINE inline __attribute__((always_inline)) |
| 30 | #endif | 29 | #endif |
| 31 | 30 | ||
| 32 | #ifndef _MSC_VER | 31 | #ifndef _MSC_VER |
| @@ -46,7 +45,8 @@ | |||
| 46 | #else | 45 | #else |
| 47 | inline u32 rotl(u32 x, int shift) { | 46 | inline u32 rotl(u32 x, int shift) { |
| 48 | shift &= 31; | 47 | shift &= 31; |
| 49 | if (!shift) return x; | 48 | if (!shift) |
| 49 | return x; | ||
| 50 | return (x << shift) | (x >> (32 - shift)); | 50 | return (x << shift) | (x >> (32 - shift)); |
| 51 | } | 51 | } |
| 52 | #endif | 52 | #endif |
| @@ -56,17 +56,18 @@ inline u32 rotl(u32 x, int shift) { | |||
| 56 | #else | 56 | #else |
| 57 | inline u32 rotr(u32 x, int shift) { | 57 | inline u32 rotr(u32 x, int shift) { |
| 58 | shift &= 31; | 58 | shift &= 31; |
| 59 | if (!shift) return x; | 59 | if (!shift) |
| 60 | return x; | ||
| 60 | return (x >> shift) | (x << (32 - shift)); | 61 | return (x >> shift) | (x << (32 - shift)); |
| 61 | } | 62 | } |
| 62 | #endif | 63 | #endif |
| 63 | 64 | ||
| 64 | inline u64 _rotl64(u64 x, unsigned int shift){ | 65 | inline u64 _rotl64(u64 x, unsigned int shift) { |
| 65 | unsigned int n = shift % 64; | 66 | unsigned int n = shift % 64; |
| 66 | return (x << n) | (x >> (64 - n)); | 67 | return (x << n) | (x >> (64 - n)); |
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | inline u64 _rotr64(u64 x, unsigned int shift){ | 70 | inline u64 _rotr64(u64 x, unsigned int shift) { |
| 70 | unsigned int n = shift % 64; | 71 | unsigned int n = shift % 64; |
| 71 | return (x >> n) | (x << (64 - n)); | 72 | return (x >> n) | (x << (64 - n)); |
| 72 | } | 73 | } |
| @@ -74,17 +75,17 @@ inline u64 _rotr64(u64 x, unsigned int shift){ | |||
| 74 | #else // _MSC_VER | 75 | #else // _MSC_VER |
| 75 | 76 | ||
| 76 | #if (_MSC_VER < 1900) | 77 | #if (_MSC_VER < 1900) |
| 77 | // Function Cross-Compatibility | 78 | // Function Cross-Compatibility |
| 78 | #define snprintf _snprintf | 79 | #define snprintf _snprintf |
| 79 | #endif | 80 | #endif |
| 80 | 81 | ||
| 81 | // Locale Cross-Compatibility | 82 | // Locale Cross-Compatibility |
| 82 | #define locale_t _locale_t | 83 | #define locale_t _locale_t |
| 83 | 84 | ||
| 84 | extern "C" { | 85 | extern "C" { |
| 85 | __declspec(dllimport) void __stdcall DebugBreak(void); | 86 | __declspec(dllimport) void __stdcall DebugBreak(void); |
| 86 | } | 87 | } |
| 87 | #define Crash() {DebugBreak();} | 88 | #define Crash() DebugBreak() |
| 88 | 89 | ||
| 89 | // cstdlib provides these on MSVC | 90 | // cstdlib provides these on MSVC |
| 90 | #define rotr _rotr | 91 | #define rotr _rotr |
diff --git a/src/common/common_paths.h b/src/common/common_paths.h index 2903f2cf2..a5342a610 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h | |||
| @@ -16,13 +16,13 @@ | |||
| 16 | #define ROOT_DIR "." | 16 | #define ROOT_DIR "." |
| 17 | #define USERDATA_DIR "user" | 17 | #define USERDATA_DIR "user" |
| 18 | #ifdef USER_DIR | 18 | #ifdef USER_DIR |
| 19 | #define EMU_DATA_DIR USER_DIR | 19 | #define EMU_DATA_DIR USER_DIR |
| 20 | #else | 20 | #else |
| 21 | #ifdef _WIN32 | 21 | #ifdef _WIN32 |
| 22 | #define EMU_DATA_DIR "Citra Emulator" | 22 | #define EMU_DATA_DIR "Citra Emulator" |
| 23 | #else | 23 | #else |
| 24 | #define EMU_DATA_DIR "citra-emu" | 24 | #define EMU_DATA_DIR "citra-emu" |
| 25 | #endif | 25 | #endif |
| 26 | #endif | 26 | #endif |
| 27 | 27 | ||
| 28 | // Dirs in both User and Sys | 28 | // Dirs in both User and Sys |
| @@ -31,32 +31,32 @@ | |||
| 31 | #define JAP_DIR "JAP" | 31 | #define JAP_DIR "JAP" |
| 32 | 32 | ||
| 33 | // Subdirs in the User dir returned by GetUserPath(D_USER_IDX) | 33 | // Subdirs in the User dir returned by GetUserPath(D_USER_IDX) |
| 34 | #define CONFIG_DIR "config" | 34 | #define CONFIG_DIR "config" |
| 35 | #define GAMECONFIG_DIR "game_config" | 35 | #define GAMECONFIG_DIR "game_config" |
| 36 | #define MAPS_DIR "maps" | 36 | #define MAPS_DIR "maps" |
| 37 | #define CACHE_DIR "cache" | 37 | #define CACHE_DIR "cache" |
| 38 | #define SDMC_DIR "sdmc" | 38 | #define SDMC_DIR "sdmc" |
| 39 | #define NAND_DIR "nand" | 39 | #define NAND_DIR "nand" |
| 40 | #define SYSDATA_DIR "sysdata" | 40 | #define SYSDATA_DIR "sysdata" |
| 41 | #define SHADERCACHE_DIR "shader_cache" | 41 | #define SHADERCACHE_DIR "shader_cache" |
| 42 | #define STATESAVES_DIR "state_saves" | 42 | #define STATESAVES_DIR "state_saves" |
| 43 | #define SCREENSHOTS_DIR "screenShots" | 43 | #define SCREENSHOTS_DIR "screenShots" |
| 44 | #define DUMP_DIR "dump" | 44 | #define DUMP_DIR "dump" |
| 45 | #define DUMP_TEXTURES_DIR "textures" | 45 | #define DUMP_TEXTURES_DIR "textures" |
| 46 | #define DUMP_FRAMES_DIR "frames" | 46 | #define DUMP_FRAMES_DIR "frames" |
| 47 | #define DUMP_AUDIO_DIR "audio" | 47 | #define DUMP_AUDIO_DIR "audio" |
| 48 | #define LOGS_DIR "logs" | 48 | #define LOGS_DIR "logs" |
| 49 | #define SHADERS_DIR "shaders" | 49 | #define SHADERS_DIR "shaders" |
| 50 | #define SYSCONF_DIR "sysconf" | 50 | #define SYSCONF_DIR "sysconf" |
| 51 | 51 | ||
| 52 | // Filenames | 52 | // Filenames |
| 53 | // Files in the directory returned by GetUserPath(D_CONFIG_IDX) | 53 | // Files in the directory returned by GetUserPath(D_CONFIG_IDX) |
| 54 | #define EMU_CONFIG "emu.ini" | 54 | #define EMU_CONFIG "emu.ini" |
| 55 | #define DEBUGGER_CONFIG "debugger.ini" | 55 | #define DEBUGGER_CONFIG "debugger.ini" |
| 56 | #define LOGGER_CONFIG "logger.ini" | 56 | #define LOGGER_CONFIG "logger.ini" |
| 57 | 57 | ||
| 58 | // Sys files | 58 | // Sys files |
| 59 | #define SHARED_FONT "shared_font.bin" | 59 | #define SHARED_FONT "shared_font.bin" |
| 60 | 60 | ||
| 61 | // Files in the directory returned by GetUserPath(D_LOGS_IDX) | 61 | // Files in the directory returned by GetUserPath(D_LOGS_IDX) |
| 62 | #define MAIN_LOG "emu.log" | 62 | #define MAIN_LOG "emu.log" |
diff --git a/src/common/common_types.h b/src/common/common_types.h index 9f51dff18..ee18eac81 100644 --- a/src/common/common_types.h +++ b/src/common/common_types.h | |||
| @@ -32,18 +32,18 @@ | |||
| 32 | #endif | 32 | #endif |
| 33 | #endif | 33 | #endif |
| 34 | 34 | ||
| 35 | typedef std::uint8_t u8; ///< 8-bit unsigned byte | 35 | typedef std::uint8_t u8; ///< 8-bit unsigned byte |
| 36 | typedef std::uint16_t u16; ///< 16-bit unsigned short | 36 | typedef std::uint16_t u16; ///< 16-bit unsigned short |
| 37 | typedef std::uint32_t u32; ///< 32-bit unsigned word | 37 | typedef std::uint32_t u32; ///< 32-bit unsigned word |
| 38 | typedef std::uint64_t u64; ///< 64-bit unsigned int | 38 | typedef std::uint64_t u64; ///< 64-bit unsigned int |
| 39 | 39 | ||
| 40 | typedef std::int8_t s8; ///< 8-bit signed byte | 40 | typedef std::int8_t s8; ///< 8-bit signed byte |
| 41 | typedef std::int16_t s16; ///< 16-bit signed short | 41 | typedef std::int16_t s16; ///< 16-bit signed short |
| 42 | typedef std::int32_t s32; ///< 32-bit signed word | 42 | typedef std::int32_t s32; ///< 32-bit signed word |
| 43 | typedef std::int64_t s64; ///< 64-bit signed int | 43 | typedef std::int64_t s64; ///< 64-bit signed int |
| 44 | 44 | ||
| 45 | typedef float f32; ///< 32-bit floating point | 45 | typedef float f32; ///< 32-bit floating point |
| 46 | typedef double f64; ///< 64-bit floating point | 46 | typedef double f64; ///< 64-bit floating point |
| 47 | 47 | ||
| 48 | // TODO: It would be nice to eventually replace these with strong types that prevent accidental | 48 | // TODO: It would be nice to eventually replace these with strong types that prevent accidental |
| 49 | // conversion between each other. | 49 | // conversion between each other. |
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp index fd728c109..122f1c212 100644 --- a/src/common/emu_window.cpp +++ b/src/common/emu_window.cpp | |||
| @@ -4,10 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <cmath> | 6 | #include <cmath> |
| 7 | |||
| 8 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 9 | #include "common/key_map.h" | 8 | #include "common/key_map.h" |
| 10 | |||
| 11 | #include "emu_window.h" | 9 | #include "emu_window.h" |
| 12 | #include "video_core/video_core.h" | 10 | #include "video_core/video_core.h" |
| 13 | 11 | ||
| @@ -44,18 +42,17 @@ void EmuWindow::CirclePadUpdated(float x, float y) { | |||
| 44 | */ | 42 | */ |
| 45 | static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsigned framebuffer_x, | 43 | static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsigned framebuffer_x, |
| 46 | unsigned framebuffer_y) { | 44 | unsigned framebuffer_y) { |
| 47 | return (framebuffer_y >= layout.bottom_screen.top && | 45 | return ( |
| 48 | framebuffer_y < layout.bottom_screen.bottom && | 46 | framebuffer_y >= layout.bottom_screen.top && framebuffer_y < layout.bottom_screen.bottom && |
| 49 | framebuffer_x >= layout.bottom_screen.left && | 47 | framebuffer_x >= layout.bottom_screen.left && framebuffer_x < layout.bottom_screen.right); |
| 50 | framebuffer_x < layout.bottom_screen.right); | ||
| 51 | } | 48 | } |
| 52 | 49 | ||
| 53 | std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { | 50 | std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { |
| 54 | new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); | 51 | new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); |
| 55 | new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1); | 52 | new_x = std::min(new_x, framebuffer_layout.bottom_screen.right - 1); |
| 56 | 53 | ||
| 57 | new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); | 54 | new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); |
| 58 | new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1); | 55 | new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom - 1); |
| 59 | 56 | ||
| 60 | return std::make_tuple(new_x, new_y); | 57 | return std::make_tuple(new_x, new_y); |
| 61 | } | 58 | } |
| @@ -64,10 +61,12 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { | |||
| 64 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) | 61 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) |
| 65 | return; | 62 | return; |
| 66 | 63 | ||
| 67 | touch_x = VideoCore::kScreenBottomWidth * (framebuffer_x - framebuffer_layout.bottom_screen.left) / | 64 | touch_x = VideoCore::kScreenBottomWidth * |
| 68 | (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); | 65 | (framebuffer_x - framebuffer_layout.bottom_screen.left) / |
| 69 | touch_y = VideoCore::kScreenBottomHeight * (framebuffer_y - framebuffer_layout.bottom_screen.top) / | 66 | (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); |
| 70 | (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); | 67 | touch_y = VideoCore::kScreenBottomHeight * |
| 68 | (framebuffer_y - framebuffer_layout.bottom_screen.top) / | ||
| 69 | (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); | ||
| 71 | 70 | ||
| 72 | touch_pressed = true; | 71 | touch_pressed = true; |
| 73 | pad_state.touch.Assign(1); | 72 | pad_state.touch.Assign(1); |
| @@ -90,16 +89,19 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { | |||
| 90 | TouchPressed(framebuffer_x, framebuffer_y); | 89 | TouchPressed(framebuffer_x, framebuffer_y); |
| 91 | } | 90 | } |
| 92 | 91 | ||
| 93 | EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) { | 92 | EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, |
| 93 | unsigned height) { | ||
| 94 | // When hiding the widget, the function receives a size of 0 | 94 | // When hiding the widget, the function receives a size of 0 |
| 95 | if (width == 0) width = 1; | 95 | if (width == 0) |
| 96 | if (height == 0) height = 1; | 96 | width = 1; |
| 97 | if (height == 0) | ||
| 98 | height = 1; | ||
| 97 | 99 | ||
| 98 | EmuWindow::FramebufferLayout res = { width, height, {}, {} }; | 100 | EmuWindow::FramebufferLayout res = {width, height, {}, {}}; |
| 99 | 101 | ||
| 100 | float window_aspect_ratio = static_cast<float>(height) / width; | 102 | float window_aspect_ratio = static_cast<float>(height) / width; |
| 101 | float emulation_aspect_ratio = static_cast<float>(VideoCore::kScreenTopHeight * 2) / | 103 | float emulation_aspect_ratio = |
| 102 | VideoCore::kScreenTopWidth; | 104 | static_cast<float>(VideoCore::kScreenTopHeight * 2) / VideoCore::kScreenTopWidth; |
| 103 | 105 | ||
| 104 | if (window_aspect_ratio > emulation_aspect_ratio) { | 106 | if (window_aspect_ratio > emulation_aspect_ratio) { |
| 105 | // Window is narrower than the emulation content => apply borders to the top and bottom | 107 | // Window is narrower than the emulation content => apply borders to the top and bottom |
| @@ -110,8 +112,9 @@ EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(u | |||
| 110 | res.top_screen.top = (height - viewport_height) / 2; | 112 | res.top_screen.top = (height - viewport_height) / 2; |
| 111 | res.top_screen.bottom = res.top_screen.top + viewport_height / 2; | 113 | res.top_screen.bottom = res.top_screen.top + viewport_height / 2; |
| 112 | 114 | ||
| 113 | int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) / | 115 | int bottom_width = static_cast<int>( |
| 114 | VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left)); | 116 | (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth) * |
| 117 | (res.top_screen.right - res.top_screen.left)); | ||
| 115 | int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; | 118 | int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; |
| 116 | 119 | ||
| 117 | res.bottom_screen.left = bottom_border; | 120 | res.bottom_screen.left = bottom_border; |
| @@ -127,8 +130,9 @@ EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(u | |||
| 127 | res.top_screen.top = 0; | 130 | res.top_screen.top = 0; |
| 128 | res.top_screen.bottom = res.top_screen.top + height / 2; | 131 | res.top_screen.bottom = res.top_screen.top + height / 2; |
| 129 | 132 | ||
| 130 | int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) / | 133 | int bottom_width = static_cast<int>( |
| 131 | VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left)); | 134 | (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth) * |
| 135 | (res.top_screen.right - res.top_screen.left)); | ||
| 132 | int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; | 136 | int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; |
| 133 | 137 | ||
| 134 | res.bottom_screen.left = res.top_screen.left + bottom_border; | 138 | res.bottom_screen.left = res.top_screen.left + bottom_border; |
diff --git a/src/common/emu_window.h b/src/common/emu_window.h index 57e303b6d..67df63e06 100644 --- a/src/common/emu_window.h +++ b/src/common/emu_window.h | |||
| @@ -6,10 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | #include <tuple> | 7 | #include <tuple> |
| 8 | #include <utility> | 8 | #include <utility> |
| 9 | |||
| 10 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 11 | #include "common/math_util.h" | 10 | #include "common/math_util.h" |
| 12 | |||
| 13 | #include "core/hle/service/hid/hid.h" | 11 | #include "core/hle/service/hid/hid.h" |
| 14 | 12 | ||
| 15 | /** | 13 | /** |
| @@ -30,15 +28,14 @@ | |||
| 30 | * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please | 28 | * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please |
| 31 | * re-read the upper points again and think about it if you don't see this. | 29 | * re-read the upper points again and think about it if you don't see this. |
| 32 | */ | 30 | */ |
| 33 | class EmuWindow | 31 | class EmuWindow { |
| 34 | { | ||
| 35 | public: | 32 | public: |
| 36 | /// Data structure to store emuwindow configuration | 33 | /// Data structure to store emuwindow configuration |
| 37 | struct WindowConfig { | 34 | struct WindowConfig { |
| 38 | bool fullscreen; | 35 | bool fullscreen; |
| 39 | int res_width; | 36 | int res_width; |
| 40 | int res_height; | 37 | int res_height; |
| 41 | std::pair<unsigned,unsigned> min_client_area_size; | 38 | std::pair<unsigned, unsigned> min_client_area_size; |
| 42 | }; | 39 | }; |
| 43 | 40 | ||
| 44 | /// Describes the layout of the window framebuffer (size and top/bottom screen positions) | 41 | /// Describes the layout of the window framebuffer (size and top/bottom screen positions) |
| @@ -193,15 +190,18 @@ public: | |||
| 193 | 190 | ||
| 194 | /** | 191 | /** |
| 195 | * Returns currently active configuration. | 192 | * Returns currently active configuration. |
| 196 | * @note Accesses to the returned object need not be consistent because it may be modified in another thread | 193 | * @note Accesses to the returned object need not be consistent because it may be modified in |
| 194 | * another thread | ||
| 197 | */ | 195 | */ |
| 198 | const WindowConfig& GetActiveConfig() const { | 196 | const WindowConfig& GetActiveConfig() const { |
| 199 | return active_config; | 197 | return active_config; |
| 200 | } | 198 | } |
| 201 | 199 | ||
| 202 | /** | 200 | /** |
| 203 | * Requests the internal configuration to be replaced by the specified argument at some point in the future. | 201 | * Requests the internal configuration to be replaced by the specified argument at some point in |
| 204 | * @note This method is thread-safe, because it delays configuration changes to the GUI event loop. Hence there is no guarantee on when the requested configuration will be active. | 202 | * the future. |
| 203 | * @note This method is thread-safe, because it delays configuration changes to the GUI event | ||
| 204 | * loop. Hence there is no guarantee on when the requested configuration will be active. | ||
| 205 | */ | 205 | */ |
| 206 | void SetConfig(const WindowConfig& val) { | 206 | void SetConfig(const WindowConfig& val) { |
| 207 | config = val; | 207 | config = val; |
| @@ -258,7 +258,7 @@ protected: | |||
| 258 | * Update internal client area size with the given parameter. | 258 | * Update internal client area size with the given parameter. |
| 259 | * @note EmuWindow implementations will usually use this in window resize event handlers. | 259 | * @note EmuWindow implementations will usually use this in window resize event handlers. |
| 260 | */ | 260 | */ |
| 261 | void NotifyClientAreaSizeChanged(const std::pair<unsigned,unsigned>& size) { | 261 | void NotifyClientAreaSizeChanged(const std::pair<unsigned, unsigned>& size) { |
| 262 | client_area_width = size.first; | 262 | client_area_width = size.first; |
| 263 | client_area_height = size.second; | 263 | client_area_height = size.second; |
| 264 | } | 264 | } |
| @@ -266,32 +266,35 @@ protected: | |||
| 266 | private: | 266 | private: |
| 267 | /** | 267 | /** |
| 268 | * Handler called when the minimal client area was requested to be changed via SetConfig. | 268 | * Handler called when the minimal client area was requested to be changed via SetConfig. |
| 269 | * For the request to be honored, EmuWindow implementations will usually reimplement this function. | 269 | * For the request to be honored, EmuWindow implementations will usually reimplement this |
| 270 | * function. | ||
| 270 | */ | 271 | */ |
| 271 | virtual void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { | 272 | virtual void OnMinimalClientAreaChangeRequest( |
| 273 | const std::pair<unsigned, unsigned>& minimal_size) { | ||
| 272 | // By default, ignore this request and do nothing. | 274 | // By default, ignore this request and do nothing. |
| 273 | } | 275 | } |
| 274 | 276 | ||
| 275 | FramebufferLayout framebuffer_layout; ///< Current framebuffer layout | 277 | FramebufferLayout framebuffer_layout; ///< Current framebuffer layout |
| 276 | 278 | ||
| 277 | unsigned client_area_width; ///< Current client width, should be set by window impl. | 279 | unsigned client_area_width; ///< Current client width, should be set by window impl. |
| 278 | unsigned client_area_height; ///< Current client height, should be set by window impl. | 280 | unsigned client_area_height; ///< Current client height, should be set by window impl. |
| 279 | 281 | ||
| 280 | WindowConfig config; ///< Internal configuration (changes pending for being applied in ProcessConfigurationChanges) | 282 | WindowConfig config; ///< Internal configuration (changes pending for being applied in |
| 281 | WindowConfig active_config; ///< Internal active configuration | 283 | /// ProcessConfigurationChanges) |
| 284 | WindowConfig active_config; ///< Internal active configuration | ||
| 282 | 285 | ||
| 283 | bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false | 286 | bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false |
| 284 | 287 | ||
| 285 | u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) | 288 | u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) |
| 286 | u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) | 289 | u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) |
| 287 | 290 | ||
| 288 | s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156) | 291 | s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156) |
| 289 | s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156) | 292 | s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156) |
| 290 | 293 | ||
| 291 | /** | 294 | /** |
| 292 | * Clip the provided coordinates to be inside the touchscreen area. | 295 | * Clip the provided coordinates to be inside the touchscreen area. |
| 293 | */ | 296 | */ |
| 294 | std::tuple<unsigned,unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); | 297 | std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); |
| 295 | 298 | ||
| 296 | Service::HID::PadState pad_state; | 299 | Service::HID::PadState pad_state; |
| 297 | }; | 300 | }; |
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index bc83ab737..14cbcac6b 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -9,66 +9,63 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | 10 | ||
| 11 | #ifdef _WIN32 | 11 | #ifdef _WIN32 |
| 12 | #include <windows.h> | 12 | #include <windows.h> |
| 13 | #include <shlobj.h> // for SHGetFolderPath | 13 | // windows.h needs to be included before other windows headers |
| 14 | #include <shellapi.h> | 14 | #include <commdlg.h> // for GetSaveFileName |
| 15 | #include <commdlg.h> // for GetSaveFileName | 15 | #include <direct.h> // getcwd |
| 16 | #include <io.h> | 16 | #include <io.h> |
| 17 | #include <direct.h> // getcwd | 17 | #include <shellapi.h> |
| 18 | #include <tchar.h> | 18 | #include <shlobj.h> // for SHGetFolderPath |
| 19 | 19 | #include <tchar.h> | |
| 20 | #include "common/string_util.h" | 20 | #include "common/string_util.h" |
| 21 | 21 | ||
| 22 | // 64 bit offsets for windows | 22 | // 64 bit offsets for windows |
| 23 | #define fseeko _fseeki64 | 23 | #define fseeko _fseeki64 |
| 24 | #define ftello _ftelli64 | 24 | #define ftello _ftelli64 |
| 25 | #define atoll _atoi64 | 25 | #define atoll _atoi64 |
| 26 | #define stat64 _stat64 | 26 | #define stat64 _stat64 |
| 27 | #define fstat64 _fstat64 | 27 | #define fstat64 _fstat64 |
| 28 | #define fileno _fileno | 28 | #define fileno _fileno |
| 29 | #else | 29 | #else |
| 30 | #ifdef __APPLE__ | 30 | #ifdef __APPLE__ |
| 31 | #include <sys/param.h> | 31 | #include <sys/param.h> |
| 32 | #endif | 32 | #endif |
| 33 | #include <cctype> | 33 | #include <cctype> |
| 34 | #include <cerrno> | 34 | #include <cerrno> |
| 35 | #include <cstdlib> | 35 | #include <cstdlib> |
| 36 | #include <cstring> | 36 | #include <cstring> |
| 37 | #include <dirent.h> | 37 | #include <dirent.h> |
| 38 | #include <pwd.h> | 38 | #include <pwd.h> |
| 39 | #include <unistd.h> | 39 | #include <unistd.h> |
| 40 | #endif | 40 | #endif |
| 41 | 41 | ||
| 42 | #if defined(__APPLE__) | 42 | #if defined(__APPLE__) |
| 43 | #include <CoreFoundation/CFString.h> | 43 | #include <CoreFoundation/CFBundle.h> |
| 44 | #include <CoreFoundation/CFURL.h> | 44 | #include <CoreFoundation/CFString.h> |
| 45 | #include <CoreFoundation/CFBundle.h> | 45 | #include <CoreFoundation/CFURL.h> |
| 46 | #endif | 46 | #endif |
| 47 | 47 | ||
| 48 | #include <algorithm> | 48 | #include <algorithm> |
| 49 | #include <sys/stat.h> | 49 | #include <sys/stat.h> |
| 50 | 50 | ||
| 51 | #ifndef S_ISDIR | 51 | #ifndef S_ISDIR |
| 52 | #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) | 52 | #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) |
| 53 | #endif | 53 | #endif |
| 54 | 54 | ||
| 55 | #ifdef BSD4_4 | 55 | #ifdef BSD4_4 |
| 56 | #define stat64 stat | 56 | #define stat64 stat |
| 57 | #define fstat64 fstat | 57 | #define fstat64 fstat |
| 58 | #endif | 58 | #endif |
| 59 | 59 | ||
| 60 | // This namespace has various generic functions related to files and paths. | 60 | // This namespace has various generic functions related to files and paths. |
| 61 | // The code still needs a ton of cleanup. | 61 | // The code still needs a ton of cleanup. |
| 62 | // REMEMBER: strdup considered harmful! | 62 | // REMEMBER: strdup considered harmful! |
| 63 | namespace FileUtil | 63 | namespace FileUtil { |
| 64 | { | ||
| 65 | 64 | ||
| 66 | // Remove any ending forward slashes from directory paths | 65 | // Remove any ending forward slashes from directory paths |
| 67 | // Modifies argument. | 66 | // Modifies argument. |
| 68 | static void StripTailDirSlashes(std::string &fname) | 67 | static void StripTailDirSlashes(std::string& fname) { |
| 69 | { | 68 | if (fname.length() > 1) { |
| 70 | if (fname.length() > 1) | ||
| 71 | { | ||
| 72 | size_t i = fname.length(); | 69 | size_t i = fname.length(); |
| 73 | while (i > 0 && fname[i - 1] == DIR_SEP_CHR) | 70 | while (i > 0 && fname[i - 1] == DIR_SEP_CHR) |
| 74 | --i; | 71 | --i; |
| @@ -78,8 +75,7 @@ static void StripTailDirSlashes(std::string &fname) | |||
| 78 | } | 75 | } |
| 79 | 76 | ||
| 80 | // Returns true if file filename exists | 77 | // Returns true if file filename exists |
| 81 | bool Exists(const std::string &filename) | 78 | bool Exists(const std::string& filename) { |
| 82 | { | ||
| 83 | struct stat64 file_info; | 79 | struct stat64 file_info; |
| 84 | 80 | ||
| 85 | std::string copy(filename); | 81 | std::string copy(filename); |
| @@ -99,8 +95,7 @@ bool Exists(const std::string &filename) | |||
| 99 | } | 95 | } |
| 100 | 96 | ||
| 101 | // Returns true if filename is a directory | 97 | // Returns true if filename is a directory |
| 102 | bool IsDirectory(const std::string &filename) | 98 | bool IsDirectory(const std::string& filename) { |
| 103 | { | ||
| 104 | struct stat64 file_info; | 99 | struct stat64 file_info; |
| 105 | 100 | ||
| 106 | std::string copy(filename); | 101 | std::string copy(filename); |
| @@ -117,8 +112,8 @@ bool IsDirectory(const std::string &filename) | |||
| 117 | #endif | 112 | #endif |
| 118 | 113 | ||
| 119 | if (result < 0) { | 114 | if (result < 0) { |
| 120 | LOG_WARNING(Common_Filesystem, "stat failed on %s: %s", | 115 | LOG_WARNING(Common_Filesystem, "stat failed on %s: %s", filename.c_str(), |
| 121 | filename.c_str(), GetLastErrorMsg()); | 116 | GetLastErrorMsg()); |
| 122 | return false; | 117 | return false; |
| 123 | } | 118 | } |
| 124 | 119 | ||
| @@ -127,36 +122,32 @@ bool IsDirectory(const std::string &filename) | |||
| 127 | 122 | ||
| 128 | // Deletes a given filename, return true on success | 123 | // Deletes a given filename, return true on success |
| 129 | // Doesn't supports deleting a directory | 124 | // Doesn't supports deleting a directory |
| 130 | bool Delete(const std::string &filename) | 125 | bool Delete(const std::string& filename) { |
| 131 | { | ||
| 132 | LOG_INFO(Common_Filesystem, "file %s", filename.c_str()); | 126 | LOG_INFO(Common_Filesystem, "file %s", filename.c_str()); |
| 133 | 127 | ||
| 134 | // Return true because we care about the file no | 128 | // Return true because we care about the file no |
| 135 | // being there, not the actual delete. | 129 | // being there, not the actual delete. |
| 136 | if (!Exists(filename)) | 130 | if (!Exists(filename)) { |
| 137 | { | ||
| 138 | LOG_WARNING(Common_Filesystem, "%s does not exist", filename.c_str()); | 131 | LOG_WARNING(Common_Filesystem, "%s does not exist", filename.c_str()); |
| 139 | return true; | 132 | return true; |
| 140 | } | 133 | } |
| 141 | 134 | ||
| 142 | // We can't delete a directory | 135 | // We can't delete a directory |
| 143 | if (IsDirectory(filename)) | 136 | if (IsDirectory(filename)) { |
| 144 | { | ||
| 145 | LOG_ERROR(Common_Filesystem, "Failed: %s is a directory", filename.c_str()); | 137 | LOG_ERROR(Common_Filesystem, "Failed: %s is a directory", filename.c_str()); |
| 146 | return false; | 138 | return false; |
| 147 | } | 139 | } |
| 148 | 140 | ||
| 149 | #ifdef _WIN32 | 141 | #ifdef _WIN32 |
| 150 | if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str())) | 142 | if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str())) { |
| 151 | { | 143 | LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s", filename.c_str(), |
| 152 | LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s", | 144 | GetLastErrorMsg()); |
| 153 | filename.c_str(), GetLastErrorMsg()); | ||
| 154 | return false; | 145 | return false; |
| 155 | } | 146 | } |
| 156 | #else | 147 | #else |
| 157 | if (unlink(filename.c_str()) == -1) { | 148 | if (unlink(filename.c_str()) == -1) { |
| 158 | LOG_ERROR(Common_Filesystem, "unlink failed on %s: %s", | 149 | LOG_ERROR(Common_Filesystem, "unlink failed on %s: %s", filename.c_str(), |
| 159 | filename.c_str(), GetLastErrorMsg()); | 150 | GetLastErrorMsg()); |
| 160 | return false; | 151 | return false; |
| 161 | } | 152 | } |
| 162 | #endif | 153 | #endif |
| @@ -165,16 +156,15 @@ bool Delete(const std::string &filename) | |||
| 165 | } | 156 | } |
| 166 | 157 | ||
| 167 | // Returns true if successful, or path already exists. | 158 | // Returns true if successful, or path already exists. |
| 168 | bool CreateDir(const std::string &path) | 159 | bool CreateDir(const std::string& path) { |
| 169 | { | ||
| 170 | LOG_TRACE(Common_Filesystem, "directory %s", path.c_str()); | 160 | LOG_TRACE(Common_Filesystem, "directory %s", path.c_str()); |
| 171 | #ifdef _WIN32 | 161 | #ifdef _WIN32 |
| 172 | if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr)) | 162 | if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr)) |
| 173 | return true; | 163 | return true; |
| 174 | DWORD error = GetLastError(); | 164 | DWORD error = GetLastError(); |
| 175 | if (error == ERROR_ALREADY_EXISTS) | 165 | if (error == ERROR_ALREADY_EXISTS) { |
| 176 | { | 166 | LOG_WARNING(Common_Filesystem, "CreateDirectory failed on %s: already exists", |
| 177 | LOG_WARNING(Common_Filesystem, "CreateDirectory failed on %s: already exists", path.c_str()); | 167 | path.c_str()); |
| 178 | return true; | 168 | return true; |
| 179 | } | 169 | } |
| 180 | LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error); | 170 | LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error); |
| @@ -185,8 +175,7 @@ bool CreateDir(const std::string &path) | |||
| 185 | 175 | ||
| 186 | int err = errno; | 176 | int err = errno; |
| 187 | 177 | ||
| 188 | if (err == EEXIST) | 178 | if (err == EEXIST) { |
| 189 | { | ||
| 190 | LOG_WARNING(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str()); | 179 | LOG_WARNING(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str()); |
| 191 | return true; | 180 | return true; |
| 192 | } | 181 | } |
| @@ -197,20 +186,17 @@ bool CreateDir(const std::string &path) | |||
| 197 | } | 186 | } |
| 198 | 187 | ||
| 199 | // Creates the full path of fullPath returns true on success | 188 | // Creates the full path of fullPath returns true on success |
| 200 | bool CreateFullPath(const std::string &fullPath) | 189 | bool CreateFullPath(const std::string& fullPath) { |
| 201 | { | ||
| 202 | int panicCounter = 100; | 190 | int panicCounter = 100; |
| 203 | LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str()); | 191 | LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str()); |
| 204 | 192 | ||
| 205 | if (FileUtil::Exists(fullPath)) | 193 | if (FileUtil::Exists(fullPath)) { |
| 206 | { | ||
| 207 | LOG_WARNING(Common_Filesystem, "path exists %s", fullPath.c_str()); | 194 | LOG_WARNING(Common_Filesystem, "path exists %s", fullPath.c_str()); |
| 208 | return true; | 195 | return true; |
| 209 | } | 196 | } |
| 210 | 197 | ||
| 211 | size_t position = 0; | 198 | size_t position = 0; |
| 212 | while (true) | 199 | while (true) { |
| 213 | { | ||
| 214 | // Find next sub path | 200 | // Find next sub path |
| 215 | position = fullPath.find(DIR_SEP_CHR, position); | 201 | position = fullPath.find(DIR_SEP_CHR, position); |
| 216 | 202 | ||
| @@ -227,8 +213,7 @@ bool CreateFullPath(const std::string &fullPath) | |||
| 227 | 213 | ||
| 228 | // A safety check | 214 | // A safety check |
| 229 | panicCounter--; | 215 | panicCounter--; |
| 230 | if (panicCounter <= 0) | 216 | if (panicCounter <= 0) { |
| 231 | { | ||
| 232 | LOG_ERROR(Common, "CreateFullPath: directory structure is too deep"); | 217 | LOG_ERROR(Common, "CreateFullPath: directory structure is too deep"); |
| 233 | return false; | 218 | return false; |
| 234 | } | 219 | } |
| @@ -236,15 +221,12 @@ bool CreateFullPath(const std::string &fullPath) | |||
| 236 | } | 221 | } |
| 237 | } | 222 | } |
| 238 | 223 | ||
| 239 | |||
| 240 | // Deletes a directory filename, returns true on success | 224 | // Deletes a directory filename, returns true on success |
| 241 | bool DeleteDir(const std::string &filename) | 225 | bool DeleteDir(const std::string& filename) { |
| 242 | { | ||
| 243 | LOG_INFO(Common_Filesystem, "directory %s", filename.c_str()); | 226 | LOG_INFO(Common_Filesystem, "directory %s", filename.c_str()); |
| 244 | 227 | ||
| 245 | // check if a directory | 228 | // check if a directory |
| 246 | if (!FileUtil::IsDirectory(filename)) | 229 | if (!FileUtil::IsDirectory(filename)) { |
| 247 | { | ||
| 248 | LOG_ERROR(Common_Filesystem, "Not a directory %s", filename.c_str()); | 230 | LOG_ERROR(Common_Filesystem, "Not a directory %s", filename.c_str()); |
| 249 | return false; | 231 | return false; |
| 250 | } | 232 | } |
| @@ -262,83 +244,73 @@ bool DeleteDir(const std::string &filename) | |||
| 262 | } | 244 | } |
| 263 | 245 | ||
| 264 | // renames file srcFilename to destFilename, returns true on success | 246 | // renames file srcFilename to destFilename, returns true on success |
| 265 | bool Rename(const std::string &srcFilename, const std::string &destFilename) | 247 | bool Rename(const std::string& srcFilename, const std::string& destFilename) { |
| 266 | { | 248 | LOG_TRACE(Common_Filesystem, "%s --> %s", srcFilename.c_str(), destFilename.c_str()); |
| 267 | LOG_TRACE(Common_Filesystem, "%s --> %s", | ||
| 268 | srcFilename.c_str(), destFilename.c_str()); | ||
| 269 | #ifdef _WIN32 | 249 | #ifdef _WIN32 |
| 270 | if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(), Common::UTF8ToUTF16W(destFilename).c_str()) == 0) | 250 | if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(), |
| 251 | Common::UTF8ToUTF16W(destFilename).c_str()) == 0) | ||
| 271 | return true; | 252 | return true; |
| 272 | #else | 253 | #else |
| 273 | if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) | 254 | if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) |
| 274 | return true; | 255 | return true; |
| 275 | #endif | 256 | #endif |
| 276 | LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", | 257 | LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), |
| 277 | srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); | 258 | GetLastErrorMsg()); |
| 278 | return false; | 259 | return false; |
| 279 | } | 260 | } |
| 280 | 261 | ||
| 281 | // copies file srcFilename to destFilename, returns true on success | 262 | // copies file srcFilename to destFilename, returns true on success |
| 282 | bool Copy(const std::string &srcFilename, const std::string &destFilename) | 263 | bool Copy(const std::string& srcFilename, const std::string& destFilename) { |
| 283 | { | 264 | LOG_TRACE(Common_Filesystem, "%s --> %s", srcFilename.c_str(), destFilename.c_str()); |
| 284 | LOG_TRACE(Common_Filesystem, "%s --> %s", | ||
| 285 | srcFilename.c_str(), destFilename.c_str()); | ||
| 286 | #ifdef _WIN32 | 265 | #ifdef _WIN32 |
| 287 | if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(), Common::UTF8ToUTF16W(destFilename).c_str(), FALSE)) | 266 | if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(), |
| 267 | Common::UTF8ToUTF16W(destFilename).c_str(), FALSE)) | ||
| 288 | return true; | 268 | return true; |
| 289 | 269 | ||
| 290 | LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", | 270 | LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), |
| 291 | srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); | 271 | GetLastErrorMsg()); |
| 292 | return false; | 272 | return false; |
| 293 | #else | 273 | #else |
| 294 | 274 | ||
| 295 | // buffer size | 275 | // buffer size |
| 296 | #define BSIZE 1024 | 276 | #define BSIZE 1024 |
| 297 | 277 | ||
| 298 | char buffer[BSIZE]; | 278 | char buffer[BSIZE]; |
| 299 | 279 | ||
| 300 | // Open input file | 280 | // Open input file |
| 301 | FILE *input = fopen(srcFilename.c_str(), "rb"); | 281 | FILE* input = fopen(srcFilename.c_str(), "rb"); |
| 302 | if (!input) | 282 | if (!input) { |
| 303 | { | 283 | LOG_ERROR(Common_Filesystem, "opening input failed %s --> %s: %s", srcFilename.c_str(), |
| 304 | LOG_ERROR(Common_Filesystem, "opening input failed %s --> %s: %s", | 284 | destFilename.c_str(), GetLastErrorMsg()); |
| 305 | srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); | ||
| 306 | return false; | 285 | return false; |
| 307 | } | 286 | } |
| 308 | 287 | ||
| 309 | // open output file | 288 | // open output file |
| 310 | FILE *output = fopen(destFilename.c_str(), "wb"); | 289 | FILE* output = fopen(destFilename.c_str(), "wb"); |
| 311 | if (!output) | 290 | if (!output) { |
| 312 | { | ||
| 313 | fclose(input); | 291 | fclose(input); |
| 314 | LOG_ERROR(Common_Filesystem, "opening output failed %s --> %s: %s", | 292 | LOG_ERROR(Common_Filesystem, "opening output failed %s --> %s: %s", srcFilename.c_str(), |
| 315 | srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); | 293 | destFilename.c_str(), GetLastErrorMsg()); |
| 316 | return false; | 294 | return false; |
| 317 | } | 295 | } |
| 318 | 296 | ||
| 319 | // copy loop | 297 | // copy loop |
| 320 | while (!feof(input)) | 298 | while (!feof(input)) { |
| 321 | { | ||
| 322 | // read input | 299 | // read input |
| 323 | int rnum = fread(buffer, sizeof(char), BSIZE, input); | 300 | int rnum = fread(buffer, sizeof(char), BSIZE, input); |
| 324 | if (rnum != BSIZE) | 301 | if (rnum != BSIZE) { |
| 325 | { | 302 | if (ferror(input) != 0) { |
| 326 | if (ferror(input) != 0) | 303 | LOG_ERROR(Common_Filesystem, "failed reading from source, %s --> %s: %s", |
| 327 | { | 304 | srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); |
| 328 | LOG_ERROR(Common_Filesystem, | ||
| 329 | "failed reading from source, %s --> %s: %s", | ||
| 330 | srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); | ||
| 331 | goto bail; | 305 | goto bail; |
| 332 | } | 306 | } |
| 333 | } | 307 | } |
| 334 | 308 | ||
| 335 | // write output | 309 | // write output |
| 336 | int wnum = fwrite(buffer, sizeof(char), rnum, output); | 310 | int wnum = fwrite(buffer, sizeof(char), rnum, output); |
| 337 | if (wnum != rnum) | 311 | if (wnum != rnum) { |
| 338 | { | 312 | LOG_ERROR(Common_Filesystem, "failed writing to output, %s --> %s: %s", |
| 339 | LOG_ERROR(Common_Filesystem, | 313 | srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); |
| 340 | "failed writing to output, %s --> %s: %s", | ||
| 341 | srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); | ||
| 342 | goto bail; | 314 | goto bail; |
| 343 | } | 315 | } |
| 344 | } | 316 | } |
| @@ -356,16 +328,13 @@ bail: | |||
| 356 | } | 328 | } |
| 357 | 329 | ||
| 358 | // Returns the size of filename (64bit) | 330 | // Returns the size of filename (64bit) |
| 359 | u64 GetSize(const std::string &filename) | 331 | u64 GetSize(const std::string& filename) { |
| 360 | { | 332 | if (!Exists(filename)) { |
| 361 | if (!Exists(filename)) | ||
| 362 | { | ||
| 363 | LOG_ERROR(Common_Filesystem, "failed %s: No such file", filename.c_str()); | 333 | LOG_ERROR(Common_Filesystem, "failed %s: No such file", filename.c_str()); |
| 364 | return 0; | 334 | return 0; |
| 365 | } | 335 | } |
| 366 | 336 | ||
| 367 | if (IsDirectory(filename)) | 337 | if (IsDirectory(filename)) { |
| 368 | { | ||
| 369 | LOG_ERROR(Common_Filesystem, "failed %s: is a directory", filename.c_str()); | 338 | LOG_ERROR(Common_Filesystem, "failed %s: is a directory", filename.c_str()); |
| 370 | return 0; | 339 | return 0; |
| 371 | } | 340 | } |
| @@ -377,65 +346,54 @@ u64 GetSize(const std::string &filename) | |||
| 377 | if (stat64(filename.c_str(), &buf) == 0) | 346 | if (stat64(filename.c_str(), &buf) == 0) |
| 378 | #endif | 347 | #endif |
| 379 | { | 348 | { |
| 380 | LOG_TRACE(Common_Filesystem, "%s: %lld", | 349 | LOG_TRACE(Common_Filesystem, "%s: %lld", filename.c_str(), (long long)buf.st_size); |
| 381 | filename.c_str(), (long long)buf.st_size); | ||
| 382 | return buf.st_size; | 350 | return buf.st_size; |
| 383 | } | 351 | } |
| 384 | 352 | ||
| 385 | LOG_ERROR(Common_Filesystem, "Stat failed %s: %s", | 353 | LOG_ERROR(Common_Filesystem, "Stat failed %s: %s", filename.c_str(), GetLastErrorMsg()); |
| 386 | filename.c_str(), GetLastErrorMsg()); | ||
| 387 | return 0; | 354 | return 0; |
| 388 | } | 355 | } |
| 389 | 356 | ||
| 390 | // Overloaded GetSize, accepts file descriptor | 357 | // Overloaded GetSize, accepts file descriptor |
| 391 | u64 GetSize(const int fd) | 358 | u64 GetSize(const int fd) { |
| 392 | { | ||
| 393 | struct stat64 buf; | 359 | struct stat64 buf; |
| 394 | if (fstat64(fd, &buf) != 0) { | 360 | if (fstat64(fd, &buf) != 0) { |
| 395 | LOG_ERROR(Common_Filesystem, "GetSize: stat failed %i: %s", | 361 | LOG_ERROR(Common_Filesystem, "GetSize: stat failed %i: %s", fd, GetLastErrorMsg()); |
| 396 | fd, GetLastErrorMsg()); | ||
| 397 | return 0; | 362 | return 0; |
| 398 | } | 363 | } |
| 399 | return buf.st_size; | 364 | return buf.st_size; |
| 400 | } | 365 | } |
| 401 | 366 | ||
| 402 | // Overloaded GetSize, accepts FILE* | 367 | // Overloaded GetSize, accepts FILE* |
| 403 | u64 GetSize(FILE *f) | 368 | u64 GetSize(FILE* f) { |
| 404 | { | ||
| 405 | // can't use off_t here because it can be 32-bit | 369 | // can't use off_t here because it can be 32-bit |
| 406 | u64 pos = ftello(f); | 370 | u64 pos = ftello(f); |
| 407 | if (fseeko(f, 0, SEEK_END) != 0) { | 371 | if (fseeko(f, 0, SEEK_END) != 0) { |
| 408 | LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", | 372 | LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", f, GetLastErrorMsg()); |
| 409 | f, GetLastErrorMsg()); | ||
| 410 | return 0; | 373 | return 0; |
| 411 | } | 374 | } |
| 412 | u64 size = ftello(f); | 375 | u64 size = ftello(f); |
| 413 | if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { | 376 | if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { |
| 414 | LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", | 377 | LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", f, GetLastErrorMsg()); |
| 415 | f, GetLastErrorMsg()); | ||
| 416 | return 0; | 378 | return 0; |
| 417 | } | 379 | } |
| 418 | return size; | 380 | return size; |
| 419 | } | 381 | } |
| 420 | 382 | ||
| 421 | // creates an empty file filename, returns true on success | 383 | // creates an empty file filename, returns true on success |
| 422 | bool CreateEmptyFile(const std::string &filename) | 384 | bool CreateEmptyFile(const std::string& filename) { |
| 423 | { | ||
| 424 | LOG_TRACE(Common_Filesystem, "%s", filename.c_str()); | 385 | LOG_TRACE(Common_Filesystem, "%s", filename.c_str()); |
| 425 | 386 | ||
| 426 | if (!FileUtil::IOFile(filename, "wb")) | 387 | if (!FileUtil::IOFile(filename, "wb")) { |
| 427 | { | 388 | LOG_ERROR(Common_Filesystem, "failed %s: %s", filename.c_str(), GetLastErrorMsg()); |
| 428 | LOG_ERROR(Common_Filesystem, "failed %s: %s", | ||
| 429 | filename.c_str(), GetLastErrorMsg()); | ||
| 430 | return false; | 389 | return false; |
| 431 | } | 390 | } |
| 432 | 391 | ||
| 433 | return true; | 392 | return true; |
| 434 | } | 393 | } |
| 435 | 394 | ||
| 436 | 395 | bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory, | |
| 437 | bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback) | 396 | DirectoryEntryCallable callback) { |
| 438 | { | ||
| 439 | LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str()); | 397 | LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str()); |
| 440 | 398 | ||
| 441 | // How many files + directories we found | 399 | // How many files + directories we found |
| @@ -457,7 +415,7 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo | |||
| 457 | do { | 415 | do { |
| 458 | const std::string virtual_name(Common::UTF16ToUTF8(ffd.cFileName)); | 416 | const std::string virtual_name(Common::UTF16ToUTF8(ffd.cFileName)); |
| 459 | #else | 417 | #else |
| 460 | DIR *dirp = opendir(directory.c_str()); | 418 | DIR* dirp = opendir(directory.c_str()); |
| 461 | if (!dirp) | 419 | if (!dirp) |
| 462 | return false; | 420 | return false; |
| 463 | 421 | ||
| @@ -493,8 +451,8 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo | |||
| 493 | return true; | 451 | return true; |
| 494 | } | 452 | } |
| 495 | 453 | ||
| 496 | unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion) | 454 | unsigned ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry, |
| 497 | { | 455 | unsigned int recursion) { |
| 498 | const auto callback = [recursion, &parent_entry](unsigned* num_entries_out, | 456 | const auto callback = [recursion, &parent_entry](unsigned* num_entries_out, |
| 499 | const std::string& directory, | 457 | const std::string& directory, |
| 500 | const std::string& virtual_name) -> bool { | 458 | const std::string& virtual_name) -> bool { |
| @@ -526,11 +484,8 @@ unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, | |||
| 526 | return ForeachDirectoryEntry(&num_entries, directory, callback) ? num_entries : 0; | 484 | return ForeachDirectoryEntry(&num_entries, directory, callback) ? num_entries : 0; |
| 527 | } | 485 | } |
| 528 | 486 | ||
| 529 | 487 | bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) { | |
| 530 | bool DeleteDirRecursively(const std::string &directory, unsigned int recursion) | 488 | const auto callback = [recursion](unsigned* num_entries_out, const std::string& directory, |
| 531 | { | ||
| 532 | const auto callback = [recursion](unsigned* num_entries_out, | ||
| 533 | const std::string& directory, | ||
| 534 | const std::string& virtual_name) -> bool { | 489 | const std::string& virtual_name) -> bool { |
| 535 | std::string new_path = directory + DIR_SEP_CHR + virtual_name; | 490 | std::string new_path = directory + DIR_SEP_CHR + virtual_name; |
| 536 | 491 | ||
| @@ -551,53 +506,53 @@ bool DeleteDirRecursively(const std::string &directory, unsigned int recursion) | |||
| 551 | } | 506 | } |
| 552 | 507 | ||
| 553 | // Create directory and copy contents (does not overwrite existing files) | 508 | // Create directory and copy contents (does not overwrite existing files) |
| 554 | void CopyDir(const std::string &source_path, const std::string &dest_path) | 509 | void CopyDir(const std::string& source_path, const std::string& dest_path) { |
| 555 | { | ||
| 556 | #ifndef _WIN32 | 510 | #ifndef _WIN32 |
| 557 | if (source_path == dest_path) return; | 511 | if (source_path == dest_path) |
| 558 | if (!FileUtil::Exists(source_path)) return; | 512 | return; |
| 559 | if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path); | 513 | if (!FileUtil::Exists(source_path)) |
| 560 | 514 | return; | |
| 561 | DIR *dirp = opendir(source_path.c_str()); | 515 | if (!FileUtil::Exists(dest_path)) |
| 562 | if (!dirp) return; | 516 | FileUtil::CreateFullPath(dest_path); |
| 517 | |||
| 518 | DIR* dirp = opendir(source_path.c_str()); | ||
| 519 | if (!dirp) | ||
| 520 | return; | ||
| 563 | 521 | ||
| 564 | while (struct dirent* result = readdir(dirp)) { | 522 | while (struct dirent* result = readdir(dirp)) { |
| 565 | const std::string virtualName(result->d_name); | 523 | const std::string virtualName(result->d_name); |
| 566 | // check for "." and ".." | 524 | // check for "." and ".." |
| 567 | if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || | 525 | if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || |
| 568 | ((virtualName[0] == '.') && (virtualName[1] == '.') && | 526 | ((virtualName[0] == '.') && (virtualName[1] == '.') && (virtualName[2] == '\0'))) |
| 569 | (virtualName[2] == '\0'))) | ||
| 570 | continue; | 527 | continue; |
| 571 | 528 | ||
| 572 | std::string source, dest; | 529 | std::string source, dest; |
| 573 | source = source_path + virtualName; | 530 | source = source_path + virtualName; |
| 574 | dest = dest_path + virtualName; | 531 | dest = dest_path + virtualName; |
| 575 | if (IsDirectory(source)) | 532 | if (IsDirectory(source)) { |
| 576 | { | ||
| 577 | source += '/'; | 533 | source += '/'; |
| 578 | dest += '/'; | 534 | dest += '/'; |
| 579 | if (!FileUtil::Exists(dest)) FileUtil::CreateFullPath(dest); | 535 | if (!FileUtil::Exists(dest)) |
| 536 | FileUtil::CreateFullPath(dest); | ||
| 580 | CopyDir(source, dest); | 537 | CopyDir(source, dest); |
| 581 | } | 538 | } else if (!FileUtil::Exists(dest)) |
| 582 | else if (!FileUtil::Exists(dest)) FileUtil::Copy(source, dest); | 539 | FileUtil::Copy(source, dest); |
| 583 | } | 540 | } |
| 584 | closedir(dirp); | 541 | closedir(dirp); |
| 585 | #endif | 542 | #endif |
| 586 | } | 543 | } |
| 587 | 544 | ||
| 588 | // Returns the current directory | 545 | // Returns the current directory |
| 589 | std::string GetCurrentDir() | 546 | std::string GetCurrentDir() { |
| 590 | { | 547 | // Get the current working directory (getcwd uses malloc) |
| 591 | // Get the current working directory (getcwd uses malloc) | ||
| 592 | #ifdef _WIN32 | 548 | #ifdef _WIN32 |
| 593 | wchar_t *dir; | 549 | wchar_t* dir; |
| 594 | if (!(dir = _wgetcwd(nullptr, 0))) { | 550 | if (!(dir = _wgetcwd(nullptr, 0))) { |
| 595 | #else | 551 | #else |
| 596 | char *dir; | 552 | char* dir; |
| 597 | if (!(dir = getcwd(nullptr, 0))) { | 553 | if (!(dir = getcwd(nullptr, 0))) { |
| 598 | #endif | 554 | #endif |
| 599 | LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s", | 555 | LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s", GetLastErrorMsg()); |
| 600 | GetLastErrorMsg()); | ||
| 601 | return nullptr; | 556 | return nullptr; |
| 602 | } | 557 | } |
| 603 | #ifdef _WIN32 | 558 | #ifdef _WIN32 |
| @@ -610,8 +565,7 @@ std::string GetCurrentDir() | |||
| 610 | } | 565 | } |
| 611 | 566 | ||
| 612 | // Sets the current directory to the given directory | 567 | // Sets the current directory to the given directory |
| 613 | bool SetCurrentDir(const std::string &directory) | 568 | bool SetCurrentDir(const std::string& directory) { |
| 614 | { | ||
| 615 | #ifdef _WIN32 | 569 | #ifdef _WIN32 |
| 616 | return _wchdir(Common::UTF8ToUTF16W(directory).c_str()) == 0; | 570 | return _wchdir(Common::UTF8ToUTF16W(directory).c_str()) == 0; |
| 617 | #else | 571 | #else |
| @@ -620,8 +574,7 @@ bool SetCurrentDir(const std::string &directory) | |||
| 620 | } | 574 | } |
| 621 | 575 | ||
| 622 | #if defined(__APPLE__) | 576 | #if defined(__APPLE__) |
| 623 | std::string GetBundleDirectory() | 577 | std::string GetBundleDirectory() { |
| 624 | { | ||
| 625 | CFURLRef BundleRef; | 578 | CFURLRef BundleRef; |
| 626 | char AppBundlePath[MAXPATHLEN]; | 579 | char AppBundlePath[MAXPATHLEN]; |
| 627 | // Get the main bundle for the app | 580 | // Get the main bundle for the app |
| @@ -636,11 +589,9 @@ std::string GetBundleDirectory() | |||
| 636 | #endif | 589 | #endif |
| 637 | 590 | ||
| 638 | #ifdef _WIN32 | 591 | #ifdef _WIN32 |
| 639 | std::string& GetExeDirectory() | 592 | std::string& GetExeDirectory() { |
| 640 | { | ||
| 641 | static std::string exe_path; | 593 | static std::string exe_path; |
| 642 | if (exe_path.empty()) | 594 | if (exe_path.empty()) { |
| 643 | { | ||
| 644 | wchar_t wchar_exe_path[2048]; | 595 | wchar_t wchar_exe_path[2048]; |
| 645 | GetModuleFileNameW(nullptr, wchar_exe_path, 2048); | 596 | GetModuleFileNameW(nullptr, wchar_exe_path, 2048); |
| 646 | exe_path = Common::UTF16ToUTF8(wchar_exe_path); | 597 | exe_path = Common::UTF16ToUTF8(wchar_exe_path); |
| @@ -660,7 +611,8 @@ static const std::string& GetHomeDirectory() { | |||
| 660 | home_path = envvar; | 611 | home_path = envvar; |
| 661 | } else { | 612 | } else { |
| 662 | auto pw = getpwuid(getuid()); | 613 | auto pw = getpwuid(getuid()); |
| 663 | ASSERT_MSG(pw, "$HOME isn’t defined, and the current user can’t be found in /etc/passwd."); | 614 | ASSERT_MSG(pw, |
| 615 | "$HOME isn’t defined, and the current user can’t be found in /etc/passwd."); | ||
| 664 | home_path = pw->pw_dir; | 616 | home_path = pw->pw_dir; |
| 665 | } | 617 | } |
| 666 | } | 618 | } |
| @@ -699,11 +651,10 @@ static const std::string GetUserDirectory(const std::string& envvar) { | |||
| 699 | } | 651 | } |
| 700 | #endif | 652 | #endif |
| 701 | 653 | ||
| 702 | std::string GetSysDirectory() | 654 | std::string GetSysDirectory() { |
| 703 | { | ||
| 704 | std::string sysDir; | 655 | std::string sysDir; |
| 705 | 656 | ||
| 706 | #if defined (__APPLE__) | 657 | #if defined(__APPLE__) |
| 707 | sysDir = GetBundleDirectory(); | 658 | sysDir = GetBundleDirectory(); |
| 708 | sysDir += DIR_SEP; | 659 | sysDir += DIR_SEP; |
| 709 | sysDir += SYSDATA_DIR; | 660 | sysDir += SYSDATA_DIR; |
| @@ -718,123 +669,114 @@ std::string GetSysDirectory() | |||
| 718 | 669 | ||
| 719 | // Returns a string with a Citra data dir or file in the user's home | 670 | // Returns a string with a Citra data dir or file in the user's home |
| 720 | // directory. To be used in "multi-user" mode (that is, installed). | 671 | // directory. To be used in "multi-user" mode (that is, installed). |
| 721 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) | 672 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath) { |
| 722 | { | ||
| 723 | static std::string paths[NUM_PATH_INDICES]; | 673 | static std::string paths[NUM_PATH_INDICES]; |
| 724 | 674 | ||
| 725 | // Set up all paths and files on the first run | 675 | // Set up all paths and files on the first run |
| 726 | if (paths[D_USER_IDX].empty()) | 676 | if (paths[D_USER_IDX].empty()) { |
| 727 | { | ||
| 728 | #ifdef _WIN32 | 677 | #ifdef _WIN32 |
| 729 | paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; | 678 | paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; |
| 730 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; | 679 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; |
| 731 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; | 680 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; |
| 732 | #else | 681 | #else |
| 733 | if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) { | 682 | if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) { |
| 734 | paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; | 683 | paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; |
| 735 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; | 684 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; |
| 736 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; | 685 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; |
| 737 | } else { | 686 | } else { |
| 738 | std::string data_dir = GetUserDirectory("XDG_DATA_HOME"); | 687 | std::string data_dir = GetUserDirectory("XDG_DATA_HOME"); |
| 739 | std::string config_dir = GetUserDirectory("XDG_CONFIG_HOME"); | 688 | std::string config_dir = GetUserDirectory("XDG_CONFIG_HOME"); |
| 740 | std::string cache_dir = GetUserDirectory("XDG_CACHE_HOME"); | 689 | std::string cache_dir = GetUserDirectory("XDG_CACHE_HOME"); |
| 741 | 690 | ||
| 742 | paths[D_USER_IDX] = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP; | 691 | paths[D_USER_IDX] = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP; |
| 743 | paths[D_CONFIG_IDX] = config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP; | 692 | paths[D_CONFIG_IDX] = config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP; |
| 744 | paths[D_CACHE_IDX] = cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP; | 693 | paths[D_CACHE_IDX] = cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP; |
| 745 | } | 694 | } |
| 746 | #endif | 695 | #endif |
| 747 | 696 | ||
| 748 | paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; | 697 | paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; |
| 749 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; | 698 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; |
| 750 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; | 699 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; |
| 751 | paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP; | 700 | paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP; |
| 752 | paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP; | 701 | paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP; |
| 753 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; | 702 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; |
| 754 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; | 703 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; |
| 755 | paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; | 704 | paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; |
| 756 | paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; | 705 | paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; |
| 757 | paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; | 706 | paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; |
| 758 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; | 707 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; |
| 759 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; | 708 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; |
| 760 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; | 709 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; |
| 761 | paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; | 710 | paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; |
| 762 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; | 711 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; |
| 763 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; | 712 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; |
| 764 | paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; | 713 | paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; |
| 765 | } | 714 | } |
| 766 | 715 | ||
| 767 | if (!newPath.empty()) | 716 | if (!newPath.empty()) { |
| 768 | { | 717 | if (!FileUtil::IsDirectory(newPath)) { |
| 769 | if (!FileUtil::IsDirectory(newPath)) | ||
| 770 | { | ||
| 771 | LOG_ERROR(Common_Filesystem, "Invalid path specified %s", newPath.c_str()); | 718 | LOG_ERROR(Common_Filesystem, "Invalid path specified %s", newPath.c_str()); |
| 772 | return paths[DirIDX]; | 719 | return paths[DirIDX]; |
| 773 | } | 720 | } else { |
| 774 | else | ||
| 775 | { | ||
| 776 | paths[DirIDX] = newPath; | 721 | paths[DirIDX] = newPath; |
| 777 | } | 722 | } |
| 778 | 723 | ||
| 779 | switch (DirIDX) | 724 | switch (DirIDX) { |
| 780 | { | ||
| 781 | case D_ROOT_IDX: | 725 | case D_ROOT_IDX: |
| 782 | paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; | 726 | paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; |
| 783 | paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; | 727 | paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; |
| 784 | paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; | 728 | paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; |
| 785 | break; | 729 | break; |
| 786 | 730 | ||
| 787 | case D_USER_IDX: | 731 | case D_USER_IDX: |
| 788 | paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; | 732 | paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; |
| 789 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; | 733 | paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; |
| 790 | paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; | 734 | paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; |
| 791 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; | 735 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; |
| 792 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; | 736 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; |
| 793 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; | 737 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; |
| 794 | paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP; | 738 | paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP; |
| 795 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; | 739 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; |
| 796 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; | 740 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; |
| 797 | paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; | 741 | paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; |
| 798 | paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; | 742 | paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; |
| 799 | paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; | 743 | paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; |
| 800 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; | 744 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; |
| 801 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; | 745 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; |
| 802 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; | 746 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; |
| 803 | paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; | 747 | paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; |
| 804 | paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; | 748 | paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; |
| 805 | paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; | 749 | paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; |
| 806 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; | 750 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; |
| 807 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; | 751 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; |
| 808 | paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; | 752 | paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; |
| 809 | break; | 753 | break; |
| 810 | 754 | ||
| 811 | case D_CONFIG_IDX: | 755 | case D_CONFIG_IDX: |
| 812 | paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; | 756 | paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; |
| 813 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; | 757 | paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; |
| 814 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; | 758 | paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; |
| 815 | break; | 759 | break; |
| 816 | 760 | ||
| 817 | case D_DUMP_IDX: | 761 | case D_DUMP_IDX: |
| 818 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; | 762 | paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; |
| 819 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; | 763 | paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; |
| 820 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; | 764 | paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; |
| 821 | break; | 765 | break; |
| 822 | 766 | ||
| 823 | case D_LOGS_IDX: | 767 | case D_LOGS_IDX: |
| 824 | paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; | 768 | paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; |
| 825 | } | 769 | } |
| 826 | } | 770 | } |
| 827 | 771 | ||
| 828 | return paths[DirIDX]; | 772 | return paths[DirIDX]; |
| 829 | } | 773 | } |
| 830 | 774 | ||
| 831 | size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename) | 775 | size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) { |
| 832 | { | ||
| 833 | return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); | 776 | return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); |
| 834 | } | 777 | } |
| 835 | 778 | ||
| 836 | size_t ReadFileToString(bool text_file, const char *filename, std::string &str) | 779 | size_t ReadFileToString(bool text_file, const char* filename, std::string& str) { |
| 837 | { | ||
| 838 | IOFile file(filename, text_file ? "r" : "rb"); | 780 | IOFile file(filename, text_file ? "r" : "rb"); |
| 839 | 781 | ||
| 840 | if (!file) | 782 | if (!file) |
| @@ -886,42 +828,35 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam | |||
| 886 | } | 828 | } |
| 887 | } | 829 | } |
| 888 | 830 | ||
| 889 | IOFile::IOFile() | 831 | IOFile::IOFile() {} |
| 890 | { | ||
| 891 | } | ||
| 892 | 832 | ||
| 893 | IOFile::IOFile(const std::string& filename, const char openmode[]) | 833 | IOFile::IOFile(const std::string& filename, const char openmode[]) { |
| 894 | { | ||
| 895 | Open(filename, openmode); | 834 | Open(filename, openmode); |
| 896 | } | 835 | } |
| 897 | 836 | ||
| 898 | IOFile::~IOFile() | 837 | IOFile::~IOFile() { |
| 899 | { | ||
| 900 | Close(); | 838 | Close(); |
| 901 | } | 839 | } |
| 902 | 840 | ||
| 903 | IOFile::IOFile(IOFile&& other) | 841 | IOFile::IOFile(IOFile&& other) { |
| 904 | { | ||
| 905 | Swap(other); | 842 | Swap(other); |
| 906 | } | 843 | } |
| 907 | 844 | ||
| 908 | IOFile& IOFile::operator=(IOFile&& other) | 845 | IOFile& IOFile::operator=(IOFile&& other) { |
| 909 | { | ||
| 910 | Swap(other); | 846 | Swap(other); |
| 911 | return *this; | 847 | return *this; |
| 912 | } | 848 | } |
| 913 | 849 | ||
| 914 | void IOFile::Swap(IOFile& other) | 850 | void IOFile::Swap(IOFile& other) { |
| 915 | { | ||
| 916 | std::swap(m_file, other.m_file); | 851 | std::swap(m_file, other.m_file); |
| 917 | std::swap(m_good, other.m_good); | 852 | std::swap(m_good, other.m_good); |
| 918 | } | 853 | } |
| 919 | 854 | ||
| 920 | bool IOFile::Open(const std::string& filename, const char openmode[]) | 855 | bool IOFile::Open(const std::string& filename, const char openmode[]) { |
| 921 | { | ||
| 922 | Close(); | 856 | Close(); |
| 923 | #ifdef _WIN32 | 857 | #ifdef _WIN32 |
| 924 | _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), Common::UTF8ToUTF16W(openmode).c_str()); | 858 | _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), |
| 859 | Common::UTF8ToUTF16W(openmode).c_str()); | ||
| 925 | #else | 860 | #else |
| 926 | m_file = fopen(filename.c_str(), openmode); | 861 | m_file = fopen(filename.c_str(), openmode); |
| 927 | #endif | 862 | #endif |
| @@ -930,8 +865,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[]) | |||
| 930 | return m_good; | 865 | return m_good; |
| 931 | } | 866 | } |
| 932 | 867 | ||
| 933 | bool IOFile::Close() | 868 | bool IOFile::Close() { |
| 934 | { | ||
| 935 | if (!IsOpen() || 0 != std::fclose(m_file)) | 869 | if (!IsOpen() || 0 != std::fclose(m_file)) |
| 936 | m_good = false; | 870 | m_good = false; |
| 937 | 871 | ||
| @@ -939,50 +873,46 @@ bool IOFile::Close() | |||
| 939 | return m_good; | 873 | return m_good; |
| 940 | } | 874 | } |
| 941 | 875 | ||
| 942 | u64 IOFile::GetSize() const | 876 | u64 IOFile::GetSize() const { |
| 943 | { | ||
| 944 | if (IsOpen()) | 877 | if (IsOpen()) |
| 945 | return FileUtil::GetSize(m_file); | 878 | return FileUtil::GetSize(m_file); |
| 946 | 879 | ||
| 947 | return 0; | 880 | return 0; |
| 948 | } | 881 | } |
| 949 | 882 | ||
| 950 | bool IOFile::Seek(s64 off, int origin) | 883 | bool IOFile::Seek(s64 off, int origin) { |
| 951 | { | ||
| 952 | if (!IsOpen() || 0 != fseeko(m_file, off, origin)) | 884 | if (!IsOpen() || 0 != fseeko(m_file, off, origin)) |
| 953 | m_good = false; | 885 | m_good = false; |
| 954 | 886 | ||
| 955 | return m_good; | 887 | return m_good; |
| 956 | } | 888 | } |
| 957 | 889 | ||
| 958 | u64 IOFile::Tell() const | 890 | u64 IOFile::Tell() const { |
| 959 | { | ||
| 960 | if (IsOpen()) | 891 | if (IsOpen()) |
| 961 | return ftello(m_file); | 892 | return ftello(m_file); |
| 962 | 893 | ||
| 963 | return -1; | 894 | return -1; |
| 964 | } | 895 | } |
| 965 | 896 | ||
| 966 | bool IOFile::Flush() | 897 | bool IOFile::Flush() { |
| 967 | { | ||
| 968 | if (!IsOpen() || 0 != std::fflush(m_file)) | 898 | if (!IsOpen() || 0 != std::fflush(m_file)) |
| 969 | m_good = false; | 899 | m_good = false; |
| 970 | 900 | ||
| 971 | return m_good; | 901 | return m_good; |
| 972 | } | 902 | } |
| 973 | 903 | ||
| 974 | bool IOFile::Resize(u64 size) | 904 | bool IOFile::Resize(u64 size) { |
| 975 | { | 905 | if (!IsOpen() || |
| 976 | if (!IsOpen() || 0 != | 906 | 0 != |
| 977 | #ifdef _WIN32 | 907 | #ifdef _WIN32 |
| 978 | // ector: _chsize sucks, not 64-bit safe | 908 | // ector: _chsize sucks, not 64-bit safe |
| 979 | // F|RES: changed to _chsize_s. i think it is 64-bit safe | 909 | // F|RES: changed to _chsize_s. i think it is 64-bit safe |
| 980 | _chsize_s(_fileno(m_file), size) | 910 | _chsize_s(_fileno(m_file), size) |
| 981 | #else | 911 | #else |
| 982 | // TODO: handle 64bit and growing | 912 | // TODO: handle 64bit and growing |
| 983 | ftruncate(fileno(m_file), size) | 913 | ftruncate(fileno(m_file), size) |
| 984 | #endif | 914 | #endif |
| 985 | ) | 915 | ) |
| 986 | m_good = false; | 916 | m_good = false; |
| 987 | 917 | ||
| 988 | return m_good; | 918 | return m_good; |
diff --git a/src/common/file_util.h b/src/common/file_util.h index 7ad7ee829..204b06f14 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -5,15 +5,13 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstdio> | ||
| 8 | #include <fstream> | 9 | #include <fstream> |
| 9 | #include <functional> | 10 | #include <functional> |
| 10 | #include <cstdio> | ||
| 11 | #include <string> | 11 | #include <string> |
| 12 | #include <type_traits> | 12 | #include <type_traits> |
| 13 | #include <vector> | 13 | #include <vector> |
| 14 | |||
| 15 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 16 | |||
| 17 | #ifdef _MSC_VER | 15 | #ifdef _MSC_VER |
| 18 | #include "common/string_util.h" | 16 | #include "common/string_util.h" |
| 19 | #endif | 17 | #endif |
| @@ -51,75 +49,75 @@ enum { | |||
| 51 | NUM_PATH_INDICES | 49 | NUM_PATH_INDICES |
| 52 | }; | 50 | }; |
| 53 | 51 | ||
| 54 | namespace FileUtil | 52 | namespace FileUtil { |
| 55 | { | ||
| 56 | 53 | ||
| 57 | // FileSystem tree node/ | 54 | // FileSystem tree node/ |
| 58 | struct FSTEntry | 55 | struct FSTEntry { |
| 59 | { | ||
| 60 | bool isDirectory; | 56 | bool isDirectory; |
| 61 | u64 size; // file length or number of entries from children | 57 | u64 size; // file length or number of entries from children |
| 62 | std::string physicalName; // name on disk | 58 | std::string physicalName; // name on disk |
| 63 | std::string virtualName; // name in FST names table | 59 | std::string virtualName; // name in FST names table |
| 64 | std::vector<FSTEntry> children; | 60 | std::vector<FSTEntry> children; |
| 65 | }; | 61 | }; |
| 66 | 62 | ||
| 67 | // Returns true if file filename exists | 63 | // Returns true if file filename exists |
| 68 | bool Exists(const std::string &filename); | 64 | bool Exists(const std::string& filename); |
| 69 | 65 | ||
| 70 | // Returns true if filename is a directory | 66 | // Returns true if filename is a directory |
| 71 | bool IsDirectory(const std::string &filename); | 67 | bool IsDirectory(const std::string& filename); |
| 72 | 68 | ||
| 73 | // Returns the size of filename (64bit) | 69 | // Returns the size of filename (64bit) |
| 74 | u64 GetSize(const std::string &filename); | 70 | u64 GetSize(const std::string& filename); |
| 75 | 71 | ||
| 76 | // Overloaded GetSize, accepts file descriptor | 72 | // Overloaded GetSize, accepts file descriptor |
| 77 | u64 GetSize(const int fd); | 73 | u64 GetSize(const int fd); |
| 78 | 74 | ||
| 79 | // Overloaded GetSize, accepts FILE* | 75 | // Overloaded GetSize, accepts FILE* |
| 80 | u64 GetSize(FILE *f); | 76 | u64 GetSize(FILE* f); |
| 81 | 77 | ||
| 82 | // Returns true if successful, or path already exists. | 78 | // Returns true if successful, or path already exists. |
| 83 | bool CreateDir(const std::string &filename); | 79 | bool CreateDir(const std::string& filename); |
| 84 | 80 | ||
| 85 | // Creates the full path of fullPath returns true on success | 81 | // Creates the full path of fullPath returns true on success |
| 86 | bool CreateFullPath(const std::string &fullPath); | 82 | bool CreateFullPath(const std::string& fullPath); |
| 87 | 83 | ||
| 88 | // Deletes a given filename, return true on success | 84 | // Deletes a given filename, return true on success |
| 89 | // Doesn't supports deleting a directory | 85 | // Doesn't supports deleting a directory |
| 90 | bool Delete(const std::string &filename); | 86 | bool Delete(const std::string& filename); |
| 91 | 87 | ||
| 92 | // Deletes a directory filename, returns true on success | 88 | // Deletes a directory filename, returns true on success |
| 93 | bool DeleteDir(const std::string &filename); | 89 | bool DeleteDir(const std::string& filename); |
| 94 | 90 | ||
| 95 | // renames file srcFilename to destFilename, returns true on success | 91 | // renames file srcFilename to destFilename, returns true on success |
| 96 | bool Rename(const std::string &srcFilename, const std::string &destFilename); | 92 | bool Rename(const std::string& srcFilename, const std::string& destFilename); |
| 97 | 93 | ||
| 98 | // copies file srcFilename to destFilename, returns true on success | 94 | // copies file srcFilename to destFilename, returns true on success |
| 99 | bool Copy(const std::string &srcFilename, const std::string &destFilename); | 95 | bool Copy(const std::string& srcFilename, const std::string& destFilename); |
| 100 | 96 | ||
| 101 | // creates an empty file filename, returns true on success | 97 | // creates an empty file filename, returns true on success |
| 102 | bool CreateEmptyFile(const std::string &filename); | 98 | bool CreateEmptyFile(const std::string& filename); |
| 103 | 99 | ||
| 104 | /** | 100 | /** |
| 105 | * @param num_entries_out to be assigned by the callable with the number of iterated directory entries, never null | 101 | * @param num_entries_out to be assigned by the callable with the number of iterated directory |
| 102 | * entries, never null | ||
| 106 | * @param directory the path to the enclosing directory | 103 | * @param directory the path to the enclosing directory |
| 107 | * @param virtual_name the entry name, without any preceding directory info | 104 | * @param virtual_name the entry name, without any preceding directory info |
| 108 | * @return whether handling the entry succeeded | 105 | * @return whether handling the entry succeeded |
| 109 | */ | 106 | */ |
| 110 | using DirectoryEntryCallable = std::function<bool(unsigned* num_entries_out, | 107 | using DirectoryEntryCallable = std::function<bool( |
| 111 | const std::string& directory, | 108 | unsigned* num_entries_out, const std::string& directory, const std::string& virtual_name)>; |
| 112 | const std::string& virtual_name)>; | ||
| 113 | 109 | ||
| 114 | /** | 110 | /** |
| 115 | * Scans a directory, calling the callback for each file/directory contained within. | 111 | * Scans a directory, calling the callback for each file/directory contained within. |
| 116 | * If the callback returns failure, scanning halts and this function returns failure as well | 112 | * If the callback returns failure, scanning halts and this function returns failure as well |
| 117 | * @param num_entries_out assigned by the function with the number of iterated directory entries, can be null | 113 | * @param num_entries_out assigned by the function with the number of iterated directory entries, |
| 114 | * can be null | ||
| 118 | * @param directory the directory to scan | 115 | * @param directory the directory to scan |
| 119 | * @param callback The callback which will be called for each entry | 116 | * @param callback The callback which will be called for each entry |
| 120 | * @return whether scanning the directory succeeded | 117 | * @return whether scanning the directory succeeded |
| 121 | */ | 118 | */ |
| 122 | bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback); | 119 | bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory, |
| 120 | DirectoryEntryCallable callback); | ||
| 123 | 121 | ||
| 124 | /** | 122 | /** |
| 125 | * Scans the directory tree, storing the results. | 123 | * Scans the directory tree, storing the results. |
| @@ -128,23 +126,24 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo | |||
| 128 | * @param recursion Number of children directories to read before giving up. | 126 | * @param recursion Number of children directories to read before giving up. |
| 129 | * @return the total number of files/directories found | 127 | * @return the total number of files/directories found |
| 130 | */ | 128 | */ |
| 131 | unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion = 0); | 129 | unsigned ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry, |
| 130 | unsigned int recursion = 0); | ||
| 132 | 131 | ||
| 133 | // deletes the given directory and anything under it. Returns true on success. | 132 | // deletes the given directory and anything under it. Returns true on success. |
| 134 | bool DeleteDirRecursively(const std::string &directory, unsigned int recursion = 256); | 133 | bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256); |
| 135 | 134 | ||
| 136 | // Returns the current directory | 135 | // Returns the current directory |
| 137 | std::string GetCurrentDir(); | 136 | std::string GetCurrentDir(); |
| 138 | 137 | ||
| 139 | // Create directory and copy contents (does not overwrite existing files) | 138 | // Create directory and copy contents (does not overwrite existing files) |
| 140 | void CopyDir(const std::string &source_path, const std::string &dest_path); | 139 | void CopyDir(const std::string& source_path, const std::string& dest_path); |
| 141 | 140 | ||
| 142 | // Set the current directory to given directory | 141 | // Set the current directory to given directory |
| 143 | bool SetCurrentDir(const std::string &directory); | 142 | bool SetCurrentDir(const std::string& directory); |
| 144 | 143 | ||
| 145 | // Returns a pointer to a string with a Citra data dir in the user's home | 144 | // Returns a pointer to a string with a Citra data dir in the user's home |
| 146 | // directory. To be used in "multi-user" mode (that is, installed). | 145 | // directory. To be used in "multi-user" mode (that is, installed). |
| 147 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); | 146 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath = ""); |
| 148 | 147 | ||
| 149 | // Returns the path to where the sys file are | 148 | // Returns the path to where the sys file are |
| 150 | std::string GetSysDirectory(); | 149 | std::string GetSysDirectory(); |
| @@ -154,11 +153,11 @@ std::string GetBundleDirectory(); | |||
| 154 | #endif | 153 | #endif |
| 155 | 154 | ||
| 156 | #ifdef _WIN32 | 155 | #ifdef _WIN32 |
| 157 | std::string &GetExeDirectory(); | 156 | std::string& GetExeDirectory(); |
| 158 | #endif | 157 | #endif |
| 159 | 158 | ||
| 160 | size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename); | 159 | size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename); |
| 161 | size_t ReadFileToString(bool text_file, const char *filename, std::string &str); | 160 | size_t ReadFileToString(bool text_file, const char* filename, std::string& str); |
| 162 | 161 | ||
| 163 | /** | 162 | /** |
| 164 | * Splits the filename into 8.3 format | 163 | * Splits the filename into 8.3 format |
| @@ -173,8 +172,7 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam | |||
| 173 | // simple wrapper for cstdlib file functions to | 172 | // simple wrapper for cstdlib file functions to |
| 174 | // hopefully will make error checking easier | 173 | // hopefully will make error checking easier |
| 175 | // and make forgetting an fclose() harder | 174 | // and make forgetting an fclose() harder |
| 176 | class IOFile : public NonCopyable | 175 | class IOFile : public NonCopyable { |
| 177 | { | ||
| 178 | public: | 176 | public: |
| 179 | IOFile(); | 177 | IOFile(); |
| 180 | IOFile(const std::string& filename, const char openmode[]); | 178 | IOFile(const std::string& filename, const char openmode[]); |
| @@ -190,11 +188,12 @@ public: | |||
| 190 | bool Close(); | 188 | bool Close(); |
| 191 | 189 | ||
| 192 | template <typename T> | 190 | template <typename T> |
| 193 | size_t ReadArray(T* data, size_t length) | 191 | size_t ReadArray(T* data, size_t length) { |
| 194 | { | 192 | static_assert(std::is_standard_layout<T>(), |
| 195 | static_assert(std::is_standard_layout<T>(), "Given array does not consist of standard layout objects"); | 193 | "Given array does not consist of standard layout objects"); |
| 196 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) | 194 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) |
| 197 | static_assert(std::is_trivially_copyable<T>(), "Given array does not consist of trivially copyable objects"); | 195 | static_assert(std::is_trivially_copyable<T>(), |
| 196 | "Given array does not consist of trivially copyable objects"); | ||
| 198 | #endif | 197 | #endif |
| 199 | 198 | ||
| 200 | if (!IsOpen()) { | 199 | if (!IsOpen()) { |
| @@ -210,11 +209,12 @@ public: | |||
| 210 | } | 209 | } |
| 211 | 210 | ||
| 212 | template <typename T> | 211 | template <typename T> |
| 213 | size_t WriteArray(const T* data, size_t length) | 212 | size_t WriteArray(const T* data, size_t length) { |
| 214 | { | 213 | static_assert(std::is_standard_layout<T>(), |
| 215 | static_assert(std::is_standard_layout<T>(), "Given array does not consist of standard layout objects"); | 214 | "Given array does not consist of standard layout objects"); |
| 216 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) | 215 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) |
| 217 | static_assert(std::is_trivially_copyable<T>(), "Given array does not consist of trivially copyable objects"); | 216 | static_assert(std::is_trivially_copyable<T>(), |
| 217 | "Given array does not consist of trivially copyable objects"); | ||
| 218 | #endif | 218 | #endif |
| 219 | 219 | ||
| 220 | if (!IsOpen()) { | 220 | if (!IsOpen()) { |
| @@ -229,27 +229,31 @@ public: | |||
| 229 | return items_written; | 229 | return items_written; |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | size_t ReadBytes(void* data, size_t length) | 232 | size_t ReadBytes(void* data, size_t length) { |
| 233 | { | ||
| 234 | return ReadArray(reinterpret_cast<char*>(data), length); | 233 | return ReadArray(reinterpret_cast<char*>(data), length); |
| 235 | } | 234 | } |
| 236 | 235 | ||
| 237 | size_t WriteBytes(const void* data, size_t length) | 236 | size_t WriteBytes(const void* data, size_t length) { |
| 238 | { | ||
| 239 | return WriteArray(reinterpret_cast<const char*>(data), length); | 237 | return WriteArray(reinterpret_cast<const char*>(data), length); |
| 240 | } | 238 | } |
| 241 | 239 | ||
| 242 | template<typename T> | 240 | template <typename T> |
| 243 | size_t WriteObject(const T& object) { | 241 | size_t WriteObject(const T& object) { |
| 244 | static_assert(!std::is_pointer<T>::value, "Given object is a pointer"); | 242 | static_assert(!std::is_pointer<T>::value, "Given object is a pointer"); |
| 245 | return WriteArray(&object, 1); | 243 | return WriteArray(&object, 1); |
| 246 | } | 244 | } |
| 247 | 245 | ||
| 248 | bool IsOpen() const { return nullptr != m_file; } | 246 | bool IsOpen() const { |
| 247 | return nullptr != m_file; | ||
| 248 | } | ||
| 249 | 249 | ||
| 250 | // m_good is set to false when a read, write or other function fails | 250 | // m_good is set to false when a read, write or other function fails |
| 251 | bool IsGood() const { return m_good; } | 251 | bool IsGood() const { |
| 252 | explicit operator bool() const { return IsGood(); } | 252 | return m_good; |
| 253 | } | ||
| 254 | explicit operator bool() const { | ||
| 255 | return IsGood(); | ||
| 256 | } | ||
| 253 | 257 | ||
| 254 | bool Seek(s64 off, int origin); | 258 | bool Seek(s64 off, int origin); |
| 255 | u64 Tell() const; | 259 | u64 Tell() const; |
| @@ -258,19 +262,21 @@ public: | |||
| 258 | bool Flush(); | 262 | bool Flush(); |
| 259 | 263 | ||
| 260 | // clear error state | 264 | // clear error state |
| 261 | void Clear() { m_good = true; std::clearerr(m_file); } | 265 | void Clear() { |
| 266 | m_good = true; | ||
| 267 | std::clearerr(m_file); | ||
| 268 | } | ||
| 262 | 269 | ||
| 263 | private: | 270 | private: |
| 264 | std::FILE* m_file = nullptr; | 271 | std::FILE* m_file = nullptr; |
| 265 | bool m_good = true; | 272 | bool m_good = true; |
| 266 | }; | 273 | }; |
| 267 | 274 | ||
| 268 | } // namespace | 275 | } // namespace |
| 269 | 276 | ||
| 270 | // To deal with Windows being dumb at unicode: | 277 | // To deal with Windows being dumb at unicode: |
| 271 | template <typename T> | 278 | template <typename T> |
| 272 | void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) | 279 | void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) { |
| 273 | { | ||
| 274 | #ifdef _MSC_VER | 280 | #ifdef _MSC_VER |
| 275 | fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode); | 281 | fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode); |
| 276 | #else | 282 | #else |
diff --git a/src/common/hash.cpp b/src/common/hash.cpp index c49c2f60e..5aa5118eb 100644 --- a/src/common/hash.cpp +++ b/src/common/hash.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #if defined(_MSC_VER) | 5 | #if defined(_MSC_VER) |
| 6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
| 7 | #endif | 7 | #endif |
| 8 | |||
| 9 | #include "common_funcs.h" | 8 | #include "common_funcs.h" |
| 10 | #include "common_types.h" | 9 | #include "common_types.h" |
| 11 | #include "hash.h" | 10 | #include "hash.h" |
| @@ -36,7 +35,7 @@ static FORCE_INLINE u64 fmix64(u64 k) { | |||
| 36 | // platforms (MurmurHash3_x64_128). It was taken from: | 35 | // platforms (MurmurHash3_x64_128). It was taken from: |
| 37 | // https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp | 36 | // https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp |
| 38 | void MurmurHash3_128(const void* key, int len, u32 seed, void* out) { | 37 | void MurmurHash3_128(const void* key, int len, u32 seed, void* out) { |
| 39 | const u8 * data = (const u8*)key; | 38 | const u8* data = (const u8*)key; |
| 40 | const int nblocks = len / 16; | 39 | const int nblocks = len / 16; |
| 41 | 40 | ||
| 42 | u64 h1 = seed; | 41 | u64 h1 = seed; |
| @@ -47,52 +46,84 @@ void MurmurHash3_128(const void* key, int len, u32 seed, void* out) { | |||
| 47 | 46 | ||
| 48 | // Body | 47 | // Body |
| 49 | 48 | ||
| 50 | const u64 * blocks = (const u64 *)(data); | 49 | const u64* blocks = (const u64*)(data); |
| 51 | 50 | ||
| 52 | for (int i = 0; i < nblocks; i++) { | 51 | for (int i = 0; i < nblocks; i++) { |
| 53 | u64 k1 = getblock64(blocks,i*2+0); | 52 | u64 k1 = getblock64(blocks, i * 2 + 0); |
| 54 | u64 k2 = getblock64(blocks,i*2+1); | 53 | u64 k2 = getblock64(blocks, i * 2 + 1); |
| 55 | 54 | ||
| 56 | k1 *= c1; k1 = _rotl64(k1,31); k1 *= c2; h1 ^= k1; | 55 | k1 *= c1; |
| 57 | 56 | k1 = _rotl64(k1, 31); | |
| 58 | h1 = _rotl64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; | 57 | k1 *= c2; |
| 59 | 58 | h1 ^= k1; | |
| 60 | k2 *= c2; k2 = _rotl64(k2,33); k2 *= c1; h2 ^= k2; | 59 | |
| 61 | 60 | h1 = _rotl64(h1, 27); | |
| 62 | h2 = _rotl64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; | 61 | h1 += h2; |
| 62 | h1 = h1 * 5 + 0x52dce729; | ||
| 63 | |||
| 64 | k2 *= c2; | ||
| 65 | k2 = _rotl64(k2, 33); | ||
| 66 | k2 *= c1; | ||
| 67 | h2 ^= k2; | ||
| 68 | |||
| 69 | h2 = _rotl64(h2, 31); | ||
| 70 | h2 += h1; | ||
| 71 | h2 = h2 * 5 + 0x38495ab5; | ||
| 63 | } | 72 | } |
| 64 | 73 | ||
| 65 | // Tail | 74 | // Tail |
| 66 | 75 | ||
| 67 | const u8 * tail = (const u8*)(data + nblocks*16); | 76 | const u8* tail = (const u8*)(data + nblocks * 16); |
| 68 | 77 | ||
| 69 | u64 k1 = 0; | 78 | u64 k1 = 0; |
| 70 | u64 k2 = 0; | 79 | u64 k2 = 0; |
| 71 | 80 | ||
| 72 | switch (len & 15) { | 81 | switch (len & 15) { |
| 73 | case 15: k2 ^= ((u64)tail[14]) << 48; | 82 | case 15: |
| 74 | case 14: k2 ^= ((u64)tail[13]) << 40; | 83 | k2 ^= ((u64)tail[14]) << 48; |
| 75 | case 13: k2 ^= ((u64)tail[12]) << 32; | 84 | case 14: |
| 76 | case 12: k2 ^= ((u64)tail[11]) << 24; | 85 | k2 ^= ((u64)tail[13]) << 40; |
| 77 | case 11: k2 ^= ((u64)tail[10]) << 16; | 86 | case 13: |
| 78 | case 10: k2 ^= ((u64)tail[ 9]) << 8; | 87 | k2 ^= ((u64)tail[12]) << 32; |
| 79 | case 9: k2 ^= ((u64)tail[ 8]) << 0; | 88 | case 12: |
| 80 | k2 *= c2; k2 = _rotl64(k2,33); k2 *= c1; h2 ^= k2; | 89 | k2 ^= ((u64)tail[11]) << 24; |
| 81 | 90 | case 11: | |
| 82 | case 8: k1 ^= ((u64)tail[ 7]) << 56; | 91 | k2 ^= ((u64)tail[10]) << 16; |
| 83 | case 7: k1 ^= ((u64)tail[ 6]) << 48; | 92 | case 10: |
| 84 | case 6: k1 ^= ((u64)tail[ 5]) << 40; | 93 | k2 ^= ((u64)tail[9]) << 8; |
| 85 | case 5: k1 ^= ((u64)tail[ 4]) << 32; | 94 | case 9: |
| 86 | case 4: k1 ^= ((u64)tail[ 3]) << 24; | 95 | k2 ^= ((u64)tail[8]) << 0; |
| 87 | case 3: k1 ^= ((u64)tail[ 2]) << 16; | 96 | k2 *= c2; |
| 88 | case 2: k1 ^= ((u64)tail[ 1]) << 8; | 97 | k2 = _rotl64(k2, 33); |
| 89 | case 1: k1 ^= ((u64)tail[ 0]) << 0; | 98 | k2 *= c1; |
| 90 | k1 *= c1; k1 = _rotl64(k1,31); k1 *= c2; h1 ^= k1; | 99 | h2 ^= k2; |
| 100 | |||
| 101 | case 8: | ||
| 102 | k1 ^= ((u64)tail[7]) << 56; | ||
| 103 | case 7: | ||
| 104 | k1 ^= ((u64)tail[6]) << 48; | ||
| 105 | case 6: | ||
| 106 | k1 ^= ((u64)tail[5]) << 40; | ||
| 107 | case 5: | ||
| 108 | k1 ^= ((u64)tail[4]) << 32; | ||
| 109 | case 4: | ||
| 110 | k1 ^= ((u64)tail[3]) << 24; | ||
| 111 | case 3: | ||
| 112 | k1 ^= ((u64)tail[2]) << 16; | ||
| 113 | case 2: | ||
| 114 | k1 ^= ((u64)tail[1]) << 8; | ||
| 115 | case 1: | ||
| 116 | k1 ^= ((u64)tail[0]) << 0; | ||
| 117 | k1 *= c1; | ||
| 118 | k1 = _rotl64(k1, 31); | ||
| 119 | k1 *= c2; | ||
| 120 | h1 ^= k1; | ||
| 91 | }; | 121 | }; |
| 92 | 122 | ||
| 93 | // Finalization | 123 | // Finalization |
| 94 | 124 | ||
| 95 | h1 ^= len; h2 ^= len; | 125 | h1 ^= len; |
| 126 | h2 ^= len; | ||
| 96 | 127 | ||
| 97 | h1 += h2; | 128 | h1 += h2; |
| 98 | h2 += h1; | 129 | h2 += h1; |
diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp index ad311d66b..79b3fcb18 100644 --- a/src/common/key_map.cpp +++ b/src/common/key_map.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <map> | 5 | #include <map> |
| 6 | |||
| 7 | #include "common/emu_window.h" | 6 | #include "common/emu_window.h" |
| 8 | #include "common/key_map.h" | 7 | #include "common/key_map.h" |
| 9 | 8 | ||
| @@ -13,11 +12,25 @@ namespace KeyMap { | |||
| 13 | // and map it directly to EmuWindow::ButtonPressed. | 12 | // and map it directly to EmuWindow::ButtonPressed. |
| 14 | // It should go the analog input way like circle pad does. | 13 | // It should go the analog input way like circle pad does. |
| 15 | const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{ | 14 | const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{ |
| 16 | Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y, | 15 | Service::HID::PAD_A, |
| 17 | Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR, | 16 | Service::HID::PAD_B, |
| 18 | Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE, | 17 | Service::HID::PAD_X, |
| 19 | Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT, | 18 | Service::HID::PAD_Y, |
| 20 | Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT, | 19 | Service::HID::PAD_L, |
| 20 | Service::HID::PAD_R, | ||
| 21 | Service::HID::PAD_ZL, | ||
| 22 | Service::HID::PAD_ZR, | ||
| 23 | Service::HID::PAD_START, | ||
| 24 | Service::HID::PAD_SELECT, | ||
| 25 | Service::HID::PAD_NONE, | ||
| 26 | Service::HID::PAD_UP, | ||
| 27 | Service::HID::PAD_DOWN, | ||
| 28 | Service::HID::PAD_LEFT, | ||
| 29 | Service::HID::PAD_RIGHT, | ||
| 30 | Service::HID::PAD_C_UP, | ||
| 31 | Service::HID::PAD_C_DOWN, | ||
| 32 | Service::HID::PAD_C_LEFT, | ||
| 33 | Service::HID::PAD_C_RIGHT, | ||
| 21 | 34 | ||
| 22 | IndirectTarget::CirclePadUp, | 35 | IndirectTarget::CirclePadUp, |
| 23 | IndirectTarget::CirclePadDown, | 36 | IndirectTarget::CirclePadDown, |
| @@ -49,7 +62,8 @@ static void UpdateCirclePad(EmuWindow& emu_window) { | |||
| 49 | --y; | 62 | --y; |
| 50 | 63 | ||
| 51 | float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0; | 64 | float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0; |
| 52 | emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0 : SQRT_HALF), y * modifier * (x == 0 ? 1.0 : SQRT_HALF)); | 65 | emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0 : SQRT_HALF), |
| 66 | y * modifier * (x == 0 ? 1.0 : SQRT_HALF)); | ||
| 53 | } | 67 | } |
| 54 | 68 | ||
| 55 | int NewDeviceId() { | 69 | int NewDeviceId() { |
| @@ -103,7 +117,7 @@ void PressKey(EmuWindow& emu_window, HostDeviceKey key) { | |||
| 103 | } | 117 | } |
| 104 | } | 118 | } |
| 105 | 119 | ||
| 106 | void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) { | 120 | void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key) { |
| 107 | auto target = key_map.find(key); | 121 | auto target = key_map.find(key); |
| 108 | if (target == key_map.end()) | 122 | if (target == key_map.end()) |
| 109 | return; | 123 | return; |
| @@ -135,5 +149,4 @@ void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) { | |||
| 135 | } | 149 | } |
| 136 | } | 150 | } |
| 137 | } | 151 | } |
| 138 | |||
| 139 | } | 152 | } |
diff --git a/src/common/key_map.h b/src/common/key_map.h index b62f017c6..040794578 100644 --- a/src/common/key_map.h +++ b/src/common/key_map.h | |||
| @@ -55,14 +55,12 @@ struct HostDeviceKey { | |||
| 55 | int key_code; | 55 | int key_code; |
| 56 | int device_id; ///< Uniquely identifies a host device | 56 | int device_id; ///< Uniquely identifies a host device |
| 57 | 57 | ||
| 58 | bool operator<(const HostDeviceKey &other) const { | 58 | bool operator<(const HostDeviceKey& other) const { |
| 59 | return std::tie(key_code, device_id) < | 59 | return std::tie(key_code, device_id) < std::tie(other.key_code, other.device_id); |
| 60 | std::tie(other.key_code, other.device_id); | ||
| 61 | } | 60 | } |
| 62 | 61 | ||
| 63 | bool operator==(const HostDeviceKey &other) const { | 62 | bool operator==(const HostDeviceKey& other) const { |
| 64 | return std::tie(key_code, device_id) == | 63 | return std::tie(key_code, device_id) == std::tie(other.key_code, other.device_id); |
| 65 | std::tie(other.key_code, other.device_id); | ||
| 66 | } | 64 | } |
| 67 | }; | 65 | }; |
| 68 | 66 | ||
| @@ -92,5 +90,4 @@ void PressKey(EmuWindow& emu_window, HostDeviceKey key); | |||
| 92 | * Maps a key release action and call the corresponding function in EmuWindow | 90 | * Maps a key release action and call the corresponding function in EmuWindow |
| 93 | */ | 91 | */ |
| 94 | void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key); | 92 | void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key); |
| 95 | |||
| 96 | } | 93 | } |
diff --git a/src/common/linear_disk_cache.h b/src/common/linear_disk_cache.h index 48529cf42..94c695163 100644 --- a/src/common/linear_disk_cache.h +++ b/src/common/linear_disk_cache.h | |||
| @@ -4,31 +4,30 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include <fstream> | 7 | #include <fstream> |
| 8 | #include "common/common_types.h" | ||
| 9 | 9 | ||
| 10 | // defined in Version.cpp | 10 | // defined in Version.cpp |
| 11 | extern const char *scm_rev_git_str; | 11 | extern const char* scm_rev_git_str; |
| 12 | 12 | ||
| 13 | // On disk format: | 13 | // On disk format: |
| 14 | //header{ | 14 | // header{ |
| 15 | // u32 'DCAC'; | 15 | // u32 'DCAC'; |
| 16 | // u32 version; // svn_rev | 16 | // u32 version; // svn_rev |
| 17 | // u16 sizeof(key_type); | 17 | // u16 sizeof(key_type); |
| 18 | // u16 sizeof(value_type); | 18 | // u16 sizeof(value_type); |
| 19 | //} | 19 | //} |
| 20 | 20 | ||
| 21 | //key_value_pair{ | 21 | // key_value_pair{ |
| 22 | // u32 value_size; | 22 | // u32 value_size; |
| 23 | // key_type key; | 23 | // key_type key; |
| 24 | // value_type[value_size] value; | 24 | // value_type[value_size] value; |
| 25 | //} | 25 | //} |
| 26 | 26 | ||
| 27 | template <typename K, typename V> | 27 | template <typename K, typename V> |
| 28 | class LinearDiskCacheReader | 28 | class LinearDiskCacheReader { |
| 29 | { | ||
| 30 | public: | 29 | public: |
| 31 | virtual void Read(const K &key, const V *value, u32 value_size) = 0; | 30 | virtual void Read(const K& key, const V* value, u32 value_size) = 0; |
| 32 | }; | 31 | }; |
| 33 | 32 | ||
| 34 | // Dead simple unsorted key-value store with append functionality. | 33 | // Dead simple unsorted key-value store with append functionality. |
| @@ -44,12 +43,10 @@ public: | |||
| 44 | // K : the key type | 43 | // K : the key type |
| 45 | // V : value array type | 44 | // V : value array type |
| 46 | template <typename K, typename V> | 45 | template <typename K, typename V> |
| 47 | class LinearDiskCache | 46 | class LinearDiskCache { |
| 48 | { | ||
| 49 | public: | 47 | public: |
| 50 | // return number of read entries | 48 | // return number of read entries |
| 51 | u32 OpenAndRead(const char *filename, LinearDiskCacheReader<K, V> &reader) | 49 | u32 OpenAndRead(const char* filename, LinearDiskCacheReader<K, V>& reader) { |
| 52 | { | ||
| 53 | using std::ios_base; | 50 | using std::ios_base; |
| 54 | 51 | ||
| 55 | // close any currently opened file | 52 | // close any currently opened file |
| @@ -65,20 +62,19 @@ public: | |||
| 65 | std::fstream::pos_type start_pos = m_file.tellg(); | 62 | std::fstream::pos_type start_pos = m_file.tellg(); |
| 66 | std::streamoff file_size = end_pos - start_pos; | 63 | std::streamoff file_size = end_pos - start_pos; |
| 67 | 64 | ||
| 68 | if (m_file.is_open() && ValidateHeader()) | 65 | if (m_file.is_open() && ValidateHeader()) { |
| 69 | { | ||
| 70 | // good header, read some key/value pairs | 66 | // good header, read some key/value pairs |
| 71 | K key; | 67 | K key; |
| 72 | 68 | ||
| 73 | V *value = nullptr; | 69 | V* value = nullptr; |
| 74 | u32 value_size; | 70 | u32 value_size; |
| 75 | u32 entry_number; | 71 | u32 entry_number; |
| 76 | 72 | ||
| 77 | std::fstream::pos_type last_pos = m_file.tellg(); | 73 | std::fstream::pos_type last_pos = m_file.tellg(); |
| 78 | 74 | ||
| 79 | while (Read(&value_size)) | 75 | while (Read(&value_size)) { |
| 80 | { | 76 | std::streamoff next_extent = |
| 81 | std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size; | 77 | (last_pos - start_pos) + sizeof(value_size) + value_size; |
| 82 | if (next_extent > file_size) | 78 | if (next_extent > file_size) |
| 83 | break; | 79 | break; |
| 84 | 80 | ||
| @@ -86,15 +82,10 @@ public: | |||
| 86 | value = new V[value_size]; | 82 | value = new V[value_size]; |
| 87 | 83 | ||
| 88 | // read key/value and pass to reader | 84 | // read key/value and pass to reader |
| 89 | if (Read(&key) && | 85 | if (Read(&key) && Read(value, value_size) && Read(&entry_number) && |
| 90 | Read(value, value_size) && | 86 | entry_number == m_num_entries + 1) { |
| 91 | Read(&entry_number) && | ||
| 92 | entry_number == m_num_entries+1) | ||
| 93 | { | ||
| 94 | reader.Read(key, value, value_size); | 87 | reader.Read(key, value, value_size); |
| 95 | } | 88 | } else { |
| 96 | else | ||
| 97 | { | ||
| 98 | break; | 89 | break; |
| 99 | } | 90 | } |
| 100 | 91 | ||
| @@ -116,13 +107,11 @@ public: | |||
| 116 | return 0; | 107 | return 0; |
| 117 | } | 108 | } |
| 118 | 109 | ||
| 119 | void Sync() | 110 | void Sync() { |
| 120 | { | ||
| 121 | m_file.flush(); | 111 | m_file.flush(); |
| 122 | } | 112 | } |
| 123 | 113 | ||
| 124 | void Close() | 114 | void Close() { |
| 125 | { | ||
| 126 | if (m_file.is_open()) | 115 | if (m_file.is_open()) |
| 127 | m_file.close(); | 116 | m_file.close(); |
| 128 | // clear any error flags | 117 | // clear any error flags |
| @@ -130,9 +119,9 @@ public: | |||
| 130 | } | 119 | } |
| 131 | 120 | ||
| 132 | // Appends a key-value pair to the store. | 121 | // Appends a key-value pair to the store. |
| 133 | void Append(const K &key, const V *value, u32 value_size) | 122 | void Append(const K& key, const V* value, u32 value_size) { |
| 134 | { | 123 | // TODO: Should do a check that we don't already have "key"? (I think each caller does that |
| 135 | // TODO: Should do a check that we don't already have "key"? (I think each caller does that already.) | 124 | // already.) |
| 136 | Write(&value_size); | 125 | Write(&value_size); |
| 137 | Write(&key); | 126 | Write(&key); |
| 138 | Write(value, value_size); | 127 | Write(value, value_size); |
| @@ -141,38 +130,29 @@ public: | |||
| 141 | } | 130 | } |
| 142 | 131 | ||
| 143 | private: | 132 | private: |
| 144 | void WriteHeader() | 133 | void WriteHeader() { |
| 145 | { | ||
| 146 | Write(&m_header); | 134 | Write(&m_header); |
| 147 | } | 135 | } |
| 148 | 136 | ||
| 149 | bool ValidateHeader() | 137 | bool ValidateHeader() { |
| 150 | { | ||
| 151 | char file_header[sizeof(Header)]; | 138 | char file_header[sizeof(Header)]; |
| 152 | 139 | ||
| 153 | return (Read(file_header, sizeof(Header)) | 140 | return (Read(file_header, sizeof(Header)) && |
| 154 | && !memcmp((const char*)&m_header, file_header, sizeof(Header))); | 141 | !memcmp((const char*)&m_header, file_header, sizeof(Header))); |
| 155 | } | 142 | } |
| 156 | 143 | ||
| 157 | template <typename D> | 144 | template <typename D> |
| 158 | bool Write(const D *data, u32 count = 1) | 145 | bool Write(const D* data, u32 count = 1) { |
| 159 | { | ||
| 160 | return m_file.write((const char*)data, count * sizeof(D)).good(); | 146 | return m_file.write((const char*)data, count * sizeof(D)).good(); |
| 161 | } | 147 | } |
| 162 | 148 | ||
| 163 | template <typename D> | 149 | template <typename D> |
| 164 | bool Read(const D *data, u32 count = 1) | 150 | bool Read(const D* data, u32 count = 1) { |
| 165 | { | ||
| 166 | return m_file.read((char*)data, count * sizeof(D)).good(); | 151 | return m_file.read((char*)data, count * sizeof(D)).good(); |
| 167 | } | 152 | } |
| 168 | 153 | ||
| 169 | struct Header | 154 | struct Header { |
| 170 | { | 155 | Header() : id(*(u32*)"DCAC"), key_t_size(sizeof(K)), value_t_size(sizeof(V)) { |
| 171 | Header() | ||
| 172 | : id(*(u32*)"DCAC") | ||
| 173 | , key_t_size(sizeof(K)) | ||
| 174 | , value_t_size(sizeof(V)) | ||
| 175 | { | ||
| 176 | memcpy(ver, scm_rev_git_str, 40); | 156 | memcpy(ver, scm_rev_git_str, 40); |
| 177 | } | 157 | } |
| 178 | 158 | ||
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 0b2fabec9..9a13a9e90 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <cstdio> | 7 | #include <cstdio> |
| 8 | |||
| 9 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 10 | #include "common/common_funcs.h" // snprintf compatibility define | 9 | #include "common/common_funcs.h" // snprintf compatibility define |
| 11 | #include "common/logging/backend.h" | 10 | #include "common/logging/backend.h" |
| @@ -16,73 +15,79 @@ | |||
| 16 | namespace Log { | 15 | namespace Log { |
| 17 | 16 | ||
| 18 | /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. | 17 | /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. |
| 19 | #define ALL_LOG_CLASSES() \ | 18 | #define ALL_LOG_CLASSES() \ |
| 20 | CLS(Log) \ | 19 | CLS(Log) \ |
| 21 | CLS(Common) \ | 20 | CLS(Common) \ |
| 22 | SUB(Common, Filesystem) \ | 21 | SUB(Common, Filesystem) \ |
| 23 | SUB(Common, Memory) \ | 22 | SUB(Common, Memory) \ |
| 24 | CLS(Core) \ | 23 | CLS(Core) \ |
| 25 | SUB(Core, ARM11) \ | 24 | SUB(Core, ARM11) \ |
| 26 | SUB(Core, Timing) \ | 25 | SUB(Core, Timing) \ |
| 27 | CLS(Config) \ | 26 | CLS(Config) \ |
| 28 | CLS(Debug) \ | 27 | CLS(Debug) \ |
| 29 | SUB(Debug, Emulated) \ | 28 | SUB(Debug, Emulated) \ |
| 30 | SUB(Debug, GPU) \ | 29 | SUB(Debug, GPU) \ |
| 31 | SUB(Debug, Breakpoint) \ | 30 | SUB(Debug, Breakpoint) \ |
| 32 | SUB(Debug, GDBStub) \ | 31 | SUB(Debug, GDBStub) \ |
| 33 | CLS(Kernel) \ | 32 | CLS(Kernel) \ |
| 34 | SUB(Kernel, SVC) \ | 33 | SUB(Kernel, SVC) \ |
| 35 | CLS(Service) \ | 34 | CLS(Service) \ |
| 36 | SUB(Service, SRV) \ | 35 | SUB(Service, SRV) \ |
| 37 | SUB(Service, FRD) \ | 36 | SUB(Service, FRD) \ |
| 38 | SUB(Service, FS) \ | 37 | SUB(Service, FS) \ |
| 39 | SUB(Service, ERR) \ | 38 | SUB(Service, ERR) \ |
| 40 | SUB(Service, APT) \ | 39 | SUB(Service, APT) \ |
| 41 | SUB(Service, GSP) \ | 40 | SUB(Service, GSP) \ |
| 42 | SUB(Service, AC) \ | 41 | SUB(Service, AC) \ |
| 43 | SUB(Service, AM) \ | 42 | SUB(Service, AM) \ |
| 44 | SUB(Service, PTM) \ | 43 | SUB(Service, PTM) \ |
| 45 | SUB(Service, LDR) \ | 44 | SUB(Service, LDR) \ |
| 46 | SUB(Service, NDM) \ | 45 | SUB(Service, NDM) \ |
| 47 | SUB(Service, NIM) \ | 46 | SUB(Service, NIM) \ |
| 48 | SUB(Service, NWM) \ | 47 | SUB(Service, NWM) \ |
| 49 | SUB(Service, CAM) \ | 48 | SUB(Service, CAM) \ |
| 50 | SUB(Service, CECD) \ | 49 | SUB(Service, CECD) \ |
| 51 | SUB(Service, CFG) \ | 50 | SUB(Service, CFG) \ |
| 52 | SUB(Service, DSP) \ | 51 | SUB(Service, DSP) \ |
| 53 | SUB(Service, DLP) \ | 52 | SUB(Service, DLP) \ |
| 54 | SUB(Service, HID) \ | 53 | SUB(Service, HID) \ |
| 55 | SUB(Service, SOC) \ | 54 | SUB(Service, SOC) \ |
| 56 | SUB(Service, IR) \ | 55 | SUB(Service, IR) \ |
| 57 | SUB(Service, Y2R) \ | 56 | SUB(Service, Y2R) \ |
| 58 | CLS(HW) \ | 57 | CLS(HW) \ |
| 59 | SUB(HW, Memory) \ | 58 | SUB(HW, Memory) \ |
| 60 | SUB(HW, LCD) \ | 59 | SUB(HW, LCD) \ |
| 61 | SUB(HW, GPU) \ | 60 | SUB(HW, GPU) \ |
| 62 | CLS(Frontend) \ | 61 | CLS(Frontend) \ |
| 63 | CLS(Render) \ | 62 | CLS(Render) \ |
| 64 | SUB(Render, Software) \ | 63 | SUB(Render, Software) \ |
| 65 | SUB(Render, OpenGL) \ | 64 | SUB(Render, OpenGL) \ |
| 66 | CLS(Audio) \ | 65 | CLS(Audio) \ |
| 67 | SUB(Audio, DSP) \ | 66 | SUB(Audio, DSP) \ |
| 68 | SUB(Audio, Sink) \ | 67 | SUB(Audio, Sink) \ |
| 69 | CLS(Loader) | 68 | CLS(Loader) |
| 70 | 69 | ||
| 71 | // GetClassName is a macro defined by Windows.h, grrr... | 70 | // GetClassName is a macro defined by Windows.h, grrr... |
| 72 | const char* GetLogClassName(Class log_class) { | 71 | const char* GetLogClassName(Class log_class) { |
| 73 | switch (log_class) { | 72 | switch (log_class) { |
| 74 | #define CLS(x) case Class::x: return #x; | 73 | #define CLS(x) \ |
| 75 | #define SUB(x, y) case Class::x##_##y: return #x "." #y; | 74 | case Class::x: \ |
| 75 | return #x; | ||
| 76 | #define SUB(x, y) \ | ||
| 77 | case Class::x##_##y: \ | ||
| 78 | return #x "." #y; | ||
| 76 | ALL_LOG_CLASSES() | 79 | ALL_LOG_CLASSES() |
| 77 | #undef CLS | 80 | #undef CLS |
| 78 | #undef SUB | 81 | #undef SUB |
| 79 | case Class::Count: | 82 | case Class::Count: |
| 80 | UNREACHABLE(); | 83 | UNREACHABLE(); |
| 81 | } | 84 | } |
| 82 | } | 85 | } |
| 83 | 86 | ||
| 84 | const char* GetLevelName(Level log_level) { | 87 | const char* GetLevelName(Level log_level) { |
| 85 | #define LVL(x) case Level::x: return #x | 88 | #define LVL(x) \ |
| 89 | case Level::x: \ | ||
| 90 | return #x | ||
| 86 | switch (log_level) { | 91 | switch (log_level) { |
| 87 | LVL(Trace); | 92 | LVL(Trace); |
| 88 | LVL(Debug); | 93 | LVL(Debug); |
| @@ -90,15 +95,14 @@ const char* GetLevelName(Level log_level) { | |||
| 90 | LVL(Warning); | 95 | LVL(Warning); |
| 91 | LVL(Error); | 96 | LVL(Error); |
| 92 | LVL(Critical); | 97 | LVL(Critical); |
| 93 | case Level::Count: | 98 | case Level::Count: |
| 94 | UNREACHABLE(); | 99 | UNREACHABLE(); |
| 95 | } | 100 | } |
| 96 | #undef LVL | 101 | #undef LVL |
| 97 | } | 102 | } |
| 98 | 103 | ||
| 99 | Entry CreateEntry(Class log_class, Level log_level, | 104 | Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, |
| 100 | const char* filename, unsigned int line_nr, const char* function, | 105 | const char* function, const char* format, va_list args) { |
| 101 | const char* format, va_list args) { | ||
| 102 | using std::chrono::steady_clock; | 106 | using std::chrono::steady_clock; |
| 103 | using std::chrono::duration_cast; | 107 | using std::chrono::duration_cast; |
| 104 | 108 | ||
| @@ -111,7 +115,8 @@ Entry CreateEntry(Class log_class, Level log_level, | |||
| 111 | entry.log_class = log_class; | 115 | entry.log_class = log_class; |
| 112 | entry.log_level = log_level; | 116 | entry.log_level = log_level; |
| 113 | 117 | ||
| 114 | snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function, line_nr); | 118 | snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function, |
| 119 | line_nr); | ||
| 115 | entry.location = std::string(formatting_buffer.data()); | 120 | entry.location = std::string(formatting_buffer.data()); |
| 116 | 121 | ||
| 117 | vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args); | 122 | vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args); |
| @@ -126,19 +131,16 @@ void SetFilter(Filter* new_filter) { | |||
| 126 | filter = new_filter; | 131 | filter = new_filter; |
| 127 | } | 132 | } |
| 128 | 133 | ||
| 129 | void LogMessage(Class log_class, Level log_level, | 134 | void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr, |
| 130 | const char* filename, unsigned int line_nr, const char* function, | 135 | const char* function, const char* format, ...) { |
| 131 | const char* format, ...) { | ||
| 132 | if (filter != nullptr && !filter->CheckMessage(log_class, log_level)) | 136 | if (filter != nullptr && !filter->CheckMessage(log_class, log_level)) |
| 133 | return; | 137 | return; |
| 134 | 138 | ||
| 135 | va_list args; | 139 | va_list args; |
| 136 | va_start(args, format); | 140 | va_start(args, format); |
| 137 | Entry entry = CreateEntry(log_class, log_level, | 141 | Entry entry = CreateEntry(log_class, log_level, filename, line_nr, function, format, args); |
| 138 | filename, line_nr, function, format, args); | ||
| 139 | va_end(args); | 142 | va_end(args); |
| 140 | 143 | ||
| 141 | PrintColoredMessage(entry); | 144 | PrintColoredMessage(entry); |
| 142 | } | 145 | } |
| 143 | |||
| 144 | } | 146 | } |
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index 795d42ebd..c4fe2acbf 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include <cstdarg> | 8 | #include <cstdarg> |
| 9 | #include <string> | 9 | #include <string> |
| 10 | #include <utility> | 10 | #include <utility> |
| 11 | |||
| 12 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 13 | 12 | ||
| 14 | namespace Log { | 13 | namespace Log { |
| @@ -44,10 +43,8 @@ const char* GetLogClassName(Class log_class); | |||
| 44 | const char* GetLevelName(Level log_level); | 43 | const char* GetLevelName(Level log_level); |
| 45 | 44 | ||
| 46 | /// Creates a log entry by formatting the given source location, and message. | 45 | /// Creates a log entry by formatting the given source location, and message. |
| 47 | Entry CreateEntry(Class log_class, Level log_level, | 46 | Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, |
| 48 | const char* filename, unsigned int line_nr, const char* function, | 47 | const char* function, const char* format, va_list args); |
| 49 | const char* format, va_list args); | ||
| 50 | 48 | ||
| 51 | void SetFilter(Filter* filter); | 49 | void SetFilter(Filter* filter); |
| 52 | |||
| 53 | } | 50 | } |
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 55cc8888a..12e5bb45d 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp | |||
| @@ -3,9 +3,8 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | |||
| 7 | #include "common/logging/filter.h" | ||
| 8 | #include "common/logging/backend.h" | 6 | #include "common/logging/backend.h" |
| 7 | #include "common/logging/filter.h" | ||
| 9 | #include "common/string_util.h" | 8 | #include "common/string_util.h" |
| 10 | 9 | ||
| 11 | namespace Log { | 10 | namespace Log { |
| @@ -63,11 +62,11 @@ static Class GetClassByName(const It begin, const It end) { | |||
| 63 | } | 62 | } |
| 64 | 63 | ||
| 65 | bool Filter::ParseFilterRule(const std::string::const_iterator begin, | 64 | bool Filter::ParseFilterRule(const std::string::const_iterator begin, |
| 66 | const std::string::const_iterator end) { | 65 | const std::string::const_iterator end) { |
| 67 | auto level_separator = std::find(begin, end, ':'); | 66 | auto level_separator = std::find(begin, end, ':'); |
| 68 | if (level_separator == end) { | 67 | if (level_separator == end) { |
| 69 | LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s", | 68 | LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s", |
| 70 | std::string(begin, end).c_str()); | 69 | std::string(begin, end).c_str()); |
| 71 | return false; | 70 | return false; |
| 72 | } | 71 | } |
| 73 | 72 | ||
| @@ -95,5 +94,4 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin, | |||
| 95 | bool Filter::CheckMessage(Class log_class, Level level) const { | 94 | bool Filter::CheckMessage(Class log_class, Level level) const { |
| 96 | return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]); | 95 | return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]); |
| 97 | } | 96 | } |
| 98 | |||
| 99 | } | 97 | } |
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h index a2b4eca43..b51df61de 100644 --- a/src/common/logging/filter.h +++ b/src/common/logging/filter.h | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <string> | 9 | #include <string> |
| 10 | |||
| 11 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 12 | 11 | ||
| 13 | namespace Log { | 12 | namespace Log { |
| @@ -42,7 +41,8 @@ public: | |||
| 42 | * - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace. | 41 | * - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace. |
| 43 | */ | 42 | */ |
| 44 | void ParseFilterString(const std::string& filter_str); | 43 | void ParseFilterString(const std::string& filter_str); |
| 45 | bool ParseFilterRule(const std::string::const_iterator start, const std::string::const_iterator end); | 44 | bool ParseFilterRule(const std::string::const_iterator start, |
| 45 | const std::string::const_iterator end); | ||
| 46 | 46 | ||
| 47 | /// Matches class/level combination against the filter, returning true if it passed. | 47 | /// Matches class/level combination against the filter, returning true if it passed. |
| 48 | bool CheckMessage(Class log_class, Level level) const; | 48 | bool CheckMessage(Class log_class, Level level) const; |
| @@ -50,5 +50,4 @@ public: | |||
| 50 | private: | 50 | private: |
| 51 | std::array<Level, (size_t)Class::Count> class_levels; | 51 | std::array<Level, (size_t)Class::Count> class_levels; |
| 52 | }; | 52 | }; |
| 53 | |||
| 54 | } | 53 | } |
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index c6910b1c7..a4b4750de 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -28,71 +28,73 @@ typedef u8 ClassType; | |||
| 28 | /** | 28 | /** |
| 29 | * Specifies the sub-system that generated the log message. | 29 | * Specifies the sub-system that generated the log message. |
| 30 | * | 30 | * |
| 31 | * @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in backend.cpp. | 31 | * @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in |
| 32 | * backend.cpp. | ||
| 32 | */ | 33 | */ |
| 33 | enum class Class : ClassType { | 34 | enum class Class : ClassType { |
| 34 | Log, ///< Messages about the log system itself | 35 | Log, ///< Messages about the log system itself |
| 35 | Common, ///< Library routines | 36 | Common, ///< Library routines |
| 36 | Common_Filesystem, ///< Filesystem interface library | 37 | Common_Filesystem, ///< Filesystem interface library |
| 37 | Common_Memory, ///< Memory mapping and management functions | 38 | Common_Memory, ///< Memory mapping and management functions |
| 38 | Core, ///< LLE emulation core | 39 | Core, ///< LLE emulation core |
| 39 | Core_ARM11, ///< ARM11 CPU core | 40 | Core_ARM11, ///< ARM11 CPU core |
| 40 | Core_Timing, ///< CoreTiming functions | 41 | Core_Timing, ///< CoreTiming functions |
| 41 | Config, ///< Emulator configuration (including commandline) | 42 | Config, ///< Emulator configuration (including commandline) |
| 42 | Debug, ///< Debugging tools | 43 | Debug, ///< Debugging tools |
| 43 | Debug_Emulated, ///< Debug messages from the emulated programs | 44 | Debug_Emulated, ///< Debug messages from the emulated programs |
| 44 | Debug_GPU, ///< GPU debugging tools | 45 | Debug_GPU, ///< GPU debugging tools |
| 45 | Debug_Breakpoint, ///< Logging breakpoints and watchpoints | 46 | Debug_Breakpoint, ///< Logging breakpoints and watchpoints |
| 46 | Debug_GDBStub, ///< GDB Stub | 47 | Debug_GDBStub, ///< GDB Stub |
| 47 | Kernel, ///< The HLE implementation of the CTR kernel | 48 | Kernel, ///< The HLE implementation of the CTR kernel |
| 48 | Kernel_SVC, ///< Kernel system calls | 49 | Kernel_SVC, ///< Kernel system calls |
| 49 | Service, ///< HLE implementation of system services. Each major service | 50 | Service, ///< HLE implementation of system services. Each major service |
| 50 | /// should have its own subclass. | 51 | /// should have its own subclass. |
| 51 | Service_SRV, ///< The SRV (Service Directory) implementation | 52 | Service_SRV, ///< The SRV (Service Directory) implementation |
| 52 | Service_FRD, ///< The FRD (Friends) service | 53 | Service_FRD, ///< The FRD (Friends) service |
| 53 | Service_FS, ///< The FS (Filesystem) service implementation | 54 | Service_FS, ///< The FS (Filesystem) service implementation |
| 54 | Service_ERR, ///< The ERR (Error) port implementation | 55 | Service_ERR, ///< The ERR (Error) port implementation |
| 55 | Service_APT, ///< The APT (Applets) service | 56 | Service_APT, ///< The APT (Applets) service |
| 56 | Service_GSP, ///< The GSP (GPU control) service | 57 | Service_GSP, ///< The GSP (GPU control) service |
| 57 | Service_AC, ///< The AC (WiFi status) service | 58 | Service_AC, ///< The AC (WiFi status) service |
| 58 | Service_AM, ///< The AM (Application manager) service | 59 | Service_AM, ///< The AM (Application manager) service |
| 59 | Service_PTM, ///< The PTM (Power status & misc.) service | 60 | Service_PTM, ///< The PTM (Power status & misc.) service |
| 60 | Service_LDR, ///< The LDR (3ds dll loader) service | 61 | Service_LDR, ///< The LDR (3ds dll loader) service |
| 61 | Service_NDM, ///< The NDM (Network daemon manager) service | 62 | Service_NDM, ///< The NDM (Network daemon manager) service |
| 62 | Service_NIM, ///< The NIM (Network interface manager) service | 63 | Service_NIM, ///< The NIM (Network interface manager) service |
| 63 | Service_NWM, ///< The NWM (Network wlan manager) service | 64 | Service_NWM, ///< The NWM (Network wlan manager) service |
| 64 | Service_CAM, ///< The CAM (Camera) service | 65 | Service_CAM, ///< The CAM (Camera) service |
| 65 | Service_CECD, ///< The CECD (StreetPass) service | 66 | Service_CECD, ///< The CECD (StreetPass) service |
| 66 | Service_CFG, ///< The CFG (Configuration) service | 67 | Service_CFG, ///< The CFG (Configuration) service |
| 67 | Service_DSP, ///< The DSP (DSP control) service | 68 | Service_DSP, ///< The DSP (DSP control) service |
| 68 | Service_DLP, ///< The DLP (Download Play) service | 69 | Service_DLP, ///< The DLP (Download Play) service |
| 69 | Service_HID, ///< The HID (Human interface device) service | 70 | Service_HID, ///< The HID (Human interface device) service |
| 70 | Service_SOC, ///< The SOC (Socket) service | 71 | Service_SOC, ///< The SOC (Socket) service |
| 71 | Service_IR, ///< The IR service | 72 | Service_IR, ///< The IR service |
| 72 | Service_Y2R, ///< The Y2R (YUV to RGB conversion) service | 73 | Service_Y2R, ///< The Y2R (YUV to RGB conversion) service |
| 73 | HW, ///< Low-level hardware emulation | 74 | HW, ///< Low-level hardware emulation |
| 74 | HW_Memory, ///< Memory-map and address translation | 75 | HW_Memory, ///< Memory-map and address translation |
| 75 | HW_LCD, ///< LCD register emulation | 76 | HW_LCD, ///< LCD register emulation |
| 76 | HW_GPU, ///< GPU control emulation | 77 | HW_GPU, ///< GPU control emulation |
| 77 | Frontend, ///< Emulator UI | 78 | Frontend, ///< Emulator UI |
| 78 | Render, ///< Emulator video output and hardware acceleration | 79 | Render, ///< Emulator video output and hardware acceleration |
| 79 | Render_Software, ///< Software renderer backend | 80 | Render_Software, ///< Software renderer backend |
| 80 | Render_OpenGL, ///< OpenGL backend | 81 | Render_OpenGL, ///< OpenGL backend |
| 81 | Audio, ///< Audio emulation | 82 | Audio, ///< Audio emulation |
| 82 | Audio_DSP, ///< The HLE implementation of the DSP | 83 | Audio_DSP, ///< The HLE implementation of the DSP |
| 83 | Audio_Sink, ///< Emulator audio output backend | 84 | Audio_Sink, ///< Emulator audio output backend |
| 84 | Loader, ///< ROM loader | 85 | Loader, ///< ROM loader |
| 85 | 86 | ||
| 86 | Count ///< Total number of logging classes | 87 | Count ///< Total number of logging classes |
| 87 | }; | 88 | }; |
| 88 | 89 | ||
| 89 | /// Logs a message to the global logger. | 90 | /// Logs a message to the global logger. |
| 90 | void LogMessage(Class log_class, Level log_level, | 91 | void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr, |
| 91 | const char* filename, unsigned int line_nr, const char* function, | 92 | const char* function, |
| 92 | #ifdef _MSC_VER | 93 | #ifdef _MSC_VER |
| 93 | _Printf_format_string_ | 94 | _Printf_format_string_ |
| 94 | #endif | 95 | #endif |
| 95 | const char* format, ...) | 96 | const char* format, |
| 97 | ...) | ||
| 96 | #ifdef __GNUC__ | 98 | #ifdef __GNUC__ |
| 97 | __attribute__((format(printf, 6, 7))) | 99 | __attribute__((format(printf, 6, 7))) |
| 98 | #endif | 100 | #endif |
| @@ -100,17 +102,23 @@ void LogMessage(Class log_class, Level log_level, | |||
| 100 | 102 | ||
| 101 | } // namespace Log | 103 | } // namespace Log |
| 102 | 104 | ||
| 103 | #define LOG_GENERIC(log_class, log_level, ...) \ | 105 | #define LOG_GENERIC(log_class, log_level, ...) \ |
| 104 | ::Log::LogMessage(log_class, log_level, __FILE__, __LINE__, __func__, __VA_ARGS__) | 106 | ::Log::LogMessage(log_class, log_level, __FILE__, __LINE__, __func__, __VA_ARGS__) |
| 105 | 107 | ||
| 106 | #ifdef _DEBUG | 108 | #ifdef _DEBUG |
| 107 | #define LOG_TRACE( log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Trace, __VA_ARGS__) | 109 | #define LOG_TRACE(log_class, ...) \ |
| 110 | LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Trace, __VA_ARGS__) | ||
| 108 | #else | 111 | #else |
| 109 | #define LOG_TRACE( log_class, ...) (void(0)) | 112 | #define LOG_TRACE(log_class, ...) (void(0)) |
| 110 | #endif | 113 | #endif |
| 111 | 114 | ||
| 112 | #define LOG_DEBUG( log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Debug, __VA_ARGS__) | 115 | #define LOG_DEBUG(log_class, ...) \ |
| 113 | #define LOG_INFO( log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Info, __VA_ARGS__) | 116 | LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Debug, __VA_ARGS__) |
| 114 | #define LOG_WARNING( log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Warning, __VA_ARGS__) | 117 | #define LOG_INFO(log_class, ...) \ |
| 115 | #define LOG_ERROR( log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Error, __VA_ARGS__) | 118 | LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Info, __VA_ARGS__) |
| 116 | #define LOG_CRITICAL(log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Critical, __VA_ARGS__) | 119 | #define LOG_WARNING(log_class, ...) \ |
| 120 | LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Warning, __VA_ARGS__) | ||
| 121 | #define LOG_ERROR(log_class, ...) \ | ||
| 122 | LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Error, __VA_ARGS__) | ||
| 123 | #define LOG_CRITICAL(log_class, ...) \ | ||
| 124 | LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Critical, __VA_ARGS__) | ||
diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp index de195b0f7..d61c1696b 100644 --- a/src/common/logging/text_formatter.cpp +++ b/src/common/logging/text_formatter.cpp | |||
| @@ -6,16 +6,15 @@ | |||
| 6 | #include <cstdio> | 6 | #include <cstdio> |
| 7 | 7 | ||
| 8 | #ifdef _WIN32 | 8 | #ifdef _WIN32 |
| 9 | # define WIN32_LEAN_AND_MEAN | 9 | #define WIN32_LEAN_AND_MEAN |
| 10 | # include <Windows.h> | 10 | #include <Windows.h> |
| 11 | #endif | 11 | #endif |
| 12 | 12 | ||
| 13 | #include "common/assert.h" | ||
| 14 | #include "common/common_funcs.h" | ||
| 13 | #include "common/logging/backend.h" | 15 | #include "common/logging/backend.h" |
| 14 | #include "common/logging/log.h" | 16 | #include "common/logging/log.h" |
| 15 | #include "common/logging/text_formatter.h" | 17 | #include "common/logging/text_formatter.h" |
| 16 | |||
| 17 | #include "common/assert.h" | ||
| 18 | #include "common/common_funcs.h" | ||
| 19 | #include "common/string_util.h" | 18 | #include "common/string_util.h" |
| 20 | 19 | ||
| 21 | namespace Log { | 20 | namespace Log { |
| @@ -44,15 +43,14 @@ const char* TrimSourcePath(const char* path, const char* root) { | |||
| 44 | } | 43 | } |
| 45 | 44 | ||
| 46 | void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) { | 45 | void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) { |
| 47 | unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000); | 46 | unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000); |
| 48 | unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000); | 47 | unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000); |
| 49 | 48 | ||
| 50 | const char* class_name = GetLogClassName(entry.log_class); | 49 | const char* class_name = GetLogClassName(entry.log_class); |
| 51 | const char* level_name = GetLevelName(entry.log_level); | 50 | const char* level_name = GetLevelName(entry.log_level); |
| 52 | 51 | ||
| 53 | snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", | 52 | snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", time_seconds, time_fractional, |
| 54 | time_seconds, time_fractional, class_name, level_name, | 53 | class_name, level_name, TrimSourcePath(entry.location.c_str()), entry.message.c_str()); |
| 55 | TrimSourcePath(entry.location.c_str()), entry.message.c_str()); | ||
| 56 | } | 54 | } |
| 57 | 55 | ||
| 58 | void PrintMessage(const Entry& entry) { | 56 | void PrintMessage(const Entry& entry) { |
| @@ -72,38 +70,50 @@ void PrintColoredMessage(const Entry& entry) { | |||
| 72 | WORD color = 0; | 70 | WORD color = 0; |
| 73 | switch (entry.log_level) { | 71 | switch (entry.log_level) { |
| 74 | case Level::Trace: // Grey | 72 | case Level::Trace: // Grey |
| 75 | color = FOREGROUND_INTENSITY; break; | 73 | color = FOREGROUND_INTENSITY; |
| 74 | break; | ||
| 76 | case Level::Debug: // Cyan | 75 | case Level::Debug: // Cyan |
| 77 | color = FOREGROUND_GREEN | FOREGROUND_BLUE; break; | 76 | color = FOREGROUND_GREEN | FOREGROUND_BLUE; |
| 77 | break; | ||
| 78 | case Level::Info: // Bright gray | 78 | case Level::Info: // Bright gray |
| 79 | color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; | 79 | color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; |
| 80 | break; | ||
| 80 | case Level::Warning: // Bright yellow | 81 | case Level::Warning: // Bright yellow |
| 81 | color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; break; | 82 | color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; |
| 83 | break; | ||
| 82 | case Level::Error: // Bright red | 84 | case Level::Error: // Bright red |
| 83 | color = FOREGROUND_RED | FOREGROUND_INTENSITY; break; | 85 | color = FOREGROUND_RED | FOREGROUND_INTENSITY; |
| 86 | break; | ||
| 84 | case Level::Critical: // Bright magenta | 87 | case Level::Critical: // Bright magenta |
| 85 | color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break; | 88 | color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; |
| 89 | break; | ||
| 86 | case Level::Count: | 90 | case Level::Count: |
| 87 | UNREACHABLE(); | 91 | UNREACHABLE(); |
| 88 | } | 92 | } |
| 89 | 93 | ||
| 90 | SetConsoleTextAttribute(console_handle, color); | 94 | SetConsoleTextAttribute(console_handle, color); |
| 91 | #else | 95 | #else |
| 92 | # define ESC "\x1b" | 96 | #define ESC "\x1b" |
| 93 | const char* color = ""; | 97 | const char* color = ""; |
| 94 | switch (entry.log_level) { | 98 | switch (entry.log_level) { |
| 95 | case Level::Trace: // Grey | 99 | case Level::Trace: // Grey |
| 96 | color = ESC "[1;30m"; break; | 100 | color = ESC "[1;30m"; |
| 101 | break; | ||
| 97 | case Level::Debug: // Cyan | 102 | case Level::Debug: // Cyan |
| 98 | color = ESC "[0;36m"; break; | 103 | color = ESC "[0;36m"; |
| 104 | break; | ||
| 99 | case Level::Info: // Bright gray | 105 | case Level::Info: // Bright gray |
| 100 | color = ESC "[0;37m"; break; | 106 | color = ESC "[0;37m"; |
| 107 | break; | ||
| 101 | case Level::Warning: // Bright yellow | 108 | case Level::Warning: // Bright yellow |
| 102 | color = ESC "[1;33m"; break; | 109 | color = ESC "[1;33m"; |
| 110 | break; | ||
| 103 | case Level::Error: // Bright red | 111 | case Level::Error: // Bright red |
| 104 | color = ESC "[1;31m"; break; | 112 | color = ESC "[1;31m"; |
| 113 | break; | ||
| 105 | case Level::Critical: // Bright magenta | 114 | case Level::Critical: // Bright magenta |
| 106 | color = ESC "[1;35m"; break; | 115 | color = ESC "[1;35m"; |
| 116 | break; | ||
| 107 | case Level::Count: | 117 | case Level::Count: |
| 108 | UNREACHABLE(); | 118 | UNREACHABLE(); |
| 109 | } | 119 | } |
| @@ -117,8 +127,7 @@ void PrintColoredMessage(const Entry& entry) { | |||
| 117 | SetConsoleTextAttribute(console_handle, original_info.wAttributes); | 127 | SetConsoleTextAttribute(console_handle, original_info.wAttributes); |
| 118 | #else | 128 | #else |
| 119 | fputs(ESC "[0m", stderr); | 129 | fputs(ESC "[0m", stderr); |
| 120 | # undef ESC | 130 | #undef ESC |
| 121 | #endif | 131 | #endif |
| 122 | } | 132 | } |
| 123 | |||
| 124 | } | 133 | } |
diff --git a/src/common/logging/text_formatter.h b/src/common/logging/text_formatter.h index 5b82f043f..0da102bc6 100644 --- a/src/common/logging/text_formatter.h +++ b/src/common/logging/text_formatter.h | |||
| @@ -28,5 +28,4 @@ void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len); | |||
| 28 | void PrintMessage(const Entry& entry); | 28 | void PrintMessage(const Entry& entry); |
| 29 | /// Prints the same message as `PrintMessage`, but colored acoording to the severity level. | 29 | /// Prints the same message as `PrintMessage`, but colored acoording to the severity level. |
| 30 | void PrintColoredMessage(const Entry& entry); | 30 | void PrintColoredMessage(const Entry& entry); |
| 31 | |||
| 32 | } | 31 | } |
diff --git a/src/common/math_util.h b/src/common/math_util.h index d44b06e74..41d89666c 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h | |||
| @@ -8,22 +8,20 @@ | |||
| 8 | #include <cstdlib> | 8 | #include <cstdlib> |
| 9 | #include <type_traits> | 9 | #include <type_traits> |
| 10 | 10 | ||
| 11 | namespace MathUtil | 11 | namespace MathUtil { |
| 12 | { | ||
| 13 | 12 | ||
| 14 | inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1, unsigned length1) { | 13 | inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1, |
| 14 | unsigned length1) { | ||
| 15 | return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1)); | 15 | return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1)); |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | template<typename T> | 18 | template <typename T> |
| 19 | inline T Clamp(const T val, const T& min, const T& max) | 19 | inline T Clamp(const T val, const T& min, const T& max) { |
| 20 | { | ||
| 21 | return std::max(min, std::min(max, val)); | 20 | return std::max(min, std::min(max, val)); |
| 22 | } | 21 | } |
| 23 | 22 | ||
| 24 | template<class T> | 23 | template <class T> |
| 25 | struct Rectangle | 24 | struct Rectangle { |
| 26 | { | ||
| 27 | T left; | 25 | T left; |
| 28 | T top; | 26 | T top; |
| 29 | T right; | 27 | T right; |
| @@ -31,10 +29,15 @@ struct Rectangle | |||
| 31 | 29 | ||
| 32 | Rectangle() {} | 30 | Rectangle() {} |
| 33 | 31 | ||
| 34 | Rectangle(T left, T top, T right, T bottom) : left(left), top(top), right(right), bottom(bottom) {} | 32 | Rectangle(T left, T top, T right, T bottom) |
| 33 | : left(left), top(top), right(right), bottom(bottom) {} | ||
| 35 | 34 | ||
| 36 | T GetWidth() const { return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); } | 35 | T GetWidth() const { |
| 37 | T GetHeight() const { return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); } | 36 | return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); |
| 37 | } | ||
| 38 | T GetHeight() const { | ||
| 39 | return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); | ||
| 40 | } | ||
| 38 | }; | 41 | }; |
| 39 | 42 | ||
| 40 | } // namespace MathUtil | 43 | } // namespace MathUtil |
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp index 07c7f79c8..c19729b21 100644 --- a/src/common/memory_util.cpp +++ b/src/common/memory_util.cpp | |||
| @@ -2,31 +2,30 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | |||
| 6 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 7 | #include "common/memory_util.h" | 6 | #include "common/memory_util.h" |
| 8 | 7 | ||
| 9 | #ifdef _WIN32 | 8 | #ifdef _WIN32 |
| 10 | #include <windows.h> | 9 | #include <windows.h> |
| 11 | #include <psapi.h> | 10 | // Windows.h needs to be included before psapi.h |
| 12 | #include "common/common_funcs.h" | 11 | #include <psapi.h> |
| 13 | #include "common/string_util.h" | 12 | #include "common/common_funcs.h" |
| 13 | #include "common/string_util.h" | ||
| 14 | #else | 14 | #else |
| 15 | #include <cstdlib> | 15 | #include <cstdlib> |
| 16 | #include <sys/mman.h> | 16 | #include <sys/mman.h> |
| 17 | #endif | 17 | #endif |
| 18 | 18 | ||
| 19 | #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) | 19 | #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) |
| 20 | #include <unistd.h> | 20 | #include <unistd.h> |
| 21 | #define PAGE_MASK (getpagesize() - 1) | 21 | #define PAGE_MASK (getpagesize() - 1) |
| 22 | #define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) | 22 | #define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) |
| 23 | #endif | 23 | #endif |
| 24 | 24 | ||
| 25 | // This is purposely not a full wrapper for virtualalloc/mmap, but it | 25 | // This is purposely not a full wrapper for virtualalloc/mmap, but it |
| 26 | // provides exactly the primitive operations that Dolphin needs. | 26 | // provides exactly the primitive operations that Dolphin needs. |
| 27 | 27 | ||
| 28 | void* AllocateExecutableMemory(size_t size, bool low) | 28 | void* AllocateExecutableMemory(size_t size, bool low) { |
| 29 | { | ||
| 30 | #if defined(_WIN32) | 29 | #if defined(_WIN32) |
| 31 | void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); | 30 | void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); |
| 32 | #else | 31 | #else |
| @@ -39,31 +38,27 @@ void* AllocateExecutableMemory(size_t size, bool low) | |||
| 39 | // effect of discarding already mapped pages that happen to be in the | 38 | // effect of discarding already mapped pages that happen to be in the |
| 40 | // requested virtual memory range (such as the emulated RAM, sometimes). | 39 | // requested virtual memory range (such as the emulated RAM, sometimes). |
| 41 | if (low && (!map_hint)) | 40 | if (low && (!map_hint)) |
| 42 | map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ | 41 | map_hint = (char*)round_page(512 * 1024 * 1024); /* 0.5 GB rounded up to the next page */ |
| 43 | #endif | 42 | #endif |
| 44 | void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, | 43 | void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE |
| 45 | MAP_ANON | MAP_PRIVATE | ||
| 46 | #if defined(ARCHITECTURE_X64) && defined(MAP_32BIT) | 44 | #if defined(ARCHITECTURE_X64) && defined(MAP_32BIT) |
| 47 | | (low ? MAP_32BIT : 0) | 45 | | (low ? MAP_32BIT : 0) |
| 48 | #endif | 46 | #endif |
| 49 | , -1, 0); | 47 | , |
| 48 | -1, 0); | ||
| 50 | #endif /* defined(_WIN32) */ | 49 | #endif /* defined(_WIN32) */ |
| 51 | 50 | ||
| 52 | #ifdef _WIN32 | 51 | #ifdef _WIN32 |
| 53 | if (ptr == nullptr) | 52 | if (ptr == nullptr) { |
| 54 | { | ||
| 55 | #else | 53 | #else |
| 56 | if (ptr == MAP_FAILED) | 54 | if (ptr == MAP_FAILED) { |
| 57 | { | ||
| 58 | ptr = nullptr; | 55 | ptr = nullptr; |
| 59 | #endif | 56 | #endif |
| 60 | LOG_ERROR(Common_Memory, "Failed to allocate executable memory"); | 57 | LOG_ERROR(Common_Memory, "Failed to allocate executable memory"); |
| 61 | } | 58 | } |
| 62 | #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) | 59 | #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) |
| 63 | else | 60 | else { |
| 64 | { | 61 | if (low) { |
| 65 | if (low) | ||
| 66 | { | ||
| 67 | map_hint += size; | 62 | map_hint += size; |
| 68 | map_hint = (char*)round_page(map_hint); /* round up to the next page */ | 63 | map_hint = (char*)round_page(map_hint); /* round up to the next page */ |
| 69 | } | 64 | } |
| @@ -78,13 +73,11 @@ void* AllocateExecutableMemory(size_t size, bool low) | |||
| 78 | return ptr; | 73 | return ptr; |
| 79 | } | 74 | } |
| 80 | 75 | ||
| 81 | void* AllocateMemoryPages(size_t size) | 76 | void* AllocateMemoryPages(size_t size) { |
| 82 | { | ||
| 83 | #ifdef _WIN32 | 77 | #ifdef _WIN32 |
| 84 | void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); | 78 | void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); |
| 85 | #else | 79 | #else |
| 86 | void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, | 80 | void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); |
| 87 | MAP_ANON | MAP_PRIVATE, -1, 0); | ||
| 88 | 81 | ||
| 89 | if (ptr == MAP_FAILED) | 82 | if (ptr == MAP_FAILED) |
| 90 | ptr = nullptr; | 83 | ptr = nullptr; |
| @@ -96,10 +89,9 @@ void* AllocateMemoryPages(size_t size) | |||
| 96 | return ptr; | 89 | return ptr; |
| 97 | } | 90 | } |
| 98 | 91 | ||
| 99 | void* AllocateAlignedMemory(size_t size,size_t alignment) | 92 | void* AllocateAlignedMemory(size_t size, size_t alignment) { |
| 100 | { | ||
| 101 | #ifdef _WIN32 | 93 | #ifdef _WIN32 |
| 102 | void* ptr = _aligned_malloc(size,alignment); | 94 | void* ptr = _aligned_malloc(size, alignment); |
| 103 | #else | 95 | #else |
| 104 | void* ptr = nullptr; | 96 | void* ptr = nullptr; |
| 105 | #ifdef ANDROID | 97 | #ifdef ANDROID |
| @@ -116,10 +108,8 @@ void* AllocateAlignedMemory(size_t size,size_t alignment) | |||
| 116 | return ptr; | 108 | return ptr; |
| 117 | } | 109 | } |
| 118 | 110 | ||
| 119 | void FreeMemoryPages(void* ptr, size_t size) | 111 | void FreeMemoryPages(void* ptr, size_t size) { |
| 120 | { | 112 | if (ptr) { |
| 121 | if (ptr) | ||
| 122 | { | ||
| 123 | #ifdef _WIN32 | 113 | #ifdef _WIN32 |
| 124 | if (!VirtualFree(ptr, 0, MEM_RELEASE)) | 114 | if (!VirtualFree(ptr, 0, MEM_RELEASE)) |
| 125 | LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg()); | 115 | LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg()); |
| @@ -129,20 +119,17 @@ void FreeMemoryPages(void* ptr, size_t size) | |||
| 129 | } | 119 | } |
| 130 | } | 120 | } |
| 131 | 121 | ||
| 132 | void FreeAlignedMemory(void* ptr) | 122 | void FreeAlignedMemory(void* ptr) { |
| 133 | { | 123 | if (ptr) { |
| 134 | if (ptr) | ||
| 135 | { | ||
| 136 | #ifdef _WIN32 | 124 | #ifdef _WIN32 |
| 137 | _aligned_free(ptr); | 125 | _aligned_free(ptr); |
| 138 | #else | 126 | #else |
| 139 | free(ptr); | 127 | free(ptr); |
| 140 | #endif | 128 | #endif |
| 141 | } | 129 | } |
| 142 | } | 130 | } |
| 143 | 131 | ||
| 144 | void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) | 132 | void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) { |
| 145 | { | ||
| 146 | #ifdef _WIN32 | 133 | #ifdef _WIN32 |
| 147 | DWORD oldValue; | 134 | DWORD oldValue; |
| 148 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) | 135 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) |
| @@ -152,19 +139,19 @@ void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) | |||
| 152 | #endif | 139 | #endif |
| 153 | } | 140 | } |
| 154 | 141 | ||
| 155 | void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) | 142 | void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) { |
| 156 | { | ||
| 157 | #ifdef _WIN32 | 143 | #ifdef _WIN32 |
| 158 | DWORD oldValue; | 144 | DWORD oldValue; |
| 159 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) | 145 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, |
| 146 | &oldValue)) | ||
| 160 | LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg()); | 147 | LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg()); |
| 161 | #else | 148 | #else |
| 162 | mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); | 149 | mprotect(ptr, size, |
| 150 | allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); | ||
| 163 | #endif | 151 | #endif |
| 164 | } | 152 | } |
| 165 | 153 | ||
| 166 | std::string MemUsage() | 154 | std::string MemUsage() { |
| 167 | { | ||
| 168 | #ifdef _WIN32 | 155 | #ifdef _WIN32 |
| 169 | #pragma comment(lib, "psapi") | 156 | #pragma comment(lib, "psapi") |
| 170 | DWORD processID = GetCurrentProcessId(); | 157 | DWORD processID = GetCurrentProcessId(); |
| @@ -175,10 +162,12 @@ std::string MemUsage() | |||
| 175 | // Print information about the memory usage of the process. | 162 | // Print information about the memory usage of the process. |
| 176 | 163 | ||
| 177 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); | 164 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); |
| 178 | if (nullptr == hProcess) return "MemUsage Error"; | 165 | if (nullptr == hProcess) |
| 166 | return "MemUsage Error"; | ||
| 179 | 167 | ||
| 180 | if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) | 168 | if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) |
| 181 | Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); | 169 | Ret = Common::StringFromFormat( |
| 170 | "%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); | ||
| 182 | 171 | ||
| 183 | CloseHandle(hProcess); | 172 | CloseHandle(hProcess); |
| 184 | return Ret; | 173 | return Ret; |
diff --git a/src/common/memory_util.h b/src/common/memory_util.h index 9bf37c44f..76ca5a30c 100644 --- a/src/common/memory_util.h +++ b/src/common/memory_util.h | |||
| @@ -10,10 +10,12 @@ | |||
| 10 | void* AllocateExecutableMemory(size_t size, bool low = true); | 10 | void* AllocateExecutableMemory(size_t size, bool low = true); |
| 11 | void* AllocateMemoryPages(size_t size); | 11 | void* AllocateMemoryPages(size_t size); |
| 12 | void FreeMemoryPages(void* ptr, size_t size); | 12 | void FreeMemoryPages(void* ptr, size_t size); |
| 13 | void* AllocateAlignedMemory(size_t size,size_t alignment); | 13 | void* AllocateAlignedMemory(size_t size, size_t alignment); |
| 14 | void FreeAlignedMemory(void* ptr); | 14 | void FreeAlignedMemory(void* ptr); |
| 15 | void WriteProtectMemory(void* ptr, size_t size, bool executable = false); | 15 | void WriteProtectMemory(void* ptr, size_t size, bool executable = false); |
| 16 | void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false); | 16 | void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false); |
| 17 | std::string MemUsage(); | 17 | std::string MemUsage(); |
| 18 | 18 | ||
| 19 | inline int GetPageSize() { return 4096; } | 19 | inline int GetPageSize() { |
| 20 | return 4096; | ||
| 21 | } | ||
diff --git a/src/common/microprofile.h b/src/common/microprofile.h index 670a58fe5..54e7f3cc4 100644 --- a/src/common/microprofile.h +++ b/src/common/microprofile.h | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | #define MICROPROFILE_WEBSERVER 0 | 13 | #define MICROPROFILE_WEBSERVER 0 |
| 14 | #define MICROPROFILE_GPU_TIMERS 0 // TODO: Implement timer queries when we upgrade to OpenGL 3.3 | 14 | #define MICROPROFILE_GPU_TIMERS 0 // TODO: Implement timer queries when we upgrade to OpenGL 3.3 |
| 15 | #define MICROPROFILE_CONTEXT_SWITCH_TRACE 0 | 15 | #define MICROPROFILE_CONTEXT_SWITCH_TRACE 0 |
| 16 | #define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048<<13) // 16 MB | 16 | #define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048 << 13) // 16 MB |
| 17 | 17 | ||
| 18 | #ifdef _WIN32 | 18 | #ifdef _WIN32 |
| 19 | // This isn't defined by the standard library in MSVC2015 | 19 | // This isn't defined by the standard library in MSVC2015 |
diff --git a/src/common/misc.cpp b/src/common/misc.cpp index d2a049b63..7be2235b0 100644 --- a/src/common/misc.cpp +++ b/src/common/misc.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstddef> | 5 | #include <cstddef> |
| 6 | |||
| 7 | #ifdef _WIN32 | 6 | #ifdef _WIN32 |
| 8 | #include <windows.h> | 7 | #include <windows.h> |
| 9 | #else | 8 | #else |
| @@ -12,23 +11,21 @@ | |||
| 12 | #endif | 11 | #endif |
| 13 | 12 | ||
| 14 | // Neither Android nor OS X support TLS | 13 | // Neither Android nor OS X support TLS |
| 15 | #if defined(__APPLE__) || (ANDROID && __clang__) | 14 | #if defined(__APPLE__) || (ANDROID && __clang__) |
| 16 | #define __thread | 15 | #define __thread |
| 17 | #endif | 16 | #endif |
| 18 | 17 | ||
| 19 | // Generic function to get last error message. | 18 | // Generic function to get last error message. |
| 20 | // Call directly after the command or use the error num. | 19 | // Call directly after the command or use the error num. |
| 21 | // This function might change the error code. | 20 | // This function might change the error code. |
| 22 | const char* GetLastErrorMsg() | 21 | const char* GetLastErrorMsg() { |
| 23 | { | ||
| 24 | static const size_t buff_size = 255; | 22 | static const size_t buff_size = 255; |
| 25 | 23 | ||
| 26 | #ifdef _WIN32 | 24 | #ifdef _WIN32 |
| 27 | static __declspec(thread) char err_str[buff_size] = {}; | 25 | static __declspec(thread) char err_str[buff_size] = {}; |
| 28 | 26 | ||
| 29 | FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), | 27 | FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), |
| 30 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | 28 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr); |
| 31 | err_str, buff_size, nullptr); | ||
| 32 | #else | 29 | #else |
| 33 | static __thread char err_str[buff_size] = {}; | 30 | static __thread char err_str[buff_size] = {}; |
| 34 | 31 | ||
diff --git a/src/common/platform.h b/src/common/platform.h index 9ba4db11b..c62fb7c8f 100644 --- a/src/common/platform.h +++ b/src/common/platform.h | |||
| @@ -28,7 +28,7 @@ | |||
| 28 | // Platform detection | 28 | // Platform detection |
| 29 | 29 | ||
| 30 | #if defined(ARCHITECTURE_x86_64) || defined(__aarch64__) | 30 | #if defined(ARCHITECTURE_x86_64) || defined(__aarch64__) |
| 31 | #define EMU_ARCH_BITS 64 | 31 | #define EMU_ARCH_BITS 64 |
| 32 | #elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) | 32 | #elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) |
| 33 | #define EMU_ARCH_BITS 32 | 33 | #define EMU_ARCH_BITS 32 |
| 34 | #endif | 34 | #endif |
diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp index 49eb3f40c..b40e7205d 100644 --- a/src/common/profiler.cpp +++ b/src/common/profiler.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <cstddef> | 6 | #include <cstddef> |
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | |||
| 9 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 10 | #include "common/profiler_reporting.h" | 9 | #include "common/profiler_reporting.h" |
| 11 | #include "common/synchronized_wrapper.h" | 10 | #include "common/synchronized_wrapper.h" |
| @@ -14,8 +13,7 @@ namespace Common { | |||
| 14 | namespace Profiling { | 13 | namespace Profiling { |
| 15 | 14 | ||
| 16 | ProfilingManager::ProfilingManager() | 15 | ProfilingManager::ProfilingManager() |
| 17 | : last_frame_end(Clock::now()), this_frame_start(Clock::now()) { | 16 | : last_frame_end(Clock::now()), this_frame_start(Clock::now()) {} |
| 18 | } | ||
| 19 | 17 | ||
| 20 | void ProfilingManager::BeginFrame() { | 18 | void ProfilingManager::BeginFrame() { |
| 21 | this_frame_start = Clock::now(); | 19 | this_frame_start = Clock::now(); |
| @@ -31,7 +29,7 @@ void ProfilingManager::FinishFrame() { | |||
| 31 | } | 29 | } |
| 32 | 30 | ||
| 33 | TimingResultsAggregator::TimingResultsAggregator(size_t window_size) | 31 | TimingResultsAggregator::TimingResultsAggregator(size_t window_size) |
| 34 | : max_window_size(window_size), window_size(0) { | 32 | : max_window_size(window_size), window_size(0) { |
| 35 | interframe_times.resize(window_size, Duration::zero()); | 33 | interframe_times.resize(window_size, Duration::zero()); |
| 36 | frame_times.resize(window_size, Duration::zero()); | 34 | frame_times.resize(window_size, Duration::zero()); |
| 37 | } | 35 | } |
diff --git a/src/common/profiler_reporting.h b/src/common/profiler_reporting.h index fa1ac883f..e9ce6d41c 100644 --- a/src/common/profiler_reporting.h +++ b/src/common/profiler_reporting.h | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include <chrono> | 7 | #include <chrono> |
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | |||
| 11 | #include "common/synchronized_wrapper.h" | 10 | #include "common/synchronized_wrapper.h" |
| 12 | 11 | ||
| 13 | namespace Common { | 12 | namespace Common { |
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h index 08f09a8c8..072ab285d 100644 --- a/src/common/scope_exit.h +++ b/src/common/scope_exit.h | |||
| @@ -4,20 +4,24 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include <utility> | 7 | #include <utility> |
| 8 | #include "common/common_funcs.h" | ||
| 9 | 9 | ||
| 10 | namespace detail { | 10 | namespace detail { |
| 11 | template <typename Func> | 11 | template <typename Func> |
| 12 | struct ScopeExitHelper { | 12 | struct ScopeExitHelper { |
| 13 | explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {} | 13 | explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {} |
| 14 | ~ScopeExitHelper() { func(); } | 14 | ~ScopeExitHelper() { |
| 15 | func(); | ||
| 16 | } | ||
| 15 | 17 | ||
| 16 | Func func; | 18 | Func func; |
| 17 | }; | 19 | }; |
| 18 | 20 | ||
| 19 | template <typename Func> | 21 | template <typename Func> |
| 20 | ScopeExitHelper<Func> ScopeExit(Func&& func) { return ScopeExitHelper<Func>(std::move(func)); } | 22 | ScopeExitHelper<Func> ScopeExit(Func&& func) { |
| 23 | return ScopeExitHelper<Func>(std::move(func)); | ||
| 24 | } | ||
| 21 | } | 25 | } |
| 22 | 26 | ||
| 23 | /** | 27 | /** |
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index f0aa072db..596ae01bf 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -8,17 +8,15 @@ | |||
| 8 | #include <cstdlib> | 8 | #include <cstdlib> |
| 9 | #include <cstring> | 9 | #include <cstring> |
| 10 | #include <boost/range/algorithm/transform.hpp> | 10 | #include <boost/range/algorithm/transform.hpp> |
| 11 | |||
| 12 | #include "common/common_paths.h" | 11 | #include "common/common_paths.h" |
| 13 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 14 | #include "common/string_util.h" | 13 | #include "common/string_util.h" |
| 15 | |||
| 16 | #ifdef _MSC_VER | 14 | #ifdef _MSC_VER |
| 17 | #include <Windows.h> | 15 | #include <codecvt> |
| 18 | #include <codecvt> | 16 | #include <Windows.h> |
| 19 | #include "common/common_funcs.h" | 17 | #include "common/common_funcs.h" |
| 20 | #else | 18 | #else |
| 21 | #include <iconv.h> | 19 | #include <iconv.h> |
| 22 | #endif | 20 | #endif |
| 23 | 21 | ||
| 24 | namespace Common { | 22 | namespace Common { |
| @@ -36,9 +34,8 @@ std::string ToUpper(std::string str) { | |||
| 36 | } | 34 | } |
| 37 | 35 | ||
| 38 | // faster than sscanf | 36 | // faster than sscanf |
| 39 | bool AsciiToHex(const char* _szValue, u32& result) | 37 | bool AsciiToHex(const char* _szValue, u32& result) { |
| 40 | { | 38 | char* endptr = nullptr; |
| 41 | char *endptr = nullptr; | ||
| 42 | const u32 value = strtoul(_szValue, &endptr, 16); | 39 | const u32 value = strtoul(_szValue, &endptr, 16); |
| 43 | 40 | ||
| 44 | if (!endptr || *endptr) | 41 | if (!endptr || *endptr) |
| @@ -48,8 +45,7 @@ bool AsciiToHex(const char* _szValue, u32& result) | |||
| 48 | return true; | 45 | return true; |
| 49 | } | 46 | } |
| 50 | 47 | ||
| 51 | bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) | 48 | bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) { |
| 52 | { | ||
| 53 | int writtenCount; | 49 | int writtenCount; |
| 54 | 50 | ||
| 55 | #ifdef _MSC_VER | 51 | #ifdef _MSC_VER |
| @@ -84,22 +80,18 @@ bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list ar | |||
| 84 | writtenCount = vsnprintf(out, outsize, format, args); | 80 | writtenCount = vsnprintf(out, outsize, format, args); |
| 85 | #endif | 81 | #endif |
| 86 | 82 | ||
| 87 | if (writtenCount > 0 && writtenCount < outsize) | 83 | if (writtenCount > 0 && writtenCount < outsize) { |
| 88 | { | ||
| 89 | out[writtenCount] = '\0'; | 84 | out[writtenCount] = '\0'; |
| 90 | return true; | 85 | return true; |
| 91 | } | 86 | } else { |
| 92 | else | ||
| 93 | { | ||
| 94 | out[outsize - 1] = '\0'; | 87 | out[outsize - 1] = '\0'; |
| 95 | return false; | 88 | return false; |
| 96 | } | 89 | } |
| 97 | } | 90 | } |
| 98 | 91 | ||
| 99 | std::string StringFromFormat(const char* format, ...) | 92 | std::string StringFromFormat(const char* format, ...) { |
| 100 | { | ||
| 101 | va_list args; | 93 | va_list args; |
| 102 | char *buf = nullptr; | 94 | char* buf = nullptr; |
| 103 | #ifdef _WIN32 | 95 | #ifdef _WIN32 |
| 104 | int required = 0; | 96 | int required = 0; |
| 105 | 97 | ||
| @@ -124,21 +116,17 @@ std::string StringFromFormat(const char* format, ...) | |||
| 124 | } | 116 | } |
| 125 | 117 | ||
| 126 | // For Debugging. Read out an u8 array. | 118 | // For Debugging. Read out an u8 array. |
| 127 | std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) | 119 | std::string ArrayToString(const u8* data, u32 size, int line_len, bool spaces) { |
| 128 | { | ||
| 129 | std::ostringstream oss; | 120 | std::ostringstream oss; |
| 130 | oss << std::setfill('0') << std::hex; | 121 | oss << std::setfill('0') << std::hex; |
| 131 | 122 | ||
| 132 | for (int line = 0; size; ++data, --size) | 123 | for (int line = 0; size; ++data, --size) { |
| 133 | { | ||
| 134 | oss << std::setw(2) << (int)*data; | 124 | oss << std::setw(2) << (int)*data; |
| 135 | 125 | ||
| 136 | if (line_len == ++line) | 126 | if (line_len == ++line) { |
| 137 | { | ||
| 138 | oss << '\n'; | 127 | oss << '\n'; |
| 139 | line = 0; | 128 | line = 0; |
| 140 | } | 129 | } else if (spaces) |
| 141 | else if (spaces) | ||
| 142 | oss << ' '; | 130 | oss << ' '; |
| 143 | } | 131 | } |
| 144 | 132 | ||
| @@ -146,8 +134,7 @@ std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) | |||
| 146 | } | 134 | } |
| 147 | 135 | ||
| 148 | // Turns " hej " into "hej". Also handles tabs. | 136 | // Turns " hej " into "hej". Also handles tabs. |
| 149 | std::string StripSpaces(const std::string &str) | 137 | std::string StripSpaces(const std::string& str) { |
| 150 | { | ||
| 151 | const size_t s = str.find_first_not_of(" \t\r\n"); | 138 | const size_t s = str.find_first_not_of(" \t\r\n"); |
| 152 | 139 | ||
| 153 | if (str.npos != s) | 140 | if (str.npos != s) |
| @@ -159,17 +146,15 @@ std::string StripSpaces(const std::string &str) | |||
| 159 | // "\"hello\"" is turned to "hello" | 146 | // "\"hello\"" is turned to "hello" |
| 160 | // This one assumes that the string has already been space stripped in both | 147 | // This one assumes that the string has already been space stripped in both |
| 161 | // ends, as done by StripSpaces above, for example. | 148 | // ends, as done by StripSpaces above, for example. |
| 162 | std::string StripQuotes(const std::string& s) | 149 | std::string StripQuotes(const std::string& s) { |
| 163 | { | ||
| 164 | if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) | 150 | if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) |
| 165 | return s.substr(1, s.size() - 2); | 151 | return s.substr(1, s.size() - 2); |
| 166 | else | 152 | else |
| 167 | return s; | 153 | return s; |
| 168 | } | 154 | } |
| 169 | 155 | ||
| 170 | bool TryParse(const std::string &str, u32 *const output) | 156 | bool TryParse(const std::string& str, u32* const output) { |
| 171 | { | 157 | char* endptr = nullptr; |
| 172 | char *endptr = nullptr; | ||
| 173 | 158 | ||
| 174 | // Reset errno to a value other than ERANGE | 159 | // Reset errno to a value other than ERANGE |
| 175 | errno = 0; | 160 | errno = 0; |
| @@ -183,8 +168,7 @@ bool TryParse(const std::string &str, u32 *const output) | |||
| 183 | return false; | 168 | return false; |
| 184 | 169 | ||
| 185 | #if ULONG_MAX > UINT_MAX | 170 | #if ULONG_MAX > UINT_MAX |
| 186 | if (value >= 0x100000000ull | 171 | if (value >= 0x100000000ull && value <= 0xFFFFFFFF00000000ull) |
| 187 | && value <= 0xFFFFFFFF00000000ull) | ||
| 188 | return false; | 172 | return false; |
| 189 | #endif | 173 | #endif |
| 190 | 174 | ||
| @@ -192,8 +176,7 @@ bool TryParse(const std::string &str, u32 *const output) | |||
| 192 | return true; | 176 | return true; |
| 193 | } | 177 | } |
| 194 | 178 | ||
| 195 | bool TryParse(const std::string &str, bool *const output) | 179 | bool TryParse(const std::string& str, bool* const output) { |
| 196 | { | ||
| 197 | if ("1" == str || "true" == ToLower(str)) | 180 | if ("1" == str || "true" == ToLower(str)) |
| 198 | *output = true; | 181 | *output = true; |
| 199 | else if ("0" == str || "false" == ToLower(str)) | 182 | else if ("0" == str || "false" == ToLower(str)) |
| @@ -204,22 +187,21 @@ bool TryParse(const std::string &str, bool *const output) | |||
| 204 | return true; | 187 | return true; |
| 205 | } | 188 | } |
| 206 | 189 | ||
| 207 | std::string StringFromBool(bool value) | 190 | std::string StringFromBool(bool value) { |
| 208 | { | ||
| 209 | return value ? "True" : "False"; | 191 | return value ? "True" : "False"; |
| 210 | } | 192 | } |
| 211 | 193 | ||
| 212 | bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) | 194 | bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, |
| 213 | { | 195 | std::string* _pExtension) { |
| 214 | if (full_path.empty()) | 196 | if (full_path.empty()) |
| 215 | return false; | 197 | return false; |
| 216 | 198 | ||
| 217 | size_t dir_end = full_path.find_last_of("/" | 199 | size_t dir_end = full_path.find_last_of("/" |
| 218 | // windows needs the : included for something like just "C:" to be considered a directory | 200 | // windows needs the : included for something like just "C:" to be considered a directory |
| 219 | #ifdef _WIN32 | 201 | #ifdef _WIN32 |
| 220 | ":" | 202 | ":" |
| 221 | #endif | 203 | #endif |
| 222 | ); | 204 | ); |
| 223 | if (std::string::npos == dir_end) | 205 | if (std::string::npos == dir_end) |
| 224 | dir_end = 0; | 206 | dir_end = 0; |
| 225 | else | 207 | else |
| @@ -241,8 +223,8 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ | |||
| 241 | return true; | 223 | return true; |
| 242 | } | 224 | } |
| 243 | 225 | ||
| 244 | void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename) | 226 | void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, |
| 245 | { | 227 | const std::string& _Filename) { |
| 246 | _CompleteFilename = _Path; | 228 | _CompleteFilename = _Path; |
| 247 | 229 | ||
| 248 | // check for seperator | 230 | // check for seperator |
| @@ -253,8 +235,7 @@ void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _P | |||
| 253 | _CompleteFilename += _Filename; | 235 | _CompleteFilename += _Filename; |
| 254 | } | 236 | } |
| 255 | 237 | ||
| 256 | void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) | 238 | void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) { |
| 257 | { | ||
| 258 | std::istringstream iss(str); | 239 | std::istringstream iss(str); |
| 259 | output.resize(1); | 240 | output.resize(1); |
| 260 | 241 | ||
| @@ -264,8 +245,7 @@ void SplitString(const std::string& str, const char delim, std::vector<std::stri | |||
| 264 | output.pop_back(); | 245 | output.pop_back(); |
| 265 | } | 246 | } |
| 266 | 247 | ||
| 267 | std::string TabsToSpaces(int tab_size, const std::string &in) | 248 | std::string TabsToSpaces(int tab_size, const std::string& in) { |
| 268 | { | ||
| 269 | const std::string spaces(tab_size, ' '); | 249 | const std::string spaces(tab_size, ' '); |
| 270 | std::string out(in); | 250 | std::string out(in); |
| 271 | 251 | ||
| @@ -276,15 +256,13 @@ std::string TabsToSpaces(int tab_size, const std::string &in) | |||
| 276 | return out; | 256 | return out; |
| 277 | } | 257 | } |
| 278 | 258 | ||
| 279 | std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) | 259 | std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) { |
| 280 | { | ||
| 281 | size_t pos = 0; | 260 | size_t pos = 0; |
| 282 | 261 | ||
| 283 | if (src == dest) | 262 | if (src == dest) |
| 284 | return result; | 263 | return result; |
| 285 | 264 | ||
| 286 | while ((pos = result.find(src, pos)) != std::string::npos) | 265 | while ((pos = result.find(src, pos)) != std::string::npos) { |
| 287 | { | ||
| 288 | result.replace(pos, src.size(), dest); | 266 | result.replace(pos, src.size(), dest); |
| 289 | pos += dest.length(); | 267 | pos += dest.length(); |
| 290 | } | 268 | } |
| @@ -294,8 +272,7 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st | |||
| 294 | 272 | ||
| 295 | #ifdef _MSC_VER | 273 | #ifdef _MSC_VER |
| 296 | 274 | ||
| 297 | std::string UTF16ToUTF8(const std::u16string& input) | 275 | std::string UTF16ToUTF8(const std::u16string& input) { |
| 298 | { | ||
| 299 | #if _MSC_VER >= 1900 | 276 | #if _MSC_VER >= 1900 |
| 300 | // Workaround for missing char16_t/char32_t instantiations in MSVC2015 | 277 | // Workaround for missing char16_t/char32_t instantiations in MSVC2015 |
| 301 | std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; | 278 | std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; |
| @@ -307,8 +284,7 @@ std::string UTF16ToUTF8(const std::u16string& input) | |||
| 307 | #endif | 284 | #endif |
| 308 | } | 285 | } |
| 309 | 286 | ||
| 310 | std::u16string UTF8ToUTF16(const std::string& input) | 287 | std::u16string UTF8ToUTF16(const std::string& input) { |
| 311 | { | ||
| 312 | #if _MSC_VER >= 1900 | 288 | #if _MSC_VER >= 1900 |
| 313 | // Workaround for missing char16_t/char32_t instantiations in MSVC2015 | 289 | // Workaround for missing char16_t/char32_t instantiations in MSVC2015 |
| 314 | std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; | 290 | std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; |
| @@ -320,57 +296,56 @@ std::u16string UTF8ToUTF16(const std::string& input) | |||
| 320 | #endif | 296 | #endif |
| 321 | } | 297 | } |
| 322 | 298 | ||
| 323 | static std::wstring CPToUTF16(u32 code_page, const std::string& input) | 299 | static std::wstring CPToUTF16(u32 code_page, const std::string& input) { |
| 324 | { | 300 | auto const size = |
| 325 | auto const size = MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0); | 301 | MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0); |
| 326 | 302 | ||
| 327 | std::wstring output; | 303 | std::wstring output; |
| 328 | output.resize(size); | 304 | output.resize(size); |
| 329 | 305 | ||
| 330 | if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()))) | 306 | if (size == 0 || |
| 307 | size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), | ||
| 308 | &output[0], static_cast<int>(output.size()))) | ||
| 331 | output.clear(); | 309 | output.clear(); |
| 332 | 310 | ||
| 333 | return output; | 311 | return output; |
| 334 | } | 312 | } |
| 335 | 313 | ||
| 336 | std::string UTF16ToUTF8(const std::wstring& input) | 314 | std::string UTF16ToUTF8(const std::wstring& input) { |
| 337 | { | 315 | auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), |
| 338 | auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), nullptr, 0, nullptr, nullptr); | 316 | nullptr, 0, nullptr, nullptr); |
| 339 | 317 | ||
| 340 | std::string output; | 318 | std::string output; |
| 341 | output.resize(size); | 319 | output.resize(size); |
| 342 | 320 | ||
| 343 | if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()), nullptr, nullptr)) | 321 | if (size == 0 || |
| 322 | size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), | ||
| 323 | &output[0], static_cast<int>(output.size()), nullptr, nullptr)) | ||
| 344 | output.clear(); | 324 | output.clear(); |
| 345 | 325 | ||
| 346 | return output; | 326 | return output; |
| 347 | } | 327 | } |
| 348 | 328 | ||
| 349 | std::wstring UTF8ToUTF16W(const std::string &input) | 329 | std::wstring UTF8ToUTF16W(const std::string& input) { |
| 350 | { | ||
| 351 | return CPToUTF16(CP_UTF8, input); | 330 | return CPToUTF16(CP_UTF8, input); |
| 352 | } | 331 | } |
| 353 | 332 | ||
| 354 | std::string SHIFTJISToUTF8(const std::string& input) | 333 | std::string SHIFTJISToUTF8(const std::string& input) { |
| 355 | { | ||
| 356 | return UTF16ToUTF8(CPToUTF16(932, input)); | 334 | return UTF16ToUTF8(CPToUTF16(932, input)); |
| 357 | } | 335 | } |
| 358 | 336 | ||
| 359 | std::string CP1252ToUTF8(const std::string& input) | 337 | std::string CP1252ToUTF8(const std::string& input) { |
| 360 | { | ||
| 361 | return UTF16ToUTF8(CPToUTF16(1252, input)); | 338 | return UTF16ToUTF8(CPToUTF16(1252, input)); |
| 362 | } | 339 | } |
| 363 | 340 | ||
| 364 | #else | 341 | #else |
| 365 | 342 | ||
| 366 | template <typename T> | 343 | template <typename T> |
| 367 | static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) | 344 | static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) { |
| 368 | { | ||
| 369 | std::string result; | 345 | std::string result; |
| 370 | 346 | ||
| 371 | iconv_t const conv_desc = iconv_open("UTF-8", fromcode); | 347 | iconv_t const conv_desc = iconv_open("UTF-8", fromcode); |
| 372 | if ((iconv_t)(-1) == conv_desc) | 348 | if ((iconv_t)(-1) == conv_desc) { |
| 373 | { | ||
| 374 | LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); | 349 | LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); |
| 375 | iconv_close(conv_desc); | 350 | iconv_close(conv_desc); |
| 376 | return {}; | 351 | return {}; |
| @@ -388,24 +363,18 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& | |||
| 388 | auto dst_buffer = &out_buffer[0]; | 363 | auto dst_buffer = &out_buffer[0]; |
| 389 | size_t dst_bytes = out_buffer.size(); | 364 | size_t dst_bytes = out_buffer.size(); |
| 390 | 365 | ||
| 391 | while (0 != src_bytes) | 366 | while (0 != src_bytes) { |
| 392 | { | 367 | size_t const iconv_result = |
| 393 | size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, | 368 | iconv(conv_desc, (char**)(&src_buffer), &src_bytes, &dst_buffer, &dst_bytes); |
| 394 | &dst_buffer, &dst_bytes); | ||
| 395 | 369 | ||
| 396 | if (static_cast<size_t>(-1) == iconv_result) | 370 | if (static_cast<size_t>(-1) == iconv_result) { |
| 397 | { | 371 | if (EILSEQ == errno || EINVAL == errno) { |
| 398 | if (EILSEQ == errno || EINVAL == errno) | ||
| 399 | { | ||
| 400 | // Try to skip the bad character | 372 | // Try to skip the bad character |
| 401 | if (0 != src_bytes) | 373 | if (0 != src_bytes) { |
| 402 | { | ||
| 403 | --src_bytes; | 374 | --src_bytes; |
| 404 | ++src_buffer; | 375 | ++src_buffer; |
| 405 | } | 376 | } |
| 406 | } | 377 | } else { |
| 407 | else | ||
| 408 | { | ||
| 409 | LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno)); | 378 | LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno)); |
| 410 | break; | 379 | break; |
| 411 | } | 380 | } |
| @@ -420,13 +389,11 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& | |||
| 420 | return result; | 389 | return result; |
| 421 | } | 390 | } |
| 422 | 391 | ||
| 423 | std::u16string UTF8ToUTF16(const std::string& input) | 392 | std::u16string UTF8ToUTF16(const std::string& input) { |
| 424 | { | ||
| 425 | std::u16string result; | 393 | std::u16string result; |
| 426 | 394 | ||
| 427 | iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8"); | 395 | iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8"); |
| 428 | if ((iconv_t)(-1) == conv_desc) | 396 | if ((iconv_t)(-1) == conv_desc) { |
| 429 | { | ||
| 430 | LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno)); | 397 | LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno)); |
| 431 | iconv_close(conv_desc); | 398 | iconv_close(conv_desc); |
| 432 | return {}; | 399 | return {}; |
| @@ -444,24 +411,18 @@ std::u16string UTF8ToUTF16(const std::string& input) | |||
| 444 | char* dst_buffer = (char*)(&out_buffer[0]); | 411 | char* dst_buffer = (char*)(&out_buffer[0]); |
| 445 | size_t dst_bytes = out_buffer.size(); | 412 | size_t dst_bytes = out_buffer.size(); |
| 446 | 413 | ||
| 447 | while (0 != src_bytes) | 414 | while (0 != src_bytes) { |
| 448 | { | 415 | size_t const iconv_result = |
| 449 | size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes, | 416 | iconv(conv_desc, &src_buffer, &src_bytes, &dst_buffer, &dst_bytes); |
| 450 | &dst_buffer, &dst_bytes); | ||
| 451 | 417 | ||
| 452 | if (static_cast<size_t>(-1) == iconv_result) | 418 | if (static_cast<size_t>(-1) == iconv_result) { |
| 453 | { | 419 | if (EILSEQ == errno || EINVAL == errno) { |
| 454 | if (EILSEQ == errno || EINVAL == errno) | ||
| 455 | { | ||
| 456 | // Try to skip the bad character | 420 | // Try to skip the bad character |
| 457 | if (0 != src_bytes) | 421 | if (0 != src_bytes) { |
| 458 | { | ||
| 459 | --src_bytes; | 422 | --src_bytes; |
| 460 | ++src_buffer; | 423 | ++src_buffer; |
| 461 | } | 424 | } |
| 462 | } | 425 | } else { |
| 463 | else | ||
| 464 | { | ||
| 465 | LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno)); | 426 | LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno)); |
| 466 | break; | 427 | break; |
| 467 | } | 428 | } |
| @@ -476,32 +437,28 @@ std::u16string UTF8ToUTF16(const std::string& input) | |||
| 476 | return result; | 437 | return result; |
| 477 | } | 438 | } |
| 478 | 439 | ||
| 479 | std::string UTF16ToUTF8(const std::u16string& input) | 440 | std::string UTF16ToUTF8(const std::u16string& input) { |
| 480 | { | ||
| 481 | return CodeToUTF8("UTF-16LE", input); | 441 | return CodeToUTF8("UTF-16LE", input); |
| 482 | } | 442 | } |
| 483 | 443 | ||
| 484 | std::string CP1252ToUTF8(const std::string& input) | 444 | std::string CP1252ToUTF8(const std::string& input) { |
| 485 | { | 445 | // return CodeToUTF8("CP1252//TRANSLIT", input); |
| 486 | //return CodeToUTF8("CP1252//TRANSLIT", input); | 446 | // return CodeToUTF8("CP1252//IGNORE", input); |
| 487 | //return CodeToUTF8("CP1252//IGNORE", input); | ||
| 488 | return CodeToUTF8("CP1252", input); | 447 | return CodeToUTF8("CP1252", input); |
| 489 | } | 448 | } |
| 490 | 449 | ||
| 491 | std::string SHIFTJISToUTF8(const std::string& input) | 450 | std::string SHIFTJISToUTF8(const std::string& input) { |
| 492 | { | 451 | // return CodeToUTF8("CP932", input); |
| 493 | //return CodeToUTF8("CP932", input); | ||
| 494 | return CodeToUTF8("SJIS", input); | 452 | return CodeToUTF8("SJIS", input); |
| 495 | } | 453 | } |
| 496 | 454 | ||
| 497 | #endif | 455 | #endif |
| 498 | 456 | ||
| 499 | std::string StringFromFixedZeroTerminatedBuffer(const char * buffer, size_t max_len) { | 457 | std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len) { |
| 500 | size_t len = 0; | 458 | size_t len = 0; |
| 501 | while (len < max_len && buffer[len] != '\0') | 459 | while (len < max_len && buffer[len] != '\0') |
| 502 | ++len; | 460 | ++len; |
| 503 | 461 | ||
| 504 | return std::string(buffer, len); | 462 | return std::string(buffer, len); |
| 505 | } | 463 | } |
| 506 | |||
| 507 | } | 464 | } |
diff --git a/src/common/string_util.h b/src/common/string_util.h index 89d9f133e..075bf4ecb 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include <sstream> | 10 | #include <sstream> |
| 11 | #include <string> | 11 | #include <string> |
| 12 | #include <vector> | 12 | #include <vector> |
| 13 | |||
| 14 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 15 | 14 | ||
| 16 | namespace Common { | 15 | namespace Common { |
| @@ -25,9 +24,8 @@ std::string StringFromFormat(const char* format, ...); | |||
| 25 | // Cheap! | 24 | // Cheap! |
| 26 | bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); | 25 | bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); |
| 27 | 26 | ||
| 28 | template<size_t Count> | 27 | template <size_t Count> |
| 29 | inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) | 28 | inline void CharArrayFromFormat(char (&out)[Count], const char* format, ...) { |
| 30 | { | ||
| 31 | va_list args; | 29 | va_list args; |
| 32 | va_start(args, format); | 30 | va_start(args, format); |
| 33 | CharArrayFromFormatV(out, Count, format, args); | 31 | CharArrayFromFormatV(out, Count, format, args); |
| @@ -35,15 +33,14 @@ inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) | |||
| 35 | } | 33 | } |
| 36 | 34 | ||
| 37 | // Good | 35 | // Good |
| 38 | std::string ArrayToString(const u8 *data, u32 size, int line_len = 20, bool spaces = true); | 36 | std::string ArrayToString(const u8* data, u32 size, int line_len = 20, bool spaces = true); |
| 39 | 37 | ||
| 40 | std::string StripSpaces(const std::string &s); | 38 | std::string StripSpaces(const std::string& s); |
| 41 | std::string StripQuotes(const std::string &s); | 39 | std::string StripQuotes(const std::string& s); |
| 42 | 40 | ||
| 43 | // Thousand separator. Turns 12345678 into 12,345,678 | 41 | // Thousand separator. Turns 12345678 into 12,345,678 |
| 44 | template <typename I> | 42 | template <typename I> |
| 45 | std::string ThousandSeparate(I value, int spaces = 0) | 43 | std::string ThousandSeparate(I value, int spaces = 0) { |
| 46 | { | ||
| 47 | std::ostringstream oss; | 44 | std::ostringstream oss; |
| 48 | 45 | ||
| 49 | // std::locale("") seems to be broken on many platforms | 46 | // std::locale("") seems to be broken on many platforms |
| @@ -57,35 +54,34 @@ std::string ThousandSeparate(I value, int spaces = 0) | |||
| 57 | 54 | ||
| 58 | std::string StringFromBool(bool value); | 55 | std::string StringFromBool(bool value); |
| 59 | 56 | ||
| 60 | bool TryParse(const std::string &str, bool *output); | 57 | bool TryParse(const std::string& str, bool* output); |
| 61 | bool TryParse(const std::string &str, u32 *output); | 58 | bool TryParse(const std::string& str, u32* output); |
| 62 | 59 | ||
| 63 | template <typename N> | 60 | template <typename N> |
| 64 | static bool TryParse(const std::string &str, N *const output) | 61 | static bool TryParse(const std::string& str, N* const output) { |
| 65 | { | ||
| 66 | std::istringstream iss(str); | 62 | std::istringstream iss(str); |
| 67 | 63 | ||
| 68 | N tmp = 0; | 64 | N tmp = 0; |
| 69 | if (iss >> tmp) | 65 | if (iss >> tmp) { |
| 70 | { | ||
| 71 | *output = tmp; | 66 | *output = tmp; |
| 72 | return true; | 67 | return true; |
| 73 | } | 68 | } else |
| 74 | else | ||
| 75 | return false; | 69 | return false; |
| 76 | } | 70 | } |
| 77 | 71 | ||
| 78 | // TODO: kill this | 72 | // TODO: kill this |
| 79 | bool AsciiToHex(const char* _szValue, u32& result); | 73 | bool AsciiToHex(const char* _szValue, u32& result); |
| 80 | 74 | ||
| 81 | std::string TabsToSpaces(int tab_size, const std::string &in); | 75 | std::string TabsToSpaces(int tab_size, const std::string& in); |
| 82 | 76 | ||
| 83 | void SplitString(const std::string& str, char delim, std::vector<std::string>& output); | 77 | void SplitString(const std::string& str, char delim, std::vector<std::string>& output); |
| 84 | 78 | ||
| 85 | // "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" | 79 | // "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" |
| 86 | bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); | 80 | bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, |
| 81 | std::string* _pExtension); | ||
| 87 | 82 | ||
| 88 | void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename); | 83 | void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, |
| 84 | const std::string& _Filename); | ||
| 89 | std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); | 85 | std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); |
| 90 | 86 | ||
| 91 | std::string UTF16ToUTF8(const std::u16string& input); | 87 | std::string UTF16ToUTF8(const std::u16string& input); |
| @@ -99,17 +95,21 @@ std::string UTF16ToUTF8(const std::wstring& input); | |||
| 99 | std::wstring UTF8ToUTF16W(const std::string& str); | 95 | std::wstring UTF8ToUTF16W(const std::string& str); |
| 100 | 96 | ||
| 101 | #ifdef _UNICODE | 97 | #ifdef _UNICODE |
| 102 | inline std::string TStrToUTF8(const std::wstring& str) | 98 | inline std::string TStrToUTF8(const std::wstring& str) { |
| 103 | { return UTF16ToUTF8(str); } | 99 | return UTF16ToUTF8(str); |
| 100 | } | ||
| 104 | 101 | ||
| 105 | inline std::wstring UTF8ToTStr(const std::string& str) | 102 | inline std::wstring UTF8ToTStr(const std::string& str) { |
| 106 | { return UTF8ToUTF16W(str); } | 103 | return UTF8ToUTF16W(str); |
| 104 | } | ||
| 107 | #else | 105 | #else |
| 108 | inline std::string TStrToUTF8(const std::string& str) | 106 | inline std::string TStrToUTF8(const std::string& str) { |
| 109 | { return str; } | 107 | return str; |
| 108 | } | ||
| 110 | 109 | ||
| 111 | inline std::string UTF8ToTStr(const std::string& str) | 110 | inline std::string UTF8ToTStr(const std::string& str) { |
| 112 | { return str; } | 111 | return str; |
| 112 | } | ||
| 113 | #endif | 113 | #endif |
| 114 | 114 | ||
| 115 | #endif | 115 | #endif |
| @@ -134,5 +134,4 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) { | |||
| 134 | * NUL-terminated then the string ends at max_len characters. | 134 | * NUL-terminated then the string ends at max_len characters. |
| 135 | */ | 135 | */ |
| 136 | std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len); | 136 | std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len); |
| 137 | |||
| 138 | } | 137 | } |
diff --git a/src/common/swap.h b/src/common/swap.h index 1749bd7a4..e241c9f73 100644 --- a/src/common/swap.h +++ b/src/common/swap.h | |||
| @@ -18,15 +18,13 @@ | |||
| 18 | #pragma once | 18 | #pragma once |
| 19 | 19 | ||
| 20 | #if defined(_MSC_VER) | 20 | #if defined(_MSC_VER) |
| 21 | #include <cstdlib> | 21 | #include <cstdlib> |
| 22 | #elif defined(__linux__) | 22 | #elif defined(__linux__) |
| 23 | #include <byteswap.h> | 23 | #include <byteswap.h> |
| 24 | #elif defined(__FreeBSD__) | 24 | #elif defined(__FreeBSD__) |
| 25 | #include <sys/endian.h> | 25 | #include <sys/endian.h> |
| 26 | #endif | 26 | #endif |
| 27 | |||
| 28 | #include <cstring> | 27 | #include <cstring> |
| 29 | |||
| 30 | #include "common/common_types.h" | 28 | #include "common/common_types.h" |
| 31 | 29 | ||
| 32 | // GCC 4.6+ | 30 | // GCC 4.6+ |
| @@ -61,38 +59,73 @@ | |||
| 61 | namespace Common { | 59 | namespace Common { |
| 62 | 60 | ||
| 63 | #ifdef _MSC_VER | 61 | #ifdef _MSC_VER |
| 64 | inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} | 62 | inline u16 swap16(u16 _data) { |
| 65 | inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} | 63 | return _byteswap_ushort(_data); |
| 66 | inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} | 64 | } |
| 65 | inline u32 swap32(u32 _data) { | ||
| 66 | return _byteswap_ulong(_data); | ||
| 67 | } | ||
| 68 | inline u64 swap64(u64 _data) { | ||
| 69 | return _byteswap_uint64(_data); | ||
| 70 | } | ||
| 67 | #elif _M_ARM | 71 | #elif _M_ARM |
| 68 | inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} | 72 | inline u16 swap16(u16 _data) { |
| 69 | inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} | 73 | u32 data = _data; |
| 70 | inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} | 74 | __asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data)); |
| 75 | return (u16)data; | ||
| 76 | } | ||
| 77 | inline u32 swap32(u32 _data) { | ||
| 78 | __asm__("rev %0, %1\n" : "=l"(_data) : "l"(_data)); | ||
| 79 | return _data; | ||
| 80 | } | ||
| 81 | inline u64 swap64(u64 _data) { | ||
| 82 | return ((u64)swap32(_data) << 32) | swap32(_data >> 32); | ||
| 83 | } | ||
| 71 | #elif __linux__ | 84 | #elif __linux__ |
| 72 | inline u16 swap16(u16 _data) {return bswap_16(_data);} | 85 | inline u16 swap16(u16 _data) { |
| 73 | inline u32 swap32(u32 _data) {return bswap_32(_data);} | 86 | return bswap_16(_data); |
| 74 | inline u64 swap64(u64 _data) {return bswap_64(_data);} | 87 | } |
| 88 | inline u32 swap32(u32 _data) { | ||
| 89 | return bswap_32(_data); | ||
| 90 | } | ||
| 91 | inline u64 swap64(u64 _data) { | ||
| 92 | return bswap_64(_data); | ||
| 93 | } | ||
| 75 | #elif __APPLE__ | 94 | #elif __APPLE__ |
| 76 | inline __attribute__((always_inline)) u16 swap16(u16 _data) | 95 | inline __attribute__((always_inline)) u16 swap16(u16 _data) { |
| 77 | {return (_data >> 8) | (_data << 8);} | 96 | return (_data >> 8) | (_data << 8); |
| 78 | inline __attribute__((always_inline)) u32 swap32(u32 _data) | 97 | } |
| 79 | {return __builtin_bswap32(_data);} | 98 | inline __attribute__((always_inline)) u32 swap32(u32 _data) { |
| 80 | inline __attribute__((always_inline)) u64 swap64(u64 _data) | 99 | return __builtin_bswap32(_data); |
| 81 | {return __builtin_bswap64(_data);} | 100 | } |
| 101 | inline __attribute__((always_inline)) u64 swap64(u64 _data) { | ||
| 102 | return __builtin_bswap64(_data); | ||
| 103 | } | ||
| 82 | #elif __FreeBSD__ | 104 | #elif __FreeBSD__ |
| 83 | inline u16 swap16(u16 _data) {return bswap16(_data);} | 105 | inline u16 swap16(u16 _data) { |
| 84 | inline u32 swap32(u32 _data) {return bswap32(_data);} | 106 | return bswap16(_data); |
| 85 | inline u64 swap64(u64 _data) {return bswap64(_data);} | 107 | } |
| 108 | inline u32 swap32(u32 _data) { | ||
| 109 | return bswap32(_data); | ||
| 110 | } | ||
| 111 | inline u64 swap64(u64 _data) { | ||
| 112 | return bswap64(_data); | ||
| 113 | } | ||
| 86 | #else | 114 | #else |
| 87 | // Slow generic implementation. | 115 | // Slow generic implementation. |
| 88 | inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} | 116 | inline u16 swap16(u16 data) { |
| 89 | inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} | 117 | return (data >> 8) | (data << 8); |
| 90 | inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} | 118 | } |
| 119 | inline u32 swap32(u32 data) { | ||
| 120 | return (swap16(data) << 16) | swap16(data >> 16); | ||
| 121 | } | ||
| 122 | inline u64 swap64(u64 data) { | ||
| 123 | return ((u64)swap32(data) << 32) | swap32(data >> 32); | ||
| 124 | } | ||
| 91 | #endif | 125 | #endif |
| 92 | 126 | ||
| 93 | inline float swapf(float f) { | 127 | inline float swapf(float f) { |
| 94 | static_assert(sizeof(u32) == sizeof(float), | 128 | static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t."); |
| 95 | "float must be the same size as uint32_t."); | ||
| 96 | 129 | ||
| 97 | u32 value; | 130 | u32 value; |
| 98 | std::memcpy(&value, &f, sizeof(u32)); | 131 | std::memcpy(&value, &f, sizeof(u32)); |
| @@ -104,8 +137,7 @@ inline float swapf(float f) { | |||
| 104 | } | 137 | } |
| 105 | 138 | ||
| 106 | inline double swapd(double f) { | 139 | inline double swapd(double f) { |
| 107 | static_assert(sizeof(u64) == sizeof(double), | 140 | static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t."); |
| 108 | "double must be the same size as uint64_t."); | ||
| 109 | 141 | ||
| 110 | u64 value; | 142 | u64 value; |
| 111 | std::memcpy(&value, &f, sizeof(u64)); | 143 | std::memcpy(&value, &f, sizeof(u64)); |
| @@ -116,8 +148,7 @@ inline double swapd(double f) { | |||
| 116 | return f; | 148 | return f; |
| 117 | } | 149 | } |
| 118 | 150 | ||
| 119 | } // Namespace Common | 151 | } // Namespace Common |
| 120 | |||
| 121 | 152 | ||
| 122 | template <typename T, typename F> | 153 | template <typename T, typename F> |
| 123 | struct swap_struct_t { | 154 | struct swap_struct_t { |
| @@ -129,251 +160,271 @@ protected: | |||
| 129 | static T swap(T v) { | 160 | static T swap(T v) { |
| 130 | return F::swap(v); | 161 | return F::swap(v); |
| 131 | } | 162 | } |
| 163 | |||
| 132 | public: | 164 | public: |
| 133 | T const swap() const { | 165 | T const swap() const { |
| 134 | return swap(value); | 166 | return swap(value); |
| 135 | |||
| 136 | } | 167 | } |
| 137 | swap_struct_t() = default; | 168 | swap_struct_t() = default; |
| 138 | swap_struct_t(const T &v): value(swap(v)) {} | 169 | swap_struct_t(const T& v) : value(swap(v)) {} |
| 139 | 170 | ||
| 140 | template <typename S> | 171 | template <typename S> |
| 141 | swapped_t& operator=(const S &source) { | 172 | swapped_t& operator=(const S& source) { |
| 142 | value = swap((T)source); | 173 | value = swap((T)source); |
| 143 | return *this; | 174 | return *this; |
| 144 | } | 175 | } |
| 145 | 176 | ||
| 146 | operator s8() const { return (s8)swap(); } | 177 | operator s8() const { |
| 147 | operator u8() const { return (u8)swap(); } | 178 | return (s8)swap(); |
| 148 | operator s16() const { return (s16)swap(); } | 179 | } |
| 149 | operator u16() const { return (u16)swap(); } | 180 | operator u8() const { |
| 150 | operator s32() const { return (s32)swap(); } | 181 | return (u8)swap(); |
| 151 | operator u32() const { return (u32)swap(); } | 182 | } |
| 152 | operator s64() const { return (s64)swap(); } | 183 | operator s16() const { |
| 153 | operator u64() const { return (u64)swap(); } | 184 | return (s16)swap(); |
| 154 | operator float() const { return (float)swap(); } | 185 | } |
| 155 | operator double() const { return (double)swap(); } | 186 | operator u16() const { |
| 187 | return (u16)swap(); | ||
| 188 | } | ||
| 189 | operator s32() const { | ||
| 190 | return (s32)swap(); | ||
| 191 | } | ||
| 192 | operator u32() const { | ||
| 193 | return (u32)swap(); | ||
| 194 | } | ||
| 195 | operator s64() const { | ||
| 196 | return (s64)swap(); | ||
| 197 | } | ||
| 198 | operator u64() const { | ||
| 199 | return (u64)swap(); | ||
| 200 | } | ||
| 201 | operator float() const { | ||
| 202 | return (float)swap(); | ||
| 203 | } | ||
| 204 | operator double() const { | ||
| 205 | return (double)swap(); | ||
| 206 | } | ||
| 156 | 207 | ||
| 157 | // +v | 208 | // +v |
| 158 | swapped_t operator +() const { | 209 | swapped_t operator+() const { |
| 159 | return +swap(); | 210 | return +swap(); |
| 160 | } | 211 | } |
| 161 | // -v | 212 | // -v |
| 162 | swapped_t operator -() const { | 213 | swapped_t operator-() const { |
| 163 | return -swap(); | 214 | return -swap(); |
| 164 | } | 215 | } |
| 165 | 216 | ||
| 166 | // v / 5 | 217 | // v / 5 |
| 167 | swapped_t operator/(const swapped_t &i) const { | 218 | swapped_t operator/(const swapped_t& i) const { |
| 168 | return swap() / i.swap(); | 219 | return swap() / i.swap(); |
| 169 | } | 220 | } |
| 170 | template <typename S> | 221 | template <typename S> |
| 171 | swapped_t operator/(const S &i) const { | 222 | swapped_t operator/(const S& i) const { |
| 172 | return swap() / i; | 223 | return swap() / i; |
| 173 | } | 224 | } |
| 174 | 225 | ||
| 175 | // v * 5 | 226 | // v * 5 |
| 176 | swapped_t operator*(const swapped_t &i) const { | 227 | swapped_t operator*(const swapped_t& i) const { |
| 177 | return swap() * i.swap(); | 228 | return swap() * i.swap(); |
| 178 | } | 229 | } |
| 179 | template <typename S> | 230 | template <typename S> |
| 180 | swapped_t operator*(const S &i) const { | 231 | swapped_t operator*(const S& i) const { |
| 181 | return swap() * i; | 232 | return swap() * i; |
| 182 | } | 233 | } |
| 183 | 234 | ||
| 184 | // v + 5 | 235 | // v + 5 |
| 185 | swapped_t operator+(const swapped_t &i) const { | 236 | swapped_t operator+(const swapped_t& i) const { |
| 186 | return swap() + i.swap(); | 237 | return swap() + i.swap(); |
| 187 | } | 238 | } |
| 188 | template <typename S> | 239 | template <typename S> |
| 189 | swapped_t operator+(const S &i) const { | 240 | swapped_t operator+(const S& i) const { |
| 190 | return swap() + (T)i; | 241 | return swap() + (T)i; |
| 191 | } | 242 | } |
| 192 | // v - 5 | 243 | // v - 5 |
| 193 | swapped_t operator-(const swapped_t &i) const { | 244 | swapped_t operator-(const swapped_t& i) const { |
| 194 | return swap() - i.swap(); | 245 | return swap() - i.swap(); |
| 195 | } | 246 | } |
| 196 | template <typename S> | 247 | template <typename S> |
| 197 | swapped_t operator-(const S &i) const { | 248 | swapped_t operator-(const S& i) const { |
| 198 | return swap() - (T)i; | 249 | return swap() - (T)i; |
| 199 | } | 250 | } |
| 200 | 251 | ||
| 201 | // v += 5 | 252 | // v += 5 |
| 202 | swapped_t& operator+=(const swapped_t &i) { | 253 | swapped_t& operator+=(const swapped_t& i) { |
| 203 | value = swap(swap() + i.swap()); | 254 | value = swap(swap() + i.swap()); |
| 204 | return *this; | 255 | return *this; |
| 205 | } | 256 | } |
| 206 | template <typename S> | 257 | template <typename S> |
| 207 | swapped_t& operator+=(const S &i) { | 258 | swapped_t& operator+=(const S& i) { |
| 208 | value = swap(swap() + (T)i); | 259 | value = swap(swap() + (T)i); |
| 209 | return *this; | 260 | return *this; |
| 210 | } | 261 | } |
| 211 | // v -= 5 | 262 | // v -= 5 |
| 212 | swapped_t& operator-=(const swapped_t &i) { | 263 | swapped_t& operator-=(const swapped_t& i) { |
| 213 | value = swap(swap() - i.swap()); | 264 | value = swap(swap() - i.swap()); |
| 214 | return *this; | 265 | return *this; |
| 215 | } | 266 | } |
| 216 | template <typename S> | 267 | template <typename S> |
| 217 | swapped_t& operator-=(const S &i) { | 268 | swapped_t& operator-=(const S& i) { |
| 218 | value = swap(swap() - (T)i); | 269 | value = swap(swap() - (T)i); |
| 219 | return *this; | 270 | return *this; |
| 220 | } | 271 | } |
| 221 | 272 | ||
| 222 | // ++v | 273 | // ++v |
| 223 | swapped_t& operator++() { | 274 | swapped_t& operator++() { |
| 224 | value = swap(swap()+1); | 275 | value = swap(swap() + 1); |
| 225 | return *this; | 276 | return *this; |
| 226 | } | 277 | } |
| 227 | // --v | 278 | // --v |
| 228 | swapped_t& operator--() { | 279 | swapped_t& operator--() { |
| 229 | value = swap(swap()-1); | 280 | value = swap(swap() - 1); |
| 230 | return *this; | 281 | return *this; |
| 231 | } | 282 | } |
| 232 | 283 | ||
| 233 | // v++ | 284 | // v++ |
| 234 | swapped_t operator++(int) { | 285 | swapped_t operator++(int) { |
| 235 | swapped_t old = *this; | 286 | swapped_t old = *this; |
| 236 | value = swap(swap()+1); | 287 | value = swap(swap() + 1); |
| 237 | return old; | 288 | return old; |
| 238 | } | 289 | } |
| 239 | // v-- | 290 | // v-- |
| 240 | swapped_t operator--(int) { | 291 | swapped_t operator--(int) { |
| 241 | swapped_t old = *this; | 292 | swapped_t old = *this; |
| 242 | value = swap(swap()-1); | 293 | value = swap(swap() - 1); |
| 243 | return old; | 294 | return old; |
| 244 | } | 295 | } |
| 245 | // Comparaison | 296 | // Comparaison |
| 246 | // v == i | 297 | // v == i |
| 247 | bool operator==(const swapped_t &i) const { | 298 | bool operator==(const swapped_t& i) const { |
| 248 | return swap() == i.swap(); | 299 | return swap() == i.swap(); |
| 249 | } | 300 | } |
| 250 | template <typename S> | 301 | template <typename S> |
| 251 | bool operator==(const S &i) const { | 302 | bool operator==(const S& i) const { |
| 252 | return swap() == i; | 303 | return swap() == i; |
| 253 | } | 304 | } |
| 254 | 305 | ||
| 255 | // v != i | 306 | // v != i |
| 256 | bool operator!=(const swapped_t &i) const { | 307 | bool operator!=(const swapped_t& i) const { |
| 257 | return swap() != i.swap(); | 308 | return swap() != i.swap(); |
| 258 | } | 309 | } |
| 259 | template <typename S> | 310 | template <typename S> |
| 260 | bool operator!=(const S &i) const { | 311 | bool operator!=(const S& i) const { |
| 261 | return swap() != i; | 312 | return swap() != i; |
| 262 | } | 313 | } |
| 263 | 314 | ||
| 264 | // v > i | 315 | // v > i |
| 265 | bool operator>(const swapped_t &i) const { | 316 | bool operator>(const swapped_t& i) const { |
| 266 | return swap() > i.swap(); | 317 | return swap() > i.swap(); |
| 267 | } | 318 | } |
| 268 | template <typename S> | 319 | template <typename S> |
| 269 | bool operator>(const S &i) const { | 320 | bool operator>(const S& i) const { |
| 270 | return swap() > i; | 321 | return swap() > i; |
| 271 | } | 322 | } |
| 272 | 323 | ||
| 273 | // v < i | 324 | // v < i |
| 274 | bool operator<(const swapped_t &i) const { | 325 | bool operator<(const swapped_t& i) const { |
| 275 | return swap() < i.swap(); | 326 | return swap() < i.swap(); |
| 276 | } | 327 | } |
| 277 | template <typename S> | 328 | template <typename S> |
| 278 | bool operator<(const S &i) const { | 329 | bool operator<(const S& i) const { |
| 279 | return swap() < i; | 330 | return swap() < i; |
| 280 | } | 331 | } |
| 281 | 332 | ||
| 282 | // v >= i | 333 | // v >= i |
| 283 | bool operator>=(const swapped_t &i) const { | 334 | bool operator>=(const swapped_t& i) const { |
| 284 | return swap() >= i.swap(); | 335 | return swap() >= i.swap(); |
| 285 | } | 336 | } |
| 286 | template <typename S> | 337 | template <typename S> |
| 287 | bool operator>=(const S &i) const { | 338 | bool operator>=(const S& i) const { |
| 288 | return swap() >= i; | 339 | return swap() >= i; |
| 289 | } | 340 | } |
| 290 | 341 | ||
| 291 | // v <= i | 342 | // v <= i |
| 292 | bool operator<=(const swapped_t &i) const { | 343 | bool operator<=(const swapped_t& i) const { |
| 293 | return swap() <= i.swap(); | 344 | return swap() <= i.swap(); |
| 294 | } | 345 | } |
| 295 | template <typename S> | 346 | template <typename S> |
| 296 | bool operator<=(const S &i) const { | 347 | bool operator<=(const S& i) const { |
| 297 | return swap() <= i; | 348 | return swap() <= i; |
| 298 | } | 349 | } |
| 299 | 350 | ||
| 300 | // logical | 351 | // logical |
| 301 | swapped_t operator !() const { | 352 | swapped_t operator!() const { |
| 302 | return !swap(); | 353 | return !swap(); |
| 303 | } | 354 | } |
| 304 | 355 | ||
| 305 | // bitmath | 356 | // bitmath |
| 306 | swapped_t operator ~() const { | 357 | swapped_t operator~() const { |
| 307 | return ~swap(); | 358 | return ~swap(); |
| 308 | } | 359 | } |
| 309 | 360 | ||
| 310 | swapped_t operator &(const swapped_t &b) const { | 361 | swapped_t operator&(const swapped_t& b) const { |
| 311 | return swap() & b.swap(); | 362 | return swap() & b.swap(); |
| 312 | } | 363 | } |
| 313 | template <typename S> | 364 | template <typename S> |
| 314 | swapped_t operator &(const S &b) const { | 365 | swapped_t operator&(const S& b) const { |
| 315 | return swap() & b; | 366 | return swap() & b; |
| 316 | } | 367 | } |
| 317 | swapped_t& operator &=(const swapped_t &b) { | 368 | swapped_t& operator&=(const swapped_t& b) { |
| 318 | value = swap(swap() & b.swap()); | 369 | value = swap(swap() & b.swap()); |
| 319 | return *this; | 370 | return *this; |
| 320 | } | 371 | } |
| 321 | template <typename S> | 372 | template <typename S> |
| 322 | swapped_t& operator &=(const S b) { | 373 | swapped_t& operator&=(const S b) { |
| 323 | value = swap(swap() & b); | 374 | value = swap(swap() & b); |
| 324 | return *this; | 375 | return *this; |
| 325 | } | 376 | } |
| 326 | 377 | ||
| 327 | swapped_t operator |(const swapped_t &b) const { | 378 | swapped_t operator|(const swapped_t& b) const { |
| 328 | return swap() | b.swap(); | 379 | return swap() | b.swap(); |
| 329 | } | 380 | } |
| 330 | template <typename S> | 381 | template <typename S> |
| 331 | swapped_t operator |(const S &b) const { | 382 | swapped_t operator|(const S& b) const { |
| 332 | return swap() | b; | 383 | return swap() | b; |
| 333 | } | 384 | } |
| 334 | swapped_t& operator |=(const swapped_t &b) { | 385 | swapped_t& operator|=(const swapped_t& b) { |
| 335 | value = swap(swap() | b.swap()); | 386 | value = swap(swap() | b.swap()); |
| 336 | return *this; | 387 | return *this; |
| 337 | } | 388 | } |
| 338 | template <typename S> | 389 | template <typename S> |
| 339 | swapped_t& operator |=(const S &b) { | 390 | swapped_t& operator|=(const S& b) { |
| 340 | value = swap(swap() | b); | 391 | value = swap(swap() | b); |
| 341 | return *this; | 392 | return *this; |
| 342 | } | 393 | } |
| 343 | 394 | ||
| 344 | swapped_t operator ^(const swapped_t &b) const { | 395 | swapped_t operator^(const swapped_t& b) const { |
| 345 | return swap() ^ b.swap(); | 396 | return swap() ^ b.swap(); |
| 346 | } | 397 | } |
| 347 | template <typename S> | 398 | template <typename S> |
| 348 | swapped_t operator ^(const S &b) const { | 399 | swapped_t operator^(const S& b) const { |
| 349 | return swap() ^ b; | 400 | return swap() ^ b; |
| 350 | } | 401 | } |
| 351 | swapped_t& operator ^=(const swapped_t &b) { | 402 | swapped_t& operator^=(const swapped_t& b) { |
| 352 | value = swap(swap() ^ b.swap()); | 403 | value = swap(swap() ^ b.swap()); |
| 353 | return *this; | 404 | return *this; |
| 354 | } | 405 | } |
| 355 | template <typename S> | 406 | template <typename S> |
| 356 | swapped_t& operator ^=(const S &b) { | 407 | swapped_t& operator^=(const S& b) { |
| 357 | value = swap(swap() ^ b); | 408 | value = swap(swap() ^ b); |
| 358 | return *this; | 409 | return *this; |
| 359 | } | 410 | } |
| 360 | 411 | ||
| 361 | template <typename S> | 412 | template <typename S> |
| 362 | swapped_t operator <<(const S &b) const { | 413 | swapped_t operator<<(const S& b) const { |
| 363 | return swap() << b; | 414 | return swap() << b; |
| 364 | } | 415 | } |
| 365 | template <typename S> | 416 | template <typename S> |
| 366 | swapped_t& operator <<=(const S &b) const { | 417 | swapped_t& operator<<=(const S& b) const { |
| 367 | value = swap(swap() << b); | 418 | value = swap(swap() << b); |
| 368 | return *this; | 419 | return *this; |
| 369 | } | 420 | } |
| 370 | 421 | ||
| 371 | template <typename S> | 422 | template <typename S> |
| 372 | swapped_t operator >>(const S &b) const { | 423 | swapped_t operator>>(const S& b) const { |
| 373 | return swap() >> b; | 424 | return swap() >> b; |
| 374 | } | 425 | } |
| 375 | template <typename S> | 426 | template <typename S> |
| 376 | swapped_t& operator >>=(const S &b) const { | 427 | swapped_t& operator>>=(const S& b) const { |
| 377 | value = swap(swap() >> b); | 428 | value = swap(swap() >> b); |
| 378 | return *this; | 429 | return *this; |
| 379 | } | 430 | } |
| @@ -381,129 +432,126 @@ public: | |||
| 381 | // Member | 432 | // Member |
| 382 | /** todo **/ | 433 | /** todo **/ |
| 383 | 434 | ||
| 384 | |||
| 385 | // Arithmetics | 435 | // Arithmetics |
| 386 | template <typename S, typename T2, typename F2> | 436 | template <typename S, typename T2, typename F2> |
| 387 | friend S operator+(const S &p, const swapped_t v); | 437 | friend S operator+(const S& p, const swapped_t v); |
| 388 | 438 | ||
| 389 | template <typename S, typename T2, typename F2> | 439 | template <typename S, typename T2, typename F2> |
| 390 | friend S operator-(const S &p, const swapped_t v); | 440 | friend S operator-(const S& p, const swapped_t v); |
| 391 | 441 | ||
| 392 | template <typename S, typename T2, typename F2> | 442 | template <typename S, typename T2, typename F2> |
| 393 | friend S operator/(const S &p, const swapped_t v); | 443 | friend S operator/(const S& p, const swapped_t v); |
| 394 | 444 | ||
| 395 | template <typename S, typename T2, typename F2> | 445 | template <typename S, typename T2, typename F2> |
| 396 | friend S operator*(const S &p, const swapped_t v); | 446 | friend S operator*(const S& p, const swapped_t v); |
| 397 | 447 | ||
| 398 | template <typename S, typename T2, typename F2> | 448 | template <typename S, typename T2, typename F2> |
| 399 | friend S operator%(const S &p, const swapped_t v); | 449 | friend S operator%(const S& p, const swapped_t v); |
| 400 | 450 | ||
| 401 | // Arithmetics + assignements | 451 | // Arithmetics + assignements |
| 402 | template <typename S, typename T2, typename F2> | 452 | template <typename S, typename T2, typename F2> |
| 403 | friend S operator+=(const S &p, const swapped_t v); | 453 | friend S operator+=(const S& p, const swapped_t v); |
| 404 | 454 | ||
| 405 | template <typename S, typename T2, typename F2> | 455 | template <typename S, typename T2, typename F2> |
| 406 | friend S operator-=(const S &p, const swapped_t v); | 456 | friend S operator-=(const S& p, const swapped_t v); |
| 407 | 457 | ||
| 408 | // Bitmath | 458 | // Bitmath |
| 409 | template <typename S, typename T2, typename F2> | 459 | template <typename S, typename T2, typename F2> |
| 410 | friend S operator&(const S &p, const swapped_t v); | 460 | friend S operator&(const S& p, const swapped_t v); |
| 411 | 461 | ||
| 412 | // Comparison | 462 | // Comparison |
| 413 | template <typename S, typename T2, typename F2> | 463 | template <typename S, typename T2, typename F2> |
| 414 | friend bool operator<(const S &p, const swapped_t v); | 464 | friend bool operator<(const S& p, const swapped_t v); |
| 415 | 465 | ||
| 416 | template <typename S, typename T2, typename F2> | 466 | template <typename S, typename T2, typename F2> |
| 417 | friend bool operator>(const S &p, const swapped_t v); | 467 | friend bool operator>(const S& p, const swapped_t v); |
| 418 | 468 | ||
| 419 | template <typename S, typename T2, typename F2> | 469 | template <typename S, typename T2, typename F2> |
| 420 | friend bool operator<=(const S &p, const swapped_t v); | 470 | friend bool operator<=(const S& p, const swapped_t v); |
| 421 | 471 | ||
| 422 | template <typename S, typename T2, typename F2> | 472 | template <typename S, typename T2, typename F2> |
| 423 | friend bool operator>=(const S &p, const swapped_t v); | 473 | friend bool operator>=(const S& p, const swapped_t v); |
| 424 | 474 | ||
| 425 | template <typename S, typename T2, typename F2> | 475 | template <typename S, typename T2, typename F2> |
| 426 | friend bool operator!=(const S &p, const swapped_t v); | 476 | friend bool operator!=(const S& p, const swapped_t v); |
| 427 | 477 | ||
| 428 | template <typename S, typename T2, typename F2> | 478 | template <typename S, typename T2, typename F2> |
| 429 | friend bool operator==(const S &p, const swapped_t v); | 479 | friend bool operator==(const S& p, const swapped_t v); |
| 430 | }; | 480 | }; |
| 431 | 481 | ||
| 432 | |||
| 433 | // Arithmetics | 482 | // Arithmetics |
| 434 | template <typename S, typename T, typename F> | 483 | template <typename S, typename T, typename F> |
| 435 | S operator+(const S &i, const swap_struct_t<T, F> v) { | 484 | S operator+(const S& i, const swap_struct_t<T, F> v) { |
| 436 | return i + v.swap(); | 485 | return i + v.swap(); |
| 437 | } | 486 | } |
| 438 | 487 | ||
| 439 | template <typename S, typename T, typename F> | 488 | template <typename S, typename T, typename F> |
| 440 | S operator-(const S &i, const swap_struct_t<T, F> v) { | 489 | S operator-(const S& i, const swap_struct_t<T, F> v) { |
| 441 | return i - v.swap(); | 490 | return i - v.swap(); |
| 442 | } | 491 | } |
| 443 | 492 | ||
| 444 | template <typename S, typename T, typename F> | 493 | template <typename S, typename T, typename F> |
| 445 | S operator/(const S &i, const swap_struct_t<T, F> v) { | 494 | S operator/(const S& i, const swap_struct_t<T, F> v) { |
| 446 | return i / v.swap(); | 495 | return i / v.swap(); |
| 447 | } | 496 | } |
| 448 | 497 | ||
| 449 | template <typename S, typename T, typename F> | 498 | template <typename S, typename T, typename F> |
| 450 | S operator*(const S &i, const swap_struct_t<T, F> v) { | 499 | S operator*(const S& i, const swap_struct_t<T, F> v) { |
| 451 | return i * v.swap(); | 500 | return i * v.swap(); |
| 452 | } | 501 | } |
| 453 | 502 | ||
| 454 | template <typename S, typename T, typename F> | 503 | template <typename S, typename T, typename F> |
| 455 | S operator%(const S &i, const swap_struct_t<T, F> v) { | 504 | S operator%(const S& i, const swap_struct_t<T, F> v) { |
| 456 | return i % v.swap(); | 505 | return i % v.swap(); |
| 457 | } | 506 | } |
| 458 | 507 | ||
| 459 | // Arithmetics + assignements | 508 | // Arithmetics + assignements |
| 460 | template <typename S, typename T, typename F> | 509 | template <typename S, typename T, typename F> |
| 461 | S &operator+=(S &i, const swap_struct_t<T, F> v) { | 510 | S& operator+=(S& i, const swap_struct_t<T, F> v) { |
| 462 | i += v.swap(); | 511 | i += v.swap(); |
| 463 | return i; | 512 | return i; |
| 464 | } | 513 | } |
| 465 | 514 | ||
| 466 | template <typename S, typename T, typename F> | 515 | template <typename S, typename T, typename F> |
| 467 | S &operator-=(S &i, const swap_struct_t<T, F> v) { | 516 | S& operator-=(S& i, const swap_struct_t<T, F> v) { |
| 468 | i -= v.swap(); | 517 | i -= v.swap(); |
| 469 | return i; | 518 | return i; |
| 470 | } | 519 | } |
| 471 | 520 | ||
| 472 | // Logical | 521 | // Logical |
| 473 | template <typename S, typename T, typename F> | 522 | template <typename S, typename T, typename F> |
| 474 | S operator&(const S &i, const swap_struct_t<T, F> v) { | 523 | S operator&(const S& i, const swap_struct_t<T, F> v) { |
| 475 | return i & v.swap(); | 524 | return i & v.swap(); |
| 476 | } | 525 | } |
| 477 | 526 | ||
| 478 | template <typename S, typename T, typename F> | 527 | template <typename S, typename T, typename F> |
| 479 | S operator&(const swap_struct_t<T, F> v, const S &i) { | 528 | S operator&(const swap_struct_t<T, F> v, const S& i) { |
| 480 | return (S)(v.swap() & i); | 529 | return (S)(v.swap() & i); |
| 481 | } | 530 | } |
| 482 | 531 | ||
| 483 | |||
| 484 | // Comparaison | 532 | // Comparaison |
| 485 | template <typename S, typename T, typename F> | 533 | template <typename S, typename T, typename F> |
| 486 | bool operator<(const S &p, const swap_struct_t<T, F> v) { | 534 | bool operator<(const S& p, const swap_struct_t<T, F> v) { |
| 487 | return p < v.swap(); | 535 | return p < v.swap(); |
| 488 | } | 536 | } |
| 489 | template <typename S, typename T, typename F> | 537 | template <typename S, typename T, typename F> |
| 490 | bool operator>(const S &p, const swap_struct_t<T, F> v) { | 538 | bool operator>(const S& p, const swap_struct_t<T, F> v) { |
| 491 | return p > v.swap(); | 539 | return p > v.swap(); |
| 492 | } | 540 | } |
| 493 | template <typename S, typename T, typename F> | 541 | template <typename S, typename T, typename F> |
| 494 | bool operator<=(const S &p, const swap_struct_t<T, F> v) { | 542 | bool operator<=(const S& p, const swap_struct_t<T, F> v) { |
| 495 | return p <= v.swap(); | 543 | return p <= v.swap(); |
| 496 | } | 544 | } |
| 497 | template <typename S, typename T, typename F> | 545 | template <typename S, typename T, typename F> |
| 498 | bool operator>=(const S &p, const swap_struct_t<T, F> v) { | 546 | bool operator>=(const S& p, const swap_struct_t<T, F> v) { |
| 499 | return p >= v.swap(); | 547 | return p >= v.swap(); |
| 500 | } | 548 | } |
| 501 | template <typename S, typename T, typename F> | 549 | template <typename S, typename T, typename F> |
| 502 | bool operator!=(const S &p, const swap_struct_t<T, F> v) { | 550 | bool operator!=(const S& p, const swap_struct_t<T, F> v) { |
| 503 | return p != v.swap(); | 551 | return p != v.swap(); |
| 504 | } | 552 | } |
| 505 | template <typename S, typename T, typename F> | 553 | template <typename S, typename T, typename F> |
| 506 | bool operator==(const S &p, const swap_struct_t<T, F> v) { | 554 | bool operator==(const S& p, const swap_struct_t<T, F> v) { |
| 507 | return p == v.swap(); | 555 | return p == v.swap(); |
| 508 | } | 556 | } |
| 509 | 557 | ||
| @@ -554,30 +602,30 @@ typedef s64 s64_le; | |||
| 554 | typedef float float_le; | 602 | typedef float float_le; |
| 555 | typedef double double_le; | 603 | typedef double double_le; |
| 556 | 604 | ||
| 557 | typedef swap_struct_t<u64, swap_64_t<u64> > u64_be; | 605 | typedef swap_struct_t<u64, swap_64_t<u64>> u64_be; |
| 558 | typedef swap_struct_t<s64, swap_64_t<s64> > s64_be; | 606 | typedef swap_struct_t<s64, swap_64_t<s64>> s64_be; |
| 559 | 607 | ||
| 560 | typedef swap_struct_t<u32, swap_32_t<u32> > u32_be; | 608 | typedef swap_struct_t<u32, swap_32_t<u32>> u32_be; |
| 561 | typedef swap_struct_t<s32, swap_32_t<s32> > s32_be; | 609 | typedef swap_struct_t<s32, swap_32_t<s32>> s32_be; |
| 562 | 610 | ||
| 563 | typedef swap_struct_t<u16, swap_16_t<u16> > u16_be; | 611 | typedef swap_struct_t<u16, swap_16_t<u16>> u16_be; |
| 564 | typedef swap_struct_t<s16, swap_16_t<s16> > s16_be; | 612 | typedef swap_struct_t<s16, swap_16_t<s16>> s16_be; |
| 565 | 613 | ||
| 566 | typedef swap_struct_t<float, swap_float_t<float> > float_be; | 614 | typedef swap_struct_t<float, swap_float_t<float>> float_be; |
| 567 | typedef swap_struct_t<double, swap_double_t<double> > double_be; | 615 | typedef swap_struct_t<double, swap_double_t<double>> double_be; |
| 568 | #else | 616 | #else |
| 569 | 617 | ||
| 570 | typedef swap_struct_t<u64, swap_64_t<u64> > u64_le; | 618 | typedef swap_struct_t<u64, swap_64_t<u64>> u64_le; |
| 571 | typedef swap_struct_t<s64, swap_64_t<s64> > s64_le; | 619 | typedef swap_struct_t<s64, swap_64_t<s64>> s64_le; |
| 572 | 620 | ||
| 573 | typedef swap_struct_t<u32, swap_32_t<u32> > u32_le; | 621 | typedef swap_struct_t<u32, swap_32_t<u32>> u32_le; |
| 574 | typedef swap_struct_t<s32, swap_32_t<s32> > s32_le; | 622 | typedef swap_struct_t<s32, swap_32_t<s32>> s32_le; |
| 575 | 623 | ||
| 576 | typedef swap_struct_t<u16, swap_16_t<u16> > u16_le; | 624 | typedef swap_struct_t<u16, swap_16_t<u16>> u16_le; |
| 577 | typedef swap_struct_t< s16, swap_16_t<s16> > s16_le; | 625 | typedef swap_struct_t<s16, swap_16_t<s16>> s16_le; |
| 578 | 626 | ||
| 579 | typedef swap_struct_t<float, swap_float_t<float> > float_le; | 627 | typedef swap_struct_t<float, swap_float_t<float>> float_le; |
| 580 | typedef swap_struct_t<double, swap_double_t<double> > double_le; | 628 | typedef swap_struct_t<double, swap_double_t<double>> double_le; |
| 581 | 629 | ||
| 582 | typedef u32 u32_be; | 630 | typedef u32 u32_be; |
| 583 | typedef u16 u16_be; | 631 | typedef u16 u16_be; |
diff --git a/src/common/symbols.cpp b/src/common/symbols.cpp index db8340043..c4d16af85 100644 --- a/src/common/symbols.cpp +++ b/src/common/symbols.cpp | |||
| @@ -6,49 +6,41 @@ | |||
| 6 | 6 | ||
| 7 | TSymbolsMap g_symbols; | 7 | TSymbolsMap g_symbols; |
| 8 | 8 | ||
| 9 | namespace Symbols | 9 | namespace Symbols { |
| 10 | { | 10 | bool HasSymbol(u32 address) { |
| 11 | bool HasSymbol(u32 address) | 11 | return g_symbols.find(address) != g_symbols.end(); |
| 12 | { | 12 | } |
| 13 | return g_symbols.find(address) != g_symbols.end(); | 13 | |
| 14 | } | 14 | void Add(u32 address, const std::string& name, u32 size, u32 type) { |
| 15 | if (!HasSymbol(address)) { | ||
| 16 | TSymbol symbol; | ||
| 17 | symbol.address = address; | ||
| 18 | symbol.name = name; | ||
| 19 | symbol.size = size; | ||
| 20 | symbol.type = type; | ||
| 15 | 21 | ||
| 16 | void Add(u32 address, const std::string& name, u32 size, u32 type) | 22 | g_symbols.emplace(address, symbol); |
| 17 | { | ||
| 18 | if (!HasSymbol(address)) | ||
| 19 | { | ||
| 20 | TSymbol symbol; | ||
| 21 | symbol.address = address; | ||
| 22 | symbol.name = name; | ||
| 23 | symbol.size = size; | ||
| 24 | symbol.type = type; | ||
| 25 | |||
| 26 | g_symbols.emplace(address, symbol); | ||
| 27 | } | ||
| 28 | } | 23 | } |
| 24 | } | ||
| 29 | 25 | ||
| 30 | TSymbol GetSymbol(u32 address) | 26 | TSymbol GetSymbol(u32 address) { |
| 31 | { | 27 | const auto iter = g_symbols.find(address); |
| 32 | const auto iter = g_symbols.find(address); | ||
| 33 | 28 | ||
| 34 | if (iter != g_symbols.end()) | 29 | if (iter != g_symbols.end()) |
| 35 | return iter->second; | 30 | return iter->second; |
| 36 | 31 | ||
| 37 | return {}; | 32 | return {}; |
| 38 | } | 33 | } |
| 39 | 34 | ||
| 40 | const std::string GetName(u32 address) | 35 | const std::string GetName(u32 address) { |
| 41 | { | 36 | return GetSymbol(address).name; |
| 42 | return GetSymbol(address).name; | 37 | } |
| 43 | } | ||
| 44 | 38 | ||
| 45 | void Remove(u32 address) | 39 | void Remove(u32 address) { |
| 46 | { | 40 | g_symbols.erase(address); |
| 47 | g_symbols.erase(address); | 41 | } |
| 48 | } | ||
| 49 | 42 | ||
| 50 | void Clear() | 43 | void Clear() { |
| 51 | { | 44 | g_symbols.clear(); |
| 52 | g_symbols.clear(); | 45 | } |
| 53 | } | ||
| 54 | } | 46 | } |
diff --git a/src/common/symbols.h b/src/common/symbols.h index 5ed16009c..f5a48e05a 100644 --- a/src/common/symbols.h +++ b/src/common/symbols.h | |||
| @@ -7,28 +7,24 @@ | |||
| 7 | #include <map> | 7 | #include <map> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include <utility> | 9 | #include <utility> |
| 10 | |||
| 11 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 12 | 11 | ||
| 13 | struct TSymbol | 12 | struct TSymbol { |
| 14 | { | 13 | u32 address = 0; |
| 15 | u32 address = 0; | ||
| 16 | std::string name; | 14 | std::string name; |
| 17 | u32 size = 0; | 15 | u32 size = 0; |
| 18 | u32 type = 0; | 16 | u32 type = 0; |
| 19 | }; | 17 | }; |
| 20 | 18 | ||
| 21 | typedef std::map<u32, TSymbol> TSymbolsMap; | 19 | typedef std::map<u32, TSymbol> TSymbolsMap; |
| 22 | typedef std::pair<u32, TSymbol> TSymbolsPair; | 20 | typedef std::pair<u32, TSymbol> TSymbolsPair; |
| 23 | 21 | ||
| 24 | namespace Symbols | 22 | namespace Symbols { |
| 25 | { | 23 | bool HasSymbol(u32 address); |
| 26 | bool HasSymbol(u32 address); | ||
| 27 | 24 | ||
| 28 | void Add(u32 address, const std::string& name, u32 size, u32 type); | 25 | void Add(u32 address, const std::string& name, u32 size, u32 type); |
| 29 | TSymbol GetSymbol(u32 address); | 26 | TSymbol GetSymbol(u32 address); |
| 30 | const std::string GetName(u32 address); | 27 | const std::string GetName(u32 address); |
| 31 | void Remove(u32 address); | 28 | void Remove(u32 address); |
| 32 | void Clear(); | 29 | void Clear(); |
| 33 | } | 30 | } |
| 34 | |||
diff --git a/src/common/synchronized_wrapper.h b/src/common/synchronized_wrapper.h index 07105a198..04b4f2e51 100644 --- a/src/common/synchronized_wrapper.h +++ b/src/common/synchronized_wrapper.h | |||
| @@ -12,15 +12,14 @@ namespace Common { | |||
| 12 | /** | 12 | /** |
| 13 | * Wraps an object, only allowing access to it via a locking reference wrapper. Good to ensure no | 13 | * Wraps an object, only allowing access to it via a locking reference wrapper. Good to ensure no |
| 14 | * one forgets to lock a mutex before acessing an object. To access the wrapped object construct a | 14 | * one forgets to lock a mutex before acessing an object. To access the wrapped object construct a |
| 15 | * SyncronizedRef on this wrapper. Inspired by Rust's Mutex type (http://doc.rust-lang.org/std/sync/struct.Mutex.html). | 15 | * SyncronizedRef on this wrapper. Inspired by Rust's Mutex type |
| 16 | * (http://doc.rust-lang.org/std/sync/struct.Mutex.html). | ||
| 16 | */ | 17 | */ |
| 17 | template <typename T> | 18 | template <typename T> |
| 18 | class SynchronizedWrapper { | 19 | class SynchronizedWrapper { |
| 19 | public: | 20 | public: |
| 20 | template <typename... Args> | 21 | template <typename... Args> |
| 21 | SynchronizedWrapper(Args&&... args) : | 22 | SynchronizedWrapper(Args&&... args) : data(std::forward<Args>(args)...) {} |
| 22 | data(std::forward<Args>(args)...) { | ||
| 23 | } | ||
| 24 | 23 | ||
| 25 | private: | 24 | private: |
| 26 | template <typename U> | 25 | template <typename U> |
| @@ -58,11 +57,19 @@ public: | |||
| 58 | return *this; | 57 | return *this; |
| 59 | } | 58 | } |
| 60 | 59 | ||
| 61 | T& operator*() { return wrapper->data; } | 60 | T& operator*() { |
| 62 | const T& operator*() const { return wrapper->data; } | 61 | return wrapper->data; |
| 62 | } | ||
| 63 | const T& operator*() const { | ||
| 64 | return wrapper->data; | ||
| 65 | } | ||
| 63 | 66 | ||
| 64 | T* operator->() { return &wrapper->data; } | 67 | T* operator->() { |
| 65 | const T* operator->() const { return &wrapper->data; } | 68 | return &wrapper->data; |
| 69 | } | ||
| 70 | const T* operator->() const { | ||
| 71 | return &wrapper->data; | ||
| 72 | } | ||
| 66 | 73 | ||
| 67 | private: | 74 | private: |
| 68 | SynchronizedWrapper<T>* wrapper; | 75 | SynchronizedWrapper<T>* wrapper; |
diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 7bbf080bc..6e7b39b9a 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp | |||
| @@ -3,29 +3,25 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/thread.h" | 5 | #include "common/thread.h" |
| 6 | |||
| 7 | #ifdef __APPLE__ | 6 | #ifdef __APPLE__ |
| 8 | #include <mach/mach.h> | 7 | #include <mach/mach.h> |
| 9 | #elif defined(_WIN32) | 8 | #elif defined(_WIN32) |
| 10 | #include <Windows.h> | 9 | #include <Windows.h> |
| 10 | #else | ||
| 11 | #if defined(BSD4_4) || defined(__OpenBSD__) | ||
| 12 | #include <pthread_np.h> | ||
| 11 | #else | 13 | #else |
| 12 | #if defined(BSD4_4) || defined(__OpenBSD__) | 14 | #include <pthread.h> |
| 13 | #include <pthread_np.h> | 15 | #endif |
| 14 | #else | 16 | #include <sched.h> |
| 15 | #include <pthread.h> | ||
| 16 | #endif | ||
| 17 | #include <sched.h> | ||
| 18 | #endif | 17 | #endif |
| 19 | |||
| 20 | #ifndef _WIN32 | 18 | #ifndef _WIN32 |
| 21 | #include <unistd.h> | 19 | #include <unistd.h> |
| 22 | #endif | 20 | #endif |
| 23 | 21 | ||
| 24 | namespace Common | 22 | namespace Common { |
| 25 | { | ||
| 26 | 23 | ||
| 27 | int CurrentThreadId() | 24 | int CurrentThreadId() { |
| 28 | { | ||
| 29 | #ifdef _MSC_VER | 25 | #ifdef _MSC_VER |
| 30 | return GetCurrentThreadId(); | 26 | return GetCurrentThreadId(); |
| 31 | #elif defined __APPLE__ | 27 | #elif defined __APPLE__ |
| @@ -37,26 +33,22 @@ int CurrentThreadId() | |||
| 37 | 33 | ||
| 38 | #ifdef _WIN32 | 34 | #ifdef _WIN32 |
| 39 | // Supporting functions | 35 | // Supporting functions |
| 40 | void SleepCurrentThread(int ms) | 36 | void SleepCurrentThread(int ms) { |
| 41 | { | ||
| 42 | Sleep(ms); | 37 | Sleep(ms); |
| 43 | } | 38 | } |
| 44 | #endif | 39 | #endif |
| 45 | 40 | ||
| 46 | #ifdef _MSC_VER | 41 | #ifdef _MSC_VER |
| 47 | 42 | ||
| 48 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) | 43 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { |
| 49 | { | ||
| 50 | SetThreadAffinityMask(thread, mask); | 44 | SetThreadAffinityMask(thread, mask); |
| 51 | } | 45 | } |
| 52 | 46 | ||
| 53 | void SetCurrentThreadAffinity(u32 mask) | 47 | void SetCurrentThreadAffinity(u32 mask) { |
| 54 | { | ||
| 55 | SetThreadAffinityMask(GetCurrentThread(), mask); | 48 | SetThreadAffinityMask(GetCurrentThread(), mask); |
| 56 | } | 49 | } |
| 57 | 50 | ||
| 58 | void SwitchCurrentThread() | 51 | void SwitchCurrentThread() { |
| 59 | { | ||
| 60 | SwitchToThread(); | 52 | SwitchToThread(); |
| 61 | } | 53 | } |
| 62 | 54 | ||
| @@ -66,40 +58,34 @@ void SwitchCurrentThread() | |||
| 66 | 58 | ||
| 67 | // This is implemented much nicer in upcoming msvc++, see: | 59 | // This is implemented much nicer in upcoming msvc++, see: |
| 68 | // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx | 60 | // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx |
| 69 | void SetCurrentThreadName(const char* szThreadName) | 61 | void SetCurrentThreadName(const char* szThreadName) { |
| 70 | { | ||
| 71 | static const DWORD MS_VC_EXCEPTION = 0x406D1388; | 62 | static const DWORD MS_VC_EXCEPTION = 0x406D1388; |
| 72 | 63 | ||
| 73 | #pragma pack(push,8) | 64 | #pragma pack(push, 8) |
| 74 | struct THREADNAME_INFO | 65 | struct THREADNAME_INFO { |
| 75 | { | 66 | DWORD dwType; // must be 0x1000 |
| 76 | DWORD dwType; // must be 0x1000 | 67 | LPCSTR szName; // pointer to name (in user addr space) |
| 77 | LPCSTR szName; // pointer to name (in user addr space) | ||
| 78 | DWORD dwThreadID; // thread ID (-1=caller thread) | 68 | DWORD dwThreadID; // thread ID (-1=caller thread) |
| 79 | DWORD dwFlags; // reserved for future use, must be zero | 69 | DWORD dwFlags; // reserved for future use, must be zero |
| 80 | } info; | 70 | } info; |
| 81 | #pragma pack(pop) | 71 | #pragma pack(pop) |
| 82 | 72 | ||
| 83 | info.dwType = 0x1000; | 73 | info.dwType = 0x1000; |
| 84 | info.szName = szThreadName; | 74 | info.szName = szThreadName; |
| 85 | info.dwThreadID = -1; //dwThreadID; | 75 | info.dwThreadID = -1; // dwThreadID; |
| 86 | info.dwFlags = 0; | 76 | info.dwFlags = 0; |
| 87 | 77 | ||
| 88 | __try | 78 | __try { |
| 89 | { | 79 | RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); |
| 90 | RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); | 80 | } __except (EXCEPTION_CONTINUE_EXECUTION) { |
| 91 | } | 81 | } |
| 92 | __except(EXCEPTION_CONTINUE_EXECUTION) | ||
| 93 | {} | ||
| 94 | } | 82 | } |
| 95 | 83 | ||
| 96 | #else // !MSVC_VER, so must be POSIX threads | 84 | #else // !MSVC_VER, so must be POSIX threads |
| 97 | 85 | ||
| 98 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) | 86 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { |
| 99 | { | ||
| 100 | #ifdef __APPLE__ | 87 | #ifdef __APPLE__ |
| 101 | thread_policy_set(pthread_mach_thread_np(thread), | 88 | thread_policy_set(pthread_mach_thread_np(thread), THREAD_AFFINITY_POLICY, (integer_t*)&mask, 1); |
| 102 | THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1); | ||
| 103 | #elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID) | 89 | #elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID) |
| 104 | cpu_set_t cpu_set; | 90 | cpu_set_t cpu_set; |
| 105 | CPU_ZERO(&cpu_set); | 91 | CPU_ZERO(&cpu_set); |
| @@ -112,27 +98,23 @@ void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) | |||
| 112 | #endif | 98 | #endif |
| 113 | } | 99 | } |
| 114 | 100 | ||
| 115 | void SetCurrentThreadAffinity(u32 mask) | 101 | void SetCurrentThreadAffinity(u32 mask) { |
| 116 | { | ||
| 117 | SetThreadAffinity(pthread_self(), mask); | 102 | SetThreadAffinity(pthread_self(), mask); |
| 118 | } | 103 | } |
| 119 | 104 | ||
| 120 | #ifndef _WIN32 | 105 | #ifndef _WIN32 |
| 121 | void SleepCurrentThread(int ms) | 106 | void SleepCurrentThread(int ms) { |
| 122 | { | ||
| 123 | usleep(1000 * ms); | 107 | usleep(1000 * ms); |
| 124 | } | 108 | } |
| 125 | 109 | ||
| 126 | void SwitchCurrentThread() | 110 | void SwitchCurrentThread() { |
| 127 | { | ||
| 128 | usleep(1000 * 1); | 111 | usleep(1000 * 1); |
| 129 | } | 112 | } |
| 130 | #endif | 113 | #endif |
| 131 | 114 | ||
| 132 | // MinGW with the POSIX threading model does not support pthread_setname_np | 115 | // MinGW with the POSIX threading model does not support pthread_setname_np |
| 133 | #if !defined(_WIN32) || defined(_MSC_VER) | 116 | #if !defined(_WIN32) || defined(_MSC_VER) |
| 134 | void SetCurrentThreadName(const char* szThreadName) | 117 | void SetCurrentThreadName(const char* szThreadName) { |
| 135 | { | ||
| 136 | #ifdef __APPLE__ | 118 | #ifdef __APPLE__ |
| 137 | pthread_setname_np(szThreadName); | 119 | pthread_setname_np(szThreadName); |
| 138 | #elif defined(__OpenBSD__) | 120 | #elif defined(__OpenBSD__) |
diff --git a/src/common/thread.h b/src/common/thread.h index bbfa8befa..9c08be7e3 100644 --- a/src/common/thread.h +++ b/src/common/thread.h | |||
| @@ -4,11 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | ||
| 8 | #include <thread> | ||
| 9 | #include <condition_variable> | 7 | #include <condition_variable> |
| 8 | #include <cstddef> | ||
| 10 | #include <mutex> | 9 | #include <mutex> |
| 11 | 10 | #include <thread> | |
| 12 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 13 | 12 | ||
| 14 | // Support for C++11's thread_local keyword was surprisingly spotty in compilers until very | 13 | // Support for C++11's thread_local keyword was surprisingly spotty in compilers until very |
| @@ -17,17 +16,17 @@ | |||
| 17 | // backwards compat support. | 16 | // backwards compat support. |
| 18 | // WARNING: This only works correctly with POD types. | 17 | // WARNING: This only works correctly with POD types. |
| 19 | #if defined(__clang__) | 18 | #if defined(__clang__) |
| 20 | # if !__has_feature(cxx_thread_local) | 19 | #if !__has_feature(cxx_thread_local) |
| 21 | # define thread_local __thread | 20 | #define thread_local __thread |
| 22 | # endif | 21 | #endif |
| 23 | #elif defined(__GNUC__) | 22 | #elif defined(__GNUC__) |
| 24 | # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) | 23 | #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) |
| 25 | # define thread_local __thread | 24 | #define thread_local __thread |
| 26 | # endif | 25 | #endif |
| 27 | #elif defined(_MSC_VER) | 26 | #elif defined(_MSC_VER) |
| 28 | # if _MSC_VER < 1900 | 27 | #if _MSC_VER < 1900 |
| 29 | # define thread_local __declspec(thread) | 28 | #define thread_local __declspec(thread) |
| 30 | # endif | 29 | #endif |
| 31 | #endif | 30 | #endif |
| 32 | 31 | ||
| 33 | namespace Common { | 32 | namespace Common { |
| @@ -51,13 +50,14 @@ public: | |||
| 51 | 50 | ||
| 52 | void Wait() { | 51 | void Wait() { |
| 53 | std::unique_lock<std::mutex> lk(mutex); | 52 | std::unique_lock<std::mutex> lk(mutex); |
| 54 | condvar.wait(lk, [&]{ return is_set; }); | 53 | condvar.wait(lk, [&] { return is_set; }); |
| 55 | is_set = false; | 54 | is_set = false; |
| 56 | } | 55 | } |
| 57 | 56 | ||
| 58 | void Reset() { | 57 | void Reset() { |
| 59 | std::unique_lock<std::mutex> lk(mutex); | 58 | std::unique_lock<std::mutex> lk(mutex); |
| 60 | // no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration | 59 | // no other action required, since wait loops on the predicate and any lingering signal will |
| 60 | // get cleared on the first iteration | ||
| 61 | is_set = false; | 61 | is_set = false; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| @@ -81,7 +81,8 @@ public: | |||
| 81 | waiting = 0; | 81 | waiting = 0; |
| 82 | condvar.notify_all(); | 82 | condvar.notify_all(); |
| 83 | } else { | 83 | } else { |
| 84 | condvar.wait(lk, [this, current_generation]{ return current_generation != generation; }); | 84 | condvar.wait(lk, |
| 85 | [this, current_generation] { return current_generation != generation; }); | ||
| 85 | } | 86 | } |
| 86 | } | 87 | } |
| 87 | 88 | ||
| @@ -94,7 +95,7 @@ private: | |||
| 94 | }; | 95 | }; |
| 95 | 96 | ||
| 96 | void SleepCurrentThread(int ms); | 97 | void SleepCurrentThread(int ms); |
| 97 | void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms | 98 | void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms |
| 98 | 99 | ||
| 99 | // Use this function during a spin-wait to make the current thread | 100 | // Use this function during a spin-wait to make the current thread |
| 100 | // relax while another thread is working. This may be more efficient | 101 | // relax while another thread is working. This may be more efficient |
| @@ -103,6 +104,6 @@ inline void YieldCPU() { | |||
| 103 | std::this_thread::yield(); | 104 | std::this_thread::yield(); |
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | void SetCurrentThreadName(const char *name); | 107 | void SetCurrentThreadName(const char* name); |
| 107 | 108 | ||
| 108 | } // namespace Common | 109 | } // namespace Common |
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h index 12455d7c4..edd0e4a3f 100644 --- a/src/common/thread_queue_list.h +++ b/src/common/thread_queue_list.h | |||
| @@ -6,12 +6,11 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <deque> | 8 | #include <deque> |
| 9 | |||
| 10 | #include <boost/range/algorithm_ext/erase.hpp> | 9 | #include <boost/range/algorithm_ext/erase.hpp> |
| 11 | 10 | ||
| 12 | namespace Common { | 11 | namespace Common { |
| 13 | 12 | ||
| 14 | template<class T, unsigned int N> | 13 | template <class T, unsigned int N> |
| 15 | struct ThreadQueueList { | 14 | struct ThreadQueueList { |
| 16 | // TODO(yuriks): If performance proves to be a problem, the std::deques can be replaced with | 15 | // TODO(yuriks): If performance proves to be a problem, the std::deques can be replaced with |
| 17 | // (dynamically resizable) circular buffers to remove their overhead when | 16 | // (dynamically resizable) circular buffers to remove their overhead when |
| @@ -39,7 +38,7 @@ struct ThreadQueueList { | |||
| 39 | } | 38 | } |
| 40 | 39 | ||
| 41 | T get_first() { | 40 | T get_first() { |
| 42 | Queue *cur = first; | 41 | Queue* cur = first; |
| 43 | while (cur != nullptr) { | 42 | while (cur != nullptr) { |
| 44 | if (!cur->data.empty()) { | 43 | if (!cur->data.empty()) { |
| 45 | return cur->data.front(); | 44 | return cur->data.front(); |
| @@ -51,7 +50,7 @@ struct ThreadQueueList { | |||
| 51 | } | 50 | } |
| 52 | 51 | ||
| 53 | T pop_first() { | 52 | T pop_first() { |
| 54 | Queue *cur = first; | 53 | Queue* cur = first; |
| 55 | while (cur != nullptr) { | 54 | while (cur != nullptr) { |
| 56 | if (!cur->data.empty()) { | 55 | if (!cur->data.empty()) { |
| 57 | auto tmp = std::move(cur->data.front()); | 56 | auto tmp = std::move(cur->data.front()); |
| @@ -65,8 +64,8 @@ struct ThreadQueueList { | |||
| 65 | } | 64 | } |
| 66 | 65 | ||
| 67 | T pop_first_better(Priority priority) { | 66 | T pop_first_better(Priority priority) { |
| 68 | Queue *cur = first; | 67 | Queue* cur = first; |
| 69 | Queue *stop = &queues[priority]; | 68 | Queue* stop = &queues[priority]; |
| 70 | while (cur < stop) { | 69 | while (cur < stop) { |
| 71 | if (!cur->data.empty()) { | 70 | if (!cur->data.empty()) { |
| 72 | auto tmp = std::move(cur->data.front()); | 71 | auto tmp = std::move(cur->data.front()); |
| @@ -80,12 +79,12 @@ struct ThreadQueueList { | |||
| 80 | } | 79 | } |
| 81 | 80 | ||
| 82 | void push_front(Priority priority, const T& thread_id) { | 81 | void push_front(Priority priority, const T& thread_id) { |
| 83 | Queue *cur = &queues[priority]; | 82 | Queue* cur = &queues[priority]; |
| 84 | cur->data.push_front(thread_id); | 83 | cur->data.push_front(thread_id); |
| 85 | } | 84 | } |
| 86 | 85 | ||
| 87 | void push_back(Priority priority, const T& thread_id) { | 86 | void push_back(Priority priority, const T& thread_id) { |
| 88 | Queue *cur = &queues[priority]; | 87 | Queue* cur = &queues[priority]; |
| 89 | cur->data.push_back(thread_id); | 88 | cur->data.push_back(thread_id); |
| 90 | } | 89 | } |
| 91 | 90 | ||
| @@ -96,12 +95,12 @@ struct ThreadQueueList { | |||
| 96 | } | 95 | } |
| 97 | 96 | ||
| 98 | void remove(Priority priority, const T& thread_id) { | 97 | void remove(Priority priority, const T& thread_id) { |
| 99 | Queue *cur = &queues[priority]; | 98 | Queue* cur = &queues[priority]; |
| 100 | boost::remove_erase(cur->data, thread_id); | 99 | boost::remove_erase(cur->data, thread_id); |
| 101 | } | 100 | } |
| 102 | 101 | ||
| 103 | void rotate(Priority priority) { | 102 | void rotate(Priority priority) { |
| 104 | Queue *cur = &queues[priority]; | 103 | Queue* cur = &queues[priority]; |
| 105 | 104 | ||
| 106 | if (cur->data.size() > 1) { | 105 | if (cur->data.size() > 1) { |
| 107 | cur->data.push_back(std::move(cur->data.front())); | 106 | cur->data.push_back(std::move(cur->data.front())); |
| @@ -115,7 +114,7 @@ struct ThreadQueueList { | |||
| 115 | } | 114 | } |
| 116 | 115 | ||
| 117 | bool empty(Priority priority) const { | 116 | bool empty(Priority priority) const { |
| 118 | const Queue *cur = &queues[priority]; | 117 | const Queue* cur = &queues[priority]; |
| 119 | return cur->data.empty(); | 118 | return cur->data.empty(); |
| 120 | } | 119 | } |
| 121 | 120 | ||
| @@ -139,7 +138,7 @@ private: | |||
| 139 | } | 138 | } |
| 140 | 139 | ||
| 141 | void link(Priority priority) { | 140 | void link(Priority priority) { |
| 142 | Queue *cur = &queues[priority]; | 141 | Queue* cur = &queues[priority]; |
| 143 | 142 | ||
| 144 | for (int i = priority - 1; i >= 0; --i) { | 143 | for (int i = priority - 1; i >= 0; --i) { |
| 145 | if (queues[i].next_nonempty != UnlinkedTag()) { | 144 | if (queues[i].next_nonempty != UnlinkedTag()) { |
diff --git a/src/common/timer.cpp b/src/common/timer.cpp index b99835ac7..e843cbd9c 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <time.h> | 5 | #include <time.h> |
| 6 | |||
| 7 | #ifdef _WIN32 | 6 | #ifdef _WIN32 |
| 8 | #include <Windows.h> | 7 | #include <Windows.h> |
| 9 | #include <mmsystem.h> | 8 | #include <mmsystem.h> |
| @@ -11,16 +10,13 @@ | |||
| 11 | #else | 10 | #else |
| 12 | #include <sys/time.h> | 11 | #include <sys/time.h> |
| 13 | #endif | 12 | #endif |
| 14 | |||
| 15 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 16 | #include "common/string_util.h" | 14 | #include "common/string_util.h" |
| 17 | #include "common/timer.h" | 15 | #include "common/timer.h" |
| 18 | 16 | ||
| 19 | namespace Common | 17 | namespace Common { |
| 20 | { | ||
| 21 | 18 | ||
| 22 | u32 Timer::GetTimeMs() | 19 | u32 Timer::GetTimeMs() { |
| 23 | { | ||
| 24 | #ifdef _WIN32 | 20 | #ifdef _WIN32 |
| 25 | return timeGetTime(); | 21 | return timeGetTime(); |
| 26 | #else | 22 | #else |
| @@ -35,32 +31,27 @@ u32 Timer::GetTimeMs() | |||
| 35 | // -------------------------------------------- | 31 | // -------------------------------------------- |
| 36 | 32 | ||
| 37 | // Set initial values for the class | 33 | // Set initial values for the class |
| 38 | Timer::Timer() | 34 | Timer::Timer() : m_LastTime(0), m_StartTime(0), m_Running(false) { |
| 39 | : m_LastTime(0), m_StartTime(0), m_Running(false) | ||
| 40 | { | ||
| 41 | Update(); | 35 | Update(); |
| 42 | } | 36 | } |
| 43 | 37 | ||
| 44 | // Write the starting time | 38 | // Write the starting time |
| 45 | void Timer::Start() | 39 | void Timer::Start() { |
| 46 | { | ||
| 47 | m_StartTime = GetTimeMs(); | 40 | m_StartTime = GetTimeMs(); |
| 48 | m_Running = true; | 41 | m_Running = true; |
| 49 | } | 42 | } |
| 50 | 43 | ||
| 51 | // Stop the timer | 44 | // Stop the timer |
| 52 | void Timer::Stop() | 45 | void Timer::Stop() { |
| 53 | { | ||
| 54 | // Write the final time | 46 | // Write the final time |
| 55 | m_LastTime = GetTimeMs(); | 47 | m_LastTime = GetTimeMs(); |
| 56 | m_Running = false; | 48 | m_Running = false; |
| 57 | } | 49 | } |
| 58 | 50 | ||
| 59 | // Update the last time variable | 51 | // Update the last time variable |
| 60 | void Timer::Update() | 52 | void Timer::Update() { |
| 61 | { | ||
| 62 | m_LastTime = GetTimeMs(); | 53 | m_LastTime = GetTimeMs(); |
| 63 | //TODO(ector) - QPF | 54 | // TODO(ector) - QPF |
| 64 | } | 55 | } |
| 65 | 56 | ||
| 66 | // ------------------------------------- | 57 | // ------------------------------------- |
| @@ -68,34 +59,32 @@ void Timer::Update() | |||
| 68 | // ------------------------------------- | 59 | // ------------------------------------- |
| 69 | 60 | ||
| 70 | // Get the number of milliseconds since the last Update() | 61 | // Get the number of milliseconds since the last Update() |
| 71 | u64 Timer::GetTimeDifference() | 62 | u64 Timer::GetTimeDifference() { |
| 72 | { | ||
| 73 | return GetTimeMs() - m_LastTime; | 63 | return GetTimeMs() - m_LastTime; |
| 74 | } | 64 | } |
| 75 | 65 | ||
| 76 | // Add the time difference since the last Update() to the starting time. | 66 | // Add the time difference since the last Update() to the starting time. |
| 77 | // This is used to compensate for a paused game. | 67 | // This is used to compensate for a paused game. |
| 78 | void Timer::AddTimeDifference() | 68 | void Timer::AddTimeDifference() { |
| 79 | { | ||
| 80 | m_StartTime += GetTimeDifference(); | 69 | m_StartTime += GetTimeDifference(); |
| 81 | } | 70 | } |
| 82 | 71 | ||
| 83 | // Get the time elapsed since the Start() | 72 | // Get the time elapsed since the Start() |
| 84 | u64 Timer::GetTimeElapsed() | 73 | u64 Timer::GetTimeElapsed() { |
| 85 | { | ||
| 86 | // If we have not started yet, return 1 (because then I don't | 74 | // If we have not started yet, return 1 (because then I don't |
| 87 | // have to change the FPS calculation in CoreRerecording.cpp . | 75 | // have to change the FPS calculation in CoreRerecording.cpp . |
| 88 | if (m_StartTime == 0) return 1; | 76 | if (m_StartTime == 0) |
| 77 | return 1; | ||
| 89 | 78 | ||
| 90 | // Return the final timer time if the timer is stopped | 79 | // Return the final timer time if the timer is stopped |
| 91 | if (!m_Running) return (m_LastTime - m_StartTime); | 80 | if (!m_Running) |
| 81 | return (m_LastTime - m_StartTime); | ||
| 92 | 82 | ||
| 93 | return (GetTimeMs() - m_StartTime); | 83 | return (GetTimeMs() - m_StartTime); |
| 94 | } | 84 | } |
| 95 | 85 | ||
| 96 | // Get the formatted time elapsed since the Start() | 86 | // Get the formatted time elapsed since the Start() |
| 97 | std::string Timer::GetTimeElapsedFormatted() const | 87 | std::string Timer::GetTimeElapsedFormatted() const { |
| 98 | { | ||
| 99 | // If we have not started yet, return zero | 88 | // If we have not started yet, return zero |
| 100 | if (m_StartTime == 0) | 89 | if (m_StartTime == 0) |
| 101 | return "00:00:00:000"; | 90 | return "00:00:00:000"; |
| @@ -114,50 +103,46 @@ std::string Timer::GetTimeElapsedFormatted() const | |||
| 114 | // Hours | 103 | // Hours |
| 115 | u32 Hours = Minutes / 60; | 104 | u32 Hours = Minutes / 60; |
| 116 | 105 | ||
| 117 | std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", | 106 | std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", Hours, Minutes % 60, Seconds % 60, |
| 118 | Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000); | 107 | Milliseconds % 1000); |
| 119 | return TmpStr; | 108 | return TmpStr; |
| 120 | } | 109 | } |
| 121 | 110 | ||
| 122 | // Get current time | 111 | // Get current time |
| 123 | void Timer::IncreaseResolution() | 112 | void Timer::IncreaseResolution() { |
| 124 | { | ||
| 125 | #ifdef _WIN32 | 113 | #ifdef _WIN32 |
| 126 | timeBeginPeriod(1); | 114 | timeBeginPeriod(1); |
| 127 | #endif | 115 | #endif |
| 128 | } | 116 | } |
| 129 | 117 | ||
| 130 | void Timer::RestoreResolution() | 118 | void Timer::RestoreResolution() { |
| 131 | { | ||
| 132 | #ifdef _WIN32 | 119 | #ifdef _WIN32 |
| 133 | timeEndPeriod(1); | 120 | timeEndPeriod(1); |
| 134 | #endif | 121 | #endif |
| 135 | } | 122 | } |
| 136 | 123 | ||
| 137 | // Get the number of seconds since January 1 1970 | 124 | // Get the number of seconds since January 1 1970 |
| 138 | u64 Timer::GetTimeSinceJan1970() | 125 | u64 Timer::GetTimeSinceJan1970() { |
| 139 | { | ||
| 140 | time_t ltime; | 126 | time_t ltime; |
| 141 | time(<ime); | 127 | time(<ime); |
| 142 | return((u64)ltime); | 128 | return ((u64)ltime); |
| 143 | } | 129 | } |
| 144 | 130 | ||
| 145 | u64 Timer::GetLocalTimeSinceJan1970() | 131 | u64 Timer::GetLocalTimeSinceJan1970() { |
| 146 | { | ||
| 147 | time_t sysTime, tzDiff, tzDST; | 132 | time_t sysTime, tzDiff, tzDST; |
| 148 | struct tm * gmTime; | 133 | struct tm* gmTime; |
| 149 | 134 | ||
| 150 | time(&sysTime); | 135 | time(&sysTime); |
| 151 | 136 | ||
| 152 | // Account for DST where needed | 137 | // Account for DST where needed |
| 153 | gmTime = localtime(&sysTime); | 138 | gmTime = localtime(&sysTime); |
| 154 | if(gmTime->tm_isdst == 1) | 139 | if (gmTime->tm_isdst == 1) |
| 155 | tzDST = 3600; | 140 | tzDST = 3600; |
| 156 | else | 141 | else |
| 157 | tzDST = 0; | 142 | tzDST = 0; |
| 158 | 143 | ||
| 159 | // Lazy way to get local time in sec | 144 | // Lazy way to get local time in sec |
| 160 | gmTime = gmtime(&sysTime); | 145 | gmTime = gmtime(&sysTime); |
| 161 | tzDiff = sysTime - mktime(gmTime); | 146 | tzDiff = sysTime - mktime(gmTime); |
| 162 | 147 | ||
| 163 | return (u64)(sysTime + tzDiff + tzDST); | 148 | return (u64)(sysTime + tzDiff + tzDST); |
| @@ -165,10 +150,9 @@ u64 Timer::GetLocalTimeSinceJan1970() | |||
| 165 | 150 | ||
| 166 | // Return the current time formatted as Minutes:Seconds:Milliseconds | 151 | // Return the current time formatted as Minutes:Seconds:Milliseconds |
| 167 | // in the form 00:00:000. | 152 | // in the form 00:00:000. |
| 168 | std::string Timer::GetTimeFormatted() | 153 | std::string Timer::GetTimeFormatted() { |
| 169 | { | ||
| 170 | time_t sysTime; | 154 | time_t sysTime; |
| 171 | struct tm * gmTime; | 155 | struct tm* gmTime; |
| 172 | char tmp[13]; | 156 | char tmp[13]; |
| 173 | 157 | ||
| 174 | time(&sysTime); | 158 | time(&sysTime); |
| @@ -176,7 +160,7 @@ std::string Timer::GetTimeFormatted() | |||
| 176 | 160 | ||
| 177 | strftime(tmp, 6, "%M:%S", gmTime); | 161 | strftime(tmp, 6, "%M:%S", gmTime); |
| 178 | 162 | ||
| 179 | // Now tack on the milliseconds | 163 | // Now tack on the milliseconds |
| 180 | #ifdef _WIN32 | 164 | #ifdef _WIN32 |
| 181 | struct timeb tp; | 165 | struct timeb tp; |
| 182 | (void)::ftime(&tp); | 166 | (void)::ftime(&tp); |
| @@ -190,8 +174,7 @@ std::string Timer::GetTimeFormatted() | |||
| 190 | 174 | ||
| 191 | // Returns a timestamp with decimals for precise time comparisons | 175 | // Returns a timestamp with decimals for precise time comparisons |
| 192 | // ---------------- | 176 | // ---------------- |
| 193 | double Timer::GetDoubleTime() | 177 | double Timer::GetDoubleTime() { |
| 194 | { | ||
| 195 | #ifdef _WIN32 | 178 | #ifdef _WIN32 |
| 196 | struct timeb tp; | 179 | struct timeb tp; |
| 197 | (void)::ftime(&tp); | 180 | (void)::ftime(&tp); |
diff --git a/src/common/timer.h b/src/common/timer.h index b5f0f2585..78d37426b 100644 --- a/src/common/timer.h +++ b/src/common/timer.h | |||
| @@ -4,13 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include <string> | 7 | #include <string> |
| 8 | #include "common/common_types.h" | ||
| 9 | 9 | ||
| 10 | namespace Common | 10 | namespace Common { |
| 11 | { | 11 | class Timer { |
| 12 | class Timer | ||
| 13 | { | ||
| 14 | public: | 12 | public: |
| 15 | Timer(); | 13 | Timer(); |
| 16 | 14 | ||
| @@ -18,7 +16,8 @@ public: | |||
| 18 | void Stop(); | 16 | void Stop(); |
| 19 | void Update(); | 17 | void Update(); |
| 20 | 18 | ||
| 21 | // The time difference is always returned in milliseconds, regardless of alternative internal representation | 19 | // The time difference is always returned in milliseconds, regardless of alternative internal |
| 20 | // representation | ||
| 22 | u64 GetTimeDifference(); | 21 | u64 GetTimeDifference(); |
| 23 | void AddTimeDifference(); | 22 | void AddTimeDifference(); |
| 24 | 23 | ||
diff --git a/src/common/vector_math.h b/src/common/vector_math.h index cfb9481b6..2d56f168c 100644 --- a/src/common/vector_math.h +++ b/src/common/vector_math.h | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | // Licensed under GPLv2 or any later version | 1 | // Licensed under GPLv2 or any later version |
| 2 | // Refer to the license.txt file included. | 2 | // Refer to the license.txt file included. |
| 3 | 3 | ||
| 4 | |||
| 5 | // Copyright 2014 Tony Wasserka | 4 | // Copyright 2014 Tony Wasserka |
| 6 | // All rights reserved. | 5 | // All rights reserved. |
| 7 | // | 6 | // |
| @@ -36,158 +35,174 @@ | |||
| 36 | 35 | ||
| 37 | namespace Math { | 36 | namespace Math { |
| 38 | 37 | ||
| 39 | template<typename T> class Vec2; | 38 | template <typename T> |
| 40 | template<typename T> class Vec3; | 39 | class Vec2; |
| 41 | template<typename T> class Vec4; | 40 | template <typename T> |
| 41 | class Vec3; | ||
| 42 | template <typename T> | ||
| 43 | class Vec4; | ||
| 42 | 44 | ||
| 43 | template<typename T> | 45 | template <typename T> |
| 44 | static inline Vec2<T> MakeVec(const T& x, const T& y); | 46 | static inline Vec2<T> MakeVec(const T& x, const T& y); |
| 45 | template<typename T> | 47 | template <typename T> |
| 46 | static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z); | 48 | static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z); |
| 47 | template<typename T> | 49 | template <typename T> |
| 48 | static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w); | 50 | static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w); |
| 49 | 51 | ||
| 50 | 52 | template <typename T> | |
| 51 | template<typename T> | ||
| 52 | class Vec2 { | 53 | class Vec2 { |
| 53 | public: | 54 | public: |
| 54 | T x; | 55 | T x; |
| 55 | T y; | 56 | T y; |
| 56 | 57 | ||
| 57 | T* AsArray() { return &x; } | 58 | T* AsArray() { |
| 59 | return &x; | ||
| 60 | } | ||
| 58 | 61 | ||
| 59 | Vec2() = default; | 62 | Vec2() = default; |
| 60 | Vec2(const T a[2]) : x(a[0]), y(a[1]) {} | 63 | Vec2(const T a[2]) : x(a[0]), y(a[1]) {} |
| 61 | Vec2(const T& _x, const T& _y) : x(_x), y(_y) {} | 64 | Vec2(const T& _x, const T& _y) : x(_x), y(_y) {} |
| 62 | 65 | ||
| 63 | template<typename T2> | 66 | template <typename T2> |
| 64 | Vec2<T2> Cast() const { | 67 | Vec2<T2> Cast() const { |
| 65 | return Vec2<T2>((T2)x, (T2)y); | 68 | return Vec2<T2>((T2)x, (T2)y); |
| 66 | } | 69 | } |
| 67 | 70 | ||
| 68 | static Vec2 AssignToAll(const T& f) | 71 | static Vec2 AssignToAll(const T& f) { |
| 69 | { | ||
| 70 | return Vec2<T>(f, f); | 72 | return Vec2<T>(f, f); |
| 71 | } | 73 | } |
| 72 | 74 | ||
| 73 | void Write(T a[2]) | 75 | void Write(T a[2]) { |
| 74 | { | 76 | a[0] = x; |
| 75 | a[0] = x; a[1] = y; | 77 | a[1] = y; |
| 76 | } | 78 | } |
| 77 | 79 | ||
| 78 | Vec2<decltype(T{}+T{})> operator +(const Vec2& other) const | 80 | Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const { |
| 79 | { | 81 | return MakeVec(x + other.x, y + other.y); |
| 80 | return MakeVec(x+other.x, y+other.y); | ||
| 81 | } | 82 | } |
| 82 | void operator += (const Vec2 &other) | 83 | void operator+=(const Vec2& other) { |
| 83 | { | 84 | x += other.x; |
| 84 | x+=other.x; y+=other.y; | 85 | y += other.y; |
| 85 | } | 86 | } |
| 86 | Vec2<decltype(T{}-T{})> operator -(const Vec2& other) const | 87 | Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const { |
| 87 | { | 88 | return MakeVec(x - other.x, y - other.y); |
| 88 | return MakeVec(x-other.x, y-other.y); | ||
| 89 | } | 89 | } |
| 90 | void operator -= (const Vec2& other) | 90 | void operator-=(const Vec2& other) { |
| 91 | { | 91 | x -= other.x; |
| 92 | x-=other.x; y-=other.y; | 92 | y -= other.y; |
| 93 | } | 93 | } |
| 94 | template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> | 94 | template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type> |
| 95 | Vec2<decltype(-T{})> operator -() const | 95 | Vec2<decltype(-T{})> operator-() const { |
| 96 | { | 96 | return MakeVec(-x, -y); |
| 97 | return MakeVec(-x,-y); | ||
| 98 | } | 97 | } |
| 99 | Vec2<decltype(T{}*T{})> operator * (const Vec2& other) const | 98 | Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const { |
| 100 | { | 99 | return MakeVec(x * other.x, y * other.y); |
| 101 | return MakeVec(x*other.x, y*other.y); | ||
| 102 | } | 100 | } |
| 103 | template<typename V> | 101 | template <typename V> |
| 104 | Vec2<decltype(T{}*V{})> operator * (const V& f) const | 102 | Vec2<decltype(T{} * V{})> operator*(const V& f) const { |
| 105 | { | 103 | return MakeVec(x * f, y * f); |
| 106 | return MakeVec(x*f,y*f); | ||
| 107 | } | 104 | } |
| 108 | template<typename V> | 105 | template <typename V> |
| 109 | void operator *= (const V& f) | 106 | void operator*=(const V& f) { |
| 110 | { | 107 | x *= f; |
| 111 | x*=f; y*=f; | 108 | y *= f; |
| 112 | } | 109 | } |
| 113 | template<typename V> | 110 | template <typename V> |
| 114 | Vec2<decltype(T{}/V{})> operator / (const V& f) const | 111 | Vec2<decltype(T{} / V{})> operator/(const V& f) const { |
| 115 | { | 112 | return MakeVec(x / f, y / f); |
| 116 | return MakeVec(x/f,y/f); | ||
| 117 | } | 113 | } |
| 118 | template<typename V> | 114 | template <typename V> |
| 119 | void operator /= (const V& f) | 115 | void operator/=(const V& f) { |
| 120 | { | ||
| 121 | *this = *this / f; | 116 | *this = *this / f; |
| 122 | } | 117 | } |
| 123 | 118 | ||
| 124 | T Length2() const | 119 | T Length2() const { |
| 125 | { | 120 | return x * x + y * y; |
| 126 | return x*x + y*y; | ||
| 127 | } | 121 | } |
| 128 | 122 | ||
| 129 | // Only implemented for T=float | 123 | // Only implemented for T=float |
| 130 | float Length() const; | 124 | float Length() const; |
| 131 | void SetLength(const float l); | 125 | void SetLength(const float l); |
| 132 | Vec2 WithLength(const float l) const; | 126 | Vec2 WithLength(const float l) const; |
| 133 | float Distance2To(Vec2 &other); | 127 | float Distance2To(Vec2& other); |
| 134 | Vec2 Normalized() const; | 128 | Vec2 Normalized() const; |
| 135 | float Normalize(); // returns the previous length, which is often useful | 129 | float Normalize(); // returns the previous length, which is often useful |
| 136 | 130 | ||
| 137 | T& operator [] (int i) //allow vector[1] = 3 (vector.y=3) | 131 | T& operator[](int i) // allow vector[1] = 3 (vector.y=3) |
| 138 | { | 132 | { |
| 139 | return *((&x) + i); | 133 | return *((&x) + i); |
| 140 | } | 134 | } |
| 141 | T operator [] (const int i) const | 135 | T operator[](const int i) const { |
| 142 | { | ||
| 143 | return *((&x) + i); | 136 | return *((&x) + i); |
| 144 | } | 137 | } |
| 145 | 138 | ||
| 146 | void SetZero() | 139 | void SetZero() { |
| 147 | { | 140 | x = 0; |
| 148 | x=0; y=0; | 141 | y = 0; |
| 149 | } | 142 | } |
| 150 | 143 | ||
| 151 | // Common aliases: UV (texel coordinates), ST (texture coordinates) | 144 | // Common aliases: UV (texel coordinates), ST (texture coordinates) |
| 152 | T& u() { return x; } | 145 | T& u() { |
| 153 | T& v() { return y; } | 146 | return x; |
| 154 | T& s() { return x; } | 147 | } |
| 155 | T& t() { return y; } | 148 | T& v() { |
| 149 | return y; | ||
| 150 | } | ||
| 151 | T& s() { | ||
| 152 | return x; | ||
| 153 | } | ||
| 154 | T& t() { | ||
| 155 | return y; | ||
| 156 | } | ||
| 156 | 157 | ||
| 157 | const T& u() const { return x; } | 158 | const T& u() const { |
| 158 | const T& v() const { return y; } | 159 | return x; |
| 159 | const T& s() const { return x; } | 160 | } |
| 160 | const T& t() const { return y; } | 161 | const T& v() const { |
| 162 | return y; | ||
| 163 | } | ||
| 164 | const T& s() const { | ||
| 165 | return x; | ||
| 166 | } | ||
| 167 | const T& t() const { | ||
| 168 | return y; | ||
| 169 | } | ||
| 161 | 170 | ||
| 162 | // swizzlers - create a subvector of specific components | 171 | // swizzlers - create a subvector of specific components |
| 163 | const Vec2 yx() const { return Vec2(y, x); } | 172 | const Vec2 yx() const { |
| 164 | const Vec2 vu() const { return Vec2(y, x); } | 173 | return Vec2(y, x); |
| 165 | const Vec2 ts() const { return Vec2(y, x); } | 174 | } |
| 175 | const Vec2 vu() const { | ||
| 176 | return Vec2(y, x); | ||
| 177 | } | ||
| 178 | const Vec2 ts() const { | ||
| 179 | return Vec2(y, x); | ||
| 180 | } | ||
| 166 | }; | 181 | }; |
| 167 | 182 | ||
| 168 | template<typename T, typename V> | 183 | template <typename T, typename V> |
| 169 | Vec2<T> operator * (const V& f, const Vec2<T>& vec) | 184 | Vec2<T> operator*(const V& f, const Vec2<T>& vec) { |
| 170 | { | 185 | return Vec2<T>(f * vec.x, f * vec.y); |
| 171 | return Vec2<T>(f*vec.x,f*vec.y); | ||
| 172 | } | 186 | } |
| 173 | 187 | ||
| 174 | typedef Vec2<float> Vec2f; | 188 | typedef Vec2<float> Vec2f; |
| 175 | 189 | ||
| 176 | template<typename T> | 190 | template <typename T> |
| 177 | class Vec3 | 191 | class Vec3 { |
| 178 | { | ||
| 179 | public: | 192 | public: |
| 180 | T x; | 193 | T x; |
| 181 | T y; | 194 | T y; |
| 182 | T z; | 195 | T z; |
| 183 | 196 | ||
| 184 | T* AsArray() { return &x; } | 197 | T* AsArray() { |
| 198 | return &x; | ||
| 199 | } | ||
| 185 | 200 | ||
| 186 | Vec3() = default; | 201 | Vec3() = default; |
| 187 | Vec3(const T a[3]) : x(a[0]), y(a[1]), z(a[2]) {} | 202 | Vec3(const T a[3]) : x(a[0]), y(a[1]), z(a[2]) {} |
| 188 | Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {} | 203 | Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {} |
| 189 | 204 | ||
| 190 | template<typename T2> | 205 | template <typename T2> |
| 191 | Vec3<T2> Cast() const { | 206 | Vec3<T2> Cast() const { |
| 192 | return MakeVec<T2>((T2)x, (T2)y, (T2)z); | 207 | return MakeVec<T2>((T2)x, (T2)y, (T2)z); |
| 193 | } | 208 | } |
| @@ -196,126 +211,161 @@ public: | |||
| 196 | static Vec3 FromRGB(unsigned int rgb); | 211 | static Vec3 FromRGB(unsigned int rgb); |
| 197 | unsigned int ToRGB() const; // alpha bits set to zero | 212 | unsigned int ToRGB() const; // alpha bits set to zero |
| 198 | 213 | ||
| 199 | static Vec3 AssignToAll(const T& f) | 214 | static Vec3 AssignToAll(const T& f) { |
| 200 | { | ||
| 201 | return MakeVec(f, f, f); | 215 | return MakeVec(f, f, f); |
| 202 | } | 216 | } |
| 203 | 217 | ||
| 204 | void Write(T a[3]) | 218 | void Write(T a[3]) { |
| 205 | { | 219 | a[0] = x; |
| 206 | a[0] = x; a[1] = y; a[2] = z; | 220 | a[1] = y; |
| 221 | a[2] = z; | ||
| 207 | } | 222 | } |
| 208 | 223 | ||
| 209 | Vec3<decltype(T{}+T{})> operator +(const Vec3 &other) const | 224 | Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const { |
| 210 | { | 225 | return MakeVec(x + other.x, y + other.y, z + other.z); |
| 211 | return MakeVec(x+other.x, y+other.y, z+other.z); | ||
| 212 | } | 226 | } |
| 213 | void operator += (const Vec3 &other) | 227 | void operator+=(const Vec3& other) { |
| 214 | { | 228 | x += other.x; |
| 215 | x+=other.x; y+=other.y; z+=other.z; | 229 | y += other.y; |
| 230 | z += other.z; | ||
| 216 | } | 231 | } |
| 217 | Vec3<decltype(T{}-T{})> operator -(const Vec3 &other) const | 232 | Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const { |
| 218 | { | 233 | return MakeVec(x - other.x, y - other.y, z - other.z); |
| 219 | return MakeVec(x-other.x, y-other.y, z-other.z); | ||
| 220 | } | 234 | } |
| 221 | void operator -= (const Vec3 &other) | 235 | void operator-=(const Vec3& other) { |
| 222 | { | 236 | x -= other.x; |
| 223 | x-=other.x; y-=other.y; z-=other.z; | 237 | y -= other.y; |
| 238 | z -= other.z; | ||
| 224 | } | 239 | } |
| 225 | template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> | 240 | template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type> |
| 226 | Vec3<decltype(-T{})> operator -() const | 241 | Vec3<decltype(-T{})> operator-() const { |
| 227 | { | 242 | return MakeVec(-x, -y, -z); |
| 228 | return MakeVec(-x,-y,-z); | ||
| 229 | } | 243 | } |
| 230 | Vec3<decltype(T{}*T{})> operator * (const Vec3 &other) const | 244 | Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const { |
| 231 | { | 245 | return MakeVec(x * other.x, y * other.y, z * other.z); |
| 232 | return MakeVec(x*other.x, y*other.y, z*other.z); | ||
| 233 | } | 246 | } |
| 234 | template<typename V> | 247 | template <typename V> |
| 235 | Vec3<decltype(T{}*V{})> operator * (const V& f) const | 248 | Vec3<decltype(T{} * V{})> operator*(const V& f) const { |
| 236 | { | 249 | return MakeVec(x * f, y * f, z * f); |
| 237 | return MakeVec(x*f,y*f,z*f); | ||
| 238 | } | 250 | } |
| 239 | template<typename V> | 251 | template <typename V> |
| 240 | void operator *= (const V& f) | 252 | void operator*=(const V& f) { |
| 241 | { | 253 | x *= f; |
| 242 | x*=f; y*=f; z*=f; | 254 | y *= f; |
| 255 | z *= f; | ||
| 243 | } | 256 | } |
| 244 | template<typename V> | 257 | template <typename V> |
| 245 | Vec3<decltype(T{}/V{})> operator / (const V& f) const | 258 | Vec3<decltype(T{} / V{})> operator/(const V& f) const { |
| 246 | { | 259 | return MakeVec(x / f, y / f, z / f); |
| 247 | return MakeVec(x/f,y/f,z/f); | ||
| 248 | } | 260 | } |
| 249 | template<typename V> | 261 | template <typename V> |
| 250 | void operator /= (const V& f) | 262 | void operator/=(const V& f) { |
| 251 | { | ||
| 252 | *this = *this / f; | 263 | *this = *this / f; |
| 253 | } | 264 | } |
| 254 | 265 | ||
| 255 | T Length2() const | 266 | T Length2() const { |
| 256 | { | 267 | return x * x + y * y + z * z; |
| 257 | return x*x + y*y + z*z; | ||
| 258 | } | 268 | } |
| 259 | 269 | ||
| 260 | // Only implemented for T=float | 270 | // Only implemented for T=float |
| 261 | float Length() const; | 271 | float Length() const; |
| 262 | void SetLength(const float l); | 272 | void SetLength(const float l); |
| 263 | Vec3 WithLength(const float l) const; | 273 | Vec3 WithLength(const float l) const; |
| 264 | float Distance2To(Vec3 &other); | 274 | float Distance2To(Vec3& other); |
| 265 | Vec3 Normalized() const; | 275 | Vec3 Normalized() const; |
| 266 | float Normalize(); // returns the previous length, which is often useful | 276 | float Normalize(); // returns the previous length, which is often useful |
| 267 | 277 | ||
| 268 | T& operator [] (int i) //allow vector[2] = 3 (vector.z=3) | 278 | T& operator[](int i) // allow vector[2] = 3 (vector.z=3) |
| 269 | { | 279 | { |
| 270 | return *((&x) + i); | 280 | return *((&x) + i); |
| 271 | } | 281 | } |
| 272 | T operator [] (const int i) const | 282 | T operator[](const int i) const { |
| 273 | { | ||
| 274 | return *((&x) + i); | 283 | return *((&x) + i); |
| 275 | } | 284 | } |
| 276 | 285 | ||
| 277 | void SetZero() | 286 | void SetZero() { |
| 278 | { | 287 | x = 0; |
| 279 | x=0; y=0; z=0; | 288 | y = 0; |
| 289 | z = 0; | ||
| 280 | } | 290 | } |
| 281 | 291 | ||
| 282 | // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates) | 292 | // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates) |
| 283 | T& u() { return x; } | 293 | T& u() { |
| 284 | T& v() { return y; } | 294 | return x; |
| 285 | T& w() { return z; } | 295 | } |
| 296 | T& v() { | ||
| 297 | return y; | ||
| 298 | } | ||
| 299 | T& w() { | ||
| 300 | return z; | ||
| 301 | } | ||
| 286 | 302 | ||
| 287 | T& r() { return x; } | 303 | T& r() { |
| 288 | T& g() { return y; } | 304 | return x; |
| 289 | T& b() { return z; } | 305 | } |
| 306 | T& g() { | ||
| 307 | return y; | ||
| 308 | } | ||
| 309 | T& b() { | ||
| 310 | return z; | ||
| 311 | } | ||
| 290 | 312 | ||
| 291 | T& s() { return x; } | 313 | T& s() { |
| 292 | T& t() { return y; } | 314 | return x; |
| 293 | T& q() { return z; } | 315 | } |
| 316 | T& t() { | ||
| 317 | return y; | ||
| 318 | } | ||
| 319 | T& q() { | ||
| 320 | return z; | ||
| 321 | } | ||
| 294 | 322 | ||
| 295 | const T& u() const { return x; } | 323 | const T& u() const { |
| 296 | const T& v() const { return y; } | 324 | return x; |
| 297 | const T& w() const { return z; } | 325 | } |
| 326 | const T& v() const { | ||
| 327 | return y; | ||
| 328 | } | ||
| 329 | const T& w() const { | ||
| 330 | return z; | ||
| 331 | } | ||
| 298 | 332 | ||
| 299 | const T& r() const { return x; } | 333 | const T& r() const { |
| 300 | const T& g() const { return y; } | 334 | return x; |
| 301 | const T& b() const { return z; } | 335 | } |
| 336 | const T& g() const { | ||
| 337 | return y; | ||
| 338 | } | ||
| 339 | const T& b() const { | ||
| 340 | return z; | ||
| 341 | } | ||
| 302 | 342 | ||
| 303 | const T& s() const { return x; } | 343 | const T& s() const { |
| 304 | const T& t() const { return y; } | 344 | return x; |
| 305 | const T& q() const { return z; } | 345 | } |
| 346 | const T& t() const { | ||
| 347 | return y; | ||
| 348 | } | ||
| 349 | const T& q() const { | ||
| 350 | return z; | ||
| 351 | } | ||
| 306 | 352 | ||
| 307 | // swizzlers - create a subvector of specific components | 353 | // swizzlers - create a subvector of specific components |
| 308 | // e.g. Vec2 uv() { return Vec2(x,y); } | 354 | // e.g. Vec2 uv() { return Vec2(x,y); } |
| 309 | // _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all component names (x<->r) and permutations (xy<->yx) | 355 | // _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all |
| 310 | #define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); } | 356 | // component names (x<->r) and permutations (xy<->yx) |
| 311 | #define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ | 357 | #define _DEFINE_SWIZZLER2(a, b, name) \ |
| 312 | _DEFINE_SWIZZLER2(a, b, a##b); \ | 358 | const Vec2<T> name() const { \ |
| 313 | _DEFINE_SWIZZLER2(a, b, a2##b2); \ | 359 | return Vec2<T>(a, b); \ |
| 314 | _DEFINE_SWIZZLER2(a, b, a3##b3); \ | 360 | } |
| 315 | _DEFINE_SWIZZLER2(a, b, a4##b4); \ | 361 | #define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ |
| 316 | _DEFINE_SWIZZLER2(b, a, b##a); \ | 362 | _DEFINE_SWIZZLER2(a, b, a##b); \ |
| 317 | _DEFINE_SWIZZLER2(b, a, b2##a2); \ | 363 | _DEFINE_SWIZZLER2(a, b, a2##b2); \ |
| 318 | _DEFINE_SWIZZLER2(b, a, b3##a3); \ | 364 | _DEFINE_SWIZZLER2(a, b, a3##b3); \ |
| 365 | _DEFINE_SWIZZLER2(a, b, a4##b4); \ | ||
| 366 | _DEFINE_SWIZZLER2(b, a, b##a); \ | ||
| 367 | _DEFINE_SWIZZLER2(b, a, b2##a2); \ | ||
| 368 | _DEFINE_SWIZZLER2(b, a, b3##a3); \ | ||
| 319 | _DEFINE_SWIZZLER2(b, a, b4##a4) | 369 | _DEFINE_SWIZZLER2(b, a, b4##a4) |
| 320 | 370 | ||
| 321 | DEFINE_SWIZZLER2(x, y, r, g, u, v, s, t); | 371 | DEFINE_SWIZZLER2(x, y, r, g, u, v, s, t); |
| @@ -325,41 +375,40 @@ public: | |||
| 325 | #undef _DEFINE_SWIZZLER2 | 375 | #undef _DEFINE_SWIZZLER2 |
| 326 | }; | 376 | }; |
| 327 | 377 | ||
| 328 | template<typename T, typename V> | 378 | template <typename T, typename V> |
| 329 | Vec3<T> operator * (const V& f, const Vec3<T>& vec) | 379 | Vec3<T> operator*(const V& f, const Vec3<T>& vec) { |
| 330 | { | 380 | return Vec3<T>(f * vec.x, f * vec.y, f * vec.z); |
| 331 | return Vec3<T>(f*vec.x,f*vec.y,f*vec.z); | ||
| 332 | } | 381 | } |
| 333 | 382 | ||
| 334 | template<> | 383 | template <> |
| 335 | inline float Vec3<float>::Length() const { | 384 | inline float Vec3<float>::Length() const { |
| 336 | return std::sqrt(x * x + y * y + z * z); | 385 | return std::sqrt(x * x + y * y + z * z); |
| 337 | } | 386 | } |
| 338 | 387 | ||
| 339 | template<> | 388 | template <> |
| 340 | inline Vec3<float> Vec3<float>::Normalized() const { | 389 | inline Vec3<float> Vec3<float>::Normalized() const { |
| 341 | return *this / Length(); | 390 | return *this / Length(); |
| 342 | } | 391 | } |
| 343 | 392 | ||
| 344 | |||
| 345 | typedef Vec3<float> Vec3f; | 393 | typedef Vec3<float> Vec3f; |
| 346 | 394 | ||
| 347 | template<typename T> | 395 | template <typename T> |
| 348 | class Vec4 | 396 | class Vec4 { |
| 349 | { | ||
| 350 | public: | 397 | public: |
| 351 | T x; | 398 | T x; |
| 352 | T y; | 399 | T y; |
| 353 | T z; | 400 | T z; |
| 354 | T w; | 401 | T w; |
| 355 | 402 | ||
| 356 | T* AsArray() { return &x; } | 403 | T* AsArray() { |
| 404 | return &x; | ||
| 405 | } | ||
| 357 | 406 | ||
| 358 | Vec4() = default; | 407 | Vec4() = default; |
| 359 | Vec4(const T a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {} | 408 | Vec4(const T a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {} |
| 360 | Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {} | 409 | Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {} |
| 361 | 410 | ||
| 362 | template<typename T2> | 411 | template <typename T2> |
| 363 | Vec4<T2> Cast() const { | 412 | Vec4<T2> Cast() const { |
| 364 | return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w); | 413 | return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w); |
| 365 | } | 414 | } |
| @@ -372,81 +421,79 @@ public: | |||
| 372 | return Vec4<T>(f, f, f, f); | 421 | return Vec4<T>(f, f, f, f); |
| 373 | } | 422 | } |
| 374 | 423 | ||
| 375 | void Write(T a[4]) | 424 | void Write(T a[4]) { |
| 376 | { | 425 | a[0] = x; |
| 377 | a[0] = x; a[1] = y; a[2] = z; a[3] = w; | 426 | a[1] = y; |
| 427 | a[2] = z; | ||
| 428 | a[3] = w; | ||
| 378 | } | 429 | } |
| 379 | 430 | ||
| 380 | Vec4<decltype(T{}+T{})> operator +(const Vec4& other) const | 431 | Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const { |
| 381 | { | 432 | return MakeVec(x + other.x, y + other.y, z + other.z, w + other.w); |
| 382 | return MakeVec(x+other.x, y+other.y, z+other.z, w+other.w); | ||
| 383 | } | 433 | } |
| 384 | void operator += (const Vec4& other) | 434 | void operator+=(const Vec4& other) { |
| 385 | { | 435 | x += other.x; |
| 386 | x+=other.x; y+=other.y; z+=other.z; w+=other.w; | 436 | y += other.y; |
| 437 | z += other.z; | ||
| 438 | w += other.w; | ||
| 387 | } | 439 | } |
| 388 | Vec4<decltype(T{}-T{})> operator -(const Vec4 &other) const | 440 | Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const { |
| 389 | { | 441 | return MakeVec(x - other.x, y - other.y, z - other.z, w - other.w); |
| 390 | return MakeVec(x-other.x, y-other.y, z-other.z, w-other.w); | ||
| 391 | } | 442 | } |
| 392 | void operator -= (const Vec4 &other) | 443 | void operator-=(const Vec4& other) { |
| 393 | { | 444 | x -= other.x; |
| 394 | x-=other.x; y-=other.y; z-=other.z; w-=other.w; | 445 | y -= other.y; |
| 446 | z -= other.z; | ||
| 447 | w -= other.w; | ||
| 395 | } | 448 | } |
| 396 | template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> | 449 | template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type> |
| 397 | Vec4<decltype(-T{})> operator -() const | 450 | Vec4<decltype(-T{})> operator-() const { |
| 398 | { | 451 | return MakeVec(-x, -y, -z, -w); |
| 399 | return MakeVec(-x,-y,-z,-w); | ||
| 400 | } | 452 | } |
| 401 | Vec4<decltype(T{}*T{})> operator * (const Vec4 &other) const | 453 | Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const { |
| 402 | { | 454 | return MakeVec(x * other.x, y * other.y, z * other.z, w * other.w); |
| 403 | return MakeVec(x*other.x, y*other.y, z*other.z, w*other.w); | ||
| 404 | } | 455 | } |
| 405 | template<typename V> | 456 | template <typename V> |
| 406 | Vec4<decltype(T{}*V{})> operator * (const V& f) const | 457 | Vec4<decltype(T{} * V{})> operator*(const V& f) const { |
| 407 | { | 458 | return MakeVec(x * f, y * f, z * f, w * f); |
| 408 | return MakeVec(x*f,y*f,z*f,w*f); | ||
| 409 | } | 459 | } |
| 410 | template<typename V> | 460 | template <typename V> |
| 411 | void operator *= (const V& f) | 461 | void operator*=(const V& f) { |
| 412 | { | 462 | x *= f; |
| 413 | x*=f; y*=f; z*=f; w*=f; | 463 | y *= f; |
| 464 | z *= f; | ||
| 465 | w *= f; | ||
| 414 | } | 466 | } |
| 415 | template<typename V> | 467 | template <typename V> |
| 416 | Vec4<decltype(T{}/V{})> operator / (const V& f) const | 468 | Vec4<decltype(T{} / V{})> operator/(const V& f) const { |
| 417 | { | 469 | return MakeVec(x / f, y / f, z / f, w / f); |
| 418 | return MakeVec(x/f,y/f,z/f,w/f); | ||
| 419 | } | 470 | } |
| 420 | template<typename V> | 471 | template <typename V> |
| 421 | void operator /= (const V& f) | 472 | void operator/=(const V& f) { |
| 422 | { | ||
| 423 | *this = *this / f; | 473 | *this = *this / f; |
| 424 | } | 474 | } |
| 425 | 475 | ||
| 426 | T Length2() const | 476 | T Length2() const { |
| 427 | { | 477 | return x * x + y * y + z * z + w * w; |
| 428 | return x*x + y*y + z*z + w*w; | ||
| 429 | } | 478 | } |
| 430 | 479 | ||
| 431 | // Only implemented for T=float | 480 | // Only implemented for T=float |
| 432 | float Length() const; | 481 | float Length() const; |
| 433 | void SetLength(const float l); | 482 | void SetLength(const float l); |
| 434 | Vec4 WithLength(const float l) const; | 483 | Vec4 WithLength(const float l) const; |
| 435 | float Distance2To(Vec4 &other); | 484 | float Distance2To(Vec4& other); |
| 436 | Vec4 Normalized() const; | 485 | Vec4 Normalized() const; |
| 437 | float Normalize(); // returns the previous length, which is often useful | 486 | float Normalize(); // returns the previous length, which is often useful |
| 438 | 487 | ||
| 439 | T& operator [] (int i) //allow vector[2] = 3 (vector.z=3) | 488 | T& operator[](int i) // allow vector[2] = 3 (vector.z=3) |
| 440 | { | 489 | { |
| 441 | return *((&x) + i); | 490 | return *((&x) + i); |
| 442 | } | 491 | } |
| 443 | T operator [] (const int i) const | 492 | T operator[](const int i) const { |
| 444 | { | ||
| 445 | return *((&x) + i); | 493 | return *((&x) + i); |
| 446 | } | 494 | } |
| 447 | 495 | ||
| 448 | void SetZero() | 496 | void SetZero() { |
| 449 | { | ||
| 450 | x = 0; | 497 | x = 0; |
| 451 | y = 0; | 498 | y = 0; |
| 452 | z = 0; | 499 | z = 0; |
| @@ -454,30 +501,50 @@ public: | |||
| 454 | } | 501 | } |
| 455 | 502 | ||
| 456 | // Common alias: RGBA (colors) | 503 | // Common alias: RGBA (colors) |
| 457 | T& r() { return x; } | 504 | T& r() { |
| 458 | T& g() { return y; } | 505 | return x; |
| 459 | T& b() { return z; } | 506 | } |
| 460 | T& a() { return w; } | 507 | T& g() { |
| 461 | 508 | return y; | |
| 462 | const T& r() const { return x; } | 509 | } |
| 463 | const T& g() const { return y; } | 510 | T& b() { |
| 464 | const T& b() const { return z; } | 511 | return z; |
| 465 | const T& a() const { return w; } | 512 | } |
| 466 | 513 | T& a() { | |
| 467 | // Swizzlers - Create a subvector of specific components | 514 | return w; |
| 468 | // e.g. Vec2 uv() { return Vec2(x,y); } | 515 | } |
| 469 | 516 | ||
| 470 | // _DEFINE_SWIZZLER2 defines a single such function | 517 | const T& r() const { |
| 471 | // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) | 518 | return x; |
| 472 | // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx) | 519 | } |
| 473 | #define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); } | 520 | const T& g() const { |
| 474 | #define DEFINE_SWIZZLER2_COMP1(a, a2) \ | 521 | return y; |
| 475 | _DEFINE_SWIZZLER2(a, a, a##a); \ | 522 | } |
| 523 | const T& b() const { | ||
| 524 | return z; | ||
| 525 | } | ||
| 526 | const T& a() const { | ||
| 527 | return w; | ||
| 528 | } | ||
| 529 | |||
| 530 | // Swizzlers - Create a subvector of specific components | ||
| 531 | // e.g. Vec2 uv() { return Vec2(x,y); } | ||
| 532 | |||
| 533 | // _DEFINE_SWIZZLER2 defines a single such function | ||
| 534 | // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) | ||
| 535 | // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and | ||
| 536 | // permutations (xy<->yx) | ||
| 537 | #define _DEFINE_SWIZZLER2(a, b, name) \ | ||
| 538 | const Vec2<T> name() const { \ | ||
| 539 | return Vec2<T>(a, b); \ | ||
| 540 | } | ||
| 541 | #define DEFINE_SWIZZLER2_COMP1(a, a2) \ | ||
| 542 | _DEFINE_SWIZZLER2(a, a, a##a); \ | ||
| 476 | _DEFINE_SWIZZLER2(a, a, a2##a2) | 543 | _DEFINE_SWIZZLER2(a, a, a2##a2) |
| 477 | #define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \ | 544 | #define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \ |
| 478 | _DEFINE_SWIZZLER2(a, b, a##b); \ | 545 | _DEFINE_SWIZZLER2(a, b, a##b); \ |
| 479 | _DEFINE_SWIZZLER2(a, b, a2##b2); \ | 546 | _DEFINE_SWIZZLER2(a, b, a2##b2); \ |
| 480 | _DEFINE_SWIZZLER2(b, a, b##a); \ | 547 | _DEFINE_SWIZZLER2(b, a, b##a); \ |
| 481 | _DEFINE_SWIZZLER2(b, a, b2##a2) | 548 | _DEFINE_SWIZZLER2(b, a, b2##a2) |
| 482 | 549 | ||
| 483 | DEFINE_SWIZZLER2_COMP2(x, y, r, g); | 550 | DEFINE_SWIZZLER2_COMP2(x, y, r, g); |
| @@ -494,22 +561,25 @@ public: | |||
| 494 | #undef DEFINE_SWIZZLER2_COMP2 | 561 | #undef DEFINE_SWIZZLER2_COMP2 |
| 495 | #undef _DEFINE_SWIZZLER2 | 562 | #undef _DEFINE_SWIZZLER2 |
| 496 | 563 | ||
| 497 | #define _DEFINE_SWIZZLER3(a, b, c, name) const Vec3<T> name() const { return Vec3<T>(a, b, c); } | 564 | #define _DEFINE_SWIZZLER3(a, b, c, name) \ |
| 498 | #define DEFINE_SWIZZLER3_COMP1(a, a2) \ | 565 | const Vec3<T> name() const { \ |
| 499 | _DEFINE_SWIZZLER3(a, a, a, a##a##a); \ | 566 | return Vec3<T>(a, b, c); \ |
| 567 | } | ||
| 568 | #define DEFINE_SWIZZLER3_COMP1(a, a2) \ | ||
| 569 | _DEFINE_SWIZZLER3(a, a, a, a##a##a); \ | ||
| 500 | _DEFINE_SWIZZLER3(a, a, a, a2##a2##a2) | 570 | _DEFINE_SWIZZLER3(a, a, a, a2##a2##a2) |
| 501 | #define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \ | 571 | #define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \ |
| 502 | _DEFINE_SWIZZLER3(a, b, c, a##b##c); \ | 572 | _DEFINE_SWIZZLER3(a, b, c, a##b##c); \ |
| 503 | _DEFINE_SWIZZLER3(a, c, b, a##c##b); \ | 573 | _DEFINE_SWIZZLER3(a, c, b, a##c##b); \ |
| 504 | _DEFINE_SWIZZLER3(b, a, c, b##a##c); \ | 574 | _DEFINE_SWIZZLER3(b, a, c, b##a##c); \ |
| 505 | _DEFINE_SWIZZLER3(b, c, a, b##c##a); \ | 575 | _DEFINE_SWIZZLER3(b, c, a, b##c##a); \ |
| 506 | _DEFINE_SWIZZLER3(c, a, b, c##a##b); \ | 576 | _DEFINE_SWIZZLER3(c, a, b, c##a##b); \ |
| 507 | _DEFINE_SWIZZLER3(c, b, a, c##b##a); \ | 577 | _DEFINE_SWIZZLER3(c, b, a, c##b##a); \ |
| 508 | _DEFINE_SWIZZLER3(a, b, c, a2##b2##c2); \ | 578 | _DEFINE_SWIZZLER3(a, b, c, a2##b2##c2); \ |
| 509 | _DEFINE_SWIZZLER3(a, c, b, a2##c2##b2); \ | 579 | _DEFINE_SWIZZLER3(a, c, b, a2##c2##b2); \ |
| 510 | _DEFINE_SWIZZLER3(b, a, c, b2##a2##c2); \ | 580 | _DEFINE_SWIZZLER3(b, a, c, b2##a2##c2); \ |
| 511 | _DEFINE_SWIZZLER3(b, c, a, b2##c2##a2); \ | 581 | _DEFINE_SWIZZLER3(b, c, a, b2##c2##a2); \ |
| 512 | _DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \ | 582 | _DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \ |
| 513 | _DEFINE_SWIZZLER3(c, b, a, c2##b2##a2) | 583 | _DEFINE_SWIZZLER3(c, b, a, c2##b2##a2) |
| 514 | 584 | ||
| 515 | DEFINE_SWIZZLER3_COMP3(x, y, z, r, g, b); | 585 | DEFINE_SWIZZLER3_COMP3(x, y, z, r, g, b); |
| @@ -525,123 +595,104 @@ public: | |||
| 525 | #undef _DEFINE_SWIZZLER3 | 595 | #undef _DEFINE_SWIZZLER3 |
| 526 | }; | 596 | }; |
| 527 | 597 | ||
| 528 | 598 | template <typename T, typename V> | |
| 529 | template<typename T, typename V> | 599 | Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { |
| 530 | Vec4<decltype(V{}*T{})> operator * (const V& f, const Vec4<T>& vec) | 600 | return MakeVec(f * vec.x, f * vec.y, f * vec.z, f * vec.w); |
| 531 | { | ||
| 532 | return MakeVec(f*vec.x,f*vec.y,f*vec.z,f*vec.w); | ||
| 533 | } | 601 | } |
| 534 | 602 | ||
| 535 | typedef Vec4<float> Vec4f; | 603 | typedef Vec4<float> Vec4f; |
| 536 | 604 | ||
| 537 | 605 | template <typename T> | |
| 538 | template<typename T> | 606 | static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) { |
| 539 | static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) | 607 | return a.x * b.x + a.y * b.y; |
| 540 | { | ||
| 541 | return a.x*b.x + a.y*b.y; | ||
| 542 | } | 608 | } |
| 543 | 609 | ||
| 544 | template<typename T> | 610 | template <typename T> |
| 545 | static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) | 611 | static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) { |
| 546 | { | 612 | return a.x * b.x + a.y * b.y + a.z * b.z; |
| 547 | return a.x*b.x + a.y*b.y + a.z*b.z; | ||
| 548 | } | 613 | } |
| 549 | 614 | ||
| 550 | template<typename T> | 615 | template <typename T> |
| 551 | static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) | 616 | static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) { |
| 552 | { | 617 | return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; |
| 553 | return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; | ||
| 554 | } | 618 | } |
| 555 | 619 | ||
| 556 | template<typename T> | 620 | template <typename T> |
| 557 | static inline Vec3<decltype(T{}*T{}-T{}*T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) | 621 | static inline Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) { |
| 558 | { | 622 | return MakeVec(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); |
| 559 | return MakeVec(a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x); | ||
| 560 | } | 623 | } |
| 561 | 624 | ||
| 562 | // linear interpolation via float: 0.0=begin, 1.0=end | 625 | // linear interpolation via float: 0.0=begin, 1.0=end |
| 563 | template<typename X> | 626 | template <typename X> |
| 564 | static inline decltype(X{}*float{}+X{}*float{}) Lerp(const X& begin, const X& end, const float t) | 627 | static inline decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end, |
| 565 | { | 628 | const float t) { |
| 566 | return begin*(1.f-t) + end*t; | 629 | return begin * (1.f - t) + end * t; |
| 567 | } | 630 | } |
| 568 | 631 | ||
| 569 | // linear interpolation via int: 0=begin, base=end | 632 | // linear interpolation via int: 0=begin, base=end |
| 570 | template<typename X, int base> | 633 | template <typename X, int base> |
| 571 | static inline decltype((X{}*int{}+X{}*int{}) / base) LerpInt(const X& begin, const X& end, const int t) | 634 | static inline decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end, |
| 572 | { | 635 | const int t) { |
| 573 | return (begin*(base-t) + end*t) / base; | 636 | return (begin * (base - t) + end * t) / base; |
| 574 | } | 637 | } |
| 575 | 638 | ||
| 576 | // Utility vector factories | 639 | // Utility vector factories |
| 577 | template<typename T> | 640 | template <typename T> |
| 578 | static inline Vec2<T> MakeVec(const T& x, const T& y) | 641 | static inline Vec2<T> MakeVec(const T& x, const T& y) { |
| 579 | { | ||
| 580 | return Vec2<T>{x, y}; | 642 | return Vec2<T>{x, y}; |
| 581 | } | 643 | } |
| 582 | 644 | ||
| 583 | template<typename T> | 645 | template <typename T> |
| 584 | static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) | 646 | static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) { |
| 585 | { | ||
| 586 | return Vec3<T>{x, y, z}; | 647 | return Vec3<T>{x, y, z}; |
| 587 | } | 648 | } |
| 588 | 649 | ||
| 589 | template<typename T> | 650 | template <typename T> |
| 590 | static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) | 651 | static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) { |
| 591 | { | ||
| 592 | return MakeVec(x, y, zw[0], zw[1]); | 652 | return MakeVec(x, y, zw[0], zw[1]); |
| 593 | } | 653 | } |
| 594 | 654 | ||
| 595 | template<typename T> | 655 | template <typename T> |
| 596 | static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) | 656 | static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) { |
| 597 | { | ||
| 598 | return MakeVec(xy[0], xy[1], z); | 657 | return MakeVec(xy[0], xy[1], z); |
| 599 | } | 658 | } |
| 600 | 659 | ||
| 601 | template<typename T> | 660 | template <typename T> |
| 602 | static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) | 661 | static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) { |
| 603 | { | ||
| 604 | return MakeVec(x, yz[0], yz[1]); | 662 | return MakeVec(x, yz[0], yz[1]); |
| 605 | } | 663 | } |
| 606 | 664 | ||
| 607 | template<typename T> | 665 | template <typename T> |
| 608 | static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) | 666 | static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) { |
| 609 | { | ||
| 610 | return Vec4<T>{x, y, z, w}; | 667 | return Vec4<T>{x, y, z, w}; |
| 611 | } | 668 | } |
| 612 | 669 | ||
| 613 | template<typename T> | 670 | template <typename T> |
| 614 | static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) | 671 | static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) { |
| 615 | { | ||
| 616 | return MakeVec(xy[0], xy[1], z, w); | 672 | return MakeVec(xy[0], xy[1], z, w); |
| 617 | } | 673 | } |
| 618 | 674 | ||
| 619 | template<typename T> | 675 | template <typename T> |
| 620 | static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) | 676 | static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) { |
| 621 | { | ||
| 622 | return MakeVec(x, yz[0], yz[1], w); | 677 | return MakeVec(x, yz[0], yz[1], w); |
| 623 | } | 678 | } |
| 624 | 679 | ||
| 625 | // NOTE: This has priority over "Vec2<Vec2<T>> MakeVec(const Vec2<T>& x, const Vec2<T>& y)". | 680 | // NOTE: This has priority over "Vec2<Vec2<T>> MakeVec(const Vec2<T>& x, const Vec2<T>& y)". |
| 626 | // Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error | 681 | // Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error |
| 627 | // out soon enough due to misuse of the returned structure. | 682 | // out soon enough due to misuse of the returned structure. |
| 628 | template<typename T> | 683 | template <typename T> |
| 629 | static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) | 684 | static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) { |
| 630 | { | ||
| 631 | return MakeVec(xy[0], xy[1], zw[0], zw[1]); | 685 | return MakeVec(xy[0], xy[1], zw[0], zw[1]); |
| 632 | } | 686 | } |
| 633 | 687 | ||
| 634 | template<typename T> | 688 | template <typename T> |
| 635 | static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) | 689 | static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) { |
| 636 | { | ||
| 637 | return MakeVec(xyz[0], xyz[1], xyz[2], w); | 690 | return MakeVec(xyz[0], xyz[1], xyz[2], w); |
| 638 | } | 691 | } |
| 639 | 692 | ||
| 640 | template<typename T> | 693 | template <typename T> |
| 641 | static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) | 694 | static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) { |
| 642 | { | ||
| 643 | return MakeVec(x, yzw[0], yzw[1], yzw[2]); | 695 | return MakeVec(x, yzw[0], yzw[1], yzw[2]); |
| 644 | } | 696 | } |
| 645 | 697 | ||
| 646 | |||
| 647 | } // namespace | 698 | } // namespace |
diff --git a/src/common/x64/abi.cpp b/src/common/x64/abi.cpp index 955eb86ce..504b9c940 100644 --- a/src/common/x64/abi.cpp +++ b/src/common/x64/abi.cpp | |||
| @@ -22,7 +22,8 @@ using namespace Gen; | |||
| 22 | 22 | ||
| 23 | // Shared code between Win64 and Unix64 | 23 | // Shared code between Win64 and Unix64 |
| 24 | 24 | ||
| 25 | void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp) { | 25 | void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, |
| 26 | size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp) { | ||
| 26 | size_t shadow = 0; | 27 | size_t shadow = 0; |
| 27 | #if defined(_WIN32) | 28 | #if defined(_WIN32) |
| 28 | shadow = 0x20; | 29 | shadow = 0x20; |
| @@ -49,17 +50,19 @@ void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_ | |||
| 49 | *xmm_offsetp = subtraction - xmm_base_subtraction; | 50 | *xmm_offsetp = subtraction - xmm_base_subtraction; |
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size) { | 53 | size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, |
| 54 | size_t needed_frame_size) { | ||
| 53 | size_t shadow, subtraction, xmm_offset; | 55 | size_t shadow, subtraction, xmm_offset; |
| 54 | ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, &xmm_offset); | 56 | ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, |
| 57 | &xmm_offset); | ||
| 55 | 58 | ||
| 56 | for (int r : mask & ABI_ALL_GPRS) | 59 | for (int r : mask& ABI_ALL_GPRS) |
| 57 | PUSH((X64Reg)r); | 60 | PUSH((X64Reg)r); |
| 58 | 61 | ||
| 59 | if (subtraction) | 62 | if (subtraction) |
| 60 | SUB(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction)); | 63 | SUB(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction)); |
| 61 | 64 | ||
| 62 | for (int x : mask & ABI_ALL_FPRS) { | 65 | for (int x : mask& ABI_ALL_FPRS) { |
| 63 | MOVAPD(MDisp(RSP, (int)xmm_offset), (X64Reg)(x - 16)); | 66 | MOVAPD(MDisp(RSP, (int)xmm_offset), (X64Reg)(x - 16)); |
| 64 | xmm_offset += 16; | 67 | xmm_offset += 16; |
| 65 | } | 68 | } |
| @@ -67,12 +70,14 @@ size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_align | |||
| 67 | return shadow; | 70 | return shadow; |
| 68 | } | 71 | } |
| 69 | 72 | ||
| 70 | void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size) { | 73 | void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, |
| 74 | size_t needed_frame_size) { | ||
| 71 | size_t shadow, subtraction, xmm_offset; | 75 | size_t shadow, subtraction, xmm_offset; |
| 72 | ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, &xmm_offset); | 76 | ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, |
| 77 | &xmm_offset); | ||
| 73 | 78 | ||
| 74 | for (int x : mask & ABI_ALL_FPRS) { | 79 | for (int x : mask& ABI_ALL_FPRS) { |
| 75 | MOVAPD((X64Reg) (x - 16), MDisp(RSP, (int)xmm_offset)); | 80 | MOVAPD((X64Reg)(x - 16), MDisp(RSP, (int)xmm_offset)); |
| 76 | xmm_offset += 16; | 81 | xmm_offset += 16; |
| 77 | } | 82 | } |
| 78 | 83 | ||
| @@ -86,10 +91,9 @@ void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignmen | |||
| 86 | } | 91 | } |
| 87 | 92 | ||
| 88 | // Common functions | 93 | // Common functions |
| 89 | void XEmitter::ABI_CallFunction(const void *func) { | 94 | void XEmitter::ABI_CallFunction(const void* func) { |
| 90 | u64 distance = u64(func) - (u64(code) + 5); | 95 | u64 distance = u64(func) - (u64(code) + 5); |
| 91 | if (distance >= 0x0000000080000000ULL | 96 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 92 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 93 | // Far call | 97 | // Far call |
| 94 | MOV(64, R(RAX), ImmPtr(func)); | 98 | MOV(64, R(RAX), ImmPtr(func)); |
| 95 | CALLptr(R(RAX)); | 99 | CALLptr(R(RAX)); |
| @@ -98,11 +102,10 @@ void XEmitter::ABI_CallFunction(const void *func) { | |||
| 98 | } | 102 | } |
| 99 | } | 103 | } |
| 100 | 104 | ||
| 101 | void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1) { | 105 | void XEmitter::ABI_CallFunctionC16(const void* func, u16 param1) { |
| 102 | MOV(32, R(ABI_PARAM1), Imm32((u32)param1)); | 106 | MOV(32, R(ABI_PARAM1), Imm32((u32)param1)); |
| 103 | u64 distance = u64(func) - (u64(code) + 5); | 107 | u64 distance = u64(func) - (u64(code) + 5); |
| 104 | if (distance >= 0x0000000080000000ULL | 108 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 105 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 106 | // Far call | 109 | // Far call |
| 107 | MOV(64, R(RAX), ImmPtr(func)); | 110 | MOV(64, R(RAX), ImmPtr(func)); |
| 108 | CALLptr(R(RAX)); | 111 | CALLptr(R(RAX)); |
| @@ -111,25 +114,23 @@ void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1) { | |||
| 111 | } | 114 | } |
| 112 | } | 115 | } |
| 113 | 116 | ||
| 114 | void XEmitter::ABI_CallFunctionCC16(const void *func, u32 param1, u16 param2) { | 117 | void XEmitter::ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2) { |
| 115 | MOV(32, R(ABI_PARAM1), Imm32(param1)); | 118 | MOV(32, R(ABI_PARAM1), Imm32(param1)); |
| 116 | MOV(32, R(ABI_PARAM2), Imm32((u32)param2)); | 119 | MOV(32, R(ABI_PARAM2), Imm32((u32)param2)); |
| 117 | u64 distance = u64(func) - (u64(code) + 5); | 120 | u64 distance = u64(func) - (u64(code) + 5); |
| 118 | if (distance >= 0x0000000080000000ULL | 121 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 119 | && distance < 0xFFFFFFFF80000000ULL) { | 122 | // Far call |
| 120 | // Far call | 123 | MOV(64, R(RAX), ImmPtr(func)); |
| 121 | MOV(64, R(RAX), ImmPtr(func)); | 124 | CALLptr(R(RAX)); |
| 122 | CALLptr(R(RAX)); | ||
| 123 | } else { | 125 | } else { |
| 124 | CALL(func); | 126 | CALL(func); |
| 125 | } | 127 | } |
| 126 | } | 128 | } |
| 127 | 129 | ||
| 128 | void XEmitter::ABI_CallFunctionC(const void *func, u32 param1) { | 130 | void XEmitter::ABI_CallFunctionC(const void* func, u32 param1) { |
| 129 | MOV(32, R(ABI_PARAM1), Imm32(param1)); | 131 | MOV(32, R(ABI_PARAM1), Imm32(param1)); |
| 130 | u64 distance = u64(func) - (u64(code) + 5); | 132 | u64 distance = u64(func) - (u64(code) + 5); |
| 131 | if (distance >= 0x0000000080000000ULL | 133 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 132 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 133 | // Far call | 134 | // Far call |
| 134 | MOV(64, R(RAX), ImmPtr(func)); | 135 | MOV(64, R(RAX), ImmPtr(func)); |
| 135 | CALLptr(R(RAX)); | 136 | CALLptr(R(RAX)); |
| @@ -138,12 +139,11 @@ void XEmitter::ABI_CallFunctionC(const void *func, u32 param1) { | |||
| 138 | } | 139 | } |
| 139 | } | 140 | } |
| 140 | 141 | ||
| 141 | void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2) { | 142 | void XEmitter::ABI_CallFunctionCC(const void* func, u32 param1, u32 param2) { |
| 142 | MOV(32, R(ABI_PARAM1), Imm32(param1)); | 143 | MOV(32, R(ABI_PARAM1), Imm32(param1)); |
| 143 | MOV(32, R(ABI_PARAM2), Imm32(param2)); | 144 | MOV(32, R(ABI_PARAM2), Imm32(param2)); |
| 144 | u64 distance = u64(func) - (u64(code) + 5); | 145 | u64 distance = u64(func) - (u64(code) + 5); |
| 145 | if (distance >= 0x0000000080000000ULL | 146 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 146 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 147 | // Far call | 147 | // Far call |
| 148 | MOV(64, R(RAX), ImmPtr(func)); | 148 | MOV(64, R(RAX), ImmPtr(func)); |
| 149 | CALLptr(R(RAX)); | 149 | CALLptr(R(RAX)); |
| @@ -152,13 +152,12 @@ void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2) { | |||
| 152 | } | 152 | } |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32 param3) { | 155 | void XEmitter::ABI_CallFunctionCCC(const void* func, u32 param1, u32 param2, u32 param3) { |
| 156 | MOV(32, R(ABI_PARAM1), Imm32(param1)); | 156 | MOV(32, R(ABI_PARAM1), Imm32(param1)); |
| 157 | MOV(32, R(ABI_PARAM2), Imm32(param2)); | 157 | MOV(32, R(ABI_PARAM2), Imm32(param2)); |
| 158 | MOV(32, R(ABI_PARAM3), Imm32(param3)); | 158 | MOV(32, R(ABI_PARAM3), Imm32(param3)); |
| 159 | u64 distance = u64(func) - (u64(code) + 5); | 159 | u64 distance = u64(func) - (u64(code) + 5); |
| 160 | if (distance >= 0x0000000080000000ULL | 160 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 161 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 162 | // Far call | 161 | // Far call |
| 163 | MOV(64, R(RAX), ImmPtr(func)); | 162 | MOV(64, R(RAX), ImmPtr(func)); |
| 164 | CALLptr(R(RAX)); | 163 | CALLptr(R(RAX)); |
| @@ -167,13 +166,12 @@ void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32 | |||
| 167 | } | 166 | } |
| 168 | } | 167 | } |
| 169 | 168 | ||
| 170 | void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, void *param3) { | 169 | void XEmitter::ABI_CallFunctionCCP(const void* func, u32 param1, u32 param2, void* param3) { |
| 171 | MOV(32, R(ABI_PARAM1), Imm32(param1)); | 170 | MOV(32, R(ABI_PARAM1), Imm32(param1)); |
| 172 | MOV(32, R(ABI_PARAM2), Imm32(param2)); | 171 | MOV(32, R(ABI_PARAM2), Imm32(param2)); |
| 173 | MOV(64, R(ABI_PARAM3), ImmPtr(param3)); | 172 | MOV(64, R(ABI_PARAM3), ImmPtr(param3)); |
| 174 | u64 distance = u64(func) - (u64(code) + 5); | 173 | u64 distance = u64(func) - (u64(code) + 5); |
| 175 | if (distance >= 0x0000000080000000ULL | 174 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 176 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 177 | // Far call | 175 | // Far call |
| 178 | MOV(64, R(RAX), ImmPtr(func)); | 176 | MOV(64, R(RAX), ImmPtr(func)); |
| 179 | CALLptr(R(RAX)); | 177 | CALLptr(R(RAX)); |
| @@ -182,14 +180,14 @@ void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, voi | |||
| 182 | } | 180 | } |
| 183 | } | 181 | } |
| 184 | 182 | ||
| 185 | void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2, u32 param3, void *param4) { | 183 | void XEmitter::ABI_CallFunctionCCCP(const void* func, u32 param1, u32 param2, u32 param3, |
| 184 | void* param4) { | ||
| 186 | MOV(32, R(ABI_PARAM1), Imm32(param1)); | 185 | MOV(32, R(ABI_PARAM1), Imm32(param1)); |
| 187 | MOV(32, R(ABI_PARAM2), Imm32(param2)); | 186 | MOV(32, R(ABI_PARAM2), Imm32(param2)); |
| 188 | MOV(32, R(ABI_PARAM3), Imm32(param3)); | 187 | MOV(32, R(ABI_PARAM3), Imm32(param3)); |
| 189 | MOV(64, R(ABI_PARAM4), ImmPtr(param4)); | 188 | MOV(64, R(ABI_PARAM4), ImmPtr(param4)); |
| 190 | u64 distance = u64(func) - (u64(code) + 5); | 189 | u64 distance = u64(func) - (u64(code) + 5); |
| 191 | if (distance >= 0x0000000080000000ULL | 190 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 192 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 193 | // Far call | 191 | // Far call |
| 194 | MOV(64, R(RAX), ImmPtr(func)); | 192 | MOV(64, R(RAX), ImmPtr(func)); |
| 195 | CALLptr(R(RAX)); | 193 | CALLptr(R(RAX)); |
| @@ -198,11 +196,10 @@ void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2, u3 | |||
| 198 | } | 196 | } |
| 199 | } | 197 | } |
| 200 | 198 | ||
| 201 | void XEmitter::ABI_CallFunctionP(const void *func, void *param1) { | 199 | void XEmitter::ABI_CallFunctionP(const void* func, void* param1) { |
| 202 | MOV(64, R(ABI_PARAM1), ImmPtr(param1)); | 200 | MOV(64, R(ABI_PARAM1), ImmPtr(param1)); |
| 203 | u64 distance = u64(func) - (u64(code) + 5); | 201 | u64 distance = u64(func) - (u64(code) + 5); |
| 204 | if (distance >= 0x0000000080000000ULL | 202 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 205 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 206 | // Far call | 203 | // Far call |
| 207 | MOV(64, R(RAX), ImmPtr(func)); | 204 | MOV(64, R(RAX), ImmPtr(func)); |
| 208 | CALLptr(R(RAX)); | 205 | CALLptr(R(RAX)); |
| @@ -211,13 +208,12 @@ void XEmitter::ABI_CallFunctionP(const void *func, void *param1) { | |||
| 211 | } | 208 | } |
| 212 | } | 209 | } |
| 213 | 210 | ||
| 214 | void XEmitter::ABI_CallFunctionPA(const void *func, void *param1, const Gen::OpArg &arg2) { | 211 | void XEmitter::ABI_CallFunctionPA(const void* func, void* param1, const Gen::OpArg& arg2) { |
| 215 | MOV(64, R(ABI_PARAM1), ImmPtr(param1)); | 212 | MOV(64, R(ABI_PARAM1), ImmPtr(param1)); |
| 216 | if (!arg2.IsSimpleReg(ABI_PARAM2)) | 213 | if (!arg2.IsSimpleReg(ABI_PARAM2)) |
| 217 | MOV(32, R(ABI_PARAM2), arg2); | 214 | MOV(32, R(ABI_PARAM2), arg2); |
| 218 | u64 distance = u64(func) - (u64(code) + 5); | 215 | u64 distance = u64(func) - (u64(code) + 5); |
| 219 | if (distance >= 0x0000000080000000ULL | 216 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 220 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 221 | // Far call | 217 | // Far call |
| 222 | MOV(64, R(RAX), ImmPtr(func)); | 218 | MOV(64, R(RAX), ImmPtr(func)); |
| 223 | CALLptr(R(RAX)); | 219 | CALLptr(R(RAX)); |
| @@ -226,15 +222,15 @@ void XEmitter::ABI_CallFunctionPA(const void *func, void *param1, const Gen::OpA | |||
| 226 | } | 222 | } |
| 227 | } | 223 | } |
| 228 | 224 | ||
| 229 | void XEmitter::ABI_CallFunctionPAA(const void *func, void *param1, const Gen::OpArg &arg2, const Gen::OpArg &arg3) { | 225 | void XEmitter::ABI_CallFunctionPAA(const void* func, void* param1, const Gen::OpArg& arg2, |
| 226 | const Gen::OpArg& arg3) { | ||
| 230 | MOV(64, R(ABI_PARAM1), ImmPtr(param1)); | 227 | MOV(64, R(ABI_PARAM1), ImmPtr(param1)); |
| 231 | if (!arg2.IsSimpleReg(ABI_PARAM2)) | 228 | if (!arg2.IsSimpleReg(ABI_PARAM2)) |
| 232 | MOV(32, R(ABI_PARAM2), arg2); | 229 | MOV(32, R(ABI_PARAM2), arg2); |
| 233 | if (!arg3.IsSimpleReg(ABI_PARAM3)) | 230 | if (!arg3.IsSimpleReg(ABI_PARAM3)) |
| 234 | MOV(32, R(ABI_PARAM3), arg3); | 231 | MOV(32, R(ABI_PARAM3), arg3); |
| 235 | u64 distance = u64(func) - (u64(code) + 5); | 232 | u64 distance = u64(func) - (u64(code) + 5); |
| 236 | if (distance >= 0x0000000080000000ULL | 233 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 237 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 238 | // Far call | 234 | // Far call |
| 239 | MOV(64, R(RAX), ImmPtr(func)); | 235 | MOV(64, R(RAX), ImmPtr(func)); |
| 240 | CALLptr(R(RAX)); | 236 | CALLptr(R(RAX)); |
| @@ -243,13 +239,12 @@ void XEmitter::ABI_CallFunctionPAA(const void *func, void *param1, const Gen::Op | |||
| 243 | } | 239 | } |
| 244 | } | 240 | } |
| 245 | 241 | ||
| 246 | void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, u32 param3) { | 242 | void XEmitter::ABI_CallFunctionPPC(const void* func, void* param1, void* param2, u32 param3) { |
| 247 | MOV(64, R(ABI_PARAM1), ImmPtr(param1)); | 243 | MOV(64, R(ABI_PARAM1), ImmPtr(param1)); |
| 248 | MOV(64, R(ABI_PARAM2), ImmPtr(param2)); | 244 | MOV(64, R(ABI_PARAM2), ImmPtr(param2)); |
| 249 | MOV(32, R(ABI_PARAM3), Imm32(param3)); | 245 | MOV(32, R(ABI_PARAM3), Imm32(param3)); |
| 250 | u64 distance = u64(func) - (u64(code) + 5); | 246 | u64 distance = u64(func) - (u64(code) + 5); |
| 251 | if (distance >= 0x0000000080000000ULL | 247 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 252 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 253 | // Far call | 248 | // Far call |
| 254 | MOV(64, R(RAX), ImmPtr(func)); | 249 | MOV(64, R(RAX), ImmPtr(func)); |
| 255 | CALLptr(R(RAX)); | 250 | CALLptr(R(RAX)); |
| @@ -259,12 +254,11 @@ void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, | |||
| 259 | } | 254 | } |
| 260 | 255 | ||
| 261 | // Pass a register as a parameter. | 256 | // Pass a register as a parameter. |
| 262 | void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) { | 257 | void XEmitter::ABI_CallFunctionR(const void* func, X64Reg reg1) { |
| 263 | if (reg1 != ABI_PARAM1) | 258 | if (reg1 != ABI_PARAM1) |
| 264 | MOV(32, R(ABI_PARAM1), R(reg1)); | 259 | MOV(32, R(ABI_PARAM1), R(reg1)); |
| 265 | u64 distance = u64(func) - (u64(code) + 5); | 260 | u64 distance = u64(func) - (u64(code) + 5); |
| 266 | if (distance >= 0x0000000080000000ULL | 261 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 267 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 268 | // Far call | 262 | // Far call |
| 269 | MOV(64, R(RAX), ImmPtr(func)); | 263 | MOV(64, R(RAX), ImmPtr(func)); |
| 270 | CALLptr(R(RAX)); | 264 | CALLptr(R(RAX)); |
| @@ -274,7 +268,7 @@ void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) { | |||
| 274 | } | 268 | } |
| 275 | 269 | ||
| 276 | // Pass two registers as parameters. | 270 | // Pass two registers as parameters. |
| 277 | void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2) { | 271 | void XEmitter::ABI_CallFunctionRR(const void* func, X64Reg reg1, X64Reg reg2) { |
| 278 | if (reg2 != ABI_PARAM1) { | 272 | if (reg2 != ABI_PARAM1) { |
| 279 | if (reg1 != ABI_PARAM1) | 273 | if (reg1 != ABI_PARAM1) |
| 280 | MOV(64, R(ABI_PARAM1), R(reg1)); | 274 | MOV(64, R(ABI_PARAM1), R(reg1)); |
| @@ -287,8 +281,7 @@ void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2) { | |||
| 287 | MOV(64, R(ABI_PARAM1), R(reg1)); | 281 | MOV(64, R(ABI_PARAM1), R(reg1)); |
| 288 | } | 282 | } |
| 289 | u64 distance = u64(func) - (u64(code) + 5); | 283 | u64 distance = u64(func) - (u64(code) + 5); |
| 290 | if (distance >= 0x0000000080000000ULL | 284 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 291 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 292 | // Far call | 285 | // Far call |
| 293 | MOV(64, R(RAX), ImmPtr(func)); | 286 | MOV(64, R(RAX), ImmPtr(func)); |
| 294 | CALLptr(R(RAX)); | 287 | CALLptr(R(RAX)); |
| @@ -297,14 +290,12 @@ void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2) { | |||
| 297 | } | 290 | } |
| 298 | } | 291 | } |
| 299 | 292 | ||
| 300 | void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32 param2) | 293 | void XEmitter::ABI_CallFunctionAC(const void* func, const Gen::OpArg& arg1, u32 param2) { |
| 301 | { | ||
| 302 | if (!arg1.IsSimpleReg(ABI_PARAM1)) | 294 | if (!arg1.IsSimpleReg(ABI_PARAM1)) |
| 303 | MOV(32, R(ABI_PARAM1), arg1); | 295 | MOV(32, R(ABI_PARAM1), arg1); |
| 304 | MOV(32, R(ABI_PARAM2), Imm32(param2)); | 296 | MOV(32, R(ABI_PARAM2), Imm32(param2)); |
| 305 | u64 distance = u64(func) - (u64(code) + 5); | 297 | u64 distance = u64(func) - (u64(code) + 5); |
| 306 | if (distance >= 0x0000000080000000ULL | 298 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 307 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 308 | // Far call | 299 | // Far call |
| 309 | MOV(64, R(RAX), ImmPtr(func)); | 300 | MOV(64, R(RAX), ImmPtr(func)); |
| 310 | CALLptr(R(RAX)); | 301 | CALLptr(R(RAX)); |
| @@ -313,15 +304,14 @@ void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32 | |||
| 313 | } | 304 | } |
| 314 | } | 305 | } |
| 315 | 306 | ||
| 316 | void XEmitter::ABI_CallFunctionACC(const void *func, const Gen::OpArg &arg1, u32 param2, u32 param3) | 307 | void XEmitter::ABI_CallFunctionACC(const void* func, const Gen::OpArg& arg1, u32 param2, |
| 317 | { | 308 | u32 param3) { |
| 318 | if (!arg1.IsSimpleReg(ABI_PARAM1)) | 309 | if (!arg1.IsSimpleReg(ABI_PARAM1)) |
| 319 | MOV(32, R(ABI_PARAM1), arg1); | 310 | MOV(32, R(ABI_PARAM1), arg1); |
| 320 | MOV(32, R(ABI_PARAM2), Imm32(param2)); | 311 | MOV(32, R(ABI_PARAM2), Imm32(param2)); |
| 321 | MOV(64, R(ABI_PARAM3), Imm64(param3)); | 312 | MOV(64, R(ABI_PARAM3), Imm64(param3)); |
| 322 | u64 distance = u64(func) - (u64(code) + 5); | 313 | u64 distance = u64(func) - (u64(code) + 5); |
| 323 | if (distance >= 0x0000000080000000ULL | 314 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 324 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 325 | // Far call | 315 | // Far call |
| 326 | MOV(64, R(RAX), ImmPtr(func)); | 316 | MOV(64, R(RAX), ImmPtr(func)); |
| 327 | CALLptr(R(RAX)); | 317 | CALLptr(R(RAX)); |
| @@ -330,13 +320,11 @@ void XEmitter::ABI_CallFunctionACC(const void *func, const Gen::OpArg &arg1, u32 | |||
| 330 | } | 320 | } |
| 331 | } | 321 | } |
| 332 | 322 | ||
| 333 | void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1) | 323 | void XEmitter::ABI_CallFunctionA(const void* func, const Gen::OpArg& arg1) { |
| 334 | { | ||
| 335 | if (!arg1.IsSimpleReg(ABI_PARAM1)) | 324 | if (!arg1.IsSimpleReg(ABI_PARAM1)) |
| 336 | MOV(32, R(ABI_PARAM1), arg1); | 325 | MOV(32, R(ABI_PARAM1), arg1); |
| 337 | u64 distance = u64(func) - (u64(code) + 5); | 326 | u64 distance = u64(func) - (u64(code) + 5); |
| 338 | if (distance >= 0x0000000080000000ULL | 327 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 339 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 340 | // Far call | 328 | // Far call |
| 341 | MOV(64, R(RAX), ImmPtr(func)); | 329 | MOV(64, R(RAX), ImmPtr(func)); |
| 342 | CALLptr(R(RAX)); | 330 | CALLptr(R(RAX)); |
| @@ -345,15 +333,14 @@ void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1) | |||
| 345 | } | 333 | } |
| 346 | } | 334 | } |
| 347 | 335 | ||
| 348 | void XEmitter::ABI_CallFunctionAA(const void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2) | 336 | void XEmitter::ABI_CallFunctionAA(const void* func, const Gen::OpArg& arg1, |
| 349 | { | 337 | const Gen::OpArg& arg2) { |
| 350 | if (!arg1.IsSimpleReg(ABI_PARAM1)) | 338 | if (!arg1.IsSimpleReg(ABI_PARAM1)) |
| 351 | MOV(32, R(ABI_PARAM1), arg1); | 339 | MOV(32, R(ABI_PARAM1), arg1); |
| 352 | if (!arg2.IsSimpleReg(ABI_PARAM2)) | 340 | if (!arg2.IsSimpleReg(ABI_PARAM2)) |
| 353 | MOV(32, R(ABI_PARAM2), arg2); | 341 | MOV(32, R(ABI_PARAM2), arg2); |
| 354 | u64 distance = u64(func) - (u64(code) + 5); | 342 | u64 distance = u64(func) - (u64(code) + 5); |
| 355 | if (distance >= 0x0000000080000000ULL | 343 | if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { |
| 356 | && distance < 0xFFFFFFFF80000000ULL) { | ||
| 357 | // Far call | 344 | // Far call |
| 358 | MOV(64, R(RAX), ImmPtr(func)); | 345 | MOV(64, R(RAX), ImmPtr(func)); |
| 359 | CALLptr(R(RAX)); | 346 | CALLptr(R(RAX)); |
diff --git a/src/common/x64/abi.h b/src/common/x64/abi.h index de6d62fdd..eaaf81d89 100644 --- a/src/common/x64/abi.h +++ b/src/common/x64/abi.h | |||
| @@ -12,7 +12,8 @@ | |||
| 12 | 12 | ||
| 13 | // Windows 64-bit | 13 | // Windows 64-bit |
| 14 | // * 4-reg "fastcall" variant, very new-skool stack handling | 14 | // * 4-reg "fastcall" variant, very new-skool stack handling |
| 15 | // * Callee moves stack pointer, to make room for shadow regs for the biggest function _it itself calls_ | 15 | // * Callee moves stack pointer, to make room for shadow regs for the biggest function _it itself |
| 16 | // calls_ | ||
| 16 | // * Parameters passed in RCX, RDX, ... further parameters are MOVed into the allocated stack space. | 17 | // * Parameters passed in RCX, RDX, ... further parameters are MOVed into the allocated stack space. |
| 17 | // Scratch: RAX RCX RDX R8 R9 R10 R11 | 18 | // Scratch: RAX RCX RDX R8 R9 R10 R11 |
| 18 | // Callee-save: RBX RSI RDI RBP R12 R13 R14 R15 | 19 | // Callee-save: RBX RSI RDI RBP R12 R13 R14 R15 |
| @@ -35,10 +36,10 @@ | |||
| 35 | #define ABI_PARAM4 R9 | 36 | #define ABI_PARAM4 R9 |
| 36 | 37 | ||
| 37 | // xmm0-xmm15 use the upper 16 bits in the functions that push/pop registers. | 38 | // xmm0-xmm15 use the upper 16 bits in the functions that push/pop registers. |
| 38 | #define ABI_ALL_CALLER_SAVED \ | 39 | #define ABI_ALL_CALLER_SAVED \ |
| 39 | (BitSet32 { RAX, RCX, RDX, R8, R9, R10, R11, \ | 40 | (BitSet32{RAX, RCX, RDX, R8, R9, R10, R11, XMM0 + 16, XMM1 + 16, XMM2 + 16, XMM3 + 16, \ |
| 40 | XMM0+16, XMM1+16, XMM2+16, XMM3+16, XMM4+16, XMM5+16 }) | 41 | XMM4 + 16, XMM5 + 16}) |
| 41 | #else //64-bit Unix / OS X | 42 | #else // 64-bit Unix / OS X |
| 42 | 43 | ||
| 43 | #define ABI_PARAM1 RDI | 44 | #define ABI_PARAM1 RDI |
| 44 | #define ABI_PARAM2 RSI | 45 | #define ABI_PARAM2 RSI |
| @@ -49,9 +50,7 @@ | |||
| 49 | 50 | ||
| 50 | // TODO: Avoid pushing all 16 XMM registers when possible. Most functions we call probably | 51 | // TODO: Avoid pushing all 16 XMM registers when possible. Most functions we call probably |
| 51 | // don't actually clobber them. | 52 | // don't actually clobber them. |
| 52 | #define ABI_ALL_CALLER_SAVED \ | 53 | #define ABI_ALL_CALLER_SAVED (BitSet32{RAX, RCX, RDX, RDI, RSI, R8, R9, R10, R11} | ABI_ALL_FPRS) |
| 53 | (BitSet32 { RAX, RCX, RDX, RDI, RSI, R8, R9, R10, R11 } | \ | ||
| 54 | ABI_ALL_FPRS) | ||
| 55 | #endif // WIN32 | 54 | #endif // WIN32 |
| 56 | 55 | ||
| 57 | #define ABI_ALL_CALLEE_SAVED (~ABI_ALL_CALLER_SAVED) | 56 | #define ABI_ALL_CALLEE_SAVED (~ABI_ALL_CALLER_SAVED) |
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index d9c430c67..6ddf9b70c 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp | |||
| @@ -5,9 +5,7 @@ | |||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include <string> | 6 | #include <string> |
| 7 | #include <thread> | 7 | #include <thread> |
| 8 | |||
| 9 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 10 | |||
| 11 | #include "cpu_detect.h" | 9 | #include "cpu_detect.h" |
| 12 | 10 | ||
| 13 | namespace Common { | 11 | namespace Common { |
| @@ -15,8 +13,8 @@ namespace Common { | |||
| 15 | #ifndef _MSC_VER | 13 | #ifndef _MSC_VER |
| 16 | 14 | ||
| 17 | #ifdef __FreeBSD__ | 15 | #ifdef __FreeBSD__ |
| 18 | #include <sys/types.h> | ||
| 19 | #include <machine/cpufunc.h> | 16 | #include <machine/cpufunc.h> |
| 17 | #include <sys/types.h> | ||
| 20 | #endif | 18 | #endif |
| 21 | 19 | ||
| 22 | static inline void __cpuidex(int info[4], int function_id, int subfunction_id) { | 20 | static inline void __cpuidex(int info[4], int function_id, int subfunction_id) { |
| @@ -26,15 +24,9 @@ static inline void __cpuidex(int info[4], int function_id, int subfunction_id) { | |||
| 26 | #else | 24 | #else |
| 27 | info[0] = function_id; // eax | 25 | info[0] = function_id; // eax |
| 28 | info[2] = subfunction_id; // ecx | 26 | info[2] = subfunction_id; // ecx |
| 29 | __asm__( | 27 | __asm__("cpuid" |
| 30 | "cpuid" | 28 | : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) |
| 31 | : "=a" (info[0]), | 29 | : "a"(function_id), "c"(subfunction_id)); |
| 32 | "=b" (info[1]), | ||
| 33 | "=c" (info[2]), | ||
| 34 | "=d" (info[3]) | ||
| 35 | : "a" (function_id), | ||
| 36 | "c" (subfunction_id) | ||
| 37 | ); | ||
| 38 | #endif | 30 | #endif |
| 39 | } | 31 | } |
| 40 | 32 | ||
| @@ -88,14 +80,22 @@ static CPUCaps Detect() { | |||
| 88 | if (max_std_fn >= 1) { | 80 | if (max_std_fn >= 1) { |
| 89 | __cpuid(cpu_id, 0x00000001); | 81 | __cpuid(cpu_id, 0x00000001); |
| 90 | 82 | ||
| 91 | if ((cpu_id[3] >> 25) & 1) caps.sse = true; | 83 | if ((cpu_id[3] >> 25) & 1) |
| 92 | if ((cpu_id[3] >> 26) & 1) caps.sse2 = true; | 84 | caps.sse = true; |
| 93 | if ((cpu_id[2]) & 1) caps.sse3 = true; | 85 | if ((cpu_id[3] >> 26) & 1) |
| 94 | if ((cpu_id[2] >> 9) & 1) caps.ssse3 = true; | 86 | caps.sse2 = true; |
| 95 | if ((cpu_id[2] >> 19) & 1) caps.sse4_1 = true; | 87 | if ((cpu_id[2]) & 1) |
| 96 | if ((cpu_id[2] >> 20) & 1) caps.sse4_2 = true; | 88 | caps.sse3 = true; |
| 97 | if ((cpu_id[2] >> 22) & 1) caps.movbe = true; | 89 | if ((cpu_id[2] >> 9) & 1) |
| 98 | if ((cpu_id[2] >> 25) & 1) caps.aes = true; | 90 | caps.ssse3 = true; |
| 91 | if ((cpu_id[2] >> 19) & 1) | ||
| 92 | caps.sse4_1 = true; | ||
| 93 | if ((cpu_id[2] >> 20) & 1) | ||
| 94 | caps.sse4_2 = true; | ||
| 95 | if ((cpu_id[2] >> 22) & 1) | ||
| 96 | caps.movbe = true; | ||
| 97 | if ((cpu_id[2] >> 25) & 1) | ||
| 98 | caps.aes = true; | ||
| 99 | 99 | ||
| 100 | if ((cpu_id[3] >> 24) & 1) { | 100 | if ((cpu_id[3] >> 24) & 1) { |
| 101 | caps.fxsave_fxrstor = true; | 101 | caps.fxsave_fxrstor = true; |
| @@ -140,10 +140,14 @@ static CPUCaps Detect() { | |||
| 140 | if (max_ex_fn >= 0x80000001) { | 140 | if (max_ex_fn >= 0x80000001) { |
| 141 | // Check for more features | 141 | // Check for more features |
| 142 | __cpuid(cpu_id, 0x80000001); | 142 | __cpuid(cpu_id, 0x80000001); |
| 143 | if (cpu_id[2] & 1) caps.lahf_sahf_64 = true; | 143 | if (cpu_id[2] & 1) |
| 144 | if ((cpu_id[2] >> 5) & 1) caps.lzcnt = true; | 144 | caps.lahf_sahf_64 = true; |
| 145 | if ((cpu_id[2] >> 16) & 1) caps.fma4 = true; | 145 | if ((cpu_id[2] >> 5) & 1) |
| 146 | if ((cpu_id[3] >> 29) & 1) caps.long_mode = true; | 146 | caps.lzcnt = true; |
| 147 | if ((cpu_id[2] >> 16) & 1) | ||
| 148 | caps.fma4 = true; | ||
| 149 | if ((cpu_id[3] >> 29) & 1) | ||
| 150 | caps.long_mode = true; | ||
| 147 | } | 151 | } |
| 148 | 152 | ||
| 149 | return caps; | 153 | return caps; |
| @@ -162,24 +166,38 @@ std::string GetCPUCapsString() { | |||
| 162 | sum += caps.brand_string; | 166 | sum += caps.brand_string; |
| 163 | sum += ")"; | 167 | sum += ")"; |
| 164 | 168 | ||
| 165 | if (caps.sse) sum += ", SSE"; | 169 | if (caps.sse) |
| 170 | sum += ", SSE"; | ||
| 166 | if (caps.sse2) { | 171 | if (caps.sse2) { |
| 167 | sum += ", SSE2"; | 172 | sum += ", SSE2"; |
| 168 | if (!caps.flush_to_zero) sum += " (without DAZ)"; | 173 | if (!caps.flush_to_zero) |
| 174 | sum += " (without DAZ)"; | ||
| 169 | } | 175 | } |
| 170 | 176 | ||
| 171 | if (caps.sse3) sum += ", SSE3"; | 177 | if (caps.sse3) |
| 172 | if (caps.ssse3) sum += ", SSSE3"; | 178 | sum += ", SSE3"; |
| 173 | if (caps.sse4_1) sum += ", SSE4.1"; | 179 | if (caps.ssse3) |
| 174 | if (caps.sse4_2) sum += ", SSE4.2"; | 180 | sum += ", SSSE3"; |
| 175 | if (caps.avx) sum += ", AVX"; | 181 | if (caps.sse4_1) |
| 176 | if (caps.avx2) sum += ", AVX2"; | 182 | sum += ", SSE4.1"; |
| 177 | if (caps.bmi1) sum += ", BMI1"; | 183 | if (caps.sse4_2) |
| 178 | if (caps.bmi2) sum += ", BMI2"; | 184 | sum += ", SSE4.2"; |
| 179 | if (caps.fma) sum += ", FMA"; | 185 | if (caps.avx) |
| 180 | if (caps.aes) sum += ", AES"; | 186 | sum += ", AVX"; |
| 181 | if (caps.movbe) sum += ", MOVBE"; | 187 | if (caps.avx2) |
| 182 | if (caps.long_mode) sum += ", 64-bit support"; | 188 | sum += ", AVX2"; |
| 189 | if (caps.bmi1) | ||
| 190 | sum += ", BMI1"; | ||
| 191 | if (caps.bmi2) | ||
| 192 | sum += ", BMI2"; | ||
| 193 | if (caps.fma) | ||
| 194 | sum += ", FMA"; | ||
| 195 | if (caps.aes) | ||
| 196 | sum += ", AES"; | ||
| 197 | if (caps.movbe) | ||
| 198 | sum += ", MOVBE"; | ||
| 199 | if (caps.long_mode) | ||
| 200 | sum += ", 64-bit support"; | ||
| 183 | 201 | ||
| 184 | return sum; | 202 | return sum; |
| 185 | } | 203 | } |
diff --git a/src/common/x64/emitter.cpp b/src/common/x64/emitter.cpp index 5662f7f86..f5930abec 100644 --- a/src/common/x64/emitter.cpp +++ b/src/common/x64/emitter.cpp | |||
| @@ -17,188 +17,169 @@ | |||
| 17 | 17 | ||
| 18 | #include <cinttypes> | 18 | #include <cinttypes> |
| 19 | #include <cstring> | 19 | #include <cstring> |
| 20 | 20 | #include "abi.h" | |
| 21 | #include "common/assert.h" | 21 | #include "common/assert.h" |
| 22 | #include "common/logging/log.h" | 22 | #include "common/logging/log.h" |
| 23 | #include "common/memory_util.h" | 23 | #include "common/memory_util.h" |
| 24 | |||
| 25 | #include "abi.h" | ||
| 26 | #include "cpu_detect.h" | 24 | #include "cpu_detect.h" |
| 27 | #include "emitter.h" | 25 | #include "emitter.h" |
| 28 | 26 | ||
| 29 | namespace Gen | 27 | namespace Gen { |
| 30 | { | ||
| 31 | 28 | ||
| 32 | struct NormalOpDef | 29 | struct NormalOpDef { |
| 33 | { | ||
| 34 | u8 toRm8, toRm32, fromRm8, fromRm32, imm8, imm32, simm8, eaximm8, eaximm32, ext; | 30 | u8 toRm8, toRm32, fromRm8, fromRm32, imm8, imm32, simm8, eaximm8, eaximm32, ext; |
| 35 | }; | 31 | }; |
| 36 | 32 | ||
| 37 | // 0xCC is code for invalid combination of immediates | 33 | // 0xCC is code for invalid combination of immediates |
| 38 | static const NormalOpDef normalops[11] = | 34 | static const NormalOpDef normalops[11] = { |
| 39 | { | 35 | {0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x83, 0x04, 0x05, 0}, // ADD |
| 40 | {0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x83, 0x04, 0x05, 0}, //ADD | 36 | {0x10, 0x11, 0x12, 0x13, 0x80, 0x81, 0x83, 0x14, 0x15, 2}, // ADC |
| 41 | {0x10, 0x11, 0x12, 0x13, 0x80, 0x81, 0x83, 0x14, 0x15, 2}, //ADC | ||
| 42 | 37 | ||
| 43 | {0x28, 0x29, 0x2A, 0x2B, 0x80, 0x81, 0x83, 0x2C, 0x2D, 5}, //SUB | 38 | {0x28, 0x29, 0x2A, 0x2B, 0x80, 0x81, 0x83, 0x2C, 0x2D, 5}, // SUB |
| 44 | {0x18, 0x19, 0x1A, 0x1B, 0x80, 0x81, 0x83, 0x1C, 0x1D, 3}, //SBB | 39 | {0x18, 0x19, 0x1A, 0x1B, 0x80, 0x81, 0x83, 0x1C, 0x1D, 3}, // SBB |
| 45 | 40 | ||
| 46 | {0x20, 0x21, 0x22, 0x23, 0x80, 0x81, 0x83, 0x24, 0x25, 4}, //AND | 41 | {0x20, 0x21, 0x22, 0x23, 0x80, 0x81, 0x83, 0x24, 0x25, 4}, // AND |
| 47 | {0x08, 0x09, 0x0A, 0x0B, 0x80, 0x81, 0x83, 0x0C, 0x0D, 1}, //OR | 42 | {0x08, 0x09, 0x0A, 0x0B, 0x80, 0x81, 0x83, 0x0C, 0x0D, 1}, // OR |
| 48 | 43 | ||
| 49 | {0x30, 0x31, 0x32, 0x33, 0x80, 0x81, 0x83, 0x34, 0x35, 6}, //XOR | 44 | {0x30, 0x31, 0x32, 0x33, 0x80, 0x81, 0x83, 0x34, 0x35, 6}, // XOR |
| 50 | {0x88, 0x89, 0x8A, 0x8B, 0xC6, 0xC7, 0xCC, 0xCC, 0xCC, 0}, //MOV | 45 | {0x88, 0x89, 0x8A, 0x8B, 0xC6, 0xC7, 0xCC, 0xCC, 0xCC, 0}, // MOV |
| 51 | 46 | ||
| 52 | {0x84, 0x85, 0x84, 0x85, 0xF6, 0xF7, 0xCC, 0xA8, 0xA9, 0}, //TEST (to == from) | 47 | {0x84, 0x85, 0x84, 0x85, 0xF6, 0xF7, 0xCC, 0xA8, 0xA9, 0}, // TEST (to == from) |
| 53 | {0x38, 0x39, 0x3A, 0x3B, 0x80, 0x81, 0x83, 0x3C, 0x3D, 7}, //CMP | 48 | {0x38, 0x39, 0x3A, 0x3B, 0x80, 0x81, 0x83, 0x3C, 0x3D, 7}, // CMP |
| 54 | 49 | ||
| 55 | {0x86, 0x87, 0x86, 0x87, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 7}, //XCHG | 50 | {0x86, 0x87, 0x86, 0x87, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 7}, // XCHG |
| 56 | }; | 51 | }; |
| 57 | 52 | ||
| 58 | enum NormalSSEOps | 53 | enum NormalSSEOps { |
| 59 | { | 54 | sseCMP = 0xC2, |
| 60 | sseCMP = 0xC2, | 55 | sseADD = 0x58, // ADD |
| 61 | sseADD = 0x58, //ADD | 56 | sseSUB = 0x5C, // SUB |
| 62 | sseSUB = 0x5C, //SUB | 57 | sseAND = 0x54, // AND |
| 63 | sseAND = 0x54, //AND | 58 | sseANDN = 0x55, // ANDN |
| 64 | sseANDN = 0x55, //ANDN | 59 | sseOR = 0x56, |
| 65 | sseOR = 0x56, | 60 | sseXOR = 0x57, |
| 66 | sseXOR = 0x57, | 61 | sseMUL = 0x59, // MUL |
| 67 | sseMUL = 0x59, //MUL | 62 | sseDIV = 0x5E, // DIV |
| 68 | sseDIV = 0x5E, //DIV | 63 | sseMIN = 0x5D, // MIN |
| 69 | sseMIN = 0x5D, //MIN | 64 | sseMAX = 0x5F, // MAX |
| 70 | sseMAX = 0x5F, //MAX | 65 | sseCOMIS = 0x2F, // COMIS |
| 71 | sseCOMIS = 0x2F, //COMIS | 66 | sseUCOMIS = 0x2E, // UCOMIS |
| 72 | sseUCOMIS = 0x2E, //UCOMIS | 67 | sseSQRT = 0x51, // SQRT |
| 73 | sseSQRT = 0x51, //SQRT | 68 | sseRSQRT = 0x52, // RSQRT (NO DOUBLE PRECISION!!!) |
| 74 | sseRSQRT = 0x52, //RSQRT (NO DOUBLE PRECISION!!!) | 69 | sseRCP = 0x53, // RCP |
| 75 | sseRCP = 0x53, //RCP | 70 | sseMOVAPfromRM = 0x28, // MOVAP from RM |
| 76 | sseMOVAPfromRM = 0x28, //MOVAP from RM | 71 | sseMOVAPtoRM = 0x29, // MOVAP to RM |
| 77 | sseMOVAPtoRM = 0x29, //MOVAP to RM | 72 | sseMOVUPfromRM = 0x10, // MOVUP from RM |
| 78 | sseMOVUPfromRM = 0x10, //MOVUP from RM | 73 | sseMOVUPtoRM = 0x11, // MOVUP to RM |
| 79 | sseMOVUPtoRM = 0x11, //MOVUP to RM | 74 | sseMOVLPfromRM = 0x12, |
| 80 | sseMOVLPfromRM= 0x12, | 75 | sseMOVLPtoRM = 0x13, |
| 81 | sseMOVLPtoRM = 0x13, | 76 | sseMOVHPfromRM = 0x16, |
| 82 | sseMOVHPfromRM= 0x16, | 77 | sseMOVHPtoRM = 0x17, |
| 83 | sseMOVHPtoRM = 0x17, | 78 | sseMOVHLPS = 0x12, |
| 84 | sseMOVHLPS = 0x12, | 79 | sseMOVLHPS = 0x16, |
| 85 | sseMOVLHPS = 0x16, | ||
| 86 | sseMOVDQfromRM = 0x6F, | 80 | sseMOVDQfromRM = 0x6F, |
| 87 | sseMOVDQtoRM = 0x7F, | 81 | sseMOVDQtoRM = 0x7F, |
| 88 | sseMASKMOVDQU = 0xF7, | 82 | sseMASKMOVDQU = 0xF7, |
| 89 | sseLDDQU = 0xF0, | 83 | sseLDDQU = 0xF0, |
| 90 | sseSHUF = 0xC6, | 84 | sseSHUF = 0xC6, |
| 91 | sseMOVNTDQ = 0xE7, | 85 | sseMOVNTDQ = 0xE7, |
| 92 | sseMOVNTP = 0x2B, | 86 | sseMOVNTP = 0x2B, |
| 93 | sseHADD = 0x7C, | 87 | sseHADD = 0x7C, |
| 94 | }; | 88 | }; |
| 95 | 89 | ||
| 96 | 90 | void XEmitter::SetCodePtr(u8* ptr) { | |
| 97 | void XEmitter::SetCodePtr(u8 *ptr) | ||
| 98 | { | ||
| 99 | code = ptr; | 91 | code = ptr; |
| 100 | } | 92 | } |
| 101 | 93 | ||
| 102 | const u8 *XEmitter::GetCodePtr() const | 94 | const u8* XEmitter::GetCodePtr() const { |
| 103 | { | ||
| 104 | return code; | 95 | return code; |
| 105 | } | 96 | } |
| 106 | 97 | ||
| 107 | u8 *XEmitter::GetWritableCodePtr() | 98 | u8* XEmitter::GetWritableCodePtr() { |
| 108 | { | ||
| 109 | return code; | 99 | return code; |
| 110 | } | 100 | } |
| 111 | 101 | ||
| 112 | void XEmitter::Write8(u8 value) | 102 | void XEmitter::Write8(u8 value) { |
| 113 | { | ||
| 114 | *code++ = value; | 103 | *code++ = value; |
| 115 | } | 104 | } |
| 116 | 105 | ||
| 117 | void XEmitter::Write16(u16 value) | 106 | void XEmitter::Write16(u16 value) { |
| 118 | { | ||
| 119 | std::memcpy(code, &value, sizeof(u16)); | 107 | std::memcpy(code, &value, sizeof(u16)); |
| 120 | code += sizeof(u16); | 108 | code += sizeof(u16); |
| 121 | } | 109 | } |
| 122 | 110 | ||
| 123 | void XEmitter::Write32(u32 value) | 111 | void XEmitter::Write32(u32 value) { |
| 124 | { | ||
| 125 | std::memcpy(code, &value, sizeof(u32)); | 112 | std::memcpy(code, &value, sizeof(u32)); |
| 126 | code += sizeof(u32); | 113 | code += sizeof(u32); |
| 127 | } | 114 | } |
| 128 | 115 | ||
| 129 | void XEmitter::Write64(u64 value) | 116 | void XEmitter::Write64(u64 value) { |
| 130 | { | ||
| 131 | std::memcpy(code, &value, sizeof(u64)); | 117 | std::memcpy(code, &value, sizeof(u64)); |
| 132 | code += sizeof(u64); | 118 | code += sizeof(u64); |
| 133 | } | 119 | } |
| 134 | 120 | ||
| 135 | void XEmitter::ReserveCodeSpace(int bytes) | 121 | void XEmitter::ReserveCodeSpace(int bytes) { |
| 136 | { | ||
| 137 | for (int i = 0; i < bytes; i++) | 122 | for (int i = 0; i < bytes; i++) |
| 138 | *code++ = 0xCC; | 123 | *code++ = 0xCC; |
| 139 | } | 124 | } |
| 140 | 125 | ||
| 141 | const u8 *XEmitter::AlignCode4() | 126 | const u8* XEmitter::AlignCode4() { |
| 142 | { | ||
| 143 | int c = int((u64)code & 3); | 127 | int c = int((u64)code & 3); |
| 144 | if (c) | 128 | if (c) |
| 145 | ReserveCodeSpace(4-c); | 129 | ReserveCodeSpace(4 - c); |
| 146 | return code; | 130 | return code; |
| 147 | } | 131 | } |
| 148 | 132 | ||
| 149 | const u8 *XEmitter::AlignCode16() | 133 | const u8* XEmitter::AlignCode16() { |
| 150 | { | ||
| 151 | int c = int((u64)code & 15); | 134 | int c = int((u64)code & 15); |
| 152 | if (c) | 135 | if (c) |
| 153 | ReserveCodeSpace(16-c); | 136 | ReserveCodeSpace(16 - c); |
| 154 | return code; | 137 | return code; |
| 155 | } | 138 | } |
| 156 | 139 | ||
| 157 | const u8 *XEmitter::AlignCodePage() | 140 | const u8* XEmitter::AlignCodePage() { |
| 158 | { | ||
| 159 | int c = int((u64)code & 4095); | 141 | int c = int((u64)code & 4095); |
| 160 | if (c) | 142 | if (c) |
| 161 | ReserveCodeSpace(4096-c); | 143 | ReserveCodeSpace(4096 - c); |
| 162 | return code; | 144 | return code; |
| 163 | } | 145 | } |
| 164 | 146 | ||
| 165 | // This operation modifies flags; check to see the flags are locked. | 147 | // This operation modifies flags; check to see the flags are locked. |
| 166 | // If the flags are locked, we should immediately and loudly fail before | 148 | // If the flags are locked, we should immediately and loudly fail before |
| 167 | // causing a subtle JIT bug. | 149 | // causing a subtle JIT bug. |
| 168 | void XEmitter::CheckFlags() | 150 | void XEmitter::CheckFlags() { |
| 169 | { | ||
| 170 | ASSERT_MSG(!flags_locked, "Attempt to modify flags while flags locked!"); | 151 | ASSERT_MSG(!flags_locked, "Attempt to modify flags while flags locked!"); |
| 171 | } | 152 | } |
| 172 | 153 | ||
| 173 | void XEmitter::WriteModRM(int mod, int reg, int rm) | 154 | void XEmitter::WriteModRM(int mod, int reg, int rm) { |
| 174 | { | ||
| 175 | Write8((u8)((mod << 6) | ((reg & 7) << 3) | (rm & 7))); | 155 | Write8((u8)((mod << 6) | ((reg & 7) << 3) | (rm & 7))); |
| 176 | } | 156 | } |
| 177 | 157 | ||
| 178 | void XEmitter::WriteSIB(int scale, int index, int base) | 158 | void XEmitter::WriteSIB(int scale, int index, int base) { |
| 179 | { | ||
| 180 | Write8((u8)((scale << 6) | ((index & 7) << 3) | (base & 7))); | 159 | Write8((u8)((scale << 6) | ((index & 7) << 3) | (base & 7))); |
| 181 | } | 160 | } |
| 182 | 161 | ||
| 183 | void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const | 162 | void OpArg::WriteRex(XEmitter* emit, int opBits, int bits, int customOp) const { |
| 184 | { | 163 | if (customOp == -1) |
| 185 | if (customOp == -1) customOp = operandReg; | 164 | customOp = operandReg; |
| 186 | #ifdef ARCHITECTURE_x86_64 | 165 | #ifdef ARCHITECTURE_x86_64 |
| 187 | u8 op = 0x40; | 166 | u8 op = 0x40; |
| 188 | // REX.W (whether operation is a 64-bit operation) | 167 | // REX.W (whether operation is a 64-bit operation) |
| 189 | if (opBits == 64) op |= 8; | 168 | if (opBits == 64) |
| 169 | op |= 8; | ||
| 190 | // REX.R (whether ModR/M reg field refers to R8-R15. | 170 | // REX.R (whether ModR/M reg field refers to R8-R15. |
| 191 | if (customOp & 8) op |= 4; | 171 | if (customOp & 8) |
| 172 | op |= 4; | ||
| 192 | // REX.X (whether ModR/M SIB index field refers to R8-R15) | 173 | // REX.X (whether ModR/M SIB index field refers to R8-R15) |
| 193 | if (indexReg & 8) op |= 2; | 174 | if (indexReg & 8) |
| 175 | op |= 2; | ||
| 194 | // REX.B (whether ModR/M rm or SIB base or opcode reg field refers to R8-R15) | 176 | // REX.B (whether ModR/M rm or SIB base or opcode reg field refers to R8-R15) |
| 195 | if (offsetOrBaseReg & 8) op |= 1; | 177 | if (offsetOrBaseReg & 8) |
| 178 | op |= 1; | ||
| 196 | // Write REX if wr have REX bits to write, or if the operation accesses | 179 | // Write REX if wr have REX bits to write, or if the operation accesses |
| 197 | // SIL, DIL, BPL, or SPL. | 180 | // SIL, DIL, BPL, or SPL. |
| 198 | if (op != 0x40 || | 181 | if (op != 0x40 || (scale == SCALE_NONE && bits == 8 && (offsetOrBaseReg & 0x10c) == 4) || |
| 199 | (scale == SCALE_NONE && bits == 8 && (offsetOrBaseReg & 0x10c) == 4) || | 182 | (opBits == 8 && (customOp & 0x10c) == 4)) { |
| 200 | (opBits == 8 && (customOp & 0x10c) == 4)) | ||
| 201 | { | ||
| 202 | emit->Write8(op); | 183 | emit->Write8(op); |
| 203 | // Check the operation doesn't access AH, BH, CH, or DH. | 184 | // Check the operation doesn't access AH, BH, CH, or DH. |
| 204 | DEBUG_ASSERT((offsetOrBaseReg & 0x100) == 0); | 185 | DEBUG_ASSERT((offsetOrBaseReg & 0x100) == 0); |
| @@ -214,8 +195,8 @@ void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const | |||
| 214 | #endif | 195 | #endif |
| 215 | } | 196 | } |
| 216 | 197 | ||
| 217 | void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, int W) const | 198 | void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, |
| 218 | { | 199 | int W) const { |
| 219 | int R = !(regOp1 & 8); | 200 | int R = !(regOp1 & 8); |
| 220 | int X = !(indexReg & 8); | 201 | int X = !(indexReg & 8); |
| 221 | int B = !(offsetOrBaseReg & 8); | 202 | int B = !(offsetOrBaseReg & 8); |
| @@ -223,14 +204,11 @@ void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp | |||
| 223 | int vvvv = (regOp2 == X64Reg::INVALID_REG) ? 0xf : (regOp2 ^ 0xf); | 204 | int vvvv = (regOp2 == X64Reg::INVALID_REG) ? 0xf : (regOp2 ^ 0xf); |
| 224 | 205 | ||
| 225 | // do we need any VEX fields that only appear in the three-byte form? | 206 | // do we need any VEX fields that only appear in the three-byte form? |
| 226 | if (X == 1 && B == 1 && W == 0 && mmmmm == 1) | 207 | if (X == 1 && B == 1 && W == 0 && mmmmm == 1) { |
| 227 | { | ||
| 228 | u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 2) | pp; | 208 | u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 2) | pp; |
| 229 | emit->Write8(0xC5); | 209 | emit->Write8(0xC5); |
| 230 | emit->Write8(RvvvvLpp); | 210 | emit->Write8(RvvvvLpp); |
| 231 | } | 211 | } else { |
| 232 | else | ||
| 233 | { | ||
| 234 | u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm; | 212 | u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm; |
| 235 | u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 2) | pp; | 213 | u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 2) | pp; |
| 236 | emit->Write8(0xC4); | 214 | emit->Write8(0xC4); |
| @@ -239,9 +217,8 @@ void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp | |||
| 239 | } | 217 | } |
| 240 | } | 218 | } |
| 241 | 219 | ||
| 242 | void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, | 220 | void OpArg::WriteRest(XEmitter* emit, int extraBytes, X64Reg _operandReg, |
| 243 | bool warn_64bit_offset) const | 221 | bool warn_64bit_offset) const { |
| 244 | { | ||
| 245 | if (_operandReg == INVALID_REG) | 222 | if (_operandReg == INVALID_REG) |
| 246 | _operandReg = (X64Reg)this->operandReg; | 223 | _operandReg = (X64Reg)this->operandReg; |
| 247 | int mod = 0; | 224 | int mod = 0; |
| @@ -249,21 +226,18 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, | |||
| 249 | bool SIB = false; | 226 | bool SIB = false; |
| 250 | int _offsetOrBaseReg = this->offsetOrBaseReg; | 227 | int _offsetOrBaseReg = this->offsetOrBaseReg; |
| 251 | 228 | ||
| 252 | if (scale == SCALE_RIP) //Also, on 32-bit, just an immediate address | 229 | if (scale == SCALE_RIP) // Also, on 32-bit, just an immediate address |
| 253 | { | 230 | { |
| 254 | // Oh, RIP addressing. | 231 | // Oh, RIP addressing. |
| 255 | _offsetOrBaseReg = 5; | 232 | _offsetOrBaseReg = 5; |
| 256 | emit->WriteModRM(0, _operandReg, _offsetOrBaseReg); | 233 | emit->WriteModRM(0, _operandReg, _offsetOrBaseReg); |
| 257 | //TODO : add some checks | 234 | // TODO : add some checks |
| 258 | #ifdef ARCHITECTURE_x86_64 | 235 | #ifdef ARCHITECTURE_x86_64 |
| 259 | u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes; | 236 | u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes; |
| 260 | s64 distance = (s64)offset - (s64)ripAddr; | 237 | s64 distance = (s64)offset - (s64)ripAddr; |
| 261 | ASSERT_MSG( | 238 | ASSERT_MSG((distance < 0x80000000LL && distance >= -0x80000000LL) || !warn_64bit_offset, |
| 262 | (distance < 0x80000000LL && | 239 | "WriteRest: op out of range (0x%" PRIx64 " uses 0x%" PRIx64 ")", ripAddr, |
| 263 | distance >= -0x80000000LL) || | 240 | offset); |
| 264 | !warn_64bit_offset, | ||
| 265 | "WriteRest: op out of range (0x%" PRIx64 " uses 0x%" PRIx64 ")", | ||
| 266 | ripAddr, offset); | ||
| 267 | s32 offs = (s32)distance; | 241 | s32 offs = (s32)distance; |
| 268 | emit->Write32((u32)offs); | 242 | emit->Write32((u32)offs); |
| 269 | #else | 243 | #else |
| @@ -272,66 +246,49 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, | |||
| 272 | return; | 246 | return; |
| 273 | } | 247 | } |
| 274 | 248 | ||
| 275 | if (scale == 0) | 249 | if (scale == 0) { |
| 276 | { | ||
| 277 | // Oh, no memory, Just a reg. | 250 | // Oh, no memory, Just a reg. |
| 278 | mod = 3; //11 | 251 | mod = 3; // 11 |
| 279 | } | 252 | } else if (scale >= 1) { |
| 280 | else if (scale >= 1) | 253 | // Ah good, no scaling. |
| 281 | { | 254 | if (scale == SCALE_ATREG && !((_offsetOrBaseReg & 7) == 4 || (_offsetOrBaseReg & 7) == 5)) { |
| 282 | //Ah good, no scaling. | 255 | // Okay, we're good. No SIB necessary. |
| 283 | if (scale == SCALE_ATREG && !((_offsetOrBaseReg & 7) == 4 || (_offsetOrBaseReg & 7) == 5)) | ||
| 284 | { | ||
| 285 | //Okay, we're good. No SIB necessary. | ||
| 286 | int ioff = (int)offset; | 256 | int ioff = (int)offset; |
| 287 | if (ioff == 0) | 257 | if (ioff == 0) { |
| 288 | { | ||
| 289 | mod = 0; | 258 | mod = 0; |
| 259 | } else if (ioff < -128 || ioff > 127) { | ||
| 260 | mod = 2; // 32-bit displacement | ||
| 261 | } else { | ||
| 262 | mod = 1; // 8-bit displacement | ||
| 290 | } | 263 | } |
| 291 | else if (ioff<-128 || ioff>127) | 264 | } else if (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8) { |
| 292 | { | ||
| 293 | mod = 2; //32-bit displacement | ||
| 294 | } | ||
| 295 | else | ||
| 296 | { | ||
| 297 | mod = 1; //8-bit displacement | ||
| 298 | } | ||
| 299 | } | ||
| 300 | else if (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8) | ||
| 301 | { | ||
| 302 | SIB = true; | 265 | SIB = true; |
| 303 | mod = 0; | 266 | mod = 0; |
| 304 | _offsetOrBaseReg = 5; | 267 | _offsetOrBaseReg = 5; |
| 305 | } | 268 | } else // if (scale != SCALE_ATREG) |
| 306 | else //if (scale != SCALE_ATREG) | ||
| 307 | { | 269 | { |
| 308 | if ((_offsetOrBaseReg & 7) == 4) //this would occupy the SIB encoding :( | 270 | if ((_offsetOrBaseReg & 7) == 4) // this would occupy the SIB encoding :( |
| 309 | { | 271 | { |
| 310 | //So we have to fake it with SIB encoding :( | 272 | // So we have to fake it with SIB encoding :( |
| 311 | SIB = true; | 273 | SIB = true; |
| 312 | } | 274 | } |
| 313 | 275 | ||
| 314 | if (scale >= SCALE_1 && scale < SCALE_ATREG) | 276 | if (scale >= SCALE_1 && scale < SCALE_ATREG) { |
| 315 | { | ||
| 316 | SIB = true; | 277 | SIB = true; |
| 317 | } | 278 | } |
| 318 | 279 | ||
| 319 | if (scale == SCALE_ATREG && ((_offsetOrBaseReg & 7) == 4)) | 280 | if (scale == SCALE_ATREG && ((_offsetOrBaseReg & 7) == 4)) { |
| 320 | { | ||
| 321 | SIB = true; | 281 | SIB = true; |
| 322 | ireg = _offsetOrBaseReg; | 282 | ireg = _offsetOrBaseReg; |
| 323 | } | 283 | } |
| 324 | 284 | ||
| 325 | //Okay, we're fine. Just disp encoding. | 285 | // Okay, we're fine. Just disp encoding. |
| 326 | //We need displacement. Which size? | 286 | // We need displacement. Which size? |
| 327 | int ioff = (int)(s64)offset; | 287 | int ioff = (int)(s64)offset; |
| 328 | if (ioff < -128 || ioff > 127) | 288 | if (ioff < -128 || ioff > 127) { |
| 329 | { | 289 | mod = 2; // 32-bit displacement |
| 330 | mod = 2; //32-bit displacement | 290 | } else { |
| 331 | } | 291 | mod = 1; // 8-bit displacement |
| 332 | else | ||
| 333 | { | ||
| 334 | mod = 1; //8-bit displacement | ||
| 335 | } | 292 | } |
| 336 | } | 293 | } |
| 337 | } | 294 | } |
| @@ -343,36 +300,55 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, | |||
| 343 | oreg = 4; | 300 | oreg = 4; |
| 344 | 301 | ||
| 345 | // TODO(ector): WTF is this if about? I don't remember writing it :-) | 302 | // TODO(ector): WTF is this if about? I don't remember writing it :-) |
| 346 | //if (RIP) | 303 | // if (RIP) |
| 347 | // oreg = 5; | 304 | // oreg = 5; |
| 348 | 305 | ||
| 349 | emit->WriteModRM(mod, _operandReg&7, oreg&7); | 306 | emit->WriteModRM(mod, _operandReg & 7, oreg & 7); |
| 350 | 307 | ||
| 351 | if (SIB) | 308 | if (SIB) { |
| 352 | { | 309 | // SIB byte |
| 353 | //SIB byte | ||
| 354 | int ss; | 310 | int ss; |
| 355 | switch (scale) | 311 | switch (scale) { |
| 356 | { | 312 | case SCALE_NONE: |
| 357 | case SCALE_NONE: _offsetOrBaseReg = 4; ss = 0; break; //RSP | 313 | _offsetOrBaseReg = 4; |
| 358 | case SCALE_1: ss = 0; break; | 314 | ss = 0; |
| 359 | case SCALE_2: ss = 1; break; | 315 | break; // RSP |
| 360 | case SCALE_4: ss = 2; break; | 316 | case SCALE_1: |
| 361 | case SCALE_8: ss = 3; break; | 317 | ss = 0; |
| 362 | case SCALE_NOBASE_2: ss = 1; break; | 318 | break; |
| 363 | case SCALE_NOBASE_4: ss = 2; break; | 319 | case SCALE_2: |
| 364 | case SCALE_NOBASE_8: ss = 3; break; | 320 | ss = 1; |
| 365 | case SCALE_ATREG: ss = 0; break; | 321 | break; |
| 366 | default: ASSERT_MSG(0, "Invalid scale for SIB byte"); ss = 0; break; | 322 | case SCALE_4: |
| 323 | ss = 2; | ||
| 324 | break; | ||
| 325 | case SCALE_8: | ||
| 326 | ss = 3; | ||
| 327 | break; | ||
| 328 | case SCALE_NOBASE_2: | ||
| 329 | ss = 1; | ||
| 330 | break; | ||
| 331 | case SCALE_NOBASE_4: | ||
| 332 | ss = 2; | ||
| 333 | break; | ||
| 334 | case SCALE_NOBASE_8: | ||
| 335 | ss = 3; | ||
| 336 | break; | ||
| 337 | case SCALE_ATREG: | ||
| 338 | ss = 0; | ||
| 339 | break; | ||
| 340 | default: | ||
| 341 | ASSERT_MSG(0, "Invalid scale for SIB byte"); | ||
| 342 | ss = 0; | ||
| 343 | break; | ||
| 367 | } | 344 | } |
| 368 | emit->Write8((u8)((ss << 6) | ((ireg&7)<<3) | (_offsetOrBaseReg&7))); | 345 | emit->Write8((u8)((ss << 6) | ((ireg & 7) << 3) | (_offsetOrBaseReg & 7))); |
| 369 | } | 346 | } |
| 370 | 347 | ||
| 371 | if (mod == 1) //8-bit disp | 348 | if (mod == 1) // 8-bit disp |
| 372 | { | 349 | { |
| 373 | emit->Write8((u8)(s8)(s32)offset); | 350 | emit->Write8((u8)(s8)(s32)offset); |
| 374 | } | 351 | } else if (mod == 2 || (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8)) // 32-bit disp |
| 375 | else if (mod == 2 || (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8)) //32-bit disp | ||
| 376 | { | 352 | { |
| 377 | emit->Write32((u32)offset); | 353 | emit->Write32((u32)offset); |
| 378 | } | 354 | } |
| @@ -382,8 +358,7 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, | |||
| 382 | // R = register# upper bit | 358 | // R = register# upper bit |
| 383 | // X = scale amnt upper bit | 359 | // X = scale amnt upper bit |
| 384 | // B = base register# upper bit | 360 | // B = base register# upper bit |
| 385 | void XEmitter::Rex(int w, int r, int x, int b) | 361 | void XEmitter::Rex(int w, int r, int x, int b) { |
| 386 | { | ||
| 387 | w = w ? 1 : 0; | 362 | w = w ? 1 : 0; |
| 388 | r = r ? 1 : 0; | 363 | r = r ? 1 : 0; |
| 389 | x = x ? 1 : 0; | 364 | x = x ? 1 : 0; |
| @@ -393,70 +368,60 @@ void XEmitter::Rex(int w, int r, int x, int b) | |||
| 393 | Write8(rx); | 368 | Write8(rx); |
| 394 | } | 369 | } |
| 395 | 370 | ||
| 396 | void XEmitter::JMP(const u8* addr, bool force5Bytes) | 371 | void XEmitter::JMP(const u8* addr, bool force5Bytes) { |
| 397 | { | ||
| 398 | u64 fn = (u64)addr; | 372 | u64 fn = (u64)addr; |
| 399 | if (!force5Bytes) | 373 | if (!force5Bytes) { |
| 400 | { | ||
| 401 | s64 distance = (s64)(fn - ((u64)code + 2)); | 374 | s64 distance = (s64)(fn - ((u64)code + 2)); |
| 402 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, | 375 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, |
| 403 | "Jump target too far away, needs force5Bytes = true"); | 376 | "Jump target too far away, needs force5Bytes = true"); |
| 404 | //8 bits will do | 377 | // 8 bits will do |
| 405 | Write8(0xEB); | 378 | Write8(0xEB); |
| 406 | Write8((u8)(s8)distance); | 379 | Write8((u8)(s8)distance); |
| 407 | } | 380 | } else { |
| 408 | else | ||
| 409 | { | ||
| 410 | s64 distance = (s64)(fn - ((u64)code + 5)); | 381 | s64 distance = (s64)(fn - ((u64)code + 5)); |
| 411 | 382 | ||
| 412 | ASSERT_MSG( | 383 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, |
| 413 | distance >= -0x80000000LL && distance < 0x80000000LL, | 384 | "Jump target too far away, needs indirect register"); |
| 414 | "Jump target too far away, needs indirect register"); | ||
| 415 | Write8(0xE9); | 385 | Write8(0xE9); |
| 416 | Write32((u32)(s32)distance); | 386 | Write32((u32)(s32)distance); |
| 417 | } | 387 | } |
| 418 | } | 388 | } |
| 419 | 389 | ||
| 420 | void XEmitter::JMPptr(const OpArg& arg2) | 390 | void XEmitter::JMPptr(const OpArg& arg2) { |
| 421 | { | ||
| 422 | OpArg arg = arg2; | 391 | OpArg arg = arg2; |
| 423 | if (arg.IsImm()) ASSERT_MSG(0, "JMPptr - Imm argument"); | 392 | if (arg.IsImm()) |
| 393 | ASSERT_MSG(0, "JMPptr - Imm argument"); | ||
| 424 | arg.operandReg = 4; | 394 | arg.operandReg = 4; |
| 425 | arg.WriteRex(this, 0, 0); | 395 | arg.WriteRex(this, 0, 0); |
| 426 | Write8(0xFF); | 396 | Write8(0xFF); |
| 427 | arg.WriteRest(this); | 397 | arg.WriteRest(this); |
| 428 | } | 398 | } |
| 429 | 399 | ||
| 430 | //Can be used to trap other processors, before overwriting their code | 400 | // Can be used to trap other processors, before overwriting their code |
| 431 | // not used in dolphin | 401 | // not used in dolphin |
| 432 | void XEmitter::JMPself() | 402 | void XEmitter::JMPself() { |
| 433 | { | ||
| 434 | Write8(0xEB); | 403 | Write8(0xEB); |
| 435 | Write8(0xFE); | 404 | Write8(0xFE); |
| 436 | } | 405 | } |
| 437 | 406 | ||
| 438 | void XEmitter::CALLptr(OpArg arg) | 407 | void XEmitter::CALLptr(OpArg arg) { |
| 439 | { | 408 | if (arg.IsImm()) |
| 440 | if (arg.IsImm()) ASSERT_MSG(0, "CALLptr - Imm argument"); | 409 | ASSERT_MSG(0, "CALLptr - Imm argument"); |
| 441 | arg.operandReg = 2; | 410 | arg.operandReg = 2; |
| 442 | arg.WriteRex(this, 0, 0); | 411 | arg.WriteRex(this, 0, 0); |
| 443 | Write8(0xFF); | 412 | Write8(0xFF); |
| 444 | arg.WriteRest(this); | 413 | arg.WriteRest(this); |
| 445 | } | 414 | } |
| 446 | 415 | ||
| 447 | void XEmitter::CALL(const void* fnptr) | 416 | void XEmitter::CALL(const void* fnptr) { |
| 448 | { | ||
| 449 | u64 distance = u64(fnptr) - (u64(code) + 5); | 417 | u64 distance = u64(fnptr) - (u64(code) + 5); |
| 450 | ASSERT_MSG( | 418 | ASSERT_MSG(distance < 0x0000000080000000ULL || distance >= 0xFFFFFFFF80000000ULL, |
| 451 | distance < 0x0000000080000000ULL || | 419 | "CALL out of range (%p calls %p)", code, fnptr); |
| 452 | distance >= 0xFFFFFFFF80000000ULL, | ||
| 453 | "CALL out of range (%p calls %p)", code, fnptr); | ||
| 454 | Write8(0xE8); | 420 | Write8(0xE8); |
| 455 | Write32(u32(distance)); | 421 | Write32(u32(distance)); |
| 456 | } | 422 | } |
| 457 | 423 | ||
| 458 | FixupBranch XEmitter::CALL() | 424 | FixupBranch XEmitter::CALL() { |
| 459 | { | ||
| 460 | FixupBranch branch; | 425 | FixupBranch branch; |
| 461 | branch.type = 1; | 426 | branch.type = 1; |
| 462 | branch.ptr = code + 5; | 427 | branch.ptr = code + 5; |
| @@ -467,38 +432,30 @@ FixupBranch XEmitter::CALL() | |||
| 467 | return branch; | 432 | return branch; |
| 468 | } | 433 | } |
| 469 | 434 | ||
| 470 | FixupBranch XEmitter::J(bool force5bytes) | 435 | FixupBranch XEmitter::J(bool force5bytes) { |
| 471 | { | ||
| 472 | FixupBranch branch; | 436 | FixupBranch branch; |
| 473 | branch.type = force5bytes ? 1 : 0; | 437 | branch.type = force5bytes ? 1 : 0; |
| 474 | branch.ptr = code + (force5bytes ? 5 : 2); | 438 | branch.ptr = code + (force5bytes ? 5 : 2); |
| 475 | if (!force5bytes) | 439 | if (!force5bytes) { |
| 476 | { | 440 | // 8 bits will do |
| 477 | //8 bits will do | ||
| 478 | Write8(0xEB); | 441 | Write8(0xEB); |
| 479 | Write8(0); | 442 | Write8(0); |
| 480 | } | 443 | } else { |
| 481 | else | ||
| 482 | { | ||
| 483 | Write8(0xE9); | 444 | Write8(0xE9); |
| 484 | Write32(0); | 445 | Write32(0); |
| 485 | } | 446 | } |
| 486 | return branch; | 447 | return branch; |
| 487 | } | 448 | } |
| 488 | 449 | ||
| 489 | FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes) | 450 | FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes) { |
| 490 | { | ||
| 491 | FixupBranch branch; | 451 | FixupBranch branch; |
| 492 | branch.type = force5bytes ? 1 : 0; | 452 | branch.type = force5bytes ? 1 : 0; |
| 493 | branch.ptr = code + (force5bytes ? 6 : 2); | 453 | branch.ptr = code + (force5bytes ? 6 : 2); |
| 494 | if (!force5bytes) | 454 | if (!force5bytes) { |
| 495 | { | 455 | // 8 bits will do |
| 496 | //8 bits will do | ||
| 497 | Write8(0x70 + conditionCode); | 456 | Write8(0x70 + conditionCode); |
| 498 | Write8(0); | 457 | Write8(0); |
| 499 | } | 458 | } else { |
| 500 | else | ||
| 501 | { | ||
| 502 | Write8(0x0F); | 459 | Write8(0x0F); |
| 503 | Write8(0x80 + conditionCode); | 460 | Write8(0x80 + conditionCode); |
| 504 | Write32(0); | 461 | Write32(0); |
| @@ -506,198 +463,268 @@ FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes) | |||
| 506 | return branch; | 463 | return branch; |
| 507 | } | 464 | } |
| 508 | 465 | ||
| 509 | void XEmitter::J_CC(CCFlags conditionCode, const u8* addr, bool force5bytes) | 466 | void XEmitter::J_CC(CCFlags conditionCode, const u8* addr, bool force5bytes) { |
| 510 | { | ||
| 511 | u64 fn = (u64)addr; | 467 | u64 fn = (u64)addr; |
| 512 | s64 distance = (s64)(fn - ((u64)code + 2)); | 468 | s64 distance = (s64)(fn - ((u64)code + 2)); |
| 513 | if (distance < -0x80 || distance >= 0x80 || force5bytes) | 469 | if (distance < -0x80 || distance >= 0x80 || force5bytes) { |
| 514 | { | ||
| 515 | distance = (s64)(fn - ((u64)code + 6)); | 470 | distance = (s64)(fn - ((u64)code + 6)); |
| 516 | ASSERT_MSG( | 471 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, |
| 517 | distance >= -0x80000000LL && distance < 0x80000000LL, | 472 | "Jump target too far away, needs indirect register"); |
| 518 | "Jump target too far away, needs indirect register"); | ||
| 519 | Write8(0x0F); | 473 | Write8(0x0F); |
| 520 | Write8(0x80 + conditionCode); | 474 | Write8(0x80 + conditionCode); |
| 521 | Write32((u32)(s32)distance); | 475 | Write32((u32)(s32)distance); |
| 522 | } | 476 | } else { |
| 523 | else | ||
| 524 | { | ||
| 525 | Write8(0x70 + conditionCode); | 477 | Write8(0x70 + conditionCode); |
| 526 | Write8((u8)(s8)distance); | 478 | Write8((u8)(s8)distance); |
| 527 | } | 479 | } |
| 528 | } | 480 | } |
| 529 | 481 | ||
| 530 | void XEmitter::SetJumpTarget(const FixupBranch& branch) | 482 | void XEmitter::SetJumpTarget(const FixupBranch& branch) { |
| 531 | { | 483 | if (branch.type == 0) { |
| 532 | if (branch.type == 0) | ||
| 533 | { | ||
| 534 | s64 distance = (s64)(code - branch.ptr); | 484 | s64 distance = (s64)(code - branch.ptr); |
| 535 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); | 485 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, |
| 486 | "Jump target too far away, needs force5Bytes = true"); | ||
| 536 | branch.ptr[-1] = (u8)(s8)distance; | 487 | branch.ptr[-1] = (u8)(s8)distance; |
| 537 | } | 488 | } else if (branch.type == 1) { |
| 538 | else if (branch.type == 1) | ||
| 539 | { | ||
| 540 | s64 distance = (s64)(code - branch.ptr); | 489 | s64 distance = (s64)(code - branch.ptr); |
| 541 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); | 490 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, |
| 491 | "Jump target too far away, needs indirect register"); | ||
| 542 | ((s32*)branch.ptr)[-1] = (s32)distance; | 492 | ((s32*)branch.ptr)[-1] = (s32)distance; |
| 543 | } | 493 | } |
| 544 | } | 494 | } |
| 545 | 495 | ||
| 546 | void XEmitter::SetJumpTarget(const FixupBranch& branch, const u8* target) | 496 | void XEmitter::SetJumpTarget(const FixupBranch& branch, const u8* target) { |
| 547 | { | 497 | if (branch.type == 0) { |
| 548 | if (branch.type == 0) | ||
| 549 | { | ||
| 550 | s64 distance = (s64)(target - branch.ptr); | 498 | s64 distance = (s64)(target - branch.ptr); |
| 551 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); | 499 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, |
| 500 | "Jump target too far away, needs force5Bytes = true"); | ||
| 552 | branch.ptr[-1] = (u8)(s8)distance; | 501 | branch.ptr[-1] = (u8)(s8)distance; |
| 553 | } | 502 | } else if (branch.type == 1) { |
| 554 | else if (branch.type == 1) | ||
| 555 | { | ||
| 556 | s64 distance = (s64)(target - branch.ptr); | 503 | s64 distance = (s64)(target - branch.ptr); |
| 557 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); | 504 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, |
| 505 | "Jump target too far away, needs indirect register"); | ||
| 558 | ((s32*)branch.ptr)[-1] = (s32)distance; | 506 | ((s32*)branch.ptr)[-1] = (s32)distance; |
| 559 | } | 507 | } |
| 560 | } | 508 | } |
| 561 | 509 | ||
| 562 | //Single byte opcodes | 510 | // Single byte opcodes |
| 563 | //There is no PUSHAD/POPAD in 64-bit mode. | 511 | // There is no PUSHAD/POPAD in 64-bit mode. |
| 564 | void XEmitter::INT3() {Write8(0xCC);} | 512 | void XEmitter::INT3() { |
| 565 | void XEmitter::RET() {Write8(0xC3);} | 513 | Write8(0xCC); |
| 566 | void XEmitter::RET_FAST() {Write8(0xF3); Write8(0xC3);} //two-byte return (rep ret) - recommended by AMD optimization manual for the case of jumping to a ret | 514 | } |
| 515 | void XEmitter::RET() { | ||
| 516 | Write8(0xC3); | ||
| 517 | } | ||
| 518 | void XEmitter::RET_FAST() { | ||
| 519 | Write8(0xF3); | ||
| 520 | Write8(0xC3); | ||
| 521 | } // two-byte return (rep ret) - recommended by AMD optimization manual for the case of jumping to a | ||
| 522 | // ret | ||
| 567 | 523 | ||
| 568 | // The first sign of decadence: optimized NOPs. | 524 | // The first sign of decadence: optimized NOPs. |
| 569 | void XEmitter::NOP(size_t size) | 525 | void XEmitter::NOP(size_t size) { |
| 570 | { | ||
| 571 | DEBUG_ASSERT((int)size > 0); | 526 | DEBUG_ASSERT((int)size > 0); |
| 572 | while (true) | 527 | while (true) { |
| 573 | { | 528 | switch (size) { |
| 574 | switch (size) | ||
| 575 | { | ||
| 576 | case 0: | 529 | case 0: |
| 577 | return; | 530 | return; |
| 578 | case 1: | 531 | case 1: |
| 579 | Write8(0x90); | 532 | Write8(0x90); |
| 580 | return; | 533 | return; |
| 581 | case 2: | 534 | case 2: |
| 582 | Write8(0x66); Write8(0x90); | 535 | Write8(0x66); |
| 536 | Write8(0x90); | ||
| 583 | return; | 537 | return; |
| 584 | case 3: | 538 | case 3: |
| 585 | Write8(0x0F); Write8(0x1F); Write8(0x00); | 539 | Write8(0x0F); |
| 540 | Write8(0x1F); | ||
| 541 | Write8(0x00); | ||
| 586 | return; | 542 | return; |
| 587 | case 4: | 543 | case 4: |
| 588 | Write8(0x0F); Write8(0x1F); Write8(0x40); Write8(0x00); | 544 | Write8(0x0F); |
| 545 | Write8(0x1F); | ||
| 546 | Write8(0x40); | ||
| 547 | Write8(0x00); | ||
| 589 | return; | 548 | return; |
| 590 | case 5: | 549 | case 5: |
| 591 | Write8(0x0F); Write8(0x1F); Write8(0x44); Write8(0x00); | 550 | Write8(0x0F); |
| 551 | Write8(0x1F); | ||
| 552 | Write8(0x44); | ||
| 553 | Write8(0x00); | ||
| 592 | Write8(0x00); | 554 | Write8(0x00); |
| 593 | return; | 555 | return; |
| 594 | case 6: | 556 | case 6: |
| 595 | Write8(0x66); Write8(0x0F); Write8(0x1F); Write8(0x44); | 557 | Write8(0x66); |
| 596 | Write8(0x00); Write8(0x00); | 558 | Write8(0x0F); |
| 559 | Write8(0x1F); | ||
| 560 | Write8(0x44); | ||
| 561 | Write8(0x00); | ||
| 562 | Write8(0x00); | ||
| 597 | return; | 563 | return; |
| 598 | case 7: | 564 | case 7: |
| 599 | Write8(0x0F); Write8(0x1F); Write8(0x80); Write8(0x00); | 565 | Write8(0x0F); |
| 600 | Write8(0x00); Write8(0x00); Write8(0x00); | 566 | Write8(0x1F); |
| 567 | Write8(0x80); | ||
| 568 | Write8(0x00); | ||
| 569 | Write8(0x00); | ||
| 570 | Write8(0x00); | ||
| 571 | Write8(0x00); | ||
| 601 | return; | 572 | return; |
| 602 | case 8: | 573 | case 8: |
| 603 | Write8(0x0F); Write8(0x1F); Write8(0x84); Write8(0x00); | 574 | Write8(0x0F); |
| 604 | Write8(0x00); Write8(0x00); Write8(0x00); Write8(0x00); | 575 | Write8(0x1F); |
| 576 | Write8(0x84); | ||
| 577 | Write8(0x00); | ||
| 578 | Write8(0x00); | ||
| 579 | Write8(0x00); | ||
| 580 | Write8(0x00); | ||
| 581 | Write8(0x00); | ||
| 605 | return; | 582 | return; |
| 606 | case 9: | 583 | case 9: |
| 607 | Write8(0x66); Write8(0x0F); Write8(0x1F); Write8(0x84); | 584 | Write8(0x66); |
| 608 | Write8(0x00); Write8(0x00); Write8(0x00); Write8(0x00); | 585 | Write8(0x0F); |
| 586 | Write8(0x1F); | ||
| 587 | Write8(0x84); | ||
| 588 | Write8(0x00); | ||
| 589 | Write8(0x00); | ||
| 590 | Write8(0x00); | ||
| 591 | Write8(0x00); | ||
| 609 | Write8(0x00); | 592 | Write8(0x00); |
| 610 | return; | 593 | return; |
| 611 | case 10: | 594 | case 10: |
| 612 | Write8(0x66); Write8(0x66); Write8(0x0F); Write8(0x1F); | 595 | Write8(0x66); |
| 613 | Write8(0x84); Write8(0x00); Write8(0x00); Write8(0x00); | 596 | Write8(0x66); |
| 614 | Write8(0x00); Write8(0x00); | 597 | Write8(0x0F); |
| 598 | Write8(0x1F); | ||
| 599 | Write8(0x84); | ||
| 600 | Write8(0x00); | ||
| 601 | Write8(0x00); | ||
| 602 | Write8(0x00); | ||
| 603 | Write8(0x00); | ||
| 604 | Write8(0x00); | ||
| 615 | return; | 605 | return; |
| 616 | default: | 606 | default: |
| 617 | // Even though x86 instructions are allowed to be up to 15 bytes long, | 607 | // Even though x86 instructions are allowed to be up to 15 bytes long, |
| 618 | // AMD advises against using NOPs longer than 11 bytes because they | 608 | // AMD advises against using NOPs longer than 11 bytes because they |
| 619 | // carry a performance penalty on CPUs older than AMD family 16h. | 609 | // carry a performance penalty on CPUs older than AMD family 16h. |
| 620 | Write8(0x66); Write8(0x66); Write8(0x66); Write8(0x0F); | 610 | Write8(0x66); |
| 621 | Write8(0x1F); Write8(0x84); Write8(0x00); Write8(0x00); | 611 | Write8(0x66); |
| 622 | Write8(0x00); Write8(0x00); Write8(0x00); | 612 | Write8(0x66); |
| 613 | Write8(0x0F); | ||
| 614 | Write8(0x1F); | ||
| 615 | Write8(0x84); | ||
| 616 | Write8(0x00); | ||
| 617 | Write8(0x00); | ||
| 618 | Write8(0x00); | ||
| 619 | Write8(0x00); | ||
| 620 | Write8(0x00); | ||
| 623 | size -= 11; | 621 | size -= 11; |
| 624 | continue; | 622 | continue; |
| 625 | } | 623 | } |
| 626 | } | 624 | } |
| 627 | } | 625 | } |
| 628 | 626 | ||
| 629 | void XEmitter::PAUSE() {Write8(0xF3); NOP();} //use in tight spinloops for energy saving on some cpu | 627 | void XEmitter::PAUSE() { |
| 630 | void XEmitter::CLC() {CheckFlags(); Write8(0xF8);} //clear carry | 628 | Write8(0xF3); |
| 631 | void XEmitter::CMC() {CheckFlags(); Write8(0xF5);} //flip carry | 629 | NOP(); |
| 632 | void XEmitter::STC() {CheckFlags(); Write8(0xF9);} //set carry | 630 | } // use in tight spinloops for energy saving on some cpu |
| 631 | void XEmitter::CLC() { | ||
| 632 | CheckFlags(); | ||
| 633 | Write8(0xF8); | ||
| 634 | } // clear carry | ||
| 635 | void XEmitter::CMC() { | ||
| 636 | CheckFlags(); | ||
| 637 | Write8(0xF5); | ||
| 638 | } // flip carry | ||
| 639 | void XEmitter::STC() { | ||
| 640 | CheckFlags(); | ||
| 641 | Write8(0xF9); | ||
| 642 | } // set carry | ||
| 633 | 643 | ||
| 634 | //TODO: xchg ah, al ??? | 644 | // TODO: xchg ah, al ??? |
| 635 | void XEmitter::XCHG_AHAL() | 645 | void XEmitter::XCHG_AHAL() { |
| 636 | { | ||
| 637 | Write8(0x86); | 646 | Write8(0x86); |
| 638 | Write8(0xe0); | 647 | Write8(0xe0); |
| 639 | // alt. 86 c4 | 648 | // alt. 86 c4 |
| 640 | } | 649 | } |
| 641 | 650 | ||
| 642 | //These two can not be executed on early Intel 64-bit CPU:s, only on AMD! | 651 | // These two can not be executed on early Intel 64-bit CPU:s, only on AMD! |
| 643 | void XEmitter::LAHF() {Write8(0x9F);} | 652 | void XEmitter::LAHF() { |
| 644 | void XEmitter::SAHF() {CheckFlags(); Write8(0x9E);} | 653 | Write8(0x9F); |
| 654 | } | ||
| 655 | void XEmitter::SAHF() { | ||
| 656 | CheckFlags(); | ||
| 657 | Write8(0x9E); | ||
| 658 | } | ||
| 645 | 659 | ||
| 646 | void XEmitter::PUSHF() {Write8(0x9C);} | 660 | void XEmitter::PUSHF() { |
| 647 | void XEmitter::POPF() {CheckFlags(); Write8(0x9D);} | 661 | Write8(0x9C); |
| 662 | } | ||
| 663 | void XEmitter::POPF() { | ||
| 664 | CheckFlags(); | ||
| 665 | Write8(0x9D); | ||
| 666 | } | ||
| 648 | 667 | ||
| 649 | void XEmitter::LFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xE8);} | 668 | void XEmitter::LFENCE() { |
| 650 | void XEmitter::MFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF0);} | 669 | Write8(0x0F); |
| 651 | void XEmitter::SFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF8);} | 670 | Write8(0xAE); |
| 671 | Write8(0xE8); | ||
| 672 | } | ||
| 673 | void XEmitter::MFENCE() { | ||
| 674 | Write8(0x0F); | ||
| 675 | Write8(0xAE); | ||
| 676 | Write8(0xF0); | ||
| 677 | } | ||
| 678 | void XEmitter::SFENCE() { | ||
| 679 | Write8(0x0F); | ||
| 680 | Write8(0xAE); | ||
| 681 | Write8(0xF8); | ||
| 682 | } | ||
| 652 | 683 | ||
| 653 | void XEmitter::WriteSimple1Byte(int bits, u8 byte, X64Reg reg) | 684 | void XEmitter::WriteSimple1Byte(int bits, u8 byte, X64Reg reg) { |
| 654 | { | ||
| 655 | if (bits == 16) | 685 | if (bits == 16) |
| 656 | Write8(0x66); | 686 | Write8(0x66); |
| 657 | Rex(bits == 64, 0, 0, (int)reg >> 3); | 687 | Rex(bits == 64, 0, 0, (int)reg >> 3); |
| 658 | Write8(byte + ((int)reg & 7)); | 688 | Write8(byte + ((int)reg & 7)); |
| 659 | } | 689 | } |
| 660 | 690 | ||
| 661 | void XEmitter::WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg) | 691 | void XEmitter::WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg) { |
| 662 | { | ||
| 663 | if (bits == 16) | 692 | if (bits == 16) |
| 664 | Write8(0x66); | 693 | Write8(0x66); |
| 665 | Rex(bits==64, 0, 0, (int)reg >> 3); | 694 | Rex(bits == 64, 0, 0, (int)reg >> 3); |
| 666 | Write8(byte1); | 695 | Write8(byte1); |
| 667 | Write8(byte2 + ((int)reg & 7)); | 696 | Write8(byte2 + ((int)reg & 7)); |
| 668 | } | 697 | } |
| 669 | 698 | ||
| 670 | void XEmitter::CWD(int bits) | 699 | void XEmitter::CWD(int bits) { |
| 671 | { | ||
| 672 | if (bits == 16) | 700 | if (bits == 16) |
| 673 | Write8(0x66); | 701 | Write8(0x66); |
| 674 | Rex(bits == 64, 0, 0, 0); | 702 | Rex(bits == 64, 0, 0, 0); |
| 675 | Write8(0x99); | 703 | Write8(0x99); |
| 676 | } | 704 | } |
| 677 | 705 | ||
| 678 | void XEmitter::CBW(int bits) | 706 | void XEmitter::CBW(int bits) { |
| 679 | { | ||
| 680 | if (bits == 8) | 707 | if (bits == 8) |
| 681 | Write8(0x66); | 708 | Write8(0x66); |
| 682 | Rex(bits == 32, 0, 0, 0); | 709 | Rex(bits == 32, 0, 0, 0); |
| 683 | Write8(0x98); | 710 | Write8(0x98); |
| 684 | } | 711 | } |
| 685 | 712 | ||
| 686 | //Simple opcodes | 713 | // Simple opcodes |
| 687 | 714 | ||
| 715 | // push/pop do not need wide to be 64-bit | ||
| 716 | void XEmitter::PUSH(X64Reg reg) { | ||
| 717 | WriteSimple1Byte(32, 0x50, reg); | ||
| 718 | } | ||
| 719 | void XEmitter::POP(X64Reg reg) { | ||
| 720 | WriteSimple1Byte(32, 0x58, reg); | ||
| 721 | } | ||
| 688 | 722 | ||
| 689 | //push/pop do not need wide to be 64-bit | 723 | void XEmitter::PUSH(int bits, const OpArg& reg) { |
| 690 | void XEmitter::PUSH(X64Reg reg) {WriteSimple1Byte(32, 0x50, reg);} | ||
| 691 | void XEmitter::POP(X64Reg reg) {WriteSimple1Byte(32, 0x58, reg);} | ||
| 692 | |||
| 693 | void XEmitter::PUSH(int bits, const OpArg& reg) | ||
| 694 | { | ||
| 695 | if (reg.IsSimpleReg()) | 724 | if (reg.IsSimpleReg()) |
| 696 | PUSH(reg.GetSimpleReg()); | 725 | PUSH(reg.GetSimpleReg()); |
| 697 | else if (reg.IsImm()) | 726 | else if (reg.IsImm()) { |
| 698 | { | 727 | switch (reg.GetImmBits()) { |
| 699 | switch (reg.GetImmBits()) | ||
| 700 | { | ||
| 701 | case 8: | 728 | case 8: |
| 702 | Write8(0x6A); | 729 | Write8(0x6A); |
| 703 | Write8((u8)(s8)reg.offset); | 730 | Write8((u8)(s8)reg.offset); |
| @@ -715,9 +742,7 @@ void XEmitter::PUSH(int bits, const OpArg& reg) | |||
| 715 | ASSERT_MSG(0, "PUSH - Bad imm bits"); | 742 | ASSERT_MSG(0, "PUSH - Bad imm bits"); |
| 716 | break; | 743 | break; |
| 717 | } | 744 | } |
| 718 | } | 745 | } else { |
| 719 | else | ||
| 720 | { | ||
| 721 | if (bits == 16) | 746 | if (bits == 16) |
| 722 | Write8(0x66); | 747 | Write8(0x66); |
| 723 | reg.WriteRex(this, bits, bits); | 748 | reg.WriteRex(this, bits, bits); |
| @@ -726,44 +751,33 @@ void XEmitter::PUSH(int bits, const OpArg& reg) | |||
| 726 | } | 751 | } |
| 727 | } | 752 | } |
| 728 | 753 | ||
| 729 | void XEmitter::POP(int /*bits*/, const OpArg& reg) | 754 | void XEmitter::POP(int /*bits*/, const OpArg& reg) { |
| 730 | { | ||
| 731 | if (reg.IsSimpleReg()) | 755 | if (reg.IsSimpleReg()) |
| 732 | POP(reg.GetSimpleReg()); | 756 | POP(reg.GetSimpleReg()); |
| 733 | else | 757 | else |
| 734 | ASSERT_MSG(0, "POP - Unsupported encoding"); | 758 | ASSERT_MSG(0, "POP - Unsupported encoding"); |
| 735 | } | 759 | } |
| 736 | 760 | ||
| 737 | void XEmitter::BSWAP(int bits, X64Reg reg) | 761 | void XEmitter::BSWAP(int bits, X64Reg reg) { |
| 738 | { | 762 | if (bits >= 32) { |
| 739 | if (bits >= 32) | ||
| 740 | { | ||
| 741 | WriteSimple2Byte(bits, 0x0F, 0xC8, reg); | 763 | WriteSimple2Byte(bits, 0x0F, 0xC8, reg); |
| 742 | } | 764 | } else if (bits == 16) { |
| 743 | else if (bits == 16) | ||
| 744 | { | ||
| 745 | ROL(16, R(reg), Imm8(8)); | 765 | ROL(16, R(reg), Imm8(8)); |
| 746 | } | 766 | } else if (bits == 8) { |
| 747 | else if (bits == 8) | ||
| 748 | { | ||
| 749 | // Do nothing - can't bswap a single byte... | 767 | // Do nothing - can't bswap a single byte... |
| 750 | } | 768 | } else { |
| 751 | else | ||
| 752 | { | ||
| 753 | ASSERT_MSG(0, "BSWAP - Wrong number of bits"); | 769 | ASSERT_MSG(0, "BSWAP - Wrong number of bits"); |
| 754 | } | 770 | } |
| 755 | } | 771 | } |
| 756 | 772 | ||
| 757 | // Undefined opcode - reserved | 773 | // Undefined opcode - reserved |
| 758 | // If we ever need a way to always cause a non-breakpoint hard exception... | 774 | // If we ever need a way to always cause a non-breakpoint hard exception... |
| 759 | void XEmitter::UD2() | 775 | void XEmitter::UD2() { |
| 760 | { | ||
| 761 | Write8(0x0F); | 776 | Write8(0x0F); |
| 762 | Write8(0x0B); | 777 | Write8(0x0B); |
| 763 | } | 778 | } |
| 764 | 779 | ||
| 765 | void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) | 780 | void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) { |
| 766 | { | ||
| 767 | ASSERT_MSG(!arg.IsImm(), "PREFETCH - Imm argument"); | 781 | ASSERT_MSG(!arg.IsImm(), "PREFETCH - Imm argument"); |
| 768 | arg.operandReg = (u8)level; | 782 | arg.operandReg = (u8)level; |
| 769 | arg.WriteRex(this, 0, 0); | 783 | arg.WriteRex(this, 0, 0); |
| @@ -772,8 +786,7 @@ void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) | |||
| 772 | arg.WriteRest(this); | 786 | arg.WriteRest(this); |
| 773 | } | 787 | } |
| 774 | 788 | ||
| 775 | void XEmitter::SETcc(CCFlags flag, OpArg dest) | 789 | void XEmitter::SETcc(CCFlags flag, OpArg dest) { |
| 776 | { | ||
| 777 | ASSERT_MSG(!dest.IsImm(), "SETcc - Imm argument"); | 790 | ASSERT_MSG(!dest.IsImm(), "SETcc - Imm argument"); |
| 778 | dest.operandReg = 0; | 791 | dest.operandReg = 0; |
| 779 | dest.WriteRex(this, 0, 8); | 792 | dest.WriteRex(this, 0, 8); |
| @@ -782,8 +795,7 @@ void XEmitter::SETcc(CCFlags flag, OpArg dest) | |||
| 782 | dest.WriteRest(this); | 795 | dest.WriteRest(this); |
| 783 | } | 796 | } |
| 784 | 797 | ||
| 785 | void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) | 798 | void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) { |
| 786 | { | ||
| 787 | ASSERT_MSG(!src.IsImm(), "CMOVcc - Imm argument"); | 799 | ASSERT_MSG(!src.IsImm(), "CMOVcc - Imm argument"); |
| 788 | ASSERT_MSG(bits != 8, "CMOVcc - 8 bits unsupported"); | 800 | ASSERT_MSG(bits != 8, "CMOVcc - 8 bits unsupported"); |
| 789 | if (bits == 16) | 801 | if (bits == 16) |
| @@ -795,34 +807,41 @@ void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) | |||
| 795 | src.WriteRest(this); | 807 | src.WriteRest(this); |
| 796 | } | 808 | } |
| 797 | 809 | ||
| 798 | void XEmitter::WriteMulDivType(int bits, OpArg src, int ext) | 810 | void XEmitter::WriteMulDivType(int bits, OpArg src, int ext) { |
| 799 | { | ||
| 800 | ASSERT_MSG(!src.IsImm(), "WriteMulDivType - Imm argument"); | 811 | ASSERT_MSG(!src.IsImm(), "WriteMulDivType - Imm argument"); |
| 801 | CheckFlags(); | 812 | CheckFlags(); |
| 802 | src.operandReg = ext; | 813 | src.operandReg = ext; |
| 803 | if (bits == 16) | 814 | if (bits == 16) |
| 804 | Write8(0x66); | 815 | Write8(0x66); |
| 805 | src.WriteRex(this, bits, bits, 0); | 816 | src.WriteRex(this, bits, bits, 0); |
| 806 | if (bits == 8) | 817 | if (bits == 8) { |
| 807 | { | ||
| 808 | Write8(0xF6); | 818 | Write8(0xF6); |
| 809 | } | 819 | } else { |
| 810 | else | ||
| 811 | { | ||
| 812 | Write8(0xF7); | 820 | Write8(0xF7); |
| 813 | } | 821 | } |
| 814 | src.WriteRest(this); | 822 | src.WriteRest(this); |
| 815 | } | 823 | } |
| 816 | 824 | ||
| 817 | void XEmitter::MUL(int bits, const OpArg& src) {WriteMulDivType(bits, src, 4);} | 825 | void XEmitter::MUL(int bits, const OpArg& src) { |
| 818 | void XEmitter::DIV(int bits, const OpArg& src) {WriteMulDivType(bits, src, 6);} | 826 | WriteMulDivType(bits, src, 4); |
| 819 | void XEmitter::IMUL(int bits, const OpArg& src) {WriteMulDivType(bits, src, 5);} | 827 | } |
| 820 | void XEmitter::IDIV(int bits, const OpArg& src) {WriteMulDivType(bits, src, 7);} | 828 | void XEmitter::DIV(int bits, const OpArg& src) { |
| 821 | void XEmitter::NEG(int bits, const OpArg& src) {WriteMulDivType(bits, src, 3);} | 829 | WriteMulDivType(bits, src, 6); |
| 822 | void XEmitter::NOT(int bits, const OpArg& src) {WriteMulDivType(bits, src, 2);} | 830 | } |
| 831 | void XEmitter::IMUL(int bits, const OpArg& src) { | ||
| 832 | WriteMulDivType(bits, src, 5); | ||
| 833 | } | ||
| 834 | void XEmitter::IDIV(int bits, const OpArg& src) { | ||
| 835 | WriteMulDivType(bits, src, 7); | ||
| 836 | } | ||
| 837 | void XEmitter::NEG(int bits, const OpArg& src) { | ||
| 838 | WriteMulDivType(bits, src, 3); | ||
| 839 | } | ||
| 840 | void XEmitter::NOT(int bits, const OpArg& src) { | ||
| 841 | WriteMulDivType(bits, src, 2); | ||
| 842 | } | ||
| 823 | 843 | ||
| 824 | void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep) | 844 | void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep) { |
| 825 | { | ||
| 826 | ASSERT_MSG(!src.IsImm(), "WriteBitSearchType - Imm argument"); | 845 | ASSERT_MSG(!src.IsImm(), "WriteBitSearchType - Imm argument"); |
| 827 | CheckFlags(); | 846 | CheckFlags(); |
| 828 | src.operandReg = (u8)dest; | 847 | src.operandReg = (u8)dest; |
| @@ -836,36 +855,35 @@ void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bo | |||
| 836 | src.WriteRest(this); | 855 | src.WriteRest(this); |
| 837 | } | 856 | } |
| 838 | 857 | ||
| 839 | void XEmitter::MOVNTI(int bits, const OpArg& dest, X64Reg src) | 858 | void XEmitter::MOVNTI(int bits, const OpArg& dest, X64Reg src) { |
| 840 | { | ||
| 841 | if (bits <= 16) | 859 | if (bits <= 16) |
| 842 | ASSERT_MSG(0, "MOVNTI - bits<=16"); | 860 | ASSERT_MSG(0, "MOVNTI - bits<=16"); |
| 843 | WriteBitSearchType(bits, src, dest, 0xC3); | 861 | WriteBitSearchType(bits, src, dest, 0xC3); |
| 844 | } | 862 | } |
| 845 | 863 | ||
| 846 | void XEmitter::BSF(int bits, X64Reg dest, const OpArg& src) {WriteBitSearchType(bits,dest,src,0xBC);} // Bottom bit to top bit | 864 | void XEmitter::BSF(int bits, X64Reg dest, const OpArg& src) { |
| 847 | void XEmitter::BSR(int bits, X64Reg dest, const OpArg& src) {WriteBitSearchType(bits,dest,src,0xBD);} // Top bit to bottom bit | 865 | WriteBitSearchType(bits, dest, src, 0xBC); |
| 866 | } // Bottom bit to top bit | ||
| 867 | void XEmitter::BSR(int bits, X64Reg dest, const OpArg& src) { | ||
| 868 | WriteBitSearchType(bits, dest, src, 0xBD); | ||
| 869 | } // Top bit to bottom bit | ||
| 848 | 870 | ||
| 849 | void XEmitter::TZCNT(int bits, X64Reg dest, const OpArg& src) | 871 | void XEmitter::TZCNT(int bits, X64Reg dest, const OpArg& src) { |
| 850 | { | ||
| 851 | CheckFlags(); | 872 | CheckFlags(); |
| 852 | if (!Common::GetCPUCaps().bmi1) | 873 | if (!Common::GetCPUCaps().bmi1) |
| 853 | ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer."); | 874 | ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer."); |
| 854 | WriteBitSearchType(bits, dest, src, 0xBC, true); | 875 | WriteBitSearchType(bits, dest, src, 0xBC, true); |
| 855 | } | 876 | } |
| 856 | void XEmitter::LZCNT(int bits, X64Reg dest, const OpArg& src) | 877 | void XEmitter::LZCNT(int bits, X64Reg dest, const OpArg& src) { |
| 857 | { | ||
| 858 | CheckFlags(); | 878 | CheckFlags(); |
| 859 | if (!Common::GetCPUCaps().lzcnt) | 879 | if (!Common::GetCPUCaps().lzcnt) |
| 860 | ASSERT_MSG(0, "Trying to use LZCNT on a system that doesn't support it. Bad programmer."); | 880 | ASSERT_MSG(0, "Trying to use LZCNT on a system that doesn't support it. Bad programmer."); |
| 861 | WriteBitSearchType(bits, dest, src, 0xBD, true); | 881 | WriteBitSearchType(bits, dest, src, 0xBD, true); |
| 862 | } | 882 | } |
| 863 | 883 | ||
| 864 | void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) | 884 | void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) { |
| 865 | { | ||
| 866 | ASSERT_MSG(!src.IsImm(), "MOVSX - Imm argument"); | 885 | ASSERT_MSG(!src.IsImm(), "MOVSX - Imm argument"); |
| 867 | if (dbits == sbits) | 886 | if (dbits == sbits) { |
| 868 | { | ||
| 869 | MOV(dbits, R(dest), src); | 887 | MOV(dbits, R(dest), src); |
| 870 | return; | 888 | return; |
| 871 | } | 889 | } |
| @@ -873,66 +891,49 @@ void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) | |||
| 873 | if (dbits == 16) | 891 | if (dbits == 16) |
| 874 | Write8(0x66); | 892 | Write8(0x66); |
| 875 | src.WriteRex(this, dbits, sbits); | 893 | src.WriteRex(this, dbits, sbits); |
| 876 | if (sbits == 8) | 894 | if (sbits == 8) { |
| 877 | { | ||
| 878 | Write8(0x0F); | 895 | Write8(0x0F); |
| 879 | Write8(0xBE); | 896 | Write8(0xBE); |
| 880 | } | 897 | } else if (sbits == 16) { |
| 881 | else if (sbits == 16) | ||
| 882 | { | ||
| 883 | Write8(0x0F); | 898 | Write8(0x0F); |
| 884 | Write8(0xBF); | 899 | Write8(0xBF); |
| 885 | } | 900 | } else if (sbits == 32 && dbits == 64) { |
| 886 | else if (sbits == 32 && dbits == 64) | ||
| 887 | { | ||
| 888 | Write8(0x63); | 901 | Write8(0x63); |
| 889 | } | 902 | } else { |
| 890 | else | ||
| 891 | { | ||
| 892 | Crash(); | 903 | Crash(); |
| 893 | } | 904 | } |
| 894 | src.WriteRest(this); | 905 | src.WriteRest(this); |
| 895 | } | 906 | } |
| 896 | 907 | ||
| 897 | void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src) | 908 | void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src) { |
| 898 | { | ||
| 899 | ASSERT_MSG(!src.IsImm(), "MOVZX - Imm argument"); | 909 | ASSERT_MSG(!src.IsImm(), "MOVZX - Imm argument"); |
| 900 | if (dbits == sbits) | 910 | if (dbits == sbits) { |
| 901 | { | ||
| 902 | MOV(dbits, R(dest), src); | 911 | MOV(dbits, R(dest), src); |
| 903 | return; | 912 | return; |
| 904 | } | 913 | } |
| 905 | src.operandReg = (u8)dest; | 914 | src.operandReg = (u8)dest; |
| 906 | if (dbits == 16) | 915 | if (dbits == 16) |
| 907 | Write8(0x66); | 916 | Write8(0x66); |
| 908 | //the 32bit result is automatically zero extended to 64bit | 917 | // the 32bit result is automatically zero extended to 64bit |
| 909 | src.WriteRex(this, dbits == 64 ? 32 : dbits, sbits); | 918 | src.WriteRex(this, dbits == 64 ? 32 : dbits, sbits); |
| 910 | if (sbits == 8) | 919 | if (sbits == 8) { |
| 911 | { | ||
| 912 | Write8(0x0F); | 920 | Write8(0x0F); |
| 913 | Write8(0xB6); | 921 | Write8(0xB6); |
| 914 | } | 922 | } else if (sbits == 16) { |
| 915 | else if (sbits == 16) | ||
| 916 | { | ||
| 917 | Write8(0x0F); | 923 | Write8(0x0F); |
| 918 | Write8(0xB7); | 924 | Write8(0xB7); |
| 919 | } | 925 | } else if (sbits == 32 && dbits == 64) { |
| 920 | else if (sbits == 32 && dbits == 64) | ||
| 921 | { | ||
| 922 | Write8(0x8B); | 926 | Write8(0x8B); |
| 923 | } | 927 | } else { |
| 924 | else | ||
| 925 | { | ||
| 926 | ASSERT_MSG(0, "MOVZX - Invalid size"); | 928 | ASSERT_MSG(0, "MOVZX - Invalid size"); |
| 927 | } | 929 | } |
| 928 | src.WriteRest(this); | 930 | src.WriteRest(this); |
| 929 | } | 931 | } |
| 930 | 932 | ||
| 931 | void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) | 933 | void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) { |
| 932 | { | 934 | ASSERT_MSG(Common::GetCPUCaps().movbe, |
| 933 | ASSERT_MSG(Common::GetCPUCaps().movbe, "Generating MOVBE on a system that does not support it."); | 935 | "Generating MOVBE on a system that does not support it."); |
| 934 | if (bits == 8) | 936 | if (bits == 8) { |
| 935 | { | ||
| 936 | MOV(bits, dest, src); | 937 | MOV(bits, dest, src); |
| 937 | return; | 938 | return; |
| 938 | } | 939 | } |
| @@ -940,71 +941,60 @@ void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) | |||
| 940 | if (bits == 16) | 941 | if (bits == 16) |
| 941 | Write8(0x66); | 942 | Write8(0x66); |
| 942 | 943 | ||
| 943 | if (dest.IsSimpleReg()) | 944 | if (dest.IsSimpleReg()) { |
| 944 | { | ||
| 945 | ASSERT_MSG(!src.IsSimpleReg() && !src.IsImm(), "MOVBE: Loading from !mem"); | 945 | ASSERT_MSG(!src.IsSimpleReg() && !src.IsImm(), "MOVBE: Loading from !mem"); |
| 946 | src.WriteRex(this, bits, bits, dest.GetSimpleReg()); | 946 | src.WriteRex(this, bits, bits, dest.GetSimpleReg()); |
| 947 | Write8(0x0F); Write8(0x38); Write8(0xF0); | 947 | Write8(0x0F); |
| 948 | Write8(0x38); | ||
| 949 | Write8(0xF0); | ||
| 948 | src.WriteRest(this, 0, dest.GetSimpleReg()); | 950 | src.WriteRest(this, 0, dest.GetSimpleReg()); |
| 949 | } | 951 | } else if (src.IsSimpleReg()) { |
| 950 | else if (src.IsSimpleReg()) | ||
| 951 | { | ||
| 952 | ASSERT_MSG(!dest.IsSimpleReg() && !dest.IsImm(), "MOVBE: Storing to !mem"); | 952 | ASSERT_MSG(!dest.IsSimpleReg() && !dest.IsImm(), "MOVBE: Storing to !mem"); |
| 953 | dest.WriteRex(this, bits, bits, src.GetSimpleReg()); | 953 | dest.WriteRex(this, bits, bits, src.GetSimpleReg()); |
| 954 | Write8(0x0F); Write8(0x38); Write8(0xF1); | 954 | Write8(0x0F); |
| 955 | Write8(0x38); | ||
| 956 | Write8(0xF1); | ||
| 955 | dest.WriteRest(this, 0, src.GetSimpleReg()); | 957 | dest.WriteRest(this, 0, src.GetSimpleReg()); |
| 956 | } | 958 | } else { |
| 957 | else | ||
| 958 | { | ||
| 959 | ASSERT_MSG(0, "MOVBE: Not loading or storing to mem"); | 959 | ASSERT_MSG(0, "MOVBE: Not loading or storing to mem"); |
| 960 | } | 960 | } |
| 961 | } | 961 | } |
| 962 | 962 | ||
| 963 | 963 | void XEmitter::LEA(int bits, X64Reg dest, OpArg src) { | |
| 964 | void XEmitter::LEA(int bits, X64Reg dest, OpArg src) | ||
| 965 | { | ||
| 966 | ASSERT_MSG(!src.IsImm(), "LEA - Imm argument"); | 964 | ASSERT_MSG(!src.IsImm(), "LEA - Imm argument"); |
| 967 | src.operandReg = (u8)dest; | 965 | src.operandReg = (u8)dest; |
| 968 | if (bits == 16) | 966 | if (bits == 16) |
| 969 | Write8(0x66); //TODO: performance warning | 967 | Write8(0x66); // TODO: performance warning |
| 970 | src.WriteRex(this, bits, bits); | 968 | src.WriteRex(this, bits, bits); |
| 971 | Write8(0x8D); | 969 | Write8(0x8D); |
| 972 | src.WriteRest(this, 0, INVALID_REG, bits == 64); | 970 | src.WriteRest(this, 0, INVALID_REG, bits == 64); |
| 973 | } | 971 | } |
| 974 | 972 | ||
| 975 | //shift can be either imm8 or cl | 973 | // shift can be either imm8 or cl |
| 976 | void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext) | 974 | void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext) { |
| 977 | { | ||
| 978 | CheckFlags(); | 975 | CheckFlags(); |
| 979 | bool writeImm = false; | 976 | bool writeImm = false; |
| 980 | if (dest.IsImm()) | 977 | if (dest.IsImm()) { |
| 981 | { | ||
| 982 | ASSERT_MSG(0, "WriteShift - can't shift imms"); | 978 | ASSERT_MSG(0, "WriteShift - can't shift imms"); |
| 983 | } | 979 | } |
| 984 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) | 980 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || |
| 985 | { | 981 | (shift.IsImm() && shift.GetImmBits() != 8)) { |
| 986 | ASSERT_MSG(0, "WriteShift - illegal argument"); | 982 | ASSERT_MSG(0, "WriteShift - illegal argument"); |
| 987 | } | 983 | } |
| 988 | dest.operandReg = ext; | 984 | dest.operandReg = ext; |
| 989 | if (bits == 16) | 985 | if (bits == 16) |
| 990 | Write8(0x66); | 986 | Write8(0x66); |
| 991 | dest.WriteRex(this, bits, bits, 0); | 987 | dest.WriteRex(this, bits, bits, 0); |
| 992 | if (shift.GetImmBits() == 8) | 988 | if (shift.GetImmBits() == 8) { |
| 993 | { | 989 | // ok an imm |
| 994 | //ok an imm | ||
| 995 | u8 imm = (u8)shift.offset; | 990 | u8 imm = (u8)shift.offset; |
| 996 | if (imm == 1) | 991 | if (imm == 1) { |
| 997 | { | ||
| 998 | Write8(bits == 8 ? 0xD0 : 0xD1); | 992 | Write8(bits == 8 ? 0xD0 : 0xD1); |
| 999 | } | 993 | } else { |
| 1000 | else | ||
| 1001 | { | ||
| 1002 | writeImm = true; | 994 | writeImm = true; |
| 1003 | Write8(bits == 8 ? 0xC0 : 0xC1); | 995 | Write8(bits == 8 ? 0xC0 : 0xC1); |
| 1004 | } | 996 | } |
| 1005 | } | 997 | } else { |
| 1006 | else | ||
| 1007 | { | ||
| 1008 | Write8(bits == 8 ? 0xD2 : 0xD3); | 998 | Write8(bits == 8 ? 0xD2 : 0xD3); |
| 1009 | } | 999 | } |
| 1010 | dest.WriteRest(this, writeImm ? 1 : 0); | 1000 | dest.WriteRest(this, writeImm ? 1 : 0); |
| @@ -1014,116 +1004,125 @@ void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext) | |||
| 1014 | 1004 | ||
| 1015 | // large rotates and shift are slower on intel than amd | 1005 | // large rotates and shift are slower on intel than amd |
| 1016 | // intel likes to rotate by 1, and the op is smaller too | 1006 | // intel likes to rotate by 1, and the op is smaller too |
| 1017 | void XEmitter::ROL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 0);} | 1007 | void XEmitter::ROL(int bits, const OpArg& dest, const OpArg& shift) { |
| 1018 | void XEmitter::ROR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 1);} | 1008 | WriteShift(bits, dest, shift, 0); |
| 1019 | void XEmitter::RCL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 2);} | 1009 | } |
| 1020 | void XEmitter::RCR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 3);} | 1010 | void XEmitter::ROR(int bits, const OpArg& dest, const OpArg& shift) { |
| 1021 | void XEmitter::SHL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 4);} | 1011 | WriteShift(bits, dest, shift, 1); |
| 1022 | void XEmitter::SHR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 5);} | 1012 | } |
| 1023 | void XEmitter::SAR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 7);} | 1013 | void XEmitter::RCL(int bits, const OpArg& dest, const OpArg& shift) { |
| 1014 | WriteShift(bits, dest, shift, 2); | ||
| 1015 | } | ||
| 1016 | void XEmitter::RCR(int bits, const OpArg& dest, const OpArg& shift) { | ||
| 1017 | WriteShift(bits, dest, shift, 3); | ||
| 1018 | } | ||
| 1019 | void XEmitter::SHL(int bits, const OpArg& dest, const OpArg& shift) { | ||
| 1020 | WriteShift(bits, dest, shift, 4); | ||
| 1021 | } | ||
| 1022 | void XEmitter::SHR(int bits, const OpArg& dest, const OpArg& shift) { | ||
| 1023 | WriteShift(bits, dest, shift, 5); | ||
| 1024 | } | ||
| 1025 | void XEmitter::SAR(int bits, const OpArg& dest, const OpArg& shift) { | ||
| 1026 | WriteShift(bits, dest, shift, 7); | ||
| 1027 | } | ||
| 1024 | 1028 | ||
| 1025 | // index can be either imm8 or register, don't use memory destination because it's slow | 1029 | // index can be either imm8 or register, don't use memory destination because it's slow |
| 1026 | void XEmitter::WriteBitTest(int bits, const OpArg& dest, const OpArg& index, int ext) | 1030 | void XEmitter::WriteBitTest(int bits, const OpArg& dest, const OpArg& index, int ext) { |
| 1027 | { | ||
| 1028 | CheckFlags(); | 1031 | CheckFlags(); |
| 1029 | if (dest.IsImm()) | 1032 | if (dest.IsImm()) { |
| 1030 | { | ||
| 1031 | ASSERT_MSG(0, "WriteBitTest - can't test imms"); | 1033 | ASSERT_MSG(0, "WriteBitTest - can't test imms"); |
| 1032 | } | 1034 | } |
| 1033 | if ((index.IsImm() && index.GetImmBits() != 8)) | 1035 | if ((index.IsImm() && index.GetImmBits() != 8)) { |
| 1034 | { | ||
| 1035 | ASSERT_MSG(0, "WriteBitTest - illegal argument"); | 1036 | ASSERT_MSG(0, "WriteBitTest - illegal argument"); |
| 1036 | } | 1037 | } |
| 1037 | if (bits == 16) | 1038 | if (bits == 16) |
| 1038 | Write8(0x66); | 1039 | Write8(0x66); |
| 1039 | if (index.IsImm()) | 1040 | if (index.IsImm()) { |
| 1040 | { | ||
| 1041 | dest.WriteRex(this, bits, bits); | 1041 | dest.WriteRex(this, bits, bits); |
| 1042 | Write8(0x0F); Write8(0xBA); | 1042 | Write8(0x0F); |
| 1043 | Write8(0xBA); | ||
| 1043 | dest.WriteRest(this, 1, (X64Reg)ext); | 1044 | dest.WriteRest(this, 1, (X64Reg)ext); |
| 1044 | Write8((u8)index.offset); | 1045 | Write8((u8)index.offset); |
| 1045 | } | 1046 | } else { |
| 1046 | else | ||
| 1047 | { | ||
| 1048 | X64Reg operand = index.GetSimpleReg(); | 1047 | X64Reg operand = index.GetSimpleReg(); |
| 1049 | dest.WriteRex(this, bits, bits, operand); | 1048 | dest.WriteRex(this, bits, bits, operand); |
| 1050 | Write8(0x0F); Write8(0x83 + 8*ext); | 1049 | Write8(0x0F); |
| 1050 | Write8(0x83 + 8 * ext); | ||
| 1051 | dest.WriteRest(this, 1, operand); | 1051 | dest.WriteRest(this, 1, operand); |
| 1052 | } | 1052 | } |
| 1053 | } | 1053 | } |
| 1054 | 1054 | ||
| 1055 | void XEmitter::BT(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 4);} | 1055 | void XEmitter::BT(int bits, const OpArg& dest, const OpArg& index) { |
| 1056 | void XEmitter::BTS(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 5);} | 1056 | WriteBitTest(bits, dest, index, 4); |
| 1057 | void XEmitter::BTR(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 6);} | 1057 | } |
| 1058 | void XEmitter::BTC(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 7);} | 1058 | void XEmitter::BTS(int bits, const OpArg& dest, const OpArg& index) { |
| 1059 | WriteBitTest(bits, dest, index, 5); | ||
| 1060 | } | ||
| 1061 | void XEmitter::BTR(int bits, const OpArg& dest, const OpArg& index) { | ||
| 1062 | WriteBitTest(bits, dest, index, 6); | ||
| 1063 | } | ||
| 1064 | void XEmitter::BTC(int bits, const OpArg& dest, const OpArg& index) { | ||
| 1065 | WriteBitTest(bits, dest, index, 7); | ||
| 1066 | } | ||
| 1059 | 1067 | ||
| 1060 | //shift can be either imm8 or cl | 1068 | // shift can be either imm8 or cl |
| 1061 | void XEmitter::SHRD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) | 1069 | void XEmitter::SHRD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) { |
| 1062 | { | ||
| 1063 | CheckFlags(); | 1070 | CheckFlags(); |
| 1064 | if (dest.IsImm()) | 1071 | if (dest.IsImm()) { |
| 1065 | { | ||
| 1066 | ASSERT_MSG(0, "SHRD - can't use imms as destination"); | 1072 | ASSERT_MSG(0, "SHRD - can't use imms as destination"); |
| 1067 | } | 1073 | } |
| 1068 | if (!src.IsSimpleReg()) | 1074 | if (!src.IsSimpleReg()) { |
| 1069 | { | ||
| 1070 | ASSERT_MSG(0, "SHRD - must use simple register as source"); | 1075 | ASSERT_MSG(0, "SHRD - must use simple register as source"); |
| 1071 | } | 1076 | } |
| 1072 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) | 1077 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || |
| 1073 | { | 1078 | (shift.IsImm() && shift.GetImmBits() != 8)) { |
| 1074 | ASSERT_MSG(0, "SHRD - illegal shift"); | 1079 | ASSERT_MSG(0, "SHRD - illegal shift"); |
| 1075 | } | 1080 | } |
| 1076 | if (bits == 16) | 1081 | if (bits == 16) |
| 1077 | Write8(0x66); | 1082 | Write8(0x66); |
| 1078 | X64Reg operand = src.GetSimpleReg(); | 1083 | X64Reg operand = src.GetSimpleReg(); |
| 1079 | dest.WriteRex(this, bits, bits, operand); | 1084 | dest.WriteRex(this, bits, bits, operand); |
| 1080 | if (shift.GetImmBits() == 8) | 1085 | if (shift.GetImmBits() == 8) { |
| 1081 | { | 1086 | Write8(0x0F); |
| 1082 | Write8(0x0F); Write8(0xAC); | 1087 | Write8(0xAC); |
| 1083 | dest.WriteRest(this, 1, operand); | 1088 | dest.WriteRest(this, 1, operand); |
| 1084 | Write8((u8)shift.offset); | 1089 | Write8((u8)shift.offset); |
| 1085 | } | 1090 | } else { |
| 1086 | else | 1091 | Write8(0x0F); |
| 1087 | { | 1092 | Write8(0xAD); |
| 1088 | Write8(0x0F); Write8(0xAD); | ||
| 1089 | dest.WriteRest(this, 0, operand); | 1093 | dest.WriteRest(this, 0, operand); |
| 1090 | } | 1094 | } |
| 1091 | } | 1095 | } |
| 1092 | 1096 | ||
| 1093 | void XEmitter::SHLD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) | 1097 | void XEmitter::SHLD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) { |
| 1094 | { | ||
| 1095 | CheckFlags(); | 1098 | CheckFlags(); |
| 1096 | if (dest.IsImm()) | 1099 | if (dest.IsImm()) { |
| 1097 | { | ||
| 1098 | ASSERT_MSG(0, "SHLD - can't use imms as destination"); | 1100 | ASSERT_MSG(0, "SHLD - can't use imms as destination"); |
| 1099 | } | 1101 | } |
| 1100 | if (!src.IsSimpleReg()) | 1102 | if (!src.IsSimpleReg()) { |
| 1101 | { | ||
| 1102 | ASSERT_MSG(0, "SHLD - must use simple register as source"); | 1103 | ASSERT_MSG(0, "SHLD - must use simple register as source"); |
| 1103 | } | 1104 | } |
| 1104 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) | 1105 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || |
| 1105 | { | 1106 | (shift.IsImm() && shift.GetImmBits() != 8)) { |
| 1106 | ASSERT_MSG(0, "SHLD - illegal shift"); | 1107 | ASSERT_MSG(0, "SHLD - illegal shift"); |
| 1107 | } | 1108 | } |
| 1108 | if (bits == 16) | 1109 | if (bits == 16) |
| 1109 | Write8(0x66); | 1110 | Write8(0x66); |
| 1110 | X64Reg operand = src.GetSimpleReg(); | 1111 | X64Reg operand = src.GetSimpleReg(); |
| 1111 | dest.WriteRex(this, bits, bits, operand); | 1112 | dest.WriteRex(this, bits, bits, operand); |
| 1112 | if (shift.GetImmBits() == 8) | 1113 | if (shift.GetImmBits() == 8) { |
| 1113 | { | 1114 | Write8(0x0F); |
| 1114 | Write8(0x0F); Write8(0xA4); | 1115 | Write8(0xA4); |
| 1115 | dest.WriteRest(this, 1, operand); | 1116 | dest.WriteRest(this, 1, operand); |
| 1116 | Write8((u8)shift.offset); | 1117 | Write8((u8)shift.offset); |
| 1117 | } | 1118 | } else { |
| 1118 | else | 1119 | Write8(0x0F); |
| 1119 | { | 1120 | Write8(0xA5); |
| 1120 | Write8(0x0F); Write8(0xA5); | ||
| 1121 | dest.WriteRest(this, 0, operand); | 1121 | dest.WriteRest(this, 0, operand); |
| 1122 | } | 1122 | } |
| 1123 | } | 1123 | } |
| 1124 | 1124 | ||
| 1125 | void OpArg::WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg _operandReg, int bits) | 1125 | void OpArg::WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg _operandReg, int bits) { |
| 1126 | { | ||
| 1127 | if (bits == 16) | 1126 | if (bits == 16) |
| 1128 | emit->Write8(0x66); | 1127 | emit->Write8(0x66); |
| 1129 | 1128 | ||
| @@ -1133,12 +1132,11 @@ void OpArg::WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg _operandReg, int bit | |||
| 1133 | WriteRest(emit); | 1132 | WriteRest(emit); |
| 1134 | } | 1133 | } |
| 1135 | 1134 | ||
| 1136 | //operand can either be immediate or register | 1135 | // operand can either be immediate or register |
| 1137 | void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& operand, int bits) const | 1136 | void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, |
| 1138 | { | 1137 | int bits) const { |
| 1139 | X64Reg _operandReg; | 1138 | X64Reg _operandReg; |
| 1140 | if (IsImm()) | 1139 | if (IsImm()) { |
| 1141 | { | ||
| 1142 | ASSERT_MSG(0, "WriteNormalOp - Imm argument, wrong order"); | 1140 | ASSERT_MSG(0, "WriteNormalOp - Imm argument, wrong order"); |
| 1143 | } | 1141 | } |
| 1144 | 1142 | ||
| @@ -1147,27 +1145,22 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o | |||
| 1147 | 1145 | ||
| 1148 | int immToWrite = 0; | 1146 | int immToWrite = 0; |
| 1149 | 1147 | ||
| 1150 | if (operand.IsImm()) | 1148 | if (operand.IsImm()) { |
| 1151 | { | ||
| 1152 | WriteRex(emit, bits, bits); | 1149 | WriteRex(emit, bits, bits); |
| 1153 | 1150 | ||
| 1154 | if (!toRM) | 1151 | if (!toRM) { |
| 1155 | { | ||
| 1156 | ASSERT_MSG(0, "WriteNormalOp - Writing to Imm (!toRM)"); | 1152 | ASSERT_MSG(0, "WriteNormalOp - Writing to Imm (!toRM)"); |
| 1157 | } | 1153 | } |
| 1158 | 1154 | ||
| 1159 | if (operand.scale == SCALE_IMM8 && bits == 8) | 1155 | if (operand.scale == SCALE_IMM8 && bits == 8) { |
| 1160 | { | ||
| 1161 | // op al, imm8 | 1156 | // op al, imm8 |
| 1162 | if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC) | 1157 | if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC) { |
| 1163 | { | ||
| 1164 | emit->Write8(normalops[op].eaximm8); | 1158 | emit->Write8(normalops[op].eaximm8); |
| 1165 | emit->Write8((u8)operand.offset); | 1159 | emit->Write8((u8)operand.offset); |
| 1166 | return; | 1160 | return; |
| 1167 | } | 1161 | } |
| 1168 | // mov reg, imm8 | 1162 | // mov reg, imm8 |
| 1169 | if (!scale && op == nrmMOV) | 1163 | if (!scale && op == nrmMOV) { |
| 1170 | { | ||
| 1171 | emit->Write8(0xB0 + (offsetOrBaseReg & 7)); | 1164 | emit->Write8(0xB0 + (offsetOrBaseReg & 7)); |
| 1172 | emit->Write8((u8)operand.offset); | 1165 | emit->Write8((u8)operand.offset); |
| 1173 | return; | 1166 | return; |
| @@ -1175,26 +1168,20 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o | |||
| 1175 | // op r/m8, imm8 | 1168 | // op r/m8, imm8 |
| 1176 | emit->Write8(normalops[op].imm8); | 1169 | emit->Write8(normalops[op].imm8); |
| 1177 | immToWrite = 8; | 1170 | immToWrite = 8; |
| 1178 | } | 1171 | } else if ((operand.scale == SCALE_IMM16 && bits == 16) || |
| 1179 | else if ((operand.scale == SCALE_IMM16 && bits == 16) || | 1172 | (operand.scale == SCALE_IMM32 && bits == 32) || |
| 1180 | (operand.scale == SCALE_IMM32 && bits == 32) || | 1173 | (operand.scale == SCALE_IMM32 && bits == 64)) { |
| 1181 | (operand.scale == SCALE_IMM32 && bits == 64)) | ||
| 1182 | { | ||
| 1183 | // Try to save immediate size if we can, but first check to see | 1174 | // Try to save immediate size if we can, but first check to see |
| 1184 | // if the instruction supports simm8. | 1175 | // if the instruction supports simm8. |
| 1185 | // op r/m, imm8 | 1176 | // op r/m, imm8 |
| 1186 | if (normalops[op].simm8 != 0xCC && | 1177 | if (normalops[op].simm8 != 0xCC && |
| 1187 | ((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) || | 1178 | ((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) || |
| 1188 | (operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset))) | 1179 | (operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset))) { |
| 1189 | { | ||
| 1190 | emit->Write8(normalops[op].simm8); | 1180 | emit->Write8(normalops[op].simm8); |
| 1191 | immToWrite = 8; | 1181 | immToWrite = 8; |
| 1192 | } | 1182 | } else { |
| 1193 | else | ||
| 1194 | { | ||
| 1195 | // mov reg, imm | 1183 | // mov reg, imm |
| 1196 | if (!scale && op == nrmMOV && bits != 64) | 1184 | if (!scale && op == nrmMOV && bits != 64) { |
| 1197 | { | ||
| 1198 | emit->Write8(0xB8 + (offsetOrBaseReg & 7)); | 1185 | emit->Write8(0xB8 + (offsetOrBaseReg & 7)); |
| 1199 | if (bits == 16) | 1186 | if (bits == 16) |
| 1200 | emit->Write16((u16)operand.offset); | 1187 | emit->Write16((u16)operand.offset); |
| @@ -1203,8 +1190,7 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o | |||
| 1203 | return; | 1190 | return; |
| 1204 | } | 1191 | } |
| 1205 | // op eax, imm | 1192 | // op eax, imm |
| 1206 | if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC) | 1193 | if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC) { |
| 1207 | { | ||
| 1208 | emit->Write8(normalops[op].eaximm32); | 1194 | emit->Write8(normalops[op].eaximm32); |
| 1209 | if (bits == 16) | 1195 | if (bits == 16) |
| 1210 | emit->Write16((u16)operand.offset); | 1196 | emit->Write16((u16)operand.offset); |
| @@ -1216,54 +1202,41 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o | |||
| 1216 | emit->Write8(normalops[op].imm32); | 1202 | emit->Write8(normalops[op].imm32); |
| 1217 | immToWrite = bits == 16 ? 16 : 32; | 1203 | immToWrite = bits == 16 ? 16 : 32; |
| 1218 | } | 1204 | } |
| 1219 | } | 1205 | } else if ((operand.scale == SCALE_IMM8 && bits == 16) || |
| 1220 | else if ((operand.scale == SCALE_IMM8 && bits == 16) || | 1206 | (operand.scale == SCALE_IMM8 && bits == 32) || |
| 1221 | (operand.scale == SCALE_IMM8 && bits == 32) || | 1207 | (operand.scale == SCALE_IMM8 && bits == 64)) { |
| 1222 | (operand.scale == SCALE_IMM8 && bits == 64)) | ||
| 1223 | { | ||
| 1224 | // op r/m, imm8 | 1208 | // op r/m, imm8 |
| 1225 | emit->Write8(normalops[op].simm8); | 1209 | emit->Write8(normalops[op].simm8); |
| 1226 | immToWrite = 8; | 1210 | immToWrite = 8; |
| 1227 | } | 1211 | } else if (operand.scale == SCALE_IMM64 && bits == 64) { |
| 1228 | else if (operand.scale == SCALE_IMM64 && bits == 64) | 1212 | if (scale) { |
| 1229 | { | ||
| 1230 | if (scale) | ||
| 1231 | { | ||
| 1232 | ASSERT_MSG(0, "WriteNormalOp - MOV with 64-bit imm requres register destination"); | 1213 | ASSERT_MSG(0, "WriteNormalOp - MOV with 64-bit imm requres register destination"); |
| 1233 | } | 1214 | } |
| 1234 | // mov reg64, imm64 | 1215 | // mov reg64, imm64 |
| 1235 | else if (op == nrmMOV) | 1216 | else if (op == nrmMOV) { |
| 1236 | { | ||
| 1237 | emit->Write8(0xB8 + (offsetOrBaseReg & 7)); | 1217 | emit->Write8(0xB8 + (offsetOrBaseReg & 7)); |
| 1238 | emit->Write64((u64)operand.offset); | 1218 | emit->Write64((u64)operand.offset); |
| 1239 | return; | 1219 | return; |
| 1240 | } | 1220 | } |
| 1241 | ASSERT_MSG(0, "WriteNormalOp - Only MOV can take 64-bit imm"); | 1221 | ASSERT_MSG(0, "WriteNormalOp - Only MOV can take 64-bit imm"); |
| 1242 | } | 1222 | } else { |
| 1243 | else | ||
| 1244 | { | ||
| 1245 | ASSERT_MSG(0, "WriteNormalOp - Unhandled case"); | 1223 | ASSERT_MSG(0, "WriteNormalOp - Unhandled case"); |
| 1246 | } | 1224 | } |
| 1247 | _operandReg = (X64Reg)normalops[op].ext; //pass extension in REG of ModRM | 1225 | _operandReg = (X64Reg)normalops[op].ext; // pass extension in REG of ModRM |
| 1248 | } | 1226 | } else { |
| 1249 | else | ||
| 1250 | { | ||
| 1251 | _operandReg = (X64Reg)operand.offsetOrBaseReg; | 1227 | _operandReg = (X64Reg)operand.offsetOrBaseReg; |
| 1252 | WriteRex(emit, bits, bits, _operandReg); | 1228 | WriteRex(emit, bits, bits, _operandReg); |
| 1253 | // op r/m, reg | 1229 | // op r/m, reg |
| 1254 | if (toRM) | 1230 | if (toRM) { |
| 1255 | { | ||
| 1256 | emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32); | 1231 | emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32); |
| 1257 | } | 1232 | } |
| 1258 | // op reg, r/m | 1233 | // op reg, r/m |
| 1259 | else | 1234 | else { |
| 1260 | { | ||
| 1261 | emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32); | 1235 | emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32); |
| 1262 | } | 1236 | } |
| 1263 | } | 1237 | } |
| 1264 | WriteRest(emit, immToWrite >> 3, _operandReg); | 1238 | WriteRest(emit, immToWrite >> 3, _operandReg); |
| 1265 | switch (immToWrite) | 1239 | switch (immToWrite) { |
| 1266 | { | ||
| 1267 | case 0: | 1240 | case 0: |
| 1268 | break; | 1241 | break; |
| 1269 | case 8: | 1242 | case 8: |
| @@ -1280,66 +1253,84 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o | |||
| 1280 | } | 1253 | } |
| 1281 | } | 1254 | } |
| 1282 | 1255 | ||
| 1283 | void XEmitter::WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2) | 1256 | void XEmitter::WriteNormalOp(XEmitter* emit, int bits, NormalOp op, const OpArg& a1, |
| 1284 | { | 1257 | const OpArg& a2) { |
| 1285 | if (a1.IsImm()) | 1258 | if (a1.IsImm()) { |
| 1286 | { | 1259 | // Booh! Can't write to an imm |
| 1287 | //Booh! Can't write to an imm | ||
| 1288 | ASSERT_MSG(0, "WriteNormalOp - a1 cannot be imm"); | 1260 | ASSERT_MSG(0, "WriteNormalOp - a1 cannot be imm"); |
| 1289 | return; | 1261 | return; |
| 1290 | } | 1262 | } |
| 1291 | if (a2.IsImm()) | 1263 | if (a2.IsImm()) { |
| 1292 | { | ||
| 1293 | a1.WriteNormalOp(emit, true, op, a2, bits); | 1264 | a1.WriteNormalOp(emit, true, op, a2, bits); |
| 1294 | } | 1265 | } else { |
| 1295 | else | 1266 | if (a1.IsSimpleReg()) { |
| 1296 | { | ||
| 1297 | if (a1.IsSimpleReg()) | ||
| 1298 | { | ||
| 1299 | a2.WriteNormalOp(emit, false, op, a1, bits); | 1267 | a2.WriteNormalOp(emit, false, op, a1, bits); |
| 1300 | } | 1268 | } else { |
| 1301 | else | 1269 | ASSERT_MSG(a2.IsSimpleReg() || a2.IsImm(), |
| 1302 | { | 1270 | "WriteNormalOp - a1 and a2 cannot both be memory"); |
| 1303 | ASSERT_MSG(a2.IsSimpleReg() || a2.IsImm(), "WriteNormalOp - a1 and a2 cannot both be memory"); | ||
| 1304 | a1.WriteNormalOp(emit, true, op, a2, bits); | 1271 | a1.WriteNormalOp(emit, true, op, a2, bits); |
| 1305 | } | 1272 | } |
| 1306 | } | 1273 | } |
| 1307 | } | 1274 | } |
| 1308 | 1275 | ||
| 1309 | void XEmitter::ADD (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmADD, a1, a2);} | 1276 | void XEmitter::ADD(int bits, const OpArg& a1, const OpArg& a2) { |
| 1310 | void XEmitter::ADC (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmADC, a1, a2);} | 1277 | CheckFlags(); |
| 1311 | void XEmitter::SUB (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmSUB, a1, a2);} | 1278 | WriteNormalOp(this, bits, nrmADD, a1, a2); |
| 1312 | void XEmitter::SBB (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmSBB, a1, a2);} | 1279 | } |
| 1313 | void XEmitter::AND (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmAND, a1, a2);} | 1280 | void XEmitter::ADC(int bits, const OpArg& a1, const OpArg& a2) { |
| 1314 | void XEmitter::OR (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmOR , a1, a2);} | 1281 | CheckFlags(); |
| 1315 | void XEmitter::XOR (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmXOR, a1, a2);} | 1282 | WriteNormalOp(this, bits, nrmADC, a1, a2); |
| 1316 | void XEmitter::MOV (int bits, const OpArg& a1, const OpArg& a2) | 1283 | } |
| 1317 | { | 1284 | void XEmitter::SUB(int bits, const OpArg& a1, const OpArg& a2) { |
| 1285 | CheckFlags(); | ||
| 1286 | WriteNormalOp(this, bits, nrmSUB, a1, a2); | ||
| 1287 | } | ||
| 1288 | void XEmitter::SBB(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1289 | CheckFlags(); | ||
| 1290 | WriteNormalOp(this, bits, nrmSBB, a1, a2); | ||
| 1291 | } | ||
| 1292 | void XEmitter::AND(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1293 | CheckFlags(); | ||
| 1294 | WriteNormalOp(this, bits, nrmAND, a1, a2); | ||
| 1295 | } | ||
| 1296 | void XEmitter::OR(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1297 | CheckFlags(); | ||
| 1298 | WriteNormalOp(this, bits, nrmOR, a1, a2); | ||
| 1299 | } | ||
| 1300 | void XEmitter::XOR(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1301 | CheckFlags(); | ||
| 1302 | WriteNormalOp(this, bits, nrmXOR, a1, a2); | ||
| 1303 | } | ||
| 1304 | void XEmitter::MOV(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1318 | if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) | 1305 | if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) |
| 1319 | LOG_ERROR(Common, "Redundant MOV @ %p - bug in JIT?", code); | 1306 | LOG_ERROR(Common, "Redundant MOV @ %p - bug in JIT?", code); |
| 1320 | WriteNormalOp(this, bits, nrmMOV, a1, a2); | 1307 | WriteNormalOp(this, bits, nrmMOV, a1, a2); |
| 1321 | } | 1308 | } |
| 1322 | void XEmitter::TEST(int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmTEST, a1, a2);} | 1309 | void XEmitter::TEST(int bits, const OpArg& a1, const OpArg& a2) { |
| 1323 | void XEmitter::CMP (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmCMP, a1, a2);} | 1310 | CheckFlags(); |
| 1324 | void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) {WriteNormalOp(this, bits, nrmXCHG, a1, a2);} | 1311 | WriteNormalOp(this, bits, nrmTEST, a1, a2); |
| 1312 | } | ||
| 1313 | void XEmitter::CMP(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1314 | CheckFlags(); | ||
| 1315 | WriteNormalOp(this, bits, nrmCMP, a1, a2); | ||
| 1316 | } | ||
| 1317 | void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1318 | WriteNormalOp(this, bits, nrmXCHG, a1, a2); | ||
| 1319 | } | ||
| 1325 | 1320 | ||
| 1326 | void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2) | 1321 | void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2) { |
| 1327 | { | ||
| 1328 | CheckFlags(); | 1322 | CheckFlags(); |
| 1329 | if (bits == 8) | 1323 | if (bits == 8) { |
| 1330 | { | ||
| 1331 | ASSERT_MSG(0, "IMUL - illegal bit size!"); | 1324 | ASSERT_MSG(0, "IMUL - illegal bit size!"); |
| 1332 | return; | 1325 | return; |
| 1333 | } | 1326 | } |
| 1334 | 1327 | ||
| 1335 | if (a1.IsImm()) | 1328 | if (a1.IsImm()) { |
| 1336 | { | ||
| 1337 | ASSERT_MSG(0, "IMUL - second arg cannot be imm!"); | 1329 | ASSERT_MSG(0, "IMUL - second arg cannot be imm!"); |
| 1338 | return; | 1330 | return; |
| 1339 | } | 1331 | } |
| 1340 | 1332 | ||
| 1341 | if (!a2.IsImm()) | 1333 | if (!a2.IsImm()) { |
| 1342 | { | ||
| 1343 | ASSERT_MSG(0, "IMUL - third arg must be imm!"); | 1334 | ASSERT_MSG(0, "IMUL - third arg must be imm!"); |
| 1344 | return; | 1335 | return; |
| 1345 | } | 1336 | } |
| @@ -1348,46 +1339,34 @@ void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2) | |||
| 1348 | Write8(0x66); | 1339 | Write8(0x66); |
| 1349 | a1.WriteRex(this, bits, bits, regOp); | 1340 | a1.WriteRex(this, bits, bits, regOp); |
| 1350 | 1341 | ||
| 1351 | if (a2.GetImmBits() == 8 || | 1342 | if (a2.GetImmBits() == 8 || (a2.GetImmBits() == 16 && (s8)a2.offset == (s16)a2.offset) || |
| 1352 | (a2.GetImmBits() == 16 && (s8)a2.offset == (s16)a2.offset) || | 1343 | (a2.GetImmBits() == 32 && (s8)a2.offset == (s32)a2.offset)) { |
| 1353 | (a2.GetImmBits() == 32 && (s8)a2.offset == (s32)a2.offset)) | ||
| 1354 | { | ||
| 1355 | Write8(0x6B); | 1344 | Write8(0x6B); |
| 1356 | a1.WriteRest(this, 1, regOp); | 1345 | a1.WriteRest(this, 1, regOp); |
| 1357 | Write8((u8)a2.offset); | 1346 | Write8((u8)a2.offset); |
| 1358 | } | 1347 | } else { |
| 1359 | else | ||
| 1360 | { | ||
| 1361 | Write8(0x69); | 1348 | Write8(0x69); |
| 1362 | if (a2.GetImmBits() == 16 && bits == 16) | 1349 | if (a2.GetImmBits() == 16 && bits == 16) { |
| 1363 | { | ||
| 1364 | a1.WriteRest(this, 2, regOp); | 1350 | a1.WriteRest(this, 2, regOp); |
| 1365 | Write16((u16)a2.offset); | 1351 | Write16((u16)a2.offset); |
| 1366 | } | 1352 | } else if (a2.GetImmBits() == 32 && (bits == 32 || bits == 64)) { |
| 1367 | else if (a2.GetImmBits() == 32 && (bits == 32 || bits == 64)) | ||
| 1368 | { | ||
| 1369 | a1.WriteRest(this, 4, regOp); | 1353 | a1.WriteRest(this, 4, regOp); |
| 1370 | Write32((u32)a2.offset); | 1354 | Write32((u32)a2.offset); |
| 1371 | } | 1355 | } else { |
| 1372 | else | ||
| 1373 | { | ||
| 1374 | ASSERT_MSG(0, "IMUL - unhandled case!"); | 1356 | ASSERT_MSG(0, "IMUL - unhandled case!"); |
| 1375 | } | 1357 | } |
| 1376 | } | 1358 | } |
| 1377 | } | 1359 | } |
| 1378 | 1360 | ||
| 1379 | void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a) | 1361 | void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a) { |
| 1380 | { | ||
| 1381 | CheckFlags(); | 1362 | CheckFlags(); |
| 1382 | if (bits == 8) | 1363 | if (bits == 8) { |
| 1383 | { | ||
| 1384 | ASSERT_MSG(0, "IMUL - illegal bit size!"); | 1364 | ASSERT_MSG(0, "IMUL - illegal bit size!"); |
| 1385 | return; | 1365 | return; |
| 1386 | } | 1366 | } |
| 1387 | 1367 | ||
| 1388 | if (a.IsImm()) | 1368 | if (a.IsImm()) { |
| 1389 | { | 1369 | IMUL(bits, regOp, R(regOp), a); |
| 1390 | IMUL(bits, regOp, R(regOp), a) ; | ||
| 1391 | return; | 1370 | return; |
| 1392 | } | 1371 | } |
| 1393 | 1372 | ||
| @@ -1399,9 +1378,7 @@ void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a) | |||
| 1399 | a.WriteRest(this, 0, regOp); | 1378 | a.WriteRest(this, 0, regOp); |
| 1400 | } | 1379 | } |
| 1401 | 1380 | ||
| 1402 | 1381 | void XEmitter::WriteSSEOp(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extrabytes) { | |
| 1403 | void XEmitter::WriteSSEOp(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extrabytes) | ||
| 1404 | { | ||
| 1405 | if (opPrefix) | 1382 | if (opPrefix) |
| 1406 | Write8(opPrefix); | 1383 | Write8(opPrefix); |
| 1407 | arg.operandReg = regOp; | 1384 | arg.operandReg = regOp; |
| @@ -1413,13 +1390,11 @@ void XEmitter::WriteSSEOp(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extr | |||
| 1413 | arg.WriteRest(this, extrabytes); | 1390 | arg.WriteRest(this, extrabytes); |
| 1414 | } | 1391 | } |
| 1415 | 1392 | ||
| 1416 | void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) | 1393 | void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) { |
| 1417 | { | ||
| 1418 | WriteAVXOp(opPrefix, op, regOp, INVALID_REG, arg, extrabytes); | 1394 | WriteAVXOp(opPrefix, op, regOp, INVALID_REG, arg, extrabytes); |
| 1419 | } | 1395 | } |
| 1420 | 1396 | ||
| 1421 | static int GetVEXmmmmm(u16 op) | 1397 | static int GetVEXmmmmm(u16 op) { |
| 1422 | { | ||
| 1423 | // Currently, only 0x38 and 0x3A are used as secondary escape byte. | 1398 | // Currently, only 0x38 and 0x3A are used as secondary escape byte. |
| 1424 | if ((op >> 8) == 0x3A) | 1399 | if ((op >> 8) == 0x3A) |
| 1425 | return 3; | 1400 | return 3; |
| @@ -1429,8 +1404,7 @@ static int GetVEXmmmmm(u16 op) | |||
| 1429 | return 1; | 1404 | return 1; |
| 1430 | } | 1405 | } |
| 1431 | 1406 | ||
| 1432 | static int GetVEXpp(u8 opPrefix) | 1407 | static int GetVEXpp(u8 opPrefix) { |
| 1433 | { | ||
| 1434 | if (opPrefix == 0x66) | 1408 | if (opPrefix == 0x66) |
| 1435 | return 1; | 1409 | return 1; |
| 1436 | if (opPrefix == 0xF3) | 1410 | if (opPrefix == 0xF3) |
| @@ -1441,21 +1415,22 @@ static int GetVEXpp(u8 opPrefix) | |||
| 1441 | return 0; | 1415 | return 0; |
| 1442 | } | 1416 | } |
| 1443 | 1417 | ||
| 1444 | void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) | 1418 | void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, |
| 1445 | { | 1419 | int extrabytes) { |
| 1446 | if (!Common::GetCPUCaps().avx) | 1420 | if (!Common::GetCPUCaps().avx) |
| 1447 | ASSERT_MSG(0, "Trying to use AVX on a system that doesn't support it. Bad programmer."); | 1421 | ASSERT_MSG(0, "Trying to use AVX on a system that doesn't support it. Bad programmer."); |
| 1448 | int mmmmm = GetVEXmmmmm(op); | 1422 | int mmmmm = GetVEXmmmmm(op); |
| 1449 | int pp = GetVEXpp(opPrefix); | 1423 | int pp = GetVEXpp(opPrefix); |
| 1450 | // FIXME: we currently don't support 256-bit instructions, and "size" is not the vector size here | 1424 | // FIXME: we currently don't support 256-bit instructions, and "size" is not the vector size |
| 1425 | // here | ||
| 1451 | arg.WriteVex(this, regOp1, regOp2, 0, pp, mmmmm); | 1426 | arg.WriteVex(this, regOp1, regOp2, 0, pp, mmmmm); |
| 1452 | Write8(op & 0xFF); | 1427 | Write8(op & 0xFF); |
| 1453 | arg.WriteRest(this, extrabytes, regOp1); | 1428 | arg.WriteRest(this, extrabytes, regOp1); |
| 1454 | } | 1429 | } |
| 1455 | 1430 | ||
| 1456 | // Like the above, but more general; covers GPR-based VEX operations, like BMI1/2 | 1431 | // Like the above, but more general; covers GPR-based VEX operations, like BMI1/2 |
| 1457 | void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) | 1432 | void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, |
| 1458 | { | 1433 | const OpArg& arg, int extrabytes) { |
| 1459 | if (size != 32 && size != 64) | 1434 | if (size != 32 && size != 64) |
| 1460 | ASSERT_MSG(0, "VEX GPR instructions only support 32-bit and 64-bit modes!"); | 1435 | ASSERT_MSG(0, "VEX GPR instructions only support 32-bit and 64-bit modes!"); |
| 1461 | int mmmmm = GetVEXmmmmm(op); | 1436 | int mmmmm = GetVEXmmmmm(op); |
| @@ -1465,49 +1440,50 @@ void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg r | |||
| 1465 | arg.WriteRest(this, extrabytes, regOp1); | 1440 | arg.WriteRest(this, extrabytes, regOp1); |
| 1466 | } | 1441 | } |
| 1467 | 1442 | ||
| 1468 | void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) | 1443 | void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, |
| 1469 | { | 1444 | const OpArg& arg, int extrabytes) { |
| 1470 | CheckFlags(); | 1445 | CheckFlags(); |
| 1471 | if (!Common::GetCPUCaps().bmi1) | 1446 | if (!Common::GetCPUCaps().bmi1) |
| 1472 | ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer."); | 1447 | ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer."); |
| 1473 | WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); | 1448 | WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); |
| 1474 | } | 1449 | } |
| 1475 | 1450 | ||
| 1476 | void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) | 1451 | void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, |
| 1477 | { | 1452 | const OpArg& arg, int extrabytes) { |
| 1478 | CheckFlags(); | 1453 | CheckFlags(); |
| 1479 | if (!Common::GetCPUCaps().bmi2) | 1454 | if (!Common::GetCPUCaps().bmi2) |
| 1480 | ASSERT_MSG(0, "Trying to use BMI2 on a system that doesn't support it. Bad programmer."); | 1455 | ASSERT_MSG(0, "Trying to use BMI2 on a system that doesn't support it. Bad programmer."); |
| 1481 | WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); | 1456 | WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); |
| 1482 | } | 1457 | } |
| 1483 | 1458 | ||
| 1484 | void XEmitter::MOVD_xmm(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x6E, dest, arg, 0);} | 1459 | void XEmitter::MOVD_xmm(X64Reg dest, const OpArg& arg) { |
| 1485 | void XEmitter::MOVD_xmm(const OpArg &arg, X64Reg src) {WriteSSEOp(0x66, 0x7E, src, arg, 0);} | 1460 | WriteSSEOp(0x66, 0x6E, dest, arg, 0); |
| 1461 | } | ||
| 1462 | void XEmitter::MOVD_xmm(const OpArg& arg, X64Reg src) { | ||
| 1463 | WriteSSEOp(0x66, 0x7E, src, arg, 0); | ||
| 1464 | } | ||
| 1486 | 1465 | ||
| 1487 | void XEmitter::MOVQ_xmm(X64Reg dest, OpArg arg) | 1466 | void XEmitter::MOVQ_xmm(X64Reg dest, OpArg arg) { |
| 1488 | { | ||
| 1489 | #ifdef ARCHITECTURE_x86_64 | 1467 | #ifdef ARCHITECTURE_x86_64 |
| 1490 | // Alternate encoding | 1468 | // Alternate encoding |
| 1491 | // This does not display correctly in MSVC's debugger, it thinks it's a MOVD | 1469 | // This does not display correctly in MSVC's debugger, it thinks it's a MOVD |
| 1492 | arg.operandReg = dest; | 1470 | arg.operandReg = dest; |
| 1493 | Write8(0x66); | 1471 | Write8(0x66); |
| 1494 | arg.WriteRex(this, 64, 0); | 1472 | arg.WriteRex(this, 64, 0); |
| 1495 | Write8(0x0f); | 1473 | Write8(0x0f); |
| 1496 | Write8(0x6E); | 1474 | Write8(0x6E); |
| 1497 | arg.WriteRest(this, 0); | 1475 | arg.WriteRest(this, 0); |
| 1498 | #else | 1476 | #else |
| 1499 | arg.operandReg = dest; | 1477 | arg.operandReg = dest; |
| 1500 | Write8(0xF3); | 1478 | Write8(0xF3); |
| 1501 | Write8(0x0f); | 1479 | Write8(0x0f); |
| 1502 | Write8(0x7E); | 1480 | Write8(0x7E); |
| 1503 | arg.WriteRest(this, 0); | 1481 | arg.WriteRest(this, 0); |
| 1504 | #endif | 1482 | #endif |
| 1505 | } | 1483 | } |
| 1506 | 1484 | ||
| 1507 | void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) | 1485 | void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) { |
| 1508 | { | 1486 | if (src > 7 || arg.IsSimpleReg()) { |
| 1509 | if (src > 7 || arg.IsSimpleReg()) | ||
| 1510 | { | ||
| 1511 | // Alternate encoding | 1487 | // Alternate encoding |
| 1512 | // This does not display correctly in MSVC's debugger, it thinks it's a MOVD | 1488 | // This does not display correctly in MSVC's debugger, it thinks it's a MOVD |
| 1513 | arg.operandReg = src; | 1489 | arg.operandReg = src; |
| @@ -1516,9 +1492,7 @@ void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) | |||
| 1516 | Write8(0x0f); | 1492 | Write8(0x0f); |
| 1517 | Write8(0x7E); | 1493 | Write8(0x7E); |
| 1518 | arg.WriteRest(this, 0); | 1494 | arg.WriteRest(this, 0); |
| 1519 | } | 1495 | } else { |
| 1520 | else | ||
| 1521 | { | ||
| 1522 | arg.operandReg = src; | 1496 | arg.operandReg = src; |
| 1523 | arg.WriteRex(this, 0, 0); | 1497 | arg.WriteRex(this, 0, 0); |
| 1524 | Write8(0x66); | 1498 | Write8(0x66); |
| @@ -1528,8 +1502,7 @@ void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) | |||
| 1528 | } | 1502 | } |
| 1529 | } | 1503 | } |
| 1530 | 1504 | ||
| 1531 | void XEmitter::WriteMXCSR(OpArg arg, int ext) | 1505 | void XEmitter::WriteMXCSR(OpArg arg, int ext) { |
| 1532 | { | ||
| 1533 | if (arg.IsImm() || arg.IsSimpleReg()) | 1506 | if (arg.IsImm() || arg.IsSimpleReg()) |
| 1534 | ASSERT_MSG(0, "MXCSR - invalid operand"); | 1507 | ASSERT_MSG(0, "MXCSR - invalid operand"); |
| 1535 | 1508 | ||
| @@ -1540,143 +1513,357 @@ void XEmitter::WriteMXCSR(OpArg arg, int ext) | |||
| 1540 | arg.WriteRest(this); | 1513 | arg.WriteRest(this); |
| 1541 | } | 1514 | } |
| 1542 | 1515 | ||
| 1543 | void XEmitter::STMXCSR(const OpArg& memloc) {WriteMXCSR(memloc, 3);} | 1516 | void XEmitter::STMXCSR(const OpArg& memloc) { |
| 1544 | void XEmitter::LDMXCSR(const OpArg& memloc) {WriteMXCSR(memloc, 2);} | 1517 | WriteMXCSR(memloc, 3); |
| 1545 | 1518 | } | |
| 1546 | void XEmitter::MOVNTDQ(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVNTDQ, regOp, arg);} | 1519 | void XEmitter::LDMXCSR(const OpArg& memloc) { |
| 1547 | void XEmitter::MOVNTPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVNTP, regOp, arg);} | 1520 | WriteMXCSR(memloc, 2); |
| 1548 | void XEmitter::MOVNTPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVNTP, regOp, arg);} | 1521 | } |
| 1549 | 1522 | ||
| 1550 | void XEmitter::ADDSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseADD, regOp, arg);} | 1523 | void XEmitter::MOVNTDQ(const OpArg& arg, X64Reg regOp) { |
| 1551 | void XEmitter::ADDSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseADD, regOp, arg);} | 1524 | WriteSSEOp(0x66, sseMOVNTDQ, regOp, arg); |
| 1552 | void XEmitter::SUBSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseSUB, regOp, arg);} | 1525 | } |
| 1553 | void XEmitter::SUBSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseSUB, regOp, arg);} | 1526 | void XEmitter::MOVNTPS(const OpArg& arg, X64Reg regOp) { |
| 1554 | void XEmitter::CMPSS(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0xF3, sseCMP, regOp, arg, 1); Write8(compare);} | 1527 | WriteSSEOp(0x00, sseMOVNTP, regOp, arg); |
| 1555 | void XEmitter::CMPSD(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0xF2, sseCMP, regOp, arg, 1); Write8(compare);} | 1528 | } |
| 1556 | void XEmitter::MULSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMUL, regOp, arg);} | 1529 | void XEmitter::MOVNTPD(const OpArg& arg, X64Reg regOp) { |
| 1557 | void XEmitter::MULSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMUL, regOp, arg);} | 1530 | WriteSSEOp(0x66, sseMOVNTP, regOp, arg); |
| 1558 | void XEmitter::DIVSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseDIV, regOp, arg);} | 1531 | } |
| 1559 | void XEmitter::DIVSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseDIV, regOp, arg);} | 1532 | |
| 1560 | void XEmitter::MINSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMIN, regOp, arg);} | 1533 | void XEmitter::ADDSS(X64Reg regOp, const OpArg& arg) { |
| 1561 | void XEmitter::MINSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMIN, regOp, arg);} | 1534 | WriteSSEOp(0xF3, sseADD, regOp, arg); |
| 1562 | void XEmitter::MAXSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMAX, regOp, arg);} | 1535 | } |
| 1563 | void XEmitter::MAXSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMAX, regOp, arg);} | 1536 | void XEmitter::ADDSD(X64Reg regOp, const OpArg& arg) { |
| 1564 | void XEmitter::SQRTSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseSQRT, regOp, arg);} | 1537 | WriteSSEOp(0xF2, sseADD, regOp, arg); |
| 1565 | void XEmitter::SQRTSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseSQRT, regOp, arg);} | 1538 | } |
| 1566 | void XEmitter::RCPSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseRCP, regOp, arg);} | 1539 | void XEmitter::SUBSS(X64Reg regOp, const OpArg& arg) { |
| 1567 | void XEmitter::RSQRTSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseRSQRT, regOp, arg);} | 1540 | WriteSSEOp(0xF3, sseSUB, regOp, arg); |
| 1568 | 1541 | } | |
| 1569 | void XEmitter::ADDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseADD, regOp, arg);} | 1542 | void XEmitter::SUBSD(X64Reg regOp, const OpArg& arg) { |
| 1570 | void XEmitter::ADDPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseADD, regOp, arg);} | 1543 | WriteSSEOp(0xF2, sseSUB, regOp, arg); |
| 1571 | void XEmitter::SUBPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseSUB, regOp, arg);} | 1544 | } |
| 1572 | void XEmitter::SUBPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseSUB, regOp, arg);} | 1545 | void XEmitter::CMPSS(X64Reg regOp, const OpArg& arg, u8 compare) { |
| 1573 | void XEmitter::CMPPS(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0x00, sseCMP, regOp, arg, 1); Write8(compare);} | 1546 | WriteSSEOp(0xF3, sseCMP, regOp, arg, 1); |
| 1574 | void XEmitter::CMPPD(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0x66, sseCMP, regOp, arg, 1); Write8(compare);} | 1547 | Write8(compare); |
| 1575 | void XEmitter::ANDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseAND, regOp, arg);} | 1548 | } |
| 1576 | void XEmitter::ANDPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseAND, regOp, arg);} | 1549 | void XEmitter::CMPSD(X64Reg regOp, const OpArg& arg, u8 compare) { |
| 1577 | void XEmitter::ANDNPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseANDN, regOp, arg);} | 1550 | WriteSSEOp(0xF2, sseCMP, regOp, arg, 1); |
| 1578 | void XEmitter::ANDNPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseANDN, regOp, arg);} | 1551 | Write8(compare); |
| 1579 | void XEmitter::ORPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseOR, regOp, arg);} | 1552 | } |
| 1580 | void XEmitter::ORPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseOR, regOp, arg);} | 1553 | void XEmitter::MULSS(X64Reg regOp, const OpArg& arg) { |
| 1581 | void XEmitter::XORPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseXOR, regOp, arg);} | 1554 | WriteSSEOp(0xF3, sseMUL, regOp, arg); |
| 1582 | void XEmitter::XORPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseXOR, regOp, arg);} | 1555 | } |
| 1583 | void XEmitter::MULPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMUL, regOp, arg);} | 1556 | void XEmitter::MULSD(X64Reg regOp, const OpArg& arg) { |
| 1584 | void XEmitter::MULPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMUL, regOp, arg);} | 1557 | WriteSSEOp(0xF2, sseMUL, regOp, arg); |
| 1585 | void XEmitter::DIVPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseDIV, regOp, arg);} | 1558 | } |
| 1586 | void XEmitter::DIVPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseDIV, regOp, arg);} | 1559 | void XEmitter::DIVSS(X64Reg regOp, const OpArg& arg) { |
| 1587 | void XEmitter::MINPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMIN, regOp, arg);} | 1560 | WriteSSEOp(0xF3, sseDIV, regOp, arg); |
| 1588 | void XEmitter::MINPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMIN, regOp, arg);} | 1561 | } |
| 1589 | void XEmitter::MAXPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMAX, regOp, arg);} | 1562 | void XEmitter::DIVSD(X64Reg regOp, const OpArg& arg) { |
| 1590 | void XEmitter::MAXPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMAX, regOp, arg);} | 1563 | WriteSSEOp(0xF2, sseDIV, regOp, arg); |
| 1591 | void XEmitter::SQRTPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseSQRT, regOp, arg);} | 1564 | } |
| 1592 | void XEmitter::SQRTPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseSQRT, regOp, arg);} | 1565 | void XEmitter::MINSS(X64Reg regOp, const OpArg& arg) { |
| 1593 | void XEmitter::RCPPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseRCP, regOp, arg); } | 1566 | WriteSSEOp(0xF3, sseMIN, regOp, arg); |
| 1594 | void XEmitter::RSQRTPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseRSQRT, regOp, arg);} | 1567 | } |
| 1595 | void XEmitter::SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0x00, sseSHUF, regOp, arg,1); Write8(shuffle);} | 1568 | void XEmitter::MINSD(X64Reg regOp, const OpArg& arg) { |
| 1596 | void XEmitter::SHUFPD(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0x66, sseSHUF, regOp, arg,1); Write8(shuffle);} | 1569 | WriteSSEOp(0xF2, sseMIN, regOp, arg); |
| 1597 | 1570 | } | |
| 1598 | void XEmitter::HADDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseHADD, regOp, arg);} | 1571 | void XEmitter::MAXSS(X64Reg regOp, const OpArg& arg) { |
| 1599 | 1572 | WriteSSEOp(0xF3, sseMAX, regOp, arg); | |
| 1600 | void XEmitter::COMISS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseCOMIS, regOp, arg);} //weird that these should be packed | 1573 | } |
| 1601 | void XEmitter::COMISD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseCOMIS, regOp, arg);} //ordered | 1574 | void XEmitter::MAXSD(X64Reg regOp, const OpArg& arg) { |
| 1602 | void XEmitter::UCOMISS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseUCOMIS, regOp, arg);} //unordered | 1575 | WriteSSEOp(0xF2, sseMAX, regOp, arg); |
| 1603 | void XEmitter::UCOMISD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseUCOMIS, regOp, arg);} | 1576 | } |
| 1604 | 1577 | void XEmitter::SQRTSS(X64Reg regOp, const OpArg& arg) { | |
| 1605 | void XEmitter::MOVAPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVAPfromRM, regOp, arg);} | 1578 | WriteSSEOp(0xF3, sseSQRT, regOp, arg); |
| 1606 | void XEmitter::MOVAPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVAPfromRM, regOp, arg);} | 1579 | } |
| 1607 | void XEmitter::MOVAPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVAPtoRM, regOp, arg);} | 1580 | void XEmitter::SQRTSD(X64Reg regOp, const OpArg& arg) { |
| 1608 | void XEmitter::MOVAPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVAPtoRM, regOp, arg);} | 1581 | WriteSSEOp(0xF2, sseSQRT, regOp, arg); |
| 1609 | 1582 | } | |
| 1610 | void XEmitter::MOVUPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVUPfromRM, regOp, arg);} | 1583 | void XEmitter::RCPSS(X64Reg regOp, const OpArg& arg) { |
| 1611 | void XEmitter::MOVUPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVUPfromRM, regOp, arg);} | 1584 | WriteSSEOp(0xF3, sseRCP, regOp, arg); |
| 1612 | void XEmitter::MOVUPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVUPtoRM, regOp, arg);} | 1585 | } |
| 1613 | void XEmitter::MOVUPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVUPtoRM, regOp, arg);} | 1586 | void XEmitter::RSQRTSS(X64Reg regOp, const OpArg& arg) { |
| 1614 | 1587 | WriteSSEOp(0xF3, sseRSQRT, regOp, arg); | |
| 1615 | void XEmitter::MOVDQA(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVDQfromRM, regOp, arg);} | 1588 | } |
| 1616 | void XEmitter::MOVDQA(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVDQtoRM, regOp, arg);} | 1589 | |
| 1617 | void XEmitter::MOVDQU(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMOVDQfromRM, regOp, arg);} | 1590 | void XEmitter::ADDPS(X64Reg regOp, const OpArg& arg) { |
| 1618 | void XEmitter::MOVDQU(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF3, sseMOVDQtoRM, regOp, arg);} | 1591 | WriteSSEOp(0x00, sseADD, regOp, arg); |
| 1619 | 1592 | } | |
| 1620 | void XEmitter::MOVSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMOVUPfromRM, regOp, arg);} | 1593 | void XEmitter::ADDPD(X64Reg regOp, const OpArg& arg) { |
| 1621 | void XEmitter::MOVSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMOVUPfromRM, regOp, arg);} | 1594 | WriteSSEOp(0x66, sseADD, regOp, arg); |
| 1622 | void XEmitter::MOVSS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF3, sseMOVUPtoRM, regOp, arg);} | 1595 | } |
| 1623 | void XEmitter::MOVSD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF2, sseMOVUPtoRM, regOp, arg);} | 1596 | void XEmitter::SUBPS(X64Reg regOp, const OpArg& arg) { |
| 1624 | 1597 | WriteSSEOp(0x00, sseSUB, regOp, arg); | |
| 1625 | void XEmitter::MOVLPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseMOVLPfromRM, regOp, arg); } | 1598 | } |
| 1626 | void XEmitter::MOVLPD(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x66, sseMOVLPfromRM, regOp, arg); } | 1599 | void XEmitter::SUBPD(X64Reg regOp, const OpArg& arg) { |
| 1627 | void XEmitter::MOVLPS(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x00, sseMOVLPtoRM, regOp, arg); } | 1600 | WriteSSEOp(0x66, sseSUB, regOp, arg); |
| 1628 | void XEmitter::MOVLPD(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x66, sseMOVLPtoRM, regOp, arg); } | 1601 | } |
| 1629 | 1602 | void XEmitter::CMPPS(X64Reg regOp, const OpArg& arg, u8 compare) { | |
| 1630 | void XEmitter::MOVHPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseMOVHPfromRM, regOp, arg); } | 1603 | WriteSSEOp(0x00, sseCMP, regOp, arg, 1); |
| 1631 | void XEmitter::MOVHPD(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x66, sseMOVHPfromRM, regOp, arg); } | 1604 | Write8(compare); |
| 1632 | void XEmitter::MOVHPS(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x00, sseMOVHPtoRM, regOp, arg); } | 1605 | } |
| 1633 | void XEmitter::MOVHPD(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x66, sseMOVHPtoRM, regOp, arg); } | 1606 | void XEmitter::CMPPD(X64Reg regOp, const OpArg& arg, u8 compare) { |
| 1634 | 1607 | WriteSSEOp(0x66, sseCMP, regOp, arg, 1); | |
| 1635 | void XEmitter::MOVHLPS(X64Reg regOp1, X64Reg regOp2) {WriteSSEOp(0x00, sseMOVHLPS, regOp1, R(regOp2));} | 1608 | Write8(compare); |
| 1636 | void XEmitter::MOVLHPS(X64Reg regOp1, X64Reg regOp2) {WriteSSEOp(0x00, sseMOVLHPS, regOp1, R(regOp2));} | 1609 | } |
| 1637 | 1610 | void XEmitter::ANDPS(X64Reg regOp, const OpArg& arg) { | |
| 1638 | void XEmitter::CVTPS2PD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, 0x5A, regOp, arg);} | 1611 | WriteSSEOp(0x00, sseAND, regOp, arg); |
| 1639 | void XEmitter::CVTPD2PS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0x5A, regOp, arg);} | 1612 | } |
| 1640 | 1613 | void XEmitter::ANDPD(X64Reg regOp, const OpArg& arg) { | |
| 1641 | void XEmitter::CVTSD2SS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x5A, regOp, arg);} | 1614 | WriteSSEOp(0x66, sseAND, regOp, arg); |
| 1642 | void XEmitter::CVTSS2SD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x5A, regOp, arg);} | 1615 | } |
| 1643 | void XEmitter::CVTSD2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2D, regOp, arg);} | 1616 | void XEmitter::ANDNPS(X64Reg regOp, const OpArg& arg) { |
| 1644 | void XEmitter::CVTSS2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2D, regOp, arg);} | 1617 | WriteSSEOp(0x00, sseANDN, regOp, arg); |
| 1645 | void XEmitter::CVTSI2SD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2A, regOp, arg);} | 1618 | } |
| 1646 | void XEmitter::CVTSI2SS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2A, regOp, arg);} | 1619 | void XEmitter::ANDNPD(X64Reg regOp, const OpArg& arg) { |
| 1647 | 1620 | WriteSSEOp(0x66, sseANDN, regOp, arg); | |
| 1648 | void XEmitter::CVTDQ2PD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0xE6, regOp, arg);} | 1621 | } |
| 1649 | void XEmitter::CVTDQ2PS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, 0x5B, regOp, arg);} | 1622 | void XEmitter::ORPS(X64Reg regOp, const OpArg& arg) { |
| 1650 | void XEmitter::CVTPD2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0xE6, regOp, arg);} | 1623 | WriteSSEOp(0x00, sseOR, regOp, arg); |
| 1651 | void XEmitter::CVTPS2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0x5B, regOp, arg);} | 1624 | } |
| 1652 | 1625 | void XEmitter::ORPD(X64Reg regOp, const OpArg& arg) { | |
| 1653 | void XEmitter::CVTTSD2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2C, regOp, arg);} | 1626 | WriteSSEOp(0x66, sseOR, regOp, arg); |
| 1654 | void XEmitter::CVTTSS2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2C, regOp, arg);} | 1627 | } |
| 1655 | void XEmitter::CVTTPS2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x5B, regOp, arg);} | 1628 | void XEmitter::XORPS(X64Reg regOp, const OpArg& arg) { |
| 1656 | void XEmitter::CVTTPD2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0xE6, regOp, arg);} | 1629 | WriteSSEOp(0x00, sseXOR, regOp, arg); |
| 1657 | 1630 | } | |
| 1658 | void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) {WriteSSEOp(0x66, sseMASKMOVDQU, dest, R(src));} | 1631 | void XEmitter::XORPD(X64Reg regOp, const OpArg& arg) { |
| 1659 | 1632 | WriteSSEOp(0x66, sseXOR, regOp, arg); | |
| 1660 | void XEmitter::MOVMSKPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x50, dest, arg);} | 1633 | } |
| 1661 | void XEmitter::MOVMSKPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x50, dest, arg);} | 1634 | void XEmitter::MULPS(X64Reg regOp, const OpArg& arg) { |
| 1662 | 1635 | WriteSSEOp(0x00, sseMUL, regOp, arg); | |
| 1663 | void XEmitter::LDDQU(X64Reg dest, const OpArg& arg) {WriteSSEOp(0xF2, sseLDDQU, dest, arg);} // For integer data only | 1636 | } |
| 1637 | void XEmitter::MULPD(X64Reg regOp, const OpArg& arg) { | ||
| 1638 | WriteSSEOp(0x66, sseMUL, regOp, arg); | ||
| 1639 | } | ||
| 1640 | void XEmitter::DIVPS(X64Reg regOp, const OpArg& arg) { | ||
| 1641 | WriteSSEOp(0x00, sseDIV, regOp, arg); | ||
| 1642 | } | ||
| 1643 | void XEmitter::DIVPD(X64Reg regOp, const OpArg& arg) { | ||
| 1644 | WriteSSEOp(0x66, sseDIV, regOp, arg); | ||
| 1645 | } | ||
| 1646 | void XEmitter::MINPS(X64Reg regOp, const OpArg& arg) { | ||
| 1647 | WriteSSEOp(0x00, sseMIN, regOp, arg); | ||
| 1648 | } | ||
| 1649 | void XEmitter::MINPD(X64Reg regOp, const OpArg& arg) { | ||
| 1650 | WriteSSEOp(0x66, sseMIN, regOp, arg); | ||
| 1651 | } | ||
| 1652 | void XEmitter::MAXPS(X64Reg regOp, const OpArg& arg) { | ||
| 1653 | WriteSSEOp(0x00, sseMAX, regOp, arg); | ||
| 1654 | } | ||
| 1655 | void XEmitter::MAXPD(X64Reg regOp, const OpArg& arg) { | ||
| 1656 | WriteSSEOp(0x66, sseMAX, regOp, arg); | ||
| 1657 | } | ||
| 1658 | void XEmitter::SQRTPS(X64Reg regOp, const OpArg& arg) { | ||
| 1659 | WriteSSEOp(0x00, sseSQRT, regOp, arg); | ||
| 1660 | } | ||
| 1661 | void XEmitter::SQRTPD(X64Reg regOp, const OpArg& arg) { | ||
| 1662 | WriteSSEOp(0x66, sseSQRT, regOp, arg); | ||
| 1663 | } | ||
| 1664 | void XEmitter::RCPPS(X64Reg regOp, const OpArg& arg) { | ||
| 1665 | WriteSSEOp(0x00, sseRCP, regOp, arg); | ||
| 1666 | } | ||
| 1667 | void XEmitter::RSQRTPS(X64Reg regOp, const OpArg& arg) { | ||
| 1668 | WriteSSEOp(0x00, sseRSQRT, regOp, arg); | ||
| 1669 | } | ||
| 1670 | void XEmitter::SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle) { | ||
| 1671 | WriteSSEOp(0x00, sseSHUF, regOp, arg, 1); | ||
| 1672 | Write8(shuffle); | ||
| 1673 | } | ||
| 1674 | void XEmitter::SHUFPD(X64Reg regOp, const OpArg& arg, u8 shuffle) { | ||
| 1675 | WriteSSEOp(0x66, sseSHUF, regOp, arg, 1); | ||
| 1676 | Write8(shuffle); | ||
| 1677 | } | ||
| 1678 | |||
| 1679 | void XEmitter::HADDPS(X64Reg regOp, const OpArg& arg) { | ||
| 1680 | WriteSSEOp(0xF2, sseHADD, regOp, arg); | ||
| 1681 | } | ||
| 1682 | |||
| 1683 | void XEmitter::COMISS(X64Reg regOp, const OpArg& arg) { | ||
| 1684 | WriteSSEOp(0x00, sseCOMIS, regOp, arg); | ||
| 1685 | } // weird that these should be packed | ||
| 1686 | void XEmitter::COMISD(X64Reg regOp, const OpArg& arg) { | ||
| 1687 | WriteSSEOp(0x66, sseCOMIS, regOp, arg); | ||
| 1688 | } // ordered | ||
| 1689 | void XEmitter::UCOMISS(X64Reg regOp, const OpArg& arg) { | ||
| 1690 | WriteSSEOp(0x00, sseUCOMIS, regOp, arg); | ||
| 1691 | } // unordered | ||
| 1692 | void XEmitter::UCOMISD(X64Reg regOp, const OpArg& arg) { | ||
| 1693 | WriteSSEOp(0x66, sseUCOMIS, regOp, arg); | ||
| 1694 | } | ||
| 1695 | |||
| 1696 | void XEmitter::MOVAPS(X64Reg regOp, const OpArg& arg) { | ||
| 1697 | WriteSSEOp(0x00, sseMOVAPfromRM, regOp, arg); | ||
| 1698 | } | ||
| 1699 | void XEmitter::MOVAPD(X64Reg regOp, const OpArg& arg) { | ||
| 1700 | WriteSSEOp(0x66, sseMOVAPfromRM, regOp, arg); | ||
| 1701 | } | ||
| 1702 | void XEmitter::MOVAPS(const OpArg& arg, X64Reg regOp) { | ||
| 1703 | WriteSSEOp(0x00, sseMOVAPtoRM, regOp, arg); | ||
| 1704 | } | ||
| 1705 | void XEmitter::MOVAPD(const OpArg& arg, X64Reg regOp) { | ||
| 1706 | WriteSSEOp(0x66, sseMOVAPtoRM, regOp, arg); | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | void XEmitter::MOVUPS(X64Reg regOp, const OpArg& arg) { | ||
| 1710 | WriteSSEOp(0x00, sseMOVUPfromRM, regOp, arg); | ||
| 1711 | } | ||
| 1712 | void XEmitter::MOVUPD(X64Reg regOp, const OpArg& arg) { | ||
| 1713 | WriteSSEOp(0x66, sseMOVUPfromRM, regOp, arg); | ||
| 1714 | } | ||
| 1715 | void XEmitter::MOVUPS(const OpArg& arg, X64Reg regOp) { | ||
| 1716 | WriteSSEOp(0x00, sseMOVUPtoRM, regOp, arg); | ||
| 1717 | } | ||
| 1718 | void XEmitter::MOVUPD(const OpArg& arg, X64Reg regOp) { | ||
| 1719 | WriteSSEOp(0x66, sseMOVUPtoRM, regOp, arg); | ||
| 1720 | } | ||
| 1721 | |||
| 1722 | void XEmitter::MOVDQA(X64Reg regOp, const OpArg& arg) { | ||
| 1723 | WriteSSEOp(0x66, sseMOVDQfromRM, regOp, arg); | ||
| 1724 | } | ||
| 1725 | void XEmitter::MOVDQA(const OpArg& arg, X64Reg regOp) { | ||
| 1726 | WriteSSEOp(0x66, sseMOVDQtoRM, regOp, arg); | ||
| 1727 | } | ||
| 1728 | void XEmitter::MOVDQU(X64Reg regOp, const OpArg& arg) { | ||
| 1729 | WriteSSEOp(0xF3, sseMOVDQfromRM, regOp, arg); | ||
| 1730 | } | ||
| 1731 | void XEmitter::MOVDQU(const OpArg& arg, X64Reg regOp) { | ||
| 1732 | WriteSSEOp(0xF3, sseMOVDQtoRM, regOp, arg); | ||
| 1733 | } | ||
| 1734 | |||
| 1735 | void XEmitter::MOVSS(X64Reg regOp, const OpArg& arg) { | ||
| 1736 | WriteSSEOp(0xF3, sseMOVUPfromRM, regOp, arg); | ||
| 1737 | } | ||
| 1738 | void XEmitter::MOVSD(X64Reg regOp, const OpArg& arg) { | ||
| 1739 | WriteSSEOp(0xF2, sseMOVUPfromRM, regOp, arg); | ||
| 1740 | } | ||
| 1741 | void XEmitter::MOVSS(const OpArg& arg, X64Reg regOp) { | ||
| 1742 | WriteSSEOp(0xF3, sseMOVUPtoRM, regOp, arg); | ||
| 1743 | } | ||
| 1744 | void XEmitter::MOVSD(const OpArg& arg, X64Reg regOp) { | ||
| 1745 | WriteSSEOp(0xF2, sseMOVUPtoRM, regOp, arg); | ||
| 1746 | } | ||
| 1747 | |||
| 1748 | void XEmitter::MOVLPS(X64Reg regOp, const OpArg& arg) { | ||
| 1749 | WriteSSEOp(0x00, sseMOVLPfromRM, regOp, arg); | ||
| 1750 | } | ||
| 1751 | void XEmitter::MOVLPD(X64Reg regOp, const OpArg& arg) { | ||
| 1752 | WriteSSEOp(0x66, sseMOVLPfromRM, regOp, arg); | ||
| 1753 | } | ||
| 1754 | void XEmitter::MOVLPS(const OpArg& arg, X64Reg regOp) { | ||
| 1755 | WriteSSEOp(0x00, sseMOVLPtoRM, regOp, arg); | ||
| 1756 | } | ||
| 1757 | void XEmitter::MOVLPD(const OpArg& arg, X64Reg regOp) { | ||
| 1758 | WriteSSEOp(0x66, sseMOVLPtoRM, regOp, arg); | ||
| 1759 | } | ||
| 1760 | |||
| 1761 | void XEmitter::MOVHPS(X64Reg regOp, const OpArg& arg) { | ||
| 1762 | WriteSSEOp(0x00, sseMOVHPfromRM, regOp, arg); | ||
| 1763 | } | ||
| 1764 | void XEmitter::MOVHPD(X64Reg regOp, const OpArg& arg) { | ||
| 1765 | WriteSSEOp(0x66, sseMOVHPfromRM, regOp, arg); | ||
| 1766 | } | ||
| 1767 | void XEmitter::MOVHPS(const OpArg& arg, X64Reg regOp) { | ||
| 1768 | WriteSSEOp(0x00, sseMOVHPtoRM, regOp, arg); | ||
| 1769 | } | ||
| 1770 | void XEmitter::MOVHPD(const OpArg& arg, X64Reg regOp) { | ||
| 1771 | WriteSSEOp(0x66, sseMOVHPtoRM, regOp, arg); | ||
| 1772 | } | ||
| 1773 | |||
| 1774 | void XEmitter::MOVHLPS(X64Reg regOp1, X64Reg regOp2) { | ||
| 1775 | WriteSSEOp(0x00, sseMOVHLPS, regOp1, R(regOp2)); | ||
| 1776 | } | ||
| 1777 | void XEmitter::MOVLHPS(X64Reg regOp1, X64Reg regOp2) { | ||
| 1778 | WriteSSEOp(0x00, sseMOVLHPS, regOp1, R(regOp2)); | ||
| 1779 | } | ||
| 1780 | |||
| 1781 | void XEmitter::CVTPS2PD(X64Reg regOp, const OpArg& arg) { | ||
| 1782 | WriteSSEOp(0x00, 0x5A, regOp, arg); | ||
| 1783 | } | ||
| 1784 | void XEmitter::CVTPD2PS(X64Reg regOp, const OpArg& arg) { | ||
| 1785 | WriteSSEOp(0x66, 0x5A, regOp, arg); | ||
| 1786 | } | ||
| 1787 | |||
| 1788 | void XEmitter::CVTSD2SS(X64Reg regOp, const OpArg& arg) { | ||
| 1789 | WriteSSEOp(0xF2, 0x5A, regOp, arg); | ||
| 1790 | } | ||
| 1791 | void XEmitter::CVTSS2SD(X64Reg regOp, const OpArg& arg) { | ||
| 1792 | WriteSSEOp(0xF3, 0x5A, regOp, arg); | ||
| 1793 | } | ||
| 1794 | void XEmitter::CVTSD2SI(X64Reg regOp, const OpArg& arg) { | ||
| 1795 | WriteSSEOp(0xF2, 0x2D, regOp, arg); | ||
| 1796 | } | ||
| 1797 | void XEmitter::CVTSS2SI(X64Reg regOp, const OpArg& arg) { | ||
| 1798 | WriteSSEOp(0xF3, 0x2D, regOp, arg); | ||
| 1799 | } | ||
| 1800 | void XEmitter::CVTSI2SD(X64Reg regOp, const OpArg& arg) { | ||
| 1801 | WriteSSEOp(0xF2, 0x2A, regOp, arg); | ||
| 1802 | } | ||
| 1803 | void XEmitter::CVTSI2SS(X64Reg regOp, const OpArg& arg) { | ||
| 1804 | WriteSSEOp(0xF3, 0x2A, regOp, arg); | ||
| 1805 | } | ||
| 1806 | |||
| 1807 | void XEmitter::CVTDQ2PD(X64Reg regOp, const OpArg& arg) { | ||
| 1808 | WriteSSEOp(0xF3, 0xE6, regOp, arg); | ||
| 1809 | } | ||
| 1810 | void XEmitter::CVTDQ2PS(X64Reg regOp, const OpArg& arg) { | ||
| 1811 | WriteSSEOp(0x00, 0x5B, regOp, arg); | ||
| 1812 | } | ||
| 1813 | void XEmitter::CVTPD2DQ(X64Reg regOp, const OpArg& arg) { | ||
| 1814 | WriteSSEOp(0xF2, 0xE6, regOp, arg); | ||
| 1815 | } | ||
| 1816 | void XEmitter::CVTPS2DQ(X64Reg regOp, const OpArg& arg) { | ||
| 1817 | WriteSSEOp(0x66, 0x5B, regOp, arg); | ||
| 1818 | } | ||
| 1819 | |||
| 1820 | void XEmitter::CVTTSD2SI(X64Reg regOp, const OpArg& arg) { | ||
| 1821 | WriteSSEOp(0xF2, 0x2C, regOp, arg); | ||
| 1822 | } | ||
| 1823 | void XEmitter::CVTTSS2SI(X64Reg regOp, const OpArg& arg) { | ||
| 1824 | WriteSSEOp(0xF3, 0x2C, regOp, arg); | ||
| 1825 | } | ||
| 1826 | void XEmitter::CVTTPS2DQ(X64Reg regOp, const OpArg& arg) { | ||
| 1827 | WriteSSEOp(0xF3, 0x5B, regOp, arg); | ||
| 1828 | } | ||
| 1829 | void XEmitter::CVTTPD2DQ(X64Reg regOp, const OpArg& arg) { | ||
| 1830 | WriteSSEOp(0x66, 0xE6, regOp, arg); | ||
| 1831 | } | ||
| 1832 | |||
| 1833 | void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) { | ||
| 1834 | WriteSSEOp(0x66, sseMASKMOVDQU, dest, R(src)); | ||
| 1835 | } | ||
| 1836 | |||
| 1837 | void XEmitter::MOVMSKPS(X64Reg dest, const OpArg& arg) { | ||
| 1838 | WriteSSEOp(0x00, 0x50, dest, arg); | ||
| 1839 | } | ||
| 1840 | void XEmitter::MOVMSKPD(X64Reg dest, const OpArg& arg) { | ||
| 1841 | WriteSSEOp(0x66, 0x50, dest, arg); | ||
| 1842 | } | ||
| 1843 | |||
| 1844 | void XEmitter::LDDQU(X64Reg dest, const OpArg& arg) { | ||
| 1845 | WriteSSEOp(0xF2, sseLDDQU, dest, arg); | ||
| 1846 | } // For integer data only | ||
| 1664 | 1847 | ||
| 1665 | // THESE TWO ARE UNTESTED. | 1848 | // THESE TWO ARE UNTESTED. |
| 1666 | void XEmitter::UNPCKLPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x14, dest, arg);} | 1849 | void XEmitter::UNPCKLPS(X64Reg dest, const OpArg& arg) { |
| 1667 | void XEmitter::UNPCKHPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x15, dest, arg);} | 1850 | WriteSSEOp(0x00, 0x14, dest, arg); |
| 1851 | } | ||
| 1852 | void XEmitter::UNPCKHPS(X64Reg dest, const OpArg& arg) { | ||
| 1853 | WriteSSEOp(0x00, 0x15, dest, arg); | ||
| 1854 | } | ||
| 1668 | 1855 | ||
| 1669 | void XEmitter::UNPCKLPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x14, dest, arg);} | 1856 | void XEmitter::UNPCKLPD(X64Reg dest, const OpArg& arg) { |
| 1670 | void XEmitter::UNPCKHPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x15, dest, arg);} | 1857 | WriteSSEOp(0x66, 0x14, dest, arg); |
| 1858 | } | ||
| 1859 | void XEmitter::UNPCKHPD(X64Reg dest, const OpArg& arg) { | ||
| 1860 | WriteSSEOp(0x66, 0x15, dest, arg); | ||
| 1861 | } | ||
| 1671 | 1862 | ||
| 1672 | void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg) | 1863 | void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg) { |
| 1673 | { | 1864 | if (Common::GetCPUCaps().sse3) { |
| 1674 | if (Common::GetCPUCaps().sse3) | 1865 | WriteSSEOp(0xF2, 0x12, regOp, arg); // SSE3 movddup |
| 1675 | { | 1866 | } else { |
| 1676 | WriteSSEOp(0xF2, 0x12, regOp, arg); //SSE3 movddup | ||
| 1677 | } | ||
| 1678 | else | ||
| 1679 | { | ||
| 1680 | // Simulate this instruction with SSE2 instructions | 1867 | // Simulate this instruction with SSE2 instructions |
| 1681 | if (!arg.IsSimpleReg(regOp)) | 1868 | if (!arg.IsSimpleReg(regOp)) |
| 1682 | MOVSD(regOp, arg); | 1869 | MOVSD(regOp, arg); |
| @@ -1684,38 +1871,48 @@ void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg) | |||
| 1684 | } | 1871 | } |
| 1685 | } | 1872 | } |
| 1686 | 1873 | ||
| 1687 | //There are a few more left | 1874 | // There are a few more left |
| 1688 | 1875 | ||
| 1689 | // Also some integer instructions are missing | 1876 | // Also some integer instructions are missing |
| 1690 | void XEmitter::PACKSSDW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x6B, dest, arg);} | 1877 | void XEmitter::PACKSSDW(X64Reg dest, const OpArg& arg) { |
| 1691 | void XEmitter::PACKSSWB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x63, dest, arg);} | 1878 | WriteSSEOp(0x66, 0x6B, dest, arg); |
| 1692 | void XEmitter::PACKUSWB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x67, dest, arg);} | 1879 | } |
| 1880 | void XEmitter::PACKSSWB(X64Reg dest, const OpArg& arg) { | ||
| 1881 | WriteSSEOp(0x66, 0x63, dest, arg); | ||
| 1882 | } | ||
| 1883 | void XEmitter::PACKUSWB(X64Reg dest, const OpArg& arg) { | ||
| 1884 | WriteSSEOp(0x66, 0x67, dest, arg); | ||
| 1885 | } | ||
| 1693 | 1886 | ||
| 1694 | void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x60, dest, arg);} | 1887 | void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg& arg) { |
| 1695 | void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x61, dest, arg);} | 1888 | WriteSSEOp(0x66, 0x60, dest, arg); |
| 1696 | void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x62, dest, arg);} | 1889 | } |
| 1697 | void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x6C, dest, arg);} | 1890 | void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg& arg) { |
| 1891 | WriteSSEOp(0x66, 0x61, dest, arg); | ||
| 1892 | } | ||
| 1893 | void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg& arg) { | ||
| 1894 | WriteSSEOp(0x66, 0x62, dest, arg); | ||
| 1895 | } | ||
| 1896 | void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg& arg) { | ||
| 1897 | WriteSSEOp(0x66, 0x6C, dest, arg); | ||
| 1898 | } | ||
| 1698 | 1899 | ||
| 1699 | void XEmitter::PSRLW(X64Reg reg, int shift) | 1900 | void XEmitter::PSRLW(X64Reg reg, int shift) { |
| 1700 | { | ||
| 1701 | WriteSSEOp(0x66, 0x71, (X64Reg)2, R(reg)); | 1901 | WriteSSEOp(0x66, 0x71, (X64Reg)2, R(reg)); |
| 1702 | Write8(shift); | 1902 | Write8(shift); |
| 1703 | } | 1903 | } |
| 1704 | 1904 | ||
| 1705 | void XEmitter::PSRLD(X64Reg reg, int shift) | 1905 | void XEmitter::PSRLD(X64Reg reg, int shift) { |
| 1706 | { | ||
| 1707 | WriteSSEOp(0x66, 0x72, (X64Reg)2, R(reg)); | 1906 | WriteSSEOp(0x66, 0x72, (X64Reg)2, R(reg)); |
| 1708 | Write8(shift); | 1907 | Write8(shift); |
| 1709 | } | 1908 | } |
| 1710 | 1909 | ||
| 1711 | void XEmitter::PSRLQ(X64Reg reg, int shift) | 1910 | void XEmitter::PSRLQ(X64Reg reg, int shift) { |
| 1712 | { | ||
| 1713 | WriteSSEOp(0x66, 0x73, (X64Reg)2, R(reg)); | 1911 | WriteSSEOp(0x66, 0x73, (X64Reg)2, R(reg)); |
| 1714 | Write8(shift); | 1912 | Write8(shift); |
| 1715 | } | 1913 | } |
| 1716 | 1914 | ||
| 1717 | void XEmitter::PSRLQ(X64Reg reg, const OpArg& arg) | 1915 | void XEmitter::PSRLQ(X64Reg reg, const OpArg& arg) { |
| 1718 | { | ||
| 1719 | WriteSSEOp(0x66, 0xd3, reg, arg); | 1916 | WriteSSEOp(0x66, 0xd3, reg, arg); |
| 1720 | } | 1917 | } |
| 1721 | 1918 | ||
| @@ -1724,20 +1921,17 @@ void XEmitter::PSRLDQ(X64Reg reg, int shift) { | |||
| 1724 | Write8(shift); | 1921 | Write8(shift); |
| 1725 | } | 1922 | } |
| 1726 | 1923 | ||
| 1727 | void XEmitter::PSLLW(X64Reg reg, int shift) | 1924 | void XEmitter::PSLLW(X64Reg reg, int shift) { |
| 1728 | { | ||
| 1729 | WriteSSEOp(0x66, 0x71, (X64Reg)6, R(reg)); | 1925 | WriteSSEOp(0x66, 0x71, (X64Reg)6, R(reg)); |
| 1730 | Write8(shift); | 1926 | Write8(shift); |
| 1731 | } | 1927 | } |
| 1732 | 1928 | ||
| 1733 | void XEmitter::PSLLD(X64Reg reg, int shift) | 1929 | void XEmitter::PSLLD(X64Reg reg, int shift) { |
| 1734 | { | ||
| 1735 | WriteSSEOp(0x66, 0x72, (X64Reg)6, R(reg)); | 1930 | WriteSSEOp(0x66, 0x72, (X64Reg)6, R(reg)); |
| 1736 | Write8(shift); | 1931 | Write8(shift); |
| 1737 | } | 1932 | } |
| 1738 | 1933 | ||
| 1739 | void XEmitter::PSLLQ(X64Reg reg, int shift) | 1934 | void XEmitter::PSLLQ(X64Reg reg, int shift) { |
| 1740 | { | ||
| 1741 | WriteSSEOp(0x66, 0x73, (X64Reg)6, R(reg)); | 1935 | WriteSSEOp(0x66, 0x73, (X64Reg)6, R(reg)); |
| 1742 | Write8(shift); | 1936 | Write8(shift); |
| 1743 | } | 1937 | } |
| @@ -1747,267 +1941,643 @@ void XEmitter::PSLLDQ(X64Reg reg, int shift) { | |||
| 1747 | Write8(shift); | 1941 | Write8(shift); |
| 1748 | } | 1942 | } |
| 1749 | 1943 | ||
| 1750 | void XEmitter::PSRAW(X64Reg reg, int shift) | 1944 | void XEmitter::PSRAW(X64Reg reg, int shift) { |
| 1751 | { | ||
| 1752 | WriteSSEOp(0x66, 0x71, (X64Reg)4, R(reg)); | 1945 | WriteSSEOp(0x66, 0x71, (X64Reg)4, R(reg)); |
| 1753 | Write8(shift); | 1946 | Write8(shift); |
| 1754 | } | 1947 | } |
| 1755 | 1948 | ||
| 1756 | void XEmitter::PSRAD(X64Reg reg, int shift) | 1949 | void XEmitter::PSRAD(X64Reg reg, int shift) { |
| 1757 | { | ||
| 1758 | WriteSSEOp(0x66, 0x72, (X64Reg)4, R(reg)); | 1950 | WriteSSEOp(0x66, 0x72, (X64Reg)4, R(reg)); |
| 1759 | Write8(shift); | 1951 | Write8(shift); |
| 1760 | } | 1952 | } |
| 1761 | 1953 | ||
| 1762 | void XEmitter::WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) | 1954 | void XEmitter::WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) { |
| 1763 | { | ||
| 1764 | if (!Common::GetCPUCaps().ssse3) | 1955 | if (!Common::GetCPUCaps().ssse3) |
| 1765 | ASSERT_MSG(0, "Trying to use SSSE3 on a system that doesn't support it. Bad programmer."); | 1956 | ASSERT_MSG(0, "Trying to use SSSE3 on a system that doesn't support it. Bad programmer."); |
| 1766 | WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); | 1957 | WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); |
| 1767 | } | 1958 | } |
| 1768 | 1959 | ||
| 1769 | void XEmitter::WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) | 1960 | void XEmitter::WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) { |
| 1770 | { | ||
| 1771 | if (!Common::GetCPUCaps().sse4_1) | 1961 | if (!Common::GetCPUCaps().sse4_1) |
| 1772 | ASSERT_MSG(0, "Trying to use SSE4.1 on a system that doesn't support it. Bad programmer."); | 1962 | ASSERT_MSG(0, "Trying to use SSE4.1 on a system that doesn't support it. Bad programmer."); |
| 1773 | WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); | 1963 | WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); |
| 1774 | } | 1964 | } |
| 1775 | 1965 | ||
| 1776 | void XEmitter::PSHUFB(X64Reg dest, const OpArg& arg) {WriteSSSE3Op(0x66, 0x3800, dest, arg);} | 1966 | void XEmitter::PSHUFB(X64Reg dest, const OpArg& arg) { |
| 1777 | void XEmitter::PTEST(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3817, dest, arg);} | 1967 | WriteSSSE3Op(0x66, 0x3800, dest, arg); |
| 1778 | void XEmitter::PACKUSDW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x382b, dest, arg);} | 1968 | } |
| 1779 | void XEmitter::DPPS(X64Reg dest, const OpArg& arg, u8 mask) {WriteSSE41Op(0x66, 0x3A40, dest, arg, 1); Write8(mask);} | 1969 | void XEmitter::PTEST(X64Reg dest, const OpArg& arg) { |
| 1780 | 1970 | WriteSSE41Op(0x66, 0x3817, dest, arg); | |
| 1781 | void XEmitter::PMINSB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3838, dest, arg);} | 1971 | } |
| 1782 | void XEmitter::PMINSD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3839, dest, arg);} | 1972 | void XEmitter::PACKUSDW(X64Reg dest, const OpArg& arg) { |
| 1783 | void XEmitter::PMINUW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383a, dest, arg);} | 1973 | WriteSSE41Op(0x66, 0x382b, dest, arg); |
| 1784 | void XEmitter::PMINUD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383b, dest, arg);} | 1974 | } |
| 1785 | void XEmitter::PMAXSB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383c, dest, arg);} | 1975 | void XEmitter::DPPS(X64Reg dest, const OpArg& arg, u8 mask) { |
| 1786 | void XEmitter::PMAXSD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383d, dest, arg);} | 1976 | WriteSSE41Op(0x66, 0x3A40, dest, arg, 1); |
| 1787 | void XEmitter::PMAXUW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383e, dest, arg);} | 1977 | Write8(mask); |
| 1788 | void XEmitter::PMAXUD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383f, dest, arg);} | 1978 | } |
| 1789 | 1979 | ||
| 1790 | void XEmitter::PMOVSXBW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3820, dest, arg);} | 1980 | void XEmitter::PMINSB(X64Reg dest, const OpArg& arg) { |
| 1791 | void XEmitter::PMOVSXBD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3821, dest, arg);} | 1981 | WriteSSE41Op(0x66, 0x3838, dest, arg); |
| 1792 | void XEmitter::PMOVSXBQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3822, dest, arg);} | 1982 | } |
| 1793 | void XEmitter::PMOVSXWD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3823, dest, arg);} | 1983 | void XEmitter::PMINSD(X64Reg dest, const OpArg& arg) { |
| 1794 | void XEmitter::PMOVSXWQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3824, dest, arg);} | 1984 | WriteSSE41Op(0x66, 0x3839, dest, arg); |
| 1795 | void XEmitter::PMOVSXDQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3825, dest, arg);} | 1985 | } |
| 1796 | void XEmitter::PMOVZXBW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3830, dest, arg);} | 1986 | void XEmitter::PMINUW(X64Reg dest, const OpArg& arg) { |
| 1797 | void XEmitter::PMOVZXBD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3831, dest, arg);} | 1987 | WriteSSE41Op(0x66, 0x383a, dest, arg); |
| 1798 | void XEmitter::PMOVZXBQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3832, dest, arg);} | 1988 | } |
| 1799 | void XEmitter::PMOVZXWD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3833, dest, arg);} | 1989 | void XEmitter::PMINUD(X64Reg dest, const OpArg& arg) { |
| 1800 | void XEmitter::PMOVZXWQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3834, dest, arg);} | 1990 | WriteSSE41Op(0x66, 0x383b, dest, arg); |
| 1801 | void XEmitter::PMOVZXDQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3835, dest, arg);} | 1991 | } |
| 1802 | 1992 | void XEmitter::PMAXSB(X64Reg dest, const OpArg& arg) { | |
| 1803 | void XEmitter::PBLENDVB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3810, dest, arg);} | 1993 | WriteSSE41Op(0x66, 0x383c, dest, arg); |
| 1804 | void XEmitter::BLENDVPS(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3814, dest, arg);} | 1994 | } |
| 1805 | void XEmitter::BLENDVPD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3815, dest, arg);} | 1995 | void XEmitter::PMAXSD(X64Reg dest, const OpArg& arg) { |
| 1806 | void XEmitter::BLENDPS(X64Reg dest, const OpArg& arg, u8 blend) { WriteSSE41Op(0x66, 0x3A0C, dest, arg, 1); Write8(blend); } | 1996 | WriteSSE41Op(0x66, 0x383d, dest, arg); |
| 1807 | void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) { WriteSSE41Op(0x66, 0x3A0D, dest, arg, 1); Write8(blend); } | 1997 | } |
| 1808 | 1998 | void XEmitter::PMAXUW(X64Reg dest, const OpArg& arg) { | |
| 1809 | void XEmitter::ROUNDSS(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A0A, dest, arg, 1); Write8(mode);} | 1999 | WriteSSE41Op(0x66, 0x383e, dest, arg); |
| 1810 | void XEmitter::ROUNDSD(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A0B, dest, arg, 1); Write8(mode);} | 2000 | } |
| 1811 | void XEmitter::ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A08, dest, arg, 1); Write8(mode);} | 2001 | void XEmitter::PMAXUD(X64Reg dest, const OpArg& arg) { |
| 1812 | void XEmitter::ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A09, dest, arg, 1); Write8(mode);} | 2002 | WriteSSE41Op(0x66, 0x383f, dest, arg); |
| 1813 | 2003 | } | |
| 1814 | void XEmitter::PAND(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDB, dest, arg);} | 2004 | |
| 1815 | void XEmitter::PANDN(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDF, dest, arg);} | 2005 | void XEmitter::PMOVSXBW(X64Reg dest, const OpArg& arg) { |
| 1816 | void XEmitter::PXOR(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEF, dest, arg);} | 2006 | WriteSSE41Op(0x66, 0x3820, dest, arg); |
| 1817 | void XEmitter::POR(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEB, dest, arg);} | 2007 | } |
| 1818 | 2008 | void XEmitter::PMOVSXBD(X64Reg dest, const OpArg& arg) { | |
| 1819 | void XEmitter::PADDB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFC, dest, arg);} | 2009 | WriteSSE41Op(0x66, 0x3821, dest, arg); |
| 1820 | void XEmitter::PADDW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFD, dest, arg);} | 2010 | } |
| 1821 | void XEmitter::PADDD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFE, dest, arg);} | 2011 | void XEmitter::PMOVSXBQ(X64Reg dest, const OpArg& arg) { |
| 1822 | void XEmitter::PADDQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD4, dest, arg);} | 2012 | WriteSSE41Op(0x66, 0x3822, dest, arg); |
| 1823 | 2013 | } | |
| 1824 | void XEmitter::PADDSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEC, dest, arg);} | 2014 | void XEmitter::PMOVSXWD(X64Reg dest, const OpArg& arg) { |
| 1825 | void XEmitter::PADDSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xED, dest, arg);} | 2015 | WriteSSE41Op(0x66, 0x3823, dest, arg); |
| 1826 | void XEmitter::PADDUSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDC, dest, arg);} | 2016 | } |
| 1827 | void XEmitter::PADDUSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDD, dest, arg);} | 2017 | void XEmitter::PMOVSXWQ(X64Reg dest, const OpArg& arg) { |
| 1828 | 2018 | WriteSSE41Op(0x66, 0x3824, dest, arg); | |
| 1829 | void XEmitter::PSUBB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF8, dest, arg);} | 2019 | } |
| 1830 | void XEmitter::PSUBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF9, dest, arg);} | 2020 | void XEmitter::PMOVSXDQ(X64Reg dest, const OpArg& arg) { |
| 1831 | void XEmitter::PSUBD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFA, dest, arg);} | 2021 | WriteSSE41Op(0x66, 0x3825, dest, arg); |
| 1832 | void XEmitter::PSUBQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFB, dest, arg);} | 2022 | } |
| 1833 | 2023 | void XEmitter::PMOVZXBW(X64Reg dest, const OpArg& arg) { | |
| 1834 | void XEmitter::PSUBSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE8, dest, arg);} | 2024 | WriteSSE41Op(0x66, 0x3830, dest, arg); |
| 1835 | void XEmitter::PSUBSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE9, dest, arg);} | 2025 | } |
| 1836 | void XEmitter::PSUBUSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD8, dest, arg);} | 2026 | void XEmitter::PMOVZXBD(X64Reg dest, const OpArg& arg) { |
| 1837 | void XEmitter::PSUBUSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD9, dest, arg);} | 2027 | WriteSSE41Op(0x66, 0x3831, dest, arg); |
| 1838 | 2028 | } | |
| 1839 | void XEmitter::PAVGB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE0, dest, arg);} | 2029 | void XEmitter::PMOVZXBQ(X64Reg dest, const OpArg& arg) { |
| 1840 | void XEmitter::PAVGW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE3, dest, arg);} | 2030 | WriteSSE41Op(0x66, 0x3832, dest, arg); |
| 1841 | 2031 | } | |
| 1842 | void XEmitter::PCMPEQB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x74, dest, arg);} | 2032 | void XEmitter::PMOVZXWD(X64Reg dest, const OpArg& arg) { |
| 1843 | void XEmitter::PCMPEQW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x75, dest, arg);} | 2033 | WriteSSE41Op(0x66, 0x3833, dest, arg); |
| 1844 | void XEmitter::PCMPEQD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x76, dest, arg);} | 2034 | } |
| 1845 | 2035 | void XEmitter::PMOVZXWQ(X64Reg dest, const OpArg& arg) { | |
| 1846 | void XEmitter::PCMPGTB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x64, dest, arg);} | 2036 | WriteSSE41Op(0x66, 0x3834, dest, arg); |
| 1847 | void XEmitter::PCMPGTW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x65, dest, arg);} | 2037 | } |
| 1848 | void XEmitter::PCMPGTD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x66, dest, arg);} | 2038 | void XEmitter::PMOVZXDQ(X64Reg dest, const OpArg& arg) { |
| 1849 | 2039 | WriteSSE41Op(0x66, 0x3835, dest, arg); | |
| 1850 | void XEmitter::PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSEOp(0x66, 0xC5, dest, arg, 1); Write8(subreg);} | 2040 | } |
| 1851 | void XEmitter::PINSRW(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSEOp(0x66, 0xC4, dest, arg, 1); Write8(subreg);} | 2041 | |
| 1852 | 2042 | void XEmitter::PBLENDVB(X64Reg dest, const OpArg& arg) { | |
| 1853 | void XEmitter::PMADDWD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF5, dest, arg); } | 2043 | WriteSSE41Op(0x66, 0x3810, dest, arg); |
| 1854 | void XEmitter::PSADBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF6, dest, arg);} | 2044 | } |
| 1855 | 2045 | void XEmitter::BLENDVPS(X64Reg dest, const OpArg& arg) { | |
| 1856 | void XEmitter::PMAXSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEE, dest, arg); } | 2046 | WriteSSE41Op(0x66, 0x3814, dest, arg); |
| 1857 | void XEmitter::PMAXUB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDE, dest, arg); } | 2047 | } |
| 1858 | void XEmitter::PMINSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEA, dest, arg); } | 2048 | void XEmitter::BLENDVPD(X64Reg dest, const OpArg& arg) { |
| 1859 | void XEmitter::PMINUB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDA, dest, arg); } | 2049 | WriteSSE41Op(0x66, 0x3815, dest, arg); |
| 1860 | 2050 | } | |
| 1861 | void XEmitter::PMOVMSKB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD7, dest, arg); } | 2051 | void XEmitter::BLENDPS(X64Reg dest, const OpArg& arg, u8 blend) { |
| 1862 | void XEmitter::PSHUFD(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0x66, 0x70, regOp, arg, 1); Write8(shuffle);} | 2052 | WriteSSE41Op(0x66, 0x3A0C, dest, arg, 1); |
| 1863 | void XEmitter::PSHUFLW(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0xF2, 0x70, regOp, arg, 1); Write8(shuffle);} | 2053 | Write8(blend); |
| 1864 | void XEmitter::PSHUFHW(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0xF3, 0x70, regOp, arg, 1); Write8(shuffle);} | 2054 | } |
| 2055 | void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) { | ||
| 2056 | WriteSSE41Op(0x66, 0x3A0D, dest, arg, 1); | ||
| 2057 | Write8(blend); | ||
| 2058 | } | ||
| 2059 | |||
| 2060 | void XEmitter::ROUNDSS(X64Reg dest, const OpArg& arg, u8 mode) { | ||
| 2061 | WriteSSE41Op(0x66, 0x3A0A, dest, arg, 1); | ||
| 2062 | Write8(mode); | ||
| 2063 | } | ||
| 2064 | void XEmitter::ROUNDSD(X64Reg dest, const OpArg& arg, u8 mode) { | ||
| 2065 | WriteSSE41Op(0x66, 0x3A0B, dest, arg, 1); | ||
| 2066 | Write8(mode); | ||
| 2067 | } | ||
| 2068 | void XEmitter::ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode) { | ||
| 2069 | WriteSSE41Op(0x66, 0x3A08, dest, arg, 1); | ||
| 2070 | Write8(mode); | ||
| 2071 | } | ||
| 2072 | void XEmitter::ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode) { | ||
| 2073 | WriteSSE41Op(0x66, 0x3A09, dest, arg, 1); | ||
| 2074 | Write8(mode); | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | void XEmitter::PAND(X64Reg dest, const OpArg& arg) { | ||
| 2078 | WriteSSEOp(0x66, 0xDB, dest, arg); | ||
| 2079 | } | ||
| 2080 | void XEmitter::PANDN(X64Reg dest, const OpArg& arg) { | ||
| 2081 | WriteSSEOp(0x66, 0xDF, dest, arg); | ||
| 2082 | } | ||
| 2083 | void XEmitter::PXOR(X64Reg dest, const OpArg& arg) { | ||
| 2084 | WriteSSEOp(0x66, 0xEF, dest, arg); | ||
| 2085 | } | ||
| 2086 | void XEmitter::POR(X64Reg dest, const OpArg& arg) { | ||
| 2087 | WriteSSEOp(0x66, 0xEB, dest, arg); | ||
| 2088 | } | ||
| 2089 | |||
| 2090 | void XEmitter::PADDB(X64Reg dest, const OpArg& arg) { | ||
| 2091 | WriteSSEOp(0x66, 0xFC, dest, arg); | ||
| 2092 | } | ||
| 2093 | void XEmitter::PADDW(X64Reg dest, const OpArg& arg) { | ||
| 2094 | WriteSSEOp(0x66, 0xFD, dest, arg); | ||
| 2095 | } | ||
| 2096 | void XEmitter::PADDD(X64Reg dest, const OpArg& arg) { | ||
| 2097 | WriteSSEOp(0x66, 0xFE, dest, arg); | ||
| 2098 | } | ||
| 2099 | void XEmitter::PADDQ(X64Reg dest, const OpArg& arg) { | ||
| 2100 | WriteSSEOp(0x66, 0xD4, dest, arg); | ||
| 2101 | } | ||
| 2102 | |||
| 2103 | void XEmitter::PADDSB(X64Reg dest, const OpArg& arg) { | ||
| 2104 | WriteSSEOp(0x66, 0xEC, dest, arg); | ||
| 2105 | } | ||
| 2106 | void XEmitter::PADDSW(X64Reg dest, const OpArg& arg) { | ||
| 2107 | WriteSSEOp(0x66, 0xED, dest, arg); | ||
| 2108 | } | ||
| 2109 | void XEmitter::PADDUSB(X64Reg dest, const OpArg& arg) { | ||
| 2110 | WriteSSEOp(0x66, 0xDC, dest, arg); | ||
| 2111 | } | ||
| 2112 | void XEmitter::PADDUSW(X64Reg dest, const OpArg& arg) { | ||
| 2113 | WriteSSEOp(0x66, 0xDD, dest, arg); | ||
| 2114 | } | ||
| 2115 | |||
| 2116 | void XEmitter::PSUBB(X64Reg dest, const OpArg& arg) { | ||
| 2117 | WriteSSEOp(0x66, 0xF8, dest, arg); | ||
| 2118 | } | ||
| 2119 | void XEmitter::PSUBW(X64Reg dest, const OpArg& arg) { | ||
| 2120 | WriteSSEOp(0x66, 0xF9, dest, arg); | ||
| 2121 | } | ||
| 2122 | void XEmitter::PSUBD(X64Reg dest, const OpArg& arg) { | ||
| 2123 | WriteSSEOp(0x66, 0xFA, dest, arg); | ||
| 2124 | } | ||
| 2125 | void XEmitter::PSUBQ(X64Reg dest, const OpArg& arg) { | ||
| 2126 | WriteSSEOp(0x66, 0xFB, dest, arg); | ||
| 2127 | } | ||
| 2128 | |||
| 2129 | void XEmitter::PSUBSB(X64Reg dest, const OpArg& arg) { | ||
| 2130 | WriteSSEOp(0x66, 0xE8, dest, arg); | ||
| 2131 | } | ||
| 2132 | void XEmitter::PSUBSW(X64Reg dest, const OpArg& arg) { | ||
| 2133 | WriteSSEOp(0x66, 0xE9, dest, arg); | ||
| 2134 | } | ||
| 2135 | void XEmitter::PSUBUSB(X64Reg dest, const OpArg& arg) { | ||
| 2136 | WriteSSEOp(0x66, 0xD8, dest, arg); | ||
| 2137 | } | ||
| 2138 | void XEmitter::PSUBUSW(X64Reg dest, const OpArg& arg) { | ||
| 2139 | WriteSSEOp(0x66, 0xD9, dest, arg); | ||
| 2140 | } | ||
| 2141 | |||
| 2142 | void XEmitter::PAVGB(X64Reg dest, const OpArg& arg) { | ||
| 2143 | WriteSSEOp(0x66, 0xE0, dest, arg); | ||
| 2144 | } | ||
| 2145 | void XEmitter::PAVGW(X64Reg dest, const OpArg& arg) { | ||
| 2146 | WriteSSEOp(0x66, 0xE3, dest, arg); | ||
| 2147 | } | ||
| 2148 | |||
| 2149 | void XEmitter::PCMPEQB(X64Reg dest, const OpArg& arg) { | ||
| 2150 | WriteSSEOp(0x66, 0x74, dest, arg); | ||
| 2151 | } | ||
| 2152 | void XEmitter::PCMPEQW(X64Reg dest, const OpArg& arg) { | ||
| 2153 | WriteSSEOp(0x66, 0x75, dest, arg); | ||
| 2154 | } | ||
| 2155 | void XEmitter::PCMPEQD(X64Reg dest, const OpArg& arg) { | ||
| 2156 | WriteSSEOp(0x66, 0x76, dest, arg); | ||
| 2157 | } | ||
| 2158 | |||
| 2159 | void XEmitter::PCMPGTB(X64Reg dest, const OpArg& arg) { | ||
| 2160 | WriteSSEOp(0x66, 0x64, dest, arg); | ||
| 2161 | } | ||
| 2162 | void XEmitter::PCMPGTW(X64Reg dest, const OpArg& arg) { | ||
| 2163 | WriteSSEOp(0x66, 0x65, dest, arg); | ||
| 2164 | } | ||
| 2165 | void XEmitter::PCMPGTD(X64Reg dest, const OpArg& arg) { | ||
| 2166 | WriteSSEOp(0x66, 0x66, dest, arg); | ||
| 2167 | } | ||
| 2168 | |||
| 2169 | void XEmitter::PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg) { | ||
| 2170 | WriteSSEOp(0x66, 0xC5, dest, arg, 1); | ||
| 2171 | Write8(subreg); | ||
| 2172 | } | ||
| 2173 | void XEmitter::PINSRW(X64Reg dest, const OpArg& arg, u8 subreg) { | ||
| 2174 | WriteSSEOp(0x66, 0xC4, dest, arg, 1); | ||
| 2175 | Write8(subreg); | ||
| 2176 | } | ||
| 2177 | |||
| 2178 | void XEmitter::PMADDWD(X64Reg dest, const OpArg& arg) { | ||
| 2179 | WriteSSEOp(0x66, 0xF5, dest, arg); | ||
| 2180 | } | ||
| 2181 | void XEmitter::PSADBW(X64Reg dest, const OpArg& arg) { | ||
| 2182 | WriteSSEOp(0x66, 0xF6, dest, arg); | ||
| 2183 | } | ||
| 2184 | |||
| 2185 | void XEmitter::PMAXSW(X64Reg dest, const OpArg& arg) { | ||
| 2186 | WriteSSEOp(0x66, 0xEE, dest, arg); | ||
| 2187 | } | ||
| 2188 | void XEmitter::PMAXUB(X64Reg dest, const OpArg& arg) { | ||
| 2189 | WriteSSEOp(0x66, 0xDE, dest, arg); | ||
| 2190 | } | ||
| 2191 | void XEmitter::PMINSW(X64Reg dest, const OpArg& arg) { | ||
| 2192 | WriteSSEOp(0x66, 0xEA, dest, arg); | ||
| 2193 | } | ||
| 2194 | void XEmitter::PMINUB(X64Reg dest, const OpArg& arg) { | ||
| 2195 | WriteSSEOp(0x66, 0xDA, dest, arg); | ||
| 2196 | } | ||
| 2197 | |||
| 2198 | void XEmitter::PMOVMSKB(X64Reg dest, const OpArg& arg) { | ||
| 2199 | WriteSSEOp(0x66, 0xD7, dest, arg); | ||
| 2200 | } | ||
| 2201 | void XEmitter::PSHUFD(X64Reg regOp, const OpArg& arg, u8 shuffle) { | ||
| 2202 | WriteSSEOp(0x66, 0x70, regOp, arg, 1); | ||
| 2203 | Write8(shuffle); | ||
| 2204 | } | ||
| 2205 | void XEmitter::PSHUFLW(X64Reg regOp, const OpArg& arg, u8 shuffle) { | ||
| 2206 | WriteSSEOp(0xF2, 0x70, regOp, arg, 1); | ||
| 2207 | Write8(shuffle); | ||
| 2208 | } | ||
| 2209 | void XEmitter::PSHUFHW(X64Reg regOp, const OpArg& arg, u8 shuffle) { | ||
| 2210 | WriteSSEOp(0xF3, 0x70, regOp, arg, 1); | ||
| 2211 | Write8(shuffle); | ||
| 2212 | } | ||
| 1865 | 2213 | ||
| 1866 | // VEX | 2214 | // VEX |
| 1867 | void XEmitter::VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseADD, regOp1, regOp2, arg);} | 2215 | void XEmitter::VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1868 | void XEmitter::VSUBSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseSUB, regOp1, regOp2, arg);} | 2216 | WriteAVXOp(0xF2, sseADD, regOp1, regOp2, arg); |
| 1869 | void XEmitter::VMULSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseMUL, regOp1, regOp2, arg);} | 2217 | } |
| 1870 | void XEmitter::VDIVSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseDIV, regOp1, regOp2, arg);} | 2218 | void XEmitter::VSUBSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1871 | void XEmitter::VADDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseADD, regOp1, regOp2, arg);} | 2219 | WriteAVXOp(0xF2, sseSUB, regOp1, regOp2, arg); |
| 1872 | void XEmitter::VSUBPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseSUB, regOp1, regOp2, arg);} | 2220 | } |
| 1873 | void XEmitter::VMULPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseMUL, regOp1, regOp2, arg);} | 2221 | void XEmitter::VMULSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1874 | void XEmitter::VDIVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseDIV, regOp1, regOp2, arg);} | 2222 | WriteAVXOp(0xF2, sseMUL, regOp1, regOp2, arg); |
| 1875 | void XEmitter::VSQRTSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseSQRT, regOp1, regOp2, arg);} | 2223 | } |
| 1876 | void XEmitter::VSHUFPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 shuffle) {WriteAVXOp(0x66, sseSHUF, regOp1, regOp2, arg, 1); Write8(shuffle);} | 2224 | void XEmitter::VDIVSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1877 | void XEmitter::VUNPCKLPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg){WriteAVXOp(0x66, 0x14, regOp1, regOp2, arg);} | 2225 | WriteAVXOp(0xF2, sseDIV, regOp1, regOp2, arg); |
| 1878 | void XEmitter::VUNPCKHPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg){WriteAVXOp(0x66, 0x15, regOp1, regOp2, arg);} | 2226 | } |
| 1879 | 2227 | void XEmitter::VADDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | |
| 1880 | void XEmitter::VANDPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseAND, regOp1, regOp2, arg); } | 2228 | WriteAVXOp(0x66, sseADD, regOp1, regOp2, arg); |
| 1881 | void XEmitter::VANDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseAND, regOp1, regOp2, arg); } | 2229 | } |
| 1882 | void XEmitter::VANDNPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseANDN, regOp1, regOp2, arg); } | 2230 | void XEmitter::VSUBPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1883 | void XEmitter::VANDNPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseANDN, regOp1, regOp2, arg); } | 2231 | WriteAVXOp(0x66, sseSUB, regOp1, regOp2, arg); |
| 1884 | void XEmitter::VORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseOR, regOp1, regOp2, arg); } | 2232 | } |
| 1885 | void XEmitter::VORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseOR, regOp1, regOp2, arg); } | 2233 | void XEmitter::VMULPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1886 | void XEmitter::VXORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseXOR, regOp1, regOp2, arg); } | 2234 | WriteAVXOp(0x66, sseMUL, regOp1, regOp2, arg); |
| 1887 | void XEmitter::VXORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseXOR, regOp1, regOp2, arg); } | 2235 | } |
| 1888 | 2236 | void XEmitter::VDIVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | |
| 1889 | void XEmitter::VPAND(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xDB, regOp1, regOp2, arg); } | 2237 | WriteAVXOp(0x66, sseDIV, regOp1, regOp2, arg); |
| 1890 | void XEmitter::VPANDN(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xDF, regOp1, regOp2, arg); } | 2238 | } |
| 1891 | void XEmitter::VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xEB, regOp1, regOp2, arg); } | 2239 | void XEmitter::VSQRTSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1892 | void XEmitter::VPXOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xEF, regOp1, regOp2, arg); } | 2240 | WriteAVXOp(0xF2, sseSQRT, regOp1, regOp2, arg); |
| 1893 | 2241 | } | |
| 1894 | void XEmitter::VFMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg); } | 2242 | void XEmitter::VSHUFPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 shuffle) { |
| 1895 | void XEmitter::VFMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg); } | 2243 | WriteAVXOp(0x66, sseSHUF, regOp1, regOp2, arg, 1); |
| 1896 | void XEmitter::VFMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg); } | 2244 | Write8(shuffle); |
| 1897 | void XEmitter::VFMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg, 1); } | 2245 | } |
| 1898 | void XEmitter::VFMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg, 1); } | 2246 | void XEmitter::VUNPCKLPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1899 | void XEmitter::VFMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg, 1); } | 2247 | WriteAVXOp(0x66, 0x14, regOp1, regOp2, arg); |
| 1900 | void XEmitter::VFMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg); } | 2248 | } |
| 1901 | void XEmitter::VFMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg); } | 2249 | void XEmitter::VUNPCKHPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1902 | void XEmitter::VFMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg); } | 2250 | WriteAVXOp(0x66, 0x15, regOp1, regOp2, arg); |
| 1903 | void XEmitter::VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg, 1); } | 2251 | } |
| 1904 | void XEmitter::VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg, 1); } | 2252 | |
| 1905 | void XEmitter::VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg, 1); } | 2253 | void XEmitter::VANDPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1906 | void XEmitter::VFMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg); } | 2254 | WriteAVXOp(0x00, sseAND, regOp1, regOp2, arg); |
| 1907 | void XEmitter::VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg); } | 2255 | } |
| 1908 | void XEmitter::VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg); } | 2256 | void XEmitter::VANDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1909 | void XEmitter::VFMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg, 1); } | 2257 | WriteAVXOp(0x66, sseAND, regOp1, regOp2, arg); |
| 1910 | void XEmitter::VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg, 1); } | 2258 | } |
| 1911 | void XEmitter::VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg, 1); } | 2259 | void XEmitter::VANDNPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1912 | void XEmitter::VFMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg); } | 2260 | WriteAVXOp(0x00, sseANDN, regOp1, regOp2, arg); |
| 1913 | void XEmitter::VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg); } | 2261 | } |
| 1914 | void XEmitter::VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg); } | 2262 | void XEmitter::VANDNPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1915 | void XEmitter::VFMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg, 1); } | 2263 | WriteAVXOp(0x66, sseANDN, regOp1, regOp2, arg); |
| 1916 | void XEmitter::VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg, 1); } | 2264 | } |
| 1917 | void XEmitter::VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg, 1); } | 2265 | void XEmitter::VORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1918 | void XEmitter::VFNMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg); } | 2266 | WriteAVXOp(0x00, sseOR, regOp1, regOp2, arg); |
| 1919 | void XEmitter::VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg); } | 2267 | } |
| 1920 | void XEmitter::VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg); } | 2268 | void XEmitter::VORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1921 | void XEmitter::VFNMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg, 1); } | 2269 | WriteAVXOp(0x66, sseOR, regOp1, regOp2, arg); |
| 1922 | void XEmitter::VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg, 1); } | 2270 | } |
| 1923 | void XEmitter::VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg, 1); } | 2271 | void XEmitter::VXORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1924 | void XEmitter::VFNMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg); } | 2272 | WriteAVXOp(0x00, sseXOR, regOp1, regOp2, arg); |
| 1925 | void XEmitter::VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg); } | 2273 | } |
| 1926 | void XEmitter::VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg); } | 2274 | void XEmitter::VXORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1927 | void XEmitter::VFNMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg, 1); } | 2275 | WriteAVXOp(0x66, sseXOR, regOp1, regOp2, arg); |
| 1928 | void XEmitter::VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg, 1); } | 2276 | } |
| 1929 | void XEmitter::VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg, 1); } | 2277 | |
| 1930 | void XEmitter::VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg); } | 2278 | void XEmitter::VPAND(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1931 | void XEmitter::VFNMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg); } | 2279 | WriteAVXOp(0x66, 0xDB, regOp1, regOp2, arg); |
| 1932 | void XEmitter::VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg); } | 2280 | } |
| 1933 | void XEmitter::VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg, 1); } | 2281 | void XEmitter::VPANDN(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1934 | void XEmitter::VFNMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg, 1); } | 2282 | WriteAVXOp(0x66, 0xDF, regOp1, regOp2, arg); |
| 1935 | void XEmitter::VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg, 1); } | 2283 | } |
| 1936 | void XEmitter::VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg); } | 2284 | void XEmitter::VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1937 | void XEmitter::VFNMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg); } | 2285 | WriteAVXOp(0x66, 0xEB, regOp1, regOp2, arg); |
| 1938 | void XEmitter::VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg); } | 2286 | } |
| 1939 | void XEmitter::VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg, 1); } | 2287 | void XEmitter::VPXOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1940 | void XEmitter::VFNMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg, 1); } | 2288 | WriteAVXOp(0x66, 0xEF, regOp1, regOp2, arg); |
| 1941 | void XEmitter::VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg, 1); } | 2289 | } |
| 1942 | void XEmitter::VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg); } | 2290 | |
| 1943 | void XEmitter::VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg); } | 2291 | void XEmitter::VFMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1944 | void XEmitter::VFMADDSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg); } | 2292 | WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg); |
| 1945 | void XEmitter::VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg, 1); } | 2293 | } |
| 1946 | void XEmitter::VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg, 1); } | 2294 | void XEmitter::VFMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1947 | void XEmitter::VFMADDSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg, 1); } | 2295 | WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg); |
| 1948 | void XEmitter::VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg); } | 2296 | } |
| 1949 | void XEmitter::VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg); } | 2297 | void XEmitter::VFMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1950 | void XEmitter::VFMSUBADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg); } | 2298 | WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg); |
| 1951 | void XEmitter::VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg, 1); } | 2299 | } |
| 1952 | void XEmitter::VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg, 1); } | 2300 | void XEmitter::VFMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1953 | void XEmitter::VFMSUBADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg, 1); } | 2301 | WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg, 1); |
| 1954 | 2302 | } | |
| 1955 | void XEmitter::SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0xF3, 0x38F7, regOp1, regOp2, arg);} | 2303 | void XEmitter::VFMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1956 | void XEmitter::SHLX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0x66, 0x38F7, regOp1, regOp2, arg);} | 2304 | WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg, 1); |
| 1957 | void XEmitter::SHRX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0xF2, 0x38F7, regOp1, regOp2, arg);} | 2305 | } |
| 1958 | void XEmitter::RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate) {WriteBMI2Op(bits, 0xF2, 0x3AF0, regOp, INVALID_REG, arg, 1); Write8(rotate);} | 2306 | void XEmitter::VFMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1959 | void XEmitter::PEXT(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI2Op(bits, 0xF3, 0x38F5, regOp1, regOp2, arg);} | 2307 | WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg, 1); |
| 1960 | void XEmitter::PDEP(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI2Op(bits, 0xF2, 0x38F5, regOp1, regOp2, arg);} | 2308 | } |
| 1961 | void XEmitter::MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI2Op(bits, 0xF2, 0x38F6, regOp2, regOp1, arg);} | 2309 | void XEmitter::VFMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1962 | void XEmitter::BZHI(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0x00, 0x38F5, regOp1, regOp2, arg);} | 2310 | WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg); |
| 1963 | void XEmitter::BLSR(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x1, regOp, arg);} | 2311 | } |
| 1964 | void XEmitter::BLSMSK(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x2, regOp, arg);} | 2312 | void XEmitter::VFMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 1965 | void XEmitter::BLSI(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x3, regOp, arg);} | 2313 | WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg); |
| 1966 | void XEmitter::BEXTR(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2){WriteBMI1Op(bits, 0x00, 0x38F7, regOp1, regOp2, arg);} | 2314 | } |
| 1967 | void XEmitter::ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F2, regOp1, regOp2, arg);} | 2315 | void XEmitter::VFMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 2316 | WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg); | ||
| 2317 | } | ||
| 2318 | void XEmitter::VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2319 | WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg, 1); | ||
| 2320 | } | ||
| 2321 | void XEmitter::VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2322 | WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg, 1); | ||
| 2323 | } | ||
| 2324 | void XEmitter::VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2325 | WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg, 1); | ||
| 2326 | } | ||
| 2327 | void XEmitter::VFMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2328 | WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg); | ||
| 2329 | } | ||
| 2330 | void XEmitter::VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2331 | WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg); | ||
| 2332 | } | ||
| 2333 | void XEmitter::VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2334 | WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg); | ||
| 2335 | } | ||
| 2336 | void XEmitter::VFMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2337 | WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg, 1); | ||
| 2338 | } | ||
| 2339 | void XEmitter::VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2340 | WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg, 1); | ||
| 2341 | } | ||
| 2342 | void XEmitter::VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2343 | WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg, 1); | ||
| 2344 | } | ||
| 2345 | void XEmitter::VFMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2346 | WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg); | ||
| 2347 | } | ||
| 2348 | void XEmitter::VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2349 | WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg); | ||
| 2350 | } | ||
| 2351 | void XEmitter::VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2352 | WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg); | ||
| 2353 | } | ||
| 2354 | void XEmitter::VFMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2355 | WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg, 1); | ||
| 2356 | } | ||
| 2357 | void XEmitter::VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2358 | WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg, 1); | ||
| 2359 | } | ||
| 2360 | void XEmitter::VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2361 | WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg, 1); | ||
| 2362 | } | ||
| 2363 | void XEmitter::VFNMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2364 | WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg); | ||
| 2365 | } | ||
| 2366 | void XEmitter::VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2367 | WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg); | ||
| 2368 | } | ||
| 2369 | void XEmitter::VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2370 | WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg); | ||
| 2371 | } | ||
| 2372 | void XEmitter::VFNMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2373 | WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg, 1); | ||
| 2374 | } | ||
| 2375 | void XEmitter::VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2376 | WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg, 1); | ||
| 2377 | } | ||
| 2378 | void XEmitter::VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2379 | WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg, 1); | ||
| 2380 | } | ||
| 2381 | void XEmitter::VFNMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2382 | WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg); | ||
| 2383 | } | ||
| 2384 | void XEmitter::VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2385 | WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg); | ||
| 2386 | } | ||
| 2387 | void XEmitter::VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2388 | WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg); | ||
| 2389 | } | ||
| 2390 | void XEmitter::VFNMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2391 | WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg, 1); | ||
| 2392 | } | ||
| 2393 | void XEmitter::VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2394 | WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg, 1); | ||
| 2395 | } | ||
| 2396 | void XEmitter::VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2397 | WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg, 1); | ||
| 2398 | } | ||
| 2399 | void XEmitter::VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2400 | WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg); | ||
| 2401 | } | ||
| 2402 | void XEmitter::VFNMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2403 | WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg); | ||
| 2404 | } | ||
| 2405 | void XEmitter::VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2406 | WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg); | ||
| 2407 | } | ||
| 2408 | void XEmitter::VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2409 | WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg, 1); | ||
| 2410 | } | ||
| 2411 | void XEmitter::VFNMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2412 | WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg, 1); | ||
| 2413 | } | ||
| 2414 | void XEmitter::VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2415 | WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg, 1); | ||
| 2416 | } | ||
| 2417 | void XEmitter::VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2418 | WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg); | ||
| 2419 | } | ||
| 2420 | void XEmitter::VFNMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2421 | WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg); | ||
| 2422 | } | ||
| 2423 | void XEmitter::VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2424 | WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg); | ||
| 2425 | } | ||
| 2426 | void XEmitter::VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2427 | WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg, 1); | ||
| 2428 | } | ||
| 2429 | void XEmitter::VFNMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2430 | WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg, 1); | ||
| 2431 | } | ||
| 2432 | void XEmitter::VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2433 | WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg, 1); | ||
| 2434 | } | ||
| 2435 | void XEmitter::VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2436 | WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg); | ||
| 2437 | } | ||
| 2438 | void XEmitter::VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2439 | WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg); | ||
| 2440 | } | ||
| 2441 | void XEmitter::VFMADDSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2442 | WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg); | ||
| 2443 | } | ||
| 2444 | void XEmitter::VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2445 | WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg, 1); | ||
| 2446 | } | ||
| 2447 | void XEmitter::VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2448 | WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg, 1); | ||
| 2449 | } | ||
| 2450 | void XEmitter::VFMADDSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2451 | WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg, 1); | ||
| 2452 | } | ||
| 2453 | void XEmitter::VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2454 | WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg); | ||
| 2455 | } | ||
| 2456 | void XEmitter::VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2457 | WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg); | ||
| 2458 | } | ||
| 2459 | void XEmitter::VFMSUBADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2460 | WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg); | ||
| 2461 | } | ||
| 2462 | void XEmitter::VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2463 | WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg, 1); | ||
| 2464 | } | ||
| 2465 | void XEmitter::VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2466 | WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg, 1); | ||
| 2467 | } | ||
| 2468 | void XEmitter::VFMSUBADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2469 | WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg, 1); | ||
| 2470 | } | ||
| 2471 | |||
| 2472 | void XEmitter::SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) { | ||
| 2473 | WriteBMI2Op(bits, 0xF3, 0x38F7, regOp1, regOp2, arg); | ||
| 2474 | } | ||
| 2475 | void XEmitter::SHLX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) { | ||
| 2476 | WriteBMI2Op(bits, 0x66, 0x38F7, regOp1, regOp2, arg); | ||
| 2477 | } | ||
| 2478 | void XEmitter::SHRX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) { | ||
| 2479 | WriteBMI2Op(bits, 0xF2, 0x38F7, regOp1, regOp2, arg); | ||
| 2480 | } | ||
| 2481 | void XEmitter::RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate) { | ||
| 2482 | WriteBMI2Op(bits, 0xF2, 0x3AF0, regOp, INVALID_REG, arg, 1); | ||
| 2483 | Write8(rotate); | ||
| 2484 | } | ||
| 2485 | void XEmitter::PEXT(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2486 | WriteBMI2Op(bits, 0xF3, 0x38F5, regOp1, regOp2, arg); | ||
| 2487 | } | ||
| 2488 | void XEmitter::PDEP(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2489 | WriteBMI2Op(bits, 0xF2, 0x38F5, regOp1, regOp2, arg); | ||
| 2490 | } | ||
| 2491 | void XEmitter::MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2492 | WriteBMI2Op(bits, 0xF2, 0x38F6, regOp2, regOp1, arg); | ||
| 2493 | } | ||
| 2494 | void XEmitter::BZHI(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) { | ||
| 2495 | WriteBMI2Op(bits, 0x00, 0x38F5, regOp1, regOp2, arg); | ||
| 2496 | } | ||
| 2497 | void XEmitter::BLSR(int bits, X64Reg regOp, const OpArg& arg) { | ||
| 2498 | WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x1, regOp, arg); | ||
| 2499 | } | ||
| 2500 | void XEmitter::BLSMSK(int bits, X64Reg regOp, const OpArg& arg) { | ||
| 2501 | WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x2, regOp, arg); | ||
| 2502 | } | ||
| 2503 | void XEmitter::BLSI(int bits, X64Reg regOp, const OpArg& arg) { | ||
| 2504 | WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x3, regOp, arg); | ||
| 2505 | } | ||
| 2506 | void XEmitter::BEXTR(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) { | ||
| 2507 | WriteBMI1Op(bits, 0x00, 0x38F7, regOp1, regOp2, arg); | ||
| 2508 | } | ||
| 2509 | void XEmitter::ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2510 | WriteBMI1Op(bits, 0x00, 0x38F2, regOp1, regOp2, arg); | ||
| 2511 | } | ||
| 1968 | 2512 | ||
| 1969 | // Prefixes | 2513 | // Prefixes |
| 1970 | 2514 | ||
| 1971 | void XEmitter::LOCK() { Write8(0xF0); } | 2515 | void XEmitter::LOCK() { |
| 1972 | void XEmitter::REP() { Write8(0xF3); } | 2516 | Write8(0xF0); |
| 1973 | void XEmitter::REPNE() { Write8(0xF2); } | 2517 | } |
| 1974 | void XEmitter::FSOverride() { Write8(0x64); } | 2518 | void XEmitter::REP() { |
| 1975 | void XEmitter::GSOverride() { Write8(0x65); } | 2519 | Write8(0xF3); |
| 2520 | } | ||
| 2521 | void XEmitter::REPNE() { | ||
| 2522 | Write8(0xF2); | ||
| 2523 | } | ||
| 2524 | void XEmitter::FSOverride() { | ||
| 2525 | Write8(0x64); | ||
| 2526 | } | ||
| 2527 | void XEmitter::GSOverride() { | ||
| 2528 | Write8(0x65); | ||
| 2529 | } | ||
| 1976 | 2530 | ||
| 1977 | void XEmitter::FWAIT() | 2531 | void XEmitter::FWAIT() { |
| 1978 | { | ||
| 1979 | Write8(0x9B); | 2532 | Write8(0x9B); |
| 1980 | } | 2533 | } |
| 1981 | 2534 | ||
| 1982 | // TODO: make this more generic | 2535 | // TODO: make this more generic |
| 1983 | void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg) | 2536 | void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg) { |
| 1984 | { | ||
| 1985 | int mf = 0; | 2537 | int mf = 0; |
| 1986 | ASSERT_MSG(!(bits == 80 && op_80b == floatINVALID), "WriteFloatLoadStore: 80 bits not supported for this instruction"); | 2538 | ASSERT_MSG(!(bits == 80 && op_80b == floatINVALID), |
| 1987 | switch (bits) | 2539 | "WriteFloatLoadStore: 80 bits not supported for this instruction"); |
| 1988 | { | 2540 | switch (bits) { |
| 1989 | case 32: mf = 0; break; | 2541 | case 32: |
| 1990 | case 64: mf = 4; break; | 2542 | mf = 0; |
| 1991 | case 80: mf = 2; break; | 2543 | break; |
| 1992 | default: ASSERT_MSG(0, "WriteFloatLoadStore: invalid bits (should be 32/64/80)"); | 2544 | case 64: |
| 2545 | mf = 4; | ||
| 2546 | break; | ||
| 2547 | case 80: | ||
| 2548 | mf = 2; | ||
| 2549 | break; | ||
| 2550 | default: | ||
| 2551 | ASSERT_MSG(0, "WriteFloatLoadStore: invalid bits (should be 32/64/80)"); | ||
| 1993 | } | 2552 | } |
| 1994 | Write8(0xd9 | mf); | 2553 | Write8(0xd9 | mf); |
| 1995 | // x87 instructions use the reg field of the ModR/M byte as opcode: | 2554 | // x87 instructions use the reg field of the ModR/M byte as opcode: |
| 1996 | if (bits == 80) | 2555 | if (bits == 80) |
| 1997 | op = op_80b; | 2556 | op = op_80b; |
| 1998 | arg.WriteRest(this, 0, (X64Reg) op); | 2557 | arg.WriteRest(this, 0, (X64Reg)op); |
| 1999 | } | 2558 | } |
| 2000 | 2559 | ||
| 2001 | void XEmitter::FLD(int bits, const OpArg& src) {WriteFloatLoadStore(bits, floatLD, floatLD80, src);} | 2560 | void XEmitter::FLD(int bits, const OpArg& src) { |
| 2002 | void XEmitter::FST(int bits, const OpArg& dest) {WriteFloatLoadStore(bits, floatST, floatINVALID, dest);} | 2561 | WriteFloatLoadStore(bits, floatLD, floatLD80, src); |
| 2003 | void XEmitter::FSTP(int bits, const OpArg& dest) {WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest);} | 2562 | } |
| 2004 | void XEmitter::FNSTSW_AX() { Write8(0xDF); Write8(0xE0); } | 2563 | void XEmitter::FST(int bits, const OpArg& dest) { |
| 2564 | WriteFloatLoadStore(bits, floatST, floatINVALID, dest); | ||
| 2565 | } | ||
| 2566 | void XEmitter::FSTP(int bits, const OpArg& dest) { | ||
| 2567 | WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest); | ||
| 2568 | } | ||
| 2569 | void XEmitter::FNSTSW_AX() { | ||
| 2570 | Write8(0xDF); | ||
| 2571 | Write8(0xE0); | ||
| 2572 | } | ||
| 2005 | 2573 | ||
| 2006 | void XEmitter::RDTSC() { Write8(0x0F); Write8(0x31); } | 2574 | void XEmitter::RDTSC() { |
| 2575 | Write8(0x0F); | ||
| 2576 | Write8(0x31); | ||
| 2577 | } | ||
| 2007 | 2578 | ||
| 2008 | void XCodeBlock::PoisonMemory() { | 2579 | void XCodeBlock::PoisonMemory() { |
| 2009 | // x86/64: 0xCC = breakpoint | 2580 | // x86/64: 0xCC = breakpoint |
| 2010 | memset(region, 0xCC, region_size); | 2581 | memset(region, 0xCC, region_size); |
| 2011 | } | 2582 | } |
| 2012 | |||
| 2013 | } | 2583 | } |
diff --git a/src/common/x64/emitter.h b/src/common/x64/emitter.h index 60a77dfe1..7d7cdde16 100644 --- a/src/common/x64/emitter.h +++ b/src/common/x64/emitter.h | |||
| @@ -18,11 +18,10 @@ | |||
| 18 | #pragma once | 18 | #pragma once |
| 19 | 19 | ||
| 20 | #include <cstddef> | 20 | #include <cstddef> |
| 21 | |||
| 22 | #include "common/assert.h" | 21 | #include "common/assert.h" |
| 23 | #include "common/bit_set.h" | 22 | #include "common/bit_set.h" |
| 24 | #include "common/common_types.h" | ||
| 25 | #include "common/code_block.h" | 23 | #include "common/code_block.h" |
| 24 | #include "common/common_types.h" | ||
| 26 | 25 | ||
| 27 | #if defined(ARCHITECTURE_x86_64) && !defined(_ARCH_64) | 26 | #if defined(ARCHITECTURE_x86_64) && !defined(_ARCH_64) |
| 28 | #define _ARCH_64 | 27 | #define _ARCH_64 |
| @@ -34,75 +33,145 @@ | |||
| 34 | #define PTRBITS 32 | 33 | #define PTRBITS 32 |
| 35 | #endif | 34 | #endif |
| 36 | 35 | ||
| 37 | namespace Gen | 36 | namespace Gen { |
| 38 | { | 37 | |
| 39 | 38 | enum X64Reg { | |
| 40 | enum X64Reg | 39 | EAX = 0, |
| 41 | { | 40 | EBX = 3, |
| 42 | EAX = 0, EBX = 3, ECX = 1, EDX = 2, | 41 | ECX = 1, |
| 43 | ESI = 6, EDI = 7, EBP = 5, ESP = 4, | 42 | EDX = 2, |
| 44 | 43 | ESI = 6, | |
| 45 | RAX = 0, RBX = 3, RCX = 1, RDX = 2, | 44 | EDI = 7, |
| 46 | RSI = 6, RDI = 7, RBP = 5, RSP = 4, | 45 | EBP = 5, |
| 47 | R8 = 8, R9 = 9, R10 = 10,R11 = 11, | 46 | ESP = 4, |
| 48 | R12 = 12,R13 = 13,R14 = 14,R15 = 15, | 47 | |
| 49 | 48 | RAX = 0, | |
| 50 | AL = 0, BL = 3, CL = 1, DL = 2, | 49 | RBX = 3, |
| 51 | SIL = 6, DIL = 7, BPL = 5, SPL = 4, | 50 | RCX = 1, |
| 52 | AH = 0x104, BH = 0x107, CH = 0x105, DH = 0x106, | 51 | RDX = 2, |
| 53 | 52 | RSI = 6, | |
| 54 | AX = 0, BX = 3, CX = 1, DX = 2, | 53 | RDI = 7, |
| 55 | SI = 6, DI = 7, BP = 5, SP = 4, | 54 | RBP = 5, |
| 56 | 55 | RSP = 4, | |
| 57 | XMM0=0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, | 56 | R8 = 8, |
| 58 | XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, | 57 | R9 = 9, |
| 59 | 58 | R10 = 10, | |
| 60 | YMM0=0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7, | 59 | R11 = 11, |
| 61 | YMM8, YMM9, YMM10, YMM11, YMM12, YMM13, YMM14, YMM15, | 60 | R12 = 12, |
| 61 | R13 = 13, | ||
| 62 | R14 = 14, | ||
| 63 | R15 = 15, | ||
| 64 | |||
| 65 | AL = 0, | ||
| 66 | BL = 3, | ||
| 67 | CL = 1, | ||
| 68 | DL = 2, | ||
| 69 | SIL = 6, | ||
| 70 | DIL = 7, | ||
| 71 | BPL = 5, | ||
| 72 | SPL = 4, | ||
| 73 | AH = 0x104, | ||
| 74 | BH = 0x107, | ||
| 75 | CH = 0x105, | ||
| 76 | DH = 0x106, | ||
| 77 | |||
| 78 | AX = 0, | ||
| 79 | BX = 3, | ||
| 80 | CX = 1, | ||
| 81 | DX = 2, | ||
| 82 | SI = 6, | ||
| 83 | DI = 7, | ||
| 84 | BP = 5, | ||
| 85 | SP = 4, | ||
| 86 | |||
| 87 | XMM0 = 0, | ||
| 88 | XMM1, | ||
| 89 | XMM2, | ||
| 90 | XMM3, | ||
| 91 | XMM4, | ||
| 92 | XMM5, | ||
| 93 | XMM6, | ||
| 94 | XMM7, | ||
| 95 | XMM8, | ||
| 96 | XMM9, | ||
| 97 | XMM10, | ||
| 98 | XMM11, | ||
| 99 | XMM12, | ||
| 100 | XMM13, | ||
| 101 | XMM14, | ||
| 102 | XMM15, | ||
| 103 | |||
| 104 | YMM0 = 0, | ||
| 105 | YMM1, | ||
| 106 | YMM2, | ||
| 107 | YMM3, | ||
| 108 | YMM4, | ||
| 109 | YMM5, | ||
| 110 | YMM6, | ||
| 111 | YMM7, | ||
| 112 | YMM8, | ||
| 113 | YMM9, | ||
| 114 | YMM10, | ||
| 115 | YMM11, | ||
| 116 | YMM12, | ||
| 117 | YMM13, | ||
| 118 | YMM14, | ||
| 119 | YMM15, | ||
| 62 | 120 | ||
| 63 | INVALID_REG = 0xFFFFFFFF | 121 | INVALID_REG = 0xFFFFFFFF |
| 64 | }; | 122 | }; |
| 65 | 123 | ||
| 66 | enum CCFlags | 124 | enum CCFlags { |
| 67 | { | 125 | CC_O = 0, |
| 68 | CC_O = 0, | 126 | CC_NO = 1, |
| 69 | CC_NO = 1, | 127 | CC_B = 2, |
| 70 | CC_B = 2, CC_C = 2, CC_NAE = 2, | 128 | CC_C = 2, |
| 71 | CC_NB = 3, CC_NC = 3, CC_AE = 3, | 129 | CC_NAE = 2, |
| 72 | CC_Z = 4, CC_E = 4, | 130 | CC_NB = 3, |
| 73 | CC_NZ = 5, CC_NE = 5, | 131 | CC_NC = 3, |
| 74 | CC_BE = 6, CC_NA = 6, | 132 | CC_AE = 3, |
| 75 | CC_NBE = 7, CC_A = 7, | 133 | CC_Z = 4, |
| 76 | CC_S = 8, | 134 | CC_E = 4, |
| 77 | CC_NS = 9, | 135 | CC_NZ = 5, |
| 78 | CC_P = 0xA, CC_PE = 0xA, | 136 | CC_NE = 5, |
| 79 | CC_NP = 0xB, CC_PO = 0xB, | 137 | CC_BE = 6, |
| 80 | CC_L = 0xC, CC_NGE = 0xC, | 138 | CC_NA = 6, |
| 81 | CC_NL = 0xD, CC_GE = 0xD, | 139 | CC_NBE = 7, |
| 82 | CC_LE = 0xE, CC_NG = 0xE, | 140 | CC_A = 7, |
| 83 | CC_NLE = 0xF, CC_G = 0xF | 141 | CC_S = 8, |
| 142 | CC_NS = 9, | ||
| 143 | CC_P = 0xA, | ||
| 144 | CC_PE = 0xA, | ||
| 145 | CC_NP = 0xB, | ||
| 146 | CC_PO = 0xB, | ||
| 147 | CC_L = 0xC, | ||
| 148 | CC_NGE = 0xC, | ||
| 149 | CC_NL = 0xD, | ||
| 150 | CC_GE = 0xD, | ||
| 151 | CC_LE = 0xE, | ||
| 152 | CC_NG = 0xE, | ||
| 153 | CC_NLE = 0xF, | ||
| 154 | CC_G = 0xF | ||
| 84 | }; | 155 | }; |
| 85 | 156 | ||
| 86 | enum | 157 | enum { |
| 87 | { | ||
| 88 | NUMGPRs = 16, | 158 | NUMGPRs = 16, |
| 89 | NUMXMMs = 16, | 159 | NUMXMMs = 16, |
| 90 | }; | 160 | }; |
| 91 | 161 | ||
| 92 | enum | 162 | enum { |
| 93 | { | ||
| 94 | SCALE_NONE = 0, | 163 | SCALE_NONE = 0, |
| 95 | SCALE_1 = 1, | 164 | SCALE_1 = 1, |
| 96 | SCALE_2 = 2, | 165 | SCALE_2 = 2, |
| 97 | SCALE_4 = 4, | 166 | SCALE_4 = 4, |
| 98 | SCALE_8 = 8, | 167 | SCALE_8 = 8, |
| 99 | SCALE_ATREG = 16, | 168 | SCALE_ATREG = 16, |
| 100 | //SCALE_NOBASE_1 is not supported and can be replaced with SCALE_ATREG | 169 | // SCALE_NOBASE_1 is not supported and can be replaced with SCALE_ATREG |
| 101 | SCALE_NOBASE_2 = 34, | 170 | SCALE_NOBASE_2 = 34, |
| 102 | SCALE_NOBASE_4 = 36, | 171 | SCALE_NOBASE_4 = 36, |
| 103 | SCALE_NOBASE_8 = 40, | 172 | SCALE_NOBASE_8 = 40, |
| 104 | SCALE_RIP = 0xFF, | 173 | SCALE_RIP = 0xFF, |
| 105 | SCALE_IMM8 = 0xF0, | 174 | SCALE_IMM8 = 0xF0, |
| 106 | SCALE_IMM16 = 0xF1, | 175 | SCALE_IMM16 = 0xF1, |
| 107 | SCALE_IMM32 = 0xF2, | 176 | SCALE_IMM32 = 0xF2, |
| 108 | SCALE_IMM64 = 0xF3, | 177 | SCALE_IMM64 = 0xF3, |
| @@ -114,7 +183,7 @@ enum NormalOp { | |||
| 114 | nrmSUB, | 183 | nrmSUB, |
| 115 | nrmSBB, | 184 | nrmSBB, |
| 116 | nrmAND, | 185 | nrmAND, |
| 117 | nrmOR , | 186 | nrmOR, |
| 118 | nrmXOR, | 187 | nrmXOR, |
| 119 | nrmMOV, | 188 | nrmMOV, |
| 120 | nrmTEST, | 189 | nrmTEST, |
| @@ -157,68 +226,73 @@ enum FloatRound { | |||
| 157 | class XEmitter; | 226 | class XEmitter; |
| 158 | 227 | ||
| 159 | // RIP addressing does not benefit from micro op fusion on Core arch | 228 | // RIP addressing does not benefit from micro op fusion on Core arch |
| 160 | struct OpArg | 229 | struct OpArg { |
| 161 | { | ||
| 162 | friend class XEmitter; | 230 | friend class XEmitter; |
| 163 | 231 | ||
| 164 | constexpr OpArg() = default; // dummy op arg, used for storage | 232 | constexpr OpArg() = default; // dummy op arg, used for storage |
| 165 | constexpr OpArg(u64 offset_, int scale_, X64Reg rmReg = RAX, X64Reg scaledReg = RAX) | 233 | constexpr OpArg(u64 offset_, int scale_, X64Reg rmReg = RAX, X64Reg scaledReg = RAX) |
| 166 | : scale(static_cast<u8>(scale_)) | 234 | : scale(static_cast<u8>(scale_)), offsetOrBaseReg(static_cast<u16>(rmReg)), |
| 167 | , offsetOrBaseReg(static_cast<u16>(rmReg)) | 235 | indexReg(static_cast<u16>(scaledReg)), offset(offset_) {} |
| 168 | , indexReg(static_cast<u16>(scaledReg)) | ||
| 169 | , offset(offset_) | ||
| 170 | { | ||
| 171 | } | ||
| 172 | 236 | ||
| 173 | constexpr bool operator==(const OpArg &b) const | 237 | constexpr bool operator==(const OpArg& b) const { |
| 174 | { | 238 | return operandReg == b.operandReg && scale == b.scale && |
| 175 | return operandReg == b.operandReg && | 239 | offsetOrBaseReg == b.offsetOrBaseReg && indexReg == b.indexReg && offset == b.offset; |
| 176 | scale == b.scale && | ||
| 177 | offsetOrBaseReg == b.offsetOrBaseReg && | ||
| 178 | indexReg == b.indexReg && | ||
| 179 | offset == b.offset; | ||
| 180 | } | 240 | } |
| 181 | 241 | ||
| 182 | void WriteRex(XEmitter *emit, int opBits, int bits, int customOp = -1) const; | 242 | void WriteRex(XEmitter* emit, int opBits, int bits, int customOp = -1) const; |
| 183 | void WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, int W = 0) const; | 243 | void WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, |
| 184 | void WriteRest(XEmitter *emit, int extraBytes=0, X64Reg operandReg=INVALID_REG, bool warn_64bit_offset = true) const; | 244 | int W = 0) const; |
| 185 | void WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg operandReg, int bits); | 245 | void WriteRest(XEmitter* emit, int extraBytes = 0, X64Reg operandReg = INVALID_REG, |
| 186 | void WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &operand, int bits) const; | 246 | bool warn_64bit_offset = true) const; |
| 187 | 247 | void WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg operandReg, int bits); | |
| 188 | constexpr bool IsImm() const { return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 || scale == SCALE_IMM64; } | 248 | void WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, |
| 189 | constexpr bool IsSimpleReg() const { return scale == SCALE_NONE; } | 249 | int bits) const; |
| 190 | constexpr bool IsSimpleReg(X64Reg reg) const | 250 | |
| 191 | { | 251 | constexpr bool IsImm() const { |
| 252 | return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 || | ||
| 253 | scale == SCALE_IMM64; | ||
| 254 | } | ||
| 255 | constexpr bool IsSimpleReg() const { | ||
| 256 | return scale == SCALE_NONE; | ||
| 257 | } | ||
| 258 | constexpr bool IsSimpleReg(X64Reg reg) const { | ||
| 192 | return IsSimpleReg() && GetSimpleReg() == reg; | 259 | return IsSimpleReg() && GetSimpleReg() == reg; |
| 193 | } | 260 | } |
| 194 | 261 | ||
| 195 | int GetImmBits() const | 262 | int GetImmBits() const { |
| 196 | { | 263 | switch (scale) { |
| 197 | switch (scale) | 264 | case SCALE_IMM8: |
| 198 | { | 265 | return 8; |
| 199 | case SCALE_IMM8: return 8; | 266 | case SCALE_IMM16: |
| 200 | case SCALE_IMM16: return 16; | 267 | return 16; |
| 201 | case SCALE_IMM32: return 32; | 268 | case SCALE_IMM32: |
| 202 | case SCALE_IMM64: return 64; | 269 | return 32; |
| 203 | default: return -1; | 270 | case SCALE_IMM64: |
| 271 | return 64; | ||
| 272 | default: | ||
| 273 | return -1; | ||
| 204 | } | 274 | } |
| 205 | } | 275 | } |
| 206 | 276 | ||
| 207 | void SetImmBits(int bits) { | 277 | void SetImmBits(int bits) { |
| 208 | switch (bits) | 278 | switch (bits) { |
| 209 | { | 279 | case 8: |
| 210 | case 8: scale = SCALE_IMM8; break; | 280 | scale = SCALE_IMM8; |
| 211 | case 16: scale = SCALE_IMM16; break; | 281 | break; |
| 212 | case 32: scale = SCALE_IMM32; break; | 282 | case 16: |
| 213 | case 64: scale = SCALE_IMM64; break; | 283 | scale = SCALE_IMM16; |
| 284 | break; | ||
| 285 | case 32: | ||
| 286 | scale = SCALE_IMM32; | ||
| 287 | break; | ||
| 288 | case 64: | ||
| 289 | scale = SCALE_IMM64; | ||
| 290 | break; | ||
| 214 | } | 291 | } |
| 215 | } | 292 | } |
| 216 | 293 | ||
| 217 | constexpr X64Reg GetSimpleReg() const | 294 | constexpr X64Reg GetSimpleReg() const { |
| 218 | { | 295 | return scale == SCALE_NONE ? static_cast<X64Reg>(offsetOrBaseReg) : INVALID_REG; |
| 219 | return scale == SCALE_NONE | ||
| 220 | ? static_cast<X64Reg>(offsetOrBaseReg) | ||
| 221 | : INVALID_REG; | ||
| 222 | } | 296 | } |
| 223 | 297 | ||
| 224 | constexpr u32 GetImmValue() const { | 298 | constexpr u32 GetImmValue() const { |
| @@ -234,41 +308,50 @@ private: | |||
| 234 | u8 scale = 0; | 308 | u8 scale = 0; |
| 235 | u16 offsetOrBaseReg = 0; | 309 | u16 offsetOrBaseReg = 0; |
| 236 | u16 indexReg = 0; | 310 | u16 indexReg = 0; |
| 237 | u64 offset = 0; // use RIP-relative as much as possible - 64-bit immediates are not available. | 311 | u64 offset = 0; // use RIP-relative as much as possible - 64-bit immediates are not available. |
| 238 | u16 operandReg = 0; | 312 | u16 operandReg = 0; |
| 239 | }; | 313 | }; |
| 240 | 314 | ||
| 241 | template <typename T> | 315 | template <typename T> |
| 242 | inline OpArg M(const T *ptr) { return OpArg(reinterpret_cast<u64>(ptr), static_cast<int>(SCALE_RIP)); } | 316 | inline OpArg M(const T* ptr) { |
| 243 | constexpr OpArg R(X64Reg value) { return OpArg(0, SCALE_NONE, value); } | 317 | return OpArg(reinterpret_cast<u64>(ptr), static_cast<int>(SCALE_RIP)); |
| 244 | constexpr OpArg MatR(X64Reg value) { return OpArg(0, SCALE_ATREG, value); } | 318 | } |
| 319 | constexpr OpArg R(X64Reg value) { | ||
| 320 | return OpArg(0, SCALE_NONE, value); | ||
| 321 | } | ||
| 322 | constexpr OpArg MatR(X64Reg value) { | ||
| 323 | return OpArg(0, SCALE_ATREG, value); | ||
| 324 | } | ||
| 245 | 325 | ||
| 246 | constexpr OpArg MDisp(X64Reg value, int offset) | 326 | constexpr OpArg MDisp(X64Reg value, int offset) { |
| 247 | { | ||
| 248 | return OpArg(static_cast<u32>(offset), SCALE_ATREG, value); | 327 | return OpArg(static_cast<u32>(offset), SCALE_ATREG, value); |
| 249 | } | 328 | } |
| 250 | 329 | ||
| 251 | constexpr OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset) | 330 | constexpr OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset) { |
| 252 | { | ||
| 253 | return OpArg(offset, scale, base, scaled); | 331 | return OpArg(offset, scale, base, scaled); |
| 254 | } | 332 | } |
| 255 | 333 | ||
| 256 | constexpr OpArg MScaled(X64Reg scaled, int scale, int offset) | 334 | constexpr OpArg MScaled(X64Reg scaled, int scale, int offset) { |
| 257 | { | 335 | return scale == SCALE_1 ? OpArg(offset, SCALE_ATREG, scaled) |
| 258 | return scale == SCALE_1 | 336 | : OpArg(offset, scale | 0x20, RAX, scaled); |
| 259 | ? OpArg(offset, SCALE_ATREG, scaled) | ||
| 260 | : OpArg(offset, scale | 0x20, RAX, scaled); | ||
| 261 | } | 337 | } |
| 262 | 338 | ||
| 263 | constexpr OpArg MRegSum(X64Reg base, X64Reg offset) | 339 | constexpr OpArg MRegSum(X64Reg base, X64Reg offset) { |
| 264 | { | ||
| 265 | return MComplex(base, offset, 1, 0); | 340 | return MComplex(base, offset, 1, 0); |
| 266 | } | 341 | } |
| 267 | 342 | ||
| 268 | constexpr OpArg Imm8 (u8 imm) { return OpArg(imm, SCALE_IMM8); } | 343 | constexpr OpArg Imm8(u8 imm) { |
| 269 | constexpr OpArg Imm16(u16 imm) { return OpArg(imm, SCALE_IMM16); } //rarely used | 344 | return OpArg(imm, SCALE_IMM8); |
| 270 | constexpr OpArg Imm32(u32 imm) { return OpArg(imm, SCALE_IMM32); } | 345 | } |
| 271 | constexpr OpArg Imm64(u64 imm) { return OpArg(imm, SCALE_IMM64); } | 346 | constexpr OpArg Imm16(u16 imm) { |
| 347 | return OpArg(imm, SCALE_IMM16); | ||
| 348 | } // rarely used | ||
| 349 | constexpr OpArg Imm32(u32 imm) { | ||
| 350 | return OpArg(imm, SCALE_IMM32); | ||
| 351 | } | ||
| 352 | constexpr OpArg Imm64(u64 imm) { | ||
| 353 | return OpArg(imm, SCALE_IMM64); | ||
| 354 | } | ||
| 272 | constexpr OpArg UImmAuto(u32 imm) { | 355 | constexpr OpArg UImmAuto(u32 imm) { |
| 273 | return OpArg(imm, imm >= 128 ? SCALE_IMM32 : SCALE_IMM8); | 356 | return OpArg(imm, imm >= 128 ? SCALE_IMM32 : SCALE_IMM8); |
| 274 | } | 357 | } |
| @@ -277,8 +360,7 @@ constexpr OpArg SImmAuto(s32 imm) { | |||
| 277 | } | 360 | } |
| 278 | 361 | ||
| 279 | template <typename T> | 362 | template <typename T> |
| 280 | OpArg ImmPtr(const T* imm) | 363 | OpArg ImmPtr(const T* imm) { |
| 281 | { | ||
| 282 | #ifdef _ARCH_64 | 364 | #ifdef _ARCH_64 |
| 283 | return Imm64(reinterpret_cast<u64>(imm)); | 365 | return Imm64(reinterpret_cast<u64>(imm)); |
| 284 | #else | 366 | #else |
| @@ -286,36 +368,31 @@ OpArg ImmPtr(const T* imm) | |||
| 286 | #endif | 368 | #endif |
| 287 | } | 369 | } |
| 288 | 370 | ||
| 289 | inline u32 PtrOffset(const void* ptr, const void* base) | 371 | inline u32 PtrOffset(const void* ptr, const void* base) { |
| 290 | { | ||
| 291 | #ifdef _ARCH_64 | 372 | #ifdef _ARCH_64 |
| 292 | s64 distance = (s64)ptr-(s64)base; | 373 | s64 distance = (s64)ptr - (s64)base; |
| 293 | if (distance >= 0x80000000LL || | 374 | if (distance >= 0x80000000LL || distance < -0x80000000LL) { |
| 294 | distance < -0x80000000LL) | ||
| 295 | { | ||
| 296 | ASSERT_MSG(0, "pointer offset out of range"); | 375 | ASSERT_MSG(0, "pointer offset out of range"); |
| 297 | return 0; | 376 | return 0; |
| 298 | } | 377 | } |
| 299 | 378 | ||
| 300 | return (u32)distance; | 379 | return (u32)distance; |
| 301 | #else | 380 | #else |
| 302 | return (u32)ptr-(u32)base; | 381 | return (u32)ptr - (u32)base; |
| 303 | #endif | 382 | #endif |
| 304 | } | 383 | } |
| 305 | 384 | ||
| 306 | //usage: int a[]; ARRAY_OFFSET(a,10) | 385 | // usage: int a[]; ARRAY_OFFSET(a,10) |
| 307 | #define ARRAY_OFFSET(array,index) ((u32)((u64)&(array)[index]-(u64)&(array)[0])) | 386 | #define ARRAY_OFFSET(array, index) ((u32)((u64) & (array)[index] - (u64) & (array)[0])) |
| 308 | //usage: struct {int e;} s; STRUCT_OFFSET(s,e) | 387 | // usage: struct {int e;} s; STRUCT_OFFSET(s,e) |
| 309 | #define STRUCT_OFFSET(str,elem) ((u32)((u64)&(str).elem-(u64)&(str))) | 388 | #define STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str))) |
| 310 | 389 | ||
| 311 | struct FixupBranch | 390 | struct FixupBranch { |
| 312 | { | 391 | u8* ptr; |
| 313 | u8 *ptr; | 392 | int type; // 0 = 8bit 1 = 32bit |
| 314 | int type; //0 = 8bit 1 = 32bit | ||
| 315 | }; | 393 | }; |
| 316 | 394 | ||
| 317 | enum SSECompare | 395 | enum SSECompare { |
| 318 | { | ||
| 319 | EQ = 0, | 396 | EQ = 0, |
| 320 | LT, | 397 | LT, |
| 321 | LE, | 398 | LE, |
| @@ -326,11 +403,10 @@ enum SSECompare | |||
| 326 | ORD, | 403 | ORD, |
| 327 | }; | 404 | }; |
| 328 | 405 | ||
| 329 | class XEmitter | 406 | class XEmitter { |
| 330 | { | 407 | friend struct OpArg; // for Write8 etc |
| 331 | friend struct OpArg; // for Write8 etc | ||
| 332 | private: | 408 | private: |
| 333 | u8 *code; | 409 | u8* code; |
| 334 | bool flags_locked; | 410 | bool flags_locked; |
| 335 | 411 | ||
| 336 | void CheckFlags(); | 412 | void CheckFlags(); |
| @@ -347,14 +423,19 @@ private: | |||
| 347 | void WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); | 423 | void WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); |
| 348 | void WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); | 424 | void WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); |
| 349 | void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); | 425 | void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); |
| 350 | void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); | 426 | void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, |
| 351 | void WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); | 427 | int extrabytes = 0); |
| 352 | void WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); | 428 | void WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, |
| 353 | void WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); | 429 | int extrabytes = 0); |
| 430 | void WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, | ||
| 431 | int extrabytes = 0); | ||
| 432 | void WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, | ||
| 433 | int extrabytes = 0); | ||
| 354 | void WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg); | 434 | void WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg); |
| 355 | void WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2); | 435 | void WriteNormalOp(XEmitter* emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2); |
| 356 | 436 | ||
| 357 | void ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp); | 437 | void ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, |
| 438 | size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp); | ||
| 358 | 439 | ||
| 359 | protected: | 440 | protected: |
| 360 | void Write8(u8 value); | 441 | void Write8(u8 value); |
| @@ -363,26 +444,37 @@ protected: | |||
| 363 | void Write64(u64 value); | 444 | void Write64(u64 value); |
| 364 | 445 | ||
| 365 | public: | 446 | public: |
| 366 | XEmitter() { code = nullptr; flags_locked = false; } | 447 | XEmitter() { |
| 367 | XEmitter(u8 *code_ptr) { code = code_ptr; flags_locked = false; } | 448 | code = nullptr; |
| 449 | flags_locked = false; | ||
| 450 | } | ||
| 451 | XEmitter(u8* code_ptr) { | ||
| 452 | code = code_ptr; | ||
| 453 | flags_locked = false; | ||
| 454 | } | ||
| 368 | virtual ~XEmitter() {} | 455 | virtual ~XEmitter() {} |
| 369 | 456 | ||
| 370 | void WriteModRM(int mod, int rm, int reg); | 457 | void WriteModRM(int mod, int rm, int reg); |
| 371 | void WriteSIB(int scale, int index, int base); | 458 | void WriteSIB(int scale, int index, int base); |
| 372 | 459 | ||
| 373 | void SetCodePtr(u8 *ptr); | 460 | void SetCodePtr(u8* ptr); |
| 374 | void ReserveCodeSpace(int bytes); | 461 | void ReserveCodeSpace(int bytes); |
| 375 | const u8 *AlignCode4(); | 462 | const u8* AlignCode4(); |
| 376 | const u8 *AlignCode16(); | 463 | const u8* AlignCode16(); |
| 377 | const u8 *AlignCodePage(); | 464 | const u8* AlignCodePage(); |
| 378 | const u8 *GetCodePtr() const; | 465 | const u8* GetCodePtr() const; |
| 379 | u8 *GetWritableCodePtr(); | 466 | u8* GetWritableCodePtr(); |
| 380 | 467 | ||
| 381 | void LockFlags() { flags_locked = true; } | 468 | void LockFlags() { |
| 382 | void UnlockFlags() { flags_locked = false; } | 469 | flags_locked = true; |
| 470 | } | ||
| 471 | void UnlockFlags() { | ||
| 472 | flags_locked = false; | ||
| 473 | } | ||
| 383 | 474 | ||
| 384 | // Looking for one of these? It's BANNED!! Some instructions are slow on modern CPU | 475 | // Looking for one of these? It's BANNED!! Some instructions are slow on modern CPU |
| 385 | // INC, DEC, LOOP, LOOPNE, LOOPE, ENTER, LEAVE, XCHG, XLAT, REP MOVSB/MOVSD, REP SCASD + other string instr., | 476 | // INC, DEC, LOOP, LOOPNE, LOOPE, ENTER, LEAVE, XCHG, XLAT, REP MOVSB/MOVSD, REP SCASD + other |
| 477 | // string instr., | ||
| 386 | // INC and DEC are slow on Intel Core, but not on AMD. They create a | 478 | // INC and DEC are slow on Intel Core, but not on AMD. They create a |
| 387 | // false flag dependency because they only update a subset of the flags. | 479 | // false flag dependency because they only update a subset of the flags. |
| 388 | // XCHG is SLOW and should be avoided. | 480 | // XCHG is SLOW and should be avoided. |
| @@ -401,11 +493,11 @@ public: | |||
| 401 | void CLC(); | 493 | void CLC(); |
| 402 | void CMC(); | 494 | void CMC(); |
| 403 | 495 | ||
| 404 | // These two can not be executed in 64-bit mode on early Intel 64-bit CPU:s, only on Core2 and AMD! | 496 | // These two can not be executed in 64-bit mode on early Intel 64-bit CPU:s, only on Core2 and |
| 497 | // AMD! | ||
| 405 | void LAHF(); // 3 cycle vector path | 498 | void LAHF(); // 3 cycle vector path |
| 406 | void SAHF(); // direct path fast | 499 | void SAHF(); // direct path fast |
| 407 | 500 | ||
| 408 | |||
| 409 | // Stack control | 501 | // Stack control |
| 410 | void PUSH(X64Reg reg); | 502 | void PUSH(X64Reg reg); |
| 411 | void POP(X64Reg reg); | 503 | void POP(X64Reg reg); |
| @@ -422,7 +514,7 @@ public: | |||
| 422 | 514 | ||
| 423 | void JMP(const u8* addr, bool force5Bytes = false); | 515 | void JMP(const u8* addr, bool force5Bytes = false); |
| 424 | void JMPptr(const OpArg& arg); | 516 | void JMPptr(const OpArg& arg); |
| 425 | void JMPself(); //infinite loop! | 517 | void JMPself(); // infinite loop! |
| 426 | #ifdef CALL | 518 | #ifdef CALL |
| 427 | #undef CALL | 519 | #undef CALL |
| 428 | #endif | 520 | #endif |
| @@ -450,12 +542,11 @@ public: | |||
| 450 | void BSR(int bits, X64Reg dest, const OpArg& src); // Top bit to bottom bit | 542 | void BSR(int bits, X64Reg dest, const OpArg& src); // Top bit to bottom bit |
| 451 | 543 | ||
| 452 | // Cache control | 544 | // Cache control |
| 453 | enum PrefetchLevel | 545 | enum PrefetchLevel { |
| 454 | { | 546 | PF_NTA, // Non-temporal (data used once and only once) |
| 455 | PF_NTA, //Non-temporal (data used once and only once) | 547 | PF_T0, // All cache levels |
| 456 | PF_T0, //All cache levels | 548 | PF_T1, // Levels 2+ (aliased to T0 on AMD) |
| 457 | PF_T1, //Levels 2+ (aliased to T0 on AMD) | 549 | PF_T2, // Levels 3+ (aliased to T0 on AMD) |
| 458 | PF_T2, //Levels 3+ (aliased to T0 on AMD) | ||
| 459 | }; | 550 | }; |
| 460 | void PREFETCH(PrefetchLevel level, OpArg arg); | 551 | void PREFETCH(PrefetchLevel level, OpArg arg); |
| 461 | void MOVNTI(int bits, const OpArg& dest, X64Reg src); | 552 | void MOVNTI(int bits, const OpArg& dest, X64Reg src); |
| @@ -464,8 +555,8 @@ public: | |||
| 464 | void MOVNTPD(const OpArg& arg, X64Reg regOp); | 555 | void MOVNTPD(const OpArg& arg, X64Reg regOp); |
| 465 | 556 | ||
| 466 | // Multiplication / division | 557 | // Multiplication / division |
| 467 | void MUL(int bits, const OpArg& src); //UNSIGNED | 558 | void MUL(int bits, const OpArg& src); // UNSIGNED |
| 468 | void IMUL(int bits, const OpArg& src); //SIGNED | 559 | void IMUL(int bits, const OpArg& src); // SIGNED |
| 469 | void IMUL(int bits, X64Reg regOp, const OpArg& src); | 560 | void IMUL(int bits, X64Reg regOp, const OpArg& src); |
| 470 | void IMUL(int bits, X64Reg regOp, const OpArg& src, const OpArg& imm); | 561 | void IMUL(int bits, X64Reg regOp, const OpArg& src, const OpArg& imm); |
| 471 | void DIV(int bits, const OpArg& src); | 562 | void DIV(int bits, const OpArg& src); |
| @@ -492,11 +583,19 @@ public: | |||
| 492 | 583 | ||
| 493 | // Extend EAX into EDX in various ways | 584 | // Extend EAX into EDX in various ways |
| 494 | void CWD(int bits = 16); | 585 | void CWD(int bits = 16); |
| 495 | void CDQ() {CWD(32);} | 586 | void CDQ() { |
| 496 | void CQO() {CWD(64);} | 587 | CWD(32); |
| 588 | } | ||
| 589 | void CQO() { | ||
| 590 | CWD(64); | ||
| 591 | } | ||
| 497 | void CBW(int bits = 8); | 592 | void CBW(int bits = 8); |
| 498 | void CWDE() {CBW(16);} | 593 | void CWDE() { |
| 499 | void CDQE() {CBW(32);} | 594 | CBW(16); |
| 595 | } | ||
| 596 | void CDQE() { | ||
| 597 | CBW(32); | ||
| 598 | } | ||
| 500 | 599 | ||
| 501 | // Load effective address | 600 | // Load effective address |
| 502 | void LEA(int bits, X64Reg dest, OpArg src); | 601 | void LEA(int bits, X64Reg dest, OpArg src); |
| @@ -511,7 +610,7 @@ public: | |||
| 511 | void CMP(int bits, const OpArg& a1, const OpArg& a2); | 610 | void CMP(int bits, const OpArg& a1, const OpArg& a2); |
| 512 | 611 | ||
| 513 | // Bit operations | 612 | // Bit operations |
| 514 | void NOT (int bits, const OpArg& src); | 613 | void NOT(int bits, const OpArg& src); |
| 515 | void OR(int bits, const OpArg& a1, const OpArg& a2); | 614 | void OR(int bits, const OpArg& a1, const OpArg& a2); |
| 516 | void XOR(int bits, const OpArg& a1, const OpArg& a2); | 615 | void XOR(int bits, const OpArg& a1, const OpArg& a2); |
| 517 | void MOV(int bits, const OpArg& a1, const OpArg& a2); | 616 | void MOV(int bits, const OpArg& a1, const OpArg& a2); |
| @@ -525,7 +624,8 @@ public: | |||
| 525 | void BSWAP(int bits, X64Reg reg); | 624 | void BSWAP(int bits, X64Reg reg); |
| 526 | 625 | ||
| 527 | // Sign/zero extension | 626 | // Sign/zero extension |
| 528 | void MOVSX(int dbits, int sbits, X64Reg dest, OpArg src); //automatically uses MOVSXD if necessary | 627 | void MOVSX(int dbits, int sbits, X64Reg dest, |
| 628 | OpArg src); // automatically uses MOVSXD if necessary | ||
| 529 | void MOVZX(int dbits, int sbits, X64Reg dest, OpArg src); | 629 | void MOVZX(int dbits, int sbits, X64Reg dest, OpArg src); |
| 530 | 630 | ||
| 531 | // Available only on Atom or >= Haswell so far. Test with GetCPUCaps().movbe. | 631 | // Available only on Atom or >= Haswell so far. Test with GetCPUCaps().movbe. |
| @@ -593,13 +693,27 @@ public: | |||
| 593 | void CMPSS(X64Reg regOp, const OpArg& arg, u8 compare); | 693 | void CMPSS(X64Reg regOp, const OpArg& arg, u8 compare); |
| 594 | void CMPSD(X64Reg regOp, const OpArg& arg, u8 compare); | 694 | void CMPSD(X64Reg regOp, const OpArg& arg, u8 compare); |
| 595 | 695 | ||
| 596 | void CMPEQSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_EQ); } | 696 | void CMPEQSS(X64Reg regOp, const OpArg& arg) { |
| 597 | void CMPLTSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_LT); } | 697 | CMPSS(regOp, arg, CMP_EQ); |
| 598 | void CMPLESS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_LE); } | 698 | } |
| 599 | void CMPUNORDSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_UNORD); } | 699 | void CMPLTSS(X64Reg regOp, const OpArg& arg) { |
| 600 | void CMPNEQSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_NEQ); } | 700 | CMPSS(regOp, arg, CMP_LT); |
| 601 | void CMPNLTSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_NLT); } | 701 | } |
| 602 | void CMPORDSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_ORD); } | 702 | void CMPLESS(X64Reg regOp, const OpArg& arg) { |
| 703 | CMPSS(regOp, arg, CMP_LE); | ||
| 704 | } | ||
| 705 | void CMPUNORDSS(X64Reg regOp, const OpArg& arg) { | ||
| 706 | CMPSS(regOp, arg, CMP_UNORD); | ||
| 707 | } | ||
| 708 | void CMPNEQSS(X64Reg regOp, const OpArg& arg) { | ||
| 709 | CMPSS(regOp, arg, CMP_NEQ); | ||
| 710 | } | ||
| 711 | void CMPNLTSS(X64Reg regOp, const OpArg& arg) { | ||
| 712 | CMPSS(regOp, arg, CMP_NLT); | ||
| 713 | } | ||
| 714 | void CMPORDSS(X64Reg regOp, const OpArg& arg) { | ||
| 715 | CMPSS(regOp, arg, CMP_ORD); | ||
| 716 | } | ||
| 603 | 717 | ||
| 604 | // SSE/SSE2: Floating point packed arithmetic (x4 for float, x2 for double) | 718 | // SSE/SSE2: Floating point packed arithmetic (x4 for float, x2 for double) |
| 605 | void ADDPS(X64Reg regOp, const OpArg& arg); | 719 | void ADDPS(X64Reg regOp, const OpArg& arg); |
| @@ -638,10 +752,12 @@ public: | |||
| 638 | // SSE/SSE2: Useful alternative to shuffle in some cases. | 752 | // SSE/SSE2: Useful alternative to shuffle in some cases. |
| 639 | void MOVDDUP(X64Reg regOp, const OpArg& arg); | 753 | void MOVDDUP(X64Reg regOp, const OpArg& arg); |
| 640 | 754 | ||
| 641 | // SSE3: Horizontal operations in SIMD registers. Very slow! shufps-based code beats it handily on Ivy. | 755 | // SSE3: Horizontal operations in SIMD registers. Very slow! shufps-based code beats it handily |
| 756 | // on Ivy. | ||
| 642 | void HADDPS(X64Reg dest, const OpArg& src); | 757 | void HADDPS(X64Reg dest, const OpArg& src); |
| 643 | 758 | ||
| 644 | // SSE4: Further horizontal operations - dot products. These are weirdly flexible, the arg contains both a read mask and a write "mask". | 759 | // SSE4: Further horizontal operations - dot products. These are weirdly flexible, the arg |
| 760 | // contains both a read mask and a write "mask". | ||
| 645 | void DPPS(X64Reg dest, const OpArg& src, u8 arg); | 761 | void DPPS(X64Reg dest, const OpArg& src, u8 arg); |
| 646 | 762 | ||
| 647 | void UNPCKLPS(X64Reg dest, const OpArg& src); | 763 | void UNPCKLPS(X64Reg dest, const OpArg& src); |
| @@ -694,11 +810,13 @@ public: | |||
| 694 | void MOVD_xmm(const OpArg& arg, X64Reg src); | 810 | void MOVD_xmm(const OpArg& arg, X64Reg src); |
| 695 | void MOVQ_xmm(OpArg arg, X64Reg src); | 811 | void MOVQ_xmm(OpArg arg, X64Reg src); |
| 696 | 812 | ||
| 697 | // SSE/SSE2: Generates a mask from the high bits of the components of the packed register in question. | 813 | // SSE/SSE2: Generates a mask from the high bits of the components of the packed register in |
| 814 | // question. | ||
| 698 | void MOVMSKPS(X64Reg dest, const OpArg& arg); | 815 | void MOVMSKPS(X64Reg dest, const OpArg& arg); |
| 699 | void MOVMSKPD(X64Reg dest, const OpArg& arg); | 816 | void MOVMSKPD(X64Reg dest, const OpArg& arg); |
| 700 | 817 | ||
| 701 | // SSE2: Selective byte store, mask in src register. EDI/RDI specifies store address. This is a weird one. | 818 | // SSE2: Selective byte store, mask in src register. EDI/RDI specifies store address. This is a |
| 819 | // weird one. | ||
| 702 | void MASKMOVDQU(X64Reg dest, X64Reg src); | 820 | void MASKMOVDQU(X64Reg dest, X64Reg src); |
| 703 | void LDDQU(X64Reg dest, const OpArg& src); | 821 | void LDDQU(X64Reg dest, const OpArg& src); |
| 704 | 822 | ||
| @@ -729,10 +847,10 @@ public: | |||
| 729 | void PACKUSDW(X64Reg dest, const OpArg& arg); | 847 | void PACKUSDW(X64Reg dest, const OpArg& arg); |
| 730 | void PACKUSWB(X64Reg dest, const OpArg& arg); | 848 | void PACKUSWB(X64Reg dest, const OpArg& arg); |
| 731 | 849 | ||
| 732 | void PUNPCKLBW(X64Reg dest, const OpArg &arg); | 850 | void PUNPCKLBW(X64Reg dest, const OpArg& arg); |
| 733 | void PUNPCKLWD(X64Reg dest, const OpArg &arg); | 851 | void PUNPCKLWD(X64Reg dest, const OpArg& arg); |
| 734 | void PUNPCKLDQ(X64Reg dest, const OpArg &arg); | 852 | void PUNPCKLDQ(X64Reg dest, const OpArg& arg); |
| 735 | void PUNPCKLQDQ(X64Reg dest, const OpArg &arg); | 853 | void PUNPCKLQDQ(X64Reg dest, const OpArg& arg); |
| 736 | 854 | ||
| 737 | void PTEST(X64Reg dest, const OpArg& arg); | 855 | void PTEST(X64Reg dest, const OpArg& arg); |
| 738 | void PAND(X64Reg dest, const OpArg& arg); | 856 | void PAND(X64Reg dest, const OpArg& arg); |
| @@ -839,25 +957,57 @@ public: | |||
| 839 | void ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode); | 957 | void ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode); |
| 840 | void ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode); | 958 | void ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode); |
| 841 | 959 | ||
| 842 | void ROUNDNEARSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_NEAREST); } | 960 | void ROUNDNEARSS(X64Reg dest, const OpArg& arg) { |
| 843 | void ROUNDFLOORSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_FLOOR); } | 961 | ROUNDSS(dest, arg, FROUND_NEAREST); |
| 844 | void ROUNDCEILSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_CEIL); } | 962 | } |
| 845 | void ROUNDZEROSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_ZERO); } | 963 | void ROUNDFLOORSS(X64Reg dest, const OpArg& arg) { |
| 964 | ROUNDSS(dest, arg, FROUND_FLOOR); | ||
| 965 | } | ||
| 966 | void ROUNDCEILSS(X64Reg dest, const OpArg& arg) { | ||
| 967 | ROUNDSS(dest, arg, FROUND_CEIL); | ||
| 968 | } | ||
| 969 | void ROUNDZEROSS(X64Reg dest, const OpArg& arg) { | ||
| 970 | ROUNDSS(dest, arg, FROUND_ZERO); | ||
| 971 | } | ||
| 846 | 972 | ||
| 847 | void ROUNDNEARSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_NEAREST); } | 973 | void ROUNDNEARSD(X64Reg dest, const OpArg& arg) { |
| 848 | void ROUNDFLOORSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_FLOOR); } | 974 | ROUNDSD(dest, arg, FROUND_NEAREST); |
| 849 | void ROUNDCEILSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_CEIL); } | 975 | } |
| 850 | void ROUNDZEROSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_ZERO); } | 976 | void ROUNDFLOORSD(X64Reg dest, const OpArg& arg) { |
| 977 | ROUNDSD(dest, arg, FROUND_FLOOR); | ||
| 978 | } | ||
| 979 | void ROUNDCEILSD(X64Reg dest, const OpArg& arg) { | ||
| 980 | ROUNDSD(dest, arg, FROUND_CEIL); | ||
| 981 | } | ||
| 982 | void ROUNDZEROSD(X64Reg dest, const OpArg& arg) { | ||
| 983 | ROUNDSD(dest, arg, FROUND_ZERO); | ||
| 984 | } | ||
| 851 | 985 | ||
| 852 | void ROUNDNEARPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_NEAREST); } | 986 | void ROUNDNEARPS(X64Reg dest, const OpArg& arg) { |
| 853 | void ROUNDFLOORPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_FLOOR); } | 987 | ROUNDPS(dest, arg, FROUND_NEAREST); |
| 854 | void ROUNDCEILPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_CEIL); } | 988 | } |
| 855 | void ROUNDZEROPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_ZERO); } | 989 | void ROUNDFLOORPS(X64Reg dest, const OpArg& arg) { |
| 990 | ROUNDPS(dest, arg, FROUND_FLOOR); | ||
| 991 | } | ||
| 992 | void ROUNDCEILPS(X64Reg dest, const OpArg& arg) { | ||
| 993 | ROUNDPS(dest, arg, FROUND_CEIL); | ||
| 994 | } | ||
| 995 | void ROUNDZEROPS(X64Reg dest, const OpArg& arg) { | ||
| 996 | ROUNDPS(dest, arg, FROUND_ZERO); | ||
| 997 | } | ||
| 856 | 998 | ||
| 857 | void ROUNDNEARPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_NEAREST); } | 999 | void ROUNDNEARPD(X64Reg dest, const OpArg& arg) { |
| 858 | void ROUNDFLOORPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_FLOOR); } | 1000 | ROUNDPD(dest, arg, FROUND_NEAREST); |
| 859 | void ROUNDCEILPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_CEIL); } | 1001 | } |
| 860 | void ROUNDZEROPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_ZERO); } | 1002 | void ROUNDFLOORPD(X64Reg dest, const OpArg& arg) { |
| 1003 | ROUNDPD(dest, arg, FROUND_FLOOR); | ||
| 1004 | } | ||
| 1005 | void ROUNDCEILPD(X64Reg dest, const OpArg& arg) { | ||
| 1006 | ROUNDPD(dest, arg, FROUND_CEIL); | ||
| 1007 | } | ||
| 1008 | void ROUNDZEROPD(X64Reg dest, const OpArg& arg) { | ||
| 1009 | ROUNDPD(dest, arg, FROUND_ZERO); | ||
| 1010 | } | ||
| 861 | 1011 | ||
| 862 | // AVX | 1012 | // AVX |
| 863 | void VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); | 1013 | void VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); |
| @@ -981,7 +1131,6 @@ public: | |||
| 981 | void ABI_CallFunctionC16(const void* func, u16 param1); | 1131 | void ABI_CallFunctionC16(const void* func, u16 param1); |
| 982 | void ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2); | 1132 | void ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2); |
| 983 | 1133 | ||
| 984 | |||
| 985 | // These only support u32 parameters, but that's enough for a lot of uses. | 1134 | // These only support u32 parameters, but that's enough for a lot of uses. |
| 986 | // These will destroy the 1 or 2 first "parameter regs". | 1135 | // These will destroy the 1 or 2 first "parameter regs". |
| 987 | void ABI_CallFunctionC(const void* func, u32 param1); | 1136 | void ABI_CallFunctionC(const void* func, u32 param1); |
| @@ -1012,29 +1161,38 @@ public: | |||
| 1012 | * | 1161 | * |
| 1013 | * @param mask Registers to push on the stack (high 16 bits are XMMs, low 16 bits are GPRs) | 1162 | * @param mask Registers to push on the stack (high 16 bits are XMMs, low 16 bits are GPRs) |
| 1014 | * @param rsp_alignment Current alignment of the stack pointer, must be 0 or 8 | 1163 | * @param rsp_alignment Current alignment of the stack pointer, must be 0 or 8 |
| 1015 | * @param needed_frame_size Additional space needed, e.g., for function arguments passed on the stack | 1164 | * @param needed_frame_size Additional space needed, e.g., for function arguments passed on the |
| 1165 | * stack | ||
| 1016 | * @return Size of the shadow space, i.e., offset of the frame | 1166 | * @return Size of the shadow space, i.e., offset of the frame |
| 1017 | */ | 1167 | */ |
| 1018 | size_t ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size = 0); | 1168 | size_t ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, |
| 1169 | size_t needed_frame_size = 0); | ||
| 1019 | 1170 | ||
| 1020 | /** | 1171 | /** |
| 1021 | * Restores specified registers and adjusts the stack to its original alignment, i.e., the alignment before | 1172 | * Restores specified registers and adjusts the stack to its original alignment, i.e., the |
| 1173 | * alignment before | ||
| 1022 | * the matching PushRegistersAndAdjustStack. | 1174 | * the matching PushRegistersAndAdjustStack. |
| 1023 | * | 1175 | * |
| 1024 | * @param mask Registers to restores from the stack (high 16 bits are XMMs, low 16 bits are GPRs) | 1176 | * @param mask Registers to restores from the stack (high 16 bits are XMMs, low 16 bits are |
| 1025 | * @param rsp_alignment Original alignment before the matching PushRegistersAndAdjustStack, must be 0 or 8 | 1177 | * GPRs) |
| 1178 | * @param rsp_alignment Original alignment before the matching PushRegistersAndAdjustStack, must | ||
| 1179 | * be 0 or 8 | ||
| 1026 | * @param needed_frame_size Additional space that was needed | 1180 | * @param needed_frame_size Additional space that was needed |
| 1027 | * @warning Stack must be currently 16-byte aligned | 1181 | * @warning Stack must be currently 16-byte aligned |
| 1028 | */ | 1182 | */ |
| 1029 | void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size = 0); | 1183 | void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, |
| 1030 | 1184 | size_t needed_frame_size = 0); | |
| 1031 | #ifdef _M_IX86 | ||
| 1032 | static int ABI_GetNumXMMRegs() { return 8; } | ||
| 1033 | #else | ||
| 1034 | static int ABI_GetNumXMMRegs() { return 16; } | ||
| 1035 | #endif | ||
| 1036 | }; // class XEmitter | ||
| 1037 | 1185 | ||
| 1186 | #ifdef _M_IX86 | ||
| 1187 | static int ABI_GetNumXMMRegs() { | ||
| 1188 | return 8; | ||
| 1189 | } | ||
| 1190 | #else | ||
| 1191 | static int ABI_GetNumXMMRegs() { | ||
| 1192 | return 16; | ||
| 1193 | } | ||
| 1194 | #endif | ||
| 1195 | }; // class XEmitter | ||
| 1038 | 1196 | ||
| 1039 | // Everything that needs to generate X86 code should inherit from this. | 1197 | // Everything that needs to generate X86 code should inherit from this. |
| 1040 | // You get memory management for free, plus, you can use all the MOV etc functions without | 1198 | // You get memory management for free, plus, you can use all the MOV etc functions without |
| @@ -1045,4 +1203,4 @@ public: | |||
| 1045 | void PoisonMemory() override; | 1203 | void PoisonMemory() override; |
| 1046 | }; | 1204 | }; |
| 1047 | 1205 | ||
| 1048 | } // namespace | 1206 | } // namespace |