/[pcsx2_0.9.7]/trunk/common/include/x86emitter/x86types.h
ViewVC logotype

Contents of /trunk/common/include/x86emitter/x86types.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 11 months ago) by william
File MIME type: text/plain
File size: 33067 byte(s)
committing r3113 initial commit again...
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #pragma once
17
18 // Register counts for x86/32 mode:
19 static const int iREGCNT_XMM = 8;
20 static const int iREGCNT_GPR = 8;
21 static const int iREGCNT_MMX = 8;
22
23 enum XMMSSEType
24 {
25 XMMT_INT = 0, // integer (sse2 only)
26 XMMT_FPS = 1, // floating point
27 //XMMT_FPD = 3, // double
28 };
29
30 // --------------------------------------------------------------------------------------
31 // __tls_emit / x86EMIT_MULTITHREADED
32 // --------------------------------------------------------------------------------------
33 // Multithreaded support for the x86 emitter. (defaults to 0)
34 // To enable the multithreaded emitter, either set the below define to 1, or set the define
35 // as a project option. The multithreaded emitter relies on native compiler support for
36 // TLS -- Macs are crap out of luck there (for now).
37
38 #ifndef x86EMIT_MULTITHREADED
39 # define x86EMIT_MULTITHREADED 0
40 #else
41 # if !PCSX2_THREAD_LOCAL
42 // No TLS support? Force-clear the MT flag:
43 # pragma message("x86emitter: TLS not available, multithreaded emitter disabled.")
44 # undef x86EMIT_MULTITHREADED
45 # define x86EMIT_MULTITHREADED 0
46 # endif
47 #endif
48
49 #ifndef __tls_emit
50 # if x86EMIT_MULTITHREADED
51 # define __tls_emit __threadlocal
52 # else
53 // Using TlsVariable is sub-optimal and could result in huge executables, so we
54 // force-disable TLS entirely, and disallow running multithreaded recompilation
55 // components within PCSX2 manually.
56 # define __tls_emit
57 # endif
58 #endif
59
60 extern __tls_emit u8* x86Ptr;
61 extern __tls_emit XMMSSEType g_xmmtypes[iREGCNT_XMM];
62
63 namespace x86Emitter
64 {
65
66 extern void xWrite8( u8 val );
67 extern void xWrite16( u16 val );
68 extern void xWrite32( u32 val );
69 extern void xWrite64( u64 val );
70
71 extern const char *const x86_regnames_gpr8[8];
72 extern const char *const x86_regnames_gpr16[8];
73 extern const char *const x86_regnames_gpr32[8];
74
75 extern const char *const x86_regnames_sse[8];
76 extern const char *const x86_regnames_mmx[8];
77
78 extern const char* xGetRegName( int regid, int operandSize );
79
80 //------------------------------------------------------------------
81 // templated version of is_s8 is required, so that u16's get correct sign extension treatment.
82 template< typename T >
83 static __forceinline bool is_s8( T imm ) { return (s8)imm == (s32)imm; }
84
85 template< typename T > void xWrite( T val );
86
87 // --------------------------------------------------------------------------------------
88 // ALWAYS_USE_MOVAPS [define] / AlwaysUseMovaps [const]
89 // --------------------------------------------------------------------------------------
90 // This tells the recompiler's emitter to always use movaps instead of movdqa. Both instructions
91 // do the exact same thing, but movaps is 1 byte shorter, and thus results in a cleaner L1 cache
92 // and some marginal speed gains as a result. (it's possible someday in the future the per-
93 // formance of the two instructions could change, so this constant is provided to restore MOVDQA
94 // use easily at a later time, if needed).
95 //
96 #define ALWAYS_USE_MOVAPS
97
98 #ifdef ALWAYS_USE_MOVAPS
99 static const bool AlwaysUseMovaps = true;
100 #else
101 static const bool AlwaysUseMovaps = false;
102 #endif
103
104 // --------------------------------------------------------------------------------------
105 // __emitline - preprocessors definition
106 // --------------------------------------------------------------------------------------
107 // This is configured to inline emitter functions appropriately for release builds, and
108 // disables some of the more aggressive inlines for dev builds (which can be helpful when
109 // debugging). Additionally, I've set up the inlining to be as practical and intelligent
110 // as possible with regard to constant propagation. Namely this involves forcing inlining
111 // for (void*) forms of ModRM, which (thanks to constprop) reduce to virtually no code, and
112 // force-disabling inlining on complicated SibSB forms [since MSVC would sometimes inline
113 // despite being a generally bad idea].
114 //
115 // In the case of (Reg, Imm) forms, the inlining is up to the discreation of the compiler.
116 //
117 // Note: I *intentionally* use __forceinline directly for most single-line class members,
118 // when needed. There's no point in using __emitline in these cases since the debugger
119 // can't trace into single-line functions anyway.
120 //
121 #ifdef PCSX2_DEVBUILD
122 # define __emitinline
123 #else
124 # define __emitinline __forceinline
125 #endif
126
127 // ModRM 'mod' field enumeration. Provided mostly for reference:
128 enum ModRm_ModField
129 {
130 Mod_NoDisp = 0, // effective address operation with no displacement, in the form of [reg] (or uses special Disp32-only encoding in the case of [ebp] form)
131 Mod_Disp8, // effective address operation with 8 bit displacement, in the form of [reg+disp8]
132 Mod_Disp32, // effective address operation with 32 bit displacement, in the form of [reg+disp32],
133 Mod_Direct, // direct reg/reg operation
134 };
135
136 // ----------------------------------------------------------------------------
137 // JccComparisonType - enumerated possibilities for inspired code branching!
138 //
139 enum JccComparisonType
140 {
141 Jcc_Unknown = -2,
142 Jcc_Unconditional = -1,
143 Jcc_Overflow = 0x0,
144 Jcc_NotOverflow = 0x1,
145 Jcc_Below = 0x2,
146 Jcc_Carry = 0x2,
147 Jcc_AboveOrEqual = 0x3,
148 Jcc_NotCarry = 0x3,
149 Jcc_Zero = 0x4,
150 Jcc_Equal = 0x4,
151 Jcc_NotZero = 0x5,
152 Jcc_NotEqual = 0x5,
153 Jcc_BelowOrEqual = 0x6,
154 Jcc_Above = 0x7,
155 Jcc_Signed = 0x8,
156 Jcc_Unsigned = 0x9,
157 Jcc_ParityEven = 0xa,
158 Jcc_ParityOdd = 0xb,
159 Jcc_Less = 0xc,
160 Jcc_GreaterOrEqual = 0xd,
161 Jcc_LessOrEqual = 0xe,
162 Jcc_Greater = 0xf,
163 };
164
165 // Not supported yet:
166 //E3 cb JECXZ rel8 Jump short if ECX register is 0.
167
168 // ----------------------------------------------------------------------------
169 // SSE2_ComparisonType - enumerated possibilities for SIMD data comparison!
170 //
171 enum SSE2_ComparisonType
172 {
173 SSE2_Equal = 0,
174 SSE2_Less,
175 SSE2_LessOrEqual,
176 SSE2_Unordered,
177 SSE2_NotEqual,
178 SSE2_NotLess,
179 SSE2_NotLessOrEqual,
180 SSE2_Ordered
181 };
182
183 static const int ModRm_UseSib = 4; // same index value as ESP (used in RM field)
184 static const int ModRm_UseDisp32 = 5; // same index value as EBP (used in Mod field)
185
186 class xAddressInfo;
187 class ModSibBase;
188
189 extern void xSetPtr( void* ptr );
190 extern void xAlignPtr( uint bytes );
191 extern void xAdvancePtr( uint bytes );
192 extern void xAlignCallTarget();
193
194 extern u8* xGetPtr();
195 extern u8* xGetAlignedCallTarget();
196
197 extern JccComparisonType xInvertCond( JccComparisonType src );
198
199 // --------------------------------------------------------------------------------------
200 // OperandSizedObject
201 // --------------------------------------------------------------------------------------
202 class OperandSizedObject
203 {
204 public:
205 virtual uint GetOperandSize() const=0;
206
207 bool Is8BitOp() const { return GetOperandSize() == 1; }
208 void prefix16() const { if( GetOperandSize() == 2 ) xWrite8( 0x66 ); }
209
210 void xWriteImm( int imm ) const
211 {
212 switch( GetOperandSize() )
213 {
214 case 1: xWrite8( imm ); break;
215 case 2: xWrite16( imm ); break;
216 case 4: xWrite32( imm ); break;
217 case 8: xWrite64( imm ); break;
218
219 jNO_DEFAULT
220 }
221 }
222 };
223
224 // Represents an unused or "empty" register assignment. If encountered by the emitter, this
225 // will be ignored (in some cases it is disallowed and generates an assertion)
226 static const int xRegId_Empty = -1;
227
228 // Represents an invalid or uninitialized register. If this is encountered by the emitter it
229 // will generate an assertion.
230 static const int xRegId_Invalid = -2;
231
232 // --------------------------------------------------------------------------------------
233 // xRegisterBase - type-unsafe x86 register representation.
234 // --------------------------------------------------------------------------------------
235 // Unless doing some fundamental stuff, use the friendly xRegister32/16/8 and xRegisterSSE/MMX
236 // instead, which are built using this class and provide strict register type safety when
237 // passed into emitter instructions.
238 //
239 class xRegisterBase : public OperandSizedObject
240 {
241 public:
242 int Id;
243
244 xRegisterBase()
245 {
246 Id = xRegId_Invalid;
247 }
248
249 explicit xRegisterBase( int regId )
250 {
251 Id = regId;
252 pxAssert( (Id >= xRegId_Empty) && (Id < 8) );
253 }
254
255 bool IsEmpty() const { return Id < 0 ; }
256 bool IsInvalid() const { return Id == xRegId_Invalid; }
257
258 // Returns true if the register is a valid accumulator: Eax, Ax, Al, XMM0.
259 bool IsAccumulator() const { return Id == 0; }
260
261 // returns true if the register is a valid MMX or XMM register.
262 bool IsSIMD() const { return GetOperandSize() == 8 || GetOperandSize() == 16; }
263
264 bool operator==( const xRegisterBase& src ) const { return (Id == src.Id); }
265 bool operator!=( const xRegisterBase& src ) const { return (Id != src.Id); }
266
267 // Diagnostics -- returns a string representation of this register. Return string
268 // is a valid non-null string for any Id, valid or invalid. No assertions are generated.
269 const char* GetName();
270 };
271
272 class xRegisterInt : public xRegisterBase
273 {
274 typedef xRegisterBase _parent;
275
276 public:
277 xRegisterInt() {}
278 explicit xRegisterInt( const xRegisterBase& src ) : _parent( src ) {}
279 explicit xRegisterInt( int regId ) : _parent( regId ) { }
280
281 bool IsSIMD() const { return false; }
282
283 bool operator==( const xRegisterInt& src ) const { return Id == src.Id && (GetOperandSize() == src.GetOperandSize()); }
284 bool operator!=( const xRegisterInt& src ) const { return !operator==(src); }
285 };
286
287 // --------------------------------------------------------------------------------------
288 // xRegister8/16/32 - Represents a basic 8/16/32 bit GPR on the x86
289 // --------------------------------------------------------------------------------------
290 class xRegister8 : public xRegisterInt
291 {
292 typedef xRegisterInt _parent;
293
294 public:
295 xRegister8(): _parent() {}
296 explicit xRegister8( int regId ) : _parent( regId ) {}
297
298 virtual uint GetOperandSize() const { return 1; }
299
300 bool operator==( const xRegister8& src ) const { return Id == src.Id; }
301 bool operator!=( const xRegister8& src ) const { return Id != src.Id; }
302 };
303
304 class xRegister16 : public xRegisterInt
305 {
306 typedef xRegisterInt _parent;
307
308 public:
309 xRegister16(): _parent() {}
310 explicit xRegister16( int regId ) : _parent( regId ) {}
311
312 virtual uint GetOperandSize() const { return 2; }
313
314 bool operator==( const xRegister16& src ) const { return this->Id == src.Id; }
315 bool operator!=( const xRegister16& src ) const { return this->Id != src.Id; }
316 };
317
318 class xRegister32 : public xRegisterInt
319 {
320 typedef xRegisterInt _parent;
321
322 public:
323 xRegister32(): _parent() {}
324 explicit xRegister32( int regId ) : _parent( regId ) {}
325
326 virtual uint GetOperandSize() const { return 4; }
327
328 bool operator==( const xRegister32& src ) const { return this->Id == src.Id; }
329 bool operator!=( const xRegister32& src ) const { return this->Id != src.Id; }
330 };
331
332 // --------------------------------------------------------------------------------------
333 // xRegisterMMX/SSE - Represents either a 64 bit or 128 bit SIMD register
334 // --------------------------------------------------------------------------------------
335 // This register type is provided to allow legal syntax for instructions that accept either
336 // an XMM or MMX register as a parameter, but do not allow for a GPR.
337
338 class xRegisterMMX : public xRegisterBase
339 {
340 typedef xRegisterBase _parent;
341
342 public:
343 xRegisterMMX(): _parent() {}
344 //xRegisterMMX( const xRegisterBase& src ) : _parent( src ) {}
345 explicit xRegisterMMX( int regId ) : _parent( regId ) {}
346
347 virtual uint GetOperandSize() const { return 8; }
348
349 bool operator==( const xRegisterMMX& src ) const { return this->Id == src.Id; }
350 bool operator!=( const xRegisterMMX& src ) const { return this->Id != src.Id; }
351 };
352
353 class xRegisterSSE : public xRegisterBase
354 {
355 typedef xRegisterBase _parent;
356
357 public:
358 xRegisterSSE(): _parent() {}
359 //xRegisterSSE( const xRegisterBase& src ) : _parent( src ) {}
360 explicit xRegisterSSE( int regId ) : _parent( regId ) {}
361
362 virtual uint GetOperandSize() const { return 16; }
363
364 bool operator==( const xRegisterSSE& src ) const { return this->Id == src.Id; }
365 bool operator!=( const xRegisterSSE& src ) const { return this->Id != src.Id; }
366
367 xRegisterSSE& operator++()
368 {
369 ++Id &= (iREGCNT_XMM-1);
370 return *this;
371 }
372
373 xRegisterSSE& operator--()
374 {
375 --Id &= (iREGCNT_XMM-1);
376 return *this;
377 }
378 };
379
380 class xRegisterCL : public xRegister8
381 {
382 public:
383 xRegisterCL(): xRegister8( 1 ) {}
384 };
385
386 // --------------------------------------------------------------------------------------
387 // xAddressReg
388 // --------------------------------------------------------------------------------------
389 // Use 32 bit registers as our index registers (for ModSib-style memory address calculations).
390 // This type is implicitly exchangeable with xRegister32.
391 //
392 // Only xAddressReg provides operators for constructing xAddressInfo types. These operators
393 // could have been added to xRegister32 directly instead, however I think this design makes
394 // more sense and allows the programmer a little more type protection if needed.
395 //
396 class xAddressReg : public xRegister32
397 {
398 public:
399 xAddressReg(): xRegister32() {}
400 xAddressReg( const xAddressReg& src ) : xRegister32( src.Id ) {}
401 xAddressReg( const xRegister32& src ) : xRegister32( src ) {}
402 explicit xAddressReg( int regId ) : xRegister32( regId ) {}
403
404 // Returns true if the register is the stack pointer: ESP.
405 bool IsStackPointer() const { return Id == 4; }
406
407 inline xAddressInfo operator+( const xAddressReg& right ) const;
408 inline xAddressInfo operator+( const xAddressInfo& right ) const;
409 inline xAddressInfo operator+( s32 right ) const;
410 inline xAddressInfo operator+( const void* right ) const;
411
412 inline xAddressInfo operator-( s32 right ) const;
413 inline xAddressInfo operator-( const void* right ) const;
414
415 inline xAddressInfo operator*( u32 factor ) const;
416 inline xAddressInfo operator<<( u32 shift ) const;
417
418 /*xAddressReg& operator=( const xRegister32& src )
419 {
420 Id = src.Id;
421 return *this;
422 }*/
423 };
424
425 // --------------------------------------------------------------------------------------
426 // xRegisterEmpty
427 // --------------------------------------------------------------------------------------
428 struct xRegisterEmpty
429 {
430 operator xRegister8() const
431 {
432 return xRegister8( xRegId_Empty );
433 }
434
435 operator xRegister16() const
436 {
437 return xRegister16( xRegId_Empty );
438 }
439
440 operator xRegisterMMX() const
441 {
442 return xRegisterMMX( xRegId_Empty );
443 }
444
445 operator xRegisterSSE() const
446 {
447 return xRegisterSSE( xRegId_Empty );
448 }
449
450 operator xAddressReg() const
451 {
452 return xAddressReg( xRegId_Empty );
453 }
454 };
455
456 class xRegister16or32
457 {
458 protected:
459 const xRegisterInt& m_convtype;
460
461 public:
462 xRegister16or32( const xRegister32& src ) : m_convtype( src ) {}
463 xRegister16or32( const xRegister16& src ) : m_convtype( src ) {}
464
465 operator const xRegisterBase&() const { return m_convtype; }
466
467 const xRegisterInt* operator->() const
468 {
469 return &m_convtype;
470 }
471 };
472
473 extern const xRegisterEmpty xEmptyReg;
474
475 // --------------------------------------------------------------------------------------
476 // xAddressInfo
477 // --------------------------------------------------------------------------------------
478 class xAddressInfo
479 {
480 public:
481 xAddressReg Base; // base register (no scale)
482 xAddressReg Index; // index reg gets multiplied by the scale
483 int Factor; // scale applied to the index register, in factor form (not a shift!)
484 s32 Displacement; // address displacement
485
486 public:
487 __forceinline xAddressInfo( const xAddressReg& base, const xAddressReg& index, int factor=1, s32 displacement=0 )
488 {
489 Base = base;
490 Index = index;
491 Factor = factor;
492 Displacement= displacement;
493
494 pxAssertMsg( base.Id != xRegId_Invalid, "Uninitialized x86 register." );
495 pxAssertMsg( index.Id != xRegId_Invalid, "Uninitialized x86 register." );
496 }
497
498 __forceinline explicit xAddressInfo( const xAddressReg& index, int displacement=0 )
499 {
500 Base = xEmptyReg;
501 Index = index;
502 Factor = 0;
503 Displacement= displacement;
504
505 pxAssertMsg( index.Id != xRegId_Invalid, "Uninitialized x86 register." );
506 }
507
508 __forceinline explicit xAddressInfo( s32 displacement=0 )
509 {
510 Base = xEmptyReg;
511 Index = xEmptyReg;
512 Factor = 0;
513 Displacement= displacement;
514 }
515
516 static xAddressInfo FromIndexReg( const xAddressReg& index, int scale=0, s32 displacement=0 );
517
518 public:
519 bool IsByteSizeDisp() const { return is_s8( Displacement ); }
520
521 __forceinline xAddressInfo& Add( s32 imm )
522 {
523 Displacement += imm;
524 return *this;
525 }
526
527 xAddressInfo& Add( const xAddressReg& src );
528 xAddressInfo& Add( const xAddressInfo& src );
529
530 __forceinline xAddressInfo operator+( const xAddressReg& right ) const { return xAddressInfo( *this ).Add( right ); }
531 __forceinline xAddressInfo operator+( const xAddressInfo& right ) const { return xAddressInfo( *this ).Add( right ); }
532 __forceinline xAddressInfo operator+( s32 imm ) const { return xAddressInfo( *this ).Add( imm ); }
533 __forceinline xAddressInfo operator-( s32 imm ) const { return xAddressInfo( *this ).Add( -imm ); }
534 __forceinline xAddressInfo operator+( const void* addr ) const { return xAddressInfo( *this ).Add( (uptr)addr ); }
535
536 __forceinline void operator+=( const xAddressReg& right ) { Add( right ); }
537 __forceinline void operator+=( const xAddressInfo& right ) { Add( right ); }
538 __forceinline void operator+=( s32 imm ) { Add( imm ); }
539 __forceinline void operator-=( s32 imm ) { Add( -imm ); }
540 };
541
542 extern const xRegisterSSE
543 xmm0, xmm1, xmm2, xmm3,
544 xmm4, xmm5, xmm6, xmm7;
545
546 extern const xRegisterMMX
547 mm0, mm1, mm2, mm3,
548 mm4, mm5, mm6, mm7;
549
550 extern const xAddressReg
551 eax, ebx, ecx, edx,
552 esi, edi, ebp, esp;
553
554 extern const xRegister16
555 ax, bx, cx, dx,
556 si, di, bp, sp;
557
558 extern const xRegister8
559 al, dl, bl,
560 ah, ch, dh, bh;
561
562 extern const xRegisterCL cl; // I'm special!
563
564 // --------------------------------------------------------------------------------------
565 // xImmReg< typename xRegType >
566 // --------------------------------------------------------------------------------------
567 // Used to represent an immediate value which can also be optimized to a register. Note
568 // that the immediate value represented by this structure is *always* legal. The register
569 // assignment is an optional optimization which can be implemented in cases where an
570 // immediate is used enough times to merit allocating it to a register.
571 //
572 // Note: not all instructions support this operand type (yet). You can always implement it
573 // manually by checking the status of IsReg() and generating the xOP conditionally.
574 //
575 template< typename xRegType >
576 class xImmReg
577 {
578 xRegType m_reg;
579 int m_imm;
580
581 public:
582 xImmReg() : m_reg()
583 {
584 m_imm = 0;
585 }
586
587 xImmReg( int imm, const xRegType& reg = xEmptyReg )
588 {
589 m_reg = reg;
590 m_imm = imm;
591 }
592
593 const xRegType& GetReg() const { return m_reg; }
594 int GetImm() const { return m_imm; }
595 bool IsReg() const { return !m_reg.IsEmpty(); }
596 };
597
598 // --------------------------------------------------------------------------------------
599 // ModSib - Internal low-level representation of the ModRM/SIB information.
600 // --------------------------------------------------------------------------------------
601 // This class serves two purposes: It houses 'reduced' ModRM/SIB info only, which means
602 // that the Base, Index, Scale, and Displacement values are all in the correct arrange-
603 // ments, and it serves as a type-safe layer between the xRegister's operators (which
604 // generate xAddressInfo types) and the emitter's ModSib instruction forms. Without this,
605 // the xRegister would pass as a ModSib type implicitly, and that would cause ambiguity
606 // on a number of instructions.
607 //
608 // End users should always use xAddressInfo instead.
609 //
610 class ModSibBase : public OperandSizedObject
611 {
612 public:
613 xAddressReg Base; // base register (no scale)
614 xAddressReg Index; // index reg gets multiplied by the scale
615 uint Scale; // scale applied to the index register, in scale/shift form
616 s32 Displacement; // offset applied to the Base/Index registers.
617
618 public:
619 explicit ModSibBase( const xAddressInfo& src )
620 {
621 Base = src.Base;
622 Index = src.Index;
623 Scale = src.Factor;
624 Displacement= src.Displacement;
625
626 Reduce();
627 }
628
629 ModSibBase( xAddressReg base, xAddressReg index, int scale=0, s32 displacement=0 )
630 {
631 Base = base;
632 Index = index;
633 Scale = scale;
634 Displacement= displacement;
635
636 Reduce();
637 }
638
639 explicit ModSibBase( s32 disp )
640 {
641 Base = xEmptyReg;
642 Index = xEmptyReg;
643 Scale = 0;
644 Displacement= disp;
645
646 // no reduction necessary :D
647 }
648
649 ModSibBase( const void* target )
650 {
651 Base = xEmptyReg;
652 Index = xEmptyReg;
653 Scale = 0;
654 Displacement= (s32)target;
655
656 // no reduction necessary :D
657 }
658
659 virtual uint GetOperandSize() const { pxFail( "Invalid operation on ModSibBase" ); return 0; }
660 bool IsByteSizeDisp() const { return is_s8( Displacement ); }
661
662 ModSibBase& Add( s32 imm )
663 {
664 Displacement += imm;
665 return *this;
666 }
667
668 __forceinline ModSibBase operator+( const s32 imm ) const { return ModSibBase( *this ).Add( imm ); }
669 __forceinline ModSibBase operator-( const s32 imm ) const { return ModSibBase( *this ).Add( -imm ); }
670
671 protected:
672 void Reduce();
673 };
674
675 // --------------------------------------------------------------------------------------
676 // ModSib32rrLass - base class 32, 16, and 8 bit operand types
677 // --------------------------------------------------------------------------------------
678 class ModSib32orLess : public ModSibBase
679 {
680 typedef ModSibBase _parent;
681
682 protected:
683 explicit ModSib32orLess( const xAddressInfo& src ) : _parent( src ) {}
684 explicit ModSib32orLess( s32 disp ) : _parent( disp ) {}
685 ModSib32orLess( const void* target ) : _parent( target ) {}
686 ModSib32orLess( xAddressReg base, xAddressReg index, int scale=0, s32 displacement=0 ) :
687 _parent( base, index, scale, displacement ) {}
688 };
689
690 // --------------------------------------------------------------------------------------
691 // ModSib8/16/32/64/128
692 // --------------------------------------------------------------------------------------
693 // Strictly-typed version of ModSibBase, which is used to apply operand size information
694 // to operations that do not involve an implicit operand size via register (such as
695 // imm,mem or mem,imm)
696 //
697 #define DECLARE_CLASS_ModSibBits( bits, baseClass ) \
698 class ModSib##bits : public baseClass \
699 { \
700 typedef baseClass _parent; \
701 public: \
702 explicit ModSib##bits( const xAddressInfo& src ) : _parent( src ) {} \
703 explicit ModSib##bits( s32 disp ) : _parent( disp ) {} \
704 ModSib##bits( const u##bits* target ) : _parent( target ) {} \
705 ModSib##bits( xAddressReg base, xAddressReg index, int scale=0, s32 displacement=0 ) : \
706 _parent( base, index, scale, displacement ) {} \
707 \
708 virtual uint GetOperandSize() const { return bits / 8; } \
709 \
710 __forceinline ModSib##bits& Add( s32 imm ) \
711 { \
712 Displacement += imm; \
713 return *this; \
714 } \
715 \
716 __forceinline ModSib##bits operator+( const s32 imm ) const { return ModSib##bits( *this ).Add( imm ); } \
717 __forceinline ModSib##bits operator-( const s32 imm ) const { return ModSib##bits( *this ).Add( -imm ); } \
718 \
719 bool operator==( const ModSib##bits& src ) const \
720 { \
721 return \
722 ( Base == src.Base ) && ( Index == src.Index ) && \
723 ( Scale == src.Scale ) && ( Displacement == src.Displacement ); \
724 } \
725 \
726 bool operator!=( const ModSib##bits& src ) const \
727 { \
728 return !operator==( src ); \
729 } \
730 }
731
732 DECLARE_CLASS_ModSibBits( 8, ModSib32orLess );
733 DECLARE_CLASS_ModSibBits( 16, ModSib32orLess );
734 DECLARE_CLASS_ModSibBits( 32, ModSib32orLess );
735 DECLARE_CLASS_ModSibBits( 64, ModSibBase );
736 DECLARE_CLASS_ModSibBits( 128, ModSibBase );
737
738 // --------------------------------------------------------------------------------------
739 // xAddressIndexer
740 // --------------------------------------------------------------------------------------
741 // This is a type-translation "interface class" which provisions our ptr[] syntax.
742 // xAddressReg types go in, and ModSibBase derived types come out.
743 //
744 template< typename xModSibType >
745 struct xAddressIndexer
746 {
747 // passthrough instruction, allows ModSib to pass silently through ptr translation
748 // without doing anything and without compiler error.
749 const xModSibType& operator[]( const xModSibType& src ) const { return src; }
750
751 xModSibType operator[]( xAddressReg src ) const
752 {
753 return xModSibType( src, xEmptyReg );
754 }
755
756 xModSibType operator[]( const xAddressInfo& src ) const
757 {
758 return xModSibType( src );
759 }
760
761 xModSibType operator[]( uptr src ) const
762 {
763 return xModSibType( src );
764 }
765
766 xModSibType operator[]( const void* src ) const
767 {
768 return xModSibType( (uptr)src );
769 }
770 };
771
772 // ptr[] - use this form for instructions which can resolve the address operand size from
773 // the other register operand sizes.
774 extern const xAddressIndexer<ModSibBase> ptr;
775 extern const xAddressIndexer<ModSib128> ptr128;
776 extern const xAddressIndexer<ModSib64> ptr64;
777 extern const xAddressIndexer<ModSib32> ptr32;
778 extern const xAddressIndexer<ModSib16> ptr16;
779 extern const xAddressIndexer<ModSib8> ptr8;
780
781 // --------------------------------------------------------------------------------------
782 // xDirectOrIndirect
783 // --------------------------------------------------------------------------------------
784 // This utility class can represent either a direct (register) or indirect (memory address)
785 // source or destination operand. When supplied to an emitted instruction, the direct form
786 // is favored *if* it is not Empty (xEmptyReg). Otherwise the indirect form is used.
787 //
788 #if 0
789 template< typename xRegType, typename xSibType >
790 class xDirectOrIndirect
791 {
792 xRegType m_RegDirect;
793 xSibType m_MemIndirect;
794
795 public:
796 xDirectOrIndirect() :
797 m_RegDirect(), m_MemIndirect( 0 ) {}
798
799 xDirectOrIndirect( const xRegType& srcreg ) :
800 m_RegDirect( srcreg ), m_MemIndirect( 0 ) {}
801
802 explicit xDirectOrIndirect( const xSibType& srcmem ) :
803 m_RegDirect(), m_MemIndirect( srcmem ) {}
804
805 const xRegType& GetReg() const { return m_RegDirect; }
806 const xSibType& GetMem() const { return m_MemIndirect; }
807 bool IsDirect() const { return !m_RegDirect.IsEmpty(); }
808 bool IsIndirect() const { return m_RegDirect.IsEmpty(); }
809
810 bool operator==( const xDirectOrIndirect& src ) const
811 {
812 return IsDirect() ?
813 (m_RegDirect == src.m_RegDirect) :
814 (m_MemIndirect == src.m_MemIndirect);
815 }
816
817 bool operator!=( const xDirectOrIndirect& src ) const
818 {
819 return !operator==( src );
820 }
821
822 bool operator==( const xRegType& src ) const { return (m_RegDirect == src); }
823 bool operator!=( const xRegType& src ) const { return (m_RegDirect != src); }
824 };
825
826 typedef xDirectOrIndirect<xRegister8,ModSib8> xDirectOrIndirect8;
827 typedef xDirectOrIndirect<xRegister16,ModSib16> xDirectOrIndirect16;
828 typedef xDirectOrIndirect<xRegister32,ModSib32> xDirectOrIndirect32;
829 typedef xDirectOrIndirect<xRegisterMMX,ModSib64> xDirectOrIndirect64;
830 typedef xDirectOrIndirect<xRegisterSSE,ModSib128> xDirectOrIndirect128;
831 #endif
832
833 // --------------------------------------------------------------------------------------
834 // xSmartJump
835 // --------------------------------------------------------------------------------------
836 // This class provides an interface for generating forward-based j8's or j32's "smartly"
837 // as per the measured displacement distance. If the displacement is a valid s8, then
838 // a j8 is inserted, else a j32.
839 //
840 // Note: This class is inherently unsafe, and so it's recommended to use xForwardJump8/32
841 // whenever it is known that the jump destination is (or is not) short. Only use
842 // xSmartJump in cases where it's unknown what jump encoding will be ideal.
843 //
844 // Important: Use this tool with caution! xSmartJump cannot be used in cases where jump
845 // targets overlap, since the writeback of the second target will alter the position of
846 // the first target (which breaks the relative addressing). To assist in avoiding such
847 // errors, xSmartJump works based on C++ block scope, where the destruction of the
848 // xSmartJump object (invoked by a '}') signals the target of the jump. Example:
849 //
850 // {
851 // iCMP( EAX, ECX );
852 // xSmartJump jumpTo( Jcc_Above );
853 // [... conditional code ...]
854 // } // smartjump targets this spot.
855 //
856 // No code inside the scope can attempt to jump outside the scoped block (unless the jump
857 // uses an immediate addressing method, such as Register or Mod/RM forms of JMP/CALL).
858 // Multiple SmartJumps can be safely nested inside scopes, as long as they are properly
859 // scoped themselves.
860 //
861 // Performance Analysis: j8's use 4 less byes per opcode, and thus can provide minor
862 // speed benefits in the form of L1/L2 cache clutter, on any CPU. They're also notably
863 // faster on P4's, and mildly faster on AMDs. (Core2's and i7's don't care)
864 //
865 class xSmartJump
866 {
867 DeclareNoncopyableObject(xSmartJump);
868
869 protected:
870 u8* m_baseptr; // base address of the instruction (passed to the instruction emitter)
871 JccComparisonType m_cc; // comparison type of the instruction
872
873 public:
874 int GetMaxInstructionSize() const
875 {
876 pxAssert( m_cc != Jcc_Unknown );
877 return ( m_cc == Jcc_Unconditional ) ? 5 : 6;
878 }
879
880 JccComparisonType GetCondition() const { return m_cc; }
881 virtual ~xSmartJump();
882
883 // ------------------------------------------------------------------------
884 // ccType - Comparison type to be written back to the jump instruction position.
885 //
886 xSmartJump( JccComparisonType ccType )
887 {
888 pxAssert( ccType != Jcc_Unknown );
889 m_baseptr = xGetPtr();
890 m_cc = ccType;
891 xAdvancePtr( GetMaxInstructionSize() );
892 }
893
894 protected:
895 void SetTarget();
896 };
897
898 // --------------------------------------------------------------------------------------
899 // xForwardJump
900 // --------------------------------------------------------------------------------------
901 // Primary use of this class is through the various xForwardJA8/xForwardJLE32/etc. helpers
902 // defined later in this header. :)
903 //
904
905 class xForwardJumpBase
906 {
907 public:
908 // pointer to base of the instruction *Following* the jump. The jump address will be
909 // relative to this address.
910 s8* BasePtr;
911
912 public:
913 xForwardJumpBase( uint opsize, JccComparisonType cctype );
914
915 protected:
916 void _setTarget( uint opsize ) const;
917 };
918
919 template< typename OperandType >
920 class xForwardJump : public xForwardJumpBase
921 {
922 public:
923 static const uint OperandSize = sizeof( OperandType );
924
925 // The jump instruction is emitted at the point of object construction. The conditional
926 // type must be valid (Jcc_Unknown generates an assertion).
927 xForwardJump( JccComparisonType cctype = Jcc_Unconditional ) : xForwardJumpBase( OperandSize, cctype ) { }
928
929 // Sets the jump target by writing back the current x86Ptr to the jump instruction.
930 // This method can be called multiple times, re-writing the jump instruction's target
931 // in each case. (the the last call is the one that takes effect).
932 void SetTarget() const
933 {
934 _setTarget( OperandSize );
935 }
936 };
937
938 static __forceinline xAddressInfo operator+( const void* addr, const xAddressReg& reg )
939 {
940 return xAddressInfo( reg, (sptr)addr );
941 }
942
943 static __forceinline xAddressInfo operator+( const void* addr, const xAddressInfo& reg )
944 {
945 return xAddressInfo( (sptr)addr ).Add( reg );
946 }
947
948 static __forceinline xAddressInfo operator+( s32 addr, const xAddressReg& reg )
949 {
950 return xAddressInfo( reg, (sptr)addr );
951 }
952
953 static __forceinline xAddressInfo operator+( s32 addr, const xAddressInfo& reg )
954 {
955 return xAddressInfo( (sptr)addr ).Add( reg );
956 }
957 }
958
959 #include "implement/helpers.h"
960
961 #include "implement/simd_helpers.h"
962 #include "implement/simd_moremovs.h"
963 #include "implement/simd_arithmetic.h"
964 #include "implement/simd_comparisons.h"
965 #include "implement/simd_shufflepack.h"
966
967 #include "implement/group1.h"
968 #include "implement/group2.h"
969 #include "implement/group3.h"
970 #include "implement/movs.h" // cmov and movsx/zx
971 #include "implement/dwshift.h" // doubleword shifts!
972 #include "implement/incdec.h"
973 #include "implement/test.h"
974 #include "implement/jmpcall.h"
975
976 #include "inlines.inl"

  ViewVC Help
Powered by ViewVC 1.1.22