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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 11 months 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 william 31 /* 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 william 62 static const uint iREGCNT_XMM = 8;
20     static const uint iREGCNT_GPR = 8;
21     static const uint iREGCNT_MMX = 8;
22 william 31
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 william 62 static __fi bool is_s8( T imm ) { return (s8)imm == (s32)imm; }
84 william 31
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 william 62 // Note: I *intentionally* use __fi directly for most single-line class members,
118 william 31 // 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 william 62 # define __emitinline __fi
125 william 31 #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 william 62 class xAddressVoid;
197    
198 william 31 // --------------------------------------------------------------------------------------
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 william 62
377     static const inline xRegisterSSE& GetInstance(uint id);
378 william 31 };
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 william 62 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 william 31
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 william 62 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 william 31 // --------------------------------------------------------------------------------------
509 william 62 // xAddressVoid
510 william 31 // --------------------------------------------------------------------------------------
511 william 62 class xAddressVoid
512 william 31 {
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 william 62 xAddressVoid( const xAddressReg& base, const xAddressReg& index, int factor=1, s32 displacement=0 );
521 william 31
522 william 62 xAddressVoid( const xAddressReg& index, int displacement=0 );
523     explicit xAddressVoid( const void* displacement );
524     explicit xAddressVoid( s32 displacement=0 );
525 william 31
526 william 62 public:
527     bool IsByteSizeDisp() const { return is_s8( Displacement ); }
528 william 31
529 william 62 xAddressVoid& Add( s32 imm )
530 william 31 {
531 william 62 Displacement += imm;
532     return *this;
533 william 31 }
534    
535 william 62 xAddressVoid& Add( const xAddressReg& src );
536     xAddressVoid& Add( const xAddressVoid& src );
537 william 31
538 william 62 __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 william 31 public:
558 william 62 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 william 31 bool IsByteSizeDisp() const { return is_s8( Displacement ); }
577    
578 william 62 xAddressInfo<BaseType>& Add( s32 imm )
579 william 31 {
580     Displacement += imm;
581     return *this;
582     }
583    
584 william 62 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 william 31
587 william 62 __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 william 31
593 william 62 __fi void operator+=( const xAddressInfo<BaseType>& right ) { Add( right ); }
594 william 31 };
595    
596 william 62 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 william 31
602 william 62 static __fi xAddressVoid operator+( const void* addr, const xAddressVoid& right )
603     {
604     return right + addr;
605     }
606 william 31
607 william 62 static __fi xAddressVoid operator+( s32 addr, const xAddressVoid& right )
608     {
609     return right + addr;
610     }
611 william 31
612 william 62 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 william 31
619 william 62 template< typename OperandType >
620     static __fi xAddressInfo<OperandType> operator+( s32 addr, const xAddressInfo<OperandType>& right )
621     {
622     return right + addr;
623     }
624 william 31
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 william 62 // xIndirectVoid - Internal low-level representation of the ModRM/SIB information.
661 william 31 // --------------------------------------------------------------------------------------
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 william 62 class xIndirectVoid : public OperandSizedObject
672 william 31 {
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 william 62 explicit xIndirectVoid( s32 disp );
681     explicit xIndirectVoid( const xAddressVoid& src );
682     xIndirectVoid( xAddressReg base, xAddressReg index, int scale=0, s32 displacement=0 );
683 william 31
684 william 62 virtual uint GetOperandSize() const;
685     xIndirectVoid& Add( s32 imm );
686 william 31
687 william 62 bool IsByteSizeDisp() const { return is_s8( Displacement ); }
688    
689     operator xAddressVoid()
690 william 31 {
691 william 62 return xAddressVoid( Base, Index, Scale, Displacement );
692 william 31 }
693    
694 william 62 __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 william 31
697 william 62 protected:
698     void Reduce();
699     };
700    
701     template< typename OperandType >
702     class xIndirect : public xIndirectVoid
703     {
704     typedef xIndirectVoid _parent;
705 william 31
706 william 62 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 william 31
712 william 62 virtual uint GetOperandSize() const { return sizeof(OperandType); }
713 william 31
714 william 62 xIndirect<OperandType>& Add( s32 imm )
715 william 31 {
716     Displacement += imm;
717     return *this;
718     }
719    
720 william 62 __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 william 31
723 william 62 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 william 31 protected:
736     void Reduce();
737     };
738    
739 william 62 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 william 31 // --------------------------------------------------------------------------------------
746 william 62 // xIndirect32orLass - base class 32, 16, and 8 bit operand types
747 william 31 // --------------------------------------------------------------------------------------
748 william 62 class xIndirect32orLess : public xIndirectVoid
749 william 31 {
750 william 62 typedef xIndirectVoid _parent;
751 william 31
752     protected:
753 william 62 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 william 31 _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 william 62 // xAddressReg types go in, and xIndirectVoid derived types come out.
775 william 31 //
776     template< typename xModSibType >
777 william 62 class xAddressIndexer
778 william 31 {
779 william 62 public:
780 william 31 // 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 william 62 xModSibType operator[]( const xAddressReg& src ) const
785 william 31 {
786     return xModSibType( src, xEmptyReg );
787     }
788    
789 william 62 xModSibType operator[]( const xAddressVoid& src ) const
790 william 31 {
791 william 62 return xModSibType( src.Base, src.Index, src.Factor, src.Displacement );
792 william 31 }
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 william 62 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 william 31
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 william 62 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 william 31 #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 william 62 static __fi xAddressVoid operator+( const void* addr, const xAddressReg& reg )
967 william 31 {
968 william 62 return reg + (sptr)addr;
969 william 31 }
970    
971 william 62 static __fi xAddressVoid operator+( s32 addr, const xAddressReg& reg )
972 william 31 {
973 william 62 return reg + (sptr)addr;
974 william 31 }
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