/[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 62 - (show annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (10 years, 1 month ago) by william
File MIME type: text/plain
File size: 34107 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
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 uint iREGCNT_XMM = 8;
20 static const uint iREGCNT_GPR = 8;
21 static const uint 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 __fi 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 __fi 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 __fi
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 extern void xSetPtr( void* ptr );
187 extern void xAlignPtr( uint bytes );
188 extern void xAdvancePtr( uint bytes );
189 extern void xAlignCallTarget();
190
191 extern u8* xGetPtr();
192 extern u8* xGetAlignedCallTarget();
193
194 extern JccComparisonType xInvertCond( JccComparisonType src );
195
196 class xAddressVoid;
197
198 // --------------------------------------------------------------------------------------
199 // OperandSizedObject
200 // --------------------------------------------------------------------------------------
201 class OperandSizedObject
202 {
203 public:
204 virtual uint GetOperandSize() const=0;
205
206 bool Is8BitOp() const { return GetOperandSize() == 1; }
207 void prefix16() const { if( GetOperandSize() == 2 ) xWrite8( 0x66 ); }
208
209 void xWriteImm( int imm ) const
210 {
211 switch( GetOperandSize() )
212 {
213 case 1: xWrite8( imm ); break;
214 case 2: xWrite16( imm ); break;
215 case 4: xWrite32( imm ); break;
216 case 8: xWrite64( imm ); break;
217
218 jNO_DEFAULT
219 }
220 }
221 };
222
223 // Represents an unused or "empty" register assignment. If encountered by the emitter, this
224 // will be ignored (in some cases it is disallowed and generates an assertion)
225 static const int xRegId_Empty = -1;
226
227 // Represents an invalid or uninitialized register. If this is encountered by the emitter it
228 // will generate an assertion.
229 static const int xRegId_Invalid = -2;
230
231 // --------------------------------------------------------------------------------------
232 // xRegisterBase - type-unsafe x86 register representation.
233 // --------------------------------------------------------------------------------------
234 // Unless doing some fundamental stuff, use the friendly xRegister32/16/8 and xRegisterSSE/MMX
235 // instead, which are built using this class and provide strict register type safety when
236 // passed into emitter instructions.
237 //
238 class xRegisterBase : public OperandSizedObject
239 {
240 public:
241 int Id;
242
243 xRegisterBase()
244 {
245 Id = xRegId_Invalid;
246 }
247
248 explicit xRegisterBase( int regId )
249 {
250 Id = regId;
251 pxAssert( (Id >= xRegId_Empty) && (Id < 8) );
252 }
253
254 bool IsEmpty() const { return Id < 0 ; }
255 bool IsInvalid() const { return Id == xRegId_Invalid; }
256
257 // Returns true if the register is a valid accumulator: Eax, Ax, Al, XMM0.
258 bool IsAccumulator() const { return Id == 0; }
259
260 // returns true if the register is a valid MMX or XMM register.
261 bool IsSIMD() const { return GetOperandSize() == 8 || GetOperandSize() == 16; }
262
263 bool operator==( const xRegisterBase& src ) const { return (Id == src.Id); }
264 bool operator!=( const xRegisterBase& src ) const { return (Id != src.Id); }
265
266 // Diagnostics -- returns a string representation of this register. Return string
267 // is a valid non-null string for any Id, valid or invalid. No assertions are generated.
268 const char* GetName();
269 };
270
271 class xRegisterInt : public xRegisterBase
272 {
273 typedef xRegisterBase _parent;
274
275 public:
276 xRegisterInt() {}
277 explicit xRegisterInt( const xRegisterBase& src ) : _parent( src ) {}
278 explicit xRegisterInt( int regId ) : _parent( regId ) { }
279
280 bool IsSIMD() const { return false; }
281
282 bool operator==( const xRegisterInt& src ) const { return Id == src.Id && (GetOperandSize() == src.GetOperandSize()); }
283 bool operator!=( const xRegisterInt& src ) const { return !operator==(src); }
284 };
285
286 // --------------------------------------------------------------------------------------
287 // xRegister8/16/32 - Represents a basic 8/16/32 bit GPR on the x86
288 // --------------------------------------------------------------------------------------
289 class xRegister8 : public xRegisterInt
290 {
291 typedef xRegisterInt _parent;
292
293 public:
294 xRegister8(): _parent() {}
295 explicit xRegister8( int regId ) : _parent( regId ) {}
296
297 virtual uint GetOperandSize() const { return 1; }
298
299 bool operator==( const xRegister8& src ) const { return Id == src.Id; }
300 bool operator!=( const xRegister8& src ) const { return Id != src.Id; }
301 };
302
303 class xRegister16 : public xRegisterInt
304 {
305 typedef xRegisterInt _parent;
306
307 public:
308 xRegister16(): _parent() {}
309 explicit xRegister16( int regId ) : _parent( regId ) {}
310
311 virtual uint GetOperandSize() const { return 2; }
312
313 bool operator==( const xRegister16& src ) const { return this->Id == src.Id; }
314 bool operator!=( const xRegister16& src ) const { return this->Id != src.Id; }
315 };
316
317 class xRegister32 : public xRegisterInt
318 {
319 typedef xRegisterInt _parent;
320
321 public:
322 xRegister32(): _parent() {}
323 explicit xRegister32( int regId ) : _parent( regId ) {}
324
325 virtual uint GetOperandSize() const { return 4; }
326
327 bool operator==( const xRegister32& src ) const { return this->Id == src.Id; }
328 bool operator!=( const xRegister32& src ) const { return this->Id != src.Id; }
329 };
330
331 // --------------------------------------------------------------------------------------
332 // xRegisterMMX/SSE - Represents either a 64 bit or 128 bit SIMD register
333 // --------------------------------------------------------------------------------------
334 // This register type is provided to allow legal syntax for instructions that accept either
335 // an XMM or MMX register as a parameter, but do not allow for a GPR.
336
337 class xRegisterMMX : public xRegisterBase
338 {
339 typedef xRegisterBase _parent;
340
341 public:
342 xRegisterMMX(): _parent() {}
343 //xRegisterMMX( const xRegisterBase& src ) : _parent( src ) {}
344 explicit xRegisterMMX( int regId ) : _parent( regId ) {}
345
346 virtual uint GetOperandSize() const { return 8; }
347
348 bool operator==( const xRegisterMMX& src ) const { return this->Id == src.Id; }
349 bool operator!=( const xRegisterMMX& src ) const { return this->Id != src.Id; }
350 };
351
352 class xRegisterSSE : public xRegisterBase
353 {
354 typedef xRegisterBase _parent;
355
356 public:
357 xRegisterSSE(): _parent() {}
358 explicit xRegisterSSE( int regId ) : _parent( regId ) {}
359
360 virtual uint GetOperandSize() const { return 16; }
361
362 bool operator==( const xRegisterSSE& src ) const { return this->Id == src.Id; }
363 bool operator!=( const xRegisterSSE& src ) const { return this->Id != src.Id; }
364
365 xRegisterSSE& operator++()
366 {
367 ++Id &= (iREGCNT_XMM-1);
368 return *this;
369 }
370
371 xRegisterSSE& operator--()
372 {
373 --Id &= (iREGCNT_XMM-1);
374 return *this;
375 }
376
377 static const inline xRegisterSSE& GetInstance(uint id);
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 xAddressVoid operator+( const xAddressReg& right ) const;
408 xAddressVoid operator+( s32 right ) const;
409 xAddressVoid operator+( const void* right ) const;
410 xAddressVoid operator-( s32 right ) const;
411 xAddressVoid operator-( const void* right ) const;
412 xAddressVoid operator*( u32 factor ) const;
413 xAddressVoid operator<<( u32 shift ) const;
414
415 /*xAddressReg& operator=( const xRegister32& src )
416 {
417 Id = src.Id;
418 return *this;
419 }*/
420 };
421
422 // --------------------------------------------------------------------------------------
423 // xRegisterEmpty
424 // --------------------------------------------------------------------------------------
425 struct xRegisterEmpty
426 {
427 operator xRegister8() const
428 {
429 return xRegister8( xRegId_Empty );
430 }
431
432 operator xRegister16() const
433 {
434 return xRegister16( xRegId_Empty );
435 }
436
437 operator xRegisterMMX() const
438 {
439 return xRegisterMMX( xRegId_Empty );
440 }
441
442 operator xRegisterSSE() const
443 {
444 return xRegisterSSE( xRegId_Empty );
445 }
446
447 operator xAddressReg() const
448 {
449 return xAddressReg( xRegId_Empty );
450 }
451 };
452
453 class xRegister16or32
454 {
455 protected:
456 const xRegisterInt& m_convtype;
457
458 public:
459 xRegister16or32( const xRegister32& src ) : m_convtype( src ) {}
460 xRegister16or32( const xRegister16& src ) : m_convtype( src ) {}
461
462 operator const xRegisterBase&() const { return m_convtype; }
463
464 const xRegisterInt* operator->() const
465 {
466 return &m_convtype;
467 }
468 };
469
470 extern const xRegisterEmpty xEmptyReg;
471
472 extern const xRegisterSSE
473 xmm0, xmm1, xmm2, xmm3,
474 xmm4, xmm5, xmm6, xmm7;
475
476 extern const xRegisterMMX
477 mm0, mm1, mm2, mm3,
478 mm4, mm5, mm6, mm7;
479
480 extern const xAddressReg
481 eax, ebx, ecx, edx,
482 esi, edi, ebp, esp;
483
484 extern const xRegister16
485 ax, bx, cx, dx,
486 si, di, bp, sp;
487
488 extern const xRegister8
489 al, dl, bl,
490 ah, ch, dh, bh;
491
492 extern const xRegisterCL cl; // I'm special!
493
494 const xRegisterSSE& xRegisterSSE::GetInstance(uint id)
495 {
496 static const xRegisterSSE *const m_tbl_xmmRegs[iREGCNT_XMM] =
497 {
498 &xmm0, &xmm1,
499 &xmm2, &xmm3,
500 &xmm4, &xmm5,
501 &xmm6, &xmm7
502 };
503
504 pxAssume(id < iREGCNT_XMM);
505 return *m_tbl_xmmRegs[id];
506 }
507
508 // --------------------------------------------------------------------------------------
509 // xAddressVoid
510 // --------------------------------------------------------------------------------------
511 class xAddressVoid
512 {
513 public:
514 xAddressReg Base; // base register (no scale)
515 xAddressReg Index; // index reg gets multiplied by the scale
516 int Factor; // scale applied to the index register, in factor form (not a shift!)
517 s32 Displacement; // address displacement
518
519 public:
520 xAddressVoid( const xAddressReg& base, const xAddressReg& index, int factor=1, s32 displacement=0 );
521
522 xAddressVoid( const xAddressReg& index, int displacement=0 );
523 explicit xAddressVoid( const void* displacement );
524 explicit xAddressVoid( s32 displacement=0 );
525
526 public:
527 bool IsByteSizeDisp() const { return is_s8( Displacement ); }
528
529 xAddressVoid& Add( s32 imm )
530 {
531 Displacement += imm;
532 return *this;
533 }
534
535 xAddressVoid& Add( const xAddressReg& src );
536 xAddressVoid& Add( const xAddressVoid& src );
537
538 __fi xAddressVoid operator+( const xAddressReg& right ) const { return xAddressVoid( *this ).Add( right ); }
539 __fi xAddressVoid operator+( const xAddressVoid& right ) const { return xAddressVoid( *this ).Add( right ); }
540 __fi xAddressVoid operator+( s32 imm ) const { return xAddressVoid( *this ).Add( imm ); }
541 __fi xAddressVoid operator-( s32 imm ) const { return xAddressVoid( *this ).Add( -imm ); }
542 __fi xAddressVoid operator+( const void* addr ) const { return xAddressVoid( *this ).Add( (uptr)addr ); }
543
544 __fi void operator+=( const xAddressReg& right ) { Add( right ); }
545 __fi void operator+=( s32 imm ) { Add( imm ); }
546 __fi void operator-=( s32 imm ) { Add( -imm ); }
547 };
548
549 // --------------------------------------------------------------------------------------
550 // xAddressInfo
551 // --------------------------------------------------------------------------------------
552 template< typename BaseType >
553 class xAddressInfo : public xAddressVoid
554 {
555 typedef xAddressVoid _parent;
556
557 public:
558 xAddressInfo( const xAddressReg& base, const xAddressReg& index, int factor=1, s32 displacement=0 )
559 : _parent( base, index, factor, displacement ) {}
560
561 /*xAddressInfo( const xAddressVoid& src )
562 : _parent( src ) {}*/
563
564 explicit xAddressInfo( const xAddressReg& index, int displacement=0 )
565 : _parent( index, displacement ) {}
566
567 explicit xAddressInfo( s32 displacement=0 )
568 : _parent( displacement ) {}
569
570 static xAddressInfo<BaseType> FromIndexReg( const xAddressReg& index, int scale=0, s32 displacement=0 );
571
572 public:
573 using _parent::operator+=;
574 using _parent::operator-=;
575
576 bool IsByteSizeDisp() const { return is_s8( Displacement ); }
577
578 xAddressInfo<BaseType>& Add( s32 imm )
579 {
580 Displacement += imm;
581 return *this;
582 }
583
584 xAddressInfo<BaseType>& Add( const xAddressReg& src ) { _parent::Add(src); return *this; }
585 xAddressInfo<BaseType>& Add( const xAddressInfo<BaseType>& src ) { _parent::Add(src); return *this; }
586
587 __fi xAddressInfo<BaseType> operator+( const xAddressReg& right ) const { return xAddressInfo( *this ).Add( right ); }
588 __fi xAddressInfo<BaseType> operator+( const xAddressInfo<BaseType>& right ) const { return xAddressInfo( *this ).Add( right ); }
589 __fi xAddressInfo<BaseType> operator+( s32 imm ) const { return xAddressInfo( *this ).Add( imm ); }
590 __fi xAddressInfo<BaseType> operator-( s32 imm ) const { return xAddressInfo( *this ).Add( -imm ); }
591 __fi xAddressInfo<BaseType> operator+( const void* addr ) const { return xAddressInfo( *this ).Add( (uptr)addr ); }
592
593 __fi void operator+=( const xAddressInfo<BaseType>& right ) { Add( right ); }
594 };
595
596 typedef xAddressInfo<u128> xAddress128;
597 typedef xAddressInfo<u64> xAddress64;
598 typedef xAddressInfo<u32> xAddress32;
599 typedef xAddressInfo<u16> xAddress16;
600 typedef xAddressInfo<u8> xAddress8;
601
602 static __fi xAddressVoid operator+( const void* addr, const xAddressVoid& right )
603 {
604 return right + addr;
605 }
606
607 static __fi xAddressVoid operator+( s32 addr, const xAddressVoid& right )
608 {
609 return right + addr;
610 }
611
612 template< typename OperandType >
613 static __fi xAddressInfo<OperandType> operator+( const void* addr, const xAddressInfo<OperandType>& right )
614 {
615 //return xAddressInfo<OperandType>( (sptr)addr ).Add( reg );
616 return right + addr;
617 }
618
619 template< typename OperandType >
620 static __fi xAddressInfo<OperandType> operator+( s32 addr, const xAddressInfo<OperandType>& right )
621 {
622 return right + addr;
623 }
624
625 // --------------------------------------------------------------------------------------
626 // xImmReg< typename xRegType >
627 // --------------------------------------------------------------------------------------
628 // Used to represent an immediate value which can also be optimized to a register. Note
629 // that the immediate value represented by this structure is *always* legal. The register
630 // assignment is an optional optimization which can be implemented in cases where an
631 // immediate is used enough times to merit allocating it to a register.
632 //
633 // Note: not all instructions support this operand type (yet). You can always implement it
634 // manually by checking the status of IsReg() and generating the xOP conditionally.
635 //
636 template< typename xRegType >
637 class xImmReg
638 {
639 xRegType m_reg;
640 int m_imm;
641
642 public:
643 xImmReg() : m_reg()
644 {
645 m_imm = 0;
646 }
647
648 xImmReg( int imm, const xRegType& reg = xEmptyReg )
649 {
650 m_reg = reg;
651 m_imm = imm;
652 }
653
654 const xRegType& GetReg() const { return m_reg; }
655 int GetImm() const { return m_imm; }
656 bool IsReg() const { return !m_reg.IsEmpty(); }
657 };
658
659 // --------------------------------------------------------------------------------------
660 // xIndirectVoid - Internal low-level representation of the ModRM/SIB information.
661 // --------------------------------------------------------------------------------------
662 // This class serves two purposes: It houses 'reduced' ModRM/SIB info only, which means
663 // that the Base, Index, Scale, and Displacement values are all in the correct arrange-
664 // ments, and it serves as a type-safe layer between the xRegister's operators (which
665 // generate xAddressInfo types) and the emitter's ModSib instruction forms. Without this,
666 // the xRegister would pass as a ModSib type implicitly, and that would cause ambiguity
667 // on a number of instructions.
668 //
669 // End users should always use xAddressInfo instead.
670 //
671 class xIndirectVoid : public OperandSizedObject
672 {
673 public:
674 xAddressReg Base; // base register (no scale)
675 xAddressReg Index; // index reg gets multiplied by the scale
676 uint Scale; // scale applied to the index register, in scale/shift form
677 s32 Displacement; // offset applied to the Base/Index registers.
678
679 public:
680 explicit xIndirectVoid( s32 disp );
681 explicit xIndirectVoid( const xAddressVoid& src );
682 xIndirectVoid( xAddressReg base, xAddressReg index, int scale=0, s32 displacement=0 );
683
684 virtual uint GetOperandSize() const;
685 xIndirectVoid& Add( s32 imm );
686
687 bool IsByteSizeDisp() const { return is_s8( Displacement ); }
688
689 operator xAddressVoid()
690 {
691 return xAddressVoid( Base, Index, Scale, Displacement );
692 }
693
694 __fi xIndirectVoid operator+( const s32 imm ) const { return xIndirectVoid( *this ).Add( imm ); }
695 __fi xIndirectVoid operator-( const s32 imm ) const { return xIndirectVoid( *this ).Add( -imm ); }
696
697 protected:
698 void Reduce();
699 };
700
701 template< typename OperandType >
702 class xIndirect : public xIndirectVoid
703 {
704 typedef xIndirectVoid _parent;
705
706 public:
707 explicit xIndirect( s32 disp ) : _parent( disp ) {}
708 explicit xIndirect( const xAddressInfo<OperandType>& src ) : _parent( src ) {}
709 xIndirect( xAddressReg base, xAddressReg index, int scale=0, s32 displacement=0 )
710 : _parent( base, index, scale, displacement ) {}
711
712 virtual uint GetOperandSize() const { return sizeof(OperandType); }
713
714 xIndirect<OperandType>& Add( s32 imm )
715 {
716 Displacement += imm;
717 return *this;
718 }
719
720 __fi xIndirect<OperandType> operator+( const s32 imm ) const { return xIndirect( *this ).Add( imm ); }
721 __fi xIndirect<OperandType> operator-( const s32 imm ) const { return xIndirect( *this ).Add( -imm ); }
722
723 bool operator==( const xIndirect<OperandType>& src ) const
724 {
725 return
726 ( Base == src.Base ) && ( Index == src.Index ) &&
727 ( Scale == src.Scale ) && ( Displacement == src.Displacement );
728 }
729
730 bool operator!=( const xIndirect<OperandType>& src ) const
731 {
732 return !operator==( src );
733 }
734
735 protected:
736 void Reduce();
737 };
738
739 typedef xIndirect<u128> xIndirect128;
740 typedef xIndirect<u64> xIndirect64;
741 typedef xIndirect<u32> xIndirect32;
742 typedef xIndirect<u16> xIndirect16;
743 typedef xIndirect<u8> xIndirect8;
744
745 // --------------------------------------------------------------------------------------
746 // xIndirect32orLass - base class 32, 16, and 8 bit operand types
747 // --------------------------------------------------------------------------------------
748 class xIndirect32orLess : public xIndirectVoid
749 {
750 typedef xIndirectVoid _parent;
751
752 protected:
753 uint m_OpSize;
754
755 public:
756 xIndirect32orLess( const xIndirect8& src ) : _parent( src ) { m_OpSize = src.GetOperandSize(); }
757 xIndirect32orLess( const xIndirect16& src ) : _parent( src ) { m_OpSize = src.GetOperandSize(); }
758 xIndirect32orLess( const xIndirect32& src ) : _parent( src ) { m_OpSize = src.GetOperandSize(); }
759
760 uint GetOperandSize() const { return m_OpSize; }
761
762 protected:
763 //xIndirect32orLess( const xAddressVoid& src ) : _parent( src ) {}
764
765 explicit xIndirect32orLess( s32 disp ) : _parent( disp ) {}
766 xIndirect32orLess( xAddressReg base, xAddressReg index, int scale=0, s32 displacement=0 ) :
767 _parent( base, index, scale, displacement ) {}
768 };
769
770 // --------------------------------------------------------------------------------------
771 // xAddressIndexer
772 // --------------------------------------------------------------------------------------
773 // This is a type-translation "interface class" which provisions our ptr[] syntax.
774 // xAddressReg types go in, and xIndirectVoid derived types come out.
775 //
776 template< typename xModSibType >
777 class xAddressIndexer
778 {
779 public:
780 // passthrough instruction, allows ModSib to pass silently through ptr translation
781 // without doing anything and without compiler error.
782 const xModSibType& operator[]( const xModSibType& src ) const { return src; }
783
784 xModSibType operator[]( const xAddressReg& src ) const
785 {
786 return xModSibType( src, xEmptyReg );
787 }
788
789 xModSibType operator[]( const xAddressVoid& src ) const
790 {
791 return xModSibType( src.Base, src.Index, src.Factor, src.Displacement );
792 }
793
794 xModSibType operator[]( const void* src ) const
795 {
796 return xModSibType( (uptr)src );
797 }
798 };
799
800 // ptr[] - use this form for instructions which can resolve the address operand size from
801 // the other register operand sizes.
802 extern const xAddressIndexer<xIndirectVoid> ptr;
803 extern const xAddressIndexer<xIndirect128> ptr128;
804 extern const xAddressIndexer<xIndirect64> ptr64;
805 extern const xAddressIndexer<xIndirect32> ptr32;
806 extern const xAddressIndexer<xIndirect16> ptr16;
807 extern const xAddressIndexer<xIndirect8> ptr8;
808
809 // --------------------------------------------------------------------------------------
810 // xDirectOrIndirect
811 // --------------------------------------------------------------------------------------
812 // This utility class can represent either a direct (register) or indirect (memory address)
813 // source or destination operand. When supplied to an emitted instruction, the direct form
814 // is favored *if* it is not Empty (xEmptyReg). Otherwise the indirect form is used.
815 //
816 #if 0
817 template< typename xRegType, typename xSibType >
818 class xDirectOrIndirect
819 {
820 xRegType m_RegDirect;
821 xSibType m_MemIndirect;
822
823 public:
824 xDirectOrIndirect() :
825 m_RegDirect(), m_MemIndirect( 0 ) {}
826
827 xDirectOrIndirect( const xRegType& srcreg ) :
828 m_RegDirect( srcreg ), m_MemIndirect( 0 ) {}
829
830 explicit xDirectOrIndirect( const xSibType& srcmem ) :
831 m_RegDirect(), m_MemIndirect( srcmem ) {}
832
833 const xRegType& GetReg() const { return m_RegDirect; }
834 const xSibType& GetMem() const { return m_MemIndirect; }
835 bool IsDirect() const { return !m_RegDirect.IsEmpty(); }
836 bool IsIndirect() const { return m_RegDirect.IsEmpty(); }
837
838 bool operator==( const xDirectOrIndirect& src ) const
839 {
840 return IsDirect() ?
841 (m_RegDirect == src.m_RegDirect) :
842 (m_MemIndirect == src.m_MemIndirect);
843 }
844
845 bool operator!=( const xDirectOrIndirect& src ) const
846 {
847 return !operator==( src );
848 }
849
850 bool operator==( const xRegType& src ) const { return (m_RegDirect == src); }
851 bool operator!=( const xRegType& src ) const { return (m_RegDirect != src); }
852 };
853
854 typedef xDirectOrIndirect<xRegister8,xIndirect8> xDirectOrIndirect8;
855 typedef xDirectOrIndirect<xRegister16,xIndirect16> xDirectOrIndirect16;
856 typedef xDirectOrIndirect<xRegister32,xIndirect32> xDirectOrIndirect32;
857 typedef xDirectOrIndirect<xRegisterMMX,xIndirect64> xDirectOrIndirect64;
858 typedef xDirectOrIndirect<xRegisterSSE,xIndirect128> xDirectOrIndirect128;
859 #endif
860
861 // --------------------------------------------------------------------------------------
862 // xSmartJump
863 // --------------------------------------------------------------------------------------
864 // This class provides an interface for generating forward-based j8's or j32's "smartly"
865 // as per the measured displacement distance. If the displacement is a valid s8, then
866 // a j8 is inserted, else a j32.
867 //
868 // Note: This class is inherently unsafe, and so it's recommended to use xForwardJump8/32
869 // whenever it is known that the jump destination is (or is not) short. Only use
870 // xSmartJump in cases where it's unknown what jump encoding will be ideal.
871 //
872 // Important: Use this tool with caution! xSmartJump cannot be used in cases where jump
873 // targets overlap, since the writeback of the second target will alter the position of
874 // the first target (which breaks the relative addressing). To assist in avoiding such
875 // errors, xSmartJump works based on C++ block scope, where the destruction of the
876 // xSmartJump object (invoked by a '}') signals the target of the jump. Example:
877 //
878 // {
879 // iCMP( EAX, ECX );
880 // xSmartJump jumpTo( Jcc_Above );
881 // [... conditional code ...]
882 // } // smartjump targets this spot.
883 //
884 // No code inside the scope can attempt to jump outside the scoped block (unless the jump
885 // uses an immediate addressing method, such as Register or Mod/RM forms of JMP/CALL).
886 // Multiple SmartJumps can be safely nested inside scopes, as long as they are properly
887 // scoped themselves.
888 //
889 // Performance Analysis: j8's use 4 less byes per opcode, and thus can provide minor
890 // speed benefits in the form of L1/L2 cache clutter, on any CPU. They're also notably
891 // faster on P4's, and mildly faster on AMDs. (Core2's and i7's don't care)
892 //
893 class xSmartJump
894 {
895 DeclareNoncopyableObject(xSmartJump);
896
897 protected:
898 u8* m_baseptr; // base address of the instruction (passed to the instruction emitter)
899 JccComparisonType m_cc; // comparison type of the instruction
900
901 public:
902 int GetMaxInstructionSize() const
903 {
904 pxAssert( m_cc != Jcc_Unknown );
905 return ( m_cc == Jcc_Unconditional ) ? 5 : 6;
906 }
907
908 JccComparisonType GetCondition() const { return m_cc; }
909 virtual ~xSmartJump();
910
911 // ------------------------------------------------------------------------
912 // ccType - Comparison type to be written back to the jump instruction position.
913 //
914 xSmartJump( JccComparisonType ccType )
915 {
916 pxAssert( ccType != Jcc_Unknown );
917 m_baseptr = xGetPtr();
918 m_cc = ccType;
919 xAdvancePtr( GetMaxInstructionSize() );
920 }
921
922 protected:
923 void SetTarget();
924 };
925
926 // --------------------------------------------------------------------------------------
927 // xForwardJump
928 // --------------------------------------------------------------------------------------
929 // Primary use of this class is through the various xForwardJA8/xForwardJLE32/etc. helpers
930 // defined later in this header. :)
931 //
932
933 class xForwardJumpBase
934 {
935 public:
936 // pointer to base of the instruction *Following* the jump. The jump address will be
937 // relative to this address.
938 s8* BasePtr;
939
940 public:
941 xForwardJumpBase( uint opsize, JccComparisonType cctype );
942
943 protected:
944 void _setTarget( uint opsize ) const;
945 };
946
947 template< typename OperandType >
948 class xForwardJump : public xForwardJumpBase
949 {
950 public:
951 static const uint OperandSize = sizeof( OperandType );
952
953 // The jump instruction is emitted at the point of object construction. The conditional
954 // type must be valid (Jcc_Unknown generates an assertion).
955 xForwardJump( JccComparisonType cctype = Jcc_Unconditional ) : xForwardJumpBase( OperandSize, cctype ) { }
956
957 // Sets the jump target by writing back the current x86Ptr to the jump instruction.
958 // This method can be called multiple times, re-writing the jump instruction's target
959 // in each case. (the the last call is the one that takes effect).
960 void SetTarget() const
961 {
962 _setTarget( OperandSize );
963 }
964 };
965
966 static __fi xAddressVoid operator+( const void* addr, const xAddressReg& reg )
967 {
968 return reg + (sptr)addr;
969 }
970
971 static __fi xAddressVoid operator+( s32 addr, const xAddressReg& reg )
972 {
973 return reg + (sptr)addr;
974 }
975 }
976
977 #include "implement/helpers.h"
978
979 #include "implement/simd_helpers.h"
980 #include "implement/simd_moremovs.h"
981 #include "implement/simd_arithmetic.h"
982 #include "implement/simd_comparisons.h"
983 #include "implement/simd_shufflepack.h"
984
985 #include "implement/group1.h"
986 #include "implement/group2.h"
987 #include "implement/group3.h"
988 #include "implement/movs.h" // cmov and movsx/zx
989 #include "implement/dwshift.h" // doubleword shifts!
990 #include "implement/incdec.h"
991 #include "implement/test.h"
992 #include "implement/jmpcall.h"
993
994 #include "inlines.inl"

  ViewVC Help
Powered by ViewVC 1.1.22