/[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 31 - (hide 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 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     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