diff --git a/README.md b/README.md index 233d147..47de201 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ Supported Environments * **Clang** - tested by Travis-CI - Clang 3.9+ (with C++11 enabled) is officially supported (older Clang versions having C++11 support are probably fine, but are not regularly tested). * **GNU** - tested by Travis-CI - GCC 4.8+ (with C++11 enabled) is officially supported. * **MINGW** - tested by Travis-CI - Use the latest version, if possible. - * **MSVC** - tested by Travis-CI - **MSVC2017+ only!** - there is a severe bug in MSVC2015's `constexpr` implementation that makes that compiler unusable. + * **MSVC** - tested by Travis-CI - VS2017+ is officially supported, VC2015 is reported to work. * Untested: * **Intel** - no maintainers and no CI environment to regularly test this compiler. * Other c++ compilers would require basic support in [core/build.h](./src/asmjit/core/build.h). diff --git a/src/asmjit/core/build.h b/src/asmjit/core/build.h index 894fdef..74c1413 100644 --- a/src/asmjit/core/build.h +++ b/src/asmjit/core/build.h @@ -250,13 +250,6 @@ #define ASMJIT_CXX_MSC ASMJIT_CXX_MAKE_VER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) #endif - // SEVERE: VS2015 handles constexpr's incorrectly in case a struct contains a - // union. There is no workaround known other than rewriting the whole - // code. VS2017 has a similar bug, but it can be workarounded. - #if ASMJIT_CXX_MSC < ASMJIT_CXX_MAKE_VER(19, 10, 0) - #error "[asmjit] At least VS2017 is required due to a severe bug in VS2015's constexpr implementation" - #endif - // Clang Compiler [Pretends to be GNU, so it must be checked before]: // - https://clang.llvm.org/cxx_status.html #elif defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) diff --git a/src/asmjit/core/operand.cpp b/src/asmjit/core/operand.cpp index 82040c0..36f0c6f 100644 --- a/src/asmjit/core/operand.cpp +++ b/src/asmjit/core/operand.cpp @@ -33,7 +33,8 @@ UNIT(operand) { EXPECT(a.isImm() == false); EXPECT(a.isLabel() == false); EXPECT(a == b); - EXPECT(a._data64 == 0); + EXPECT(a._data[0] == 0); + EXPECT(a._data[1] == 0); INFO("Checking basic functionality of Label"); Label label; @@ -43,7 +44,8 @@ UNIT(operand) { INFO("Checking basic functionality of BaseReg"); EXPECT(BaseReg().isReg() == true); EXPECT(BaseReg().isValid() == false); - EXPECT(BaseReg()._data64 == 0); + EXPECT(BaseReg()._data[0] == 0); + EXPECT(BaseReg()._data[1] == 0); EXPECT(dummy.as().isValid() == false); // Create some register (not specific to any architecture). @@ -63,7 +65,8 @@ UNIT(operand) { EXPECT(r1.size() == 8); EXPECT(r1.id() == 5); EXPECT(r1.isReg(1, 5) == true); // RegType and Id. - EXPECT(r1._data64 == 0); + EXPECT(r1._data[0] == 0); + EXPECT(r1._data[1] == 0); // The same type of register having different id. BaseReg r2(r1, 6); @@ -107,6 +110,8 @@ UNIT(operand) { INFO("Checking basic functionality of Imm"); EXPECT(Imm(-1).i64() == int64_t(-1)); + EXPECT(imm(-1).i64() == int64_t(-1)); + EXPECT(imm(0xFFFFFFFF).i64() == int64_t(0xFFFFFFFF)); } #endif diff --git a/src/asmjit/core/operand.h b/src/asmjit/core/operand.h index 27610dc..5d88172 100644 --- a/src/asmjit/core/operand.h +++ b/src/asmjit/core/operand.h @@ -113,6 +113,24 @@ struct Operand_ { //! Either base id as used by memory operand or any id as used by others. uint32_t _baseId; + //! Data specific to the operand type. + //! + //! The reason we don't use union is that we have `constexpr` constructors that + //! construct operands and other `constexpr` functions that return wither another + //! Operand or something else. These cannot generally work with unions so we also + //! cannot use `union` if we want to be standard compliant. + uint32_t _data[2]; + + //! Indexes to `_data` array. + enum DataIndex : uint32_t { + kDataMemIndexId = 0, + kDataMemOffsetLo = 1, + + kDataImmValueLo = ASMJIT_ARCH_LE ? 0 : 1, + kDataImmValueHi = ASMJIT_ARCH_LE ? 1 : 0 + }; + + /* //! Memory operand data. struct MemData { //! Index register id. @@ -131,6 +149,7 @@ struct Operand_ { //! Memory address data. MemData _mem; }; + */ //! Operand types that can be encoded in `Operand`. enum OpType : uint32_t { @@ -227,7 +246,8 @@ struct Operand_ { inline void _initReg(uint32_t signature, uint32_t id) noexcept { _signature = signature; _baseId = id; - _data64 = 0; + _data[0] = 0; + _data[1] = 0; } //! Initializes the operand from `other` (used by operator overloads). @@ -265,7 +285,8 @@ struct Operand_ { inline void reset() noexcept { _signature = 0; _baseId = 0; - _data64 = 0; + _data[0] = 0; + _data[1] = 0; } //! \} @@ -382,7 +403,8 @@ struct Operand_ { constexpr bool isEqual(const Operand_& other) const noexcept { return (_signature == other._signature) & (_baseId == other._baseId ) & - (_data64 == other._data64 ) ; + (_data[0] == other._data[0] ) & + (_data[1] == other._data[1] ) ; } //! Tests whether the operand is a register matching `rType`. @@ -416,7 +438,7 @@ public: //! Creates `kOpNone` operand having all members initialized to zero. constexpr Operand() noexcept - : Operand_{ kOpNone, 0u, {{ 0u, 0u }}} {} + : Operand_{ kOpNone, 0u, { 0u, 0u }} {} //! Creates a cloned `other` operand. constexpr Operand(const Operand& other) noexcept = default; @@ -427,7 +449,7 @@ public: //! Creates an operand initialized to raw `[u0, u1, u2, u3]` values. constexpr Operand(Globals::Init_, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) noexcept - : Operand_{ u0, u1, {{ u2, u3 }}} {} + : Operand_{ u0, u1, { u2, u3 }} {} //! Creates an uninitialized operand (dangerous). inline explicit Operand(Globals::NoInit_) noexcept {} @@ -533,7 +555,8 @@ public: inline void reset() noexcept { _signature = kOpLabel; _baseId = Globals::kInvalidId; - _data64 = 0; + _data[0] = 0; + _data[1] = 0; } //! \} @@ -990,7 +1013,8 @@ public: inline void reset() noexcept { _signature = kOpMem; _baseId = 0; - _data64 = 0; + _data[0] = 0; + _data[1] = 0; } //! \} @@ -1061,12 +1085,12 @@ public: constexpr uint32_t baseId() const noexcept { return _baseId; } //! Returns the id of the INDEX register. - constexpr uint32_t indexId() const noexcept { return _mem.indexId; } + constexpr uint32_t indexId() const noexcept { return _data[kDataMemIndexId]; } //! Sets the id of the BASE register (without modifying its type). inline void setBaseId(uint32_t rId) noexcept { _baseId = rId; } //! Sets the id of the INDEX register (without modifying its type). - inline void setIndexId(uint32_t rId) noexcept { _mem.indexId = rId; } + inline void setIndexId(uint32_t rId) noexcept { _data[kDataMemIndexId] = rId; } //! Sets the base register to type and id of the given `base` operand. inline void setBase(const BaseReg& base) noexcept { return _setBase(base.type(), base.id()); } @@ -1080,7 +1104,7 @@ public: inline void _setIndex(uint32_t rType, uint32_t rId) noexcept { _setSignaturePart(rType); - _mem.indexId = rId; + _data[kDataMemIndexId] = rId; } //! Resets the memory operand's BASE register or label. @@ -1098,17 +1122,17 @@ public: //! Tests whether the memory operand has a non-zero offset or absolute address. constexpr bool hasOffset() const noexcept { - return (_mem.offsetLo32 | uint32_t(_baseId & Support::bitMaskFromBool(isOffset64Bit()))) != 0; + return (_data[kDataMemOffsetLo] | uint32_t(_baseId & Support::bitMaskFromBool(isOffset64Bit()))) != 0; } //! Returns either relative offset or absolute address as 64-bit integer. constexpr int64_t offset() const noexcept { - return isOffset64Bit() ? int64_t(uint64_t(_mem.offsetLo32) | (uint64_t(_baseId) << 32)) - : int64_t(int32_t(_mem.offsetLo32)); // Sign extend 32-bit offset. + return isOffset64Bit() ? int64_t(uint64_t(_data[kDataMemOffsetLo]) | (uint64_t(_baseId) << 32)) + : int64_t(int32_t(_data[kDataMemOffsetLo])); // Sign extend 32-bit offset. } //! Returns a 32-bit low part of a 64-bit offset or absolute address. - constexpr int32_t offsetLo32() const noexcept { return int32_t(_mem.offsetLo32); } + constexpr int32_t offsetLo32() const noexcept { return int32_t(_data[kDataMemOffsetLo]); } //! Returns a 32-but high part of a 64-bit offset or absolute address. //! //! \note This function is UNSAFE and returns garbage if `isOffset64Bit()` @@ -1127,11 +1151,11 @@ public: uint32_t hi = uint32_t(uint64_t(offset) >> 32); uint32_t hiMsk = Support::bitMaskFromBool(isOffset64Bit()); - _mem.offsetLo32 = lo; + _data[kDataMemOffsetLo] = lo; _baseId = (hi & hiMsk) | (_baseId & ~hiMsk); } //! Sets a low 32-bit offset to `offset` (don't use without knowing how BaseMem works). - inline void setOffsetLo32(int32_t offset) noexcept { _mem.offsetLo32 = uint32_t(offset); } + inline void setOffsetLo32(int32_t offset) noexcept { _data[kDataMemOffsetLo] = uint32_t(offset); } //! Adjusts the offset by `offset`. //! @@ -1142,18 +1166,18 @@ public: //! Adjusts the offset by a 64-bit `offset`. inline void addOffset(int64_t offset) noexcept { if (isOffset64Bit()) { - int64_t result = offset + int64_t(uint64_t(_mem.offsetLo32) | (uint64_t(_baseId) << 32)); - _mem.offsetLo32 = uint32_t(uint64_t(result) & 0xFFFFFFFFu); - _baseId = uint32_t(uint64_t(result) >> 32); + int64_t result = offset + int64_t(uint64_t(_data[kDataMemOffsetLo]) | (uint64_t(_baseId) << 32)); + _data[kDataMemOffsetLo] = uint32_t(uint64_t(result) & 0xFFFFFFFFu); + _baseId = uint32_t(uint64_t(result) >> 32); } else { - _mem.offsetLo32 += uint32_t(uint64_t(offset) & 0xFFFFFFFFu); + _data[kDataMemOffsetLo] += uint32_t(uint64_t(offset) & 0xFFFFFFFFu); } } //! Adds `offset` to a low 32-bit offset part (don't use without knowing how //! BaseMem works). - inline void addOffsetLo32(int32_t offset) noexcept { _mem.offsetLo32 += uint32_t(offset); } + inline void addOffsetLo32(int32_t offset) noexcept { _data[kDataMemOffsetLo] += uint32_t(offset); } //! Resets the memory offset to zero. inline void resetOffset() noexcept { setOffset(0); } @@ -1210,76 +1234,77 @@ public: //! \name Accessors //! \{ - //! Tests whether the immediate can be casted to 8-bit signed integer. - constexpr bool isInt8() const noexcept { return Support::isInt8(int64_t(_data64)); } - //! Tests whether the immediate can be casted to 8-bit unsigned integer. - constexpr bool isUInt8() const noexcept { return Support::isUInt8(int64_t(_data64)); } - //! Tests whether the immediate can be casted to 16-bit signed integer. - constexpr bool isInt16() const noexcept { return Support::isInt16(int64_t(_data64)); } - //! Tests whether the immediate can be casted to 16-bit unsigned integer. - constexpr bool isUInt16() const noexcept { return Support::isUInt16(int64_t(_data64)); } - //! Tests whether the immediate can be casted to 32-bit signed integer. - constexpr bool isInt32() const noexcept { return Support::isInt32(int64_t(_data64)); } - //! Tests whether the immediate can be casted to 32-bit unsigned integer. - constexpr bool isUInt32() const noexcept { return Support::isUInt32(int64_t(_data64)); } - //! Returns immediate value as 8-bit signed integer, possibly cropped. - constexpr int8_t i8() const noexcept { return int8_t(_data64 & 0xFFu); } + constexpr int8_t i8() const noexcept { return int8_t(_data[kDataImmValueLo] & 0xFFu); } //! Returns immediate value as 8-bit unsigned integer, possibly cropped. - constexpr uint8_t u8() const noexcept { return uint8_t(_data64 & 0xFFu); } + constexpr uint8_t u8() const noexcept { return uint8_t(_data[kDataImmValueLo] & 0xFFu); } //! Returns immediate value as 16-bit signed integer, possibly cropped. - constexpr int16_t i16() const noexcept { return int16_t(_data64 & 0xFFFFu);} + constexpr int16_t i16() const noexcept { return int16_t(_data[kDataImmValueLo] & 0xFFFFu);} //! Returns immediate value as 16-bit unsigned integer, possibly cropped. - constexpr uint16_t u16() const noexcept { return uint16_t(_data64 & 0xFFFFu);} + constexpr uint16_t u16() const noexcept { return uint16_t(_data[kDataImmValueLo] & 0xFFFFu);} //! Returns immediate value as 32-bit signed integer, possibly cropped. - constexpr int32_t i32() const noexcept { return int32_t(_data64 & 0xFFFFFFFFu); } + constexpr int32_t i32() const noexcept { return int32_t(_data[kDataImmValueLo]); } //! Returns low 32-bit signed integer. - constexpr int32_t i32Lo() const noexcept { return int32_t(_data64 & 0xFFFFFFFFu); } + constexpr int32_t i32Lo() const noexcept { return int32_t(_data[kDataImmValueLo]); } //! Returns high 32-bit signed integer. - constexpr int32_t i32Hi() const noexcept { return int32_t(_data64 >> 32); } + constexpr int32_t i32Hi() const noexcept { return int32_t(_data[kDataImmValueHi]); } //! Returns immediate value as 32-bit unsigned integer, possibly cropped. - constexpr uint32_t u32() const noexcept { return uint32_t(_data64 & 0xFFFFFFFFu); } + constexpr uint32_t u32() const noexcept { return _data[kDataImmValueLo]; } //! Returns low 32-bit signed integer. - constexpr uint32_t u32Lo() const noexcept { return uint32_t(_data64 & 0xFFFFFFFFu); } + constexpr uint32_t u32Lo() const noexcept { return _data[kDataImmValueLo]; } //! Returns high 32-bit signed integer. - constexpr uint32_t u32Hi() const noexcept { return uint32_t(_data64 >> 32); } + constexpr uint32_t u32Hi() const noexcept { return _data[kDataImmValueHi]; } //! Returns immediate value as 64-bit signed integer. - constexpr int64_t i64() const noexcept { return int64_t(_data64); } + constexpr int64_t i64() const noexcept { return int64_t((uint64_t(_data[kDataImmValueHi]) << 32) | _data[kDataImmValueLo]); } //! Returns immediate value as 64-bit unsigned integer. - constexpr uint64_t u64() const noexcept { return _data64; } + constexpr uint64_t u64() const noexcept { return uint64_t(i64()); } //! Returns immediate value as `intptr_t`, possibly cropped if size of `intptr_t` is 32 bits. - constexpr intptr_t iptr() const noexcept { return (sizeof(intptr_t) == sizeof(int64_t)) ? intptr_t(_data64) : intptr_t(i32()); } + constexpr intptr_t iptr() const noexcept { return (sizeof(intptr_t) == sizeof(int64_t)) ? intptr_t(i64()) : intptr_t(i32()); } //! Returns immediate value as `uintptr_t`, possibly cropped if size of `uintptr_t` is 32 bits. - constexpr uintptr_t uptr() const noexcept { return (sizeof(uintptr_t) == sizeof(uint64_t)) ? uintptr_t(_data64) : uintptr_t(u32()); } + constexpr uintptr_t uptr() const noexcept { return (sizeof(uintptr_t) == sizeof(uint64_t)) ? uintptr_t(u64()) : uintptr_t(u32()); } + + //! Tests whether the immediate can be casted to 8-bit signed integer. + constexpr bool isInt8() const noexcept { return Support::isInt8(i64()); } + //! Tests whether the immediate can be casted to 8-bit unsigned integer. + constexpr bool isUInt8() const noexcept { return Support::isUInt8(i64()); } + //! Tests whether the immediate can be casted to 16-bit signed integer. + constexpr bool isInt16() const noexcept { return Support::isInt16(i64()); } + //! Tests whether the immediate can be casted to 16-bit unsigned integer. + constexpr bool isUInt16() const noexcept { return Support::isUInt16(i64()); } + //! Tests whether the immediate can be casted to 32-bit signed integer. + constexpr bool isInt32() const noexcept { return Support::isInt32(i64()); } + //! Tests whether the immediate can be casted to 32-bit unsigned integer. + constexpr bool isUInt32() const noexcept { return _data[kDataImmValueHi] == 0; } //! Sets immediate value to 8-bit signed integer `val`. - inline void setI8(int8_t val) noexcept { _data64 = uint64_t(int64_t(val)); } + inline void setI8(int8_t val) noexcept { setI64(val); } //! Sets immediate value to 8-bit unsigned integer `val`. - inline void setU8(uint8_t val) noexcept { _data64 = uint64_t(val); } + inline void setU8(uint8_t val) noexcept { setU64(val); } //! Sets immediate value to 16-bit signed integer `val`. - inline void setI16(int16_t val) noexcept { _data64 = uint64_t(int64_t(val)); } + inline void setI16(int16_t val) noexcept { setI64(val); } //! Sets immediate value to 16-bit unsigned integer `val`. - inline void setU16(uint16_t val) noexcept { _data64 = uint64_t(val); } + inline void setU16(uint16_t val) noexcept { setU64(val); } //! Sets immediate value to 32-bit signed integer `val`. - inline void setI32(int32_t val) noexcept { _data64 = uint64_t(int64_t(val)); } + inline void setI32(int32_t val) noexcept { setI64(val); } //! Sets immediate value to 32-bit unsigned integer `val`. - inline void setU32(uint32_t val) noexcept { _data64 = uint64_t(val); } + inline void setU32(uint32_t val) noexcept { setU64(val); } //! Sets immediate value to 64-bit signed integer `val`. - inline void setI64(int64_t val) noexcept { _data64 = uint64_t(val); } + inline void setI64(int64_t val) noexcept { + _data[kDataImmValueHi] = uint32_t(uint64_t(val) >> 32); + _data[kDataImmValueLo] = uint32_t(uint64_t(val) & 0xFFFFFFFFu); + } //! Sets immediate value to 64-bit unsigned integer `val`. - inline void setU64(uint64_t val) noexcept { _data64 = val; } + inline void setU64(uint64_t val) noexcept { setI64(int64_t(val)); } //! Sets immediate value to intptr_t `val`. - inline void setIPtr(intptr_t val) noexcept { _data64 = uint64_t(int64_t(val)); } + inline void setIPtr(intptr_t val) noexcept { setI64(val); } //! Sets immediate value to uintptr_t `val`. - inline void setUPtr(uintptr_t val) noexcept { _data64 = uint64_t(val); } + inline void setUPtr(uintptr_t val) noexcept { setU64(val); } //! Sets immediate value to `val`. template inline void setValue(T val) noexcept { setI64(int64_t(Support::asNormalized(val))); } - inline void setDouble(double d) noexcept { - _data64 = Support::bitCast(d); - } + inline void setDouble(double d) noexcept { setU64(Support::bitCast(d)); } //! \} @@ -1289,13 +1314,13 @@ public: //! Clones the immediate operand. constexpr Imm clone() const noexcept { return Imm(*this); } - inline void signExtend8Bits() noexcept { _data64 = uint64_t(int64_t(i8())); } - inline void signExtend16Bits() noexcept { _data64 = uint64_t(int64_t(i16())); } - inline void signExtend32Bits() noexcept { _data64 = uint64_t(int64_t(i32())); } + inline void signExtend8Bits() noexcept { setI64(int64_t(i8())); } + inline void signExtend16Bits() noexcept { setI64(int64_t(i16())); } + inline void signExtend32Bits() noexcept { setI64(int64_t(i32())); } - inline void zeroExtend8Bits() noexcept { _data64 &= 0x000000FFu; } - inline void zeroExtend16Bits() noexcept { _data64 &= 0x0000FFFFu; } - inline void zeroExtend32Bits() noexcept { _data64 &= 0xFFFFFFFFu; } + inline void zeroExtend8Bits() noexcept { setU64(u8()); } + inline void zeroExtend16Bits() noexcept { setU64(u16()); } + inline void zeroExtend32Bits() noexcept { _data[kDataImmValueHi] = 0u; } //! \} }; diff --git a/src/asmjit/x86/x86operand.h b/src/asmjit/x86/x86operand.h index 50a8739..97ef3d8 100644 --- a/src/asmjit/x86/x86operand.h +++ b/src/asmjit/x86/x86operand.h @@ -477,13 +477,13 @@ public: //! The memory must have a valid index register otherwise the result will be wrong. inline Reg indexReg() const noexcept { return Reg::fromTypeAndId(indexType(), indexId()); } - constexpr Mem _1to1() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To1 << kSignatureMemBroadcastShift), _baseId, _data32[0], _data32[1]); } - constexpr Mem _1to2() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To2 << kSignatureMemBroadcastShift), _baseId, _data32[0], _data32[1]); } - constexpr Mem _1to4() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To4 << kSignatureMemBroadcastShift), _baseId, _data32[0], _data32[1]); } - constexpr Mem _1to8() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To8 << kSignatureMemBroadcastShift), _baseId, _data32[0], _data32[1]); } - constexpr Mem _1to16() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To16 << kSignatureMemBroadcastShift), _baseId, _data32[0], _data32[1]); } - constexpr Mem _1to32() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To32 << kSignatureMemBroadcastShift), _baseId, _data32[0], _data32[1]); } - constexpr Mem _1to64() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To64 << kSignatureMemBroadcastShift), _baseId, _data32[0], _data32[1]); } + constexpr Mem _1to1() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To1 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } + constexpr Mem _1to2() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To2 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } + constexpr Mem _1to4() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To4 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } + constexpr Mem _1to8() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To8 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } + constexpr Mem _1to16() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To16 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } + constexpr Mem _1to32() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To32 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } + constexpr Mem _1to64() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To64 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } // -------------------------------------------------------------------------- // [Mem] diff --git a/src/asmjit/x86/x86rapass.cpp b/src/asmjit/x86/x86rapass.cpp index 5e20a8e..4e4c052 100644 --- a/src/asmjit/x86/x86rapass.cpp +++ b/src/asmjit/x86/x86rapass.cpp @@ -274,9 +274,9 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild uint32_t outRewriteMask = 0; if (flags & RATiedReg::kUse) - useRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._mem.indexId)); + useRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._data[Operand::kDataMemIndexId])); else - outRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._mem.indexId)); + outRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._data[Operand::kDataMemIndexId])); ASMJIT_PROPAGATE(ib.add(workReg, RATiedReg::kUse | RATiedReg::kRead, allocable, useId, useRewriteMask, outId, outRewriteMask)); }