Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / mkl-dnn / src / cpu / xbyak / xbyak.h
index 74d91d4..5c202f4 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
-* Copyright 2016-2018 Intel Corporation
+* Copyright 2016-2019 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -85,6 +85,8 @@
 // This covers -std=(gnu|c)++(0x|11|1y), -stdlib=libc++, and modern Microsoft.
 #if ((defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(_LIBCPP_VERSION) ||\
                                 ((__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)))
+       #include <unordered_set>
+       #define XBYAK_STD_UNORDERED_SET std::unordered_set
        #include <unordered_map>
        #define XBYAK_STD_UNORDERED_MAP std::unordered_map
        #define XBYAK_STD_UNORDERED_MULTIMAP std::unordered_multimap
        libstdcxx 20070719 (from GCC 4.2.1, the last GPL 2 version).
 */
 #elif XBYAK_GNUC_PREREQ(4, 5) || (XBYAK_GNUC_PREREQ(4, 2) && __GLIBCXX__ >= 20070719) || defined(__INTEL_COMPILER) || defined(__llvm__)
+       #include <tr1/unordered_set>
+       #define XBYAK_STD_UNORDERED_SET std::tr1::unordered_set
        #include <tr1/unordered_map>
        #define XBYAK_STD_UNORDERED_MAP std::tr1::unordered_map
        #define XBYAK_STD_UNORDERED_MULTIMAP std::tr1::unordered_multimap
 
 #elif defined(_MSC_VER) && (_MSC_VER >= 1500) && (_MSC_VER < 1600)
+       #include <unordered_set>
+       #define XBYAK_STD_UNORDERED_SET std::tr1::unordered_set
        #include <unordered_map>
        #define XBYAK_STD_UNORDERED_MAP std::tr1::unordered_map
        #define XBYAK_STD_UNORDERED_MULTIMAP std::tr1::unordered_multimap
 
 #else
+       #include <set>
+       #define XBYAK_STD_UNORDERED_SET std::set
        #include <map>
        #define XBYAK_STD_UNORDERED_MAP std::map
        #define XBYAK_STD_UNORDERED_MULTIMAP std::multimap
