root/lang/objective-cplusplus/i3/trunk/src/mil/include/xbyak/xbyak.h @ 36430

Revision 36430, 41.9 kB (checked in by saturday06, 3 years ago)

mznkt

Line 
1#ifndef XBYAK_H_
2#define XBYAK_H_
3/*!
4        @file xbyak.h
5        @brief Xbyak ; JIT assembler for x86(IA32)/x64 by C++
6        @author herumi
7        @version $Revision: 1.151 $
8        @date $Date: 2008/09/18 14:55:27 $
9        @note modified new BSD license
10        http://www.opensource.org/licenses/bsd-license.php
11*/
12
13#include <stdio.h> // for debug print
14#include <assert.h>
15#include <map>
16#include <string>
17#if defined(__GNUC__) && !defined(_WIN32)
18#include <unistd.h>
19#include <sys/mman.h>
20#endif
21
22#ifdef __x86_64__
23                #define XBYAK64_GCC
24#elif defined(_WIN64)
25                #define XBYAK64_WIN
26#endif
27#if !defined(XBYAK64) && !defined(XBYAK32)
28        #if defined(XBYAK64_GCC) || defined(XBYAK64_WIN)
29                #define XBYAK64
30        #else
31                #define XBYAK32
32        #endif
33#endif
34
35#ifdef _MSC_VER
36        #pragma warning(push)
37        #pragma warning(disable : 4514) /* remove inline function */
38        #pragma warning(disable : 4786) /* identifier is too long */
39        #pragma warning(disable : 4503) /* name is too long */
40        #pragma warning(disable : 4127) /* constant expresison */
41        #if (_MSC_VER <= 1200)
42                #ifndef for
43                        #define for if(0);else for
44                        #pragma warning(disable : 4127) /* condition is constant(for "if" trick) */
45                #endif
46        #endif
47        #include <windows.h>
48#elif defined(_WIN32)
49        #include <windows.h>
50#endif
51
52#ifndef NUM_OF_ARRAY
53        #define NUM_OF_ARRAY(x) (sizeof(x)/sizeof(x[0]))
54#endif
55
56namespace Xbyak {
57
58#include "xbyak_bin2hex.h"
59
60enum {
61        DEFAULT_MAX_CODE_SIZE = 2048,
62        VERSION = 0x2060, /* 0xABCD = A.BC(D) */
63};
64
65#ifndef MIE_DEFINED_UINT32
66        #define MIE_DEFINED_UINT32
67        #ifdef _MSC_VER
68                typedef unsigned __int64 uint64;
69        #else
70                typedef unsigned long long uint64;
71        #endif
72        typedef unsigned int uint32;
73        typedef unsigned short uint16;
74        typedef unsigned char uint8;
75        #ifndef MIE_ALIGN
76                #ifdef _MSC_VER
77                        #define MIE_ALIGN(x) __declspec(align(x))
78                #else
79                        #define MIE_ALIGN(x) __attribute__((aligned(x)))
80                #endif
81        #endif
82#endif
83
84enum Error {
85        ERR_NONE = 0,
86        ERR_BAD_ADDRESSING,
87        ERR_CODE_IS_TOO_BIG,
88        ERR_BAD_SCALE,
89        ERR_ESP_CANT_BE_INDEX,
90        ERR_BAD_COMBINATION,
91        ERR_BAD_SIZE_OF_REGISTER,
92        ERR_IMM_IS_TOO_BIG,
93        ERR_BAD_ALIGN,
94        ERR_LABEL_IS_REDEFINED,
95        ERR_LABEL_IS_TOO_FAR,
96        ERR_LABEL_IS_NOT_FOUND,
97        ERR_CODE_ISNOT_COPYABLE,
98        ERR_BAD_PARAMETER,
99        ERR_CANT_PROTECT,
100        ERR_CANT_USE_64BIT_DISP,
101        ERR_OFFSET_IS_TOO_BIG,
102        ERR_MEM_SIZE_IS_NOT_SPECIFIED,
103        ERR_INTERNAL
104};
105
106static inline const char *ConvertErrorToString(Error err)
107{
108        static const char errTbl[][40] = {
109                "none",
110                "bad addressing",
111                "code is too big",
112                "bad scale",
113                "esp can't be index",
114                "bad combination",
115                "bad size of register",
116                "imm is too big",
117                "bad align",
118                "label is redefined",
119                "label is too far",
120                "label is not found",
121                "code is not copyable",
122                "bad parameter",
123                "can't protect",
124                "can't use 64bit disp(use (void*))",
125                "offset is too big",
126                "MEM size is not specified",
127                "internal error",
128        };
129        if (err < 0 || err > ERR_INTERNAL) return 0;
130        return errTbl[err];
131}
132
133namespace inner {
134
135enum { debug = 1 };
136
137static inline uint32 GetPtrDist(const void *p1, const void *p2 = 0)
138{
139        uint64 diff = static_cast<const char *>(p1) - static_cast<const char *>(p2);
140#ifdef XBYAK64
141        if (0x7FFFFFFFULL < diff && diff < 0xFFFFFFFF80000000ULL) throw ERR_OFFSET_IS_TOO_BIG;
142#endif
143        return static_cast<uint32>(diff);
144}
145
146static inline bool IsInDisp8(uint32 x) { return 0xFFFFFF80 <= x || x <= 0x7F; }
147
148}
149
150class Operand {
151private:
152        const uint8 idx_;
153        const uint8 kind_;
154        const uint8 bit_;
155        const uint8 ext8bit_; // 1 if spl/bpl/sil/dil, otherwise 0
156        void operator=(Operand&);
157public:
158        enum Kind {
159                NONE = 0,
160                MEM = 1 << 1,
161                IMM = 1 << 2,
162                REG = 1 << 3,
163                MMX = 1 << 4,
164                XMM = 1 << 5,
165                FPU = 1 << 6
166        };
167        enum Code {
168#ifdef XBYAK64
169                RAX = 0, RCX, RDX, RBX, RSP, RBP, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15,
170                R8D = 8, R9D, R10D, R11D, R12D, R13D, R14D, R15D,
171                R8W = 8, R9W, R10W, R11W, R12W, R13W, R14W, R15W,
172                R8B = 8, R9B, R10B, R11B, R12B, R13B, R14B, R15B,
173                SPL = 4, BPL, SIL, DIL,
174#endif
175                EAX = 0, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
176                AX = 0, CX, DX, BX, SP, BP, SI, DI,
177                AL = 0, CL, DL, BL, AH, CH, DH, BH
178        };
179        Operand() : idx_(0), kind_(0), bit_(0), ext8bit_(0) { }
180        Operand(int idx, Kind kind, int bit, int ext8bit = 0)
181                : idx_(static_cast<uint8>(idx))
182                , kind_(static_cast<uint8>(kind))
183                , bit_(static_cast<uint8>(bit))
184                , ext8bit_(static_cast<uint8>(ext8bit))
185        {
186                assert((bit_ & (bit_ - 1)) == 0); // bit must be power of two
187        }
188        Kind getKind() const { return static_cast<Kind>(kind_); }
189        int getIdx() const { return idx_; }
190        bool isNone() const { return kind_ == 0; }
191        bool isMMX() const { return is(MMX); }
192        bool isXMM() const { return is(XMM); }
193        bool isREG(int bit = 0) const { return is(REG, bit); }
194        bool isMEM(int bit = 0) const { return is(MEM, bit); }
195        bool isExt8bit() const { return ext8bit_ != 0; }
196        Operand changeBit(int bit) const { return Operand(idx_, static_cast<Kind>(kind_), bit, ext8bit_); }
197        // any bit is accetable if bit == 0
198        bool is(int kind, uint32 bit = 0) const
199        {
200                return (kind_ & kind) && (bit == 0 || (bit_ & bit)); // cf. you can set (8|16)
201        }
202        bool isBit(uint32 bit) const { return (bit_ & bit) != 0; }
203        uint32 getBit() const { return bit_; }
204        const char *toString() const
205        {
206                if (kind_ == REG) {
207                        if (ext8bit_) {
208                                static const char tbl[4][4] = { "spl", "bpl", "sil", "dil" };
209                                return tbl[idx_ - 4];
210                        }
211                        static const char tbl[4][16][5] = {
212                                { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", "r8b", "r9b", "r10b",  "r11b", "r12b", "r13b", "r14b", "r15b" },
213                                { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w",  "r11w", "r12w", "r13w", "r14w", "r15w" },
214                                { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d",  "r11d", "r12d", "r13d", "r14d", "r15d" },
215                                { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10",  "r11", "r12", "r13", "r14", "r15" },
216                        };
217                        return tbl[bit_ == 8 ? 0 : bit_ == 16 ? 1 : bit_ == 32 ? 2 : 3][idx_];
218                } else if (isMMX()) {
219                        static const char tbl[8][4] = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" };
220                        return tbl[idx_];
221                } else if (isXMM()) {
222                        static const char tbl[16][5] = { "xm0", "xm1", "xm2", "xm3", "xm4", "xm5", "xm6", "xm7", "xm8", "xm9", "xm10", "xm11", "xm12", "xm13", "xm14", "xm15" };
223                        return tbl[idx_];
224                }
225                throw ERR_INTERNAL;
226        }
227};
228
229class Reg : public Operand {
230        void operator=(const Reg&);
231public:
232        Reg() { }
233        Reg(int idx, Kind kind, int bit = 0, int ext8bit = 0) : Operand(idx, kind, bit, ext8bit) { }
234        // reg = this
235        uint8 getRex(const Reg& index = Reg(), const Reg& base = Reg()) const
236        {
237                if ((!isExt8bit() && !index.isExt8bit() && !base.isExt8bit()) && (getIdx() | index.getIdx() | base.getIdx()) < 8) return 0;
238                return uint8(0x40 | ((getIdx() >> 3) << 2)| ((index.getIdx() >> 3) << 1) | (base.getIdx() >> 3));
239        }
240};
241
242class Reg8 : public Reg {
243        void operator=(const Reg8&);
244public:
245        explicit Reg8(int idx, int ext8bit = 0) : Reg(idx, Operand::REG, 8, ext8bit) { }
246};
247
248class Reg16 : public Reg {
249        void operator=(const Reg16&);
250public:
251        explicit Reg16(int idx) : Reg(idx, Operand::REG, 16) { }
252};
253
254class Mmx : public Reg {
255        void operator=(const Mmx&);
256public:
257        explicit Mmx(int idx, Kind kind = Operand::MMX, int bit = 64) : Reg(idx, kind, bit) { }
258};
259
260class Xmm : public Mmx {
261        void operator=(const Xmm&);
262public:
263        explicit Xmm(int idx) : Mmx(idx, Operand::XMM, 128) { }
264};
265
266// register for addressing(32bit or 64bit)
267class Reg32e : public Reg {
268public:
269        // [base_(this) + index_ * scale_ + disp_]
270        const Reg index_;
271        const int scale_; // 0(index is none), 1, 2, 4, 8
272        const uint32 disp_;
273private:
274        friend class Address;
275        friend Reg32e operator+(const Reg32e& a, const Reg32e& b)
276        {
277                if (a.scale_ == 0) {
278                        if (b.scale_ == 0) { // base + base
279                                if (b.getIdx() == Operand::ESP) { // [reg + esp] => [esp + reg]
280                                        return Reg32e(b, a, 1, a.disp_ + b.disp_);
281                                } else {
282                                        return Reg32e(a, b, 1, a.disp_ + b.disp_);
283                                }
284                        } else if (b.isNone()) { // base + index
285                                return Reg32e(a, b.index_, b.scale_, a.disp_ + b.disp_);
286                        }
287                }
288                throw ERR_BAD_ADDRESSING;
289        }
290        friend Reg32e operator*(const Reg32e& r, int scale)
291        {
292                if (r.scale_ == 0) {
293                        if (scale == 1) {
294                                return r;
295                        } else if (scale == 2 || scale == 4 || scale == 8) {
296                                return Reg32e(Reg(), r, scale, r.disp_);
297                        }
298                }
299                throw ERR_BAD_SCALE;
300        }
301        friend Reg32e operator+(const Reg32e& r, unsigned int disp)
302        {
303                return Reg32e(r, r.index_, r.scale_, r.disp_ + disp);
304        }
305        friend Reg32e operator-(const Reg32e& r, unsigned int disp)
306        {
307                return operator+(r, -static_cast<int>(disp));
308        }
309        void operator=(const Reg32e&); // don't call
310public:
311        explicit Reg32e(int idx, int bit)
312                : Reg(idx, REG, bit)
313                , index_()
314                , scale_(0)
315                , disp_(0)
316        {
317        }
318        Reg32e(const Reg& base, const Reg& index, int scale, unsigned int disp)
319                : Reg(base)
320                , index_(index)
321                , scale_(scale)
322                , disp_(disp)
323        {
324                if (scale != 0 && scale != 1 && scale != 2 && scale != 4 && scale != 8) throw ERR_BAD_SCALE;
325                if (!base.isNone() && !index.isNone() && base.getBit() != index.getBit()) throw ERR_BAD_COMBINATION;
326                if (index.getIdx() == Operand::ESP) throw ERR_ESP_CANT_BE_INDEX;
327        }
328        Reg32e optimize() const // select smaller size
329        {
330                // [reg * 2] => [reg + reg]
331                if (isNone() && !index_.isNone() && scale_ == 2) {
332                        const Reg index(index_.getIdx(), Operand::REG, index_.getBit());
333                        return Reg32e(index, index, 1, disp_);
334                }
335                return *this;
336        }
337};
338
339struct Reg32 : public Reg32e {
340        explicit Reg32(int idx) : Reg32e(idx, 32) {}
341private:
342        void operator=(const Reg32&);
343};
344#ifdef XBYAK64
345struct Reg64 : public Reg32e {
346        explicit Reg64(int idx) : Reg32e(idx, 64) {}
347private:
348        void operator=(const Reg64&);
349};
350struct RegRip {
351        uint32 disp_;
352        RegRip(unsigned int disp = 0) : disp_(disp) {}
353        friend const RegRip operator+(const RegRip& r, unsigned int disp) {
354                return RegRip(r.disp_ + disp);
355        }
356        friend const RegRip operator-(const RegRip& r, unsigned int disp) {
357                return RegRip(r.disp_ - disp);
358        }
359};
360#endif
361
362class CodeArray {
363        enum {
364                ALIGN_SIZE = 16,
365                MAX_FIXED_BUF_SIZE = 8
366        };
367        enum Type {
368                FIXED_BUF, // use buf_(non alignment, non protect)
369                USER_BUF, // use userPtr(non alignment, non protect)
370                ALLOC_BUF // use new(alignment, protect)
371        };
372        void operator=(const CodeArray&);
373        Type type_;
374        uint8 *const allocPtr_; // for ALLOC_BUF
375        uint8 buf_[MAX_FIXED_BUF_SIZE]; // for FIXED_BUF
376protected:
377        const size_t maxSize_;
378        uint8 *const top_;
379        size_t size_;
380public:
381        CodeArray(size_t maxSize = MAX_FIXED_BUF_SIZE, void *userPtr = 0)
382                : type_(userPtr ? USER_BUF : maxSize <= MAX_FIXED_BUF_SIZE ? FIXED_BUF : ALLOC_BUF)
383                , allocPtr_(type_ == ALLOC_BUF ? new uint8[maxSize + ALIGN_SIZE] : 0)
384                , maxSize_(maxSize)
385                , top_(type_ == ALLOC_BUF ? getAlignedAddress(allocPtr_) : type_ == USER_BUF ? reinterpret_cast<uint8*>(userPtr) : buf_)
386                , size_(0)
387        {
388                if (type_ == ALLOC_BUF && !protect(top_, maxSize, true)) {
389//                      fprintf(stderr, "can't protect (addr=%p, size=%u, canExec=%d)\n", addr, size, canExec);
390                        throw ERR_CANT_PROTECT;
391                }
392        }
393        virtual ~CodeArray()
394        {
395                if (type_ == ALLOC_BUF) {
396                        protect(top_, maxSize_, false);
397                        delete[] allocPtr_;
398                }
399        }
400        CodeArray(const CodeArray& rhs)
401                : type_(rhs.type_)
402                , allocPtr_(0)
403                , maxSize_(rhs.maxSize_)
404                , top_(buf_)
405                , size_(rhs.size_)
406        {
407                if (type_ != FIXED_BUF) throw ERR_CODE_ISNOT_COPYABLE;
408                for (size_t i = 0; i < size_; i++) top_[i] = rhs.top_[i];
409        }
410        void db(int code)
411        {
412                if (size_ >= maxSize_) throw ERR_CODE_IS_TOO_BIG;
413                top_[size_++] = static_cast<uint8>(code);
414        }
415        void db(const uint8 *code, int codeSize)
416        {
417                for (int i = 0; i < codeSize; i++) db(code[i]);
418        }
419        void db(uint64 code, int codeSize)
420        {
421                if (codeSize > 8) throw ERR_BAD_PARAMETER;
422                for (int i = 0; i < codeSize; i++) db(static_cast<uint8>(code >> (i * 8)));
423        }
424        void dw(uint32 code) { db(code, 2); }
425        void dd(uint32 code) { db(code, 4); }
426        const uint8 *getCode() const { return top_; }
427        const uint8 *getCurr() const { return &top_[size_]; }
428        size_t getSize() const { return size_; }
429        void dump() const
430        {
431                const uint8 *p = getCode();
432                size_t bufSize = getSize();
433                size_t remain = bufSize;
434                for (int i = 0; i < 4; i++) {
435                        size_t disp = 16;
436                        if (remain < 16) {
437                                disp = remain;
438                        }
439                        for (size_t j = 0; j < 16; j++) {
440                                if (j < disp) {
441                                        printf("%02X", p[i * 16 + j]);
442                                }
443                        }
444                        putchar('\n');
445                        remain -= disp;
446                        if (remain <= 0) {
447                                break;
448                        }
449                }
450        }
451        /*
452                @param data [in] address of jmp data
453                @param disp [in] offset from the next of jmp
454                @param isShort [in] true if short jmp
455        */
456        void rewrite(uint8 *data, uint32 disp, bool isShort)
457        {
458                if (isShort) {
459                        data[0] = static_cast<uint8>(disp);
460                } else {
461                        data[0] = static_cast<uint8>(disp);
462                        data[1] = static_cast<uint8>(disp >> 8);
463                        data[2] = static_cast<uint8>(disp >> 16);
464                        data[3] = static_cast<uint8>(disp >> 24);
465                }
466        }
467        /**
468                change exec permission of memory
469                @param addr [in] buffer address
470                @param size [in] buffer size
471                @param canExec [in] true(enable to exec), false(disable to exec)
472                @return true(success), false(failure)
473        */
474        static inline bool protect(const void *addr, size_t size, bool canExec)
475        {
476#ifdef _WIN32
477                DWORD oldProtect;
478                return VirtualProtect(const_cast<void*>(addr), size, canExec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldProtect) != 0;
479#elif defined(__GNUC__)
480                size_t pageSize = sysconf(_SC_PAGESIZE);
481                size_t iaddr = reinterpret_cast<size_t>(addr);
482                size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
483                int mode = PROT_READ | PROT_WRITE | (canExec ? PROT_EXEC : 0);
484                return mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode) == 0;
485#else
486                return true;
487#endif
488        }
489        /**
490                get aligned memory pointer
491                @param addr [in] address
492                @param alingedSize [in] power of two
493                @return aligned addr by alingedSize
494        */
495        static inline uint8 *getAlignedAddress(uint8 *addr, size_t alignedSize = ALIGN_SIZE)
496        {
497                return reinterpret_cast<uint8*>((reinterpret_cast<size_t>(addr) + alignedSize - 1) & ~(alignedSize - static_cast<size_t>(1)));
498        }
499};
500
501class Address : public Operand, public CodeArray {
502        void operator=(const Address&);
503        uint64 disp_;
504        bool isOnlyDisp_;
505        bool is64bitDisp_;
506        uint8 rex_;
507public:
508        const bool is32bit_;
509        Address(uint32 sizeBit, bool isOnlyDisp, uint64 disp, bool is32bit, bool is64bitDisp = false)
510                : Operand(0, MEM, sizeBit)
511                , CodeArray(6) // 6 = 1(ModRM) + 1(SIB) + 4(disp)
512                , disp_(disp)
513                , isOnlyDisp_(isOnlyDisp)
514                , is64bitDisp_(is64bitDisp)
515                , rex_(0)
516                , is32bit_(is32bit)
517        {
518        }
519        bool isOnlyDisp() const { return isOnlyDisp_; } // for mov eax
520        uint64 getDisp() const { return disp_; }
521        uint8 getRex() const { return rex_; }
522        bool is64bitDisp() const { return is64bitDisp_; } // for moffset
523#ifdef XBYAK64
524        void setRex(uint8 rex) { rex_ = rex; }
525#else
526        void setRex(uint8) { }
527#endif
528};
529
530class AddressFrame {
531private:
532        void operator=(const AddressFrame&);
533public:
534        const uint32 bit_;
535        explicit AddressFrame(uint32 bit) : bit_(bit) { }
536        Address operator[](const void *disp) const
537        {
538                Reg32e r(Reg(), Reg(), 0, inner::GetPtrDist(disp));
539                return operator[](r);
540        }
541#ifdef XBYAK64
542        Address operator[](uint64 disp) const
543        {
544                return Address(64, true, disp, false, true);
545        }
546        Address operator[](const RegRip& addr) const {
547                Address frame(64, true, addr.disp_, false);
548                frame.db(B00000101);
549                frame.dd(addr.disp_);
550                return frame;
551        }
552#endif
553        Address operator[](const Reg32e& in) const
554        {
555                const Reg32e& r = in.optimize();
556                Address frame(bit_, (r.isNone() && r.index_.isNone()), r.disp_, r.isBit(32) || r.index_.isBit(32));
557                enum {
558                        mod00 = 0, mod01 = 1, mod10 = 2
559                };
560                int mod;
561                if (r.isNone() || ((r.getIdx() & 7) != Operand::EBP && r.disp_ == 0)) {
562                        mod = mod00;
563                } else if (inner::IsInDisp8(r.disp_)) {
564                        mod = mod01;
565                } else {
566                        mod = mod10;
567                }
568                const int base = r.isNone() ? Operand::EBP : (r.getIdx() & 7);
569                /* ModR/M = [2:3:3] = [Mod:reg/code:R/M] */
570                bool hasSIB = !r.index_.isNone() || (r.getIdx() & 7) == Operand::ESP;
571#ifdef XBYAK64
572                if (r.isNone() && r.index_.isNone()) hasSIB = true;
573#endif
574                if (!hasSIB) {
575                        frame.db((mod << 6) | base);
576                } else {
577                        frame.db((mod << 6) | Operand::ESP);
578                        /* SIB = [2:3:3] = [SS:index:base(=rm)] */
579                        int index = r.index_.isNone() ? Operand::ESP : (r.index_.getIdx() & 7);
580                        int ss = (r.scale_ == 8) ? 3 : (r.scale_ == 4) ? 2 : (r.scale_ == 2) ? 1 : 0;
581                        frame.db((ss << 6) | (index << 3) | base);
582                }
583                if (mod == mod01) {
584                        frame.db(r.disp_);
585                } else if (mod == mod10 || (mod == mod00 && r.isNone())) {
586                        frame.dd(r.disp_);
587                }
588                frame.setRex(Reg().getRex(r.index_, r));
589                return frame;
590        }
591};
592
593struct JmpLabel {
594        uint8 *endOfJmp; /* end address of jmp */
595        bool isShort;
596};
597
598class Label {
599        CodeArray *base_;
600        int anonymousCount_; // for @@, @f, @b
601        int localCount_; // for .***
602        typedef std::map<const std::string, const uint8*> DefinedList;
603        typedef std::multimap<const std::string, JmpLabel> UndefinedList;
604        DefinedList definedList_;
605        UndefinedList undefinedList_;
606
607        /*
608                @@ --> @@.<num>
609                @b --> @@.<num>
610                @f --> @@.<num + 1>
611                .*** -> .***.<num>
612        */
613        std::string convertLabel(const char *label) const
614        {
615                std::string newLabel(label);
616                if (newLabel == "@f" || newLabel == "@F") {
617                        newLabel = std::string("@@") + toStr(anonymousCount_ + 1);
618                } else if (newLabel == "@b" || newLabel == "@B") {
619                        newLabel = std::string("@@") + toStr(anonymousCount_);
620                } else if (*label == '.') {
621                        newLabel += toStr(localCount_);
622                }
623                return newLabel;
624        }
625public:
626        Label()
627                : base_(0)
628                , anonymousCount_(0)
629                , localCount_(0)
630        {
631        }
632        void incLocalCount() { localCount_++; }
633        void decLocalCount() { localCount_--; }
634        void set(CodeArray *base)
635        {
636                base_ = base;
637        }
638        void define(const char *label, const uint8 *address)
639        {
640                std::string newLabel(label);
641                if (newLabel == "@@") {
642                        newLabel += toStr(++anonymousCount_);
643                } else if (*label == '.') {
644                        newLabel += toStr(localCount_);
645                }
646                label = newLabel.c_str();
647                // add label
648                DefinedList::value_type item(label, address);
649                std::pair<DefinedList::iterator, bool> ret = definedList_.insert(item);
650                if (!ret.second) throw ERR_LABEL_IS_REDEFINED;
651                // search undefined label
652                for (;;) {
653                        UndefinedList::iterator itr = undefinedList_.find(label);
654                        if (itr == undefinedList_.end()) break;
655                        const JmpLabel *jmp = &itr->second;
656                        uint32 disp = inner::GetPtrDist(address, jmp->endOfJmp);
657                        if (jmp->isShort && !inner::IsInDisp8(disp)) throw ERR_LABEL_IS_TOO_FAR;
658                        uint8 *data = jmp->endOfJmp - (jmp->isShort ? 1 : 4);
659                        base_->rewrite(data, disp, jmp->isShort);
660                        undefinedList_.erase(itr);
661                }
662        }
663        const uint8 *getAddress(const char *label) const
664        {
665                std::string newLabel = convertLabel(label);
666                DefinedList::const_iterator itr = definedList_.find(newLabel);
667                if (itr != definedList_.end()) {
668                        return itr->second;
669                } else {
670                        return 0;
671                }
672        }
673        void addUndefinedLabel(const char *label, const JmpLabel& jmp)
674        {
675                std::string newLabel = convertLabel(label);
676                undefinedList_.insert(UndefinedList::value_type(newLabel, jmp));
677        }
678        bool hasUndefinedLabel() const
679        {
680                if (inner::debug) {
681                        for (UndefinedList::const_iterator i = undefinedList_.begin(); i != undefinedList_.end(); ++i) {
682                                fprintf(stderr, "undefined label:%s\n", i->first.c_str());
683                        }
684                }
685                return !undefinedList_.empty();
686        }
687        static inline std::string toStr(int num)
688        {
689                char buf[16];
690#ifdef _MSC_VER
691                _snprintf_s(buf, sizeof(buf), ".%08x", num);
692#else
693                snprintf(buf, sizeof(buf), ".%08x", num);
694#endif
695                return buf;
696        }
697};
698
699class CodeGenerator : public CodeArray {
700protected:
701        enum LabelType {
702                T_SHORT,
703                T_NEAR,
704                T_AUTO // T_SHORT if possible
705        };
706private:
707        CodeGenerator operator=(const CodeGenerator&); // don't call
708#ifdef XBYAK64
709        enum { i32e = 32 | 64, BIT = 64 };
710#else
711        enum { i32e = 32, BIT = 32 };
712#endif
713        // (XMM, XMM|MEM)
714        static inline bool isXMM_XMMorMEM(const Operand& op1, const Operand& op2)
715        {
716                return op1.isXMM() && (op2.isXMM() || op2.isMEM());
717        }
718        // (MMX, MMX|MEM) or (XMM, XMM|MEM)
719        static inline bool isXMMorMMX_MEM(const Operand& op1, const Operand& op2)
720        {
721                return (op1.isMMX() && (op2.isMMX() || op2.isMEM())) || isXMM_XMMorMEM(op1, op2);
722        }
723        // (XMM, MMX|MEM)
724        static inline bool isXMM_MMXorMEM(const Operand& op1, const Operand& op2)
725        {
726                return op1.isXMM() && (op2.isMMX() || op2.isMEM());
727        }
728        // (MMX, XMM|MEM)
729        static inline bool isMMX_XMMorMEM(const Operand& op1, const Operand& op2)
730        {
731                return op1.isMMX() && (op2.isXMM() || op2.isMEM());
732        }
733        // (XMM, REG32|MEM)
734        static inline bool isXMM_REG32orMEM(const Operand& op1, const Operand& op2)
735        {
736                return op1.isXMM() && (op2.isREG(i32e) || op2.isMEM());
737        }
738        // (REG32, XMM|MEM)
739        static inline bool isREG32_XMMorMEM(const Operand& op1, const Operand& op2)
740        {
741                return op1.isREG(i32e) && (op2.isXMM() || op2.isMEM());
742        }
743        void if16bit(const Operand& reg1, const Operand& reg2)
744        {
745                // except movsx(16bit, 32/64bit)
746                if ((reg1.isBit(16) && !reg2.isBit(i32e)) || (reg2.isBit(16) && !reg1.isBit(i32e))) db(0x66);
747        }
748        void rexAddr(const Address& addr, const Reg& reg = Reg())
749        {
750#ifdef XBYAK64
751                if (addr.is32bit_) db(0x67);
752#endif
753                if16bit(reg, addr);
754                uint32 rex = addr.getRex() | reg.getRex();
755                if (reg.isREG(64)) rex |= 0x48;
756                if (rex) db(rex);
757        }
758        void rex(const Operand& op1, const Operand& op2 = Operand())
759        {
760                if (op1.isMEM()) {
761                        rexAddr(static_cast<const Address&>(op1), static_cast<const Reg&>(op2));
762                } else if (op2.isMEM()) {
763                        rexAddr(static_cast<const Address&>(op2), static_cast<const Reg&>(op1));
764                } else {
765                        const Reg& reg1 = static_cast<const Reg&>(op1);
766                        const Reg& reg2 = static_cast<const Reg&>(op2);
767                        // ModRM(reg, base);
768                        if16bit(reg1, reg2);
769                        uint8 rex = reg2.getRex(Reg(), reg1);
770                        if (reg1.isREG(64) || reg2.isREG(64)) rex |= 0x48;
771                        if (rex) db(rex);
772                }
773        }
774        Label label_;
775        bool isInDisp16(uint32 x) const { return 0xFFFF8000 <= x || x <= 0x7FFF; }
776        uint8 getModRM(int mod, int r1, int r2) const { return static_cast<uint8>((mod << 6) | ((r1 & 7) << 3) | (r2 & 7)); }
777        void opModR(const Reg& reg1, const Reg& reg2, int code0, int code1 = NONE, int code2 = NONE)
778        {
779                rex(reg2, reg1);
780                db(code0 | (reg1.isBit(8) ? 0 : 1)); if (code1 != NONE) db(code1); if (code2 != NONE) db(code2);
781                db(getModRM(3, reg1.getIdx(), reg2.getIdx()));
782        }
783        void opModM(const Address& addr, const Reg& reg, int code0, int code1 = NONE, int code2 = NONE)
784        {
785                if (addr.is64bitDisp()) throw ERR_CANT_USE_64BIT_DISP;
786                rex(addr, reg);
787                db(code0 | (reg.isBit(8) ? 0 : 1)); if (code1 != NONE) db(code1); if (code2 != NONE) db(code2);
788                uint8 t = *addr.getCode();
789                assert((t & ~0xC7) == 0); /* 0b11000111 */
790                db(t | ((reg.getIdx() & 7) << 3)); // update reg field
791                db(addr.getCode() + 1, static_cast<int>(addr.getSize()) - 1);
792        }
793        void opJmp(const char *label, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref)
794        {
795                const uint8 *address = label_.getAddress(label);
796                if (address) { /* label exists */
797                        opJmp(address, type, shortCode, longCode, longPref);
798                } else {
799                        const int shortHeaderSize = 1;
800                        const int shortJmpSize = shortHeaderSize + 1; /* +1 means 8-bit displacement */
801                        const int longHeaderSize = longPref ? 2 : 1;
802                        const int longJmpSize = longHeaderSize + 4; /* +4 means 32-bit displacement */
803                        uint8 *top = const_cast<uint8*>(getCurr());
804                        bool isShort = (type != T_NEAR);
805                        JmpLabel jmp;
806                        jmp.endOfJmp = top + (isShort ? shortJmpSize : longJmpSize);
807                        jmp.isShort = isShort;
808                        if (isShort) {
809                                db(shortCode);
810                                db(0);
811                        } else {
812                                if (longPref) db(longPref);
813                                db(longCode);
814                                dd(0);
815                        }
816                        label_.addUndefinedLabel(label, jmp);
817                }
818        }
819        void opJmp(const void *addr, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref)
820        {
821                const int shortHeaderSize = 1;
822                const int shortJmpSize = shortHeaderSize + 1; /* +1 means 8-bit displacement */
823                const int longHeaderSize = longPref ? 2 : 1;
824                const int longJmpSize = longHeaderSize + 4; /* +4 means 32-bit displacement */
825
826                uint8 *top = const_cast<uint8*>(getCurr());
827                uint32 disp = inner::GetPtrDist(addr, top);
828                if (type != T_NEAR && inner::IsInDisp8(disp - shortJmpSize)) {
829                        db(shortCode);
830                        db(0);
831                        rewrite(top + shortHeaderSize, disp - shortJmpSize, true);
832                } else {
833                        if (type == T_SHORT) throw ERR_LABEL_IS_TOO_FAR;
834                        if (longPref) db(longPref);
835                        db(longCode);
836                        dd(0);
837                        rewrite(top + longHeaderSize, disp - longJmpSize, false);
838                }
839        }
840        /* preCode is for SSSE3/SSE4 */
841        void opGen(const Operand& reg, const Operand& op, int code, int pref, bool isValid(const Operand&, const Operand&), int imm8 = NONE, int preCode = NONE)
842        {
843                if (isValid && !isValid(reg, op)) throw ERR_BAD_COMBINATION;
844                if (pref != NONE) db(pref);
845                if (op.isMEM()) {
846                        opModM(static_cast<const Address&>(op), static_cast<const Reg&>(reg), 0x0F, preCode, code);
847                } else {
848                        opModR(static_cast<const Reg&>(reg), static_cast<const Reg&>(op), 0x0F, preCode, code);
849                }
850                if (imm8 != NONE) db(imm8);
851        }
852        void opMMX_IMM(const Mmx& mmx, int imm8, int code, int ext)
853        {
854                if (mmx.isXMM()) db(0x66);
855                opModR(Reg32(ext), mmx, 0x0F, code);
856                db(imm8);
857        }
858        void opMMX(const Mmx& mmx, const Operand& op, int code, int pref = 0x66, int imm8 = NONE, int preCode = NONE)
859        {
860                pref = mmx.isXMM() ? pref : NONE;
861                opGen(mmx, op, code, pref, isXMMorMMX_MEM, imm8, preCode);
862        }
863        void opMovXMM(const Operand& op1, const Operand& op2, int code, int pref)
864        {
865                if (pref != NONE) db(pref);
866                if (op1.isXMM() && op2.isMEM()) {
867                        opModM(static_cast<const Address&>(op2), static_cast<const Reg&>(op1), 0x0F, code);
868                } else if (op1.isMEM() && op2.isXMM()) {
869                        opModM(static_cast<const Address&>(op1), static_cast<const Reg&>(op2), 0x0F, code | 1);
870                } else {
871                        throw ERR_BAD_COMBINATION;
872                }
873        }
874        void opExt(const Operand& op, const Mmx& mmx, int code, int imm, bool hasMMX2 = false)
875        {
876                if (hasMMX2 && op.isREG(i32e)) { /* pextrw is special */
877                        if (mmx.isXMM()) db(0x66);
878                        opModR(static_cast<const Reg&>(op), mmx, 0x0F, B11000101); db(imm);
879                } else {
880                        opGen(mmx, op, code, 0x66, isXMM_REG32orMEM, imm, B00111010);
881                }
882        }
883        void opR_ModM(const Operand& op, int bit, uint8 mod, int ext, int code0, int code1 = NONE, int code2 = NONE)
884        {
885                if (op.isREG(bit)) {
886                        rex(op);
887                        db(code0 | (op.isBit(8) ? 0 : 1)); if (code1 != NONE) db(code1); if (code2 != NONE) db(code2);
888                        db(getModRM(mod, ext, op.getIdx()));
889                } else if (op.isMEM()) {
890                        opModM(static_cast<const Address&>(op), Reg(ext, Operand::REG, op.getBit()), code0, code1, code2);
891                } else {
892                        throw ERR_BAD_COMBINATION;
893                }
894        }
895        void opShift(const Operand& op, int imm, int ext)
896        {
897                verifyMemHasSize(op);
898                opR_ModM(op, 0, 3, ext, (B11000000 | ((imm == 1 ? 1 : 0) << 4)));
899                if (imm != 1) db(imm);
900        }
901        void opShift(const Operand& op, const Reg8& cl, int ext)
902        {
903                if (cl.getIdx() != Operand::CL) throw ERR_BAD_COMBINATION;
904                opR_ModM(op, 0, 3, ext, B11010010);
905        }
906        void opModRM(const Operand& op1, const Operand& op2, bool condR, bool condM, int code0, int code1 = NONE, int code2 = NONE)
907        {
908                if (condR) {
909                        opModR(static_cast<const Reg&>(op1), static_cast<const Reg&>(op2), code0, code1, code2);
910                } else if (condM) {
911                        opModM(static_cast<const Address&>(op2), static_cast<const Reg&>(op1), code0, code1, code2);
912                } else {
913                        throw ERR_BAD_COMBINATION;
914                }
915        }
916        void opShxd(const Operand& op, const Reg& reg, uint8 imm, int code, const Reg8 *cl = 0)
917        {
918                if (cl && cl->getIdx() != Operand::CL) throw ERR_BAD_COMBINATION;
919                opModRM(reg, op, (op.isREG(16 | i32e) && op.getBit() == reg.getBit()), op.isMEM() && (reg.isREG(16 | i32e)), 0x0F, code | (cl ? 1 : 0));
920                if (!cl) db(imm);
921        }
922        // (REG, REG|MEM), (MEM, REG)
923        void opRM_RM(const Operand& op1, const Operand& op2, int code)
924        {
925                if (op1.isREG() && op2.isMEM()) {
926                        opModM(static_cast<const Address&>(op2), static_cast<const Reg&>(op1), code | 2);
927                } else {
928                        opModRM(op2, op1, op1.isREG() && op1.getKind() == op2.getKind(), op1.isMEM() && op2.isREG(), code);
929                }
930        }
931        // (REG|MEM, IMM)
932        void opRM_I(const Operand& op, uint32 imm, int code, int ext)
933        {
934                verifyMemHasSize(op);
935                uint32 immBit = inner::IsInDisp8(imm) ? 8 : isInDisp16(imm) ? 16 : 32;
936                if (op.getBit() < immBit) throw ERR_IMM_IS_TOO_BIG;
937                if (op.isREG()) {
938                        if (immBit == 16 && op.isBit(32)) immBit = 32; /* don't use MEM16 if 32bit mode */
939                }
940                if (op.isREG() && op.getIdx() == 0 && (op.getBit() == immBit || (op.isBit(64) && immBit == 32))) { // rax, eax, ax, al
941                        rex(op);
942                        db(code | 4 | (immBit == 8 ? 0 : 1));
943                } else {
944                        int tmp = (op.getBit() > immBit && 32 > immBit) ? 2 : 0;
945                        opR_ModM(op, 0, 3, ext, B10000000 | tmp);
946                }
947                db(imm, immBit / 8);
948        }
949        void opIncDec(const Operand& op, int code, int ext)
950        {
951#ifndef XBYAK64
952                if (op.isREG() && !op.isBit(8)) {
953                        rex(op); db(code | op.getIdx());
954                        return;
955                }
956#endif
957                code = B11111110;
958                if (op.isREG()) {
959                        opModR(Reg(ext, Operand::REG, op.getBit()), static_cast<const Reg&>(op), code);
960                } else if (op.isMEM() && op.getBit() > 0) {
961                        opModM(static_cast<const Address&>(op), Reg(ext, Operand::REG, op.getBit()), code);
962                } else {
963                        throw ERR_BAD_COMBINATION;
964                }
965        }
966        void opPushPop(const Operand& op, int code, int ext, int alt)
967        {
968                if (op.isREG()) {
969#ifdef XBYAK64
970                        if (op.isBit(16)) db(0x66);
971                        if (static_cast<const Reg&>(op).getIdx() >= 8) db(0x41);
972#else
973                        rex(op);
974#endif
975                        db(alt | (op.getIdx() & 7));
976                } else if (op.isMEM()) {
977                        opModM(static_cast<const Address&>(op), Reg(ext, Operand::REG, op.getBit()), code);
978                } else {
979                        throw ERR_BAD_COMBINATION;
980                }
981        }
982        void verifyMemHasSize(const Operand& op) const
983        {
984                if (op.isMEM() && op.getBit() == 0) throw ERR_MEM_SIZE_IS_NOT_SPECIFIED;
985        }
986protected:
987        unsigned int getVersion() const { return VERSION; }
988        using CodeArray::db;
989        const Mmx mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
990        const Xmm xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
991        const Xmm &xm0, &xm1, &xm2, &xm3, &xm4, &xm5, &xm6, &xm7;
992        const Reg32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
993        const Reg16 ax, cx, dx, bx, sp, bp, si, di;
994        const Reg8 al, cl, dl, bl, ah, ch, dh, bh;
995        const AddressFrame ptr, byte, word, dword, qword;
996#ifdef XBYAK64
997        const Reg64 rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15;
998        const Reg32 r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d;
999        const Reg16 r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w;
1000        const Reg8 r8b, r9b, r10b, r11b, r12b, r13b, r14b, r15b;
1001        const Reg8 spl, bpl, sil, dil;
1002        const Xmm xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15;
1003        const Xmm &xm8, &xm9, &xm10, &xm11, &xm12, &xm13, &xm14, &xm15;
1004        const RegRip rip;
1005#endif
1006
1007        void L(const char *label)
1008        {
1009                label_.define(label, getCurr());
1010        }
1011        void inLocalLabel() { label_.incLocalCount(); }
1012        void outLocalLabel() { label_.decLocalCount(); }
1013        void jmp(const char *label, LabelType type = T_AUTO)
1014        {
1015                opJmp(label, type, B11101011, B11101001, 0);
1016        }
1017        void jmp(const void *addr, LabelType type = T_AUTO)
1018        {
1019                opJmp(addr, type, B11101011, B11101001, 0);
1020        }
1021        void jmp(const Operand& op)
1022        {
1023                opR_ModM(op, i32e, 3, 4, 0xFF);
1024        }
1025        // (REG|MEM, REG)
1026        void test(const Operand& op, const Reg& reg)
1027        {
1028                opModRM(reg, op, op.isREG() && (op.getKind() == reg.getKind()), op.isMEM(), B10000100);
1029        }
1030        // (REG|MEM, IMM)
1031        void test(const Operand& op, uint32 imm)
1032        {
1033                verifyMemHasSize(op);
1034                if (op.isREG() && op.getIdx() == 0) { // al, ax, eax
1035                        rex(op);
1036                        db(B10101000 | (op.isBit(8) ? 0 : 1));
1037                } else {
1038                        opR_ModM(op, 0, 3, 0, B11110110);
1039                }
1040                int size = op.getBit() / 8; if (size > 4) size = 4;
1041                db(imm, size);
1042        }
1043        void ret(int imm = 0)
1044        {
1045                if (imm) {
1046                        db(B11000010); dw(imm);
1047                } else {
1048                        db(B11000011);
1049                }
1050        }
1051        // (REG16|REG32, REG16|REG32|MEM)
1052        void imul(const Reg& reg, const Operand& op)
1053        {
1054                opModRM(reg, op, op.isREG() && (reg.getKind() == op.getKind()), op.isMEM(), 0x0F, B10101111);
1055        }
1056        void imul(const Reg& reg, const Operand& op, int imm)
1057        {
1058                int s = inner::IsInDisp8(imm) ? 1 : 0;
1059                opModRM(reg, op, op.isREG() && (reg.getKind() == op.getKind()), op.isMEM(), B01101001 | (s << 1));
1060                int size = s ? 1 : reg.isREG(16) ? 2 : 4;
1061                db(imm, size);
1062        }
1063        void pop(const Operand& op)
1064        {
1065                opPushPop(op, B10001111, 0, B01011000);
1066        }
1067        void push(const Operand& op)
1068        {
1069                opPushPop(op, B11111111, 6, B01010000);
1070        }
1071        void push(const AddressFrame& af, uint32 imm)
1072        {
1073                if (af.bit_ == 8 && inner::IsInDisp8(imm)) {
1074                        db(B01101010); db(imm);
1075                } else if (af.bit_ == 16 && isInDisp16(imm)) {
1076                        db(0x66); db(B01101000); dw(imm);
1077                } else {
1078                        db(B01101000); dd(imm);
1079                }
1080        }
1081        /* use "push(word, 4)" if you want "push word 4" */
1082        void push(uint32 imm)
1083        {
1084                if (inner::IsInDisp8(imm)) {
1085                        push(byte, imm);
1086                } else {
1087                        push(dword, imm);
1088                }
1089        }
1090        void bswap(const Reg32e& reg)
1091        {
1092                opModR(Reg32(1), reg, 0x0F);
1093        }
1094        void mov(const Operand& reg1, const Operand& reg2)
1095        {
1096                const Reg *reg = 0;
1097                const Address *addr = 0;
1098                uint8 code = 0;
1099                if (reg1.isREG() && reg1.getIdx() == 0 && reg2.isMEM()) { // mov eax|ax|al, [disp]
1100                        reg = &static_cast<const Reg&>(reg1);
1101                        addr= &static_cast<const Address&>(reg2);
1102                        code = B10100000;
1103                } else
1104                if (reg1.isMEM() && reg2.isREG() && reg2.getIdx() == 0) { // mov [disp], eax|ax|al
1105                        reg = &static_cast<const Reg&>(reg2);
1106                        addr= &static_cast<const Address&>(reg1);
1107                        code = B10100010;
1108                }
1109#ifdef XBYAK64
1110                if (addr && addr->is64bitDisp()) {
1111                        if (code) {
1112                                rex(*reg);
1113                                db(reg1.isREG(8) ? 0xA0 : reg1.isREG() ? 0xA1 : reg2.isREG(8) ? 0xA2 : 0xA3);
1114                                db(addr->getDisp(), 8);
1115                        } else {
1116                                throw ERR_BAD_COMBINATION;
1117                        }
1118                } else
1119#else
1120                if (code && addr->isOnlyDisp()) {
1121                        rex(*reg, *addr);
1122                        db(code | (reg->isBit(8) ? 0 : 1));
1123                        dd(static_cast<uint32>(addr->getDisp()));
1124                } else
1125#endif
1126                {
1127                        opRM_RM(reg1, reg2, B10001000);
1128                }
1129        }
1130        void mov(const Operand& op, uint64 imm)
1131        {
1132                verifyMemHasSize(op);
1133                if (op.isREG()) {
1134                        int w = op.isBit(8) ? 0 : 1;
1135                        rex(op); db(B10110000 | (w << 3) | (op.getIdx() & 7));
1136                } else if (op.isMEM()) {
1137                        opModM(static_cast<const Address&>(op), Reg(0, Operand::REG, op.getBit()), B11000110);
1138                } else {
1139                        throw ERR_BAD_COMBINATION;
1140                }
1141                db(imm, op.getBit() / 8);
1142        }
1143        void opMovxx(const Reg& reg, const Operand& op, uint8 code)
1144        {
1145                int w = op.isBit(16);
1146                bool cond = reg.isREG() && (reg.getBit() > op.getBit());
1147                opModRM(reg, op, cond && op.isREG(), cond && op.isMEM(), 0x0F, code | w);
1148        }
1149        void cmpxchg8b(const Address& addr) { opModM(addr, Reg32(1), 0x0F, B11000111); }
1150#ifdef XBYAK64
1151        void cmpxchg16b(const Address& addr) { opModM(addr, Reg64(1), 0x0F, B11000111); }
1152#endif
1153        void xadd(const Operand& op, const Reg& reg)
1154        {
1155                opModRM(reg, op, (op.isREG() && reg.isREG() && op.getBit() == reg.getBit()), op.isMEM(), 0x0F, B11000000 | (reg.isBit(8) ? 0 : 1));
1156        }
1157        void xchg(const Operand& op1, const Operand& op2)
1158        {
1159                const Operand *p1 = &op1, *p2 = &op2;
1160                if (p1->isMEM() || (p2->isREG(16 | i32e) && p2->getIdx() == 0)) {
1161                        p1 = &op2; p2 = &op1;
1162                }
1163                if (p1->isMEM()) throw ERR_BAD_COMBINATION;
1164                if (p2->isREG() && (p1->isREG(16 | i32e) && p1->getIdx() == 0)
1165#ifdef XBYAK64
1166                        && (p2->getIdx() != 0 || !p1->isREG(32))
1167#endif
1168                ) {
1169                        rex(*p2, *p1); db(0x90 | (p2->getIdx() & 7));
1170                        return;
1171                }
1172                opModRM(*p1, *p2, (p1->isREG() && p2->isREG() && (p1->getBit() == p2->getBit())), p2->isMEM(), B10000110 | (p1->isBit(8) ? 0 : 1));
1173        }
1174        void call(const char *label)
1175        {
1176                opJmp(label, T_NEAR, 0, B10011010, 0);
1177        }
1178        void call(const void *addr)
1179        {
1180                opJmp(addr, T_AUTO, 0, B11101000, 0);
1181        }
1182        void call(const Operand& op)
1183        {
1184                opR_ModM(op, 16 | i32e, 3, 2, B11111111);
1185        }
1186        // special case
1187        void movd(const Address& addr, const Mmx& mmx)
1188        {
1189                opModM(addr, Reg(mmx.getIdx(), Operand::REG, mmx.getBit() / 8), 0x0F, B01111110);
1190        }
1191        void movd(const Reg32& reg, const Mmx& mmx)
1192        {
1193                if (mmx.isXMM()) db(0x66);
1194                opModR(mmx, reg, 0x0F, B01111110);
1195        }
1196        void movd(const Mmx& mmx, const Address& addr)
1197        {
1198                opModM(addr, Reg(mmx.getIdx(), Operand::REG, mmx.getBit() / 8), 0x0F, B01101110);
1199        }
1200        void movd(const Mmx& mmx, const Reg32& reg)
1201        {
1202                if (mmx.isXMM()) db(0x66);
1203                opModR(mmx, reg, 0x0F, B01101110);
1204        }
1205        void movq2dq(const Xmm& xmm, const Mmx& mmx)
1206        {
1207                db(0xF3); opModR(xmm, mmx, 0x0F, B11010110);
1208        }
1209        void movdq2q(const Mmx& mmx, const Xmm& xmm)
1210        {
1211                db(0xF2); opModR(mmx, xmm, 0x0F, B11010110);
1212        }
1213        void movq(const Mmx& mmx, const Operand& op)
1214        {
1215                if (mmx.isXMM()) db(0xF3);
1216                opModRM(mmx, op, (mmx.getKind() == op.getKind()), op.isMEM(), 0x0F, mmx.isXMM() ? B01111110 : B01101111);
1217        }
1218        void movq(const Address& addr, const Mmx& mmx)
1219        {
1220                opModM(addr, Reg(mmx.getIdx(), Operand::REG, mmx.getBit() / 8), 0x0F, mmx.isXMM() ? B11010110 : B01111111);
1221        }
1222        // MMX2 : pextrw : reg, mmx/xmm, imm
1223        // SSE4 : pextrw, pextrb, pextrd, extractps : reg/mem, mmx/xmm, imm
1224        void pextrw(const Operand& op, const Mmx& xmm, uint8 imm) { opExt(op, xmm, 0x15, imm, true); }
1225        void pextrb(const Operand& op, const Xmm& xmm, uint8 imm) { opExt(op, xmm, 0x14, imm); }
1226        void pextrd(const Operand& op, const Xmm& xmm, uint8 imm) { opExt(op, xmm, 0x16, imm); }
1227        void extractps(const Operand& op, const Xmm& xmm, uint8 imm) { opExt(op, xmm, 0x17, imm); }
1228        void pinsrw(const Mmx& mmx, const Operand& op, int imm)
1229        {
1230                if (!op.isREG(32) && !op.isMEM()) throw ERR_BAD_COMBINATION;
1231                opGen(mmx, op, B11000100, mmx.isXMM() ? 0x66 : NONE, 0, imm);
1232        }
1233        void insertps(const Xmm& xmm, const Operand& op, uint8 imm) { opGen(xmm, op, 0x21, 0x66, isXMM_XMMorMEM, imm, B00111010); }
1234        void pinsrb(const Xmm& xmm, const Operand& op, uint8 imm) { opGen(xmm, op, 0x20, 0x66, isXMM_REG32orMEM, imm, B00111010); }
1235        void pinsrd(const Xmm& xmm, const Operand& op, uint8 imm) { opGen(xmm, op, 0x22, 0x66, isXMM_REG32orMEM, imm, B00111010); }
1236
1237        void pmovmskb(const Reg32e& reg, const Mmx& mmx)
1238        {
1239                if (mmx.isXMM()) db(0x66);
1240                opModR(reg, mmx, 0x0F, B11010111);
1241        }
1242        void maskmovq(const Mmx& reg1, const Mmx& reg2)
1243        {
1244                if (!reg1.isMMX() || !reg2.isMMX()) throw ERR_BAD_COMBINATION;
1245                opModR(reg1, reg2, 0x0F, B11110111);
1246        }
1247        void lea(const Reg32e& reg, const Address& addr) { opModM(addr, reg, B10001101); }
1248
1249        void movmskps(const Reg32e& reg, const Xmm& xmm) { opModR(reg, xmm, 0x0F, B01010000); }
1250        void movmskpd(const Reg32e& reg, const Xmm& xmm) { db(0x66); movmskps(reg, xmm); }
1251        void movntps(const Address& addr, const Xmm& xmm) { opModM(addr, Mmx(xmm.getIdx()), 0x0F, B00101011); }
1252        void movntdqa(const Xmm& xmm, const Address& addr) { db(0x66); opModM(addr, xmm, 0x0F, 0x38, 0x2A); }
1253        void lddqu(const Xmm& xmm, const Address& addr) { db(0xF2); opModM(addr, xmm, 0x0F, B11110000); }
1254        void movnti(const Address& addr, const Reg32e& reg) { opModM(addr, reg, 0x0F, B11000011); }
1255        void movntq(const Address& addr, const Mmx& mmx)
1256        {
1257                if (!mmx.isMMX()) throw ERR_BAD_COMBINATION;
1258                opModM(addr, mmx, 0x0F, B11100111);
1259        }
1260        void popcnt(const Reg& reg, const Operand& op)
1261        {
1262                bool is16bit = reg.isREG(16) && (op.isREG(16) || op.isMEM());
1263                if (!is16bit && !(reg.isREG(i32e) && (op.isREG(i32e) || op.isMEM()))) throw ERR_BAD_COMBINATION;
1264                if (is16bit) db(0x66);
1265                db(0xF3); opModRM(Reg(reg.getIdx(), Operand::REG, i32e == 32 ? 32 : reg.getBit()), op, op.isREG(), true, 0x0F, 0xB8);
1266        }
1267        void crc32(const Reg32e& reg, const Operand& op)
1268        {
1269                if (reg.isBit(32) && op.isBit(16)) db(0x66);
1270                db(0xF2);
1271                opModRM(reg, op, op.isREG(), op.isMEM(), 0x0F, 0x38, 0xF0 | (op.isBit(8) ? 0 : 1));
1272        }
1273public:
1274        enum { NONE = 256 };
1275        CodeGenerator(size_t maxSize = DEFAULT_MAX_CODE_SIZE, void *userPtr = 0)
1276                : CodeArray(maxSize, userPtr)
1277                , mm0(0), mm1(1), mm2(2), mm3(3), mm4(4), mm5(5), mm6(6), mm7(7)
1278                , xmm0(0), xmm1(1), xmm2(2), xmm3(3), xmm4(4), xmm5(5), xmm6(6), xmm7(7)
1279                , xm0(xmm0), xm1(xmm1), xm2(xmm2), xm3(xmm3), xm4(xmm4), xm5(xmm5), xm6(xmm6), xm7(xmm7) // for my convenience
1280                , eax(Operand::EAX), ecx(Operand::ECX), edx(Operand::EDX), ebx(Operand::EBX), esp(Operand::ESP), ebp(Operand::EBP), esi(Operand::ESI), edi(Operand::EDI)
1281                , ax(Operand::EAX), cx(Operand::ECX), dx(Operand::EDX), bx(Operand::EBX), sp(Operand::ESP), bp(Operand::EBP), si(Operand::ESI), di(Operand::EDI)
1282                , al(Operand::AL), cl(Operand::CL), dl(Operand::DL), bl(Operand::BL), ah(Operand::AH), ch(Operand::CH), dh(Operand::DH), bh(Operand::BH)
1283                , ptr(0), byte(8), word(16), dword(32), qword(64)
1284#ifdef XBYAK64
1285                , rax(Operand::RAX), rcx(Operand::RCX), rdx(Operand::RDX), rbx(Operand::RBX), rsp(Operand::RSP), rbp(Operand::RBP), rsi(Operand::RSI), rdi(Operand::RDI), r8(Operand::R8), r9(Operand::R9), r10(Operand::R10), r11(Operand::R11), r12(Operand::R12), r13(Operand::R13), r14(Operand::R14), r15(Operand::R15)
1286                , r8d(Operand::R8D), r9d(Operand::R9D), r10d(Operand::R10D), r11d(Operand::R11D), r12d(Operand::R12D), r13d(Operand::R13D), r14d(Operand::R14D), r15d(Operand::R15D)
1287                , r8w(Operand::R8W), r9w(Operand::R9W), r10w(Operand::R10W), r11w(Operand::R11W), r12w(Operand::R12W), r13w(Operand::R13W), r14w(Operand::R14W), r15w(Operand::R15W)
1288                , r8b(Operand::R8B), r9b(Operand::R9B), r10b(Operand::R10B), r11b(Operand::R11B), r12b(Operand::R12B), r13b(Operand::R13B), r14b(Operand::R14B), r15b(Operand::R15B)
1289                , spl(Operand::SPL, 1), bpl(Operand::BPL, 1), sil(Operand::SIL, 1), dil(Operand::DIL, 1)
1290                , xmm8(8), xmm9(9), xmm10(10), xmm11(11), xmm12(12), xmm13(13), xmm14(14), xmm15(15)
1291                , xm8(xmm8), xm9(xmm9), xm10(xmm10), xm11(xmm11), xm12(xmm12), xm13(xmm13), xm14(xmm14), xm15(xmm15) // for my convenience
1292                , rip()
1293#endif
1294        {
1295                label_.set(this);
1296        }
1297        bool hasUndefinedLabel() const { return label_.hasUndefinedLabel(); }
1298        const uint8 *getCode() const
1299        {
1300                assert(!hasUndefinedLabel());
1301//              if (hasUndefinedLabel()) throw ERR_LABEL_IS_NOT_FOUND;
1302                return top_;
1303        }
1304#ifdef TEST_NM
1305        void dump(bool doClear = true)
1306        {
1307                CodeArray::dump();
1308                if (doClear) size_ = 0;
1309        }
1310#endif
1311
1312#ifndef XBYAK_DONT_READ_LIST
1313#include "xbyak_mnemonic.h"
1314        void align(int x = 16)
1315        {
1316                if (x != 4 && x != 8 && x != 16 && x != 32) throw ERR_BAD_ALIGN;
1317                while (inner::GetPtrDist(getCurr()) % x) {
1318                        nop();
1319                }
1320        }
1321#endif
1322};
1323
1324#ifdef _MSC_VER
1325        #pragma warning(pop)
1326#endif
1327
1328} // end of namespace
1329
1330#endif // XBYAK_H_
Note: See TracBrowser for help on using the browser.