summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/assert.h27
-rw-r--r--src/common/bit_field.h27
-rw-r--r--src/common/bit_set.h185
-rw-r--r--src/common/break_points.cpp57
-rw-r--r--src/common/break_points.h19
-rw-r--r--src/common/chunk_file.h539
-rw-r--r--src/common/code_block.h40
-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.cpp50
-rw-r--r--src/common/emu_window.h53
-rw-r--r--src/common/file_util.cpp514
-rw-r--r--src/common/file_util.h120
-rw-r--r--src/common/hash.cpp97
-rw-r--r--src/common/key_map.cpp31
-rw-r--r--src/common/key_map.h11
-rw-r--r--src/common/linear_disk_cache.h78
-rw-r--r--src/common/logging/backend.cpp140
-rw-r--r--src/common/logging/backend.h7
-rw-r--r--src/common/logging/filter.cpp8
-rw-r--r--src/common/logging/filter.h5
-rw-r--r--src/common/logging/log.h136
-rw-r--r--src/common/logging/text_formatter.cpp57
-rw-r--r--src/common/logging/text_formatter.h1
-rw-r--r--src/common/math_util.h29
-rw-r--r--src/common/memory_util.cpp89
-rw-r--r--src/common/memory_util.h6
-rw-r--r--src/common/microprofile.h2
-rw-r--r--src/common/misc.cpp9
-rw-r--r--src/common/platform.h4
-rw-r--r--src/common/profiler.cpp6
-rw-r--r--src/common/profiler_reporting.h1
-rw-r--r--src/common/scope_exit.h22
-rw-r--r--src/common/string_util.cpp193
-rw-r--r--src/common/string_util.h57
-rw-r--r--src/common/swap.h332
-rw-r--r--src/common/symbols.cpp66
-rw-r--r--src/common/symbols.h26
-rw-r--r--src/common/synchronized_wrapper.h23
-rw-r--r--src/common/thread.cpp82
-rw-r--r--src/common/thread.h35
-rw-r--r--src/common/thread_queue_list.h23
-rw-r--r--src/common/timer.cpp75
-rw-r--r--src/common/timer.h11
-rw-r--r--src/common/vector_math.h689
-rw-r--r--src/common/x64/abi.cpp127
-rw-r--r--src/common/x64/abi.h15
-rw-r--r--src/common/x64/cpu_detect.cpp94
-rw-r--r--src/common/x64/emitter.cpp2614
-rw-r--r--src/common/x64/emitter.h600
52 files changed, 4132 insertions, 3417 deletions
diff --git a/src/common/assert.h b/src/common/assert.h
index cd9b819a9..04e80c87a 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <cstdlib> 7#include <cstdlib>
8
9#include "common/common_funcs.h" 8#include "common/common_funcs.h"
10#include "common/logging/log.h" 9#include "common/logging/log.h"
11 10
@@ -18,25 +17,29 @@
18// enough for our purposes. 17// enough for our purposes.
19template <typename Fn> 18template <typename Fn>
20#if defined(_MSC_VER) 19#if defined(_MSC_VER)
21 __declspec(noinline, noreturn) 20__declspec(noinline, noreturn)
22#elif defined(__GNUC__) 21#elif defined(__GNUC__)
23 __attribute__((noinline, noreturn, cold)) 22 __attribute__((noinline, noreturn, cold))
24#endif 23#endif
25static void assert_noinline_call(const Fn& fn) { 24 static void assert_noinline_call(const Fn& fn) {
26 fn(); 25 fn();
27 Crash(); 26 Crash();
28 exit(1); // Keeps GCC's mouth shut about this actually returning 27 exit(1); // Keeps GCC's mouth shut about this actually returning
29} 28}
30 29
31#define ASSERT(_a_) \ 30#define ASSERT(_a_) \
32 do if (!(_a_)) { assert_noinline_call([] { \ 31 do \
33 LOG_CRITICAL(Debug, "Assertion Failed!"); \ 32 if (!(_a_)) { \
34 }); } while (0) 33 assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \
34 } \
35 while (0)
35 36
36#define ASSERT_MSG(_a_, ...) \ 37#define ASSERT_MSG(_a_, ...) \
37 do if (!(_a_)) { assert_noinline_call([&] { \ 38 do \
38 LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \ 39 if (!(_a_)) { \
39 }); } while (0) 40 assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
41 } \
42 while (0)
40 43
41#define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!") 44#define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!")
42#define UNREACHABLE_MSG(...) ASSERT_MSG(false, __VA_ARGS__) 45#define UNREACHABLE_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
@@ -50,4 +53,4 @@ static void assert_noinline_call(const Fn& fn) {
50#endif 53#endif
51 54
52#define UNIMPLEMENTED() DEBUG_ASSERT_MSG(false, "Unimplemented code!") 55#define UNIMPLEMENTED() DEBUG_ASSERT_MSG(false, "Unimplemented code!")
53#define UNIMPLEMENTED_MSG(_a_, ...) ASSERT_MSG(false, _a_, __VA_ARGS__) \ No newline at end of file 56#define UNIMPLEMENTED_MSG(_a_, ...) ASSERT_MSG(false, _a_, __VA_ARGS__)
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 4748999ed..030f7caeb 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -1,7 +1,6 @@
1// Licensed under GPLv2 or any later version 1// Licensed under GPLv2 or any later version
2// Refer to the license.txt file included. 2// Refer to the license.txt file included.
3 3
4
5// Copyright 2014 Tony Wasserka 4// Copyright 2014 Tony Wasserka
6// All rights reserved. 5// All rights reserved.
7// 6//
@@ -29,13 +28,11 @@
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 30
32
33#pragma once 31#pragma once
34 32
35#include <cstddef> 33#include <cstddef>
36#include <limits> 34#include <limits>
37#include <type_traits> 35#include <type_traits>
38
39#include "common/common_funcs.h" 36#include "common/common_funcs.h"
40 37
41/* 38/*
@@ -111,9 +108,8 @@
111 * symptoms. 108 * symptoms.
112 */ 109 */
113#pragma pack(1) 110#pragma pack(1)
114template<std::size_t position, std::size_t bits, typename T> 111template <std::size_t position, std::size_t bits, typename T>
115struct BitField 112struct BitField {
116{
117private: 113private:
118 // We hide the copy assigment operator here, because the default copy 114 // We hide the copy assigment operator here, because the default copy
119 // assignment would copy the full storage value, rather than just the bits 115 // assignment would copy the full storage value, rather than just the bits
@@ -141,13 +137,10 @@ public:
141 } 137 }
142 138
143 FORCE_INLINE T Value() const { 139 FORCE_INLINE T Value() const {
144 if (std::numeric_limits<T>::is_signed) 140 if (std::numeric_limits<T>::is_signed) {
145 { 141 std::size_t shift = 8 * sizeof(T) - bits;
146 std::size_t shift = 8 * sizeof(T)-bits;
147 return (T)((storage << (shift - position)) >> shift); 142 return (T)((storage << (shift - position)) >> shift);
148 } 143 } else {
149 else
150 {
151 return (T)((storage & GetMask()) >> position); 144 return (T)((storage & GetMask()) >> position);
152 } 145 }
153 } 146 }
@@ -162,15 +155,14 @@ private:
162 // T is an enumeration. Note that T is wrapped within an enable_if in the 155 // T is an enumeration. Note that T is wrapped within an enable_if in the
163 // former case to workaround compile errors which arise when using 156 // former case to workaround compile errors which arise when using
164 // std::underlying_type<T>::type directly. 157 // std::underlying_type<T>::type directly.
165 typedef typename std::conditional < std::is_enum<T>::value, 158 typedef typename std::conditional<std::is_enum<T>::value, std::underlying_type<T>,
166 std::underlying_type<T>, 159 std::enable_if<true, T>>::type::type StorageType;
167 std::enable_if < true, T >> ::type::type StorageType;
168 160
169 // Unsigned version of StorageType 161 // Unsigned version of StorageType
170 typedef typename std::make_unsigned<StorageType>::type StorageTypeU; 162 typedef typename std::make_unsigned<StorageType>::type StorageTypeU;
171 163
172 FORCE_INLINE StorageType GetMask() const { 164 FORCE_INLINE StorageType GetMask() const {
173 return (((StorageTypeU)~0) >> (8 * sizeof(T)-bits)) << position; 165 return (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position;
174 } 166 }
175 167
176 StorageType storage; 168 StorageType storage;
@@ -186,5 +178,6 @@ private:
186#pragma pack() 178#pragma pack()
187 179
188#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) 180#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
189static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, "BitField must be trivially copyable"); 181static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value,
182 "BitField must be trivially copyable");
190#endif 183#endif
diff --git a/src/common/bit_set.h b/src/common/bit_set.h
index 7f5de8df2..c48b3b769 100644
--- a/src/common/bit_set.h
+++ b/src/common/bit_set.h
@@ -18,49 +18,60 @@ namespace Common {
18 18
19#ifdef _WIN32 19#ifdef _WIN32
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,57 +95,62 @@ static inline int LeastSignificantSetBit(u64 val) { return __builtin_ctzll(val);
84// TODO: use constexpr when MSVC gets out of the Dark Ages 95// TODO: use constexpr when MSVC gets out of the Dark Ages
85 96
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 Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
97 operator bool() const { return (m_bs->m_val & m_mask) != 0; } 107 operator bool() const {
98 bool operator=(bool set) 108 return (m_bs->m_val & m_mask) != 0;
99 { 109 }
110 bool operator=(bool set) {
100 m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0); 111 m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
101 return set; 112 return set;
102 } 113 }
114
103 private: 115 private:
104 BitSet* m_bs; 116 BitSet* m_bs;
105 IntTy m_mask; 117 IntTy m_mask;
106 }; 118 };
107 119
108 // A STL-like iterator is required to be able to use range-based for loops. 120 // A STL-like iterator is required to be able to use range-based for loops.
109 class Iterator 121 class Iterator {
110 {
111 public: 122 public:
112 Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {} 123 Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {}
113 Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) {} 124 Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) {}
114 Iterator& operator=(Iterator other) { new (this) Iterator(other); return *this; } 125 Iterator& operator=(Iterator other) {
115 int operator*() { return m_bit; } 126 new (this) Iterator(other);
116 Iterator& operator++() 127 return *this;
117 { 128 }
118 if (m_val == 0) 129 int operator*() {
119 { 130 return m_bit;
131 }
132 Iterator& operator++() {
133 if (m_val == 0) {
120 m_bit = -1; 134 m_bit = -1;
121 } 135 } else {
122 else
123 {
124 int bit = LeastSignificantSetBit(m_val); 136 int bit = LeastSignificantSetBit(m_val);
125 m_val &= ~(1 << bit); 137 m_val &= ~(1 << bit);
126 m_bit = bit; 138 m_bit = bit;
127 } 139 }
128 return *this; 140 return *this;
129 } 141 }
130 Iterator operator++(int _) 142 Iterator operator++(int _) {
131 {
132 Iterator other(*this); 143 Iterator other(*this);
133 ++*this; 144 ++*this;
134 return other; 145 return other;
135 } 146 }
136 bool operator==(Iterator other) const { return m_bit == other.m_bit; } 147 bool operator==(Iterator other) const {
137 bool operator!=(Iterator other) const { return m_bit != other.m_bit; } 148 return m_bit == other.m_bit;
149 }
150 bool operator!=(Iterator other) const {
151 return m_bit != other.m_bit;
152 }
153
138 private: 154 private:
139 IntTy m_val; 155 IntTy m_val;
140 int m_bit; 156 int m_bit;
@@ -142,42 +158,75 @@ public:
142 158
143 BitSet() : m_val(0) {} 159 BitSet() : m_val(0) {}
144 explicit BitSet(IntTy val) : m_val(val) {} 160 explicit BitSet(IntTy val) : m_val(val) {}
145 BitSet(std::initializer_list<int> init) 161 BitSet(std::initializer_list<int> init) {
146 {
147 m_val = 0; 162 m_val = 0;
148 for (int bit : init) 163 for (int bit : init)
149 m_val |= (IntTy)1 << bit; 164 m_val |= (IntTy)1 << bit;
150 } 165 }
151 166
152 static BitSet AllTrue(size_t count) 167 static BitSet AllTrue(size_t count) {
153 { 168 return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
154 return BitSet(count == sizeof(IntTy)*8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); 169 }
155 } 170
156 171 Ref operator[](size_t bit) {
157 Ref operator[](size_t bit) { return Ref(this, (IntTy)1 << bit); } 172 return Ref(this, (IntTy)1 << bit);
158 const Ref operator[](size_t bit) const { return (*const_cast<BitSet*>(this))[bit]; } 173 }
159 bool operator==(BitSet other) const { return m_val == other.m_val; } 174 const Ref operator[](size_t bit) const {
160 bool operator!=(BitSet other) const { return m_val != other.m_val; } 175 return (*const_cast<BitSet*>(this))[bit];
161 bool operator<(BitSet other) const { return m_val < other.m_val; } 176 }
162 bool operator>(BitSet other) const { return m_val > other.m_val; } 177 bool operator==(BitSet other) const {
163 BitSet operator|(BitSet other) const { return BitSet(m_val | other.m_val); } 178 return m_val == other.m_val;
164 BitSet operator&(BitSet other) const { return BitSet(m_val & other.m_val); } 179 }
165 BitSet operator^(BitSet other) const { return BitSet(m_val ^ other.m_val); } 180 bool operator!=(BitSet other) const {
166 BitSet operator~() const { return BitSet(~m_val); } 181 return m_val != other.m_val;
167 BitSet& operator|=(BitSet other) { return *this = *this | other; } 182 }
168 BitSet& operator&=(BitSet other) { return *this = *this & other; } 183 bool operator<(BitSet other) const {
169 BitSet& operator^=(BitSet other) { return *this = *this ^ other; } 184 return m_val < other.m_val;
185 }
186 bool operator>(BitSet other) const {
187 return m_val > other.m_val;
188 }
189 BitSet operator|(BitSet other) const {
190 return BitSet(m_val | other.m_val);
191 }
192 BitSet operator&(BitSet other) const {
193 return BitSet(m_val & other.m_val);
194 }
195 BitSet operator^(BitSet other) const {
196 return BitSet(m_val ^ other.m_val);
197 }
198 BitSet operator~() const {
199 return BitSet(~m_val);
200 }
201 BitSet& operator|=(BitSet other) {
202 return *this = *this | other;
203 }
204 BitSet& operator&=(BitSet other) {
205 return *this = *this & other;
206 }
207 BitSet& operator^=(BitSet other) {
208 return *this = *this ^ other;
209 }
170 operator u32() = delete; 210 operator u32() = delete;
171 operator bool() { return m_val != 0; } 211 operator bool() {
212 return m_val != 0;
213 }
172 214
173 // Warning: Even though on modern CPUs this is a single fast instruction, 215 // Warning: Even though on modern CPUs this is a single fast instruction,
174 // Dolphin's official builds do not currently assume POPCNT support on x86, 216 // Dolphin's official builds do not currently assume POPCNT support on x86,
175 // so slower explicit bit twiddling is generated. Still should generally 217 // so slower explicit bit twiddling is generated. Still should generally
176 // be faster than a loop. 218 // be faster than a loop.
177 unsigned int Count() const { return CountSetBits(m_val); } 219 unsigned int Count() const {
220 return CountSetBits(m_val);
221 }
178 222
179 Iterator begin() const { Iterator it(m_val, 0); return ++it; } 223 Iterator begin() const {
180 Iterator end() const { return Iterator(m_val, -1); } 224 Iterator it(m_val, 0);
225 return ++it;
226 }
227 Iterator end() const {
228 return Iterator(m_val, -1);
229 }
181 230
182 IntTy m_val; 231 IntTy m_val;
183}; 232};
diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp
index e7d0d3e43..03a19acba 100644
--- a/src/common/break_points.cpp
+++ b/src/common/break_points.cpp
@@ -2,33 +2,29 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <sstream>
5#include "common/break_points.h" 7#include "common/break_points.h"
6#include "common/logging/log.h" 8#include "common/logging/log.h"
7 9
8#include <sstream> 10bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const {
9#include <algorithm>
10
11bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const
12{
13 auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; }; 11 auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; };
14 auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); 12 auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
15 return it != m_BreakPoints.end(); 13 return it != m_BreakPoints.end();
16} 14}
17 15
18bool BreakPoints::IsTempBreakPoint(u32 iAddress) const 16bool BreakPoints::IsTempBreakPoint(u32 iAddress) const {
19{ 17 auto cond = [&iAddress](const TBreakPoint& bp) {
20 auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress && bp.bTemporary; }; 18 return bp.iAddress == iAddress && bp.bTemporary;
21 auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); 19 };
20 auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
22 return it != m_BreakPoints.end(); 21 return it != m_BreakPoints.end();
23} 22}
24 23
25BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const 24BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const {
26{
27 TBreakPointsStr bps; 25 TBreakPointsStr bps;
28 for (auto breakpoint : m_BreakPoints) 26 for (auto breakpoint : m_BreakPoints) {
29 { 27 if (!breakpoint.bTemporary) {
30 if (!breakpoint.bTemporary)
31 {
32 std::stringstream bp; 28 std::stringstream bp;
33 bp << std::hex << breakpoint.iAddress << " " << (breakpoint.bOn ? "n" : ""); 29 bp << std::hex << breakpoint.iAddress << " " << (breakpoint.bOn ? "n" : "");
34 bps.push_back(bp.str()); 30 bps.push_back(bp.str());
@@ -38,10 +34,8 @@ BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const
38 return bps; 34 return bps;
39} 35}
40 36
41void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) 37void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) {
42{ 38 for (auto bps_item : bps) {
43 for (auto bps_item : bps)
44 {
45 TBreakPoint bp; 39 TBreakPoint bp;
46 std::stringstream bpstr; 40 std::stringstream bpstr;
47 bpstr << std::hex << bps_item; 41 bpstr << std::hex << bps_item;
@@ -52,18 +46,15 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bps)
52 } 46 }
53} 47}
54 48
55void BreakPoints::Add(const TBreakPoint& bp) 49void BreakPoints::Add(const TBreakPoint& bp) {
56{ 50 if (!IsAddressBreakPoint(bp.iAddress)) {
57 if (!IsAddressBreakPoint(bp.iAddress))
58 {
59 m_BreakPoints.push_back(bp); 51 m_BreakPoints.push_back(bp);
60 //if (jit) 52 // if (jit)
61 // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); 53 // jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4);
62 } 54 }
63} 55}
64 56
65void BreakPoints::Add(u32 em_address, bool temp) 57void BreakPoints::Add(u32 em_address, bool temp) {
66{
67 if (!IsAddressBreakPoint(em_address)) // only add new addresses 58 if (!IsAddressBreakPoint(em_address)) // only add new addresses
68 { 59 {
69 TBreakPoint pt; // breakpoint settings 60 TBreakPoint pt; // breakpoint settings
@@ -73,22 +64,20 @@ void BreakPoints::Add(u32 em_address, bool temp)
73 64
74 m_BreakPoints.push_back(pt); 65 m_BreakPoints.push_back(pt);
75 66
76 //if (jit) 67 // if (jit)
77 // jit->GetBlockCache()->InvalidateICache(em_address, 4); 68 // jit->GetBlockCache()->InvalidateICache(em_address, 4);
78 } 69 }
79} 70}
80 71
81void BreakPoints::Remove(u32 em_address) 72void BreakPoints::Remove(u32 em_address) {
82{
83 auto cond = [&em_address](const TBreakPoint& bp) { return bp.iAddress == em_address; }; 73 auto cond = [&em_address](const TBreakPoint& bp) { return bp.iAddress == em_address; };
84 auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond); 74 auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
85 if (it != m_BreakPoints.end()) 75 if (it != m_BreakPoints.end())
86 m_BreakPoints.erase(it); 76 m_BreakPoints.erase(it);
87} 77}
88 78
89void BreakPoints::Clear() 79void BreakPoints::Clear() {
90{ 80 // if (jit)
91 //if (jit)
92 //{ 81 //{
93 // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(), 82 // std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(),
94 // [](const TBreakPoint& bp) 83 // [](const TBreakPoint& bp)
diff --git a/src/common/break_points.h b/src/common/break_points.h
index b0629df37..e15b9f842 100644
--- a/src/common/break_points.h
+++ b/src/common/break_points.h
@@ -4,28 +4,27 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector>
8#include <string> 7#include <string>
9 8#include <vector>
10#include "common/common_types.h" 9#include "common/common_types.h"
11 10
12class DebugInterface; 11class DebugInterface;
13 12
14struct TBreakPoint 13struct TBreakPoint {
15{ 14 u32 iAddress;
16 u32 iAddress;
17 bool bOn; 15 bool bOn;
18 bool bTemporary; 16 bool bTemporary;
19}; 17};
20 18
21// Code breakpoints. 19// Code breakpoints.
22class BreakPoints 20class BreakPoints {
23{
24public: 21public:
25 typedef std::vector<TBreakPoint> TBreakPoints; 22 typedef std::vector<TBreakPoint> TBreakPoints;
26 typedef std::vector<std::string> TBreakPointsStr; 23 typedef std::vector<std::string> TBreakPointsStr;
27 24
28 const TBreakPoints& GetBreakPoints() { return m_BreakPoints; } 25 const TBreakPoints& GetBreakPoints() {
26 return m_BreakPoints;
27 }
29 28
30 TBreakPointsStr GetStrings() const; 29 TBreakPointsStr GetStrings() const;
31 void AddFromStrings(const TBreakPointsStr& bps); 30 void AddFromStrings(const TBreakPointsStr& bps);
@@ -35,7 +34,7 @@ public:
35 bool IsTempBreakPoint(u32 iAddress) const; 34 bool IsTempBreakPoint(u32 iAddress) const;
36 35
37 // Add BreakPoint 36 // Add BreakPoint
38 void Add(u32 em_address, bool temp=false); 37 void Add(u32 em_address, bool temp = false);
39 void Add(const TBreakPoint& bp); 38 void Add(const TBreakPoint& bp);
40 39
41 // Remove Breakpoint 40 // Remove Breakpoint
@@ -46,5 +45,5 @@ public:
46 45
47private: 46private:
48 TBreakPoints m_BreakPoints; 47 TBreakPoints m_BreakPoints;
49 u32 m_iBreakOnCount; 48 u32 m_iBreakOnCount;
50}; 49};
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h
index 1e1bcff31..5145a3657 100644
--- a/src/common/chunk_file.h
+++ b/src/common/chunk_file.h
@@ -35,87 +35,90 @@
35#include <type_traits> 35#include <type_traits>
36#include <utility> 36#include <utility>
37#include <vector> 37#include <vector>
38
39#include "common/assert.h" 38#include "common/assert.h"
40#include "common/common_types.h" 39#include "common/common_types.h"
41#include "common/logging/log.h" 40#include "common/logging/log.h"
42 41
43template <class T> 42template <class T>
44struct LinkedListItem : public T 43struct LinkedListItem : public T {
45{ 44 LinkedListItem<T>* next;
46 LinkedListItem<T> *next;
47}; 45};
48 46
49class PointerWrap; 47class PointerWrap;
50 48
51class PointerWrapSection 49class PointerWrapSection {
52{
53public: 50public:
54 PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { 51 PointerWrapSection(PointerWrap& p, int ver, const char* title)
55 } 52 : p_(p), ver_(ver), title_(title) {}
56 ~PointerWrapSection(); 53 ~PointerWrapSection();
57 54
58 bool operator == (const int &v) const { return ver_ == v; } 55 bool operator==(const int& v) const {
59 bool operator != (const int &v) const { return ver_ != v; } 56 return ver_ == v;
60 bool operator <= (const int &v) const { return ver_ <= v; } 57 }
61 bool operator >= (const int &v) const { return ver_ >= v; } 58 bool operator!=(const int& v) const {
62 bool operator < (const int &v) const { return ver_ < v; } 59 return ver_ != v;
63 bool operator > (const int &v) const { return ver_ > v; } 60 }
61 bool operator<=(const int& v) const {
62 return ver_ <= v;
63 }
64 bool operator>=(const int& v) const {
65 return ver_ >= v;
66 }
67 bool operator<(const int& v) const {
68 return ver_ < v;
69 }
70 bool operator>(const int& v) const {
71 return ver_ > v;
72 }
64 73
65 operator bool() const { 74 operator bool() const {
66 return ver_ > 0; 75 return ver_ > 0;
67 } 76 }
68 77
69private: 78private:
70 PointerWrap &p_; 79 PointerWrap& p_;
71 int ver_; 80 int ver_;
72 const char *title_; 81 const char* title_;
73}; 82};
74 83
75// Wrapper class 84// Wrapper class
76class PointerWrap 85class PointerWrap {
77{ 86// This makes it a compile error if you forget to define DoState() on non-POD.
78 // This makes it a compile error if you forget to define DoState() on non-POD. 87// Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason...
79 // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason...
80#ifdef _MSC_VER 88#ifdef _MSC_VER
81 template<typename T, bool isPOD = std::is_pod<T>::value, bool isPointer = std::is_pointer<T>::value> 89 template <typename T, bool isPOD = std::is_pod<T>::value,
90 bool isPointer = std::is_pointer<T>::value>
82#else 91#else
83 template<typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value> 92 template <typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value>
84#endif 93#endif
85 struct DoHelper 94 struct DoHelper {
86 { 95 static void DoArray(PointerWrap* p, T* x, int count) {
87 static void DoArray(PointerWrap *p, T *x, int count)
88 {
89 for (int i = 0; i < count; ++i) 96 for (int i = 0; i < count; ++i)
90 p->Do(x[i]); 97 p->Do(x[i]);
91 } 98 }
92 99
93 static void Do(PointerWrap *p, T &x) 100 static void Do(PointerWrap* p, T& x) {
94 {
95 p->DoClass(x); 101 p->DoClass(x);
96 } 102 }
97 }; 103 };
98 104
99 template<typename T> 105 template <typename T>
100 struct DoHelper<T, true, false> 106 struct DoHelper<T, true, false> {
101 { 107 static void DoArray(PointerWrap* p, T* x, int count) {
102 static void DoArray(PointerWrap *p, T *x, int count) 108 p->DoVoid((void*)x, sizeof(T) * count);
103 {
104 p->DoVoid((void *)x, sizeof(T) * count);
105 } 109 }
106 110
107 static void Do(PointerWrap *p, T &x) 111 static void Do(PointerWrap* p, T& x) {
108 { 112 p->DoVoid((void*)&x, sizeof(x));
109 p->DoVoid((void *)&x, sizeof(x));
110 } 113 }
111 }; 114 };
112 115
113public: 116public:
114 enum Mode { 117 enum Mode {
115 MODE_READ = 1, // load 118 MODE_READ = 1, // load
116 MODE_WRITE, // save 119 MODE_WRITE, // save
117 MODE_MEASURE, // calculate size 120 MODE_MEASURE, // calculate size
118 MODE_VERIFY, // compare 121 MODE_VERIFY, // compare
119 }; 122 };
120 123
121 enum Error { 124 enum Error {
@@ -124,247 +127,237 @@ public:
124 ERROR_FAILURE = 2, 127 ERROR_FAILURE = 2,
125 }; 128 };
126 129
127 u8 **ptr; 130 u8** ptr;
128 Mode mode; 131 Mode mode;
129 Error error; 132 Error error;
130 133
131public: 134public:
132 PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} 135 PointerWrap(u8** ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {}
133 PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} 136 PointerWrap(unsigned char** ptr_, int mode_)
137 : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {}
134 138
135 PointerWrapSection Section(const char *title, int ver) { 139 PointerWrapSection Section(const char* title, int ver) {
136 return Section(title, ver, ver); 140 return Section(title, ver, ver);
137 } 141 }
138 142
139 // The returned object can be compared against the version that was loaded. 143 // The returned object can be compared against the version that was loaded.
140 // This can be used to support versions as old as minVer. 144 // This can be used to support versions as old as minVer.
141 // Version = 0 means the section was not found. 145 // Version = 0 means the section was not found.
142 PointerWrapSection Section(const char *title, int minVer, int ver) { 146 PointerWrapSection Section(const char* title, int minVer, int ver) {
143 char marker[16] = {0}; 147 char marker[16] = {0};
144 int foundVersion = ver; 148 int foundVersion = ver;
145 149
146 strncpy(marker, title, sizeof(marker)); 150 strncpy(marker, title, sizeof(marker));
147 if (!ExpectVoid(marker, sizeof(marker))) 151 if (!ExpectVoid(marker, sizeof(marker))) {
148 {
149 // Might be before we added name markers for safety. 152 // Might be before we added name markers for safety.
150 if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) 153 if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion)))
151 DoMarker(title); 154 DoMarker(title);
152 // Wasn't found, but maybe we can still load the state. 155 // Wasn't found, but maybe we can still load the state.
153 else 156 else
154 foundVersion = 0; 157 foundVersion = 0;
155 } 158 } else
156 else
157 Do(foundVersion); 159 Do(foundVersion);
158 160
159 if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { 161 if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) {
160 LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion, title); 162 LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion,
163 title);
161 SetError(ERROR_FAILURE); 164 SetError(ERROR_FAILURE);
162 return PointerWrapSection(*this, -1, title); 165 return PointerWrapSection(*this, -1, title);
163 } 166 }
164 return PointerWrapSection(*this, foundVersion, title); 167 return PointerWrapSection(*this, foundVersion, title);
165 } 168 }
166 169
167 void SetMode(Mode mode_) {mode = mode_;} 170 void SetMode(Mode mode_) {
168 Mode GetMode() const {return mode;} 171 mode = mode_;
169 u8 **GetPPtr() {return ptr;} 172 }
170 void SetError(Error error_) 173 Mode GetMode() const {
171 { 174 return mode;
175 }
176 u8** GetPPtr() {
177 return ptr;
178 }
179 void SetError(Error error_) {
172 if (error < error_) 180 if (error < error_)
173 error = error_; 181 error = error_;
174 if (error > ERROR_WARNING) 182 if (error > ERROR_WARNING)
175 mode = PointerWrap::MODE_MEASURE; 183 mode = PointerWrap::MODE_MEASURE;
176 } 184 }
177 185
178 bool ExpectVoid(void *data, int size) 186 bool ExpectVoid(void* data, int size) {
179 {
180 switch (mode) { 187 switch (mode) {
181 case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break; 188 case MODE_READ:
182 case MODE_WRITE: memcpy(*ptr, data, size); break; 189 if (memcmp(data, *ptr, size) != 0)
183 case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything 190 return false;
191 break;
192 case MODE_WRITE:
193 memcpy(*ptr, data, size);
194 break;
195 case MODE_MEASURE:
196 break; // MODE_MEASURE - don't need to do anything
184 case MODE_VERIFY: 197 case MODE_VERIFY:
185 for (int i = 0; i < size; i++) { 198 for (int i = 0; i < size; i++) {
186 DEBUG_ASSERT_MSG(((u8*)data)[i] == (*ptr)[i], 199 DEBUG_ASSERT_MSG(
200 ((u8*)data)[i] == (*ptr)[i],
187 "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", 201 "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
188 ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], 202 ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i],
189 (*ptr)[i], (*ptr)[i], &(*ptr)[i]); 203 &(*ptr)[i]);
190 } 204 }
191 break; 205 break;
192 default: break; // throw an error? 206 default:
207 break; // throw an error?
193 } 208 }
194 (*ptr) += size; 209 (*ptr) += size;
195 return true; 210 return true;
196 } 211 }
197 212
198 void DoVoid(void *data, int size) 213 void DoVoid(void* data, int size) {
199 {
200 switch (mode) { 214 switch (mode) {
201 case MODE_READ: memcpy(data, *ptr, size); break; 215 case MODE_READ:
202 case MODE_WRITE: memcpy(*ptr, data, size); break; 216 memcpy(data, *ptr, size);
203 case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything 217 break;
218 case MODE_WRITE:
219 memcpy(*ptr, data, size);
220 break;
221 case MODE_MEASURE:
222 break; // MODE_MEASURE - don't need to do anything
204 case MODE_VERIFY: 223 case MODE_VERIFY:
205 for (int i = 0; i < size; i++) { 224 for (int i = 0; i < size; i++) {
206 DEBUG_ASSERT_MSG(((u8*)data)[i] == (*ptr)[i], 225 DEBUG_ASSERT_MSG(
226 ((u8*)data)[i] == (*ptr)[i],
207 "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", 227 "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
208 ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], 228 ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i],
209 (*ptr)[i], (*ptr)[i], &(*ptr)[i]); 229 &(*ptr)[i]);
210 } 230 }
211 break; 231 break;
212 default: break; // throw an error? 232 default:
233 break; // throw an error?
213 } 234 }
214 (*ptr) += size; 235 (*ptr) += size;
215 } 236 }
216 237
217 template<class K, class T> 238 template <class K, class T>
218 void Do(std::map<K, T *> &x) 239 void Do(std::map<K, T*>& x) {
219 { 240 if (mode == MODE_READ) {
220 if (mode == MODE_READ) 241 for (auto it = x.begin(), end = x.end(); it != end; ++it) {
221 {
222 for (auto it = x.begin(), end = x.end(); it != end; ++it)
223 {
224 if (it->second != nullptr) 242 if (it->second != nullptr)
225 delete it->second; 243 delete it->second;
226 } 244 }
227 } 245 }
228 T *dv = nullptr; 246 T* dv = nullptr;
229 DoMap(x, dv); 247 DoMap(x, dv);
230 } 248 }
231 249
232 template<class K, class T> 250 template <class K, class T>
233 void Do(std::map<K, T> &x) 251 void Do(std::map<K, T>& x) {
234 {
235 T dv = T(); 252 T dv = T();
236 DoMap(x, dv); 253 DoMap(x, dv);
237 } 254 }
238 255
239 template<class K, class T> 256 template <class K, class T>
240 void DoMap(std::map<K, T> &x, T &default_val) 257 void DoMap(std::map<K, T>& x, T& default_val) {
241 {
242 unsigned int number = (unsigned int)x.size(); 258 unsigned int number = (unsigned int)x.size();
243 Do(number); 259 Do(number);
244 switch (mode) { 260 switch (mode) {
245 case MODE_READ: 261 case MODE_READ: {
246 { 262 x.clear();
247 x.clear(); 263 while (number > 0) {
248 while (number > 0) 264 K first = K();
249 { 265 Do(first);
250 K first = K(); 266 T second = default_val;
251 Do(first); 267 Do(second);
252 T second = default_val; 268 x[first] = second;
253 Do(second); 269 --number;
254 x[first] = second;
255 --number;
256 }
257 } 270 }
258 break; 271 } break;
259 case MODE_WRITE: 272 case MODE_WRITE:
260 case MODE_MEASURE: 273 case MODE_MEASURE:
261 case MODE_VERIFY: 274 case MODE_VERIFY: {
262 { 275 typename std::map<K, T>::iterator itr = x.begin();
263 typename std::map<K, T>::iterator itr = x.begin(); 276 while (number > 0) {
264 while (number > 0) 277 K first = itr->first;
265 { 278 Do(first);
266 K first = itr->first; 279 Do(itr->second);
267 Do(first); 280 --number;
268 Do(itr->second); 281 ++itr;
269 --number;
270 ++itr;
271 }
272 } 282 }
273 break; 283 } break;
274 } 284 }
275 } 285 }
276 286
277 template<class K, class T> 287 template <class K, class T>
278 void Do(std::multimap<K, T *> &x) 288 void Do(std::multimap<K, T*>& x) {
279 { 289 if (mode == MODE_READ) {
280 if (mode == MODE_READ) 290 for (auto it = x.begin(), end = x.end(); it != end; ++it) {
281 {
282 for (auto it = x.begin(), end = x.end(); it != end; ++it)
283 {
284 if (it->second != nullptr) 291 if (it->second != nullptr)
285 delete it->second; 292 delete it->second;
286 } 293 }
287 } 294 }
288 T *dv = nullptr; 295 T* dv = nullptr;
289 DoMultimap(x, dv); 296 DoMultimap(x, dv);
290 } 297 }
291 298
292 template<class K, class T> 299 template <class K, class T>
293 void Do(std::multimap<K, T> &x) 300 void Do(std::multimap<K, T>& x) {
294 {
295 T dv = T(); 301 T dv = T();
296 DoMultimap(x, dv); 302 DoMultimap(x, dv);
297 } 303 }
298 304
299 template<class K, class T> 305 template <class K, class T>
300 void DoMultimap(std::multimap<K, T> &x, T &default_val) 306 void DoMultimap(std::multimap<K, T>& x, T& default_val) {
301 {
302 unsigned int number = (unsigned int)x.size(); 307 unsigned int number = (unsigned int)x.size();
303 Do(number); 308 Do(number);
304 switch (mode) { 309 switch (mode) {
305 case MODE_READ: 310 case MODE_READ: {
306 { 311 x.clear();
307 x.clear(); 312 while (number > 0) {
308 while (number > 0) 313 K first = K();
309 { 314 Do(first);
310 K first = K(); 315 T second = default_val;
311 Do(first); 316 Do(second);
312 T second = default_val; 317 x.insert(std::make_pair(first, second));
313 Do(second); 318 --number;
314 x.insert(std::make_pair(first, second));
315 --number;
316 }
317 } 319 }
318 break; 320 } break;
319 case MODE_WRITE: 321 case MODE_WRITE:
320 case MODE_MEASURE: 322 case MODE_MEASURE:
321 case MODE_VERIFY: 323 case MODE_VERIFY: {
322 { 324 typename std::multimap<K, T>::iterator itr = x.begin();
323 typename std::multimap<K, T>::iterator itr = x.begin(); 325 while (number > 0) {
324 while (number > 0) 326 Do(itr->first);
325 { 327 Do(itr->second);
326 Do(itr->first); 328 --number;
327 Do(itr->second); 329 ++itr;
328 --number;
329 ++itr;
330 }
331 } 330 }
332 break; 331 } break;
333 } 332 }
334 } 333 }
335 334
336 // Store vectors. 335 // Store vectors.
337 template<class T> 336 template <class T>
338 void Do(std::vector<T *> &x) 337 void Do(std::vector<T*>& x) {
339 { 338 T* dv = nullptr;
340 T *dv = nullptr;
341 DoVector(x, dv); 339 DoVector(x, dv);
342 } 340 }
343 341
344 template<class T> 342 template <class T>
345 void Do(std::vector<T> &x) 343 void Do(std::vector<T>& x) {
346 {
347 T dv = T(); 344 T dv = T();
348 DoVector(x, dv); 345 DoVector(x, dv);
349 } 346 }
350 347
351 348 template <class T>
352 template<class T> 349 void DoPOD(std::vector<T>& x) {
353 void DoPOD(std::vector<T> &x)
354 {
355 T dv = T(); 350 T dv = T();
356 DoVectorPOD(x, dv); 351 DoVectorPOD(x, dv);
357 } 352 }
358 353
359 template<class T> 354 template <class T>
360 void Do(std::vector<T> &x, T &default_val) 355 void Do(std::vector<T>& x, T& default_val) {
361 {
362 DoVector(x, default_val); 356 DoVector(x, default_val);
363 } 357 }
364 358
365 template<class T> 359 template <class T>
366 void DoVector(std::vector<T> &x, T &default_val) 360 void DoVector(std::vector<T>& x, T& default_val) {
367 {
368 u32 vec_size = (u32)x.size(); 361 u32 vec_size = (u32)x.size();
369 Do(vec_size); 362 Do(vec_size);
370 x.resize(vec_size, default_val); 363 x.resize(vec_size, default_val);
@@ -372,9 +365,8 @@ public:
372 DoArray(&x[0], vec_size); 365 DoArray(&x[0], vec_size);
373 } 366 }
374 367
375 template<class T> 368 template <class T>
376 void DoVectorPOD(std::vector<T> &x, T &default_val) 369 void DoVectorPOD(std::vector<T>& x, T& default_val) {
377 {
378 u32 vec_size = (u32)x.size(); 370 u32 vec_size = (u32)x.size();
379 Do(vec_size); 371 Do(vec_size);
380 x.resize(vec_size, default_val); 372 x.resize(vec_size, default_val);
@@ -383,55 +375,48 @@ public:
383 } 375 }
384 376
385 // Store deques. 377 // Store deques.
386 template<class T> 378 template <class T>
387 void Do(std::deque<T *> &x) 379 void Do(std::deque<T*>& x) {
388 { 380 T* dv = nullptr;
389 T *dv = nullptr;
390 DoDeque(x, dv); 381 DoDeque(x, dv);
391 } 382 }
392 383
393 template<class T> 384 template <class T>
394 void Do(std::deque<T> &x) 385 void Do(std::deque<T>& x) {
395 {
396 T dv = T(); 386 T dv = T();
397 DoDeque(x, dv); 387 DoDeque(x, dv);
398 } 388 }
399 389
400 template<class T> 390 template <class T>
401 void DoDeque(std::deque<T> &x, T &default_val) 391 void DoDeque(std::deque<T>& x, T& default_val) {
402 {
403 u32 deq_size = (u32)x.size(); 392 u32 deq_size = (u32)x.size();
404 Do(deq_size); 393 Do(deq_size);
405 x.resize(deq_size, default_val); 394 x.resize(deq_size, default_val);
406 u32 i; 395 u32 i;
407 for(i = 0; i < deq_size; i++) 396 for (i = 0; i < deq_size; i++)
408 Do(x[i]); 397 Do(x[i]);
409 } 398 }
410 399
411 // Store STL lists. 400 // Store STL lists.
412 template<class T> 401 template <class T>
413 void Do(std::list<T *> &x) 402 void Do(std::list<T*>& x) {
414 { 403 T* dv = nullptr;
415 T *dv = nullptr;
416 Do(x, dv); 404 Do(x, dv);
417 } 405 }
418 406
419 template<class T> 407 template <class T>
420 void Do(std::list<T> &x) 408 void Do(std::list<T>& x) {
421 {
422 T dv = T(); 409 T dv = T();
423 DoList(x, dv); 410 DoList(x, dv);
424 } 411 }
425 412
426 template<class T> 413 template <class T>
427 void Do(std::list<T> &x, T &default_val) 414 void Do(std::list<T>& x, T& default_val) {
428 {
429 DoList(x, default_val); 415 DoList(x, default_val);
430 } 416 }
431 417
432 template<class T> 418 template <class T>
433 void DoList(std::list<T> &x, T &default_val) 419 void DoList(std::list<T>& x, T& default_val) {
434 {
435 u32 list_size = (u32)x.size(); 420 u32 list_size = (u32)x.size();
436 Do(list_size); 421 Do(list_size);
437 x.resize(list_size, default_val); 422 x.resize(list_size, default_val);
@@ -441,15 +426,11 @@ public:
441 Do(*itr); 426 Do(*itr);
442 } 427 }
443 428
444
445 // Store STL sets. 429 // Store STL sets.
446 template <class T> 430 template <class T>
447 void Do(std::set<T *> &x) 431 void Do(std::set<T*>& x) {
448 { 432 if (mode == MODE_READ) {
449 if (mode == MODE_READ) 433 for (auto it = x.begin(), end = x.end(); it != end; ++it) {
450 {
451 for (auto it = x.begin(), end = x.end(); it != end; ++it)
452 {
453 if (*it != nullptr) 434 if (*it != nullptr)
454 delete *it; 435 delete *it;
455 } 436 }
@@ -458,39 +439,31 @@ public:
458 } 439 }
459 440
460 template <class T> 441 template <class T>
461 void Do(std::set<T> &x) 442 void Do(std::set<T>& x) {
462 {
463 DoSet(x); 443 DoSet(x);
464 } 444 }
465 445
466 template <class T> 446 template <class T>
467 void DoSet(std::set<T> &x) 447 void DoSet(std::set<T>& x) {
468 {
469 unsigned int number = (unsigned int)x.size(); 448 unsigned int number = (unsigned int)x.size();
470 Do(number); 449 Do(number);
471 450
472 switch (mode) 451 switch (mode) {
473 { 452 case MODE_READ: {
474 case MODE_READ: 453 x.clear();
475 { 454 while (number-- > 0) {
476 x.clear(); 455 T it = T();
477 while (number-- > 0) 456 Do(it);
478 { 457 x.insert(it);
479 T it = T();
480 Do(it);
481 x.insert(it);
482 }
483 } 458 }
484 break; 459 } break;
485 case MODE_WRITE: 460 case MODE_WRITE:
486 case MODE_MEASURE: 461 case MODE_MEASURE:
487 case MODE_VERIFY: 462 case MODE_VERIFY: {
488 { 463 typename std::set<T>::iterator itr = x.begin();
489 typename std::set<T>::iterator itr = x.begin(); 464 while (number-- > 0)
490 while (number-- > 0) 465 Do(*itr++);
491 Do(*itr++); 466 } break;
492 }
493 break;
494 467
495 default: 468 default:
496 LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode); 469 LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode);
@@ -498,51 +471,58 @@ public:
498 } 471 }
499 472
500 // Store strings. 473 // Store strings.
501 void Do(std::string &x) 474 void Do(std::string& x) {
502 {
503 int stringLen = (int)x.length() + 1; 475 int stringLen = (int)x.length() + 1;
504 Do(stringLen); 476 Do(stringLen);
505 477
506 switch (mode) { 478 switch (mode) {
507 case MODE_READ: x = (char*)*ptr; break; 479 case MODE_READ:
508 case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; 480 x = (char*)*ptr;
509 case MODE_MEASURE: break; 481 break;
482 case MODE_WRITE:
483 memcpy(*ptr, x.c_str(), stringLen);
484 break;
485 case MODE_MEASURE:
486 break;
510 case MODE_VERIFY: 487 case MODE_VERIFY:
511 DEBUG_ASSERT_MSG((x == (char*)*ptr), 488 DEBUG_ASSERT_MSG((x == (char*)*ptr),
512 "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", 489 "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n",
513 x.c_str(), (char*)*ptr, ptr); 490 x.c_str(), (char*)*ptr, ptr);
514 break; 491 break;
515 } 492 }
516 (*ptr) += stringLen; 493 (*ptr) += stringLen;
517 } 494 }
518 495
519 void Do(std::wstring &x) 496 void Do(std::wstring& x) {
520 { 497 int stringLen = sizeof(wchar_t) * ((int)x.length() + 1);
521 int stringLen = sizeof(wchar_t)*((int)x.length() + 1);
522 Do(stringLen); 498 Do(stringLen);
523 499
524 switch (mode) { 500 switch (mode) {
525 case MODE_READ: x = (wchar_t*)*ptr; break; 501 case MODE_READ:
526 case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; 502 x = (wchar_t*)*ptr;
527 case MODE_MEASURE: break; 503 break;
504 case MODE_WRITE:
505 memcpy(*ptr, x.c_str(), stringLen);
506 break;
507 case MODE_MEASURE:
508 break;
528 case MODE_VERIFY: 509 case MODE_VERIFY:
529 DEBUG_ASSERT_MSG((x == (wchar_t*)*ptr), 510 DEBUG_ASSERT_MSG((x == (wchar_t*)*ptr),
530 "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", 511 "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n",
531 x.c_str(), (wchar_t*)*ptr, ptr); 512 x.c_str(), (wchar_t*)*ptr, ptr);
532 break; 513 break;
533 } 514 }
534 (*ptr) += stringLen; 515 (*ptr) += stringLen;
535 } 516 }
536 517
537 template<class T> 518 template <class T>
538 void DoClass(T &x) { 519 void DoClass(T& x) {
539 x.DoState(*this); 520 x.DoState(*this);
540 } 521 }
541 522
542 template<class T> 523 template <class T>
543 void DoClass(T *&x) { 524 void DoClass(T*& x) {
544 if (mode == MODE_READ) 525 if (mode == MODE_READ) {
545 {
546 if (x != nullptr) 526 if (x != nullptr)
547 delete x; 527 delete x;
548 x = new T(); 528 x = new T();
@@ -550,81 +530,70 @@ public:
550 x->DoState(*this); 530 x->DoState(*this);
551 } 531 }
552 532
553 template<class T> 533 template <class T>
554 void DoArray(T *x, int count) { 534 void DoArray(T* x, int count) {
555 DoHelper<T>::DoArray(this, x, count); 535 DoHelper<T>::DoArray(this, x, count);
556 } 536 }
557 537
558 template<class T> 538 template <class T>
559 void Do(T &x) { 539 void Do(T& x) {
560 DoHelper<T>::Do(this, x); 540 DoHelper<T>::Do(this, x);
561 } 541 }
562 542
563 template<class T> 543 template <class T>
564 void DoPOD(T &x) { 544 void DoPOD(T& x) {
565 DoHelper<T>::Do(this, x); 545 DoHelper<T>::Do(this, x);
566 } 546 }
567 547
568 template<class T> 548 template <class T>
569 void DoPointer(T* &x, T*const base) { 549 void DoPointer(T*& x, T* const base) {
570 // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range 550 // pointers can be more than 2^31 apart, but you're using this function wrong if you need
551 // that much range
571 s32 offset = x - base; 552 s32 offset = x - base;
572 Do(offset); 553 Do(offset);
573 if (mode == MODE_READ) 554 if (mode == MODE_READ)
574 x = base + offset; 555 x = base + offset;
575 } 556 }
576 557
577 template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)> 558 template <class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*),
578 void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr) 559 void (*TDo)(PointerWrap&, T*)>
579 { 560 void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr) {
580 LinkedListItem<T>* list_cur = list_start; 561 LinkedListItem<T>* list_cur = list_start;
581 LinkedListItem<T>* prev = nullptr; 562 LinkedListItem<T>* prev = nullptr;
582 563
583 while (true) 564 while (true) {
584 {
585 u8 shouldExist = (list_cur ? 1 : 0); 565 u8 shouldExist = (list_cur ? 1 : 0);
586 Do(shouldExist); 566 Do(shouldExist);
587 if (shouldExist == 1) 567 if (shouldExist == 1) {
588 {
589 LinkedListItem<T>* cur = list_cur ? list_cur : TNew(); 568 LinkedListItem<T>* cur = list_cur ? list_cur : TNew();
590 TDo(*this, (T*)cur); 569 TDo(*this, (T*)cur);
591 if (!list_cur) 570 if (!list_cur) {
592 { 571 if (mode == MODE_READ) {
593 if (mode == MODE_READ)
594 {
595 cur->next = nullptr; 572 cur->next = nullptr;
596 list_cur = cur; 573 list_cur = cur;
597 if (prev) 574 if (prev)
598 prev->next = cur; 575 prev->next = cur;
599 else 576 else
600 list_start = cur; 577 list_start = cur;
601 } 578 } else {
602 else
603 {
604 TFree(cur); 579 TFree(cur);
605 continue; 580 continue;
606 } 581 }
607 } 582 }
608 } 583 } else {
609 else 584 if (mode == MODE_READ) {
610 {
611 if (mode == MODE_READ)
612 {
613 if (prev) 585 if (prev)
614 prev->next = nullptr; 586 prev->next = nullptr;
615 if (list_end) 587 if (list_end)
616 *list_end = prev; 588 *list_end = prev;
617 if (list_cur) 589 if (list_cur) {
618 {
619 if (list_start == list_cur) 590 if (list_start == list_cur)
620 list_start = nullptr; 591 list_start = nullptr;
621 do 592 do {
622 {
623 LinkedListItem<T>* next = list_cur->next; 593 LinkedListItem<T>* next = list_cur->next;
624 TFree(list_cur); 594 TFree(list_cur);
625 list_cur = next; 595 list_cur = next;
626 } 596 } while (list_cur);
627 while (list_cur);
628 } 597 }
629 } 598 }
630 break; 599 break;
@@ -634,13 +603,13 @@ public:
634 } 603 }
635 } 604 }
636 605
637 void DoMarker(const char* prevName, u32 arbitraryNumber=0x42) 606 void DoMarker(const char* prevName, u32 arbitraryNumber = 0x42) {
638 {
639 u32 cookie = arbitraryNumber; 607 u32 cookie = arbitraryNumber;
640 Do(cookie); 608 Do(cookie);
641 if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) 609 if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) {
642 { 610 LOG_ERROR(Common, "After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). "
643 LOG_ERROR(Common, "After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); 611 "Aborting savestate load...",
612 prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
644 SetError(ERROR_FAILURE); 613 SetError(ERROR_FAILURE);
645 } 614 }
646 } 615 }
diff --git a/src/common/code_block.h b/src/common/code_block.h
index 2fa4a0090..6a55a8e30 100644
--- a/src/common/code_block.h
+++ b/src/common/code_block.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8
9#include "common/common_types.h" 8#include "common/common_types.h"
10#include "common/memory_util.h" 9#include "common/memory_util.h"
11 10
@@ -14,24 +13,27 @@
14// having to prefix them with gen-> or something similar. 13// having to prefix them with gen-> or something similar.
15// Example implementation: 14// Example implementation:
16// class JIT : public CodeBlock<ARMXEmitter> {} 15// class JIT : public CodeBlock<ARMXEmitter> {}
17template<class T> class CodeBlock : public T, NonCopyable 16template <class T>
18{ 17class CodeBlock : public T, NonCopyable {
19private: 18private:
20 // A privately used function to set the executable RAM space to something invalid. 19 // A privately used function to set the executable RAM space to something invalid.
21 // For debugging usefulness it should be used to set the RAM to a host specific breakpoint instruction 20 // For debugging usefulness it should be used to set the RAM to a host specific breakpoint
21 // instruction
22 virtual void PoisonMemory() = 0; 22 virtual void PoisonMemory() = 0;
23 23
24protected: 24protected:
25 u8 *region; 25 u8* region;
26 size_t region_size; 26 size_t region_size;
27 27
28public: 28public:
29 CodeBlock() : region(nullptr), region_size(0) {} 29 CodeBlock() : region(nullptr), region_size(0) {}
30 virtual ~CodeBlock() { if (region) FreeCodeSpace(); } 30 virtual ~CodeBlock() {
31 if (region)
32 FreeCodeSpace();
33 }
31 34
32 // Call this before you generate any code. 35 // Call this before you generate any code.
33 void AllocCodeSpace(int size) 36 void AllocCodeSpace(int size) {
34 {
35 region_size = size; 37 region_size = size;
36 region = (u8*)AllocateExecutableMemory(region_size); 38 region = (u8*)AllocateExecutableMemory(region_size);
37 T::SetCodePtr(region); 39 T::SetCodePtr(region);
@@ -39,15 +41,13 @@ public:
39 41
40 // Always clear code space with breakpoints, so that if someone accidentally executes 42 // Always clear code space with breakpoints, so that if someone accidentally executes
41 // uninitialized, it just breaks into the debugger. 43 // uninitialized, it just breaks into the debugger.
42 void ClearCodeSpace() 44 void ClearCodeSpace() {
43 {
44 PoisonMemory(); 45 PoisonMemory();
45 ResetCodePtr(); 46 ResetCodePtr();
46 } 47 }
47 48
48 // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. 49 // Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
49 void FreeCodeSpace() 50 void FreeCodeSpace() {
50 {
51#ifdef __SYMBIAN32__ 51#ifdef __SYMBIAN32__
52 ResetExecutableMemory(region); 52 ResetExecutableMemory(region);
53#else 53#else
@@ -57,33 +57,29 @@ public:
57 region_size = 0; 57 region_size = 0;
58 } 58 }
59 59
60 bool IsInSpace(const u8 *ptr) 60 bool IsInSpace(const u8* ptr) {
61 {
62 return (ptr >= region) && (ptr < (region + region_size)); 61 return (ptr >= region) && (ptr < (region + region_size));
63 } 62 }
64 63
65 // Cannot currently be undone. Will write protect the entire code region. 64 // Cannot currently be undone. Will write protect the entire code region.
66 // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). 65 // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
67 void WriteProtect() 66 void WriteProtect() {
68 {
69 WriteProtectMemory(region, region_size, true); 67 WriteProtectMemory(region, region_size, true);
70 } 68 }
71 69
72 void ResetCodePtr() 70 void ResetCodePtr() {
73 {
74 T::SetCodePtr(region); 71 T::SetCodePtr(region);
75 } 72 }
76 73
77 size_t GetSpaceLeft() const 74 size_t GetSpaceLeft() const {
78 {
79 return region_size - (T::GetCodePtr() - region); 75 return region_size - (T::GetCodePtr() - region);
80 } 76 }
81 77
82 u8 *GetBasePtr() { 78 u8* GetBasePtr() {
83 return region; 79 return region;
84 } 80 }
85 81
86 size_t GetOffset(const u8 *ptr) const { 82 size_t GetOffset(const u8* ptr) const {
87 return ptr - region; 83 return ptr - region;
88 } 84 }
89}; 85};
diff --git a/src/common/color.h b/src/common/color.h
index 908879ea6..4ebd4f3d0 100644
--- a/src/common/color.h
+++ b/src/common/color.h
@@ -56,7 +56,7 @@ constexpr u8 Convert8To6(u8 value) {
56 * @return Result color decoded as Math::Vec4<u8> 56 * @return Result color decoded as Math::Vec4<u8>
57 */ 57 */
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..b141e79ed 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -7,14 +7,13 @@
7#if !defined(ARCHITECTURE_x86_64) && !defined(_M_ARM) 7#if !defined(ARCHITECTURE_x86_64) && !defined(_M_ARM)
8#include <cstdlib> // for exit 8#include <cstdlib> // for exit
9#endif 9#endif
10
11#include "common_types.h" 10#include "common_types.h"
12 11
13#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 12#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
14 13
15/// Textually concatenates two tokens. The double-expansion is required by the C preprocessor. 14/// Textually concatenates two tokens. The double-expansion is required by the C preprocessor.
16#define CONCAT2(x, y) DO_CONCAT2(x, y) 15#define CONCAT2(x, y) DO_CONCAT2(x, y)
17#define DO_CONCAT2(x, y) x ## y 16#define DO_CONCAT2(x, y) x##y
18 17
19// helper macro to properly align structure members. 18// helper macro to properly align structure members.
20// Calling INSERT_PADDING_BYTES will add a new member variable with a name like "pad121", 19// Calling INSERT_PADDING_BYTES will add a new member variable with a name like "pad121",
@@ -24,9 +23,9 @@
24 23
25// Inlining 24// Inlining
26#ifdef _WIN32 25#ifdef _WIN32
27 #define FORCE_INLINE __forceinline 26#define FORCE_INLINE __forceinline
28#else 27#else
29 #define FORCE_INLINE inline __attribute__((always_inline)) 28#define FORCE_INLINE inline __attribute__((always_inline))
30#endif 29#endif
31 30
32#ifndef _MSC_VER 31#ifndef _MSC_VER
@@ -46,7 +45,8 @@
46#else 45#else
47inline u32 rotl(u32 x, int shift) { 46inline u32 rotl(u32 x, int shift) {
48 shift &= 31; 47 shift &= 31;
49 if (!shift) return x; 48 if (!shift)
49 return x;
50 return (x << shift) | (x >> (32 - shift)); 50 return (x << shift) | (x >> (32 - shift));
51} 51}
52#endif 52#endif
@@ -56,17 +56,18 @@ inline u32 rotl(u32 x, int shift) {
56#else 56#else
57inline u32 rotr(u32 x, int shift) { 57inline u32 rotr(u32 x, int shift) {
58 shift &= 31; 58 shift &= 31;
59 if (!shift) return x; 59 if (!shift)
60 return x;
60 return (x >> shift) | (x << (32 - shift)); 61 return (x >> shift) | (x << (32 - shift));
61} 62}
62#endif 63#endif
63 64
64inline u64 _rotl64(u64 x, unsigned int shift){ 65inline u64 _rotl64(u64 x, unsigned int shift) {
65 unsigned int n = shift % 64; 66 unsigned int n = shift % 64;
66 return (x << n) | (x >> (64 - n)); 67 return (x << n) | (x >> (64 - n));
67} 68}
68 69
69inline u64 _rotr64(u64 x, unsigned int shift){ 70inline u64 _rotr64(u64 x, unsigned int shift) {
70 unsigned int n = shift % 64; 71 unsigned int n = shift % 64;
71 return (x >> n) | (x << (64 - n)); 72 return (x >> n) | (x << (64 - n));
72} 73}
@@ -74,17 +75,17 @@ inline u64 _rotr64(u64 x, unsigned int shift){
74#else // _MSC_VER 75#else // _MSC_VER
75 76
76#if (_MSC_VER < 1900) 77#if (_MSC_VER < 1900)
77 // Function Cross-Compatibility 78// Function Cross-Compatibility
78 #define snprintf _snprintf 79#define snprintf _snprintf
79#endif 80#endif
80 81
81// Locale Cross-Compatibility 82// Locale Cross-Compatibility
82#define locale_t _locale_t 83#define locale_t _locale_t
83 84
84extern "C" { 85extern "C" {
85 __declspec(dllimport) void __stdcall DebugBreak(void); 86__declspec(dllimport) void __stdcall DebugBreak(void);
86} 87}
87#define Crash() {DebugBreak();} 88#define Crash() DebugBreak()
88 89
89// cstdlib provides these on MSVC 90// cstdlib provides these on MSVC
90#define rotr _rotr 91#define rotr _rotr
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index 2903f2cf2..a5342a610 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -16,13 +16,13 @@
16#define ROOT_DIR "." 16#define ROOT_DIR "."
17#define USERDATA_DIR "user" 17#define USERDATA_DIR "user"
18#ifdef USER_DIR 18#ifdef USER_DIR
19 #define EMU_DATA_DIR USER_DIR 19#define EMU_DATA_DIR USER_DIR
20#else 20#else
21 #ifdef _WIN32 21#ifdef _WIN32
22 #define EMU_DATA_DIR "Citra Emulator" 22#define EMU_DATA_DIR "Citra Emulator"
23 #else 23#else
24 #define EMU_DATA_DIR "citra-emu" 24#define EMU_DATA_DIR "citra-emu"
25 #endif 25#endif
26#endif 26#endif
27 27
28// Dirs in both User and Sys 28// Dirs in both User and Sys
@@ -31,32 +31,32 @@
31#define JAP_DIR "JAP" 31#define JAP_DIR "JAP"
32 32
33// Subdirs in the User dir returned by GetUserPath(D_USER_IDX) 33// Subdirs in the User dir returned by GetUserPath(D_USER_IDX)
34#define CONFIG_DIR "config" 34#define CONFIG_DIR "config"
35#define GAMECONFIG_DIR "game_config" 35#define GAMECONFIG_DIR "game_config"
36#define MAPS_DIR "maps" 36#define MAPS_DIR "maps"
37#define CACHE_DIR "cache" 37#define CACHE_DIR "cache"
38#define SDMC_DIR "sdmc" 38#define SDMC_DIR "sdmc"
39#define NAND_DIR "nand" 39#define NAND_DIR "nand"
40#define SYSDATA_DIR "sysdata" 40#define SYSDATA_DIR "sysdata"
41#define SHADERCACHE_DIR "shader_cache" 41#define SHADERCACHE_DIR "shader_cache"
42#define STATESAVES_DIR "state_saves" 42#define STATESAVES_DIR "state_saves"
43#define SCREENSHOTS_DIR "screenShots" 43#define SCREENSHOTS_DIR "screenShots"
44#define DUMP_DIR "dump" 44#define DUMP_DIR "dump"
45#define DUMP_TEXTURES_DIR "textures" 45#define DUMP_TEXTURES_DIR "textures"
46#define DUMP_FRAMES_DIR "frames" 46#define DUMP_FRAMES_DIR "frames"
47#define DUMP_AUDIO_DIR "audio" 47#define DUMP_AUDIO_DIR "audio"
48#define LOGS_DIR "logs" 48#define LOGS_DIR "logs"
49#define SHADERS_DIR "shaders" 49#define SHADERS_DIR "shaders"
50#define SYSCONF_DIR "sysconf" 50#define SYSCONF_DIR "sysconf"
51 51
52// Filenames 52// Filenames
53// Files in the directory returned by GetUserPath(D_CONFIG_IDX) 53// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
54#define EMU_CONFIG "emu.ini" 54#define EMU_CONFIG "emu.ini"
55#define DEBUGGER_CONFIG "debugger.ini" 55#define DEBUGGER_CONFIG "debugger.ini"
56#define LOGGER_CONFIG "logger.ini" 56#define LOGGER_CONFIG "logger.ini"
57 57
58// Sys files 58// Sys files
59#define SHARED_FONT "shared_font.bin" 59#define SHARED_FONT "shared_font.bin"
60 60
61// Files in the directory returned by GetUserPath(D_LOGS_IDX) 61// Files in the directory returned by GetUserPath(D_LOGS_IDX)
62#define MAIN_LOG "emu.log" 62#define MAIN_LOG "emu.log"
diff --git a/src/common/common_types.h b/src/common/common_types.h
index 9f51dff18..ee18eac81 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -32,18 +32,18 @@
32#endif 32#endif
33#endif 33#endif
34 34
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..122f1c212 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -4,10 +4,8 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cmath> 6#include <cmath>
7
8#include "common/assert.h" 7#include "common/assert.h"
9#include "common/key_map.h" 8#include "common/key_map.h"
10
11#include "emu_window.h" 9#include "emu_window.h"
12#include "video_core/video_core.h" 10#include "video_core/video_core.h"
13 11
@@ -44,18 +42,17 @@ void EmuWindow::CirclePadUpdated(float x, float y) {
44 */ 42 */
45static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsigned framebuffer_x, 43static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsigned framebuffer_x,
46 unsigned framebuffer_y) { 44 unsigned framebuffer_y) {
47 return (framebuffer_y >= layout.bottom_screen.top && 45 return (
48 framebuffer_y < layout.bottom_screen.bottom && 46 framebuffer_y >= layout.bottom_screen.top && framebuffer_y < layout.bottom_screen.bottom &&
49 framebuffer_x >= layout.bottom_screen.left && 47 framebuffer_x >= layout.bottom_screen.left && framebuffer_x < layout.bottom_screen.right);
50 framebuffer_x < layout.bottom_screen.right);
51} 48}
52 49
53std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { 50std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) {
54 new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); 51 new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
55 new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1); 52 new_x = std::min(new_x, framebuffer_layout.bottom_screen.right - 1);
56 53
57 new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); 54 new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
58 new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1); 55 new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom - 1);
59 56
60 return std::make_tuple(new_x, new_y); 57 return std::make_tuple(new_x, new_y);
61} 58}
@@ -64,10 +61,12 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
64 if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) 61 if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
65 return; 62 return;
66 63
67 touch_x = VideoCore::kScreenBottomWidth * (framebuffer_x - framebuffer_layout.bottom_screen.left) / 64 touch_x = VideoCore::kScreenBottomWidth *
68 (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); 65 (framebuffer_x - framebuffer_layout.bottom_screen.left) /
69 touch_y = VideoCore::kScreenBottomHeight * (framebuffer_y - framebuffer_layout.bottom_screen.top) / 66 (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left);
70 (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); 67 touch_y = VideoCore::kScreenBottomHeight *
68 (framebuffer_y - framebuffer_layout.bottom_screen.top) /
69 (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top);
71 70
72 touch_pressed = true; 71 touch_pressed = true;
73 pad_state.touch.Assign(1); 72 pad_state.touch.Assign(1);
@@ -90,16 +89,19 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
90 TouchPressed(framebuffer_x, framebuffer_y); 89 TouchPressed(framebuffer_x, framebuffer_y);
91} 90}
92 91
93EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) { 92EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width,
93 unsigned height) {
94 // When hiding the widget, the function receives a size of 0 94 // When hiding the widget, the function receives a size of 0
95 if (width == 0) width = 1; 95 if (width == 0)
96 if (height == 0) height = 1; 96 width = 1;
97 if (height == 0)
98 height = 1;
97 99
98 EmuWindow::FramebufferLayout res = { width, height, {}, {} }; 100 EmuWindow::FramebufferLayout res = {width, height, {}, {}};
99 101
100 float window_aspect_ratio = static_cast<float>(height) / width; 102 float window_aspect_ratio = static_cast<float>(height) / width;
101 float emulation_aspect_ratio = static_cast<float>(VideoCore::kScreenTopHeight * 2) / 103 float emulation_aspect_ratio =
102 VideoCore::kScreenTopWidth; 104 static_cast<float>(VideoCore::kScreenTopHeight * 2) / VideoCore::kScreenTopWidth;
103 105
104 if (window_aspect_ratio > emulation_aspect_ratio) { 106 if (window_aspect_ratio > emulation_aspect_ratio) {
105 // Window is narrower than the emulation content => apply borders to the top and bottom 107 // Window is narrower than the emulation content => apply borders to the top and bottom
@@ -110,8 +112,9 @@ EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(u
110 res.top_screen.top = (height - viewport_height) / 2; 112 res.top_screen.top = (height - viewport_height) / 2;
111 res.top_screen.bottom = res.top_screen.top + viewport_height / 2; 113 res.top_screen.bottom = res.top_screen.top + viewport_height / 2;
112 114
113 int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) / 115 int bottom_width = static_cast<int>(
114 VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left)); 116 (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth) *
117 (res.top_screen.right - res.top_screen.left));
115 int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; 118 int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2;
116 119
117 res.bottom_screen.left = bottom_border; 120 res.bottom_screen.left = bottom_border;
@@ -127,8 +130,9 @@ EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(u
127 res.top_screen.top = 0; 130 res.top_screen.top = 0;
128 res.top_screen.bottom = res.top_screen.top + height / 2; 131 res.top_screen.bottom = res.top_screen.top + height / 2;
129 132
130 int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) / 133 int bottom_width = static_cast<int>(
131 VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left)); 134 (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth) *
135 (res.top_screen.right - res.top_screen.left));
132 int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; 136 int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2;
133 137
134 res.bottom_screen.left = res.top_screen.left + bottom_border; 138 res.bottom_screen.left = res.top_screen.left + bottom_border;
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 57e303b6d..67df63e06 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -6,10 +6,8 @@
6 6
7#include <tuple> 7#include <tuple>
8#include <utility> 8#include <utility>
9
10#include "common/common_types.h" 9#include "common/common_types.h"
11#include "common/math_util.h" 10#include "common/math_util.h"
12
13#include "core/hle/service/hid/hid.h" 11#include "core/hle/service/hid/hid.h"
14 12
15/** 13/**
@@ -30,15 +28,14 @@
30 * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please 28 * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please
31 * re-read the upper points again and think about it if you don't see this. 29 * re-read the upper points again and think about it if you don't see this.
32 */ 30 */
33class EmuWindow 31class EmuWindow {
34{
35public: 32public:
36 /// Data structure to store emuwindow configuration 33 /// Data structure to store emuwindow configuration
37 struct WindowConfig { 34 struct WindowConfig {
38 bool fullscreen; 35 bool fullscreen;
39 int res_width; 36 int res_width;
40 int res_height; 37 int res_height;
41 std::pair<unsigned,unsigned> min_client_area_size; 38 std::pair<unsigned, unsigned> min_client_area_size;
42 }; 39 };
43 40
44 /// Describes the layout of the window framebuffer (size and top/bottom screen positions) 41 /// Describes the layout of the window framebuffer (size and top/bottom screen positions)
@@ -193,15 +190,18 @@ public:
193 190
194 /** 191 /**
195 * Returns currently active configuration. 192 * Returns currently active configuration.
196 * @note Accesses to the returned object need not be consistent because it may be modified in another thread 193 * @note Accesses to the returned object need not be consistent because it may be modified in
194 * another thread
197 */ 195 */
198 const WindowConfig& GetActiveConfig() const { 196 const WindowConfig& GetActiveConfig() const {
199 return active_config; 197 return active_config;
200 } 198 }
201 199
202 /** 200 /**
203 * Requests the internal configuration to be replaced by the specified argument at some point in the future. 201 * Requests the internal configuration to be replaced by the specified argument at some point in
204 * @note This method is thread-safe, because it delays configuration changes to the GUI event loop. Hence there is no guarantee on when the requested configuration will be active. 202 * the future.
203 * @note This method is thread-safe, because it delays configuration changes to the GUI event
204 * loop. Hence there is no guarantee on when the requested configuration will be active.
205 */ 205 */
206 void SetConfig(const WindowConfig& val) { 206 void SetConfig(const WindowConfig& val) {
207 config = val; 207 config = val;
@@ -258,7 +258,7 @@ protected:
258 * Update internal client area size with the given parameter. 258 * Update internal client area size with the given parameter.
259 * @note EmuWindow implementations will usually use this in window resize event handlers. 259 * @note EmuWindow implementations will usually use this in window resize event handlers.
260 */ 260 */
261 void NotifyClientAreaSizeChanged(const std::pair<unsigned,unsigned>& size) { 261 void NotifyClientAreaSizeChanged(const std::pair<unsigned, unsigned>& size) {
262 client_area_width = size.first; 262 client_area_width = size.first;
263 client_area_height = size.second; 263 client_area_height = size.second;
264 } 264 }
@@ -266,32 +266,35 @@ protected:
266private: 266private:
267 /** 267 /**
268 * Handler called when the minimal client area was requested to be changed via SetConfig. 268 * Handler called when the minimal client area was requested to be changed via SetConfig.
269 * For the request to be honored, EmuWindow implementations will usually reimplement this function. 269 * For the request to be honored, EmuWindow implementations will usually reimplement this
270 * function.
270 */ 271 */
271 virtual void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { 272 virtual void OnMinimalClientAreaChangeRequest(
273 const std::pair<unsigned, unsigned>& minimal_size) {
272 // By default, ignore this request and do nothing. 274 // By default, ignore this request and do nothing.
273 } 275 }
274 276
275 FramebufferLayout framebuffer_layout; ///< Current framebuffer layout 277 FramebufferLayout framebuffer_layout; ///< Current framebuffer layout
276 278
277 unsigned client_area_width; ///< Current client width, should be set by window impl. 279 unsigned client_area_width; ///< Current client width, should be set by window impl.
278 unsigned client_area_height; ///< Current client height, should be set by window impl. 280 unsigned client_area_height; ///< Current client height, should be set by window impl.
279 281
280 WindowConfig config; ///< Internal configuration (changes pending for being applied in ProcessConfigurationChanges) 282 WindowConfig config; ///< Internal configuration (changes pending for being applied in
281 WindowConfig active_config; ///< Internal active configuration 283 /// ProcessConfigurationChanges)
284 WindowConfig active_config; ///< Internal active configuration
282 285
283 bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false 286 bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false
284 287
285 u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) 288 u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
286 u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) 289 u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
287 290
288 s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156) 291 s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156)
289 s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156) 292 s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156)
290 293
291 /** 294 /**
292 * Clip the provided coordinates to be inside the touchscreen area. 295 * Clip the provided coordinates to be inside the touchscreen area.
293 */ 296 */
294 std::tuple<unsigned,unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); 297 std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
295 298
296 Service::HID::PadState pad_state; 299 Service::HID::PadState pad_state;
297}; 300};
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index bc83ab737..14cbcac6b 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -9,66 +9,63 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10 10
11#ifdef _WIN32 11#ifdef _WIN32
12 #include <windows.h> 12#include <windows.h>
13 #include <shlobj.h> // for SHGetFolderPath 13// windows.h needs to be included before other windows headers
14 #include <shellapi.h> 14#include <commdlg.h> // for GetSaveFileName
15 #include <commdlg.h> // for GetSaveFileName 15#include <direct.h> // getcwd
16 #include <io.h> 16#include <io.h>
17 #include <direct.h> // getcwd 17#include <shellapi.h>
18 #include <tchar.h> 18#include <shlobj.h> // for SHGetFolderPath
19 19#include <tchar.h>
20 #include "common/string_util.h" 20#include "common/string_util.h"
21 21
22 // 64 bit offsets for windows 22// 64 bit offsets for windows
23 #define fseeko _fseeki64 23#define fseeko _fseeki64
24 #define ftello _ftelli64 24#define ftello _ftelli64
25 #define atoll _atoi64 25#define atoll _atoi64
26 #define stat64 _stat64 26#define stat64 _stat64
27 #define fstat64 _fstat64 27#define fstat64 _fstat64
28 #define fileno _fileno 28#define fileno _fileno
29#else 29#else
30 #ifdef __APPLE__ 30#ifdef __APPLE__
31 #include <sys/param.h> 31#include <sys/param.h>
32 #endif 32#endif
33 #include <cctype> 33#include <cctype>
34 #include <cerrno> 34#include <cerrno>
35 #include <cstdlib> 35#include <cstdlib>
36 #include <cstring> 36#include <cstring>
37 #include <dirent.h> 37#include <dirent.h>
38 #include <pwd.h> 38#include <pwd.h>
39 #include <unistd.h> 39#include <unistd.h>
40#endif 40#endif
41 41
42#if defined(__APPLE__) 42#if defined(__APPLE__)
43 #include <CoreFoundation/CFString.h> 43#include <CoreFoundation/CFBundle.h>
44 #include <CoreFoundation/CFURL.h> 44#include <CoreFoundation/CFString.h>
45 #include <CoreFoundation/CFBundle.h> 45#include <CoreFoundation/CFURL.h>
46#endif 46#endif
47 47
48#include <algorithm> 48#include <algorithm>
49#include <sys/stat.h> 49#include <sys/stat.h>
50 50
51#ifndef S_ISDIR 51#ifndef S_ISDIR
52 #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) 52#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
53#endif 53#endif
54 54
55#ifdef BSD4_4 55#ifdef BSD4_4
56 #define stat64 stat 56#define stat64 stat
57 #define fstat64 fstat 57#define fstat64 fstat
58#endif 58#endif
59 59
60// This namespace has various generic functions related to files and paths. 60// This namespace has various generic functions related to files and paths.
61// The code still needs a ton of cleanup. 61// The code still needs a ton of cleanup.
62// REMEMBER: strdup considered harmful! 62// REMEMBER: strdup considered harmful!
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,35 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
886 } 828 }
887} 829}
888 830
889IOFile::IOFile() 831IOFile::IOFile() {}
890{
891}
892 832
893IOFile::IOFile(const std::string& filename, const char openmode[]) 833IOFile::IOFile(const std::string& filename, const char openmode[]) {
894{
895 Open(filename, openmode); 834 Open(filename, openmode);
896} 835}
897 836
898IOFile::~IOFile() 837IOFile::~IOFile() {
899{
900 Close(); 838 Close();
901} 839}
902 840
903IOFile::IOFile(IOFile&& other) 841IOFile::IOFile(IOFile&& other) {
904{
905 Swap(other); 842 Swap(other);
906} 843}
907 844
908IOFile& IOFile::operator=(IOFile&& other) 845IOFile& IOFile::operator=(IOFile&& other) {
909{
910 Swap(other); 846 Swap(other);
911 return *this; 847 return *this;
912} 848}
913 849
914void IOFile::Swap(IOFile& other) 850void IOFile::Swap(IOFile& other) {
915{
916 std::swap(m_file, other.m_file); 851 std::swap(m_file, other.m_file);
917 std::swap(m_good, other.m_good); 852 std::swap(m_good, other.m_good);
918} 853}
919 854
920bool IOFile::Open(const std::string& filename, const char openmode[]) 855bool IOFile::Open(const std::string& filename, const char openmode[]) {
921{
922 Close(); 856 Close();
923#ifdef _WIN32 857#ifdef _WIN32
924 _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), Common::UTF8ToUTF16W(openmode).c_str()); 858 _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(),
859 Common::UTF8ToUTF16W(openmode).c_str());
925#else 860#else
926 m_file = fopen(filename.c_str(), openmode); 861 m_file = fopen(filename.c_str(), openmode);
927#endif 862#endif
@@ -930,8 +865,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[])
930 return m_good; 865 return m_good;
931} 866}
932 867
933bool IOFile::Close() 868bool IOFile::Close() {
934{
935 if (!IsOpen() || 0 != std::fclose(m_file)) 869 if (!IsOpen() || 0 != std::fclose(m_file))
936 m_good = false; 870 m_good = false;
937 871
@@ -939,50 +873,46 @@ bool IOFile::Close()
939 return m_good; 873 return m_good;
940} 874}
941 875
942u64 IOFile::GetSize() const 876u64 IOFile::GetSize() const {
943{
944 if (IsOpen()) 877 if (IsOpen())
945 return FileUtil::GetSize(m_file); 878 return FileUtil::GetSize(m_file);
946 879
947 return 0; 880 return 0;
948} 881}
949 882
950bool IOFile::Seek(s64 off, int origin) 883bool IOFile::Seek(s64 off, int origin) {
951{
952 if (!IsOpen() || 0 != fseeko(m_file, off, origin)) 884 if (!IsOpen() || 0 != fseeko(m_file, off, origin))
953 m_good = false; 885 m_good = false;
954 886
955 return m_good; 887 return m_good;
956} 888}
957 889
958u64 IOFile::Tell() const 890u64 IOFile::Tell() const {
959{
960 if (IsOpen()) 891 if (IsOpen())
961 return ftello(m_file); 892 return ftello(m_file);
962 893
963 return -1; 894 return -1;
964} 895}
965 896
966bool IOFile::Flush() 897bool IOFile::Flush() {
967{
968 if (!IsOpen() || 0 != std::fflush(m_file)) 898 if (!IsOpen() || 0 != std::fflush(m_file))
969 m_good = false; 899 m_good = false;
970 900
971 return m_good; 901 return m_good;
972} 902}
973 903
974bool IOFile::Resize(u64 size) 904bool IOFile::Resize(u64 size) {
975{ 905 if (!IsOpen() ||
976 if (!IsOpen() || 0 != 906 0 !=
977#ifdef _WIN32 907#ifdef _WIN32
978 // ector: _chsize sucks, not 64-bit safe 908 // ector: _chsize sucks, not 64-bit safe
979 // F|RES: changed to _chsize_s. i think it is 64-bit safe 909 // F|RES: changed to _chsize_s. i think it is 64-bit safe
980 _chsize_s(_fileno(m_file), size) 910 _chsize_s(_fileno(m_file), size)
981#else 911#else
982 // TODO: handle 64bit and growing 912 // TODO: handle 64bit and growing
983 ftruncate(fileno(m_file), size) 913 ftruncate(fileno(m_file), size)
984#endif 914#endif
985 ) 915 )
986 m_good = false; 916 m_good = false;
987 917
988 return m_good; 918 return m_good;
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 7ad7ee829..204b06f14 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -5,15 +5,13 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <cstdio>
8#include <fstream> 9#include <fstream>
9#include <functional> 10#include <functional>
10#include <cstdio>
11#include <string> 11#include <string>
12#include <type_traits> 12#include <type_traits>
13#include <vector> 13#include <vector>
14
15#include "common/common_types.h" 14#include "common/common_types.h"
16
17#ifdef _MSC_VER 15#ifdef _MSC_VER
18#include "common/string_util.h" 16#include "common/string_util.h"
19#endif 17#endif
@@ -51,75 +49,75 @@ enum {
51 NUM_PATH_INDICES 49 NUM_PATH_INDICES
52}; 50};
53 51
54namespace FileUtil 52namespace FileUtil {
55{
56 53
57// FileSystem tree node/ 54// FileSystem tree node/
58struct FSTEntry 55struct FSTEntry {
59{
60 bool isDirectory; 56 bool isDirectory;
61 u64 size; // file length or number of entries from children 57 u64 size; // file length or number of entries from children
62 std::string physicalName; // name on disk 58 std::string physicalName; // name on disk
63 std::string virtualName; // name in FST names table 59 std::string virtualName; // name in FST names table
64 std::vector<FSTEntry> children; 60 std::vector<FSTEntry> children;
65}; 61};
66 62
67// Returns true if file filename exists 63// Returns true if file filename exists
68bool Exists(const std::string &filename); 64bool Exists(const std::string& filename);
69 65
70// Returns true if filename is a directory 66// Returns true if filename is a directory
71bool IsDirectory(const std::string &filename); 67bool IsDirectory(const std::string& filename);
72 68
73// Returns the size of filename (64bit) 69// Returns the size of filename (64bit)
74u64 GetSize(const std::string &filename); 70u64 GetSize(const std::string& filename);
75 71
76// Overloaded GetSize, accepts file descriptor 72// Overloaded GetSize, accepts file descriptor
77u64 GetSize(const int fd); 73u64 GetSize(const int fd);
78 74
79// Overloaded GetSize, accepts FILE* 75// Overloaded GetSize, accepts FILE*
80u64 GetSize(FILE *f); 76u64 GetSize(FILE* f);
81 77
82// Returns true if successful, or path already exists. 78// Returns true if successful, or path already exists.
83bool CreateDir(const std::string &filename); 79bool CreateDir(const std::string& filename);
84 80
85// Creates the full path of fullPath returns true on success 81// Creates the full path of fullPath returns true on success
86bool CreateFullPath(const std::string &fullPath); 82bool CreateFullPath(const std::string& fullPath);
87 83
88// Deletes a given filename, return true on success 84// Deletes a given filename, return true on success
89// Doesn't supports deleting a directory 85// Doesn't supports deleting a directory
90bool Delete(const std::string &filename); 86bool Delete(const std::string& filename);
91 87
92// Deletes a directory filename, returns true on success 88// Deletes a directory filename, returns true on success
93bool DeleteDir(const std::string &filename); 89bool DeleteDir(const std::string& filename);
94 90
95// renames file srcFilename to destFilename, returns true on success 91// renames file srcFilename to destFilename, returns true on success
96bool Rename(const std::string &srcFilename, const std::string &destFilename); 92bool Rename(const std::string& srcFilename, const std::string& destFilename);
97 93
98// copies file srcFilename to destFilename, returns true on success 94// copies file srcFilename to destFilename, returns true on success
99bool Copy(const std::string &srcFilename, const std::string &destFilename); 95bool Copy(const std::string& srcFilename, const std::string& destFilename);
100 96
101// creates an empty file filename, returns true on success 97// creates an empty file filename, returns true on success
102bool CreateEmptyFile(const std::string &filename); 98bool CreateEmptyFile(const std::string& filename);
103 99
104/** 100/**
105 * @param num_entries_out to be assigned by the callable with the number of iterated directory entries, never null 101 * @param num_entries_out to be assigned by the callable with the number of iterated directory
102 * entries, never null
106 * @param directory the path to the enclosing directory 103 * @param directory the path to the enclosing directory
107 * @param virtual_name the entry name, without any preceding directory info 104 * @param virtual_name the entry name, without any preceding directory info
108 * @return whether handling the entry succeeded 105 * @return whether handling the entry succeeded
109 */ 106 */
110using DirectoryEntryCallable = std::function<bool(unsigned* num_entries_out, 107using DirectoryEntryCallable = std::function<bool(
111 const std::string& directory, 108 unsigned* num_entries_out, const std::string& directory, const std::string& virtual_name)>;
112 const std::string& virtual_name)>;
113 109
114/** 110/**
115 * Scans a directory, calling the callback for each file/directory contained within. 111 * Scans a directory, calling the callback for each file/directory contained within.
116 * If the callback returns failure, scanning halts and this function returns failure as well 112 * If the callback returns failure, scanning halts and this function returns failure as well
117 * @param num_entries_out assigned by the function with the number of iterated directory entries, can be null 113 * @param num_entries_out assigned by the function with the number of iterated directory entries,
114 * can be null
118 * @param directory the directory to scan 115 * @param directory the directory to scan
119 * @param callback The callback which will be called for each entry 116 * @param callback The callback which will be called for each entry
120 * @return whether scanning the directory succeeded 117 * @return whether scanning the directory succeeded
121 */ 118 */
122bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback); 119bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory,
120 DirectoryEntryCallable callback);
123 121
124/** 122/**
125 * Scans the directory tree, storing the results. 123 * Scans the directory tree, storing the results.
@@ -128,23 +126,24 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
128 * @param recursion Number of children directories to read before giving up. 126 * @param recursion Number of children directories to read before giving up.
129 * @return the total number of files/directories found 127 * @return the total number of files/directories found
130 */ 128 */
131unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion = 0); 129unsigned ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
130 unsigned int recursion = 0);
132 131
133// deletes the given directory and anything under it. Returns true on success. 132// deletes the given directory and anything under it. Returns true on success.
134bool DeleteDirRecursively(const std::string &directory, unsigned int recursion = 256); 133bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256);
135 134
136// Returns the current directory 135// Returns the current directory
137std::string GetCurrentDir(); 136std::string GetCurrentDir();
138 137
139// Create directory and copy contents (does not overwrite existing files) 138// Create directory and copy contents (does not overwrite existing files)
140void CopyDir(const std::string &source_path, const std::string &dest_path); 139void CopyDir(const std::string& source_path, const std::string& dest_path);
141 140
142// Set the current directory to given directory 141// Set the current directory to given directory
143bool SetCurrentDir(const std::string &directory); 142bool SetCurrentDir(const std::string& directory);
144 143
145// Returns a pointer to a string with a Citra data dir in the user's home 144// Returns a pointer to a string with a Citra data dir in the user's home
146// directory. To be used in "multi-user" mode (that is, installed). 145// directory. To be used in "multi-user" mode (that is, installed).
147const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); 146const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath = "");
148 147
149// Returns the path to where the sys file are 148// Returns the path to where the sys file are
150std::string GetSysDirectory(); 149std::string GetSysDirectory();
@@ -154,11 +153,11 @@ std::string GetBundleDirectory();
154#endif 153#endif
155 154
156#ifdef _WIN32 155#ifdef _WIN32
157std::string &GetExeDirectory(); 156std::string& GetExeDirectory();
158#endif 157#endif
159 158
160size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename); 159size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename);
161size_t ReadFileToString(bool text_file, const char *filename, std::string &str); 160size_t ReadFileToString(bool text_file, const char* filename, std::string& str);
162 161
163/** 162/**
164 * Splits the filename into 8.3 format 163 * Splits the filename into 8.3 format
@@ -173,8 +172,7 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
173// simple wrapper for cstdlib file functions to 172// simple wrapper for cstdlib file functions to
174// hopefully will make error checking easier 173// hopefully will make error checking easier
175// and make forgetting an fclose() harder 174// and make forgetting an fclose() harder
176class IOFile : public NonCopyable 175class IOFile : public NonCopyable {
177{
178public: 176public:
179 IOFile(); 177 IOFile();
180 IOFile(const std::string& filename, const char openmode[]); 178 IOFile(const std::string& filename, const char openmode[]);
@@ -190,11 +188,12 @@ public:
190 bool Close(); 188 bool Close();
191 189
192 template <typename T> 190 template <typename T>
193 size_t ReadArray(T* data, size_t length) 191 size_t ReadArray(T* data, size_t length) {
194 { 192 static_assert(std::is_standard_layout<T>(),
195 static_assert(std::is_standard_layout<T>(), "Given array does not consist of standard layout objects"); 193 "Given array does not consist of standard layout objects");
196#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) 194#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
197 static_assert(std::is_trivially_copyable<T>(), "Given array does not consist of trivially copyable objects"); 195 static_assert(std::is_trivially_copyable<T>(),
196 "Given array does not consist of trivially copyable objects");
198#endif 197#endif
199 198
200 if (!IsOpen()) { 199 if (!IsOpen()) {
@@ -210,11 +209,12 @@ public:
210 } 209 }
211 210
212 template <typename T> 211 template <typename T>
213 size_t WriteArray(const T* data, size_t length) 212 size_t WriteArray(const T* data, size_t length) {
214 { 213 static_assert(std::is_standard_layout<T>(),
215 static_assert(std::is_standard_layout<T>(), "Given array does not consist of standard layout objects"); 214 "Given array does not consist of standard layout objects");
216#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) 215#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
217 static_assert(std::is_trivially_copyable<T>(), "Given array does not consist of trivially copyable objects"); 216 static_assert(std::is_trivially_copyable<T>(),
217 "Given array does not consist of trivially copyable objects");
218#endif 218#endif
219 219
220 if (!IsOpen()) { 220 if (!IsOpen()) {
@@ -229,27 +229,31 @@ public:
229 return items_written; 229 return items_written;
230 } 230 }
231 231
232 size_t ReadBytes(void* data, size_t length) 232 size_t ReadBytes(void* data, size_t length) {
233 {
234 return ReadArray(reinterpret_cast<char*>(data), length); 233 return ReadArray(reinterpret_cast<char*>(data), length);
235 } 234 }
236 235
237 size_t WriteBytes(const void* data, size_t length) 236 size_t WriteBytes(const void* data, size_t length) {
238 {
239 return WriteArray(reinterpret_cast<const char*>(data), length); 237 return WriteArray(reinterpret_cast<const char*>(data), length);
240 } 238 }
241 239
242 template<typename T> 240 template <typename T>
243 size_t WriteObject(const T& object) { 241 size_t WriteObject(const T& object) {
244 static_assert(!std::is_pointer<T>::value, "Given object is a pointer"); 242 static_assert(!std::is_pointer<T>::value, "Given object is a pointer");
245 return WriteArray(&object, 1); 243 return WriteArray(&object, 1);
246 } 244 }
247 245
248 bool IsOpen() const { return nullptr != m_file; } 246 bool IsOpen() const {
247 return nullptr != m_file;
248 }
249 249
250 // m_good is set to false when a read, write or other function fails 250 // m_good is set to false when a read, write or other function fails
251 bool IsGood() const { return m_good; } 251 bool IsGood() const {
252 explicit operator bool() const { return IsGood(); } 252 return m_good;
253 }
254 explicit operator bool() const {
255 return IsGood();
256 }
253 257
254 bool Seek(s64 off, int origin); 258 bool Seek(s64 off, int origin);
255 u64 Tell() const; 259 u64 Tell() const;
@@ -258,19 +262,21 @@ public:
258 bool Flush(); 262 bool Flush();
259 263
260 // clear error state 264 // clear error state
261 void Clear() { m_good = true; std::clearerr(m_file); } 265 void Clear() {
266 m_good = true;
267 std::clearerr(m_file);
268 }
262 269
263private: 270private:
264 std::FILE* m_file = nullptr; 271 std::FILE* m_file = nullptr;
265 bool m_good = true; 272 bool m_good = true;
266}; 273};
267 274
268} // namespace 275} // namespace
269 276
270// To deal with Windows being dumb at unicode: 277// To deal with Windows being dumb at unicode:
271template <typename T> 278template <typename T>
272void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) 279void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) {
273{
274#ifdef _MSC_VER 280#ifdef _MSC_VER
275 fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode); 281 fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode);
276#else 282#else
diff --git a/src/common/hash.cpp b/src/common/hash.cpp
index c49c2f60e..5aa5118eb 100644
--- a/src/common/hash.cpp
+++ b/src/common/hash.cpp
@@ -5,7 +5,6 @@
5#if defined(_MSC_VER) 5#if defined(_MSC_VER)
6#include <stdlib.h> 6#include <stdlib.h>
7#endif 7#endif
8
9#include "common_funcs.h" 8#include "common_funcs.h"
10#include "common_types.h" 9#include "common_types.h"
11#include "hash.h" 10#include "hash.h"
@@ -36,7 +35,7 @@ static FORCE_INLINE u64 fmix64(u64 k) {
36// platforms (MurmurHash3_x64_128). It was taken from: 35// platforms (MurmurHash3_x64_128). It was taken from:
37// https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp 36// https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
38void MurmurHash3_128(const void* key, int len, u32 seed, void* out) { 37void MurmurHash3_128(const void* key, int len, u32 seed, void* out) {
39 const u8 * data = (const u8*)key; 38 const u8* data = (const u8*)key;
40 const int nblocks = len / 16; 39 const int nblocks = len / 16;
41 40
42 u64 h1 = seed; 41 u64 h1 = seed;
@@ -47,52 +46,84 @@ void MurmurHash3_128(const void* key, int len, u32 seed, void* out) {
47 46
48 // Body 47 // Body
49 48
50 const u64 * blocks = (const u64 *)(data); 49 const u64* blocks = (const u64*)(data);
51 50
52 for (int i = 0; i < nblocks; i++) { 51 for (int i = 0; i < nblocks; i++) {
53 u64 k1 = getblock64(blocks,i*2+0); 52 u64 k1 = getblock64(blocks, i * 2 + 0);
54 u64 k2 = getblock64(blocks,i*2+1); 53 u64 k2 = getblock64(blocks, i * 2 + 1);
55 54
56 k1 *= c1; k1 = _rotl64(k1,31); k1 *= c2; h1 ^= k1; 55 k1 *= c1;
57 56 k1 = _rotl64(k1, 31);
58 h1 = _rotl64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; 57 k1 *= c2;
59 58 h1 ^= k1;
60 k2 *= c2; k2 = _rotl64(k2,33); k2 *= c1; h2 ^= k2; 59
61 60 h1 = _rotl64(h1, 27);
62 h2 = _rotl64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; 61 h1 += h2;
62 h1 = h1 * 5 + 0x52dce729;
63
64 k2 *= c2;
65 k2 = _rotl64(k2, 33);
66 k2 *= c1;
67 h2 ^= k2;
68
69 h2 = _rotl64(h2, 31);
70 h2 += h1;
71 h2 = h2 * 5 + 0x38495ab5;
63 } 72 }
64 73
65 // Tail 74 // Tail
66 75
67 const u8 * tail = (const u8*)(data + nblocks*16); 76 const u8* tail = (const u8*)(data + nblocks * 16);
68 77
69 u64 k1 = 0; 78 u64 k1 = 0;
70 u64 k2 = 0; 79 u64 k2 = 0;
71 80
72 switch (len & 15) { 81 switch (len & 15) {
73 case 15: k2 ^= ((u64)tail[14]) << 48; 82 case 15:
74 case 14: k2 ^= ((u64)tail[13]) << 40; 83 k2 ^= ((u64)tail[14]) << 48;
75 case 13: k2 ^= ((u64)tail[12]) << 32; 84 case 14:
76 case 12: k2 ^= ((u64)tail[11]) << 24; 85 k2 ^= ((u64)tail[13]) << 40;
77 case 11: k2 ^= ((u64)tail[10]) << 16; 86 case 13:
78 case 10: k2 ^= ((u64)tail[ 9]) << 8; 87 k2 ^= ((u64)tail[12]) << 32;
79 case 9: k2 ^= ((u64)tail[ 8]) << 0; 88 case 12:
80 k2 *= c2; k2 = _rotl64(k2,33); k2 *= c1; h2 ^= k2; 89 k2 ^= ((u64)tail[11]) << 24;
81 90 case 11:
82 case 8: k1 ^= ((u64)tail[ 7]) << 56; 91 k2 ^= ((u64)tail[10]) << 16;
83 case 7: k1 ^= ((u64)tail[ 6]) << 48; 92 case 10:
84 case 6: k1 ^= ((u64)tail[ 5]) << 40; 93 k2 ^= ((u64)tail[9]) << 8;
85 case 5: k1 ^= ((u64)tail[ 4]) << 32; 94 case 9:
86 case 4: k1 ^= ((u64)tail[ 3]) << 24; 95 k2 ^= ((u64)tail[8]) << 0;
87 case 3: k1 ^= ((u64)tail[ 2]) << 16; 96 k2 *= c2;
88 case 2: k1 ^= ((u64)tail[ 1]) << 8; 97 k2 = _rotl64(k2, 33);
89 case 1: k1 ^= ((u64)tail[ 0]) << 0; 98 k2 *= c1;
90 k1 *= c1; k1 = _rotl64(k1,31); k1 *= c2; h1 ^= k1; 99 h2 ^= k2;
100
101 case 8:
102 k1 ^= ((u64)tail[7]) << 56;
103 case 7:
104 k1 ^= ((u64)tail[6]) << 48;
105 case 6:
106 k1 ^= ((u64)tail[5]) << 40;
107 case 5:
108 k1 ^= ((u64)tail[4]) << 32;
109 case 4:
110 k1 ^= ((u64)tail[3]) << 24;
111 case 3:
112 k1 ^= ((u64)tail[2]) << 16;
113 case 2:
114 k1 ^= ((u64)tail[1]) << 8;
115 case 1:
116 k1 ^= ((u64)tail[0]) << 0;
117 k1 *= c1;
118 k1 = _rotl64(k1, 31);
119 k1 *= c2;
120 h1 ^= k1;
91 }; 121 };
92 122
93 // Finalization 123 // Finalization
94 124
95 h1 ^= len; h2 ^= len; 125 h1 ^= len;
126 h2 ^= len;
96 127
97 h1 += h2; 128 h1 += h2;
98 h2 += h1; 129 h2 += h1;
diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp
index ad311d66b..79b3fcb18 100644
--- a/src/common/key_map.cpp
+++ b/src/common/key_map.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
6
7#include "common/emu_window.h" 6#include "common/emu_window.h"
8#include "common/key_map.h" 7#include "common/key_map.h"
9 8
@@ -13,11 +12,25 @@ namespace KeyMap {
13// and map it directly to EmuWindow::ButtonPressed. 12// and map it directly to EmuWindow::ButtonPressed.
14// It should go the analog input way like circle pad does. 13// It should go the analog input way like circle pad does.
15const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{ 14const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{
16 Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y, 15 Service::HID::PAD_A,
17 Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR, 16 Service::HID::PAD_B,
18 Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE, 17 Service::HID::PAD_X,
19 Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT, 18 Service::HID::PAD_Y,
20 Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT, 19 Service::HID::PAD_L,
20 Service::HID::PAD_R,
21 Service::HID::PAD_ZL,
22 Service::HID::PAD_ZR,
23 Service::HID::PAD_START,
24 Service::HID::PAD_SELECT,
25 Service::HID::PAD_NONE,
26 Service::HID::PAD_UP,
27 Service::HID::PAD_DOWN,
28 Service::HID::PAD_LEFT,
29 Service::HID::PAD_RIGHT,
30 Service::HID::PAD_C_UP,
31 Service::HID::PAD_C_DOWN,
32 Service::HID::PAD_C_LEFT,
33 Service::HID::PAD_C_RIGHT,
21 34
22 IndirectTarget::CirclePadUp, 35 IndirectTarget::CirclePadUp,
23 IndirectTarget::CirclePadDown, 36 IndirectTarget::CirclePadDown,
@@ -49,7 +62,8 @@ static void UpdateCirclePad(EmuWindow& emu_window) {
49 --y; 62 --y;
50 63
51 float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0; 64 float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0;
52 emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0 : SQRT_HALF), y * modifier * (x == 0 ? 1.0 : SQRT_HALF)); 65 emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0 : SQRT_HALF),
66 y * modifier * (x == 0 ? 1.0 : SQRT_HALF));
53} 67}
54 68
55int NewDeviceId() { 69int NewDeviceId() {
@@ -103,7 +117,7 @@ void PressKey(EmuWindow& emu_window, HostDeviceKey key) {
103 } 117 }
104} 118}
105 119
106void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) { 120void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key) {
107 auto target = key_map.find(key); 121 auto target = key_map.find(key);
108 if (target == key_map.end()) 122 if (target == key_map.end())
109 return; 123 return;
@@ -135,5 +149,4 @@ void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) {
135 } 149 }
136 } 150 }
137} 151}
138
139} 152}
diff --git a/src/common/key_map.h b/src/common/key_map.h
index b62f017c6..040794578 100644
--- a/src/common/key_map.h
+++ b/src/common/key_map.h
@@ -55,14 +55,12 @@ struct HostDeviceKey {
55 int key_code; 55 int key_code;
56 int device_id; ///< Uniquely identifies a host device 56 int device_id; ///< Uniquely identifies a host device
57 57
58 bool operator<(const HostDeviceKey &other) const { 58 bool operator<(const HostDeviceKey& other) const {
59 return std::tie(key_code, device_id) < 59 return std::tie(key_code, device_id) < std::tie(other.key_code, other.device_id);
60 std::tie(other.key_code, other.device_id);
61 } 60 }
62 61
63 bool operator==(const HostDeviceKey &other) const { 62 bool operator==(const HostDeviceKey& other) const {
64 return std::tie(key_code, device_id) == 63 return std::tie(key_code, device_id) == std::tie(other.key_code, other.device_id);
65 std::tie(other.key_code, other.device_id);
66 } 64 }
67}; 65};
68 66
@@ -92,5 +90,4 @@ void PressKey(EmuWindow& emu_window, HostDeviceKey key);
92 * Maps a key release action and call the corresponding function in EmuWindow 90 * Maps a key release action and call the corresponding function in EmuWindow
93 */ 91 */
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..9a13a9e90 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -5,7 +5,6 @@
5#include <algorithm> 5#include <algorithm>
6#include <array> 6#include <array>
7#include <cstdio> 7#include <cstdio>
8
9#include "common/assert.h" 8#include "common/assert.h"
10#include "common/common_funcs.h" // snprintf compatibility define 9#include "common/common_funcs.h" // snprintf compatibility define
11#include "common/logging/backend.h" 10#include "common/logging/backend.h"
@@ -16,73 +15,79 @@
16namespace Log { 15namespace Log {
17 16
18/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. 17/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
19#define ALL_LOG_CLASSES() \ 18#define ALL_LOG_CLASSES() \
20 CLS(Log) \ 19 CLS(Log) \
21 CLS(Common) \ 20 CLS(Common) \
22 SUB(Common, Filesystem) \ 21 SUB(Common, Filesystem) \
23 SUB(Common, Memory) \ 22 SUB(Common, Memory) \
24 CLS(Core) \ 23 CLS(Core) \
25 SUB(Core, ARM11) \ 24 SUB(Core, ARM11) \
26 SUB(Core, Timing) \ 25 SUB(Core, Timing) \
27 CLS(Config) \ 26 CLS(Config) \
28 CLS(Debug) \ 27 CLS(Debug) \
29 SUB(Debug, Emulated) \ 28 SUB(Debug, Emulated) \
30 SUB(Debug, GPU) \ 29 SUB(Debug, GPU) \
31 SUB(Debug, Breakpoint) \ 30 SUB(Debug, Breakpoint) \
32 SUB(Debug, GDBStub) \ 31 SUB(Debug, GDBStub) \
33 CLS(Kernel) \ 32 CLS(Kernel) \
34 SUB(Kernel, SVC) \ 33 SUB(Kernel, SVC) \
35 CLS(Service) \ 34 CLS(Service) \
36 SUB(Service, SRV) \ 35 SUB(Service, SRV) \
37 SUB(Service, FRD) \ 36 SUB(Service, FRD) \
38 SUB(Service, FS) \ 37 SUB(Service, FS) \
39 SUB(Service, ERR) \ 38 SUB(Service, ERR) \
40 SUB(Service, APT) \ 39 SUB(Service, APT) \
41 SUB(Service, GSP) \ 40 SUB(Service, GSP) \
42 SUB(Service, AC) \ 41 SUB(Service, AC) \
43 SUB(Service, AM) \ 42 SUB(Service, AM) \
44 SUB(Service, PTM) \ 43 SUB(Service, PTM) \
45 SUB(Service, LDR) \ 44 SUB(Service, LDR) \
46 SUB(Service, NDM) \ 45 SUB(Service, NDM) \
47 SUB(Service, NIM) \ 46 SUB(Service, NIM) \
48 SUB(Service, NWM) \ 47 SUB(Service, NWM) \
49 SUB(Service, CAM) \ 48 SUB(Service, CAM) \
50 SUB(Service, CECD) \ 49 SUB(Service, CECD) \
51 SUB(Service, CFG) \ 50 SUB(Service, CFG) \
52 SUB(Service, DSP) \ 51 SUB(Service, DSP) \
53 SUB(Service, DLP) \ 52 SUB(Service, DLP) \
54 SUB(Service, HID) \ 53 SUB(Service, HID) \
55 SUB(Service, SOC) \ 54 SUB(Service, SOC) \
56 SUB(Service, IR) \ 55 SUB(Service, IR) \
57 SUB(Service, Y2R) \ 56 SUB(Service, Y2R) \
58 CLS(HW) \ 57 CLS(HW) \
59 SUB(HW, Memory) \ 58 SUB(HW, Memory) \
60 SUB(HW, LCD) \ 59 SUB(HW, LCD) \
61 SUB(HW, GPU) \ 60 SUB(HW, GPU) \
62 CLS(Frontend) \ 61 CLS(Frontend) \
63 CLS(Render) \ 62 CLS(Render) \
64 SUB(Render, Software) \ 63 SUB(Render, Software) \
65 SUB(Render, OpenGL) \ 64 SUB(Render, OpenGL) \
66 CLS(Audio) \ 65 CLS(Audio) \
67 SUB(Audio, DSP) \ 66 SUB(Audio, DSP) \
68 SUB(Audio, Sink) \ 67 SUB(Audio, Sink) \
69 CLS(Loader) 68 CLS(Loader)
70 69
71// GetClassName is a macro defined by Windows.h, grrr... 70// GetClassName is a macro defined by Windows.h, grrr...
72const char* GetLogClassName(Class log_class) { 71const char* GetLogClassName(Class log_class) {
73 switch (log_class) { 72 switch (log_class) {
74#define CLS(x) case Class::x: return #x; 73#define CLS(x) \
75#define SUB(x, y) case Class::x##_##y: return #x "." #y; 74 case Class::x: \
75 return #x;
76#define SUB(x, y) \
77 case Class::x##_##y: \
78 return #x "." #y;
76 ALL_LOG_CLASSES() 79 ALL_LOG_CLASSES()
77#undef CLS 80#undef CLS
78#undef SUB 81#undef SUB
79 case Class::Count: 82 case Class::Count:
80 UNREACHABLE(); 83 UNREACHABLE();
81 } 84 }
82} 85}
83 86
84const char* GetLevelName(Level log_level) { 87const char* GetLevelName(Level log_level) {
85#define LVL(x) case Level::x: return #x 88#define LVL(x) \
89 case Level::x: \
90 return #x
86 switch (log_level) { 91 switch (log_level) {
87 LVL(Trace); 92 LVL(Trace);
88 LVL(Debug); 93 LVL(Debug);
@@ -90,15 +95,14 @@ const char* GetLevelName(Level log_level) {
90 LVL(Warning); 95 LVL(Warning);
91 LVL(Error); 96 LVL(Error);
92 LVL(Critical); 97 LVL(Critical);
93 case Level::Count: 98 case Level::Count:
94 UNREACHABLE(); 99 UNREACHABLE();
95 } 100 }
96#undef LVL 101#undef LVL
97} 102}
98 103
99Entry CreateEntry(Class log_class, Level log_level, 104Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
100 const char* filename, unsigned int line_nr, const char* function, 105 const char* function, const char* format, va_list args) {
101 const char* format, va_list args) {
102 using std::chrono::steady_clock; 106 using std::chrono::steady_clock;
103 using std::chrono::duration_cast; 107 using std::chrono::duration_cast;
104 108
@@ -111,7 +115,8 @@ Entry CreateEntry(Class log_class, Level log_level,
111 entry.log_class = log_class; 115 entry.log_class = log_class;
112 entry.log_level = log_level; 116 entry.log_level = log_level;
113 117
114 snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function, line_nr); 118 snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function,
119 line_nr);
115 entry.location = std::string(formatting_buffer.data()); 120 entry.location = std::string(formatting_buffer.data());
116 121
117 vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args); 122 vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args);
@@ -126,19 +131,16 @@ void SetFilter(Filter* new_filter) {
126 filter = new_filter; 131 filter = new_filter;
127} 132}
128 133
129void LogMessage(Class log_class, Level log_level, 134void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
130 const char* filename, unsigned int line_nr, const char* function, 135 const char* function, const char* format, ...) {
131 const char* format, ...) {
132 if (filter != nullptr && !filter->CheckMessage(log_class, log_level)) 136 if (filter != nullptr && !filter->CheckMessage(log_class, log_level))
133 return; 137 return;
134 138
135 va_list args; 139 va_list args;
136 va_start(args, format); 140 va_start(args, format);
137 Entry entry = CreateEntry(log_class, log_level, 141 Entry entry = CreateEntry(log_class, log_level, filename, line_nr, function, format, args);
138 filename, line_nr, function, format, args);
139 va_end(args); 142 va_end(args);
140 143
141 PrintColoredMessage(entry); 144 PrintColoredMessage(entry);
142} 145}
143
144} 146}
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index 795d42ebd..c4fe2acbf 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -8,7 +8,6 @@
8#include <cstdarg> 8#include <cstdarg>
9#include <string> 9#include <string>
10#include <utility> 10#include <utility>
11
12#include "common/logging/log.h" 11#include "common/logging/log.h"
13 12
14namespace Log { 13namespace Log {
@@ -44,10 +43,8 @@ const char* GetLogClassName(Class log_class);
44const char* GetLevelName(Level log_level); 43const char* GetLevelName(Level log_level);
45 44
46/// Creates a log entry by formatting the given source location, and message. 45/// Creates a log entry by formatting the given source location, and message.
47Entry CreateEntry(Class log_class, Level log_level, 46Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
48 const char* filename, unsigned int line_nr, const char* function, 47 const char* function, const char* format, va_list args);
49 const char* format, va_list args);
50 48
51void SetFilter(Filter* filter); 49void SetFilter(Filter* filter);
52
53} 50}
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 55cc8888a..12e5bb45d 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -3,9 +3,8 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6
7#include "common/logging/filter.h"
8#include "common/logging/backend.h" 6#include "common/logging/backend.h"
7#include "common/logging/filter.h"
9#include "common/string_util.h" 8#include "common/string_util.h"
10 9
11namespace Log { 10namespace Log {
@@ -63,11 +62,11 @@ static Class GetClassByName(const It begin, const It end) {
63} 62}
64 63
65bool Filter::ParseFilterRule(const std::string::const_iterator begin, 64bool Filter::ParseFilterRule(const std::string::const_iterator begin,
66 const std::string::const_iterator end) { 65 const std::string::const_iterator end) {
67 auto level_separator = std::find(begin, end, ':'); 66 auto level_separator = std::find(begin, end, ':');
68 if (level_separator == end) { 67 if (level_separator == end) {
69 LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s", 68 LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s",
70 std::string(begin, end).c_str()); 69 std::string(begin, end).c_str());
71 return false; 70 return false;
72 } 71 }
73 72
@@ -95,5 +94,4 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
95bool Filter::CheckMessage(Class log_class, Level level) const { 94bool Filter::CheckMessage(Class log_class, Level level) const {
96 return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]); 95 return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
97} 96}
98
99} 97}
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h
index a2b4eca43..b51df61de 100644
--- a/src/common/logging/filter.h
+++ b/src/common/logging/filter.h
@@ -7,7 +7,6 @@
7#include <array> 7#include <array>
8#include <cstddef> 8#include <cstddef>
9#include <string> 9#include <string>
10
11#include "common/logging/log.h" 10#include "common/logging/log.h"
12 11
13namespace Log { 12namespace Log {
@@ -42,7 +41,8 @@ public:
42 * - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace. 41 * - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace.
43 */ 42 */
44 void ParseFilterString(const std::string& filter_str); 43 void ParseFilterString(const std::string& filter_str);
45 bool ParseFilterRule(const std::string::const_iterator start, const std::string::const_iterator end); 44 bool ParseFilterRule(const std::string::const_iterator start,
45 const std::string::const_iterator end);
46 46
47 /// Matches class/level combination against the filter, returning true if it passed. 47 /// Matches class/level combination against the filter, returning true if it passed.
48 bool CheckMessage(Class log_class, Level level) const; 48 bool CheckMessage(Class log_class, Level level) const;
@@ -50,5 +50,4 @@ public:
50private: 50private:
51 std::array<Level, (size_t)Class::Count> class_levels; 51 std::array<Level, (size_t)Class::Count> class_levels;
52}; 52};
53
54} 53}
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index c6910b1c7..a4b4750de 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -28,71 +28,73 @@ typedef u8 ClassType;
28/** 28/**
29 * Specifies the sub-system that generated the log message. 29 * Specifies the sub-system that generated the log message.
30 * 30 *
31 * @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in backend.cpp. 31 * @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in
32 * backend.cpp.
32 */ 33 */
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..d61c1696b 100644
--- a/src/common/logging/text_formatter.cpp
+++ b/src/common/logging/text_formatter.cpp
@@ -6,16 +6,15 @@
6#include <cstdio> 6#include <cstdio>
7 7
8#ifdef _WIN32 8#ifdef _WIN32
9# define WIN32_LEAN_AND_MEAN 9#define WIN32_LEAN_AND_MEAN
10# include <Windows.h> 10#include <Windows.h>
11#endif 11#endif
12 12
13#include "common/assert.h"
14#include "common/common_funcs.h"
13#include "common/logging/backend.h" 15#include "common/logging/backend.h"
14#include "common/logging/log.h" 16#include "common/logging/log.h"
15#include "common/logging/text_formatter.h" 17#include "common/logging/text_formatter.h"
16
17#include "common/assert.h"
18#include "common/common_funcs.h"
19#include "common/string_util.h" 18#include "common/string_util.h"
20 19
21namespace Log { 20namespace Log {
@@ -44,15 +43,14 @@ const char* TrimSourcePath(const char* path, const char* root) {
44} 43}
45 44
46void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) { 45void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) {
47 unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000); 46 unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000);
48 unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000); 47 unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000);
49 48
50 const char* class_name = GetLogClassName(entry.log_class); 49 const char* class_name = GetLogClassName(entry.log_class);
51 const char* level_name = GetLevelName(entry.log_level); 50 const char* level_name = GetLevelName(entry.log_level);
52 51
53 snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", 52 snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", time_seconds, time_fractional,
54 time_seconds, time_fractional, class_name, level_name, 53 class_name, level_name, TrimSourcePath(entry.location.c_str()), entry.message.c_str());
55 TrimSourcePath(entry.location.c_str()), entry.message.c_str());
56} 54}
57 55
58void PrintMessage(const Entry& entry) { 56void PrintMessage(const Entry& entry) {
@@ -72,38 +70,50 @@ void PrintColoredMessage(const Entry& entry) {
72 WORD color = 0; 70 WORD color = 0;
73 switch (entry.log_level) { 71 switch (entry.log_level) {
74 case Level::Trace: // Grey 72 case Level::Trace: // Grey
75 color = FOREGROUND_INTENSITY; break; 73 color = FOREGROUND_INTENSITY;
74 break;
76 case Level::Debug: // Cyan 75 case Level::Debug: // Cyan
77 color = FOREGROUND_GREEN | FOREGROUND_BLUE; break; 76 color = FOREGROUND_GREEN | FOREGROUND_BLUE;
77 break;
78 case Level::Info: // Bright gray 78 case Level::Info: // Bright gray
79 color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; 79 color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
80 break;
80 case Level::Warning: // Bright yellow 81 case Level::Warning: // Bright yellow
81 color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; break; 82 color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
83 break;
82 case Level::Error: // Bright red 84 case Level::Error: // Bright red
83 color = FOREGROUND_RED | FOREGROUND_INTENSITY; break; 85 color = FOREGROUND_RED | FOREGROUND_INTENSITY;
86 break;
84 case Level::Critical: // Bright magenta 87 case Level::Critical: // Bright magenta
85 color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break; 88 color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
89 break;
86 case Level::Count: 90 case Level::Count:
87 UNREACHABLE(); 91 UNREACHABLE();
88 } 92 }
89 93
90 SetConsoleTextAttribute(console_handle, color); 94 SetConsoleTextAttribute(console_handle, color);
91#else 95#else
92# define ESC "\x1b" 96#define ESC "\x1b"
93 const char* color = ""; 97 const char* color = "";
94 switch (entry.log_level) { 98 switch (entry.log_level) {
95 case Level::Trace: // Grey 99 case Level::Trace: // Grey
96 color = ESC "[1;30m"; break; 100 color = ESC "[1;30m";
101 break;
97 case Level::Debug: // Cyan 102 case Level::Debug: // Cyan
98 color = ESC "[0;36m"; break; 103 color = ESC "[0;36m";
104 break;
99 case Level::Info: // Bright gray 105 case Level::Info: // Bright gray
100 color = ESC "[0;37m"; break; 106 color = ESC "[0;37m";
107 break;
101 case Level::Warning: // Bright yellow 108 case Level::Warning: // Bright yellow
102 color = ESC "[1;33m"; break; 109 color = ESC "[1;33m";
110 break;
103 case Level::Error: // Bright red 111 case Level::Error: // Bright red
104 color = ESC "[1;31m"; break; 112 color = ESC "[1;31m";
113 break;
105 case Level::Critical: // Bright magenta 114 case Level::Critical: // Bright magenta
106 color = ESC "[1;35m"; break; 115 color = ESC "[1;35m";
116 break;
107 case Level::Count: 117 case Level::Count:
108 UNREACHABLE(); 118 UNREACHABLE();
109 } 119 }
@@ -117,8 +127,7 @@ void PrintColoredMessage(const Entry& entry) {
117 SetConsoleTextAttribute(console_handle, original_info.wAttributes); 127 SetConsoleTextAttribute(console_handle, original_info.wAttributes);
118#else 128#else
119 fputs(ESC "[0m", stderr); 129 fputs(ESC "[0m", stderr);
120# undef ESC 130#undef ESC
121#endif 131#endif
122} 132}
123
124} 133}
diff --git a/src/common/logging/text_formatter.h b/src/common/logging/text_formatter.h
index 5b82f043f..0da102bc6 100644
--- a/src/common/logging/text_formatter.h
+++ b/src/common/logging/text_formatter.h
@@ -28,5 +28,4 @@ void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len);
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..41d89666c 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -8,22 +8,20 @@
8#include <cstdlib> 8#include <cstdlib>
9#include <type_traits> 9#include <type_traits>
10 10
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;
@@ -31,10 +29,15 @@ struct Rectangle
31 29
32 Rectangle() {} 30 Rectangle() {}
33 31
34 Rectangle(T left, T top, T right, T bottom) : left(left), top(top), right(right), bottom(bottom) {} 32 Rectangle(T left, T top, T right, T bottom)
33 : left(left), top(top), right(right), bottom(bottom) {}
35 34
36 T GetWidth() const { return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); } 35 T GetWidth() const {
37 T GetHeight() const { return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); } 36 return std::abs(static_cast<typename std::make_signed<T>::type>(right - left));
37 }
38 T GetHeight() const {
39 return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top));
40 }
38}; 41};
39 42
40} // namespace MathUtil 43} // namespace MathUtil
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
index 07c7f79c8..c19729b21 100644
--- a/src/common/memory_util.cpp
+++ b/src/common/memory_util.cpp
@@ -2,31 +2,30 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5
6#include "common/logging/log.h" 5#include "common/logging/log.h"
7#include "common/memory_util.h" 6#include "common/memory_util.h"
8 7
9#ifdef _WIN32 8#ifdef _WIN32
10 #include <windows.h> 9#include <windows.h>
11 #include <psapi.h> 10// Windows.h needs to be included before psapi.h
12 #include "common/common_funcs.h" 11#include <psapi.h>
13 #include "common/string_util.h" 12#include "common/common_funcs.h"
13#include "common/string_util.h"
14#else 14#else
15 #include <cstdlib> 15#include <cstdlib>
16 #include <sys/mman.h> 16#include <sys/mman.h>
17#endif 17#endif
18 18
19#if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) 19#if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
20#include <unistd.h> 20#include <unistd.h>
21#define PAGE_MASK (getpagesize() - 1) 21#define PAGE_MASK (getpagesize() - 1)
22#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) 22#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
23#endif 23#endif
24 24
25// This is purposely not a full wrapper for virtualalloc/mmap, but it 25// This is purposely not a full wrapper for virtualalloc/mmap, but it
26// provides exactly the primitive operations that Dolphin needs. 26// provides exactly the primitive operations that Dolphin needs.
27 27
28void* AllocateExecutableMemory(size_t size, bool low) 28void* AllocateExecutableMemory(size_t size, bool low) {
29{
30#if defined(_WIN32) 29#if defined(_WIN32)
31 void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 30 void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
32#else 31#else
@@ -39,31 +38,27 @@ void* AllocateExecutableMemory(size_t size, bool low)
39 // effect of discarding already mapped pages that happen to be in the 38 // effect of discarding already mapped pages that happen to be in the
40 // requested virtual memory range (such as the emulated RAM, sometimes). 39 // requested virtual memory range (such as the emulated RAM, sometimes).
41 if (low && (!map_hint)) 40 if (low && (!map_hint))
42 map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ 41 map_hint = (char*)round_page(512 * 1024 * 1024); /* 0.5 GB rounded up to the next page */
43#endif 42#endif
44 void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, 43 void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE
45 MAP_ANON | MAP_PRIVATE
46#if defined(ARCHITECTURE_X64) && defined(MAP_32BIT) 44#if defined(ARCHITECTURE_X64) && defined(MAP_32BIT)
47 | (low ? MAP_32BIT : 0) 45 | (low ? MAP_32BIT : 0)
48#endif 46#endif
49 , -1, 0); 47 ,
48 -1, 0);
50#endif /* defined(_WIN32) */ 49#endif /* defined(_WIN32) */
51 50
52#ifdef _WIN32 51#ifdef _WIN32
53 if (ptr == nullptr) 52 if (ptr == nullptr) {
54 {
55#else 53#else
56 if (ptr == MAP_FAILED) 54 if (ptr == MAP_FAILED) {
57 {
58 ptr = nullptr; 55 ptr = nullptr;
59#endif 56#endif
60 LOG_ERROR(Common_Memory, "Failed to allocate executable memory"); 57 LOG_ERROR(Common_Memory, "Failed to allocate executable memory");
61 } 58 }
62#if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT) 59#if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
63 else 60 else {
64 { 61 if (low) {
65 if (low)
66 {
67 map_hint += size; 62 map_hint += size;
68 map_hint = (char*)round_page(map_hint); /* round up to the next page */ 63 map_hint = (char*)round_page(map_hint); /* round up to the next page */
69 } 64 }
@@ -78,13 +73,11 @@ void* AllocateExecutableMemory(size_t size, bool low)
78 return ptr; 73 return ptr;
79} 74}
80 75
81void* AllocateMemoryPages(size_t size) 76void* AllocateMemoryPages(size_t size) {
82{
83#ifdef _WIN32 77#ifdef _WIN32
84 void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); 78 void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
85#else 79#else
86 void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, 80 void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
87 MAP_ANON | MAP_PRIVATE, -1, 0);
88 81
89 if (ptr == MAP_FAILED) 82 if (ptr == MAP_FAILED)
90 ptr = nullptr; 83 ptr = nullptr;
@@ -96,10 +89,9 @@ void* AllocateMemoryPages(size_t size)
96 return ptr; 89 return ptr;
97} 90}
98 91
99void* AllocateAlignedMemory(size_t size,size_t alignment) 92void* AllocateAlignedMemory(size_t size, size_t alignment) {
100{
101#ifdef _WIN32 93#ifdef _WIN32
102 void* ptr = _aligned_malloc(size,alignment); 94 void* ptr = _aligned_malloc(size, alignment);
103#else 95#else
104 void* ptr = nullptr; 96 void* ptr = nullptr;
105#ifdef ANDROID 97#ifdef ANDROID
@@ -116,10 +108,8 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
116 return ptr; 108 return ptr;
117} 109}
118 110
119void FreeMemoryPages(void* ptr, size_t size) 111void FreeMemoryPages(void* ptr, size_t size) {
120{ 112 if (ptr) {
121 if (ptr)
122 {
123#ifdef _WIN32 113#ifdef _WIN32
124 if (!VirtualFree(ptr, 0, MEM_RELEASE)) 114 if (!VirtualFree(ptr, 0, MEM_RELEASE))
125 LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg()); 115 LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg());
@@ -129,20 +119,17 @@ void FreeMemoryPages(void* ptr, size_t size)
129 } 119 }
130} 120}
131 121
132void FreeAlignedMemory(void* ptr) 122void FreeAlignedMemory(void* ptr) {
133{ 123 if (ptr) {
134 if (ptr)
135 {
136#ifdef _WIN32 124#ifdef _WIN32
137 _aligned_free(ptr); 125 _aligned_free(ptr);
138#else 126#else
139 free(ptr); 127 free(ptr);
140#endif 128#endif
141 } 129 }
142} 130}
143 131
144void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) 132void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
145{
146#ifdef _WIN32 133#ifdef _WIN32
147 DWORD oldValue; 134 DWORD oldValue;
148 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) 135 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
@@ -152,19 +139,19 @@ void WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
152#endif 139#endif
153} 140}
154 141
155void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) 142void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
156{
157#ifdef _WIN32 143#ifdef _WIN32
158 DWORD oldValue; 144 DWORD oldValue;
159 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) 145 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
146 &oldValue))
160 LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg()); 147 LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
161#else 148#else
162 mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); 149 mprotect(ptr, size,
150 allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
163#endif 151#endif
164} 152}
165 153
166std::string MemUsage() 154std::string MemUsage() {
167{
168#ifdef _WIN32 155#ifdef _WIN32
169#pragma comment(lib, "psapi") 156#pragma comment(lib, "psapi")
170 DWORD processID = GetCurrentProcessId(); 157 DWORD processID = GetCurrentProcessId();
@@ -175,10 +162,12 @@ std::string MemUsage()
175 // Print information about the memory usage of the process. 162 // Print information about the memory usage of the process.
176 163
177 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); 164 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
178 if (nullptr == hProcess) return "MemUsage Error"; 165 if (nullptr == hProcess)
166 return "MemUsage Error";
179 167
180 if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) 168 if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
181 Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); 169 Ret = Common::StringFromFormat(
170 "%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
182 171
183 CloseHandle(hProcess); 172 CloseHandle(hProcess);
184 return Ret; 173 return Ret;
diff --git a/src/common/memory_util.h b/src/common/memory_util.h
index 9bf37c44f..76ca5a30c 100644
--- a/src/common/memory_util.h
+++ b/src/common/memory_util.h
@@ -10,10 +10,12 @@
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..7be2235b0 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstddef> 5#include <cstddef>
6
7#ifdef _WIN32 6#ifdef _WIN32
8#include <windows.h> 7#include <windows.h>
9#else 8#else
@@ -12,23 +11,21 @@
12#endif 11#endif
13 12
14// Neither Android nor OS X support TLS 13// Neither Android nor OS X support TLS
15#if defined(__APPLE__) || (ANDROID && __clang__) 14#if defined(__APPLE__) || (ANDROID && __clang__)
16#define __thread 15#define __thread
17#endif 16#endif
18 17
19// Generic function to get last error message. 18// Generic function to get last error message.
20// Call directly after the command or use the error num. 19// Call directly after the command or use the error num.
21// This function might change the error code. 20// This function might change the error code.
22const char* GetLastErrorMsg() 21const char* GetLastErrorMsg() {
23{
24 static const size_t buff_size = 255; 22 static const size_t buff_size = 255;
25 23
26#ifdef _WIN32 24#ifdef _WIN32
27 static __declspec(thread) char err_str[buff_size] = {}; 25 static __declspec(thread) char err_str[buff_size] = {};
28 26
29 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 27 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
30 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 28 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr);
31 err_str, buff_size, nullptr);
32#else 29#else
33 static __thread char err_str[buff_size] = {}; 30 static __thread char err_str[buff_size] = {};
34 31
diff --git a/src/common/platform.h b/src/common/platform.h
index 9ba4db11b..c62fb7c8f 100644
--- a/src/common/platform.h
+++ b/src/common/platform.h
@@ -28,7 +28,7 @@
28// Platform detection 28// Platform detection
29 29
30#if defined(ARCHITECTURE_x86_64) || defined(__aarch64__) 30#if defined(ARCHITECTURE_x86_64) || defined(__aarch64__)
31 #define EMU_ARCH_BITS 64 31#define EMU_ARCH_BITS 64
32#elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) 32#elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM)
33 #define EMU_ARCH_BITS 32 33#define EMU_ARCH_BITS 32
34#endif 34#endif
diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp
index 49eb3f40c..b40e7205d 100644
--- a/src/common/profiler.cpp
+++ b/src/common/profiler.cpp
@@ -5,7 +5,6 @@
5#include <algorithm> 5#include <algorithm>
6#include <cstddef> 6#include <cstddef>
7#include <vector> 7#include <vector>
8
9#include "common/assert.h" 8#include "common/assert.h"
10#include "common/profiler_reporting.h" 9#include "common/profiler_reporting.h"
11#include "common/synchronized_wrapper.h" 10#include "common/synchronized_wrapper.h"
@@ -14,8 +13,7 @@ namespace Common {
14namespace Profiling { 13namespace Profiling {
15 14
16ProfilingManager::ProfilingManager() 15ProfilingManager::ProfilingManager()
17 : last_frame_end(Clock::now()), this_frame_start(Clock::now()) { 16 : last_frame_end(Clock::now()), this_frame_start(Clock::now()) {}
18}
19 17
20void ProfilingManager::BeginFrame() { 18void ProfilingManager::BeginFrame() {
21 this_frame_start = Clock::now(); 19 this_frame_start = Clock::now();
@@ -31,7 +29,7 @@ void ProfilingManager::FinishFrame() {
31} 29}
32 30
33TimingResultsAggregator::TimingResultsAggregator(size_t window_size) 31TimingResultsAggregator::TimingResultsAggregator(size_t window_size)
34 : max_window_size(window_size), window_size(0) { 32 : max_window_size(window_size), window_size(0) {
35 interframe_times.resize(window_size, Duration::zero()); 33 interframe_times.resize(window_size, Duration::zero());
36 frame_times.resize(window_size, Duration::zero()); 34 frame_times.resize(window_size, Duration::zero());
37} 35}
diff --git a/src/common/profiler_reporting.h b/src/common/profiler_reporting.h
index fa1ac883f..e9ce6d41c 100644
--- a/src/common/profiler_reporting.h
+++ b/src/common/profiler_reporting.h
@@ -7,7 +7,6 @@
7#include <chrono> 7#include <chrono>
8#include <cstddef> 8#include <cstddef>
9#include <vector> 9#include <vector>
10
11#include "common/synchronized_wrapper.h" 10#include "common/synchronized_wrapper.h"
12 11
13namespace Common { 12namespace Common {
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h
index 08f09a8c8..072ab285d 100644
--- a/src/common/scope_exit.h
+++ b/src/common/scope_exit.h
@@ -4,20 +4,24 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_funcs.h"
8#include <utility> 7#include <utility>
8#include "common/common_funcs.h"
9 9
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 ~ScopeExitHelper() {
15 func();
16 }
15 17
16 Func func; 18 Func func;
17 }; 19};
18 20
19 template <typename Func> 21template <typename Func>
20 ScopeExitHelper<Func> ScopeExit(Func&& func) { return ScopeExitHelper<Func>(std::move(func)); } 22ScopeExitHelper<Func> ScopeExit(Func&& func) {
23 return ScopeExitHelper<Func>(std::move(func));
24}
21} 25}
22 26
23/** 27/**
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index f0aa072db..596ae01bf 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -8,17 +8,15 @@
8#include <cstdlib> 8#include <cstdlib>
9#include <cstring> 9#include <cstring>
10#include <boost/range/algorithm/transform.hpp> 10#include <boost/range/algorithm/transform.hpp>
11
12#include "common/common_paths.h" 11#include "common/common_paths.h"
13#include "common/logging/log.h" 12#include "common/logging/log.h"
14#include "common/string_util.h" 13#include "common/string_util.h"
15
16#ifdef _MSC_VER 14#ifdef _MSC_VER
17 #include <Windows.h> 15#include <codecvt>
18 #include <codecvt> 16#include <Windows.h>
19 #include "common/common_funcs.h" 17#include "common/common_funcs.h"
20#else 18#else
21 #include <iconv.h> 19#include <iconv.h>
22#endif 20#endif
23 21
24namespace Common { 22namespace Common {
@@ -36,9 +34,8 @@ std::string ToUpper(std::string str) {
36} 34}
37 35
38// faster than sscanf 36// faster than sscanf
39bool AsciiToHex(const char* _szValue, u32& result) 37bool AsciiToHex(const char* _szValue, u32& result) {
40{ 38 char* endptr = nullptr;
41 char *endptr = nullptr;
42 const u32 value = strtoul(_szValue, &endptr, 16); 39 const u32 value = strtoul(_szValue, &endptr, 16);
43 40
44 if (!endptr || *endptr) 41 if (!endptr || *endptr)
@@ -48,8 +45,7 @@ bool AsciiToHex(const char* _szValue, u32& result)
48 return true; 45 return true;
49} 46}
50 47
51bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) 48bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) {
52{
53 int writtenCount; 49 int writtenCount;
54 50
55#ifdef _MSC_VER 51#ifdef _MSC_VER
@@ -84,22 +80,18 @@ bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list ar
84 writtenCount = vsnprintf(out, outsize, format, args); 80 writtenCount = vsnprintf(out, outsize, format, args);
85#endif 81#endif
86 82
87 if (writtenCount > 0 && writtenCount < outsize) 83 if (writtenCount > 0 && writtenCount < outsize) {
88 {
89 out[writtenCount] = '\0'; 84 out[writtenCount] = '\0';
90 return true; 85 return true;
91 } 86 } else {
92 else
93 {
94 out[outsize - 1] = '\0'; 87 out[outsize - 1] = '\0';
95 return false; 88 return false;
96 } 89 }
97} 90}
98 91
99std::string StringFromFormat(const char* format, ...) 92std::string StringFromFormat(const char* format, ...) {
100{
101 va_list args; 93 va_list args;
102 char *buf = nullptr; 94 char* buf = nullptr;
103#ifdef _WIN32 95#ifdef _WIN32
104 int required = 0; 96 int required = 0;
105 97
@@ -124,21 +116,17 @@ std::string StringFromFormat(const char* format, ...)
124} 116}
125 117
126// For Debugging. Read out an u8 array. 118// For Debugging. Read out an u8 array.
127std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) 119std::string ArrayToString(const u8* data, u32 size, int line_len, bool spaces) {
128{
129 std::ostringstream oss; 120 std::ostringstream oss;
130 oss << std::setfill('0') << std::hex; 121 oss << std::setfill('0') << std::hex;
131 122
132 for (int line = 0; size; ++data, --size) 123 for (int line = 0; size; ++data, --size) {
133 {
134 oss << std::setw(2) << (int)*data; 124 oss << std::setw(2) << (int)*data;
135 125
136 if (line_len == ++line) 126 if (line_len == ++line) {
137 {
138 oss << '\n'; 127 oss << '\n';
139 line = 0; 128 line = 0;
140 } 129 } else if (spaces)
141 else if (spaces)
142 oss << ' '; 130 oss << ' ';
143 } 131 }
144 132
@@ -146,8 +134,7 @@ std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces)
146} 134}
147 135
148// Turns " hej " into "hej". Also handles tabs. 136// Turns " hej " into "hej". Also handles tabs.
149std::string StripSpaces(const std::string &str) 137std::string StripSpaces(const std::string& str) {
150{
151 const size_t s = str.find_first_not_of(" \t\r\n"); 138 const size_t s = str.find_first_not_of(" \t\r\n");
152 139
153 if (str.npos != s) 140 if (str.npos != s)
@@ -159,17 +146,15 @@ std::string StripSpaces(const std::string &str)
159// "\"hello\"" is turned to "hello" 146// "\"hello\"" is turned to "hello"
160// This one assumes that the string has already been space stripped in both 147// This one assumes that the string has already been space stripped in both
161// ends, as done by StripSpaces above, for example. 148// ends, as done by StripSpaces above, for example.
162std::string StripQuotes(const std::string& s) 149std::string StripQuotes(const std::string& s) {
163{
164 if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) 150 if (s.size() && '\"' == s[0] && '\"' == *s.rbegin())
165 return s.substr(1, s.size() - 2); 151 return s.substr(1, s.size() - 2);
166 else 152 else
167 return s; 153 return s;
168} 154}
169 155
170bool TryParse(const std::string &str, u32 *const output) 156bool TryParse(const std::string& str, u32* const output) {
171{ 157 char* endptr = nullptr;
172 char *endptr = nullptr;
173 158
174 // Reset errno to a value other than ERANGE 159 // Reset errno to a value other than ERANGE
175 errno = 0; 160 errno = 0;
@@ -183,8 +168,7 @@ bool TryParse(const std::string &str, u32 *const output)
183 return false; 168 return false;
184 169
185#if ULONG_MAX > UINT_MAX 170#if ULONG_MAX > UINT_MAX
186 if (value >= 0x100000000ull 171 if (value >= 0x100000000ull && value <= 0xFFFFFFFF00000000ull)
187 && value <= 0xFFFFFFFF00000000ull)
188 return false; 172 return false;
189#endif 173#endif
190 174
@@ -192,8 +176,7 @@ bool TryParse(const std::string &str, u32 *const output)
192 return true; 176 return true;
193} 177}
194 178
195bool TryParse(const std::string &str, bool *const output) 179bool TryParse(const std::string& str, bool* const output) {
196{
197 if ("1" == str || "true" == ToLower(str)) 180 if ("1" == str || "true" == ToLower(str))
198 *output = true; 181 *output = true;
199 else if ("0" == str || "false" == ToLower(str)) 182 else if ("0" == str || "false" == ToLower(str))
@@ -204,22 +187,21 @@ bool TryParse(const std::string &str, bool *const output)
204 return true; 187 return true;
205} 188}
206 189
207std::string StringFromBool(bool value) 190std::string StringFromBool(bool value) {
208{
209 return value ? "True" : "False"; 191 return value ? "True" : "False";
210} 192}
211 193
212bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) 194bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
213{ 195 std::string* _pExtension) {
214 if (full_path.empty()) 196 if (full_path.empty())
215 return false; 197 return false;
216 198
217 size_t dir_end = full_path.find_last_of("/" 199 size_t dir_end = full_path.find_last_of("/"
218 // windows needs the : included for something like just "C:" to be considered a directory 200// windows needs the : included for something like just "C:" to be considered a directory
219#ifdef _WIN32 201#ifdef _WIN32
220 ":" 202 ":"
221#endif 203#endif
222 ); 204 );
223 if (std::string::npos == dir_end) 205 if (std::string::npos == dir_end)
224 dir_end = 0; 206 dir_end = 0;
225 else 207 else
@@ -241,8 +223,8 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
241 return true; 223 return true;
242} 224}
243 225
244void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename) 226void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
245{ 227 const std::string& _Filename) {
246 _CompleteFilename = _Path; 228 _CompleteFilename = _Path;
247 229
248 // check for seperator 230 // check for seperator
@@ -253,8 +235,7 @@ void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _P
253 _CompleteFilename += _Filename; 235 _CompleteFilename += _Filename;
254} 236}
255 237
256void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) 238void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) {
257{
258 std::istringstream iss(str); 239 std::istringstream iss(str);
259 output.resize(1); 240 output.resize(1);
260 241
@@ -264,8 +245,7 @@ void SplitString(const std::string& str, const char delim, std::vector<std::stri
264 output.pop_back(); 245 output.pop_back();
265} 246}
266 247
267std::string TabsToSpaces(int tab_size, const std::string &in) 248std::string TabsToSpaces(int tab_size, const std::string& in) {
268{
269 const std::string spaces(tab_size, ' '); 249 const std::string spaces(tab_size, ' ');
270 std::string out(in); 250 std::string out(in);
271 251
@@ -276,15 +256,13 @@ std::string TabsToSpaces(int tab_size, const std::string &in)
276 return out; 256 return out;
277} 257}
278 258
279std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) 259std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) {
280{
281 size_t pos = 0; 260 size_t pos = 0;
282 261
283 if (src == dest) 262 if (src == dest)
284 return result; 263 return result;
285 264
286 while ((pos = result.find(src, pos)) != std::string::npos) 265 while ((pos = result.find(src, pos)) != std::string::npos) {
287 {
288 result.replace(pos, src.size(), dest); 266 result.replace(pos, src.size(), dest);
289 pos += dest.length(); 267 pos += dest.length();
290 } 268 }
@@ -294,8 +272,7 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
294 272
295#ifdef _MSC_VER 273#ifdef _MSC_VER
296 274
297std::string UTF16ToUTF8(const std::u16string& input) 275std::string UTF16ToUTF8(const std::u16string& input) {
298{
299#if _MSC_VER >= 1900 276#if _MSC_VER >= 1900
300 // Workaround for missing char16_t/char32_t instantiations in MSVC2015 277 // Workaround for missing char16_t/char32_t instantiations in MSVC2015
301 std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; 278 std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
@@ -307,8 +284,7 @@ std::string UTF16ToUTF8(const std::u16string& input)
307#endif 284#endif
308} 285}
309 286
310std::u16string UTF8ToUTF16(const std::string& input) 287std::u16string UTF8ToUTF16(const std::string& input) {
311{
312#if _MSC_VER >= 1900 288#if _MSC_VER >= 1900
313 // Workaround for missing char16_t/char32_t instantiations in MSVC2015 289 // Workaround for missing char16_t/char32_t instantiations in MSVC2015
314 std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert; 290 std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
@@ -320,57 +296,56 @@ std::u16string UTF8ToUTF16(const std::string& input)
320#endif 296#endif
321} 297}
322 298
323static std::wstring CPToUTF16(u32 code_page, const std::string& input) 299static std::wstring CPToUTF16(u32 code_page, const std::string& input) {
324{ 300 auto const size =
325 auto const size = MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0); 301 MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);
326 302
327 std::wstring output; 303 std::wstring output;
328 output.resize(size); 304 output.resize(size);
329 305
330 if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()))) 306 if (size == 0 ||
307 size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()),
308 &output[0], static_cast<int>(output.size())))
331 output.clear(); 309 output.clear();
332 310
333 return output; 311 return output;
334} 312}
335 313
336std::string UTF16ToUTF8(const std::wstring& input) 314std::string UTF16ToUTF8(const std::wstring& input) {
337{ 315 auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()),
338 auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), nullptr, 0, nullptr, nullptr); 316 nullptr, 0, nullptr, nullptr);
339 317
340 std::string output; 318 std::string output;
341 output.resize(size); 319 output.resize(size);
342 320
343 if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()), nullptr, nullptr)) 321 if (size == 0 ||
322 size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()),
323 &output[0], static_cast<int>(output.size()), nullptr, nullptr))
344 output.clear(); 324 output.clear();
345 325
346 return output; 326 return output;
347} 327}
348 328
349std::wstring UTF8ToUTF16W(const std::string &input) 329std::wstring UTF8ToUTF16W(const std::string& input) {
350{
351 return CPToUTF16(CP_UTF8, input); 330 return CPToUTF16(CP_UTF8, input);
352} 331}
353 332
354std::string SHIFTJISToUTF8(const std::string& input) 333std::string SHIFTJISToUTF8(const std::string& input) {
355{
356 return UTF16ToUTF8(CPToUTF16(932, input)); 334 return UTF16ToUTF8(CPToUTF16(932, input));
357} 335}
358 336
359std::string CP1252ToUTF8(const std::string& input) 337std::string CP1252ToUTF8(const std::string& input) {
360{
361 return UTF16ToUTF8(CPToUTF16(1252, input)); 338 return UTF16ToUTF8(CPToUTF16(1252, input));
362} 339}
363 340
364#else 341#else
365 342
366template <typename T> 343template <typename T>
367static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) 344static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) {
368{
369 std::string result; 345 std::string result;
370 346
371 iconv_t const conv_desc = iconv_open("UTF-8", fromcode); 347 iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
372 if ((iconv_t)(-1) == conv_desc) 348 if ((iconv_t)(-1) == conv_desc) {
373 {
374 LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); 349 LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
375 iconv_close(conv_desc); 350 iconv_close(conv_desc);
376 return {}; 351 return {};
@@ -388,24 +363,18 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
388 auto dst_buffer = &out_buffer[0]; 363 auto dst_buffer = &out_buffer[0];
389 size_t dst_bytes = out_buffer.size(); 364 size_t dst_bytes = out_buffer.size();
390 365
391 while (0 != src_bytes) 366 while (0 != src_bytes) {
392 { 367 size_t const iconv_result =
393 size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, 368 iconv(conv_desc, (char**)(&src_buffer), &src_bytes, &dst_buffer, &dst_bytes);
394 &dst_buffer, &dst_bytes);
395 369
396 if (static_cast<size_t>(-1) == iconv_result) 370 if (static_cast<size_t>(-1) == iconv_result) {
397 { 371 if (EILSEQ == errno || EINVAL == errno) {
398 if (EILSEQ == errno || EINVAL == errno)
399 {
400 // Try to skip the bad character 372 // Try to skip the bad character
401 if (0 != src_bytes) 373 if (0 != src_bytes) {
402 {
403 --src_bytes; 374 --src_bytes;
404 ++src_buffer; 375 ++src_buffer;
405 } 376 }
406 } 377 } else {
407 else
408 {
409 LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno)); 378 LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno));
410 break; 379 break;
411 } 380 }
@@ -420,13 +389,11 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
420 return result; 389 return result;
421} 390}
422 391
423std::u16string UTF8ToUTF16(const std::string& input) 392std::u16string UTF8ToUTF16(const std::string& input) {
424{
425 std::u16string result; 393 std::u16string result;
426 394
427 iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8"); 395 iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8");
428 if ((iconv_t)(-1) == conv_desc) 396 if ((iconv_t)(-1) == conv_desc) {
429 {
430 LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno)); 397 LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno));
431 iconv_close(conv_desc); 398 iconv_close(conv_desc);
432 return {}; 399 return {};
@@ -444,24 +411,18 @@ std::u16string UTF8ToUTF16(const std::string& input)
444 char* dst_buffer = (char*)(&out_buffer[0]); 411 char* dst_buffer = (char*)(&out_buffer[0]);
445 size_t dst_bytes = out_buffer.size(); 412 size_t dst_bytes = out_buffer.size();
446 413
447 while (0 != src_bytes) 414 while (0 != src_bytes) {
448 { 415 size_t const iconv_result =
449 size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes, 416 iconv(conv_desc, &src_buffer, &src_bytes, &dst_buffer, &dst_bytes);
450 &dst_buffer, &dst_bytes);
451 417
452 if (static_cast<size_t>(-1) == iconv_result) 418 if (static_cast<size_t>(-1) == iconv_result) {
453 { 419 if (EILSEQ == errno || EINVAL == errno) {
454 if (EILSEQ == errno || EINVAL == errno)
455 {
456 // Try to skip the bad character 420 // Try to skip the bad character
457 if (0 != src_bytes) 421 if (0 != src_bytes) {
458 {
459 --src_bytes; 422 --src_bytes;
460 ++src_buffer; 423 ++src_buffer;
461 } 424 }
462 } 425 } else {
463 else
464 {
465 LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno)); 426 LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno));
466 break; 427 break;
467 } 428 }
@@ -476,32 +437,28 @@ std::u16string UTF8ToUTF16(const std::string& input)
476 return result; 437 return result;
477} 438}
478 439
479std::string UTF16ToUTF8(const std::u16string& input) 440std::string UTF16ToUTF8(const std::u16string& input) {
480{
481 return CodeToUTF8("UTF-16LE", input); 441 return CodeToUTF8("UTF-16LE", input);
482} 442}
483 443
484std::string CP1252ToUTF8(const std::string& input) 444std::string CP1252ToUTF8(const std::string& input) {
485{ 445 // return CodeToUTF8("CP1252//TRANSLIT", input);
486 //return CodeToUTF8("CP1252//TRANSLIT", input); 446 // return CodeToUTF8("CP1252//IGNORE", input);
487 //return CodeToUTF8("CP1252//IGNORE", input);
488 return CodeToUTF8("CP1252", input); 447 return CodeToUTF8("CP1252", input);
489} 448}
490 449
491std::string SHIFTJISToUTF8(const std::string& input) 450std::string SHIFTJISToUTF8(const std::string& input) {
492{ 451 // return CodeToUTF8("CP932", input);
493 //return CodeToUTF8("CP932", input);
494 return CodeToUTF8("SJIS", input); 452 return CodeToUTF8("SJIS", input);
495} 453}
496 454
497#endif 455#endif
498 456
499std::string StringFromFixedZeroTerminatedBuffer(const char * buffer, size_t max_len) { 457std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len) {
500 size_t len = 0; 458 size_t len = 0;
501 while (len < max_len && buffer[len] != '\0') 459 while (len < max_len && buffer[len] != '\0')
502 ++len; 460 ++len;
503 461
504 return std::string(buffer, len); 462 return std::string(buffer, len);
505} 463}
506
507} 464}
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 89d9f133e..075bf4ecb 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -10,7 +10,6 @@
10#include <sstream> 10#include <sstream>
11#include <string> 11#include <string>
12#include <vector> 12#include <vector>
13
14#include "common/common_types.h" 13#include "common/common_types.h"
15 14
16namespace Common { 15namespace Common {
@@ -25,9 +24,8 @@ std::string StringFromFormat(const char* format, ...);
25// Cheap! 24// Cheap!
26bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); 25bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args);
27 26
28template<size_t Count> 27template <size_t Count>
29inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) 28inline void CharArrayFromFormat(char (&out)[Count], const char* format, ...) {
30{
31 va_list args; 29 va_list args;
32 va_start(args, format); 30 va_start(args, format);
33 CharArrayFromFormatV(out, Count, format, args); 31 CharArrayFromFormatV(out, Count, format, args);
@@ -35,15 +33,14 @@ inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...)
35} 33}
36 34
37// Good 35// Good
38std::string ArrayToString(const u8 *data, u32 size, int line_len = 20, bool spaces = true); 36std::string ArrayToString(const u8* data, u32 size, int line_len = 20, bool spaces = true);
39 37
40std::string StripSpaces(const std::string &s); 38std::string StripSpaces(const std::string& s);
41std::string StripQuotes(const std::string &s); 39std::string StripQuotes(const std::string& s);
42 40
43// Thousand separator. Turns 12345678 into 12,345,678 41// Thousand separator. Turns 12345678 into 12,345,678
44template <typename I> 42template <typename I>
45std::string ThousandSeparate(I value, int spaces = 0) 43std::string ThousandSeparate(I value, int spaces = 0) {
46{
47 std::ostringstream oss; 44 std::ostringstream oss;
48 45
49// std::locale("") seems to be broken on many platforms 46// std::locale("") seems to be broken on many platforms
@@ -57,35 +54,34 @@ std::string ThousandSeparate(I value, int spaces = 0)
57 54
58std::string StringFromBool(bool value); 55std::string StringFromBool(bool value);
59 56
60bool TryParse(const std::string &str, bool *output); 57bool TryParse(const std::string& str, bool* output);
61bool TryParse(const std::string &str, u32 *output); 58bool TryParse(const std::string& str, u32* output);
62 59
63template <typename N> 60template <typename N>
64static bool TryParse(const std::string &str, N *const output) 61static bool TryParse(const std::string& str, N* const output) {
65{
66 std::istringstream iss(str); 62 std::istringstream iss(str);
67 63
68 N tmp = 0; 64 N tmp = 0;
69 if (iss >> tmp) 65 if (iss >> tmp) {
70 {
71 *output = tmp; 66 *output = tmp;
72 return true; 67 return true;
73 } 68 } else
74 else
75 return false; 69 return false;
76} 70}
77 71
78// TODO: kill this 72// TODO: kill this
79bool AsciiToHex(const char* _szValue, u32& result); 73bool AsciiToHex(const char* _szValue, u32& result);
80 74
81std::string TabsToSpaces(int tab_size, const std::string &in); 75std::string TabsToSpaces(int tab_size, const std::string& in);
82 76
83void SplitString(const std::string& str, char delim, std::vector<std::string>& output); 77void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
84 78
85// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" 79// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe"
86bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); 80bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
81 std::string* _pExtension);
87 82
88void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename); 83void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
84 const std::string& _Filename);
89std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); 85std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest);
90 86
91std::string UTF16ToUTF8(const std::u16string& input); 87std::string UTF16ToUTF8(const std::u16string& input);
@@ -99,17 +95,21 @@ std::string UTF16ToUTF8(const std::wstring& input);
99std::wstring UTF8ToUTF16W(const std::string& str); 95std::wstring UTF8ToUTF16W(const std::string& str);
100 96
101#ifdef _UNICODE 97#ifdef _UNICODE
102inline std::string TStrToUTF8(const std::wstring& str) 98inline std::string TStrToUTF8(const std::wstring& str) {
103{ return UTF16ToUTF8(str); } 99 return UTF16ToUTF8(str);
100}
104 101
105inline std::wstring UTF8ToTStr(const std::string& str) 102inline std::wstring UTF8ToTStr(const std::string& str) {
106{ return UTF8ToUTF16W(str); } 103 return UTF8ToUTF16W(str);
104}
107#else 105#else
108inline std::string TStrToUTF8(const std::string& str) 106inline std::string TStrToUTF8(const std::string& str) {
109{ return str; } 107 return str;
108}
110 109
111inline std::string UTF8ToTStr(const std::string& str) 110inline std::string UTF8ToTStr(const std::string& str) {
112{ return str; } 111 return str;
112}
113#endif 113#endif
114 114
115#endif 115#endif
@@ -134,5 +134,4 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
134 * NUL-terminated then the string ends at max_len characters. 134 * NUL-terminated then the string ends at max_len characters.
135 */ 135 */
136std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len); 136std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len);
137
138} 137}
diff --git a/src/common/swap.h b/src/common/swap.h
index 1749bd7a4..e241c9f73 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -18,15 +18,13 @@
18#pragma once 18#pragma once
19 19
20#if defined(_MSC_VER) 20#if defined(_MSC_VER)
21 #include <cstdlib> 21#include <cstdlib>
22#elif defined(__linux__) 22#elif defined(__linux__)
23 #include <byteswap.h> 23#include <byteswap.h>
24#elif defined(__FreeBSD__) 24#elif defined(__FreeBSD__)
25 #include <sys/endian.h> 25#include <sys/endian.h>
26#endif 26#endif
27
28#include <cstring> 27#include <cstring>
29
30#include "common/common_types.h" 28#include "common/common_types.h"
31 29
32// GCC 4.6+ 30// GCC 4.6+
@@ -61,38 +59,73 @@
61namespace Common { 59namespace Common {
62 60
63#ifdef _MSC_VER 61#ifdef _MSC_VER
64inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} 62inline u16 swap16(u16 _data) {
65inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} 63 return _byteswap_ushort(_data);
66inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} 64}
65inline u32 swap32(u32 _data) {
66 return _byteswap_ulong(_data);
67}
68inline u64 swap64(u64 _data) {
69 return _byteswap_uint64(_data);
70}
67#elif _M_ARM 71#elif _M_ARM
68inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} 72inline u16 swap16(u16 _data) {
69inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} 73 u32 data = _data;
70inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} 74 __asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data));
75 return (u16)data;
76}
77inline u32 swap32(u32 _data) {
78 __asm__("rev %0, %1\n" : "=l"(_data) : "l"(_data));
79 return _data;
80}
81inline u64 swap64(u64 _data) {
82 return ((u64)swap32(_data) << 32) | swap32(_data >> 32);
83}
71#elif __linux__ 84#elif __linux__
72inline u16 swap16(u16 _data) {return bswap_16(_data);} 85inline u16 swap16(u16 _data) {
73inline u32 swap32(u32 _data) {return bswap_32(_data);} 86 return bswap_16(_data);
74inline u64 swap64(u64 _data) {return bswap_64(_data);} 87}
88inline u32 swap32(u32 _data) {
89 return bswap_32(_data);
90}
91inline u64 swap64(u64 _data) {
92 return bswap_64(_data);
93}
75#elif __APPLE__ 94#elif __APPLE__
76inline __attribute__((always_inline)) u16 swap16(u16 _data) 95inline __attribute__((always_inline)) u16 swap16(u16 _data) {
77{return (_data >> 8) | (_data << 8);} 96 return (_data >> 8) | (_data << 8);
78inline __attribute__((always_inline)) u32 swap32(u32 _data) 97}
79{return __builtin_bswap32(_data);} 98inline __attribute__((always_inline)) u32 swap32(u32 _data) {
80inline __attribute__((always_inline)) u64 swap64(u64 _data) 99 return __builtin_bswap32(_data);
81{return __builtin_bswap64(_data);} 100}
101inline __attribute__((always_inline)) u64 swap64(u64 _data) {
102 return __builtin_bswap64(_data);
103}
82#elif __FreeBSD__ 104#elif __FreeBSD__
83inline u16 swap16(u16 _data) {return bswap16(_data);} 105inline u16 swap16(u16 _data) {
84inline u32 swap32(u32 _data) {return bswap32(_data);} 106 return bswap16(_data);
85inline u64 swap64(u64 _data) {return bswap64(_data);} 107}
108inline u32 swap32(u32 _data) {
109 return bswap32(_data);
110}
111inline u64 swap64(u64 _data) {
112 return bswap64(_data);
113}
86#else 114#else
87// Slow generic implementation. 115// Slow generic implementation.
88inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} 116inline u16 swap16(u16 data) {
89inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} 117 return (data >> 8) | (data << 8);
90inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} 118}
119inline u32 swap32(u32 data) {
120 return (swap16(data) << 16) | swap16(data >> 16);
121}
122inline u64 swap64(u64 data) {
123 return ((u64)swap32(data) << 32) | swap32(data >> 32);
124}
91#endif 125#endif
92 126
93inline float swapf(float f) { 127inline float swapf(float f) {
94 static_assert(sizeof(u32) == sizeof(float), 128 static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t.");
95 "float must be the same size as uint32_t.");
96 129
97 u32 value; 130 u32 value;
98 std::memcpy(&value, &f, sizeof(u32)); 131 std::memcpy(&value, &f, sizeof(u32));
@@ -104,8 +137,7 @@ inline float swapf(float f) {
104} 137}
105 138
106inline double swapd(double f) { 139inline double swapd(double f) {
107 static_assert(sizeof(u64) == sizeof(double), 140 static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t.");
108 "double must be the same size as uint64_t.");
109 141
110 u64 value; 142 u64 value;
111 std::memcpy(&value, &f, sizeof(u64)); 143 std::memcpy(&value, &f, sizeof(u64));
@@ -116,8 +148,7 @@ inline double swapd(double f) {
116 return f; 148 return f;
117} 149}
118 150
119} // Namespace Common 151} // Namespace Common
120
121 152
122template <typename T, typename F> 153template <typename T, typename F>
123struct swap_struct_t { 154struct swap_struct_t {
@@ -129,251 +160,271 @@ protected:
129 static T swap(T v) { 160 static T swap(T v) {
130 return F::swap(v); 161 return F::swap(v);
131 } 162 }
163
132public: 164public:
133 T const swap() const { 165 T const swap() const {
134 return swap(value); 166 return swap(value);
135
136 } 167 }
137 swap_struct_t() = default; 168 swap_struct_t() = default;
138 swap_struct_t(const T &v): value(swap(v)) {} 169 swap_struct_t(const T& v) : value(swap(v)) {}
139 170
140 template <typename S> 171 template <typename S>
141 swapped_t& operator=(const S &source) { 172 swapped_t& operator=(const S& source) {
142 value = swap((T)source); 173 value = swap((T)source);
143 return *this; 174 return *this;
144 } 175 }
145 176
146 operator s8() const { return (s8)swap(); } 177 operator s8() const {
147 operator u8() const { return (u8)swap(); } 178 return (s8)swap();
148 operator s16() const { return (s16)swap(); } 179 }
149 operator u16() const { return (u16)swap(); } 180 operator u8() const {
150 operator s32() const { return (s32)swap(); } 181 return (u8)swap();
151 operator u32() const { return (u32)swap(); } 182 }
152 operator s64() const { return (s64)swap(); } 183 operator s16() const {
153 operator u64() const { return (u64)swap(); } 184 return (s16)swap();
154 operator float() const { return (float)swap(); } 185 }
155 operator double() const { return (double)swap(); } 186 operator u16() const {
187 return (u16)swap();
188 }
189 operator s32() const {
190 return (s32)swap();
191 }
192 operator u32() const {
193 return (u32)swap();
194 }
195 operator s64() const {
196 return (s64)swap();
197 }
198 operator u64() const {
199 return (u64)swap();
200 }
201 operator float() const {
202 return (float)swap();
203 }
204 operator double() const {
205 return (double)swap();
206 }
156 207
157 // +v 208 // +v
158 swapped_t operator +() const { 209 swapped_t operator+() const {
159 return +swap(); 210 return +swap();
160 } 211 }
161 // -v 212 // -v
162 swapped_t operator -() const { 213 swapped_t operator-() const {
163 return -swap(); 214 return -swap();
164 } 215 }
165 216
166 // v / 5 217 // v / 5
167 swapped_t operator/(const swapped_t &i) const { 218 swapped_t operator/(const swapped_t& i) const {
168 return swap() / i.swap(); 219 return swap() / i.swap();
169 } 220 }
170 template <typename S> 221 template <typename S>
171 swapped_t operator/(const S &i) const { 222 swapped_t operator/(const S& i) const {
172 return swap() / i; 223 return swap() / i;
173 } 224 }
174 225
175 // v * 5 226 // v * 5
176 swapped_t operator*(const swapped_t &i) const { 227 swapped_t operator*(const swapped_t& i) const {
177 return swap() * i.swap(); 228 return swap() * i.swap();
178 } 229 }
179 template <typename S> 230 template <typename S>
180 swapped_t operator*(const S &i) const { 231 swapped_t operator*(const S& i) const {
181 return swap() * i; 232 return swap() * i;
182 } 233 }
183 234
184 // v + 5 235 // v + 5
185 swapped_t operator+(const swapped_t &i) const { 236 swapped_t operator+(const swapped_t& i) const {
186 return swap() + i.swap(); 237 return swap() + i.swap();
187 } 238 }
188 template <typename S> 239 template <typename S>
189 swapped_t operator+(const S &i) const { 240 swapped_t operator+(const S& i) const {
190 return swap() + (T)i; 241 return swap() + (T)i;
191 } 242 }
192 // v - 5 243 // v - 5
193 swapped_t operator-(const swapped_t &i) const { 244 swapped_t operator-(const swapped_t& i) const {
194 return swap() - i.swap(); 245 return swap() - i.swap();
195 } 246 }
196 template <typename S> 247 template <typename S>
197 swapped_t operator-(const S &i) const { 248 swapped_t operator-(const S& i) const {
198 return swap() - (T)i; 249 return swap() - (T)i;
199 } 250 }
200 251
201 // v += 5 252 // v += 5
202 swapped_t& operator+=(const swapped_t &i) { 253 swapped_t& operator+=(const swapped_t& i) {
203 value = swap(swap() + i.swap()); 254 value = swap(swap() + i.swap());
204 return *this; 255 return *this;
205 } 256 }
206 template <typename S> 257 template <typename S>
207 swapped_t& operator+=(const S &i) { 258 swapped_t& operator+=(const S& i) {
208 value = swap(swap() + (T)i); 259 value = swap(swap() + (T)i);
209 return *this; 260 return *this;
210 } 261 }
211 // v -= 5 262 // v -= 5
212 swapped_t& operator-=(const swapped_t &i) { 263 swapped_t& operator-=(const swapped_t& i) {
213 value = swap(swap() - i.swap()); 264 value = swap(swap() - i.swap());
214 return *this; 265 return *this;
215 } 266 }
216 template <typename S> 267 template <typename S>
217 swapped_t& operator-=(const S &i) { 268 swapped_t& operator-=(const S& i) {
218 value = swap(swap() - (T)i); 269 value = swap(swap() - (T)i);
219 return *this; 270 return *this;
220 } 271 }
221 272
222 // ++v 273 // ++v
223 swapped_t& operator++() { 274 swapped_t& operator++() {
224 value = swap(swap()+1); 275 value = swap(swap() + 1);
225 return *this; 276 return *this;
226 } 277 }
227 // --v 278 // --v
228 swapped_t& operator--() { 279 swapped_t& operator--() {
229 value = swap(swap()-1); 280 value = swap(swap() - 1);
230 return *this; 281 return *this;
231 } 282 }
232 283
233 // v++ 284 // v++
234 swapped_t operator++(int) { 285 swapped_t operator++(int) {
235 swapped_t old = *this; 286 swapped_t old = *this;
236 value = swap(swap()+1); 287 value = swap(swap() + 1);
237 return old; 288 return old;
238 } 289 }
239 // v-- 290 // v--
240 swapped_t operator--(int) { 291 swapped_t operator--(int) {
241 swapped_t old = *this; 292 swapped_t old = *this;
242 value = swap(swap()-1); 293 value = swap(swap() - 1);
243 return old; 294 return old;
244 } 295 }
245 // Comparaison 296 // Comparaison
246 // v == i 297 // v == i
247 bool operator==(const swapped_t &i) const { 298 bool operator==(const swapped_t& i) const {
248 return swap() == i.swap(); 299 return swap() == i.swap();
249 } 300 }
250 template <typename S> 301 template <typename S>
251 bool operator==(const S &i) const { 302 bool operator==(const S& i) const {
252 return swap() == i; 303 return swap() == i;
253 } 304 }
254 305
255 // v != i 306 // v != i
256 bool operator!=(const swapped_t &i) const { 307 bool operator!=(const swapped_t& i) const {
257 return swap() != i.swap(); 308 return swap() != i.swap();
258 } 309 }
259 template <typename S> 310 template <typename S>
260 bool operator!=(const S &i) const { 311 bool operator!=(const S& i) const {
261 return swap() != i; 312 return swap() != i;
262 } 313 }
263 314
264 // v > i 315 // v > i
265 bool operator>(const swapped_t &i) const { 316 bool operator>(const swapped_t& i) const {
266 return swap() > i.swap(); 317 return swap() > i.swap();
267 } 318 }
268 template <typename S> 319 template <typename S>
269 bool operator>(const S &i) const { 320 bool operator>(const S& i) const {
270 return swap() > i; 321 return swap() > i;
271 } 322 }
272 323
273 // v < i 324 // v < i
274 bool operator<(const swapped_t &i) const { 325 bool operator<(const swapped_t& i) const {
275 return swap() < i.swap(); 326 return swap() < i.swap();
276 } 327 }
277 template <typename S> 328 template <typename S>
278 bool operator<(const S &i) const { 329 bool operator<(const S& i) const {
279 return swap() < i; 330 return swap() < i;
280 } 331 }
281 332
282 // v >= i 333 // v >= i
283 bool operator>=(const swapped_t &i) const { 334 bool operator>=(const swapped_t& i) const {
284 return swap() >= i.swap(); 335 return swap() >= i.swap();
285 } 336 }
286 template <typename S> 337 template <typename S>
287 bool operator>=(const S &i) const { 338 bool operator>=(const S& i) const {
288 return swap() >= i; 339 return swap() >= i;
289 } 340 }
290 341
291 // v <= i 342 // v <= i
292 bool operator<=(const swapped_t &i) const { 343 bool operator<=(const swapped_t& i) const {
293 return swap() <= i.swap(); 344 return swap() <= i.swap();
294 } 345 }
295 template <typename S> 346 template <typename S>
296 bool operator<=(const S &i) const { 347 bool operator<=(const S& i) const {
297 return swap() <= i; 348 return swap() <= i;
298 } 349 }
299 350
300 // logical 351 // logical
301 swapped_t operator !() const { 352 swapped_t operator!() const {
302 return !swap(); 353 return !swap();
303 } 354 }
304 355
305 // bitmath 356 // bitmath
306 swapped_t operator ~() const { 357 swapped_t operator~() const {
307 return ~swap(); 358 return ~swap();
308 } 359 }
309 360
310 swapped_t operator &(const swapped_t &b) const { 361 swapped_t operator&(const swapped_t& b) const {
311 return swap() & b.swap(); 362 return swap() & b.swap();
312 } 363 }
313 template <typename S> 364 template <typename S>
314 swapped_t operator &(const S &b) const { 365 swapped_t operator&(const S& b) const {
315 return swap() & b; 366 return swap() & b;
316 } 367 }
317 swapped_t& operator &=(const swapped_t &b) { 368 swapped_t& operator&=(const swapped_t& b) {
318 value = swap(swap() & b.swap()); 369 value = swap(swap() & b.swap());
319 return *this; 370 return *this;
320 } 371 }
321 template <typename S> 372 template <typename S>
322 swapped_t& operator &=(const S b) { 373 swapped_t& operator&=(const S b) {
323 value = swap(swap() & b); 374 value = swap(swap() & b);
324 return *this; 375 return *this;
325 } 376 }
326 377
327 swapped_t operator |(const swapped_t &b) const { 378 swapped_t operator|(const swapped_t& b) const {
328 return swap() | b.swap(); 379 return swap() | b.swap();
329 } 380 }
330 template <typename S> 381 template <typename S>
331 swapped_t operator |(const S &b) const { 382 swapped_t operator|(const S& b) const {
332 return swap() | b; 383 return swap() | b;
333 } 384 }
334 swapped_t& operator |=(const swapped_t &b) { 385 swapped_t& operator|=(const swapped_t& b) {
335 value = swap(swap() | b.swap()); 386 value = swap(swap() | b.swap());
336 return *this; 387 return *this;
337 } 388 }
338 template <typename S> 389 template <typename S>
339 swapped_t& operator |=(const S &b) { 390 swapped_t& operator|=(const S& b) {
340 value = swap(swap() | b); 391 value = swap(swap() | b);
341 return *this; 392 return *this;
342 } 393 }
343 394
344 swapped_t operator ^(const swapped_t &b) const { 395 swapped_t operator^(const swapped_t& b) const {
345 return swap() ^ b.swap(); 396 return swap() ^ b.swap();
346 } 397 }
347 template <typename S> 398 template <typename S>
348 swapped_t operator ^(const S &b) const { 399 swapped_t operator^(const S& b) const {
349 return swap() ^ b; 400 return swap() ^ b;
350 } 401 }
351 swapped_t& operator ^=(const swapped_t &b) { 402 swapped_t& operator^=(const swapped_t& b) {
352 value = swap(swap() ^ b.swap()); 403 value = swap(swap() ^ b.swap());
353 return *this; 404 return *this;
354 } 405 }
355 template <typename S> 406 template <typename S>
356 swapped_t& operator ^=(const S &b) { 407 swapped_t& operator^=(const S& b) {
357 value = swap(swap() ^ b); 408 value = swap(swap() ^ b);
358 return *this; 409 return *this;
359 } 410 }
360 411
361 template <typename S> 412 template <typename S>
362 swapped_t operator <<(const S &b) const { 413 swapped_t operator<<(const S& b) const {
363 return swap() << b; 414 return swap() << b;
364 } 415 }
365 template <typename S> 416 template <typename S>
366 swapped_t& operator <<=(const S &b) const { 417 swapped_t& operator<<=(const S& b) const {
367 value = swap(swap() << b); 418 value = swap(swap() << b);
368 return *this; 419 return *this;
369 } 420 }
370 421
371 template <typename S> 422 template <typename S>
372 swapped_t operator >>(const S &b) const { 423 swapped_t operator>>(const S& b) const {
373 return swap() >> b; 424 return swap() >> b;
374 } 425 }
375 template <typename S> 426 template <typename S>
376 swapped_t& operator >>=(const S &b) const { 427 swapped_t& operator>>=(const S& b) const {
377 value = swap(swap() >> b); 428 value = swap(swap() >> b);
378 return *this; 429 return *this;
379 } 430 }
@@ -381,129 +432,126 @@ public:
381 // Member 432 // Member
382 /** todo **/ 433 /** todo **/
383 434
384
385 // Arithmetics 435 // Arithmetics
386 template <typename S, typename T2, typename F2> 436 template <typename S, typename T2, typename F2>
387 friend S operator+(const S &p, const swapped_t v); 437 friend S operator+(const S& p, const swapped_t v);
388 438
389 template <typename S, typename T2, typename F2> 439 template <typename S, typename T2, typename F2>
390 friend S operator-(const S &p, const swapped_t v); 440 friend S operator-(const S& p, const swapped_t v);
391 441
392 template <typename S, typename T2, typename F2> 442 template <typename S, typename T2, typename F2>
393 friend S operator/(const S &p, const swapped_t v); 443 friend S operator/(const S& p, const swapped_t v);
394 444
395 template <typename S, typename T2, typename F2> 445 template <typename S, typename T2, typename F2>
396 friend S operator*(const S &p, const swapped_t v); 446 friend S operator*(const S& p, const swapped_t v);
397 447
398 template <typename S, typename T2, typename F2> 448 template <typename S, typename T2, typename F2>
399 friend S operator%(const S &p, const swapped_t v); 449 friend S operator%(const S& p, const swapped_t v);
400 450
401 // Arithmetics + assignements 451 // Arithmetics + assignements
402 template <typename S, typename T2, typename F2> 452 template <typename S, typename T2, typename F2>
403 friend S operator+=(const S &p, const swapped_t v); 453 friend S operator+=(const S& p, const swapped_t v);
404 454
405 template <typename S, typename T2, typename F2> 455 template <typename S, typename T2, typename F2>
406 friend S operator-=(const S &p, const swapped_t v); 456 friend S operator-=(const S& p, const swapped_t v);
407 457
408 // Bitmath 458 // Bitmath
409 template <typename S, typename T2, typename F2> 459 template <typename S, typename T2, typename F2>
410 friend S operator&(const S &p, const swapped_t v); 460 friend S operator&(const S& p, const swapped_t v);
411 461
412 // Comparison 462 // Comparison
413 template <typename S, typename T2, typename F2> 463 template <typename S, typename T2, typename F2>
414 friend bool operator<(const S &p, const swapped_t v); 464 friend bool operator<(const S& p, const swapped_t v);
415 465
416 template <typename S, typename T2, typename F2> 466 template <typename S, typename T2, typename F2>
417 friend bool operator>(const S &p, const swapped_t v); 467 friend bool operator>(const S& p, const swapped_t v);
418 468
419 template <typename S, typename T2, typename F2> 469 template <typename S, typename T2, typename F2>
420 friend bool operator<=(const S &p, const swapped_t v); 470 friend bool operator<=(const S& p, const swapped_t v);
421 471
422 template <typename S, typename T2, typename F2> 472 template <typename S, typename T2, typename F2>
423 friend bool operator>=(const S &p, const swapped_t v); 473 friend bool operator>=(const S& p, const swapped_t v);
424 474
425 template <typename S, typename T2, typename F2> 475 template <typename S, typename T2, typename F2>
426 friend bool operator!=(const S &p, const swapped_t v); 476 friend bool operator!=(const S& p, const swapped_t v);
427 477
428 template <typename S, typename T2, typename F2> 478 template <typename S, typename T2, typename F2>
429 friend bool operator==(const S &p, const swapped_t v); 479 friend bool operator==(const S& p, const swapped_t v);
430}; 480};
431 481
432
433// Arithmetics 482// Arithmetics
434template <typename S, typename T, typename F> 483template <typename S, typename T, typename F>
435S operator+(const S &i, const swap_struct_t<T, F> v) { 484S operator+(const S& i, const swap_struct_t<T, F> v) {
436 return i + v.swap(); 485 return i + v.swap();
437} 486}
438 487
439template <typename S, typename T, typename F> 488template <typename S, typename T, typename F>
440S operator-(const S &i, const swap_struct_t<T, F> v) { 489S operator-(const S& i, const swap_struct_t<T, F> v) {
441 return i - v.swap(); 490 return i - v.swap();
442} 491}
443 492
444template <typename S, typename T, typename F> 493template <typename S, typename T, typename F>
445S operator/(const S &i, const swap_struct_t<T, F> v) { 494S operator/(const S& i, const swap_struct_t<T, F> v) {
446 return i / v.swap(); 495 return i / v.swap();
447} 496}
448 497
449template <typename S, typename T, typename F> 498template <typename S, typename T, typename F>
450S operator*(const S &i, const swap_struct_t<T, F> v) { 499S operator*(const S& i, const swap_struct_t<T, F> v) {
451 return i * v.swap(); 500 return i * v.swap();
452} 501}
453 502
454template <typename S, typename T, typename F> 503template <typename S, typename T, typename F>
455S operator%(const S &i, const swap_struct_t<T, F> v) { 504S operator%(const S& i, const swap_struct_t<T, F> v) {
456 return i % v.swap(); 505 return i % v.swap();
457} 506}
458 507
459// Arithmetics + assignements 508// Arithmetics + assignements
460template <typename S, typename T, typename F> 509template <typename S, typename T, typename F>
461S &operator+=(S &i, const swap_struct_t<T, F> v) { 510S& operator+=(S& i, const swap_struct_t<T, F> v) {
462 i += v.swap(); 511 i += v.swap();
463 return i; 512 return i;
464} 513}
465 514
466template <typename S, typename T, typename F> 515template <typename S, typename T, typename F>
467S &operator-=(S &i, const swap_struct_t<T, F> v) { 516S& operator-=(S& i, const swap_struct_t<T, F> v) {
468 i -= v.swap(); 517 i -= v.swap();
469 return i; 518 return i;
470} 519}
471 520
472// Logical 521// Logical
473template <typename S, typename T, typename F> 522template <typename S, typename T, typename F>
474S operator&(const S &i, const swap_struct_t<T, F> v) { 523S operator&(const S& i, const swap_struct_t<T, F> v) {
475 return i & v.swap(); 524 return i & v.swap();
476} 525}
477 526
478template <typename S, typename T, typename F> 527template <typename S, typename T, typename F>
479S operator&(const swap_struct_t<T, F> v, const S &i) { 528S operator&(const swap_struct_t<T, F> v, const S& i) {
480 return (S)(v.swap() & i); 529 return (S)(v.swap() & i);
481} 530}
482 531
483
484// Comparaison 532// Comparaison
485template <typename S, typename T, typename F> 533template <typename S, typename T, typename F>
486bool operator<(const S &p, const swap_struct_t<T, F> v) { 534bool operator<(const S& p, const swap_struct_t<T, F> v) {
487 return p < v.swap(); 535 return p < v.swap();
488} 536}
489template <typename S, typename T, typename F> 537template <typename S, typename T, typename F>
490bool operator>(const S &p, const swap_struct_t<T, F> v) { 538bool operator>(const S& p, const swap_struct_t<T, F> v) {
491 return p > v.swap(); 539 return p > v.swap();
492} 540}
493template <typename S, typename T, typename F> 541template <typename S, typename T, typename F>
494bool operator<=(const S &p, const swap_struct_t<T, F> v) { 542bool operator<=(const S& p, const swap_struct_t<T, F> v) {
495 return p <= v.swap(); 543 return p <= v.swap();
496} 544}
497template <typename S, typename T, typename F> 545template <typename S, typename T, typename F>
498bool operator>=(const S &p, const swap_struct_t<T, F> v) { 546bool operator>=(const S& p, const swap_struct_t<T, F> v) {
499 return p >= v.swap(); 547 return p >= v.swap();
500} 548}
501template <typename S, typename T, typename F> 549template <typename S, typename T, typename F>
502bool operator!=(const S &p, const swap_struct_t<T, F> v) { 550bool operator!=(const S& p, const swap_struct_t<T, F> v) {
503 return p != v.swap(); 551 return p != v.swap();
504} 552}
505template <typename S, typename T, typename F> 553template <typename S, typename T, typename F>
506bool operator==(const S &p, const swap_struct_t<T, F> v) { 554bool operator==(const S& p, const swap_struct_t<T, F> v) {
507 return p == v.swap(); 555 return p == v.swap();
508} 556}
509 557
@@ -554,30 +602,30 @@ typedef s64 s64_le;
554typedef float float_le; 602typedef float float_le;
555typedef double double_le; 603typedef double double_le;
556 604
557typedef swap_struct_t<u64, swap_64_t<u64> > u64_be; 605typedef swap_struct_t<u64, swap_64_t<u64>> u64_be;
558typedef swap_struct_t<s64, swap_64_t<s64> > s64_be; 606typedef swap_struct_t<s64, swap_64_t<s64>> s64_be;
559 607
560typedef swap_struct_t<u32, swap_32_t<u32> > u32_be; 608typedef swap_struct_t<u32, swap_32_t<u32>> u32_be;
561typedef swap_struct_t<s32, swap_32_t<s32> > s32_be; 609typedef swap_struct_t<s32, swap_32_t<s32>> s32_be;
562 610
563typedef swap_struct_t<u16, swap_16_t<u16> > u16_be; 611typedef swap_struct_t<u16, swap_16_t<u16>> u16_be;
564typedef swap_struct_t<s16, swap_16_t<s16> > s16_be; 612typedef swap_struct_t<s16, swap_16_t<s16>> s16_be;
565 613
566typedef swap_struct_t<float, swap_float_t<float> > float_be; 614typedef swap_struct_t<float, swap_float_t<float>> float_be;
567typedef swap_struct_t<double, swap_double_t<double> > double_be; 615typedef swap_struct_t<double, swap_double_t<double>> double_be;
568#else 616#else
569 617
570typedef swap_struct_t<u64, swap_64_t<u64> > u64_le; 618typedef swap_struct_t<u64, swap_64_t<u64>> u64_le;
571typedef swap_struct_t<s64, swap_64_t<s64> > s64_le; 619typedef swap_struct_t<s64, swap_64_t<s64>> s64_le;
572 620
573typedef swap_struct_t<u32, swap_32_t<u32> > u32_le; 621typedef swap_struct_t<u32, swap_32_t<u32>> u32_le;
574typedef swap_struct_t<s32, swap_32_t<s32> > s32_le; 622typedef swap_struct_t<s32, swap_32_t<s32>> s32_le;
575 623
576typedef swap_struct_t<u16, swap_16_t<u16> > u16_le; 624typedef swap_struct_t<u16, swap_16_t<u16>> u16_le;
577typedef swap_struct_t< s16, swap_16_t<s16> > s16_le; 625typedef swap_struct_t<s16, swap_16_t<s16>> s16_le;
578 626
579typedef swap_struct_t<float, swap_float_t<float> > float_le; 627typedef swap_struct_t<float, swap_float_t<float>> float_le;
580typedef swap_struct_t<double, swap_double_t<double> > double_le; 628typedef swap_struct_t<double, swap_double_t<double>> double_le;
581 629
582typedef u32 u32_be; 630typedef u32 u32_be;
583typedef u16 u16_be; 631typedef 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..f5a48e05a 100644
--- a/src/common/symbols.h
+++ b/src/common/symbols.h
@@ -7,28 +7,24 @@
7#include <map> 7#include <map>
8#include <string> 8#include <string>
9#include <utility> 9#include <utility>
10
11#include "common/common_types.h" 10#include "common/common_types.h"
12 11
13struct TSymbol 12struct TSymbol {
14{ 13 u32 address = 0;
15 u32 address = 0;
16 std::string name; 14 std::string name;
17 u32 size = 0; 15 u32 size = 0;
18 u32 type = 0; 16 u32 type = 0;
19}; 17};
20 18
21typedef std::map<u32, TSymbol> TSymbolsMap; 19typedef std::map<u32, TSymbol> TSymbolsMap;
22typedef std::pair<u32, TSymbol> TSymbolsPair; 20typedef std::pair<u32, TSymbol> TSymbolsPair;
23 21
24namespace Symbols 22namespace Symbols {
25{ 23bool HasSymbol(u32 address);
26 bool HasSymbol(u32 address);
27 24
28 void Add(u32 address, const std::string& name, u32 size, u32 type); 25void Add(u32 address, const std::string& name, u32 size, u32 type);
29 TSymbol GetSymbol(u32 address); 26TSymbol GetSymbol(u32 address);
30 const std::string GetName(u32 address); 27const std::string GetName(u32 address);
31 void Remove(u32 address); 28void Remove(u32 address);
32 void Clear(); 29void Clear();
33} 30}
34
diff --git a/src/common/synchronized_wrapper.h b/src/common/synchronized_wrapper.h
index 07105a198..04b4f2e51 100644
--- a/src/common/synchronized_wrapper.h
+++ b/src/common/synchronized_wrapper.h
@@ -12,15 +12,14 @@ namespace Common {
12/** 12/**
13 * Wraps an object, only allowing access to it via a locking reference wrapper. Good to ensure no 13 * Wraps an object, only allowing access to it via a locking reference wrapper. Good to ensure no
14 * one forgets to lock a mutex before acessing an object. To access the wrapped object construct a 14 * one forgets to lock a mutex before acessing an object. To access the wrapped object construct a
15 * SyncronizedRef on this wrapper. Inspired by Rust's Mutex type (http://doc.rust-lang.org/std/sync/struct.Mutex.html). 15 * SyncronizedRef on this wrapper. Inspired by Rust's Mutex type
16 * (http://doc.rust-lang.org/std/sync/struct.Mutex.html).
16 */ 17 */
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 }
24 23
25private: 24private:
26 template <typename U> 25 template <typename U>
@@ -58,11 +57,19 @@ public:
58 return *this; 57 return *this;
59 } 58 }
60 59
61 T& operator*() { return wrapper->data; } 60 T& operator*() {
62 const T& operator*() const { return wrapper->data; } 61 return wrapper->data;
62 }
63 const T& operator*() const {
64 return wrapper->data;
65 }
63 66
64 T* operator->() { return &wrapper->data; } 67 T* operator->() {
65 const T* operator->() const { return &wrapper->data; } 68 return &wrapper->data;
69 }
70 const T* operator->() const {
71 return &wrapper->data;
72 }
66 73
67private: 74private:
68 SynchronizedWrapper<T>* wrapper; 75 SynchronizedWrapper<T>* wrapper;
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 7bbf080bc..6e7b39b9a 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -3,29 +3,25 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/thread.h" 5#include "common/thread.h"
6
7#ifdef __APPLE__ 6#ifdef __APPLE__
8 #include <mach/mach.h> 7#include <mach/mach.h>
9#elif defined(_WIN32) 8#elif defined(_WIN32)
10 #include <Windows.h> 9#include <Windows.h>
10#else
11#if defined(BSD4_4) || defined(__OpenBSD__)
12#include <pthread_np.h>
11#else 13#else
12 #if defined(BSD4_4) || defined(__OpenBSD__) 14#include <pthread.h>
13 #include <pthread_np.h> 15#endif
14 #else 16#include <sched.h>
15 #include <pthread.h>
16 #endif
17 #include <sched.h>
18#endif 17#endif
19
20#ifndef _WIN32 18#ifndef _WIN32
21 #include <unistd.h> 19#include <unistd.h>
22#endif 20#endif
23 21
24namespace Common 22namespace Common {
25{
26 23
27int CurrentThreadId() 24int CurrentThreadId() {
28{
29#ifdef _MSC_VER 25#ifdef _MSC_VER
30 return GetCurrentThreadId(); 26 return GetCurrentThreadId();
31#elif defined __APPLE__ 27#elif defined __APPLE__
@@ -37,26 +33,22 @@ int CurrentThreadId()
37 33
38#ifdef _WIN32 34#ifdef _WIN32
39// Supporting functions 35// Supporting functions
40void SleepCurrentThread(int ms) 36void SleepCurrentThread(int ms) {
41{
42 Sleep(ms); 37 Sleep(ms);
43} 38}
44#endif 39#endif
45 40
46#ifdef _MSC_VER 41#ifdef _MSC_VER
47 42
48void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) 43void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
49{
50 SetThreadAffinityMask(thread, mask); 44 SetThreadAffinityMask(thread, mask);
51} 45}
52 46
53void SetCurrentThreadAffinity(u32 mask) 47void SetCurrentThreadAffinity(u32 mask) {
54{
55 SetThreadAffinityMask(GetCurrentThread(), mask); 48 SetThreadAffinityMask(GetCurrentThread(), mask);
56} 49}
57 50
58void SwitchCurrentThread() 51void SwitchCurrentThread() {
59{
60 SwitchToThread(); 52 SwitchToThread();
61} 53}
62 54
@@ -66,40 +58,34 @@ void SwitchCurrentThread()
66 58
67// This is implemented much nicer in upcoming msvc++, see: 59// This is implemented much nicer in upcoming msvc++, see:
68// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx 60// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
69void SetCurrentThreadName(const char* szThreadName) 61void SetCurrentThreadName(const char* szThreadName) {
70{
71 static const DWORD MS_VC_EXCEPTION = 0x406D1388; 62 static const DWORD MS_VC_EXCEPTION = 0x406D1388;
72 63
73 #pragma pack(push,8) 64#pragma pack(push, 8)
74 struct THREADNAME_INFO 65 struct THREADNAME_INFO {
75 { 66 DWORD dwType; // must be 0x1000
76 DWORD dwType; // must be 0x1000 67 LPCSTR szName; // pointer to name (in user addr space)
77 LPCSTR szName; // pointer to name (in user addr space)
78 DWORD dwThreadID; // thread ID (-1=caller thread) 68 DWORD dwThreadID; // thread ID (-1=caller thread)
79 DWORD dwFlags; // reserved for future use, must be zero 69 DWORD dwFlags; // reserved for future use, must be zero
80 } info; 70 } info;
81 #pragma pack(pop) 71#pragma pack(pop)
82 72
83 info.dwType = 0x1000; 73 info.dwType = 0x1000;
84 info.szName = szThreadName; 74 info.szName = szThreadName;
85 info.dwThreadID = -1; //dwThreadID; 75 info.dwThreadID = -1; // dwThreadID;
86 info.dwFlags = 0; 76 info.dwFlags = 0;
87 77
88 __try 78 __try {
89 { 79 RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
90 RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); 80 } __except (EXCEPTION_CONTINUE_EXECUTION) {
91 } 81 }
92 __except(EXCEPTION_CONTINUE_EXECUTION)
93 {}
94} 82}
95 83
96#else // !MSVC_VER, so must be POSIX threads 84#else // !MSVC_VER, so must be POSIX threads
97 85
98void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) 86void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
99{
100#ifdef __APPLE__ 87#ifdef __APPLE__
101 thread_policy_set(pthread_mach_thread_np(thread), 88 thread_policy_set(pthread_mach_thread_np(thread), THREAD_AFFINITY_POLICY, (integer_t*)&mask, 1);
102 THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1);
103#elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID) 89#elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID)
104 cpu_set_t cpu_set; 90 cpu_set_t cpu_set;
105 CPU_ZERO(&cpu_set); 91 CPU_ZERO(&cpu_set);
@@ -112,27 +98,23 @@ void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
112#endif 98#endif
113} 99}
114 100
115void SetCurrentThreadAffinity(u32 mask) 101void SetCurrentThreadAffinity(u32 mask) {
116{
117 SetThreadAffinity(pthread_self(), mask); 102 SetThreadAffinity(pthread_self(), mask);
118} 103}
119 104
120#ifndef _WIN32 105#ifndef _WIN32
121void SleepCurrentThread(int ms) 106void SleepCurrentThread(int ms) {
122{
123 usleep(1000 * ms); 107 usleep(1000 * ms);
124} 108}
125 109
126void SwitchCurrentThread() 110void SwitchCurrentThread() {
127{
128 usleep(1000 * 1); 111 usleep(1000 * 1);
129} 112}
130#endif 113#endif
131 114
132// MinGW with the POSIX threading model does not support pthread_setname_np 115// MinGW with the POSIX threading model does not support pthread_setname_np
133#if !defined(_WIN32) || defined(_MSC_VER) 116#if !defined(_WIN32) || defined(_MSC_VER)
134void SetCurrentThreadName(const char* szThreadName) 117void SetCurrentThreadName(const char* szThreadName) {
135{
136#ifdef __APPLE__ 118#ifdef __APPLE__
137 pthread_setname_np(szThreadName); 119 pthread_setname_np(szThreadName);
138#elif defined(__OpenBSD__) 120#elif defined(__OpenBSD__)
diff --git a/src/common/thread.h b/src/common/thread.h
index bbfa8befa..9c08be7e3 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -4,11 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8#include <thread>
9#include <condition_variable> 7#include <condition_variable>
8#include <cstddef>
10#include <mutex> 9#include <mutex>
11 10#include <thread>
12#include "common/common_types.h" 11#include "common/common_types.h"
13 12
14// Support for C++11's thread_local keyword was surprisingly spotty in compilers until very 13// Support for C++11's thread_local keyword was surprisingly spotty in compilers until very
@@ -17,17 +16,17 @@
17// backwards compat support. 16// backwards compat support.
18// WARNING: This only works correctly with POD types. 17// WARNING: This only works correctly with POD types.
19#if defined(__clang__) 18#if defined(__clang__)
20# if !__has_feature(cxx_thread_local) 19#if !__has_feature(cxx_thread_local)
21# define thread_local __thread 20#define thread_local __thread
22# endif 21#endif
23#elif defined(__GNUC__) 22#elif defined(__GNUC__)
24# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) 23#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
25# define thread_local __thread 24#define thread_local __thread
26# endif 25#endif
27#elif defined(_MSC_VER) 26#elif defined(_MSC_VER)
28# if _MSC_VER < 1900 27#if _MSC_VER < 1900
29# define thread_local __declspec(thread) 28#define thread_local __declspec(thread)
30# endif 29#endif
31#endif 30#endif
32 31
33namespace Common { 32namespace Common {
@@ -51,13 +50,14 @@ public:
51 50
52 void Wait() { 51 void Wait() {
53 std::unique_lock<std::mutex> lk(mutex); 52 std::unique_lock<std::mutex> lk(mutex);
54 condvar.wait(lk, [&]{ return is_set; }); 53 condvar.wait(lk, [&] { return is_set; });
55 is_set = false; 54 is_set = false;
56 } 55 }
57 56
58 void Reset() { 57 void Reset() {
59 std::unique_lock<std::mutex> lk(mutex); 58 std::unique_lock<std::mutex> lk(mutex);
60 // no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration 59 // no other action required, since wait loops on the predicate and any lingering signal will
60 // get cleared on the first iteration
61 is_set = false; 61 is_set = false;
62 } 62 }
63 63
@@ -81,7 +81,8 @@ public:
81 waiting = 0; 81 waiting = 0;
82 condvar.notify_all(); 82 condvar.notify_all();
83 } else { 83 } else {
84 condvar.wait(lk, [this, current_generation]{ return current_generation != generation; }); 84 condvar.wait(lk,
85 [this, current_generation] { return current_generation != generation; });
85 } 86 }
86 } 87 }
87 88
@@ -94,7 +95,7 @@ private:
94}; 95};
95 96
96void SleepCurrentThread(int ms); 97void SleepCurrentThread(int ms);
97void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms 98void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
98 99
99// Use this function during a spin-wait to make the current thread 100// Use this function during a spin-wait to make the current thread
100// relax while another thread is working. This may be more efficient 101// relax while another thread is working. This may be more efficient
@@ -103,6 +104,6 @@ inline void YieldCPU() {
103 std::this_thread::yield(); 104 std::this_thread::yield();
104} 105}
105 106
106void SetCurrentThreadName(const char *name); 107void SetCurrentThreadName(const char* name);
107 108
108} // namespace Common 109} // namespace Common
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 12455d7c4..edd0e4a3f 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -6,12 +6,11 @@
6 6
7#include <array> 7#include <array>
8#include <deque> 8#include <deque>
9
10#include <boost/range/algorithm_ext/erase.hpp> 9#include <boost/range/algorithm_ext/erase.hpp>
11 10
12namespace Common { 11namespace Common {
13 12
14template<class T, unsigned int N> 13template <class T, unsigned int N>
15struct ThreadQueueList { 14struct ThreadQueueList {
16 // TODO(yuriks): If performance proves to be a problem, the std::deques can be replaced with 15 // TODO(yuriks): If performance proves to be a problem, the std::deques can be replaced with
17 // (dynamically resizable) circular buffers to remove their overhead when 16 // (dynamically resizable) circular buffers to remove their overhead when
@@ -39,7 +38,7 @@ struct ThreadQueueList {
39 } 38 }
40 39
41 T get_first() { 40 T get_first() {
42 Queue *cur = first; 41 Queue* cur = first;
43 while (cur != nullptr) { 42 while (cur != nullptr) {
44 if (!cur->data.empty()) { 43 if (!cur->data.empty()) {
45 return cur->data.front(); 44 return cur->data.front();
@@ -51,7 +50,7 @@ struct ThreadQueueList {
51 } 50 }
52 51
53 T pop_first() { 52 T pop_first() {
54 Queue *cur = first; 53 Queue* cur = first;
55 while (cur != nullptr) { 54 while (cur != nullptr) {
56 if (!cur->data.empty()) { 55 if (!cur->data.empty()) {
57 auto tmp = std::move(cur->data.front()); 56 auto tmp = std::move(cur->data.front());
@@ -65,8 +64,8 @@ struct ThreadQueueList {
65 } 64 }
66 65
67 T pop_first_better(Priority priority) { 66 T pop_first_better(Priority priority) {
68 Queue *cur = first; 67 Queue* cur = first;
69 Queue *stop = &queues[priority]; 68 Queue* stop = &queues[priority];
70 while (cur < stop) { 69 while (cur < stop) {
71 if (!cur->data.empty()) { 70 if (!cur->data.empty()) {
72 auto tmp = std::move(cur->data.front()); 71 auto tmp = std::move(cur->data.front());
@@ -80,12 +79,12 @@ struct ThreadQueueList {
80 } 79 }
81 80
82 void push_front(Priority priority, const T& thread_id) { 81 void push_front(Priority priority, const T& thread_id) {
83 Queue *cur = &queues[priority]; 82 Queue* cur = &queues[priority];
84 cur->data.push_front(thread_id); 83 cur->data.push_front(thread_id);
85 } 84 }
86 85
87 void push_back(Priority priority, const T& thread_id) { 86 void push_back(Priority priority, const T& thread_id) {
88 Queue *cur = &queues[priority]; 87 Queue* cur = &queues[priority];
89 cur->data.push_back(thread_id); 88 cur->data.push_back(thread_id);
90 } 89 }
91 90
@@ -96,12 +95,12 @@ struct ThreadQueueList {
96 } 95 }
97 96
98 void remove(Priority priority, const T& thread_id) { 97 void remove(Priority priority, const T& thread_id) {
99 Queue *cur = &queues[priority]; 98 Queue* cur = &queues[priority];
100 boost::remove_erase(cur->data, thread_id); 99 boost::remove_erase(cur->data, thread_id);
101 } 100 }
102 101
103 void rotate(Priority priority) { 102 void rotate(Priority priority) {
104 Queue *cur = &queues[priority]; 103 Queue* cur = &queues[priority];
105 104
106 if (cur->data.size() > 1) { 105 if (cur->data.size() > 1) {
107 cur->data.push_back(std::move(cur->data.front())); 106 cur->data.push_back(std::move(cur->data.front()));
@@ -115,7 +114,7 @@ struct ThreadQueueList {
115 } 114 }
116 115
117 bool empty(Priority priority) const { 116 bool empty(Priority priority) const {
118 const Queue *cur = &queues[priority]; 117 const Queue* cur = &queues[priority];
119 return cur->data.empty(); 118 return cur->data.empty();
120 } 119 }
121 120
@@ -139,7 +138,7 @@ private:
139 } 138 }
140 139
141 void link(Priority priority) { 140 void link(Priority priority) {
142 Queue *cur = &queues[priority]; 141 Queue* cur = &queues[priority];
143 142
144 for (int i = priority - 1; i >= 0; --i) { 143 for (int i = priority - 1; i >= 0; --i) {
145 if (queues[i].next_nonempty != UnlinkedTag()) { 144 if (queues[i].next_nonempty != UnlinkedTag()) {
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index b99835ac7..e843cbd9c 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <time.h> 5#include <time.h>
6
7#ifdef _WIN32 6#ifdef _WIN32
8#include <Windows.h> 7#include <Windows.h>
9#include <mmsystem.h> 8#include <mmsystem.h>
@@ -11,16 +10,13 @@
11#else 10#else
12#include <sys/time.h> 11#include <sys/time.h>
13#endif 12#endif
14
15#include "common/common_types.h" 13#include "common/common_types.h"
16#include "common/string_util.h" 14#include "common/string_util.h"
17#include "common/timer.h" 15#include "common/timer.h"
18 16
19namespace Common 17namespace Common {
20{
21 18
22u32 Timer::GetTimeMs() 19u32 Timer::GetTimeMs() {
23{
24#ifdef _WIN32 20#ifdef _WIN32
25 return timeGetTime(); 21 return timeGetTime();
26#else 22#else
@@ -35,32 +31,27 @@ u32 Timer::GetTimeMs()
35// -------------------------------------------- 31// --------------------------------------------
36 32
37// Set initial values for the class 33// Set initial values for the class
38Timer::Timer() 34Timer::Timer() : m_LastTime(0), m_StartTime(0), m_Running(false) {
39 : m_LastTime(0), m_StartTime(0), m_Running(false)
40{
41 Update(); 35 Update();
42} 36}
43 37
44// Write the starting time 38// Write the starting time
45void Timer::Start() 39void Timer::Start() {
46{
47 m_StartTime = GetTimeMs(); 40 m_StartTime = GetTimeMs();
48 m_Running = true; 41 m_Running = true;
49} 42}
50 43
51// Stop the timer 44// Stop the timer
52void Timer::Stop() 45void Timer::Stop() {
53{
54 // Write the final time 46 // Write the final time
55 m_LastTime = GetTimeMs(); 47 m_LastTime = GetTimeMs();
56 m_Running = false; 48 m_Running = false;
57} 49}
58 50
59// Update the last time variable 51// Update the last time variable
60void Timer::Update() 52void Timer::Update() {
61{
62 m_LastTime = GetTimeMs(); 53 m_LastTime = GetTimeMs();
63 //TODO(ector) - QPF 54 // TODO(ector) - QPF
64} 55}
65 56
66// ------------------------------------- 57// -------------------------------------
@@ -68,34 +59,32 @@ void Timer::Update()
68// ------------------------------------- 59// -------------------------------------
69 60
70// Get the number of milliseconds since the last Update() 61// Get the number of milliseconds since the last Update()
71u64 Timer::GetTimeDifference() 62u64 Timer::GetTimeDifference() {
72{
73 return GetTimeMs() - m_LastTime; 63 return GetTimeMs() - m_LastTime;
74} 64}
75 65
76// Add the time difference since the last Update() to the starting time. 66// Add the time difference since the last Update() to the starting time.
77// This is used to compensate for a paused game. 67// This is used to compensate for a paused game.
78void Timer::AddTimeDifference() 68void Timer::AddTimeDifference() {
79{
80 m_StartTime += GetTimeDifference(); 69 m_StartTime += GetTimeDifference();
81} 70}
82 71
83// Get the time elapsed since the Start() 72// Get the time elapsed since the Start()
84u64 Timer::GetTimeElapsed() 73u64 Timer::GetTimeElapsed() {
85{
86 // If we have not started yet, return 1 (because then I don't 74 // If we have not started yet, return 1 (because then I don't
87 // have to change the FPS calculation in CoreRerecording.cpp . 75 // have to change the FPS calculation in CoreRerecording.cpp .
88 if (m_StartTime == 0) return 1; 76 if (m_StartTime == 0)
77 return 1;
89 78
90 // Return the final timer time if the timer is stopped 79 // Return the final timer time if the timer is stopped
91 if (!m_Running) return (m_LastTime - m_StartTime); 80 if (!m_Running)
81 return (m_LastTime - m_StartTime);
92 82
93 return (GetTimeMs() - m_StartTime); 83 return (GetTimeMs() - m_StartTime);
94} 84}
95 85
96// Get the formatted time elapsed since the Start() 86// Get the formatted time elapsed since the Start()
97std::string Timer::GetTimeElapsedFormatted() const 87std::string Timer::GetTimeElapsedFormatted() const {
98{
99 // If we have not started yet, return zero 88 // If we have not started yet, return zero
100 if (m_StartTime == 0) 89 if (m_StartTime == 0)
101 return "00:00:00:000"; 90 return "00:00:00:000";
@@ -114,50 +103,46 @@ std::string Timer::GetTimeElapsedFormatted() const
114 // Hours 103 // Hours
115 u32 Hours = Minutes / 60; 104 u32 Hours = Minutes / 60;
116 105
117 std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", 106 std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", Hours, Minutes % 60, Seconds % 60,
118 Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000); 107 Milliseconds % 1000);
119 return TmpStr; 108 return TmpStr;
120} 109}
121 110
122// Get current time 111// Get current time
123void Timer::IncreaseResolution() 112void Timer::IncreaseResolution() {
124{
125#ifdef _WIN32 113#ifdef _WIN32
126 timeBeginPeriod(1); 114 timeBeginPeriod(1);
127#endif 115#endif
128} 116}
129 117
130void Timer::RestoreResolution() 118void Timer::RestoreResolution() {
131{
132#ifdef _WIN32 119#ifdef _WIN32
133 timeEndPeriod(1); 120 timeEndPeriod(1);
134#endif 121#endif
135} 122}
136 123
137// Get the number of seconds since January 1 1970 124// Get the number of seconds since January 1 1970
138u64 Timer::GetTimeSinceJan1970() 125u64 Timer::GetTimeSinceJan1970() {
139{
140 time_t ltime; 126 time_t ltime;
141 time(&ltime); 127 time(&ltime);
142 return((u64)ltime); 128 return ((u64)ltime);
143} 129}
144 130
145u64 Timer::GetLocalTimeSinceJan1970() 131u64 Timer::GetLocalTimeSinceJan1970() {
146{
147 time_t sysTime, tzDiff, tzDST; 132 time_t sysTime, tzDiff, tzDST;
148 struct tm * gmTime; 133 struct tm* gmTime;
149 134
150 time(&sysTime); 135 time(&sysTime);
151 136
152 // Account for DST where needed 137 // Account for DST where needed
153 gmTime = localtime(&sysTime); 138 gmTime = localtime(&sysTime);
154 if(gmTime->tm_isdst == 1) 139 if (gmTime->tm_isdst == 1)
155 tzDST = 3600; 140 tzDST = 3600;
156 else 141 else
157 tzDST = 0; 142 tzDST = 0;
158 143
159 // Lazy way to get local time in sec 144 // Lazy way to get local time in sec
160 gmTime = gmtime(&sysTime); 145 gmTime = gmtime(&sysTime);
161 tzDiff = sysTime - mktime(gmTime); 146 tzDiff = sysTime - mktime(gmTime);
162 147
163 return (u64)(sysTime + tzDiff + tzDST); 148 return (u64)(sysTime + tzDiff + tzDST);
@@ -165,10 +150,9 @@ u64 Timer::GetLocalTimeSinceJan1970()
165 150
166// Return the current time formatted as Minutes:Seconds:Milliseconds 151// Return the current time formatted as Minutes:Seconds:Milliseconds
167// in the form 00:00:000. 152// in the form 00:00:000.
168std::string Timer::GetTimeFormatted() 153std::string Timer::GetTimeFormatted() {
169{
170 time_t sysTime; 154 time_t sysTime;
171 struct tm * gmTime; 155 struct tm* gmTime;
172 char tmp[13]; 156 char tmp[13];
173 157
174 time(&sysTime); 158 time(&sysTime);
@@ -176,7 +160,7 @@ std::string Timer::GetTimeFormatted()
176 160
177 strftime(tmp, 6, "%M:%S", gmTime); 161 strftime(tmp, 6, "%M:%S", gmTime);
178 162
179 // Now tack on the milliseconds 163// Now tack on the milliseconds
180#ifdef _WIN32 164#ifdef _WIN32
181 struct timeb tp; 165 struct timeb tp;
182 (void)::ftime(&tp); 166 (void)::ftime(&tp);
@@ -190,8 +174,7 @@ std::string Timer::GetTimeFormatted()
190 174
191// Returns a timestamp with decimals for precise time comparisons 175// Returns a timestamp with decimals for precise time comparisons
192// ---------------- 176// ----------------
193double Timer::GetDoubleTime() 177double Timer::GetDoubleTime() {
194{
195#ifdef _WIN32 178#ifdef _WIN32
196 struct timeb tp; 179 struct timeb tp;
197 (void)::ftime(&tp); 180 (void)::ftime(&tp);
diff --git a/src/common/timer.h b/src/common/timer.h
index b5f0f2585..78d37426b 100644
--- a/src/common/timer.h
+++ b/src/common/timer.h
@@ -4,13 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h"
8#include <string> 7#include <string>
8#include "common/common_types.h"
9 9
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..2d56f168c 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -1,7 +1,6 @@
1// Licensed under GPLv2 or any later version 1// Licensed under GPLv2 or any later version
2// Refer to the license.txt file included. 2// Refer to the license.txt file included.
3 3
4
5// Copyright 2014 Tony Wasserka 4// Copyright 2014 Tony Wasserka
6// All rights reserved. 5// All rights reserved.
7// 6//
@@ -36,158 +35,174 @@
36 35
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 Vec2(const T& _x, const T& _y) : x(_x), y(_y) {}
62 65
63 template<typename T2> 66 template <typename T2>
64 Vec2<T2> Cast() const { 67 Vec2<T2> Cast() const {
65 return Vec2<T2>((T2)x, (T2)y); 68 return Vec2<T2>((T2)x, (T2)y);
66 } 69 }
67 70
68 static Vec2 AssignToAll(const T& f) 71 static Vec2 AssignToAll(const T& f) {
69 {
70 return Vec2<T>(f, f); 72 return Vec2<T>(f, f);
71 } 73 }
72 74
73 void Write(T a[2]) 75 void Write(T a[2]) {
74 { 76 a[0] = x;
75 a[0] = x; a[1] = y; 77 a[1] = y;
76 } 78 }
77 79
78 Vec2<decltype(T{}+T{})> operator +(const Vec2& other) const 80 Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
79 { 81 return MakeVec(x + other.x, y + other.y);
80 return MakeVec(x+other.x, y+other.y);
81 } 82 }
82 void operator += (const Vec2 &other) 83 void operator+=(const Vec2& other) {
83 { 84 x += other.x;
84 x+=other.x; y+=other.y; 85 y += other.y;
85 } 86 }
86 Vec2<decltype(T{}-T{})> operator -(const Vec2& other) const 87 Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
87 { 88 return MakeVec(x - other.x, y - other.y);
88 return MakeVec(x-other.x, y-other.y);
89 } 89 }
90 void operator -= (const Vec2& other) 90 void operator-=(const Vec2& other) {
91 { 91 x -= other.x;
92 x-=other.x; y-=other.y; 92 y -= other.y;
93 } 93 }
94 template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> 94 template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type>
95 Vec2<decltype(-T{})> operator -() const 95 Vec2<decltype(-T{})> operator-() const {
96 { 96 return MakeVec(-x, -y);
97 return MakeVec(-x,-y);
98 } 97 }
99 Vec2<decltype(T{}*T{})> operator * (const Vec2& other) const 98 Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
100 { 99 return MakeVec(x * other.x, y * other.y);
101 return MakeVec(x*other.x, y*other.y);
102 } 100 }
103 template<typename V> 101 template <typename V>
104 Vec2<decltype(T{}*V{})> operator * (const V& f) const 102 Vec2<decltype(T{} * V{})> operator*(const V& f) const {
105 { 103 return MakeVec(x * f, y * f);
106 return MakeVec(x*f,y*f);
107 } 104 }
108 template<typename V> 105 template <typename V>
109 void operator *= (const V& f) 106 void operator*=(const V& f) {
110 { 107 x *= f;
111 x*=f; y*=f; 108 y *= f;
112 } 109 }
113 template<typename V> 110 template <typename V>
114 Vec2<decltype(T{}/V{})> operator / (const V& f) const 111 Vec2<decltype(T{} / V{})> operator/(const V& f) const {
115 { 112 return MakeVec(x / f, y / f);
116 return MakeVec(x/f,y/f);
117 } 113 }
118 template<typename V> 114 template <typename V>
119 void operator /= (const V& f) 115 void operator/=(const V& f) {
120 {
121 *this = *this / f; 116 *this = *this / f;
122 } 117 }
123 118
124 T Length2() const 119 T Length2() const {
125 { 120 return x * x + y * y;
126 return x*x + y*y;
127 } 121 }
128 122
129 // Only implemented for T=float 123 // Only implemented for T=float
130 float Length() const; 124 float Length() const;
131 void SetLength(const float l); 125 void SetLength(const float l);
132 Vec2 WithLength(const float l) const; 126 Vec2 WithLength(const float l) const;
133 float Distance2To(Vec2 &other); 127 float Distance2To(Vec2& other);
134 Vec2 Normalized() const; 128 Vec2 Normalized() const;
135 float Normalize(); // returns the previous length, which is often useful 129 float Normalize(); // returns the previous length, which is often useful
136 130
137 T& operator [] (int i) //allow vector[1] = 3 (vector.y=3) 131 T& operator[](int i) // allow vector[1] = 3 (vector.y=3)
138 { 132 {
139 return *((&x) + i); 133 return *((&x) + i);
140 } 134 }
141 T operator [] (const int i) const 135 T operator[](const int i) const {
142 {
143 return *((&x) + i); 136 return *((&x) + i);
144 } 137 }
145 138
146 void SetZero() 139 void SetZero() {
147 { 140 x = 0;
148 x=0; y=0; 141 y = 0;
149 } 142 }
150 143
151 // Common aliases: UV (texel coordinates), ST (texture coordinates) 144 // Common aliases: UV (texel coordinates), ST (texture coordinates)
152 T& u() { return x; } 145 T& u() {
153 T& v() { return y; } 146 return x;
154 T& s() { return x; } 147 }
155 T& t() { return y; } 148 T& v() {
149 return y;
150 }
151 T& s() {
152 return x;
153 }
154 T& t() {
155 return y;
156 }
156 157
157 const T& u() const { return x; } 158 const T& u() const {
158 const T& v() const { return y; } 159 return x;
159 const T& s() const { return x; } 160 }
160 const T& t() const { return y; } 161 const T& v() const {
162 return y;
163 }
164 const T& s() const {
165 return x;
166 }
167 const T& t() const {
168 return y;
169 }
161 170
162 // swizzlers - create a subvector of specific components 171 // swizzlers - create a subvector of specific components
163 const Vec2 yx() const { return Vec2(y, x); } 172 const Vec2 yx() const {
164 const Vec2 vu() const { return Vec2(y, x); } 173 return Vec2(y, x);
165 const Vec2 ts() const { return Vec2(y, x); } 174 }
175 const Vec2 vu() const {
176 return Vec2(y, x);
177 }
178 const Vec2 ts() const {
179 return Vec2(y, x);
180 }
166}; 181};
167 182
168template<typename T, typename V> 183template <typename T, typename V>
169Vec2<T> operator * (const V& f, const Vec2<T>& vec) 184Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
170{ 185 return Vec2<T>(f * vec.x, f * vec.y);
171 return Vec2<T>(f*vec.x,f*vec.y);
172} 186}
173 187
174typedef Vec2<float> Vec2f; 188typedef Vec2<float> Vec2f;
175 189
176template<typename T> 190template <typename T>
177class Vec3 191class Vec3 {
178{
179public: 192public:
180 T x; 193 T x;
181 T y; 194 T y;
182 T z; 195 T z;
183 196
184 T* AsArray() { return &x; } 197 T* AsArray() {
198 return &x;
199 }
185 200
186 Vec3() = default; 201 Vec3() = default;
187 Vec3(const T a[3]) : x(a[0]), y(a[1]), z(a[2]) {} 202 Vec3(const T a[3]) : x(a[0]), y(a[1]), z(a[2]) {}
188 Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {} 203 Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {}
189 204
190 template<typename T2> 205 template <typename T2>
191 Vec3<T2> Cast() const { 206 Vec3<T2> Cast() const {
192 return MakeVec<T2>((T2)x, (T2)y, (T2)z); 207 return MakeVec<T2>((T2)x, (T2)y, (T2)z);
193 } 208 }
@@ -196,126 +211,161 @@ public:
196 static Vec3 FromRGB(unsigned int rgb); 211 static Vec3 FromRGB(unsigned int rgb);
197 unsigned int ToRGB() const; // alpha bits set to zero 212 unsigned int ToRGB() const; // alpha bits set to zero
198 213
199 static Vec3 AssignToAll(const T& f) 214 static Vec3 AssignToAll(const T& f) {
200 {
201 return MakeVec(f, f, f); 215 return MakeVec(f, f, f);
202 } 216 }
203 217
204 void Write(T a[3]) 218 void Write(T a[3]) {
205 { 219 a[0] = x;
206 a[0] = x; a[1] = y; a[2] = z; 220 a[1] = y;
221 a[2] = z;
207 } 222 }
208 223
209 Vec3<decltype(T{}+T{})> operator +(const Vec3 &other) const 224 Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
210 { 225 return MakeVec(x + other.x, y + other.y, z + other.z);
211 return MakeVec(x+other.x, y+other.y, z+other.z);
212 } 226 }
213 void operator += (const Vec3 &other) 227 void operator+=(const Vec3& other) {
214 { 228 x += other.x;
215 x+=other.x; y+=other.y; z+=other.z; 229 y += other.y;
230 z += other.z;
216 } 231 }
217 Vec3<decltype(T{}-T{})> operator -(const Vec3 &other) const 232 Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
218 { 233 return MakeVec(x - other.x, y - other.y, z - other.z);
219 return MakeVec(x-other.x, y-other.y, z-other.z);
220 } 234 }
221 void operator -= (const Vec3 &other) 235 void operator-=(const Vec3& other) {
222 { 236 x -= other.x;
223 x-=other.x; y-=other.y; z-=other.z; 237 y -= other.y;
238 z -= other.z;
224 } 239 }
225 template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> 240 template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type>
226 Vec3<decltype(-T{})> operator -() const 241 Vec3<decltype(-T{})> operator-() const {
227 { 242 return MakeVec(-x, -y, -z);
228 return MakeVec(-x,-y,-z);
229 } 243 }
230 Vec3<decltype(T{}*T{})> operator * (const Vec3 &other) const 244 Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
231 { 245 return MakeVec(x * other.x, y * other.y, z * other.z);
232 return MakeVec(x*other.x, y*other.y, z*other.z);
233 } 246 }
234 template<typename V> 247 template <typename V>
235 Vec3<decltype(T{}*V{})> operator * (const V& f) const 248 Vec3<decltype(T{} * V{})> operator*(const V& f) const {
236 { 249 return MakeVec(x * f, y * f, z * f);
237 return MakeVec(x*f,y*f,z*f);
238 } 250 }
239 template<typename V> 251 template <typename V>
240 void operator *= (const V& f) 252 void operator*=(const V& f) {
241 { 253 x *= f;
242 x*=f; y*=f; z*=f; 254 y *= f;
255 z *= f;
243 } 256 }
244 template<typename V> 257 template <typename V>
245 Vec3<decltype(T{}/V{})> operator / (const V& f) const 258 Vec3<decltype(T{} / V{})> operator/(const V& f) const {
246 { 259 return MakeVec(x / f, y / f, z / f);
247 return MakeVec(x/f,y/f,z/f);
248 } 260 }
249 template<typename V> 261 template <typename V>
250 void operator /= (const V& f) 262 void operator/=(const V& f) {
251 {
252 *this = *this / f; 263 *this = *this / f;
253 } 264 }
254 265
255 T Length2() const 266 T Length2() const {
256 { 267 return x * x + y * y + z * z;
257 return x*x + y*y + z*z;
258 } 268 }
259 269
260 // Only implemented for T=float 270 // Only implemented for T=float
261 float Length() const; 271 float Length() const;
262 void SetLength(const float l); 272 void SetLength(const float l);
263 Vec3 WithLength(const float l) const; 273 Vec3 WithLength(const float l) const;
264 float Distance2To(Vec3 &other); 274 float Distance2To(Vec3& other);
265 Vec3 Normalized() const; 275 Vec3 Normalized() const;
266 float Normalize(); // returns the previous length, which is often useful 276 float Normalize(); // returns the previous length, which is often useful
267 277
268 T& operator [] (int i) //allow vector[2] = 3 (vector.z=3) 278 T& operator[](int i) // allow vector[2] = 3 (vector.z=3)
269 { 279 {
270 return *((&x) + i); 280 return *((&x) + i);
271 } 281 }
272 T operator [] (const int i) const 282 T operator[](const int i) const {
273 {
274 return *((&x) + i); 283 return *((&x) + i);
275 } 284 }
276 285
277 void SetZero() 286 void SetZero() {
278 { 287 x = 0;
279 x=0; y=0; z=0; 288 y = 0;
289 z = 0;
280 } 290 }
281 291
282 // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates) 292 // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates)
283 T& u() { return x; } 293 T& u() {
284 T& v() { return y; } 294 return x;
285 T& w() { return z; } 295 }
296 T& v() {
297 return y;
298 }
299 T& w() {
300 return z;
301 }
286 302
287 T& r() { return x; } 303 T& r() {
288 T& g() { return y; } 304 return x;
289 T& b() { return z; } 305 }
306 T& g() {
307 return y;
308 }
309 T& b() {
310 return z;
311 }
290 312
291 T& s() { return x; } 313 T& s() {
292 T& t() { return y; } 314 return x;
293 T& q() { return z; } 315 }
316 T& t() {
317 return y;
318 }
319 T& q() {
320 return z;
321 }
294 322
295 const T& u() const { return x; } 323 const T& u() const {
296 const T& v() const { return y; } 324 return x;
297 const T& w() const { return z; } 325 }
326 const T& v() const {
327 return y;
328 }
329 const T& w() const {
330 return z;
331 }
298 332
299 const T& r() const { return x; } 333 const T& r() const {
300 const T& g() const { return y; } 334 return x;
301 const T& b() const { return z; } 335 }
336 const T& g() const {
337 return y;
338 }
339 const T& b() const {
340 return z;
341 }
302 342
303 const T& s() const { return x; } 343 const T& s() const {
304 const T& t() const { return y; } 344 return x;
305 const T& q() const { return z; } 345 }
346 const T& t() const {
347 return y;
348 }
349 const T& q() const {
350 return z;
351 }
306 352
307 // swizzlers - create a subvector of specific components 353// swizzlers - create a subvector of specific components
308 // e.g. Vec2 uv() { return Vec2(x,y); } 354// e.g. Vec2 uv() { return Vec2(x,y); }
309 // _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all component names (x<->r) and permutations (xy<->yx) 355// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
310#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); } 356// component names (x<->r) and permutations (xy<->yx)
311#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ 357#define _DEFINE_SWIZZLER2(a, b, name) \
312 _DEFINE_SWIZZLER2(a, b, a##b); \ 358 const Vec2<T> name() const { \
313 _DEFINE_SWIZZLER2(a, b, a2##b2); \ 359 return Vec2<T>(a, b); \
314 _DEFINE_SWIZZLER2(a, b, a3##b3); \ 360 }
315 _DEFINE_SWIZZLER2(a, b, a4##b4); \ 361#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
316 _DEFINE_SWIZZLER2(b, a, b##a); \ 362 _DEFINE_SWIZZLER2(a, b, a##b); \
317 _DEFINE_SWIZZLER2(b, a, b2##a2); \ 363 _DEFINE_SWIZZLER2(a, b, a2##b2); \
318 _DEFINE_SWIZZLER2(b, a, b3##a3); \ 364 _DEFINE_SWIZZLER2(a, b, a3##b3); \
365 _DEFINE_SWIZZLER2(a, b, a4##b4); \
366 _DEFINE_SWIZZLER2(b, a, b##a); \
367 _DEFINE_SWIZZLER2(b, a, b2##a2); \
368 _DEFINE_SWIZZLER2(b, a, b3##a3); \
319 _DEFINE_SWIZZLER2(b, a, b4##a4) 369 _DEFINE_SWIZZLER2(b, a, b4##a4)
320 370
321 DEFINE_SWIZZLER2(x, y, r, g, u, v, s, t); 371 DEFINE_SWIZZLER2(x, y, r, g, u, v, s, t);
@@ -325,41 +375,40 @@ public:
325#undef _DEFINE_SWIZZLER2 375#undef _DEFINE_SWIZZLER2
326}; 376};
327 377
328template<typename T, typename V> 378template <typename T, typename V>
329Vec3<T> operator * (const V& f, const Vec3<T>& vec) 379Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
330{ 380 return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
331 return Vec3<T>(f*vec.x,f*vec.y,f*vec.z);
332} 381}
333 382
334template<> 383template <>
335inline float Vec3<float>::Length() const { 384inline float Vec3<float>::Length() const {
336 return std::sqrt(x * x + y * y + z * z); 385 return std::sqrt(x * x + y * y + z * z);
337} 386}
338 387
339template<> 388template <>
340inline Vec3<float> Vec3<float>::Normalized() const { 389inline Vec3<float> Vec3<float>::Normalized() const {
341 return *this / Length(); 390 return *this / Length();
342} 391}
343 392
344
345typedef Vec3<float> Vec3f; 393typedef Vec3<float> Vec3f;
346 394
347template<typename T> 395template <typename T>
348class Vec4 396class Vec4 {
349{
350public: 397public:
351 T x; 398 T x;
352 T y; 399 T y;
353 T z; 400 T z;
354 T w; 401 T w;
355 402
356 T* AsArray() { return &x; } 403 T* AsArray() {
404 return &x;
405 }
357 406
358 Vec4() = default; 407 Vec4() = default;
359 Vec4(const T a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {} 408 Vec4(const T a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {}
360 Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {} 409 Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {}
361 410
362 template<typename T2> 411 template <typename T2>
363 Vec4<T2> Cast() const { 412 Vec4<T2> Cast() const {
364 return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w); 413 return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w);
365 } 414 }
@@ -372,81 +421,79 @@ public:
372 return Vec4<T>(f, f, f, f); 421 return Vec4<T>(f, f, f, f);
373 } 422 }
374 423
375 void Write(T a[4]) 424 void Write(T a[4]) {
376 { 425 a[0] = x;
377 a[0] = x; a[1] = y; a[2] = z; a[3] = w; 426 a[1] = y;
427 a[2] = z;
428 a[3] = w;
378 } 429 }
379 430
380 Vec4<decltype(T{}+T{})> operator +(const Vec4& other) const 431 Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
381 { 432 return MakeVec(x + other.x, y + other.y, z + other.z, w + other.w);
382 return MakeVec(x+other.x, y+other.y, z+other.z, w+other.w);
383 } 433 }
384 void operator += (const Vec4& other) 434 void operator+=(const Vec4& other) {
385 { 435 x += other.x;
386 x+=other.x; y+=other.y; z+=other.z; w+=other.w; 436 y += other.y;
437 z += other.z;
438 w += other.w;
387 } 439 }
388 Vec4<decltype(T{}-T{})> operator -(const Vec4 &other) const 440 Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
389 { 441 return MakeVec(x - other.x, y - other.y, z - other.z, w - other.w);
390 return MakeVec(x-other.x, y-other.y, z-other.z, w-other.w);
391 } 442 }
392 void operator -= (const Vec4 &other) 443 void operator-=(const Vec4& other) {
393 { 444 x -= other.x;
394 x-=other.x; y-=other.y; z-=other.z; w-=other.w; 445 y -= other.y;
446 z -= other.z;
447 w -= other.w;
395 } 448 }
396 template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> 449 template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type>
397 Vec4<decltype(-T{})> operator -() const 450 Vec4<decltype(-T{})> operator-() const {
398 { 451 return MakeVec(-x, -y, -z, -w);
399 return MakeVec(-x,-y,-z,-w);
400 } 452 }
401 Vec4<decltype(T{}*T{})> operator * (const Vec4 &other) const 453 Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
402 { 454 return MakeVec(x * other.x, y * other.y, z * other.z, w * other.w);
403 return MakeVec(x*other.x, y*other.y, z*other.z, w*other.w);
404 } 455 }
405 template<typename V> 456 template <typename V>
406 Vec4<decltype(T{}*V{})> operator * (const V& f) const 457 Vec4<decltype(T{} * V{})> operator*(const V& f) const {
407 { 458 return MakeVec(x * f, y * f, z * f, w * f);
408 return MakeVec(x*f,y*f,z*f,w*f);
409 } 459 }
410 template<typename V> 460 template <typename V>
411 void operator *= (const V& f) 461 void operator*=(const V& f) {
412 { 462 x *= f;
413 x*=f; y*=f; z*=f; w*=f; 463 y *= f;
464 z *= f;
465 w *= f;
414 } 466 }
415 template<typename V> 467 template <typename V>
416 Vec4<decltype(T{}/V{})> operator / (const V& f) const 468 Vec4<decltype(T{} / V{})> operator/(const V& f) const {
417 { 469 return MakeVec(x / f, y / f, z / f, w / f);
418 return MakeVec(x/f,y/f,z/f,w/f);
419 } 470 }
420 template<typename V> 471 template <typename V>
421 void operator /= (const V& f) 472 void operator/=(const V& f) {
422 {
423 *this = *this / f; 473 *this = *this / f;
424 } 474 }
425 475
426 T Length2() const 476 T Length2() const {
427 { 477 return x * x + y * y + z * z + w * w;
428 return x*x + y*y + z*z + w*w;
429 } 478 }
430 479
431 // Only implemented for T=float 480 // Only implemented for T=float
432 float Length() const; 481 float Length() const;
433 void SetLength(const float l); 482 void SetLength(const float l);
434 Vec4 WithLength(const float l) const; 483 Vec4 WithLength(const float l) const;
435 float Distance2To(Vec4 &other); 484 float Distance2To(Vec4& other);
436 Vec4 Normalized() const; 485 Vec4 Normalized() const;
437 float Normalize(); // returns the previous length, which is often useful 486 float Normalize(); // returns the previous length, which is often useful
438 487
439 T& operator [] (int i) //allow vector[2] = 3 (vector.z=3) 488 T& operator[](int i) // allow vector[2] = 3 (vector.z=3)
440 { 489 {
441 return *((&x) + i); 490 return *((&x) + i);
442 } 491 }
443 T operator [] (const int i) const 492 T operator[](const int i) const {
444 {
445 return *((&x) + i); 493 return *((&x) + i);
446 } 494 }
447 495
448 void SetZero() 496 void SetZero() {
449 {
450 x = 0; 497 x = 0;
451 y = 0; 498 y = 0;
452 z = 0; 499 z = 0;
@@ -454,30 +501,50 @@ public:
454 } 501 }
455 502
456 // Common alias: RGBA (colors) 503 // Common alias: RGBA (colors)
457 T& r() { return x; } 504 T& r() {
458 T& g() { return y; } 505 return x;
459 T& b() { return z; } 506 }
460 T& a() { return w; } 507 T& g() {
461 508 return y;
462 const T& r() const { return x; } 509 }
463 const T& g() const { return y; } 510 T& b() {
464 const T& b() const { return z; } 511 return z;
465 const T& a() const { return w; } 512 }
466 513 T& a() {
467 // Swizzlers - Create a subvector of specific components 514 return w;
468 // e.g. Vec2 uv() { return Vec2(x,y); } 515 }
469 516
470 // _DEFINE_SWIZZLER2 defines a single such function 517 const T& r() const {
471 // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) 518 return x;
472 // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx) 519 }
473#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); } 520 const T& g() const {
474#define DEFINE_SWIZZLER2_COMP1(a, a2) \ 521 return y;
475 _DEFINE_SWIZZLER2(a, a, a##a); \ 522 }
523 const T& b() const {
524 return z;
525 }
526 const T& a() const {
527 return w;
528 }
529
530// Swizzlers - Create a subvector of specific components
531// e.g. Vec2 uv() { return Vec2(x,y); }
532
533// _DEFINE_SWIZZLER2 defines a single such function
534// DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r)
535// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
536// permutations (xy<->yx)
537#define _DEFINE_SWIZZLER2(a, b, name) \
538 const Vec2<T> name() const { \
539 return Vec2<T>(a, b); \
540 }
541#define DEFINE_SWIZZLER2_COMP1(a, a2) \
542 _DEFINE_SWIZZLER2(a, a, a##a); \
476 _DEFINE_SWIZZLER2(a, a, a2##a2) 543 _DEFINE_SWIZZLER2(a, a, a2##a2)
477#define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \ 544#define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \
478 _DEFINE_SWIZZLER2(a, b, a##b); \ 545 _DEFINE_SWIZZLER2(a, b, a##b); \
479 _DEFINE_SWIZZLER2(a, b, a2##b2); \ 546 _DEFINE_SWIZZLER2(a, b, a2##b2); \
480 _DEFINE_SWIZZLER2(b, a, b##a); \ 547 _DEFINE_SWIZZLER2(b, a, b##a); \
481 _DEFINE_SWIZZLER2(b, a, b2##a2) 548 _DEFINE_SWIZZLER2(b, a, b2##a2)
482 549
483 DEFINE_SWIZZLER2_COMP2(x, y, r, g); 550 DEFINE_SWIZZLER2_COMP2(x, y, r, g);
@@ -494,22 +561,25 @@ public:
494#undef DEFINE_SWIZZLER2_COMP2 561#undef DEFINE_SWIZZLER2_COMP2
495#undef _DEFINE_SWIZZLER2 562#undef _DEFINE_SWIZZLER2
496 563
497#define _DEFINE_SWIZZLER3(a, b, c, name) const Vec3<T> name() const { return Vec3<T>(a, b, c); } 564#define _DEFINE_SWIZZLER3(a, b, c, name) \
498#define DEFINE_SWIZZLER3_COMP1(a, a2) \ 565 const Vec3<T> name() const { \
499 _DEFINE_SWIZZLER3(a, a, a, a##a##a); \ 566 return Vec3<T>(a, b, c); \
567 }
568#define DEFINE_SWIZZLER3_COMP1(a, a2) \
569 _DEFINE_SWIZZLER3(a, a, a, a##a##a); \
500 _DEFINE_SWIZZLER3(a, a, a, a2##a2##a2) 570 _DEFINE_SWIZZLER3(a, a, a, a2##a2##a2)
501#define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \ 571#define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \
502 _DEFINE_SWIZZLER3(a, b, c, a##b##c); \ 572 _DEFINE_SWIZZLER3(a, b, c, a##b##c); \
503 _DEFINE_SWIZZLER3(a, c, b, a##c##b); \ 573 _DEFINE_SWIZZLER3(a, c, b, a##c##b); \
504 _DEFINE_SWIZZLER3(b, a, c, b##a##c); \ 574 _DEFINE_SWIZZLER3(b, a, c, b##a##c); \
505 _DEFINE_SWIZZLER3(b, c, a, b##c##a); \ 575 _DEFINE_SWIZZLER3(b, c, a, b##c##a); \
506 _DEFINE_SWIZZLER3(c, a, b, c##a##b); \ 576 _DEFINE_SWIZZLER3(c, a, b, c##a##b); \
507 _DEFINE_SWIZZLER3(c, b, a, c##b##a); \ 577 _DEFINE_SWIZZLER3(c, b, a, c##b##a); \
508 _DEFINE_SWIZZLER3(a, b, c, a2##b2##c2); \ 578 _DEFINE_SWIZZLER3(a, b, c, a2##b2##c2); \
509 _DEFINE_SWIZZLER3(a, c, b, a2##c2##b2); \ 579 _DEFINE_SWIZZLER3(a, c, b, a2##c2##b2); \
510 _DEFINE_SWIZZLER3(b, a, c, b2##a2##c2); \ 580 _DEFINE_SWIZZLER3(b, a, c, b2##a2##c2); \
511 _DEFINE_SWIZZLER3(b, c, a, b2##c2##a2); \ 581 _DEFINE_SWIZZLER3(b, c, a, b2##c2##a2); \
512 _DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \ 582 _DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \
513 _DEFINE_SWIZZLER3(c, b, a, c2##b2##a2) 583 _DEFINE_SWIZZLER3(c, b, a, c2##b2##a2)
514 584
515 DEFINE_SWIZZLER3_COMP3(x, y, z, r, g, b); 585 DEFINE_SWIZZLER3_COMP3(x, y, z, r, g, b);
@@ -525,123 +595,104 @@ public:
525#undef _DEFINE_SWIZZLER3 595#undef _DEFINE_SWIZZLER3
526}; 596};
527 597
528 598template <typename T, typename V>
529template<typename T, typename V> 599Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
530Vec4<decltype(V{}*T{})> operator * (const V& f, const Vec4<T>& vec) 600 return MakeVec(f * vec.x, f * vec.y, f * vec.z, f * vec.w);
531{
532 return MakeVec(f*vec.x,f*vec.y,f*vec.z,f*vec.w);
533} 601}
534 602
535typedef Vec4<float> Vec4f; 603typedef Vec4<float> Vec4f;
536 604
537 605template <typename T>
538template<typename T> 606static 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) 607 return a.x * b.x + a.y * b.y;
540{
541 return a.x*b.x + a.y*b.y;
542} 608}
543 609
544template<typename T> 610template <typename T>
545static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) 611static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
546{ 612 return a.x * b.x + a.y * b.y + a.z * b.z;
547 return a.x*b.x + a.y*b.y + a.z*b.z;
548} 613}
549 614
550template<typename T> 615template <typename T>
551static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) 616static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
552{ 617 return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
553 return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
554} 618}
555 619
556template<typename T> 620template <typename T>
557static inline Vec3<decltype(T{}*T{}-T{}*T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) 621static inline Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) {
558{ 622 return MakeVec(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
559 return MakeVec(a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x);
560} 623}
561 624
562// linear interpolation via float: 0.0=begin, 1.0=end 625// linear interpolation via float: 0.0=begin, 1.0=end
563template<typename X> 626template <typename X>
564static inline decltype(X{}*float{}+X{}*float{}) Lerp(const X& begin, const X& end, const float t) 627static inline decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
565{ 628 const float t) {
566 return begin*(1.f-t) + end*t; 629 return begin * (1.f - t) + end * t;
567} 630}
568 631
569// linear interpolation via int: 0=begin, base=end 632// linear interpolation via int: 0=begin, base=end
570template<typename X, int base> 633template <typename X, int base>
571static inline decltype((X{}*int{}+X{}*int{}) / base) LerpInt(const X& begin, const X& end, const int t) 634static inline decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end,
572{ 635 const int t) {
573 return (begin*(base-t) + end*t) / base; 636 return (begin * (base - t) + end * t) / base;
574} 637}
575 638
576// Utility vector factories 639// Utility vector factories
577template<typename T> 640template <typename T>
578static inline Vec2<T> MakeVec(const T& x, const T& y) 641static inline Vec2<T> MakeVec(const T& x, const T& y) {
579{
580 return Vec2<T>{x, y}; 642 return Vec2<T>{x, y};
581} 643}
582 644
583template<typename T> 645template <typename T>
584static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) 646static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
585{
586 return Vec3<T>{x, y, z}; 647 return Vec3<T>{x, y, z};
587} 648}
588 649
589template<typename T> 650template <typename T>
590static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) 651static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
591{
592 return MakeVec(x, y, zw[0], zw[1]); 652 return MakeVec(x, y, zw[0], zw[1]);
593} 653}
594 654
595template<typename T> 655template <typename T>
596static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) 656static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
597{
598 return MakeVec(xy[0], xy[1], z); 657 return MakeVec(xy[0], xy[1], z);
599} 658}
600 659
601template<typename T> 660template <typename T>
602static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) 661static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
603{
604 return MakeVec(x, yz[0], yz[1]); 662 return MakeVec(x, yz[0], yz[1]);
605} 663}
606 664
607template<typename T> 665template <typename T>
608static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) 666static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
609{
610 return Vec4<T>{x, y, z, w}; 667 return Vec4<T>{x, y, z, w};
611} 668}
612 669
613template<typename T> 670template <typename T>
614static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) 671static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
615{
616 return MakeVec(xy[0], xy[1], z, w); 672 return MakeVec(xy[0], xy[1], z, w);
617} 673}
618 674
619template<typename T> 675template <typename T>
620static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) 676static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
621{
622 return MakeVec(x, yz[0], yz[1], w); 677 return MakeVec(x, yz[0], yz[1], w);
623} 678}
624 679
625// NOTE: This has priority over "Vec2<Vec2<T>> MakeVec(const Vec2<T>& x, const Vec2<T>& y)". 680// NOTE: This has priority over "Vec2<Vec2<T>> MakeVec(const Vec2<T>& x, const Vec2<T>& y)".
626// Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error 681// Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error
627// out soon enough due to misuse of the returned structure. 682// out soon enough due to misuse of the returned structure.
628template<typename T> 683template <typename T>
629static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) 684static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
630{
631 return MakeVec(xy[0], xy[1], zw[0], zw[1]); 685 return MakeVec(xy[0], xy[1], zw[0], zw[1]);
632} 686}
633 687
634template<typename T> 688template <typename T>
635static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) 689static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
636{
637 return MakeVec(xyz[0], xyz[1], xyz[2], w); 690 return MakeVec(xyz[0], xyz[1], xyz[2], w);
638} 691}
639 692
640template<typename T> 693template <typename T>
641static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) 694static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
642{
643 return MakeVec(x, yzw[0], yzw[1], yzw[2]); 695 return MakeVec(x, yzw[0], yzw[1], yzw[2]);
644} 696}
645 697
646
647} // namespace 698} // namespace
diff --git a/src/common/x64/abi.cpp b/src/common/x64/abi.cpp
index 955eb86ce..504b9c940 100644
--- a/src/common/x64/abi.cpp
+++ b/src/common/x64/abi.cpp
@@ -22,7 +22,8 @@ using namespace Gen;
22 22
23// Shared code between Win64 and Unix64 23// Shared code between Win64 and Unix64
24 24
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..6ddf9b70c 100644
--- a/src/common/x64/cpu_detect.cpp
+++ b/src/common/x64/cpu_detect.cpp
@@ -5,9 +5,7 @@
5#include <cstring> 5#include <cstring>
6#include <string> 6#include <string>
7#include <thread> 7#include <thread>
8
9#include "common/common_types.h" 8#include "common/common_types.h"
10
11#include "cpu_detect.h" 9#include "cpu_detect.h"
12 10
13namespace Common { 11namespace Common {
@@ -15,8 +13,8 @@ namespace Common {
15#ifndef _MSC_VER 13#ifndef _MSC_VER
16 14
17#ifdef __FreeBSD__ 15#ifdef __FreeBSD__
18#include <sys/types.h>
19#include <machine/cpufunc.h> 16#include <machine/cpufunc.h>
17#include <sys/types.h>
20#endif 18#endif
21 19
22static inline void __cpuidex(int info[4], int function_id, int subfunction_id) { 20static inline void __cpuidex(int info[4], int function_id, int subfunction_id) {
@@ -26,15 +24,9 @@ static inline void __cpuidex(int info[4], int function_id, int subfunction_id) {
26#else 24#else
27 info[0] = function_id; // eax 25 info[0] = function_id; // eax
28 info[2] = subfunction_id; // ecx 26 info[2] = subfunction_id; // ecx
29 __asm__( 27 __asm__("cpuid"
30 "cpuid" 28 : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3])
31 : "=a" (info[0]), 29 : "a"(function_id), "c"(subfunction_id));
32 "=b" (info[1]),
33 "=c" (info[2]),
34 "=d" (info[3])
35 : "a" (function_id),
36 "c" (subfunction_id)
37 );
38#endif 30#endif
39} 31}
40 32
@@ -88,14 +80,22 @@ static CPUCaps Detect() {
88 if (max_std_fn >= 1) { 80 if (max_std_fn >= 1) {
89 __cpuid(cpu_id, 0x00000001); 81 __cpuid(cpu_id, 0x00000001);
90 82
91 if ((cpu_id[3] >> 25) & 1) caps.sse = true; 83 if ((cpu_id[3] >> 25) & 1)
92 if ((cpu_id[3] >> 26) & 1) caps.sse2 = true; 84 caps.sse = true;
93 if ((cpu_id[2]) & 1) caps.sse3 = true; 85 if ((cpu_id[3] >> 26) & 1)
94 if ((cpu_id[2] >> 9) & 1) caps.ssse3 = true; 86 caps.sse2 = true;
95 if ((cpu_id[2] >> 19) & 1) caps.sse4_1 = true; 87 if ((cpu_id[2]) & 1)
96 if ((cpu_id[2] >> 20) & 1) caps.sse4_2 = true; 88 caps.sse3 = true;
97 if ((cpu_id[2] >> 22) & 1) caps.movbe = true; 89 if ((cpu_id[2] >> 9) & 1)
98 if ((cpu_id[2] >> 25) & 1) caps.aes = true; 90 caps.ssse3 = true;
91 if ((cpu_id[2] >> 19) & 1)
92 caps.sse4_1 = true;
93 if ((cpu_id[2] >> 20) & 1)
94 caps.sse4_2 = true;
95 if ((cpu_id[2] >> 22) & 1)
96 caps.movbe = true;
97 if ((cpu_id[2] >> 25) & 1)
98 caps.aes = true;
99 99
100 if ((cpu_id[3] >> 24) & 1) { 100 if ((cpu_id[3] >> 24) & 1) {
101 caps.fxsave_fxrstor = true; 101 caps.fxsave_fxrstor = true;
@@ -140,10 +140,14 @@ static CPUCaps Detect() {
140 if (max_ex_fn >= 0x80000001) { 140 if (max_ex_fn >= 0x80000001) {
141 // Check for more features 141 // Check for more features
142 __cpuid(cpu_id, 0x80000001); 142 __cpuid(cpu_id, 0x80000001);
143 if (cpu_id[2] & 1) caps.lahf_sahf_64 = true; 143 if (cpu_id[2] & 1)
144 if ((cpu_id[2] >> 5) & 1) caps.lzcnt = true; 144 caps.lahf_sahf_64 = true;
145 if ((cpu_id[2] >> 16) & 1) caps.fma4 = true; 145 if ((cpu_id[2] >> 5) & 1)
146 if ((cpu_id[3] >> 29) & 1) caps.long_mode = true; 146 caps.lzcnt = true;
147 if ((cpu_id[2] >> 16) & 1)
148 caps.fma4 = true;
149 if ((cpu_id[3] >> 29) & 1)
150 caps.long_mode = true;
147 } 151 }
148 152
149 return caps; 153 return caps;
@@ -162,24 +166,38 @@ std::string GetCPUCapsString() {
162 sum += caps.brand_string; 166 sum += caps.brand_string;
163 sum += ")"; 167 sum += ")";
164 168
165 if (caps.sse) sum += ", SSE"; 169 if (caps.sse)
170 sum += ", SSE";
166 if (caps.sse2) { 171 if (caps.sse2) {
167 sum += ", SSE2"; 172 sum += ", SSE2";
168 if (!caps.flush_to_zero) sum += " (without DAZ)"; 173 if (!caps.flush_to_zero)
174 sum += " (without DAZ)";
169 } 175 }
170 176
171 if (caps.sse3) sum += ", SSE3"; 177 if (caps.sse3)
172 if (caps.ssse3) sum += ", SSSE3"; 178 sum += ", SSE3";
173 if (caps.sse4_1) sum += ", SSE4.1"; 179 if (caps.ssse3)
174 if (caps.sse4_2) sum += ", SSE4.2"; 180 sum += ", SSSE3";
175 if (caps.avx) sum += ", AVX"; 181 if (caps.sse4_1)
176 if (caps.avx2) sum += ", AVX2"; 182 sum += ", SSE4.1";
177 if (caps.bmi1) sum += ", BMI1"; 183 if (caps.sse4_2)
178 if (caps.bmi2) sum += ", BMI2"; 184 sum += ", SSE4.2";
179 if (caps.fma) sum += ", FMA"; 185 if (caps.avx)
180 if (caps.aes) sum += ", AES"; 186 sum += ", AVX";
181 if (caps.movbe) sum += ", MOVBE"; 187 if (caps.avx2)
182 if (caps.long_mode) sum += ", 64-bit support"; 188 sum += ", AVX2";
189 if (caps.bmi1)
190 sum += ", BMI1";
191 if (caps.bmi2)
192 sum += ", BMI2";
193 if (caps.fma)
194 sum += ", FMA";
195 if (caps.aes)
196 sum += ", AES";
197 if (caps.movbe)
198 sum += ", MOVBE";
199 if (caps.long_mode)
200 sum += ", 64-bit support";
183 201
184 return sum; 202 return sum;
185} 203}
diff --git a/src/common/x64/emitter.cpp b/src/common/x64/emitter.cpp
index 5662f7f86..f5930abec 100644
--- a/src/common/x64/emitter.cpp
+++ b/src/common/x64/emitter.cpp
@@ -17,188 +17,169 @@
17 17
18#include <cinttypes> 18#include <cinttypes>
19#include <cstring> 19#include <cstring>
20 20#include "abi.h"
21#include "common/assert.h" 21#include "common/assert.h"
22#include "common/logging/log.h" 22#include "common/logging/log.h"
23#include "common/memory_util.h" 23#include "common/memory_util.h"
24
25#include "abi.h"
26#include "cpu_detect.h" 24#include "cpu_detect.h"
27#include "emitter.h" 25#include "emitter.h"
28 26
29namespace Gen 27namespace Gen {
30{
31 28
32struct NormalOpDef 29struct NormalOpDef {
33{
34 u8 toRm8, toRm32, fromRm8, fromRm32, imm8, imm32, simm8, eaximm8, eaximm32, ext; 30 u8 toRm8, toRm32, fromRm8, fromRm32, imm8, imm32, simm8, eaximm8, eaximm32, ext;
35}; 31};
36 32
37// 0xCC is code for invalid combination of immediates 33// 0xCC is code for invalid combination of immediates
38static const NormalOpDef normalops[11] = 34static const NormalOpDef normalops[11] = {
39{ 35 {0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x83, 0x04, 0x05, 0}, // ADD
40 {0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x83, 0x04, 0x05, 0}, //ADD 36 {0x10, 0x11, 0x12, 0x13, 0x80, 0x81, 0x83, 0x14, 0x15, 2}, // ADC
41 {0x10, 0x11, 0x12, 0x13, 0x80, 0x81, 0x83, 0x14, 0x15, 2}, //ADC
42 37
43 {0x28, 0x29, 0x2A, 0x2B, 0x80, 0x81, 0x83, 0x2C, 0x2D, 5}, //SUB 38 {0x28, 0x29, 0x2A, 0x2B, 0x80, 0x81, 0x83, 0x2C, 0x2D, 5}, // SUB
44 {0x18, 0x19, 0x1A, 0x1B, 0x80, 0x81, 0x83, 0x1C, 0x1D, 3}, //SBB 39 {0x18, 0x19, 0x1A, 0x1B, 0x80, 0x81, 0x83, 0x1C, 0x1D, 3}, // SBB
45 40
46 {0x20, 0x21, 0x22, 0x23, 0x80, 0x81, 0x83, 0x24, 0x25, 4}, //AND 41 {0x20, 0x21, 0x22, 0x23, 0x80, 0x81, 0x83, 0x24, 0x25, 4}, // AND
47 {0x08, 0x09, 0x0A, 0x0B, 0x80, 0x81, 0x83, 0x0C, 0x0D, 1}, //OR 42 {0x08, 0x09, 0x0A, 0x0B, 0x80, 0x81, 0x83, 0x0C, 0x0D, 1}, // OR
48 43
49 {0x30, 0x31, 0x32, 0x33, 0x80, 0x81, 0x83, 0x34, 0x35, 6}, //XOR 44 {0x30, 0x31, 0x32, 0x33, 0x80, 0x81, 0x83, 0x34, 0x35, 6}, // XOR
50 {0x88, 0x89, 0x8A, 0x8B, 0xC6, 0xC7, 0xCC, 0xCC, 0xCC, 0}, //MOV 45 {0x88, 0x89, 0x8A, 0x8B, 0xC6, 0xC7, 0xCC, 0xCC, 0xCC, 0}, // MOV
51 46
52 {0x84, 0x85, 0x84, 0x85, 0xF6, 0xF7, 0xCC, 0xA8, 0xA9, 0}, //TEST (to == from) 47 {0x84, 0x85, 0x84, 0x85, 0xF6, 0xF7, 0xCC, 0xA8, 0xA9, 0}, // TEST (to == from)
53 {0x38, 0x39, 0x3A, 0x3B, 0x80, 0x81, 0x83, 0x3C, 0x3D, 7}, //CMP 48 {0x38, 0x39, 0x3A, 0x3B, 0x80, 0x81, 0x83, 0x3C, 0x3D, 7}, // CMP
54 49
55 {0x86, 0x87, 0x86, 0x87, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 7}, //XCHG 50 {0x86, 0x87, 0x86, 0x87, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 7}, // XCHG
56}; 51};
57 52
58enum NormalSSEOps 53enum NormalSSEOps {
59{ 54 sseCMP = 0xC2,
60 sseCMP = 0xC2, 55 sseADD = 0x58, // ADD
61 sseADD = 0x58, //ADD 56 sseSUB = 0x5C, // SUB
62 sseSUB = 0x5C, //SUB 57 sseAND = 0x54, // AND
63 sseAND = 0x54, //AND 58 sseANDN = 0x55, // ANDN
64 sseANDN = 0x55, //ANDN 59 sseOR = 0x56,
65 sseOR = 0x56, 60 sseXOR = 0x57,
66 sseXOR = 0x57, 61 sseMUL = 0x59, // MUL
67 sseMUL = 0x59, //MUL 62 sseDIV = 0x5E, // DIV
68 sseDIV = 0x5E, //DIV 63 sseMIN = 0x5D, // MIN
69 sseMIN = 0x5D, //MIN 64 sseMAX = 0x5F, // MAX
70 sseMAX = 0x5F, //MAX 65 sseCOMIS = 0x2F, // COMIS
71 sseCOMIS = 0x2F, //COMIS 66 sseUCOMIS = 0x2E, // UCOMIS
72 sseUCOMIS = 0x2E, //UCOMIS 67 sseSQRT = 0x51, // SQRT
73 sseSQRT = 0x51, //SQRT 68 sseRSQRT = 0x52, // RSQRT (NO DOUBLE PRECISION!!!)
74 sseRSQRT = 0x52, //RSQRT (NO DOUBLE PRECISION!!!) 69 sseRCP = 0x53, // RCP
75 sseRCP = 0x53, //RCP 70 sseMOVAPfromRM = 0x28, // MOVAP from RM
76 sseMOVAPfromRM = 0x28, //MOVAP from RM 71 sseMOVAPtoRM = 0x29, // MOVAP to RM
77 sseMOVAPtoRM = 0x29, //MOVAP to RM 72 sseMOVUPfromRM = 0x10, // MOVUP from RM
78 sseMOVUPfromRM = 0x10, //MOVUP from RM 73 sseMOVUPtoRM = 0x11, // MOVUP to RM
79 sseMOVUPtoRM = 0x11, //MOVUP to RM 74 sseMOVLPfromRM = 0x12,
80 sseMOVLPfromRM= 0x12, 75 sseMOVLPtoRM = 0x13,
81 sseMOVLPtoRM = 0x13, 76 sseMOVHPfromRM = 0x16,
82 sseMOVHPfromRM= 0x16, 77 sseMOVHPtoRM = 0x17,
83 sseMOVHPtoRM = 0x17, 78 sseMOVHLPS = 0x12,
84 sseMOVHLPS = 0x12, 79 sseMOVLHPS = 0x16,
85 sseMOVLHPS = 0x16,
86 sseMOVDQfromRM = 0x6F, 80 sseMOVDQfromRM = 0x6F,
87 sseMOVDQtoRM = 0x7F, 81 sseMOVDQtoRM = 0x7F,
88 sseMASKMOVDQU = 0xF7, 82 sseMASKMOVDQU = 0xF7,
89 sseLDDQU = 0xF0, 83 sseLDDQU = 0xF0,
90 sseSHUF = 0xC6, 84 sseSHUF = 0xC6,
91 sseMOVNTDQ = 0xE7, 85 sseMOVNTDQ = 0xE7,
92 sseMOVNTP = 0x2B, 86 sseMOVNTP = 0x2B,
93 sseHADD = 0x7C, 87 sseHADD = 0x7C,
94}; 88};
95 89
96 90void XEmitter::SetCodePtr(u8* ptr) {
97void XEmitter::SetCodePtr(u8 *ptr)
98{
99 code = ptr; 91 code = ptr;
100} 92}
101 93
102const u8 *XEmitter::GetCodePtr() const 94const u8* XEmitter::GetCodePtr() const {
103{
104 return code; 95 return code;
105} 96}
106 97
107u8 *XEmitter::GetWritableCodePtr() 98u8* XEmitter::GetWritableCodePtr() {
108{
109 return code; 99 return code;
110} 100}
111 101
112void XEmitter::Write8(u8 value) 102void XEmitter::Write8(u8 value) {
113{
114 *code++ = value; 103 *code++ = value;
115} 104}
116 105
117void XEmitter::Write16(u16 value) 106void XEmitter::Write16(u16 value) {
118{
119 std::memcpy(code, &value, sizeof(u16)); 107 std::memcpy(code, &value, sizeof(u16));
120 code += sizeof(u16); 108 code += sizeof(u16);
121} 109}
122 110
123void XEmitter::Write32(u32 value) 111void XEmitter::Write32(u32 value) {
124{
125 std::memcpy(code, &value, sizeof(u32)); 112 std::memcpy(code, &value, sizeof(u32));
126 code += sizeof(u32); 113 code += sizeof(u32);
127} 114}
128 115
129void XEmitter::Write64(u64 value) 116void XEmitter::Write64(u64 value) {
130{
131 std::memcpy(code, &value, sizeof(u64)); 117 std::memcpy(code, &value, sizeof(u64));
132 code += sizeof(u64); 118 code += sizeof(u64);
133} 119}
134 120
135void XEmitter::ReserveCodeSpace(int bytes) 121void XEmitter::ReserveCodeSpace(int bytes) {
136{
137 for (int i = 0; i < bytes; i++) 122 for (int i = 0; i < bytes; i++)
138 *code++ = 0xCC; 123 *code++ = 0xCC;
139} 124}
140 125
141const u8 *XEmitter::AlignCode4() 126const u8* XEmitter::AlignCode4() {
142{
143 int c = int((u64)code & 3); 127 int c = int((u64)code & 3);
144 if (c) 128 if (c)
145 ReserveCodeSpace(4-c); 129 ReserveCodeSpace(4 - c);
146 return code; 130 return code;
147} 131}
148 132
149const u8 *XEmitter::AlignCode16() 133const u8* XEmitter::AlignCode16() {
150{
151 int c = int((u64)code & 15); 134 int c = int((u64)code & 15);
152 if (c) 135 if (c)
153 ReserveCodeSpace(16-c); 136 ReserveCodeSpace(16 - c);
154 return code; 137 return code;
155} 138}
156 139
157const u8 *XEmitter::AlignCodePage() 140const u8* XEmitter::AlignCodePage() {
158{
159 int c = int((u64)code & 4095); 141 int c = int((u64)code & 4095);
160 if (c) 142 if (c)
161 ReserveCodeSpace(4096-c); 143 ReserveCodeSpace(4096 - c);
162 return code; 144 return code;
163} 145}
164 146
165// This operation modifies flags; check to see the flags are locked. 147// This operation modifies flags; check to see the flags are locked.
166// If the flags are locked, we should immediately and loudly fail before 148// If the flags are locked, we should immediately and loudly fail before
167// causing a subtle JIT bug. 149// causing a subtle JIT bug.
168void XEmitter::CheckFlags() 150void XEmitter::CheckFlags() {
169{
170 ASSERT_MSG(!flags_locked, "Attempt to modify flags while flags locked!"); 151 ASSERT_MSG(!flags_locked, "Attempt to modify flags while flags locked!");
171} 152}
172 153
173void XEmitter::WriteModRM(int mod, int reg, int rm) 154void XEmitter::WriteModRM(int mod, int reg, int rm) {
174{
175 Write8((u8)((mod << 6) | ((reg & 7) << 3) | (rm & 7))); 155 Write8((u8)((mod << 6) | ((reg & 7) << 3) | (rm & 7)));
176} 156}
177 157
178void XEmitter::WriteSIB(int scale, int index, int base) 158void XEmitter::WriteSIB(int scale, int index, int base) {
179{
180 Write8((u8)((scale << 6) | ((index & 7) << 3) | (base & 7))); 159 Write8((u8)((scale << 6) | ((index & 7) << 3) | (base & 7)));
181} 160}
182 161
183void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const 162void OpArg::WriteRex(XEmitter* emit, int opBits, int bits, int customOp) const {
184{ 163 if (customOp == -1)
185 if (customOp == -1) customOp = operandReg; 164 customOp = operandReg;
186#ifdef ARCHITECTURE_x86_64 165#ifdef ARCHITECTURE_x86_64
187 u8 op = 0x40; 166 u8 op = 0x40;
188 // REX.W (whether operation is a 64-bit operation) 167 // REX.W (whether operation is a 64-bit operation)
189 if (opBits == 64) op |= 8; 168 if (opBits == 64)
169 op |= 8;
190 // REX.R (whether ModR/M reg field refers to R8-R15. 170 // REX.R (whether ModR/M reg field refers to R8-R15.
191 if (customOp & 8) op |= 4; 171 if (customOp & 8)
172 op |= 4;
192 // REX.X (whether ModR/M SIB index field refers to R8-R15) 173 // REX.X (whether ModR/M SIB index field refers to R8-R15)
193 if (indexReg & 8) op |= 2; 174 if (indexReg & 8)
175 op |= 2;
194 // REX.B (whether ModR/M rm or SIB base or opcode reg field refers to R8-R15) 176 // REX.B (whether ModR/M rm or SIB base or opcode reg field refers to R8-R15)
195 if (offsetOrBaseReg & 8) op |= 1; 177 if (offsetOrBaseReg & 8)
178 op |= 1;
196 // Write REX if wr have REX bits to write, or if the operation accesses 179 // Write REX if wr have REX bits to write, or if the operation accesses
197 // SIL, DIL, BPL, or SPL. 180 // SIL, DIL, BPL, or SPL.
198 if (op != 0x40 || 181 if (op != 0x40 || (scale == SCALE_NONE && bits == 8 && (offsetOrBaseReg & 0x10c) == 4) ||
199 (scale == SCALE_NONE && bits == 8 && (offsetOrBaseReg & 0x10c) == 4) || 182 (opBits == 8 && (customOp & 0x10c) == 4)) {
200 (opBits == 8 && (customOp & 0x10c) == 4))
201 {
202 emit->Write8(op); 183 emit->Write8(op);
203 // Check the operation doesn't access AH, BH, CH, or DH. 184 // Check the operation doesn't access AH, BH, CH, or DH.
204 DEBUG_ASSERT((offsetOrBaseReg & 0x100) == 0); 185 DEBUG_ASSERT((offsetOrBaseReg & 0x100) == 0);
@@ -214,8 +195,8 @@ void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const
214#endif 195#endif
215} 196}
216 197
217void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, int W) const 198void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm,
218{ 199 int W) const {
219 int R = !(regOp1 & 8); 200 int R = !(regOp1 & 8);
220 int X = !(indexReg & 8); 201 int X = !(indexReg & 8);
221 int B = !(offsetOrBaseReg & 8); 202 int B = !(offsetOrBaseReg & 8);
@@ -223,14 +204,11 @@ void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp
223 int vvvv = (regOp2 == X64Reg::INVALID_REG) ? 0xf : (regOp2 ^ 0xf); 204 int vvvv = (regOp2 == X64Reg::INVALID_REG) ? 0xf : (regOp2 ^ 0xf);
224 205
225 // do we need any VEX fields that only appear in the three-byte form? 206 // do we need any VEX fields that only appear in the three-byte form?
226 if (X == 1 && B == 1 && W == 0 && mmmmm == 1) 207 if (X == 1 && B == 1 && W == 0 && mmmmm == 1) {
227 {
228 u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 2) | pp; 208 u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 2) | pp;
229 emit->Write8(0xC5); 209 emit->Write8(0xC5);
230 emit->Write8(RvvvvLpp); 210 emit->Write8(RvvvvLpp);
231 } 211 } else {
232 else
233 {
234 u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm; 212 u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm;
235 u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 2) | pp; 213 u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 2) | pp;
236 emit->Write8(0xC4); 214 emit->Write8(0xC4);
@@ -239,9 +217,8 @@ void OpArg::WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp
239 } 217 }
240} 218}
241 219
242void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg, 220void OpArg::WriteRest(XEmitter* emit, int extraBytes, X64Reg _operandReg,
243 bool warn_64bit_offset) const 221 bool warn_64bit_offset) const {
244{
245 if (_operandReg == INVALID_REG) 222 if (_operandReg == INVALID_REG)
246 _operandReg = (X64Reg)this->operandReg; 223 _operandReg = (X64Reg)this->operandReg;
247 int mod = 0; 224 int mod = 0;
@@ -249,21 +226,18 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg,
249 bool SIB = false; 226 bool SIB = false;
250 int _offsetOrBaseReg = this->offsetOrBaseReg; 227 int _offsetOrBaseReg = this->offsetOrBaseReg;
251 228
252 if (scale == SCALE_RIP) //Also, on 32-bit, just an immediate address 229 if (scale == SCALE_RIP) // Also, on 32-bit, just an immediate address
253 { 230 {
254 // Oh, RIP addressing. 231 // Oh, RIP addressing.
255 _offsetOrBaseReg = 5; 232 _offsetOrBaseReg = 5;
256 emit->WriteModRM(0, _operandReg, _offsetOrBaseReg); 233 emit->WriteModRM(0, _operandReg, _offsetOrBaseReg);
257 //TODO : add some checks 234// TODO : add some checks
258#ifdef ARCHITECTURE_x86_64 235#ifdef ARCHITECTURE_x86_64
259 u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes; 236 u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes;
260 s64 distance = (s64)offset - (s64)ripAddr; 237 s64 distance = (s64)offset - (s64)ripAddr;
261 ASSERT_MSG( 238 ASSERT_MSG((distance < 0x80000000LL && distance >= -0x80000000LL) || !warn_64bit_offset,
262 (distance < 0x80000000LL && 239 "WriteRest: op out of range (0x%" PRIx64 " uses 0x%" PRIx64 ")", ripAddr,
263 distance >= -0x80000000LL) || 240 offset);
264 !warn_64bit_offset,
265 "WriteRest: op out of range (0x%" PRIx64 " uses 0x%" PRIx64 ")",
266 ripAddr, offset);
267 s32 offs = (s32)distance; 241 s32 offs = (s32)distance;
268 emit->Write32((u32)offs); 242 emit->Write32((u32)offs);
269#else 243#else
@@ -272,66 +246,49 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg,
272 return; 246 return;
273 } 247 }
274 248
275 if (scale == 0) 249 if (scale == 0) {
276 {
277 // Oh, no memory, Just a reg. 250 // Oh, no memory, Just a reg.
278 mod = 3; //11 251 mod = 3; // 11
279 } 252 } else if (scale >= 1) {
280 else if (scale >= 1) 253 // Ah good, no scaling.
281 { 254 if (scale == SCALE_ATREG && !((_offsetOrBaseReg & 7) == 4 || (_offsetOrBaseReg & 7) == 5)) {
282 //Ah good, no scaling. 255 // Okay, we're good. No SIB necessary.
283 if (scale == SCALE_ATREG && !((_offsetOrBaseReg & 7) == 4 || (_offsetOrBaseReg & 7) == 5))
284 {
285 //Okay, we're good. No SIB necessary.
286 int ioff = (int)offset; 256 int ioff = (int)offset;
287 if (ioff == 0) 257 if (ioff == 0) {
288 {
289 mod = 0; 258 mod = 0;
259 } else if (ioff < -128 || ioff > 127) {
260 mod = 2; // 32-bit displacement
261 } else {
262 mod = 1; // 8-bit displacement
290 } 263 }
291 else if (ioff<-128 || ioff>127) 264 } else if (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8) {
292 {
293 mod = 2; //32-bit displacement
294 }
295 else
296 {
297 mod = 1; //8-bit displacement
298 }
299 }
300 else if (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8)
301 {
302 SIB = true; 265 SIB = true;
303 mod = 0; 266 mod = 0;
304 _offsetOrBaseReg = 5; 267 _offsetOrBaseReg = 5;
305 } 268 } else // if (scale != SCALE_ATREG)
306 else //if (scale != SCALE_ATREG)
307 { 269 {
308 if ((_offsetOrBaseReg & 7) == 4) //this would occupy the SIB encoding :( 270 if ((_offsetOrBaseReg & 7) == 4) // this would occupy the SIB encoding :(
309 { 271 {
310 //So we have to fake it with SIB encoding :( 272 // So we have to fake it with SIB encoding :(
311 SIB = true; 273 SIB = true;
312 } 274 }
313 275
314 if (scale >= SCALE_1 && scale < SCALE_ATREG) 276 if (scale >= SCALE_1 && scale < SCALE_ATREG) {
315 {
316 SIB = true; 277 SIB = true;
317 } 278 }
318 279
319 if (scale == SCALE_ATREG && ((_offsetOrBaseReg & 7) == 4)) 280 if (scale == SCALE_ATREG && ((_offsetOrBaseReg & 7) == 4)) {
320 {
321 SIB = true; 281 SIB = true;
322 ireg = _offsetOrBaseReg; 282 ireg = _offsetOrBaseReg;
323 } 283 }
324 284
325 //Okay, we're fine. Just disp encoding. 285 // Okay, we're fine. Just disp encoding.
326 //We need displacement. Which size? 286 // We need displacement. Which size?
327 int ioff = (int)(s64)offset; 287 int ioff = (int)(s64)offset;
328 if (ioff < -128 || ioff > 127) 288 if (ioff < -128 || ioff > 127) {
329 { 289 mod = 2; // 32-bit displacement
330 mod = 2; //32-bit displacement 290 } else {
331 } 291 mod = 1; // 8-bit displacement
332 else
333 {
334 mod = 1; //8-bit displacement
335 } 292 }
336 } 293 }
337 } 294 }
@@ -343,36 +300,55 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg,
343 oreg = 4; 300 oreg = 4;
344 301
345 // TODO(ector): WTF is this if about? I don't remember writing it :-) 302 // TODO(ector): WTF is this if about? I don't remember writing it :-)
346 //if (RIP) 303 // if (RIP)
347 // oreg = 5; 304 // oreg = 5;
348 305
349 emit->WriteModRM(mod, _operandReg&7, oreg&7); 306 emit->WriteModRM(mod, _operandReg & 7, oreg & 7);
350 307
351 if (SIB) 308 if (SIB) {
352 { 309 // SIB byte
353 //SIB byte
354 int ss; 310 int ss;
355 switch (scale) 311 switch (scale) {
356 { 312 case SCALE_NONE:
357 case SCALE_NONE: _offsetOrBaseReg = 4; ss = 0; break; //RSP 313 _offsetOrBaseReg = 4;
358 case SCALE_1: ss = 0; break; 314 ss = 0;
359 case SCALE_2: ss = 1; break; 315 break; // RSP
360 case SCALE_4: ss = 2; break; 316 case SCALE_1:
361 case SCALE_8: ss = 3; break; 317 ss = 0;
362 case SCALE_NOBASE_2: ss = 1; break; 318 break;
363 case SCALE_NOBASE_4: ss = 2; break; 319 case SCALE_2:
364 case SCALE_NOBASE_8: ss = 3; break; 320 ss = 1;
365 case SCALE_ATREG: ss = 0; break; 321 break;
366 default: ASSERT_MSG(0, "Invalid scale for SIB byte"); ss = 0; break; 322 case SCALE_4:
323 ss = 2;
324 break;
325 case SCALE_8:
326 ss = 3;
327 break;
328 case SCALE_NOBASE_2:
329 ss = 1;
330 break;
331 case SCALE_NOBASE_4:
332 ss = 2;
333 break;
334 case SCALE_NOBASE_8:
335 ss = 3;
336 break;
337 case SCALE_ATREG:
338 ss = 0;
339 break;
340 default:
341 ASSERT_MSG(0, "Invalid scale for SIB byte");
342 ss = 0;
343 break;
367 } 344 }
368 emit->Write8((u8)((ss << 6) | ((ireg&7)<<3) | (_offsetOrBaseReg&7))); 345 emit->Write8((u8)((ss << 6) | ((ireg & 7) << 3) | (_offsetOrBaseReg & 7)));
369 } 346 }
370 347
371 if (mod == 1) //8-bit disp 348 if (mod == 1) // 8-bit disp
372 { 349 {
373 emit->Write8((u8)(s8)(s32)offset); 350 emit->Write8((u8)(s8)(s32)offset);
374 } 351 } else if (mod == 2 || (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8)) // 32-bit disp
375 else if (mod == 2 || (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8)) //32-bit disp
376 { 352 {
377 emit->Write32((u32)offset); 353 emit->Write32((u32)offset);
378 } 354 }
@@ -382,8 +358,7 @@ void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg,
382// R = register# upper bit 358// R = register# upper bit
383// X = scale amnt upper bit 359// X = scale amnt upper bit
384// B = base register# upper bit 360// B = base register# upper bit
385void XEmitter::Rex(int w, int r, int x, int b) 361void XEmitter::Rex(int w, int r, int x, int b) {
386{
387 w = w ? 1 : 0; 362 w = w ? 1 : 0;
388 r = r ? 1 : 0; 363 r = r ? 1 : 0;
389 x = x ? 1 : 0; 364 x = x ? 1 : 0;
@@ -393,70 +368,60 @@ void XEmitter::Rex(int w, int r, int x, int b)
393 Write8(rx); 368 Write8(rx);
394} 369}
395 370
396void XEmitter::JMP(const u8* addr, bool force5Bytes) 371void XEmitter::JMP(const u8* addr, bool force5Bytes) {
397{
398 u64 fn = (u64)addr; 372 u64 fn = (u64)addr;
399 if (!force5Bytes) 373 if (!force5Bytes) {
400 {
401 s64 distance = (s64)(fn - ((u64)code + 2)); 374 s64 distance = (s64)(fn - ((u64)code + 2));
402 ASSERT_MSG(distance >= -0x80 && distance < 0x80, 375 ASSERT_MSG(distance >= -0x80 && distance < 0x80,
403 "Jump target too far away, needs force5Bytes = true"); 376 "Jump target too far away, needs force5Bytes = true");
404 //8 bits will do 377 // 8 bits will do
405 Write8(0xEB); 378 Write8(0xEB);
406 Write8((u8)(s8)distance); 379 Write8((u8)(s8)distance);
407 } 380 } else {
408 else
409 {
410 s64 distance = (s64)(fn - ((u64)code + 5)); 381 s64 distance = (s64)(fn - ((u64)code + 5));
411 382
412 ASSERT_MSG( 383 ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL,
413 distance >= -0x80000000LL && distance < 0x80000000LL, 384 "Jump target too far away, needs indirect register");
414 "Jump target too far away, needs indirect register");
415 Write8(0xE9); 385 Write8(0xE9);
416 Write32((u32)(s32)distance); 386 Write32((u32)(s32)distance);
417 } 387 }
418} 388}
419 389
420void XEmitter::JMPptr(const OpArg& arg2) 390void XEmitter::JMPptr(const OpArg& arg2) {
421{
422 OpArg arg = arg2; 391 OpArg arg = arg2;
423 if (arg.IsImm()) ASSERT_MSG(0, "JMPptr - Imm argument"); 392 if (arg.IsImm())
393 ASSERT_MSG(0, "JMPptr - Imm argument");
424 arg.operandReg = 4; 394 arg.operandReg = 4;
425 arg.WriteRex(this, 0, 0); 395 arg.WriteRex(this, 0, 0);
426 Write8(0xFF); 396 Write8(0xFF);
427 arg.WriteRest(this); 397 arg.WriteRest(this);
428} 398}
429 399
430//Can be used to trap other processors, before overwriting their code 400// Can be used to trap other processors, before overwriting their code
431// not used in dolphin 401// not used in dolphin
432void XEmitter::JMPself() 402void XEmitter::JMPself() {
433{
434 Write8(0xEB); 403 Write8(0xEB);
435 Write8(0xFE); 404 Write8(0xFE);
436} 405}
437 406
438void XEmitter::CALLptr(OpArg arg) 407void XEmitter::CALLptr(OpArg arg) {
439{ 408 if (arg.IsImm())
440 if (arg.IsImm()) ASSERT_MSG(0, "CALLptr - Imm argument"); 409 ASSERT_MSG(0, "CALLptr - Imm argument");
441 arg.operandReg = 2; 410 arg.operandReg = 2;
442 arg.WriteRex(this, 0, 0); 411 arg.WriteRex(this, 0, 0);
443 Write8(0xFF); 412 Write8(0xFF);
444 arg.WriteRest(this); 413 arg.WriteRest(this);
445} 414}
446 415
447void XEmitter::CALL(const void* fnptr) 416void XEmitter::CALL(const void* fnptr) {
448{
449 u64 distance = u64(fnptr) - (u64(code) + 5); 417 u64 distance = u64(fnptr) - (u64(code) + 5);
450 ASSERT_MSG( 418 ASSERT_MSG(distance < 0x0000000080000000ULL || distance >= 0xFFFFFFFF80000000ULL,
451 distance < 0x0000000080000000ULL || 419 "CALL out of range (%p calls %p)", code, fnptr);
452 distance >= 0xFFFFFFFF80000000ULL,
453 "CALL out of range (%p calls %p)", code, fnptr);
454 Write8(0xE8); 420 Write8(0xE8);
455 Write32(u32(distance)); 421 Write32(u32(distance));
456} 422}
457 423
458FixupBranch XEmitter::CALL() 424FixupBranch XEmitter::CALL() {
459{
460 FixupBranch branch; 425 FixupBranch branch;
461 branch.type = 1; 426 branch.type = 1;
462 branch.ptr = code + 5; 427 branch.ptr = code + 5;
@@ -467,38 +432,30 @@ FixupBranch XEmitter::CALL()
467 return branch; 432 return branch;
468} 433}
469 434
470FixupBranch XEmitter::J(bool force5bytes) 435FixupBranch XEmitter::J(bool force5bytes) {
471{
472 FixupBranch branch; 436 FixupBranch branch;
473 branch.type = force5bytes ? 1 : 0; 437 branch.type = force5bytes ? 1 : 0;
474 branch.ptr = code + (force5bytes ? 5 : 2); 438 branch.ptr = code + (force5bytes ? 5 : 2);
475 if (!force5bytes) 439 if (!force5bytes) {
476 { 440 // 8 bits will do
477 //8 bits will do
478 Write8(0xEB); 441 Write8(0xEB);
479 Write8(0); 442 Write8(0);
480 } 443 } else {
481 else
482 {
483 Write8(0xE9); 444 Write8(0xE9);
484 Write32(0); 445 Write32(0);
485 } 446 }
486 return branch; 447 return branch;
487} 448}
488 449
489FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes) 450FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes) {
490{
491 FixupBranch branch; 451 FixupBranch branch;
492 branch.type = force5bytes ? 1 : 0; 452 branch.type = force5bytes ? 1 : 0;
493 branch.ptr = code + (force5bytes ? 6 : 2); 453 branch.ptr = code + (force5bytes ? 6 : 2);
494 if (!force5bytes) 454 if (!force5bytes) {
495 { 455 // 8 bits will do
496 //8 bits will do
497 Write8(0x70 + conditionCode); 456 Write8(0x70 + conditionCode);
498 Write8(0); 457 Write8(0);
499 } 458 } else {
500 else
501 {
502 Write8(0x0F); 459 Write8(0x0F);
503 Write8(0x80 + conditionCode); 460 Write8(0x80 + conditionCode);
504 Write32(0); 461 Write32(0);
@@ -506,198 +463,268 @@ FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes)
506 return branch; 463 return branch;
507} 464}
508 465
509void XEmitter::J_CC(CCFlags conditionCode, const u8* addr, bool force5bytes) 466void XEmitter::J_CC(CCFlags conditionCode, const u8* addr, bool force5bytes) {
510{
511 u64 fn = (u64)addr; 467 u64 fn = (u64)addr;
512 s64 distance = (s64)(fn - ((u64)code + 2)); 468 s64 distance = (s64)(fn - ((u64)code + 2));
513 if (distance < -0x80 || distance >= 0x80 || force5bytes) 469 if (distance < -0x80 || distance >= 0x80 || force5bytes) {
514 {
515 distance = (s64)(fn - ((u64)code + 6)); 470 distance = (s64)(fn - ((u64)code + 6));
516 ASSERT_MSG( 471 ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL,
517 distance >= -0x80000000LL && distance < 0x80000000LL, 472 "Jump target too far away, needs indirect register");
518 "Jump target too far away, needs indirect register");
519 Write8(0x0F); 473 Write8(0x0F);
520 Write8(0x80 + conditionCode); 474 Write8(0x80 + conditionCode);
521 Write32((u32)(s32)distance); 475 Write32((u32)(s32)distance);
522 } 476 } else {
523 else
524 {
525 Write8(0x70 + conditionCode); 477 Write8(0x70 + conditionCode);
526 Write8((u8)(s8)distance); 478 Write8((u8)(s8)distance);
527 } 479 }
528} 480}
529 481
530void XEmitter::SetJumpTarget(const FixupBranch& branch) 482void XEmitter::SetJumpTarget(const FixupBranch& branch) {
531{ 483 if (branch.type == 0) {
532 if (branch.type == 0)
533 {
534 s64 distance = (s64)(code - branch.ptr); 484 s64 distance = (s64)(code - branch.ptr);
535 ASSERT_MSG(distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); 485 ASSERT_MSG(distance >= -0x80 && distance < 0x80,
486 "Jump target too far away, needs force5Bytes = true");
536 branch.ptr[-1] = (u8)(s8)distance; 487 branch.ptr[-1] = (u8)(s8)distance;
537 } 488 } else if (branch.type == 1) {
538 else if (branch.type == 1)
539 {
540 s64 distance = (s64)(code - branch.ptr); 489 s64 distance = (s64)(code - branch.ptr);
541 ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); 490 ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL,
491 "Jump target too far away, needs indirect register");
542 ((s32*)branch.ptr)[-1] = (s32)distance; 492 ((s32*)branch.ptr)[-1] = (s32)distance;
543 } 493 }
544} 494}
545 495
546void XEmitter::SetJumpTarget(const FixupBranch& branch, const u8* target) 496void XEmitter::SetJumpTarget(const FixupBranch& branch, const u8* target) {
547{ 497 if (branch.type == 0) {
548 if (branch.type == 0)
549 {
550 s64 distance = (s64)(target - branch.ptr); 498 s64 distance = (s64)(target - branch.ptr);
551 ASSERT_MSG(distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); 499 ASSERT_MSG(distance >= -0x80 && distance < 0x80,
500 "Jump target too far away, needs force5Bytes = true");
552 branch.ptr[-1] = (u8)(s8)distance; 501 branch.ptr[-1] = (u8)(s8)distance;
553 } 502 } else if (branch.type == 1) {
554 else if (branch.type == 1)
555 {
556 s64 distance = (s64)(target - branch.ptr); 503 s64 distance = (s64)(target - branch.ptr);
557 ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); 504 ASSERT_MSG(distance >= -0x80000000LL && distance < 0x80000000LL,
505 "Jump target too far away, needs indirect register");
558 ((s32*)branch.ptr)[-1] = (s32)distance; 506 ((s32*)branch.ptr)[-1] = (s32)distance;
559 } 507 }
560} 508}
561 509
562//Single byte opcodes 510// Single byte opcodes
563//There is no PUSHAD/POPAD in 64-bit mode. 511// There is no PUSHAD/POPAD in 64-bit mode.
564void XEmitter::INT3() {Write8(0xCC);} 512void XEmitter::INT3() {
565void XEmitter::RET() {Write8(0xC3);} 513 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 514}
515void XEmitter::RET() {
516 Write8(0xC3);
517}
518void XEmitter::RET_FAST() {
519 Write8(0xF3);
520 Write8(0xC3);
521} // two-byte return (rep ret) - recommended by AMD optimization manual for the case of jumping to a
522 // ret
567 523
568// The first sign of decadence: optimized NOPs. 524// The first sign of decadence: optimized NOPs.
569void XEmitter::NOP(size_t size) 525void XEmitter::NOP(size_t size) {
570{
571 DEBUG_ASSERT((int)size > 0); 526 DEBUG_ASSERT((int)size > 0);
572 while (true) 527 while (true) {
573 { 528 switch (size) {
574 switch (size)
575 {
576 case 0: 529 case 0:
577 return; 530 return;
578 case 1: 531 case 1:
579 Write8(0x90); 532 Write8(0x90);
580 return; 533 return;
581 case 2: 534 case 2:
582 Write8(0x66); Write8(0x90); 535 Write8(0x66);
536 Write8(0x90);
583 return; 537 return;
584 case 3: 538 case 3:
585 Write8(0x0F); Write8(0x1F); Write8(0x00); 539 Write8(0x0F);
540 Write8(0x1F);
541 Write8(0x00);
586 return; 542 return;
587 case 4: 543 case 4:
588 Write8(0x0F); Write8(0x1F); Write8(0x40); Write8(0x00); 544 Write8(0x0F);
545 Write8(0x1F);
546 Write8(0x40);
547 Write8(0x00);
589 return; 548 return;
590 case 5: 549 case 5:
591 Write8(0x0F); Write8(0x1F); Write8(0x44); Write8(0x00); 550 Write8(0x0F);
551 Write8(0x1F);
552 Write8(0x44);
553 Write8(0x00);
592 Write8(0x00); 554 Write8(0x00);
593 return; 555 return;
594 case 6: 556 case 6:
595 Write8(0x66); Write8(0x0F); Write8(0x1F); Write8(0x44); 557 Write8(0x66);
596 Write8(0x00); Write8(0x00); 558 Write8(0x0F);
559 Write8(0x1F);
560 Write8(0x44);
561 Write8(0x00);
562 Write8(0x00);
597 return; 563 return;
598 case 7: 564 case 7:
599 Write8(0x0F); Write8(0x1F); Write8(0x80); Write8(0x00); 565 Write8(0x0F);
600 Write8(0x00); Write8(0x00); Write8(0x00); 566 Write8(0x1F);
567 Write8(0x80);
568 Write8(0x00);
569 Write8(0x00);
570 Write8(0x00);
571 Write8(0x00);
601 return; 572 return;
602 case 8: 573 case 8:
603 Write8(0x0F); Write8(0x1F); Write8(0x84); Write8(0x00); 574 Write8(0x0F);
604 Write8(0x00); Write8(0x00); Write8(0x00); Write8(0x00); 575 Write8(0x1F);
576 Write8(0x84);
577 Write8(0x00);
578 Write8(0x00);
579 Write8(0x00);
580 Write8(0x00);
581 Write8(0x00);
605 return; 582 return;
606 case 9: 583 case 9:
607 Write8(0x66); Write8(0x0F); Write8(0x1F); Write8(0x84); 584 Write8(0x66);
608 Write8(0x00); Write8(0x00); Write8(0x00); Write8(0x00); 585 Write8(0x0F);
586 Write8(0x1F);
587 Write8(0x84);
588 Write8(0x00);
589 Write8(0x00);
590 Write8(0x00);
591 Write8(0x00);
609 Write8(0x00); 592 Write8(0x00);
610 return; 593 return;
611 case 10: 594 case 10:
612 Write8(0x66); Write8(0x66); Write8(0x0F); Write8(0x1F); 595 Write8(0x66);
613 Write8(0x84); Write8(0x00); Write8(0x00); Write8(0x00); 596 Write8(0x66);
614 Write8(0x00); Write8(0x00); 597 Write8(0x0F);
598 Write8(0x1F);
599 Write8(0x84);
600 Write8(0x00);
601 Write8(0x00);
602 Write8(0x00);
603 Write8(0x00);
604 Write8(0x00);
615 return; 605 return;
616 default: 606 default:
617 // Even though x86 instructions are allowed to be up to 15 bytes long, 607 // Even though x86 instructions are allowed to be up to 15 bytes long,
618 // AMD advises against using NOPs longer than 11 bytes because they 608 // AMD advises against using NOPs longer than 11 bytes because they
619 // carry a performance penalty on CPUs older than AMD family 16h. 609 // carry a performance penalty on CPUs older than AMD family 16h.
620 Write8(0x66); Write8(0x66); Write8(0x66); Write8(0x0F); 610 Write8(0x66);
621 Write8(0x1F); Write8(0x84); Write8(0x00); Write8(0x00); 611 Write8(0x66);
622 Write8(0x00); Write8(0x00); Write8(0x00); 612 Write8(0x66);
613 Write8(0x0F);
614 Write8(0x1F);
615 Write8(0x84);
616 Write8(0x00);
617 Write8(0x00);
618 Write8(0x00);
619 Write8(0x00);
620 Write8(0x00);
623 size -= 11; 621 size -= 11;
624 continue; 622 continue;
625 } 623 }
626 } 624 }
627} 625}
628 626
629void XEmitter::PAUSE() {Write8(0xF3); NOP();} //use in tight spinloops for energy saving on some cpu 627void XEmitter::PAUSE() {
630void XEmitter::CLC() {CheckFlags(); Write8(0xF8);} //clear carry 628 Write8(0xF3);
631void XEmitter::CMC() {CheckFlags(); Write8(0xF5);} //flip carry 629 NOP();
632void XEmitter::STC() {CheckFlags(); Write8(0xF9);} //set carry 630} // use in tight spinloops for energy saving on some cpu
631void XEmitter::CLC() {
632 CheckFlags();
633 Write8(0xF8);
634} // clear carry
635void XEmitter::CMC() {
636 CheckFlags();
637 Write8(0xF5);
638} // flip carry
639void XEmitter::STC() {
640 CheckFlags();
641 Write8(0xF9);
642} // set carry
633 643
634//TODO: xchg ah, al ??? 644// TODO: xchg ah, al ???
635void XEmitter::XCHG_AHAL() 645void XEmitter::XCHG_AHAL() {
636{
637 Write8(0x86); 646 Write8(0x86);
638 Write8(0xe0); 647 Write8(0xe0);
639 // alt. 86 c4 648 // alt. 86 c4
640} 649}
641 650
642//These two can not be executed on early Intel 64-bit CPU:s, only on AMD! 651// These two can not be executed on early Intel 64-bit CPU:s, only on AMD!
643void XEmitter::LAHF() {Write8(0x9F);} 652void XEmitter::LAHF() {
644void XEmitter::SAHF() {CheckFlags(); Write8(0x9E);} 653 Write8(0x9F);
654}
655void XEmitter::SAHF() {
656 CheckFlags();
657 Write8(0x9E);
658}
645 659
646void XEmitter::PUSHF() {Write8(0x9C);} 660void XEmitter::PUSHF() {
647void XEmitter::POPF() {CheckFlags(); Write8(0x9D);} 661 Write8(0x9C);
662}
663void XEmitter::POPF() {
664 CheckFlags();
665 Write8(0x9D);
666}
648 667
649void XEmitter::LFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xE8);} 668void XEmitter::LFENCE() {
650void XEmitter::MFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF0);} 669 Write8(0x0F);
651void XEmitter::SFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF8);} 670 Write8(0xAE);
671 Write8(0xE8);
672}
673void XEmitter::MFENCE() {
674 Write8(0x0F);
675 Write8(0xAE);
676 Write8(0xF0);
677}
678void XEmitter::SFENCE() {
679 Write8(0x0F);
680 Write8(0xAE);
681 Write8(0xF8);
682}
652 683
653void XEmitter::WriteSimple1Byte(int bits, u8 byte, X64Reg reg) 684void XEmitter::WriteSimple1Byte(int bits, u8 byte, X64Reg reg) {
654{
655 if (bits == 16) 685 if (bits == 16)
656 Write8(0x66); 686 Write8(0x66);
657 Rex(bits == 64, 0, 0, (int)reg >> 3); 687 Rex(bits == 64, 0, 0, (int)reg >> 3);
658 Write8(byte + ((int)reg & 7)); 688 Write8(byte + ((int)reg & 7));
659} 689}
660 690
661void XEmitter::WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg) 691void XEmitter::WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg) {
662{
663 if (bits == 16) 692 if (bits == 16)
664 Write8(0x66); 693 Write8(0x66);
665 Rex(bits==64, 0, 0, (int)reg >> 3); 694 Rex(bits == 64, 0, 0, (int)reg >> 3);
666 Write8(byte1); 695 Write8(byte1);
667 Write8(byte2 + ((int)reg & 7)); 696 Write8(byte2 + ((int)reg & 7));
668} 697}
669 698
670void XEmitter::CWD(int bits) 699void XEmitter::CWD(int bits) {
671{
672 if (bits == 16) 700 if (bits == 16)
673 Write8(0x66); 701 Write8(0x66);
674 Rex(bits == 64, 0, 0, 0); 702 Rex(bits == 64, 0, 0, 0);
675 Write8(0x99); 703 Write8(0x99);
676} 704}
677 705
678void XEmitter::CBW(int bits) 706void XEmitter::CBW(int bits) {
679{
680 if (bits == 8) 707 if (bits == 8)
681 Write8(0x66); 708 Write8(0x66);
682 Rex(bits == 32, 0, 0, 0); 709 Rex(bits == 32, 0, 0, 0);
683 Write8(0x98); 710 Write8(0x98);
684} 711}
685 712
686//Simple opcodes 713// Simple opcodes
687 714
715// push/pop do not need wide to be 64-bit
716void XEmitter::PUSH(X64Reg reg) {
717 WriteSimple1Byte(32, 0x50, reg);
718}
719void XEmitter::POP(X64Reg reg) {
720 WriteSimple1Byte(32, 0x58, reg);
721}
688 722
689//push/pop do not need wide to be 64-bit 723void XEmitter::PUSH(int bits, const OpArg& reg) {
690void XEmitter::PUSH(X64Reg reg) {WriteSimple1Byte(32, 0x50, reg);}
691void XEmitter::POP(X64Reg reg) {WriteSimple1Byte(32, 0x58, reg);}
692
693void XEmitter::PUSH(int bits, const OpArg& reg)
694{
695 if (reg.IsSimpleReg()) 724 if (reg.IsSimpleReg())
696 PUSH(reg.GetSimpleReg()); 725 PUSH(reg.GetSimpleReg());
697 else if (reg.IsImm()) 726 else if (reg.IsImm()) {
698 { 727 switch (reg.GetImmBits()) {
699 switch (reg.GetImmBits())
700 {
701 case 8: 728 case 8:
702 Write8(0x6A); 729 Write8(0x6A);
703 Write8((u8)(s8)reg.offset); 730 Write8((u8)(s8)reg.offset);
@@ -715,9 +742,7 @@ void XEmitter::PUSH(int bits, const OpArg& reg)
715 ASSERT_MSG(0, "PUSH - Bad imm bits"); 742 ASSERT_MSG(0, "PUSH - Bad imm bits");
716 break; 743 break;
717 } 744 }
718 } 745 } else {
719 else
720 {
721 if (bits == 16) 746 if (bits == 16)
722 Write8(0x66); 747 Write8(0x66);
723 reg.WriteRex(this, bits, bits); 748 reg.WriteRex(this, bits, bits);
@@ -726,44 +751,33 @@ void XEmitter::PUSH(int bits, const OpArg& reg)
726 } 751 }
727} 752}
728 753
729void XEmitter::POP(int /*bits*/, const OpArg& reg) 754void XEmitter::POP(int /*bits*/, const OpArg& reg) {
730{
731 if (reg.IsSimpleReg()) 755 if (reg.IsSimpleReg())
732 POP(reg.GetSimpleReg()); 756 POP(reg.GetSimpleReg());
733 else 757 else
734 ASSERT_MSG(0, "POP - Unsupported encoding"); 758 ASSERT_MSG(0, "POP - Unsupported encoding");
735} 759}
736 760
737void XEmitter::BSWAP(int bits, X64Reg reg) 761void XEmitter::BSWAP(int bits, X64Reg reg) {
738{ 762 if (bits >= 32) {
739 if (bits >= 32)
740 {
741 WriteSimple2Byte(bits, 0x0F, 0xC8, reg); 763 WriteSimple2Byte(bits, 0x0F, 0xC8, reg);
742 } 764 } else if (bits == 16) {
743 else if (bits == 16)
744 {
745 ROL(16, R(reg), Imm8(8)); 765 ROL(16, R(reg), Imm8(8));
746 } 766 } else if (bits == 8) {
747 else if (bits == 8)
748 {
749 // Do nothing - can't bswap a single byte... 767 // Do nothing - can't bswap a single byte...
750 } 768 } else {
751 else
752 {
753 ASSERT_MSG(0, "BSWAP - Wrong number of bits"); 769 ASSERT_MSG(0, "BSWAP - Wrong number of bits");
754 } 770 }
755} 771}
756 772
757// Undefined opcode - reserved 773// Undefined opcode - reserved
758// If we ever need a way to always cause a non-breakpoint hard exception... 774// If we ever need a way to always cause a non-breakpoint hard exception...
759void XEmitter::UD2() 775void XEmitter::UD2() {
760{
761 Write8(0x0F); 776 Write8(0x0F);
762 Write8(0x0B); 777 Write8(0x0B);
763} 778}
764 779
765void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) 780void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) {
766{
767 ASSERT_MSG(!arg.IsImm(), "PREFETCH - Imm argument"); 781 ASSERT_MSG(!arg.IsImm(), "PREFETCH - Imm argument");
768 arg.operandReg = (u8)level; 782 arg.operandReg = (u8)level;
769 arg.WriteRex(this, 0, 0); 783 arg.WriteRex(this, 0, 0);
@@ -772,8 +786,7 @@ void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg)
772 arg.WriteRest(this); 786 arg.WriteRest(this);
773} 787}
774 788
775void XEmitter::SETcc(CCFlags flag, OpArg dest) 789void XEmitter::SETcc(CCFlags flag, OpArg dest) {
776{
777 ASSERT_MSG(!dest.IsImm(), "SETcc - Imm argument"); 790 ASSERT_MSG(!dest.IsImm(), "SETcc - Imm argument");
778 dest.operandReg = 0; 791 dest.operandReg = 0;
779 dest.WriteRex(this, 0, 8); 792 dest.WriteRex(this, 0, 8);
@@ -782,8 +795,7 @@ void XEmitter::SETcc(CCFlags flag, OpArg dest)
782 dest.WriteRest(this); 795 dest.WriteRest(this);
783} 796}
784 797
785void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) 798void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) {
786{
787 ASSERT_MSG(!src.IsImm(), "CMOVcc - Imm argument"); 799 ASSERT_MSG(!src.IsImm(), "CMOVcc - Imm argument");
788 ASSERT_MSG(bits != 8, "CMOVcc - 8 bits unsupported"); 800 ASSERT_MSG(bits != 8, "CMOVcc - 8 bits unsupported");
789 if (bits == 16) 801 if (bits == 16)
@@ -795,34 +807,41 @@ void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag)
795 src.WriteRest(this); 807 src.WriteRest(this);
796} 808}
797 809
798void XEmitter::WriteMulDivType(int bits, OpArg src, int ext) 810void XEmitter::WriteMulDivType(int bits, OpArg src, int ext) {
799{
800 ASSERT_MSG(!src.IsImm(), "WriteMulDivType - Imm argument"); 811 ASSERT_MSG(!src.IsImm(), "WriteMulDivType - Imm argument");
801 CheckFlags(); 812 CheckFlags();
802 src.operandReg = ext; 813 src.operandReg = ext;
803 if (bits == 16) 814 if (bits == 16)
804 Write8(0x66); 815 Write8(0x66);
805 src.WriteRex(this, bits, bits, 0); 816 src.WriteRex(this, bits, bits, 0);
806 if (bits == 8) 817 if (bits == 8) {
807 {
808 Write8(0xF6); 818 Write8(0xF6);
809 } 819 } else {
810 else
811 {
812 Write8(0xF7); 820 Write8(0xF7);
813 } 821 }
814 src.WriteRest(this); 822 src.WriteRest(this);
815} 823}
816 824
817void XEmitter::MUL(int bits, const OpArg& src) {WriteMulDivType(bits, src, 4);} 825void XEmitter::MUL(int bits, const OpArg& src) {
818void XEmitter::DIV(int bits, const OpArg& src) {WriteMulDivType(bits, src, 6);} 826 WriteMulDivType(bits, src, 4);
819void XEmitter::IMUL(int bits, const OpArg& src) {WriteMulDivType(bits, src, 5);} 827}
820void XEmitter::IDIV(int bits, const OpArg& src) {WriteMulDivType(bits, src, 7);} 828void XEmitter::DIV(int bits, const OpArg& src) {
821void XEmitter::NEG(int bits, const OpArg& src) {WriteMulDivType(bits, src, 3);} 829 WriteMulDivType(bits, src, 6);
822void XEmitter::NOT(int bits, const OpArg& src) {WriteMulDivType(bits, src, 2);} 830}
831void XEmitter::IMUL(int bits, const OpArg& src) {
832 WriteMulDivType(bits, src, 5);
833}
834void XEmitter::IDIV(int bits, const OpArg& src) {
835 WriteMulDivType(bits, src, 7);
836}
837void XEmitter::NEG(int bits, const OpArg& src) {
838 WriteMulDivType(bits, src, 3);
839}
840void XEmitter::NOT(int bits, const OpArg& src) {
841 WriteMulDivType(bits, src, 2);
842}
823 843
824void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep) 844void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep) {
825{
826 ASSERT_MSG(!src.IsImm(), "WriteBitSearchType - Imm argument"); 845 ASSERT_MSG(!src.IsImm(), "WriteBitSearchType - Imm argument");
827 CheckFlags(); 846 CheckFlags();
828 src.operandReg = (u8)dest; 847 src.operandReg = (u8)dest;
@@ -836,36 +855,35 @@ void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bo
836 src.WriteRest(this); 855 src.WriteRest(this);
837} 856}
838 857
839void XEmitter::MOVNTI(int bits, const OpArg& dest, X64Reg src) 858void XEmitter::MOVNTI(int bits, const OpArg& dest, X64Reg src) {
840{
841 if (bits <= 16) 859 if (bits <= 16)
842 ASSERT_MSG(0, "MOVNTI - bits<=16"); 860 ASSERT_MSG(0, "MOVNTI - bits<=16");
843 WriteBitSearchType(bits, src, dest, 0xC3); 861 WriteBitSearchType(bits, src, dest, 0xC3);
844} 862}
845 863
846void XEmitter::BSF(int bits, X64Reg dest, const OpArg& src) {WriteBitSearchType(bits,dest,src,0xBC);} // Bottom bit to top bit 864void 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 865 WriteBitSearchType(bits, dest, src, 0xBC);
866} // Bottom bit to top bit
867void XEmitter::BSR(int bits, X64Reg dest, const OpArg& src) {
868 WriteBitSearchType(bits, dest, src, 0xBD);
869} // Top bit to bottom bit
848 870
849void XEmitter::TZCNT(int bits, X64Reg dest, const OpArg& src) 871void XEmitter::TZCNT(int bits, X64Reg dest, const OpArg& src) {
850{
851 CheckFlags(); 872 CheckFlags();
852 if (!Common::GetCPUCaps().bmi1) 873 if (!Common::GetCPUCaps().bmi1)
853 ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer."); 874 ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer.");
854 WriteBitSearchType(bits, dest, src, 0xBC, true); 875 WriteBitSearchType(bits, dest, src, 0xBC, true);
855} 876}
856void XEmitter::LZCNT(int bits, X64Reg dest, const OpArg& src) 877void XEmitter::LZCNT(int bits, X64Reg dest, const OpArg& src) {
857{
858 CheckFlags(); 878 CheckFlags();
859 if (!Common::GetCPUCaps().lzcnt) 879 if (!Common::GetCPUCaps().lzcnt)
860 ASSERT_MSG(0, "Trying to use LZCNT on a system that doesn't support it. Bad programmer."); 880 ASSERT_MSG(0, "Trying to use LZCNT on a system that doesn't support it. Bad programmer.");
861 WriteBitSearchType(bits, dest, src, 0xBD, true); 881 WriteBitSearchType(bits, dest, src, 0xBD, true);
862} 882}
863 883
864void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) 884void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) {
865{
866 ASSERT_MSG(!src.IsImm(), "MOVSX - Imm argument"); 885 ASSERT_MSG(!src.IsImm(), "MOVSX - Imm argument");
867 if (dbits == sbits) 886 if (dbits == sbits) {
868 {
869 MOV(dbits, R(dest), src); 887 MOV(dbits, R(dest), src);
870 return; 888 return;
871 } 889 }
@@ -873,66 +891,49 @@ void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src)
873 if (dbits == 16) 891 if (dbits == 16)
874 Write8(0x66); 892 Write8(0x66);
875 src.WriteRex(this, dbits, sbits); 893 src.WriteRex(this, dbits, sbits);
876 if (sbits == 8) 894 if (sbits == 8) {
877 {
878 Write8(0x0F); 895 Write8(0x0F);
879 Write8(0xBE); 896 Write8(0xBE);
880 } 897 } else if (sbits == 16) {
881 else if (sbits == 16)
882 {
883 Write8(0x0F); 898 Write8(0x0F);
884 Write8(0xBF); 899 Write8(0xBF);
885 } 900 } else if (sbits == 32 && dbits == 64) {
886 else if (sbits == 32 && dbits == 64)
887 {
888 Write8(0x63); 901 Write8(0x63);
889 } 902 } else {
890 else
891 {
892 Crash(); 903 Crash();
893 } 904 }
894 src.WriteRest(this); 905 src.WriteRest(this);
895} 906}
896 907
897void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src) 908void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src) {
898{
899 ASSERT_MSG(!src.IsImm(), "MOVZX - Imm argument"); 909 ASSERT_MSG(!src.IsImm(), "MOVZX - Imm argument");
900 if (dbits == sbits) 910 if (dbits == sbits) {
901 {
902 MOV(dbits, R(dest), src); 911 MOV(dbits, R(dest), src);
903 return; 912 return;
904 } 913 }
905 src.operandReg = (u8)dest; 914 src.operandReg = (u8)dest;
906 if (dbits == 16) 915 if (dbits == 16)
907 Write8(0x66); 916 Write8(0x66);
908 //the 32bit result is automatically zero extended to 64bit 917 // the 32bit result is automatically zero extended to 64bit
909 src.WriteRex(this, dbits == 64 ? 32 : dbits, sbits); 918 src.WriteRex(this, dbits == 64 ? 32 : dbits, sbits);
910 if (sbits == 8) 919 if (sbits == 8) {
911 {
912 Write8(0x0F); 920 Write8(0x0F);
913 Write8(0xB6); 921 Write8(0xB6);
914 } 922 } else if (sbits == 16) {
915 else if (sbits == 16)
916 {
917 Write8(0x0F); 923 Write8(0x0F);
918 Write8(0xB7); 924 Write8(0xB7);
919 } 925 } else if (sbits == 32 && dbits == 64) {
920 else if (sbits == 32 && dbits == 64)
921 {
922 Write8(0x8B); 926 Write8(0x8B);
923 } 927 } else {
924 else
925 {
926 ASSERT_MSG(0, "MOVZX - Invalid size"); 928 ASSERT_MSG(0, "MOVZX - Invalid size");
927 } 929 }
928 src.WriteRest(this); 930 src.WriteRest(this);
929} 931}
930 932
931void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) 933void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src) {
932{ 934 ASSERT_MSG(Common::GetCPUCaps().movbe,
933 ASSERT_MSG(Common::GetCPUCaps().movbe, "Generating MOVBE on a system that does not support it."); 935 "Generating MOVBE on a system that does not support it.");
934 if (bits == 8) 936 if (bits == 8) {
935 {
936 MOV(bits, dest, src); 937 MOV(bits, dest, src);
937 return; 938 return;
938 } 939 }
@@ -940,71 +941,60 @@ void XEmitter::MOVBE(int bits, const OpArg& dest, const OpArg& src)
940 if (bits == 16) 941 if (bits == 16)
941 Write8(0x66); 942 Write8(0x66);
942 943
943 if (dest.IsSimpleReg()) 944 if (dest.IsSimpleReg()) {
944 {
945 ASSERT_MSG(!src.IsSimpleReg() && !src.IsImm(), "MOVBE: Loading from !mem"); 945 ASSERT_MSG(!src.IsSimpleReg() && !src.IsImm(), "MOVBE: Loading from !mem");
946 src.WriteRex(this, bits, bits, dest.GetSimpleReg()); 946 src.WriteRex(this, bits, bits, dest.GetSimpleReg());
947 Write8(0x0F); Write8(0x38); Write8(0xF0); 947 Write8(0x0F);
948 Write8(0x38);
949 Write8(0xF0);
948 src.WriteRest(this, 0, dest.GetSimpleReg()); 950 src.WriteRest(this, 0, dest.GetSimpleReg());
949 } 951 } else if (src.IsSimpleReg()) {
950 else if (src.IsSimpleReg())
951 {
952 ASSERT_MSG(!dest.IsSimpleReg() && !dest.IsImm(), "MOVBE: Storing to !mem"); 952 ASSERT_MSG(!dest.IsSimpleReg() && !dest.IsImm(), "MOVBE: Storing to !mem");
953 dest.WriteRex(this, bits, bits, src.GetSimpleReg()); 953 dest.WriteRex(this, bits, bits, src.GetSimpleReg());
954 Write8(0x0F); Write8(0x38); Write8(0xF1); 954 Write8(0x0F);
955 Write8(0x38);
956 Write8(0xF1);
955 dest.WriteRest(this, 0, src.GetSimpleReg()); 957 dest.WriteRest(this, 0, src.GetSimpleReg());
956 } 958 } else {
957 else
958 {
959 ASSERT_MSG(0, "MOVBE: Not loading or storing to mem"); 959 ASSERT_MSG(0, "MOVBE: Not loading or storing to mem");
960 } 960 }
961} 961}
962 962
963 963void 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"); 964 ASSERT_MSG(!src.IsImm(), "LEA - Imm argument");
967 src.operandReg = (u8)dest; 965 src.operandReg = (u8)dest;
968 if (bits == 16) 966 if (bits == 16)
969 Write8(0x66); //TODO: performance warning 967 Write8(0x66); // TODO: performance warning
970 src.WriteRex(this, bits, bits); 968 src.WriteRex(this, bits, bits);
971 Write8(0x8D); 969 Write8(0x8D);
972 src.WriteRest(this, 0, INVALID_REG, bits == 64); 970 src.WriteRest(this, 0, INVALID_REG, bits == 64);
973} 971}
974 972
975//shift can be either imm8 or cl 973// shift can be either imm8 or cl
976void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext) 974void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext) {
977{
978 CheckFlags(); 975 CheckFlags();
979 bool writeImm = false; 976 bool writeImm = false;
980 if (dest.IsImm()) 977 if (dest.IsImm()) {
981 {
982 ASSERT_MSG(0, "WriteShift - can't shift imms"); 978 ASSERT_MSG(0, "WriteShift - can't shift imms");
983 } 979 }
984 if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) 980 if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) ||
985 { 981 (shift.IsImm() && shift.GetImmBits() != 8)) {
986 ASSERT_MSG(0, "WriteShift - illegal argument"); 982 ASSERT_MSG(0, "WriteShift - illegal argument");
987 } 983 }
988 dest.operandReg = ext; 984 dest.operandReg = ext;
989 if (bits == 16) 985 if (bits == 16)
990 Write8(0x66); 986 Write8(0x66);
991 dest.WriteRex(this, bits, bits, 0); 987 dest.WriteRex(this, bits, bits, 0);
992 if (shift.GetImmBits() == 8) 988 if (shift.GetImmBits() == 8) {
993 { 989 // ok an imm
994 //ok an imm
995 u8 imm = (u8)shift.offset; 990 u8 imm = (u8)shift.offset;
996 if (imm == 1) 991 if (imm == 1) {
997 {
998 Write8(bits == 8 ? 0xD0 : 0xD1); 992 Write8(bits == 8 ? 0xD0 : 0xD1);
999 } 993 } else {
1000 else
1001 {
1002 writeImm = true; 994 writeImm = true;
1003 Write8(bits == 8 ? 0xC0 : 0xC1); 995 Write8(bits == 8 ? 0xC0 : 0xC1);
1004 } 996 }
1005 } 997 } else {
1006 else
1007 {
1008 Write8(bits == 8 ? 0xD2 : 0xD3); 998 Write8(bits == 8 ? 0xD2 : 0xD3);
1009 } 999 }
1010 dest.WriteRest(this, writeImm ? 1 : 0); 1000 dest.WriteRest(this, writeImm ? 1 : 0);
@@ -1014,116 +1004,125 @@ void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext)
1014 1004
1015// large rotates and shift are slower on intel than amd 1005// large rotates and shift are slower on intel than amd
1016// intel likes to rotate by 1, and the op is smaller too 1006// intel likes to rotate by 1, and the op is smaller too
1017void XEmitter::ROL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 0);} 1007void 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);} 1008 WriteShift(bits, dest, shift, 0);
1019void XEmitter::RCL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 2);} 1009}
1020void XEmitter::RCR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 3);} 1010void 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);} 1011 WriteShift(bits, dest, shift, 1);
1022void XEmitter::SHR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 5);} 1012}
1023void XEmitter::SAR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 7);} 1013void XEmitter::RCL(int bits, const OpArg& dest, const OpArg& shift) {
1014 WriteShift(bits, dest, shift, 2);
1015}
1016void XEmitter::RCR(int bits, const OpArg& dest, const OpArg& shift) {
1017 WriteShift(bits, dest, shift, 3);
1018}
1019void XEmitter::SHL(int bits, const OpArg& dest, const OpArg& shift) {
1020 WriteShift(bits, dest, shift, 4);
1021}
1022void XEmitter::SHR(int bits, const OpArg& dest, const OpArg& shift) {
1023 WriteShift(bits, dest, shift, 5);
1024}
1025void XEmitter::SAR(int bits, const OpArg& dest, const OpArg& shift) {
1026 WriteShift(bits, dest, shift, 7);
1027}
1024 1028
1025// index can be either imm8 or register, don't use memory destination because it's slow 1029// index can be either imm8 or register, don't use memory destination because it's slow
1026void XEmitter::WriteBitTest(int bits, const OpArg& dest, const OpArg& index, int ext) 1030void XEmitter::WriteBitTest(int bits, const OpArg& dest, const OpArg& index, int ext) {
1027{
1028 CheckFlags(); 1031 CheckFlags();
1029 if (dest.IsImm()) 1032 if (dest.IsImm()) {
1030 {
1031 ASSERT_MSG(0, "WriteBitTest - can't test imms"); 1033 ASSERT_MSG(0, "WriteBitTest - can't test imms");
1032 } 1034 }
1033 if ((index.IsImm() && index.GetImmBits() != 8)) 1035 if ((index.IsImm() && index.GetImmBits() != 8)) {
1034 {
1035 ASSERT_MSG(0, "WriteBitTest - illegal argument"); 1036 ASSERT_MSG(0, "WriteBitTest - illegal argument");
1036 } 1037 }
1037 if (bits == 16) 1038 if (bits == 16)
1038 Write8(0x66); 1039 Write8(0x66);
1039 if (index.IsImm()) 1040 if (index.IsImm()) {
1040 {
1041 dest.WriteRex(this, bits, bits); 1041 dest.WriteRex(this, bits, bits);
1042 Write8(0x0F); Write8(0xBA); 1042 Write8(0x0F);
1043 Write8(0xBA);
1043 dest.WriteRest(this, 1, (X64Reg)ext); 1044 dest.WriteRest(this, 1, (X64Reg)ext);
1044 Write8((u8)index.offset); 1045 Write8((u8)index.offset);
1045 } 1046 } else {
1046 else
1047 {
1048 X64Reg operand = index.GetSimpleReg(); 1047 X64Reg operand = index.GetSimpleReg();
1049 dest.WriteRex(this, bits, bits, operand); 1048 dest.WriteRex(this, bits, bits, operand);
1050 Write8(0x0F); Write8(0x83 + 8*ext); 1049 Write8(0x0F);
1050 Write8(0x83 + 8 * ext);
1051 dest.WriteRest(this, 1, operand); 1051 dest.WriteRest(this, 1, operand);
1052 } 1052 }
1053} 1053}
1054 1054
1055void XEmitter::BT(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 4);} 1055void 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);} 1056 WriteBitTest(bits, dest, index, 4);
1057void XEmitter::BTR(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 6);} 1057}
1058void XEmitter::BTC(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 7);} 1058void XEmitter::BTS(int bits, const OpArg& dest, const OpArg& index) {
1059 WriteBitTest(bits, dest, index, 5);
1060}
1061void XEmitter::BTR(int bits, const OpArg& dest, const OpArg& index) {
1062 WriteBitTest(bits, dest, index, 6);
1063}
1064void XEmitter::BTC(int bits, const OpArg& dest, const OpArg& index) {
1065 WriteBitTest(bits, dest, index, 7);
1066}
1059 1067
1060//shift can be either imm8 or cl 1068// shift can be either imm8 or cl
1061void XEmitter::SHRD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) 1069void XEmitter::SHRD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) {
1062{
1063 CheckFlags(); 1070 CheckFlags();
1064 if (dest.IsImm()) 1071 if (dest.IsImm()) {
1065 {
1066 ASSERT_MSG(0, "SHRD - can't use imms as destination"); 1072 ASSERT_MSG(0, "SHRD - can't use imms as destination");
1067 } 1073 }
1068 if (!src.IsSimpleReg()) 1074 if (!src.IsSimpleReg()) {
1069 {
1070 ASSERT_MSG(0, "SHRD - must use simple register as source"); 1075 ASSERT_MSG(0, "SHRD - must use simple register as source");
1071 } 1076 }
1072 if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) 1077 if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) ||
1073 { 1078 (shift.IsImm() && shift.GetImmBits() != 8)) {
1074 ASSERT_MSG(0, "SHRD - illegal shift"); 1079 ASSERT_MSG(0, "SHRD - illegal shift");
1075 } 1080 }
1076 if (bits == 16) 1081 if (bits == 16)
1077 Write8(0x66); 1082 Write8(0x66);
1078 X64Reg operand = src.GetSimpleReg(); 1083 X64Reg operand = src.GetSimpleReg();
1079 dest.WriteRex(this, bits, bits, operand); 1084 dest.WriteRex(this, bits, bits, operand);
1080 if (shift.GetImmBits() == 8) 1085 if (shift.GetImmBits() == 8) {
1081 { 1086 Write8(0x0F);
1082 Write8(0x0F); Write8(0xAC); 1087 Write8(0xAC);
1083 dest.WriteRest(this, 1, operand); 1088 dest.WriteRest(this, 1, operand);
1084 Write8((u8)shift.offset); 1089 Write8((u8)shift.offset);
1085 } 1090 } else {
1086 else 1091 Write8(0x0F);
1087 { 1092 Write8(0xAD);
1088 Write8(0x0F); Write8(0xAD);
1089 dest.WriteRest(this, 0, operand); 1093 dest.WriteRest(this, 0, operand);
1090 } 1094 }
1091} 1095}
1092 1096
1093void XEmitter::SHLD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) 1097void XEmitter::SHLD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) {
1094{
1095 CheckFlags(); 1098 CheckFlags();
1096 if (dest.IsImm()) 1099 if (dest.IsImm()) {
1097 {
1098 ASSERT_MSG(0, "SHLD - can't use imms as destination"); 1100 ASSERT_MSG(0, "SHLD - can't use imms as destination");
1099 } 1101 }
1100 if (!src.IsSimpleReg()) 1102 if (!src.IsSimpleReg()) {
1101 {
1102 ASSERT_MSG(0, "SHLD - must use simple register as source"); 1103 ASSERT_MSG(0, "SHLD - must use simple register as source");
1103 } 1104 }
1104 if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) 1105 if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) ||
1105 { 1106 (shift.IsImm() && shift.GetImmBits() != 8)) {
1106 ASSERT_MSG(0, "SHLD - illegal shift"); 1107 ASSERT_MSG(0, "SHLD - illegal shift");
1107 } 1108 }
1108 if (bits == 16) 1109 if (bits == 16)
1109 Write8(0x66); 1110 Write8(0x66);
1110 X64Reg operand = src.GetSimpleReg(); 1111 X64Reg operand = src.GetSimpleReg();
1111 dest.WriteRex(this, bits, bits, operand); 1112 dest.WriteRex(this, bits, bits, operand);
1112 if (shift.GetImmBits() == 8) 1113 if (shift.GetImmBits() == 8) {
1113 { 1114 Write8(0x0F);
1114 Write8(0x0F); Write8(0xA4); 1115 Write8(0xA4);
1115 dest.WriteRest(this, 1, operand); 1116 dest.WriteRest(this, 1, operand);
1116 Write8((u8)shift.offset); 1117 Write8((u8)shift.offset);
1117 } 1118 } else {
1118 else 1119 Write8(0x0F);
1119 { 1120 Write8(0xA5);
1120 Write8(0x0F); Write8(0xA5);
1121 dest.WriteRest(this, 0, operand); 1121 dest.WriteRest(this, 0, operand);
1122 } 1122 }
1123} 1123}
1124 1124
1125void OpArg::WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg _operandReg, int bits) 1125void OpArg::WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg _operandReg, int bits) {
1126{
1127 if (bits == 16) 1126 if (bits == 16)
1128 emit->Write8(0x66); 1127 emit->Write8(0x66);
1129 1128
@@ -1133,12 +1132,11 @@ void OpArg::WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg _operandReg, int bit
1133 WriteRest(emit); 1132 WriteRest(emit);
1134} 1133}
1135 1134
1136//operand can either be immediate or register 1135// operand can either be immediate or register
1137void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& operand, int bits) const 1136void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand,
1138{ 1137 int bits) const {
1139 X64Reg _operandReg; 1138 X64Reg _operandReg;
1140 if (IsImm()) 1139 if (IsImm()) {
1141 {
1142 ASSERT_MSG(0, "WriteNormalOp - Imm argument, wrong order"); 1140 ASSERT_MSG(0, "WriteNormalOp - Imm argument, wrong order");
1143 } 1141 }
1144 1142
@@ -1147,27 +1145,22 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o
1147 1145
1148 int immToWrite = 0; 1146 int immToWrite = 0;
1149 1147
1150 if (operand.IsImm()) 1148 if (operand.IsImm()) {
1151 {
1152 WriteRex(emit, bits, bits); 1149 WriteRex(emit, bits, bits);
1153 1150
1154 if (!toRM) 1151 if (!toRM) {
1155 {
1156 ASSERT_MSG(0, "WriteNormalOp - Writing to Imm (!toRM)"); 1152 ASSERT_MSG(0, "WriteNormalOp - Writing to Imm (!toRM)");
1157 } 1153 }
1158 1154
1159 if (operand.scale == SCALE_IMM8 && bits == 8) 1155 if (operand.scale == SCALE_IMM8 && bits == 8) {
1160 {
1161 // op al, imm8 1156 // op al, imm8
1162 if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC) 1157 if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC) {
1163 {
1164 emit->Write8(normalops[op].eaximm8); 1158 emit->Write8(normalops[op].eaximm8);
1165 emit->Write8((u8)operand.offset); 1159 emit->Write8((u8)operand.offset);
1166 return; 1160 return;
1167 } 1161 }
1168 // mov reg, imm8 1162 // mov reg, imm8
1169 if (!scale && op == nrmMOV) 1163 if (!scale && op == nrmMOV) {
1170 {
1171 emit->Write8(0xB0 + (offsetOrBaseReg & 7)); 1164 emit->Write8(0xB0 + (offsetOrBaseReg & 7));
1172 emit->Write8((u8)operand.offset); 1165 emit->Write8((u8)operand.offset);
1173 return; 1166 return;
@@ -1175,26 +1168,20 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o
1175 // op r/m8, imm8 1168 // op r/m8, imm8
1176 emit->Write8(normalops[op].imm8); 1169 emit->Write8(normalops[op].imm8);
1177 immToWrite = 8; 1170 immToWrite = 8;
1178 } 1171 } else if ((operand.scale == SCALE_IMM16 && bits == 16) ||
1179 else if ((operand.scale == SCALE_IMM16 && bits == 16) || 1172 (operand.scale == SCALE_IMM32 && bits == 32) ||
1180 (operand.scale == SCALE_IMM32 && bits == 32) || 1173 (operand.scale == SCALE_IMM32 && bits == 64)) {
1181 (operand.scale == SCALE_IMM32 && bits == 64))
1182 {
1183 // Try to save immediate size if we can, but first check to see 1174 // Try to save immediate size if we can, but first check to see
1184 // if the instruction supports simm8. 1175 // if the instruction supports simm8.
1185 // op r/m, imm8 1176 // op r/m, imm8
1186 if (normalops[op].simm8 != 0xCC && 1177 if (normalops[op].simm8 != 0xCC &&
1187 ((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) || 1178 ((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) ||
1188 (operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset))) 1179 (operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset))) {
1189 {
1190 emit->Write8(normalops[op].simm8); 1180 emit->Write8(normalops[op].simm8);
1191 immToWrite = 8; 1181 immToWrite = 8;
1192 } 1182 } else {
1193 else
1194 {
1195 // mov reg, imm 1183 // mov reg, imm
1196 if (!scale && op == nrmMOV && bits != 64) 1184 if (!scale && op == nrmMOV && bits != 64) {
1197 {
1198 emit->Write8(0xB8 + (offsetOrBaseReg & 7)); 1185 emit->Write8(0xB8 + (offsetOrBaseReg & 7));
1199 if (bits == 16) 1186 if (bits == 16)
1200 emit->Write16((u16)operand.offset); 1187 emit->Write16((u16)operand.offset);
@@ -1203,8 +1190,7 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o
1203 return; 1190 return;
1204 } 1191 }
1205 // op eax, imm 1192 // op eax, imm
1206 if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC) 1193 if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC) {
1207 {
1208 emit->Write8(normalops[op].eaximm32); 1194 emit->Write8(normalops[op].eaximm32);
1209 if (bits == 16) 1195 if (bits == 16)
1210 emit->Write16((u16)operand.offset); 1196 emit->Write16((u16)operand.offset);
@@ -1216,54 +1202,41 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o
1216 emit->Write8(normalops[op].imm32); 1202 emit->Write8(normalops[op].imm32);
1217 immToWrite = bits == 16 ? 16 : 32; 1203 immToWrite = bits == 16 ? 16 : 32;
1218 } 1204 }
1219 } 1205 } else if ((operand.scale == SCALE_IMM8 && bits == 16) ||
1220 else if ((operand.scale == SCALE_IMM8 && bits == 16) || 1206 (operand.scale == SCALE_IMM8 && bits == 32) ||
1221 (operand.scale == SCALE_IMM8 && bits == 32) || 1207 (operand.scale == SCALE_IMM8 && bits == 64)) {
1222 (operand.scale == SCALE_IMM8 && bits == 64))
1223 {
1224 // op r/m, imm8 1208 // op r/m, imm8
1225 emit->Write8(normalops[op].simm8); 1209 emit->Write8(normalops[op].simm8);
1226 immToWrite = 8; 1210 immToWrite = 8;
1227 } 1211 } else if (operand.scale == SCALE_IMM64 && bits == 64) {
1228 else if (operand.scale == SCALE_IMM64 && bits == 64) 1212 if (scale) {
1229 {
1230 if (scale)
1231 {
1232 ASSERT_MSG(0, "WriteNormalOp - MOV with 64-bit imm requres register destination"); 1213 ASSERT_MSG(0, "WriteNormalOp - MOV with 64-bit imm requres register destination");
1233 } 1214 }
1234 // mov reg64, imm64 1215 // mov reg64, imm64
1235 else if (op == nrmMOV) 1216 else if (op == nrmMOV) {
1236 {
1237 emit->Write8(0xB8 + (offsetOrBaseReg & 7)); 1217 emit->Write8(0xB8 + (offsetOrBaseReg & 7));
1238 emit->Write64((u64)operand.offset); 1218 emit->Write64((u64)operand.offset);
1239 return; 1219 return;
1240 } 1220 }
1241 ASSERT_MSG(0, "WriteNormalOp - Only MOV can take 64-bit imm"); 1221 ASSERT_MSG(0, "WriteNormalOp - Only MOV can take 64-bit imm");
1242 } 1222 } else {
1243 else
1244 {
1245 ASSERT_MSG(0, "WriteNormalOp - Unhandled case"); 1223 ASSERT_MSG(0, "WriteNormalOp - Unhandled case");
1246 } 1224 }
1247 _operandReg = (X64Reg)normalops[op].ext; //pass extension in REG of ModRM 1225 _operandReg = (X64Reg)normalops[op].ext; // pass extension in REG of ModRM
1248 } 1226 } else {
1249 else
1250 {
1251 _operandReg = (X64Reg)operand.offsetOrBaseReg; 1227 _operandReg = (X64Reg)operand.offsetOrBaseReg;
1252 WriteRex(emit, bits, bits, _operandReg); 1228 WriteRex(emit, bits, bits, _operandReg);
1253 // op r/m, reg 1229 // op r/m, reg
1254 if (toRM) 1230 if (toRM) {
1255 {
1256 emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32); 1231 emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32);
1257 } 1232 }
1258 // op reg, r/m 1233 // op reg, r/m
1259 else 1234 else {
1260 {
1261 emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32); 1235 emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32);
1262 } 1236 }
1263 } 1237 }
1264 WriteRest(emit, immToWrite >> 3, _operandReg); 1238 WriteRest(emit, immToWrite >> 3, _operandReg);
1265 switch (immToWrite) 1239 switch (immToWrite) {
1266 {
1267 case 0: 1240 case 0:
1268 break; 1241 break;
1269 case 8: 1242 case 8:
@@ -1280,66 +1253,84 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg& o
1280 } 1253 }
1281} 1254}
1282 1255
1283void XEmitter::WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2) 1256void XEmitter::WriteNormalOp(XEmitter* emit, int bits, NormalOp op, const OpArg& a1,
1284{ 1257 const OpArg& a2) {
1285 if (a1.IsImm()) 1258 if (a1.IsImm()) {
1286 { 1259 // Booh! Can't write to an imm
1287 //Booh! Can't write to an imm
1288 ASSERT_MSG(0, "WriteNormalOp - a1 cannot be imm"); 1260 ASSERT_MSG(0, "WriteNormalOp - a1 cannot be imm");
1289 return; 1261 return;
1290 } 1262 }
1291 if (a2.IsImm()) 1263 if (a2.IsImm()) {
1292 {
1293 a1.WriteNormalOp(emit, true, op, a2, bits); 1264 a1.WriteNormalOp(emit, true, op, a2, bits);
1294 } 1265 } else {
1295 else 1266 if (a1.IsSimpleReg()) {
1296 {
1297 if (a1.IsSimpleReg())
1298 {
1299 a2.WriteNormalOp(emit, false, op, a1, bits); 1267 a2.WriteNormalOp(emit, false, op, a1, bits);
1300 } 1268 } else {
1301 else 1269 ASSERT_MSG(a2.IsSimpleReg() || a2.IsImm(),
1302 { 1270 "WriteNormalOp - a1 and a2 cannot both be memory");
1303 ASSERT_MSG(a2.IsSimpleReg() || a2.IsImm(), "WriteNormalOp - a1 and a2 cannot both be memory");
1304 a1.WriteNormalOp(emit, true, op, a2, bits); 1271 a1.WriteNormalOp(emit, true, op, a2, bits);
1305 } 1272 }
1306 } 1273 }
1307} 1274}
1308 1275
1309void XEmitter::ADD (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmADD, a1, a2);} 1276void 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);} 1277 CheckFlags();
1311void XEmitter::SUB (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmSUB, a1, a2);} 1278 WriteNormalOp(this, bits, nrmADD, a1, a2);
1312void XEmitter::SBB (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmSBB, a1, a2);} 1279}
1313void XEmitter::AND (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmAND, a1, a2);} 1280void 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);} 1281 CheckFlags();
1315void XEmitter::XOR (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmXOR, a1, a2);} 1282 WriteNormalOp(this, bits, nrmADC, a1, a2);
1316void XEmitter::MOV (int bits, const OpArg& a1, const OpArg& a2) 1283}
1317{ 1284void XEmitter::SUB(int bits, const OpArg& a1, const OpArg& a2) {
1285 CheckFlags();
1286 WriteNormalOp(this, bits, nrmSUB, a1, a2);
1287}
1288void XEmitter::SBB(int bits, const OpArg& a1, const OpArg& a2) {
1289 CheckFlags();
1290 WriteNormalOp(this, bits, nrmSBB, a1, a2);
1291}
1292void XEmitter::AND(int bits, const OpArg& a1, const OpArg& a2) {
1293 CheckFlags();
1294 WriteNormalOp(this, bits, nrmAND, a1, a2);
1295}
1296void XEmitter::OR(int bits, const OpArg& a1, const OpArg& a2) {
1297 CheckFlags();
1298 WriteNormalOp(this, bits, nrmOR, a1, a2);
1299}
1300void XEmitter::XOR(int bits, const OpArg& a1, const OpArg& a2) {
1301 CheckFlags();
1302 WriteNormalOp(this, bits, nrmXOR, a1, a2);
1303}
1304void XEmitter::MOV(int bits, const OpArg& a1, const OpArg& a2) {
1318 if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) 1305 if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg())
1319 LOG_ERROR(Common, "Redundant MOV @ %p - bug in JIT?", code); 1306 LOG_ERROR(Common, "Redundant MOV @ %p - bug in JIT?", code);
1320 WriteNormalOp(this, bits, nrmMOV, a1, a2); 1307 WriteNormalOp(this, bits, nrmMOV, a1, a2);
1321} 1308}
1322void XEmitter::TEST(int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(this, bits, nrmTEST, a1, a2);} 1309void 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);} 1310 CheckFlags();
1324void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) {WriteNormalOp(this, bits, nrmXCHG, a1, a2);} 1311 WriteNormalOp(this, bits, nrmTEST, a1, a2);
1312}
1313void XEmitter::CMP(int bits, const OpArg& a1, const OpArg& a2) {
1314 CheckFlags();
1315 WriteNormalOp(this, bits, nrmCMP, a1, a2);
1316}
1317void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) {
1318 WriteNormalOp(this, bits, nrmXCHG, a1, a2);
1319}
1325 1320
1326void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2) 1321void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2) {
1327{
1328 CheckFlags(); 1322 CheckFlags();
1329 if (bits == 8) 1323 if (bits == 8) {
1330 {
1331 ASSERT_MSG(0, "IMUL - illegal bit size!"); 1324 ASSERT_MSG(0, "IMUL - illegal bit size!");
1332 return; 1325 return;
1333 } 1326 }
1334 1327
1335 if (a1.IsImm()) 1328 if (a1.IsImm()) {
1336 {
1337 ASSERT_MSG(0, "IMUL - second arg cannot be imm!"); 1329 ASSERT_MSG(0, "IMUL - second arg cannot be imm!");
1338 return; 1330 return;
1339 } 1331 }
1340 1332
1341 if (!a2.IsImm()) 1333 if (!a2.IsImm()) {
1342 {
1343 ASSERT_MSG(0, "IMUL - third arg must be imm!"); 1334 ASSERT_MSG(0, "IMUL - third arg must be imm!");
1344 return; 1335 return;
1345 } 1336 }
@@ -1348,46 +1339,34 @@ void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2)
1348 Write8(0x66); 1339 Write8(0x66);
1349 a1.WriteRex(this, bits, bits, regOp); 1340 a1.WriteRex(this, bits, bits, regOp);
1350 1341
1351 if (a2.GetImmBits() == 8 || 1342 if (a2.GetImmBits() == 8 || (a2.GetImmBits() == 16 && (s8)a2.offset == (s16)a2.offset) ||
1352 (a2.GetImmBits() == 16 && (s8)a2.offset == (s16)a2.offset) || 1343 (a2.GetImmBits() == 32 && (s8)a2.offset == (s32)a2.offset)) {
1353 (a2.GetImmBits() == 32 && (s8)a2.offset == (s32)a2.offset))
1354 {
1355 Write8(0x6B); 1344 Write8(0x6B);
1356 a1.WriteRest(this, 1, regOp); 1345 a1.WriteRest(this, 1, regOp);
1357 Write8((u8)a2.offset); 1346 Write8((u8)a2.offset);
1358 } 1347 } else {
1359 else
1360 {
1361 Write8(0x69); 1348 Write8(0x69);
1362 if (a2.GetImmBits() == 16 && bits == 16) 1349 if (a2.GetImmBits() == 16 && bits == 16) {
1363 {
1364 a1.WriteRest(this, 2, regOp); 1350 a1.WriteRest(this, 2, regOp);
1365 Write16((u16)a2.offset); 1351 Write16((u16)a2.offset);
1366 } 1352 } else if (a2.GetImmBits() == 32 && (bits == 32 || bits == 64)) {
1367 else if (a2.GetImmBits() == 32 && (bits == 32 || bits == 64))
1368 {
1369 a1.WriteRest(this, 4, regOp); 1353 a1.WriteRest(this, 4, regOp);
1370 Write32((u32)a2.offset); 1354 Write32((u32)a2.offset);
1371 } 1355 } else {
1372 else
1373 {
1374 ASSERT_MSG(0, "IMUL - unhandled case!"); 1356 ASSERT_MSG(0, "IMUL - unhandled case!");
1375 } 1357 }
1376 } 1358 }
1377} 1359}
1378 1360
1379void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a) 1361void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a) {
1380{
1381 CheckFlags(); 1362 CheckFlags();
1382 if (bits == 8) 1363 if (bits == 8) {
1383 {
1384 ASSERT_MSG(0, "IMUL - illegal bit size!"); 1364 ASSERT_MSG(0, "IMUL - illegal bit size!");
1385 return; 1365 return;
1386 } 1366 }
1387 1367
1388 if (a.IsImm()) 1368 if (a.IsImm()) {
1389 { 1369 IMUL(bits, regOp, R(regOp), a);
1390 IMUL(bits, regOp, R(regOp), a) ;
1391 return; 1370 return;
1392 } 1371 }
1393 1372
@@ -1399,9 +1378,7 @@ void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a)
1399 a.WriteRest(this, 0, regOp); 1378 a.WriteRest(this, 0, regOp);
1400} 1379}
1401 1380
1402 1381void 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) 1382 if (opPrefix)
1406 Write8(opPrefix); 1383 Write8(opPrefix);
1407 arg.operandReg = regOp; 1384 arg.operandReg = regOp;
@@ -1413,13 +1390,11 @@ void XEmitter::WriteSSEOp(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extr
1413 arg.WriteRest(this, extrabytes); 1390 arg.WriteRest(this, extrabytes);
1414} 1391}
1415 1392
1416void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) 1393void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) {
1417{
1418 WriteAVXOp(opPrefix, op, regOp, INVALID_REG, arg, extrabytes); 1394 WriteAVXOp(opPrefix, op, regOp, INVALID_REG, arg, extrabytes);
1419} 1395}
1420 1396
1421static int GetVEXmmmmm(u16 op) 1397static int GetVEXmmmmm(u16 op) {
1422{
1423 // Currently, only 0x38 and 0x3A are used as secondary escape byte. 1398 // Currently, only 0x38 and 0x3A are used as secondary escape byte.
1424 if ((op >> 8) == 0x3A) 1399 if ((op >> 8) == 0x3A)
1425 return 3; 1400 return 3;
@@ -1429,8 +1404,7 @@ static int GetVEXmmmmm(u16 op)
1429 return 1; 1404 return 1;
1430} 1405}
1431 1406
1432static int GetVEXpp(u8 opPrefix) 1407static int GetVEXpp(u8 opPrefix) {
1433{
1434 if (opPrefix == 0x66) 1408 if (opPrefix == 0x66)
1435 return 1; 1409 return 1;
1436 if (opPrefix == 0xF3) 1410 if (opPrefix == 0xF3)
@@ -1441,21 +1415,22 @@ static int GetVEXpp(u8 opPrefix)
1441 return 0; 1415 return 0;
1442} 1416}
1443 1417
1444void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) 1418void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg,
1445{ 1419 int extrabytes) {
1446 if (!Common::GetCPUCaps().avx) 1420 if (!Common::GetCPUCaps().avx)
1447 ASSERT_MSG(0, "Trying to use AVX on a system that doesn't support it. Bad programmer."); 1421 ASSERT_MSG(0, "Trying to use AVX on a system that doesn't support it. Bad programmer.");
1448 int mmmmm = GetVEXmmmmm(op); 1422 int mmmmm = GetVEXmmmmm(op);
1449 int pp = GetVEXpp(opPrefix); 1423 int pp = GetVEXpp(opPrefix);
1450 // FIXME: we currently don't support 256-bit instructions, and "size" is not the vector size here 1424 // FIXME: we currently don't support 256-bit instructions, and "size" is not the vector size
1425 // here
1451 arg.WriteVex(this, regOp1, regOp2, 0, pp, mmmmm); 1426 arg.WriteVex(this, regOp1, regOp2, 0, pp, mmmmm);
1452 Write8(op & 0xFF); 1427 Write8(op & 0xFF);
1453 arg.WriteRest(this, extrabytes, regOp1); 1428 arg.WriteRest(this, extrabytes, regOp1);
1454} 1429}
1455 1430
1456// Like the above, but more general; covers GPR-based VEX operations, like BMI1/2 1431// Like the above, but more general; covers GPR-based VEX operations, like BMI1/2
1457void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) 1432void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2,
1458{ 1433 const OpArg& arg, int extrabytes) {
1459 if (size != 32 && size != 64) 1434 if (size != 32 && size != 64)
1460 ASSERT_MSG(0, "VEX GPR instructions only support 32-bit and 64-bit modes!"); 1435 ASSERT_MSG(0, "VEX GPR instructions only support 32-bit and 64-bit modes!");
1461 int mmmmm = GetVEXmmmmm(op); 1436 int mmmmm = GetVEXmmmmm(op);
@@ -1465,49 +1440,50 @@ void XEmitter::WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg r
1465 arg.WriteRest(this, extrabytes, regOp1); 1440 arg.WriteRest(this, extrabytes, regOp1);
1466} 1441}
1467 1442
1468void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) 1443void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2,
1469{ 1444 const OpArg& arg, int extrabytes) {
1470 CheckFlags(); 1445 CheckFlags();
1471 if (!Common::GetCPUCaps().bmi1) 1446 if (!Common::GetCPUCaps().bmi1)
1472 ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer."); 1447 ASSERT_MSG(0, "Trying to use BMI1 on a system that doesn't support it. Bad programmer.");
1473 WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); 1448 WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes);
1474} 1449}
1475 1450
1476void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) 1451void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2,
1477{ 1452 const OpArg& arg, int extrabytes) {
1478 CheckFlags(); 1453 CheckFlags();
1479 if (!Common::GetCPUCaps().bmi2) 1454 if (!Common::GetCPUCaps().bmi2)
1480 ASSERT_MSG(0, "Trying to use BMI2 on a system that doesn't support it. Bad programmer."); 1455 ASSERT_MSG(0, "Trying to use BMI2 on a system that doesn't support it. Bad programmer.");
1481 WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); 1456 WriteVEXOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes);
1482} 1457}
1483 1458
1484void XEmitter::MOVD_xmm(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x6E, dest, arg, 0);} 1459void XEmitter::MOVD_xmm(X64Reg dest, const OpArg& arg) {
1485void XEmitter::MOVD_xmm(const OpArg &arg, X64Reg src) {WriteSSEOp(0x66, 0x7E, src, arg, 0);} 1460 WriteSSEOp(0x66, 0x6E, dest, arg, 0);
1461}
1462void XEmitter::MOVD_xmm(const OpArg& arg, X64Reg src) {
1463 WriteSSEOp(0x66, 0x7E, src, arg, 0);
1464}
1486 1465
1487void XEmitter::MOVQ_xmm(X64Reg dest, OpArg arg) 1466void XEmitter::MOVQ_xmm(X64Reg dest, OpArg arg) {
1488{
1489#ifdef ARCHITECTURE_x86_64 1467#ifdef ARCHITECTURE_x86_64
1490 // Alternate encoding 1468 // Alternate encoding
1491 // This does not display correctly in MSVC's debugger, it thinks it's a MOVD 1469 // This does not display correctly in MSVC's debugger, it thinks it's a MOVD
1492 arg.operandReg = dest; 1470 arg.operandReg = dest;
1493 Write8(0x66); 1471 Write8(0x66);
1494 arg.WriteRex(this, 64, 0); 1472 arg.WriteRex(this, 64, 0);
1495 Write8(0x0f); 1473 Write8(0x0f);
1496 Write8(0x6E); 1474 Write8(0x6E);
1497 arg.WriteRest(this, 0); 1475 arg.WriteRest(this, 0);
1498#else 1476#else
1499 arg.operandReg = dest; 1477 arg.operandReg = dest;
1500 Write8(0xF3); 1478 Write8(0xF3);
1501 Write8(0x0f); 1479 Write8(0x0f);
1502 Write8(0x7E); 1480 Write8(0x7E);
1503 arg.WriteRest(this, 0); 1481 arg.WriteRest(this, 0);
1504#endif 1482#endif
1505} 1483}
1506 1484
1507void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) 1485void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) {
1508{ 1486 if (src > 7 || arg.IsSimpleReg()) {
1509 if (src > 7 || arg.IsSimpleReg())
1510 {
1511 // Alternate encoding 1487 // Alternate encoding
1512 // This does not display correctly in MSVC's debugger, it thinks it's a MOVD 1488 // This does not display correctly in MSVC's debugger, it thinks it's a MOVD
1513 arg.operandReg = src; 1489 arg.operandReg = src;
@@ -1516,9 +1492,7 @@ void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src)
1516 Write8(0x0f); 1492 Write8(0x0f);
1517 Write8(0x7E); 1493 Write8(0x7E);
1518 arg.WriteRest(this, 0); 1494 arg.WriteRest(this, 0);
1519 } 1495 } else {
1520 else
1521 {
1522 arg.operandReg = src; 1496 arg.operandReg = src;
1523 arg.WriteRex(this, 0, 0); 1497 arg.WriteRex(this, 0, 0);
1524 Write8(0x66); 1498 Write8(0x66);
@@ -1528,8 +1502,7 @@ void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src)
1528 } 1502 }
1529} 1503}
1530 1504
1531void XEmitter::WriteMXCSR(OpArg arg, int ext) 1505void XEmitter::WriteMXCSR(OpArg arg, int ext) {
1532{
1533 if (arg.IsImm() || arg.IsSimpleReg()) 1506 if (arg.IsImm() || arg.IsSimpleReg())
1534 ASSERT_MSG(0, "MXCSR - invalid operand"); 1507 ASSERT_MSG(0, "MXCSR - invalid operand");
1535 1508
@@ -1540,143 +1513,357 @@ void XEmitter::WriteMXCSR(OpArg arg, int ext)
1540 arg.WriteRest(this); 1513 arg.WriteRest(this);
1541} 1514}
1542 1515
1543void XEmitter::STMXCSR(const OpArg& memloc) {WriteMXCSR(memloc, 3);} 1516void XEmitter::STMXCSR(const OpArg& memloc) {
1544void XEmitter::LDMXCSR(const OpArg& memloc) {WriteMXCSR(memloc, 2);} 1517 WriteMXCSR(memloc, 3);
1545 1518}
1546void XEmitter::MOVNTDQ(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVNTDQ, regOp, arg);} 1519void XEmitter::LDMXCSR(const OpArg& memloc) {
1547void XEmitter::MOVNTPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVNTP, regOp, arg);} 1520 WriteMXCSR(memloc, 2);
1548void XEmitter::MOVNTPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVNTP, regOp, arg);} 1521}
1549 1522
1550void XEmitter::ADDSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseADD, regOp, arg);} 1523void XEmitter::MOVNTDQ(const OpArg& arg, X64Reg regOp) {
1551void XEmitter::ADDSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseADD, regOp, arg);} 1524 WriteSSEOp(0x66, sseMOVNTDQ, regOp, arg);
1552void XEmitter::SUBSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseSUB, regOp, arg);} 1525}
1553void XEmitter::SUBSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseSUB, regOp, arg);} 1526void 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);} 1527 WriteSSEOp(0x00, sseMOVNTP, regOp, arg);
1555void XEmitter::CMPSD(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0xF2, sseCMP, regOp, arg, 1); Write8(compare);} 1528}
1556void XEmitter::MULSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMUL, regOp, arg);} 1529void XEmitter::MOVNTPD(const OpArg& arg, X64Reg regOp) {
1557void XEmitter::MULSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMUL, regOp, arg);} 1530 WriteSSEOp(0x66, sseMOVNTP, regOp, arg);
1558void XEmitter::DIVSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseDIV, regOp, arg);} 1531}
1559void XEmitter::DIVSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseDIV, regOp, arg);} 1532
1560void XEmitter::MINSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMIN, regOp, arg);} 1533void XEmitter::ADDSS(X64Reg regOp, const OpArg& arg) {
1561void XEmitter::MINSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMIN, regOp, arg);} 1534 WriteSSEOp(0xF3, sseADD, regOp, arg);
1562void XEmitter::MAXSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMAX, regOp, arg);} 1535}
1563void XEmitter::MAXSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMAX, regOp, arg);} 1536void XEmitter::ADDSD(X64Reg regOp, const OpArg& arg) {
1564void XEmitter::SQRTSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseSQRT, regOp, arg);} 1537 WriteSSEOp(0xF2, sseADD, regOp, arg);
1565void XEmitter::SQRTSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseSQRT, regOp, arg);} 1538}
1566void XEmitter::RCPSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseRCP, regOp, arg);} 1539void XEmitter::SUBSS(X64Reg regOp, const OpArg& arg) {
1567void XEmitter::RSQRTSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseRSQRT, regOp, arg);} 1540 WriteSSEOp(0xF3, sseSUB, regOp, arg);
1568 1541}
1569void XEmitter::ADDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseADD, regOp, arg);} 1542void XEmitter::SUBSD(X64Reg regOp, const OpArg& arg) {
1570void XEmitter::ADDPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseADD, regOp, arg);} 1543 WriteSSEOp(0xF2, sseSUB, regOp, arg);
1571void XEmitter::SUBPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseSUB, regOp, arg);} 1544}
1572void XEmitter::SUBPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseSUB, regOp, arg);} 1545void 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);} 1546 WriteSSEOp(0xF3, sseCMP, regOp, arg, 1);
1574void XEmitter::CMPPD(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0x66, sseCMP, regOp, arg, 1); Write8(compare);} 1547 Write8(compare);
1575void XEmitter::ANDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseAND, regOp, arg);} 1548}
1576void XEmitter::ANDPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseAND, regOp, arg);} 1549void XEmitter::CMPSD(X64Reg regOp, const OpArg& arg, u8 compare) {
1577void XEmitter::ANDNPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseANDN, regOp, arg);} 1550 WriteSSEOp(0xF2, sseCMP, regOp, arg, 1);
1578void XEmitter::ANDNPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseANDN, regOp, arg);} 1551 Write8(compare);
1579void XEmitter::ORPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseOR, regOp, arg);} 1552}
1580void XEmitter::ORPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseOR, regOp, arg);} 1553void XEmitter::MULSS(X64Reg regOp, const OpArg& arg) {
1581void XEmitter::XORPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseXOR, regOp, arg);} 1554 WriteSSEOp(0xF3, sseMUL, regOp, arg);
1582void XEmitter::XORPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseXOR, regOp, arg);} 1555}
1583void XEmitter::MULPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMUL, regOp, arg);} 1556void XEmitter::MULSD(X64Reg regOp, const OpArg& arg) {
1584void XEmitter::MULPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMUL, regOp, arg);} 1557 WriteSSEOp(0xF2, sseMUL, regOp, arg);
1585void XEmitter::DIVPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseDIV, regOp, arg);} 1558}
1586void XEmitter::DIVPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseDIV, regOp, arg);} 1559void XEmitter::DIVSS(X64Reg regOp, const OpArg& arg) {
1587void XEmitter::MINPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMIN, regOp, arg);} 1560 WriteSSEOp(0xF3, sseDIV, regOp, arg);
1588void XEmitter::MINPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMIN, regOp, arg);} 1561}
1589void XEmitter::MAXPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMAX, regOp, arg);} 1562void XEmitter::DIVSD(X64Reg regOp, const OpArg& arg) {
1590void XEmitter::MAXPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMAX, regOp, arg);} 1563 WriteSSEOp(0xF2, sseDIV, regOp, arg);
1591void XEmitter::SQRTPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseSQRT, regOp, arg);} 1564}
1592void XEmitter::SQRTPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseSQRT, regOp, arg);} 1565void XEmitter::MINSS(X64Reg regOp, const OpArg& arg) {
1593void XEmitter::RCPPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseRCP, regOp, arg); } 1566 WriteSSEOp(0xF3, sseMIN, regOp, arg);
1594void XEmitter::RSQRTPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseRSQRT, regOp, arg);} 1567}
1595void XEmitter::SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0x00, sseSHUF, regOp, arg,1); Write8(shuffle);} 1568void 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);} 1569 WriteSSEOp(0xF2, sseMIN, regOp, arg);
1597 1570}
1598void XEmitter::HADDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseHADD, regOp, arg);} 1571void XEmitter::MAXSS(X64Reg regOp, const OpArg& arg) {
1599 1572 WriteSSEOp(0xF3, sseMAX, regOp, arg);
1600void XEmitter::COMISS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseCOMIS, regOp, arg);} //weird that these should be packed 1573}
1601void XEmitter::COMISD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseCOMIS, regOp, arg);} //ordered 1574void XEmitter::MAXSD(X64Reg regOp, const OpArg& arg) {
1602void XEmitter::UCOMISS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseUCOMIS, regOp, arg);} //unordered 1575 WriteSSEOp(0xF2, sseMAX, regOp, arg);
1603void XEmitter::UCOMISD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseUCOMIS, regOp, arg);} 1576}
1604 1577void XEmitter::SQRTSS(X64Reg regOp, const OpArg& arg) {
1605void XEmitter::MOVAPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVAPfromRM, regOp, arg);} 1578 WriteSSEOp(0xF3, sseSQRT, regOp, arg);
1606void XEmitter::MOVAPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVAPfromRM, regOp, arg);} 1579}
1607void XEmitter::MOVAPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVAPtoRM, regOp, arg);} 1580void XEmitter::SQRTSD(X64Reg regOp, const OpArg& arg) {
1608void XEmitter::MOVAPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVAPtoRM, regOp, arg);} 1581 WriteSSEOp(0xF2, sseSQRT, regOp, arg);
1609 1582}
1610void XEmitter::MOVUPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVUPfromRM, regOp, arg);} 1583void XEmitter::RCPSS(X64Reg regOp, const OpArg& arg) {
1611void XEmitter::MOVUPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVUPfromRM, regOp, arg);} 1584 WriteSSEOp(0xF3, sseRCP, regOp, arg);
1612void XEmitter::MOVUPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVUPtoRM, regOp, arg);} 1585}
1613void XEmitter::MOVUPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVUPtoRM, regOp, arg);} 1586void XEmitter::RSQRTSS(X64Reg regOp, const OpArg& arg) {
1614 1587 WriteSSEOp(0xF3, sseRSQRT, regOp, arg);
1615void XEmitter::MOVDQA(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVDQfromRM, regOp, arg);} 1588}
1616void XEmitter::MOVDQA(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVDQtoRM, regOp, arg);} 1589
1617void XEmitter::MOVDQU(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMOVDQfromRM, regOp, arg);} 1590void XEmitter::ADDPS(X64Reg regOp, const OpArg& arg) {
1618void XEmitter::MOVDQU(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF3, sseMOVDQtoRM, regOp, arg);} 1591 WriteSSEOp(0x00, sseADD, regOp, arg);
1619 1592}
1620void XEmitter::MOVSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMOVUPfromRM, regOp, arg);} 1593void XEmitter::ADDPD(X64Reg regOp, const OpArg& arg) {
1621void XEmitter::MOVSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMOVUPfromRM, regOp, arg);} 1594 WriteSSEOp(0x66, sseADD, regOp, arg);
1622void XEmitter::MOVSS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF3, sseMOVUPtoRM, regOp, arg);} 1595}
1623void XEmitter::MOVSD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF2, sseMOVUPtoRM, regOp, arg);} 1596void XEmitter::SUBPS(X64Reg regOp, const OpArg& arg) {
1624 1597 WriteSSEOp(0x00, sseSUB, regOp, arg);
1625void XEmitter::MOVLPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseMOVLPfromRM, regOp, arg); } 1598}
1626void XEmitter::MOVLPD(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x66, sseMOVLPfromRM, regOp, arg); } 1599void XEmitter::SUBPD(X64Reg regOp, const OpArg& arg) {
1627void XEmitter::MOVLPS(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x00, sseMOVLPtoRM, regOp, arg); } 1600 WriteSSEOp(0x66, sseSUB, regOp, arg);
1628void XEmitter::MOVLPD(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x66, sseMOVLPtoRM, regOp, arg); } 1601}
1629 1602void XEmitter::CMPPS(X64Reg regOp, const OpArg& arg, u8 compare) {
1630void XEmitter::MOVHPS(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x00, sseMOVHPfromRM, regOp, arg); } 1603 WriteSSEOp(0x00, sseCMP, regOp, arg, 1);
1631void XEmitter::MOVHPD(X64Reg regOp, const OpArg& arg) { WriteSSEOp(0x66, sseMOVHPfromRM, regOp, arg); } 1604 Write8(compare);
1632void XEmitter::MOVHPS(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x00, sseMOVHPtoRM, regOp, arg); } 1605}
1633void XEmitter::MOVHPD(const OpArg& arg, X64Reg regOp) { WriteSSEOp(0x66, sseMOVHPtoRM, regOp, arg); } 1606void XEmitter::CMPPD(X64Reg regOp, const OpArg& arg, u8 compare) {
1634 1607 WriteSSEOp(0x66, sseCMP, regOp, arg, 1);
1635void XEmitter::MOVHLPS(X64Reg regOp1, X64Reg regOp2) {WriteSSEOp(0x00, sseMOVHLPS, regOp1, R(regOp2));} 1608 Write8(compare);
1636void XEmitter::MOVLHPS(X64Reg regOp1, X64Reg regOp2) {WriteSSEOp(0x00, sseMOVLHPS, regOp1, R(regOp2));} 1609}
1637 1610void XEmitter::ANDPS(X64Reg regOp, const OpArg& arg) {
1638void XEmitter::CVTPS2PD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, 0x5A, regOp, arg);} 1611 WriteSSEOp(0x00, sseAND, regOp, arg);
1639void XEmitter::CVTPD2PS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0x5A, regOp, arg);} 1612}
1640 1613void XEmitter::ANDPD(X64Reg regOp, const OpArg& arg) {
1641void XEmitter::CVTSD2SS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x5A, regOp, arg);} 1614 WriteSSEOp(0x66, sseAND, regOp, arg);
1642void XEmitter::CVTSS2SD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x5A, regOp, arg);} 1615}
1643void XEmitter::CVTSD2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2D, regOp, arg);} 1616void XEmitter::ANDNPS(X64Reg regOp, const OpArg& arg) {
1644void XEmitter::CVTSS2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2D, regOp, arg);} 1617 WriteSSEOp(0x00, sseANDN, regOp, arg);
1645void XEmitter::CVTSI2SD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2A, regOp, arg);} 1618}
1646void XEmitter::CVTSI2SS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2A, regOp, arg);} 1619void XEmitter::ANDNPD(X64Reg regOp, const OpArg& arg) {
1647 1620 WriteSSEOp(0x66, sseANDN, regOp, arg);
1648void XEmitter::CVTDQ2PD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0xE6, regOp, arg);} 1621}
1649void XEmitter::CVTDQ2PS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, 0x5B, regOp, arg);} 1622void XEmitter::ORPS(X64Reg regOp, const OpArg& arg) {
1650void XEmitter::CVTPD2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0xE6, regOp, arg);} 1623 WriteSSEOp(0x00, sseOR, regOp, arg);
1651void XEmitter::CVTPS2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0x5B, regOp, arg);} 1624}
1652 1625void XEmitter::ORPD(X64Reg regOp, const OpArg& arg) {
1653void XEmitter::CVTTSD2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2C, regOp, arg);} 1626 WriteSSEOp(0x66, sseOR, regOp, arg);
1654void XEmitter::CVTTSS2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2C, regOp, arg);} 1627}
1655void XEmitter::CVTTPS2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x5B, regOp, arg);} 1628void XEmitter::XORPS(X64Reg regOp, const OpArg& arg) {
1656void XEmitter::CVTTPD2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0xE6, regOp, arg);} 1629 WriteSSEOp(0x00, sseXOR, regOp, arg);
1657 1630}
1658void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) {WriteSSEOp(0x66, sseMASKMOVDQU, dest, R(src));} 1631void XEmitter::XORPD(X64Reg regOp, const OpArg& arg) {
1659 1632 WriteSSEOp(0x66, sseXOR, regOp, arg);
1660void XEmitter::MOVMSKPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x50, dest, arg);} 1633}
1661void XEmitter::MOVMSKPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x50, dest, arg);} 1634void XEmitter::MULPS(X64Reg regOp, const OpArg& arg) {
1662 1635 WriteSSEOp(0x00, sseMUL, regOp, arg);
1663void XEmitter::LDDQU(X64Reg dest, const OpArg& arg) {WriteSSEOp(0xF2, sseLDDQU, dest, arg);} // For integer data only 1636}
1637void XEmitter::MULPD(X64Reg regOp, const OpArg& arg) {
1638 WriteSSEOp(0x66, sseMUL, regOp, arg);
1639}
1640void XEmitter::DIVPS(X64Reg regOp, const OpArg& arg) {
1641 WriteSSEOp(0x00, sseDIV, regOp, arg);
1642}
1643void XEmitter::DIVPD(X64Reg regOp, const OpArg& arg) {
1644 WriteSSEOp(0x66, sseDIV, regOp, arg);
1645}
1646void XEmitter::MINPS(X64Reg regOp, const OpArg& arg) {
1647 WriteSSEOp(0x00, sseMIN, regOp, arg);
1648}
1649void XEmitter::MINPD(X64Reg regOp, const OpArg& arg) {
1650 WriteSSEOp(0x66, sseMIN, regOp, arg);
1651}
1652void XEmitter::MAXPS(X64Reg regOp, const OpArg& arg) {
1653 WriteSSEOp(0x00, sseMAX, regOp, arg);
1654}
1655void XEmitter::MAXPD(X64Reg regOp, const OpArg& arg) {
1656 WriteSSEOp(0x66, sseMAX, regOp, arg);
1657}
1658void XEmitter::SQRTPS(X64Reg regOp, const OpArg& arg) {
1659 WriteSSEOp(0x00, sseSQRT, regOp, arg);
1660}
1661void XEmitter::SQRTPD(X64Reg regOp, const OpArg& arg) {
1662 WriteSSEOp(0x66, sseSQRT, regOp, arg);
1663}
1664void XEmitter::RCPPS(X64Reg regOp, const OpArg& arg) {
1665 WriteSSEOp(0x00, sseRCP, regOp, arg);
1666}
1667void XEmitter::RSQRTPS(X64Reg regOp, const OpArg& arg) {
1668 WriteSSEOp(0x00, sseRSQRT, regOp, arg);
1669}
1670void XEmitter::SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle) {
1671 WriteSSEOp(0x00, sseSHUF, regOp, arg, 1);
1672 Write8(shuffle);
1673}
1674void XEmitter::SHUFPD(X64Reg regOp, const OpArg& arg, u8 shuffle) {
1675 WriteSSEOp(0x66, sseSHUF, regOp, arg, 1);
1676 Write8(shuffle);
1677}
1678
1679void XEmitter::HADDPS(X64Reg regOp, const OpArg& arg) {
1680 WriteSSEOp(0xF2, sseHADD, regOp, arg);
1681}
1682
1683void XEmitter::COMISS(X64Reg regOp, const OpArg& arg) {
1684 WriteSSEOp(0x00, sseCOMIS, regOp, arg);
1685} // weird that these should be packed
1686void XEmitter::COMISD(X64Reg regOp, const OpArg& arg) {
1687 WriteSSEOp(0x66, sseCOMIS, regOp, arg);
1688} // ordered
1689void XEmitter::UCOMISS(X64Reg regOp, const OpArg& arg) {
1690 WriteSSEOp(0x00, sseUCOMIS, regOp, arg);
1691} // unordered
1692void XEmitter::UCOMISD(X64Reg regOp, const OpArg& arg) {
1693 WriteSSEOp(0x66, sseUCOMIS, regOp, arg);
1694}
1695
1696void XEmitter::MOVAPS(X64Reg regOp, const OpArg& arg) {
1697 WriteSSEOp(0x00, sseMOVAPfromRM, regOp, arg);
1698}
1699void XEmitter::MOVAPD(X64Reg regOp, const OpArg& arg) {
1700 WriteSSEOp(0x66, sseMOVAPfromRM, regOp, arg);
1701}
1702void XEmitter::MOVAPS(const OpArg& arg, X64Reg regOp) {
1703 WriteSSEOp(0x00, sseMOVAPtoRM, regOp, arg);
1704}
1705void XEmitter::MOVAPD(const OpArg& arg, X64Reg regOp) {
1706 WriteSSEOp(0x66, sseMOVAPtoRM, regOp, arg);
1707}
1708
1709void XEmitter::MOVUPS(X64Reg regOp, const OpArg& arg) {
1710 WriteSSEOp(0x00, sseMOVUPfromRM, regOp, arg);
1711}
1712void XEmitter::MOVUPD(X64Reg regOp, const OpArg& arg) {
1713 WriteSSEOp(0x66, sseMOVUPfromRM, regOp, arg);
1714}
1715void XEmitter::MOVUPS(const OpArg& arg, X64Reg regOp) {
1716 WriteSSEOp(0x00, sseMOVUPtoRM, regOp, arg);
1717}
1718void XEmitter::MOVUPD(const OpArg& arg, X64Reg regOp) {
1719 WriteSSEOp(0x66, sseMOVUPtoRM, regOp, arg);
1720}
1721
1722void XEmitter::MOVDQA(X64Reg regOp, const OpArg& arg) {
1723 WriteSSEOp(0x66, sseMOVDQfromRM, regOp, arg);
1724}
1725void XEmitter::MOVDQA(const OpArg& arg, X64Reg regOp) {
1726 WriteSSEOp(0x66, sseMOVDQtoRM, regOp, arg);
1727}
1728void XEmitter::MOVDQU(X64Reg regOp, const OpArg& arg) {
1729 WriteSSEOp(0xF3, sseMOVDQfromRM, regOp, arg);
1730}
1731void XEmitter::MOVDQU(const OpArg& arg, X64Reg regOp) {
1732 WriteSSEOp(0xF3, sseMOVDQtoRM, regOp, arg);
1733}
1734
1735void XEmitter::MOVSS(X64Reg regOp, const OpArg& arg) {
1736 WriteSSEOp(0xF3, sseMOVUPfromRM, regOp, arg);
1737}
1738void XEmitter::MOVSD(X64Reg regOp, const OpArg& arg) {
1739 WriteSSEOp(0xF2, sseMOVUPfromRM, regOp, arg);
1740}
1741void XEmitter::MOVSS(const OpArg& arg, X64Reg regOp) {
1742 WriteSSEOp(0xF3, sseMOVUPtoRM, regOp, arg);
1743}
1744void XEmitter::MOVSD(const OpArg& arg, X64Reg regOp) {
1745 WriteSSEOp(0xF2, sseMOVUPtoRM, regOp, arg);
1746}
1747
1748void XEmitter::MOVLPS(X64Reg regOp, const OpArg& arg) {
1749 WriteSSEOp(0x00, sseMOVLPfromRM, regOp, arg);
1750}
1751void XEmitter::MOVLPD(X64Reg regOp, const OpArg& arg) {
1752 WriteSSEOp(0x66, sseMOVLPfromRM, regOp, arg);
1753}
1754void XEmitter::MOVLPS(const OpArg& arg, X64Reg regOp) {
1755 WriteSSEOp(0x00, sseMOVLPtoRM, regOp, arg);
1756}
1757void XEmitter::MOVLPD(const OpArg& arg, X64Reg regOp) {
1758 WriteSSEOp(0x66, sseMOVLPtoRM, regOp, arg);
1759}
1760
1761void XEmitter::MOVHPS(X64Reg regOp, const OpArg& arg) {
1762 WriteSSEOp(0x00, sseMOVHPfromRM, regOp, arg);
1763}
1764void XEmitter::MOVHPD(X64Reg regOp, const OpArg& arg) {
1765 WriteSSEOp(0x66, sseMOVHPfromRM, regOp, arg);
1766}
1767void XEmitter::MOVHPS(const OpArg& arg, X64Reg regOp) {
1768 WriteSSEOp(0x00, sseMOVHPtoRM, regOp, arg);
1769}
1770void XEmitter::MOVHPD(const OpArg& arg, X64Reg regOp) {
1771 WriteSSEOp(0x66, sseMOVHPtoRM, regOp, arg);
1772}
1773
1774void XEmitter::MOVHLPS(X64Reg regOp1, X64Reg regOp2) {
1775 WriteSSEOp(0x00, sseMOVHLPS, regOp1, R(regOp2));
1776}
1777void XEmitter::MOVLHPS(X64Reg regOp1, X64Reg regOp2) {
1778 WriteSSEOp(0x00, sseMOVLHPS, regOp1, R(regOp2));
1779}
1780
1781void XEmitter::CVTPS2PD(X64Reg regOp, const OpArg& arg) {
1782 WriteSSEOp(0x00, 0x5A, regOp, arg);
1783}
1784void XEmitter::CVTPD2PS(X64Reg regOp, const OpArg& arg) {
1785 WriteSSEOp(0x66, 0x5A, regOp, arg);
1786}
1787
1788void XEmitter::CVTSD2SS(X64Reg regOp, const OpArg& arg) {
1789 WriteSSEOp(0xF2, 0x5A, regOp, arg);
1790}
1791void XEmitter::CVTSS2SD(X64Reg regOp, const OpArg& arg) {
1792 WriteSSEOp(0xF3, 0x5A, regOp, arg);
1793}
1794void XEmitter::CVTSD2SI(X64Reg regOp, const OpArg& arg) {
1795 WriteSSEOp(0xF2, 0x2D, regOp, arg);
1796}
1797void XEmitter::CVTSS2SI(X64Reg regOp, const OpArg& arg) {
1798 WriteSSEOp(0xF3, 0x2D, regOp, arg);
1799}
1800void XEmitter::CVTSI2SD(X64Reg regOp, const OpArg& arg) {
1801 WriteSSEOp(0xF2, 0x2A, regOp, arg);
1802}
1803void XEmitter::CVTSI2SS(X64Reg regOp, const OpArg& arg) {
1804 WriteSSEOp(0xF3, 0x2A, regOp, arg);
1805}
1806
1807void XEmitter::CVTDQ2PD(X64Reg regOp, const OpArg& arg) {
1808 WriteSSEOp(0xF3, 0xE6, regOp, arg);
1809}
1810void XEmitter::CVTDQ2PS(X64Reg regOp, const OpArg& arg) {
1811 WriteSSEOp(0x00, 0x5B, regOp, arg);
1812}
1813void XEmitter::CVTPD2DQ(X64Reg regOp, const OpArg& arg) {
1814 WriteSSEOp(0xF2, 0xE6, regOp, arg);
1815}
1816void XEmitter::CVTPS2DQ(X64Reg regOp, const OpArg& arg) {
1817 WriteSSEOp(0x66, 0x5B, regOp, arg);
1818}
1819
1820void XEmitter::CVTTSD2SI(X64Reg regOp, const OpArg& arg) {
1821 WriteSSEOp(0xF2, 0x2C, regOp, arg);
1822}
1823void XEmitter::CVTTSS2SI(X64Reg regOp, const OpArg& arg) {
1824 WriteSSEOp(0xF3, 0x2C, regOp, arg);
1825}
1826void XEmitter::CVTTPS2DQ(X64Reg regOp, const OpArg& arg) {
1827 WriteSSEOp(0xF3, 0x5B, regOp, arg);
1828}
1829void XEmitter::CVTTPD2DQ(X64Reg regOp, const OpArg& arg) {
1830 WriteSSEOp(0x66, 0xE6, regOp, arg);
1831}
1832
1833void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) {
1834 WriteSSEOp(0x66, sseMASKMOVDQU, dest, R(src));
1835}
1836
1837void XEmitter::MOVMSKPS(X64Reg dest, const OpArg& arg) {
1838 WriteSSEOp(0x00, 0x50, dest, arg);
1839}
1840void XEmitter::MOVMSKPD(X64Reg dest, const OpArg& arg) {
1841 WriteSSEOp(0x66, 0x50, dest, arg);
1842}
1843
1844void XEmitter::LDDQU(X64Reg dest, const OpArg& arg) {
1845 WriteSSEOp(0xF2, sseLDDQU, dest, arg);
1846} // For integer data only
1664 1847
1665// THESE TWO ARE UNTESTED. 1848// THESE TWO ARE UNTESTED.
1666void XEmitter::UNPCKLPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x14, dest, arg);} 1849void XEmitter::UNPCKLPS(X64Reg dest, const OpArg& arg) {
1667void XEmitter::UNPCKHPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x15, dest, arg);} 1850 WriteSSEOp(0x00, 0x14, dest, arg);
1851}
1852void XEmitter::UNPCKHPS(X64Reg dest, const OpArg& arg) {
1853 WriteSSEOp(0x00, 0x15, dest, arg);
1854}
1668 1855
1669void XEmitter::UNPCKLPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x14, dest, arg);} 1856void XEmitter::UNPCKLPD(X64Reg dest, const OpArg& arg) {
1670void XEmitter::UNPCKHPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x15, dest, arg);} 1857 WriteSSEOp(0x66, 0x14, dest, arg);
1858}
1859void XEmitter::UNPCKHPD(X64Reg dest, const OpArg& arg) {
1860 WriteSSEOp(0x66, 0x15, dest, arg);
1861}
1671 1862
1672void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg) 1863void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg) {
1673{ 1864 if (Common::GetCPUCaps().sse3) {
1674 if (Common::GetCPUCaps().sse3) 1865 WriteSSEOp(0xF2, 0x12, regOp, arg); // SSE3 movddup
1675 { 1866 } else {
1676 WriteSSEOp(0xF2, 0x12, regOp, arg); //SSE3 movddup
1677 }
1678 else
1679 {
1680 // Simulate this instruction with SSE2 instructions 1867 // Simulate this instruction with SSE2 instructions
1681 if (!arg.IsSimpleReg(regOp)) 1868 if (!arg.IsSimpleReg(regOp))
1682 MOVSD(regOp, arg); 1869 MOVSD(regOp, arg);
@@ -1684,38 +1871,48 @@ void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg)
1684 } 1871 }
1685} 1872}
1686 1873
1687//There are a few more left 1874// There are a few more left
1688 1875
1689// Also some integer instructions are missing 1876// Also some integer instructions are missing
1690void XEmitter::PACKSSDW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x6B, dest, arg);} 1877void XEmitter::PACKSSDW(X64Reg dest, const OpArg& arg) {
1691void XEmitter::PACKSSWB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x63, dest, arg);} 1878 WriteSSEOp(0x66, 0x6B, dest, arg);
1692void XEmitter::PACKUSWB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x67, dest, arg);} 1879}
1880void XEmitter::PACKSSWB(X64Reg dest, const OpArg& arg) {
1881 WriteSSEOp(0x66, 0x63, dest, arg);
1882}
1883void XEmitter::PACKUSWB(X64Reg dest, const OpArg& arg) {
1884 WriteSSEOp(0x66, 0x67, dest, arg);
1885}
1693 1886
1694void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x60, dest, arg);} 1887void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg& arg) {
1695void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x61, dest, arg);} 1888 WriteSSEOp(0x66, 0x60, dest, arg);
1696void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x62, dest, arg);} 1889}
1697void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg &arg) {WriteSSEOp(0x66, 0x6C, dest, arg);} 1890void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg& arg) {
1891 WriteSSEOp(0x66, 0x61, dest, arg);
1892}
1893void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg& arg) {
1894 WriteSSEOp(0x66, 0x62, dest, arg);
1895}
1896void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg& arg) {
1897 WriteSSEOp(0x66, 0x6C, dest, arg);
1898}
1698 1899
1699void XEmitter::PSRLW(X64Reg reg, int shift) 1900void XEmitter::PSRLW(X64Reg reg, int shift) {
1700{
1701 WriteSSEOp(0x66, 0x71, (X64Reg)2, R(reg)); 1901 WriteSSEOp(0x66, 0x71, (X64Reg)2, R(reg));
1702 Write8(shift); 1902 Write8(shift);
1703} 1903}
1704 1904
1705void XEmitter::PSRLD(X64Reg reg, int shift) 1905void XEmitter::PSRLD(X64Reg reg, int shift) {
1706{
1707 WriteSSEOp(0x66, 0x72, (X64Reg)2, R(reg)); 1906 WriteSSEOp(0x66, 0x72, (X64Reg)2, R(reg));
1708 Write8(shift); 1907 Write8(shift);
1709} 1908}
1710 1909
1711void XEmitter::PSRLQ(X64Reg reg, int shift) 1910void XEmitter::PSRLQ(X64Reg reg, int shift) {
1712{
1713 WriteSSEOp(0x66, 0x73, (X64Reg)2, R(reg)); 1911 WriteSSEOp(0x66, 0x73, (X64Reg)2, R(reg));
1714 Write8(shift); 1912 Write8(shift);
1715} 1913}
1716 1914
1717void XEmitter::PSRLQ(X64Reg reg, const OpArg& arg) 1915void XEmitter::PSRLQ(X64Reg reg, const OpArg& arg) {
1718{
1719 WriteSSEOp(0x66, 0xd3, reg, arg); 1916 WriteSSEOp(0x66, 0xd3, reg, arg);
1720} 1917}
1721 1918
@@ -1724,20 +1921,17 @@ void XEmitter::PSRLDQ(X64Reg reg, int shift) {
1724 Write8(shift); 1921 Write8(shift);
1725} 1922}
1726 1923
1727void XEmitter::PSLLW(X64Reg reg, int shift) 1924void XEmitter::PSLLW(X64Reg reg, int shift) {
1728{
1729 WriteSSEOp(0x66, 0x71, (X64Reg)6, R(reg)); 1925 WriteSSEOp(0x66, 0x71, (X64Reg)6, R(reg));
1730 Write8(shift); 1926 Write8(shift);
1731} 1927}
1732 1928
1733void XEmitter::PSLLD(X64Reg reg, int shift) 1929void XEmitter::PSLLD(X64Reg reg, int shift) {
1734{
1735 WriteSSEOp(0x66, 0x72, (X64Reg)6, R(reg)); 1930 WriteSSEOp(0x66, 0x72, (X64Reg)6, R(reg));
1736 Write8(shift); 1931 Write8(shift);
1737} 1932}
1738 1933
1739void XEmitter::PSLLQ(X64Reg reg, int shift) 1934void XEmitter::PSLLQ(X64Reg reg, int shift) {
1740{
1741 WriteSSEOp(0x66, 0x73, (X64Reg)6, R(reg)); 1935 WriteSSEOp(0x66, 0x73, (X64Reg)6, R(reg));
1742 Write8(shift); 1936 Write8(shift);
1743} 1937}
@@ -1747,267 +1941,643 @@ void XEmitter::PSLLDQ(X64Reg reg, int shift) {
1747 Write8(shift); 1941 Write8(shift);
1748} 1942}
1749 1943
1750void XEmitter::PSRAW(X64Reg reg, int shift) 1944void XEmitter::PSRAW(X64Reg reg, int shift) {
1751{
1752 WriteSSEOp(0x66, 0x71, (X64Reg)4, R(reg)); 1945 WriteSSEOp(0x66, 0x71, (X64Reg)4, R(reg));
1753 Write8(shift); 1946 Write8(shift);
1754} 1947}
1755 1948
1756void XEmitter::PSRAD(X64Reg reg, int shift) 1949void XEmitter::PSRAD(X64Reg reg, int shift) {
1757{
1758 WriteSSEOp(0x66, 0x72, (X64Reg)4, R(reg)); 1950 WriteSSEOp(0x66, 0x72, (X64Reg)4, R(reg));
1759 Write8(shift); 1951 Write8(shift);
1760} 1952}
1761 1953
1762void XEmitter::WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) 1954void XEmitter::WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) {
1763{
1764 if (!Common::GetCPUCaps().ssse3) 1955 if (!Common::GetCPUCaps().ssse3)
1765 ASSERT_MSG(0, "Trying to use SSSE3 on a system that doesn't support it. Bad programmer."); 1956 ASSERT_MSG(0, "Trying to use SSSE3 on a system that doesn't support it. Bad programmer.");
1766 WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); 1957 WriteSSEOp(opPrefix, op, regOp, arg, extrabytes);
1767} 1958}
1768 1959
1769void XEmitter::WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) 1960void XEmitter::WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) {
1770{
1771 if (!Common::GetCPUCaps().sse4_1) 1961 if (!Common::GetCPUCaps().sse4_1)
1772 ASSERT_MSG(0, "Trying to use SSE4.1 on a system that doesn't support it. Bad programmer."); 1962 ASSERT_MSG(0, "Trying to use SSE4.1 on a system that doesn't support it. Bad programmer.");
1773 WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); 1963 WriteSSEOp(opPrefix, op, regOp, arg, extrabytes);
1774} 1964}
1775 1965
1776void XEmitter::PSHUFB(X64Reg dest, const OpArg& arg) {WriteSSSE3Op(0x66, 0x3800, dest, arg);} 1966void XEmitter::PSHUFB(X64Reg dest, const OpArg& arg) {
1777void XEmitter::PTEST(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3817, dest, arg);} 1967 WriteSSSE3Op(0x66, 0x3800, dest, arg);
1778void XEmitter::PACKUSDW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x382b, dest, arg);} 1968}
1779void XEmitter::DPPS(X64Reg dest, const OpArg& arg, u8 mask) {WriteSSE41Op(0x66, 0x3A40, dest, arg, 1); Write8(mask);} 1969void XEmitter::PTEST(X64Reg dest, const OpArg& arg) {
1780 1970 WriteSSE41Op(0x66, 0x3817, dest, arg);
1781void XEmitter::PMINSB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3838, dest, arg);} 1971}
1782void XEmitter::PMINSD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3839, dest, arg);} 1972void XEmitter::PACKUSDW(X64Reg dest, const OpArg& arg) {
1783void XEmitter::PMINUW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383a, dest, arg);} 1973 WriteSSE41Op(0x66, 0x382b, dest, arg);
1784void XEmitter::PMINUD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383b, dest, arg);} 1974}
1785void XEmitter::PMAXSB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383c, dest, arg);} 1975void XEmitter::DPPS(X64Reg dest, const OpArg& arg, u8 mask) {
1786void XEmitter::PMAXSD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383d, dest, arg);} 1976 WriteSSE41Op(0x66, 0x3A40, dest, arg, 1);
1787void XEmitter::PMAXUW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383e, dest, arg);} 1977 Write8(mask);
1788void XEmitter::PMAXUD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x383f, dest, arg);} 1978}
1789 1979
1790void XEmitter::PMOVSXBW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3820, dest, arg);} 1980void XEmitter::PMINSB(X64Reg dest, const OpArg& arg) {
1791void XEmitter::PMOVSXBD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3821, dest, arg);} 1981 WriteSSE41Op(0x66, 0x3838, dest, arg);
1792void XEmitter::PMOVSXBQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3822, dest, arg);} 1982}
1793void XEmitter::PMOVSXWD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3823, dest, arg);} 1983void XEmitter::PMINSD(X64Reg dest, const OpArg& arg) {
1794void XEmitter::PMOVSXWQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3824, dest, arg);} 1984 WriteSSE41Op(0x66, 0x3839, dest, arg);
1795void XEmitter::PMOVSXDQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3825, dest, arg);} 1985}
1796void XEmitter::PMOVZXBW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3830, dest, arg);} 1986void XEmitter::PMINUW(X64Reg dest, const OpArg& arg) {
1797void XEmitter::PMOVZXBD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3831, dest, arg);} 1987 WriteSSE41Op(0x66, 0x383a, dest, arg);
1798void XEmitter::PMOVZXBQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3832, dest, arg);} 1988}
1799void XEmitter::PMOVZXWD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3833, dest, arg);} 1989void XEmitter::PMINUD(X64Reg dest, const OpArg& arg) {
1800void XEmitter::PMOVZXWQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3834, dest, arg);} 1990 WriteSSE41Op(0x66, 0x383b, dest, arg);
1801void XEmitter::PMOVZXDQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3835, dest, arg);} 1991}
1802 1992void XEmitter::PMAXSB(X64Reg dest, const OpArg& arg) {
1803void XEmitter::PBLENDVB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3810, dest, arg);} 1993 WriteSSE41Op(0x66, 0x383c, dest, arg);
1804void XEmitter::BLENDVPS(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3814, dest, arg);} 1994}
1805void XEmitter::BLENDVPD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3815, dest, arg);} 1995void 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); } 1996 WriteSSE41Op(0x66, 0x383d, dest, arg);
1807void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) { WriteSSE41Op(0x66, 0x3A0D, dest, arg, 1); Write8(blend); } 1997}
1808 1998void 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);} 1999 WriteSSE41Op(0x66, 0x383e, dest, arg);
1810void XEmitter::ROUNDSD(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A0B, dest, arg, 1); Write8(mode);} 2000}
1811void XEmitter::ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode) {WriteSSE41Op(0x66, 0x3A08, dest, arg, 1); Write8(mode);} 2001void 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);} 2002 WriteSSE41Op(0x66, 0x383f, dest, arg);
1813 2003}
1814void XEmitter::PAND(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDB, dest, arg);} 2004
1815void XEmitter::PANDN(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDF, dest, arg);} 2005void XEmitter::PMOVSXBW(X64Reg dest, const OpArg& arg) {
1816void XEmitter::PXOR(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEF, dest, arg);} 2006 WriteSSE41Op(0x66, 0x3820, dest, arg);
1817void XEmitter::POR(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEB, dest, arg);} 2007}
1818 2008void XEmitter::PMOVSXBD(X64Reg dest, const OpArg& arg) {
1819void XEmitter::PADDB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFC, dest, arg);} 2009 WriteSSE41Op(0x66, 0x3821, dest, arg);
1820void XEmitter::PADDW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFD, dest, arg);} 2010}
1821void XEmitter::PADDD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFE, dest, arg);} 2011void XEmitter::PMOVSXBQ(X64Reg dest, const OpArg& arg) {
1822void XEmitter::PADDQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD4, dest, arg);} 2012 WriteSSE41Op(0x66, 0x3822, dest, arg);
1823 2013}
1824void XEmitter::PADDSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEC, dest, arg);} 2014void XEmitter::PMOVSXWD(X64Reg dest, const OpArg& arg) {
1825void XEmitter::PADDSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xED, dest, arg);} 2015 WriteSSE41Op(0x66, 0x3823, dest, arg);
1826void XEmitter::PADDUSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDC, dest, arg);} 2016}
1827void XEmitter::PADDUSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDD, dest, arg);} 2017void XEmitter::PMOVSXWQ(X64Reg dest, const OpArg& arg) {
1828 2018 WriteSSE41Op(0x66, 0x3824, dest, arg);
1829void XEmitter::PSUBB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF8, dest, arg);} 2019}
1830void XEmitter::PSUBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF9, dest, arg);} 2020void XEmitter::PMOVSXDQ(X64Reg dest, const OpArg& arg) {
1831void XEmitter::PSUBD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFA, dest, arg);} 2021 WriteSSE41Op(0x66, 0x3825, dest, arg);
1832void XEmitter::PSUBQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFB, dest, arg);} 2022}
1833 2023void XEmitter::PMOVZXBW(X64Reg dest, const OpArg& arg) {
1834void XEmitter::PSUBSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE8, dest, arg);} 2024 WriteSSE41Op(0x66, 0x3830, dest, arg);
1835void XEmitter::PSUBSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE9, dest, arg);} 2025}
1836void XEmitter::PSUBUSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD8, dest, arg);} 2026void XEmitter::PMOVZXBD(X64Reg dest, const OpArg& arg) {
1837void XEmitter::PSUBUSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD9, dest, arg);} 2027 WriteSSE41Op(0x66, 0x3831, dest, arg);
1838 2028}
1839void XEmitter::PAVGB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE0, dest, arg);} 2029void XEmitter::PMOVZXBQ(X64Reg dest, const OpArg& arg) {
1840void XEmitter::PAVGW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE3, dest, arg);} 2030 WriteSSE41Op(0x66, 0x3832, dest, arg);
1841 2031}
1842void XEmitter::PCMPEQB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x74, dest, arg);} 2032void XEmitter::PMOVZXWD(X64Reg dest, const OpArg& arg) {
1843void XEmitter::PCMPEQW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x75, dest, arg);} 2033 WriteSSE41Op(0x66, 0x3833, dest, arg);
1844void XEmitter::PCMPEQD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x76, dest, arg);} 2034}
1845 2035void XEmitter::PMOVZXWQ(X64Reg dest, const OpArg& arg) {
1846void XEmitter::PCMPGTB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x64, dest, arg);} 2036 WriteSSE41Op(0x66, 0x3834, dest, arg);
1847void XEmitter::PCMPGTW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x65, dest, arg);} 2037}
1848void XEmitter::PCMPGTD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x66, dest, arg);} 2038void XEmitter::PMOVZXDQ(X64Reg dest, const OpArg& arg) {
1849 2039 WriteSSE41Op(0x66, 0x3835, dest, arg);
1850void XEmitter::PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSEOp(0x66, 0xC5, dest, arg, 1); Write8(subreg);} 2040}
1851void XEmitter::PINSRW(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSEOp(0x66, 0xC4, dest, arg, 1); Write8(subreg);} 2041
1852 2042void XEmitter::PBLENDVB(X64Reg dest, const OpArg& arg) {
1853void XEmitter::PMADDWD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF5, dest, arg); } 2043 WriteSSE41Op(0x66, 0x3810, dest, arg);
1854void XEmitter::PSADBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF6, dest, arg);} 2044}
1855 2045void XEmitter::BLENDVPS(X64Reg dest, const OpArg& arg) {
1856void XEmitter::PMAXSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEE, dest, arg); } 2046 WriteSSE41Op(0x66, 0x3814, dest, arg);
1857void XEmitter::PMAXUB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDE, dest, arg); } 2047}
1858void XEmitter::PMINSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEA, dest, arg); } 2048void XEmitter::BLENDVPD(X64Reg dest, const OpArg& arg) {
1859void XEmitter::PMINUB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDA, dest, arg); } 2049 WriteSSE41Op(0x66, 0x3815, dest, arg);
1860 2050}
1861void XEmitter::PMOVMSKB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD7, dest, arg); } 2051void 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);} 2052 WriteSSE41Op(0x66, 0x3A0C, dest, arg, 1);
1863void XEmitter::PSHUFLW(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0xF2, 0x70, regOp, arg, 1); Write8(shuffle);} 2053 Write8(blend);
1864void XEmitter::PSHUFHW(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0xF3, 0x70, regOp, arg, 1); Write8(shuffle);} 2054}
2055void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) {
2056 WriteSSE41Op(0x66, 0x3A0D, dest, arg, 1);
2057 Write8(blend);
2058}
2059
2060void XEmitter::ROUNDSS(X64Reg dest, const OpArg& arg, u8 mode) {
2061 WriteSSE41Op(0x66, 0x3A0A, dest, arg, 1);
2062 Write8(mode);
2063}
2064void XEmitter::ROUNDSD(X64Reg dest, const OpArg& arg, u8 mode) {
2065 WriteSSE41Op(0x66, 0x3A0B, dest, arg, 1);
2066 Write8(mode);
2067}
2068void XEmitter::ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode) {
2069 WriteSSE41Op(0x66, 0x3A08, dest, arg, 1);
2070 Write8(mode);
2071}
2072void XEmitter::ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode) {
2073 WriteSSE41Op(0x66, 0x3A09, dest, arg, 1);
2074 Write8(mode);
2075}
2076
2077void XEmitter::PAND(X64Reg dest, const OpArg& arg) {
2078 WriteSSEOp(0x66, 0xDB, dest, arg);
2079}
2080void XEmitter::PANDN(X64Reg dest, const OpArg& arg) {
2081 WriteSSEOp(0x66, 0xDF, dest, arg);
2082}
2083void XEmitter::PXOR(X64Reg dest, const OpArg& arg) {
2084 WriteSSEOp(0x66, 0xEF, dest, arg);
2085}
2086void XEmitter::POR(X64Reg dest, const OpArg& arg) {
2087 WriteSSEOp(0x66, 0xEB, dest, arg);
2088}
2089
2090void XEmitter::PADDB(X64Reg dest, const OpArg& arg) {
2091 WriteSSEOp(0x66, 0xFC, dest, arg);
2092}
2093void XEmitter::PADDW(X64Reg dest, const OpArg& arg) {
2094 WriteSSEOp(0x66, 0xFD, dest, arg);
2095}
2096void XEmitter::PADDD(X64Reg dest, const OpArg& arg) {
2097 WriteSSEOp(0x66, 0xFE, dest, arg);
2098}
2099void XEmitter::PADDQ(X64Reg dest, const OpArg& arg) {
2100 WriteSSEOp(0x66, 0xD4, dest, arg);
2101}
2102
2103void XEmitter::PADDSB(X64Reg dest, const OpArg& arg) {
2104 WriteSSEOp(0x66, 0xEC, dest, arg);
2105}
2106void XEmitter::PADDSW(X64Reg dest, const OpArg& arg) {
2107 WriteSSEOp(0x66, 0xED, dest, arg);
2108}
2109void XEmitter::PADDUSB(X64Reg dest, const OpArg& arg) {
2110 WriteSSEOp(0x66, 0xDC, dest, arg);
2111}
2112void XEmitter::PADDUSW(X64Reg dest, const OpArg& arg) {
2113 WriteSSEOp(0x66, 0xDD, dest, arg);
2114}
2115
2116void XEmitter::PSUBB(X64Reg dest, const OpArg& arg) {
2117 WriteSSEOp(0x66, 0xF8, dest, arg);
2118}
2119void XEmitter::PSUBW(X64Reg dest, const OpArg& arg) {
2120 WriteSSEOp(0x66, 0xF9, dest, arg);
2121}
2122void XEmitter::PSUBD(X64Reg dest, const OpArg& arg) {
2123 WriteSSEOp(0x66, 0xFA, dest, arg);
2124}
2125void XEmitter::PSUBQ(X64Reg dest, const OpArg& arg) {
2126 WriteSSEOp(0x66, 0xFB, dest, arg);
2127}
2128
2129void XEmitter::PSUBSB(X64Reg dest, const OpArg& arg) {
2130 WriteSSEOp(0x66, 0xE8, dest, arg);
2131}
2132void XEmitter::PSUBSW(X64Reg dest, const OpArg& arg) {
2133 WriteSSEOp(0x66, 0xE9, dest, arg);
2134}
2135void XEmitter::PSUBUSB(X64Reg dest, const OpArg& arg) {
2136 WriteSSEOp(0x66, 0xD8, dest, arg);
2137}
2138void XEmitter::PSUBUSW(X64Reg dest, const OpArg& arg) {
2139 WriteSSEOp(0x66, 0xD9, dest, arg);
2140}
2141
2142void XEmitter::PAVGB(X64Reg dest, const OpArg& arg) {
2143 WriteSSEOp(0x66, 0xE0, dest, arg);
2144}
2145void XEmitter::PAVGW(X64Reg dest, const OpArg& arg) {
2146 WriteSSEOp(0x66, 0xE3, dest, arg);
2147}
2148
2149void XEmitter::PCMPEQB(X64Reg dest, const OpArg& arg) {
2150 WriteSSEOp(0x66, 0x74, dest, arg);
2151}
2152void XEmitter::PCMPEQW(X64Reg dest, const OpArg& arg) {
2153 WriteSSEOp(0x66, 0x75, dest, arg);
2154}
2155void XEmitter::PCMPEQD(X64Reg dest, const OpArg& arg) {
2156 WriteSSEOp(0x66, 0x76, dest, arg);
2157}
2158
2159void XEmitter::PCMPGTB(X64Reg dest, const OpArg& arg) {
2160 WriteSSEOp(0x66, 0x64, dest, arg);
2161}
2162void XEmitter::PCMPGTW(X64Reg dest, const OpArg& arg) {
2163 WriteSSEOp(0x66, 0x65, dest, arg);
2164}
2165void XEmitter::PCMPGTD(X64Reg dest, const OpArg& arg) {
2166 WriteSSEOp(0x66, 0x66, dest, arg);
2167}
2168
2169void XEmitter::PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg) {
2170 WriteSSEOp(0x66, 0xC5, dest, arg, 1);
2171 Write8(subreg);
2172}
2173void XEmitter::PINSRW(X64Reg dest, const OpArg& arg, u8 subreg) {
2174 WriteSSEOp(0x66, 0xC4, dest, arg, 1);
2175 Write8(subreg);
2176}
2177
2178void XEmitter::PMADDWD(X64Reg dest, const OpArg& arg) {
2179 WriteSSEOp(0x66, 0xF5, dest, arg);
2180}
2181void XEmitter::PSADBW(X64Reg dest, const OpArg& arg) {
2182 WriteSSEOp(0x66, 0xF6, dest, arg);
2183}
2184
2185void XEmitter::PMAXSW(X64Reg dest, const OpArg& arg) {
2186 WriteSSEOp(0x66, 0xEE, dest, arg);
2187}
2188void XEmitter::PMAXUB(X64Reg dest, const OpArg& arg) {
2189 WriteSSEOp(0x66, 0xDE, dest, arg);
2190}
2191void XEmitter::PMINSW(X64Reg dest, const OpArg& arg) {
2192 WriteSSEOp(0x66, 0xEA, dest, arg);
2193}
2194void XEmitter::PMINUB(X64Reg dest, const OpArg& arg) {
2195 WriteSSEOp(0x66, 0xDA, dest, arg);
2196}
2197
2198void XEmitter::PMOVMSKB(X64Reg dest, const OpArg& arg) {
2199 WriteSSEOp(0x66, 0xD7, dest, arg);
2200}
2201void XEmitter::PSHUFD(X64Reg regOp, const OpArg& arg, u8 shuffle) {
2202 WriteSSEOp(0x66, 0x70, regOp, arg, 1);
2203 Write8(shuffle);
2204}
2205void XEmitter::PSHUFLW(X64Reg regOp, const OpArg& arg, u8 shuffle) {
2206 WriteSSEOp(0xF2, 0x70, regOp, arg, 1);
2207 Write8(shuffle);
2208}
2209void XEmitter::PSHUFHW(X64Reg regOp, const OpArg& arg, u8 shuffle) {
2210 WriteSSEOp(0xF3, 0x70, regOp, arg, 1);
2211 Write8(shuffle);
2212}
1865 2213
1866// VEX 2214// VEX
1867void XEmitter::VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseADD, regOp1, regOp2, arg);} 2215void 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);} 2216 WriteAVXOp(0xF2, sseADD, regOp1, regOp2, arg);
1869void XEmitter::VMULSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseMUL, regOp1, regOp2, arg);} 2217}
1870void XEmitter::VDIVSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseDIV, regOp1, regOp2, arg);} 2218void 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);} 2219 WriteAVXOp(0xF2, sseSUB, regOp1, regOp2, arg);
1872void XEmitter::VSUBPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseSUB, regOp1, regOp2, arg);} 2220}
1873void XEmitter::VMULPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseMUL, regOp1, regOp2, arg);} 2221void 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);} 2222 WriteAVXOp(0xF2, sseMUL, regOp1, regOp2, arg);
1875void XEmitter::VSQRTSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseSQRT, regOp1, regOp2, arg);} 2223}
1876void XEmitter::VSHUFPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 shuffle) {WriteAVXOp(0x66, sseSHUF, regOp1, regOp2, arg, 1); Write8(shuffle);} 2224void 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);} 2225 WriteAVXOp(0xF2, sseDIV, regOp1, regOp2, arg);
1878void XEmitter::VUNPCKHPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg){WriteAVXOp(0x66, 0x15, regOp1, regOp2, arg);} 2226}
1879 2227void 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); } 2228 WriteAVXOp(0x66, sseADD, regOp1, regOp2, arg);
1881void XEmitter::VANDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseAND, regOp1, regOp2, arg); } 2229}
1882void XEmitter::VANDNPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseANDN, regOp1, regOp2, arg); } 2230void 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); } 2231 WriteAVXOp(0x66, sseSUB, regOp1, regOp2, arg);
1884void XEmitter::VORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x00, sseOR, regOp1, regOp2, arg); } 2232}
1885void XEmitter::VORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseOR, regOp1, regOp2, arg); } 2233void 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); } 2234 WriteAVXOp(0x66, sseMUL, regOp1, regOp2, arg);
1887void XEmitter::VXORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, sseXOR, regOp1, regOp2, arg); } 2235}
1888 2236void 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); } 2237 WriteAVXOp(0x66, sseDIV, regOp1, regOp2, arg);
1890void XEmitter::VPANDN(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xDF, regOp1, regOp2, arg); } 2238}
1891void XEmitter::VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0xEB, regOp1, regOp2, arg); } 2239void 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); } 2240 WriteAVXOp(0xF2, sseSQRT, regOp1, regOp2, arg);
1893 2241}
1894void XEmitter::VFMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg); } 2242void 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); } 2243 WriteAVXOp(0x66, sseSHUF, regOp1, regOp2, arg, 1);
1896void XEmitter::VFMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg); } 2244 Write8(shuffle);
1897void XEmitter::VFMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg, 1); } 2245}
1898void XEmitter::VFMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg, 1); } 2246void 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); } 2247 WriteAVXOp(0x66, 0x14, regOp1, regOp2, arg);
1900void XEmitter::VFMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg); } 2248}
1901void XEmitter::VFMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg); } 2249void 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); } 2250 WriteAVXOp(0x66, 0x15, regOp1, regOp2, arg);
1903void XEmitter::VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg, 1); } 2251}
1904void XEmitter::VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg, 1); } 2252
1905void XEmitter::VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg, 1); } 2253void 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); } 2254 WriteAVXOp(0x00, sseAND, regOp1, regOp2, arg);
1907void XEmitter::VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg); } 2255}
1908void XEmitter::VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg); } 2256void 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); } 2257 WriteAVXOp(0x66, sseAND, regOp1, regOp2, arg);
1910void XEmitter::VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg, 1); } 2258}
1911void XEmitter::VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg, 1); } 2259void 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); } 2260 WriteAVXOp(0x00, sseANDN, regOp1, regOp2, arg);
1913void XEmitter::VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg); } 2261}
1914void XEmitter::VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg); } 2262void 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); } 2263 WriteAVXOp(0x66, sseANDN, regOp1, regOp2, arg);
1916void XEmitter::VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg, 1); } 2264}
1917void XEmitter::VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg, 1); } 2265void 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); } 2266 WriteAVXOp(0x00, sseOR, regOp1, regOp2, arg);
1919void XEmitter::VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg); } 2267}
1920void XEmitter::VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg); } 2268void 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); } 2269 WriteAVXOp(0x66, sseOR, regOp1, regOp2, arg);
1922void XEmitter::VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg, 1); } 2270}
1923void XEmitter::VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg, 1); } 2271void 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); } 2272 WriteAVXOp(0x00, sseXOR, regOp1, regOp2, arg);
1925void XEmitter::VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg); } 2273}
1926void XEmitter::VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg); } 2274void 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); } 2275 WriteAVXOp(0x66, sseXOR, regOp1, regOp2, arg);
1928void XEmitter::VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg, 1); } 2276}
1929void XEmitter::VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg, 1); } 2277
1930void XEmitter::VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg); } 2278void 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); } 2279 WriteAVXOp(0x66, 0xDB, regOp1, regOp2, arg);
1932void XEmitter::VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg); } 2280}
1933void XEmitter::VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg, 1); } 2281void 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); } 2282 WriteAVXOp(0x66, 0xDF, regOp1, regOp2, arg);
1935void XEmitter::VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg, 1); } 2283}
1936void XEmitter::VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg); } 2284void 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); } 2285 WriteAVXOp(0x66, 0xEB, regOp1, regOp2, arg);
1938void XEmitter::VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg); } 2286}
1939void XEmitter::VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg, 1); } 2287void 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); } 2288 WriteAVXOp(0x66, 0xEF, regOp1, regOp2, arg);
1941void XEmitter::VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg, 1); } 2289}
1942void XEmitter::VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg); } 2290
1943void XEmitter::VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg); } 2291void 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); } 2292 WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg);
1945void XEmitter::VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg, 1); } 2293}
1946void XEmitter::VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg, 1); } 2294void 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); } 2295 WriteAVXOp(0x66, 0x38A8, regOp1, regOp2, arg);
1948void XEmitter::VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg); } 2296}
1949void XEmitter::VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg); } 2297void 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); } 2298 WriteAVXOp(0x66, 0x38B8, regOp1, regOp2, arg);
1951void XEmitter::VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg, 1); } 2299}
1952void XEmitter::VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) { WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg, 1); } 2300void 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); } 2301 WriteAVXOp(0x66, 0x3898, regOp1, regOp2, arg, 1);
1954 2302}
1955void XEmitter::SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0xF3, 0x38F7, regOp1, regOp2, arg);} 2303void 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);} 2304 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);} 2305}
1958void XEmitter::RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate) {WriteBMI2Op(bits, 0xF2, 0x3AF0, regOp, INVALID_REG, arg, 1); Write8(rotate);} 2306void 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);} 2307 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);} 2308}
1961void XEmitter::MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI2Op(bits, 0xF2, 0x38F6, regOp2, regOp1, arg);} 2309void 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);} 2310 WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg);
1963void XEmitter::BLSR(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x1, regOp, arg);} 2311}
1964void XEmitter::BLSMSK(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x2, regOp, arg);} 2312void 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);} 2313 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);} 2314}
1967void XEmitter::ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F2, regOp1, regOp2, arg);} 2315void XEmitter::VFMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2316 WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg);
2317}
2318void XEmitter::VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2319 WriteAVXOp(0x66, 0x3899, regOp1, regOp2, arg, 1);
2320}
2321void XEmitter::VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2322 WriteAVXOp(0x66, 0x38A9, regOp1, regOp2, arg, 1);
2323}
2324void XEmitter::VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2325 WriteAVXOp(0x66, 0x38B9, regOp1, regOp2, arg, 1);
2326}
2327void XEmitter::VFMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2328 WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg);
2329}
2330void XEmitter::VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2331 WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg);
2332}
2333void XEmitter::VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2334 WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg);
2335}
2336void XEmitter::VFMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2337 WriteAVXOp(0x66, 0x389A, regOp1, regOp2, arg, 1);
2338}
2339void XEmitter::VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2340 WriteAVXOp(0x66, 0x38AA, regOp1, regOp2, arg, 1);
2341}
2342void XEmitter::VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2343 WriteAVXOp(0x66, 0x38BA, regOp1, regOp2, arg, 1);
2344}
2345void XEmitter::VFMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2346 WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg);
2347}
2348void XEmitter::VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2349 WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg);
2350}
2351void XEmitter::VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2352 WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg);
2353}
2354void XEmitter::VFMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2355 WriteAVXOp(0x66, 0x389B, regOp1, regOp2, arg, 1);
2356}
2357void XEmitter::VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2358 WriteAVXOp(0x66, 0x38AB, regOp1, regOp2, arg, 1);
2359}
2360void XEmitter::VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2361 WriteAVXOp(0x66, 0x38BB, regOp1, regOp2, arg, 1);
2362}
2363void XEmitter::VFNMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2364 WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg);
2365}
2366void XEmitter::VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2367 WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg);
2368}
2369void XEmitter::VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2370 WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg);
2371}
2372void XEmitter::VFNMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2373 WriteAVXOp(0x66, 0x389C, regOp1, regOp2, arg, 1);
2374}
2375void XEmitter::VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2376 WriteAVXOp(0x66, 0x38AC, regOp1, regOp2, arg, 1);
2377}
2378void XEmitter::VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2379 WriteAVXOp(0x66, 0x38BC, regOp1, regOp2, arg, 1);
2380}
2381void XEmitter::VFNMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2382 WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg);
2383}
2384void XEmitter::VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2385 WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg);
2386}
2387void XEmitter::VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2388 WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg);
2389}
2390void XEmitter::VFNMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2391 WriteAVXOp(0x66, 0x389D, regOp1, regOp2, arg, 1);
2392}
2393void XEmitter::VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2394 WriteAVXOp(0x66, 0x38AD, regOp1, regOp2, arg, 1);
2395}
2396void XEmitter::VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2397 WriteAVXOp(0x66, 0x38BD, regOp1, regOp2, arg, 1);
2398}
2399void XEmitter::VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2400 WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg);
2401}
2402void XEmitter::VFNMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2403 WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg);
2404}
2405void XEmitter::VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2406 WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg);
2407}
2408void XEmitter::VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2409 WriteAVXOp(0x66, 0x389E, regOp1, regOp2, arg, 1);
2410}
2411void XEmitter::VFNMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2412 WriteAVXOp(0x66, 0x38AE, regOp1, regOp2, arg, 1);
2413}
2414void XEmitter::VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2415 WriteAVXOp(0x66, 0x38BE, regOp1, regOp2, arg, 1);
2416}
2417void XEmitter::VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2418 WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg);
2419}
2420void XEmitter::VFNMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2421 WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg);
2422}
2423void XEmitter::VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2424 WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg);
2425}
2426void XEmitter::VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2427 WriteAVXOp(0x66, 0x389F, regOp1, regOp2, arg, 1);
2428}
2429void XEmitter::VFNMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2430 WriteAVXOp(0x66, 0x38AF, regOp1, regOp2, arg, 1);
2431}
2432void XEmitter::VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2433 WriteAVXOp(0x66, 0x38BF, regOp1, regOp2, arg, 1);
2434}
2435void XEmitter::VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2436 WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg);
2437}
2438void XEmitter::VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2439 WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg);
2440}
2441void XEmitter::VFMADDSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2442 WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg);
2443}
2444void XEmitter::VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2445 WriteAVXOp(0x66, 0x3896, regOp1, regOp2, arg, 1);
2446}
2447void XEmitter::VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2448 WriteAVXOp(0x66, 0x38A6, regOp1, regOp2, arg, 1);
2449}
2450void XEmitter::VFMADDSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2451 WriteAVXOp(0x66, 0x38B6, regOp1, regOp2, arg, 1);
2452}
2453void XEmitter::VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2454 WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg);
2455}
2456void XEmitter::VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2457 WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg);
2458}
2459void XEmitter::VFMSUBADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2460 WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg);
2461}
2462void XEmitter::VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2463 WriteAVXOp(0x66, 0x3897, regOp1, regOp2, arg, 1);
2464}
2465void XEmitter::VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2466 WriteAVXOp(0x66, 0x38A7, regOp1, regOp2, arg, 1);
2467}
2468void XEmitter::VFMSUBADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2469 WriteAVXOp(0x66, 0x38B7, regOp1, regOp2, arg, 1);
2470}
2471
2472void XEmitter::SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {
2473 WriteBMI2Op(bits, 0xF3, 0x38F7, regOp1, regOp2, arg);
2474}
2475void XEmitter::SHLX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {
2476 WriteBMI2Op(bits, 0x66, 0x38F7, regOp1, regOp2, arg);
2477}
2478void XEmitter::SHRX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {
2479 WriteBMI2Op(bits, 0xF2, 0x38F7, regOp1, regOp2, arg);
2480}
2481void XEmitter::RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate) {
2482 WriteBMI2Op(bits, 0xF2, 0x3AF0, regOp, INVALID_REG, arg, 1);
2483 Write8(rotate);
2484}
2485void XEmitter::PEXT(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2486 WriteBMI2Op(bits, 0xF3, 0x38F5, regOp1, regOp2, arg);
2487}
2488void XEmitter::PDEP(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2489 WriteBMI2Op(bits, 0xF2, 0x38F5, regOp1, regOp2, arg);
2490}
2491void XEmitter::MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2492 WriteBMI2Op(bits, 0xF2, 0x38F6, regOp2, regOp1, arg);
2493}
2494void XEmitter::BZHI(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {
2495 WriteBMI2Op(bits, 0x00, 0x38F5, regOp1, regOp2, arg);
2496}
2497void XEmitter::BLSR(int bits, X64Reg regOp, const OpArg& arg) {
2498 WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x1, regOp, arg);
2499}
2500void XEmitter::BLSMSK(int bits, X64Reg regOp, const OpArg& arg) {
2501 WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x2, regOp, arg);
2502}
2503void XEmitter::BLSI(int bits, X64Reg regOp, const OpArg& arg) {
2504 WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x3, regOp, arg);
2505}
2506void XEmitter::BEXTR(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {
2507 WriteBMI1Op(bits, 0x00, 0x38F7, regOp1, regOp2, arg);
2508}
2509void XEmitter::ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {
2510 WriteBMI1Op(bits, 0x00, 0x38F2, regOp1, regOp2, arg);
2511}
1968 2512
1969// Prefixes 2513// Prefixes
1970 2514
1971void XEmitter::LOCK() { Write8(0xF0); } 2515void XEmitter::LOCK() {
1972void XEmitter::REP() { Write8(0xF3); } 2516 Write8(0xF0);
1973void XEmitter::REPNE() { Write8(0xF2); } 2517}
1974void XEmitter::FSOverride() { Write8(0x64); } 2518void XEmitter::REP() {
1975void XEmitter::GSOverride() { Write8(0x65); } 2519 Write8(0xF3);
2520}
2521void XEmitter::REPNE() {
2522 Write8(0xF2);
2523}
2524void XEmitter::FSOverride() {
2525 Write8(0x64);
2526}
2527void XEmitter::GSOverride() {
2528 Write8(0x65);
2529}
1976 2530
1977void XEmitter::FWAIT() 2531void XEmitter::FWAIT() {
1978{
1979 Write8(0x9B); 2532 Write8(0x9B);
1980} 2533}
1981 2534
1982// TODO: make this more generic 2535// TODO: make this more generic
1983void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg) 2536void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg) {
1984{
1985 int mf = 0; 2537 int mf = 0;
1986 ASSERT_MSG(!(bits == 80 && op_80b == floatINVALID), "WriteFloatLoadStore: 80 bits not supported for this instruction"); 2538 ASSERT_MSG(!(bits == 80 && op_80b == floatINVALID),
1987 switch (bits) 2539 "WriteFloatLoadStore: 80 bits not supported for this instruction");
1988 { 2540 switch (bits) {
1989 case 32: mf = 0; break; 2541 case 32:
1990 case 64: mf = 4; break; 2542 mf = 0;
1991 case 80: mf = 2; break; 2543 break;
1992 default: ASSERT_MSG(0, "WriteFloatLoadStore: invalid bits (should be 32/64/80)"); 2544 case 64:
2545 mf = 4;
2546 break;
2547 case 80:
2548 mf = 2;
2549 break;
2550 default:
2551 ASSERT_MSG(0, "WriteFloatLoadStore: invalid bits (should be 32/64/80)");
1993 } 2552 }
1994 Write8(0xd9 | mf); 2553 Write8(0xd9 | mf);
1995 // x87 instructions use the reg field of the ModR/M byte as opcode: 2554 // x87 instructions use the reg field of the ModR/M byte as opcode:
1996 if (bits == 80) 2555 if (bits == 80)
1997 op = op_80b; 2556 op = op_80b;
1998 arg.WriteRest(this, 0, (X64Reg) op); 2557 arg.WriteRest(this, 0, (X64Reg)op);
1999} 2558}
2000 2559
2001void XEmitter::FLD(int bits, const OpArg& src) {WriteFloatLoadStore(bits, floatLD, floatLD80, src);} 2560void XEmitter::FLD(int bits, const OpArg& src) {
2002void XEmitter::FST(int bits, const OpArg& dest) {WriteFloatLoadStore(bits, floatST, floatINVALID, dest);} 2561 WriteFloatLoadStore(bits, floatLD, floatLD80, src);
2003void XEmitter::FSTP(int bits, const OpArg& dest) {WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest);} 2562}
2004void XEmitter::FNSTSW_AX() { Write8(0xDF); Write8(0xE0); } 2563void XEmitter::FST(int bits, const OpArg& dest) {
2564 WriteFloatLoadStore(bits, floatST, floatINVALID, dest);
2565}
2566void XEmitter::FSTP(int bits, const OpArg& dest) {
2567 WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest);
2568}
2569void XEmitter::FNSTSW_AX() {
2570 Write8(0xDF);
2571 Write8(0xE0);
2572}
2005 2573
2006void XEmitter::RDTSC() { Write8(0x0F); Write8(0x31); } 2574void XEmitter::RDTSC() {
2575 Write8(0x0F);
2576 Write8(0x31);
2577}
2007 2578
2008void XCodeBlock::PoisonMemory() { 2579void XCodeBlock::PoisonMemory() {
2009 // x86/64: 0xCC = breakpoint 2580 // x86/64: 0xCC = breakpoint
2010 memset(region, 0xCC, region_size); 2581 memset(region, 0xCC, region_size);
2011} 2582}
2012
2013} 2583}
diff --git a/src/common/x64/emitter.h b/src/common/x64/emitter.h
index 60a77dfe1..7d7cdde16 100644
--- a/src/common/x64/emitter.h
+++ b/src/common/x64/emitter.h
@@ -18,11 +18,10 @@
18#pragma once 18#pragma once
19 19
20#include <cstddef> 20#include <cstddef>
21
22#include "common/assert.h" 21#include "common/assert.h"
23#include "common/bit_set.h" 22#include "common/bit_set.h"
24#include "common/common_types.h"
25#include "common/code_block.h" 23#include "common/code_block.h"
24#include "common/common_types.h"
26 25
27#if defined(ARCHITECTURE_x86_64) && !defined(_ARCH_64) 26#if defined(ARCHITECTURE_x86_64) && !defined(_ARCH_64)
28#define _ARCH_64 27#define _ARCH_64
@@ -34,75 +33,145 @@
34#define PTRBITS 32 33#define PTRBITS 32
35#endif 34#endif
36 35
37namespace Gen 36namespace Gen {
38{ 37
39 38enum X64Reg {
40enum X64Reg 39 EAX = 0,
41{ 40 EBX = 3,
42 EAX = 0, EBX = 3, ECX = 1, EDX = 2, 41 ECX = 1,
43 ESI = 6, EDI = 7, EBP = 5, ESP = 4, 42 EDX = 2,
44 43 ESI = 6,
45 RAX = 0, RBX = 3, RCX = 1, RDX = 2, 44 EDI = 7,
46 RSI = 6, RDI = 7, RBP = 5, RSP = 4, 45 EBP = 5,
47 R8 = 8, R9 = 9, R10 = 10,R11 = 11, 46 ESP = 4,
48 R12 = 12,R13 = 13,R14 = 14,R15 = 15, 47
49 48 RAX = 0,
50 AL = 0, BL = 3, CL = 1, DL = 2, 49 RBX = 3,
51 SIL = 6, DIL = 7, BPL = 5, SPL = 4, 50 RCX = 1,
52 AH = 0x104, BH = 0x107, CH = 0x105, DH = 0x106, 51 RDX = 2,
53 52 RSI = 6,
54 AX = 0, BX = 3, CX = 1, DX = 2, 53 RDI = 7,
55 SI = 6, DI = 7, BP = 5, SP = 4, 54 RBP = 5,
56 55 RSP = 4,
57 XMM0=0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, 56 R8 = 8,
58 XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, 57 R9 = 9,
59 58 R10 = 10,
60 YMM0=0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7, 59 R11 = 11,
61 YMM8, YMM9, YMM10, YMM11, YMM12, YMM13, YMM14, YMM15, 60 R12 = 12,
61 R13 = 13,
62 R14 = 14,
63 R15 = 15,
64
65 AL = 0,
66 BL = 3,
67 CL = 1,
68 DL = 2,
69 SIL = 6,
70 DIL = 7,
71 BPL = 5,
72 SPL = 4,
73 AH = 0x104,
74 BH = 0x107,
75 CH = 0x105,
76 DH = 0x106,
77
78 AX = 0,
79 BX = 3,
80 CX = 1,
81 DX = 2,
82 SI = 6,
83 DI = 7,
84 BP = 5,
85 SP = 4,
86
87 XMM0 = 0,
88 XMM1,
89 XMM2,
90 XMM3,
91 XMM4,
92 XMM5,
93 XMM6,
94 XMM7,
95 XMM8,
96 XMM9,
97 XMM10,
98 XMM11,
99 XMM12,
100 XMM13,
101 XMM14,
102 XMM15,
103
104 YMM0 = 0,
105 YMM1,
106 YMM2,
107 YMM3,
108 YMM4,
109 YMM5,
110 YMM6,
111 YMM7,
112 YMM8,
113 YMM9,
114 YMM10,
115 YMM11,
116 YMM12,
117 YMM13,
118 YMM14,
119 YMM15,
62 120
63 INVALID_REG = 0xFFFFFFFF 121 INVALID_REG = 0xFFFFFFFF
64}; 122};
65 123
66enum CCFlags 124enum CCFlags {
67{ 125 CC_O = 0,
68 CC_O = 0, 126 CC_NO = 1,
69 CC_NO = 1, 127 CC_B = 2,
70 CC_B = 2, CC_C = 2, CC_NAE = 2, 128 CC_C = 2,
71 CC_NB = 3, CC_NC = 3, CC_AE = 3, 129 CC_NAE = 2,
72 CC_Z = 4, CC_E = 4, 130 CC_NB = 3,
73 CC_NZ = 5, CC_NE = 5, 131 CC_NC = 3,
74 CC_BE = 6, CC_NA = 6, 132 CC_AE = 3,
75 CC_NBE = 7, CC_A = 7, 133 CC_Z = 4,
76 CC_S = 8, 134 CC_E = 4,
77 CC_NS = 9, 135 CC_NZ = 5,
78 CC_P = 0xA, CC_PE = 0xA, 136 CC_NE = 5,
79 CC_NP = 0xB, CC_PO = 0xB, 137 CC_BE = 6,
80 CC_L = 0xC, CC_NGE = 0xC, 138 CC_NA = 6,
81 CC_NL = 0xD, CC_GE = 0xD, 139 CC_NBE = 7,
82 CC_LE = 0xE, CC_NG = 0xE, 140 CC_A = 7,
83 CC_NLE = 0xF, CC_G = 0xF 141 CC_S = 8,
142 CC_NS = 9,
143 CC_P = 0xA,
144 CC_PE = 0xA,
145 CC_NP = 0xB,
146 CC_PO = 0xB,
147 CC_L = 0xC,
148 CC_NGE = 0xC,
149 CC_NL = 0xD,
150 CC_GE = 0xD,
151 CC_LE = 0xE,
152 CC_NG = 0xE,
153 CC_NLE = 0xF,
154 CC_G = 0xF
84}; 155};
85 156
86enum 157enum {
87{
88 NUMGPRs = 16, 158 NUMGPRs = 16,
89 NUMXMMs = 16, 159 NUMXMMs = 16,
90}; 160};
91 161
92enum 162enum {
93{
94 SCALE_NONE = 0, 163 SCALE_NONE = 0,
95 SCALE_1 = 1, 164 SCALE_1 = 1,
96 SCALE_2 = 2, 165 SCALE_2 = 2,
97 SCALE_4 = 4, 166 SCALE_4 = 4,
98 SCALE_8 = 8, 167 SCALE_8 = 8,
99 SCALE_ATREG = 16, 168 SCALE_ATREG = 16,
100 //SCALE_NOBASE_1 is not supported and can be replaced with SCALE_ATREG 169 // SCALE_NOBASE_1 is not supported and can be replaced with SCALE_ATREG
101 SCALE_NOBASE_2 = 34, 170 SCALE_NOBASE_2 = 34,
102 SCALE_NOBASE_4 = 36, 171 SCALE_NOBASE_4 = 36,
103 SCALE_NOBASE_8 = 40, 172 SCALE_NOBASE_8 = 40,
104 SCALE_RIP = 0xFF, 173 SCALE_RIP = 0xFF,
105 SCALE_IMM8 = 0xF0, 174 SCALE_IMM8 = 0xF0,
106 SCALE_IMM16 = 0xF1, 175 SCALE_IMM16 = 0xF1,
107 SCALE_IMM32 = 0xF2, 176 SCALE_IMM32 = 0xF2,
108 SCALE_IMM64 = 0xF3, 177 SCALE_IMM64 = 0xF3,
@@ -114,7 +183,7 @@ enum NormalOp {
114 nrmSUB, 183 nrmSUB,
115 nrmSBB, 184 nrmSBB,
116 nrmAND, 185 nrmAND,
117 nrmOR , 186 nrmOR,
118 nrmXOR, 187 nrmXOR,
119 nrmMOV, 188 nrmMOV,
120 nrmTEST, 189 nrmTEST,
@@ -157,68 +226,73 @@ enum FloatRound {
157class XEmitter; 226class XEmitter;
158 227
159// RIP addressing does not benefit from micro op fusion on Core arch 228// RIP addressing does not benefit from micro op fusion on Core arch
160struct OpArg 229struct OpArg {
161{
162 friend class XEmitter; 230 friend class XEmitter;
163 231
164 constexpr OpArg() = default; // dummy op arg, used for storage 232 constexpr OpArg() = default; // dummy op arg, used for storage
165 constexpr OpArg(u64 offset_, int scale_, X64Reg rmReg = RAX, X64Reg scaledReg = RAX) 233 constexpr OpArg(u64 offset_, int scale_, X64Reg rmReg = RAX, X64Reg scaledReg = RAX)
166 : scale(static_cast<u8>(scale_)) 234 : scale(static_cast<u8>(scale_)), offsetOrBaseReg(static_cast<u16>(rmReg)),
167 , offsetOrBaseReg(static_cast<u16>(rmReg)) 235 indexReg(static_cast<u16>(scaledReg)), offset(offset_) {}
168 , indexReg(static_cast<u16>(scaledReg))
169 , offset(offset_)
170 {
171 }
172 236
173 constexpr bool operator==(const OpArg &b) const 237 constexpr bool operator==(const OpArg& b) const {
174 { 238 return operandReg == b.operandReg && scale == b.scale &&
175 return operandReg == b.operandReg && 239 offsetOrBaseReg == b.offsetOrBaseReg && indexReg == b.indexReg && offset == b.offset;
176 scale == b.scale &&
177 offsetOrBaseReg == b.offsetOrBaseReg &&
178 indexReg == b.indexReg &&
179 offset == b.offset;
180 } 240 }
181 241
182 void WriteRex(XEmitter *emit, int opBits, int bits, int customOp = -1) const; 242 void WriteRex(XEmitter* emit, int opBits, int bits, int customOp = -1) const;
183 void WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, int W = 0) const; 243 void WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm,
184 void WriteRest(XEmitter *emit, int extraBytes=0, X64Reg operandReg=INVALID_REG, bool warn_64bit_offset = true) const; 244 int W = 0) const;
185 void WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg operandReg, int bits); 245 void WriteRest(XEmitter* emit, int extraBytes = 0, X64Reg operandReg = INVALID_REG,
186 void WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &operand, int bits) const; 246 bool warn_64bit_offset = true) const;
187 247 void WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg operandReg, int bits);
188 constexpr bool IsImm() const { return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 || scale == SCALE_IMM64; } 248 void WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand,
189 constexpr bool IsSimpleReg() const { return scale == SCALE_NONE; } 249 int bits) const;
190 constexpr bool IsSimpleReg(X64Reg reg) const 250
191 { 251 constexpr bool IsImm() const {
252 return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 ||
253 scale == SCALE_IMM64;
254 }
255 constexpr bool IsSimpleReg() const {
256 return scale == SCALE_NONE;
257 }
258 constexpr bool IsSimpleReg(X64Reg reg) const {
192 return IsSimpleReg() && GetSimpleReg() == reg; 259 return IsSimpleReg() && GetSimpleReg() == reg;
193 } 260 }
194 261
195 int GetImmBits() const 262 int GetImmBits() const {
196 { 263 switch (scale) {
197 switch (scale) 264 case SCALE_IMM8:
198 { 265 return 8;
199 case SCALE_IMM8: return 8; 266 case SCALE_IMM16:
200 case SCALE_IMM16: return 16; 267 return 16;
201 case SCALE_IMM32: return 32; 268 case SCALE_IMM32:
202 case SCALE_IMM64: return 64; 269 return 32;
203 default: return -1; 270 case SCALE_IMM64:
271 return 64;
272 default:
273 return -1;
204 } 274 }
205 } 275 }
206 276
207 void SetImmBits(int bits) { 277 void SetImmBits(int bits) {
208 switch (bits) 278 switch (bits) {
209 { 279 case 8:
210 case 8: scale = SCALE_IMM8; break; 280 scale = SCALE_IMM8;
211 case 16: scale = SCALE_IMM16; break; 281 break;
212 case 32: scale = SCALE_IMM32; break; 282 case 16:
213 case 64: scale = SCALE_IMM64; break; 283 scale = SCALE_IMM16;
284 break;
285 case 32:
286 scale = SCALE_IMM32;
287 break;
288 case 64:
289 scale = SCALE_IMM64;
290 break;
214 } 291 }
215 } 292 }
216 293
217 constexpr X64Reg GetSimpleReg() const 294 constexpr X64Reg GetSimpleReg() const {
218 { 295 return scale == SCALE_NONE ? static_cast<X64Reg>(offsetOrBaseReg) : INVALID_REG;
219 return scale == SCALE_NONE
220 ? static_cast<X64Reg>(offsetOrBaseReg)
221 : INVALID_REG;
222 } 296 }
223 297
224 constexpr u32 GetImmValue() const { 298 constexpr u32 GetImmValue() const {
@@ -234,41 +308,50 @@ private:
234 u8 scale = 0; 308 u8 scale = 0;
235 u16 offsetOrBaseReg = 0; 309 u16 offsetOrBaseReg = 0;
236 u16 indexReg = 0; 310 u16 indexReg = 0;
237 u64 offset = 0; // use RIP-relative as much as possible - 64-bit immediates are not available. 311 u64 offset = 0; // use RIP-relative as much as possible - 64-bit immediates are not available.
238 u16 operandReg = 0; 312 u16 operandReg = 0;
239}; 313};
240 314
241template <typename T> 315template <typename T>
242inline OpArg M(const T *ptr) { return OpArg(reinterpret_cast<u64>(ptr), static_cast<int>(SCALE_RIP)); } 316inline OpArg M(const T* ptr) {
243constexpr OpArg R(X64Reg value) { return OpArg(0, SCALE_NONE, value); } 317 return OpArg(reinterpret_cast<u64>(ptr), static_cast<int>(SCALE_RIP));
244constexpr OpArg MatR(X64Reg value) { return OpArg(0, SCALE_ATREG, value); } 318}
319constexpr OpArg R(X64Reg value) {
320 return OpArg(0, SCALE_NONE, value);
321}
322constexpr OpArg MatR(X64Reg value) {
323 return OpArg(0, SCALE_ATREG, value);
324}
245 325
246constexpr OpArg MDisp(X64Reg value, int offset) 326constexpr OpArg MDisp(X64Reg value, int offset) {
247{
248 return OpArg(static_cast<u32>(offset), SCALE_ATREG, value); 327 return OpArg(static_cast<u32>(offset), SCALE_ATREG, value);
249} 328}
250 329
251constexpr OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset) 330constexpr OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset) {
252{
253 return OpArg(offset, scale, base, scaled); 331 return OpArg(offset, scale, base, scaled);
254} 332}
255 333
256constexpr OpArg MScaled(X64Reg scaled, int scale, int offset) 334constexpr OpArg MScaled(X64Reg scaled, int scale, int offset) {
257{ 335 return scale == SCALE_1 ? OpArg(offset, SCALE_ATREG, scaled)
258 return scale == SCALE_1 336 : OpArg(offset, scale | 0x20, RAX, scaled);
259 ? OpArg(offset, SCALE_ATREG, scaled)
260 : OpArg(offset, scale | 0x20, RAX, scaled);
261} 337}
262 338
263constexpr OpArg MRegSum(X64Reg base, X64Reg offset) 339constexpr OpArg MRegSum(X64Reg base, X64Reg offset) {
264{
265 return MComplex(base, offset, 1, 0); 340 return MComplex(base, offset, 1, 0);
266} 341}
267 342
268constexpr OpArg Imm8 (u8 imm) { return OpArg(imm, SCALE_IMM8); } 343constexpr OpArg Imm8(u8 imm) {
269constexpr OpArg Imm16(u16 imm) { return OpArg(imm, SCALE_IMM16); } //rarely used 344 return OpArg(imm, SCALE_IMM8);
270constexpr OpArg Imm32(u32 imm) { return OpArg(imm, SCALE_IMM32); } 345}
271constexpr OpArg Imm64(u64 imm) { return OpArg(imm, SCALE_IMM64); } 346constexpr OpArg Imm16(u16 imm) {
347 return OpArg(imm, SCALE_IMM16);
348} // rarely used
349constexpr OpArg Imm32(u32 imm) {
350 return OpArg(imm, SCALE_IMM32);
351}
352constexpr OpArg Imm64(u64 imm) {
353 return OpArg(imm, SCALE_IMM64);
354}
272constexpr OpArg UImmAuto(u32 imm) { 355constexpr OpArg UImmAuto(u32 imm) {
273 return OpArg(imm, imm >= 128 ? SCALE_IMM32 : SCALE_IMM8); 356 return OpArg(imm, imm >= 128 ? SCALE_IMM32 : SCALE_IMM8);
274} 357}
@@ -277,8 +360,7 @@ constexpr OpArg SImmAuto(s32 imm) {
277} 360}
278 361
279template <typename T> 362template <typename T>
280OpArg ImmPtr(const T* imm) 363OpArg ImmPtr(const T* imm) {
281{
282#ifdef _ARCH_64 364#ifdef _ARCH_64
283 return Imm64(reinterpret_cast<u64>(imm)); 365 return Imm64(reinterpret_cast<u64>(imm));
284#else 366#else
@@ -286,36 +368,31 @@ OpArg ImmPtr(const T* imm)
286#endif 368#endif
287} 369}
288 370
289inline u32 PtrOffset(const void* ptr, const void* base) 371inline u32 PtrOffset(const void* ptr, const void* base) {
290{
291#ifdef _ARCH_64 372#ifdef _ARCH_64
292 s64 distance = (s64)ptr-(s64)base; 373 s64 distance = (s64)ptr - (s64)base;
293 if (distance >= 0x80000000LL || 374 if (distance >= 0x80000000LL || distance < -0x80000000LL) {
294 distance < -0x80000000LL)
295 {
296 ASSERT_MSG(0, "pointer offset out of range"); 375 ASSERT_MSG(0, "pointer offset out of range");
297 return 0; 376 return 0;
298 } 377 }
299 378
300 return (u32)distance; 379 return (u32)distance;
301#else 380#else
302 return (u32)ptr-(u32)base; 381 return (u32)ptr - (u32)base;
303#endif 382#endif
304} 383}
305 384
306//usage: int a[]; ARRAY_OFFSET(a,10) 385// usage: int a[]; ARRAY_OFFSET(a,10)
307#define ARRAY_OFFSET(array,index) ((u32)((u64)&(array)[index]-(u64)&(array)[0])) 386#define ARRAY_OFFSET(array, index) ((u32)((u64) & (array)[index] - (u64) & (array)[0]))
308//usage: struct {int e;} s; STRUCT_OFFSET(s,e) 387// usage: struct {int e;} s; STRUCT_OFFSET(s,e)
309#define STRUCT_OFFSET(str,elem) ((u32)((u64)&(str).elem-(u64)&(str))) 388#define STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str)))
310 389
311struct FixupBranch 390struct FixupBranch {
312{ 391 u8* ptr;
313 u8 *ptr; 392 int type; // 0 = 8bit 1 = 32bit
314 int type; //0 = 8bit 1 = 32bit
315}; 393};
316 394
317enum SSECompare 395enum SSECompare {
318{
319 EQ = 0, 396 EQ = 0,
320 LT, 397 LT,
321 LE, 398 LE,
@@ -326,11 +403,10 @@ enum SSECompare
326 ORD, 403 ORD,
327}; 404};
328 405
329class XEmitter 406class XEmitter {
330{ 407 friend struct OpArg; // for Write8 etc
331 friend struct OpArg; // for Write8 etc
332private: 408private:
333 u8 *code; 409 u8* code;
334 bool flags_locked; 410 bool flags_locked;
335 411
336 void CheckFlags(); 412 void CheckFlags();
@@ -347,14 +423,19 @@ private:
347 void WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); 423 void WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0);
348 void WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); 424 void WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0);
349 void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); 425 void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0);
350 void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); 426 void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg,
351 void WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); 427 int extrabytes = 0);
352 void WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); 428 void WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg,
353 void WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); 429 int extrabytes = 0);
430 void WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg,
431 int extrabytes = 0);
432 void WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg,
433 int extrabytes = 0);
354 void WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg); 434 void WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg);
355 void WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2); 435 void WriteNormalOp(XEmitter* emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2);
356 436
357 void ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp); 437 void ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size,
438 size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp);
358 439
359protected: 440protected:
360 void Write8(u8 value); 441 void Write8(u8 value);
@@ -363,26 +444,37 @@ protected:
363 void Write64(u64 value); 444 void Write64(u64 value);
364 445
365public: 446public:
366 XEmitter() { code = nullptr; flags_locked = false; } 447 XEmitter() {
367 XEmitter(u8 *code_ptr) { code = code_ptr; flags_locked = false; } 448 code = nullptr;
449 flags_locked = false;
450 }
451 XEmitter(u8* code_ptr) {
452 code = code_ptr;
453 flags_locked = false;
454 }
368 virtual ~XEmitter() {} 455 virtual ~XEmitter() {}
369 456
370 void WriteModRM(int mod, int rm, int reg); 457 void WriteModRM(int mod, int rm, int reg);
371 void WriteSIB(int scale, int index, int base); 458 void WriteSIB(int scale, int index, int base);
372 459
373 void SetCodePtr(u8 *ptr); 460 void SetCodePtr(u8* ptr);
374 void ReserveCodeSpace(int bytes); 461 void ReserveCodeSpace(int bytes);
375 const u8 *AlignCode4(); 462 const u8* AlignCode4();
376 const u8 *AlignCode16(); 463 const u8* AlignCode16();
377 const u8 *AlignCodePage(); 464 const u8* AlignCodePage();
378 const u8 *GetCodePtr() const; 465 const u8* GetCodePtr() const;
379 u8 *GetWritableCodePtr(); 466 u8* GetWritableCodePtr();
380 467
381 void LockFlags() { flags_locked = true; } 468 void LockFlags() {
382 void UnlockFlags() { flags_locked = false; } 469 flags_locked = true;
470 }
471 void UnlockFlags() {
472 flags_locked = false;
473 }
383 474
384 // Looking for one of these? It's BANNED!! Some instructions are slow on modern CPU 475 // Looking for one of these? It's BANNED!! Some instructions are slow on modern CPU
385 // INC, DEC, LOOP, LOOPNE, LOOPE, ENTER, LEAVE, XCHG, XLAT, REP MOVSB/MOVSD, REP SCASD + other string instr., 476 // INC, DEC, LOOP, LOOPNE, LOOPE, ENTER, LEAVE, XCHG, XLAT, REP MOVSB/MOVSD, REP SCASD + other
477 // string instr.,
386 // INC and DEC are slow on Intel Core, but not on AMD. They create a 478 // INC and DEC are slow on Intel Core, but not on AMD. They create a
387 // false flag dependency because they only update a subset of the flags. 479 // false flag dependency because they only update a subset of the flags.
388 // XCHG is SLOW and should be avoided. 480 // XCHG is SLOW and should be avoided.
@@ -401,11 +493,11 @@ public:
401 void CLC(); 493 void CLC();
402 void CMC(); 494 void CMC();
403 495
404 // These two can not be executed in 64-bit mode on early Intel 64-bit CPU:s, only on Core2 and AMD! 496 // These two can not be executed in 64-bit mode on early Intel 64-bit CPU:s, only on Core2 and
497 // AMD!
405 void LAHF(); // 3 cycle vector path 498 void LAHF(); // 3 cycle vector path
406 void SAHF(); // direct path fast 499 void SAHF(); // direct path fast
407 500
408
409 // Stack control 501 // Stack control
410 void PUSH(X64Reg reg); 502 void PUSH(X64Reg reg);
411 void POP(X64Reg reg); 503 void POP(X64Reg reg);
@@ -422,7 +514,7 @@ public:
422 514
423 void JMP(const u8* addr, bool force5Bytes = false); 515 void JMP(const u8* addr, bool force5Bytes = false);
424 void JMPptr(const OpArg& arg); 516 void JMPptr(const OpArg& arg);
425 void JMPself(); //infinite loop! 517 void JMPself(); // infinite loop!
426#ifdef CALL 518#ifdef CALL
427#undef CALL 519#undef CALL
428#endif 520#endif
@@ -450,12 +542,11 @@ public:
450 void BSR(int bits, X64Reg dest, const OpArg& src); // Top bit to bottom bit 542 void BSR(int bits, X64Reg dest, const OpArg& src); // Top bit to bottom bit
451 543
452 // Cache control 544 // Cache control
453 enum PrefetchLevel 545 enum PrefetchLevel {
454 { 546 PF_NTA, // Non-temporal (data used once and only once)
455 PF_NTA, //Non-temporal (data used once and only once) 547 PF_T0, // All cache levels
456 PF_T0, //All cache levels 548 PF_T1, // Levels 2+ (aliased to T0 on AMD)
457 PF_T1, //Levels 2+ (aliased to T0 on AMD) 549 PF_T2, // Levels 3+ (aliased to T0 on AMD)
458 PF_T2, //Levels 3+ (aliased to T0 on AMD)
459 }; 550 };
460 void PREFETCH(PrefetchLevel level, OpArg arg); 551 void PREFETCH(PrefetchLevel level, OpArg arg);
461 void MOVNTI(int bits, const OpArg& dest, X64Reg src); 552 void MOVNTI(int bits, const OpArg& dest, X64Reg src);
@@ -464,8 +555,8 @@ public:
464 void MOVNTPD(const OpArg& arg, X64Reg regOp); 555 void MOVNTPD(const OpArg& arg, X64Reg regOp);
465 556
466 // Multiplication / division 557 // Multiplication / division
467 void MUL(int bits, const OpArg& src); //UNSIGNED 558 void MUL(int bits, const OpArg& src); // UNSIGNED
468 void IMUL(int bits, const OpArg& src); //SIGNED 559 void IMUL(int bits, const OpArg& src); // SIGNED
469 void IMUL(int bits, X64Reg regOp, const OpArg& src); 560 void IMUL(int bits, X64Reg regOp, const OpArg& src);
470 void IMUL(int bits, X64Reg regOp, const OpArg& src, const OpArg& imm); 561 void IMUL(int bits, X64Reg regOp, const OpArg& src, const OpArg& imm);
471 void DIV(int bits, const OpArg& src); 562 void DIV(int bits, const OpArg& src);
@@ -492,11 +583,19 @@ public:
492 583
493 // Extend EAX into EDX in various ways 584 // Extend EAX into EDX in various ways
494 void CWD(int bits = 16); 585 void CWD(int bits = 16);
495 void CDQ() {CWD(32);} 586 void CDQ() {
496 void CQO() {CWD(64);} 587 CWD(32);
588 }
589 void CQO() {
590 CWD(64);
591 }
497 void CBW(int bits = 8); 592 void CBW(int bits = 8);
498 void CWDE() {CBW(16);} 593 void CWDE() {
499 void CDQE() {CBW(32);} 594 CBW(16);
595 }
596 void CDQE() {
597 CBW(32);
598 }
500 599
501 // Load effective address 600 // Load effective address
502 void LEA(int bits, X64Reg dest, OpArg src); 601 void LEA(int bits, X64Reg dest, OpArg src);
@@ -511,7 +610,7 @@ public:
511 void CMP(int bits, const OpArg& a1, const OpArg& a2); 610 void CMP(int bits, const OpArg& a1, const OpArg& a2);
512 611
513 // Bit operations 612 // Bit operations
514 void NOT (int bits, const OpArg& src); 613 void NOT(int bits, const OpArg& src);
515 void OR(int bits, const OpArg& a1, const OpArg& a2); 614 void OR(int bits, const OpArg& a1, const OpArg& a2);
516 void XOR(int bits, const OpArg& a1, const OpArg& a2); 615 void XOR(int bits, const OpArg& a1, const OpArg& a2);
517 void MOV(int bits, const OpArg& a1, const OpArg& a2); 616 void MOV(int bits, const OpArg& a1, const OpArg& a2);
@@ -525,7 +624,8 @@ public:
525 void BSWAP(int bits, X64Reg reg); 624 void BSWAP(int bits, X64Reg reg);
526 625
527 // Sign/zero extension 626 // Sign/zero extension
528 void MOVSX(int dbits, int sbits, X64Reg dest, OpArg src); //automatically uses MOVSXD if necessary 627 void MOVSX(int dbits, int sbits, X64Reg dest,
628 OpArg src); // automatically uses MOVSXD if necessary
529 void MOVZX(int dbits, int sbits, X64Reg dest, OpArg src); 629 void MOVZX(int dbits, int sbits, X64Reg dest, OpArg src);
530 630
531 // Available only on Atom or >= Haswell so far. Test with GetCPUCaps().movbe. 631 // Available only on Atom or >= Haswell so far. Test with GetCPUCaps().movbe.
@@ -593,13 +693,27 @@ public:
593 void CMPSS(X64Reg regOp, const OpArg& arg, u8 compare); 693 void CMPSS(X64Reg regOp, const OpArg& arg, u8 compare);
594 void CMPSD(X64Reg regOp, const OpArg& arg, u8 compare); 694 void CMPSD(X64Reg regOp, const OpArg& arg, u8 compare);
595 695
596 void CMPEQSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_EQ); } 696 void CMPEQSS(X64Reg regOp, const OpArg& arg) {
597 void CMPLTSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_LT); } 697 CMPSS(regOp, arg, CMP_EQ);
598 void CMPLESS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_LE); } 698 }
599 void CMPUNORDSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_UNORD); } 699 void CMPLTSS(X64Reg regOp, const OpArg& arg) {
600 void CMPNEQSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_NEQ); } 700 CMPSS(regOp, arg, CMP_LT);
601 void CMPNLTSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_NLT); } 701 }
602 void CMPORDSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_ORD); } 702 void CMPLESS(X64Reg regOp, const OpArg& arg) {
703 CMPSS(regOp, arg, CMP_LE);
704 }
705 void CMPUNORDSS(X64Reg regOp, const OpArg& arg) {
706 CMPSS(regOp, arg, CMP_UNORD);
707 }
708 void CMPNEQSS(X64Reg regOp, const OpArg& arg) {
709 CMPSS(regOp, arg, CMP_NEQ);
710 }
711 void CMPNLTSS(X64Reg regOp, const OpArg& arg) {
712 CMPSS(regOp, arg, CMP_NLT);
713 }
714 void CMPORDSS(X64Reg regOp, const OpArg& arg) {
715 CMPSS(regOp, arg, CMP_ORD);
716 }
603 717
604 // SSE/SSE2: Floating point packed arithmetic (x4 for float, x2 for double) 718 // SSE/SSE2: Floating point packed arithmetic (x4 for float, x2 for double)
605 void ADDPS(X64Reg regOp, const OpArg& arg); 719 void ADDPS(X64Reg regOp, const OpArg& arg);
@@ -638,10 +752,12 @@ public:
638 // SSE/SSE2: Useful alternative to shuffle in some cases. 752 // SSE/SSE2: Useful alternative to shuffle in some cases.
639 void MOVDDUP(X64Reg regOp, const OpArg& arg); 753 void MOVDDUP(X64Reg regOp, const OpArg& arg);
640 754
641 // SSE3: Horizontal operations in SIMD registers. Very slow! shufps-based code beats it handily on Ivy. 755 // SSE3: Horizontal operations in SIMD registers. Very slow! shufps-based code beats it handily
756 // on Ivy.
642 void HADDPS(X64Reg dest, const OpArg& src); 757 void HADDPS(X64Reg dest, const OpArg& src);
643 758
644 // SSE4: Further horizontal operations - dot products. These are weirdly flexible, the arg contains both a read mask and a write "mask". 759 // SSE4: Further horizontal operations - dot products. These are weirdly flexible, the arg
760 // contains both a read mask and a write "mask".
645 void DPPS(X64Reg dest, const OpArg& src, u8 arg); 761 void DPPS(X64Reg dest, const OpArg& src, u8 arg);
646 762
647 void UNPCKLPS(X64Reg dest, const OpArg& src); 763 void UNPCKLPS(X64Reg dest, const OpArg& src);
@@ -694,11 +810,13 @@ public:
694 void MOVD_xmm(const OpArg& arg, X64Reg src); 810 void MOVD_xmm(const OpArg& arg, X64Reg src);
695 void MOVQ_xmm(OpArg arg, X64Reg src); 811 void MOVQ_xmm(OpArg arg, X64Reg src);
696 812
697 // SSE/SSE2: Generates a mask from the high bits of the components of the packed register in question. 813 // SSE/SSE2: Generates a mask from the high bits of the components of the packed register in
814 // question.
698 void MOVMSKPS(X64Reg dest, const OpArg& arg); 815 void MOVMSKPS(X64Reg dest, const OpArg& arg);
699 void MOVMSKPD(X64Reg dest, const OpArg& arg); 816 void MOVMSKPD(X64Reg dest, const OpArg& arg);
700 817
701 // SSE2: Selective byte store, mask in src register. EDI/RDI specifies store address. This is a weird one. 818 // SSE2: Selective byte store, mask in src register. EDI/RDI specifies store address. This is a
819 // weird one.
702 void MASKMOVDQU(X64Reg dest, X64Reg src); 820 void MASKMOVDQU(X64Reg dest, X64Reg src);
703 void LDDQU(X64Reg dest, const OpArg& src); 821 void LDDQU(X64Reg dest, const OpArg& src);
704 822
@@ -729,10 +847,10 @@ public:
729 void PACKUSDW(X64Reg dest, const OpArg& arg); 847 void PACKUSDW(X64Reg dest, const OpArg& arg);
730 void PACKUSWB(X64Reg dest, const OpArg& arg); 848 void PACKUSWB(X64Reg dest, const OpArg& arg);
731 849
732 void PUNPCKLBW(X64Reg dest, const OpArg &arg); 850 void PUNPCKLBW(X64Reg dest, const OpArg& arg);
733 void PUNPCKLWD(X64Reg dest, const OpArg &arg); 851 void PUNPCKLWD(X64Reg dest, const OpArg& arg);
734 void PUNPCKLDQ(X64Reg dest, const OpArg &arg); 852 void PUNPCKLDQ(X64Reg dest, const OpArg& arg);
735 void PUNPCKLQDQ(X64Reg dest, const OpArg &arg); 853 void PUNPCKLQDQ(X64Reg dest, const OpArg& arg);
736 854
737 void PTEST(X64Reg dest, const OpArg& arg); 855 void PTEST(X64Reg dest, const OpArg& arg);
738 void PAND(X64Reg dest, const OpArg& arg); 856 void PAND(X64Reg dest, const OpArg& arg);
@@ -839,25 +957,57 @@ public:
839 void ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode); 957 void ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode);
840 void ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode); 958 void ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode);
841 959
842 void ROUNDNEARSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_NEAREST); } 960 void ROUNDNEARSS(X64Reg dest, const OpArg& arg) {
843 void ROUNDFLOORSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_FLOOR); } 961 ROUNDSS(dest, arg, FROUND_NEAREST);
844 void ROUNDCEILSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_CEIL); } 962 }
845 void ROUNDZEROSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_ZERO); } 963 void ROUNDFLOORSS(X64Reg dest, const OpArg& arg) {
964 ROUNDSS(dest, arg, FROUND_FLOOR);
965 }
966 void ROUNDCEILSS(X64Reg dest, const OpArg& arg) {
967 ROUNDSS(dest, arg, FROUND_CEIL);
968 }
969 void ROUNDZEROSS(X64Reg dest, const OpArg& arg) {
970 ROUNDSS(dest, arg, FROUND_ZERO);
971 }
846 972
847 void ROUNDNEARSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_NEAREST); } 973 void ROUNDNEARSD(X64Reg dest, const OpArg& arg) {
848 void ROUNDFLOORSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_FLOOR); } 974 ROUNDSD(dest, arg, FROUND_NEAREST);
849 void ROUNDCEILSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_CEIL); } 975 }
850 void ROUNDZEROSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_ZERO); } 976 void ROUNDFLOORSD(X64Reg dest, const OpArg& arg) {
977 ROUNDSD(dest, arg, FROUND_FLOOR);
978 }
979 void ROUNDCEILSD(X64Reg dest, const OpArg& arg) {
980 ROUNDSD(dest, arg, FROUND_CEIL);
981 }
982 void ROUNDZEROSD(X64Reg dest, const OpArg& arg) {
983 ROUNDSD(dest, arg, FROUND_ZERO);
984 }
851 985
852 void ROUNDNEARPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_NEAREST); } 986 void ROUNDNEARPS(X64Reg dest, const OpArg& arg) {
853 void ROUNDFLOORPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_FLOOR); } 987 ROUNDPS(dest, arg, FROUND_NEAREST);
854 void ROUNDCEILPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_CEIL); } 988 }
855 void ROUNDZEROPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_ZERO); } 989 void ROUNDFLOORPS(X64Reg dest, const OpArg& arg) {
990 ROUNDPS(dest, arg, FROUND_FLOOR);
991 }
992 void ROUNDCEILPS(X64Reg dest, const OpArg& arg) {
993 ROUNDPS(dest, arg, FROUND_CEIL);
994 }
995 void ROUNDZEROPS(X64Reg dest, const OpArg& arg) {
996 ROUNDPS(dest, arg, FROUND_ZERO);
997 }
856 998
857 void ROUNDNEARPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_NEAREST); } 999 void ROUNDNEARPD(X64Reg dest, const OpArg& arg) {
858 void ROUNDFLOORPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_FLOOR); } 1000 ROUNDPD(dest, arg, FROUND_NEAREST);
859 void ROUNDCEILPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_CEIL); } 1001 }
860 void ROUNDZEROPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_ZERO); } 1002 void ROUNDFLOORPD(X64Reg dest, const OpArg& arg) {
1003 ROUNDPD(dest, arg, FROUND_FLOOR);
1004 }
1005 void ROUNDCEILPD(X64Reg dest, const OpArg& arg) {
1006 ROUNDPD(dest, arg, FROUND_CEIL);
1007 }
1008 void ROUNDZEROPD(X64Reg dest, const OpArg& arg) {
1009 ROUNDPD(dest, arg, FROUND_ZERO);
1010 }
861 1011
862 // AVX 1012 // AVX
863 void VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); 1013 void VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg);
@@ -981,7 +1131,6 @@ public:
981 void ABI_CallFunctionC16(const void* func, u16 param1); 1131 void ABI_CallFunctionC16(const void* func, u16 param1);
982 void ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2); 1132 void ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2);
983 1133
984
985 // These only support u32 parameters, but that's enough for a lot of uses. 1134 // These only support u32 parameters, but that's enough for a lot of uses.
986 // These will destroy the 1 or 2 first "parameter regs". 1135 // These will destroy the 1 or 2 first "parameter regs".
987 void ABI_CallFunctionC(const void* func, u32 param1); 1136 void ABI_CallFunctionC(const void* func, u32 param1);
@@ -1012,29 +1161,38 @@ public:
1012 * 1161 *
1013 * @param mask Registers to push on the stack (high 16 bits are XMMs, low 16 bits are GPRs) 1162 * @param mask Registers to push on the stack (high 16 bits are XMMs, low 16 bits are GPRs)
1014 * @param rsp_alignment Current alignment of the stack pointer, must be 0 or 8 1163 * @param rsp_alignment Current alignment of the stack pointer, must be 0 or 8
1015 * @param needed_frame_size Additional space needed, e.g., for function arguments passed on the stack 1164 * @param needed_frame_size Additional space needed, e.g., for function arguments passed on the
1165 * stack
1016 * @return Size of the shadow space, i.e., offset of the frame 1166 * @return Size of the shadow space, i.e., offset of the frame
1017 */ 1167 */
1018 size_t ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size = 0); 1168 size_t ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment,
1169 size_t needed_frame_size = 0);
1019 1170
1020 /** 1171 /**
1021 * Restores specified registers and adjusts the stack to its original alignment, i.e., the alignment before 1172 * Restores specified registers and adjusts the stack to its original alignment, i.e., the
1173 * alignment before
1022 * the matching PushRegistersAndAdjustStack. 1174 * the matching PushRegistersAndAdjustStack.
1023 * 1175 *
1024 * @param mask Registers to restores from the stack (high 16 bits are XMMs, low 16 bits are GPRs) 1176 * @param mask Registers to restores from the stack (high 16 bits are XMMs, low 16 bits are
1025 * @param rsp_alignment Original alignment before the matching PushRegistersAndAdjustStack, must be 0 or 8 1177 * GPRs)
1178 * @param rsp_alignment Original alignment before the matching PushRegistersAndAdjustStack, must
1179 * be 0 or 8
1026 * @param needed_frame_size Additional space that was needed 1180 * @param needed_frame_size Additional space that was needed
1027 * @warning Stack must be currently 16-byte aligned 1181 * @warning Stack must be currently 16-byte aligned
1028 */ 1182 */
1029 void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size = 0); 1183 void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment,
1030 1184 size_t needed_frame_size = 0);
1031 #ifdef _M_IX86
1032 static int ABI_GetNumXMMRegs() { return 8; }
1033 #else
1034 static int ABI_GetNumXMMRegs() { return 16; }
1035 #endif
1036}; // class XEmitter
1037 1185
1186#ifdef _M_IX86
1187 static int ABI_GetNumXMMRegs() {
1188 return 8;
1189 }
1190#else
1191 static int ABI_GetNumXMMRegs() {
1192 return 16;
1193 }
1194#endif
1195}; // class XEmitter
1038 1196
1039// Everything that needs to generate X86 code should inherit from this. 1197// Everything that needs to generate X86 code should inherit from this.
1040// You get memory management for free, plus, you can use all the MOV etc functions without 1198// You get memory management for free, plus, you can use all the MOV etc functions without
@@ -1045,4 +1203,4 @@ public:
1045 void PoisonMemory() override; 1203 void PoisonMemory() override;
1046}; 1204};
1047 1205
1048} // namespace 1206} // namespace