summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/assert.h26
-rw-r--r--src/common/bit_field.h26
-rw-r--r--src/common/bit_set.h203
-rw-r--r--src/common/break_points.cpp54
-rw-r--r--src/common/break_points.h18
-rw-r--r--src/common/chunk_file.h539
-rw-r--r--src/common/code_block.h42
-rw-r--r--src/common/color.h30
-rw-r--r--src/common/common_funcs.h25
-rw-r--r--src/common/common_paths.h54
-rw-r--r--src/common/common_types.h8
-rw-r--r--src/common/emu_window.cpp48
-rw-r--r--src/common/emu_window.h54
-rw-r--r--src/common/file_util.cpp515
-rw-r--r--src/common/file_util.h118
-rw-r--r--src/common/hash.cpp96
-rw-r--r--src/common/key_map.cpp30
-rw-r--r--src/common/key_map.h11
-rw-r--r--src/common/linear_disk_cache.h78
-rw-r--r--src/common/logging/backend.cpp139
-rw-r--r--src/common/logging/backend.h6
-rw-r--r--src/common/logging/filter.cpp7
-rw-r--r--src/common/logging/filter.h4
-rw-r--r--src/common/logging/log.h136
-rw-r--r--src/common/logging/text_formatter.cpp52
-rw-r--r--src/common/logging/text_formatter.h1
-rw-r--r--src/common/math_util.h33
-rw-r--r--src/common/memory_util.cpp90
-rw-r--r--src/common/memory_util.h6
-rw-r--r--src/common/microprofile.h2
-rw-r--r--src/common/misc.cpp8
-rw-r--r--src/common/platform.h4
-rw-r--r--src/common/profiler.cpp4
-rw-r--r--src/common/scope_exit.h23
-rw-r--r--src/common/string_util.cpp191
-rw-r--r--src/common/string_util.h56
-rw-r--r--src/common/swap.h331
-rw-r--r--src/common/symbols.cpp66
-rw-r--r--src/common/symbols.h25
-rw-r--r--src/common/synchronized_wrapper.h22
-rw-r--r--src/common/thread.cpp80
-rw-r--r--src/common/thread.h40
-rw-r--r--src/common/thread_queue_list.h22
-rw-r--r--src/common/timer.cpp73
-rw-r--r--src/common/timer.h11
-rw-r--r--src/common/vector_math.h707
-rw-r--r--src/common/x64/abi.cpp127
-rw-r--r--src/common/x64/abi.h15
-rw-r--r--src/common/x64/cpu_detect.cpp92
-rw-r--r--src/common/x64/emitter.cpp2612
-rw-r--r--src/common/x64/emitter.h601
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.
19template <typename Fn> 19template <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
25static 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)
114template<std::size_t position, std::size_t bits, typename T> 112template <std::size_t position, std::size_t bits, typename T>
115struct BitField 113struct BitField {
116{
117private: 114private:
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)
189static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, "BitField must be trivially copyable"); 182static_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
20template <typename T> 20template <typename T>
21static inline int CountSetBits(T v) 21static 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}
31static inline int LeastSignificantSetBit(u8 val) 30static 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}
37static inline int LeastSignificantSetBit(u16 val) 35static 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}
43static inline int LeastSignificantSetBit(u32 val) 40static 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}
49static inline int LeastSignificantSetBit(u64 val) 45static 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
56static inline int CountSetBits(u8 val) { return __builtin_popcount(val); } 51static inline int CountSetBits(u8 val) {
57static inline int CountSetBits(u16 val) { return __builtin_popcount(val); } 52 return __builtin_popcount(val);
58static inline int CountSetBits(u32 val) { return __builtin_popcount(val); } 53}
59static inline int CountSetBits(u64 val) { return __builtin_popcountll(val); } 54static inline int CountSetBits(u16 val) {
60static inline int LeastSignificantSetBit(u8 val) { return __builtin_ctz(val); } 55 return __builtin_popcount(val);
61static inline int LeastSignificantSetBit(u16 val) { return __builtin_ctz(val); } 56}
62static inline int LeastSignificantSetBit(u32 val) { return __builtin_ctz(val); } 57static inline int CountSetBits(u32 val) {
63static inline int LeastSignificantSetBit(u64 val) { return __builtin_ctzll(val); } 58 return __builtin_popcount(val);
59}
60static inline int CountSetBits(u64 val) {
61 return __builtin_popcountll(val);
62}
63static inline int LeastSignificantSetBit(u8 val) {
64 return __builtin_ctz(val);
65}
66static inline int LeastSignificantSetBit(u16 val) {
67 return __builtin_ctz(val);
68}
69static inline int LeastSignificantSetBit(u32 val) {
70 return __builtin_ctz(val);
71}
72static 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
86template <typename IntTy> 97template <typename IntTy>
87class BitSet 98class 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
90public: 101public:
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
11bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const 11bool 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
18bool BreakPoints::IsTempBreakPoint(u32 iAddress) const 17bool 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
25BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const 25BreakPoints::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
41void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) 38void 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
55void BreakPoints::Add(const TBreakPoint& bp) 50void 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
65void BreakPoints::Add(u32 em_address, bool temp) 58void 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
81void BreakPoints::Remove(u32 em_address) 73void 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
89void BreakPoints::Clear() 80void 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
12class DebugInterface; 12class DebugInterface;
13 13
14struct TBreakPoint 14struct 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.
22class BreakPoints 21class BreakPoints {
23{
24public: 22public:
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
47private: 47private:
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
43template <class T> 43template <class T>
44struct LinkedListItem : public T 44struct LinkedListItem : public T {
45{ 45 LinkedListItem<T>* next;
46 LinkedListItem<T> *next;
47}; 46};
48 47
49class PointerWrap; 48class PointerWrap;
50 49
51class PointerWrapSection 50class PointerWrapSection {
52{
53public: 51public:
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
69private: 80private:
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
76class PointerWrap 87class 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
113public: 118public:
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
131public: 136public:
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> {}
17template<class T> class CodeBlock : public T, NonCopyable 17template <class T>
18{ 18class CodeBlock : public T, NonCopyable {
19private: 19private:
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
24protected: 25protected:
25 u8 *region; 26 u8* region;
26 size_t region_size; 27 size_t region_size;
27 28
28public: 29public:
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 */
58inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) { 58inline 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 */
67inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) { 67inline 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 */
76inline const Math::Vec4<u8> DecodeRG8(const u8* bytes) { 76inline 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 */
85inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) { 85inline 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 */
96inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { 96inline 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 */
107inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) { 107inline 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 */
136inline const Math::Vec2<u32> DecodeD24S8(const u8* bytes) { 136inline 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 */
177inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { 177inline 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 */
187inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { 187inline 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 */
197inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) { 198inline 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
47inline u32 rotl(u32 x, int shift) { 47inline 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
57inline u32 rotr(u32 x, int shift) { 58inline 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
64inline u64 _rotl64(u64 x, unsigned int shift){ 66inline 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
69inline u64 _rotr64(u64 x, unsigned int shift){ 71inline 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
84extern "C" { 86extern "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
35typedef std::uint8_t u8; ///< 8-bit unsigned byte 35typedef std::uint8_t u8; ///< 8-bit unsigned byte
36typedef std::uint16_t u16; ///< 16-bit unsigned short 36typedef std::uint16_t u16; ///< 16-bit unsigned short
37typedef std::uint32_t u32; ///< 32-bit unsigned word 37typedef std::uint32_t u32; ///< 32-bit unsigned word
38typedef std::uint64_t u64; ///< 64-bit unsigned int 38typedef std::uint64_t u64; ///< 64-bit unsigned int
39 39
40typedef std::int8_t s8; ///< 8-bit signed byte 40typedef std::int8_t s8; ///< 8-bit signed byte
41typedef std::int16_t s16; ///< 16-bit signed short 41typedef std::int16_t s16; ///< 16-bit signed short
42typedef std::int32_t s32; ///< 32-bit signed word 42typedef std::int32_t s32; ///< 32-bit signed word
43typedef std::int64_t s64; ///< 64-bit signed int 43typedef std::int64_t s64; ///< 64-bit signed int
44 44
45typedef float f32; ///< 32-bit floating point 45typedef float f32; ///< 32-bit floating point
46typedef double f64; ///< 64-bit floating point 46typedef 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 */
45static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsigned framebuffer_x, 45static 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
53std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { 52std::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
93EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) { 94EmuWindow::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 */
33class EmuWindow 33class EmuWindow {
34{
35public: 34public:
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:
266private: 269private:
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!
63namespace FileUtil 63namespace 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.
68static void StripTailDirSlashes(std::string &fname) 67static 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
81bool Exists(const std::string &filename) 78bool 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
102bool IsDirectory(const std::string &filename) 98bool 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
130bool Delete(const std::string &filename) 125bool 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.
168bool CreateDir(const std::string &path) 159bool 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
200bool CreateFullPath(const std::string &fullPath) 189bool 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
241bool DeleteDir(const std::string &filename) 225bool 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
265bool Rename(const std::string &srcFilename, const std::string &destFilename) 247bool 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
282bool Copy(const std::string &srcFilename, const std::string &destFilename) 263bool 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)
359u64 GetSize(const std::string &filename) 331u64 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
391u64 GetSize(const int fd) 358u64 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*
403u64 GetSize(FILE *f) 368u64 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
422bool CreateEmptyFile(const std::string &filename) 384bool 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 395bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory,
437bool 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
496unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion) 454unsigned 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 487bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) {
530bool 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)
554void CopyDir(const std::string &source_path, const std::string &dest_path) 509void 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
589std::string GetCurrentDir() 546std::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
613bool SetCurrentDir(const std::string &directory) 568bool 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__)
623std::string GetBundleDirectory() 577std::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
639std::string& GetExeDirectory() 592std::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
702std::string GetSysDirectory() 654std::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).
721const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) 672const 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
831size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename) 775size_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
836size_t ReadFileToString(bool text_file, const char *filename, std::string &str) 779size_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
889IOFile::IOFile() 831IOFile::IOFile() {
890{
891} 832}
892 833
893IOFile::IOFile(const std::string& filename, const char openmode[]) 834IOFile::IOFile(const std::string& filename, const char openmode[]) {
894{
895 Open(filename, openmode); 835 Open(filename, openmode);
896} 836}
897 837
898IOFile::~IOFile() 838IOFile::~IOFile() {
899{
900 Close(); 839 Close();
901} 840}
902 841
903IOFile::IOFile(IOFile&& other) 842IOFile::IOFile(IOFile&& other) {
904{
905 Swap(other); 843 Swap(other);
906} 844}
907 845
908IOFile& IOFile::operator=(IOFile&& other) 846IOFile& IOFile::operator=(IOFile&& other) {
909{
910 Swap(other); 847 Swap(other);
911 return *this; 848 return *this;
912} 849}
913 850
914void IOFile::Swap(IOFile& other) 851void 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
920bool IOFile::Open(const std::string& filename, const char openmode[]) 856bool 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
933bool IOFile::Close() 869bool 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
942u64 IOFile::GetSize() const 877u64 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
950bool IOFile::Seek(s64 off, int origin) 884bool 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
958u64 IOFile::Tell() const 891u64 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
966bool IOFile::Flush() 898bool 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
974bool IOFile::Resize(u64 size) 905bool 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
54namespace FileUtil 54namespace FileUtil {
55{
56 55
57// FileSystem tree node/ 56// FileSystem tree node/
58struct FSTEntry 57struct 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
68bool Exists(const std::string &filename); 66bool Exists(const std::string& filename);
69 67
70// Returns true if filename is a directory 68// Returns true if filename is a directory
71bool IsDirectory(const std::string &filename); 69bool IsDirectory(const std::string& filename);
72 70
73// Returns the size of filename (64bit) 71// Returns the size of filename (64bit)
74u64 GetSize(const std::string &filename); 72u64 GetSize(const std::string& filename);
75 73
76// Overloaded GetSize, accepts file descriptor 74// Overloaded GetSize, accepts file descriptor
77u64 GetSize(const int fd); 75u64 GetSize(const int fd);
78 76
79// Overloaded GetSize, accepts FILE* 77// Overloaded GetSize, accepts FILE*
80u64 GetSize(FILE *f); 78u64 GetSize(FILE* f);
81 79
82// Returns true if successful, or path already exists. 80// Returns true if successful, or path already exists.
83bool CreateDir(const std::string &filename); 81bool 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
86bool CreateFullPath(const std::string &fullPath); 84bool 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
90bool Delete(const std::string &filename); 88bool 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
93bool DeleteDir(const std::string &filename); 91bool 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
96bool Rename(const std::string &srcFilename, const std::string &destFilename); 94bool 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
99bool Copy(const std::string &srcFilename, const std::string &destFilename); 97bool 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
102bool CreateEmptyFile(const std::string &filename); 100bool 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 */
110using DirectoryEntryCallable = std::function<bool(unsigned* num_entries_out, 109using 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 */
122bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback); 121bool 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 */
131unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion = 0); 131unsigned 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.
134bool DeleteDirRecursively(const std::string &directory, unsigned int recursion = 256); 135bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256);
135 136
136// Returns the current directory 137// Returns the current directory
137std::string GetCurrentDir(); 138std::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)
140void CopyDir(const std::string &source_path, const std::string &dest_path); 141void 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
143bool SetCurrentDir(const std::string &directory); 144bool 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).
147const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); 148const 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
150std::string GetSysDirectory(); 151std::string GetSysDirectory();
@@ -154,11 +155,11 @@ std::string GetBundleDirectory();
154#endif 155#endif
155 156
156#ifdef _WIN32 157#ifdef _WIN32
157std::string &GetExeDirectory(); 158std::string& GetExeDirectory();
158#endif 159#endif
159 160
160size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename); 161size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename);
161size_t ReadFileToString(bool text_file, const char *filename, std::string &str); 162size_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
176class IOFile : public NonCopyable 177class IOFile : public NonCopyable {
177{
178public: 178public:
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
263private: 272private:
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:
271template <typename T> 280template <typename T>
272void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) 281void 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
38void MurmurHash3_128(const void* key, int len, u32 seed, void* out) { 38void 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.
15const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{ 15const 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
55int NewDeviceId() { 70int NewDeviceId() {
@@ -103,7 +118,7 @@ void PressKey(EmuWindow& emu_window, HostDeviceKey key) {
103 } 118 }
104} 119}
105 120
106void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) { 121void 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 */
94void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key); 92void 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
11extern const char *scm_rev_git_str; 11extern 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
27template <typename K, typename V> 27template <typename K, typename V>
28class LinearDiskCacheReader 28class LinearDiskCacheReader {
29{
30public: 29public:
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
46template <typename K, typename V> 45template <typename K, typename V>
47class LinearDiskCache 46class LinearDiskCache {
48{
49public: 47public:
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
143private: 132private:
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 @@
16namespace Log { 16namespace 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...
72const char* GetLogClassName(Class log_class) { 72const 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
84const char* GetLevelName(Level log_level) { 88const 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
99Entry CreateEntry(Class log_class, Level log_level, 105Entry 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
129void LogMessage(Class log_class, Level log_level, 135void 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);
44const char* GetLevelName(Level log_level); 44const 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.
47Entry CreateEntry(Class log_class, Level log_level, 47Entry 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
51void SetFilter(Filter* filter); 50void 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
11namespace Log { 11namespace Log {
@@ -63,11 +63,11 @@ static Class GetClassByName(const It begin, const It end) {
63} 63}
64 64
65bool Filter::ParseFilterRule(const std::string::const_iterator begin, 65bool 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,
95bool Filter::CheckMessage(Class log_class, Level level) const { 95bool 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:
50private: 51private:
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 */
33enum class Class : ClassType { 34enum 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.
90void LogMessage(Class log_class, Level log_level, 91void 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
46void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) { 46void 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
58void PrintMessage(const Entry& entry) { 57void 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);
28void PrintMessage(const Entry& entry); 28void 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.
30void PrintColoredMessage(const Entry& entry); 30void 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
11namespace MathUtil 11namespace MathUtil {
12{
13 12
14inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1, unsigned length1) { 13inline 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
18template<typename T> 18template <typename T>
19inline T Clamp(const T val, const T& min, const T& max) 19inline 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
24template<class T> 23template <class T>
25struct Rectangle 24struct 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
28void* AllocateExecutableMemory(size_t size, bool low) 27void* 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
81void* AllocateMemoryPages(size_t size) 75void* 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
99void* AllocateAlignedMemory(size_t size,size_t alignment) 91void* 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
119void FreeMemoryPages(void* ptr, size_t size) 110void 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
132void FreeAlignedMemory(void* ptr) 121void 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
144void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) 131void 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
155void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) 141void 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
166std::string MemUsage() 153std::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 @@
10void* AllocateExecutableMemory(size_t size, bool low = true); 10void* AllocateExecutableMemory(size_t size, bool low = true);
11void* AllocateMemoryPages(size_t size); 11void* AllocateMemoryPages(size_t size);
12void FreeMemoryPages(void* ptr, size_t size); 12void FreeMemoryPages(void* ptr, size_t size);
13void* AllocateAlignedMemory(size_t size,size_t alignment); 13void* AllocateAlignedMemory(size_t size, size_t alignment);
14void FreeAlignedMemory(void* ptr); 14void FreeAlignedMemory(void* ptr);
15void WriteProtectMemory(void* ptr, size_t size, bool executable = false); 15void WriteProtectMemory(void* ptr, size_t size, bool executable = false);
16void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false); 16void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false);
17std::string MemUsage(); 17std::string MemUsage();
18 18
19inline int GetPageSize() { return 4096; } 19inline 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.
22const char* GetLastErrorMsg() 22const 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 {
14namespace Profiling { 14namespace Profiling {
15 15
16ProfilingManager::ProfilingManager() 16ProfilingManager::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
20void ProfilingManager::BeginFrame() { 20void ProfilingManager::BeginFrame() {
@@ -31,7 +31,7 @@ void ProfilingManager::FinishFrame() {
31} 31}
32 32
33TimingResultsAggregator::TimingResultsAggregator(size_t window_size) 33TimingResultsAggregator::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
10namespace detail { 10namespace detail {
11 template <typename Func> 11template <typename Func>
12 struct ScopeExitHelper { 12struct 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> 22template <typename Func>
20 ScopeExitHelper<Func> ScopeExit(Func&& func) { return ScopeExitHelper<Func>(std::move(func)); } 23ScopeExitHelper<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
24namespace Common { 24namespace Common {
@@ -36,9 +36,8 @@ std::string ToUpper(std::string str) {
36} 36}
37 37
38// faster than sscanf 38// faster than sscanf
39bool AsciiToHex(const char* _szValue, u32& result) 39bool 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
51bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) 50bool 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
99std::string StringFromFormat(const char* format, ...) 94std::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.
127std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) 121std::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.
149std::string StripSpaces(const std::string &str) 139std::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.
162std::string StripQuotes(const std::string& s) 151std::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
170bool TryParse(const std::string &str, u32 *const output) 158bool 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
195bool TryParse(const std::string &str, bool *const output) 181bool 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
207std::string StringFromBool(bool value) 192std::string StringFromBool(bool value) {
208{
209 return value ? "True" : "False"; 193 return value ? "True" : "False";
210} 194}
211 195
212bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) 196bool 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
244void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename) 228void 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
256void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) 240void 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
267std::string TabsToSpaces(int tab_size, const std::string &in) 250std::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
279std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) 261std::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
297std::string UTF16ToUTF8(const std::u16string& input) 277std::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
310std::u16string UTF8ToUTF16(const std::string& input) 289std::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
323static std::wstring CPToUTF16(u32 code_page, const std::string& input) 301static 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
336std::string UTF16ToUTF8(const std::wstring& input) 316std::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
349std::wstring UTF8ToUTF16W(const std::string &input) 331std::wstring UTF8ToUTF16W(const std::string& input) {
350{
351 return CPToUTF16(CP_UTF8, input); 332 return CPToUTF16(CP_UTF8, input);
352} 333}
353 334
354std::string SHIFTJISToUTF8(const std::string& input) 335std::string SHIFTJISToUTF8(const std::string& input) {
355{
356 return UTF16ToUTF8(CPToUTF16(932, input)); 336 return UTF16ToUTF8(CPToUTF16(932, input));
357} 337}
358 338
359std::string CP1252ToUTF8(const std::string& input) 339std::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
366template <typename T> 345template <typename T>
367static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) 346static 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
423std::u16string UTF8ToUTF16(const std::string& input) 394std::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
479std::string UTF16ToUTF8(const std::u16string& input) 442std::string UTF16ToUTF8(const std::u16string& input) {
480{
481 return CodeToUTF8("UTF-16LE", input); 443 return CodeToUTF8("UTF-16LE", input);
482} 444}
483 445
484std::string CP1252ToUTF8(const std::string& input) 446std::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
491std::string SHIFTJISToUTF8(const std::string& input) 452std::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
499std::string StringFromFixedZeroTerminatedBuffer(const char * buffer, size_t max_len) { 459std::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!
26bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); 26bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args);
27 27
28template<size_t Count> 28template <size_t Count>
29inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) 29inline 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
38std::string ArrayToString(const u8 *data, u32 size, int line_len = 20, bool spaces = true); 37std::string ArrayToString(const u8* data, u32 size, int line_len = 20, bool spaces = true);
39 38
40std::string StripSpaces(const std::string &s); 39std::string StripSpaces(const std::string& s);
41std::string StripQuotes(const std::string &s); 40std::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
44template <typename I> 43template <typename I>
45std::string ThousandSeparate(I value, int spaces = 0) 44std::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
58std::string StringFromBool(bool value); 56std::string StringFromBool(bool value);
59 57
60bool TryParse(const std::string &str, bool *output); 58bool TryParse(const std::string& str, bool* output);
61bool TryParse(const std::string &str, u32 *output); 59bool TryParse(const std::string& str, u32* output);
62 60
63template <typename N> 61template <typename N>
64static bool TryParse(const std::string &str, N *const output) 62static 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
79bool AsciiToHex(const char* _szValue, u32& result); 74bool AsciiToHex(const char* _szValue, u32& result);
80 75
81std::string TabsToSpaces(int tab_size, const std::string &in); 76std::string TabsToSpaces(int tab_size, const std::string& in);
82 77
83void SplitString(const std::string& str, char delim, std::vector<std::string>& output); 78void 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"
86bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); 81bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
82 std::string* _pExtension);
87 83
88void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename); 84void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
85 const std::string& _Filename);
89std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); 86std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest);
90 87
91std::string UTF16ToUTF8(const std::u16string& input); 88std::string UTF16ToUTF8(const std::u16string& input);
@@ -99,17 +96,21 @@ std::string UTF16ToUTF8(const std::wstring& input);
99std::wstring UTF8ToUTF16W(const std::string& str); 96std::wstring UTF8ToUTF16W(const std::string& str);
100 97
101#ifdef _UNICODE 98#ifdef _UNICODE
102inline std::string TStrToUTF8(const std::wstring& str) 99inline std::string TStrToUTF8(const std::wstring& str) {
103{ return UTF16ToUTF8(str); } 100 return UTF16ToUTF8(str);
101}
104 102
105inline std::wstring UTF8ToTStr(const std::string& str) 103inline std::wstring UTF8ToTStr(const std::string& str) {
106{ return UTF8ToUTF16W(str); } 104 return UTF8ToUTF16W(str);
105}
107#else 106#else
108inline std::string TStrToUTF8(const std::string& str) 107inline std::string TStrToUTF8(const std::string& str) {
109{ return str; } 108 return str;
109}
110 110
111inline std::string UTF8ToTStr(const std::string& str) 111inline 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 */
136std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len); 137std::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 @@
61namespace Common { 61namespace Common {
62 62
63#ifdef _MSC_VER 63#ifdef _MSC_VER
64inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} 64inline u16 swap16(u16 _data) {
65inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} 65 return _byteswap_ushort(_data);
66inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} 66}
67inline u32 swap32(u32 _data) {
68 return _byteswap_ulong(_data);
69}
70inline u64 swap64(u64 _data) {
71 return _byteswap_uint64(_data);
72}
67#elif _M_ARM 73#elif _M_ARM
68inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} 74inline u16 swap16(u16 _data) {
69inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} 75 u32 data = _data;
70inline 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}
79inline u32 swap32(u32 _data) {
80 __asm__("rev %0, %1\n" : "=l"(_data) : "l"(_data));
81 return _data;
82}
83inline u64 swap64(u64 _data) {
84 return ((u64)swap32(_data) << 32) | swap32(_data >> 32);
85}
71#elif __linux__ 86#elif __linux__
72inline u16 swap16(u16 _data) {return bswap_16(_data);} 87inline u16 swap16(u16 _data) {
73inline u32 swap32(u32 _data) {return bswap_32(_data);} 88 return bswap_16(_data);
74inline u64 swap64(u64 _data) {return bswap_64(_data);} 89}
90inline u32 swap32(u32 _data) {
91 return bswap_32(_data);
92}
93inline u64 swap64(u64 _data) {
94 return bswap_64(_data);
95}
75#elif __APPLE__ 96#elif __APPLE__
76inline __attribute__((always_inline)) u16 swap16(u16 _data) 97inline __attribute__((always_inline)) u16 swap16(u16 _data) {
77{return (_data >> 8) | (_data << 8);} 98 return (_data >> 8) | (_data << 8);
78inline __attribute__((always_inline)) u32 swap32(u32 _data) 99}
79{return __builtin_bswap32(_data);} 100inline __attribute__((always_inline)) u32 swap32(u32 _data) {
80inline __attribute__((always_inline)) u64 swap64(u64 _data) 101 return __builtin_bswap32(_data);
81{return __builtin_bswap64(_data);} 102}
103inline __attribute__((always_inline)) u64 swap64(u64 _data) {
104 return __builtin_bswap64(_data);
105}
82#elif __FreeBSD__ 106#elif __FreeBSD__
83inline u16 swap16(u16 _data) {return bswap16(_data);} 107inline u16 swap16(u16 _data) {
84inline u32 swap32(u32 _data) {return bswap32(_data);} 108 return bswap16(_data);
85inline u64 swap64(u64 _data) {return bswap64(_data);} 109}
110inline u32 swap32(u32 _data) {
111 return bswap32(_data);
112}
113inline u64 swap64(u64 _data) {
114 return bswap64(_data);
115}
86#else 116#else
87// Slow generic implementation. 117// Slow generic implementation.
88inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} 118inline u16 swap16(u16 data) {
89inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} 119 return (data >> 8) | (data << 8);
90inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} 120}
121inline u32 swap32(u32 data) {
122 return (swap16(data) << 16) | swap16(data >> 16);
123}
124inline u64 swap64(u64 data) {
125 return ((u64)swap32(data) << 32) | swap32(data >> 32);
126}
91#endif 127#endif
92 128
93inline float swapf(float f) { 129inline 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
106inline double swapd(double f) { 141inline 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
122template <typename T, typename F> 155template <typename T, typename F>
123struct swap_struct_t { 156struct 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
132public: 166public:
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
434template <typename S, typename T, typename F> 486template <typename S, typename T, typename F>
435S operator+(const S &i, const swap_struct_t<T, F> v) { 487S 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
439template <typename S, typename T, typename F> 491template <typename S, typename T, typename F>
440S operator-(const S &i, const swap_struct_t<T, F> v) { 492S 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
444template <typename S, typename T, typename F> 496template <typename S, typename T, typename F>
445S operator/(const S &i, const swap_struct_t<T, F> v) { 497S 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
449template <typename S, typename T, typename F> 501template <typename S, typename T, typename F>
450S operator*(const S &i, const swap_struct_t<T, F> v) { 502S 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
454template <typename S, typename T, typename F> 506template <typename S, typename T, typename F>
455S operator%(const S &i, const swap_struct_t<T, F> v) { 507S 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
460template <typename S, typename T, typename F> 512template <typename S, typename T, typename F>
461S &operator+=(S &i, const swap_struct_t<T, F> v) { 513S& 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
466template <typename S, typename T, typename F> 518template <typename S, typename T, typename F>
467S &operator-=(S &i, const swap_struct_t<T, F> v) { 519S& 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
473template <typename S, typename T, typename F> 525template <typename S, typename T, typename F>
474S operator&(const S &i, const swap_struct_t<T, F> v) { 526S 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
478template <typename S, typename T, typename F> 530template <typename S, typename T, typename F>
479S operator&(const swap_struct_t<T, F> v, const S &i) { 531S 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
485template <typename S, typename T, typename F> 536template <typename S, typename T, typename F>
486bool operator<(const S &p, const swap_struct_t<T, F> v) { 537bool operator<(const S& p, const swap_struct_t<T, F> v) {
487 return p < v.swap(); 538 return p < v.swap();
488} 539}
489template <typename S, typename T, typename F> 540template <typename S, typename T, typename F>
490bool operator>(const S &p, const swap_struct_t<T, F> v) { 541bool operator>(const S& p, const swap_struct_t<T, F> v) {
491 return p > v.swap(); 542 return p > v.swap();
492} 543}
493template <typename S, typename T, typename F> 544template <typename S, typename T, typename F>
494bool operator<=(const S &p, const swap_struct_t<T, F> v) { 545bool operator<=(const S& p, const swap_struct_t<T, F> v) {
495 return p <= v.swap(); 546 return p <= v.swap();
496} 547}
497template <typename S, typename T, typename F> 548template <typename S, typename T, typename F>
498bool operator>=(const S &p, const swap_struct_t<T, F> v) { 549bool operator>=(const S& p, const swap_struct_t<T, F> v) {
499 return p >= v.swap(); 550 return p >= v.swap();
500} 551}
501template <typename S, typename T, typename F> 552template <typename S, typename T, typename F>
502bool operator!=(const S &p, const swap_struct_t<T, F> v) { 553bool operator!=(const S& p, const swap_struct_t<T, F> v) {
503 return p != v.swap(); 554 return p != v.swap();
504} 555}
505template <typename S, typename T, typename F> 556template <typename S, typename T, typename F>
506bool operator==(const S &p, const swap_struct_t<T, F> v) { 557bool 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;
554typedef float float_le; 605typedef float float_le;
555typedef double double_le; 606typedef double double_le;
556 607
557typedef swap_struct_t<u64, swap_64_t<u64> > u64_be; 608typedef swap_struct_t<u64, swap_64_t<u64>> u64_be;
558typedef swap_struct_t<s64, swap_64_t<s64> > s64_be; 609typedef swap_struct_t<s64, swap_64_t<s64>> s64_be;
559 610
560typedef swap_struct_t<u32, swap_32_t<u32> > u32_be; 611typedef swap_struct_t<u32, swap_32_t<u32>> u32_be;
561typedef swap_struct_t<s32, swap_32_t<s32> > s32_be; 612typedef swap_struct_t<s32, swap_32_t<s32>> s32_be;
562 613
563typedef swap_struct_t<u16, swap_16_t<u16> > u16_be; 614typedef swap_struct_t<u16, swap_16_t<u16>> u16_be;
564typedef swap_struct_t<s16, swap_16_t<s16> > s16_be; 615typedef swap_struct_t<s16, swap_16_t<s16>> s16_be;
565 616
566typedef swap_struct_t<float, swap_float_t<float> > float_be; 617typedef swap_struct_t<float, swap_float_t<float>> float_be;
567typedef swap_struct_t<double, swap_double_t<double> > double_be; 618typedef swap_struct_t<double, swap_double_t<double>> double_be;
568#else 619#else
569 620
570typedef swap_struct_t<u64, swap_64_t<u64> > u64_le; 621typedef swap_struct_t<u64, swap_64_t<u64>> u64_le;
571typedef swap_struct_t<s64, swap_64_t<s64> > s64_le; 622typedef swap_struct_t<s64, swap_64_t<s64>> s64_le;
572 623
573typedef swap_struct_t<u32, swap_32_t<u32> > u32_le; 624typedef swap_struct_t<u32, swap_32_t<u32>> u32_le;
574typedef swap_struct_t<s32, swap_32_t<s32> > s32_le; 625typedef swap_struct_t<s32, swap_32_t<s32>> s32_le;
575 626
576typedef swap_struct_t<u16, swap_16_t<u16> > u16_le; 627typedef swap_struct_t<u16, swap_16_t<u16>> u16_le;
577typedef swap_struct_t< s16, swap_16_t<s16> > s16_le; 628typedef swap_struct_t<s16, swap_16_t<s16>> s16_le;
578 629
579typedef swap_struct_t<float, swap_float_t<float> > float_le; 630typedef swap_struct_t<float, swap_float_t<float>> float_le;
580typedef swap_struct_t<double, swap_double_t<double> > double_le; 631typedef swap_struct_t<double, swap_double_t<double>> double_le;
581 632
582typedef u32 u32_be; 633typedef u32 u32_be;
583typedef u16 u16_be; 634typedef 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
7TSymbolsMap g_symbols; 7TSymbolsMap g_symbols;
8 8
9namespace Symbols 9namespace Symbols {
10{ 10bool 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 } 14void 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) 26TSymbol 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) 35const 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) 39void Remove(u32 address) {
46 { 40 g_symbols.erase(address);
47 g_symbols.erase(address); 41}
48 }
49 42
50 void Clear() 43void 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
13struct TSymbol 13struct 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
21typedef std::map<u32, TSymbol> TSymbolsMap; 20typedef std::map<u32, TSymbol> TSymbolsMap;
22typedef std::pair<u32, TSymbol> TSymbolsPair; 21typedef std::pair<u32, TSymbol> TSymbolsPair;
23 22
24namespace Symbols 23namespace Symbols {
25{ 24bool HasSymbol(u32 address);
26 bool HasSymbol(u32 address);
27 25
28 void Add(u32 address, const std::string& name, u32 size, u32 type); 26void Add(u32 address, const std::string& name, u32 size, u32 type);
29 TSymbol GetSymbol(u32 address); 27TSymbol GetSymbol(u32 address);
30 const std::string GetName(u32 address); 28const std::string GetName(u32 address);
31 void Remove(u32 address); 29void Remove(u32 address);
32 void Clear(); 30void 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 */
17template <typename T> 18template <typename T>
18class SynchronizedWrapper { 19class SynchronizedWrapper {
19public: 20public:
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
25private: 25private:
@@ -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
67private: 75private:
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
24namespace Common 24namespace Common {
25{
26 25
27int CurrentThreadId() 26int 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
40void SleepCurrentThread(int ms) 38void 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
48void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) 45void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
49{
50 SetThreadAffinityMask(thread, mask); 46 SetThreadAffinityMask(thread, mask);
51} 47}
52 48
53void SetCurrentThreadAffinity(u32 mask) 49void SetCurrentThreadAffinity(u32 mask) {
54{
55 SetThreadAffinityMask(GetCurrentThread(), mask); 50 SetThreadAffinityMask(GetCurrentThread(), mask);
56} 51}
57 52
58void SwitchCurrentThread() 53void 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
69void SetCurrentThreadName(const char* szThreadName) 63void 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
98void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) 88void 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
115void SetCurrentThreadAffinity(u32 mask) 103void SetCurrentThreadAffinity(u32 mask) {
116{
117 SetThreadAffinity(pthread_self(), mask); 104 SetThreadAffinity(pthread_self(), mask);
118} 105}
119 106
120#ifndef _WIN32 107#ifndef _WIN32
121void SleepCurrentThread(int ms) 108void SleepCurrentThread(int ms) {
122{
123 usleep(1000 * ms); 109 usleep(1000 * ms);
124} 110}
125 111
126void SwitchCurrentThread() 112void 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)
134void SetCurrentThreadName(const char* szThreadName) 119void 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
33namespace Common { 33namespace Common {
@@ -39,7 +39,8 @@ void SetCurrentThreadAffinity(u32 mask);
39 39
40class Event { 40class Event {
41public: 41public:
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
70class Barrier { 72class Barrier {
71public: 73public:
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
96void SleepCurrentThread(int ms); 100void SleepCurrentThread(int ms);
97void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms 101void 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
106void SetCurrentThreadName(const char *name); 110void 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
12namespace Common { 12namespace Common {
13 13
14template<class T, unsigned int N> 14template <class T, unsigned int N>
15struct ThreadQueueList { 15struct 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
19namespace Common 19namespace Common {
20{
21 20
22u32 Timer::GetTimeMs() 21u32 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
38Timer::Timer() 36Timer::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
45void Timer::Start() 41void 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
52void Timer::Stop() 47void 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
60void Timer::Update() 54void 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()
71u64 Timer::GetTimeDifference() 64u64 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.
78void Timer::AddTimeDifference() 70void 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()
84u64 Timer::GetTimeElapsed() 75u64 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()
97std::string Timer::GetTimeElapsedFormatted() const 89std::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
123void Timer::IncreaseResolution() 114void Timer::IncreaseResolution() {
124{
125#ifdef _WIN32 115#ifdef _WIN32
126 timeBeginPeriod(1); 116 timeBeginPeriod(1);
127#endif 117#endif
128} 118}
129 119
130void Timer::RestoreResolution() 120void 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
138u64 Timer::GetTimeSinceJan1970() 127u64 Timer::GetTimeSinceJan1970() {
139{
140 time_t ltime; 128 time_t ltime;
141 time(&ltime); 129 time(&ltime);
142 return((u64)ltime); 130 return ((u64)ltime);
143} 131}
144 132
145u64 Timer::GetLocalTimeSinceJan1970() 133u64 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.
168std::string Timer::GetTimeFormatted() 155std::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// ----------------
193double Timer::GetDoubleTime() 179double 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
10namespace Common 10namespace Common {
11{ 11class Timer {
12class Timer
13{
14public: 12public:
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
37namespace Math { 36namespace Math {
38 37
39template<typename T> class Vec2; 38template <typename T>
40template<typename T> class Vec3; 39class Vec2;
41template<typename T> class Vec4; 40template <typename T>
41class Vec3;
42template <typename T>
43class Vec4;
42 44
43template<typename T> 45template <typename T>
44static inline Vec2<T> MakeVec(const T& x, const T& y); 46static inline Vec2<T> MakeVec(const T& x, const T& y);
45template<typename T> 47template <typename T>
46static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z); 48static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z);
47template<typename T> 49template <typename T>
48static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w); 50static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w);
49 51
50 52template <typename T>
51template<typename T>
52class Vec2 { 53class Vec2 {
53public: 54public:
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
168template<typename T, typename V> 185template <typename T, typename V>
169Vec2<T> operator * (const V& f, const Vec2<T>& vec) 186Vec2<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
174typedef Vec2<float> Vec2f; 190typedef Vec2<float> Vec2f;
175 191
176template<typename T> 192template <typename T>
177class Vec3 193class Vec3 {
178{
179public: 194public:
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
328template<typename T, typename V> 382template <typename T, typename V>
329Vec3<T> operator * (const V& f, const Vec3<T>& vec) 383Vec3<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
334template<> 387template <>
335inline float Vec3<float>::Length() const { 388inline 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
339template<> 392template <>
340inline Vec3<float> Vec3<float>::Normalized() const { 393inline Vec3<float> Vec3<float>::Normalized() const {
341 return *this / Length(); 394 return *this / Length();
342} 395}
343 396
344
345typedef Vec3<float> Vec3f; 397typedef Vec3<float> Vec3f;
346 398
347template<typename T> 399template <typename T>
348class Vec4 400class Vec4 {
349{
350public: 401public:
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 604template <typename T, typename V>
529template<typename T, typename V> 605Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
530Vec4<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
535typedef Vec4<float> Vec4f; 609typedef Vec4<float> Vec4f;
536 610
537 611template <typename T>
538template<typename T> 612static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) {
539static 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
544template<typename T> 616template <typename T>
545static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) 617static 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
550template<typename T> 621template <typename T>
551static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) 622static 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
556template<typename T> 626template <typename T>
557static inline Vec3<decltype(T{}*T{}-T{}*T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) 627static 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
563template<typename X> 632template <typename X>
564static inline decltype(X{}*float{}+X{}*float{}) Lerp(const X& begin, const X& end, const float t) 633static 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
570template<typename X, int base> 639template <typename X, int base>
571static inline decltype((X{}*int{}+X{}*int{}) / base) LerpInt(const X& begin, const X& end, const int t) 640static 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
577template<typename T> 646template <typename T>
578static inline Vec2<T> MakeVec(const T& x, const T& y) 647static 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
583template<typename T> 651template <typename T>
584static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) 652static 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
589template<typename T> 656template <typename T>
590static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) 657static 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
595template<typename T> 661template <typename T>
596static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) 662static 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
601template<typename T> 666template <typename T>
602static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) 667static 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
607template<typename T> 671template <typename T>
608static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) 672static 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
613template<typename T> 676template <typename T>
614static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) 677static 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
619template<typename T> 681template <typename T>
620static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) 682static 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.
628template<typename T> 689template <typename T>
629static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) 690static 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
634template<typename T> 694template <typename T>
635static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) 695static 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
640template<typename T> 699template <typename T>
641static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) 700static 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
25void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp) { 25void 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
52size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size) { 53size_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
70void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size) { 73void 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
89void XEmitter::ABI_CallFunction(const void *func) { 94void 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
101void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1) { 105void 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
114void XEmitter::ABI_CallFunctionCC16(const void *func, u32 param1, u16 param2) { 117void 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
128void XEmitter::ABI_CallFunctionC(const void *func, u32 param1) { 130void 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
141void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2) { 142void 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
155void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32 param3) { 155void 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
170void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, void *param3) { 169void 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
185void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2, u32 param3, void *param4) { 183void 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
201void XEmitter::ABI_CallFunctionP(const void *func, void *param1) { 199void 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
214void XEmitter::ABI_CallFunctionPA(const void *func, void *param1, const Gen::OpArg &arg2) { 211void 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
229void XEmitter::ABI_CallFunctionPAA(const void *func, void *param1, const Gen::OpArg &arg2, const Gen::OpArg &arg3) { 225void 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
246void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, u32 param3) { 242void 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.
262void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) { 257void 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.
277void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2) { 271void 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
300void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32 param2) 293void 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
316void XEmitter::ABI_CallFunctionACC(const void *func, const Gen::OpArg &arg1, u32 param2, u32 param3) 307void 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
333void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1) 323void 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
348void XEmitter::ABI_CallFunctionAA(const void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2) 336void 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
22static inline void __cpuidex(int info[4], int function_id, int subfunction_id) { 22static 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
29namespace Gen 29namespace Gen {
30{
31 30
32struct NormalOpDef 31struct 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
38static const NormalOpDef normalops[11] = 36static 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
58enum NormalSSEOps 55enum 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 92void XEmitter::SetCodePtr(u8* ptr) {
97void XEmitter::SetCodePtr(u8 *ptr)
98{
99 code = ptr; 93 code = ptr;
100} 94}
101 95
102const u8 *XEmitter::GetCodePtr() const 96const u8* XEmitter::GetCodePtr() const {
103{
104 return code; 97 return code;
105} 98}
106 99
107u8 *XEmitter::GetWritableCodePtr() 100u8* XEmitter::GetWritableCodePtr() {
108{
109 return code; 101 return code;
110} 102}
111 103
112void XEmitter::Write8(u8 value) 104void XEmitter::Write8(u8 value) {
113{
114 *code++ = value; 105 *code++ = value;
115} 106}
116 107
117void XEmitter::Write16(u16 value) 108void 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
123void XEmitter::Write32(u32 value) 113void 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
129void XEmitter::Write64(u64 value) 118void 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
135void XEmitter::ReserveCodeSpace(int bytes) 123void 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
141const u8 *XEmitter::AlignCode4() 128const 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
149const u8 *XEmitter::AlignCode16() 135const 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
157const u8 *XEmitter::AlignCodePage() 142const 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.
168void XEmitter::CheckFlags() 152void 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
173void XEmitter::WriteModRM(int mod, int reg, int rm) 156void 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
178void XEmitter::WriteSIB(int scale, int index, int base) 160void 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
183void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const 164void 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
217void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, int W) const 200void 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
242void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, 222void 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
385void XEmitter::Rex(int w, int r, int x, int b) 363void 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
396void XEmitter::JMP(const u8* addr, bool force5Bytes) 373void 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
420void XEmitter::JMPptr(const OpArg& arg2) 392void 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
432void XEmitter::JMPself() 404void XEmitter::JMPself() {
433{
434 Write8(0xEB); 405 Write8(0xEB);
435 Write8(0xFE); 406 Write8(0xFE);
436} 407}
437 408
438void XEmitter::CALLptr(OpArg arg) 409void 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
447void XEmitter::CALL(const void* fnptr) 418void 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
458FixupBranch XEmitter::CALL() 426FixupBranch 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
470FixupBranch XEmitter::J(bool force5bytes) 437FixupBranch 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
489FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes) 452FixupBranch 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
509void XEmitter::J_CC(CCFlags conditionCode, const u8* addr, bool force5bytes) 468void 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
530void XEmitter::SetJumpTarget(const FixupBranch& branch) 484void 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
546void XEmitter::SetJumpTarget(const FixupBranch& branch, const u8* target) 498void 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.
564void XEmitter::INT3() {Write8(0xCC);} 514void XEmitter::INT3() {
565void XEmitter::RET() {Write8(0xC3);} 515 Write8(0xCC);
566void 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}
517void XEmitter::RET() {
518 Write8(0xC3);
519}
520void 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.
569void XEmitter::NOP(size_t size) 527void 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
629void XEmitter::PAUSE() {Write8(0xF3); NOP();} //use in tight spinloops for energy saving on some cpu 629void XEmitter::PAUSE() {
630void XEmitter::CLC() {CheckFlags(); Write8(0xF8);} //clear carry 630 Write8(0xF3);
631void XEmitter::CMC() {CheckFlags(); Write8(0xF5);} //flip carry 631 NOP();
632void XEmitter::STC() {CheckFlags(); Write8(0xF9);} //set carry 632} // use in tight spinloops for energy saving on some cpu
633void XEmitter::CLC() {
634 CheckFlags();
635 Write8(0xF8);
636} // clear carry
637void XEmitter::CMC() {
638 CheckFlags();
639 Write8(0xF5);
640} // flip carry
641void XEmitter::STC() {
642 CheckFlags();
643 Write8(0xF9);
644} // set carry
633 645
634//TODO: xchg ah, al ??? 646// TODO: xchg ah, al ???
635void XEmitter::XCHG_AHAL() 647void 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!
643void XEmitter::LAHF() {Write8(0x9F);} 654void XEmitter::LAHF() {
644void XEmitter::SAHF() {CheckFlags(); Write8(0x9E);} 655 Write8(0x9F);
656}
657void XEmitter::SAHF() {
658 CheckFlags();
659 Write8(0x9E);
660}
645 661
646void XEmitter::PUSHF() {Write8(0x9C);} 662void XEmitter::PUSHF() {
647void XEmitter::POPF() {CheckFlags(); Write8(0x9D);} 663 Write8(0x9C);
664}
665void XEmitter::POPF() {
666 CheckFlags();
667 Write8(0x9D);
668}
648 669
649void XEmitter::LFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xE8);} 670void XEmitter::LFENCE() {
650void XEmitter::MFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF0);} 671 Write8(0x0F);
651void XEmitter::SFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF8);} 672 Write8(0xAE);
673 Write8(0xE8);
674}
675void XEmitter::MFENCE() {
676 Write8(0x0F);
677 Write8(0xAE);
678 Write8(0xF0);
679}
680void XEmitter::SFENCE() {
681 Write8(0x0F);
682 Write8(0xAE);
683 Write8(0xF8);
684}
652 685
653void XEmitter::WriteSimple1Byte(int bits, u8 byte, X64Reg reg) 686void 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
661void XEmitter::WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg) 693void 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
670void XEmitter::CWD(int bits) 701void 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
678void XEmitter::CBW(int bits) 708void 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
690void XEmitter::PUSH(X64Reg reg) {WriteSimple1Byte(32, 0x50, reg);} 718void XEmitter::PUSH(X64Reg reg) {
691void XEmitter::POP(X64Reg reg) {WriteSimple1Byte(32, 0x58, reg);} 719 WriteSimple1Byte(32, 0x50, reg);
720}
721void XEmitter::POP(X64Reg reg) {
722 WriteSimple1Byte(32, 0x58, reg);
723}
692 724
693void XEmitter::PUSH(int bits, const OpArg& reg) 725void 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
729void XEmitter::POP(int /*bits*/, const OpArg& reg) 756void 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
737void XEmitter::BSWAP(int bits, X64Reg reg) 763void 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...
759void XEmitter::UD2() 777void XEmitter::UD2() {
760{
761 Write8(0x0F); 778 Write8(0x0F);
762 Write8(0x0B); 779 Write8(0x0B);
763} 780}
764 781
765void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) 782void 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
775void XEmitter::SETcc(CCFlags flag, OpArg dest) 791void 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
785void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) 800void 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
798void XEmitter::WriteMulDivType(int bits, OpArg src, int ext) 812void 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
817void XEmitter::MUL(int bits, const OpArg& src) {WriteMulDivType(bits, src, 4);} 827void XEmitter::MUL(int bits, const OpArg& src) {
818void XEmitter::DIV(int bits, const OpArg& src) {WriteMulDivType(bits, src, 6);} 828 WriteMulDivType(bits, src, 4);
819void XEmitter::IMUL(int bits, const OpArg& src) {WriteMulDivType(bits, src, 5);} 829}
820void XEmitter::IDIV(int bits, const OpArg& src) {WriteMulDivType(bits, src, 7);} 830void XEmitter::DIV(int bits, const OpArg& src) {
821void XEmitter::NEG(int bits, const OpArg& src) {WriteMulDivType(bits, src, 3);} 831 WriteMulDivType(bits, src, 6);
822void XEmitter::NOT(int bits, const OpArg& src) {WriteMulDivType(bits, src, 2);} 832}
833void XEmitter::IMUL(int bits, const OpArg& src) {
834 WriteMulDivType(bits, src, 5);
835}
836void XEmitter::IDIV(int bits, const OpArg& src) {
837 WriteMulDivType(bits, src, 7);
838}
839void XEmitter::NEG(int bits, const OpArg& src) {
840 WriteMulDivType(bits, src, 3);
841}
842void XEmitter::NOT(int bits, const OpArg& src) {
843 WriteMulDivType(bits, src, 2);
844}
823 845
824void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep) 846void 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
839void XEmitter::MOVNTI(int bits, const OpArg& dest, X64Reg src) 860void 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
846void XEmitter::BSF(int bits, X64Reg dest, const OpArg& src) {WriteBitSearchType(bits,dest,src,0xBC);} // Bottom bit to top bit 866void XEmitter::BSF(int bits, X64Reg dest, const OpArg& src) {
847void 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
869void XEmitter::BSR(int bits, X64Reg dest, const OpArg& src) {
870 WriteBitSearchType(bits, dest, src, 0xBD);
871} // Top bit to bottom bit
848 872
849void XEmitter::TZCNT(int bits, X64Reg dest, const OpArg& src) 873void 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}
856void XEmitter::LZCNT(int bits, X64Reg dest, const OpArg& src) 879void 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
864void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) 886void 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
897void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src) 910void 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
931void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) 935void 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 965void XEmitter::LEA(int bits, X64Reg dest, OpArg src) {
964void 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
976void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext) 976void 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
1017void XEmitter::ROL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 0);} 1009void XEmitter::ROL(int bits, const OpArg& dest, const OpArg& shift) {
1018void XEmitter::ROR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 1);} 1010 WriteShift(bits, dest, shift, 0);
1019void XEmitter::RCL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 2);} 1011}
1020void XEmitter::RCR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 3);} 1012void XEmitter::ROR(int bits, const OpArg& dest, const OpArg& shift) {
1021void XEmitter::SHL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 4);} 1013 WriteShift(bits, dest, shift, 1);
1022void XEmitter::SHR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 5);} 1014}
1023void XEmitter::SAR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 7);} 1015void XEmitter::RCL(int bits, const OpArg& dest, const OpArg& shift) {
1016 WriteShift(bits, dest, shift, 2);
1017}
1018void XEmitter::RCR(int bits, const OpArg& dest, const OpArg& shift) {
1019 WriteShift(bits, dest, shift, 3);
1020}
1021void XEmitter::SHL(int bits, const OpArg& dest, const OpArg& shift) {
1022 WriteShift(bits, dest, shift, 4);
1023}
1024void XEmitter::SHR(int bits, const OpArg& dest, const OpArg& shift) {
1025 WriteShift(bits, dest, shift, 5);
1026}
1027void 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
1026void XEmitter::WriteBitTest(int bits, const OpArg& dest, const OpArg& index, int ext) 1032void 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
1055void XEmitter::BT(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 4);} 1057void XEmitter::BT(int bits, const OpArg& dest, const OpArg& index) {
1056void XEmitter::BTS(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 5);} 1058 WriteBitTest(bits, dest, index, 4);
1057void XEmitter::BTR(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 6);} 1059}
1058void XEmitter::BTC(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 7);} 1060void XEmitter::BTS(int bits, const OpArg& dest, const OpArg& index) {
1061 WriteBitTest(bits, dest, index, 5);
1062}
1063void XEmitter::BTR(int bits, const OpArg& dest, const OpArg& index) {
1064 WriteBitTest(bits, dest, index, 6);
1065}
1066void 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
1061void XEmitter::SHRD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) 1071void 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
1093void XEmitter::SHLD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) 1099void 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
1125void OpArg::WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg _operandReg, int bits) 1127void 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
1137void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& operand, int bits) const 1138void 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
1283void XEmitter::WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2) 1258void 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
1309void XEmitter::ADD (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmADD, a1, a2);} 1278void XEmitter::ADD(int bits, const OpArg& a1, const OpArg& a2) {
1310void XEmitter::ADC (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmADC, a1, a2);} 1279 CheckFlags();
1311void XEmitter::SUB (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmSUB, a1, a2);} 1280 WriteNormalOp(this, bits, nrmADD, a1, a2);
1312void XEmitter::SBB (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmSBB, a1, a2);} 1281}
1313void XEmitter::AND (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmAND, a1, a2);} 1282void XEmitter::ADC(int bits, const OpArg& a1, const OpArg& a2) {
1314void XEmitter::OR (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmOR , a1, a2);} 1283 CheckFlags();
1315void XEmitter::XOR (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmXOR, a1, a2);} 1284 WriteNormalOp(this, bits, nrmADC, a1, a2);
1316void XEmitter::MOV (int bits, const OpArg& a1, const OpArg& a2) 1285}
1317{ 1286void XEmitter::SUB(int bits, const OpArg& a1, const OpArg& a2) {
1287 CheckFlags();
1288 WriteNormalOp(this, bits, nrmSUB, a1, a2);
1289}
1290void XEmitter::SBB(int bits, const OpArg& a1, const OpArg& a2) {
1291 CheckFlags();
1292 WriteNormalOp(this, bits, nrmSBB, a1, a2);
1293}
1294void XEmitter::AND(int bits, const OpArg& a1, const OpArg& a2) {
1295 CheckFlags();
1296 WriteNormalOp(this, bits, nrmAND, a1, a2);
1297}
1298void XEmitter::OR(int bits, const OpArg& a1, const OpArg& a2) {
1299 CheckFlags();
1300 WriteNormalOp(this, bits, nrmOR, a1, a2);
1301}
1302void XEmitter::XOR(int bits, const OpArg& a1, const OpArg& a2) {
1303 CheckFlags();
1304 WriteNormalOp(this, bits, nrmXOR, a1, a2);
1305}
1306void 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}
1322void XEmitter::TEST(int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmTEST, a1, a2);} 1311void XEmitter::TEST(int bits, const OpArg& a1, const OpArg& a2) {
1323void XEmitter::CMP (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmCMP, a1, a2);} 1312 CheckFlags();
1324void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) {WriteNormalOp(this, bits, nrmXCHG, a1, a2);} 1313 WriteNormalOp(this, bits, nrmTEST, a1, a2);
1314}
1315void XEmitter::CMP(int bits, const OpArg& a1, const OpArg& a2) {
1316 CheckFlags();
1317 WriteNormalOp(this, bits, nrmCMP, a1, a2);
1318}
1319void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) {
1320 WriteNormalOp(this, bits, nrmXCHG, a1, a2);
1321}
1325 1322
1326void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2) 1323void 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
1379void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a) 1363void 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 1383void XEmitter::WriteSSEOp(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extrabytes) {
1403void 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
1416void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) 1395void 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
1421static int GetVEXmmmmm(u16 op) 1399static 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
1432static int GetVEXpp(u8 opPrefix) 1409static 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
1444void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) 1420void 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
1457void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) 1434void 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
1468void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) 1445void 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
1476void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) 1453void 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
1484void XEmitter::MOVD_xmm(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x6E, dest, arg, 0);} 1461void XEmitter::MOVD_xmm(X64Reg dest, const OpArg& arg) {
1485void XEmitter::MOVD_xmm(const OpArg &arg, X64Reg src) {WriteSSEOp(0x66, 0x7E, src, arg, 0);} 1462 WriteSSEOp(0x66, 0x6E, dest, arg, 0);
1463}
1464void XEmitter::MOVD_xmm(const OpArg& arg, X64Reg src) {
1465 WriteSSEOp(0x66, 0x7E, src, arg, 0);
1466}
1486 1467
1487void XEmitter::MOVQ_xmm(X64Reg dest, OpArg arg) 1468void 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
1507void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) 1487void 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
1531void XEmitter::WriteMXCSR(OpArg arg, int ext) 1507void 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
1543void XEmitter::STMXCSR(const OpArg& memloc) {WriteMXCSR(memloc, 3);} 1518void XEmitter::STMXCSR(const OpArg& memloc) {
1544void XEmitter::LDMXCSR(const OpArg& memloc) {WriteMXCSR(memloc, 2);} 1519 WriteMXCSR(memloc, 3);
1545 1520}
1546void XEmitter::MOVNTDQ(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVNTDQ, regOp, arg);} 1521void XEmitter::LDMXCSR(const OpArg& memloc) {
1547void XEmitter::MOVNTPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVNTP, regOp, arg);} 1522 WriteMXCSR(memloc, 2);
1548void XEmitter::MOVNTPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVNTP, regOp, arg);} 1523}
1549 1524
1550void XEmitter::ADDSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseADD, regOp, arg);} 1525void XEmitter::MOVNTDQ(const OpArg& arg, X64Reg regOp) {
1551void XEmitter::ADDSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseADD, regOp, arg);} 1526 WriteSSEOp(0x66, sseMOVNTDQ, regOp, arg);
1552void XEmitter::SUBSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseSUB, regOp, arg);} 1527}
1553void XEmitter::SUBSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseSUB, regOp, arg);} 1528void XEmitter::MOVNTPS(const OpArg& arg, X64Reg regOp) {
1554void XEmitter::CMPSS(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0xF3, sseCMP, regOp, arg, 1); Write8(compare);} 1529 WriteSSEOp(0x00, sseMOVNTP, regOp, arg);
1555void XEmitter::CMPSD(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0xF2, sseCMP, regOp, arg, 1); Write8(compare);} 1530}
1556void XEmitter::MULSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMUL, regOp, arg);} 1531void XEmitter::MOVNTPD(const OpArg& arg, X64Reg regOp) {
1557void XEmitter::MULSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMUL, regOp, arg);} 1532 WriteSSEOp(0x66, sseMOVNTP, regOp, arg);
1558void XEmitter::DIVSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseDIV, regOp, arg);} 1533}
1559void XEmitter::DIVSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseDIV, regOp, arg);} 1534
1560void XEmitter::MINSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMIN, regOp, arg);} 1535void XEmitter::ADDSS(X64Reg regOp, const OpArg& arg) {
1561void XEmitter::MINSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMIN, regOp, arg);} 1536 WriteSSEOp(0xF3, sseADD, regOp, arg);
1562void XEmitter::MAXSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMAX, regOp, arg);} 1537}
1563void XEmitter::MAXSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMAX, regOp, arg);} 1538void XEmitter::ADDSD(X64Reg regOp, const OpArg& arg) {
1564void XEmitter::SQRTSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseSQRT, regOp, arg);} 1539 WriteSSEOp(0xF2, sseADD, regOp, arg);
1565void XEmitter::SQRTSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseSQRT, regOp, arg);} 1540}
1566void XEmitter::RCPSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseRCP, regOp, arg);} 1541void XEmitter::SUBSS(X64Reg regOp, const OpArg& arg) {
1567void XEmitter::RSQRTSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseRSQRT, regOp, arg);} 1542 WriteSSEOp(0xF3, sseSUB, regOp, arg);
1568 1543}
1569void XEmitter::ADDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseADD, regOp, arg);} 1544void XEmitter::SUBSD(X64Reg regOp, const OpArg& arg) {
1570void XEmitter::ADDPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseADD, regOp, arg);} 1545 WriteSSEOp(0xF2, sseSUB, regOp, arg);
1571void XEmitter::SUBPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseSUB, regOp, arg);} 1546}
1572void XEmitter::SUBPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseSUB, regOp, arg);} 1547void XEmitter::CMPSS(X64Reg regOp, const OpArg& arg, u8 compare) {
1573void XEmitter::CMPPS(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0x00, sseCMP, regOp, arg, 1); Write8(compare);} 1548 WriteSSEOp(0xF3, sseCMP, regOp, arg, 1);
1574void XEmitter::CMPPD(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0x66, sseCMP, regOp, arg, 1); Write8(compare);} 1549 Write8(compare);
1575void XEmitter::ANDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseAND, regOp, arg);} 1550}
1576void XEmitter::ANDPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseAND, regOp, arg);} 1551void XEmitter::CMPSD(X64Reg regOp, const OpArg& arg, u8 compare) {
1577void XEmitter::ANDNPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseANDN, regOp, arg);} 1552 WriteSSEOp(0xF2, sseCMP, regOp, arg, 1);
1578void XEmitter::ANDNPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseANDN, regOp, arg);} 1553 Write8(compare);
1579void XEmitter::ORPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseOR, regOp, arg);} 1554}
1580void XEmitter::ORPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseOR, regOp, arg);} 1555void XEmitter::MULSS(X64Reg regOp, const OpArg& arg) {
1581void XEmitter::XORPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseXOR, regOp, arg);} 1556 WriteSSEOp(0xF3, sseMUL, regOp, arg);
1582void XEmitter::XORPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseXOR, regOp, arg);} 1557}
1583void XEmitter::MULPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMUL, regOp, arg);} 1558void XEmitter::MULSD(X64Reg regOp, const OpArg& arg) {
1584void XEmitter::MULPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMUL, regOp, arg);} 1559 WriteSSEOp(0xF2, sseMUL, regOp, arg);
1585void XEmitter::DIVPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseDIV, regOp, arg);} 1560}
1586void XEmitter::DIVPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseDIV, regOp, arg);} 1561void XEmitter::DIVSS(X64Reg regOp, const OpArg& arg) {
1587void XEmitter::MINPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMIN, regOp, arg);} 1562 WriteSSEOp(0xF3, sseDIV, regOp, arg);
1588void XEmitter::MINPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMIN, regOp, arg);} 1563}
1589void XEmitter::MAXPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMAX, regOp, arg);} 1564void XEmitter::DIVSD(X64Reg regOp, const OpArg& arg) {
1590void XEmitter::MAXPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMAX, regOp, arg);} 1565 WriteSSEOp(0xF2, sseDIV, regOp, arg);
1591void XEmitter::SQRTPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseSQRT, regOp, arg);} 1566}
1592void XEmitter::SQRTPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseSQRT, regOp, arg);} 1567void XEmitter::MINSS(X64Reg regOp, const OpArg& arg) {
1593void XEmitter::RCPPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseRCP, regOp, arg); } 1568 WriteSSEOp(0xF3, sseMIN, regOp, arg);
1594void XEmitter::RSQRTPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseRSQRT, regOp, arg);} 1569}
1595void XEmitter::SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0x00, sseSHUF, regOp, arg,1); Write8(shuffle);} 1570void XEmitter::MINSD(X64Reg regOp, const OpArg& arg) {
1596void 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}
1598void XEmitter::HADDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseHADD, regOp, arg);} 1573void XEmitter::MAXSS(X64Reg regOp, const OpArg& arg) {
1599 1574 WriteSSEOp(0xF3, sseMAX, regOp, arg);
1600void XEmitter::COMISS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseCOMIS, regOp, arg);} //weird that these should be packed 1575}
1601void XEmitter::COMISD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseCOMIS, regOp, arg);} //ordered 1576void XEmitter::MAXSD(X64Reg regOp, const OpArg& arg) {
1602void XEmitter::UCOMISS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseUCOMIS, regOp, arg);} //unordered 1577 WriteSSEOp(0xF2, sseMAX, regOp, arg);
1603void XEmitter::UCOMISD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseUCOMIS, regOp, arg);} 1578}
1604 1579void XEmitter::SQRTSS(X64Reg regOp, const OpArg& arg) {
1605void XEmitter::MOVAPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVAPfromRM, regOp, arg);} 1580 WriteSSEOp(0xF3, sseSQRT, regOp, arg);
1606void XEmitter::MOVAPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVAPfromRM, regOp, arg);} 1581}
1607void XEmitter::MOVAPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVAPtoRM, regOp, arg);} 1582void XEmitter::SQRTSD(X64Reg regOp, const OpArg& arg) {
1608void XEmitter::MOVAPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVAPtoRM, regOp, arg);} 1583 WriteSSEOp(0xF2, sseSQRT, regOp, arg);
1609 1584}
1610void XEmitter::MOVUPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVUPfromRM, regOp, arg);} 1585void XEmitter::RCPSS(X64Reg regOp, const OpArg& arg) {
1611void XEmitter::MOVUPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVUPfromRM, regOp, arg);} 1586 WriteSSEOp(0xF3, sseRCP, regOp, arg);
1612void XEmitter::MOVUPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVUPtoRM, regOp, arg);} 1587}
1613void XEmitter::MOVUPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVUPtoRM, regOp, arg);} 1588void XEmitter::RSQRTSS(X64Reg regOp, const OpArg& arg) {
1614 1589 WriteSSEOp(0xF3, sseRSQRT, regOp, arg);
1615void XEmitter::MOVDQA(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVDQfromRM, regOp, arg);} 1590}
1616void XEmitter::MOVDQA(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVDQtoRM, regOp, arg);} 1591
1617void XEmitter::MOVDQU(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMOVDQfromRM, regOp, arg);} 1592void XEmitter::ADDPS(X64Reg regOp, const OpArg& arg) {
1618void XEmitter::MOVDQU(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF3, sseMOVDQtoRM, regOp, arg);} 1593 WriteSSEOp(0x00, sseADD, regOp, arg);
1619 1594}
1620void XEmitter::MOVSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMOVUPfromRM, regOp, arg);} 1595void XEmitter::ADDPD(X64Reg regOp, const OpArg& arg) {
1621void XEmitter::MOVSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMOVUPfromRM, regOp, arg);} 1596 WriteSSEOp(0x66, sseADD, regOp, arg);
1622void XEmitter::MOVSS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF3, sseMOVUPtoRM, regOp, arg);} 1597}
1623void XEmitter::MOVSD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF2, sseMOVUPtoRM, regOp, arg);} 1598void XEmitter::SUBPS(X64Reg regOp, const OpArg& arg) {
1624 1599 WriteSSEOp(0x00, sseSUB, regOp, arg);
1625void XEmitter::MOVLPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseMOVLPfromRM, regOp, arg); } 1600}
1626void XEmitter::MOVLPD(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x66, sseMOVLPfromRM, regOp, arg); } 1601void XEmitter::SUBPD(X64Reg regOp, const OpArg& arg) {
1627void XEmitter::MOVLPS(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x00, sseMOVLPtoRM, regOp, arg); } 1602 WriteSSEOp(0x66, sseSUB, regOp, arg);
1628void XEmitter::MOVLPD(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x66, sseMOVLPtoRM, regOp, arg); } 1603}
1629 1604void XEmitter::CMPPS(X64Reg regOp, const OpArg& arg, u8 compare) {
1630void XEmitter::MOVHPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseMOVHPfromRM, regOp, arg); } 1605 WriteSSEOp(0x00, sseCMP, regOp, arg, 1);
1631void XEmitter::MOVHPD(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x66, sseMOVHPfromRM, regOp, arg); } 1606 Write8(compare);
1632void XEmitter::MOVHPS(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x00, sseMOVHPtoRM, regOp, arg); } 1607}
1633void XEmitter::MOVHPD(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x66, sseMOVHPtoRM, regOp, arg); } 1608void XEmitter::CMPPD(X64Reg regOp, const OpArg& arg, u8 compare) {
1634 1609 WriteSSEOp(0x66, sseCMP, regOp, arg, 1);
1635void XEmitter::MOVHLPS(X64Reg regOp1, X64Reg regOp2) {WriteSSEOp(0x00, sseMOVHLPS, regOp1, R(regOp2));} 1610 Write8(compare);
1636void XEmitter::MOVLHPS(X64Reg regOp1, X64Reg regOp2) {WriteSSEOp(0x00, sseMOVLHPS, regOp1, R(regOp2));} 1611}
1637 1612void XEmitter::ANDPS(X64Reg regOp, const OpArg& arg) {
1638void XEmitter::CVTPS2PD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, 0x5A, regOp, arg);} 1613 WriteSSEOp(0x00, sseAND, regOp, arg);
1639void XEmitter::CVTPD2PS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0x5A, regOp, arg);} 1614}
1640 1615void XEmitter::ANDPD(X64Reg regOp, const OpArg& arg) {
1641void XEmitter::CVTSD2SS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x5A, regOp, arg);} 1616 WriteSSEOp(0x66, sseAND, regOp, arg);
1642void XEmitter::CVTSS2SD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x5A, regOp, arg);} 1617}
1643void XEmitter::CVTSD2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2D, regOp, arg);} 1618void XEmitter::ANDNPS(X64Reg regOp, const OpArg& arg) {
1644void XEmitter::CVTSS2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2D, regOp, arg);} 1619 WriteSSEOp(0x00, sseANDN, regOp, arg);
1645void XEmitter::CVTSI2SD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2A, regOp, arg);} 1620}
1646void XEmitter::CVTSI2SS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2A, regOp, arg);} 1621void XEmitter::ANDNPD(X64Reg regOp, const OpArg& arg) {
1647 1622 WriteSSEOp(0x66, sseANDN, regOp, arg);
1648void XEmitter::CVTDQ2PD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0xE6, regOp, arg);} 1623}
1649void XEmitter::CVTDQ2PS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, 0x5B, regOp, arg);} 1624void XEmitter::ORPS(X64Reg regOp, const OpArg& arg) {
1650void XEmitter::CVTPD2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0xE6, regOp, arg);} 1625 WriteSSEOp(0x00, sseOR, regOp, arg);
1651void XEmitter::CVTPS2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0x5B, regOp, arg);} 1626}
1652 1627void XEmitter::ORPD(X64Reg regOp, const OpArg& arg) {
1653void XEmitter::CVTTSD2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2C, regOp, arg);} 1628 WriteSSEOp(0x66, sseOR, regOp, arg);
1654void XEmitter::CVTTSS2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2C, regOp, arg);} 1629}
1655void XEmitter::CVTTPS2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x5B, regOp, arg);} 1630void XEmitter::XORPS(X64Reg regOp, const OpArg& arg) {
1656void XEmitter::CVTTPD2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0xE6, regOp, arg);} 1631 WriteSSEOp(0x00, sseXOR, regOp, arg);
1657 1632}
1658void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) {WriteSSEOp(0x66, sseMASKMOVDQU, dest, R(src));} 1633void XEmitter::XORPD(X64Reg regOp, const OpArg& arg) {
1659 1634 WriteSSEOp(0x66, sseXOR, regOp, arg);
1660void XEmitter::MOVMSKPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x50, dest, arg);} 1635}
1661void XEmitter::MOVMSKPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x50, dest, arg);} 1636void XEmitter::MULPS(X64Reg regOp, const OpArg& arg) {
1662 1637 WriteSSEOp(0x00, sseMUL, regOp, arg);
1663void XEmitter::LDDQU(X64Reg dest, const OpArg& arg) {WriteSSEOp(0xF2, sseLDDQU, dest, arg);} // For integer data only 1638}
1639void XEmitter::MULPD(X64Reg regOp, const OpArg& arg) {
1640 WriteSSEOp(0x66, sseMUL, regOp, arg);
1641}
1642void XEmitter::DIVPS(X64Reg regOp, const OpArg& arg) {
1643 WriteSSEOp(0x00, sseDIV, regOp, arg);
1644}
1645void XEmitter::DIVPD(X64Reg regOp, const OpArg& arg) {
1646 WriteSSEOp(0x66, sseDIV, regOp, arg);
1647}
1648void XEmitter::MINPS(X64Reg regOp, const OpArg& arg) {
1649 WriteSSEOp(0x00, sseMIN, regOp, arg);
1650}
1651void XEmitter::MINPD(X64Reg regOp, const OpArg& arg) {
1652 WriteSSEOp(0x66, sseMIN, regOp, arg);
1653}
1654void XEmitter::MAXPS(X64Reg regOp, const OpArg& arg) {
1655 WriteSSEOp(0x00, sseMAX, regOp, arg);
1656}
1657void XEmitter::MAXPD(X64Reg regOp, const OpArg& arg) {
1658 WriteSSEOp(0x66, sseMAX, regOp, arg);
1659}
1660void XEmitter::SQRTPS(X64Reg regOp, const OpArg& arg) {
1661 WriteSSEOp(0x00, sseSQRT, regOp, arg);
1662}
1663void XEmitter::SQRTPD(X64Reg regOp, const OpArg& arg) {
1664 WriteSSEOp(0x66, sseSQRT, regOp, arg);
1665}
1666void XEmitter::RCPPS(X64Reg regOp, const OpArg& arg) {
1667 WriteSSEOp(0x00, sseRCP, regOp, arg);
1668}
1669void XEmitter::RSQRTPS(X64Reg regOp, const OpArg& arg) {
1670 WriteSSEOp(0x00, sseRSQRT, regOp, arg);
1671}
1672void XEmitter::SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle) {
1673 WriteSSEOp(0x00, sseSHUF, regOp, arg, 1);
1674 Write8(shuffle);
1675}
1676void XEmitter::SHUFPD(X64Reg regOp, const OpArg& arg, u8 shuffle) {
1677 WriteSSEOp(0x66, sseSHUF, regOp, arg, 1);
1678 Write8(shuffle);
1679}
1680
1681void XEmitter::HADDPS(X64Reg regOp, const OpArg& arg) {
1682 WriteSSEOp(0xF2, sseHADD, regOp, arg);
1683}
1684
1685void XEmitter::COMISS(X64Reg regOp, const OpArg& arg) {
1686 WriteSSEOp(0x00, sseCOMIS, regOp, arg);
1687} // weird that these should be packed
1688void XEmitter::COMISD(X64Reg regOp, const OpArg& arg) {
1689 WriteSSEOp(0x66, sseCOMIS, regOp, arg);
1690} // ordered
1691void XEmitter::UCOMISS(X64Reg regOp, const OpArg& arg) {
1692 WriteSSEOp(0x00, sseUCOMIS, regOp, arg);
1693} // unordered
1694void XEmitter::UCOMISD(X64Reg regOp, const OpArg& arg) {
1695 WriteSSEOp(0x66, sseUCOMIS, regOp, arg);
1696}
1697
1698void XEmitter::MOVAPS(X64Reg regOp, const OpArg& arg) {
1699 WriteSSEOp(0x00, sseMOVAPfromRM, regOp, arg);
1700}
1701void XEmitter::MOVAPD(X64Reg regOp, const OpArg& arg) {
1702 WriteSSEOp(0x66, sseMOVAPfromRM, regOp, arg);
1703}
1704void XEmitter::MOVAPS(const OpArg& arg, X64Reg regOp) {
1705 WriteSSEOp(0x00, sseMOVAPtoRM, regOp, arg);
1706}
1707void XEmitter::MOVAPD(const OpArg& arg, X64Reg regOp) {
1708 WriteSSEOp(0x66, sseMOVAPtoRM, regOp, arg);
1709}
1710
1711void XEmitter::MOVUPS(X64Reg regOp, const OpArg& arg) {
1712 WriteSSEOp(0x00, sseMOVUPfromRM, regOp, arg);
1713}
1714void XEmitter::MOVUPD(X64Reg regOp, const OpArg& arg) {
1715 WriteSSEOp(0x66, sseMOVUPfromRM, regOp, arg);
1716}
1717void XEmitter::MOVUPS(const OpArg& arg, X64Reg regOp) {
1718 WriteSSEOp(0x00, sseMOVUPtoRM, regOp, arg);
1719}
1720void XEmitter::MOVUPD(const OpArg& arg, X64Reg regOp) {
1721 WriteSSEOp(0x66, sseMOVUPtoRM, regOp, arg);
1722}
1723
1724void XEmitter::MOVDQA(X64Reg regOp, const OpArg& arg) {
1725 WriteSSEOp(0x66, sseMOVDQfromRM, regOp, arg);
1726}
1727void XEmitter::MOVDQA(const OpArg& arg, X64Reg regOp) {
1728 WriteSSEOp(0x66, sseMOVDQtoRM, regOp, arg);
1729}
1730void XEmitter::MOVDQU(X64Reg regOp, const OpArg& arg) {
1731 WriteSSEOp(0xF3, sseMOVDQfromRM, regOp, arg);
1732}
1733void XEmitter::MOVDQU(const OpArg& arg, X64Reg regOp) {
1734 WriteSSEOp(0xF3, sseMOVDQtoRM, regOp, arg);
1735}
1736
1737void XEmitter::MOVSS(X64Reg regOp, const OpArg& arg) {
1738 WriteSSEOp(0xF3, sseMOVUPfromRM, regOp, arg);
1739}
1740void XEmitter::MOVSD(X64Reg regOp, const OpArg& arg) {
1741 WriteSSEOp(0xF2, sseMOVUPfromRM, regOp, arg);
1742}
1743void XEmitter::MOVSS(const OpArg& arg, X64Reg regOp) {
1744 WriteSSEOp(0xF3, sseMOVUPtoRM, regOp, arg);
1745}
1746void XEmitter::MOVSD(const OpArg& arg, X64Reg regOp) {
1747 WriteSSEOp(0xF2, sseMOVUPtoRM, regOp, arg);
1748}
1749
1750void XEmitter::MOVLPS(X64Reg regOp, const OpArg& arg) {
1751 WriteSSEOp(0x00, sseMOVLPfromRM, regOp, arg);
1752}
1753void XEmitter::MOVLPD(X64Reg regOp, const OpArg& arg) {
1754 WriteSSEOp(0x66, sseMOVLPfromRM, regOp, arg);
1755}
1756void XEmitter::MOVLPS(const OpArg& arg, X64Reg regOp) {
1757 WriteSSEOp(0x00, sseMOVLPtoRM, regOp, arg);
1758}
1759void XEmitter::MOVLPD(const OpArg& arg, X64Reg regOp) {
1760 WriteSSEOp(0x66, sseMOVLPtoRM, regOp, arg);
1761}
1762
1763void XEmitter::MOVHPS(X64Reg regOp, const OpArg& arg) {
1764 WriteSSEOp(0x00, sseMOVHPfromRM, regOp, arg);
1765}
1766void XEmitter::MOVHPD(X64Reg regOp, const OpArg& arg) {
1767 WriteSSEOp(0x66, sseMOVHPfromRM, regOp, arg);
1768}
1769void XEmitter::MOVHPS(const OpArg& arg, X64Reg regOp) {
1770 WriteSSEOp(0x00, sseMOVHPtoRM, regOp, arg);
1771}
1772void XEmitter::MOVHPD(const OpArg& arg, X64Reg regOp) {
1773 WriteSSEOp(0x66, sseMOVHPtoRM, regOp, arg);
1774}
1775
1776void XEmitter::MOVHLPS(X64Reg regOp1, X64Reg regOp2) {
1777 WriteSSEOp(0x00, sseMOVHLPS, regOp1, R(regOp2));
1778}
1779void XEmitter::MOVLHPS(X64Reg regOp1, X64Reg regOp2) {
1780 WriteSSEOp(0x00, sseMOVLHPS, regOp1, R(regOp2));
1781}
1782
1783void XEmitter::CVTPS2PD(X64Reg regOp, const OpArg& arg) {
1784 WriteSSEOp(0x00, 0x5A, regOp, arg);
1785}
1786void XEmitter::CVTPD2PS(X64Reg regOp, const OpArg& arg) {
1787 WriteSSEOp(0x66, 0x5A, regOp, arg);
1788}
1789
1790void XEmitter::CVTSD2SS(X64Reg regOp, const OpArg& arg) {
1791 WriteSSEOp(0xF2, 0x5A, regOp, arg);
1792}
1793void XEmitter::CVTSS2SD(X64Reg regOp, const OpArg& arg) {
1794 WriteSSEOp(0xF3, 0x5A, regOp, arg);
1795}
1796void XEmitter::CVTSD2SI(X64Reg regOp, const OpArg& arg) {
1797 WriteSSEOp(0xF2, 0x2D, regOp, arg);
1798}
1799void XEmitter::CVTSS2SI(X64Reg regOp, const OpArg& arg) {
1800 WriteSSEOp(0xF3, 0x2D, regOp, arg);
1801}
1802void XEmitter::CVTSI2SD(X64Reg regOp, const OpArg& arg) {
1803 WriteSSEOp(0xF2, 0x2A, regOp, arg);
1804}
1805void XEmitter::CVTSI2SS(X64Reg regOp, const OpArg& arg) {
1806 WriteSSEOp(0xF3, 0x2A, regOp, arg);
1807}
1808
1809void XEmitter::CVTDQ2PD(X64Reg regOp, const OpArg& arg) {
1810 WriteSSEOp(0xF3, 0xE6, regOp, arg);
1811}
1812void XEmitter::CVTDQ2PS(X64Reg regOp, const OpArg& arg) {
1813 WriteSSEOp(0x00, 0x5B, regOp, arg);
1814}
1815void XEmitter::CVTPD2DQ(X64Reg regOp, const OpArg& arg) {
1816 WriteSSEOp(0xF2, 0xE6, regOp, arg);
1817}
1818void XEmitter::CVTPS2DQ(X64Reg regOp, const OpArg& arg) {
1819 WriteSSEOp(0x66, 0x5B, regOp, arg);
1820}
1821
1822void XEmitter::CVTTSD2SI(X64Reg regOp, const OpArg& arg) {
1823 WriteSSEOp(0xF2, 0x2C, regOp, arg);
1824}
1825void XEmitter::CVTTSS2SI(X64Reg regOp, const OpArg& arg) {
1826 WriteSSEOp(0xF3, 0x2C, regOp, arg);
1827}
1828void XEmitter::CVTTPS2DQ(X64Reg regOp, const OpArg& arg) {
1829 WriteSSEOp(0xF3, 0x5B, regOp, arg);
1830}
1831void XEmitter::CVTTPD2DQ(X64Reg regOp, const OpArg& arg) {
1832 WriteSSEOp(0x66, 0xE6, regOp, arg);
1833}
1834
1835void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) {
1836 WriteSSEOp(0x66, sseMASKMOVDQU, dest, R(src));
1837}
1838
1839void XEmitter::MOVMSKPS(X64Reg dest, const OpArg& arg) {
1840 WriteSSEOp(0x00, 0x50, dest, arg);
1841}
1842void XEmitter::MOVMSKPD(X64Reg dest, const OpArg& arg) {
1843 WriteSSEOp(0x66, 0x50, dest, arg);
1844}
1845
1846void 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.
1666void XEmitter::UNPCKLPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x14, dest, arg);} 1851void XEmitter::UNPCKLPS(X64Reg dest, const OpArg& arg) {
1667void XEmitter::UNPCKHPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x15, dest, arg);} 1852 WriteSSEOp(0x00, 0x14, dest, arg);
1853}
1854void XEmitter::UNPCKHPS(X64Reg dest, const OpArg& arg) {
1855 WriteSSEOp(0x00, 0x15, dest, arg);
1856}
1668 1857
1669void XEmitter::UNPCKLPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x14, dest, arg);} 1858void XEmitter::UNPCKLPD(X64Reg dest, const OpArg& arg) {
1670void XEmitter::UNPCKHPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x15, dest, arg);} 1859 WriteSSEOp(0x66, 0x14, dest, arg);
1860}
1861void XEmitter::UNPCKHPD(X64Reg dest, const OpArg& arg) {
1862 WriteSSEOp(0x66, 0x15, dest, arg);
1863}
1671 1864
1672void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg) 1865void 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
1690void XEmitter::PACKSSDW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x6B, dest, arg);} 1879void XEmitter::PACKSSDW(X64Reg dest, const OpArg& arg) {
1691void XEmitter::PACKSSWB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x63, dest, arg);} 1880 WriteSSEOp(0x66, 0x6B, dest, arg);
1692void XEmitter::PACKUSWB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x67, dest, arg);} 1881}
1882void XEmitter::PACKSSWB(X64Reg dest, const OpArg& arg) {
1883 WriteSSEOp(0x66, 0x63, dest, arg);
1884}
1885void XEmitter::PACKUSWB(X64Reg dest, const OpArg& arg) {
1886 WriteSSEOp(0x66, 0x67, dest, arg);
1887}
1693 1888
1694void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x60, dest, arg);} 1889void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg& arg) {
1695void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x61, dest, arg);} 1890 WriteSSEOp(0x66, 0x60, dest, arg);
1696void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x62, dest, arg);} 1891}
1697void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x6C, dest, arg);} 1892void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg& arg) {
1893 WriteSSEOp(0x66, 0x61, dest, arg);
1894}
1895void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg& arg) {
1896 WriteSSEOp(0x66, 0x62, dest, arg);
1897}
1898void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg& arg) {
1899 WriteSSEOp(0x66, 0x6C, dest, arg);
1900}
1698 1901
1699void XEmitter::PSRLW(X64Reg reg, int shift) 1902void 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
1705void XEmitter::PSRLD(X64Reg reg, int shift) 1907void 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
1711void XEmitter::PSRLQ(X64Reg reg, int shift) 1912void 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
1717void XEmitter::PSRLQ(X64Reg reg, const OpArg& arg) 1917void 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
1727void XEmitter::PSLLW(X64Reg reg, int shift) 1926void 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
1733void XEmitter::PSLLD(X64Reg reg, int shift) 1931void 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
1739void XEmitter::PSLLQ(X64Reg reg, int shift) 1936void 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
1750void XEmitter::PSRAW(X64Reg reg, int shift) 1946void 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
1756void XEmitter::PSRAD(X64Reg reg, int shift) 1951void 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
1762void XEmitter::WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) 1956void 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
1769void XEmitter::WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) 1962void 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
1776void XEmitter::PSHUFB(X64Reg dest, const OpArg& arg) {WriteSSSE3Op(0x66, 0x3800, dest, arg);} 1968void XEmitter::PSHUFB(X64Reg dest, const OpArg& arg) {
1777void XEmitter::PTEST(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3817, dest, arg);} 1969 WriteSSSE3Op(0x66, 0x3800, dest, arg);
1778void XEmitter::PACKUSDW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x382b, dest, arg);} 1970}
1779void XEmitter::DPPS(X64Reg dest, const OpArg& arg, u8 mask) {WriteSSE41Op(0x66, 0x3A40, dest, arg, 1); Write8(mask);} 1971void XEmitter::PTEST(X64Reg dest, const OpArg& arg) {
1780 1972 WriteSSE41Op(0x66, 0x3817, dest, arg);
1781void XEmitter::PMINSB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3838, dest, arg);} 1973}
1782void XEmitter::PMINSD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3839, dest, arg);} 1974void XEmitter::PACKUSDW(X64Reg dest, const OpArg& arg) {
1783void XEmitter::PMINUW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383a, dest, arg);} 1975 WriteSSE41Op(0x66, 0x382b, dest, arg);
1784void XEmitter::PMINUD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383b, dest, arg);} 1976}
1785void XEmitter::PMAXSB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383c, dest, arg);} 1977void XEmitter::DPPS(X64Reg dest, const OpArg& arg, u8 mask) {
1786void XEmitter::PMAXSD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383d, dest, arg);} 1978 WriteSSE41Op(0x66, 0x3A40, dest, arg, 1);
1787void XEmitter::PMAXUW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383e, dest, arg);} 1979 Write8(mask);
1788void XEmitter::PMAXUD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383f, dest, arg);} 1980}
1789 1981
1790void XEmitter::PMOVSXBW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3820, dest, arg);} 1982void XEmitter::PMINSB(X64Reg dest, const OpArg& arg) {
1791void XEmitter::PMOVSXBD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3821, dest, arg);} 1983 WriteSSE41Op(0x66, 0x3838, dest, arg);
1792void XEmitter::PMOVSXBQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3822, dest, arg);} 1984}
1793void XEmitter::PMOVSXWD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3823, dest, arg);} 1985void XEmitter::PMINSD(X64Reg dest, const OpArg& arg) {
1794void XEmitter::PMOVSXWQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3824, dest, arg);} 1986 WriteSSE41Op(0x66, 0x3839, dest, arg);
1795void XEmitter::PMOVSXDQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3825, dest, arg);} 1987}
1796void XEmitter::PMOVZXBW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3830, dest, arg);} 1988void XEmitter::PMINUW(X64Reg dest, const OpArg& arg) {
1797void XEmitter::PMOVZXBD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3831, dest, arg);} 1989 WriteSSE41Op(0x66, 0x383a, dest, arg);
1798void XEmitter::PMOVZXBQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3832, dest, arg);} 1990}
1799void XEmitter::PMOVZXWD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3833, dest, arg);} 1991void XEmitter::PMINUD(X64Reg dest, const OpArg& arg) {
1800void XEmitter::PMOVZXWQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3834, dest, arg);} 1992 WriteSSE41Op(0x66, 0x383b, dest, arg);
1801void XEmitter::PMOVZXDQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3835, dest, arg);} 1993}
1802 1994void XEmitter::PMAXSB(X64Reg dest, const OpArg& arg) {
1803void XEmitter::PBLENDVB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3810, dest, arg);} 1995 WriteSSE41Op(0x66, 0x383c, dest, arg);
1804void XEmitter::BLENDVPS(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3814, dest, arg);} 1996}
1805void XEmitter::BLENDVPD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3815, dest, arg);} 1997void XEmitter::PMAXSD(X64Reg dest, const OpArg& arg) {
1806void XEmitter::BLENDPS(X64Reg dest, const OpArg& arg, u8 blend) { WriteSSE41Op(0x66, 0x3A0C, dest, arg, 1); Write8(blend); } 1998 WriteSSE41Op(0x66, 0x383d, dest, arg);
1807void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) { WriteSSE41Op(0x66, 0x3A0D, dest, arg, 1); Write8(blend); } 1999}
1808 2000void XEmitter::PMAXUW(X64Reg dest, const OpArg& arg) {
1809void XEmitter::ROUNDSS(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A0A, dest, arg, 1); Write8(mode);} 2001 WriteSSE41Op(0x66, 0x383e, dest, arg);
1810void XEmitter::ROUNDSD(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A0B, dest, arg, 1); Write8(mode);} 2002}
1811void XEmitter::ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A08, dest, arg, 1); Write8(mode);} 2003void XEmitter::PMAXUD(X64Reg dest, const OpArg& arg) {
1812void 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}
1814void XEmitter::PAND(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDB, dest, arg);} 2006
1815void XEmitter::PANDN(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDF, dest, arg);} 2007void XEmitter::PMOVSXBW(X64Reg dest, const OpArg& arg) {
1816void XEmitter::PXOR(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEF, dest, arg);} 2008 WriteSSE41Op(0x66, 0x3820, dest, arg);
1817void XEmitter::POR(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEB, dest, arg);} 2009}
1818 2010void XEmitter::PMOVSXBD(X64Reg dest, const OpArg& arg) {
1819void XEmitter::PADDB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFC, dest, arg);} 2011 WriteSSE41Op(0x66, 0x3821, dest, arg);
1820void XEmitter::PADDW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFD, dest, arg);} 2012}
1821void XEmitter::PADDD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFE, dest, arg);} 2013void XEmitter::PMOVSXBQ(X64Reg dest, const OpArg& arg) {
1822void XEmitter::PADDQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD4, dest, arg);} 2014 WriteSSE41Op(0x66, 0x3822, dest, arg);
1823 2015}
1824void XEmitter::PADDSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEC, dest, arg);} 2016void XEmitter::PMOVSXWD(X64Reg dest, const OpArg& arg) {
1825void XEmitter::PADDSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xED, dest, arg);} 2017 WriteSSE41Op(0x66, 0x3823, dest, arg);
1826void XEmitter::PADDUSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDC, dest, arg);} 2018}
1827void XEmitter::PADDUSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDD, dest, arg);} 2019void XEmitter::PMOVSXWQ(X64Reg dest, const OpArg& arg) {
1828 2020 WriteSSE41Op(0x66, 0x3824, dest, arg);
1829void XEmitter::PSUBB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF8, dest, arg);} 2021}
1830void XEmitter::PSUBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF9, dest, arg);} 2022void XEmitter::PMOVSXDQ(X64Reg dest, const OpArg& arg) {
1831void XEmitter::PSUBD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFA, dest, arg);} 2023 WriteSSE41Op(0x66, 0x3825, dest, arg);
1832void XEmitter::PSUBQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFB, dest, arg);} 2024}
1833 2025void XEmitter::PMOVZXBW(X64Reg dest, const OpArg& arg) {
1834void XEmitter::PSUBSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE8, dest, arg);} 2026 WriteSSE41Op(0x66, 0x3830, dest, arg);
1835void XEmitter::PSUBSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE9, dest, arg);} 2027}
1836void XEmitter::PSUBUSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD8, dest, arg);} 2028void XEmitter::PMOVZXBD(X64Reg dest, const OpArg& arg) {
1837void XEmitter::PSUBUSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD9, dest, arg);} 2029 WriteSSE41Op(0x66, 0x3831, dest, arg);
1838 2030}
1839void XEmitter::PAVGB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE0, dest, arg);} 2031void XEmitter::PMOVZXBQ(X64Reg dest, const OpArg& arg) {
1840void XEmitter::PAVGW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE3, dest, arg);} 2032 WriteSSE41Op(0x66, 0x3832, dest, arg);
1841 2033}
1842void XEmitter::PCMPEQB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x74, dest, arg);} 2034void XEmitter::PMOVZXWD(X64Reg dest, const OpArg& arg) {
1843void XEmitter::PCMPEQW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x75, dest, arg);} 2035 WriteSSE41Op(0x66, 0x3833, dest, arg);
1844void XEmitter::PCMPEQD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x76, dest, arg);} 2036}
1845 2037void XEmitter::PMOVZXWQ(X64Reg dest, const OpArg& arg) {
1846void XEmitter::PCMPGTB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x64, dest, arg);} 2038 WriteSSE41Op(0x66, 0x3834, dest, arg);
1847void XEmitter::PCMPGTW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x65, dest, arg);} 2039}
1848void XEmitter::PCMPGTD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x66, dest, arg);} 2040void XEmitter::PMOVZXDQ(X64Reg dest, const OpArg& arg) {
1849 2041 WriteSSE41Op(0x66, 0x3835, dest, arg);
1850void XEmitter::PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSEOp(0x66, 0xC5, dest, arg, 1); Write8(subreg);} 2042}
1851void XEmitter::PINSRW(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSEOp(0x66, 0xC4, dest, arg, 1); Write8(subreg);} 2043
1852 2044void XEmitter::PBLENDVB(X64Reg dest, const OpArg& arg) {
1853void XEmitter::PMADDWD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF5, dest, arg); } 2045 WriteSSE41Op(0x66, 0x3810, dest, arg);
1854void XEmitter::PSADBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF6, dest, arg);} 2046}
1855 2047void XEmitter::BLENDVPS(X64Reg dest, const OpArg& arg) {
1856void XEmitter::PMAXSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEE, dest, arg); } 2048 WriteSSE41Op(0x66, 0x3814, dest, arg);
1857void XEmitter::PMAXUB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDE, dest, arg); } 2049}
1858void XEmitter::PMINSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEA, dest, arg); } 2050void XEmitter::BLENDVPD(X64Reg dest, const OpArg& arg) {
1859void XEmitter::PMINUB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDA, dest, arg); } 2051 WriteSSE41Op(0x66, 0x3815, dest, arg);
1860 2052}
1861void XEmitter::PMOVMSKB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD7, dest, arg); } 2053void XEmitter::BLENDPS(X64Reg dest, const OpArg& arg, u8 blend) {
1862void XEmitter::PSHUFD(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0x66, 0x70, regOp, arg, 1); Write8(shuffle);} 2054 WriteSSE41Op(0x66, 0x3A0C, dest, arg, 1);
1863void XEmitter::PSHUFLW(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0xF2, 0x70, regOp, arg, 1); Write8(shuffle);} 2055 Write8(blend);
1864void XEmitter::PSHUFHW(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0xF3, 0x70, regOp, arg, 1); Write8(shuffle);} 2056}
2057void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) {
2058 WriteSSE41Op(0x66, 0x3A0D, dest, arg, 1);
2059 Write8(blend);
2060}
2061
2062void XEmitter::ROUNDSS(X64Reg dest, const OpArg& arg, u8 mode) {
2063 WriteSSE41Op(0x66, 0x3A0A, dest, arg, 1);
2064 Write8(mode);
2065}
2066void XEmitter::ROUNDSD(X64Reg dest, const OpArg& arg, u8 mode) {
2067 WriteSSE41Op(0x66, 0x3A0B, dest, arg, 1);
2068 Write8(mode);
2069}
2070void XEmitter::ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode) {
2071 WriteSSE41Op(0x66, 0x3A08, dest, arg, 1);
2072 Write8(mode);
2073}
2074void XEmitter::ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode) {
2075 WriteSSE41Op(0x66, 0x3A09, dest, arg, 1);
2076 Write8(mode);
2077}
2078
2079void XEmitter::PAND(X64Reg dest, const OpArg& arg) {
2080 WriteSSEOp(0x66, 0xDB, dest, arg);
2081}
2082void XEmitter::PANDN(X64Reg dest, const OpArg& arg) {
2083 WriteSSEOp(0x66, 0xDF, dest, arg);
2084}
2085void XEmitter::PXOR(X64Reg dest, const OpArg& arg) {
2086 WriteSSEOp(0x66, 0xEF, dest, arg);
2087}
2088void XEmitter::POR(X64Reg dest, const OpArg& arg) {
2089 WriteSSEOp(0x66, 0xEB, dest, arg);
2090}
2091
2092void XEmitter::PADDB(X64Reg dest, const OpArg& arg) {
2093 WriteSSEOp(0x66, 0xFC, dest, arg);
2094}
2095void XEmitter::PADDW(X64Reg dest, const OpArg& arg) {
2096 WriteSSEOp(0x66, 0xFD, dest, arg);
2097}
2098void XEmitter::PADDD(X64Reg dest, const OpArg& arg) {
2099 WriteSSEOp(0x66, 0xFE, dest, arg);
2100}
2101void XEmitter::PADDQ(X64Reg dest, const OpArg& arg) {
2102 WriteSSEOp(0x66, 0xD4, dest, arg);
2103}
2104
2105void XEmitter::PADDSB(X64Reg dest, const OpArg& arg) {
2106 WriteSSEOp(0x66, 0xEC, dest, arg);
2107}
2108void XEmitter::PADDSW(X64Reg dest, const OpArg& arg) {
2109 WriteSSEOp(0x66, 0xED, dest, arg);
2110}
2111void XEmitter::PADDUSB(X64Reg dest, const OpArg& arg) {
2112 WriteSSEOp(0x66, 0xDC, dest, arg);
2113}
2114void XEmitter::PADDUSW(X64Reg dest, const OpArg& arg) {
2115 WriteSSEOp(0x66, 0xDD, dest, arg);
2116}
2117
2118void XEmitter::PSUBB(X64Reg dest, const OpArg& arg) {
2119 WriteSSEOp(0x66, 0xF8, dest, arg);
2120}
2121void XEmitter::PSUBW(X64Reg dest, const OpArg& arg) {
2122 WriteSSEOp(0x66, 0xF9, dest, arg);
2123}
2124void XEmitter::PSUBD(X64Reg dest, const OpArg& arg) {
2125 WriteSSEOp(0x66, 0xFA, dest, arg);
2126}
2127void XEmitter::PSUBQ(X64Reg dest, const OpArg& arg) {
2128 WriteSSEOp(0x66, 0xFB, dest, arg);
2129}
2130
2131void XEmitter::PSUBSB(X64Reg dest, const OpArg& arg) {
2132 WriteSSEOp(0x66, 0xE8, dest, arg);
2133}
2134void XEmitter::PSUBSW(X64Reg dest, const OpArg& arg) {
2135 WriteSSEOp(0x66, 0xE9, dest, arg);
2136}
2137void XEmitter::PSUBUSB(X64Reg dest, const OpArg& arg) {
2138 WriteSSEOp(0x66, 0xD8, dest, arg);
2139}
2140void XEmitter::PSUBUSW(X64Reg dest, const OpArg& arg) {
2141 WriteSSEOp(0x66, 0xD9, dest, arg);
2142}
2143
2144void XEmitter::PAVGB(X64Reg dest, const OpArg& arg) {
2145 WriteSSEOp(0x66, 0xE0, dest, arg);
2146}
2147void XEmitter::PAVGW(X64Reg dest, const OpArg& arg) {
2148 WriteSSEOp(0x66, 0xE3, dest, arg);
2149}
2150
2151void XEmitter::PCMPEQB(X64Reg dest, const OpArg& arg) {
2152 WriteSSEOp(0x66, 0x74, dest, arg);
2153}
2154void XEmitter::PCMPEQW(X64Reg dest, const OpArg& arg) {
2155 WriteSSEOp(0x66, 0x75, dest, arg);
2156}
2157void XEmitter::PCMPEQD(X64Reg dest, const OpArg& arg) {
2158 WriteSSEOp(0x66, 0x76, dest, arg);
2159}
2160
2161void XEmitter::PCMPGTB(X64Reg dest, const OpArg& arg) {
2162 WriteSSEOp(0x66, 0x64, dest, arg);
2163}
2164void XEmitter::PCMPGTW(X64Reg dest, const OpArg& arg) {
2165 WriteSSEOp(0x66, 0x65, dest, arg);
2166}
2167void XEmitter::PCMPGTD(X64Reg dest, const OpArg& arg) {
2168 WriteSSEOp(0x66, 0x66, dest, arg);
2169}
2170
2171void XEmitter::PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg) {
2172 WriteSSEOp(0x66, 0xC5, dest, arg, 1);
2173 Write8(subreg);
2174}
2175void XEmitter::PINSRW(X64Reg dest, const OpArg& arg, u8 subreg) {
2176 WriteSSEOp(0x66, 0xC4, dest, arg, 1);
2177 Write8(subreg);
2178}
2179
2180void XEmitter::PMADDWD(X64Reg dest, const OpArg& arg) {
2181 WriteSSEOp(0x66, 0xF5, dest, arg);
2182}
2183void XEmitter::PSADBW(X64Reg dest, const OpArg& arg) {
2184 WriteSSEOp(0x66, 0xF6, dest, arg);
2185}
2186
2187void XEmitter::PMAXSW(X64Reg dest, const OpArg& arg) {
2188 WriteSSEOp(0x66, 0xEE, dest, arg);
2189}
2190void XEmitter::PMAXUB(X64Reg dest, const OpArg& arg) {
2191 WriteSSEOp(0x66, 0xDE, dest, arg);
2192}
2193void XEmitter::PMINSW(X64Reg dest, const OpArg& arg) {
2194 WriteSSEOp(0x66, 0xEA, dest, arg);
2195}
2196void XEmitter::PMINUB(X64Reg dest, const OpArg& arg) {
2197 WriteSSEOp(0x66, 0xDA, dest, arg);
2198}
2199
2200void XEmitter::PMOVMSKB(X64Reg dest, const OpArg& arg) {
2201 WriteSSEOp(0x66, 0xD7, dest, arg);
2202}
2203void XEmitter::PSHUFD(X64Reg regOp, const OpArg& arg, u8 shuffle) {
2204 WriteSSEOp(0x66, 0x70, regOp, arg, 1);
2205 Write8(shuffle);
2206}
2207void XEmitter::PSHUFLW(X64Reg regOp, const OpArg& arg, u8 shuffle) {
2208 WriteSSEOp(0xF2, 0x70, regOp, arg, 1);
2209 Write8(shuffle);
2210}
2211void 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
1867void XEmitter::VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseADD, regOp1, regOp2, arg);} 2217void XEmitter::VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1868void XEmitter::VSUBSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseSUB, regOp1, regOp2, arg);} 2218 WriteAVXOp(0xF2, sseADD, regOp1, regOp2, arg);
1869void XEmitter::VMULSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseMUL, regOp1, regOp2, arg);} 2219}
1870void XEmitter::VDIVSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseDIV, regOp1, regOp2, arg);} 2220void XEmitter::VSUBSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1871void XEmitter::VADDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseADD, regOp1, regOp2, arg);} 2221 WriteAVXOp(0xF2, sseSUB, regOp1, regOp2, arg);
1872void XEmitter::VSUBPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseSUB, regOp1, regOp2, arg);} 2222}
1873void XEmitter::VMULPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseMUL, regOp1, regOp2, arg);} 2223void XEmitter::VMULSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1874void XEmitter::VDIVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseDIV, regOp1, regOp2, arg);} 2224 WriteAVXOp(0xF2, sseMUL, regOp1, regOp2, arg);
1875void XEmitter::VSQRTSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseSQRT, regOp1, regOp2, arg);} 2225}
1876void XEmitter::VSHUFPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 shuffle) {WriteAVXOp(0x66, sseSHUF, regOp1, regOp2, arg, 1); Write8(shuffle);} 2226void XEmitter::VDIVSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1877void XEmitter::VUNPCKLPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg){WriteAVXOp(0x66, 0x14, regOp1, regOp2, arg);} 2227 WriteAVXOp(0xF2, sseDIV, regOp1, regOp2, arg);
1878void XEmitter::VUNPCKHPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg){WriteAVXOp(0x66, 0x15, regOp1, regOp2, arg);} 2228}
1879 2229void XEmitter::VADDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1880void XEmitter::VANDPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseAND, regOp1, regOp2, arg); } 2230 WriteAVXOp(0x66, sseADD, regOp1, regOp2, arg);
1881void XEmitter::VANDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseAND, regOp1, regOp2, arg); } 2231}
1882void XEmitter::VANDNPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseANDN, regOp1, regOp2, arg); } 2232void XEmitter::VSUBPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1883void XEmitter::VANDNPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseANDN, regOp1, regOp2, arg); } 2233 WriteAVXOp(0x66, sseSUB, regOp1, regOp2, arg);
1884void XEmitter::VORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseOR, regOp1, regOp2, arg); } 2234}
1885void XEmitter::VORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseOR, regOp1, regOp2, arg); } 2235void XEmitter::VMULPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1886void XEmitter::VXORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseXOR, regOp1, regOp2, arg); } 2236 WriteAVXOp(0x66, sseMUL, regOp1, regOp2, arg);
1887void XEmitter::VXORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseXOR, regOp1, regOp2, arg); } 2237}
1888 2238void XEmitter::VDIVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1889void XEmitter::VPAND(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xDB, regOp1, regOp2, arg); } 2239 WriteAVXOp(0x66, sseDIV, regOp1, regOp2, arg);
1890void XEmitter::VPANDN(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xDF, regOp1, regOp2, arg); } 2240}
1891void XEmitter::VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xEB, regOp1, regOp2, arg); } 2241void XEmitter::VSQRTSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1892void XEmitter::VPXOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xEF, regOp1, regOp2, arg); } 2242 WriteAVXOp(0xF2, sseSQRT, regOp1, regOp2, arg);
1893 2243}
1894void XEmitter::VFMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg); } 2244void XEmitter::VSHUFPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 shuffle) {
1895void XEmitter::VFMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg); } 2245 WriteAVXOp(0x66, sseSHUF, regOp1, regOp2, arg, 1);
1896void XEmitter::VFMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg); } 2246 Write8(shuffle);
1897void XEmitter::VFMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg, 1); } 2247}
1898void XEmitter::VFMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg, 1); } 2248void XEmitter::VUNPCKLPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1899void XEmitter::VFMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg, 1); } 2249 WriteAVXOp(0x66, 0x14, regOp1, regOp2, arg);
1900void XEmitter::VFMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg); } 2250}
1901void XEmitter::VFMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg); } 2251void XEmitter::VUNPCKHPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1902void XEmitter::VFMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg); } 2252 WriteAVXOp(0x66, 0x15, regOp1, regOp2, arg);
1903void XEmitter::VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg, 1); } 2253}
1904void XEmitter::VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg, 1); } 2254
1905void XEmitter::VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg, 1); } 2255void XEmitter::VANDPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1906void XEmitter::VFMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg); } 2256 WriteAVXOp(0x00, sseAND, regOp1, regOp2, arg);
1907void XEmitter::VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg); } 2257}
1908void XEmitter::VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg); } 2258void XEmitter::VANDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1909void XEmitter::VFMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg, 1); } 2259 WriteAVXOp(0x66, sseAND, regOp1, regOp2, arg);
1910void XEmitter::VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg, 1); } 2260}
1911void XEmitter::VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg, 1); } 2261void XEmitter::VANDNPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1912void XEmitter::VFMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg); } 2262 WriteAVXOp(0x00, sseANDN, regOp1, regOp2, arg);
1913void XEmitter::VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg); } 2263}
1914void XEmitter::VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg); } 2264void XEmitter::VANDNPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1915void XEmitter::VFMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg, 1); } 2265 WriteAVXOp(0x66, sseANDN, regOp1, regOp2, arg);
1916void XEmitter::VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg, 1); } 2266}
1917void XEmitter::VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg, 1); } 2267void XEmitter::VORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1918void XEmitter::VFNMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg); } 2268 WriteAVXOp(0x00, sseOR, regOp1, regOp2, arg);
1919void XEmitter::VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg); } 2269}
1920void XEmitter::VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg); } 2270void XEmitter::VORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1921void XEmitter::VFNMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg, 1); } 2271 WriteAVXOp(0x66, sseOR, regOp1, regOp2, arg);
1922void XEmitter::VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg, 1); } 2272}
1923void XEmitter::VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg, 1); } 2273void XEmitter::VXORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1924void XEmitter::VFNMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg); } 2274 WriteAVXOp(0x00, sseXOR, regOp1, regOp2, arg);
1925void XEmitter::VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg); } 2275}
1926void XEmitter::VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg); } 2276void XEmitter::VXORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1927void XEmitter::VFNMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg, 1); } 2277 WriteAVXOp(0x66, sseXOR, regOp1, regOp2, arg);
1928void XEmitter::VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg, 1); } 2278}
1929void XEmitter::VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg, 1); } 2279
1930void XEmitter::VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg); } 2280void XEmitter::VPAND(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1931void XEmitter::VFNMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg); } 2281 WriteAVXOp(0x66, 0xDB, regOp1, regOp2, arg);
1932void XEmitter::VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg); } 2282}
1933void XEmitter::VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg, 1); } 2283void XEmitter::VPANDN(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1934void XEmitter::VFNMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg, 1); } 2284 WriteAVXOp(0x66, 0xDF, regOp1, regOp2, arg);
1935void XEmitter::VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg, 1); } 2285}
1936void XEmitter::VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg); } 2286void XEmitter::VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1937void XEmitter::VFNMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg); } 2287 WriteAVXOp(0x66, 0xEB, regOp1, regOp2, arg);
1938void XEmitter::VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg); } 2288}
1939void XEmitter::VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg, 1); } 2289void XEmitter::VPXOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1940void XEmitter::VFNMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg, 1); } 2290 WriteAVXOp(0x66, 0xEF, regOp1, regOp2, arg);
1941void XEmitter::VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg, 1); } 2291}
1942void XEmitter::VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg); } 2292
1943void XEmitter::VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg); } 2293void XEmitter::VFMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1944void XEmitter::VFMADDSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg); } 2294 WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg);
1945void XEmitter::VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg, 1); } 2295}
1946void XEmitter::VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg, 1); } 2296void XEmitter::VFMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1947void XEmitter::VFMADDSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg, 1); } 2297 WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg);
1948void XEmitter::VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg); } 2298}
1949void XEmitter::VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg); } 2299void XEmitter::VFMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1950void XEmitter::VFMSUBADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg); } 2300 WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg);
1951void XEmitter::VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg, 1); } 2301}
1952void XEmitter::VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg, 1); } 2302void XEmitter::VFMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1953void 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}
1955void XEmitter::SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0xF3, 0x38F7, regOp1, regOp2, arg);} 2305void XEmitter::VFMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1956void 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);
1957void XEmitter::SHRX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0xF2, 0x38F7, regOp1, regOp2, arg);} 2307}
1958void XEmitter::RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate) {WriteBMI2Op(bits, 0xF2, 0x3AF0, regOp, INVALID_REG, arg, 1); Write8(rotate);} 2308void XEmitter::VFMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1959void 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);
1960void XEmitter::PDEP(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI2Op(bits, 0xF2, 0x38F5, regOp1, regOp2, arg);} 2310}
1961void XEmitter::MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI2Op(bits, 0xF2, 0x38F6, regOp2, regOp1, arg);} 2311void XEmitter::VFMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1962void 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);
1963void XEmitter::BLSR(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x1, regOp, arg);} 2313}
1964void XEmitter::BLSMSK(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x2, regOp, arg);} 2314void XEmitter::VFMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
1965void XEmitter::BLSI(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x3, regOp, arg);} 2315 WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg);
1966void XEmitter::BEXTR(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2){WriteBMI1Op(bits, 0x00, 0x38F7, regOp1, regOp2, arg);} 2316}
1967void XEmitter::ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F2, regOp1, regOp2, arg);} 2317void XEmitter::VFMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2318 WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg);
2319}
2320void XEmitter::VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2321 WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg, 1);
2322}
2323void XEmitter::VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2324 WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg, 1);
2325}
2326void XEmitter::VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2327 WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg, 1);
2328}
2329void XEmitter::VFMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2330 WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg);
2331}
2332void XEmitter::VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2333 WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg);
2334}
2335void XEmitter::VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2336 WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg);
2337}
2338void XEmitter::VFMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2339 WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg, 1);
2340}
2341void XEmitter::VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2342 WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg, 1);
2343}
2344void XEmitter::VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2345 WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg, 1);
2346}
2347void XEmitter::VFMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2348 WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg);
2349}
2350void XEmitter::VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2351 WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg);
2352}
2353void XEmitter::VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2354 WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg);
2355}
2356void XEmitter::VFMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2357 WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg, 1);
2358}
2359void XEmitter::VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2360 WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg, 1);
2361}
2362void XEmitter::VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2363 WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg, 1);
2364}
2365void XEmitter::VFNMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2366 WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg);
2367}
2368void XEmitter::VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2369 WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg);
2370}
2371void XEmitter::VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2372 WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg);
2373}
2374void XEmitter::VFNMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2375 WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg, 1);
2376}
2377void XEmitter::VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2378 WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg, 1);
2379}
2380void XEmitter::VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2381 WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg, 1);
2382}
2383void XEmitter::VFNMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2384 WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg);
2385}
2386void XEmitter::VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2387 WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg);
2388}
2389void XEmitter::VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2390 WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg);
2391}
2392void XEmitter::VFNMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2393 WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg, 1);
2394}
2395void XEmitter::VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2396 WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg, 1);
2397}
2398void XEmitter::VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2399 WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg, 1);
2400}
2401void XEmitter::VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2402 WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg);
2403}
2404void XEmitter::VFNMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2405 WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg);
2406}
2407void XEmitter::VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2408 WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg);
2409}
2410void XEmitter::VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2411 WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg, 1);
2412}
2413void XEmitter::VFNMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2414 WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg, 1);
2415}
2416void XEmitter::VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2417 WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg, 1);
2418}
2419void XEmitter::VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2420 WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg);
2421}
2422void XEmitter::VFNMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2423 WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg);
2424}
2425void XEmitter::VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2426 WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg);
2427}
2428void XEmitter::VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2429 WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg, 1);
2430}
2431void XEmitter::VFNMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2432 WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg, 1);
2433}
2434void XEmitter::VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2435 WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg, 1);
2436}
2437void XEmitter::VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2438 WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg);
2439}
2440void XEmitter::VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2441 WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg);
2442}
2443void XEmitter::VFMADDSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2444 WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg);
2445}
2446void XEmitter::VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2447 WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg, 1);
2448}
2449void XEmitter::VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2450 WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg, 1);
2451}
2452void XEmitter::VFMADDSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2453 WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg, 1);
2454}
2455void XEmitter::VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2456 WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg);
2457}
2458void XEmitter::VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2459 WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg);
2460}
2461void XEmitter::VFMSUBADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2462 WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg);
2463}
2464void XEmitter::VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2465 WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg, 1);
2466}
2467void XEmitter::VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2468 WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg, 1);
2469}
2470void XEmitter::VFMSUBADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2471 WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg, 1);
2472}
2473
2474void XEmitter::SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {
2475 WriteBMI2Op(bits, 0xF3, 0x38F7, regOp1, regOp2, arg);
2476}
2477void XEmitter::SHLX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {
2478 WriteBMI2Op(bits, 0x66, 0x38F7, regOp1, regOp2, arg);
2479}
2480void XEmitter::SHRX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {
2481 WriteBMI2Op(bits, 0xF2, 0x38F7, regOp1, regOp2, arg);
2482}
2483void 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}
2487void XEmitter::PEXT(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2488 WriteBMI2Op(bits, 0xF3, 0x38F5, regOp1, regOp2, arg);
2489}
2490void XEmitter::PDEP(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2491 WriteBMI2Op(bits, 0xF2, 0x38F5, regOp1, regOp2, arg);
2492}
2493void XEmitter::MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2494 WriteBMI2Op(bits, 0xF2, 0x38F6, regOp2, regOp1, arg);
2495}
2496void XEmitter::BZHI(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {
2497 WriteBMI2Op(bits, 0x00, 0x38F5, regOp1, regOp2, arg);
2498}
2499void XEmitter::BLSR(int bits, X64Reg regOp, const OpArg& arg) {
2500 WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x1, regOp, arg);
2501}
2502void XEmitter::BLSMSK(int bits, X64Reg regOp, const OpArg& arg) {
2503 WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x2, regOp, arg);
2504}
2505void XEmitter::BLSI(int bits, X64Reg regOp, const OpArg& arg) {
2506 WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x3, regOp, arg);
2507}
2508void XEmitter::BEXTR(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {
2509 WriteBMI1Op(bits, 0x00, 0x38F7, regOp1, regOp2, arg);
2510}
2511void 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
1971void XEmitter::LOCK() { Write8(0xF0); } 2517void XEmitter::LOCK() {
1972void XEmitter::REP() { Write8(0xF3); } 2518 Write8(0xF0);
1973void XEmitter::REPNE() { Write8(0xF2); } 2519}
1974void XEmitter::FSOverride() { Write8(0x64); } 2520void XEmitter::REP() {
1975void XEmitter::GSOverride() { Write8(0x65); } 2521 Write8(0xF3);
2522}
2523void XEmitter::REPNE() {
2524 Write8(0xF2);
2525}
2526void XEmitter::FSOverride() {
2527 Write8(0x64);
2528}
2529void XEmitter::GSOverride() {
2530 Write8(0x65);
2531}
1976 2532
1977void XEmitter::FWAIT() 2533void 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
1983void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg) 2538void 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
2001void XEmitter::FLD(int bits, const OpArg& src) {WriteFloatLoadStore(bits, floatLD, floatLD80, src);} 2562void XEmitter::FLD(int bits, const OpArg& src) {
2002void XEmitter::FST(int bits, const OpArg& dest) {WriteFloatLoadStore(bits, floatST, floatINVALID, dest);} 2563 WriteFloatLoadStore(bits, floatLD, floatLD80, src);
2003void XEmitter::FSTP(int bits, const OpArg& dest) {WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest);} 2564}
2004void XEmitter::FNSTSW_AX() { Write8(0xDF); Write8(0xE0); } 2565void XEmitter::FST(int bits, const OpArg& dest) {
2566 WriteFloatLoadStore(bits, floatST, floatINVALID, dest);
2567}
2568void XEmitter::FSTP(int bits, const OpArg& dest) {
2569 WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest);
2570}
2571void XEmitter::FNSTSW_AX() {
2572 Write8(0xDF);
2573 Write8(0xE0);
2574}
2005 2575
2006void XEmitter::RDTSC() { Write8(0x0F); Write8(0x31); } 2576void XEmitter::RDTSC() {
2577 Write8(0x0F);
2578 Write8(0x31);
2579}
2007 2580
2008void XCodeBlock::PoisonMemory() { 2581void 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
37namespace Gen 37namespace Gen {
38{ 38
39 39enum X64Reg {
40enum 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
66enum CCFlags 125enum 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
86enum 158enum {
87{
88 NUMGPRs = 16, 159 NUMGPRs = 16,
89 NUMXMMs = 16, 160 NUMXMMs = 16,
90}; 161};
91 162
92enum 163enum {
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 {
157class XEmitter; 227class 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
160struct OpArg 230struct 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
241template <typename T> 317template <typename T>
242inline OpArg M(const T *ptr) { return OpArg(reinterpret_cast<u64>(ptr), static_cast<int>(SCALE_RIP)); } 318inline OpArg M(const T* ptr) {
243constexpr OpArg R(X64Reg value) { return OpArg(0, SCALE_NONE, value); } 319 return OpArg(reinterpret_cast<u64>(ptr), static_cast<int>(SCALE_RIP));
244constexpr OpArg MatR(X64Reg value) { return OpArg(0, SCALE_ATREG, value); } 320}
321constexpr OpArg R(X64Reg value) {
322 return OpArg(0, SCALE_NONE, value);
323}
324constexpr OpArg MatR(X64Reg value) {
325 return OpArg(0, SCALE_ATREG, value);
326}
245 327
246constexpr OpArg MDisp(X64Reg value, int offset) 328constexpr 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
251constexpr OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset) 332constexpr 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
256constexpr OpArg MScaled(X64Reg scaled, int scale, int offset) 336constexpr 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
263constexpr OpArg MRegSum(X64Reg base, X64Reg offset) 341constexpr 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
268constexpr OpArg Imm8 (u8 imm) { return OpArg(imm, SCALE_IMM8); } 345constexpr OpArg Imm8(u8 imm) {
269constexpr OpArg Imm16(u16 imm) { return OpArg(imm, SCALE_IMM16); } //rarely used 346 return OpArg(imm, SCALE_IMM8);
270constexpr OpArg Imm32(u32 imm) { return OpArg(imm, SCALE_IMM32); } 347}
271constexpr OpArg Imm64(u64 imm) { return OpArg(imm, SCALE_IMM64); } 348constexpr OpArg Imm16(u16 imm) {
349 return OpArg(imm, SCALE_IMM16);
350} // rarely used
351constexpr OpArg Imm32(u32 imm) {
352 return OpArg(imm, SCALE_IMM32);
353}
354constexpr OpArg Imm64(u64 imm) {
355 return OpArg(imm, SCALE_IMM64);
356}
272constexpr OpArg UImmAuto(u32 imm) { 357constexpr 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
279template <typename T> 364template <typename T>
280OpArg ImmPtr(const T* imm) 365OpArg 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
289inline u32 PtrOffset(const void* ptr, const void* base) 373inline 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
311struct FixupBranch 392struct 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
317enum SSECompare 397enum 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
329class XEmitter 408class XEmitter {
330{ 409 friend struct OpArg; // for Write8 etc
331 friend struct OpArg; // for Write8 etc
332private: 410private:
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
359protected: 442protected:
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
365public: 448public:
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