Bug Summary

File:Source/Core/Common/Src/x64Emitter.cpp
Location:line 170, column 3
Description:Value stored to '_offsetOrBaseReg' is never read

Annotated Source Code

1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "Common.h"
6#include "x64Emitter.h"
7#include "x64ABI.h"
8#include "CPUDetect.h"
9
10namespace Gen
11{
12
13// TODO(ector): Add EAX special casing, for ever so slightly smaller code.
14struct NormalOpDef
15{
16 u8 toRm8, toRm32, fromRm8, fromRm32, imm8, imm32, simm8, ext;
17};
18
19static const NormalOpDef nops[11] =
20{
21 {0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x83, 0}, //ADD
22 {0x10, 0x11, 0x12, 0x13, 0x80, 0x81, 0x83, 2}, //ADC
23
24 {0x28, 0x29, 0x2A, 0x2B, 0x80, 0x81, 0x83, 5}, //SUB
25 {0x18, 0x19, 0x1A, 0x1B, 0x80, 0x81, 0x83, 3}, //SBB
26
27 {0x20, 0x21, 0x22, 0x23, 0x80, 0x81, 0x83, 4}, //AND
28 {0x08, 0x09, 0x0A, 0x0B, 0x80, 0x81, 0x83, 1}, //OR
29
30 {0x30, 0x31, 0x32, 0x33, 0x80, 0x81, 0x83, 6}, //XOR
31 {0x88, 0x89, 0x8A, 0x8B, 0xC6, 0xC7, 0xCC, 0}, //MOV
32
33 {0x84, 0x85, 0x84, 0x85, 0xF6, 0xF7, 0xCC, 0}, //TEST (to == from)
34 {0x38, 0x39, 0x3A, 0x3B, 0x80, 0x81, 0x83, 7}, //CMP
35
36 {0x86, 0x87, 0x86, 0x87, 0xCC, 0xCC, 0xCC, 7}, //XCHG
37};
38
39enum NormalSSEOps
40{
41 sseCMP = 0xC2,
42 sseADD = 0x58, //ADD
43 sseSUB = 0x5C, //SUB
44 sseAND = 0x54, //AND
45 sseANDN = 0x55, //ANDN
46 sseOR = 0x56,
47 sseXOR = 0x57,
48 sseMUL = 0x59, //MUL
49 sseDIV = 0x5E, //DIV
50 sseMIN = 0x5D, //MIN
51 sseMAX = 0x5F, //MAX
52 sseCOMIS = 0x2F, //COMIS
53 sseUCOMIS = 0x2E, //UCOMIS
54 sseSQRT = 0x51, //SQRT
55 sseRSQRT = 0x52, //RSQRT (NO DOUBLE PRECISION!!!)
56 sseMOVAPfromRM = 0x28, //MOVAP from RM
57 sseMOVAPtoRM = 0x29, //MOVAP to RM
58 sseMOVUPfromRM = 0x10, //MOVUP from RM
59 sseMOVUPtoRM = 0x11, //MOVUP to RM
60 sseMASKMOVDQU = 0xF7,
61 sseLDDQU = 0xF0,
62 sseSHUF = 0xC6,
63 sseMOVNTDQ = 0xE7,
64 sseMOVNTP = 0x2B,
65};
66
67
68void XEmitter::SetCodePtr(u8 *ptr)
69{
70 code = ptr;
71}
72
73const u8 *XEmitter::GetCodePtr() const
74{
75 return code;
76}
77
78u8 *XEmitter::GetWritableCodePtr()
79{
80 return code;
81}
82
83void XEmitter::ReserveCodeSpace(int bytes)
84{
85 for (int i = 0; i < bytes; i++)
86 *code++ = 0xCC;
87}
88
89const u8 *XEmitter::AlignCode4()
90{
91 int c = int((u64)code & 3);
92 if (c)
93 ReserveCodeSpace(4-c);
94 return code;
95}
96
97const u8 *XEmitter::AlignCode16()
98{
99 int c = int((u64)code & 15);
100 if (c)
101 ReserveCodeSpace(16-c);
102 return code;
103}
104
105const u8 *XEmitter::AlignCodePage()
106{
107 int c = int((u64)code & 4095);
108 if (c)
109 ReserveCodeSpace(4096-c);
110 return code;
111}
112
113void XEmitter::WriteModRM(int mod, int rm, int reg)
114{
115 Write8((u8)((mod << 6) | ((rm & 7) << 3) | (reg & 7)));
116}
117
118void XEmitter::WriteSIB(int scale, int index, int base)
119{
120 Write8((u8)((scale << 6) | ((index & 7) << 3) | (base & 7)));
121}
122
123void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const
124{
125 if (customOp == -1) customOp = operandReg;
126#ifdef _M_X641
127 u8 op = 0x40;
128 if (opBits == 64) op |= 8;
129 if (customOp & 8) op |= 4;
130 if (indexReg & 8) op |= 2;
131 if (offsetOrBaseReg & 8) op |= 1; //TODO investigate if this is dangerous
132 if (op != 0x40 ||
133 (bits == 8 && (offsetOrBaseReg & 0x10c) == 4) ||
134 (opBits == 8 && (customOp & 0x10c) == 4)) {
135 emit->Write8(op);
136 _dbg_assert_(DYNA_REC, (offsetOrBaseReg & 0x100) == 0 || bits != 8){};
137 _dbg_assert_(DYNA_REC, (customOp & 0x100) == 0 || opBits != 8){};
138 } else {
139 _dbg_assert_(DYNA_REC, (offsetOrBaseReg & 0x10c) == 0 ||{}
140 (offsetOrBaseReg & 0x10c) == 0x104 ||{}
141 bits != 8){};
142 _dbg_assert_(DYNA_REC, (customOp & 0x10c) == 0 ||{}
143 (customOp & 0x10c) == 0x104 ||{}
144 opBits != 8){};
145 }
146
147#else
148 _dbg_assert_(DYNA_REC, opBits != 64){};
149 _dbg_assert_(DYNA_REC, (customOp & 8) == 0 || customOp == -1){};
150 _dbg_assert_(DYNA_REC, (indexReg & 8) == 0){};
151 _dbg_assert_(DYNA_REC, (offsetOrBaseReg & 8) == 0){};
152 _dbg_assert_(DYNA_REC, opBits != 8 || (customOp & 0x10c) != 4 || customOp == -1){};
153 _dbg_assert_(DYNA_REC, bits != 8 || (offsetOrBaseReg & 0x10c) != 4){};
154#endif
155}
156
157void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg,
158 bool warn_64bit_offset) const
159{
160 if (_operandReg == 0xff)
161 _operandReg = (X64Reg)this->operandReg;
162 int mod = 0;
163 int ireg = indexReg;
164 bool SIB = false;
165 int _offsetOrBaseReg = this->offsetOrBaseReg;
166
167 if (scale == SCALE_RIP) //Also, on 32-bit, just an immediate address
168 {
169 // Oh, RIP addressing.
170 _offsetOrBaseReg = 5;
Value stored to '_offsetOrBaseReg' is never read
171 emit->WriteModRM(0, _operandReg&7, 5);
172 //TODO : add some checks
173#ifdef _M_X641
174 u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes;
175 s64 distance = (s64)offset - (s64)ripAddr;
176 _assert_msg_(DYNA_REC, (distance < 0x80000000LLif (!((distance < 0x80000000LL && distance >= -
0x80000000LL) || !warn_64bit_offset)) { if (!MsgAlert(true, WARNING
, "WriteRest: op out of range (0x%llx uses 0x%llx)", ripAddr,
offset)) {{asm ("int $3");};} }
177 && distance >= -0x80000000LL) ||if (!((distance < 0x80000000LL && distance >= -
0x80000000LL) || !warn_64bit_offset)) { if (!MsgAlert(true, WARNING
, "WriteRest: op out of range (0x%llx uses 0x%llx)", ripAddr,
offset)) {{asm ("int $3");};} }
178 !warn_64bit_offset,if (!((distance < 0x80000000LL && distance >= -
0x80000000LL) || !warn_64bit_offset)) { if (!MsgAlert(true, WARNING
, "WriteRest: op out of range (0x%llx uses 0x%llx)", ripAddr,
offset)) {{asm ("int $3");};} }
179 "WriteRest: op out of range (0x%llx uses 0x%llx)",if (!((distance < 0x80000000LL && distance >= -
0x80000000LL) || !warn_64bit_offset)) { if (!MsgAlert(true, WARNING
, "WriteRest: op out of range (0x%llx uses 0x%llx)", ripAddr,
offset)) {{asm ("int $3");};} }
180 ripAddr, offset)if (!((distance < 0x80000000LL && distance >= -
0x80000000LL) || !warn_64bit_offset)) { if (!MsgAlert(true, WARNING
, "WriteRest: op out of range (0x%llx uses 0x%llx)", ripAddr,
offset)) {{asm ("int $3");};} }
;
181 s32 offs = (s32)distance;
182 emit->Write32((u32)offs);
183#else
184 emit->Write32((u32)offset);
185#endif
186 return;
187 }
188
189 if (scale == 0)
190 {
191 // Oh, no memory, Just a reg.
192 mod = 3; //11
193 }
194 else if (scale >= 1)
195 {
196 //Ah good, no scaling.
197 if (scale == SCALE_ATREG && !((_offsetOrBaseReg & 7) == 4 || (_offsetOrBaseReg & 7) == 5))
198 {
199 //Okay, we're good. No SIB necessary.
200 int ioff = (int)offset;
201 if (ioff == 0)
202 {
203 mod = 0;
204 }
205 else if (ioff<-128 || ioff>127)
206 {
207 mod = 2; //32-bit displacement
208 }
209 else
210 {
211 mod = 1; //8-bit displacement
212 }
213 }
214 else if (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8)
215 {
216 SIB = true;
217 mod = 0;
218 _offsetOrBaseReg = 5;
219 }
220 else //if (scale != SCALE_ATREG)
221 {
222 if ((_offsetOrBaseReg & 7) == 4) //this would occupy the SIB encoding :(
223 {
224 //So we have to fake it with SIB encoding :(
225 SIB = true;
226 }
227
228 if (scale >= SCALE_1 && scale < SCALE_ATREG)
229 {
230 SIB = true;
231 }
232
233 if (scale == SCALE_ATREG && ((_offsetOrBaseReg & 7) == 4))
234 {
235 SIB = true;
236 ireg = _offsetOrBaseReg;
237 }
238
239 //Okay, we're fine. Just disp encoding.
240 //We need displacement. Which size?
241 int ioff = (int)(s64)offset;
242 if (ioff < -128 || ioff > 127)
243 {
244 mod = 2; //32-bit displacement
245 }
246 else
247 {
248 mod = 1; //8-bit displacement
249 }
250 }
251 }
252
253 // Okay. Time to do the actual writing
254 // ModRM byte:
255 int oreg = _offsetOrBaseReg;
256 if (SIB)
257 oreg = 4;
258
259 // TODO(ector): WTF is this if about? I don't remember writing it :-)
260 //if (RIP)
261 // oreg = 5;
262
263 emit->WriteModRM(mod, _operandReg&7, oreg&7);
264
265 if (SIB)
266 {
267 //SIB byte
268 int ss;
269 switch (scale)
270 {
271 case SCALE_NONE: _offsetOrBaseReg = 4; ss = 0; break; //RSP
272 case SCALE_1: ss = 0; break;
273 case SCALE_2: ss = 1; break;
274 case SCALE_4: ss = 2; break;
275 case SCALE_8: ss = 3; break;
276 case SCALE_NOBASE_2: ss = 1; break;
277 case SCALE_NOBASE_4: ss = 2; break;
278 case SCALE_NOBASE_8: ss = 3; break;
279 case SCALE_ATREG: ss = 0; break;
280 default: _assert_msg_(DYNA_REC, 0, "Invalid scale for SIB byte")if (!(0)) { if (!MsgAlert(true, WARNING, "Invalid scale for SIB byte"
)) {{asm ("int $3");};} }
; ss = 0; break;
281 }
282 emit->Write8((u8)((ss << 6) | ((ireg&7)<<3) | (_offsetOrBaseReg&7)));
283 }
284
285 if (mod == 1) //8-bit disp
286 {
287 emit->Write8((u8)(s8)(s32)offset);
288 }
289 else if (mod == 2 || (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8)) //32-bit disp
290 {
291 emit->Write32((u32)offset);
292 }
293}
294
295
296// W = operand extended width (1 if 64-bit)
297// R = register# upper bit
298// X = scale amnt upper bit
299// B = base register# upper bit
300void XEmitter::Rex(int w, int r, int x, int b)
301{
302 w = w ? 1 : 0;
303 r = r ? 1 : 0;
304 x = x ? 1 : 0;
305 b = b ? 1 : 0;
306 u8 rx = (u8)(0x40 | (w << 3) | (r << 2) | (x << 1) | (b));
307 if (rx != 0x40)
308 Write8(rx);
309}
310
311void XEmitter::JMP(const u8 *addr, bool force5Bytes)
312{
313 u64 fn = (u64)addr;
314 if (!force5Bytes)
315 {
316 s64 distance = (s64)(fn - ((u64)code + 2));
317 _assert_msg_(DYNA_REC, distance >= -0x80 && distance < 0x80,if (!(distance >= -0x80 && distance < 0x80)) { if
(!MsgAlert(true, WARNING, "Jump target too far away, needs force5Bytes = true"
)) {{asm ("int $3");};} }
318 "Jump target too far away, needs force5Bytes = true")if (!(distance >= -0x80 && distance < 0x80)) { if
(!MsgAlert(true, WARNING, "Jump target too far away, needs force5Bytes = true"
)) {{asm ("int $3");};} }
;
319 //8 bits will do
320 Write8(0xEB);
321 Write8((u8)(s8)distance);
322 }
323 else
324 {
325 s64 distance = (s64)(fn - ((u64)code + 5));
326
327 _assert_msg_(DYNA_REC, distance >= -0x80000000LLif (!(distance >= -0x80000000LL && distance < 0x80000000LL
)) { if (!MsgAlert(true, WARNING, "Jump target too far away, needs indirect register"
)) {{asm ("int $3");};} }
328 && distance < 0x80000000LL,if (!(distance >= -0x80000000LL && distance < 0x80000000LL
)) { if (!MsgAlert(true, WARNING, "Jump target too far away, needs indirect register"
)) {{asm ("int $3");};} }
329 "Jump target too far away, needs indirect register")if (!(distance >= -0x80000000LL && distance < 0x80000000LL
)) { if (!MsgAlert(true, WARNING, "Jump target too far away, needs indirect register"
)) {{asm ("int $3");};} }
;
330 Write8(0xE9);
331 Write32((u32)(s32)distance);
332 }
333}
334
335void XEmitter::JMPptr(const OpArg &arg2)
336{
337 OpArg arg = arg2;
338 if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "JMPptr - Imm argument")if (!(0)) { if (!MsgAlert(true, WARNING, "JMPptr - Imm argument"
)) {{asm ("int $3");};} }
;
339 arg.operandReg = 4;
340 arg.WriteRex(this, 0, 0);
341 Write8(0xFF);
342 arg.WriteRest(this);
343}
344
345//Can be used to trap other processors, before overwriting their code
346// not used in dolphin
347void XEmitter::JMPself()
348{
349 Write8(0xEB);
350 Write8(0xFE);
351}
352
353void XEmitter::CALLptr(OpArg arg)
354{
355 if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "CALLptr - Imm argument")if (!(0)) { if (!MsgAlert(true, WARNING, "CALLptr - Imm argument"
)) {{asm ("int $3");};} }
;
356 arg.operandReg = 2;
357 arg.WriteRex(this, 0, 0);
358 Write8(0xFF);
359 arg.WriteRest(this);
360}
361
362void XEmitter::CALL(const void *fnptr)
363{
364 u64 distance = u64(fnptr) - (u64(code) + 5);
365 _assert_msg_(DYNA_REC, distance < 0x0000000080000000ULLif (!(distance < 0x0000000080000000ULL || distance >= 0xFFFFFFFF80000000ULL
)) { if (!MsgAlert(true, WARNING, "CALL out of range (%p calls %p)"
, code, fnptr)) {{asm ("int $3");};} }
366 || distance >= 0xFFFFFFFF80000000ULL,if (!(distance < 0x0000000080000000ULL || distance >= 0xFFFFFFFF80000000ULL
)) { if (!MsgAlert(true, WARNING, "CALL out of range (%p calls %p)"
, code, fnptr)) {{asm ("int $3");};} }
367 "CALL out of range (%p calls %p)", code, fnptr)if (!(distance < 0x0000000080000000ULL || distance >= 0xFFFFFFFF80000000ULL
)) { if (!MsgAlert(true, WARNING, "CALL out of range (%p calls %p)"
, code, fnptr)) {{asm ("int $3");};} }
;
368 Write8(0xE8);
369 Write32(u32(distance));
370}
371
372FixupBranch XEmitter::J(bool force5bytes)
373{
374 FixupBranch branch;
375 branch.type = force5bytes ? 1 : 0;
376 branch.ptr = code + (force5bytes ? 5 : 2);
377 if (!force5bytes)
378 {
379 //8 bits will do
380 Write8(0xEB);
381 Write8(0);
382 }
383 else
384 {
385 Write8(0xE9);
386 Write32(0);
387 }
388 return branch;
389}
390
391FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes)
392{
393 FixupBranch branch;
394 branch.type = force5bytes ? 1 : 0;
395 branch.ptr = code + (force5bytes ? 6 : 2);
396 if (!force5bytes)
397 {
398 //8 bits will do
399 Write8(0x70 + conditionCode);
400 Write8(0);
401 }
402 else
403 {
404 Write8(0x0F);
405 Write8(0x80 + conditionCode);
406 Write32(0);
407 }
408 return branch;
409}
410
411void XEmitter::J_CC(CCFlags conditionCode, const u8 * addr, bool force5Bytes)
412{
413 u64 fn = (u64)addr;
414 if (!force5Bytes)
415 {
416 s64 distance = (s64)(fn - ((u64)code + 2));
417 _assert_msg_(DYNA_REC, distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true")if (!(distance >= -0x80 && distance < 0x80)) { if
(!MsgAlert(true, WARNING, "Jump target too far away, needs force5Bytes = true"
)) {{asm ("int $3");};} }
;
418 //8 bits will do
419 Write8(0x70 + conditionCode);
420 Write8((u8)(s8)distance);
421 }
422 else
423 {
424 s64 distance = (s64)(fn - ((u64)code + 6));
425 _assert_msg_(DYNA_REC, distance >= -0x80000000LLif (!(distance >= -0x80000000LL && distance < 0x80000000LL
)) { if (!MsgAlert(true, WARNING, "Jump target too far away, needs indirect register"
)) {{asm ("int $3");};} }
426 && distance < 0x80000000LL,if (!(distance >= -0x80000000LL && distance < 0x80000000LL
)) { if (!MsgAlert(true, WARNING, "Jump target too far away, needs indirect register"
)) {{asm ("int $3");};} }
427 "Jump target too far away, needs indirect register")if (!(distance >= -0x80000000LL && distance < 0x80000000LL
)) { if (!MsgAlert(true, WARNING, "Jump target too far away, needs indirect register"
)) {{asm ("int $3");};} }
;
428 Write8(0x0F);
429 Write8(0x80 + conditionCode);
430 Write32((u32)(s32)distance);
431 }
432}
433
434void XEmitter::SetJumpTarget(const FixupBranch &branch)
435{
436 if (branch.type == 0)
437 {
438 s64 distance = (s64)(code - branch.ptr);
439 _assert_msg_(DYNA_REC, distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true")if (!(distance >= -0x80 && distance < 0x80)) { if
(!MsgAlert(true, WARNING, "Jump target too far away, needs force5Bytes = true"
)) {{asm ("int $3");};} }
;
440 branch.ptr[-1] = (u8)(s8)distance;
441 }
442 else if (branch.type == 1)
443 {
444 s64 distance = (s64)(code - branch.ptr);
445 _assert_msg_(DYNA_REC, distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register")if (!(distance >= -0x80000000LL && distance < 0x80000000LL
)) { if (!MsgAlert(true, WARNING, "Jump target too far away, needs indirect register"
)) {{asm ("int $3");};} }
;
446 ((s32*)branch.ptr)[-1] = (s32)distance;
447 }
448}
449
450// INC/DEC considered harmful on newer CPUs due to partial flag set.
451// Use ADD, SUB instead.
452
453/*
454void XEmitter::INC(int bits, OpArg arg)
455{
456 if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "INC - Imm argument");
457 arg.operandReg = 0;
458 if (bits == 16) {Write8(0x66);}
459 arg.WriteRex(this, bits, bits);
460 Write8(bits == 8 ? 0xFE : 0xFF);
461 arg.WriteRest(this);
462}
463void XEmitter::DEC(int bits, OpArg arg)
464{
465 if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "DEC - Imm argument");
466 arg.operandReg = 1;
467 if (bits == 16) {Write8(0x66);}
468 arg.WriteRex(this, bits, bits);
469 Write8(bits == 8 ? 0xFE : 0xFF);
470 arg.WriteRest(this);
471}
472*/
473
474//Single byte opcodes
475//There is no PUSHAD/POPAD in 64-bit mode.
476void XEmitter::INT3() {Write8(0xCC);}
477void XEmitter::RET() {Write8(0xC3);}
478void 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
479
480void XEmitter::NOP(int count)
481{
482 // TODO: look up the fastest nop sleds for various sizes
483 int i;
484 switch (count) {
485 case 1:
486 Write8(0x90);
487 break;
488 case 2:
489 Write8(0x66);
490 Write8(0x90);
491 break;
492 default:
493 for (i = 0; i < count; i++) {
494 Write8(0x90);
495 }
496 break;
497 }
498}
499
500void XEmitter::PAUSE() {Write8(0xF3); NOP();} //use in tight spinloops for energy saving on some cpu
501void XEmitter::CLC() {Write8(0xF8);} //clear carry
502void XEmitter::CMC() {Write8(0xF5);} //flip carry
503void XEmitter::STC() {Write8(0xF9);} //set carry
504
505//TODO: xchg ah, al ???
506void XEmitter::XCHG_AHAL()
507{
508 Write8(0x86);
509 Write8(0xe0);
510 // alt. 86 c4
511}
512
513//These two can not be executed on early Intel 64-bit CPU:s, only on AMD!
514void XEmitter::LAHF() {Write8(0x9F);}
515void XEmitter::SAHF() {Write8(0x9E);}
516
517void XEmitter::PUSHF() {Write8(0x9C);}
518void XEmitter::POPF() {Write8(0x9D);}
519
520void XEmitter::LFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xE8);}
521void XEmitter::MFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF0);}
522void XEmitter::SFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF8);}
523
524void XEmitter::WriteSimple1Byte(int bits, u8 byte, X64Reg reg)
525{
526 if (bits == 16) {Write8(0x66);}
527 Rex(bits == 64, 0, 0, (int)reg >> 3);
528 Write8(byte + ((int)reg & 7));
529}
530
531void XEmitter::WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg)
532{
533 if (bits == 16) {Write8(0x66);}
534 Rex(bits==64, 0, 0, (int)reg >> 3);
535 Write8(byte1);
536 Write8(byte2 + ((int)reg & 7));
537}
538
539void XEmitter::CWD(int bits)
540{
541 if (bits == 16) {Write8(0x66);}
542 Rex(bits == 64, 0, 0, 0);
543 Write8(0x99);
544}
545
546void XEmitter::CBW(int bits)
547{
548 if (bits == 8) {Write8(0x66);}
549 Rex(bits == 32, 0, 0, 0);
550 Write8(0x98);
551}
552
553//Simple opcodes
554
555
556//push/pop do not need wide to be 64-bit
557void XEmitter::PUSH(X64Reg reg) {WriteSimple1Byte(32, 0x50, reg);}
558void XEmitter::POP(X64Reg reg) {WriteSimple1Byte(32, 0x58, reg);}
559
560void XEmitter::PUSH(int bits, const OpArg &reg)
561{
562 if (reg.IsSimpleReg())
563 PUSH(reg.GetSimpleReg());
564 else if (reg.IsImm())
565 {
566 switch (reg.GetImmBits())
567 {
568 case 8:
569 Write8(0x6A);
570 Write8((u8)(s8)reg.offset);
571 break;
572 case 16:
573 Write8(0x66);
574 Write8(0x68);
575 Write16((u16)(s16)(s32)reg.offset);
576 break;
577 case 32:
578 Write8(0x68);
579 Write32((u32)reg.offset);
580 break;
581 default:
582 _assert_msg_(DYNA_REC, 0, "PUSH - Bad imm bits")if (!(0)) { if (!MsgAlert(true, WARNING, "PUSH - Bad imm bits"
)) {{asm ("int $3");};} }
;
583 break;
584 }
585 }
586 else
587 {
588 if (bits == 16)
589 Write8(0x66);
590 reg.WriteRex(this, bits, bits);
591 Write8(0xFF);
592 reg.WriteRest(this, 0, (X64Reg)6);
593 }
594}
595
596void XEmitter::POP(int /*bits*/, const OpArg &reg)
597{
598 if (reg.IsSimpleReg())
599 POP(reg.GetSimpleReg());
600 else
601 INT3();
602}
603
604void XEmitter::BSWAP(int bits, X64Reg reg)
605{
606 if (bits >= 32)
607 {
608 WriteSimple2Byte(bits, 0x0F, 0xC8, reg);
609 }
610 else if (bits == 16)
611 {
612 ROL(16, R(reg), Imm8(8));
613 }
614 else if (bits == 8)
615 {
616 // Do nothing - can't bswap a single byte...
617 }
618 else
619 {
620 _assert_msg_(DYNA_REC, 0, "BSWAP - Wrong number of bits")if (!(0)) { if (!MsgAlert(true, WARNING, "BSWAP - Wrong number of bits"
)) {{asm ("int $3");};} }
;
621 }
622}
623
624// Undefined opcode - reserved
625// If we ever need a way to always cause a non-breakpoint hard exception...
626void XEmitter::UD2()
627{
628 Write8(0x0F);
629 Write8(0x0B);
630}
631
632void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg)
633{
634 if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "PREFETCH - Imm argument")if (!(0)) { if (!MsgAlert(true, WARNING, "PREFETCH - Imm argument"
)) {{asm ("int $3");};} }
;;
635 arg.operandReg = (u8)level;
636 arg.WriteRex(this, 0, 0);
637 Write8(0x0F);
638 Write8(0x18);
639 arg.WriteRest(this);
640}
641
642void XEmitter::SETcc(CCFlags flag, OpArg dest)
643{
644 if (dest.IsImm()) _assert_msg_(DYNA_REC, 0, "SETcc - Imm argument")if (!(0)) { if (!MsgAlert(true, WARNING, "SETcc - Imm argument"
)) {{asm ("int $3");};} }
;
645 dest.operandReg = 0;
646 dest.WriteRex(this, 0, 0);
647 Write8(0x0F);
648 Write8(0x90 + (u8)flag);
649 dest.WriteRest(this);
650}
651
652void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag)
653{
654 if (src.IsImm()) _assert_msg_(DYNA_REC, 0, "CMOVcc - Imm argument")if (!(0)) { if (!MsgAlert(true, WARNING, "CMOVcc - Imm argument"
)) {{asm ("int $3");};} }
;
655 src.operandReg = dest;
656 src.WriteRex(this, bits, bits);
657 Write8(0x0F);
658 Write8(0x40 + (u8)flag);
659 src.WriteRest(this);
660}
661
662void XEmitter::WriteMulDivType(int bits, OpArg src, int ext)
663{
664 if (src.IsImm()) _assert_msg_(DYNA_REC, 0, "WriteMulDivType - Imm argument")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteMulDivType - Imm argument"
)) {{asm ("int $3");};} }
;
665 src.operandReg = ext;
666 if (bits == 16) Write8(0x66);
667 src.WriteRex(this, bits, bits);
668 if (bits == 8)
669 {
670 Write8(0xF6);
671 }
672 else
673 {
674 Write8(0xF7);
675 }
676 src.WriteRest(this);
677}
678
679void XEmitter::MUL(int bits, OpArg src) {WriteMulDivType(bits, src, 4);}
680void XEmitter::DIV(int bits, OpArg src) {WriteMulDivType(bits, src, 6);}
681void XEmitter::IMUL(int bits, OpArg src) {WriteMulDivType(bits, src, 5);}
682void XEmitter::IDIV(int bits, OpArg src) {WriteMulDivType(bits, src, 7);}
683void XEmitter::NEG(int bits, OpArg src) {WriteMulDivType(bits, src, 3);}
684void XEmitter::NOT(int bits, OpArg src) {WriteMulDivType(bits, src, 2);}
685
686void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2)
687{
688 if (src.IsImm()) _assert_msg_(DYNA_REC, 0, "WriteBitSearchType - Imm argument")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteBitSearchType - Imm argument"
)) {{asm ("int $3");};} }
;
689 src.operandReg = (u8)dest;
690 if (bits == 16) Write8(0x66);
691 src.WriteRex(this, bits, bits);
692 Write8(0x0F);
693 Write8(byte2);
694 src.WriteRest(this);
695}
696
697void XEmitter::MOVNTI(int bits, OpArg dest, X64Reg src)
698{
699 if (bits <= 16) _assert_msg_(DYNA_REC, 0, "MOVNTI - bits<=16")if (!(0)) { if (!MsgAlert(true, WARNING, "MOVNTI - bits<=16"
)) {{asm ("int $3");};} }
;
700 WriteBitSearchType(bits, src, dest, 0xC3);
701}
702
703void XEmitter::BSF(int bits, X64Reg dest, OpArg src) {WriteBitSearchType(bits,dest,src,0xBC);} //bottom bit to top bit
704void XEmitter::BSR(int bits, X64Reg dest, OpArg src) {WriteBitSearchType(bits,dest,src,0xBD);} //top bit to bottom bit
705
706void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src)
707{
708 if (src.IsImm()) _assert_msg_(DYNA_REC, 0, "MOVSX - Imm argument")if (!(0)) { if (!MsgAlert(true, WARNING, "MOVSX - Imm argument"
)) {{asm ("int $3");};} }
;
709 if (dbits == sbits) {
710 MOV(dbits, R(dest), src);
711 return;
712 }
713 src.operandReg = (u8)dest;
714 if (dbits == 16) Write8(0x66);
715 src.WriteRex(this, dbits, sbits);
716 if (sbits == 8)
717 {
718 Write8(0x0F);
719 Write8(0xBE);
720 }
721 else if (sbits == 16)
722 {
723 Write8(0x0F);
724 Write8(0xBF);
725 }
726 else if (sbits == 32 && dbits == 64)
727 {
728 Write8(0x63);
729 }
730 else
731 {
732 Crash(){asm ("int $3");};
733 }
734 src.WriteRest(this);
735}
736
737void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src)
738{
739 if (src.IsImm()) _assert_msg_(DYNA_REC, 0, "MOVZX - Imm argument")if (!(0)) { if (!MsgAlert(true, WARNING, "MOVZX - Imm argument"
)) {{asm ("int $3");};} }
;
740 if (dbits == sbits) {
741 MOV(dbits, R(dest), src);
742 return;
743 }
744 src.operandReg = (u8)dest;
745 if (dbits == 16) Write8(0x66);
746 //the 32bit result is automatically zero extended to 64bit
747 src.WriteRex(this, dbits == 64 ? 32 : dbits, sbits);
748 if (sbits == 8)
749 {
750 Write8(0x0F);
751 Write8(0xB6);
752 }
753 else if (sbits == 16)
754 {
755 Write8(0x0F);
756 Write8(0xB7);
757 }
758 else if (sbits == 32 && dbits == 64)
759 {
760 Write8(0x8B);
761 }
762 else
763 {
764 Crash(){asm ("int $3");};
765 }
766 src.WriteRest(this);
767}
768
769
770void XEmitter::LEA(int bits, X64Reg dest, OpArg src)
771{
772 if (src.IsImm()) _assert_msg_(DYNA_REC, 0, "LEA - Imm argument")if (!(0)) { if (!MsgAlert(true, WARNING, "LEA - Imm argument"
)) {{asm ("int $3");};} }
;
773 src.operandReg = (u8)dest;
774 if (bits == 16) Write8(0x66); //TODO: performance warning
775 src.WriteRex(this, bits, bits);
776 Write8(0x8D);
777 src.WriteRest(this, 0, (X64Reg)0xFF, bits == 64);
778}
779
780//shift can be either imm8 or cl
781void XEmitter::WriteShift(int bits, OpArg dest, OpArg &shift, int ext)
782{
783 bool writeImm = false;
784 if (dest.IsImm())
785 {
786 _assert_msg_(DYNA_REC, 0, "WriteShift - can't shift imms")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteShift - can't shift imms"
)) {{asm ("int $3");};} }
;
787 }
788 if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8))
789 {
790 _assert_msg_(DYNA_REC, 0, "WriteShift - illegal argument")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteShift - illegal argument"
)) {{asm ("int $3");};} }
;
791 }
792 dest.operandReg = ext;
793 if (bits == 16) Write8(0x66);
794 dest.WriteRex(this, bits, bits, 0);
795 if (shift.GetImmBits() == 8)
796 {
797 //ok an imm
798 u8 imm = (u8)shift.offset;
799 if (imm == 1)
800 {
801 Write8(bits == 8 ? 0xD0 : 0xD1);
802 }
803 else
804 {
805 writeImm = true;
806 Write8(bits == 8 ? 0xC0 : 0xC1);
807 }
808 }
809 else
810 {
811 Write8(bits == 8 ? 0xD2 : 0xD3);
812 }
813 dest.WriteRest(this, writeImm ? 1 : 0);
814 if (writeImm)
815 Write8((u8)shift.offset);
816}
817
818// large rotates and shift are slower on intel than amd
819// intel likes to rotate by 1, and the op is smaller too
820void XEmitter::ROL(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 0);}
821void XEmitter::ROR(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 1);}
822void XEmitter::RCL(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 2);}
823void XEmitter::RCR(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 3);}
824void XEmitter::SHL(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 4);}
825void XEmitter::SHR(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 5);}
826void XEmitter::SAR(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 7);}
827
828// index can be either imm8 or register, don't use memory destination because it's slow
829void XEmitter::WriteBitTest(int bits, OpArg &dest, OpArg &index, int ext)
830{
831 if (dest.IsImm())
832 {
833 _assert_msg_(DYNA_REC, 0, "WriteBitTest - can't test imms")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteBitTest - can't test imms"
)) {{asm ("int $3");};} }
;
834 }
835 if ((index.IsImm() && index.GetImmBits() != 8))
836 {
837 _assert_msg_(DYNA_REC, 0, "WriteBitTest - illegal argument")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteBitTest - illegal argument"
)) {{asm ("int $3");};} }
;
838 }
839 if (bits == 16) Write8(0x66);
840 if (index.IsImm())
841 {
842 dest.WriteRex(this, bits, bits);
843 Write8(0x0F); Write8(0xBA);
844 dest.WriteRest(this, 1, (X64Reg)ext);
845 Write8((u8)index.offset);
846 }
847 else
848 {
849 X64Reg operand = index.GetSimpleReg();
850 dest.WriteRex(this, bits, bits, operand);
851 Write8(0x0F); Write8(0x83 + 8*ext);
852 dest.WriteRest(this, 1, operand);
853 }
854}
855
856void XEmitter::BT(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 4);}
857void XEmitter::BTS(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 5);}
858void XEmitter::BTR(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 6);}
859void XEmitter::BTC(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 7);}
860
861//shift can be either imm8 or cl
862void XEmitter::SHRD(int bits, OpArg dest, OpArg src, OpArg shift)
863{
864 if (dest.IsImm())
865 {
866 _assert_msg_(DYNA_REC, 0, "SHRD - can't use imms as destination")if (!(0)) { if (!MsgAlert(true, WARNING, "SHRD - can't use imms as destination"
)) {{asm ("int $3");};} }
;
867 }
868 if (!src.IsSimpleReg())
869 {
870 _assert_msg_(DYNA_REC, 0, "SHRD - must use simple register as source")if (!(0)) { if (!MsgAlert(true, WARNING, "SHRD - must use simple register as source"
)) {{asm ("int $3");};} }
;
871 }
872 if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8))
873 {
874 _assert_msg_(DYNA_REC, 0, "SHRD - illegal shift")if (!(0)) { if (!MsgAlert(true, WARNING, "SHRD - illegal shift"
)) {{asm ("int $3");};} }
;
875 }
876 if (bits == 16) Write8(0x66);
877 X64Reg operand = src.GetSimpleReg();
878 dest.WriteRex(this, bits, bits, operand);
879 if (shift.GetImmBits() == 8)
880 {
881 Write8(0x0F); Write8(0xAC);
882 dest.WriteRest(this, 1, operand);
883 Write8((u8)shift.offset);
884 }
885 else
886 {
887 Write8(0x0F); Write8(0xAD);
888 dest.WriteRest(this, 0, operand);
889 }
890}
891
892void XEmitter::SHLD(int bits, OpArg dest, OpArg src, OpArg shift)
893{
894 if (dest.IsImm())
895 {
896 _assert_msg_(DYNA_REC, 0, "SHLD - can't use imms as destination")if (!(0)) { if (!MsgAlert(true, WARNING, "SHLD - can't use imms as destination"
)) {{asm ("int $3");};} }
;
897 }
898 if (!src.IsSimpleReg())
899 {
900 _assert_msg_(DYNA_REC, 0, "SHLD - must use simple register as source")if (!(0)) { if (!MsgAlert(true, WARNING, "SHLD - must use simple register as source"
)) {{asm ("int $3");};} }
;
901 }
902 if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8))
903 {
904 _assert_msg_(DYNA_REC, 0, "SHLD - illegal shift")if (!(0)) { if (!MsgAlert(true, WARNING, "SHLD - illegal shift"
)) {{asm ("int $3");};} }
;
905 }
906 if (bits == 16) Write8(0x66);
907 X64Reg operand = src.GetSimpleReg();
908 dest.WriteRex(this, bits, bits, operand);
909 if (shift.GetImmBits() == 8)
910 {
911 Write8(0x0F); Write8(0xA4);
912 dest.WriteRest(this, 1, operand);
913 Write8((u8)shift.offset);
914 }
915 else
916 {
917 Write8(0x0F); Write8(0xA5);
918 dest.WriteRest(this, 0, operand);
919 }
920}
921
922void OpArg::WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg _operandReg, int bits)
923{
924 if (bits == 16)
925 emit->Write8(0x66);
926
927 this->operandReg = (u8)_operandReg;
928 WriteRex(emit, bits, bits);
929 emit->Write8(op);
930 WriteRest(emit);
931}
932
933//operand can either be immediate or register
934void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &operand, int bits) const
935{
936 X64Reg _operandReg = (X64Reg)this->operandReg;
937 if (IsImm())
938 {
939 _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Imm argument, wrong order")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteNormalOp - Imm argument, wrong order"
)) {{asm ("int $3");};} }
;
940 }
941
942 if (bits == 16)
943 emit->Write8(0x66);
944
945 int immToWrite = 0;
946
947 if (operand.IsImm())
948 {
949 _operandReg = (X64Reg)0;
950 WriteRex(emit, bits, bits);
951
952 if (!toRM)
953 {
954 _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Writing to Imm (!toRM)")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteNormalOp - Writing to Imm (!toRM)"
)) {{asm ("int $3");};} }
;
955 }
956
957 if (operand.scale == SCALE_IMM8 && bits == 8)
958 {
959 emit->Write8(nops[op].imm8);
960 immToWrite = 8;
961 }
962 else if ((operand.scale == SCALE_IMM16 && bits == 16) ||
963 (operand.scale == SCALE_IMM32 && bits == 32) ||
964 (operand.scale == SCALE_IMM32 && bits == 64))
965 {
966 emit->Write8(nops[op].imm32);
967 immToWrite = bits == 16 ? 16 : 32;
968 }
969 else if ((operand.scale == SCALE_IMM8 && bits == 16) ||
970 (operand.scale == SCALE_IMM8 && bits == 32) ||
971 (operand.scale == SCALE_IMM8 && bits == 64))
972 {
973 emit->Write8(nops[op].simm8);
974 immToWrite = 8;
975 }
976 else if (operand.scale == SCALE_IMM64 && bits == 64)
977 {
978 if (op == nrmMOV)
979 {
980 emit->Write8(0xB8 + (offsetOrBaseReg & 7));
981 emit->Write64((u64)operand.offset);
982 return;
983 }
984 _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Only MOV can take 64-bit imm")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteNormalOp - Only MOV can take 64-bit imm"
)) {{asm ("int $3");};} }
;
985 }
986 else
987 {
988 _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Unhandled case")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteNormalOp - Unhandled case"
)) {{asm ("int $3");};} }
;
989 }
990 _operandReg = (X64Reg)nops[op].ext; //pass extension in REG of ModRM
991 }
992 else
993 {
994 _operandReg = (X64Reg)operand.offsetOrBaseReg;
995 WriteRex(emit, bits, bits, _operandReg);
996 // mem/reg or reg/reg op
997 if (toRM)
998 {
999 emit->Write8(bits == 8 ? nops[op].toRm8 : nops[op].toRm32);
1000 // _assert_msg_(DYNA_REC, code[-1] != 0xCC, "ARGH4");
1001 }
1002 else
1003 {
1004 emit->Write8(bits == 8 ? nops[op].fromRm8 : nops[op].fromRm32);
1005 // _assert_msg_(DYNA_REC, code[-1] != 0xCC, "ARGH5");
1006 }
1007 }
1008 WriteRest(emit, immToWrite>>3, _operandReg);
1009 switch (immToWrite)
1010 {
1011 case 0:
1012 break;
1013 case 8:
1014 emit->Write8((u8)operand.offset);
1015 break;
1016 case 16:
1017 emit->Write16((u16)operand.offset);
1018 break;
1019 case 32:
1020 emit->Write32((u32)operand.offset);
1021 break;
1022 default:
1023 _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Unhandled case")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteNormalOp - Unhandled case"
)) {{asm ("int $3");};} }
;
1024 }
1025}
1026
1027void XEmitter::WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg &a1, const OpArg &a2)
1028{
1029 if (a1.IsImm())
1030 {
1031 //Booh! Can't write to an imm
1032 _assert_msg_(DYNA_REC, 0, "WriteNormalOp - a1 cannot be imm")if (!(0)) { if (!MsgAlert(true, WARNING, "WriteNormalOp - a1 cannot be imm"
)) {{asm ("int $3");};} }
;
1033 return;
1034 }
1035 if (a2.IsImm())
1036 {
1037 a1.WriteNormalOp(emit, true, op, a2, bits);
1038 }
1039 else
1040 {
1041 if (a1.IsSimpleReg())
1042 {
1043 a2.WriteNormalOp(emit, false, op, a1, bits);
1044 }
1045 else
1046 {
1047 a1.WriteNormalOp(emit, true, op, a2, bits);
1048 }
1049 }
1050}
1051
1052void XEmitter::ADD (int bits, const OpArg &a1, const OpArg &a2) {WriteNormalOp(this, bits, nrmADD, a1, a2);}
1053void XEmitter::ADC (int bits, const OpArg &a1, const OpArg &a2) {WriteNormalOp(this, bits, nrmADC, a1, a2);}
1054void XEmitter::SUB (int bits, const OpArg &a1, const OpArg &a2) {WriteNormalOp(this, bits, nrmSUB, a1, a2);}
1055void XEmitter::SBB (int bits, const OpArg &a1, const OpArg &a2) {WriteNormalOp(this, bits, nrmSBB, a1, a2);}
1056void XEmitter::AND (int bits, const OpArg &a1, const OpArg &a2) {WriteNormalOp(this, bits, nrmAND, a1, a2);}
1057void XEmitter::OR (int bits, const OpArg &a1, const OpArg &a2) {WriteNormalOp(this, bits, nrmOR , a1, a2);}
1058void XEmitter::XOR (int bits, const OpArg &a1, const OpArg &a2) {WriteNormalOp(this, bits, nrmXOR, a1, a2);}
1059void XEmitter::MOV (int bits, const OpArg &a1, const OpArg &a2)
1060{
1061#ifdef _DEBUG
1062 _assert_msg_(DYNA_REC, !a1.IsSimpleReg() || !a2.IsSimpleReg() || a1.GetSimpleReg() != a2.GetSimpleReg(), "Redundant MOV @ %p - bug in JIT?",if (!(!a1.IsSimpleReg() || !a2.IsSimpleReg() || a1.GetSimpleReg
() != a2.GetSimpleReg())) { if (!MsgAlert(true, WARNING, "Redundant MOV @ %p - bug in JIT?"
, code)) {{asm ("int $3");};} }
1063 code)if (!(!a1.IsSimpleReg() || !a2.IsSimpleReg() || a1.GetSimpleReg
() != a2.GetSimpleReg())) { if (!MsgAlert(true, WARNING, "Redundant MOV @ %p - bug in JIT?"
, code)) {{asm ("int $3");};} }
;
1064#endif
1065 WriteNormalOp(this, bits, nrmMOV, a1, a2);
1066}
1067void XEmitter::TEST(int bits, const OpArg &a1, const OpArg &a2) {WriteNormalOp(this, bits, nrmTEST, a1, a2);}
1068void XEmitter::CMP (int bits, const OpArg &a1, const OpArg &a2) {WriteNormalOp(this, bits, nrmCMP, a1, a2);}
1069void XEmitter::XCHG(int bits, const OpArg &a1, const OpArg &a2) {WriteNormalOp(this, bits, nrmXCHG, a1, a2);}
1070
1071void XEmitter::IMUL(int bits, X64Reg regOp, OpArg a1, OpArg a2)
1072{
1073 if (bits == 8) {
1074 _assert_msg_(DYNA_REC, 0, "IMUL - illegal bit size!")if (!(0)) { if (!MsgAlert(true, WARNING, "IMUL - illegal bit size!"
)) {{asm ("int $3");};} }
;
1075 return;
1076 }
1077 if (a1.IsImm()) {
1078 _assert_msg_(DYNA_REC, 0, "IMUL - second arg cannot be imm!")if (!(0)) { if (!MsgAlert(true, WARNING, "IMUL - second arg cannot be imm!"
)) {{asm ("int $3");};} }
;
1079 return;
1080 }
1081 if (!a2.IsImm())
1082 {
1083 _assert_msg_(DYNA_REC, 0, "IMUL - third arg must be imm!")if (!(0)) { if (!MsgAlert(true, WARNING, "IMUL - third arg must be imm!"
)) {{asm ("int $3");};} }
;
1084 return;
1085 }
1086
1087 if (bits == 16)
1088 Write8(0x66);
1089 a1.WriteRex(this, bits, bits, regOp);
1090
1091 if (a2.GetImmBits() == 8) {
1092 Write8(0x6B);
1093 a1.WriteRest(this, 1, regOp);
1094 Write8((u8)a2.offset);
1095 } else {
1096 Write8(0x69);
1097 if (a2.GetImmBits() == 16 && bits == 16) {
1098 a1.WriteRest(this, 2, regOp);
1099 Write16((u16)a2.offset);
1100 } else if (a2.GetImmBits() == 32 &&
1101 (bits == 32 || bits == 64)) {
1102 a1.WriteRest(this, 4, regOp);
1103 Write32((u32)a2.offset);
1104 } else {
1105 _assert_msg_(DYNA_REC, 0, "IMUL - unhandled case!")if (!(0)) { if (!MsgAlert(true, WARNING, "IMUL - unhandled case!"
)) {{asm ("int $3");};} }
;
1106 }
1107 }
1108}
1109
1110void XEmitter::IMUL(int bits, X64Reg regOp, OpArg a)
1111{
1112 if (bits == 8) {
1113 _assert_msg_(DYNA_REC, 0, "IMUL - illegal bit size!")if (!(0)) { if (!MsgAlert(true, WARNING, "IMUL - illegal bit size!"
)) {{asm ("int $3");};} }
;
1114 return;
1115 }
1116 if (a.IsImm())
1117 {
1118 IMUL(bits, regOp, R(regOp), a) ;
1119 return;
1120 }
1121
1122 if (bits == 16)
1123 Write8(0x66);
1124 a.WriteRex(this, bits, bits, regOp);
1125 Write8(0x0F);
1126 Write8(0xAF);
1127 a.WriteRest(this, 0, regOp);
1128}
1129
1130
1131void XEmitter::WriteSSEOp(int size, u8 sseOp, bool packed, X64Reg regOp, OpArg arg, int extrabytes)
1132{
1133 if (size == 64 && packed)
1134 Write8(0x66); //this time, override goes upwards
1135 if (!packed)
1136 Write8(size == 64 ? 0xF2 : 0xF3);
1137 arg.operandReg = regOp;
1138 arg.WriteRex(this, 0, 0);
1139 Write8(0x0F);
1140 Write8(sseOp);
1141 arg.WriteRest(this, extrabytes);
1142}
1143
1144void XEmitter::MOVD_xmm(X64Reg dest, const OpArg &arg) {WriteSSEOp(64, 0x6E, true, dest, arg, 0);}
1145void XEmitter::MOVD_xmm(const OpArg &arg, X64Reg src) {WriteSSEOp(64, 0x7E, true, src, arg, 0);}
1146
1147void XEmitter::MOVQ_xmm(X64Reg dest, OpArg arg) {
1148#ifdef _M_X641
1149 // Alternate encoding
1150 // This does not display correctly in MSVC's debugger, it thinks it's a MOVD
1151 arg.operandReg = dest;
1152 Write8(0x66);
1153 arg.WriteRex(this, 64, 0);
1154 Write8(0x0f);
1155 Write8(0x6E);
1156 arg.WriteRest(this, 0);
1157#else
1158 arg.operandReg = dest;
1159 Write8(0xF3);
1160 Write8(0x0f);
1161 Write8(0x7E);
1162 arg.WriteRest(this, 0);
1163#endif
1164}
1165
1166void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) {
1167 if (arg.IsSimpleReg())
1168 PanicAlert("Emitter: MOVQ_xmm doesn't support single registers as destination")MsgAlert(false, WARNING, "Emitter: MOVQ_xmm doesn't support single registers as destination"
)
;
1169 if (src > 7)
1170 {
1171 // Alternate encoding
1172 // This does not display correctly in MSVC's debugger, it thinks it's a MOVD
1173 arg.operandReg = src;
1174 Write8(0x66);
1175 arg.WriteRex(this, 64, 0);
1176 Write8(0x0f);
1177 Write8(0x7E);
1178 arg.WriteRest(this, 0);
1179 } else {
1180 arg.operandReg = src;
1181 arg.WriteRex(this, 0, 0);
1182 Write8(0x66);
1183 Write8(0x0f);
1184 Write8(0xD6);
1185 arg.WriteRest(this, 0);
1186 }
1187}
1188
1189void XEmitter::WriteMXCSR(OpArg arg, int ext)
1190{
1191 if (arg.IsImm() || arg.IsSimpleReg())
1192 _assert_msg_(DYNA_REC, 0, "MXCSR - invalid operand")if (!(0)) { if (!MsgAlert(true, WARNING, "MXCSR - invalid operand"
)) {{asm ("int $3");};} }
;
1193
1194 arg.operandReg = ext;
1195 arg.WriteRex(this, 0, 0);
1196 Write8(0x0F);
1197 Write8(0xAE);
1198 arg.WriteRest(this);
1199}
1200
1201void XEmitter::STMXCSR(OpArg memloc) {WriteMXCSR(memloc, 3);}
1202void XEmitter::LDMXCSR(OpArg memloc) {WriteMXCSR(memloc, 2);}
1203
1204void XEmitter::MOVNTDQ(OpArg arg, X64Reg regOp) {WriteSSEOp(64, sseMOVNTDQ, true, regOp, arg);}
1205void XEmitter::MOVNTPS(OpArg arg, X64Reg regOp) {WriteSSEOp(32, sseMOVNTP, true, regOp, arg);}
1206void XEmitter::MOVNTPD(OpArg arg, X64Reg regOp) {WriteSSEOp(64, sseMOVNTP, true, regOp, arg);}
1207
1208void XEmitter::ADDSS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseADD, false, regOp, arg);}
1209void XEmitter::ADDSD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseADD, false, regOp, arg);}
1210void XEmitter::SUBSS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseSUB, false, regOp, arg);}
1211void XEmitter::SUBSD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseSUB, false, regOp, arg);}
1212void XEmitter::CMPSS(X64Reg regOp, OpArg arg, u8 compare) {WriteSSEOp(32, sseCMP, false, regOp, arg,1); Write8(compare);}
1213void XEmitter::CMPSD(X64Reg regOp, OpArg arg, u8 compare) {WriteSSEOp(64, sseCMP, false, regOp, arg,1); Write8(compare);}
1214void XEmitter::MULSS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseMUL, false, regOp, arg);}
1215void XEmitter::MULSD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseMUL, false, regOp, arg);}
1216void XEmitter::DIVSS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseDIV, false, regOp, arg);}
1217void XEmitter::DIVSD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseDIV, false, regOp, arg);}
1218void XEmitter::MINSS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseMIN, false, regOp, arg);}
1219void XEmitter::MINSD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseMIN, false, regOp, arg);}
1220void XEmitter::MAXSS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseMAX, false, regOp, arg);}
1221void XEmitter::MAXSD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseMAX, false, regOp, arg);}
1222void XEmitter::SQRTSS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseSQRT, false, regOp, arg);}
1223void XEmitter::SQRTSD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseSQRT, false, regOp, arg);}
1224void XEmitter::RSQRTSS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseRSQRT, false, regOp, arg);}
1225
1226void XEmitter::ADDPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseADD, true, regOp, arg);}
1227void XEmitter::ADDPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseADD, true, regOp, arg);}
1228void XEmitter::SUBPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseSUB, true, regOp, arg);}
1229void XEmitter::SUBPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseSUB, true, regOp, arg);}
1230void XEmitter::CMPPS(X64Reg regOp, OpArg arg, u8 compare) {WriteSSEOp(32, sseCMP, true, regOp, arg,1); Write8(compare);}
1231void XEmitter::CMPPD(X64Reg regOp, OpArg arg, u8 compare) {WriteSSEOp(64, sseCMP, true, regOp, arg,1); Write8(compare);}
1232void XEmitter::ANDPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseAND, true, regOp, arg);}
1233void XEmitter::ANDPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseAND, true, regOp, arg);}
1234void XEmitter::ANDNPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseANDN, true, regOp, arg);}
1235void XEmitter::ANDNPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseANDN, true, regOp, arg);}
1236void XEmitter::ORPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseOR, true, regOp, arg);}
1237void XEmitter::ORPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseOR, true, regOp, arg);}
1238void XEmitter::XORPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseXOR, true, regOp, arg);}
1239void XEmitter::XORPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseXOR, true, regOp, arg);}
1240void XEmitter::MULPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseMUL, true, regOp, arg);}
1241void XEmitter::MULPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseMUL, true, regOp, arg);}
1242void XEmitter::DIVPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseDIV, true, regOp, arg);}
1243void XEmitter::DIVPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseDIV, true, regOp, arg);}
1244void XEmitter::MINPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseMIN, true, regOp, arg);}
1245void XEmitter::MINPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseMIN, true, regOp, arg);}
1246void XEmitter::MAXPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseMAX, true, regOp, arg);}
1247void XEmitter::MAXPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseMAX, true, regOp, arg);}
1248void XEmitter::SQRTPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseSQRT, true, regOp, arg);}
1249void XEmitter::SQRTPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseSQRT, true, regOp, arg);}
1250void XEmitter::RSQRTPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseRSQRT, true, regOp, arg);}
1251void XEmitter::SHUFPS(X64Reg regOp, OpArg arg, u8 shuffle) {WriteSSEOp(32, sseSHUF, true, regOp, arg,1); Write8(shuffle);}
1252void XEmitter::SHUFPD(X64Reg regOp, OpArg arg, u8 shuffle) {WriteSSEOp(64, sseSHUF, true, regOp, arg,1); Write8(shuffle);}
1253
1254void XEmitter::COMISS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseCOMIS, true, regOp, arg);} //weird that these should be packed
1255void XEmitter::COMISD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseCOMIS, true, regOp, arg);} //ordered
1256void XEmitter::UCOMISS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseUCOMIS, true, regOp, arg);} //unordered
1257void XEmitter::UCOMISD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseUCOMIS, true, regOp, arg);}
1258
1259void XEmitter::MOVAPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseMOVAPfromRM, true, regOp, arg);}
1260void XEmitter::MOVAPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseMOVAPfromRM, true, regOp, arg);}
1261void XEmitter::MOVAPS(OpArg arg, X64Reg regOp) {WriteSSEOp(32, sseMOVAPtoRM, true, regOp, arg);}
1262void XEmitter::MOVAPD(OpArg arg, X64Reg regOp) {WriteSSEOp(64, sseMOVAPtoRM, true, regOp, arg);}
1263
1264void XEmitter::MOVUPS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseMOVUPfromRM, true, regOp, arg);}
1265void XEmitter::MOVUPD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseMOVUPfromRM, true, regOp, arg);}
1266void XEmitter::MOVUPS(OpArg arg, X64Reg regOp) {WriteSSEOp(32, sseMOVUPtoRM, true, regOp, arg);}
1267void XEmitter::MOVUPD(OpArg arg, X64Reg regOp) {WriteSSEOp(64, sseMOVUPtoRM, true, regOp, arg);}
1268
1269void XEmitter::MOVSS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, sseMOVUPfromRM, false, regOp, arg);}
1270void XEmitter::MOVSD(X64Reg regOp, OpArg arg) {WriteSSEOp(64, sseMOVUPfromRM, false, regOp, arg);}
1271void XEmitter::MOVSS(OpArg arg, X64Reg regOp) {WriteSSEOp(32, sseMOVUPtoRM, false, regOp, arg);}
1272void XEmitter::MOVSD(OpArg arg, X64Reg regOp) {WriteSSEOp(64, sseMOVUPtoRM, false, regOp, arg);}
1273
1274void XEmitter::CVTPS2PD(X64Reg regOp, OpArg arg) {WriteSSEOp(32, 0x5A, true, regOp, arg);}
1275void XEmitter::CVTPD2PS(X64Reg regOp, OpArg arg) {WriteSSEOp(64, 0x5A, true, regOp, arg);}
1276
1277void XEmitter::CVTSD2SS(X64Reg regOp, OpArg arg) {WriteSSEOp(64, 0x5A, false, regOp, arg);}
1278void XEmitter::CVTSS2SD(X64Reg regOp, OpArg arg) {WriteSSEOp(32, 0x5A, false, regOp, arg);}
1279void XEmitter::CVTSD2SI(X64Reg regOp, OpArg arg) {WriteSSEOp(64, 0x2D, false, regOp, arg);}
1280
1281void XEmitter::CVTDQ2PD(X64Reg regOp, OpArg arg) {WriteSSEOp(32, 0xE6, false, regOp, arg);}
1282void XEmitter::CVTDQ2PS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, 0x5B, true, regOp, arg);}
1283void XEmitter::CVTPD2DQ(X64Reg regOp, OpArg arg) {WriteSSEOp(64, 0xE6, false, regOp, arg);}
1284void XEmitter::CVTPS2DQ(X64Reg regOp, OpArg arg) {WriteSSEOp(64, 0x5B, true, regOp, arg);}
1285
1286void XEmitter::CVTTSS2SI(X64Reg xregdest, OpArg arg) {WriteSSEOp(32, 0x2C, false, xregdest, arg);}
1287void XEmitter::CVTTPS2DQ(X64Reg xregdest, OpArg arg) {WriteSSEOp(32, 0x5B, false, xregdest, arg);}
1288
1289void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) {WriteSSEOp(64, sseMASKMOVDQU, true, dest, R(src));}
1290
1291void XEmitter::MOVMSKPS(X64Reg dest, OpArg arg) {WriteSSEOp(32, 0x50, true, dest, arg);}
1292void XEmitter::MOVMSKPD(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x50, true, dest, arg);}
1293
1294void XEmitter::LDDQU(X64Reg dest, OpArg arg) {WriteSSEOp(64, sseLDDQU, false, dest, arg);} // For integer data only
1295
1296// THESE TWO ARE UNTESTED.
1297void XEmitter::UNPCKLPS(X64Reg dest, OpArg arg) {WriteSSEOp(32, 0x14, true, dest, arg);}
1298void XEmitter::UNPCKHPS(X64Reg dest, OpArg arg) {WriteSSEOp(32, 0x15, true, dest, arg);}
1299
1300void XEmitter::UNPCKLPD(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x14, true, dest, arg);}
1301void XEmitter::UNPCKHPD(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x15, true, dest, arg);}
1302
1303void XEmitter::MOVDDUP(X64Reg regOp, OpArg arg)
1304{
1305 if (cpu_info.bSSE3)
1306 {
1307 WriteSSEOp(64, 0x12, false, regOp, arg); //SSE3 movddup
1308 }
1309 else
1310 {
1311 // Simulate this instruction with SSE2 instructions
1312 if (!arg.IsSimpleReg(regOp))
1313 MOVSD(regOp, arg);
1314 UNPCKLPD(regOp, R(regOp));
1315 }
1316}
1317
1318//There are a few more left
1319
1320// Also some integer instructions are missing
1321void XEmitter::PACKSSDW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x6B, true, dest, arg);}
1322void XEmitter::PACKSSWB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x63, true, dest, arg);}
1323//void PACKUSDW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x66, true, dest, arg);} // WRONG
1324void XEmitter::PACKUSWB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x67, true, dest, arg);}
1325
1326void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg &arg) {WriteSSEOp(64, 0x60, true, dest, arg);}
1327void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg &arg) {WriteSSEOp(64, 0x61, true, dest, arg);}
1328void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg &arg) {WriteSSEOp(64, 0x62, true, dest, arg);}
1329//void PUNPCKLQDQ(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x60, true, dest, arg);}
1330
1331void XEmitter::PSRLW(X64Reg reg, int shift) {
1332 WriteSSEOp(64, 0x71, true, (X64Reg)2, R(reg));
1333 Write8(shift);
1334}
1335
1336void XEmitter::PSRLD(X64Reg reg, int shift) {
1337 WriteSSEOp(64, 0x72, true, (X64Reg)2, R(reg));
1338 Write8(shift);
1339}
1340
1341void XEmitter::PSRLQ(X64Reg reg, int shift) {
1342 WriteSSEOp(64, 0x73, true, (X64Reg)2, R(reg));
1343 Write8(shift);
1344}
1345
1346void XEmitter::PSLLW(X64Reg reg, int shift) {
1347 WriteSSEOp(64, 0x71, true, (X64Reg)6, R(reg));
1348 Write8(shift);
1349}
1350
1351void XEmitter::PSLLD(X64Reg reg, int shift) {
1352 WriteSSEOp(64, 0x72, true, (X64Reg)6, R(reg));
1353 Write8(shift);
1354}
1355
1356void XEmitter::PSLLQ(X64Reg reg, int shift) {
1357 WriteSSEOp(64, 0x73, true, (X64Reg)6, R(reg));
1358 Write8(shift);
1359}
1360
1361// WARNING not REX compatible
1362void XEmitter::PSRAW(X64Reg reg, int shift) {
1363 if (reg > 7)
1364 PanicAlert("The PSRAW-emitter does not support regs above 7")MsgAlert(false, WARNING, "The PSRAW-emitter does not support regs above 7"
)
;
1365 Write8(0x66);
1366 Write8(0x0f);
1367 Write8(0x71);
1368 Write8(0xE0 | reg);
1369 Write8(shift);
1370}
1371
1372// WARNING not REX compatible
1373void XEmitter::PSRAD(X64Reg reg, int shift) {
1374 if (reg > 7)
1375 PanicAlert("The PSRAD-emitter does not support regs above 7")MsgAlert(false, WARNING, "The PSRAD-emitter does not support regs above 7"
)
;
1376 Write8(0x66);
1377 Write8(0x0f);
1378 Write8(0x72);
1379 Write8(0xE0 | reg);
1380 Write8(shift);
1381}
1382
1383void XEmitter::PSHUFB(X64Reg dest, OpArg arg) {
1384 if (!cpu_info.bSSSE3) {
1385 PanicAlert("Trying to use PSHUFB on a system that doesn't support it. Bad programmer.")MsgAlert(false, WARNING, "Trying to use PSHUFB on a system that doesn't support it. Bad programmer."
)
;
1386 }
1387 Write8(0x66);
1388 arg.operandReg = dest;
1389 arg.WriteRex(this, 0, 0);
1390 Write8(0x0f);
1391 Write8(0x38);
1392 Write8(0x00);
1393 arg.WriteRest(this, 0);
1394}
1395
1396void XEmitter::PAND(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xDB, true, dest, arg);}
1397void XEmitter::PANDN(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xDF, true, dest, arg);}
1398void XEmitter::PXOR(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xEF, true, dest, arg);}
1399void XEmitter::POR(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xEB, true, dest, arg);}
1400
1401void XEmitter::PADDB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xFC, true, dest, arg);}
1402void XEmitter::PADDW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xFD, true, dest, arg);}
1403void XEmitter::PADDD(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xFE, true, dest, arg);}
1404void XEmitter::PADDQ(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xD4, true, dest, arg);}
1405
1406void XEmitter::PADDSB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xEC, true, dest, arg);}
1407void XEmitter::PADDSW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xED, true, dest, arg);}
1408void XEmitter::PADDUSB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xDC, true, dest, arg);}
1409void XEmitter::PADDUSW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xDD, true, dest, arg);}
1410
1411void XEmitter::PSUBB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xF8, true, dest, arg);}
1412void XEmitter::PSUBW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xF9, true, dest, arg);}
1413void XEmitter::PSUBD(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xFA, true, dest, arg);}
1414void XEmitter::PSUBQ(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xDB, true, dest, arg);}
1415
1416void XEmitter::PSUBSB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xE8, true, dest, arg);}
1417void XEmitter::PSUBSW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xE9, true, dest, arg);}
1418void XEmitter::PSUBUSB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xD8, true, dest, arg);}
1419void XEmitter::PSUBUSW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xD9, true, dest, arg);}
1420
1421void XEmitter::PAVGB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xE0, true, dest, arg);}
1422void XEmitter::PAVGW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xE3, true, dest, arg);}
1423
1424void XEmitter::PCMPEQB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x74, true, dest, arg);}
1425void XEmitter::PCMPEQW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x75, true, dest, arg);}
1426void XEmitter::PCMPEQD(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x76, true, dest, arg);}
1427
1428void XEmitter::PCMPGTB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x64, true, dest, arg);}
1429void XEmitter::PCMPGTW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x65, true, dest, arg);}
1430void XEmitter::PCMPGTD(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x66, true, dest, arg);}
1431
1432void XEmitter::PEXTRW(X64Reg dest, OpArg arg, u8 subreg) {WriteSSEOp(64, 0xC5, true, dest, arg); Write8(subreg);}
1433void XEmitter::PINSRW(X64Reg dest, OpArg arg, u8 subreg) {WriteSSEOp(64, 0xC4, true, dest, arg); Write8(subreg);}
1434
1435void XEmitter::PMADDWD(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xF5, true, dest, arg); }
1436void XEmitter::PSADBW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xF6, true, dest, arg);}
1437
1438void XEmitter::PMAXSW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xEE, true, dest, arg); }
1439void XEmitter::PMAXUB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xDE, true, dest, arg); }
1440void XEmitter::PMINSW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xEA, true, dest, arg); }
1441void XEmitter::PMINUB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xDA, true, dest, arg); }
1442
1443void XEmitter::PMOVMSKB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xD7, true, dest, arg); }
1444
1445void XEmitter::PSHUFLW(X64Reg regOp, OpArg arg, u8 shuffle) {WriteSSEOp(64, 0x70, false, regOp, arg, 1); Write8(shuffle);}
1446
1447// Prefixes
1448
1449void XEmitter::LOCK() { Write8(0xF0); }
1450void XEmitter::REP() { Write8(0xF3); }
1451void XEmitter::REPNE() { Write8(0xF2); }
1452
1453void XEmitter::FWAIT()
1454{
1455 Write8(0x9B);
1456}
1457
1458void XEmitter::RTDSC() { Write8(0x0F); Write8(0x31); }
1459
1460// helper routines for setting pointers
1461void XEmitter::CallCdeclFunction3(void* fnptr, u32 arg0, u32 arg1, u32 arg2)
1462{
1463 using namespace Gen;
1464#ifdef _M_X641
1465
1466#ifdef _MSC_VER
1467 MOV(32, R(RCX), Imm32(arg0));
1468 MOV(32, R(RDX), Imm32(arg1));
1469 MOV(32, R(R8), Imm32(arg2));
1470 CALL(fnptr);
1471#else
1472 MOV(32, R(RDI), Imm32(arg0));
1473 MOV(32, R(RSI), Imm32(arg1));
1474 MOV(32, R(RDX), Imm32(arg2));
1475 CALL(fnptr);
1476#endif
1477
1478#else
1479 ABI_AlignStack(3 * 4);
1480 PUSH(32, Imm32(arg2));
1481 PUSH(32, Imm32(arg1));
1482 PUSH(32, Imm32(arg0));
1483 CALL(fnptr);
1484#ifdef _WIN32
1485 // don't inc stack
1486#else
1487 ABI_RestoreStack(3 * 4);
1488#endif
1489#endif
1490}
1491
1492void XEmitter::CallCdeclFunction4(void* fnptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3)
1493{
1494 using namespace Gen;
1495#ifdef _M_X641
1496
1497#ifdef _MSC_VER
1498 MOV(32, R(RCX), Imm32(arg0));
1499 MOV(32, R(RDX), Imm32(arg1));
1500 MOV(32, R(R8), Imm32(arg2));
1501 MOV(32, R(R9), Imm32(arg3));
1502 CALL(fnptr);
1503#else
1504 MOV(32, R(RDI), Imm32(arg0));
1505 MOV(32, R(RSI), Imm32(arg1));
1506 MOV(32, R(RDX), Imm32(arg2));
1507 MOV(32, R(RCX), Imm32(arg3));
1508 CALL(fnptr);
1509#endif
1510
1511#else
1512 ABI_AlignStack(4 * 4);
1513 PUSH(32, Imm32(arg3));
1514 PUSH(32, Imm32(arg2));
1515 PUSH(32, Imm32(arg1));
1516 PUSH(32, Imm32(arg0));
1517 CALL(fnptr);
1518#ifdef _WIN32
1519 // don't inc stack
1520#else
1521 ABI_RestoreStack(4 * 4);
1522#endif
1523#endif
1524}
1525
1526void XEmitter::CallCdeclFunction5(void* fnptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
1527{
1528 using namespace Gen;
1529#ifdef _M_X641
1530
1531#ifdef _MSC_VER
1532 MOV(32, R(RCX), Imm32(arg0));
1533 MOV(32, R(RDX), Imm32(arg1));
1534 MOV(32, R(R8), Imm32(arg2));
1535 MOV(32, R(R9), Imm32(arg3));
1536 MOV(32, MDisp(RSP, 0x20), Imm32(arg4));
1537 CALL(fnptr);
1538#else
1539 MOV(32, R(RDI), Imm32(arg0));
1540 MOV(32, R(RSI), Imm32(arg1));
1541 MOV(32, R(RDX), Imm32(arg2));
1542 MOV(32, R(RCX), Imm32(arg3));
1543 MOV(32, R(R8), Imm32(arg4));
1544 CALL(fnptr);
1545#endif
1546
1547#else
1548 ABI_AlignStack(5 * 4);
1549 PUSH(32, Imm32(arg4));
1550 PUSH(32, Imm32(arg3));
1551 PUSH(32, Imm32(arg2));
1552 PUSH(32, Imm32(arg1));
1553 PUSH(32, Imm32(arg0));
1554 CALL(fnptr);
1555#ifdef _WIN32
1556 // don't inc stack
1557#else
1558 ABI_RestoreStack(5 * 4);
1559#endif
1560#endif
1561}
1562
1563void XEmitter::CallCdeclFunction6(void* fnptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
1564{
1565 using namespace Gen;
1566#ifdef _M_X641
1567
1568#ifdef _MSC_VER
1569 MOV(32, R(RCX), Imm32(arg0));
1570 MOV(32, R(RDX), Imm32(arg1));
1571 MOV(32, R(R8), Imm32(arg2));
1572 MOV(32, R(R9), Imm32(arg3));
1573 MOV(32, MDisp(RSP, 0x20), Imm32(arg4));
1574 MOV(32, MDisp(RSP, 0x28), Imm32(arg5));
1575 CALL(fnptr);
1576#else
1577 MOV(32, R(RDI), Imm32(arg0));
1578 MOV(32, R(RSI), Imm32(arg1));
1579 MOV(32, R(RDX), Imm32(arg2));
1580 MOV(32, R(RCX), Imm32(arg3));
1581 MOV(32, R(R8), Imm32(arg4));
1582 MOV(32, R(R9), Imm32(arg5));
1583 CALL(fnptr);
1584#endif
1585
1586#else
1587 ABI_AlignStack(6 * 4);
1588 PUSH(32, Imm32(arg5));
1589 PUSH(32, Imm32(arg4));
1590 PUSH(32, Imm32(arg3));
1591 PUSH(32, Imm32(arg2));
1592 PUSH(32, Imm32(arg1));
1593 PUSH(32, Imm32(arg0));
1594 CALL(fnptr);
1595#ifdef _WIN32
1596 // don't inc stack
1597#else
1598 ABI_RestoreStack(6 * 4);
1599#endif
1600#endif
1601}
1602
1603#ifdef _M_X641
1604
1605// See header
1606void XEmitter::___CallCdeclImport3(void* impptr, u32 arg0, u32 arg1, u32 arg2) {
1607 MOV(32, R(RCX), Imm32(arg0));
1608 MOV(32, R(RDX), Imm32(arg1));
1609 MOV(32, R(R8), Imm32(arg2));
1610 CALLptr(M(impptr));
1611}
1612void XEmitter::___CallCdeclImport4(void* impptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3) {
1613 MOV(32, R(RCX), Imm32(arg0));
1614 MOV(32, R(RDX), Imm32(arg1));
1615 MOV(32, R(R8), Imm32(arg2));
1616 MOV(32, R(R9), Imm32(arg3));
1617 CALLptr(M(impptr));
1618}
1619void XEmitter::___CallCdeclImport5(void* impptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) {
1620 MOV(32, R(RCX), Imm32(arg0));
1621 MOV(32, R(RDX), Imm32(arg1));
1622 MOV(32, R(R8), Imm32(arg2));
1623 MOV(32, R(R9), Imm32(arg3));
1624 MOV(32, MDisp(RSP, 0x20), Imm32(arg4));
1625 CALLptr(M(impptr));
1626}
1627void XEmitter::___CallCdeclImport6(void* impptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 arg5) {
1628 MOV(32, R(RCX), Imm32(arg0));
1629 MOV(32, R(RDX), Imm32(arg1));
1630 MOV(32, R(R8), Imm32(arg2));
1631 MOV(32, R(R9), Imm32(arg3));
1632 MOV(32, MDisp(RSP, 0x20), Imm32(arg4));
1633 MOV(32, MDisp(RSP, 0x28), Imm32(arg5));
1634 CALLptr(M(impptr));
1635}
1636
1637#endif
1638
1639}