@@ -150,7 +158,7 @@ namespace Xbyak {
 
 enum {
        DEFAULT_MAX_CODE_SIZE = 4096,
-       VERSION = 0x5631 /* 0xABCD = A.BC(D) */
+       VERSION = 0x5760 /* 0xABCD = A.BC(D) */
 };
 
 #ifndef MIE_INTEGER_TYPE_DEFINED
@@ -223,7 +231,8 @@ enum {
        ERR_INVALID_ZERO,
        ERR_INVALID_RIP_IN_AUTO_GROW,
        ERR_INVALID_MIB_ADDRESS,
-       ERR_INTERNAL
+       ERR_INTERNAL,
+       ERR_X2APIC_IS_NOT_SUPPORTED
 };
 
 class Error : public std::exception {
@@ -285,6 +294,7 @@ public:
                        "invalid rip in AutoGrow",
                        "invalid mib address",
                        "internal error",
+                       "x2APIC is not supported"
                };
                assert((size_t)err_ < sizeof(errTbl) / sizeof(*errTbl));
                return errTbl[err_];
@@ -662,6 +672,12 @@ struct RegRip {
        const Label* label_;
        bool isAddr_;
        explicit RegRip(sint64 disp = 0, const Label* label = 0, bool isAddr = false) : disp_(disp), label_(label), isAddr_(isAddr) {}
+       friend const RegRip operator+(const RegRip& r, int disp) {
+               return RegRip(r.disp_ + disp, r.label_, r.isAddr_);
+       }
+       friend const RegRip operator-(const RegRip& r, int disp) {
+               return RegRip(r.disp_ - disp, r.label_, r.isAddr_);
+       }
        friend const RegRip operator+(const RegRip& r, sint64 disp) {
                return RegRip(r.disp_ + disp, r.label_, r.isAddr_);
        }
@@ -831,6 +847,7 @@ inline RegExp operator-(const RegExp& e, size_t disp)
 
 // 2nd parameter for constructor of CodeArray(maxSize, userPtr, alloc)
 void *const AutoGrow = (void*)1; //-V566
+void *const DontSetProtectRWE = (void*)2; //-V566
 
 class CodeArray {
        enum Type {
@@ -870,6 +887,7 @@ protected:
        size_t size_;
        bool isCalledCalcJmpAddress_;
 
+       bool useProtect() const { return alloc_->useProtect(); }
        /*
                allocate new memory and copy old data to the new area
        */
@@ -893,12 +911,16 @@ protected:
                        uint64 disp = i->getVal(top_);
                        rewrite(i->codeOffset, disp, i->jmpSize);
                }
-               if (alloc_->useProtect() && !protect(top_, size_, true)) throw Error(ERR_CANT_PROTECT);
                isCalledCalcJmpAddress_ = true;
        }
 public:
+       enum ProtectMode {
+               PROTECT_RW = 0, // read/write
+               PROTECT_RWE = 1, // read/write/exec
+               PROTECT_RE = 2 // read/exec
+       };
        explicit CodeArray(size_t maxSize, void *userPtr = 0, Allocator *allocator = 0)
-               : type_(userPtr == AutoGrow ? AUTO_GROW : userPtr ? USER_BUF : ALLOC_BUF)
+               : type_(userPtr == AutoGrow ? AUTO_GROW : (userPtr == 0 || userPtr == DontSetProtectRWE) ? ALLOC_BUF : USER_BUF)
                , alloc_(allocator ? allocator : (Allocator*)&defaultAllocator_)
                , maxSize_(maxSize)
                , top_(type_ == USER_BUF ? reinterpret_cast<uint8*>(userPtr) : alloc_->alloc((std::max<size_t>)(maxSize, 1)))
@@ -906,7 +928,7 @@ public:
                , isCalledCalcJmpAddress_(false)
        {
                if (maxSize_ > 0 && top_ == 0) throw Error(ERR_CANT_ALLOC);
-               if ((type_ == ALLOC_BUF && alloc_->useProtect()) && !protect(top_, maxSize, true)) {
+               if ((type_ == ALLOC_BUF && userPtr != DontSetProtectRWE && useProtect()) && !setProtectMode(PROTECT_RWE, false)) {
                        alloc_->free(top_);
                        throw Error(ERR_CANT_PROTECT);
                }
@@ -914,10 +936,19 @@ public:
        virtual ~CodeArray()
        {
                if (isAllocType()) {
-                       if (alloc_->useProtect()) protect(top_, maxSize_, false);
+                       if (useProtect()) setProtectModeRW(false);
                        alloc_->free(top_);
                }
        }
+       bool setProtectMode(ProtectMode mode, bool throwException = true)
+       {
+               bool isOK = protect(top_, maxSize_, mode);
+               if (isOK) return true;
+               if (throwException) throw Error(ERR_CANT_PROTECT);
+               return false;
+       }
+       bool setProtectModeRE(bool throwException = true) { return setProtectMode(PROTECT_RE, throwException); }
+       bool setProtectModeRW(bool throwException = true) { return setProtectMode(PROTECT_RW, throwException); }
        void resetSize()
        {
                size_ = 0;
@@ -949,10 +980,10 @@ public:
        void dq(uint64 code) { db(code, 8); }
        const uint8 *getCode() const { return top_; }
        template<class F>
-       const F getCode() const { return CastTo<F>(top_); }
+       const F getCode() const { return reinterpret_cast<F>(top_); }
        const uint8 *getCurr() const { return &top_[size_]; }
        template<class F>
-       const F getCurr() const { return CastTo<F>(&top_[size_]); }
+       const F getCurr() const { return reinterpret_cast<F>(&top_[size_]); }
        size_t getSize() const { return size_; }
        void setSize(size_t size)
        {
@@ -1005,19 +1036,39 @@ public:
                change exec permission of memory
                @param addr [in] buffer address
                @param size [in] buffer size
-               @param canExec [in] true(enable to exec), false(disable to exec)
+               @param protectMode [in] mode(RW/RWE/RE)
                @return true(success), false(failure)
        */
-       static inline bool protect(const void *addr, size_t size, bool canExec)
+       static inline bool protect(const void *addr, size_t size, int protectMode)
        {
 #if defined(_WIN32)
+               const DWORD c_rw = PAGE_READWRITE;
+               const DWORD c_rwe = PAGE_EXECUTE_READWRITE;
+               const DWORD c_re = PAGE_EXECUTE_READ;
+               DWORD mode;
+#else
+               const int c_rw = PROT_READ | PROT_WRITE;
+               const int c_rwe = PROT_READ | PROT_WRITE | PROT_EXEC;
+               const int c_re = PROT_READ | PROT_EXEC;
+               int mode;
+#endif
+               switch (protectMode) {
+               case PROTECT_RW: mode = c_rw; break;
+               case PROTECT_RWE: mode = c_rwe; break;
+               case PROTECT_RE: mode = c_re; break;
+               default:
+                       return false;
+               }
+#if defined(_WIN32)
                DWORD oldProtect;
-               return VirtualProtect(const_cast<void*>(addr), size, canExec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldProtect) != 0;
+               return VirtualProtect(const_cast<void*>(addr), size, mode, &oldProtect) != 0;
 #elif defined(__GNUC__)
                size_t pageSize = sysconf(_SC_PAGESIZE);
                size_t iaddr = reinterpret_cast<size_t>(addr);
                size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
-               int mode = PROT_READ | PROT_WRITE | (canExec ? PROT_EXEC : 0);
+#ifndef NDEBUG
+               if (pageSize != 4096) fprintf(stderr, "large page(%zd) is used. not tested enough.\n", pageSize);
+#endif
                return mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode) == 0;
 #else
                return true;
@@ -1044,46 +1095,43 @@ public:
                M_ripAddr
        };
        Address(uint32 sizeBit, bool broadcast, const RegExp& e)
-               : Operand(0, MEM, sizeBit), e_(e), label_(0), mode_(M_ModRM), permitVsib_(false), broadcast_(broadcast)
+               : Operand(0, MEM, sizeBit), e_(e), label_(0), mode_(M_ModRM), broadcast_(broadcast)
        {
                e_.verify();
        }
 #ifdef XBYAK64
        explicit Address(size_t disp)
-               : Operand(0, MEM, 64), e_(disp), label_(0), mode_(M_64bitDisp), permitVsib_(false), broadcast_(false){ }
+               : Operand(0, MEM, 64), e_(disp), label_(0), mode_(M_64bitDisp), broadcast_(false){ }
        Address(uint32 sizeBit, bool broadcast, const RegRip& addr)
-               : Operand(0, MEM, sizeBit), e_(addr.disp_), label_(addr.label_), mode_(addr.isAddr_ ? M_ripAddr : M_rip), permitVsib_(false), broadcast_(broadcast) { }
+               : Operand(0, MEM, sizeBit), e_(addr.disp_), label_(addr.label_), mode_(addr.isAddr_ ? M_ripAddr : M_rip), broadcast_(broadcast) { }
 #endif
-       void permitVsib() const { permitVsib_ = true; }
        RegExp getRegExp(bool optimize = true) const
        {
                return optimize ? e_.optimize() : e_;
        }
        Mode getMode() const { return mode_; }
-       bool is32bit() const { verify(); return e_.getBase().getBit() == 32 || e_.getIndex().getBit() == 32; }
-       bool isOnlyDisp() const { verify(); return !e_.getBase().getBit() && !e_.getIndex().getBit(); } // for mov eax
-       size_t getDisp() const { verify(); return e_.getDisp(); }
+       bool is32bit() const { return e_.getBase().getBit() == 32 || e_.getIndex().getBit() == 32; }
+       bool isOnlyDisp() const { return !e_.getBase().getBit() && !e_.getIndex().getBit(); } // for mov eax
+       size_t getDisp() const { return e_.getDisp(); }
        uint8 getRex() const
        {
-               verify();
                if (mode_ != M_ModRM) return 0;
                return getRegExp().getRex();
        }
-       bool is64bitDisp() const { verify(); return mode_ == M_64bitDisp; } // for moffset
+       bool is64bitDisp() const { return mode_ == M_64bitDisp; } // for moffset
        bool isBroadcast() const { return broadcast_; }
        const Label* getLabel() const { return label_; }
        bool operator==(const Address& rhs) const
        {
-               return getBit() == rhs.getBit() && e_ == rhs.e_ && label_ == rhs.label_ && mode_ == rhs.mode_ && permitVsib_ == rhs.permitVsib_ && broadcast_ == rhs.broadcast_;
+               return getBit() == rhs.getBit() && e_ == rhs.e_ && label_ == rhs.label_ && mode_ == rhs.mode_ && broadcast_ == rhs.broadcast_;
        }
        bool operator!=(const Address& rhs) const { return !operator==(rhs); }
+       bool isVsib() const { return e_.isVsib(); }
 private:
        RegExp e_;
        const Label* label_;
        Mode mode_;
-       mutable bool permitVsib_;
        bool broadcast_;
-       void verify() const { if (e_.isVsib() && !permitVsib_) throw Error(ERR_BAD_VSIB_ADDRESSING); }
 };
 
 inline const Address& Operand::getAddress() const
@@ -1141,6 +1189,7 @@ public:
        Label(const Label& rhs);
        Label& operator=(const Label& rhs);
        ~Label();
+       void clear() { mgr = 0; id = 0; }
        int getId() const { return id; }
        const uint8 *getAddress() const;
 
@@ -1179,6 +1228,7 @@ class LabelManager {
        };
        typedef XBYAK_STD_UNORDERED_MAP<int, ClabelVal> ClabelDefList;
        typedef XBYAK_STD_UNORDERED_MULTIMAP<int, const JmpLabel> ClabelUndefList;
+       typedef XBYAK_STD_UNORDERED_SET<Label*> LabelPtrList;
 
        CodeArray *base_;
        // global : stateList_.front(), local : stateList_.back()
@@ -1186,6 +1236,7 @@ class LabelManager {
        mutable int labelId_;
        ClabelDefList clabelDefList_;
        ClabelUndefList clabelUndefList_;
+       LabelPtrList labelPtrList_;
 
        int getId(const Label& label) const
        {
@@ -1234,9 +1285,14 @@ class LabelManager {
                return true;
        }
        friend class Label;
-       void incRefCount(int id) { clabelDefList_[id].refCount++; }
-       void decRefCount(int id)
+       void incRefCount(int id, Label *label)
        {
+               clabelDefList_[id].refCount++;
+               labelPtrList_.insert(label);
+       }
+       void decRefCount(int id, Label *label)
+       {
+               labelPtrList_.erase(label);
                ClabelDefList::iterator i = clabelDefList_.find(id);
                if (i == clabelDefList_.end()) return;
                if (i->second.refCount == 1) {
@@ -1255,11 +1311,23 @@ class LabelManager {
 #endif
                return !list.empty();
        }
+       // detach all labels linked to LabelManager
+       void resetLabelPtrList()
+       {
+               for (LabelPtrList::iterator i = labelPtrList_.begin(), ie = labelPtrList_.end(); i != ie; ++i) {
+                       (*i)->clear();
+               }
+               labelPtrList_.clear();
+       }
 public:
        LabelManager()
        {
                reset();
        }
+       ~LabelManager()
+       {
+               resetLabelPtrList();
+       }
        void reset()
        {
                base_ = 0;
@@ -1269,6 +1337,7 @@ public:
                stateList_.push_back(SlabelState());
                clabelDefList_.clear();
                clabelUndefList_.clear();
+               resetLabelPtrList();
        }
        void enterLocal()
        {
@@ -1301,10 +1370,11 @@ public:
                SlabelState& st = *label.c_str() == '.' ? stateList_.back() : stateList_.front();
                define_inner(st.defList, st.undefList, label, base_->getSize());
        }
-       void defineClabel(const Label& label)
+       void defineClabel(Label& label)
        {
                define_inner(clabelDefList_, clabelUndefList_, getId(label), base_->getSize());
                label.mgr = this;
+               labelPtrList_.insert(&label);
        }
        void assign(Label& dst, const Label& src)
        {
@@ -1312,6 +1382,7 @@ public:
                if (i == clabelDefList_.end()) throw Error(ERR_LABEL_ISNOT_SET_BY_L);
                define_inner(clabelDefList_, clabelUndefList_, dst.id, i->second.offset);
                dst.mgr = this;
+               labelPtrList_.insert(&dst);
        }
        bool getOffset(size_t *offset, std::string& label) const
        {
@@ -1359,19 +1430,19 @@ inline Label::Label(const Label& rhs)
 {
        id = rhs.id;
        mgr = rhs.mgr;
-       if (mgr) mgr->incRefCount(id);
+       if (mgr) mgr->incRefCount(id, this);
 }
 inline Label& Label::operator=(const Label& rhs)
 {
        if (id) throw Error(ERR_LABEL_IS_ALREADY_SET_BY_L);
        id = rhs.id;
        mgr = rhs.mgr;
-       if (mgr) mgr->incRefCount(id);
+       if (mgr) mgr->incRefCount(id, this);
        return *this;
 }
 inline Label::~Label()
 {
-       if (id && mgr) mgr->decRefCount(id);
+       if (id && mgr) mgr->decRefCount(id, this);
 }
 inline const uint8* Label::getAddress() const
 {
@@ -1488,6 +1559,8 @@ private:
                T_B32 = 1 << 26, // m32bcst
                T_B64 = 1 << 27, // m64bcst
                T_M_K = 1 << 28, // mem{k}
+               T_VSIB = 1 << 29,
+               T_MEM_EVEX = 1 << 30, // use evex if mem
                T_XXX
        };
        void vex(const Reg& reg, const Reg& base, const Operand *v, int type, int code, bool x = false)
@@ -1525,7 +1598,7 @@ private:
                if ((a > 0 && a != v) + (b > 0 && b != v) + (c > 0 && c != v) > 0) return Error(err);
                return v;
        }
-       int evex(const Reg& reg, const Reg& base, const Operand *v, int type, int code, bool x = false, bool b = false, int aaa = 0, uint32 VL = 0)
+       int evex(const Reg& reg, const Reg& base, const Operand *v, int type, int code, bool x = false, bool b = false, int aaa = 0, uint32 VL = 0, bool Hi16Vidx = false)
        {
                if (!(type & (T_EVEX | T_MUST_EVEX))) throw Error(ERR_EVEX_IS_INVALID);
                int w = (type & T_EW1) ? 1 : 0;
@@ -1568,7 +1641,7 @@ private:
                                }
                        }
                }
-               bool Vp = !(v ? v->isExtIdx2() : 0);
+               bool Vp = !((v ? v->isExtIdx2() : 0) | Hi16Vidx);
                bool z = reg.hasZero() || base.hasZero() || (v ? v->hasZero() : false);
                if (aaa == 0) aaa = verifyDuplicate(base.getOpmaskIdx(), reg.getOpmaskIdx(), (v ? v->getOpmaskIdx() : 0), ERR_OPMASK_IS_ALREADY_SET);
                db(0x62);
@@ -1714,8 +1787,9 @@ private:
        // reg is reg field of ModRM
        // immSize is the size for immediate value
        // disp8N = 0(normal), disp8N = 1(force disp32), disp8N = {2, 4, 8} ; compressed displacement
-       void opAddr(const Address &addr, int reg, int immSize = 0, int disp8N = 0)
+       void opAddr(const Address &addr, int reg, int immSize = 0, int disp8N = 0, bool permitVisb = false)
        {
+               if (!permitVisb && addr.isVsib()) throw Error(ERR_BAD_VSIB_ADDRESSING);
                if (addr.getMode() == Address::M_ModRM) {
                        setSIB(addr.getRegExp(), reg, disp8N);
                } else if (addr.getMode() == Address::M_rip || addr.getMode() == Address::M_ripAddr) {
@@ -1857,15 +1931,20 @@ private:
        }
        void opPushPop(const Operand& op, int code, int ext, int alt)
        {
-               if (op.isREG()) {
-                       if (op.isBit(16)) db(0x66);
-                       if (op.getReg().getIdx() >= 8) db(0x41);
-                       db(alt | (op.getIdx() & 7));
-               } else if (op.isMEM()) {
-                       opModM(op.getAddress(), Reg(ext, Operand::REG, op.getBit()), code);
-               } else {
-                       throw Error(ERR_BAD_COMBINATION);
+               int bit = op.getBit();
+               if (bit == 16 || bit == BIT) {
+                       if (bit == 16) db(0x66);
+                       if (op.isREG()) {
+                               if (op.getReg().getIdx() >= 8) db(0x41);
+                               db(alt | (op.getIdx() & 7));
+                               return;
+                       }
+                       if (op.isMEM()) {
+                               opModM(op.getAddress(), Reg(ext, Operand::REG, 32), code);
+                               return;
+                       }
                }
+               throw Error(ERR_BAD_COMBINATION);
        }
        void verifyMemHasSize(const Operand& op) const
        {
@@ -1954,10 +2033,11 @@ private:
                        const Address& addr = op2.getAddress();
                        const RegExp& regExp = addr.getRegExp();
                        const Reg& base = regExp.getBase();
+                       const Reg& index = regExp.getIndex();
                        if (BIT == 64 && addr.is32bit()) db(0x67);
                        int disp8N = 0;
-                       bool x = regExp.getIndex().isExtIdx();
-                       if ((type & T_MUST_EVEX) || r.hasEvex() || (p1 && p1->hasEvex()) || addr.isBroadcast() || addr.getOpmaskIdx()) {
+                       bool x = index.isExtIdx();
+                       if ((type & (T_MUST_EVEX|T_MEM_EVEX)) || r.hasEvex() || (p1 && p1->hasEvex()) || addr.isBroadcast() || addr.getOpmaskIdx()) {
                                int aaa = addr.getOpmaskIdx();
                                if (aaa && !(type & T_M_K)) throw Error(ERR_INVALID_OPMASK_WITH_MEMORY);
                                bool b = false;
@@ -1965,12 +2045,12 @@ private:
                                        if (!(type & (T_B32 | T_B64))) throw Error(ERR_INVALID_BROADCAST);
                                        b = true;
                                }
-                               int VL = regExp.isVsib() ? regExp.getIndex().getBit() : 0;
-                               disp8N = evex(r, base, p1, type, code, x, b, aaa, VL);
+                               int VL = regExp.isVsib() ? index.getBit() : 0;
+                               disp8N = evex(r, base, p1, type, code, x, b, aaa, VL, index.isExtIdx2());
                        } else {
                                vex(r, base, p1, type, code, x);
                        }
-                       opAddr(addr, r.getIdx(), (imm8 != NONE) ? 1 : 0, disp8N);
+                       opAddr(addr, r.getIdx(), (imm8 != NONE) ? 1 : 0, disp8N, (type & T_VSIB) != 0);
                } else {
                        const Reg& base = op2.getReg();
                        if ((type & T_MUST_EVEX) || r.hasEvex() || (p1 && p1->hasEvex()) || base.hasEvex()) {
@@ -2071,8 +2151,7 @@ private:
                        }
                        if (!isOK) throw Error(ERR_BAD_VSIB_ADDRESSING);
                }
-               addr.permitVsib();
-               opAVX_X_X_XM(isAddrYMM ? Ymm(x1.getIdx()) : x1, isAddrYMM ? Ymm(x2.getIdx()) : x2, addr, type | T_YMM, code);
+               opAVX_X_X_XM(isAddrYMM ? Ymm(x1.getIdx()) : x1, isAddrYMM ? Ymm(x2.getIdx()) : x2, addr, type, code);
        }
        enum {
                xx_yy_zz = 0,
@@ -2096,7 +2175,6 @@ private:
        {
                if (x.hasZero()) throw Error(ERR_INVALID_ZERO);
                checkGather2(x, addr.getRegExp().getIndex(), mode);
-               addr.permitVsib();
                opVex(x, 0, addr, type, code);
        }
        /*
@@ -2116,7 +2194,6 @@ private:
        {
                if (addr.hasZero()) throw Error(ERR_INVALID_ZERO);
                if (addr.getRegExp().getIndex().getKind() != kind) throw Error(ERR_BAD_VSIB_ADDRESSING);
-               addr.permitVsib();
                opVex(x, 0, addr, type, code);
        }
 public:
@@ -2169,7 +2246,8 @@ public:
        const Segment es, cs, ss, ds, fs, gs;
 #endif
        void L(const std::string& label) { labelMgr_.defineSlabel(label); }
-       void L(const Label& label) { labelMgr_.defineClabel(label); }
+       void L(Label& label) { labelMgr_.defineClabel(label); }
+       Label L() { Label label; L(label); return label; }
        void inLocalLabel() { labelMgr_.enterLocal(); }
        void outLocalLabel() { labelMgr_.leaveLocal(); }
        /*
@@ -2200,7 +2278,7 @@ public:
        // call(function pointer)
 #ifdef XBYAK_VARIADIC_TEMPLATE
        template<class Ret, class... Params>
-       void call(Ret(*func)(Params...)) { call(CastTo<const void*>(func)); }
+       void call(Ret(*func)(Params...)) { call(reinterpret_cast<const void*>(func)); }
 #endif
        void call(const void *addr) { opJmpAbs(addr, T_NEAR, 0, 0xE8); }
 
@@ -2458,11 +2536,16 @@ public:
                MUST call ready() to complete generating code if you use AutoGrow mode.
                It is not necessary for the other mode if hasUndefinedLabel() is true.
        */
-       void ready()
+       void ready(ProtectMode mode = PROTECT_RWE)
        {
                if (hasUndefinedLabel()) throw Error(ERR_LABEL_IS_NOT_FOUND);
-               if (isAutoGrow()) calcJmpAddress();
+               if (isAutoGrow()) {
+                       calcJmpAddress();
+                       if (useProtect()) setProtectMode(mode);
+               }
        }
+       // set read/exec
+       void readyRE() { return ready(PROTECT_RE); }
 #ifdef XBYAK_TEST
        void dump(bool doClear = true)
        {