diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/common/assert.h | 5 | ||||
| -rw-r--r-- | src/common/bit_field.h | 19 | ||||
| -rw-r--r-- | src/common/bit_set.h | 244 | ||||
| -rw-r--r-- | src/common/logging/backend.cpp | 11 | ||||
| -rw-r--r-- | src/common/logging/backend.h | 14 | ||||
| -rw-r--r-- | src/common/math_util.h | 16 | ||||
| -rw-r--r-- | src/common/string_util.cpp | 66 | ||||
| -rw-r--r-- | src/common/string_util.h | 41 | ||||
| -rw-r--r-- | src/common/thread.cpp | 35 | ||||
| -rw-r--r-- | src/common/thread.h | 20 | ||||
| -rw-r--r-- | src/common/x64/xbyak_abi.h | 222 | ||||
| -rw-r--r-- | src/common/x64/xbyak_util.h | 47 |
13 files changed, 75 insertions, 671 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index eccd8f64a..a5e71d879 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -44,7 +44,6 @@ add_library(common STATIC | |||
| 44 | detached_tasks.cpp | 44 | detached_tasks.cpp |
| 45 | detached_tasks.h | 45 | detached_tasks.h |
| 46 | bit_field.h | 46 | bit_field.h |
| 47 | bit_set.h | ||
| 48 | cityhash.cpp | 47 | cityhash.cpp |
| 49 | cityhash.h | 48 | cityhash.h |
| 50 | color.h | 49 | color.h |
| @@ -95,14 +94,9 @@ if(ARCHITECTURE_x86_64) | |||
| 95 | PRIVATE | 94 | PRIVATE |
| 96 | x64/cpu_detect.cpp | 95 | x64/cpu_detect.cpp |
| 97 | x64/cpu_detect.h | 96 | x64/cpu_detect.h |
| 98 | x64/xbyak_abi.h | ||
| 99 | x64/xbyak_util.h | ||
| 100 | ) | 97 | ) |
| 101 | endif() | 98 | endif() |
| 102 | 99 | ||
| 103 | create_target_directory_groups(common) | 100 | create_target_directory_groups(common) |
| 104 | 101 | ||
| 105 | target_link_libraries(common PUBLIC Boost::boost fmt microprofile) | 102 | target_link_libraries(common PUBLIC Boost::boost fmt microprofile) |
| 106 | if (ARCHITECTURE_x86_64) | ||
| 107 | target_link_libraries(common PRIVATE xbyak) | ||
| 108 | endif() | ||
diff --git a/src/common/assert.h b/src/common/assert.h index 0d4eddc19..6002f7ab1 100644 --- a/src/common/assert.h +++ b/src/common/assert.h | |||
| @@ -52,5 +52,8 @@ __declspec(noinline, noreturn) | |||
| 52 | #define DEBUG_ASSERT_MSG(_a_, _desc_, ...) | 52 | #define DEBUG_ASSERT_MSG(_a_, _desc_, ...) |
| 53 | #endif | 53 | #endif |
| 54 | 54 | ||
| 55 | #define UNIMPLEMENTED() LOG_CRITICAL(Debug, "Unimplemented code!") | 55 | #define UNIMPLEMENTED() ASSERT_MSG(false, "Unimplemented code!") |
| 56 | #define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__) | 56 | #define UNIMPLEMENTED_MSG(...) ASSERT_MSG(false, __VA_ARGS__) |
| 57 | |||
| 58 | #define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!") | ||
| 59 | #define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__) | ||
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index bf803da8d..21e07925d 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h | |||
| @@ -117,21 +117,21 @@ private: | |||
| 117 | // We don't delete it because we want BitField to be trivially copyable. | 117 | // We don't delete it because we want BitField to be trivially copyable. |
| 118 | constexpr BitField& operator=(const BitField&) = default; | 118 | constexpr BitField& operator=(const BitField&) = default; |
| 119 | 119 | ||
| 120 | // StorageType is T for non-enum types and the underlying type of T if | 120 | // UnderlyingType is T for non-enum types and the underlying type of T if |
| 121 | // T is an enumeration. Note that T is wrapped within an enable_if in the | 121 | // T is an enumeration. Note that T is wrapped within an enable_if in the |
| 122 | // former case to workaround compile errors which arise when using | 122 | // former case to workaround compile errors which arise when using |
| 123 | // std::underlying_type<T>::type directly. | 123 | // std::underlying_type<T>::type directly. |
| 124 | using StorageType = typename std::conditional_t<std::is_enum<T>::value, std::underlying_type<T>, | 124 | using UnderlyingType = typename std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>, |
| 125 | std::enable_if<true, T>>::type; | 125 | std::enable_if<true, T>>::type; |
| 126 | 126 | ||
| 127 | // Unsigned version of StorageType | 127 | // We store the value as the unsigned type to avoid undefined behaviour on value shifting |
| 128 | using StorageTypeU = std::make_unsigned_t<StorageType>; | 128 | using StorageType = std::make_unsigned_t<UnderlyingType>; |
| 129 | 129 | ||
| 130 | public: | 130 | public: |
| 131 | /// Constants to allow limited introspection of fields if needed | 131 | /// Constants to allow limited introspection of fields if needed |
| 132 | static constexpr std::size_t position = Position; | 132 | static constexpr std::size_t position = Position; |
| 133 | static constexpr std::size_t bits = Bits; | 133 | static constexpr std::size_t bits = Bits; |
| 134 | static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; | 134 | static constexpr StorageType mask = (((StorageType)~0) >> (8 * sizeof(T) - bits)) << position; |
| 135 | 135 | ||
| 136 | /** | 136 | /** |
| 137 | * Formats a value by masking and shifting it according to the field parameters. A value | 137 | * Formats a value by masking and shifting it according to the field parameters. A value |
| @@ -148,11 +148,12 @@ public: | |||
| 148 | * union in a constexpr context. | 148 | * union in a constexpr context. |
| 149 | */ | 149 | */ |
| 150 | static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { | 150 | static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { |
| 151 | if (std::numeric_limits<T>::is_signed) { | 151 | if constexpr (std::numeric_limits<UnderlyingType>::is_signed) { |
| 152 | std::size_t shift = 8 * sizeof(T) - bits; | 152 | std::size_t shift = 8 * sizeof(T) - bits; |
| 153 | return (T)((storage << (shift - position)) >> shift); | 153 | return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >> |
| 154 | shift); | ||
| 154 | } else { | 155 | } else { |
| 155 | return (T)((storage & mask) >> position); | 156 | return static_cast<T>((storage & mask) >> position); |
| 156 | } | 157 | } |
| 157 | } | 158 | } |
| 158 | 159 | ||
diff --git a/src/common/bit_set.h b/src/common/bit_set.h deleted file mode 100644 index 5cd1352b2..000000000 --- a/src/common/bit_set.h +++ /dev/null | |||
| @@ -1,244 +0,0 @@ | |||
| 1 | // This file is under the public domain. | ||
| 2 | |||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include <cstddef> | ||
| 6 | #ifdef _WIN32 | ||
| 7 | #include <intrin.h> | ||
| 8 | #endif | ||
| 9 | #include <initializer_list> | ||
| 10 | #include <new> | ||
| 11 | #include <type_traits> | ||
| 12 | #include "common/common_types.h" | ||
| 13 | |||
| 14 | // namespace avoids conflict with OS X Carbon; don't use BitSet<T> directly | ||
| 15 | namespace Common { | ||
| 16 | |||
| 17 | // Helper functions: | ||
| 18 | |||
| 19 | #ifdef _MSC_VER | ||
| 20 | template <typename T> | ||
| 21 | static inline int CountSetBits(T v) { | ||
| 22 | // from https://graphics.stanford.edu/~seander/bithacks.html | ||
| 23 | // GCC has this built in, but MSVC's intrinsic will only emit the actual | ||
| 24 | // POPCNT instruction, which we're not depending on | ||
| 25 | v = v - ((v >> 1) & (T) ~(T)0 / 3); | ||
| 26 | v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3); | ||
| 27 | v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15; | ||
| 28 | return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8; | ||
| 29 | } | ||
| 30 | static inline int LeastSignificantSetBit(u8 val) { | ||
| 31 | unsigned long index; | ||
| 32 | _BitScanForward(&index, val); | ||
| 33 | return (int)index; | ||
| 34 | } | ||
| 35 | static inline int LeastSignificantSetBit(u16 val) { | ||
| 36 | unsigned long index; | ||
| 37 | _BitScanForward(&index, val); | ||
| 38 | return (int)index; | ||
| 39 | } | ||
| 40 | static inline int LeastSignificantSetBit(u32 val) { | ||
| 41 | unsigned long index; | ||
| 42 | _BitScanForward(&index, val); | ||
| 43 | return (int)index; | ||
| 44 | } | ||
| 45 | static inline int LeastSignificantSetBit(u64 val) { | ||
| 46 | unsigned long index; | ||
| 47 | _BitScanForward64(&index, val); | ||
| 48 | return (int)index; | ||
| 49 | } | ||
| 50 | #else | ||
| 51 | static inline int CountSetBits(u8 val) { | ||
| 52 | return __builtin_popcount(val); | ||
| 53 | } | ||
| 54 | static inline int CountSetBits(u16 val) { | ||
| 55 | return __builtin_popcount(val); | ||
| 56 | } | ||
| 57 | static inline int CountSetBits(u32 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 | } | ||
| 75 | #endif | ||
| 76 | |||
| 77 | // Similar to std::bitset, this is a class which encapsulates a bitset, i.e. | ||
| 78 | // using the set bits of an integer to represent a set of integers. Like that | ||
| 79 | // class, it acts like an array of bools: | ||
| 80 | // BitSet32 bs; | ||
| 81 | // bs[1] = true; | ||
| 82 | // but also like the underlying integer ([0] = least significant bit): | ||
| 83 | // BitSet32 bs2 = ...; | ||
| 84 | // bs = (bs ^ bs2) & BitSet32(0xffff); | ||
| 85 | // The following additional functionality is provided: | ||
| 86 | // - Construction using an initializer list. | ||
| 87 | // BitSet bs { 1, 2, 4, 8 }; | ||
| 88 | // - Efficiently iterating through the set bits: | ||
| 89 | // for (int i : bs) | ||
| 90 | // [i is the *index* of a set bit] | ||
| 91 | // (This uses the appropriate CPU instruction to find the next set bit in one | ||
| 92 | // operation.) | ||
| 93 | // - Counting set bits using .Count() - see comment on that method. | ||
| 94 | |||
| 95 | // TODO: use constexpr when MSVC gets out of the Dark Ages | ||
| 96 | |||
| 97 | template <typename IntTy> | ||
| 98 | class BitSet { | ||
| 99 | static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types"); | ||
| 100 | |||
| 101 | public: | ||
| 102 | // A reference to a particular bit, returned from operator[]. | ||
| 103 | class Ref { | ||
| 104 | public: | ||
| 105 | Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {} | ||
| 106 | Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {} | ||
| 107 | operator bool() const { | ||
| 108 | return (m_bs->m_val & m_mask) != 0; | ||
| 109 | } | ||
| 110 | bool operator=(bool set) { | ||
| 111 | m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0); | ||
| 112 | return set; | ||
| 113 | } | ||
| 114 | |||
| 115 | private: | ||
| 116 | BitSet* m_bs; | ||
| 117 | IntTy m_mask; | ||
| 118 | }; | ||
| 119 | |||
| 120 | // A STL-like iterator is required to be able to use range-based for loops. | ||
| 121 | class Iterator { | ||
| 122 | public: | ||
| 123 | Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {} | ||
| 124 | Iterator(IntTy val) : m_val(val), m_bit(0) {} | ||
| 125 | Iterator& operator=(Iterator other) { | ||
| 126 | new (this) Iterator(other); | ||
| 127 | return *this; | ||
| 128 | } | ||
| 129 | int operator*() { | ||
| 130 | return m_bit + ComputeLsb(); | ||
| 131 | } | ||
| 132 | Iterator& operator++() { | ||
| 133 | int lsb = ComputeLsb(); | ||
| 134 | m_val >>= lsb + 1; | ||
| 135 | m_bit += lsb + 1; | ||
| 136 | m_has_lsb = false; | ||
| 137 | return *this; | ||
| 138 | } | ||
| 139 | Iterator operator++(int _) { | ||
| 140 | Iterator other(*this); | ||
| 141 | ++*this; | ||
| 142 | return other; | ||
| 143 | } | ||
| 144 | bool operator==(Iterator other) const { | ||
| 145 | return m_val == other.m_val; | ||
| 146 | } | ||
| 147 | bool operator!=(Iterator other) const { | ||
| 148 | return m_val != other.m_val; | ||
| 149 | } | ||
| 150 | |||
| 151 | private: | ||
| 152 | int ComputeLsb() { | ||
| 153 | if (!m_has_lsb) { | ||
| 154 | m_lsb = LeastSignificantSetBit(m_val); | ||
| 155 | m_has_lsb = true; | ||
| 156 | } | ||
| 157 | return m_lsb; | ||
| 158 | } | ||
| 159 | IntTy m_val; | ||
| 160 | int m_bit; | ||
| 161 | int m_lsb = -1; | ||
| 162 | bool m_has_lsb = false; | ||
| 163 | }; | ||
| 164 | |||
| 165 | BitSet() : m_val(0) {} | ||
| 166 | explicit BitSet(IntTy val) : m_val(val) {} | ||
| 167 | BitSet(std::initializer_list<int> init) { | ||
| 168 | m_val = 0; | ||
| 169 | for (int bit : init) | ||
| 170 | m_val |= (IntTy)1 << bit; | ||
| 171 | } | ||
| 172 | |||
| 173 | static BitSet AllTrue(std::size_t count) { | ||
| 174 | return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); | ||
| 175 | } | ||
| 176 | |||
| 177 | Ref operator[](std::size_t bit) { | ||
| 178 | return Ref(this, (IntTy)1 << bit); | ||
| 179 | } | ||
| 180 | const Ref operator[](std::size_t bit) const { | ||
| 181 | return (*const_cast<BitSet*>(this))[bit]; | ||
| 182 | } | ||
| 183 | bool operator==(BitSet other) const { | ||
| 184 | return m_val == other.m_val; | ||
| 185 | } | ||
| 186 | bool operator!=(BitSet other) const { | ||
| 187 | return m_val != other.m_val; | ||
| 188 | } | ||
| 189 | bool operator<(BitSet other) const { | ||
| 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 | } | ||
| 216 | operator u32() = delete; | ||
| 217 | operator bool() { | ||
| 218 | return m_val != 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | // Warning: Even though on modern CPUs this is a single fast instruction, | ||
| 222 | // Dolphin's official builds do not currently assume POPCNT support on x86, | ||
| 223 | // so slower explicit bit twiddling is generated. Still should generally | ||
| 224 | // be faster than a loop. | ||
| 225 | unsigned int Count() const { | ||
| 226 | return CountSetBits(m_val); | ||
| 227 | } | ||
| 228 | |||
| 229 | Iterator begin() const { | ||
| 230 | return Iterator(m_val); | ||
| 231 | } | ||
| 232 | Iterator end() const { | ||
| 233 | return Iterator(0); | ||
| 234 | } | ||
| 235 | |||
| 236 | IntTy m_val; | ||
| 237 | }; | ||
| 238 | |||
| 239 | } // namespace Common | ||
| 240 | |||
| 241 | typedef Common::BitSet<u8> BitSet8; | ||
| 242 | typedef Common::BitSet<u16> BitSet16; | ||
| 243 | typedef Common::BitSet<u32> BitSet32; | ||
| 244 | typedef Common::BitSet<u64> BitSet64; | ||
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 6d5218465..5753b871a 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -12,7 +12,8 @@ | |||
| 12 | #include <thread> | 12 | #include <thread> |
| 13 | #include <vector> | 13 | #include <vector> |
| 14 | #ifdef _WIN32 | 14 | #ifdef _WIN32 |
| 15 | #include <share.h> // For _SH_DENYWR | 15 | #include <share.h> // For _SH_DENYWR |
| 16 | #include <windows.h> // For OutputDebugStringA | ||
| 16 | #else | 17 | #else |
| 17 | #define _SH_DENYWR 0 | 18 | #define _SH_DENYWR 0 |
| 18 | #endif | 19 | #endif |
| @@ -139,12 +140,18 @@ void FileBackend::Write(const Entry& entry) { | |||
| 139 | if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) { | 140 | if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) { |
| 140 | return; | 141 | return; |
| 141 | } | 142 | } |
| 142 | bytes_written += file.WriteString(FormatLogMessage(entry) + '\n'); | 143 | bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n')); |
| 143 | if (entry.log_level >= Level::Error) { | 144 | if (entry.log_level >= Level::Error) { |
| 144 | file.Flush(); | 145 | file.Flush(); |
| 145 | } | 146 | } |
| 146 | } | 147 | } |
| 147 | 148 | ||
| 149 | void DebuggerBackend::Write(const Entry& entry) { | ||
| 150 | #ifdef _WIN32 | ||
| 151 | ::OutputDebugStringA(FormatLogMessage(entry).append(1, '\n').c_str()); | ||
| 152 | #endif | ||
| 153 | } | ||
| 154 | |||
| 148 | /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. | 155 | /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. |
| 149 | #define ALL_LOG_CLASSES() \ | 156 | #define ALL_LOG_CLASSES() \ |
| 150 | CLS(Log) \ | 157 | CLS(Log) \ |
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index 11edbf1b6..91bb0c309 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h | |||
| @@ -103,6 +103,20 @@ private: | |||
| 103 | std::size_t bytes_written; | 103 | std::size_t bytes_written; |
| 104 | }; | 104 | }; |
| 105 | 105 | ||
| 106 | /** | ||
| 107 | * Backend that writes to Visual Studio's output window | ||
| 108 | */ | ||
| 109 | class DebuggerBackend : public Backend { | ||
| 110 | public: | ||
| 111 | static const char* Name() { | ||
| 112 | return "debugger"; | ||
| 113 | } | ||
| 114 | const char* GetName() const override { | ||
| 115 | return Name(); | ||
| 116 | } | ||
| 117 | void Write(const Entry& entry) override; | ||
| 118 | }; | ||
| 119 | |||
| 106 | void AddBackend(std::unique_ptr<Backend> backend); | 120 | void AddBackend(std::unique_ptr<Backend> backend); |
| 107 | 121 | ||
| 108 | void RemoveBackend(std::string_view backend_name); | 122 | void RemoveBackend(std::string_view backend_name); |
diff --git a/src/common/math_util.h b/src/common/math_util.h index 343cdd902..94b4394c5 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h | |||
| @@ -4,18 +4,12 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <algorithm> | ||
| 8 | #include <cstdlib> | 7 | #include <cstdlib> |
| 9 | #include <type_traits> | 8 | #include <type_traits> |
| 10 | 9 | ||
| 11 | namespace MathUtil { | 10 | namespace MathUtil { |
| 12 | 11 | ||
| 13 | static constexpr float PI = 3.14159265f; | 12 | constexpr float PI = 3.14159265f; |
| 14 | |||
| 15 | inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1, | ||
| 16 | unsigned length1) { | ||
| 17 | return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1)); | ||
| 18 | } | ||
| 19 | 13 | ||
| 20 | template <class T> | 14 | template <class T> |
| 21 | struct Rectangle { | 15 | struct Rectangle { |
| @@ -24,16 +18,16 @@ struct Rectangle { | |||
| 24 | T right{}; | 18 | T right{}; |
| 25 | T bottom{}; | 19 | T bottom{}; |
| 26 | 20 | ||
| 27 | Rectangle() = default; | 21 | constexpr Rectangle() = default; |
| 28 | 22 | ||
| 29 | Rectangle(T left, T top, T right, T bottom) | 23 | constexpr Rectangle(T left, T top, T right, T bottom) |
| 30 | : left(left), top(top), right(right), bottom(bottom) {} | 24 | : left(left), top(top), right(right), bottom(bottom) {} |
| 31 | 25 | ||
| 32 | T GetWidth() const { | 26 | T GetWidth() const { |
| 33 | return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); | 27 | return std::abs(static_cast<std::make_signed_t<T>>(right - left)); |
| 34 | } | 28 | } |
| 35 | T GetHeight() const { | 29 | T GetHeight() const { |
| 36 | return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); | 30 | return std::abs(static_cast<std::make_signed_t<T>>(bottom - top)); |
| 37 | } | 31 | } |
| 38 | Rectangle<T> TranslateX(const T x) const { | 32 | Rectangle<T> TranslateX(const T x) const { |
| 39 | return Rectangle{left + x, top, right + x, bottom}; | 33 | return Rectangle{left + x, top, right + x, bottom}; |
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 731d1db34..959f278aa 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -4,11 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <cctype> | 6 | #include <cctype> |
| 7 | #include <cerrno> | ||
| 8 | #include <codecvt> | 7 | #include <codecvt> |
| 9 | #include <cstdio> | ||
| 10 | #include <cstdlib> | 8 | #include <cstdlib> |
| 11 | #include <cstring> | 9 | #include <locale> |
| 10 | #include <sstream> | ||
| 12 | #include "common/common_paths.h" | 11 | #include "common/common_paths.h" |
| 13 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 14 | #include "common/string_util.h" | 13 | #include "common/string_util.h" |
| @@ -33,24 +32,6 @@ std::string ToUpper(std::string str) { | |||
| 33 | return str; | 32 | return str; |
| 34 | } | 33 | } |
| 35 | 34 | ||
| 36 | // For Debugging. Read out an u8 array. | ||
| 37 | std::string ArrayToString(const u8* data, std::size_t size, int line_len, bool spaces) { | ||
| 38 | std::ostringstream oss; | ||
| 39 | oss << std::setfill('0') << std::hex; | ||
| 40 | |||
| 41 | for (int line = 0; size; ++data, --size) { | ||
| 42 | oss << std::setw(2) << (int)*data; | ||
| 43 | |||
| 44 | if (line_len == ++line) { | ||
| 45 | oss << '\n'; | ||
| 46 | line = 0; | ||
| 47 | } else if (spaces) | ||
| 48 | oss << ' '; | ||
| 49 | } | ||
| 50 | |||
| 51 | return oss.str(); | ||
| 52 | } | ||
| 53 | |||
| 54 | std::string StringFromBuffer(const std::vector<u8>& data) { | 35 | std::string StringFromBuffer(const std::vector<u8>& data) { |
| 55 | return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); | 36 | return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); |
| 56 | } | 37 | } |
| @@ -75,40 +56,6 @@ std::string StripQuotes(const std::string& s) { | |||
| 75 | return s; | 56 | return s; |
| 76 | } | 57 | } |
| 77 | 58 | ||
| 78 | bool TryParse(const std::string& str, u32* const output) { | ||
| 79 | char* endptr = nullptr; | ||
| 80 | |||
| 81 | // Reset errno to a value other than ERANGE | ||
| 82 | errno = 0; | ||
| 83 | |||
| 84 | unsigned long value = strtoul(str.c_str(), &endptr, 0); | ||
| 85 | |||
| 86 | if (!endptr || *endptr) | ||
| 87 | return false; | ||
| 88 | |||
| 89 | if (errno == ERANGE) | ||
| 90 | return false; | ||
| 91 | |||
| 92 | #if ULONG_MAX > UINT_MAX | ||
| 93 | if (value >= 0x100000000ull && value <= 0xFFFFFFFF00000000ull) | ||
| 94 | return false; | ||
| 95 | #endif | ||
| 96 | |||
| 97 | *output = static_cast<u32>(value); | ||
| 98 | return true; | ||
| 99 | } | ||
| 100 | |||
| 101 | bool TryParse(const std::string& str, bool* const output) { | ||
| 102 | if ("1" == str || "true" == ToLower(str)) | ||
| 103 | *output = true; | ||
| 104 | else if ("0" == str || "false" == ToLower(str)) | ||
| 105 | *output = false; | ||
| 106 | else | ||
| 107 | return false; | ||
| 108 | |||
| 109 | return true; | ||
| 110 | } | ||
| 111 | |||
| 112 | std::string StringFromBool(bool value) { | 59 | std::string StringFromBool(bool value) { |
| 113 | return value ? "True" : "False"; | 60 | return value ? "True" : "False"; |
| 114 | } | 61 | } |
| @@ -267,6 +214,15 @@ std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t | |||
| 267 | return std::string(buffer, len); | 214 | return std::string(buffer, len); |
| 268 | } | 215 | } |
| 269 | 216 | ||
| 217 | std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, | ||
| 218 | std::size_t max_len) { | ||
| 219 | std::size_t len = 0; | ||
| 220 | while (len < max_len && buffer[len] != '\0') | ||
| 221 | ++len; | ||
| 222 | |||
| 223 | return std::u16string(buffer.begin(), buffer.begin() + len); | ||
| 224 | } | ||
| 225 | |||
| 270 | const char* TrimSourcePath(const char* path, const char* root) { | 226 | const char* TrimSourcePath(const char* path, const char* root) { |
| 271 | const char* p = path; | 227 | const char* p = path; |
| 272 | 228 | ||
diff --git a/src/common/string_util.h b/src/common/string_util.h index 32bf6a19c..583fd05e6 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h | |||
| @@ -5,8 +5,6 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <iomanip> | ||
| 9 | #include <sstream> | ||
| 10 | #include <string> | 8 | #include <string> |
| 11 | #include <vector> | 9 | #include <vector> |
| 12 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| @@ -19,44 +17,13 @@ std::string ToLower(std::string str); | |||
| 19 | /// Make a string uppercase | 17 | /// Make a string uppercase |
| 20 | std::string ToUpper(std::string str); | 18 | std::string ToUpper(std::string str); |
| 21 | 19 | ||
| 22 | std::string ArrayToString(const u8* data, std::size_t size, int line_len = 20, bool spaces = true); | ||
| 23 | |||
| 24 | std::string StringFromBuffer(const std::vector<u8>& data); | 20 | std::string StringFromBuffer(const std::vector<u8>& data); |
| 25 | 21 | ||
| 26 | std::string StripSpaces(const std::string& s); | 22 | std::string StripSpaces(const std::string& s); |
| 27 | std::string StripQuotes(const std::string& s); | 23 | std::string StripQuotes(const std::string& s); |
| 28 | 24 | ||
| 29 | // Thousand separator. Turns 12345678 into 12,345,678 | ||
| 30 | template <typename I> | ||
| 31 | std::string ThousandSeparate(I value, int spaces = 0) { | ||
| 32 | std::ostringstream oss; | ||
| 33 | |||
| 34 | // std::locale("") seems to be broken on many platforms | ||
| 35 | #if defined _WIN32 || (defined __linux__ && !defined __clang__) | ||
| 36 | oss.imbue(std::locale("")); | ||
| 37 | #endif | ||
| 38 | oss << std::setw(spaces) << value; | ||
| 39 | |||
| 40 | return oss.str(); | ||
| 41 | } | ||
| 42 | |||
| 43 | std::string StringFromBool(bool value); | 25 | std::string StringFromBool(bool value); |
| 44 | 26 | ||
| 45 | bool TryParse(const std::string& str, bool* output); | ||
| 46 | bool TryParse(const std::string& str, u32* output); | ||
| 47 | |||
| 48 | template <typename N> | ||
| 49 | static bool TryParse(const std::string& str, N* const output) { | ||
| 50 | std::istringstream iss(str); | ||
| 51 | |||
| 52 | N tmp = 0; | ||
| 53 | if (iss >> tmp) { | ||
| 54 | *output = tmp; | ||
| 55 | return true; | ||
| 56 | } else | ||
| 57 | return false; | ||
| 58 | } | ||
| 59 | |||
| 60 | std::string TabsToSpaces(int tab_size, std::string in); | 27 | std::string TabsToSpaces(int tab_size, std::string in); |
| 61 | 28 | ||
| 62 | void SplitString(const std::string& str, char delim, std::vector<std::string>& output); | 29 | void SplitString(const std::string& str, char delim, std::vector<std::string>& output); |
| @@ -100,6 +67,14 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) { | |||
| 100 | std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len); | 67 | std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len); |
| 101 | 68 | ||
| 102 | /** | 69 | /** |
| 70 | * Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't | ||
| 71 | * null-terminated, then the string ends at the greatest multiple of two less then or equal to | ||
| 72 | * max_len_bytes. | ||
| 73 | */ | ||
| 74 | std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, | ||
| 75 | std::size_t max_len); | ||
| 76 | |||
| 77 | /** | ||
| 103 | * Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's | 78 | * Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's |
| 104 | * intended to be used to strip a system-specific build directory from the `__FILE__` macro, | 79 | * intended to be used to strip a system-specific build directory from the `__FILE__` macro, |
| 105 | * leaving only the path relative to the sources root. | 80 | * leaving only the path relative to the sources root. |
diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 9e207118f..5144c0d9f 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp | |||
| @@ -25,23 +25,6 @@ | |||
| 25 | 25 | ||
| 26 | namespace Common { | 26 | namespace Common { |
| 27 | 27 | ||
| 28 | int CurrentThreadId() { | ||
| 29 | #ifdef _MSC_VER | ||
| 30 | return GetCurrentThreadId(); | ||
| 31 | #elif defined __APPLE__ | ||
| 32 | return mach_thread_self(); | ||
| 33 | #else | ||
| 34 | return 0; | ||
| 35 | #endif | ||
| 36 | } | ||
| 37 | |||
| 38 | #ifdef _WIN32 | ||
| 39 | // Supporting functions | ||
| 40 | void SleepCurrentThread(int ms) { | ||
| 41 | Sleep(ms); | ||
| 42 | } | ||
| 43 | #endif | ||
| 44 | |||
| 45 | #ifdef _MSC_VER | 28 | #ifdef _MSC_VER |
| 46 | 29 | ||
| 47 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { | 30 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { |
| @@ -62,7 +45,7 @@ void SwitchCurrentThread() { | |||
| 62 | 45 | ||
| 63 | // This is implemented much nicer in upcoming msvc++, see: | 46 | // This is implemented much nicer in upcoming msvc++, see: |
| 64 | // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx | 47 | // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx |
| 65 | void SetCurrentThreadName(const char* szThreadName) { | 48 | void SetCurrentThreadName(const char* name) { |
| 66 | static const DWORD MS_VC_EXCEPTION = 0x406D1388; | 49 | static const DWORD MS_VC_EXCEPTION = 0x406D1388; |
| 67 | 50 | ||
| 68 | #pragma pack(push, 8) | 51 | #pragma pack(push, 8) |
| @@ -75,7 +58,7 @@ void SetCurrentThreadName(const char* szThreadName) { | |||
| 75 | #pragma pack(pop) | 58 | #pragma pack(pop) |
| 76 | 59 | ||
| 77 | info.dwType = 0x1000; | 60 | info.dwType = 0x1000; |
| 78 | info.szName = szThreadName; | 61 | info.szName = name; |
| 79 | info.dwThreadID = -1; // dwThreadID; | 62 | info.dwThreadID = -1; // dwThreadID; |
| 80 | info.dwFlags = 0; | 63 | info.dwFlags = 0; |
| 81 | 64 | ||
| @@ -107,10 +90,6 @@ void SetCurrentThreadAffinity(u32 mask) { | |||
| 107 | } | 90 | } |
| 108 | 91 | ||
| 109 | #ifndef _WIN32 | 92 | #ifndef _WIN32 |
| 110 | void SleepCurrentThread(int ms) { | ||
| 111 | usleep(1000 * ms); | ||
| 112 | } | ||
| 113 | |||
| 114 | void SwitchCurrentThread() { | 93 | void SwitchCurrentThread() { |
| 115 | usleep(1000 * 1); | 94 | usleep(1000 * 1); |
| 116 | } | 95 | } |
| @@ -118,15 +97,15 @@ void SwitchCurrentThread() { | |||
| 118 | 97 | ||
| 119 | // MinGW with the POSIX threading model does not support pthread_setname_np | 98 | // MinGW with the POSIX threading model does not support pthread_setname_np |
| 120 | #if !defined(_WIN32) || defined(_MSC_VER) | 99 | #if !defined(_WIN32) || defined(_MSC_VER) |
| 121 | void SetCurrentThreadName(const char* szThreadName) { | 100 | void SetCurrentThreadName(const char* name) { |
| 122 | #ifdef __APPLE__ | 101 | #ifdef __APPLE__ |
| 123 | pthread_setname_np(szThreadName); | 102 | pthread_setname_np(name); |
| 124 | #elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) | 103 | #elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) |
| 125 | pthread_set_name_np(pthread_self(), szThreadName); | 104 | pthread_set_name_np(pthread_self(), name); |
| 126 | #elif defined(__NetBSD__) | 105 | #elif defined(__NetBSD__) |
| 127 | pthread_setname_np(pthread_self(), "%s", (void*)szThreadName); | 106 | pthread_setname_np(pthread_self(), "%s", (void*)name); |
| 128 | #else | 107 | #else |
| 129 | pthread_setname_np(pthread_self(), szThreadName); | 108 | pthread_setname_np(pthread_self(), name); |
| 130 | #endif | 109 | #endif |
| 131 | } | 110 | } |
| 132 | #endif | 111 | #endif |
diff --git a/src/common/thread.h b/src/common/thread.h index 6cbdb96a3..2cf74452d 100644 --- a/src/common/thread.h +++ b/src/common/thread.h | |||
| @@ -13,15 +13,8 @@ | |||
| 13 | 13 | ||
| 14 | namespace Common { | 14 | namespace Common { |
| 15 | 15 | ||
| 16 | int CurrentThreadId(); | ||
| 17 | |||
| 18 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); | ||
| 19 | void SetCurrentThreadAffinity(u32 mask); | ||
| 20 | |||
| 21 | class Event { | 16 | class Event { |
| 22 | public: | 17 | public: |
| 23 | Event() : is_set(false) {} | ||
| 24 | |||
| 25 | void Set() { | 18 | void Set() { |
| 26 | std::lock_guard<std::mutex> lk(mutex); | 19 | std::lock_guard<std::mutex> lk(mutex); |
| 27 | if (!is_set) { | 20 | if (!is_set) { |
| @@ -53,14 +46,14 @@ public: | |||
| 53 | } | 46 | } |
| 54 | 47 | ||
| 55 | private: | 48 | private: |
| 56 | bool is_set; | 49 | bool is_set = false; |
| 57 | std::condition_variable condvar; | 50 | std::condition_variable condvar; |
| 58 | std::mutex mutex; | 51 | std::mutex mutex; |
| 59 | }; | 52 | }; |
| 60 | 53 | ||
| 61 | class Barrier { | 54 | class Barrier { |
| 62 | public: | 55 | public: |
| 63 | explicit Barrier(std::size_t count_) : count(count_), waiting(0), generation(0) {} | 56 | explicit Barrier(std::size_t count_) : count(count_) {} |
| 64 | 57 | ||
| 65 | /// Blocks until all "count" threads have called Sync() | 58 | /// Blocks until all "count" threads have called Sync() |
| 66 | void Sync() { | 59 | void Sync() { |
| @@ -80,12 +73,13 @@ public: | |||
| 80 | private: | 73 | private: |
| 81 | std::condition_variable condvar; | 74 | std::condition_variable condvar; |
| 82 | std::mutex mutex; | 75 | std::mutex mutex; |
| 83 | const std::size_t count; | 76 | std::size_t count; |
| 84 | std::size_t waiting; | 77 | std::size_t waiting = 0; |
| 85 | std::size_t generation; // Incremented once each time the barrier is used | 78 | std::size_t generation = 0; // Incremented once each time the barrier is used |
| 86 | }; | 79 | }; |
| 87 | 80 | ||
| 88 | void SleepCurrentThread(int ms); | 81 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); |
| 82 | void SetCurrentThreadAffinity(u32 mask); | ||
| 89 | void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms | 83 | void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms |
| 90 | void SetCurrentThreadName(const char* name); | 84 | void SetCurrentThreadName(const char* name); |
| 91 | 85 | ||
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h deleted file mode 100644 index 636a5c0f9..000000000 --- a/src/common/x64/xbyak_abi.h +++ /dev/null | |||
| @@ -1,222 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <initializer_list> | ||
| 8 | #include <xbyak.h> | ||
| 9 | #include "common/assert.h" | ||
| 10 | #include "common/bit_set.h" | ||
| 11 | |||
| 12 | namespace Common::X64 { | ||
| 13 | |||
| 14 | inline int RegToIndex(const Xbyak::Reg& reg) { | ||
| 15 | using Kind = Xbyak::Reg::Kind; | ||
| 16 | ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0, | ||
| 17 | "RegSet only support GPRs and XMM registers."); | ||
| 18 | ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15."); | ||
| 19 | return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16); | ||
| 20 | } | ||
| 21 | |||
| 22 | inline Xbyak::Reg64 IndexToReg64(int reg_index) { | ||
| 23 | ASSERT(reg_index < 16); | ||
| 24 | return Xbyak::Reg64(reg_index); | ||
| 25 | } | ||
| 26 | |||
| 27 | inline Xbyak::Xmm IndexToXmm(int reg_index) { | ||
| 28 | ASSERT(reg_index >= 16 && reg_index < 32); | ||
| 29 | return Xbyak::Xmm(reg_index - 16); | ||
| 30 | } | ||
| 31 | |||
| 32 | inline Xbyak::Reg IndexToReg(int reg_index) { | ||
| 33 | if (reg_index < 16) { | ||
| 34 | return IndexToReg64(reg_index); | ||
| 35 | } else { | ||
| 36 | return IndexToXmm(reg_index); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | inline BitSet32 BuildRegSet(std::initializer_list<Xbyak::Reg> regs) { | ||
| 41 | BitSet32 bits; | ||
| 42 | for (const Xbyak::Reg& reg : regs) { | ||
| 43 | bits[RegToIndex(reg)] = true; | ||
| 44 | } | ||
| 45 | return bits; | ||
| 46 | } | ||
| 47 | |||
| 48 | const BitSet32 ABI_ALL_GPRS(0x0000FFFF); | ||
| 49 | const BitSet32 ABI_ALL_XMMS(0xFFFF0000); | ||
| 50 | |||
| 51 | #ifdef _WIN32 | ||
| 52 | |||
| 53 | // Microsoft x64 ABI | ||
| 54 | const Xbyak::Reg ABI_RETURN = Xbyak::util::rax; | ||
| 55 | const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx; | ||
| 56 | const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx; | ||
| 57 | const Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8; | ||
| 58 | const Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9; | ||
| 59 | |||
| 60 | const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({ | ||
| 61 | // GPRs | ||
| 62 | Xbyak::util::rcx, | ||
| 63 | Xbyak::util::rdx, | ||
| 64 | Xbyak::util::r8, | ||
| 65 | Xbyak::util::r9, | ||
| 66 | Xbyak::util::r10, | ||
| 67 | Xbyak::util::r11, | ||
| 68 | // XMMs | ||
| 69 | Xbyak::util::xmm0, | ||
| 70 | Xbyak::util::xmm1, | ||
| 71 | Xbyak::util::xmm2, | ||
| 72 | Xbyak::util::xmm3, | ||
| 73 | Xbyak::util::xmm4, | ||
| 74 | Xbyak::util::xmm5, | ||
| 75 | }); | ||
| 76 | |||
| 77 | const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({ | ||
| 78 | // GPRs | ||
| 79 | Xbyak::util::rbx, | ||
| 80 | Xbyak::util::rsi, | ||
| 81 | Xbyak::util::rdi, | ||
| 82 | Xbyak::util::rbp, | ||
| 83 | Xbyak::util::r12, | ||
| 84 | Xbyak::util::r13, | ||
| 85 | Xbyak::util::r14, | ||
| 86 | Xbyak::util::r15, | ||
| 87 | // XMMs | ||
| 88 | Xbyak::util::xmm6, | ||
| 89 | Xbyak::util::xmm7, | ||
| 90 | Xbyak::util::xmm8, | ||
| 91 | Xbyak::util::xmm9, | ||
| 92 | Xbyak::util::xmm10, | ||
| 93 | Xbyak::util::xmm11, | ||
| 94 | Xbyak::util::xmm12, | ||
| 95 | Xbyak::util::xmm13, | ||
| 96 | Xbyak::util::xmm14, | ||
| 97 | Xbyak::util::xmm15, | ||
| 98 | }); | ||
| 99 | |||
| 100 | constexpr std::size_t ABI_SHADOW_SPACE = 0x20; | ||
| 101 | |||
| 102 | #else | ||
| 103 | |||
| 104 | // System V x86-64 ABI | ||
| 105 | const Xbyak::Reg ABI_RETURN = Xbyak::util::rax; | ||
| 106 | const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi; | ||
| 107 | const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi; | ||
| 108 | const Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx; | ||
| 109 | const Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx; | ||
| 110 | |||
| 111 | const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({ | ||
| 112 | // GPRs | ||
| 113 | Xbyak::util::rcx, | ||
| 114 | Xbyak::util::rdx, | ||
| 115 | Xbyak::util::rdi, | ||
| 116 | Xbyak::util::rsi, | ||
| 117 | Xbyak::util::r8, | ||
| 118 | Xbyak::util::r9, | ||
| 119 | Xbyak::util::r10, | ||
| 120 | Xbyak::util::r11, | ||
| 121 | // XMMs | ||
| 122 | Xbyak::util::xmm0, | ||
| 123 | Xbyak::util::xmm1, | ||
| 124 | Xbyak::util::xmm2, | ||
| 125 | Xbyak::util::xmm3, | ||
| 126 | Xbyak::util::xmm4, | ||
| 127 | Xbyak::util::xmm5, | ||
| 128 | Xbyak::util::xmm6, | ||
| 129 | Xbyak::util::xmm7, | ||
| 130 | Xbyak::util::xmm8, | ||
| 131 | Xbyak::util::xmm9, | ||
| 132 | Xbyak::util::xmm10, | ||
| 133 | Xbyak::util::xmm11, | ||
| 134 | Xbyak::util::xmm12, | ||
| 135 | Xbyak::util::xmm13, | ||
| 136 | Xbyak::util::xmm14, | ||
| 137 | Xbyak::util::xmm15, | ||
| 138 | }); | ||
| 139 | |||
| 140 | const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({ | ||
| 141 | // GPRs | ||
| 142 | Xbyak::util::rbx, | ||
| 143 | Xbyak::util::rbp, | ||
| 144 | Xbyak::util::r12, | ||
| 145 | Xbyak::util::r13, | ||
| 146 | Xbyak::util::r14, | ||
| 147 | Xbyak::util::r15, | ||
| 148 | }); | ||
| 149 | |||
| 150 | constexpr std::size_t ABI_SHADOW_SPACE = 0; | ||
| 151 | |||
| 152 | #endif | ||
| 153 | |||
| 154 | inline void ABI_CalculateFrameSize(BitSet32 regs, std::size_t rsp_alignment, | ||
| 155 | std::size_t needed_frame_size, s32* out_subtraction, | ||
| 156 | s32* out_xmm_offset) { | ||
| 157 | int count = (regs & ABI_ALL_GPRS).Count(); | ||
| 158 | rsp_alignment -= count * 8; | ||
| 159 | std::size_t subtraction = 0; | ||
| 160 | int xmm_count = (regs & ABI_ALL_XMMS).Count(); | ||
| 161 | if (xmm_count) { | ||
| 162 | // If we have any XMMs to save, we must align the stack here. | ||
| 163 | subtraction = rsp_alignment & 0xF; | ||
| 164 | } | ||
| 165 | subtraction += 0x10 * xmm_count; | ||
| 166 | std::size_t xmm_base_subtraction = subtraction; | ||
| 167 | subtraction += needed_frame_size; | ||
| 168 | subtraction += ABI_SHADOW_SPACE; | ||
| 169 | // Final alignment. | ||
| 170 | rsp_alignment -= subtraction; | ||
| 171 | subtraction += rsp_alignment & 0xF; | ||
| 172 | |||
| 173 | *out_subtraction = (s32)subtraction; | ||
| 174 | *out_xmm_offset = (s32)(subtraction - xmm_base_subtraction); | ||
| 175 | } | ||
| 176 | |||
| 177 | inline std::size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, | ||
| 178 | std::size_t rsp_alignment, | ||
| 179 | std::size_t needed_frame_size = 0) { | ||
| 180 | s32 subtraction, xmm_offset; | ||
| 181 | ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset); | ||
| 182 | |||
| 183 | for (int reg_index : (regs & ABI_ALL_GPRS)) { | ||
| 184 | code.push(IndexToReg64(reg_index)); | ||
| 185 | } | ||
| 186 | |||
| 187 | if (subtraction != 0) { | ||
| 188 | code.sub(code.rsp, subtraction); | ||
| 189 | } | ||
| 190 | |||
| 191 | for (int reg_index : (regs & ABI_ALL_XMMS)) { | ||
| 192 | code.movaps(code.xword[code.rsp + xmm_offset], IndexToXmm(reg_index)); | ||
| 193 | xmm_offset += 0x10; | ||
| 194 | } | ||
| 195 | |||
| 196 | return ABI_SHADOW_SPACE; | ||
| 197 | } | ||
| 198 | |||
| 199 | inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, | ||
| 200 | std::size_t rsp_alignment, | ||
| 201 | std::size_t needed_frame_size = 0) { | ||
| 202 | s32 subtraction, xmm_offset; | ||
| 203 | ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset); | ||
| 204 | |||
| 205 | for (int reg_index : (regs & ABI_ALL_XMMS)) { | ||
| 206 | code.movaps(IndexToXmm(reg_index), code.xword[code.rsp + xmm_offset]); | ||
| 207 | xmm_offset += 0x10; | ||
| 208 | } | ||
| 209 | |||
| 210 | if (subtraction != 0) { | ||
| 211 | code.add(code.rsp, subtraction); | ||
| 212 | } | ||
| 213 | |||
| 214 | // GPRs need to be popped in reverse order | ||
| 215 | for (int reg_index = 15; reg_index >= 0; reg_index--) { | ||
| 216 | if (regs[reg_index]) { | ||
| 217 | code.pop(IndexToReg64(reg_index)); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | } // namespace Common::X64 | ||
diff --git a/src/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h deleted file mode 100644 index 5cc8a8c76..000000000 --- a/src/common/x64/xbyak_util.h +++ /dev/null | |||
| @@ -1,47 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <type_traits> | ||
| 8 | #include <xbyak.h> | ||
| 9 | #include "common/x64/xbyak_abi.h" | ||
| 10 | |||
| 11 | namespace Common::X64 { | ||
| 12 | |||
| 13 | // Constants for use with cmpps/cmpss | ||
| 14 | enum { | ||
| 15 | CMP_EQ = 0, | ||
| 16 | CMP_LT = 1, | ||
| 17 | CMP_LE = 2, | ||
| 18 | CMP_UNORD = 3, | ||
| 19 | CMP_NEQ = 4, | ||
| 20 | CMP_NLT = 5, | ||
| 21 | CMP_NLE = 6, | ||
| 22 | CMP_ORD = 7, | ||
| 23 | }; | ||
| 24 | |||
| 25 | inline bool IsWithin2G(uintptr_t ref, uintptr_t target) { | ||
| 26 | u64 distance = target - (ref + 5); | ||
| 27 | return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL); | ||
| 28 | } | ||
| 29 | |||
| 30 | inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) { | ||
| 31 | return IsWithin2G(reinterpret_cast<uintptr_t>(code.getCurr()), target); | ||
| 32 | } | ||
| 33 | |||
| 34 | template <typename T> | ||
| 35 | inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) { | ||
| 36 | static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer."); | ||
| 37 | std::size_t addr = reinterpret_cast<std::size_t>(f); | ||
| 38 | if (IsWithin2G(code, addr)) { | ||
| 39 | code.call(f); | ||
| 40 | } else { | ||
| 41 | // ABI_RETURN is a safe temp register to use before a call | ||
| 42 | code.mov(ABI_RETURN, addr); | ||
| 43 | code.call(ABI_RETURN); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | } // namespace Common::X64 | ||