diff options
Diffstat (limited to 'src/common')
51 files changed, 4172 insertions, 3389 deletions
diff --git a/src/common/assert.h b/src/common/assert.h index cd9b819a9..70214efae 100644 --- a/src/common/assert.h +++ b/src/common/assert.h | |||
| @@ -18,25 +18,29 @@ | |||
| 18 | // enough for our purposes. | 18 | // enough for our purposes. |
| 19 | template <typename Fn> | 19 | template <typename Fn> |
| 20 | #if defined(_MSC_VER) | 20 | #if defined(_MSC_VER) |
| 21 | __declspec(noinline, noreturn) | 21 | __declspec(noinline, noreturn) |
| 22 | #elif defined(__GNUC__) | 22 | #elif defined(__GNUC__) |
| 23 | __attribute__((noinline, noreturn, cold)) | 23 | __attribute__((noinline, noreturn, cold)) |
| 24 | #endif | 24 | #endif |
| 25 | static void assert_noinline_call(const Fn& fn) { | 25 | static void assert_noinline_call(const Fn& fn) { |
| 26 | fn(); | 26 | fn(); |
| 27 | Crash(); | 27 | Crash(); |
| 28 | exit(1); // Keeps GCC's mouth shut about this actually returning | 28 | exit(1); // Keeps GCC's mouth shut about this actually returning |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | #define ASSERT(_a_) \ | 31 | #define ASSERT(_a_) \ |
| 32 | do if (!(_a_)) { assert_noinline_call([] { \ | 32 | do \ |
| 33 | LOG_CRITICAL(Debug, "Assertion Failed!"); \ | 33 | if (!(_a_)) { \ |
| 34 | }); } while (0) | 34 | assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \ |
| 35 | 35 | } \ | |
| 36 | #define ASSERT_MSG(_a_, ...) \ | 36 | while (0) |
| 37 | do if (!(_a_)) { assert_noinline_call([&] { \ | 37 | |
| 38 | LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \ | 38 | #define ASSERT_MSG(_a_, ...) \ |
| 39 | }); } while (0) | 39 | do \ |
| 40 | if (!(_a_)) { \ | ||
| 41 | assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \ | ||
| 42 | } \ | ||
| 43 | while (0) | ||
| 40 | 44 | ||
| 41 | #define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!") | 45 | #define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!") |
| 42 | #define UNREACHABLE_MSG(...) ASSERT_MSG(false, __VA_ARGS__) | 46 | #define UNREACHABLE_MSG(...) ASSERT_MSG(false, __VA_ARGS__) |
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 4748999ed..8d45743e2 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,7 +28,6 @@ | |||
| 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> |
| @@ -111,9 +109,8 @@ | |||
| 111 | * symptoms. | 109 | * symptoms. |
| 112 | */ | 110 | */ |
| 113 | #pragma pack(1) | 111 | #pragma pack(1) |
| 114 | template<std::size_t position, std::size_t bits, typename T> | 112 | template <std::size_t position, std::size_t bits, typename T> |
| 115 | struct BitField | 113 | struct BitField { |
| 116 | { | ||
| 117 | private: | 114 | private: |
| 118 | // We hide the copy assigment operator here, because the default copy | 115 | // We hide the copy assigment operator here, because the default copy |
| 119 | // assignment would copy the full storage value, rather than just the bits | 116 | // assignment would copy the full storage value, rather than just the bits |
| @@ -141,13 +138,10 @@ public: | |||
| 141 | } | 138 | } |
| 142 | 139 | ||
| 143 | FORCE_INLINE T Value() const { | 140 | FORCE_INLINE T Value() const { |
| 144 | if (std::numeric_limits<T>::is_signed) | 141 | if (std::numeric_limits<T>::is_signed) { |
| 145 | { | 142 | std::size_t shift = 8 * sizeof(T) - bits; |
| 146 | std::size_t shift = 8 * sizeof(T)-bits; | ||
| 147 | return (T)((storage << (shift - position)) >> shift); | 143 | return (T)((storage << (shift - position)) >> shift); |
| 148 | } | 144 | } else { |
| 149 | else | ||
| 150 | { | ||
| 151 | return (T)((storage & GetMask()) >> position); | 145 | return (T)((storage & GetMask()) >> position); |
| 152 | } | 146 | } |
| 153 | } | 147 | } |
| @@ -162,15 +156,14 @@ private: | |||
| 162 | // T is an enumeration. Note that T is wrapped within an enable_if in the | 156 | // 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 | 157 | // former case to workaround compile errors which arise when using |
| 164 | // std::underlying_type<T>::type directly. | 158 | // std::underlying_type<T>::type directly. |
| 165 | typedef typename std::conditional < std::is_enum<T>::value, | 159 | typedef typename std::conditional<std::is_enum<T>::value, std::underlying_type<T>, |
| 166 | std::underlying_type<T>, | 160 | std::enable_if<true, T>>::type::type StorageType; |
| 167 | std::enable_if < true, T >> ::type::type StorageType; | ||
| 168 | 161 | ||
| 169 | // Unsigned version of StorageType | 162 | // Unsigned version of StorageType |
| 170 | typedef typename std::make_unsigned<StorageType>::type StorageTypeU; | 163 | typedef typename std::make_unsigned<StorageType>::type StorageTypeU; |
| 171 | 164 | ||
| 172 | FORCE_INLINE StorageType GetMask() const { | 165 | FORCE_INLINE StorageType GetMask() const { |
| 173 | return (((StorageTypeU)~0) >> (8 * sizeof(T)-bits)) << position; | 166 | return (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; |
| 174 | } | 167 | } |
| 175 | 168 | ||
| 176 | StorageType storage; | 169 | StorageType storage; |
| @@ -186,5 +179,6 @@ private: | |||
| 186 | #pragma pack() | 179 | #pragma pack() |
| 187 | 180 | ||
| 188 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) | 181 | #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"); | 182 | static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, |
| 183 | "BitField must be trivially copyable"); | ||
| 190 | #endif | 184 | #endif |
diff --git a/src/common/bit_set.h b/src/common/bit_set.h index 7f5de8df2..b83cbbb36 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,100 +95,144 @@ 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 | } |
| 97 | operator bool() const { return (m_bs->m_val & m_mask) != 0; } | 107 | Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) { |
| 98 | bool operator=(bool set) | 108 | } |
| 99 | { | 109 | operator bool() const { |
| 110 | return (m_bs->m_val & m_mask) != 0; | ||
| 111 | } | ||
| 112 | bool operator=(bool set) { | ||
| 100 | m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0); | 113 | m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0); |
| 101 | return set; | 114 | return set; |
| 102 | } | 115 | } |
| 116 | |||
| 103 | private: | 117 | private: |
| 104 | BitSet* m_bs; | 118 | BitSet* m_bs; |
| 105 | IntTy m_mask; | 119 | IntTy m_mask; |
| 106 | }; | 120 | }; |
| 107 | 121 | ||
| 108 | // A STL-like iterator is required to be able to use range-based for loops. | 122 | // A STL-like iterator is required to be able to use range-based for loops. |
| 109 | class Iterator | 123 | class Iterator { |
| 110 | { | ||
| 111 | public: | 124 | public: |
| 112 | Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {} | 125 | 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) {} | 126 | } |
| 114 | Iterator& operator=(Iterator other) { new (this) Iterator(other); return *this; } | 127 | Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) { |
| 115 | int operator*() { return m_bit; } | 128 | } |
| 116 | Iterator& operator++() | 129 | Iterator& operator=(Iterator other) { |
| 117 | { | 130 | new (this) Iterator(other); |
| 118 | if (m_val == 0) | 131 | return *this; |
| 119 | { | 132 | } |
| 133 | int operator*() { | ||
| 134 | return m_bit; | ||
| 135 | } | ||
| 136 | Iterator& operator++() { | ||
| 137 | if (m_val == 0) { | ||
| 120 | m_bit = -1; | 138 | m_bit = -1; |
| 121 | } | 139 | } else { |
| 122 | else | ||
| 123 | { | ||
| 124 | int bit = LeastSignificantSetBit(m_val); | 140 | int bit = LeastSignificantSetBit(m_val); |
| 125 | m_val &= ~(1 << bit); | 141 | m_val &= ~(1 << bit); |
| 126 | m_bit = bit; | 142 | m_bit = bit; |
| 127 | } | 143 | } |
| 128 | return *this; | 144 | return *this; |
| 129 | } | 145 | } |
| 130 | Iterator operator++(int _) | 146 | Iterator operator++(int _) { |
| 131 | { | ||
| 132 | Iterator other(*this); | 147 | Iterator other(*this); |
| 133 | ++*this; | 148 | ++*this; |
| 134 | return other; | 149 | return other; |
| 135 | } | 150 | } |
| 136 | bool operator==(Iterator other) const { return m_bit == other.m_bit; } | 151 | bool operator==(Iterator other) const { |
| 137 | bool operator!=(Iterator other) const { return m_bit != other.m_bit; } | 152 | return m_bit == other.m_bit; |
| 153 | } | ||
| 154 | bool operator!=(Iterator other) const { | ||
| 155 | return m_bit != other.m_bit; | ||
| 156 | } | ||
| 157 | |||
| 138 | private: | 158 | private: |
| 139 | IntTy m_val; | 159 | IntTy m_val; |
| 140 | int m_bit; | 160 | int m_bit; |
| 141 | }; | 161 | }; |
| 142 | 162 | ||
| 143 | BitSet() : m_val(0) {} | 163 | BitSet() : m_val(0) { |
| 144 | explicit BitSet(IntTy val) : m_val(val) {} | 164 | } |
| 145 | BitSet(std::initializer_list<int> init) | 165 | explicit BitSet(IntTy val) : m_val(val) { |
| 146 | { | 166 | } |
| 167 | BitSet(std::initializer_list<int> init) { | ||
| 147 | m_val = 0; | 168 | m_val = 0; |
| 148 | for (int bit : init) | 169 | for (int bit : init) |
| 149 | m_val |= (IntTy)1 << bit; | 170 | m_val |= (IntTy)1 << bit; |
| 150 | } | 171 | } |
| 151 | 172 | ||
| 152 | static BitSet AllTrue(size_t count) | 173 | static BitSet AllTrue(size_t count) { |
| 153 | { | 174 | 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)); | 175 | } |
| 155 | } | 176 | |
| 156 | 177 | Ref operator[](size_t bit) { | |
| 157 | Ref operator[](size_t bit) { return Ref(this, (IntTy)1 << bit); } | 178 | return Ref(this, (IntTy)1 << bit); |
| 158 | const Ref operator[](size_t bit) const { return (*const_cast<BitSet*>(this))[bit]; } | 179 | } |
| 159 | bool operator==(BitSet other) const { return m_val == other.m_val; } | 180 | const Ref operator[](size_t bit) const { |
| 160 | bool operator!=(BitSet other) const { return m_val != other.m_val; } | 181 | return (*const_cast<BitSet*>(this))[bit]; |
| 161 | bool operator<(BitSet other) const { return m_val < other.m_val; } | 182 | } |
| 162 | bool operator>(BitSet other) const { return m_val > other.m_val; } | 183 | bool operator==(BitSet other) const { |
| 163 | BitSet operator|(BitSet other) const { return BitSet(m_val | other.m_val); } | 184 | return m_val == other.m_val; |
| 164 | BitSet operator&(BitSet other) const { return BitSet(m_val & other.m_val); } | 185 | } |
| 165 | BitSet operator^(BitSet other) const { return BitSet(m_val ^ other.m_val); } | 186 | bool operator!=(BitSet other) const { |
| 166 | BitSet operator~() const { return BitSet(~m_val); } | 187 | return m_val != other.m_val; |
| 167 | BitSet& operator|=(BitSet other) { return *this = *this | other; } | 188 | } |
| 168 | BitSet& operator&=(BitSet other) { return *this = *this & other; } | 189 | bool operator<(BitSet other) const { |
| 169 | BitSet& operator^=(BitSet other) { return *this = *this ^ other; } | 190 | return m_val < other.m_val; |
| 191 | } | ||
| 192 | bool operator>(BitSet other) const { | ||
| 193 | return m_val > other.m_val; | ||
| 194 | } | ||
| 195 | BitSet operator|(BitSet other) const { | ||
| 196 | return BitSet(m_val | other.m_val); | ||
| 197 | } | ||
| 198 | BitSet operator&(BitSet other) const { | ||
| 199 | return BitSet(m_val & other.m_val); | ||
| 200 | } | ||
| 201 | BitSet operator^(BitSet other) const { | ||
| 202 | return BitSet(m_val ^ other.m_val); | ||
| 203 | } | ||
| 204 | BitSet operator~() const { | ||
| 205 | return BitSet(~m_val); | ||
| 206 | } | ||
| 207 | BitSet& operator|=(BitSet other) { | ||
| 208 | return *this = *this | other; | ||
| 209 | } | ||
| 210 | BitSet& operator&=(BitSet other) { | ||
| 211 | return *this = *this & other; | ||
| 212 | } | ||
| 213 | BitSet& operator^=(BitSet other) { | ||
| 214 | return *this = *this ^ other; | ||
| 215 | } | ||
| 170 | operator u32() = delete; | 216 | operator u32() = delete; |
| 171 | operator bool() { return m_val != 0; } | 217 | operator bool() { |
| 218 | return m_val != 0; | ||
| 219 | } | ||
| 172 | 220 | ||
| 173 | // Warning: Even though on modern CPUs this is a single fast instruction, | 221 | // 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, | 222 | // Dolphin's official builds do not currently assume POPCNT support on x86, |
| 175 | // so slower explicit bit twiddling is generated. Still should generally | 223 | // so slower explicit bit twiddling is generated. Still should generally |
| 176 | // be faster than a loop. | 224 | // be faster than a loop. |
| 177 | unsigned int Count() const { return CountSetBits(m_val); } | 225 | unsigned int Count() const { |
| 226 | return CountSetBits(m_val); | ||
| 227 | } | ||
| 178 | 228 | ||
| 179 | Iterator begin() const { Iterator it(m_val, 0); return ++it; } | 229 | Iterator begin() const { |
| 180 | Iterator end() const { return Iterator(m_val, -1); } | 230 | Iterator it(m_val, 0); |
| 231 | return ++it; | ||
| 232 | } | ||
| 233 | Iterator end() const { | ||
| 234 | return Iterator(m_val, -1); | ||
| 235 | } | ||
| 181 | 236 | ||
| 182 | IntTy m_val; | 237 | IntTy m_val; |
| 183 | }; | 238 | }; |
diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp index e7d0d3e43..3218db314 100644 --- a/src/common/break_points.cpp +++ b/src/common/break_points.cpp | |||
| @@ -5,30 +5,27 @@ | |||
| 5 | #include "common/break_points.h" | 5 | #include "common/break_points.h" |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | 7 | ||
| 8 | #include <sstream> | ||
| 9 | #include <algorithm> | 8 | #include <algorithm> |
| 9 | #include <sstream> | ||
| 10 | 10 | ||
| 11 | bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const | 11 | bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const { |
| 12 | { | ||
| 13 | auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; }; | 12 | auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; }; |
| 14 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); | 13 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); |
| 15 | return it != m_BreakPoints.end(); | 14 | return it != m_BreakPoints.end(); |
| 16 | } | 15 | } |
| 17 | 16 | ||
| 18 | bool BreakPoints::IsTempBreakPoint(u32 iAddress) const | 17 | bool BreakPoints::IsTempBreakPoint(u32 iAddress) const { |
| 19 | { | 18 | auto cond = [&iAddress](const TBreakPoint& bp) { |
| 20 | auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress && bp.bTemporary; }; | 19 | return bp.iAddress == iAddress && bp.bTemporary; |
| 21 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); | 20 | }; |
| 21 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); | ||
| 22 | return it != m_BreakPoints.end(); | 22 | return it != m_BreakPoints.end(); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const | 25 | BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const { |
| 26 | { | ||
| 27 | TBreakPointsStr bps; | 26 | TBreakPointsStr bps; |
| 28 | for (auto breakpoint : m_BreakPoints) | 27 | for (auto breakpoint : m_BreakPoints) { |
| 29 | { | 28 | if (!breakpoint.bTemporary) { |
| 30 | if (!breakpoint.bTemporary) | ||
| 31 | { | ||
| 32 | std::stringstream bp; | 29 | std::stringstream bp; |
| 33 | bp << std::hex << breakpoint.iAddress << " " << (breakpoint.bOn ? "n" : ""); | 30 | bp << std::hex << breakpoint.iAddress << " " << (breakpoint.bOn ? "n" : ""); |
| 34 | bps.push_back(bp.str()); | 31 | bps.push_back(bp.str()); |
| @@ -38,10 +35,8 @@ BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const | |||
| 38 | return bps; | 35 | return bps; |
| 39 | } | 36 | } |
| 40 | 37 | ||
| 41 | void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) | 38 | void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) { |
| 42 | { | 39 | for (auto bps_item : bps) { |
| 43 | for (auto bps_item : bps) | ||
| 44 | { | ||
| 45 | TBreakPoint bp; | 40 | TBreakPoint bp; |
| 46 | std::stringstream bpstr; | 41 | std::stringstream bpstr; |
| 47 | bpstr << std::hex << bps_item; | 42 | bpstr << std::hex << bps_item; |
| @@ -52,18 +47,15 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) | |||
| 52 | } | 47 | } |
| 53 | } | 48 | } |
| 54 | 49 | ||
| 55 | void BreakPoints::Add(const TBreakPoint& bp) | 50 | void BreakPoints::Add(const TBreakPoint& bp) { |
| 56 | { | 51 | if (!IsAddressBreakPoint(bp.iAddress)) { |
| 57 | if (!IsAddressBreakPoint(bp.iAddress)) | ||
| 58 | { | ||
| 59 | m_BreakPoints.push_back(bp); | 52 | m_BreakPoints.push_back(bp); |
| 60 | //if (jit) | 53 | // if (jit) |
| 61 | // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); | 54 | // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); |
| 62 | } | 55 | } |
| 63 | } | 56 | } |
| 64 | 57 | ||
| 65 | void BreakPoints::Add(u32 em_address, bool temp) | 58 | void BreakPoints::Add(u32 em_address, bool temp) { |
| 66 | { | ||
| 67 | if (!IsAddressBreakPoint(em_address)) // only add new addresses | 59 | if (!IsAddressBreakPoint(em_address)) // only add new addresses |
| 68 | { | 60 | { |
| 69 | TBreakPoint pt; // breakpoint settings | 61 | TBreakPoint pt; // breakpoint settings |
| @@ -73,22 +65,20 @@ void BreakPoints::Add(u32 em_address, bool temp) | |||
| 73 | 65 | ||
| 74 | m_BreakPoints.push_back(pt); | 66 | m_BreakPoints.push_back(pt); |
| 75 | 67 | ||
| 76 | //if (jit) | 68 | // if (jit) |
| 77 | // jit->GetBlockCache()->InvalidateICache(em_address, 4); | 69 | // jit->GetBlockCache()->InvalidateICache(em_address, 4); |
| 78 | } | 70 | } |
| 79 | } | 71 | } |
| 80 | 72 | ||
| 81 | void BreakPoints::Remove(u32 em_address) | 73 | void BreakPoints::Remove(u32 em_address) { |
| 82 | { | ||
| 83 | auto cond = [&em_address](const TBreakPoint& bp) { return bp.iAddress == em_address; }; | 74 | 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); | 75 | auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); |
| 85 | if (it != m_BreakPoints.end()) | 76 | if (it != m_BreakPoints.end()) |
| 86 | m_BreakPoints.erase(it); | 77 | m_BreakPoints.erase(it); |
| 87 | } | 78 | } |
| 88 | 79 | ||
| 89 | void BreakPoints::Clear() | 80 | void BreakPoints::Clear() { |
| 90 | { | 81 | // if (jit) |
| 91 | //if (jit) | ||
| 92 | //{ | 82 | //{ |
| 93 | // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(), | 83 | // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(), |
| 94 | // [](const TBreakPoint& bp) | 84 | // [](const TBreakPoint& bp) |
diff --git a/src/common/break_points.h b/src/common/break_points.h index b0629df37..1a5b7d296 100644 --- a/src/common/break_points.h +++ b/src/common/break_points.h | |||
| @@ -4,28 +4,28 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | ||
| 8 | #include <string> | 7 | #include <string> |
| 8 | #include <vector> | ||
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | 11 | ||
| 12 | class DebugInterface; | 12 | class DebugInterface; |
| 13 | 13 | ||
| 14 | struct TBreakPoint | 14 | struct TBreakPoint { |
| 15 | { | 15 | u32 iAddress; |
| 16 | u32 iAddress; | ||
| 17 | bool bOn; | 16 | bool bOn; |
| 18 | bool bTemporary; | 17 | bool bTemporary; |
| 19 | }; | 18 | }; |
| 20 | 19 | ||
| 21 | // Code breakpoints. | 20 | // Code breakpoints. |
| 22 | class BreakPoints | 21 | class BreakPoints { |
| 23 | { | ||
| 24 | public: | 22 | public: |
| 25 | typedef std::vector<TBreakPoint> TBreakPoints; | 23 | typedef std::vector<TBreakPoint> TBreakPoints; |
| 26 | typedef std::vector<std::string> TBreakPointsStr; | 24 | typedef std::vector<std::string> TBreakPointsStr; |
| 27 | 25 | ||
| 28 | const TBreakPoints& GetBreakPoints() { return m_BreakPoints; } | 26 | const TBreakPoints& GetBreakPoints() { |
| 27 | return m_BreakPoints; | ||
| 28 | } | ||
| 29 | 29 | ||
| 30 | TBreakPointsStr GetStrings() const; | 30 | TBreakPointsStr GetStrings() const; |
| 31 | void AddFromStrings(const TBreakPointsStr& bps); | 31 | void AddFromStrings(const TBreakPointsStr& bps); |
| @@ -35,7 +35,7 @@ public: | |||
| 35 | bool IsTempBreakPoint(u32 iAddress) const; | 35 | bool IsTempBreakPoint(u32 iAddress) const; |
| 36 | 36 | ||
| 37 | // Add BreakPoint | 37 | // Add BreakPoint |
| 38 | void Add(u32 em_address, bool temp=false); | 38 | void Add(u32 em_address, bool temp = false); |
| 39 | void Add(const TBreakPoint& bp); | 39 | void Add(const TBreakPoint& bp); |
| 40 | 40 | ||
| 41 | // Remove Breakpoint | 41 | // Remove Breakpoint |
| @@ -46,5 +46,5 @@ public: | |||
| 46 | 46 | ||
| 47 | private: | 47 | private: |
| 48 | TBreakPoints m_BreakPoints; | 48 | TBreakPoints m_BreakPoints; |
| 49 | u32 m_iBreakOnCount; | 49 | u32 m_iBreakOnCount; |
| 50 | }; | 50 | }; |
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h index 1e1bcff31..3b36c0a9e 100644 --- a/src/common/chunk_file.h +++ b/src/common/chunk_file.h | |||
| @@ -41,81 +41,86 @@ | |||
| 41 | #include "common/logging/log.h" | 41 | #include "common/logging/log.h" |
| 42 | 42 | ||
| 43 | template <class T> | 43 | template <class T> |
| 44 | struct LinkedListItem : public T | 44 | struct LinkedListItem : public T { |
| 45 | { | 45 | LinkedListItem<T>* next; |
| 46 | LinkedListItem<T> *next; | ||
| 47 | }; | 46 | }; |
| 48 | 47 | ||
| 49 | class PointerWrap; | 48 | class PointerWrap; |
| 50 | 49 | ||
| 51 | class PointerWrapSection | 50 | class PointerWrapSection { |
| 52 | { | ||
| 53 | public: | 51 | public: |
| 54 | PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { | 52 | PointerWrapSection(PointerWrap& p, int ver, const char* title) |
| 53 | : p_(p), ver_(ver), title_(title) { | ||
| 55 | } | 54 | } |
| 56 | ~PointerWrapSection(); | 55 | ~PointerWrapSection(); |
| 57 | 56 | ||
| 58 | bool operator == (const int &v) const { return ver_ == v; } | 57 | bool operator==(const int& v) const { |
| 59 | bool operator != (const int &v) const { return ver_ != v; } | 58 | return ver_ == v; |
| 60 | bool operator <= (const int &v) const { return ver_ <= v; } | 59 | } |
| 61 | bool operator >= (const int &v) const { return ver_ >= v; } | 60 | bool operator!=(const int& v) const { |
| 62 | bool operator < (const int &v) const { return ver_ < v; } | 61 | return ver_ != v; |
| 63 | bool operator > (const int &v) const { return ver_ > v; } | 62 | } |
| 63 | bool operator<=(const int& v) const { | ||
| 64 | return ver_ <= v; | ||
| 65 | } | ||
| 66 | bool operator>=(const int& v) const { | ||
| 67 | return ver_ >= v; | ||
| 68 | } | ||
| 69 | bool operator<(const int& v) const { | ||
| 70 | return ver_ < v; | ||
| 71 | } | ||
| 72 | bool operator>(const int& v) const { | ||
| 73 | return ver_ > v; | ||
| 74 | } | ||
| 64 | 75 | ||
| 65 | operator bool() const { | 76 | operator bool() const { |
| 66 | return ver_ > 0; | 77 | return ver_ > 0; |
| 67 | } | 78 | } |
| 68 | 79 | ||
| 69 | private: | 80 | private: |
| 70 | PointerWrap &p_; | 81 | PointerWrap& p_; |
| 71 | int ver_; | 82 | int ver_; |
| 72 | const char *title_; | 83 | const char* title_; |
| 73 | }; | 84 | }; |
| 74 | 85 | ||
| 75 | // Wrapper class | 86 | // Wrapper class |
| 76 | class PointerWrap | 87 | class PointerWrap { |
| 77 | { | 88 | // 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. | 89 | // 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 | 90 | #ifdef _MSC_VER |
| 81 | template<typename T, bool isPOD = std::is_pod<T>::value, bool isPointer = std::is_pointer<T>::value> | 91 | template <typename T, bool isPOD = std::is_pod<T>::value, |
| 92 | bool isPointer = std::is_pointer<T>::value> | ||
| 82 | #else | 93 | #else |
| 83 | template<typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value> | 94 | template <typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value> |
| 84 | #endif | 95 | #endif |
| 85 | struct DoHelper | 96 | struct DoHelper { |
| 86 | { | 97 | 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) | 98 | for (int i = 0; i < count; ++i) |
| 90 | p->Do(x[i]); | 99 | p->Do(x[i]); |
| 91 | } | 100 | } |
| 92 | 101 | ||
| 93 | static void Do(PointerWrap *p, T &x) | 102 | static void Do(PointerWrap* p, T& x) { |
| 94 | { | ||
| 95 | p->DoClass(x); | 103 | p->DoClass(x); |
| 96 | } | 104 | } |
| 97 | }; | 105 | }; |
| 98 | 106 | ||
| 99 | template<typename T> | 107 | template <typename T> |
| 100 | struct DoHelper<T, true, false> | 108 | struct DoHelper<T, true, false> { |
| 101 | { | 109 | static void DoArray(PointerWrap* p, T* x, int count) { |
| 102 | static void DoArray(PointerWrap *p, T *x, int count) | 110 | p->DoVoid((void*)x, sizeof(T) * count); |
| 103 | { | ||
| 104 | p->DoVoid((void *)x, sizeof(T) * count); | ||
| 105 | } | 111 | } |
| 106 | 112 | ||
| 107 | static void Do(PointerWrap *p, T &x) | 113 | static void Do(PointerWrap* p, T& x) { |
| 108 | { | 114 | p->DoVoid((void*)&x, sizeof(x)); |
| 109 | p->DoVoid((void *)&x, sizeof(x)); | ||
| 110 | } | 115 | } |
| 111 | }; | 116 | }; |
| 112 | 117 | ||
| 113 | public: | 118 | public: |
| 114 | enum Mode { | 119 | enum Mode { |
| 115 | MODE_READ = 1, // load | 120 | MODE_READ = 1, // load |
| 116 | MODE_WRITE, // save | 121 | MODE_WRITE, // save |
| 117 | MODE_MEASURE, // calculate size | 122 | MODE_MEASURE, // calculate size |
| 118 | MODE_VERIFY, // compare | 123 | MODE_VERIFY, // compare |
| 119 | }; | 124 | }; |
| 120 | 125 | ||
| 121 | enum Error { | 126 | enum Error { |
| @@ -124,247 +129,239 @@ public: | |||
| 124 | ERROR_FAILURE = 2, | 129 | ERROR_FAILURE = 2, |
| 125 | }; | 130 | }; |
| 126 | 131 | ||
| 127 | u8 **ptr; | 132 | u8** ptr; |
| 128 | Mode mode; | 133 | Mode mode; |
| 129 | Error error; | 134 | Error error; |
| 130 | 135 | ||
| 131 | public: | 136 | public: |
| 132 | PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} | 137 | 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) {} | 138 | } |
| 139 | PointerWrap(unsigned char** ptr_, int mode_) | ||
| 140 | : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) { | ||
| 141 | } | ||
| 134 | 142 | ||
| 135 | PointerWrapSection Section(const char *title, int ver) { | 143 | PointerWrapSection Section(const char* title, int ver) { |
| 136 | return Section(title, ver, ver); | 144 | return Section(title, ver, ver); |
| 137 | } | 145 | } |
| 138 | 146 | ||
| 139 | // The returned object can be compared against the version that was loaded. | 147 | // The returned object can be compared against the version that was loaded. |
| 140 | // This can be used to support versions as old as minVer. | 148 | // This can be used to support versions as old as minVer. |
| 141 | // Version = 0 means the section was not found. | 149 | // Version = 0 means the section was not found. |
| 142 | PointerWrapSection Section(const char *title, int minVer, int ver) { | 150 | PointerWrapSection Section(const char* title, int minVer, int ver) { |
| 143 | char marker[16] = {0}; | 151 | char marker[16] = {0}; |
| 144 | int foundVersion = ver; | 152 | int foundVersion = ver; |
| 145 | 153 | ||
| 146 | strncpy(marker, title, sizeof(marker)); | 154 | strncpy(marker, title, sizeof(marker)); |
| 147 | if (!ExpectVoid(marker, sizeof(marker))) | 155 | if (!ExpectVoid(marker, sizeof(marker))) { |
| 148 | { | ||
| 149 | // Might be before we added name markers for safety. | 156 | // Might be before we added name markers for safety. |
| 150 | if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) | 157 | if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) |
| 151 | DoMarker(title); | 158 | DoMarker(title); |
| 152 | // Wasn't found, but maybe we can still load the state. | 159 | // Wasn't found, but maybe we can still load the state. |
| 153 | else | 160 | else |
| 154 | foundVersion = 0; | 161 | foundVersion = 0; |
| 155 | } | 162 | } else |
| 156 | else | ||
| 157 | Do(foundVersion); | 163 | Do(foundVersion); |
| 158 | 164 | ||
| 159 | if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { | 165 | if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { |
| 160 | LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion, title); | 166 | LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion, |
| 167 | title); | ||
| 161 | SetError(ERROR_FAILURE); | 168 | SetError(ERROR_FAILURE); |
| 162 | return PointerWrapSection(*this, -1, title); | 169 | return PointerWrapSection(*this, -1, title); |
| 163 | } | 170 | } |
| 164 | return PointerWrapSection(*this, foundVersion, title); | 171 | return PointerWrapSection(*this, foundVersion, title); |
| 165 | } | 172 | } |
| 166 | 173 | ||
| 167 | void SetMode(Mode mode_) {mode = mode_;} | 174 | void SetMode(Mode mode_) { |
| 168 | Mode GetMode() const {return mode;} | 175 | mode = mode_; |
| 169 | u8 **GetPPtr() {return ptr;} | 176 | } |
| 170 | void SetError(Error error_) | 177 | Mode GetMode() const { |
| 171 | { | 178 | return mode; |
| 179 | } | ||
| 180 | u8** GetPPtr() { | ||
| 181 | return ptr; | ||
| 182 | } | ||
| 183 | void SetError(Error error_) { | ||
| 172 | if (error < error_) | 184 | if (error < error_) |
| 173 | error = error_; | 185 | error = error_; |
| 174 | if (error > ERROR_WARNING) | 186 | if (error > ERROR_WARNING) |
| 175 | mode = PointerWrap::MODE_MEASURE; | 187 | mode = PointerWrap::MODE_MEASURE; |
| 176 | } | 188 | } |
| 177 | 189 | ||
| 178 | bool ExpectVoid(void *data, int size) | 190 | bool ExpectVoid(void* data, int size) { |
| 179 | { | ||
| 180 | switch (mode) { | 191 | switch (mode) { |
| 181 | case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break; | 192 | case MODE_READ: |
| 182 | case MODE_WRITE: memcpy(*ptr, data, size); break; | 193 | if (memcmp(data, *ptr, size) != 0) |
| 183 | case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything | 194 | return false; |
| 195 | break; | ||
| 196 | case MODE_WRITE: | ||
| 197 | memcpy(*ptr, data, size); | ||
| 198 | break; | ||
| 199 | case MODE_MEASURE: | ||
| 200 | break; // MODE_MEASURE - don't need to do anything | ||
| 184 | case MODE_VERIFY: | 201 | case MODE_VERIFY: |
| 185 | for (int i = 0; i < size; i++) { | 202 | for (int i = 0; i < size; i++) { |
| 186 | DEBUG_ASSERT_MSG(((u8*)data)[i] == (*ptr)[i], | 203 | DEBUG_ASSERT_MSG( |
| 204 | ((u8*)data)[i] == (*ptr)[i], | ||
| 187 | "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", | 205 | "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", |
| 188 | ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], | 206 | ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], |
| 189 | (*ptr)[i], (*ptr)[i], &(*ptr)[i]); | 207 | &(*ptr)[i]); |
| 190 | } | 208 | } |
| 191 | break; | 209 | break; |
| 192 | default: break; // throw an error? | 210 | default: |
| 211 | break; // throw an error? | ||
| 193 | } | 212 | } |
| 194 | (*ptr) += size; | 213 | (*ptr) += size; |
| 195 | return true; | 214 | return true; |
| 196 | } | 215 | } |
| 197 | 216 | ||
| 198 | void DoVoid(void *data, int size) | 217 | void DoVoid(void* data, int size) { |
| 199 | { | ||
| 200 | switch (mode) { | 218 | switch (mode) { |
| 201 | case MODE_READ: memcpy(data, *ptr, size); break; | 219 | case MODE_READ: |
| 202 | case MODE_WRITE: memcpy(*ptr, data, size); break; | 220 | memcpy(data, *ptr, size); |
| 203 | case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything | 221 | break; |
| 222 | case MODE_WRITE: | ||
| 223 | memcpy(*ptr, data, size); | ||
| 224 | break; | ||
| 225 | case MODE_MEASURE: | ||
| 226 | break; // MODE_MEASURE - don't need to do anything | ||
| 204 | case MODE_VERIFY: | 227 | case MODE_VERIFY: |
| 205 | for (int i = 0; i < size; i++) { | 228 | for (int i = 0; i < size; i++) { |
| 206 | DEBUG_ASSERT_MSG(((u8*)data)[i] == (*ptr)[i], | 229 | DEBUG_ASSERT_MSG( |
| 230 | ((u8*)data)[i] == (*ptr)[i], | ||
| 207 | "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", | 231 | "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", |
| 208 | ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], | 232 | ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], |
| 209 | (*ptr)[i], (*ptr)[i], &(*ptr)[i]); | 233 | &(*ptr)[i]); |
| 210 | } | 234 | } |
| 211 | break; | 235 | break; |
| 212 | default: break; // throw an error? | 236 | default: |
| 237 | break; // throw an error? | ||
| 213 | } | 238 | } |
| 214 | (*ptr) += size; | 239 | (*ptr) += size; |
| 215 | } | 240 | } |
| 216 | 241 | ||
| 217 | template<class K, class T> | 242 | template <class K, class T> |
| 218 | void Do(std::map<K, T *> &x) | 243 | void Do(std::map<K, T*>& x) { |
| 219 | { | 244 | if (mode == MODE_READ) { |
| 220 | if (mode == MODE_READ) | 245 | 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) | 246 | if (it->second != nullptr) |
| 225 | delete it->second; | 247 | delete it->second; |
| 226 | } | 248 | } |
| 227 | } | 249 | } |
| 228 | T *dv = nullptr; | 250 | T* dv = nullptr; |
| 229 | DoMap(x, dv); | 251 | DoMap(x, dv); |
| 230 | } | 252 | } |
| 231 | 253 | ||
| 232 | template<class K, class T> | 254 | template <class K, class T> |
| 233 | void Do(std::map<K, T> &x) | 255 | void Do(std::map<K, T>& x) { |
| 234 | { | ||
| 235 | T dv = T(); | 256 | T dv = T(); |
| 236 | DoMap(x, dv); | 257 | DoMap(x, dv); |
| 237 | } | 258 | } |
| 238 | 259 | ||
| 239 | template<class K, class T> | 260 | template <class K, class T> |
| 240 | void DoMap(std::map<K, T> &x, T &default_val) | 261 | void DoMap(std::map<K, T>& x, T& default_val) { |
| 241 | { | ||
| 242 | unsigned int number = (unsigned int)x.size(); | 262 | unsigned int number = (unsigned int)x.size(); |
| 243 | Do(number); | 263 | Do(number); |
| 244 | switch (mode) { | 264 | switch (mode) { |
| 245 | case MODE_READ: | 265 | case MODE_READ: { |
| 246 | { | 266 | x.clear(); |
| 247 | x.clear(); | 267 | while (number > 0) { |
| 248 | while (number > 0) | 268 | K first = K(); |
| 249 | { | 269 | Do(first); |
| 250 | K first = K(); | 270 | T second = default_val; |
| 251 | Do(first); | 271 | Do(second); |
| 252 | T second = default_val; | 272 | x[first] = second; |
| 253 | Do(second); | 273 | --number; |
| 254 | x[first] = second; | ||
| 255 | --number; | ||
| 256 | } | ||
| 257 | } | 274 | } |
| 258 | break; | 275 | } break; |
| 259 | case MODE_WRITE: | 276 | case MODE_WRITE: |
| 260 | case MODE_MEASURE: | 277 | case MODE_MEASURE: |
| 261 | case MODE_VERIFY: | 278 | case MODE_VERIFY: { |
| 262 | { | 279 | typename std::map<K, T>::iterator itr = x.begin(); |
| 263 | typename std::map<K, T>::iterator itr = x.begin(); | 280 | while (number > 0) { |
| 264 | while (number > 0) | 281 | K first = itr->first; |
| 265 | { | 282 | Do(first); |
| 266 | K first = itr->first; | 283 | Do(itr->second); |
| 267 | Do(first); | 284 | --number; |
| 268 | Do(itr->second); | 285 | ++itr; |
| 269 | --number; | ||
| 270 | ++itr; | ||
| 271 | } | ||
| 272 | } | 286 | } |
| 273 | break; | 287 | } break; |
| 274 | } | 288 | } |
| 275 | } | 289 | } |
| 276 | 290 | ||
| 277 | template<class K, class T> | 291 | template <class K, class T> |
| 278 | void Do(std::multimap<K, T *> &x) | 292 | void Do(std::multimap<K, T*>& x) { |
| 279 | { | 293 | if (mode == MODE_READ) { |
| 280 | if (mode == MODE_READ) | 294 | 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) | 295 | if (it->second != nullptr) |
| 285 | delete it->second; | 296 | delete it->second; |
| 286 | } | 297 | } |
| 287 | } | 298 | } |
| 288 | T *dv = nullptr; | 299 | T* dv = nullptr; |
| 289 | DoMultimap(x, dv); | 300 | DoMultimap(x, dv); |
| 290 | } | 301 | } |
| 291 | 302 | ||
| 292 | template<class K, class T> | 303 | template <class K, class T> |
| 293 | void Do(std::multimap<K, T> &x) | 304 | void Do(std::multimap<K, T>& x) { |
| 294 | { | ||
| 295 | T dv = T(); | 305 | T dv = T(); |
| 296 | DoMultimap(x, dv); | 306 | DoMultimap(x, dv); |
| 297 | } | 307 | } |
| 298 | 308 | ||
| 299 | template<class K, class T> | 309 | template <class K, class T> |
| 300 | void DoMultimap(std::multimap<K, T> &x, T &default_val) | 310 | void DoMultimap(std::multimap<K, T>& x, T& default_val) { |
| 301 | { | ||
| 302 | unsigned int number = (unsigned int)x.size(); | 311 | unsigned int number = (unsigned int)x.size(); |
| 303 | Do(number); | 312 | Do(number); |
| 304 | switch (mode) { | 313 | switch (mode) { |
| 305 | case MODE_READ: | 314 | case MODE_READ: { |
| 306 | { | 315 | x.clear(); |
| 307 | x.clear(); | 316 | while (number > 0) { |
| 308 | while (number > 0) | 317 | K first = K(); |
| 309 | { | 318 | Do(first); |
| 310 | K first = K(); | 319 | T second = default_val; |
| 311 | Do(first); | 320 | Do(second); |
| 312 | T second = default_val; | 321 | x.insert(std::make_pair(first, second)); |
| 313 | Do(second); | 322 | --number; |
| 314 | x.insert(std::make_pair(first, second)); | ||
| 315 | --number; | ||
| 316 | } | ||
| 317 | } | 323 | } |
| 318 | break; | 324 | } break; |
| 319 | case MODE_WRITE: | 325 | case MODE_WRITE: |
| 320 | case MODE_MEASURE: | 326 | case MODE_MEASURE: |
| 321 | case MODE_VERIFY: | 327 | case MODE_VERIFY: { |
| 322 | { | 328 | typename std::multimap<K, T>::iterator itr = x.begin(); |
| 323 | typename std::multimap<K, T>::iterator itr = x.begin(); | 329 | while (number > 0) { |
| 324 | while (number > 0) | 330 | Do(itr->first); |
| 325 | { | 331 | Do(itr->second); |
| 326 | Do(itr->first); | 332 | --number; |
| 327 | Do(itr->second); | 333 | ++itr; |
| 328 | --number; | ||
| 329 | ++itr; | ||
| 330 | } | ||
| 331 | } | 334 | } |
| 332 | break; | 335 | } break; |
| 333 | } | 336 | } |
| 334 | } | 337 | } |
| 335 | 338 | ||
| 336 | // Store vectors. | 339 | // Store vectors. |
| 337 | template<class T> | 340 | template <class T> |
| 338 | void Do(std::vector<T *> &x) | 341 | void Do(std::vector<T*>& x) { |
| 339 | { | 342 | T* dv = nullptr; |
| 340 | T *dv = nullptr; | ||
| 341 | DoVector(x, dv); | 343 | DoVector(x, dv); |
| 342 | } | 344 | } |
| 343 | 345 | ||
| 344 | template<class T> | 346 | template <class T> |
| 345 | void Do(std::vector<T> &x) | 347 | void Do(std::vector<T>& x) { |
| 346 | { | ||
| 347 | T dv = T(); | 348 | T dv = T(); |
| 348 | DoVector(x, dv); | 349 | DoVector(x, dv); |
| 349 | } | 350 | } |
| 350 | 351 | ||
| 351 | 352 | template <class T> | |
| 352 | template<class T> | 353 | void DoPOD(std::vector<T>& x) { |
| 353 | void DoPOD(std::vector<T> &x) | ||
| 354 | { | ||
| 355 | T dv = T(); | 354 | T dv = T(); |
| 356 | DoVectorPOD(x, dv); | 355 | DoVectorPOD(x, dv); |
| 357 | } | 356 | } |
| 358 | 357 | ||
| 359 | template<class T> | 358 | template <class T> |
| 360 | void Do(std::vector<T> &x, T &default_val) | 359 | void Do(std::vector<T>& x, T& default_val) { |
| 361 | { | ||
| 362 | DoVector(x, default_val); | 360 | DoVector(x, default_val); |
| 363 | } | 361 | } |
| 364 | 362 | ||
| 365 | template<class T> | 363 | template <class T> |
| 366 | void DoVector(std::vector<T> &x, T &default_val) | 364 | void DoVector(std::vector<T>& x, T& default_val) { |
| 367 | { | ||
| 368 | u32 vec_size = (u32)x.size(); | 365 | u32 vec_size = (u32)x.size(); |
| 369 | Do(vec_size); | 366 | Do(vec_size); |
| 370 | x.resize(vec_size, default_val); | 367 | x.resize(vec_size, default_val); |
| @@ -372,9 +369,8 @@ public: | |||
| 372 | DoArray(&x[0], vec_size); | 369 | DoArray(&x[0], vec_size); |
| 373 | } | 370 | } |
| 374 | 371 | ||
| 375 | template<class T> | 372 | template <class T> |
| 376 | void DoVectorPOD(std::vector<T> &x, T &default_val) | 373 | void DoVectorPOD(std::vector<T>& x, T& default_val) { |
| 377 | { | ||
| 378 | u32 vec_size = (u32)x.size(); | 374 | u32 vec_size = (u32)x.size(); |
| 379 | Do(vec_size); | 375 | Do(vec_size); |
| 380 | x.resize(vec_size, default_val); | 376 | x.resize(vec_size, default_val); |
| @@ -383,55 +379,48 @@ public: | |||
| 383 | } | 379 | } |
| 384 | 380 | ||
| 385 | // Store deques. | 381 | // Store deques. |
| 386 | template<class T> | 382 | template <class T> |
| 387 | void Do(std::deque<T *> &x) | 383 | void Do(std::deque<T*>& x) { |
| 388 | { | 384 | T* dv = nullptr; |
| 389 | T *dv = nullptr; | ||
| 390 | DoDeque(x, dv); | 385 | DoDeque(x, dv); |
| 391 | } | 386 | } |
| 392 | 387 | ||
| 393 | template<class T> | 388 | template <class T> |
| 394 | void Do(std::deque<T> &x) | 389 | void Do(std::deque<T>& x) { |
| 395 | { | ||
| 396 | T dv = T(); | 390 | T dv = T(); |
| 397 | DoDeque(x, dv); | 391 | DoDeque(x, dv); |
| 398 | } | 392 | } |
| 399 | 393 | ||
| 400 | template<class T> | 394 | template <class T> |
| 401 | void DoDeque(std::deque<T> &x, T &default_val) | 395 | void DoDeque(std::deque<T>& x, T& default_val) { |
| 402 | { | ||
| 403 | u32 deq_size = (u32)x.size(); | 396 | u32 deq_size = (u32)x.size(); |
| 404 | Do(deq_size); | 397 | Do(deq_size); |
| 405 | x.resize(deq_size, default_val); | 398 | x.resize(deq_size, default_val); |
| 406 | u32 i; | 399 | u32 i; |
| 407 | for(i = 0; i < deq_size; i++) | 400 | for (i = 0; i < deq_size; i++) |
| 408 | Do(x[i]); | 401 | Do(x[i]); |
| 409 | } | 402 | } |
| 410 | 403 | ||
| 411 | // Store STL lists. | 404 | // Store STL lists. |
| 412 | template<class T> | 405 | template <class T> |
| 413 | void Do(std::list<T *> &x) | 406 | void Do(std::list<T*>& x) { |
| 414 | { | 407 | T* dv = nullptr; |
| 415 | T *dv = nullptr; | ||
| 416 | Do(x, dv); | 408 | Do(x, dv); |
| 417 | } | 409 | } |
| 418 | 410 | ||
| 419 | template<class T> | 411 | template <class T> |
| 420 | void Do(std::list<T> &x) | 412 | void Do(std::list<T>& x) { |
| 421 | { | ||
| 422 | T dv = T(); | 413 | T dv = T(); |
| 423 | DoList(x, dv); | 414 | DoList(x, dv); |
| 424 | } | 415 | } |
| 425 | 416 | ||
| 426 | template<class T> | 417 | template <class T> |
| 427 | void Do(std::list<T> &x, T &default_val) | 418 | void Do(std::list<T>& x, T& default_val) { |
| 428 | { | ||
| 429 | DoList(x, default_val); | 419 | DoList(x, default_val); |
| 430 | } | 420 | } |
| 431 | 421 | ||
| 432 | template<class T> | 422 | template <class T> |
| 433 | void DoList(std::list<T> &x, T &default_val) | 423 | void DoList(std::list<T>& x, T& default_val) { |
| 434 | { | ||
| 435 | u32 list_size = (u32)x.size(); | 424 | u32 list_size = (u32)x.size(); |
| 436 | Do(list_size); | 425 | Do(list_size); |
| 437 | x.resize(list_size, default_val); | 426 | x.resize(list_size, default_val); |
| @@ -441,15 +430,11 @@ public: | |||
| 441 | Do(*itr); | 430 | Do(*itr); |
| 442 | } | 431 | } |
| 443 | 432 | ||
| 444 | |||
| 445 | // Store STL sets. | 433 | // Store STL sets. |
| 446 | template <class T> | 434 | template <class T> |
| 447 | void Do(std::set<T *> &x) | 435 | void Do(std::set<T*>& x) { |
| 448 | { | 436 | if (mode == MODE_READ) { |
| 449 | if (mode == MODE_READ) | 437 | 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) | 438 | if (*it != nullptr) |
| 454 | delete *it; | 439 | delete *it; |
| 455 | } | 440 | } |
| @@ -458,39 +443,31 @@ public: | |||
| 458 | } | 443 | } |
| 459 | 444 | ||
| 460 | template <class T> | 445 | template <class T> |
| 461 | void Do(std::set<T> &x) | 446 | void Do(std::set<T>& x) { |
| 462 | { | ||
| 463 | DoSet(x); | 447 | DoSet(x); |
| 464 | } | 448 | } |
| 465 | 449 | ||
| 466 | template <class T> | 450 | template <class T> |
| 467 | void DoSet(std::set<T> &x) | 451 | void DoSet(std::set<T>& x) { |
| 468 | { | ||
| 469 | unsigned int number = (unsigned int)x.size(); | 452 | unsigned int number = (unsigned int)x.size(); |
| 470 | Do(number); | 453 | Do(number); |
| 471 | 454 | ||
| 472 | switch (mode) | 455 | switch (mode) { |
| 473 | { | 456 | case MODE_READ: { |
| 474 | case MODE_READ: | 457 | x.clear(); |
| 475 | { | 458 | while (number-- > 0) { |
| 476 | x.clear(); | 459 | T it = T(); |
| 477 | while (number-- > 0) | 460 | Do(it); |
| 478 | { | 461 | x.insert(it); |
| 479 | T it = T(); | ||
| 480 | Do(it); | ||
| 481 | x.insert(it); | ||
| 482 | } | ||
| 483 | } | 462 | } |
| 484 | break; | 463 | } break; |
| 485 | case MODE_WRITE: | 464 | case MODE_WRITE: |
| 486 | case MODE_MEASURE: | 465 | case MODE_MEASURE: |
| 487 | case MODE_VERIFY: | 466 | case MODE_VERIFY: { |
| 488 | { | 467 | typename std::set<T>::iterator itr = x.begin(); |
| 489 | typename std::set<T>::iterator itr = x.begin(); | 468 | while (number-- > 0) |
| 490 | while (number-- > 0) | 469 | Do(*itr++); |
| 491 | Do(*itr++); | 470 | } break; |
| 492 | } | ||
| 493 | break; | ||
| 494 | 471 | ||
| 495 | default: | 472 | default: |
| 496 | LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode); | 473 | LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode); |
| @@ -498,51 +475,58 @@ public: | |||
| 498 | } | 475 | } |
| 499 | 476 | ||
| 500 | // Store strings. | 477 | // Store strings. |
| 501 | void Do(std::string &x) | 478 | void Do(std::string& x) { |
| 502 | { | ||
| 503 | int stringLen = (int)x.length() + 1; | 479 | int stringLen = (int)x.length() + 1; |
| 504 | Do(stringLen); | 480 | Do(stringLen); |
| 505 | 481 | ||
| 506 | switch (mode) { | 482 | switch (mode) { |
| 507 | case MODE_READ: x = (char*)*ptr; break; | 483 | case MODE_READ: |
| 508 | case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; | 484 | x = (char*)*ptr; |
| 509 | case MODE_MEASURE: break; | 485 | break; |
| 486 | case MODE_WRITE: | ||
| 487 | memcpy(*ptr, x.c_str(), stringLen); | ||
| 488 | break; | ||
| 489 | case MODE_MEASURE: | ||
| 490 | break; | ||
| 510 | case MODE_VERIFY: | 491 | case MODE_VERIFY: |
| 511 | DEBUG_ASSERT_MSG((x == (char*)*ptr), | 492 | DEBUG_ASSERT_MSG((x == (char*)*ptr), |
| 512 | "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", | 493 | "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", |
| 513 | x.c_str(), (char*)*ptr, ptr); | 494 | x.c_str(), (char*)*ptr, ptr); |
| 514 | break; | 495 | break; |
| 515 | } | 496 | } |
| 516 | (*ptr) += stringLen; | 497 | (*ptr) += stringLen; |
| 517 | } | 498 | } |
| 518 | 499 | ||
| 519 | void Do(std::wstring &x) | 500 | void Do(std::wstring& x) { |
| 520 | { | 501 | int stringLen = sizeof(wchar_t) * ((int)x.length() + 1); |
| 521 | int stringLen = sizeof(wchar_t)*((int)x.length() + 1); | ||
| 522 | Do(stringLen); | 502 | Do(stringLen); |
| 523 | 503 | ||
| 524 | switch (mode) { | 504 | switch (mode) { |
| 525 | case MODE_READ: x = (wchar_t*)*ptr; break; | 505 | case MODE_READ: |
| 526 | case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; | 506 | x = (wchar_t*)*ptr; |
| 527 | case MODE_MEASURE: break; | 507 | break; |
| 508 | case MODE_WRITE: | ||
| 509 | memcpy(*ptr, x.c_str(), stringLen); | ||
| 510 | break; | ||
| 511 | case MODE_MEASURE: | ||
| 512 | break; | ||
| 528 | case MODE_VERIFY: | 513 | case MODE_VERIFY: |
| 529 | DEBUG_ASSERT_MSG((x == (wchar_t*)*ptr), | 514 | DEBUG_ASSERT_MSG((x == (wchar_t*)*ptr), |
| 530 | "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", | 515 | "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", |
| 531 | x.c_str(), (wchar_t*)*ptr, ptr); | 516 | x.c_str(), (wchar_t*)*ptr, ptr); |
| 532 | break; | 517 | break; |
| 533 | } | 518 | } |
| 534 | (*ptr) += stringLen; | 519 | (*ptr) += stringLen; |
| 535 | } | 520 | } |
| 536 | 521 | ||
| 537 | template<class T> | 522 | template <class T> |
| 538 | void DoClass(T &x) { | 523 | void DoClass(T& x) { |
| 539 | x.DoState(*this); | 524 | x.DoState(*this); |
| 540 | } | 525 | } |
| 541 | 526 | ||
| 542 | template<class T> | 527 | template <class T> |
| 543 | void DoClass(T *&x) { | 528 | void DoClass(T*& x) { |
| 544 | if (mode == MODE_READ) | 529 | if (mode == MODE_READ) { |
| 545 | { | ||
| 546 | if (x != nullptr) | 530 | if (x != nullptr) |
| 547 | delete x; | 531 | delete x; |
| 548 | x = new T(); | 532 | x = new T(); |
| @@ -550,81 +534,70 @@ public: | |||
| 550 | x->DoState(*this); | 534 | x->DoState(*this); |
| 551 | } | 535 | } |
| 552 | 536 | ||
| 553 | template<class T> | 537 | template <class T> |
| 554 | void DoArray(T *x, int count) { | 538 | void DoArray(T* x, int count) { |
| 555 | DoHelper<T>::DoArray(this, x, count); | 539 | DoHelper<T>::DoArray(this, x, count); |
| 556 | } | 540 | } |
| 557 | 541 | ||
| 558 | template<class T> | 542 | template <class T> |
| 559 | void Do(T &x) { | 543 | void Do(T& x) { |
| 560 | DoHelper<T>::Do(this, x); | 544 | DoHelper<T>::Do(this, x); |
| 561 | } | 545 | } |
| 562 | 546 | ||
| 563 | template<class T> | 547 | template <class T> |
| 564 | void DoPOD(T &x) { | 548 | void DoPOD(T& x) { |
| 565 | DoHelper<T>::Do(this, x); | 549 | DoHelper<T>::Do(this, x); |
| 566 | } | 550 | } |
| 567 | 551 | ||
| 568 | template<class T> | 552 | template <class T> |
| 569 | void DoPointer(T* &x, T*const base) { | 553 | 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 | 554 | // pointers can be more than 2^31 apart, but you're using this function wrong if you need |
| 555 | // that much range | ||
| 571 | s32 offset = x - base; | 556 | s32 offset = x - base; |
| 572 | Do(offset); | 557 | Do(offset); |
| 573 | if (mode == MODE_READ) | 558 | if (mode == MODE_READ) |
| 574 | x = base + offset; | 559 | x = base + offset; |
| 575 | } | 560 | } |
| 576 | 561 | ||
| 577 | template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)> | 562 | template <class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), |
| 578 | void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr) | 563 | void (*TDo)(PointerWrap&, T*)> |
| 579 | { | 564 | void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr) { |
| 580 | LinkedListItem<T>* list_cur = list_start; | 565 | LinkedListItem<T>* list_cur = list_start; |
| 581 | LinkedListItem<T>* prev = nullptr; | 566 | LinkedListItem<T>* prev = nullptr; |
| 582 | 567 | ||
| 583 | while (true) | 568 | while (true) { |
| 584 | { | ||
| 585 | u8 shouldExist = (list_cur ? 1 : 0); | 569 | u8 shouldExist = (list_cur ? 1 : 0); |
| 586 | Do(shouldExist); | 570 | Do(shouldExist); |
| 587 | if (shouldExist == 1) | 571 | if (shouldExist == 1) { |
| 588 | { | ||
| 589 | LinkedListItem<T>* cur = list_cur ? list_cur : TNew(); | 572 | LinkedListItem<T>* cur = list_cur ? list_cur : TNew(); |
| 590 | TDo(*this, (T*)cur); | 573 | TDo(*this, (T*)cur); |
| 591 | if (!list_cur) | 574 | if (!list_cur) { |
| 592 | { | 575 | if (mode == MODE_READ) { |
| 593 | if (mode == MODE_READ) | ||
| 594 | { | ||
| 595 | cur->next = nullptr; | 576 | cur->next = nullptr; |
| 596 | list_cur = cur; | 577 | list_cur = cur; |
| 597 | if (prev) | 578 | if (prev) |
| 598 | prev->next = cur; | 579 | prev->next = cur; |
| 599 | else | 580 | else |
| 600 | list_start = cur; | 581 | list_start = cur; |
| 601 | } | 582 | } else { |
| 602 | else | ||
| 603 | { | ||
| 604 | TFree(cur); | 583 | TFree(cur); |
| 605 | continue; | 584 | continue; |
| 606 | } | 585 | } |
| 607 | } | 586 | } |
| 608 | } | 587 | } else { |
| 609 | else | 588 | if (mode == MODE_READ) { |
| 610 | { | ||
| 611 | if (mode == MODE_READ) | ||
| 612 | { | ||
| 613 | if (prev) | 589 | if (prev) |
| 614 | prev->next = nullptr; | 590 | prev->next = nullptr; |
| 615 | if (list_end) | 591 | if (list_end) |
| 616 | *list_end = prev; | 592 | *list_end = prev; |
| 617 | if (list_cur) | 593 | if (list_cur) { |
| 618 | { | ||
| 619 | if (list_start == list_cur) | 594 | if (list_start == list_cur) |
| 620 | list_start = nullptr; | 595 | list_start = nullptr; |
| 621 | do | 596 | do { |
| 622 | { | ||
| 623 | LinkedListItem<T>* next = list_cur->next; | 597 | LinkedListItem<T>* next = list_cur->next; |
| 624 | TFree(list_cur); | 598 | TFree(list_cur); |
| 625 | list_cur = next; | 599 | list_cur = next; |
| 626 | } | 600 | } while (list_cur); |
| 627 | while (list_cur); | ||
| 628 | } | 601 | } |
| 629 | } | 602 | } |
| 630 | break; | 603 | break; |
| @@ -634,13 +607,13 @@ public: | |||
| 634 | } | 607 | } |
| 635 | } | 608 | } |
| 636 | 609 | ||
| 637 | void DoMarker(const char* prevName, u32 arbitraryNumber=0x42) | 610 | void DoMarker(const char* prevName, u32 arbitraryNumber = 0x42) { |
| 638 | { | ||
| 639 | u32 cookie = arbitraryNumber; | 611 | u32 cookie = arbitraryNumber; |
| 640 | Do(cookie); | 612 | Do(cookie); |
| 641 | if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) | 613 | if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) { |
| 642 | { | 614 | 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); | 615 | "Aborting savestate load...", |
| 616 | prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); | ||
| 644 | SetError(ERROR_FAILURE); | 617 | SetError(ERROR_FAILURE); |
| 645 | } | 618 | } |
| 646 | } | 619 | } |
diff --git a/src/common/code_block.h b/src/common/code_block.h index 2fa4a0090..58696737e 100644 --- a/src/common/code_block.h +++ b/src/common/code_block.h | |||
| @@ -14,24 +14,28 @@ | |||
| 14 | // having to prefix them with gen-> or something similar. | 14 | // having to prefix them with gen-> or something similar. |
| 15 | // Example implementation: | 15 | // Example implementation: |
| 16 | // class JIT : public CodeBlock<ARMXEmitter> {} | 16 | // class JIT : public CodeBlock<ARMXEmitter> {} |
| 17 | template<class T> class CodeBlock : public T, NonCopyable | 17 | template <class T> |
| 18 | { | 18 | class CodeBlock : public T, NonCopyable { |
| 19 | private: | 19 | private: |
| 20 | // A privately used function to set the executable RAM space to something invalid. | 20 | // 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 | 21 | // For debugging usefulness it should be used to set the RAM to a host specific breakpoint |
| 22 | // instruction | ||
| 22 | virtual void PoisonMemory() = 0; | 23 | virtual void PoisonMemory() = 0; |
| 23 | 24 | ||
| 24 | protected: | 25 | protected: |
| 25 | u8 *region; | 26 | u8* region; |
| 26 | size_t region_size; | 27 | size_t region_size; |
| 27 | 28 | ||
| 28 | public: | 29 | public: |
| 29 | CodeBlock() : region(nullptr), region_size(0) {} | 30 | CodeBlock() : region(nullptr), region_size(0) { |
| 30 | virtual ~CodeBlock() { if (region) FreeCodeSpace(); } | 31 | } |
| 32 | virtual ~CodeBlock() { | ||
| 33 | if (region) | ||
| 34 | FreeCodeSpace(); | ||
| 35 | } | ||
| 31 | 36 | ||
| 32 | // Call this before you generate any code. | 37 | // Call this before you generate any code. |
| 33 | void AllocCodeSpace(int size) | 38 | void AllocCodeSpace(int size) { |
| 34 | { | ||
| 35 | region_size = size; | 39 | region_size = size; |
| 36 | region = (u8*)AllocateExecutableMemory(region_size); | 40 | region = (u8*)AllocateExecutableMemory(region_size); |
| 37 | T::SetCodePtr(region); | 41 | T::SetCodePtr(region); |
| @@ -39,15 +43,13 @@ public: | |||
| 39 | 43 | ||
| 40 | // Always clear code space with breakpoints, so that if someone accidentally executes | 44 | // Always clear code space with breakpoints, so that if someone accidentally executes |
| 41 | // uninitialized, it just breaks into the debugger. | 45 | // uninitialized, it just breaks into the debugger. |
| 42 | void ClearCodeSpace() | 46 | void ClearCodeSpace() { |
| 43 | { | ||
| 44 | PoisonMemory(); | 47 | PoisonMemory(); |
| 45 | ResetCodePtr(); | 48 | ResetCodePtr(); |
| 46 | } | 49 | } |
| 47 | 50 | ||
| 48 | // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. | 51 | // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. |
| 49 | void FreeCodeSpace() | 52 | void FreeCodeSpace() { |
| 50 | { | ||
| 51 | #ifdef __SYMBIAN32__ | 53 | #ifdef __SYMBIAN32__ |
| 52 | ResetExecutableMemory(region); | 54 | ResetExecutableMemory(region); |
| 53 | #else | 55 | #else |
| @@ -57,33 +59,29 @@ public: | |||
| 57 | region_size = 0; | 59 | region_size = 0; |
| 58 | } | 60 | } |
| 59 | 61 | ||
| 60 | bool IsInSpace(const u8 *ptr) | 62 | bool IsInSpace(const u8* ptr) { |
| 61 | { | ||
| 62 | return (ptr >= region) && (ptr < (region + region_size)); | 63 | return (ptr >= region) && (ptr < (region + region_size)); |
| 63 | } | 64 | } |
| 64 | 65 | ||
| 65 | // Cannot currently be undone. Will write protect the entire code region. | 66 | // Cannot currently be undone. Will write protect the entire code region. |
| 66 | // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). | 67 | // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). |
| 67 | void WriteProtect() | 68 | void WriteProtect() { |
| 68 | { | ||
| 69 | WriteProtectMemory(region, region_size, true); | 69 | WriteProtectMemory(region, region_size, true); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | void ResetCodePtr() | 72 | void ResetCodePtr() { |
| 73 | { | ||
| 74 | T::SetCodePtr(region); | 73 | T::SetCodePtr(region); |
| 75 | } | 74 | } |
| 76 | 75 | ||
| 77 | size_t GetSpaceLeft() const | 76 | size_t GetSpaceLeft() const { |
| 78 | { | ||
| 79 | return region_size - (T::GetCodePtr() - region); | 77 | return region_size - (T::GetCodePtr() - region); |
| 80 | } | 78 | } |
| 81 | 79 | ||
| 82 | u8 *GetBasePtr() { | 80 | u8* GetBasePtr() { |
| 83 | return region; | 81 | return region; |
| 84 | } | 82 | } |
| 85 | 83 | ||
| 86 | size_t GetOffset(const u8 *ptr) const { | 84 | size_t GetOffset(const u8* ptr) const { |
| 87 | return ptr - region; | 85 | return ptr - region; |
| 88 | } | 86 | } |
| 89 | }; | 87 | }; |
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..ad5bdbc08 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | /// Textually concatenates two tokens. The double-expansion is required by the C preprocessor. | 15 | /// Textually concatenates two tokens. The double-expansion is required by the C preprocessor. |
| 16 | #define CONCAT2(x, y) DO_CONCAT2(x, y) | 16 | #define CONCAT2(x, y) DO_CONCAT2(x, y) |
| 17 | #define DO_CONCAT2(x, y) x ## y | 17 | #define DO_CONCAT2(x, y) x##y |
| 18 | 18 | ||
| 19 | // helper macro to properly align structure members. | 19 | // helper macro to properly align structure members. |
| 20 | // Calling INSERT_PADDING_BYTES will add a new member variable with a name like "pad121", | 20 | // Calling INSERT_PADDING_BYTES will add a new member variable with a name like "pad121", |
| @@ -24,9 +24,9 @@ | |||
| 24 | 24 | ||
| 25 | // Inlining | 25 | // Inlining |
| 26 | #ifdef _WIN32 | 26 | #ifdef _WIN32 |
| 27 | #define FORCE_INLINE __forceinline | 27 | #define FORCE_INLINE __forceinline |
| 28 | #else | 28 | #else |
| 29 | #define FORCE_INLINE inline __attribute__((always_inline)) | 29 | #define FORCE_INLINE inline __attribute__((always_inline)) |
| 30 | #endif | 30 | #endif |
| 31 | 31 | ||
| 32 | #ifndef _MSC_VER | 32 | #ifndef _MSC_VER |
| @@ -46,7 +46,8 @@ | |||
| 46 | #else | 46 | #else |
| 47 | inline u32 rotl(u32 x, int shift) { | 47 | inline u32 rotl(u32 x, int shift) { |
| 48 | shift &= 31; | 48 | shift &= 31; |
| 49 | if (!shift) return x; | 49 | if (!shift) |
| 50 | return x; | ||
| 50 | return (x << shift) | (x >> (32 - shift)); | 51 | return (x << shift) | (x >> (32 - shift)); |
| 51 | } | 52 | } |
| 52 | #endif | 53 | #endif |
| @@ -56,17 +57,18 @@ inline u32 rotl(u32 x, int shift) { | |||
| 56 | #else | 57 | #else |
| 57 | inline u32 rotr(u32 x, int shift) { | 58 | inline u32 rotr(u32 x, int shift) { |
| 58 | shift &= 31; | 59 | shift &= 31; |
| 59 | if (!shift) return x; | 60 | if (!shift) |
| 61 | return x; | ||
| 60 | return (x >> shift) | (x << (32 - shift)); | 62 | return (x >> shift) | (x << (32 - shift)); |
| 61 | } | 63 | } |
| 62 | #endif | 64 | #endif |
| 63 | 65 | ||
| 64 | inline u64 _rotl64(u64 x, unsigned int shift){ | 66 | inline u64 _rotl64(u64 x, unsigned int shift) { |
| 65 | unsigned int n = shift % 64; | 67 | unsigned int n = shift % 64; |
| 66 | return (x << n) | (x >> (64 - n)); | 68 | return (x << n) | (x >> (64 - n)); |
| 67 | } | 69 | } |
| 68 | 70 | ||
| 69 | inline u64 _rotr64(u64 x, unsigned int shift){ | 71 | inline u64 _rotr64(u64 x, unsigned int shift) { |
| 70 | unsigned int n = shift % 64; | 72 | unsigned int n = shift % 64; |
| 71 | return (x >> n) | (x << (64 - n)); | 73 | return (x >> n) | (x << (64 - n)); |
| 72 | } | 74 | } |
| @@ -74,17 +76,18 @@ inline u64 _rotr64(u64 x, unsigned int shift){ | |||
| 74 | #else // _MSC_VER | 76 | #else // _MSC_VER |
| 75 | 77 | ||
| 76 | #if (_MSC_VER < 1900) | 78 | #if (_MSC_VER < 1900) |
| 77 | // Function Cross-Compatibility | 79 | // Function Cross-Compatibility |
| 78 | #define snprintf _snprintf | 80 | #define snprintf _snprintf |
| 79 | #endif | 81 | #endif |
| 80 | 82 | ||
| 81 | // Locale Cross-Compatibility | 83 | // Locale Cross-Compatibility |
| 82 | #define locale_t _locale_t | 84 | #define locale_t _locale_t |
| 83 | 85 | ||
| 84 | extern "C" { | 86 | extern "C" { |
| 85 | __declspec(dllimport) void __stdcall DebugBreak(void); | 87 | __declspec(dllimport) void __stdcall DebugBreak(void); |
| 86 | } | 88 | } |
| 87 | #define Crash() {DebugBreak();} | 89 | #define Crash() \ |
| 90 | { DebugBreak(); } | ||
| 88 | 91 | ||
| 89 | // cstdlib provides these on MSVC | 92 | // cstdlib provides these on MSVC |
| 90 | #define rotr _rotr | 93 | #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..c86f663a8 100644 --- a/src/common/emu_window.cpp +++ b/src/common/emu_window.cpp | |||
| @@ -44,18 +44,17 @@ void EmuWindow::CirclePadUpdated(float x, float y) { | |||
| 44 | */ | 44 | */ |
| 45 | static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsigned framebuffer_x, | 45 | static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsigned framebuffer_x, |
| 46 | unsigned framebuffer_y) { | 46 | unsigned framebuffer_y) { |
| 47 | return (framebuffer_y >= layout.bottom_screen.top && | 47 | return ( |
| 48 | framebuffer_y < layout.bottom_screen.bottom && | 48 | framebuffer_y >= layout.bottom_screen.top && framebuffer_y < layout.bottom_screen.bottom && |
| 49 | framebuffer_x >= layout.bottom_screen.left && | 49 | framebuffer_x >= layout.bottom_screen.left && framebuffer_x < layout.bottom_screen.right); |
| 50 | framebuffer_x < layout.bottom_screen.right); | ||
| 51 | } | 50 | } |
| 52 | 51 | ||
| 53 | std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { | 52 | std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { |
| 54 | new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); | 53 | new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); |
| 55 | new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1); | 54 | new_x = std::min(new_x, framebuffer_layout.bottom_screen.right - 1); |
| 56 | 55 | ||
| 57 | new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); | 56 | new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); |
| 58 | new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1); | 57 | new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom - 1); |
| 59 | 58 | ||
| 60 | return std::make_tuple(new_x, new_y); | 59 | return std::make_tuple(new_x, new_y); |
| 61 | } | 60 | } |
| @@ -64,10 +63,12 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { | |||
| 64 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) | 63 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) |
| 65 | return; | 64 | return; |
| 66 | 65 | ||
| 67 | touch_x = VideoCore::kScreenBottomWidth * (framebuffer_x - framebuffer_layout.bottom_screen.left) / | 66 | touch_x = VideoCore::kScreenBottomWidth * |
| 68 | (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); | 67 | (framebuffer_x - framebuffer_layout.bottom_screen.left) / |
| 69 | touch_y = VideoCore::kScreenBottomHeight * (framebuffer_y - framebuffer_layout.bottom_screen.top) / | 68 | (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); |
| 70 | (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); | 69 | touch_y = VideoCore::kScreenBottomHeight * |
| 70 | (framebuffer_y - framebuffer_layout.bottom_screen.top) / | ||
| 71 | (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); | ||
| 71 | 72 | ||
| 72 | touch_pressed = true; | 73 | touch_pressed = true; |
| 73 | pad_state.touch.Assign(1); | 74 | pad_state.touch.Assign(1); |
| @@ -90,16 +91,19 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { | |||
| 90 | TouchPressed(framebuffer_x, framebuffer_y); | 91 | TouchPressed(framebuffer_x, framebuffer_y); |
| 91 | } | 92 | } |
| 92 | 93 | ||
| 93 | EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) { | 94 | EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, |
| 95 | unsigned height) { | ||
| 94 | // When hiding the widget, the function receives a size of 0 | 96 | // When hiding the widget, the function receives a size of 0 |
| 95 | if (width == 0) width = 1; | 97 | if (width == 0) |
| 96 | if (height == 0) height = 1; | 98 | width = 1; |
| 99 | if (height == 0) | ||
| 100 | height = 1; | ||
| 97 | 101 | ||
| 98 | EmuWindow::FramebufferLayout res = { width, height, {}, {} }; | 102 | EmuWindow::FramebufferLayout res = {width, height, {}, {}}; |
| 99 | 103 | ||
| 100 | float window_aspect_ratio = static_cast<float>(height) / width; | 104 | float window_aspect_ratio = static_cast<float>(height) / width; |
| 101 | float emulation_aspect_ratio = static_cast<float>(VideoCore::kScreenTopHeight * 2) / | 105 | float emulation_aspect_ratio = |
| 102 | VideoCore::kScreenTopWidth; | 106 | static_cast<float>(VideoCore::kScreenTopHeight * 2) / VideoCore::kScreenTopWidth; |
| 103 | 107 | ||
| 104 | if (window_aspect_ratio > emulation_aspect_ratio) { | 108 | if (window_aspect_ratio > emulation_aspect_ratio) { |
| 105 | // Window is narrower than the emulation content => apply borders to the top and bottom | 109 | // Window is narrower than the emulation content => apply borders to the top and bottom |
| @@ -110,8 +114,9 @@ EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(u | |||
| 110 | res.top_screen.top = (height - viewport_height) / 2; | 114 | res.top_screen.top = (height - viewport_height) / 2; |
| 111 | res.top_screen.bottom = res.top_screen.top + viewport_height / 2; | 115 | res.top_screen.bottom = res.top_screen.top + viewport_height / 2; |
| 112 | 116 | ||
| 113 | int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) / | 117 | int bottom_width = static_cast<int>( |
| 114 | VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left)); | 118 | (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth) * |
| 119 | (res.top_screen.right - res.top_screen.left)); | ||
| 115 | int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; | 120 | int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; |
| 116 | 121 | ||
| 117 | res.bottom_screen.left = bottom_border; | 122 | res.bottom_screen.left = bottom_border; |
| @@ -127,8 +132,9 @@ EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(u | |||
| 127 | res.top_screen.top = 0; | 132 | res.top_screen.top = 0; |
| 128 | res.top_screen.bottom = res.top_screen.top + height / 2; | 133 | res.top_screen.bottom = res.top_screen.top + height / 2; |
| 129 | 134 | ||
| 130 | int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) / | 135 | int bottom_width = static_cast<int>( |
| 131 | VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left)); | 136 | (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth) * |
| 137 | (res.top_screen.right - res.top_screen.left)); | ||
| 132 | int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; | 138 | int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; |
| 133 | 139 | ||
| 134 | res.bottom_screen.left = res.top_screen.left + bottom_border; | 140 | 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..de8badd4f 100644 --- a/src/common/emu_window.h +++ b/src/common/emu_window.h | |||
| @@ -30,15 +30,14 @@ | |||
| 30 | * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please | 30 | * - 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. | 31 | * re-read the upper points again and think about it if you don't see this. |
| 32 | */ | 32 | */ |
| 33 | class EmuWindow | 33 | class EmuWindow { |
| 34 | { | ||
| 35 | public: | 34 | public: |
| 36 | /// Data structure to store emuwindow configuration | 35 | /// Data structure to store emuwindow configuration |
| 37 | struct WindowConfig { | 36 | struct WindowConfig { |
| 38 | bool fullscreen; | 37 | bool fullscreen; |
| 39 | int res_width; | 38 | int res_width; |
| 40 | int res_height; | 39 | int res_height; |
| 41 | std::pair<unsigned,unsigned> min_client_area_size; | 40 | std::pair<unsigned, unsigned> min_client_area_size; |
| 42 | }; | 41 | }; |
| 43 | 42 | ||
| 44 | /// Describes the layout of the window framebuffer (size and top/bottom screen positions) | 43 | /// Describes the layout of the window framebuffer (size and top/bottom screen positions) |
| @@ -193,15 +192,18 @@ public: | |||
| 193 | 192 | ||
| 194 | /** | 193 | /** |
| 195 | * Returns currently active configuration. | 194 | * Returns currently active configuration. |
| 196 | * @note Accesses to the returned object need not be consistent because it may be modified in another thread | 195 | * @note Accesses to the returned object need not be consistent because it may be modified in |
| 196 | * another thread | ||
| 197 | */ | 197 | */ |
| 198 | const WindowConfig& GetActiveConfig() const { | 198 | const WindowConfig& GetActiveConfig() const { |
| 199 | return active_config; | 199 | return active_config; |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | /** | 202 | /** |
| 203 | * Requests the internal configuration to be replaced by the specified argument at some point in the future. | 203 | * 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. | 204 | * the future. |
| 205 | * @note This method is thread-safe, because it delays configuration changes to the GUI event | ||
| 206 | * loop. Hence there is no guarantee on when the requested configuration will be active. | ||
| 205 | */ | 207 | */ |
| 206 | void SetConfig(const WindowConfig& val) { | 208 | void SetConfig(const WindowConfig& val) { |
| 207 | config = val; | 209 | config = val; |
| @@ -227,7 +229,8 @@ protected: | |||
| 227 | circle_pad_y = 0; | 229 | circle_pad_y = 0; |
| 228 | touch_pressed = false; | 230 | touch_pressed = false; |
| 229 | } | 231 | } |
| 230 | virtual ~EmuWindow() {} | 232 | virtual ~EmuWindow() { |
| 233 | } | ||
| 231 | 234 | ||
| 232 | /** | 235 | /** |
| 233 | * Processes any pending configuration changes from the last SetConfig call. | 236 | * Processes any pending configuration changes from the last SetConfig call. |
| @@ -258,7 +261,7 @@ protected: | |||
| 258 | * Update internal client area size with the given parameter. | 261 | * Update internal client area size with the given parameter. |
| 259 | * @note EmuWindow implementations will usually use this in window resize event handlers. | 262 | * @note EmuWindow implementations will usually use this in window resize event handlers. |
| 260 | */ | 263 | */ |
| 261 | void NotifyClientAreaSizeChanged(const std::pair<unsigned,unsigned>& size) { | 264 | void NotifyClientAreaSizeChanged(const std::pair<unsigned, unsigned>& size) { |
| 262 | client_area_width = size.first; | 265 | client_area_width = size.first; |
| 263 | client_area_height = size.second; | 266 | client_area_height = size.second; |
| 264 | } | 267 | } |
| @@ -266,32 +269,35 @@ protected: | |||
| 266 | private: | 269 | private: |
| 267 | /** | 270 | /** |
| 268 | * Handler called when the minimal client area was requested to be changed via SetConfig. | 271 | * 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. | 272 | * For the request to be honored, EmuWindow implementations will usually reimplement this |
| 273 | * function. | ||
| 270 | */ | 274 | */ |
| 271 | virtual void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { | 275 | virtual void |
| 276 | OnMinimalClientAreaChangeRequest(const std::pair<unsigned, unsigned>& minimal_size) { | ||
| 272 | // By default, ignore this request and do nothing. | 277 | // By default, ignore this request and do nothing. |
| 273 | } | 278 | } |
| 274 | 279 | ||
| 275 | FramebufferLayout framebuffer_layout; ///< Current framebuffer layout | 280 | FramebufferLayout framebuffer_layout; ///< Current framebuffer layout |
| 276 | 281 | ||
| 277 | unsigned client_area_width; ///< Current client width, should be set by window impl. | 282 | 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. | 283 | unsigned client_area_height; ///< Current client height, should be set by window impl. |
| 279 | 284 | ||
| 280 | WindowConfig config; ///< Internal configuration (changes pending for being applied in ProcessConfigurationChanges) | 285 | WindowConfig config; ///< Internal configuration (changes pending for being applied in |
| 281 | WindowConfig active_config; ///< Internal active configuration | 286 | /// ProcessConfigurationChanges) |
| 287 | WindowConfig active_config; ///< Internal active configuration | ||
| 282 | 288 | ||
| 283 | bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false | 289 | bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false |
| 284 | 290 | ||
| 285 | u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) | 291 | 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) | 292 | u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) |
| 287 | 293 | ||
| 288 | s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156) | 294 | 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) | 295 | s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156) |
| 290 | 296 | ||
| 291 | /** | 297 | /** |
| 292 | * Clip the provided coordinates to be inside the touchscreen area. | 298 | * Clip the provided coordinates to be inside the touchscreen area. |
| 293 | */ | 299 | */ |
| 294 | std::tuple<unsigned,unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); | 300 | std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); |
| 295 | 301 | ||
| 296 | Service::HID::PadState pad_state; | 302 | Service::HID::PadState pad_state; |
| 297 | }; | 303 | }; |
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index bc83ab737..c8723a4b3 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -2,73 +2,70 @@ | |||
| 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 "common/file_util.h" | ||
| 5 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 6 | #include "common/common_funcs.h" | 7 | #include "common/common_funcs.h" |
| 7 | #include "common/common_paths.h" | 8 | #include "common/common_paths.h" |
| 8 | #include "common/file_util.h" | ||
| 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 | #include <commdlg.h> // for GetSaveFileName |
| 14 | #include <shellapi.h> | 14 | #include <direct.h> // getcwd |
| 15 | #include <commdlg.h> // for GetSaveFileName | 15 | #include <io.h> |
| 16 | #include <io.h> | 16 | #include <shellapi.h> |
| 17 | #include <direct.h> // getcwd | 17 | #include <shlobj.h> // for SHGetFolderPath |
| 18 | #include <tchar.h> | 18 | #include <tchar.h> |
| 19 | 19 | ||
| 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,36 @@ 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 | } | 832 | } |
| 892 | 833 | ||
| 893 | IOFile::IOFile(const std::string& filename, const char openmode[]) | 834 | IOFile::IOFile(const std::string& filename, const char openmode[]) { |
| 894 | { | ||
| 895 | Open(filename, openmode); | 835 | Open(filename, openmode); |
| 896 | } | 836 | } |
| 897 | 837 | ||
| 898 | IOFile::~IOFile() | 838 | IOFile::~IOFile() { |
| 899 | { | ||
| 900 | Close(); | 839 | Close(); |
| 901 | } | 840 | } |
| 902 | 841 | ||
| 903 | IOFile::IOFile(IOFile&& other) | 842 | IOFile::IOFile(IOFile&& other) { |
| 904 | { | ||
| 905 | Swap(other); | 843 | Swap(other); |
| 906 | } | 844 | } |
| 907 | 845 | ||
| 908 | IOFile& IOFile::operator=(IOFile&& other) | 846 | IOFile& IOFile::operator=(IOFile&& other) { |
| 909 | { | ||
| 910 | Swap(other); | 847 | Swap(other); |
| 911 | return *this; | 848 | return *this; |
| 912 | } | 849 | } |
| 913 | 850 | ||
| 914 | void IOFile::Swap(IOFile& other) | 851 | void IOFile::Swap(IOFile& other) { |
| 915 | { | ||
| 916 | std::swap(m_file, other.m_file); | 852 | std::swap(m_file, other.m_file); |
| 917 | std::swap(m_good, other.m_good); | 853 | std::swap(m_good, other.m_good); |
| 918 | } | 854 | } |
| 919 | 855 | ||
| 920 | bool IOFile::Open(const std::string& filename, const char openmode[]) | 856 | bool IOFile::Open(const std::string& filename, const char openmode[]) { |
| 921 | { | ||
| 922 | Close(); | 857 | Close(); |
| 923 | #ifdef _WIN32 | 858 | #ifdef _WIN32 |
| 924 | _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), Common::UTF8ToUTF16W(openmode).c_str()); | 859 | _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), |
| 860 | Common::UTF8ToUTF16W(openmode).c_str()); | ||
| 925 | #else | 861 | #else |
| 926 | m_file = fopen(filename.c_str(), openmode); | 862 | m_file = fopen(filename.c_str(), openmode); |
| 927 | #endif | 863 | #endif |
| @@ -930,8 +866,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[]) | |||
| 930 | return m_good; | 866 | return m_good; |
| 931 | } | 867 | } |
| 932 | 868 | ||
| 933 | bool IOFile::Close() | 869 | bool IOFile::Close() { |
| 934 | { | ||
| 935 | if (!IsOpen() || 0 != std::fclose(m_file)) | 870 | if (!IsOpen() || 0 != std::fclose(m_file)) |
| 936 | m_good = false; | 871 | m_good = false; |
| 937 | 872 | ||
| @@ -939,50 +874,46 @@ bool IOFile::Close() | |||
| 939 | return m_good; | 874 | return m_good; |
| 940 | } | 875 | } |
| 941 | 876 | ||
| 942 | u64 IOFile::GetSize() const | 877 | u64 IOFile::GetSize() const { |
| 943 | { | ||
| 944 | if (IsOpen()) | 878 | if (IsOpen()) |
| 945 | return FileUtil::GetSize(m_file); | 879 | return FileUtil::GetSize(m_file); |
| 946 | 880 | ||
| 947 | return 0; | 881 | return 0; |
| 948 | } | 882 | } |
| 949 | 883 | ||
| 950 | bool IOFile::Seek(s64 off, int origin) | 884 | bool IOFile::Seek(s64 off, int origin) { |
| 951 | { | ||
| 952 | if (!IsOpen() || 0 != fseeko(m_file, off, origin)) | 885 | if (!IsOpen() || 0 != fseeko(m_file, off, origin)) |
| 953 | m_good = false; | 886 | m_good = false; |
| 954 | 887 | ||
| 955 | return m_good; | 888 | return m_good; |
| 956 | } | 889 | } |
| 957 | 890 | ||
| 958 | u64 IOFile::Tell() const | 891 | u64 IOFile::Tell() const { |
| 959 | { | ||
| 960 | if (IsOpen()) | 892 | if (IsOpen()) |
| 961 | return ftello(m_file); | 893 | return ftello(m_file); |
| 962 | 894 | ||
| 963 | return -1; | 895 | return -1; |
| 964 | } | 896 | } |
| 965 | 897 | ||
| 966 | bool IOFile::Flush() | 898 | bool IOFile::Flush() { |
| 967 | { | ||
| 968 | if (!IsOpen() || 0 != std::fflush(m_file)) | 899 | if (!IsOpen() || 0 != std::fflush(m_file)) |
| 969 | m_good = false; | 900 | m_good = false; |
| 970 | 901 | ||
| 971 | return m_good; | 902 | return m_good; |
| 972 | } | 903 | } |
| 973 | 904 | ||
| 974 | bool IOFile::Resize(u64 size) | 905 | bool IOFile::Resize(u64 size) { |
| 975 | { | 906 | if (!IsOpen() || |
| 976 | if (!IsOpen() || 0 != | 907 | 0 != |
| 977 | #ifdef _WIN32 | 908 | #ifdef _WIN32 |
| 978 | // ector: _chsize sucks, not 64-bit safe | 909 | // ector: _chsize sucks, not 64-bit safe |
| 979 | // F|RES: changed to _chsize_s. i think it is 64-bit safe | 910 | // F|RES: changed to _chsize_s. i think it is 64-bit safe |
| 980 | _chsize_s(_fileno(m_file), size) | 911 | _chsize_s(_fileno(m_file), size) |
| 981 | #else | 912 | #else |
| 982 | // TODO: handle 64bit and growing | 913 | // TODO: handle 64bit and growing |
| 983 | ftruncate(fileno(m_file), size) | 914 | ftruncate(fileno(m_file), size) |
| 984 | #endif | 915 | #endif |
| 985 | ) | 916 | ) |
| 986 | m_good = false; | 917 | m_good = false; |
| 987 | 918 | ||
| 988 | return m_good; | 919 | return m_good; |
diff --git a/src/common/file_util.h b/src/common/file_util.h index 7ad7ee829..b15021a63 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -5,9 +5,9 @@ | |||
| 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> |
| @@ -51,75 +51,75 @@ enum { | |||
| 51 | NUM_PATH_INDICES | 51 | NUM_PATH_INDICES |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | namespace FileUtil | 54 | namespace FileUtil { |
| 55 | { | ||
| 56 | 55 | ||
| 57 | // FileSystem tree node/ | 56 | // FileSystem tree node/ |
| 58 | struct FSTEntry | 57 | struct FSTEntry { |
| 59 | { | ||
| 60 | bool isDirectory; | 58 | bool isDirectory; |
| 61 | u64 size; // file length or number of entries from children | 59 | u64 size; // file length or number of entries from children |
| 62 | std::string physicalName; // name on disk | 60 | std::string physicalName; // name on disk |
| 63 | std::string virtualName; // name in FST names table | 61 | std::string virtualName; // name in FST names table |
| 64 | std::vector<FSTEntry> children; | 62 | std::vector<FSTEntry> children; |
| 65 | }; | 63 | }; |
| 66 | 64 | ||
| 67 | // Returns true if file filename exists | 65 | // Returns true if file filename exists |
| 68 | bool Exists(const std::string &filename); | 66 | bool Exists(const std::string& filename); |
| 69 | 67 | ||
| 70 | // Returns true if filename is a directory | 68 | // Returns true if filename is a directory |
| 71 | bool IsDirectory(const std::string &filename); | 69 | bool IsDirectory(const std::string& filename); |
| 72 | 70 | ||
| 73 | // Returns the size of filename (64bit) | 71 | // Returns the size of filename (64bit) |
| 74 | u64 GetSize(const std::string &filename); | 72 | u64 GetSize(const std::string& filename); |
| 75 | 73 | ||
| 76 | // Overloaded GetSize, accepts file descriptor | 74 | // Overloaded GetSize, accepts file descriptor |
| 77 | u64 GetSize(const int fd); | 75 | u64 GetSize(const int fd); |
| 78 | 76 | ||
| 79 | // Overloaded GetSize, accepts FILE* | 77 | // Overloaded GetSize, accepts FILE* |
| 80 | u64 GetSize(FILE *f); | 78 | u64 GetSize(FILE* f); |
| 81 | 79 | ||
| 82 | // Returns true if successful, or path already exists. | 80 | // Returns true if successful, or path already exists. |
| 83 | bool CreateDir(const std::string &filename); | 81 | bool CreateDir(const std::string& filename); |
| 84 | 82 | ||
| 85 | // Creates the full path of fullPath returns true on success | 83 | // Creates the full path of fullPath returns true on success |
| 86 | bool CreateFullPath(const std::string &fullPath); | 84 | bool CreateFullPath(const std::string& fullPath); |
| 87 | 85 | ||
| 88 | // Deletes a given filename, return true on success | 86 | // Deletes a given filename, return true on success |
| 89 | // Doesn't supports deleting a directory | 87 | // Doesn't supports deleting a directory |
| 90 | bool Delete(const std::string &filename); | 88 | bool Delete(const std::string& filename); |
| 91 | 89 | ||
| 92 | // Deletes a directory filename, returns true on success | 90 | // Deletes a directory filename, returns true on success |
| 93 | bool DeleteDir(const std::string &filename); | 91 | bool DeleteDir(const std::string& filename); |
| 94 | 92 | ||
| 95 | // renames file srcFilename to destFilename, returns true on success | 93 | // renames file srcFilename to destFilename, returns true on success |
| 96 | bool Rename(const std::string &srcFilename, const std::string &destFilename); | 94 | bool Rename(const std::string& srcFilename, const std::string& destFilename); |
| 97 | 95 | ||
| 98 | // copies file srcFilename to destFilename, returns true on success | 96 | // copies file srcFilename to destFilename, returns true on success |
| 99 | bool Copy(const std::string &srcFilename, const std::string &destFilename); | 97 | bool Copy(const std::string& srcFilename, const std::string& destFilename); |
| 100 | 98 | ||
| 101 | // creates an empty file filename, returns true on success | 99 | // creates an empty file filename, returns true on success |
| 102 | bool CreateEmptyFile(const std::string &filename); | 100 | bool CreateEmptyFile(const std::string& filename); |
| 103 | 101 | ||
| 104 | /** | 102 | /** |
| 105 | * @param num_entries_out to be assigned by the callable with the number of iterated directory entries, never null | 103 | * @param num_entries_out to be assigned by the callable with the number of iterated directory |
| 104 | * entries, never null | ||
| 106 | * @param directory the path to the enclosing directory | 105 | * @param directory the path to the enclosing directory |
| 107 | * @param virtual_name the entry name, without any preceding directory info | 106 | * @param virtual_name the entry name, without any preceding directory info |
| 108 | * @return whether handling the entry succeeded | 107 | * @return whether handling the entry succeeded |
| 109 | */ | 108 | */ |
| 110 | using DirectoryEntryCallable = std::function<bool(unsigned* num_entries_out, | 109 | using DirectoryEntryCallable = std::function<bool( |
| 111 | const std::string& directory, | 110 | unsigned* num_entries_out, const std::string& directory, const std::string& virtual_name)>; |
| 112 | const std::string& virtual_name)>; | ||
| 113 | 111 | ||
| 114 | /** | 112 | /** |
| 115 | * Scans a directory, calling the callback for each file/directory contained within. | 113 | * 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 | 114 | * 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 | 115 | * @param num_entries_out assigned by the function with the number of iterated directory entries, |
| 116 | * can be null | ||
| 118 | * @param directory the directory to scan | 117 | * @param directory the directory to scan |
| 119 | * @param callback The callback which will be called for each entry | 118 | * @param callback The callback which will be called for each entry |
| 120 | * @return whether scanning the directory succeeded | 119 | * @return whether scanning the directory succeeded |
| 121 | */ | 120 | */ |
| 122 | bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback); | 121 | bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory, |
| 122 | DirectoryEntryCallable callback); | ||
| 123 | 123 | ||
| 124 | /** | 124 | /** |
| 125 | * Scans the directory tree, storing the results. | 125 | * Scans the directory tree, storing the results. |
| @@ -128,23 +128,24 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo | |||
| 128 | * @param recursion Number of children directories to read before giving up. | 128 | * @param recursion Number of children directories to read before giving up. |
| 129 | * @return the total number of files/directories found | 129 | * @return the total number of files/directories found |
| 130 | */ | 130 | */ |
| 131 | unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion = 0); | 131 | unsigned ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry, |
| 132 | unsigned int recursion = 0); | ||
| 132 | 133 | ||
| 133 | // deletes the given directory and anything under it. Returns true on success. | 134 | // deletes the given directory and anything under it. Returns true on success. |
| 134 | bool DeleteDirRecursively(const std::string &directory, unsigned int recursion = 256); | 135 | bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256); |
| 135 | 136 | ||
| 136 | // Returns the current directory | 137 | // Returns the current directory |
| 137 | std::string GetCurrentDir(); | 138 | std::string GetCurrentDir(); |
| 138 | 139 | ||
| 139 | // Create directory and copy contents (does not overwrite existing files) | 140 | // Create directory and copy contents (does not overwrite existing files) |
| 140 | void CopyDir(const std::string &source_path, const std::string &dest_path); | 141 | void CopyDir(const std::string& source_path, const std::string& dest_path); |
| 141 | 142 | ||
| 142 | // Set the current directory to given directory | 143 | // Set the current directory to given directory |
| 143 | bool SetCurrentDir(const std::string &directory); | 144 | bool SetCurrentDir(const std::string& directory); |
| 144 | 145 | ||
| 145 | // Returns a pointer to a string with a Citra data dir in the user's home | 146 | // 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). | 147 | // directory. To be used in "multi-user" mode (that is, installed). |
| 147 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); | 148 | const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath = ""); |
| 148 | 149 | ||
| 149 | // Returns the path to where the sys file are | 150 | // Returns the path to where the sys file are |
| 150 | std::string GetSysDirectory(); | 151 | std::string GetSysDirectory(); |
| @@ -154,11 +155,11 @@ std::string GetBundleDirectory(); | |||
| 154 | #endif | 155 | #endif |
| 155 | 156 | ||
| 156 | #ifdef _WIN32 | 157 | #ifdef _WIN32 |
| 157 | std::string &GetExeDirectory(); | 158 | std::string& GetExeDirectory(); |
| 158 | #endif | 159 | #endif |
| 159 | 160 | ||
| 160 | size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename); | 161 | 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); | 162 | size_t ReadFileToString(bool text_file, const char* filename, std::string& str); |
| 162 | 163 | ||
| 163 | /** | 164 | /** |
| 164 | * Splits the filename into 8.3 format | 165 | * Splits the filename into 8.3 format |
| @@ -173,8 +174,7 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam | |||
| 173 | // simple wrapper for cstdlib file functions to | 174 | // simple wrapper for cstdlib file functions to |
| 174 | // hopefully will make error checking easier | 175 | // hopefully will make error checking easier |
| 175 | // and make forgetting an fclose() harder | 176 | // and make forgetting an fclose() harder |
| 176 | class IOFile : public NonCopyable | 177 | class IOFile : public NonCopyable { |
| 177 | { | ||
| 178 | public: | 178 | public: |
| 179 | IOFile(); | 179 | IOFile(); |
| 180 | IOFile(const std::string& filename, const char openmode[]); | 180 | IOFile(const std::string& filename, const char openmode[]); |
| @@ -190,11 +190,12 @@ public: | |||
| 190 | bool Close(); | 190 | bool Close(); |
| 191 | 191 | ||
| 192 | template <typename T> | 192 | template <typename T> |
| 193 | size_t ReadArray(T* data, size_t length) | 193 | size_t ReadArray(T* data, size_t length) { |
| 194 | { | 194 | static_assert(std::is_standard_layout<T>(), |
| 195 | static_assert(std::is_standard_layout<T>(), "Given array does not consist of standard layout objects"); | 195 | "Given array does not consist of standard layout objects"); |
| 196 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) | 196 | #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"); | 197 | static_assert(std::is_trivially_copyable<T>(), |
| 198 | "Given array does not consist of trivially copyable objects"); | ||
| 198 | #endif | 199 | #endif |
| 199 | 200 | ||
| 200 | if (!IsOpen()) { | 201 | if (!IsOpen()) { |
| @@ -210,11 +211,12 @@ public: | |||
| 210 | } | 211 | } |
| 211 | 212 | ||
| 212 | template <typename T> | 213 | template <typename T> |
| 213 | size_t WriteArray(const T* data, size_t length) | 214 | size_t WriteArray(const T* data, size_t length) { |
| 214 | { | 215 | static_assert(std::is_standard_layout<T>(), |
| 215 | static_assert(std::is_standard_layout<T>(), "Given array does not consist of standard layout objects"); | 216 | "Given array does not consist of standard layout objects"); |
| 216 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) | 217 | #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"); | 218 | static_assert(std::is_trivially_copyable<T>(), |
| 219 | "Given array does not consist of trivially copyable objects"); | ||
| 218 | #endif | 220 | #endif |
| 219 | 221 | ||
| 220 | if (!IsOpen()) { | 222 | if (!IsOpen()) { |
| @@ -229,27 +231,31 @@ public: | |||
| 229 | return items_written; | 231 | return items_written; |
| 230 | } | 232 | } |
| 231 | 233 | ||
| 232 | size_t ReadBytes(void* data, size_t length) | 234 | size_t ReadBytes(void* data, size_t length) { |
| 233 | { | ||
| 234 | return ReadArray(reinterpret_cast<char*>(data), length); | 235 | return ReadArray(reinterpret_cast<char*>(data), length); |
| 235 | } | 236 | } |
| 236 | 237 | ||
| 237 | size_t WriteBytes(const void* data, size_t length) | 238 | size_t WriteBytes(const void* data, size_t length) { |
| 238 | { | ||
| 239 | return WriteArray(reinterpret_cast<const char*>(data), length); | 239 | return WriteArray(reinterpret_cast<const char*>(data), length); |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | template<typename T> | 242 | template <typename T> |
| 243 | size_t WriteObject(const T& object) { | 243 | size_t WriteObject(const T& object) { |
| 244 | static_assert(!std::is_pointer<T>::value, "Given object is a pointer"); | 244 | static_assert(!std::is_pointer<T>::value, "Given object is a pointer"); |
| 245 | return WriteArray(&object, 1); | 245 | return WriteArray(&object, 1); |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | bool IsOpen() const { return nullptr != m_file; } | 248 | bool IsOpen() const { |
| 249 | return nullptr != m_file; | ||
| 250 | } | ||
| 249 | 251 | ||
| 250 | // m_good is set to false when a read, write or other function fails | 252 | // m_good is set to false when a read, write or other function fails |
| 251 | bool IsGood() const { return m_good; } | 253 | bool IsGood() const { |
| 252 | explicit operator bool() const { return IsGood(); } | 254 | return m_good; |
| 255 | } | ||
| 256 | explicit operator bool() const { | ||
| 257 | return IsGood(); | ||
| 258 | } | ||
| 253 | 259 | ||
| 254 | bool Seek(s64 off, int origin); | 260 | bool Seek(s64 off, int origin); |
| 255 | u64 Tell() const; | 261 | u64 Tell() const; |
| @@ -258,19 +264,21 @@ public: | |||
| 258 | bool Flush(); | 264 | bool Flush(); |
| 259 | 265 | ||
| 260 | // clear error state | 266 | // clear error state |
| 261 | void Clear() { m_good = true; std::clearerr(m_file); } | 267 | void Clear() { |
| 268 | m_good = true; | ||
| 269 | std::clearerr(m_file); | ||
| 270 | } | ||
| 262 | 271 | ||
| 263 | private: | 272 | private: |
| 264 | std::FILE* m_file = nullptr; | 273 | std::FILE* m_file = nullptr; |
| 265 | bool m_good = true; | 274 | bool m_good = true; |
| 266 | }; | 275 | }; |
| 267 | 276 | ||
| 268 | } // namespace | 277 | } // namespace |
| 269 | 278 | ||
| 270 | // To deal with Windows being dumb at unicode: | 279 | // To deal with Windows being dumb at unicode: |
| 271 | template <typename T> | 280 | template <typename T> |
| 272 | void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) | 281 | void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) { |
| 273 | { | ||
| 274 | #ifdef _MSC_VER | 282 | #ifdef _MSC_VER |
| 275 | fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode); | 283 | fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode); |
| 276 | #else | 284 | #else |
diff --git a/src/common/hash.cpp b/src/common/hash.cpp index c49c2f60e..a46c92553 100644 --- a/src/common/hash.cpp +++ b/src/common/hash.cpp | |||
| @@ -36,7 +36,7 @@ static FORCE_INLINE u64 fmix64(u64 k) { | |||
| 36 | // platforms (MurmurHash3_x64_128). It was taken from: | 36 | // platforms (MurmurHash3_x64_128). It was taken from: |
| 37 | // https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp | 37 | // https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp |
| 38 | void MurmurHash3_128(const void* key, int len, u32 seed, void* out) { | 38 | void MurmurHash3_128(const void* key, int len, u32 seed, void* out) { |
| 39 | const u8 * data = (const u8*)key; | 39 | const u8* data = (const u8*)key; |
| 40 | const int nblocks = len / 16; | 40 | const int nblocks = len / 16; |
| 41 | 41 | ||
| 42 | u64 h1 = seed; | 42 | u64 h1 = seed; |
| @@ -47,52 +47,84 @@ void MurmurHash3_128(const void* key, int len, u32 seed, void* out) { | |||
| 47 | 47 | ||
| 48 | // Body | 48 | // Body |
| 49 | 49 | ||
| 50 | const u64 * blocks = (const u64 *)(data); | 50 | const u64* blocks = (const u64*)(data); |
| 51 | 51 | ||
| 52 | for (int i = 0; i < nblocks; i++) { | 52 | for (int i = 0; i < nblocks; i++) { |
| 53 | u64 k1 = getblock64(blocks,i*2+0); | 53 | u64 k1 = getblock64(blocks, i * 2 + 0); |
| 54 | u64 k2 = getblock64(blocks,i*2+1); | 54 | u64 k2 = getblock64(blocks, i * 2 + 1); |
| 55 | 55 | ||
| 56 | k1 *= c1; k1 = _rotl64(k1,31); k1 *= c2; h1 ^= k1; | 56 | k1 *= c1; |
| 57 | 57 | k1 = _rotl64(k1, 31); | |
| 58 | h1 = _rotl64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; | 58 | k1 *= c2; |
| 59 | 59 | h1 ^= k1; | |
| 60 | k2 *= c2; k2 = _rotl64(k2,33); k2 *= c1; h2 ^= k2; | 60 | |
| 61 | 61 | h1 = _rotl64(h1, 27); | |
| 62 | h2 = _rotl64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; | 62 | h1 += h2; |
| 63 | h1 = h1 * 5 + 0x52dce729; | ||
| 64 | |||
| 65 | k2 *= c2; | ||
| 66 | k2 = _rotl64(k2, 33); | ||
| 67 | k2 *= c1; | ||
| 68 | h2 ^= k2; | ||
| 69 | |||
| 70 | h2 = _rotl64(h2, 31); | ||
| 71 | h2 += h1; | ||
| 72 | h2 = h2 * 5 + 0x38495ab5; | ||
| 63 | } | 73 | } |
| 64 | 74 | ||
| 65 | // Tail | 75 | // Tail |
| 66 | 76 | ||
| 67 | const u8 * tail = (const u8*)(data + nblocks*16); | 77 | const u8* tail = (const u8*)(data + nblocks * 16); |
| 68 | 78 | ||
| 69 | u64 k1 = 0; | 79 | u64 k1 = 0; |
| 70 | u64 k2 = 0; | 80 | u64 k2 = 0; |
| 71 | 81 | ||
| 72 | switch (len & 15) { | 82 | switch (len & 15) { |
| 73 | case 15: k2 ^= ((u64)tail[14]) << 48; | 83 | case 15: |
| 74 | case 14: k2 ^= ((u64)tail[13]) << 40; | 84 | k2 ^= ((u64)tail[14]) << 48; |
| 75 | case 13: k2 ^= ((u64)tail[12]) << 32; | 85 | case 14: |
| 76 | case 12: k2 ^= ((u64)tail[11]) << 24; | 86 | k2 ^= ((u64)tail[13]) << 40; |
| 77 | case 11: k2 ^= ((u64)tail[10]) << 16; | 87 | case 13: |
| 78 | case 10: k2 ^= ((u64)tail[ 9]) << 8; | 88 | k2 ^= ((u64)tail[12]) << 32; |
| 79 | case 9: k2 ^= ((u64)tail[ 8]) << 0; | 89 | case 12: |
| 80 | k2 *= c2; k2 = _rotl64(k2,33); k2 *= c1; h2 ^= k2; | 90 | k2 ^= ((u64)tail[11]) << 24; |
| 81 | 91 | case 11: | |
| 82 | case 8: k1 ^= ((u64)tail[ 7]) << 56; | 92 | k2 ^= ((u64)tail[10]) << 16; |
| 83 | case 7: k1 ^= ((u64)tail[ 6]) << 48; | 93 | case 10: |
| 84 | case 6: k1 ^= ((u64)tail[ 5]) << 40; | 94 | k2 ^= ((u64)tail[9]) << 8; |
| 85 | case 5: k1 ^= ((u64)tail[ 4]) << 32; | 95 | case 9: |
| 86 | case 4: k1 ^= ((u64)tail[ 3]) << 24; | 96 | k2 ^= ((u64)tail[8]) << 0; |
| 87 | case 3: k1 ^= ((u64)tail[ 2]) << 16; | 97 | k2 *= c2; |
| 88 | case 2: k1 ^= ((u64)tail[ 1]) << 8; | 98 | k2 = _rotl64(k2, 33); |
| 89 | case 1: k1 ^= ((u64)tail[ 0]) << 0; | 99 | k2 *= c1; |
| 90 | k1 *= c1; k1 = _rotl64(k1,31); k1 *= c2; h1 ^= k1; | 100 | h2 ^= k2; |
| 101 | |||
| 102 | case 8: | ||
| 103 | k1 ^= ((u64)tail[7]) << 56; | ||
| 104 | case 7: | ||
| 105 | k1 ^= ((u64)tail[6]) << 48; | ||
| 106 | case 6: | ||
| 107 | k1 ^= ((u64)tail[5]) << 40; | ||
| 108 | case 5: | ||
| 109 | k1 ^= ((u64)tail[4]) << 32; | ||
| 110 | case 4: | ||
| 111 | k1 ^= ((u64)tail[3]) << 24; | ||
| 112 | case 3: | ||
| 113 | k1 ^= ((u64)tail[2]) << 16; | ||
| 114 | case 2: | ||
| 115 | k1 ^= ((u64)tail[1]) << 8; | ||
| 116 | case 1: | ||
| 117 | k1 ^= ((u64)tail[0]) << 0; | ||
| 118 | k1 *= c1; | ||
| 119 | k1 = _rotl64(k1, 31); | ||
| 120 | k1 *= c2; | ||
| 121 | h1 ^= k1; | ||
| 91 | }; | 122 | }; |
| 92 | 123 | ||
| 93 | // Finalization | 124 | // Finalization |
| 94 | 125 | ||
| 95 | h1 ^= len; h2 ^= len; | 126 | h1 ^= len; |
| 127 | h2 ^= len; | ||
| 96 | 128 | ||
| 97 | h1 += h2; | 129 | h1 += h2; |
| 98 | h2 += h1; | 130 | h2 += h1; |
diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp index ad311d66b..e882f5f52 100644 --- a/src/common/key_map.cpp +++ b/src/common/key_map.cpp | |||
| @@ -13,11 +13,25 @@ namespace KeyMap { | |||
| 13 | // and map it directly to EmuWindow::ButtonPressed. | 13 | // and map it directly to EmuWindow::ButtonPressed. |
| 14 | // It should go the analog input way like circle pad does. | 14 | // It should go the analog input way like circle pad does. |
| 15 | const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{ | 15 | 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, | 16 | Service::HID::PAD_A, |
| 17 | Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR, | 17 | Service::HID::PAD_B, |
| 18 | Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE, | 18 | Service::HID::PAD_X, |
| 19 | Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT, | 19 | 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, | 20 | Service::HID::PAD_L, |
| 21 | Service::HID::PAD_R, | ||
| 22 | Service::HID::PAD_ZL, | ||
| 23 | Service::HID::PAD_ZR, | ||
| 24 | Service::HID::PAD_START, | ||
| 25 | Service::HID::PAD_SELECT, | ||
| 26 | Service::HID::PAD_NONE, | ||
| 27 | Service::HID::PAD_UP, | ||
| 28 | Service::HID::PAD_DOWN, | ||
| 29 | Service::HID::PAD_LEFT, | ||
| 30 | Service::HID::PAD_RIGHT, | ||
| 31 | Service::HID::PAD_C_UP, | ||
| 32 | Service::HID::PAD_C_DOWN, | ||
| 33 | Service::HID::PAD_C_LEFT, | ||
| 34 | Service::HID::PAD_C_RIGHT, | ||
| 21 | 35 | ||
| 22 | IndirectTarget::CirclePadUp, | 36 | IndirectTarget::CirclePadUp, |
| 23 | IndirectTarget::CirclePadDown, | 37 | IndirectTarget::CirclePadDown, |
| @@ -49,7 +63,8 @@ static void UpdateCirclePad(EmuWindow& emu_window) { | |||
| 49 | --y; | 63 | --y; |
| 50 | 64 | ||
| 51 | float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0; | 65 | 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)); | 66 | emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0 : SQRT_HALF), |
| 67 | y * modifier * (x == 0 ? 1.0 : SQRT_HALF)); | ||
| 53 | } | 68 | } |
| 54 | 69 | ||
| 55 | int NewDeviceId() { | 70 | int NewDeviceId() { |
| @@ -103,7 +118,7 @@ void PressKey(EmuWindow& emu_window, HostDeviceKey key) { | |||
| 103 | } | 118 | } |
| 104 | } | 119 | } |
| 105 | 120 | ||
| 106 | void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) { | 121 | void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key) { |
| 107 | auto target = key_map.find(key); | 122 | auto target = key_map.find(key); |
| 108 | if (target == key_map.end()) | 123 | if (target == key_map.end()) |
| 109 | return; | 124 | return; |
| @@ -135,5 +150,4 @@ void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) { | |||
| 135 | } | 150 | } |
| 136 | } | 151 | } |
| 137 | } | 152 | } |
| 138 | |||
| 139 | } | 153 | } |
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..b3d6598e4 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -16,73 +16,79 @@ | |||
| 16 | namespace Log { | 16 | namespace Log { |
| 17 | 17 | ||
| 18 | /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. | 18 | /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. |
| 19 | #define ALL_LOG_CLASSES() \ | 19 | #define ALL_LOG_CLASSES() \ |
| 20 | CLS(Log) \ | 20 | CLS(Log) \ |
| 21 | CLS(Common) \ | 21 | CLS(Common) \ |
| 22 | SUB(Common, Filesystem) \ | 22 | SUB(Common, Filesystem) \ |
| 23 | SUB(Common, Memory) \ | 23 | SUB(Common, Memory) \ |
| 24 | CLS(Core) \ | 24 | CLS(Core) \ |
| 25 | SUB(Core, ARM11) \ | 25 | SUB(Core, ARM11) \ |
| 26 | SUB(Core, Timing) \ | 26 | SUB(Core, Timing) \ |
| 27 | CLS(Config) \ | 27 | CLS(Config) \ |
| 28 | CLS(Debug) \ | 28 | CLS(Debug) \ |
| 29 | SUB(Debug, Emulated) \ | 29 | SUB(Debug, Emulated) \ |
| 30 | SUB(Debug, GPU) \ | 30 | SUB(Debug, GPU) \ |
| 31 | SUB(Debug, Breakpoint) \ | 31 | SUB(Debug, Breakpoint) \ |
| 32 | SUB(Debug, GDBStub) \ | 32 | SUB(Debug, GDBStub) \ |
| 33 | CLS(Kernel) \ | 33 | CLS(Kernel) \ |
| 34 | SUB(Kernel, SVC) \ | 34 | SUB(Kernel, SVC) \ |
| 35 | CLS(Service) \ | 35 | CLS(Service) \ |
| 36 | SUB(Service, SRV) \ | 36 | SUB(Service, SRV) \ |
| 37 | SUB(Service, FRD) \ | 37 | SUB(Service, FRD) \ |
| 38 | SUB(Service, FS) \ | 38 | SUB(Service, FS) \ |
| 39 | SUB(Service, ERR) \ | 39 | SUB(Service, ERR) \ |
| 40 | SUB(Service, APT) \ | 40 | SUB(Service, APT) \ |
| 41 | SUB(Service, GSP) \ | 41 | SUB(Service, GSP) \ |
| 42 | SUB(Service, AC) \ | 42 | SUB(Service, AC) \ |
| 43 | SUB(Service, AM) \ | 43 | SUB(Service, AM) \ |
| 44 | SUB(Service, PTM) \ | 44 | SUB(Service, PTM) \ |
| 45 | SUB(Service, LDR) \ | 45 | SUB(Service, LDR) \ |
| 46 | SUB(Service, NDM) \ | 46 | SUB(Service, NDM) \ |
| 47 | SUB(Service, NIM) \ | 47 | SUB(Service, NIM) \ |
| 48 | SUB(Service, NWM) \ | 48 | SUB(Service, NWM) \ |
| 49 | SUB(Service, CAM) \ | 49 | SUB(Service, CAM) \ |
| 50 | SUB(Service, CECD) \ | 50 | SUB(Service, CECD) \ |
| 51 | SUB(Service, CFG) \ | 51 | SUB(Service, CFG) \ |
| 52 | SUB(Service, DSP) \ | 52 | SUB(Service, DSP) \ |
| 53 | SUB(Service, DLP) \ | 53 | SUB(Service, DLP) \ |
| 54 | SUB(Service, HID) \ | 54 | SUB(Service, HID) \ |
| 55 | SUB(Service, SOC) \ | 55 | SUB(Service, SOC) \ |
| 56 | SUB(Service, IR) \ | 56 | SUB(Service, IR) \ |
| 57 | SUB(Service, Y2R) \ | 57 | SUB(Service, Y2R) \ |
| 58 | CLS(HW) \ | 58 | CLS(HW) \ |
| 59 | SUB(HW, Memory) \ | 59 | SUB(HW, Memory) \ |
| 60 | SUB(HW, LCD) \ | 60 | SUB(HW, LCD) \ |
| 61 | SUB(HW, GPU) \ | 61 | SUB(HW, GPU) \ |
| 62 | CLS(Frontend) \ | 62 | CLS(Frontend) \ |
| 63 | CLS(Render) \ | 63 | CLS(Render) \ |
| 64 | SUB(Render, Software) \ | 64 | SUB(Render, Software) \ |
| 65 | SUB(Render, OpenGL) \ | 65 | SUB(Render, OpenGL) \ |
| 66 | CLS(Audio) \ | 66 | CLS(Audio) \ |
| 67 | SUB(Audio, DSP) \ | 67 | SUB(Audio, DSP) \ |
| 68 | SUB(Audio, Sink) \ | 68 | SUB(Audio, Sink) \ |
| 69 | CLS(Loader) | 69 | CLS(Loader) |
| 70 | 70 | ||
| 71 | // GetClassName is a macro defined by Windows.h, grrr... | 71 | // GetClassName is a macro defined by Windows.h, grrr... |
| 72 | const char* GetLogClassName(Class log_class) { | 72 | const char* GetLogClassName(Class log_class) { |
| 73 | switch (log_class) { | 73 | switch (log_class) { |
| 74 | #define CLS(x) case Class::x: return #x; | 74 | #define CLS(x) \ |
| 75 | #define SUB(x, y) case Class::x##_##y: return #x "." #y; | 75 | case Class::x: \ |
| 76 | return #x; | ||
| 77 | #define SUB(x, y) \ | ||
| 78 | case Class::x##_##y: \ | ||
| 79 | return #x "." #y; | ||
| 76 | ALL_LOG_CLASSES() | 80 | ALL_LOG_CLASSES() |
| 77 | #undef CLS | 81 | #undef CLS |
| 78 | #undef SUB | 82 | #undef SUB |
| 79 | case Class::Count: | 83 | case Class::Count: |
| 80 | UNREACHABLE(); | 84 | UNREACHABLE(); |
| 81 | } | 85 | } |
| 82 | } | 86 | } |
| 83 | 87 | ||
| 84 | const char* GetLevelName(Level log_level) { | 88 | const char* GetLevelName(Level log_level) { |
| 85 | #define LVL(x) case Level::x: return #x | 89 | #define LVL(x) \ |
| 90 | case Level::x: \ | ||
| 91 | return #x | ||
| 86 | switch (log_level) { | 92 | switch (log_level) { |
| 87 | LVL(Trace); | 93 | LVL(Trace); |
| 88 | LVL(Debug); | 94 | LVL(Debug); |
| @@ -90,15 +96,14 @@ const char* GetLevelName(Level log_level) { | |||
| 90 | LVL(Warning); | 96 | LVL(Warning); |
| 91 | LVL(Error); | 97 | LVL(Error); |
| 92 | LVL(Critical); | 98 | LVL(Critical); |
| 93 | case Level::Count: | 99 | case Level::Count: |
| 94 | UNREACHABLE(); | 100 | UNREACHABLE(); |
| 95 | } | 101 | } |
| 96 | #undef LVL | 102 | #undef LVL |
| 97 | } | 103 | } |
| 98 | 104 | ||
| 99 | Entry CreateEntry(Class log_class, Level log_level, | 105 | 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, | 106 | const char* function, const char* format, va_list args) { |
| 101 | const char* format, va_list args) { | ||
| 102 | using std::chrono::steady_clock; | 107 | using std::chrono::steady_clock; |
| 103 | using std::chrono::duration_cast; | 108 | using std::chrono::duration_cast; |
| 104 | 109 | ||
| @@ -111,7 +116,8 @@ Entry CreateEntry(Class log_class, Level log_level, | |||
| 111 | entry.log_class = log_class; | 116 | entry.log_class = log_class; |
| 112 | entry.log_level = log_level; | 117 | entry.log_level = log_level; |
| 113 | 118 | ||
| 114 | snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function, line_nr); | 119 | snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function, |
| 120 | line_nr); | ||
| 115 | entry.location = std::string(formatting_buffer.data()); | 121 | entry.location = std::string(formatting_buffer.data()); |
| 116 | 122 | ||
| 117 | vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args); | 123 | vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args); |
| @@ -126,19 +132,16 @@ void SetFilter(Filter* new_filter) { | |||
| 126 | filter = new_filter; | 132 | filter = new_filter; |
| 127 | } | 133 | } |
| 128 | 134 | ||
| 129 | void LogMessage(Class log_class, Level log_level, | 135 | 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, | 136 | const char* function, const char* format, ...) { |
| 131 | const char* format, ...) { | ||
| 132 | if (filter != nullptr && !filter->CheckMessage(log_class, log_level)) | 137 | if (filter != nullptr && !filter->CheckMessage(log_class, log_level)) |
| 133 | return; | 138 | return; |
| 134 | 139 | ||
| 135 | va_list args; | 140 | va_list args; |
| 136 | va_start(args, format); | 141 | va_start(args, format); |
| 137 | Entry entry = CreateEntry(log_class, log_level, | 142 | Entry entry = CreateEntry(log_class, log_level, filename, line_nr, function, format, args); |
| 138 | filename, line_nr, function, format, args); | ||
| 139 | va_end(args); | 143 | va_end(args); |
| 140 | 144 | ||
| 141 | PrintColoredMessage(entry); | 145 | PrintColoredMessage(entry); |
| 142 | } | 146 | } |
| 143 | |||
| 144 | } | 147 | } |
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index 795d42ebd..3fe88e4f6 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h | |||
| @@ -44,10 +44,8 @@ const char* GetLogClassName(Class log_class); | |||
| 44 | const char* GetLevelName(Level log_level); | 44 | const char* GetLevelName(Level log_level); |
| 45 | 45 | ||
| 46 | /// Creates a log entry by formatting the given source location, and message. | 46 | /// Creates a log entry by formatting the given source location, and message. |
| 47 | Entry CreateEntry(Class log_class, Level log_level, | 47 | 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, | 48 | const char* function, const char* format, va_list args); |
| 49 | const char* format, va_list args); | ||
| 50 | 49 | ||
| 51 | void SetFilter(Filter* filter); | 50 | void SetFilter(Filter* filter); |
| 52 | |||
| 53 | } | 51 | } |
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 55cc8888a..186e0b621 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | 6 | ||
| 7 | #include "common/logging/filter.h" | ||
| 8 | #include "common/logging/backend.h" | 7 | #include "common/logging/backend.h" |
| 8 | #include "common/logging/filter.h" | ||
| 9 | #include "common/string_util.h" | 9 | #include "common/string_util.h" |
| 10 | 10 | ||
| 11 | namespace Log { | 11 | namespace Log { |
| @@ -63,11 +63,11 @@ static Class GetClassByName(const It begin, const It end) { | |||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | bool Filter::ParseFilterRule(const std::string::const_iterator begin, | 65 | bool Filter::ParseFilterRule(const std::string::const_iterator begin, |
| 66 | const std::string::const_iterator end) { | 66 | const std::string::const_iterator end) { |
| 67 | auto level_separator = std::find(begin, end, ':'); | 67 | auto level_separator = std::find(begin, end, ':'); |
| 68 | if (level_separator == end) { | 68 | if (level_separator == end) { |
| 69 | LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s", | 69 | LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s", |
| 70 | std::string(begin, end).c_str()); | 70 | std::string(begin, end).c_str()); |
| 71 | return false; | 71 | return false; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| @@ -95,5 +95,4 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin, | |||
| 95 | bool Filter::CheckMessage(Class log_class, Level level) const { | 95 | 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)]); | 96 | return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]); |
| 97 | } | 97 | } |
| 98 | |||
| 99 | } | 98 | } |
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h index a2b4eca43..db526fead 100644 --- a/src/common/logging/filter.h +++ b/src/common/logging/filter.h | |||
| @@ -42,7 +42,8 @@ public: | |||
| 42 | * - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace. | 42 | * - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace. |
| 43 | */ | 43 | */ |
| 44 | void ParseFilterString(const std::string& filter_str); | 44 | void ParseFilterString(const std::string& filter_str); |
| 45 | bool ParseFilterRule(const std::string::const_iterator start, const std::string::const_iterator end); | 45 | bool ParseFilterRule(const std::string::const_iterator start, |
| 46 | const std::string::const_iterator end); | ||
| 46 | 47 | ||
| 47 | /// Matches class/level combination against the filter, returning true if it passed. | 48 | /// Matches class/level combination against the filter, returning true if it passed. |
| 48 | bool CheckMessage(Class log_class, Level level) const; | 49 | bool CheckMessage(Class log_class, Level level) const; |
| @@ -50,5 +51,4 @@ public: | |||
| 50 | private: | 51 | private: |
| 51 | std::array<Level, (size_t)Class::Count> class_levels; | 52 | std::array<Level, (size_t)Class::Count> class_levels; |
| 52 | }; | 53 | }; |
| 53 | |||
| 54 | } | 54 | } |
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..955358553 100644 --- a/src/common/logging/text_formatter.cpp +++ b/src/common/logging/text_formatter.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 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/logging/backend.h" | 13 | #include "common/logging/backend.h" |
| @@ -44,15 +44,14 @@ const char* TrimSourcePath(const char* path, const char* root) { | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) { | 46 | 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); | 47 | 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); | 48 | unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000); |
| 49 | 49 | ||
| 50 | const char* class_name = GetLogClassName(entry.log_class); | 50 | const char* class_name = GetLogClassName(entry.log_class); |
| 51 | const char* level_name = GetLevelName(entry.log_level); | 51 | const char* level_name = GetLevelName(entry.log_level); |
| 52 | 52 | ||
| 53 | snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", | 53 | snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", time_seconds, time_fractional, |
| 54 | time_seconds, time_fractional, class_name, level_name, | 54 | class_name, level_name, TrimSourcePath(entry.location.c_str()), entry.message.c_str()); |
| 55 | TrimSourcePath(entry.location.c_str()), entry.message.c_str()); | ||
| 56 | } | 55 | } |
| 57 | 56 | ||
| 58 | void PrintMessage(const Entry& entry) { | 57 | void PrintMessage(const Entry& entry) { |
| @@ -72,38 +71,50 @@ void PrintColoredMessage(const Entry& entry) { | |||
| 72 | WORD color = 0; | 71 | WORD color = 0; |
| 73 | switch (entry.log_level) { | 72 | switch (entry.log_level) { |
| 74 | case Level::Trace: // Grey | 73 | case Level::Trace: // Grey |
| 75 | color = FOREGROUND_INTENSITY; break; | 74 | color = FOREGROUND_INTENSITY; |
| 75 | break; | ||
| 76 | case Level::Debug: // Cyan | 76 | case Level::Debug: // Cyan |
| 77 | color = FOREGROUND_GREEN | FOREGROUND_BLUE; break; | 77 | color = FOREGROUND_GREEN | FOREGROUND_BLUE; |
| 78 | break; | ||
| 78 | case Level::Info: // Bright gray | 79 | case Level::Info: // Bright gray |
| 79 | color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; | 80 | color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; |
| 81 | break; | ||
| 80 | case Level::Warning: // Bright yellow | 82 | case Level::Warning: // Bright yellow |
| 81 | color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; break; | 83 | color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; |
| 84 | break; | ||
| 82 | case Level::Error: // Bright red | 85 | case Level::Error: // Bright red |
| 83 | color = FOREGROUND_RED | FOREGROUND_INTENSITY; break; | 86 | color = FOREGROUND_RED | FOREGROUND_INTENSITY; |
| 87 | break; | ||
| 84 | case Level::Critical: // Bright magenta | 88 | case Level::Critical: // Bright magenta |
| 85 | color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break; | 89 | color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; |
| 90 | break; | ||
| 86 | case Level::Count: | 91 | case Level::Count: |
| 87 | UNREACHABLE(); | 92 | UNREACHABLE(); |
| 88 | } | 93 | } |
| 89 | 94 | ||
| 90 | SetConsoleTextAttribute(console_handle, color); | 95 | SetConsoleTextAttribute(console_handle, color); |
| 91 | #else | 96 | #else |
| 92 | # define ESC "\x1b" | 97 | #define ESC "\x1b" |
| 93 | const char* color = ""; | 98 | const char* color = ""; |
| 94 | switch (entry.log_level) { | 99 | switch (entry.log_level) { |
| 95 | case Level::Trace: // Grey | 100 | case Level::Trace: // Grey |
| 96 | color = ESC "[1;30m"; break; | 101 | color = ESC "[1;30m"; |
| 102 | break; | ||
| 97 | case Level::Debug: // Cyan | 103 | case Level::Debug: // Cyan |
| 98 | color = ESC "[0;36m"; break; | 104 | color = ESC "[0;36m"; |
| 105 | break; | ||
| 99 | case Level::Info: // Bright gray | 106 | case Level::Info: // Bright gray |
| 100 | color = ESC "[0;37m"; break; | 107 | color = ESC "[0;37m"; |
| 108 | break; | ||
| 101 | case Level::Warning: // Bright yellow | 109 | case Level::Warning: // Bright yellow |
| 102 | color = ESC "[1;33m"; break; | 110 | color = ESC "[1;33m"; |
| 111 | break; | ||
| 103 | case Level::Error: // Bright red | 112 | case Level::Error: // Bright red |
| 104 | color = ESC "[1;31m"; break; | 113 | color = ESC "[1;31m"; |
| 114 | break; | ||
| 105 | case Level::Critical: // Bright magenta | 115 | case Level::Critical: // Bright magenta |
| 106 | color = ESC "[1;35m"; break; | 116 | color = ESC "[1;35m"; |
| 117 | break; | ||
| 107 | case Level::Count: | 118 | case Level::Count: |
| 108 | UNREACHABLE(); | 119 | UNREACHABLE(); |
| 109 | } | 120 | } |
| @@ -117,8 +128,7 @@ void PrintColoredMessage(const Entry& entry) { | |||
| 117 | SetConsoleTextAttribute(console_handle, original_info.wAttributes); | 128 | SetConsoleTextAttribute(console_handle, original_info.wAttributes); |
| 118 | #else | 129 | #else |
| 119 | fputs(ESC "[0m", stderr); | 130 | fputs(ESC "[0m", stderr); |
| 120 | # undef ESC | 131 | #undef ESC |
| 121 | #endif | 132 | #endif |
| 122 | } | 133 | } |
| 123 | |||
| 124 | } | 134 | } |
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..696bd43ea 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h | |||
| @@ -8,33 +8,38 @@ | |||
| 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; |
| 30 | T bottom; | 28 | T bottom; |
| 31 | 29 | ||
| 32 | Rectangle() {} | 30 | Rectangle() { |
| 31 | } | ||
| 33 | 32 | ||
| 34 | Rectangle(T left, T top, T right, T bottom) : left(left), top(top), right(right), bottom(bottom) {} | 33 | Rectangle(T left, T top, T right, T bottom) |
| 34 | : left(left), top(top), right(right), bottom(bottom) { | ||
| 35 | } | ||
| 35 | 36 | ||
| 36 | T GetWidth() const { return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); } | 37 | T GetWidth() const { |
| 37 | T GetHeight() const { return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); } | 38 | return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); |
| 39 | } | ||
| 40 | T GetHeight() const { | ||
| 41 | return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); | ||
| 42 | } | ||
| 38 | }; | 43 | }; |
| 39 | 44 | ||
| 40 | } // namespace MathUtil | 45 | } // namespace MathUtil |
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp index 07c7f79c8..7d352f00f 100644 --- a/src/common/memory_util.cpp +++ b/src/common/memory_util.cpp | |||
| @@ -2,31 +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 | |||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "common/memory_util.h" | 5 | #include "common/memory_util.h" |
| 6 | #include "common/logging/log.h" | ||
| 8 | 7 | ||
| 9 | #ifdef _WIN32 | 8 | #ifdef _WIN32 |
| 10 | #include <windows.h> | 9 | #include <windows.h> |
| 11 | #include <psapi.h> | 10 | #include <psapi.h> |
| 12 | #include "common/common_funcs.h" | 11 | #include "common/common_funcs.h" |
| 13 | #include "common/string_util.h" | 12 | #include "common/string_util.h" |
| 14 | #else | 13 | #else |
| 15 | #include <cstdlib> | 14 | #include <cstdlib> |
| 16 | #include <sys/mman.h> | 15 | #include <sys/mman.h> |
| 17 | #endif | 16 | #endif |
| 18 | 17 | ||
| 19 | #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) | 18 | #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) |
| 20 | #include <unistd.h> | 19 | #include <unistd.h> |
| 21 | #define PAGE_MASK (getpagesize() - 1) | 20 | #define PAGE_MASK (getpagesize() - 1) |
| 22 | #define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) | 21 | #define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) |
| 23 | #endif | 22 | #endif |
| 24 | 23 | ||
| 25 | // This is purposely not a full wrapper for virtualalloc/mmap, but it | 24 | // This is purposely not a full wrapper for virtualalloc/mmap, but it |
| 26 | // provides exactly the primitive operations that Dolphin needs. | 25 | // provides exactly the primitive operations that Dolphin needs. |
| 27 | 26 | ||
| 28 | void* AllocateExecutableMemory(size_t size, bool low) | 27 | void* AllocateExecutableMemory(size_t size, bool low) { |
| 29 | { | ||
| 30 | #if defined(_WIN32) | 28 | #if defined(_WIN32) |
| 31 | void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); | 29 | void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); |
| 32 | #else | 30 | #else |
| @@ -39,31 +37,27 @@ void* AllocateExecutableMemory(size_t size, bool low) | |||
| 39 | // effect of discarding already mapped pages that happen to be in the | 37 | // effect of discarding already mapped pages that happen to be in the |
| 40 | // requested virtual memory range (such as the emulated RAM, sometimes). | 38 | // requested virtual memory range (such as the emulated RAM, sometimes). |
| 41 | if (low && (!map_hint)) | 39 | if (low && (!map_hint)) |
| 42 | map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ | 40 | map_hint = (char*)round_page(512 * 1024 * 1024); /* 0.5 GB rounded up to the next page */ |
| 43 | #endif | 41 | #endif |
| 44 | void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, | 42 | 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) | 43 | #if defined(ARCHITECTURE_X64) && defined(MAP_32BIT) |
| 47 | | (low ? MAP_32BIT : 0) | 44 | | (low ? MAP_32BIT : 0) |
| 48 | #endif | 45 | #endif |
| 49 | , -1, 0); | 46 | , |
| 47 | -1, 0); | ||
| 50 | #endif /* defined(_WIN32) */ | 48 | #endif /* defined(_WIN32) */ |
| 51 | 49 | ||
| 52 | #ifdef _WIN32 | 50 | #ifdef _WIN32 |
| 53 | if (ptr == nullptr) | 51 | if (ptr == nullptr) { |
| 54 | { | ||
| 55 | #else | 52 | #else |
| 56 | if (ptr == MAP_FAILED) | 53 | if (ptr == MAP_FAILED) { |
| 57 | { | ||
| 58 | ptr = nullptr; | 54 | ptr = nullptr; |
| 59 | #endif | 55 | #endif |
| 60 | LOG_ERROR(Common_Memory, "Failed to allocate executable memory"); | 56 | LOG_ERROR(Common_Memory, "Failed to allocate executable memory"); |
| 61 | } | 57 | } |
| 62 | #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) | 58 | #if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) |
| 63 | else | 59 | else { |
| 64 | { | 60 | if (low) { |
| 65 | if (low) | ||
| 66 | { | ||
| 67 | map_hint += size; | 61 | map_hint += size; |
| 68 | map_hint = (char*)round_page(map_hint); /* round up to the next page */ | 62 | map_hint = (char*)round_page(map_hint); /* round up to the next page */ |
| 69 | } | 63 | } |
| @@ -78,13 +72,11 @@ void* AllocateExecutableMemory(size_t size, bool low) | |||
| 78 | return ptr; | 72 | return ptr; |
| 79 | } | 73 | } |
| 80 | 74 | ||
| 81 | void* AllocateMemoryPages(size_t size) | 75 | void* AllocateMemoryPages(size_t size) { |
| 82 | { | ||
| 83 | #ifdef _WIN32 | 76 | #ifdef _WIN32 |
| 84 | void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); | 77 | void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); |
| 85 | #else | 78 | #else |
| 86 | void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, | 79 | void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); |
| 87 | MAP_ANON | MAP_PRIVATE, -1, 0); | ||
| 88 | 80 | ||
| 89 | if (ptr == MAP_FAILED) | 81 | if (ptr == MAP_FAILED) |
| 90 | ptr = nullptr; | 82 | ptr = nullptr; |
| @@ -96,10 +88,9 @@ void* AllocateMemoryPages(size_t size) | |||
| 96 | return ptr; | 88 | return ptr; |
| 97 | } | 89 | } |
| 98 | 90 | ||
| 99 | void* AllocateAlignedMemory(size_t size,size_t alignment) | 91 | void* AllocateAlignedMemory(size_t size, size_t alignment) { |
| 100 | { | ||
| 101 | #ifdef _WIN32 | 92 | #ifdef _WIN32 |
| 102 | void* ptr = _aligned_malloc(size,alignment); | 93 | void* ptr = _aligned_malloc(size, alignment); |
| 103 | #else | 94 | #else |
| 104 | void* ptr = nullptr; | 95 | void* ptr = nullptr; |
| 105 | #ifdef ANDROID | 96 | #ifdef ANDROID |
| @@ -116,10 +107,8 @@ void* AllocateAlignedMemory(size_t size,size_t alignment) | |||
| 116 | return ptr; | 107 | return ptr; |
| 117 | } | 108 | } |
| 118 | 109 | ||
| 119 | void FreeMemoryPages(void* ptr, size_t size) | 110 | void FreeMemoryPages(void* ptr, size_t size) { |
| 120 | { | 111 | if (ptr) { |
| 121 | if (ptr) | ||
| 122 | { | ||
| 123 | #ifdef _WIN32 | 112 | #ifdef _WIN32 |
| 124 | if (!VirtualFree(ptr, 0, MEM_RELEASE)) | 113 | if (!VirtualFree(ptr, 0, MEM_RELEASE)) |
| 125 | LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg()); | 114 | LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg()); |
| @@ -129,20 +118,17 @@ void FreeMemoryPages(void* ptr, size_t size) | |||
| 129 | } | 118 | } |
| 130 | } | 119 | } |
| 131 | 120 | ||
| 132 | void FreeAlignedMemory(void* ptr) | 121 | void FreeAlignedMemory(void* ptr) { |
| 133 | { | 122 | if (ptr) { |
| 134 | if (ptr) | ||
| 135 | { | ||
| 136 | #ifdef _WIN32 | 123 | #ifdef _WIN32 |
| 137 | _aligned_free(ptr); | 124 | _aligned_free(ptr); |
| 138 | #else | 125 | #else |
| 139 | free(ptr); | 126 | free(ptr); |
| 140 | #endif | 127 | #endif |
| 141 | } | 128 | } |
| 142 | } | 129 | } |
| 143 | 130 | ||
| 144 | void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) | 131 | void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) { |
| 145 | { | ||
| 146 | #ifdef _WIN32 | 132 | #ifdef _WIN32 |
| 147 | DWORD oldValue; | 133 | DWORD oldValue; |
| 148 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) | 134 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) |
| @@ -152,19 +138,19 @@ void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) | |||
| 152 | #endif | 138 | #endif |
| 153 | } | 139 | } |
| 154 | 140 | ||
| 155 | void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) | 141 | void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) { |
| 156 | { | ||
| 157 | #ifdef _WIN32 | 142 | #ifdef _WIN32 |
| 158 | DWORD oldValue; | 143 | DWORD oldValue; |
| 159 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) | 144 | if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, |
| 145 | &oldValue)) | ||
| 160 | LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg()); | 146 | LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg()); |
| 161 | #else | 147 | #else |
| 162 | mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); | 148 | mprotect(ptr, size, |
| 149 | allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); | ||
| 163 | #endif | 150 | #endif |
| 164 | } | 151 | } |
| 165 | 152 | ||
| 166 | std::string MemUsage() | 153 | std::string MemUsage() { |
| 167 | { | ||
| 168 | #ifdef _WIN32 | 154 | #ifdef _WIN32 |
| 169 | #pragma comment(lib, "psapi") | 155 | #pragma comment(lib, "psapi") |
| 170 | DWORD processID = GetCurrentProcessId(); | 156 | DWORD processID = GetCurrentProcessId(); |
| @@ -175,10 +161,12 @@ std::string MemUsage() | |||
| 175 | // Print information about the memory usage of the process. | 161 | // Print information about the memory usage of the process. |
| 176 | 162 | ||
| 177 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); | 163 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); |
| 178 | if (nullptr == hProcess) return "MemUsage Error"; | 164 | if (nullptr == hProcess) |
| 165 | return "MemUsage Error"; | ||
| 179 | 166 | ||
| 180 | if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) | 167 | if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) |
| 181 | Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); | 168 | Ret = Common::StringFromFormat( |
| 169 | "%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); | ||
| 182 | 170 | ||
| 183 | CloseHandle(hProcess); | 171 | CloseHandle(hProcess); |
| 184 | return Ret; | 172 | 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..5938e6289 100644 --- a/src/common/misc.cpp +++ b/src/common/misc.cpp | |||
| @@ -12,23 +12,21 @@ | |||
| 12 | #endif | 12 | #endif |
| 13 | 13 | ||
| 14 | // Neither Android nor OS X support TLS | 14 | // Neither Android nor OS X support TLS |
| 15 | #if defined(__APPLE__) || (ANDROID && __clang__) | 15 | #if defined(__APPLE__) || (ANDROID && __clang__) |
| 16 | #define __thread | 16 | #define __thread |
| 17 | #endif | 17 | #endif |
| 18 | 18 | ||
| 19 | // Generic function to get last error message. | 19 | // Generic function to get last error message. |
| 20 | // Call directly after the command or use the error num. | 20 | // Call directly after the command or use the error num. |
| 21 | // This function might change the error code. | 21 | // This function might change the error code. |
| 22 | const char* GetLastErrorMsg() | 22 | const char* GetLastErrorMsg() { |
| 23 | { | ||
| 24 | static const size_t buff_size = 255; | 23 | static const size_t buff_size = 255; |
| 25 | 24 | ||
| 26 | #ifdef _WIN32 | 25 | #ifdef _WIN32 |
| 27 | static __declspec(thread) char err_str[buff_size] = {}; | 26 | static __declspec(thread) char err_str[buff_size] = {}; |
| 28 | 27 | ||
| 29 | FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), | 28 | FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), |
| 30 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | 29 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr); |
| 31 | err_str, buff_size, nullptr); | ||
| 32 | #else | 30 | #else |
| 33 | static __thread char err_str[buff_size] = {}; | 31 | static __thread char err_str[buff_size] = {}; |
| 34 | 32 | ||
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..992ec25b2 100644 --- a/src/common/profiler.cpp +++ b/src/common/profiler.cpp | |||
| @@ -14,7 +14,7 @@ namespace Common { | |||
| 14 | namespace Profiling { | 14 | namespace Profiling { |
| 15 | 15 | ||
| 16 | ProfilingManager::ProfilingManager() | 16 | ProfilingManager::ProfilingManager() |
| 17 | : last_frame_end(Clock::now()), this_frame_start(Clock::now()) { | 17 | : last_frame_end(Clock::now()), this_frame_start(Clock::now()) { |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | void ProfilingManager::BeginFrame() { | 20 | void ProfilingManager::BeginFrame() { |
| @@ -31,7 +31,7 @@ void ProfilingManager::FinishFrame() { | |||
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | TimingResultsAggregator::TimingResultsAggregator(size_t window_size) | 33 | TimingResultsAggregator::TimingResultsAggregator(size_t window_size) |
| 34 | : max_window_size(window_size), window_size(0) { | 34 | : max_window_size(window_size), window_size(0) { |
| 35 | interframe_times.resize(window_size, Duration::zero()); | 35 | interframe_times.resize(window_size, Duration::zero()); |
| 36 | frame_times.resize(window_size, Duration::zero()); | 36 | frame_times.resize(window_size, Duration::zero()); |
| 37 | } | 37 | } |
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h index 08f09a8c8..73b2a262e 100644 --- a/src/common/scope_exit.h +++ b/src/common/scope_exit.h | |||
| @@ -4,20 +4,25 @@ | |||
| 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 | } |
| 15 | ~ScopeExitHelper() { | ||
| 16 | func(); | ||
| 17 | } | ||
| 15 | 18 | ||
| 16 | Func func; | 19 | Func func; |
| 17 | }; | 20 | }; |
| 18 | 21 | ||
| 19 | template <typename Func> | 22 | template <typename Func> |
| 20 | ScopeExitHelper<Func> ScopeExit(Func&& func) { return ScopeExitHelper<Func>(std::move(func)); } | 23 | ScopeExitHelper<Func> ScopeExit(Func&& func) { |
| 24 | return ScopeExitHelper<Func>(std::move(func)); | ||
| 25 | } | ||
| 21 | } | 26 | } |
| 22 | 27 | ||
| 23 | /** | 28 | /** |
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index f0aa072db..9ccd6f135 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -14,11 +14,11 @@ | |||
| 14 | #include "common/string_util.h" | 14 | #include "common/string_util.h" |
| 15 | 15 | ||
| 16 | #ifdef _MSC_VER | 16 | #ifdef _MSC_VER |
| 17 | #include <Windows.h> | 17 | #include <Windows.h> |
| 18 | #include <codecvt> | 18 | #include <codecvt> |
| 19 | #include "common/common_funcs.h" | 19 | #include "common/common_funcs.h" |
| 20 | #else | 20 | #else |
| 21 | #include <iconv.h> | 21 | #include <iconv.h> |
| 22 | #endif | 22 | #endif |
| 23 | 23 | ||
| 24 | namespace Common { | 24 | namespace Common { |
| @@ -36,9 +36,8 @@ std::string ToUpper(std::string str) { | |||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | // faster than sscanf | 38 | // faster than sscanf |
| 39 | bool AsciiToHex(const char* _szValue, u32& result) | 39 | bool AsciiToHex(const char* _szValue, u32& result) { |
| 40 | { | 40 | char* endptr = nullptr; |
| 41 | char *endptr = nullptr; | ||
| 42 | const u32 value = strtoul(_szValue, &endptr, 16); | 41 | const u32 value = strtoul(_szValue, &endptr, 16); |
| 43 | 42 | ||
| 44 | if (!endptr || *endptr) | 43 | if (!endptr || *endptr) |
| @@ -48,8 +47,7 @@ bool AsciiToHex(const char* _szValue, u32& result) | |||
| 48 | return true; | 47 | return true; |
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) | 50 | bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) { |
| 52 | { | ||
| 53 | int writtenCount; | 51 | int writtenCount; |
| 54 | 52 | ||
| 55 | #ifdef _MSC_VER | 53 | #ifdef _MSC_VER |
| @@ -84,22 +82,18 @@ bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list ar | |||
| 84 | writtenCount = vsnprintf(out, outsize, format, args); | 82 | writtenCount = vsnprintf(out, outsize, format, args); |
| 85 | #endif | 83 | #endif |
| 86 | 84 | ||
| 87 | if (writtenCount > 0 && writtenCount < outsize) | 85 | if (writtenCount > 0 && writtenCount < outsize) { |
| 88 | { | ||
| 89 | out[writtenCount] = '\0'; | 86 | out[writtenCount] = '\0'; |
| 90 | return true; | 87 | return true; |
| 91 | } | 88 | } else { |
| 92 | else | ||
| 93 | { | ||
| 94 | out[outsize - 1] = '\0'; | 89 | out[outsize - 1] = '\0'; |
| 95 | return false; | 90 | return false; |
| 96 | } | 91 | } |
| 97 | } | 92 | } |
| 98 | 93 | ||
| 99 | std::string StringFromFormat(const char* format, ...) | 94 | std::string StringFromFormat(const char* format, ...) { |
| 100 | { | ||
| 101 | va_list args; | 95 | va_list args; |
| 102 | char *buf = nullptr; | 96 | char* buf = nullptr; |
| 103 | #ifdef _WIN32 | 97 | #ifdef _WIN32 |
| 104 | int required = 0; | 98 | int required = 0; |
| 105 | 99 | ||
| @@ -124,21 +118,17 @@ std::string StringFromFormat(const char* format, ...) | |||
| 124 | } | 118 | } |
| 125 | 119 | ||
| 126 | // For Debugging. Read out an u8 array. | 120 | // For Debugging. Read out an u8 array. |
| 127 | std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) | 121 | std::string ArrayToString(const u8* data, u32 size, int line_len, bool spaces) { |
| 128 | { | ||
| 129 | std::ostringstream oss; | 122 | std::ostringstream oss; |
| 130 | oss << std::setfill('0') << std::hex; | 123 | oss << std::setfill('0') << std::hex; |
| 131 | 124 | ||
| 132 | for (int line = 0; size; ++data, --size) | 125 | for (int line = 0; size; ++data, --size) { |
| 133 | { | ||
| 134 | oss << std::setw(2) << (int)*data; | 126 | oss << std::setw(2) << (int)*data; |
| 135 | 127 | ||
| 136 | if (line_len == ++line) | 128 | if (line_len == ++line) { |
| 137 | { | ||
| 138 | oss << '\n'; | 129 | oss << '\n'; |
| 139 | line = 0; | 130 | line = 0; |
| 140 | } | 131 | } else if (spaces) |
| 141 | else if (spaces) | ||
| 142 | oss << ' '; | 132 | oss << ' '; |
| 143 | } | 133 | } |
| 144 | 134 | ||
| @@ -146,8 +136,7 @@ std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) | |||
| 146 | } | 136 | } |
| 147 | 137 | ||
| 148 | // Turns " hej " into "hej". Also handles tabs. | 138 | // Turns " hej " into "hej". Also handles tabs. |
| 149 | std::string StripSpaces(const std::string &str) | 139 | std::string StripSpaces(const std::string& str) { |
| 150 | { | ||
| 151 | const size_t s = str.find_first_not_of(" \t\r\n"); | 140 | const size_t s = str.find_first_not_of(" \t\r\n"); |
| 152 | 141 | ||
| 153 | if (str.npos != s) | 142 | if (str.npos != s) |
| @@ -159,17 +148,15 @@ std::string StripSpaces(const std::string &str) | |||
| 159 | // "\"hello\"" is turned to "hello" | 148 | // "\"hello\"" is turned to "hello" |
| 160 | // This one assumes that the string has already been space stripped in both | 149 | // This one assumes that the string has already been space stripped in both |
| 161 | // ends, as done by StripSpaces above, for example. | 150 | // ends, as done by StripSpaces above, for example. |
| 162 | std::string StripQuotes(const std::string& s) | 151 | std::string StripQuotes(const std::string& s) { |
| 163 | { | ||
| 164 | if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) | 152 | if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) |
| 165 | return s.substr(1, s.size() - 2); | 153 | return s.substr(1, s.size() - 2); |
| 166 | else | 154 | else |
| 167 | return s; | 155 | return s; |
| 168 | } | 156 | } |
| 169 | 157 | ||
| 170 | bool TryParse(const std::string &str, u32 *const output) | 158 | bool TryParse(const std::string& str, u32* const output) { |
| 171 | { | 159 | char* endptr = nullptr; |
| 172 | char *endptr = nullptr; | ||
| 173 | 160 | ||
| 174 | // Reset errno to a value other than ERANGE | 161 | // Reset errno to a value other than ERANGE |
| 175 | errno = 0; | 162 | errno = 0; |
| @@ -183,8 +170,7 @@ bool TryParse(const std::string &str, u32 *const output) | |||
| 183 | return false; | 170 | return false; |
| 184 | 171 | ||
| 185 | #if ULONG_MAX > UINT_MAX | 172 | #if ULONG_MAX > UINT_MAX |
| 186 | if (value >= 0x100000000ull | 173 | if (value >= 0x100000000ull && value <= 0xFFFFFFFF00000000ull) |
| 187 | && value <= 0xFFFFFFFF00000000ull) | ||
| 188 | return false; | 174 | return false; |
| 189 | #endif | 175 | #endif |
| 190 | 176 | ||
| @@ -192,8 +178,7 @@ bool TryParse(const std::string &str, u32 *const output) | |||
| 192 | return true; | 178 | return true; |
| 193 | } | 179 | } |
| 194 | 180 | ||
| 195 | bool TryParse(const std::string &str, bool *const output) | 181 | bool TryParse(const std::string& str, bool* const output) { |
| 196 | { | ||
| 197 | if ("1" == str || "true" == ToLower(str)) | 182 | if ("1" == str || "true" == ToLower(str)) |
| 198 | *output = true; | 183 | *output = true; |
| 199 | else if ("0" == str || "false" == ToLower(str)) | 184 | else if ("0" == str || "false" == ToLower(str)) |
| @@ -204,22 +189,21 @@ bool TryParse(const std::string &str, bool *const output) | |||
| 204 | return true; | 189 | return true; |
| 205 | } | 190 | } |
| 206 | 191 | ||
| 207 | std::string StringFromBool(bool value) | 192 | std::string StringFromBool(bool value) { |
| 208 | { | ||
| 209 | return value ? "True" : "False"; | 193 | return value ? "True" : "False"; |
| 210 | } | 194 | } |
| 211 | 195 | ||
| 212 | bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) | 196 | bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, |
| 213 | { | 197 | std::string* _pExtension) { |
| 214 | if (full_path.empty()) | 198 | if (full_path.empty()) |
| 215 | return false; | 199 | return false; |
| 216 | 200 | ||
| 217 | size_t dir_end = full_path.find_last_of("/" | 201 | size_t dir_end = full_path.find_last_of("/" |
| 218 | // windows needs the : included for something like just "C:" to be considered a directory | 202 | // windows needs the : included for something like just "C:" to be considered a directory |
| 219 | #ifdef _WIN32 | 203 | #ifdef _WIN32 |
| 220 | ":" | 204 | ":" |
| 221 | #endif | 205 | #endif |
| 222 | ); | 206 | ); |
| 223 | if (std::string::npos == dir_end) | 207 | if (std::string::npos == dir_end) |
| 224 | dir_end = 0; | 208 | dir_end = 0; |
| 225 | else | 209 | else |
| @@ -241,8 +225,8 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ | |||
| 241 | return true; | 225 | return true; |
| 242 | } | 226 | } |
| 243 | 227 | ||
| 244 | void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename) | 228 | void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, |
| 245 | { | 229 | const std::string& _Filename) { |
| 246 | _CompleteFilename = _Path; | 230 | _CompleteFilename = _Path; |
| 247 | 231 | ||
| 248 | // check for seperator | 232 | // check for seperator |
| @@ -253,8 +237,7 @@ void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _P | |||
| 253 | _CompleteFilename += _Filename; | 237 | _CompleteFilename += _Filename; |
| 254 | } | 238 | } |
| 255 | 239 | ||
| 256 | void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) | 240 | void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) { |
| 257 | { | ||
| 258 | std::istringstream iss(str); | 241 | std::istringstream iss(str); |
| 259 | output.resize(1); | 242 | output.resize(1); |
| 260 | 243 | ||
| @@ -264,8 +247,7 @@ void SplitString(const std::string& str, const char delim, std::vector<std::stri | |||
| 264 | output.pop_back(); | 247 | output.pop_back(); |
| 265 | } | 248 | } |
| 266 | 249 | ||
| 267 | std::string TabsToSpaces(int tab_size, const std::string &in) | 250 | std::string TabsToSpaces(int tab_size, const std::string& in) { |
| 268 | { | ||
| 269 | const std::string spaces(tab_size, ' '); | 251 | const std::string spaces(tab_size, ' '); |
| 270 | std::string out(in); | 252 | std::string out(in); |
| 271 | 253 | ||
| @@ -276,15 +258,13 @@ std::string TabsToSpaces(int tab_size, const std::string &in) | |||
| 276 | return out; | 258 | return out; |
| 277 | } | 259 | } |
| 278 | 260 | ||
| 279 | std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) | 261 | std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) { |
| 280 | { | ||
| 281 | size_t pos = 0; | 262 | size_t pos = 0; |
| 282 | 263 | ||
| 283 | if (src == dest) | 264 | if (src == dest) |
| 284 | return result; | 265 | return result; |
| 285 | 266 | ||
| 286 | while ((pos = result.find(src, pos)) != std::string::npos) | 267 | while ((pos = result.find(src, pos)) != std::string::npos) { |
| 287 | { | ||
| 288 | result.replace(pos, src.size(), dest); | 268 | result.replace(pos, src.size(), dest); |
| 289 | pos += dest.length(); | 269 | pos += dest.length(); |
| 290 | } | 270 | } |
| @@ -294,8 +274,7 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st | |||
| 294 | 274 | ||
| 295 | #ifdef _MSC_VER | 275 | #ifdef _MSC_VER |
| 296 | 276 | ||
| 297 | std::string UTF16ToUTF8(const std::u16string& input) | 277 | std::string UTF16ToUTF8(const std::u16string& input) { |
| 298 | { | ||
| 299 | #if _MSC_VER >= 1900 | 278 | #if _MSC_VER >= 1900 |
| 300 | // Workaround for missing char16_t/char32_t instantiations in MSVC2015 | 279 | // Workaround for missing char16_t/char32_t instantiations in MSVC2015 |
| 301 | std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; | 280 | std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; |
| @@ -307,8 +286,7 @@ std::string UTF16ToUTF8(const std::u16string& input) | |||
| 307 | #endif | 286 | #endif |
| 308 | } | 287 | } |
| 309 | 288 | ||
| 310 | std::u16string UTF8ToUTF16(const std::string& input) | 289 | std::u16string UTF8ToUTF16(const std::string& input) { |
| 311 | { | ||
| 312 | #if _MSC_VER >= 1900 | 290 | #if _MSC_VER >= 1900 |
| 313 | // Workaround for missing char16_t/char32_t instantiations in MSVC2015 | 291 | // Workaround for missing char16_t/char32_t instantiations in MSVC2015 |
| 314 | std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; | 292 | std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; |
| @@ -320,57 +298,56 @@ std::u16string UTF8ToUTF16(const std::string& input) | |||
| 320 | #endif | 298 | #endif |
| 321 | } | 299 | } |
| 322 | 300 | ||
| 323 | static std::wstring CPToUTF16(u32 code_page, const std::string& input) | 301 | static std::wstring CPToUTF16(u32 code_page, const std::string& input) { |
| 324 | { | 302 | auto const size = |
| 325 | auto const size = MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0); | 303 | MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0); |
| 326 | 304 | ||
| 327 | std::wstring output; | 305 | std::wstring output; |
| 328 | output.resize(size); | 306 | output.resize(size); |
| 329 | 307 | ||
| 330 | if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()))) | 308 | if (size == 0 || |
| 309 | size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), | ||
| 310 | &output[0], static_cast<int>(output.size()))) | ||
| 331 | output.clear(); | 311 | output.clear(); |
| 332 | 312 | ||
| 333 | return output; | 313 | return output; |
| 334 | } | 314 | } |
| 335 | 315 | ||
| 336 | std::string UTF16ToUTF8(const std::wstring& input) | 316 | std::string UTF16ToUTF8(const std::wstring& input) { |
| 337 | { | 317 | 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); | 318 | nullptr, 0, nullptr, nullptr); |
| 339 | 319 | ||
| 340 | std::string output; | 320 | std::string output; |
| 341 | output.resize(size); | 321 | output.resize(size); |
| 342 | 322 | ||
| 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)) | 323 | if (size == 0 || |
| 324 | size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), | ||
| 325 | &output[0], static_cast<int>(output.size()), nullptr, nullptr)) | ||
| 344 | output.clear(); | 326 | output.clear(); |
| 345 | 327 | ||
| 346 | return output; | 328 | return output; |
| 347 | } | 329 | } |
| 348 | 330 | ||
| 349 | std::wstring UTF8ToUTF16W(const std::string &input) | 331 | std::wstring UTF8ToUTF16W(const std::string& input) { |
| 350 | { | ||
| 351 | return CPToUTF16(CP_UTF8, input); | 332 | return CPToUTF16(CP_UTF8, input); |
| 352 | } | 333 | } |
| 353 | 334 | ||
| 354 | std::string SHIFTJISToUTF8(const std::string& input) | 335 | std::string SHIFTJISToUTF8(const std::string& input) { |
| 355 | { | ||
| 356 | return UTF16ToUTF8(CPToUTF16(932, input)); | 336 | return UTF16ToUTF8(CPToUTF16(932, input)); |
| 357 | } | 337 | } |
| 358 | 338 | ||
| 359 | std::string CP1252ToUTF8(const std::string& input) | 339 | std::string CP1252ToUTF8(const std::string& input) { |
| 360 | { | ||
| 361 | return UTF16ToUTF8(CPToUTF16(1252, input)); | 340 | return UTF16ToUTF8(CPToUTF16(1252, input)); |
| 362 | } | 341 | } |
| 363 | 342 | ||
| 364 | #else | 343 | #else |
| 365 | 344 | ||
| 366 | template <typename T> | 345 | template <typename T> |
| 367 | static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) | 346 | static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) { |
| 368 | { | ||
| 369 | std::string result; | 347 | std::string result; |
| 370 | 348 | ||
| 371 | iconv_t const conv_desc = iconv_open("UTF-8", fromcode); | 349 | iconv_t const conv_desc = iconv_open("UTF-8", fromcode); |
| 372 | if ((iconv_t)(-1) == conv_desc) | 350 | if ((iconv_t)(-1) == conv_desc) { |
| 373 | { | ||
| 374 | LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); | 351 | LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); |
| 375 | iconv_close(conv_desc); | 352 | iconv_close(conv_desc); |
| 376 | return {}; | 353 | return {}; |
| @@ -388,24 +365,18 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& | |||
| 388 | auto dst_buffer = &out_buffer[0]; | 365 | auto dst_buffer = &out_buffer[0]; |
| 389 | size_t dst_bytes = out_buffer.size(); | 366 | size_t dst_bytes = out_buffer.size(); |
| 390 | 367 | ||
| 391 | while (0 != src_bytes) | 368 | while (0 != src_bytes) { |
| 392 | { | 369 | size_t const iconv_result = |
| 393 | size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, | 370 | iconv(conv_desc, (char**)(&src_buffer), &src_bytes, &dst_buffer, &dst_bytes); |
| 394 | &dst_buffer, &dst_bytes); | ||
| 395 | 371 | ||
| 396 | if (static_cast<size_t>(-1) == iconv_result) | 372 | if (static_cast<size_t>(-1) == iconv_result) { |
| 397 | { | 373 | if (EILSEQ == errno || EINVAL == errno) { |
| 398 | if (EILSEQ == errno || EINVAL == errno) | ||
| 399 | { | ||
| 400 | // Try to skip the bad character | 374 | // Try to skip the bad character |
| 401 | if (0 != src_bytes) | 375 | if (0 != src_bytes) { |
| 402 | { | ||
| 403 | --src_bytes; | 376 | --src_bytes; |
| 404 | ++src_buffer; | 377 | ++src_buffer; |
| 405 | } | 378 | } |
| 406 | } | 379 | } else { |
| 407 | else | ||
| 408 | { | ||
| 409 | LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno)); | 380 | LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno)); |
| 410 | break; | 381 | break; |
| 411 | } | 382 | } |
| @@ -420,13 +391,11 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& | |||
| 420 | return result; | 391 | return result; |
| 421 | } | 392 | } |
| 422 | 393 | ||
| 423 | std::u16string UTF8ToUTF16(const std::string& input) | 394 | std::u16string UTF8ToUTF16(const std::string& input) { |
| 424 | { | ||
| 425 | std::u16string result; | 395 | std::u16string result; |
| 426 | 396 | ||
| 427 | iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8"); | 397 | iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8"); |
| 428 | if ((iconv_t)(-1) == conv_desc) | 398 | if ((iconv_t)(-1) == conv_desc) { |
| 429 | { | ||
| 430 | LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno)); | 399 | LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno)); |
| 431 | iconv_close(conv_desc); | 400 | iconv_close(conv_desc); |
| 432 | return {}; | 401 | return {}; |
| @@ -444,24 +413,18 @@ std::u16string UTF8ToUTF16(const std::string& input) | |||
| 444 | char* dst_buffer = (char*)(&out_buffer[0]); | 413 | char* dst_buffer = (char*)(&out_buffer[0]); |
| 445 | size_t dst_bytes = out_buffer.size(); | 414 | size_t dst_bytes = out_buffer.size(); |
| 446 | 415 | ||
| 447 | while (0 != src_bytes) | 416 | while (0 != src_bytes) { |
| 448 | { | 417 | size_t const iconv_result = |
| 449 | size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes, | 418 | iconv(conv_desc, &src_buffer, &src_bytes, &dst_buffer, &dst_bytes); |
| 450 | &dst_buffer, &dst_bytes); | ||
| 451 | 419 | ||
| 452 | if (static_cast<size_t>(-1) == iconv_result) | 420 | if (static_cast<size_t>(-1) == iconv_result) { |
| 453 | { | 421 | if (EILSEQ == errno || EINVAL == errno) { |
| 454 | if (EILSEQ == errno || EINVAL == errno) | ||
| 455 | { | ||
| 456 | // Try to skip the bad character | 422 | // Try to skip the bad character |
| 457 | if (0 != src_bytes) | 423 | if (0 != src_bytes) { |
| 458 | { | ||
| 459 | --src_bytes; | 424 | --src_bytes; |
| 460 | ++src_buffer; | 425 | ++src_buffer; |
| 461 | } | 426 | } |
| 462 | } | 427 | } else { |
| 463 | else | ||
| 464 | { | ||
| 465 | LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno)); | 428 | LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno)); |
| 466 | break; | 429 | break; |
| 467 | } | 430 | } |
| @@ -476,32 +439,28 @@ std::u16string UTF8ToUTF16(const std::string& input) | |||
| 476 | return result; | 439 | return result; |
| 477 | } | 440 | } |
| 478 | 441 | ||
| 479 | std::string UTF16ToUTF8(const std::u16string& input) | 442 | std::string UTF16ToUTF8(const std::u16string& input) { |
| 480 | { | ||
| 481 | return CodeToUTF8("UTF-16LE", input); | 443 | return CodeToUTF8("UTF-16LE", input); |
| 482 | } | 444 | } |
| 483 | 445 | ||
| 484 | std::string CP1252ToUTF8(const std::string& input) | 446 | std::string CP1252ToUTF8(const std::string& input) { |
| 485 | { | 447 | // return CodeToUTF8("CP1252//TRANSLIT", input); |
| 486 | //return CodeToUTF8("CP1252//TRANSLIT", input); | 448 | // return CodeToUTF8("CP1252//IGNORE", input); |
| 487 | //return CodeToUTF8("CP1252//IGNORE", input); | ||
| 488 | return CodeToUTF8("CP1252", input); | 449 | return CodeToUTF8("CP1252", input); |
| 489 | } | 450 | } |
| 490 | 451 | ||
| 491 | std::string SHIFTJISToUTF8(const std::string& input) | 452 | std::string SHIFTJISToUTF8(const std::string& input) { |
| 492 | { | 453 | // return CodeToUTF8("CP932", input); |
| 493 | //return CodeToUTF8("CP932", input); | ||
| 494 | return CodeToUTF8("SJIS", input); | 454 | return CodeToUTF8("SJIS", input); |
| 495 | } | 455 | } |
| 496 | 456 | ||
| 497 | #endif | 457 | #endif |
| 498 | 458 | ||
| 499 | std::string StringFromFixedZeroTerminatedBuffer(const char * buffer, size_t max_len) { | 459 | std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len) { |
| 500 | size_t len = 0; | 460 | size_t len = 0; |
| 501 | while (len < max_len && buffer[len] != '\0') | 461 | while (len < max_len && buffer[len] != '\0') |
| 502 | ++len; | 462 | ++len; |
| 503 | 463 | ||
| 504 | return std::string(buffer, len); | 464 | return std::string(buffer, len); |
| 505 | } | 465 | } |
| 506 | |||
| 507 | } | 466 | } |
diff --git a/src/common/string_util.h b/src/common/string_util.h index 89d9f133e..6ffd735f4 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h | |||
| @@ -25,9 +25,8 @@ std::string StringFromFormat(const char* format, ...); | |||
| 25 | // Cheap! | 25 | // Cheap! |
| 26 | bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); | 26 | bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); |
| 27 | 27 | ||
| 28 | template<size_t Count> | 28 | template <size_t Count> |
| 29 | inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) | 29 | inline void CharArrayFromFormat(char (&out)[Count], const char* format, ...) { |
| 30 | { | ||
| 31 | va_list args; | 30 | va_list args; |
| 32 | va_start(args, format); | 31 | va_start(args, format); |
| 33 | CharArrayFromFormatV(out, Count, format, args); | 32 | CharArrayFromFormatV(out, Count, format, args); |
| @@ -35,15 +34,14 @@ inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) | |||
| 35 | } | 34 | } |
| 36 | 35 | ||
| 37 | // Good | 36 | // Good |
| 38 | std::string ArrayToString(const u8 *data, u32 size, int line_len = 20, bool spaces = true); | 37 | std::string ArrayToString(const u8* data, u32 size, int line_len = 20, bool spaces = true); |
| 39 | 38 | ||
| 40 | std::string StripSpaces(const std::string &s); | 39 | std::string StripSpaces(const std::string& s); |
| 41 | std::string StripQuotes(const std::string &s); | 40 | std::string StripQuotes(const std::string& s); |
| 42 | 41 | ||
| 43 | // Thousand separator. Turns 12345678 into 12,345,678 | 42 | // Thousand separator. Turns 12345678 into 12,345,678 |
| 44 | template <typename I> | 43 | template <typename I> |
| 45 | std::string ThousandSeparate(I value, int spaces = 0) | 44 | std::string ThousandSeparate(I value, int spaces = 0) { |
| 46 | { | ||
| 47 | std::ostringstream oss; | 45 | std::ostringstream oss; |
| 48 | 46 | ||
| 49 | // std::locale("") seems to be broken on many platforms | 47 | // std::locale("") seems to be broken on many platforms |
| @@ -57,35 +55,34 @@ std::string ThousandSeparate(I value, int spaces = 0) | |||
| 57 | 55 | ||
| 58 | std::string StringFromBool(bool value); | 56 | std::string StringFromBool(bool value); |
| 59 | 57 | ||
| 60 | bool TryParse(const std::string &str, bool *output); | 58 | bool TryParse(const std::string& str, bool* output); |
| 61 | bool TryParse(const std::string &str, u32 *output); | 59 | bool TryParse(const std::string& str, u32* output); |
| 62 | 60 | ||
| 63 | template <typename N> | 61 | template <typename N> |
| 64 | static bool TryParse(const std::string &str, N *const output) | 62 | static bool TryParse(const std::string& str, N* const output) { |
| 65 | { | ||
| 66 | std::istringstream iss(str); | 63 | std::istringstream iss(str); |
| 67 | 64 | ||
| 68 | N tmp = 0; | 65 | N tmp = 0; |
| 69 | if (iss >> tmp) | 66 | if (iss >> tmp) { |
| 70 | { | ||
| 71 | *output = tmp; | 67 | *output = tmp; |
| 72 | return true; | 68 | return true; |
| 73 | } | 69 | } else |
| 74 | else | ||
| 75 | return false; | 70 | return false; |
| 76 | } | 71 | } |
| 77 | 72 | ||
| 78 | // TODO: kill this | 73 | // TODO: kill this |
| 79 | bool AsciiToHex(const char* _szValue, u32& result); | 74 | bool AsciiToHex(const char* _szValue, u32& result); |
| 80 | 75 | ||
| 81 | std::string TabsToSpaces(int tab_size, const std::string &in); | 76 | std::string TabsToSpaces(int tab_size, const std::string& in); |
| 82 | 77 | ||
| 83 | void SplitString(const std::string& str, char delim, std::vector<std::string>& output); | 78 | void SplitString(const std::string& str, char delim, std::vector<std::string>& output); |
| 84 | 79 | ||
| 85 | // "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" | 80 | // "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); | 81 | bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, |
| 82 | std::string* _pExtension); | ||
| 87 | 83 | ||
| 88 | void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename); | 84 | void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, |
| 85 | const std::string& _Filename); | ||
| 89 | std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); | 86 | std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); |
| 90 | 87 | ||
| 91 | std::string UTF16ToUTF8(const std::u16string& input); | 88 | std::string UTF16ToUTF8(const std::u16string& input); |
| @@ -99,17 +96,21 @@ std::string UTF16ToUTF8(const std::wstring& input); | |||
| 99 | std::wstring UTF8ToUTF16W(const std::string& str); | 96 | std::wstring UTF8ToUTF16W(const std::string& str); |
| 100 | 97 | ||
| 101 | #ifdef _UNICODE | 98 | #ifdef _UNICODE |
| 102 | inline std::string TStrToUTF8(const std::wstring& str) | 99 | inline std::string TStrToUTF8(const std::wstring& str) { |
| 103 | { return UTF16ToUTF8(str); } | 100 | return UTF16ToUTF8(str); |
| 101 | } | ||
| 104 | 102 | ||
| 105 | inline std::wstring UTF8ToTStr(const std::string& str) | 103 | inline std::wstring UTF8ToTStr(const std::string& str) { |
| 106 | { return UTF8ToUTF16W(str); } | 104 | return UTF8ToUTF16W(str); |
| 105 | } | ||
| 107 | #else | 106 | #else |
| 108 | inline std::string TStrToUTF8(const std::string& str) | 107 | inline std::string TStrToUTF8(const std::string& str) { |
| 109 | { return str; } | 108 | return str; |
| 109 | } | ||
| 110 | 110 | ||
| 111 | inline std::string UTF8ToTStr(const std::string& str) | 111 | inline std::string UTF8ToTStr(const std::string& str) { |
| 112 | { return str; } | 112 | return str; |
| 113 | } | ||
| 113 | #endif | 114 | #endif |
| 114 | 115 | ||
| 115 | #endif | 116 | #endif |
| @@ -134,5 +135,4 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) { | |||
| 134 | * NUL-terminated then the string ends at max_len characters. | 135 | * NUL-terminated then the string ends at max_len characters. |
| 135 | */ | 136 | */ |
| 136 | std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len); | 137 | std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len); |
| 137 | |||
| 138 | } | 138 | } |
diff --git a/src/common/swap.h b/src/common/swap.h index 1749bd7a4..1794144fb 100644 --- a/src/common/swap.h +++ b/src/common/swap.h | |||
| @@ -18,11 +18,11 @@ | |||
| 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 | 27 | ||
| 28 | #include <cstring> | 28 | #include <cstring> |
| @@ -61,38 +61,73 @@ | |||
| 61 | namespace Common { | 61 | namespace Common { |
| 62 | 62 | ||
| 63 | #ifdef _MSC_VER | 63 | #ifdef _MSC_VER |
| 64 | inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} | 64 | inline u16 swap16(u16 _data) { |
| 65 | inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} | 65 | return _byteswap_ushort(_data); |
| 66 | inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} | 66 | } |
| 67 | inline u32 swap32(u32 _data) { | ||
| 68 | return _byteswap_ulong(_data); | ||
| 69 | } | ||
| 70 | inline u64 swap64(u64 _data) { | ||
| 71 | return _byteswap_uint64(_data); | ||
| 72 | } | ||
| 67 | #elif _M_ARM | 73 | #elif _M_ARM |
| 68 | inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} | 74 | inline u16 swap16(u16 _data) { |
| 69 | inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} | 75 | u32 data = _data; |
| 70 | inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} | 76 | __asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data)); |
| 77 | return (u16)data; | ||
| 78 | } | ||
| 79 | inline u32 swap32(u32 _data) { | ||
| 80 | __asm__("rev %0, %1\n" : "=l"(_data) : "l"(_data)); | ||
| 81 | return _data; | ||
| 82 | } | ||
| 83 | inline u64 swap64(u64 _data) { | ||
| 84 | return ((u64)swap32(_data) << 32) | swap32(_data >> 32); | ||
| 85 | } | ||
| 71 | #elif __linux__ | 86 | #elif __linux__ |
| 72 | inline u16 swap16(u16 _data) {return bswap_16(_data);} | 87 | inline u16 swap16(u16 _data) { |
| 73 | inline u32 swap32(u32 _data) {return bswap_32(_data);} | 88 | return bswap_16(_data); |
| 74 | inline u64 swap64(u64 _data) {return bswap_64(_data);} | 89 | } |
| 90 | inline u32 swap32(u32 _data) { | ||
| 91 | return bswap_32(_data); | ||
| 92 | } | ||
| 93 | inline u64 swap64(u64 _data) { | ||
| 94 | return bswap_64(_data); | ||
| 95 | } | ||
| 75 | #elif __APPLE__ | 96 | #elif __APPLE__ |
| 76 | inline __attribute__((always_inline)) u16 swap16(u16 _data) | 97 | inline __attribute__((always_inline)) u16 swap16(u16 _data) { |
| 77 | {return (_data >> 8) | (_data << 8);} | 98 | return (_data >> 8) | (_data << 8); |
| 78 | inline __attribute__((always_inline)) u32 swap32(u32 _data) | 99 | } |
| 79 | {return __builtin_bswap32(_data);} | 100 | inline __attribute__((always_inline)) u32 swap32(u32 _data) { |
| 80 | inline __attribute__((always_inline)) u64 swap64(u64 _data) | 101 | return __builtin_bswap32(_data); |
| 81 | {return __builtin_bswap64(_data);} | 102 | } |
| 103 | inline __attribute__((always_inline)) u64 swap64(u64 _data) { | ||
| 104 | return __builtin_bswap64(_data); | ||
| 105 | } | ||
| 82 | #elif __FreeBSD__ | 106 | #elif __FreeBSD__ |
| 83 | inline u16 swap16(u16 _data) {return bswap16(_data);} | 107 | inline u16 swap16(u16 _data) { |
| 84 | inline u32 swap32(u32 _data) {return bswap32(_data);} | 108 | return bswap16(_data); |
| 85 | inline u64 swap64(u64 _data) {return bswap64(_data);} | 109 | } |
| 110 | inline u32 swap32(u32 _data) { | ||
| 111 | return bswap32(_data); | ||
| 112 | } | ||
| 113 | inline u64 swap64(u64 _data) { | ||
| 114 | return bswap64(_data); | ||
| 115 | } | ||
| 86 | #else | 116 | #else |
| 87 | // Slow generic implementation. | 117 | // Slow generic implementation. |
| 88 | inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} | 118 | inline u16 swap16(u16 data) { |
| 89 | inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} | 119 | return (data >> 8) | (data << 8); |
| 90 | inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} | 120 | } |
| 121 | inline u32 swap32(u32 data) { | ||
| 122 | return (swap16(data) << 16) | swap16(data >> 16); | ||
| 123 | } | ||
| 124 | inline u64 swap64(u64 data) { | ||
| 125 | return ((u64)swap32(data) << 32) | swap32(data >> 32); | ||
| 126 | } | ||
| 91 | #endif | 127 | #endif |
| 92 | 128 | ||
| 93 | inline float swapf(float f) { | 129 | inline float swapf(float f) { |
| 94 | static_assert(sizeof(u32) == sizeof(float), | 130 | 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 | 131 | ||
| 97 | u32 value; | 132 | u32 value; |
| 98 | std::memcpy(&value, &f, sizeof(u32)); | 133 | std::memcpy(&value, &f, sizeof(u32)); |
| @@ -104,8 +139,7 @@ inline float swapf(float f) { | |||
| 104 | } | 139 | } |
| 105 | 140 | ||
| 106 | inline double swapd(double f) { | 141 | inline double swapd(double f) { |
| 107 | static_assert(sizeof(u64) == sizeof(double), | 142 | 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 | 143 | ||
| 110 | u64 value; | 144 | u64 value; |
| 111 | std::memcpy(&value, &f, sizeof(u64)); | 145 | std::memcpy(&value, &f, sizeof(u64)); |
| @@ -116,8 +150,7 @@ inline double swapd(double f) { | |||
| 116 | return f; | 150 | return f; |
| 117 | } | 151 | } |
| 118 | 152 | ||
| 119 | } // Namespace Common | 153 | } // Namespace Common |
| 120 | |||
| 121 | 154 | ||
| 122 | template <typename T, typename F> | 155 | template <typename T, typename F> |
| 123 | struct swap_struct_t { | 156 | struct swap_struct_t { |
| @@ -129,251 +162,272 @@ protected: | |||
| 129 | static T swap(T v) { | 162 | static T swap(T v) { |
| 130 | return F::swap(v); | 163 | return F::swap(v); |
| 131 | } | 164 | } |
| 165 | |||
| 132 | public: | 166 | public: |
| 133 | T const swap() const { | 167 | T const swap() const { |
| 134 | return swap(value); | 168 | return swap(value); |
| 135 | |||
| 136 | } | 169 | } |
| 137 | swap_struct_t() = default; | 170 | swap_struct_t() = default; |
| 138 | swap_struct_t(const T &v): value(swap(v)) {} | 171 | swap_struct_t(const T& v) : value(swap(v)) { |
| 172 | } | ||
| 139 | 173 | ||
| 140 | template <typename S> | 174 | template <typename S> |
| 141 | swapped_t& operator=(const S &source) { | 175 | swapped_t& operator=(const S& source) { |
| 142 | value = swap((T)source); | 176 | value = swap((T)source); |
| 143 | return *this; | 177 | return *this; |
| 144 | } | 178 | } |
| 145 | 179 | ||
| 146 | operator s8() const { return (s8)swap(); } | 180 | operator s8() const { |
| 147 | operator u8() const { return (u8)swap(); } | 181 | return (s8)swap(); |
| 148 | operator s16() const { return (s16)swap(); } | 182 | } |
| 149 | operator u16() const { return (u16)swap(); } | 183 | operator u8() const { |
| 150 | operator s32() const { return (s32)swap(); } | 184 | return (u8)swap(); |
| 151 | operator u32() const { return (u32)swap(); } | 185 | } |
| 152 | operator s64() const { return (s64)swap(); } | 186 | operator s16() const { |
| 153 | operator u64() const { return (u64)swap(); } | 187 | return (s16)swap(); |
| 154 | operator float() const { return (float)swap(); } | 188 | } |
| 155 | operator double() const { return (double)swap(); } | 189 | operator u16() const { |
| 190 | return (u16)swap(); | ||
| 191 | } | ||
| 192 | operator s32() const { | ||
| 193 | return (s32)swap(); | ||
| 194 | } | ||
| 195 | operator u32() const { | ||
| 196 | return (u32)swap(); | ||
| 197 | } | ||
| 198 | operator s64() const { | ||
| 199 | return (s64)swap(); | ||
| 200 | } | ||
| 201 | operator u64() const { | ||
| 202 | return (u64)swap(); | ||
| 203 | } | ||
| 204 | operator float() const { | ||
| 205 | return (float)swap(); | ||
| 206 | } | ||
| 207 | operator double() const { | ||
| 208 | return (double)swap(); | ||
| 209 | } | ||
| 156 | 210 | ||
| 157 | // +v | 211 | // +v |
| 158 | swapped_t operator +() const { | 212 | swapped_t operator+() const { |
| 159 | return +swap(); | 213 | return +swap(); |
| 160 | } | 214 | } |
| 161 | // -v | 215 | // -v |
| 162 | swapped_t operator -() const { | 216 | swapped_t operator-() const { |
| 163 | return -swap(); | 217 | return -swap(); |
| 164 | } | 218 | } |
| 165 | 219 | ||
| 166 | // v / 5 | 220 | // v / 5 |
| 167 | swapped_t operator/(const swapped_t &i) const { | 221 | swapped_t operator/(const swapped_t& i) const { |
| 168 | return swap() / i.swap(); | 222 | return swap() / i.swap(); |
| 169 | } | 223 | } |
| 170 | template <typename S> | 224 | template <typename S> |
| 171 | swapped_t operator/(const S &i) const { | 225 | swapped_t operator/(const S& i) const { |
| 172 | return swap() / i; | 226 | return swap() / i; |
| 173 | } | 227 | } |
| 174 | 228 | ||
| 175 | // v * 5 | 229 | // v * 5 |
| 176 | swapped_t operator*(const swapped_t &i) const { | 230 | swapped_t operator*(const swapped_t& i) const { |
| 177 | return swap() * i.swap(); | 231 | return swap() * i.swap(); |
| 178 | } | 232 | } |
| 179 | template <typename S> | 233 | template <typename S> |
| 180 | swapped_t operator*(const S &i) const { | 234 | swapped_t operator*(const S& i) const { |
| 181 | return swap() * i; | 235 | return swap() * i; |
| 182 | } | 236 | } |
| 183 | 237 | ||
| 184 | // v + 5 | 238 | // v + 5 |
| 185 | swapped_t operator+(const swapped_t &i) const { | 239 | swapped_t operator+(const swapped_t& i) const { |
| 186 | return swap() + i.swap(); | 240 | return swap() + i.swap(); |
| 187 | } | 241 | } |
| 188 | template <typename S> | 242 | template <typename S> |
| 189 | swapped_t operator+(const S &i) const { | 243 | swapped_t operator+(const S& i) const { |
| 190 | return swap() + (T)i; | 244 | return swap() + (T)i; |
| 191 | } | 245 | } |
| 192 | // v - 5 | 246 | // v - 5 |
| 193 | swapped_t operator-(const swapped_t &i) const { | 247 | swapped_t operator-(const swapped_t& i) const { |
| 194 | return swap() - i.swap(); | 248 | return swap() - i.swap(); |
| 195 | } | 249 | } |
| 196 | template <typename S> | 250 | template <typename S> |
| 197 | swapped_t operator-(const S &i) const { | 251 | swapped_t operator-(const S& i) const { |
| 198 | return swap() - (T)i; | 252 | return swap() - (T)i; |
| 199 | } | 253 | } |
| 200 | 254 | ||
| 201 | // v += 5 | 255 | // v += 5 |
| 202 | swapped_t& operator+=(const swapped_t &i) { | 256 | swapped_t& operator+=(const swapped_t& i) { |
| 203 | value = swap(swap() + i.swap()); | 257 | value = swap(swap() + i.swap()); |
| 204 | return *this; | 258 | return *this; |
| 205 | } | 259 | } |
| 206 | template <typename S> | 260 | template <typename S> |
| 207 | swapped_t& operator+=(const S &i) { | 261 | swapped_t& operator+=(const S& i) { |
| 208 | value = swap(swap() + (T)i); | 262 | value = swap(swap() + (T)i); |
| 209 | return *this; | 263 | return *this; |
| 210 | } | 264 | } |
| 211 | // v -= 5 | 265 | // v -= 5 |
| 212 | swapped_t& operator-=(const swapped_t &i) { | 266 | swapped_t& operator-=(const swapped_t& i) { |
| 213 | value = swap(swap() - i.swap()); | 267 | value = swap(swap() - i.swap()); |
| 214 | return *this; | 268 | return *this; |
| 215 | } | 269 | } |
| 216 | template <typename S> | 270 | template <typename S> |
| 217 | swapped_t& operator-=(const S &i) { | 271 | swapped_t& operator-=(const S& i) { |
| 218 | value = swap(swap() - (T)i); | 272 | value = swap(swap() - (T)i); |
| 219 | return *this; | 273 | return *this; |
| 220 | } | 274 | } |
| 221 | 275 | ||
| 222 | // ++v | 276 | // ++v |
| 223 | swapped_t& operator++() { | 277 | swapped_t& operator++() { |
| 224 | value = swap(swap()+1); | 278 | value = swap(swap() + 1); |
| 225 | return *this; | 279 | return *this; |
| 226 | } | 280 | } |
| 227 | // --v | 281 | // --v |
| 228 | swapped_t& operator--() { | 282 | swapped_t& operator--() { |
| 229 | value = swap(swap()-1); | 283 | value = swap(swap() - 1); |
| 230 | return *this; | 284 | return *this; |
| 231 | } | 285 | } |
| 232 | 286 | ||
| 233 | // v++ | 287 | // v++ |
| 234 | swapped_t operator++(int) { | 288 | swapped_t operator++(int) { |
| 235 | swapped_t old = *this; | 289 | swapped_t old = *this; |
| 236 | value = swap(swap()+1); | 290 | value = swap(swap() + 1); |
| 237 | return old; | 291 | return old; |
| 238 | } | 292 | } |
| 239 | // v-- | 293 | // v-- |
| 240 | swapped_t operator--(int) { | 294 | swapped_t operator--(int) { |
| 241 | swapped_t old = *this; | 295 | swapped_t old = *this; |
| 242 | value = swap(swap()-1); | 296 | value = swap(swap() - 1); |
| 243 | return old; | 297 | return old; |
| 244 | } | 298 | } |
| 245 | // Comparaison | 299 | // Comparaison |
| 246 | // v == i | 300 | // v == i |
| 247 | bool operator==(const swapped_t &i) const { | 301 | bool operator==(const swapped_t& i) const { |
| 248 | return swap() == i.swap(); | 302 | return swap() == i.swap(); |
| 249 | } | 303 | } |
| 250 | template <typename S> | 304 | template <typename S> |
| 251 | bool operator==(const S &i) const { | 305 | bool operator==(const S& i) const { |
| 252 | return swap() == i; | 306 | return swap() == i; |
| 253 | } | 307 | } |
| 254 | 308 | ||
| 255 | // v != i | 309 | // v != i |
| 256 | bool operator!=(const swapped_t &i) const { | 310 | bool operator!=(const swapped_t& i) const { |
| 257 | return swap() != i.swap(); | 311 | return swap() != i.swap(); |
| 258 | } | 312 | } |
| 259 | template <typename S> | 313 | template <typename S> |
| 260 | bool operator!=(const S &i) const { | 314 | bool operator!=(const S& i) const { |
| 261 | return swap() != i; | 315 | return swap() != i; |
| 262 | } | 316 | } |
| 263 | 317 | ||
| 264 | // v > i | 318 | // v > i |
| 265 | bool operator>(const swapped_t &i) const { | 319 | bool operator>(const swapped_t& i) const { |
| 266 | return swap() > i.swap(); | 320 | return swap() > i.swap(); |
| 267 | } | 321 | } |
| 268 | template <typename S> | 322 | template <typename S> |
| 269 | bool operator>(const S &i) const { | 323 | bool operator>(const S& i) const { |
| 270 | return swap() > i; | 324 | return swap() > i; |
| 271 | } | 325 | } |
| 272 | 326 | ||
| 273 | // v < i | 327 | // v < i |
| 274 | bool operator<(const swapped_t &i) const { | 328 | bool operator<(const swapped_t& i) const { |
| 275 | return swap() < i.swap(); | 329 | return swap() < i.swap(); |
| 276 | } | 330 | } |
| 277 | template <typename S> | 331 | template <typename S> |
| 278 | bool operator<(const S &i) const { | 332 | bool operator<(const S& i) const { |
| 279 | return swap() < i; | 333 | return swap() < i; |
| 280 | } | 334 | } |
| 281 | 335 | ||
| 282 | // v >= i | 336 | // v >= i |
| 283 | bool operator>=(const swapped_t &i) const { | 337 | bool operator>=(const swapped_t& i) const { |
| 284 | return swap() >= i.swap(); | 338 | return swap() >= i.swap(); |
| 285 | } | 339 | } |
| 286 | template <typename S> | 340 | template <typename S> |
| 287 | bool operator>=(const S &i) const { | 341 | bool operator>=(const S& i) const { |
| 288 | return swap() >= i; | 342 | return swap() >= i; |
| 289 | } | 343 | } |
| 290 | 344 | ||
| 291 | // v <= i | 345 | // v <= i |
| 292 | bool operator<=(const swapped_t &i) const { | 346 | bool operator<=(const swapped_t& i) const { |
| 293 | return swap() <= i.swap(); | 347 | return swap() <= i.swap(); |
| 294 | } | 348 | } |
| 295 | template <typename S> | 349 | template <typename S> |
| 296 | bool operator<=(const S &i) const { | 350 | bool operator<=(const S& i) const { |
| 297 | return swap() <= i; | 351 | return swap() <= i; |
| 298 | } | 352 | } |
| 299 | 353 | ||
| 300 | // logical | 354 | // logical |
| 301 | swapped_t operator !() const { | 355 | swapped_t operator!() const { |
| 302 | return !swap(); | 356 | return !swap(); |
| 303 | } | 357 | } |
| 304 | 358 | ||
| 305 | // bitmath | 359 | // bitmath |
| 306 | swapped_t operator ~() const { | 360 | swapped_t operator~() const { |
| 307 | return ~swap(); | 361 | return ~swap(); |
| 308 | } | 362 | } |
| 309 | 363 | ||
| 310 | swapped_t operator &(const swapped_t &b) const { | 364 | swapped_t operator&(const swapped_t& b) const { |
| 311 | return swap() & b.swap(); | 365 | return swap() & b.swap(); |
| 312 | } | 366 | } |
| 313 | template <typename S> | 367 | template <typename S> |
| 314 | swapped_t operator &(const S &b) const { | 368 | swapped_t operator&(const S& b) const { |
| 315 | return swap() & b; | 369 | return swap() & b; |
| 316 | } | 370 | } |
| 317 | swapped_t& operator &=(const swapped_t &b) { | 371 | swapped_t& operator&=(const swapped_t& b) { |
| 318 | value = swap(swap() & b.swap()); | 372 | value = swap(swap() & b.swap()); |
| 319 | return *this; | 373 | return *this; |
| 320 | } | 374 | } |
| 321 | template <typename S> | 375 | template <typename S> |
| 322 | swapped_t& operator &=(const S b) { | 376 | swapped_t& operator&=(const S b) { |
| 323 | value = swap(swap() & b); | 377 | value = swap(swap() & b); |
| 324 | return *this; | 378 | return *this; |
| 325 | } | 379 | } |
| 326 | 380 | ||
| 327 | swapped_t operator |(const swapped_t &b) const { | 381 | swapped_t operator|(const swapped_t& b) const { |
| 328 | return swap() | b.swap(); | 382 | return swap() | b.swap(); |
| 329 | } | 383 | } |
| 330 | template <typename S> | 384 | template <typename S> |
| 331 | swapped_t operator |(const S &b) const { | 385 | swapped_t operator|(const S& b) const { |
| 332 | return swap() | b; | 386 | return swap() | b; |
| 333 | } | 387 | } |
| 334 | swapped_t& operator |=(const swapped_t &b) { | 388 | swapped_t& operator|=(const swapped_t& b) { |
| 335 | value = swap(swap() | b.swap()); | 389 | value = swap(swap() | b.swap()); |
| 336 | return *this; | 390 | return *this; |
| 337 | } | 391 | } |
| 338 | template <typename S> | 392 | template <typename S> |
| 339 | swapped_t& operator |=(const S &b) { | 393 | swapped_t& operator|=(const S& b) { |
| 340 | value = swap(swap() | b); | 394 | value = swap(swap() | b); |
| 341 | return *this; | 395 | return *this; |
| 342 | } | 396 | } |
| 343 | 397 | ||
| 344 | swapped_t operator ^(const swapped_t &b) const { | 398 | swapped_t operator^(const swapped_t& b) const { |
| 345 | return swap() ^ b.swap(); | 399 | return swap() ^ b.swap(); |
| 346 | } | 400 | } |
| 347 | template <typename S> | 401 | template <typename S> |
| 348 | swapped_t operator ^(const S &b) const { | 402 | swapped_t operator^(const S& b) const { |
| 349 | return swap() ^ b; | 403 | return swap() ^ b; |
| 350 | } | 404 | } |
| 351 | swapped_t& operator ^=(const swapped_t &b) { | 405 | swapped_t& operator^=(const swapped_t& b) { |
| 352 | value = swap(swap() ^ b.swap()); | 406 | value = swap(swap() ^ b.swap()); |
| 353 | return *this; | 407 | return *this; |
| 354 | } | 408 | } |
| 355 | template <typename S> | 409 | template <typename S> |
| 356 | swapped_t& operator ^=(const S &b) { | 410 | swapped_t& operator^=(const S& b) { |
| 357 | value = swap(swap() ^ b); | 411 | value = swap(swap() ^ b); |
| 358 | return *this; | 412 | return *this; |
| 359 | } | 413 | } |
| 360 | 414 | ||
| 361 | template <typename S> | 415 | template <typename S> |
| 362 | swapped_t operator <<(const S &b) const { | 416 | swapped_t operator<<(const S& b) const { |
| 363 | return swap() << b; | 417 | return swap() << b; |
| 364 | } | 418 | } |
| 365 | template <typename S> | 419 | template <typename S> |
| 366 | swapped_t& operator <<=(const S &b) const { | 420 | swapped_t& operator<<=(const S& b) const { |
| 367 | value = swap(swap() << b); | 421 | value = swap(swap() << b); |
| 368 | return *this; | 422 | return *this; |
| 369 | } | 423 | } |
| 370 | 424 | ||
| 371 | template <typename S> | 425 | template <typename S> |
| 372 | swapped_t operator >>(const S &b) const { | 426 | swapped_t operator>>(const S& b) const { |
| 373 | return swap() >> b; | 427 | return swap() >> b; |
| 374 | } | 428 | } |
| 375 | template <typename S> | 429 | template <typename S> |
| 376 | swapped_t& operator >>=(const S &b) const { | 430 | swapped_t& operator>>=(const S& b) const { |
| 377 | value = swap(swap() >> b); | 431 | value = swap(swap() >> b); |
| 378 | return *this; | 432 | return *this; |
| 379 | } | 433 | } |
| @@ -381,129 +435,126 @@ public: | |||
| 381 | // Member | 435 | // Member |
| 382 | /** todo **/ | 436 | /** todo **/ |
| 383 | 437 | ||
| 384 | |||
| 385 | // Arithmetics | 438 | // Arithmetics |
| 386 | template <typename S, typename T2, typename F2> | 439 | template <typename S, typename T2, typename F2> |
| 387 | friend S operator+(const S &p, const swapped_t v); | 440 | friend S operator+(const S& p, const swapped_t v); |
| 388 | 441 | ||
| 389 | template <typename S, typename T2, typename F2> | 442 | template <typename S, typename T2, typename F2> |
| 390 | friend S operator-(const S &p, const swapped_t v); | 443 | friend S operator-(const S& p, const swapped_t v); |
| 391 | 444 | ||
| 392 | template <typename S, typename T2, typename F2> | 445 | template <typename S, typename T2, typename F2> |
| 393 | friend S operator/(const S &p, const swapped_t v); | 446 | friend S operator/(const S& p, const swapped_t v); |
| 394 | 447 | ||
| 395 | template <typename S, typename T2, typename F2> | 448 | template <typename S, typename T2, typename F2> |
| 396 | friend S operator*(const S &p, const swapped_t v); | 449 | friend S operator*(const S& p, const swapped_t v); |
| 397 | 450 | ||
| 398 | template <typename S, typename T2, typename F2> | 451 | template <typename S, typename T2, typename F2> |
| 399 | friend S operator%(const S &p, const swapped_t v); | 452 | friend S operator%(const S& p, const swapped_t v); |
| 400 | 453 | ||
| 401 | // Arithmetics + assignements | 454 | // Arithmetics + assignements |
| 402 | template <typename S, typename T2, typename F2> | 455 | template <typename S, typename T2, typename F2> |
| 403 | friend S operator+=(const S &p, const swapped_t v); | 456 | friend S operator+=(const S& p, const swapped_t v); |
| 404 | 457 | ||
| 405 | template <typename S, typename T2, typename F2> | 458 | template <typename S, typename T2, typename F2> |
| 406 | friend S operator-=(const S &p, const swapped_t v); | 459 | friend S operator-=(const S& p, const swapped_t v); |
| 407 | 460 | ||
| 408 | // Bitmath | 461 | // Bitmath |
| 409 | template <typename S, typename T2, typename F2> | 462 | template <typename S, typename T2, typename F2> |
| 410 | friend S operator&(const S &p, const swapped_t v); | 463 | friend S operator&(const S& p, const swapped_t v); |
| 411 | 464 | ||
| 412 | // Comparison | 465 | // Comparison |
| 413 | template <typename S, typename T2, typename F2> | 466 | template <typename S, typename T2, typename F2> |
| 414 | friend bool operator<(const S &p, const swapped_t v); | 467 | friend bool operator<(const S& p, const swapped_t v); |
| 415 | 468 | ||
| 416 | template <typename S, typename T2, typename F2> | 469 | template <typename S, typename T2, typename F2> |
| 417 | friend bool operator>(const S &p, const swapped_t v); | 470 | friend bool operator>(const S& p, const swapped_t v); |
| 418 | 471 | ||
| 419 | template <typename S, typename T2, typename F2> | 472 | template <typename S, typename T2, typename F2> |
| 420 | friend bool operator<=(const S &p, const swapped_t v); | 473 | friend bool operator<=(const S& p, const swapped_t v); |
| 421 | 474 | ||
| 422 | template <typename S, typename T2, typename F2> | 475 | template <typename S, typename T2, typename F2> |
| 423 | friend bool operator>=(const S &p, const swapped_t v); | 476 | friend bool operator>=(const S& p, const swapped_t v); |
| 424 | 477 | ||
| 425 | template <typename S, typename T2, typename F2> | 478 | template <typename S, typename T2, typename F2> |
| 426 | friend bool operator!=(const S &p, const swapped_t v); | 479 | friend bool operator!=(const S& p, const swapped_t v); |
| 427 | 480 | ||
| 428 | template <typename S, typename T2, typename F2> | 481 | template <typename S, typename T2, typename F2> |
| 429 | friend bool operator==(const S &p, const swapped_t v); | 482 | friend bool operator==(const S& p, const swapped_t v); |
| 430 | }; | 483 | }; |
| 431 | 484 | ||
| 432 | |||
| 433 | // Arithmetics | 485 | // Arithmetics |
| 434 | template <typename S, typename T, typename F> | 486 | template <typename S, typename T, typename F> |
| 435 | S operator+(const S &i, const swap_struct_t<T, F> v) { | 487 | S operator+(const S& i, const swap_struct_t<T, F> v) { |
| 436 | return i + v.swap(); | 488 | return i + v.swap(); |
| 437 | } | 489 | } |
| 438 | 490 | ||
| 439 | template <typename S, typename T, typename F> | 491 | template <typename S, typename T, typename F> |
| 440 | S operator-(const S &i, const swap_struct_t<T, F> v) { | 492 | S operator-(const S& i, const swap_struct_t<T, F> v) { |
| 441 | return i - v.swap(); | 493 | return i - v.swap(); |
| 442 | } | 494 | } |
| 443 | 495 | ||
| 444 | template <typename S, typename T, typename F> | 496 | template <typename S, typename T, typename F> |
| 445 | S operator/(const S &i, const swap_struct_t<T, F> v) { | 497 | S operator/(const S& i, const swap_struct_t<T, F> v) { |
| 446 | return i / v.swap(); | 498 | return i / v.swap(); |
| 447 | } | 499 | } |
| 448 | 500 | ||
| 449 | template <typename S, typename T, typename F> | 501 | template <typename S, typename T, typename F> |
| 450 | S operator*(const S &i, const swap_struct_t<T, F> v) { | 502 | S operator*(const S& i, const swap_struct_t<T, F> v) { |
| 451 | return i * v.swap(); | 503 | return i * v.swap(); |
| 452 | } | 504 | } |
| 453 | 505 | ||
| 454 | template <typename S, typename T, typename F> | 506 | template <typename S, typename T, typename F> |
| 455 | S operator%(const S &i, const swap_struct_t<T, F> v) { | 507 | S operator%(const S& i, const swap_struct_t<T, F> v) { |
| 456 | return i % v.swap(); | 508 | return i % v.swap(); |
| 457 | } | 509 | } |
| 458 | 510 | ||
| 459 | // Arithmetics + assignements | 511 | // Arithmetics + assignements |
| 460 | template <typename S, typename T, typename F> | 512 | template <typename S, typename T, typename F> |
| 461 | S &operator+=(S &i, const swap_struct_t<T, F> v) { | 513 | S& operator+=(S& i, const swap_struct_t<T, F> v) { |
| 462 | i += v.swap(); | 514 | i += v.swap(); |
| 463 | return i; | 515 | return i; |
| 464 | } | 516 | } |
| 465 | 517 | ||
| 466 | template <typename S, typename T, typename F> | 518 | template <typename S, typename T, typename F> |
| 467 | S &operator-=(S &i, const swap_struct_t<T, F> v) { | 519 | S& operator-=(S& i, const swap_struct_t<T, F> v) { |
| 468 | i -= v.swap(); | 520 | i -= v.swap(); |
| 469 | return i; | 521 | return i; |
| 470 | } | 522 | } |
| 471 | 523 | ||
| 472 | // Logical | 524 | // Logical |
| 473 | template <typename S, typename T, typename F> | 525 | template <typename S, typename T, typename F> |
| 474 | S operator&(const S &i, const swap_struct_t<T, F> v) { | 526 | S operator&(const S& i, const swap_struct_t<T, F> v) { |
| 475 | return i & v.swap(); | 527 | return i & v.swap(); |
| 476 | } | 528 | } |
| 477 | 529 | ||
| 478 | template <typename S, typename T, typename F> | 530 | template <typename S, typename T, typename F> |
| 479 | S operator&(const swap_struct_t<T, F> v, const S &i) { | 531 | S operator&(const swap_struct_t<T, F> v, const S& i) { |
| 480 | return (S)(v.swap() & i); | 532 | return (S)(v.swap() & i); |
| 481 | } | 533 | } |
| 482 | 534 | ||
| 483 | |||
| 484 | // Comparaison | 535 | // Comparaison |
| 485 | template <typename S, typename T, typename F> | 536 | template <typename S, typename T, typename F> |
| 486 | bool operator<(const S &p, const swap_struct_t<T, F> v) { | 537 | bool operator<(const S& p, const swap_struct_t<T, F> v) { |
| 487 | return p < v.swap(); | 538 | return p < v.swap(); |
| 488 | } | 539 | } |
| 489 | template <typename S, typename T, typename F> | 540 | template <typename S, typename T, typename F> |
| 490 | bool operator>(const S &p, const swap_struct_t<T, F> v) { | 541 | bool operator>(const S& p, const swap_struct_t<T, F> v) { |
| 491 | return p > v.swap(); | 542 | return p > v.swap(); |
| 492 | } | 543 | } |
| 493 | template <typename S, typename T, typename F> | 544 | template <typename S, typename T, typename F> |
| 494 | bool operator<=(const S &p, const swap_struct_t<T, F> v) { | 545 | bool operator<=(const S& p, const swap_struct_t<T, F> v) { |
| 495 | return p <= v.swap(); | 546 | return p <= v.swap(); |
| 496 | } | 547 | } |
| 497 | template <typename S, typename T, typename F> | 548 | template <typename S, typename T, typename F> |
| 498 | bool operator>=(const S &p, const swap_struct_t<T, F> v) { | 549 | bool operator>=(const S& p, const swap_struct_t<T, F> v) { |
| 499 | return p >= v.swap(); | 550 | return p >= v.swap(); |
| 500 | } | 551 | } |
| 501 | template <typename S, typename T, typename F> | 552 | template <typename S, typename T, typename F> |
| 502 | bool operator!=(const S &p, const swap_struct_t<T, F> v) { | 553 | bool operator!=(const S& p, const swap_struct_t<T, F> v) { |
| 503 | return p != v.swap(); | 554 | return p != v.swap(); |
| 504 | } | 555 | } |
| 505 | template <typename S, typename T, typename F> | 556 | template <typename S, typename T, typename F> |
| 506 | bool operator==(const S &p, const swap_struct_t<T, F> v) { | 557 | bool operator==(const S& p, const swap_struct_t<T, F> v) { |
| 507 | return p == v.swap(); | 558 | return p == v.swap(); |
| 508 | } | 559 | } |
| 509 | 560 | ||
| @@ -554,30 +605,30 @@ typedef s64 s64_le; | |||
| 554 | typedef float float_le; | 605 | typedef float float_le; |
| 555 | typedef double double_le; | 606 | typedef double double_le; |
| 556 | 607 | ||
| 557 | typedef swap_struct_t<u64, swap_64_t<u64> > u64_be; | 608 | typedef swap_struct_t<u64, swap_64_t<u64>> u64_be; |
| 558 | typedef swap_struct_t<s64, swap_64_t<s64> > s64_be; | 609 | typedef swap_struct_t<s64, swap_64_t<s64>> s64_be; |
| 559 | 610 | ||
| 560 | typedef swap_struct_t<u32, swap_32_t<u32> > u32_be; | 611 | typedef swap_struct_t<u32, swap_32_t<u32>> u32_be; |
| 561 | typedef swap_struct_t<s32, swap_32_t<s32> > s32_be; | 612 | typedef swap_struct_t<s32, swap_32_t<s32>> s32_be; |
| 562 | 613 | ||
| 563 | typedef swap_struct_t<u16, swap_16_t<u16> > u16_be; | 614 | typedef swap_struct_t<u16, swap_16_t<u16>> u16_be; |
| 564 | typedef swap_struct_t<s16, swap_16_t<s16> > s16_be; | 615 | typedef swap_struct_t<s16, swap_16_t<s16>> s16_be; |
| 565 | 616 | ||
| 566 | typedef swap_struct_t<float, swap_float_t<float> > float_be; | 617 | typedef swap_struct_t<float, swap_float_t<float>> float_be; |
| 567 | typedef swap_struct_t<double, swap_double_t<double> > double_be; | 618 | typedef swap_struct_t<double, swap_double_t<double>> double_be; |
| 568 | #else | 619 | #else |
| 569 | 620 | ||
| 570 | typedef swap_struct_t<u64, swap_64_t<u64> > u64_le; | 621 | typedef swap_struct_t<u64, swap_64_t<u64>> u64_le; |
| 571 | typedef swap_struct_t<s64, swap_64_t<s64> > s64_le; | 622 | typedef swap_struct_t<s64, swap_64_t<s64>> s64_le; |
| 572 | 623 | ||
| 573 | typedef swap_struct_t<u32, swap_32_t<u32> > u32_le; | 624 | typedef swap_struct_t<u32, swap_32_t<u32>> u32_le; |
| 574 | typedef swap_struct_t<s32, swap_32_t<s32> > s32_le; | 625 | typedef swap_struct_t<s32, swap_32_t<s32>> s32_le; |
| 575 | 626 | ||
| 576 | typedef swap_struct_t<u16, swap_16_t<u16> > u16_le; | 627 | typedef swap_struct_t<u16, swap_16_t<u16>> u16_le; |
| 577 | typedef swap_struct_t< s16, swap_16_t<s16> > s16_le; | 628 | typedef swap_struct_t<s16, swap_16_t<s16>> s16_le; |
| 578 | 629 | ||
| 579 | typedef swap_struct_t<float, swap_float_t<float> > float_le; | 630 | typedef swap_struct_t<float, swap_float_t<float>> float_le; |
| 580 | typedef swap_struct_t<double, swap_double_t<double> > double_le; | 631 | typedef swap_struct_t<double, swap_double_t<double>> double_le; |
| 581 | 632 | ||
| 582 | typedef u32 u32_be; | 633 | typedef u32 u32_be; |
| 583 | typedef u16 u16_be; | 634 | 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..6044c9db6 100644 --- a/src/common/symbols.h +++ b/src/common/symbols.h | |||
| @@ -10,25 +10,22 @@ | |||
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | 12 | ||
| 13 | struct TSymbol | 13 | struct TSymbol { |
| 14 | { | 14 | u32 address = 0; |
| 15 | u32 address = 0; | ||
| 16 | std::string name; | 15 | std::string name; |
| 17 | u32 size = 0; | 16 | u32 size = 0; |
| 18 | u32 type = 0; | 17 | u32 type = 0; |
| 19 | }; | 18 | }; |
| 20 | 19 | ||
| 21 | typedef std::map<u32, TSymbol> TSymbolsMap; | 20 | typedef std::map<u32, TSymbol> TSymbolsMap; |
| 22 | typedef std::pair<u32, TSymbol> TSymbolsPair; | 21 | typedef std::pair<u32, TSymbol> TSymbolsPair; |
| 23 | 22 | ||
| 24 | namespace Symbols | 23 | namespace Symbols { |
| 25 | { | 24 | bool HasSymbol(u32 address); |
| 26 | bool HasSymbol(u32 address); | ||
| 27 | 25 | ||
| 28 | void Add(u32 address, const std::string& name, u32 size, u32 type); | 26 | void Add(u32 address, const std::string& name, u32 size, u32 type); |
| 29 | TSymbol GetSymbol(u32 address); | 27 | TSymbol GetSymbol(u32 address); |
| 30 | const std::string GetName(u32 address); | 28 | const std::string GetName(u32 address); |
| 31 | void Remove(u32 address); | 29 | void Remove(u32 address); |
| 32 | void Clear(); | 30 | void Clear(); |
| 33 | } | 31 | } |
| 34 | |||
diff --git a/src/common/synchronized_wrapper.h b/src/common/synchronized_wrapper.h index 07105a198..8dc4ddeac 100644 --- a/src/common/synchronized_wrapper.h +++ b/src/common/synchronized_wrapper.h | |||
| @@ -12,14 +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 | } | 23 | } |
| 24 | 24 | ||
| 25 | private: | 25 | private: |
| @@ -58,11 +58,19 @@ public: | |||
| 58 | return *this; | 58 | return *this; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | T& operator*() { return wrapper->data; } | 61 | T& operator*() { |
| 62 | const T& operator*() const { return wrapper->data; } | 62 | return wrapper->data; |
| 63 | } | ||
| 64 | const T& operator*() const { | ||
| 65 | return wrapper->data; | ||
| 66 | } | ||
| 63 | 67 | ||
| 64 | T* operator->() { return &wrapper->data; } | 68 | T* operator->() { |
| 65 | const T* operator->() const { return &wrapper->data; } | 69 | return &wrapper->data; |
| 70 | } | ||
| 71 | const T* operator->() const { | ||
| 72 | return &wrapper->data; | ||
| 73 | } | ||
| 66 | 74 | ||
| 67 | private: | 75 | private: |
| 68 | SynchronizedWrapper<T>* wrapper; | 76 | SynchronizedWrapper<T>* wrapper; |
diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 7bbf080bc..bee607ce9 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp | |||
| @@ -5,27 +5,25 @@ | |||
| 5 | #include "common/thread.h" | 5 | #include "common/thread.h" |
| 6 | 6 | ||
| 7 | #ifdef __APPLE__ | 7 | #ifdef __APPLE__ |
| 8 | #include <mach/mach.h> | 8 | #include <mach/mach.h> |
| 9 | #elif defined(_WIN32) | 9 | #elif defined(_WIN32) |
| 10 | #include <Windows.h> | 10 | #include <Windows.h> |
| 11 | #else | 11 | #else |
| 12 | #if defined(BSD4_4) || defined(__OpenBSD__) | 12 | #if defined(BSD4_4) || defined(__OpenBSD__) |
| 13 | #include <pthread_np.h> | 13 | #include <pthread_np.h> |
| 14 | #else | 14 | #else |
| 15 | #include <pthread.h> | 15 | #include <pthread.h> |
| 16 | #endif | 16 | #endif |
| 17 | #include <sched.h> | 17 | #include <sched.h> |
| 18 | #endif | 18 | #endif |
| 19 | 19 | ||
| 20 | #ifndef _WIN32 | 20 | #ifndef _WIN32 |
| 21 | #include <unistd.h> | 21 | #include <unistd.h> |
| 22 | #endif | 22 | #endif |
| 23 | 23 | ||
| 24 | namespace Common | 24 | namespace Common { |
| 25 | { | ||
| 26 | 25 | ||
| 27 | int CurrentThreadId() | 26 | int CurrentThreadId() { |
| 28 | { | ||
| 29 | #ifdef _MSC_VER | 27 | #ifdef _MSC_VER |
| 30 | return GetCurrentThreadId(); | 28 | return GetCurrentThreadId(); |
| 31 | #elif defined __APPLE__ | 29 | #elif defined __APPLE__ |
| @@ -37,26 +35,22 @@ int CurrentThreadId() | |||
| 37 | 35 | ||
| 38 | #ifdef _WIN32 | 36 | #ifdef _WIN32 |
| 39 | // Supporting functions | 37 | // Supporting functions |
| 40 | void SleepCurrentThread(int ms) | 38 | void SleepCurrentThread(int ms) { |
| 41 | { | ||
| 42 | Sleep(ms); | 39 | Sleep(ms); |
| 43 | } | 40 | } |
| 44 | #endif | 41 | #endif |
| 45 | 42 | ||
| 46 | #ifdef _MSC_VER | 43 | #ifdef _MSC_VER |
| 47 | 44 | ||
| 48 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) | 45 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { |
| 49 | { | ||
| 50 | SetThreadAffinityMask(thread, mask); | 46 | SetThreadAffinityMask(thread, mask); |
| 51 | } | 47 | } |
| 52 | 48 | ||
| 53 | void SetCurrentThreadAffinity(u32 mask) | 49 | void SetCurrentThreadAffinity(u32 mask) { |
| 54 | { | ||
| 55 | SetThreadAffinityMask(GetCurrentThread(), mask); | 50 | SetThreadAffinityMask(GetCurrentThread(), mask); |
| 56 | } | 51 | } |
| 57 | 52 | ||
| 58 | void SwitchCurrentThread() | 53 | void SwitchCurrentThread() { |
| 59 | { | ||
| 60 | SwitchToThread(); | 54 | SwitchToThread(); |
| 61 | } | 55 | } |
| 62 | 56 | ||
| @@ -66,40 +60,34 @@ void SwitchCurrentThread() | |||
| 66 | 60 | ||
| 67 | // This is implemented much nicer in upcoming msvc++, see: | 61 | // This is implemented much nicer in upcoming msvc++, see: |
| 68 | // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx | 62 | // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx |
| 69 | void SetCurrentThreadName(const char* szThreadName) | 63 | void SetCurrentThreadName(const char* szThreadName) { |
| 70 | { | ||
| 71 | static const DWORD MS_VC_EXCEPTION = 0x406D1388; | 64 | static const DWORD MS_VC_EXCEPTION = 0x406D1388; |
| 72 | 65 | ||
| 73 | #pragma pack(push,8) | 66 | #pragma pack(push, 8) |
| 74 | struct THREADNAME_INFO | 67 | struct THREADNAME_INFO { |
| 75 | { | 68 | DWORD dwType; // must be 0x1000 |
| 76 | DWORD dwType; // must be 0x1000 | 69 | 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) | 70 | DWORD dwThreadID; // thread ID (-1=caller thread) |
| 79 | DWORD dwFlags; // reserved for future use, must be zero | 71 | DWORD dwFlags; // reserved for future use, must be zero |
| 80 | } info; | 72 | } info; |
| 81 | #pragma pack(pop) | 73 | #pragma pack(pop) |
| 82 | 74 | ||
| 83 | info.dwType = 0x1000; | 75 | info.dwType = 0x1000; |
| 84 | info.szName = szThreadName; | 76 | info.szName = szThreadName; |
| 85 | info.dwThreadID = -1; //dwThreadID; | 77 | info.dwThreadID = -1; // dwThreadID; |
| 86 | info.dwFlags = 0; | 78 | info.dwFlags = 0; |
| 87 | 79 | ||
| 88 | __try | 80 | __try { |
| 89 | { | 81 | 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); | 82 | } __except (EXCEPTION_CONTINUE_EXECUTION) { |
| 91 | } | 83 | } |
| 92 | __except(EXCEPTION_CONTINUE_EXECUTION) | ||
| 93 | {} | ||
| 94 | } | 84 | } |
| 95 | 85 | ||
| 96 | #else // !MSVC_VER, so must be POSIX threads | 86 | #else // !MSVC_VER, so must be POSIX threads |
| 97 | 87 | ||
| 98 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) | 88 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { |
| 99 | { | ||
| 100 | #ifdef __APPLE__ | 89 | #ifdef __APPLE__ |
| 101 | thread_policy_set(pthread_mach_thread_np(thread), | 90 | 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) | 91 | #elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID) |
| 104 | cpu_set_t cpu_set; | 92 | cpu_set_t cpu_set; |
| 105 | CPU_ZERO(&cpu_set); | 93 | CPU_ZERO(&cpu_set); |
| @@ -112,27 +100,23 @@ void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) | |||
| 112 | #endif | 100 | #endif |
| 113 | } | 101 | } |
| 114 | 102 | ||
| 115 | void SetCurrentThreadAffinity(u32 mask) | 103 | void SetCurrentThreadAffinity(u32 mask) { |
| 116 | { | ||
| 117 | SetThreadAffinity(pthread_self(), mask); | 104 | SetThreadAffinity(pthread_self(), mask); |
| 118 | } | 105 | } |
| 119 | 106 | ||
| 120 | #ifndef _WIN32 | 107 | #ifndef _WIN32 |
| 121 | void SleepCurrentThread(int ms) | 108 | void SleepCurrentThread(int ms) { |
| 122 | { | ||
| 123 | usleep(1000 * ms); | 109 | usleep(1000 * ms); |
| 124 | } | 110 | } |
| 125 | 111 | ||
| 126 | void SwitchCurrentThread() | 112 | void SwitchCurrentThread() { |
| 127 | { | ||
| 128 | usleep(1000 * 1); | 113 | usleep(1000 * 1); |
| 129 | } | 114 | } |
| 130 | #endif | 115 | #endif |
| 131 | 116 | ||
| 132 | // MinGW with the POSIX threading model does not support pthread_setname_np | 117 | // MinGW with the POSIX threading model does not support pthread_setname_np |
| 133 | #if !defined(_WIN32) || defined(_MSC_VER) | 118 | #if !defined(_WIN32) || defined(_MSC_VER) |
| 134 | void SetCurrentThreadName(const char* szThreadName) | 119 | void SetCurrentThreadName(const char* szThreadName) { |
| 135 | { | ||
| 136 | #ifdef __APPLE__ | 120 | #ifdef __APPLE__ |
| 137 | pthread_setname_np(szThreadName); | 121 | pthread_setname_np(szThreadName); |
| 138 | #elif defined(__OpenBSD__) | 122 | #elif defined(__OpenBSD__) |
diff --git a/src/common/thread.h b/src/common/thread.h index bbfa8befa..b189dc764 100644 --- a/src/common/thread.h +++ b/src/common/thread.h | |||
| @@ -4,10 +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> |
| 10 | #include <thread> | ||
| 11 | 11 | ||
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | 13 | ||
| @@ -17,17 +17,17 @@ | |||
| 17 | // backwards compat support. | 17 | // backwards compat support. |
| 18 | // WARNING: This only works correctly with POD types. | 18 | // WARNING: This only works correctly with POD types. |
| 19 | #if defined(__clang__) | 19 | #if defined(__clang__) |
| 20 | # if !__has_feature(cxx_thread_local) | 20 | #if !__has_feature(cxx_thread_local) |
| 21 | # define thread_local __thread | 21 | #define thread_local __thread |
| 22 | # endif | 22 | #endif |
| 23 | #elif defined(__GNUC__) | 23 | #elif defined(__GNUC__) |
| 24 | # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) | 24 | #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) |
| 25 | # define thread_local __thread | 25 | #define thread_local __thread |
| 26 | # endif | 26 | #endif |
| 27 | #elif defined(_MSC_VER) | 27 | #elif defined(_MSC_VER) |
| 28 | # if _MSC_VER < 1900 | 28 | #if _MSC_VER < 1900 |
| 29 | # define thread_local __declspec(thread) | 29 | #define thread_local __declspec(thread) |
| 30 | # endif | 30 | #endif |
| 31 | #endif | 31 | #endif |
| 32 | 32 | ||
| 33 | namespace Common { | 33 | namespace Common { |
| @@ -39,7 +39,8 @@ void SetCurrentThreadAffinity(u32 mask); | |||
| 39 | 39 | ||
| 40 | class Event { | 40 | class Event { |
| 41 | public: | 41 | public: |
| 42 | Event() : is_set(false) {} | 42 | Event() : is_set(false) { |
| 43 | } | ||
| 43 | 44 | ||
| 44 | void Set() { | 45 | void Set() { |
| 45 | std::lock_guard<std::mutex> lk(mutex); | 46 | std::lock_guard<std::mutex> lk(mutex); |
| @@ -51,13 +52,14 @@ public: | |||
| 51 | 52 | ||
| 52 | void Wait() { | 53 | void Wait() { |
| 53 | std::unique_lock<std::mutex> lk(mutex); | 54 | std::unique_lock<std::mutex> lk(mutex); |
| 54 | condvar.wait(lk, [&]{ return is_set; }); | 55 | condvar.wait(lk, [&] { return is_set; }); |
| 55 | is_set = false; | 56 | is_set = false; |
| 56 | } | 57 | } |
| 57 | 58 | ||
| 58 | void Reset() { | 59 | void Reset() { |
| 59 | std::unique_lock<std::mutex> lk(mutex); | 60 | 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 | 61 | // no other action required, since wait loops on the predicate and any lingering signal will |
| 62 | // get cleared on the first iteration | ||
| 61 | is_set = false; | 63 | is_set = false; |
| 62 | } | 64 | } |
| 63 | 65 | ||
| @@ -69,7 +71,8 @@ private: | |||
| 69 | 71 | ||
| 70 | class Barrier { | 72 | class Barrier { |
| 71 | public: | 73 | public: |
| 72 | explicit Barrier(size_t count_) : count(count_), waiting(0), generation(0) {} | 74 | explicit Barrier(size_t count_) : count(count_), waiting(0), generation(0) { |
| 75 | } | ||
| 73 | 76 | ||
| 74 | /// Blocks until all "count" threads have called Sync() | 77 | /// Blocks until all "count" threads have called Sync() |
| 75 | void Sync() { | 78 | void Sync() { |
| @@ -81,7 +84,8 @@ public: | |||
| 81 | waiting = 0; | 84 | waiting = 0; |
| 82 | condvar.notify_all(); | 85 | condvar.notify_all(); |
| 83 | } else { | 86 | } else { |
| 84 | condvar.wait(lk, [this, current_generation]{ return current_generation != generation; }); | 87 | condvar.wait(lk, |
| 88 | [this, current_generation] { return current_generation != generation; }); | ||
| 85 | } | 89 | } |
| 86 | } | 90 | } |
| 87 | 91 | ||
| @@ -94,7 +98,7 @@ private: | |||
| 94 | }; | 98 | }; |
| 95 | 99 | ||
| 96 | void SleepCurrentThread(int ms); | 100 | void SleepCurrentThread(int ms); |
| 97 | void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms | 101 | void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms |
| 98 | 102 | ||
| 99 | // Use this function during a spin-wait to make the current thread | 103 | // Use this function during a spin-wait to make the current thread |
| 100 | // relax while another thread is working. This may be more efficient | 104 | // relax while another thread is working. This may be more efficient |
| @@ -103,6 +107,6 @@ inline void YieldCPU() { | |||
| 103 | std::this_thread::yield(); | 107 | std::this_thread::yield(); |
| 104 | } | 108 | } |
| 105 | 109 | ||
| 106 | void SetCurrentThreadName(const char *name); | 110 | void SetCurrentThreadName(const char* name); |
| 107 | 111 | ||
| 108 | } // namespace Common | 112 | } // namespace Common |
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h index 12455d7c4..0dcf785b6 100644 --- a/src/common/thread_queue_list.h +++ b/src/common/thread_queue_list.h | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | namespace Common { | 12 | namespace Common { |
| 13 | 13 | ||
| 14 | template<class T, unsigned int N> | 14 | template <class T, unsigned int N> |
| 15 | struct ThreadQueueList { | 15 | struct ThreadQueueList { |
| 16 | // TODO(yuriks): If performance proves to be a problem, the std::deques can be replaced with | 16 | // 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 | 17 | // (dynamically resizable) circular buffers to remove their overhead when |
| @@ -39,7 +39,7 @@ struct ThreadQueueList { | |||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | T get_first() { | 41 | T get_first() { |
| 42 | Queue *cur = first; | 42 | Queue* cur = first; |
| 43 | while (cur != nullptr) { | 43 | while (cur != nullptr) { |
| 44 | if (!cur->data.empty()) { | 44 | if (!cur->data.empty()) { |
| 45 | return cur->data.front(); | 45 | return cur->data.front(); |
| @@ -51,7 +51,7 @@ struct ThreadQueueList { | |||
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | T pop_first() { | 53 | T pop_first() { |
| 54 | Queue *cur = first; | 54 | Queue* cur = first; |
| 55 | while (cur != nullptr) { | 55 | while (cur != nullptr) { |
| 56 | if (!cur->data.empty()) { | 56 | if (!cur->data.empty()) { |
| 57 | auto tmp = std::move(cur->data.front()); | 57 | auto tmp = std::move(cur->data.front()); |
| @@ -65,8 +65,8 @@ struct ThreadQueueList { | |||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | T pop_first_better(Priority priority) { | 67 | T pop_first_better(Priority priority) { |
| 68 | Queue *cur = first; | 68 | Queue* cur = first; |
| 69 | Queue *stop = &queues[priority]; | 69 | Queue* stop = &queues[priority]; |
| 70 | while (cur < stop) { | 70 | while (cur < stop) { |
| 71 | if (!cur->data.empty()) { | 71 | if (!cur->data.empty()) { |
| 72 | auto tmp = std::move(cur->data.front()); | 72 | auto tmp = std::move(cur->data.front()); |
| @@ -80,12 +80,12 @@ struct ThreadQueueList { | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | void push_front(Priority priority, const T& thread_id) { | 82 | void push_front(Priority priority, const T& thread_id) { |
| 83 | Queue *cur = &queues[priority]; | 83 | Queue* cur = &queues[priority]; |
| 84 | cur->data.push_front(thread_id); | 84 | cur->data.push_front(thread_id); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | void push_back(Priority priority, const T& thread_id) { | 87 | void push_back(Priority priority, const T& thread_id) { |
| 88 | Queue *cur = &queues[priority]; | 88 | Queue* cur = &queues[priority]; |
| 89 | cur->data.push_back(thread_id); | 89 | cur->data.push_back(thread_id); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| @@ -96,12 +96,12 @@ struct ThreadQueueList { | |||
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | void remove(Priority priority, const T& thread_id) { | 98 | void remove(Priority priority, const T& thread_id) { |
| 99 | Queue *cur = &queues[priority]; | 99 | Queue* cur = &queues[priority]; |
| 100 | boost::remove_erase(cur->data, thread_id); | 100 | boost::remove_erase(cur->data, thread_id); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | void rotate(Priority priority) { | 103 | void rotate(Priority priority) { |
| 104 | Queue *cur = &queues[priority]; | 104 | Queue* cur = &queues[priority]; |
| 105 | 105 | ||
| 106 | if (cur->data.size() > 1) { | 106 | if (cur->data.size() > 1) { |
| 107 | cur->data.push_back(std::move(cur->data.front())); | 107 | cur->data.push_back(std::move(cur->data.front())); |
| @@ -115,7 +115,7 @@ struct ThreadQueueList { | |||
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | bool empty(Priority priority) const { | 117 | bool empty(Priority priority) const { |
| 118 | const Queue *cur = &queues[priority]; | 118 | const Queue* cur = &queues[priority]; |
| 119 | return cur->data.empty(); | 119 | return cur->data.empty(); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| @@ -139,7 +139,7 @@ private: | |||
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | void link(Priority priority) { | 141 | void link(Priority priority) { |
| 142 | Queue *cur = &queues[priority]; | 142 | Queue* cur = &queues[priority]; |
| 143 | 143 | ||
| 144 | for (int i = priority - 1; i >= 0; --i) { | 144 | for (int i = priority - 1; i >= 0; --i) { |
| 145 | if (queues[i].next_nonempty != UnlinkedTag()) { | 145 | if (queues[i].next_nonempty != UnlinkedTag()) { |
diff --git a/src/common/timer.cpp b/src/common/timer.cpp index b99835ac7..27560eb0b 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp | |||
| @@ -16,11 +16,9 @@ | |||
| 16 | #include "common/string_util.h" | 16 | #include "common/string_util.h" |
| 17 | #include "common/timer.h" | 17 | #include "common/timer.h" |
| 18 | 18 | ||
| 19 | namespace Common | 19 | namespace Common { |
| 20 | { | ||
| 21 | 20 | ||
| 22 | u32 Timer::GetTimeMs() | 21 | u32 Timer::GetTimeMs() { |
| 23 | { | ||
| 24 | #ifdef _WIN32 | 22 | #ifdef _WIN32 |
| 25 | return timeGetTime(); | 23 | return timeGetTime(); |
| 26 | #else | 24 | #else |
| @@ -35,32 +33,27 @@ u32 Timer::GetTimeMs() | |||
| 35 | // -------------------------------------------- | 33 | // -------------------------------------------- |
| 36 | 34 | ||
| 37 | // Set initial values for the class | 35 | // Set initial values for the class |
| 38 | Timer::Timer() | 36 | Timer::Timer() : m_LastTime(0), m_StartTime(0), m_Running(false) { |
| 39 | : m_LastTime(0), m_StartTime(0), m_Running(false) | ||
| 40 | { | ||
| 41 | Update(); | 37 | Update(); |
| 42 | } | 38 | } |
| 43 | 39 | ||
| 44 | // Write the starting time | 40 | // Write the starting time |
| 45 | void Timer::Start() | 41 | void Timer::Start() { |
| 46 | { | ||
| 47 | m_StartTime = GetTimeMs(); | 42 | m_StartTime = GetTimeMs(); |
| 48 | m_Running = true; | 43 | m_Running = true; |
| 49 | } | 44 | } |
| 50 | 45 | ||
| 51 | // Stop the timer | 46 | // Stop the timer |
| 52 | void Timer::Stop() | 47 | void Timer::Stop() { |
| 53 | { | ||
| 54 | // Write the final time | 48 | // Write the final time |
| 55 | m_LastTime = GetTimeMs(); | 49 | m_LastTime = GetTimeMs(); |
| 56 | m_Running = false; | 50 | m_Running = false; |
| 57 | } | 51 | } |
| 58 | 52 | ||
| 59 | // Update the last time variable | 53 | // Update the last time variable |
| 60 | void Timer::Update() | 54 | void Timer::Update() { |
| 61 | { | ||
| 62 | m_LastTime = GetTimeMs(); | 55 | m_LastTime = GetTimeMs(); |
| 63 | //TODO(ector) - QPF | 56 | // TODO(ector) - QPF |
| 64 | } | 57 | } |
| 65 | 58 | ||
| 66 | // ------------------------------------- | 59 | // ------------------------------------- |
| @@ -68,34 +61,32 @@ void Timer::Update() | |||
| 68 | // ------------------------------------- | 61 | // ------------------------------------- |
| 69 | 62 | ||
| 70 | // Get the number of milliseconds since the last Update() | 63 | // Get the number of milliseconds since the last Update() |
| 71 | u64 Timer::GetTimeDifference() | 64 | u64 Timer::GetTimeDifference() { |
| 72 | { | ||
| 73 | return GetTimeMs() - m_LastTime; | 65 | return GetTimeMs() - m_LastTime; |
| 74 | } | 66 | } |
| 75 | 67 | ||
| 76 | // Add the time difference since the last Update() to the starting time. | 68 | // Add the time difference since the last Update() to the starting time. |
| 77 | // This is used to compensate for a paused game. | 69 | // This is used to compensate for a paused game. |
| 78 | void Timer::AddTimeDifference() | 70 | void Timer::AddTimeDifference() { |
| 79 | { | ||
| 80 | m_StartTime += GetTimeDifference(); | 71 | m_StartTime += GetTimeDifference(); |
| 81 | } | 72 | } |
| 82 | 73 | ||
| 83 | // Get the time elapsed since the Start() | 74 | // Get the time elapsed since the Start() |
| 84 | u64 Timer::GetTimeElapsed() | 75 | u64 Timer::GetTimeElapsed() { |
| 85 | { | ||
| 86 | // If we have not started yet, return 1 (because then I don't | 76 | // If we have not started yet, return 1 (because then I don't |
| 87 | // have to change the FPS calculation in CoreRerecording.cpp . | 77 | // have to change the FPS calculation in CoreRerecording.cpp . |
| 88 | if (m_StartTime == 0) return 1; | 78 | if (m_StartTime == 0) |
| 79 | return 1; | ||
| 89 | 80 | ||
| 90 | // Return the final timer time if the timer is stopped | 81 | // Return the final timer time if the timer is stopped |
| 91 | if (!m_Running) return (m_LastTime - m_StartTime); | 82 | if (!m_Running) |
| 83 | return (m_LastTime - m_StartTime); | ||
| 92 | 84 | ||
| 93 | return (GetTimeMs() - m_StartTime); | 85 | return (GetTimeMs() - m_StartTime); |
| 94 | } | 86 | } |
| 95 | 87 | ||
| 96 | // Get the formatted time elapsed since the Start() | 88 | // Get the formatted time elapsed since the Start() |
| 97 | std::string Timer::GetTimeElapsedFormatted() const | 89 | std::string Timer::GetTimeElapsedFormatted() const { |
| 98 | { | ||
| 99 | // If we have not started yet, return zero | 90 | // If we have not started yet, return zero |
| 100 | if (m_StartTime == 0) | 91 | if (m_StartTime == 0) |
| 101 | return "00:00:00:000"; | 92 | return "00:00:00:000"; |
| @@ -114,50 +105,46 @@ std::string Timer::GetTimeElapsedFormatted() const | |||
| 114 | // Hours | 105 | // Hours |
| 115 | u32 Hours = Minutes / 60; | 106 | u32 Hours = Minutes / 60; |
| 116 | 107 | ||
| 117 | std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", | 108 | std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", Hours, Minutes % 60, Seconds % 60, |
| 118 | Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000); | 109 | Milliseconds % 1000); |
| 119 | return TmpStr; | 110 | return TmpStr; |
| 120 | } | 111 | } |
| 121 | 112 | ||
| 122 | // Get current time | 113 | // Get current time |
| 123 | void Timer::IncreaseResolution() | 114 | void Timer::IncreaseResolution() { |
| 124 | { | ||
| 125 | #ifdef _WIN32 | 115 | #ifdef _WIN32 |
| 126 | timeBeginPeriod(1); | 116 | timeBeginPeriod(1); |
| 127 | #endif | 117 | #endif |
| 128 | } | 118 | } |
| 129 | 119 | ||
| 130 | void Timer::RestoreResolution() | 120 | void Timer::RestoreResolution() { |
| 131 | { | ||
| 132 | #ifdef _WIN32 | 121 | #ifdef _WIN32 |
| 133 | timeEndPeriod(1); | 122 | timeEndPeriod(1); |
| 134 | #endif | 123 | #endif |
| 135 | } | 124 | } |
| 136 | 125 | ||
| 137 | // Get the number of seconds since January 1 1970 | 126 | // Get the number of seconds since January 1 1970 |
| 138 | u64 Timer::GetTimeSinceJan1970() | 127 | u64 Timer::GetTimeSinceJan1970() { |
| 139 | { | ||
| 140 | time_t ltime; | 128 | time_t ltime; |
| 141 | time(<ime); | 129 | time(<ime); |
| 142 | return((u64)ltime); | 130 | return ((u64)ltime); |
| 143 | } | 131 | } |
| 144 | 132 | ||
| 145 | u64 Timer::GetLocalTimeSinceJan1970() | 133 | u64 Timer::GetLocalTimeSinceJan1970() { |
| 146 | { | ||
| 147 | time_t sysTime, tzDiff, tzDST; | 134 | time_t sysTime, tzDiff, tzDST; |
| 148 | struct tm * gmTime; | 135 | struct tm* gmTime; |
| 149 | 136 | ||
| 150 | time(&sysTime); | 137 | time(&sysTime); |
| 151 | 138 | ||
| 152 | // Account for DST where needed | 139 | // Account for DST where needed |
| 153 | gmTime = localtime(&sysTime); | 140 | gmTime = localtime(&sysTime); |
| 154 | if(gmTime->tm_isdst == 1) | 141 | if (gmTime->tm_isdst == 1) |
| 155 | tzDST = 3600; | 142 | tzDST = 3600; |
| 156 | else | 143 | else |
| 157 | tzDST = 0; | 144 | tzDST = 0; |
| 158 | 145 | ||
| 159 | // Lazy way to get local time in sec | 146 | // Lazy way to get local time in sec |
| 160 | gmTime = gmtime(&sysTime); | 147 | gmTime = gmtime(&sysTime); |
| 161 | tzDiff = sysTime - mktime(gmTime); | 148 | tzDiff = sysTime - mktime(gmTime); |
| 162 | 149 | ||
| 163 | return (u64)(sysTime + tzDiff + tzDST); | 150 | return (u64)(sysTime + tzDiff + tzDST); |
| @@ -165,10 +152,9 @@ u64 Timer::GetLocalTimeSinceJan1970() | |||
| 165 | 152 | ||
| 166 | // Return the current time formatted as Minutes:Seconds:Milliseconds | 153 | // Return the current time formatted as Minutes:Seconds:Milliseconds |
| 167 | // in the form 00:00:000. | 154 | // in the form 00:00:000. |
| 168 | std::string Timer::GetTimeFormatted() | 155 | std::string Timer::GetTimeFormatted() { |
| 169 | { | ||
| 170 | time_t sysTime; | 156 | time_t sysTime; |
| 171 | struct tm * gmTime; | 157 | struct tm* gmTime; |
| 172 | char tmp[13]; | 158 | char tmp[13]; |
| 173 | 159 | ||
| 174 | time(&sysTime); | 160 | time(&sysTime); |
| @@ -176,7 +162,7 @@ std::string Timer::GetTimeFormatted() | |||
| 176 | 162 | ||
| 177 | strftime(tmp, 6, "%M:%S", gmTime); | 163 | strftime(tmp, 6, "%M:%S", gmTime); |
| 178 | 164 | ||
| 179 | // Now tack on the milliseconds | 165 | // Now tack on the milliseconds |
| 180 | #ifdef _WIN32 | 166 | #ifdef _WIN32 |
| 181 | struct timeb tp; | 167 | struct timeb tp; |
| 182 | (void)::ftime(&tp); | 168 | (void)::ftime(&tp); |
| @@ -190,8 +176,7 @@ std::string Timer::GetTimeFormatted() | |||
| 190 | 176 | ||
| 191 | // Returns a timestamp with decimals for precise time comparisons | 177 | // Returns a timestamp with decimals for precise time comparisons |
| 192 | // ---------------- | 178 | // ---------------- |
| 193 | double Timer::GetDoubleTime() | 179 | double Timer::GetDoubleTime() { |
| 194 | { | ||
| 195 | #ifdef _WIN32 | 180 | #ifdef _WIN32 |
| 196 | struct timeb tp; | 181 | struct timeb tp; |
| 197 | (void)::ftime(&tp); | 182 | (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..b2d630829 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,178 @@ | |||
| 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 | } |
| 65 | Vec2(const T& _x, const T& _y) : x(_x), y(_y) { | ||
| 66 | } | ||
| 62 | 67 | ||
| 63 | template<typename T2> | 68 | template <typename T2> |
| 64 | Vec2<T2> Cast() const { | 69 | Vec2<T2> Cast() const { |
| 65 | return Vec2<T2>((T2)x, (T2)y); | 70 | return Vec2<T2>((T2)x, (T2)y); |
| 66 | } | 71 | } |
| 67 | 72 | ||
| 68 | static Vec2 AssignToAll(const T& f) | 73 | static Vec2 AssignToAll(const T& f) { |
| 69 | { | ||
| 70 | return Vec2<T>(f, f); | 74 | return Vec2<T>(f, f); |
| 71 | } | 75 | } |
| 72 | 76 | ||
| 73 | void Write(T a[2]) | 77 | void Write(T a[2]) { |
| 74 | { | 78 | a[0] = x; |
| 75 | a[0] = x; a[1] = y; | 79 | a[1] = y; |
| 76 | } | 80 | } |
| 77 | 81 | ||
| 78 | Vec2<decltype(T{}+T{})> operator +(const Vec2& other) const | 82 | Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const { |
| 79 | { | 83 | return MakeVec(x + other.x, y + other.y); |
| 80 | return MakeVec(x+other.x, y+other.y); | ||
| 81 | } | 84 | } |
| 82 | void operator += (const Vec2 &other) | 85 | void operator+=(const Vec2& other) { |
| 83 | { | 86 | x += other.x; |
| 84 | x+=other.x; y+=other.y; | 87 | y += other.y; |
| 85 | } | 88 | } |
| 86 | Vec2<decltype(T{}-T{})> operator -(const Vec2& other) const | 89 | Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const { |
| 87 | { | 90 | return MakeVec(x - other.x, y - other.y); |
| 88 | return MakeVec(x-other.x, y-other.y); | ||
| 89 | } | 91 | } |
| 90 | void operator -= (const Vec2& other) | 92 | void operator-=(const Vec2& other) { |
| 91 | { | 93 | x -= other.x; |
| 92 | x-=other.x; y-=other.y; | 94 | y -= other.y; |
| 93 | } | 95 | } |
| 94 | template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> | 96 | template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type> |
| 95 | Vec2<decltype(-T{})> operator -() const | 97 | Vec2<decltype(-T{})> operator-() const { |
| 96 | { | 98 | return MakeVec(-x, -y); |
| 97 | return MakeVec(-x,-y); | ||
| 98 | } | 99 | } |
| 99 | Vec2<decltype(T{}*T{})> operator * (const Vec2& other) const | 100 | Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const { |
| 100 | { | 101 | return MakeVec(x * other.x, y * other.y); |
| 101 | return MakeVec(x*other.x, y*other.y); | ||
| 102 | } | 102 | } |
| 103 | template<typename V> | 103 | template <typename V> |
| 104 | Vec2<decltype(T{}*V{})> operator * (const V& f) const | 104 | Vec2<decltype(T{} * V{})> operator*(const V& f) const { |
| 105 | { | 105 | return MakeVec(x * f, y * f); |
| 106 | return MakeVec(x*f,y*f); | ||
| 107 | } | 106 | } |
| 108 | template<typename V> | 107 | template <typename V> |
| 109 | void operator *= (const V& f) | 108 | void operator*=(const V& f) { |
| 110 | { | 109 | x *= f; |
| 111 | x*=f; y*=f; | 110 | y *= f; |
| 112 | } | 111 | } |
| 113 | template<typename V> | 112 | template <typename V> |
| 114 | Vec2<decltype(T{}/V{})> operator / (const V& f) const | 113 | Vec2<decltype(T{} / V{})> operator/(const V& f) const { |
| 115 | { | 114 | return MakeVec(x / f, y / f); |
| 116 | return MakeVec(x/f,y/f); | ||
| 117 | } | 115 | } |
| 118 | template<typename V> | 116 | template <typename V> |
| 119 | void operator /= (const V& f) | 117 | void operator/=(const V& f) { |
| 120 | { | ||
| 121 | *this = *this / f; | 118 | *this = *this / f; |
| 122 | } | 119 | } |
| 123 | 120 | ||
| 124 | T Length2() const | 121 | T Length2() const { |
| 125 | { | 122 | return x * x + y * y; |
| 126 | return x*x + y*y; | ||
| 127 | } | 123 | } |
| 128 | 124 | ||
| 129 | // Only implemented for T=float | 125 | // Only implemented for T=float |
| 130 | float Length() const; | 126 | float Length() const; |
| 131 | void SetLength(const float l); | 127 | void SetLength(const float l); |
| 132 | Vec2 WithLength(const float l) const; | 128 | Vec2 WithLength(const float l) const; |
| 133 | float Distance2To(Vec2 &other); | 129 | float Distance2To(Vec2& other); |
| 134 | Vec2 Normalized() const; | 130 | Vec2 Normalized() const; |
| 135 | float Normalize(); // returns the previous length, which is often useful | 131 | float Normalize(); // returns the previous length, which is often useful |
| 136 | 132 | ||
| 137 | T& operator [] (int i) //allow vector[1] = 3 (vector.y=3) | 133 | T& operator[](int i) // allow vector[1] = 3 (vector.y=3) |
| 138 | { | 134 | { |
| 139 | return *((&x) + i); | 135 | return *((&x) + i); |
| 140 | } | 136 | } |
| 141 | T operator [] (const int i) const | 137 | T operator[](const int i) const { |
| 142 | { | ||
| 143 | return *((&x) + i); | 138 | return *((&x) + i); |
| 144 | } | 139 | } |
| 145 | 140 | ||
| 146 | void SetZero() | 141 | void SetZero() { |
| 147 | { | 142 | x = 0; |
| 148 | x=0; y=0; | 143 | y = 0; |
| 149 | } | 144 | } |
| 150 | 145 | ||
| 151 | // Common aliases: UV (texel coordinates), ST (texture coordinates) | 146 | // Common aliases: UV (texel coordinates), ST (texture coordinates) |
| 152 | T& u() { return x; } | 147 | T& u() { |
| 153 | T& v() { return y; } | 148 | return x; |
| 154 | T& s() { return x; } | 149 | } |
| 155 | T& t() { return y; } | 150 | T& v() { |
| 151 | return y; | ||
| 152 | } | ||
| 153 | T& s() { | ||
| 154 | return x; | ||
| 155 | } | ||
| 156 | T& t() { | ||
| 157 | return y; | ||
| 158 | } | ||
| 156 | 159 | ||
| 157 | const T& u() const { return x; } | 160 | const T& u() const { |
| 158 | const T& v() const { return y; } | 161 | return x; |
| 159 | const T& s() const { return x; } | 162 | } |
| 160 | const T& t() const { return y; } | 163 | const T& v() const { |
| 164 | return y; | ||
| 165 | } | ||
| 166 | const T& s() const { | ||
| 167 | return x; | ||
| 168 | } | ||
| 169 | const T& t() const { | ||
| 170 | return y; | ||
| 171 | } | ||
| 161 | 172 | ||
| 162 | // swizzlers - create a subvector of specific components | 173 | // swizzlers - create a subvector of specific components |
| 163 | const Vec2 yx() const { return Vec2(y, x); } | 174 | const Vec2 yx() const { |
| 164 | const Vec2 vu() const { return Vec2(y, x); } | 175 | return Vec2(y, x); |
| 165 | const Vec2 ts() const { return Vec2(y, x); } | 176 | } |
| 177 | const Vec2 vu() const { | ||
| 178 | return Vec2(y, x); | ||
| 179 | } | ||
| 180 | const Vec2 ts() const { | ||
| 181 | return Vec2(y, x); | ||
| 182 | } | ||
| 166 | }; | 183 | }; |
| 167 | 184 | ||
| 168 | template<typename T, typename V> | 185 | template <typename T, typename V> |
| 169 | Vec2<T> operator * (const V& f, const Vec2<T>& vec) | 186 | Vec2<T> operator*(const V& f, const Vec2<T>& vec) { |
| 170 | { | 187 | return Vec2<T>(f * vec.x, f * vec.y); |
| 171 | return Vec2<T>(f*vec.x,f*vec.y); | ||
| 172 | } | 188 | } |
| 173 | 189 | ||
| 174 | typedef Vec2<float> Vec2f; | 190 | typedef Vec2<float> Vec2f; |
| 175 | 191 | ||
| 176 | template<typename T> | 192 | template <typename T> |
| 177 | class Vec3 | 193 | class Vec3 { |
| 178 | { | ||
| 179 | public: | 194 | public: |
| 180 | T x; | 195 | T x; |
| 181 | T y; | 196 | T y; |
| 182 | T z; | 197 | T z; |
| 183 | 198 | ||
| 184 | T* AsArray() { return &x; } | 199 | T* AsArray() { |
| 200 | return &x; | ||
| 201 | } | ||
| 185 | 202 | ||
| 186 | Vec3() = default; | 203 | Vec3() = default; |
| 187 | Vec3(const T a[3]) : x(a[0]), y(a[1]), z(a[2]) {} | 204 | 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) {} | 205 | } |
| 206 | Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) { | ||
| 207 | } | ||
| 189 | 208 | ||
| 190 | template<typename T2> | 209 | template <typename T2> |
| 191 | Vec3<T2> Cast() const { | 210 | Vec3<T2> Cast() const { |
| 192 | return MakeVec<T2>((T2)x, (T2)y, (T2)z); | 211 | return MakeVec<T2>((T2)x, (T2)y, (T2)z); |
| 193 | } | 212 | } |
| @@ -196,126 +215,161 @@ public: | |||
| 196 | static Vec3 FromRGB(unsigned int rgb); | 215 | static Vec3 FromRGB(unsigned int rgb); |
| 197 | unsigned int ToRGB() const; // alpha bits set to zero | 216 | unsigned int ToRGB() const; // alpha bits set to zero |
| 198 | 217 | ||
| 199 | static Vec3 AssignToAll(const T& f) | 218 | static Vec3 AssignToAll(const T& f) { |
| 200 | { | ||
| 201 | return MakeVec(f, f, f); | 219 | return MakeVec(f, f, f); |
| 202 | } | 220 | } |
| 203 | 221 | ||
| 204 | void Write(T a[3]) | 222 | void Write(T a[3]) { |
| 205 | { | 223 | a[0] = x; |
| 206 | a[0] = x; a[1] = y; a[2] = z; | 224 | a[1] = y; |
| 225 | a[2] = z; | ||
| 207 | } | 226 | } |
| 208 | 227 | ||
| 209 | Vec3<decltype(T{}+T{})> operator +(const Vec3 &other) const | 228 | Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const { |
| 210 | { | 229 | return MakeVec(x + other.x, y + other.y, z + other.z); |
| 211 | return MakeVec(x+other.x, y+other.y, z+other.z); | ||
| 212 | } | 230 | } |
| 213 | void operator += (const Vec3 &other) | 231 | void operator+=(const Vec3& other) { |
| 214 | { | 232 | x += other.x; |
| 215 | x+=other.x; y+=other.y; z+=other.z; | 233 | y += other.y; |
| 234 | z += other.z; | ||
| 216 | } | 235 | } |
| 217 | Vec3<decltype(T{}-T{})> operator -(const Vec3 &other) const | 236 | Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const { |
| 218 | { | 237 | return MakeVec(x - other.x, y - other.y, z - other.z); |
| 219 | return MakeVec(x-other.x, y-other.y, z-other.z); | ||
| 220 | } | 238 | } |
| 221 | void operator -= (const Vec3 &other) | 239 | void operator-=(const Vec3& other) { |
| 222 | { | 240 | x -= other.x; |
| 223 | x-=other.x; y-=other.y; z-=other.z; | 241 | y -= other.y; |
| 242 | z -= other.z; | ||
| 224 | } | 243 | } |
| 225 | template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> | 244 | template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type> |
| 226 | Vec3<decltype(-T{})> operator -() const | 245 | Vec3<decltype(-T{})> operator-() const { |
| 227 | { | 246 | return MakeVec(-x, -y, -z); |
| 228 | return MakeVec(-x,-y,-z); | ||
| 229 | } | 247 | } |
| 230 | Vec3<decltype(T{}*T{})> operator * (const Vec3 &other) const | 248 | Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const { |
| 231 | { | 249 | return MakeVec(x * other.x, y * other.y, z * other.z); |
| 232 | return MakeVec(x*other.x, y*other.y, z*other.z); | ||
| 233 | } | 250 | } |
| 234 | template<typename V> | 251 | template <typename V> |
| 235 | Vec3<decltype(T{}*V{})> operator * (const V& f) const | 252 | Vec3<decltype(T{} * V{})> operator*(const V& f) const { |
| 236 | { | 253 | return MakeVec(x * f, y * f, z * f); |
| 237 | return MakeVec(x*f,y*f,z*f); | ||
| 238 | } | 254 | } |
| 239 | template<typename V> | 255 | template <typename V> |
| 240 | void operator *= (const V& f) | 256 | void operator*=(const V& f) { |
| 241 | { | 257 | x *= f; |
| 242 | x*=f; y*=f; z*=f; | 258 | y *= f; |
| 259 | z *= f; | ||
| 243 | } | 260 | } |
| 244 | template<typename V> | 261 | template <typename V> |
| 245 | Vec3<decltype(T{}/V{})> operator / (const V& f) const | 262 | Vec3<decltype(T{} / V{})> operator/(const V& f) const { |
| 246 | { | 263 | return MakeVec(x / f, y / f, z / f); |
| 247 | return MakeVec(x/f,y/f,z/f); | ||
| 248 | } | 264 | } |
| 249 | template<typename V> | 265 | template <typename V> |
| 250 | void operator /= (const V& f) | 266 | void operator/=(const V& f) { |
| 251 | { | ||
| 252 | *this = *this / f; | 267 | *this = *this / f; |
| 253 | } | 268 | } |
| 254 | 269 | ||
| 255 | T Length2() const | 270 | T Length2() const { |
| 256 | { | 271 | return x * x + y * y + z * z; |
| 257 | return x*x + y*y + z*z; | ||
| 258 | } | 272 | } |
| 259 | 273 | ||
| 260 | // Only implemented for T=float | 274 | // Only implemented for T=float |
| 261 | float Length() const; | 275 | float Length() const; |
| 262 | void SetLength(const float l); | 276 | void SetLength(const float l); |
| 263 | Vec3 WithLength(const float l) const; | 277 | Vec3 WithLength(const float l) const; |
| 264 | float Distance2To(Vec3 &other); | 278 | float Distance2To(Vec3& other); |
| 265 | Vec3 Normalized() const; | 279 | Vec3 Normalized() const; |
| 266 | float Normalize(); // returns the previous length, which is often useful | 280 | float Normalize(); // returns the previous length, which is often useful |
| 267 | 281 | ||
| 268 | T& operator [] (int i) //allow vector[2] = 3 (vector.z=3) | 282 | T& operator[](int i) // allow vector[2] = 3 (vector.z=3) |
| 269 | { | 283 | { |
| 270 | return *((&x) + i); | 284 | return *((&x) + i); |
| 271 | } | 285 | } |
| 272 | T operator [] (const int i) const | 286 | T operator[](const int i) const { |
| 273 | { | ||
| 274 | return *((&x) + i); | 287 | return *((&x) + i); |
| 275 | } | 288 | } |
| 276 | 289 | ||
| 277 | void SetZero() | 290 | void SetZero() { |
| 278 | { | 291 | x = 0; |
| 279 | x=0; y=0; z=0; | 292 | y = 0; |
| 293 | z = 0; | ||
| 280 | } | 294 | } |
| 281 | 295 | ||
| 282 | // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates) | 296 | // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates) |
| 283 | T& u() { return x; } | 297 | T& u() { |
| 284 | T& v() { return y; } | 298 | return x; |
| 285 | T& w() { return z; } | 299 | } |
| 300 | T& v() { | ||
| 301 | return y; | ||
| 302 | } | ||
| 303 | T& w() { | ||
| 304 | return z; | ||
| 305 | } | ||
| 286 | 306 | ||
| 287 | T& r() { return x; } | 307 | T& r() { |
| 288 | T& g() { return y; } | 308 | return x; |
| 289 | T& b() { return z; } | 309 | } |
| 310 | T& g() { | ||
| 311 | return y; | ||
| 312 | } | ||
| 313 | T& b() { | ||
| 314 | return z; | ||
| 315 | } | ||
| 290 | 316 | ||
| 291 | T& s() { return x; } | 317 | T& s() { |
| 292 | T& t() { return y; } | 318 | return x; |
| 293 | T& q() { return z; } | 319 | } |
| 320 | T& t() { | ||
| 321 | return y; | ||
| 322 | } | ||
| 323 | T& q() { | ||
| 324 | return z; | ||
| 325 | } | ||
| 294 | 326 | ||
| 295 | const T& u() const { return x; } | 327 | const T& u() const { |
| 296 | const T& v() const { return y; } | 328 | return x; |
| 297 | const T& w() const { return z; } | 329 | } |
| 330 | const T& v() const { | ||
| 331 | return y; | ||
| 332 | } | ||
| 333 | const T& w() const { | ||
| 334 | return z; | ||
| 335 | } | ||
| 298 | 336 | ||
| 299 | const T& r() const { return x; } | 337 | const T& r() const { |
| 300 | const T& g() const { return y; } | 338 | return x; |
| 301 | const T& b() const { return z; } | 339 | } |
| 340 | const T& g() const { | ||
| 341 | return y; | ||
| 342 | } | ||
| 343 | const T& b() const { | ||
| 344 | return z; | ||
| 345 | } | ||
| 302 | 346 | ||
| 303 | const T& s() const { return x; } | 347 | const T& s() const { |
| 304 | const T& t() const { return y; } | 348 | return x; |
| 305 | const T& q() const { return z; } | 349 | } |
| 350 | const T& t() const { | ||
| 351 | return y; | ||
| 352 | } | ||
| 353 | const T& q() const { | ||
| 354 | return z; | ||
| 355 | } | ||
| 306 | 356 | ||
| 307 | // swizzlers - create a subvector of specific components | 357 | // swizzlers - create a subvector of specific components |
| 308 | // e.g. Vec2 uv() { return Vec2(x,y); } | 358 | // 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) | 359 | // _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); } | 360 | // component names (x<->r) and permutations (xy<->yx) |
| 311 | #define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ | 361 | #define _DEFINE_SWIZZLER2(a, b, name) \ |
| 312 | _DEFINE_SWIZZLER2(a, b, a##b); \ | 362 | const Vec2<T> name() const { \ |
| 313 | _DEFINE_SWIZZLER2(a, b, a2##b2); \ | 363 | return Vec2<T>(a, b); \ |
| 314 | _DEFINE_SWIZZLER2(a, b, a3##b3); \ | 364 | } |
| 315 | _DEFINE_SWIZZLER2(a, b, a4##b4); \ | 365 | #define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ |
| 316 | _DEFINE_SWIZZLER2(b, a, b##a); \ | 366 | _DEFINE_SWIZZLER2(a, b, a##b); \ |
| 317 | _DEFINE_SWIZZLER2(b, a, b2##a2); \ | 367 | _DEFINE_SWIZZLER2(a, b, a2##b2); \ |
| 318 | _DEFINE_SWIZZLER2(b, a, b3##a3); \ | 368 | _DEFINE_SWIZZLER2(a, b, a3##b3); \ |
| 369 | _DEFINE_SWIZZLER2(a, b, a4##b4); \ | ||
| 370 | _DEFINE_SWIZZLER2(b, a, b##a); \ | ||
| 371 | _DEFINE_SWIZZLER2(b, a, b2##a2); \ | ||
| 372 | _DEFINE_SWIZZLER2(b, a, b3##a3); \ | ||
| 319 | _DEFINE_SWIZZLER2(b, a, b4##a4) | 373 | _DEFINE_SWIZZLER2(b, a, b4##a4) |
| 320 | 374 | ||
| 321 | DEFINE_SWIZZLER2(x, y, r, g, u, v, s, t); | 375 | DEFINE_SWIZZLER2(x, y, r, g, u, v, s, t); |
| @@ -325,41 +379,42 @@ public: | |||
| 325 | #undef _DEFINE_SWIZZLER2 | 379 | #undef _DEFINE_SWIZZLER2 |
| 326 | }; | 380 | }; |
| 327 | 381 | ||
| 328 | template<typename T, typename V> | 382 | template <typename T, typename V> |
| 329 | Vec3<T> operator * (const V& f, const Vec3<T>& vec) | 383 | Vec3<T> operator*(const V& f, const Vec3<T>& vec) { |
| 330 | { | 384 | 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 | } | 385 | } |
| 333 | 386 | ||
| 334 | template<> | 387 | template <> |
| 335 | inline float Vec3<float>::Length() const { | 388 | inline float Vec3<float>::Length() const { |
| 336 | return std::sqrt(x * x + y * y + z * z); | 389 | return std::sqrt(x * x + y * y + z * z); |
| 337 | } | 390 | } |
| 338 | 391 | ||
| 339 | template<> | 392 | template <> |
| 340 | inline Vec3<float> Vec3<float>::Normalized() const { | 393 | inline Vec3<float> Vec3<float>::Normalized() const { |
| 341 | return *this / Length(); | 394 | return *this / Length(); |
| 342 | } | 395 | } |
| 343 | 396 | ||
| 344 | |||
| 345 | typedef Vec3<float> Vec3f; | 397 | typedef Vec3<float> Vec3f; |
| 346 | 398 | ||
| 347 | template<typename T> | 399 | template <typename T> |
| 348 | class Vec4 | 400 | class Vec4 { |
| 349 | { | ||
| 350 | public: | 401 | public: |
| 351 | T x; | 402 | T x; |
| 352 | T y; | 403 | T y; |
| 353 | T z; | 404 | T z; |
| 354 | T w; | 405 | T w; |
| 355 | 406 | ||
| 356 | T* AsArray() { return &x; } | 407 | T* AsArray() { |
| 408 | return &x; | ||
| 409 | } | ||
| 357 | 410 | ||
| 358 | Vec4() = default; | 411 | Vec4() = default; |
| 359 | Vec4(const T a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {} | 412 | 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) {} | 413 | } |
| 414 | Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) { | ||
| 415 | } | ||
| 361 | 416 | ||
| 362 | template<typename T2> | 417 | template <typename T2> |
| 363 | Vec4<T2> Cast() const { | 418 | Vec4<T2> Cast() const { |
| 364 | return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w); | 419 | return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w); |
| 365 | } | 420 | } |
| @@ -372,81 +427,79 @@ public: | |||
| 372 | return Vec4<T>(f, f, f, f); | 427 | return Vec4<T>(f, f, f, f); |
| 373 | } | 428 | } |
| 374 | 429 | ||
| 375 | void Write(T a[4]) | 430 | void Write(T a[4]) { |
| 376 | { | 431 | a[0] = x; |
| 377 | a[0] = x; a[1] = y; a[2] = z; a[3] = w; | 432 | a[1] = y; |
| 433 | a[2] = z; | ||
| 434 | a[3] = w; | ||
| 378 | } | 435 | } |
| 379 | 436 | ||
| 380 | Vec4<decltype(T{}+T{})> operator +(const Vec4& other) const | 437 | Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const { |
| 381 | { | 438 | 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 | } | 439 | } |
| 384 | void operator += (const Vec4& other) | 440 | void operator+=(const Vec4& other) { |
| 385 | { | 441 | x += other.x; |
| 386 | x+=other.x; y+=other.y; z+=other.z; w+=other.w; | 442 | y += other.y; |
| 443 | z += other.z; | ||
| 444 | w += other.w; | ||
| 387 | } | 445 | } |
| 388 | Vec4<decltype(T{}-T{})> operator -(const Vec4 &other) const | 446 | Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const { |
| 389 | { | 447 | 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 | } | 448 | } |
| 392 | void operator -= (const Vec4 &other) | 449 | void operator-=(const Vec4& other) { |
| 393 | { | 450 | x -= other.x; |
| 394 | x-=other.x; y-=other.y; z-=other.z; w-=other.w; | 451 | y -= other.y; |
| 452 | z -= other.z; | ||
| 453 | w -= other.w; | ||
| 395 | } | 454 | } |
| 396 | template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> | 455 | template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type> |
| 397 | Vec4<decltype(-T{})> operator -() const | 456 | Vec4<decltype(-T{})> operator-() const { |
| 398 | { | 457 | return MakeVec(-x, -y, -z, -w); |
| 399 | return MakeVec(-x,-y,-z,-w); | ||
| 400 | } | 458 | } |
| 401 | Vec4<decltype(T{}*T{})> operator * (const Vec4 &other) const | 459 | Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const { |
| 402 | { | 460 | 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 | } | 461 | } |
| 405 | template<typename V> | 462 | template <typename V> |
| 406 | Vec4<decltype(T{}*V{})> operator * (const V& f) const | 463 | Vec4<decltype(T{} * V{})> operator*(const V& f) const { |
| 407 | { | 464 | return MakeVec(x * f, y * f, z * f, w * f); |
| 408 | return MakeVec(x*f,y*f,z*f,w*f); | ||
| 409 | } | 465 | } |
| 410 | template<typename V> | 466 | template <typename V> |
| 411 | void operator *= (const V& f) | 467 | void operator*=(const V& f) { |
| 412 | { | 468 | x *= f; |
| 413 | x*=f; y*=f; z*=f; w*=f; | 469 | y *= f; |
| 470 | z *= f; | ||
| 471 | w *= f; | ||
| 414 | } | 472 | } |
| 415 | template<typename V> | 473 | template <typename V> |
| 416 | Vec4<decltype(T{}/V{})> operator / (const V& f) const | 474 | Vec4<decltype(T{} / V{})> operator/(const V& f) const { |
| 417 | { | 475 | return MakeVec(x / f, y / f, z / f, w / f); |
| 418 | return MakeVec(x/f,y/f,z/f,w/f); | ||
| 419 | } | 476 | } |
| 420 | template<typename V> | 477 | template <typename V> |
| 421 | void operator /= (const V& f) | 478 | void operator/=(const V& f) { |
| 422 | { | ||
| 423 | *this = *this / f; | 479 | *this = *this / f; |
| 424 | } | 480 | } |
| 425 | 481 | ||
| 426 | T Length2() const | 482 | T Length2() const { |
| 427 | { | 483 | return x * x + y * y + z * z + w * w; |
| 428 | return x*x + y*y + z*z + w*w; | ||
| 429 | } | 484 | } |
| 430 | 485 | ||
| 431 | // Only implemented for T=float | 486 | // Only implemented for T=float |
| 432 | float Length() const; | 487 | float Length() const; |
| 433 | void SetLength(const float l); | 488 | void SetLength(const float l); |
| 434 | Vec4 WithLength(const float l) const; | 489 | Vec4 WithLength(const float l) const; |
| 435 | float Distance2To(Vec4 &other); | 490 | float Distance2To(Vec4& other); |
| 436 | Vec4 Normalized() const; | 491 | Vec4 Normalized() const; |
| 437 | float Normalize(); // returns the previous length, which is often useful | 492 | float Normalize(); // returns the previous length, which is often useful |
| 438 | 493 | ||
| 439 | T& operator [] (int i) //allow vector[2] = 3 (vector.z=3) | 494 | T& operator[](int i) // allow vector[2] = 3 (vector.z=3) |
| 440 | { | 495 | { |
| 441 | return *((&x) + i); | 496 | return *((&x) + i); |
| 442 | } | 497 | } |
| 443 | T operator [] (const int i) const | 498 | T operator[](const int i) const { |
| 444 | { | ||
| 445 | return *((&x) + i); | 499 | return *((&x) + i); |
| 446 | } | 500 | } |
| 447 | 501 | ||
| 448 | void SetZero() | 502 | void SetZero() { |
| 449 | { | ||
| 450 | x = 0; | 503 | x = 0; |
| 451 | y = 0; | 504 | y = 0; |
| 452 | z = 0; | 505 | z = 0; |
| @@ -454,30 +507,50 @@ public: | |||
| 454 | } | 507 | } |
| 455 | 508 | ||
| 456 | // Common alias: RGBA (colors) | 509 | // Common alias: RGBA (colors) |
| 457 | T& r() { return x; } | 510 | T& r() { |
| 458 | T& g() { return y; } | 511 | return x; |
| 459 | T& b() { return z; } | 512 | } |
| 460 | T& a() { return w; } | 513 | T& g() { |
| 461 | 514 | return y; | |
| 462 | const T& r() const { return x; } | 515 | } |
| 463 | const T& g() const { return y; } | 516 | T& b() { |
| 464 | const T& b() const { return z; } | 517 | return z; |
| 465 | const T& a() const { return w; } | 518 | } |
| 466 | 519 | T& a() { | |
| 467 | // Swizzlers - Create a subvector of specific components | 520 | return w; |
| 468 | // e.g. Vec2 uv() { return Vec2(x,y); } | 521 | } |
| 469 | 522 | ||
| 470 | // _DEFINE_SWIZZLER2 defines a single such function | 523 | const T& r() const { |
| 471 | // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) | 524 | return x; |
| 472 | // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx) | 525 | } |
| 473 | #define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); } | 526 | const T& g() const { |
| 474 | #define DEFINE_SWIZZLER2_COMP1(a, a2) \ | 527 | return y; |
| 475 | _DEFINE_SWIZZLER2(a, a, a##a); \ | 528 | } |
| 529 | const T& b() const { | ||
| 530 | return z; | ||
| 531 | } | ||
| 532 | const T& a() const { | ||
| 533 | return w; | ||
| 534 | } | ||
| 535 | |||
| 536 | // Swizzlers - Create a subvector of specific components | ||
| 537 | // e.g. Vec2 uv() { return Vec2(x,y); } | ||
| 538 | |||
| 539 | // _DEFINE_SWIZZLER2 defines a single such function | ||
| 540 | // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) | ||
| 541 | // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and | ||
| 542 | // permutations (xy<->yx) | ||
| 543 | #define _DEFINE_SWIZZLER2(a, b, name) \ | ||
| 544 | const Vec2<T> name() const { \ | ||
| 545 | return Vec2<T>(a, b); \ | ||
| 546 | } | ||
| 547 | #define DEFINE_SWIZZLER2_COMP1(a, a2) \ | ||
| 548 | _DEFINE_SWIZZLER2(a, a, a##a); \ | ||
| 476 | _DEFINE_SWIZZLER2(a, a, a2##a2) | 549 | _DEFINE_SWIZZLER2(a, a, a2##a2) |
| 477 | #define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \ | 550 | #define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \ |
| 478 | _DEFINE_SWIZZLER2(a, b, a##b); \ | 551 | _DEFINE_SWIZZLER2(a, b, a##b); \ |
| 479 | _DEFINE_SWIZZLER2(a, b, a2##b2); \ | 552 | _DEFINE_SWIZZLER2(a, b, a2##b2); \ |
| 480 | _DEFINE_SWIZZLER2(b, a, b##a); \ | 553 | _DEFINE_SWIZZLER2(b, a, b##a); \ |
| 481 | _DEFINE_SWIZZLER2(b, a, b2##a2) | 554 | _DEFINE_SWIZZLER2(b, a, b2##a2) |
| 482 | 555 | ||
| 483 | DEFINE_SWIZZLER2_COMP2(x, y, r, g); | 556 | DEFINE_SWIZZLER2_COMP2(x, y, r, g); |
| @@ -494,22 +567,25 @@ public: | |||
| 494 | #undef DEFINE_SWIZZLER2_COMP2 | 567 | #undef DEFINE_SWIZZLER2_COMP2 |
| 495 | #undef _DEFINE_SWIZZLER2 | 568 | #undef _DEFINE_SWIZZLER2 |
| 496 | 569 | ||
| 497 | #define _DEFINE_SWIZZLER3(a, b, c, name) const Vec3<T> name() const { return Vec3<T>(a, b, c); } | 570 | #define _DEFINE_SWIZZLER3(a, b, c, name) \ |
| 498 | #define DEFINE_SWIZZLER3_COMP1(a, a2) \ | 571 | const Vec3<T> name() const { \ |
| 499 | _DEFINE_SWIZZLER3(a, a, a, a##a##a); \ | 572 | return Vec3<T>(a, b, c); \ |
| 573 | } | ||
| 574 | #define DEFINE_SWIZZLER3_COMP1(a, a2) \ | ||
| 575 | _DEFINE_SWIZZLER3(a, a, a, a##a##a); \ | ||
| 500 | _DEFINE_SWIZZLER3(a, a, a, a2##a2##a2) | 576 | _DEFINE_SWIZZLER3(a, a, a, a2##a2##a2) |
| 501 | #define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \ | 577 | #define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \ |
| 502 | _DEFINE_SWIZZLER3(a, b, c, a##b##c); \ | 578 | _DEFINE_SWIZZLER3(a, b, c, a##b##c); \ |
| 503 | _DEFINE_SWIZZLER3(a, c, b, a##c##b); \ | 579 | _DEFINE_SWIZZLER3(a, c, b, a##c##b); \ |
| 504 | _DEFINE_SWIZZLER3(b, a, c, b##a##c); \ | 580 | _DEFINE_SWIZZLER3(b, a, c, b##a##c); \ |
| 505 | _DEFINE_SWIZZLER3(b, c, a, b##c##a); \ | 581 | _DEFINE_SWIZZLER3(b, c, a, b##c##a); \ |
| 506 | _DEFINE_SWIZZLER3(c, a, b, c##a##b); \ | 582 | _DEFINE_SWIZZLER3(c, a, b, c##a##b); \ |
| 507 | _DEFINE_SWIZZLER3(c, b, a, c##b##a); \ | 583 | _DEFINE_SWIZZLER3(c, b, a, c##b##a); \ |
| 508 | _DEFINE_SWIZZLER3(a, b, c, a2##b2##c2); \ | 584 | _DEFINE_SWIZZLER3(a, b, c, a2##b2##c2); \ |
| 509 | _DEFINE_SWIZZLER3(a, c, b, a2##c2##b2); \ | 585 | _DEFINE_SWIZZLER3(a, c, b, a2##c2##b2); \ |
| 510 | _DEFINE_SWIZZLER3(b, a, c, b2##a2##c2); \ | 586 | _DEFINE_SWIZZLER3(b, a, c, b2##a2##c2); \ |
| 511 | _DEFINE_SWIZZLER3(b, c, a, b2##c2##a2); \ | 587 | _DEFINE_SWIZZLER3(b, c, a, b2##c2##a2); \ |
| 512 | _DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \ | 588 | _DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \ |
| 513 | _DEFINE_SWIZZLER3(c, b, a, c2##b2##a2) | 589 | _DEFINE_SWIZZLER3(c, b, a, c2##b2##a2) |
| 514 | 590 | ||
| 515 | DEFINE_SWIZZLER3_COMP3(x, y, z, r, g, b); | 591 | DEFINE_SWIZZLER3_COMP3(x, y, z, r, g, b); |
| @@ -525,123 +601,104 @@ public: | |||
| 525 | #undef _DEFINE_SWIZZLER3 | 601 | #undef _DEFINE_SWIZZLER3 |
| 526 | }; | 602 | }; |
| 527 | 603 | ||
| 528 | 604 | template <typename T, typename V> | |
| 529 | template<typename T, typename V> | 605 | 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) | 606 | 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 | } | 607 | } |
| 534 | 608 | ||
| 535 | typedef Vec4<float> Vec4f; | 609 | typedef Vec4<float> Vec4f; |
| 536 | 610 | ||
| 537 | 611 | template <typename T> | |
| 538 | template<typename T> | 612 | 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) | 613 | return a.x * b.x + a.y * b.y; |
| 540 | { | ||
| 541 | return a.x*b.x + a.y*b.y; | ||
| 542 | } | 614 | } |
| 543 | 615 | ||
| 544 | template<typename T> | 616 | template <typename T> |
| 545 | static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) | 617 | static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) { |
| 546 | { | 618 | 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 | } | 619 | } |
| 549 | 620 | ||
| 550 | template<typename T> | 621 | template <typename T> |
| 551 | static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) | 622 | static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) { |
| 552 | { | 623 | 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 | } | 624 | } |
| 555 | 625 | ||
| 556 | template<typename T> | 626 | template <typename T> |
| 557 | static inline Vec3<decltype(T{}*T{}-T{}*T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) | 627 | static inline Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) { |
| 558 | { | 628 | 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 | } | 629 | } |
| 561 | 630 | ||
| 562 | // linear interpolation via float: 0.0=begin, 1.0=end | 631 | // linear interpolation via float: 0.0=begin, 1.0=end |
| 563 | template<typename X> | 632 | template <typename X> |
| 564 | static inline decltype(X{}*float{}+X{}*float{}) Lerp(const X& begin, const X& end, const float t) | 633 | static inline decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end, |
| 565 | { | 634 | const float t) { |
| 566 | return begin*(1.f-t) + end*t; | 635 | return begin * (1.f - t) + end * t; |
| 567 | } | 636 | } |
| 568 | 637 | ||
| 569 | // linear interpolation via int: 0=begin, base=end | 638 | // linear interpolation via int: 0=begin, base=end |
| 570 | template<typename X, int base> | 639 | template <typename X, int base> |
| 571 | static inline decltype((X{}*int{}+X{}*int{}) / base) LerpInt(const X& begin, const X& end, const int t) | 640 | static inline decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end, |
| 572 | { | 641 | const int t) { |
| 573 | return (begin*(base-t) + end*t) / base; | 642 | return (begin * (base - t) + end * t) / base; |
| 574 | } | 643 | } |
| 575 | 644 | ||
| 576 | // Utility vector factories | 645 | // Utility vector factories |
| 577 | template<typename T> | 646 | template <typename T> |
| 578 | static inline Vec2<T> MakeVec(const T& x, const T& y) | 647 | static inline Vec2<T> MakeVec(const T& x, const T& y) { |
| 579 | { | ||
| 580 | return Vec2<T>{x, y}; | 648 | return Vec2<T>{x, y}; |
| 581 | } | 649 | } |
| 582 | 650 | ||
| 583 | template<typename T> | 651 | template <typename T> |
| 584 | static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) | 652 | static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) { |
| 585 | { | ||
| 586 | return Vec3<T>{x, y, z}; | 653 | return Vec3<T>{x, y, z}; |
| 587 | } | 654 | } |
| 588 | 655 | ||
| 589 | template<typename T> | 656 | template <typename T> |
| 590 | static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) | 657 | 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]); | 658 | return MakeVec(x, y, zw[0], zw[1]); |
| 593 | } | 659 | } |
| 594 | 660 | ||
| 595 | template<typename T> | 661 | template <typename T> |
| 596 | static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) | 662 | static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) { |
| 597 | { | ||
| 598 | return MakeVec(xy[0], xy[1], z); | 663 | return MakeVec(xy[0], xy[1], z); |
| 599 | } | 664 | } |
| 600 | 665 | ||
| 601 | template<typename T> | 666 | template <typename T> |
| 602 | static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) | 667 | static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) { |
| 603 | { | ||
| 604 | return MakeVec(x, yz[0], yz[1]); | 668 | return MakeVec(x, yz[0], yz[1]); |
| 605 | } | 669 | } |
| 606 | 670 | ||
| 607 | template<typename T> | 671 | template <typename T> |
| 608 | static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) | 672 | 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}; | 673 | return Vec4<T>{x, y, z, w}; |
| 611 | } | 674 | } |
| 612 | 675 | ||
| 613 | template<typename T> | 676 | template <typename T> |
| 614 | static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) | 677 | 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); | 678 | return MakeVec(xy[0], xy[1], z, w); |
| 617 | } | 679 | } |
| 618 | 680 | ||
| 619 | template<typename T> | 681 | template <typename T> |
| 620 | static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) | 682 | 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); | 683 | return MakeVec(x, yz[0], yz[1], w); |
| 623 | } | 684 | } |
| 624 | 685 | ||
| 625 | // NOTE: This has priority over "Vec2<Vec2<T>> MakeVec(const Vec2<T>& x, const Vec2<T>& y)". | 686 | // 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 | 687 | // 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. | 688 | // out soon enough due to misuse of the returned structure. |
| 628 | template<typename T> | 689 | template <typename T> |
| 629 | static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) | 690 | 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]); | 691 | return MakeVec(xy[0], xy[1], zw[0], zw[1]); |
| 632 | } | 692 | } |
| 633 | 693 | ||
| 634 | template<typename T> | 694 | template <typename T> |
| 635 | static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) | 695 | static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) { |
| 636 | { | ||
| 637 | return MakeVec(xyz[0], xyz[1], xyz[2], w); | 696 | return MakeVec(xyz[0], xyz[1], xyz[2], w); |
| 638 | } | 697 | } |
| 639 | 698 | ||
| 640 | template<typename T> | 699 | template <typename T> |
| 641 | static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) | 700 | static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) { |
| 642 | { | ||
| 643 | return MakeVec(x, yzw[0], yzw[1], yzw[2]); | 701 | return MakeVec(x, yzw[0], yzw[1], yzw[2]); |
| 644 | } | 702 | } |
| 645 | 703 | ||
| 646 | |||
| 647 | } // namespace | 704 | } // 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..19f1a4030 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp | |||
| @@ -15,8 +15,8 @@ namespace Common { | |||
| 15 | #ifndef _MSC_VER | 15 | #ifndef _MSC_VER |
| 16 | 16 | ||
| 17 | #ifdef __FreeBSD__ | 17 | #ifdef __FreeBSD__ |
| 18 | #include <sys/types.h> | ||
| 19 | #include <machine/cpufunc.h> | 18 | #include <machine/cpufunc.h> |
| 19 | #include <sys/types.h> | ||
| 20 | #endif | 20 | #endif |
| 21 | 21 | ||
| 22 | static inline void __cpuidex(int info[4], int function_id, int subfunction_id) { | 22 | static inline void __cpuidex(int info[4], int function_id, int subfunction_id) { |
| @@ -26,15 +26,9 @@ static inline void __cpuidex(int info[4], int function_id, int subfunction_id) { | |||
| 26 | #else | 26 | #else |
| 27 | info[0] = function_id; // eax | 27 | info[0] = function_id; // eax |
| 28 | info[2] = subfunction_id; // ecx | 28 | info[2] = subfunction_id; // ecx |
| 29 | __asm__( | 29 | __asm__("cpuid" |
| 30 | "cpuid" | 30 | : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) |
| 31 | : "=a" (info[0]), | 31 | : "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 | 32 | #endif |
| 39 | } | 33 | } |
| 40 | 34 | ||
| @@ -88,14 +82,22 @@ static CPUCaps Detect() { | |||
| 88 | if (max_std_fn >= 1) { | 82 | if (max_std_fn >= 1) { |
| 89 | __cpuid(cpu_id, 0x00000001); | 83 | __cpuid(cpu_id, 0x00000001); |
| 90 | 84 | ||
| 91 | if ((cpu_id[3] >> 25) & 1) caps.sse = true; | 85 | if ((cpu_id[3] >> 25) & 1) |
| 92 | if ((cpu_id[3] >> 26) & 1) caps.sse2 = true; | 86 | caps.sse = true; |
| 93 | if ((cpu_id[2]) & 1) caps.sse3 = true; | 87 | if ((cpu_id[3] >> 26) & 1) |
| 94 | if ((cpu_id[2] >> 9) & 1) caps.ssse3 = true; | 88 | caps.sse2 = true; |
| 95 | if ((cpu_id[2] >> 19) & 1) caps.sse4_1 = true; | 89 | if ((cpu_id[2]) & 1) |
| 96 | if ((cpu_id[2] >> 20) & 1) caps.sse4_2 = true; | 90 | caps.sse3 = true; |
| 97 | if ((cpu_id[2] >> 22) & 1) caps.movbe = true; | 91 | if ((cpu_id[2] >> 9) & 1) |
| 98 | if ((cpu_id[2] >> 25) & 1) caps.aes = true; | 92 | caps.ssse3 = true; |
| 93 | if ((cpu_id[2] >> 19) & 1) | ||
| 94 | caps.sse4_1 = true; | ||
| 95 | if ((cpu_id[2] >> 20) & 1) | ||
| 96 | caps.sse4_2 = true; | ||
| 97 | if ((cpu_id[2] >> 22) & 1) | ||
| 98 | caps.movbe = true; | ||
| 99 | if ((cpu_id[2] >> 25) & 1) | ||
| 100 | caps.aes = true; | ||
| 99 | 101 | ||
| 100 | if ((cpu_id[3] >> 24) & 1) { | 102 | if ((cpu_id[3] >> 24) & 1) { |
| 101 | caps.fxsave_fxrstor = true; | 103 | caps.fxsave_fxrstor = true; |
| @@ -140,10 +142,14 @@ static CPUCaps Detect() { | |||
| 140 | if (max_ex_fn >= 0x80000001) { | 142 | if (max_ex_fn >= 0x80000001) { |
| 141 | // Check for more features | 143 | // Check for more features |
| 142 | __cpuid(cpu_id, 0x80000001); | 144 | __cpuid(cpu_id, 0x80000001); |
| 143 | if (cpu_id[2] & 1) caps.lahf_sahf_64 = true; | 145 | if (cpu_id[2] & 1) |
| 144 | if ((cpu_id[2] >> 5) & 1) caps.lzcnt = true; | 146 | caps.lahf_sahf_64 = true; |
| 145 | if ((cpu_id[2] >> 16) & 1) caps.fma4 = true; | 147 | if ((cpu_id[2] >> 5) & 1) |
| 146 | if ((cpu_id[3] >> 29) & 1) caps.long_mode = true; | 148 | caps.lzcnt = true; |
| 149 | if ((cpu_id[2] >> 16) & 1) | ||
| 150 | caps.fma4 = true; | ||
| 151 | if ((cpu_id[3] >> 29) & 1) | ||
| 152 | caps.long_mode = true; | ||
| 147 | } | 153 | } |
| 148 | 154 | ||
| 149 | return caps; | 155 | return caps; |
| @@ -162,24 +168,38 @@ std::string GetCPUCapsString() { | |||
| 162 | sum += caps.brand_string; | 168 | sum += caps.brand_string; |
| 163 | sum += ")"; | 169 | sum += ")"; |
| 164 | 170 | ||
| 165 | if (caps.sse) sum += ", SSE"; | 171 | if (caps.sse) |
| 172 | sum += ", SSE"; | ||
| 166 | if (caps.sse2) { | 173 | if (caps.sse2) { |
| 167 | sum += ", SSE2"; | 174 | sum += ", SSE2"; |
| 168 | if (!caps.flush_to_zero) sum += " (without DAZ)"; | 175 | if (!caps.flush_to_zero) |
| 176 | sum += " (without DAZ)"; | ||
| 169 | } | 177 | } |
| 170 | 178 | ||
| 171 | if (caps.sse3) sum += ", SSE3"; | 179 | if (caps.sse3) |
| 172 | if (caps.ssse3) sum += ", SSSE3"; | 180 | sum += ", SSE3"; |
| 173 | if (caps.sse4_1) sum += ", SSE4.1"; | 181 | if (caps.ssse3) |
| 174 | if (caps.sse4_2) sum += ", SSE4.2"; | 182 | sum += ", SSSE3"; |
| 175 | if (caps.avx) sum += ", AVX"; | 183 | if (caps.sse4_1) |
| 176 | if (caps.avx2) sum += ", AVX2"; | 184 | sum += ", SSE4.1"; |
| 177 | if (caps.bmi1) sum += ", BMI1"; | 185 | if (caps.sse4_2) |
| 178 | if (caps.bmi2) sum += ", BMI2"; | 186 | sum += ", SSE4.2"; |
| 179 | if (caps.fma) sum += ", FMA"; | 187 | if (caps.avx) |
| 180 | if (caps.aes) sum += ", AES"; | 188 | sum += ", AVX"; |
| 181 | if (caps.movbe) sum += ", MOVBE"; | 189 | if (caps.avx2) |
| 182 | if (caps.long_mode) sum += ", 64-bit support"; | 190 | sum += ", AVX2"; |
| 191 | if (caps.bmi1) | ||
| 192 | sum += ", BMI1"; | ||
| 193 | if (caps.bmi2) | ||
| 194 | sum += ", BMI2"; | ||
| 195 | if (caps.fma) | ||
| 196 | sum += ", FMA"; | ||
| 197 | if (caps.aes) | ||
| 198 | sum += ", AES"; | ||
| 199 | if (caps.movbe) | ||
| 200 | sum += ", MOVBE"; | ||
| 201 | if (caps.long_mode) | ||
| 202 | sum += ", 64-bit support"; | ||
| 183 | 203 | ||
| 184 | return sum; | 204 | return sum; |
| 185 | } | 205 | } |
diff --git a/src/common/x64/emitter.cpp b/src/common/x64/emitter.cpp index 5662f7f86..1a9fd6a6b 100644 --- a/src/common/x64/emitter.cpp +++ b/src/common/x64/emitter.cpp | |||
| @@ -26,179 +26,162 @@ | |||
| 26 | #include "cpu_detect.h" | 26 | #include "cpu_detect.h" |
| 27 | #include "emitter.h" | 27 | #include "emitter.h" |
| 28 | 28 | ||
| 29 | namespace Gen | 29 | namespace Gen { |
| 30 | { | ||
| 31 | 30 | ||
| 32 | struct NormalOpDef | 31 | struct NormalOpDef { |
| 33 | { | ||
| 34 | u8 toRm8, toRm32, fromRm8, fromRm32, imm8, imm32, simm8, eaximm8, eaximm32, ext; | 32 | u8 toRm8, toRm32, fromRm8, fromRm32, imm8, imm32, simm8, eaximm8, eaximm32, ext; |
| 35 | }; | 33 | }; |
| 36 | 34 | ||
| 37 | // 0xCC is code for invalid combination of immediates | 35 | // 0xCC is code for invalid combination of immediates |
| 38 | static const NormalOpDef normalops[11] = | 36 | static const NormalOpDef normalops[11] = { |
| 39 | { | 37 | {0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x83, 0x04, 0x05, 0}, // ADD |
| 40 | {0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x83, 0x04, 0x05, 0}, //ADD | 38 | {0x10, 0x11, 0x12, 0x13, 0x80, 0x81, 0x83, 0x14, 0x15, 2}, // ADC |
| 41 | {0x10, 0x11, 0x12, 0x13, 0x80, 0x81, 0x83, 0x14, 0x15, 2}, //ADC | ||
| 42 | 39 | ||
| 43 | {0x28, 0x29, 0x2A, 0x2B, 0x80, 0x81, 0x83, 0x2C, 0x2D, 5}, //SUB | 40 | {0x28, 0x29, 0x2A, 0x2B, 0x80, 0x81, 0x83, 0x2C, 0x2D, 5}, // SUB |
| 44 | {0x18, 0x19, 0x1A, 0x1B, 0x80, 0x81, 0x83, 0x1C, 0x1D, 3}, //SBB | 41 | {0x18, 0x19, 0x1A, 0x1B, 0x80, 0x81, 0x83, 0x1C, 0x1D, 3}, // SBB |
| 45 | 42 | ||
| 46 | {0x20, 0x21, 0x22, 0x23, 0x80, 0x81, 0x83, 0x24, 0x25, 4}, //AND | 43 | {0x20, 0x21, 0x22, 0x23, 0x80, 0x81, 0x83, 0x24, 0x25, 4}, // AND |
| 47 | {0x08, 0x09, 0x0A, 0x0B, 0x80, 0x81, 0x83, 0x0C, 0x0D, 1}, //OR | 44 | {0x08, 0x09, 0x0A, 0x0B, 0x80, 0x81, 0x83, 0x0C, 0x0D, 1}, // OR |
| 48 | 45 | ||
| 49 | {0x30, 0x31, 0x32, 0x33, 0x80, 0x81, 0x83, 0x34, 0x35, 6}, //XOR | 46 | {0x30, 0x31, 0x32, 0x33, 0x80, 0x81, 0x83, 0x34, 0x35, 6}, // XOR |
| 50 | {0x88, 0x89, 0x8A, 0x8B, 0xC6, 0xC7, 0xCC, 0xCC, 0xCC, 0}, //MOV | 47 | {0x88, 0x89, 0x8A, 0x8B, 0xC6, 0xC7, 0xCC, 0xCC, 0xCC, 0}, // MOV |
| 51 | 48 | ||
| 52 | {0x84, 0x85, 0x84, 0x85, 0xF6, 0xF7, 0xCC, 0xA8, 0xA9, 0}, //TEST (to == from) | 49 | {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 | 50 | {0x38, 0x39, 0x3A, 0x3B, 0x80, 0x81, 0x83, 0x3C, 0x3D, 7}, // CMP |
| 54 | 51 | ||
| 55 | {0x86, 0x87, 0x86, 0x87, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 7}, //XCHG | 52 | {0x86, 0x87, 0x86, 0x87, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 7}, // XCHG |
| 56 | }; | 53 | }; |
| 57 | 54 | ||
| 58 | enum NormalSSEOps | 55 | enum NormalSSEOps { |
| 59 | { | 56 | sseCMP = 0xC2, |
| 60 | sseCMP = 0xC2, | 57 | sseADD = 0x58, // ADD |
| 61 | sseADD = 0x58, //ADD | 58 | sseSUB = 0x5C, // SUB |
| 62 | sseSUB = 0x5C, //SUB | 59 | sseAND = 0x54, // AND |
| 63 | sseAND = 0x54, //AND | 60 | sseANDN = 0x55, // ANDN |
| 64 | sseANDN = 0x55, //ANDN | 61 | sseOR = 0x56, |
| 65 | sseOR = 0x56, | 62 | sseXOR = 0x57, |
| 66 | sseXOR = 0x57, | 63 | sseMUL = 0x59, // MUL |
| 67 | sseMUL = 0x59, //MUL | 64 | sseDIV = 0x5E, // DIV |
| 68 | sseDIV = 0x5E, //DIV | 65 | sseMIN = 0x5D, // MIN |
| 69 | sseMIN = 0x5D, //MIN | 66 | sseMAX = 0x5F, // MAX |
| 70 | sseMAX = 0x5F, //MAX | 67 | sseCOMIS = 0x2F, // COMIS |
| 71 | sseCOMIS = 0x2F, //COMIS | 68 | sseUCOMIS = 0x2E, // UCOMIS |
| 72 | sseUCOMIS = 0x2E, //UCOMIS | 69 | sseSQRT = 0x51, // SQRT |
| 73 | sseSQRT = 0x51, //SQRT | 70 | sseRSQRT = 0x52, // RSQRT (NO DOUBLE PRECISION!!!) |
| 74 | sseRSQRT = 0x52, //RSQRT (NO DOUBLE PRECISION!!!) | 71 | sseRCP = 0x53, // RCP |
| 75 | sseRCP = 0x53, //RCP | 72 | sseMOVAPfromRM = 0x28, // MOVAP from RM |
| 76 | sseMOVAPfromRM = 0x28, //MOVAP from RM | 73 | sseMOVAPtoRM = 0x29, // MOVAP to RM |
| 77 | sseMOVAPtoRM = 0x29, //MOVAP to RM | 74 | sseMOVUPfromRM = 0x10, // MOVUP from RM |
| 78 | sseMOVUPfromRM = 0x10, //MOVUP from RM | 75 | sseMOVUPtoRM = 0x11, // MOVUP to RM |
| 79 | sseMOVUPtoRM = 0x11, //MOVUP to RM | 76 | sseMOVLPfromRM = 0x12, |
| 80 | sseMOVLPfromRM= 0x12, | 77 | sseMOVLPtoRM = 0x13, |
| 81 | sseMOVLPtoRM = 0x13, | 78 | sseMOVHPfromRM = 0x16, |
| 82 | sseMOVHPfromRM= 0x16, | 79 | sseMOVHPtoRM = 0x17, |
| 83 | sseMOVHPtoRM = 0x17, | 80 | sseMOVHLPS = 0x12, |
| 84 | sseMOVHLPS = 0x12, | 81 | sseMOVLHPS = 0x16, |
| 85 | sseMOVLHPS = 0x16, | ||
| 86 | sseMOVDQfromRM = 0x6F, | 82 | sseMOVDQfromRM = 0x6F, |
| 87 | sseMOVDQtoRM = 0x7F, | 83 | sseMOVDQtoRM = 0x7F, |
| 88 | sseMASKMOVDQU = 0xF7, | 84 | sseMASKMOVDQU = 0xF7, |
| 89 | sseLDDQU = 0xF0, | 85 | sseLDDQU = 0xF0, |
| 90 | sseSHUF = 0xC6, | 86 | sseSHUF = 0xC6, |
| 91 | sseMOVNTDQ = 0xE7, | 87 | sseMOVNTDQ = 0xE7, |
| 92 | sseMOVNTP = 0x2B, | 88 | sseMOVNTP = 0x2B, |
| 93 | sseHADD = 0x7C, | 89 | sseHADD = 0x7C, |
| 94 | }; | 90 | }; |
| 95 | 91 | ||
| 96 | 92 | void XEmitter::SetCodePtr(u8* ptr) { | |
| 97 | void XEmitter::SetCodePtr(u8 *ptr) | ||
| 98 | { | ||
| 99 | code = ptr; | 93 | code = ptr; |
| 100 | } | 94 | } |
| 101 | 95 | ||
| 102 | const u8 *XEmitter::GetCodePtr() const | 96 | const u8* XEmitter::GetCodePtr() const { |
| 103 | { | ||
| 104 | return code; | 97 | return code; |
| 105 | } | 98 | } |
| 106 | 99 | ||
| 107 | u8 *XEmitter::GetWritableCodePtr() | 100 | u8* XEmitter::GetWritableCodePtr() { |
| 108 | { | ||
| 109 | return code; | 101 | return code; |
| 110 | } | 102 | } |
| 111 | 103 | ||
| 112 | void XEmitter::Write8(u8 value) | 104 | void XEmitter::Write8(u8 value) { |
| 113 | { | ||
| 114 | *code++ = value; | 105 | *code++ = value; |
| 115 | } | 106 | } |
| 116 | 107 | ||
| 117 | void XEmitter::Write16(u16 value) | 108 | void XEmitter::Write16(u16 value) { |
| 118 | { | ||
| 119 | std::memcpy(code, &value, sizeof(u16)); | 109 | std::memcpy(code, &value, sizeof(u16)); |
| 120 | code += sizeof(u16); | 110 | code += sizeof(u16); |
| 121 | } | 111 | } |
| 122 | 112 | ||
| 123 | void XEmitter::Write32(u32 value) | 113 | void XEmitter::Write32(u32 value) { |
| 124 | { | ||
| 125 | std::memcpy(code, &value, sizeof(u32)); | 114 | std::memcpy(code, &value, sizeof(u32)); |
| 126 | code += sizeof(u32); | 115 | code += sizeof(u32); |
| 127 | } | 116 | } |
| 128 | 117 | ||
| 129 | void XEmitter::Write64(u64 value) | 118 | void XEmitter::Write64(u64 value) { |
| 130 | { | ||
| 131 | std::memcpy(code, &value, sizeof(u64)); | 119 | std::memcpy(code, &value, sizeof(u64)); |
| 132 | code += sizeof(u64); | 120 | code += sizeof(u64); |
| 133 | } | 121 | } |
| 134 | 122 | ||
| 135 | void XEmitter::ReserveCodeSpace(int bytes) | 123 | void XEmitter::ReserveCodeSpace(int bytes) { |
| 136 | { | ||
| 137 | for (int i = 0; i < bytes; i++) | 124 | for (int i = 0; i < bytes; i++) |
| 138 | *code++ = 0xCC; | 125 | *code++ = 0xCC; |
| 139 | } | 126 | } |
| 140 | 127 | ||
| 141 | const u8 *XEmitter::AlignCode4() | 128 | const u8* XEmitter::AlignCode4() { |
| 142 | { | ||
| 143 | int c = int((u64)code & 3); | 129 | int c = int((u64)code & 3); |
| 144 | if (c) | 130 | if (c) |
| 145 | ReserveCodeSpace(4-c); | 131 | ReserveCodeSpace(4 - c); |
| 146 | return code; | 132 | return code; |
| 147 | } | 133 | } |
| 148 | 134 | ||
| 149 | const u8 *XEmitter::AlignCode16() | 135 | const u8* XEmitter::AlignCode16() { |
| 150 | { | ||
| 151 | int c = int((u64)code & 15); | 136 | int c = int((u64)code & 15); |
| 152 | if (c) | 137 | if (c) |
| 153 | ReserveCodeSpace(16-c); | 138 | ReserveCodeSpace(16 - c); |
| 154 | return code; | 139 | return code; |
| 155 | } | 140 | } |
| 156 | 141 | ||
| 157 | const u8 *XEmitter::AlignCodePage() | 142 | const u8* XEmitter::AlignCodePage() { |
| 158 | { | ||
| 159 | int c = int((u64)code & 4095); | 143 | int c = int((u64)code & 4095); |
| 160 | if (c) | 144 | if (c) |
| 161 | ReserveCodeSpace(4096-c); | 145 | ReserveCodeSpace(4096 - c); |
| 162 | return code; | 146 | return code; |
| 163 | } | 147 | } |
| 164 | 148 | ||
| 165 | // This operation modifies flags; check to see the flags are locked. | 149 | // This operation modifies flags; check to see the flags are locked. |
| 166 | // If the flags are locked, we should immediately and loudly fail before | 150 | // If the flags are locked, we should immediately and loudly fail before |
| 167 | // causing a subtle JIT bug. | 151 | // causing a subtle JIT bug. |
| 168 | void XEmitter::CheckFlags() | 152 | void XEmitter::CheckFlags() { |
| 169 | { | ||
| 170 | ASSERT_MSG(!flags_locked, "Attempt to modify flags while flags locked!"); | 153 | ASSERT_MSG(!flags_locked, "Attempt to modify flags while flags locked!"); |
| 171 | } | 154 | } |
| 172 | 155 | ||
| 173 | void XEmitter::WriteModRM(int mod, int reg, int rm) | 156 | void XEmitter::WriteModRM(int mod, int reg, int rm) { |
| 174 | { | ||
| 175 | Write8((u8)((mod << 6) | ((reg & 7) << 3) | (rm & 7))); | 157 | Write8((u8)((mod << 6) | ((reg & 7) << 3) | (rm & 7))); |
| 176 | } | 158 | } |
| 177 | 159 | ||
| 178 | void XEmitter::WriteSIB(int scale, int index, int base) | 160 | void XEmitter::WriteSIB(int scale, int index, int base) { |
| 179 | { | ||
| 180 | Write8((u8)((scale << 6) | ((index & 7) << 3) | (base & 7))); | 161 | Write8((u8)((scale << 6) | ((index & 7) << 3) | (base & 7))); |
| 181 | } | 162 | } |
| 182 | 163 | ||
| 183 | void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const | 164 | void OpArg::WriteRex(XEmitter* emit, int opBits, int bits, int customOp) const { |
| 184 | { | 165 | if (customOp == -1) |
| 185 | if (customOp == -1) customOp = operandReg; | 166 | customOp = operandReg; |
| 186 | #ifdef ARCHITECTURE_x86_64 | 167 | #ifdef ARCHITECTURE_x86_64 |
| 187 | u8 op = 0x40; | 168 | u8 op = 0x40; |
| 188 | // REX.W (whether operation is a 64-bit operation) | 169 | // REX.W (whether operation is a 64-bit operation) |
| 189 | if (opBits == 64) op |= 8; | 170 | if (opBits == 64) |
| 171 | op |= 8; | ||
| 190 | // REX.R (whether ModR/M reg field refers to R8-R15. | 172 | // REX.R (whether ModR/M reg field refers to R8-R15. |
| 191 | if (customOp & 8) op |= 4; | 173 | if (customOp & 8) |
| 174 | op |= 4; | ||
| 192 | // REX.X (whether ModR/M SIB index field refers to R8-R15) | 175 | // REX.X (whether ModR/M SIB index field refers to R8-R15) |
| 193 | if (indexReg & 8) op |= 2; | 176 | if (indexReg & 8) |
| 177 | op |= 2; | ||
| 194 | // REX.B (whether ModR/M rm or SIB base or opcode reg field refers to R8-R15) | 178 | // REX.B (whether ModR/M rm or SIB base or opcode reg field refers to R8-R15) |
| 195 | if (offsetOrBaseReg & 8) op |= 1; | 179 | if (offsetOrBaseReg & 8) |
| 180 | op |= 1; | ||
| 196 | // Write REX if wr have REX bits to write, or if the operation accesses | 181 | // Write REX if wr have REX bits to write, or if the operation accesses |
| 197 | // SIL, DIL, BPL, or SPL. | 182 | // SIL, DIL, BPL, or SPL. |
| 198 | if (op != 0x40 || | 183 | if (op != 0x40 || (scale == SCALE_NONE && bits == 8 && (offsetOrBaseReg & 0x10c) == 4) || |
| 199 | (scale == SCALE_NONE && bits == 8 && (offsetOrBaseReg & 0x10c) == 4) || | 184 | (opBits == 8 && (customOp & 0x10c) == 4)) { |
| 200 | (opBits == 8 && (customOp & 0x10c) == 4)) | ||
| 201 | { | ||
| 202 | emit->Write8(op); | 185 | emit->Write8(op); |
| 203 | // Check the operation doesn't access AH, BH, CH, or DH. | 186 | // Check the operation doesn't access AH, BH, CH, or DH. |
| 204 | DEBUG_ASSERT((offsetOrBaseReg & 0x100) == 0); | 187 | DEBUG_ASSERT((offsetOrBaseReg & 0x100) == 0); |
| @@ -214,8 +197,8 @@ void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const | |||
| 214 | #endif | 197 | #endif |
| 215 | } | 198 | } |
| 216 | 199 | ||
| 217 | void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, int W) const | 200 | void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, |
| 218 | { | 201 | int W) const { |
| 219 | int R = !(regOp1 & 8); | 202 | int R = !(regOp1 & 8); |
| 220 | int X = !(indexReg & 8); | 203 | int X = !(indexReg & 8); |
| 221 | int B = !(offsetOrBaseReg & 8); | 204 | int B = !(offsetOrBaseReg & 8); |
| @@ -223,14 +206,11 @@ void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp | |||
| 223 | int vvvv = (regOp2 == X64Reg::INVALID_REG) ? 0xf : (regOp2 ^ 0xf); | 206 | int vvvv = (regOp2 == X64Reg::INVALID_REG) ? 0xf : (regOp2 ^ 0xf); |
| 224 | 207 | ||
| 225 | // do we need any VEX fields that only appear in the three-byte form? | 208 | // do we need any VEX fields that only appear in the three-byte form? |
| 226 | if (X == 1 && B == 1 && W == 0 && mmmmm == 1) | 209 | if (X == 1 && B == 1 && W == 0 && mmmmm == 1) { |
| 227 | { | ||
| 228 | u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 2) | pp; | 210 | u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 2) | pp; |
| 229 | emit->Write8(0xC5); | 211 | emit->Write8(0xC5); |
| 230 | emit->Write8(RvvvvLpp); | 212 | emit->Write8(RvvvvLpp); |
| 231 | } | 213 | } else { |
| 232 | else | ||
| 233 | { | ||
| 234 | u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm; | 214 | u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm; |
| 235 | u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 2) | pp; | 215 | u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 2) | pp; |
| 236 | emit->Write8(0xC4); | 216 | emit->Write8(0xC4); |
| @@ -239,31 +219,27 @@ void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp | |||
| 239 | } | 219 | } |
| 240 | } | 220 | } |
| 241 | 221 | ||
| 242 | void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, | 222 | void OpArg::WriteRest(XEmitter* emit, int extraBytes, X64Reg _operandReg, |
| 243 | bool warn_64bit_offset) const | 223 | bool warn_64bit_offset) const { |
| 244 | { | ||
| 245 | if (_operandReg == INVALID_REG) | 224 | if (_operandReg == INVALID_REG) |
| 246 | _operandReg = (X64Reg)this->operandReg; | 225 | _operandReg = (X64Reg) this->operandReg; |
| 247 | int mod = 0; | 226 | int mod = 0; |
| 248 | int ireg = indexReg; | 227 | int ireg = indexReg; |
| 249 | bool SIB = false; | 228 | bool SIB = false; |
| 250 | int _offsetOrBaseReg = this->offsetOrBaseReg; | 229 | int _offsetOrBaseReg = this->offsetOrBaseReg; |
| 251 | 230 | ||
| 252 | if (scale == SCALE_RIP) //Also, on 32-bit, just an immediate address | 231 | if (scale == SCALE_RIP) // Also, on 32-bit, just an immediate address |
| 253 | { | 232 | { |
| 254 | // Oh, RIP addressing. | 233 | // Oh, RIP addressing. |
| 255 | _offsetOrBaseReg = 5; | 234 | _offsetOrBaseReg = 5; |
| 256 | emit->WriteModRM(0, _operandReg, _offsetOrBaseReg); | 235 | emit->WriteModRM(0, _operandReg, _offsetOrBaseReg); |
| 257 | //TODO : add some checks | 236 | // TODO : add some checks |
| 258 | #ifdef ARCHITECTURE_x86_64 | 237 | #ifdef ARCHITECTURE_x86_64 |
| 259 | u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes; | 238 | u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes; |
| 260 | s64 distance = (s64)offset - (s64)ripAddr; | 239 | s64 distance = (s64)offset - (s64)ripAddr; |
| 261 | ASSERT_MSG( | 240 | ASSERT_MSG((distance < 0x80000000LL && distance >= -0x80000000LL) || !warn_64bit_offset, |
| 262 | (distance < 0x80000000LL && | 241 | "WriteRest: op out of range (0x%" PRIx64 " uses 0x%" PRIx64 ")", ripAddr, |
| 263 | distance >= -0x80000000LL) || | 242 | offset); |
| 264 | !warn_64bit_offset, | ||
| 265 | "WriteRest: op out of range (0x%" PRIx64 " uses 0x%" PRIx64 ")", | ||
| 266 | ripAddr, offset); | ||
| 267 | s32 offs = (s32)distance; | 243 | s32 offs = (s32)distance; |
| 268 | emit->Write32((u32)offs); | 244 | emit->Write32((u32)offs); |
| 269 | #else | 245 | #else |
| @@ -272,66 +248,49 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, | |||
| 272 | return; | 248 | return; |
| 273 | } | 249 | } |
| 274 | 250 | ||
| 275 | if (scale == 0) | 251 | if (scale == 0) { |
| 276 | { | ||
| 277 | // Oh, no memory, Just a reg. | 252 | // Oh, no memory, Just a reg. |
| 278 | mod = 3; //11 | 253 | mod = 3; // 11 |
| 279 | } | 254 | } else if (scale >= 1) { |
| 280 | else if (scale >= 1) | 255 | // Ah good, no scaling. |
| 281 | { | 256 | if (scale == SCALE_ATREG && !((_offsetOrBaseReg & 7) == 4 || (_offsetOrBaseReg & 7) == 5)) { |
| 282 | //Ah good, no scaling. | 257 | // 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; | 258 | int ioff = (int)offset; |
| 287 | if (ioff == 0) | 259 | if (ioff == 0) { |
| 288 | { | ||
| 289 | mod = 0; | 260 | mod = 0; |
| 261 | } else if (ioff < -128 || ioff > 127) { | ||
| 262 | mod = 2; // 32-bit displacement | ||
| 263 | } else { | ||
| 264 | mod = 1; // 8-bit displacement | ||
| 290 | } | 265 | } |
| 291 | else if (ioff<-128 || ioff>127) | 266 | } 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; | 267 | SIB = true; |
| 303 | mod = 0; | 268 | mod = 0; |
| 304 | _offsetOrBaseReg = 5; | 269 | _offsetOrBaseReg = 5; |
| 305 | } | 270 | } else // if (scale != SCALE_ATREG) |
| 306 | else //if (scale != SCALE_ATREG) | ||
| 307 | { | 271 | { |
| 308 | if ((_offsetOrBaseReg & 7) == 4) //this would occupy the SIB encoding :( | 272 | if ((_offsetOrBaseReg & 7) == 4) // this would occupy the SIB encoding :( |
| 309 | { | 273 | { |
| 310 | //So we have to fake it with SIB encoding :( | 274 | // So we have to fake it with SIB encoding :( |
| 311 | SIB = true; | 275 | SIB = true; |
| 312 | } | 276 | } |
| 313 | 277 | ||
| 314 | if (scale >= SCALE_1 && scale < SCALE_ATREG) | 278 | if (scale >= SCALE_1 && scale < SCALE_ATREG) { |
| 315 | { | ||
| 316 | SIB = true; | 279 | SIB = true; |
| 317 | } | 280 | } |
| 318 | 281 | ||
| 319 | if (scale == SCALE_ATREG && ((_offsetOrBaseReg & 7) == 4)) | 282 | if (scale == SCALE_ATREG && ((_offsetOrBaseReg & 7) == 4)) { |
| 320 | { | ||
| 321 | SIB = true; | 283 | SIB = true; |
| 322 | ireg = _offsetOrBaseReg; | 284 | ireg = _offsetOrBaseReg; |
| 323 | } | 285 | } |
| 324 | 286 | ||
| 325 | //Okay, we're fine. Just disp encoding. | 287 | // Okay, we're fine. Just disp encoding. |
| 326 | //We need displacement. Which size? | 288 | // We need displacement. Which size? |
| 327 | int ioff = (int)(s64)offset; | 289 | int ioff = (int)(s64)offset; |
| 328 | if (ioff < -128 || ioff > 127) | 290 | if (ioff < -128 || ioff > 127) { |
| 329 | { | 291 | mod = 2; // 32-bit displacement |
| 330 | mod = 2; //32-bit displacement | 292 | } else { |
| 331 | } | 293 | mod = 1; // 8-bit displacement |
| 332 | else | ||
| 333 | { | ||
| 334 | mod = 1; //8-bit displacement | ||
| 335 | } | 294 | } |
| 336 | } | 295 | } |
| 337 | } | 296 | } |
| @@ -343,36 +302,55 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, | |||
| 343 | oreg = 4; | 302 | oreg = 4; |
| 344 | 303 | ||
| 345 | // TODO(ector): WTF is this if about? I don't remember writing it :-) | 304 | // TODO(ector): WTF is this if about? I don't remember writing it :-) |
| 346 | //if (RIP) | 305 | // if (RIP) |
| 347 | // oreg = 5; | 306 | // oreg = 5; |
| 348 | 307 | ||
| 349 | emit->WriteModRM(mod, _operandReg&7, oreg&7); | 308 | emit->WriteModRM(mod, _operandReg & 7, oreg & 7); |
| 350 | 309 | ||
| 351 | if (SIB) | 310 | if (SIB) { |
| 352 | { | 311 | // SIB byte |
| 353 | //SIB byte | ||
| 354 | int ss; | 312 | int ss; |
| 355 | switch (scale) | 313 | switch (scale) { |
| 356 | { | 314 | case SCALE_NONE: |
| 357 | case SCALE_NONE: _offsetOrBaseReg = 4; ss = 0; break; //RSP | 315 | _offsetOrBaseReg = 4; |
| 358 | case SCALE_1: ss = 0; break; | 316 | ss = 0; |
| 359 | case SCALE_2: ss = 1; break; | 317 | break; // RSP |
| 360 | case SCALE_4: ss = 2; break; | 318 | case SCALE_1: |
| 361 | case SCALE_8: ss = 3; break; | 319 | ss = 0; |
| 362 | case SCALE_NOBASE_2: ss = 1; break; | 320 | break; |
| 363 | case SCALE_NOBASE_4: ss = 2; break; | 321 | case SCALE_2: |
| 364 | case SCALE_NOBASE_8: ss = 3; break; | 322 | ss = 1; |
| 365 | case SCALE_ATREG: ss = 0; break; | 323 | break; |
| 366 | default: ASSERT_MSG(0, "Invalid scale for SIB byte"); ss = 0; break; | 324 | case SCALE_4: |
| 325 | ss = 2; | ||
| 326 | break; | ||
| 327 | case SCALE_8: | ||
| 328 | ss = 3; | ||
| 329 | break; | ||
| 330 | case SCALE_NOBASE_2: | ||
| 331 | ss = 1; | ||
| 332 | break; | ||
| 333 | case SCALE_NOBASE_4: | ||
| 334 | ss = 2; | ||
| 335 | break; | ||
| 336 | case SCALE_NOBASE_8: | ||
| 337 | ss = 3; | ||
| 338 | break; | ||
| 339 | case SCALE_ATREG: | ||
| 340 | ss = 0; | ||
| 341 | break; | ||
| 342 | default: | ||
| 343 | ASSERT_MSG(0, "Invalid scale for SIB byte"); | ||
| 344 | ss = 0; | ||
| 345 | break; | ||
| 367 | } | 346 | } |
| 368 | emit->Write8((u8)((ss << 6) | ((ireg&7)<<3) | (_offsetOrBaseReg&7))); | 347 | emit->Write8((u8)((ss << 6) | ((ireg & 7) << 3) | (_offsetOrBaseReg & 7))); |
| 369 | } | 348 | } |
| 370 | 349 | ||
| 371 | if (mod == 1) //8-bit disp | 350 | if (mod == 1) // 8-bit disp |
| 372 | { | 351 | { |
| 373 | emit->Write8((u8)(s8)(s32)offset); | 352 | emit->Write8((u8)(s8)(s32)offset); |
| 374 | } | 353 | } 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 | { | 354 | { |
| 377 | emit->Write32((u32)offset); | 355 | emit->Write32((u32)offset); |
| 378 | } | 356 | } |
| @@ -382,8 +360,7 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, | |||
| 382 | // R = register# upper bit | 360 | // R = register# upper bit |
| 383 | // X = scale amnt upper bit | 361 | // X = scale amnt upper bit |
| 384 | // B = base register# upper bit | 362 | // B = base register# upper bit |
| 385 | void XEmitter::Rex(int w, int r, int x, int b) | 363 | void XEmitter::Rex(int w, int r, int x, int b) { |
| 386 | { | ||
| 387 | w = w ? 1 : 0; | 364 | w = w ? 1 : 0; |
| 388 | r = r ? 1 : 0; | 365 | r = r ? 1 : 0; |
| 389 | x = x ? 1 : 0; | 366 | x = x ? 1 : 0; |
| @@ -393,70 +370,60 @@ void XEmitter::Rex(int w, int r, int x, int b) | |||
| 393 | Write8(rx); | 370 | Write8(rx); |
| 394 | } | 371 | } |
| 395 | 372 | ||
| 396 | void XEmitter::JMP(const u8* addr, bool force5Bytes) | 373 | void XEmitter::JMP(const u8* addr, bool force5Bytes) { |
| 397 | { | ||
| 398 | u64 fn = (u64)addr; | 374 | u64 fn = (u64)addr; |
| 399 | if (!force5Bytes) | 375 | if (!force5Bytes) { |
| 400 | { | ||
| 401 | s64 distance = (s64)(fn - ((u64)code + 2)); | 376 | s64 distance = (s64)(fn - ((u64)code + 2)); |
| 402 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, | 377 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, |
| 403 | "Jump target too far away, needs force5Bytes = true"); | 378 | "Jump target too far away, needs force5Bytes = true"); |
| 404 | //8 bits will do | 379 | // 8 bits will do |
| 405 | Write8(0xEB); | 380 | Write8(0xEB); |
| 406 | Write8((u8)(s8)distance); | 381 | Write8((u8)(s8)distance); |
| 407 | } | 382 | } else { |
| 408 | else | ||
| 409 | { | ||
| 410 | s64 distance = (s64)(fn - ((u64)code + 5)); | 383 | s64 distance = (s64)(fn - ((u64)code + 5)); |
| 411 | 384 | ||
| 412 | ASSERT_MSG( | 385 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, |
| 413 | distance >= -0x80000000LL && distance < 0x80000000LL, | 386 | "Jump target too far away, needs indirect register"); |
| 414 | "Jump target too far away, needs indirect register"); | ||
| 415 | Write8(0xE9); | 387 | Write8(0xE9); |
| 416 | Write32((u32)(s32)distance); | 388 | Write32((u32)(s32)distance); |
| 417 | } | 389 | } |
| 418 | } | 390 | } |
| 419 | 391 | ||
| 420 | void XEmitter::JMPptr(const OpArg& arg2) | 392 | void XEmitter::JMPptr(const OpArg& arg2) { |
| 421 | { | ||
| 422 | OpArg arg = arg2; | 393 | OpArg arg = arg2; |
| 423 | if (arg.IsImm()) ASSERT_MSG(0, "JMPptr - Imm argument"); | 394 | if (arg.IsImm()) |
| 395 | ASSERT_MSG(0, "JMPptr - Imm argument"); | ||
| 424 | arg.operandReg = 4; | 396 | arg.operandReg = 4; |
| 425 | arg.WriteRex(this, 0, 0); | 397 | arg.WriteRex(this, 0, 0); |
| 426 | Write8(0xFF); | 398 | Write8(0xFF); |
| 427 | arg.WriteRest(this); | 399 | arg.WriteRest(this); |
| 428 | } | 400 | } |
| 429 | 401 | ||
| 430 | //Can be used to trap other processors, before overwriting their code | 402 | // Can be used to trap other processors, before overwriting their code |
| 431 | // not used in dolphin | 403 | // not used in dolphin |
| 432 | void XEmitter::JMPself() | 404 | void XEmitter::JMPself() { |
| 433 | { | ||
| 434 | Write8(0xEB); | 405 | Write8(0xEB); |
| 435 | Write8(0xFE); | 406 | Write8(0xFE); |
| 436 | } | 407 | } |
| 437 | 408 | ||
| 438 | void XEmitter::CALLptr(OpArg arg) | 409 | void XEmitter::CALLptr(OpArg arg) { |
| 439 | { | 410 | if (arg.IsImm()) |
| 440 | if (arg.IsImm()) ASSERT_MSG(0, "CALLptr - Imm argument"); | 411 | ASSERT_MSG(0, "CALLptr - Imm argument"); |
| 441 | arg.operandReg = 2; | 412 | arg.operandReg = 2; |
| 442 | arg.WriteRex(this, 0, 0); | 413 | arg.WriteRex(this, 0, 0); |
| 443 | Write8(0xFF); | 414 | Write8(0xFF); |
| 444 | arg.WriteRest(this); | 415 | arg.WriteRest(this); |
| 445 | } | 416 | } |
| 446 | 417 | ||
| 447 | void XEmitter::CALL(const void* fnptr) | 418 | void XEmitter::CALL(const void* fnptr) { |
| 448 | { | ||
| 449 | u64 distance = u64(fnptr) - (u64(code) + 5); | 419 | u64 distance = u64(fnptr) - (u64(code) + 5); |
| 450 | ASSERT_MSG( | 420 | ASSERT_MSG(distance < 0x0000000080000000ULL || distance >= 0xFFFFFFFF80000000ULL, |
| 451 | distance < 0x0000000080000000ULL || | 421 | "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); | 422 | Write8(0xE8); |
| 455 | Write32(u32(distance)); | 423 | Write32(u32(distance)); |
| 456 | } | 424 | } |
| 457 | 425 | ||
| 458 | FixupBranch XEmitter::CALL() | 426 | FixupBranch XEmitter::CALL() { |
| 459 | { | ||
| 460 | FixupBranch branch; | 427 | FixupBranch branch; |
| 461 | branch.type = 1; | 428 | branch.type = 1; |
| 462 | branch.ptr = code + 5; | 429 | branch.ptr = code + 5; |
| @@ -467,38 +434,30 @@ FixupBranch XEmitter::CALL() | |||
| 467 | return branch; | 434 | return branch; |
| 468 | } | 435 | } |
| 469 | 436 | ||
| 470 | FixupBranch XEmitter::J(bool force5bytes) | 437 | FixupBranch XEmitter::J(bool force5bytes) { |
| 471 | { | ||
| 472 | FixupBranch branch; | 438 | FixupBranch branch; |
| 473 | branch.type = force5bytes ? 1 : 0; | 439 | branch.type = force5bytes ? 1 : 0; |
| 474 | branch.ptr = code + (force5bytes ? 5 : 2); | 440 | branch.ptr = code + (force5bytes ? 5 : 2); |
| 475 | if (!force5bytes) | 441 | if (!force5bytes) { |
| 476 | { | 442 | // 8 bits will do |
| 477 | //8 bits will do | ||
| 478 | Write8(0xEB); | 443 | Write8(0xEB); |
| 479 | Write8(0); | 444 | Write8(0); |
| 480 | } | 445 | } else { |
| 481 | else | ||
| 482 | { | ||
| 483 | Write8(0xE9); | 446 | Write8(0xE9); |
| 484 | Write32(0); | 447 | Write32(0); |
| 485 | } | 448 | } |
| 486 | return branch; | 449 | return branch; |
| 487 | } | 450 | } |
| 488 | 451 | ||
| 489 | FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes) | 452 | FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes) { |
| 490 | { | ||
| 491 | FixupBranch branch; | 453 | FixupBranch branch; |
| 492 | branch.type = force5bytes ? 1 : 0; | 454 | branch.type = force5bytes ? 1 : 0; |
| 493 | branch.ptr = code + (force5bytes ? 6 : 2); | 455 | branch.ptr = code + (force5bytes ? 6 : 2); |
| 494 | if (!force5bytes) | 456 | if (!force5bytes) { |
| 495 | { | 457 | // 8 bits will do |
| 496 | //8 bits will do | ||
| 497 | Write8(0x70 + conditionCode); | 458 | Write8(0x70 + conditionCode); |
| 498 | Write8(0); | 459 | Write8(0); |
| 499 | } | 460 | } else { |
| 500 | else | ||
| 501 | { | ||
| 502 | Write8(0x0F); | 461 | Write8(0x0F); |
| 503 | Write8(0x80 + conditionCode); | 462 | Write8(0x80 + conditionCode); |
| 504 | Write32(0); | 463 | Write32(0); |
| @@ -506,198 +465,268 @@ FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes) | |||
| 506 | return branch; | 465 | return branch; |
| 507 | } | 466 | } |
| 508 | 467 | ||
| 509 | void XEmitter::J_CC(CCFlags conditionCode, const u8* addr, bool force5bytes) | 468 | void XEmitter::J_CC(CCFlags conditionCode, const u8* addr, bool force5bytes) { |
| 510 | { | ||
| 511 | u64 fn = (u64)addr; | 469 | u64 fn = (u64)addr; |
| 512 | s64 distance = (s64)(fn - ((u64)code + 2)); | 470 | s64 distance = (s64)(fn - ((u64)code + 2)); |
| 513 | if (distance < -0x80 || distance >= 0x80 || force5bytes) | 471 | if (distance < -0x80 || distance >= 0x80 || force5bytes) { |
| 514 | { | ||
| 515 | distance = (s64)(fn - ((u64)code + 6)); | 472 | distance = (s64)(fn - ((u64)code + 6)); |
| 516 | ASSERT_MSG( | 473 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, |
| 517 | distance >= -0x80000000LL && distance < 0x80000000LL, | 474 | "Jump target too far away, needs indirect register"); |
| 518 | "Jump target too far away, needs indirect register"); | ||
| 519 | Write8(0x0F); | 475 | Write8(0x0F); |
| 520 | Write8(0x80 + conditionCode); | 476 | Write8(0x80 + conditionCode); |
| 521 | Write32((u32)(s32)distance); | 477 | Write32((u32)(s32)distance); |
| 522 | } | 478 | } else { |
| 523 | else | ||
| 524 | { | ||
| 525 | Write8(0x70 + conditionCode); | 479 | Write8(0x70 + conditionCode); |
| 526 | Write8((u8)(s8)distance); | 480 | Write8((u8)(s8)distance); |
| 527 | } | 481 | } |
| 528 | } | 482 | } |
| 529 | 483 | ||
| 530 | void XEmitter::SetJumpTarget(const FixupBranch& branch) | 484 | void XEmitter::SetJumpTarget(const FixupBranch& branch) { |
| 531 | { | 485 | if (branch.type == 0) { |
| 532 | if (branch.type == 0) | ||
| 533 | { | ||
| 534 | s64 distance = (s64)(code - branch.ptr); | 486 | s64 distance = (s64)(code - branch.ptr); |
| 535 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); | 487 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, |
| 488 | "Jump target too far away, needs force5Bytes = true"); | ||
| 536 | branch.ptr[-1] = (u8)(s8)distance; | 489 | branch.ptr[-1] = (u8)(s8)distance; |
| 537 | } | 490 | } else if (branch.type == 1) { |
| 538 | else if (branch.type == 1) | ||
| 539 | { | ||
| 540 | s64 distance = (s64)(code - branch.ptr); | 491 | s64 distance = (s64)(code - branch.ptr); |
| 541 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); | 492 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, |
| 493 | "Jump target too far away, needs indirect register"); | ||
| 542 | ((s32*)branch.ptr)[-1] = (s32)distance; | 494 | ((s32*)branch.ptr)[-1] = (s32)distance; |
| 543 | } | 495 | } |
| 544 | } | 496 | } |
| 545 | 497 | ||
| 546 | void XEmitter::SetJumpTarget(const FixupBranch& branch, const u8* target) | 498 | void XEmitter::SetJumpTarget(const FixupBranch& branch, const u8* target) { |
| 547 | { | 499 | if (branch.type == 0) { |
| 548 | if (branch.type == 0) | ||
| 549 | { | ||
| 550 | s64 distance = (s64)(target - branch.ptr); | 500 | s64 distance = (s64)(target - branch.ptr); |
| 551 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); | 501 | ASSERT_MSG(distance >= -0x80 && distance < 0x80, |
| 502 | "Jump target too far away, needs force5Bytes = true"); | ||
| 552 | branch.ptr[-1] = (u8)(s8)distance; | 503 | branch.ptr[-1] = (u8)(s8)distance; |
| 553 | } | 504 | } else if (branch.type == 1) { |
| 554 | else if (branch.type == 1) | ||
| 555 | { | ||
| 556 | s64 distance = (s64)(target - branch.ptr); | 505 | s64 distance = (s64)(target - branch.ptr); |
| 557 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); | 506 | ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, |
| 507 | "Jump target too far away, needs indirect register"); | ||
| 558 | ((s32*)branch.ptr)[-1] = (s32)distance; | 508 | ((s32*)branch.ptr)[-1] = (s32)distance; |
| 559 | } | 509 | } |
| 560 | } | 510 | } |
| 561 | 511 | ||
| 562 | //Single byte opcodes | 512 | // Single byte opcodes |
| 563 | //There is no PUSHAD/POPAD in 64-bit mode. | 513 | // There is no PUSHAD/POPAD in 64-bit mode. |
| 564 | void XEmitter::INT3() {Write8(0xCC);} | 514 | void XEmitter::INT3() { |
| 565 | void XEmitter::RET() {Write8(0xC3);} | 515 | 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 | 516 | } |
| 517 | void XEmitter::RET() { | ||
| 518 | Write8(0xC3); | ||
| 519 | } | ||
| 520 | void XEmitter::RET_FAST() { | ||
| 521 | Write8(0xF3); | ||
| 522 | Write8(0xC3); | ||
| 523 | } // two-byte return (rep ret) - recommended by AMD optimization manual for the case of jumping to a | ||
| 524 | // ret | ||
| 567 | 525 | ||
| 568 | // The first sign of decadence: optimized NOPs. | 526 | // The first sign of decadence: optimized NOPs. |
| 569 | void XEmitter::NOP(size_t size) | 527 | void XEmitter::NOP(size_t size) { |
| 570 | { | ||
| 571 | DEBUG_ASSERT((int)size > 0); | 528 | DEBUG_ASSERT((int)size > 0); |
| 572 | while (true) | 529 | while (true) { |
| 573 | { | 530 | switch (size) { |
| 574 | switch (size) | ||
| 575 | { | ||
| 576 | case 0: | 531 | case 0: |
| 577 | return; | 532 | return; |
| 578 | case 1: | 533 | case 1: |
| 579 | Write8(0x90); | 534 | Write8(0x90); |
| 580 | return; | 535 | return; |
| 581 | case 2: | 536 | case 2: |
| 582 | Write8(0x66); Write8(0x90); | 537 | Write8(0x66); |
| 538 | Write8(0x90); | ||
| 583 | return; | 539 | return; |
| 584 | case 3: | 540 | case 3: |
| 585 | Write8(0x0F); Write8(0x1F); Write8(0x00); | 541 | Write8(0x0F); |
| 542 | Write8(0x1F); | ||
| 543 | Write8(0x00); | ||
| 586 | return; | 544 | return; |
| 587 | case 4: | 545 | case 4: |
| 588 | Write8(0x0F); Write8(0x1F); Write8(0x40); Write8(0x00); | 546 | Write8(0x0F); |
| 547 | Write8(0x1F); | ||
| 548 | Write8(0x40); | ||
| 549 | Write8(0x00); | ||
| 589 | return; | 550 | return; |
| 590 | case 5: | 551 | case 5: |
| 591 | Write8(0x0F); Write8(0x1F); Write8(0x44); Write8(0x00); | 552 | Write8(0x0F); |
| 553 | Write8(0x1F); | ||
| 554 | Write8(0x44); | ||
| 555 | Write8(0x00); | ||
| 592 | Write8(0x00); | 556 | Write8(0x00); |
| 593 | return; | 557 | return; |
| 594 | case 6: | 558 | case 6: |
| 595 | Write8(0x66); Write8(0x0F); Write8(0x1F); Write8(0x44); | 559 | Write8(0x66); |
| 596 | Write8(0x00); Write8(0x00); | 560 | Write8(0x0F); |
| 561 | Write8(0x1F); | ||
| 562 | Write8(0x44); | ||
| 563 | Write8(0x00); | ||
| 564 | Write8(0x00); | ||
| 597 | return; | 565 | return; |
| 598 | case 7: | 566 | case 7: |
| 599 | Write8(0x0F); Write8(0x1F); Write8(0x80); Write8(0x00); | 567 | Write8(0x0F); |
| 600 | Write8(0x00); Write8(0x00); Write8(0x00); | 568 | Write8(0x1F); |
| 569 | Write8(0x80); | ||
| 570 | Write8(0x00); | ||
| 571 | Write8(0x00); | ||
| 572 | Write8(0x00); | ||
| 573 | Write8(0x00); | ||
| 601 | return; | 574 | return; |
| 602 | case 8: | 575 | case 8: |
| 603 | Write8(0x0F); Write8(0x1F); Write8(0x84); Write8(0x00); | 576 | Write8(0x0F); |
| 604 | Write8(0x00); Write8(0x00); Write8(0x00); Write8(0x00); | 577 | Write8(0x1F); |
| 578 | Write8(0x84); | ||
| 579 | Write8(0x00); | ||
| 580 | Write8(0x00); | ||
| 581 | Write8(0x00); | ||
| 582 | Write8(0x00); | ||
| 583 | Write8(0x00); | ||
| 605 | return; | 584 | return; |
| 606 | case 9: | 585 | case 9: |
| 607 | Write8(0x66); Write8(0x0F); Write8(0x1F); Write8(0x84); | 586 | Write8(0x66); |
| 608 | Write8(0x00); Write8(0x00); Write8(0x00); Write8(0x00); | 587 | Write8(0x0F); |
| 588 | Write8(0x1F); | ||
| 589 | Write8(0x84); | ||
| 590 | Write8(0x00); | ||
| 591 | Write8(0x00); | ||
| 592 | Write8(0x00); | ||
| 593 | Write8(0x00); | ||
| 609 | Write8(0x00); | 594 | Write8(0x00); |
| 610 | return; | 595 | return; |
| 611 | case 10: | 596 | case 10: |
| 612 | Write8(0x66); Write8(0x66); Write8(0x0F); Write8(0x1F); | 597 | Write8(0x66); |
| 613 | Write8(0x84); Write8(0x00); Write8(0x00); Write8(0x00); | 598 | Write8(0x66); |
| 614 | Write8(0x00); Write8(0x00); | 599 | Write8(0x0F); |
| 600 | Write8(0x1F); | ||
| 601 | Write8(0x84); | ||
| 602 | Write8(0x00); | ||
| 603 | Write8(0x00); | ||
| 604 | Write8(0x00); | ||
| 605 | Write8(0x00); | ||
| 606 | Write8(0x00); | ||
| 615 | return; | 607 | return; |
| 616 | default: | 608 | default: |
| 617 | // Even though x86 instructions are allowed to be up to 15 bytes long, | 609 | // 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 | 610 | // AMD advises against using NOPs longer than 11 bytes because they |
| 619 | // carry a performance penalty on CPUs older than AMD family 16h. | 611 | // carry a performance penalty on CPUs older than AMD family 16h. |
| 620 | Write8(0x66); Write8(0x66); Write8(0x66); Write8(0x0F); | 612 | Write8(0x66); |
| 621 | Write8(0x1F); Write8(0x84); Write8(0x00); Write8(0x00); | 613 | Write8(0x66); |
| 622 | Write8(0x00); Write8(0x00); Write8(0x00); | 614 | Write8(0x66); |
| 615 | Write8(0x0F); | ||
| 616 | Write8(0x1F); | ||
| 617 | Write8(0x84); | ||
| 618 | Write8(0x00); | ||
| 619 | Write8(0x00); | ||
| 620 | Write8(0x00); | ||
| 621 | Write8(0x00); | ||
| 622 | Write8(0x00); | ||
| 623 | size -= 11; | 623 | size -= 11; |
| 624 | continue; | 624 | continue; |
| 625 | } | 625 | } |
| 626 | } | 626 | } |
| 627 | } | 627 | } |
| 628 | 628 | ||
| 629 | void XEmitter::PAUSE() {Write8(0xF3); NOP();} //use in tight spinloops for energy saving on some cpu | 629 | void XEmitter::PAUSE() { |
| 630 | void XEmitter::CLC() {CheckFlags(); Write8(0xF8);} //clear carry | 630 | Write8(0xF3); |
| 631 | void XEmitter::CMC() {CheckFlags(); Write8(0xF5);} //flip carry | 631 | NOP(); |
| 632 | void XEmitter::STC() {CheckFlags(); Write8(0xF9);} //set carry | 632 | } // use in tight spinloops for energy saving on some cpu |
| 633 | void XEmitter::CLC() { | ||
| 634 | CheckFlags(); | ||
| 635 | Write8(0xF8); | ||
| 636 | } // clear carry | ||
| 637 | void XEmitter::CMC() { | ||
| 638 | CheckFlags(); | ||
| 639 | Write8(0xF5); | ||
| 640 | } // flip carry | ||
| 641 | void XEmitter::STC() { | ||
| 642 | CheckFlags(); | ||
| 643 | Write8(0xF9); | ||
| 644 | } // set carry | ||
| 633 | 645 | ||
| 634 | //TODO: xchg ah, al ??? | 646 | // TODO: xchg ah, al ??? |
| 635 | void XEmitter::XCHG_AHAL() | 647 | void XEmitter::XCHG_AHAL() { |
| 636 | { | ||
| 637 | Write8(0x86); | 648 | Write8(0x86); |
| 638 | Write8(0xe0); | 649 | Write8(0xe0); |
| 639 | // alt. 86 c4 | 650 | // alt. 86 c4 |
| 640 | } | 651 | } |
| 641 | 652 | ||
| 642 | //These two can not be executed on early Intel 64-bit CPU:s, only on AMD! | 653 | // These two can not be executed on early Intel 64-bit CPU:s, only on AMD! |
| 643 | void XEmitter::LAHF() {Write8(0x9F);} | 654 | void XEmitter::LAHF() { |
| 644 | void XEmitter::SAHF() {CheckFlags(); Write8(0x9E);} | 655 | Write8(0x9F); |
| 656 | } | ||
| 657 | void XEmitter::SAHF() { | ||
| 658 | CheckFlags(); | ||
| 659 | Write8(0x9E); | ||
| 660 | } | ||
| 645 | 661 | ||
| 646 | void XEmitter::PUSHF() {Write8(0x9C);} | 662 | void XEmitter::PUSHF() { |
| 647 | void XEmitter::POPF() {CheckFlags(); Write8(0x9D);} | 663 | Write8(0x9C); |
| 664 | } | ||
| 665 | void XEmitter::POPF() { | ||
| 666 | CheckFlags(); | ||
| 667 | Write8(0x9D); | ||
| 668 | } | ||
| 648 | 669 | ||
| 649 | void XEmitter::LFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xE8);} | 670 | void XEmitter::LFENCE() { |
| 650 | void XEmitter::MFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF0);} | 671 | Write8(0x0F); |
| 651 | void XEmitter::SFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF8);} | 672 | Write8(0xAE); |
| 673 | Write8(0xE8); | ||
| 674 | } | ||
| 675 | void XEmitter::MFENCE() { | ||
| 676 | Write8(0x0F); | ||
| 677 | Write8(0xAE); | ||
| 678 | Write8(0xF0); | ||
| 679 | } | ||
| 680 | void XEmitter::SFENCE() { | ||
| 681 | Write8(0x0F); | ||
| 682 | Write8(0xAE); | ||
| 683 | Write8(0xF8); | ||
| 684 | } | ||
| 652 | 685 | ||
| 653 | void XEmitter::WriteSimple1Byte(int bits, u8 byte, X64Reg reg) | 686 | void XEmitter::WriteSimple1Byte(int bits, u8 byte, X64Reg reg) { |
| 654 | { | ||
| 655 | if (bits == 16) | 687 | if (bits == 16) |
| 656 | Write8(0x66); | 688 | Write8(0x66); |
| 657 | Rex(bits == 64, 0, 0, (int)reg >> 3); | 689 | Rex(bits == 64, 0, 0, (int)reg >> 3); |
| 658 | Write8(byte + ((int)reg & 7)); | 690 | Write8(byte + ((int)reg & 7)); |
| 659 | } | 691 | } |
| 660 | 692 | ||
| 661 | void XEmitter::WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg) | 693 | void XEmitter::WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg) { |
| 662 | { | ||
| 663 | if (bits == 16) | 694 | if (bits == 16) |
| 664 | Write8(0x66); | 695 | Write8(0x66); |
| 665 | Rex(bits==64, 0, 0, (int)reg >> 3); | 696 | Rex(bits == 64, 0, 0, (int)reg >> 3); |
| 666 | Write8(byte1); | 697 | Write8(byte1); |
| 667 | Write8(byte2 + ((int)reg & 7)); | 698 | Write8(byte2 + ((int)reg & 7)); |
| 668 | } | 699 | } |
| 669 | 700 | ||
| 670 | void XEmitter::CWD(int bits) | 701 | void XEmitter::CWD(int bits) { |
| 671 | { | ||
| 672 | if (bits == 16) | 702 | if (bits == 16) |
| 673 | Write8(0x66); | 703 | Write8(0x66); |
| 674 | Rex(bits == 64, 0, 0, 0); | 704 | Rex(bits == 64, 0, 0, 0); |
| 675 | Write8(0x99); | 705 | Write8(0x99); |
| 676 | } | 706 | } |
| 677 | 707 | ||
| 678 | void XEmitter::CBW(int bits) | 708 | void XEmitter::CBW(int bits) { |
| 679 | { | ||
| 680 | if (bits == 8) | 709 | if (bits == 8) |
| 681 | Write8(0x66); | 710 | Write8(0x66); |
| 682 | Rex(bits == 32, 0, 0, 0); | 711 | Rex(bits == 32, 0, 0, 0); |
| 683 | Write8(0x98); | 712 | Write8(0x98); |
| 684 | } | 713 | } |
| 685 | 714 | ||
| 686 | //Simple opcodes | 715 | // Simple opcodes |
| 687 | |||
| 688 | 716 | ||
| 689 | //push/pop do not need wide to be 64-bit | 717 | // push/pop do not need wide to be 64-bit |
| 690 | void XEmitter::PUSH(X64Reg reg) {WriteSimple1Byte(32, 0x50, reg);} | 718 | void XEmitter::PUSH(X64Reg reg) { |
| 691 | void XEmitter::POP(X64Reg reg) {WriteSimple1Byte(32, 0x58, reg);} | 719 | WriteSimple1Byte(32, 0x50, reg); |
| 720 | } | ||
| 721 | void XEmitter::POP(X64Reg reg) { | ||
| 722 | WriteSimple1Byte(32, 0x58, reg); | ||
| 723 | } | ||
| 692 | 724 | ||
| 693 | void XEmitter::PUSH(int bits, const OpArg& reg) | 725 | void XEmitter::PUSH(int bits, const OpArg& reg) { |
| 694 | { | ||
| 695 | if (reg.IsSimpleReg()) | 726 | if (reg.IsSimpleReg()) |
| 696 | PUSH(reg.GetSimpleReg()); | 727 | PUSH(reg.GetSimpleReg()); |
| 697 | else if (reg.IsImm()) | 728 | else if (reg.IsImm()) { |
| 698 | { | 729 | switch (reg.GetImmBits()) { |
| 699 | switch (reg.GetImmBits()) | ||
| 700 | { | ||
| 701 | case 8: | 730 | case 8: |
| 702 | Write8(0x6A); | 731 | Write8(0x6A); |
| 703 | Write8((u8)(s8)reg.offset); | 732 | Write8((u8)(s8)reg.offset); |
| @@ -715,9 +744,7 @@ void XEmitter::PUSH(int bits, const OpArg& reg) | |||
| 715 | ASSERT_MSG(0, "PUSH - Bad imm bits"); | 744 | ASSERT_MSG(0, "PUSH - Bad imm bits"); |
| 716 | break; | 745 | break; |
| 717 | } | 746 | } |
| 718 | } | 747 | } else { |
| 719 | else | ||
| 720 | { | ||
| 721 | if (bits == 16) | 748 | if (bits == 16) |
| 722 | Write8(0x66); | 749 | Write8(0x66); |
| 723 | reg.WriteRex(this, bits, bits); | 750 | reg.WriteRex(this, bits, bits); |
| @@ -726,44 +753,33 @@ void XEmitter::PUSH(int bits, const OpArg& reg) | |||
| 726 | } | 753 | } |
| 727 | } | 754 | } |
| 728 | 755 | ||
| 729 | void XEmitter::POP(int /*bits*/, const OpArg& reg) | 756 | void XEmitter::POP(int /*bits*/, const OpArg& reg) { |
| 730 | { | ||
| 731 | if (reg.IsSimpleReg()) | 757 | if (reg.IsSimpleReg()) |
| 732 | POP(reg.GetSimpleReg()); | 758 | POP(reg.GetSimpleReg()); |
| 733 | else | 759 | else |
| 734 | ASSERT_MSG(0, "POP - Unsupported encoding"); | 760 | ASSERT_MSG(0, "POP - Unsupported encoding"); |
| 735 | } | 761 | } |
| 736 | 762 | ||
| 737 | void XEmitter::BSWAP(int bits, X64Reg reg) | 763 | void XEmitter::BSWAP(int bits, X64Reg reg) { |
| 738 | { | 764 | if (bits >= 32) { |
| 739 | if (bits >= 32) | ||
| 740 | { | ||
| 741 | WriteSimple2Byte(bits, 0x0F, 0xC8, reg); | 765 | WriteSimple2Byte(bits, 0x0F, 0xC8, reg); |
| 742 | } | 766 | } else if (bits == 16) { |
| 743 | else if (bits == 16) | ||
| 744 | { | ||
| 745 | ROL(16, R(reg), Imm8(8)); | 767 | ROL(16, R(reg), Imm8(8)); |
| 746 | } | 768 | } else if (bits == 8) { |
| 747 | else if (bits == 8) | ||
| 748 | { | ||
| 749 | // Do nothing - can't bswap a single byte... | 769 | // Do nothing - can't bswap a single byte... |
| 750 | } | 770 | } else { |
| 751 | else | ||
| 752 | { | ||
| 753 | ASSERT_MSG(0, "BSWAP - Wrong number of bits"); | 771 | ASSERT_MSG(0, "BSWAP - Wrong number of bits"); |
| 754 | } | 772 | } |
| 755 | } | 773 | } |
| 756 | 774 | ||
| 757 | // Undefined opcode - reserved | 775 | // Undefined opcode - reserved |
| 758 | // If we ever need a way to always cause a non-breakpoint hard exception... | 776 | // If we ever need a way to always cause a non-breakpoint hard exception... |
| 759 | void XEmitter::UD2() | 777 | void XEmitter::UD2() { |
| 760 | { | ||
| 761 | Write8(0x0F); | 778 | Write8(0x0F); |
| 762 | Write8(0x0B); | 779 | Write8(0x0B); |
| 763 | } | 780 | } |
| 764 | 781 | ||
| 765 | void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) | 782 | void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) { |
| 766 | { | ||
| 767 | ASSERT_MSG(!arg.IsImm(), "PREFETCH - Imm argument"); | 783 | ASSERT_MSG(!arg.IsImm(), "PREFETCH - Imm argument"); |
| 768 | arg.operandReg = (u8)level; | 784 | arg.operandReg = (u8)level; |
| 769 | arg.WriteRex(this, 0, 0); | 785 | arg.WriteRex(this, 0, 0); |
| @@ -772,8 +788,7 @@ void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) | |||
| 772 | arg.WriteRest(this); | 788 | arg.WriteRest(this); |
| 773 | } | 789 | } |
| 774 | 790 | ||
| 775 | void XEmitter::SETcc(CCFlags flag, OpArg dest) | 791 | void XEmitter::SETcc(CCFlags flag, OpArg dest) { |
| 776 | { | ||
| 777 | ASSERT_MSG(!dest.IsImm(), "SETcc - Imm argument"); | 792 | ASSERT_MSG(!dest.IsImm(), "SETcc - Imm argument"); |
| 778 | dest.operandReg = 0; | 793 | dest.operandReg = 0; |
| 779 | dest.WriteRex(this, 0, 8); | 794 | dest.WriteRex(this, 0, 8); |
| @@ -782,8 +797,7 @@ void XEmitter::SETcc(CCFlags flag, OpArg dest) | |||
| 782 | dest.WriteRest(this); | 797 | dest.WriteRest(this); |
| 783 | } | 798 | } |
| 784 | 799 | ||
| 785 | void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) | 800 | void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) { |
| 786 | { | ||
| 787 | ASSERT_MSG(!src.IsImm(), "CMOVcc - Imm argument"); | 801 | ASSERT_MSG(!src.IsImm(), "CMOVcc - Imm argument"); |
| 788 | ASSERT_MSG(bits != 8, "CMOVcc - 8 bits unsupported"); | 802 | ASSERT_MSG(bits != 8, "CMOVcc - 8 bits unsupported"); |
| 789 | if (bits == 16) | 803 | if (bits == 16) |
| @@ -795,34 +809,41 @@ void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) | |||
| 795 | src.WriteRest(this); | 809 | src.WriteRest(this); |
| 796 | } | 810 | } |
| 797 | 811 | ||
| 798 | void XEmitter::WriteMulDivType(int bits, OpArg src, int ext) | 812 | void XEmitter::WriteMulDivType(int bits, OpArg src, int ext) { |
| 799 | { | ||
| 800 | ASSERT_MSG(!src.IsImm(), "WriteMulDivType - Imm argument"); | 813 | ASSERT_MSG(!src.IsImm(), "WriteMulDivType - Imm argument"); |
| 801 | CheckFlags(); | 814 | CheckFlags(); |
| 802 | src.operandReg = ext; | 815 | src.operandReg = ext; |
| 803 | if (bits == 16) | 816 | if (bits == 16) |
| 804 | Write8(0x66); | 817 | Write8(0x66); |
| 805 | src.WriteRex(this, bits, bits, 0); | 818 | src.WriteRex(this, bits, bits, 0); |
| 806 | if (bits == 8) | 819 | if (bits == 8) { |
| 807 | { | ||
| 808 | Write8(0xF6); | 820 | Write8(0xF6); |
| 809 | } | 821 | } else { |
| 810 | else | ||
| 811 | { | ||
| 812 | Write8(0xF7); | 822 | Write8(0xF7); |
| 813 | } | 823 | } |
| 814 | src.WriteRest(this); | 824 | src.WriteRest(this); |
| 815 | } | 825 | } |
| 816 | 826 | ||
| 817 | void XEmitter::MUL(int bits, const OpArg& src) {WriteMulDivType(bits, src, 4);} | 827 | void XEmitter::MUL(int bits, const OpArg& src) { |
| 818 | void XEmitter::DIV(int bits, const OpArg& src) {WriteMulDivType(bits, src, 6);} | 828 | WriteMulDivType(bits, src, 4); |
| 819 | void XEmitter::IMUL(int bits, const OpArg& src) {WriteMulDivType(bits, src, 5);} | 829 | } |
| 820 | void XEmitter::IDIV(int bits, const OpArg& src) {WriteMulDivType(bits, src, 7);} | 830 | void XEmitter::DIV(int bits, const OpArg& src) { |
| 821 | void XEmitter::NEG(int bits, const OpArg& src) {WriteMulDivType(bits, src, 3);} | 831 | WriteMulDivType(bits, src, 6); |
| 822 | void XEmitter::NOT(int bits, const OpArg& src) {WriteMulDivType(bits, src, 2);} | 832 | } |
| 833 | void XEmitter::IMUL(int bits, const OpArg& src) { | ||
| 834 | WriteMulDivType(bits, src, 5); | ||
| 835 | } | ||
| 836 | void XEmitter::IDIV(int bits, const OpArg& src) { | ||
| 837 | WriteMulDivType(bits, src, 7); | ||
| 838 | } | ||
| 839 | void XEmitter::NEG(int bits, const OpArg& src) { | ||
| 840 | WriteMulDivType(bits, src, 3); | ||
| 841 | } | ||
| 842 | void XEmitter::NOT(int bits, const OpArg& src) { | ||
| 843 | WriteMulDivType(bits, src, 2); | ||
| 844 | } | ||
| 823 | 845 | ||
| 824 | void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep) | 846 | void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep) { |
| 825 | { | ||
| 826 | ASSERT_MSG(!src.IsImm(), "WriteBitSearchType - Imm argument"); | 847 | ASSERT_MSG(!src.IsImm(), "WriteBitSearchType - Imm argument"); |
| 827 | CheckFlags(); | 848 | CheckFlags(); |
| 828 | src.operandReg = (u8)dest; | 849 | src.operandReg = (u8)dest; |
| @@ -836,36 +857,35 @@ void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bo | |||
| 836 | src.WriteRest(this); | 857 | src.WriteRest(this); |
| 837 | } | 858 | } |
| 838 | 859 | ||
| 839 | void XEmitter::MOVNTI(int bits, const OpArg& dest, X64Reg src) | 860 | void XEmitter::MOVNTI(int bits, const OpArg& dest, X64Reg src) { |
| 840 | { | ||
| 841 | if (bits <= 16) | 861 | if (bits <= 16) |
| 842 | ASSERT_MSG(0, "MOVNTI - bits<=16"); | 862 | ASSERT_MSG(0, "MOVNTI - bits<=16"); |
| 843 | WriteBitSearchType(bits, src, dest, 0xC3); | 863 | WriteBitSearchType(bits, src, dest, 0xC3); |
| 844 | } | 864 | } |
| 845 | 865 | ||
| 846 | void XEmitter::BSF(int bits, X64Reg dest, const OpArg& src) {WriteBitSearchType(bits,dest,src,0xBC);} // Bottom bit to top bit | 866 | 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 | 867 | WriteBitSearchType(bits, dest, src, 0xBC); |
| 868 | } // Bottom bit to top bit | ||
| 869 | void XEmitter::BSR(int bits, X64Reg dest, const OpArg& src) { | ||
| 870 | WriteBitSearchType(bits, dest, src, 0xBD); | ||
| 871 | } // Top bit to bottom bit | ||
| 848 | 872 | ||
| 849 | void XEmitter::TZCNT(int bits, X64Reg dest, const OpArg& src) | 873 | void XEmitter::TZCNT(int bits, X64Reg dest, const OpArg& src) { |
| 850 | { | ||
| 851 | CheckFlags(); | 874 | CheckFlags(); |
| 852 | if (!Common::GetCPUCaps().bmi1) | 875 | if (!Common::GetCPUCaps().bmi1) |
| 853 | ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer."); | 876 | ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer."); |
| 854 | WriteBitSearchType(bits, dest, src, 0xBC, true); | 877 | WriteBitSearchType(bits, dest, src, 0xBC, true); |
| 855 | } | 878 | } |
| 856 | void XEmitter::LZCNT(int bits, X64Reg dest, const OpArg& src) | 879 | void XEmitter::LZCNT(int bits, X64Reg dest, const OpArg& src) { |
| 857 | { | ||
| 858 | CheckFlags(); | 880 | CheckFlags(); |
| 859 | if (!Common::GetCPUCaps().lzcnt) | 881 | if (!Common::GetCPUCaps().lzcnt) |
| 860 | ASSERT_MSG(0, "Trying to use LZCNT on a system that doesn't support it. Bad programmer."); | 882 | ASSERT_MSG(0, "Trying to use LZCNT on a system that doesn't support it. Bad programmer."); |
| 861 | WriteBitSearchType(bits, dest, src, 0xBD, true); | 883 | WriteBitSearchType(bits, dest, src, 0xBD, true); |
| 862 | } | 884 | } |
| 863 | 885 | ||
| 864 | void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) | 886 | void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) { |
| 865 | { | ||
| 866 | ASSERT_MSG(!src.IsImm(), "MOVSX - Imm argument"); | 887 | ASSERT_MSG(!src.IsImm(), "MOVSX - Imm argument"); |
| 867 | if (dbits == sbits) | 888 | if (dbits == sbits) { |
| 868 | { | ||
| 869 | MOV(dbits, R(dest), src); | 889 | MOV(dbits, R(dest), src); |
| 870 | return; | 890 | return; |
| 871 | } | 891 | } |
| @@ -873,66 +893,49 @@ void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) | |||
| 873 | if (dbits == 16) | 893 | if (dbits == 16) |
| 874 | Write8(0x66); | 894 | Write8(0x66); |
| 875 | src.WriteRex(this, dbits, sbits); | 895 | src.WriteRex(this, dbits, sbits); |
| 876 | if (sbits == 8) | 896 | if (sbits == 8) { |
| 877 | { | ||
| 878 | Write8(0x0F); | 897 | Write8(0x0F); |
| 879 | Write8(0xBE); | 898 | Write8(0xBE); |
| 880 | } | 899 | } else if (sbits == 16) { |
| 881 | else if (sbits == 16) | ||
| 882 | { | ||
| 883 | Write8(0x0F); | 900 | Write8(0x0F); |
| 884 | Write8(0xBF); | 901 | Write8(0xBF); |
| 885 | } | 902 | } else if (sbits == 32 && dbits == 64) { |
| 886 | else if (sbits == 32 && dbits == 64) | ||
| 887 | { | ||
| 888 | Write8(0x63); | 903 | Write8(0x63); |
| 889 | } | 904 | } else { |
| 890 | else | ||
| 891 | { | ||
| 892 | Crash(); | 905 | Crash(); |
| 893 | } | 906 | } |
| 894 | src.WriteRest(this); | 907 | src.WriteRest(this); |
| 895 | } | 908 | } |
| 896 | 909 | ||
| 897 | void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src) | 910 | void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src) { |
| 898 | { | ||
| 899 | ASSERT_MSG(!src.IsImm(), "MOVZX - Imm argument"); | 911 | ASSERT_MSG(!src.IsImm(), "MOVZX - Imm argument"); |
| 900 | if (dbits == sbits) | 912 | if (dbits == sbits) { |
| 901 | { | ||
| 902 | MOV(dbits, R(dest), src); | 913 | MOV(dbits, R(dest), src); |
| 903 | return; | 914 | return; |
| 904 | } | 915 | } |
| 905 | src.operandReg = (u8)dest; | 916 | src.operandReg = (u8)dest; |
| 906 | if (dbits == 16) | 917 | if (dbits == 16) |
| 907 | Write8(0x66); | 918 | Write8(0x66); |
| 908 | //the 32bit result is automatically zero extended to 64bit | 919 | // the 32bit result is automatically zero extended to 64bit |
| 909 | src.WriteRex(this, dbits == 64 ? 32 : dbits, sbits); | 920 | src.WriteRex(this, dbits == 64 ? 32 : dbits, sbits); |
| 910 | if (sbits == 8) | 921 | if (sbits == 8) { |
| 911 | { | ||
| 912 | Write8(0x0F); | 922 | Write8(0x0F); |
| 913 | Write8(0xB6); | 923 | Write8(0xB6); |
| 914 | } | 924 | } else if (sbits == 16) { |
| 915 | else if (sbits == 16) | ||
| 916 | { | ||
| 917 | Write8(0x0F); | 925 | Write8(0x0F); |
| 918 | Write8(0xB7); | 926 | Write8(0xB7); |
| 919 | } | 927 | } else if (sbits == 32 && dbits == 64) { |
| 920 | else if (sbits == 32 && dbits == 64) | ||
| 921 | { | ||
| 922 | Write8(0x8B); | 928 | Write8(0x8B); |
| 923 | } | 929 | } else { |
| 924 | else | ||
| 925 | { | ||
| 926 | ASSERT_MSG(0, "MOVZX - Invalid size"); | 930 | ASSERT_MSG(0, "MOVZX - Invalid size"); |
| 927 | } | 931 | } |
| 928 | src.WriteRest(this); | 932 | src.WriteRest(this); |
| 929 | } | 933 | } |
| 930 | 934 | ||
| 931 | void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) | 935 | void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) { |
| 932 | { | 936 | ASSERT_MSG(Common::GetCPUCaps().movbe, |
| 933 | ASSERT_MSG(Common::GetCPUCaps().movbe, "Generating MOVBE on a system that does not support it."); | 937 | "Generating MOVBE on a system that does not support it."); |
| 934 | if (bits == 8) | 938 | if (bits == 8) { |
| 935 | { | ||
| 936 | MOV(bits, dest, src); | 939 | MOV(bits, dest, src); |
| 937 | return; | 940 | return; |
| 938 | } | 941 | } |
| @@ -940,71 +943,60 @@ void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) | |||
| 940 | if (bits == 16) | 943 | if (bits == 16) |
| 941 | Write8(0x66); | 944 | Write8(0x66); |
| 942 | 945 | ||
| 943 | if (dest.IsSimpleReg()) | 946 | if (dest.IsSimpleReg()) { |
| 944 | { | ||
| 945 | ASSERT_MSG(!src.IsSimpleReg() && !src.IsImm(), "MOVBE: Loading from !mem"); | 947 | ASSERT_MSG(!src.IsSimpleReg() && !src.IsImm(), "MOVBE: Loading from !mem"); |
| 946 | src.WriteRex(this, bits, bits, dest.GetSimpleReg()); | 948 | src.WriteRex(this, bits, bits, dest.GetSimpleReg()); |
| 947 | Write8(0x0F); Write8(0x38); Write8(0xF0); | 949 | Write8(0x0F); |
| 950 | Write8(0x38); | ||
| 951 | Write8(0xF0); | ||
| 948 | src.WriteRest(this, 0, dest.GetSimpleReg()); | 952 | src.WriteRest(this, 0, dest.GetSimpleReg()); |
| 949 | } | 953 | } else if (src.IsSimpleReg()) { |
| 950 | else if (src.IsSimpleReg()) | ||
| 951 | { | ||
| 952 | ASSERT_MSG(!dest.IsSimpleReg() && !dest.IsImm(), "MOVBE: Storing to !mem"); | 954 | ASSERT_MSG(!dest.IsSimpleReg() && !dest.IsImm(), "MOVBE: Storing to !mem"); |
| 953 | dest.WriteRex(this, bits, bits, src.GetSimpleReg()); | 955 | dest.WriteRex(this, bits, bits, src.GetSimpleReg()); |
| 954 | Write8(0x0F); Write8(0x38); Write8(0xF1); | 956 | Write8(0x0F); |
| 957 | Write8(0x38); | ||
| 958 | Write8(0xF1); | ||
| 955 | dest.WriteRest(this, 0, src.GetSimpleReg()); | 959 | dest.WriteRest(this, 0, src.GetSimpleReg()); |
| 956 | } | 960 | } else { |
| 957 | else | ||
| 958 | { | ||
| 959 | ASSERT_MSG(0, "MOVBE: Not loading or storing to mem"); | 961 | ASSERT_MSG(0, "MOVBE: Not loading or storing to mem"); |
| 960 | } | 962 | } |
| 961 | } | 963 | } |
| 962 | 964 | ||
| 963 | 965 | 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"); | 966 | ASSERT_MSG(!src.IsImm(), "LEA - Imm argument"); |
| 967 | src.operandReg = (u8)dest; | 967 | src.operandReg = (u8)dest; |
| 968 | if (bits == 16) | 968 | if (bits == 16) |
| 969 | Write8(0x66); //TODO: performance warning | 969 | Write8(0x66); // TODO: performance warning |
| 970 | src.WriteRex(this, bits, bits); | 970 | src.WriteRex(this, bits, bits); |
| 971 | Write8(0x8D); | 971 | Write8(0x8D); |
| 972 | src.WriteRest(this, 0, INVALID_REG, bits == 64); | 972 | src.WriteRest(this, 0, INVALID_REG, bits == 64); |
| 973 | } | 973 | } |
| 974 | 974 | ||
| 975 | //shift can be either imm8 or cl | 975 | // shift can be either imm8 or cl |
| 976 | void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext) | 976 | void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext) { |
| 977 | { | ||
| 978 | CheckFlags(); | 977 | CheckFlags(); |
| 979 | bool writeImm = false; | 978 | bool writeImm = false; |
| 980 | if (dest.IsImm()) | 979 | if (dest.IsImm()) { |
| 981 | { | ||
| 982 | ASSERT_MSG(0, "WriteShift - can't shift imms"); | 980 | ASSERT_MSG(0, "WriteShift - can't shift imms"); |
| 983 | } | 981 | } |
| 984 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) | 982 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || |
| 985 | { | 983 | (shift.IsImm() && shift.GetImmBits() != 8)) { |
| 986 | ASSERT_MSG(0, "WriteShift - illegal argument"); | 984 | ASSERT_MSG(0, "WriteShift - illegal argument"); |
| 987 | } | 985 | } |
| 988 | dest.operandReg = ext; | 986 | dest.operandReg = ext; |
| 989 | if (bits == 16) | 987 | if (bits == 16) |
| 990 | Write8(0x66); | 988 | Write8(0x66); |
| 991 | dest.WriteRex(this, bits, bits, 0); | 989 | dest.WriteRex(this, bits, bits, 0); |
| 992 | if (shift.GetImmBits() == 8) | 990 | if (shift.GetImmBits() == 8) { |
| 993 | { | 991 | // ok an imm |
| 994 | //ok an imm | ||
| 995 | u8 imm = (u8)shift.offset; | 992 | u8 imm = (u8)shift.offset; |
| 996 | if (imm == 1) | 993 | if (imm == 1) { |
| 997 | { | ||
| 998 | Write8(bits == 8 ? 0xD0 : 0xD1); | 994 | Write8(bits == 8 ? 0xD0 : 0xD1); |
| 999 | } | 995 | } else { |
| 1000 | else | ||
| 1001 | { | ||
| 1002 | writeImm = true; | 996 | writeImm = true; |
| 1003 | Write8(bits == 8 ? 0xC0 : 0xC1); | 997 | Write8(bits == 8 ? 0xC0 : 0xC1); |
| 1004 | } | 998 | } |
| 1005 | } | 999 | } else { |
| 1006 | else | ||
| 1007 | { | ||
| 1008 | Write8(bits == 8 ? 0xD2 : 0xD3); | 1000 | Write8(bits == 8 ? 0xD2 : 0xD3); |
| 1009 | } | 1001 | } |
| 1010 | dest.WriteRest(this, writeImm ? 1 : 0); | 1002 | dest.WriteRest(this, writeImm ? 1 : 0); |
| @@ -1014,116 +1006,125 @@ void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext) | |||
| 1014 | 1006 | ||
| 1015 | // large rotates and shift are slower on intel than amd | 1007 | // large rotates and shift are slower on intel than amd |
| 1016 | // intel likes to rotate by 1, and the op is smaller too | 1008 | // 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);} | 1009 | 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);} | 1010 | WriteShift(bits, dest, shift, 0); |
| 1019 | void XEmitter::RCL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 2);} | 1011 | } |
| 1020 | void XEmitter::RCR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 3);} | 1012 | 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);} | 1013 | WriteShift(bits, dest, shift, 1); |
| 1022 | void XEmitter::SHR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 5);} | 1014 | } |
| 1023 | void XEmitter::SAR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 7);} | 1015 | void XEmitter::RCL(int bits, const OpArg& dest, const OpArg& shift) { |
| 1016 | WriteShift(bits, dest, shift, 2); | ||
| 1017 | } | ||
| 1018 | void XEmitter::RCR(int bits, const OpArg& dest, const OpArg& shift) { | ||
| 1019 | WriteShift(bits, dest, shift, 3); | ||
| 1020 | } | ||
| 1021 | void XEmitter::SHL(int bits, const OpArg& dest, const OpArg& shift) { | ||
| 1022 | WriteShift(bits, dest, shift, 4); | ||
| 1023 | } | ||
| 1024 | void XEmitter::SHR(int bits, const OpArg& dest, const OpArg& shift) { | ||
| 1025 | WriteShift(bits, dest, shift, 5); | ||
| 1026 | } | ||
| 1027 | void XEmitter::SAR(int bits, const OpArg& dest, const OpArg& shift) { | ||
| 1028 | WriteShift(bits, dest, shift, 7); | ||
| 1029 | } | ||
| 1024 | 1030 | ||
| 1025 | // index can be either imm8 or register, don't use memory destination because it's slow | 1031 | // 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) | 1032 | void XEmitter::WriteBitTest(int bits, const OpArg& dest, const OpArg& index, int ext) { |
| 1027 | { | ||
| 1028 | CheckFlags(); | 1033 | CheckFlags(); |
| 1029 | if (dest.IsImm()) | 1034 | if (dest.IsImm()) { |
| 1030 | { | ||
| 1031 | ASSERT_MSG(0, "WriteBitTest - can't test imms"); | 1035 | ASSERT_MSG(0, "WriteBitTest - can't test imms"); |
| 1032 | } | 1036 | } |
| 1033 | if ((index.IsImm() && index.GetImmBits() != 8)) | 1037 | if ((index.IsImm() && index.GetImmBits() != 8)) { |
| 1034 | { | ||
| 1035 | ASSERT_MSG(0, "WriteBitTest - illegal argument"); | 1038 | ASSERT_MSG(0, "WriteBitTest - illegal argument"); |
| 1036 | } | 1039 | } |
| 1037 | if (bits == 16) | 1040 | if (bits == 16) |
| 1038 | Write8(0x66); | 1041 | Write8(0x66); |
| 1039 | if (index.IsImm()) | 1042 | if (index.IsImm()) { |
| 1040 | { | ||
| 1041 | dest.WriteRex(this, bits, bits); | 1043 | dest.WriteRex(this, bits, bits); |
| 1042 | Write8(0x0F); Write8(0xBA); | 1044 | Write8(0x0F); |
| 1045 | Write8(0xBA); | ||
| 1043 | dest.WriteRest(this, 1, (X64Reg)ext); | 1046 | dest.WriteRest(this, 1, (X64Reg)ext); |
| 1044 | Write8((u8)index.offset); | 1047 | Write8((u8)index.offset); |
| 1045 | } | 1048 | } else { |
| 1046 | else | ||
| 1047 | { | ||
| 1048 | X64Reg operand = index.GetSimpleReg(); | 1049 | X64Reg operand = index.GetSimpleReg(); |
| 1049 | dest.WriteRex(this, bits, bits, operand); | 1050 | dest.WriteRex(this, bits, bits, operand); |
| 1050 | Write8(0x0F); Write8(0x83 + 8*ext); | 1051 | Write8(0x0F); |
| 1052 | Write8(0x83 + 8 * ext); | ||
| 1051 | dest.WriteRest(this, 1, operand); | 1053 | dest.WriteRest(this, 1, operand); |
| 1052 | } | 1054 | } |
| 1053 | } | 1055 | } |
| 1054 | 1056 | ||
| 1055 | void XEmitter::BT(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 4);} | 1057 | 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);} | 1058 | WriteBitTest(bits, dest, index, 4); |
| 1057 | void XEmitter::BTR(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 6);} | 1059 | } |
| 1058 | void XEmitter::BTC(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 7);} | 1060 | void XEmitter::BTS(int bits, const OpArg& dest, const OpArg& index) { |
| 1061 | WriteBitTest(bits, dest, index, 5); | ||
| 1062 | } | ||
| 1063 | void XEmitter::BTR(int bits, const OpArg& dest, const OpArg& index) { | ||
| 1064 | WriteBitTest(bits, dest, index, 6); | ||
| 1065 | } | ||
| 1066 | void XEmitter::BTC(int bits, const OpArg& dest, const OpArg& index) { | ||
| 1067 | WriteBitTest(bits, dest, index, 7); | ||
| 1068 | } | ||
| 1059 | 1069 | ||
| 1060 | //shift can be either imm8 or cl | 1070 | // shift can be either imm8 or cl |
| 1061 | void XEmitter::SHRD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) | 1071 | void XEmitter::SHRD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) { |
| 1062 | { | ||
| 1063 | CheckFlags(); | 1072 | CheckFlags(); |
| 1064 | if (dest.IsImm()) | 1073 | if (dest.IsImm()) { |
| 1065 | { | ||
| 1066 | ASSERT_MSG(0, "SHRD - can't use imms as destination"); | 1074 | ASSERT_MSG(0, "SHRD - can't use imms as destination"); |
| 1067 | } | 1075 | } |
| 1068 | if (!src.IsSimpleReg()) | 1076 | if (!src.IsSimpleReg()) { |
| 1069 | { | ||
| 1070 | ASSERT_MSG(0, "SHRD - must use simple register as source"); | 1077 | ASSERT_MSG(0, "SHRD - must use simple register as source"); |
| 1071 | } | 1078 | } |
| 1072 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) | 1079 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || |
| 1073 | { | 1080 | (shift.IsImm() && shift.GetImmBits() != 8)) { |
| 1074 | ASSERT_MSG(0, "SHRD - illegal shift"); | 1081 | ASSERT_MSG(0, "SHRD - illegal shift"); |
| 1075 | } | 1082 | } |
| 1076 | if (bits == 16) | 1083 | if (bits == 16) |
| 1077 | Write8(0x66); | 1084 | Write8(0x66); |
| 1078 | X64Reg operand = src.GetSimpleReg(); | 1085 | X64Reg operand = src.GetSimpleReg(); |
| 1079 | dest.WriteRex(this, bits, bits, operand); | 1086 | dest.WriteRex(this, bits, bits, operand); |
| 1080 | if (shift.GetImmBits() == 8) | 1087 | if (shift.GetImmBits() == 8) { |
| 1081 | { | 1088 | Write8(0x0F); |
| 1082 | Write8(0x0F); Write8(0xAC); | 1089 | Write8(0xAC); |
| 1083 | dest.WriteRest(this, 1, operand); | 1090 | dest.WriteRest(this, 1, operand); |
| 1084 | Write8((u8)shift.offset); | 1091 | Write8((u8)shift.offset); |
| 1085 | } | 1092 | } else { |
| 1086 | else | 1093 | Write8(0x0F); |
| 1087 | { | 1094 | Write8(0xAD); |
| 1088 | Write8(0x0F); Write8(0xAD); | ||
| 1089 | dest.WriteRest(this, 0, operand); | 1095 | dest.WriteRest(this, 0, operand); |
| 1090 | } | 1096 | } |
| 1091 | } | 1097 | } |
| 1092 | 1098 | ||
| 1093 | void XEmitter::SHLD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) | 1099 | void XEmitter::SHLD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) { |
| 1094 | { | ||
| 1095 | CheckFlags(); | 1100 | CheckFlags(); |
| 1096 | if (dest.IsImm()) | 1101 | if (dest.IsImm()) { |
| 1097 | { | ||
| 1098 | ASSERT_MSG(0, "SHLD - can't use imms as destination"); | 1102 | ASSERT_MSG(0, "SHLD - can't use imms as destination"); |
| 1099 | } | 1103 | } |
| 1100 | if (!src.IsSimpleReg()) | 1104 | if (!src.IsSimpleReg()) { |
| 1101 | { | ||
| 1102 | ASSERT_MSG(0, "SHLD - must use simple register as source"); | 1105 | ASSERT_MSG(0, "SHLD - must use simple register as source"); |
| 1103 | } | 1106 | } |
| 1104 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) | 1107 | if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || |
| 1105 | { | 1108 | (shift.IsImm() && shift.GetImmBits() != 8)) { |
| 1106 | ASSERT_MSG(0, "SHLD - illegal shift"); | 1109 | ASSERT_MSG(0, "SHLD - illegal shift"); |
| 1107 | } | 1110 | } |
| 1108 | if (bits == 16) | 1111 | if (bits == 16) |
| 1109 | Write8(0x66); | 1112 | Write8(0x66); |
| 1110 | X64Reg operand = src.GetSimpleReg(); | 1113 | X64Reg operand = src.GetSimpleReg(); |
| 1111 | dest.WriteRex(this, bits, bits, operand); | 1114 | dest.WriteRex(this, bits, bits, operand); |
| 1112 | if (shift.GetImmBits() == 8) | 1115 | if (shift.GetImmBits() == 8) { |
| 1113 | { | 1116 | Write8(0x0F); |
| 1114 | Write8(0x0F); Write8(0xA4); | 1117 | Write8(0xA4); |
| 1115 | dest.WriteRest(this, 1, operand); | 1118 | dest.WriteRest(this, 1, operand); |
| 1116 | Write8((u8)shift.offset); | 1119 | Write8((u8)shift.offset); |
| 1117 | } | 1120 | } else { |
| 1118 | else | 1121 | Write8(0x0F); |
| 1119 | { | 1122 | Write8(0xA5); |
| 1120 | Write8(0x0F); Write8(0xA5); | ||
| 1121 | dest.WriteRest(this, 0, operand); | 1123 | dest.WriteRest(this, 0, operand); |
| 1122 | } | 1124 | } |
| 1123 | } | 1125 | } |
| 1124 | 1126 | ||
| 1125 | void OpArg::WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg _operandReg, int bits) | 1127 | void OpArg::WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg _operandReg, int bits) { |
| 1126 | { | ||
| 1127 | if (bits == 16) | 1128 | if (bits == 16) |
| 1128 | emit->Write8(0x66); | 1129 | emit->Write8(0x66); |
| 1129 | 1130 | ||
| @@ -1133,12 +1134,11 @@ void OpArg::WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg _operandReg, int bit | |||
| 1133 | WriteRest(emit); | 1134 | WriteRest(emit); |
| 1134 | } | 1135 | } |
| 1135 | 1136 | ||
| 1136 | //operand can either be immediate or register | 1137 | // operand can either be immediate or register |
| 1137 | void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& operand, int bits) const | 1138 | void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, |
| 1138 | { | 1139 | int bits) const { |
| 1139 | X64Reg _operandReg; | 1140 | X64Reg _operandReg; |
| 1140 | if (IsImm()) | 1141 | if (IsImm()) { |
| 1141 | { | ||
| 1142 | ASSERT_MSG(0, "WriteNormalOp - Imm argument, wrong order"); | 1142 | ASSERT_MSG(0, "WriteNormalOp - Imm argument, wrong order"); |
| 1143 | } | 1143 | } |
| 1144 | 1144 | ||
| @@ -1147,27 +1147,22 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o | |||
| 1147 | 1147 | ||
| 1148 | int immToWrite = 0; | 1148 | int immToWrite = 0; |
| 1149 | 1149 | ||
| 1150 | if (operand.IsImm()) | 1150 | if (operand.IsImm()) { |
| 1151 | { | ||
| 1152 | WriteRex(emit, bits, bits); | 1151 | WriteRex(emit, bits, bits); |
| 1153 | 1152 | ||
| 1154 | if (!toRM) | 1153 | if (!toRM) { |
| 1155 | { | ||
| 1156 | ASSERT_MSG(0, "WriteNormalOp - Writing to Imm (!toRM)"); | 1154 | ASSERT_MSG(0, "WriteNormalOp - Writing to Imm (!toRM)"); |
| 1157 | } | 1155 | } |
| 1158 | 1156 | ||
| 1159 | if (operand.scale == SCALE_IMM8 && bits == 8) | 1157 | if (operand.scale == SCALE_IMM8 && bits == 8) { |
| 1160 | { | ||
| 1161 | // op al, imm8 | 1158 | // op al, imm8 |
| 1162 | if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC) | 1159 | if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC) { |
| 1163 | { | ||
| 1164 | emit->Write8(normalops[op].eaximm8); | 1160 | emit->Write8(normalops[op].eaximm8); |
| 1165 | emit->Write8((u8)operand.offset); | 1161 | emit->Write8((u8)operand.offset); |
| 1166 | return; | 1162 | return; |
| 1167 | } | 1163 | } |
| 1168 | // mov reg, imm8 | 1164 | // mov reg, imm8 |
| 1169 | if (!scale && op == nrmMOV) | 1165 | if (!scale && op == nrmMOV) { |
| 1170 | { | ||
| 1171 | emit->Write8(0xB0 + (offsetOrBaseReg & 7)); | 1166 | emit->Write8(0xB0 + (offsetOrBaseReg & 7)); |
| 1172 | emit->Write8((u8)operand.offset); | 1167 | emit->Write8((u8)operand.offset); |
| 1173 | return; | 1168 | return; |
| @@ -1175,26 +1170,20 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o | |||
| 1175 | // op r/m8, imm8 | 1170 | // op r/m8, imm8 |
| 1176 | emit->Write8(normalops[op].imm8); | 1171 | emit->Write8(normalops[op].imm8); |
| 1177 | immToWrite = 8; | 1172 | immToWrite = 8; |
| 1178 | } | 1173 | } else if ((operand.scale == SCALE_IMM16 && bits == 16) || |
| 1179 | else if ((operand.scale == SCALE_IMM16 && bits == 16) || | 1174 | (operand.scale == SCALE_IMM32 && bits == 32) || |
| 1180 | (operand.scale == SCALE_IMM32 && bits == 32) || | 1175 | (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 | 1176 | // Try to save immediate size if we can, but first check to see |
| 1184 | // if the instruction supports simm8. | 1177 | // if the instruction supports simm8. |
| 1185 | // op r/m, imm8 | 1178 | // op r/m, imm8 |
| 1186 | if (normalops[op].simm8 != 0xCC && | 1179 | if (normalops[op].simm8 != 0xCC && |
| 1187 | ((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) || | 1180 | ((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) || |
| 1188 | (operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset))) | 1181 | (operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset))) { |
| 1189 | { | ||
| 1190 | emit->Write8(normalops[op].simm8); | 1182 | emit->Write8(normalops[op].simm8); |
| 1191 | immToWrite = 8; | 1183 | immToWrite = 8; |
| 1192 | } | 1184 | } else { |
| 1193 | else | ||
| 1194 | { | ||
| 1195 | // mov reg, imm | 1185 | // mov reg, imm |
| 1196 | if (!scale && op == nrmMOV && bits != 64) | 1186 | if (!scale && op == nrmMOV && bits != 64) { |
| 1197 | { | ||
| 1198 | emit->Write8(0xB8 + (offsetOrBaseReg & 7)); | 1187 | emit->Write8(0xB8 + (offsetOrBaseReg & 7)); |
| 1199 | if (bits == 16) | 1188 | if (bits == 16) |
| 1200 | emit->Write16((u16)operand.offset); | 1189 | emit->Write16((u16)operand.offset); |
| @@ -1203,8 +1192,7 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o | |||
| 1203 | return; | 1192 | return; |
| 1204 | } | 1193 | } |
| 1205 | // op eax, imm | 1194 | // op eax, imm |
| 1206 | if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC) | 1195 | if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC) { |
| 1207 | { | ||
| 1208 | emit->Write8(normalops[op].eaximm32); | 1196 | emit->Write8(normalops[op].eaximm32); |
| 1209 | if (bits == 16) | 1197 | if (bits == 16) |
| 1210 | emit->Write16((u16)operand.offset); | 1198 | emit->Write16((u16)operand.offset); |
| @@ -1216,54 +1204,41 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o | |||
| 1216 | emit->Write8(normalops[op].imm32); | 1204 | emit->Write8(normalops[op].imm32); |
| 1217 | immToWrite = bits == 16 ? 16 : 32; | 1205 | immToWrite = bits == 16 ? 16 : 32; |
| 1218 | } | 1206 | } |
| 1219 | } | 1207 | } else if ((operand.scale == SCALE_IMM8 && bits == 16) || |
| 1220 | else if ((operand.scale == SCALE_IMM8 && bits == 16) || | 1208 | (operand.scale == SCALE_IMM8 && bits == 32) || |
| 1221 | (operand.scale == SCALE_IMM8 && bits == 32) || | 1209 | (operand.scale == SCALE_IMM8 && bits == 64)) { |
| 1222 | (operand.scale == SCALE_IMM8 && bits == 64)) | ||
| 1223 | { | ||
| 1224 | // op r/m, imm8 | 1210 | // op r/m, imm8 |
| 1225 | emit->Write8(normalops[op].simm8); | 1211 | emit->Write8(normalops[op].simm8); |
| 1226 | immToWrite = 8; | 1212 | immToWrite = 8; |
| 1227 | } | 1213 | } else if (operand.scale == SCALE_IMM64 && bits == 64) { |
| 1228 | else if (operand.scale == SCALE_IMM64 && bits == 64) | 1214 | if (scale) { |
| 1229 | { | ||
| 1230 | if (scale) | ||
| 1231 | { | ||
| 1232 | ASSERT_MSG(0, "WriteNormalOp - MOV with 64-bit imm requres register destination"); | 1215 | ASSERT_MSG(0, "WriteNormalOp - MOV with 64-bit imm requres register destination"); |
| 1233 | } | 1216 | } |
| 1234 | // mov reg64, imm64 | 1217 | // mov reg64, imm64 |
| 1235 | else if (op == nrmMOV) | 1218 | else if (op == nrmMOV) { |
| 1236 | { | ||
| 1237 | emit->Write8(0xB8 + (offsetOrBaseReg & 7)); | 1219 | emit->Write8(0xB8 + (offsetOrBaseReg & 7)); |
| 1238 | emit->Write64((u64)operand.offset); | 1220 | emit->Write64((u64)operand.offset); |
| 1239 | return; | 1221 | return; |
| 1240 | } | 1222 | } |
| 1241 | ASSERT_MSG(0, "WriteNormalOp - Only MOV can take 64-bit imm"); | 1223 | ASSERT_MSG(0, "WriteNormalOp - Only MOV can take 64-bit imm"); |
| 1242 | } | 1224 | } else { |
| 1243 | else | ||
| 1244 | { | ||
| 1245 | ASSERT_MSG(0, "WriteNormalOp - Unhandled case"); | 1225 | ASSERT_MSG(0, "WriteNormalOp - Unhandled case"); |
| 1246 | } | 1226 | } |
| 1247 | _operandReg = (X64Reg)normalops[op].ext; //pass extension in REG of ModRM | 1227 | _operandReg = (X64Reg)normalops[op].ext; // pass extension in REG of ModRM |
| 1248 | } | 1228 | } else { |
| 1249 | else | ||
| 1250 | { | ||
| 1251 | _operandReg = (X64Reg)operand.offsetOrBaseReg; | 1229 | _operandReg = (X64Reg)operand.offsetOrBaseReg; |
| 1252 | WriteRex(emit, bits, bits, _operandReg); | 1230 | WriteRex(emit, bits, bits, _operandReg); |
| 1253 | // op r/m, reg | 1231 | // op r/m, reg |
| 1254 | if (toRM) | 1232 | if (toRM) { |
| 1255 | { | ||
| 1256 | emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32); | 1233 | emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32); |
| 1257 | } | 1234 | } |
| 1258 | // op reg, r/m | 1235 | // op reg, r/m |
| 1259 | else | 1236 | else { |
| 1260 | { | ||
| 1261 | emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32); | 1237 | emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32); |
| 1262 | } | 1238 | } |
| 1263 | } | 1239 | } |
| 1264 | WriteRest(emit, immToWrite >> 3, _operandReg); | 1240 | WriteRest(emit, immToWrite >> 3, _operandReg); |
| 1265 | switch (immToWrite) | 1241 | switch (immToWrite) { |
| 1266 | { | ||
| 1267 | case 0: | 1242 | case 0: |
| 1268 | break; | 1243 | break; |
| 1269 | case 8: | 1244 | case 8: |
| @@ -1280,66 +1255,84 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o | |||
| 1280 | } | 1255 | } |
| 1281 | } | 1256 | } |
| 1282 | 1257 | ||
| 1283 | void XEmitter::WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2) | 1258 | void XEmitter::WriteNormalOp(XEmitter* emit, int bits, NormalOp op, const OpArg& a1, |
| 1284 | { | 1259 | const OpArg& a2) { |
| 1285 | if (a1.IsImm()) | 1260 | if (a1.IsImm()) { |
| 1286 | { | 1261 | // Booh! Can't write to an imm |
| 1287 | //Booh! Can't write to an imm | ||
| 1288 | ASSERT_MSG(0, "WriteNormalOp - a1 cannot be imm"); | 1262 | ASSERT_MSG(0, "WriteNormalOp - a1 cannot be imm"); |
| 1289 | return; | 1263 | return; |
| 1290 | } | 1264 | } |
| 1291 | if (a2.IsImm()) | 1265 | if (a2.IsImm()) { |
| 1292 | { | ||
| 1293 | a1.WriteNormalOp(emit, true, op, a2, bits); | 1266 | a1.WriteNormalOp(emit, true, op, a2, bits); |
| 1294 | } | 1267 | } else { |
| 1295 | else | 1268 | if (a1.IsSimpleReg()) { |
| 1296 | { | ||
| 1297 | if (a1.IsSimpleReg()) | ||
| 1298 | { | ||
| 1299 | a2.WriteNormalOp(emit, false, op, a1, bits); | 1269 | a2.WriteNormalOp(emit, false, op, a1, bits); |
| 1300 | } | 1270 | } else { |
| 1301 | else | 1271 | ASSERT_MSG(a2.IsSimpleReg() || a2.IsImm(), |
| 1302 | { | 1272 | "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); | 1273 | a1.WriteNormalOp(emit, true, op, a2, bits); |
| 1305 | } | 1274 | } |
| 1306 | } | 1275 | } |
| 1307 | } | 1276 | } |
| 1308 | 1277 | ||
| 1309 | void XEmitter::ADD (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmADD, a1, a2);} | 1278 | 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);} | 1279 | CheckFlags(); |
| 1311 | void XEmitter::SUB (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmSUB, a1, a2);} | 1280 | 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);} | 1281 | } |
| 1313 | void XEmitter::AND (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmAND, a1, a2);} | 1282 | 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);} | 1283 | CheckFlags(); |
| 1315 | void XEmitter::XOR (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmXOR, a1, a2);} | 1284 | WriteNormalOp(this, bits, nrmADC, a1, a2); |
| 1316 | void XEmitter::MOV (int bits, const OpArg& a1, const OpArg& a2) | 1285 | } |
| 1317 | { | 1286 | void XEmitter::SUB(int bits, const OpArg& a1, const OpArg& a2) { |
| 1287 | CheckFlags(); | ||
| 1288 | WriteNormalOp(this, bits, nrmSUB, a1, a2); | ||
| 1289 | } | ||
| 1290 | void XEmitter::SBB(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1291 | CheckFlags(); | ||
| 1292 | WriteNormalOp(this, bits, nrmSBB, a1, a2); | ||
| 1293 | } | ||
| 1294 | void XEmitter::AND(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1295 | CheckFlags(); | ||
| 1296 | WriteNormalOp(this, bits, nrmAND, a1, a2); | ||
| 1297 | } | ||
| 1298 | void XEmitter::OR(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1299 | CheckFlags(); | ||
| 1300 | WriteNormalOp(this, bits, nrmOR, a1, a2); | ||
| 1301 | } | ||
| 1302 | void XEmitter::XOR(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1303 | CheckFlags(); | ||
| 1304 | WriteNormalOp(this, bits, nrmXOR, a1, a2); | ||
| 1305 | } | ||
| 1306 | void XEmitter::MOV(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1318 | if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) | 1307 | if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) |
| 1319 | LOG_ERROR(Common, "Redundant MOV @ %p - bug in JIT?", code); | 1308 | LOG_ERROR(Common, "Redundant MOV @ %p - bug in JIT?", code); |
| 1320 | WriteNormalOp(this, bits, nrmMOV, a1, a2); | 1309 | WriteNormalOp(this, bits, nrmMOV, a1, a2); |
| 1321 | } | 1310 | } |
| 1322 | void XEmitter::TEST(int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmTEST, a1, a2);} | 1311 | 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);} | 1312 | CheckFlags(); |
| 1324 | void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) {WriteNormalOp(this, bits, nrmXCHG, a1, a2);} | 1313 | WriteNormalOp(this, bits, nrmTEST, a1, a2); |
| 1314 | } | ||
| 1315 | void XEmitter::CMP(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1316 | CheckFlags(); | ||
| 1317 | WriteNormalOp(this, bits, nrmCMP, a1, a2); | ||
| 1318 | } | ||
| 1319 | void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) { | ||
| 1320 | WriteNormalOp(this, bits, nrmXCHG, a1, a2); | ||
| 1321 | } | ||
| 1325 | 1322 | ||
| 1326 | void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2) | 1323 | void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2) { |
| 1327 | { | ||
| 1328 | CheckFlags(); | 1324 | CheckFlags(); |
| 1329 | if (bits == 8) | 1325 | if (bits == 8) { |
| 1330 | { | ||
| 1331 | ASSERT_MSG(0, "IMUL - illegal bit size!"); | 1326 | ASSERT_MSG(0, "IMUL - illegal bit size!"); |
| 1332 | return; | 1327 | return; |
| 1333 | } | 1328 | } |
| 1334 | 1329 | ||
| 1335 | if (a1.IsImm()) | 1330 | if (a1.IsImm()) { |
| 1336 | { | ||
| 1337 | ASSERT_MSG(0, "IMUL - second arg cannot be imm!"); | 1331 | ASSERT_MSG(0, "IMUL - second arg cannot be imm!"); |
| 1338 | return; | 1332 | return; |
| 1339 | } | 1333 | } |
| 1340 | 1334 | ||
| 1341 | if (!a2.IsImm()) | 1335 | if (!a2.IsImm()) { |
| 1342 | { | ||
| 1343 | ASSERT_MSG(0, "IMUL - third arg must be imm!"); | 1336 | ASSERT_MSG(0, "IMUL - third arg must be imm!"); |
| 1344 | return; | 1337 | return; |
| 1345 | } | 1338 | } |
| @@ -1348,46 +1341,34 @@ void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2) | |||
| 1348 | Write8(0x66); | 1341 | Write8(0x66); |
| 1349 | a1.WriteRex(this, bits, bits, regOp); | 1342 | a1.WriteRex(this, bits, bits, regOp); |
| 1350 | 1343 | ||
| 1351 | if (a2.GetImmBits() == 8 || | 1344 | if (a2.GetImmBits() == 8 || (a2.GetImmBits() == 16 && (s8)a2.offset == (s16)a2.offset) || |
| 1352 | (a2.GetImmBits() == 16 && (s8)a2.offset == (s16)a2.offset) || | 1345 | (a2.GetImmBits() == 32 && (s8)a2.offset == (s32)a2.offset)) { |
| 1353 | (a2.GetImmBits() == 32 && (s8)a2.offset == (s32)a2.offset)) | ||
| 1354 | { | ||
| 1355 | Write8(0x6B); | 1346 | Write8(0x6B); |
| 1356 | a1.WriteRest(this, 1, regOp); | 1347 | a1.WriteRest(this, 1, regOp); |
| 1357 | Write8((u8)a2.offset); | 1348 | Write8((u8)a2.offset); |
| 1358 | } | 1349 | } else { |
| 1359 | else | ||
| 1360 | { | ||
| 1361 | Write8(0x69); | 1350 | Write8(0x69); |
| 1362 | if (a2.GetImmBits() == 16 && bits == 16) | 1351 | if (a2.GetImmBits() == 16 && bits == 16) { |
| 1363 | { | ||
| 1364 | a1.WriteRest(this, 2, regOp); | 1352 | a1.WriteRest(this, 2, regOp); |
| 1365 | Write16((u16)a2.offset); | 1353 | Write16((u16)a2.offset); |
| 1366 | } | 1354 | } 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); | 1355 | a1.WriteRest(this, 4, regOp); |
| 1370 | Write32((u32)a2.offset); | 1356 | Write32((u32)a2.offset); |
| 1371 | } | 1357 | } else { |
| 1372 | else | ||
| 1373 | { | ||
| 1374 | ASSERT_MSG(0, "IMUL - unhandled case!"); | 1358 | ASSERT_MSG(0, "IMUL - unhandled case!"); |
| 1375 | } | 1359 | } |
| 1376 | } | 1360 | } |
| 1377 | } | 1361 | } |
| 1378 | 1362 | ||
| 1379 | void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a) | 1363 | void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a) { |
| 1380 | { | ||
| 1381 | CheckFlags(); | 1364 | CheckFlags(); |
| 1382 | if (bits == 8) | 1365 | if (bits == 8) { |
| 1383 | { | ||
| 1384 | ASSERT_MSG(0, "IMUL - illegal bit size!"); | 1366 | ASSERT_MSG(0, "IMUL - illegal bit size!"); |
| 1385 | return; | 1367 | return; |
| 1386 | } | 1368 | } |
| 1387 | 1369 | ||
| 1388 | if (a.IsImm()) | 1370 | if (a.IsImm()) { |
| 1389 | { | 1371 | IMUL(bits, regOp, R(regOp), a); |
| 1390 | IMUL(bits, regOp, R(regOp), a) ; | ||
| 1391 | return; | 1372 | return; |
| 1392 | } | 1373 | } |
| 1393 | 1374 | ||
| @@ -1399,9 +1380,7 @@ void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a) | |||
| 1399 | a.WriteRest(this, 0, regOp); | 1380 | a.WriteRest(this, 0, regOp); |
| 1400 | } | 1381 | } |
| 1401 | 1382 | ||
| 1402 | 1383 | 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) | 1384 | if (opPrefix) |
| 1406 | Write8(opPrefix); | 1385 | Write8(opPrefix); |
| 1407 | arg.operandReg = regOp; | 1386 | arg.operandReg = regOp; |
| @@ -1413,13 +1392,11 @@ void XEmitter::WriteSSEOp(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extr | |||
| 1413 | arg.WriteRest(this, extrabytes); | 1392 | arg.WriteRest(this, extrabytes); |
| 1414 | } | 1393 | } |
| 1415 | 1394 | ||
| 1416 | void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) | 1395 | void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) { |
| 1417 | { | ||
| 1418 | WriteAVXOp(opPrefix, op, regOp, INVALID_REG, arg, extrabytes); | 1396 | WriteAVXOp(opPrefix, op, regOp, INVALID_REG, arg, extrabytes); |
| 1419 | } | 1397 | } |
| 1420 | 1398 | ||
| 1421 | static int GetVEXmmmmm(u16 op) | 1399 | static int GetVEXmmmmm(u16 op) { |
| 1422 | { | ||
| 1423 | // Currently, only 0x38 and 0x3A are used as secondary escape byte. | 1400 | // Currently, only 0x38 and 0x3A are used as secondary escape byte. |
| 1424 | if ((op >> 8) == 0x3A) | 1401 | if ((op >> 8) == 0x3A) |
| 1425 | return 3; | 1402 | return 3; |
| @@ -1429,8 +1406,7 @@ static int GetVEXmmmmm(u16 op) | |||
| 1429 | return 1; | 1406 | return 1; |
| 1430 | } | 1407 | } |
| 1431 | 1408 | ||
| 1432 | static int GetVEXpp(u8 opPrefix) | 1409 | static int GetVEXpp(u8 opPrefix) { |
| 1433 | { | ||
| 1434 | if (opPrefix == 0x66) | 1410 | if (opPrefix == 0x66) |
| 1435 | return 1; | 1411 | return 1; |
| 1436 | if (opPrefix == 0xF3) | 1412 | if (opPrefix == 0xF3) |
| @@ -1441,21 +1417,22 @@ static int GetVEXpp(u8 opPrefix) | |||
| 1441 | return 0; | 1417 | return 0; |
| 1442 | } | 1418 | } |
| 1443 | 1419 | ||
| 1444 | void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) | 1420 | void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, |
| 1445 | { | 1421 | int extrabytes) { |
| 1446 | if (!Common::GetCPUCaps().avx) | 1422 | if (!Common::GetCPUCaps().avx) |
| 1447 | ASSERT_MSG(0, "Trying to use AVX on a system that doesn't support it. Bad programmer."); | 1423 | ASSERT_MSG(0, "Trying to use AVX on a system that doesn't support it. Bad programmer."); |
| 1448 | int mmmmm = GetVEXmmmmm(op); | 1424 | int mmmmm = GetVEXmmmmm(op); |
| 1449 | int pp = GetVEXpp(opPrefix); | 1425 | int pp = GetVEXpp(opPrefix); |
| 1450 | // FIXME: we currently don't support 256-bit instructions, and "size" is not the vector size here | 1426 | // FIXME: we currently don't support 256-bit instructions, and "size" is not the vector size |
| 1427 | // here | ||
| 1451 | arg.WriteVex(this, regOp1, regOp2, 0, pp, mmmmm); | 1428 | arg.WriteVex(this, regOp1, regOp2, 0, pp, mmmmm); |
| 1452 | Write8(op & 0xFF); | 1429 | Write8(op & 0xFF); |
| 1453 | arg.WriteRest(this, extrabytes, regOp1); | 1430 | arg.WriteRest(this, extrabytes, regOp1); |
| 1454 | } | 1431 | } |
| 1455 | 1432 | ||
| 1456 | // Like the above, but more general; covers GPR-based VEX operations, like BMI1/2 | 1433 | // 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) | 1434 | void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, |
| 1458 | { | 1435 | const OpArg& arg, int extrabytes) { |
| 1459 | if (size != 32 && size != 64) | 1436 | if (size != 32 && size != 64) |
| 1460 | ASSERT_MSG(0, "VEX GPR instructions only support 32-bit and 64-bit modes!"); | 1437 | ASSERT_MSG(0, "VEX GPR instructions only support 32-bit and 64-bit modes!"); |
| 1461 | int mmmmm = GetVEXmmmmm(op); | 1438 | int mmmmm = GetVEXmmmmm(op); |
| @@ -1465,49 +1442,50 @@ void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg r | |||
| 1465 | arg.WriteRest(this, extrabytes, regOp1); | 1442 | arg.WriteRest(this, extrabytes, regOp1); |
| 1466 | } | 1443 | } |
| 1467 | 1444 | ||
| 1468 | void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) | 1445 | void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, |
| 1469 | { | 1446 | const OpArg& arg, int extrabytes) { |
| 1470 | CheckFlags(); | 1447 | CheckFlags(); |
| 1471 | if (!Common::GetCPUCaps().bmi1) | 1448 | if (!Common::GetCPUCaps().bmi1) |
| 1472 | ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer."); | 1449 | 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); | 1450 | WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); |
| 1474 | } | 1451 | } |
| 1475 | 1452 | ||
| 1476 | void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) | 1453 | void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, |
| 1477 | { | 1454 | const OpArg& arg, int extrabytes) { |
| 1478 | CheckFlags(); | 1455 | CheckFlags(); |
| 1479 | if (!Common::GetCPUCaps().bmi2) | 1456 | if (!Common::GetCPUCaps().bmi2) |
| 1480 | ASSERT_MSG(0, "Trying to use BMI2 on a system that doesn't support it. Bad programmer."); | 1457 | 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); | 1458 | WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); |
| 1482 | } | 1459 | } |
| 1483 | 1460 | ||
| 1484 | void XEmitter::MOVD_xmm(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x6E, dest, arg, 0);} | 1461 | 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);} | 1462 | WriteSSEOp(0x66, 0x6E, dest, arg, 0); |
| 1463 | } | ||
| 1464 | void XEmitter::MOVD_xmm(const OpArg& arg, X64Reg src) { | ||
| 1465 | WriteSSEOp(0x66, 0x7E, src, arg, 0); | ||
| 1466 | } | ||
| 1486 | 1467 | ||
| 1487 | void XEmitter::MOVQ_xmm(X64Reg dest, OpArg arg) | 1468 | void XEmitter::MOVQ_xmm(X64Reg dest, OpArg arg) { |
| 1488 | { | ||
| 1489 | #ifdef ARCHITECTURE_x86_64 | 1469 | #ifdef ARCHITECTURE_x86_64 |
| 1490 | // Alternate encoding | 1470 | // Alternate encoding |
| 1491 | // This does not display correctly in MSVC's debugger, it thinks it's a MOVD | 1471 | // This does not display correctly in MSVC's debugger, it thinks it's a MOVD |
| 1492 | arg.operandReg = dest; | 1472 | arg.operandReg = dest; |
| 1493 | Write8(0x66); | 1473 | Write8(0x66); |
| 1494 | arg.WriteRex(this, 64, 0); | 1474 | arg.WriteRex(this, 64, 0); |
| 1495 | Write8(0x0f); | 1475 | Write8(0x0f); |
| 1496 | Write8(0x6E); | 1476 | Write8(0x6E); |
| 1497 | arg.WriteRest(this, 0); | 1477 | arg.WriteRest(this, 0); |
| 1498 | #else | 1478 | #else |
| 1499 | arg.operandReg = dest; | 1479 | arg.operandReg = dest; |
| 1500 | Write8(0xF3); | 1480 | Write8(0xF3); |
| 1501 | Write8(0x0f); | 1481 | Write8(0x0f); |
| 1502 | Write8(0x7E); | 1482 | Write8(0x7E); |
| 1503 | arg.WriteRest(this, 0); | 1483 | arg.WriteRest(this, 0); |
| 1504 | #endif | 1484 | #endif |
| 1505 | } | 1485 | } |
| 1506 | 1486 | ||
| 1507 | void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) | 1487 | void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) { |
| 1508 | { | 1488 | if (src > 7 || arg.IsSimpleReg()) { |
| 1509 | if (src > 7 || arg.IsSimpleReg()) | ||
| 1510 | { | ||
| 1511 | // Alternate encoding | 1489 | // Alternate encoding |
| 1512 | // This does not display correctly in MSVC's debugger, it thinks it's a MOVD | 1490 | // This does not display correctly in MSVC's debugger, it thinks it's a MOVD |
| 1513 | arg.operandReg = src; | 1491 | arg.operandReg = src; |
| @@ -1516,9 +1494,7 @@ void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) | |||
| 1516 | Write8(0x0f); | 1494 | Write8(0x0f); |
| 1517 | Write8(0x7E); | 1495 | Write8(0x7E); |
| 1518 | arg.WriteRest(this, 0); | 1496 | arg.WriteRest(this, 0); |
| 1519 | } | 1497 | } else { |
| 1520 | else | ||
| 1521 | { | ||
| 1522 | arg.operandReg = src; | 1498 | arg.operandReg = src; |
| 1523 | arg.WriteRex(this, 0, 0); | 1499 | arg.WriteRex(this, 0, 0); |
| 1524 | Write8(0x66); | 1500 | Write8(0x66); |
| @@ -1528,8 +1504,7 @@ void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) | |||
| 1528 | } | 1504 | } |
| 1529 | } | 1505 | } |
| 1530 | 1506 | ||
| 1531 | void XEmitter::WriteMXCSR(OpArg arg, int ext) | 1507 | void XEmitter::WriteMXCSR(OpArg arg, int ext) { |
| 1532 | { | ||
| 1533 | if (arg.IsImm() || arg.IsSimpleReg()) | 1508 | if (arg.IsImm() || arg.IsSimpleReg()) |
| 1534 | ASSERT_MSG(0, "MXCSR - invalid operand"); | 1509 | ASSERT_MSG(0, "MXCSR - invalid operand"); |
| 1535 | 1510 | ||
| @@ -1540,143 +1515,357 @@ void XEmitter::WriteMXCSR(OpArg arg, int ext) | |||
| 1540 | arg.WriteRest(this); | 1515 | arg.WriteRest(this); |
| 1541 | } | 1516 | } |
| 1542 | 1517 | ||
| 1543 | void XEmitter::STMXCSR(const OpArg& memloc) {WriteMXCSR(memloc, 3);} | 1518 | void XEmitter::STMXCSR(const OpArg& memloc) { |
| 1544 | void XEmitter::LDMXCSR(const OpArg& memloc) {WriteMXCSR(memloc, 2);} | 1519 | WriteMXCSR(memloc, 3); |
| 1545 | 1520 | } | |
| 1546 | void XEmitter::MOVNTDQ(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVNTDQ, regOp, arg);} | 1521 | void XEmitter::LDMXCSR(const OpArg& memloc) { |
| 1547 | void XEmitter::MOVNTPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVNTP, regOp, arg);} | 1522 | WriteMXCSR(memloc, 2); |
| 1548 | void XEmitter::MOVNTPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVNTP, regOp, arg);} | 1523 | } |
| 1549 | 1524 | ||
| 1550 | void XEmitter::ADDSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseADD, regOp, arg);} | 1525 | void XEmitter::MOVNTDQ(const OpArg& arg, X64Reg regOp) { |
| 1551 | void XEmitter::ADDSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseADD, regOp, arg);} | 1526 | WriteSSEOp(0x66, sseMOVNTDQ, regOp, arg); |
| 1552 | void XEmitter::SUBSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseSUB, regOp, arg);} | 1527 | } |
| 1553 | void XEmitter::SUBSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseSUB, regOp, arg);} | 1528 | 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);} | 1529 | WriteSSEOp(0x00, sseMOVNTP, regOp, arg); |
| 1555 | void XEmitter::CMPSD(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0xF2, sseCMP, regOp, arg, 1); Write8(compare);} | 1530 | } |
| 1556 | void XEmitter::MULSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMUL, regOp, arg);} | 1531 | void XEmitter::MOVNTPD(const OpArg& arg, X64Reg regOp) { |
| 1557 | void XEmitter::MULSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMUL, regOp, arg);} | 1532 | WriteSSEOp(0x66, sseMOVNTP, regOp, arg); |
| 1558 | void XEmitter::DIVSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseDIV, regOp, arg);} | 1533 | } |
| 1559 | void XEmitter::DIVSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseDIV, regOp, arg);} | 1534 | |
| 1560 | void XEmitter::MINSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMIN, regOp, arg);} | 1535 | void XEmitter::ADDSS(X64Reg regOp, const OpArg& arg) { |
| 1561 | void XEmitter::MINSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMIN, regOp, arg);} | 1536 | WriteSSEOp(0xF3, sseADD, regOp, arg); |
| 1562 | void XEmitter::MAXSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMAX, regOp, arg);} | 1537 | } |
| 1563 | void XEmitter::MAXSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMAX, regOp, arg);} | 1538 | void XEmitter::ADDSD(X64Reg regOp, const OpArg& arg) { |
| 1564 | void XEmitter::SQRTSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseSQRT, regOp, arg);} | 1539 | WriteSSEOp(0xF2, sseADD, regOp, arg); |
| 1565 | void XEmitter::SQRTSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseSQRT, regOp, arg);} | 1540 | } |
| 1566 | void XEmitter::RCPSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseRCP, regOp, arg);} | 1541 | void XEmitter::SUBSS(X64Reg regOp, const OpArg& arg) { |
| 1567 | void XEmitter::RSQRTSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseRSQRT, regOp, arg);} | 1542 | WriteSSEOp(0xF3, sseSUB, regOp, arg); |
| 1568 | 1543 | } | |
| 1569 | void XEmitter::ADDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseADD, regOp, arg);} | 1544 | void XEmitter::SUBSD(X64Reg regOp, const OpArg& arg) { |
| 1570 | void XEmitter::ADDPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseADD, regOp, arg);} | 1545 | WriteSSEOp(0xF2, sseSUB, regOp, arg); |
| 1571 | void XEmitter::SUBPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseSUB, regOp, arg);} | 1546 | } |
| 1572 | void XEmitter::SUBPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseSUB, regOp, arg);} | 1547 | 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);} | 1548 | 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);} | 1549 | Write8(compare); |
| 1575 | void XEmitter::ANDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseAND, regOp, arg);} | 1550 | } |
| 1576 | void XEmitter::ANDPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseAND, regOp, arg);} | 1551 | void XEmitter::CMPSD(X64Reg regOp, const OpArg& arg, u8 compare) { |
| 1577 | void XEmitter::ANDNPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseANDN, regOp, arg);} | 1552 | WriteSSEOp(0xF2, sseCMP, regOp, arg, 1); |
| 1578 | void XEmitter::ANDNPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseANDN, regOp, arg);} | 1553 | Write8(compare); |
| 1579 | void XEmitter::ORPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseOR, regOp, arg);} | 1554 | } |
| 1580 | void XEmitter::ORPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseOR, regOp, arg);} | 1555 | void XEmitter::MULSS(X64Reg regOp, const OpArg& arg) { |
| 1581 | void XEmitter::XORPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseXOR, regOp, arg);} | 1556 | WriteSSEOp(0xF3, sseMUL, regOp, arg); |
| 1582 | void XEmitter::XORPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseXOR, regOp, arg);} | 1557 | } |
| 1583 | void XEmitter::MULPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMUL, regOp, arg);} | 1558 | void XEmitter::MULSD(X64Reg regOp, const OpArg& arg) { |
| 1584 | void XEmitter::MULPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMUL, regOp, arg);} | 1559 | WriteSSEOp(0xF2, sseMUL, regOp, arg); |
| 1585 | void XEmitter::DIVPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseDIV, regOp, arg);} | 1560 | } |
| 1586 | void XEmitter::DIVPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseDIV, regOp, arg);} | 1561 | void XEmitter::DIVSS(X64Reg regOp, const OpArg& arg) { |
| 1587 | void XEmitter::MINPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMIN, regOp, arg);} | 1562 | WriteSSEOp(0xF3, sseDIV, regOp, arg); |
| 1588 | void XEmitter::MINPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMIN, regOp, arg);} | 1563 | } |
| 1589 | void XEmitter::MAXPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMAX, regOp, arg);} | 1564 | void XEmitter::DIVSD(X64Reg regOp, const OpArg& arg) { |
| 1590 | void XEmitter::MAXPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMAX, regOp, arg);} | 1565 | WriteSSEOp(0xF2, sseDIV, regOp, arg); |
| 1591 | void XEmitter::SQRTPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseSQRT, regOp, arg);} | 1566 | } |
| 1592 | void XEmitter::SQRTPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseSQRT, regOp, arg);} | 1567 | void XEmitter::MINSS(X64Reg regOp, const OpArg& arg) { |
| 1593 | void XEmitter::RCPPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseRCP, regOp, arg); } | 1568 | WriteSSEOp(0xF3, sseMIN, regOp, arg); |
| 1594 | void XEmitter::RSQRTPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseRSQRT, regOp, arg);} | 1569 | } |
| 1595 | void XEmitter::SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0x00, sseSHUF, regOp, arg,1); Write8(shuffle);} | 1570 | 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);} | 1571 | WriteSSEOp(0xF2, sseMIN, regOp, arg); |
| 1597 | 1572 | } | |
| 1598 | void XEmitter::HADDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseHADD, regOp, arg);} | 1573 | void XEmitter::MAXSS(X64Reg regOp, const OpArg& arg) { |
| 1599 | 1574 | 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 | 1575 | } |
| 1601 | void XEmitter::COMISD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseCOMIS, regOp, arg);} //ordered | 1576 | void XEmitter::MAXSD(X64Reg regOp, const OpArg& arg) { |
| 1602 | void XEmitter::UCOMISS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseUCOMIS, regOp, arg);} //unordered | 1577 | WriteSSEOp(0xF2, sseMAX, regOp, arg); |
| 1603 | void XEmitter::UCOMISD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseUCOMIS, regOp, arg);} | 1578 | } |
| 1604 | 1579 | void XEmitter::SQRTSS(X64Reg regOp, const OpArg& arg) { | |
| 1605 | void XEmitter::MOVAPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVAPfromRM, regOp, arg);} | 1580 | WriteSSEOp(0xF3, sseSQRT, regOp, arg); |
| 1606 | void XEmitter::MOVAPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVAPfromRM, regOp, arg);} | 1581 | } |
| 1607 | void XEmitter::MOVAPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVAPtoRM, regOp, arg);} | 1582 | void XEmitter::SQRTSD(X64Reg regOp, const OpArg& arg) { |
| 1608 | void XEmitter::MOVAPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVAPtoRM, regOp, arg);} | 1583 | WriteSSEOp(0xF2, sseSQRT, regOp, arg); |
| 1609 | 1584 | } | |
| 1610 | void XEmitter::MOVUPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVUPfromRM, regOp, arg);} | 1585 | void XEmitter::RCPSS(X64Reg regOp, const OpArg& arg) { |
| 1611 | void XEmitter::MOVUPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVUPfromRM, regOp, arg);} | 1586 | WriteSSEOp(0xF3, sseRCP, regOp, arg); |
| 1612 | void XEmitter::MOVUPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVUPtoRM, regOp, arg);} | 1587 | } |
| 1613 | void XEmitter::MOVUPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVUPtoRM, regOp, arg);} | 1588 | void XEmitter::RSQRTSS(X64Reg regOp, const OpArg& arg) { |
| 1614 | 1589 | WriteSSEOp(0xF3, sseRSQRT, regOp, arg); | |
| 1615 | void XEmitter::MOVDQA(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVDQfromRM, regOp, arg);} | 1590 | } |
| 1616 | void XEmitter::MOVDQA(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVDQtoRM, regOp, arg);} | 1591 | |
| 1617 | void XEmitter::MOVDQU(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMOVDQfromRM, regOp, arg);} | 1592 | void XEmitter::ADDPS(X64Reg regOp, const OpArg& arg) { |
| 1618 | void XEmitter::MOVDQU(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF3, sseMOVDQtoRM, regOp, arg);} | 1593 | WriteSSEOp(0x00, sseADD, regOp, arg); |
| 1619 | 1594 | } | |
| 1620 | void XEmitter::MOVSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMOVUPfromRM, regOp, arg);} | 1595 | void XEmitter::ADDPD(X64Reg regOp, const OpArg& arg) { |
| 1621 | void XEmitter::MOVSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMOVUPfromRM, regOp, arg);} | 1596 | WriteSSEOp(0x66, sseADD, regOp, arg); |
| 1622 | void XEmitter::MOVSS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF3, sseMOVUPtoRM, regOp, arg);} | 1597 | } |
| 1623 | void XEmitter::MOVSD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF2, sseMOVUPtoRM, regOp, arg);} | 1598 | void XEmitter::SUBPS(X64Reg regOp, const OpArg& arg) { |
| 1624 | 1599 | WriteSSEOp(0x00, sseSUB, regOp, arg); | |
| 1625 | void XEmitter::MOVLPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseMOVLPfromRM, regOp, arg); } | 1600 | } |
| 1626 | void XEmitter::MOVLPD(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x66, sseMOVLPfromRM, regOp, arg); } | 1601 | void XEmitter::SUBPD(X64Reg regOp, const OpArg& arg) { |
| 1627 | void XEmitter::MOVLPS(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x00, sseMOVLPtoRM, regOp, arg); } | 1602 | WriteSSEOp(0x66, sseSUB, regOp, arg); |
| 1628 | void XEmitter::MOVLPD(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x66, sseMOVLPtoRM, regOp, arg); } | 1603 | } |
| 1629 | 1604 | void XEmitter::CMPPS(X64Reg regOp, const OpArg& arg, u8 compare) { | |
| 1630 | void XEmitter::MOVHPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseMOVHPfromRM, regOp, arg); } | 1605 | WriteSSEOp(0x00, sseCMP, regOp, arg, 1); |
| 1631 | void XEmitter::MOVHPD(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x66, sseMOVHPfromRM, regOp, arg); } | 1606 | Write8(compare); |
| 1632 | void XEmitter::MOVHPS(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x00, sseMOVHPtoRM, regOp, arg); } | 1607 | } |
| 1633 | void XEmitter::MOVHPD(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x66, sseMOVHPtoRM, regOp, arg); } | 1608 | void XEmitter::CMPPD(X64Reg regOp, const OpArg& arg, u8 compare) { |
| 1634 | 1609 | WriteSSEOp(0x66, sseCMP, regOp, arg, 1); | |
| 1635 | void XEmitter::MOVHLPS(X64Reg regOp1, X64Reg regOp2) {WriteSSEOp(0x00, sseMOVHLPS, regOp1, R(regOp2));} | 1610 | Write8(compare); |
| 1636 | void XEmitter::MOVLHPS(X64Reg regOp1, X64Reg regOp2) {WriteSSEOp(0x00, sseMOVLHPS, regOp1, R(regOp2));} | 1611 | } |
| 1637 | 1612 | void XEmitter::ANDPS(X64Reg regOp, const OpArg& arg) { | |
| 1638 | void XEmitter::CVTPS2PD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, 0x5A, regOp, arg);} | 1613 | WriteSSEOp(0x00, sseAND, regOp, arg); |
| 1639 | void XEmitter::CVTPD2PS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0x5A, regOp, arg);} | 1614 | } |
| 1640 | 1615 | void XEmitter::ANDPD(X64Reg regOp, const OpArg& arg) { | |
| 1641 | void XEmitter::CVTSD2SS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x5A, regOp, arg);} | 1616 | WriteSSEOp(0x66, sseAND, regOp, arg); |
| 1642 | void XEmitter::CVTSS2SD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x5A, regOp, arg);} | 1617 | } |
| 1643 | void XEmitter::CVTSD2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2D, regOp, arg);} | 1618 | void XEmitter::ANDNPS(X64Reg regOp, const OpArg& arg) { |
| 1644 | void XEmitter::CVTSS2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2D, regOp, arg);} | 1619 | WriteSSEOp(0x00, sseANDN, regOp, arg); |
| 1645 | void XEmitter::CVTSI2SD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2A, regOp, arg);} | 1620 | } |
| 1646 | void XEmitter::CVTSI2SS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2A, regOp, arg);} | 1621 | void XEmitter::ANDNPD(X64Reg regOp, const OpArg& arg) { |
| 1647 | 1622 | WriteSSEOp(0x66, sseANDN, regOp, arg); | |
| 1648 | void XEmitter::CVTDQ2PD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0xE6, regOp, arg);} | 1623 | } |
| 1649 | void XEmitter::CVTDQ2PS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, 0x5B, regOp, arg);} | 1624 | void XEmitter::ORPS(X64Reg regOp, const OpArg& arg) { |
| 1650 | void XEmitter::CVTPD2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0xE6, regOp, arg);} | 1625 | WriteSSEOp(0x00, sseOR, regOp, arg); |
| 1651 | void XEmitter::CVTPS2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0x5B, regOp, arg);} | 1626 | } |
| 1652 | 1627 | void XEmitter::ORPD(X64Reg regOp, const OpArg& arg) { | |
| 1653 | void XEmitter::CVTTSD2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2C, regOp, arg);} | 1628 | WriteSSEOp(0x66, sseOR, regOp, arg); |
| 1654 | void XEmitter::CVTTSS2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2C, regOp, arg);} | 1629 | } |
| 1655 | void XEmitter::CVTTPS2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x5B, regOp, arg);} | 1630 | void XEmitter::XORPS(X64Reg regOp, const OpArg& arg) { |
| 1656 | void XEmitter::CVTTPD2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0xE6, regOp, arg);} | 1631 | WriteSSEOp(0x00, sseXOR, regOp, arg); |
| 1657 | 1632 | } | |
| 1658 | void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) {WriteSSEOp(0x66, sseMASKMOVDQU, dest, R(src));} | 1633 | void XEmitter::XORPD(X64Reg regOp, const OpArg& arg) { |
| 1659 | 1634 | WriteSSEOp(0x66, sseXOR, regOp, arg); | |
| 1660 | void XEmitter::MOVMSKPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x50, dest, arg);} | 1635 | } |
| 1661 | void XEmitter::MOVMSKPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x50, dest, arg);} | 1636 | void XEmitter::MULPS(X64Reg regOp, const OpArg& arg) { |
| 1662 | 1637 | WriteSSEOp(0x00, sseMUL, regOp, arg); | |
| 1663 | void XEmitter::LDDQU(X64Reg dest, const OpArg& arg) {WriteSSEOp(0xF2, sseLDDQU, dest, arg);} // For integer data only | 1638 | } |
| 1639 | void XEmitter::MULPD(X64Reg regOp, const OpArg& arg) { | ||
| 1640 | WriteSSEOp(0x66, sseMUL, regOp, arg); | ||
| 1641 | } | ||
| 1642 | void XEmitter::DIVPS(X64Reg regOp, const OpArg& arg) { | ||
| 1643 | WriteSSEOp(0x00, sseDIV, regOp, arg); | ||
| 1644 | } | ||
| 1645 | void XEmitter::DIVPD(X64Reg regOp, const OpArg& arg) { | ||
| 1646 | WriteSSEOp(0x66, sseDIV, regOp, arg); | ||
| 1647 | } | ||
| 1648 | void XEmitter::MINPS(X64Reg regOp, const OpArg& arg) { | ||
| 1649 | WriteSSEOp(0x00, sseMIN, regOp, arg); | ||
| 1650 | } | ||
| 1651 | void XEmitter::MINPD(X64Reg regOp, const OpArg& arg) { | ||
| 1652 | WriteSSEOp(0x66, sseMIN, regOp, arg); | ||
| 1653 | } | ||
| 1654 | void XEmitter::MAXPS(X64Reg regOp, const OpArg& arg) { | ||
| 1655 | WriteSSEOp(0x00, sseMAX, regOp, arg); | ||
| 1656 | } | ||
| 1657 | void XEmitter::MAXPD(X64Reg regOp, const OpArg& arg) { | ||
| 1658 | WriteSSEOp(0x66, sseMAX, regOp, arg); | ||
| 1659 | } | ||
| 1660 | void XEmitter::SQRTPS(X64Reg regOp, const OpArg& arg) { | ||
| 1661 | WriteSSEOp(0x00, sseSQRT, regOp, arg); | ||
| 1662 | } | ||
| 1663 | void XEmitter::SQRTPD(X64Reg regOp, const OpArg& arg) { | ||
| 1664 | WriteSSEOp(0x66, sseSQRT, regOp, arg); | ||
| 1665 | } | ||
| 1666 | void XEmitter::RCPPS(X64Reg regOp, const OpArg& arg) { | ||
| 1667 | WriteSSEOp(0x00, sseRCP, regOp, arg); | ||
| 1668 | } | ||
| 1669 | void XEmitter::RSQRTPS(X64Reg regOp, const OpArg& arg) { | ||
| 1670 | WriteSSEOp(0x00, sseRSQRT, regOp, arg); | ||
| 1671 | } | ||
| 1672 | void XEmitter::SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle) { | ||
| 1673 | WriteSSEOp(0x00, sseSHUF, regOp, arg, 1); | ||
| 1674 | Write8(shuffle); | ||
| 1675 | } | ||
| 1676 | void XEmitter::SHUFPD(X64Reg regOp, const OpArg& arg, u8 shuffle) { | ||
| 1677 | WriteSSEOp(0x66, sseSHUF, regOp, arg, 1); | ||
| 1678 | Write8(shuffle); | ||
| 1679 | } | ||
| 1680 | |||
| 1681 | void XEmitter::HADDPS(X64Reg regOp, const OpArg& arg) { | ||
| 1682 | WriteSSEOp(0xF2, sseHADD, regOp, arg); | ||
| 1683 | } | ||
| 1684 | |||
| 1685 | void XEmitter::COMISS(X64Reg regOp, const OpArg& arg) { | ||
| 1686 | WriteSSEOp(0x00, sseCOMIS, regOp, arg); | ||
| 1687 | } // weird that these should be packed | ||
| 1688 | void XEmitter::COMISD(X64Reg regOp, const OpArg& arg) { | ||
| 1689 | WriteSSEOp(0x66, sseCOMIS, regOp, arg); | ||
| 1690 | } // ordered | ||
| 1691 | void XEmitter::UCOMISS(X64Reg regOp, const OpArg& arg) { | ||
| 1692 | WriteSSEOp(0x00, sseUCOMIS, regOp, arg); | ||
| 1693 | } // unordered | ||
| 1694 | void XEmitter::UCOMISD(X64Reg regOp, const OpArg& arg) { | ||
| 1695 | WriteSSEOp(0x66, sseUCOMIS, regOp, arg); | ||
| 1696 | } | ||
| 1697 | |||
| 1698 | void XEmitter::MOVAPS(X64Reg regOp, const OpArg& arg) { | ||
| 1699 | WriteSSEOp(0x00, sseMOVAPfromRM, regOp, arg); | ||
| 1700 | } | ||
| 1701 | void XEmitter::MOVAPD(X64Reg regOp, const OpArg& arg) { | ||
| 1702 | WriteSSEOp(0x66, sseMOVAPfromRM, regOp, arg); | ||
| 1703 | } | ||
| 1704 | void XEmitter::MOVAPS(const OpArg& arg, X64Reg regOp) { | ||
| 1705 | WriteSSEOp(0x00, sseMOVAPtoRM, regOp, arg); | ||
| 1706 | } | ||
| 1707 | void XEmitter::MOVAPD(const OpArg& arg, X64Reg regOp) { | ||
| 1708 | WriteSSEOp(0x66, sseMOVAPtoRM, regOp, arg); | ||
| 1709 | } | ||
| 1710 | |||
| 1711 | void XEmitter::MOVUPS(X64Reg regOp, const OpArg& arg) { | ||
| 1712 | WriteSSEOp(0x00, sseMOVUPfromRM, regOp, arg); | ||
| 1713 | } | ||
| 1714 | void XEmitter::MOVUPD(X64Reg regOp, const OpArg& arg) { | ||
| 1715 | WriteSSEOp(0x66, sseMOVUPfromRM, regOp, arg); | ||
| 1716 | } | ||
| 1717 | void XEmitter::MOVUPS(const OpArg& arg, X64Reg regOp) { | ||
| 1718 | WriteSSEOp(0x00, sseMOVUPtoRM, regOp, arg); | ||
| 1719 | } | ||
| 1720 | void XEmitter::MOVUPD(const OpArg& arg, X64Reg regOp) { | ||
| 1721 | WriteSSEOp(0x66, sseMOVUPtoRM, regOp, arg); | ||
| 1722 | } | ||
| 1723 | |||
| 1724 | void XEmitter::MOVDQA(X64Reg regOp, const OpArg& arg) { | ||
| 1725 | WriteSSEOp(0x66, sseMOVDQfromRM, regOp, arg); | ||
| 1726 | } | ||
| 1727 | void XEmitter::MOVDQA(const OpArg& arg, X64Reg regOp) { | ||
| 1728 | WriteSSEOp(0x66, sseMOVDQtoRM, regOp, arg); | ||
| 1729 | } | ||
| 1730 | void XEmitter::MOVDQU(X64Reg regOp, const OpArg& arg) { | ||
| 1731 | WriteSSEOp(0xF3, sseMOVDQfromRM, regOp, arg); | ||
| 1732 | } | ||
| 1733 | void XEmitter::MOVDQU(const OpArg& arg, X64Reg regOp) { | ||
| 1734 | WriteSSEOp(0xF3, sseMOVDQtoRM, regOp, arg); | ||
| 1735 | } | ||
| 1736 | |||
| 1737 | void XEmitter::MOVSS(X64Reg regOp, const OpArg& arg) { | ||
| 1738 | WriteSSEOp(0xF3, sseMOVUPfromRM, regOp, arg); | ||
| 1739 | } | ||
| 1740 | void XEmitter::MOVSD(X64Reg regOp, const OpArg& arg) { | ||
| 1741 | WriteSSEOp(0xF2, sseMOVUPfromRM, regOp, arg); | ||
| 1742 | } | ||
| 1743 | void XEmitter::MOVSS(const OpArg& arg, X64Reg regOp) { | ||
| 1744 | WriteSSEOp(0xF3, sseMOVUPtoRM, regOp, arg); | ||
| 1745 | } | ||
| 1746 | void XEmitter::MOVSD(const OpArg& arg, X64Reg regOp) { | ||
| 1747 | WriteSSEOp(0xF2, sseMOVUPtoRM, regOp, arg); | ||
| 1748 | } | ||
| 1749 | |||
| 1750 | void XEmitter::MOVLPS(X64Reg regOp, const OpArg& arg) { | ||
| 1751 | WriteSSEOp(0x00, sseMOVLPfromRM, regOp, arg); | ||
| 1752 | } | ||
| 1753 | void XEmitter::MOVLPD(X64Reg regOp, const OpArg& arg) { | ||
| 1754 | WriteSSEOp(0x66, sseMOVLPfromRM, regOp, arg); | ||
| 1755 | } | ||
| 1756 | void XEmitter::MOVLPS(const OpArg& arg, X64Reg regOp) { | ||
| 1757 | WriteSSEOp(0x00, sseMOVLPtoRM, regOp, arg); | ||
| 1758 | } | ||
| 1759 | void XEmitter::MOVLPD(const OpArg& arg, X64Reg regOp) { | ||
| 1760 | WriteSSEOp(0x66, sseMOVLPtoRM, regOp, arg); | ||
| 1761 | } | ||
| 1762 | |||
| 1763 | void XEmitter::MOVHPS(X64Reg regOp, const OpArg& arg) { | ||
| 1764 | WriteSSEOp(0x00, sseMOVHPfromRM, regOp, arg); | ||
| 1765 | } | ||
| 1766 | void XEmitter::MOVHPD(X64Reg regOp, const OpArg& arg) { | ||
| 1767 | WriteSSEOp(0x66, sseMOVHPfromRM, regOp, arg); | ||
| 1768 | } | ||
| 1769 | void XEmitter::MOVHPS(const OpArg& arg, X64Reg regOp) { | ||
| 1770 | WriteSSEOp(0x00, sseMOVHPtoRM, regOp, arg); | ||
| 1771 | } | ||
| 1772 | void XEmitter::MOVHPD(const OpArg& arg, X64Reg regOp) { | ||
| 1773 | WriteSSEOp(0x66, sseMOVHPtoRM, regOp, arg); | ||
| 1774 | } | ||
| 1775 | |||
| 1776 | void XEmitter::MOVHLPS(X64Reg regOp1, X64Reg regOp2) { | ||
| 1777 | WriteSSEOp(0x00, sseMOVHLPS, regOp1, R(regOp2)); | ||
| 1778 | } | ||
| 1779 | void XEmitter::MOVLHPS(X64Reg regOp1, X64Reg regOp2) { | ||
| 1780 | WriteSSEOp(0x00, sseMOVLHPS, regOp1, R(regOp2)); | ||
| 1781 | } | ||
| 1782 | |||
| 1783 | void XEmitter::CVTPS2PD(X64Reg regOp, const OpArg& arg) { | ||
| 1784 | WriteSSEOp(0x00, 0x5A, regOp, arg); | ||
| 1785 | } | ||
| 1786 | void XEmitter::CVTPD2PS(X64Reg regOp, const OpArg& arg) { | ||
| 1787 | WriteSSEOp(0x66, 0x5A, regOp, arg); | ||
| 1788 | } | ||
| 1789 | |||
| 1790 | void XEmitter::CVTSD2SS(X64Reg regOp, const OpArg& arg) { | ||
| 1791 | WriteSSEOp(0xF2, 0x5A, regOp, arg); | ||
| 1792 | } | ||
| 1793 | void XEmitter::CVTSS2SD(X64Reg regOp, const OpArg& arg) { | ||
| 1794 | WriteSSEOp(0xF3, 0x5A, regOp, arg); | ||
| 1795 | } | ||
| 1796 | void XEmitter::CVTSD2SI(X64Reg regOp, const OpArg& arg) { | ||
| 1797 | WriteSSEOp(0xF2, 0x2D, regOp, arg); | ||
| 1798 | } | ||
| 1799 | void XEmitter::CVTSS2SI(X64Reg regOp, const OpArg& arg) { | ||
| 1800 | WriteSSEOp(0xF3, 0x2D, regOp, arg); | ||
| 1801 | } | ||
| 1802 | void XEmitter::CVTSI2SD(X64Reg regOp, const OpArg& arg) { | ||
| 1803 | WriteSSEOp(0xF2, 0x2A, regOp, arg); | ||
| 1804 | } | ||
| 1805 | void XEmitter::CVTSI2SS(X64Reg regOp, const OpArg& arg) { | ||
| 1806 | WriteSSEOp(0xF3, 0x2A, regOp, arg); | ||
| 1807 | } | ||
| 1808 | |||
| 1809 | void XEmitter::CVTDQ2PD(X64Reg regOp, const OpArg& arg) { | ||
| 1810 | WriteSSEOp(0xF3, 0xE6, regOp, arg); | ||
| 1811 | } | ||
| 1812 | void XEmitter::CVTDQ2PS(X64Reg regOp, const OpArg& arg) { | ||
| 1813 | WriteSSEOp(0x00, 0x5B, regOp, arg); | ||
| 1814 | } | ||
| 1815 | void XEmitter::CVTPD2DQ(X64Reg regOp, const OpArg& arg) { | ||
| 1816 | WriteSSEOp(0xF2, 0xE6, regOp, arg); | ||
| 1817 | } | ||
| 1818 | void XEmitter::CVTPS2DQ(X64Reg regOp, const OpArg& arg) { | ||
| 1819 | WriteSSEOp(0x66, 0x5B, regOp, arg); | ||
| 1820 | } | ||
| 1821 | |||
| 1822 | void XEmitter::CVTTSD2SI(X64Reg regOp, const OpArg& arg) { | ||
| 1823 | WriteSSEOp(0xF2, 0x2C, regOp, arg); | ||
| 1824 | } | ||
| 1825 | void XEmitter::CVTTSS2SI(X64Reg regOp, const OpArg& arg) { | ||
| 1826 | WriteSSEOp(0xF3, 0x2C, regOp, arg); | ||
| 1827 | } | ||
| 1828 | void XEmitter::CVTTPS2DQ(X64Reg regOp, const OpArg& arg) { | ||
| 1829 | WriteSSEOp(0xF3, 0x5B, regOp, arg); | ||
| 1830 | } | ||
| 1831 | void XEmitter::CVTTPD2DQ(X64Reg regOp, const OpArg& arg) { | ||
| 1832 | WriteSSEOp(0x66, 0xE6, regOp, arg); | ||
| 1833 | } | ||
| 1834 | |||
| 1835 | void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) { | ||
| 1836 | WriteSSEOp(0x66, sseMASKMOVDQU, dest, R(src)); | ||
| 1837 | } | ||
| 1838 | |||
| 1839 | void XEmitter::MOVMSKPS(X64Reg dest, const OpArg& arg) { | ||
| 1840 | WriteSSEOp(0x00, 0x50, dest, arg); | ||
| 1841 | } | ||
| 1842 | void XEmitter::MOVMSKPD(X64Reg dest, const OpArg& arg) { | ||
| 1843 | WriteSSEOp(0x66, 0x50, dest, arg); | ||
| 1844 | } | ||
| 1845 | |||
| 1846 | void XEmitter::LDDQU(X64Reg dest, const OpArg& arg) { | ||
| 1847 | WriteSSEOp(0xF2, sseLDDQU, dest, arg); | ||
| 1848 | } // For integer data only | ||
| 1664 | 1849 | ||
| 1665 | // THESE TWO ARE UNTESTED. | 1850 | // THESE TWO ARE UNTESTED. |
| 1666 | void XEmitter::UNPCKLPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x14, dest, arg);} | 1851 | void XEmitter::UNPCKLPS(X64Reg dest, const OpArg& arg) { |
| 1667 | void XEmitter::UNPCKHPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x15, dest, arg);} | 1852 | WriteSSEOp(0x00, 0x14, dest, arg); |
| 1853 | } | ||
| 1854 | void XEmitter::UNPCKHPS(X64Reg dest, const OpArg& arg) { | ||
| 1855 | WriteSSEOp(0x00, 0x15, dest, arg); | ||
| 1856 | } | ||
| 1668 | 1857 | ||
| 1669 | void XEmitter::UNPCKLPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x14, dest, arg);} | 1858 | void XEmitter::UNPCKLPD(X64Reg dest, const OpArg& arg) { |
| 1670 | void XEmitter::UNPCKHPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x15, dest, arg);} | 1859 | WriteSSEOp(0x66, 0x14, dest, arg); |
| 1860 | } | ||
| 1861 | void XEmitter::UNPCKHPD(X64Reg dest, const OpArg& arg) { | ||
| 1862 | WriteSSEOp(0x66, 0x15, dest, arg); | ||
| 1863 | } | ||
| 1671 | 1864 | ||
| 1672 | void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg) | 1865 | void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg) { |
| 1673 | { | 1866 | if (Common::GetCPUCaps().sse3) { |
| 1674 | if (Common::GetCPUCaps().sse3) | 1867 | WriteSSEOp(0xF2, 0x12, regOp, arg); // SSE3 movddup |
| 1675 | { | 1868 | } else { |
| 1676 | WriteSSEOp(0xF2, 0x12, regOp, arg); //SSE3 movddup | ||
| 1677 | } | ||
| 1678 | else | ||
| 1679 | { | ||
| 1680 | // Simulate this instruction with SSE2 instructions | 1869 | // Simulate this instruction with SSE2 instructions |
| 1681 | if (!arg.IsSimpleReg(regOp)) | 1870 | if (!arg.IsSimpleReg(regOp)) |
| 1682 | MOVSD(regOp, arg); | 1871 | MOVSD(regOp, arg); |
| @@ -1684,38 +1873,48 @@ void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg) | |||
| 1684 | } | 1873 | } |
| 1685 | } | 1874 | } |
| 1686 | 1875 | ||
| 1687 | //There are a few more left | 1876 | // There are a few more left |
| 1688 | 1877 | ||
| 1689 | // Also some integer instructions are missing | 1878 | // Also some integer instructions are missing |
| 1690 | void XEmitter::PACKSSDW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x6B, dest, arg);} | 1879 | void XEmitter::PACKSSDW(X64Reg dest, const OpArg& arg) { |
| 1691 | void XEmitter::PACKSSWB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x63, dest, arg);} | 1880 | WriteSSEOp(0x66, 0x6B, dest, arg); |
| 1692 | void XEmitter::PACKUSWB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x67, dest, arg);} | 1881 | } |
| 1882 | void XEmitter::PACKSSWB(X64Reg dest, const OpArg& arg) { | ||
| 1883 | WriteSSEOp(0x66, 0x63, dest, arg); | ||
| 1884 | } | ||
| 1885 | void XEmitter::PACKUSWB(X64Reg dest, const OpArg& arg) { | ||
| 1886 | WriteSSEOp(0x66, 0x67, dest, arg); | ||
| 1887 | } | ||
| 1693 | 1888 | ||
| 1694 | void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x60, dest, arg);} | 1889 | void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg& arg) { |
| 1695 | void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x61, dest, arg);} | 1890 | WriteSSEOp(0x66, 0x60, dest, arg); |
| 1696 | void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x62, dest, arg);} | 1891 | } |
| 1697 | void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x6C, dest, arg);} | 1892 | void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg& arg) { |
| 1893 | WriteSSEOp(0x66, 0x61, dest, arg); | ||
| 1894 | } | ||
| 1895 | void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg& arg) { | ||
| 1896 | WriteSSEOp(0x66, 0x62, dest, arg); | ||
| 1897 | } | ||
| 1898 | void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg& arg) { | ||
| 1899 | WriteSSEOp(0x66, 0x6C, dest, arg); | ||
| 1900 | } | ||
| 1698 | 1901 | ||
| 1699 | void XEmitter::PSRLW(X64Reg reg, int shift) | 1902 | void XEmitter::PSRLW(X64Reg reg, int shift) { |
| 1700 | { | ||
| 1701 | WriteSSEOp(0x66, 0x71, (X64Reg)2, R(reg)); | 1903 | WriteSSEOp(0x66, 0x71, (X64Reg)2, R(reg)); |
| 1702 | Write8(shift); | 1904 | Write8(shift); |
| 1703 | } | 1905 | } |
| 1704 | 1906 | ||
| 1705 | void XEmitter::PSRLD(X64Reg reg, int shift) | 1907 | void XEmitter::PSRLD(X64Reg reg, int shift) { |
| 1706 | { | ||
| 1707 | WriteSSEOp(0x66, 0x72, (X64Reg)2, R(reg)); | 1908 | WriteSSEOp(0x66, 0x72, (X64Reg)2, R(reg)); |
| 1708 | Write8(shift); | 1909 | Write8(shift); |
| 1709 | } | 1910 | } |
| 1710 | 1911 | ||
| 1711 | void XEmitter::PSRLQ(X64Reg reg, int shift) | 1912 | void XEmitter::PSRLQ(X64Reg reg, int shift) { |
| 1712 | { | ||
| 1713 | WriteSSEOp(0x66, 0x73, (X64Reg)2, R(reg)); | 1913 | WriteSSEOp(0x66, 0x73, (X64Reg)2, R(reg)); |
| 1714 | Write8(shift); | 1914 | Write8(shift); |
| 1715 | } | 1915 | } |
| 1716 | 1916 | ||
| 1717 | void XEmitter::PSRLQ(X64Reg reg, const OpArg& arg) | 1917 | void XEmitter::PSRLQ(X64Reg reg, const OpArg& arg) { |
| 1718 | { | ||
| 1719 | WriteSSEOp(0x66, 0xd3, reg, arg); | 1918 | WriteSSEOp(0x66, 0xd3, reg, arg); |
| 1720 | } | 1919 | } |
| 1721 | 1920 | ||
| @@ -1724,20 +1923,17 @@ void XEmitter::PSRLDQ(X64Reg reg, int shift) { | |||
| 1724 | Write8(shift); | 1923 | Write8(shift); |
| 1725 | } | 1924 | } |
| 1726 | 1925 | ||
| 1727 | void XEmitter::PSLLW(X64Reg reg, int shift) | 1926 | void XEmitter::PSLLW(X64Reg reg, int shift) { |
| 1728 | { | ||
| 1729 | WriteSSEOp(0x66, 0x71, (X64Reg)6, R(reg)); | 1927 | WriteSSEOp(0x66, 0x71, (X64Reg)6, R(reg)); |
| 1730 | Write8(shift); | 1928 | Write8(shift); |
| 1731 | } | 1929 | } |
| 1732 | 1930 | ||
| 1733 | void XEmitter::PSLLD(X64Reg reg, int shift) | 1931 | void XEmitter::PSLLD(X64Reg reg, int shift) { |
| 1734 | { | ||
| 1735 | WriteSSEOp(0x66, 0x72, (X64Reg)6, R(reg)); | 1932 | WriteSSEOp(0x66, 0x72, (X64Reg)6, R(reg)); |
| 1736 | Write8(shift); | 1933 | Write8(shift); |
| 1737 | } | 1934 | } |
| 1738 | 1935 | ||
| 1739 | void XEmitter::PSLLQ(X64Reg reg, int shift) | 1936 | void XEmitter::PSLLQ(X64Reg reg, int shift) { |
| 1740 | { | ||
| 1741 | WriteSSEOp(0x66, 0x73, (X64Reg)6, R(reg)); | 1937 | WriteSSEOp(0x66, 0x73, (X64Reg)6, R(reg)); |
| 1742 | Write8(shift); | 1938 | Write8(shift); |
| 1743 | } | 1939 | } |
| @@ -1747,267 +1943,643 @@ void XEmitter::PSLLDQ(X64Reg reg, int shift) { | |||
| 1747 | Write8(shift); | 1943 | Write8(shift); |
| 1748 | } | 1944 | } |
| 1749 | 1945 | ||
| 1750 | void XEmitter::PSRAW(X64Reg reg, int shift) | 1946 | void XEmitter::PSRAW(X64Reg reg, int shift) { |
| 1751 | { | ||
| 1752 | WriteSSEOp(0x66, 0x71, (X64Reg)4, R(reg)); | 1947 | WriteSSEOp(0x66, 0x71, (X64Reg)4, R(reg)); |
| 1753 | Write8(shift); | 1948 | Write8(shift); |
| 1754 | } | 1949 | } |
| 1755 | 1950 | ||
| 1756 | void XEmitter::PSRAD(X64Reg reg, int shift) | 1951 | void XEmitter::PSRAD(X64Reg reg, int shift) { |
| 1757 | { | ||
| 1758 | WriteSSEOp(0x66, 0x72, (X64Reg)4, R(reg)); | 1952 | WriteSSEOp(0x66, 0x72, (X64Reg)4, R(reg)); |
| 1759 | Write8(shift); | 1953 | Write8(shift); |
| 1760 | } | 1954 | } |
| 1761 | 1955 | ||
| 1762 | void XEmitter::WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) | 1956 | void XEmitter::WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) { |
| 1763 | { | ||
| 1764 | if (!Common::GetCPUCaps().ssse3) | 1957 | if (!Common::GetCPUCaps().ssse3) |
| 1765 | ASSERT_MSG(0, "Trying to use SSSE3 on a system that doesn't support it. Bad programmer."); | 1958 | ASSERT_MSG(0, "Trying to use SSSE3 on a system that doesn't support it. Bad programmer."); |
| 1766 | WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); | 1959 | WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); |
| 1767 | } | 1960 | } |
| 1768 | 1961 | ||
| 1769 | void XEmitter::WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) | 1962 | void XEmitter::WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) { |
| 1770 | { | ||
| 1771 | if (!Common::GetCPUCaps().sse4_1) | 1963 | if (!Common::GetCPUCaps().sse4_1) |
| 1772 | ASSERT_MSG(0, "Trying to use SSE4.1 on a system that doesn't support it. Bad programmer."); | 1964 | 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); | 1965 | WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); |
| 1774 | } | 1966 | } |
| 1775 | 1967 | ||
| 1776 | void XEmitter::PSHUFB(X64Reg dest, const OpArg& arg) {WriteSSSE3Op(0x66, 0x3800, dest, arg);} | 1968 | void XEmitter::PSHUFB(X64Reg dest, const OpArg& arg) { |
| 1777 | void XEmitter::PTEST(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3817, dest, arg);} | 1969 | WriteSSSE3Op(0x66, 0x3800, dest, arg); |
| 1778 | void XEmitter::PACKUSDW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x382b, dest, arg);} | 1970 | } |
| 1779 | void XEmitter::DPPS(X64Reg dest, const OpArg& arg, u8 mask) {WriteSSE41Op(0x66, 0x3A40, dest, arg, 1); Write8(mask);} | 1971 | void XEmitter::PTEST(X64Reg dest, const OpArg& arg) { |
| 1780 | 1972 | WriteSSE41Op(0x66, 0x3817, dest, arg); | |
| 1781 | void XEmitter::PMINSB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3838, dest, arg);} | 1973 | } |
| 1782 | void XEmitter::PMINSD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3839, dest, arg);} | 1974 | void XEmitter::PACKUSDW(X64Reg dest, const OpArg& arg) { |
| 1783 | void XEmitter::PMINUW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383a, dest, arg);} | 1975 | WriteSSE41Op(0x66, 0x382b, dest, arg); |
| 1784 | void XEmitter::PMINUD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383b, dest, arg);} | 1976 | } |
| 1785 | void XEmitter::PMAXSB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383c, dest, arg);} | 1977 | void XEmitter::DPPS(X64Reg dest, const OpArg& arg, u8 mask) { |
| 1786 | void XEmitter::PMAXSD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383d, dest, arg);} | 1978 | WriteSSE41Op(0x66, 0x3A40, dest, arg, 1); |
| 1787 | void XEmitter::PMAXUW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383e, dest, arg);} | 1979 | Write8(mask); |
| 1788 | void XEmitter::PMAXUD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383f, dest, arg);} | 1980 | } |
| 1789 | 1981 | ||
| 1790 | void XEmitter::PMOVSXBW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3820, dest, arg);} | 1982 | void XEmitter::PMINSB(X64Reg dest, const OpArg& arg) { |
| 1791 | void XEmitter::PMOVSXBD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3821, dest, arg);} | 1983 | WriteSSE41Op(0x66, 0x3838, dest, arg); |
| 1792 | void XEmitter::PMOVSXBQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3822, dest, arg);} | 1984 | } |
| 1793 | void XEmitter::PMOVSXWD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3823, dest, arg);} | 1985 | void XEmitter::PMINSD(X64Reg dest, const OpArg& arg) { |
| 1794 | void XEmitter::PMOVSXWQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3824, dest, arg);} | 1986 | WriteSSE41Op(0x66, 0x3839, dest, arg); |
| 1795 | void XEmitter::PMOVSXDQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3825, dest, arg);} | 1987 | } |
| 1796 | void XEmitter::PMOVZXBW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3830, dest, arg);} | 1988 | void XEmitter::PMINUW(X64Reg dest, const OpArg& arg) { |
| 1797 | void XEmitter::PMOVZXBD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3831, dest, arg);} | 1989 | WriteSSE41Op(0x66, 0x383a, dest, arg); |
| 1798 | void XEmitter::PMOVZXBQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3832, dest, arg);} | 1990 | } |
| 1799 | void XEmitter::PMOVZXWD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3833, dest, arg);} | 1991 | void XEmitter::PMINUD(X64Reg dest, const OpArg& arg) { |
| 1800 | void XEmitter::PMOVZXWQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3834, dest, arg);} | 1992 | WriteSSE41Op(0x66, 0x383b, dest, arg); |
| 1801 | void XEmitter::PMOVZXDQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3835, dest, arg);} | 1993 | } |
| 1802 | 1994 | void XEmitter::PMAXSB(X64Reg dest, const OpArg& arg) { | |
| 1803 | void XEmitter::PBLENDVB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3810, dest, arg);} | 1995 | WriteSSE41Op(0x66, 0x383c, dest, arg); |
| 1804 | void XEmitter::BLENDVPS(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3814, dest, arg);} | 1996 | } |
| 1805 | void XEmitter::BLENDVPD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3815, dest, arg);} | 1997 | 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); } | 1998 | WriteSSE41Op(0x66, 0x383d, dest, arg); |
| 1807 | void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) { WriteSSE41Op(0x66, 0x3A0D, dest, arg, 1); Write8(blend); } | 1999 | } |
| 1808 | 2000 | 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);} | 2001 | WriteSSE41Op(0x66, 0x383e, dest, arg); |
| 1810 | void XEmitter::ROUNDSD(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A0B, dest, arg, 1); Write8(mode);} | 2002 | } |
| 1811 | void XEmitter::ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A08, dest, arg, 1); Write8(mode);} | 2003 | 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);} | 2004 | WriteSSE41Op(0x66, 0x383f, dest, arg); |
| 1813 | 2005 | } | |
| 1814 | void XEmitter::PAND(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDB, dest, arg);} | 2006 | |
| 1815 | void XEmitter::PANDN(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDF, dest, arg);} | 2007 | void XEmitter::PMOVSXBW(X64Reg dest, const OpArg& arg) { |
| 1816 | void XEmitter::PXOR(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEF, dest, arg);} | 2008 | WriteSSE41Op(0x66, 0x3820, dest, arg); |
| 1817 | void XEmitter::POR(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEB, dest, arg);} | 2009 | } |
| 1818 | 2010 | void XEmitter::PMOVSXBD(X64Reg dest, const OpArg& arg) { | |
| 1819 | void XEmitter::PADDB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFC, dest, arg);} | 2011 | WriteSSE41Op(0x66, 0x3821, dest, arg); |
| 1820 | void XEmitter::PADDW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFD, dest, arg);} | 2012 | } |
| 1821 | void XEmitter::PADDD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFE, dest, arg);} | 2013 | void XEmitter::PMOVSXBQ(X64Reg dest, const OpArg& arg) { |
| 1822 | void XEmitter::PADDQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD4, dest, arg);} | 2014 | WriteSSE41Op(0x66, 0x3822, dest, arg); |
| 1823 | 2015 | } | |
| 1824 | void XEmitter::PADDSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEC, dest, arg);} | 2016 | void XEmitter::PMOVSXWD(X64Reg dest, const OpArg& arg) { |
| 1825 | void XEmitter::PADDSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xED, dest, arg);} | 2017 | WriteSSE41Op(0x66, 0x3823, dest, arg); |
| 1826 | void XEmitter::PADDUSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDC, dest, arg);} | 2018 | } |
| 1827 | void XEmitter::PADDUSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDD, dest, arg);} | 2019 | void XEmitter::PMOVSXWQ(X64Reg dest, const OpArg& arg) { |
| 1828 | 2020 | WriteSSE41Op(0x66, 0x3824, dest, arg); | |
| 1829 | void XEmitter::PSUBB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF8, dest, arg);} | 2021 | } |
| 1830 | void XEmitter::PSUBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF9, dest, arg);} | 2022 | void XEmitter::PMOVSXDQ(X64Reg dest, const OpArg& arg) { |
| 1831 | void XEmitter::PSUBD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFA, dest, arg);} | 2023 | WriteSSE41Op(0x66, 0x3825, dest, arg); |
| 1832 | void XEmitter::PSUBQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFB, dest, arg);} | 2024 | } |
| 1833 | 2025 | void XEmitter::PMOVZXBW(X64Reg dest, const OpArg& arg) { | |
| 1834 | void XEmitter::PSUBSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE8, dest, arg);} | 2026 | WriteSSE41Op(0x66, 0x3830, dest, arg); |
| 1835 | void XEmitter::PSUBSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE9, dest, arg);} | 2027 | } |
| 1836 | void XEmitter::PSUBUSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD8, dest, arg);} | 2028 | void XEmitter::PMOVZXBD(X64Reg dest, const OpArg& arg) { |
| 1837 | void XEmitter::PSUBUSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD9, dest, arg);} | 2029 | WriteSSE41Op(0x66, 0x3831, dest, arg); |
| 1838 | 2030 | } | |
| 1839 | void XEmitter::PAVGB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE0, dest, arg);} | 2031 | void XEmitter::PMOVZXBQ(X64Reg dest, const OpArg& arg) { |
| 1840 | void XEmitter::PAVGW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE3, dest, arg);} | 2032 | WriteSSE41Op(0x66, 0x3832, dest, arg); |
| 1841 | 2033 | } | |
| 1842 | void XEmitter::PCMPEQB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x74, dest, arg);} | 2034 | void XEmitter::PMOVZXWD(X64Reg dest, const OpArg& arg) { |
| 1843 | void XEmitter::PCMPEQW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x75, dest, arg);} | 2035 | WriteSSE41Op(0x66, 0x3833, dest, arg); |
| 1844 | void XEmitter::PCMPEQD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x76, dest, arg);} | 2036 | } |
| 1845 | 2037 | void XEmitter::PMOVZXWQ(X64Reg dest, const OpArg& arg) { | |
| 1846 | void XEmitter::PCMPGTB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x64, dest, arg);} | 2038 | WriteSSE41Op(0x66, 0x3834, dest, arg); |
| 1847 | void XEmitter::PCMPGTW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x65, dest, arg);} | 2039 | } |
| 1848 | void XEmitter::PCMPGTD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x66, dest, arg);} | 2040 | void XEmitter::PMOVZXDQ(X64Reg dest, const OpArg& arg) { |
| 1849 | 2041 | WriteSSE41Op(0x66, 0x3835, dest, arg); | |
| 1850 | void XEmitter::PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSEOp(0x66, 0xC5, dest, arg, 1); Write8(subreg);} | 2042 | } |
| 1851 | void XEmitter::PINSRW(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSEOp(0x66, 0xC4, dest, arg, 1); Write8(subreg);} | 2043 | |
| 1852 | 2044 | void XEmitter::PBLENDVB(X64Reg dest, const OpArg& arg) { | |
| 1853 | void XEmitter::PMADDWD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF5, dest, arg); } | 2045 | WriteSSE41Op(0x66, 0x3810, dest, arg); |
| 1854 | void XEmitter::PSADBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF6, dest, arg);} | 2046 | } |
| 1855 | 2047 | void XEmitter::BLENDVPS(X64Reg dest, const OpArg& arg) { | |
| 1856 | void XEmitter::PMAXSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEE, dest, arg); } | 2048 | WriteSSE41Op(0x66, 0x3814, dest, arg); |
| 1857 | void XEmitter::PMAXUB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDE, dest, arg); } | 2049 | } |
| 1858 | void XEmitter::PMINSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEA, dest, arg); } | 2050 | void XEmitter::BLENDVPD(X64Reg dest, const OpArg& arg) { |
| 1859 | void XEmitter::PMINUB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDA, dest, arg); } | 2051 | WriteSSE41Op(0x66, 0x3815, dest, arg); |
| 1860 | 2052 | } | |
| 1861 | void XEmitter::PMOVMSKB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD7, dest, arg); } | 2053 | 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);} | 2054 | 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);} | 2055 | Write8(blend); |
| 1864 | void XEmitter::PSHUFHW(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0xF3, 0x70, regOp, arg, 1); Write8(shuffle);} | 2056 | } |
| 2057 | void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) { | ||
| 2058 | WriteSSE41Op(0x66, 0x3A0D, dest, arg, 1); | ||
| 2059 | Write8(blend); | ||
| 2060 | } | ||
| 2061 | |||
| 2062 | void XEmitter::ROUNDSS(X64Reg dest, const OpArg& arg, u8 mode) { | ||
| 2063 | WriteSSE41Op(0x66, 0x3A0A, dest, arg, 1); | ||
| 2064 | Write8(mode); | ||
| 2065 | } | ||
| 2066 | void XEmitter::ROUNDSD(X64Reg dest, const OpArg& arg, u8 mode) { | ||
| 2067 | WriteSSE41Op(0x66, 0x3A0B, dest, arg, 1); | ||
| 2068 | Write8(mode); | ||
| 2069 | } | ||
| 2070 | void XEmitter::ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode) { | ||
| 2071 | WriteSSE41Op(0x66, 0x3A08, dest, arg, 1); | ||
| 2072 | Write8(mode); | ||
| 2073 | } | ||
| 2074 | void XEmitter::ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode) { | ||
| 2075 | WriteSSE41Op(0x66, 0x3A09, dest, arg, 1); | ||
| 2076 | Write8(mode); | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | void XEmitter::PAND(X64Reg dest, const OpArg& arg) { | ||
| 2080 | WriteSSEOp(0x66, 0xDB, dest, arg); | ||
| 2081 | } | ||
| 2082 | void XEmitter::PANDN(X64Reg dest, const OpArg& arg) { | ||
| 2083 | WriteSSEOp(0x66, 0xDF, dest, arg); | ||
| 2084 | } | ||
| 2085 | void XEmitter::PXOR(X64Reg dest, const OpArg& arg) { | ||
| 2086 | WriteSSEOp(0x66, 0xEF, dest, arg); | ||
| 2087 | } | ||
| 2088 | void XEmitter::POR(X64Reg dest, const OpArg& arg) { | ||
| 2089 | WriteSSEOp(0x66, 0xEB, dest, arg); | ||
| 2090 | } | ||
| 2091 | |||
| 2092 | void XEmitter::PADDB(X64Reg dest, const OpArg& arg) { | ||
| 2093 | WriteSSEOp(0x66, 0xFC, dest, arg); | ||
| 2094 | } | ||
| 2095 | void XEmitter::PADDW(X64Reg dest, const OpArg& arg) { | ||
| 2096 | WriteSSEOp(0x66, 0xFD, dest, arg); | ||
| 2097 | } | ||
| 2098 | void XEmitter::PADDD(X64Reg dest, const OpArg& arg) { | ||
| 2099 | WriteSSEOp(0x66, 0xFE, dest, arg); | ||
| 2100 | } | ||
| 2101 | void XEmitter::PADDQ(X64Reg dest, const OpArg& arg) { | ||
| 2102 | WriteSSEOp(0x66, 0xD4, dest, arg); | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | void XEmitter::PADDSB(X64Reg dest, const OpArg& arg) { | ||
| 2106 | WriteSSEOp(0x66, 0xEC, dest, arg); | ||
| 2107 | } | ||
| 2108 | void XEmitter::PADDSW(X64Reg dest, const OpArg& arg) { | ||
| 2109 | WriteSSEOp(0x66, 0xED, dest, arg); | ||
| 2110 | } | ||
| 2111 | void XEmitter::PADDUSB(X64Reg dest, const OpArg& arg) { | ||
| 2112 | WriteSSEOp(0x66, 0xDC, dest, arg); | ||
| 2113 | } | ||
| 2114 | void XEmitter::PADDUSW(X64Reg dest, const OpArg& arg) { | ||
| 2115 | WriteSSEOp(0x66, 0xDD, dest, arg); | ||
| 2116 | } | ||
| 2117 | |||
| 2118 | void XEmitter::PSUBB(X64Reg dest, const OpArg& arg) { | ||
| 2119 | WriteSSEOp(0x66, 0xF8, dest, arg); | ||
| 2120 | } | ||
| 2121 | void XEmitter::PSUBW(X64Reg dest, const OpArg& arg) { | ||
| 2122 | WriteSSEOp(0x66, 0xF9, dest, arg); | ||
| 2123 | } | ||
| 2124 | void XEmitter::PSUBD(X64Reg dest, const OpArg& arg) { | ||
| 2125 | WriteSSEOp(0x66, 0xFA, dest, arg); | ||
| 2126 | } | ||
| 2127 | void XEmitter::PSUBQ(X64Reg dest, const OpArg& arg) { | ||
| 2128 | WriteSSEOp(0x66, 0xFB, dest, arg); | ||
| 2129 | } | ||
| 2130 | |||
| 2131 | void XEmitter::PSUBSB(X64Reg dest, const OpArg& arg) { | ||
| 2132 | WriteSSEOp(0x66, 0xE8, dest, arg); | ||
| 2133 | } | ||
| 2134 | void XEmitter::PSUBSW(X64Reg dest, const OpArg& arg) { | ||
| 2135 | WriteSSEOp(0x66, 0xE9, dest, arg); | ||
| 2136 | } | ||
| 2137 | void XEmitter::PSUBUSB(X64Reg dest, const OpArg& arg) { | ||
| 2138 | WriteSSEOp(0x66, 0xD8, dest, arg); | ||
| 2139 | } | ||
| 2140 | void XEmitter::PSUBUSW(X64Reg dest, const OpArg& arg) { | ||
| 2141 | WriteSSEOp(0x66, 0xD9, dest, arg); | ||
| 2142 | } | ||
| 2143 | |||
| 2144 | void XEmitter::PAVGB(X64Reg dest, const OpArg& arg) { | ||
| 2145 | WriteSSEOp(0x66, 0xE0, dest, arg); | ||
| 2146 | } | ||
| 2147 | void XEmitter::PAVGW(X64Reg dest, const OpArg& arg) { | ||
| 2148 | WriteSSEOp(0x66, 0xE3, dest, arg); | ||
| 2149 | } | ||
| 2150 | |||
| 2151 | void XEmitter::PCMPEQB(X64Reg dest, const OpArg& arg) { | ||
| 2152 | WriteSSEOp(0x66, 0x74, dest, arg); | ||
| 2153 | } | ||
| 2154 | void XEmitter::PCMPEQW(X64Reg dest, const OpArg& arg) { | ||
| 2155 | WriteSSEOp(0x66, 0x75, dest, arg); | ||
| 2156 | } | ||
| 2157 | void XEmitter::PCMPEQD(X64Reg dest, const OpArg& arg) { | ||
| 2158 | WriteSSEOp(0x66, 0x76, dest, arg); | ||
| 2159 | } | ||
| 2160 | |||
| 2161 | void XEmitter::PCMPGTB(X64Reg dest, const OpArg& arg) { | ||
| 2162 | WriteSSEOp(0x66, 0x64, dest, arg); | ||
| 2163 | } | ||
| 2164 | void XEmitter::PCMPGTW(X64Reg dest, const OpArg& arg) { | ||
| 2165 | WriteSSEOp(0x66, 0x65, dest, arg); | ||
| 2166 | } | ||
| 2167 | void XEmitter::PCMPGTD(X64Reg dest, const OpArg& arg) { | ||
| 2168 | WriteSSEOp(0x66, 0x66, dest, arg); | ||
| 2169 | } | ||
| 2170 | |||
| 2171 | void XEmitter::PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg) { | ||
| 2172 | WriteSSEOp(0x66, 0xC5, dest, arg, 1); | ||
| 2173 | Write8(subreg); | ||
| 2174 | } | ||
| 2175 | void XEmitter::PINSRW(X64Reg dest, const OpArg& arg, u8 subreg) { | ||
| 2176 | WriteSSEOp(0x66, 0xC4, dest, arg, 1); | ||
| 2177 | Write8(subreg); | ||
| 2178 | } | ||
| 2179 | |||
| 2180 | void XEmitter::PMADDWD(X64Reg dest, const OpArg& arg) { | ||
| 2181 | WriteSSEOp(0x66, 0xF5, dest, arg); | ||
| 2182 | } | ||
| 2183 | void XEmitter::PSADBW(X64Reg dest, const OpArg& arg) { | ||
| 2184 | WriteSSEOp(0x66, 0xF6, dest, arg); | ||
| 2185 | } | ||
| 2186 | |||
| 2187 | void XEmitter::PMAXSW(X64Reg dest, const OpArg& arg) { | ||
| 2188 | WriteSSEOp(0x66, 0xEE, dest, arg); | ||
| 2189 | } | ||
| 2190 | void XEmitter::PMAXUB(X64Reg dest, const OpArg& arg) { | ||
| 2191 | WriteSSEOp(0x66, 0xDE, dest, arg); | ||
| 2192 | } | ||
| 2193 | void XEmitter::PMINSW(X64Reg dest, const OpArg& arg) { | ||
| 2194 | WriteSSEOp(0x66, 0xEA, dest, arg); | ||
| 2195 | } | ||
| 2196 | void XEmitter::PMINUB(X64Reg dest, const OpArg& arg) { | ||
| 2197 | WriteSSEOp(0x66, 0xDA, dest, arg); | ||
| 2198 | } | ||
| 2199 | |||
| 2200 | void XEmitter::PMOVMSKB(X64Reg dest, const OpArg& arg) { | ||
| 2201 | WriteSSEOp(0x66, 0xD7, dest, arg); | ||
| 2202 | } | ||
| 2203 | void XEmitter::PSHUFD(X64Reg regOp, const OpArg& arg, u8 shuffle) { | ||
| 2204 | WriteSSEOp(0x66, 0x70, regOp, arg, 1); | ||
| 2205 | Write8(shuffle); | ||
| 2206 | } | ||
| 2207 | void XEmitter::PSHUFLW(X64Reg regOp, const OpArg& arg, u8 shuffle) { | ||
| 2208 | WriteSSEOp(0xF2, 0x70, regOp, arg, 1); | ||
| 2209 | Write8(shuffle); | ||
| 2210 | } | ||
| 2211 | void XEmitter::PSHUFHW(X64Reg regOp, const OpArg& arg, u8 shuffle) { | ||
| 2212 | WriteSSEOp(0xF3, 0x70, regOp, arg, 1); | ||
| 2213 | Write8(shuffle); | ||
| 2214 | } | ||
| 1865 | 2215 | ||
| 1866 | // VEX | 2216 | // VEX |
| 1867 | void XEmitter::VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseADD, regOp1, regOp2, arg);} | 2217 | 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);} | 2218 | WriteAVXOp(0xF2, sseADD, regOp1, regOp2, arg); |
| 1869 | void XEmitter::VMULSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseMUL, regOp1, regOp2, arg);} | 2219 | } |
| 1870 | void XEmitter::VDIVSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseDIV, regOp1, regOp2, arg);} | 2220 | 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);} | 2221 | WriteAVXOp(0xF2, sseSUB, regOp1, regOp2, arg); |
| 1872 | void XEmitter::VSUBPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseSUB, regOp1, regOp2, arg);} | 2222 | } |
| 1873 | void XEmitter::VMULPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseMUL, regOp1, regOp2, arg);} | 2223 | 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);} | 2224 | WriteAVXOp(0xF2, sseMUL, regOp1, regOp2, arg); |
| 1875 | void XEmitter::VSQRTSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseSQRT, regOp1, regOp2, arg);} | 2225 | } |
| 1876 | void XEmitter::VSHUFPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 shuffle) {WriteAVXOp(0x66, sseSHUF, regOp1, regOp2, arg, 1); Write8(shuffle);} | 2226 | 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);} | 2227 | WriteAVXOp(0xF2, sseDIV, regOp1, regOp2, arg); |
| 1878 | void XEmitter::VUNPCKHPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg){WriteAVXOp(0x66, 0x15, regOp1, regOp2, arg);} | 2228 | } |
| 1879 | 2229 | 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); } | 2230 | WriteAVXOp(0x66, sseADD, regOp1, regOp2, arg); |
| 1881 | void XEmitter::VANDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseAND, regOp1, regOp2, arg); } | 2231 | } |
| 1882 | void XEmitter::VANDNPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseANDN, regOp1, regOp2, arg); } | 2232 | 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); } | 2233 | WriteAVXOp(0x66, sseSUB, regOp1, regOp2, arg); |
| 1884 | void XEmitter::VORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseOR, regOp1, regOp2, arg); } | 2234 | } |
| 1885 | void XEmitter::VORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseOR, regOp1, regOp2, arg); } | 2235 | 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); } | 2236 | WriteAVXOp(0x66, sseMUL, regOp1, regOp2, arg); |
| 1887 | void XEmitter::VXORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseXOR, regOp1, regOp2, arg); } | 2237 | } |
| 1888 | 2238 | 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); } | 2239 | WriteAVXOp(0x66, sseDIV, regOp1, regOp2, arg); |
| 1890 | void XEmitter::VPANDN(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xDF, regOp1, regOp2, arg); } | 2240 | } |
| 1891 | void XEmitter::VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xEB, regOp1, regOp2, arg); } | 2241 | 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); } | 2242 | WriteAVXOp(0xF2, sseSQRT, regOp1, regOp2, arg); |
| 1893 | 2243 | } | |
| 1894 | void XEmitter::VFMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg); } | 2244 | 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); } | 2245 | WriteAVXOp(0x66, sseSHUF, regOp1, regOp2, arg, 1); |
| 1896 | void XEmitter::VFMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg); } | 2246 | Write8(shuffle); |
| 1897 | void XEmitter::VFMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg, 1); } | 2247 | } |
| 1898 | void XEmitter::VFMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg, 1); } | 2248 | 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); } | 2249 | WriteAVXOp(0x66, 0x14, regOp1, regOp2, arg); |
| 1900 | void XEmitter::VFMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg); } | 2250 | } |
| 1901 | void XEmitter::VFMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg); } | 2251 | 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); } | 2252 | WriteAVXOp(0x66, 0x15, regOp1, regOp2, arg); |
| 1903 | void XEmitter::VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg, 1); } | 2253 | } |
| 1904 | void XEmitter::VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg, 1); } | 2254 | |
| 1905 | void XEmitter::VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg, 1); } | 2255 | 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); } | 2256 | WriteAVXOp(0x00, sseAND, regOp1, regOp2, arg); |
| 1907 | void XEmitter::VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg); } | 2257 | } |
| 1908 | void XEmitter::VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg); } | 2258 | 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); } | 2259 | WriteAVXOp(0x66, sseAND, regOp1, regOp2, arg); |
| 1910 | void XEmitter::VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg, 1); } | 2260 | } |
| 1911 | void XEmitter::VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg, 1); } | 2261 | 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); } | 2262 | WriteAVXOp(0x00, sseANDN, regOp1, regOp2, arg); |
| 1913 | void XEmitter::VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg); } | 2263 | } |
| 1914 | void XEmitter::VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg); } | 2264 | 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); } | 2265 | WriteAVXOp(0x66, sseANDN, regOp1, regOp2, arg); |
| 1916 | void XEmitter::VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg, 1); } | 2266 | } |
| 1917 | void XEmitter::VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg, 1); } | 2267 | 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); } | 2268 | WriteAVXOp(0x00, sseOR, regOp1, regOp2, arg); |
| 1919 | void XEmitter::VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg); } | 2269 | } |
| 1920 | void XEmitter::VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg); } | 2270 | 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); } | 2271 | WriteAVXOp(0x66, sseOR, regOp1, regOp2, arg); |
| 1922 | void XEmitter::VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg, 1); } | 2272 | } |
| 1923 | void XEmitter::VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg, 1); } | 2273 | 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); } | 2274 | WriteAVXOp(0x00, sseXOR, regOp1, regOp2, arg); |
| 1925 | void XEmitter::VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg); } | 2275 | } |
| 1926 | void XEmitter::VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg); } | 2276 | 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); } | 2277 | WriteAVXOp(0x66, sseXOR, regOp1, regOp2, arg); |
| 1928 | void XEmitter::VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg, 1); } | 2278 | } |
| 1929 | void XEmitter::VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg, 1); } | 2279 | |
| 1930 | void XEmitter::VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg); } | 2280 | 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); } | 2281 | WriteAVXOp(0x66, 0xDB, regOp1, regOp2, arg); |
| 1932 | void XEmitter::VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg); } | 2282 | } |
| 1933 | void XEmitter::VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg, 1); } | 2283 | 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); } | 2284 | WriteAVXOp(0x66, 0xDF, regOp1, regOp2, arg); |
| 1935 | void XEmitter::VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg, 1); } | 2285 | } |
| 1936 | void XEmitter::VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg); } | 2286 | 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); } | 2287 | WriteAVXOp(0x66, 0xEB, regOp1, regOp2, arg); |
| 1938 | void XEmitter::VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg); } | 2288 | } |
| 1939 | void XEmitter::VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg, 1); } | 2289 | 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); } | 2290 | WriteAVXOp(0x66, 0xEF, regOp1, regOp2, arg); |
| 1941 | void XEmitter::VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg, 1); } | 2291 | } |
| 1942 | void XEmitter::VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg); } | 2292 | |
| 1943 | void XEmitter::VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg); } | 2293 | 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); } | 2294 | WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg); |
| 1945 | void XEmitter::VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg, 1); } | 2295 | } |
| 1946 | void XEmitter::VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg, 1); } | 2296 | 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); } | 2297 | WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg); |
| 1948 | void XEmitter::VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg); } | 2298 | } |
| 1949 | void XEmitter::VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg); } | 2299 | 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); } | 2300 | WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg); |
| 1951 | void XEmitter::VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg, 1); } | 2301 | } |
| 1952 | void XEmitter::VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg, 1); } | 2302 | 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); } | 2303 | WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg, 1); |
| 1954 | 2304 | } | |
| 1955 | void XEmitter::SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0xF3, 0x38F7, regOp1, regOp2, arg);} | 2305 | 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);} | 2306 | 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);} | 2307 | } |
| 1958 | void XEmitter::RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate) {WriteBMI2Op(bits, 0xF2, 0x3AF0, regOp, INVALID_REG, arg, 1); Write8(rotate);} | 2308 | 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);} | 2309 | 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);} | 2310 | } |
| 1961 | void XEmitter::MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI2Op(bits, 0xF2, 0x38F6, regOp2, regOp1, arg);} | 2311 | 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);} | 2312 | 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);} | 2313 | } |
| 1964 | void XEmitter::BLSMSK(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x2, regOp, arg);} | 2314 | 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);} | 2315 | 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);} | 2316 | } |
| 1967 | void XEmitter::ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F2, regOp1, regOp2, arg);} | 2317 | void XEmitter::VFMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { |
| 2318 | WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg); | ||
| 2319 | } | ||
| 2320 | void XEmitter::VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2321 | WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg, 1); | ||
| 2322 | } | ||
| 2323 | void XEmitter::VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2324 | WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg, 1); | ||
| 2325 | } | ||
| 2326 | void XEmitter::VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2327 | WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg, 1); | ||
| 2328 | } | ||
| 2329 | void XEmitter::VFMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2330 | WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg); | ||
| 2331 | } | ||
| 2332 | void XEmitter::VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2333 | WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg); | ||
| 2334 | } | ||
| 2335 | void XEmitter::VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2336 | WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg); | ||
| 2337 | } | ||
| 2338 | void XEmitter::VFMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2339 | WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg, 1); | ||
| 2340 | } | ||
| 2341 | void XEmitter::VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2342 | WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg, 1); | ||
| 2343 | } | ||
| 2344 | void XEmitter::VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2345 | WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg, 1); | ||
| 2346 | } | ||
| 2347 | void XEmitter::VFMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2348 | WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg); | ||
| 2349 | } | ||
| 2350 | void XEmitter::VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2351 | WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg); | ||
| 2352 | } | ||
| 2353 | void XEmitter::VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2354 | WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg); | ||
| 2355 | } | ||
| 2356 | void XEmitter::VFMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2357 | WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg, 1); | ||
| 2358 | } | ||
| 2359 | void XEmitter::VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2360 | WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg, 1); | ||
| 2361 | } | ||
| 2362 | void XEmitter::VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2363 | WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg, 1); | ||
| 2364 | } | ||
| 2365 | void XEmitter::VFNMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2366 | WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg); | ||
| 2367 | } | ||
| 2368 | void XEmitter::VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2369 | WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg); | ||
| 2370 | } | ||
| 2371 | void XEmitter::VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2372 | WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg); | ||
| 2373 | } | ||
| 2374 | void XEmitter::VFNMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2375 | WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg, 1); | ||
| 2376 | } | ||
| 2377 | void XEmitter::VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2378 | WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg, 1); | ||
| 2379 | } | ||
| 2380 | void XEmitter::VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2381 | WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg, 1); | ||
| 2382 | } | ||
| 2383 | void XEmitter::VFNMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2384 | WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg); | ||
| 2385 | } | ||
| 2386 | void XEmitter::VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2387 | WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg); | ||
| 2388 | } | ||
| 2389 | void XEmitter::VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2390 | WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg); | ||
| 2391 | } | ||
| 2392 | void XEmitter::VFNMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2393 | WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg, 1); | ||
| 2394 | } | ||
| 2395 | void XEmitter::VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2396 | WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg, 1); | ||
| 2397 | } | ||
| 2398 | void XEmitter::VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2399 | WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg, 1); | ||
| 2400 | } | ||
| 2401 | void XEmitter::VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2402 | WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg); | ||
| 2403 | } | ||
| 2404 | void XEmitter::VFNMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2405 | WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg); | ||
| 2406 | } | ||
| 2407 | void XEmitter::VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2408 | WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg); | ||
| 2409 | } | ||
| 2410 | void XEmitter::VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2411 | WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg, 1); | ||
| 2412 | } | ||
| 2413 | void XEmitter::VFNMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2414 | WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg, 1); | ||
| 2415 | } | ||
| 2416 | void XEmitter::VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2417 | WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg, 1); | ||
| 2418 | } | ||
| 2419 | void XEmitter::VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2420 | WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg); | ||
| 2421 | } | ||
| 2422 | void XEmitter::VFNMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2423 | WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg); | ||
| 2424 | } | ||
| 2425 | void XEmitter::VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2426 | WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg); | ||
| 2427 | } | ||
| 2428 | void XEmitter::VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2429 | WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg, 1); | ||
| 2430 | } | ||
| 2431 | void XEmitter::VFNMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2432 | WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg, 1); | ||
| 2433 | } | ||
| 2434 | void XEmitter::VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2435 | WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg, 1); | ||
| 2436 | } | ||
| 2437 | void XEmitter::VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2438 | WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg); | ||
| 2439 | } | ||
| 2440 | void XEmitter::VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2441 | WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg); | ||
| 2442 | } | ||
| 2443 | void XEmitter::VFMADDSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2444 | WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg); | ||
| 2445 | } | ||
| 2446 | void XEmitter::VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2447 | WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg, 1); | ||
| 2448 | } | ||
| 2449 | void XEmitter::VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2450 | WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg, 1); | ||
| 2451 | } | ||
| 2452 | void XEmitter::VFMADDSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2453 | WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg, 1); | ||
| 2454 | } | ||
| 2455 | void XEmitter::VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2456 | WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg); | ||
| 2457 | } | ||
| 2458 | void XEmitter::VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2459 | WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg); | ||
| 2460 | } | ||
| 2461 | void XEmitter::VFMSUBADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2462 | WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg); | ||
| 2463 | } | ||
| 2464 | void XEmitter::VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2465 | WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg, 1); | ||
| 2466 | } | ||
| 2467 | void XEmitter::VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2468 | WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg, 1); | ||
| 2469 | } | ||
| 2470 | void XEmitter::VFMSUBADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2471 | WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg, 1); | ||
| 2472 | } | ||
| 2473 | |||
| 2474 | void XEmitter::SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) { | ||
| 2475 | WriteBMI2Op(bits, 0xF3, 0x38F7, regOp1, regOp2, arg); | ||
| 2476 | } | ||
| 2477 | void XEmitter::SHLX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) { | ||
| 2478 | WriteBMI2Op(bits, 0x66, 0x38F7, regOp1, regOp2, arg); | ||
| 2479 | } | ||
| 2480 | void XEmitter::SHRX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) { | ||
| 2481 | WriteBMI2Op(bits, 0xF2, 0x38F7, regOp1, regOp2, arg); | ||
| 2482 | } | ||
| 2483 | void XEmitter::RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate) { | ||
| 2484 | WriteBMI2Op(bits, 0xF2, 0x3AF0, regOp, INVALID_REG, arg, 1); | ||
| 2485 | Write8(rotate); | ||
| 2486 | } | ||
| 2487 | void XEmitter::PEXT(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2488 | WriteBMI2Op(bits, 0xF3, 0x38F5, regOp1, regOp2, arg); | ||
| 2489 | } | ||
| 2490 | void XEmitter::PDEP(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2491 | WriteBMI2Op(bits, 0xF2, 0x38F5, regOp1, regOp2, arg); | ||
| 2492 | } | ||
| 2493 | void XEmitter::MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2494 | WriteBMI2Op(bits, 0xF2, 0x38F6, regOp2, regOp1, arg); | ||
| 2495 | } | ||
| 2496 | void XEmitter::BZHI(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) { | ||
| 2497 | WriteBMI2Op(bits, 0x00, 0x38F5, regOp1, regOp2, arg); | ||
| 2498 | } | ||
| 2499 | void XEmitter::BLSR(int bits, X64Reg regOp, const OpArg& arg) { | ||
| 2500 | WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x1, regOp, arg); | ||
| 2501 | } | ||
| 2502 | void XEmitter::BLSMSK(int bits, X64Reg regOp, const OpArg& arg) { | ||
| 2503 | WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x2, regOp, arg); | ||
| 2504 | } | ||
| 2505 | void XEmitter::BLSI(int bits, X64Reg regOp, const OpArg& arg) { | ||
| 2506 | WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x3, regOp, arg); | ||
| 2507 | } | ||
| 2508 | void XEmitter::BEXTR(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) { | ||
| 2509 | WriteBMI1Op(bits, 0x00, 0x38F7, regOp1, regOp2, arg); | ||
| 2510 | } | ||
| 2511 | void XEmitter::ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { | ||
| 2512 | WriteBMI1Op(bits, 0x00, 0x38F2, regOp1, regOp2, arg); | ||
| 2513 | } | ||
| 1968 | 2514 | ||
| 1969 | // Prefixes | 2515 | // Prefixes |
| 1970 | 2516 | ||
| 1971 | void XEmitter::LOCK() { Write8(0xF0); } | 2517 | void XEmitter::LOCK() { |
| 1972 | void XEmitter::REP() { Write8(0xF3); } | 2518 | Write8(0xF0); |
| 1973 | void XEmitter::REPNE() { Write8(0xF2); } | 2519 | } |
| 1974 | void XEmitter::FSOverride() { Write8(0x64); } | 2520 | void XEmitter::REP() { |
| 1975 | void XEmitter::GSOverride() { Write8(0x65); } | 2521 | Write8(0xF3); |
| 2522 | } | ||
| 2523 | void XEmitter::REPNE() { | ||
| 2524 | Write8(0xF2); | ||
| 2525 | } | ||
| 2526 | void XEmitter::FSOverride() { | ||
| 2527 | Write8(0x64); | ||
| 2528 | } | ||
| 2529 | void XEmitter::GSOverride() { | ||
| 2530 | Write8(0x65); | ||
| 2531 | } | ||
| 1976 | 2532 | ||
| 1977 | void XEmitter::FWAIT() | 2533 | void XEmitter::FWAIT() { |
| 1978 | { | ||
| 1979 | Write8(0x9B); | 2534 | Write8(0x9B); |
| 1980 | } | 2535 | } |
| 1981 | 2536 | ||
| 1982 | // TODO: make this more generic | 2537 | // TODO: make this more generic |
| 1983 | void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg) | 2538 | void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg) { |
| 1984 | { | ||
| 1985 | int mf = 0; | 2539 | int mf = 0; |
| 1986 | ASSERT_MSG(!(bits == 80 && op_80b == floatINVALID), "WriteFloatLoadStore: 80 bits not supported for this instruction"); | 2540 | ASSERT_MSG(!(bits == 80 && op_80b == floatINVALID), |
| 1987 | switch (bits) | 2541 | "WriteFloatLoadStore: 80 bits not supported for this instruction"); |
| 1988 | { | 2542 | switch (bits) { |
| 1989 | case 32: mf = 0; break; | 2543 | case 32: |
| 1990 | case 64: mf = 4; break; | 2544 | mf = 0; |
| 1991 | case 80: mf = 2; break; | 2545 | break; |
| 1992 | default: ASSERT_MSG(0, "WriteFloatLoadStore: invalid bits (should be 32/64/80)"); | 2546 | case 64: |
| 2547 | mf = 4; | ||
| 2548 | break; | ||
| 2549 | case 80: | ||
| 2550 | mf = 2; | ||
| 2551 | break; | ||
| 2552 | default: | ||
| 2553 | ASSERT_MSG(0, "WriteFloatLoadStore: invalid bits (should be 32/64/80)"); | ||
| 1993 | } | 2554 | } |
| 1994 | Write8(0xd9 | mf); | 2555 | Write8(0xd9 | mf); |
| 1995 | // x87 instructions use the reg field of the ModR/M byte as opcode: | 2556 | // x87 instructions use the reg field of the ModR/M byte as opcode: |
| 1996 | if (bits == 80) | 2557 | if (bits == 80) |
| 1997 | op = op_80b; | 2558 | op = op_80b; |
| 1998 | arg.WriteRest(this, 0, (X64Reg) op); | 2559 | arg.WriteRest(this, 0, (X64Reg)op); |
| 1999 | } | 2560 | } |
| 2000 | 2561 | ||
| 2001 | void XEmitter::FLD(int bits, const OpArg& src) {WriteFloatLoadStore(bits, floatLD, floatLD80, src);} | 2562 | void XEmitter::FLD(int bits, const OpArg& src) { |
| 2002 | void XEmitter::FST(int bits, const OpArg& dest) {WriteFloatLoadStore(bits, floatST, floatINVALID, dest);} | 2563 | WriteFloatLoadStore(bits, floatLD, floatLD80, src); |
| 2003 | void XEmitter::FSTP(int bits, const OpArg& dest) {WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest);} | 2564 | } |
| 2004 | void XEmitter::FNSTSW_AX() { Write8(0xDF); Write8(0xE0); } | 2565 | void XEmitter::FST(int bits, const OpArg& dest) { |
| 2566 | WriteFloatLoadStore(bits, floatST, floatINVALID, dest); | ||
| 2567 | } | ||
| 2568 | void XEmitter::FSTP(int bits, const OpArg& dest) { | ||
| 2569 | WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest); | ||
| 2570 | } | ||
| 2571 | void XEmitter::FNSTSW_AX() { | ||
| 2572 | Write8(0xDF); | ||
| 2573 | Write8(0xE0); | ||
| 2574 | } | ||
| 2005 | 2575 | ||
| 2006 | void XEmitter::RDTSC() { Write8(0x0F); Write8(0x31); } | 2576 | void XEmitter::RDTSC() { |
| 2577 | Write8(0x0F); | ||
| 2578 | Write8(0x31); | ||
| 2579 | } | ||
| 2007 | 2580 | ||
| 2008 | void XCodeBlock::PoisonMemory() { | 2581 | void XCodeBlock::PoisonMemory() { |
| 2009 | // x86/64: 0xCC = breakpoint | 2582 | // x86/64: 0xCC = breakpoint |
| 2010 | memset(region, 0xCC, region_size); | 2583 | memset(region, 0xCC, region_size); |
| 2011 | } | 2584 | } |
| 2012 | |||
| 2013 | } | 2585 | } |
diff --git a/src/common/x64/emitter.h b/src/common/x64/emitter.h index 60a77dfe1..467f7812f 100644 --- a/src/common/x64/emitter.h +++ b/src/common/x64/emitter.h | |||
| @@ -21,8 +21,8 @@ | |||
| 21 | 21 | ||
| 22 | #include "common/assert.h" | 22 | #include "common/assert.h" |
| 23 | #include "common/bit_set.h" | 23 | #include "common/bit_set.h" |
| 24 | #include "common/common_types.h" | ||
| 25 | #include "common/code_block.h" | 24 | #include "common/code_block.h" |
| 25 | #include "common/common_types.h" | ||
| 26 | 26 | ||
| 27 | #if defined(ARCHITECTURE_x86_64) && !defined(_ARCH_64) | 27 | #if defined(ARCHITECTURE_x86_64) && !defined(_ARCH_64) |
| 28 | #define _ARCH_64 | 28 | #define _ARCH_64 |
| @@ -34,75 +34,145 @@ | |||
| 34 | #define PTRBITS 32 | 34 | #define PTRBITS 32 |
| 35 | #endif | 35 | #endif |
| 36 | 36 | ||
| 37 | namespace Gen | 37 | namespace Gen { |
| 38 | { | 38 | |
| 39 | 39 | enum X64Reg { | |
| 40 | enum X64Reg | 40 | EAX = 0, |
| 41 | { | 41 | EBX = 3, |
| 42 | EAX = 0, EBX = 3, ECX = 1, EDX = 2, | 42 | ECX = 1, |
| 43 | ESI = 6, EDI = 7, EBP = 5, ESP = 4, | 43 | EDX = 2, |
| 44 | 44 | ESI = 6, | |
| 45 | RAX = 0, RBX = 3, RCX = 1, RDX = 2, | 45 | EDI = 7, |
| 46 | RSI = 6, RDI = 7, RBP = 5, RSP = 4, | 46 | EBP = 5, |
| 47 | R8 = 8, R9 = 9, R10 = 10,R11 = 11, | 47 | ESP = 4, |
| 48 | R12 = 12,R13 = 13,R14 = 14,R15 = 15, | 48 | |
| 49 | 49 | RAX = 0, | |
| 50 | AL = 0, BL = 3, CL = 1, DL = 2, | 50 | RBX = 3, |
| 51 | SIL = 6, DIL = 7, BPL = 5, SPL = 4, | 51 | RCX = 1, |
| 52 | AH = 0x104, BH = 0x107, CH = 0x105, DH = 0x106, | 52 | RDX = 2, |
| 53 | 53 | RSI = 6, | |
| 54 | AX = 0, BX = 3, CX = 1, DX = 2, | 54 | RDI = 7, |
| 55 | SI = 6, DI = 7, BP = 5, SP = 4, | 55 | RBP = 5, |
| 56 | 56 | RSP = 4, | |
| 57 | XMM0=0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, | 57 | R8 = 8, |
| 58 | XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, | 58 | R9 = 9, |
| 59 | 59 | R10 = 10, | |
| 60 | YMM0=0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7, | 60 | R11 = 11, |
| 61 | YMM8, YMM9, YMM10, YMM11, YMM12, YMM13, YMM14, YMM15, | 61 | R12 = 12, |
| 62 | R13 = 13, | ||
| 63 | R14 = 14, | ||
| 64 | R15 = 15, | ||
| 65 | |||
| 66 | AL = 0, | ||
| 67 | BL = 3, | ||
| 68 | CL = 1, | ||
| 69 | DL = 2, | ||
| 70 | SIL = 6, | ||
| 71 | DIL = 7, | ||
| 72 | BPL = 5, | ||
| 73 | SPL = 4, | ||
| 74 | AH = 0x104, | ||
| 75 | BH = 0x107, | ||
| 76 | CH = 0x105, | ||
| 77 | DH = 0x106, | ||
| 78 | |||
| 79 | AX = 0, | ||
| 80 | BX = 3, | ||
| 81 | CX = 1, | ||
| 82 | DX = 2, | ||
| 83 | SI = 6, | ||
| 84 | DI = 7, | ||
| 85 | BP = 5, | ||
| 86 | SP = 4, | ||
| 87 | |||
| 88 | XMM0 = 0, | ||
| 89 | XMM1, | ||
| 90 | XMM2, | ||
| 91 | XMM3, | ||
| 92 | XMM4, | ||
| 93 | XMM5, | ||
| 94 | XMM6, | ||
| 95 | XMM7, | ||
| 96 | XMM8, | ||
| 97 | XMM9, | ||
| 98 | XMM10, | ||
| 99 | XMM11, | ||
| 100 | XMM12, | ||
| 101 | XMM13, | ||
| 102 | XMM14, | ||
| 103 | XMM15, | ||
| 104 | |||
| 105 | YMM0 = 0, | ||
| 106 | YMM1, | ||
| 107 | YMM2, | ||
| 108 | YMM3, | ||
| 109 | YMM4, | ||
| 110 | YMM5, | ||
| 111 | YMM6, | ||
| 112 | YMM7, | ||
| 113 | YMM8, | ||
| 114 | YMM9, | ||
| 115 | YMM10, | ||
| 116 | YMM11, | ||
| 117 | YMM12, | ||
| 118 | YMM13, | ||
| 119 | YMM14, | ||
| 120 | YMM15, | ||
| 62 | 121 | ||
| 63 | INVALID_REG = 0xFFFFFFFF | 122 | INVALID_REG = 0xFFFFFFFF |
| 64 | }; | 123 | }; |
| 65 | 124 | ||
| 66 | enum CCFlags | 125 | enum CCFlags { |
| 67 | { | 126 | CC_O = 0, |
| 68 | CC_O = 0, | 127 | CC_NO = 1, |
| 69 | CC_NO = 1, | 128 | CC_B = 2, |
| 70 | CC_B = 2, CC_C = 2, CC_NAE = 2, | 129 | CC_C = 2, |
| 71 | CC_NB = 3, CC_NC = 3, CC_AE = 3, | 130 | CC_NAE = 2, |
| 72 | CC_Z = 4, CC_E = 4, | 131 | CC_NB = 3, |
| 73 | CC_NZ = 5, CC_NE = 5, | 132 | CC_NC = 3, |
| 74 | CC_BE = 6, CC_NA = 6, | 133 | CC_AE = 3, |
| 75 | CC_NBE = 7, CC_A = 7, | 134 | CC_Z = 4, |
| 76 | CC_S = 8, | 135 | CC_E = 4, |
| 77 | CC_NS = 9, | 136 | CC_NZ = 5, |
| 78 | CC_P = 0xA, CC_PE = 0xA, | 137 | CC_NE = 5, |
| 79 | CC_NP = 0xB, CC_PO = 0xB, | 138 | CC_BE = 6, |
| 80 | CC_L = 0xC, CC_NGE = 0xC, | 139 | CC_NA = 6, |
| 81 | CC_NL = 0xD, CC_GE = 0xD, | 140 | CC_NBE = 7, |
| 82 | CC_LE = 0xE, CC_NG = 0xE, | 141 | CC_A = 7, |
| 83 | CC_NLE = 0xF, CC_G = 0xF | 142 | CC_S = 8, |
| 143 | CC_NS = 9, | ||
| 144 | CC_P = 0xA, | ||
| 145 | CC_PE = 0xA, | ||
| 146 | CC_NP = 0xB, | ||
| 147 | CC_PO = 0xB, | ||
| 148 | CC_L = 0xC, | ||
| 149 | CC_NGE = 0xC, | ||
| 150 | CC_NL = 0xD, | ||
| 151 | CC_GE = 0xD, | ||
| 152 | CC_LE = 0xE, | ||
| 153 | CC_NG = 0xE, | ||
| 154 | CC_NLE = 0xF, | ||
| 155 | CC_G = 0xF | ||
| 84 | }; | 156 | }; |
| 85 | 157 | ||
| 86 | enum | 158 | enum { |
| 87 | { | ||
| 88 | NUMGPRs = 16, | 159 | NUMGPRs = 16, |
| 89 | NUMXMMs = 16, | 160 | NUMXMMs = 16, |
| 90 | }; | 161 | }; |
| 91 | 162 | ||
| 92 | enum | 163 | enum { |
| 93 | { | ||
| 94 | SCALE_NONE = 0, | 164 | SCALE_NONE = 0, |
| 95 | SCALE_1 = 1, | 165 | SCALE_1 = 1, |
| 96 | SCALE_2 = 2, | 166 | SCALE_2 = 2, |
| 97 | SCALE_4 = 4, | 167 | SCALE_4 = 4, |
| 98 | SCALE_8 = 8, | 168 | SCALE_8 = 8, |
| 99 | SCALE_ATREG = 16, | 169 | SCALE_ATREG = 16, |
| 100 | //SCALE_NOBASE_1 is not supported and can be replaced with SCALE_ATREG | 170 | // SCALE_NOBASE_1 is not supported and can be replaced with SCALE_ATREG |
| 101 | SCALE_NOBASE_2 = 34, | 171 | SCALE_NOBASE_2 = 34, |
| 102 | SCALE_NOBASE_4 = 36, | 172 | SCALE_NOBASE_4 = 36, |
| 103 | SCALE_NOBASE_8 = 40, | 173 | SCALE_NOBASE_8 = 40, |
| 104 | SCALE_RIP = 0xFF, | 174 | SCALE_RIP = 0xFF, |
| 105 | SCALE_IMM8 = 0xF0, | 175 | SCALE_IMM8 = 0xF0, |
| 106 | SCALE_IMM16 = 0xF1, | 176 | SCALE_IMM16 = 0xF1, |
| 107 | SCALE_IMM32 = 0xF2, | 177 | SCALE_IMM32 = 0xF2, |
| 108 | SCALE_IMM64 = 0xF3, | 178 | SCALE_IMM64 = 0xF3, |
| @@ -114,7 +184,7 @@ enum NormalOp { | |||
| 114 | nrmSUB, | 184 | nrmSUB, |
| 115 | nrmSBB, | 185 | nrmSBB, |
| 116 | nrmAND, | 186 | nrmAND, |
| 117 | nrmOR , | 187 | nrmOR, |
| 118 | nrmXOR, | 188 | nrmXOR, |
| 119 | nrmMOV, | 189 | nrmMOV, |
| 120 | nrmTEST, | 190 | nrmTEST, |
| @@ -157,68 +227,74 @@ enum FloatRound { | |||
| 157 | class XEmitter; | 227 | class XEmitter; |
| 158 | 228 | ||
| 159 | // RIP addressing does not benefit from micro op fusion on Core arch | 229 | // RIP addressing does not benefit from micro op fusion on Core arch |
| 160 | struct OpArg | 230 | struct OpArg { |
| 161 | { | ||
| 162 | friend class XEmitter; | 231 | friend class XEmitter; |
| 163 | 232 | ||
| 164 | constexpr OpArg() = default; // dummy op arg, used for storage | 233 | constexpr OpArg() = default; // dummy op arg, used for storage |
| 165 | constexpr OpArg(u64 offset_, int scale_, X64Reg rmReg = RAX, X64Reg scaledReg = RAX) | 234 | constexpr OpArg(u64 offset_, int scale_, X64Reg rmReg = RAX, X64Reg scaledReg = RAX) |
| 166 | : scale(static_cast<u8>(scale_)) | 235 | : scale(static_cast<u8>(scale_)), offsetOrBaseReg(static_cast<u16>(rmReg)), |
| 167 | , offsetOrBaseReg(static_cast<u16>(rmReg)) | 236 | indexReg(static_cast<u16>(scaledReg)), offset(offset_) { |
| 168 | , indexReg(static_cast<u16>(scaledReg)) | ||
| 169 | , offset(offset_) | ||
| 170 | { | ||
| 171 | } | 237 | } |
| 172 | 238 | ||
| 173 | constexpr bool operator==(const OpArg &b) const | 239 | constexpr bool operator==(const OpArg& b) const { |
| 174 | { | 240 | return operandReg == b.operandReg && scale == b.scale && |
| 175 | return operandReg == b.operandReg && | 241 | 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 | } | 242 | } |
| 181 | 243 | ||
| 182 | void WriteRex(XEmitter *emit, int opBits, int bits, int customOp = -1) const; | 244 | 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; | 245 | 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; | 246 | int W = 0) const; |
| 185 | void WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg operandReg, int bits); | 247 | 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; | 248 | bool warn_64bit_offset = true) const; |
| 187 | 249 | 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; } | 250 | void WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, |
| 189 | constexpr bool IsSimpleReg() const { return scale == SCALE_NONE; } | 251 | int bits) const; |
| 190 | constexpr bool IsSimpleReg(X64Reg reg) const | 252 | |
| 191 | { | 253 | constexpr bool IsImm() const { |
| 254 | return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 || | ||
| 255 | scale == SCALE_IMM64; | ||
| 256 | } | ||
| 257 | constexpr bool IsSimpleReg() const { | ||
| 258 | return scale == SCALE_NONE; | ||
| 259 | } | ||
| 260 | constexpr bool IsSimpleReg(X64Reg reg) const { | ||
| 192 | return IsSimpleReg() && GetSimpleReg() == reg; | 261 | return IsSimpleReg() && GetSimpleReg() == reg; |
| 193 | } | 262 | } |
| 194 | 263 | ||
| 195 | int GetImmBits() const | 264 | int GetImmBits() const { |
| 196 | { | 265 | switch (scale) { |
| 197 | switch (scale) | 266 | case SCALE_IMM8: |
| 198 | { | 267 | return 8; |
| 199 | case SCALE_IMM8: return 8; | 268 | case SCALE_IMM16: |
| 200 | case SCALE_IMM16: return 16; | 269 | return 16; |
| 201 | case SCALE_IMM32: return 32; | 270 | case SCALE_IMM32: |
| 202 | case SCALE_IMM64: return 64; | 271 | return 32; |
| 203 | default: return -1; | 272 | case SCALE_IMM64: |
| 273 | return 64; | ||
| 274 | default: | ||
| 275 | return -1; | ||
| 204 | } | 276 | } |
| 205 | } | 277 | } |
| 206 | 278 | ||
| 207 | void SetImmBits(int bits) { | 279 | void SetImmBits(int bits) { |
| 208 | switch (bits) | 280 | switch (bits) { |
| 209 | { | 281 | case 8: |
| 210 | case 8: scale = SCALE_IMM8; break; | 282 | scale = SCALE_IMM8; |
| 211 | case 16: scale = SCALE_IMM16; break; | 283 | break; |
| 212 | case 32: scale = SCALE_IMM32; break; | 284 | case 16: |
| 213 | case 64: scale = SCALE_IMM64; break; | 285 | scale = SCALE_IMM16; |
| 286 | break; | ||
| 287 | case 32: | ||
| 288 | scale = SCALE_IMM32; | ||
| 289 | break; | ||
| 290 | case 64: | ||
| 291 | scale = SCALE_IMM64; | ||
| 292 | break; | ||
| 214 | } | 293 | } |
| 215 | } | 294 | } |
| 216 | 295 | ||
| 217 | constexpr X64Reg GetSimpleReg() const | 296 | constexpr X64Reg GetSimpleReg() const { |
| 218 | { | 297 | return scale == SCALE_NONE ? static_cast<X64Reg>(offsetOrBaseReg) : INVALID_REG; |
| 219 | return scale == SCALE_NONE | ||
| 220 | ? static_cast<X64Reg>(offsetOrBaseReg) | ||
| 221 | : INVALID_REG; | ||
| 222 | } | 298 | } |
| 223 | 299 | ||
| 224 | constexpr u32 GetImmValue() const { | 300 | constexpr u32 GetImmValue() const { |
| @@ -234,41 +310,50 @@ private: | |||
| 234 | u8 scale = 0; | 310 | u8 scale = 0; |
| 235 | u16 offsetOrBaseReg = 0; | 311 | u16 offsetOrBaseReg = 0; |
| 236 | u16 indexReg = 0; | 312 | u16 indexReg = 0; |
| 237 | u64 offset = 0; // use RIP-relative as much as possible - 64-bit immediates are not available. | 313 | u64 offset = 0; // use RIP-relative as much as possible - 64-bit immediates are not available. |
| 238 | u16 operandReg = 0; | 314 | u16 operandReg = 0; |
| 239 | }; | 315 | }; |
| 240 | 316 | ||
| 241 | template <typename T> | 317 | template <typename T> |
| 242 | inline OpArg M(const T *ptr) { return OpArg(reinterpret_cast<u64>(ptr), static_cast<int>(SCALE_RIP)); } | 318 | inline OpArg M(const T* ptr) { |
| 243 | constexpr OpArg R(X64Reg value) { return OpArg(0, SCALE_NONE, value); } | 319 | return OpArg(reinterpret_cast<u64>(ptr), static_cast<int>(SCALE_RIP)); |
| 244 | constexpr OpArg MatR(X64Reg value) { return OpArg(0, SCALE_ATREG, value); } | 320 | } |
| 321 | constexpr OpArg R(X64Reg value) { | ||
| 322 | return OpArg(0, SCALE_NONE, value); | ||
| 323 | } | ||
| 324 | constexpr OpArg MatR(X64Reg value) { | ||
| 325 | return OpArg(0, SCALE_ATREG, value); | ||
| 326 | } | ||
| 245 | 327 | ||
| 246 | constexpr OpArg MDisp(X64Reg value, int offset) | 328 | constexpr OpArg MDisp(X64Reg value, int offset) { |
| 247 | { | ||
| 248 | return OpArg(static_cast<u32>(offset), SCALE_ATREG, value); | 329 | return OpArg(static_cast<u32>(offset), SCALE_ATREG, value); |
| 249 | } | 330 | } |
| 250 | 331 | ||
| 251 | constexpr OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset) | 332 | constexpr OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset) { |
| 252 | { | ||
| 253 | return OpArg(offset, scale, base, scaled); | 333 | return OpArg(offset, scale, base, scaled); |
| 254 | } | 334 | } |
| 255 | 335 | ||
| 256 | constexpr OpArg MScaled(X64Reg scaled, int scale, int offset) | 336 | constexpr OpArg MScaled(X64Reg scaled, int scale, int offset) { |
| 257 | { | 337 | return scale == SCALE_1 ? OpArg(offset, SCALE_ATREG, scaled) |
| 258 | return scale == SCALE_1 | 338 | : OpArg(offset, scale | 0x20, RAX, scaled); |
| 259 | ? OpArg(offset, SCALE_ATREG, scaled) | ||
| 260 | : OpArg(offset, scale | 0x20, RAX, scaled); | ||
| 261 | } | 339 | } |
| 262 | 340 | ||
| 263 | constexpr OpArg MRegSum(X64Reg base, X64Reg offset) | 341 | constexpr OpArg MRegSum(X64Reg base, X64Reg offset) { |
| 264 | { | ||
| 265 | return MComplex(base, offset, 1, 0); | 342 | return MComplex(base, offset, 1, 0); |
| 266 | } | 343 | } |
| 267 | 344 | ||
| 268 | constexpr OpArg Imm8 (u8 imm) { return OpArg(imm, SCALE_IMM8); } | 345 | constexpr OpArg Imm8(u8 imm) { |
| 269 | constexpr OpArg Imm16(u16 imm) { return OpArg(imm, SCALE_IMM16); } //rarely used | 346 | return OpArg(imm, SCALE_IMM8); |
| 270 | constexpr OpArg Imm32(u32 imm) { return OpArg(imm, SCALE_IMM32); } | 347 | } |
| 271 | constexpr OpArg Imm64(u64 imm) { return OpArg(imm, SCALE_IMM64); } | 348 | constexpr OpArg Imm16(u16 imm) { |
| 349 | return OpArg(imm, SCALE_IMM16); | ||
| 350 | } // rarely used | ||
| 351 | constexpr OpArg Imm32(u32 imm) { | ||
| 352 | return OpArg(imm, SCALE_IMM32); | ||
| 353 | } | ||
| 354 | constexpr OpArg Imm64(u64 imm) { | ||
| 355 | return OpArg(imm, SCALE_IMM64); | ||
| 356 | } | ||
| 272 | constexpr OpArg UImmAuto(u32 imm) { | 357 | constexpr OpArg UImmAuto(u32 imm) { |
| 273 | return OpArg(imm, imm >= 128 ? SCALE_IMM32 : SCALE_IMM8); | 358 | return OpArg(imm, imm >= 128 ? SCALE_IMM32 : SCALE_IMM8); |
| 274 | } | 359 | } |
| @@ -277,8 +362,7 @@ constexpr OpArg SImmAuto(s32 imm) { | |||
| 277 | } | 362 | } |
| 278 | 363 | ||
| 279 | template <typename T> | 364 | template <typename T> |
| 280 | OpArg ImmPtr(const T* imm) | 365 | OpArg ImmPtr(const T* imm) { |
| 281 | { | ||
| 282 | #ifdef _ARCH_64 | 366 | #ifdef _ARCH_64 |
| 283 | return Imm64(reinterpret_cast<u64>(imm)); | 367 | return Imm64(reinterpret_cast<u64>(imm)); |
| 284 | #else | 368 | #else |
| @@ -286,36 +370,31 @@ OpArg ImmPtr(const T* imm) | |||
| 286 | #endif | 370 | #endif |
| 287 | } | 371 | } |
| 288 | 372 | ||
| 289 | inline u32 PtrOffset(const void* ptr, const void* base) | 373 | inline u32 PtrOffset(const void* ptr, const void* base) { |
| 290 | { | ||
| 291 | #ifdef _ARCH_64 | 374 | #ifdef _ARCH_64 |
| 292 | s64 distance = (s64)ptr-(s64)base; | 375 | s64 distance = (s64)ptr - (s64)base; |
| 293 | if (distance >= 0x80000000LL || | 376 | if (distance >= 0x80000000LL || distance < -0x80000000LL) { |
| 294 | distance < -0x80000000LL) | ||
| 295 | { | ||
| 296 | ASSERT_MSG(0, "pointer offset out of range"); | 377 | ASSERT_MSG(0, "pointer offset out of range"); |
| 297 | return 0; | 378 | return 0; |
| 298 | } | 379 | } |
| 299 | 380 | ||
| 300 | return (u32)distance; | 381 | return (u32)distance; |
| 301 | #else | 382 | #else |
| 302 | return (u32)ptr-(u32)base; | 383 | return (u32)ptr - (u32)base; |
| 303 | #endif | 384 | #endif |
| 304 | } | 385 | } |
| 305 | 386 | ||
| 306 | //usage: int a[]; ARRAY_OFFSET(a,10) | 387 | // usage: int a[]; ARRAY_OFFSET(a,10) |
| 307 | #define ARRAY_OFFSET(array,index) ((u32)((u64)&(array)[index]-(u64)&(array)[0])) | 388 | #define ARRAY_OFFSET(array, index) ((u32)((u64) & (array)[index] - (u64) & (array)[0])) |
| 308 | //usage: struct {int e;} s; STRUCT_OFFSET(s,e) | 389 | // usage: struct {int e;} s; STRUCT_OFFSET(s,e) |
| 309 | #define STRUCT_OFFSET(str,elem) ((u32)((u64)&(str).elem-(u64)&(str))) | 390 | #define STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str))) |
| 310 | 391 | ||
| 311 | struct FixupBranch | 392 | struct FixupBranch { |
| 312 | { | 393 | u8* ptr; |
| 313 | u8 *ptr; | 394 | int type; // 0 = 8bit 1 = 32bit |
| 314 | int type; //0 = 8bit 1 = 32bit | ||
| 315 | }; | 395 | }; |
| 316 | 396 | ||
| 317 | enum SSECompare | 397 | enum SSECompare { |
| 318 | { | ||
| 319 | EQ = 0, | 398 | EQ = 0, |
| 320 | LT, | 399 | LT, |
| 321 | LE, | 400 | LE, |
| @@ -326,11 +405,10 @@ enum SSECompare | |||
| 326 | ORD, | 405 | ORD, |
| 327 | }; | 406 | }; |
| 328 | 407 | ||
| 329 | class XEmitter | 408 | class XEmitter { |
| 330 | { | 409 | friend struct OpArg; // for Write8 etc |
| 331 | friend struct OpArg; // for Write8 etc | ||
| 332 | private: | 410 | private: |
| 333 | u8 *code; | 411 | u8* code; |
| 334 | bool flags_locked; | 412 | bool flags_locked; |
| 335 | 413 | ||
| 336 | void CheckFlags(); | 414 | void CheckFlags(); |
| @@ -347,14 +425,19 @@ private: | |||
| 347 | void WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); | 425 | 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); | 426 | 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); | 427 | 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); | 428 | 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); | 429 | int extrabytes = 0); |
| 352 | void WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); | 430 | 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); | 431 | int extrabytes = 0); |
| 432 | void WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, | ||
| 433 | int extrabytes = 0); | ||
| 434 | void WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, | ||
| 435 | int extrabytes = 0); | ||
| 354 | void WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg); | 436 | 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); | 437 | void WriteNormalOp(XEmitter* emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2); |
| 356 | 438 | ||
| 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); | 439 | void ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, |
| 440 | size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp); | ||
| 358 | 441 | ||
| 359 | protected: | 442 | protected: |
| 360 | void Write8(u8 value); | 443 | void Write8(u8 value); |
| @@ -363,26 +446,38 @@ protected: | |||
| 363 | void Write64(u64 value); | 446 | void Write64(u64 value); |
| 364 | 447 | ||
| 365 | public: | 448 | public: |
| 366 | XEmitter() { code = nullptr; flags_locked = false; } | 449 | XEmitter() { |
| 367 | XEmitter(u8 *code_ptr) { code = code_ptr; flags_locked = false; } | 450 | code = nullptr; |
| 368 | virtual ~XEmitter() {} | 451 | flags_locked = false; |
| 452 | } | ||
| 453 | XEmitter(u8* code_ptr) { | ||
| 454 | code = code_ptr; | ||
| 455 | flags_locked = false; | ||
| 456 | } | ||
| 457 | virtual ~XEmitter() { | ||
| 458 | } | ||
| 369 | 459 | ||
| 370 | void WriteModRM(int mod, int rm, int reg); | 460 | void WriteModRM(int mod, int rm, int reg); |
| 371 | void WriteSIB(int scale, int index, int base); | 461 | void WriteSIB(int scale, int index, int base); |
| 372 | 462 | ||
| 373 | void SetCodePtr(u8 *ptr); | 463 | void SetCodePtr(u8* ptr); |
| 374 | void ReserveCodeSpace(int bytes); | 464 | void ReserveCodeSpace(int bytes); |
| 375 | const u8 *AlignCode4(); | 465 | const u8* AlignCode4(); |
| 376 | const u8 *AlignCode16(); | 466 | const u8* AlignCode16(); |
| 377 | const u8 *AlignCodePage(); | 467 | const u8* AlignCodePage(); |
| 378 | const u8 *GetCodePtr() const; | 468 | const u8* GetCodePtr() const; |
| 379 | u8 *GetWritableCodePtr(); | 469 | u8* GetWritableCodePtr(); |
| 380 | 470 | ||
| 381 | void LockFlags() { flags_locked = true; } | 471 | void LockFlags() { |
| 382 | void UnlockFlags() { flags_locked = false; } | 472 | flags_locked = true; |
| 473 | } | ||
| 474 | void UnlockFlags() { | ||
| 475 | flags_locked = false; | ||
| 476 | } | ||
| 383 | 477 | ||
| 384 | // Looking for one of these? It's BANNED!! Some instructions are slow on modern CPU | 478 | // 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., | 479 | // INC, DEC, LOOP, LOOPNE, LOOPE, ENTER, LEAVE, XCHG, XLAT, REP MOVSB/MOVSD, REP SCASD + other |
| 480 | // string instr., | ||
| 386 | // INC and DEC are slow on Intel Core, but not on AMD. They create a | 481 | // 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. | 482 | // false flag dependency because they only update a subset of the flags. |
| 388 | // XCHG is SLOW and should be avoided. | 483 | // XCHG is SLOW and should be avoided. |
| @@ -401,11 +496,11 @@ public: | |||
| 401 | void CLC(); | 496 | void CLC(); |
| 402 | void CMC(); | 497 | void CMC(); |
| 403 | 498 | ||
| 404 | // These two can not be executed in 64-bit mode on early Intel 64-bit CPU:s, only on Core2 and AMD! | 499 | // These two can not be executed in 64-bit mode on early Intel 64-bit CPU:s, only on Core2 and |
| 500 | // AMD! | ||
| 405 | void LAHF(); // 3 cycle vector path | 501 | void LAHF(); // 3 cycle vector path |
| 406 | void SAHF(); // direct path fast | 502 | void SAHF(); // direct path fast |
| 407 | 503 | ||
| 408 | |||
| 409 | // Stack control | 504 | // Stack control |
| 410 | void PUSH(X64Reg reg); | 505 | void PUSH(X64Reg reg); |
| 411 | void POP(X64Reg reg); | 506 | void POP(X64Reg reg); |
| @@ -422,7 +517,7 @@ public: | |||
| 422 | 517 | ||
| 423 | void JMP(const u8* addr, bool force5Bytes = false); | 518 | void JMP(const u8* addr, bool force5Bytes = false); |
| 424 | void JMPptr(const OpArg& arg); | 519 | void JMPptr(const OpArg& arg); |
| 425 | void JMPself(); //infinite loop! | 520 | void JMPself(); // infinite loop! |
| 426 | #ifdef CALL | 521 | #ifdef CALL |
| 427 | #undef CALL | 522 | #undef CALL |
| 428 | #endif | 523 | #endif |
| @@ -450,12 +545,11 @@ public: | |||
| 450 | void BSR(int bits, X64Reg dest, const OpArg& src); // Top bit to bottom bit | 545 | void BSR(int bits, X64Reg dest, const OpArg& src); // Top bit to bottom bit |
| 451 | 546 | ||
| 452 | // Cache control | 547 | // Cache control |
| 453 | enum PrefetchLevel | 548 | enum PrefetchLevel { |
| 454 | { | 549 | PF_NTA, // Non-temporal (data used once and only once) |
| 455 | PF_NTA, //Non-temporal (data used once and only once) | 550 | PF_T0, // All cache levels |
| 456 | PF_T0, //All cache levels | 551 | PF_T1, // Levels 2+ (aliased to T0 on AMD) |
| 457 | PF_T1, //Levels 2+ (aliased to T0 on AMD) | 552 | PF_T2, // Levels 3+ (aliased to T0 on AMD) |
| 458 | PF_T2, //Levels 3+ (aliased to T0 on AMD) | ||
| 459 | }; | 553 | }; |
| 460 | void PREFETCH(PrefetchLevel level, OpArg arg); | 554 | void PREFETCH(PrefetchLevel level, OpArg arg); |
| 461 | void MOVNTI(int bits, const OpArg& dest, X64Reg src); | 555 | void MOVNTI(int bits, const OpArg& dest, X64Reg src); |
| @@ -464,8 +558,8 @@ public: | |||
| 464 | void MOVNTPD(const OpArg& arg, X64Reg regOp); | 558 | void MOVNTPD(const OpArg& arg, X64Reg regOp); |
| 465 | 559 | ||
| 466 | // Multiplication / division | 560 | // Multiplication / division |
| 467 | void MUL(int bits, const OpArg& src); //UNSIGNED | 561 | void MUL(int bits, const OpArg& src); // UNSIGNED |
| 468 | void IMUL(int bits, const OpArg& src); //SIGNED | 562 | void IMUL(int bits, const OpArg& src); // SIGNED |
| 469 | void IMUL(int bits, X64Reg regOp, const OpArg& src); | 563 | void IMUL(int bits, X64Reg regOp, const OpArg& src); |
| 470 | void IMUL(int bits, X64Reg regOp, const OpArg& src, const OpArg& imm); | 564 | void IMUL(int bits, X64Reg regOp, const OpArg& src, const OpArg& imm); |
| 471 | void DIV(int bits, const OpArg& src); | 565 | void DIV(int bits, const OpArg& src); |
| @@ -492,11 +586,19 @@ public: | |||
| 492 | 586 | ||
| 493 | // Extend EAX into EDX in various ways | 587 | // Extend EAX into EDX in various ways |
| 494 | void CWD(int bits = 16); | 588 | void CWD(int bits = 16); |
| 495 | void CDQ() {CWD(32);} | 589 | void CDQ() { |
| 496 | void CQO() {CWD(64);} | 590 | CWD(32); |
| 591 | } | ||
| 592 | void CQO() { | ||
| 593 | CWD(64); | ||
| 594 | } | ||
| 497 | void CBW(int bits = 8); | 595 | void CBW(int bits = 8); |
| 498 | void CWDE() {CBW(16);} | 596 | void CWDE() { |
| 499 | void CDQE() {CBW(32);} | 597 | CBW(16); |
| 598 | } | ||
| 599 | void CDQE() { | ||
| 600 | CBW(32); | ||
| 601 | } | ||
| 500 | 602 | ||
| 501 | // Load effective address | 603 | // Load effective address |
| 502 | void LEA(int bits, X64Reg dest, OpArg src); | 604 | void LEA(int bits, X64Reg dest, OpArg src); |
| @@ -511,7 +613,7 @@ public: | |||
| 511 | void CMP(int bits, const OpArg& a1, const OpArg& a2); | 613 | void CMP(int bits, const OpArg& a1, const OpArg& a2); |
| 512 | 614 | ||
| 513 | // Bit operations | 615 | // Bit operations |
| 514 | void NOT (int bits, const OpArg& src); | 616 | void NOT(int bits, const OpArg& src); |
| 515 | void OR(int bits, const OpArg& a1, const OpArg& a2); | 617 | void OR(int bits, const OpArg& a1, const OpArg& a2); |
| 516 | void XOR(int bits, const OpArg& a1, const OpArg& a2); | 618 | void XOR(int bits, const OpArg& a1, const OpArg& a2); |
| 517 | void MOV(int bits, const OpArg& a1, const OpArg& a2); | 619 | void MOV(int bits, const OpArg& a1, const OpArg& a2); |
| @@ -525,7 +627,8 @@ public: | |||
| 525 | void BSWAP(int bits, X64Reg reg); | 627 | void BSWAP(int bits, X64Reg reg); |
| 526 | 628 | ||
| 527 | // Sign/zero extension | 629 | // Sign/zero extension |
| 528 | void MOVSX(int dbits, int sbits, X64Reg dest, OpArg src); //automatically uses MOVSXD if necessary | 630 | void MOVSX(int dbits, int sbits, X64Reg dest, |
| 631 | OpArg src); // automatically uses MOVSXD if necessary | ||
| 529 | void MOVZX(int dbits, int sbits, X64Reg dest, OpArg src); | 632 | void MOVZX(int dbits, int sbits, X64Reg dest, OpArg src); |
| 530 | 633 | ||
| 531 | // Available only on Atom or >= Haswell so far. Test with GetCPUCaps().movbe. | 634 | // Available only on Atom or >= Haswell so far. Test with GetCPUCaps().movbe. |
| @@ -593,13 +696,27 @@ public: | |||
| 593 | void CMPSS(X64Reg regOp, const OpArg& arg, u8 compare); | 696 | void CMPSS(X64Reg regOp, const OpArg& arg, u8 compare); |
| 594 | void CMPSD(X64Reg regOp, const OpArg& arg, u8 compare); | 697 | void CMPSD(X64Reg regOp, const OpArg& arg, u8 compare); |
| 595 | 698 | ||
| 596 | void CMPEQSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_EQ); } | 699 | void CMPEQSS(X64Reg regOp, const OpArg& arg) { |
| 597 | void CMPLTSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_LT); } | 700 | CMPSS(regOp, arg, CMP_EQ); |
| 598 | void CMPLESS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_LE); } | 701 | } |
| 599 | void CMPUNORDSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_UNORD); } | 702 | void CMPLTSS(X64Reg regOp, const OpArg& arg) { |
| 600 | void CMPNEQSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_NEQ); } | 703 | CMPSS(regOp, arg, CMP_LT); |
| 601 | void CMPNLTSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_NLT); } | 704 | } |
| 602 | void CMPORDSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_ORD); } | 705 | void CMPLESS(X64Reg regOp, const OpArg& arg) { |
| 706 | CMPSS(regOp, arg, CMP_LE); | ||
| 707 | } | ||
| 708 | void CMPUNORDSS(X64Reg regOp, const OpArg& arg) { | ||
| 709 | CMPSS(regOp, arg, CMP_UNORD); | ||
| 710 | } | ||
| 711 | void CMPNEQSS(X64Reg regOp, const OpArg& arg) { | ||
| 712 | CMPSS(regOp, arg, CMP_NEQ); | ||
| 713 | } | ||
| 714 | void CMPNLTSS(X64Reg regOp, const OpArg& arg) { | ||
| 715 | CMPSS(regOp, arg, CMP_NLT); | ||
| 716 | } | ||
| 717 | void CMPORDSS(X64Reg regOp, const OpArg& arg) { | ||
| 718 | CMPSS(regOp, arg, CMP_ORD); | ||
| 719 | } | ||
| 603 | 720 | ||
| 604 | // SSE/SSE2: Floating point packed arithmetic (x4 for float, x2 for double) | 721 | // SSE/SSE2: Floating point packed arithmetic (x4 for float, x2 for double) |
| 605 | void ADDPS(X64Reg regOp, const OpArg& arg); | 722 | void ADDPS(X64Reg regOp, const OpArg& arg); |
| @@ -638,10 +755,12 @@ public: | |||
| 638 | // SSE/SSE2: Useful alternative to shuffle in some cases. | 755 | // SSE/SSE2: Useful alternative to shuffle in some cases. |
| 639 | void MOVDDUP(X64Reg regOp, const OpArg& arg); | 756 | void MOVDDUP(X64Reg regOp, const OpArg& arg); |
| 640 | 757 | ||
| 641 | // SSE3: Horizontal operations in SIMD registers. Very slow! shufps-based code beats it handily on Ivy. | 758 | // SSE3: Horizontal operations in SIMD registers. Very slow! shufps-based code beats it handily |
| 759 | // on Ivy. | ||
| 642 | void HADDPS(X64Reg dest, const OpArg& src); | 760 | void HADDPS(X64Reg dest, const OpArg& src); |
| 643 | 761 | ||
| 644 | // SSE4: Further horizontal operations - dot products. These are weirdly flexible, the arg contains both a read mask and a write "mask". | 762 | // SSE4: Further horizontal operations - dot products. These are weirdly flexible, the arg |
| 763 | // contains both a read mask and a write "mask". | ||
| 645 | void DPPS(X64Reg dest, const OpArg& src, u8 arg); | 764 | void DPPS(X64Reg dest, const OpArg& src, u8 arg); |
| 646 | 765 | ||
| 647 | void UNPCKLPS(X64Reg dest, const OpArg& src); | 766 | void UNPCKLPS(X64Reg dest, const OpArg& src); |
| @@ -694,11 +813,13 @@ public: | |||
| 694 | void MOVD_xmm(const OpArg& arg, X64Reg src); | 813 | void MOVD_xmm(const OpArg& arg, X64Reg src); |
| 695 | void MOVQ_xmm(OpArg arg, X64Reg src); | 814 | void MOVQ_xmm(OpArg arg, X64Reg src); |
| 696 | 815 | ||
| 697 | // SSE/SSE2: Generates a mask from the high bits of the components of the packed register in question. | 816 | // SSE/SSE2: Generates a mask from the high bits of the components of the packed register in |
| 817 | // question. | ||
| 698 | void MOVMSKPS(X64Reg dest, const OpArg& arg); | 818 | void MOVMSKPS(X64Reg dest, const OpArg& arg); |
| 699 | void MOVMSKPD(X64Reg dest, const OpArg& arg); | 819 | void MOVMSKPD(X64Reg dest, const OpArg& arg); |
| 700 | 820 | ||
| 701 | // SSE2: Selective byte store, mask in src register. EDI/RDI specifies store address. This is a weird one. | 821 | // SSE2: Selective byte store, mask in src register. EDI/RDI specifies store address. This is a |
| 822 | // weird one. | ||
| 702 | void MASKMOVDQU(X64Reg dest, X64Reg src); | 823 | void MASKMOVDQU(X64Reg dest, X64Reg src); |
| 703 | void LDDQU(X64Reg dest, const OpArg& src); | 824 | void LDDQU(X64Reg dest, const OpArg& src); |
| 704 | 825 | ||
| @@ -729,10 +850,10 @@ public: | |||
| 729 | void PACKUSDW(X64Reg dest, const OpArg& arg); | 850 | void PACKUSDW(X64Reg dest, const OpArg& arg); |
| 730 | void PACKUSWB(X64Reg dest, const OpArg& arg); | 851 | void PACKUSWB(X64Reg dest, const OpArg& arg); |
| 731 | 852 | ||
| 732 | void PUNPCKLBW(X64Reg dest, const OpArg &arg); | 853 | void PUNPCKLBW(X64Reg dest, const OpArg& arg); |
| 733 | void PUNPCKLWD(X64Reg dest, const OpArg &arg); | 854 | void PUNPCKLWD(X64Reg dest, const OpArg& arg); |
| 734 | void PUNPCKLDQ(X64Reg dest, const OpArg &arg); | 855 | void PUNPCKLDQ(X64Reg dest, const OpArg& arg); |
| 735 | void PUNPCKLQDQ(X64Reg dest, const OpArg &arg); | 856 | void PUNPCKLQDQ(X64Reg dest, const OpArg& arg); |
| 736 | 857 | ||
| 737 | void PTEST(X64Reg dest, const OpArg& arg); | 858 | void PTEST(X64Reg dest, const OpArg& arg); |
| 738 | void PAND(X64Reg dest, const OpArg& arg); | 859 | void PAND(X64Reg dest, const OpArg& arg); |
| @@ -839,25 +960,57 @@ public: | |||
| 839 | void ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode); | 960 | void ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode); |
| 840 | void ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode); | 961 | void ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode); |
| 841 | 962 | ||
| 842 | void ROUNDNEARSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_NEAREST); } | 963 | void ROUNDNEARSS(X64Reg dest, const OpArg& arg) { |
| 843 | void ROUNDFLOORSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_FLOOR); } | 964 | ROUNDSS(dest, arg, FROUND_NEAREST); |
| 844 | void ROUNDCEILSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_CEIL); } | 965 | } |
| 845 | void ROUNDZEROSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_ZERO); } | 966 | void ROUNDFLOORSS(X64Reg dest, const OpArg& arg) { |
| 967 | ROUNDSS(dest, arg, FROUND_FLOOR); | ||
| 968 | } | ||
| 969 | void ROUNDCEILSS(X64Reg dest, const OpArg& arg) { | ||
| 970 | ROUNDSS(dest, arg, FROUND_CEIL); | ||
| 971 | } | ||
| 972 | void ROUNDZEROSS(X64Reg dest, const OpArg& arg) { | ||
| 973 | ROUNDSS(dest, arg, FROUND_ZERO); | ||
| 974 | } | ||
| 846 | 975 | ||
| 847 | void ROUNDNEARSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_NEAREST); } | 976 | void ROUNDNEARSD(X64Reg dest, const OpArg& arg) { |
| 848 | void ROUNDFLOORSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_FLOOR); } | 977 | ROUNDSD(dest, arg, FROUND_NEAREST); |
| 849 | void ROUNDCEILSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_CEIL); } | 978 | } |
| 850 | void ROUNDZEROSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_ZERO); } | 979 | void ROUNDFLOORSD(X64Reg dest, const OpArg& arg) { |
| 980 | ROUNDSD(dest, arg, FROUND_FLOOR); | ||
| 981 | } | ||
| 982 | void ROUNDCEILSD(X64Reg dest, const OpArg& arg) { | ||
| 983 | ROUNDSD(dest, arg, FROUND_CEIL); | ||
| 984 | } | ||
| 985 | void ROUNDZEROSD(X64Reg dest, const OpArg& arg) { | ||
| 986 | ROUNDSD(dest, arg, FROUND_ZERO); | ||
| 987 | } | ||
| 851 | 988 | ||
| 852 | void ROUNDNEARPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_NEAREST); } | 989 | void ROUNDNEARPS(X64Reg dest, const OpArg& arg) { |
| 853 | void ROUNDFLOORPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_FLOOR); } | 990 | ROUNDPS(dest, arg, FROUND_NEAREST); |
| 854 | void ROUNDCEILPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_CEIL); } | 991 | } |
| 855 | void ROUNDZEROPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_ZERO); } | 992 | void ROUNDFLOORPS(X64Reg dest, const OpArg& arg) { |
| 993 | ROUNDPS(dest, arg, FROUND_FLOOR); | ||
| 994 | } | ||
| 995 | void ROUNDCEILPS(X64Reg dest, const OpArg& arg) { | ||
| 996 | ROUNDPS(dest, arg, FROUND_CEIL); | ||
| 997 | } | ||
| 998 | void ROUNDZEROPS(X64Reg dest, const OpArg& arg) { | ||
| 999 | ROUNDPS(dest, arg, FROUND_ZERO); | ||
| 1000 | } | ||
| 856 | 1001 | ||
| 857 | void ROUNDNEARPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_NEAREST); } | 1002 | void ROUNDNEARPD(X64Reg dest, const OpArg& arg) { |
| 858 | void ROUNDFLOORPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_FLOOR); } | 1003 | ROUNDPD(dest, arg, FROUND_NEAREST); |
| 859 | void ROUNDCEILPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_CEIL); } | 1004 | } |
| 860 | void ROUNDZEROPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_ZERO); } | 1005 | void ROUNDFLOORPD(X64Reg dest, const OpArg& arg) { |
| 1006 | ROUNDPD(dest, arg, FROUND_FLOOR); | ||
| 1007 | } | ||
| 1008 | void ROUNDCEILPD(X64Reg dest, const OpArg& arg) { | ||
| 1009 | ROUNDPD(dest, arg, FROUND_CEIL); | ||
| 1010 | } | ||
| 1011 | void ROUNDZEROPD(X64Reg dest, const OpArg& arg) { | ||
| 1012 | ROUNDPD(dest, arg, FROUND_ZERO); | ||
| 1013 | } | ||
| 861 | 1014 | ||
| 862 | // AVX | 1015 | // AVX |
| 863 | void VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); | 1016 | void VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); |
| @@ -981,7 +1134,6 @@ public: | |||
| 981 | void ABI_CallFunctionC16(const void* func, u16 param1); | 1134 | void ABI_CallFunctionC16(const void* func, u16 param1); |
| 982 | void ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2); | 1135 | void ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2); |
| 983 | 1136 | ||
| 984 | |||
| 985 | // These only support u32 parameters, but that's enough for a lot of uses. | 1137 | // 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". | 1138 | // These will destroy the 1 or 2 first "parameter regs". |
| 987 | void ABI_CallFunctionC(const void* func, u32 param1); | 1139 | void ABI_CallFunctionC(const void* func, u32 param1); |
| @@ -1012,29 +1164,38 @@ public: | |||
| 1012 | * | 1164 | * |
| 1013 | * @param mask Registers to push on the stack (high 16 bits are XMMs, low 16 bits are GPRs) | 1165 | * @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 | 1166 | * @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 | 1167 | * @param needed_frame_size Additional space needed, e.g., for function arguments passed on the |
| 1168 | * stack | ||
| 1016 | * @return Size of the shadow space, i.e., offset of the frame | 1169 | * @return Size of the shadow space, i.e., offset of the frame |
| 1017 | */ | 1170 | */ |
| 1018 | size_t ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size = 0); | 1171 | size_t ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, |
| 1172 | size_t needed_frame_size = 0); | ||
| 1019 | 1173 | ||
| 1020 | /** | 1174 | /** |
| 1021 | * Restores specified registers and adjusts the stack to its original alignment, i.e., the alignment before | 1175 | * Restores specified registers and adjusts the stack to its original alignment, i.e., the |
| 1176 | * alignment before | ||
| 1022 | * the matching PushRegistersAndAdjustStack. | 1177 | * the matching PushRegistersAndAdjustStack. |
| 1023 | * | 1178 | * |
| 1024 | * @param mask Registers to restores from the stack (high 16 bits are XMMs, low 16 bits are GPRs) | 1179 | * @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 | 1180 | * GPRs) |
| 1181 | * @param rsp_alignment Original alignment before the matching PushRegistersAndAdjustStack, must | ||
| 1182 | * be 0 or 8 | ||
| 1026 | * @param needed_frame_size Additional space that was needed | 1183 | * @param needed_frame_size Additional space that was needed |
| 1027 | * @warning Stack must be currently 16-byte aligned | 1184 | * @warning Stack must be currently 16-byte aligned |
| 1028 | */ | 1185 | */ |
| 1029 | void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size = 0); | 1186 | void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, |
| 1030 | 1187 | 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 | 1188 | ||
| 1189 | #ifdef _M_IX86 | ||
| 1190 | static int ABI_GetNumXMMRegs() { | ||
| 1191 | return 8; | ||
| 1192 | } | ||
| 1193 | #else | ||
| 1194 | static int ABI_GetNumXMMRegs() { | ||
| 1195 | return 16; | ||
| 1196 | } | ||
| 1197 | #endif | ||
| 1198 | }; // class XEmitter | ||
| 1038 | 1199 | ||
| 1039 | // Everything that needs to generate X86 code should inherit from this. | 1200 | // 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 | 1201 | // You get memory management for free, plus, you can use all the MOV etc functions without |
| @@ -1045,4 +1206,4 @@ public: | |||
| 1045 | void PoisonMemory() override; | 1206 | void PoisonMemory() override; |
| 1046 | }; | 1207 | }; |
| 1047 | 1208 | ||
| 1048 | } // namespace | 1209 | } // namespace |