diff options
Diffstat (limited to '3rdparty/asmjit/src')
104 files changed, 13053 insertions, 8642 deletions
diff --git a/3rdparty/asmjit/src/asmjit.natvis b/3rdparty/asmjit/src/asmjit.natvis index 18a083c6c12..b73d8487276 100644 --- a/3rdparty/asmjit/src/asmjit.natvis +++ b/3rdparty/asmjit/src/asmjit.natvis @@ -35,25 +35,25 @@ </Type> <Type Name="asmjit::Operand_"> - <Intrinsic Name="opType" Expression="(unsigned int)(_signature & 0x7)"/> - <Intrinsic Name="opSize" Expression="(_signature >> 24) & 0xFF"/> + <Intrinsic Name="opType" Expression="(unsigned int)(_signature & 0x7)" /> + <Intrinsic Name="opSize" Expression="(_signature >> 24) & 0xFF" /> - <Intrinsic Name="regType" Expression="(_signature >> 3) & 0x1F"/> - <Intrinsic Name="regGroup" Expression="(_signature >> 8) & 0xF"/> + <Intrinsic Name="regType" Expression="(_signature >> 3) & 0x1F" /> + <Intrinsic Name="regGroup" Expression="(_signature >> 8) & 0xF" /> - <Intrinsic Name="memBaseType" Expression="(_signature >> 3) & 0x1F"/> - <Intrinsic Name="memIndexType" Expression="(_signature >> 8) & 0x1F"/> - <Intrinsic Name="memAddrType" Expression="(_signature >> 13) & 0x3"/> - <Intrinsic Name="memRegHome" Expression="(_signature >> 15) & 0x1"/> + <Intrinsic Name="memBaseType" Expression="(_signature >> 3) & 0x1F" /> + <Intrinsic Name="memIndexType" Expression="(_signature >> 8) & 0x1F" /> + <Intrinsic Name="memAddrType" Expression="(_signature >> 13) & 0x3" /> + <Intrinsic Name="memRegHome" Expression="(_signature >> 15) & 0x1" /> - <Intrinsic Name="memBaseId" Expression="_baseId"/> - <Intrinsic Name="memIndexId" Expression="_data[0]"/> + <Intrinsic Name="memBaseId" Expression="_baseId" /> + <Intrinsic Name="memIndexId" Expression="_data[0]" /> - <Intrinsic Name="memOffset32b" Expression="(__int64)int(_data[1])"/> - <Intrinsic Name="memOffset64b" Expression="(__int64) ((unsigned __int64)_baseId << 32) | ((unsigned __int64)_data[1])"/> - <Intrinsic Name="memOffset" Expression="memBaseType() != 0 ? memOffset32b() : memOffset64b()"/> + <Intrinsic Name="memOffset32b" Expression="(__int64)int(_data[1])" /> + <Intrinsic Name="memOffset64b" Expression="(__int64) ((unsigned __int64)_baseId << 32) | ((unsigned __int64)_data[1])" /> + <Intrinsic Name="memOffset" Expression="memBaseType() != 0 ? memOffset32b() : memOffset64b()" /> - <Intrinsic Name="immValue" Expression="((__int64)_data[1] << 32) | (__int64)_data[0]"/> + <Intrinsic Name="immValue" Expression="((__int64)_data[1] << 32) | (__int64)_data[0]" /> <DisplayString Condition="opType() == 0">[None]</DisplayString> <DisplayString Condition="opType() == 1">[Reg] {{ id={_baseId, d} group={regGroup(), d} type={regType(), d} size={opSize(), d} }}</DisplayString> @@ -80,4 +80,122 @@ <Item Name="_data[ImmLo]" Condition="opType() == 3">_data[1]</Item> </Expand> </Type> + + <Type Name="asmjit::FuncValue"> + <Intrinsic Name="isReg" Expression="(_data & asmjit::FuncValue::kFlagIsReg) != 0" /> + <Intrinsic Name="isStack" Expression="(_data & asmjit::FuncValue::kFlagIsStack) != 0" /> + <Intrinsic Name="isIndirect" Expression="(_data & asmjit::FuncValue::kFlagIsIndirect) != 0" /> + <Intrinsic Name="isDone" Expression="(_data & asmjit::FuncValue::kFlagIsDone) != 0" /> + + <Intrinsic Name="typeId" Expression="((_data & asmjit::FuncValue::kTypeIdMask) >> asmjit::FuncValue::kTypeIdShift)" /> + <Intrinsic Name="regId" Expression="((_data & asmjit::FuncValue::kRegIdMask) >> asmjit::FuncValue::kRegIdShift)" /> + <Intrinsic Name="regType" Expression="((_data & asmjit::FuncValue::kRegTypeMask) >> asmjit::FuncValue::kRegTypeShift)" /> + <Intrinsic Name="stackOffset" Expression="((_data & asmjit::FuncValue::kStackOffsetMask) >> asmjit::FuncValue::kStackOffsetShift)" /> + + <DisplayString Condition="isReg()">[RegValue {{ regType={regType()} indirect={isIndirect()} done={isDone()} }}]</DisplayString> + <DisplayString Condition="isStack()">[StackValue {{ indirect={isIndirect()} done={isDone()} }}]</DisplayString> + <DisplayString Condition="!isReg() && !isStack()">[Unknown]</DisplayString> + + <Expand HideRawView="true"> + <Item Name="data">_data</Item> + <Item Name="typeId">(asmjit::Type::Id)(typeId())</Item> + <Item Name="regType" Condition="isReg()">(asmjit::BaseReg::RegType)regType()</Item> + <Item Name="regId" Condition="isReg()">regId()</Item> + <Item Name="stackOffset" Condition="isStack()">stackOffset()</Item> + </Expand> + </Type> + + <Type Name="asmjit::BaseNode"> + <Intrinsic Name="nodeType" Expression="_any._nodeType" /> + + <Intrinsic Name="isInst" Expression="nodeType() == asmjit::BaseNode::kNodeInst"></Intrinsic> + <Intrinsic Name="isSection" Expression="nodeType() == asmjit::BaseNode::kNodeSection"></Intrinsic> + <Intrinsic Name="isLabel" Expression="nodeType() == asmjit::BaseNode::kNodeLabel"></Intrinsic> + <Intrinsic Name="isAlign" Expression="nodeType() == asmjit::BaseNode::kNodeAlign"></Intrinsic> + <Intrinsic Name="isEmbedData" Expression="nodeType() == asmjit::BaseNode::kNodeEmbedData"></Intrinsic> + <Intrinsic Name="isEmbedLabel" Expression="nodeType() == asmjit::BaseNode::kNodeEmbedLabel"></Intrinsic> + <Intrinsic Name="isEmbedLabelDelta" Expression="nodeType() == asmjit::BaseNode::kNodeEmbedLabelDelta"></Intrinsic> + <Intrinsic Name="isConstPool" Expression="nodeType() == asmjit::BaseNode::kNodeConstPool"></Intrinsic> + <Intrinsic Name="isComment" Expression="nodeType() == asmjit::BaseNode::kNodeComment"></Intrinsic> + <Intrinsic Name="isSentinel" Expression="nodeType() == asmjit::BaseNode::kNodeSentinel"></Intrinsic> + <Intrinsic Name="isJump" Expression="nodeType() == asmjit::BaseNode::kNodeJump"></Intrinsic> + <Intrinsic Name="isFunc" Expression="nodeType() == asmjit::BaseNode::kNodeFunc"></Intrinsic> + <Intrinsic Name="isFuncRet" Expression="nodeType() == asmjit::BaseNode::kNodeFuncRet"></Intrinsic> + <Intrinsic Name="isInvoke" Expression="nodeType() == asmjit::BaseNode::kNodeInvoke"></Intrinsic> + + <Intrinsic Name="actsAsInst" Expression="isInst() || isJump() || isFunc() || isFuncRet() || isInvoke()" /> + <Intrinsic Name="actsAsLabel" Expression="isLabel() || isFunc()" /> + + <DisplayString Condition="isInst()">[InstNode]</DisplayString> + <DisplayString Condition="isSentinel()">[SectionNode]</DisplayString> + <DisplayString Condition="isLabel()">[LabelNode]</DisplayString> + <DisplayString Condition="isAlign()">[AlignNode]</DisplayString> + <DisplayString Condition="isEmbedData()">[EmbedDataNode]</DisplayString> + <DisplayString Condition="isEmbedLabel()">[EmbedLabelNode]</DisplayString> + <DisplayString Condition="isEmbedLabelDelta()">[EmbedLabelDeltaNode]</DisplayString> + <DisplayString Condition="isConstPool()">[ConstPoolNode]</DisplayString> + <DisplayString Condition="isComment()">[CommentNode]</DisplayString> + <DisplayString Condition="isSentinel()">[SentinelNode]</DisplayString> + <DisplayString Condition="isJump()">[JumpNode]</DisplayString> + <DisplayString Condition="isFunc()">[FuncNode]</DisplayString> + <DisplayString Condition="isFuncRet()">[FuncRetNode]</DisplayString> + <DisplayString Condition="isInvoke()">[InvokeNode]</DisplayString> + <DisplayString Condition="nodeType() == 0 || nodeType() > 18">[UnknownNode {nodeType(), d}]</DisplayString> + + <Expand HideRawView="true"> + <Item Name="prev">_prev</Item> + <Item Name="next">_next</Item> + + <Item Name="nodeType">(asmjit::BaseNode::NodeType)_any._nodeType</Item> + <Item Name="nodeFlags">(asmjit::BaseNode::Flags)_any._nodeFlags</Item> + + <Item Name="position">_position</Item> + <Item Name="userData.u64">_userDataU64</Item> + <Item Name="userData.ptr">_userDataPtr</Item> + <Item Name="passData">_passData</Item> + <Item Name="inlineComment">_inlineComment, s8</Item> + + <Item Name="baseInst" Condition="actsAsInst()">((asmjit::InstNode*)this)->_baseInst</Item> + <Item Name="opCount" Condition="actsAsInst()">_inst._opCount</Item> + <Item Name="opCapacity" Condition="actsAsInst()">_inst._opCapacity</Item> + <Item Name="opArray" Condition="actsAsInst()">((asmjit::InstNode*)this)->_opArray, [_inst._opCount]</Item> + + <Item Name="sectionId" Condition="isSection()">((asmjit::SectionNode*)this)->_id</Item> + <Item Name="nextSection" Condition="isSection()">((asmjit::SectionNode*)this)->_nextSection</Item> + + <Item Name="labelId" Condition="isLabel()">((asmjit::LabelNode*)this)->_id</Item> + + <Item Name="alignMode" Condition="isAlign()">((asmjit::AlignNode*)this)->_alignMode</Item> + <Item Name="alignment" Condition="isAlign()">((asmjit::AlignNode*)this)->_alignment</Item> + + <Item Name="typeId" Condition="isEmbedData()">_embed._typeId, d</Item> + <Item Name="typeSize" Condition="isEmbedData()">_embed._typeSize, d</Item> + <Item Name="itemCount" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_itemCount</Item> + <Item Name="repeatCount" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_repeatCount</Item> + <Item Name="inlineData" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_inlineData</Item> + <Item Name="externalData" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_externalData</Item> + + <Item Name="labelId" Condition="isEmbedLabel()">((asmjit::EmbedLabelNode*)this)->_id</Item> + + <Item Name="labelId" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_id</Item> + <Item Name="baseId" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_baseId</Item> + <Item Name="dataSize" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_dataSize</Item> + + <Item Name="constPool" Condition="isConstPool()">((asmjit::ConstPoolNode*)this)->_constPool</Item> + + <Item Name="sentinel.sentinelType" Condition="isSentinel()">(asmjit::SentinelNode::SentinelType)_sentinel._sentinelType</Item> + + <Item Name="annotation" Condition="isJump()">((asmjit::JumpNode*)this)->_annotation</Item> + + <Item Name="funcDetail" Condition="isFunc()">((asmjit::FuncNode*)this)->_funcDetail</Item> + <Item Name="frame" Condition="isFunc()">((asmjit::FuncNode*)this)->_frame</Item> + <Item Name="exitNode" Condition="isFunc()">((asmjit::FuncNode*)this)->_exitNode</Item> + <Item Name="end" Condition="isFunc()">((asmjit::FuncNode*)this)->_end</Item> + <Item Name="args" Condition="isFunc()">((asmjit::FuncNode*)this)->_args, [((asmjit::FuncNode*)this)->_funcDetail._argCount]</Item> + + <Item Name="funcDetail" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_funcDetail</Item> + <Item Name="rets" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_rets, [((asmjit::InvokeNode*)this)->_funcDetail._retCount]</Item> + <Item Name="args" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_args, [((asmjit::InvokeNode*)this)->_funcDetail._argCount]</Item> + </Expand> + </Type> </AutoVisualizer> diff --git a/3rdparty/asmjit/src/asmjit/asmjit.h b/3rdparty/asmjit/src/asmjit/asmjit.h index e543a633d04..400426c40a7 100644 --- a/3rdparty/asmjit/src/asmjit/asmjit.h +++ b/3rdparty/asmjit/src/asmjit/asmjit.h @@ -24,27 +24,6 @@ #ifndef ASMJIT_ASMJIT_H_INCLUDED #define ASMJIT_ASMJIT_H_INCLUDED -//! \mainpage API Reference -//! -//! AsmJit C++ API reference documentation generated by Doxygen. -//! -//! Introduction provided by the project page at https://github.com/asmjit/asmjit. -//! -//! \section main_groups Groups -//! -//! The documentation is split into the following groups: -//! -//! $$DOCS_GROUP_OVERVIEW$$ -//! -//! \section main_other Other Pages -//! -//! - <a href="annotated.html">Class List</a> - List of classes sorted alphabetically -//! - <a href="namespaceasmjit.html">AsmJit Namespace</a> - List of symbols provided by `asmjit` namespace - -//! \namespace asmjit -//! -//! Root namespace used by AsmJit. - #include "./core.h" #ifdef ASMJIT_BUILD_X86 diff --git a/3rdparty/asmjit/src/asmjit/core.h b/3rdparty/asmjit/src/asmjit/core.h index f9a56fc51fb..d0fb214d0ce 100644 --- a/3rdparty/asmjit/src/asmjit/core.h +++ b/3rdparty/asmjit/src/asmjit/core.h @@ -24,48 +24,1983 @@ #ifndef ASMJIT_CORE_H_INCLUDED #define ASMJIT_CORE_H_INCLUDED +//! Root namespace used by AsmJit. +namespace asmjit { + +// ============================================================================ +// [Documentation - mainpage] +// ============================================================================ + +//! \mainpage API Reference +//! +//! AsmJit C++ API reference documentation generated by Doxygen. +//! +//! AsmJit library uses one global namespace called \ref asmjit, which provides +//! the whole functionality. Core functionality is within \ref asmjit namespace +//! and architecture specific functionality is always in its own namespace. For +//! example \ref asmjit::x86 provides both 32-bit and 64-bit X86 code generation. +//! +//! \section main_groups Documentation Groups +//! +//! AsmJit documentation is structured into groups. Groups can be followed in +//! order to learn AsmJit, but knowledge from multiple groups is required to +//! use AsmJit properly: +//! +//! $$DOCS_GROUP_OVERVIEW$$ +//! +//! \note It's important to understand that in order to learn AsmJit all groups +//! are important. Some groups can be omitted if a particular tool is out of +//! interest - for example \ref asmjit_assembler users don't need to know about +//! \ref asmjit_builder, but it's not the opposite. \ref asmjit_builder users +//! must know about \ref asmjit_assembler as it also uses operands, labels, and +//! other concepts. Similarly \ref asmjit_compiler users must know how both \ref +//! asmjit_assembler and \ref asmjit_builder tools work. +//! +//! \section where_to_start Where To Start +//! +//! AsmJit \ref asmjit_core provides the following two classes that are essential +//! from the code generation perspective: +//! +//! - \ref CodeHolder provides functionality +//! to temporarily hold the generated code. It stores all the necessary +//! information about the code - code buffers, sections, labels, symbols, +//! and information about relocations. +//! +//! - \ref BaseEmitter provides interface used +//! by emitter implementations. The interface provides basic building blocks +//! that are then implemented by \ref BaseAssembler, \ref BaseBuilder, and +//! \ref BaseCompiler. +//! +//! Code emitters: +//! +//! - \ref asmjit_assembler - provides direct machine code generation. +//! +//! - \ref asmjit_builder - provides intermediate code generation that can +//! be processed before it's serialized to \ref BaseAssembler. +//! +//! - \ref asmjit_compiler - provides high-level code generation with built-in +//! register allocation. +//! +//! - \ref FuncNode - provides insight into how function looks from the Compiler +//! perspective and how it's stored in a node-list. +//! +//! \section main_recommendations Recommendations +//! +//! The following steps are recommended for all AsmJit users: +//! +//! - Make sure that you use \ref Logger, see \ref asmjit_logging. +//! +//! - Make sure that you use \ref ErrorHandler, see \ref asmjit_error_handling. +//! +//! - Instruction validation in your debug builds can reveal problems too. +//! AsmJit provides validation at instruction level, that can be enabled +//! by \ref BaseEmitter::addValidationOptions(). +//! +//! See \ref BaseEmitter::ValidationOptions for more details. +//! +//! - Make sure you put a breakpoint into \ref DebugUtils::errored() function +//! if you have a problem with AsmJit returning errors during instruction +//! encoding or register allocation. Having an active breakpoint there can +//! help to reveal the origin of the error, to inspect variables and other +//! conditions that caused to it. +//! +//! The reason for using \ref Logger and \ref ErrorHandler is that they provide +//! a very useful information about what's happening inside emitters. In many +//! cases the information provided by these two is crucial to quickly fix issues +//! that happen during development (for example wrong instruction, address, or +//! register used). In addition, output from \ref Logger is always necessary +//! when filling bug reports. In other words, using logging and proper error +//! handling can save a lot of time during the development. +//! +//! \section main_other Other Pages +//! +//! - <a href="annotated.html">Class List</a> - List of classes sorted alphabetically +//! - <a href="namespaceasmjit.html">AsmJit Namespace</a> - List of symbols provided by `asmjit` namespace + +// ============================================================================ +// [Documentation - asmjit_build] +// ============================================================================ + +//! \defgroup asmjit_build Build Instructions +//! \brief Build instructions, supported environments, and feature selection. +//! +//! ### Overview +//! +//! AsmJit is designed to be easy embeddable in any project. However, it depends +//! on some compile-time definitions that can be used to enable or disable +//! features to decrease the resulting binary size. A typical way of building +//! AsmJit is to use [cmake](https://www.cmake.org), but it's also possible to +//! just include AsmJit source code in your project and to just build it. The +//! easiest way to include AsmJit in your project is to just include **src** +//! directory in your project and to define \ref ASMJIT_STATIC. AsmJit can be +//! just updated from time to time without any changes to this integration +//! process. Do not embed AsmJit's `test` files in such case as these are used +//! exclusively for testing. +//! +//! ### Supported C++ Compilers +//! +//! - Requirements: +//! +//! - AsmJit won't build without C++11 enabled. If you use older GCC or Clang +//! you would have to enable at least C++11 standard through compiler flags. +//! +//! - Tested: +//! +//! - **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 - VS2017+ is officially supported, VS2015 +//! 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/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h). +//! +//! ### Supported Operating Systems and Platforms +//! +//! - Tested: +//! +//! - **Linux** - Tested by Travis-CI (any distribution is generally supported). +//! +//! - **OSX** - Tested by Travis-CI (any version is supported). +//! +//! - **Windows** - Tested by Travis-CI - (Windows 7+ is officially supported). +//! +//! - **Emscripten** - Works if compiled with \ref ASMJIT_NO_JIT. AsmJit +//! cannot generate WASM code, but can be used to generate X86/X64 code +//! within a browser, for example. +//! +//! - Untested: +//! +//! - **BSDs** - No maintainers, no CI environment to regularly test BSDs, +//! but they should work out of box. +//! +//! - **Haiku** - Not regularly tested, but reported to work. +//! +//! - **Other** operating systems would require some testing and support in +//! the following files: +//! - [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h) +//! - [core/osutils.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/osutils.cpp) +//! - [core/virtmem.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/virtmem.cpp) +//! +//! ### Supported Backends / Architectures +//! +//! - **X86** - Both 32-bit and 64-bit backends tested by Travis-CI. +//! - **ARM** - Work-in-progress (not public at the moment). +//! +//! ### Static Builds and Embedding +//! +//! These definitions can be used to enable static library build. Embed is used +//! when AsmJit's source code is embedded directly in another project, implies +//! static build as well. +//! +//! - \ref ASMJIT_EMBED - Asmjit is embedded, implies \ref ASMJIT_STATIC. +//! - \ref ASMJIT_STATIC - Enable static-library build. +//! +//! \note Projects that use AsmJit statically must define \ref ASMJIT_STATIC in +//! all compilation units that use AsmJit, otherwise AsmJit would use dynamic +//! library imports in \ref ASMJIT_API decorator. The recommendation is to +//! define this macro across the whole project that uses AsmJit this way. +//! +//! ### Build Configuration +//! +//! These definitions control whether asserts are active or not. By default +//! AsmJit would autodetect build configuration from existing pre-processor +//! definitions, but this behavior can be overridden, for example to enable +//! debug asserts in release configuration. +//! +//! - \ref ASMJIT_BUILD_DEBUG - Overrides build configuration to debug, +//! asserts will be enabled in this case. +//! - \ref ASMJIT_BUILD_RELEASE - Overrides build configuration to release, +//! asserts will be disabled in this case. +//! +//! \note There is usually no need to override the build configuration. AsmJit +//! detects the build configuration by checking whether `NDEBUG` is defined and +//! automatically defines \ref ASMJIT_BUILD_RELEASE if configuration overrides +//! were not used. We only recommend using build configuration overrides in +//! special situations, like using AsmJit in release configuration with asserts +//! enabled for whatever reason. +//! +//! ### AsmJit Backends +//! +//! AsmJit currently supports only X86/X64 backend, but the plan is to add more +//! backends in the future. By default AsmJit builds only the host backend, which +//! is autodetected at compile-time, but this can be overridden. +//! +//! - \ref ASMJIT_BUILD_X86 - Always build X86 backend (X86 and X86_64). +//! - \ref ASMJIT_BUILD_ARM - Always build ARM backend (ARM and AArch64). +//! - \ref ASMJIT_BUILD_HOST - Always build the host backend, implied by default. +//! +//! ### Features Selection +//! +//! AsmJit builds by defaults all supported features, which includes all emitters, +//! logging, instruction validation and introspection, and JIT memory allocation. +//! Features can be disabled at compile time by using `ASMJIT_NO_...` definitions. +//! +//! - \ref ASMJIT_NO_DEPRECATED - Disables deprecated API at compile time +//! so it won't be available and the compilation will fail if there is +//! attempt to use such API. This includes deprecated classes, namespaces, +//! enumerations, and functions. +//! +//! - \ref ASMJIT_NO_BUILDER - Disables \ref asmjit_builder functionality +//! completely. This implies \ref ASMJIT_NO_COMPILER as \ref asmjit_compiler +//! cannot be used without \ref asmjit_builder. +//! +//! - \ref ASMJIT_NO_COMPILER - Disables \ref asmjit_compiler functionality +//! completely. +//! +//! - \ref ASMJIT_NO_JIT - Disables JIT memory management and \ref JitRuntime. +//! +//! - \ref ASMJIT_NO_LOGGING - Disables \ref Logger and \ref Formatter. +//! +//! - \ref ASMJIT_NO_TEXT - Disables everything that contains string +//! representation of AsmJit constants, should be used together with +//! \ref ASMJIT_NO_LOGGING as logging doesn't make sense without the +//! ability to quiry instruction names, register names, etc... +//! +//! - \ref ASMJIT_NO_VALIDATION - Disables validation API. +//! +//! - \ref ASMJIT_NO_INTROSPECTION - Disables instruction introspection API, +//! must be used together with \ref ASMJIT_NO_COMPILER as \ref asmjit_compiler +//! requires introspection for its liveness analysis and register allocation. +//! +//! \note It's not recommended to disable features if you plan to build AsmJit +//! as a shared library that will be used by multiple projects that you don't +//! control how AsmJit was built (for example AsmJit in a Linux distribution). +//! The possibility to disable certain features exists mainly for customized +//! AsmJit builds. + +// ============================================================================ +// [Documentation - asmjit_breaking_changes] +// ============================================================================ + +//! \defgroup asmjit_breaking_changes Breaking Changes +//! \brief Documentation of breaking changes +//! +//! ### Overview +//! +//! AsmJit is a live project that is being actively developed. Deprecating the +//! existing API in favor of a new one is preferred, but it's not always +//! possible if the changes are significant. AsmJit authors prefer to do +//! accumulated breaking changes at once instead of breaking the API often. +//! This page documents deprecated and removed APIs and should serve as a how-to +//! guide for people that want to port existing code to work with the newest AsmJit. +//! +//! ### Tips +//! +//! Useful tips before you start: +//! +//! - Visit our [Public Gitter Channel](https://gitter.im/asmjit/asmjit) if +//! you need a quick help. +//! +//! - Build AsmJit with `ASMJIT_NO_DEPRECATED` macro defined to make sure that +//! you are not using deprecated functionality at all. Deprecated functions +//! are decorated with `ASMJIT_DEPRECATED()` macro, but sometimes it's not +//! possible to decorate everything like classes, which are used by deprecated +//! functions as well, because some compilers would warn about that. If your +//! project compiles fine with `ASMJIT_NO_DEPRECATED` it's not using anything, +//! which was deprecated. +//! +//! ### Changes committed at 2020-05-30 +//! +//! AsmJit has been cleaned up significantly, many todo items have been fixed +//! and many functions and classes have been redesigned, some in an incompatible +//! way. +//! +//! Core changes: +//! +//! - \ref Imm operand has now only \ref Imm::value() and \ref Imm::valueAs() +//! functions that return its value content, and \ref Imm::setValue() function +//! that sets the content. Functions like `setI8()`, `setU8()` were deprecated. +//! +//! Old functions were deprecated, but code using them should still compile. +//! +//! - `ArchInfo` has been replaced with \ref Environment. Environment provides +//! more details about the architecture, but drops some properties that +//! were used by arch info - `gpSize(`) and `gpCount()`. `gpSize()` can +//! be replaced with `registerSize()` getter, which returns a native register +//! size of the architecture the environment uses. However, `gpCount()` was +//! removed - at the moment \ref ArchRegs can be used to access such properties. +//! +//! Some other functions were renamed, like `ArchInfo::isX86Family()` is +//! now \ref Environment::isFamilyX86(), etc. The reason for changing the +//! order was support for more propertries and all the accessors now +//! start with the type of the property, like \ref Environment::isPlatformWindows(). +//! +//! This function causes many other classes to provide `environment()` getter +//! instead of `archInfo()` getter. In addition, AsmJit now uses `arch()` to +//! get an architecture instead of `archId()`. `ArchInfo::kIdXXX` was renamed +//! to `Environment::kArchXXX`. +//! +//! Some functions were deprecated, some removed... +//! +//! - `CodeInfo` has been removed in favor of \ref Environment. If you used +//! `CodeInfo` to set architecture and base address, this is now possible +//! with \ref Environment and setting base address explicitly by \ref +//! CodeHolder::init() - the first argument is \ref Environment, and the +//! second argument is base address, which defaults to \ref +//! Globals::kNoBaseAddress. +//! +//! CodeInfo class was deprecated, but the code using it should still +//! compile with warnings. +//! +//! - \ref CallConv has been updated to offer a more unified way of representing +//! calling conventions - many calling conventions were abstracted to follow +//! standard naming like \ref CallConv::kIdCDecl or \ref CallConv::kIdStdCall. +//! +//! This change means that other APIs like \ref FuncDetail::init() now +//! require both, calling convention and target \ref Environment. +//! +//! - `Logging` namespace has been renamed to \ref Formatter, which now +//! provides general functionality for formatting in AsmJit. +//! +//! Logging namespace should still work, but its use is deprecated. +//! Unfortunately this will be without deprecation warnings, so please +//! make sure you don't use it. +//! +//! - `Data64`, `Data128`, and `Data256` structs were deprecated and should +//! no longer be used. There is no replacement, AsmJit users should simply +//! create their own structures if they need them or use the new repeated +//! embed API in emitters, see \ref BaseEmitter::embedDataArray(). +//! +//! Emitter changes: +//! +//! - \ref BaseEmitter::emit() function signature has been changed to accept +//! 3 operands by reference and the rest 3 operands as a continuous array. +//! This change is purely cosmetic and shouldn't affect users as emit() +//! has many overloads that dispatch to the right function. +//! +//! - \ref x86::Emitter (Assembler, Builder, Compiler) deprecates embed +//! utilities like `dint8()`, `duint8()`, `duint16()`, `dxmm()`, etc... +//! in favor of a new and more powerful \ref BaseEmitter::embedDataArray(). +//! This function also allows emitting repeated values and/or patterns, +//! which is used by helpers \ref BaseEmitter::embedUInt8(), and others... +//! +//! - Validation is now available through \ref BaseEmitter::ValidationOptions, +//! which can be enabled/disabled through \ref BaseEmitter::addValidationOptions() +//! and \ref BaseEmitter::clearValidationOptions(), respectively. Validation +//! options now separate between encoding and Builder/Compiler so it's possible +//! to choose the granularity required. +//! +//! Builder changes: +//! +//! - Internal functions for creating nodes were redesigned. They now accept +//! a pointer to the node created as a first parameter. These changes should +//! not affect AsmJit users as these functions were used internally. +//! +//! Compiler changes: +//! +//! - `FuncCallNode` has been renamed to \ref InvokeNode. Additionally, function +//! calls should now use \ref x86::Compiler::invoke() instead of `call()`. +//! The reason behind this is to remove the confusion between a `call` +//! instruction and AsmJit's `call()` intrinsic, which is now `invoke()`. +//! +//! - Creating new nodes also changed. Now the preferred way of invoking a +//! function is to call \ref x86::Compiler::invoke() where the first +//! argument is `InvokeNode**`. The function now returns an error and would +//! call \ref ErrorHandler in case of a failure. Error handling was +//! unspecified in the past - the function was marked noexcept, but called +//! error handler, which could throw. +//! +//! The reason behind this change is to make the API consistent with other +//! changes and to also make it possible to inspect the possible error. In +//! the previous API it returned a new node or `nullptr` in case of error, +//! which the user couldn't inspect unless there was an attached \ref +//! ErrorHandler. +//! +//! Samples: +//! +//! ``` +//! #include <asmjit/x86.h> +//! using namespace asmjit; +//! +//! // The basic setup of JitRuntime and CodeHolder changed, use environment() +//! // instead of codeInfo(). +//! void basicSetup() { +//! JitRuntime rt; +//! CodeHolder code(rt.environment()); +//! } +//! +//! // Calling a function (Compiler) changed - use invoke() instead of call(). +//! void functionInvocation(x86::Compiler& cc) { +//! InvokeNode* invokeNode; +//! cc.invoke(&invokeNode, targetOperand, FuncSignatureT<...>(...)); +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_core] +// ============================================================================ + //! \defgroup asmjit_core Core -//! \brief Core API. +//! \brief Globals, code storage, and emitter interface. //! -//! API that provides classes and functions not specific to any architecture. +//! ### Overview +//! +//! AsmJit library uses \ref CodeHolder to hold code during code generation and +//! emitters inheriting from \ref BaseEmitter to emit code. CodeHolder uses +//! containers to manage its data: +//! +//! - \ref Section - stores information about a code or data section. +//! - \ref CodeBuffer - stores actual code or data, part of \ref Section. +//! - \ref LabelEntry - stores information about a label - its name, offset, +//! section where it belongs to, and other bits. +//! - \ref LabelLink - stores information about yet unbound label, which was +//! already used by the assembler. +//! - \ref RelocEntry - stores information about a relocation. +//! - \ref AddressTableEntry - stores information about an address, which was +//! used in a jump or call. Such address may need relocation. +//! +//! To generate code you would need to instantiate at least the following classes: +//! +//! - \ref CodeHolder - to hold code during code generation. +//! - \ref BaseEmitter - to emit code into \ref CodeHolder. +//! - \ref Target (optional) - most likely \ref JitRuntime to keep the generated +//! code in executable memory. \ref Target can be customized by inheriting from +//! it. +//! +//! There are also other core classes that are important: +//! +//! - \ref Environment - describes where the code will run. Environment brings +//! the concept of target triples or tuples into AsmJit, which means that users +//! can specify target architecture, platform, and ABI. +//! - \ref Type - encapsulates lightweight type functionality that can be used +//! to describe primitive and vector types. Types are used by higher level +//! utilities, for example by \ref asmjit_function and \ref asmjit_compiler. +//! - \ref CpuInfo - encapsulates CPU information - stores both CPU information +//! and features described by \ref BaseFeatures. +//! +//! AsmJit also provides global constants: +//! +//! - \ref Globals - namespace that provides global constants. +//! - \ref ByteOrder - byte-order constants and functionality. +//! +//! \note CodeHolder examples use \ref x86::Assembler as abstract interfaces cannot +//! be used to generate code. +//! +//! ### CodeHolder & Emitters +//! +//! The example below shows how the mentioned classes interact to generate X86 code: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef int (*Func)(void); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! +//! CodeHolder code; // Holds code and relocation information. +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! a.mov(x86::eax, 1); // Move one to eax register. +//! a.ret(); // Return from function. +//! // ===== x86::Assembler is no longer needed from here and can be destroyed ===== +//! +//! Func fn; // Holds address to the generated function. +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ===== CodeHolder is no longer needed from here and can be destroyed ===== +//! +//! int result = fn(); // Execute the generated code. +//! printf("%d\n", result); // Print the resulting "1". +//! +//! // All classes use RAII, all resources will be released before `main()` returns, +//! // the generated function can be, however, released explicitly if you intend to +//! // reuse or keep the runtime alive, which you should in a production-ready code. +//! rt.release(fn); +//! +//! return 0; +//! } +//! ``` +//! +//! The example above used \ref x86::Assembler as an emitter. AsmJit provides the +//! following emitters that offer various levels of abstraction: +//! +//! - \ref asmjit_assembler - Low-level emitter that emits directly to \ref CodeBuffer. +//! - \ref asmjit_builder - Low-level emitter that emits to a \ref BaseNode list. +//! - \ref asmjit_compiler - High-level emitter that provides register allocation. +//! +//! ### Targets and JitRuntime +//! +//! AsmJit's \ref Target is an interface that provides basic target abstraction. +//! At the moment AsmJit provides only one implementation called \ref JitRuntime, +//! which as the name suggests provides JIT code target and execution runtime. +//! \ref JitRuntime provides all the necessary stuff to implement a simple JIT +//! compiler with basic memory management. It only provides \ref JitRuntime::add() +//! and \ref JitRuntime::release() functions that are used to either add code +//! to the runtime or release it. \ref JitRuntime doesn't do any decisions on +//! when the code should be released, the decision is up to the developer. +//! +//! See more at \ref asmjit_virtual_memory group. +//! +//! ### More About Environment +//! +//! In the previous example the \ref Environment is retrieved from \ref JitRuntime. +//! It's logical as \ref JitRuntime always returns an \ref Environment that is +//! compatible with the host. For example if your application runs in 64-bit mode +//! the \ref Environment returned will use \ref Environment::kArchX64 architecture +//! in contrast to \ref Environment::kArchX86, which will be used in 32-bit mode on +//! any X86 platform. +//! +//! AsmJit allows to setup the \ref Environment manually and to select a different +//! architecture and ABI when necessary. So let's do something else this time, let's +//! always generate a 32-bit code and print its binary representation. To do that, we +//! can create our own \ref Environment and initialize it to \ref Environment::kArchX86. +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! int main(int argc, char* argv[]) { +//! using namespace asmjit::x86; +//! +//! // Create a custom environment initialized to 32-bit X86 architecture. +//! Environment env; +//! env.setArch(Environment::kArchX86); +//! +//! CodeHolder code; // Create a CodeHolder. +//! code.init(env); // Initialize CodeHolder with custom environment. +//! +//! // Generate a 32-bit function that sums 4 floats and looks like: +//! // void func(float* dst, const float* a, const float* b) +//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. +//! +//! a.mov(eax, dword_ptr(esp, 4)); // Load the destination pointer. +//! a.mov(ecx, dword_ptr(esp, 8)); // Load the first source pointer. +//! a.mov(edx, dword_ptr(esp, 12)); // Load the second source pointer. +//! +//! a.movups(xmm0, ptr(ecx)); // Load 4 floats from [ecx] to XMM0. +//! a.movups(xmm1, ptr(edx)); // Load 4 floats from [edx] to XMM1. +//! a.addps(xmm0, xmm1); // Add 4 floats in XMM1 to XMM0. +//! a.movups(ptr(eax), xmm0); // Store the result to [eax]. +//! a.ret(); // Return from function. +//! +//! // We have no Runtime this time, it's on us what we do with the code. +//! // CodeHolder stores code in Section, which provides some basic properties +//! // and CodeBuffer structure. We are interested in section's CodeBuffer. +//! // +//! // NOTE: The first section is always '.text', it can be retrieved by +//! // code.sectionById(0) or simply by code.textSection(). +//! CodeBuffer& buffer = code.textSection()->buffer(); +//! +//! // Print the machine-code generated or do something else with it... +//! // 8B4424048B4C24048B5424040F28010F58010F2900C3 +//! for (size_t i = 0; i < buffer.length; i++) +//! printf("%02X", buffer.data[i]); +//! +//! return 0; +//! } +//! ``` +//! +//! ### Explicit Code Relocation +//! +//! In addition to \ref Environment, \ref CodeHolder can be configured to +//! specify a base-address (or a virtual base-address in a linker terminology), +//! which could be static (useful when you know the location where the target's +//! machine code will be) or dynamic. AsmJit assumes dynamic base-address by +//! default and relocates the code held by \ref CodeHolder to a user provided +//! address on-demand. To be able to relocate to a user provided address it needs +//! to store some information about relocations, which is represented by \ref +//! RelocEntry. Relocation entries are only required if you call external functions +//! from the generated code that cannot be encoded by using a 32-bit displacement +//! (64-bit displacements are not provided by aby supported architecture). +//! +//! There is also a concept called \ref LabelLink - label link is a lightweight +//! data structure that doesn't have any identifier and is stored in \ref LabelEntry +//! as a single-linked list. Label link represents either unbound yet used label +//! and cross-sections links (only relevant to code that uses multiple sections). +//! Since crossing sections is something that cannot be resolved immediately these +//! links persist until offsets of these sections are assigned and until +//! \ref CodeHolder::resolveUnresolvedLinks() is called. It's an error if you end +//! up with code that has unresolved label links after flattening. You can verify +//! it by calling \ref CodeHolder::hasUnresolvedLinks(), which inspects the value +//! returned by \ref CodeHolder::unresolvedLinkCount(). +//! +//! AsmJit can flatten code that uses multiple sections by assigning each section +//! an incrementing offset that respects its alignment. Use \ref CodeHolder::flatten() +//! to do that. After the sections are flattened their offsets and virtual-sizes +//! are adjusted to respect each section's buffer size and alignment. The \ref +//! CodeHolder::resolveUnresolvedLinks() function must be called before relocating +//! the code held by \ref CodeHolder. You can also flatten your code manually by +//! iterating over all sections and calculating their offsets (relative to base) +//! by your own algorithm. In that case \ref CodeHolder::flatten() should not be +//! called, however, \ref CodeHolder::resolveUnresolvedLinks() should be. +//! +//! The example below shows how to use a built-in virtual memory allocator +//! \ref JitAllocator instead of using \ref JitRuntime (just in case you want +//! to use your own memory management) and how to relocate the generated code +//! into your own memory block - you can use your own virtual memory allocator +//! if you prefer that, but that's OS specific and not covered by the documentation. +//! +//! The following code is similar to the previous one, but implements a function +//! working in both 32-bit and 64-bit environments: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); +//! +//! int main() { +//! // Create a custom environment that matches the current host environment. +//! Environment env = hostEnvironment(); +//! +//! CodeHolder code; // Create a CodeHolder. +//! code.init(env); // Initialize CodeHolder with environment. +//! +//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. +//! +//! // Signature: 'void func(int* dst, const int* a, const int* b)'. +//! x86::Gp dst; +//! x86::Gp src_a; +//! x86::Gp src_b; +//! +//! // Handle the difference between 32-bit and 64-bit calling conventions +//! // (arguments passed through stack vs. arguments passed by registers). +//! if (env.is32Bit()) { +//! dst = x86::eax; +//! src_a = x86::ecx; +//! src_b = x86::edx; +//! a.mov(dst , x86::dword_ptr(x86::esp, 4)); +//! a.mov(src_a, x86::dword_ptr(x86::esp, 8)); +//! a.mov(src_b, x86::dword_ptr(x86::esp, 12)); +//! } +//! else { +//! if (env.isPlatformWindows()) { +//! dst = x86::rcx; // First argument (destination pointer). +//! src_a = x86::rdx; // Second argument (source 'a' pointer). +//! src_b = x86::r8; // Third argument (source 'b' pointer). +//! } +//! else { +//! dst = x86::rdi; // First argument (destination pointer). +//! src_a = x86::rsi; // Second argument (source 'a' pointer). +//! src_b = x86::rdx; // Third argument (source 'b' pointer). +//! } +//! } +//! +//! a.movdqu(x86::xmm0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. +//! a.movdqu(x86::xmm1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. +//! a.paddd(x86::xmm0, x86::xmm1); // Add 4 ints in XMM1 to XMM0. +//! a.movdqu(x86::ptr(dst), x86::xmm0); // Store the result to [dst]. +//! a.ret(); // Return from function. +//! +//! // Even when we didn't use multiple sections AsmJit could insert one section +//! // called '.addrtab' (address table section), which would be filled by data +//! // required by relocations (absolute jumps and calls). You can omit this code +//! // if you are 100% sure your code doesn't contain multiple sections and +//! // such relocations. You can use `CodeHolder::hasAddressTable()` to verify +//! // whether the address table section does exist. +//! code.flatten(); +//! code.resolveUnresolvedLinks(); +//! +//! // After the code was generated it can be relocated manually to any memory +//! // location, however, we need to know it's size before we perform memory +//! // allocation. `CodeHolder::codeSize()` returns the worst estimated code +//! // size in case that relocations are not possible without trampolines (in +//! // that case some extra code at the end of the current code buffer is +//! // generated during relocation). +//! size_t estimatedSize = code.codeSize(); +//! +//! // Instead of rolling up our own memory allocator we can use the one AsmJit +//! // provides. It's decoupled so you don't need to use `JitRuntime` for that. +//! JitAllocator allocator; +//! +//! // Allocate an executable virtual memory and handle a possible failure. +//! void* p = allocator.alloc(estimatedSize); +//! if (!p) +//! return 0; +//! +//! // Now relocate the code to the address provided by the memory allocator. +//! // Please note that this DOESN'T COPY anything to `p`. This function will +//! // store the address in CodeHolder and use relocation entries to patch the +//! // existing code in all sections to respect the base address provided. +//! code.relocateToBase((uint64_t)p); +//! +//! // This is purely optional. There are cases in which the relocation can omit +//! // unneeded data, which would shrink the size of address table. If that +//! // happened the codeSize returned after relocateToBase() would be smaller +//! // than the originally `estimatedSize`. +//! size_t codeSize = code.codeSize(); +//! +//! // This will copy code from all sections to `p`. Iterating over all sections +//! // and calling `memcpy()` would work as well, however, this function supports +//! // additional options that can be used to also zero pad sections' virtual +//! // size, etc. +//! // +//! // With some additional features, copyFlattenData() does roughly this: +//! // for (Section* section : code.sections()) +//! // memcpy((uint8_t*)p + section->offset(), +//! // section->data(), +//! // section->bufferSize()); +//! code.copyFlattenedData(p, codeSize, CodeHolder::kCopyPadSectionBuffer); +//! +//! // Execute the generated function. +//! int inA[4] = { 4, 3, 2, 1 }; +//! int inB[4] = { 1, 5, 2, 8 }; +//! int out[4]; +//! +//! // This code uses AsmJit's ptr_as_func<> to cast between void* and SumIntsFunc. +//! ptr_as_func<SumIntsFunc>(p)(out, inA, inB); +//! +//! // Prints {5 8 4 9} +//! printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); +//! +//! // Release 'p' is it's no longer needed. It will be destroyed with 'vm' +//! // instance anyway, but it's a good practice to release it explicitly +//! // when you know that the function will not be needed anymore. +//! allocator.release(p); +//! +//! return 0; +//! } +//! ``` +//! +//! If you know the base-address in advance (before the code generation) it can +//! be passed as a second argument to \ref CodeHolder::init(). In that case the +//! Assembler will know the absolute position of each instruction and would be +//! able to use it during instruction encoding to prevent relocations where +//! possible. The following example shows how to configure the base address: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! void initializeCodeHolder(CodeHolder& code) { +//! Environment env = hostEnvironment(); +//! uint64_t baseAddress = uint64_t(0x1234); +//! +//! // initialize CodeHolder with environment and custom base address. +//! code.init(env, baseAddress); +//! } +//! ``` +//! +//! ### Label Offsets and Links +//! +//! When a label that is not yet bound is used by the Assembler, it creates a +//! \ref LabelLink, which is then added to a \ref LabelEntry. These links are +//! also created if a label is used in a different section than in which it +//! was bound. Let's examine some functions that can be used to check whether +//! there are any unresolved links. +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! +//! void labelLinksExample(CodeHolder& code, const Label& label) { +//! // Tests whether the `label` is bound. +//! bool isBound = code.isLabelBound(label); +//! printf("Label %u is %s\n", label.id(), isBound ? "bound" : "not bound"); +//! +//! // Returns true if the code contains either referenced, but unbound +//! // labels, or cross-section label links that are not resolved yet. +//! bool hasUnresolved = code.hasUnresolvedLinks(); // Boolean answer. +//! size_t nUnresolved = code.unresolvedLinkCount(); // Count of unresolved links. +//! +//! printf("Number of unresolved links: %zu\n", nUnresolved); +//! } +//! ``` +//! +//! There is no function that would return the number of unbound labels as this +//! is completely unimportant from CodeHolder's perspective. If a label is not +//! used then it doesn't matter whether it's bound or not, only actually used +//! labels matter. After a Label is bound it's possible to query its offset +//! offset relative to the start of the section where it was bound: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! +//! void labelOffsetExample(CodeHolder& code, const Label& label) { +//! // Label offset is known after it's bound. The offset provided is relative +//! // to the start of the section, see below for alternative. If the given +//! // label is not bound the offset returned will be zero. It's recommended +//! // to always check whether the label is bound before using its offset. +//! uint64_t sectionOffset = code.labelOffset(label); +//! printf("Label offset relative to section: %llu\n", (unsigned long long)sectionOffset); +//! +//! // If you use multiple sections and want the offset relative to the base. +//! // NOTE: This function expects that the section has already an offset and +//! // the label-link was resolved (if this is not true you will still get an +//! // offset relative to the start of the section). +//! uint64_t baseOffset = code.labelOffsetFromBase(label); +//! printf("Label offset relative to base: %llu\n", (unsigned long long)baseOffset); +//! } +//! ``` +//! +//! ### Sections +//! +//! AsmJit allows to create multiple sections within the same \ref CodeHolder. +//! A test-case [asmjit_test_x86_sections.cpp](https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_sections.cpp) +//! can be used as a reference point although the following example should +//! also provide a useful insight: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! void sectionsExample(CodeHolder& code) { +//! // Text section is always provided as the first section. +//! Section* text = code.textSection(); // or code.sectionById(0); +//! +//! // To create another section use CodeHolder::newSection(). +//! Section* data; +//! Error err = code.newSection(&data, +//! ".data", // Section name +//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX). +//! 0, // Section flags, see Section::Flags. +//! 8); // Section alignment, must be power of 2. +//! +//! // When you switch sections in Assembler, Builder, or Compiler the cursor +//! // will always move to the end of that section. When you create an Assembler +//! // the cursor would be placed at the end of the first (.text) section, which +//! // is initially empty. +//! x86::Assembler a(&code); +//! Label L_Data = a.newLabel(); +//! +//! a.mov(x86::eax, x86::ebx); // Emits in .text section. +//! +//! a.section(data); // Switches to the end of .data section. +//! a.bind(L_Data); // Binds label in this .data section +//! a.db(0x01); // Emits byte in .data section. +//! +//! a.section(text); // Switches to the end of .text section. +//! a.add(x86::ebx, x86::eax); // Emits in .text section. +//! +//! // References a label in .text section, which was bound in .data section. +//! // This would create a LabelLink even when the L_Data is already bound, +//! // because the reference crosses sections. See below... +//! a.lea(x86::rsi, x86::ptr(L_Data)); +//! } +//! ``` +//! +//! The last line in the example above shows that a LabelLink would be created +//! even for bound labels that cross sections. In this case a referenced label +//! was bound in another section, which means that the link couldn't be resolved +//! at that moment. If your code uses sections, but you wish AsmJit to flatten +//! these sections (you don't plan to flatten them manually) then there is an +//! API for that. +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! // ... (continuing the previous example) ... +//! void sectionsExampleContinued(CodeHolder& code) { +//! // Suppose we have some code that contains multiple sections and +//! // we would like to flatten it by using AsmJit's built-in API: +//! Error err = code.flatten(); +//! if (err) { +//! // There are many reasons it can fail, so always handle a possible error. +//! printf("Failed to flatten the code: %s\n", DebugUtils::errorAsString(err)); +//! exit(1); +//! } +//! +//! // After flattening all sections would contain assigned offsets +//! // relative to base. Offsets are 64-bit unsigned integers so we +//! // cast them to `size_t` for simplicity. On 32-bit targets it's +//! // guaranteed that the offset cannot be greater than `2^32 - 1`. +//! printf("Data section offset %zu", size_t(data->offset())); +//! +//! // The flattening doesn't resolve unresolved label links, this +//! // has to be done manually as flattening can be done separately. +//! err = code.resolveUnresolvedLinks(); +//! if (err) { +//! // This is the kind of error that should always be handled... +//! printf("Failed to resolve label links: %s\n", DebugUtils::errorAsString(err)); +//! exit(1); +//! } +//! +//! if (code.hasUnresolvedLinks()) { +//! // This would mean either unbound label or some other issue. +//! printf("The code has %zu unbound labels\n", code.unresovedLinkCount()); +//! exit(1); +//! } +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_assembler] +// ============================================================================ + +//! \defgroup asmjit_assembler Assembler +//! \brief Assembler interface and operands. +//! +//! ### Overview +//! +//! AsmJit's Assembler is used to emit machine code directly into a \ref +//! CodeBuffer. In general, code generation with assembler requires the knowledge +//! of the following: +//! +//! - \ref BaseAssembler and architecture-specific assemblers: +//! - \ref x86::Assembler - Assembler specific to X86 architecture +//! - \ref Operand and its variations: +//! - \ref BaseReg - Base class for a register operand, inherited by: +//! - \ref x86::Reg - Register operand specific to X86 architecture. +//! - \ref BaseMem - Base class for a memory operand, inherited by: +//! - \ref x86::Mem - Memory operand specific to X86 architecture. +//! - \ref Imm - Immediate (value) operand. +//! - \ref Label - Label operand. +//! +//! \note Assembler examples use \ref x86::Assembler as abstract interfaces cannot +//! be used to generate code. +//! +//! ### Operand Basics +//! +//! Let's start with operands. \ref Operand is a data structure that defines a +//! data layout of any operand. It can be inherited, but any class inheriting +//! it cannot add any members to it, only the existing layout can be reused. +//! AsmJit allows to construct operands dynamically, to store them, and to query +//! a complete information about them at run-time. Operands are small (always 16 +//! bytes per \ref Operand) and can be copied and passed by value. Please never +//! allocate individual operands dynamically by using a `new` keyword - it would +//! work, but then you would have to be responsible for deleting such operands. +//! In AsmJit operands are always part of some other data structures like \ref +//! InstNode, which is part of \ref asmjit_builder tool. +//! +//! Operands contain only identifiers, but not pointers to any code-generation data. +//! For example \ref Label operand only provides label identifier, but not a pointer +//! to \ref LabelEntry structure. In AsmJit such IDs are used to link stuff together +//! without having to deal with pointers. +//! +//! AsmJit's operands all inherit from a base class called \ref Operand. Operands +//! have the following properties that are commonly accessible by getters and setters: +//! +//! - \ref Operand - Base operand, which only provides accessors that are common +//! to all operand types. +//! - \ref BaseReg - Describes either physical or virtual register. Physical +//! registers have id that matches the target's machine id directly whereas +//! virtual registers must be allocated into physical registers by a register +//! allocator pass. Register operand provides: +//! - Register Type - Unique id that describes each possible register provided +//! by the target architecture - for example X86 backend provides \ref +//! x86::Reg::RegType, which defines all variations of general purpose registers +//! (GPB-LO, GPB-HI, GPW, GPD, and GPQ) and all types of other registers like K, +//! MM, BND, XMM, YMM, and ZMM. +//! - Register Group - Groups multiple register types under a single group - for +//! example all general-purpose registers (of all sizes) on X86 are part of +//! \ref x86::Reg::kGroupGp and all SIMD registers (XMM, YMM, ZMM) are part +//! of \ref x86::Reg::kGroupVec. +//! - Register Size - Contains the size of the register in bytes. If the size +//! depends on the mode (32-bit vs 64-bit) then generally the higher size is +//! used (for example RIP register has size 8 by default). +//! - Register Id - Contains physical or virtual id of the register. +//! - \ref BaseMem - Used to reference a memory location. Memory operand provides: +//! - Base Register - A base register type and id (physical or virtual). +//! - Index Register - An index register type and id (physical or virtual). +//! - Offset - Displacement or absolute address to be referenced (32-bit if base +//! register is used and 64-bit if base register is not used). +//! - Flags that can describe various architecture dependent information (like +//! scale and segment-override on X86). +//! - \ref Imm - Immediate values are usually part of instructions (encoded within +//! the instruction itself) or data. +//! - \ref Label - used to reference a location in code or data. Labels must be +//! created by the \ref BaseEmitter or by \ref CodeHolder. Each label has its +//! unique id per \ref CodeHolder instance. +//! +//! ### Operand Manipulation +//! +//! AsmJit allows to construct operands dynamically, to store them, and to query +//! a complete information about them at run-time. Operands are small (always 16 +//! bytes per `Operand`) and should be always copied (by value) if you intend to +//! store them (don't create operands by using `new` keyword, it's not recommended). +//! Operands are safe to be passed to `memcpy()` and `memset()`, which becomes +//! handy when working with arrays of operands. If you set all members of an \ref +//! Operand to zero the operand would become NONE operand, which is the same as a +//! default constructed Operand. +//! +//! The example below illustrates how operands can be used and modified even +//! without using any other code generation classes. The example uses X86 +//! architecture-specific operands. +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! // Registers can be copied, it's a common practice. +//! x86::Gp dstRegByValue() { return x86::ecx; } +//! +//! void usingOperandsExample(x86::Assembler& a) { +//! // Gets `ecx` register returned by a function. +//! x86::Gp dst = dstRegByValue(); +//! // Gets `rax` register directly from the provided `x86` namespace. +//! x86::Gp src = x86::rax; +//! // Constructs `r10` dynamically. +//! x86::Gp idx = x86::gpq(10); +//! // Constructs [src + idx] memory address - referencing [rax + r10]. +//! x86::Mem m = x86::ptr(src, idx); +//! +//! // Examine `m`: Returns `x86::Reg::kTypeGpq`. +//! m.indexType(); +//! // Examine `m`: Returns 10 (`r10`). +//! m.indexId(); +//! +//! // Reconstruct `idx` stored in mem: +//! x86::Gp idx_2 = x86::Gp::fromTypeAndId(m.indexType(), m.indexId()); +//! +//! // True, `idx` and idx_2` are identical. +//! idx == idx_2; +//! +//! // Possible - op will still be the same as `m`. +//! Operand op = m; +//! // True (can be casted to BaseMem or architecture-specific Mem). +//! op.isMem(); +//! +//! // True, `op` is just a copy of `m`. +//! m == op; +//! +//! // Static cast is fine and valid here. +//! static_cast<BaseMem&>(op).addOffset(1); +//! // However, using `as<T>()` to cast to a derived type is preferred. +//! op.as<BaseMem>().addOffset(1); +//! // False, `op` now points to [rax + r10 + 2], which is not [rax + r10]. +//! m == op; +//! +//! // Emitting 'mov' - type safe way. +//! a.mov(dst, m); +//! // Not possible, `mov` doesn't provide mov(x86::Gp, Operand) overload. +//! a.mov(dst, op); +//! +//! // Type-unsafe, but possible. +//! a.emit(x86::Inst::kIdMov, dst, m); +//! // Also possible, `emit()` is typeless and can be used with raw Operand. +//! a.emit(x86::Inst::kIdMov, dst, op); +//! } +//! ``` +//! +//! Some operands have to be created explicitly by emitters. For example labels +//! must be created by \ref BaseEmitter::newLabel(), which creates a label entry +//! and returns a \ref Label operand with the id that refers to it. Such label +//! then can be used by emitters. +//! +//! ### Memory Operands +//! +//! Some architectures like X86 provide a complex memory addressing model that +//! allows to encode addresses having a BASE register, INDEX register with a +//! possible scale (left shift), and displacement (called offset in AsmJit). +//! Memory address on X86 can also specify memory segment (segment-override in +//! X86 terminology) and some instructions (gather / scatter) require INDEX to +//! be a \ref x86::Vec register instead of a general-purpose register. +//! +//! AsmJit allows to encode and work with all forms of addresses mentioned and +//! implemented by X86. In addition, it also allows to construct absolute 64-bit +//! memory address operands, which is only allowed in one form of 'mov' instruction. +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void testX86Mem() { +//! // Makes it easier to access x86 stuff... +//! using namespace asmjit::x86; +//! +//! // BASE + OFFSET. +//! Mem a = ptr(rax); // a = [rax] +//! Mem b = ptr(rax, 15); // b = [rax + 15] +//! +//! // BASE + INDEX << SHIFT - Shift is in BITS as used by X86! +//! Mem c = ptr(rax, rbx); // c = [rax + rbx] +//! Mem d = ptr(rax, rbx, 2); // d = [rax + rbx << 2] +//! Mem e = ptr(rax, rbx, 2, 15); // e = [rax + rbx << 2 + 15] +//! +//! // BASE + VM (Vector Index) (encoded as MOD+VSIB). +//! Mem f = ptr(rax, xmm1); // f = [rax + xmm1] +//! Mem g = ptr(rax, xmm1, 2); // g = [rax + xmm1 << 2] +//! Mem h = ptr(rax, xmm1, 2, 15); // h = [rax + xmm1 << 2 + 15] +//! +//! // Absolute adddress: +//! uint64_t addr = (uint64_t)0x1234; +//! Mem i = ptr(addr); // i = [0x1234] +//! Mem j = ptr(addr, rbx); // j = [0x1234 + rbx] +//! Mem k = ptr(addr, rbx, 2); // k = [0x1234 + rbx << 2] +//! +//! // LABEL - Will be encoded as RIP (64-bit) or absolute address (32-bit). +//! Label L = ...; +//! Mem m = ptr(L); // m = [L] +//! Mem n = ptr(L, rbx); // n = [L + rbx] +//! Mem o = ptr(L, rbx, 2); // o = [L + rbx << 2] +//! Mem p = ptr(L, rbx, 2, 15); // p = [L + rbx << 2 + 15] +//! +//! // RIP - 64-bit only (RIP can't use INDEX). +//! Mem q = ptr(rip, 24); // q = [rip + 24] +//! } +//! ``` +//! +//! Memory operands can optionally contain memory size. This is required by +//! instructions where the memory size cannot be deduced from other operands, +//! like `inc` and `dec` on X86: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void testX86Mem() { +//! // The same as: dword ptr [rax + rbx]. +//! x86::Mem a = x86::dword_ptr(rax, rbx); +//! +//! // The same as: qword ptr [rdx + rsi << 0 + 1]. +//! x86::Mem b = x86::qword_ptr(rdx, rsi, 0, 1); +//! } +//! ``` +//! +//! Memory operands provide API that can be used to access its properties: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void testX86Mem() { +//! // The same as: dword ptr [rax + 12]. +//! x86::Mem mem = x86::dword_ptr(rax, 12); +//! +//! mem.hasBase(); // true. +//! mem.hasIndex(); // false. +//! mem.size(); // 4. +//! mem.offset(); // 12. +//! +//! mem.setSize(0); // Sets the size to 0 (makes it sizeless). +//! mem.addOffset(-1); // Adds -1 to the offset and makes it 11. +//! mem.setOffset(0); // Sets the offset to 0. +//! mem.setBase(rcx); // Changes BASE to RCX. +//! mem.setIndex(rax); // Changes INDEX to RAX. +//! mem.hasIndex(); // true. +//! } +//! // ... +//! ``` +//! +//! Making changes to memory operand is very comfortable when emitting loads +//! and stores: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void testX86Mem(CodeHolder& code) { +//! x86::Assembler a(code); // Your initialized x86::Assembler. +//! x86::Mem mSrc = x86::ptr(eax); // Construct [eax] memory operand. +//! +//! // One way of emitting bunch of loads is to use `mem.adjusted()`, which +//! // returns a new memory operand and keeps the source operand unchanged. +//! a.movaps(x86::xmm0, mSrc); // No adjustment needed to load [eax]. +//! a.movaps(x86::xmm1, mSrc.adjusted(16)); // Loads from [eax + 16]. +//! a.movaps(x86::xmm2, mSrc.adjusted(32)); // Loads from [eax + 32]. +//! a.movaps(x86::xmm3, mSrc.adjusted(48)); // Loads from [eax + 48]. +//! +//! // ... do something with xmm0-3 ... +//! +//! // Another way of adjusting memory is to change the operand in-place. +//! // If you want to keep the original operand you can simply clone it. +//! x86::Mem mDst = mSrc.clone(); // Clone mSrc. +//! +//! a.movaps(mDst, x86::xmm0); // Stores xmm0 to [eax]. +//! mDst.addOffset(16); // Adds 16 to `mDst`. +//! +//! a.movaps(mDst, x86::xmm1); // Stores to [eax + 16] . +//! mDst.addOffset(16); // Adds 16 to `mDst`. +//! +//! a.movaps(mDst, x86::xmm2); // Stores to [eax + 32]. +//! mDst.addOffset(16); // Adds 16 to `mDst`. +//! +//! a.movaps(mDst, x86::xmm3); // Stores to [eax + 48]. +//! } +//! ``` +//! +//! ### Assembler Examples +//! +//! - \ref x86::Assembler provides many X86/X64 examples. + +// ============================================================================ +// [Documentation - asmjit_builder] +// ============================================================================ //! \defgroup asmjit_builder Builder -//! \brief Builder API. +//! \brief Builder interface, nodes, and passes. +//! +//! ### Overview +//! +//! Both \ref BaseBuilder and \ref BaseCompiler interfaces describe emitters +//! that emit into a representation that allows further processing. The code +//! stored in such representation is completely safe to be patched, simplified, +//! reordered, obfuscated, removed, injected, analyzed, or processed some other +//! way. Each instruction, label, directive, or other building block is stored +//! as \ref BaseNode (or derived class like \ref InstNode or \ref LabelNode) +//! and contains all the information necessary to pass that node later to the +//! assembler. +//! +//! \ref BaseBuilder is an emitter that inherits from \ref BaseEmitter interface. +//! It was designed to provide a maximum compatibility with the existing \ref +//! BaseAssembler emitter so users can move from assembler to builder when needed, +//! for example to implement post-processing, which is not possible with Assembler. +//! +//! ### Builder Nodes +//! +//! \ref BaseBuilder doesn't generate machine code directly, it uses an intermediate +//! representation based on nodes, however, it allows to serialize to \ref BaseAssembler +//! when the code is ready to be encoded. //! -//! Both Builder and Compiler are emitters that emit everything to a representation -//! that allows further processing. The code stored in such representation is -//! completely safe to be patched, simplified, reordered, obfuscated, removed, -//! injected, analyzed, or processed some other way. Each instruction, label, -//! directive, or other building block is stored as \ref BaseNode (or derived -//! class like \ref InstNode or \ref LabelNode) and contains all the information -//! necessary to pass that node later to the Assembler. +//! There are multiple node types used by both \ref BaseBuilder and \ref BaseCompiler : +//! +//! - Basic nodes: +//! - \ref BaseNode - Base class for all nodes. +//! - \ref InstNode - Represents an instruction node. +//! - \ref AlignNode - Represents an alignment directive (.align). +//! - \ref LabelNode - Represents a location where to bound a \ref Label. +//! +//! - Data nodes: +//! - \ref EmbedDataNode - Represents data. +//! - \ref EmbedLabelNode - Represents \ref Label address embedded as data. +//! - \ref EmbedLabelDeltaNode - Represents a difference of two labels +//! embedded in data. +//! - \ref ConstPoolNode - Represents a constant pool data embedded as data. +//! +//! - Informative nodes: +//! - \ref CommentNode - Represents a comment string, doesn't affect code +//! generation. +//! - \ref SentinelNode - A marker that can be used to remember certain +//! position in code or data, doesn't affect code generation. Used by +//! \ref FuncNode to mark the end of a function. +//! +//! - Other nodes are provided by \ref asmjit_compiler infrastructure. +//! +//! ### Builder Examples +//! +//! - \ref x86::Builder provides many X86/X64 examples. + +// ============================================================================ +// [Documentation - asmjit_compiler] +// ============================================================================ //! \defgroup asmjit_compiler Compiler -//! \brief Compiler API. +//! \brief Compiler interface. +//! +//! ### Overview +//! +//! \ref BaseCompiler is a high-level interface built on top of \ref BaseBuilder +//! interface, which provides register allocation and support for defining and +//! invoking functions. At the moment it's the easiest way of generating code +//! in AsmJit as most architecture and OS specifics is properly abstracted and +//! handled by AsmJit automatically. However, abstractions also mean restrictions, +//! which means that \ref BaseCompiler has more limitations that \ref BaseAssembler +//! or \ref BaseBuilder. +//! +//! Since \ref BaseCompiler provides register allocation it also establishes the +//! concept of functions - a function in Compiler sense is a unit in which virtual +//! registers are allocated into physical registers by the register allocator. +//! In addition, it enables to use such virtual registers in function invocations. +//! +//! \ref BaseCompiler automatically handles function calling conventions. It's +//! still architecture dependent, but makes the code generation much easies. +//! Functions are essential; the first-step to generate some code is to define a +//! signature of the function to be generated (before generating the function body +//! itself). Function arguments and return value(s) are handled by assigning +//! virtual registers to them. Similarly, function calls are handled the same way. +//! +//! ### Compiler Nodes +//! +//! \ref BaseCompiler adds some nodes that are required for function generation +//! and invocation: +//! +//! - \ref FuncNode - Represents a function definition. +//! - \ref FuncRetNode - Represents a function return. +//! - \ref InvokeNode - Represents a function invocation. +//! +//! \ref BaseCompiler also makes the use of passes (\ref Pass) and automatically +//! adds an architecture-dependent register allocator pass to the list of passes +//! when attached to \ref CodeHolder. +//! +//! ### Compiler Examples +//! +//! - \ref x86::Compiler provides many X86/X64 examples. +//! +//! ### Compiler Tips +//! +//! Users of AsmJit have done mistakes in the past, this section should provide +//! some useful tips for beginners: +//! +//! - Virtual registers in compiler are bound to a single function. At the +//! moment the implementation doesn't care whether a single virtual register +//! is used in multiple functions, but it sees it as two independent virtual +//! registers in that case. This means that virtual registers cannot be used +//! to implement global variables. Global variables are basically memory +//! addresses which functions can read from and write to, and they have to +//! be implemented in the same way. +//! +//! - Compiler provides a useful debugging functionality, which can be turned +//! on through \ref FormatOptions::Flags. Use \ref Logger::addFlags() to +//! turn on additional logging features when using Compiler. + +// ============================================================================ +// [Documentation - asmjit_function] +// ============================================================================ + +//! \defgroup asmjit_function Function +//! \brief Function definitions. +//! +//! ### Overview +//! +//! AsmJit provides functionality that can be used to define function signatures +//! and to calculate automatically optimal function frame that can be used directly +//! by a prolog and epilog insertion. This feature was exclusive to AsmJit's Compiler +//! for a very long time, but was abstracted out and is now available for all users +//! regardless of the emitter they use. The following use cases are possible: +//! +//! - Calculate function frame before the function is generated - this is the +//! only way available to \ref BaseAssembler users and it will be described +//! in this section. +//! +//! - Calculate function frame after the function is generated - this way is +//! generally used by \ref BaseBuilder and \ref BaseCompiler emitters and +//! this way is generally described in \ref asmjit_compiler section. +//! +//! The following concepts are used to describe and create functions in AsmJit: +//! +//! - \ref Type::Id - Type-id is an 8-bit value that describes a platform +//! independent type as we know from C/C++. It provides abstractions for +//! most common types like `int8_t`, `uint32_t`, `uintptr_t`, `float`, +//! `double`, and all possible vector types to match ISAs up to AVX512. +//! \ref Type::Id was introduced originally for \ref asmjit_compiler, but +//! it's now used by \ref FuncSignature as well. +//! +//! - \ref CallConv - Describes a calling convention - this class contains +//! instructions to assign registers and stack addresses to function +//! arguments and return value(s), but doesn't specify any function +//! signature itself. Calling conventions are architecture and OS dependent. +//! +//! - \ref FuncSignature - Describes a function signature, for example +//! `int func(int, int)`. FuncSignature contains a function calling convention +//! id, return value type, and function arguments. The signature itself is +//! platform independent and uses \ref Type::Id to describe types of function +//! arguments and function return value(s). +//! +//! - \ref FuncDetail - Architecture and ABI dependent information that describes +//! \ref CallConv and expanded \ref FuncSignature. Each function argument and +//! return value is represented as \ref FuncValue that contains the original +//! \ref Type::Id enriched with additional information that specifies whether +//! the value is passed or returned by register (and which register) or by +//! stack. Each value also contains some other metadata that provide additional +//! information required to handle it properly (for example whether a vector is +//! passed indirectly by a pointer as required by WIN64 calling convention). +//! +//! - \ref FuncFrame - Contains information about the function frame that can +//! be used by prolog/epilog inserter (PEI). Holds call stack size size and +//! alignment, local stack size and alignment, and various attributes that +//! describe how prolog and epilog should be constructed. `FuncFrame` doesn't +//! know anything about function's arguments or return values, it hold only +//! information necessary to create a valid and ABI conforming function prologs +//! and epilogs. +//! +//! - \ref FuncArgsAssignment - A helper class that can be used to reassign +//! function arguments into user specified registers. It's architecture and +//! ABI dependent mapping from function arguments described by \ref CallConv +//! and \ref FuncDetail into registers specified by the user. +//! +//! It's a lot of concepts where each represents one step in a function frame +//! calculation. It can be used to create function prologs, epilogs, and also +//! to calculate information necessary to perform function calls. + +// ============================================================================ +// [Documentation - asmjit_logging] +// ============================================================================ + +//! \defgroup asmjit_logging Logging +//! \brief Logging and formatting. +//! +//! ### Overview +//! +//! The initial phase of a project that generates machine code is not always smooth. +//! Failure cases are common not just at the beginning phase, but also during the +//! development or refactoring. AsmJit provides logging functionality to address +//! this issue. AsmJit does already a good job with function overloading to prevent +//! from emitting unencodable instructions, but it can't prevent from emitting machine +//! code that is correct at instruction level, but doesn't work when it's executed as +//! a whole. Logging has always been an important part of AsmJit's infrastructure and +//! looking at logs can sometimes reveal code generation issues quickly. +//! +//! AsmJit provides API for logging and formatting: +//! - \ref Logger - A logger that you can pass to \ref CodeHolder and all emitters +//! that inherit from \ref BaseEmitter. +//! - \ref FormatOptions - Formatting options that can change how instructions and +//! operands are formatted. +//! - \ref Formatter - A namespace that provides functions that can format input +//! data like \ref Operand, \ref BaseReg, \ref Label, and \ref BaseNode into +//! \ref String. +//! +//! AsmJit's \ref Logger serves the following purposes: +//! - Provides a basic foundation for logging. +//! - Abstract class leaving the implementation on users. The following built-in +//! inplementations are provided for simplicty: +//! - \ref FileLogger implements logging into a standard `FILE` stream. +//! - \ref StringLogger serializes all logs into a \ref String instance. +//! +//! AsmJit's \ref FormatOptions provides the following to customize the formatting of +//! instructions and operands through: +//! - \ref FormatOptions::Flags +//! - \ref FormatOptions::IndentationType +//! +//! ### Logging +//! +//! A \ref Logger is typically attached to a \ref CodeHolder, which propagates it +//! to all attached emitters automatically. The example below illustrates how to +//! use \ref FileLogger that outputs to standard output: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! FileLogger logger(stdout); // Logger should always survive CodeHolder. +//! +//! CodeHolder code; // Holds code and relocation information. +//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime. +//! code.setLogger(&logger); // Attach the `logger` to `code` holder. +//! +//! // ... code as usual, everything emitted will be logged to `stdout` ... +//! return 0; +//! } +//! ``` +//! +//! If output to FILE stream is not desired it's possible to use \ref StringLogger, +//! which concatenates everything into a multi-line string: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! #include <utility> +//! +//! using namespace asmjit; +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! StringLogger logger; // Logger should always survive CodeHolder. +//! +//! CodeHolder code; // Holds code and relocation information. +//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime. +//! code.setLogger(&logger); // Attach the `logger` to `code` holder. +//! +//! // ... code as usual, logging will be concatenated to logger string ... +//! +//! // You can either use the string from StringLogger directly or you can +//! // move it. Logger::data() returns its content as null terminated char[]. +//! printf("Logger content: %s\n", logger.data()); +//! +//! // It can be moved into your own string like this: +//! String content = std::move(logger.content()); +//! printf("The same content: %s\n", content.data()); +//! +//! return 0; +//! } +//! ``` +//! +//! ### Formatting +//! +//! AsmJit uses \ref Formatter to format inputs that are then passed to \ref +//! Logger. Formatting is public and can be used by AsmJit users as well. The +//! most important thing to know regarding formatting is that \ref Formatter +//! always appends to the output string, so it can be used to build complex +//! strings without having to concatenate intermediate strings. +//! +//! The first example illustrates how to format operands: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! void logOperand(uint32_t arch, const Operand_& op) { +//! // The emitter is optional (named labels and virtual registers need it). +//! BaseEmitter* emitter = nullptr; //! -//! Compiler tool is built on top of a \ref asmjit_builder API and adds register -//! allocation and support for defining and calling functions into it. At the -//! moment it's the easiest way to generate some code as most architecture and -//! OS specific stuff is properly abstracted, however, abstractions also mean -//! that not everything is possible with the Compiler. +//! // No flags by default. +//! uint32_t formatFlags = FormatOptions::kNoFlags; +//! +//! StringTmp<128> sb; +//! Formatter::formatOperand(sb, formatFlags, emitter, arch, op); +//! printf("%s\n", sb.data()); +//! } +//! +//! void formattingExample() { +//! using namespace x86; +//! +//! // Architecture is not part of operand, it must be passed explicitly. +//! // Format flags. We pass it explicitly also to 'logOperand' to make +//! // compatible with what AsmJit normally does. +//! uint32_t arch = Environment::kArchX64; +//! +//! log(arch, rax); // Prints 'rax'. +//! log(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`. +//! log(arch, dword_ptr(rax, rbx, 2)); // Prints 'dword [rax + rbx * 4]`. +//! log(arch, imm(42)); // Prints '42'. +//! } +//! ``` +//! +//! Next example illustrates how to format whole instructions: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! #include <utility> +//! +//! using namespace asmjit; +//! +//! template<typename... Args> +//! void logInstruction(uint32_t arch, const BaseInst& inst, Args&&... args) { +//! // The emitter is optional (named labels and virtual registers need it). +//! BaseEmitter* emitter = nullptr; +//! +//! // No flags by default. +//! uint32_t formatFlags = FormatOptions::kNoFlags; +//! +//! // The formatter expects operands in an array. +//! Operand_ operands { std::forward<Args>(args)... }; +//! +//! StringTmp<128> sb; +//! Formatter::formatInstruction( +//! sb, formatFlags, emitter, arch, inst, operands, sizeof...(args)); +//! printf("%s\n", sb.data()); +//! } +//! +//! void formattingExample() { +//! using namespace x86; +//! +//! // Architecture is not part of operand, it must be passed explicitly. +//! // Format flags. We pass it explicitly also to 'logOperand' to make +//! // compatible with what AsmJit normally does. +//! uint32_t arch = Environment::kArchX64; +//! +//! // Prints 'mov rax, rcx'. +//! logInstruction(arch, BaseInst(Inst::kIdMov), rax, rcx); +//! +//! // Prints 'vaddpd zmm0, zmm1, [rax] {1to8}'. +//! logInstruction(arch, +//! BaseInst(Inst::kIdVaddpd), +//! zmm0, zmm1, ptr(rax)._1toN()); +//! +//! // BaseInst abstracts instruction id, instruction options, and extraReg. +//! // Prints 'lock add [rax], rcx'. +//! logInstruction(arch, +//! BaseInst(Inst::kIdAdd, Inst::kOptionLock), +//! x86::ptr(rax), rcx); +//! +//! // Similarly an extra register (like AVX-512 selector) can be used. +//! // Prints 'vaddpd zmm0 {k2} {z}, zmm1, [rax]'. +//! logInstruction(arch, +//! BaseInst(Inst::kIdAdd, Inst::kOptionZMask, k2), +//! zmm0, zmm1, ptr(rax)); +//! } +//! ``` +//! +//! And finally, the example below illustrates how to use a built-in function +//! to format the content of \ref BaseBuilder, which consists of nodes: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! void formattingExample(BaseBuilder* builder) { +//! uint32_t formatFlags = FormatOptions::kNoFlags; +//! +//! // This also shows how temporary strings can be used. +//! StringTmp<512> sb; +//! +//! // FormatNodeList requires the String for output, formatting flags, which +//! // were zero (no extra flags), and the builder instance, which we have +//! // provided. An overloaded version also exists, which accepts begin and +//! // and end nodes, which can be used to only format a range of nodes. +//! Formatter::formatNodeList(sb, formatFlags, builder); +//! +//! // You can do whatever else with the string, it's always null terminated, +//! // so it can be passed to C functions like printf(). +//! printf("%s\n", sb.data()); +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_error_handling] +// ============================================================================ + +//! \defgroup asmjit_error_handling Error Handling +//! \brief Error handling. +//! +//! ### Overview +//! +//! AsmJit uses error codes to represent and return errors. Every function that +//! can fail returns an \ref Error code. Exceptions are never thrown by AsmJit +//! itself even in extreme conditions like out-of-memory, but it's possible to +//! override \ref ErrorHandler::handleError() to throw, in that case no error +//! will be returned and exception will be thrown instead. All functions where +//! this can happen are not marked `noexcept`. +//! +//! Errors should never be ignored, however, checking errors after each AsmJit +//! API call would simply overcomplicate the whole code generation experience. +//! \ref ErrorHandler exists to make the use of AsmJit API simpler as it allows +//! to customize how errors can be handled: +//! +//! - Record the error and continue (the way how the error is user-implemented). +//! - Throw an exception. AsmJit doesn't use exceptions and is completely +//! exception-safe, but it's perfectly legal to throw an exception from +//! the error handler. +//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, +//! Builder and Compiler to a consistent state before calling \ref +//! ErrorHandler::handleError(), so `longjmp()` can be used without issues to +//! cancel the code-generation if an error occurred. This method can be used if +//! exception handling in your project is turned off and you still want some +//! comfort. In most cases it should be safe as AsmJit uses \ref Zone memory +//! and the ownership of memory it allocates always ends with the instance that +//! allocated it. If using this approach please never jump outside the life-time +//! of \ref CodeHolder and \ref BaseEmitter. +//! +//! ### Using ErrorHandler +//! +//! An example of attaching \ref ErrorHandler to \ref CodeHolder. +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // A simple error handler implementation, extend according to your needs. +//! class MyErrorHandler : public ErrorHandler { +//! public: +//! void handleError(Error err, const char* message, BaseEmitter* origin) override { +//! printf("AsmJit error: %s\n", message); +//! } +//! }; +//! +//! int main() { +//! JitRuntime rt; +//! +//! MyErrorHandler myErrorHandler; +//! CodeHolder code; +//! +//! code.init(rt.environment()); +//! code.setErrorHandler(&myErrorHandler); +//! +//! x86::Assembler a(&code); +//! // ... code generation ... +//! +//! return 0; +//! } +//! ``` +//! +//! Useful classes in error handling group: +//! +//! - See \ref DebugUtils that provides utilities useful for debugging. +//! - See \ref Error that lists error codes that AsmJit uses. +//! - See \ref ErrorHandler for more details about error handling. -//! \defgroup asmjit_func Function -//! \brief Function API. +// ============================================================================ +// [Documentation - asmjit_instruction_db] +// ============================================================================ -//! \defgroup asmjit_jit JIT -//! \brief JIT API and Virtual Memory Management. +//! \defgroup asmjit_instruction_db Instruction DB +//! \brief Instruction database (introspection, read/write, validation, ...). +//! +//! ### Overview +//! +//! AsmJit provides a public instruction database that can be used to query +//! information about a complete instruction. The instruction database requires +//! the knowledge of the following: +//! +//! - \ref BaseInst - Base instruction that contains instruction id, options, +//! and a possible extra-register that represents either REP prefix counter +//! or AVX-512 selector (mask). +//! - \ref Operand - Represents operands of an instruction. +//! +//! Each instruction can be then queried for the following information: +//! +//! - \ref InstRWInfo - Read/write information of instruction and its oprands. +//! - \ref OpRWInfo - Read/write information of a single operand, part of +//! \ref InstRWInfo data structure. +//! - \ref BaseFeatures - CPU features required to execute the instruction. +//! +//! In addition to query functionality AsmJit is also able to validate whether +//! an instruction and its operands are valid. This is useful for making sure +//! that what user tries to emit is correct and it can be also used by other +//! projects that parse user input, like AsmTK project. +//! +//! ### Query API +//! +//! The instruction query API is provided by \ref InstAPI namespace. The +//! following queries are possible: +//! +//! - \ref InstAPI::queryRWInfo() - queries read/write information of the +//! given instruction and its operands. Includes also CPU flags read/written. +//! +//! - \ref InstAPI::queryFeatures() - queries CPU features that are required +//! to execute the given instruction. A full instruction with operands must +//! be given as some architectures like X86 may require different features +//! for the same instruction based on its operands. +//! +//! - <a href="https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_instinfo.cpp">asmjit_test_x86_instinfo.cpp</a> +//! can be also used as a reference about accessing instruction information. +//! +//! ### Validation API +//! +//! The instruction validation API is provided by \ref InstAPI namespace in the +//! similar fashion like the Query API, however, validation can also be turned +//! on at \ref BaseEmitter level. The following is possible: +//! +//! - \ref InstAPI::validate() - low-level instruction validation function +//! that is used internally by emitters if strict validation is enabled. +//! +//! - \ref BaseEmitter::addValidationOptions() - can be used to enable +//! validation at emitter level, see \ref BaseEmitter::ValidationOptions. -//! \defgroup asmjit_zone Zone -//! \brief Zone allocator and zone allocated containers. -//! \defgroup asmjit_support Support -//! \brief Support API. +// ============================================================================ +// [Documentation - asmjit_virtual_memory] +// ============================================================================ + +//! \defgroup asmjit_virtual_memory Virtual Memory +//! \brief Virtual memory management. +//! +//! ### Overview +//! +//! AsmJit's virtual memory management is divided into two main categories: +//! +//! - Low level API that provides cross-platform abstractions for virtual +//! memory allocation. Implemented in \ref VirtMem namespace. +//! - High level API that makes it very easy to store generated code for +//! execution. See \ref JitRuntime, which is used by many examples for its +//! simplicity and easy integration with \ref CodeHolder. There is also +//! \ref JitAllocator, which lays somewhere between RAW memory allocation +//! and \ref JitRuntime. + +// ============================================================================ +// [Documentation - asmjit_zone_memory] +// ============================================================================ + +//! \defgroup asmjit_zone Zone Memory +//! \brief Zone memory allocator and containers. +//! +//! ### Overview +//! +//! AsmJit uses zone memory allocation (also known as Arena allocation) to allocate +//! most of the data it uses. It's a fast allocator that allows AsmJit to allocate +//! a lot of small data structures fast and without `malloc()` overhead. Since +//! code generators and all related classes are usually short-lived this approach +//! decreases memory usage and fragmentation as arena-based allocators always +//! allocate larger blocks of memory, which are then split into smaller chunks. +//! +//! Another advantage of zone memory allocation is that since the whole library +//! uses this strategy it's very easy to deallocate everything that a particular +//! instance is holding by simply releasing the memory the allocator holds. This +//! improves destruction time of such objects as there is no destruction at all. +//! Long-lived objects just reset its data in destructor or in their reset() +//! member function for a future reuse. For this purpose all containers in AsmJit +//! are also zone allocated. +//! +//! ### Zone Allocation +//! +//! - \ref Zone - Incremental zone memory allocator with minimum features. It +//! can only allocate memory without the possibility to return it back to +//! the allocator. +//! +//! - \ref ZoneTmp - A temporary \ref Zone with some initial static storage. +//! If the allocation requests fit the static storage allocated then there +//! will be no dynamic memory allocation during the lifetime of \ref ZoneTmp, +//! otherwise it would act as \ref Zone with one preallocated block on the +//! stack. +//! +//! - \ref ZoneAllocator - A wrapper of \ref Zone that provides the capability +//! of returning memory to the allocator. Such memory is stored in a pool for +//! later reuse. +//! +//! ### Zone Allocated Containers +//! +//! - \ref ZoneString - Zone allocated string. +//! - \ref ZoneHash - Zone allocated hash table. +//! - \ref ZoneTree - Zone allocated red-black tree. +//! - \ref ZoneList - Zone allocated double-linked list. +//! - \ref ZoneStack - Zone allocated stack. +//! - \ref ZoneVector - Zone allocated vector. +//! - \ref ZoneBitVector - Zone allocated vector of bits. +//! +//! ### Using Zone Allocated Containers +//! +//! The most common data structure exposed by AsmJit is \ref ZoneVector. It's very +//! similar to `std::vector`, but the implementation doesn't use exceptions and +//! uses the mentioned \ref ZoneAllocator for performance reasons. You don't have +//! to worry about allocations as you should not need to add items to AsmJit's +//! data structures directly as there should be API for all required operations. +//! +//! The following APIs in \ref CodeHolder returns \ref ZoneVector reference: +//! +//! ``` +//! using namespace asmjit; +//! +//! void example(CodeHolder& code) { +//! // Contains all emitters attached to CodeHolder. +//! const ZoneVector<BaseEmitter*>& emitters = code.emitters(); +//! +//! // Contains all section entries managed by CodeHolder. +//! const ZoneVector<Section*>& sections = code.sections(); +//! +//! // Contains all label entries managed by CodeHolder. +//! const ZoneVector<LabelEntry*>& labelEntries = code.labelEntries(); +//! +//! // Contains all relocation entries managed by CodeHolder. +//! const ZoneVector<RelocEntry*>& relocEntries = code.relocEntries(); +//! } +//! ``` +//! +//! \ref ZoneVector has overloaded array access operator to make it possible +//! to access its elements through operator[]. Some standard functions like +//! \ref ZoneVector::empty(), \ref ZoneVector::size(), and \ref ZoneVector::data() +//! are provided as well. Vectors are also iterable through a range-based for loop: +//! +//! ``` +//! using namespace asmjit; +//! +//! void example(CodeHolder& code) { +//! for (LabelEntry* le : code.labelEntries()) { +//! printf("Label #%u {Bound=%s Offset=%llu}", +//! le->id(), +//! le->isBound() ? "true" : "false", +//! (unsigned long long)le->offset()); +//! } +//! } +//! ``` +//! +//! ### Design Considerations +//! +//! Zone-allocated containers do not store the allocator within the container. +//! This decision was made to reduce the footprint of such containers as AsmJit +//! tooling, especially Compiler's register allocation, may use many instances +//! of such containers to perform code analysis and register allocation. +//! +//! For example to append an item into a \ref ZoneVector it's required to pass +//! the allocator as the first argument, so it can be used in case that the +//! vector needs a reallocation. Such function also returns an error, which +//! must be propagated to the caller. +//! +//! ``` +//! using namespace asmjit +//! +//! Error example(ZoneAllocator* allocator) { +//! ZoneVector<int> vector; +//! +//! // Unfortunately, allocator must be provided to all functions that mutate +//! // the vector. However, AsmJit users should never need to do this as all +//! // manipulation should be done through public API, which takes care of +//! // that. +//! for (int i = 0; i < 100; i++) { +//! ASMJIT_PROPAGATE(vector.append(allocator, i)); +//! } +//! +//! // By default vector's destructor doesn't release anything as it knows +//! // that its content is zone allocated. However, \ref ZoneVector::release +//! // can be used to explicitly release the vector data to the allocator if +//! // necessary +//! vector.release(allocator); +//! } +//! ``` +//! +//! Containers like \ref ZoneVector also provide a functionality to reserve a +//! certain number of items before any items are added to it. This approach is +//! used internally in most places as it allows to prepare space for data that +//! will be added to some container before the data itself was created. +//! +//! ``` +//! using namespace asmjit +//! +//! Error example(ZoneAllocator* allocator) { +//! ZoneVector<int> vector; +//! +//! ASMJIT_PROPAGATE(vector.willGrow(100)); +//! for (int i = 0; i < 100; i++) { +//! // Cannot fail. +//! vector.appendUnsafe(allocator, i); +//! } +//! +//! vector.release(allocator); +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_utilities] +// ============================================================================ + +//! \defgroup asmjit_utilities Utilities +//! \brief Utility classes and functions. +//! +//! ### Overview +//! +//! AsmJit uses and provides utility classes and functions, that can be used +//! with AsmJit. The functionality can be divided into the following topics: +//! +//! ### String Functionality +//! +//! - \ref String - AsmJit's string container, which is used internally +//! and which doesn't use exceptions and has a stable layout, which is +//! not dependent on C++ standard library. +//! - \ref StringTmp - String that can have base storage allocated on +//! stack. The amount of storage on stack can be specified as a template +//! parameter. +//! - \ref FixedString - Fixed string container limited up to N characters. +//! +//! ### Code Generation Utilities +//! +//! - \ref ConstPool - Constant pool used by \ref BaseCompiler, but also +//! available to users that may find use of it. +//! +//! ### Support Functionality Used by AsmJit +//! +//! - \ref Support namespace provides many other utility functions and +//! classes that are used by AsmJit, and made public. + +// ============================================================================ +// [Documentation - asmjit_<arch> backends] +// ============================================================================ + +//! \defgroup asmjit_x86 X86 Backend +//! \brief X86/X64 backend. + +// ============================================================================ +// [Documentation - asmjit_ra] +// ============================================================================ //! \cond INTERNAL //! \defgroup asmjit_ra RA //! \brief Register allocator internals. //! \endcond +} // {asmjit} + +// ============================================================================ +// [Core Headers] +// ============================================================================ + #include "./core/globals.h" #include "./core/arch.h" @@ -78,12 +2013,15 @@ #include "./core/cpuinfo.h" #include "./core/datatypes.h" #include "./core/emitter.h" +#include "./core/environment.h" +#include "./core/errorhandler.h" #include "./core/features.h" +#include "./core/formatter.h" #include "./core/func.h" #include "./core/inst.h" #include "./core/jitallocator.h" #include "./core/jitruntime.h" -#include "./core/logging.h" +#include "./core/logger.h" #include "./core/operand.h" #include "./core/osutils.h" #include "./core/string.h" @@ -99,4 +2037,23 @@ #include "./core/zonestring.h" #include "./core/zonevector.h" +// ============================================================================ +// [Deprecated] +// ============================================================================ + +#ifndef ASMJIT_NO_DEPRECATED +namespace asmjit { + +#ifndef ASMJIT_NO_COMPILER +ASMJIT_DEPRECATED("Use InvokeNode instead of FuncCallNode") +typedef InvokeNode FuncCallNode; +#endif // !ASMJIT_NO_COMPILER + +#ifndef ASMJIT_NO_LOGGING +namespace Logging { using namespace Formatter; } +#endif //! ASMJIT_NO_LOGGING + +} // {asmjit} +#endif // !ASMJIT_NO_DEPRECATED + #endif // ASMJIT_CORE_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/api-build_p.h b/3rdparty/asmjit/src/asmjit/core/api-build_p.h index 714107c204d..db37ca77e93 100644 --- a/3rdparty/asmjit/src/asmjit/core/api-build_p.h +++ b/3rdparty/asmjit/src/asmjit/core/api-build_p.h @@ -53,7 +53,7 @@ #include "./api-config.h" -#if !defined(ASMJIT_BUILD_DEBUG) && ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 4, 0) +#if !defined(ASMJIT_BUILD_DEBUG) && defined(__GNUC__) && !defined(__clang__) #define ASMJIT_FAVOR_SIZE __attribute__((__optimize__("Os"))) #define ASMJIT_FAVOR_SPEED __attribute__((__optimize__("O3"))) #elif ASMJIT_CXX_HAS_ATTRIBUTE(__minsize__, 0) diff --git a/3rdparty/asmjit/src/asmjit/core/api-config.h b/3rdparty/asmjit/src/asmjit/core/api-config.h index de5985a066a..1388da49618 100644 --- a/3rdparty/asmjit/src/asmjit/core/api-config.h +++ b/3rdparty/asmjit/src/asmjit/core/api-config.h @@ -28,78 +28,90 @@ // [asmjit::Version] // ============================================================================ -#define ASMJIT_LIBRARY_VERSION 0x010200 /* 1.2.0 */ +//! \addtogroup asmjit_core +//! \{ + +//! AsmJit library version in `(Major << 16) | (Minor << 8) | (Patch)` format. +#define ASMJIT_LIBRARY_VERSION 0x010400 /* 1.4.0 */ + +//! \} // ============================================================================ -// [asmjit::Options] +// [asmjit::Build - Documentation] // ============================================================================ -// AsmJit Static Builds and Embedding -// ---------------------------------- -// -// These definitions can be used to enable static library build. Embed is used -// when AsmJit's source code is embedded directly in another project, implies -// static build as well. -// -// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_BUILD_STATIC). -#define ASMJIT_STATIC // Enable static-library build. +// NOTE: Doxygen cannot document macros that are not defined, that's why we have +// to define them and then undefine them, so it won't use the macros with its +// own preprocessor. +#ifdef _DOXYGEN +namespace asmjit { -// AsmJit Build Mode -// ----------------- -// -// These definitions control the build mode and tracing support. The build mode -// should be auto-detected at compile time, but it's possible to override it in -// case that the auto-detection fails. -// -// Tracing is a feature that is never compiled by default and it's only used to -// debug AsmJit itself. -// -// #define ASMJIT_BUILD_DEBUG // Always use debug-mode (ASMJIT_ASSERT enabled). -// #define ASMJIT_BUILD_RELEASE // Always use release-mode (ASMJIT_ASSERT disabled). +//! \addtogroup asmjit_build +//! \{ -// AsmJit Build Backends -// --------------------- -// -// These definitions control which backends to compile. If none of these is -// defined AsmJit will use host architecture by default (for JIT code generation). -// -// #define ASMJIT_BUILD_X86 // Enable X86 targets (X86 and X86_64). -// #define ASMJIT_BUILD_ARM // Enable ARM targets (ARM and AArch64). -// #define ASMJIT_BUILD_HOST // Enable targets based on target arch (default). +//! Asmjit is embedded, implies \ref ASMJIT_STATIC. +#define ASMJIT_EMBED -// AsmJit Build Options -// -------------------- -// -// Flags can be defined to disable standard features. These are handy especially -// when building AsmJit statically and some features are not needed or unwanted -// (like BaseCompiler). -// -// AsmJit features are enabled by default. -// #define ASMJIT_NO_BUILDER // Disable Builder (completely). -// #define ASMJIT_NO_COMPILER // Disable Compiler (completely). -// #define ASMJIT_NO_JIT // Disable JIT memory manager and JitRuntime. -// #define ASMJIT_NO_LOGGING // Disable logging and formatting (completely). -// #define ASMJIT_NO_TEXT // Disable everything that contains text -// // representation (instructions, errors, ...). -// #define ASMJIT_NO_VALIDATION // Disable validation API and options. -// #define ASMJIT_NO_INTROSPECTION // Disable API related to instruction database. -// // (validation, cpu features, rw-info, etc). +//! Enables static-library build. +#define ASMJIT_STATIC -// ASMJIT_NO_BUILDER implies ASMJIT_NO_COMPILER. -#if defined(ASMJIT_NO_BUILDER) && !defined(ASMJIT_NO_COMPILER) - #define ASMJIT_NO_COMPILER -#endif +//! Defined when AsmJit's build configuration is 'Debug'. +//! +//! \note Can be defined explicitly to bypass autodetection. +#define ASMJIT_BUILD_DEBUG -// Prevent compile-time errors caused by misconfiguration. -#if defined(ASMJIT_NO_TEXT) && !defined(ASMJIT_NO_LOGGING) - #pragma "ASMJIT_NO_TEXT can only be defined when ASMJIT_NO_LOGGING is defined." - #undef ASMJIT_NO_TEXT -#endif +//! Defined when AsmJit's build configuration is 'Release'. +//! +//! \note Can be defined explicitly to bypass autodetection. +#define ASMJIT_BUILD_RELEASE -#if defined(ASMJIT_NO_INTROSPECTION) && !defined(ASMJIT_NO_COMPILER) - #pragma message("ASMJIT_NO_INTROSPECTION can only be defined when ASMJIT_NO_COMPILER is defined") - #undef ASMJIT_NO_INTROSPECTION -#endif +//! Defined to build X86/X64 backend. +#define ASMJIT_BUILD_X86 + +//! Defined to build ARM/AArch64 backend. +#define ASMJIT_BUILD_ARM + +//! Defined to build host backend autodetected at compile-time. +#define ASMJIT_BUILD_HOST + +//! Disables deprecated API at compile time. +#define ASMJIT_NO_DEPRECATED + +//! Disables \ref asmjit_builder functionality completely. +#define ASMJIT_NO_BUILDER + +//! Disables \ref asmjit_compiler functionality completely. +#define ASMJIT_NO_COMPILER + +//! Disables JIT memory management and \ref JitRuntime. +#define ASMJIT_NO_JIT + +//! Disables \ref Logger and \ref Formatter. +#define ASMJIT_NO_LOGGING + +//! Disables everything that contains text. +#define ASMJIT_NO_TEXT + +//! Disables instruction validation API. +#define ASMJIT_NO_VALIDATION + +//! Disables instruction introspection API. +#define ASMJIT_NO_INTROSPECTION + +// Avoid doxygen preprocessor using feature-selection definitions. +#undef ASMJIT_NO_DEPRECATED +#undef ASMJIT_NO_BUILDER +#undef ASMJIT_NO_COMPILER +#undef ASMJIT_NO_JIT +#undef ASMJIT_NO_LOGGING +#undef ASMJIT_NO_TEXT +#undef ASMJIT_NO_VALIDATION +#undef ASMJIT_NO_INTROSPECTION + +//! \} + +} // {asmjit} +#endif // _DOXYGEN // ============================================================================ // [asmjit::Dependencies] @@ -122,23 +134,45 @@ #include <pthread.h> #endif + +// ============================================================================ +// [asmjit::Options] +// ============================================================================ + +// ASMJIT_NO_BUILDER implies ASMJIT_NO_COMPILER. +#if defined(ASMJIT_NO_BUILDER) && !defined(ASMJIT_NO_COMPILER) + #define ASMJIT_NO_COMPILER +#endif + +// Prevent compile-time errors caused by misconfiguration. +#if defined(ASMJIT_NO_TEXT) && !defined(ASMJIT_NO_LOGGING) + #pragma "ASMJIT_NO_TEXT can only be defined when ASMJIT_NO_LOGGING is defined." + #undef ASMJIT_NO_TEXT +#endif + +#if defined(ASMJIT_NO_INTROSPECTION) && !defined(ASMJIT_NO_COMPILER) + #pragma message("ASMJIT_NO_INTROSPECTION can only be defined when ASMJIT_NO_COMPILER is defined") + #undef ASMJIT_NO_INTROSPECTION +#endif + // ============================================================================ // [asmjit::Build - Globals - Deprecated] // ============================================================================ -// DEPRECATED: Will be removed in the future. -#if defined(ASMJIT_BUILD_EMBED) || defined(ASMJIT_BUILD_STATIC) - #if defined(ASMJIT_BUILD_EMBED) - #pragma message("'ASMJIT_BUILD_EMBED' is deprecated, use 'ASMJIT_STATIC'") - #endif - #if defined(ASMJIT_BUILD_STATIC) - #pragma message("'ASMJIT_BUILD_STATIC' is deprecated, use 'ASMJIT_STATIC'") - #endif +#ifndef ASMJIT_NO_DEPRECATED + #if defined(ASMJIT_BUILD_EMBED) || defined(ASMJIT_BUILD_STATIC) + #if defined(ASMJIT_BUILD_EMBED) + #pragma message("'ASMJIT_BUILD_EMBED' is deprecated, use 'ASMJIT_STATIC'") + #endif + #if defined(ASMJIT_BUILD_STATIC) + #pragma message("'ASMJIT_BUILD_STATIC' is deprecated, use 'ASMJIT_STATIC'") + #endif - #if !defined(ASMJIT_STATIC) - #define ASMJIT_STATIC + #if !defined(ASMJIT_STATIC) + #define ASMJIT_STATIC + #endif #endif -#endif +#endif // !ASMJIT_NO_DEPRECATED // ============================================================================ // [asmjit::Build - Globals - Build Mode] @@ -181,7 +215,7 @@ #define ASMJIT_ARCH_MIPS 0 #endif -#define ASMJIT_ARCH_BITS (ASMJIT_ARCH_X86 | ASMJIT_ARCH_ARM | ASMJIT_ARCH_MIPS) +#define ASMJIT_ARCH_BITS (ASMJIT_ARCH_X86 | ASMJIT_ARCH_ARM | ASMJIT_ARCH_MIPS) #if ASMJIT_ARCH_BITS == 0 #undef ASMJIT_ARCH_BITS #if defined (__LP64__) || defined(_LP64) @@ -221,11 +255,8 @@ // [asmjit::Build - Globals - C++ Compiler and Features Detection] // ============================================================================ -#define ASMJIT_CXX_CLANG 0 #define ASMJIT_CXX_GNU 0 -#define ASMJIT_CXX_INTEL 0 -#define ASMJIT_CXX_MSC 0 -#define ASMJIT_CXX_MAKE_VER(MAJOR, MINOR, PATCH) ((MAJOR) * 10000000 + (MINOR) * 100000 + (PATCH)) +#define ASMJIT_CXX_MAKE_VER(MAJOR, MINOR) ((MAJOR) * 1000 + (MINOR)) // Intel Compiler [pretends to be GNU or MSC, so it must be checked first]: // - https://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler @@ -233,9 +264,6 @@ // - https://software.intel.com/en-us/articles/c17-features-supported-by-intel-c-compiler #if defined(__INTEL_COMPILER) - #undef ASMJIT_CXX_INTEL - #define ASMJIT_CXX_INTEL ASMJIT_CXX_MAKE_VER(__INTEL_COMPILER / 100, (__INTEL_COMPILER / 10) % 10, __INTEL_COMPILER % 10) - // MSC Compiler: // - https://msdn.microsoft.com/en-us/library/hh567368.aspx // @@ -247,72 +275,26 @@ // - 19.10.0 == VS2017 #elif defined(_MSC_VER) && defined(_MSC_FULL_VER) - #undef ASMJIT_CXX_MSC - #if _MSC_VER == _MSC_FULL_VER / 10000 - #define ASMJIT_CXX_MSC ASMJIT_CXX_MAKE_VER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) - #else - #define ASMJIT_CXX_MSC ASMJIT_CXX_MAKE_VER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) - #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__) - #undef ASMJIT_CXX_CLANG - #define ASMJIT_CXX_CLANG ASMJIT_CXX_MAKE_VER(__clang_major__, __clang_minor__, __clang_patchlevel__) - // GNU Compiler: // - https://gcc.gnu.org/projects/cxx-status.html #elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) #undef ASMJIT_CXX_GNU - #define ASMJIT_CXX_GNU ASMJIT_CXX_MAKE_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) + #define ASMJIT_CXX_GNU ASMJIT_CXX_MAKE_VER(__GNUC__, __GNUC_MINOR__) #endif // Compiler features detection macros. -#if ASMJIT_CXX_CLANG && defined(__has_builtin) - #define ASMJIT_CXX_HAS_BUILTIN(NAME, CHECK) (__has_builtin(NAME)) -#else - #define ASMJIT_CXX_HAS_BUILTIN(NAME, CHECK) (!(!(CHECK))) -#endif - -#if ASMJIT_CXX_CLANG && defined(__has_extension) - #define ASMJIT_CXX_HAS_FEATURE(NAME, CHECK) (__has_extension(NAME)) -#elif ASMJIT_CXX_CLANG && defined(__has_feature) - #define ASMJIT_CXX_HAS_FEATURE(NAME, CHECK) (__has_feature(NAME)) -#else - #define ASMJIT_CXX_HAS_FEATURE(NAME, CHECK) (!(!(CHECK))) -#endif - -#if ASMJIT_CXX_CLANG && defined(__has_attribute) +#if defined(__clang__) && defined(__has_attribute) #define ASMJIT_CXX_HAS_ATTRIBUTE(NAME, CHECK) (__has_attribute(NAME)) #else #define ASMJIT_CXX_HAS_ATTRIBUTE(NAME, CHECK) (!(!(CHECK))) #endif -#if ASMJIT_CXX_CLANG && defined(__has_cpp_attribute) - #define ASMJIT_CXX_HAS_CPP_ATTRIBUTE(NAME, CHECK) (__has_cpp_attribute(NAME)) -#else - #define ASMJIT_CXX_HAS_CPP_ATTRIBUTE(NAME, CHECK) (!(!(CHECK))) -#endif - -// Compiler features by vendor. -#if defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED) - #define ASMJIT_CXX_HAS_NATIVE_WCHAR_T 0 -#else - #define ASMJIT_CXX_HAS_NATIVE_WCHAR_T 1 -#endif - -#if ASMJIT_CXX_HAS_FEATURE(cxx_unicode_literals, ( \ - (ASMJIT_CXX_INTEL >= ASMJIT_CXX_MAKE_VER(14, 0, 0)) || \ - (ASMJIT_CXX_MSC >= ASMJIT_CXX_MAKE_VER(19, 0, 0)) || \ - (ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4 , 5, 0) && __cplusplus >= 201103L) )) - #define ASMJIT_CXX_HAS_UNICODE_LITERALS 1 -#else - #define ASMJIT_CXX_HAS_UNICODE_LITERALS 0 -#endif - // ============================================================================ // [asmjit::Build - Globals - API Decorators & Language Extensions] // ============================================================================ @@ -394,6 +376,15 @@ #define ASMJIT_REGPARM(N) #endif +#if ASMJIT_ARCH_X86 && defined(_WIN32) && defined(_MSC_VER) + #define ASMJIT_VECTORCALL __vectorcall +#elif ASMJIT_ARCH_X86 && defined(_WIN32) + #define ASMJIT_VECTORCALL __attribute__((__vectorcall__)) +#else + #define ASMJIT_VECTORCALL +#endif + + // Type alignment (not allowed by C++11 'alignas' keyword). #if defined(__GNUC__) #define ASMJIT_ALIGN_TYPE(TYPE, N) __attribute__((__aligned__(N))) TYPE @@ -403,13 +394,22 @@ #define ASMJIT_ALIGN_TYPE(TYPE, N) TYPE #endif +//! \def ASMJIT_MAY_ALIAS +//! +//! Expands to `__attribute__((__may_alias__))` if supported. #if defined(__GNUC__) #define ASMJIT_MAY_ALIAS __attribute__((__may_alias__)) #else #define ASMJIT_MAY_ALIAS #endif -// Annotations. +//! \def ASMJIT_LIKELY(...) +//! +//! Condition is likely to be taken (mostly error handling and edge cases). + +//! \def ASMJIT_UNLIKELY(...) +//! +//! Condition is unlikely to be taken (mostly error handling and edge cases). #if defined(__GNUC__) #define ASMJIT_LIKELY(...) __builtin_expect(!!(__VA_ARGS__), 1) #define ASMJIT_UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0) @@ -418,29 +418,42 @@ #define ASMJIT_UNLIKELY(...) (__VA_ARGS__) #endif +//! \def ASMJIT_FALLTHROUGH +//! +//! Portable [[fallthrough]] attribute. #if defined(__clang__) && __cplusplus >= 201103L #define ASMJIT_FALLTHROUGH [[clang::fallthrough]] -#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(7, 0, 0) +#elif defined(__GNUC__) && __GNUC__ >= 7 #define ASMJIT_FALLTHROUGH __attribute__((__fallthrough__)) #else #define ASMJIT_FALLTHROUGH ((void)0) /* fallthrough */ #endif +//! \def ASMJIT_DEPRECATED +//! +//! Marks function, class, struct, enum, or anything else as deprecated. +#if defined(__GNUC__) + #define ASMJIT_DEPRECATED(MESSAGE) __attribute__((__deprecated__(MESSAGE))) + #if defined(__clang__) + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) __attribute__((__deprecated__(MESSAGE))) + #else + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) /* not usable if a deprecated function uses it */ + #endif +#elif defined(_MSC_VER) + #define ASMJIT_DEPRECATED(MESSAGE) __declspec(deprecated(MESSAGE)) + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) /* not usable if a deprecated function uses it */ +#else + #define ASMJIT_DEPRECATED(MESSAGE) + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) +#endif + // Utilities. #define ASMJIT_OFFSET_OF(STRUCT, MEMBER) ((int)(intptr_t)((const char*)&((const STRUCT*)0x100)->MEMBER) - 0x100) #define ASMJIT_ARRAY_SIZE(X) uint32_t(sizeof(X) / sizeof(X[0])) -#if ASMJIT_CXX_HAS_ATTRIBUTE(attribute_deprecated_with_message, ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 5, 0)) - #define ASMJIT_DEPRECATED(DECL, MESSAGE) DECL __attribute__((__deprecated__(MESSAGE))) -#elif ASMJIT_CXX_MSC - #define ASMJIT_DEPRECATED(DECL, MESSAGE) __declspec(deprecated(MESSAGE)) DECL -#else - #define ASMJIT_DEPRECATED(DECL, MESSAGE) DECL -#endif - #if ASMJIT_CXX_HAS_ATTRIBUTE(no_sanitize, 0) #define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF __attribute__((__no_sanitize__("undefined"))) -#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 9, 0) +#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 9) #define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF __attribute__((__no_sanitize_undefined__)) #else #define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF @@ -459,8 +472,7 @@ #define ASMJIT_END_NAMESPACE \ _Pragma("clang diagnostic pop") \ } -#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 0, 0) && \ - ASMJIT_CXX_GNU < ASMJIT_CXX_MAKE_VER(5, 0, 0) +#elif defined(__GNUC__) && __GNUC__ == 4 #define ASMJIT_BEGIN_NAMESPACE \ namespace asmjit { \ _Pragma("GCC diagnostic push") \ @@ -468,7 +480,7 @@ #define ASMJIT_END_NAMESPACE \ _Pragma("GCC diagnostic pop") \ } -#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(8, 0, 0) +#elif defined(__GNUC__) && __GNUC__ >= 8 #define ASMJIT_BEGIN_NAMESPACE \ namespace asmjit { \ _Pragma("GCC diagnostic push") \ @@ -480,8 +492,8 @@ #define ASMJIT_BEGIN_NAMESPACE \ namespace asmjit { \ __pragma(warning(push)) \ - __pragma(warning(disable: 4127)) /* conditional expression is constant*/\ - __pragma(warning(disable: 4201)) /* nameless struct/union */ + __pragma(warning(disable: 4127)) /* conditional expression is const */ \ + __pragma(warning(disable: 4201)) /* nameless struct/union */ #define ASMJIT_END_NAMESPACE \ __pragma(warning(pop)) \ } @@ -521,13 +533,8 @@ // [asmjit::Build - Globals - Cleanup] // ============================================================================ -// Try to cleanup things not used in other public headers. -#ifndef ASMJIT_EXPORTS - #undef ASMJIT_CXX_CLANG - #undef ASMJIT_CXX_GNU - #undef ASMJIT_CXX_INTEL - #undef ASMJIT_CXX_MSC - #undef ASMJIT_CXX_MAKE_VER -#endif +// Cleanup definitions that are only used within this header file. +#undef ASMJIT_CXX_GNU +#undef ASMJIT_CXX_MAKE_VER #endif // ASMJIT_CORE_API_CONFIG_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/arch.cpp b/3rdparty/asmjit/src/asmjit/core/arch.cpp index 97fca9d5c47..7200897b0a0 100644 --- a/3rdparty/asmjit/src/asmjit/core/arch.cpp +++ b/3rdparty/asmjit/src/asmjit/core/arch.cpp @@ -23,151 +23,34 @@ #include "../core/api-build_p.h" #include "../core/arch.h" -#include "../core/support.h" -#include "../core/type.h" #ifdef ASMJIT_BUILD_X86 - #include "../x86/x86operand.h" + #include "../x86/x86archdata_p.h" #endif #ifdef ASMJIT_BUILD_ARM - #include "../arm/armoperand.h" + #include "../arm/armarchdata_p.h" #endif ASMJIT_BEGIN_NAMESPACE // ============================================================================ -// [asmjit::ArchInfo] -// ============================================================================ - -// NOTE: Keep `const constexpr` otherwise MSC would not compile this code correctly. -static const constexpr uint32_t archInfoTable[] = { - // <--------------------+---------------------+-------------------+-------+ - // | Type | SubType | GPInfo| - // <--------------------+---------------------+-------------------+-------+ - Support::bytepack32_4x8(ArchInfo::kIdNone , ArchInfo::kSubIdNone, 0, 0), - Support::bytepack32_4x8(ArchInfo::kIdX86 , ArchInfo::kSubIdNone, 4, 8), - Support::bytepack32_4x8(ArchInfo::kIdX64 , ArchInfo::kSubIdNone, 8, 16), - Support::bytepack32_4x8(ArchInfo::kIdA32 , ArchInfo::kSubIdNone, 4, 16), - Support::bytepack32_4x8(ArchInfo::kIdA64 , ArchInfo::kSubIdNone, 8, 32) -}; - -ASMJIT_FAVOR_SIZE void ArchInfo::init(uint32_t id, uint32_t subId) noexcept { - uint32_t index = id < ASMJIT_ARRAY_SIZE(archInfoTable) ? id : uint32_t(0); - - // Make sure the `archInfoTable` array is correctly indexed. - _signature = archInfoTable[index]; - ASMJIT_ASSERT(_id == index); - - // Even if the architecture is not known we setup its id and sub-id, - // however, such architecture is not really useful. - _id = uint8_t(id); - _subId = uint8_t(subId); -} - -// ============================================================================ // [asmjit::ArchUtils] // ============================================================================ -ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t archId, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept { - uint32_t typeId = typeIdInOut; - - // Zero the signature so it's clear in case that typeId is not invalid. - regInfo._signature = 0; +ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfoOut) noexcept { + // Zero the output in case the input is invalid. + *typeIdOut = 0; + regInfoOut->reset(); - // TODO: Move to X86 backend. #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) { - // Passed RegType instead of TypeId? - if (typeId <= BaseReg::kTypeMax) - typeId = x86::opData.archRegs.regTypeToTypeId[typeId]; - - if (ASMJIT_UNLIKELY(!Type::isValid(typeId))) - return DebugUtils::errored(kErrorInvalidTypeId); - - // First normalize architecture dependent types. - if (Type::isAbstract(typeId)) { - if (typeId == Type::kIdIntPtr) - typeId = (archId == ArchInfo::kIdX86) ? Type::kIdI32 : Type::kIdI64; - else - typeId = (archId == ArchInfo::kIdX86) ? Type::kIdU32 : Type::kIdU64; - } - - // Type size helps to construct all groupss of registers. If the size is zero - // then the TypeId is invalid. - uint32_t size = Type::sizeOf(typeId); - if (ASMJIT_UNLIKELY(!size)) - return DebugUtils::errored(kErrorInvalidTypeId); - - if (ASMJIT_UNLIKELY(typeId == Type::kIdF80)) - return DebugUtils::errored(kErrorInvalidUseOfF80); - - uint32_t regType = 0; - - switch (typeId) { - case Type::kIdI8: - case Type::kIdU8: - regType = x86::Reg::kTypeGpbLo; - break; - - case Type::kIdI16: - case Type::kIdU16: - regType = x86::Reg::kTypeGpw; - break; - - case Type::kIdI32: - case Type::kIdU32: - regType = x86::Reg::kTypeGpd; - break; - - case Type::kIdI64: - case Type::kIdU64: - if (archId == ArchInfo::kIdX86) - return DebugUtils::errored(kErrorInvalidUseOfGpq); - - regType = x86::Reg::kTypeGpq; - break; - - // F32 and F64 are always promoted to use vector registers. - case Type::kIdF32: - typeId = Type::kIdF32x1; - regType = x86::Reg::kTypeXmm; - break; - - case Type::kIdF64: - typeId = Type::kIdF64x1; - regType = x86::Reg::kTypeXmm; - break; - - // Mask registers {k}. - case Type::kIdMask8: - case Type::kIdMask16: - case Type::kIdMask32: - case Type::kIdMask64: - regType = x86::Reg::kTypeKReg; - break; - - // MMX registers. - case Type::kIdMmx32: - case Type::kIdMmx64: - regType = x86::Reg::kTypeMm; - break; - - // XMM|YMM|ZMM registers. - default: - if (size <= 16) - regType = x86::Reg::kTypeXmm; - else if (size == 32) - regType = x86::Reg::kTypeYmm; - else - regType = x86::Reg::kTypeZmm; - break; - } + if (Environment::isFamilyX86(arch)) + return x86::ArchInternal::typeIdToRegInfo(arch, typeId, typeIdOut, regInfoOut); +#endif - typeIdInOut = typeId; - regInfo._signature = x86::opData.archRegs.regInfo[regType].signature(); - return kErrorOk; - } +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::ArchInternal::typeIdToRegInfo(arch, typeId, typeIdOut, regInfoOut); #endif return DebugUtils::errored(kErrorInvalidArch); diff --git a/3rdparty/asmjit/src/asmjit/core/arch.h b/3rdparty/asmjit/src/asmjit/core/arch.h index b0a27fd9cd5..4991a3330d3 100644 --- a/3rdparty/asmjit/src/asmjit/core/arch.h +++ b/3rdparty/asmjit/src/asmjit/core/arch.h @@ -24,7 +24,7 @@ #ifndef ASMJIT_CORE_ARCH_H_INCLUDED #define ASMJIT_CORE_ARCH_H_INCLUDED -#include "../core/globals.h" +#include "../core/environment.h" #include "../core/operand.h" ASMJIT_BEGIN_NAMESPACE @@ -33,153 +33,10 @@ ASMJIT_BEGIN_NAMESPACE //! \{ // ============================================================================ -// [asmjit::ArchInfo] -// ============================================================================ - -class ArchInfo { -public: - union { - struct { - //! Architecture id. - uint8_t _id; - //! Architecture sub-id. - uint8_t _subId; - //! Default size of a general purpose register. - uint8_t _gpSize; - //! Count of all general purpose registers. - uint8_t _gpCount; - }; - //! Architecture signature (32-bit int). - uint32_t _signature; - }; - - //! Architecture id. - enum Id : uint32_t { - kIdNone = 0, //!< No/Unknown architecture. - - // X86 architectures. - kIdX86 = 1, //!< X86 architecture (32-bit). - kIdX64 = 2, //!< X64 architecture (64-bit) (AMD64). - - // ARM architectures. - kIdA32 = 3, //!< ARM 32-bit architecture (AArch32/ARM/THUMB). - kIdA64 = 4, //!< ARM 64-bit architecture (AArch64). - - //! Architecture detected at compile-time (architecture of the host). - kIdHost = ASMJIT_ARCH_X86 == 32 ? kIdX86 : - ASMJIT_ARCH_X86 == 64 ? kIdX64 : - ASMJIT_ARCH_ARM == 32 ? kIdA32 : - ASMJIT_ARCH_ARM == 64 ? kIdA64 : kIdNone - }; - - //! Architecture sub-type or execution mode. - enum SubType : uint32_t { - kSubIdNone = 0, //!< Default mode (or no specific mode). - - // X86 sub-types. - kSubIdX86_AVX = 1, //!< Code generation uses AVX by default (VEC instructions). - kSubIdX86_AVX2 = 2, //!< Code generation uses AVX2 by default (VEC instructions). - kSubIdX86_AVX512 = 3, //!< Code generation uses AVX-512F by default (+32 vector regs). - kSubIdX86_AVX512VL = 4, //!< Code generation uses AVX-512F-VL by default (+VL extensions). - - // ARM sub-types. - kSubIdA32_Thumb = 8, //!< THUMB|THUMBv2 sub-type (only ARM in 32-bit mode). - -#if (ASMJIT_ARCH_X86) && defined(__AVX512VL__) - kSubIdHost = kSubIdX86_AVX512VL -#elif (ASMJIT_ARCH_X86) && defined(__AVX512F__) - kSubIdHost = kSubIdX86_AVX512 -#elif (ASMJIT_ARCH_X86) && defined(__AVX2__) - kSubIdHost = kSubIdX86_AVX2 -#elif (ASMJIT_ARCH_X86) && defined(__AVX__) - kSubIdHost = kSubIdX86_AVX -#elif (ASMJIT_ARCH_ARM == 32) && (defined(_M_ARMT) || defined(__thumb__) || defined(__thumb2__)) - kSubIdHost = kSubIdA32_Thumb -#else - kSubIdHost = 0 -#endif - }; - - //! \name Construction & Destruction - //! \{ - - inline ArchInfo() noexcept : _signature(0) {} - inline ArchInfo(const ArchInfo& other) noexcept : _signature(other._signature) {} - inline explicit ArchInfo(uint32_t type, uint32_t subType = kSubIdNone) noexcept { init(type, subType); } - inline explicit ArchInfo(Globals::NoInit_) noexcept {} - - inline static ArchInfo host() noexcept { return ArchInfo(kIdHost, kSubIdHost); } - - inline bool isInitialized() const noexcept { return _id != kIdNone; } - - ASMJIT_API void init(uint32_t type, uint32_t subType = kSubIdNone) noexcept; - inline void reset() noexcept { _signature = 0; } - - //! \} - - //! \name Overloaded Operators - //! \{ - - inline ArchInfo& operator=(const ArchInfo& other) noexcept = default; - - inline bool operator==(const ArchInfo& other) const noexcept { return _signature == other._signature; } - inline bool operator!=(const ArchInfo& other) const noexcept { return _signature != other._signature; } - - //! \} - - //! \name Accessors - //! \{ - - //! Returns the architecture id, see `Id`. - inline uint32_t archId() const noexcept { return _id; } - - //! Returns the architecture sub-id, see `SubType`. - //! - //! X86 & X64 - //! --------- - //! - //! Architecture subtype describe the highest instruction-set level that can - //! be used. - //! - //! A32 & A64 - //! --------- - //! - //! Architecture mode means the instruction encoding to be used when generating - //! machine code, thus mode can be used to force generation of THUMB and THUMBv2 - //! encoding or regular ARM encoding. - inline uint32_t archSubId() const noexcept { return _subId; } - - //! Tests whether this architecture is 32-bit. - inline bool is32Bit() const noexcept { return _gpSize == 4; } - //! Tests whether this architecture is 64-bit. - inline bool is64Bit() const noexcept { return _gpSize == 8; } - - //! Tests whether this architecture is X86, X64. - inline bool isX86Family() const noexcept { return isX86Family(_id); } - //! Tests whether this architecture is ARM32 or ARM64. - inline bool isArmFamily() const noexcept { return isArmFamily(_id); } - - //! Returns the native size of a general-purpose register. - inline uint32_t gpSize() const noexcept { return _gpSize; } - //! Returns number of general-purpose registers. - inline uint32_t gpCount() const noexcept { return _gpCount; } - - //! \} - - //! \name Static Functions - //! \{ - - static inline bool isX86Family(uint32_t archId) noexcept { return archId >= kIdX86 && archId <= kIdX64; } - static inline bool isArmFamily(uint32_t archId) noexcept { return archId >= kIdA32 && archId <= kIdA64; } - - //! \} -}; - -// ============================================================================ // [asmjit::ArchRegs] // ============================================================================ -//! Information about all architecture registers. +//! Information about registers of a CPU architecture. struct ArchRegs { //! Register information and signatures indexed by `BaseReg::RegType`. RegInfo regInfo[BaseReg::kTypeMax + 1]; @@ -193,9 +50,12 @@ struct ArchRegs { // [asmjit::ArchUtils] // ============================================================================ -struct ArchUtils { - ASMJIT_API static Error typeIdToRegInfo(uint32_t archId, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept; -}; +//! Architecture utilities. +namespace ArchUtils { + +ASMJIT_API Error typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfo) noexcept; + +} // {ArchUtils} //! \} diff --git a/3rdparty/asmjit/src/asmjit/core/assembler.cpp b/3rdparty/asmjit/src/asmjit/core/assembler.cpp index 35c39ab6089..2eea9cbae94 100644 --- a/3rdparty/asmjit/src/asmjit/core/assembler.cpp +++ b/3rdparty/asmjit/src/asmjit/core/assembler.cpp @@ -25,7 +25,9 @@ #include "../core/assembler.h" #include "../core/codebufferwriter_p.h" #include "../core/constpool.h" -#include "../core/logging.h" +#include "../core/emitterutils_p.h" +#include "../core/formatter.h" +#include "../core/logger.h" #include "../core/support.h" ASMJIT_BEGIN_NAMESPACE @@ -39,9 +41,7 @@ BaseAssembler::BaseAssembler() noexcept _section(nullptr), _bufferData(nullptr), _bufferEnd(nullptr), - _bufferPtr(nullptr), - _op4(), - _op5() {} + _bufferPtr(nullptr) {} BaseAssembler::~BaseAssembler() noexcept {} // ============================================================================ @@ -50,7 +50,7 @@ BaseAssembler::~BaseAssembler() noexcept {} Error BaseAssembler::setOffset(size_t offset) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); size_t size = Support::max<size_t>(_section->bufferSize(), this->offset()); if (ASMJIT_UNLIKELY(offset > size)) @@ -61,25 +61,6 @@ Error BaseAssembler::setOffset(size_t offset) { } // ============================================================================ -// [asmjit::BaseAssembler - Logging] -// ============================================================================ - -#ifndef ASMJIT_NO_LOGGING -static void BaseAssembler_logLabel(BaseAssembler* self, const Label& label) noexcept { - Logger* logger = self->_code->_logger; - - StringTmp<512> sb; - size_t binSize = logger->hasFlag(FormatOptions::kFlagMachineCode) ? size_t(0) : std::numeric_limits<size_t>::max(); - - sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationLabel)); - Logging::formatLabel(sb, logger->flags(), self, label.id()); - sb.appendChar(':'); - Logging::formatLine(sb, nullptr, binSize, 0, 0, self->_inlineComment); - logger->log(sb.data(), sb.size()); -} -#endif - -// ============================================================================ // [asmjit::BaseAssembler - Section Management] // ============================================================================ @@ -100,8 +81,8 @@ Error BaseAssembler::section(Section* section) { return reportError(DebugUtils::errored(kErrorInvalidSection)); #ifndef ASMJIT_NO_LOGGING - if (hasEmitterOption(kOptionLoggingEnabled)) - _code->_logger->logf(".section %s {#%u}\n", section->name(), section->id()); + if (_logger) + _logger->logf(".section %s {#%u}\n", section->name(), section->id()); #endif BaseAssembler_initSection(this, section); @@ -119,7 +100,8 @@ Label BaseAssembler::newLabel() { Error err = _code->newLabelEntry(&le); if (ASMJIT_UNLIKELY(err)) reportError(err); - labelId = le->id(); + else + labelId = le->id(); } return Label(labelId); } @@ -131,20 +113,21 @@ Label BaseAssembler::newNamedLabel(const char* name, size_t nameSize, uint32_t t Error err = _code->newNamedLabelEntry(&le, name, nameSize, type, parentId); if (ASMJIT_UNLIKELY(err)) reportError(err); - labelId = le->id(); + else + labelId = le->id(); } return Label(labelId); } Error BaseAssembler::bind(const Label& label) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); Error err = _code->bindLabel(label, _section->id(), offset()); #ifndef ASMJIT_NO_LOGGING - if (hasEmitterOption(kOptionLoggingEnabled)) - BaseAssembler_logLabel(this, label); + if (_logger) + EmitterUtils::logLabelBound(this, label); #endif resetInlineComment(); @@ -155,165 +138,112 @@ Error BaseAssembler::bind(const Label& label) { } // ============================================================================ -// [asmjit::BaseAssembler - Emit (Low-Level)] +// [asmjit::BaseAssembler - Embed] // ============================================================================ -Error BaseAssembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) { - _op4 = o4; - _op5 = o5; - _instOptions |= BaseInst::kOptionOp4Op5Used; - return _emit(instId, o0, o1, o2, o3); -} - -Error BaseAssembler::_emitOpArray(uint32_t instId, const Operand_* operands, size_t count) { - const Operand_* o0 = &operands[0]; - const Operand_* o1 = &operands[1]; - const Operand_* o2 = &operands[2]; - const Operand_* o3 = &operands[3]; - - switch (count) { - case 0: o0 = &Globals::none; ASMJIT_FALLTHROUGH; - case 1: o1 = &Globals::none; ASMJIT_FALLTHROUGH; - case 2: o2 = &Globals::none; ASMJIT_FALLTHROUGH; - case 3: o3 = &Globals::none; ASMJIT_FALLTHROUGH; - case 4: - return _emit(instId, *o0, *o1, *o2, *o3); - - case 5: - _op4 = operands[4]; - _op5.reset(); - _instOptions |= BaseInst::kOptionOp4Op5Used; - return _emit(instId, *o0, *o1, *o2, *o3); - - case 6: - _op4 = operands[4]; - _op5 = operands[5]; - _instOptions |= BaseInst::kOptionOp4Op5Used; - return _emit(instId, *o0, *o1, *o2, *o3); - - default: - return DebugUtils::errored(kErrorInvalidArgument); - } -} - #ifndef ASMJIT_NO_LOGGING -void BaseAssembler::_emitLog( - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, - uint32_t relSize, uint32_t immSize, uint8_t* afterCursor) { +struct DataSizeByPower { + char str[4]; +}; - Logger* logger = _code->logger(); - ASMJIT_ASSERT(logger != nullptr); - ASMJIT_ASSERT(options & BaseEmitter::kOptionLoggingEnabled); +static const DataSizeByPower dataSizeByPowerTable[] = { + { "db" }, + { "dw" }, + { "dd" }, + { "dq" } +}; +#endif - StringTmp<256> sb; - uint32_t flags = logger->flags(); +Error BaseAssembler::embed(const void* data, size_t dataSize) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); - uint8_t* beforeCursor = _bufferPtr; - intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor); + if (dataSize == 0) + return kErrorOk; - Operand_ operands[Globals::kMaxOpCount]; - operands[0].copyFrom(o0); - operands[1].copyFrom(o1); - operands[2].copyFrom(o2); - operands[3].copyFrom(o3); + CodeBufferWriter writer(this); + ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); - if (options & BaseInst::kOptionOp4Op5Used) { - operands[4].copyFrom(_op4); - operands[5].copyFrom(_op5); - } - else { - operands[4].reset(); - operands[5].reset(); - } + writer.emitData(data, dataSize); - sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationCode)); - Logging::formatInstruction(sb, flags, this, archId(), BaseInst(instId, options, _extraReg), operands, Globals::kMaxOpCount); +#ifndef ASMJIT_NO_LOGGING + if (_logger) + _logger->logBinary(data, dataSize); +#endif - if ((flags & FormatOptions::kFlagMachineCode) != 0) - Logging::formatLine(sb, _bufferPtr, size_t(emittedSize), relSize, immSize, inlineComment()); - else - Logging::formatLine(sb, nullptr, std::numeric_limits<size_t>::max(), 0, 0, inlineComment()); - logger->log(sb); + writer.done(this); + return kErrorOk; } -Error BaseAssembler::_emitFailed( - Error err, - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { +Error BaseAssembler::embedDataArray(uint32_t typeId, const void* data, size_t itemCcount, size_t repeatCount) { + uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize()); + uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta); - StringTmp<256> sb; - sb.appendString(DebugUtils::errorAsString(err)); - sb.appendString(": "); + if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId))) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); - Operand_ operands[Globals::kMaxOpCount]; - operands[0].copyFrom(o0); - operands[1].copyFrom(o1); - operands[2].copyFrom(o2); - operands[3].copyFrom(o3); + if (itemCcount == 0 || repeatCount == 0) + return kErrorOk; - if (options & BaseInst::kOptionOp4Op5Used) { - operands[4].copyFrom(_op4); - operands[5].copyFrom(_op5); - } - else { - operands[4].reset(); - operands[5].reset(); - } + uint32_t typeSize = Type::sizeOf(finalTypeId); + Support::FastUInt8 of = 0; - Logging::formatInstruction(sb, 0, this, archId(), BaseInst(instId, options, _extraReg), operands, Globals::kMaxOpCount); + size_t dataSize = Support::mulOverflow(itemCcount, size_t(typeSize), &of); + size_t totalSize = Support::mulOverflow(dataSize, repeatCount, &of); - if (inlineComment()) { - sb.appendString(" ; "); - sb.appendString(inlineComment()); - } + if (ASMJIT_UNLIKELY(of)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); - resetInstOptions(); - resetExtraReg(); - resetInlineComment(); - return reportError(err, sb.data()); -} + CodeBufferWriter writer(this); + ASMJIT_PROPAGATE(writer.ensureSpace(this, totalSize)); + +#ifndef ASMJIT_NO_LOGGING + const uint8_t* start = writer.cursor(); #endif -// ============================================================================ -// [asmjit::BaseAssembler - Embed] -// ============================================================================ + for (size_t i = 0; i < repeatCount; i++) { + writer.emitData(data, dataSize); + } #ifndef ASMJIT_NO_LOGGING -struct DataSizeByPower { - char str[4]; -}; - -static const DataSizeByPower dataSizeByPowerTable[] = { - { "db" }, - { "dw" }, - { "dd" }, - { "dq" } -}; + if (_logger) + _logger->logBinary(start, totalSize); #endif -Error BaseAssembler::embed(const void* data, uint32_t dataSize) { + writer.done(this); + return kErrorOk; +} + +Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); - if (dataSize == 0) - return DebugUtils::errored(kErrorInvalidArgument); + if (ASMJIT_UNLIKELY(!isLabelValid(label))) + return reportError(DebugUtils::errored(kErrorInvalidLabel)); + ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment()))); + ASMJIT_PROPAGATE(bind(label)); + + size_t size = pool.size(); CodeBufferWriter writer(this); - ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); + ASMJIT_PROPAGATE(writer.ensureSpace(this, size)); - writer.emitData(data, dataSize); + pool.fill(writer.cursor()); #ifndef ASMJIT_NO_LOGGING - if (ASMJIT_UNLIKELY(hasEmitterOption(kOptionLoggingEnabled))) - _code->_logger->logBinary(data, dataSize); + if (_logger) + _logger->logBinary(writer.cursor(), size); #endif + writer.advance(size); writer.done(this); + return kErrorOk; } Error BaseAssembler::embedLabel(const Label& label) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); ASMJIT_ASSERT(_code != nullptr); RelocEntry* re; @@ -322,30 +252,22 @@ Error BaseAssembler::embedLabel(const Label& label) { if (ASMJIT_UNLIKELY(!le)) return reportError(DebugUtils::errored(kErrorInvalidLabel)); - uint32_t dataSize = gpSize(); + uint32_t dataSize = registerSize(); ASMJIT_ASSERT(dataSize <= 8); CodeBufferWriter writer(this); ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); #ifndef ASMJIT_NO_LOGGING - if (ASMJIT_UNLIKELY(hasEmitterOption(kOptionLoggingEnabled))) { + if (_logger) { StringTmp<256> sb; - sb.appendFormat(".%s ", dataSizeByPowerTable[Support::ctz(dataSize)].str); - Logging::formatLabel(sb, 0, this, label.id()); - sb.appendChar('\n'); - _code->_logger->log(sb); + sb.appendFormat("%s ", dataSizeByPowerTable[Support::ctz(dataSize)].str); + Formatter::formatLabel(sb, 0, this, label.id()); + sb.append('\n'); + _logger->log(sb); } #endif - // TODO: Does it make sense to calculate the address here if everything is known? - /* - if (_code->hasBaseAddress() && currentSection() == _code->textSection() && le->isBound()) { - uint64_t addr = _code->baseAddress() + _code->textSection()->offset() + le->offset(); - writer.emitValueLE(addr, dataSize); - } - */ - Error err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, dataSize); if (ASMJIT_UNLIKELY(err)) return reportError(err); @@ -371,9 +293,9 @@ Error BaseAssembler::embedLabel(const Label& label) { return kErrorOk; } -Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) { +Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); LabelEntry* labelEntry = _code->labelEntry(label); LabelEntry* baseEntry = _code->labelEntry(base); @@ -382,7 +304,7 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, uint return reportError(DebugUtils::errored(kErrorInvalidLabel)); if (dataSize == 0) - dataSize = gpSize(); + dataSize = registerSize(); if (ASMJIT_UNLIKELY(!Support::isPowerOf2(dataSize) || dataSize > 8)) return reportError(DebugUtils::errored(kErrorInvalidOperandSize)); @@ -391,14 +313,14 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, uint ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); #ifndef ASMJIT_NO_LOGGING - if (ASMJIT_UNLIKELY(hasEmitterOption(kOptionLoggingEnabled))) { + if (_logger) { StringTmp<256> sb; sb.appendFormat(".%s (", dataSizeByPowerTable[Support::ctz(dataSize)].str); - Logging::formatLabel(sb, 0, this, label.id()); - sb.appendString(" - "); - Logging::formatLabel(sb, 0, this, base.id()); - sb.appendString(")\n"); - _code->_logger->log(sb); + Formatter::formatLabel(sb, 0, this, label.id()); + sb.append(" - "); + Formatter::formatLabel(sb, 0, this, base.id()); + sb.append(")\n"); + _logger->log(sb); } #endif @@ -409,7 +331,7 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, uint } else { RelocEntry* re; - Error err = _code->newRelocEntry(&re, RelocEntry::kTypeExpression, dataSize); + Error err = _code->newRelocEntry(&re, RelocEntry::kTypeExpression, uint32_t(dataSize)); if (ASMJIT_UNLIKELY(err)) return reportError(err); @@ -433,46 +355,18 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, uint return kErrorOk; } -Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) { - if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); - - if (ASMJIT_UNLIKELY(!isLabelValid(label))) - return DebugUtils::errored(kErrorInvalidLabel); - - ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment()))); - ASMJIT_PROPAGATE(bind(label)); - - size_t size = pool.size(); - CodeBufferWriter writer(this); - ASMJIT_PROPAGATE(writer.ensureSpace(this, size)); - - pool.fill(writer.cursor()); - -#ifndef ASMJIT_NO_LOGGING - if (ASMJIT_UNLIKELY(hasEmitterOption(kOptionLoggingEnabled))) - _code->_logger->logBinary(writer.cursor(), size); -#endif - - writer.advance(size); - writer.done(this); - - return kErrorOk; -} - // ============================================================================ // [asmjit::BaseAssembler - Comment] // ============================================================================ Error BaseAssembler::comment(const char* data, size_t size) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); #ifndef ASMJIT_NO_LOGGING - if (hasEmitterOption(kOptionLoggingEnabled)) { - Logger* logger = _code->logger(); - logger->log(data, size); - logger->log("\n", 1); + if (_logger) { + _logger->log(data, size); + _logger->log("\n", 1); return kErrorOk; } #else @@ -492,10 +386,6 @@ Error BaseAssembler::onAttach(CodeHolder* code) noexcept { // Attach to the end of the .text section. BaseAssembler_initSection(this, code->_sections[0]); - // And reset everything that is used temporarily. - _op4.reset(); - _op5.reset(); - return kErrorOk; } @@ -504,10 +394,6 @@ Error BaseAssembler::onDetach(CodeHolder* code) noexcept { _bufferData = nullptr; _bufferEnd = nullptr; _bufferPtr = nullptr; - - _op4.reset(); - _op5.reset(); - return Base::onDetach(code); } diff --git a/3rdparty/asmjit/src/asmjit/core/assembler.h b/3rdparty/asmjit/src/asmjit/core/assembler.h index fd2c1c33c28..966dabb06e0 100644 --- a/3rdparty/asmjit/src/asmjit/core/assembler.h +++ b/3rdparty/asmjit/src/asmjit/core/assembler.h @@ -31,14 +31,23 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_core +//! \addtogroup asmjit_assembler //! \{ // ============================================================================ // [asmjit::BaseAssembler] // ============================================================================ -//! Base encoder (assembler). +//! Base assembler. +//! +//! This is a base class that provides interface used by architecture specific +//! assembler implementations. Assembler doesn't hold any data, instead it's +//! attached to \ref CodeHolder, which provides all the data that Assembler +//! needs and which can be altered by it. +//! +//! Check out architecture specific assemblers for more details and examples: +//! +//! - \ref x86::Assembler - X86/X64 assembler implementation. class ASMJIT_VIRTAPI BaseAssembler : public BaseEmitter { public: ASMJIT_NONCOPYABLE(BaseAssembler) @@ -52,10 +61,6 @@ public: uint8_t* _bufferEnd; //! Pointer in the CodeBuffer of the current section. uint8_t* _bufferPtr; - //! 5th operand data, used only temporarily. - Operand_ _op4; - //! 6th operand data, used only temporarily. - Operand_ _op5; //! \name Construction & Destruction //! \{ @@ -77,10 +82,11 @@ public: //! Returns the current position in the CodeBuffer. inline size_t offset() const noexcept { return (size_t)(_bufferPtr - _bufferData); } + //! Sets the current position in the CodeBuffer to `offset`. //! - //! \note The `offset` cannot be outside of the buffer size (even if it's - //! within buffer's capacity). + //! \note The `offset` cannot be greater than buffer size even if it's + //! within the buffer's capacity. ASMJIT_API Error setOffset(size_t offset); //! Returns the start of the CodeBuffer in the current section. @@ -95,6 +101,7 @@ public: //! \name Section Management //! \{ + //! Returns the current section. inline Section* currentSection() const noexcept { return _section; } ASMJIT_API Error section(Section* section) override; @@ -110,47 +117,16 @@ public: //! \} - //! \cond INTERNAL - //! \name Emit - //! \{ - - using BaseEmitter::_emit; - - ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override; - ASMJIT_API Error _emitOpArray(uint32_t instId, const Operand_* operands, size_t count) override; - -protected: -#ifndef ASMJIT_NO_LOGGING - void _emitLog( - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, - uint32_t relSize, uint32_t immSize, uint8_t* afterCursor); - - Error _emitFailed( - Error err, - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3); -#else - inline Error _emitFailed( - uint32_t err, - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { - - DebugUtils::unused(instId, options, o0, o1, o2, o3); - resetInstOptions(); - resetInlineComment(); - return reportError(err); - } -#endif -public: - //! \} - //! \endcond - //! \name Embed //! \{ - ASMJIT_API Error embed(const void* data, uint32_t dataSize) override; - ASMJIT_API Error embedLabel(const Label& label) override; - ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) override; + ASMJIT_API Error embed(const void* data, size_t dataSize) override; + ASMJIT_API Error embedDataArray(uint32_t typeId, const void* data, size_t itemCcount, size_t repeatCount = 1) override; ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override; + ASMJIT_API Error embedLabel(const Label& label) override; + ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize) override; + //! \} //! \name Comment diff --git a/3rdparty/asmjit/src/asmjit/core/builder.cpp b/3rdparty/asmjit/src/asmjit/core/builder.cpp index 35d7127481c..97780c767a4 100644 --- a/3rdparty/asmjit/src/asmjit/core/builder.cpp +++ b/3rdparty/asmjit/src/asmjit/core/builder.cpp @@ -25,7 +25,10 @@ #ifndef ASMJIT_NO_BUILDER #include "../core/builder.h" -#include "../core/logging.h" +#include "../core/emitterutils_p.h" +#include "../core/errorhandler.h" +#include "../core/formatter.h" +#include "../core/logger.h" #include "../core/support.h" ASMJIT_BEGIN_NAMESPACE @@ -41,13 +44,23 @@ class PostponedErrorHandler : public ErrorHandler { public: void handleError(Error err, const char* message, BaseEmitter* origin) override { DebugUtils::unused(err, origin); - _message.assignString(message); + _message.assign(message); } StringTmp<128> _message; }; // ============================================================================ +// [asmjit::BaseBuilder - Utilities] +// ============================================================================ + +static void BaseBuilder_deletePasses(BaseBuilder* self) noexcept { + for (Pass* pass : self->_passes) + pass->~Pass(); + self->_passes.reset(); +} + +// ============================================================================ // [asmjit::BaseBuilder - Construction / Destruction] // ============================================================================ @@ -63,132 +76,101 @@ BaseBuilder::BaseBuilder() noexcept _firstNode(nullptr), _lastNode(nullptr), _nodeFlags(0) {} -BaseBuilder::~BaseBuilder() noexcept {} + +BaseBuilder::~BaseBuilder() noexcept { + BaseBuilder_deletePasses(this); +} // ============================================================================ // [asmjit::BaseBuilder - Node Management] // ============================================================================ -LabelNode* BaseBuilder::newLabelNode() noexcept { - LabelNode* node = newNodeT<LabelNode>(); - if (!node || registerLabelNode(node) != kErrorOk) - return nullptr; - return node; -} +Error BaseBuilder::_newInstNode(InstNode** out, uint32_t instId, uint32_t instOptions, uint32_t opCount) { + uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); + ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity); -AlignNode* BaseBuilder::newAlignNode(uint32_t alignMode, uint32_t alignment) noexcept { - return newNodeT<AlignNode>(alignMode, alignment); + InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); + if (ASMJIT_UNLIKELY(!node)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + + *out = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); + return kErrorOk; } -EmbedDataNode* BaseBuilder::newEmbedDataNode(const void* data, uint32_t size) noexcept { - if (size > EmbedDataNode::kInlineBufferSize) { - void* cloned = _dataZone.alloc(size); - if (ASMJIT_UNLIKELY(!cloned)) - return nullptr; - if (data) - memcpy(cloned, data, size); - data = cloned; - } +Error BaseBuilder::_newLabelNode(LabelNode** out) { + *out = nullptr; - return newNodeT<EmbedDataNode>(const_cast<void*>(data), size); + ASMJIT_PROPAGATE(_newNodeT<LabelNode>(out)); + return registerLabelNode(*out); } -ConstPoolNode* BaseBuilder::newConstPoolNode() noexcept { - ConstPoolNode* node = newNodeT<ConstPoolNode>(); - if (!node || registerLabelNode(node) != kErrorOk) - return nullptr; - return node; +Error BaseBuilder::_newAlignNode(AlignNode** out, uint32_t alignMode, uint32_t alignment) { + *out = nullptr; + return _newNodeT<AlignNode>(out, alignMode, alignment); } -CommentNode* BaseBuilder::newCommentNode(const char* data, size_t size) noexcept { - if (data) { - if (size == SIZE_MAX) - size = strlen(data); +Error BaseBuilder::_newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount) { + *out = nullptr; - if (size > 0) { - data = static_cast<char*>(_dataZone.dup(data, size, true)); - if (!data) return nullptr; - } - } + uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize()); + uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta); - return newNodeT<CommentNode>(data); -} + if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId))) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); -InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0) noexcept { - uint32_t opCount = 1; - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); + uint32_t typeSize = Type::sizeOf(finalTypeId); + Support::FastUInt8 of = 0; - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - if (ASMJIT_UNLIKELY(!node)) - return nullptr; + size_t dataSize = Support::mulOverflow(itemCount, size_t(typeSize), &of); + if (ASMJIT_UNLIKELY(of)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); - node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); - node->setOp(0, o0); - node->resetOps(opCount, opCapacity); - return node; -} + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newNodeT<EmbedDataNode>(&node)); -InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1) noexcept { - uint32_t opCount = 2; - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); + node->_embed._typeId = uint8_t(typeId); + node->_embed._typeSize = uint8_t(typeSize); + node->_itemCount = itemCount; + node->_repeatCount = repeatCount; - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - if (ASMJIT_UNLIKELY(!node)) - return nullptr; + uint8_t* dstData = node->_inlineData; + if (dataSize > EmbedDataNode::kInlineBufferSize) { + dstData = static_cast<uint8_t*>(_dataZone.alloc(dataSize, 8)); + if (ASMJIT_UNLIKELY(!dstData)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + node->_externalData = dstData; + } - node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); - node->setOp(0, o0); - node->setOp(1, o1); - node->resetOps(opCount, opCapacity); - return node; -} + if (data) + memcpy(dstData, data, dataSize); -InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1, const Operand_& o2) noexcept { - uint32_t opCount = 3; - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); + *out = node; + return kErrorOk; +} - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - if (ASMJIT_UNLIKELY(!node)) - return nullptr; +Error BaseBuilder::_newConstPoolNode(ConstPoolNode** out) { + *out = nullptr; - node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); - node->setOp(0, o0); - node->setOp(1, o1); - node->setOp(2, o2); - node->resetOps(opCount, opCapacity); - return node; + ASMJIT_PROPAGATE(_newNodeT<ConstPoolNode>(out)); + return registerLabelNode(*out); } -InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) noexcept { - uint32_t opCount = 4; - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); - - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - if (ASMJIT_UNLIKELY(!node)) - return nullptr; +Error BaseBuilder::_newCommentNode(CommentNode** out, const char* data, size_t size) { + *out = nullptr; - node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); - node->setOp(0, o0); - node->setOp(1, o1); - node->setOp(2, o2); - node->setOp(3, o3); - node->resetOps(opCount, opCapacity); - return node; -} + if (data) { + if (size == SIZE_MAX) + size = strlen(data); -InstNode* BaseBuilder::newInstNodeRaw(uint32_t instId, uint32_t instOptions, uint32_t opCount) noexcept { - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); + if (size > 0) { + data = static_cast<char*>(_dataZone.dup(data, size, true)); + if (ASMJIT_UNLIKELY(!data)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + } + } - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - if (ASMJIT_UNLIKELY(!node)) - return nullptr; - return new(node) InstNode(this, instId, instOptions, opCount, opCapacity); + return _newNodeT<CommentNode>(out, data); } BaseNode* BaseBuilder::addNode(BaseNode* node) noexcept { @@ -368,34 +350,42 @@ BaseNode* BaseBuilder::setCursor(BaseNode* node) noexcept { // [asmjit::BaseBuilder - Section] // ============================================================================ -Error BaseBuilder::sectionNodeOf(SectionNode** pOut, uint32_t sectionId) noexcept { +Error BaseBuilder::sectionNodeOf(SectionNode** out, uint32_t sectionId) { + *out = nullptr; + if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); if (ASMJIT_UNLIKELY(!_code->isSectionValid(sectionId))) - return DebugUtils::errored(kErrorInvalidSection); + return reportError(DebugUtils::errored(kErrorInvalidSection)); - if (sectionId >= _sectionNodes.size()) - ASMJIT_PROPAGATE(_sectionNodes.resize(&_allocator, sectionId + 1)); + if (sectionId >= _sectionNodes.size()) { + Error err = _sectionNodes.reserve(&_allocator, sectionId + 1); + if (ASMJIT_UNLIKELY(err != kErrorOk)) + return reportError(err); + } + + SectionNode* node = nullptr; + if (sectionId < _sectionNodes.size()) + node = _sectionNodes[sectionId]; - SectionNode* node = _sectionNodes[sectionId]; if (!node) { - node = newNodeT<SectionNode>(sectionId); - if (ASMJIT_UNLIKELY(!node)) - return DebugUtils::errored(kErrorOutOfMemory); + ASMJIT_PROPAGATE(_newNodeT<SectionNode>(&node, sectionId)); + + // We have already reserved enough space, this cannot fail now. + if (sectionId >= _sectionNodes.size()) + _sectionNodes.resize(&_allocator, sectionId + 1); + _sectionNodes[sectionId] = node; } - *pOut = node; + *out = node; return kErrorOk; } Error BaseBuilder::section(Section* section) { SectionNode* node; - Error err = sectionNodeOf(&node, section->id()); - - if (ASMJIT_UNLIKELY(err)) - return reportError(err); + ASMJIT_PROPAGATE(sectionNodeOf(&node, section->id())); if (!node->isActive()) { // Insert the section at the end if it was not part of the code. @@ -444,7 +434,9 @@ void BaseBuilder::updateSectionLinks() noexcept { // [asmjit::BaseBuilder - Labels] // ============================================================================ -Error BaseBuilder::labelNodeOf(LabelNode** pOut, uint32_t labelId) noexcept { +Error BaseBuilder::labelNodeOf(LabelNode** out, uint32_t labelId) { + *out = nullptr; + if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); @@ -457,22 +449,18 @@ Error BaseBuilder::labelNodeOf(LabelNode** pOut, uint32_t labelId) noexcept { LabelNode* node = _labelNodes[index]; if (!node) { - node = newNodeT<LabelNode>(labelId); - if (ASMJIT_UNLIKELY(!node)) - return DebugUtils::errored(kErrorOutOfMemory); + ASMJIT_PROPAGATE(_newNodeT<LabelNode>(&node, labelId)); _labelNodes[index] = node; } - *pOut = node; + *out = node; return kErrorOk; } -Error BaseBuilder::registerLabelNode(LabelNode* node) noexcept { +Error BaseBuilder::registerLabelNode(LabelNode* node) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - // Don't call `reportError()` from here, we are noexcept and we are called - // by `newLabelNode()` and `newFuncNode()`, which are noexcept as well. LabelEntry* le; ASMJIT_PROPAGATE(_code->newLabelEntry(&le)); uint32_t labelId = le->id(); @@ -482,68 +470,58 @@ Error BaseBuilder::registerLabelNode(LabelNode* node) noexcept { ASMJIT_PROPAGATE(_labelNodes.resize(&_allocator, labelId + 1)); _labelNodes[labelId] = node; - node->_id = labelId; + node->_labelId = labelId; return kErrorOk; } -static Error BaseBuilder_newLabelInternal(BaseBuilder* self, uint32_t labelId) noexcept { +static Error BaseBuilder_newLabelInternal(BaseBuilder* self, uint32_t labelId) { ASMJIT_ASSERT(self->_labelNodes.size() < labelId + 1); - LabelNode* node = self->newNodeT<LabelNode>(labelId); - if (ASMJIT_UNLIKELY(!node)) - return DebugUtils::errored(kErrorOutOfMemory); + uint32_t growBy = labelId - self->_labelNodes.size(); + Error err = self->_labelNodes.willGrow(&self->_allocator, growBy); + + if (ASMJIT_UNLIKELY(err)) + return self->reportError(err); + + LabelNode* node; + ASMJIT_PROPAGATE(self->_newNodeT<LabelNode>(&node, labelId)); - ASMJIT_PROPAGATE(self->_labelNodes.resize(&self->_allocator, labelId + 1)); + self->_labelNodes.resize(&self->_allocator, labelId + 1); self->_labelNodes[labelId] = node; - node->_id = labelId; + node->_labelId = labelId; return kErrorOk; } Label BaseBuilder::newLabel() { uint32_t labelId = Globals::kInvalidId; - if (_code) { - LabelEntry* le; - Error err = _code->newLabelEntry(&le); - if (ASMJIT_UNLIKELY(err)) { - reportError(err); - } - else { - err = BaseBuilder_newLabelInternal(this, le->id()); - if (ASMJIT_UNLIKELY(err)) - reportError(err); - else - labelId = le->id(); - } + LabelEntry* le; + + if (_code && + _code->newLabelEntry(&le) == kErrorOk && + BaseBuilder_newLabelInternal(this, le->id()) == kErrorOk) { + labelId = le->id(); } + return Label(labelId); } Label BaseBuilder::newNamedLabel(const char* name, size_t nameSize, uint32_t type, uint32_t parentId) { uint32_t labelId = Globals::kInvalidId; - if (_code) { - LabelEntry* le; - Error err = _code->newNamedLabelEntry(&le, name, nameSize, type, parentId); - if (ASMJIT_UNLIKELY(err)) { - reportError(err); - } - else { - err = BaseBuilder_newLabelInternal(this, le->id()); - if (ASMJIT_UNLIKELY(err)) - reportError(err); - else - labelId = le->id(); - } + LabelEntry* le; + + if (_code && + _code->newNamedLabelEntry(&le, name, nameSize, type, parentId) == kErrorOk && + BaseBuilder_newLabelInternal(this, le->id()) == kErrorOk) { + labelId = le->id(); } + return Label(labelId); } Error BaseBuilder::bind(const Label& label) { LabelNode* node; - Error err = labelNodeOf(&node, label); - - if (ASMJIT_UNLIKELY(err)) - return reportError(err); + ASMJIT_PROPAGATE(labelNodeOf(&node, label)); addNode(node); return kErrorOk; @@ -610,7 +588,6 @@ Error BaseBuilder::runPasses() { if (_passes.empty()) return kErrorOk; - Logger* logger = code()->logger(); ErrorHandler* prev = errorHandler(); PostponedErrorHandler postponed; @@ -619,8 +596,9 @@ Error BaseBuilder::runPasses() { for (Pass* pass : _passes) { _passZone.reset(); - err = pass->run(&_passZone, logger); - if (err) break; + err = pass->run(&_passZone, _logger); + if (err) + break; } _passZone.reset(); setErrorHandler(prev); @@ -635,104 +613,21 @@ Error BaseBuilder::runPasses() { // [asmjit::BaseBuilder - Emit] // ============================================================================ -Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { - uint32_t opCount = 4; - - if (o3.isNone()) { - opCount = 3; - if (o2.isNone()) { - opCount = 2; - if (o1.isNone()) { - opCount = 1; - if (o0.isNone()) - opCount = 0; - } - } - } +Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) { + uint32_t opCount = EmitterUtils::opCountFromEmitArgs(o0, o1, o2, opExt); + uint32_t options = instOptions() | forcedInstOptions(); - uint32_t options = instOptions() | globalInstOptions(); if (options & BaseInst::kOptionReserved) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); #ifndef ASMJIT_NO_VALIDATION // Strict validation. - if (hasEmitterOption(kOptionStrictValidation)) { - Operand_ opArray[4]; - opArray[0].copyFrom(o0); - opArray[1].copyFrom(o1); - opArray[2].copyFrom(o2); - opArray[3].copyFrom(o3); - - Error err = InstAPI::validate(archId(), BaseInst(instId, options, _extraReg), opArray, opCount); - if (ASMJIT_UNLIKELY(err)) { - resetInstOptions(); - resetExtraReg(); - resetInlineComment(); - return reportError(err); - } - } -#endif - - // Clear options that should never be part of `InstNode`. - options &= ~BaseInst::kOptionReserved; - } - - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); - - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - const char* comment = inlineComment(); - - resetInstOptions(); - resetInlineComment(); - - if (ASMJIT_UNLIKELY(!node)) { - resetExtraReg(); - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - } - - node = new(node) InstNode(this, instId, options, opCount, opCapacity); - node->setExtraReg(extraReg()); - node->setOp(0, o0); - node->setOp(1, o1); - node->setOp(2, o2); - node->setOp(3, o3); - node->resetOps(4, opCapacity); - - if (comment) - node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true))); - - addNode(node); - resetExtraReg(); - return kErrorOk; -} - -Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) { - uint32_t opCount = Globals::kMaxOpCount; - if (o5.isNone()) { - opCount = 5; - if (o4.isNone()) - return _emit(instId, o0, o1, o2, o3); - } - - uint32_t options = instOptions() | globalInstOptions(); - if (ASMJIT_UNLIKELY(options & BaseInst::kOptionReserved)) { - if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); - -#ifndef ASMJIT_NO_VALIDATION - // Strict validation. - if (hasEmitterOption(kOptionStrictValidation)) { + if (hasValidationOption(kValidationOptionIntermediate)) { Operand_ opArray[Globals::kMaxOpCount]; - opArray[0].copyFrom(o0); - opArray[1].copyFrom(o1); - opArray[2].copyFrom(o2); - opArray[3].copyFrom(o3); - opArray[4].copyFrom(o4); - opArray[5].copyFrom(o5); - - Error err = InstAPI::validate(archId(), BaseInst(instId, options, _extraReg), opArray, opCount); + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); + + Error err = InstAPI::validate(arch(), BaseInst(instId, options, _extraReg), opArray, opCount); if (ASMJIT_UNLIKELY(err)) { resetInstOptions(); resetExtraReg(); @@ -747,7 +642,7 @@ Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1 } uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= opCount); + ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity); InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); const char* comment = inlineComment(); @@ -765,11 +660,9 @@ Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1 node->setOp(0, o0); node->setOp(1, o1); node->setOp(2, o2); - node->setOp(3, o3); - node->setOp(4, o4); - - if (opCapacity > 5) - node->setOp(5, o5); + for (uint32_t i = 3; i < opCount; i++) + node->setOp(i, opExt[i - 3]); + node->resetOpRange(opCount, opCapacity); if (comment) node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true))); @@ -787,9 +680,8 @@ Error BaseBuilder::align(uint32_t alignMode, uint32_t alignment) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - AlignNode* node = newAlignNode(alignMode, alignment); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + AlignNode* node; + ASMJIT_PROPAGATE(_newAlignNode(&node, alignMode, alignment)); addNode(node); return kErrorOk; @@ -799,57 +691,71 @@ Error BaseBuilder::align(uint32_t alignMode, uint32_t alignment) { // [asmjit::BaseBuilder - Embed] // ============================================================================ -Error BaseBuilder::embed(const void* data, uint32_t dataSize) { +Error BaseBuilder::embed(const void* data, size_t dataSize) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - EmbedDataNode* node = newEmbedDataNode(data, dataSize); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newEmbedDataNode(&node, Type::kIdU8, data, dataSize)); addNode(node); return kErrorOk; } -Error BaseBuilder::embedLabel(const Label& label) { +Error BaseBuilder::embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t itemRepeat) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - EmbedLabelNode* node = newNodeT<EmbedLabelNode>(label.id()); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newEmbedDataNode(&node, typeId, data, itemCount, itemRepeat)); addNode(node); return kErrorOk; } -Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) { +Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - EmbedLabelDeltaNode* node = newNodeT<EmbedLabelDeltaNode>(label.id(), base.id(), dataSize); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + if (!isLabelValid(label)) + return reportError(DebugUtils::errored(kErrorInvalidLabel)); + ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment()))); + ASMJIT_PROPAGATE(bind(label)); + + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newEmbedDataNode(&node, Type::kIdU8, nullptr, pool.size())); + + pool.fill(node->data()); addNode(node); return kErrorOk; } -Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) { +Error BaseBuilder::embedLabel(const Label& label) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - if (!isLabelValid(label)) - return reportError(DebugUtils::errored(kErrorInvalidLabel)); - ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment()))); - ASMJIT_PROPAGATE(bind(label)); + EmbedLabelNode* node; + ASMJIT_PROPAGATE(_newNodeT<EmbedLabelNode>(&node, label.id())); - EmbedDataNode* node = newEmbedDataNode(nullptr, uint32_t(pool.size())); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + addNode(node); + return kErrorOk; +} + +Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + // If dataSize is zero it means that the size is the same as target register + // width, however, if it's provided we really want to validate whether it's + // within the possible range. + if (dataSize && (!Support::isPowerOf2(dataSize) || dataSize > 8)) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + EmbedLabelDeltaNode* node; + ASMJIT_PROPAGATE(_newNodeT<EmbedLabelDeltaNode>(&node, label.id(), base.id(), uint32_t(dataSize))); - pool.fill(node->data()); addNode(node); return kErrorOk; } @@ -862,9 +768,8 @@ Error BaseBuilder::comment(const char* data, size_t size) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - CommentNode* node = newCommentNode(data, size); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + CommentNode* node; + ASMJIT_PROPAGATE(_newCommentNode(&node, data, size)); addNode(node); return kErrorOk; @@ -878,12 +783,38 @@ Error BaseBuilder::serialize(BaseEmitter* dst) { Error err = kErrorOk; BaseNode* node_ = _firstNode; + Operand_ opArray[Globals::kMaxOpCount]; + do { dst->setInlineComment(node_->inlineComment()); if (node_->isInst()) { InstNode* node = node_->as<InstNode>(); - err = dst->emitInst(node->baseInst(), node->operands(), node->opCount()); + + // NOTE: Inlined to remove one additional call per instruction. + dst->setInstOptions(node->instOptions()); + dst->setExtraReg(node->extraReg()); + + const Operand_* op = node->operands(); + const Operand_* opExt = EmitterUtils::noExt; + + uint32_t opCount = node->opCount(); + if (opCount > 3) { + uint32_t i = 4; + opArray[3] = op[3]; + + while (i < opCount) { + opArray[i].copyFrom(op[i]); + i++; + } + while (i < Globals::kMaxOpCount) { + opArray[i].reset(); + i++; + } + opExt = opArray + 3; + } + + err = dst->_emit(node->id(), op[0], op[1], op[2], opExt); } else if (node_->isLabel()) { if (node_->isConstPool()) { @@ -901,7 +832,7 @@ Error BaseBuilder::serialize(BaseEmitter* dst) { } else if (node_->isEmbedData()) { EmbedDataNode* node = node_->as<EmbedDataNode>(); - err = dst->embed(node->data(), node->size()); + err = dst->embedDataArray(node->typeId(), node->data(), node->itemCount(), node->repeatCount()); } else if (node_->isEmbedLabel()) { EmbedLabelNode* node = node_->as<EmbedLabelNode>(); @@ -928,23 +859,6 @@ Error BaseBuilder::serialize(BaseEmitter* dst) { } // ============================================================================ -// [asmjit::BaseBuilder - Logging] -// ============================================================================ - -#ifndef ASMJIT_NO_LOGGING -Error BaseBuilder::dump(String& sb, uint32_t flags) const noexcept { - BaseNode* node = _firstNode; - while (node) { - ASMJIT_PROPAGATE(Logging::formatNode(sb, flags, this, node)); - sb.appendChar('\n'); - node = node->next(); - } - - return kErrorOk; -} -#endif - -// ============================================================================ // [asmjit::BaseBuilder - Events] // ============================================================================ @@ -962,7 +876,6 @@ Error BaseBuilder::onAttach(CodeHolder* code) noexcept { return err; } - _cursor = initialSection; _firstNode = initialSection; _lastNode = initialSection; @@ -972,7 +885,7 @@ Error BaseBuilder::onAttach(CodeHolder* code) noexcept { } Error BaseBuilder::onDetach(CodeHolder* code) noexcept { - _passes.reset(); + BaseBuilder_deletePasses(this); _sectionNodes.reset(); _labelNodes.reset(); diff --git a/3rdparty/asmjit/src/asmjit/core/builder.h b/3rdparty/asmjit/src/asmjit/core/builder.h index c6d359995fc..ba99267dafa 100644 --- a/3rdparty/asmjit/src/asmjit/core/builder.h +++ b/3rdparty/asmjit/src/asmjit/core/builder.h @@ -30,10 +30,12 @@ #include "../core/assembler.h" #include "../core/codeholder.h" #include "../core/constpool.h" +#include "../core/formatter.h" #include "../core/inst.h" #include "../core/operand.h" #include "../core/string.h" #include "../core/support.h" +#include "../core/type.h" #include "../core/zone.h" #include "../core/zonevector.h" @@ -68,6 +70,18 @@ class JumpAnnotation; // [asmjit::BaseBuilder] // ============================================================================ +//! Builder interface. +//! +//! `BaseBuilder` interface was designed to be used as a \ref BaseAssembler +//! replacement in case pre-processing or post-processing of the generated code +//! is required. The code can be modified during or after code generation. Pre +//! or post processing can be done manually or through a \ref Pass object. \ref +//! BaseBuilder stores the emitted code as a double-linked list of nodes, which +//! allows O(1) insertion and removal during processing. +//! +//! Check out architecture specific builders for more details and examples: +//! +//! - \ref x86::Builder - X86/X64 builder implementation. class ASMJIT_VIRTAPI BaseBuilder : public BaseEmitter { public: ASMJIT_NONCOPYABLE(BaseBuilder) @@ -127,33 +141,26 @@ public: //! \remarks The pointer returned (if non-null) is owned by the Builder or //! Compiler. When the Builder/Compiler is destroyed it destroys all nodes //! it created so no manual memory management is required. - template<typename T> - inline T* newNodeT() noexcept { - return _allocator.newT<T>(this); - } - - //! \overload template<typename T, typename... Args> - inline T* newNodeT(Args&&... args) noexcept { - return _allocator.newT<T>(this, std::forward<Args>(args)...); + inline Error _newNodeT(T** out, Args&&... args) { + *out = _allocator.newT<T>(this, std::forward<Args>(args)...); + if (ASMJIT_UNLIKELY(!*out)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + return kErrorOk; } - //! Creates a new `LabelNode`. - ASMJIT_API LabelNode* newLabelNode() noexcept; - //! Creates a new `AlignNode`. - ASMJIT_API AlignNode* newAlignNode(uint32_t alignMode, uint32_t alignment) noexcept; - //! Creates a new `EmbedDataNode`. - ASMJIT_API EmbedDataNode* newEmbedDataNode(const void* data, uint32_t size) noexcept; - //! Creates a new `ConstPoolNode`. - ASMJIT_API ConstPoolNode* newConstPoolNode() noexcept; - //! Creates a new `CommentNode`. - ASMJIT_API CommentNode* newCommentNode(const char* data, size_t size) noexcept; - - ASMJIT_API InstNode* newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0) noexcept; - ASMJIT_API InstNode* newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1) noexcept; - ASMJIT_API InstNode* newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1, const Operand_& o2) noexcept; - ASMJIT_API InstNode* newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) noexcept; - ASMJIT_API InstNode* newInstNodeRaw(uint32_t instId, uint32_t instOptions, uint32_t opCount) noexcept; + //! Creates a new \ref InstNode. + ASMJIT_API Error _newInstNode(InstNode** out, uint32_t instId, uint32_t instOptions, uint32_t opCount); + //! Creates a new \ref LabelNode. + ASMJIT_API Error _newLabelNode(LabelNode** out); + //! Creates a new \ref AlignNode. + ASMJIT_API Error _newAlignNode(AlignNode** out, uint32_t alignMode, uint32_t alignment); + //! Creates a new \ref EmbedDataNode. + ASMJIT_API Error _newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1); + //! Creates a new \ref ConstPoolNode. + ASMJIT_API Error _newConstPoolNode(ConstPoolNode** out); + //! Creates a new \ref CommentNode. + ASMJIT_API Error _newCommentNode(CommentNode** out, const char* data, size_t size); //! Adds `node` after the current and sets the current node to the given `node`. ASMJIT_API BaseNode* addNode(BaseNode* node) noexcept; @@ -173,7 +180,9 @@ public: //! added they are always added after the cursor and the cursor is changed //! to be that newly added node. Use `setCursor()` to change where new nodes //! are inserted. - inline BaseNode* cursor() const noexcept { return _cursor; } + inline BaseNode* cursor() const noexcept { + return _cursor; + } //! Sets the current node to `node` and return the previous one. ASMJIT_API BaseNode* setCursor(BaseNode* node) noexcept; @@ -182,7 +191,9 @@ public: //! //! Only use this function if you are concerned about performance and want //! this inlined (for example if you set the cursor in a loop, etc...). - inline void _setCursor(BaseNode* node) noexcept { _cursor = node; } + inline void _setCursor(BaseNode* node) noexcept { + _cursor = node; + } //! \} @@ -193,7 +204,9 @@ public: //! //! \note If a section of some id is not associated with the Builder/Compiler //! it would be null, so always check for nulls if you iterate over the vector. - inline const ZoneVector<SectionNode*>& sectionNodes() const noexcept { return _sectionNodes; } + inline const ZoneVector<SectionNode*>& sectionNodes() const noexcept { + return _sectionNodes; + } //! Tests whether the `SectionNode` of the given `sectionId` was registered. inline bool hasRegisteredSectionNode(uint32_t sectionId) const noexcept { @@ -205,7 +218,7 @@ public: //! \remarks This function will either get the existing `SectionNode` or create //! it in case it wasn't created before. You can check whether a section has a //! registered `SectionNode` by using `BaseBuilder::hasRegisteredSectionNode()`. - ASMJIT_API Error sectionNodeOf(SectionNode** pOut, uint32_t sectionId) noexcept; + ASMJIT_API Error sectionNodeOf(SectionNode** out, uint32_t sectionId); ASMJIT_API Error section(Section* section) override; @@ -221,7 +234,7 @@ public: //! \name Label Management //! \{ - //! Returns a vector of LabelNode nodes. + //! Returns a vector of \ref LabelNode nodes. //! //! \note If a label of some id is not associated with the Builder/Compiler //! it would be null, so always check for nulls if you iterate over the vector. @@ -237,24 +250,24 @@ public: return hasRegisteredLabelNode(label.id()); } - //! Gets or creates a `LabelNode` that matches the given `labelId`. + //! Gets or creates a \ref LabelNode that matches the given `labelId`. //! //! \remarks This function will either get the existing `LabelNode` or create //! it in case it wasn't created before. You can check whether a label has a - //! registered `LabelNode` by using `BaseBuilder::hasRegisteredLabelNode()`. - ASMJIT_API Error labelNodeOf(LabelNode** pOut, uint32_t labelId) noexcept; + //! registered `LabelNode` by calling \ref BaseBuilder::hasRegisteredLabelNode(). + ASMJIT_API Error labelNodeOf(LabelNode** out, uint32_t labelId); //! \overload - inline Error labelNodeOf(LabelNode** pOut, const Label& label) noexcept { - return labelNodeOf(pOut, label.id()); + inline Error labelNodeOf(LabelNode** out, const Label& label) { + return labelNodeOf(out, label.id()); } - //! Registers this label node [Internal]. + //! Registers this \ref LabelNode (internal). //! //! This function is used internally to register a newly created `LabelNode` - //! with this instance of Builder/Compiler. Use `labelNodeOf()` functions to - //! get back `LabelNode` from a label or its identifier. - ASMJIT_API Error registerLabelNode(LabelNode* node) noexcept; + //! with this instance of Builder/Compiler. Use \ref labelNodeOf() functions + //! to get back \ref LabelNode from a label or its identifier. + ASMJIT_API Error registerLabelNode(LabelNode* node); ASMJIT_API Label newLabel() override; ASMJIT_API Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, uint32_t type = Label::kTypeGlobal, uint32_t parentId = Globals::kInvalidId) override; @@ -284,12 +297,14 @@ public: inline T* newPassT(Args&&... args) noexcept { return _codeZone.newT<T>(std::forward<Args>(args)...); } template<typename T> - inline Error addPassT() noexcept { return addPass(newPassT<T>()); } + inline Error addPassT() { return addPass(newPassT<T>()); } template<typename T, typename... Args> - inline Error addPassT(Args&&... args) noexcept { return addPass(newPassT<T, Args...>(std::forward<Args>(args)...)); } + inline Error addPassT(Args&&... args) { return addPass(newPassT<T, Args...>(std::forward<Args>(args)...)); } //! Returns `Pass` by name. + //! + //! If the pass having the given `name` doesn't exist `nullptr` is returned. ASMJIT_API Pass* passByName(const char* name) const noexcept; //! Adds `pass` to the list of passes. ASMJIT_API Error addPass(Pass* pass) noexcept; @@ -304,8 +319,7 @@ public: //! \name Emit //! \{ - ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) override; - ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override; + ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) override; //! \} @@ -319,11 +333,13 @@ public: //! \name Embed //! \{ - ASMJIT_API Error embed(const void* data, uint32_t dataSize) override; - ASMJIT_API Error embedLabel(const Label& label) override; - ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) override; + ASMJIT_API Error embed(const void* data, size_t dataSize) override; + ASMJIT_API Error embedDataArray(uint32_t typeId, const void* data, size_t count, size_t repeat = 1) override; ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override; + ASMJIT_API Error embedLabel(const Label& label) override; + ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize) override; + //! \} //! \name Comment @@ -345,15 +361,6 @@ public: //! \} - //! \name Logging - //! \{ - -#ifndef ASMJIT_NO_LOGGING - ASMJIT_API Error dump(String& sb, uint32_t flags = 0) const noexcept; -#endif - - //! \} - //! \name Events //! \{ @@ -361,6 +368,15 @@ public: ASMJIT_API Error onDetach(CodeHolder* code) noexcept override; //! \} + +#ifndef ASMJIT_NO_DEPRECATED +#ifndef ASMJIT_NO_LOGGING + ASMJIT_DEPRECATED("Use Formatter::formatNodeList(sb, formatFlags, builder)") + inline Error dump(String& sb, uint32_t formatFlags = 0) const noexcept { + return Formatter::formatNodeList(sb, formatFlags, this); + } +#endif // !ASMJIT_NO_LOGGING +#endif // !ASMJIT_NO_DEPRECATED }; // ============================================================================ @@ -369,11 +385,11 @@ public: //! Base node. //! -//! Every node represents a building-block used by `BaseBuilder`. It can be -//! instruction, data, label, comment, directive, or any other high-level +//! Every node represents a building-block used by \ref BaseBuilder. It can +//! be instruction, data, label, comment, directive, or any other high-level //! representation that can be transformed to the building blocks mentioned. -//! Every class that inherits `BaseBuilder` can define its own nodes that it -//! can lower to basic nodes. +//! Every class that inherits \ref BaseBuilder can define its own high-level +//! nodes that can be later lowered to basic nodes like instructions. class BaseNode { public: ASMJIT_NONCOPYABLE(BaseNode) @@ -385,7 +401,7 @@ public: //! Next node. BaseNode* _next; }; - //! Links (previous and next nodes). + //! Links (an alternative view to previous and next nodes). BaseNode* _links[2]; }; @@ -401,6 +417,7 @@ public: uint8_t _reserved1; }; + //! Data used by \ref InstNode. struct InstData { //! Node type, see \ref NodeType. uint8_t _nodeType; @@ -412,6 +429,19 @@ public: uint8_t _opCapacity; }; + //! Data used by \ref EmbedDataNode. + struct EmbedData { + //! Node type, see \ref NodeType. + uint8_t _nodeType; + //! Node flags, see \ref Flags. + uint8_t _nodeFlags; + //! Type id, see \ref Type::Id. + uint8_t _typeId; + //! Size of `_typeId`. + uint8_t _typeSize; + }; + + //! Data used by \ref SentinelNode. struct SentinelData { //! Node type, see \ref NodeType. uint8_t _nodeType; @@ -423,9 +453,15 @@ public: uint8_t _reserved1; }; + //! Data that can have different meaning dependning on \ref NodeType. union { + //! Data useful by any node type. AnyData _any; + //! Data specific to \ref InstNode. InstData _inst; + //! Data specific to \ref EmbedDataNode. + EmbedData _embed; + //! Data specific to \ref SentinelNode. SentinelData _sentinel; }; @@ -434,7 +470,9 @@ public: //! Value reserved for AsmJit users never touched by AsmJit itself. union { + //! User data as 64-bit integer. uint64_t _userDataU64; + //! User data as pointer. void* _userDataPtr; }; @@ -451,54 +489,66 @@ public: // [BaseBuilder] - //! Node is `InstNode` or `InstExNode`. + //! Node is \ref InstNode or \ref InstExNode. kNodeInst = 1, - //! Node is `SectionNode`. + //! Node is \ref SectionNode. kNodeSection = 2, - //! Node is `LabelNode`. + //! Node is \ref LabelNode. kNodeLabel = 3, - //! Node is `AlignNode`. + //! Node is \ref AlignNode. kNodeAlign = 4, - //! Node is `EmbedDataNode`. + //! Node is \ref EmbedDataNode. kNodeEmbedData = 5, - //! Node is `EmbedLabelNode`. + //! Node is \ref EmbedLabelNode. kNodeEmbedLabel = 6, - //! Node is `EmbedLabelDeltaNode`. + //! Node is \ref EmbedLabelDeltaNode. kNodeEmbedLabelDelta = 7, - //! Node is `ConstPoolNode`. + //! Node is \ref ConstPoolNode. kNodeConstPool = 8, - //! Node is `CommentNode`. + //! Node is \ref CommentNode. kNodeComment = 9, - //! Node is `SentinelNode`. + //! Node is \ref SentinelNode. kNodeSentinel = 10, // [BaseCompiler] - //! Node is `JumpNode` (acts as InstNode). + //! Node is \ref JumpNode (acts as InstNode). kNodeJump = 15, - //! Node is `FuncNode` (acts as LabelNode). + //! Node is \ref FuncNode (acts as LabelNode). kNodeFunc = 16, - //! Node is `FuncRetNode` (acts as InstNode). + //! Node is \ref FuncRetNode (acts as InstNode). kNodeFuncRet = 17, - //! Node is `FuncCallNode` (acts as InstNode). - kNodeFuncCall = 18, + //! Node is \ref InvokeNode (acts as InstNode). + kNodeInvoke = 18, // [UserDefined] //! First id of a user-defined node. - kNodeUser = 32 + kNodeUser = 32, + +#ifndef ASMJIT_NO_DEPRECATED + kNodeFuncCall = kNodeInvoke +#endif // !ASMJIT_NO_DEPRECATED }; //! Node flags, specify what the node is and/or does. enum Flags : uint32_t { - kFlagIsCode = 0x01u, //!< Node is code that can be executed (instruction, label, align, etc...). - kFlagIsData = 0x02u, //!< Node is data that cannot be executed (data, const-pool, etc...). - kFlagIsInformative = 0x04u, //!< Node is informative, can be removed and ignored. - kFlagIsRemovable = 0x08u, //!< Node can be safely removed if unreachable. - kFlagHasNoEffect = 0x10u, //!< Node does nothing when executed (label, align, explicit nop). - kFlagActsAsInst = 0x20u, //!< Node is an instruction or acts as it. - kFlagActsAsLabel = 0x40u, //!< Node is a label or acts as it. - kFlagIsActive = 0x80u //!< Node is active (part of the code). + //! Node is code that can be executed (instruction, label, align, etc...). + kFlagIsCode = 0x01u, + //! Node is data that cannot be executed (data, const-pool, etc...). + kFlagIsData = 0x02u, + //! Node is informative, can be removed and ignored. + kFlagIsInformative = 0x04u, + //! Node can be safely removed if unreachable. + kFlagIsRemovable = 0x08u, + //! Node does nothing when executed (label, align, explicit nop). + kFlagHasNoEffect = 0x10u, + //! Node is an instruction or acts as it. + kFlagActsAsInst = 0x20u, + //! Node is a label or acts as it. + kFlagActsAsLabel = 0x40u, + //! Node is active (part of the code). + kFlagIsActive = 0x80u }; //! \name Construction & Destruction @@ -572,8 +622,13 @@ public: inline bool isFunc() const noexcept { return type() == kNodeFunc; } //! Tests whether this node is `FuncRetNode`. inline bool isFuncRet() const noexcept { return type() == kNodeFuncRet; } - //! Tests whether this node is `FuncCallNode`. - inline bool isFuncCall() const noexcept { return type() == kNodeFuncCall; } + //! Tests whether this node is `InvokeNode`. + inline bool isInvoke() const noexcept { return type() == kNodeInvoke; } + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use isInvoke") + inline bool isFuncCall() const noexcept { return isInvoke(); } +#endif // !ASMJIT_NO_DEPRECATED //! Returns the node flags, see \ref Flags. inline uint32_t flags() const noexcept { return _any._nodeFlags; } @@ -697,12 +752,13 @@ public: _inst._opCount = uint8_t(opCount); } + //! \cond INTERNAL //! Reset all built-in operands, including `extraReg`. inline void _resetOps() noexcept { _baseInst.resetExtraReg(); - for (uint32_t i = 0, count = opCapacity(); i < count; i++) - _opArray[i].reset(); + resetOpRange(0, opCapacity()); } + //! \endcond //! \} @@ -739,12 +795,12 @@ public: //! Resets extra register operand. inline void resetExtraReg() noexcept { _baseInst.resetExtraReg(); } - //! Returns operands count. + //! Returns operand count. inline uint32_t opCount() const noexcept { return _inst._opCount; } - //! Returns operands capacity. + //! Returns operand capacity. inline uint32_t opCapacity() const noexcept { return _inst._opCapacity; } - //! Sets operands count. + //! Sets operand count. inline void setOpCount(uint32_t opCount) noexcept { _inst._opCount = uint8_t(opCount); } //! Returns operands array. @@ -752,27 +808,32 @@ public: //! Returns operands array (const). inline const Operand* operands() const noexcept { return (const Operand*)_opArray; } - inline Operand& opType(uint32_t index) noexcept { + //! Returns operand at the given `index`. + inline Operand& op(uint32_t index) noexcept { ASMJIT_ASSERT(index < opCapacity()); return _opArray[index].as<Operand>(); } - inline const Operand& opType(uint32_t index) const noexcept { + //! Returns operand at the given `index` (const). + inline const Operand& op(uint32_t index) const noexcept { ASMJIT_ASSERT(index < opCapacity()); return _opArray[index].as<Operand>(); } + //! Sets operand at the given `index` to `op`. inline void setOp(uint32_t index, const Operand_& op) noexcept { ASMJIT_ASSERT(index < opCapacity()); _opArray[index].copyFrom(op); } + //! Resets operand at the given `index` to none. inline void resetOp(uint32_t index) noexcept { ASMJIT_ASSERT(index < opCapacity()); _opArray[index].reset(); } - inline void resetOps(uint32_t start, uint32_t end) noexcept { + //! Resets operands at `[start, end)` range. + inline void resetOpRange(uint32_t start, uint32_t end) noexcept { for (uint32_t i = start; i < end; i++) _opArray[i].reset(); } @@ -816,6 +877,7 @@ public: //! \name Rewriting //! \{ + //! \cond INTERNAL inline uint32_t* _getRewriteArray() noexcept { return &_baseInst._extraReg._id; } inline const uint32_t* _getRewriteArray() const noexcept { return &_baseInst._extraReg._id; } @@ -833,12 +895,14 @@ public: uint32_t* array = _getRewriteArray(); array[index] = id; } + //! \endcond //! \} //! \name Static Functions //! \{ + //! \cond INTERNAL static inline uint32_t capacityOfOpCount(uint32_t opCount) noexcept { return opCount <= kBaseOpCapacity ? kBaseOpCapacity : Globals::kMaxOpCount; } @@ -847,6 +911,7 @@ public: size_t base = sizeof(InstNode) - kBaseOpCapacity * sizeof(Operand); return base + opCapacity * sizeof(Operand); } + //! \endcond //! \} }; @@ -855,7 +920,7 @@ public: // [asmjit::InstExNode] // ============================================================================ -//! Instruction node with maximum number of operands.. +//! Instruction node with maximum number of operands. //! //! This node is created automatically by Builder/Compiler in case that the //! required number of operands exceeds the default capacity of `InstNode`. @@ -925,27 +990,33 @@ class LabelNode : public BaseNode { public: ASMJIT_NONCOPYABLE(LabelNode) - uint32_t _id; + //! Label identifier. + uint32_t _labelId; //! \name Construction & Destruction //! \{ //! Creates a new `LabelNode` instance. - inline LabelNode(BaseBuilder* cb, uint32_t id = 0) noexcept + inline LabelNode(BaseBuilder* cb, uint32_t labelId = 0) noexcept : BaseNode(cb, kNodeLabel, kFlagHasNoEffect | kFlagActsAsLabel), - _id(id) {} + _labelId(labelId) {} //! \} //! \name Accessors //! \{ + //! Returns \ref Label representation of the \ref LabelNode. + inline Label label() const noexcept { return Label(_labelId); } //! Returns the id of the label. - inline uint32_t id() const noexcept { return _id; } - //! Returns the label as `Label` operand. - inline Label label() const noexcept { return Label(_id); } + inline uint32_t labelId() const noexcept { return _labelId; } //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use labelId() instead") + inline uint32_t id() const noexcept { return labelId(); } +#endif // !ASMJIT_NO_DEPRECATED }; // ============================================================================ @@ -1005,37 +1076,28 @@ public: ASMJIT_NONCOPYABLE(EmbedDataNode) enum : uint32_t { - kInlineBufferSize = uint32_t(64 - sizeof(BaseNode) - 4) + kInlineBufferSize = 128 - (sizeof(BaseNode) + sizeof(size_t) * 2) }; + size_t _itemCount; + size_t _repeatCount; + union { - struct { - //! Embedded data buffer. - uint8_t _buf[kInlineBufferSize]; - //! Size of the data. - uint32_t _size; - }; - struct { - //! Pointer to external data. - uint8_t* _externalPtr; - }; + uint8_t* _externalData; + uint8_t _inlineData[kInlineBufferSize]; }; //! \name Construction & Destruction //! \{ //! Creates a new `EmbedDataNode` instance. - inline EmbedDataNode(BaseBuilder* cb, void* data, uint32_t size) noexcept - : BaseNode(cb, kNodeEmbedData, kFlagIsData) { - - if (size <= kInlineBufferSize) { - if (data) - memcpy(_buf, data, size); - } - else { - _externalPtr = static_cast<uint8_t*>(data); - } - _size = size; + inline EmbedDataNode(BaseBuilder* cb) noexcept + : BaseNode(cb, kNodeEmbedData, kFlagIsData), + _itemCount(0), + _repeatCount(0) { + _embed._typeId = uint8_t(Type::kIdU8), + _embed._typeSize = uint8_t(1); + memset(_inlineData, 0, kInlineBufferSize); } //! \} @@ -1043,10 +1105,32 @@ public: //! \name Accessors //! \{ - //! Returns pointer to the data. - inline uint8_t* data() const noexcept { return _size <= kInlineBufferSize ? const_cast<uint8_t*>(_buf) : _externalPtr; } - //! Returns size of the data. - inline uint32_t size() const noexcept { return _size; } + //! Returns \ref Type::Id of the data. + inline uint32_t typeId() const noexcept { return _embed._typeId; } + //! Returns the size of a single data element. + inline uint32_t typeSize() const noexcept { return _embed._typeSize; } + + //! Returns a pointer to the data casted to `uint8_t`. + inline uint8_t* data() const noexcept { + return dataSize() <= kInlineBufferSize ? const_cast<uint8_t*>(_inlineData) : _externalData; + } + + //! Returns a pointer to the data casted to `T`. + template<typename T> + inline T* dataAs() const noexcept { return reinterpret_cast<T*>(data()); } + + //! Returns the number of (typed) items in the array. + inline size_t itemCount() const noexcept { return _itemCount; } + + //! Returns how many times the data is repeated (default 1). + //! + //! Repeated data is useful when defining constants for SIMD, for example. + inline size_t repeatCount() const noexcept { return _repeatCount; } + + //! Returns the size of the data, not considering the number of times it repeats. + //! + //! \note The returned value is the same as `typeSize() * itemCount()`. + inline size_t dataSize() const noexcept { return typeSize() * _itemCount; } //! \} }; @@ -1060,32 +1144,37 @@ class EmbedLabelNode : public BaseNode { public: ASMJIT_NONCOPYABLE(EmbedLabelNode) - uint32_t _id; + uint32_t _labelId; //! \name Construction & Destruction //! \{ //! Creates a new `EmbedLabelNode` instance. - inline EmbedLabelNode(BaseBuilder* cb, uint32_t id = 0) noexcept + inline EmbedLabelNode(BaseBuilder* cb, uint32_t labelId = 0) noexcept : BaseNode(cb, kNodeEmbedLabel, kFlagIsData), - _id(id) {} + _labelId(labelId) {} //! \} //! \name Accessors //! \{ + //! Returns the label to embed as \ref Label operand. + inline Label label() const noexcept { return Label(_labelId); } //! Returns the id of the label. - inline uint32_t id() const noexcept { return _id; } - //! Sets the label id (use with caution, improper use can break a lot of things). - inline void setId(uint32_t id) noexcept { _id = id; } + inline uint32_t labelId() const noexcept { return _labelId; } - //! Returns the label as `Label` operand. - inline Label label() const noexcept { return Label(_id); } //! Sets the label id from `label` operand. - inline void setLabel(const Label& label) noexcept { setId(label.id()); } + inline void setLabel(const Label& label) noexcept { setLabelId(label.id()); } + //! Sets the label id (use with caution, improper use can break a lot of things). + inline void setLabelId(uint32_t labelId) noexcept { _labelId = labelId; } //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use labelId() instead") + inline uint32_t id() const noexcept { return labelId(); } +#endif // !ASMJIT_NO_DEPRECATED }; // ============================================================================ @@ -1097,18 +1186,18 @@ class EmbedLabelDeltaNode : public BaseNode { public: ASMJIT_NONCOPYABLE(EmbedLabelDeltaNode) - uint32_t _id; - uint32_t _baseId; + uint32_t _labelId; + uint32_t _baseLabelId; uint32_t _dataSize; //! \name Construction & Destruction //! \{ //! Creates a new `EmbedLabelDeltaNode` instance. - inline EmbedLabelDeltaNode(BaseBuilder* cb, uint32_t id = 0, uint32_t baseId = 0, uint32_t dataSize = 0) noexcept + inline EmbedLabelDeltaNode(BaseBuilder* cb, uint32_t labelId = 0, uint32_t baseLabelId = 0, uint32_t dataSize = 0) noexcept : BaseNode(cb, kNodeEmbedLabelDelta, kFlagIsData), - _id(id), - _baseId(baseId), + _labelId(labelId), + _baseLabelId(baseLabelId), _dataSize(dataSize) {} //! \} @@ -1116,28 +1205,46 @@ public: //! \name Accessors //! \{ - //! Returns the id of the label. - inline uint32_t id() const noexcept { return _id; } - //! Sets the label id. - inline void setId(uint32_t id) noexcept { _id = id; } //! Returns the label as `Label` operand. - inline Label label() const noexcept { return Label(_id); } + inline Label label() const noexcept { return Label(_labelId); } + //! Returns the id of the label. + inline uint32_t labelId() const noexcept { return _labelId; } + //! Sets the label id from `label` operand. - inline void setLabel(const Label& label) noexcept { setId(label.id()); } + inline void setLabel(const Label& label) noexcept { setLabelId(label.id()); } + //! Sets the label id. + inline void setLabelId(uint32_t labelId) noexcept { _labelId = labelId; } - //! Returns the id of the base label. - inline uint32_t baseId() const noexcept { return _baseId; } - //! Sets the base label id. - inline void setBaseId(uint32_t baseId) noexcept { _baseId = baseId; } //! Returns the base label as `Label` operand. - inline Label baseLabel() const noexcept { return Label(_baseId); } + inline Label baseLabel() const noexcept { return Label(_baseLabelId); } + //! Returns the id of the base label. + inline uint32_t baseLabelId() const noexcept { return _baseLabelId; } + //! Sets the base label id from `label` operand. - inline void setBaseLabel(const Label& baseLabel) noexcept { setBaseId(baseLabel.id()); } + inline void setBaseLabel(const Label& baseLabel) noexcept { setBaseLabelId(baseLabel.id()); } + //! Sets the base label id. + inline void setBaseLabelId(uint32_t baseLabelId) noexcept { _baseLabelId = baseLabelId; } + //! Returns the size of the embedded label address. inline uint32_t dataSize() const noexcept { return _dataSize; } + //! Sets the size of the embedded label address. inline void setDataSize(uint32_t dataSize) noexcept { _dataSize = dataSize; } //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use labelId() instead") + inline uint32_t id() const noexcept { return labelId(); } + + ASMJIT_DEPRECATED("Use setLabelId() instead") + inline void setId(uint32_t id) noexcept { setLabelId(id); } + + ASMJIT_DEPRECATED("Use baseLabelId() instead") + inline uint32_t baseId() const noexcept { return baseLabelId(); } + + ASMJIT_DEPRECATED("Use setBaseLabelId() instead") + inline void setBaseId(uint32_t id) noexcept { setBaseLabelId(id); } +#endif // !ASMJIT_NO_DEPRECATED }; // ============================================================================ @@ -1229,7 +1336,9 @@ public: //! Type of the sentinel (purery informative purpose). enum SentinelType : uint32_t { + //! Type of the sentinel is not known. kSentinelUnknown = 0u, + //! This is a sentinel used at the end of \ref FuncNode. kSentinelFuncEnd = 1u }; @@ -1248,8 +1357,15 @@ public: //! \name Accessors //! \{ - inline uint32_t sentinelType() const noexcept { return _sentinel._sentinelType; } - inline void setSentinelType(uint32_t type) noexcept { _sentinel._sentinelType = uint8_t(type); } + //! Returns the type of the sentinel. + inline uint32_t sentinelType() const noexcept { + return _sentinel._sentinelType; + } + + //! Sets the type of the sentinel. + inline void setSentinelType(uint32_t type) noexcept { + _sentinel._sentinelType = uint8_t(type); + } //! \} }; @@ -1280,7 +1396,9 @@ public: //! \name Accessors //! \{ + //! Returns \ref BaseBuilder associated with the pass. inline const BaseBuilder* cb() const noexcept { return _cb; } + //! Returns the name of the pass. inline const char* name() const noexcept { return _name; } //! \} @@ -1292,7 +1410,7 @@ public: //! //! This is the only function that is called by the `BaseBuilder` to process //! the code. It passes `zone`, which will be reset after the `run()` finishes. - virtual Error run(Zone* zone, Logger* logger) noexcept = 0; + virtual Error run(Zone* zone, Logger* logger) = 0; //! \} }; diff --git a/3rdparty/asmjit/src/asmjit/core/callconv.cpp b/3rdparty/asmjit/src/asmjit/core/callconv.cpp index 5d915d0e38d..722dbcdb238 100644 --- a/3rdparty/asmjit/src/asmjit/core/callconv.cpp +++ b/3rdparty/asmjit/src/asmjit/core/callconv.cpp @@ -40,17 +40,17 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::CallConv - Init / Reset] // ============================================================================ -ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId) noexcept { +ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId, const Environment& environment) noexcept { reset(); #ifdef ASMJIT_BUILD_X86 - if (CallConv::isX86Family(ccId)) - return x86::CallConvInternal::init(*this, ccId); + if (environment.isFamilyX86()) + return x86::CallConvInternal::init(*this, ccId, environment); #endif #ifdef ASMJIT_BUILD_ARM - if (CallConv::isArmFamily(ccId)) - return arm::CallConvInternal::init(*this, ccId); + if (environment.isFamilyARM()) + return arm::CallConvInternal::init(*this, ccIdv, environment); #endif return DebugUtils::errored(kErrorInvalidArgument); diff --git a/3rdparty/asmjit/src/asmjit/core/callconv.h b/3rdparty/asmjit/src/asmjit/core/callconv.h index f3dc385dfec..6e75540c545 100644 --- a/3rdparty/asmjit/src/asmjit/core/callconv.h +++ b/3rdparty/asmjit/src/asmjit/core/callconv.h @@ -30,7 +30,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_func +//! \addtogroup asmjit_function //! \{ // ============================================================================ @@ -46,8 +46,8 @@ ASMJIT_BEGIN_NAMESPACE struct CallConv { //! Calling convention id, see `Id`. uint8_t _id; - //! Architecture id (see `ArchInfo::Id`). - uint8_t _archId; + //! Architecture identifier, see \ref Environment::Arch. + uint8_t _arch; //! Register assignment strategy. uint8_t _strategy; //! Flags. @@ -78,179 +78,117 @@ struct CallConv { uint32_t packed[(kMaxRegArgsPerGroup + 3) / 4]; }; - //! Passed registers' order, per group. + //! Passed registers' order, per register group. RegOrder _passedOrder[BaseReg::kGroupVirt]; //! Calling convention id. + //! + //! Calling conventions can be divided into the following groups: + //! + //! - Universal - calling conventions are applicable to any target. They + //! will be converted to a target dependent calling convention at runtime + //! by \ref init(). The purpose of these conventions is to make using + //! functions less target dependent and closer to how they are declared + //! in C and C++. + //! + //! - Target specific - calling conventions that are used by a particular + //! architecture and ABI. For example Windows 64-bit calling convention + //! and AMD64 SystemV calling convention. enum Id : uint32_t { //! None or invalid (can't be used). kIdNone = 0, // ------------------------------------------------------------------------ - // [Universal] + // [Universal Calling Conventions] // ------------------------------------------------------------------------ - // TODO: To make this possible we need to know target ARCH and ABI. - - /* - - // Universal calling conventions are applicable to any target and are - // converted to target dependent conventions at runtime. The purpose of - // these conventions is to make using functions less target dependent. - + //! Standard function call or explicit `__cdecl` where it can be specified. + //! + //! This is a universal convention, which is used to initialize specific + //! calling connventions based on architecture, platform, and its ABI. kIdCDecl = 1, + + //! `__stdcall` on targets that support this calling convention. + //! + //! \note This calling convention is only supported on 32-bit X86. If used + //! on environment that doesn't support this calling convention \ref kIdCDecl + //! will be used instead. kIdStdCall = 2, + + //! `__fastcall` on targets that support this calling convention. + //! + //! \note This calling convention is only supported on 32-bit X86. If used + //! on environment that doesn't support this calling convention \ref kIdCDecl + //! will be used instead. kIdFastCall = 3, + //! `__vectorcall` on targets that support this calling convention. + //! + //! \note This calling convention is only supported on 32-bit and 64-bit + //! X86 architecture on Windows platform. If used on environment that doesn't + //! support this calling convention \ref kIdCDecl will be used instead. + kIdVectorCall = 4, + + //! `__thiscall` on targets that support this calling convention. + //! + //! \note This calling convention is only supported on 32-bit X86 Windows + //! platform. If used on environment that doesn't support this calling + //! convention \ref kIdCDecl will be used instead. + kIdThisCall = 5, + + //! `__attribute__((regparm(1)))` convention (GCC and Clang). + kIdRegParm1 = 6, + //! `__attribute__((regparm(2)))` convention (GCC and Clang). + kIdRegParm2 = 7, + //! `__attribute__((regparm(3)))` convention (GCC and Clang). + kIdRegParm3 = 8, + + //! Soft-float calling convention (ARM). + //! + //! Floating point arguments are passed via general purpose registers. + kIdSoftFloat = 9, + + //! Hard-float calling convention (ARM). + //! + //! Floating point arguments are passed via SIMD registers. + kIdHardFloat = 10, + //! AsmJit specific calling convention designed for calling functions //! inside a multimedia code that don't use many registers internally, //! but are long enough to be called and not inlined. These functions are //! usually used to calculate trigonometric functions, logarithms, etc... - kIdLightCall2 = 10, - kIdLightCall3 = 11, - kIdLightCall4 = 12, - */ - - // ------------------------------------------------------------------------ - // [X86] - // ------------------------------------------------------------------------ - - //! X86 `__cdecl` calling convention (used by C runtime and libraries). - kIdX86CDecl = 16, - //! X86 `__stdcall` calling convention (used mostly by WinAPI). - kIdX86StdCall = 17, - //! X86 `__thiscall` calling convention (MSVC/Intel). - kIdX86MsThisCall = 18, - //! X86 `__fastcall` convention (MSVC/Intel). - kIdX86MsFastCall = 19, - //! X86 `__fastcall` convention (GCC and Clang). - kIdX86GccFastCall = 20, - //! X86 `regparm(1)` convention (GCC and Clang). - kIdX86GccRegParm1 = 21, - //! X86 `regparm(2)` convention (GCC and Clang). - kIdX86GccRegParm2 = 22, - //! X86 `regparm(3)` convention (GCC and Clang). - kIdX86GccRegParm3 = 23, - - kIdX86LightCall2 = 29, - kIdX86LightCall3 = 30, - kIdX86LightCall4 = 31, - - //! X64 calling convention - WIN64-ABI. - kIdX86Win64 = 32, - //! X64 calling convention - SystemV / AMD64-ABI. - kIdX86SysV64 = 33, - - kIdX64LightCall2 = 45, - kIdX64LightCall3 = 46, - kIdX64LightCall4 = 47, - - // ------------------------------------------------------------------------ - // [ARM] - // ------------------------------------------------------------------------ - - //! Legacy calling convention, floating point arguments are passed via GP registers. - kIdArm32SoftFP = 48, - //! Modern calling convention, uses VFP registers to pass floating point arguments. - kIdArm32HardFP = 49, + kIdLightCall2 = 16, + kIdLightCall3 = 17, + kIdLightCall4 = 18, // ------------------------------------------------------------------------ - // [Internal] + // [ABI-Specific Calling Conventions] // ------------------------------------------------------------------------ - //! \cond INTERNAL - - _kIdX86Start = 16, - _kIdX86End = 31, - - _kIdX64Start = 32, - _kIdX64End = 47, - - _kIdArmStart = 48, - _kIdArmEnd = 49, - - //! \endcond + kIdX64SystemV = 32, + kIdX64Windows = 33, // ------------------------------------------------------------------------ // [Host] // ------------------------------------------------------------------------ -#if defined(ASMJIT_DOCGEN) - - //! Default calling convention based on the current C++ compiler's settings. - //! - //! \note This should be always the same as `kIdHostCDecl`, but some - //! compilers allow to override the default calling convention. Overriding - //! is not detected at the moment. - kIdHost = DETECTED_AT_COMPILE_TIME, - - //! Default CDECL calling convention based on the current C++ compiler's settings. - kIdHostCDecl = DETECTED_AT_COMPILE_TIME, - - //! Default STDCALL calling convention based on the current C++ compiler's settings. - //! - //! \note If not defined by the host then it's the same as `kIdHostCDecl`. - kIdHostStdCall = DETECTED_AT_COMPILE_TIME, - - //! Compatibility for `__fastcall` calling convention. - //! - //! \note If not defined by the host then it's the same as `kIdHostCDecl`. - kIdHostFastCall = DETECTED_AT_COMPILE_TIME - -#elif ASMJIT_ARCH_X86 == 32 - - kIdHost = kIdX86CDecl, - kIdHostCDecl = kIdX86CDecl, - kIdHostStdCall = kIdX86StdCall, - -# if defined(_MSC_VER) - kIdHostFastCall = kIdX86MsFastCall, -# elif defined(__GNUC__) - kIdHostFastCall = kIdX86GccFastCall, -# else - kIdHostFastCall = kIdHost, -# endif - - kIdHostLightCall2 = kIdX86LightCall2, - kIdHostLightCall3 = kIdX86LightCall3, - kIdHostLightCall4 = kIdX86LightCall4 - -#elif ASMJIT_ARCH_X86 == 64 - -# if defined(_WIN32) - kIdHost = kIdX86Win64, -# else - kIdHost = kIdX86SysV64, -# endif - - kIdHostCDecl = kIdHost, // Doesn't exist, redirected to host. - kIdHostStdCall = kIdHost, // Doesn't exist, redirected to host. - kIdHostFastCall = kIdHost, // Doesn't exist, redirected to host. - - kIdHostLightCall2 = kIdX64LightCall2, - kIdHostLightCall3 = kIdX64LightCall3, - kIdHostLightCall4 = kIdX64LightCall4 - -#elif ASMJIT_ARCH_ARM == 32 - -# if defined(__SOFTFP__) - kIdHost = kIdArm32SoftFP, -# else - kIdHost = kIdArm32HardFP, -# endif - // These don't exist on ARM. - kIdHostCDecl = kIdHost, // Doesn't exist, redirected to host. - kIdHostStdCall = kIdHost, // Doesn't exist, redirected to host. - kIdHostFastCall = kIdHost // Doesn't exist, redirected to host. - + kIdHost = +#if ASMJIT_ARCH_ARM == 32 && defined(__SOFTFP__) + kIdSoftFloat +#elif ASMJIT_ARCH_ARM == 32 && !defined(__SOFTFP__) + kIdHardFloat #else - - kIdHost = kIdNone, - kIdHostCDecl = kIdHost, - kIdHostStdCall = kIdHost, - kIdHostFastCall = kIdHost - + kIdCDecl #endif + +#ifndef ASMJIT_NO_DEPRECATE + , kIdHostCDecl = kIdCDecl + , kIdHostStdCall = kIdStdCall + , kIdHostFastCall = kIdFastCall + , kIdHostLightCall2 = kIdLightCall2 + , kIdHostLightCall3 = kIdLightCall3 + , kIdHostLightCall4 = kIdLightCall4 +#endif // !ASMJIT_NO_DEPRECATE }; //! Strategy used to assign registers to function arguments. @@ -262,23 +200,50 @@ struct CallConv { //! as defined by WIN64 calling convention - it applies to 64-bit calling //! conventions only. enum Strategy : uint32_t { - kStrategyDefault = 0, //!< Default register assignment strategy. - kStrategyWin64 = 1 //!< WIN64 specific register assignment strategy. + //! Default register assignment strategy. + kStrategyDefault = 0, + //! Windows 64-bit ABI register assignment strategy. + kStrategyX64Windows = 1, + //! Windows 64-bit __vectorcall register assignment strategy. + kStrategyX64VectorCall = 2, + + //! Number of assignment strategies. + kStrategyCount = 3 }; //! Calling convention flags. enum Flags : uint32_t { - kFlagCalleePopsStack = 0x01, //!< Callee is responsible for cleaning up the stack. - kFlagPassFloatsByVec = 0x02, //!< Pass F32 and F64 arguments by VEC128 register. - kFlagVectorCall = 0x04, //!< This is a '__vectorcall' calling convention. - kFlagIndirectVecArgs = 0x08 //!< Pass vector arguments indirectly (as a pointer). + //! Callee is responsible for cleaning up the stack. + kFlagCalleePopsStack = 0x01u, + //! Pass vector arguments indirectly (as a pointer). + kFlagIndirectVecArgs = 0x02u, + //! Pass F32 and F64 arguments by VEC128 register. + kFlagPassFloatsByVec = 0x04u, + //! Pass MMX and vector arguments by stack if the function has variable arguments. + kFlagPassVecByStackIfVA = 0x08u, + //! MMX registers are passed and returned via GP registers. + kFlagPassMmxByGp = 0x10u, + //! MMX registers are passed and returned via XMM registers. + kFlagPassMmxByXmm = 0x20u, + //! Calling convention can be used with variable arguments. + kFlagVarArgCompatible = 0x80u }; //! \name Construction & Destruction //! \{ - ASMJIT_API Error init(uint32_t ccId) noexcept; + //! Initializes this calling convention to the given `ccId` based on the + //! `environment`. + //! + //! See \ref Id and \ref Environment for more details. + ASMJIT_API Error init(uint32_t ccId, const Environment& environment) noexcept; + //! Resets this CallConv struct into a defined state. + //! + //! It's recommended to reset the \ref CallConv struct in case you would + //! like create a custom calling convention as it prevents from using an + //! uninitialized data (CallConv doesn't have a constructor that would + //! initialize it, it's just a struct). inline void reset() noexcept { memset(this, 0, sizeof(*this)); memset(_passedOrder, 0xFF, sizeof(_passedOrder)); @@ -295,9 +260,9 @@ struct CallConv { inline void setId(uint32_t id) noexcept { _id = uint8_t(id); } //! Returns the calling function architecture id. - inline uint32_t archId() const noexcept { return _archId; } + inline uint32_t arch() const noexcept { return _arch; } //! Sets the calling function architecture id. - inline void setArchType(uint32_t archId) noexcept { _archId = uint8_t(archId); } + inline void setArch(uint32_t arch) noexcept { _arch = uint8_t(arch); } //! Returns the strategy used to assign registers to arguments, see `Strategy`. inline uint32_t strategy() const noexcept { return _strategy; } @@ -337,11 +302,13 @@ struct CallConv { //! implement custom calling conventions that guarantee higher stack alignment. inline void setNaturalStackAlignment(uint32_t value) noexcept { _naturalStackAlignment = uint8_t(value); } + //! Returns the order of passed registers of the given `group`, see \ref BaseReg::RegGroup. inline const uint8_t* passedOrder(uint32_t group) const noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); return _passedOrder[group].id; } + //! Returns the mask of passed registers of the given `group`, see \ref BaseReg::RegGroup. inline uint32_t passedRegs(uint32_t group) const noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); return _passedRegs[group]; @@ -356,6 +323,7 @@ struct CallConv { _passedOrder[group].packed[3] = p3; } + //! Resets the order and mask of passed registers. inline void setPassedToNone(uint32_t group) noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); @@ -363,6 +331,7 @@ struct CallConv { _passedRegs[group] = 0u; } + //! Sets the order and mask of passed registers. inline void setPassedOrder(uint32_t group, uint32_t a0, uint32_t a1 = 0xFF, uint32_t a2 = 0xFF, uint32_t a3 = 0xFF, uint32_t a4 = 0xFF, uint32_t a5 = 0xFF, uint32_t a6 = 0xFF, uint32_t a7 = 0xFF) noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); @@ -383,25 +352,19 @@ struct CallConv { (a7 != 0xFF ? 1u << a7 : 0u) ; } + //! Returns preserved register mask of the given `group`, see \ref BaseReg::RegGroup. inline uint32_t preservedRegs(uint32_t group) const noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); return _preservedRegs[group]; } + //! Sets preserved register mask of the given `group`, see \ref BaseReg::RegGroup. inline void setPreservedRegs(uint32_t group, uint32_t regs) noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); _preservedRegs[group] = regs; } //! \} - - //! \name Static Functions - //! \{ - - static inline bool isX86Family(uint32_t ccId) noexcept { return ccId >= _kIdX86Start && ccId <= _kIdX64End; } - static inline bool isArmFamily(uint32_t ccId) noexcept { return ccId >= _kIdArmStart && ccId <= _kIdArmEnd; } - - //! \} }; //! \} diff --git a/3rdparty/asmjit/src/asmjit/core/codebuffer.h b/3rdparty/asmjit/src/asmjit/core/codebuffer.h new file mode 100644 index 00000000000..76c86b1f631 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/codebuffer.h @@ -0,0 +1,126 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_CODEBUFFER_H_INCLUDED +#define ASMJIT_CORE_CODEBUFFER_H_INCLUDED + +#include "../core/globals.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::CodeBuffer] +// ============================================================================ + +//! Code or data buffer. +struct CodeBuffer { + //! The content of the buffer (data). + uint8_t* _data; + //! Number of bytes of `data` used. + size_t _size; + //! Buffer capacity (in bytes). + size_t _capacity; + //! Buffer flags. + uint32_t _flags; + + //! Code buffer flags. + enum Flags : uint32_t { + //! Buffer is external (not allocated by asmjit). + kFlagIsExternal = 0x00000001u, + //! Buffer is fixed (cannot be reallocated). + kFlagIsFixed = 0x00000002u + }; + + //! \name Overloaded Operators + //! \{ + + //! Returns a referebce to the byte at the given `index`. + inline uint8_t& operator[](size_t index) noexcept { + ASMJIT_ASSERT(index < _size); + return _data[index]; + } + //! \overload + inline const uint8_t& operator[](size_t index) const noexcept { + ASMJIT_ASSERT(index < _size); + return _data[index]; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns code buffer flags, see \ref Flags. + inline uint32_t flags() const noexcept { return _flags; } + //! Tests whether the code buffer has the given `flag` set. + inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + + //! Tests whether this code buffer has a fixed size. + //! + //! Fixed size means that the code buffer is fixed and cannot grow. + inline bool isFixed() const noexcept { return hasFlag(kFlagIsFixed); } + + //! Tests whether the data in this code buffer is external. + //! + //! External data can only be provided by users, it's never used by AsmJit. + inline bool isExternal() const noexcept { return hasFlag(kFlagIsExternal); } + + //! Tests whether the data in this code buffer is allocated (non-null). + inline bool isAllocated() const noexcept { return _data != nullptr; } + + //! Tests whether the code buffer is empty. + inline bool empty() const noexcept { return !_size; } + + //! Returns the size of the data. + inline size_t size() const noexcept { return _size; } + //! Returns the capacity of the data. + inline size_t capacity() const noexcept { return _capacity; } + + //! Returns the pointer to the data the buffer references. + inline uint8_t* data() noexcept { return _data; } + //! \overload + inline const uint8_t* data() const noexcept { return _data; } + + //! \} + + //! \name Iterators + //! \{ + + inline uint8_t* begin() noexcept { return _data; } + inline const uint8_t* begin() const noexcept { return _data; } + + inline uint8_t* end() noexcept { return _data + _size; } + inline const uint8_t* end() const noexcept { return _data + _size; } + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_CODEBUFFER_H_INCLUDED + diff --git a/3rdparty/asmjit/src/asmjit/core/codebufferwriter_p.h b/3rdparty/asmjit/src/asmjit/core/codebufferwriter_p.h index ee7521153a3..75ee04748f4 100644 --- a/3rdparty/asmjit/src/asmjit/core/codebufferwriter_p.h +++ b/3rdparty/asmjit/src/asmjit/core/codebufferwriter_p.h @@ -25,12 +25,13 @@ #define ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED #include "../core/assembler.h" +#include "../core/codebuffer.h" #include "../core/support.h" ASMJIT_BEGIN_NAMESPACE //! \cond INTERNAL -//! \addtogroup asmjit_core +//! \addtogroup asmjit_assembler //! \{ // ============================================================================ diff --git a/3rdparty/asmjit/src/asmjit/core/codeholder.cpp b/3rdparty/asmjit/src/asmjit/core/codeholder.cpp index 93c9a99df88..8711e382ce4 100644 --- a/3rdparty/asmjit/src/asmjit/core/codeholder.cpp +++ b/3rdparty/asmjit/src/asmjit/core/codeholder.cpp @@ -23,7 +23,7 @@ #include "../core/api-build_p.h" #include "../core/assembler.h" -#include "../core/logging.h" +#include "../core/logger.h" #include "../core/support.h" ASMJIT_BEGIN_NAMESPACE @@ -78,13 +78,6 @@ public: }; // ============================================================================ -// [asmjit::ErrorHandler] -// ============================================================================ - -ErrorHandler::ErrorHandler() noexcept {} -ErrorHandler::~ErrorHandler() noexcept {} - -// ============================================================================ // [asmjit::CodeHolder - Utilities] // ============================================================================ @@ -97,8 +90,8 @@ static void CodeHolder_resetInternal(CodeHolder* self, uint32_t resetPolicy) noe self->detach(emitters[--i]); // Reset everything into its construction state. - self->_codeInfo.reset(); - self->_emitterOptions = 0; + self->_environment.reset(); + self->_baseAddress = Globals::kNoBaseAddress; self->_logger = nullptr; self->_errorHandler = nullptr; @@ -129,20 +122,10 @@ static void CodeHolder_resetInternal(CodeHolder* self, uint32_t resetPolicy) noe self->_zone.reset(resetPolicy); } -static void CodeHolder_modifyEmitterOptions(CodeHolder* self, uint32_t clear, uint32_t add) noexcept { - uint32_t oldOpt = self->_emitterOptions; - uint32_t newOpt = (oldOpt & ~clear) | add; - - if (oldOpt == newOpt) - return; - - // Modify emitter options of `CodeHolder` itself. - self->_emitterOptions = newOpt; - - // Modify emitter options of all attached emitters. +static void CodeHolder_onSettingsUpdated(CodeHolder* self) noexcept { + // Notify all attached emitters about a settings update. for (BaseEmitter* emitter : self->emitters()) { - emitter->_emitterOptions = (emitter->_emitterOptions & ~clear) | add; - emitter->onUpdateGlobalInstOptions(); + emitter->onSettingsUpdated(); } } @@ -151,8 +134,8 @@ static void CodeHolder_modifyEmitterOptions(CodeHolder* self, uint32_t clear, ui // ============================================================================ CodeHolder::CodeHolder() noexcept - : _codeInfo(), - _emitterOptions(0), + : _environment(), + _baseAddress(Globals::kNoBaseAddress), _logger(nullptr), _errorHandler(nullptr), _zone(16384 - Zone::kBlockOverhead), @@ -177,7 +160,7 @@ inline void CodeHolder_setSectionDefaultName( section->_name.u32[1] = Support::bytepack32_4x8(uint8_t(c4), uint8_t(c5), uint8_t(c6), uint8_t(c7)); } -Error CodeHolder::init(const CodeInfo& info) noexcept { +Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noexcept { // Cannot reinitialize if it's locked or there is one or more emitter attached. if (isInitialized()) return DebugUtils::errored(kErrorAlreadyInitialized); @@ -185,7 +168,7 @@ Error CodeHolder::init(const CodeInfo& info) noexcept { // If we are just initializing there should be no emitters attached. ASMJIT_ASSERT(_emitters.empty()); - // Create the default section and insert it to the `_sections` array. + // Create a default section and insert it to the `_sections` array. Error err = _sections.willGrow(&_allocator); if (err == kErrorOk) { Section* section = _allocator.allocZeroedT<Section>(); @@ -204,7 +187,8 @@ Error CodeHolder::init(const CodeInfo& info) noexcept { return err; } else { - _codeInfo = info; + _environment = environment; + _baseAddress = baseAddress; return kErrorOk; } } @@ -271,34 +255,28 @@ Error CodeHolder::detach(BaseEmitter* emitter) noexcept { } // ============================================================================ -// [asmjit::CodeHolder - Emitter Options] -// ============================================================================ - -static constexpr uint32_t kEmitterOptionsFilter = ~uint32_t(BaseEmitter::kOptionLoggingEnabled); - -void CodeHolder::addEmitterOptions(uint32_t options) noexcept { - CodeHolder_modifyEmitterOptions(this, 0, options & kEmitterOptionsFilter); -} - -void CodeHolder::clearEmitterOptions(uint32_t options) noexcept { - CodeHolder_modifyEmitterOptions(this, options & kEmitterOptionsFilter, 0); -} - -// ============================================================================ -// [asmjit::CodeHolder - Logging & Error Handling] +// [asmjit::CodeHolder - Logging] // ============================================================================ void CodeHolder::setLogger(Logger* logger) noexcept { #ifndef ASMJIT_NO_LOGGING _logger = logger; - uint32_t option = !logger ? uint32_t(0) : uint32_t(BaseEmitter::kOptionLoggingEnabled); - CodeHolder_modifyEmitterOptions(this, BaseEmitter::kOptionLoggingEnabled, option); + CodeHolder_onSettingsUpdated(this); #else DebugUtils::unused(logger); #endif } // ============================================================================ +// [asmjit::CodeHolder - Error Handling] +// ============================================================================ + +void CodeHolder::setErrorHandler(ErrorHandler* errorHandler) noexcept { + _errorHandler = errorHandler; + CodeHolder_onSettingsUpdated(this); +} + +// ============================================================================ // [asmjit::CodeHolder - Code Buffer] // ============================================================================ @@ -440,7 +418,7 @@ Section* CodeHolder::ensureAddressTableSection() noexcept { if (_addressTableSection) return _addressTableSection; - newSection(&_addressTableSection, CodeHolder_addrTabName, sizeof(CodeHolder_addrTabName) - 1, 0, _codeInfo.gpSize()); + newSection(&_addressTableSection, CodeHolder_addrTabName, sizeof(CodeHolder_addrTabName) - 1, 0, _environment.registerSize()); return _addressTableSection; } @@ -458,7 +436,7 @@ Error CodeHolder::addAddressToAddressTable(uint64_t address) noexcept { return DebugUtils::errored(kErrorOutOfMemory); _addressTableEntries.insert(entry); - section->_virtualSize += _codeInfo.gpSize(); + section->_virtualSize += _environment.registerSize(); return kErrorOk; } @@ -470,20 +448,24 @@ Error CodeHolder::addAddressToAddressTable(uint64_t address) noexcept { //! Only used to lookup a label from `_namedLabels`. class LabelByName { public: - inline LabelByName(const char* key, size_t keySize, uint32_t hashCode) noexcept + inline LabelByName(const char* key, size_t keySize, uint32_t hashCode, uint32_t parentId) noexcept : _key(key), _keySize(uint32_t(keySize)), - _hashCode(hashCode) {} + _hashCode(hashCode), + _parentId(parentId) {} inline uint32_t hashCode() const noexcept { return _hashCode; } inline bool matches(const LabelEntry* entry) const noexcept { - return entry->nameSize() == _keySize && ::memcmp(entry->name(), _key, _keySize) == 0; + return entry->nameSize() == _keySize && + entry->parentId() == _parentId && + ::memcmp(entry->name(), _key, _keySize) == 0; } const char* _key; uint32_t _keySize; uint32_t _hashCode; + uint32_t _parentId; }; // Returns a hash of `name` and fixes `nameSize` if it's `SIZE_MAX`. @@ -539,7 +521,7 @@ LabelLink* CodeHolder::newLabelLink(LabelEntry* le, uint32_t sectionId, size_t o } Error CodeHolder::newLabelEntry(LabelEntry** entryOut) noexcept { - *entryOut = 0; + *entryOut = nullptr; uint32_t labelId = _labelEntries.size(); if (ASMJIT_UNLIKELY(labelId == Globals::kInvalidId)) @@ -561,7 +543,7 @@ Error CodeHolder::newLabelEntry(LabelEntry** entryOut) noexcept { } Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, uint32_t type, uint32_t parentId) noexcept { - *entryOut = 0; + *entryOut = nullptr; uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize); if (ASMJIT_UNLIKELY(nameSize == 0)) @@ -580,7 +562,7 @@ Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, si case Label::kTypeGlobal: if (ASMJIT_UNLIKELY(parentId != Globals::kInvalidId)) - return DebugUtils::errored(kErrorNonLocalLabelCantHaveParent); + return DebugUtils::errored(kErrorNonLocalLabelCannotHaveParent); break; @@ -591,7 +573,7 @@ Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, si // Don't allow to insert duplicates. Local labels allow duplicates that have // different id, this is already accomplished by having a different hashes // between the same label names having different parent labels. - LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode)); + LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode, parentId)); if (ASMJIT_UNLIKELY(le)) return DebugUtils::errored(kErrorLabelAlreadyDefined); @@ -610,7 +592,7 @@ Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, si le->_hashCode = hashCode; le->_setId(labelId); le->_type = uint8_t(type); - le->_parentId = Globals::kInvalidId; + le->_parentId = parentId; le->_offset = 0; ASMJIT_PROPAGATE(le->_name.setData(&_zone, name, nameSize)); @@ -622,13 +604,14 @@ Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, si } uint32_t CodeHolder::labelIdByName(const char* name, size_t nameSize, uint32_t parentId) noexcept { - // TODO: Finalize - parent id is not used here? - DebugUtils::unused(parentId); - uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize); - if (ASMJIT_UNLIKELY(!nameSize)) return 0; + if (ASMJIT_UNLIKELY(!nameSize)) + return 0; + + if (parentId != Globals::kInvalidId) + hashCode ^= parentId; - LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode)); + LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode, parentId)); return le ? le->id() : uint32_t(Globals::kInvalidId); } @@ -906,7 +889,6 @@ size_t CodeHolder::codeSize() const noexcept { } } - // TODO: Not nice, maybe changing `codeSize()` to return `uint64_t` instead? if ((sizeof(uint64_t) > sizeof(size_t) && offset > SIZE_MAX) || of) return SIZE_MAX; @@ -918,8 +900,8 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { if (ASMJIT_UNLIKELY(baseAddress == Globals::kNoBaseAddress)) return DebugUtils::errored(kErrorInvalidArgument); - _codeInfo.setBaseAddress(baseAddress); - uint32_t gpSize = _codeInfo.gpSize(); + _baseAddress = baseAddress; + uint32_t addressSize = _environment.registerSize(); Section* addressTableSection = _addressTableSection; uint32_t addressTableEntryCount = 0; @@ -980,7 +962,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { case RelocEntry::kTypeAbsToRel: { value -= baseAddress + sectionOffset + sourceOffset + regionSize; - if (gpSize > 4 && !Support::isInt32(int64_t(value))) + if (addressSize > 4 && !Support::isInt32(int64_t(value))) return DebugUtils::errored(kErrorRelocOffsetOutOfRange); break; } @@ -1003,7 +985,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { if (!atEntry->hasAssignedSlot()) atEntry->_slot = addressTableEntryCount++; - size_t atEntryIndex = size_t(atEntry->slot()) * gpSize; + size_t atEntryIndex = size_t(atEntry->slot()) * addressSize; uint64_t addrSrc = sectionOffset + sourceOffset + regionSize; uint64_t addrDst = addressTableSection->offset() + uint64_t(atEntryIndex); @@ -1064,7 +1046,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { // Fixup the virtual size of the address table if it's the last section. if (_sections.last() == addressTableSection) { - size_t addressTableSize = addressTableEntryCount * gpSize; + size_t addressTableSize = addressTableEntryCount * addressSize; addressTableSection->_buffer._size = addressTableSize; addressTableSection->_virtualSize = addressTableSize; } @@ -1072,7 +1054,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { return kErrorOk; } -Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t options) noexcept { +Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t copyOptions) noexcept { if (ASMJIT_UNLIKELY(!isSectionValid(sectionId))) return DebugUtils::errored(kErrorInvalidSection); @@ -1084,7 +1066,7 @@ Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, memcpy(dst, section->data(), bufferSize); - if (bufferSize < dstSize && (options & kCopyWithPadding)) { + if (bufferSize < dstSize && (copyOptions & kCopyPadSectionBuffer)) { size_t paddingSize = dstSize - bufferSize; memset(static_cast<uint8_t*>(dst) + bufferSize, 0, paddingSize); } @@ -1092,7 +1074,7 @@ Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, return kErrorOk; } -Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t options) noexcept { +Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOptions) noexcept { size_t end = 0; for (Section* section : _sections) { if (section->offset() > dstSize) @@ -1108,7 +1090,7 @@ Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t options) size_t paddingSize = 0; memcpy(dstTarget, section->data(), bufferSize); - if ((options & kCopyWithPadding) && bufferSize < section->virtualSize()) { + if ((copyOptions & kCopyPadSectionBuffer) && bufferSize < section->virtualSize()) { paddingSize = Support::min<size_t>(dstSize - offset, size_t(section->virtualSize())) - bufferSize; memset(dstTarget + bufferSize, 0, paddingSize); } @@ -1116,8 +1098,9 @@ Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t options) end = Support::max(end, offset + bufferSize + paddingSize); } - // TODO: `end` is not used atm, we need an option to also pad anything beyond - // the code in case that the destination was much larger (for example page-size). + if (end < dstSize && (copyOptions & kCopyPadTargetBuffer)) { + memset(static_cast<uint8_t*>(dst) + end, 0, dstSize - end); + } return kErrorOk; } diff --git a/3rdparty/asmjit/src/asmjit/core/codeholder.h b/3rdparty/asmjit/src/asmjit/core/codeholder.h index 5f6a21d6241..9b3466dbb58 100644 --- a/3rdparty/asmjit/src/asmjit/core/codeholder.h +++ b/3rdparty/asmjit/src/asmjit/core/codeholder.h @@ -25,7 +25,9 @@ #define ASMJIT_CORE_CODEHOLDER_H_INCLUDED #include "../core/arch.h" +#include "../core/codebuffer.h" #include "../core/datatypes.h" +#include "../core/errorhandler.h" #include "../core/operand.h" #include "../core/string.h" #include "../core/support.h" @@ -56,126 +58,14 @@ class Logger; //! Align mode. enum AlignMode : uint32_t { - kAlignCode = 0, //!< Align executable code. - kAlignData = 1, //!< Align non-executable code. - kAlignZero = 2, //!< Align by a sequence of zeros. - kAlignCount = 3 //!< Count of alignment modes. -}; - -// ============================================================================ -// [asmjit::ErrorHandler] -// ============================================================================ - -//! Error handler can be used to override the default behavior of error handling -//! available to all classes that inherit `BaseEmitter`. -//! -//! Override `ErrorHandler::handleError()` to implement your own error handler. -class ASMJIT_VIRTAPI ErrorHandler { -public: - ASMJIT_BASE_CLASS(ErrorHandler) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Creates a new `ErrorHandler` instance. - ASMJIT_API ErrorHandler() noexcept; - //! Destroys the `ErrorHandler` instance. - ASMJIT_API virtual ~ErrorHandler() noexcept; - - // -------------------------------------------------------------------------- - // [Handle Error] - // -------------------------------------------------------------------------- - - //! Error handler (must be reimplemented). - //! - //! Error handler is called after an error happened and before it's propagated - //! to the caller. There are multiple ways how the error handler can be used: - //! - //! 1. User-based error handling without throwing exception or using C's - //! `longjmp()`. This is for users that don't use exceptions and want - //! customized error handling. - //! - //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely - //! exception-safe, but you can throw exception from your error handler if - //! this way is the preferred way of handling errors in your project. - //! - //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts - //! `BaseEmitter` to a consistent state before calling `handleError()` - //! so `longjmp()` can be used without any issues to cancel the code - //! generation if an error occurred. There is no difference between - //! exceptions and `longjmp()` from AsmJit's perspective, however, - //! never jump outside of `CodeHolder` and `BaseEmitter` scope as you - //! would leak memory. - virtual void handleError(Error err, const char* message, BaseEmitter* origin) = 0; -}; - -// ============================================================================ -// [asmjit::CodeBuffer] -// ============================================================================ - -//! Code or data buffer. -struct CodeBuffer { - //! The content of the buffer (data). - uint8_t* _data; - //! Number of bytes of `data` used. - size_t _size; - //! Buffer capacity (in bytes). - size_t _capacity; - //! Buffer flags. - uint32_t _flags; - - enum Flags : uint32_t { - //! Buffer is external (not allocated by asmjit). - kFlagIsExternal = 0x00000001u, - //! Buffer is fixed (cannot be reallocated). - kFlagIsFixed = 0x00000002u - }; - - //! \name Overloaded Operators - //! \{ - - inline uint8_t& operator[](size_t index) noexcept { - ASMJIT_ASSERT(index < _size); - return _data[index]; - } - - inline const uint8_t& operator[](size_t index) const noexcept { - ASMJIT_ASSERT(index < _size); - return _data[index]; - } - - //! \} - - //! \name Accessors - //! \{ - - inline uint32_t flags() const noexcept { return _flags; } - inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } - - inline bool isAllocated() const noexcept { return _data != nullptr; } - inline bool isFixed() const noexcept { return hasFlag(kFlagIsFixed); } - inline bool isExternal() const noexcept { return hasFlag(kFlagIsExternal); } - - inline uint8_t* data() noexcept { return _data; } - inline const uint8_t* data() const noexcept { return _data; } - - inline bool empty() const noexcept { return !_size; } - inline size_t size() const noexcept { return _size; } - inline size_t capacity() const noexcept { return _capacity; } - - //! \} - - //! \name Iterators - //! \{ - - inline uint8_t* begin() noexcept { return _data; } - inline const uint8_t* begin() const noexcept { return _data; } - - inline uint8_t* end() noexcept { return _data + _size; } - inline const uint8_t* end() const noexcept { return _data + _size; } - - //! \} + //! Align executable code. + kAlignCode = 0, + //! Align non-executable code. + kAlignData = 1, + //! Align by a sequence of zeros. + kAlignZero = 2, + //! Count of alignment modes. + kAlignCount = 3 }; // ============================================================================ @@ -204,31 +94,48 @@ public: //! Section flags. enum Flags : uint32_t { - kFlagExec = 0x00000001u, //!< Executable (.text sections). - kFlagConst = 0x00000002u, //!< Read-only (.text and .data sections). - kFlagZero = 0x00000004u, //!< Zero initialized by the loader (BSS). - kFlagInfo = 0x00000008u, //!< Info / comment flag. - kFlagImplicit = 0x80000000u //!< Section created implicitly and can be deleted by `Target`. + //! Executable (.text sections). + kFlagExec = 0x00000001u, + //! Read-only (.text and .data sections). + kFlagConst = 0x00000002u, + //! Zero initialized by the loader (BSS). + kFlagZero = 0x00000004u, + //! Info / comment flag. + kFlagInfo = 0x00000008u, + //! Section created implicitly and can be deleted by \ref Target. + kFlagImplicit = 0x80000000u }; //! \name Accessors //! \{ + //! Returns the section id. inline uint32_t id() const noexcept { return _id; } + //! Returns the section name, as a null terminated string. inline const char* name() const noexcept { return _name.str; } + //! Returns the section data. inline uint8_t* data() noexcept { return _buffer.data(); } + //! \overload inline const uint8_t* data() const noexcept { return _buffer.data(); } + //! Returns the section flags, see \ref Flags. inline uint32_t flags() const noexcept { return _flags; } + //! Tests whether the section has the given `flag`. inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + //! Adds `flags` to the section flags. inline void addFlags(uint32_t flags) noexcept { _flags |= flags; } + //! Removes `flags` from the section flags. inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } + //! Returns the minimum section alignment inline uint32_t alignment() const noexcept { return _alignment; } + //! Sets the minimum section alignment inline void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; } + //! Returns the section offset, relative to base. inline uint64_t offset() const noexcept { return _offset; } + //! Set the section offset. inline void setOffset(uint64_t offset) noexcept { _offset = offset; } //! Returns the virtual size of the section. @@ -277,46 +184,73 @@ struct LabelLink { // [asmjit::Expression] // ============================================================================ +//! Expression node that can reference constants, labels, and another expressions. struct Expression { + //! Operation type. enum OpType : uint8_t { + //! Addition. kOpAdd = 0, + //! Subtraction. kOpSub = 1, + //! Multiplication kOpMul = 2, + //! Logical left shift. kOpSll = 3, + //! Logical right shift. kOpSrl = 4, + //! Arithmetic right shift. kOpSra = 5 }; + //! Type of \ref Value. enum ValueType : uint8_t { + //! No value or invalid. kValueNone = 0, + //! Value is 64-bit unsigned integer (constant). kValueConstant = 1, + //! Value is \ref LabelEntry, which references a \ref Label. kValueLabel = 2, + //! Value is \ref Expression kValueExpression = 3 }; + //! Expression value. union Value { + //! Constant. uint64_t constant; + //! Pointer to another expression. Expression* expression; + //! Poitner to \ref LabelEntry. LabelEntry* label; }; + //! Operation type. uint8_t opType; + //! Value types of \ref value. uint8_t valueType[2]; + //! Reserved for future use, should be initialized to zero. uint8_t reserved[5]; + //! Expression left and right values. Value value[2]; + //! Resets the whole expression. + //! + //! Changes both values to \ref kValueNone. inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + //! Sets the value type at `index` to \ref kValueConstant and its content to `constant`. inline void setValueAsConstant(size_t index, uint64_t constant) noexcept { valueType[index] = kValueConstant; value[index].constant = constant; } - inline void setValueAsLabel(size_t index, LabelEntry* label) noexcept { + //! Sets the value type at `index` to \ref kValueLabel and its content to `labelEntry`. + inline void setValueAsLabel(size_t index, LabelEntry* labelEntry) noexcept { valueType[index] = kValueLabel; - value[index].label = label; + value[index].label = labelEntry; } + //! Sets the value type at `index` to \ref kValueExpression and its content to `expression`. inline void setValueAsExpression(size_t index, Expression* expression) noexcept { valueType[index] = kValueLabel; value[index].expression = expression; @@ -510,11 +444,14 @@ struct RelocEntry { // [asmjit::AddressTableEntry] // ============================================================================ +//! Entry in an address table. class AddressTableEntry : public ZoneTreeNodeT<AddressTableEntry> { public: ASMJIT_NONCOPYABLE(AddressTableEntry) + //! Address. uint64_t _address; + //! Slot. uint32_t _slot; //! \name Construction & Destruction @@ -547,22 +484,24 @@ public: // [asmjit::CodeHolder] // ============================================================================ -//! Contains basic information about the target architecture plus its settings, -//! and holds code & data (including sections, labels, and relocation information). -//! CodeHolder can store both binary and intermediate representation of assembly, -//! which can be generated by `BaseAssembler` and/or `BaseBuilder`. +//! Contains basic information about the target architecture and its options. +//! +//! In addition, it holds assembled code & data (including sections, labels, and +//! relocation information). `CodeHolder` can store both binary and intermediate +//! representation of assembly, which can be generated by \ref BaseAssembler, +//! \ref BaseBuilder, and \ref BaseCompiler //! -//! \note `CodeHolder` has ability to attach an `ErrorHandler`, however, the -//! error handler is not triggered by `CodeHolder` itself, it's only used by -//! emitters attached to `CodeHolder`. +//! \note `CodeHolder` has an ability to attach an \ref ErrorHandler, however, +//! the error handler is not triggered by `CodeHolder` itself, it's instead +//! propagated to all emitters that attach to it. class CodeHolder { public: ASMJIT_NONCOPYABLE(CodeHolder) - //! Basic information about the code (architecture and other info). - CodeInfo _codeInfo; - //! Emitter options, propagated to all emitters when changed. - uint32_t _emitterOptions; + //! Environment information. + Environment _environment; + //! Base address or \ref Globals::kNoBaseAddress. + uint64_t _baseAddress; //! Attached `Logger`, used by all consumers. Logger* _logger; @@ -574,7 +513,7 @@ public: //! Zone allocator, used to manage internal containers. ZoneAllocator _allocator; - //! Attached code emitters. + //! Attached emitters. ZoneVector<BaseEmitter*> _emitters; //! Section entries. ZoneVector<Section*> _sections; @@ -592,6 +531,25 @@ public: //! Address table entries. ZoneTree<AddressTableEntry> _addressTableEntries; + //! Options that can be used with \ref copySectionData() and \ref copyFlattenedData(). + enum CopyOptions : uint32_t { + //! If virtual size of a section is greater than the size of its \ref CodeBuffer + //! then all bytes between the buffer size and virtual size will be zeroed. + //! If this option is not set then those bytes would be left as is, which + //! means that if the user didn't initialize them they would have a previous + //! content, which may be unwanted. + kCopyPadSectionBuffer = 0x00000001u, + +#ifndef ASMJIT_NO_DEPRECATED + kCopyWithPadding = kCopyPadSectionBuffer, +#endif // !ASMJIT_NO_DEPRECATED + + //! Zeroes the target buffer if the flattened data is less than the destination + //! size. This option works only with \ref copyFlattenedData() as it processes + //! multiple sections. It is ignored by \ref copySectionData(). + kCopyPadTargetBuffer = 0x00000002u + }; + //! \name Construction & Destruction //! \{ @@ -600,10 +558,13 @@ public: //! Destroys the CodeHolder. ASMJIT_API ~CodeHolder() noexcept; - inline bool isInitialized() const noexcept { return _codeInfo.isInitialized(); } + //! Tests whether the `CodeHolder` has been initialized. + //! + //! Emitters can be only attached to initialized `CodeHolder` instances. + inline bool isInitialized() const noexcept { return _environment.isInitialized(); } - //! Initializes CodeHolder to hold code described by `codeInfo`. - ASMJIT_API Error init(const CodeInfo& info) noexcept; + //! Initializes CodeHolder to hold code described by code `info`. + ASMJIT_API Error init(const Environment& environment, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept; //! Detaches all code-generators attached and resets the `CodeHolder`. ASMJIT_API void reset(uint32_t resetPolicy = Globals::kResetSoft) noexcept; @@ -622,65 +583,62 @@ public: //! \name Allocators //! \{ + //! Returns the allocator that the `CodeHolder` uses. + //! + //! \note This should be only used for AsmJit's purposes. Code holder uses + //! arena allocator to allocate everything, so anything allocated through + //! this allocator will be invalidated by \ref CodeHolder::reset() or by + //! CodeHolder's destructor. inline ZoneAllocator* allocator() const noexcept { return const_cast<ZoneAllocator*>(&_allocator); } //! \} - //! \name Code Emitter + //! \name Code & Architecture //! \{ - inline const ZoneVector<BaseEmitter*>& emitters() const noexcept { return _emitters; } + //! Returns the target environment information, see \ref Environment. + inline const Environment& environment() const noexcept { return _environment; } - //! Returns global emitter options, internally propagated to all attached emitters. - inline uint32_t emitterOptions() const noexcept { return _emitterOptions; } + //! Returns the target architecture. + inline uint32_t arch() const noexcept { return environment().arch(); } + //! Returns the target sub-architecture. + inline uint32_t subArch() const noexcept { return environment().subArch(); } - //! Enables the given global emitter `options` and propagates the resulting - //! options to all attached emitters. - ASMJIT_API void addEmitterOptions(uint32_t options) noexcept; - - //! Disables the given global emitter `options` and propagates the resulting - //! options to all attached emitters. - ASMJIT_API void clearEmitterOptions(uint32_t options) noexcept; + //! Tests whether a static base-address is set. + inline bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; } + //! Returns a static base-address or \ref Globals::kNoBaseAddress, if not set. + inline uint64_t baseAddress() const noexcept { return _baseAddress; } //! \} - //! \name Code & Architecture + //! \name Emitters //! \{ - //! Returns the target architecture information, see `ArchInfo`. - inline const ArchInfo& archInfo() const noexcept { return _codeInfo.archInfo(); } - //! Returns the target code information, see `CodeInfo`. - inline const CodeInfo& codeInfo() const noexcept { return _codeInfo; } - - //! Returns the target architecture id. - inline uint32_t archId() const noexcept { return archInfo().archId(); } - //! Returns the target architecture sub-id. - inline uint32_t archSubId() const noexcept { return archInfo().archSubId(); } - - //! Tests whether a static base-address is set. - inline bool hasBaseAddress() const noexcept { return _codeInfo.hasBaseAddress(); } - //! Returns a static base-address (uint64_t). - inline uint64_t baseAddress() const noexcept { return _codeInfo.baseAddress(); } + //! Returns a vector of attached emitters. + inline const ZoneVector<BaseEmitter*>& emitters() const noexcept { return _emitters; } //! \} - //! \name Logging & Error Handling + //! \name Logging //! \{ - //! Returns the attached logger. + //! Returns the attached logger, see \ref Logger. inline Logger* logger() const noexcept { return _logger; } //! Attaches a `logger` to CodeHolder and propagates it to all attached emitters. ASMJIT_API void setLogger(Logger* logger) noexcept; //! Resets the logger to none. inline void resetLogger() noexcept { setLogger(nullptr); } - //! Tests whether the global error handler is attached. + //! \name Error Handling + //! \{ + + //! Tests whether the CodeHolder has an attached error handler, see \ref ErrorHandler. inline bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; } - //! Returns the global error handler. + //! Returns the attached error handler. inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; } - //! Sets the global error handler. - inline void setErrorHandler(ErrorHandler* handler) noexcept { _errorHandler = handler; } - //! Resets the global error handler to none. + //! Attach an error handler to this `CodeHolder`. + ASMJIT_API void setErrorHandler(ErrorHandler* errorHandler) noexcept; + //! Resets the error handler to none. inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); } //! \} @@ -688,7 +646,16 @@ public: //! \name Code Buffer //! \{ + //! Makes sure that at least `n` bytes can be added to CodeHolder's buffer `cb`. + //! + //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the + //! behavior of the function is undefined. ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept; + + //! Reserves the size of `cb` to at least `n` bytes. + //! + //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the + //! behavior of the function is undefined. ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept; //! \} @@ -719,7 +686,7 @@ public: //! Returns '.text' section (section that commonly represents code). //! - //! \note Text section is always the first section in `CodeHolder::sections()` array. + //! \note Text section is always the first section in \ref CodeHolder::sections() array. inline Section* textSection() const noexcept { return _sections[0]; } //! Tests whether '.addrtab' section exists. @@ -729,6 +696,8 @@ public: //! //! This section is used exclusively by AsmJit to store absolute 64-bit //! addresses that cannot be encoded in instructions like 'jmp' or 'call'. + //! + //! \note This section is created on demand, the returned pointer can be null. inline Section* addressTableSection() const noexcept { return _addressTableSection; } //! Ensures that '.addrtab' section exists (creates it if it doesn't) and @@ -825,18 +794,38 @@ public: //! Returns `Error`, does not report error to `ErrorHandler`. ASMJIT_API Error newLabelEntry(LabelEntry** entryOut) noexcept; - //! Creates a new named label label-type `type`. + //! Creates a new named \ref LabelEntry of the given label `type`. //! - //! Returns `Error`, does not report a possible error to `ErrorHandler`. + //! \param entryOut Where to store the created \ref LabelEntry. + //! \param name The name of the label. + //! \param nameSize The length of `name` argument, or `SIZE_MAX` if `name` is + //! a null terminated string, which means that the `CodeHolder` will + //! use `strlen()` to determine the length. + //! \param type The type of the label to create, see \ref Label::LabelType. + //! \param parentId Parent id of a local label, otherwise it must be + //! \ref Globals::kInvalidId. + //! + //! \retval Always returns \ref Error, does not report a possible error to + //! the attached \ref ErrorHandler. + //! + //! AsmJit has a support for local labels (\ref Label::kTypeLocal) which + //! require a parent label id (parentId). The names of local labels can + //! conflict with names of other local labels that have a different parent. ASMJIT_API Error newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, uint32_t type, uint32_t parentId = Globals::kInvalidId) noexcept; - //! Returns a label id by name. - ASMJIT_API uint32_t labelIdByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept; - + //! Returns a label by name. + //! + //! If the named label doesn't a default constructed \ref Label is returned, + //! which has its id set to \ref Globals::kInvalidId. inline Label labelByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept { return Label(labelIdByName(name, nameSize, parentId)); } + //! Returns a label id by name. + //! + //! If the named label doesn't exist \ref Globals::kInvalidId is returned. + ASMJIT_API uint32_t labelIdByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept; + //! Tests whether there are any unresolved label links. inline bool hasUnresolvedLinks() const noexcept { return _unresolvedLinkCount != 0; } //! Returns the number of label links, which are unresolved. @@ -903,24 +892,34 @@ public: //! \note This should never be called more than once. ASMJIT_API Error relocateToBase(uint64_t baseAddress) noexcept; - //! Options that can be used with \ref copySectionData(). - enum CopyOptions : uint32_t { - //! If virtual size of the section is larger than the size of its buffer - //! then all bytes between buffer size and virtual size will be zeroed. - kCopyWithPadding = 0x1 - }; - //! Copies a single section into `dst`. - ASMJIT_API Error copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t options = 0) noexcept; + ASMJIT_API Error copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t copyOptions = 0) noexcept; //! Copies all sections into `dst`. //! //! This should only be used if the data was flattened and there are no gaps //! between the sections. The `dstSize` is always checked and the copy will //! never write anything outside the provided buffer. - ASMJIT_API Error copyFlattenedData(void* dst, size_t dstSize, uint32_t options = 0) noexcept; + ASMJIT_API Error copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOptions = 0) noexcept; //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use 'CodeHolder::init(const Environment& environment, uint64_t baseAddress)' instead") + inline Error init(const CodeInfo& codeInfo) noexcept { return init(codeInfo._environment, codeInfo._baseAddress); } + + ASMJIT_DEPRECATED("Use nevironment() instead") + inline CodeInfo codeInfo() const noexcept { return CodeInfo(_environment, _baseAddress); } + + ASMJIT_DEPRECATED("Use BaseEmitter::encodingOptions() - this function always returns zero") + inline uint32_t emitterOptions() const noexcept { return 0; } + + ASMJIT_DEPRECATED("Use BaseEmitter::addEncodingOptions() - this function does nothing") + inline void addEmitterOptions(uint32_t options) noexcept { DebugUtils::unused(options); } + + ASMJIT_DEPRECATED("Use BaseEmitter::clearEncodingOptions() - this function does nothing") + inline void clearEmitterOptions(uint32_t options) noexcept { DebugUtils::unused(options); } +#endif // !ASMJIT_NO_DEPRECATED }; //! \} diff --git a/3rdparty/asmjit/src/asmjit/core/compiler.cpp b/3rdparty/asmjit/src/asmjit/core/compiler.cpp index 13dbf54300a..28bc93f29f2 100644 --- a/3rdparty/asmjit/src/asmjit/core/compiler.cpp +++ b/3rdparty/asmjit/src/asmjit/core/compiler.cpp @@ -27,7 +27,7 @@ #include "../core/assembler.h" #include "../core/compiler.h" #include "../core/cpuinfo.h" -#include "../core/logging.h" +#include "../core/logger.h" #include "../core/rapass_p.h" #include "../core/rastack_p.h" #include "../core/support.h" @@ -40,12 +40,12 @@ ASMJIT_BEGIN_NAMESPACE // ============================================================================ class GlobalConstPoolPass : public Pass { - ASMJIT_NONCOPYABLE(GlobalConstPoolPass) typedef Pass Base; + ASMJIT_NONCOPYABLE(GlobalConstPoolPass) GlobalConstPoolPass() noexcept : Pass("GlobalConstPoolPass") {} - Error run(Zone* zone, Logger* logger) noexcept override { + Error run(Zone* zone, Logger* logger) override { DebugUtils::unused(zone, logger); // Flush the global constant pool. @@ -54,15 +54,16 @@ class GlobalConstPoolPass : public Pass { compiler->addAfter(compiler->_globalConstPool, compiler->lastNode()); compiler->_globalConstPool = nullptr; } + return kErrorOk; } }; // ============================================================================ -// [asmjit::FuncCallNode - Arg / Ret] +// [asmjit::InvokeNode - Arg / Ret] // ============================================================================ -bool FuncCallNode::_setArg(uint32_t i, const Operand_& op) noexcept { +bool InvokeNode::_setArg(uint32_t i, const Operand_& op) noexcept { if ((i & ~kFuncArgHi) >= _funcDetail.argCount()) return false; @@ -70,7 +71,7 @@ bool FuncCallNode::_setArg(uint32_t i, const Operand_& op) noexcept { return true; } -bool FuncCallNode::_setRet(uint32_t i, const Operand_& op) noexcept { +bool InvokeNode::_setRet(uint32_t i, const Operand_& op) noexcept { if (i >= 2) return false; @@ -90,72 +91,81 @@ BaseCompiler::BaseCompiler() noexcept _localConstPool(nullptr), _globalConstPool(nullptr) { - _type = kTypeCompiler; + _emitterType = uint8_t(kTypeCompiler); + _validationFlags = uint8_t(InstAPI::kValidationFlagVirtRegs); } BaseCompiler::~BaseCompiler() noexcept {} // ============================================================================ -// [asmjit::BaseCompiler - Function API] +// [asmjit::BaseCompiler - Function Management] // ============================================================================ -FuncNode* BaseCompiler::newFunc(const FuncSignature& sign) noexcept { - Error err; - - FuncNode* func = newNodeT<FuncNode>(); - if (ASMJIT_UNLIKELY(!func)) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } +Error BaseCompiler::_newFuncNode(FuncNode** out, const FuncSignature& signature) { + *out = nullptr; - err = registerLabelNode(func); - if (ASMJIT_UNLIKELY(err)) { - // TODO: Calls reportError, maybe rethink noexcept? - reportError(err); - return nullptr; - } - - // Create helper nodes. - func->_exitNode = newLabelNode(); - func->_end = newNodeT<SentinelNode>(SentinelNode::kSentinelFuncEnd); - - if (ASMJIT_UNLIKELY(!func->_exitNode || !func->_end)) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } + // Create FuncNode together with all the required surrounding nodes. + FuncNode* funcNode; + ASMJIT_PROPAGATE(_newNodeT<FuncNode>(&funcNode)); + ASMJIT_PROPAGATE(_newLabelNode(&funcNode->_exitNode)); + ASMJIT_PROPAGATE(_newNodeT<SentinelNode>(&funcNode->_end, SentinelNode::kSentinelFuncEnd)); - // Initialize the function info. - err = func->detail().init(sign); - if (ASMJIT_UNLIKELY(err)) { - reportError(err); - return nullptr; - } + // Initialize the function's detail info. + Error err = funcNode->detail().init(signature, environment()); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); // If the Target guarantees greater stack alignment than required by the // calling convention then override it as we can prevent having to perform // dynamic stack alignment - if (func->_funcDetail._callConv.naturalStackAlignment() < _codeInfo.stackAlignment()) - func->_funcDetail._callConv.setNaturalStackAlignment(_codeInfo.stackAlignment()); + uint32_t environmentStackAlignment = _environment.stackAlignment(); + + if (funcNode->_funcDetail._callConv.naturalStackAlignment() < environmentStackAlignment) + funcNode->_funcDetail._callConv.setNaturalStackAlignment(environmentStackAlignment); // Initialize the function frame. - err = func->_frame.init(func->_funcDetail); - if (ASMJIT_UNLIKELY(err)) { - reportError(err); - return nullptr; - } + err = funcNode->_frame.init(funcNode->_funcDetail); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); // Allocate space for function arguments. - func->_args = nullptr; - if (func->argCount() != 0) { - func->_args = _allocator.allocT<VirtReg*>(func->argCount() * sizeof(VirtReg*)); - if (ASMJIT_UNLIKELY(!func->_args)) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } - - memset(func->_args, 0, func->argCount() * sizeof(VirtReg*)); + funcNode->_args = nullptr; + if (funcNode->argCount() != 0) { + funcNode->_args = _allocator.allocT<VirtReg*>(funcNode->argCount() * sizeof(VirtReg*)); + if (ASMJIT_UNLIKELY(!funcNode->_args)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + memset(funcNode->_args, 0, funcNode->argCount() * sizeof(VirtReg*)); } - return func; + ASMJIT_PROPAGATE(registerLabelNode(funcNode)); + + *out = funcNode; + return kErrorOk; +} + +Error BaseCompiler::_addFuncNode(FuncNode** out, const FuncSignature& signature) { + ASMJIT_PROPAGATE(_newFuncNode(out, signature)); + addFunc(*out); + return kErrorOk; +} + +Error BaseCompiler::_newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) { + uint32_t opCount = !o1.isNone() ? 2u : !o0.isNone() ? 1u : 0u; + FuncRetNode* node; + + ASMJIT_PROPAGATE(_newNodeT<FuncRetNode>(&node)); + node->setOpCount(opCount); + node->setOp(0, o0); + node->setOp(1, o1); + node->resetOpRange(2, node->opCapacity()); + + *out = node; + return kErrorOk; +} + +Error BaseCompiler::_addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) { + ASMJIT_PROPAGATE(_newRetNode(out, o0, o1)); + addNode(*out); + return kErrorOk; } FuncNode* BaseCompiler::addFunc(FuncNode* func) { @@ -165,25 +175,15 @@ FuncNode* BaseCompiler::addFunc(FuncNode* func) { addNode(func); // Function node. BaseNode* prev = cursor(); // {CURSOR}. addNode(func->exitNode()); // Function exit label. - addNode(func->endNode()); // Function end marker. + addNode(func->endNode()); // Function end sentinel. _setCursor(prev); return func; } -FuncNode* BaseCompiler::addFunc(const FuncSignature& sign) { - FuncNode* func = newFunc(sign); - - if (!func) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } - - return addFunc(func); -} - Error BaseCompiler::endFunc() { FuncNode* func = _func; + if (ASMJIT_UNLIKELY(!func)) return reportError(DebugUtils::errored(kErrorInvalidState)); @@ -199,6 +199,7 @@ Error BaseCompiler::endFunc() { SentinelNode* end = func->endNode(); setCursor(end); + return kErrorOk; } @@ -217,71 +218,43 @@ Error BaseCompiler::setArg(uint32_t argIndex, const BaseReg& r) { return kErrorOk; } -FuncRetNode* BaseCompiler::newRet(const Operand_& o0, const Operand_& o1) noexcept { - FuncRetNode* node = newNodeT<FuncRetNode>(); - if (!node) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } - - node->setOp(0, o0); - node->setOp(1, o1); - node->setOpCount(!o1.isNone() ? 2u : !o0.isNone() ? 1u : 0u); - - return node; -} - -FuncRetNode* BaseCompiler::addRet(const Operand_& o0, const Operand_& o1) noexcept { - FuncRetNode* node = newRet(o0, o1); - if (!node) return nullptr; - return addNode(node)->as<FuncRetNode>(); -} - // ============================================================================ -// [asmjit::BaseCompiler - Call] +// [asmjit::BaseCompiler - Function Invocation] // ============================================================================ -FuncCallNode* BaseCompiler::newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept { - FuncCallNode* node = newNodeT<FuncCallNode>(instId, 0u); - if (ASMJIT_UNLIKELY(!node)) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } +Error BaseCompiler::_newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + InvokeNode* node; + ASMJIT_PROPAGATE(_newNodeT<InvokeNode>(&node, instId, 0u)); node->setOpCount(1); node->setOp(0, o0); - node->resetOp(1); - node->resetOp(2); - node->resetOp(3); + node->resetOpRange(1, node->opCapacity()); - Error err = node->detail().init(sign); - if (ASMJIT_UNLIKELY(err)) { - reportError(err); - return nullptr; - } - - // If there are no arguments skip the allocation. - uint32_t nArgs = sign.argCount(); - if (!nArgs) return node; + Error err = node->detail().init(signature, environment()); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); - node->_args = static_cast<Operand*>(_allocator.alloc(nArgs * sizeof(Operand))); - if (!node->_args) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; + // Skip the allocation if there are no arguments. + uint32_t argCount = signature.argCount(); + if (argCount) { + node->_args = static_cast<Operand*>(_allocator.alloc(argCount * sizeof(Operand))); + if (!node->_args) + reportError(DebugUtils::errored(kErrorOutOfMemory)); + memset(node->_args, 0, argCount * sizeof(Operand)); } - memset(node->_args, 0, nArgs * sizeof(Operand)); - return node; + *out = node; + return kErrorOk; } -FuncCallNode* BaseCompiler::addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept { - FuncCallNode* node = newCall(instId, o0, sign); - if (!node) return nullptr; - return addNode(node)->as<FuncCallNode>(); +Error BaseCompiler::_addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + ASMJIT_PROPAGATE(_newInvokeNode(out, instId, o0, signature)); + addNode(*out); + return kErrorOk; } // ============================================================================ -// [asmjit::BaseCompiler - Vars] +// [asmjit::BaseCompiler - Virtual Registers] // ============================================================================ static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) { @@ -294,16 +267,19 @@ static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) { vReg->_name.setData(&self->_dataZone, buf, unsigned(size)); } -VirtReg* BaseCompiler::newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept { +Error BaseCompiler::newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signature, const char* name) { + *out = nullptr; uint32_t index = _vRegArray.size(); + if (ASMJIT_UNLIKELY(index >= uint32_t(Operand::kVirtIdCount))) - return nullptr; + return reportError(DebugUtils::errored(kErrorTooManyVirtRegs)); - if (_vRegArray.willGrow(&_allocator) != kErrorOk) - return nullptr; + if (ASMJIT_UNLIKELY(_vRegArray.willGrow(&_allocator) != kErrorOk)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); VirtReg* vReg = _vRegZone.allocZeroedT<VirtReg>(); - if (ASMJIT_UNLIKELY(!vReg)) return nullptr; + if (ASMJIT_UNLIKELY(!vReg)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); uint32_t size = Type::sizeOf(typeId); uint32_t alignment = Support::min<uint32_t>(size, 64); @@ -320,26 +296,28 @@ VirtReg* BaseCompiler::newVirtReg(uint32_t typeId, uint32_t signature, const cha #endif _vRegArray.appendUnsafe(vReg); - return vReg; + *out = vReg; + + return kErrorOk; } -Error BaseCompiler::_newReg(BaseReg& out, uint32_t typeId, const char* name) { +Error BaseCompiler::_newReg(BaseReg* out, uint32_t typeId, const char* name) { + out->reset(); + RegInfo regInfo; + Error err = ArchUtils::typeIdToRegInfo(arch(), typeId, &typeId, ®Info); - Error err = ArchUtils::typeIdToRegInfo(archId(), typeId, regInfo); - if (ASMJIT_UNLIKELY(err)) return reportError(err); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); - VirtReg* vReg = newVirtReg(typeId, regInfo.signature(), name); - if (ASMJIT_UNLIKELY(!vReg)) { - out.reset(); - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - } + VirtReg* vReg; + ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regInfo.signature(), name)); - out._initReg(regInfo.signature(), vReg->id()); + out->_initReg(regInfo.signature(), vReg->id()); return kErrorOk; } -Error BaseCompiler::_newRegFmt(BaseReg& out, uint32_t typeId, const char* fmt, ...) { +Error BaseCompiler::_newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...) { va_list ap; StringTmp<256> sb; @@ -350,7 +328,9 @@ Error BaseCompiler::_newRegFmt(BaseReg& out, uint32_t typeId, const char* fmt, . return _newReg(out, typeId, sb.data()); } -Error BaseCompiler::_newReg(BaseReg& out, const BaseReg& ref, const char* name) { +Error BaseCompiler::_newReg(BaseReg* out, const BaseReg& ref, const char* name) { + out->reset(); + RegInfo regInfo; uint32_t typeId; @@ -412,20 +392,18 @@ Error BaseCompiler::_newReg(BaseReg& out, const BaseReg& ref, const char* name) typeId = ref.type(); } - Error err = ArchUtils::typeIdToRegInfo(archId(), typeId, regInfo); - if (ASMJIT_UNLIKELY(err)) return reportError(err); + Error err = ArchUtils::typeIdToRegInfo(arch(), typeId, &typeId, ®Info); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); - VirtReg* vReg = newVirtReg(typeId, regInfo.signature(), name); - if (ASMJIT_UNLIKELY(!vReg)) { - out.reset(); - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - } + VirtReg* vReg; + ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regInfo.signature(), name)); - out._initReg(regInfo.signature(), vReg->id()); + out->_initReg(regInfo.signature(), vReg->id()); return kErrorOk; } -Error BaseCompiler::_newRegFmt(BaseReg& out, const BaseReg& ref, const char* fmt, ...) { +Error BaseCompiler::_newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...) { va_list ap; StringTmp<256> sb; @@ -436,7 +414,9 @@ Error BaseCompiler::_newRegFmt(BaseReg& out, const BaseReg& ref, const char* fmt return _newReg(out, ref, sb.data()); } -Error BaseCompiler::_newStack(BaseMem& out, uint32_t size, uint32_t alignment, const char* name) { +Error BaseCompiler::_newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name) { + out->reset(); + if (size == 0) return reportError(DebugUtils::errored(kErrorInvalidArgument)); @@ -449,22 +429,19 @@ Error BaseCompiler::_newStack(BaseMem& out, uint32_t size, uint32_t alignment, c if (alignment > 64) alignment = 64; - VirtReg* vReg = newVirtReg(0, 0, name); - if (ASMJIT_UNLIKELY(!vReg)) { - out.reset(); - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - } + VirtReg* vReg; + ASMJIT_PROPAGATE(newVirtReg(&vReg, 0, 0, name)); vReg->_virtSize = size; vReg->_isStack = true; vReg->_alignment = uint8_t(alignment); // Set the memory operand to GPD/GPQ and its id to VirtReg. - out = BaseMem(BaseMem::Decomposed { _gpRegInfo.type(), vReg->id(), BaseReg::kTypeNone, 0, 0, 0, BaseMem::kSignatureMemRegHomeFlag }); + *out = BaseMem(BaseMem::Decomposed { _gpRegInfo.type(), vReg->id(), BaseReg::kTypeNone, 0, 0, 0, BaseMem::kSignatureMemRegHomeFlag }); return kErrorOk; } -Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment) noexcept { +Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment) { if (!isVirtIdValid(virtId)) return DebugUtils::errored(kErrorInvalidVirtId); @@ -493,8 +470,10 @@ Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t new return kErrorOk; } -Error BaseCompiler::_newConst(BaseMem& out, uint32_t scope, const void* data, size_t size) { +Error BaseCompiler::_newConst(BaseMem* out, uint32_t scope, const void* data, size_t size) { + out->reset(); ConstPoolNode** pPool; + if (scope == ConstPool::kScopeLocal) pPool = &_localConstPool; else if (scope == ConstPool::kScopeGlobal) @@ -502,29 +481,26 @@ Error BaseCompiler::_newConst(BaseMem& out, uint32_t scope, const void* data, si else return reportError(DebugUtils::errored(kErrorInvalidArgument)); - ConstPoolNode* pool = *pPool; - if (!pool) { - pool = newConstPoolNode(); - if (ASMJIT_UNLIKELY(!pool)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - *pPool = pool; - } + if (!*pPool) + ASMJIT_PROPAGATE(_newConstPoolNode(pPool)); + ConstPoolNode* pool = *pPool; size_t off; Error err = pool->add(data, size, off); if (ASMJIT_UNLIKELY(err)) return reportError(err); - out = BaseMem(BaseMem::Decomposed { + *out = BaseMem(BaseMem::Decomposed { Label::kLabelTag, // Base type. - pool->id(), // Base id. + pool->labelId(), // Base id. 0, // Index type. 0, // Index id. int32_t(off), // Offset. uint32_t(size), // Size. 0 // Flags. }); + return kErrorOk; } @@ -553,38 +529,38 @@ void BaseCompiler::rename(const BaseReg& reg, const char* fmt, ...) { // [asmjit::BaseCompiler - Jump Annotations] // ============================================================================ -JumpNode* BaseCompiler::newJumpNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation) noexcept { - uint32_t opCount = 1; +Error BaseCompiler::newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation) { JumpNode* node = _allocator.allocT<JumpNode>(); + uint32_t opCount = 1; + if (ASMJIT_UNLIKELY(!node)) - return nullptr; + return reportError(DebugUtils::errored(kErrorOutOfMemory)); node = new(node) JumpNode(this, instId, instOptions, opCount, annotation); node->setOp(0, o0); - node->resetOps(opCount, JumpNode::kBaseOpCapacity); - return node; + node->resetOpRange(opCount, JumpNode::kBaseOpCapacity); + + *out = node; + return kErrorOk; } Error BaseCompiler::emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation) { - uint32_t options = instOptions() | globalInstOptions(); + uint32_t options = instOptions() | forcedInstOptions(); + RegOnly extra = extraReg(); const char* comment = inlineComment(); - JumpNode* node = newJumpNode(instId, options, o0, annotation); - resetInstOptions(); resetInlineComment(); + resetExtraReg(); - if (ASMJIT_UNLIKELY(!node)) { - resetExtraReg(); - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - } + JumpNode* node; + ASMJIT_PROPAGATE(newJumpNode(&node, instId, options, o0, annotation)); - node->setExtraReg(extraReg()); + node->setExtraReg(extra); if (comment) node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true))); addNode(node); - resetExtraReg(); return kErrorOk; } @@ -644,7 +620,7 @@ FuncPass::FuncPass(const char* name) noexcept // [asmjit::FuncPass - Run] // ============================================================================ -Error FuncPass::run(Zone* zone, Logger* logger) noexcept { +Error FuncPass::run(Zone* zone, Logger* logger) { BaseNode* node = cb()->firstNode(); if (!node) return kErrorOk; diff --git a/3rdparty/asmjit/src/asmjit/core/compiler.h b/3rdparty/asmjit/src/asmjit/core/compiler.h index 32b2a8bb271..71f89ec701e 100644 --- a/3rdparty/asmjit/src/asmjit/core/compiler.h +++ b/3rdparty/asmjit/src/asmjit/core/compiler.h @@ -51,7 +51,7 @@ class JumpAnnotation; class JumpNode; class FuncNode; class FuncRetNode; -class FuncCallNode; +class InvokeNode; //! \addtogroup asmjit_compiler //! \{ @@ -60,7 +60,7 @@ class FuncCallNode; // [asmjit::VirtReg] // ============================================================================ -//! Virtual register data (BaseCompiler). +//! Virtual register data, managed by \ref BaseCompiler. class VirtReg { public: ASMJIT_NONCOPYABLE(VirtReg) @@ -192,14 +192,18 @@ public: //! primarily designed for merging multiple parts of code into a function //! without worrying about registers and function calling conventions. //! -//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit -//! code at the same time. +//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and +//! 64-bit code generation within a single code base. //! //! BaseCompiler is based on BaseBuilder and contains all the features it //! provides. It means that the code it stores can be modified (removed, added, //! injected) and analyzed. When the code is finalized the compiler can emit //! the code into an Assembler to translate the abstract representation into a //! machine code. +//! +//! Check out architecture specific compilers for more details and examples: +//! +//! - \ref x86::Compiler - X86/X64 compiler implementation. class ASMJIT_VIRTAPI BaseCompiler : public BaseBuilder { public: ASMJIT_NONCOPYABLE(BaseCompiler) @@ -229,38 +233,80 @@ public: //! \} - //! \name Function API + //! \name Function Management //! \{ //! Returns the current function. inline FuncNode* func() const noexcept { return _func; } - //! Creates a new `FuncNode`. - ASMJIT_API FuncNode* newFunc(const FuncSignature& sign) noexcept; - //! Adds a function `node` to the stream. + //! Creates a new \ref FuncNode. + ASMJIT_API Error _newFuncNode(FuncNode** out, const FuncSignature& signature); + //! Creates a new \ref FuncNode adds it to the compiler. + ASMJIT_API Error _addFuncNode(FuncNode** out, const FuncSignature& signature); + + //! Creates a new \ref FuncRetNode. + ASMJIT_API Error _newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1); + //! Creates a new \ref FuncRetNode and adds it to the compiler. + ASMJIT_API Error _addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1); + + //! Creates a new \ref FuncNode with the given `signature` and returns it. + inline FuncNode* newFunc(const FuncSignature& signature) { + FuncNode* node; + _newFuncNode(&node, signature); + return node; + } + + //! Creates a new \ref FuncNode with the given `signature`, adds it to the + //! compiler by using the \ref addFunc(FuncNode*) overload, and returns it. + inline FuncNode* addFunc(const FuncSignature& signature) { + FuncNode* node; + _addFuncNode(&node, signature); + return node; + } + + //! Adds a function `node` to the instruction stream. ASMJIT_API FuncNode* addFunc(FuncNode* func); - //! Adds a new function. - ASMJIT_API FuncNode* addFunc(const FuncSignature& sign); //! Emits a sentinel that marks the end of the current function. ASMJIT_API Error endFunc(); //! Sets a function argument at `argIndex` to `reg`. ASMJIT_API Error setArg(uint32_t argIndex, const BaseReg& reg); - //! Creates a new `FuncRetNode`. - ASMJIT_API FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) noexcept; - //! Adds a new `FuncRetNode`. - ASMJIT_API FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) noexcept; + inline FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) { + FuncRetNode* node; + _newRetNode(&node, o0, o1); + return node; + } + + inline FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) { + FuncRetNode* node; + _addRetNode(&node, o0, o1); + return node; + } //! \} - //! \name Function Calls + //! \name Function Invocation //! \{ - //! Creates a new `FuncCallNode`. - ASMJIT_API FuncCallNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept; - //! Adds a new `FuncCallNode`. - ASMJIT_API FuncCallNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept; + //! Creates a new \ref InvokeNode. + ASMJIT_API Error _newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature); + //! Creates a new \ref InvokeNode and adds it to Compiler. + ASMJIT_API Error _addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature); + + //! Creates a new `InvokeNode`. + inline InvokeNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + InvokeNode* node; + _newInvokeNode(&node, instId, o0, signature); + return node; + } + + //! Adds a new `InvokeNode`. + inline InvokeNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + InvokeNode* node; + _addInvokeNode(&node, instId, o0, signature); + return node; + } //! \} @@ -268,13 +314,27 @@ public: //! \{ //! Creates a new virtual register representing the given `typeId` and `signature`. - ASMJIT_API VirtReg* newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept; + //! + //! \note This function is public, but it's not generally recommended to be used + //! by AsmJit users, use architecture-specific `newReg()` functionality instead + //! or functions like \ref _newReg() and \ref _newRegFmt(). + ASMJIT_API Error newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signature, const char* name); - ASMJIT_API Error _newReg(BaseReg& out, uint32_t typeId, const char* name = nullptr); - ASMJIT_API Error _newRegFmt(BaseReg& out, uint32_t typeId, const char* fmt, ...); + //! Creates a new virtual register of the given `typeId` and stores it to `out` operand. + ASMJIT_API Error _newReg(BaseReg* out, uint32_t typeId, const char* name = nullptr); - ASMJIT_API Error _newReg(BaseReg& out, const BaseReg& ref, const char* name = nullptr); - ASMJIT_API Error _newRegFmt(BaseReg& out, const BaseReg& ref, const char* fmt, ...); + //! Creates a new virtual register of the given `typeId` and stores it to `out` operand. + //! + //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments. + ASMJIT_API Error _newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...); + + //! Creates a new virtual register compatible with the provided reference register `ref`. + ASMJIT_API Error _newReg(BaseReg* out, const BaseReg& ref, const char* name = nullptr); + + //! Creates a new virtual register compatible with the provided reference register `ref`. + //! + //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments. + ASMJIT_API Error _newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...); //! Tests whether the given `id` is a valid virtual register id. inline bool isVirtIdValid(uint32_t id) const noexcept { @@ -286,14 +346,20 @@ public: return isVirtIdValid(reg.id()); } - //! Returns `VirtReg` associated with the given `id`. + //! Returns \ref VirtReg associated with the given `id`. inline VirtReg* virtRegById(uint32_t id) const noexcept { ASMJIT_ASSERT(isVirtIdValid(id)); return _vRegArray[Operand::virtIdToIndex(id)]; } - //! Returns `VirtReg` associated with the given `reg`. + + //! Returns \ref VirtReg associated with the given `reg`. inline VirtReg* virtRegByReg(const BaseReg& reg) const noexcept { return virtRegById(reg.id()); } - //! Returns `VirtReg` associated with the given `index`. + + //! Returns \ref VirtReg associated with the given virtual register `index`. + //! + //! \note This is not the same as virtual register id. The conversion between + //! id and its index is implemented by \ref Operand_::virtIdToIndex() and \ref + //! Operand_::indexToVirtId() functions. inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; } //! Returns an array of all virtual registers managed by the Compiler. @@ -302,13 +368,16 @@ public: //! \name Stack //! \{ - ASMJIT_API Error _newStack(BaseMem& out, uint32_t size, uint32_t alignment, const char* name = nullptr); + //! Creates a new stack of the given `size` and `alignment` and stores it to `out`. + //! + //! \note `name` can be used to give the stack a name, for debugging purposes. + ASMJIT_API Error _newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name = nullptr); //! Updates the stack size of a stack created by `_newStack()` by its `virtId`. - ASMJIT_API Error setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment = 0) noexcept; + ASMJIT_API Error setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment = 0); //! Updates the stack size of a stack created by `_newStack()`. - inline Error setStackSize(const BaseMem& mem, uint32_t newSize, uint32_t newAlignment = 0) noexcept { + inline Error setStackSize(const BaseMem& mem, uint32_t newSize, uint32_t newAlignment = 0) { return setStackSize(mem.id(), newSize, newAlignment); } @@ -317,7 +386,11 @@ public: //! \name Constants //! \{ - ASMJIT_API Error _newConst(BaseMem& out, uint32_t scope, const void* data, size_t size); + //! Creates a new constant of the given `scope` (see \ref ConstPool::Scope). + //! + //! This function adds a constant of the given `size` to the built-in \ref + //! ConstPool and stores the reference to that constant to the `out` operand. + ASMJIT_API Error _newConst(BaseMem* out, uint32_t scope, const void* data, size_t size); //! \} @@ -325,8 +398,6 @@ public: //! \{ //! Rename the given virtual register `reg` to a formatted string `fmt`. - //! - //! \note Only new name will appear in the logger. ASMJIT_API void rename(const BaseReg& reg, const char* fmt, ...); //! \} @@ -338,7 +409,7 @@ public: return _jumpAnnotations; } - ASMJIT_API JumpNode* newJumpNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation) noexcept; + ASMJIT_API Error newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation); ASMJIT_API Error emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation); //! Returns a new `JumpAnnotation` instance, which can be used to aggregate @@ -348,9 +419,12 @@ public: //! \} - // TODO: These should be removed - inline void alloc(BaseReg& reg) { DebugUtils::unused(reg); } - inline void spill(BaseReg& reg) { DebugUtils::unused(reg); } +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("alloc() has no effect, it will be removed in the future") + inline void alloc(BaseReg&) {} + ASMJIT_DEPRECATED("spill() has no effect, it will be removed in the future") + inline void spill(BaseReg&) {} +#endif // !ASMJIT_NO_DEPRECATED //! \name Events //! \{ @@ -365,26 +439,44 @@ public: // [asmjit::JumpAnnotation] // ============================================================================ +//! Jump annotation used to annotate jumps. +//! +//! \ref BaseCompiler allows to emit jumps where the target is either register +//! or memory operand. Such jumps cannot be trivially inspected, so instead of +//! doing heuristics AsmJit allows to annotate such jumps with possible targets. +//! Register allocator then use the annotation to construct control-flow, which +//! is then used by liveness analysis and other tools to prepare ground for +//! register allocation. class JumpAnnotation { public: ASMJIT_NONCOPYABLE(JumpAnnotation) + //! Compiler that owns this JumpAnnotation. BaseCompiler* _compiler; + //! Annotation identifier. uint32_t _annotationId; + //! Vector of label identifiers, see \ref labelIds(). ZoneVector<uint32_t> _labelIds; inline JumpAnnotation(BaseCompiler* compiler, uint32_t annotationId) noexcept : _compiler(compiler), _annotationId(annotationId) {} + //! Returns the compiler that owns this JumpAnnotation. inline BaseCompiler* compiler() const noexcept { return _compiler; } + //! Returns the annotation id. inline uint32_t annotationId() const noexcept { return _annotationId; } + //! Returns a vector of label identifiers that lists all targets of the jump. const ZoneVector<uint32_t>& labelIds() const noexcept { return _labelIds; } + //! Tests whether the given `label` is a target of this JumpAnnotation. inline bool hasLabel(const Label& label) const noexcept { return hasLabelId(label.id()); } + //! Tests whether the given `labelId` is a target of this JumpAnnotation. inline bool hasLabelId(uint32_t labelId) const noexcept { return _labelIds.contains(labelId); } + //! Adds the `label` to the list of targets of this JumpAnnotation. inline Error addLabel(const Label& label) noexcept { return addLabelId(label.id()); } + //! Adds the `labelId` to the list of targets of this JumpAnnotation. inline Error addLabelId(uint32_t labelId) noexcept { return _labelIds.append(&_compiler->_allocator, labelId); } }; @@ -418,8 +510,11 @@ public: //! \name Accessors //! \{ + //! Tests whether this JumpNode has associated a \ref JumpAnnotation. inline bool hasAnnotation() const noexcept { return _annotation != nullptr; } + //! Returns the \ref JumpAnnotation associated with this jump, or `nullptr`. inline JumpAnnotation* annotation() const noexcept { return _annotation; } + //! Sets the \ref JumpAnnotation associated with this jump to `annotation`. inline void setAnnotation(JumpAnnotation* annotation) noexcept { _annotation = annotation; } //! \} @@ -429,7 +524,51 @@ public: // [asmjit::FuncNode] // ============================================================================ -//! Function entry (BaseCompiler). +//! Function node represents a function used by \ref BaseCompiler. +//! +//! A function is composed of the following: +//! +//! - Function entry, \ref FuncNode acts as a label, so the entry is implicit. +//! To get the entry, simply use \ref FuncNode::label(), which is the same +//! as \ref LabelNode::label(). +//! +//! - Function exit, which is represented by \ref FuncNode::exitNode(). A +//! helper function \ref FuncNode::exitLabel() exists and returns an exit +//! label instead of node. +//! +//! - Function \ref FuncNode::endNode() sentinel. This node marks the end of +//! a function - there should be no code that belongs to the function after +//! this node, but the Compiler doesn't enforce that at the moment. +//! +//! - Function detail, see \ref FuncNode::detail(). +//! +//! - Function frame, see \ref FuncNode::frame(). +//! +//! - Function arguments mapped to virtual registers, see \ref FuncNode::args(). +//! +//! In a node list, the function and its body looks like the following: +//! +//! \code{.unparsed} +//! [...] - Anything before the function. +//! +//! [FuncNode] - Entry point of the function, acts as a label as well. +//! <Prolog> - Prolog inserted by the register allocator. +//! {...} - Function body - user code basically. +//! [ExitLabel] - Exit label +//! <Epilog> - Epilog inserted by the register allocator. +//! <Return> - Return inserted by the register allocator. +//! {...} - Can contain data or user code (error handling, special cases, ...). +//! [FuncEnd] - End sentinel +//! +//! [...] - Anything after the function. +//! \endcode +//! +//! When a function is added to the compiler by \ref BaseCompiler::addFunc() it +//! actually inserts 3 nodes (FuncNode, ExitLabel, and FuncEnd) and sets the +//! current cursor to be FuncNode. When \ref BaseCompiler::endFunc() is called +//! the cursor is set to FuncEnd. This guarantees that user can use ExitLabel +//! as a marker after additional code or data can be placed, and it's a common +//! practice. class FuncNode : public LabelNode { public: ASMJIT_NONCOPYABLE(FuncNode) @@ -438,7 +577,7 @@ public: FuncDetail _funcDetail; //! Function frame. FuncFrame _frame; - //! Function exit (label). + //! Function exit label. LabelNode* _exitNode; //! Function end (sentinel). SentinelNode* _end; @@ -510,7 +649,9 @@ public: _args[i] = nullptr; } + //! Returns function attributes. inline uint32_t attributes() const noexcept { return _frame.attributes(); } + //! Adds `attrs` to the function attributes. inline void addAttributes(uint32_t attrs) noexcept { _frame.addAttributes(attrs); } //! \} @@ -520,7 +661,7 @@ public: // [asmjit::FuncRetNode] // ============================================================================ -//! Function return (BaseCompiler). +//! Function return, used by \ref BaseCompiler. class FuncRetNode : public InstNode { public: ASMJIT_NONCOPYABLE(FuncRetNode) @@ -537,13 +678,13 @@ public: }; // ============================================================================ -// [asmjit::FuncCallNode] +// [asmjit::InvokeNode] // ============================================================================ -//! Function call (BaseCompiler). -class FuncCallNode : public InstNode { +//! Function invocation, used by \ref BaseCompiler. +class InvokeNode : public InstNode { public: - ASMJIT_NONCOPYABLE(FuncCallNode) + ASMJIT_NONCOPYABLE(InvokeNode) //! Function detail. FuncDetail _funcDetail; @@ -555,12 +696,12 @@ public: //! \name Construction & Destruction //! \{ - //! Creates a new `FuncCallNode` instance. - inline FuncCallNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept + //! Creates a new `InvokeNode` instance. + inline InvokeNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept : InstNode(cb, instId, options, kBaseOpCapacity), _funcDetail(), _args(nullptr) { - setType(kNodeFuncCall); + setType(kNodeInvoke); _resetOps(); _rets[0].reset(); _rets[1].reset(); @@ -573,8 +714,8 @@ public: //! \{ //! Sets the function signature. - inline Error setSignature(const FuncSignature& sign) noexcept { - return _funcDetail.init(sign); + inline Error init(const FuncSignature& signature, const Environment& environment) noexcept { + return _funcDetail.init(signature, environment); } //! Returns the function detail. @@ -634,6 +775,7 @@ public: // [asmjit::FuncPass] // ============================================================================ +//! Function pass extends \ref Pass with \ref FuncPass::runOnFunction(). class ASMJIT_VIRTAPI FuncPass : public Pass { public: ASMJIT_NONCOPYABLE(FuncPass) @@ -658,10 +800,10 @@ public: //! \{ //! Calls `runOnFunction()` on each `FuncNode` node found. - ASMJIT_API Error run(Zone* zone, Logger* logger) noexcept override; + ASMJIT_API Error run(Zone* zone, Logger* logger) override; //! Called once per `FuncNode`. - virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) noexcept = 0; + virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) = 0; //! \} }; diff --git a/3rdparty/asmjit/src/asmjit/core/constpool.h b/3rdparty/asmjit/src/asmjit/core/constpool.h index 259615fcaa8..d9ac58952a8 100644 --- a/3rdparty/asmjit/src/asmjit/core/constpool.h +++ b/3rdparty/asmjit/src/asmjit/core/constpool.h @@ -30,7 +30,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_core +//! \addtogroup asmjit_utilities //! \{ // ============================================================================ @@ -65,9 +65,12 @@ public: //! Zone-allocated const-pool gap created by two differently aligned constants. struct Gap { - Gap* _next; //!< Pointer to the next gap - size_t _offset; //!< Offset of the gap. - size_t _size; //!< Remaining bytes of the gap (basically a gap size). + //! Pointer to the next gap + Gap* _next; + //! Offset of the gap. + size_t _offset; + //! Remaining bytes of the gap (basically a gap size). + size_t _size; }; //! Zone-allocated const-pool node. @@ -75,6 +78,11 @@ public: public: ASMJIT_NONCOPYABLE(Node) + //! If this constant is shared with another. + uint32_t _shared : 1; + //! Data offset from the beginning of the pool. + uint32_t _offset; + inline Node(size_t offset, bool shared) noexcept : ZoneTreeNodeT<Node>(), _shared(shared), @@ -83,14 +91,13 @@ public: inline void* data() const noexcept { return static_cast<void*>(const_cast<ConstPool::Node*>(this) + 1); } - - uint32_t _shared : 1; //!< If this constant is shared with another. - uint32_t _offset; //!< Data offset from the beginning of the pool. }; //! Data comparer used internally. class Compare { public: + size_t _dataSize; + inline Compare(size_t dataSize) noexcept : _dataSize(dataSize) {} @@ -101,12 +108,17 @@ public: inline int operator()(const Node& a, const void* data) const noexcept { return ::memcmp(a.data(), data, _dataSize); } - - size_t _dataSize; }; //! Zone-allocated const-pool tree. struct Tree { + //! RB tree. + ZoneTree<Node> _tree; + //! Size of the tree (number of nodes). + size_t _size; + //! Size of the data. + size_t _dataSize; + inline explicit Tree(size_t dataSize = 0) noexcept : _tree(), _size(0), @@ -177,13 +189,6 @@ public: memcpy(node->data(), data, size); return node; } - - //! RB tree. - ZoneTree<Node> _tree; - //! Size of the tree (number of nodes). - size_t _size; - //! Size of the data. - size_t _dataSize; }; //! \endcond diff --git a/3rdparty/asmjit/src/asmjit/core/cpuinfo.h b/3rdparty/asmjit/src/asmjit/core/cpuinfo.h index d2defb90ed6..ee2c9e5514a 100644 --- a/3rdparty/asmjit/src/asmjit/core/cpuinfo.h +++ b/3rdparty/asmjit/src/asmjit/core/cpuinfo.h @@ -31,7 +31,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_support +//! \addtogroup asmjit_core //! \{ // ============================================================================ @@ -41,8 +41,12 @@ ASMJIT_BEGIN_NAMESPACE //! CPU information. class CpuInfo { public: - //! CPU architecture information. - ArchInfo _archInfo; + //! Architecture. + uint8_t _arch; + //! Sub-architecture. + uint8_t _subArch; + //! Reserved for future use. + uint16_t _reserved; //! CPU family ID. uint32_t _familyId; //! CPU model ID. @@ -74,15 +78,15 @@ public: inline CpuInfo(const CpuInfo& other) noexcept = default; inline explicit CpuInfo(Globals::NoInit_) noexcept - : _archInfo(Globals::NoInit), - _features(Globals::NoInit) {}; + : _features(Globals::NoInit) {}; //! Returns the host CPU information. ASMJIT_API static const CpuInfo& host() noexcept; - //! Initializes CpuInfo to the given architecture, see `ArchInfo`. - inline void initArch(uint32_t archId, uint32_t archMode = 0) noexcept { - _archInfo.init(archId, archMode); + //! Initializes CpuInfo to the given architecture, see \ref Environment. + inline void initArch(uint32_t arch, uint32_t subArch = 0u) noexcept { + _arch = uint8_t(arch); + _subArch = uint8_t(subArch); } inline void reset() noexcept { memset(this, 0, sizeof(*this)); } @@ -99,12 +103,10 @@ public: //! \name Accessors //! \{ - //! Returns the CPU architecture information. - inline const ArchInfo& archInfo() const noexcept { return _archInfo; } - //! Returns the CPU architecture id, see `ArchInfo::Id`. - inline uint32_t archId() const noexcept { return _archInfo.archId(); } - //! Returns the CPU architecture sub-id, see `ArchInfo::SubId`. - inline uint32_t archSubId() const noexcept { return _archInfo.archSubId(); } + //! Returns the CPU architecture id, see \ref Environment::Arch. + inline uint32_t arch() const noexcept { return _arch; } + //! Returns the CPU architecture sub-id, see \ref Environment::SubArch. + inline uint32_t subArch() const noexcept { return _subArch; } //! Returns the CPU family ID. inline uint32_t familyId() const noexcept { return _familyId; } diff --git a/3rdparty/asmjit/src/asmjit/core/datatypes.h b/3rdparty/asmjit/src/asmjit/core/datatypes.h index bee4572294c..2f6cc1e5b42 100644 --- a/3rdparty/asmjit/src/asmjit/core/datatypes.h +++ b/3rdparty/asmjit/src/asmjit/core/datatypes.h @@ -26,17 +26,16 @@ #include "../core/globals.h" -ASMJIT_BEGIN_NAMESPACE +#ifndef ASMJIT_NO_DEPRECATED -//! \addtogroup asmjit_support -//! \{ +ASMJIT_BEGIN_NAMESPACE // ============================================================================ // [asmjit::Data64] // ============================================================================ //! 64-bit data useful for creating SIMD constants. -union Data64 { +union ASMJIT_DEPRECATED_STRUCT("Data64 is deprecated and will be removed in the future") Data64 { //! Array of eight 8-bit signed integers. int8_t sb[8]; //! Array of eight 8-bit unsigned integers. @@ -303,7 +302,7 @@ union Data64 { // ============================================================================ //! 128-bit data useful for creating SIMD constants. -union Data128 { +union ASMJIT_DEPRECATED_STRUCT("Data128 is deprecated and will be removed in the future") Data128 { //! Array of sixteen 8-bit signed integers. int8_t sb[16]; //! Array of sixteen 8-bit unsigned integers. @@ -648,7 +647,7 @@ union Data128 { // ============================================================================ //! 256-bit data useful for creating SIMD constants. -union Data256 { +union ASMJIT_DEPRECATED_STRUCT("Data256 is deprecated and will be removed in the future") Data256 { //! Array of thirty two 8-bit signed integers. int8_t sb[32]; //! Array of thirty two 8-bit unsigned integers. @@ -1066,8 +1065,7 @@ union Data256 { //! \} }; -//! \} - ASMJIT_END_NAMESPACE +#endif // !ASMJIT_NO_DEPRECATED #endif // ASMJIT_CORE_DATATYPES_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/emitter.cpp b/3rdparty/asmjit/src/asmjit/core/emitter.cpp index ebf8c179008..b6ecc3d3cca 100644 --- a/3rdparty/asmjit/src/asmjit/core/emitter.cpp +++ b/3rdparty/asmjit/src/asmjit/core/emitter.cpp @@ -22,7 +22,9 @@ // 3. This notice may not be removed or altered from any source distribution. #include "../core/api-build_p.h" -#include "../core/logging.h" +#include "../core/emitterutils_p.h" +#include "../core/errorhandler.h" +#include "../core/logger.h" #include "../core/support.h" #ifdef ASMJIT_BUILD_X86 @@ -41,94 +43,212 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::BaseEmitter - Construction / Destruction] // ============================================================================ -BaseEmitter::BaseEmitter(uint32_t type) noexcept - : _type(uint8_t(type)), - _reserved(0), - _flags(0), - _emitterOptions(0), +BaseEmitter::BaseEmitter(uint32_t emitterType) noexcept + : _emitterType(uint8_t(emitterType)), + _emitterFlags(0), + _validationFlags(0), + _validationOptions(0), + _encodingOptions(0), + _forcedInstOptions(BaseInst::kOptionReserved), + _privateData(0), _code(nullptr), + _logger(nullptr), _errorHandler(nullptr), - _codeInfo(), + _environment(), _gpRegInfo(), - _privateData(0), _instOptions(0), - _globalInstOptions(BaseInst::kOptionReserved), _extraReg(), _inlineComment(nullptr) {} BaseEmitter::~BaseEmitter() noexcept { if (_code) { - _addFlags(kFlagDestroyed); + _addEmitterFlags(kFlagDestroyed); _code->detach(this); } } // ============================================================================ -// [asmjit::BaseEmitter - Code-Generation] +// [asmjit::BaseEmitter - Finalize] // ============================================================================ -Error BaseEmitter::_emitOpArray(uint32_t instId, const Operand_* operands, size_t count) { - const Operand_* op = operands; - const Operand& none_ = Globals::none; - - switch (count) { - case 0: return _emit(instId, none_, none_, none_, none_); - case 1: return _emit(instId, op[0], none_, none_, none_); - case 2: return _emit(instId, op[0], op[1], none_, none_); - case 3: return _emit(instId, op[0], op[1], op[2], none_); - case 4: return _emit(instId, op[0], op[1], op[2], op[3]); - case 5: return _emit(instId, op[0], op[1], op[2], op[3], op[4], none_); - case 6: return _emit(instId, op[0], op[1], op[2], op[3], op[4], op[5]); - default: return DebugUtils::errored(kErrorInvalidArgument); - } +Error BaseEmitter::finalize() { + // Does nothing by default, overridden by `BaseBuilder` and `BaseCompiler`. + return kErrorOk; } // ============================================================================ -// [asmjit::BaseEmitter - Finalize] +// [asmjit::BaseEmitter - Internals] // ============================================================================ -Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept { - return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : uint32_t(Globals::kInvalidId)); +static constexpr uint32_t kEmitterPreservedFlags = + BaseEmitter::kFlagOwnLogger | + BaseEmitter::kFlagOwnErrorHandler ; + +static ASMJIT_NOINLINE void BaseEmitter_updateForcedOptions(BaseEmitter* self) noexcept { + bool hasLogger = self->_logger != nullptr; + bool hasValidationOptions; + + if (self->emitterType() == BaseEmitter::kTypeAssembler) + hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionAssembler); + else + hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionIntermediate); + + self->_forcedInstOptions &= ~BaseInst::kOptionReserved; + if (hasLogger || hasValidationOptions) + self->_forcedInstOptions |= BaseInst::kOptionReserved; } // ============================================================================ -// [asmjit::BaseEmitter - Finalize] +// [asmjit::BaseEmitter - Validation Options] // ============================================================================ -Error BaseEmitter::finalize() { - // Does nothing by default, overridden by `BaseBuilder` and `BaseCompiler`. - return kErrorOk; +void BaseEmitter::addValidationOptions(uint32_t options) noexcept { + _validationOptions = uint8_t(_validationOptions | options); + BaseEmitter_updateForcedOptions(this); +} + +void BaseEmitter::clearValidationOptions(uint32_t options) noexcept { + _validationOptions = uint8_t(_validationOptions | options); + BaseEmitter_updateForcedOptions(this); +} + +// ============================================================================ +// [asmjit::BaseEmitter - Logging] +// ============================================================================ + +void BaseEmitter::setLogger(Logger* logger) noexcept { +#ifndef ASMJIT_NO_LOGGING + if (logger) { + _logger = logger; + _addEmitterFlags(kFlagOwnLogger); + } + else { + _logger = nullptr; + _clearEmitterFlags(kFlagOwnLogger); + if (_code) + _logger = _code->logger(); + } + BaseEmitter_updateForcedOptions(this); +#else + DebugUtils::unused(logger); +#endif } // ============================================================================ // [asmjit::BaseEmitter - Error Handling] // ============================================================================ -Error BaseEmitter::reportError(Error err, const char* message) { - ErrorHandler* handler = errorHandler(); - if (!handler) { - if (code()) - handler = code()->errorHandler(); +void BaseEmitter::setErrorHandler(ErrorHandler* errorHandler) noexcept { + if (errorHandler) { + _errorHandler = errorHandler; + _addEmitterFlags(kFlagOwnErrorHandler); } + else { + _errorHandler = nullptr; + _clearEmitterFlags(kFlagOwnErrorHandler); + if (_code) + _errorHandler = _code->errorHandler(); + } +} - if (handler) { +Error BaseEmitter::reportError(Error err, const char* message) { + ErrorHandler* eh = _errorHandler; + if (eh) { if (!message) message = DebugUtils::errorAsString(err); - handler->handleError(err, message, this); + eh->handleError(err, message, this); } - return err; } // ============================================================================ -// [asmjit::BaseEmitter - Label Management] +// [asmjit::BaseEmitter - Labels] // ============================================================================ +Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept { + return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : uint32_t(Globals::kInvalidId)); +} + bool BaseEmitter::isLabelValid(uint32_t labelId) const noexcept { return _code && labelId < _code->labelCount(); } // ============================================================================ +// [asmjit::BaseEmitter - Emit (Low-Level)] +// ============================================================================ + +using EmitterUtils::noExt; + +Error BaseEmitter::_emitI(uint32_t instId) { + return _emit(instId, noExt[0], noExt[1], noExt[2], noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0) { + return _emit(instId, o0, noExt[1], noExt[2], noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1) { + return _emit(instId, o0, o1, noExt[2], noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2) { + return _emit(instId, o0, o1, o2, noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { + Operand_ opExt[3] = { o3 }; + return _emit(instId, o0, o1, o2, opExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4) { + Operand_ opExt[3] = { o3, o4 }; + return _emit(instId, o0, o1, o2, opExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) { + Operand_ opExt[3] = { o3, o4, o5 }; + return _emit(instId, o0, o1, o2, opExt); +} + +Error BaseEmitter::_emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount) { + const Operand_* op = operands; + + Operand_ opExt[3]; + + switch (opCount) { + case 0: + return _emit(instId, noExt[0], noExt[1], noExt[2], noExt); + + case 1: + return _emit(instId, op[0], noExt[1], noExt[2], noExt); + + case 2: + return _emit(instId, op[0], op[1], noExt[2], noExt); + + case 3: + return _emit(instId, op[0], op[1], op[2], noExt); + + case 4: + opExt[0] = op[3]; + opExt[1].reset(); + opExt[2].reset(); + return _emit(instId, op[0], op[1], op[2], opExt); + + case 5: + opExt[0] = op[3]; + opExt[1] = op[4]; + opExt[2].reset(); + return _emit(instId, op[0], op[1], op[2], opExt); + + case 6: + return _emit(instId, op[0], op[1], op[2], op + 3); + + default: + return DebugUtils::errored(kErrorInvalidArgument); + } +} + +// ============================================================================ // [asmjit::BaseEmitter - Emit (High-Level)] // ============================================================================ @@ -137,12 +257,12 @@ ASMJIT_FAVOR_SIZE Error BaseEmitter::emitProlog(const FuncFrame& frame) { return DebugUtils::errored(kErrorNotInitialized); #ifdef ASMJIT_BUILD_X86 - if (archInfo().isX86Family()) + if (environment().isFamilyX86()) return x86::X86Internal::emitProlog(as<x86::Emitter>(), frame); #endif #ifdef ASMJIT_BUILD_ARM - if (archInfo().isArmFamily()) + if (environment().isFamilyARM()) return arm::ArmInternal::emitProlog(as<arm::Emitter>(), frame); #endif @@ -154,12 +274,12 @@ ASMJIT_FAVOR_SIZE Error BaseEmitter::emitEpilog(const FuncFrame& frame) { return DebugUtils::errored(kErrorNotInitialized); #ifdef ASMJIT_BUILD_X86 - if (archInfo().isX86Family()) + if (environment().isFamilyX86()) return x86::X86Internal::emitEpilog(as<x86::Emitter>(), frame); #endif #ifdef ASMJIT_BUILD_ARM - if (archInfo().isArmFamily()) + if (environment().isFamilyARM()) return arm::ArmInternal::emitEpilog(as<arm::Emitter>(), frame); #endif @@ -171,12 +291,12 @@ ASMJIT_FAVOR_SIZE Error BaseEmitter::emitArgsAssignment(const FuncFrame& frame, return DebugUtils::errored(kErrorNotInitialized); #ifdef ASMJIT_BUILD_X86 - if (archInfo().isX86Family()) + if (environment().isFamilyX86()) return x86::X86Internal::emitArgsAssignment(as<x86::Emitter>(), frame, args); #endif #ifdef ASMJIT_BUILD_ARM - if (archInfo().isArmFamily()) + if (environment().isFamilyARM()) return arm::ArmInternal::emitArgsAssignment(as<arm::Emitter>(), frame, args); #endif @@ -192,17 +312,11 @@ Error BaseEmitter::commentf(const char* fmt, ...) { return DebugUtils::errored(kErrorNotInitialized); #ifndef ASMJIT_NO_LOGGING - StringTmp<1024> sb; - va_list ap; va_start(ap, fmt); - Error err = sb.appendVFormat(fmt, ap); + Error err = commentv(fmt, ap); va_end(ap); - - if (ASMJIT_UNLIKELY(err)) - return err; - - return comment(sb.data(), sb.size()); + return err; #else DebugUtils::unused(fmt); return kErrorOk; @@ -215,8 +329,8 @@ Error BaseEmitter::commentv(const char* fmt, va_list ap) { #ifndef ASMJIT_NO_LOGGING StringTmp<1024> sb; - Error err = sb.appendVFormat(fmt, ap); + if (ASMJIT_UNLIKELY(err)) return err; @@ -233,40 +347,46 @@ Error BaseEmitter::commentv(const char* fmt, va_list ap) { Error BaseEmitter::onAttach(CodeHolder* code) noexcept { _code = code; - _codeInfo = code->codeInfo(); - _emitterOptions = code->emitterOptions(); + _environment = code->environment(); - onUpdateGlobalInstOptions(); + onSettingsUpdated(); return kErrorOk; } Error BaseEmitter::onDetach(CodeHolder* code) noexcept { DebugUtils::unused(code); - _flags = 0; - _emitterOptions = 0; - _errorHandler = nullptr; + _clearEmitterFlags(~kEmitterPreservedFlags); + _forcedInstOptions = BaseInst::kOptionReserved; + _privateData = 0; + + if (!hasOwnLogger()) + _logger = nullptr; + + if (!hasOwnErrorHandler()) + _errorHandler = nullptr; - _codeInfo.reset(); + _environment.reset(); _gpRegInfo.reset(); - _privateData = 0; _instOptions = 0; - _globalInstOptions = BaseInst::kOptionReserved; _extraReg.reset(); _inlineComment = nullptr; return kErrorOk; } -void BaseEmitter::onUpdateGlobalInstOptions() noexcept { - constexpr uint32_t kCriticalEmitterOptions = - kOptionLoggingEnabled | - kOptionStrictValidation ; +void BaseEmitter::onSettingsUpdated() noexcept { + // Only called when attached to CodeHolder by CodeHolder. + ASMJIT_ASSERT(_code != nullptr); + + if (!hasOwnLogger()) + _logger = _code->logger(); + + if (!hasOwnErrorHandler()) + _errorHandler = _code->errorHandler(); - _globalInstOptions &= ~BaseInst::kOptionReserved; - if ((_emitterOptions & kCriticalEmitterOptions) != 0) - _globalInstOptions |= BaseInst::kOptionReserved; + BaseEmitter_updateForcedOptions(this); } ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/emitter.h b/3rdparty/asmjit/src/asmjit/core/emitter.h index 585558457bd..cfdb6951488 100644 --- a/3rdparty/asmjit/src/asmjit/core/emitter.h +++ b/3rdparty/asmjit/src/asmjit/core/emitter.h @@ -25,9 +25,10 @@ #define ASMJIT_CORE_EMITTER_H_INCLUDED #include "../core/arch.h" +#include "../core/codeholder.h" #include "../core/inst.h" #include "../core/operand.h" -#include "../core/codeholder.h" +#include "../core/type.h" ASMJIT_BEGIN_NAMESPACE @@ -52,31 +53,40 @@ class ASMJIT_VIRTAPI BaseEmitter { public: ASMJIT_BASE_CLASS(BaseEmitter) - //! See `EmitterType`. - uint8_t _type; - //! Reserved for future use. - uint8_t _reserved; - //! See \ref BaseEmitter::Flags. - uint16_t _flags; - //! Emitter options, always in sync with CodeHolder. - uint32_t _emitterOptions; + //! See \ref EmitterType. + uint8_t _emitterType; + //! See \ref BaseEmitter::EmitterFlags. + uint8_t _emitterFlags; + //! Validation flags in case validation is used, see \ref InstAPI::ValidationFlags. + //! + //! \note Validation flags are specific to the emitter and they are setup at + //! construction time and then never changed. + uint8_t _validationFlags; + //! Validation options, see \ref ValidationOptions. + uint8_t _validationOptions; + + //! Encoding options, see \ref EncodingOptions. + uint32_t _encodingOptions; - //! CodeHolder the BaseEmitter is attached to. + //! Forced instruction options, combined with \ref _instOptions by \ref emit(). + uint32_t _forcedInstOptions; + //! Internal private data used freely by any emitter. + uint32_t _privateData; + + //! CodeHolder the emitter is attached to. CodeHolder* _code; - //! Attached `ErrorHandler`. + //! Attached \ref Logger. + Logger* _logger; + //! Attached \ref ErrorHandler. ErrorHandler* _errorHandler; - //! Basic information about the code (matches CodeHolder::_codeInfo). - CodeInfo _codeInfo; + //! Describes the target environment, matches \ref CodeHolder::environment(). + Environment _environment; //! Native GP register signature and signature related information. RegInfo _gpRegInfo; - //! Internal private data used freely by any emitter. - uint32_t _privateData; //! Next instruction options (affects the next instruction). uint32_t _instOptions; - //! Global Instruction options (combined with `_instOptions` by `emit...()`). - uint32_t _globalInstOptions; //! Extra register (op-mask {k} on AVX-512) (affects the next instruction). RegOnly _extraReg; //! Inline comment of the next instruction (affects the next instruction). @@ -86,41 +96,34 @@ public: enum EmitterType : uint32_t { //! Unknown or uninitialized. kTypeNone = 0, - //! Emitter inherits from `BaseAssembler`. + //! Emitter inherits from \ref BaseAssembler. kTypeAssembler = 1, - //! Emitter inherits from `BaseBuilder`. + //! Emitter inherits from \ref BaseBuilder. kTypeBuilder = 2, - //! Emitter inherits from `BaseCompiler`. + //! Emitter inherits from \ref BaseCompiler. kTypeCompiler = 3, + //! Count of emitter types. kTypeCount = 4 }; //! Emitter flags. - enum Flags : uint32_t { + enum EmitterFlags : uint32_t { + //! The emitter has its own \ref Logger (not propagated from \ref CodeHolder). + kFlagOwnLogger = 0x10u, + //! The emitter has its own \ref ErrorHandler (not propagated from \ref CodeHolder). + kFlagOwnErrorHandler = 0x20u, //! The emitter was finalized. - kFlagFinalized = 0x4000u, + kFlagFinalized = 0x40u, //! The emitter was destroyed. - kFlagDestroyed = 0x8000u + kFlagDestroyed = 0x80u }; - //! Emitter options. - enum Options : uint32_t { - //! Logging is enabled, `BaseEmitter::logger()` must return a valid logger. - //! This option is set automatically by the emitter if the logger is present. - //! User code should never alter this value. - //! - //! Default `false`. - kOptionLoggingEnabled = 0x00000001u, - - //! Stricly validate each instruction before it's emitted. - //! - //! Default `false`. - kOptionStrictValidation = 0x00000002u, - + //! Encoding options. + enum EncodingOptions : uint32_t { //! Emit instructions that are optimized for size, if possible. //! - //! Default `false`. + //! Default: false. //! //! X86 Specific //! ------------ @@ -130,11 +133,11 @@ public: //! by taking advantage of implicit zero extension. For example instruction //! like `mov r64, imm` and `and r64, imm` can be translated to `mov r32, imm` //! and `and r32, imm` when the immediate constant is lesser than `2^31`. - kOptionOptimizedForSize = 0x00000004u, + kEncodingOptionOptimizeForSize = 0x00000001u, //! Emit optimized code-alignment sequences. //! - //! Default `false`. + //! Default: false. //! //! X86 Specific //! ------------ @@ -144,11 +147,11 @@ public: //! more optimized align sequences for 2-11 bytes that may execute faster //! on certain CPUs. If this feature is enabled AsmJit will generate //! specialized sequences for alignment between 2 to 11 bytes. - kOptionOptimizedAlign = 0x00000008u, + kEncodingOptionOptimizedAlign = 0x00000002u, //! Emit jump-prediction hints. //! - //! Default `false`. + //! Default: false. //! //! X86 Specific //! ------------ @@ -163,14 +166,56 @@ public: //! This feature is disabled by default, because the only processor that //! used to take into consideration prediction hints was P4. Newer processors //! implement heuristics for branch prediction and ignore static hints. This - //! means that this feature can be used for annotation purposes. - kOptionPredictedJumps = 0x00000010u + //! means that this feature can be only used for annotation purposes. + kEncodingOptionPredictedJumps = 0x00000010u + }; + +#ifndef ASMJIT_NO_DEPRECATED + enum EmitterOptions : uint32_t { + kOptionOptimizedForSize = kEncodingOptionOptimizeForSize, + kOptionOptimizedAlign = kEncodingOptionOptimizedAlign, + kOptionPredictedJumps = kEncodingOptionPredictedJumps + }; +#endif + + //! Validation options are used to tell emitters to perform strict validation + //! of instructions passed to \ref emit(). + //! + //! \ref BaseAssembler implementation perform by default only basic checks + //! that are necessary to identify all variations of an instruction so the + //! correct encoding can be selected. This is fine for production-ready code + //! as the assembler doesn't have to perform checks that would slow it down. + //! However, sometimes these checks are beneficial especially when the project + //! that uses AsmJit is in a development phase, in which mistakes happen often. + //! To make the experience of using AsmJit seamless it offers validation + //! features that can be controlled by `ValidationOptions`. + enum ValidationOptions : uint32_t { + //! Perform strict validation in \ref BaseAssembler::emit() implementations. + //! + //! This flag ensures that each instruction is checked before it's encoded + //! into a binary representation. This flag is only relevant for \ref + //! BaseAssembler implementations, but can be set in any other emitter type, + //! in that case if that emitter needs to create an assembler on its own, + //! for the purpose of \ref finalize() it would propagate this flag to such + //! assembler so all instructions passed to it are explicitly validated. + //! + //! Default: false. + kValidationOptionAssembler = 0x00000001u, + + //! Perform strict validation in \ref BaseBuilder::emit() and \ref + //! BaseCompiler::emit() implementations. + //! + //! This flag ensures that each instruction is checked before an \ref + //! InstNode representing the instruction is created by Builder or Compiler. + //! + //! Default: false. + kValidationOptionIntermediate = 0x00000002u }; //! \name Construction & Destruction //! \{ - ASMJIT_API explicit BaseEmitter(uint32_t type) noexcept; + ASMJIT_API explicit BaseEmitter(uint32_t emitterType) noexcept; ASMJIT_API virtual ~BaseEmitter() noexcept; //! \} @@ -190,28 +235,28 @@ public: //! \{ //! Returns the type of this emitter, see `EmitterType`. - inline uint32_t emitterType() const noexcept { return _type; } + inline uint32_t emitterType() const noexcept { return _emitterType; } //! Returns emitter flags , see `Flags`. - inline uint32_t emitterFlags() const noexcept { return _flags; } + inline uint32_t emitterFlags() const noexcept { return _emitterFlags; } //! Tests whether the emitter inherits from `BaseAssembler`. - inline bool isAssembler() const noexcept { return _type == kTypeAssembler; } + inline bool isAssembler() const noexcept { return _emitterType == kTypeAssembler; } //! Tests whether the emitter inherits from `BaseBuilder`. //! //! \note Both Builder and Compiler emitters would return `true`. - inline bool isBuilder() const noexcept { return _type >= kTypeBuilder; } + inline bool isBuilder() const noexcept { return _emitterType >= kTypeBuilder; } //! Tests whether the emitter inherits from `BaseCompiler`. - inline bool isCompiler() const noexcept { return _type == kTypeCompiler; } + inline bool isCompiler() const noexcept { return _emitterType == kTypeCompiler; } //! Tests whether the emitter has the given `flag` enabled. - inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + inline bool hasEmitterFlag(uint32_t flag) const noexcept { return (_emitterFlags & flag) != 0; } //! Tests whether the emitter is finalized. - inline bool isFinalized() const noexcept { return hasFlag(kFlagFinalized); } + inline bool isFinalized() const noexcept { return hasEmitterFlag(kFlagFinalized); } //! Tests whether the emitter is destroyed (only used during destruction). - inline bool isDestroyed() const noexcept { return hasFlag(kFlagDestroyed); } + inline bool isDestroyed() const noexcept { return hasEmitterFlag(kFlagDestroyed); } - inline void _addFlags(uint32_t flags) noexcept { _flags = uint16_t(_flags | flags); } - inline void _clearFlags(uint32_t flags) noexcept { _flags = uint16_t(_flags & ~flags); } + inline void _addEmitterFlags(uint32_t flags) noexcept { _emitterFlags = uint8_t(_emitterFlags | flags); } + inline void _clearEmitterFlags(uint32_t flags) noexcept { _emitterFlags = uint8_t(_emitterFlags & ~flags); } //! \} @@ -220,90 +265,187 @@ public: //! Returns the CodeHolder this emitter is attached to. inline CodeHolder* code() const noexcept { return _code; } - //! Returns an information about the code, see `CodeInfo`. - inline const CodeInfo& codeInfo() const noexcept { return _codeInfo; } - //! Returns an information about the architecture, see `ArchInfo`. - inline const ArchInfo& archInfo() const noexcept { return _codeInfo.archInfo(); } + + //! Returns the target environment, see \ref Environment. + //! + //! The returned \ref Environment reference matches \ref CodeHolder::environment(). + inline const Environment& environment() const noexcept { return _environment; } //! Tests whether the target architecture is 32-bit. - inline bool is32Bit() const noexcept { return archInfo().is32Bit(); } + inline bool is32Bit() const noexcept { return environment().is32Bit(); } //! Tests whether the target architecture is 64-bit. - inline bool is64Bit() const noexcept { return archInfo().is64Bit(); } + inline bool is64Bit() const noexcept { return environment().is64Bit(); } //! Returns the target architecture type. - inline uint32_t archId() const noexcept { return archInfo().archId(); } + inline uint32_t arch() const noexcept { return environment().arch(); } //! Returns the target architecture sub-type. - inline uint32_t archSubId() const noexcept { return archInfo().archSubId(); } + inline uint32_t subArch() const noexcept { return environment().subArch(); } + //! Returns the target architecture's GP register size (4 or 8 bytes). - inline uint32_t gpSize() const noexcept { return archInfo().gpSize(); } - //! Returns the number of target GP registers. - inline uint32_t gpCount() const noexcept { return archInfo().gpCount(); } + inline uint32_t registerSize() const noexcept { return environment().registerSize(); } //! \} //! \name Initialization & Finalization //! \{ - //! Tests whether the BaseEmitter is initialized (i.e. attached to the `CodeHolder`). + //! Tests whether the emitter is initialized (i.e. attached to \ref CodeHolder). inline bool isInitialized() const noexcept { return _code != nullptr; } + //! Finalizes this emitter. + //! + //! Materializes the content of the emitter by serializing it to the attached + //! \ref CodeHolder through an architecture specific \ref BaseAssembler. This + //! function won't do anything if the emitter inherits from \ref BaseAssembler + //! as assemblers emit directly to a \ref CodeBuffer held by \ref CodeHolder. + //! However, if this is an emitter that inherits from \ref BaseBuilder or \ref + //! BaseCompiler then these emitters need the materialization phase as they + //! store their content in a representation not visible to \ref CodeHolder. ASMJIT_API virtual Error finalize(); //! \} - //! \name Emitter Options + //! \name Logging //! \{ - //! Tests whether the `option` is present in emitter options. - inline bool hasEmitterOption(uint32_t option) const noexcept { return (_emitterOptions & option) != 0; } - //! Returns the emitter options. - inline uint32_t emitterOptions() const noexcept { return _emitterOptions; } + //! Tests whether the emitter has a logger. + inline bool hasLogger() const noexcept { return _logger != nullptr; } - // TODO: Deprecate and remove, CodeHolder::addEmitterOptions() is the way. - inline void addEmitterOptions(uint32_t options) noexcept { - _emitterOptions |= options; - onUpdateGlobalInstOptions(); - } + //! Tests whether the emitter has its own logger. + //! + //! Own logger means that it overrides the possible logger that may be used + //! by \ref CodeHolder this emitter is attached to. + inline bool hasOwnLogger() const noexcept { return hasEmitterFlag(kFlagOwnLogger); } - inline void clearEmitterOptions(uint32_t options) noexcept { - _emitterOptions &= ~options; - onUpdateGlobalInstOptions(); - } + //! Returns the logger this emitter uses. + //! + //! The returned logger is either the emitter's own logger or it's logger + //! used by \ref CodeHolder this emitter is attached to. + inline Logger* logger() const noexcept { return _logger; } + + //! Sets or resets the logger of the emitter. + //! + //! If the `logger` argument is non-null then the logger will be considered + //! emitter's own logger, see \ref hasOwnLogger() for more details. If the + //! given `logger` is null then the emitter will automatically use logger + //! that is attached to the \ref CodeHolder this emitter is attached to. + ASMJIT_API void setLogger(Logger* logger) noexcept; - //! Returns the global instruction options. + //! Resets the logger of this emitter. //! - //! Default instruction options are merged with instruction options before the - //! instruction is encoded. These options have some bits reserved that are used - //! for error handling, logging, and strict validation. Other options are globals that - //! affect each instruction, for example if VEX3 is set globally, it will all - //! instructions, even those that don't have such option set. - inline uint32_t globalInstOptions() const noexcept { return _globalInstOptions; } + //! The emitter will bail to using a logger attached to \ref CodeHolder this + //! emitter is attached to, or no logger at all if \ref CodeHolder doesn't + //! have one. + inline void resetLogger() noexcept { return setLogger(nullptr); } //! \} //! \name Error Handling //! \{ - //! Tests whether the local error handler is attached. + //! Tests whether the emitter has an error handler attached. inline bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; } - //! Returns the local error handler. + + //! Tests whether the emitter has its own error handler. + //! + //! Own error handler means that it overrides the possible error handler that + //! may be used by \ref CodeHolder this emitter is attached to. + inline bool hasOwnErrorHandler() const noexcept { return hasEmitterFlag(kFlagOwnErrorHandler); } + + //! Returns the error handler this emitter uses. + //! + //! The returned error handler is either the emitter's own error handler or + //! it's error handler used by \ref CodeHolder this emitter is attached to. inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; } - //! Sets the local error handler. - inline void setErrorHandler(ErrorHandler* handler) noexcept { _errorHandler = handler; } - //! Resets the local error handler (does nothing if not attached). + + //! Sets or resets the error handler of the emitter. + ASMJIT_API void setErrorHandler(ErrorHandler* errorHandler) noexcept; + + //! Resets the error handler. inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); } //! Handles the given error in the following way: - //! 1. Gets either Emitter's (preferred) or CodeHolder's ErrorHandler. - //! 2. If exists, calls `ErrorHandler::handleError(error, message, this)`. - //! 3. Returns the given `err` if ErrorHandler haven't thrown. + //! 1. If the emitter has \ref ErrorHandler attached, it calls its + //! \ref ErrorHandler::handleError() member function first, and + //! then returns the error. The `handleError()` function may throw. + //! 2. if the emitter doesn't have \ref ErrorHandler, the error is + //! simply returned. ASMJIT_API Error reportError(Error err, const char* message = nullptr); //! \} + //! \name Encoding Options + //! \{ + + //! Returns encoding options, see \ref EncodingOptions. + inline uint32_t encodingOptions() const noexcept { return _encodingOptions; } + //! Tests whether the encoding `option` is set. + inline bool hasEncodingOption(uint32_t option) const noexcept { return (_encodingOptions & option) != 0; } + + //! Enables the given encoding `options`, see \ref EncodingOptions. + inline void addEncodingOptions(uint32_t options) noexcept { _encodingOptions |= options; } + //! Disables the given encoding `options`, see \ref EncodingOptions. + inline void clearEncodingOptions(uint32_t options) noexcept { _encodingOptions &= ~options; } + + //! \} + + //! \name Validation Options + //! \{ + + //! Returns the emitter's validation options, see \ref ValidationOptions. + inline uint32_t validationOptions() const noexcept { + return _validationOptions; + } + + //! Tests whether the given `option` is present in validation options. + inline bool hasValidationOption(uint32_t option) const noexcept { + return (_validationOptions & option) != 0; + } + + //! Activates the given validation `options`, see \ref ValidationOptions. + //! + //! This function is used to activate explicit validation options that will + //! be then used by all emitter implementations. There are in general two + //! possibilities: + //! + //! - Architecture specific assembler is used. In this case a + //! \ref kValidationOptionAssembler can be used to turn on explicit + //! validation that will be used before an instruction is emitted. + //! This means that internally an extra step will be performed to + //! make sure that the instruction is correct. This is needed, because + //! by default assemblers prefer speed over strictness. + //! + //! This option should be used in debug builds as it's pretty expensive. + //! + //! - Architecture specific builder or compiler is used. In this case + //! the user can turn on \ref kValidationOptionIntermediate option + //! that adds explicit validation step before the Builder or Compiler + //! creates an \ref InstNode to represent an emitted instruction. Error + //! will be returned if the instruction is ill-formed. In addition, + //! also \ref kValidationOptionAssembler can be used, which would not be + //! consumed by Builder / Compiler directly, but it would be propagated + //! to an architecture specific \ref BaseAssembler implementation it + //! creates during \ref BaseEmitter::finalize(). + ASMJIT_API void addValidationOptions(uint32_t options) noexcept; + + //! Deactivates the given validation `options`. + //! + //! See \ref addValidationOptions() and \ref ValidationOptions for more details. + ASMJIT_API void clearValidationOptions(uint32_t options) noexcept; + + //! \} + //! \name Instruction Options //! \{ + //! Returns forced instruction options. + //! + //! Forced instruction options are merged with next instruction options before + //! the instruction is encoded. These options have some bits reserved that are + //! used by error handling, logging, and instruction validation purposes. Other + //! options are globals that affect each instruction. + inline uint32_t forcedInstOptions() const noexcept { return _forcedInstOptions; } + //! Returns options of the next instruction. inline uint32_t instOptions() const noexcept { return _instOptions; } //! Returns options of the next instruction. @@ -377,100 +519,49 @@ public: // NOTE: These `emit()` helpers are designed to address a code-bloat generated // by C++ compilers to call a function having many arguments. Each parameter to - // `_emit()` requires some code to pass it, which means that if we default to 4 - // operand parameters in `_emit()` and instId the C++ compiler would have to - // generate a virtual function call having 5 parameters, which is quite a lot. - // Since by default asm instructions have 2 to 3 operands it's better to - // introduce helpers that pass those and fill out the remaining operands. - - #define OP const Operand_& - #define NONE Globals::none - - //! Emits an instruction. - ASMJIT_NOINLINE Error emit(uint32_t instId) { return _emit(instId, NONE, NONE, NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0) { return _emit(instId, o0, NONE, NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1) { return _emit(instId, o0, o1, NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2) { return _emit(instId, o0, o1, o2, NONE); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3) { return _emit(instId, o0, o1, o2, o3); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4) { return _emit(instId, o0, o1, o2, o3, o4, NONE); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, OP o5) { return _emit(instId, o0, o1, o2, o3, o4, o5); } - - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, int o0) { return _emit(instId, Imm(o0), NONE, NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, int o1) { return _emit(instId, o0, Imm(o1), NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, int o2) { return _emit(instId, o0, o1, Imm(o2), NONE); } + // `_emit()` requires some code to pass it, which means that if we default to + // 5 arguments in `_emit()` and instId the C++ compiler would have to generate + // a virtual function call having 5 parameters and additional `this` argument, + // which is quite a lot. Since by default most instructions have 2 to 3 operands + // it's better to introduce helpers that pass from 0 to 6 operands that help to + // reduce the size of emit(...) function call. + + //! Emits an instruction (internal). + ASMJIT_API Error _emitI(uint32_t instId); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, int o3) { return _emit(instId, o0, o1, o2, Imm(o3)); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), NONE); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); } - - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, int64_t o0) { return _emit(instId, Imm(o0), NONE, NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, int64_t o1) { return _emit(instId, o0, Imm(o1), NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, int64_t o2) { return _emit(instId, o0, o1, Imm(o2), NONE); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, int64_t o3) { return _emit(instId, o0, o1, o2, Imm(o3)); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int64_t o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), NONE); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int64_t o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5); - //! \overload - inline Error emit(uint32_t instId, unsigned int o0) { return emit(instId, int64_t(o0)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, unsigned int o1) { return emit(instId, o0, int64_t(o1)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, unsigned int o2) { return emit(instId, o0, o1, int64_t(o2)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, unsigned int o3) { return emit(instId, o0, o1, o2, int64_t(o3)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, unsigned int o4) { return emit(instId, o0, o1, o2, o3, int64_t(o4)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, unsigned int o5) { return emit(instId, o0, o1, o2, o3, o4, int64_t(o5)); } - - //! \overload - inline Error emit(uint32_t instId, uint64_t o0) { return emit(instId, int64_t(o0)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, uint64_t o1) { return emit(instId, o0, int64_t(o1)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, uint64_t o2) { return emit(instId, o0, o1, int64_t(o2)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, uint64_t o3) { return emit(instId, o0, o1, o2, int64_t(o3)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, uint64_t o4) { return emit(instId, o0, o1, o2, o3, int64_t(o4)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, uint64_t o5) { return emit(instId, o0, o1, o2, o3, o4, int64_t(o5)); } - - #undef NONE - #undef OP + //! Emits an instruction `instId` with the given `operands`. + template<typename... Args> + ASMJIT_INLINE Error emit(uint32_t instId, Args&&... operands) { + return _emitI(instId, Support::ForwardOp<Args>::forward(operands)...); + } - inline Error emitOpArray(uint32_t instId, const Operand_* operands, size_t count) { return _emitOpArray(instId, operands, count); } + inline Error emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount) { + return _emitOpArray(instId, operands, opCount); + } - inline Error emitInst(const BaseInst& inst, const Operand_* operands, size_t count) { + inline Error emitInst(const BaseInst& inst, const Operand_* operands, size_t opCount) { setInstOptions(inst.options()); setExtraReg(inst.extraReg()); - return _emitOpArray(inst.id(), operands, count); + return _emitOpArray(inst.id(), operands, opCount); } //! \cond INTERNAL - //! Emits instruction having max 4 operands. - virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) = 0; - //! Emits instruction having max 6 operands. - virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) = 0; + //! Emits an instruction - all 6 operands must be defined. + virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt) = 0; //! Emits instruction having operands stored in array. - virtual Error _emitOpArray(uint32_t instId, const Operand_* operands, size_t count); + virtual Error _emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount); //! \endcond //! \} @@ -478,19 +569,19 @@ public: //! \name Emit Utilities //! \{ - ASMJIT_API Error emitProlog(const FuncFrame& layout); - ASMJIT_API Error emitEpilog(const FuncFrame& layout); - ASMJIT_API Error emitArgsAssignment(const FuncFrame& layout, const FuncArgsAssignment& args); + ASMJIT_API Error emitProlog(const FuncFrame& frame); + ASMJIT_API Error emitEpilog(const FuncFrame& frame); + ASMJIT_API Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args); //! \} //! \name Align //! \{ - //! Aligns the current CodeBuffer to the `alignment` specified. + //! Aligns the current CodeBuffer position to the `alignment` specified. //! //! The sequence that is used to fill the gap between the aligned location - //! and the current location depends on the align `mode`, see `AlignMode`. + //! and the current location depends on the align `mode`, see \ref AlignMode. virtual Error align(uint32_t alignMode, uint32_t alignment) = 0; //! \} @@ -498,16 +589,38 @@ public: //! \name Embed //! \{ - //! Embeds raw data into the CodeBuffer. - virtual Error embed(const void* data, uint32_t dataSize) = 0; - - //! Embeds an absolute label address as data (4 or 8 bytes). - virtual Error embedLabel(const Label& label) = 0; + //! Embeds raw data into the \ref CodeBuffer. + virtual Error embed(const void* data, size_t dataSize) = 0; - //! Embeds a delta (distance) between the `label` and `base` calculating it - //! as `label - base`. This function was designed to make it easier to embed - //! lookup tables where each index is a relative distance of two labels. - virtual Error embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) = 0; + //! Embeds a typed data array. + //! + //! This is the most flexible function for embedding data as it allows to: + //! - Assign a `typeId` to the data, so the emitter knows the type of + //! items stored in `data`. Binary data should use \ref Type::kIdU8. + //! - Repeat the given data `repeatCount` times, so the data can be used + //! as a fill pattern for example, or as a pattern used by SIMD instructions. + virtual Error embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1) = 0; + + //! Embeds int8_t `value` repeated by `repeatCount`. + inline Error embedInt8(int8_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI8, &value, 1, repeatCount); } + //! Embeds uint8_t `value` repeated by `repeatCount`. + inline Error embedUInt8(uint8_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU8, &value, 1, repeatCount); } + //! Embeds int16_t `value` repeated by `repeatCount`. + inline Error embedInt16(int16_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI16, &value, 1, repeatCount); } + //! Embeds uint16_t `value` repeated by `repeatCount`. + inline Error embedUInt16(uint16_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU16, &value, 1, repeatCount); } + //! Embeds int32_t `value` repeated by `repeatCount`. + inline Error embedInt32(int32_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI32, &value, 1, repeatCount); } + //! Embeds uint32_t `value` repeated by `repeatCount`. + inline Error embedUInt32(uint32_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU32, &value, 1, repeatCount); } + //! Embeds int64_t `value` repeated by `repeatCount`. + inline Error embedInt64(int64_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI64, &value, 1, repeatCount); } + //! Embeds uint64_t `value` repeated by `repeatCount`. + inline Error embedUInt64(uint64_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU64, &value, 1, repeatCount); } + //! Embeds a floating point `value` repeated by `repeatCount`. + inline Error embedFloat(float value, size_t repeatCount = 1) { return embedDataArray(Type::kIdF32, &value, 1, repeatCount); } + //! Embeds a floating point `value` repeated by `repeatCount`. + inline Error embedDouble(double value, size_t repeatCount = 1) { return embedDataArray(Type::IdOfT<double>::kTypeId, &value, 1, repeatCount); } //! Embeds a constant pool at the current offset by performing the following: //! 1. Aligns by using kAlignData to the minimum `pool` alignment. @@ -515,6 +628,14 @@ public: //! 3. Emits ConstPool content. virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0; + //! Embeds an absolute label address as data (4 or 8 bytes). + virtual Error embedLabel(const Label& label) = 0; + + //! Embeds a delta (distance) between the `label` and `base` calculating it + //! as `label - base`. This function was designed to make it easier to embed + //! lookup tables where each index is a relative distance of two labels. + virtual Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize) = 0; + //! \} //! \name Comment @@ -538,13 +659,48 @@ public: //! Called after the emitter was detached from `CodeHolder`. virtual Error onDetach(CodeHolder* code) noexcept = 0; - //! Called to update `_globalInstOptions` based on `_emitterOptions`. + //! Called when \ref CodeHolder has updated an important setting, which + //! involves the following: //! - //! This function should only touch one bit `BaseInst::kOptionReserved`, which - //! is used to handle errors and special-cases in a way that minimizes branching. - ASMJIT_API void onUpdateGlobalInstOptions() noexcept; + //! - \ref Logger has been changed (\ref CodeHolder::setLogger() has been + //! called). + //! - \ref ErrorHandler has been changed (\ref CodeHolder::setErrorHandler() + //! has been called). + //! + //! This function ensures that the settings are properly propagated from + //! \ref CodeHolder to the emitter. + //! + //! \note This function is virtual and can be overridden, however, if you + //! do so, always call \ref BaseEmitter::onSettingsUpdated() within your + //! own implementation to ensure that the emitter is in a consisten state. + ASMJIT_API virtual void onSettingsUpdated() noexcept; //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use environment() instead") + inline CodeInfo codeInfo() const noexcept { + return CodeInfo(_environment, _code ? _code->baseAddress() : Globals::kNoBaseAddress); + } + + ASMJIT_DEPRECATED("Use arch() instead") + inline uint32_t archId() const noexcept { return arch(); } + + ASMJIT_DEPRECATED("Use registerSize() instead") + inline uint32_t gpSize() const noexcept { return registerSize(); } + + ASMJIT_DEPRECATED("Use encodingOptions() instead") + inline uint32_t emitterOptions() const noexcept { return encodingOptions(); } + + ASMJIT_DEPRECATED("Use addEncodingOptions() instead") + inline void addEmitterOptions(uint32_t options) noexcept { addEncodingOptions(options); } + + ASMJIT_DEPRECATED("Use clearEncodingOptions() instead") + inline void clearEmitterOptions(uint32_t options) noexcept { clearEncodingOptions(options); } + + ASMJIT_DEPRECATED("Use forcedInstOptions() instead") + inline uint32_t globalInstOptions() const noexcept { return forcedInstOptions(); } +#endif // !ASMJIT_NO_DEPRECATED }; //! \} diff --git a/3rdparty/asmjit/src/asmjit/core/emitterutils.cpp b/3rdparty/asmjit/src/asmjit/core/emitterutils.cpp new file mode 100644 index 00000000000..1115934e21e --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/emitterutils.cpp @@ -0,0 +1,150 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/assembler.h" +#include "../core/emitterutils_p.h" +#include "../core/formatter.h" +#include "../core/logger.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::EmitterUtils] +// ============================================================================ + +namespace EmitterUtils { + +#ifndef ASMJIT_NO_LOGGING + +Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept { + size_t currentSize = sb.size(); + size_t commentSize = comment ? Support::strLen(comment, Globals::kMaxCommentSize) : 0; + + ASMJIT_ASSERT(binSize >= dispSize); + const size_t kNoBinSize = SIZE_MAX; + + if ((binSize != 0 && binSize != kNoBinSize) || commentSize) { + size_t align = kMaxInstLineSize; + char sep = ';'; + + for (size_t i = (binSize == kNoBinSize); i < 2; i++) { + size_t begin = sb.size(); + ASMJIT_PROPAGATE(sb.padEnd(align)); + + if (sep) { + ASMJIT_PROPAGATE(sb.append(sep)); + ASMJIT_PROPAGATE(sb.append(' ')); + } + + // Append binary data or comment. + if (i == 0) { + ASMJIT_PROPAGATE(sb.appendHex(binData, binSize - dispSize - immSize)); + ASMJIT_PROPAGATE(sb.appendChars('.', dispSize * 2)); + ASMJIT_PROPAGATE(sb.appendHex(binData + binSize - immSize, immSize)); + if (commentSize == 0) break; + } + else { + ASMJIT_PROPAGATE(sb.append(comment, commentSize)); + } + + currentSize += sb.size() - begin; + align += kMaxBinarySize; + sep = '|'; + } + } + + return sb.append('\n'); +} + +void logLabelBound(BaseAssembler* self, const Label& label) noexcept { + Logger* logger = self->logger(); + + StringTmp<512> sb; + size_t binSize = logger->hasFlag(FormatOptions::kFlagMachineCode) ? size_t(0) : SIZE_MAX; + + sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationLabel)); + Formatter::formatLabel(sb, logger->flags(), self, label.id()); + sb.append(':'); + EmitterUtils::formatLine(sb, nullptr, binSize, 0, 0, self->_inlineComment); + logger->log(sb.data(), sb.size()); +} + +void logInstructionEmitted( + BaseAssembler* self, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt, + uint32_t relSize, uint32_t immSize, uint8_t* afterCursor) { + + Logger* logger = self->logger(); + ASMJIT_ASSERT(logger != nullptr); + + StringTmp<256> sb; + uint32_t flags = logger->flags(); + + uint8_t* beforeCursor = self->bufferPtr(); + intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor); + + Operand_ opArray[Globals::kMaxOpCount]; + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); + + sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationCode)); + Formatter::formatInstruction(sb, flags, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount); + + if ((flags & FormatOptions::kFlagMachineCode) != 0) + EmitterUtils::formatLine(sb, self->bufferPtr(), size_t(emittedSize), relSize, immSize, self->inlineComment()); + else + EmitterUtils::formatLine(sb, nullptr, SIZE_MAX, 0, 0, self->inlineComment()); + logger->log(sb); +} + +Error logInstructionFailed( + BaseAssembler* self, + Error err, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) { + + StringTmp<256> sb; + sb.append(DebugUtils::errorAsString(err)); + sb.append(": "); + + Operand_ opArray[Globals::kMaxOpCount]; + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); + + Formatter::formatInstruction(sb, 0, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount); + + if (self->inlineComment()) { + sb.append(" ; "); + sb.append(self->inlineComment()); + } + + self->resetInstOptions(); + self->resetExtraReg(); + self->resetInlineComment(); + return self->reportError(err, sb.data()); +} + +#endif + +} // {EmitterUtils} + +ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/emitterutils_p.h b/3rdparty/asmjit/src/asmjit/core/emitterutils_p.h new file mode 100644 index 00000000000..7e222d3ad00 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/emitterutils_p.h @@ -0,0 +1,109 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED +#define ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED + +#include "../core/emitter.h" +#include "../core/operand.h" + +ASMJIT_BEGIN_NAMESPACE + +class BaseAssembler; + +//! \cond INTERNAL +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::EmitterUtils] +// ============================================================================ + +namespace EmitterUtils { + +static const Operand_ noExt[3] {}; + +enum kOpIndex { + kOp3 = 0, + kOp4 = 1, + kOp5 = 2 +}; + +static ASMJIT_INLINE uint32_t opCountFromEmitArgs(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) noexcept { + uint32_t opCount = 0; + + if (opExt[kOp3].isNone()) { + if (!o0.isNone()) opCount = 1; + if (!o1.isNone()) opCount = 2; + if (!o2.isNone()) opCount = 3; + } + else { + opCount = 4; + if (!opExt[kOp4].isNone()) { + opCount = 5 + uint32_t(!opExt[kOp5].isNone()); + } + } + + return opCount; +} + +static ASMJIT_INLINE void opArrayFromEmitArgs(Operand_ dst[Globals::kMaxOpCount], const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) noexcept { + dst[0].copyFrom(o0); + dst[1].copyFrom(o1); + dst[2].copyFrom(o2); + dst[3].copyFrom(opExt[kOp3]); + dst[4].copyFrom(opExt[kOp4]); + dst[5].copyFrom(opExt[kOp5]); +} + +#ifndef ASMJIT_NO_LOGGING +enum : uint32_t { + // Has to be big to be able to hold all metadata compiler can assign to a + // single instruction. + kMaxInstLineSize = 44, + kMaxBinarySize = 26 +}; + +Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept; + +void logLabelBound(BaseAssembler* self, const Label& label) noexcept; + +void logInstructionEmitted( + BaseAssembler* self, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt, + uint32_t relSize, uint32_t immSize, uint8_t* afterCursor); + +Error logInstructionFailed( + BaseAssembler* self, + Error err, uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt); +#endif + +} + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED + diff --git a/3rdparty/asmjit/src/asmjit/core/environment.cpp b/3rdparty/asmjit/src/asmjit/core/environment.cpp new file mode 100644 index 00000000000..3be2b15a590 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/environment.cpp @@ -0,0 +1,64 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/environment.h" + +ASMJIT_BEGIN_NAMESPACE + +// X86 Target +// ---------- +// +// - 32-bit - Linux, OSX, BSD, and apparently also Haiku guarantee 16-byte +// stack alignment. Other operating systems are assumed to have +// 4-byte alignment by default for safety reasons. +// - 64-bit - stack must be aligned to 16 bytes. +// +// ARM Target +// ---------- +// +// - 32-bit - Stack must be aligned to 8 bytes. +// - 64-bit - Stack must be aligned to 16 bytes (hardware requirement). +uint32_t Environment::stackAlignment() const noexcept { + if (is64Bit()) { + // Assume 16-byte alignment on any 64-bit target. + return 16; + } + else { + // The following platforms use 16-byte alignment in 32-bit mode. + if (isPlatformLinux() || + isPlatformBSD() || + isPlatformApple() || + isPlatformHaiku()) { + return 16u; + } + + if (isFamilyARM()) + return 8; + + // Bail to 4-byte alignment if we don't know. + return 4; + } +} + +ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/environment.h b/3rdparty/asmjit/src/asmjit/core/environment.h new file mode 100644 index 00000000000..99b34ec9dbd --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/environment.h @@ -0,0 +1,591 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_ENVIRONMENT_H_INCLUDED +#define ASMJIT_CORE_ENVIRONMENT_H_INCLUDED + +#include "../core/globals.h" + +#if defined(__APPLE__) + #include <TargetConditionals.h> +#endif + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::Environment] +// ============================================================================ + +//! Represents an environment, which is usually related to a \ref Target. +//! +//! Environment has usually an 'arch-subarch-vendor-os-abi' format, which is +//! sometimes called "Triple" (historically it used to be 3 only parts) or +//! "Tuple", which is a convention used by Debian Linux. +//! +//! AsmJit doesn't support all possible combinations or architectures and ABIs, +//! however, it models the environment similarly to other compilers for future +//! extensibility. +class Environment { +public: + //! Architecture type, see \ref Arch. + uint8_t _arch; + //! Sub-architecture type, see \ref SubArch. + uint8_t _subArch; + //! Vendor type, see \ref Vendor. + uint8_t _vendor; + //! Platform type, see \ref Platform. + uint8_t _platform; + //! ABI type, see \ref Abi. + uint8_t _abi; + //! Object format, see \ref Format. + uint8_t _format; + //! Reserved for future use, must be zero. + uint16_t _reserved; + + //! Architecture. + enum Arch : uint32_t { + //! Unknown or uninitialized architecture. + kArchUnknown = 0, + + //! Mask used by 32-bit architectures (odd are 32-bit, even are 64-bit). + kArch32BitMask = 0x01, + //! Mask used by big-endian architectures. + kArchBigEndianMask = 0x80u, + + //! 32-bit X86 architecture. + kArchX86 = 1, + //! 64-bit X86 architecture also known as X86_64 and AMD64. + kArchX64 = 2, + + //! 32-bit RISC-V architecture. + kArchRISCV32 = 3, + //! 64-bit RISC-V architecture. + kArchRISCV64 = 4, + + //! 32-bit ARM architecture (little endian). + kArchARM = 5, + //! 32-bit ARM architecture (big endian). + kArchARM_BE = kArchARM | kArchBigEndianMask, + //! 64-bit ARM architecture in (little endian). + kArchAArch64 = 6, + //! 64-bit ARM architecture in (big endian). + kArchAArch64_BE = kArchAArch64 | kArchBigEndianMask, + //! 32-bit ARM in Thumb mode (little endian). + kArchThumb = 7, + //! 32-bit ARM in Thumb mode (big endian). + kArchThumb_BE = kArchThumb | kArchBigEndianMask, + + // 8 is not used, even numbers are 64-bit architectures. + + //! 32-bit MIPS architecture in (little endian). + kArchMIPS_LE = 9, + //! 32-bit MIPS architecture in (big endian). + kArchMIPS_BE = kArchMIPS_LE | kArchBigEndianMask, + //! 64-bit MIPS architecture in (little endian). + kArchMIPS64_LE = 10, + //! 64-bit MIPS architecture in (big endian). + kArchMIPS64_BE = kArchMIPS64_LE | kArchBigEndianMask, + + //! Count of architectures. + kArchCount + }; + + //! Sub-architecture. + enum SubArch : uint32_t { + //! Unknown or uninitialized architecture sub-type. + kSubArchUnknown = 0, + + //! Count of sub-architectures. + kSubArchCount + }; + + //! Vendor. + //! + //! \note AsmJit doesn't use vendor information at the moment. It's provided + //! for future use, if required. + enum Vendor : uint32_t { + //! Unknown or uninitialized vendor. + kVendorUnknown = 0, + + //! Count of vendor identifiers. + kVendorCount + }; + + //! Platform / OS. + enum Platform : uint32_t { + //! Unknown or uninitialized platform. + kPlatformUnknown = 0, + + //! Windows OS. + kPlatformWindows, + + //! Other platform, most likely POSIX based. + kPlatformOther, + + //! Linux OS. + kPlatformLinux, + //! GNU/Hurd OS. + kPlatformHurd, + + //! FreeBSD OS. + kPlatformFreeBSD, + //! OpenBSD OS. + kPlatformOpenBSD, + //! NetBSD OS. + kPlatformNetBSD, + //! DragonFly BSD OS. + kPlatformDragonFlyBSD, + + //! Haiku OS. + kPlatformHaiku, + + //! Apple OSX. + kPlatformOSX, + //! Apple iOS. + kPlatformIOS, + //! Apple TVOS. + kPlatformTVOS, + //! Apple WatchOS. + kPlatformWatchOS, + + //! Emscripten platform. + kPlatformEmscripten, + + //! Count of platform identifiers. + kPlatformCount + }; + + //! ABI. + enum Abi : uint32_t { + //! Unknown or uninitialied environment. + kAbiUnknown = 0, + //! Microsoft ABI. + kAbiMSVC, + //! GNU ABI. + kAbiGNU, + //! Android Environment / ABI. + kAbiAndroid, + //! Cygwin ABI. + kAbiCygwin, + + //! Count of known ABI types. + kAbiCount + }; + + //! Object format. + //! + //! \note AsmJit doesn't really use anything except \ref kFormatUnknown and + //! \ref kFormatJIT at the moment. Object file formats are provided for + //! future extensibility and a possibility to generate object files at some + //! point. + enum Format : uint32_t { + //! Unknown or uninitialized object format. + kFormatUnknown = 0, + + //! JIT code generation object, most likely \ref JitRuntime or a custom + //! \ref Target implementation. + kFormatJIT, + + //! Executable and linkable format (ELF). + kFormatELF, + //! Common object file format. + kFormatCOFF, + //! Extended COFF object format. + kFormatXCOFF, + //! Mach object file format. + kFormatMachO, + + //! Count of object format types. + kFormatCount + }; + + //! \name Environment Detection + //! \{ + +#ifdef _DOXYGEN + //! Architecture detected at compile-time (architecture of the host). + static constexpr Arch kArchHost = DETECTED_AT_COMPILE_TIME; + //! Sub-architecture detected at compile-time (sub-architecture of the host). + static constexpr SubArch kSubArchHost = DETECTED_AT_COMPILE_TIME; + //! Vendor detected at compile-time (vendor of the host). + static constexpr Vendor kVendorHost = DETECTED_AT_COMPILE_TIME; + //! Platform detected at compile-time (platform of the host). + static constexpr Platform kPlatformHost = DETECTED_AT_COMPILE_TIME; + //! ABI detected at compile-time (ABI of the host). + static constexpr Abi kAbiHost = DETECTED_AT_COMPILE_TIME; +#else + static constexpr Arch kArchHost = + ASMJIT_ARCH_X86 == 32 ? kArchX86 : + ASMJIT_ARCH_X86 == 64 ? kArchX64 : + + ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_LE ? kArchARM : + ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_BE ? kArchARM_BE : + ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_LE ? kArchAArch64 : + ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_BE ? kArchAArch64_BE : + + ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_LE ? kArchMIPS_LE : + ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_BE ? kArchMIPS_BE : + ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_LE ? kArchMIPS64_LE : + ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_BE ? kArchMIPS64_BE : + + kArchUnknown; + + static constexpr SubArch kSubArchHost = + kSubArchUnknown; + + static constexpr Vendor kVendorHost = + kVendorUnknown; + + static constexpr Platform kPlatformHost = +#if defined(__EMSCRIPTEN__) + kPlatformEmscripten +#elif defined(_WIN32) + kPlatformWindows +#elif defined(__linux__) + kPlatformLinux +#elif defined(__gnu_hurd__) + kPlatformHurd +#elif defined(__FreeBSD__) + kPlatformFreeBSD +#elif defined(__OpenBSD__) + kPlatformOpenBSD +#elif defined(__NetBSD__) + kPlatformNetBSD +#elif defined(__DragonFly__) + kPlatformDragonFlyBSD +#elif defined(__HAIKU__) + kPlatformHaiku +#elif defined(__APPLE__) && TARGET_OS_OSX + kPlatformOSX +#elif defined(__APPLE__) && TARGET_OS_TV + kPlatformTVOS +#elif defined(__APPLE__) && TARGET_OS_WATCH + kPlatformWatchOS +#elif defined(__APPLE__) && TARGET_OS_IPHONE + kPlatformIOS +#else + kPlatformOther +#endif + ; + + static constexpr Abi kAbiHost = +#if defined(_MSC_VER) + kAbiMSVC +#elif defined(__CYGWIN__) + kAbiCygwin +#elif defined(__MINGW32__) || defined(__GLIBC__) + kAbiGNU +#elif defined(__ANDROID__) + kAbiAndroid +#else + kAbiUnknown +#endif + ; + +#endif + + //! \} + + //! \name Construction / Destruction + //! \{ + + inline Environment() noexcept : + _arch(uint8_t(kArchUnknown)), + _subArch(uint8_t(kSubArchUnknown)), + _vendor(uint8_t(kVendorUnknown)), + _platform(uint8_t(kPlatformUnknown)), + _abi(uint8_t(kAbiUnknown)), + _format(uint8_t(kFormatUnknown)), + _reserved(0) {} + + inline Environment(const Environment& other) noexcept = default; + + inline explicit Environment(uint32_t arch, + uint32_t subArch = kSubArchUnknown, + uint32_t vendor = kVendorUnknown, + uint32_t platform = kPlatformUnknown, + uint32_t abi = kAbiUnknown, + uint32_t format = kFormatUnknown) noexcept { + init(arch, subArch, vendor, platform, abi, format); + } + + //! \} + + //! \name Overloaded Operators + //! \{ + + inline Environment& operator=(const Environment& other) noexcept = default; + + inline bool operator==(const Environment& other) const noexcept { return equals(other); } + inline bool operator!=(const Environment& other) const noexcept { return !equals(other); } + + //! \} + + //! \name Accessors + //! \{ + + //! Tests whether the environment is not set up. + //! + //! Returns true if all members are zero, and thus unknown. + inline bool empty() const noexcept { + // Unfortunately compilers won't optimize fields are checked one by one... + return _packed() == 0; + } + + //! Tests whether the environment is intialized, which means it must have + //! a valid architecture. + inline bool isInitialized() const noexcept { + return _arch != kArchUnknown; + } + + inline uint64_t _packed() const noexcept { + uint64_t x; + memcpy(&x, this, 8); + return x; + } + + //! Resets all members of the environment to zero / unknown. + inline void reset() noexcept { + _arch = uint8_t(kArchUnknown); + _subArch = uint8_t(kSubArchUnknown); + _vendor = uint8_t(kVendorUnknown); + _platform = uint8_t(kPlatformUnknown); + _abi = uint8_t(kAbiUnknown); + _format = uint8_t(kFormatUnknown); + _reserved = 0; + } + + inline bool equals(const Environment& other) const noexcept { + return _packed() == other._packed(); + } + + //! Returns the architecture, see \ref Arch. + inline uint32_t arch() const noexcept { return _arch; } + //! Returns the sub-architecture, see \ref SubArch. + inline uint32_t subArch() const noexcept { return _subArch; } + //! Returns vendor, see \ref Vendor. + inline uint32_t vendor() const noexcept { return _vendor; } + //! Returns target's platform or operating system, see \ref Platform. + inline uint32_t platform() const noexcept { return _platform; } + //! Returns target's ABI, see \ref Abi. + inline uint32_t abi() const noexcept { return _abi; } + //! Returns target's object format, see \ref Format. + inline uint32_t format() const noexcept { return _format; } + + inline void init(uint32_t arch, + uint32_t subArch = kSubArchUnknown, + uint32_t vendor = kVendorUnknown, + uint32_t platform = kPlatformUnknown, + uint32_t abi = kAbiUnknown, + uint32_t format = kFormatUnknown) noexcept { + _arch = uint8_t(arch); + _subArch = uint8_t(subArch); + _vendor = uint8_t(vendor); + _platform = uint8_t(platform); + _abi = uint8_t(abi); + _format = uint8_t(format); + _reserved = 0; + } + + //! Tests whether the architecture is 32-bit. + inline bool is32Bit() const noexcept { return is32Bit(_arch); } + //! Tests whether the architecture is 64-bit. + inline bool is64Bit() const noexcept { return is64Bit(_arch); } + + //! Tests whether the architecture is little endian. + inline bool isLittleEndian() const noexcept { return isLittleEndian(_arch); } + //! Tests whether the architecture is big endian. + inline bool isBigEndian() const noexcept { return isBigEndian(_arch); } + + //! Tests whether this architecture is of X86 family. + inline bool isFamilyX86() const noexcept { return isFamilyX86(_arch); } + //! Tests whether this architecture is of ARM family. + inline bool isFamilyRISCV() const noexcept { return isFamilyRISCV(_arch); } + //! Tests whether this architecture is of ARM family. + inline bool isFamilyARM() const noexcept { return isFamilyARM(_arch); } + //! Tests whether this architecture is of ARM family. + inline bool isFamilyMIPS() const noexcept { return isFamilyMIPS(_arch); } + + //! Tests whether the environment platform is Windows. + inline bool isPlatformWindows() const noexcept { return _platform == kPlatformWindows; } + + //! Tests whether the environment platform is Linux. + inline bool isPlatformLinux() const noexcept { return _platform == kPlatformLinux; } + + //! Tests whether the environment platform is Hurd. + inline bool isPlatformHurd() const noexcept { return _platform == kPlatformHurd; } + + //! Tests whether the environment platform is Haiku. + inline bool isPlatformHaiku() const noexcept { return _platform == kPlatformHaiku; } + + //! Tests whether the environment platform is any BSD. + inline bool isPlatformBSD() const noexcept { + return _platform == kPlatformFreeBSD || + _platform == kPlatformOpenBSD || + _platform == kPlatformNetBSD || + _platform == kPlatformDragonFlyBSD; + } + + //! Tests whether the environment platform is any Apple platform (OSX, iOS, TVOS, WatchOS). + inline bool isPlatformApple() const noexcept { + return _platform == kPlatformOSX || + _platform == kPlatformIOS || + _platform == kPlatformTVOS || + _platform == kPlatformWatchOS; + } + + //! Tests whether the ABI is MSVC. + inline bool isAbiMSVC() const noexcept { return _abi == kAbiMSVC; } + //! Tests whether the ABI is GNU. + inline bool isAbiGNU() const noexcept { return _abi == kAbiGNU; } + + //! Returns a calculated stack alignment for this environment. + ASMJIT_API uint32_t stackAlignment() const noexcept; + + //! Returns a native register size of this architecture. + uint32_t registerSize() const noexcept { return registerSizeFromArch(_arch); } + + //! Sets the architecture to `arch`. + inline void setArch(uint32_t arch) noexcept { _arch = uint8_t(arch); } + //! Sets the sub-architecture to `subArch`. + inline void setSubArch(uint32_t subArch) noexcept { _subArch = uint8_t(subArch); } + //! Sets the vendor to `vendor`. + inline void setVendor(uint32_t vendor) noexcept { _vendor = uint8_t(vendor); } + //! Sets the platform to `platform`. + inline void setPlatform(uint32_t platform) noexcept { _platform = uint8_t(platform); } + //! Sets the ABI to `abi`. + inline void setAbi(uint32_t abi) noexcept { _abi = uint8_t(abi); } + //! Sets the object format to `format`. + inline void setFormat(uint32_t format) noexcept { _format = uint8_t(format); } + + //! \} + + //! \name Static Utilities + //! \{ + + //! Tests whether the given architecture `arch` is 32-bit. + static inline bool is32Bit(uint32_t arch) noexcept { + return (arch & kArch32BitMask) == kArch32BitMask; + } + + //! Tests whether the given architecture `arch` is 64-bit. + static inline bool is64Bit(uint32_t arch) noexcept { + return (arch & kArch32BitMask) == 0; + } + + //! Tests whether the given architecture `arch` is little endian. + static inline bool isLittleEndian(uint32_t arch) noexcept { + return (arch & kArchBigEndianMask) == 0; + } + + //! Tests whether the given architecture `arch` is big endian. + static inline bool isBigEndian(uint32_t arch) noexcept { + return (arch & kArchBigEndianMask) == kArchBigEndianMask; + } + + //! Tests whether the given architecture family is X86 or X64. + static inline bool isFamilyX86(uint32_t arch) noexcept { + return arch == kArchX86 || + arch == kArchX64; + } + + //! Tests whether the given architecture family is RISC-V (both 32-bit and 64-bit). + static inline bool isFamilyRISCV(uint32_t arch) noexcept { + return arch == kArchRISCV32 || + arch == kArchRISCV64; + } + + //! Tests whether the given architecture family is ARM, Thumb, or AArch64. + static inline bool isFamilyARM(uint32_t arch) noexcept { + arch &= ~kArchBigEndianMask; + return arch == kArchARM || + arch == kArchAArch64 || + arch == kArchThumb; + } + + //! Tests whether the given architecture family is MISP or MIPS64. + static inline bool isFamilyMIPS(uint32_t arch) noexcept { + arch &= ~kArchBigEndianMask; + return arch == kArchMIPS_LE || + arch == kArchMIPS64_LE; + } + + //! Returns a native general purpose register size from the given architecture. + static uint32_t registerSizeFromArch(uint32_t arch) noexcept { + return is32Bit(arch) ? 4u : 8u; + } + + //! \} +}; + +//! Returns the host environment constructed from preprocessor macros defined +//! by the compiler. +//! +//! The returned environment should precisely match the target host architecture, +//! sub-architecture, platform, and ABI. +static ASMJIT_INLINE Environment hostEnvironment() noexcept { + return Environment(Environment::kArchHost, + Environment::kSubArchHost, + Environment::kVendorHost, + Environment::kPlatformHost, + Environment::kAbiHost, + Environment::kFormatUnknown); +} + +static_assert(sizeof(Environment) == 8, + "Environment must occupy exactly 8 bytes."); + +//! \} + +#ifndef ASMJIT_NO_DEPRECATED +class ASMJIT_DEPRECATED_STRUCT("Use Environment instead") ArchInfo : public Environment { +public: + inline ArchInfo() noexcept : Environment() {} + + inline ArchInfo(const Environment& other) noexcept : Environment(other) {} + inline explicit ArchInfo(uint32_t arch, uint32_t subArch = kSubArchUnknown) noexcept + : Environment(arch, subArch) {} + + enum Id : uint32_t { + kIdNone = Environment::kArchUnknown, + kIdX86 = Environment::kArchX86, + kIdX64 = Environment::kArchX64, + kIdA32 = Environment::kArchARM, + kIdA64 = Environment::kArchAArch64, + kIdHost = Environment::kArchHost + }; + + enum SubType : uint32_t { + kSubIdNone = Environment::kSubArchUnknown + }; + + static inline ArchInfo host() noexcept { return ArchInfo(hostEnvironment()); } +}; +#endif // !ASMJIT_NO_DEPRECATED + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_ENVIRONMENT_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/errorhandler.cpp b/3rdparty/asmjit/src/asmjit/core/errorhandler.cpp new file mode 100644 index 00000000000..8372d75a463 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/errorhandler.cpp @@ -0,0 +1,37 @@ + +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/errorhandler.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::ErrorHandler] +// ============================================================================ + +ErrorHandler::ErrorHandler() noexcept {} +ErrorHandler::~ErrorHandler() noexcept {} + +ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/errorhandler.h b/3rdparty/asmjit/src/asmjit/core/errorhandler.h new file mode 100644 index 00000000000..2337cd8d841 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/errorhandler.h @@ -0,0 +1,267 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_ERRORHANDLER_H_INCLUDED +#define ASMJIT_CORE_ERRORHANDLER_H_INCLUDED + +#include "../core/globals.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_error_handling +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class BaseEmitter; + +// ============================================================================ +// [asmjit::ErrorHandler] +// ============================================================================ + +//! Error handler can be used to override the default behavior of error handling. +//! +//! It's available to all classes that inherit `BaseEmitter`. Override +//! \ref ErrorHandler::handleError() to implement your own error handler. +//! +//! The following use-cases are supported: +//! +//! - Record the error and continue code generation. This is the simplest +//! approach that can be used to at least log possible errors. +//! - Throw an exception. AsmJit doesn't use exceptions and is completely +//! exception-safe, but it's perfectly legal to throw an exception from +//! the error handler. +//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, +//! Builder and Compiler to a consistent state before calling \ref handleError(), +//! so `longjmp()` can be used without issues to cancel the code-generation if +//! an error occurred. This method can be used if exception handling in your +//! project is turned off and you still want some comfort. In most cases it +//! should be safe as AsmJit uses \ref Zone memory and the ownership of memory +//! it allocates always ends with the instance that allocated it. If using this +//! approach please never jump outside the life-time of \ref CodeHolder and +//! \ref BaseEmitter. +//! +//! \ref ErrorHandler can be attached to \ref CodeHolder or \ref BaseEmitter, +//! which has a priority. The example below uses error handler that just prints +//! the error, but lets AsmJit continue: +//! +//! ``` +//! // Error Handling #1 - Logging and returing Error. +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Error handler that just prints the error and lets AsmJit ignore it. +//! class SimpleErrorHandler : public ErrorHandler { +//! public: +//! Error err; +//! +//! inline SimpleErrorHandler() : err(kErrorOk) {} +//! +//! void handleError(Error err, const char* message, BaseEmitter* origin) override { +//! this->err = err; +//! fprintf(stderr, "ERROR: %s\n", message); +//! } +//! }; +//! +//! int main() { +//! JitRuntime rt; +//! SimpleErrorHandler eh; +//! +//! CodeHolder code; +//! code.init(rt.environment()); +//! code.setErrorHandler(&eh); +//! +//! // Try to emit instruction that doesn't exist. +//! x86::Assembler a(&code); +//! a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); +//! +//! if (eh.err) { +//! // Assembler failed! +//! return 1; +//! } +//! +//! return 0; +//! } +//! ``` +//! +//! If error happens during instruction emitting / encoding the assembler behaves +//! transactionally - the output buffer won't advance if encoding failed, thus +//! either a fully encoded instruction or nothing is emitted. The error handling +//! shown above is useful, but it's still not the best way of dealing with errors +//! in AsmJit. The following example shows how to use exception handling to handle +//! errors in a more C++ way: +//! +//! ``` +//! // Error Handling #2 - Throwing an exception. +//! #include <asmjit/x86.h> +//! #include <exception> +//! #include <string> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Error handler that throws a user-defined `AsmJitException`. +//! class AsmJitException : public std::exception { +//! public: +//! Error err; +//! std::string message; +//! +//! AsmJitException(Error err, const char* message) noexcept +//! : err(err), +//! message(message) {} +//! +//! const char* what() const noexcept override { return message.c_str(); } +//! }; +//! +//! class ThrowableErrorHandler : public ErrorHandler { +//! public: +//! // Throw is possible, functions that use ErrorHandler are never 'noexcept'. +//! void handleError(Error err, const char* message, BaseEmitter* origin) override { +//! throw AsmJitException(err, message); +//! } +//! }; +//! +//! int main() { +//! JitRuntime rt; +//! ThrowableErrorHandler eh; +//! +//! CodeHolder code; +//! code.init(rt.environment()); +//! code.setErrorHandler(&eh); +//! +//! x86::Assembler a(&code); +//! +//! // Try to emit instruction that doesn't exist. +//! try { +//! a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); +//! } +//! catch (const AsmJitException& ex) { +//! printf("EXCEPTION THROWN: %s\n", ex.what()); +//! return 1; +//! } +//! +//! return 0; +//! } +//! ``` +//! +//! If C++ exceptions are not what you like or your project turns off them +//! completely there is still a way of reducing the error handling to a minimum +//! by using a standard setjmp/longjmp approach. AsmJit is exception-safe and +//! cleans up everything before calling the ErrorHandler, so any approach is +//! safe. You can simply jump from the error handler without causing any +//! side-effects or memory leaks. The following example demonstrates how it +//! could be done: +//! +//! ``` +//! // Error Handling #3 - Using setjmp/longjmp if exceptions are not allowed. +//! #include <asmjit/x86.h> +//! #include <setjmp.h> +//! #include <stdio.h> +//! +//! class LongJmpErrorHandler : public asmjit::ErrorHandler { +//! public: +//! inline LongJmpErrorHandler() : err(asmjit::kErrorOk) {} +//! +//! void handleError(asmjit::Error err, const char* message, asmjit::BaseEmitter* origin) override { +//! this->err = err; +//! longjmp(state, 1); +//! } +//! +//! jmp_buf state; +//! asmjit::Error err; +//! }; +//! +//! int main(int argc, char* argv[]) { +//! using namespace asmjit; +//! +//! JitRuntime rt; +//! LongJmpErrorHandler eh; +//! +//! CodeHolder code; +//! code.init(rt.rt.environment()); +//! code.setErrorHandler(&eh); +//! +//! x86::Assembler a(&code); +//! +//! if (!setjmp(eh.state)) { +//! // Try to emit instruction that doesn't exist. +//! a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); +//! } +//! else { +//! Error err = eh.err; +//! printf("ASMJIT ERROR: 0x%08X [%s]\n", err, DebugUtils::errorAsString(err)); +//! } +//! +//! return 0; +//! } +//! ``` +class ASMJIT_VIRTAPI ErrorHandler { +public: + ASMJIT_BASE_CLASS(ErrorHandler) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Creates a new `ErrorHandler` instance. + ASMJIT_API ErrorHandler() noexcept; + //! Destroys the `ErrorHandler` instance. + ASMJIT_API virtual ~ErrorHandler() noexcept; + + // -------------------------------------------------------------------------- + // [Handle Error] + // -------------------------------------------------------------------------- + + //! Error handler (must be reimplemented). + //! + //! Error handler is called after an error happened and before it's propagated + //! to the caller. There are multiple ways how the error handler can be used: + //! + //! 1. User-based error handling without throwing exception or using C's + //! `longjmp()`. This is for users that don't use exceptions and want + //! customized error handling. + //! + //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely + //! exception-safe, but you can throw exception from your error handler if + //! this way is the preferred way of handling errors in your project. + //! + //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts + //! `BaseEmitter` to a consistent state before calling `handleError()` + //! so `longjmp()` can be used without any issues to cancel the code + //! generation if an error occurred. There is no difference between + //! exceptions and `longjmp()` from AsmJit's perspective, however, + //! never jump outside of `CodeHolder` and `BaseEmitter` scope as you + //! would leak memory. + virtual void handleError(Error err, const char* message, BaseEmitter* origin) = 0; +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_ERRORHANDLER_H_INCLUDED + diff --git a/3rdparty/asmjit/src/asmjit/core/features.h b/3rdparty/asmjit/src/asmjit/core/features.h index 193841c76c8..fd28472c91f 100644 --- a/3rdparty/asmjit/src/asmjit/core/features.h +++ b/3rdparty/asmjit/src/asmjit/core/features.h @@ -36,9 +36,15 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::BaseFeatures] // ============================================================================ +//! Base class that provides information about CPU features. +//! +//! Internally each feature is repreesnted by a single bit in an embedded +//! bit-array, however, feature bits are defined by an architecture specific +//! implementations, like \ref x86::Features. class BaseFeatures { public: typedef Support::BitWord BitWord; + typedef Support::BitVectorIterator<BitWord> Iterator; enum : uint32_t { kMaxFeatures = 128, @@ -74,9 +80,11 @@ public: //! \name Cast //! \{ + //! Casts this base class into a derived type `T`. template<typename T> inline T& as() noexcept { return static_cast<T&>(*this); } + //! Casts this base class into a derived type `T` (const). template<typename T> inline const T& as() const noexcept { return static_cast<const T&>(*this); } @@ -85,11 +93,27 @@ public: //! \name Accessors //! \{ - //! Returns all features as `BitWord` array. + inline bool empty() const noexcept { + for (uint32_t i = 0; i < kNumBitWords; i++) + if (_bits[i]) + return false; + return true; + } + + //! Returns all features as array of bitwords (see \ref Support::BitWord). inline BitWord* bits() noexcept { return _bits; } - //! Returns all features as `BitWord` array (const). + //! Returns all features as array of bitwords (const). inline const BitWord* bits() const noexcept { return _bits; } + //! Returns the number of BitWords returned by \ref bits(). + inline size_t bitWordCount() const noexcept { return kNumBitWords; } + + //! Returns \ref Support::BitVectorIterator, that can be used to iterate + //! all features efficiently + inline Iterator iterator() const noexcept { + return Iterator(_bits, kNumBitWords); + } + //! Tests whether the feature `featureId` is present. inline bool has(uint32_t featureId) const noexcept { ASMJIT_ASSERT(featureId < kMaxFeatures); diff --git a/3rdparty/asmjit/src/asmjit/core/formatter.cpp b/3rdparty/asmjit/src/asmjit/core/formatter.cpp new file mode 100644 index 00000000000..404edaf3820 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/formatter.cpp @@ -0,0 +1,469 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifndef ASMJIT_NO_LOGGING + +#include "../core/builder.h" +#include "../core/codeholder.h" +#include "../core/compiler.h" +#include "../core/emitter.h" +#include "../core/formatter.h" +#include "../core/string.h" +#include "../core/support.h" +#include "../core/type.h" + +#ifdef ASMJIT_BUILD_X86 + #include "../x86/x86formatter_p.h" +#endif + +#ifdef ASMJIT_BUILD_ARM + #include "../arm/armformatter_p.h" +#endif + +ASMJIT_BEGIN_NAMESPACE + +#if defined(ASMJIT_NO_COMPILER) +class VirtReg; +#endif + +// ============================================================================ +// [asmjit::Formatter] +// ============================================================================ + +namespace Formatter { + +Error formatTypeId(String& sb, uint32_t typeId) noexcept { + if (typeId == Type::kIdVoid) + return sb.append("void"); + + if (!Type::isValid(typeId)) + return sb.append("unknown"); + + const char* typeName = "unknown"; + uint32_t typeSize = Type::sizeOf(typeId); + + uint32_t baseId = Type::baseOf(typeId); + switch (baseId) { + case Type::kIdIntPtr : typeName = "iptr" ; break; + case Type::kIdUIntPtr: typeName = "uptr" ; break; + case Type::kIdI8 : typeName = "i8" ; break; + case Type::kIdU8 : typeName = "u8" ; break; + case Type::kIdI16 : typeName = "i16" ; break; + case Type::kIdU16 : typeName = "u16" ; break; + case Type::kIdI32 : typeName = "i32" ; break; + case Type::kIdU32 : typeName = "u32" ; break; + case Type::kIdI64 : typeName = "i64" ; break; + case Type::kIdU64 : typeName = "u64" ; break; + case Type::kIdF32 : typeName = "f32" ; break; + case Type::kIdF64 : typeName = "f64" ; break; + case Type::kIdF80 : typeName = "f80" ; break; + case Type::kIdMask8 : typeName = "mask8" ; break; + case Type::kIdMask16 : typeName = "mask16"; break; + case Type::kIdMask32 : typeName = "mask32"; break; + case Type::kIdMask64 : typeName = "mask64"; break; + case Type::kIdMmx32 : typeName = "mmx32" ; break; + case Type::kIdMmx64 : typeName = "mmx64" ; break; + } + + uint32_t baseSize = Type::sizeOf(baseId); + if (typeSize > baseSize) { + uint32_t count = typeSize / baseSize; + return sb.appendFormat("%sx%u", typeName, unsigned(count)); + } + else { + return sb.append(typeName); + } +} + +Error formatFeature( + String& sb, + uint32_t arch, + uint32_t featureId) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatFeature(sb, featureId); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatFeature(sb, featureId); +#endif + + return kErrorInvalidArch; +} + +Error formatLabel( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t labelId) noexcept { + + DebugUtils::unused(formatFlags); + + const LabelEntry* le = emitter->code()->labelEntry(labelId); + if (ASMJIT_UNLIKELY(!le)) + return sb.appendFormat("<InvalidLabel:%u>", labelId); + + if (le->hasName()) { + if (le->hasParent()) { + uint32_t parentId = le->parentId(); + const LabelEntry* pe = emitter->code()->labelEntry(parentId); + + if (ASMJIT_UNLIKELY(!pe)) + ASMJIT_PROPAGATE(sb.appendFormat("<InvalidLabel:%u>", labelId)); + else if (ASMJIT_UNLIKELY(!pe->hasName())) + ASMJIT_PROPAGATE(sb.appendFormat("L%u", parentId)); + else + ASMJIT_PROPAGATE(sb.append(pe->name())); + + ASMJIT_PROPAGATE(sb.append('.')); + } + return sb.append(le->name()); + } + else { + return sb.appendFormat("L%u", labelId); + } +} + +Error formatRegister( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + uint32_t regType, + uint32_t regId) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatRegister(sb, formatFlags, emitter, arch, regType, regId); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatRegister(sb, formatFlags, emitter, arch, regType, regId); +#endif + + return kErrorInvalidArch; +} + +Error formatOperand( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const Operand_& op) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatOperand(sb, formatFlags, emitter, arch, op); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatOperand(sb, formatFlags, emitter, arch, op); +#endif + + return kErrorInvalidArch; +} + +Error formatInstruction( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatInstruction(sb, formatFlags, emitter, arch, inst, operands, opCount); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatInstruction(sb, formatFlags, emitter, arch, inst, operands, opCount); +#endif + + return kErrorInvalidArch; +} + +#ifndef ASMJIT_NO_BUILDER +static Error formatFuncValue(String& sb, uint32_t formatFlags, const BaseEmitter* emitter, FuncValue value) noexcept { + uint32_t typeId = value.typeId(); + ASMJIT_PROPAGATE(formatTypeId(sb, typeId)); + + if (value.isAssigned()) { + ASMJIT_PROPAGATE(sb.append('@')); + + if (value.isIndirect()) + ASMJIT_PROPAGATE(sb.append('[')); + + // NOTE: It should be either reg or stack, but never both. We + // use two IFs on purpose so if the FuncValue is both it would + // show in logs. + if (value.isReg()) { + ASMJIT_PROPAGATE(formatRegister(sb, formatFlags, emitter, emitter->arch(), value.regType(), value.regId())); + } + + if (value.isStack()) { + ASMJIT_PROPAGATE(sb.appendFormat("[%d]", int(value.stackOffset()))); + } + + if (value.isIndirect()) + ASMJIT_PROPAGATE(sb.append(']')); + } + + return kErrorOk; +} + +static Error formatFuncRets( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + const FuncDetail& fd, + VirtReg* const* vRegs) noexcept { + + if (!fd.hasRet()) + return sb.append("void"); + + for (uint32_t i = 0; i < fd.retCount(); i++) { + if (i) ASMJIT_PROPAGATE(sb.append(", ")); + ASMJIT_PROPAGATE(formatFuncValue(sb, formatFlags, emitter, fd.ret(i))); + +#ifndef ASMJIT_NO_COMPILER + if (vRegs) { + static const char nullRet[] = "<none>"; + ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[i] ? vRegs[i]->name() : nullRet)); + } +#else + DebugUtils::unused(vRegs); +#endif + } + + return kErrorOk; +} + +static Error formatFuncArgs( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + const FuncDetail& fd, + VirtReg* const* vRegs) noexcept { + + uint32_t count = fd.argCount(); + if (!count) + return sb.append("void"); + + for (uint32_t i = 0; i < count; i++) { + if (i) + ASMJIT_PROPAGATE(sb.append(", ")); + + ASMJIT_PROPAGATE(formatFuncValue(sb, formatFlags, emitter, fd.arg(i))); + +#ifndef ASMJIT_NO_COMPILER + if (vRegs) { + static const char nullArg[] = "<none>"; + ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[i] ? vRegs[i]->name() : nullArg)); + } +#else + DebugUtils::unused(vRegs); +#endif + } + + return kErrorOk; +} + +Error formatNode( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* node) noexcept { + + if (node->hasPosition() && (formatFlags & FormatOptions::kFlagPositions) != 0) + ASMJIT_PROPAGATE(sb.appendFormat("<%05u> ", node->position())); + + switch (node->type()) { + case BaseNode::kNodeInst: + case BaseNode::kNodeJump: { + const InstNode* instNode = node->as<InstNode>(); + ASMJIT_PROPAGATE( + formatInstruction(sb, formatFlags, builder, + builder->arch(), + instNode->baseInst(), instNode->operands(), instNode->opCount())); + break; + } + + case BaseNode::kNodeSection: { + const SectionNode* sectionNode = node->as<SectionNode>(); + if (builder->_code->isSectionValid(sectionNode->id())) { + const Section* section = builder->_code->sectionById(sectionNode->id()); + ASMJIT_PROPAGATE(sb.appendFormat(".section %s", section->name())); + } + break; + } + + case BaseNode::kNodeLabel: { + const LabelNode* labelNode = node->as<LabelNode>(); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, labelNode->labelId())); + ASMJIT_PROPAGATE(sb.append(":")); + break; + } + + case BaseNode::kNodeAlign: { + const AlignNode* alignNode = node->as<AlignNode>(); + ASMJIT_PROPAGATE( + sb.appendFormat("align %u (%s)", + alignNode->alignment(), + alignNode->alignMode() == kAlignCode ? "code" : "data")); + break; + } + + case BaseNode::kNodeEmbedData: { + const EmbedDataNode* embedNode = node->as<EmbedDataNode>(); + ASMJIT_PROPAGATE(sb.append("embed ")); + if (embedNode->repeatCount() != 1) + ASMJIT_PROPAGATE(sb.appendFormat("[repeat=%zu] ", size_t(embedNode->repeatCount()))); + ASMJIT_PROPAGATE(sb.appendFormat("%u bytes", embedNode->dataSize())); + break; + } + + case BaseNode::kNodeEmbedLabel: { + const EmbedLabelNode* embedNode = node->as<EmbedLabelNode>(); + ASMJIT_PROPAGATE(sb.append(".label ")); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->labelId())); + break; + } + + case BaseNode::kNodeEmbedLabelDelta: { + const EmbedLabelDeltaNode* embedNode = node->as<EmbedLabelDeltaNode>(); + ASMJIT_PROPAGATE(sb.append(".label (")); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->labelId())); + ASMJIT_PROPAGATE(sb.append(" - ")); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->baseLabelId())); + ASMJIT_PROPAGATE(sb.append(")")); + break; + } + + case BaseNode::kNodeComment: { + const CommentNode* commentNode = node->as<CommentNode>(); + ASMJIT_PROPAGATE(sb.appendFormat("; %s", commentNode->inlineComment())); + break; + } + + case BaseNode::kNodeSentinel: { + const SentinelNode* sentinelNode = node->as<SentinelNode>(); + const char* sentinelName = nullptr; + + switch (sentinelNode->sentinelType()) { + case SentinelNode::kSentinelFuncEnd: + sentinelName = "[FuncEnd]"; + break; + + default: + sentinelName = "[Sentinel]"; + break; + } + + ASMJIT_PROPAGATE(sb.append(sentinelName)); + break; + } + +#ifndef ASMJIT_NO_COMPILER + case BaseNode::kNodeFunc: { + const FuncNode* funcNode = node->as<FuncNode>(); + + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, funcNode->labelId())); + ASMJIT_PROPAGATE(sb.append(": ")); + + ASMJIT_PROPAGATE(formatFuncRets(sb, formatFlags, builder, funcNode->detail(), nullptr)); + ASMJIT_PROPAGATE(sb.append(" Func(")); + ASMJIT_PROPAGATE(formatFuncArgs(sb, formatFlags, builder, funcNode->detail(), funcNode->args())); + ASMJIT_PROPAGATE(sb.append(")")); + break; + } + + case BaseNode::kNodeFuncRet: { + const FuncRetNode* retNode = node->as<FuncRetNode>(); + ASMJIT_PROPAGATE(sb.append("[FuncRet]")); + + for (uint32_t i = 0; i < 2; i++) { + const Operand_& op = retNode->_opArray[i]; + if (!op.isNone()) { + ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", ")); + ASMJIT_PROPAGATE(formatOperand(sb, formatFlags, builder, builder->arch(), op)); + } + } + break; + } + + case BaseNode::kNodeInvoke: { + const InvokeNode* invokeNode = node->as<InvokeNode>(); + ASMJIT_PROPAGATE( + formatInstruction(sb, formatFlags, builder, + builder->arch(), + invokeNode->baseInst(), invokeNode->operands(), invokeNode->opCount())); + break; + } +#endif + + default: { + ASMJIT_PROPAGATE(sb.appendFormat("[UserNode:%u]", node->type())); + break; + } + } + + return kErrorOk; +} + + +Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder) noexcept { + + return formatNodeList(sb, formatFlags, builder, builder->firstNode(), nullptr); +} + +Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* begin, + const BaseNode* end) noexcept { + + const BaseNode* node = begin; + while (node != end) { + ASMJIT_PROPAGATE(formatNode(sb, formatFlags, builder, node)); + ASMJIT_PROPAGATE(sb.append('\n')); + node = node->next(); + } + return kErrorOk; +} +#endif + +} // {Formatter} + +ASMJIT_END_NAMESPACE + +#endif diff --git a/3rdparty/asmjit/src/asmjit/core/formatter.h b/3rdparty/asmjit/src/asmjit/core/formatter.h new file mode 100644 index 00000000000..81d1c77ccdf --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/formatter.h @@ -0,0 +1,252 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_FORMATTER_H_INCLUDED +#define ASMJIT_CORE_FORMATTER_H_INCLUDED + +#include "../core/inst.h" +#include "../core/string.h" + +#ifndef ASMJIT_NO_LOGGING + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_logging +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class BaseEmitter; +struct Operand_; + +#ifndef ASMJIT_NO_BUILDER +class BaseBuilder; +class BaseNode; +#endif + +// ============================================================================ +// [asmjit::FormatOptions] +// ============================================================================ + +//! Formatting options used by \ref Logger and \ref Formatter. +class FormatOptions { +public: + //! Format flags, see \ref Flags. + uint32_t _flags; + //! Indentation by type, see \ref IndentationType. + uint8_t _indentation[4]; + + //! Flags can enable a logging feature. + enum Flags : uint32_t { + //! No flags. + kNoFlags = 0u, + + //! Show also binary form of each logged instruction (Assembler). + kFlagMachineCode = 0x00000001u, + //! Show a text explanation of some immediate values. + kFlagExplainImms = 0x00000002u, + //! Use hexadecimal notation of immediate values. + kFlagHexImms = 0x00000004u, + //! Use hexadecimal notation of address offsets. + kFlagHexOffsets = 0x00000008u, + //! Show casts between virtual register types (Compiler). + kFlagRegCasts = 0x00000010u, + //! Show positions associated with nodes (Compiler). + kFlagPositions = 0x00000020u, + //! Annotate nodes that are lowered by passes. + kFlagAnnotations = 0x00000040u, + + // TODO: These must go, keep this only for formatting. + //! Show an additional output from passes. + kFlagDebugPasses = 0x00000080u, + //! Show an additional output from RA. + kFlagDebugRA = 0x00000100u + }; + + //! Describes indentation type of code, label, or comment in logger output. + enum IndentationType : uint32_t { + //! Indentation used for instructions and directives. + kIndentationCode = 0u, + //! Indentation used for labels and function nodes. + kIndentationLabel = 1u, + //! Indentation used for comments (not inline comments). + kIndentationComment = 2u, + //! \cond INTERNAL + //! Reserved for future use. + kIndentationReserved = 3u + //! \endcond + }; + + //! \name Construction & Destruction + //! \{ + + //! Creates a default-initialized FormatOptions. + constexpr FormatOptions() noexcept + : _flags(0), + _indentation { 0, 0, 0, 0 } {} + + constexpr FormatOptions(const FormatOptions& other) noexcept = default; + inline FormatOptions& operator=(const FormatOptions& other) noexcept = default; + + //! Resets FormatOptions to its default initialized state. + inline void reset() noexcept { + _flags = 0; + _indentation[0] = 0; + _indentation[1] = 0; + _indentation[2] = 0; + _indentation[3] = 0; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns format flags. + constexpr uint32_t flags() const noexcept { return _flags; } + //! Tests whether the given `flag` is set in format flags. + constexpr bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + //! Resets all format flags to `flags`. + inline void setFlags(uint32_t flags) noexcept { _flags = flags; } + //! Adds `flags` to format flags. + inline void addFlags(uint32_t flags) noexcept { _flags |= flags; } + //! Removes `flags` from format flags. + inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } + + //! Returns indentation for the given `type`, see \ref IndentationType. + constexpr uint8_t indentation(uint32_t type) const noexcept { return _indentation[type]; } + //! Sets indentation for the given `type`, see \ref IndentationType. + inline void setIndentation(uint32_t type, uint32_t n) noexcept { _indentation[type] = uint8_t(n); } + //! Resets indentation for the given `type` to zero. + inline void resetIndentation(uint32_t type) noexcept { _indentation[type] = uint8_t(0); } + + //! \} +}; + +// ============================================================================ +// [asmjit::Formatter] +// ============================================================================ + +//! Provides formatting functionality to format operands, instructions, and nodes. +namespace Formatter { + +//! Appends a formatted `typeId` to the output string `sb`. +ASMJIT_API Error formatTypeId( + String& sb, + uint32_t typeId) noexcept; + +//! Appends a formatted `featureId` to the output string `sb`. +//! +//! See \ref BaseFeatures. +ASMJIT_API Error formatFeature( + String& sb, + uint32_t arch, + uint32_t featureId) noexcept; + +//! Appends a formatted register to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format virtual registers, +//! which won't be formatted properly if the `emitter` is not provided. +ASMJIT_API Error formatRegister( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + uint32_t regType, + uint32_t regId) noexcept; + +//! Appends a formatted label to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format named labels +//! properly, otherwise the formatted as it is an anonymous label. +ASMJIT_API Error formatLabel( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t labelId) noexcept; + +//! Appends a formatted operand to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format named labels and +//! virtual registers. See \ref formatRegister() and \ref formatLabel() for +//! more details. +ASMJIT_API Error formatOperand( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const Operand_& op) noexcept; + +//! Appends a formatted instruction to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format named labels and +//! virtual registers. See \ref formatRegister() and \ref formatLabel() for +//! more details. +ASMJIT_API Error formatInstruction( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept; + +#ifndef ASMJIT_NO_BUILDER +//! Appends a formatted node to the output string `sb`. +//! +//! The `node` must belong to the provided `builder`. +ASMJIT_API Error formatNode( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* node) noexcept; + +//! Appends formatted nodes to the output string `sb`. +//! +//! All nodes that are part of the given `builder` will be appended. +ASMJIT_API Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder) noexcept; + +//! Appends formatted nodes to the output string `sb`. +//! +//! This function works the same as \ref formatNode(), but appends more nodes +//! to the output string, separating each node with a newline '\n' character. +ASMJIT_API Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* begin, + const BaseNode* end) noexcept; +#endif + +} // {Formatter} + +//! \} + +ASMJIT_END_NAMESPACE + +#endif + +#endif // ASMJIT_CORE_FORMATTER_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/func.cpp b/3rdparty/asmjit/src/asmjit/core/func.cpp index 79eab2e83ad..514ae9db4e1 100644 --- a/3rdparty/asmjit/src/asmjit/core/func.cpp +++ b/3rdparty/asmjit/src/asmjit/core/func.cpp @@ -42,41 +42,41 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::FuncDetail - Init / Reset] // ============================================================================ -ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& sign) { - uint32_t ccId = sign.callConv(); - CallConv& cc = _callConv; +ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& signature, const Environment& environment) noexcept { + uint32_t ccId = signature.callConv(); + uint32_t argCount = signature.argCount(); - uint32_t argCount = sign.argCount(); if (ASMJIT_UNLIKELY(argCount > Globals::kMaxFuncArgs)) return DebugUtils::errored(kErrorInvalidArgument); - ASMJIT_PROPAGATE(cc.init(ccId)); + CallConv& cc = _callConv; + ASMJIT_PROPAGATE(cc.init(ccId, environment)); - uint32_t gpSize = (cc.archId() == ArchInfo::kIdX86) ? 4 : 8; - uint32_t deabstractDelta = Type::deabstractDeltaOfSize(gpSize); + uint32_t registerSize = Environment::registerSizeFromArch(cc.arch()); + uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize); - const uint8_t* args = sign.args(); + const uint8_t* args = signature.args(); for (uint32_t i = 0; i < argCount; i++) { FuncValue& arg = _args[i]; arg.initTypeId(Type::deabstract(args[i], deabstractDelta)); } _argCount = uint8_t(argCount); - _vaIndex = uint8_t(sign.vaIndex()); + _vaIndex = uint8_t(signature.vaIndex()); - uint32_t ret = sign.ret(); + uint32_t ret = signature.ret(); if (ret != Type::kIdVoid) { _rets[0].initTypeId(Type::deabstract(ret, deabstractDelta)); _retCount = 1; } #ifdef ASMJIT_BUILD_X86 - if (CallConv::isX86Family(ccId)) - return x86::X86Internal::initFuncDetail(*this, sign, gpSize); + if (environment.isFamilyX86()) + return x86::X86Internal::initFuncDetail(*this, signature, registerSize); #endif #ifdef ASMJIT_BUILD_ARM - if (CallConv::isArmFamily(ccId)) - return arm::ArmInternal::initFuncDetail(*this, sign, gpSize); + if (environment.isFamilyARM()) + return arm::ArmInternal::initFuncDetail(*this, signature, registerSize); #endif // We should never bubble here as if `cc.init()` succeeded then there has to @@ -89,15 +89,13 @@ ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& sign) { // ============================================================================ ASMJIT_FAVOR_SIZE Error FuncFrame::init(const FuncDetail& func) noexcept { - uint32_t ccId = func.callConv().id(); - #ifdef ASMJIT_BUILD_X86 - if (CallConv::isX86Family(ccId)) + if (Environment::isFamilyX86(func.callConv().arch())) return x86::X86Internal::initFuncFrame(*this, func); #endif #ifdef ASMJIT_BUILD_ARM - if (CallConv::isArmFamily(ccId)) + if (Environment::isFamilyARM(func.callConv().arch())) return arm::ArmInternal::initFuncFrame(*this, func); #endif @@ -106,12 +104,12 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::init(const FuncDetail& func) noexcept { ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept { #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId())) + if (Environment::isFamilyX86(arch())) return x86::X86Internal::finalizeFuncFrame(*this); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId())) + if (Environment::isFamilyARM(arch())) return arm::ArmInternal::finalizeFuncFrame(*this); #endif @@ -123,18 +121,19 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept { // ============================================================================ ASMJIT_FAVOR_SIZE Error FuncArgsAssignment::updateFuncFrame(FuncFrame& frame) const noexcept { + uint32_t arch = frame.arch(); const FuncDetail* func = funcDetail(); - if (!func) return DebugUtils::errored(kErrorInvalidState); - uint32_t ccId = func->callConv().id(); + if (!func) + return DebugUtils::errored(kErrorInvalidState); #ifdef ASMJIT_BUILD_X86 - if (CallConv::isX86Family(ccId)) + if (Environment::isFamilyX86(arch)) return x86::X86Internal::argsToFuncFrame(*this, frame); #endif #ifdef ASMJIT_BUILD_ARM - if (CallConv::isArmFamily(ccId)) + if (Environment::isFamilyARM(arch)) return arm::ArmInternal::argsToFuncFrame(*this, frame); #endif diff --git a/3rdparty/asmjit/src/asmjit/core/func.h b/3rdparty/asmjit/src/asmjit/core/func.h index 36ebf9bb526..9c45c1f8b3d 100644 --- a/3rdparty/asmjit/src/asmjit/core/func.h +++ b/3rdparty/asmjit/src/asmjit/core/func.h @@ -26,13 +26,14 @@ #include "../core/arch.h" #include "../core/callconv.h" +#include "../core/environment.h" #include "../core/operand.h" #include "../core/type.h" #include "../core/support.h" ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_func +//! \addtogroup asmjit_function //! \{ // ============================================================================ @@ -365,7 +366,7 @@ public: inline FuncDetail(const FuncDetail& other) noexcept = default; //! Initializes this `FuncDetail` to the given signature. - ASMJIT_API Error init(const FuncSignature& sign); + ASMJIT_API Error init(const FuncSignature& signature, const Environment& environment) noexcept; inline void reset() noexcept { memset(this, 0, sizeof(*this)); } //! \} @@ -472,12 +473,13 @@ public: //! frame. The function frame in most cases won't use all of the properties //! illustrated (for example Spill Zone and Red Zone are never used together). //! +//! ``` //! +-----------------------------+ //! | Arguments Passed by Stack | //! +-----------------------------+ //! | Spill Zone | //! +-----------------------------+ <- Stack offset (args) starts from here. -//! | Return Address if Pushed | +//! | Return Address, if Pushed | //! +-----------------------------+ <- Stack pointer (SP) upon entry. //! | Save/Restore Stack. | //! +-----------------------------+-----------------------------+ @@ -487,32 +489,42 @@ public: //! +-----------------------------+-----------------------------+ <- SP after prolog. //! | Red Zone | //! +-----------------------------+ +//! ``` class FuncFrame { public: enum Tag : uint32_t { - kTagInvalidOffset = 0xFFFFFFFFu //!< Tag used to inform that some offset is invalid. + //! Tag used to inform that some offset is invalid. + kTagInvalidOffset = 0xFFFFFFFFu }; //! Attributes are designed in a way that all are initially false, and user //! or FuncFrame finalizer adds them when necessary. enum Attributes : uint32_t { - kAttrHasVarArgs = 0x00000001u, //!< Function has variable number of arguments. - kAttrHasPreservedFP = 0x00000010u, //!< Preserve frame pointer (don't omit FP). - kAttrHasFuncCalls = 0x00000020u, //!< Function calls other functions (is not leaf). - - kAttrX86AvxEnabled = 0x00010000u, //!< Use AVX instead of SSE for all operations (X86). - kAttrX86AvxCleanup = 0x00020000u, //!< Emit VZEROUPPER instruction in epilog (X86). - kAttrX86MmxCleanup = 0x00040000u, //!< Emit EMMS instruction in epilog (X86). - - kAttrAlignedVecSR = 0x40000000u, //!< Function has aligned save/restore of vector registers. - kAttrIsFinalized = 0x80000000u //!< FuncFrame is finalized and can be used by PEI. + //! Function has variable number of arguments. + kAttrHasVarArgs = 0x00000001u, + //! Preserve frame pointer (don't omit FP). + kAttrHasPreservedFP = 0x00000010u, + //! Function calls other functions (is not leaf). + kAttrHasFuncCalls = 0x00000020u, + + //! Use AVX instead of SSE for all operations (X86). + kAttrX86AvxEnabled = 0x00010000u, + //! Emit VZEROUPPER instruction in epilog (X86). + kAttrX86AvxCleanup = 0x00020000u, + //! Emit EMMS instruction in epilog (X86). + kAttrX86MmxCleanup = 0x00040000u, + + //! Function has aligned save/restore of vector registers. + kAttrAlignedVecSR = 0x40000000u, + //! FuncFrame is finalized and can be used by PEI. + kAttrIsFinalized = 0x80000000u }; //! Function attributes. uint32_t _attributes; - //! Architecture ID. - uint8_t _archId; + //! Architecture, see \ref Environment::Arch. + uint8_t _arch; //! SP register ID (to access call stack and local stack). uint8_t _spRegId; //! SA register ID (to access stack arguments). @@ -591,7 +603,7 @@ public: //! \{ //! Returns the target architecture of the function frame. - inline uint32_t archId() const noexcept { return _archId; } + inline uint32_t arch() const noexcept { return _arch; } //! Returns function frame attributes, see `Attributes`. inline uint32_t attributes() const noexcept { return _attributes; } @@ -784,10 +796,8 @@ public: } inline void setAllDirty() noexcept { - _dirtyRegs[0] = 0xFFFFFFFFu; - _dirtyRegs[1] = 0xFFFFFFFFu; - _dirtyRegs[2] = 0xFFFFFFFFu; - _dirtyRegs[3] = 0xFFFFFFFFu; + for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_dirtyRegs); i++) + _dirtyRegs[i] = 0xFFFFFFFFu; } inline void setAllDirty(uint32_t group) noexcept { diff --git a/3rdparty/asmjit/src/asmjit/core/globals.cpp b/3rdparty/asmjit/src/asmjit/core/globals.cpp index 426fce8f533..7ec66283e80 100644 --- a/3rdparty/asmjit/src/asmjit/core/globals.cpp +++ b/3rdparty/asmjit/src/asmjit/core/globals.cpp @@ -33,75 +33,88 @@ ASMJIT_BEGIN_NAMESPACE ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept { #ifndef ASMJIT_NO_TEXT - static const char errorMessages[] = + // @EnumStringBegin{"enum": "ErrorCode", "output": "sError", "strip": "kError"}@ + static const char sErrorString[] = "Ok\0" - "Out of memory\0" - "Invalid argument\0" - "Invalid state\0" - "Invalid architecture\0" - "Not initialized\0" - "Already initialized\0" - "Feature not enabled\0" - "Too many handles or file descriptors\0" - "Too large (code or memory request)\0" - "No code generated\0" - "Invalid directive\0" - "Invalid label\0" - "Too many labels\0" - "Label already bound\0" - "Label already defined\0" - "Label name too long\0" - "Invalid label name\0" - "Invalid parent label\0" - "Non-local label can't have parent\0" - "Invalid section\0" - "Too many sections\0" - "Invalid section name\0" - "Too many relocations\0" - "Invalid relocation entry\0" - "Relocation offset out of range\0" - "Invalid assignment\0" - "Invalid instruction\0" - "Invalid register type\0" - "Invalid register group\0" - "Invalid register physical id\0" - "Invalid register virtual id\0" - "Invalid prefix combination\0" - "Invalid lock prefix\0" - "Invalid xacquire prefix\0" - "Invalid xrelease prefix\0" - "Invalid rep prefix\0" - "Invalid rex prefix\0" - "Invalid {...} register \0" - "Invalid use of {k}\0" - "Invalid use of {k}{z}\0" - "Invalid broadcast {1tox}\0" - "Invalid {er} or {sae} option\0" - "Invalid address\0" - "Invalid address index\0" - "Invalid address scale\0" - "Invalid use of 64-bit address or offset\0" - "Invalid use of 64-bit address or offset that requires 32-bit zero-extension\0" - "Invalid displacement\0" - "Invalid segment\0" - "Invalid immediate value\0" - "Invalid operand size\0" - "Ambiguous operand size\0" - "Operand size mismatch\0" - "Invalid option\0" - "Option already defined\0" - "Invalid type-info\0" - "Invalid use of a low 8-bit GPB register\0" - "Invalid use of a 64-bit GPQ register in 32-bit mode\0" - "Invalid use of an 80-bit float\0" - "Not consecutive registers\0" - "No more physical registers\0" - "Overlapped registers\0" - "Overlapping register and arguments base-address register\0" - "Unbound label cannot be evaluated by expression\0" - "Arithmetic overflow during expression evaluation\0" - "Unknown error\0"; - return Support::findPackedString(errorMessages, Support::min<Error>(err, kErrorCount)); + "OutOfMemory\0" + "InvalidArgument\0" + "InvalidState\0" + "InvalidArch\0" + "NotInitialized\0" + "AlreadyInitialized\0" + "FeatureNotEnabled\0" + "TooManyHandles\0" + "TooLarge\0" + "NoCodeGenerated\0" + "InvalidDirective\0" + "InvalidLabel\0" + "TooManyLabels\0" + "LabelAlreadyBound\0" + "LabelAlreadyDefined\0" + "LabelNameTooLong\0" + "InvalidLabelName\0" + "InvalidParentLabel\0" + "NonLocalLabelCannotHaveParent\0" + "InvalidSection\0" + "TooManySections\0" + "InvalidSectionName\0" + "TooManyRelocations\0" + "InvalidRelocEntry\0" + "RelocOffsetOutOfRange\0" + "InvalidAssignment\0" + "InvalidInstruction\0" + "InvalidRegType\0" + "InvalidRegGroup\0" + "InvalidPhysId\0" + "InvalidVirtId\0" + "InvalidPrefixCombination\0" + "InvalidLockPrefix\0" + "InvalidXAcquirePrefix\0" + "InvalidXReleasePrefix\0" + "InvalidRepPrefix\0" + "InvalidRexPrefix\0" + "InvalidExtraReg\0" + "InvalidKMaskUse\0" + "InvalidKZeroUse\0" + "InvalidBroadcast\0" + "InvalidEROrSAE\0" + "InvalidAddress\0" + "InvalidAddressIndex\0" + "InvalidAddressScale\0" + "InvalidAddress64Bit\0" + "InvalidAddress64BitZeroExtension\0" + "InvalidDisplacement\0" + "InvalidSegment\0" + "InvalidImmediate\0" + "InvalidOperandSize\0" + "AmbiguousOperandSize\0" + "OperandSizeMismatch\0" + "InvalidOption\0" + "OptionAlreadyDefined\0" + "InvalidTypeId\0" + "InvalidUseOfGpbHi\0" + "InvalidUseOfGpq\0" + "InvalidUseOfF80\0" + "NotConsecutiveRegs\0" + "IllegalVirtReg\0" + "TooManyVirtRegs\0" + "NoMorePhysRegs\0" + "OverlappedRegs\0" + "OverlappingStackRegWithRegArg\0" + "ExpressionLabelNotBound\0" + "ExpressionOverflow\0" + "<Unknown>\0"; + + static const uint16_t sErrorIndex[] = { + 0, 3, 15, 31, 44, 56, 71, 90, 108, 123, 132, 148, 165, 178, 192, 210, 230, + 247, 264, 283, 313, 328, 344, 363, 382, 400, 422, 440, 459, 474, 490, 504, + 518, 543, 561, 583, 605, 622, 639, 655, 671, 687, 704, 719, 734, 754, 774, + 794, 827, 847, 862, 879, 898, 919, 939, 953, 974, 988, 1006, 1022, 1038, + 1057, 1072, 1088, 1103, 1118, 1148, 1172, 1191 + }; + // @EnumStringEnd@ + + return sErrorString + sErrorIndex[Support::min<Error>(err, kErrorCount)]; #else DebugUtils::unused(err); static const char noMessage[] = ""; diff --git a/3rdparty/asmjit/src/asmjit/core/globals.h b/3rdparty/asmjit/src/asmjit/core/globals.h index 6373b7e8c6a..67a8769a403 100644 --- a/3rdparty/asmjit/src/asmjit/core/globals.h +++ b/3rdparty/asmjit/src/asmjit/core/globals.h @@ -33,7 +33,7 @@ ASMJIT_BEGIN_NAMESPACE // ============================================================================ //! \cond INTERNAL -//! \addtogroup Support +//! \addtogroup asmjit_utilities //! \{ namespace Support { //! Cast designed to cast between function and void* pointers. @@ -88,9 +88,9 @@ constexpr uint32_t kAllocAlignment = 8; //! Aggressive growing strategy threshold. constexpr uint32_t kGrowThreshold = 1024 * 1024 * 16; -//! Maximum height of RB-Tree is: +//! Maximum depth of RB-Tree is: //! -//! `2 * log2(n + 1)`. +//! `2 * log2(n + 1)` //! //! Size of RB node is at least two pointers (without data), //! so a theoretical architecture limit would be: @@ -104,7 +104,7 @@ constexpr uint32_t kMaxTreeHeight = (ASMJIT_ARCH_BITS == 32 ? 30 : 61) + 1; //! Maximum number of operands per a single instruction. constexpr uint32_t kMaxOpCount = 6; -// TODO: Use this one. +//! Maximum arguments of a function supported by the Compiler / Function API. constexpr uint32_t kMaxFuncArgs = 16; //! Maximum number of physical registers AsmJit can use per register group. @@ -169,14 +169,45 @@ static const constexpr NoInit_ NoInit {}; } // {Globals} // ============================================================================ +// [asmjit::ByteOrder] +// ============================================================================ + +//! Byte order. +namespace ByteOrder { + enum : uint32_t { + kLE = 0, + kBE = 1, + kNative = ASMJIT_ARCH_LE ? kLE : kBE, + kSwapped = ASMJIT_ARCH_LE ? kBE : kLE + }; +} + +// ============================================================================ +// [asmjit::ptr_as_func / func_as_ptr] +// ============================================================================ + +template<typename Func> +static inline Func ptr_as_func(void* func) noexcept { return Support::ptr_cast_impl<Func, void*>(func); } + +template<typename Func> +static inline void* func_as_ptr(Func func) noexcept { return Support::ptr_cast_impl<void*, Func>(func); } + +//! \} + +// ============================================================================ // [asmjit::Error] // ============================================================================ +//! \addtogroup asmjit_error_handling +//! \{ + //! AsmJit error type (uint32_t). typedef uint32_t Error; //! AsmJit error codes. enum ErrorCode : uint32_t { + // @EnumValuesBegin{"enum": "ErrorCode"}@ + //! No error (success). kErrorOk = 0, @@ -211,16 +242,16 @@ enum ErrorCode : uint32_t { //! No code generated. //! - //! Returned by runtime if the `CodeHolder` contains no code. + //! Returned by runtime if the \ref CodeHolder contains no code. kErrorNoCodeGenerated, //! Invalid directive. kErrorInvalidDirective, //! Attempt to use uninitialized label. kErrorInvalidLabel, - //! Label index overflow - a single `Assembler` instance can hold almost - //! 2^32 (4 billion) labels. If there is an attempt to create more labels - //! then this error is returned. + //! Label index overflow - a single \ref BaseAssembler instance can hold + //! almost 2^32 (4 billion) labels. If there is an attempt to create more + //! labels then this error is returned. kErrorTooManyLabels, //! Label is already bound. kErrorLabelAlreadyBound, @@ -230,10 +261,10 @@ enum ErrorCode : uint32_t { kErrorLabelNameTooLong, //! Label must always be local if it's anonymous (without a name). kErrorInvalidLabelName, - //! Parent id passed to `CodeHolder::newNamedLabelId()` was invalid. + //! Parent id passed to \ref CodeHolder::newNamedLabelEntry() was invalid. kErrorInvalidParentLabel, //! Parent id specified for a non-local (global) label. - kErrorNonLocalLabelCantHaveParent, + kErrorNonLocalLabelCannotHaveParent, //! Invalid section. kErrorInvalidSection, @@ -257,9 +288,9 @@ enum ErrorCode : uint32_t { kErrorInvalidRegType, //! Invalid register group. kErrorInvalidRegGroup, - //! Invalid register's physical id. + //! Invalid physical register id. kErrorInvalidPhysId, - //! Invalid register's virtual id. + //! Invalid virtual register id. kErrorInvalidVirtId, //! Invalid prefix combination. kErrorInvalidPrefixCombination, @@ -319,11 +350,17 @@ enum ErrorCode : uint32_t { kErrorInvalidUseOfGpbHi, //! Invalid use of a 64-bit GPQ register in 32-bit mode. kErrorInvalidUseOfGpq, - //! Invalid use of an 80-bit float (Type::kIdF80). + //! Invalid use of an 80-bit float (\ref Type::kIdF80). kErrorInvalidUseOfF80, - //! Some registers in the instruction muse be consecutive (some ARM and AVX512 neural-net instructions). + //! Some registers in the instruction muse be consecutive (some ARM and AVX512 + //! neural-net instructions). kErrorNotConsecutiveRegs, + //! Illegal virtual register - reported by instruction validation. + kErrorIllegalVirtReg, + //! AsmJit cannot create more virtual registers. + kErrorTooManyVirtRegs, + //! AsmJit requires a physical register, but no one is available. kErrorNoMorePhysRegs, //! A variable has been assigned more than once to a function argument (BaseCompiler). @@ -336,43 +373,24 @@ enum ErrorCode : uint32_t { //! Arithmetic overflow during expression evaluation. kErrorExpressionOverflow, + // @EnumValuesEnd@ + //! Count of AsmJit error codes. kErrorCount }; // ============================================================================ -// [asmjit::ByteOrder] -// ============================================================================ - -//! Byte order. -namespace ByteOrder { - enum : uint32_t { - kLE = 0, - kBE = 1, - kNative = ASMJIT_ARCH_LE ? kLE : kBE, - kSwapped = ASMJIT_ARCH_LE ? kBE : kLE - }; -} - -// ============================================================================ -// [asmjit::ptr_as_func / func_as_ptr] -// ============================================================================ - -template<typename Func> -static inline Func ptr_as_func(void* func) noexcept { return Support::ptr_cast_impl<Func, void*>(func); } -template<typename Func> -static inline void* func_as_ptr(Func func) noexcept { return Support::ptr_cast_impl<void*, Func>(func); } - -// ============================================================================ // [asmjit::DebugUtils] // ============================================================================ //! Debugging utilities. namespace DebugUtils { +//! \cond INTERNAL //! Used to silence warnings about unused arguments or variables. template<typename... Args> static ASMJIT_INLINE void unused(Args&&...) noexcept {} +//! \endcond //! Returns the error `err` passed. //! @@ -392,23 +410,35 @@ ASMJIT_API void debugOutput(const char* str) noexcept; //! \param line Line in the source file. //! \param msg Message to display. //! -//! If you have problems with assertions put a breakpoint at assertionFailed() -//! function (asmjit/core/globals.cpp) and check the call stack to locate the -//! failing code. +//! If you have problems with assertion failures a breakpoint can be put +//! at \ref assertionFailed() function (asmjit/core/globals.cpp). A call stack +//! will be available when such assertion failure is triggered. AsmJit always +//! returns errors on failures, assertions are a last resort and usually mean +//! unrecoverable state due to out of range array access or totally invalid +//! arguments like nullptr where a valid pointer should be provided, etc... ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept; +} // {DebugUtils} + +//! \def ASMJIT_ASSERT(...) +//! +//! AsmJit's own assert macro used in AsmJit code-base. #if defined(ASMJIT_BUILD_DEBUG) -#define ASMJIT_ASSERT(EXP) \ +#define ASMJIT_ASSERT(...) \ do { \ - if (ASMJIT_LIKELY(EXP)) \ + if (ASMJIT_LIKELY(__VA_ARGS__)) \ break; \ - ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #EXP); \ + ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #__VA_ARGS__); \ } while (0) #else -#define ASMJIT_ASSERT(EXP) ((void)0) +#define ASMJIT_ASSERT(...) ((void)0) #endif -//! Used by AsmJit to propagate a possible `Error` produced by `...` to the caller. +//! \def ASMJIT_PROPAGATE(...) +//! +//! Propagates a possible `Error` produced by `...` to the caller by returning +//! the error immediately. Used by AsmJit internally, but kept public for users +//! that want to use the same technique to propagate errors to the caller. #define ASMJIT_PROPAGATE(...) \ do { \ ::asmjit::Error _err = __VA_ARGS__; \ @@ -416,8 +446,6 @@ ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, cons return _err; \ } while (0) -} // {DebugUtils} - //! \} ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/inst.cpp b/3rdparty/asmjit/src/asmjit/core/inst.cpp index d89c29f1917..a233b9383bf 100644 --- a/3rdparty/asmjit/src/asmjit/core/inst.cpp +++ b/3rdparty/asmjit/src/asmjit/core/inst.cpp @@ -42,29 +42,29 @@ ASMJIT_BEGIN_NAMESPACE // ============================================================================ #ifndef ASMJIT_NO_TEXT -Error InstAPI::instIdToString(uint32_t archId, uint32_t instId, String& output) noexcept { +Error InstAPI::instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept { #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::InstInternal::instIdToString(archId, instId, output); + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::instIdToString(arch, instId, output); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::InstInternal::instIdToString(archId, instId, output); + if (Environment::isFamilyARM(arch)) + return arm::InstInternal::instIdToString(arch, instId, output); #endif return DebugUtils::errored(kErrorInvalidArch); } -uint32_t InstAPI::stringToInstId(uint32_t archId, const char* s, size_t len) noexcept { +uint32_t InstAPI::stringToInstId(uint32_t arch, const char* s, size_t len) noexcept { #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::InstInternal::stringToInstId(archId, s, len); + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::stringToInstId(arch, s, len); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::InstInternal::stringToInstId(archId, s, len); + if (Environment::isFamilyARM(arch)) + return arm::InstInternal::stringToInstId(arch, s, len); #endif return 0; @@ -76,15 +76,15 @@ uint32_t InstAPI::stringToInstId(uint32_t archId, const char* s, size_t len) noe // ============================================================================ #ifndef ASMJIT_NO_VALIDATION -Error InstAPI::validate(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept { +Error InstAPI::validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags) noexcept { #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::InstInternal::validate(archId, inst, operands, opCount); + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::validate(arch, inst, operands, opCount, validationFlags); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::InstInternal::validate(archId, inst, operands, opCount); + if (Environment::isFamilyARM(arch)) + return arm::InstInternal::validate(arch, inst, operands, opCount, validationFlags); #endif return DebugUtils::errored(kErrorInvalidArch); @@ -96,18 +96,18 @@ Error InstAPI::validate(uint32_t archId, const BaseInst& inst, const Operand_* o // ============================================================================ #ifndef ASMJIT_NO_INTROSPECTION -Error InstAPI::queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, InstRWInfo& out) noexcept { - if (ASMJIT_UNLIKELY(opCount > 6)) +Error InstAPI::queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept { + if (ASMJIT_UNLIKELY(opCount > Globals::kMaxOpCount)) return DebugUtils::errored(kErrorInvalidArgument); #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::InstInternal::queryRWInfo(archId, inst, operands, opCount, out); + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::queryRWInfo(arch, inst, operands, opCount, out); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::InstInternal::queryRWInfo(archId, inst, operands, opCount, out); + if (Environment::isFamilyARM(arch)) + return arm::InstInternal::queryRWInfo(arch, inst, operands, opCount, out); #endif return DebugUtils::errored(kErrorInvalidArch); @@ -119,15 +119,15 @@ Error InstAPI::queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_ // ============================================================================ #ifndef ASMJIT_NO_INTROSPECTION -Error InstAPI::queryFeatures(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, BaseFeatures& out) noexcept { +Error InstAPI::queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept { #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::InstInternal::queryFeatures(archId, inst, operands, opCount, out); + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::queryFeatures(arch, inst, operands, opCount, out); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::InstInternal::queryFeatures(archId, inst, operands, opCount, out); + if (Environment::isFamilyARM(arch)) + return arm::InstInternal::queryFeatures(arch, inst, operands, opCount, out); #endif return DebugUtils::errored(kErrorInvalidArch); diff --git a/3rdparty/asmjit/src/asmjit/core/inst.h b/3rdparty/asmjit/src/asmjit/core/inst.h index 91671822043..e34f93c87f1 100644 --- a/3rdparty/asmjit/src/asmjit/core/inst.h +++ b/3rdparty/asmjit/src/asmjit/core/inst.h @@ -31,45 +31,173 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_core +//! \addtogroup asmjit_instruction_db //! \{ // ============================================================================ -// [asmjit::InstInfo] +// [asmjit::BaseInst] // ============================================================================ -// TODO: Finalize instruction info and make more x86::InstDB methods/structs private. +//! Instruction id, options, and extraReg in a single structure. This structure +//! exists mainly to simplify analysis and validation API that requires `BaseInst` +//! and `Operand[]` array. +class BaseInst { +public: + //! Instruction id, see \ref BaseInst::Id or {arch-specific}::Inst::Id. + uint32_t _id; + //! Instruction options, see \ref BaseInst::Options or {arch-specific}::Inst::Options. + uint32_t _options; + //! Extra register used by instruction (either REP register or AVX-512 selector). + RegOnly _extraReg; -/* + enum Id : uint32_t { + //! Invalid or uninitialized instruction id. + kIdNone = 0x00000000u, + //! Abstract instruction (BaseBuilder and BaseCompiler). + kIdAbstract = 0x80000000u + }; + + enum Options : uint32_t { + //! Used internally by emitters for handling errors and rare cases. + kOptionReserved = 0x00000001u, + + //! Prevents following a jump during compilation (BaseCompiler). + kOptionUnfollow = 0x00000010u, -struct InstInfo { - //! Architecture agnostic attributes. - enum Attributes : uint32_t { + //! Overwrite the destination operand(s) (BaseCompiler). + //! + //! Hint that is important for register liveness analysis. It tells the + //! compiler that the destination operand will be overwritten now or by + //! adjacent instructions. BaseCompiler knows when a register is completely + //! overwritten by a single instruction, for example you don't have to + //! mark "movaps" or "pxor x, x", however, if a pair of instructions is + //! used and the first of them doesn't completely overwrite the content + //! of the destination, BaseCompiler fails to mark that register as dead. + //! + //! X86 Specific + //! ------------ + //! + //! - All instructions that always overwrite at least the size of the + //! register the virtual-register uses , for example "mov", "movq", + //! "movaps" don't need the overwrite option to be used - conversion, + //! shuffle, and other miscellaneous instructions included. + //! + //! - All instructions that clear the destination register if all operands + //! are the same, for example "xor x, x", "pcmpeqb x x", etc... + //! + //! - Consecutive instructions that partially overwrite the variable until + //! there is no old content require `BaseCompiler::overwrite()` to be used. + //! Some examples (not always the best use cases thought): + //! + //! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa + //! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa + //! - `mov al, ?` followed by `and ax, 0xFF` + //! - `mov al, ?` followed by `mov ah, al` + //! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1` + //! + //! - If allocated variable is used temporarily for scalar operations. For + //! example if you allocate a full vector like `x86::Compiler::newXmm()` + //! and then use that vector for scalar operations you should use + //! `overwrite()` directive: + //! + //! - `sqrtss x, y` - only LO element of `x` is changed, if you don't + //! use HI elements, use `compiler.overwrite().sqrtss(x, y)`. + kOptionOverwrite = 0x00000020u, + //! Emit short-form of the instruction. + kOptionShortForm = 0x00000040u, + //! Emit long-form of the instruction. + kOptionLongForm = 0x00000080u, + //! Conditional jump is likely to be taken. + kOptionTaken = 0x00000100u, + //! Conditional jump is unlikely to be taken. + kOptionNotTaken = 0x00000200u }; - //! Instruction attributes. - uint32_t _attributes; + //! Control type. + enum ControlType : uint32_t { + //! No control type (doesn't jump). + kControlNone = 0u, + //! Unconditional jump. + kControlJump = 1u, + //! Conditional jump (branch). + kControlBranch = 2u, + //! Function call. + kControlCall = 3u, + //! Function return. + kControlReturn = 4u + }; - inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + //! \name Construction & Destruction + //! \{ - inline uint32_t attributes() const noexcept { return _attributes; } - inline bool hasAttribute(uint32_t attr) const noexcept { return (_attributes & attr) != 0; } -}; + //! Creates a new BaseInst instance with `id` and `options` set. + //! + //! Default values of `id` and `options` are zero, which means none instruciton. + //! Such instruction is guaranteed to never exist for any architecture supported + //! by AsmJit. + inline explicit BaseInst(uint32_t id = 0, uint32_t options = 0) noexcept + : _id(id), + _options(options), + _extraReg() {} + + inline BaseInst(uint32_t id, uint32_t options, const RegOnly& extraReg) noexcept + : _id(id), + _options(options), + _extraReg(extraReg) {} + + inline BaseInst(uint32_t id, uint32_t options, const BaseReg& extraReg) noexcept + : _id(id), + _options(options), + _extraReg { extraReg.signature(), extraReg.id() } {} + + //! \} -//! Gets attributes of the given instruction. -ASMJIT_API Error queryCommonInfo(uint32_t archId, uint32_t instId, InstInfo& out) noexcept; + //! \name Instruction ID + //! \{ + + //! Returns the instruction id. + inline uint32_t id() const noexcept { return _id; } + //! Sets the instruction id to the given `id`. + inline void setId(uint32_t id) noexcept { _id = id; } + //! Resets the instruction id to zero, see \ref kIdNone. + inline void resetId() noexcept { _id = 0; } + + //! \} -*/ + //! \name Instruction Options + //! \{ + + inline uint32_t options() const noexcept { return _options; } + inline bool hasOption(uint32_t option) const noexcept { return (_options & option) != 0; } + inline void setOptions(uint32_t options) noexcept { _options = options; } + inline void addOptions(uint32_t options) noexcept { _options |= options; } + inline void clearOptions(uint32_t options) noexcept { _options &= ~options; } + inline void resetOptions() noexcept { _options = 0; } + + //! \} + + //! \name Extra Register + //! \{ + + inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); } + inline RegOnly& extraReg() noexcept { return _extraReg; } + inline const RegOnly& extraReg() const noexcept { return _extraReg; } + inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); } + inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); } + inline void resetExtraReg() noexcept { _extraReg.reset(); } + + //! \} +}; // ============================================================================ -// [asmjit::InstRWInfo / OpRWInfo] +// [asmjit::OpRWInfo] // ============================================================================ -//! Read/Write information related to a single operand, used by `InstRWInfo`. +//! Read/Write information related to a single operand, used by \ref InstRWInfo. struct OpRWInfo { - //! Read/Write flags, see `OpRWInfo::Flags`. + //! Read/Write flags, see \ref OpRWInfo::Flags. uint32_t _opFlags; //! Physical register index, if required. uint8_t _physId; @@ -87,18 +215,12 @@ struct OpRWInfo { //! Flags describe how the operand is accessed and some additional information. enum Flags : uint32_t { //! Operand is read. - //! - //! \note This flag must be `0x00000001`. kRead = 0x00000001u, //! Operand is written. - //! - //! \note This flag must be `0x00000002`. kWrite = 0x00000002u, //! Operand is both read and written. - //! - //! \note This combination of flags must be `0x00000003`. kRW = 0x00000003u, //! Register operand can be replaced by a memory operand. @@ -107,9 +229,9 @@ struct OpRWInfo { //! The `extendByteMask()` represents a zero extension. kZExt = 0x00000010u, - //! Register operand must use `physId()`. + //! Register operand must use \ref physId(). kRegPhysId = 0x00000100u, - //! Base register of a memory operand must use `physId()`. + //! Base register of a memory operand must use \ref physId(). kMemPhysId = 0x00000200u, //! This memory operand is only used to encode registers and doesn't access memory. @@ -140,6 +262,8 @@ struct OpRWInfo { kMemBasePostModify = 0x00020000u }; + // Don't remove these asserts. Read/Write flags are used extensively + // by Compiler and they must always be compatible with constants below. static_assert(kRead == 0x1, "OpRWInfo::kRead flag must be 0x1"); static_assert(kWrite == 0x2, "OpRWInfo::kWrite flag must be 0x2"); static_assert(kRegMem == 0x4, "OpRWInfo::kRegMem flag must be 0x4"); @@ -147,7 +271,11 @@ struct OpRWInfo { //! \name Reset //! \{ + //! Resets this operand information to all zeros. inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + + //! Resets this operand info (resets all members) and set common information + //! to the given `opFlags`, `regSize`, and possibly `physId`. inline void reset(uint32_t opFlags, uint32_t regSize, uint32_t physId = BaseReg::kIdBad) noexcept { _opFlags = opFlags; _physId = uint8_t(physId); @@ -169,35 +297,96 @@ struct OpRWInfo { //! \name Operand Flags //! \{ + //! Returns operand flags, see \ref Flags. inline uint32_t opFlags() const noexcept { return _opFlags; } + //! Tests whether operand flags contain the given `flag`. inline bool hasOpFlag(uint32_t flag) const noexcept { return (_opFlags & flag) != 0; } + //! Adds the given `flags` to operand flags. inline void addOpFlags(uint32_t flags) noexcept { _opFlags |= flags; } + //! Removes the given `flags` from operand flags. inline void clearOpFlags(uint32_t flags) noexcept { _opFlags &= ~flags; } + //! Tests whether this operand is read from. inline bool isRead() const noexcept { return hasOpFlag(kRead); } + //! Tests whether this operand is written to. inline bool isWrite() const noexcept { return hasOpFlag(kWrite); } + //! Tests whether this operand is both read and write. inline bool isReadWrite() const noexcept { return (_opFlags & kRW) == kRW; } + //! Tests whether this operand is read only. inline bool isReadOnly() const noexcept { return (_opFlags & kRW) == kRead; } + //! Tests whether this operand is write only. inline bool isWriteOnly() const noexcept { return (_opFlags & kRW) == kWrite; } + + //! Tests whether this operand is Reg/Mem + //! + //! Reg/Mem operands can use either register or memory. inline bool isRm() const noexcept { return hasOpFlag(kRegMem); } + + //! Tests whether the operand will be zero extended. inline bool isZExt() const noexcept { return hasOpFlag(kZExt); } //! \} + //! \name Memory Flags + //! \{ + + //! Tests whether this is a fake memory operand, which is only used, because + //! of encoding. Fake memory operands do not access any memory, they are only + //! used to encode registers. + inline bool isMemFake() const noexcept { return hasOpFlag(kMemFake); } + + //! Tests whether the instruction reads from its BASE registers. + inline bool isMemBaseRead() const noexcept { return hasOpFlag(kMemBaseRead); } + //! Tests whether the instruction writes to its BASE registers. + inline bool isMemBaseWrite() const noexcept { return hasOpFlag(kMemBaseWrite); } + //! Tests whether the instruction reads and writes from/to its BASE registers. + inline bool isMemBaseReadWrite() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseRW; } + //! Tests whether the instruction only reads from its BASE registers. + inline bool isMemBaseReadOnly() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseRead; } + //! Tests whether the instruction only writes to its BASE registers. + inline bool isMemBaseWriteOnly() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseWrite; } + + //! Tests whether the instruction modifies the BASE register before it uses + //! it to calculate the target address. + inline bool isMemBasePreModify() const noexcept { return hasOpFlag(kMemBasePreModify); } + //! Tests whether the instruction modifies the BASE register after it uses + //! it to calculate the target address. + inline bool isMemBasePostModify() const noexcept { return hasOpFlag(kMemBasePostModify); } + + //! Tests whether the instruction reads the INDEX registers. + inline bool isMemIndexRead() const noexcept { return hasOpFlag(kMemIndexRead); } + //! Tests whether the instruction writes to its INDEX registers. + inline bool isMemIndexWrite() const noexcept { return hasOpFlag(kMemIndexWrite); } + //! Tests whether the instruction reads and writes from/to its INDEX registers. + inline bool isMemIndexReadWrite() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexRW; } + //! Tests whether the instruction only reads from its INDEX registers. + inline bool isMemIndexReadOnly() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexRead; } + //! Tests whether the instruction only writes to its INDEX registers. + inline bool isMemIndexWriteOnly() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexWrite; } + + //! \} + //! \name Physical Register ID //! \{ + //! Returns a physical id of the register that is fixed for this operand. + //! + //! Returns \ref BaseReg::kIdBad if any register can be used. inline uint32_t physId() const noexcept { return _physId; } + //! Tests whether \ref physId() would return a valid physical register id. inline bool hasPhysId() const noexcept { return _physId != BaseReg::kIdBad; } + //! Sets physical register id, which would be fixed for this operand. inline void setPhysId(uint32_t physId) noexcept { _physId = uint8_t(physId); } //! \} - //! \name Reg/Mem + //! \name Reg/Mem Information //! \{ + //! Returns Reg/Mem size of the operand. inline uint32_t rmSize() const noexcept { return _rmSize; } + //! Sets Reg/Mem size of the operand. inline void setRmSize(uint32_t rmSize) noexcept { _rmSize = uint8_t(rmSize); } //! \} @@ -205,46 +394,76 @@ struct OpRWInfo { //! \name Read & Write Masks //! \{ + //! Returns read mask. inline uint64_t readByteMask() const noexcept { return _readByteMask; } + //! Returns write mask. inline uint64_t writeByteMask() const noexcept { return _writeByteMask; } + //! Returns extend mask. inline uint64_t extendByteMask() const noexcept { return _extendByteMask; } + //! Sets read mask. inline void setReadByteMask(uint64_t mask) noexcept { _readByteMask = mask; } + //! Sets write mask. inline void setWriteByteMask(uint64_t mask) noexcept { _writeByteMask = mask; } + //! Sets externd mask. inline void setExtendByteMask(uint64_t mask) noexcept { _extendByteMask = mask; } //! \} }; +// ============================================================================ +// [asmjit::InstRWInfo] +// ============================================================================ + //! Read/Write information of an instruction. struct InstRWInfo { - //! Instruction flags. + //! Instruction flags (there are no flags at the moment, this field is reserved). uint32_t _instFlags; - //! Mask of flags read. + //! Mask of CPU flags read. uint32_t _readFlags; - //! Mask of flags written. + //! Mask of CPU flags written. uint32_t _writeFlags; //! Count of operands. uint8_t _opCount; //! CPU feature required for replacing register operand with memory operand. uint8_t _rmFeature; //! Reserved for future use. - uint8_t _reserved[19]; + uint8_t _reserved[18]; //! Read/Write onfo of extra register (rep{} or kz{}). OpRWInfo _extraReg; //! Read/Write info of instruction operands. OpRWInfo _operands[Globals::kMaxOpCount]; + //! \name Commons + //! \{ + + //! Resets this RW information to all zeros. inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + //! \} + + //! \name Instruction Flags + //! + //! \{ + inline uint32_t instFlags() const noexcept { return _instFlags; } inline bool hasInstFlag(uint32_t flag) const noexcept { return (_instFlags & flag) != 0; } - inline uint32_t opCount() const noexcept { return _opCount; } + //! } + //! \name CPU Flags Read/Write Information + //! \{ + + //! Returns read flags of the instruction. inline uint32_t readFlags() const noexcept { return _readFlags; } + //! Returns write flags of the instruction. inline uint32_t writeFlags() const noexcept { return _writeFlags; } + //! \} + + //! \name Reg/Mem Information + //! \{ + //! Returns the CPU feature required to replace a register operand with memory //! operand. If the returned feature is zero (none) then this instruction //! either doesn't provide memory operand combination or there is no extra @@ -259,166 +478,25 @@ struct InstRWInfo { //! 'reg/mem/imm' combination. inline uint32_t rmFeature() const noexcept { return _rmFeature; } + //! \} + + //! \name Operand Read/Write Information + //! \{ + + //! Returns RW information of extra register operand (extraReg). inline const OpRWInfo& extraReg() const noexcept { return _extraReg; } + + //! Returns RW information of all instruction's operands. inline const OpRWInfo* operands() const noexcept { return _operands; } + //! Returns RW information of the operand at the given `index`. inline const OpRWInfo& operand(size_t index) const noexcept { ASMJIT_ASSERT(index < Globals::kMaxOpCount); return _operands[index]; } -}; - -// ============================================================================ -// [asmjit::BaseInst] -// ============================================================================ - -//! Instruction id, options, and extraReg in a single structure. This structure -//! exists mainly to simplify analysis and validation API that requires `BaseInst` -//! and `Operand[]` array. -class BaseInst { -public: - //! Instruction id. - uint32_t _id; - //! Instruction options. - uint32_t _options; - //! Extra register used by instruction (either REP register or AVX-512 selector). - RegOnly _extraReg; - - enum Id : uint32_t { - //! Invalid or uninitialized instruction id. - kIdNone = 0x00000000u, - //! Abstract instruction (BaseBuilder and BaseCompiler). - kIdAbstract = 0x80000000u - }; - - enum Options : uint32_t { - //! Used internally by emitters for handling errors and rare cases. - kOptionReserved = 0x00000001u, - - //! Used only by Assembler to mark that `_op4` and `_op5` are used (internal). - //! - //! TODO: This should be removed in the future. - kOptionOp4Op5Used = 0x00000002u, - - //! Prevents following a jump during compilation (BaseCompiler). - //! - //! TODO: This should be renamed to kOptionNoReturn. - kOptionUnfollow = 0x00000010u, - - //! Overwrite the destination operand(s) (BaseCompiler). - //! - //! Hint that is important for register liveness analysis. It tells the - //! compiler that the destination operand will be overwritten now or by - //! adjacent instructions. BaseCompiler knows when a register is completely - //! overwritten by a single instruction, for example you don't have to - //! mark "movaps" or "pxor x, x", however, if a pair of instructions is - //! used and the first of them doesn't completely overwrite the content - //! of the destination, BaseCompiler fails to mark that register as dead. - //! - //! X86 Specific - //! ------------ - //! - //! - All instructions that always overwrite at least the size of the - //! register the virtual-register uses , for example "mov", "movq", - //! "movaps" don't need the overwrite option to be used - conversion, - //! shuffle, and other miscellaneous instructions included. - //! - //! - All instructions that clear the destination register if all operands - //! are the same, for example "xor x, x", "pcmpeqb x x", etc... - //! - //! - Consecutive instructions that partially overwrite the variable until - //! there is no old content require `BaseCompiler::overwrite()` to be used. - //! Some examples (not always the best use cases thought): - //! - //! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa - //! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa - //! - `mov al, ?` followed by `and ax, 0xFF` - //! - `mov al, ?` followed by `mov ah, al` - //! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1` - //! - //! - If allocated variable is used temporarily for scalar operations. For - //! example if you allocate a full vector like `x86::Compiler::newXmm()` - //! and then use that vector for scalar operations you should use - //! `overwrite()` directive: - //! - //! - `sqrtss x, y` - only LO element of `x` is changed, if you don't - //! use HI elements, use `compiler.overwrite().sqrtss(x, y)`. - kOptionOverwrite = 0x00000020u, - - //! Emit short-form of the instruction. - kOptionShortForm = 0x00000040u, - //! Emit long-form of the instruction. - kOptionLongForm = 0x00000080u, - - //! Conditional jump is likely to be taken. - kOptionTaken = 0x00000100u, - //! Conditional jump is unlikely to be taken. - kOptionNotTaken = 0x00000200u - }; - - //! Control type. - enum ControlType : uint32_t { - //! No control type (doesn't jump). - kControlNone = 0u, - //! Unconditional jump. - kControlJump = 1u, - //! Conditional jump (branch). - kControlBranch = 2u, - //! Function call. - kControlCall = 3u, - //! Function return. - kControlReturn = 4u - }; - - //! \name Construction & Destruction - //! \{ - inline explicit BaseInst(uint32_t id = 0, uint32_t options = 0) noexcept - : _id(id), - _options(options), - _extraReg() {} - - inline BaseInst(uint32_t id, uint32_t options, const RegOnly& extraReg) noexcept - : _id(id), - _options(options), - _extraReg(extraReg) {} - - inline BaseInst(uint32_t id, uint32_t options, const BaseReg& extraReg) noexcept - : _id(id), - _options(options), - _extraReg { extraReg.signature(), extraReg.id() } {} - - //! \} - - //! \name Instruction ID - //! \{ - - inline uint32_t id() const noexcept { return _id; } - inline void setId(uint32_t id) noexcept { _id = id; } - inline void resetId() noexcept { _id = 0; } - - //! \} - - //! \name Instruction Options - //! \{ - - inline uint32_t options() const noexcept { return _options; } - inline void setOptions(uint32_t options) noexcept { _options = options; } - inline void addOptions(uint32_t options) noexcept { _options |= options; } - inline void clearOptions(uint32_t options) noexcept { _options &= ~options; } - inline void resetOptions() noexcept { _options = 0; } - - //! \} - - //! \name Extra Register - //! \{ - - inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); } - inline RegOnly& extraReg() noexcept { return _extraReg; } - inline const RegOnly& extraReg() const noexcept { return _extraReg; } - inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); } - inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); } - inline void resetExtraReg() noexcept { _extraReg.reset(); } + //! Returns the number of operands this instruction has. + inline uint32_t opCount() const noexcept { return _opCount; } //! \} }; @@ -430,6 +508,12 @@ public: //! Instruction API. namespace InstAPI { +//! Validation flags that can be used with \ref InstAPI::validate(). +enum ValidationFlags : uint32_t { + //! Allow virtual registers in the instruction. + kValidationFlagVirtRegs = 0x01u +}; + #ifndef ASMJIT_NO_TEXT //! Appends the name of the instruction specified by `instId` and `instOptions` //! into the `output` string. @@ -437,27 +521,29 @@ namespace InstAPI { //! \note Instruction options would only affect instruction prefix & suffix, //! other options would be ignored. If `instOptions` is zero then only raw //! instruction name (without any additional text) will be appended. -ASMJIT_API Error instIdToString(uint32_t archId, uint32_t instId, String& output) noexcept; +ASMJIT_API Error instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept; //! Parses an instruction name in the given string `s`. Length is specified //! by `len` argument, which can be `SIZE_MAX` if `s` is known to be null //! terminated. //! -//! The output is stored in `instId`. -ASMJIT_API uint32_t stringToInstId(uint32_t archId, const char* s, size_t len) noexcept; +//! Returns the parsed instruction id or \ref BaseInst::kIdNone if no such +//! instruction exists. +ASMJIT_API uint32_t stringToInstId(uint32_t arch, const char* s, size_t len) noexcept; #endif // !ASMJIT_NO_TEXT #ifndef ASMJIT_NO_VALIDATION -//! Validates the given instruction. -ASMJIT_API Error validate(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept; +//! Validates the given instruction considering the validation `flags`, see +//! \ref ValidationFlags. +ASMJIT_API Error validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags = 0) noexcept; #endif // !ASMJIT_NO_VALIDATION #ifndef ASMJIT_NO_INTROSPECTION //! Gets Read/Write information of the given instruction. -ASMJIT_API Error queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, InstRWInfo& out) noexcept; +ASMJIT_API Error queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept; //! Gets CPU features required by the given instruction. -ASMJIT_API Error queryFeatures(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, BaseFeatures& out) noexcept; +ASMJIT_API Error queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept; #endif // !ASMJIT_NO_INTROSPECTION } // {InstAPI} diff --git a/3rdparty/asmjit/src/asmjit/core/jitallocator.cpp b/3rdparty/asmjit/src/asmjit/core/jitallocator.cpp index a8ca0c3d75a..b2285113d3d 100644 --- a/3rdparty/asmjit/src/asmjit/core/jitallocator.cpp +++ b/3rdparty/asmjit/src/asmjit/core/jitallocator.cpp @@ -26,7 +26,7 @@ #include "../core/arch.h" #include "../core/jitallocator.h" -#include "../core/osutils.h" +#include "../core/osutils_p.h" #include "../core/support.h" #include "../core/virtmem.h" #include "../core/zone.h" @@ -938,7 +938,7 @@ public: // Helper class to verify that JitAllocator doesn't return addresses that overlap. class JitAllocatorWrapper { public: - explicit inline JitAllocatorWrapper(const JitAllocator::CreateParams* params) noexcept + inline explicit JitAllocatorWrapper(const JitAllocator::CreateParams* params) noexcept : _zone(1024 * 1024), _heap(&_zone), _allocator(params) {} diff --git a/3rdparty/asmjit/src/asmjit/core/jitallocator.h b/3rdparty/asmjit/src/asmjit/core/jitallocator.h index 111716ed59e..9cd0a1f7b7e 100644 --- a/3rdparty/asmjit/src/asmjit/core/jitallocator.h +++ b/3rdparty/asmjit/src/asmjit/core/jitallocator.h @@ -32,7 +32,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_jit +//! \addtogroup asmjit_virtual_memory //! \{ // ============================================================================ @@ -132,9 +132,6 @@ public: //! JitAllocator allocator(¶ms); //! ``` struct CreateParams { - // Reset the content of `CreateParams`. - inline void reset() noexcept { memset(this, 0, sizeof(*this)); } - //! Allocator options, see \ref JitAllocator::Options. //! //! No options are used by default. @@ -161,6 +158,9 @@ public: //! //! Only used if \ref kOptionCustomFillPattern is set. uint32_t fillPattern; + + // Reset the content of `CreateParams`. + inline void reset() noexcept { memset(this, 0, sizeof(*this)); } }; //! Creates a `JitAllocator` instance. @@ -221,6 +221,15 @@ public: //! Statistics about `JitAllocator`. struct Statistics { + //! Number of blocks `JitAllocator` maintains. + size_t _blockCount; + //! How many bytes are currently used / allocated. + size_t _usedSize; + //! How many bytes are currently reserved by the allocator. + size_t _reservedSize; + //! Allocation overhead (in bytes) required to maintain all blocks. + size_t _overheadSize; + inline void reset() noexcept { _blockCount = 0; _usedSize = 0; @@ -251,15 +260,6 @@ public: inline double overheadSizeAsPercent() const noexcept { return (double(overheadSize()) / (double(reservedSize()) + 1e-16)) * 100.0; } - - //! Number of blocks `JitAllocator` maintains. - size_t _blockCount; - //! How many bytes are currently used / allocated. - size_t _usedSize; - //! How many bytes are currently reserved by the allocator. - size_t _reservedSize; - //! Allocation overhead (in bytes) required to maintain all blocks. - size_t _overheadSize; }; //! Returns JIT allocator statistics. diff --git a/3rdparty/asmjit/src/asmjit/core/jitruntime.cpp b/3rdparty/asmjit/src/asmjit/core/jitruntime.cpp index 625cc3d2f51..1127c866aad 100644 --- a/3rdparty/asmjit/src/asmjit/core/jitruntime.cpp +++ b/3rdparty/asmjit/src/asmjit/core/jitruntime.cpp @@ -43,52 +43,16 @@ static inline void JitRuntime_flushInstructionCache(const void* p, size_t size) #endif } -// X86 Target -// ---------- -// -// - 32-bit - Linux, OSX, BSD, and apparently also Haiku guarantee 16-byte -// stack alignment. Other operating systems are assumed to have -// 4-byte alignment by default for safety reasons. -// - 64-bit - stack must be aligned to 16 bytes. -// -// ARM Target -// ---------- -// -// - 32-bit - Stack must be aligned to 8 bytes. -// - 64-bit - Stack must be aligned to 16 bytes (hardware requirement). -static inline uint32_t JitRuntime_detectNaturalStackAlignment() noexcept { -#if ASMJIT_ARCH_BITS == 64 || \ - defined(__APPLE__ ) || \ - defined(__DragonFly__) || \ - defined(__HAIKU__ ) || \ - defined(__FreeBSD__ ) || \ - defined(__NetBSD__ ) || \ - defined(__OpenBSD__ ) || \ - defined(__bsdi__ ) || \ - defined(__linux__ ) - return 16; -#elif ASMJIT_ARCH_ARM - return 8; -#else - return uint32_t(sizeof(uintptr_t)); -#endif -} - // ============================================================================ // [asmjit::JitRuntime - Construction / Destruction] // ============================================================================ JitRuntime::JitRuntime(const JitAllocator::CreateParams* params) noexcept : _allocator(params) { - - // Setup target properties. - _targetType = kTargetJit; - _codeInfo._archInfo = CpuInfo::host().archInfo(); - _codeInfo._stackAlignment = uint8_t(JitRuntime_detectNaturalStackAlignment()); - _codeInfo._cdeclCallConv = CallConv::kIdHostCDecl; - _codeInfo._stdCallConv = CallConv::kIdHostStdCall; - _codeInfo._fastCallConv = CallConv::kIdHostFastCall; + _environment = hostEnvironment(); + _environment.setFormat(Environment::kFormatJIT); } + JitRuntime::~JitRuntime() noexcept {} // ============================================================================ diff --git a/3rdparty/asmjit/src/asmjit/core/jitruntime.h b/3rdparty/asmjit/src/asmjit/core/jitruntime.h index 97f26e7a6c1..91880e688c0 100644 --- a/3rdparty/asmjit/src/asmjit/core/jitruntime.h +++ b/3rdparty/asmjit/src/asmjit/core/jitruntime.h @@ -35,7 +35,7 @@ ASMJIT_BEGIN_NAMESPACE class CodeHolder; -//! \addtogroup asmjit_jit +//! \addtogroup asmjit_virtual_memory //! \{ // ============================================================================ diff --git a/3rdparty/asmjit/src/asmjit/core/logger.cpp b/3rdparty/asmjit/src/asmjit/core/logger.cpp new file mode 100644 index 00000000000..22e0b9af08a --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/logger.cpp @@ -0,0 +1,124 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifndef ASMJIT_NO_LOGGING + +#include "../core/logger.h" +#include "../core/string.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::Logger - Construction / Destruction] +// ============================================================================ + +Logger::Logger() noexcept + : _options() {} +Logger::~Logger() noexcept {} + +// ============================================================================ +// [asmjit::Logger - Logging] +// ============================================================================ + +Error Logger::logf(const char* fmt, ...) noexcept { + Error err; + va_list ap; + + va_start(ap, fmt); + err = logv(fmt, ap); + va_end(ap); + + return err; +} + +Error Logger::logv(const char* fmt, va_list ap) noexcept { + StringTmp<2048> sb; + ASMJIT_PROPAGATE(sb.appendVFormat(fmt, ap)); + return log(sb); +} + +Error Logger::logBinary(const void* data, size_t size) noexcept { + static const char prefix[] = "db "; + + StringTmp<256> sb; + sb.append(prefix, ASMJIT_ARRAY_SIZE(prefix) - 1); + + size_t i = size; + const uint8_t* s = static_cast<const uint8_t*>(data); + + while (i) { + uint32_t n = uint32_t(Support::min<size_t>(i, 16)); + sb.truncate(ASMJIT_ARRAY_SIZE(prefix) - 1); + sb.appendHex(s, n); + sb.append('\n'); + ASMJIT_PROPAGATE(log(sb)); + s += n; + i -= n; + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::FileLogger - Construction / Destruction] +// ============================================================================ + +FileLogger::FileLogger(FILE* file) noexcept + : _file(file) {} +FileLogger::~FileLogger() noexcept {} + +// ============================================================================ +// [asmjit::FileLogger - Logging] +// ============================================================================ + +Error FileLogger::_log(const char* data, size_t size) noexcept { + if (!_file) + return kErrorOk; + + if (size == SIZE_MAX) + size = strlen(data); + + fwrite(data, 1, size, _file); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::StringLogger - Construction / Destruction] +// ============================================================================ + +StringLogger::StringLogger() noexcept {} +StringLogger::~StringLogger() noexcept {} + +// ============================================================================ +// [asmjit::StringLogger - Logging] +// ============================================================================ + +Error StringLogger::_log(const char* data, size_t size) noexcept { + return _content.append(data, size); +} + +ASMJIT_END_NAMESPACE + +#endif diff --git a/3rdparty/asmjit/src/asmjit/core/logging.h b/3rdparty/asmjit/src/asmjit/core/logger.h index 468e3a1ba2b..2840869b476 100644 --- a/3rdparty/asmjit/src/asmjit/core/logging.h +++ b/3rdparty/asmjit/src/asmjit/core/logger.h @@ -26,119 +26,28 @@ #include "../core/inst.h" #include "../core/string.h" - -ASMJIT_BEGIN_NAMESPACE - -//! \addtogroup asmjit_core -//! \{ +#include "../core/formatter.h" #ifndef ASMJIT_NO_LOGGING -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -class BaseEmitter; -class BaseReg; -class Logger; -struct Operand_; - -#ifndef ASMJIT_NO_BUILDER -class BaseBuilder; -class BaseNode; -#endif - -// ============================================================================ -// [asmjit::FormatOptions] -// ============================================================================ - -class FormatOptions { -public: - uint32_t _flags; - uint8_t _indentation[4]; - - enum Flags : uint32_t { - //! Show also binary form of each logged instruction (assembler). - kFlagMachineCode = 0x00000001u, - //! Show a text explanation of some immediate values. - kFlagExplainImms = 0x00000002u, - //! Use hexadecimal notation of immediate values. - kFlagHexImms = 0x00000004u, - //! Use hexadecimal notation of address offsets. - kFlagHexOffsets = 0x00000008u, - //! Show casts between virtual register types (compiler). - kFlagRegCasts = 0x00000010u, - //! Show positions associated with nodes (compiler). - kFlagPositions = 0x00000020u, - //! Annotate nodes that are lowered by passes. - kFlagAnnotations = 0x00000040u, - - // TODO: These must go, keep this only for formatting. - //! Show an additional output from passes. - kFlagDebugPasses = 0x00000080u, - //! Show an additional output from RA. - kFlagDebugRA = 0x00000100u - }; - - enum IndentationType : uint32_t { - //! Indentation used for instructions and directives. - kIndentationCode = 0u, - //! Indentation used for labels and function nodes. - kIndentationLabel = 1u, - //! Indentation used for comments (not inline comments). - kIndentationComment = 2u, - kIndentationReserved = 3u - }; - - //! \name Construction & Destruction - //! \{ - - constexpr FormatOptions() noexcept - : _flags(0), - _indentation { 0, 0, 0, 0 } {} - - constexpr FormatOptions(const FormatOptions& other) noexcept = default; - inline FormatOptions& operator=(const FormatOptions& other) noexcept = default; - - inline void reset() noexcept { - _flags = 0; - _indentation[0] = 0; - _indentation[1] = 0; - _indentation[2] = 0; - _indentation[3] = 0; - } - - //! \} - - //! \name Accessors - //! \{ - - constexpr uint32_t flags() const noexcept { return _flags; } - constexpr bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } - inline void setFlags(uint32_t flags) noexcept { _flags = flags; } - inline void addFlags(uint32_t flags) noexcept { _flags |= flags; } - inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } - - constexpr uint8_t indentation(uint32_t type) const noexcept { return _indentation[type]; } - inline void setIndentation(uint32_t type, uint32_t n) noexcept { _indentation[type] = uint8_t(n); } - inline void resetIndentation(uint32_t type) noexcept { _indentation[type] = uint8_t(0); } +ASMJIT_BEGIN_NAMESPACE - //! \} -}; +//! \addtogroup asmjit_logging +//! \{ // ============================================================================ // [asmjit::Logger] // ============================================================================ -//! Abstract logging interface and helpers. +//! Logging interface. //! -//! This class can be inherited and reimplemented to fit into your logging -//! subsystem. When reimplementing use `Logger::_log()` method to log into -//! a custom stream. +//! This class can be inherited and reimplemented to fit into your own logging +//! needs. When reimplementing a logger use \ref Logger::_log() method to log +//! customize the output. //! //! There are two `Logger` implementations offered by AsmJit: -//! - `FileLogger` - allows to log into `FILE*`. -//! - `StringLogger` - logs into a `String`. +//! - \ref FileLogger - logs into a `FILE*`. +//! - \ref StringLogger - concatenates all logs into a \ref String. class ASMJIT_VIRTAPI Logger { public: ASMJIT_BASE_CLASS(Logger) @@ -160,17 +69,28 @@ public: //! \name Format Options //! \{ + //! Returns \ref FormatOptions of this logger. inline FormatOptions& options() noexcept { return _options; } + //! \overload inline const FormatOptions& options() const noexcept { return _options; } + //! Returns formatting flags, see \ref FormatOptions::Flags. inline uint32_t flags() const noexcept { return _options.flags(); } + //! Tests whether the logger has the given `flag` enabled. inline bool hasFlag(uint32_t flag) const noexcept { return _options.hasFlag(flag); } + //! Sets formatting flags to `flags`, see \ref FormatOptions::Flags. inline void setFlags(uint32_t flags) noexcept { _options.setFlags(flags); } + //! Enables the given formatting `flags`, see \ref FormatOptions::Flags. inline void addFlags(uint32_t flags) noexcept { _options.addFlags(flags); } + //! Disables the given formatting `flags`, see \ref FormatOptions::Flags. inline void clearFlags(uint32_t flags) noexcept { _options.clearFlags(flags); } + //! Returns indentation of `type`, see \ref FormatOptions::IndentationType. inline uint32_t indentation(uint32_t type) const noexcept { return _options.indentation(type); } + //! Sets indentation of the given indentation `type` to `n` spaces, see \ref + //! FormatOptions::IndentationType. inline void setIndentation(uint32_t type, uint32_t n) noexcept { _options.setIndentation(type, n); } + //! Resets indentation of the given indentation `type` to 0 spaces. inline void resetIndentation(uint32_t type) noexcept { _options.resetIndentation(type); } //! \} @@ -179,6 +99,11 @@ public: //! \{ //! Logs `str` - must be reimplemented. + //! + //! The function can accept either a null terminated string if `size` is + //! `SIZE_MAX` or a non-null terminated string of the given `size`. The + //! function cannot assume that the data is null terminated and must handle + //! non-null terminated inputs. virtual Error _log(const char* data, size_t size) noexcept = 0; //! Logs string `str`, which is either null terminated or having size `size`. @@ -186,15 +111,15 @@ public: //! Logs content of a string `str`. inline Error log(const String& str) noexcept { return _log(str.data(), str.size()); } - //! Formats the message by using `snprintf()` and then sends the result - //! to `log()`. + //! Formats the message by using `snprintf()` and then passes the formatted + //! string to \ref _log(). ASMJIT_API Error logf(const char* fmt, ...) noexcept; - //! Formats the message by using `vsnprintf()` and then sends the result - //! to `log()`. + //! Formats the message by using `vsnprintf()` and then passes the formatted + //! string to \ref _log(). ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept; - //! Logs binary data. + //! Logs binary `data` of the given `size`. ASMJIT_API Error logBinary(const void* data, size_t size) noexcept; //! \} @@ -267,6 +192,13 @@ public: //! \name Logger Data Accessors //! \{ + //! Returns the content of the logger as \ref String. + //! + //! It can be moved, if desired. + inline String& content() noexcept { return _content; } + //! \overload + inline const String& content() const noexcept { return _content; } + //! Returns aggregated logger data as `char*` pointer. //! //! The pointer is owned by `StringLogger`, it can't be modified or freed. @@ -287,69 +219,10 @@ public: ASMJIT_API Error _log(const char* data, size_t size = SIZE_MAX) noexcept override; }; -// ============================================================================ -// [asmjit::Logging] -// ============================================================================ - -struct Logging { - ASMJIT_API static Error formatRegister( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - uint32_t regType, - uint32_t regId) noexcept; - - ASMJIT_API static Error formatLabel( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t labelId) noexcept; - - ASMJIT_API static Error formatOperand( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const Operand_& op) noexcept; - - ASMJIT_API static Error formatInstruction( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept; - - ASMJIT_API static Error formatTypeId( - String& sb, - uint32_t typeId) noexcept; - -#ifndef ASMJIT_NO_BUILDER - ASMJIT_API static Error formatNode( - String& sb, - uint32_t flags, - const BaseBuilder* cb, - const BaseNode* node_) noexcept; -#endif - - // Only used by AsmJit internals, not available to users. -#ifdef ASMJIT_EXPORTS - enum { - // Has to be big to be able to hold all metadata compiler can assign to a - // single instruction. - kMaxInstLineSize = 44, - kMaxBinarySize = 26 - }; - - static Error formatLine( - String& sb, - const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept; -#endif -}; -#endif - //! \} ASMJIT_END_NAMESPACE +#endif + #endif // ASMJIT_CORE_LOGGER_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/logging.cpp b/3rdparty/asmjit/src/asmjit/core/logging.cpp deleted file mode 100644 index 7e10af27c2d..00000000000 --- a/3rdparty/asmjit/src/asmjit/core/logging.cpp +++ /dev/null @@ -1,535 +0,0 @@ -// AsmJit - Machine code generation for C++ -// -// * Official AsmJit Home Page: https://asmjit.com -// * Official Github Repository: https://github.com/asmjit/asmjit -// -// Copyright (c) 2008-2020 The AsmJit Authors -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -#include "../core/api-build_p.h" -#ifndef ASMJIT_NO_LOGGING - -#include "../core/builder.h" -#include "../core/codeholder.h" -#include "../core/compiler.h" -#include "../core/emitter.h" -#include "../core/logging.h" -#include "../core/string.h" -#include "../core/support.h" -#include "../core/type.h" - -#ifdef ASMJIT_BUILD_X86 - #include "../x86/x86logging_p.h" -#endif - -#ifdef ASMJIT_BUILD_ARM - #include "../arm/armlogging_p.h" -#endif - -ASMJIT_BEGIN_NAMESPACE - -#if defined(ASMJIT_NO_COMPILER) -class VirtReg; -#endif - -// ============================================================================ -// [asmjit::Logger - Construction / Destruction] -// ============================================================================ - -Logger::Logger() noexcept - : _options() {} -Logger::~Logger() noexcept {} - -// ============================================================================ -// [asmjit::Logger - Logging] -// ============================================================================ - -Error Logger::logf(const char* fmt, ...) noexcept { - Error err; - va_list ap; - - va_start(ap, fmt); - err = logv(fmt, ap); - va_end(ap); - - return err; -} - -Error Logger::logv(const char* fmt, va_list ap) noexcept { - StringTmp<2048> sb; - ASMJIT_PROPAGATE(sb.appendVFormat(fmt, ap)); - return log(sb); -} - -Error Logger::logBinary(const void* data, size_t size) noexcept { - static const char prefix[] = "db "; - - StringTmp<256> sb; - sb.appendString(prefix, ASMJIT_ARRAY_SIZE(prefix) - 1); - - size_t i = size; - const uint8_t* s = static_cast<const uint8_t*>(data); - - while (i) { - uint32_t n = uint32_t(Support::min<size_t>(i, 16)); - sb.truncate(ASMJIT_ARRAY_SIZE(prefix) - 1); - sb.appendHex(s, n); - sb.appendChar('\n'); - ASMJIT_PROPAGATE(log(sb)); - s += n; - i -= n; - } - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::FileLogger - Construction / Destruction] -// ============================================================================ - -FileLogger::FileLogger(FILE* file) noexcept - : _file(nullptr) { setFile(file); } -FileLogger::~FileLogger() noexcept {} - -// ============================================================================ -// [asmjit::FileLogger - Logging] -// ============================================================================ - -Error FileLogger::_log(const char* data, size_t size) noexcept { - if (!_file) - return kErrorOk; - - if (size == SIZE_MAX) - size = strlen(data); - - fwrite(data, 1, size, _file); - return kErrorOk; -} - -// ============================================================================ -// [asmjit::StringLogger - Construction / Destruction] -// ============================================================================ - -StringLogger::StringLogger() noexcept {} -StringLogger::~StringLogger() noexcept {} - -// ============================================================================ -// [asmjit::StringLogger - Logging] -// ============================================================================ - -Error StringLogger::_log(const char* data, size_t size) noexcept { - return _content.appendString(data, size); -} - -// ============================================================================ -// [asmjit::Logging] -// ============================================================================ - -Error Logging::formatLabel( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t labelId) noexcept { - - DebugUtils::unused(flags); - - const LabelEntry* le = emitter->code()->labelEntry(labelId); - if (ASMJIT_UNLIKELY(!le)) - return sb.appendFormat("InvalidLabel[Id=%u]", labelId); - - if (le->hasName()) { - if (le->hasParent()) { - uint32_t parentId = le->parentId(); - const LabelEntry* pe = emitter->code()->labelEntry(parentId); - - if (ASMJIT_UNLIKELY(!pe)) - ASMJIT_PROPAGATE(sb.appendFormat("InvalidLabel[Id=%u]", labelId)); - else if (ASMJIT_UNLIKELY(!pe->hasName())) - ASMJIT_PROPAGATE(sb.appendFormat("L%u", parentId)); - else - ASMJIT_PROPAGATE(sb.appendString(pe->name())); - - ASMJIT_PROPAGATE(sb.appendChar('.')); - } - return sb.appendString(le->name()); - } - else { - return sb.appendFormat("L%u", labelId); - } -} - -Error Logging::formatRegister( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - uint32_t regType, - uint32_t regId) noexcept { - -#ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::LoggingInternal::formatRegister(sb, flags, emitter, archId, regType, regId); -#endif - -#ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::LoggingInternal::formatRegister(sb, flags, emitter, archId, regType, regId); -#endif - - return kErrorInvalidArch; -} - -Error Logging::formatOperand( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const Operand_& op) noexcept { - -#ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::LoggingInternal::formatOperand(sb, flags, emitter, archId, op); -#endif - -#ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::LoggingInternal::formatOperand(sb, flags, emitter, archId, op); -#endif - - return kErrorInvalidArch; -} - -Error Logging::formatInstruction( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept { - -#ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::LoggingInternal::formatInstruction(sb, flags, emitter, archId, inst, operands, opCount); -#endif - -#ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::LoggingInternal::formatInstruction(sb, flags, emitter, archId, inst, operands, opCount); -#endif - - return kErrorInvalidArch; -} - -Error Logging::formatTypeId(String& sb, uint32_t typeId) noexcept { - if (typeId == Type::kIdVoid) - return sb.appendString("void"); - - if (!Type::isValid(typeId)) - return sb.appendString("unknown"); - - const char* typeName = "unknown"; - uint32_t typeSize = Type::sizeOf(typeId); - - uint32_t baseId = Type::baseOf(typeId); - switch (baseId) { - case Type::kIdIntPtr : typeName = "iptr" ; break; - case Type::kIdUIntPtr: typeName = "uptr" ; break; - case Type::kIdI8 : typeName = "i8" ; break; - case Type::kIdU8 : typeName = "u8" ; break; - case Type::kIdI16 : typeName = "i16" ; break; - case Type::kIdU16 : typeName = "u16" ; break; - case Type::kIdI32 : typeName = "i32" ; break; - case Type::kIdU32 : typeName = "u32" ; break; - case Type::kIdI64 : typeName = "i64" ; break; - case Type::kIdU64 : typeName = "u64" ; break; - case Type::kIdF32 : typeName = "f32" ; break; - case Type::kIdF64 : typeName = "f64" ; break; - case Type::kIdF80 : typeName = "f80" ; break; - case Type::kIdMask8 : typeName = "mask8" ; break; - case Type::kIdMask16 : typeName = "mask16"; break; - case Type::kIdMask32 : typeName = "mask32"; break; - case Type::kIdMask64 : typeName = "mask64"; break; - case Type::kIdMmx32 : typeName = "mmx32" ; break; - case Type::kIdMmx64 : typeName = "mmx64" ; break; - } - - uint32_t baseSize = Type::sizeOf(baseId); - if (typeSize > baseSize) { - uint32_t count = typeSize / baseSize; - return sb.appendFormat("%sx%u", typeName, unsigned(count)); - } - else { - return sb.appendString(typeName); - } - -} - -#ifndef ASMJIT_NO_BUILDER -static Error formatFuncValue(String& sb, uint32_t flags, const BaseEmitter* emitter, FuncValue value) noexcept { - uint32_t typeId = value.typeId(); - ASMJIT_PROPAGATE(Logging::formatTypeId(sb, typeId)); - - if (value.isReg()) { - ASMJIT_PROPAGATE(sb.appendChar('@')); - ASMJIT_PROPAGATE(Logging::formatRegister(sb, flags, emitter, emitter->archId(), value.regType(), value.regId())); - } - - if (value.isStack()) { - ASMJIT_PROPAGATE(sb.appendFormat("@[%d]", int(value.stackOffset()))); - } - - return kErrorOk; -} - -static Error formatFuncRets( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - const FuncDetail& fd, - VirtReg* const* vRegs) noexcept { - - if (!fd.hasRet()) - return sb.appendString("void"); - - for (uint32_t i = 0; i < fd.retCount(); i++) { - if (i) ASMJIT_PROPAGATE(sb.appendString(", ")); - ASMJIT_PROPAGATE(formatFuncValue(sb, flags, emitter, fd.ret(i))); - -#ifndef ASMJIT_NO_COMPILER - if (vRegs) { - static const char nullRet[] = "<none>"; - ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[i] ? vRegs[i]->name() : nullRet)); - } -#else - DebugUtils::unused(vRegs); -#endif - } - - return kErrorOk; -} - -static Error formatFuncArgs( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - const FuncDetail& fd, - VirtReg* const* vRegs) noexcept { - - uint32_t count = fd.argCount(); - if (!count) - return sb.appendString("void"); - - for (uint32_t i = 0; i < count; i++) { - if (i) ASMJIT_PROPAGATE(sb.appendString(", ")); - ASMJIT_PROPAGATE(formatFuncValue(sb, flags, emitter, fd.arg(i))); - -#ifndef ASMJIT_NO_COMPILER - if (vRegs) { - static const char nullArg[] = "<none>"; - ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[i] ? vRegs[i]->name() : nullArg)); - } -#else - DebugUtils::unused(vRegs); -#endif - } - - return kErrorOk; -} - -Error Logging::formatNode( - String& sb, - uint32_t flags, - const BaseBuilder* cb, - const BaseNode* node_) noexcept { - - if (node_->hasPosition() && (flags & FormatOptions::kFlagPositions) != 0) - ASMJIT_PROPAGATE(sb.appendFormat("<%05u> ", node_->position())); - - switch (node_->type()) { - case BaseNode::kNodeInst: - case BaseNode::kNodeJump: { - const InstNode* node = node_->as<InstNode>(); - ASMJIT_PROPAGATE( - Logging::formatInstruction(sb, flags, cb, - cb->archId(), - node->baseInst(), node->operands(), node->opCount())); - break; - } - - case BaseNode::kNodeSection: { - const SectionNode* node = node_->as<SectionNode>(); - if (cb->_code->isSectionValid(node->id())) { - const Section* section = cb->_code->sectionById(node->id()); - ASMJIT_PROPAGATE(sb.appendFormat(".section %s", section->name())); - } - break; - } - - case BaseNode::kNodeLabel: { - const LabelNode* node = node_->as<LabelNode>(); - ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id())); - ASMJIT_PROPAGATE(sb.appendString(":")); - break; - } - - case BaseNode::kNodeAlign: { - const AlignNode* node = node_->as<AlignNode>(); - ASMJIT_PROPAGATE( - sb.appendFormat(".align %u (%s)", - node->alignment(), - node->alignMode() == kAlignCode ? "code" : "data")); - break; - } - - case BaseNode::kNodeEmbedData: { - const EmbedDataNode* node = node_->as<EmbedDataNode>(); - ASMJIT_PROPAGATE(sb.appendFormat(".embed (%u bytes)", node->size())); - break; - } - - case BaseNode::kNodeEmbedLabel: { - const EmbedLabelNode* node = node_->as<EmbedLabelNode>(); - ASMJIT_PROPAGATE(sb.appendString(".label ")); - ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id())); - break; - } - - case BaseNode::kNodeEmbedLabelDelta: { - const EmbedLabelDeltaNode* node = node_->as<EmbedLabelDeltaNode>(); - ASMJIT_PROPAGATE(sb.appendString(".label (")); - ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id())); - ASMJIT_PROPAGATE(sb.appendString(" - ")); - ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->baseId())); - ASMJIT_PROPAGATE(sb.appendString(")")); - break; - } - - case BaseNode::kNodeComment: { - const CommentNode* node = node_->as<CommentNode>(); - ASMJIT_PROPAGATE(sb.appendFormat("; %s", node->inlineComment())); - break; - } - - case BaseNode::kNodeSentinel: { - const SentinelNode* node = node_->as<SentinelNode>(); - const char* sentinelName = nullptr; - - switch (node->sentinelType()) { - case SentinelNode::kSentinelFuncEnd: - sentinelName = "[FuncEnd]"; - break; - - default: - sentinelName = "[Sentinel]"; - break; - } - - ASMJIT_PROPAGATE(sb.appendString(sentinelName)); - break; - } - -#ifndef ASMJIT_NO_COMPILER - case BaseNode::kNodeFunc: { - const FuncNode* node = node_->as<FuncNode>(); - - ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id())); - ASMJIT_PROPAGATE(sb.appendString(": ")); - - ASMJIT_PROPAGATE(formatFuncRets(sb, flags, cb, node->detail(), nullptr)); - ASMJIT_PROPAGATE(sb.appendString(" Func(")); - ASMJIT_PROPAGATE(formatFuncArgs(sb, flags, cb, node->detail(), node->args())); - ASMJIT_PROPAGATE(sb.appendString(")")); - break; - } - - case BaseNode::kNodeFuncRet: { - const FuncRetNode* node = node_->as<FuncRetNode>(); - ASMJIT_PROPAGATE(sb.appendString("[FuncRet]")); - - for (uint32_t i = 0; i < 2; i++) { - const Operand_& op = node->_opArray[i]; - if (!op.isNone()) { - ASMJIT_PROPAGATE(sb.appendString(i == 0 ? " " : ", ")); - ASMJIT_PROPAGATE(formatOperand(sb, flags, cb, cb->archId(), op)); - } - } - break; - } - - case BaseNode::kNodeFuncCall: { - const FuncCallNode* node = node_->as<FuncCallNode>(); - ASMJIT_PROPAGATE( - Logging::formatInstruction(sb, flags, cb, - cb->archId(), - node->baseInst(), node->operands(), node->opCount())); - break; - } -#endif - - default: { - ASMJIT_PROPAGATE(sb.appendFormat("[User:%u]", node_->type())); - break; - } - } - - return kErrorOk; -} -#endif - -Error Logging::formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept { - size_t currentSize = sb.size(); - size_t commentSize = comment ? Support::strLen(comment, Globals::kMaxCommentSize) : 0; - - ASMJIT_ASSERT(binSize >= dispSize); - const size_t kNoBinSize = std::numeric_limits<size_t>::max(); - - if ((binSize != 0 && binSize != kNoBinSize) || commentSize) { - size_t align = kMaxInstLineSize; - char sep = ';'; - - for (size_t i = (binSize == kNoBinSize); i < 2; i++) { - size_t begin = sb.size(); - ASMJIT_PROPAGATE(sb.padEnd(align)); - - if (sep) { - ASMJIT_PROPAGATE(sb.appendChar(sep)); - ASMJIT_PROPAGATE(sb.appendChar(' ')); - } - - // Append binary data or comment. - if (i == 0) { - ASMJIT_PROPAGATE(sb.appendHex(binData, binSize - dispSize - immSize)); - ASMJIT_PROPAGATE(sb.appendChars('.', dispSize * 2)); - ASMJIT_PROPAGATE(sb.appendHex(binData + binSize - immSize, immSize)); - if (commentSize == 0) break; - } - else { - ASMJIT_PROPAGATE(sb.appendString(comment, commentSize)); - } - - currentSize += sb.size() - begin; - align += kMaxBinarySize; - sep = '|'; - } - } - - return sb.appendChar('\n'); -} - -ASMJIT_END_NAMESPACE - -#endif diff --git a/3rdparty/asmjit/src/asmjit/core/misc_p.h b/3rdparty/asmjit/src/asmjit/core/misc_p.h index 916ca9db67c..b1056f473ae 100644 --- a/3rdparty/asmjit/src/asmjit/core/misc_p.h +++ b/3rdparty/asmjit/src/asmjit/core/misc_p.h @@ -29,7 +29,7 @@ ASMJIT_BEGIN_NAMESPACE //! \cond INTERNAL -//! \addtogroup asmjit_support +//! \addtogroup asmjit_utilities //! \{ #define ASMJIT_LOOKUP_TABLE_8(T, I) T((I)), T((I+1)), T((I+2)), T((I+3)), T((I+4)), T((I+5)), T((I+6)), T((I+7)) diff --git a/3rdparty/asmjit/src/asmjit/core/operand.cpp b/3rdparty/asmjit/src/asmjit/core/operand.cpp index 9d11f3f6ddc..46bb23a289c 100644 --- a/3rdparty/asmjit/src/asmjit/core/operand.cpp +++ b/3rdparty/asmjit/src/asmjit/core/operand.cpp @@ -126,10 +126,10 @@ UNIT(operand) { INFO("Checking basic functionality of Imm"); Imm immValue(-42); - EXPECT(Imm(-1).i64() == int64_t(-1)); - EXPECT(imm(-1).i64() == int64_t(-1)); - EXPECT(immValue.i64() == int64_t(-42)); - EXPECT(imm(0xFFFFFFFF).i64() == int64_t(0xFFFFFFFF)); + EXPECT(Imm(-1).value() == -1); + EXPECT(imm(-1).value() == -1); + EXPECT(immValue.value() == -42); + EXPECT(imm(0xFFFFFFFF).value() == int64_t(0xFFFFFFFF)); } #endif diff --git a/3rdparty/asmjit/src/asmjit/core/operand.h b/3rdparty/asmjit/src/asmjit/core/operand.h index eee1af4244e..01cc1eaa560 100644 --- a/3rdparty/asmjit/src/asmjit/core/operand.h +++ b/3rdparty/asmjit/src/asmjit/core/operand.h @@ -103,7 +103,7 @@ public: \ constexpr explicit REG(uint32_t rId) noexcept \ : BASE(kSignature, rId) {} -//! \addtogroup asmjit_core +//! \addtogroup asmjit_assembler //! \{ // ============================================================================ @@ -162,6 +162,16 @@ struct Operand_ { }; static_assert(kOpMem == kOpReg + 1, "asmjit::Operand requires `kOpMem` to be `kOpReg+1`."); + //! Label tag. + enum LabelTag { + //! Label tag is used as a sub-type, forming a unique signature across all + //! operand types as 0x1 is never associated with any register type. This + //! means that a memory operand's BASE register can be constructed from + //! virtually any operand (register vs. label) by just assigning its type + //! (register type or label-tag) and operand id. + kLabelTag = 0x1 + }; + // \cond INTERNAL enum SignatureBits : uint32_t { // Operand type (3 least significant bits). @@ -211,7 +221,6 @@ struct Operand_ { }; //! \endcond - //! \cond INTERNAL //! Constants useful for VirtId <-> Index translation. enum VirtIdConstants : uint32_t { //! Minimum valid packed-id. @@ -225,14 +234,12 @@ struct Operand_ { //! Tests whether the given `id` is a valid virtual register id. Since AsmJit //! supports both physical and virtual registers it must be able to distinguish //! between these two. The idea is that physical registers are always limited - //! in size, so virtual identifiers start from `kVirtIdMin` and end at - //! `kVirtIdMax`. + //! in size, so virtual identifiers start from `kVirtIdMin` and end at `kVirtIdMax`. static ASMJIT_INLINE bool isVirtId(uint32_t id) noexcept { return id - kVirtIdMin < uint32_t(kVirtIdCount); } //! Converts a real-id into a packed-id that can be stored in Operand. static ASMJIT_INLINE uint32_t indexToVirtId(uint32_t id) noexcept { return id + kVirtIdMin; } //! Converts a packed-id back to real-id. static ASMJIT_INLINE uint32_t virtIdToIndex(uint32_t id) noexcept { return id - kVirtIdMin; } - //! \endcond //! \name Construction & Destruction //! \{ @@ -245,10 +252,10 @@ struct Operand_ { _data[0] = 0; _data[1] = 0; } + //! \endcond - //! Initializes the operand from `other` (used by operator overloads). + //! Initializes the operand from `other` operand (used by operator overloads). inline void copyFrom(const Operand_& other) noexcept { memcpy(this, &other, sizeof(Operand_)); } - //! \endcond //! Resets the `Operand` to none. //! @@ -290,8 +297,10 @@ struct Operand_ { //! \name Operator Overloads //! \{ - constexpr bool operator==(const Operand_& other) const noexcept { return isEqual(other); } - constexpr bool operator!=(const Operand_& other) const noexcept { return !isEqual(other); } + //! Tests whether this operand is the same as `other`. + constexpr bool operator==(const Operand_& other) const noexcept { return equals(other); } + //! Tests whether this operand is not the same as `other`. + constexpr bool operator!=(const Operand_& other) const noexcept { return !equals(other); } //! \} @@ -395,14 +404,22 @@ struct Operand_ { //! initialized. constexpr uint32_t id() const noexcept { return _baseId; } - //! Tests whether the operand is 100% equal to `other`. - constexpr bool isEqual(const Operand_& other) const noexcept { + //! Tests whether the operand is 100% equal to `other` operand. + //! + //! \note This basically performs a binary comparison, if aby bit is + //! different the operands are not equal. + constexpr bool equals(const Operand_& other) const noexcept { return (_signature == other._signature) & (_baseId == other._baseId ) & (_data[0] == other._data[0] ) & (_data[1] == other._data[1] ) ; } +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use equals() instead") + constexpr bool isEqual(const Operand_& other) const noexcept { return equals(other); } +#endif //!ASMJIT_NO_DEPRECATED + //! Tests whether the operand is a register matching `rType`. constexpr bool isReg(uint32_t rType) const noexcept { return (_signature & (kSignatureOpMask | kSignatureRegTypeMask)) == @@ -471,11 +488,6 @@ public: static_assert(sizeof(Operand) == 16, "asmjit::Operand must be exactly 16 bytes long"); -namespace Globals { - //! A default-constructed operand of `Operand_::kOpNone` type. - static constexpr const Operand none; -} - // ============================================================================ // [asmjit::Label] // ============================================================================ @@ -519,16 +531,6 @@ public: kTypeCount = 3 }; - // TODO: Find a better place, find a better name. - enum { - //! Label tag is used as a sub-type, forming a unique signature across all - //! operand types as 0x1 is never associated with any register (reg-type). - //! This means that a memory operand's BASE register can be constructed - //! from virtually any operand (register vs. label) by just assigning its - //! type (reg type or label-tag) and operand id. - kLabelTag = 0x1 - }; - //! \name Construction & Destruction //! \{ @@ -536,7 +538,7 @@ public: constexpr Label() noexcept : Operand(Globals::Init, kOpLabel, Globals::kInvalidId, 0, 0) {} - //! Creates a cloned label operand of `other` . + //! Creates a cloned label operand of `other`. constexpr Label(const Label& other) noexcept : Operand(other) {} @@ -610,7 +612,7 @@ struct BaseRegTraits { //! This information is compatible with operand's signature (32-bit integer) //! and `RegInfo` just provides easy way to access it. struct RegInfo { - inline void reset() noexcept { _signature = 0; } + inline void reset(uint32_t signature = 0) noexcept { _signature = signature; } inline void setSignature(uint32_t signature) noexcept { _signature = signature; } template<uint32_t mask> @@ -628,7 +630,7 @@ struct RegInfo { uint32_t _signature; }; -//! Physical/Virtual register operand. +//! Physical or virtual register operand. class BaseReg : public Operand { public: //! Architecture neutral register types. @@ -638,7 +640,7 @@ public: //! of a memory operand. enum RegType : uint32_t { //! No register - unused, invalid, multiple meanings. - kTypeNone = 0, + kTypeNone = 0, // (1 is used as a LabelTag) @@ -736,15 +738,14 @@ public: //! Tests whether this register is the same as `other`. //! //! This is just an optimization. Registers by default only use the first - //! 8 bytes of the Operand, so this method takes advantage of this knowledge + //! 8 bytes of Operand data, so this method takes advantage of this knowledge //! and only compares these 8 bytes. If both operands were created correctly - //! then `isEqual()` and `isSame()` should give the same answer, however, if - //! some one of the two operand contains a garbage or other metadata in the - //! upper 8 bytes then `isSame()` may return `true` in cases where `isEqual()` + //! both \ref equals() and \ref isSame() should give the same answer, however, + //! if any of these two contains garbage or other metadata in the upper 8 + //! bytes then \ref isSame() may return `true` in cases in which \ref equals() //! returns false. constexpr bool isSame(const BaseReg& other) const noexcept { - return (_signature == other._signature) & - (_baseId == other._baseId ) ; + return (_signature == other._signature) & (_baseId == other._baseId); } //! Tests whether the register is valid (either virtual or physical). @@ -810,6 +811,7 @@ public: //! \name Static Functions //! \{ + //! Tests whether the `op` operand is a general purpose register. static inline bool isGp(const Operand_& op) noexcept { // Check operand type and register group. Not interested in register type and size. const uint32_t kSgn = (kOpReg << kSignatureOpShift ) | @@ -817,7 +819,7 @@ public: return (op.signature() & (kSignatureOpMask | kSignatureRegGroupMask)) == kSgn; } - //! Tests whether the `op` operand is either a low or high 8-bit GPB register. + //! Tests whether the `op` operand is a vector register. static inline bool isVec(const Operand_& op) noexcept { // Check operand type and register group. Not interested in register type and size. const uint32_t kSgn = (kOpReg << kSignatureOpShift ) | @@ -825,7 +827,9 @@ public: return (op.signature() & (kSignatureOpMask | kSignatureRegGroupMask)) == kSgn; } + //! Tests whether the `op` is a general purpose register of the given `rId`. static inline bool isGp(const Operand_& op, uint32_t rId) noexcept { return isGp(op) & (op.id() == rId); } + //! Tests whether the `op` is a vector register of the given `rId`. static inline bool isVec(const Operand_& op, uint32_t rId) noexcept { return isVec(op) & (op.id() == rId); } //! \} @@ -947,10 +951,14 @@ struct RegOnly { //! index shift (scale). class BaseMem : public Operand { public: + //! Address type. enum AddrType : uint32_t { + //! Default address type, Assembler will select the best type when necessary. kAddrTypeDefault = 0, - kAddrTypeAbs = 1, - kAddrTypeRel = 2 + //! Absolute address type. + kAddrTypeAbs = 1, + //! Relative address type. + kAddrTypeRel = 2 }; // Shortcuts. @@ -1028,25 +1036,37 @@ public: //! Clones the memory operand. constexpr BaseMem clone() const noexcept { return BaseMem(*this); } + //! Returns the address type (see \ref AddrType) of the memory operand. + //! + //! By default, address type of newly created memory operands is always \ref kAddrTypeDefault. constexpr uint32_t addrType() const noexcept { return _getSignaturePart<kSignatureMemAddrTypeMask>(); } + //! Sets the address type to `addrType`, see \ref AddrType. inline void setAddrType(uint32_t addrType) noexcept { _setSignaturePart<kSignatureMemAddrTypeMask>(addrType); } + //! Resets the address type to \ref kAddrTypeDefault. inline void resetAddrType() noexcept { _setSignaturePart<kSignatureMemAddrTypeMask>(0); } + //! Tests whether the address type is \ref kAddrTypeAbs. constexpr bool isAbs() const noexcept { return addrType() == kAddrTypeAbs; } + //! Sets the address type to \ref kAddrTypeAbs. inline void setAbs() noexcept { setAddrType(kAddrTypeAbs); } + //! Tests whether the address type is \ref kAddrTypeRel. constexpr bool isRel() const noexcept { return addrType() == kAddrTypeRel; } + //! Sets the address type to \ref kAddrTypeRel. inline void setRel() noexcept { setAddrType(kAddrTypeRel); } + //! Tests whether this memory operand is a register home (only used by \ref asmjit_compiler) constexpr bool isRegHome() const noexcept { return _hasSignaturePart<kSignatureMemRegHomeFlag>(); } + //! Mark this memory operand as register home (only used by \ref asmjit_compiler). inline void setRegHome() noexcept { _signature |= kSignatureMemRegHomeFlag; } + //! Marks this operand to not be a register home (only used by \ref asmjit_compiler). inline void clearRegHome() noexcept { _signature &= ~kSignatureMemRegHomeFlag; } //! Tests whether the memory operand has a BASE register or label specified. constexpr bool hasBase() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0; } //! Tests whether the memory operand has an INDEX register specified. constexpr bool hasIndex() const noexcept { return (_signature & kSignatureMemIndexTypeMask) != 0; } - //! Tests whether the memory operand has BASE and INDEX register. + //! Tests whether the memory operand has BASE or INDEX register. constexpr bool hasBaseOrIndex() const noexcept { return (_signature & kSignatureMemBaseIndexMask) != 0; } //! Tests whether the memory operand has BASE and INDEX register. constexpr bool hasBaseAndIndex() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0 && (_signature & kSignatureMemIndexTypeMask) != 0; } @@ -1093,6 +1113,7 @@ public: //! Sets the index register to type and id of the given `index` operand. inline void setIndex(const BaseReg& index) noexcept { return _setIndex(index.type(), index.id()); } + //! \cond INTERNAL inline void _setBase(uint32_t rType, uint32_t rId) noexcept { _setSignaturePart<kSignatureMemBaseTypeMask>(rType); _baseId = rId; @@ -1102,6 +1123,7 @@ public: _setSignaturePart<kSignatureMemIndexTypeMask>(rType); _data[kDataMemIndexId] = rId; } + //! \endcond //! Resets the memory operand's BASE register or label. inline void resetBase() noexcept { _setBase(0, 0); } @@ -1159,7 +1181,7 @@ public: //! 64-bit offset. Use it only if you know that there is a BASE register //! and the offset is only 32 bits anyway. - //! Adjusts the offset by a 64-bit `offset`. + //! Adjusts the memory operand offset by a `offset`. inline void addOffset(int64_t offset) noexcept { if (isOffset64Bit()) { int64_t result = offset + int64_t(uint64_t(_data[kDataMemOffsetLo]) | (uint64_t(_baseId) << 32)); @@ -1230,77 +1252,54 @@ public: //! \name Accessors //! \{ - //! Returns immediate value as 8-bit signed integer, possibly cropped. - 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(_data[kDataImmValueLo] & 0xFFu); } - //! Returns immediate value as 16-bit signed integer, possibly cropped. - 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(_data[kDataImmValueLo] & 0xFFFFu);} - //! Returns immediate value as 32-bit signed integer, possibly cropped. - 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(_data[kDataImmValueLo]); } - //! Returns high 32-bit signed integer. - 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 _data[kDataImmValueLo]; } - //! Returns low 32-bit signed integer. - constexpr uint32_t u32Lo() const noexcept { return _data[kDataImmValueLo]; } - //! Returns high 32-bit signed integer. - 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((uint64_t(_data[kDataImmValueHi]) << 32) | _data[kDataImmValueLo]); } - //! Returns immediate value as 64-bit unsigned integer. - 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(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(u64()) : uintptr_t(u32()); } + //! Returns the immediate value as `int64_t`, which is the internal format Imm uses. + constexpr int64_t value() const noexcept { + return int64_t((uint64_t(_data[kDataImmValueHi]) << 32) | _data[kDataImmValueLo]); + } //! Tests whether the immediate can be casted to 8-bit signed integer. - constexpr bool isInt8() const noexcept { return Support::isInt8(i64()); } + constexpr bool isInt8() const noexcept { return Support::isInt8(value()); } //! Tests whether the immediate can be casted to 8-bit unsigned integer. - constexpr bool isUInt8() const noexcept { return Support::isUInt8(i64()); } + constexpr bool isUInt8() const noexcept { return Support::isUInt8(value()); } //! Tests whether the immediate can be casted to 16-bit signed integer. - constexpr bool isInt16() const noexcept { return Support::isInt16(i64()); } + constexpr bool isInt16() const noexcept { return Support::isInt16(value()); } //! Tests whether the immediate can be casted to 16-bit unsigned integer. - constexpr bool isUInt16() const noexcept { return Support::isUInt16(i64()); } + constexpr bool isUInt16() const noexcept { return Support::isUInt16(value()); } //! Tests whether the immediate can be casted to 32-bit signed integer. - constexpr bool isInt32() const noexcept { return Support::isInt32(i64()); } + constexpr bool isInt32() const noexcept { return Support::isInt32(value()); } //! 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 { setI64(val); } - //! Sets immediate value to 8-bit unsigned integer `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 { setI64(val); } - //! Sets immediate value to 16-bit unsigned integer `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 { setI64(val); } - //! Sets immediate value to 32-bit unsigned integer `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 { - _data[kDataImmValueHi] = uint32_t(uint64_t(val) >> 32); - _data[kDataImmValueLo] = uint32_t(uint64_t(val) & 0xFFFFFFFFu); + //! Returns the immediate value casted to `T`. + //! + //! The value is masked before it's casted to `T` so the returned value is + //! simply the representation of `T` considering the original value's lowest + //! bits. + template<typename T> + constexpr T valueAs() const noexcept { + return T(uint64_t(value()) & Support::allOnes<typename std::make_unsigned<T>::type>()); } - //! Sets immediate value to 64-bit unsigned integer `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 { setI64(val); } - //! Sets immediate value to uintptr_t `val`. - inline void setUPtr(uintptr_t val) noexcept { setU64(val); } - - //! Sets immediate value to `val`. + + //! Returns low 32-bit signed integer. + constexpr int32_t int32Lo() const noexcept { return int32_t(_data[kDataImmValueLo]); } + //! Returns high 32-bit signed integer. + constexpr int32_t int32Hi() const noexcept { return int32_t(_data[kDataImmValueHi]); } + //! Returns low 32-bit signed integer. + constexpr uint32_t uint32Lo() const noexcept { return _data[kDataImmValueLo]; } + //! Returns high 32-bit signed integer. + constexpr uint32_t uint32Hi() const noexcept { return _data[kDataImmValueHi]; } + + //! Sets immediate value to `val`, the value is casted to a signed 64-bit integer. template<typename T> - inline void setValue(T val) noexcept { setI64(int64_t(Support::asNormalized(val))); } + inline void setValue(const T& val) noexcept { + int64_t val64 = int64_t(Support::asNormalized(val)); + _data[kDataImmValueHi] = uint32_t(uint64_t(val64) >> 32); + _data[kDataImmValueLo] = uint32_t(uint64_t(val64) & 0xFFFFFFFFu); + } - inline void setDouble(double d) noexcept { setU64(Support::bitCast<uint64_t>(d)); } + inline void setDouble(double d) noexcept { + setValue(Support::bitCast<uint64_t>(d)); + } //! \} @@ -1310,15 +1309,59 @@ public: //! Clones the immediate operand. constexpr Imm clone() const noexcept { return Imm(*this); } - 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 signExtend8Bits() noexcept { setValue(int64_t(valueAs<int8_t>())); } + inline void signExtend16Bits() noexcept { setValue(int64_t(valueAs<int16_t>())); } + inline void signExtend32Bits() noexcept { setValue(int64_t(valueAs<int32_t>())); } - inline void zeroExtend8Bits() noexcept { setU64(u8()); } - inline void zeroExtend16Bits() noexcept { setU64(u16()); } + inline void zeroExtend8Bits() noexcept { setValue(valueAs<uint8_t>()); } + inline void zeroExtend16Bits() noexcept { setValue(valueAs<uint16_t>()); } inline void zeroExtend32Bits() noexcept { _data[kDataImmValueHi] = 0u; } //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use valueAs<int8_t>() instead") + inline int8_t i8() const noexcept { return valueAs<int8_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<uint8_t>() instead") + inline uint8_t u8() const noexcept { return valueAs<uint8_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<int16_t>() instead") + inline int16_t i16() const noexcept { return valueAs<int16_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<uint16_t>() instead") + inline uint16_t u16() const noexcept { return valueAs<uint16_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<int32_t>() instead") + inline int32_t i32() const noexcept { return valueAs<int32_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<uint32_t>() instead") + inline uint32_t u32() const noexcept { return valueAs<uint32_t>(); } + + ASMJIT_DEPRECATED("Use value() instead") + inline int64_t i64() const noexcept { return value(); } + + ASMJIT_DEPRECATED("Use valueAs<uint64_t>() instead") + inline uint64_t u64() const noexcept { return valueAs<uint64_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<intptr_t>() instead") + inline intptr_t iptr() const noexcept { return valueAs<intptr_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<uintptr_t>() instead") + inline uintptr_t uptr() const noexcept { return valueAs<uintptr_t>(); } + + ASMJIT_DEPRECATED("Use int32Lo() instead") + inline int32_t i32Lo() const noexcept { return int32Lo(); } + + ASMJIT_DEPRECATED("Use uint32Lo() instead") + inline uint32_t u32Lo() const noexcept { return uint32Lo(); } + + ASMJIT_DEPRECATED("Use int32Hi() instead") + inline int32_t i32Hi() const noexcept { return int32Hi(); } + + ASMJIT_DEPRECATED("Use uint32Hi() instead") + inline uint32_t u32Hi() const noexcept { return uint32Hi(); } +#endif // !ASMJIT_NO_DEPRECATED }; //! Creates a new immediate operand. @@ -1332,6 +1375,44 @@ static constexpr Imm imm(T val) noexcept { //! \} +// ============================================================================ +// [asmjit::Globals::none] +// ============================================================================ + +namespace Globals { + //! \ingroup asmjit_assembler + //! + //! A default-constructed operand of `Operand_::kOpNone` type. + static constexpr const Operand none; +} + +// ============================================================================ +// [asmjit::Support::ForwardOp] +// ============================================================================ + +//! \cond INTERNAL +namespace Support { + +template<typename T, bool IsIntegral> +struct ForwardOpImpl { + static ASMJIT_INLINE const T& forward(const T& value) noexcept { return value; } +}; + +template<typename T> +struct ForwardOpImpl<T, true> { + static ASMJIT_INLINE Imm forward(const T& value) noexcept { return Imm(value); } +}; + +//! Either forwards operand T or returns a new operand for T if T is a type +//! convertible to operand. At the moment this is only used to convert integers +//! to \ref Imm operands. +template<typename T> +struct ForwardOp : public ForwardOpImpl<T, std::is_integral<typename std::decay<T>::type>::value> {}; + +} + +//! \endcond + ASMJIT_END_NAMESPACE #endif // ASMJIT_CORE_OPERAND_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/osutils.h b/3rdparty/asmjit/src/asmjit/core/osutils.h index b9a2df4ad8f..a4691295b20 100644 --- a/3rdparty/asmjit/src/asmjit/core/osutils.h +++ b/3rdparty/asmjit/src/asmjit/core/osutils.h @@ -28,7 +28,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_support +//! \addtogroup asmjit_utilities //! \{ // ============================================================================ @@ -50,7 +50,7 @@ namespace OSUtils { //! Lock. //! //! Lock is internal, it cannot be used outside of AsmJit, however, its internal -//! layout is exposed as it's used by some other public classes. +//! layout is exposed as it's used by some other classes, which are public. class Lock { public: ASMJIT_NONCOPYABLE(Lock) @@ -78,60 +78,8 @@ public: inline void lock() noexcept; inline void unlock() noexcept; }; - -#ifdef ASMJIT_EXPORTS -#if defined(_WIN32) - -// Win32 implementation. -static_assert(sizeof(Lock::Handle) == sizeof(CRITICAL_SECTION), "asmjit::Lock::Handle layout must match CRITICAL_SECTION"); -static_assert(alignof(Lock::Handle) == alignof(CRITICAL_SECTION), "asmjit::Lock::Handle alignment must match CRITICAL_SECTION"); - -inline Lock::Lock() noexcept { InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } -inline Lock::~Lock() noexcept { DeleteCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } -inline void Lock::lock() noexcept { EnterCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } -inline void Lock::unlock() noexcept { LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } - -#elif !defined(__EMSCRIPTEN__) - -// PThread implementation. -inline Lock::Lock() noexcept { pthread_mutex_init(&_handle, nullptr); } -inline Lock::~Lock() noexcept { pthread_mutex_destroy(&_handle); } -inline void Lock::lock() noexcept { pthread_mutex_lock(&_handle); } -inline void Lock::unlock() noexcept { pthread_mutex_unlock(&_handle); } - -#else - -// Dummy implementation - Emscripten or other unsupported platform. -inline Lock::Lock() noexcept {} -inline Lock::~Lock() noexcept {} -inline void Lock::lock() noexcept {} -inline void Lock::unlock() noexcept {} - -#endif -#endif - //! \endcond -// ============================================================================ -// [asmjit::LockGuard] -// ============================================================================ - -#ifdef ASMJIT_EXPORTS -//! \cond INTERNAL - -//! Scoped lock. -struct LockGuard { - ASMJIT_NONCOPYABLE(LockGuard) - - Lock& _target; - - inline LockGuard(Lock& target) noexcept : _target(target) { _target.lock(); } - inline ~LockGuard() noexcept { _target.unlock(); } -}; - -//! \endcond -#endif - //! \} ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/osutils_p.h b/3rdparty/asmjit/src/asmjit/core/osutils_p.h new file mode 100644 index 00000000000..31db308bdcf --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/osutils_p.h @@ -0,0 +1,94 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_OSUTILS_P_H_INCLUDED +#define ASMJIT_CORE_OSUTILS_P_H_INCLUDED + +#include "../core/osutils.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \cond INTERNAL +//! \addtogroup asmjit_utilities +//! \{ + +// ============================================================================ +// [asmjit::Lock] +// ============================================================================ + +#if defined(_WIN32) + +// Windows implementation. +static_assert(sizeof(Lock::Handle) == sizeof(CRITICAL_SECTION), "asmjit::Lock::Handle layout must match CRITICAL_SECTION"); +static_assert(alignof(Lock::Handle) == alignof(CRITICAL_SECTION), "asmjit::Lock::Handle alignment must match CRITICAL_SECTION"); + +inline Lock::Lock() noexcept { InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } +inline Lock::~Lock() noexcept { DeleteCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } +inline void Lock::lock() noexcept { EnterCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } +inline void Lock::unlock() noexcept { LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } + +#elif !defined(__EMSCRIPTEN__) + +// PThread implementation. +#ifdef PTHREAD_MUTEX_INITIALIZER +inline Lock::Lock() noexcept : _handle(PTHREAD_MUTEX_INITIALIZER) {} +#else +inline Lock::Lock() noexcept { pthread_mutex_init(&_handle, nullptr); } +#endif +inline Lock::~Lock() noexcept { pthread_mutex_destroy(&_handle); } +inline void Lock::lock() noexcept { pthread_mutex_lock(&_handle); } +inline void Lock::unlock() noexcept { pthread_mutex_unlock(&_handle); } + +#else + +// Dummy implementation - Emscripten or other unsupported platform. +inline Lock::Lock() noexcept {} +inline Lock::~Lock() noexcept {} +inline void Lock::lock() noexcept {} +inline void Lock::unlock() noexcept {} + +#endif + +// ============================================================================ +// [asmjit::LockGuard] +// ============================================================================ + +//! Scoped lock. +class LockGuard { +public: + ASMJIT_NONCOPYABLE(LockGuard) + + Lock& _target; + + inline LockGuard(Lock& target) noexcept + : _target(target) { _target.lock(); } + inline ~LockGuard() noexcept { _target.unlock(); } +}; + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_OSUTILS_P_H_INCLUDED + diff --git a/3rdparty/asmjit/src/asmjit/core/rabuilders_p.h b/3rdparty/asmjit/src/asmjit/core/rabuilders_p.h index 6f400ad1c3a..50624bf58cd 100644 --- a/3rdparty/asmjit/src/asmjit/core/rabuilders_p.h +++ b/3rdparty/asmjit/src/asmjit/core/rabuilders_p.h @@ -27,6 +27,7 @@ #include "../core/api-config.h" #ifndef ASMJIT_NO_COMPILER +#include "../core/formatter.h" #include "../core/rapass_p.h" ASMJIT_BEGIN_NAMESPACE @@ -66,7 +67,7 @@ public: static constexpr uint32_t kCodeIndentation = 4; // NOTE: This is a bit hacky. There are some nodes which are processed twice - // (see `onBeforeCall()` and `onBeforeRet()`) as they can insert some nodes + // (see `onBeforeInvoke()` and `onBeforeRet()`) as they can insert some nodes // around them. Since we don't have any flags to mark these we just use their // position that is [at that time] unassigned. static constexpr uint32_t kNodePositionDidOnBefore = 0xFFFFFFFFu; @@ -122,7 +123,7 @@ public: // Instruction | Jump | Invoke | Return // ------------------------------------ - // Handle `InstNode`, `FuncCallNode`, and `FuncRetNode`. All of them + // Handle `InstNode`, `InvokeNode`, and `FuncRetNode`. All of them // share the same interface that provides operands that have read/write // semantics. if (ASMJIT_UNLIKELY(!_curBlock)) { @@ -135,18 +136,18 @@ public: _hasCode = true; - if (node->isFuncCall() || node->isFuncRet()) { + if (node->isInvoke() || node->isFuncRet()) { if (node->position() != kNodePositionDidOnBefore) { // Call and Reg are complicated as they may insert some surrounding // code around them. The simplest approach is to get the previous // node, call the `onBefore()` handlers and then check whether // anything changed and restart if so. By restart we mean that the // current `node` would go back to the first possible inserted node - // by `onBeforeCall()` or `onBeforeRet()`. + // by `onBeforeInvoke()` or `onBeforeRet()`. BaseNode* prev = node->prev(); - if (node->type() == BaseNode::kNodeFuncCall) - ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeCall(node->as<FuncCallNode>())); + if (node->type() == BaseNode::kNodeInvoke) + ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeInvoke(node->as<InvokeNode>())); else ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeRet(node->as<FuncRetNode>())); @@ -159,7 +160,7 @@ public: node->setPosition(kNodePositionDidOnBefore); node = prev->next(); - // `onBeforeCall()` and `onBeforeRet()` can only insert instructions. + // `onBeforeInvoke()` and `onBeforeRet()` can only insert instructions. ASMJIT_ASSERT(node->isInst()); } @@ -179,8 +180,8 @@ public: ib.reset(); ASMJIT_PROPAGATE(static_cast<This*>(this)->onInst(inst, controlType, ib)); - if (node->isFuncCall()) { - ASMJIT_PROPAGATE(static_cast<This*>(this)->onCall(inst->as<FuncCallNode>(), ib)); + if (node->isInvoke()) { + ASMJIT_PROPAGATE(static_cast<This*>(this)->onInvoke(inst->as<InvokeNode>(), ib)); } if (node->isFuncRet()) { @@ -409,7 +410,7 @@ public: logNode(node, kRootIndentation); // Unlikely: Assume that the exit label is reached only once per function. - if (ASMJIT_UNLIKELY(node->as<LabelNode>()->id() == _exitLabelId)) { + if (ASMJIT_UNLIKELY(node->as<LabelNode>()->labelId() == _exitLabelId)) { _curBlock->setLast(node); _curBlock->makeConstructed(_blockRegStats); ASMJIT_PROPAGATE(_pass->addExitBlock(_curBlock)); @@ -492,7 +493,7 @@ public: // Reset everything we may need. _blockRegStats.reset(); - _exitLabelId = func->exitNode()->id(); + _exitLabelId = func->exitNode()->labelId(); // Initially we assume there is no code in the function body. _hasCode = false; @@ -599,11 +600,11 @@ public: _sb.clear(); _sb.appendChars(' ', indentation); if (action) { - _sb.appendString(action); - _sb.appendChar(' '); + _sb.append(action); + _sb.append(' '); } - Logging::formatNode(_sb, _logFlags, cc(), node); - _sb.appendChar('\n'); + Formatter::formatNode(_sb, _logFlags, cc(), node); + _sb.append('\n'); _logger->log(_sb); } #else diff --git a/3rdparty/asmjit/src/asmjit/core/radefs_p.h b/3rdparty/asmjit/src/asmjit/core/radefs_p.h index c63a1a33966..b77ed1bd738 100644 --- a/3rdparty/asmjit/src/asmjit/core/radefs_p.h +++ b/3rdparty/asmjit/src/asmjit/core/radefs_p.h @@ -28,7 +28,7 @@ #ifndef ASMJIT_NO_COMPILER #include "../core/compiler.h" -#include "../core/logging.h" +#include "../core/logger.h" #include "../core/support.h" #include "../core/zone.h" #include "../core/zonevector.h" @@ -984,10 +984,7 @@ public: //! Stack allocation is preferred. kFlagStackPreferred = 0x00000004u, //! Marked for stack argument reassignment. - kFlagStackArgToStack = 0x00000008u, - - // TODO: Used? - kFlagDirtyStats = 0x80000000u + kFlagStackArgToStack = 0x00000008u }; enum ArgIndex : uint32_t { @@ -1004,7 +1001,7 @@ public: _tiedReg(nullptr), _stackSlot(nullptr), _info(vReg->info()), - _flags(kFlagDirtyStats), + _flags(0), _allocatedMask(0), _clobberSurvivalMask(0), _regByteMask(0), diff --git a/3rdparty/asmjit/src/asmjit/core/ralocal.cpp b/3rdparty/asmjit/src/asmjit/core/ralocal.cpp index 98d7d8fd568..88cb86bde18 100644 --- a/3rdparty/asmjit/src/asmjit/core/ralocal.cpp +++ b/3rdparty/asmjit/src/asmjit/core/ralocal.cpp @@ -596,7 +596,7 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept { // DECIDE whether to MOVE or SPILL. if (allocableRegs) { - uint32_t reassignedId = decideOnUnassignment(group, workId, assignedId, allocableRegs); + uint32_t reassignedId = decideOnReassignment(group, workId, assignedId, allocableRegs); if (reassignedId != RAAssignment::kPhysNone) { ASMJIT_PROPAGATE(onMoveReg(group, workId, reassignedId, assignedId)); allocableRegs ^= Support::bitMask(reassignedId); @@ -897,7 +897,7 @@ Error RALocalAllocator::allocBranch(InstNode* node, RABlock* target, RABlock* co // Additional instructions emitted to switch from the current state to // the `target` state. This means that we have to move these instructions // into an independent code block and patch the jump location. - Operand& targetOp(node->opType(node->opCount() - 1)); + Operand& targetOp = node->op(node->opCount() - 1); if (ASMJIT_UNLIKELY(!targetOp.isLabel())) return DebugUtils::errored(kErrorInvalidState); @@ -970,38 +970,39 @@ Error RALocalAllocator::allocJumpTable(InstNode* node, const RABlocks& targets, // ============================================================================ uint32_t RALocalAllocator::decideOnAssignment(uint32_t group, uint32_t workId, uint32_t physId, uint32_t allocableRegs) const noexcept { - DebugUtils::unused(group, physId); ASMJIT_ASSERT(allocableRegs != 0); + DebugUtils::unused(group, physId); RAWorkReg* workReg = workRegById(workId); - // HIGHEST PRIORITY: Home register id. + // Prefer home register id, if possible. if (workReg->hasHomeRegId()) { uint32_t homeId = workReg->homeRegId(); if (Support::bitTest(allocableRegs, homeId)) return homeId; } - // HIGH PRIORITY: Register IDs used upon block entries. + // Prefer registers used upon block entries. uint32_t previouslyAssignedRegs = workReg->allocatedMask(); if (allocableRegs & previouslyAssignedRegs) allocableRegs &= previouslyAssignedRegs; - if (Support::isPowerOf2(allocableRegs)) - return Support::ctz(allocableRegs); - - // TODO: This is not finished. return Support::ctz(allocableRegs); } -uint32_t RALocalAllocator::decideOnUnassignment(uint32_t group, uint32_t workId, uint32_t physId, uint32_t allocableRegs) const noexcept { +uint32_t RALocalAllocator::decideOnReassignment(uint32_t group, uint32_t workId, uint32_t physId, uint32_t allocableRegs) const noexcept { ASMJIT_ASSERT(allocableRegs != 0); + DebugUtils::unused(group, physId); - // TODO: - DebugUtils::unused(allocableRegs, group, workId, physId); + RAWorkReg* workReg = workRegById(workId); + + // Prefer allocating back to HomeId, if possible. + if (workReg->hasHomeRegId()) { + if (Support::bitTest(allocableRegs, workReg->homeRegId())) + return workReg->homeRegId(); + } - // if (!_curAssignment.isPhysDirty(group, physId)) { - // } + // TODO: [Register Allocator] This could be improved. // Decided to SPILL. return RAAssignment::kPhysNone; diff --git a/3rdparty/asmjit/src/asmjit/core/ralocal_p.h b/3rdparty/asmjit/src/asmjit/core/ralocal_p.h index 0af595b3cd5..c944aad2bb4 100644 --- a/3rdparty/asmjit/src/asmjit/core/ralocal_p.h +++ b/3rdparty/asmjit/src/asmjit/core/ralocal_p.h @@ -198,12 +198,13 @@ public: //! Decides on register assignment. uint32_t decideOnAssignment(uint32_t group, uint32_t workId, uint32_t assignedId, uint32_t allocableRegs) const noexcept; - //! Decides on whether to MOVE or SPILL the given WorkReg. + //! Decides on whether to MOVE or SPILL the given WorkReg, because it's allocated + //! in a physical register that have to be used by another WorkReg. //! //! The function must return either `RAAssignment::kPhysNone`, which means that - //! the WorkReg should be spilled, or a valid physical register ID, which means - //! that the register should be moved to that physical register instead. - uint32_t decideOnUnassignment(uint32_t group, uint32_t workId, uint32_t assignedId, uint32_t allocableRegs) const noexcept; + //! the WorkReg of `workId` should be spilled, or a valid physical register ID, + //! which means that the register should be moved to that physical register instead. + uint32_t decideOnReassignment(uint32_t group, uint32_t workId, uint32_t assignedId, uint32_t allocableRegs) const noexcept; //! Decides on best spill given a register mask `spillableRegs` uint32_t decideOnSpillFor(uint32_t group, uint32_t workId, uint32_t spillableRegs, uint32_t* spillWorkId) const noexcept; diff --git a/3rdparty/asmjit/src/asmjit/core/rapass.cpp b/3rdparty/asmjit/src/asmjit/core/rapass.cpp index 1174635d75d..c5b5ce88a16 100644 --- a/3rdparty/asmjit/src/asmjit/core/rapass.cpp +++ b/3rdparty/asmjit/src/asmjit/core/rapass.cpp @@ -24,6 +24,7 @@ #include "../core/api-build_p.h" #ifndef ASMJIT_NO_COMPILER +#include "../core/formatter.h" #include "../core/ralocal_p.h" #include "../core/rapass_p.h" #include "../core/support.h" @@ -161,7 +162,7 @@ static void RAPass_resetVirtRegData(RAPass* self) noexcept { } } -Error RAPass::runOnFunction(Zone* zone, Logger* logger, FuncNode* func) noexcept { +Error RAPass::runOnFunction(Zone* zone, Logger* logger, FuncNode* func) { _allocator.reset(zone); #ifndef ASMJIT_NO_LOGGING @@ -194,7 +195,6 @@ Error RAPass::runOnFunction(Zone* zone, Logger* logger, FuncNode* func) noexcept // Must be called regardless of the allocation status. onDone(); - // TODO: I don't like this... // Reset possible connections introduced by the register allocator. RAPass_resetVirtRegData(this); @@ -472,7 +472,7 @@ Error RAPass::buildViews() noexcept { if (block->hasSuccessors()) { sb.appendFormat(" #%u -> {", block->blockId()); _dumpBlockIds(sb, block->successors()); - sb.appendString("}\n"); + sb.append("}\n"); } else { sb.appendFormat(" #%u -> {Exit}\n", block->blockId()); @@ -1133,11 +1133,11 @@ static void RAPass_dumpSpans(String& sb, uint32_t index, const LiveRegSpans& liv for (uint32_t i = 0; i < liveSpans.size(); i++) { const LiveRegSpan& liveSpan = liveSpans[i]; - if (i) sb.appendString(", "); + if (i) sb.append(", "); sb.appendFormat("[%u:%u@%u]", liveSpan.a, liveSpan.b, liveSpan.id); } - sb.appendChar('\n'); + sb.append('\n'); } #endif @@ -1296,10 +1296,10 @@ ASMJIT_FAVOR_SPEED Error RAPass::binPack(uint32_t group) noexcept { sb.appendFormat(" Unassigned (%u): ", count); for (i = 0; i < numWorkRegs; i++) { RAWorkReg* workReg = workRegs[i]; - if (i) sb.appendString(", "); - sb.appendString(workReg->name()); + if (i) sb.append(", "); + sb.append(workReg->name()); } - sb.appendChar('\n'); + sb.append('\n'); logger->log(sb); }); } @@ -1380,8 +1380,8 @@ Error RAPass::runLocalAllocator() noexcept { } ASMJIT_PROPAGATE(lra.allocInst(inst)); - if (inst->type() == BaseNode::kNodeFuncCall) - ASMJIT_PROPAGATE(onEmitPreCall(inst->as<FuncCallNode>())); + if (inst->type() == BaseNode::kNodeInvoke) + ASMJIT_PROPAGATE(onEmitPreCall(inst->as<InvokeNode>())); else ASMJIT_PROPAGATE(lra.spillAfterAllocation(inst)); } @@ -1595,7 +1595,7 @@ Error RAPass::useTemporaryMem(BaseMem& out, uint32_t size, uint32_t alignment) n ASMJIT_ASSERT(alignment <= 64); if (_temporaryMem.isNone()) { - ASMJIT_PROPAGATE(cc()->_newStack(_temporaryMem.as<BaseMem>(), size, alignment)); + ASMJIT_PROPAGATE(cc()->_newStack(&_temporaryMem.as<BaseMem>(), size, alignment)); } else { ASMJIT_ASSERT(_temporaryMem.as<BaseMem>().isRegHome()); @@ -1852,27 +1852,31 @@ static void RAPass_dumpRAInst(RAPass* pass, String& sb, const RAInst* raInst) no for (uint32_t i = 0; i < tiedCount; i++) { const RATiedReg& tiedReg = tiedRegs[i]; - if (i != 0) sb.appendChar(' '); + if (i != 0) + sb.append(' '); sb.appendFormat("%s{", pass->workRegById(tiedReg.workId())->name()); - sb.appendChar(tiedReg.isReadWrite() ? 'X' : - tiedReg.isRead() ? 'R' : - tiedReg.isWrite() ? 'W' : '?'); + sb.append(tiedReg.isReadWrite() ? 'X' : + tiedReg.isRead() ? 'R' : + tiedReg.isWrite() ? 'W' : '?'); if (tiedReg.hasUseId()) sb.appendFormat("|Use=%u", tiedReg.useId()); else if (tiedReg.isUse()) - sb.appendString("|Use"); + sb.append("|Use"); if (tiedReg.hasOutId()) sb.appendFormat("|Out=%u", tiedReg.outId()); else if (tiedReg.isOut()) - sb.appendString("|Out"); + sb.append("|Out"); + + if (tiedReg.isLast()) + sb.append("|Last"); - if (tiedReg.isLast()) sb.appendString("|Last"); - if (tiedReg.isKill()) sb.appendString("|Kill"); + if (tiedReg.isKill()) + sb.append("|Kill"); - sb.appendString("}"); + sb.append("}"); } } @@ -1887,13 +1891,13 @@ ASMJIT_FAVOR_SIZE Error RAPass::annotateCode() noexcept { BaseNode* last = block->last(); for (;;) { sb.clear(); - Logging::formatNode(sb, loggerFlags, cc(), node); + Formatter::formatNode(sb, loggerFlags, cc(), node); if ((loggerFlags & FormatOptions::kFlagDebugRA) != 0 && node->isInst() && node->hasPassData()) { const RAInst* raInst = node->passData<RAInst>(); if (raInst->tiedCount() > 0) { sb.padEnd(40); - sb.appendString(" | "); + sb.append(" | "); RAPass_dumpRAInst(this, sb, raInst); } } @@ -1940,15 +1944,15 @@ ASMJIT_FAVOR_SIZE Error RAPass::_dumpBlockLiveness(String& sb, const RABlock* bl if (!n) sb.appendFormat(" %s [", bitsName); else - sb.appendString(", "); + sb.append(", "); - sb.appendString(wReg->name()); + sb.append(wReg->name()); n++; } } if (n) - sb.appendString("]\n"); + sb.append("]\n"); } return kErrorOk; @@ -1961,10 +1965,10 @@ ASMJIT_FAVOR_SIZE Error RAPass::_dumpLiveSpans(String& sb) noexcept { for (uint32_t workId = 0; workId < numWorkRegs; workId++) { RAWorkReg* workReg = _workRegs[workId]; - sb.appendString(" "); + sb.append(" "); size_t oldSize = sb.size(); - sb.appendString(workReg->name()); + sb.append(workReg->name()); sb.padEnd(oldSize + maxSize); RALiveStats& stats = workReg->liveStats(); @@ -1973,16 +1977,17 @@ ASMJIT_FAVOR_SIZE Error RAPass::_dumpLiveSpans(String& sb) noexcept { stats.width(), stats.freq(), stats.priority()); - sb.appendString(": "); + sb.append(": "); LiveRegSpans& liveSpans = workReg->liveSpans(); for (uint32_t x = 0; x < liveSpans.size(); x++) { const LiveRegSpan& liveSpan = liveSpans[x]; - if (x) sb.appendString(", "); + if (x) + sb.append(", "); sb.appendFormat("[%u:%u]", liveSpan.a, liveSpan.b); } - sb.appendChar('\n'); + sb.append('\n'); } return kErrorOk; diff --git a/3rdparty/asmjit/src/asmjit/core/rapass_p.h b/3rdparty/asmjit/src/asmjit/core/rapass_p.h index 5a575ad4bae..df5eb9d7aad 100644 --- a/3rdparty/asmjit/src/asmjit/core/rapass_p.h +++ b/3rdparty/asmjit/src/asmjit/core/rapass_p.h @@ -42,6 +42,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::RABlock] // ============================================================================ +//! Basic block used by register allocator pass. class RABlock { public: ASMJIT_NONCOPYABLE(RABlock) @@ -53,6 +54,7 @@ public: kUnassignedId = 0xFFFFFFFFu }; + //! Basic block flags. enum Flags : uint32_t { //! Block has been constructed from nodes. kFlagIsConstructed = 0x00000001u, @@ -111,9 +113,6 @@ public: //! Block successors. RABlocks _successors; - // TODO: Used? - RABlocks _doms; - enum LiveType : uint32_t { kLiveIn = 0, kLiveOut = 1, @@ -157,7 +156,6 @@ public: _idom(nullptr), _predecessors(), _successors(), - _doms(), _sharedAssignmentId(Globals::kInvalidId), _entryScratchGpRegs(0), _exitScratchGpRegs(0), @@ -470,7 +468,7 @@ public: //! \name Utilities //! \{ - ASMJIT_INLINE Error add(RAWorkReg* workReg, uint32_t flags, uint32_t allocable, uint32_t useId, uint32_t useRewriteMask, uint32_t outId, uint32_t outRewriteMask, uint32_t rmSize = 0) noexcept { + Error add(RAWorkReg* workReg, uint32_t flags, uint32_t allocable, uint32_t useId, uint32_t useRewriteMask, uint32_t outId, uint32_t outRewriteMask, uint32_t rmSize = 0) noexcept { uint32_t group = workReg->group(); RATiedReg* tiedReg = workReg->tiedReg(); @@ -510,7 +508,6 @@ public: if (ASMJIT_UNLIKELY(tiedReg->hasOutId())) return DebugUtils::errored(kErrorOverlappedRegs); tiedReg->setOutId(outId); - // TODO: ? _used[group] |= Support::bitMask(outId); } tiedReg->addRefCount(); @@ -523,7 +520,7 @@ public: } } - ASMJIT_INLINE Error addCallArg(RAWorkReg* workReg, uint32_t useId) noexcept { + Error addCallArg(RAWorkReg* workReg, uint32_t useId) noexcept { ASMJIT_ASSERT(useId != BaseReg::kIdBad); uint32_t flags = RATiedReg::kUse | RATiedReg::kRead | RATiedReg::kUseFixed; @@ -563,7 +560,7 @@ public: } } - ASMJIT_INLINE Error addCallRet(RAWorkReg* workReg, uint32_t outId) noexcept { + Error addCallRet(RAWorkReg* workReg, uint32_t outId) noexcept { ASMJIT_ASSERT(outId != BaseReg::kIdBad); uint32_t flags = RATiedReg::kOut | RATiedReg::kWrite | RATiedReg::kOutFixed; @@ -761,14 +758,14 @@ public: //! \name Accessors //! \{ - //! Returns `Logger` passed to `runOnFunction()`. + //! Returns \ref Logger passed to \ref runOnFunction(). inline Logger* logger() const noexcept { return _logger; } - //! Returns `Logger` passed to `runOnFunction()` or null if `kOptionDebugPasses` is not set. + //! Returns \ref Logger passed to \ref runOnFunction() or null if `kOptionDebugPasses` is not set. inline Logger* debugLogger() const noexcept { return _debugLogger; } - //! Returns `Zone` passed to `runOnFunction()`. + //! Returns \ref Zone passed to \ref runOnFunction(). inline Zone* zone() const noexcept { return _allocator.zone(); } - //! Returns `ZoneAllocator` used by the register allocator. + //! Returns \ref ZoneAllocator used by the register allocator. inline ZoneAllocator* allocator() const noexcept { return const_cast<ZoneAllocator*>(&_allocator); } inline const ZoneVector<RASharedAssignment>& sharedAssignments() const { return _sharedAssignments; } @@ -800,7 +797,7 @@ public: } //! Runs the register allocator for the given `func`. - Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) noexcept override; + Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) override; //! Performs all allocation steps sequentially, called by `runOnFunction()`. Error onPerformAllSteps() noexcept; @@ -810,11 +807,11 @@ public: //! \name Events //! \{ - //! Called by `runOnFunction()` before the register allocation to initialize + //! Called by \ref runOnFunction() before the register allocation to initialize //! architecture-specific data and constraints. virtual void onInit() noexcept = 0; - //! Called by `runOnFunction()` after register allocation to clean everything + //! Called by \ref runOnFunction(` after register allocation to clean everything //! up. Called even if the register allocation failed. virtual void onDone() noexcept = 0; @@ -1009,7 +1006,7 @@ public: //! \{ //! Returns a native size of the general-purpose register of the target architecture. - inline uint32_t gpSize() const noexcept { return _sp.size(); } + inline uint32_t registerSize() const noexcept { return _sp.size(); } inline uint32_t availableRegCount(uint32_t group) const noexcept { return _availableRegCount[group]; } inline RAWorkReg* workRegById(uint32_t workId) const noexcept { return _workRegs[workId]; } @@ -1049,9 +1046,11 @@ public: inline RAStackSlot* getOrCreateStackSlot(RAWorkReg* workReg) noexcept { RAStackSlot* slot = workReg->stackSlot(); - if (slot) return slot; - slot = _stackAllocator.newSlot(_sp.id(), workReg->virtReg()->virtSize(), workReg->virtReg()->alignment(), 0); + if (slot) + return slot; + + slot = _stackAllocator.newSlot(_sp.id(), workReg->virtReg()->virtSize(), workReg->virtReg()->alignment(), RAStackSlot::kFlagRegHome); workReg->_stackSlot = slot; workReg->markStackUsed(); return slot; @@ -1166,7 +1165,7 @@ public: virtual Error onEmitSave(uint32_t workId, uint32_t srcPhysId) noexcept = 0; virtual Error onEmitJump(const Label& label) noexcept = 0; - virtual Error onEmitPreCall(FuncCallNode* call) noexcept = 0; + virtual Error onEmitPreCall(InvokeNode* invokeNode) noexcept = 0; //! \} }; diff --git a/3rdparty/asmjit/src/asmjit/core/rastack.cpp b/3rdparty/asmjit/src/asmjit/core/rastack.cpp index 342b7ce7c9e..b886279a5f3 100644 --- a/3rdparty/asmjit/src/asmjit/core/rastack.cpp +++ b/3rdparty/asmjit/src/asmjit/core/rastack.cpp @@ -43,11 +43,9 @@ RAStackSlot* RAStackAllocator::newSlot(uint32_t baseRegId, uint32_t size, uint32 slot->_baseRegId = uint8_t(baseRegId); slot->_alignment = uint8_t(Support::max<uint32_t>(alignment, 1)); - slot->_reserved[0] = 0; - slot->_reserved[1] = 0; + slot->_flags = uint16_t(flags); slot->_useCount = 0; slot->_size = size; - slot->_flags = flags; slot->_weight = 0; slot->_offset = 0; @@ -92,7 +90,7 @@ Error RAStackAllocator::calculateStackFrame() noexcept { uint32_t alignment = slot->alignment(); ASMJIT_ASSERT(alignment > 0); - uint32_t power = Support::ctz(alignment); + uint32_t power = Support::min<uint32_t>(Support::ctz(alignment), 6); uint64_t weight; if (slot->isRegHome()) @@ -128,7 +126,8 @@ Error RAStackAllocator::calculateStackFrame() noexcept { ZoneVector<RAStackGap> gaps[kSizeCount - 1]; for (RAStackSlot* slot : _slots) { - if (slot->isStackArg()) continue; + if (slot->isStackArg()) + continue; uint32_t slotAlignment = slot->alignment(); uint32_t alignedOffset = Support::alignUp(offset, slotAlignment); diff --git a/3rdparty/asmjit/src/asmjit/core/rastack_p.h b/3rdparty/asmjit/src/asmjit/core/rastack_p.h index d45f7aa8896..33d4e1d15e8 100644 --- a/3rdparty/asmjit/src/asmjit/core/rastack_p.h +++ b/3rdparty/asmjit/src/asmjit/core/rastack_p.h @@ -41,10 +41,14 @@ ASMJIT_BEGIN_NAMESPACE //! Stack slot. struct RAStackSlot { + //! Stack slot flags. + //! + //! TODO: kFlagStackArg is not used by the current implementation, do we need to keep it? enum Flags : uint32_t { - // TODO: kFlagRegHome is apparently not used, but isRegHome() is. - kFlagRegHome = 0x00000001u, //!< Stack slot is register home slot. - kFlagStackArg = 0x00000002u //!< Stack slot position matches argument passed via stack. + //! Stack slot is register home slot. + kFlagRegHome = 0x0001u, + //! Stack slot position matches argument passed via stack. + kFlagStackArg = 0x0002u }; enum ArgIndex : uint32_t { @@ -56,17 +60,15 @@ struct RAStackSlot { //! Minimum alignment required by the slot. uint8_t _alignment; //! Reserved for future use. - uint8_t _reserved[2]; + uint16_t _flags; //! Size of memory required by the slot. uint32_t _size; - //! Slot flags. - uint32_t _flags; //! Usage counter (one unit equals one memory access). uint32_t _useCount; - //! Weight of the slot (calculated by `calculateStackFrame()`). + //! Weight of the slot, calculated by \ref RAStackAllocator::calculateStackFrame(). uint32_t _weight; - //! Stack offset (calculated by `calculateStackFrame()`). + //! Stack offset, calculated by \ref RAStackAllocator::calculateStackFrame(). int32_t _offset; //! \name Accessors @@ -79,9 +81,11 @@ struct RAStackSlot { inline uint32_t alignment() const noexcept { return _alignment; } inline uint32_t flags() const noexcept { return _flags; } - inline void addFlags(uint32_t flags) noexcept { _flags |= flags; } - inline bool isRegHome() const noexcept { return (_flags & kFlagRegHome) != 0; } - inline bool isStackArg() const noexcept { return (_flags & kFlagStackArg) != 0; } + inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + inline void addFlags(uint32_t flags) noexcept { _flags = uint16_t(_flags | flags); } + + inline bool isRegHome() const noexcept { return hasFlag(kFlagRegHome); } + inline bool isStackArg() const noexcept { return hasFlag(kFlagStackArg); } inline uint32_t useCount() const noexcept { return _useCount; } inline void addUseCount(uint32_t n = 1) noexcept { _useCount += n; } diff --git a/3rdparty/asmjit/src/asmjit/core/string.cpp b/3rdparty/asmjit/src/asmjit/core/string.cpp index 564a566f042..e059884c844 100644 --- a/3rdparty/asmjit/src/asmjit/core/string.cpp +++ b/3rdparty/asmjit/src/asmjit/core/string.cpp @@ -34,7 +34,7 @@ ASMJIT_BEGIN_NAMESPACE static const char String_baseN[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; constexpr size_t kMinAllocSize = 64; -constexpr size_t kMaxAllocSize = std::numeric_limits<size_t>::max() - Globals::kGrowThreshold; +constexpr size_t kMaxAllocSize = SIZE_MAX - Globals::kGrowThreshold; // ============================================================================ // [asmjit::String] @@ -150,7 +150,7 @@ char* String::prepare(uint32_t op, size_t size) noexcept { } } -Error String::assignString(const char* data, size_t size) noexcept { +Error String::assign(const char* data, size_t size) noexcept { char* dst = nullptr; // Null terminated string without `size` specified. @@ -222,7 +222,8 @@ Error String::_opString(uint32_t op, const char* str, size_t size) noexcept { return kErrorOk; char* p = prepare(op, size); - if (!p) return DebugUtils::errored(kErrorOutOfMemory); + if (!p) + return DebugUtils::errored(kErrorOutOfMemory); memcpy(p, str, size); return kErrorOk; @@ -230,7 +231,8 @@ Error String::_opString(uint32_t op, const char* str, size_t size) noexcept { Error String::_opChar(uint32_t op, char c) noexcept { char* p = prepare(op, 1); - if (!p) return DebugUtils::errored(kErrorOutOfMemory); + if (!p) + return DebugUtils::errored(kErrorOutOfMemory); *p = c; return kErrorOk; @@ -241,7 +243,8 @@ Error String::_opChars(uint32_t op, char c, size_t n) noexcept { return kErrorOk; char* p = prepare(op, n); - if (!p) return DebugUtils::errored(kErrorOutOfMemory); + if (!p) + return DebugUtils::errored(kErrorOutOfMemory); memset(p, c, n); return kErrorOk; @@ -349,7 +352,7 @@ Error String::_opHex(uint32_t op, const void* data, size_t size, char separator) return kErrorOk; if (separator) { - if (ASMJIT_UNLIKELY(size >= std::numeric_limits<size_t>::max() / 3)) + if (ASMJIT_UNLIKELY(size >= SIZE_MAX / 3)) return DebugUtils::errored(kErrorOutOfMemory); dst = prepare(op, size * 3 - 1); @@ -369,7 +372,7 @@ Error String::_opHex(uint32_t op, const void* data, size_t size, char separator) } } else { - if (ASMJIT_UNLIKELY(size >= std::numeric_limits<size_t>::max() / 2)) + if (ASMJIT_UNLIKELY(size >= SIZE_MAX / 2)) return DebugUtils::errored(kErrorOutOfMemory); dst = prepare(op, size * 2); @@ -404,6 +407,9 @@ Error String::_opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept { int fmtResult; size_t outputSize; + va_list apCopy; + va_copy(apCopy, ap); + if (remainingCapacity >= 128) { fmtResult = vsnprintf(data() + startAt, remainingCapacity, fmt, ap); outputSize = size_t(fmtResult); @@ -428,7 +434,7 @@ Error String::_opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept { if (ASMJIT_UNLIKELY(!p)) return DebugUtils::errored(kErrorOutOfMemory); - fmtResult = vsnprintf(p, outputSize + 1, fmt, ap); + fmtResult = vsnprintf(p, outputSize + 1, fmt, apCopy); ASMJIT_ASSERT(size_t(fmtResult) == outputSize); return kErrorOk; @@ -483,7 +489,7 @@ UNIT(core_string) { EXPECT(s.isLarge() == false); EXPECT(s.isExternal() == false); - EXPECT(s.assignChar('a') == kErrorOk); + EXPECT(s.assign('a') == kErrorOk); EXPECT(s.size() == 1); EXPECT(s.capacity() == String::kSSOCapacity); EXPECT(s.data()[0] == 'a'); @@ -502,7 +508,7 @@ UNIT(core_string) { EXPECT(s.eq("bbbb") == true); EXPECT(s.eq("bbbb", 4) == true); - EXPECT(s.assignString("abc") == kErrorOk); + EXPECT(s.assign("abc") == kErrorOk); EXPECT(s.size() == 3); EXPECT(s.capacity() == String::kSSOCapacity); EXPECT(s.data()[0] == 'a'); @@ -513,7 +519,7 @@ UNIT(core_string) { EXPECT(s.eq("abc", 3) == true); const char* large = "Large string that will not fit into SSO buffer"; - EXPECT(s.assignString(large) == kErrorOk); + EXPECT(s.assign(large) == kErrorOk); EXPECT(s.isLarge() == true); EXPECT(s.size() == strlen(large)); EXPECT(s.capacity() > String::kSSOCapacity); @@ -522,7 +528,7 @@ UNIT(core_string) { const char* additional = " (additional content)"; EXPECT(s.isLarge() == true); - EXPECT(s.appendString(additional) == kErrorOk); + EXPECT(s.append(additional) == kErrorOk); EXPECT(s.size() == strlen(large) + strlen(additional)); EXPECT(s.clear() == kErrorOk); diff --git a/3rdparty/asmjit/src/asmjit/core/string.h b/3rdparty/asmjit/src/asmjit/core/string.h index 22108f21f8b..4c490d87b1d 100644 --- a/3rdparty/asmjit/src/asmjit/core/string.h +++ b/3rdparty/asmjit/src/asmjit/core/string.h @@ -29,10 +29,34 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_support +//! \addtogroup asmjit_utilities //! \{ // ============================================================================ +// [asmjit::FixedString] +// ============================================================================ + +//! A fixed string - only useful for strings that would never exceed `N - 1` +//! characters; always null-terminated. +template<size_t N> +union FixedString { + enum : uint32_t { + kNumU32 = uint32_t((N + sizeof(uint32_t) - 1) / sizeof(uint32_t)) + }; + + char str[kNumU32 * sizeof(uint32_t)]; + uint32_t u32[kNumU32]; + + //! \name Utilities + //! \{ + + inline bool eq(const char* other) const noexcept { + return strcmp(str, other) == 0; + } + + //! \} +}; +// ============================================================================ // [asmjit::String] // ============================================================================ @@ -60,8 +84,10 @@ public: //! String operation. enum Op : uint32_t { - kOpAssign = 0, - kOpAppend = 1 + //! Assignment - a new content replaces the current one. + kOpAssign = 0, + //! Append - a new content is appended to the string. + kOpAppend = 1 }; //! String format flags. @@ -114,12 +140,13 @@ public: //! \name Construction & Destruction //! \{ + //! Creates a default-initialized string if zero length. inline String() noexcept : _small {} {} + //! Creates a string that takes ownership of the content of the `other` string. inline String(String&& other) noexcept { - for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_raw.uptr); i++) - _raw.uptr[i] = other._raw.uptr[i]; + _raw = other._raw; other._resetInternal(); } @@ -135,6 +162,12 @@ public: //! \name Overloaded Operators //! \{ + inline String& operator=(String&& other) noexcept { + swap(other); + other.reset(); + return *this; + } + inline bool operator==(const char* other) const noexcept { return eq(other); } inline bool operator!=(const char* other) const noexcept { return !eq(other); } @@ -149,13 +182,21 @@ public: inline bool isLarge() const noexcept { return _type >= kTypeLarge; } inline bool isExternal() const noexcept { return _type == kTypeExternal; } + //! Tests whether the string is empty. inline bool empty() const noexcept { return size() == 0; } + //! Returns the size of the string. inline size_t size() const noexcept { return isLarge() ? size_t(_large.size) : size_t(_type); } + //! Returns the capacity of the string. inline size_t capacity() const noexcept { return isLarge() ? _large.capacity : size_t(kSSOCapacity); } + //! Returns the data of the string. inline char* data() noexcept { return isLarge() ? _large.data : _small.data; } + //! \overload inline const char* data() const noexcept { return isLarge() ? _large.data : _small.data; } + inline char* start() noexcept { return data(); } + inline const char* start() const noexcept { return data(); } + inline char* end() noexcept { return data() + size(); } inline const char* end() const noexcept { return data() + size(); } @@ -164,102 +205,120 @@ public: //! \name String Operations //! \{ - //! Clear the content of the string. + //! Swaps the content of this string with `other`. + inline void swap(String& other) noexcept { + std::swap(_raw, other._raw); + } + + //! Clears the content of the string. ASMJIT_API Error clear() noexcept; ASMJIT_API char* prepare(uint32_t op, size_t size) noexcept; ASMJIT_API Error _opString(uint32_t op, const char* str, size_t size = SIZE_MAX) noexcept; - ASMJIT_API Error _opFormat(uint32_t op, const char* fmt, ...) noexcept; - ASMJIT_API Error _opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept; ASMJIT_API Error _opChar(uint32_t op, char c) noexcept; ASMJIT_API Error _opChars(uint32_t op, char c, size_t n) noexcept; ASMJIT_API Error _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept; ASMJIT_API Error _opHex(uint32_t op, const void* data, size_t size, char separator = '\0') noexcept; + ASMJIT_API Error _opFormat(uint32_t op, const char* fmt, ...) noexcept; + ASMJIT_API Error _opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept; - //! Replace the string content to a string specified by `data` and `size`. If - //! `size` is `SIZE_MAX` then it's considered null-terminated and its length - //! will be obtained through `strlen()`. - ASMJIT_API Error assignString(const char* data, size_t size = SIZE_MAX) noexcept; - - //! Replace the current content by a formatted string `fmt`. - template<typename... Args> - inline Error assignFormat(const char* fmt, Args&&... args) noexcept { - return _opFormat(kOpAssign, fmt, std::forward<Args>(args)...); - } + //! Replaces the current of the string with `data` of the given `size`. + //! + //! Null terminated strings can set `size` to `SIZE_MAX`. + ASMJIT_API Error assign(const char* data, size_t size = SIZE_MAX) noexcept; - //! Replace the current content by a formatted string `fmt` (va_list version). - inline Error assignVFormat(const char* fmt, va_list ap) noexcept { - return _opVFormat(kOpAssign, fmt, ap); + //! Replaces the current of the string with `other` string. + inline Error assign(const String& other) noexcept { + return assign(other.data(), other.size()); } - //! Replace the current content by a single `c` character. - inline Error assignChar(char c) noexcept { + //! Replaces the current of the string by a single `c` character. + inline Error assign(char c) noexcept { return _opChar(kOpAssign, c); } - //! Replace the current content by `c` character `n` times. + //! Replaces the current of the string by a `c` character, repeated `n` times. inline Error assignChars(char c, size_t n) noexcept { return _opChars(kOpAssign, c, n); } - //! Replace the current content by a formatted integer `i` (signed). + //! Replaces the current of the string by a formatted integer `i` (signed). inline Error assignInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { return _opNumber(kOpAssign, uint64_t(i), base, width, flags | kFormatSigned); } - //! Replace the current content by a formatted integer `i` (unsigned). + //! Replaces the current of the string by a formatted integer `i` (unsigned). inline Error assignUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { return _opNumber(kOpAssign, i, base, width, flags); } - //! Replace the current content by the given `data` converted to a HEX string. + //! Replaces the current of the string by the given `data` converted to a HEX string. inline Error assignHex(const void* data, size_t size, char separator = '\0') noexcept { return _opHex(kOpAssign, data, size, separator); } - //! Append string `str` of size `size` (or possibly null terminated). - inline Error appendString(const char* str, size_t size = SIZE_MAX) noexcept { - return _opString(kOpAppend, str, size); + //! Replaces the current of the string by a formatted string `fmt`. + template<typename... Args> + inline Error assignFormat(const char* fmt, Args&&... args) noexcept { + return _opFormat(kOpAssign, fmt, std::forward<Args>(args)...); } - template<typename... Args> - inline Error appendFormat(const char* fmt, Args&&... args) noexcept { - return _opFormat(kOpAppend, fmt, std::forward<Args>(args)...); + //! Replaces the current of the string by a formatted string `fmt` (va_list version). + inline Error assignVFormat(const char* fmt, va_list ap) noexcept { + return _opVFormat(kOpAssign, fmt, ap); } - //! Append a formatted string `fmt` (va_list version). - inline Error appendVFormat(const char* fmt, va_list ap) noexcept { - return _opVFormat(kOpAppend, fmt, ap); + //! Appends `str` having the given size `size` to the string. + //! + //! Null terminated strings can set `size` to `SIZE_MAX`. + inline Error append(const char* str, size_t size = SIZE_MAX) noexcept { + return _opString(kOpAppend, str, size); + } + + //! Appends `other` string to this string. + inline Error append(const String& other) noexcept { + return append(other.data(), other.size()); } - //! Append a single `c` character. - inline Error appendChar(char c) noexcept { + //! Appends a single `c` character. + inline Error append(char c) noexcept { return _opChar(kOpAppend, c); } - //! Append `c` character `n` times. + //! Appends `c` character repeated `n` times. inline Error appendChars(char c, size_t n) noexcept { return _opChars(kOpAppend, c, n); } - ASMJIT_API Error padEnd(size_t n, char c = ' ') noexcept; - - //! Append `i`. + //! Appends a formatted integer `i` (signed). inline Error appendInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { return _opNumber(kOpAppend, uint64_t(i), base, width, flags | kFormatSigned); } - //! Append `i`. + //! Appends a formatted integer `i` (unsigned). inline Error appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { return _opNumber(kOpAppend, i, base, width, flags); } - //! Append the given `data` converted to a HEX string. + //! Appends the given `data` converted to a HEX string. inline Error appendHex(const void* data, size_t size, char separator = '\0') noexcept { return _opHex(kOpAppend, data, size, separator); } + //! Appends a formatted string `fmt` with `args`. + template<typename... Args> + inline Error appendFormat(const char* fmt, Args&&... args) noexcept { + return _opFormat(kOpAppend, fmt, std::forward<Args>(args)...); + } + + //! Appends a formatted string `fmt` (va_list version). + inline Error appendVFormat(const char* fmt, va_list ap) noexcept { + return _opVFormat(kOpAppend, fmt, ap); + } + + ASMJIT_API Error padEnd(size_t n, char c = ' ') noexcept; + //! Truncate the string length into `newSize`. ASMJIT_API Error truncate(size_t newSize) noexcept; @@ -288,6 +347,20 @@ public: } //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use assign() instead of assignString()") + inline Error assignString(const char* data, size_t size = SIZE_MAX) noexcept { return assign(data, size); } + + ASMJIT_DEPRECATED("Use assign() instead of assignChar()") + inline Error assignChar(char c) noexcept { return assign(c); } + + ASMJIT_DEPRECATED("Use append() instead of appendString()") + inline Error appendString(const char* data, size_t size = SIZE_MAX) noexcept { return append(data, size); } + + ASMJIT_DEPRECATED("Use append() instead of appendChar()") + inline Error appendChar(char c) noexcept { return append(c); } +#endif // !ASMJIT_NO_DEPRECATED }; // ============================================================================ @@ -320,31 +393,6 @@ public: //! \} }; -// ============================================================================ -// [asmjit::FixedString] -// ============================================================================ - -//! A fixed string - only useful for strings that would never exceed `N - 1` -//! characters; always null-terminated. -template<size_t N> -union FixedString { - enum : uint32_t { - kNumU32 = uint32_t((N + sizeof(uint32_t) - 1) / sizeof(uint32_t)) - }; - - char str[kNumU32 * sizeof(uint32_t)]; - uint32_t u32[kNumU32]; - - //! \name Utilities - //! \{ - - inline bool eq(const char* other) const noexcept { - return strcmp(str, other) == 0; - } - - //! \} -}; - //! \} ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/support.cpp b/3rdparty/asmjit/src/asmjit/core/support.cpp index 6b7e0854d81..a99477dc9fe 100644 --- a/3rdparty/asmjit/src/asmjit/core/support.cpp +++ b/3rdparty/asmjit/src/asmjit/core/support.cpp @@ -100,7 +100,7 @@ static void testBitUtils() noexcept { EXPECT(Support::bitTest((1 << i), i) == true, "Support::bitTest(%X, %u) should return true", (1 << i), i); } - INFO("Support::lsbMask()"); + INFO("Support::lsbMask<uint32_t>()"); for (i = 0; i < 32; i++) { uint32_t expectedBits = 0; for (uint32_t b = 0; b < i; b++) @@ -108,6 +108,14 @@ static void testBitUtils() noexcept { EXPECT(Support::lsbMask<uint32_t>(i) == expectedBits); } + INFO("Support::lsbMask<uint64_t>()"); + for (i = 0; i < 64; i++) { + uint64_t expectedBits = 0; + for (uint32_t b = 0; b < i; b++) + expectedBits |= uint64_t(1) << b; + EXPECT(Support::lsbMask<uint64_t>(i) == expectedBits); + } + INFO("Support::popcnt()"); for (i = 0; i < 32; i++) EXPECT(Support::popcnt((uint32_t(1) << i)) == 1); for (i = 0; i < 64; i++) EXPECT(Support::popcnt((uint64_t(1) << i)) == 1); diff --git a/3rdparty/asmjit/src/asmjit/core/support.h b/3rdparty/asmjit/src/asmjit/core/support.h index 0f49b78f0af..9e2bee477cb 100644 --- a/3rdparty/asmjit/src/asmjit/core/support.h +++ b/3rdparty/asmjit/src/asmjit/core/support.h @@ -32,7 +32,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_support +//! \addtogroup asmjit_utilities //! \{ //! Contains support classes and functions that may be used by AsmJit source @@ -69,28 +69,35 @@ namespace Internal { template<> struct AlignedInt<uint64_t, 4> { typedef uint64_t ASMJIT_ALIGN_TYPE(T, 4); }; template<> struct AlignedInt<uint64_t, 8> { typedef uint64_t T; }; - // IntBySize - Make an int-type by size (signed or unsigned) that is the + // StdInt - Make an int-type by size (signed or unsigned) that is the // same as types defined by <stdint.h>. // Int32Or64 - Make an int-type that has at least 32 bits: [u]int[32|64]_t. - template<size_t SIZE, int IS_SIGNED> - struct IntBySize {}; // Fail if not specialized. + template<size_t Size, unsigned Unsigned> + struct StdInt {}; // Fail if not specialized. - template<> struct IntBySize<1, 0> { typedef uint8_t Type; }; - template<> struct IntBySize<1, 1> { typedef int8_t Type; }; - template<> struct IntBySize<2, 0> { typedef uint16_t Type; }; - template<> struct IntBySize<2, 1> { typedef int16_t Type; }; - template<> struct IntBySize<4, 0> { typedef uint32_t Type; }; - template<> struct IntBySize<4, 1> { typedef int32_t Type; }; - template<> struct IntBySize<8, 0> { typedef uint64_t Type; }; - template<> struct IntBySize<8, 1> { typedef int64_t Type; }; + template<> struct StdInt<1, 0> { typedef int8_t Type; }; + template<> struct StdInt<1, 1> { typedef uint8_t Type; }; + template<> struct StdInt<2, 0> { typedef int16_t Type; }; + template<> struct StdInt<2, 1> { typedef uint16_t Type; }; + template<> struct StdInt<4, 0> { typedef int32_t Type; }; + template<> struct StdInt<4, 1> { typedef uint32_t Type; }; + template<> struct StdInt<8, 0> { typedef int64_t Type; }; + template<> struct StdInt<8, 1> { typedef uint64_t Type; }; - template<typename T, int IS_SIGNED = std::is_signed<T>::value> - struct Int32Or64 : public IntBySize<sizeof(T) <= 4 ? size_t(4) : sizeof(T), IS_SIGNED> {}; + template<typename T, int Unsigned = std::is_unsigned<T>::value> + struct Int32Or64 : public StdInt<sizeof(T) <= 4 ? size_t(4) : sizeof(T), Unsigned> {}; } //! \endcond // ============================================================================ +// [asmjit::Support - Basic Traits] +// ============================================================================ + +template<typename T> +static constexpr bool isUnsigned() noexcept { return std::is_unsigned<T>::value; } + +// ============================================================================ // [asmjit::Support - FastUInt8] // ============================================================================ @@ -101,20 +108,32 @@ typedef unsigned int FastUInt8; #endif // ============================================================================ -// [asmjit::Support - IntBySize / Int32Or64] +// [asmjit::Support - asInt / asUInt / asNormalized] // ============================================================================ //! Casts an integer `x` to either `int32_t` or `int64_t` depending on `T`. template<typename T> -static constexpr typename Internal::Int32Or64<T, 1>::Type asInt(T x) noexcept { return (typename Internal::Int32Or64<T, 1>::Type)x; } +static constexpr typename Internal::Int32Or64<T, 0>::Type asInt(const T& x) noexcept { + return (typename Internal::Int32Or64<T, 0>::Type)x; +} //! Casts an integer `x` to either `uint32_t` or `uint64_t` depending on `T`. template<typename T> -static constexpr typename Internal::Int32Or64<T, 0>::Type asUInt(T x) noexcept { return (typename Internal::Int32Or64<T, 0>::Type)x; } +static constexpr typename Internal::Int32Or64<T, 1>::Type asUInt(const T& x) noexcept { + return (typename Internal::Int32Or64<T, 1>::Type)x; +} //! Casts an integer `x` to either `int32_t`, uint32_t`, `int64_t`, or `uint64_t` depending on `T`. template<typename T> -static constexpr typename Internal::Int32Or64<T>::Type asNormalized(T x) noexcept { return (typename Internal::Int32Or64<T>::Type)x; } +static constexpr typename Internal::Int32Or64<T>::Type asNormalized(const T& x) noexcept { + return (typename Internal::Int32Or64<T>::Type)x; +} + +//! Casts an integer `x` to the same type as defined by `<stdint.h>`. +template<typename T> +static constexpr typename Internal::StdInt<sizeof(T), isUnsigned<T>()>::Type asStdInt(const T& x) noexcept { + return (typename Internal::StdInt<sizeof(T), isUnsigned<T>()>::Type)x; +} // ============================================================================ // [asmjit::Support - BitCast] @@ -142,7 +161,7 @@ static inline Dst bitCast(const Src& x) noexcept { return Internal::BitCastUnion // ============================================================================ //! Storage used to store a pack of bits (should by compatible with a machine word). -typedef Internal::IntBySize<sizeof(uintptr_t), 0>::Type BitWord; +typedef Internal::StdInt<sizeof(uintptr_t), 1>::Type BitWord; template<typename T> static constexpr uint32_t bitSizeOf() noexcept { return uint32_t(sizeof(T) * 8u); } @@ -194,14 +213,14 @@ static constexpr T blsi(T x) noexcept { //! Generate a trailing bit-mask that has `n` least significant (trailing) bits set. template<typename T, typename CountT> -static constexpr T lsbMask(CountT n) noexcept { +static constexpr T lsbMask(const CountT& n) noexcept { typedef typename std::make_unsigned<T>::type U; return (sizeof(U) < sizeof(uintptr_t)) + // Prevent undefined behavior by using a larger type than T. ? T(U((uintptr_t(1) << n) - uintptr_t(1))) - // Shifting more bits than the type provides is UNDEFINED BEHAVIOR. - // In such case we trash the result by ORing it with a mask that has - // all bits set and discards the UNDEFINED RESULT of the shift. - : T(((U(1) << n) - U(1u)) | neg(U(n >= CountT(bitSizeOf<T>())))); + // Prevent undefined behavior by performing `n & (nBits - 1)` so it's always within the range. + : shr(sar(neg(T(n)), bitSizeOf<T>() - 1u), + neg(T(n)) & CountT(bitSizeOf<T>() - 1u)); } //! Tests whether the given value `x` has `n`th bit set. @@ -398,30 +417,113 @@ static constexpr T max(const T& a, const T& b, Args&&... args) noexcept { return //! \cond namespace Internal { template<typename T> - static ASMJIT_INLINE T addOverflowImpl(T x, T y, FastUInt8* of) noexcept { + ASMJIT_INLINE T addOverflowFallback(T x, T y, FastUInt8* of) noexcept { typedef typename std::make_unsigned<T>::type U; U result = U(x) + U(y); - *of = FastUInt8(*of | FastUInt8(std::is_unsigned<T>::value ? result < U(x) : T((U(x) ^ ~U(y)) & (U(x) ^ result)) < 0)); + *of = FastUInt8(*of | FastUInt8(isUnsigned<T>() ? result < U(x) : T((U(x) ^ ~U(y)) & (U(x) ^ result)) < 0)); return T(result); } template<typename T> - static ASMJIT_INLINE T subOverflowImpl(T x, T y, FastUInt8* of) noexcept { + ASMJIT_INLINE T subOverflowFallback(T x, T y, FastUInt8* of) noexcept { typedef typename std::make_unsigned<T>::type U; U result = U(x) - U(y); - *of = FastUInt8(*of | FastUInt8(std::is_unsigned<T>::value ? result > U(x) : T((U(x) ^ U(y)) & (U(x) ^ result)) < 0)); + *of = FastUInt8(*of | FastUInt8(isUnsigned<T>() ? result > U(x) : T((U(x) ^ U(y)) & (U(x) ^ result)) < 0)); return T(result); } -} + + template<typename T> + ASMJIT_INLINE T mulOverflowFallback(T x, T y, FastUInt8* of) noexcept { + typedef typename Internal::StdInt<sizeof(T) * 2, isUnsigned<T>()>::Type I; + typedef typename std::make_unsigned<I>::type U; + + U mask = allOnes<U>(); + if (std::is_signed<T>::value) { + U prod = U(I(x)) * U(I(y)); + *of = FastUInt8(*of | FastUInt8(I(prod) < I(std::numeric_limits<T>::lowest()) || I(prod) > I(std::numeric_limits<T>::max()))); + return T(I(prod & mask)); + } + else { + U prod = U(x) * U(y); + *of = FastUInt8(*of | FastUInt8((prod & ~mask) != 0)); + return T(prod & mask); + } + } + + template<> + ASMJIT_INLINE int64_t mulOverflowFallback(int64_t x, int64_t y, FastUInt8* of) noexcept { + int64_t result = int64_t(uint64_t(x) * uint64_t(y)); + *of = FastUInt8(*of | FastUInt8(x && (result / x != y))); + return result; + } + + template<> + ASMJIT_INLINE uint64_t mulOverflowFallback(uint64_t x, uint64_t y, FastUInt8* of) noexcept { + uint64_t result = x * y; + *of = FastUInt8(*of | FastUInt8(y != 0 && allOnes<uint64_t>() / y < x)); + return result; + } + + // These can be specialized. + template<typename T> ASMJIT_INLINE T addOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return addOverflowFallback(x, y, of); } + template<typename T> ASMJIT_INLINE T subOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return subOverflowFallback(x, y, of); } + template<typename T> ASMJIT_INLINE T mulOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return mulOverflowFallback(x, y, of); } + + #if defined(__GNUC__) && !defined(ASMJIT_NO_INTRINSICS) + #if defined(__clang__) || __GNUC__ >= 5 + #define ASMJIT_ARITH_OVERFLOW_SPECIALIZE(FUNC, T, RESULT_T, BUILTIN) \ + template<> \ + ASMJIT_INLINE T FUNC(const T& x, const T& y, FastUInt8* of) noexcept { \ + RESULT_T result; \ + *of = FastUInt8(*of | (BUILTIN((RESULT_T)x, (RESULT_T)y, &result))); \ + return T(result); \ + } + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, int32_t , int , __builtin_sadd_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint32_t, unsigned int , __builtin_uadd_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, int64_t , long long , __builtin_saddll_overflow) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint64_t, unsigned long long, __builtin_uaddll_overflow) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, int32_t , int , __builtin_ssub_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint32_t, unsigned int , __builtin_usub_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, int64_t , long long , __builtin_ssubll_overflow) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint64_t, unsigned long long, __builtin_usubll_overflow) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, int32_t , int , __builtin_smul_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, uint32_t, unsigned int , __builtin_umul_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, int64_t , long long , __builtin_smulll_overflow) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, uint64_t, unsigned long long, __builtin_umulll_overflow) + #undef ASMJIT_ARITH_OVERFLOW_SPECIALIZE + #endif + #endif + + // There is a bug in MSVC that makes these specializations unusable, maybe in the future... + #if defined(_MSC_VER) && 0 + #define ASMJIT_ARITH_OVERFLOW_SPECIALIZE(FUNC, T, ALT_T, BUILTIN) \ + template<> \ + ASMJIT_INLINE T FUNC(T x, T y, FastUInt8* of) noexcept { \ + ALT_T result; \ + *of = FastUInt8(*of | BUILTIN(0, (ALT_T)x, (ALT_T)y, &result)); \ + return T(result); \ + } + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint32_t, unsigned int , _addcarry_u32 ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint32_t, unsigned int , _subborrow_u32) + #if ARCH_BITS >= 64 + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint64_t, unsigned __int64 , _addcarry_u64 ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint64_t, unsigned __int64 , _subborrow_u64) + #endif + #undef ASMJIT_ARITH_OVERFLOW_SPECIALIZE + #endif +} // {Internal} //! \endcond template<typename T> -static ASMJIT_INLINE T addOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::addOverflowImpl(x, y, of)); } +static ASMJIT_INLINE T addOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::addOverflowImpl(asStdInt(x), asStdInt(y), of)); } + +template<typename T> +static ASMJIT_INLINE T subOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::subOverflowImpl(asStdInt(x), asStdInt(y), of)); } template<typename T> -static ASMJIT_INLINE T subOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::subOverflowImpl(x, y, of)); } +static ASMJIT_INLINE T mulOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::mulOverflowImpl(asStdInt(x), asStdInt(y), of)); } // ============================================================================ // [asmjit::Support - Alignment] @@ -429,7 +531,7 @@ static ASMJIT_INLINE T subOverflow(const T& x, const T& y, FastUInt8* of) noexce template<typename X, typename Y> static constexpr bool isAligned(X base, Y alignment) noexcept { - typedef typename Internal::IntBySize<sizeof(X), 0>::Type U; + typedef typename Internal::StdInt<sizeof(X), 1>::Type U; return ((U)base % (U)alignment) == 0; } @@ -442,27 +544,27 @@ static constexpr bool isPowerOf2(T x) noexcept { template<typename X, typename Y> static constexpr X alignUp(X x, Y alignment) noexcept { - typedef typename Internal::IntBySize<sizeof(X), 0>::Type U; + typedef typename Internal::StdInt<sizeof(X), 1>::Type U; return (X)( ((U)x + ((U)(alignment) - 1u)) & ~((U)(alignment) - 1u) ); } template<typename T> static constexpr T alignUpPowerOf2(T x) noexcept { - typedef typename Internal::IntBySize<sizeof(T), 0>::Type U; + typedef typename Internal::StdInt<sizeof(T), 1>::Type U; return (T)(fillTrailingBits(U(x) - 1u) + 1u); } //! Returns either zero or a positive difference between `base` and `base` when //! aligned to `alignment`. template<typename X, typename Y> -static constexpr typename Internal::IntBySize<sizeof(X), 0>::Type alignUpDiff(X base, Y alignment) noexcept { - typedef typename Internal::IntBySize<sizeof(X), 0>::Type U; +static constexpr typename Internal::StdInt<sizeof(X), 1>::Type alignUpDiff(X base, Y alignment) noexcept { + typedef typename Internal::StdInt<sizeof(X), 1>::Type U; return alignUp(U(base), alignment) - U(base); } template<typename X, typename Y> static constexpr X alignDown(X x, Y alignment) noexcept { - typedef typename Internal::IntBySize<sizeof(X), 0>::Type U; + typedef typename Internal::StdInt<sizeof(X), 1>::Type U; return (X)( (U)x & ~((U)(alignment) - 1u) ); } @@ -475,7 +577,7 @@ static constexpr X alignDown(X x, Y alignment) noexcept { //! the number of BitWords to represent N bits, for example. template<typename X, typename Y> static constexpr X numGranularized(X base, Y granularity) noexcept { - typedef typename Internal::IntBySize<sizeof(X), 0>::Type U; + typedef typename Internal::StdInt<sizeof(X), 1>::Type U; return X((U(base) + U(granularity) - 1) / U(granularity)); } @@ -620,10 +722,10 @@ static inline uint32_t byteShiftOfDWordStruct(uint32_t index) noexcept { // ============================================================================ template<typename T> -static constexpr T asciiToLower(T c) noexcept { return c ^ (T(c >= T('A') && c <= T('Z')) << 5); } +static constexpr T asciiToLower(T c) noexcept { return T(c ^ T(T(c >= T('A') && c <= T('Z')) << 5)); } template<typename T> -static constexpr T asciiToUpper(T c) noexcept { return c ^ (T(c >= T('a') && c <= T('z')) << 5); } +static constexpr T asciiToUpper(T c) noexcept { return T(c ^ T(T(c >= T('a') && c <= T('z')) << 5)); } static ASMJIT_INLINE size_t strLen(const char* s, size_t maxSize) noexcept { size_t i = 0; @@ -920,6 +1022,7 @@ static inline void writeU64uBE(void* p, uint64_t x) noexcept { writeU64xBE<1>(p, // [asmjit::Support - Operators] // ============================================================================ +//! \cond INTERNAL struct Set { template<typename T> static inline T op(T x, T y) noexcept { DebugUtils::unused(x); return y; } }; struct SetNot { template<typename T> static inline T op(T x, T y) noexcept { DebugUtils::unused(x); return ~y; } }; struct And { template<typename T> static inline T op(T x, T y) noexcept { return x & y; } }; @@ -931,6 +1034,7 @@ struct Add { template<typename T> static inline T op(T x, T y) noexcept { ret struct Sub { template<typename T> static inline T op(T x, T y) noexcept { return x - y; } }; struct Min { template<typename T> static inline T op(T x, T y) noexcept { return min<T>(x, y); } }; struct Max { template<typename T> static inline T op(T x, T y) noexcept { return max<T>(x, y); } }; +//! \endcond // ============================================================================ // [asmjit::Support - BitWordIterator] @@ -1081,6 +1185,13 @@ static inline size_t bitVectorIndexOf(T* buf, size_t start, bool value) noexcept template<typename T> class BitVectorIterator { public: + const T* _ptr; + size_t _idx; + size_t _end; + T _current; + + ASMJIT_INLINE BitVectorIterator(const BitVectorIterator& other) noexcept = default; + ASMJIT_INLINE BitVectorIterator(const T* data, size_t numBitWords, size_t start = 0) noexcept { init(data, numBitWords, start); } @@ -1126,11 +1237,6 @@ public: ASMJIT_ASSERT(_current != T(0)); return _idx + ctz(_current); } - - const T* _ptr; - size_t _idx; - size_t _end; - T _current; }; // ============================================================================ @@ -1142,6 +1248,12 @@ class BitVectorOpIterator { public: static constexpr uint32_t kTSizeInBits = bitSizeOf<T>(); + const T* _aPtr; + const T* _bPtr; + size_t _idx; + size_t _end; + T _current; + ASMJIT_INLINE BitVectorOpIterator(const T* aData, const T* bData, size_t numBitWords, size_t start = 0) noexcept { init(aData, bData, numBitWords, start); } @@ -1184,12 +1296,6 @@ public: _current = bitWord; return n; } - - const T* _aPtr; - const T* _bPtr; - size_t _idx; - size_t _end; - T _current; }; // ============================================================================ @@ -1290,7 +1396,6 @@ namespace Internal { } //! \endcond - //! Quick sort implementation. //! //! The main reason to provide a custom qsort implementation is that we needed diff --git a/3rdparty/asmjit/src/asmjit/core/target.cpp b/3rdparty/asmjit/src/asmjit/core/target.cpp index ad120b443a3..9ce94f32410 100644 --- a/3rdparty/asmjit/src/asmjit/core/target.cpp +++ b/3rdparty/asmjit/src/asmjit/core/target.cpp @@ -31,8 +31,7 @@ ASMJIT_BEGIN_NAMESPACE // ============================================================================ Target::Target() noexcept - : _targetType(kTargetNone), - _codeInfo() {} + : _environment() {} Target::~Target() noexcept {} ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/target.h b/3rdparty/asmjit/src/asmjit/core/target.h index f3da0e5de8e..4d144c64ee2 100644 --- a/3rdparty/asmjit/src/asmjit/core/target.h +++ b/3rdparty/asmjit/src/asmjit/core/target.h @@ -36,20 +36,13 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::CodeInfo] // ============================================================================ +#ifndef ASMJIT_NO_DEPRECATED //! Basic information about a code (or target). It describes its architecture, //! code generation mode (or optimization level), and base address. -class CodeInfo { +class ASMJIT_DEPRECATED_STRUCT("Use Environment instead of CodeInfo") CodeInfo { public: - //!< Architecture information. - ArchInfo _archInfo; - //! Natural stack alignment (ARCH+OS). - uint8_t _stackAlignment; - //! Default CDECL calling convention. - uint8_t _cdeclCallConv; - //! Default STDCALL calling convention. - uint8_t _stdCallConv; - //! Default FASTCALL calling convention. - uint8_t _fastCallConv; + //!< Environment information. + Environment _environment; //! Base address. uint64_t _baseAddress; @@ -57,46 +50,35 @@ public: //! \{ inline CodeInfo() noexcept - : _archInfo(), - _stackAlignment(0), - _cdeclCallConv(CallConv::kIdNone), - _stdCallConv(CallConv::kIdNone), - _fastCallConv(CallConv::kIdNone), + : _environment(), _baseAddress(Globals::kNoBaseAddress) {} - inline explicit CodeInfo(uint32_t archId, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept - : _archInfo(archId, archMode), - _stackAlignment(0), - _cdeclCallConv(CallConv::kIdNone), - _stdCallConv(CallConv::kIdNone), - _fastCallConv(CallConv::kIdNone), + inline explicit CodeInfo(uint32_t arch, uint32_t subArch = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept + : _environment(arch, subArch), _baseAddress(baseAddress) {} + inline explicit CodeInfo(const Environment& environment, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept + : _environment(environment), + _baseAddress(baseAddress) {} + + inline CodeInfo(const CodeInfo& other) noexcept { init(other); } inline bool isInitialized() const noexcept { - return _archInfo.archId() != ArchInfo::kIdNone; + return _environment.arch() != Environment::kArchUnknown; } inline void init(const CodeInfo& other) noexcept { *this = other; } - inline void init(uint32_t archId, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept { - _archInfo.init(archId, archMode); - _stackAlignment = 0; - _cdeclCallConv = CallConv::kIdNone; - _stdCallConv = CallConv::kIdNone; - _fastCallConv = CallConv::kIdNone; + inline void init(uint32_t arch, uint32_t subArch = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept { + _environment.init(arch, subArch); _baseAddress = baseAddress; } inline void reset() noexcept { - _archInfo.reset(); - _stackAlignment = 0; - _cdeclCallConv = CallConv::kIdNone; - _stdCallConv = CallConv::kIdNone; - _fastCallConv = CallConv::kIdNone; + _environment.reset(); _baseAddress = Globals::kNoBaseAddress; } @@ -115,39 +97,28 @@ public: //! \name Accessors //! \{ - //! Returns the target architecture information, see `ArchInfo`. - inline const ArchInfo& archInfo() const noexcept { return _archInfo; } + //! Returns the target environment information, see \ref Environment. + inline const Environment& environment() const noexcept { return _environment; } - //! Returns the target architecture id, see `ArchInfo::Id`. - inline uint32_t archId() const noexcept { return _archInfo.archId(); } - //! Returns the target architecture sub-type, see `ArchInfo::SubId`. - inline uint32_t archSubId() const noexcept { return _archInfo.archSubId(); } + //! Returns the target architecture, see \ref Environment::Arch. + inline uint32_t arch() const noexcept { return _environment.arch(); } + //! Returns the target sub-architecture, see \ref Environment::SubArch. + inline uint32_t subArch() const noexcept { return _environment.subArch(); } //! Returns the native size of the target's architecture GP register. - inline uint32_t gpSize() const noexcept { return _archInfo.gpSize(); } - //! Returns the number of GP registers of the target's architecture. - inline uint32_t gpCount() const noexcept { return _archInfo.gpCount(); } - - //! Returns a natural stack alignment that must be honored (or 0 if not known). - inline uint32_t stackAlignment() const noexcept { return _stackAlignment; } - //! Sets a natural stack alignment that must be honored. - inline void setStackAlignment(uint32_t sa) noexcept { _stackAlignment = uint8_t(sa); } - - inline uint32_t cdeclCallConv() const noexcept { return _cdeclCallConv; } - inline void setCdeclCallConv(uint32_t cc) noexcept { _cdeclCallConv = uint8_t(cc); } - - inline uint32_t stdCallConv() const noexcept { return _stdCallConv; } - inline void setStdCallConv(uint32_t cc) noexcept { _stdCallConv = uint8_t(cc); } - - inline uint32_t fastCallConv() const noexcept { return _fastCallConv; } - inline void setFastCallConv(uint32_t cc) noexcept { _fastCallConv = uint8_t(cc); } + inline uint32_t gpSize() const noexcept { return _environment.registerSize(); } + //! Tests whether this CodeInfo has a base address set. inline bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; } + //! Returns the base address or \ref Globals::kNoBaseAddress if it's not set. inline uint64_t baseAddress() const noexcept { return _baseAddress; } + //! Sets base address to `p`. inline void setBaseAddress(uint64_t p) noexcept { _baseAddress = p; } + //! Resets base address (implicitly sets it to \ref Globals::kNoBaseAddress). inline void resetBaseAddress() noexcept { _baseAddress = Globals::kNoBaseAddress; } //! \} }; +#endif // !ASMJIT_NO_DEPRECATED // ============================================================================ // [asmjit::Target] @@ -159,19 +130,8 @@ public: ASMJIT_BASE_CLASS(Target) ASMJIT_NONCOPYABLE(Target) - //! Tartget type, see `TargetType`. - uint8_t _targetType; - //! Reserved for future use. - uint8_t _reserved[7]; - //! Basic information about the Runtime's code. - CodeInfo _codeInfo; - - enum TargetType : uint32_t { - //! Uninitialized target or unknown target type. - kTargetNone = 0, - //! JIT target type, see `JitRuntime`. - kTargetJit = 1 - }; + //! Target environment information. + Environment _environment; //! \name Construction & Destruction //! \{ @@ -190,15 +150,20 @@ public: //! //! CodeInfo can be used to setup a CodeHolder in case you plan to generate a //! code compatible and executable by this Runtime. - inline const CodeInfo& codeInfo() const noexcept { return _codeInfo; } + inline const Environment& environment() const noexcept { return _environment; } + + //! Returns the target architecture, see \ref Environment::Arch. + inline uint32_t arch() const noexcept { return _environment.arch(); } + //! Returns the target sub-architecture, see \ref Environment::SubArch. + inline uint32_t subArch() const noexcept { return _environment.subArch(); } - //! Returns the target architecture id, see `ArchInfo::Id`. - inline uint32_t archId() const noexcept { return _codeInfo.archId(); } - //! Returns the target architecture sub-id, see `ArchInfo::SubId`. - inline uint32_t archSubId() const noexcept { return _codeInfo.archSubId(); } +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use environment() instead") + inline CodeInfo codeInfo() const noexcept { return CodeInfo(_environment); } - //! Returns the target type, see `TargetType`. - inline uint32_t targetType() const noexcept { return _targetType; } + ASMJIT_DEPRECATED("Use environment().format() instead") + inline uint32_t targetType() const noexcept { return _environment.format(); } +#endif // !ASMJIT_NO_DEPRECATED //! \} }; diff --git a/3rdparty/asmjit/src/asmjit/core/type.cpp b/3rdparty/asmjit/src/asmjit/core/type.cpp index 67662db5075..97892d9815e 100644 --- a/3rdparty/asmjit/src/asmjit/core/type.cpp +++ b/3rdparty/asmjit/src/asmjit/core/type.cpp @@ -31,14 +31,62 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::Type] // ============================================================================ -const Type::TypeData Type::_typeData = { - #define VALUE(X) Type::BaseOfTypeId<X>::kTypeId +namespace Type { + +template<uint32_t TYPE_ID> +struct BaseOfTypeId { + static constexpr uint32_t kTypeId = + isBase (TYPE_ID) ? TYPE_ID : + isMask8 (TYPE_ID) ? kIdU8 : + isMask16(TYPE_ID) ? kIdU16 : + isMask32(TYPE_ID) ? kIdU32 : + isMask64(TYPE_ID) ? kIdU64 : + isMmx32 (TYPE_ID) ? kIdI32 : + isMmx64 (TYPE_ID) ? kIdI64 : + isVec32 (TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec32Start : + isVec64 (TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec64Start : + isVec128(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec128Start : + isVec256(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec256Start : + isVec512(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec512Start : 0; +}; + +template<uint32_t TYPE_ID> +struct SizeOfTypeId { + static constexpr uint32_t kTypeSize = + isInt8 (TYPE_ID) ? 1 : + isUInt8 (TYPE_ID) ? 1 : + isInt16 (TYPE_ID) ? 2 : + isUInt16 (TYPE_ID) ? 2 : + isInt32 (TYPE_ID) ? 4 : + isUInt32 (TYPE_ID) ? 4 : + isInt64 (TYPE_ID) ? 8 : + isUInt64 (TYPE_ID) ? 8 : + isFloat32(TYPE_ID) ? 4 : + isFloat64(TYPE_ID) ? 8 : + isFloat80(TYPE_ID) ? 10 : + isMask8 (TYPE_ID) ? 1 : + isMask16 (TYPE_ID) ? 2 : + isMask32 (TYPE_ID) ? 4 : + isMask64 (TYPE_ID) ? 8 : + isMmx32 (TYPE_ID) ? 4 : + isMmx64 (TYPE_ID) ? 8 : + isVec32 (TYPE_ID) ? 4 : + isVec64 (TYPE_ID) ? 8 : + isVec128 (TYPE_ID) ? 16 : + isVec256 (TYPE_ID) ? 32 : + isVec512 (TYPE_ID) ? 64 : 0; +}; + +const TypeData _typeData = { + #define VALUE(X) BaseOfTypeId<X>::kTypeId { ASMJIT_LOOKUP_TABLE_256(VALUE, 0) }, #undef VALUE - #define VALUE(X) Type::SizeOfTypeId<X>::kTypeSize + #define VALUE(X) SizeOfTypeId<X>::kTypeSize { ASMJIT_LOOKUP_TABLE_256(VALUE, 0) } #undef VALUE }; +} // {Type} + ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/type.h b/3rdparty/asmjit/src/asmjit/core/type.h index 59a17e92625..ef03ecb8360 100644 --- a/3rdparty/asmjit/src/asmjit/core/type.h +++ b/3rdparty/asmjit/src/asmjit/core/type.h @@ -35,7 +35,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::Type] // ============================================================================ -//! Provides minimum type-system that is used by \ref asmjit_func and \ref asmjit_compiler. +//! Provides a minimalist type-system that is used by Asmjit library. namespace Type { //! TypeId. @@ -46,7 +46,7 @@ namespace Type { //! width used) and it's also used by APIs that allow to describe and work with //! function signatures. enum Id : uint32_t { - kIdVoid = 0, + kIdVoid = 0, //!< Void type. _kIdBaseStart = 32, _kIdBaseEnd = 44, @@ -54,38 +54,38 @@ enum Id : uint32_t { _kIdIntStart = 32, _kIdIntEnd = 41, - kIdIntPtr = 32, - kIdUIntPtr = 33, + kIdIntPtr = 32, //!< Abstract signed integer type that has a native size. + kIdUIntPtr = 33, //!< Abstract unsigned integer type that has a native size. - kIdI8 = 34, - kIdU8 = 35, - kIdI16 = 36, - kIdU16 = 37, - kIdI32 = 38, - kIdU32 = 39, - kIdI64 = 40, - kIdU64 = 41, + kIdI8 = 34, //!< 8-bit signed integer type. + kIdU8 = 35, //!< 8-bit unsigned integer type. + kIdI16 = 36, //!< 16-bit signed integer type. + kIdU16 = 37, //!< 16-bit unsigned integer type. + kIdI32 = 38, //!< 32-bit signed integer type. + kIdU32 = 39, //!< 32-bit unsigned integer type. + kIdI64 = 40, //!< 64-bit signed integer type. + kIdU64 = 41, //!< 64-bit unsigned integer type. _kIdFloatStart = 42, _kIdFloatEnd = 44, - kIdF32 = 42, - kIdF64 = 43, - kIdF80 = 44, + kIdF32 = 42, //!< 32-bit floating point type. + kIdF64 = 43, //!< 64-bit floating point type. + kIdF80 = 44, //!< 80-bit floating point type. _kIdMaskStart = 45, _kIdMaskEnd = 48, - kIdMask8 = 45, - kIdMask16 = 46, - kIdMask32 = 47, - kIdMask64 = 48, + kIdMask8 = 45, //!< 8-bit opmask register (K). + kIdMask16 = 46, //!< 16-bit opmask register (K). + kIdMask32 = 47, //!< 32-bit opmask register (K). + kIdMask64 = 48, //!< 64-bit opmask register (K). _kIdMmxStart = 49, _kIdMmxEnd = 50, - kIdMmx32 = 49, - kIdMmx64 = 50, + kIdMmx32 = 49, //!< 64-bit MMX register only used for 32 bits. + kIdMmx64 = 50, //!< 64-bit MMX register. _kIdVec32Start = 51, _kIdVec32End = 60, @@ -206,72 +206,74 @@ static constexpr bool isVec128(uint32_t typeId) noexcept { return typeId >= _kId static constexpr bool isVec256(uint32_t typeId) noexcept { return typeId >= _kIdVec256Start && typeId <= _kIdVec256End; } static constexpr bool isVec512(uint32_t typeId) noexcept { return typeId >= _kIdVec512Start && typeId <= _kIdVec512End; } -//! IdOfT<> template allows to get a TypeId of a C++ `T` type. -template<typename T> struct IdOfT { /* Fail if not specialized. */ }; - //! \cond -template<typename T> struct IdOfT<T*> { - enum : uint32_t { kTypeId = kIdUIntPtr }; +enum TypeCategory : uint32_t { + kTypeCategoryUnknown = 0, + kTypeCategoryEnum = 1, + kTypeCategoryIntegral = 2, + kTypeCategoryFloatingPoint = 3, + kTypeCategoryFunction = 4 }; -template<typename T> struct IdOfT<T&> { - enum : uint32_t { kTypeId = kIdUIntPtr }; -}; +template<typename T, uint32_t Category> +struct IdOfT_ByCategory {}; // Fails if not specialized. template<typename T> -struct IdOfIntT { - static constexpr uint32_t kTypeId = - sizeof(T) == 1 ? (std::is_signed<T>::value ? kIdI8 : kIdU8 ) : - sizeof(T) == 2 ? (std::is_signed<T>::value ? kIdI16 : kIdU16) : - sizeof(T) == 4 ? (std::is_signed<T>::value ? kIdI32 : kIdU32) : - sizeof(T) == 8 ? (std::is_signed<T>::value ? kIdI64 : kIdU64) : kIdVoid; +struct IdOfT_ByCategory<T, kTypeCategoryIntegral> { + enum : uint32_t { + kTypeId = (sizeof(T) == 1 && std::is_signed<T>::value) ? kIdI8 : + (sizeof(T) == 1 && !std::is_signed<T>::value) ? kIdU8 : + (sizeof(T) == 2 && std::is_signed<T>::value) ? kIdI16 : + (sizeof(T) == 2 && !std::is_signed<T>::value) ? kIdU16 : + (sizeof(T) == 4 && std::is_signed<T>::value) ? kIdI32 : + (sizeof(T) == 4 && !std::is_signed<T>::value) ? kIdU32 : + (sizeof(T) == 8 && std::is_signed<T>::value) ? kIdI64 : + (sizeof(T) == 8 && !std::is_signed<T>::value) ? kIdU64 : kIdVoid + }; }; -template<uint32_t TYPE_ID> -struct BaseOfTypeId { - static constexpr uint32_t kTypeId = - isBase (TYPE_ID) ? TYPE_ID : - isMask8 (TYPE_ID) ? kIdU8 : - isMask16(TYPE_ID) ? kIdU16 : - isMask32(TYPE_ID) ? kIdU32 : - isMask64(TYPE_ID) ? kIdU64 : - isMmx32 (TYPE_ID) ? kIdI32 : - isMmx64 (TYPE_ID) ? kIdI64 : - isVec32 (TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec32Start : - isVec64 (TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec64Start : - isVec128(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec128Start : - isVec256(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec256Start : - isVec512(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec512Start : 0; +template<typename T> +struct IdOfT_ByCategory<T, kTypeCategoryFloatingPoint> { + enum : uint32_t { + kTypeId = (sizeof(T) == 4 ) ? kIdF32 : + (sizeof(T) == 8 ) ? kIdF64 : + (sizeof(T) >= 10) ? kIdF80 : kIdVoid + }; }; -template<uint32_t TYPE_ID> -struct SizeOfTypeId { - static constexpr uint32_t kTypeSize = - isInt8 (TYPE_ID) ? 1 : - isUInt8 (TYPE_ID) ? 1 : - isInt16 (TYPE_ID) ? 2 : - isUInt16 (TYPE_ID) ? 2 : - isInt32 (TYPE_ID) ? 4 : - isUInt32 (TYPE_ID) ? 4 : - isInt64 (TYPE_ID) ? 8 : - isUInt64 (TYPE_ID) ? 8 : - isFloat32(TYPE_ID) ? 4 : - isFloat64(TYPE_ID) ? 8 : - isFloat80(TYPE_ID) ? 10 : - isMask8 (TYPE_ID) ? 1 : - isMask16 (TYPE_ID) ? 2 : - isMask32 (TYPE_ID) ? 4 : - isMask64 (TYPE_ID) ? 8 : - isMmx32 (TYPE_ID) ? 4 : - isMmx64 (TYPE_ID) ? 8 : - isVec32 (TYPE_ID) ? 4 : - isVec64 (TYPE_ID) ? 8 : - isVec128 (TYPE_ID) ? 16 : - isVec256 (TYPE_ID) ? 32 : - isVec512 (TYPE_ID) ? 64 : 0; +template<typename T> +struct IdOfT_ByCategory<T, kTypeCategoryEnum> + : public IdOfT_ByCategory<typename std::underlying_type<T>::type, kTypeCategoryIntegral> {}; + +template<typename T> +struct IdOfT_ByCategory<T, kTypeCategoryFunction> { + enum: uint32_t { kTypeId = kIdUIntPtr }; }; //! \endcond +//! IdOfT<> template allows to get a TypeId from a C++ type `T`. +template<typename T> +struct IdOfT +#ifdef _DOXYGEN + //! TypeId of C++ type `T`. + static constexpr uint32_t kTypeId = _TypeIdDeducedAtCompileTime_; +#else + : public IdOfT_ByCategory<T, + std::is_enum<T>::value ? kTypeCategoryEnum : + std::is_integral<T>::value ? kTypeCategoryIntegral : + std::is_floating_point<T>::value ? kTypeCategoryFloatingPoint : + std::is_function<T>::value ? kTypeCategoryFunction : kTypeCategoryUnknown> +#endif +{}; + +//! \cond +template<typename T> +struct IdOfT<T*> { enum : uint32_t { kTypeId = kIdUIntPtr }; }; + +template<typename T> +struct IdOfT<T&> { enum : uint32_t { kTypeId = kIdUIntPtr }; }; +//! \endcond + static inline uint32_t baseOf(uint32_t typeId) noexcept { ASMJIT_ASSERT(typeId <= kIdMax); return _typeData.baseOf[typeId]; @@ -283,14 +285,14 @@ static inline uint32_t sizeOf(uint32_t typeId) noexcept { } //! Returns offset needed to convert a `kIntPtr` and `kUIntPtr` TypeId -//! into a type that matches `gpSize` (general-purpose register size). +//! into a type that matches `registerSize` (general-purpose register size). //! If you find such TypeId it's then only about adding the offset to it. //! //! For example: //! //! ``` -//! uint32_t gpSize = '4' or '8'; -//! uint32_t deabstractDelta = Type::deabstractDeltaOfSize(gpSize); +//! uint32_t registerSize = '4' or '8'; +//! uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize); //! //! uint32_t typeId = 'some type-id'; //! @@ -300,8 +302,8 @@ static inline uint32_t sizeOf(uint32_t typeId) noexcept { //! // The same, but by using Type::deabstract() function. //! typeId = Type::deabstract(typeId, deabstractDelta); //! ``` -static constexpr uint32_t deabstractDeltaOfSize(uint32_t gpSize) noexcept { - return gpSize >= 8 ? kIdI64 - kIdIntPtr : kIdI32 - kIdIntPtr; +static constexpr uint32_t deabstractDeltaOfSize(uint32_t registerSize) noexcept { + return registerSize >= 8 ? kIdI64 - kIdIntPtr : kIdI32 - kIdIntPtr; } static constexpr uint32_t deabstract(uint32_t typeId, uint32_t deabstractDelta) noexcept { @@ -350,45 +352,20 @@ namespace Type { \ }; \ } -ASMJIT_DEFINE_TYPE_ID(bool , IdOfIntT<bool >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(char , IdOfIntT<char >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(signed char , IdOfIntT<signed char >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned char , IdOfIntT<unsigned char >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(short , IdOfIntT<short >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned short , IdOfIntT<unsigned short >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(int , IdOfIntT<int >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned int , IdOfIntT<unsigned int >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(long , IdOfIntT<long >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned long , IdOfIntT<unsigned long >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(long long , IdOfIntT<long long >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned long long, IdOfIntT<unsigned long long>::kTypeId); - -#if ASMJIT_CXX_HAS_NATIVE_WCHAR_T -ASMJIT_DEFINE_TYPE_ID(wchar_t , IdOfIntT<wchar_t >::kTypeId); -#endif - -#if ASMJIT_CXX_HAS_UNICODE_LITERALS -ASMJIT_DEFINE_TYPE_ID(char16_t , IdOfIntT<char16_t >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(char32_t , IdOfIntT<char32_t >::kTypeId); -#endif - -ASMJIT_DEFINE_TYPE_ID(void , kIdVoid); -ASMJIT_DEFINE_TYPE_ID(float , kIdF32); -ASMJIT_DEFINE_TYPE_ID(double , kIdF64); - -ASMJIT_DEFINE_TYPE_ID(Bool , kIdU8); -ASMJIT_DEFINE_TYPE_ID(I8 , kIdI8); -ASMJIT_DEFINE_TYPE_ID(U8 , kIdU8); -ASMJIT_DEFINE_TYPE_ID(I16 , kIdI16); -ASMJIT_DEFINE_TYPE_ID(U16 , kIdU16); -ASMJIT_DEFINE_TYPE_ID(I32 , kIdI32); -ASMJIT_DEFINE_TYPE_ID(U32 , kIdU32); -ASMJIT_DEFINE_TYPE_ID(I64 , kIdI64); -ASMJIT_DEFINE_TYPE_ID(U64 , kIdU64); -ASMJIT_DEFINE_TYPE_ID(IPtr , kIdIntPtr); -ASMJIT_DEFINE_TYPE_ID(UPtr , kIdUIntPtr); -ASMJIT_DEFINE_TYPE_ID(F32 , kIdF32); -ASMJIT_DEFINE_TYPE_ID(F64 , kIdF64); +ASMJIT_DEFINE_TYPE_ID(void, kIdVoid); +ASMJIT_DEFINE_TYPE_ID(Bool, kIdU8); +ASMJIT_DEFINE_TYPE_ID(I8 , kIdI8); +ASMJIT_DEFINE_TYPE_ID(U8 , kIdU8); +ASMJIT_DEFINE_TYPE_ID(I16 , kIdI16); +ASMJIT_DEFINE_TYPE_ID(U16 , kIdU16); +ASMJIT_DEFINE_TYPE_ID(I32 , kIdI32); +ASMJIT_DEFINE_TYPE_ID(U32 , kIdU32); +ASMJIT_DEFINE_TYPE_ID(I64 , kIdI64); +ASMJIT_DEFINE_TYPE_ID(U64 , kIdU64); +ASMJIT_DEFINE_TYPE_ID(IPtr, kIdIntPtr); +ASMJIT_DEFINE_TYPE_ID(UPtr, kIdUIntPtr); +ASMJIT_DEFINE_TYPE_ID(F32 , kIdF32); +ASMJIT_DEFINE_TYPE_ID(F64 , kIdF64); //! \endcond //! \} diff --git a/3rdparty/asmjit/src/asmjit/core/virtmem.cpp b/3rdparty/asmjit/src/asmjit/core/virtmem.cpp index e373cf8d723..0606748ef7f 100644 --- a/3rdparty/asmjit/src/asmjit/core/virtmem.cpp +++ b/3rdparty/asmjit/src/asmjit/core/virtmem.cpp @@ -45,7 +45,7 @@ // Apple recently introduced MAP_JIT flag, which we want to use. #if defined(__APPLE__) #include <TargetConditionals.h> - #if defined(TARGET_OS_OSX) + #if TARGET_OS_OSX #include <sys/utsname.h> #endif // Older SDK doesn't define `MAP_JIT`. @@ -316,10 +316,10 @@ static ASMJIT_INLINE bool VirtMem_isHardened() noexcept { // MAP_JIT flag required to run unsigned JIT code is only supported by kernel // version 10.14+ (Mojave) and IOS. static ASMJIT_INLINE bool VirtMem_hasMapJitSupport() noexcept { -#if defined(TARGET_OS_OSX) - static volatile uint32_t globalVersion; +#if TARGET_OS_OSX + static volatile int globalVersion; - uint32_t ver = globalVersion; + int ver = globalVersion; if (!ver) { struct utsname osname; uname(&osname); @@ -333,19 +333,19 @@ static ASMJIT_INLINE bool VirtMem_hasMapJitSupport() noexcept { #endif } -static ASMJIT_INLINE uint32_t VirtMem_appleSpecificMMapFlags(uint32_t flags) { +static ASMJIT_INLINE int VirtMem_appleSpecificMMapFlags(uint32_t flags) { // Always use MAP_JIT flag if user asked for it (could be used for testing // on non-hardened processes) and detect whether it must be used when the // process is actually hardened (in that case it doesn't make sense to rely // on user `flags`). bool useMapJit = ((flags & VirtMem::kMMapEnableMapJit) != 0) || VirtMem_isHardened(); if (useMapJit) - return VirtMem_hasMapJitSupport() ? MAP_JIT : 0u; + return VirtMem_hasMapJitSupport() ? int(MAP_JIT) : 0; else return 0; } #else -static ASMJIT_INLINE uint32_t VirtMem_appleSpecificMMapFlags(uint32_t flags) { +static ASMJIT_INLINE int VirtMem_appleSpecificMMapFlags(uint32_t flags) { DebugUtils::unused(flags); return 0; } @@ -406,7 +406,7 @@ static Error VirtMem_openAnonymousMemory(int* fd, bool preferTmpOverDevShm) noex bits = ((bits >> 14) ^ (bits << 6)) + uint64_t(++internalCounter) * 10619863; if (!ASMJIT_VM_SHM_DETECT || preferTmpOverDevShm) { - uniqueName.assignString(VirtMem_getTmpDir()); + uniqueName.assign(VirtMem_getTmpDir()); uniqueName.appendFormat(kShmFormat, (unsigned long long)bits); *fd = open(uniqueName.data(), O_RDWR | O_CREAT | O_EXCL, 0); if (ASMJIT_LIKELY(*fd >= 0)) { diff --git a/3rdparty/asmjit/src/asmjit/core/virtmem.h b/3rdparty/asmjit/src/asmjit/core/virtmem.h index a37005d947e..8d3ee01ee5b 100644 --- a/3rdparty/asmjit/src/asmjit/core/virtmem.h +++ b/3rdparty/asmjit/src/asmjit/core/virtmem.h @@ -31,7 +31,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_jit +//! \addtogroup asmjit_virtual_memory //! \{ // ============================================================================ diff --git a/3rdparty/asmjit/src/asmjit/core/zone.cpp b/3rdparty/asmjit/src/asmjit/core/zone.cpp index 16de89becec..61f7cec796d 100644 --- a/3rdparty/asmjit/src/asmjit/core/zone.cpp +++ b/3rdparty/asmjit/src/asmjit/core/zone.cpp @@ -144,7 +144,7 @@ void* Zone::_alloc(size_t size, size_t alignment) noexcept { size_t newSize = Support::max(blockSize(), size); // Prevent arithmetic overflow. - if (ASMJIT_UNLIKELY(newSize > std::numeric_limits<size_t>::max() - kBlockSize - blockAlignmentOverhead)) + if (ASMJIT_UNLIKELY(newSize > SIZE_MAX - kBlockSize - blockAlignmentOverhead)) return nullptr; // Allocate new block - we add alignment overhead to `newSize`, which becomes the @@ -200,7 +200,7 @@ void* Zone::dup(const void* data, size_t size, bool nullTerminate) noexcept { if (ASMJIT_UNLIKELY(!data || !size)) return nullptr; - ASMJIT_ASSERT(size != std::numeric_limits<size_t>::max()); + ASMJIT_ASSERT(size != SIZE_MAX); uint8_t* m = allocT<uint8_t>(size + nullTerminate); if (ASMJIT_UNLIKELY(!m)) return nullptr; @@ -318,7 +318,7 @@ void* ZoneAllocator::_alloc(size_t size, size_t& allocatedSize) noexcept { size_t kBlockOverhead = sizeof(DynamicBlock) + sizeof(DynamicBlock*) + kBlockAlignment; // Handle a possible overflow. - if (ASMJIT_UNLIKELY(kBlockOverhead >= std::numeric_limits<size_t>::max() - size)) + if (ASMJIT_UNLIKELY(kBlockOverhead >= SIZE_MAX - size)) return nullptr; void* p = ::malloc(size + kBlockOverhead); diff --git a/3rdparty/asmjit/src/asmjit/core/zone.h b/3rdparty/asmjit/src/asmjit/core/zone.h index c426f785c0c..52e9f125461 100644 --- a/3rdparty/asmjit/src/asmjit/core/zone.h +++ b/3rdparty/asmjit/src/asmjit/core/zone.h @@ -383,15 +383,22 @@ public: // [b2d::ZoneTmp] // ============================================================================ +//! \ref Zone with `N` bytes of a static storage, used for the initial block. +//! +//! Temporary zones are used in cases where it's known that some memory will be +//! required, but in many cases it won't exceed N bytes, so the whole operation +//! can be performed without a dynamic memory allocation. template<size_t N> class ZoneTmp : public Zone { public: ASMJIT_NONCOPYABLE(ZoneTmp<N>) + //! Temporary storage, embedded after \ref Zone. struct Storage { char data[N]; } _storage; + //! Creates a temporary zone. Dynamic block size is specified by `blockSize`. ASMJIT_INLINE explicit ZoneTmp(size_t blockSize, size_t blockAlignment = 1) noexcept : Zone(blockSize, blockAlignment, Support::Temporary(_storage.data, N)) {} }; diff --git a/3rdparty/asmjit/src/asmjit/core/zonehash.h b/3rdparty/asmjit/src/asmjit/core/zonehash.h index bdc1da76027..0f1f21f148c 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonehash.h +++ b/3rdparty/asmjit/src/asmjit/core/zonehash.h @@ -35,7 +35,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::ZoneHashNode] // ============================================================================ -//! Node used by `ZoneHash<>` template. +//! Node used by \ref ZoneHash template. //! //! You must provide function `bool eq(const Key& key)` in order to make //! `ZoneHash::get()` working. @@ -60,6 +60,7 @@ public: // [asmjit::ZoneHashBase] // ============================================================================ +//! Base class used by \ref ZoneHash template class ZoneHashBase { public: ASMJIT_NONCOPYABLE(ZoneHashBase) diff --git a/3rdparty/asmjit/src/asmjit/core/zonelist.h b/3rdparty/asmjit/src/asmjit/core/zonelist.h index 9d300b03606..bc726deca94 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonelist.h +++ b/3rdparty/asmjit/src/asmjit/core/zonelist.h @@ -35,6 +35,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::ZoneListNode] // ============================================================================ +//! Node used by \ref ZoneList template. template<typename NodeT> class ZoneListNode { public: @@ -69,6 +70,7 @@ public: // [asmjit::ZoneList<T>] // ============================================================================ +//! Zone allocated list container that uses nodes of `NodeT` type. template <typename NodeT> class ZoneList { public: diff --git a/3rdparty/asmjit/src/asmjit/core/zonestack.h b/3rdparty/asmjit/src/asmjit/core/zonestack.h index 3c7b5ce0c45..2de6cdc05a7 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonestack.h +++ b/3rdparty/asmjit/src/asmjit/core/zonestack.h @@ -35,7 +35,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::ZoneStackBase] // ============================================================================ -//! Base class used by `ZoneStack<T>`. +//! Base class used by \ref ZoneStack. class ZoneStackBase { public: ASMJIT_NONCOPYABLE(ZoneStackBase) diff --git a/3rdparty/asmjit/src/asmjit/core/zonestring.h b/3rdparty/asmjit/src/asmjit/core/zonestring.h index dfb06b4c754..cb25b29ce7d 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonestring.h +++ b/3rdparty/asmjit/src/asmjit/core/zonestring.h @@ -36,6 +36,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::ZoneStringBase] // ============================================================================ +//! A helper class used by \ref ZoneString implementation. struct ZoneStringBase { union { struct { @@ -77,11 +78,12 @@ struct ZoneStringBase { // [asmjit::ZoneString<N>] // ============================================================================ -//! Small string is a template that helps to create strings that can be either -//! statically allocated if they are small, or externally allocated in case -//! their size exceeds the limit. The `N` represents the size of the whole -//! `ZoneString` structure, based on that size the maximum size of the internal -//! buffer is determined. +//! A string template that can be zone allocated. +//! +//! Helps with creating strings that can be either statically allocated if they +//! are small, or externally allocated in case their size exceeds the limit. +//! The `N` represents the size of the whole `ZoneString` structure, based on +//! that size the maximum size of the internal buffer is determined. template<size_t N> class ZoneString { public: @@ -105,12 +107,22 @@ public: //! \name Accessors //! \{ - inline const char* data() const noexcept { return _base._size <= kMaxEmbeddedSize ? _base._embedded : _base._external; } + //! Tests whether the string is empty. inline bool empty() const noexcept { return _base._size == 0; } + + //! Returns the string data. + inline const char* data() const noexcept { return _base._size <= kMaxEmbeddedSize ? _base._embedded : _base._external; } + //! Returns the string size. inline uint32_t size() const noexcept { return _base._size; } + //! Tests whether the string is embedded (e.g. no dynamically allocated). inline bool isEmbedded() const noexcept { return _base._size <= kMaxEmbeddedSize; } + //! Copies a new `data` of the given `size` to the string. + //! + //! If the `size` exceeds the internal buffer the given `zone` will be + //! used to duplicate the data, otherwise the internal buffer will be + //! used as a storage. inline Error setData(Zone* zone, const char* data, size_t size) noexcept { return _base.setData(zone, kMaxEmbeddedSize, data, size); } diff --git a/3rdparty/asmjit/src/asmjit/core/zonetree.h b/3rdparty/asmjit/src/asmjit/core/zonetree.h index 6cb88ed499b..1877919d67b 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonetree.h +++ b/3rdparty/asmjit/src/asmjit/core/zonetree.h @@ -99,7 +99,7 @@ public: //! \endcond }; -//! RB-Tree typed to `NodeT`. +//! RB-Tree node casted to `NodeT`. template<typename NodeT> class ZoneTreeNodeT : public ZoneTreeNode { public: diff --git a/3rdparty/asmjit/src/asmjit/core/zonevector.h b/3rdparty/asmjit/src/asmjit/core/zonevector.h index 7ee04ce7807..770543baee1 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonevector.h +++ b/3rdparty/asmjit/src/asmjit/core/zonevector.h @@ -36,9 +36,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::ZoneVectorBase] // ============================================================================ -//! \cond INTERNAL - -//! Base class implementing core `ZoneVector<>` functionality. +//! Base class used by \ref ZoneVector template. class ZoneVectorBase { public: ASMJIT_NONCOPYABLE(ZoneVectorBase) @@ -93,6 +91,7 @@ protected: } //! \} + //! \endcond public: //! \name Accessors @@ -133,8 +132,6 @@ public: //! \} }; -//! \endcond - // ============================================================================ // [asmjit::ZoneVector<T>] // ============================================================================ @@ -180,7 +177,7 @@ public: inline const T* data() const noexcept { return static_cast<const T*>(_data); } //! Returns item at the given index `i` (const). - inline const T& at(uint32_t i) const noexcept { + inline const T& at(size_t i) const noexcept { ASMJIT_ASSERT(i < _size); return data()[i]; } @@ -259,6 +256,7 @@ public: return kErrorOk; } + //! Appends `other` vector at the end of this vector. inline Error concat(ZoneAllocator* allocator, const ZoneVector<T>& other) noexcept { uint32_t size = other._size; if (_capacity - _size < size) @@ -338,6 +336,7 @@ public: ::memmove(data, data + 1, size_t(size) * sizeof(T)); } + //! Pops the last element from the vector and returns it. inline T pop() noexcept { ASMJIT_ASSERT(_size > 0); @@ -351,21 +350,33 @@ public: } //! Returns item at index `i`. - inline T& operator[](uint32_t i) noexcept { + inline T& operator[](size_t i) noexcept { ASMJIT_ASSERT(i < _size); return data()[i]; } //! Returns item at index `i`. - inline const T& operator[](uint32_t i) const noexcept { + inline const T& operator[](size_t i) const noexcept { ASMJIT_ASSERT(i < _size); return data()[i]; } + //! Returns a reference to the first element of the vector. + //! + //! \note The vector must have at least one element. Attempting to use + //! `first()` on empty vector will trigger an assertion failure in debug + //! builds. inline T& first() noexcept { return operator[](0); } + //! \overload inline const T& first() const noexcept { return operator[](0); } + //! Returns a reference to the last element of the vector. + //! + //! \note The vector must have at least one element. Attempting to use + //! `last()` on empty vector will trigger an assertion failure in debug + //! builds. inline T& last() noexcept { return operator[](_size - 1); } + //! \overload inline const T& last() const noexcept { return operator[](_size - 1); } //! \} @@ -408,6 +419,7 @@ public: // [asmjit::ZoneBitVector] // ============================================================================ +//! Zone-allocated bit vector. class ZoneBitVector { public: typedef Support::BitWord BitWord; @@ -689,7 +701,6 @@ public: }; //! \} - }; //! \} diff --git a/3rdparty/asmjit/src/asmjit/x86.h b/3rdparty/asmjit/src/asmjit/x86.h index 161b3be19fb..3c2224c966a 100644 --- a/3rdparty/asmjit/src/asmjit/x86.h +++ b/3rdparty/asmjit/src/asmjit/x86.h @@ -24,9 +24,83 @@ #ifndef ASMJIT_X86_H_INCLUDED #define ASMJIT_X86_H_INCLUDED -//! \defgroup asmjit_x86 X86 +//! \addtogroup asmjit_x86 //! -//! \brief X86/X64 Backend. +//! ### Namespace +//! +//! - \ref x86 - x86 namespace provides support for X86/X64 code generation. +//! +//! ### Emitters +//! +//! - \ref x86::Assembler - X86/X64 assembler (must read, provides examples). +//! - \ref x86::Builder - X86/X64 builder. +//! - \ref x86::Compiler - X86/X64 compiler. +//! - \ref x86::Emitter - X86/X64 emitter (abstract). +//! +//! ### Supported Instructions +//! +//! - Emitters: +//! - \ref x86::EmitterExplicitT - Provides all instructions that use +//! explicit operands, provides also utility functions. The member +//! functions provided are part of all X86 emitters. +//! - \ref x86::EmitterImplicitT - Provides all instructions that use +//! implicit operands, these cannot be used with \ref x86::Compiler. +//! - Instruction representation: +//! - \ref x86::Inst::Id - instruction identifiers. +//! - \ref x86::Inst::Options - instruction options. +//! +//! ### Register Operands +//! +//! - \ref x86::Reg - Base class for any X86 register. +//! - \ref x86::Gp - General purpose register: +//! - \ref x86::GpbLo - 8-bit low register. +//! - \ref x86::GpbHi - 8-bit high register. +//! - \ref x86::Gpw - 16-bit register. +//! - \ref x86::Gpd - 32-bit register. +//! - \ref x86::Gpq - 64-bit register (X64 only). +//! - \ref x86::Vec - Vector (SIMD) register: +//! - \ref x86::Xmm - 128-bit SIMD register (SSE+). +//! - \ref x86::Ymm - 256-bit SIMD register (AVX+). +//! - \ref x86::Zmm - 512-bit SIMD register (AVX512+). +//! - \ref x86::Mm - 64-bit MMX register. +//! - \ref x86::St - 80-bit FPU register. +//! - \ref x86::KReg - opmask registers (AVX512+). +//! - \ref x86::SReg - segment register. +//! - \ref x86::CReg - control register. +//! - \ref x86::DReg - debug register. +//! - \ref x86::Bnd - bound register (discontinued). +//! - \ref x86::Rip - relative instruction pointer. +//! +//! ### Memory Operands +//! +//! - \ref x86::Mem - X86/X64 memory operand that provides support for all +//! X86 and X64 addressing features, including absolute addresses, index +//! scales, and segment override prefixes. +//! +//! ### Other +//! +//! - \ref x86::Features - X86/X64 CPU features on top of \ref BaseFeatures. +//! +//! ### Status and Control Words +//! +//! - \ref asmjit::x86::FpuWord::Status - FPU status word. +//! - \ref asmjit::x86::FpuWord::Control - FPU control word. +//! +//! ### Predicates +//! +//! - \ref x86::Predicate - namespace that provides X86/X64 predicates. +//! - \ref x86::Predicate::Cmp - `CMP[PD|PS|SD|SS]` predicate (SSE+). +//! - \ref x86::Predicate::PCmpStr - `[V]PCMP[I|E]STR[I|M]` predicate (SSE4.1+). +//! - \ref x86::Predicate::Round - `ROUND[PD|PS|SD|SS]` predicate (SSE+). +//! - \ref x86::Predicate::VCmp - `VCMP[PD|PS|SD|SS]` predicate (AVX+). +//! - \ref x86::Predicate::VFixupImm - `VFIXUPIMM[PD|PS|SD|SS]` predicate (AVX512+). +//! - \ref x86::Predicate::VFPClass - `VFPCLASS[PD|PS|SD|SS]` predicate (AVX512+). +//! - \ref x86::Predicate::VGetMant - `VGETMANT[PD|PS|SD|SS]` predicate (AVX512+). +//! - \ref x86::Predicate::VPCmp - `VPCMP[U][B|W|D|Q]` predicate (AVX512+). +//! - \ref x86::Predicate::VPCom - `VPCOM[U][B|W|D|Q]` predicate (XOP). +//! - \ref x86::Predicate::VRange - `VRANGE[PD|PS|SD|SS]` predicate (AVX512+). +//! - \ref x86::Predicate::VReduce - `REDUCE[PD|PS|SD|SS]` predicate (AVX512+). +//! - \ref x86::TLog - namespace that provides `VPTERNLOG[D|Q]` predicate / operations. #include "./core.h" diff --git a/3rdparty/asmjit/src/asmjit/x86/x86archdata.cpp b/3rdparty/asmjit/src/asmjit/x86/x86archdata.cpp new file mode 100644 index 00000000000..cd928b2534b --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/x86/x86archdata.cpp @@ -0,0 +1,137 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifdef ASMJIT_BUILD_X86 + +#include "../core/support.h" +#include "../core/type.h" +#include "../x86/x86archdata_p.h" +#include "../x86/x86operand.h" + +ASMJIT_BEGIN_SUB_NAMESPACE(x86) + +// ============================================================================ +// [asmjit::x86::ArchInternal] +// ============================================================================ + +namespace ArchInternal { + +Error typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfoOut) noexcept { + // Passed RegType instead of TypeId? + if (typeId <= BaseReg::kTypeMax) + typeId = opData.archRegs.regTypeToTypeId[typeId]; + + if (ASMJIT_UNLIKELY(!Type::isValid(typeId))) + return DebugUtils::errored(kErrorInvalidTypeId); + + // First normalize architecture dependent types. + if (Type::isAbstract(typeId)) { + bool is32Bit = arch == Environment::kArchX86; + if (typeId == Type::kIdIntPtr) + typeId = is32Bit ? Type::kIdI32 : Type::kIdI64; + else + typeId = is32Bit ? Type::kIdU32 : Type::kIdU64; + } + + // Type size helps to construct all groups of registers. + // TypeId is invalid if the size is zero. + uint32_t size = Type::sizeOf(typeId); + if (ASMJIT_UNLIKELY(!size)) + return DebugUtils::errored(kErrorInvalidTypeId); + + if (ASMJIT_UNLIKELY(typeId == Type::kIdF80)) + return DebugUtils::errored(kErrorInvalidUseOfF80); + + uint32_t regType = 0; + + switch (typeId) { + case Type::kIdI8: + case Type::kIdU8: + regType = Reg::kTypeGpbLo; + break; + + case Type::kIdI16: + case Type::kIdU16: + regType = Reg::kTypeGpw; + break; + + case Type::kIdI32: + case Type::kIdU32: + regType = Reg::kTypeGpd; + break; + + case Type::kIdI64: + case Type::kIdU64: + if (arch == Environment::kArchX86) + return DebugUtils::errored(kErrorInvalidUseOfGpq); + + regType = Reg::kTypeGpq; + break; + + // F32 and F64 are always promoted to use vector registers. + case Type::kIdF32: + typeId = Type::kIdF32x1; + regType = Reg::kTypeXmm; + break; + + case Type::kIdF64: + typeId = Type::kIdF64x1; + regType = Reg::kTypeXmm; + break; + + // Mask registers {k}. + case Type::kIdMask8: + case Type::kIdMask16: + case Type::kIdMask32: + case Type::kIdMask64: + regType = Reg::kTypeKReg; + break; + + // MMX registers. + case Type::kIdMmx32: + case Type::kIdMmx64: + regType = Reg::kTypeMm; + break; + + // XMM|YMM|ZMM registers. + default: + if (size <= 16) + regType = Reg::kTypeXmm; + else if (size == 32) + regType = Reg::kTypeYmm; + else + regType = Reg::kTypeZmm; + break; + } + + *typeIdOut = typeId; + regInfoOut->reset(opData.archRegs.regInfo[regType].signature()); + return kErrorOk; +} + +} // {ArchInternal} + +ASMJIT_END_SUB_NAMESPACE + +#endif // ASMJIT_BUILD_X86 diff --git a/3rdparty/asmjit/src/asmjit/x86/x86archdata_p.h b/3rdparty/asmjit/src/asmjit/x86/x86archdata_p.h new file mode 100644 index 00000000000..e765cb9b02a --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/x86/x86archdata_p.h @@ -0,0 +1,51 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_X86_X86ARCHDATA_P_H_INCLUDED +#define ASMJIT_X86_X86ARCHDATA_P_H_INCLUDED + +#include "../core/arch.h" + +ASMJIT_BEGIN_SUB_NAMESPACE(x86) + +//! \cond INTERNAL +//! \addtogroup asmjit_x86 +//! \{ + +// ============================================================================ +// [asmjit::x86::ArchInternal] +// ============================================================================ + +//! X86-specific function API (calling conventions and other utilities). +namespace ArchInternal { + +Error typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfoOut) noexcept; + +} // {ArchInternal} + +//! \} +//! \endcond + +ASMJIT_END_SUB_NAMESPACE + +#endif // ASMJIT_X86_X86ARCHDATA_P_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/x86/x86assembler.cpp b/3rdparty/asmjit/src/asmjit/x86/x86assembler.cpp index d509926e5f5..879fb2f0151 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86assembler.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86assembler.cpp @@ -24,14 +24,17 @@ #include "../core/api-build_p.h" #ifdef ASMJIT_BUILD_X86 +#include "../core/assembler.h" #include "../core/codebufferwriter_p.h" #include "../core/cpuinfo.h" -#include "../core/logging.h" +#include "../core/emitterutils_p.h" +#include "../core/formatter.h" +#include "../core/logger.h" #include "../core/misc_p.h" #include "../core/support.h" #include "../x86/x86assembler.h" #include "../x86/x86instdb_p.h" -#include "../x86/x86logging_p.h" +#include "../x86/x86formatter_p.h" #include "../x86/x86opcode_p.h" ASMJIT_BEGIN_SUB_NAMESPACE(x86) @@ -508,7 +511,7 @@ static ASMJIT_INLINE uint32_t x86GetMovAbsAddrType(Assembler* self, X86BufferWri if (addrType == BaseMem::kAddrTypeDefault && !(options & Inst::kOptionModMR)) { if (self->is64Bit()) { - uint64_t baseAddress = self->codeInfo().baseAddress(); + uint64_t baseAddress = self->code()->baseAddress(); if (baseAddress != Globals::kNoBaseAddress && !rmRel.hasSegment()) { uint32_t instructionSize = x86GetMovAbsInstSize64Bit(regSize, options, rmRel); uint64_t virtualOffset = uint64_t(writer.offsetFrom(self->_bufferData)); @@ -545,18 +548,18 @@ Assembler::~Assembler() noexcept {} // [asmjit::x86::Assembler - Emit (Low-Level)] // ============================================================================ -ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { +ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) { constexpr uint32_t kVSHR_W = Opcode::kW_Shift - 23; constexpr uint32_t kVSHR_PP = Opcode::kPP_Shift - 16; constexpr uint32_t kVSHR_PP_EW = Opcode::kPP_Shift - 16; constexpr uint32_t kRequiresSpecialHandling = - Inst::kOptionReserved | // Logging/Validation/Error. - Inst::kOptionRep | // REP/REPE prefix. - Inst::kOptionRepne | // REPNE prefix. - Inst::kOptionLock | // LOCK prefix. - Inst::kOptionXAcquire | // XACQUIRE prefix. - Inst::kOptionXRelease ; // XRELEASE prefix. + uint32_t(Inst::kOptionReserved) | // Logging/Validation/Error. + uint32_t(Inst::kOptionRep ) | // REP/REPE prefix. + uint32_t(Inst::kOptionRepne ) | // REPNE prefix. + uint32_t(Inst::kOptionLock ) | // LOCK prefix. + uint32_t(Inst::kOptionXAcquire) | // XACQUIRE prefix. + uint32_t(Inst::kOptionXRelease) ; // XRELEASE prefix. Error err; @@ -595,12 +598,12 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, c // instruction) are handled by the next branch. options = uint32_t(instId == 0); options |= uint32_t((size_t)(_bufferEnd - writer.cursor()) < 16); - options |= uint32_t(instOptions() | globalInstOptions()); + options |= uint32_t(instOptions() | forcedInstOptions()); // Handle failure and rare cases first. if (ASMJIT_UNLIKELY(options & kRequiresSpecialHandling)) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); // Unknown instruction. if (ASMJIT_UNLIKELY(instId == 0)) @@ -613,25 +616,13 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, c #ifndef ASMJIT_NO_VALIDATION // Strict validation. - if (hasEmitterOption(kOptionStrictValidation)) { + if (hasValidationOption(kValidationOptionAssembler)) { Operand_ opArray[Globals::kMaxOpCount]; + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); - opArray[0].copyFrom(o0); - opArray[1].copyFrom(o1); - opArray[2].copyFrom(o2); - opArray[3].copyFrom(o3); - - if (options & Inst::kOptionOp4Op5Used) { - opArray[4].copyFrom(_op4); - opArray[5].copyFrom(_op5); - } - else { - opArray[4].reset(); - opArray[5].reset(); - } - - err = InstAPI::validate(archId(), BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount); - if (ASMJIT_UNLIKELY(err)) goto Failed; + err = InstAPI::validate(arch(), BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount); + if (ASMJIT_UNLIKELY(err)) + goto Failed; } #endif @@ -693,7 +684,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, c if (ASMJIT_UNLIKELY(isign3 != ENC_OPS1(Imm))) goto InvalidInstruction; - immValue = o0.as<Imm>().u8(); + immValue = o0.as<Imm>().valueAs<uint8_t>(); immSize = 1; ASMJIT_FALLTHROUGH; @@ -738,14 +729,14 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, c case InstDB::kEncodingX86I_xAX: // Implicit form. if (isign3 == ENC_OPS1(Imm)) { - immValue = o0.as<Imm>().u8(); + immValue = o0.as<Imm>().valueAs<uint8_t>(); immSize = 1; goto EmitX86Op; } // Explicit form. if (isign3 == ENC_OPS2(Reg, Imm) && o0.id() == Gp::kIdAx) { - immValue = o1.as<Imm>().u8(); + immValue = o1.as<Imm>().valueAs<uint8_t>(); immSize = 1; goto EmitX86Op; } @@ -996,7 +987,7 @@ CaseX86M_GPB_MulDiv: uint32_t size = o0.size(); rbReg = o0.id(); - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); if (size == 1) { FIXUP_GPB(o0, rbReg); @@ -1022,8 +1013,7 @@ CaseX86M_GPB_MulDiv: else goto InvalidImmediate; } - else if (canTransformTo32Bit && hasEmitterOption(kOptionOptimizedForSize)) { - // This is a code-size optimization. + else if (canTransformTo32Bit && hasEncodingOption(kEncodingOptionOptimizeForSize)) { size = 4; } @@ -1053,7 +1043,7 @@ CaseX86M_GPB_MulDiv: if (ASMJIT_UNLIKELY(memSize == 0)) goto AmbiguousOperandSize; - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = FastUInt8(Support::min<uint32_t>(memSize, 4)); // Sign extend so isInt8 returns the right result. @@ -1098,7 +1088,7 @@ CaseX86M_GPB_MulDiv: } // The remaining instructions use the secondary opcode/r. - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = 1; opcode = x86AltOpcodeOf(instInfo); @@ -1175,8 +1165,11 @@ CaseX86M_GPB_MulDiv: } case InstDB::kEncodingX86Cmpxchg8b_16b: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; + const Operand_& o4 = opExt[EmitterUtils::kOp4]; + if (isign3 == ENC_OPS3(Mem, Reg, Reg)) { - if (o3.isReg() && _op4.isReg()) { + if (o3.isReg() && o4.isReg()) { rmRel = &o0; goto EmitX86M; } @@ -1224,8 +1217,8 @@ CaseX86M_GPB_MulDiv: case InstDB::kEncodingX86Enter: if (isign3 == ENC_OPS2(Imm, Imm)) { - uint32_t iw = o0.as<Imm>().u16(); - uint32_t ib = o1.as<Imm>().u8(); + uint32_t iw = o0.as<Imm>().valueAs<uint16_t>(); + uint32_t ib = o1.as<Imm>().valueAs<uint8_t>(); immValue = iw | (ib << 16); immSize = 3; @@ -1239,7 +1232,7 @@ CaseX86M_GPB_MulDiv: opcode = 0x6B; opcode.addPrefixBySize(o0.size()); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (!Support::isInt8(immValue) || (options & Inst::kOptionLongForm)) { @@ -1257,7 +1250,7 @@ CaseX86M_GPB_MulDiv: opcode = 0x6B; opcode.addPrefixBySize(o0.size()); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; // Sign extend so isInt8 returns the right result. @@ -1309,7 +1302,7 @@ CaseX86M_GPB_MulDiv: opcode = 0x6B; opcode.addPrefixBySize(o0.size()); - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = 1; // Sign extend so isInt8 returns the right result. @@ -1333,7 +1326,7 @@ CaseX86M_GPB_MulDiv: if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdAx)) goto InvalidInstruction; - immValue = o1.as<Imm>().u8(); + immValue = o1.as<Imm>().valueAs<uint8_t>(); immSize = 1; opcode = x86AltOpcodeOf(instInfo) + (o0.size() != 1); @@ -1398,18 +1391,16 @@ CaseX86M_GPB_MulDiv: case InstDB::kEncodingX86Int: if (isign3 == ENC_OPS1(Imm)) { - immValue = o0.as<Imm>().i64(); + immValue = o0.as<Imm>().value(); immSize = 1; goto EmitX86Op; } break; case InstDB::kEncodingX86Jcc: - if (_emitterOptions & kOptionPredictedJumps) { - if (options & Inst::kOptionTaken) - writer.emit8(0x3E); - if (options & Inst::kOptionNotTaken) - writer.emit8(0x2E); + if ((options & (Inst::kOptionTaken | Inst::kOptionNotTaken)) && hasEncodingOption(kEncodingOptionPredictedJumps)) { + uint8_t prefix = (options & Inst::kOptionTaken) ? uint8_t(0x3E) : uint8_t(0x2E); + writer.emit8(prefix); } rmRel = &o0; @@ -1649,16 +1640,16 @@ CaseX86M_GPB_MulDiv: FIXUP_GPB(o0, opReg); opcode = 0xB0; - immValue = o1.as<Imm>().u8(); + immValue = o1.as<Imm>().valueAs<uint8_t>(); goto EmitX86OpReg; } else { // 64-bit immediate in 64-bit mode is allowed. - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); // Optimize the instruction size by using a 32-bit immediate if possible. if (immSize == 8 && !(options & Inst::kOptionLongForm)) { - if (Support::isUInt32(immValue) && hasEmitterOption(kOptionOptimizedForSize)) { + if (Support::isUInt32(immValue) && hasEncodingOption(kEncodingOptionOptimizeForSize)) { // Zero-extend by using a 32-bit GPD destination instead of a 64-bit GPQ. immSize = 4; } @@ -1690,7 +1681,7 @@ CaseX86M_GPB_MulDiv: opReg = 0; rmRel = &o0; - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = FastUInt8(Support::min<uint32_t>(memSize, 4)); goto EmitX86M; } @@ -1753,7 +1744,7 @@ CaseX86M_GPB_MulDiv: opcode = x86AltOpcodeOf(instInfo) + (o1.size() != 1); opcode.add66hBySize(o1.size()); - immValue = o0.as<Imm>().u8(); + immValue = o0.as<Imm>().valueAs<uint8_t>(); immSize = 1; goto EmitX86Op; } @@ -1800,7 +1791,7 @@ CaseX86M_GPB_MulDiv: } if (isign3 == ENC_OPS1(Imm)) { - immValue = o0.as<Imm>().i64(); + immValue = o0.as<Imm>().value(); immSize = 4; if (Support::isInt8(immValue) && !(options & Inst::kOptionLongForm)) @@ -1840,7 +1831,7 @@ CaseX86PushPop_Gp: if (ASMJIT_UNLIKELY(o0.size() == 0)) goto AmbiguousOperandSize; - if (ASMJIT_UNLIKELY(o0.size() != 2 && o0.size() != gpSize())) + if (ASMJIT_UNLIKELY(o0.size() != 2 && o0.size() != registerSize())) goto InvalidInstruction; opcode.add66hBySize(o0.size()); @@ -1857,7 +1848,7 @@ CaseX86PushPop_Gp: } if (isign3 == ENC_OPS1(Imm)) { - immValue = o0.as<Imm>().i64(); + immValue = o0.as<Imm>().value(); if (immValue == 0 && !(options & Inst::kOptionLongForm)) { // 'ret' without immediate, change C2 to C3. opcode.add(1); @@ -1887,7 +1878,7 @@ CaseX86PushPop_Gp: } if (isign3 == ENC_OPS2(Reg, Imm)) { - immValue = o1.as<Imm>().i64() & 0xFF; + immValue = o1.as<Imm>().value() & 0xFF; immSize = 0; if (immValue == 1 && !(options & Inst::kOptionLongForm)) @@ -1915,7 +1906,7 @@ CaseX86PushPop_Gp: goto AmbiguousOperandSize; rmRel = &o0; - immValue = o1.as<Imm>().i64() & 0xFF; + immValue = o1.as<Imm>().value() & 0xFF; immSize = 0; if (immValue == 1 && !(options & Inst::kOptionLongForm)) @@ -1947,7 +1938,7 @@ CaseX86PushPop_Gp: opReg = o1.id(); rbReg = o0.id(); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; goto EmitX86R; } @@ -1957,7 +1948,7 @@ CaseX86PushPop_Gp: opReg = o1.id(); rmRel = &o0; - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; goto EmitX86M; } @@ -2077,11 +2068,11 @@ CaseX86PushPop_Gp: if (o0.size() == 1) { FIXUP_GPB(o0, rbReg); - immValue = o1.as<Imm>().u8(); + immValue = o1.as<Imm>().valueAs<uint8_t>(); immSize = 1; } else { - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = FastUInt8(Support::min<uint32_t>(o0.size(), 4)); } @@ -2102,7 +2093,7 @@ CaseX86PushPop_Gp: opcode.addArithBySize(o0.size()); rmRel = &o0; - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = FastUInt8(Support::min<uint32_t>(o0.size(), 4)); goto EmitX86M; } @@ -2345,7 +2336,7 @@ CaseFpuArith_Mem: if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { opcode.add66hIf(Reg::isXmm(o1)); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; opReg = o0.id(); @@ -2358,7 +2349,7 @@ CaseFpuArith_Mem: opcode = x86AltOpcodeOf(instInfo); opcode.add66hIf(Reg::isXmm(o1)); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; opReg = o1.id(); @@ -2371,7 +2362,7 @@ CaseFpuArith_Mem: if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { opcode.add66hIf(Reg::isXmm(o1)); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; opReg = o1.id(); @@ -2382,7 +2373,7 @@ CaseFpuArith_Mem: if (isign3 == ENC_OPS3(Mem, Reg, Imm)) { opcode.add66hIf(Reg::isXmm(o1)); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; opReg = o1.id(); @@ -2621,7 +2612,7 @@ CaseExtRm: opReg = opcode.extractO(); if (isign3 == ENC_OPS2(Reg, Imm)) { - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = 1; rbReg = o0.id(); @@ -2653,7 +2644,7 @@ CaseExtRm: if (isign3 == ENC_OPS2(Reg, Imm)) { opcode.add66hIf(Reg::isXmm(o0)); - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = 1; rbReg = o0.id(); @@ -2662,7 +2653,7 @@ CaseExtRm: break; case InstDB::kEncodingExtRmi: - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -2679,7 +2670,7 @@ CaseExtRm: break; case InstDB::kEncodingExtRmi_P: - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -2714,8 +2705,8 @@ CaseExtRm: opcode = x86AltOpcodeOf(instInfo); if (isign3 == ENC_OPS3(Reg, Imm, Imm)) { - immValue = (o1.as<Imm>().u32() ) + - (o2.as<Imm>().u32() << 8) ; + immValue = (uint32_t(o1.as<Imm>().valueAs<uint8_t>()) ) + + (uint32_t(o2.as<Imm>().valueAs<uint8_t>()) << 8) ; immSize = 2; rbReg = opcode.extractO(); @@ -2724,7 +2715,9 @@ CaseExtRm: break; case InstDB::kEncodingExtInsertq: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); + opReg = o0.id(); rbReg = o1.id(); @@ -2735,8 +2728,8 @@ CaseExtRm: opcode = x86AltOpcodeOf(instInfo); if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { - immValue = (o2.as<Imm>().u32() ) + - (o3.as<Imm>().u32() << 8) ; + immValue = (uint32_t(o2.as<Imm>().valueAs<uint8_t>()) ) + + (uint32_t(o3.as<Imm>().valueAs<uint8_t>()) << 8) ; immSize = 2; goto EmitX86R; } @@ -2869,7 +2862,7 @@ CaseExtRm: ASMJIT_FALLTHROUGH; case InstDB::kEncodingVexMri: - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -2934,24 +2927,22 @@ CaseVexRm: break; case InstDB::kEncodingVexRm_T1_4X: { - if (!(options & Inst::kOptionOp4Op5Used)) - goto InvalidInstruction; + const Operand_& o3 = opExt[EmitterUtils::kOp3]; + const Operand_& o4 = opExt[EmitterUtils::kOp4]; + const Operand_& o5 = opExt[EmitterUtils::kOp5]; - if (Reg::isZmm(o0 ) && Reg::isZmm(o1) && - Reg::isZmm(o2 ) && Reg::isZmm(o3) && - Reg::isZmm(_op4) && _op5.isMem()) { - - // Registers [o1, o2, o3, _op4] must start aligned and must be consecutive. + if (Reg::isZmm(o0) && Reg::isZmm(o1) && Reg::isZmm(o2) && Reg::isZmm(o3) && Reg::isZmm(o4) && o5.isMem()) { + // Registers [o1, o2, o3, o4] must start aligned and must be consecutive. uint32_t i1 = o1.id(); uint32_t i2 = o2.id(); uint32_t i3 = o3.id(); - uint32_t i4 = _op4.id(); + uint32_t i4 = o4.id(); if (ASMJIT_UNLIKELY((i1 & 0x3) != 0 || i2 != i1 + 1 || i3 != i1 + 2 || i4 != i1 + 3)) goto NotConsecutiveRegs; opReg = o0.id(); - rmRel = &_op5; + rmRel = &o5; goto EmitVexEvexM; } break; @@ -2967,7 +2958,7 @@ CaseVexRm: case InstDB::kEncodingVexRmi: CaseVexRmi: - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -2999,25 +2990,32 @@ CaseVexRvm_R: } break; - case InstDB::kEncodingVexRvm_ZDX_Wx: + case InstDB::kEncodingVexRvm_ZDX_Wx: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; if (ASMJIT_UNLIKELY(!o3.isNone() && !Reg::isGp(o3, Gp::kIdDx))) goto InvalidInstruction; ASMJIT_FALLTHROUGH; + } - case InstDB::kEncodingVexRvm_Wx: + case InstDB::kEncodingVexRvm_Wx: { opcode.addWIf(Reg::isGpq(o0) | (o2.size() == 8)); goto CaseVexRvm; + } - case InstDB::kEncodingVexRvm_Lx: + case InstDB::kEncodingVexRvm_Lx: { opcode |= x86OpcodeLBySize(o0.size() | o1.size()); goto CaseVexRvm; + } - case InstDB::kEncodingVexRvmr_Lx: + case InstDB::kEncodingVexRvmr_Lx: { opcode |= x86OpcodeLBySize(o0.size() | o1.size()); ASMJIT_FALLTHROUGH; + } case InstDB::kEncodingVexRvmr: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); + immValue = o3.id() << 4; immSize = 1; @@ -3040,8 +3038,10 @@ CaseVexRvm_R: ASMJIT_FALLTHROUGH; case InstDB::kEncodingVexRvmi: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); - immValue = o3.as<Imm>().i64(); + + immValue = o3.as<Imm>().value(); immSize = 1; if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { @@ -3100,8 +3100,10 @@ CaseVexRvm_R: case InstDB::kEncodingVexRmvi: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); - immValue = o3.as<Imm>().i64(); + + immValue = o3.as<Imm>().value(); immSize = 1; if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { @@ -3249,7 +3251,7 @@ CaseVexRvm_R: opcode &= Opcode::kLL_Mask; opcode |= x86AltOpcodeOf(instInfo); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -3295,7 +3297,7 @@ CaseVexRvm_R: // The following instructions use the secondary opcode. opcode = x86AltOpcodeOf(instInfo); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -3390,7 +3392,7 @@ CaseVexRvm_R: opcode |= x86AltOpcodeOf(instInfo); opReg = opcode.extractO(); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -3434,7 +3436,7 @@ CaseVexRvm_R: ASMJIT_FALLTHROUGH; case InstDB::kEncodingVexVmi: - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; CaseVexVmi_AfterImm: @@ -3453,7 +3455,7 @@ CaseVexVmi_AfterImm: case InstDB::kEncodingVexVmi4_Wx: opcode.addWIf(Reg::isGpq(o0) || o1.size() == 8); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 4; goto CaseVexVmi_AfterImm; @@ -3462,6 +3464,7 @@ CaseVexVmi_AfterImm: ASMJIT_FALLTHROUGH; case InstDB::kEncodingVexRvrmRvmr: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { @@ -3495,13 +3498,16 @@ CaseVexVmi_AfterImm: } case InstDB::kEncodingVexRvrmiRvmri_Lx: { - if (!(options & Inst::kOptionOp4Op5Used) || !_op4.isImm()) + const Operand_& o3 = opExt[EmitterUtils::kOp3]; + const Operand_& o4 = opExt[EmitterUtils::kOp4]; + + if (ASMJIT_UNLIKELY(!o4.isImm())) goto InvalidInstruction; const uint32_t isign4 = isign3 + (o3.opType() << 9); opcode |= x86OpcodeLBySize(o0.size() | o1.size() | o2.size() | o3.size()); - immValue = _op4.as<Imm>().u8() & 0x0F; + immValue = o4.as<Imm>().valueAs<uint8_t>() & 0x0F; immSize = 1; if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { @@ -3560,6 +3566,7 @@ CaseVexVmi_AfterImm: ASMJIT_FALLTHROUGH; case InstDB::kEncodingFma4: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { @@ -3600,7 +3607,7 @@ CaseVexVmi_AfterImm: // -------------------------------------------------------------------------- EmitX86OpMovAbs: - immSize = FastUInt8(gpSize()); + immSize = FastUInt8(registerSize()); writer.emitSegmentOverride(rmRel->as<Mem>().segmentId()); EmitX86Op: @@ -3805,7 +3812,7 @@ EmitModSib: else { bool isOffsetI32 = rmRel->as<Mem>().offsetHi32() == (relOffset >> 31); bool isOffsetU32 = rmRel->as<Mem>().offsetHi32() == 0; - uint64_t baseAddress = codeInfo().baseAddress(); + uint64_t baseAddress = code()->baseAddress(); // If relative addressing was not explicitly set then we can try to guess. // By guessing we check some properties of the memory operand and try to @@ -4241,7 +4248,7 @@ EmitVexEvexR: rbReg &= 0x7; writer.emit8(x86EncodeMod(3, opReg, rbReg)); - writer.emitImmByteOrDWord(immValue, immSize); + writer.emitImmByteOrDWord(uint64_t(immValue), immSize); goto EmitDone; } @@ -4262,7 +4269,7 @@ EmitVexEvexR: rbReg &= 0x7; writer.emit8(x86EncodeMod(3, opReg, rbReg)); - writer.emitImmByteOrDWord(immValue, immSize); + writer.emitImmByteOrDWord(uint64_t(immValue), immSize); goto EmitDone; } else { @@ -4276,7 +4283,7 @@ EmitVexEvexR: rbReg &= 0x7; writer.emit8(x86EncodeMod(3, opReg, rbReg)); - writer.emitImmByteOrDWord(immValue, immSize); + writer.emitImmByteOrDWord(uint64_t(immValue), immSize); goto EmitDone; } } @@ -4459,15 +4466,15 @@ EmitJmpCall: } if (rmRel->isImm()) { - uint64_t baseAddress = codeInfo().baseAddress(); - uint64_t jumpAddress = rmRel->as<Imm>().u64(); + uint64_t baseAddress = code()->baseAddress(); + uint64_t jumpAddress = rmRel->as<Imm>().valueAs<uint64_t>(); // If the base-address is known calculate a relative displacement and // check if it fits in 32 bits (which is always true in 32-bit mode). // Emit relative displacement as it was a bound label if all checks are ok. if (baseAddress != Globals::kNoBaseAddress) { uint64_t rel64 = jumpAddress - (ip + baseAddress) - inst32Size; - if (archId() == ArchInfo::kIdX86 || Support::isInt32(int64_t(rel64))) { + if (Environment::is32Bit(arch()) || Support::isInt32(int64_t(rel64))) { rel32 = uint32_t(rel64 & 0xFFFFFFFFu); goto EmitJmpCallRel; } @@ -4492,7 +4499,7 @@ EmitJmpCall: // REX prefix does nothing if not patched, but allows to patch the // instruction to use MOD/M and to point to a memory where the final // 64-bit address is stored. - if (archId() != ArchInfo::kIdX86 && x86IsJmpOrCall(instId)) { + if (Environment::is64Bit(arch()) && x86IsJmpOrCall(instId)) { if (!rex) writer.emit8(kX86ByteRex); @@ -4582,13 +4589,13 @@ EmitRel: EmitDone: if (ASMJIT_UNLIKELY(options & Inst::kOptionReserved)) { #ifndef ASMJIT_NO_LOGGING - if (hasEmitterOption(kOptionLoggingEnabled)) - _emitLog(instId, options, o0, o1, o2, o3, relSize, immSize, writer.cursor()); + if (_logger) + EmitterUtils::logInstructionEmitted(this, instId, options, o0, o1, o2, opExt, relSize, immSize, writer.cursor()); #endif } - resetInstOptions(); resetExtraReg(); + resetInstOptions(); resetInlineComment(); writer.done(this); @@ -4625,7 +4632,14 @@ EmitDone: #undef ERROR_HANDLER Failed: - return _emitFailed(err, instId, options, o0, o1, o2, o3); +#ifndef ASMJIT_NO_LOGGING + return EmitterUtils::logInstructionFailed(this, err, instId, options, o0, o1, o2, opExt); +#else + resetExtraReg(); + resetInstOptions(); + resetInlineComment(); + return reportError(err); +#endif } // ============================================================================ @@ -4633,6 +4647,9 @@ Failed: // ============================================================================ Error Assembler::align(uint32_t alignMode, uint32_t alignment) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + if (ASMJIT_UNLIKELY(alignMode >= kAlignCount)) return reportError(DebugUtils::errored(kErrorInvalidArgument)); @@ -4650,7 +4667,7 @@ Error Assembler::align(uint32_t alignMode, uint32_t alignment) { uint8_t pattern = 0x00; switch (alignMode) { case kAlignCode: { - if (hasEmitterOption(kOptionOptimizedAlign)) { + if (hasEncodingOption(kEncodingOptionOptimizedAlign)) { // Intel 64 and IA-32 Architectures Software Developer's Manual - Volume 2B (NOP). enum { kMaxNopSize = 9 }; @@ -4699,12 +4716,11 @@ Error Assembler::align(uint32_t alignMode, uint32_t alignment) { } #ifndef ASMJIT_NO_LOGGING - if (hasEmitterOption(kOptionLoggingEnabled)) { - Logger* logger = _code->logger(); + if (_logger) { StringTmp<128> sb; - sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationCode)); + sb.appendChars(' ', _logger->indentation(FormatOptions::kIndentationCode)); sb.appendFormat("align %u\n", alignment); - logger->log(sb); + _logger->log(sb); } #endif @@ -4716,22 +4732,22 @@ Error Assembler::align(uint32_t alignMode, uint32_t alignment) { // ============================================================================ Error Assembler::onAttach(CodeHolder* code) noexcept { - uint32_t archId = code->archId(); - if (!ArchInfo::isX86Family(archId)) + uint32_t arch = code->arch(); + if (!Environment::isFamilyX86(arch)) return DebugUtils::errored(kErrorInvalidArch); ASMJIT_PROPAGATE(Base::onAttach(code)); - if (archId == ArchInfo::kIdX86) { + if (Environment::is32Bit(arch)) { // 32 bit architecture - X86. _gpRegInfo.setSignature(Gpd::kSignature); - _globalInstOptions |= Inst::_kOptionInvalidRex; + _forcedInstOptions |= Inst::_kOptionInvalidRex; _setAddressOverrideMask(kX86MemInfo_67H_X86); } else { // 64 bit architecture - X64. _gpRegInfo.setSignature(Gpq::kSignature); - _globalInstOptions &= ~Inst::_kOptionInvalidRex; + _forcedInstOptions &= ~Inst::_kOptionInvalidRex; _setAddressOverrideMask(kX86MemInfo_67H_X64); } @@ -4739,6 +4755,9 @@ Error Assembler::onAttach(CodeHolder* code) noexcept { } Error Assembler::onDetach(CodeHolder* code) noexcept { + _forcedInstOptions &= ~Inst::_kOptionInvalidRex; + _setAddressOverrideMask(0); + return Base::onDetach(code); } diff --git a/3rdparty/asmjit/src/asmjit/x86/x86assembler.h b/3rdparty/asmjit/src/asmjit/x86/x86assembler.h index 3e3027bab4a..8cd10143b0e 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86assembler.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86assembler.h @@ -37,9 +37,652 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // [asmjit::Assembler] // ============================================================================ -//! Assembler (X86). +//! X86/X64 assembler implementation. //! -//! Emits X86 machine-code into buffers managed by `CodeHolder`. +//! x86::Assembler is a code emitter that emits machine code directly into the +//! \ref CodeBuffer. The assembler is capable of targeting both 32-bit and 64-bit +//! instruction sets, the instruction set can be configured through \ref CodeHolder. +//! +//! ### Basics +//! +//! The following example shows a basic use of `x86::Assembler`, how to generate +//! a function that works in both 32-bit and 64-bit modes, and how to connect +//! \ref JitRuntime, \ref CodeHolder, and `x86::Assembler`. +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef int (*SumFunc)(const int* arr, size_t count); +//! +//! int main() { +//! JitRuntime rt; // Create a runtime specialized for JIT. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! +//! // Decide between 32-bit CDECL, WIN64, and SysV64 calling conventions: +//! // 32-BIT - passed all arguments by stack. +//! // WIN64 - passes first 4 arguments by RCX, RDX, R8, and R9. +//! // UNIX64 - passes first 6 arguments by RDI, RSI, RCX, RDX, R8, and R9. +//! x86::Gp arr, cnt; +//! x86::Gp sum = x86::eax; // Use EAX as 'sum' as it's a return register. +//! +//! if (ASMJIT_ARCH_BITS == 64) { +//! #if defined(_WIN32) +//! arr = x86::rcx; // First argument (array ptr). +//! cnt = x86::rdx; // Second argument (number of elements) +//! #else +//! arr = x86::rdi; // First argument (array ptr). +//! cnt = x86::rsi; // Second argument (number of elements) +//! #endif +//! } +//! else { +//! arr = x86::edx; // Use EDX to hold the array pointer. +//! cnt = x86::ecx; // Use ECX to hold the counter. +//! // Fetch first and second arguments from [ESP + 4] and [ESP + 8]. +//! a.mov(arr, x86::ptr(x86::esp, 4)); +//! a.mov(cnt, x86::ptr(x86::esp, 8)); +//! } +//! +//! Label Loop = a.newLabel(); // To construct the loop, we need some labels. +//! Label Exit = a.newLabel(); +//! +//! a.xor_(sum, sum); // Clear 'sum' register (shorter than 'mov'). +//! a.test(cnt, cnt); // Border case: +//! a.jz(Exit); // If 'cnt' is zero jump to 'Exit' now. +//! +//! a.bind(Loop); // Start of a loop iteration. +//! a.add(sum, x86::dword_ptr(arr)); // Add int at [arr] to 'sum'. +//! a.add(arr, 4); // Increment 'arr' pointer. +//! a.dec(cnt); // Decrease 'cnt'. +//! a.jnz(Loop); // If not zero jump to 'Loop'. +//! +//! a.bind(Exit); // Exit to handle the border case. +//! a.ret(); // Return from function ('sum' == 'eax'). +//! // ----> x86::Assembler is no longer needed from here and can be destroyed <---- +//! +//! SumFunc fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ----> CodeHolder is no longer needed from here and can be destroyed <---- +//! +//! static const int array[6] = { 4, 8, 15, 16, 23, 42 }; +//! +//! int result = fn(array, 6); // Execute the generated code. +//! printf("%d\n", result); // Print sum of array (108). +//! +//! rt.release(fn); // Explicitly remove the function from the runtime +//! return 0; // Everything successful... +//! } +//! ``` +//! +//! The example should be self-explanatory. It shows how to work with labels, +//! how to use operands, and how to emit instructions that can use different +//! registers based on runtime selection. It implements 32-bit CDECL, WIN64, +//! and SysV64 caling conventions and will work on most X86/X64 environments. +//! +//! Although functions prologs / epilogs can be implemented manually, AsmJit +//! provides utilities that can be used to create function prologs and epilogs +//! automatically, see \ref asmjit_function for more details. +//! +//! ### Instruction Validation +//! +//! Assembler prefers speed over strictness by default. The implementation checks +//! the type of operands and fails if the signature of types is invalid, however, +//! it does only basic checks regarding registers and their groups used in +//! instructions. It's possible to pass operands that don't form any valid +//! signature to the implementation and succeed. This is usually not a problem +//! as Assembler provides typed API so operand types are normally checked by C++ +//! compiler at compile time, however, Assembler is fully dynamic and its \ref +//! emit() function can be called with any instruction id, options, and operands. +//! Moreover, it's also possible to form instructions that will be accepted by +//! the typed API, for example by calling `mov(x86::eax, x86::al)` - the C++ +//! compiler won't see a problem as both EAX and AL are \ref Gp registers. +//! +//! To help with common mistakes AsmJit allows to activate instruction validation. +//! This feature instruments the Assembler to call \ref InstAPI::validate() before +//! it attempts to encode any instruction. +//! +//! The example below illustrates how validation can be turned on: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! int main(int argc, char* argv[]) { +//! JitRuntime rt; // Create a runtime specialized for JIT. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! +//! // Enable strict validation. +//! a.addValidationOptions(BaseEmitter::kValidationOptionAssembler); +//! +//! // Try to encode invalid or ill-formed instructions. +//! Error err; +//! +//! // Invalid instruction. +//! err = a.mov(x86::eax, x86::al); +//! printf("Status: %s\n", DebugUtils::errorAsString(err)); +//! +//! // Invalid instruction. +//! err = a.emit(x86::Inst::kIdMovss, x86::eax, x86::xmm0); +//! printf("Status: %s\n", DebugUtils::errorAsString(err)); +//! +//! // Ambiguous operand size - the pointer requires size. +//! err = a.inc(x86::ptr(x86::rax), 1); +//! printf("Status: %s\n", DebugUtils::errorAsString(err)); +//! +//! return 0; +//! } +//! ``` +//! +//! ### Native Registers +//! +//! All emitters provide functions to construct machine-size registers depending +//! on the target. This feature is for users that want to write code targeting +//! both 32-bit and 64-bit architectures at the same time. In AsmJit terminology +//! such registers have prefix `z`, so for example on X86 architecture the +//! following native registers are provided: +//! +//! - `zax` - mapped to either `eax` or `rax` +//! - `zbx` - mapped to either `ebx` or `rbx` +//! - `zcx` - mapped to either `ecx` or `rcx` +//! - `zdx` - mapped to either `edx` or `rdx` +//! - `zsp` - mapped to either `esp` or `rsp` +//! - `zbp` - mapped to either `ebp` or `rbp` +//! - `zsi` - mapped to either `esi` or `rsi` +//! - `zdi` - mapped to either `edi` or `rdi` +//! +//! They are accessible through \ref x86::Assembler, \ref x86::Builder, and +//! \ref x86::Compiler. The example below illustrates how to use this feature: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! typedef int (*Func)(void); +//! +//! int main(int argc, char* argv[]) { +//! JitRuntime rt; // Create a runtime specialized for JIT. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! +//! // Let's get these registers from x86::Assembler. +//! x86::Gp zbp = a.zbp(); +//! x86::Gp zsp = a.zsp(); +//! +//! int stackSize = 32; +//! +//! // Function prolog. +//! a.push(zbp); +//! a.mov(zbp, zsp); +//! a.sub(zsp, stackSize); +//! +//! // ... emit some code (this just sets return value to zero) ... +//! a.xor_(x86::eax, x86::eax); +//! +//! // Function epilog and return. +//! a.mov(zsp, zbp); +//! a.pop(zbp); +//! a.ret(); +//! +//! // To make the example complete let's call it. +//! Func fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! +//! int result = fn(); // Execute the generated code. +//! printf("%d\n", result); // Print the resulting "0". +//! +//! rt.release(fn); // Remove the function from the runtime. +//! return 0; +//! } +//! ``` +//! +//! The example just returns `0`, but the function generated contains a standard +//! prolog and epilog sequence and the function itself reserves 32 bytes of local +//! stack. The advantage is clear - a single code-base can handle multiple targets +//! easily. If you want to create a register of native size dynamically by +//! specifying its id it's also possible: +//! +//! ``` +//! void example(x86::Assembler& a) { +//! x86::Gp zax = a.gpz(x86::Gp::kIdAx); +//! x86::Gp zbx = a.gpz(x86::Gp::kIdBx); +//! x86::Gp zcx = a.gpz(x86::Gp::kIdCx); +//! x86::Gp zdx = a.gpz(x86::Gp::kIdDx); +//! +//! // You can also change register's id easily. +//! x86::Gp zsp = zax; +//! zsp.setId(4); // or x86::Gp::kIdSp. +//! } +//! ``` +//! +//! ### Data Embedding +//! +//! x86::Assembler extends the standard \ref BaseAssembler with X86/X64 specific +//! conventions that are often used by assemblers to embed data next to the code. +//! The following functions can be used to embed data: +//! +//! - \ref x86::Assembler::db() - embeds byte (8 bits) (x86 naming). +//! - \ref x86::Assembler::dw() - embeds word (16 bits) (x86 naming). +//! - \ref x86::Assembler::dd() - embeds dword (32 bits) (x86 naming). +//! - \ref x86::Assembler::dq() - embeds qword (64 bits) (x86 naming). +//! +//! - \ref BaseAssembler::embedInt8() - embeds int8_t (portable naming). +//! - \ref BaseAssembler::embedUInt8() - embeds uint8_t (portable naming). +//! - \ref BaseAssembler::embedInt16() - embeds int16_t (portable naming). +//! - \ref BaseAssembler::embedUInt16() - embeds uint16_t (portable naming). +//! - \ref BaseAssembler::embedInt32() - embeds int32_t (portable naming). +//! - \ref BaseAssembler::embedUInt32() - embeds uint32_t (portable naming). +//! - \ref BaseAssembler::embedInt64() - embeds int64_t (portable naming). +//! - \ref BaseAssembler::embedUInt64() - embeds uint64_t (portable naming). +//! - \ref BaseAssembler::embedFloat() - embeds float (portable naming). +//! - \ref BaseAssembler::embedDouble() - embeds double (portable naming). +//! +//! The following example illustrates how embed works: +//! +//! ``` +//! #include <asmjit/x86.h> +//! using namespace asmjit; +//! +//! void embedData(x86::Assembler& a) { +//! a.db(0xFF); // Embeds 0xFF byte. +//! a.dw(0xFF00); // Embeds 0xFF00 word (little-endian). +//! a.dd(0xFF000000); // Embeds 0xFF000000 dword (little-endian). +//! a.embedFloat(0.4f); // Embeds 0.4f (32-bit float, little-endian). +//! } +//! ``` +//! +//! Sometimes it's required to read the data that is embedded after code, for +//! example. This can be done through \ref Label as shown below: +//! +//! ``` +//! #include <asmjit/x86.h> +//! using namespace asmjit; +//! +//! void embedData(x86::Assembler& a, const Label& L_Data) { +//! x86::Gp addr = a.zax(); // EAX or RAX. +//! x86::Gp val = x86::edi; // Where to store some value... +//! +//! // Approach 1 - Load the address to register through LEA. This approach +//! // is flexible as the address can be then manipulated, for +//! // example if you have a data array, which would need index. +//! a.lea(addr, L_Data); // Loads the address of the label to EAX or RAX. +//! a.mov(val, dword_ptr(addr)); +//! +//! // Approach 2 - Load the data directly by using L_Data in address. It's +//! // worth noting that this doesn't work with indexes in X64 +//! // mode. It will use absolute address in 32-bit mode and +//! // relative address (RIP) in 64-bit mode. +//! a.mov(val, dword_ptr(L_Data)); +//! } +//! ``` +//! +//! ### Label Embedding +//! +//! It's also possible to embed labels. In general AsmJit provides the following +//! options: +//! +//! - \ref BaseEmitter::embedLabel() - Embeds absolute address of a label. +//! This is target dependent and would embed either 32-bit or 64-bit data +//! that embeds absolute label address. This kind of embedding cannot be +//! used in a position independent code. +//! +//! - \ref BaseEmitter::embedLabelDelta() - Embeds a difference between two +//! labels. The size of the difference can be specified so it's possible to +//! embed 8-bit, 16-bit, 32-bit, and 64-bit difference, which is sufficient +//! for most purposes. +//! +//! The following example demonstrates how to embed labels and their differences: +//! +//! ``` +//! #include <asmjit/x86.h> +//! using namespace asmjit; +//! +//! void embedLabel(x86::Assembler& a, const Label& L_Data) { +//! // [1] Embed L_Data - the size of the data will be dependent on the target. +//! a.embedLabel(L_Data); +//! +//! // [2] Embed a 32-bit difference of two labels. +//! Label L_Here = a.newLabel(); +//! a.bind(L_Here); +//! // Embeds int32_t(L_Data - L_Here). +//! a.embedLabelDelta(L_Data, L_Here, 4); +//! } +//! ``` +//! +//! ### Using FuncFrame and FuncDetail with x86::Assembler +//! +//! The example below demonstrates how \ref FuncFrame and \ref FuncDetail can be +//! used together with \ref x86::Assembler to generate a function that will use +//! platform dependent calling conventions automatically depending on the target: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); +//! +//! int main(int argc, char* argv[]) { +//! JitRuntime rt; // Create JIT Runtime. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! +//! // Decide which registers will be mapped to function arguments. Try changing +//! // registers of dst, src_a, and src_b and see what happens in function's +//! // prolog and epilog. +//! x86::Gp dst = a.zax(); +//! x86::Gp src_a = a.zcx(); +//! x86::Gp src_b = a.zdx(); +//! +//! X86::Xmm vec0 = x86::xmm0; +//! X86::Xmm vec1 = x86::xmm1; +//! +//! // Create/initialize FuncDetail and FuncFrame. +//! FuncDetail func; +//! func.init(FuncSignatureT<void, int*, const int*, const int*>(CallConv::kIdHost)); +//! +//! FuncFrame frame; +//! frame.init(func); +//! +//! // Make XMM0 and XMM1 dirty - kGroupVec describes XMM|YMM|ZMM registers. +//! frame.setDirtyRegs(x86::Reg::kGroupVec, IntUtils::mask(0, 1)); +//! +//! // Alternatively, if you don't want to use register masks you can pass BaseReg +//! // to addDirtyRegs(). The following code would add both xmm0 and xmm1. +//! frame.addDirtyRegs(x86::xmm0, x86::xmm1); +//! +//! FuncArgsAssignment args(&func); // Create arguments assignment context. +//! args.assignAll(dst, src_a, src_b);// Assign our registers to arguments. +//! args.updateFrameInfo(frame); // Reflect our args in FuncFrame. +//! frame.finalize(); // Finalize the FuncFrame (updates it). +//! +//! a.emitProlog(frame); // Emit function prolog. +//! a.emitArgsAssignment(frame, args);// Assign arguments to registers. +//! a.movdqu(vec0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. +//! a.movdqu(vec1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. +//! a.paddd(vec0, vec1); // Add 4 ints in XMM1 to XMM0. +//! a.movdqu(x86::ptr(dst), vec0); // Store the result to [dst]. +//! a.emitEpilog(frame); // Emit function epilog and return. +//! +//! SumIntsFunc fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error case. +//! +//! // Execute the generated function. +//! int inA[4] = { 4, 3, 2, 1 }; +//! int inB[4] = { 1, 5, 2, 8 }; +//! int out[4]; +//! fn(out, inA, inB); +//! +//! // Prints {5 8 4 9} +//! printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); +//! +//! rt.release(fn); +//! return 0; +//! } +//! ``` +//! +//! ### Using x86::Assembler as Code-Patcher +//! +//! This is an advanced topic that is sometimes unavoidable. AsmJit by default +//! appends machine code it generates into a \ref CodeBuffer, however, it also +//! allows to set the offset in \ref CodeBuffer explicitly and to overwrite its +//! content. This technique is extremely dangerous as X86 instructions have +//! variable length (see below), so you should in general only patch code to +//! change instruction's immediate values or some other details not known the +//! at a time the instruction was emitted. A typical scenario that requires +//! code-patching is when you start emitting function and you don't know how +//! much stack you want to reserve for it. +//! +//! Before we go further it's important to introduce instruction options, because +//! they can help with code-patching (and not only patching, but that will be +//! explained in AVX-512 section): +//! +//! - Many general-purpose instructions (especially arithmetic ones) on X86 +//! have multiple encodings - in AsmJit this is usually called 'short form' +//! and 'long form'. +//! - AsmJit always tries to use 'short form' as it makes the resulting +//! machine-code smaller, which is always good - this decision is used +//! by majority of assemblers out there. +//! - AsmJit allows to override the default decision by using `short_()` +//! and `long_()` instruction options to force short or long form, +//! respectively. The most useful is `long_()` as it basically forces +//! AsmJit to always emit the longest form. The `short_()` is not that +//! useful as it's automatic (except jumps to non-bound labels). Note that +//! the underscore after each function name avoids collision with built-in +//! C++ types. +//! +//! To illustrate what short form and long form means in binary let's assume +//! we want to emit "add esp, 16" instruction, which has two possible binary +//! encodings: +//! +//! - `83C410` - This is a short form aka `short add esp, 16` - You can see +//! opcode byte (0x8C), MOD/RM byte (0xC4) and an 8-bit immediate value +//! representing `16`. +//! - `81C410000000` - This is a long form aka `long add esp, 16` - You can +//! see a different opcode byte (0x81), the same Mod/RM byte (0xC4) and a +//! 32-bit immediate in little-endian representing `16`. +//! +//! It should be obvious that patching an existing instruction into an instruction +//! having a different size may create various problems. So it's recommended to be +//! careful and to only patch instructions into instructions having the same size. +//! The example below demonstrates how instruction options can be used to guarantee +//! the size of an instruction by forcing the assembler to use long-form encoding: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! typedef int (*Func)(void); +//! +//! int main(int argc, char* argv[]) { +//! JitRuntime rt; // Create a runtime specialized for JIT. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! +//! // Let's get these registers from x86::Assembler. +//! x86::Gp zbp = a.zbp(); +//! x86::Gp zsp = a.zsp(); +//! +//! // Function prolog. +//! a.push(zbp); +//! a.mov(zbp, zsp); +//! +//! // This is where we are gonna patch the code later, so let's get the offset +//! // (the current location) from the beginning of the code-buffer. +//! size_t patchOffset = a.offset(); +//! // Let's just emit 'sub zsp, 0' for now, but don't forget to use LONG form. +//! a.long_().sub(zsp, 0); +//! +//! // ... emit some code (this just sets return value to zero) ... +//! a.xor_(x86::eax, x86::eax); +//! +//! // Function epilog and return. +//! a.mov(zsp, zbp); +//! a.pop(zbp); +//! a.ret(); +//! +//! // Now we know how much stack size we want to reserve. I have chosen 128 +//! // bytes on purpose as it's encodable only in long form that we have used. +//! +//! int stackSize = 128; // Number of bytes to reserve on the stack. +//! a.setOffset(patchOffset); // Move the current cursor to `patchOffset`. +//! a.long_().sub(zsp, stackSize); // Patch the code; don't forget to use LONG form. +//! +//! // Now the code is ready to be called +//! Func fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! +//! int result = fn(); // Execute the generated code. +//! printf("%d\n", result); // Print the resulting "0". +//! +//! rt.release(fn); // Remove the function from the runtime. +//! return 0; +//! } +//! ``` +//! +//! If you run the example it will just work, because both instructions have +//! the same size. As an experiment you can try removing `long_()` form to +//! see what happens when wrong code is generated. +//! +//! ### Code Patching and REX Prefix +//! +//! In 64-bit mode there is one more thing to worry about when patching code: +//! REX prefix. It's a single byte prefix designed to address registers with +//! ids from 9 to 15 and to override the default width of operation from 32 +//! to 64 bits. AsmJit, like other assemblers, only emits REX prefix when it's +//! necessary. If the patched code only changes the immediate value as shown +//! in the previous example then there is nothing to worry about as it doesn't +//! change the logic behind emitting REX prefix, however, if the patched code +//! changes register id or overrides the operation width then it's important +//! to take care of REX prefix as well. +//! +//! AsmJit contains another instruction option that controls (forces) REX +//! prefix - `rex()`. If you use it the instruction emitted will always use +//! REX prefix even when it's encodable without it. The following list contains +//! some instructions and their binary representations to illustrate when it's +//! emitted: +//! +//! - `__83C410` - `add esp, 16` - 32-bit operation in 64-bit mode doesn't require REX prefix. +//! - `4083C410` - `rex add esp, 16` - 32-bit operation in 64-bit mode with forced REX prefix (0x40). +//! - `4883C410` - `add rsp, 16` - 64-bit operation in 64-bit mode requires REX prefix (0x48). +//! - `4183C410` - `add r12d, 16` - 32-bit operation in 64-bit mode using R12D requires REX prefix (0x41). +//! - `4983C410` - `add r12, 16` - 64-bit operation in 64-bit mode using R12 requires REX prefix (0x49). +//! +//! ### More Prefixes +//! +//! X86 architecture is known for its prefixes. AsmJit supports all prefixes +//! that can affect how the instruction is encoded: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void prefixesExample(x86::Assembler& a) { +//! // Lock prefix for implementing atomics: +//! // lock add dword ptr [dst], 1 +//! a.lock().add(x86::dword_ptr(dst), 1); +//! +//! // Similarly, XAcquire/XRelease prefixes are also available: +//! // xacquire add dword ptr [dst], 1 +//! a.xacquire().add(x86::dword_ptr(dst), 1); +//! +//! // Rep prefix (see also repe/repz and repne/repnz): +//! // rep movs byte ptr [dst], byte ptr [src] +//! a.rep().movs(x86::byte_ptr(dst), x86::byte_ptr(src)); +//! +//! // Forcing REX prefix in 64-bit mode. +//! // rex mov eax, 1 +//! a.rex().mov(x86::eax, 1); +//! +//! // AVX instruction without forced prefix uses the shortest encoding: +//! // vaddpd xmm0, xmm1, xmm2 -> [C5|F1|58|C2] +//! a.vaddpd(x86::xmm0, x86::xmm1, x86::xmm2); +//! +//! // Forcing VEX3 prefix (AVX): +//! // vex3 vaddpd xmm0, xmm1, xmm2 -> [C4|E1|71|58|C2] +//! a.vex3().vaddpd(x86::xmm0, x86::xmm1, x86::xmm2); +//! +//! // Forcing EVEX prefix (AVX512): +//! // evex vaddpd xmm0, xmm1, xmm2 -> [62|F1|F5|08|58|C2] +//! a.evex().vaddpd(x86::xmm0, x86::xmm1, x86::xmm2); +//! +//! // Some instructions accept prefixes not originally intended to: +//! // rep ret +//! a.rep().ret(); +//! } +//! ``` +//! +//! It's important to understand that prefixes are part of instruction options. +//! When a member function that involves adding a prefix is called the prefix +//! is combined with existing instruction options, which will affect the next +//! instruction generated. +//! +//! ### Generating AVX512 code. +//! +//! x86::Assembler can generate AVX512+ code including the use of opmask +//! registers. Opmask can be specified through \ref x86::Assembler::k() +//! function, which stores it as an extra register, which will be used +//! by the next instruction. AsmJit uses such concept for manipulating +//! instruction options as well. +//! +//! The following AVX512 features are supported: +//! +//! - Opmask selector {k} and zeroing {z}. +//! - Rounding modes {rn|rd|ru|rz} and suppress-all-exceptions {sae} option. +//! - AVX512 broadcasts {1toN}. +//! +//! The following example demonstrates how AVX512 features can be used: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void generateAVX512Code(x86::Assembler& a) { +//! using namespace x86; +//! +//! // Opmask Selectors +//! // ---------------- +//! // +//! // - Opmask / zeroing is part of the instruction options / extraReg. +//! // - k(reg) is like {kreg} in Intel syntax. +//! // - z() is like {z} in Intel syntax. +//! +//! // vaddpd zmm {k1} {z}, zmm1, zmm2 +//! a.k(k1).z().vaddpd(zmm0, zmm1, zmm2); +//! +//! // Memory Broadcasts +//! // ----------------- +//! // +//! // - Broadcast data is part of memory operand. +//! // - Use x86::Mem::_1toN(), which returns a new x86::Mem operand. +//! +//! // vaddpd zmm0 {k1} {z}, zmm1, [rcx] {1to8} +//! a.k(k1).z().vaddpd(zmm0, zmm1, x86::mem(rcx)._1to8()); +//! +//! // Embedded Rounding & Suppress-All-Exceptoins +//! // ------------------------------------------- +//! // +//! // - Rounding mode and {sae} are part of instruction options. +//! // - Use sae() to enable exception suppression. +//! // - Use rn_sae(), rd_sae(), ru_sae(), and rz_sae() - to enable rounding. +//! // - Embedded rounding implicitly sets {sae} as well, that's why the API +//! // also has sae() suffix, to make it clear. +//! +//! // vcmppd k1, zmm1, zmm2, 0x00 {sae} +//! a.sae().vcmppd(k1, zmm1, zmm2, 0); +//! +//! // vaddpd zmm0, zmm1, zmm2 {rz} +//! a.rz_sae().vaddpd(zmm0, zmm1, zmm2); +//! } +//! ``` class ASMJIT_VIRTAPI Assembler : public BaseAssembler, public EmitterImplicitT<Assembler> { @@ -69,12 +712,10 @@ public: //! \} //! \endcond - //! \cond INTERNAL //! \name Emit //! \{ - using BaseEmitter::_emit; - ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) override; + ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) override; //! \} //! \endcond diff --git a/3rdparty/asmjit/src/asmjit/x86/x86builder.cpp b/3rdparty/asmjit/src/asmjit/x86/x86builder.cpp index 4e65c7b16b5..b3c0b261a0b 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86builder.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86builder.cpp @@ -46,6 +46,8 @@ Builder::~Builder() noexcept {} Error Builder::finalize() { ASMJIT_PROPAGATE(runPasses()); Assembler a(_code); + a.addEncodingOptions(encodingOptions()); + a.addValidationOptions(validationOptions()); return serialize(&a); } @@ -54,13 +56,13 @@ Error Builder::finalize() { // ============================================================================ Error Builder::onAttach(CodeHolder* code) noexcept { - uint32_t archId = code->archId(); - if (!ArchInfo::isX86Family(archId)) + uint32_t arch = code->arch(); + if (!Environment::isFamilyX86(arch)) return DebugUtils::errored(kErrorInvalidArch); ASMJIT_PROPAGATE(Base::onAttach(code)); - _gpRegInfo.setSignature(archId == ArchInfo::kIdX86 ? uint32_t(Gpd::kSignature) : uint32_t(Gpq::kSignature)); + _gpRegInfo.setSignature(Environment::is32Bit(arch) ? uint32_t(Gpd::kSignature) : uint32_t(Gpq::kSignature)); return kErrorOk; } diff --git a/3rdparty/asmjit/src/asmjit/x86/x86builder.h b/3rdparty/asmjit/src/asmjit/x86/x86builder.h index 66e2dfc99d8..256bc9ecbec 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86builder.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86builder.h @@ -40,7 +40,315 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // [asmjit::x86::Builder] // ============================================================================ -//! Architecture-dependent asm-builder (X86). +//! X86/X64 builder implementation. +//! +//! The code representation used by \ref BaseBuilder is compatible with everything +//! AsmJit provides. Each instruction is stored as \ref InstNode, which contains +//! instruction id, options, and operands. Each instruction emitted will create +//! a new \ref InstNode instance and add it to the current cursor in the double-linked +//! list of nodes. Since the instruction stream used by \ref BaseBuilder can be +//! manipulated, we can rewrite the SumInts example from \ref asmjit_assembler +//! into the following: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); +//! +//! // Small helper function to print the current content of `cb`. +//! static void dumpCode(BaseBuilder& builder, const char* phase) { +//! String sb; +//! builder.dump(sb); +//! printf("%s:\n%s\n", phase, sb.data()); +//! } +//! +//! int main() { +//! JitRuntime rt; // Create JIT Runtime. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Builder cb(&code); // Create and attach x86::Builder to `code`. +//! +//! // Decide which registers will be mapped to function arguments. Try changing +//! // registers of `dst`, `srcA`, and `srcB` and see what happens in function's +//! // prolog and epilog. +//! x86::Gp dst = cb.zax(); +//! x86::Gp srcA = cb.zcx(); +//! x86::Gp srcB = cb.zdx(); +//! +//! X86::Xmm vec0 = x86::xmm0; +//! X86::Xmm vec1 = x86::xmm1; +//! +//! // Create and initialize `FuncDetail`. +//! FuncDetail func; +//! func.init(FuncSignatureT<void, int*, const int*, const int*>(CallConv::kIdHost)); +//! +//! // Remember prolog insertion point. +//! BaseNode* prologInsertionPoint = cb.cursor(); +//! +//! // Emit function body: +//! cb.movdqu(vec0, x86::ptr(srcA)); // Load 4 ints from [srcA] to XMM0. +//! cb.movdqu(vec1, x86::ptr(srcB)); // Load 4 ints from [srcB] to XMM1. +//! cb.paddd(vec0, vec1); // Add 4 ints in XMM1 to XMM0. +//! cb.movdqu(x86::ptr(dst), vec0); // Store the result to [dst]. +//! +//! // Remember epilog insertion point. +//! BaseNode* epilogInsertionPoint = cb.cursor(); +//! +//! // Let's see what we have now. +//! dumpCode(cb, "Raw Function"); +//! +//! // Now, after we emitted the function body, we can insert the prolog, arguments +//! // allocation, and epilog. This is not possible with using pure x86::Assembler. +//! FuncFrame frame; +//! frame.init(func); +//! +//! // Make XMM0 and XMM1 dirty; `kGroupVec` describes XMM|YMM|ZMM registers. +//! frame.setDirtyRegs(x86::Reg::kGroupVec, IntUtils::mask(0, 1)); +//! +//! FuncArgsAssignment args(&func); // Create arguments assignment context. +//! args.assignAll(dst, srcA, srcB); // Assign our registers to arguments. +//! args.updateFrame(frame); // Reflect our args in FuncFrame. +//! frame.finalize(); // Finalize the FuncFrame (updates it). +//! +//! // Insert function prolog and allocate arguments to registers. +//! cb.setCursor(prologInsertionPoint); +//! cb.emitProlog(frame); +//! cb.emitArgsAssignment(frame, args); +//! +//! // Insert function epilog. +//! cb.setCursor(epilogInsertionPoint); +//! cb.emitEpilog(frame); +//! +//! // Let's see how the function's prolog and epilog looks. +//! dumpCode(cb, "Prolog & Epilog"); +//! +//! // IMPORTANT: Builder requires finalize() to be called to serialize its +//! // code to the Assembler (it automatically creates one if not attached). +//! cb.finalize(); +//! +//! SumIntsFunc fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error case. +//! +//! // Execute the generated function. +//! int inA[4] = { 4, 3, 2, 1 }; +//! int inB[4] = { 1, 5, 2, 8 }; +//! int out[4]; +//! fn(out, inA, inB); +//! +//! // Prints {5 8 4 9} +//! printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); +//! +//! rt.release(fn); // Explicitly remove the function from the runtime. +//! return 0; +//! } +//! ``` +//! +//! When the example is executed it should output the following (this one using +//! AMD64-SystemV ABI): +//! +//! ``` +//! Raw Function: +//! movdqu xmm0, [rcx] +//! movdqu xmm1, [rdx] +//! paddd xmm0, xmm1 +//! movdqu [rax], xmm0 +//! +//! Prolog & Epilog: +//! mov rax, rdi +//! mov rcx, rsi +//! movdqu xmm0, [rcx] +//! movdqu xmm1, [rdx] +//! paddd xmm0, xmm1 +//! movdqu [rax], xmm0 +//! ret +//! +//! {5 8 4 9} +//! ``` +//! +//! The number of use-cases of \ref BaseBuilder is not limited and highly depends +//! on your creativity and experience. The previous example can be easily improved +//! to collect all dirty registers inside the function programmatically and to pass +//! them to \ref FuncFrame::setDirtyRegs(). +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! // NOTE: This function doesn't cover all possible constructs. It ignores +//! // instructions that write to implicit registers that are not part of the +//! // operand list. It also counts read-only registers. Real implementation +//! // would be a bit more complicated, but still relatively easy to implement. +//! static void collectDirtyRegs(const BaseNode* first, +//! const BaseNode* last, +//! uint32_t regMask[BaseReg::kGroupVirt]) { +//! const BaseNode* node = first; +//! while (node) { +//! if (node->actsAsInst()) { +//! const InstNode* inst = node->as<InstNode>(); +//! const Operand* opArray = inst->operands(); +//! +//! for (uint32_t i = 0, opCount = inst->opCount(); i < opCount; i++) { +//! const Operand& op = opArray[i]; +//! if (op.isReg()) { +//! const x86::Reg& reg = op.as<x86::Reg>(); +//! if (reg.group() < BaseReg::kGroupVirt) { +//! regMask[reg.group()] |= 1u << reg.id(); +//! } +//! } +//! } +//! } +//! +//! if (node == last) +//! break; +//! node = node->next(); +//! } +//! } +//! +//! static void setDirtyRegsOfFuncFrame(const x86::Builder& builder, FuncFrame& frame) { +//! uint32_t regMask[BaseReg::kGroupVirt] {}; +//! collectDirtyRegs(builder.firstNode(), builder.lastNode(), regMask); +//! +//! // X86/X64 ABIs only require to save GP/XMM registers: +//! frame.setDirtyRegs(x86::Reg::kGroupGp , regMask[x86::Reg::kGroupGp ]); +//! frame.setDirtyRegs(x86::Reg::kGroupVec, regMask[x86::Reg::kGroupVec]); +//! } +//! ``` +//! +//! ### Casting Between Various Emitters +//! +//! Even when \ref BaseAssembler and \ref BaseBuilder provide the same interface +//! as defined by \ref BaseEmitter their platform dependent variants like \ref +//! x86::Assembler and \ref x86::Builder cannot be interchanged or casted +//! to each other by using a C++ `static_cast<>`. The main reason is the +//! inheritance graph of these classes is different and cast-incompatible, as +//! illustrated below: +//! +//! ``` +//! +--------------+ +=========================+ +//! +----------------------->| x86::Emitter |<--+--# x86::EmitterImplicitT<> #<--+ +//! | +--------------+ | +=========================+ | +//! | (abstract) | (mixin) | +//! | +--------------+ +~~~~~~~~~~~~~~+ | | +//! +-->| BaseAssembler|---->|x86::Assembler|<--+ | +//! | +--------------+ +~~~~~~~~~~~~~~+ | | +//! | (abstract) (final) | | +//! +===============+ | +--------------+ +~~~~~~~~~~~~~~+ | | +//! # BaseEmitter #--+-->| BaseBuilder |--+->| x86::Builder |<--+ | +//! +===============+ +--------------+ | +~~~~~~~~~~~~~~+ | +//! (abstract) (abstract) | (final) | +//! +---------------------+ | +//! | | +//! | +--------------+ +~~~~~~~~~~~~~~+ +=========================+ | +//! +-->| BaseCompiler |---->| x86::Compiler|<-----# x86::EmitterExplicitT<> #---+ +//! +--------------+ +~~~~~~~~~~~~~~+ +=========================+ +//! (abstract) (final) (mixin) +//! ``` +//! +//! The graph basically shows that it's not possible to cast between \ref +//! x86::Assembler and \ref x86::Builder. However, since both share the +//! base interface (\ref BaseEmitter) it's possible to cast them to a class +//! that cannot be instantiated, but defines the same interface - the class +//! is called \ref x86::Emitter and was introduced to make it possible to +//! write a function that can emit to both \ref x86::Assembler and \ref +//! x86::Builder. Note that \ref x86::Emitter cannot be created, it's abstract +//! and has private constructors and destructors; it was only designed to be +//! casted to and used as an interface. +//! +//! Each architecture-specific emitter implements a member function called +//! `as<arch::Emitter>()`, which casts the instance to the architecture +//! specific emitter as illustrated below: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! static void emitSomething(x86::Emitter* e) { +//! e->mov(x86::eax, x86::ebx); +//! } +//! +//! static void assemble(CodeHolder& code, bool useAsm) { +//! if (useAsm) { +//! x86::Assembler assembler(&code); +//! emitSomething(assembler.as<x86::Emitter>()); +//! } +//! else { +//! x86::Builder builder(&code); +//! emitSomething(builder.as<x86::Emitter>()); +//! +//! // NOTE: Builder requires `finalize()` to be called to serialize its +//! // content to Assembler (it automatically creates one if not attached). +//! builder.finalize(); +//! } +//! } +//! ``` +//! +//! The example above shows how to create a function that can emit code to +//! either \ref x86::Assembler or \ref x86::Builder through \ref x86::Emitter, +//! which provides emitter-neutral functionality. \ref x86::Emitter, however, +//! doesn't provide any emitter-specific functionality like `setCursor()`. +//! +//! ### Code Injection and Manipulation +//! +//! \ref BaseBuilder emitter stores its nodes in a double-linked list, which +//! makes it easy to manipulate that list during the code generation or +//! afterwards. Each node is always emitted next to the current cursor and the +//! cursor is advanced to that newly emitted node. The cursor can be retrieved +//! and changed by \ref BaseBuilder::cursor() and \ref BaseBuilder::setCursor(), +//! respectively. +//! +//! The example below demonstrates how to remember a node and inject something +//! next to it. +//! +//! ``` +//! static void example(x86::Builder& builder) { +//! // Emit something, after it returns the cursor would point at the last +//! // emitted node. +//! builder.mov(x86::rax, x86::rdx); // [1] +//! +//! // We can retrieve the node. +//! BaseNode* node = builder.cursor(); +//! +//! // Change the instruction we just emitted, just for fun... +//! if (node->isInst()) { +//! InstNode* inst = node->as<InstNode>(); +//! // Changes the operands at index [1] to RCX. +//! inst->setOp(1, x86::rcx); +//! } +//! +//! // ------------------------- Generate Some Code ------------------------- +//! builder.add(x86::rax, x86::rdx); // [2] +//! builder.shr(x86::rax, 3); // [3] +//! // ---------------------------------------------------------------------- +//! +//! // Now, we know where our node is, and we can simply change the cursor +//! // and start emitting something after it. The setCursor() function +//! // returns the previous cursor, and it's always a good practice to remember +//! // it, because you never know if you are not already injecting the code +//! // somewhere else... +//! BaseNode* oldCursor = builder.setCursor(node); +//! +//! builder.mul(x86::rax, 8); // [4] +//! +//! // Restore the cursor +//! builder.setCursor(oldCursor); +//! } +//! ``` +//! +//! The function above would actually emit the following: +//! +//! ``` +//! mov rax, rcx ; [1] Patched at the beginning. +//! mul rax, 8 ; [4] Injected. +//! add rax, rdx ; [2] Followed [1] initially. +//! shr rax, 3 ; [3] Follows [2]. +//! ``` class ASMJIT_VIRTAPI Builder : public BaseBuilder, public EmitterImplicitT<Builder> { diff --git a/3rdparty/asmjit/src/asmjit/x86/x86callconv.cpp b/3rdparty/asmjit/src/asmjit/x86/x86callconv.cpp index 7ec4c55ef0a..e0a3f213dfe 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86callconv.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86callconv.cpp @@ -33,13 +33,19 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // [asmjit::x86::CallConvInternal - Init] // ============================================================================ -static inline void CallConv_initX86Common(CallConv& cc) noexcept { - cc.setNaturalStackAlignment(4); - cc.setArchType(ArchInfo::kIdX86); - cc.setPreservedRegs(Reg::kGroupGp, Support::bitMask(Gp::kIdBx, Gp::kIdSp, Gp::kIdBp, Gp::kIdSi, Gp::kIdDi)); +namespace CallConvInternal { + +static inline bool shouldThreatAsCDeclIn64BitMode(uint32_t ccId) noexcept { + return ccId == CallConv::kIdCDecl || + ccId == CallConv::kIdStdCall || + ccId == CallConv::kIdThisCall || + ccId == CallConv::kIdFastCall || + ccId == CallConv::kIdRegParm1 || + ccId == CallConv::kIdRegParm2 || + ccId == CallConv::kIdRegParm3; } -ASMJIT_FAVOR_SIZE Error CallConvInternal::init(CallConv& cc, uint32_t ccId) noexcept { +ASMJIT_FAVOR_SIZE Error init(CallConv& cc, uint32_t ccId, const Environment& environment) noexcept { constexpr uint32_t kGroupGp = Reg::kGroupGp; constexpr uint32_t kGroupVec = Reg::kGroupVec; constexpr uint32_t kGroupMm = Reg::kGroupMm; @@ -54,110 +60,179 @@ ASMJIT_FAVOR_SIZE Error CallConvInternal::init(CallConv& cc, uint32_t ccId) noex constexpr uint32_t kZsi = Gp::kIdSi; constexpr uint32_t kZdi = Gp::kIdDi; - switch (ccId) { - case CallConv::kIdX86StdCall: - cc.setFlags(CallConv::kFlagCalleePopsStack); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86MsThisCall: - cc.setFlags(CallConv::kFlagCalleePopsStack); - cc.setPassedOrder(kGroupGp, kZcx); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86MsFastCall: - case CallConv::kIdX86GccFastCall: - cc.setFlags(CallConv::kFlagCalleePopsStack); - cc.setPassedOrder(kGroupGp, kZcx, kZdx); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86GccRegParm1: - cc.setPassedOrder(kGroupGp, kZax); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86GccRegParm2: - cc.setPassedOrder(kGroupGp, kZax, kZdx); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86GccRegParm3: - cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86CDecl: - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86Win64: - cc.setArchType(ArchInfo::kIdX64); - cc.setStrategy(CallConv::kStrategyWin64); - cc.setFlags(CallConv::kFlagPassFloatsByVec | CallConv::kFlagIndirectVecArgs); - cc.setNaturalStackAlignment(16); - cc.setSpillZoneSize(32); - cc.setPassedOrder(kGroupGp, kZcx, kZdx, 8, 9); - cc.setPassedOrder(kGroupVec, 0, 1, 2, 3); - cc.setPreservedRegs(kGroupGp, Support::bitMask(kZbx, kZsp, kZbp, kZsi, kZdi, 12, 13, 14, 15)); - cc.setPreservedRegs(kGroupVec, Support::bitMask(6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); - break; - - case CallConv::kIdX86SysV64: - cc.setArchType(ArchInfo::kIdX64); - cc.setFlags(CallConv::kFlagPassFloatsByVec); - cc.setNaturalStackAlignment(16); - cc.setRedZoneSize(128); - cc.setPassedOrder(kGroupGp, kZdi, kZsi, kZdx, kZcx, 8, 9); - cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); - cc.setPreservedRegs(kGroupGp, Support::bitMask(kZbx, kZsp, kZbp, 12, 13, 14, 15)); - break; - - case CallConv::kIdX86LightCall2: - case CallConv::kIdX86LightCall3: - case CallConv::kIdX86LightCall4: { - uint32_t n = (ccId - CallConv::kIdX86LightCall2) + 2; - - cc.setArchType(ArchInfo::kIdX86); - cc.setFlags(CallConv::kFlagPassFloatsByVec); - cc.setNaturalStackAlignment(16); - cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx, kZsi, kZdi); - cc.setPassedOrder(kGroupMm, 0, 1, 2, 3, 4, 5, 6, 7); - cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); - cc.setPassedOrder(kGroupKReg, 0, 1, 2, 3, 4, 5, 6, 7); - - cc.setPreservedRegs(kGroupGp , Support::lsbMask<uint32_t>(8)); - cc.setPreservedRegs(kGroupVec , Support::lsbMask<uint32_t>(8) & ~Support::lsbMask<uint32_t>(n)); - break; + bool winABI = environment.isPlatformWindows() || environment.isAbiMSVC(); + + cc.setArch(environment.arch()); + + if (environment.is32Bit()) { + bool isStandardCallConv = true; + + cc.setPreservedRegs(Reg::kGroupGp, Support::bitMask(Gp::kIdBx, Gp::kIdSp, Gp::kIdBp, Gp::kIdSi, Gp::kIdDi)); + cc.setNaturalStackAlignment(4); + + switch (ccId) { + case CallConv::kIdCDecl: + break; + + case CallConv::kIdStdCall: + cc.setFlags(CallConv::kFlagCalleePopsStack); + break; + + case CallConv::kIdFastCall: + cc.setFlags(CallConv::kFlagCalleePopsStack); + cc.setPassedOrder(kGroupGp, kZcx, kZdx); + break; + + case CallConv::kIdVectorCall: + cc.setFlags(CallConv::kFlagCalleePopsStack); + cc.setPassedOrder(kGroupGp, kZcx, kZdx); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5); + break; + + case CallConv::kIdThisCall: + // NOTE: Even MINGW (starting with GCC 4.7.0) now uses __thiscall on MS Windows, + // so we won't bail to any other calling convention if __thiscall was specified. + if (winABI) { + cc.setFlags(CallConv::kFlagCalleePopsStack); + cc.setPassedOrder(kGroupGp, kZcx); + } + else { + ccId = CallConv::kIdCDecl; + } + break; + + case CallConv::kIdRegParm1: + cc.setPassedOrder(kGroupGp, kZax); + break; + + case CallConv::kIdRegParm2: + cc.setPassedOrder(kGroupGp, kZax, kZdx); + break; + + case CallConv::kIdRegParm3: + cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx); + break; + + case CallConv::kIdLightCall2: + case CallConv::kIdLightCall3: + case CallConv::kIdLightCall4: { + uint32_t n = (ccId - CallConv::kIdLightCall2) + 2; + + cc.setFlags(CallConv::kFlagPassFloatsByVec); + cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx, kZsi, kZdi); + cc.setPassedOrder(kGroupMm, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPassedOrder(kGroupKReg, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPreservedRegs(kGroupGp, Support::lsbMask<uint32_t>(8)); + cc.setPreservedRegs(kGroupVec, Support::lsbMask<uint32_t>(8) & ~Support::lsbMask<uint32_t>(n)); + + cc.setNaturalStackAlignment(16); + isStandardCallConv = false; + break; + } + + default: + return DebugUtils::errored(kErrorInvalidArgument); } - case CallConv::kIdX64LightCall2: - case CallConv::kIdX64LightCall3: - case CallConv::kIdX64LightCall4: { - uint32_t n = (ccId - CallConv::kIdX64LightCall2) + 2; - - cc.setArchType(ArchInfo::kIdX64); - cc.setFlags(CallConv::kFlagPassFloatsByVec); - cc.setNaturalStackAlignment(16); - cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx, kZsi, kZdi); - cc.setPassedOrder(kGroupMm, 0, 1, 2, 3, 4, 5, 6, 7); - cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); - cc.setPassedOrder(kGroupKReg, 0, 1, 2, 3, 4, 5, 6, 7); - - cc.setPreservedRegs(kGroupGp , Support::lsbMask<uint32_t>(16)); - cc.setPreservedRegs(kGroupVec ,~Support::lsbMask<uint32_t>(n)); - break; + if (isStandardCallConv) { + // MMX arguments is something where compiler vendors disagree. For example + // GCC and MSVC would pass first three via registers and the rest via stack, + // however Clang passes all via stack. Returning MMX registers is even more + // fun, where GCC uses MM0, but Clang uses EAX:EDX pair. I'm not sure it's + // something we should be worried about as MMX is deprecated anyway. + cc.setPassedOrder(kGroupMm, 0, 1, 2); + + // Vector arguments (XMM|YMM|ZMM) are passed via registers. However, if the + // function is variadic then they have to be passed via stack. + cc.setPassedOrder(kGroupVec, 0, 1, 2); + + // Functions with variable arguments always use stack for MM and vector + // arguments. + cc.addFlags(CallConv::kFlagPassVecByStackIfVA); } - default: - return DebugUtils::errored(kErrorInvalidArgument); + if (ccId == CallConv::kIdCDecl) { + cc.addFlags(CallConv::kFlagVarArgCompatible); + } + } + else { + // Preprocess the calling convention into a common id as many conventions + // are normally ignored even by C/C++ compilers and treated as `__cdecl`. + if (shouldThreatAsCDeclIn64BitMode(ccId)) + ccId = winABI ? CallConv::kIdX64Windows : CallConv::kIdX64SystemV; + + switch (ccId) { + case CallConv::kIdX64SystemV: { + cc.setFlags(CallConv::kFlagPassFloatsByVec | + CallConv::kFlagPassMmxByXmm | + CallConv::kFlagVarArgCompatible); + cc.setNaturalStackAlignment(16); + cc.setRedZoneSize(128); + cc.setPassedOrder(kGroupGp, kZdi, kZsi, kZdx, kZcx, 8, 9); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPreservedRegs(kGroupGp, Support::bitMask(kZbx, kZsp, kZbp, 12, 13, 14, 15)); + break; + } + + case CallConv::kIdX64Windows: { + cc.setStrategy(CallConv::kStrategyX64Windows); + cc.setFlags(CallConv::kFlagPassFloatsByVec | + CallConv::kFlagIndirectVecArgs | + CallConv::kFlagPassMmxByGp | + CallConv::kFlagVarArgCompatible); + cc.setNaturalStackAlignment(16); + // Maximum 4 arguments in registers, each adds 8 bytes to the spill zone. + cc.setSpillZoneSize(4 * 8); + cc.setPassedOrder(kGroupGp, kZcx, kZdx, 8, 9); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3); + cc.setPreservedRegs(kGroupGp, Support::bitMask(kZbx, kZsp, kZbp, kZsi, kZdi, 12, 13, 14, 15)); + cc.setPreservedRegs(kGroupVec, Support::bitMask(6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); + break; + } + + case CallConv::kIdVectorCall: { + cc.setStrategy(CallConv::kStrategyX64VectorCall); + cc.setFlags(CallConv::kFlagPassFloatsByVec | + CallConv::kFlagPassMmxByGp ); + cc.setNaturalStackAlignment(16); + // Maximum 6 arguments in registers, each adds 8 bytes to the spill zone. + cc.setSpillZoneSize(6 * 8); + cc.setPassedOrder(kGroupGp, kZcx, kZdx, 8, 9); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5); + cc.setPreservedRegs(kGroupGp, Support::bitMask(kZbx, kZsp, kZbp, kZsi, kZdi, 12, 13, 14, 15)); + cc.setPreservedRegs(kGroupVec, Support::bitMask(6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); + break; + } + + case CallConv::kIdLightCall2: + case CallConv::kIdLightCall3: + case CallConv::kIdLightCall4: { + uint32_t n = (ccId - CallConv::kIdLightCall2) + 2; + + cc.setFlags(CallConv::kFlagPassFloatsByVec); + cc.setNaturalStackAlignment(16); + cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx, kZsi, kZdi); + cc.setPassedOrder(kGroupMm, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPassedOrder(kGroupKReg, 0, 1, 2, 3, 4, 5, 6, 7); + + cc.setPreservedRegs(kGroupGp, Support::lsbMask<uint32_t>(16)); + cc.setPreservedRegs(kGroupVec, ~Support::lsbMask<uint32_t>(n)); + break; + } + + default: + return DebugUtils::errored(kErrorInvalidArgument); + } } cc.setId(ccId); return kErrorOk; } +} // {CallConvInternal} + ASMJIT_END_SUB_NAMESPACE #endif // ASMJIT_BUILD_X86 diff --git a/3rdparty/asmjit/src/asmjit/x86/x86callconv_p.h b/3rdparty/asmjit/src/asmjit/x86/x86callconv_p.h index 5fc21133cef..1607ea2e385 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86callconv_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86callconv_p.h @@ -38,9 +38,11 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! X86-specific function API (calling conventions and other utilities). namespace CallConvInternal { - //! Initialize `CallConv` structure (X86 specific). - Error init(CallConv& cc, uint32_t ccId) noexcept; -} + +//! Initialize `CallConv` structure (X86 specific). +Error init(CallConv& cc, uint32_t ccId, const Environment& environment) noexcept; + +} // {CallConvInternal} //! \} //! \endcond diff --git a/3rdparty/asmjit/src/asmjit/x86/x86compiler.cpp b/3rdparty/asmjit/src/asmjit/x86/x86compiler.cpp index 910ed5e7dde..33377e9f98b 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86compiler.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86compiler.cpp @@ -47,20 +47,24 @@ Compiler::~Compiler() noexcept {} Error Compiler::finalize() { ASMJIT_PROPAGATE(runPasses()); Assembler a(_code); + a.addEncodingOptions(encodingOptions()); + a.addValidationOptions(validationOptions()); return serialize(&a); } - // ============================================================================ // [asmjit::x86::Compiler - Events] // ============================================================================ Error Compiler::onAttach(CodeHolder* code) noexcept { - uint32_t archId = code->archId(); - if (!ArchInfo::isX86Family(archId)) + uint32_t arch = code->arch(); + if (!Environment::isFamilyX86(arch)) return DebugUtils::errored(kErrorInvalidArch); ASMJIT_PROPAGATE(Base::onAttach(code)); - _gpRegInfo.setSignature(archId == ArchInfo::kIdX86 ? uint32_t(Gpd::kSignature) : uint32_t(Gpq::kSignature)); + + bool is32Bit = Environment::is32Bit(arch); + _gpRegInfo.setSignature(is32Bit ? uint32_t(Gpd::kSignature) + : uint32_t(Gpq::kSignature)); Error err = addPassT<X86RAPass>(); if (ASMJIT_UNLIKELY(err)) { diff --git a/3rdparty/asmjit/src/asmjit/x86/x86compiler.h b/3rdparty/asmjit/src/asmjit/x86/x86compiler.h index cc7035b2990..4c64b3b6e40 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86compiler.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86compiler.h @@ -41,7 +41,413 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // [asmjit::x86::Compiler] // ============================================================================ -//! Architecture-dependent asm-compiler (X86). +//! X86/X64 compiler implementation. +//! +//! ### Compiler Basics +//! +//! The first \ref x86::Compiler example shows how to generate a function that +//! simply returns an integer value. It's an analogy to the first Assembler example: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef int (*Func)(void); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! CodeHolder code; // Holds code and relocation information. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. +//! +//! cc.addFunc(FuncSignatureT<int>());// Begin a function of `int fn(void)` signature. +//! +//! x86::Gp vReg = cc.newGpd(); // Create a 32-bit general purpose register. +//! cc.mov(vReg, 1); // Move one to our virtual register `vReg`. +//! cc.ret(vReg); // Return `vReg` from the function. +//! +//! cc.endFunc(); // End of the function body. +//! cc.finalize(); // Translate and assemble the whole 'cc' content. +//! // ----> x86::Compiler is no longer needed from here and can be destroyed <---- +//! +//! Func fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ----> CodeHolder is no longer needed from here and can be destroyed <---- +//! +//! int result = fn(); // Execute the generated code. +//! printf("%d\n", result); // Print the resulting "1". +//! +//! rt.release(fn); // Explicitly remove the function from the runtime. +//! return 0; +//! } +//! ``` +//! +//! The \ref BaseCompiler::addFunc() and \ref BaseCompiler::endFunc() functions +//! are used to define the function and its end. Both must be called per function, +//! but the body doesn't have to be generated in sequence. An example of generating +//! two functions will be shown later. The next example shows more complicated code +//! that contain a loop and generates a simple memory copy function that uses +//! `uint32_t` items: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef void (*MemCpy32)(uint32_t* dst, const uint32_t* src, size_t count); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! CodeHolder code; // Holds code and relocation information. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. +//! +//! cc.addFunc( // Begin the function of the following signature: +//! FuncSignatureT<void, // Return value - void (no return value). +//! uint32_t*, // 1st argument - uint32_t* (machine reg-size). +//! const uint32_t*, // 2nd argument - uint32_t* (machine reg-size). +//! size_t>()); // 3rd argument - size_t (machine reg-size). +//! +//! Label L_Loop = cc.newLabel(); // Start of the loop. +//! Label L_Exit = cc.newLabel(); // Used to exit early. +//! +//! x86::Gp dst = cc.newIntPtr("dst");// Create `dst` register (destination pointer). +//! x86::Gp src = cc.newIntPtr("src");// Create `src` register (source pointer). +//! x86::Gp i = cc.newUIntPtr("i"); // Create `i` register (loop counter). +//! +//! cc.setArg(0, dst); // Assign `dst` argument. +//! cc.setArg(1, src); // Assign `src` argument. +//! cc.setArg(2, i); // Assign `i` argument. +//! +//! cc.test(i, i); // Early exit if length is zero. +//! cc.jz(L_Exit); +//! +//! cc.bind(L_Loop); // Bind the beginning of the loop here. +//! +//! x86::Gp tmp = cc.newInt32("tmp"); // Copy a single dword (4 bytes). +//! cc.mov(tmp, x86::dword_ptr(src)); // Load DWORD from [src] address. +//! cc.mov(x86::dword_ptr(dst), tmp); // Store DWORD to [dst] address. +//! +//! cc.add(src, 4); // Increment `src`. +//! cc.add(dst, 4); // Increment `dst`. +//! +//! cc.dec(i); // Loop until `i` is non-zero. +//! cc.jnz(L_Loop); +//! +//! cc.bind(L_Exit); // Label used by early exit. +//! cc.endFunc(); // End of the function body. +//! +//! cc.finalize(); // Translate and assemble the whole 'cc' content. +//! // ----> x86::Compiler is no longer needed from here and can be destroyed <---- +//! +//! // Add the generated code to the runtime. +//! MemCpy32 memcpy32; +//! Error err = rt.add(&memcpy32, &code); +//! +//! // Handle a possible error returned by AsmJit. +//! if (err) +//! return 1; +//! // ----> CodeHolder is no longer needed from here and can be destroyed <---- +//! +//! // Test the generated code. +//! uint32_t input[6] = { 1, 2, 3, 5, 8, 13 }; +//! uint32_t output[6]; +//! memcpy32(output, input, 6); +//! +//! for (uint32_t i = 0; i < 6; i++) +//! printf("%d\n", output[i]); +//! +//! rt.release(memcpy32); +//! return 0; +//! } +//! ``` +//! +//! ### Recursive Functions +//! +//! It's possible to create more functions by using the same \ref x86::Compiler +//! instance and make links between them. In such case it's important to keep +//! the pointer to \ref FuncNode. +//! +//! The example below creates a simple Fibonacci function that calls itself recursively: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef uint32_t (*Fibonacci)(uint32_t x); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! CodeHolder code; // Holds code and relocation information. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. +//! +//! FuncNode* func = cc.addFunc( // Begin of the Fibonacci function, addFunc() +//! FuncSignatureT<int, int>()); // Returns a pointer to the FuncNode node. +//! +//! Label L_Exit = cc.newLabel() // Exit label. +//! x86::Gp x = cc.newU32(); // Function x argument. +//! x86::Gp y = cc.newU32(); // Temporary. +//! +//! cc.setArg(0, x); +//! +//! cc.cmp(x, 3); // Return x if less than 3. +//! cc.jb(L_Exit); +//! +//! cc.mov(y, x); // Make copy of the original x. +//! cc.dec(x); // Decrease x. +//! +//! InvokeNode* invokeNode; // Function invocation: +//! cc.invoke(&invokeNode, // - InvokeNode (output). +//! func->label(), // - Function address or Label. +//! FuncSignatureT<int, int>()); // - Function signature. +//! +//! invokeNode->setArg(0, x); // Assign x as the first argument. +//! invokeNode->setRet(0, x); // Assign x as a return value as well. +//! +//! cc.add(x, y); // Combine the return value with y. +//! +//! cc.bind(L_Exit); +//! cc.ret(x); // Return x. +//! cc.endFunc(); // End of the function body. +//! +//! cc.finalize(); // Translate and assemble the whole 'cc' content. +//! // ----> x86::Compiler is no longer needed from here and can be destroyed <---- +//! +//! Fibonacci fib; +//! Error err = rt.add(&fib, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ----> CodeHolder is no longer needed from here and can be destroyed <---- +//! +//! // Test the generated code. +//! printf("Fib(%u) -> %u\n", 8, fib(8)); +//! +//! rt.release(fib); +//! return 0; +//! } +//! ``` +//! +//! ### Stack Management +//! +//! Function's stack-frame is managed automatically, which is used by the register allocator to spill virtual registers. It also provides an interface to allocate user-defined block of the stack, which can be used as a temporary storage by the generated function. In the following example a stack of 256 bytes size is allocated, filled by bytes starting from 0 to 255 and then iterated again to sum all the values. +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef int (*Func)(void); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! CodeHolder code; // Holds code and relocation information. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. +//! +//! cc.addFunc(FuncSignatureT<int>());// Create a function that returns int. +//! +//! x86::Gp p = cc.newIntPtr("p"); +//! x86::Gp i = cc.newIntPtr("i"); +//! +//! // Allocate 256 bytes on the stack aligned to 4 bytes. +//! x86::Mem stack = cc.newStack(256, 4); +//! +//! x86::Mem stackIdx(stack); // Copy of stack with i added. +//! stackIdx.setIndex(i); // stackIdx <- stack[i]. +//! stackIdx.setSize(1); // stackIdx <- byte ptr stack[i]. +//! +//! // Load a stack address to `p`. This step is purely optional and shows +//! // that `lea` is useful to load a memory operands address (even absolute) +//! // to a general purpose register. +//! cc.lea(p, stack); +//! +//! // Clear i (xor is a C++ keyword, hence 'xor_' is used instead). +//! cc.xor_(i, i); +//! +//! Label L1 = cc.newLabel(); +//! Label L2 = cc.newLabel(); +//! +//! cc.bind(L1); // First loop, fill the stack. +//! cc.mov(stackIdx, i.r8()); // stack[i] = uint8_t(i). +//! +//! cc.inc(i); // i++; +//! cc.cmp(i, 256); // if (i < 256) +//! cc.jb(L1); // goto L1; +//! +//! // Second loop, sum all bytes stored in `stack`. +//! x86::Gp sum = cc.newI32("sum"); +//! x86::Gp val = cc.newI32("val"); +//! +//! cc.xor_(i, i); +//! cc.xor_(sum, sum); +//! +//! cc.bind(L2); +//! +//! cc.movzx(val, stackIdx); // val = uint32_t(stack[i]); +//! cc.add(sum, val); // sum += val; +//! +//! cc.inc(i); // i++; +//! cc.cmp(i, 256); // if (i < 256) +//! cc.jb(L2); // goto L2; +//! +//! cc.ret(sum); // Return the `sum` of all values. +//! cc.endFunc(); // End of the function body. +//! +//! cc.finalize(); // Translate and assemble the whole 'cc' content. +//! // ----> x86::Compiler is no longer needed from here and can be destroyed <---- +//! +//! Func func; +//! Error err = rt.add(&func, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ----> CodeHolder is no longer needed from here and can be destroyed <---- +//! +//! printf("Func() -> %d\n", func()); // Test the generated code. +//! +//! rt.release(func); +//! return 0; +//! } +//! ``` +//! +//! ### Constant Pool +//! +//! Compiler provides two constant pools for a general purpose code generation: +//! +//! - Local constant pool - Part of \ref FuncNode, can be only used by a +//! single function and added after the function epilog sequence (after +//! `ret` instruction). +//! +//! - Global constant pool - Part of \ref BaseCompiler, flushed at the end +//! of the generated code by \ref BaseEmitter::finalize(). +//! +//! The example below illustrates how a built-in constant pool can be used: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! static void exampleUseOfConstPool(x86::Compiler& cc) { +//! cc.addFunc(FuncSignatureT<int>()); +//! +//! x86::Gp v0 = cc.newGpd("v0"); +//! x86::Gp v1 = cc.newGpd("v1"); +//! +//! x86::Mem c0 = cc.newInt32Const(ConstPool::kScopeLocal, 200); +//! x86::Mem c1 = cc.newInt32Const(ConstPool::kScopeLocal, 33); +//! +//! cc.mov(v0, c0); +//! cc.mov(v1, c1); +//! cc.add(v0, v1); +//! +//! cc.ret(v0); +//! cc.endFunc(); +//! } +//! ``` +//! +//! ### Jump Tables +//! +//! x86::Compiler supports `jmp` instruction with reg/mem operand, which is a +//! commonly used pattern to implement indirect jumps within a function, for +//! example to implement `switch()` statement in a programming languages. By +//! default AsmJit assumes that every basic block can be a possible jump +//! target as it's unable to deduce targets from instruction's operands. This +//! is a very pessimistic default that should be avoided if possible as it's +//! costly and very unfriendly to liveness analysis and register allocation. +//! +//! Instead of relying on such pessimistic default behavior, let's use \ref +//! JumpAnnotation to annotate a jump where all targets are known: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! static void exampleUseOfIndirectJump(x86::Compiler& cc) { +//! cc.addFunc(FuncSignatureT<float, float, float, uint32_t>(CallConv::kIdHost)); +//! +//! // Function arguments +//! x86::Xmm a = cc.newXmmSs("a"); +//! x86::Xmm b = cc.newXmmSs("b"); +//! x86::Gp op = cc.newUInt32("op"); +//! +//! x86::Gp target = cc.newIntPtr("target"); +//! x86::Gp offset = cc.newIntPtr("offset"); +//! +//! Label L_Table = cc.newLabel(); +//! Label L_Add = cc.newLabel(); +//! Label L_Sub = cc.newLabel(); +//! Label L_Mul = cc.newLabel(); +//! Label L_Div = cc.newLabel(); +//! Label L_End = cc.newLabel(); +//! +//! cc.setArg(0, a); +//! cc.setArg(1, b); +//! cc.setArg(2, op); +//! +//! // Jump annotation is a building block that allows to annotate all +//! // possible targets where `jmp()` can jump. It then drives the CFG +//! // contruction and liveness analysis, which impacts register allocation. +//! JumpAnnotation* annotation = cc.newJumpAnnotation(); +//! annotation->addLabel(L_Add); +//! annotation->addLabel(L_Sub); +//! annotation->addLabel(L_Mul); +//! annotation->addLabel(L_Div); +//! +//! // Most likely not the common indirect jump approach, but it +//! // doesn't really matter how final address is calculated. The +//! // most important path using JumpAnnotation with `jmp()`. +//! cc.lea(offset, x86::ptr(L_Table)); +//! if (cc.is64Bit()) +//! cc.movsxd(target, x86::dword_ptr(offset, op.cloneAs(offset), 2)); +//! else +//! cc.mov(target, x86::dword_ptr(offset, op.cloneAs(offset), 2)); +//! cc.add(target, offset); +//! cc.jmp(target, annotation); +//! +//! // Acts like a switch() statement in C. +//! cc.bind(L_Add); +//! cc.addss(a, b); +//! cc.jmp(L_End); +//! +//! cc.bind(L_Sub); +//! cc.subss(a, b); +//! cc.jmp(L_End); +//! +//! cc.bind(L_Mul); +//! cc.mulss(a, b); +//! cc.jmp(L_End); +//! +//! cc.bind(L_Div); +//! cc.divss(a, b); +//! +//! cc.bind(L_End); +//! cc.ret(a); +//! +//! cc.endFunc(); +//! +//! // Relative int32_t offsets of `L_XXX - L_Table`. +//! cc.bind(L_Table); +//! cc.embedLabelDelta(L_Add, L_Table, 4); +//! cc.embedLabelDelta(L_Sub, L_Table, 4); +//! cc.embedLabelDelta(L_Mul, L_Table, 4); +//! cc.embedLabelDelta(L_Div, L_Table, 4); +//! } +//! ``` class ASMJIT_VIRTAPI Compiler : public BaseCompiler, public EmitterExplicitT<Compiler> { @@ -62,18 +468,18 @@ public: #ifndef ASMJIT_NO_LOGGING # define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \ - _newRegFmt(OUT, PARAM, FORMAT, ARGS) + _newRegFmt(&OUT, PARAM, FORMAT, ARGS) #else # define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \ DebugUtils::unused(FORMAT); \ DebugUtils::unused(std::forward<Args>(args)...); \ - _newReg(OUT, PARAM) + _newReg(&OUT, PARAM) #endif #define ASMJIT_NEW_REG_CUSTOM(FUNC, REG) \ inline REG FUNC(uint32_t typeId) { \ REG reg(Globals::NoInit); \ - _newReg(reg, typeId); \ + _newReg(®, typeId); \ return reg; \ } \ \ @@ -87,7 +493,7 @@ public: #define ASMJIT_NEW_REG_TYPED(FUNC, REG, TYPE_ID) \ inline REG FUNC() { \ REG reg(Globals::NoInit); \ - _newReg(reg, TYPE_ID); \ + _newReg(®, TYPE_ID); \ return reg; \ } \ \ @@ -170,7 +576,7 @@ public: //! Creates a new memory chunk allocated on the current function's stack. inline Mem newStack(uint32_t size, uint32_t alignment, const char* name = nullptr) { Mem m(Globals::NoInit); - _newStack(m, size, alignment, name); + _newStack(&m, size, alignment, name); return m; } @@ -182,7 +588,7 @@ public: //! Put data to a constant-pool and get a memory reference to it. inline Mem newConst(uint32_t scope, const void* data, size_t size) { Mem m(Globals::NoInit); - _newConst(m, scope, data, size); + _newConst(&m, scope, data, size); return m; } @@ -213,12 +619,16 @@ public: //! Put a DP-FP `val` to a constant-pool. inline Mem newDoubleConst(uint32_t scope, double val) noexcept { return newConst(scope, &val, 8); } - //! Put a MMX `val` to a constant-pool. +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("newMmConst() uses a deprecated Data64, use newConst() with your own data instead") inline Mem newMmConst(uint32_t scope, const Data64& val) noexcept { return newConst(scope, &val, 8); } - //! Put a XMM `val` to a constant-pool. + + ASMJIT_DEPRECATED("newXmmConst() uses a deprecated Data128, use newConst() with your own data instead") inline Mem newXmmConst(uint32_t scope, const Data128& val) noexcept { return newConst(scope, &val, 16); } - //! Put a YMM `val` to a constant-pool. + + ASMJIT_DEPRECATED("newYmmConst() uses a deprecated Data256, use newConst() with your own data instead") inline Mem newYmmConst(uint32_t scope, const Data256& val) noexcept { return newConst(scope, &val, 32); } +#endif // !ASMJIT_NO_DEPRECATED //! \} @@ -235,16 +645,37 @@ public: //! \name Function Call & Ret Intrinsics //! \{ - //! Call a function. - inline FuncCallNode* call(const Gp& target, const FuncSignature& sign) { return addCall(Inst::kIdCall, target, sign); } + //! Invoke a function call without `target` type enforcement. + inline Error invoke_(InvokeNode** out, const Operand_& target, const FuncSignature& signature) { + return _addInvokeNode(out, Inst::kIdCall, target, signature); + } + + //! Invoke a function call of the given `target` and `signature` and store + //! the added node to `out`. + //! + //! Creates a new \ref InvokeNode, initializes all the necessary members to + //! match the given function `signature`, adds the node to the compiler, and + //! stores its pointer to `out`. The operation is atomic, if anything fails + //! nullptr is stored in `out` and error code is returned. + inline Error invoke(InvokeNode** out, const Gp& target, const FuncSignature& signature) { return invoke_(out, target, signature); } //! \overload - inline FuncCallNode* call(const Mem& target, const FuncSignature& sign) { return addCall(Inst::kIdCall, target, sign); } + inline Error invoke(InvokeNode** out, const Mem& target, const FuncSignature& signature) { return invoke_(out, target, signature); } //! \overload - inline FuncCallNode* call(const Label& target, const FuncSignature& sign) { return addCall(Inst::kIdCall, target, sign); } + inline Error invoke(InvokeNode** out, const Label& target, const FuncSignature& signature) { return invoke_(out, target, signature); } //! \overload - inline FuncCallNode* call(const Imm& target, const FuncSignature& sign) { return addCall(Inst::kIdCall, target, sign); } + inline Error invoke(InvokeNode** out, const Imm& target, const FuncSignature& signature) { return invoke_(out, target, signature); } //! \overload - inline FuncCallNode* call(uint64_t target, const FuncSignature& sign) { return addCall(Inst::kIdCall, Imm(int64_t(target)), sign); } + inline Error invoke(InvokeNode** out, uint64_t target, const FuncSignature& signature) { return invoke_(out, Imm(int64_t(target)), signature); } + +#ifndef _DOXYGEN + template<typename Target> + ASMJIT_DEPRECATED("Use invoke() instead of call()") + inline InvokeNode* call(const Target& target, const FuncSignature& signature) { + InvokeNode* invokeNode; + invoke(&invokeNode, target, signature); + return invokeNode; + } +#endif //! Return. inline FuncRetNode* ret() { return addRet(Operand(), Operand()); } @@ -260,7 +691,9 @@ public: using EmitterExplicitT<Compiler>::jmp; + //! Adds a jump to the given `target` with the provided jump `annotation`. inline Error jmp(const BaseReg& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdJmp, target, annotation); } + //! \overload inline Error jmp(const BaseMem& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdJmp, target, annotation); } //! \} diff --git a/3rdparty/asmjit/src/asmjit/x86/x86emitter.h b/3rdparty/asmjit/src/asmjit/x86/x86emitter.h index cfd96a18809..561acdd6000 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86emitter.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86emitter.h @@ -39,10 +39,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define ASMJIT_INST_1i(NAME, ID, T0) \ inline Error NAME(const T0& o0) { return _emitter()->emit(Inst::kId##ID, o0); } \ + /** \cond */ \ inline Error NAME(int o0) { return _emitter()->emit(Inst::kId##ID, Support::asInt(o0)); } \ inline Error NAME(unsigned int o0) { return _emitter()->emit(Inst::kId##ID, Support::asInt(o0)); } \ inline Error NAME(int64_t o0) { return _emitter()->emit(Inst::kId##ID, Support::asInt(o0)); } \ - inline Error NAME(uint64_t o0) { return _emitter()->emit(Inst::kId##ID, Support::asInt(o0)); } + inline Error NAME(uint64_t o0) { return _emitter()->emit(Inst::kId##ID, Support::asInt(o0)); } \ + /** \endcond */ #define ASMJIT_INST_1c(NAME, ID, CONV, T0) \ inline Error NAME(uint32_t cc, const T0& o0) { return _emitter()->emit(CONV(cc), o0); } \ @@ -82,10 +84,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define ASMJIT_INST_2i(NAME, ID, T0, T1) \ inline Error NAME(const T0& o0, const T1& o1) { return _emitter()->emit(Inst::kId##ID, o0, o1); } \ + /** \cond */ \ inline Error NAME(const T0& o0, int o1) { return _emitter()->emit(Inst::kId##ID, o0, Support::asInt(o1)); } \ inline Error NAME(const T0& o0, unsigned int o1) { return _emitter()->emit(Inst::kId##ID, o0, Support::asInt(o1)); } \ inline Error NAME(const T0& o0, int64_t o1) { return _emitter()->emit(Inst::kId##ID, o0, Support::asInt(o1)); } \ - inline Error NAME(const T0& o0, uint64_t o1) { return _emitter()->emit(Inst::kId##ID, o0, Support::asInt(o1)); } + inline Error NAME(const T0& o0, uint64_t o1) { return _emitter()->emit(Inst::kId##ID, o0, Support::asInt(o1)); } \ + /** \endcond */ #define ASMJIT_INST_2c(NAME, ID, CONV, T0, T1) \ inline Error NAME(uint32_t cc, const T0& o0, const T1& o1) { return _emitter()->emit(CONV(cc), o0, o1); } \ @@ -125,10 +129,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define ASMJIT_INST_3i(NAME, ID, T0, T1, T2) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2); } \ + /** \cond */ \ inline Error NAME(const T0& o0, const T1& o1, int o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, Support::asInt(o2)); } \ inline Error NAME(const T0& o0, const T1& o1, unsigned int o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, Support::asInt(o2)); } \ inline Error NAME(const T0& o0, const T1& o1, int64_t o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, Support::asInt(o2)); } \ - inline Error NAME(const T0& o0, const T1& o1, uint64_t o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, Support::asInt(o2)); } + inline Error NAME(const T0& o0, const T1& o1, uint64_t o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, Support::asInt(o2)); } \ + /** \endcond */ #define ASMJIT_INST_3ii(NAME, ID, T0, T1, T2) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2); } \ @@ -139,10 +145,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define ASMJIT_INST_4i(NAME, ID, T0, T1, T2, T3) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3); } \ + /** \cond */ \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, int o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, Support::asInt(o3)); } \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, unsigned int o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, Support::asInt(o3)); } \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, int64_t o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, Support::asInt(o3)); } \ - inline Error NAME(const T0& o0, const T1& o1, const T2& o2, uint64_t o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, Support::asInt(o3)); } + inline Error NAME(const T0& o0, const T1& o1, const T2& o2, uint64_t o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, Support::asInt(o3)); } \ + /** \endcond */ #define ASMJIT_INST_4ii(NAME, ID, T0, T1, T2, T3) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3); } \ @@ -153,10 +161,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define ASMJIT_INST_5i(NAME, ID, T0, T1, T2, T3, T4) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, const T4& o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, o4); } \ + /** \cond */ \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, int o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, Support::asInt(o4)); } \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, unsigned int o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, Support::asInt(o4)); } \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, int64_t o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, Support::asInt(o4)); } \ - inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, uint64_t o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, Support::asInt(o4)); } + inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, uint64_t o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, Support::asInt(o4)); } \ + /** \endcond */ #define ASMJIT_INST_6x(NAME, ID, T0, T1, T2, T3, T4, T5) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, const T4& o4, const T5& o5) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, o4, o5); } @@ -244,57 +254,57 @@ struct EmitterExplicitT { //! Creates an `intptr_t` memory operand depending on the current architecture. inline Mem intptr_ptr(const Gp& base, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Gp& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Label& base, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Label& base, const Gp& index, uint32_t shift, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Label& base, const Vec& index, uint32_t shift, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Rip& rip, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(rip, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(uint64_t base) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, nativeGpSize); } //! \overload inline Mem intptr_ptr(uint64_t base, const Gp& index, uint32_t shift = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, nativeGpSize); } //! \overload inline Mem intptr_ptr_abs(uint64_t base) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, nativeGpSize, BaseMem::kSignatureMemAbs); } //! \overload inline Mem intptr_ptr_abs(uint64_t base, const Gp& index, uint32_t shift = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, nativeGpSize, BaseMem::kSignatureMemAbs); } @@ -303,46 +313,55 @@ struct EmitterExplicitT { //! \name Embed //! \{ - //! Adds 8-bit integer data to the CodeBuffer. - inline Error db(uint8_t x) { return _emitter()->embed(&x, 1); } - //! Adds 16-bit integer data to the CodeBuffer. - inline Error dw(uint16_t x) { return _emitter()->embed(&x, 2); } - //! Adds 32-bit integer data to the CodeBuffer. - inline Error dd(uint32_t x) { return _emitter()->embed(&x, 4); } - //! Adds 64-bit integer data to the CodeBuffer. - inline Error dq(uint64_t x) { return _emitter()->embed(&x, 8); } - - //! Adds 8-bit integer data to the CodeBuffer. + //! Embeds 8-bit integer data. + inline Error db(uint8_t x, size_t repeatCount = 1) { return _emitter()->embedUInt8(x, repeatCount); } + //! Embeds 16-bit integer data. + inline Error dw(uint16_t x, size_t repeatCount = 1) { return _emitter()->embedUInt16(x, repeatCount); } + //! Embeds 32-bit integer data. + inline Error dd(uint32_t x, size_t repeatCount = 1) { return _emitter()->embedUInt32(x, repeatCount); } + //! Embeds 64-bit integer data. + inline Error dq(uint64_t x, size_t repeatCount = 1) { return _emitter()->embedUInt64(x, repeatCount); } + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use embedInt8() instead of dint8()") inline Error dint8(int8_t x) { return _emitter()->embed(&x, sizeof(int8_t)); } - //! Adds 8-bit integer data to the CodeBuffer. + + ASMJIT_DEPRECATED("Use embedUInt8() instead of duint8()") inline Error duint8(uint8_t x) { return _emitter()->embed(&x, sizeof(uint8_t)); } - //! Adds 16-bit integer data to the CodeBuffer. + ASMJIT_DEPRECATED("Use embedInt16() instead of dint16()") inline Error dint16(int16_t x) { return _emitter()->embed(&x, sizeof(int16_t)); } - //! Adds 16-bit integer data to the CodeBuffer. + + ASMJIT_DEPRECATED("Use embedUInt16() instead of duint16()") inline Error duint16(uint16_t x) { return _emitter()->embed(&x, sizeof(uint16_t)); } - //! Adds 32-bit integer data to the CodeBuffer. + ASMJIT_DEPRECATED("Use embedInt32() instead of dint32()") inline Error dint32(int32_t x) { return _emitter()->embed(&x, sizeof(int32_t)); } - //! Adds 32-bit integer data to the CodeBuffer. + + ASMJIT_DEPRECATED("Use embedUInt32() instead of duint32()") inline Error duint32(uint32_t x) { return _emitter()->embed(&x, sizeof(uint32_t)); } - //! Adds 64-bit integer data to the CodeBuffer. + ASMJIT_DEPRECATED("Use embedInt64() instead of dint64()") inline Error dint64(int64_t x) { return _emitter()->embed(&x, sizeof(int64_t)); } - //! Adds 64-bit integer data to the CodeBuffer. + + ASMJIT_DEPRECATED("Use embedUInt64() instead of duint64()") inline Error duint64(uint64_t x) { return _emitter()->embed(&x, sizeof(uint64_t)); } - //! Adds float data to the CodeBuffer. + ASMJIT_DEPRECATED("Use embedFloat() instead of float()") inline Error dfloat(float x) { return _emitter()->embed(&x, sizeof(float)); } - //! Adds double data to the CodeBuffer. + + ASMJIT_DEPRECATED("Use embedDouble() instead of ddouble()") inline Error ddouble(double x) { return _emitter()->embed(&x, sizeof(double)); } - //! Adds MMX data to the CodeBuffer. - inline Error dmm(const Data64& x) { return _emitter()->embed(&x, sizeof(Data64)); } - //! Adds XMM data to the CodeBuffer. - inline Error dxmm(const Data128& x) { return _emitter()->embed(&x, sizeof(Data128)); } - //! Adds YMM data to the CodeBuffer. - inline Error dymm(const Data256& x) { return _emitter()->embed(&x, sizeof(Data256)); } + ASMJIT_DEPRECATED("Use embed[U]IntN() or embed[Float|Double]() instead of dmm()") + inline Error dmm(const Data64& x) { return _emitter()->embed(&x, 8); } + + ASMJIT_DEPRECATED("Use embed[U]IntN() or embed[Float|Double]() instead of dxmm()") + inline Error dxmm(const Data128& x) { return _emitter()->embed(&x, 16); } + + ASMJIT_DEPRECATED("Use embed[U]IntN() or embed[Float|Double]() instead of dymm()") + inline Error dymm(const Data256& x) { return _emitter()->embed(&x, 32); } +#endif // !ASMJIT_NO_DEPRECATED //! Adds data in a given structure instance to the CodeBuffer. template<typename T> @@ -2025,203 +2044,90 @@ public: ASMJIT_INST_6x(v4fmaddss, V4fmaddss, Xmm, Xmm, Xmm, Xmm, Xmm, Mem) // AVX512_4FMAPS{kz} ASMJIT_INST_6x(v4fnmaddps, V4fnmaddps, Zmm, Zmm, Zmm, Zmm, Zmm, Mem) // AVX512_4FMAPS{kz} ASMJIT_INST_6x(v4fnmaddss, V4fnmaddss, Xmm, Xmm, Xmm, Xmm, Xmm, Mem) // AVX512_4FMAPS{kz} - ASMJIT_INST_3x(vaddpd, Vaddpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vaddpd, Vaddpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vaddpd, Vaddpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vaddpd, Vaddpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vaddpd, Vaddpd, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vaddpd, Vaddpd, Zmm, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vaddps, Vaddps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vaddps, Vaddps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vaddps, Vaddps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vaddps, Vaddps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vaddps, Vaddps, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vaddps, Vaddps, Zmm, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vaddpd, Vaddpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vaddpd, Vaddpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vaddps, Vaddps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vaddps, Vaddps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_3x(vaddsd, Vaddsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vaddsd, Vaddsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vaddss, Vaddss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vaddss, Vaddss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} - ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vaddsubps, Vaddsubps, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaddsubps, Vaddsubps, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaddsubps, Vaddsubps, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vaddsubps, Vaddsubps, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vaesdec, Vaesdec, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaesdec, Vaesdec, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaesdec, Vaesdec, Ymm, Ymm, Ymm) // VAES AVX512_VL - ASMJIT_INST_3x(vaesdec, Vaesdec, Ymm, Ymm, Mem) // VAES AVX512_VL - ASMJIT_INST_3x(vaesdec, Vaesdec, Zmm, Zmm, Zmm) // VAES - ASMJIT_INST_3x(vaesdec, Vaesdec, Zmm, Zmm, Mem) // VAES - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Ymm, Ymm, Ymm) // VAES AVX512_VL - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Ymm, Ymm, Mem) // VAES AVX512_VL - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Zmm, Zmm, Zmm) // VAES - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Zmm, Zmm, Mem) // VAES - ASMJIT_INST_3x(vaesenc, Vaesenc, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaesenc, Vaesenc, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaesenc, Vaesenc, Ymm, Ymm, Ymm) // VAES AVX512_VL - ASMJIT_INST_3x(vaesenc, Vaesenc, Ymm, Ymm, Mem) // VAES AVX512_VL - ASMJIT_INST_3x(vaesenc, Vaesenc, Zmm, Zmm, Zmm) // VAES - ASMJIT_INST_3x(vaesenc, Vaesenc, Zmm, Zmm, Mem) // VAES - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Ymm, Ymm, Ymm) // VAES AVX512_VL - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Ymm, Ymm, Mem) // VAES AVX512_VL - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Zmm, Zmm, Zmm) // VAES - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Zmm, Zmm, Mem) // VAES - ASMJIT_INST_2x(vaesimc, Vaesimc, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vaesimc, Vaesimc, Xmm, Mem) // AVX - ASMJIT_INST_3i(vaeskeygenassist, Vaeskeygenassist, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_3i(vaeskeygenassist, Vaeskeygenassist, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(valignd, Valignd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(valignd, Valignd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(valignd, Valignd, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(valignd, Valignd, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(valignd, Valignd, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(valignd, Valignd, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(valignq, Valignq, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(valignq, Valignq, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(valignq, Valignq, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(valignq, Valignq, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(valignq, Valignq, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(valignq, Valignq, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vandnpd, Vandnpd, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandnpd, Vandnpd, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandnpd, Vandnpd, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandnpd, Vandnpd, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandnpd, Vandnpd, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vandnpd, Vandnpd, Zmm, Zmm, Mem) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vandnps, Vandnps, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandnps, Vandnps, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandnps, Vandnps, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandnps, Vandnps, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandnps, Vandnps, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b32} - ASMJIT_INST_3x(vandnps, Vandnps, Zmm, Zmm, Mem) // AVX512_DQ{kz|b32} - ASMJIT_INST_3x(vandpd, Vandpd, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandpd, Vandpd, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandpd, Vandpd, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandpd, Vandpd, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandpd, Vandpd, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vandpd, Vandpd, Zmm, Zmm, Mem) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vandps, Vandps, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandps, Vandps, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandps, Vandps, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandps, Vandps, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandps, Vandps, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b32} - ASMJIT_INST_3x(vandps, Vandps, Zmm, Zmm, Mem) // AVX512_DQ{kz|b32} - ASMJIT_INST_3x(vblendmb, Vblendmb, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmb, Vblendmb, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmb, Vblendmb, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmb, Vblendmb, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmb, Vblendmb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vblendmb, Vblendmb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vblendmd, Vblendmd, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmd, Vblendmd, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmd, Vblendmd, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmd, Vblendmd, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmd, Vblendmd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vblendmd, Vblendmd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vblendmps, Vblendmps, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmps, Vblendmps, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmps, Vblendmps, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmps, Vblendmps, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmps, Vblendmps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vblendmps, Vblendmps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vblendmq, Vblendmq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmq, Vblendmq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmq, Vblendmq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmq, Vblendmq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmq, Vblendmq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vblendmq, Vblendmq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vblendmw, Vblendmw, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmw, Vblendmw, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmw, Vblendmw, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmw, Vblendmw, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmw, Vblendmw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vblendmw, Vblendmw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_4i(vblendpd, Vblendpd, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vblendpd, Vblendpd, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vblendpd, Vblendpd, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vblendpd, Vblendpd, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4i(vblendps, Vblendps, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vblendps, Vblendps, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vblendps, Vblendps, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vblendps, Vblendps, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4x(vblendvpd, Vblendvpd, Xmm, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_4x(vblendvpd, Vblendvpd, Xmm, Xmm, Mem, Xmm) // AVX - ASMJIT_INST_4x(vblendvpd, Vblendvpd, Ymm, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_4x(vblendvpd, Vblendvpd, Ymm, Ymm, Mem, Ymm) // AVX - ASMJIT_INST_4x(vblendvps, Vblendvps, Xmm, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_4x(vblendvps, Vblendvps, Xmm, Xmm, Mem, Xmm) // AVX - ASMJIT_INST_4x(vblendvps, Vblendvps, Ymm, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_4x(vblendvps, Vblendvps, Ymm, Ymm, Mem, Ymm) // AVX - ASMJIT_INST_2x(vbroadcastf128, Vbroadcastf128, Ymm, Mem) // AVX - ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Ymm, Xmm) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Ymm, Mem) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Zmm, Xmm) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcastf32x4, Vbroadcastf32x4, Ymm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastf32x4, Vbroadcastf32x4, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastf32x8, Vbroadcastf32x8, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcastf64x2, Vbroadcastf64x2, Ymm, Mem) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcastf64x2, Vbroadcastf64x2, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcastf64x4, Vbroadcastf64x4, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcasti128, Vbroadcasti128, Ymm, Mem) // AVX2 - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Xmm, Xmm) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Xmm, Mem) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Ymm, Xmm) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Ymm, Mem) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Zmm, Xmm) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcasti32x4, Vbroadcasti32x4, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcasti32x4, Vbroadcasti32x4, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcasti32x8, Vbroadcasti32x8, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Ymm, Xmm) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Ymm, Mem) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Zmm, Xmm) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcasti64x4, Vbroadcasti64x4, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcasti64x4, Vbroadcasti64x4, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Xmm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Ymm, Mem) // AVX AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Ymm, Xmm) // AVX2 AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Zmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Zmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_4i(vcmppd, Vcmppd, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vcmppd, Vcmppd, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vcmppd, Vcmppd, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vcmppd, Vcmppd, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Zmm, Mem, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_4i(vcmpps, Vcmpps, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vcmpps, Vcmpps, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vcmpps, Vcmpps, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vcmpps, Vcmpps, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Zmm, Mem, Imm) // AVX512_F{kz|sae|b32} + ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vaddsubps, Vaddsubps, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vaddsubps, Vaddsubps, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vaesdec, Vaesdec, Vec, Vec, Vec) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesdec, Vaesdec, Vec, Vec, Mem) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Vec, Vec, Vec) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Vec, Vec, Mem) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesenc, Vaesenc, Vec, Vec, Vec) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesenc, Vaesenc, Vec, Vec, Mem) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesenclast, Vaesenclast, Vec, Vec, Vec) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesenclast, Vaesenclast, Vec, Vec, Mem) // AVX+AESNI VAES + ASMJIT_INST_2x(vaesimc, Vaesimc, Xmm, Xmm) // AVX+AESNI + ASMJIT_INST_2x(vaesimc, Vaesimc, Xmm, Mem) // AVX+AESNI + ASMJIT_INST_3i(vaeskeygenassist, Vaeskeygenassist, Xmm, Xmm, Imm) // AVX+AESNI + ASMJIT_INST_3i(vaeskeygenassist, Vaeskeygenassist, Xmm, Mem, Imm) // AVX+AESNI + ASMJIT_INST_4i(valignd, Valignd, Vec, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(valignd, Valignd, Vec, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(valignq, Valignq, Vec, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(valignq, Valignq, Vec, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vandnpd, Vandnpd, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vandnpd, Vandnpd, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vandnps, Vandnps, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vandnps, Vandnps, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vandpd, Vandpd, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vandpd, Vandpd, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vandps, Vandps, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vandps, Vandps, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vblendmb, Vblendmb, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vblendmb, Vblendmb, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3x(vblendmd, Vblendmd, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vblendmd, Vblendmd, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vblendmpd, Vblendmpd, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vblendmpd, Vblendmpd, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vblendmps, Vblendmps, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vblendmps, Vblendmps, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vblendmq, Vblendmq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vblendmq, Vblendmq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vblendmw, Vblendmw, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vblendmw, Vblendmw, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_4i(vblendpd, Vblendpd, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vblendpd, Vblendpd, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vblendps, Vblendps, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vblendps, Vblendps, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4x(vblendvpd, Vblendvpd, Vec, Vec, Vec, Vec) // AVX + ASMJIT_INST_4x(vblendvpd, Vblendvpd, Vec, Vec, Mem, Vec) // AVX + ASMJIT_INST_4x(vblendvps, Vblendvps, Vec, Vec, Vec, Vec) // AVX + ASMJIT_INST_4x(vblendvps, Vblendvps, Vec, Vec, Mem, Vec) // AVX + ASMJIT_INST_2x(vbroadcastf128, Vbroadcastf128, Vec, Mem) // AVX + ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Vec, Vec) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcastf32x4, Vbroadcastf32x4, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vbroadcastf32x8, Vbroadcastf32x8, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcastf64x2, Vbroadcastf64x2, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcastf64x4, Vbroadcastf64x4, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vbroadcasti128, Vbroadcasti128, Vec, Mem) // AVX2 + ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Vec, Vec) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcasti32x4, Vbroadcasti32x4, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vbroadcasti32x8, Vbroadcasti32x8, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Vec, Vec) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcasti64x4, Vbroadcasti64x4, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vbroadcasti64x4, Vbroadcasti64x4, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Vec, Xmm) // AVX2 AVX512_F{kz} + ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Vec, Xmm) // AVX2 AVX512_F{kz} + ASMJIT_INST_4i(vcmppd, Vcmppd, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vcmppd, Vcmppd, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vcmpps, Vcmpps, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vcmpps, Vcmpps, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Vec, Mem, Imm) // AVX512_F{kz|b32} ASMJIT_INST_4i(vcmpsd, Vcmpsd, Xmm, Xmm, Xmm, Imm) // AVX ASMJIT_INST_4i(vcmpsd, Vcmpsd, Xmm, Xmm, Mem, Imm) // AVX ASMJIT_INST_4i(vcmpsd, Vcmpsd, KReg, Xmm, Xmm, Imm) // AVX512_F{kz|sae} @@ -2234,121 +2140,46 @@ public: ASMJIT_INST_2x(vcomisd, Vcomisd, Xmm, Mem) // AVX AVX512_F{sae} ASMJIT_INST_2x(vcomiss, Vcomiss, Xmm, Xmm) // AVX AVX512_F{sae} ASMJIT_INST_2x(vcomiss, Vcomiss, Xmm, Mem) // AVX AVX512_F{sae} - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vcompressps, Vcompressps, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompressps, Vcompressps, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompressps, Vcompressps, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompressps, Vcompressps, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompressps, Vcompressps, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vcompressps, Vcompressps, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Ymm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Zmm, Ymm) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Zmm, Mem) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Xmm, Xmm, Xmm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Xmm, Xmm, Mem) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Ymm, Ymm, Ymm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Ymm, Ymm, Mem) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Zmm, Zmm, Zmm) // AVX512_BF16{kz|b32} - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Zmm, Zmm, Mem) // AVX512_BF16{kz|b32} - ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Xmm, Xmm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Xmm, Ymm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Xmm, Mem) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Ymm, Zmm) // AVX512_BF16{kz|b32} - ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Ymm, Mem) // AVX512_BF16{kz|b32} - ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Xmm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Ymm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Ymm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Xmm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Ymm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Ymm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Zmm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Zmm, Mem) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Xmm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Ymm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Ymm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Zmm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Zmm, Mem) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Xmm, Xmm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Xmm, Mem) // F16C AVX512_F{kz}-VL - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Ymm, Xmm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Ymm, Mem) // F16C AVX512_F{kz}-VL - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Zmm, Ymm) // AVX512_F{kz|sae} - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Zmm, Mem) // AVX512_F{kz|sae} - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Zmm, Mem) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Ymm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Zmm, Ymm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Zmm, Mem) // AVX512_F{kz|er|b32} - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Xmm, Xmm, Imm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Mem, Xmm, Imm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Xmm, Ymm, Imm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Mem, Ymm, Imm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Ymm, Zmm, Imm) // AVX512_F{kz|sae} - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Mem, Zmm, Imm) // AVX512_F{kz|sae} - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Xmm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Xmm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Ymm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Ymm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Zmm, Ymm) // AVX512_DQ{kz|er|b32} - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Zmm, Mem) // AVX512_DQ{kz|er|b32} - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Zmm, Mem) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Xmm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Xmm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Ymm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Ymm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Zmm, Ymm) // AVX512_DQ{kz|er|b32} - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Zmm, Mem) // AVX512_DQ{kz|er|b32} - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Zmm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Zmm, Mem) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Xmm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Ymm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Ymm, Mem) // AVX512_DQ{kz|er|b64} + ASMJIT_INST_2x(vcompresspd, Vcompresspd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vcompresspd, Vcompresspd, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vcompressps, Vcompressps, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vcompressps, Vcompressps, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Vec, Vec, Vec) // AVX512_BF16{kz|b32} + ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Vec, Vec, Mem) // AVX512_BF16{kz|b32} + ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Vec, Vec) // AVX512_BF16{kz|b32} + ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Vec, Mem) // AVX512_BF16{kz|b32} + ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Vec, Vec) // F16C AVX512_F{kz} + ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Vec, Mem) // F16C AVX512_F{kz} + ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Vec, Vec, Imm) // F16C AVX512_F{kz} + ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Mem, Vec, Imm) // F16C AVX512_F{kz} + ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Vec, Vec) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Vec, Mem) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Vec, Vec) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Vec, Mem) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Vec, Mem) // AVX512_DQ{kz|b64} ASMJIT_INST_2x(vcvtsd2si, Vcvtsd2si, Gp, Xmm) // AVX AVX512_F{er} ASMJIT_INST_2x(vcvtsd2si, Vcvtsd2si, Gp, Mem) // AVX AVX512_F{er} ASMJIT_INST_3x(vcvtsd2ss, Vcvtsd2ss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} @@ -2365,52 +2196,22 @@ public: ASMJIT_INST_2x(vcvtss2si, Vcvtss2si, Gp, Mem) // AVX AVX512_F{er} ASMJIT_INST_2x(vcvtss2usi, Vcvtss2usi, Gp, Xmm) // AVX512_F{er} ASMJIT_INST_2x(vcvtss2usi, Vcvtss2usi, Gp, Mem) // AVX512_F{er} - ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Xmm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Ymm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Ymm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Zmm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Zmm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Xmm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Ymm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Ymm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Zmm, Zmm) // AVX512_DQ{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Zmm, Mem) // AVX512_DQ{kz|sae|b64} - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Zmm, Zmm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Zmm, Mem) // AVX512_F{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Xmm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Xmm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Ymm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Ymm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Zmm, Ymm) // AVX512_DQ{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Zmm, Mem) // AVX512_DQ{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Zmm, Zmm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Zmm, Mem) // AVX512_F{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Xmm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Xmm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Ymm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Ymm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Zmm, Ymm) // AVX512_DQ{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Zmm, Mem) // AVX512_DQ{kz|sae|b32} + ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Vec, Vec) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Vec, Mem) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Vec, Vec) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Vec, Mem) // AVX512_DQ{kz|b32} ASMJIT_INST_2x(vcvttsd2si, Vcvttsd2si, Gp, Xmm) // AVX AVX512_F{sae} ASMJIT_INST_2x(vcvttsd2si, Vcvttsd2si, Gp, Mem) // AVX AVX512_F{sae} ASMJIT_INST_2x(vcvttsd2usi, Vcvttsd2usi, Gp, Xmm) // AVX512_F{sae} @@ -2419,415 +2220,204 @@ public: ASMJIT_INST_2x(vcvttss2si, Vcvttss2si, Gp, Mem) // AVX AVX512_F{sae} ASMJIT_INST_2x(vcvttss2usi, Vcvttss2usi, Gp, Xmm) // AVX512_F{sae} ASMJIT_INST_2x(vcvttss2usi, Vcvttss2usi, Gp, Mem) // AVX512_F{sae} - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Ymm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Zmm, Ymm) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Zmm, Mem) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Zmm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Zmm, Mem) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Xmm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Ymm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Ymm, Mem) // AVX512_DQ{kz|er|b64} + ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Vec, Mem) // AVX512_DQ{kz|b64} ASMJIT_INST_3x(vcvtusi2sd, Vcvtusi2sd, Xmm, Xmm, Gp) // AVX512_F{er} ASMJIT_INST_3x(vcvtusi2sd, Vcvtusi2sd, Xmm, Xmm, Mem) // AVX512_F{er} ASMJIT_INST_3x(vcvtusi2ss, Vcvtusi2ss, Xmm, Xmm, Gp) // AVX512_F{er} ASMJIT_INST_3x(vcvtusi2ss, Vcvtusi2ss, Xmm, Xmm, Mem) // AVX512_F{er} - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Xmm, Xmm, Xmm, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Xmm, Xmm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Ymm, Ymm, Ymm, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Ymm, Ymm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Zmm, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Zmm, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3x(vdivpd, Vdivpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vdivpd, Vdivpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vdivpd, Vdivpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vdivpd, Vdivpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vdivpd, Vdivpd, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vdivpd, Vdivpd, Zmm, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vdivps, Vdivps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vdivps, Vdivps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vdivps, Vdivps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vdivps, Vdivps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vdivps, Vdivps, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vdivps, Vdivps, Zmm, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Vec, Vec, Vec, Imm) // AVX512_BW{kz} + ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Vec, Vec, Mem, Imm) // AVX512_BW{kz} + ASMJIT_INST_3x(vdivpd, Vdivpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vdivpd, Vdivpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vdivps, Vdivps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vdivps, Vdivps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_3x(vdivsd, Vdivsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vdivsd, Vdivsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vdivss, Vdivss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vdivss, Vdivss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Xmm, Xmm, Xmm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Xmm, Xmm, Mem) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Ymm, Ymm, Ymm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Ymm, Ymm, Mem) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Zmm, Zmm, Zmm) // AVX512_BF16{kz|b32} - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Zmm, Zmm, Mem) // AVX512_BF16{kz|b32} - ASMJIT_INST_4i(vdppd, Vdppd, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vdppd, Vdppd, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vdpps, Vdpps, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vdpps, Vdpps, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vdpps, Vdpps, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vdpps, Vdpps, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_2x(vexp2pd, Vexp2pd, Zmm, Zmm) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vexp2pd, Vexp2pd, Zmm, Mem) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vexp2ps, Vexp2ps, Zmm, Zmm) // AVX512_ER{kz|sae|b32} - ASMJIT_INST_2x(vexp2ps, Vexp2ps, Zmm, Mem) // AVX512_ER{kz|sae|b32} - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vexpandps, Vexpandps, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandps, Vexpandps, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandps, Vexpandps, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandps, Vexpandps, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandps, Vexpandps, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vexpandps, Vexpandps, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vextractf128, Vextractf128, Xmm, Ymm, Imm) // AVX - ASMJIT_INST_3i(vextractf128, Vextractf128, Mem, Ymm, Imm) // AVX - ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Xmm, Ymm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Mem, Ymm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Xmm, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Mem, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextractf32x8, Vextractf32x8, Ymm, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextractf32x8, Vextractf32x8, Mem, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Xmm, Ymm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Mem, Ymm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Xmm, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Mem, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextractf64x4, Vextractf64x4, Ymm, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextractf64x4, Vextractf64x4, Mem, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextracti128, Vextracti128, Xmm, Ymm, Imm) // AVX2 - ASMJIT_INST_3i(vextracti128, Vextracti128, Mem, Ymm, Imm) // AVX2 - ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Xmm, Ymm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Mem, Ymm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Xmm, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Mem, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextracti32x8, Vextracti32x8, Ymm, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextracti32x8, Vextracti32x8, Mem, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Xmm, Ymm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Mem, Ymm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Xmm, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Mem, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextracti64x4, Vextracti64x4, Ymm, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextracti64x4, Vextracti64x4, Mem, Zmm, Imm) // AVX512_F{kz} + ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Vec, Vec, Vec) // AVX512_BF16{kz|b32} + ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Vec, Vec, Mem) // AVX512_BF16{kz|b32} + ASMJIT_INST_4i(vdppd, Vdppd, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vdppd, Vdppd, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vdpps, Vdpps, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vdpps, Vdpps, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_2x(vexp2pd, Vexp2pd, Vec, Vec) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vexp2pd, Vexp2pd, Vec, Mem) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vexp2ps, Vexp2ps, Vec, Vec) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vexp2ps, Vexp2ps, Vec, Mem) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vexpandpd, Vexpandpd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vexpandpd, Vexpandpd, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vexpandps, Vexpandps, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vexpandps, Vexpandps, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_3i(vextractf128, Vextractf128, Vec, Vec, Imm) // AVX + ASMJIT_INST_3i(vextractf128, Vextractf128, Mem, Vec, Imm) // AVX + ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Mem, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextractf32x8, Vextractf32x8, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextractf32x8, Vextractf32x8, Mem, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Mem, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextractf64x4, Vextractf64x4, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextractf64x4, Vextractf64x4, Mem, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextracti128, Vextracti128, Vec, Vec, Imm) // AVX2 + ASMJIT_INST_3i(vextracti128, Vextracti128, Mem, Vec, Imm) // AVX2 + ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Mem, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextracti32x8, Vextracti32x8, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextracti32x8, Vextracti32x8, Mem, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Mem, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextracti64x4, Vextracti64x4, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextracti64x4, Vextracti64x4, Mem, Vec, Imm) // AVX512_F{kz} ASMJIT_INST_3i(vextractps, Vextractps, Gp, Xmm, Imm) // AVX AVX512_F ASMJIT_INST_3i(vextractps, Vextractps, Mem, Xmm, Imm) // AVX AVX512_F - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|sae|b32} + ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Vec, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Vec, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Vec, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Vec, Vec, Mem, Imm) // AVX512_F{kz|b32} ASMJIT_INST_4i(vfixupimmsd, Vfixupimmsd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vfixupimmsd, Vfixupimmsd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vfixupimmss, Vfixupimmss, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vfixupimmss, Vfixupimmss, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmadd132sd, Vfmadd132sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd132sd, Vfmadd132sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd132ss, Vfmadd132ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd132ss, Vfmadd132ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmadd213sd, Vfmadd213sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd213sd, Vfmadd213sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd213ss, Vfmadd213ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd213ss, Vfmadd213ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmadd231sd, Vfmadd231sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd231sd, Vfmadd231sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd231ss, Vfmadd231ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd231ss, Vfmadd231ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmsub132sd, Vfmsub132sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub132sd, Vfmsub132sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub132ss, Vfmsub132ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub132ss, Vfmsub132ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmsub213sd, Vfmsub213sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub213sd, Vfmsub213sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub213ss, Vfmsub213ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub213ss, Vfmsub213ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmsub231sd, Vfmsub231sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub231sd, Vfmsub231sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub231ss, Vfmsub231ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub231ss, Vfmsub231ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmadd132sd, Vfnmadd132sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd132sd, Vfnmadd132sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd132ss, Vfnmadd132ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd132ss, Vfnmadd132ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmadd213sd, Vfnmadd213sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd213sd, Vfnmadd213sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd213ss, Vfnmadd213ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd213ss, Vfnmadd213ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmadd231sd, Vfnmadd231sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd231sd, Vfnmadd231sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd231ss, Vfnmadd231ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd231ss, Vfnmadd231ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmsub132sd, Vfnmsub132sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub132sd, Vfnmsub132sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub132ss, Vfnmsub132ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub132ss, Vfnmsub132ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmsub213sd, Vfnmsub213sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub213sd, Vfnmsub213sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub213ss, Vfnmsub213ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub213ss, Vfnmsub213ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmsub231sd, Vfnmsub231sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub231sd, Vfnmsub231sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub231ss, Vfnmsub231ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub231ss, Vfnmsub231ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Xmm, Imm) // AVX512_DQ{k|b64}-VL - ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Mem, Imm) // AVX512_DQ{k|b64} AVX512_DQ{k|b64}-VL - ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Ymm, Imm) // AVX512_DQ{k|b64}-VL - ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Zmm, Imm) // AVX512_DQ{k|b64} - ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Xmm, Imm) // AVX512_DQ{k|b32}-VL - ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Mem, Imm) // AVX512_DQ{k|b32} AVX512_DQ{k|b32}-VL - ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Ymm, Imm) // AVX512_DQ{k|b32}-VL - ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Zmm, Imm) // AVX512_DQ{k|b32} + ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Vec, Imm) // AVX512_DQ{k|b64} + ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Mem, Imm) // AVX512_DQ{k|b64} + ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Vec, Imm) // AVX512_DQ{k|b32} + ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Mem, Imm) // AVX512_DQ{k|b32} ASMJIT_INST_3i(vfpclasssd, Vfpclasssd, KReg, Xmm, Imm) // AVX512_DQ{k} ASMJIT_INST_3i(vfpclasssd, Vfpclasssd, KReg, Mem, Imm) // AVX512_DQ{k} ASMJIT_INST_3i(vfpclassss, Vfpclassss, KReg, Xmm, Imm) // AVX512_DQ{k} ASMJIT_INST_3i(vfpclassss, Vfpclassss, KReg, Mem, Imm) // AVX512_DQ{k} - ASMJIT_INST_3x(vgatherdpd, Vgatherdpd, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vgatherdpd, Vgatherdpd, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vgatherdpd, Vgatherdpd, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherdpd, Vgatherdpd, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherdpd, Vgatherdpd, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vgatherdps, Vgatherdps, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vgatherdps, Vgatherdps, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vgatherdps, Vgatherdps, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherdps, Vgatherdps, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherdps, Vgatherdps, Zmm, Mem) // AVX512_F{k} + ASMJIT_INST_2x(vgatherdpd, Vgatherdpd, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vgatherdpd, Vgatherdpd, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vgatherdps, Vgatherdps, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vgatherdps, Vgatherdps, Vec, Mem, Vec) // AVX2 ASMJIT_INST_1x(vgatherpf0dpd, Vgatherpf0dpd, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vgatherpf0dps, Vgatherpf0dps, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vgatherpf0qpd, Vgatherpf0qpd, Mem) // AVX512_PF{k} @@ -2836,249 +2426,121 @@ public: ASMJIT_INST_1x(vgatherpf1dps, Vgatherpf1dps, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vgatherpf1qpd, Vgatherpf1qpd, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vgatherpf1qps, Vgatherpf1qps, Mem) // AVX512_PF{k} - ASMJIT_INST_3x(vgatherqpd, Vgatherqpd, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vgatherqpd, Vgatherqpd, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vgatherqpd, Vgatherqpd, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherqpd, Vgatherqpd, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherqpd, Vgatherqpd, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vgatherqps, Vgatherqps, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_2x(vgatherqps, Vgatherqps, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherqps, Vgatherqps, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherqps, Vgatherqps, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Zmm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Zmm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Zmm, Zmm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Zmm, Mem) // AVX512_F{kz|sae|b32} + ASMJIT_INST_2x(vgatherqpd, Vgatherqpd, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vgatherqpd, Vgatherqpd, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vgatherqps, Vgatherqps, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vgatherqps, Vgatherqps, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vgetexppd, Vgetexppd, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vgetexppd, Vgetexppd, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vgetexpps, Vgetexpps, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vgetexpps, Vgetexpps, Vec, Mem) // AVX512_F{kz|b32} ASMJIT_INST_3x(vgetexpsd, Vgetexpsd, Xmm, Xmm, Xmm) // AVX512_F{kz|sae} ASMJIT_INST_3x(vgetexpsd, Vgetexpsd, Xmm, Xmm, Mem) // AVX512_F{kz|sae} ASMJIT_INST_3x(vgetexpss, Vgetexpss, Xmm, Xmm, Xmm) // AVX512_F{kz|sae} ASMJIT_INST_3x(vgetexpss, Vgetexpss, Xmm, Xmm, Mem) // AVX512_F{kz|sae} - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Zmm, Mem, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Zmm, Mem, Imm) // AVX512_F{kz|sae|b32} + ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vgetmantps, Vgetmantps, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vgetmantps, Vgetmantps, Vec, Mem, Imm) // AVX512_F{kz|b32} ASMJIT_INST_4i(vgetmantsd, Vgetmantsd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vgetmantsd, Vgetmantsd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vgetmantss, Vgetmantss, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vgetmantss, Vgetmantss, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Xmm,Xmm,Xmm,Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Xmm,Xmm,Mem,Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Ymm,Ymm,Ymm,Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Ymm,Ymm,Mem,Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Zmm,Zmm,Zmm,Imm) // AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Zmm,Zmm,Mem,Imm) // AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Xmm, Xmm, Xmm, Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Xmm, Xmm, Mem, Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Ymm, Ymm, Ymm, Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Ymm, Ymm, Mem, Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Zmm, Zmm, Zmm, Imm) // AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Zmm, Zmm, Mem, Imm) // AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Xmm, Xmm, Xmm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Xmm, Xmm, Mem) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Ymm, Ymm, Ymm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Ymm, Ymm, Mem) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Zmm, Zmm, Zmm) // AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Zmm, Zmm, Mem) // AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vhaddpd, Vhaddpd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vhaddpd, Vhaddpd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vhaddpd, Vhaddpd, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vhaddpd, Vhaddpd, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vhaddps, Vhaddps, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vhaddps, Vhaddps, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vhaddps, Vhaddps, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vhaddps, Vhaddps, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vhsubpd, Vhsubpd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vhsubpd, Vhsubpd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vhsubpd, Vhsubpd, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vhsubpd, Vhsubpd, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vhsubps, Vhsubps, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vhsubps, Vhsubps, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vhsubps, Vhsubps, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vhsubps, Vhsubps, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_4i(vinsertf128, Vinsertf128, Ymm, Ymm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vinsertf128, Vinsertf128, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Ymm, Ymm, Xmm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Ymm, Ymm, Mem, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Zmm, Zmm, Xmm, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinsertf32x8, Vinsertf32x8, Zmm, Zmm, Ymm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinsertf32x8, Vinsertf32x8, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Ymm, Ymm, Xmm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Ymm, Ymm, Mem, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Zmm, Zmm, Xmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinsertf64x4, Vinsertf64x4, Zmm, Zmm, Ymm, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinsertf64x4, Vinsertf64x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinserti128, Vinserti128, Ymm, Ymm, Xmm, Imm) // AVX2 - ASMJIT_INST_4i(vinserti128, Vinserti128, Ymm, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Ymm, Ymm, Xmm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Ymm, Ymm, Mem, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Zmm, Zmm, Xmm, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinserti32x8, Vinserti32x8, Zmm, Zmm, Ymm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinserti32x8, Vinserti32x8, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Ymm, Ymm, Xmm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Ymm, Ymm, Mem, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Zmm, Zmm, Xmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinserti64x4, Vinserti64x4, Zmm, Zmm, Ymm, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinserti64x4, Vinserti64x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Vec,Vec,Vec,Imm) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Vec,Vec,Mem,Imm) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Vec, Vec, Vec, Imm) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Vec, Vec, Mem, Imm) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Vec, Vec, Vec) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Vec, Vec, Mem) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_3x(vhaddpd, Vhaddpd, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vhaddpd, Vhaddpd, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vhaddps, Vhaddps, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vhaddps, Vhaddps, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vhsubpd, Vhsubpd, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vhsubpd, Vhsubpd, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vhsubps, Vhsubps, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vhsubps, Vhsubps, Vec, Vec, Mem) // AVX + ASMJIT_INST_4i(vinsertf128, Vinsertf128, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vinsertf128, Vinsertf128, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Vec, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Vec, Vec, Mem, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinsertf32x8, Vinsertf32x8, Vec, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinsertf32x8, Vinsertf32x8, Vec, Vec, Mem, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Vec, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Vec, Vec, Mem, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinsertf64x4, Vinsertf64x4, Vec, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinsertf64x4, Vinsertf64x4, Vec, Vec, Mem, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinserti128, Vinserti128, Vec, Vec, Vec, Imm) // AVX2 + ASMJIT_INST_4i(vinserti128, Vinserti128, Vec, Vec, Mem, Imm) // AVX2 + ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Vec, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Vec, Vec, Mem, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinserti32x8, Vinserti32x8, Vec, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinserti32x8, Vinserti32x8, Vec, Vec, Mem, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Vec, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Vec, Vec, Mem, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinserti64x4, Vinserti64x4, Vec, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinserti64x4, Vinserti64x4, Vec, Vec, Mem, Imm) // AVX512_F{kz} ASMJIT_INST_4i(vinsertps, Vinsertps, Xmm, Xmm, Xmm, Imm) // AVX AVX512_F ASMJIT_INST_4i(vinsertps, Vinsertps, Xmm, Xmm, Mem, Imm) // AVX AVX512_F - ASMJIT_INST_2x(vlddqu, Vlddqu, Xmm, Mem) // AVX - ASMJIT_INST_2x(vlddqu, Vlddqu, Ymm, Mem) // AVX + ASMJIT_INST_2x(vlddqu, Vlddqu, Vec, Mem) // AVX ASMJIT_INST_1x(vldmxcsr, Vldmxcsr, Mem) // AVX - ASMJIT_INST_3x(vmaskmovdqu, Vmaskmovdqu, Xmm, Xmm, DS_ZDI) // AVX [EXPLICIT] - ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Mem, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Mem, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Mem, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Mem, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Zmm, Zmm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Zmm, Zmm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3x(vmaxps, Vmaxps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmaxps, Vmaxps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmaxps, Vmaxps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmaxps, Vmaxps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmaxps, Vmaxps, Zmm, Zmm, Zmm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3x(vmaxps, Vmaxps, Zmm, Zmm, Mem) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3x(vmaxsd, Vmaxsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vmaxsd, Vmaxsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vmaxss, Vmaxss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vmaxss, Vmaxss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vminpd, Vminpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vminpd, Vminpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vminpd, Vminpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vminpd, Vminpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vminpd, Vminpd, Zmm, Zmm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3x(vminpd, Vminpd, Zmm, Zmm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3x(vminps, Vminps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vminps, Vminps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vminps, Vminps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vminps, Vminps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vminps, Vminps, Zmm, Zmm, Zmm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3x(vminps, Vminps, Zmm, Zmm, Mem) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3x(vminsd, Vminsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vminsd, Vminsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vminss, Vminss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vminss, Vminss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Mem, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Mem, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovapd, Vmovapd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovapd, Vmovapd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovaps, Vmovaps, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Mem, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Mem, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovaps, Vmovaps, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovaps, Vmovaps, Mem, Zmm) // AVX512_F{kz} + ASMJIT_INST_3x(vmaskmovdqu, Vmaskmovdqu, Vec, Vec, DS_ZDI) // AVX [EXPLICIT] + ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Mem, Vec, Vec) // AVX + ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Mem, Vec, Vec) // AVX + ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vmaxpd, Vmaxpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vmaxpd, Vmaxpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vmaxps, Vmaxps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vmaxps, Vmaxps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vmaxsd, Vmaxsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vmaxsd, Vmaxsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vmaxss, Vmaxss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vmaxss, Vmaxss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vminpd, Vminpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vminpd, Vminpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vminps, Vminps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vminps, Vminps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vminsd, Vminsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vminsd, Vminsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vminss, Vminss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vminss, Vminss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae} + ASMJIT_INST_2x(vmovapd, Vmovapd, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovapd, Vmovapd, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovapd, Vmovapd, Mem, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovaps, Vmovaps, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovaps, Vmovaps, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovaps, Vmovaps, Mem, Vec) // AVX AVX512_F{kz} ASMJIT_INST_2x(vmovd, Vmovd, Gp, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovd, Vmovd, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovd, Vmovd, Xmm, Gp) // AVX AVX512_F ASMJIT_INST_2x(vmovd, Vmovd, Xmm, Mem) // AVX AVX512_F - ASMJIT_INST_2x(vmovddup, Vmovddup, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovddup, Vmovddup, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovddup, Vmovddup, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovddup, Vmovddup, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovddup, Vmovddup, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovddup, Vmovddup, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Xmm, Mem) // AVX - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Mem, Xmm) // AVX - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Ymm, Mem) // AVX - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Mem, Ymm) // AVX - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Xmm, Mem) // AVX - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Mem, Xmm) // AVX - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Ymm, Mem) // AVX - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Mem, Ymm) // AVX - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Mem, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Mem, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Mem, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Mem, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Mem, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Mem, Zmm) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovddup, Vmovddup, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovddup, Vmovddup, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa, Vmovdqa, Vec, Vec) // AVX + ASMJIT_INST_2x(vmovdqa, Vmovdqa, Vec, Mem) // AVX + ASMJIT_INST_2x(vmovdqa, Vmovdqa, Mem, Vec) // AVX + ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu, Vmovdqu, Vec, Vec) // AVX + ASMJIT_INST_2x(vmovdqu, Vmovdqu, Vec, Mem) // AVX + ASMJIT_INST_2x(vmovdqu, Vmovdqu, Mem, Vec) // AVX + ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Mem, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Mem, Vec) // AVX512_BW{kz} ASMJIT_INST_3x(vmovhlps, Vmovhlps, Xmm, Xmm, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovhpd, Vmovhpd, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_3x(vmovhpd, Vmovhpd, Xmm, Xmm, Mem) // AVX AVX512_F @@ -3089,22 +2551,12 @@ public: ASMJIT_INST_3x(vmovlpd, Vmovlpd, Xmm, Xmm, Mem) // AVX AVX512_F ASMJIT_INST_2x(vmovlps, Vmovlps, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_3x(vmovlps, Vmovlps, Xmm, Xmm, Mem) // AVX AVX512_F - ASMJIT_INST_2x(vmovmskpd, Vmovmskpd, Gp, Xmm) // AVX - ASMJIT_INST_2x(vmovmskpd, Vmovmskpd, Gp, Ymm) // AVX - ASMJIT_INST_2x(vmovmskps, Vmovmskps, Gp, Xmm) // AVX - ASMJIT_INST_2x(vmovmskps, Vmovmskps, Gp, Ymm) // AVX - ASMJIT_INST_2x(vmovntdq, Vmovntdq, Mem, Xmm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntdq, Vmovntdq, Mem, Ymm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntdq, Vmovntdq, Mem, Zmm) // AVX512_F - ASMJIT_INST_2x(vmovntdqa, Vmovntdqa, Xmm, Mem) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntdqa, Vmovntdqa, Ymm, Mem) // AVX2 AVX512_F-VL - ASMJIT_INST_2x(vmovntdqa, Vmovntdqa, Zmm, Mem) // AVX512_F - ASMJIT_INST_2x(vmovntpd, Vmovntpd, Mem, Xmm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntpd, Vmovntpd, Mem, Ymm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntpd, Vmovntpd, Mem, Zmm) // AVX512_F - ASMJIT_INST_2x(vmovntps, Vmovntps, Mem, Xmm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntps, Vmovntps, Mem, Ymm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntps, Vmovntps, Mem, Zmm) // AVX512_F + ASMJIT_INST_2x(vmovmskpd, Vmovmskpd, Gp, Vec) // AVX + ASMJIT_INST_2x(vmovmskps, Vmovmskps, Gp, Vec) // AVX + ASMJIT_INST_2x(vmovntdq, Vmovntdq, Mem, Vec) // AVX+ AVX512_F + ASMJIT_INST_2x(vmovntdqa, Vmovntdqa, Vec, Mem) // AVX+ AVX512_F + ASMJIT_INST_2x(vmovntpd, Vmovntpd, Mem, Vec) // AVX AVX512_F + ASMJIT_INST_2x(vmovntps, Vmovntps, Mem, Vec) // AVX AVX512_F ASMJIT_INST_2x(vmovq, Vmovq, Gp, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovq, Vmovq, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovq, Vmovq, Xmm, Mem) // AVX AVX512_F @@ -3113,627 +2565,241 @@ public: ASMJIT_INST_2x(vmovsd, Vmovsd, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovsd, Vmovsd, Xmm, Mem) // AVX AVX512_F{kz} ASMJIT_INST_3x(vmovsd, Vmovsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz} - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Zmm, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vmovshdup, Vmovshdup, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovshdup, Vmovshdup, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovsldup, Vmovsldup, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovsldup, Vmovsldup, Vec, Mem) // AVX AVX512_F{kz} ASMJIT_INST_2x(vmovss, Vmovss, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovss, Vmovss, Xmm, Mem) // AVX AVX512_F{kz} ASMJIT_INST_3x(vmovss, Vmovss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz} - ASMJIT_INST_2x(vmovupd, Vmovupd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Mem, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Mem, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovupd, Vmovupd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovupd, Vmovupd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovups, Vmovups, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Mem, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Mem, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovups, Vmovups, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovups, Vmovups, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Ymm, Ymm, Ymm, Imm) // AVX2 - ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Ymm, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_3x(vmulpd, Vmulpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmulpd, Vmulpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmulpd, Vmulpd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmulpd, Vmulpd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmulpd, Vmulpd, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vmulpd, Vmulpd, Zmm, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vmulps, Vmulps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmulps, Vmulps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmulps, Vmulps, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmulps, Vmulps, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmulps, Vmulps, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vmulps, Vmulps, Zmm, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_2x(vmovupd, Vmovupd, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovupd, Vmovupd, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovupd, Vmovupd, Mem, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovups, Vmovups, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovups, Vmovups, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovups, Vmovups, Mem, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Vec, Vec, Vec, Imm) // AVX+ + ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Vec, Vec, Mem, Imm) // AVX+ + ASMJIT_INST_3x(vmulpd, Vmulpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vmulpd, Vmulpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vmulps, Vmulps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vmulps, Vmulps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_3x(vmulsd, Vmulsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vmulsd, Vmulsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vmulss, Vmulss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vmulss, Vmulss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} - ASMJIT_INST_3x(vorpd, Vorpd, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vorpd, Vorpd, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vorpd, Vorpd, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vorpd, Vorpd, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vorpd, Vorpd, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vorpd, Vorpd, Zmm, Zmm, Mem) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vorps, Vorps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vorps, Vorps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vorps, Vorps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vorps, Vorps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vorps, Vorps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vorps, Vorps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vorpd, Vorpd, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vorpd, Vorpd, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vorps, Vorps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vorps, Vorps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_6x(vp4dpwssd, Vp4dpwssd, Zmm, Zmm, Zmm, Zmm, Zmm, Mem) // AVX512_4FMAPS{kz} ASMJIT_INST_6x(vp4dpwssds, Vp4dpwssds, Zmm, Zmm, Zmm, Zmm, Zmm, Mem) // AVX512_4FMAPS{kz} - ASMJIT_INST_2x(vpabsb, Vpabsb, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsb, Vpabsb, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsb, Vpabsb, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsb, Vpabsb, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsb, Vpabsb, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpabsb, Vpabsb, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpabsd, Vpabsd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsd, Vpabsd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsd, Vpabsd, Ymm, Ymm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsd, Vpabsd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsd, Vpabsd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpabsd, Vpabsd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpabsq, Vpabsq, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsq, Vpabsq, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsq, Vpabsq, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsq, Vpabsq, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsq, Vpabsq, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpabsq, Vpabsq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpabsw, Vpabsw, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsw, Vpabsw, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsw, Vpabsw, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsw, Vpabsw, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsw, Vpabsw, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpabsw, Vpabsw, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Zmm, Zmm, Zmm) // AVX512_BW{kz|b32} - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Zmm, Zmm, Mem) // AVX512_BW{kz|b32} - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Zmm, Zmm, Zmm) // AVX512_BW{kz|b32} - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Zmm, Zmm, Mem) // AVX512_BW{kz|b32} - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddb, Vpaddb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddb, Vpaddb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddb, Vpaddb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddb, Vpaddb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddb, Vpaddb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddb, Vpaddb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddd, Vpaddd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpaddd, Vpaddd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpaddd, Vpaddd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpaddd, Vpaddd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpaddd, Vpaddd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpaddd, Vpaddd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpaddq, Vpaddq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpaddq, Vpaddq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpaddq, Vpaddq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpaddq, Vpaddq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpaddq, Vpaddq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpaddq, Vpaddq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddw, Vpaddw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddw, Vpaddw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddw, Vpaddw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddw, Vpaddw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddw, Vpaddw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddw, Vpaddw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_4i(vpalignr, Vpalignr, Xmm, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_4i(vpalignr, Vpalignr, Xmm, Xmm, Mem, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_4i(vpalignr, Vpalignr, Ymm, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_4i(vpalignr, Vpalignr, Ymm, Ymm, Mem, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_4i(vpalignr, Vpalignr, Zmm, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_4i(vpalignr, Vpalignr, Zmm, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpand, Vpand, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpand, Vpand, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpand, Vpand, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpand, Vpand, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpandd, Vpandd, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandd, Vpandd, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandd, Vpandd, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandd, Vpandd, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandd, Vpandd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpandd, Vpandd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpandn, Vpandn, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpandn, Vpandn, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpandn, Vpandn, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpandn, Vpandn, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpandnd, Vpandnd, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandnd, Vpandnd, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandnd, Vpandnd, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandnd, Vpandnd, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandnd, Vpandnd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpandnd, Vpandnd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpandnq, Vpandnq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandnq, Vpandnq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandnq, Vpandnq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandnq, Vpandnq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandnq, Vpandnq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpandnq, Vpandnq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpandq, Vpandq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandq, Vpandq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandq, Vpandq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandq, Vpandq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandq, Vpandq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpandq, Vpandq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpavgb, Vpavgb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgb, Vpavgb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgb, Vpavgb, Ymm, Ymm, Ymm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgb, Vpavgb, Ymm, Ymm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgb, Vpavgb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpavgb, Vpavgb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpavgw, Vpavgw, Xmm, Xmm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgw, Vpavgw, Xmm, Xmm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgw, Vpavgw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgw, Vpavgw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgw, Vpavgw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpavgw, Vpavgw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_4i(vpblendd, Vpblendd, Xmm, Xmm, Xmm, Imm) // AVX2 - ASMJIT_INST_4i(vpblendd, Vpblendd, Xmm, Xmm, Mem, Imm) // AVX2 - ASMJIT_INST_4i(vpblendd, Vpblendd, Ymm, Ymm, Ymm, Imm) // AVX2 - ASMJIT_INST_4i(vpblendd, Vpblendd, Ymm, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_4x(vpblendvb, Vpblendvb, Xmm, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_4x(vpblendvb, Vpblendvb, Xmm, Xmm, Mem, Xmm) // AVX - ASMJIT_INST_4x(vpblendvb, Vpblendvb, Ymm, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_4x(vpblendvb, Vpblendvb, Ymm, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_4i(vpblendw, Vpblendw, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vpblendw, Vpblendw, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vpblendw, Vpblendw, Ymm, Ymm, Ymm, Imm) // AVX2 - ASMJIT_INST_4i(vpblendw, Vpblendw, Ymm, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Xmm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Xmm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Xmm, Gp) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Ymm, Gp) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Zmm, Gp) // AVX512_BW{kz} - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Zmm, Xmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Xmm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Xmm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Xmm, Gp) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Ymm, Gp) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Zmm, Gp) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastmb2d, Vpbroadcastmb2d, Xmm, KReg) // AVX512_CD-VL - ASMJIT_INST_2x(vpbroadcastmb2d, Vpbroadcastmb2d, Ymm, KReg) // AVX512_CD-VL - ASMJIT_INST_2x(vpbroadcastmb2d, Vpbroadcastmb2d, Zmm, KReg) // AVX512_CD - ASMJIT_INST_2x(vpbroadcastmb2q, Vpbroadcastmb2q, Xmm, KReg) // AVX512_CD-VL - ASMJIT_INST_2x(vpbroadcastmb2q, Vpbroadcastmb2q, Ymm, KReg) // AVX512_CD-VL - ASMJIT_INST_2x(vpbroadcastmb2q, Vpbroadcastmb2q, Zmm, KReg) // AVX512_CD - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Xmm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Xmm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Xmm, Gp) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Ymm, Gp) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Zmm, Gp) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Xmm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Xmm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Xmm, Gp) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Ymm, Gp) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Zmm, Gp) // AVX512_BW{kz} - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Zmm, Xmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Xmm, Xmm, Xmm, Imm) // AVX AVX512_F-VL - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Xmm, Xmm, Mem, Imm) // AVX AVX512_F-VL - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Ymm, Ymm, Ymm, Imm) // AVX512_F-VL VPCLMULQDQ - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Ymm, Ymm, Mem, Imm) // AVX512_F-VL VPCLMULQDQ - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Zmm, Zmm, Zmm, Imm) // AVX512_F VPCLMULQDQ - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Zmm, Zmm, Mem, Imm) // AVX512_F VPCLMULQDQ - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Xmm, Xmm, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Xmm, Mem, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Ymm, Ymm, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Ymm, Mem, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Zmm, Zmm, Imm) // AVX512_BW{k} - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Zmm, Mem, Imm) // AVX512_BW{k} - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Xmm, Xmm, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Xmm, Mem, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Ymm, Ymm, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Ymm, Mem, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Zmm, Zmm, Imm) // AVX512_F{k|b32} - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Zmm, Mem, Imm) // AVX512_F{k|b32} - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Xmm, Xmm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Xmm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Ymm, Ymm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Ymm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Zmm, Zmm) // AVX512_F{k|b32} - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Zmm, Mem) // AVX512_F{k|b32} - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Xmm, Xmm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Xmm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Ymm, Ymm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Ymm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Zmm, Zmm) // AVX512_F{k|b64} - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Zmm, Mem) // AVX512_F{k|b64} - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_6x(vpcmpestri, Vpcmpestri, Xmm, Xmm, Imm, ECX, EAX, EDX) // AVX [EXPLICIT] - ASMJIT_INST_6x(vpcmpestri, Vpcmpestri, Xmm, Mem, Imm, ECX, EAX, EDX) // AVX [EXPLICIT] - ASMJIT_INST_6x(vpcmpestrm, Vpcmpestrm, Xmm, Xmm, Imm, XMM0, EAX, EDX)// AVX [EXPLICIT] - ASMJIT_INST_6x(vpcmpestrm, Vpcmpestrm, Xmm, Mem, Imm, XMM0, EAX, EDX)// AVX [EXPLICIT] - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Xmm, Xmm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Xmm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Ymm, Ymm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Ymm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Zmm, Zmm) // AVX512_F{k|b32} - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Zmm, Mem) // AVX512_F{k|b32} - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Xmm, Xmm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Xmm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Ymm, Ymm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Ymm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Zmm, Zmm) // AVX512_F{k|b64} - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Zmm, Mem) // AVX512_F{k|b64} - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_4x(vpcmpistri, Vpcmpistri, Xmm, Xmm, Imm, ECX) // AVX [EXPLICIT] - ASMJIT_INST_4x(vpcmpistri, Vpcmpistri, Xmm, Mem, Imm, ECX) // AVX [EXPLICIT] - ASMJIT_INST_4x(vpcmpistrm, Vpcmpistrm, Xmm, Xmm, Imm, XMM0) // AVX [EXPLICIT] - ASMJIT_INST_4x(vpcmpistrm, Vpcmpistrm, Xmm, Mem, Imm, XMM0) // AVX [EXPLICIT] - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Xmm, Xmm, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Xmm, Mem, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Ymm, Ymm, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Ymm, Mem, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Zmm, Zmm, Imm) // AVX512_F{k|b64} - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Zmm, Mem, Imm) // AVX512_F{k|b64} - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Xmm, Xmm, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Xmm, Mem, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Ymm, Ymm, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Ymm, Mem, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Zmm, Zmm, Imm) // AVX512_BW{k} - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Zmm, Mem, Imm) // AVX512_BW{k} - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Xmm, Xmm, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Xmm, Mem, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Ymm, Ymm, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Ymm, Mem, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Zmm, Zmm, Imm) // AVX512_F{k|b32} - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Zmm, Mem, Imm) // AVX512_F{k|b32} - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Xmm, Xmm, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Xmm, Mem, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Ymm, Ymm, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Ymm, Mem, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Zmm, Zmm, Imm) // AVX512_F{k|b64} - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Zmm, Mem, Imm) // AVX512_F{k|b64} - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Xmm, Xmm, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Xmm, Mem, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Ymm, Ymm, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Ymm, Mem, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Zmm, Zmm, Imm) // AVX512_BW{k|b64} - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Zmm, Mem, Imm) // AVX512_BW{k|b64} - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Xmm, Xmm, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Xmm, Mem, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Ymm, Ymm, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Ymm, Mem, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Zmm, Zmm, Imm) // AVX512_BW{k|b64} - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Zmm, Mem, Imm) // AVX512_BW{k|b64} - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Mem, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Mem, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Mem, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Mem, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Mem, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Mem, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Xmm, Xmm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Xmm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Ymm, Ymm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Ymm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Zmm, Zmm) // AVX512_CD{kz|b32} - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Zmm, Mem) // AVX512_CD{kz|b32} - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Xmm, Xmm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Xmm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Ymm, Ymm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Ymm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Zmm, Zmm) // AVX512_CD{kz|b32} - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Zmm, Mem) // AVX512_CD{kz|b32} - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Xmm, Xmm, Xmm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Xmm, Xmm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Ymm, Ymm, Ymm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Ymm, Ymm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Zmm, Zmm, Zmm) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Zmm, Zmm, Mem) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Xmm, Xmm, Xmm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Xmm, Xmm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Ymm, Ymm, Ymm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Ymm, Ymm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Zmm, Zmm, Zmm) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Zmm, Zmm, Mem) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Xmm, Xmm, Xmm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Xmm, Xmm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Ymm, Ymm, Ymm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Ymm, Ymm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Zmm, Zmm, Zmm) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Zmm, Zmm, Mem) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Xmm, Xmm, Xmm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Xmm, Xmm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Ymm, Ymm, Ymm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Ymm, Ymm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Zmm, Zmm, Zmm) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Zmm, Zmm, Mem) // AVX512_VNNI{kz|b32} - ASMJIT_INST_4i(vperm2f128, Vperm2f128, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vperm2f128, Vperm2f128, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4i(vperm2i128, Vperm2i128, Ymm, Ymm, Ymm, Imm) // AVX2 - ASMJIT_INST_4i(vperm2i128, Vperm2i128, Ymm, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_3x(vpermb, Vpermb, Xmm, Xmm, Xmm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermb, Vpermb, Xmm, Xmm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermb, Vpermb, Ymm, Ymm, Ymm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermb, Vpermb, Ymm, Ymm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermb, Vpermb, Zmm, Zmm, Zmm) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermb, Vpermb, Zmm, Zmm, Mem) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermd, Vpermd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermd, Vpermd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermd, Vpermd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermd, Vpermd, Zmm, Zmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Xmm, Xmm, Xmm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Xmm, Xmm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Ymm, Ymm, Ymm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Ymm, Ymm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Zmm, Zmm, Zmm) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Zmm, Zmm, Mem) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Xmm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Ymm, Ymm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Ymm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermilps, Vpermilps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilps, Vpermilps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilps, Vpermilps, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilps, Vpermilps, Xmm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilps, Vpermilps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilps, Vpermilps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilps, Vpermilps, Ymm, Ymm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilps, Vpermilps, Ymm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilps, Vpermilps, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermilps, Vpermilps, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpermilps, Vpermilps, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpermilps, Vpermilps, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpermpd, Vpermpd, Ymm, Ymm, Imm) // AVX2 - ASMJIT_INST_3i(vpermpd, Vpermpd, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_3x(vpermps, Vpermps, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpermps, Vpermps, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3i(vpermq, Vpermq, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermq, Vpermq, Ymm, Mem, Imm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermq, Vpermq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermq, Vpermq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermq, Vpermq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermq, Vpermq, Zmm, Zmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermq, Vpermq, Zmm, Zmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermq, Vpermq, Zmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Xmm, Xmm, Xmm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Xmm, Xmm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Ymm, Ymm, Ymm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Ymm, Ymm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Zmm, Zmm, Zmm) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Zmm, Zmm, Mem) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpermw, Vpermw, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermw, Vpermw, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermw, Vpermw, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermw, Vpermw, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermw, Vpermw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpermw, Vpermw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Zmm, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpabsb, Vpabsb, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpabsb, Vpabsb, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpabsd, Vpabsd, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpabsd, Vpabsd, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpabsq, Vpabsq, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpabsq, Vpabsq, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vpabsw, Vpabsw, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpabsw, Vpabsw, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpackssdw, Vpackssdw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz|b32} + ASMJIT_INST_3x(vpackssdw, Vpackssdw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz|b32} + ASMJIT_INST_3x(vpacksswb, Vpacksswb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpacksswb, Vpacksswb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpackusdw, Vpackusdw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz|b32} + ASMJIT_INST_3x(vpackusdw, Vpackusdw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz|b32} + ASMJIT_INST_3x(vpackuswb, Vpackuswb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpackuswb, Vpackuswb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddb, Vpaddb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddb, Vpaddb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddd, Vpaddd, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpaddd, Vpaddd, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpaddq, Vpaddq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpaddq, Vpaddq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpaddsb, Vpaddsb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddsb, Vpaddsb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddsw, Vpaddsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddsw, Vpaddsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddusb, Vpaddusb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddusb, Vpaddusb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddusw, Vpaddusw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddusw, Vpaddusw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddw, Vpaddw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddw, Vpaddw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_4i(vpalignr, Vpalignr, Vec, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_4i(vpalignr, Vpalignr, Vec, Vec, Mem, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpand, Vpand, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpand, Vpand, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpandd, Vpandd, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpandd, Vpandd, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpandn, Vpandn, Vec, Vec, Vec) // AV+ + ASMJIT_INST_3x(vpandn, Vpandn, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpandnd, Vpandnd, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpandnd, Vpandnd, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpandnq, Vpandnq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpandnq, Vpandnq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpandq, Vpandq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpandq, Vpandq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpavgb, Vpavgb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpavgb, Vpavgb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpavgw, Vpavgw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpavgw, Vpavgw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_4i(vpblendd, Vpblendd, Vec, Vec, Vec, Imm) // AVX2 + ASMJIT_INST_4i(vpblendd, Vpblendd, Vec, Vec, Mem, Imm) // AVX2 + ASMJIT_INST_4x(vpblendvb, Vpblendvb, Vec, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_4x(vpblendvb, Vpblendvb, Vec, Vec, Mem, Vec) // AVX+ + ASMJIT_INST_4i(vpblendw, Vpblendw, Vec, Vec, Vec, Imm) // AVX+ + ASMJIT_INST_4i(vpblendw, Vpblendw, Vec, Vec, Mem, Imm) // AVX+ + ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Vec, Vec) // AVX2 AVX512_BW{kz} + ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Vec, Mem) // AVX2 AVX512_BW{kz} + ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Vec, Gp) // AVX512_BW{kz} + ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Vec, Vec) // AVX2 AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Vec, Mem) // AVX2 AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Vec, Gp) // AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastmb2d, Vpbroadcastmb2d, Vec, KReg) // AVX512_CD + ASMJIT_INST_2x(vpbroadcastmb2q, Vpbroadcastmb2q, Vec, KReg) // AVX512_CD + ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Vec, Vec) // AVX2 AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Vec, Mem) // AVX2 AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Vec, Gp) // AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Vec, Vec) // AVX2 AVX512_BW{kz} + ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Vec, Mem) // AVX2 AVX512_BW{kz} + ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Vec, Gp) // AVX512_BW{kz} + ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Vec, Vec, Vec, Imm) // AVX VPCLMULQDQ AVX512_F + ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Vec, Vec, Mem, Imm) // AVX VPCLMULQDQ AVX512_F + ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Vec, Vec, Imm) // AVX512_BW{k} + ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Vec, Mem, Imm) // AVX512_BW{k} + ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Vec, Vec, Imm) // AVX512_F{k|b32} + ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Vec, Mem, Imm) // AVX512_F{k|b32} + ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Vec, Vec) // AVX512_F{k|b32} + ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Vec, Mem) // AVX512_F{k|b32} + ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Vec, Vec) // AVX512_F{k|b64} + ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Vec, Mem) // AVX512_F{k|b64} + ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_6x(vpcmpestri, Vpcmpestri, Vec, Vec, Imm, ECX, EAX, EDX) // AVX [EXPLICIT] + ASMJIT_INST_6x(vpcmpestri, Vpcmpestri, Vec, Mem, Imm, ECX, EAX, EDX) // AVX [EXPLICIT] + ASMJIT_INST_6x(vpcmpestrm, Vpcmpestrm, Vec, Vec, Imm, XMM0, EAX, EDX)// AVX [EXPLICIT] + ASMJIT_INST_6x(vpcmpestrm, Vpcmpestrm, Vec, Mem, Imm, XMM0, EAX, EDX)// AVX [EXPLICIT] + ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Vec, Vec) // AVX512_F{k|b32} + ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Vec, Mem) // AVX512_F{k|b32} + ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Vec, Vec) // AVX512_F{k|b64} + ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Vec, Mem) // AVX512_F{k|b64} + ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_4x(vpcmpistri, Vpcmpistri, Vec, Vec, Imm, ECX) // AVX [EXPLICIT] + ASMJIT_INST_4x(vpcmpistri, Vpcmpistri, Vec, Mem, Imm, ECX) // AVX [EXPLICIT] + ASMJIT_INST_4x(vpcmpistrm, Vpcmpistrm, Vec, Vec, Imm, XMM0) // AVX [EXPLICIT] + ASMJIT_INST_4x(vpcmpistrm, Vpcmpistrm, Vec, Mem, Imm, XMM0) // AVX [EXPLICIT] + ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Vec, Vec, Imm) // AVX512_F{k|b64} + ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Vec, Mem, Imm) // AVX512_F{k|b64} + ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Vec, Vec, Imm) // AVX512_BW{k} + ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Vec, Mem, Imm) // AVX512_BW{k} + ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Vec, Vec, Imm) // AVX512_F{k|b32} + ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Vec, Mem, Imm) // AVX512_F{k|b32} + ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Vec, Vec, Imm) // AVX512_F{k|b64} + ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Vec, Mem, Imm) // AVX512_F{k|b64} + ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Vec, Vec, Imm) // AVX512_BW{k|b64} + ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Vec, Mem, Imm) // AVX512_BW{k|b64} + ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Vec, Vec, Imm) // AVX512_BW{k|b64} + ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Vec, Mem, Imm) // AVX512_BW{k|b64} + ASMJIT_INST_2x(vpcompressb, Vpcompressb, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpcompressb, Vpcompressb, Mem, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpcompressd, Vpcompressd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpcompressd, Vpcompressd, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpcompressq, Vpcompressq, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpcompressq, Vpcompressq, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpcompressw, Vpcompressw, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpcompressw, Vpcompressw, Mem, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpconflictd, Vpconflictd, Vec, Vec) // AVX512_CD{kz|b32} + ASMJIT_INST_2x(vpconflictd, Vpconflictd, Vec, Mem) // AVX512_CD{kz|b32} + ASMJIT_INST_2x(vpconflictq, Vpconflictq, Vec, Vec) // AVX512_CD{kz|b32} + ASMJIT_INST_2x(vpconflictq, Vpconflictq, Vec, Mem) // AVX512_CD{kz|b32} + ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Vec, Vec, Vec) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Vec, Vec, Mem) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Vec, Vec, Vec) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Vec, Vec, Mem) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Vec, Vec, Vec) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Vec, Vec, Mem) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Vec, Vec, Vec) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Vec, Vec, Mem) // AVX512_VNNI{kz|b32} + ASMJIT_INST_4i(vperm2f128, Vperm2f128, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vperm2f128, Vperm2f128, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vperm2i128, Vperm2i128, Vec, Vec, Vec, Imm) // AVX2 + ASMJIT_INST_4i(vperm2i128, Vperm2i128, Vec, Vec, Mem, Imm) // AVX2 + ASMJIT_INST_3x(vpermb, Vpermb, Vec, Vec, Vec) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermb, Vpermb, Vec, Vec, Mem) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermd, Vpermd, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermd, Vpermd, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermi2b, Vpermi2b, Vec, Vec, Vec) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermi2b, Vpermi2b, Vec, Vec, Mem) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermi2d, Vpermi2d, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermi2d, Vpermi2d, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermi2q, Vpermi2q, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermi2q, Vpermi2q, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermi2w, Vpermi2w, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpermi2w, Vpermi2w, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3x(vpermilpd, Vpermilpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermilpd, Vpermilpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermilpd, Vpermilpd, Vec, Vec, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermilpd, Vpermilpd, Vec, Mem, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermilps, Vpermilps, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermilps, Vpermilps, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermilps, Vpermilps, Vec, Vec, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermilps, Vpermilps, Vec, Mem, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermpd, Vpermpd, Vec, Vec, Imm) // AVX2 + ASMJIT_INST_3i(vpermpd, Vpermpd, Vec, Mem, Imm) // AVX2 + ASMJIT_INST_3x(vpermps, Vpermps, Vec, Vec, Vec) // AVX2 + ASMJIT_INST_3x(vpermps, Vpermps, Vec, Vec, Mem) // AVX2 + ASMJIT_INST_3i(vpermq, Vpermq, Vec, Vec, Imm) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermq, Vpermq, Vec, Mem, Imm) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermq, Vpermq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermq, Vpermq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermt2b, Vpermt2b, Vec, Vec, Vec) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermt2b, Vpermt2b, Vec, Vec, Mem) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermt2d, Vpermt2d, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermt2d, Vpermt2d, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermt2q, Vpermt2q, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermt2q, Vpermt2q, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermt2w, Vpermt2w, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpermt2w, Vpermt2w, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3x(vpermw, Vpermw, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpermw, Vpermw, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_2x(vpexpandb, Vpexpandb, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpexpandb, Vpexpandb, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpexpandd, Vpexpandd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpexpandd, Vpexpandd, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vpexpandq, Vpexpandq, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpexpandq, Vpexpandq, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vpexpandw, Vpexpandw, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpexpandw, Vpexpandw, Vec, Mem) // AVX512_VBMI2{kz} ASMJIT_INST_3i(vpextrb, Vpextrb, Gp, Xmm, Imm) // AVX AVX512_BW ASMJIT_INST_3i(vpextrb, Vpextrb, Mem, Xmm, Imm) // AVX AVX512_BW ASMJIT_INST_3i(vpextrd, Vpextrd, Gp, Xmm, Imm) // AVX AVX512_DQ @@ -3742,51 +2808,28 @@ public: ASMJIT_INST_3i(vpextrq, Vpextrq, Mem, Xmm, Imm) // AVX AVX512_DQ ASMJIT_INST_3i(vpextrw, Vpextrw, Gp, Xmm, Imm) // AVX AVX512_BW ASMJIT_INST_3i(vpextrw, Vpextrw, Mem, Xmm, Imm) // AVX AVX512_BW - ASMJIT_INST_3x(vpgatherdd, Vpgatherdd, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vpgatherdd, Vpgatherdd, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vpgatherdd, Vpgatherdd, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherdd, Vpgatherdd, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherdd, Vpgatherdd, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vpgatherdq, Vpgatherdq, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vpgatherdq, Vpgatherdq, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vpgatherdq, Vpgatherdq, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherdq, Vpgatherdq, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherdq, Vpgatherdq, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vpgatherqd, Vpgatherqd, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_2x(vpgatherqd, Vpgatherqd, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherqd, Vpgatherqd, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherqd, Vpgatherqd, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vpgatherqq, Vpgatherqq, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vpgatherqq, Vpgatherqq, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vpgatherqq, Vpgatherqq, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherqq, Vpgatherqq, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherqq, Vpgatherqq, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vphaddd, Vphaddd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphaddd, Vphaddd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphaddd, Vphaddd, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphaddd, Vphaddd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vphaddsw, Vphaddsw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphaddsw, Vphaddsw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphaddsw, Vphaddsw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphaddsw, Vphaddsw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vphaddw, Vphaddw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphaddw, Vphaddw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphaddw, Vphaddw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphaddw, Vphaddw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_2x(vphminposuw, Vphminposuw, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vphminposuw, Vphminposuw, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphsubd, Vphsubd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphsubd, Vphsubd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphsubd, Vphsubd, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphsubd, Vphsubd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vphsubsw, Vphsubsw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphsubsw, Vphsubsw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphsubsw, Vphsubsw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphsubsw, Vphsubsw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vphsubw, Vphsubw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphsubw, Vphsubw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphsubw, Vphsubw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphsubw, Vphsubw, Ymm, Ymm, Mem) // AVX2 + ASMJIT_INST_2x(vpgatherdd, Vpgatherdd, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vpgatherdd, Vpgatherdd, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vpgatherdq, Vpgatherdq, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vpgatherdq, Vpgatherdq, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vpgatherqd, Vpgatherqd, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vpgatherqd, Vpgatherqd, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vpgatherqq, Vpgatherqq, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vpgatherqq, Vpgatherqq, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_3x(vphaddd, Vphaddd, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphaddd, Vphaddd, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vphaddsw, Vphaddsw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphaddsw, Vphaddsw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vphaddw, Vphaddw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphaddw, Vphaddw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_2x(vphminposuw, Vphminposuw, Vec, Vec) // AVX + ASMJIT_INST_2x(vphminposuw, Vphminposuw, Vec, Mem) // AVX + ASMJIT_INST_3x(vphsubd, Vphsubd, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphsubd, Vphsubd, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vphsubsw, Vphsubsw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphsubsw, Vphsubsw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vphsubw, Vphsubw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphsubw, Vphsubw, Vec, Vec, Mem) // AVX+ ASMJIT_INST_4i(vpinsrb, Vpinsrb, Xmm, Xmm, Gp, Imm) // AVX AVX512_BW{kz} ASMJIT_INST_4i(vpinsrb, Vpinsrb, Xmm, Xmm, Mem, Imm) // AVX AVX512_BW{kz} ASMJIT_INST_4i(vpinsrd, Vpinsrd, Xmm, Xmm, Gp, Imm) // AVX AVX512_DQ{kz} @@ -3795,1099 +2838,411 @@ public: ASMJIT_INST_4i(vpinsrq, Vpinsrq, Xmm, Xmm, Mem, Imm) // AVX AVX512_DQ{kz} ASMJIT_INST_4i(vpinsrw, Vpinsrw, Xmm, Xmm, Gp, Imm) // AVX AVX512_BW{kz} ASMJIT_INST_4i(vpinsrw, Vpinsrw, Xmm, Xmm, Mem, Imm) // AVX AVX512_BW{kz} - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Xmm, Xmm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Xmm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Ymm, Ymm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Ymm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Zmm, Zmm) // AVX512_CD{kz|b32} - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Zmm, Mem) // AVX512_CD{kz|b32} - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Xmm, Xmm) // AVX512_CD{kz|b64}-VL - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Xmm, Mem) // AVX512_CD{kz|b64}-VL - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Ymm, Ymm) // AVX512_CD{kz|b64}-VL - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Ymm, Mem) // AVX512_CD{kz|b64}-VL - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Zmm, Zmm) // AVX512_CD{kz|b64} - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Zmm, Mem) // AVX512_CD{kz|b64} - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Xmm, Xmm, Xmm) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Xmm, Xmm, Mem) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Ymm, Ymm, Ymm) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Ymm, Ymm, Mem) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Zmm, Zmm, Zmm) // AVX512_IFMA{kz|b64} - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Zmm, Zmm, Mem) // AVX512_IFMA{kz|b64} - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Xmm, Xmm, Xmm) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Xmm, Xmm, Mem) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Ymm, Ymm, Ymm) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Ymm, Ymm, Mem) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Zmm, Zmm, Zmm) // AVX512_IFMA{kz|b64} - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Zmm, Zmm, Mem) // AVX512_IFMA{kz|b64} - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Mem, Xmm, Xmm) // AVX2 - ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Mem, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Xmm, Xmm, Mem) // AVX2 - ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Mem, Xmm, Xmm) // AVX2 - ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Mem, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Xmm, Xmm, Mem) // AVX2 - ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminsb, Vpminsb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsb, Vpminsb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsb, Vpminsb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsb, Vpminsb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsb, Vpminsb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminsb, Vpminsb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminsd, Vpminsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminsd, Vpminsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminsd, Vpminsd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminsd, Vpminsd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminsd, Vpminsd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpminsd, Vpminsd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpminsq, Vpminsq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminsq, Vpminsq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminsq, Vpminsq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminsq, Vpminsq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminsq, Vpminsq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpminsq, Vpminsq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpminsw, Vpminsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsw, Vpminsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsw, Vpminsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsw, Vpminsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsw, Vpminsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminsw, Vpminsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminub, Vpminub, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminub, Vpminub, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminub, Vpminub, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminub, Vpminub, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminub, Vpminub, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminub, Vpminub, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminud, Vpminud, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminud, Vpminud, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminud, Vpminud, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminud, Vpminud, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminud, Vpminud, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpminud, Vpminud, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpminuq, Vpminuq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminuq, Vpminuq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminuq, Vpminuq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminuq, Vpminuq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminuq, Vpminuq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpminuq, Vpminuq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpminuw, Vpminuw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminuw, Vpminuw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminuw, Vpminuw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminuw, Vpminuw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminuw, Vpminuw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminuw, Vpminuw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovb2m, Vpmovb2m, KReg, Xmm) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovb2m, Vpmovb2m, KReg, Ymm) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovb2m, Vpmovb2m, KReg, Zmm) // AVX512_BW - ASMJIT_INST_2x(vpmovd2m, Vpmovd2m, KReg, Xmm) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovd2m, Vpmovd2m, KReg, Ymm) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovd2m, Vpmovd2m, KReg, Zmm) // AVX512_DQ - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovm2b, Vpmovm2b, Xmm, KReg) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovm2b, Vpmovm2b, Ymm, KReg) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovm2b, Vpmovm2b, Zmm, KReg) // AVX512_BW - ASMJIT_INST_2x(vpmovm2d, Vpmovm2d, Xmm, KReg) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovm2d, Vpmovm2d, Ymm, KReg) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovm2d, Vpmovm2d, Zmm, KReg) // AVX512_DQ - ASMJIT_INST_2x(vpmovm2q, Vpmovm2q, Xmm, KReg) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovm2q, Vpmovm2q, Ymm, KReg) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovm2q, Vpmovm2q, Zmm, KReg) // AVX512_DQ - ASMJIT_INST_2x(vpmovm2w, Vpmovm2w, Xmm, KReg) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovm2w, Vpmovm2w, Ymm, KReg) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovm2w, Vpmovm2w, Zmm, KReg) // AVX512_BW - ASMJIT_INST_2x(vpmovmskb, Vpmovmskb, Gp, Xmm) // AVX - ASMJIT_INST_2x(vpmovmskb, Vpmovmskb, Gp, Ymm) // AVX2 - ASMJIT_INST_2x(vpmovq2m, Vpmovq2m, KReg, Xmm) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovq2m, Vpmovq2m, KReg, Ymm) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovq2m, Vpmovq2m, KReg, Zmm) // AVX512_DQ - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Mem, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Xmm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Mem, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Ymm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Mem, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Zmm, Ymm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Zmm, Ymm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Zmm, Ymm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Mem, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Xmm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Mem, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Ymm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Mem, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovw2m, Vpmovw2m, KReg, Xmm) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovw2m, Vpmovw2m, KReg, Ymm) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovw2m, Vpmovw2m, KReg, Zmm) // AVX512_BW - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Mem, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Xmm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Mem, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Ymm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Mem, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Zmm, Ymm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Zmm, Ymm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Zmm, Ymm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulld, Vpmulld, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmulld, Vpmulld, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmulld, Vpmulld, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmulld, Vpmulld, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmulld, Vpmulld, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmulld, Vpmulld, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmullq, Vpmullq, Xmm, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vpmullq, Vpmullq, Xmm, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vpmullq, Vpmullq, Ymm, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vpmullq, Vpmullq, Ymm, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vpmullq, Vpmullq, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vpmullq, Vpmullq, Zmm, Zmm, Mem) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vpmullw, Vpmullw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmullw, Vpmullw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmullw, Vpmullw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmullw, Vpmullw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmullw, Vpmullw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmullw, Vpmullw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Xmm, Xmm, Xmm) // AVX512_VBMI{kz|b64}-VL - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Xmm, Xmm, Mem) // AVX512_VBMI{kz|b64}-VL - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Ymm, Ymm, Ymm) // AVX512_VBMI{kz|b64}-VL - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Ymm, Ymm, Mem) // AVX512_VBMI{kz|b64}-VL - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Zmm, Zmm, Zmm) // AVX512_VBMI{kz|b64} - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Zmm, Zmm, Mem) // AVX512_VBMI{kz|b64} - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Xmm, Xmm) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Xmm, Mem) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Ymm, Ymm) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Ymm, Mem) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Zmm, Zmm) // AVX512_BITALG{kz|b32} - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Zmm, Mem) // AVX512_BITALG{kz|b32} - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Xmm, Xmm) // AVX512_VPOPCNTDQ{kz|b32}-VL - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Xmm, Mem) // AVX512_VPOPCNTDQ{kz|b32}-VL - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Ymm, Ymm) // AVX512_VPOPCNTDQ{kz|b32}-VL - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Ymm, Mem) // AVX512_VPOPCNTDQ{kz|b32}-VL - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Zmm, Zmm) // AVX512_VPOPCNTDQ{kz|b32} - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Zmm, Mem) // AVX512_VPOPCNTDQ{kz|b32} - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Xmm, Xmm) // AVX512_VPOPCNTDQ{kz|b64}-VL - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Xmm, Mem) // AVX512_VPOPCNTDQ{kz|b64}-VL - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Ymm, Ymm) // AVX512_VPOPCNTDQ{kz|b64}-VL - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Ymm, Mem) // AVX512_VPOPCNTDQ{kz|b64}-VL - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Zmm, Zmm) // AVX512_VPOPCNTDQ{kz|b64} - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Zmm, Mem) // AVX512_VPOPCNTDQ{kz|b64} - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Xmm, Xmm) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Xmm, Mem) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Ymm, Ymm) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Ymm, Mem) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Zmm, Zmm) // AVX512_BITALG{kz|b32} - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Zmm, Mem) // AVX512_BITALG{kz|b32} - ASMJIT_INST_3x(vpor, Vpor, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpor, Vpor, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpor, Vpor, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpor, Vpor, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpord, Vpord, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpord, Vpord, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpord, Vpord, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpord, Vpord, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpord, Vpord, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpord, Vpord, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vporq, Vporq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vporq, Vporq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vporq, Vporq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vporq, Vporq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vporq, Vporq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vporq, Vporq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vprold, Vprold, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprold, Vprold, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprold, Vprold, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprold, Vprold, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprold, Vprold, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vprold, Vprold, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vprolq, Vprolq, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprolq, Vprolq, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprolq, Vprolq, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprolq, Vprolq, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprolq, Vprolq, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vprolq, Vprolq, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vprolvd, Vprolvd, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprolvd, Vprolvd, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprolvd, Vprolvd, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprolvd, Vprolvd, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprolvd, Vprolvd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vprolvd, Vprolvd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vprolvq, Vprolvq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprolvq, Vprolvq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprolvq, Vprolvq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprolvq, Vprolvq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprolvq, Vprolvq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vprolvq, Vprolvq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vprord, Vprord, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprord, Vprord, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprord, Vprord, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprord, Vprord, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprord, Vprord, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vprord, Vprord, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vprorq, Vprorq, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprorq, Vprorq, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprorq, Vprorq, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprorq, Vprorq, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprorq, Vprorq, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vprorq, Vprorq, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vprorvd, Vprorvd, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprorvd, Vprorvd, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprorvd, Vprorvd, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprorvd, Vprorvd, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprorvd, Vprorvd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vprorvd, Vprorvd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vprorvq, Vprorvq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprorvq, Vprorvq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprorvq, Vprorvq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprorvq, Vprorvq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprorvq, Vprorvq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vprorvq, Vprorvq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Xmm, Xmm, Xmm) // AVX AVX512_BW-VL - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Xmm, Xmm, Mem) // AVX AVX512_BW-VL - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW-VL - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Ymm, Ymm, Mem) // AVX2 AVX512_BW-VL - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Zmm, Zmm, Zmm) // AVX512_BW - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Zmm, Zmm, Mem) // AVX512_BW - ASMJIT_INST_2x(vpscatterdd, Vpscatterdd, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterdd, Vpscatterdd, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterdd, Vpscatterdd, Mem, Zmm) // AVX512_F{k} - ASMJIT_INST_2x(vpscatterdq, Vpscatterdq, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterdq, Vpscatterdq, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterdq, Vpscatterdq, Mem, Zmm) // AVX512_F{k} - ASMJIT_INST_2x(vpscatterqd, Vpscatterqd, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterqd, Vpscatterqd, Mem, Ymm) // AVX512_F{k} - ASMJIT_INST_2x(vpscatterqq, Vpscatterqq, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterqq, Vpscatterqq, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterqq, Vpscatterqq, Mem, Zmm) // AVX512_F{k} - ASMJIT_INST_4i(vpshldd, Vpshldd, Xmm, Xmm, Xmm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshldd, Vpshldd, Xmm, Xmm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshldd, Vpshldd, Ymm, Ymm, Ymm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshldd, Vpshldd, Ymm, Ymm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshldd, Vpshldd, Zmm, Zmm, Zmm, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_4i(vpshldd, Vpshldd, Zmm, Zmm, Mem, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Xmm, Xmm, Xmm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Xmm, Xmm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Ymm, Ymm, Ymm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Ymm, Ymm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Zmm, Zmm, Zmm, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Zmm, Zmm, Mem, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Xmm, Xmm, Xmm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Xmm, Xmm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Ymm, Ymm, Ymm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Ymm, Ymm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Zmm, Zmm, Zmm, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Zmm, Zmm, Mem, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshufb, Vpshufb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpshufb, Vpshufb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpshufb, Vpshufb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpshufb, Vpshufb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpshufb, Vpshufb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpshufb, Vpshufb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Xmm, Xmm) // AVX512_BITALG{k}-VL - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Xmm, Mem) // AVX512_BITALG{k}-VL - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Ymm, Ymm) // AVX512_BITALG{k}-VL - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Ymm, Mem) // AVX512_BITALG{k}-VL - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Zmm, Zmm) // AVX512_BITALG{k} - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Zmm, Mem) // AVX512_BITALG{k} - ASMJIT_INST_3i(vpshufd, Vpshufd, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpshufd, Vpshufd, Xmm, Mem, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpshufd, Vpshufd, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpshufd, Vpshufd, Ymm, Mem, Imm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpshufd, Vpshufd, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpshufd, Vpshufd, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Xmm, Mem, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Ymm, Mem, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Xmm, Mem, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Ymm, Mem, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsignb, Vpsignb, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpsignb, Vpsignb, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpsignb, Vpsignb, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpsignb, Vpsignb, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpsignd, Vpsignd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpsignd, Vpsignd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpsignd, Vpsignd, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpsignd, Vpsignd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpsignw, Vpsignw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpsignw, Vpsignw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpsignw, Vpsignw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpsignw, Vpsignw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3i(vpslld, Vpslld, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpslld, Vpslld, Xmm, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3x(vpslld, Vpslld, Xmm, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3i(vpslld, Vpslld, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpslld, Vpslld, Ymm, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3x(vpslld, Vpslld, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3i(vpslld, Vpslld, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpslld, Vpslld, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpslld, Vpslld, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpslld, Vpslld, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpslld, Vpslld, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpslld, Vpslld, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpslldq, Vpslldq, Xmm, Xmm, Imm) // AVX AVX512_BW-VL - ASMJIT_INST_3i(vpslldq, Vpslldq, Ymm, Ymm, Imm) // AVX2 AVX512_BW-VL - ASMJIT_INST_3i(vpslldq, Vpslldq, Xmm, Mem, Imm) // AVX512_BW-VL - ASMJIT_INST_3i(vpslldq, Vpslldq, Ymm, Mem, Imm) // AVX512_BW-VL - ASMJIT_INST_3i(vpslldq, Vpslldq, Zmm, Zmm, Imm) // AVX512_BW - ASMJIT_INST_3i(vpslldq, Vpslldq, Zmm, Mem, Imm) // AVX512_BW - ASMJIT_INST_3i(vpsllq, Vpsllq, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllq, Vpsllq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsllq, Vpsllq, Xmm, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsllq, Vpsllq, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllq, Vpsllq, Ymm, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsllq, Vpsllq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsllq, Vpsllq, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpsllq, Vpsllq, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllq, Vpsllq, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpsllq, Vpsllq, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpsllq, Vpsllq, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpsllq, Vpsllq, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Xmm, Xmm, Xmm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Xmm, Xmm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Xmm, Xmm, Xmm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Xmm, Xmm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsllw, Vpsllw, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllw, Vpsllw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllw, Vpsllw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsllw, Vpsllw, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllw, Vpsllw, Ymm, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllw, Vpsllw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsllw, Vpsllw, Xmm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsllw, Vpsllw, Ymm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllw, Vpsllw, Zmm, Zmm, Xmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsllw, Vpsllw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsllw, Vpsllw, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsllw, Vpsllw, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsrad, Vpsrad, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrad, Vpsrad, Xmm, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrad, Vpsrad, Xmm, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrad, Vpsrad, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrad, Vpsrad, Ymm, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrad, Vpsrad, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrad, Vpsrad, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpsrad, Vpsrad, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrad, Vpsrad, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpsrad, Vpsrad, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpsrad, Vpsrad, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpsrad, Vpsrad, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsraq, Vpsraq, Xmm, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsraq, Vpsraq, Xmm, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsraq, Vpsraq, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpsraq, Vpsraq, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsraq, Vpsraq, Ymm, Ymm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsraq, Vpsraq, Ymm, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsraq, Vpsraq, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpsraq, Vpsraq, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsraq, Vpsraq, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpsraq, Vpsraq, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpsraq, Vpsraq, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpsraq, Vpsraq, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsravd, Vpsravd, Xmm, Xmm, Xmm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsravd, Vpsravd, Xmm, Xmm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsravd, Vpsravd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsravd, Vpsravd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsravd, Vpsravd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsravd, Vpsravd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsravq, Vpsravq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsravq, Vpsravq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsravq, Vpsravq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsravq, Vpsravq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsravq, Vpsravq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsravq, Vpsravq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsravw, Vpsravw, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsravw, Vpsravw, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsravw, Vpsravw, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsravw, Vpsravw, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsravw, Vpsravw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsravw, Vpsravw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsraw, Vpsraw, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsraw, Vpsraw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsraw, Vpsraw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsraw, Vpsraw, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsraw, Vpsraw, Ymm, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsraw, Vpsraw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsraw, Vpsraw, Xmm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsraw, Vpsraw, Ymm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsraw, Vpsraw, Zmm, Zmm, Xmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsraw, Vpsraw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsraw, Vpsraw, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsraw, Vpsraw, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsrld, Vpsrld, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrld, Vpsrld, Xmm, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrld, Vpsrld, Xmm, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrld, Vpsrld, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrld, Vpsrld, Ymm, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrld, Vpsrld, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrld, Vpsrld, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpsrld, Vpsrld, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrld, Vpsrld, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpsrld, Vpsrld, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpsrld, Vpsrld, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpsrld, Vpsrld, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Xmm, Xmm, Imm) // AVX AVX512_BW-VL - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Ymm, Ymm, Imm) // AVX2 AVX512_BW-VL - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Xmm, Mem, Imm) // AVX512_BW-VL - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Ymm, Mem, Imm) // AVX512_BW-VL - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Zmm, Zmm, Imm) // AVX512_BW - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Zmm, Mem, Imm) // AVX512_BW - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Xmm, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Ymm, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Xmm, Xmm, Xmm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Xmm, Xmm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Xmm, Xmm, Xmm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Xmm, Xmm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Ymm, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Xmm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Ymm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Zmm, Zmm, Xmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubb, Vpsubb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubb, Vpsubb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubb, Vpsubb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubb, Vpsubb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubb, Vpsubb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubb, Vpsubb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubd, Vpsubd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsubd, Vpsubd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsubd, Vpsubd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsubd, Vpsubd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsubd, Vpsubd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsubd, Vpsubd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsubq, Vpsubq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsubq, Vpsubq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsubq, Vpsubq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsubq, Vpsubq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsubq, Vpsubq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsubq, Vpsubq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubw, Vpsubw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubw, Vpsubw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubw, Vpsubw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubw, Vpsubw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubw, Vpsubw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubw, Vpsubw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vptest, Vptest, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vptest, Vptest, Xmm, Mem) // AVX - ASMJIT_INST_2x(vptest, Vptest, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vptest, Vptest, Ymm, Mem) // AVX - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Xmm, Xmm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Xmm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Ymm, Ymm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Ymm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Zmm, Zmm) // AVX512_F{k|b32} - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Zmm, Mem) // AVX512_F{k|b32} - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Xmm, Xmm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Xmm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Ymm, Ymm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Ymm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Zmm, Zmm) // AVX512_F{k|b64} - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Zmm, Mem) // AVX512_F{k|b64} - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Xmm, Xmm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Xmm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Ymm, Ymm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Ymm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Zmm, Zmm) // AVX512_F{k|b32} - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Zmm, Mem) // AVX512_F{k|b32} - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Xmm, Xmm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Xmm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Ymm, Ymm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Ymm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Zmm, Zmm) // AVX512_F{k|b64} - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Zmm, Mem) // AVX512_F{k|b64} - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpxor, Vpxor, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpxor, Vpxor, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpxor, Vpxor, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpxor, Vpxor, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpxord, Vpxord, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpxord, Vpxord, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpxord, Vpxord, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpxord, Vpxord, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpxord, Vpxord, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpxord, Vpxord, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpxorq, Vpxorq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpxorq, Vpxorq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpxorq, Vpxorq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpxorq, Vpxorq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpxorq, Vpxorq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpxorq, Vpxorq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vrangepd, Vrangepd, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_4i(vrangepd, Vrangepd, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_4i(vrangepd, Vrangepd, Ymm, Ymm, Ymm, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_4i(vrangepd, Vrangepd, Ymm, Ymm, Mem, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_4i(vrangepd, Vrangepd, Zmm, Zmm, Zmm, Imm) // AVX512_DQ{kz|sae|b64} - ASMJIT_INST_4i(vrangepd, Vrangepd, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz|sae|b64} - ASMJIT_INST_4i(vrangeps, Vrangeps, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_4i(vrangeps, Vrangeps, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_4i(vrangeps, Vrangeps, Ymm, Ymm, Ymm, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_4i(vrangeps, Vrangeps, Ymm, Ymm, Mem, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_4i(vrangeps, Vrangeps, Zmm, Zmm, Zmm, Imm) // AVX512_DQ{kz|sae|b32} - ASMJIT_INST_4i(vrangeps, Vrangeps, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz|sae|b32} + ASMJIT_INST_2x(vplzcntd, Vplzcntd, Vec, Vec) // AVX512_CD{kz|b32} + ASMJIT_INST_2x(vplzcntd, Vplzcntd, Vec, Mem) // AVX512_CD{kz|b32} + ASMJIT_INST_2x(vplzcntq, Vplzcntq, Vec, Vec) // AVX512_CD{kz|b64} + ASMJIT_INST_2x(vplzcntq, Vplzcntq, Vec, Mem) // AVX512_CD{kz|b64} + ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Vec, Vec, Vec) // AVX512_IFMA{kz|b64} + ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Vec, Vec, Mem) // AVX512_IFMA{kz|b64} + ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Vec, Vec, Vec) // AVX512_IFMA{kz|b64} + ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Vec, Vec, Mem) // AVX512_IFMA{kz|b64} + ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Mem, Vec, Vec) // AVX2 + ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Vec, Vec, Mem) // AVX2 + ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Mem, Vec, Vec) // AVX2 + ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Vec, Vec, Mem) // AVX2 + ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxub, Vpmaxub, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxub, Vpmaxub, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxud, Vpmaxud, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmaxud, Vpmaxud, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminsb, Vpminsb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminsb, Vpminsb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminsd, Vpminsd, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpminsd, Vpminsd, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpminsq, Vpminsq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpminsq, Vpminsq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpminsw, Vpminsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminsw, Vpminsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminub, Vpminub, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminub, Vpminub, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminud, Vpminud, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpminud, Vpminud, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpminuq, Vpminuq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpminuq, Vpminuq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpminuw, Vpminuw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminuw, Vpminuw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpmovb2m, Vpmovb2m, KReg, Vec) // AVX512_BW + ASMJIT_INST_2x(vpmovd2m, Vpmovd2m, KReg, Vec) // AVX512_DQ + ASMJIT_INST_2x(vpmovdb, Vpmovdb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovdb, Vpmovdb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovdw, Vpmovdw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovdw, Vpmovdw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovm2b, Vpmovm2b, Vec, KReg) // AVX512_BW + ASMJIT_INST_2x(vpmovm2d, Vpmovm2d, Vec, KReg) // AVX512_DQ + ASMJIT_INST_2x(vpmovm2q, Vpmovm2q, Vec, KReg) // AVX512_DQ + ASMJIT_INST_2x(vpmovm2w, Vpmovm2w, Vec, KReg) // AVX512_BW + ASMJIT_INST_2x(vpmovmskb, Vpmovmskb, Gp, Vec) // AVX+ + ASMJIT_INST_2x(vpmovq2m, Vpmovq2m, KReg, Vec) // AVX512_DQ + ASMJIT_INST_2x(vpmovqb, Vpmovqb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovqb, Vpmovqb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovqd, Vpmovqd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovqd, Vpmovqd, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovqw, Vpmovqw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovqw, Vpmovqw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovswb, Vpmovswb, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovswb, Vpmovswb, Mem, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Mem, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovw2m, Vpmovw2m, KReg, Vec) // AVX512_BW + ASMJIT_INST_2x(vpmovwb, Vpmovwb, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovwb, Vpmovwb, Mem, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_3x(vpmuldq, Vpmuldq, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmuldq, Vpmuldq, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulhw, Vpmulhw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulhw, Vpmulhw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulld, Vpmulld, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmulld, Vpmulld, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmullq, Vpmullq, Vec, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vpmullq, Vpmullq, Vec, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vpmullw, Vpmullw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmullw, Vpmullw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Vec, Vec, Vec) // AVX512_VBMI{kz|b64} + ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Vec, Vec, Mem) // AVX512_VBMI{kz|b64} + ASMJIT_INST_3x(vpmuludq, Vpmuludq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmuludq, Vpmuludq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_2x(vpopcntb, Vpopcntb, Vec, Vec) // AVX512_BITALG{kz|b32} + ASMJIT_INST_2x(vpopcntb, Vpopcntb, Vec, Mem) // AVX512_BITALG{kz|b32} + ASMJIT_INST_2x(vpopcntd, Vpopcntd, Vec, Vec) // AVX512_VPOPCNTDQ{kz|b32} + ASMJIT_INST_2x(vpopcntd, Vpopcntd, Vec, Mem) // AVX512_VPOPCNTDQ{kz|b32} + ASMJIT_INST_2x(vpopcntq, Vpopcntq, Vec, Vec) // AVX512_VPOPCNTDQ{kz|b64} + ASMJIT_INST_2x(vpopcntq, Vpopcntq, Vec, Mem) // AVX512_VPOPCNTDQ{kz|b64} + ASMJIT_INST_2x(vpopcntw, Vpopcntw, Vec, Vec) // AVX512_BITALG{kz|b32} + ASMJIT_INST_2x(vpopcntw, Vpopcntw, Vec, Mem) // AVX512_BITALG{kz|b32} + ASMJIT_INST_3x(vpor, Vpor, Vec, Vec, Vec) // AV+ + ASMJIT_INST_3x(vpor, Vpor, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpord, Vpord, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpord, Vpord, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vporq, Vporq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vporq, Vporq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vprold, Vprold, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vprold, Vprold, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vprolq, Vprolq, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vprolq, Vprolq, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vprolvd, Vprolvd, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vprolvd, Vprolvd, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vprolvq, Vprolvq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vprolvq, Vprolvq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vprord, Vprord, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vprord, Vprord, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vprorq, Vprorq, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vprorq, Vprorq, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vprorvd, Vprorvd, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vprorvd, Vprorvd, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vprorvq, Vprorvq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vprorvq, Vprorvq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsadbw, Vpsadbw, Vec, Vec, Vec) // AVX+ AVX512_BW + ASMJIT_INST_3x(vpsadbw, Vpsadbw, Vec, Vec, Mem) // AVX+ AVX512_BW + ASMJIT_INST_2x(vpscatterdd, Vpscatterdd, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_2x(vpscatterdq, Vpscatterdq, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_2x(vpscatterqd, Vpscatterqd, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_2x(vpscatterqq, Vpscatterqq, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_4i(vpshldd, Vpshldd, Vec, Vec, Vec, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_4i(vpshldd, Vpshldd, Vec, Vec, Mem, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvd, Vpshldvd, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvd, Vpshldvd, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvq, Vpshldvq, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvq, Vpshldvq, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvw, Vpshldvw, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvw, Vpshldvw, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_4i(vpshrdd, Vpshrdd, Vec, Vec, Vec, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_4i(vpshrdd, Vpshrdd, Vec, Vec, Mem, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_4i(vpshrdw, Vpshrdw, Vec, Vec, Vec, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_4i(vpshrdw, Vpshrdw, Vec, Vec, Mem, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshufb, Vpshufb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpshufb, Vpshufb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Vec, Vec) // AVX512_BITALG{k} + ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Vec, Mem) // AVX512_BITALG{k} + ASMJIT_INST_3i(vpshufd, Vpshufd, Vec, Vec, Imm) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3i(vpshufd, Vpshufd, Vec, Mem, Imm) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3i(vpshufhw, Vpshufhw, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpshufhw, Vpshufhw, Vec, Mem, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpshuflw, Vpshuflw, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpshuflw, Vpshuflw, Vec, Mem, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsignb, Vpsignb, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpsignb, Vpsignb, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpsignd, Vpsignd, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpsignd, Vpsignd, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpsignw, Vpsignw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpsignw, Vpsignw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3i(vpslld, Vpslld, Vec, Vec, Imm) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpslld, Vpslld, Vec, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_3x(vpslld, Vpslld, Vec, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_3i(vpslld, Vpslld, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vpslldq, Vpslldq, Vec, Vec, Imm) // AVX+ AVX512_BW + ASMJIT_INST_3i(vpslldq, Vpslldq, Vec, Mem, Imm) // AVX512_BW + ASMJIT_INST_3i(vpsllq, Vpsllq, Vec, Vec, Imm) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsllq, Vpsllq, Vec, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_3x(vpsllq, Vpsllq, Vec, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_3i(vpsllq, Vpsllq, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsllvd, Vpsllvd, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsllvd, Vpsllvd, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsllvq, Vpsllvq, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsllvq, Vpsllvq, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsllvw, Vpsllvw, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpsllvw, Vpsllvw, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3i(vpsllw, Vpsllw, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsllw, Vpsllw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsllw, Vpsllw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpsllw, Vpsllw, Vec, Mem, Imm) // AVX512_BW{kz} + ASMJIT_INST_3i(vpsrad, Vpsrad, Vec, Vec, Imm) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsrad, Vpsrad, Vec, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_3x(vpsrad, Vpsrad, Vec, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_3i(vpsrad, Vpsrad, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsraq, Vpsraq, Vec, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_3x(vpsraq, Vpsraq, Vec, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_3i(vpsraq, Vpsraq, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vpsraq, Vpsraq, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsravd, Vpsravd, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsravd, Vpsravd, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsravq, Vpsravq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsravq, Vpsravq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsravw, Vpsravw, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpsravw, Vpsravw, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3i(vpsraw, Vpsraw, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsraw, Vpsraw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsraw, Vpsraw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpsraw, Vpsraw, Vec, Mem, Imm) // AVX512_BW{kz} + ASMJIT_INST_3i(vpsrld, Vpsrld, Vec, Vec, Imm) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsrld, Vpsrld, Vec, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_3x(vpsrld, Vpsrld, Vec, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_3i(vpsrld, Vpsrld, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vpsrldq, Vpsrldq, Vec, Vec, Imm) // AVX+ AVX512_BW + ASMJIT_INST_3i(vpsrldq, Vpsrldq, Vec, Mem, Imm) // AVX512_BW + ASMJIT_INST_3i(vpsrlq, Vpsrlq, Vec, Vec, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsrlq, Vpsrlq, Vec, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_3x(vpsrlq, Vpsrlq, Vec, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_3i(vpsrlq, Vpsrlq, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3i(vpsrlw, Vpsrlw, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsrlw, Vpsrlw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsrlw, Vpsrlw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpsrlw, Vpsrlw, Vec, Mem, Imm) // AVX512_BW{kz} + ASMJIT_INST_3x(vpsubb, Vpsubb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubb, Vpsubb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubd, Vpsubd, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsubd, Vpsubd, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsubq, Vpsubq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsubq, Vpsubq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsubsb, Vpsubsb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubsb, Vpsubsb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubsw, Vpsubsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubsw, Vpsubsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubusb, Vpsubusb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubusb, Vpsubusb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubusw, Vpsubusw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubusw, Vpsubusw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubw, Vpsubw, Vec, Vec, Vec) // AVX AVX512_BW{kz} + ASMJIT_INST_3x(vpsubw, Vpsubw, Vec, Vec, Mem) // AVX AVX512_BW{kz} + ASMJIT_INST_4i(vpternlogd, Vpternlogd, Vec, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vpternlogd, Vpternlogd, Vec, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vpternlogq, Vpternlogq, Vec, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vpternlogq, Vpternlogq, Vec, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vptest, Vptest, Vec, Vec) // AVX + ASMJIT_INST_2x(vptest, Vptest, Vec, Mem) // AVX + ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Vec, Vec) // AVX512_F{k|b32} + ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Vec, Mem) // AVX512_F{k|b32} + ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Vec, Vec) // AVX512_F{k|b64} + ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Vec, Mem) // AVX512_F{k|b64} + ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Vec, Vec) // AVX512_F{k|b32} + ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Vec, Mem) // AVX512_F{k|b32} + ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Vec, Vec) // AVX512_F{k|b64} + ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Vec, Mem) // AVX512_F{k|b64} + ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpxor, Vpxor, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpxor, Vpxor, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpxord, Vpxord, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpxord, Vpxord, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpxorq, Vpxorq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpxorq, Vpxorq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vrangepd, Vrangepd, Vec, Vec, Vec, Imm) // AVX512_DQ{kz|b64} + ASMJIT_INST_4i(vrangepd, Vrangepd, Vec, Vec, Mem, Imm) // AVX512_DQ{kz|b64} + ASMJIT_INST_4i(vrangeps, Vrangeps, Vec, Vec, Vec, Imm) // AVX512_DQ{kz|b32} + ASMJIT_INST_4i(vrangeps, Vrangeps, Vec, Vec, Mem, Imm) // AVX512_DQ{kz|b32} ASMJIT_INST_4i(vrangesd, Vrangesd, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz|sae} ASMJIT_INST_4i(vrangesd, Vrangesd, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz|sae} ASMJIT_INST_4i(vrangess, Vrangess, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz|sae} ASMJIT_INST_4i(vrangess, Vrangess, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz|sae} - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Zmm, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Vec, Mem) // AVX512_F{kz|b32} ASMJIT_INST_3x(vrcp14sd, Vrcp14sd, Xmm, Xmm, Xmm) // AVX512_F{kz} ASMJIT_INST_3x(vrcp14sd, Vrcp14sd, Xmm, Xmm, Mem) // AVX512_F{kz} ASMJIT_INST_3x(vrcp14ss, Vrcp14ss, Xmm, Xmm, Xmm) // AVX512_F{kz} ASMJIT_INST_3x(vrcp14ss, Vrcp14ss, Xmm, Xmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vrcp28pd, Vrcp28pd, Zmm, Zmm) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vrcp28pd, Vrcp28pd, Zmm, Mem) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vrcp28ps, Vrcp28ps, Zmm, Zmm) // AVX512_ER{kz|sae|b32} - ASMJIT_INST_2x(vrcp28ps, Vrcp28ps, Zmm, Mem) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vrcp28pd, Vrcp28pd, Vec, Vec) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vrcp28pd, Vrcp28pd, Vec, Mem) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vrcp28ps, Vrcp28ps, Vec, Vec) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vrcp28ps, Vrcp28ps, Vec, Mem) // AVX512_ER{kz|sae|b32} ASMJIT_INST_3x(vrcp28sd, Vrcp28sd, Xmm, Xmm, Xmm) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrcp28sd, Vrcp28sd, Xmm, Xmm, Mem) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrcp28ss, Vrcp28ss, Xmm, Xmm, Xmm) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrcp28ss, Vrcp28ss, Xmm, Xmm, Mem) // AVX512_ER{kz|sae} - ASMJIT_INST_2x(vrcpps, Vrcpps, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vrcpps, Vrcpps, Xmm, Mem) // AVX - ASMJIT_INST_2x(vrcpps, Vrcpps, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vrcpps, Vrcpps, Ymm, Mem) // AVX + ASMJIT_INST_2x(vrcpps, Vrcpps, Vec, Vec) // AVX + ASMJIT_INST_2x(vrcpps, Vrcpps, Vec, Mem) // AVX ASMJIT_INST_3x(vrcpss, Vrcpss, Xmm, Xmm, Xmm) // AVX ASMJIT_INST_3x(vrcpss, Vrcpss, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3i(vreducepd, Vreducepd, Xmm, Xmm, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3i(vreducepd, Vreducepd, Xmm, Mem, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3i(vreducepd, Vreducepd, Ymm, Ymm, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3i(vreducepd, Vreducepd, Ymm, Mem, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3i(vreducepd, Vreducepd, Zmm, Zmm, Imm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3i(vreducepd, Vreducepd, Zmm, Mem, Imm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3i(vreduceps, Vreduceps, Xmm, Xmm, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3i(vreduceps, Vreduceps, Xmm, Mem, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3i(vreduceps, Vreduceps, Ymm, Ymm, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3i(vreduceps, Vreduceps, Ymm, Mem, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3i(vreduceps, Vreduceps, Zmm, Zmm, Imm) // AVX512_DQ{kz|b32} - ASMJIT_INST_3i(vreduceps, Vreduceps, Zmm, Mem, Imm) // AVX512_DQ{kz|b32} + ASMJIT_INST_3i(vreducepd, Vreducepd, Vec, Vec, Imm) // AVX512_DQ{kz|b64} + ASMJIT_INST_3i(vreducepd, Vreducepd, Vec, Mem, Imm) // AVX512_DQ{kz|b64} + ASMJIT_INST_3i(vreduceps, Vreduceps, Vec, Vec, Imm) // AVX512_DQ{kz|b32} + ASMJIT_INST_3i(vreduceps, Vreduceps, Vec, Mem, Imm) // AVX512_DQ{kz|b32} ASMJIT_INST_4i(vreducesd, Vreducesd, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz} ASMJIT_INST_4i(vreducesd, Vreducesd, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz} ASMJIT_INST_4i(vreducess, Vreducess, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz} ASMJIT_INST_4i(vreducess, Vreducess, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Zmm, Mem, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Zmm, Mem, Imm) // AVX512_F{kz|sae|b32} + ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Vec, Mem, Imm) // AVX512_F{kz|b32} ASMJIT_INST_4i(vrndscalesd, Vrndscalesd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vrndscalesd, Vrndscalesd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vrndscaless, Vrndscaless, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vrndscaless, Vrndscaless, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} - ASMJIT_INST_3i(vroundpd, Vroundpd, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_3i(vroundpd, Vroundpd, Xmm, Mem, Imm) // AVX - ASMJIT_INST_3i(vroundpd, Vroundpd, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_3i(vroundpd, Vroundpd, Ymm, Mem, Imm) // AVX - ASMJIT_INST_3i(vroundps, Vroundps, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_3i(vroundps, Vroundps, Xmm, Mem, Imm) // AVX - ASMJIT_INST_3i(vroundps, Vroundps, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_3i(vroundps, Vroundps, Ymm, Mem, Imm) // AVX + ASMJIT_INST_3i(vroundpd, Vroundpd, Vec, Vec, Imm) // AVX + ASMJIT_INST_3i(vroundpd, Vroundpd, Vec, Mem, Imm) // AVX + ASMJIT_INST_3i(vroundps, Vroundps, Vec, Vec, Imm) // AVX + ASMJIT_INST_3i(vroundps, Vroundps, Vec, Mem, Imm) // AVX ASMJIT_INST_4i(vroundsd, Vroundsd, Xmm, Xmm, Xmm, Imm) // AVX ASMJIT_INST_4i(vroundsd, Vroundsd, Xmm, Xmm, Mem, Imm) // AVX ASMJIT_INST_4i(vroundss, Vroundss, Xmm, Xmm, Xmm, Imm) // AVX ASMJIT_INST_4i(vroundss, Vroundss, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Zmm, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Vec, Mem) // AVX512_F{kz|b32} ASMJIT_INST_3x(vrsqrt14sd, Vrsqrt14sd, Xmm, Xmm, Xmm) // AVX512_F{kz} ASMJIT_INST_3x(vrsqrt14sd, Vrsqrt14sd, Xmm, Xmm, Mem) // AVX512_F{kz} ASMJIT_INST_3x(vrsqrt14ss, Vrsqrt14ss, Xmm, Xmm, Xmm) // AVX512_F{kz} ASMJIT_INST_3x(vrsqrt14ss, Vrsqrt14ss, Xmm, Xmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vrsqrt28pd, Vrsqrt28pd, Zmm, Zmm) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vrsqrt28pd, Vrsqrt28pd, Zmm, Mem) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vrsqrt28ps, Vrsqrt28ps, Zmm, Zmm) // AVX512_ER{kz|sae|b32} - ASMJIT_INST_2x(vrsqrt28ps, Vrsqrt28ps, Zmm, Mem) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vrsqrt28pd, Vrsqrt28pd, Vec, Vec) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vrsqrt28pd, Vrsqrt28pd, Vec, Mem) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vrsqrt28ps, Vrsqrt28ps, Vec, Vec) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vrsqrt28ps, Vrsqrt28ps, Vec, Mem) // AVX512_ER{kz|sae|b32} ASMJIT_INST_3x(vrsqrt28sd, Vrsqrt28sd, Xmm, Xmm, Xmm) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrsqrt28sd, Vrsqrt28sd, Xmm, Xmm, Mem) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrsqrt28ss, Vrsqrt28ss, Xmm, Xmm, Xmm) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrsqrt28ss, Vrsqrt28ss, Xmm, Xmm, Mem) // AVX512_ER{kz|sae} - ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Xmm, Mem) // AVX - ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Ymm, Mem) // AVX + ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Vec, Vec) // AVX + ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Vec, Mem) // AVX ASMJIT_INST_3x(vrsqrtss, Vrsqrtss, Xmm, Xmm, Xmm) // AVX ASMJIT_INST_3x(vrsqrtss, Vrsqrtss, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Zmm, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vscalefps, Vscalefps, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vscalefps, Vscalefps, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vscalefps, Vscalefps, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vscalefps, Vscalefps, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vscalefps, Vscalefps, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vscalefps, Vscalefps, Zmm, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vscalefpd, Vscalefpd, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vscalefpd, Vscalefpd, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vscalefps, Vscalefps, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vscalefps, Vscalefps, Vec, Vec, Mem) // AVX512_F{kz|b32} ASMJIT_INST_3x(vscalefsd, Vscalefsd, Xmm, Xmm, Xmm) // AVX512_F{kz|er} ASMJIT_INST_3x(vscalefsd, Vscalefsd, Xmm, Xmm, Mem) // AVX512_F{kz|er} ASMJIT_INST_3x(vscalefss, Vscalefss, Xmm, Xmm, Xmm) // AVX512_F{kz|er} ASMJIT_INST_3x(vscalefss, Vscalefss, Xmm, Xmm, Mem) // AVX512_F{kz|er} - ASMJIT_INST_2x(vscatterdpd, Vscatterdpd, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterdpd, Vscatterdpd, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterdpd, Vscatterdpd, Mem, Zmm) // AVX512_F{k} - ASMJIT_INST_2x(vscatterdps, Vscatterdps, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterdps, Vscatterdps, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterdps, Vscatterdps, Mem, Zmm) // AVX512_F{k} + ASMJIT_INST_2x(vscatterdpd, Vscatterdpd, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_2x(vscatterdps, Vscatterdps, Mem, Vec) // AVX512_F{k} ASMJIT_INST_1x(vscatterpf0dpd, Vscatterpf0dpd, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vscatterpf0dps, Vscatterpf0dps, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vscatterpf0qpd, Vscatterpf0qpd, Mem) // AVX512_PF{k} @@ -4896,120 +3251,57 @@ public: ASMJIT_INST_1x(vscatterpf1dps, Vscatterpf1dps, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vscatterpf1qpd, Vscatterpf1qpd, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vscatterpf1qps, Vscatterpf1qps, Mem) // AVX512_PF{k} - ASMJIT_INST_2x(vscatterqpd, Vscatterqpd, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterqpd, Vscatterqpd, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterqpd, Vscatterqpd, Mem, Zmm) // AVX512_F{k} - ASMJIT_INST_2x(vscatterqps, Vscatterqps, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterqps, Vscatterqps, Mem, Ymm) // AVX512_F{k} - ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vshufpd, Vshufpd, Xmm, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufpd, Vshufpd, Xmm, Xmm, Mem, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufpd, Vshufpd, Ymm, Ymm, Ymm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufpd, Vshufpd, Ymm, Ymm, Mem, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufpd, Vshufpd, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshufpd, Vshufpd, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshufps, Vshufps, Xmm, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufps, Vshufps, Xmm, Xmm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufps, Vshufps, Ymm, Ymm, Ymm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufps, Vshufps, Ymm, Ymm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufps, Vshufps, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vshufps, Vshufps, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_2x(vscatterqpd, Vscatterqpd, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_2x(vscatterqps, Vscatterqps, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Vec, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Vec, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Vec, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Vec, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Vec, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Vec, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Vec, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Vec, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vshufpd, Vshufpd, Vec, Vec, Vec, Imm) // AVX AVX512_F{kz|b32} + ASMJIT_INST_4i(vshufpd, Vshufpd, Vec, Vec, Mem, Imm) // AVX AVX512_F{kz|b32} + ASMJIT_INST_4i(vshufps, Vshufps, Vec, Vec, Vec, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_4i(vshufps, Vshufps, Vec, Vec, Mem, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vsqrtps, Vsqrtps, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vsqrtps, Vsqrtps, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_3x(vsqrtsd, Vsqrtsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsqrtsd, Vsqrtsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsqrtss, Vsqrtss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsqrtss, Vsqrtss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_1x(vstmxcsr, Vstmxcsr, Mem) // AVX - ASMJIT_INST_3x(vsubpd, Vsubpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vsubpd, Vsubpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vsubpd, Vsubpd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vsubpd, Vsubpd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vsubpd, Vsubpd, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vsubpd, Vsubpd, Zmm, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vsubps, Vsubps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vsubps, Vsubps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vsubps, Vsubps, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vsubps, Vsubps, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vsubps, Vsubps, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vsubps, Vsubps, Zmm, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vsubpd, Vsubpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vsubpd, Vsubpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vsubps, Vsubps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vsubps, Vsubps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_3x(vsubsd, Vsubsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsubsd, Vsubsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsubss, Vsubss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsubss, Vsubss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} - ASMJIT_INST_2x(vtestpd, Vtestpd, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vtestpd, Vtestpd, Xmm, Mem) // AVX - ASMJIT_INST_2x(vtestpd, Vtestpd, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vtestpd, Vtestpd, Ymm, Mem) // AVX - ASMJIT_INST_2x(vtestps, Vtestps, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vtestps, Vtestps, Xmm, Mem) // AVX - ASMJIT_INST_2x(vtestps, Vtestps, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vtestps, Vtestps, Ymm, Mem) // AVX + ASMJIT_INST_2x(vtestpd, Vtestpd, Vec, Vec) // AVX + ASMJIT_INST_2x(vtestpd, Vtestpd, Vec, Mem) // AVX + ASMJIT_INST_2x(vtestps, Vtestps, Vec, Vec) // AVX + ASMJIT_INST_2x(vtestps, Vtestps, Vec, Mem) // AVX ASMJIT_INST_2x(vucomisd, Vucomisd, Xmm, Xmm) // AVX AVX512_F{sae} ASMJIT_INST_2x(vucomisd, Vucomisd, Xmm, Mem) // AVX AVX512_F{sae} ASMJIT_INST_2x(vucomiss, Vucomiss, Xmm, Xmm) // AVX AVX512_F{sae} ASMJIT_INST_2x(vucomiss, Vucomiss, Xmm, Mem) // AVX AVX512_F{sae} - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vxorpd, Vxorpd, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vxorpd, Vxorpd, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vxorpd, Vxorpd, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vxorpd, Vxorpd, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vxorpd, Vxorpd, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vxorpd, Vxorpd, Zmm, Zmm, Mem) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vxorps, Vxorps, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vxorps, Vxorps, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vxorps, Vxorps, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vxorps, Vxorps, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vxorps, Vxorps, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b32} - ASMJIT_INST_3x(vxorps, Vxorps, Zmm, Zmm, Mem) // AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vunpckhps, Vunpckhps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vunpckhps, Vunpckhps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vunpcklps, Vunpcklps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vunpcklps, Vunpcklps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vxorpd, Vxorpd, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vxorpd, Vxorpd, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vxorps, Vxorps, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vxorps, Vxorps, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b32} ASMJIT_INST_0x(vzeroall, Vzeroall) // AVX ASMJIT_INST_0x(vzeroupper, Vzeroupper) // AVX @@ -5018,96 +3310,60 @@ public: //! \name FMA4 Instructions //! \{ - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Ymm, Ymm, Ymm, Mem) // FMA4 + ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmaddps, Vfmaddps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddps, Vfmaddps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddps, Vfmaddps, Vec, Vec, Vec, Mem) // FMA4 ASMJIT_INST_4x(vfmaddsd, Vfmaddsd, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfmaddsd, Vfmaddsd, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfmaddsd, Vfmaddsd, Xmm, Xmm, Xmm, Mem) // FMA4 ASMJIT_INST_4x(vfmaddss, Vfmaddss, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfmaddss, Vfmaddss, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfmaddss, Vfmaddss, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Ymm, Ymm, Ymm, Mem) // FMA4 + ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmsubps, Vfmsubps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubps, Vfmsubps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubps, Vfmsubps, Vec, Vec, Vec, Mem) // FMA4 ASMJIT_INST_4x(vfmsubsd, Vfmsubsd, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfmsubsd, Vfmsubsd, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfmsubsd, Vfmsubsd, Xmm, Xmm, Xmm, Mem) // FMA4 ASMJIT_INST_4x(vfmsubss, Vfmsubss, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfmsubss, Vfmsubss, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfmsubss, Vfmsubss, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Ymm, Ymm, Ymm, Mem) // FMA4 + ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Vec, Vec, Vec, Mem) // FMA4 ASMJIT_INST_4x(vfnmaddsd, Vfnmaddsd, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfnmaddsd, Vfnmaddsd, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfnmaddsd, Vfnmaddsd, Xmm, Xmm, Xmm, Mem) // FMA4 ASMJIT_INST_4x(vfnmaddss, Vfnmaddss, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfnmaddss, Vfnmaddss, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfnmaddss, Vfnmaddss, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Ymm, Ymm, Ymm, Mem) // FMA4 + ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Vec, Vec, Vec, Mem) // FMA4 ASMJIT_INST_4x(vfnmsubsd, Vfnmsubsd, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfnmsubsd, Vfnmsubsd, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfnmsubsd, Vfnmsubsd, Xmm, Xmm, Xmm, Mem) // FMA4 @@ -5120,24 +3376,17 @@ public: //! \name XOP Instructions (Deprecated) //! \{ - ASMJIT_INST_2x(vfrczpd, Vfrczpd, Xmm, Xmm) // XOP - ASMJIT_INST_2x(vfrczpd, Vfrczpd, Xmm, Mem) // XOP - ASMJIT_INST_2x(vfrczpd, Vfrczpd, Ymm, Ymm) // XOP - ASMJIT_INST_2x(vfrczpd, Vfrczpd, Ymm, Mem) // XOP - ASMJIT_INST_2x(vfrczps, Vfrczps, Xmm, Xmm) // XOP - ASMJIT_INST_2x(vfrczps, Vfrczps, Xmm, Mem) // XOP - ASMJIT_INST_2x(vfrczps, Vfrczps, Ymm, Ymm) // XOP - ASMJIT_INST_2x(vfrczps, Vfrczps, Ymm, Mem) // XOP + ASMJIT_INST_2x(vfrczpd, Vfrczpd, Vec, Vec) // XOP + ASMJIT_INST_2x(vfrczpd, Vfrczpd, Vec, Mem) // XOP + ASMJIT_INST_2x(vfrczps, Vfrczps, Vec, Vec) // XOP + ASMJIT_INST_2x(vfrczps, Vfrczps, Vec, Mem) // XOP ASMJIT_INST_2x(vfrczsd, Vfrczsd, Xmm, Xmm) // XOP ASMJIT_INST_2x(vfrczsd, Vfrczsd, Xmm, Mem) // XOP ASMJIT_INST_2x(vfrczss, Vfrczss, Xmm, Xmm) // XOP ASMJIT_INST_2x(vfrczss, Vfrczss, Xmm, Mem) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Xmm, Xmm, Xmm, Xmm) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Xmm, Xmm, Mem, Xmm) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Xmm, Xmm, Xmm, Mem) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Ymm, Ymm, Ymm, Ymm) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Ymm, Ymm, Mem, Ymm) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Ymm, Ymm, Ymm, Mem) // XOP + ASMJIT_INST_4x(vpcmov, Vpcmov, Vec, Vec, Vec, Vec) // XOP + ASMJIT_INST_4x(vpcmov, Vpcmov, Vec, Vec, Mem, Vec) // XOP + ASMJIT_INST_4x(vpcmov, Vpcmov, Vec, Vec, Vec, Mem) // XOP ASMJIT_INST_4i(vpcomb, Vpcomb, Xmm, Xmm, Xmm, Imm) // XOP ASMJIT_INST_4i(vpcomb, Vpcomb, Xmm, Xmm, Mem, Imm) // XOP ASMJIT_INST_4i(vpcomd, Vpcomd, Xmm, Xmm, Xmm, Imm) // XOP @@ -5154,18 +3403,12 @@ public: ASMJIT_INST_4i(vpcomuq, Vpcomuq, Xmm, Xmm, Mem, Imm) // XOP ASMJIT_INST_4i(vpcomuw, Vpcomuw, Xmm, Xmm, Xmm, Imm) // XOP ASMJIT_INST_4i(vpcomuw, Vpcomuw, Xmm, Xmm, Mem, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Xmm, Xmm, Xmm, Xmm, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Xmm, Xmm, Mem, Xmm, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Xmm, Xmm, Xmm, Mem, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Ymm, Ymm, Ymm, Ymm, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Ymm, Ymm, Mem, Ymm, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Ymm, Ymm, Ymm, Mem, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Xmm, Xmm, Xmm, Xmm, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Xmm, Xmm, Mem, Xmm, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Xmm, Xmm, Xmm, Mem, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Ymm, Ymm, Ymm, Ymm, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Ymm, Ymm, Mem, Ymm, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Ymm, Ymm, Ymm, Mem, Imm) // XOP + ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Vec, Vec, Vec, Vec, Imm) // XOP + ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Vec, Vec, Mem, Vec, Imm) // XOP + ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Vec, Vec, Vec, Mem, Imm) // XOP + ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Vec, Vec, Vec, Vec, Imm) // XOP + ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Vec, Vec, Mem, Vec, Imm) // XOP + ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Vec, Vec, Vec, Mem, Imm) // XOP ASMJIT_INST_2x(vphaddbd, Vphaddbd, Xmm, Xmm) // XOP ASMJIT_INST_2x(vphaddbd, Vphaddbd, Xmm, Mem) // XOP ASMJIT_INST_2x(vphaddbq, Vphaddbq, Xmm, Xmm) // XOP diff --git a/3rdparty/asmjit/src/asmjit/x86/x86features.cpp b/3rdparty/asmjit/src/asmjit/x86/x86features.cpp index 6ee5772374b..7c9505da197 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86features.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86features.cpp @@ -106,22 +106,25 @@ static inline void simplifyCpuVendor(CpuInfo& cpu, uint32_t d0, uint32_t d1, uin } static inline void simplifyCpuBrand(char* s) noexcept { - // Used to always clear the current character to ensure that the result - // doesn't contain garbage after the new zero terminator. char* d = s; + char c = s[0]; char prev = 0; - char curr = s[0]; + + // Used to always clear the current character to ensure that the result + // doesn't contain garbage after a new null terminator is placed at the end. s[0] = '\0'; for (;;) { - if (curr == 0) + if (!c) break; - if (!(curr == ' ' && (prev == '@' || s[1] == ' ' || s[1] == '@'))) - *d++ = prev = curr; + if (!(c == ' ' && (prev == '@' || s[1] == ' ' || s[1] == '@'))) { + *d++ = c; + prev = c; + } - curr = *++s; + c = *++s; s[0] = '\0'; } @@ -136,7 +139,9 @@ ASMJIT_FAVOR_SIZE void detectCpu(CpuInfo& cpu) noexcept { Features& features = cpu._features.as<Features>(); cpu.reset(); - cpu._archInfo.init(ArchInfo::kIdHost); + cpu._arch = Environment::kArchHost; + cpu._subArch = Environment::kSubArchUnknown; + cpu._reserved = 0; cpu._maxLogicalProcessors = 1; features.add(Features::kI486); diff --git a/3rdparty/asmjit/src/asmjit/x86/x86features.h b/3rdparty/asmjit/src/asmjit/x86/x86features.h index d73c063877f..b26b52454b1 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86features.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86features.h @@ -40,6 +40,8 @@ class Features : public BaseFeatures { public: //! CPU feature ID. enum Id : uint32_t { + // @EnumValuesBegin{"enum": "x86::Features::Id"}@ + kNone = 0, //!< No feature (never set, used internally). kMT, //!< CPU has multi-threading capabilities. @@ -145,6 +147,8 @@ public: kXSAVEOPT, //!< CPU has XSAVEOPT. kXSAVES, //!< CPU has XSAVES. + // @EnumValuesEnd@ + kCount //!< Count of X86 CPU features. }; diff --git a/3rdparty/asmjit/src/asmjit/x86/x86logging.cpp b/3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp index cfb91dbf596..06553e401e0 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86logging.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp @@ -26,8 +26,9 @@ #include "../core/misc_p.h" #include "../core/support.h" +#include "../x86/x86features.h" +#include "../x86/x86formatter_p.h" #include "../x86/x86instdb_p.h" -#include "../x86/x86logging_p.h" #include "../x86/x86operand.h" #ifndef ASMJIT_NO_COMPILER @@ -37,7 +38,7 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // ============================================================================ -// [asmjit::x86::LoggingInternal - Constants] +// [asmjit::x86::FormatterInternal - Constants] // ============================================================================ struct RegFormatInfo { @@ -196,56 +197,181 @@ static const char* x86GetAddressSizeString(uint32_t size) noexcept { } // ============================================================================ -// [asmjit::x86::LoggingInternal - Format Operand] +// [asmjit::x86::FormatterInternal - Format Feature] // ============================================================================ -ASMJIT_FAVOR_SIZE Error LoggingInternal::formatOperand( +Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept { + // @EnumStringBegin{"enum": "x86::Features::Id", "output": "sFeature", "strip": "k"}@ + static const char sFeatureString[] = + "None\0" + "MT\0" + "NX\0" + "3DNOW\0" + "3DNOW2\0" + "ADX\0" + "AESNI\0" + "ALTMOVCR8\0" + "AVX\0" + "AVX2\0" + "AVX512_4FMAPS\0" + "AVX512_4VNNIW\0" + "AVX512_BF16\0" + "AVX512_BITALG\0" + "AVX512_BW\0" + "AVX512_CDI\0" + "AVX512_DQ\0" + "AVX512_ERI\0" + "AVX512_F\0" + "AVX512_IFMA\0" + "AVX512_PFI\0" + "AVX512_VBMI\0" + "AVX512_VBMI2\0" + "AVX512_VL\0" + "AVX512_VNNI\0" + "AVX512_VP2INTERSECT\0" + "AVX512_VPOPCNTDQ\0" + "BMI\0" + "BMI2\0" + "CLDEMOTE\0" + "CLFLUSH\0" + "CLFLUSHOPT\0" + "CLWB\0" + "CLZERO\0" + "CMOV\0" + "CMPXCHG16B\0" + "CMPXCHG8B\0" + "ENCLV\0" + "ENQCMD\0" + "ERMS\0" + "F16C\0" + "FMA\0" + "FMA4\0" + "FPU\0" + "FSGSBASE\0" + "FXSR\0" + "FXSROPT\0" + "GEODE\0" + "GFNI\0" + "HLE\0" + "I486\0" + "LAHFSAHF\0" + "LWP\0" + "LZCNT\0" + "MMX\0" + "MMX2\0" + "MONITOR\0" + "MONITORX\0" + "MOVBE\0" + "MOVDIR64B\0" + "MOVDIRI\0" + "MPX\0" + "MSR\0" + "MSSE\0" + "OSXSAVE\0" + "PCLMULQDQ\0" + "PCOMMIT\0" + "PCONFIG\0" + "POPCNT\0" + "PREFETCHW\0" + "PREFETCHWT1\0" + "RDPID\0" + "RDRAND\0" + "RDSEED\0" + "RDTSC\0" + "RDTSCP\0" + "RTM\0" + "SHA\0" + "SKINIT\0" + "SMAP\0" + "SMEP\0" + "SMX\0" + "SSE\0" + "SSE2\0" + "SSE3\0" + "SSE4_1\0" + "SSE4_2\0" + "SSE4A\0" + "SSSE3\0" + "SVM\0" + "TBM\0" + "TSX\0" + "VAES\0" + "VMX\0" + "VPCLMULQDQ\0" + "WAITPKG\0" + "WBNOINVD\0" + "XOP\0" + "XSAVE\0" + "XSAVEC\0" + "XSAVEOPT\0" + "XSAVES\0" + "<Unknown>\0"; + + static const uint16_t sFeatureIndex[] = { + 0, 5, 8, 11, 17, 24, 28, 34, 44, 48, 53, 67, 81, 93, 107, 117, 128, 138, + 149, 158, 170, 181, 193, 206, 216, 228, 248, 265, 269, 274, 283, 291, 302, + 307, 314, 319, 330, 340, 346, 353, 358, 363, 367, 372, 376, 385, 390, 398, + 404, 409, 413, 418, 427, 431, 437, 441, 446, 454, 463, 469, 479, 487, 491, + 495, 500, 508, 518, 526, 534, 541, 551, 563, 569, 576, 583, 589, 596, 600, + 604, 611, 616, 621, 625, 629, 634, 639, 646, 653, 659, 665, 669, 673, 677, + 682, 686, 697, 705, 714, 718, 724, 731, 740, 747 + }; + // @EnumStringEnd@ + + return sb.append(sFeatureString + sFeatureIndex[Support::min<uint32_t>(featureId, x86::Features::kCount)]); +} + +// ============================================================================ +// [asmjit::x86::FormatterInternal - Format Operand] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand( String& sb, uint32_t flags, const BaseEmitter* emitter, - uint32_t archId, + uint32_t arch, const Operand_& op) noexcept { if (op.isReg()) - return formatRegister(sb, flags, emitter, archId, op.as<BaseReg>().type(), op.as<BaseReg>().id()); + return formatRegister(sb, flags, emitter, arch, op.as<BaseReg>().type(), op.as<BaseReg>().id()); if (op.isMem()) { const Mem& m = op.as<Mem>(); - ASMJIT_PROPAGATE(sb.appendString(x86GetAddressSizeString(m.size()))); + ASMJIT_PROPAGATE(sb.append(x86GetAddressSizeString(m.size()))); // Segment override prefix. uint32_t seg = m.segmentId(); if (seg != SReg::kIdNone && seg < SReg::kIdCount) - ASMJIT_PROPAGATE(sb.appendFormat("%s:", x86RegFormatInfo.nameStrings + 224 + seg * 4)); + ASMJIT_PROPAGATE(sb.appendFormat("%s:", x86RegFormatInfo.nameStrings + 224 + size_t(seg) * 4)); - ASMJIT_PROPAGATE(sb.appendChar('[')); + ASMJIT_PROPAGATE(sb.append('[')); switch (m.addrType()) { - case BaseMem::kAddrTypeAbs: ASMJIT_PROPAGATE(sb.appendString("abs ")); break; - case BaseMem::kAddrTypeRel: ASMJIT_PROPAGATE(sb.appendString("rel ")); break; + case BaseMem::kAddrTypeAbs: ASMJIT_PROPAGATE(sb.append("abs ")); break; + case BaseMem::kAddrTypeRel: ASMJIT_PROPAGATE(sb.append("rel ")); break; } char opSign = '\0'; if (m.hasBase()) { opSign = '+'; if (m.hasBaseLabel()) { - ASMJIT_PROPAGATE(Logging::formatLabel(sb, flags, emitter, m.baseId())); + ASMJIT_PROPAGATE(Formatter::formatLabel(sb, flags, emitter, m.baseId())); } else { uint32_t modifiedFlags = flags; if (m.isRegHome()) { - ASMJIT_PROPAGATE(sb.appendString("&")); + ASMJIT_PROPAGATE(sb.append("&")); modifiedFlags &= ~FormatOptions::kFlagRegCasts; } - ASMJIT_PROPAGATE(formatRegister(sb, modifiedFlags, emitter, archId, m.baseType(), m.baseId())); + ASMJIT_PROPAGATE(formatRegister(sb, modifiedFlags, emitter, arch, m.baseType(), m.baseId())); } } if (m.hasIndex()) { if (opSign) - ASMJIT_PROPAGATE(sb.appendChar(opSign)); + ASMJIT_PROPAGATE(sb.append(opSign)); opSign = '+'; - ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, archId, m.indexType(), m.indexId())); + ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, m.indexType(), m.indexId())); if (m.hasShift()) ASMJIT_PROPAGATE(sb.appendFormat("*%u", 1 << m.shift())); } @@ -258,26 +384,26 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatOperand( } if (opSign) - ASMJIT_PROPAGATE(sb.appendChar(opSign)); + ASMJIT_PROPAGATE(sb.append(opSign)); uint32_t base = 10; if ((flags & FormatOptions::kFlagHexOffsets) != 0 && off > 9) { - ASMJIT_PROPAGATE(sb.appendString("0x", 2)); + ASMJIT_PROPAGATE(sb.append("0x", 2)); base = 16; } ASMJIT_PROPAGATE(sb.appendUInt(off, base)); } - return sb.appendChar(']'); + return sb.append(']'); } if (op.isImm()) { const Imm& i = op.as<Imm>(); - int64_t val = i.i64(); + int64_t val = i.value(); if ((flags & FormatOptions::kFlagHexImms) != 0 && uint64_t(val) > 9) { - ASMJIT_PROPAGATE(sb.appendString("0x", 2)); + ASMJIT_PROPAGATE(sb.append("0x", 2)); return sb.appendUInt(uint64_t(val), 16); } else { @@ -286,14 +412,14 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatOperand( } if (op.isLabel()) { - return Logging::formatLabel(sb, flags, emitter, op.id()); + return Formatter::formatLabel(sb, flags, emitter, op.id()); } - return sb.appendString("<None>"); + return sb.append("<None>"); } // ============================================================================ -// [asmjit::x86::LoggingInternal - Format Immediate (Extension)] +// [asmjit::x86::FormatterInternal - Format Immediate (Extension)] // ============================================================================ static constexpr char kImmCharStart = '{'; @@ -312,22 +438,22 @@ struct ImmBits { char text[48 - 3]; }; -ASMJIT_FAVOR_SIZE static Error LoggingInternal_formatImmShuf(String& sb, uint32_t u8, uint32_t bits, uint32_t count) noexcept { +ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmShuf(String& sb, uint32_t u8, uint32_t bits, uint32_t count) noexcept { uint32_t mask = (1 << bits) - 1; for (uint32_t i = 0; i < count; i++, u8 >>= bits) { uint32_t value = u8 & mask; - ASMJIT_PROPAGATE(sb.appendChar(i == 0 ? kImmCharStart : kImmCharOr)); + ASMJIT_PROPAGATE(sb.append(i == 0 ? kImmCharStart : kImmCharOr)); ASMJIT_PROPAGATE(sb.appendUInt(value)); } if (kImmCharEnd) - ASMJIT_PROPAGATE(sb.appendChar(kImmCharEnd)); + ASMJIT_PROPAGATE(sb.append(kImmCharEnd)); return kErrorOk; } -ASMJIT_FAVOR_SIZE static Error LoggingInternal_formatImmBits(String& sb, uint32_t u8, const ImmBits* bits, uint32_t count) noexcept { +ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmBits(String& sb, uint32_t u8, const ImmBits* bits, uint32_t count) noexcept { uint32_t n = 0; char buf[64]; @@ -354,33 +480,33 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_formatImmBits(String& sb, uint32_ if (!str[0]) continue; - ASMJIT_PROPAGATE(sb.appendChar(++n == 1 ? kImmCharStart : kImmCharOr)); - ASMJIT_PROPAGATE(sb.appendString(str)); + ASMJIT_PROPAGATE(sb.append(++n == 1 ? kImmCharStart : kImmCharOr)); + ASMJIT_PROPAGATE(sb.append(str)); } if (n && kImmCharEnd) - ASMJIT_PROPAGATE(sb.appendChar(kImmCharEnd)); + ASMJIT_PROPAGATE(sb.append(kImmCharEnd)); return kErrorOk; } -ASMJIT_FAVOR_SIZE static Error LoggingInternal_formatImmText(String& sb, uint32_t u8, uint32_t bits, uint32_t advance, const char* text, uint32_t count = 1) noexcept { +ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmText(String& sb, uint32_t u8, uint32_t bits, uint32_t advance, const char* text, uint32_t count = 1) noexcept { uint32_t mask = (1u << bits) - 1; uint32_t pos = 0; for (uint32_t i = 0; i < count; i++, u8 >>= bits, pos += advance) { uint32_t value = (u8 & mask) + pos; - ASMJIT_PROPAGATE(sb.appendChar(i == 0 ? kImmCharStart : kImmCharOr)); - ASMJIT_PROPAGATE(sb.appendString(Support::findPackedString(text, value))); + ASMJIT_PROPAGATE(sb.append(i == 0 ? kImmCharStart : kImmCharOr)); + ASMJIT_PROPAGATE(sb.append(Support::findPackedString(text, value))); } if (kImmCharEnd) - ASMJIT_PROPAGATE(sb.appendChar(kImmCharEnd)); + ASMJIT_PROPAGATE(sb.append(kImmCharEnd)); return kErrorOk; } -ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( +ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst( String& sb, uint32_t flags, uint32_t instId, @@ -456,51 +582,51 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( { 0x08u, 3, ImmBits::kModeLookup, "\0" "INEXACT\0" } }; - uint32_t u8 = imm.u8(); + uint32_t u8 = imm.valueAs<uint8_t>(); switch (instId) { case Inst::kIdVblendpd: case Inst::kIdBlendpd: - return LoggingInternal_formatImmShuf(sb, u8, 1, vecSize / 8); + return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 8); case Inst::kIdVblendps: case Inst::kIdBlendps: - return LoggingInternal_formatImmShuf(sb, u8, 1, vecSize / 4); + return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 4); case Inst::kIdVcmppd: case Inst::kIdVcmpps: case Inst::kIdVcmpsd: case Inst::kIdVcmpss: - return LoggingInternal_formatImmText(sb, u8, 5, 0, vcmpx); + return FormatterInternal_formatImmText(sb, u8, 5, 0, vcmpx); case Inst::kIdCmppd: case Inst::kIdCmpps: case Inst::kIdCmpsd: case Inst::kIdCmpss: - return LoggingInternal_formatImmText(sb, u8, 3, 0, vcmpx); + return FormatterInternal_formatImmText(sb, u8, 3, 0, vcmpx); case Inst::kIdVdbpsadbw: - return LoggingInternal_formatImmShuf(sb, u8, 2, 4); + return FormatterInternal_formatImmShuf(sb, u8, 2, 4); case Inst::kIdVdppd: case Inst::kIdVdpps: case Inst::kIdDppd: case Inst::kIdDpps: - return LoggingInternal_formatImmShuf(sb, u8, 1, 8); + return FormatterInternal_formatImmShuf(sb, u8, 1, 8); case Inst::kIdVmpsadbw: case Inst::kIdMpsadbw: - return LoggingInternal_formatImmBits(sb, u8, vmpsadbw, Support::min<uint32_t>(vecSize / 8, 4)); + return FormatterInternal_formatImmBits(sb, u8, vmpsadbw, Support::min<uint32_t>(vecSize / 8, 4)); case Inst::kIdVpblendw: case Inst::kIdPblendw: - return LoggingInternal_formatImmShuf(sb, u8, 1, 8); + return FormatterInternal_formatImmShuf(sb, u8, 1, 8); case Inst::kIdVpblendd: - return LoggingInternal_formatImmShuf(sb, u8, 1, Support::min<uint32_t>(vecSize / 4, 8)); + return FormatterInternal_formatImmShuf(sb, u8, 1, Support::min<uint32_t>(vecSize / 4, 8)); case Inst::kIdVpclmulqdq: case Inst::kIdPclmulqdq: - return LoggingInternal_formatImmBits(sb, u8, vpclmulqdq, ASMJIT_ARRAY_SIZE(vpclmulqdq)); + return FormatterInternal_formatImmBits(sb, u8, vpclmulqdq, ASMJIT_ARRAY_SIZE(vpclmulqdq)); case Inst::kIdVroundpd: case Inst::kIdVroundps: @@ -510,57 +636,57 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( case Inst::kIdRoundps: case Inst::kIdRoundsd: case Inst::kIdRoundss: - return LoggingInternal_formatImmBits(sb, u8, vroundxx, ASMJIT_ARRAY_SIZE(vroundxx)); + return FormatterInternal_formatImmBits(sb, u8, vroundxx, ASMJIT_ARRAY_SIZE(vroundxx)); case Inst::kIdVshufpd: case Inst::kIdShufpd: - return LoggingInternal_formatImmText(sb, u8, 1, 2, vshufpd, Support::min<uint32_t>(vecSize / 8, 8)); + return FormatterInternal_formatImmText(sb, u8, 1, 2, vshufpd, Support::min<uint32_t>(vecSize / 8, 8)); case Inst::kIdVshufps: case Inst::kIdShufps: - return LoggingInternal_formatImmText(sb, u8, 2, 4, vshufps, 4); + return FormatterInternal_formatImmText(sb, u8, 2, 4, vshufps, 4); case Inst::kIdVcvtps2ph: - return LoggingInternal_formatImmBits(sb, u8, vroundxx, 1); + return FormatterInternal_formatImmBits(sb, u8, vroundxx, 1); case Inst::kIdVperm2f128: case Inst::kIdVperm2i128: - return LoggingInternal_formatImmBits(sb, u8, vperm2x128, ASMJIT_ARRAY_SIZE(vperm2x128)); + return FormatterInternal_formatImmBits(sb, u8, vperm2x128, ASMJIT_ARRAY_SIZE(vperm2x128)); case Inst::kIdVpermilpd: - return LoggingInternal_formatImmShuf(sb, u8, 1, vecSize / 8); + return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 8); case Inst::kIdVpermilps: - return LoggingInternal_formatImmShuf(sb, u8, 2, 4); + return FormatterInternal_formatImmShuf(sb, u8, 2, 4); case Inst::kIdVpshufd: case Inst::kIdPshufd: - return LoggingInternal_formatImmShuf(sb, u8, 2, 4); + return FormatterInternal_formatImmShuf(sb, u8, 2, 4); case Inst::kIdVpshufhw: case Inst::kIdVpshuflw: case Inst::kIdPshufhw: case Inst::kIdPshuflw: case Inst::kIdPshufw: - return LoggingInternal_formatImmShuf(sb, u8, 2, 4); + return FormatterInternal_formatImmShuf(sb, u8, 2, 4); case Inst::kIdVfixupimmpd: case Inst::kIdVfixupimmps: case Inst::kIdVfixupimmsd: case Inst::kIdVfixupimmss: - return LoggingInternal_formatImmBits(sb, u8, vfixupimmxx, ASMJIT_ARRAY_SIZE(vfixupimmxx)); + return FormatterInternal_formatImmBits(sb, u8, vfixupimmxx, ASMJIT_ARRAY_SIZE(vfixupimmxx)); case Inst::kIdVfpclasspd: case Inst::kIdVfpclassps: case Inst::kIdVfpclasssd: case Inst::kIdVfpclassss: - return LoggingInternal_formatImmBits(sb, u8, vfpclassxx, ASMJIT_ARRAY_SIZE(vfpclassxx)); + return FormatterInternal_formatImmBits(sb, u8, vfpclassxx, ASMJIT_ARRAY_SIZE(vfpclassxx)); case Inst::kIdVgetmantpd: case Inst::kIdVgetmantps: case Inst::kIdVgetmantsd: case Inst::kIdVgetmantss: - return LoggingInternal_formatImmBits(sb, u8, vgetmantxx, ASMJIT_ARRAY_SIZE(vgetmantxx)); + return FormatterInternal_formatImmBits(sb, u8, vgetmantxx, ASMJIT_ARRAY_SIZE(vgetmantxx)); case Inst::kIdVpcmpb: case Inst::kIdVpcmpd: @@ -570,7 +696,7 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( case Inst::kIdVpcmpud: case Inst::kIdVpcmpuq: case Inst::kIdVpcmpuw: - return LoggingInternal_formatImmText(sb, u8, 3, 0, vpcmpx); + return FormatterInternal_formatImmText(sb, u8, 3, 0, vpcmpx); case Inst::kIdVpcomb: case Inst::kIdVpcomd: @@ -580,21 +706,21 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( case Inst::kIdVpcomud: case Inst::kIdVpcomuq: case Inst::kIdVpcomuw: - return LoggingInternal_formatImmText(sb, u8, 3, 0, vpcomx); + return FormatterInternal_formatImmText(sb, u8, 3, 0, vpcomx); case Inst::kIdVpermq: case Inst::kIdVpermpd: - return LoggingInternal_formatImmShuf(sb, u8, 2, 4); + return FormatterInternal_formatImmShuf(sb, u8, 2, 4); case Inst::kIdVpternlogd: case Inst::kIdVpternlogq: - return LoggingInternal_formatImmShuf(sb, u8, 1, 8); + return FormatterInternal_formatImmShuf(sb, u8, 1, 8); case Inst::kIdVrangepd: case Inst::kIdVrangeps: case Inst::kIdVrangesd: case Inst::kIdVrangess: - return LoggingInternal_formatImmBits(sb, u8, vrangexx, ASMJIT_ARRAY_SIZE(vrangexx)); + return FormatterInternal_formatImmBits(sb, u8, vrangexx, ASMJIT_ARRAY_SIZE(vrangexx)); case Inst::kIdVreducepd: case Inst::kIdVreduceps: @@ -604,7 +730,7 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( case Inst::kIdVrndscaleps: case Inst::kIdVrndscalesd: case Inst::kIdVrndscaless: - return LoggingInternal_formatImmBits(sb, u8, vreducexx_vrndscalexx, ASMJIT_ARRAY_SIZE(vreducexx_vrndscalexx)); + return FormatterInternal_formatImmBits(sb, u8, vreducexx_vrndscalexx, ASMJIT_ARRAY_SIZE(vreducexx_vrndscalexx)); case Inst::kIdVshuff32x4: case Inst::kIdVshuff64x2: @@ -612,7 +738,7 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( case Inst::kIdVshufi64x2: { uint32_t count = Support::max<uint32_t>(vecSize / 16, 2u); uint32_t bits = count <= 2 ? 1u : 2u; - return LoggingInternal_formatImmShuf(sb, u8, bits, count); + return FormatterInternal_formatImmShuf(sb, u8, bits, count); } default: @@ -621,11 +747,11 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( } // ============================================================================ -// [asmjit::x86::LoggingInternal - Format Register] +// [asmjit::x86::FormatterInternal - Format Register] // ============================================================================ -ASMJIT_FAVOR_SIZE Error LoggingInternal::formatRegister(String& sb, uint32_t flags, const BaseEmitter* emitter, uint32_t archId, uint32_t rType, uint32_t rId) noexcept { - DebugUtils::unused(archId); +ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(String& sb, uint32_t flags, const BaseEmitter* emitter, uint32_t arch, uint32_t rType, uint32_t rId) noexcept { + DebugUtils::unused(arch); const RegFormatInfo& info = x86RegFormatInfo; #ifndef ASMJIT_NO_COMPILER @@ -638,7 +764,7 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatRegister(String& sb, uint32_t fla const char* name = vReg->name(); if (name && name[0] != '\0') - ASMJIT_PROPAGATE(sb.appendString(name)); + ASMJIT_PROPAGATE(sb.append(name)); else ASMJIT_PROPAGATE(sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(rId)))); @@ -660,7 +786,7 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatRegister(String& sb, uint32_t fla const RegFormatInfo::NameEntry& nameEntry = info.nameEntries[rType]; if (rId < nameEntry.specialCount) - return sb.appendString(info.nameStrings + nameEntry.specialIndex + rId * 4); + return sb.append(info.nameStrings + nameEntry.specialIndex + rId * 4); if (rId < nameEntry.count) return sb.appendFormat(info.nameStrings + nameEntry.formatIndex, unsigned(rId)); @@ -674,15 +800,15 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatRegister(String& sb, uint32_t fla } // ============================================================================ -// [asmjit::x86::LoggingInternal - Format Instruction] +// [asmjit::x86::FormatterInternal - Format Instruction] // ============================================================================ -ASMJIT_FAVOR_SIZE Error LoggingInternal::formatInstruction( +ASMJIT_FAVOR_SIZE Error FormatterInternal::formatInstruction( String& sb, uint32_t flags, const BaseEmitter* emitter, - uint32_t archId, - const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept { + uint32_t arch, + const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept { uint32_t instId = inst.id(); uint32_t options = inst.options(); @@ -690,21 +816,21 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatInstruction( // Format instruction options and instruction mnemonic. if (instId < Inst::_kIdCount) { // SHORT|LONG options. - if (options & Inst::kOptionShortForm) ASMJIT_PROPAGATE(sb.appendString("short ")); - if (options & Inst::kOptionLongForm) ASMJIT_PROPAGATE(sb.appendString("long ")); + if (options & Inst::kOptionShortForm) ASMJIT_PROPAGATE(sb.append("short ")); + if (options & Inst::kOptionLongForm) ASMJIT_PROPAGATE(sb.append("long ")); // LOCK|XACQUIRE|XRELEASE options. - if (options & Inst::kOptionXAcquire) ASMJIT_PROPAGATE(sb.appendString("xacquire ")); - if (options & Inst::kOptionXRelease) ASMJIT_PROPAGATE(sb.appendString("xrelease ")); - if (options & Inst::kOptionLock) ASMJIT_PROPAGATE(sb.appendString("lock ")); + if (options & Inst::kOptionXAcquire) ASMJIT_PROPAGATE(sb.append("xacquire ")); + if (options & Inst::kOptionXRelease) ASMJIT_PROPAGATE(sb.append("xrelease ")); + if (options & Inst::kOptionLock) ASMJIT_PROPAGATE(sb.append("lock ")); // REP|REPNE options. if (options & (Inst::kOptionRep | Inst::kOptionRepne)) { - sb.appendString((options & Inst::kOptionRep) ? "rep " : "repnz "); + sb.append((options & Inst::kOptionRep) ? "rep " : "repnz "); if (inst.hasExtraReg()) { - ASMJIT_PROPAGATE(sb.appendString("{")); - ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, archId, inst.extraReg().toReg<BaseReg>())); - ASMJIT_PROPAGATE(sb.appendString("} ")); + ASMJIT_PROPAGATE(sb.append("{")); + ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, arch, inst.extraReg().toReg<BaseReg>())); + ASMJIT_PROPAGATE(sb.append("} ")); } } @@ -715,23 +841,23 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatInstruction( Inst::kOptionOpCodeB | Inst::kOptionOpCodeW ; if (options & kRXBWMask) { - sb.appendString("rex."); - if (options & Inst::kOptionOpCodeR) sb.appendChar('r'); - if (options & Inst::kOptionOpCodeX) sb.appendChar('x'); - if (options & Inst::kOptionOpCodeB) sb.appendChar('b'); - if (options & Inst::kOptionOpCodeW) sb.appendChar('w'); - sb.appendChar(' '); + sb.append("rex."); + if (options & Inst::kOptionOpCodeR) sb.append('r'); + if (options & Inst::kOptionOpCodeX) sb.append('x'); + if (options & Inst::kOptionOpCodeB) sb.append('b'); + if (options & Inst::kOptionOpCodeW) sb.append('w'); + sb.append(' '); } else { - ASMJIT_PROPAGATE(sb.appendString("rex ")); + ASMJIT_PROPAGATE(sb.append("rex ")); } } // VEX|EVEX options. - if (options & Inst::kOptionVex3) ASMJIT_PROPAGATE(sb.appendString("vex3 ")); - if (options & Inst::kOptionEvex) ASMJIT_PROPAGATE(sb.appendString("evex ")); + if (options & Inst::kOptionVex3) ASMJIT_PROPAGATE(sb.append("vex3 ")); + if (options & Inst::kOptionEvex) ASMJIT_PROPAGATE(sb.append("evex ")); - ASMJIT_PROPAGATE(InstAPI::instIdToString(archId, instId, sb)); + ASMJIT_PROPAGATE(InstAPI::instIdToString(arch, instId, sb)); } else { ASMJIT_PROPAGATE(sb.appendFormat("[InstId=#%u]", unsigned(instId))); @@ -741,29 +867,29 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatInstruction( const Operand_& op = operands[i]; if (op.isNone()) break; - ASMJIT_PROPAGATE(sb.appendString(i == 0 ? " " : ", ")); - ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, archId, op)); + ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", ")); + ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, arch, op)); if (op.isImm() && (flags & FormatOptions::kFlagExplainImms)) { uint32_t vecSize = 16; for (uint32_t j = 0; j < opCount; j++) if (operands[j].isReg()) vecSize = Support::max<uint32_t>(vecSize, operands[j].size()); - ASMJIT_PROPAGATE(LoggingInternal_explainConst(sb, flags, instId, vecSize, op.as<Imm>())); + ASMJIT_PROPAGATE(FormatterInternal_explainConst(sb, flags, instId, vecSize, op.as<Imm>())); } // Support AVX-512 masking - {k}{z}. if (i == 0) { if (inst.extraReg().group() == Reg::kGroupKReg) { - ASMJIT_PROPAGATE(sb.appendString(" {")); - ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, archId, inst.extraReg().type(), inst.extraReg().id())); - ASMJIT_PROPAGATE(sb.appendChar('}')); + ASMJIT_PROPAGATE(sb.append(" {")); + ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, inst.extraReg().type(), inst.extraReg().id())); + ASMJIT_PROPAGATE(sb.append('}')); if (options & Inst::kOptionZMask) - ASMJIT_PROPAGATE(sb.appendString("{z}")); + ASMJIT_PROPAGATE(sb.append("{z}")); } else if (options & Inst::kOptionZMask) { - ASMJIT_PROPAGATE(sb.appendString(" {z}")); + ASMJIT_PROPAGATE(sb.append(" {z}")); } } diff --git a/3rdparty/asmjit/src/asmjit/x86/x86logging_p.h b/3rdparty/asmjit/src/asmjit/x86/x86formatter_p.h index c0d7d16e3f2..d7d58e42d67 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86logging_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86formatter_p.h @@ -21,52 +21,60 @@ // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. -#ifndef ASMJIT_X86_X86LOGGING_P_H_INCLUDED -#define ASMJIT_X86_X86LOGGING_P_H_INCLUDED +#ifndef ASMJIT_X86_X86FORMATTER_P_H_INCLUDED +#define ASMJIT_X86_X86FORMATTER_P_H_INCLUDED #include "../core/api-config.h" #ifndef ASMJIT_NO_LOGGING -#include "../core/logging.h" +#include "../core/formatter.h" #include "../core/string.h" #include "../x86/x86globals.h" ASMJIT_BEGIN_SUB_NAMESPACE(x86) +//! \cond INTERNAL //! \addtogroup asmjit_x86 //! \{ // ============================================================================ -// [asmjit::x86::LoggingInternal] +// [asmjit::x86::FormatterInternal] // ============================================================================ -namespace LoggingInternal { - Error formatRegister( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - uint32_t regType, - uint32_t regId) noexcept; +namespace FormatterInternal { - Error formatOperand( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const Operand_& op) noexcept; +Error formatFeature( + String& sb, + uint32_t featureId) noexcept; - Error formatInstruction( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept; -}; +Error formatRegister( + String& sb, + uint32_t flags, + const BaseEmitter* emitter, + uint32_t arch, + uint32_t regType, + uint32_t regId) noexcept; + +Error formatOperand( + String& sb, + uint32_t flags, + const BaseEmitter* emitter, + uint32_t arch, + const Operand_& op) noexcept; + +Error formatInstruction( + String& sb, + uint32_t flags, + const BaseEmitter* emitter, + uint32_t arch, + const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept; + +} // {FormatterInternal} //! \} +//! \endcond ASMJIT_END_SUB_NAMESPACE #endif // !ASMJIT_NO_LOGGING -#endif // ASMJIT_X86_X86LOGGING_P_H_INCLUDED +#endif // ASMJIT_X86_X86FORMATTER_P_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/x86/x86globals.h b/3rdparty/asmjit/src/asmjit/x86/x86globals.h index dca2b95732c..f7d258f3b62 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86globals.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86globals.h @@ -1652,14 +1652,14 @@ namespace Condition { kUnsignedGT = kA, //!< Unsigned `a > b`. kUnsignedGE = kAE, //!< Unsigned `a >= b`. - kZero = kZ, - kNotZero = kNZ, + kZero = kZ, //!< Zero flag. + kNotZero = kNZ, //!< Non-zero flag. - kNegative = kS, - kPositive = kNS, + kNegative = kS, //!< Sign flag. + kPositive = kNS, //!< No sign flag. - kParityEven = kP, - kParityOdd = kPO + kParityEven = kP, //!< Even parity flag. + kParityOdd = kPO //!< Odd parity flag. }; static constexpr uint8_t reverseTable[kCount] = { @@ -1696,54 +1696,92 @@ namespace Condition { // [asmjit::x86::FpuWord] // ============================================================================ -//! FPU control and status word. +//! FPU control and status words. namespace FpuWord { //! FPU status word. enum Status : uint32_t { + //! Invalid operation. kStatusInvalid = 0x0001u, + //! Denormalized operand. kStatusDenormalized = 0x0002u, + //! Division by zero. kStatusDivByZero = 0x0004u, + //! Overflown. kStatusOverflow = 0x0008u, + //! Underflown. kStatusUnderflow = 0x0010u, + //! Precision lost. kStatusPrecision = 0x0020u, + //! Stack fault. kStatusStackFault = 0x0040u, + //! Interrupt. kStatusInterrupt = 0x0080u, + //! C0 flag. kStatusC0 = 0x0100u, + //! C1 flag. kStatusC1 = 0x0200u, + //! C2 flag. kStatusC2 = 0x0400u, + //! Top of the stack. kStatusTop = 0x3800u, + //! C3 flag. kStatusC3 = 0x4000u, + //! FPU is busy. kStatusBusy = 0x8000u }; //! FPU control word. enum Control : uint32_t { - // Bits 0-5. + // [Bits 0-5] + + //! Exception mask (0x3F). kControlEM_Mask = 0x003Fu, + //! Invalid operation exception. kControlEM_Invalid = 0x0001u, + //! Denormalized operand exception. kControlEM_Denormal = 0x0002u, + //! Division by zero exception. kControlEM_DivByZero = 0x0004u, + //! Overflow exception. kControlEM_Overflow = 0x0008u, + //! Underflow exception. kControlEM_Underflow = 0x0010u, + //! Inexact operation exception. kControlEM_Inexact = 0x0020u, - // Bits 8-9. + // [Bits 8-9] + + //! Precision control mask. kControlPC_Mask = 0x0300u, + //! Single precision (24 bits). kControlPC_Float = 0x0000u, + //! Reserved. kControlPC_Reserved = 0x0100u, + //! Double precision (53 bits). kControlPC_Double = 0x0200u, + //! Extended precision (64 bits). kControlPC_Extended = 0x0300u, - // Bits 10-11. + // [Bits 10-11] + + //! Rounding control mask. kControlRC_Mask = 0x0C00u, + //! Round to nearest even. kControlRC_Nearest = 0x0000u, + //! Round down (floor). kControlRC_Down = 0x0400u, + //! Round up (ceil). kControlRC_Up = 0x0800u, + //! Round towards zero (truncate). kControlRC_Truncate = 0x0C00u, - // Bit 12. + // [Bit 12] + + //! Infinity control. kControlIC_Mask = 0x1000u, + //! Projective (not supported on X64). kControlIC_Projective = 0x0000u, + //! Affine (default). kControlIC_Affine = 0x1000u }; } @@ -1760,26 +1798,39 @@ namespace Status { // [Architecture Neutral Flags - 0x000000FF] // ------------------------------------------------------------------------ - kCF = 0x00000001u, //!< Carry flag. - kOF = 0x00000002u, //!< Signed overflow flag. - kSF = 0x00000004u, //!< Sign flag (negative/sign, if set). - kZF = 0x00000008u, //!< Zero and/or equality flag (1 if zero/equal). + //! Carry flag. + kCF = 0x00000001u, + //! Signed overflow flag. + kOF = 0x00000002u, + //! Sign flag (negative/sign, if set). + kSF = 0x00000004u, + //! Zero and/or equality flag (1 if zero/equal). + kZF = 0x00000008u, // ------------------------------------------------------------------------ // [Architecture Specific Flags - 0xFFFFFF00] // ------------------------------------------------------------------------ - kAF = 0x00000100u, //!< Adjust flag. - kPF = 0x00000200u, //!< Parity flag. - kDF = 0x00000400u, //!< Direction flag. - kIF = 0x00000800u, //!< Interrupt enable flag. - - kAC = 0x00001000u, //!< Alignment check. - - kC0 = 0x00010000u, //!< FPU C0 status flag. - kC1 = 0x00020000u, //!< FPU C1 status flag. - kC2 = 0x00040000u, //!< FPU C2 status flag. - kC3 = 0x00080000u //!< FPU C3 status flag. + //! Adjust flag. + kAF = 0x00000100u, + //! Parity flag. + kPF = 0x00000200u, + //! Direction flag. + kDF = 0x00000400u, + //! Interrupt enable flag. + kIF = 0x00000800u, + + //! Alignment check. + kAC = 0x00001000u, + + //! FPU C0 status flag. + kC0 = 0x00010000u, + //! FPU C1 status flag. + kC1 = 0x00020000u, + //! FPU C2 status flag. + kC2 = 0x00040000u, + //! FPU C3 status flag. + kC3 = 0x00080000u }; } @@ -1834,12 +1885,18 @@ namespace Predicate { //! A predicate used by ROUND[PD|PS|SD|SS] instructions. enum Round : uint32_t { - kRoundNearest = 0x00u, //!< Round to nearest (even). - kRoundDown = 0x01u, //!< Round to down toward -INF (floor), - kRoundUp = 0x02u, //!< Round to up toward +INF (ceil). - kRoundTrunc = 0x03u, //!< Round toward zero (truncate). - kRoundCurrent = 0x04u, //!< Round to the current rounding mode set (ignores other RC bits). - kRoundInexact = 0x08u //!< Avoids inexact exception, if set. + //! Round to nearest (even). + kRoundNearest = 0x00u, + //! Round to down toward -INF (floor), + kRoundDown = 0x01u, + //! Round to up toward +INF (ceil). + kRoundUp = 0x02u, + //! Round toward zero (truncate). + kRoundTrunc = 0x03u, + //! Round to the current rounding mode set (ignores other RC bits). + kRoundCurrent = 0x04u, + //! Avoids inexact exception, if set. + kRoundInexact = 0x08u }; //! A predicate used by VCMP[PD|PS|SD|SS] instructions. @@ -1998,25 +2055,46 @@ namespace Predicate { //! Bitwise ternary logic between 3 operands introduced by AVX-512. namespace TLog { //! A predicate that can be used to create a common predicate for VPTERNLOG[D|Q]. + //! + //! There are 3 inputs to the instruction (\ref kA, \ref kB, \ref kC), and + //! ternary logic can define any combination that would be performed on these + //! 3 inputs to get the desired output - any combination of AND, OR, XOR, NOT. enum Operator : uint32_t { - k0 = 0x00u, //!< 0 value. - k1 = 0xFFu, //!< 1 value. - kA = 0xF0u, //!< A value. - kB = 0xCCu, //!< B value. - kC = 0xAAu, //!< C value. - kNotA = kA ^ k1, //!< `!A` expression. - kNotB = kB ^ k1, //!< `!B` expression. - kNotC = kC ^ k1, //!< `!C` expression. - - kAB = kA & kB, //!< `A & B` expression. - kAC = kA & kC, //!< `A & C` expression. - kBC = kB & kC, //!< `B & C` expression. - kNotAB = kAB ^ k1, //!< `!(A & B)` expression. - kNotAC = kAC ^ k1, //!< `!(A & C)` expression. - kNotBC = kBC ^ k1, //!< `!(B & C)` expression. - - kABC = kAB & kC, //!< `A & B & C` expression. - kNotABC = kABC ^ k1 //!< `!(A & B & C)` expression. + //! 0 value. + k0 = 0x00u, + //! 1 value. + k1 = 0xFFu, + //! A value. + kA = 0xF0u, + //! B value. + kB = 0xCCu, + //! C value. + kC = 0xAAu, + + //! `!A` expression. + kNotA = kA ^ k1, + //! `!B` expression. + kNotB = kB ^ k1, + //! `!C` expression. + kNotC = kC ^ k1, + + //! `A & B` expression. + kAB = kA & kB, + //! `A & C` expression. + kAC = kA & kC, + //! `B & C` expression. + kBC = kB & kC, + //! `!(A & B)` expression. + kNotAB = kAB ^ k1, + //! `!(A & C)` expression. + kNotAC = kAC ^ k1, + //! `!(B & C)` expression. + kNotBC = kBC ^ k1, + + //! `A & B & C` expression. + kABC = kAB & kC, + //! `!(A & B & C)` expression. + kNotABC = kABC ^ k1 }; //! Creates an immediate that can be used by VPTERNLOG[D|Q] instructions. diff --git a/3rdparty/asmjit/src/asmjit/x86/x86instapi.cpp b/3rdparty/asmjit/src/asmjit/x86/x86instapi.cpp index 6c5e28be46a..82f782e0fc6 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86instapi.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86instapi.cpp @@ -58,18 +58,18 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // ============================================================================ #ifndef ASMJIT_NO_TEXT -Error InstInternal::instIdToString(uint32_t archId, uint32_t instId, String& output) noexcept { - DebugUtils::unused(archId); +Error InstInternal::instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept { + DebugUtils::unused(arch); if (ASMJIT_UNLIKELY(!Inst::isDefinedId(instId))) return DebugUtils::errored(kErrorInvalidInstruction); const InstDB::InstInfo& info = InstDB::infoById(instId); - return output.appendString(InstDB::_nameData + info._nameDataIndex); + return output.append(InstDB::_nameData + info._nameDataIndex); } -uint32_t InstInternal::stringToInstId(uint32_t archId, const char* s, size_t len) noexcept { - DebugUtils::unused(archId); +uint32_t InstInternal::stringToInstId(uint32_t arch, const char* s, size_t len) noexcept { + DebugUtils::unused(arch); if (ASMJIT_UNLIKELY(!s)) return Inst::kIdNone; @@ -235,18 +235,18 @@ static ASMJIT_INLINE bool x86CheckOSig(const InstDB::OpSignature& op, const Inst return true; } -ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept { - // Only called when `archId` matches X86 family. - ASMJIT_ASSERT(ArchInfo::isX86Family(archId)); +ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags) noexcept { + // Only called when `arch` matches X86 family. + ASMJIT_ASSERT(Environment::isFamilyX86(arch)); const X86ValidationData* vd; - if (archId == ArchInfo::kIdX86) + if (arch == Environment::kArchX86) vd = &_x86ValidationData; else vd = &_x64ValidationData; uint32_t i; - uint32_t mode = InstDB::modeFromArchId(archId); + uint32_t mode = InstDB::modeFromArch(arch); // Get the instruction data. uint32_t instId = inst.id(); @@ -328,7 +328,6 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& // that the register is virtual and its index will be assigned later // by the register allocator. We must pass unless asked to disallow // virtual registers. - // TODO: We need an option to refuse virtual regs here. uint32_t regId = op.id(); if (regId < Operand::kVirtIdMin) { if (ASMJIT_UNLIKELY(regId >= 32)) @@ -341,6 +340,8 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& combinedRegMask |= regMask; } else { + if (!(validationFlags & InstAPI::kValidationFlagVirtRegs)) + return DebugUtils::errored(kErrorIllegalVirtReg); regMask = 0xFFFFFFFFu; } break; @@ -393,6 +394,9 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& // memory operand. Basically only usable for string instructions and other // instructions where memory operand is implicit and has 'seg:[reg]' form. if (baseId < Operand::kVirtIdMin) { + if (ASMJIT_UNLIKELY(baseId >= 32)) + return DebugUtils::errored(kErrorInvalidPhysId); + // Physical base id. regMask = Support::bitMask(baseId); combinedRegMask |= regMask; @@ -400,6 +404,8 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& else { // Virtual base id - fill the whole mask for implicit mem validation. // The register is not assigned yet, so we cannot predict the phys id. + if (!(validationFlags & InstAPI::kValidationFlagVirtRegs)) + return DebugUtils::errored(kErrorIllegalVirtReg); regMask = 0xFFFFFFFFu; } @@ -461,8 +467,16 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& return DebugUtils::errored(kErrorInvalidAddress); uint32_t indexId = m.indexId(); - if (indexId < Operand::kVirtIdMin) + if (indexId < Operand::kVirtIdMin) { + if (ASMJIT_UNLIKELY(indexId >= 32)) + return DebugUtils::errored(kErrorInvalidPhysId); + combinedRegMask |= Support::bitMask(indexId); + } + else { + if (!(validationFlags & InstAPI::kValidationFlagVirtRegs)) + return DebugUtils::errored(kErrorIllegalVirtReg); + } // Only used for implicit memory operands having 'seg:[reg]' form, so clear it. regMask = 0; @@ -490,7 +504,7 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& } case Operand::kOpImm: { - uint64_t immValue = op.as<Imm>().u64(); + uint64_t immValue = op.as<Imm>().valueAs<uint64_t>(); uint32_t immFlags = 0; if (int64_t(immValue) >= 0) { @@ -574,7 +588,9 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& } else { // Illegal use of a high 8-bit register with REX prefix. - if (ASMJIT_UNLIKELY((combinedOpFlags & InstDB::kOpGpbHi) != 0 && (combinedRegMask & 0xFFFFFF00u) != 0)) + bool hasREX = inst.hasOption(Inst::kOptionRex) || + ((combinedRegMask & 0xFFFFFF00u) != 0); + if (ASMJIT_UNLIKELY(hasREX && (combinedOpFlags & InstDB::kOpGpbHi) != 0)) return DebugUtils::errored(kErrorInvalidUseOfGpbHi); } @@ -761,12 +777,6 @@ static const uint64_t rwRegGroupByteMask[Reg::kGroupCount] = { 0x00000000000000FFu // RIP. }; -// TODO: Make universal. -static ASMJIT_INLINE uint32_t gpRegSizeByArchId(uint32_t archId) noexcept { - static const uint8_t table[] = { 0, 4, 8, 4, 8 }; - return table[archId]; -} - static ASMJIT_INLINE void rwZeroExtendGp(OpRWInfo& opRwInfo, const Gp& reg, uint32_t nativeGpSize) noexcept { ASMJIT_ASSERT(BaseReg::isGp(reg.as<Operand>())); if (reg.size() + 4 == nativeGpSize) { @@ -793,11 +803,11 @@ static ASMJIT_INLINE void rwZeroExtendNonVec(OpRWInfo& opRwInfo, const Reg& reg) } } -Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, InstRWInfo& out) noexcept { +Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept { using namespace Status; - // Only called when `archId` matches X86 family. - ASMJIT_ASSERT(ArchInfo::isX86Family(archId)); + // Only called when `arch` matches X86 family. + ASMJIT_ASSERT(Environment::isFamilyX86(arch)); // Get the instruction data. uint32_t instId = inst.id(); @@ -817,14 +827,14 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope const InstDB::RWInfo& instRwInfo = InstDB::rwInfo[InstDB::rwInfoIndex[instId * 2u + uint32_t(opCount != 2)]]; const InstDB::RWInfoRm& instRmInfo = InstDB::rwInfoRm[instRwInfo.rmInfo]; - out._instFlags = 0; - out._opCount = uint8_t(opCount); - out._rmFeature = instRmInfo.rmFeature; - out._extraReg.reset(); - out._readFlags = rwFlags.readFlags; - out._writeFlags = rwFlags.writeFlags; + out->_instFlags = 0; + out->_opCount = uint8_t(opCount); + out->_rmFeature = instRmInfo.rmFeature; + out->_extraReg.reset(); + out->_readFlags = rwFlags.readFlags; + out->_writeFlags = rwFlags.writeFlags; - uint32_t nativeGpSize = gpRegSizeByArchId(archId); + uint32_t nativeGpSize = Environment::registerSizeFromArch(arch); constexpr uint32_t R = OpRWInfo::kRead; constexpr uint32_t W = OpRWInfo::kWrite; @@ -839,7 +849,7 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope uint32_t rmMaxSize = 0; for (i = 0; i < opCount; i++) { - OpRWInfo& op = out._operands[i]; + OpRWInfo& op = out->_operands[i]; const Operand_& srcOp = operands[i]; const InstDB::RWInfoOp& rwOpData = InstDB::rwInfoOp[instRwInfo.opInfoIndex[i]]; @@ -893,7 +903,7 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope do { i = it.next(); - OpRWInfo& op = out._operands[i]; + OpRWInfo& op = out->_operands[i]; op.addOpFlags(RegM); switch (instRmInfo.category) { @@ -932,38 +942,38 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope const Reg& o1 = operands[1].as<Reg>(); if (o0.isGp() && o1.isGp()) { - out._operands[0].reset(W | RegM, operands[0].size()); - out._operands[1].reset(R | RegM, operands[1].size()); + out->_operands[0].reset(W | RegM, operands[0].size()); + out->_operands[1].reset(R | RegM, operands[1].size()); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); return kErrorOk; } if (o0.isGp() && o1.isSReg()) { - out._operands[0].reset(W | RegM, nativeGpSize); - out._operands[0].setRmSize(2); - out._operands[1].reset(R, 2); + out->_operands[0].reset(W | RegM, nativeGpSize); + out->_operands[0].setRmSize(2); + out->_operands[1].reset(R, 2); return kErrorOk; } if (o0.isSReg() && o1.isGp()) { - out._operands[0].reset(W, 2); - out._operands[1].reset(R | RegM, 2); - out._operands[1].setRmSize(2); + out->_operands[0].reset(W, 2); + out->_operands[1].reset(R | RegM, 2); + out->_operands[1].setRmSize(2); return kErrorOk; } if (o0.isGp() && (o1.isCReg() || o1.isDReg())) { - out._operands[0].reset(W, nativeGpSize); - out._operands[1].reset(R, nativeGpSize); - out._writeFlags = kOF | kSF | kZF | kAF | kPF | kCF; + out->_operands[0].reset(W, nativeGpSize); + out->_operands[1].reset(R, nativeGpSize); + out->_writeFlags = kOF | kSF | kZF | kAF | kPF | kCF; return kErrorOk; } if ((o0.isCReg() || o0.isDReg()) && o1.isGp()) { - out._operands[0].reset(W, nativeGpSize); - out._operands[1].reset(R, nativeGpSize); - out._writeFlags = kOF | kSF | kZF | kAF | kPF | kCF; + out->_operands[0].reset(W, nativeGpSize); + out->_operands[1].reset(R, nativeGpSize); + out->_writeFlags = kOF | kSF | kZF | kAF | kPF | kCF; return kErrorOk; } } @@ -974,18 +984,18 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope if (o0.isGp()) { if (!o1.isOffset64Bit()) - out._operands[0].reset(W, o0.size()); + out->_operands[0].reset(W, o0.size()); else - out._operands[0].reset(W | RegPhys, o0.size(), Gp::kIdAx); + out->_operands[0].reset(W | RegPhys, o0.size(), Gp::kIdAx); - out._operands[1].reset(R | MibRead, o0.size()); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + out->_operands[1].reset(R | MibRead, o0.size()); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); return kErrorOk; } if (o0.isSReg()) { - out._operands[0].reset(W, 2); - out._operands[1].reset(R, 2); + out->_operands[0].reset(W, 2); + out->_operands[1].reset(R, 2); return kErrorOk; } } @@ -995,34 +1005,34 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope const Reg& o1 = operands[1].as<Reg>(); if (o1.isGp()) { - out._operands[0].reset(W | MibRead, o1.size()); + out->_operands[0].reset(W | MibRead, o1.size()); if (!o0.isOffset64Bit()) - out._operands[1].reset(R, o1.size()); + out->_operands[1].reset(R, o1.size()); else - out._operands[1].reset(R | RegPhys, o1.size(), Gp::kIdAx); + out->_operands[1].reset(R | RegPhys, o1.size(), Gp::kIdAx); return kErrorOk; } if (o1.isSReg()) { - out._operands[0].reset(W | MibRead, 2); - out._operands[1].reset(R, 2); + out->_operands[0].reset(W | MibRead, 2); + out->_operands[1].reset(R, 2); return kErrorOk; } } if (Reg::isGp(operands[0]) && operands[1].isImm()) { const Reg& o0 = operands[0].as<Reg>(); - out._operands[0].reset(W | RegM, o0.size()); - out._operands[1].reset(); + out->_operands[0].reset(W | RegM, o0.size()); + out->_operands[1].reset(); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); return kErrorOk; } if (operands[0].isMem() && operands[1].isImm()) { const Reg& o0 = operands[0].as<Reg>(); - out._operands[0].reset(W | MibRead, o0.size()); - out._operands[1].reset(); + out->_operands[0].reset(W | MibRead, o0.size()); + out->_operands[1].reset(); return kErrorOk; } } @@ -1040,51 +1050,51 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope if (opCount == 2) { if (operands[0].isReg() && operands[1].isImm()) { - out._operands[0].reset(X, operands[0].size()); - out._operands[1].reset(); + out->_operands[0].reset(X, operands[0].size()); + out->_operands[1].reset(); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); return kErrorOk; } if (Reg::isGpw(operands[0]) && operands[1].size() == 1) { // imul ax, r8/m8 <- AX = AL * r8/m8 - out._operands[0].reset(X | RegPhys, 2, Gp::kIdAx); - out._operands[0].setReadByteMask(Support::lsbMask<uint64_t>(1)); - out._operands[1].reset(R | RegM, 1); + out->_operands[0].reset(X | RegPhys, 2, Gp::kIdAx); + out->_operands[0].setReadByteMask(Support::lsbMask<uint64_t>(1)); + out->_operands[1].reset(R | RegM, 1); } else { // imul r?, r?/m? - out._operands[0].reset(X, operands[0].size()); - out._operands[1].reset(R | RegM, operands[0].size()); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + out->_operands[0].reset(X, operands[0].size()); + out->_operands[1].reset(R | RegM, operands[0].size()); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); } if (operands[1].isMem()) - out._operands[1].addOpFlags(MibRead); + out->_operands[1].addOpFlags(MibRead); return kErrorOk; } if (opCount == 3) { if (operands[2].isImm()) { - out._operands[0].reset(W, operands[0].size()); - out._operands[1].reset(R | RegM, operands[1].size()); - out._operands[2].reset(); + out->_operands[0].reset(W, operands[0].size()); + out->_operands[1].reset(R | RegM, operands[1].size()); + out->_operands[2].reset(); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); if (operands[1].isMem()) - out._operands[1].addOpFlags(MibRead); + out->_operands[1].addOpFlags(MibRead); return kErrorOk; } else { - out._operands[0].reset(W | RegPhys, operands[0].size(), Gp::kIdDx); - out._operands[1].reset(X | RegPhys, operands[1].size(), Gp::kIdAx); - out._operands[2].reset(R | RegM, operands[2].size()); + out->_operands[0].reset(W | RegPhys, operands[0].size(), Gp::kIdDx); + out->_operands[1].reset(X | RegPhys, operands[1].size(), Gp::kIdAx); + out->_operands[2].reset(R | RegM, operands[2].size()); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); - rwZeroExtendGp(out._operands[1], operands[1].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[1], operands[1].as<Gp>(), nativeGpSize); if (operands[2].isMem()) - out._operands[2].addOpFlags(MibRead); + out->_operands[2].addOpFlags(MibRead); return kErrorOk; } } @@ -1097,16 +1107,16 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope // 2 or 3 operands that are use `kCategoryGeneric`. if (opCount == 2) { if (BaseReg::isVec(operands[0]) && operands[1].isMem()) { - out._operands[0].reset(W, 8); - out._operands[0].setWriteByteMask(Support::lsbMask<uint64_t>(8) << 8); - out._operands[1].reset(R | MibRead, 8); + out->_operands[0].reset(W, 8); + out->_operands[0].setWriteByteMask(Support::lsbMask<uint64_t>(8) << 8); + out->_operands[1].reset(R | MibRead, 8); return kErrorOk; } if (operands[0].isMem() && BaseReg::isVec(operands[1])) { - out._operands[0].reset(W | MibRead, 8); - out._operands[1].reset(R, 8); - out._operands[1].setReadByteMask(Support::lsbMask<uint64_t>(8) << 8); + out->_operands[0].reset(W | MibRead, 8); + out->_operands[1].reset(R, 8); + out->_operands[1].setReadByteMask(Support::lsbMask<uint64_t>(8) << 8); return kErrorOk; } } @@ -1117,18 +1127,18 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope // Special case for 'vmaskmovpd|vmaskmovps|vpmaskmovd|vpmaskmovq' instructions. if (opCount == 3) { if (BaseReg::isVec(operands[0]) && BaseReg::isVec(operands[1]) && operands[2].isMem()) { - out._operands[0].reset(W, operands[0].size()); - out._operands[1].reset(R, operands[1].size()); - out._operands[2].reset(R | MibRead, operands[1].size()); + out->_operands[0].reset(W, operands[0].size()); + out->_operands[1].reset(R, operands[1].size()); + out->_operands[2].reset(R | MibRead, operands[1].size()); - rwZeroExtendAvxVec(out._operands[0], operands[0].as<Vec>()); + rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>()); return kErrorOk; } if (operands[0].isMem() && BaseReg::isVec(operands[1]) && BaseReg::isVec(operands[2])) { - out._operands[0].reset(X | MibRead, operands[1].size()); - out._operands[1].reset(R, operands[1].size()); - out._operands[2].reset(R, operands[2].size()); + out->_operands[0].reset(X | MibRead, operands[1].size()); + out->_operands[1].reset(R, operands[1].size()); + out->_operands[2].reset(R, operands[2].size()); return kErrorOk; } } @@ -1145,11 +1155,11 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope uint32_t o0Size = operands[0].size(); uint32_t o1Size = o0Size == 16 ? 8 : o0Size; - out._operands[0].reset(W, o0Size); - out._operands[1].reset(R | RegM, o1Size); - out._operands[1]._readByteMask &= 0x00FF00FF00FF00FFu; + out->_operands[0].reset(W, o0Size); + out->_operands[1].reset(R | RegM, o1Size); + out->_operands[1]._readByteMask &= 0x00FF00FF00FF00FFu; - rwZeroExtendAvxVec(out._operands[0], operands[0].as<Vec>()); + rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>()); return kErrorOk; } @@ -1157,10 +1167,10 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope uint32_t o0Size = operands[0].size(); uint32_t o1Size = o0Size == 16 ? 8 : o0Size; - out._operands[0].reset(W, o0Size); - out._operands[1].reset(R | MibRead, o1Size); + out->_operands[0].reset(W, o0Size); + out->_operands[1].reset(R | MibRead, o1Size); - rwZeroExtendAvxVec(out._operands[0], operands[0].as<Vec>()); + rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>()); return kErrorOk; } } @@ -1172,9 +1182,9 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope // Special case for 'vmovmskpd|vmovmskps' instructions. if (opCount == 2) { if (BaseReg::isGp(operands[0]) && BaseReg::isVec(operands[1])) { - out._operands[0].reset(W, 1); - out._operands[0].setExtendByteMask(Support::lsbMask<uint32_t>(nativeGpSize - 1) << 1); - out._operands[1].reset(R, operands[1].size()); + out->_operands[0].reset(W, 1); + out->_operands[0].setExtendByteMask(Support::lsbMask<uint32_t>(nativeGpSize - 1) << 1); + out->_operands[1].reset(R, operands[1].size()); return kErrorOk; } } @@ -1208,32 +1218,32 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope if (opCount >= 3) { if (opCount > 3) return DebugUtils::errored(kErrorInvalidInstruction); - out._operands[2].reset(); + out->_operands[2].reset(); } if (operands[0].isReg() && operands[1].isReg()) { uint32_t size1 = operands[1].size(); uint32_t size0 = size1 >> shift; - out._operands[0].reset(W, size0); - out._operands[1].reset(R, size1); + out->_operands[0].reset(W, size0); + out->_operands[1].reset(R, size1); if (instRmInfo.rmOpsMask & 0x1) { - out._operands[0].addOpFlags(RegM); - out._operands[0].setRmSize(size0); + out->_operands[0].addOpFlags(RegM); + out->_operands[0].setRmSize(size0); } if (instRmInfo.rmOpsMask & 0x2) { - out._operands[1].addOpFlags(RegM); - out._operands[1].setRmSize(size1); + out->_operands[1].addOpFlags(RegM); + out->_operands[1].setRmSize(size1); } // Handle 'pmovmskb|vpmovmskb'. if (BaseReg::isGp(operands[0])) - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); if (BaseReg::isVec(operands[0])) - rwZeroExtendAvxVec(out._operands[0], operands[0].as<Vec>()); + rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>()); return kErrorOk; } @@ -1242,8 +1252,8 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope uint32_t size1 = operands[1].size() ? operands[1].size() : uint32_t(16); uint32_t size0 = size1 >> shift; - out._operands[0].reset(W, size0); - out._operands[1].reset(R | MibRead, size1); + out->_operands[0].reset(W, size0); + out->_operands[1].reset(R | MibRead, size1); return kErrorOk; } @@ -1251,8 +1261,8 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope uint32_t size1 = operands[1].size(); uint32_t size0 = size1 >> shift; - out._operands[0].reset(W | MibRead, size0); - out._operands[1].reset(R, size1); + out->_operands[0].reset(W | MibRead, size0); + out->_operands[1].reset(R, size1); return kErrorOk; } } @@ -1285,30 +1295,30 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope if (opCount >= 3) { if (opCount > 3) return DebugUtils::errored(kErrorInvalidInstruction); - out._operands[2].reset(); + out->_operands[2].reset(); } uint32_t size0 = operands[0].size(); uint32_t size1 = size0 >> shift; - out._operands[0].reset(W, size0); - out._operands[1].reset(R, size1); + out->_operands[0].reset(W, size0); + out->_operands[1].reset(R, size1); if (operands[0].isReg() && operands[1].isReg()) { if (instRmInfo.rmOpsMask & 0x1) { - out._operands[0].addOpFlags(RegM); - out._operands[0].setRmSize(size0); + out->_operands[0].addOpFlags(RegM); + out->_operands[0].setRmSize(size0); } if (instRmInfo.rmOpsMask & 0x2) { - out._operands[1].addOpFlags(RegM); - out._operands[1].setRmSize(size1); + out->_operands[1].addOpFlags(RegM); + out->_operands[1].setRmSize(size1); } return kErrorOk; } if (operands[0].isReg() && operands[1].isMem()) { - out._operands[1].addOpFlags(MibRead); + out->_operands[1].addOpFlags(MibRead); return kErrorOk; } } @@ -1334,7 +1344,7 @@ struct RegAnalysis { } }; -static RegAnalysis InstInternal_regAnalysis(const Operand_* operands, uint32_t opCount) noexcept { +static RegAnalysis InstInternal_regAnalysis(const Operand_* operands, size_t opCount) noexcept { uint32_t mask = 0; uint32_t highVecUsed = 0; @@ -1359,10 +1369,10 @@ static RegAnalysis InstInternal_regAnalysis(const Operand_* operands, uint32_t o return RegAnalysis { mask, highVecUsed }; } -Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, BaseFeatures& out) noexcept { - // Only called when `archId` matches X86 family. - DebugUtils::unused(archId); - ASMJIT_ASSERT(ArchInfo::isX86Family(archId)); +Error InstInternal::queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept { + // Only called when `arch` matches X86 family. + DebugUtils::unused(arch); + ASMJIT_ASSERT(Environment::isFamilyX86(arch)); // Get the instruction data. uint32_t instId = inst.id(); @@ -1378,12 +1388,12 @@ Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const O const uint8_t* fEnd = tableB.featuresEnd(); // Copy all features to `out`. - out.reset(); + out->reset(); do { uint32_t feature = fData[0]; if (!feature) break; - out.add(feature); + out->add(feature); } while (++fData != fEnd); // Since AsmJit aggregates instructions that share the same name we have to @@ -1392,19 +1402,19 @@ Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const O RegAnalysis regAnalysis = InstInternal_regAnalysis(operands, opCount); // Handle MMX vs SSE overlap. - if (out.has(Features::kMMX) || out.has(Features::kMMX2)) { + if (out->has(Features::kMMX) || out->has(Features::kMMX2)) { // Only instructions defined by SSE and SSE2 overlap. Instructions // introduced by newer instruction sets like SSE3+ don't state MMX as // they require SSE3+. - if (out.has(Features::kSSE) || out.has(Features::kSSE2)) { + if (out->has(Features::kSSE) || out->has(Features::kSSE2)) { if (!regAnalysis.hasRegType(Reg::kTypeXmm)) { // The instruction doesn't use XMM register(s), thus it's MMX/MMX2 only. - out.remove(Features::kSSE); - out.remove(Features::kSSE2); + out->remove(Features::kSSE); + out->remove(Features::kSSE2); } else { - out.remove(Features::kMMX); - out.remove(Features::kMMX2); + out->remove(Features::kMMX); + out->remove(Features::kMMX2); } // Special case: PEXTRW instruction is MMX/SSE2 instruction. However, @@ -1414,34 +1424,34 @@ Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const O // can extract directly to memory. This instruction is, of course, not // compatible with MMX/SSE2 and would #UD if SSE4.1 is not supported. if (instId == Inst::kIdPextrw) { - ASMJIT_ASSERT(out.has(Features::kSSE2)); - ASMJIT_ASSERT(out.has(Features::kSSE4_1)); + ASMJIT_ASSERT(out->has(Features::kSSE2)); + ASMJIT_ASSERT(out->has(Features::kSSE4_1)); if (opCount >= 1 && operands[0].isMem()) - out.remove(Features::kSSE2); + out->remove(Features::kSSE2); else - out.remove(Features::kSSE4_1); + out->remove(Features::kSSE4_1); } } } // Handle PCLMULQDQ vs VPCLMULQDQ. - if (out.has(Features::kVPCLMULQDQ)) { + if (out->has(Features::kVPCLMULQDQ)) { if (regAnalysis.hasRegType(Reg::kTypeZmm) || Support::bitTest(options, Inst::kOptionEvex)) { // AVX512_F & VPCLMULQDQ. - out.remove(Features::kAVX, Features::kPCLMULQDQ); + out->remove(Features::kAVX, Features::kPCLMULQDQ); } else if (regAnalysis.hasRegType(Reg::kTypeYmm)) { - out.remove(Features::kAVX512_F, Features::kAVX512_VL); + out->remove(Features::kAVX512_F, Features::kAVX512_VL); } else { // AVX & PCLMULQDQ. - out.remove(Features::kAVX512_F, Features::kAVX512_VL, Features::kVPCLMULQDQ); + out->remove(Features::kAVX512_F, Features::kAVX512_VL, Features::kVPCLMULQDQ); } } // Handle AVX vs AVX2 overlap. - if (out.has(Features::kAVX) && out.has(Features::kAVX2)) { + if (out->has(Features::kAVX) && out->has(Features::kAVX2)) { bool isAVX2 = true; // Special case: VBROADCASTSS and VBROADCASTSD were introduced in AVX, but // only version that uses memory as a source operand. AVX2 then added support @@ -1459,15 +1469,15 @@ Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const O } if (isAVX2) - out.remove(Features::kAVX); + out->remove(Features::kAVX); else - out.remove(Features::kAVX2); + out->remove(Features::kAVX2); } // Handle AVX|AVX2|FMA|F16C vs AVX512 overlap. - if (out.has(Features::kAVX) || out.has(Features::kAVX2) || out.has(Features::kFMA) || out.has(Features::kF16C)) { + if (out->has(Features::kAVX) || out->has(Features::kAVX2) || out->has(Features::kFMA) || out->has(Features::kF16C)) { // Only AVX512-F|BW|DQ allow to encode AVX/AVX2/FMA/F16C instructions - if (out.has(Features::kAVX512_F) || out.has(Features::kAVX512_BW) || out.has(Features::kAVX512_DQ)) { + if (out->has(Features::kAVX512_F) || out->has(Features::kAVX512_BW) || out->has(Features::kAVX512_DQ)) { uint32_t hasEvex = options & (Inst::kOptionEvex | Inst::_kOptionAvx512Mask); uint32_t hasKMask = inst.extraReg().type() == Reg::kTypeKReg; uint32_t hasKOrZmm = regAnalysis.regTypeMask & Support::bitMask(Reg::kTypeZmm, Reg::kTypeKReg); @@ -1500,15 +1510,15 @@ Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const O } if (!(hasEvex | mustUseEvex | hasKMask | hasKOrZmm | regAnalysis.highVecUsed)) - out.remove(Features::kAVX512_F, Features::kAVX512_BW, Features::kAVX512_DQ, Features::kAVX512_VL); + out->remove(Features::kAVX512_F, Features::kAVX512_BW, Features::kAVX512_DQ, Features::kAVX512_VL); else - out.remove(Features::kAVX, Features::kAVX2, Features::kFMA, Features::kF16C); + out->remove(Features::kAVX, Features::kAVX2, Features::kFMA, Features::kF16C); } } // Clear AVX512_VL if ZMM register is used. if (regAnalysis.hasRegType(Reg::kTypeZmm)) - out.remove(Features::kAVX512_VL); + out->remove(Features::kAVX512_VL); } return kErrorOk; diff --git a/3rdparty/asmjit/src/asmjit/x86/x86instapi_p.h b/3rdparty/asmjit/src/asmjit/x86/x86instapi_p.h index 0389cf562a9..83b3f77cf6d 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86instapi_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86instapi_p.h @@ -36,17 +36,17 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) namespace InstInternal { #ifndef ASMJIT_NO_TEXT -Error instIdToString(uint32_t archId, uint32_t instId, String& output) noexcept; -uint32_t stringToInstId(uint32_t archId, const char* s, size_t len) noexcept; +Error instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept; +uint32_t stringToInstId(uint32_t arch, const char* s, size_t len) noexcept; #endif // !ASMJIT_NO_TEXT #ifndef ASMJIT_NO_VALIDATION -Error validate(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept; +Error validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags) noexcept; #endif // !ASMJIT_NO_VALIDATION #ifndef ASMJIT_NO_INTROSPECTION -Error queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, InstRWInfo& out) noexcept; -Error queryFeatures(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, BaseFeatures& out) noexcept; +Error queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept; +Error queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept; #endif // !ASMJIT_NO_INTROSPECTION } // {InstInternal} diff --git a/3rdparty/asmjit/src/asmjit/x86/x86instdb.cpp b/3rdparty/asmjit/src/asmjit/x86/x86instdb.cpp index 2d4855848f8..72ad0989c26 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86instdb.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86instdb.cpp @@ -537,7 +537,7 @@ const InstDB::InstInfo InstDB::_instInfoTable[] = { INST(Movsldup , ExtRm , O(F30F00,12,_,_,_,_,_,_ ), 0 , 6 , 0 , 6179 , 5 , 6 ), // #440 INST(Movss , ExtMov , O(F30F00,10,_,_,_,_,_,_ ), O(F30F00,11,_,_,_,_,_,_ ), 6 , 61 , 6189 , 124, 5 ), // #441 INST(Movsx , X86MovsxMovzx , O(000F00,BE,_,_,x,_,_,_ ), 0 , 4 , 0 , 1962 , 125, 0 ), // #442 - INST(Movsxd , X86Rm , O(000000,63,_,_,1,_,_,_ ), 0 , 20 , 0 , 1968 , 126, 0 ), // #443 + INST(Movsxd , X86Rm , O(000000,63,_,_,x,_,_,_ ), 0 , 0 , 0 , 1968 , 126, 0 ), // #443 INST(Movupd , ExtMov , O(660F00,10,_,_,_,_,_,_ ), O(660F00,11,_,_,_,_,_,_ ), 3 , 62 , 6196 , 107, 4 ), // #444 INST(Movups , ExtMov , O(000F00,10,_,_,_,_,_,_ ), O(000F00,11,_,_,_,_,_,_ ), 4 , 63 , 6204 , 107, 5 ), // #445 INST(Movzx , X86MovsxMovzx , O(000F00,B6,_,_,x,_,_,_ ), 0 , 4 , 0 , 1975 , 125, 0 ), // #446 @@ -1610,7 +1610,7 @@ const InstDB::InstInfo InstDB::_instInfoTable[] = { // ${MainOpcodeTable:Begin} // ------------------- Automatically generated, do not edit ------------------- const uint32_t InstDB::_mainOpcodeTable[] = { - O(000000,00,0,0,0,0,0,_ ), // #0 [ref=55x] + O(000000,00,0,0,0,0,0,_ ), // #0 [ref=56x] O(000000,00,2,0,0,0,0,_ ), // #1 [ref=4x] O(660F38,00,0,0,0,0,0,_ ), // #2 [ref=42x] O(660F00,00,0,0,0,0,0,_ ), // #3 [ref=38x] @@ -1630,7 +1630,7 @@ const uint32_t InstDB::_mainOpcodeTable[] = { V(000F38,00,2,0,0,0,0,_ ), // #17 [ref=1x] V(000F38,00,1,0,0,0,0,_ ), // #18 [ref=1x] O(660000,00,0,0,0,0,0,_ ), // #19 [ref=7x] - O(000000,00,0,0,1,0,0,_ ), // #20 [ref=4x] + O(000000,00,0,0,1,0,0,_ ), // #20 [ref=3x] O(000F01,00,0,0,0,0,0,_ ), // #21 [ref=25x] O(000F00,00,7,0,0,0,0,_ ), // #22 [ref=5x] O(660F00,00,7,0,0,0,0,_ ), // #23 [ref=2x] @@ -1991,8 +1991,8 @@ const uint32_t InstDB::_altOpcodeTable[] = { #define SINGLE_REG(VAL) InstDB::kSingleReg##VAL const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { 0 , 0 , 0 , CONTROL(None) , SINGLE_REG(None), 0 }, // #0 [ref=1x] - { 0 , 339, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #1 [ref=4x] - { 0 , 340, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #2 [ref=2x] + { 0 , 341, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #1 [ref=4x] + { 0 , 342, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #2 [ref=2x] { F(Lock)|F(XAcquire)|F(XRelease) , 16 , 12, CONTROL(None) , SINGLE_REG(None), 0 }, // #3 [ref=2x] { 0 , 151, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #4 [ref=2x] { F(Vec) , 70 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #5 [ref=54x] @@ -2002,173 +2002,173 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Lock)|F(XAcquire)|F(XRelease) , 28 , 11, CONTROL(None) , SINGLE_REG(RO) , 0 }, // #9 [ref=1x] { F(Vex) , 237, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #10 [ref=3x] { F(Vec) , 70 , 1 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #11 [ref=12x] - { 0 , 341, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #12 [ref=1x] + { 0 , 343, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #12 [ref=1x] { F(Vex) , 239, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #13 [ref=5x] { F(Vex) , 151, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #14 [ref=12x] - { F(Vec) , 342, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #15 [ref=4x] + { F(Vec) , 344, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #15 [ref=4x] { 0 , 241, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #16 [ref=3x] - { F(Mib) , 343, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #17 [ref=1x] - { 0 , 344, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #18 [ref=1x] + { F(Mib) , 345, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #17 [ref=1x] + { 0 , 346, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #18 [ref=1x] { 0 , 243, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #19 [ref=1x] - { F(Mib) , 345, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #20 [ref=1x] + { F(Mib) , 347, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #20 [ref=1x] { 0 , 245, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #21 [ref=1x] { 0 , 150, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #22 [ref=35x] - { 0 , 346, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #23 [ref=3x] + { 0 , 348, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #23 [ref=3x] { 0 , 114, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #24 [ref=1x] { F(Lock)|F(XAcquire)|F(XRelease) , 114, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #25 [ref=3x] { F(Rep)|F(RepIgnored) , 247, 2 , CONTROL(Call) , SINGLE_REG(None), 0 }, // #26 [ref=1x] - { 0 , 347, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #27 [ref=1x] - { 0 , 348, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #28 [ref=2x] - { 0 , 322, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #29 [ref=1x] + { 0 , 349, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #27 [ref=1x] + { 0 , 350, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #28 [ref=2x] + { 0 , 324, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #29 [ref=1x] { 0 , 257, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #30 [ref=74x] - { 0 , 349, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #31 [ref=24x] - { 0 , 350, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #32 [ref=1x] + { 0 , 351, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #31 [ref=24x] + { 0 , 352, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #32 [ref=1x] { 0 , 16 , 12, CONTROL(None) , SINGLE_REG(None), 0 }, // #33 [ref=1x] - { F(Rep) , 351, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #34 [ref=1x] - { F(Vec) , 352, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #35 [ref=2x] - { F(Vec) , 353, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #36 [ref=3x] + { F(Rep) , 353, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #34 [ref=1x] + { F(Vec) , 354, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #35 [ref=2x] + { F(Vec) , 355, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #36 [ref=3x] { F(Lock)|F(XAcquire)|F(XRelease) , 118, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #37 [ref=1x] - { F(Lock)|F(XAcquire)|F(XRelease) , 354, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #38 [ref=1x] - { F(Lock)|F(XAcquire)|F(XRelease) , 355, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #39 [ref=1x] - { 0 , 356, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #40 [ref=1x] - { 0 , 357, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #41 [ref=1x] + { F(Lock)|F(XAcquire)|F(XRelease) , 356, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #38 [ref=1x] + { F(Lock)|F(XAcquire)|F(XRelease) , 357, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #39 [ref=1x] + { 0 , 358, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #40 [ref=1x] + { 0 , 359, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #41 [ref=1x] { 0 , 249, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #42 [ref=1x] - { F(Mmx)|F(Vec) , 358, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #43 [ref=2x] - { F(Mmx)|F(Vec) , 359, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #44 [ref=2x] - { F(Mmx)|F(Vec) , 360, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #45 [ref=2x] - { F(Vec) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #46 [ref=2x] - { F(Vec) , 362, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #47 [ref=2x] - { F(Vec) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #48 [ref=2x] - { 0 , 364, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #49 [ref=1x] - { 0 , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #50 [ref=2x] + { F(Mmx)|F(Vec) , 360, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #43 [ref=2x] + { F(Mmx)|F(Vec) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #44 [ref=2x] + { F(Mmx)|F(Vec) , 362, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #45 [ref=2x] + { F(Vec) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #46 [ref=2x] + { F(Vec) , 364, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #47 [ref=2x] + { F(Vec) , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #48 [ref=2x] + { 0 , 366, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #49 [ref=1x] + { 0 , 367, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #50 [ref=2x] { F(Lock)|F(XAcquire)|F(XRelease) , 251, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #51 [ref=2x] { 0 , 39 , 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #52 [ref=3x] { F(Mmx) , 257, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #53 [ref=1x] { 0 , 253, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #54 [ref=2x] - { 0 , 366, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #55 [ref=1x] - { F(Vec) , 367, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #56 [ref=2x] + { 0 , 368, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #55 [ref=1x] + { F(Vec) , 369, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #56 [ref=2x] { F(Vec) , 255, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #57 [ref=1x] { F(FpuM32)|F(FpuM64) , 153, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #58 [ref=6x] { 0 , 257, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #59 [ref=9x] - { F(FpuM80) , 368, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #60 [ref=2x] + { F(FpuM80) , 370, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #60 [ref=2x] { 0 , 258, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #61 [ref=13x] { F(FpuM32)|F(FpuM64) , 259, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #62 [ref=2x] - { F(FpuM16)|F(FpuM32) , 369, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #63 [ref=9x] - { F(FpuM16)|F(FpuM32)|F(FpuM64) , 370, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #64 [ref=3x] - { F(FpuM32)|F(FpuM64)|F(FpuM80) , 371, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #65 [ref=2x] - { F(FpuM16) , 372, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #66 [ref=3x] - { F(FpuM16) , 373, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #67 [ref=2x] + { F(FpuM16)|F(FpuM32) , 371, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #63 [ref=9x] + { F(FpuM16)|F(FpuM32)|F(FpuM64) , 372, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #64 [ref=3x] + { F(FpuM32)|F(FpuM64)|F(FpuM80) , 373, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #65 [ref=2x] + { F(FpuM16) , 374, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #66 [ref=3x] + { F(FpuM16) , 375, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #67 [ref=2x] { F(FpuM32)|F(FpuM64) , 260, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #68 [ref=1x] - { 0 , 374, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #69 [ref=2x] + { 0 , 376, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #69 [ref=2x] { 0 , 39 , 10, CONTROL(None) , SINGLE_REG(None), 0 }, // #70 [ref=1x] - { 0 , 375, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #71 [ref=1x] - { F(Rep) , 376, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #72 [ref=1x] + { 0 , 377, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #71 [ref=1x] + { F(Rep) , 378, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #72 [ref=1x] { F(Vec) , 261, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #73 [ref=1x] - { 0 , 377, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #74 [ref=2x] - { 0 , 378, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #75 [ref=8x] + { 0 , 379, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #74 [ref=2x] + { 0 , 380, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #75 [ref=8x] { 0 , 263, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #76 [ref=3x] { 0 , 265, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #77 [ref=1x] { 0 , 257, 1 , CONTROL(Return) , SINGLE_REG(None), 0 }, // #78 [ref=3x] - { 0 , 379, 1 , CONTROL(Return) , SINGLE_REG(None), 0 }, // #79 [ref=1x] + { 0 , 381, 1 , CONTROL(Return) , SINGLE_REG(None), 0 }, // #79 [ref=1x] { F(Rep)|F(RepIgnored) , 267, 2 , CONTROL(Branch) , SINGLE_REG(None), 0 }, // #80 [ref=30x] { F(Rep)|F(RepIgnored) , 269, 2 , CONTROL(Branch) , SINGLE_REG(None), 0 }, // #81 [ref=1x] { F(Rep)|F(RepIgnored) , 271, 2 , CONTROL(Jump) , SINGLE_REG(None), 0 }, // #82 [ref=1x] - { F(Vec)|F(Vex) , 380, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #83 [ref=27x] + { F(Vec)|F(Vex) , 382, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #83 [ref=27x] { F(Vec)|F(Vex) , 273, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #84 [ref=1x] { F(Vec)|F(Vex) , 275, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #85 [ref=1x] { F(Vec)|F(Vex) , 277, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #86 [ref=1x] { F(Vec)|F(Vex) , 279, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #87 [ref=1x] - { F(Vec)|F(Vex) , 381, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #88 [ref=12x] - { F(Vec)|F(Vex) , 382, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #89 [ref=8x] - { 0 , 383, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #90 [ref=2x] + { F(Vec)|F(Vex) , 383, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #88 [ref=12x] + { F(Vec)|F(Vex) , 384, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #89 [ref=8x] + { 0 , 385, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #90 [ref=2x] { 0 , 281, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #91 [ref=1x] { F(Vec) , 192, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #92 [ref=2x] - { 0 , 384, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #93 [ref=2x] + { 0 , 386, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #93 [ref=2x] { 0 , 283, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #94 [ref=2x] - { 0 , 385, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #95 [ref=1x] + { 0 , 387, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #95 [ref=1x] { 0 , 156, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #96 [ref=3x] - { 0 , 386, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #97 [ref=5x] - { F(Vex) , 387, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #98 [ref=2x] - { F(Rep) , 388, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #99 [ref=1x] + { 0 , 388, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #97 [ref=5x] + { F(Vex) , 389, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #98 [ref=2x] + { F(Rep) , 390, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #99 [ref=1x] { 0 , 269, 2 , CONTROL(Branch) , SINGLE_REG(None), 0 }, // #100 [ref=3x] { 0 , 285, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #101 [ref=1x] - { F(Vex) , 389, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #102 [ref=2x] - { F(Vec) , 390, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #103 [ref=1x] - { F(Mmx) , 391, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #104 [ref=1x] - { 0 , 392, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #105 [ref=2x] + { F(Vex) , 391, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #102 [ref=2x] + { F(Vec) , 392, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #103 [ref=1x] + { F(Mmx) , 393, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #104 [ref=1x] + { 0 , 394, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #105 [ref=2x] { F(XRelease) , 0 , 16, CONTROL(None) , SINGLE_REG(None), 0 }, // #106 [ref=1x] { F(Vec) , 70 , 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #107 [ref=6x] { 0 , 64 , 6 , CONTROL(None) , SINGLE_REG(None), 0 }, // #108 [ref=1x] { F(Mmx)|F(Vec) , 287, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #109 [ref=1x] - { 0 , 393, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #110 [ref=1x] + { 0 , 395, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #110 [ref=1x] { 0 , 68 , 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #111 [ref=2x] - { F(Mmx)|F(Vec) , 394, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #112 [ref=1x] + { F(Mmx)|F(Vec) , 396, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #112 [ref=1x] { F(Vec) , 256, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #113 [ref=2x] { F(Vec) , 198, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #114 [ref=4x] - { F(Vec) , 395, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #115 [ref=2x] + { F(Vec) , 397, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #115 [ref=2x] { F(Vec) , 71 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #116 [ref=3x] - { F(Mmx) , 396, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #117 [ref=1x] + { F(Mmx) , 398, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #117 [ref=1x] { F(Vec) , 98 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #118 [ref=1x] { F(Vec) , 201, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #119 [ref=1x] { F(Mmx)|F(Vec) , 94 , 5 , CONTROL(None) , SINGLE_REG(None), 0 }, // #120 [ref=1x] - { F(Mmx)|F(Vec) , 397, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #121 [ref=1x] - { F(Rep) , 398, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #122 [ref=1x] + { F(Mmx)|F(Vec) , 399, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #121 [ref=1x] + { F(Rep) , 400, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #122 [ref=1x] { F(Vec) , 97 , 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #123 [ref=1x] { F(Vec) , 289, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #124 [ref=1x] { 0 , 291, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #125 [ref=2x] - { 0 , 399, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #126 [ref=1x] - { F(Vex) , 293, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #127 [ref=1x] - { 0 , 400, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #128 [ref=1x] - { 0 , 401, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #129 [ref=1x] + { 0 , 293, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #126 [ref=1x] + { F(Vex) , 295, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #127 [ref=1x] + { 0 , 401, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #128 [ref=1x] + { 0 , 402, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #129 [ref=1x] { F(Lock)|F(XAcquire)|F(XRelease) , 252, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #130 [ref=2x] - { 0 , 295, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #131 [ref=1x] + { 0 , 297, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #131 [ref=1x] { F(Lock)|F(XAcquire)|F(XRelease) , 16 , 12, CONTROL(None) , SINGLE_REG(RO) , 0 }, // #132 [ref=1x] - { 0 , 402, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #133 [ref=1x] - { F(Rep) , 403, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #134 [ref=1x] - { F(Mmx)|F(Vec) , 297, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #135 [ref=40x] - { F(Mmx)|F(Vec) , 299, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #136 [ref=1x] - { F(Mmx)|F(Vec) , 297, 2 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #137 [ref=6x] - { F(Mmx)|F(Vec) , 297, 2 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #138 [ref=16x] - { F(Mmx) , 297, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #139 [ref=26x] + { 0 , 403, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #133 [ref=1x] + { F(Rep) , 404, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #134 [ref=1x] + { F(Mmx)|F(Vec) , 299, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #135 [ref=40x] + { F(Mmx)|F(Vec) , 301, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #136 [ref=1x] + { F(Mmx)|F(Vec) , 299, 2 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #137 [ref=6x] + { F(Mmx)|F(Vec) , 299, 2 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #138 [ref=16x] + { F(Mmx) , 299, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #139 [ref=26x] { F(Vec) , 70 , 1 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #140 [ref=4x] - { F(Vec) , 404, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #141 [ref=1x] - { F(Vec) , 405, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #142 [ref=1x] - { F(Vec) , 406, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #143 [ref=1x] - { F(Vec) , 407, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #144 [ref=1x] - { F(Vec) , 408, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #145 [ref=1x] - { F(Vec) , 409, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #146 [ref=1x] - { F(Mmx)|F(Vec) , 301, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #147 [ref=1x] - { F(Vec) , 410, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #148 [ref=1x] - { F(Vec) , 411, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #149 [ref=1x] - { F(Vec) , 412, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #150 [ref=1x] - { F(Mmx)|F(Vec) , 413, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #151 [ref=1x] - { F(Mmx)|F(Vec) , 414, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #152 [ref=1x] + { F(Vec) , 405, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #141 [ref=1x] + { F(Vec) , 406, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #142 [ref=1x] + { F(Vec) , 407, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #143 [ref=1x] + { F(Vec) , 408, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #144 [ref=1x] + { F(Vec) , 409, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #145 [ref=1x] + { F(Vec) , 410, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #146 [ref=1x] + { F(Mmx)|F(Vec) , 303, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #147 [ref=1x] + { F(Vec) , 411, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #148 [ref=1x] + { F(Vec) , 412, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #149 [ref=1x] + { F(Vec) , 413, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #150 [ref=1x] + { F(Mmx)|F(Vec) , 414, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #151 [ref=1x] + { F(Mmx)|F(Vec) , 415, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #152 [ref=1x] { F(Vec) , 225, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #153 [ref=2x] { 0 , 122, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #154 [ref=1x] - { 0 , 379, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #155 [ref=6x] - { F(Mmx) , 299, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #156 [ref=1x] - { F(Mmx)|F(Vec) , 303, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #157 [ref=8x] - { F(Vec) , 415, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #158 [ref=2x] + { 0 , 381, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #155 [ref=6x] + { F(Mmx) , 301, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #156 [ref=1x] + { F(Mmx)|F(Vec) , 305, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #157 [ref=8x] + { F(Vec) , 416, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #158 [ref=2x] { 0 , 126, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #159 [ref=1x] - { 0 , 416, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #160 [ref=8x] - { 0 , 417, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #161 [ref=4x] - { 0 , 418, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #162 [ref=6x] - { 0 , 305, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #163 [ref=1x] - { F(Rep)|F(RepIgnored) , 307, 2 , CONTROL(Return) , SINGLE_REG(None), 0 }, // #164 [ref=1x] - { F(Vex) , 309, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #165 [ref=1x] + { 0 , 417, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #160 [ref=8x] + { 0 , 418, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #161 [ref=4x] + { 0 , 419, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #162 [ref=6x] + { 0 , 307, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #163 [ref=1x] + { F(Rep)|F(RepIgnored) , 309, 2 , CONTROL(Return) , SINGLE_REG(None), 0 }, // #164 [ref=1x] + { F(Vex) , 311, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #165 [ref=1x] { F(Lock)|F(XAcquire)|F(XRelease) , 16 , 12, CONTROL(None) , SINGLE_REG(WO) , 0 }, // #166 [ref=3x] - { F(Rep) , 419, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #167 [ref=1x] - { 0 , 420, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #168 [ref=30x] + { F(Rep) , 420, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #167 [ref=1x] + { 0 , 421, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #168 [ref=30x] { 0 , 159, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #169 [ref=2x] - { 0 , 421, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #170 [ref=3x] - { F(Rep) , 422, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #171 [ref=1x] + { 0 , 422, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #170 [ref=3x] + { F(Rep) , 423, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #171 [ref=1x] { 0 , 57 , 7 , CONTROL(None) , SINGLE_REG(None), 0 }, // #172 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512T4X)|F(Avx512KZ) , 423, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #173 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512T4X)|F(Avx512KZ) , 424, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #174 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512T4X)|F(Avx512KZ) , 424, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #173 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512T4X)|F(Avx512KZ) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #174 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #175 [ref=22x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #176 [ref=22x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #177 [ref=18x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #178 [ref=17x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #177 [ref=18x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #178 [ref=17x] { F(Vec)|F(Vex) , 162, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #179 [ref=15x] { F(Vec)|F(Vex)|F(Evex) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #180 [ref=5x] { F(Vec)|F(Vex) , 70 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #181 [ref=17x] @@ -2183,136 +2183,136 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #190 [ref=16x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #191 [ref=19x] { F(Vec)|F(Vex) , 165, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #192 [ref=6x] - { F(Vec)|F(Vex) , 311, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #193 [ref=3x] - { F(Vec)|F(Vex) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #194 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 428, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #195 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 429, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #196 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 430, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #197 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 431, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #198 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 428, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #199 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 432, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #200 [ref=1x] + { F(Vec)|F(Vex) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #193 [ref=3x] + { F(Vec)|F(Vex) , 428, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #194 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 429, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #195 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 430, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #196 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 431, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #197 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 432, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #198 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 429, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #199 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 433, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #200 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B64) , 168, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #201 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B32) , 168, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #202 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 433, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #203 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 434, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #204 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 434, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #203 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 435, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #204 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 97 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #205 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 222, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #206 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ) , 171, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #207 [ref=6x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B32) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #208 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #209 [ref=3x] - { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #210 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #211 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #210 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #211 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #212 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #213 [ref=3x] + { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #213 [ref=3x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #214 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #215 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 180, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #216 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #217 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #218 [ref=2x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #219 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #220 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 435, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #221 [ref=2x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #222 [ref=3x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #223 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #224 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B64) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #225 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #219 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #220 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 436, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #221 [ref=2x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #222 [ref=3x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #223 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #224 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B64) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #225 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #226 [ref=3x] - { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #227 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #227 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B32) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #228 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B32) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #229 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B32) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #230 [ref=2x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #231 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512SAE) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #232 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #233 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #234 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #231 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #232 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #233 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512SAE) , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #234 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #235 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 435, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #236 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 436, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #236 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #237 [ref=3x] { F(Vec)|F(Vex) , 165, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #238 [ref=9x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 74 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #239 [ref=3x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B32) , 74 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #240 [ref=3x] { F(Vec)|F(Evex)|F(Avx512KZ) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #241 [ref=9x] { F(Vec)|F(Vex) , 181, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #242 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 436, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #243 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 437, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #243 [ref=4x] { F(Vec)|F(Evex)|F(Avx512KZ) , 182, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #244 [ref=4x] - { F(Vec)|F(Vex)|F(Evex) , 367, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #245 [ref=2x] + { F(Vec)|F(Vex)|F(Evex) , 369, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #245 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #246 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B32) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #247 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 437, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #248 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #249 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #248 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #249 [ref=4x] { F(Vec)|F(Vex) , 130, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #250 [ref=13x] - { F(Vec)|F(Vex) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #251 [ref=4x] - { F(Vec)|F(Vex) , 317, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #252 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512K_B64) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #253 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512K_B32) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #254 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512K) , 440, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #255 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512K) , 441, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #256 [ref=1x] + { F(Vec)|F(Vex) , 317, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #251 [ref=4x] + { F(Vec)|F(Vex) , 319, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #252 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512K_B64) , 440, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #253 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512K_B32) , 440, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #254 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512K) , 441, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #255 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512K) , 442, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #256 [ref=1x] { F(Vec)|F(Vex) , 177, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #257 [ref=7x] { F(Vec)|F(Vex) , 97 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #258 [ref=1x] { F(Vec)|F(Vex) , 222, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #259 [ref=1x] { F(Vec)|F(Vsib)|F(Vex)|F(Evex)|F(Avx512K) , 99 , 5 , CONTROL(None) , SINGLE_REG(None), 0 }, // #260 [ref=2x] { F(Vec)|F(Vsib)|F(Vex)|F(Evex)|F(Avx512K) , 104, 5 , CONTROL(None) , SINGLE_REG(None), 0 }, // #261 [ref=2x] - { F(Vsib)|F(Evex)|F(Avx512K) , 442, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #262 [ref=4x] - { F(Vsib)|F(Evex)|F(Avx512K) , 443, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #263 [ref=4x] - { F(Vsib)|F(Evex)|F(Avx512K) , 444, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #264 [ref=8x] + { F(Vsib)|F(Evex)|F(Avx512K) , 443, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #262 [ref=4x] + { F(Vsib)|F(Evex)|F(Avx512K) , 444, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #263 [ref=4x] + { F(Vsib)|F(Evex)|F(Avx512K) , 445, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #264 [ref=8x] { F(Vec)|F(Vsib)|F(Vex)|F(Evex)|F(Avx512K) , 109, 5 , CONTROL(None) , SINGLE_REG(None), 0 }, // #265 [ref=2x] { F(Vec)|F(Vsib)|F(Vex)|F(Evex)|F(Avx512K) , 134, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #266 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #267 [ref=3x] - { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #268 [ref=3x] + { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #267 [ref=3x] + { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #268 [ref=3x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #269 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B32) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #270 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #271 [ref=3x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #272 [ref=22x] - { F(Vec)|F(Vex) , 319, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #273 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 319, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #274 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 445, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #275 [ref=4x] - { F(Vec)|F(Vex)|F(Evex) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #276 [ref=1x] + { F(Vec)|F(Vex) , 321, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #273 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 321, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #274 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 446, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #275 [ref=4x] + { F(Vec)|F(Vex)|F(Evex) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #276 [ref=1x] { F(Vec)|F(Vex) , 192, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #277 [ref=1x] - { F(Vex) , 384, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #278 [ref=2x] - { F(Vec)|F(Vex) , 390, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #279 [ref=1x] + { F(Vex) , 386, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #278 [ref=2x] + { F(Vec)|F(Vex) , 392, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #279 [ref=1x] { F(Vec)|F(Vex) , 138, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #280 [ref=4x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #281 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #282 [ref=2x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #283 [ref=2x] - { 0 , 446, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #284 [ref=4x] - { 0 , 321, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #285 [ref=3x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #283 [ref=2x] + { 0 , 447, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #284 [ref=4x] + { 0 , 323, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #285 [ref=3x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 70 , 6 , CONTROL(None) , SINGLE_REG(None), 0 }, // #286 [ref=4x] - { F(Vec)|F(Vex)|F(Evex) , 323, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #287 [ref=1x] + { F(Vec)|F(Vex)|F(Evex) , 325, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #287 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 186, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #288 [ref=1x] { F(Vec)|F(Vex) , 70 , 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #289 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ) , 70 , 6 , CONTROL(None) , SINGLE_REG(None), 0 }, // #290 [ref=6x] { F(Vec)|F(Vex)|F(Evex) , 200, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #291 [ref=2x] - { F(Vec)|F(Vex)|F(Evex) , 325, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #292 [ref=4x] - { F(Vec)|F(Vex) , 447, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #293 [ref=3x] + { F(Vec)|F(Vex)|F(Evex) , 327, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #292 [ref=4x] + { F(Vec)|F(Vex) , 448, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #293 [ref=3x] { F(Vec)|F(Vex)|F(Evex) , 189, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #294 [ref=3x] { F(Vec)|F(Vex)|F(Evex) , 192, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #295 [ref=1x] { F(Vec)|F(Vex)|F(Evex) , 195, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #296 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 198, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #297 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #298 [ref=5x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 201, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #299 [ref=1x] - { 0 , 327, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #300 [ref=1x] - { 0 , 329, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #301 [ref=1x] + { 0 , 329, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #300 [ref=1x] + { 0 , 331, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #301 [ref=1x] { F(Vec)|F(Vex) , 162, 2 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #302 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #303 [ref=2x] { F(Vec)|F(Vex) , 162, 2 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #304 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #305 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #306 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #307 [ref=2x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 448, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #308 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 449, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #309 [ref=1x] - { F(Vec)|F(Evex) , 450, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #310 [ref=6x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 449, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #308 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 450, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #309 [ref=1x] + { F(Vec)|F(Evex) , 451, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #310 [ref=6x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 204, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #311 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 451, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #312 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 452, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #312 [ref=1x] { F(Vec)|F(Vex)|F(Evex) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #313 [ref=1x] { F(Vec)|F(Evex)|F(Avx512K) , 207, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #314 [ref=2x] { F(Vec)|F(Evex)|F(Avx512K_B32) , 207, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #315 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512K) , 210, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #316 [ref=4x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512K_B32) , 210, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #317 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512K_B64) , 210, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #318 [ref=2x] - { F(Vec)|F(Vex) , 404, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #319 [ref=1x] - { F(Vec)|F(Vex) , 405, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #320 [ref=1x] - { F(Vec)|F(Vex) , 406, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #321 [ref=1x] - { F(Vec)|F(Vex) , 407, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #322 [ref=1x] + { F(Vec)|F(Vex) , 405, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #319 [ref=1x] + { F(Vec)|F(Vex) , 406, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #320 [ref=1x] + { F(Vec)|F(Vex) , 407, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #321 [ref=1x] + { F(Vec)|F(Vex) , 408, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #322 [ref=1x] { F(Vec)|F(Evex)|F(Avx512K_B64) , 207, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #323 [ref=4x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #324 [ref=6x] { F(Vec)|F(Vex) , 166, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #325 [ref=2x] @@ -2320,17 +2320,17 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Vex) , 142, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #327 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B64) , 76 , 6 , CONTROL(None) , SINGLE_REG(None), 0 }, // #328 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B64) , 146, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #329 [ref=2x] - { F(Vec)|F(Vex)|F(Evex) , 408, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #330 [ref=1x] - { F(Vec)|F(Vex)|F(Evex) , 409, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #331 [ref=1x] - { F(Vec)|F(Vex)|F(Evex) , 452, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #332 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 453, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #333 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 454, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #334 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 455, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #335 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 456, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #336 [ref=1x] + { F(Vec)|F(Vex)|F(Evex) , 409, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #330 [ref=1x] + { F(Vec)|F(Vex)|F(Evex) , 410, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #331 [ref=1x] + { F(Vec)|F(Vex)|F(Evex) , 453, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #332 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 454, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #333 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 455, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #334 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 456, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #335 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 457, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #336 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #337 [ref=4x] - { F(Vec)|F(Vex) , 311, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #338 [ref=12x] + { F(Vec)|F(Vex) , 313, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #338 [ref=12x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 162, 3 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #339 [ref=8x] - { F(Vec)|F(Evex) , 457, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #340 [ref=4x] + { F(Vec)|F(Evex) , 458, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #340 [ref=4x] { F(Vec)|F(Evex)|F(Avx512KZ) , 213, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #341 [ref=6x] { F(Vec)|F(Evex)|F(Avx512KZ) , 216, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #342 [ref=9x] { F(Vec)|F(Evex)|F(Avx512KZ) , 219, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #343 [ref=3x] @@ -2340,11 +2340,11 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Vex) , 130, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #347 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #348 [ref=3x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #349 [ref=3x] - { F(Vec)|F(Vex) , 331, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #350 [ref=4x] + { F(Vec)|F(Vex) , 333, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #350 [ref=4x] { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 228, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #351 [ref=3x] - { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 333, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #352 [ref=2x] + { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 335, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #352 [ref=2x] { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 231, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #353 [ref=2x] - { F(Vec)|F(Vex) , 335, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #354 [ref=8x] + { F(Vec)|F(Vex) , 337, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #354 [ref=8x] { F(Vec)|F(Evex)|F(Avx512K) , 234, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #355 [ref=5x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B32) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #356 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #357 [ref=2x] @@ -2358,19 +2358,19 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #365 [ref=2x] { F(Vec)|F(Evex)|F(Avx512K_B32) , 234, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #366 [ref=2x] { F(Vec)|F(Evex)|F(Avx512K_B64) , 234, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #367 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #368 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #369 [ref=2x] - { F(Vec)|F(Vex) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #370 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 437, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #371 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #372 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #368 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #369 [ref=2x] + { F(Vec)|F(Vex) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #370 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #371 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #372 [ref=1x] { F(Vec)|F(Vex) , 183, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #373 [ref=2x] - { F(Vec)|F(Vex) , 437, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #374 [ref=1x] - { F(Vec)|F(Vex) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #375 [ref=1x] + { F(Vec)|F(Vex) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #374 [ref=1x] + { F(Vec)|F(Vex) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #375 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #376 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #377 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #378 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #379 [ref=1x] - { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 337, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #380 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #378 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #379 [ref=1x] + { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 339, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #380 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 166, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #381 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 166, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #382 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B32) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #383 [ref=1x] @@ -2378,10 +2378,10 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #385 [ref=1x] { F(Vec)|F(Vex) , 257, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #386 [ref=2x] { F(Lock)|F(XAcquire)|F(XRelease) , 49 , 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #387 [ref=1x] - { 0 , 458, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #388 [ref=1x] + { 0 , 459, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #388 [ref=1x] { F(Lock)|F(XAcquire) , 49 , 8 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #389 [ref=1x] - { 0 , 459, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #390 [ref=6x] - { 0 , 460, 1 , CONTROL(None) , SINGLE_REG(None), 0 } // #391 [ref=6x] + { 0 , 460, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #390 [ref=6x] + { 0 , 461, 1 , CONTROL(None) , SINGLE_REG(None), 0 } // #391 [ref=6x] }; #undef SINGLE_REG #undef CONTROL @@ -3070,174 +3070,175 @@ const InstDB::InstSignature InstDB::_instSignatureTable[] = { ROW(2, 1, 1, 0, 29 , 45 , 0 , 0 , 0 , 0 ), // {m32|mem, xmm} ROW(2, 1, 1, 0, 4 , 9 , 0 , 0 , 0 , 0 ), // #291 {r16, r8lo|r8hi|m8} ROW(2, 1, 1, 0, 114, 115, 0 , 0 , 0 , 0 ), // {r32|r64, r8lo|r8hi|m8|r16|m16} - ROW(4, 1, 1, 1, 6 , 6 , 28 , 35 , 0 , 0 ), // #293 {r32, r32, r32|m32|mem, <edx>} + ROW(2, 0, 1, 0, 4 , 27 , 0 , 0 , 0 , 0 ), // #293 {r16, r16|m16|mem} + ROW(2, 0, 1, 0, 114, 28 , 0 , 0 , 0 , 0 ), // {r32|r64, r32|m32|mem} + ROW(4, 1, 1, 1, 6 , 6 , 28 , 35 , 0 , 0 ), // #295 {r32, r32, r32|m32|mem, <edx>} ROW(4, 0, 1, 1, 8 , 8 , 15 , 37 , 0 , 0 ), // {r64, r64, r64|m64|mem, <rdx>} - ROW(0, 1, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #295 {} + ROW(0, 1, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #297 {} ROW(1, 1, 1, 0, 116, 0 , 0 , 0 , 0 , 0 ), // {r16|m16|r32|m32} - ROW(2, 1, 1, 0, 57 , 117, 0 , 0 , 0 , 0 ), // #297 {mm, mm|m64|mem} + ROW(2, 1, 1, 0, 57 , 117, 0 , 0 , 0 , 0 ), // #299 {mm, mm|m64|mem} ROW(2, 1, 1, 0, 45 , 46 , 0 , 0 , 0 , 0 ), // {xmm, xmm|m128|mem} - ROW(3, 1, 1, 0, 57 , 117, 10 , 0 , 0 , 0 ), // #299 {mm, mm|m64|mem, i8|u8} + ROW(3, 1, 1, 0, 57 , 117, 10 , 0 , 0 , 0 ), // #301 {mm, mm|m64|mem, i8|u8} ROW(3, 1, 1, 0, 45 , 46 , 10 , 0 , 0 , 0 ), // {xmm, xmm|m128|mem, i8|u8} - ROW(3, 1, 1, 0, 6 , 59 , 10 , 0 , 0 , 0 ), // #301 {r32, mm|xmm, i8|u8} + ROW(3, 1, 1, 0, 6 , 59 , 10 , 0 , 0 , 0 ), // #303 {r32, mm|xmm, i8|u8} ROW(3, 1, 1, 0, 21 , 45 , 10 , 0 , 0 , 0 ), // {m16|mem, xmm, i8|u8} - ROW(2, 1, 1, 0, 57 , 118, 0 , 0 , 0 , 0 ), // #303 {mm, i8|u8|mm|m64|mem} + ROW(2, 1, 1, 0, 57 , 118, 0 , 0 , 0 , 0 ), // #305 {mm, i8|u8|mm|m64|mem} ROW(2, 1, 1, 0, 45 , 54 , 0 , 0 , 0 , 0 ), // {xmm, i8|u8|xmm|m128|mem} - ROW(1, 1, 0, 0, 6 , 0 , 0 , 0 , 0 , 0 ), // #305 {r32} + ROW(1, 1, 0, 0, 6 , 0 , 0 , 0 , 0 , 0 ), // #307 {r32} ROW(1, 0, 1, 0, 8 , 0 , 0 , 0 , 0 , 0 ), // {r64} - ROW(0, 1, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #307 {} + ROW(0, 1, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #309 {} ROW(1, 1, 1, 0, 119, 0 , 0 , 0 , 0 , 0 ), // {u16} - ROW(3, 1, 1, 0, 6 , 28 , 10 , 0 , 0 , 0 ), // #309 {r32, r32|m32|mem, i8|u8} + ROW(3, 1, 1, 0, 6 , 28 , 10 , 0 , 0 , 0 ), // #311 {r32, r32|m32|mem, i8|u8} ROW(3, 0, 1, 0, 8 , 15 , 10 , 0 , 0 , 0 ), // {r64, r64|m64|mem, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 46 , 45 , 0 , 0 ), // #311 {xmm, xmm, xmm|m128|mem, xmm} + ROW(4, 1, 1, 0, 45 , 45 , 46 , 45 , 0 , 0 ), // #313 {xmm, xmm, xmm|m128|mem, xmm} ROW(4, 1, 1, 0, 48 , 48 , 49 , 48 , 0 , 0 ), // {ymm, ymm, ymm|m256|mem, ymm} - ROW(2, 1, 1, 0, 45 , 120, 0 , 0 , 0 , 0 ), // #313 {xmm, xmm|m128|ymm|m256} + ROW(2, 1, 1, 0, 45 , 120, 0 , 0 , 0 , 0 ), // #315 {xmm, xmm|m128|ymm|m256} ROW(2, 1, 1, 0, 48 , 52 , 0 , 0 , 0 , 0 ), // {ymm, zmm|m512|mem} - ROW(4, 1, 1, 0, 45 , 45 , 45 , 60 , 0 , 0 ), // #315 {xmm, xmm, xmm, xmm|m64|mem} + ROW(4, 1, 1, 0, 45 , 45 , 45 , 60 , 0 , 0 ), // #317 {xmm, xmm, xmm, xmm|m64|mem} ROW(4, 1, 1, 0, 45 , 45 , 30 , 45 , 0 , 0 ), // {xmm, xmm, m64|mem, xmm} - ROW(4, 1, 1, 0, 45 , 45 , 45 , 87 , 0 , 0 ), // #317 {xmm, xmm, xmm, xmm|m32|mem} + ROW(4, 1, 1, 0, 45 , 45 , 45 , 87 , 0 , 0 ), // #319 {xmm, xmm, xmm, xmm|m32|mem} ROW(4, 1, 1, 0, 45 , 45 , 29 , 45 , 0 , 0 ), // {xmm, xmm, m32|mem, xmm} - ROW(4, 1, 1, 0, 48 , 48 , 46 , 10 , 0 , 0 ), // #319 {ymm, ymm, xmm|m128|mem, i8|u8} + ROW(4, 1, 1, 0, 48 , 48 , 46 , 10 , 0 , 0 ), // #321 {ymm, ymm, xmm|m128|mem, i8|u8} ROW(4, 1, 1, 0, 51 , 51 , 46 , 10 , 0 , 0 ), // {zmm, zmm, xmm|m128|mem, i8|u8} - ROW(1, 1, 0, 1, 36 , 0 , 0 , 0 , 0 , 0 ), // #321 {<eax>} - ROW(1, 0, 1, 1, 38 , 0 , 0 , 0 , 0 , 0 ), // #322 {<rax>} - ROW(2, 1, 1, 0, 28 , 45 , 0 , 0 , 0 , 0 ), // #323 {r32|m32|mem, xmm} + ROW(1, 1, 0, 1, 36 , 0 , 0 , 0 , 0 , 0 ), // #323 {<eax>} + ROW(1, 0, 1, 1, 38 , 0 , 0 , 0 , 0 , 0 ), // #324 {<rax>} + ROW(2, 1, 1, 0, 28 , 45 , 0 , 0 , 0 , 0 ), // #325 {r32|m32|mem, xmm} ROW(2, 1, 1, 0, 45 , 28 , 0 , 0 , 0 , 0 ), // {xmm, r32|m32|mem} - ROW(2, 1, 1, 0, 30 , 45 , 0 , 0 , 0 , 0 ), // #325 {m64|mem, xmm} + ROW(2, 1, 1, 0, 30 , 45 , 0 , 0 , 0 , 0 ), // #327 {m64|mem, xmm} ROW(3, 1, 1, 0, 45 , 45 , 30 , 0 , 0 , 0 ), // {xmm, xmm, m64|mem} - ROW(2, 1, 0, 0, 28 , 6 , 0 , 0 , 0 , 0 ), // #327 {r32|m32|mem, r32} + ROW(2, 1, 0, 0, 28 , 6 , 0 , 0 , 0 , 0 ), // #329 {r32|m32|mem, r32} ROW(2, 0, 1, 0, 15 , 8 , 0 , 0 , 0 , 0 ), // {r64|m64|mem, r64} - ROW(2, 1, 0, 0, 6 , 28 , 0 , 0 , 0 , 0 ), // #329 {r32, r32|m32|mem} + ROW(2, 1, 0, 0, 6 , 28 , 0 , 0 , 0 , 0 ), // #331 {r32, r32|m32|mem} ROW(2, 0, 1, 0, 8 , 15 , 0 , 0 , 0 , 0 ), // {r64, r64|m64|mem} - ROW(3, 1, 1, 0, 45 , 45 , 54 , 0 , 0 , 0 ), // #331 {xmm, xmm, xmm|m128|mem|i8|u8} + ROW(3, 1, 1, 0, 45 , 45 , 54 , 0 , 0 , 0 ), // #333 {xmm, xmm, xmm|m128|mem|i8|u8} ROW(3, 1, 1, 0, 45 , 47 , 121, 0 , 0 , 0 ), // {xmm, m128|mem, i8|u8|xmm} - ROW(2, 1, 1, 0, 74 , 45 , 0 , 0 , 0 , 0 ), // #333 {vm64x|vm64y, xmm} + ROW(2, 1, 1, 0, 74 , 45 , 0 , 0 , 0 , 0 ), // #335 {vm64x|vm64y, xmm} ROW(2, 1, 1, 0, 66 , 48 , 0 , 0 , 0 , 0 ), // {vm64z, ymm} - ROW(3, 1, 1, 0, 45 , 45 , 46 , 0 , 0 , 0 ), // #335 {xmm, xmm, xmm|m128|mem} + ROW(3, 1, 1, 0, 45 , 45 , 46 , 0 , 0 , 0 ), // #337 {xmm, xmm, xmm|m128|mem} ROW(3, 1, 1, 0, 45 , 47 , 45 , 0 , 0 , 0 ), // {xmm, m128|mem, xmm} - ROW(2, 1, 1, 0, 61 , 86 , 0 , 0 , 0 , 0 ), // #337 {vm32x, xmm|ymm} + ROW(2, 1, 1, 0, 61 , 86 , 0 , 0 , 0 , 0 ), // #339 {vm32x, xmm|ymm} ROW(2, 1, 1, 0, 62 , 51 , 0 , 0 , 0 , 0 ), // {vm32y, zmm} - ROW(1, 1, 0, 1, 33 , 0 , 0 , 0 , 0 , 0 ), // #339 {<ax>} - ROW(2, 1, 0, 1, 33 , 10 , 0 , 0 , 0 , 0 ), // #340 {<ax>, i8|u8} - ROW(2, 1, 0, 0, 27 , 4 , 0 , 0 , 0 , 0 ), // #341 {r16|m16|mem, r16} - ROW(3, 1, 1, 1, 45 , 46 , 122, 0 , 0 , 0 ), // #342 {xmm, xmm|m128|mem, <xmm0>} - ROW(2, 1, 1, 0, 89 , 123, 0 , 0 , 0 , 0 ), // #343 {bnd, mib} - ROW(2, 1, 1, 0, 89 , 91 , 0 , 0 , 0 , 0 ), // #344 {bnd, mem} - ROW(2, 1, 1, 0, 123, 89 , 0 , 0 , 0 , 0 ), // #345 {mib, bnd} - ROW(1, 1, 1, 0, 124, 0 , 0 , 0 , 0 , 0 ), // #346 {r16|r32|r64} - ROW(1, 1, 1, 1, 33 , 0 , 0 , 0 , 0 , 0 ), // #347 {<ax>} - ROW(2, 1, 1, 2, 35 , 36 , 0 , 0 , 0 , 0 ), // #348 {<edx>, <eax>} - ROW(1, 1, 1, 0, 91 , 0 , 0 , 0 , 0 , 0 ), // #349 {mem} - ROW(1, 1, 1, 1, 125, 0 , 0 , 0 , 0 , 0 ), // #350 {<ds:[memBase|zax]>} - ROW(2, 1, 1, 2, 126, 127, 0 , 0 , 0 , 0 ), // #351 {<ds:[memBase|zsi]>, <es:[memBase|zdi]>} - ROW(3, 1, 1, 0, 45 , 60 , 10 , 0 , 0 , 0 ), // #352 {xmm, xmm|m64|mem, i8|u8} - ROW(3, 1, 1, 0, 45 , 87 , 10 , 0 , 0 , 0 ), // #353 {xmm, xmm|m32|mem, i8|u8} - ROW(5, 0, 1, 4, 47 , 37 , 38 , 128, 129, 0 ), // #354 {m128|mem, <rdx>, <rax>, <rcx>, <rbx>} - ROW(5, 1, 1, 4, 30 , 35 , 36 , 99 , 130, 0 ), // #355 {m64|mem, <edx>, <eax>, <ecx>, <ebx>} - ROW(4, 1, 1, 4, 36 , 130, 99 , 35 , 0 , 0 ), // #356 {<eax>, <ebx>, <ecx>, <edx>} - ROW(2, 0, 1, 2, 37 , 38 , 0 , 0 , 0 , 0 ), // #357 {<rdx>, <rax>} - ROW(2, 1, 1, 0, 57 , 46 , 0 , 0 , 0 , 0 ), // #358 {mm, xmm|m128|mem} - ROW(2, 1, 1, 0, 45 , 117, 0 , 0 , 0 , 0 ), // #359 {xmm, mm|m64|mem} - ROW(2, 1, 1, 0, 57 , 60 , 0 , 0 , 0 , 0 ), // #360 {mm, xmm|m64|mem} - ROW(2, 1, 1, 0, 114, 60 , 0 , 0 , 0 , 0 ), // #361 {r32|r64, xmm|m64|mem} - ROW(2, 1, 1, 0, 45 , 131, 0 , 0 , 0 , 0 ), // #362 {xmm, r32|m32|mem|r64|m64} - ROW(2, 1, 1, 0, 114, 87 , 0 , 0 , 0 , 0 ), // #363 {r32|r64, xmm|m32|mem} - ROW(2, 1, 1, 2, 34 , 33 , 0 , 0 , 0 , 0 ), // #364 {<dx>, <ax>} - ROW(1, 1, 1, 1, 36 , 0 , 0 , 0 , 0 , 0 ), // #365 {<eax>} - ROW(2, 1, 1, 0, 12 , 10 , 0 , 0 , 0 , 0 ), // #366 {i16|u16, i8|u8} - ROW(3, 1, 1, 0, 28 , 45 , 10 , 0 , 0 , 0 ), // #367 {r32|m32|mem, xmm, i8|u8} - ROW(1, 1, 1, 0, 80 , 0 , 0 , 0 , 0 , 0 ), // #368 {m80|mem} - ROW(1, 1, 1, 0, 132, 0 , 0 , 0 , 0 , 0 ), // #369 {m16|m32} - ROW(1, 1, 1, 0, 133, 0 , 0 , 0 , 0 , 0 ), // #370 {m16|m32|m64} - ROW(1, 1, 1, 0, 134, 0 , 0 , 0 , 0 , 0 ), // #371 {m32|m64|m80|st} - ROW(1, 1, 1, 0, 21 , 0 , 0 , 0 , 0 , 0 ), // #372 {m16|mem} - ROW(1, 1, 1, 0, 135, 0 , 0 , 0 , 0 , 0 ), // #373 {ax|m16|mem} - ROW(1, 0, 1, 0, 91 , 0 , 0 , 0 , 0 , 0 ), // #374 {mem} - ROW(2, 1, 1, 0, 136, 137, 0 , 0 , 0 , 0 ), // #375 {al|ax|eax, i8|u8|dx} - ROW(2, 1, 1, 0, 138, 139, 0 , 0 , 0 , 0 ), // #376 {es:[memBase|zdi], dx} - ROW(1, 1, 1, 0, 10 , 0 , 0 , 0 , 0 , 0 ), // #377 {i8|u8} - ROW(0, 1, 0, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #378 {} - ROW(0, 0, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #379 {} - ROW(3, 1, 1, 0, 84 , 84 , 84 , 0 , 0 , 0 ), // #380 {k, k, k} - ROW(2, 1, 1, 0, 84 , 84 , 0 , 0 , 0 , 0 ), // #381 {k, k} - ROW(3, 1, 1, 0, 84 , 84 , 10 , 0 , 0 , 0 ), // #382 {k, k, i8|u8} - ROW(1, 1, 1, 1, 140, 0 , 0 , 0 , 0 , 0 ), // #383 {<ah>} - ROW(1, 1, 1, 0, 29 , 0 , 0 , 0 , 0 , 0 ), // #384 {m32|mem} - ROW(2, 1, 1, 0, 124, 141, 0 , 0 , 0 , 0 ), // #385 {r16|r32|r64, mem|m8|m16|m32|m48|m64|m80|m128|m256|m512|m1024} - ROW(1, 1, 1, 0, 27 , 0 , 0 , 0 , 0 , 0 ), // #386 {r16|m16|mem} - ROW(1, 1, 1, 0, 114, 0 , 0 , 0 , 0 , 0 ), // #387 {r32|r64} - ROW(2, 1, 1, 2, 142, 126, 0 , 0 , 0 , 0 ), // #388 {<al|ax|eax|rax>, <ds:[memBase|zsi]>} - ROW(3, 1, 1, 0, 114, 28 , 14 , 0 , 0 , 0 ), // #389 {r32|r64, r32|m32|mem, i32|u32} - ROW(3, 1, 1, 1, 45 , 45 , 143, 0 , 0 , 0 ), // #390 {xmm, xmm, <ds:[memBase|zdi]>} - ROW(3, 1, 1, 1, 57 , 57 , 143, 0 , 0 , 0 ), // #391 {mm, mm, <ds:[memBase|zdi]>} - ROW(3, 1, 1, 3, 125, 99 , 35 , 0 , 0 , 0 ), // #392 {<ds:[memBase|zax]>, <ecx>, <edx>} - ROW(2, 1, 1, 0, 97 , 53 , 0 , 0 , 0 , 0 ), // #393 {es:[memBase], m512|mem} - ROW(2, 1, 1, 0, 57 , 45 , 0 , 0 , 0 , 0 ), // #394 {mm, xmm} - ROW(2, 1, 1, 0, 6 , 45 , 0 , 0 , 0 , 0 ), // #395 {r32, xmm} - ROW(2, 1, 1, 0, 30 , 57 , 0 , 0 , 0 , 0 ), // #396 {m64|mem, mm} - ROW(2, 1, 1, 0, 45 , 57 , 0 , 0 , 0 , 0 ), // #397 {xmm, mm} - ROW(2, 1, 1, 2, 127, 126, 0 , 0 , 0 , 0 ), // #398 {<es:[memBase|zdi]>, <ds:[memBase|zsi]>} - ROW(2, 0, 1, 0, 8 , 28 , 0 , 0 , 0 , 0 ), // #399 {r64, r32|m32|mem} - ROW(2, 1, 1, 2, 36 , 99 , 0 , 0 , 0 , 0 ), // #400 {<eax>, <ecx>} - ROW(3, 1, 1, 3, 36 , 99 , 130, 0 , 0 , 0 ), // #401 {<eax>, <ecx>, <ebx>} - ROW(2, 1, 1, 0, 144, 136, 0 , 0 , 0 , 0 ), // #402 {u8|dx, al|ax|eax} - ROW(2, 1, 1, 0, 139, 145, 0 , 0 , 0 , 0 ), // #403 {dx, ds:[memBase|zsi]} - ROW(6, 1, 1, 3, 45 , 46 , 10 , 99 , 36 , 35 ), // #404 {xmm, xmm|m128|mem, i8|u8, <ecx>, <eax>, <edx>} - ROW(6, 1, 1, 3, 45 , 46 , 10 , 122, 36 , 35 ), // #405 {xmm, xmm|m128|mem, i8|u8, <xmm0>, <eax>, <edx>} - ROW(4, 1, 1, 1, 45 , 46 , 10 , 99 , 0 , 0 ), // #406 {xmm, xmm|m128|mem, i8|u8, <ecx>} - ROW(4, 1, 1, 1, 45 , 46 , 10 , 122, 0 , 0 ), // #407 {xmm, xmm|m128|mem, i8|u8, <xmm0>} - ROW(3, 1, 1, 0, 109, 45 , 10 , 0 , 0 , 0 ), // #408 {r32|m8|mem|r8lo|r8hi|r16, xmm, i8|u8} - ROW(3, 0, 1, 0, 15 , 45 , 10 , 0 , 0 , 0 ), // #409 {r64|m64|mem, xmm, i8|u8} - ROW(3, 1, 1, 0, 45 , 109, 10 , 0 , 0 , 0 ), // #410 {xmm, r32|m8|mem|r8lo|r8hi|r16, i8|u8} - ROW(3, 1, 1, 0, 45 , 28 , 10 , 0 , 0 , 0 ), // #411 {xmm, r32|m32|mem, i8|u8} - ROW(3, 0, 1, 0, 45 , 15 , 10 , 0 , 0 , 0 ), // #412 {xmm, r64|m64|mem, i8|u8} - ROW(3, 1, 1, 0, 59 , 113, 10 , 0 , 0 , 0 ), // #413 {mm|xmm, r32|m16|mem|r16, i8|u8} - ROW(2, 1, 1, 0, 6 , 59 , 0 , 0 , 0 , 0 ), // #414 {r32, mm|xmm} - ROW(2, 1, 1, 0, 45 , 10 , 0 , 0 , 0 , 0 ), // #415 {xmm, i8|u8} - ROW(2, 1, 1, 0, 31 , 81 , 0 , 0 , 0 , 0 ), // #416 {r8lo|r8hi|m8|r16|m16|r32|m32|r64|m64|mem, cl|i8|u8} - ROW(1, 0, 1, 0, 114, 0 , 0 , 0 , 0 , 0 ), // #417 {r32|r64} - ROW(3, 1, 1, 3, 35 , 36 , 99 , 0 , 0 , 0 ), // #418 {<edx>, <eax>, <ecx>} - ROW(2, 1, 1, 2, 142, 127, 0 , 0 , 0 , 0 ), // #419 {<al|ax|eax|rax>, <es:[memBase|zdi]>} - ROW(1, 1, 1, 0, 1 , 0 , 0 , 0 , 0 , 0 ), // #420 {r8lo|r8hi|m8|mem} - ROW(1, 1, 1, 0, 146, 0 , 0 , 0 , 0 , 0 ), // #421 {r16|m16|mem|r32|r64} - ROW(2, 1, 1, 2, 127, 142, 0 , 0 , 0 , 0 ), // #422 {<es:[memBase|zdi]>, <al|ax|eax|rax>} - ROW(6, 1, 1, 0, 51 , 51 , 51 , 51 , 51 , 47 ), // #423 {zmm, zmm, zmm, zmm, zmm, m128|mem} - ROW(6, 1, 1, 0, 45 , 45 , 45 , 45 , 45 , 47 ), // #424 {xmm, xmm, xmm, xmm, xmm, m128|mem} - ROW(3, 1, 1, 0, 45 , 45 , 60 , 0 , 0 , 0 ), // #425 {xmm, xmm, xmm|m64|mem} - ROW(3, 1, 1, 0, 45 , 45 , 87 , 0 , 0 , 0 ), // #426 {xmm, xmm, xmm|m32|mem} - ROW(2, 1, 1, 0, 48 , 47 , 0 , 0 , 0 , 0 ), // #427 {ymm, m128|mem} - ROW(2, 1, 1, 0, 147, 60 , 0 , 0 , 0 , 0 ), // #428 {ymm|zmm, xmm|m64|mem} - ROW(2, 1, 1, 0, 147, 47 , 0 , 0 , 0 , 0 ), // #429 {ymm|zmm, m128|mem} - ROW(2, 1, 1, 0, 51 , 50 , 0 , 0 , 0 , 0 ), // #430 {zmm, m256|mem} - ROW(2, 1, 1, 0, 148, 60 , 0 , 0 , 0 , 0 ), // #431 {xmm|ymm|zmm, xmm|m64|mem} - ROW(2, 1, 1, 0, 148, 87 , 0 , 0 , 0 , 0 ), // #432 {xmm|ymm|zmm, m32|mem|xmm} - ROW(4, 1, 1, 0, 82 , 45 , 60 , 10 , 0 , 0 ), // #433 {xmm|k, xmm, xmm|m64|mem, i8|u8} - ROW(4, 1, 1, 0, 82 , 45 , 87 , 10 , 0 , 0 ), // #434 {xmm|k, xmm, xmm|m32|mem, i8|u8} - ROW(3, 1, 1, 0, 45 , 45 , 131, 0 , 0 , 0 ), // #435 {xmm, xmm, r32|m32|mem|r64|m64} - ROW(3, 1, 1, 0, 46 , 147, 10 , 0 , 0 , 0 ), // #436 {xmm|m128|mem, ymm|zmm, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 60 , 10 , 0 , 0 ), // #437 {xmm, xmm, xmm|m64|mem, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 87 , 10 , 0 , 0 ), // #438 {xmm, xmm, xmm|m32|mem, i8|u8} - ROW(3, 1, 1, 0, 84 , 149, 10 , 0 , 0 , 0 ), // #439 {k, xmm|m128|ymm|m256|zmm|m512, i8|u8} - ROW(3, 1, 1, 0, 84 , 60 , 10 , 0 , 0 , 0 ), // #440 {k, xmm|m64|mem, i8|u8} - ROW(3, 1, 1, 0, 84 , 87 , 10 , 0 , 0 , 0 ), // #441 {k, xmm|m32|mem, i8|u8} - ROW(1, 1, 1, 0, 62 , 0 , 0 , 0 , 0 , 0 ), // #442 {vm32y} - ROW(1, 1, 1, 0, 63 , 0 , 0 , 0 , 0 , 0 ), // #443 {vm32z} - ROW(1, 1, 1, 0, 66 , 0 , 0 , 0 , 0 , 0 ), // #444 {vm64z} - ROW(4, 1, 1, 0, 51 , 51 , 49 , 10 , 0 , 0 ), // #445 {zmm, zmm, ymm|m256|mem, i8|u8} - ROW(1, 1, 1, 0, 30 , 0 , 0 , 0 , 0 , 0 ), // #446 {m64|mem} - ROW(2, 1, 1, 0, 6 , 86 , 0 , 0 , 0 , 0 ), // #447 {r32, xmm|ymm} - ROW(2, 1, 1, 0, 148, 150, 0 , 0 , 0 , 0 ), // #448 {xmm|ymm|zmm, xmm|m8|mem|r32|r8lo|r8hi|r16} - ROW(2, 1, 1, 0, 148, 151, 0 , 0 , 0 , 0 ), // #449 {xmm|ymm|zmm, xmm|m32|mem|r32} - ROW(2, 1, 1, 0, 148, 84 , 0 , 0 , 0 , 0 ), // #450 {xmm|ymm|zmm, k} - ROW(2, 1, 1, 0, 148, 152, 0 , 0 , 0 , 0 ), // #451 {xmm|ymm|zmm, xmm|m16|mem|r32|r16} - ROW(3, 1, 1, 0, 113, 45 , 10 , 0 , 0 , 0 ), // #452 {r32|m16|mem|r16, xmm, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 109, 10 , 0 , 0 ), // #453 {xmm, xmm, r32|m8|mem|r8lo|r8hi|r16, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 28 , 10 , 0 , 0 ), // #454 {xmm, xmm, r32|m32|mem, i8|u8} - ROW(4, 0, 1, 0, 45 , 45 , 15 , 10 , 0 , 0 ), // #455 {xmm, xmm, r64|m64|mem, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 113, 10 , 0 , 0 ), // #456 {xmm, xmm, r32|m16|mem|r16, i8|u8} - ROW(2, 1, 1, 0, 84 , 148, 0 , 0 , 0 , 0 ), // #457 {k, xmm|ymm|zmm} - ROW(1, 1, 1, 0, 102, 0 , 0 , 0 , 0 , 0 ), // #458 {rel16|rel32} - ROW(3, 1, 1, 2, 91 , 35 , 36 , 0 , 0 , 0 ), // #459 {mem, <edx>, <eax>} - ROW(3, 0, 1, 2, 91 , 35 , 36 , 0 , 0 , 0 ) // #460 {mem, <edx>, <eax>} + ROW(1, 1, 0, 1, 33 , 0 , 0 , 0 , 0 , 0 ), // #341 {<ax>} + ROW(2, 1, 0, 1, 33 , 10 , 0 , 0 , 0 , 0 ), // #342 {<ax>, i8|u8} + ROW(2, 1, 0, 0, 27 , 4 , 0 , 0 , 0 , 0 ), // #343 {r16|m16|mem, r16} + ROW(3, 1, 1, 1, 45 , 46 , 122, 0 , 0 , 0 ), // #344 {xmm, xmm|m128|mem, <xmm0>} + ROW(2, 1, 1, 0, 89 , 123, 0 , 0 , 0 , 0 ), // #345 {bnd, mib} + ROW(2, 1, 1, 0, 89 , 91 , 0 , 0 , 0 , 0 ), // #346 {bnd, mem} + ROW(2, 1, 1, 0, 123, 89 , 0 , 0 , 0 , 0 ), // #347 {mib, bnd} + ROW(1, 1, 1, 0, 124, 0 , 0 , 0 , 0 , 0 ), // #348 {r16|r32|r64} + ROW(1, 1, 1, 1, 33 , 0 , 0 , 0 , 0 , 0 ), // #349 {<ax>} + ROW(2, 1, 1, 2, 35 , 36 , 0 , 0 , 0 , 0 ), // #350 {<edx>, <eax>} + ROW(1, 1, 1, 0, 91 , 0 , 0 , 0 , 0 , 0 ), // #351 {mem} + ROW(1, 1, 1, 1, 125, 0 , 0 , 0 , 0 , 0 ), // #352 {<ds:[memBase|zax]>} + ROW(2, 1, 1, 2, 126, 127, 0 , 0 , 0 , 0 ), // #353 {<ds:[memBase|zsi]>, <es:[memBase|zdi]>} + ROW(3, 1, 1, 0, 45 , 60 , 10 , 0 , 0 , 0 ), // #354 {xmm, xmm|m64|mem, i8|u8} + ROW(3, 1, 1, 0, 45 , 87 , 10 , 0 , 0 , 0 ), // #355 {xmm, xmm|m32|mem, i8|u8} + ROW(5, 0, 1, 4, 47 , 37 , 38 , 128, 129, 0 ), // #356 {m128|mem, <rdx>, <rax>, <rcx>, <rbx>} + ROW(5, 1, 1, 4, 30 , 35 , 36 , 99 , 130, 0 ), // #357 {m64|mem, <edx>, <eax>, <ecx>, <ebx>} + ROW(4, 1, 1, 4, 36 , 130, 99 , 35 , 0 , 0 ), // #358 {<eax>, <ebx>, <ecx>, <edx>} + ROW(2, 0, 1, 2, 37 , 38 , 0 , 0 , 0 , 0 ), // #359 {<rdx>, <rax>} + ROW(2, 1, 1, 0, 57 , 46 , 0 , 0 , 0 , 0 ), // #360 {mm, xmm|m128|mem} + ROW(2, 1, 1, 0, 45 , 117, 0 , 0 , 0 , 0 ), // #361 {xmm, mm|m64|mem} + ROW(2, 1, 1, 0, 57 , 60 , 0 , 0 , 0 , 0 ), // #362 {mm, xmm|m64|mem} + ROW(2, 1, 1, 0, 114, 60 , 0 , 0 , 0 , 0 ), // #363 {r32|r64, xmm|m64|mem} + ROW(2, 1, 1, 0, 45 , 131, 0 , 0 , 0 , 0 ), // #364 {xmm, r32|m32|mem|r64|m64} + ROW(2, 1, 1, 0, 114, 87 , 0 , 0 , 0 , 0 ), // #365 {r32|r64, xmm|m32|mem} + ROW(2, 1, 1, 2, 34 , 33 , 0 , 0 , 0 , 0 ), // #366 {<dx>, <ax>} + ROW(1, 1, 1, 1, 36 , 0 , 0 , 0 , 0 , 0 ), // #367 {<eax>} + ROW(2, 1, 1, 0, 12 , 10 , 0 , 0 , 0 , 0 ), // #368 {i16|u16, i8|u8} + ROW(3, 1, 1, 0, 28 , 45 , 10 , 0 , 0 , 0 ), // #369 {r32|m32|mem, xmm, i8|u8} + ROW(1, 1, 1, 0, 80 , 0 , 0 , 0 , 0 , 0 ), // #370 {m80|mem} + ROW(1, 1, 1, 0, 132, 0 , 0 , 0 , 0 , 0 ), // #371 {m16|m32} + ROW(1, 1, 1, 0, 133, 0 , 0 , 0 , 0 , 0 ), // #372 {m16|m32|m64} + ROW(1, 1, 1, 0, 134, 0 , 0 , 0 , 0 , 0 ), // #373 {m32|m64|m80|st} + ROW(1, 1, 1, 0, 21 , 0 , 0 , 0 , 0 , 0 ), // #374 {m16|mem} + ROW(1, 1, 1, 0, 135, 0 , 0 , 0 , 0 , 0 ), // #375 {ax|m16|mem} + ROW(1, 0, 1, 0, 91 , 0 , 0 , 0 , 0 , 0 ), // #376 {mem} + ROW(2, 1, 1, 0, 136, 137, 0 , 0 , 0 , 0 ), // #377 {al|ax|eax, i8|u8|dx} + ROW(2, 1, 1, 0, 138, 139, 0 , 0 , 0 , 0 ), // #378 {es:[memBase|zdi], dx} + ROW(1, 1, 1, 0, 10 , 0 , 0 , 0 , 0 , 0 ), // #379 {i8|u8} + ROW(0, 1, 0, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #380 {} + ROW(0, 0, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #381 {} + ROW(3, 1, 1, 0, 84 , 84 , 84 , 0 , 0 , 0 ), // #382 {k, k, k} + ROW(2, 1, 1, 0, 84 , 84 , 0 , 0 , 0 , 0 ), // #383 {k, k} + ROW(3, 1, 1, 0, 84 , 84 , 10 , 0 , 0 , 0 ), // #384 {k, k, i8|u8} + ROW(1, 1, 1, 1, 140, 0 , 0 , 0 , 0 , 0 ), // #385 {<ah>} + ROW(1, 1, 1, 0, 29 , 0 , 0 , 0 , 0 , 0 ), // #386 {m32|mem} + ROW(2, 1, 1, 0, 124, 141, 0 , 0 , 0 , 0 ), // #387 {r16|r32|r64, mem|m8|m16|m32|m48|m64|m80|m128|m256|m512|m1024} + ROW(1, 1, 1, 0, 27 , 0 , 0 , 0 , 0 , 0 ), // #388 {r16|m16|mem} + ROW(1, 1, 1, 0, 114, 0 , 0 , 0 , 0 , 0 ), // #389 {r32|r64} + ROW(2, 1, 1, 2, 142, 126, 0 , 0 , 0 , 0 ), // #390 {<al|ax|eax|rax>, <ds:[memBase|zsi]>} + ROW(3, 1, 1, 0, 114, 28 , 14 , 0 , 0 , 0 ), // #391 {r32|r64, r32|m32|mem, i32|u32} + ROW(3, 1, 1, 1, 45 , 45 , 143, 0 , 0 , 0 ), // #392 {xmm, xmm, <ds:[memBase|zdi]>} + ROW(3, 1, 1, 1, 57 , 57 , 143, 0 , 0 , 0 ), // #393 {mm, mm, <ds:[memBase|zdi]>} + ROW(3, 1, 1, 3, 125, 99 , 35 , 0 , 0 , 0 ), // #394 {<ds:[memBase|zax]>, <ecx>, <edx>} + ROW(2, 1, 1, 0, 97 , 53 , 0 , 0 , 0 , 0 ), // #395 {es:[memBase], m512|mem} + ROW(2, 1, 1, 0, 57 , 45 , 0 , 0 , 0 , 0 ), // #396 {mm, xmm} + ROW(2, 1, 1, 0, 6 , 45 , 0 , 0 , 0 , 0 ), // #397 {r32, xmm} + ROW(2, 1, 1, 0, 30 , 57 , 0 , 0 , 0 , 0 ), // #398 {m64|mem, mm} + ROW(2, 1, 1, 0, 45 , 57 , 0 , 0 , 0 , 0 ), // #399 {xmm, mm} + ROW(2, 1, 1, 2, 127, 126, 0 , 0 , 0 , 0 ), // #400 {<es:[memBase|zdi]>, <ds:[memBase|zsi]>} + ROW(2, 1, 1, 2, 36 , 99 , 0 , 0 , 0 , 0 ), // #401 {<eax>, <ecx>} + ROW(3, 1, 1, 3, 36 , 99 , 130, 0 , 0 , 0 ), // #402 {<eax>, <ecx>, <ebx>} + ROW(2, 1, 1, 0, 144, 136, 0 , 0 , 0 , 0 ), // #403 {u8|dx, al|ax|eax} + ROW(2, 1, 1, 0, 139, 145, 0 , 0 , 0 , 0 ), // #404 {dx, ds:[memBase|zsi]} + ROW(6, 1, 1, 3, 45 , 46 , 10 , 99 , 36 , 35 ), // #405 {xmm, xmm|m128|mem, i8|u8, <ecx>, <eax>, <edx>} + ROW(6, 1, 1, 3, 45 , 46 , 10 , 122, 36 , 35 ), // #406 {xmm, xmm|m128|mem, i8|u8, <xmm0>, <eax>, <edx>} + ROW(4, 1, 1, 1, 45 , 46 , 10 , 99 , 0 , 0 ), // #407 {xmm, xmm|m128|mem, i8|u8, <ecx>} + ROW(4, 1, 1, 1, 45 , 46 , 10 , 122, 0 , 0 ), // #408 {xmm, xmm|m128|mem, i8|u8, <xmm0>} + ROW(3, 1, 1, 0, 109, 45 , 10 , 0 , 0 , 0 ), // #409 {r32|m8|mem|r8lo|r8hi|r16, xmm, i8|u8} + ROW(3, 0, 1, 0, 15 , 45 , 10 , 0 , 0 , 0 ), // #410 {r64|m64|mem, xmm, i8|u8} + ROW(3, 1, 1, 0, 45 , 109, 10 , 0 , 0 , 0 ), // #411 {xmm, r32|m8|mem|r8lo|r8hi|r16, i8|u8} + ROW(3, 1, 1, 0, 45 , 28 , 10 , 0 , 0 , 0 ), // #412 {xmm, r32|m32|mem, i8|u8} + ROW(3, 0, 1, 0, 45 , 15 , 10 , 0 , 0 , 0 ), // #413 {xmm, r64|m64|mem, i8|u8} + ROW(3, 1, 1, 0, 59 , 113, 10 , 0 , 0 , 0 ), // #414 {mm|xmm, r32|m16|mem|r16, i8|u8} + ROW(2, 1, 1, 0, 6 , 59 , 0 , 0 , 0 , 0 ), // #415 {r32, mm|xmm} + ROW(2, 1, 1, 0, 45 , 10 , 0 , 0 , 0 , 0 ), // #416 {xmm, i8|u8} + ROW(2, 1, 1, 0, 31 , 81 , 0 , 0 , 0 , 0 ), // #417 {r8lo|r8hi|m8|r16|m16|r32|m32|r64|m64|mem, cl|i8|u8} + ROW(1, 0, 1, 0, 114, 0 , 0 , 0 , 0 , 0 ), // #418 {r32|r64} + ROW(3, 1, 1, 3, 35 , 36 , 99 , 0 , 0 , 0 ), // #419 {<edx>, <eax>, <ecx>} + ROW(2, 1, 1, 2, 142, 127, 0 , 0 , 0 , 0 ), // #420 {<al|ax|eax|rax>, <es:[memBase|zdi]>} + ROW(1, 1, 1, 0, 1 , 0 , 0 , 0 , 0 , 0 ), // #421 {r8lo|r8hi|m8|mem} + ROW(1, 1, 1, 0, 146, 0 , 0 , 0 , 0 , 0 ), // #422 {r16|m16|mem|r32|r64} + ROW(2, 1, 1, 2, 127, 142, 0 , 0 , 0 , 0 ), // #423 {<es:[memBase|zdi]>, <al|ax|eax|rax>} + ROW(6, 1, 1, 0, 51 , 51 , 51 , 51 , 51 , 47 ), // #424 {zmm, zmm, zmm, zmm, zmm, m128|mem} + ROW(6, 1, 1, 0, 45 , 45 , 45 , 45 , 45 , 47 ), // #425 {xmm, xmm, xmm, xmm, xmm, m128|mem} + ROW(3, 1, 1, 0, 45 , 45 , 60 , 0 , 0 , 0 ), // #426 {xmm, xmm, xmm|m64|mem} + ROW(3, 1, 1, 0, 45 , 45 , 87 , 0 , 0 , 0 ), // #427 {xmm, xmm, xmm|m32|mem} + ROW(2, 1, 1, 0, 48 , 47 , 0 , 0 , 0 , 0 ), // #428 {ymm, m128|mem} + ROW(2, 1, 1, 0, 147, 60 , 0 , 0 , 0 , 0 ), // #429 {ymm|zmm, xmm|m64|mem} + ROW(2, 1, 1, 0, 147, 47 , 0 , 0 , 0 , 0 ), // #430 {ymm|zmm, m128|mem} + ROW(2, 1, 1, 0, 51 , 50 , 0 , 0 , 0 , 0 ), // #431 {zmm, m256|mem} + ROW(2, 1, 1, 0, 148, 60 , 0 , 0 , 0 , 0 ), // #432 {xmm|ymm|zmm, xmm|m64|mem} + ROW(2, 1, 1, 0, 148, 87 , 0 , 0 , 0 , 0 ), // #433 {xmm|ymm|zmm, m32|mem|xmm} + ROW(4, 1, 1, 0, 82 , 45 , 60 , 10 , 0 , 0 ), // #434 {xmm|k, xmm, xmm|m64|mem, i8|u8} + ROW(4, 1, 1, 0, 82 , 45 , 87 , 10 , 0 , 0 ), // #435 {xmm|k, xmm, xmm|m32|mem, i8|u8} + ROW(3, 1, 1, 0, 45 , 45 , 131, 0 , 0 , 0 ), // #436 {xmm, xmm, r32|m32|mem|r64|m64} + ROW(3, 1, 1, 0, 46 , 147, 10 , 0 , 0 , 0 ), // #437 {xmm|m128|mem, ymm|zmm, i8|u8} + ROW(4, 1, 1, 0, 45 , 45 , 60 , 10 , 0 , 0 ), // #438 {xmm, xmm, xmm|m64|mem, i8|u8} + ROW(4, 1, 1, 0, 45 , 45 , 87 , 10 , 0 , 0 ), // #439 {xmm, xmm, xmm|m32|mem, i8|u8} + ROW(3, 1, 1, 0, 84 , 149, 10 , 0 , 0 , 0 ), // #440 {k, xmm|m128|ymm|m256|zmm|m512, i8|u8} + ROW(3, 1, 1, 0, 84 , 60 , 10 , 0 , 0 , 0 ), // #441 {k, xmm|m64|mem, i8|u8} + ROW(3, 1, 1, 0, 84 , 87 , 10 , 0 , 0 , 0 ), // #442 {k, xmm|m32|mem, i8|u8} + ROW(1, 1, 1, 0, 62 , 0 , 0 , 0 , 0 , 0 ), // #443 {vm32y} + ROW(1, 1, 1, 0, 63 , 0 , 0 , 0 , 0 , 0 ), // #444 {vm32z} + ROW(1, 1, 1, 0, 66 , 0 , 0 , 0 , 0 , 0 ), // #445 {vm64z} + ROW(4, 1, 1, 0, 51 , 51 , 49 , 10 , 0 , 0 ), // #446 {zmm, zmm, ymm|m256|mem, i8|u8} + ROW(1, 1, 1, 0, 30 , 0 , 0 , 0 , 0 , 0 ), // #447 {m64|mem} + ROW(2, 1, 1, 0, 6 , 86 , 0 , 0 , 0 , 0 ), // #448 {r32, xmm|ymm} + ROW(2, 1, 1, 0, 148, 150, 0 , 0 , 0 , 0 ), // #449 {xmm|ymm|zmm, xmm|m8|mem|r32|r8lo|r8hi|r16} + ROW(2, 1, 1, 0, 148, 151, 0 , 0 , 0 , 0 ), // #450 {xmm|ymm|zmm, xmm|m32|mem|r32} + ROW(2, 1, 1, 0, 148, 84 , 0 , 0 , 0 , 0 ), // #451 {xmm|ymm|zmm, k} + ROW(2, 1, 1, 0, 148, 152, 0 , 0 , 0 , 0 ), // #452 {xmm|ymm|zmm, xmm|m16|mem|r32|r16} + ROW(3, 1, 1, 0, 113, 45 , 10 , 0 , 0 , 0 ), // #453 {r32|m16|mem|r16, xmm, i8|u8} + ROW(4, 1, 1, 0, 45 , 45 , 109, 10 , 0 , 0 ), // #454 {xmm, xmm, r32|m8|mem|r8lo|r8hi|r16, i8|u8} + ROW(4, 1, 1, 0, 45 , 45 , 28 , 10 , 0 , 0 ), // #455 {xmm, xmm, r32|m32|mem, i8|u8} + ROW(4, 0, 1, 0, 45 , 45 , 15 , 10 , 0 , 0 ), // #456 {xmm, xmm, r64|m64|mem, i8|u8} + ROW(4, 1, 1, 0, 45 , 45 , 113, 10 , 0 , 0 ), // #457 {xmm, xmm, r32|m16|mem|r16, i8|u8} + ROW(2, 1, 1, 0, 84 , 148, 0 , 0 , 0 , 0 ), // #458 {k, xmm|ymm|zmm} + ROW(1, 1, 1, 0, 102, 0 , 0 , 0 , 0 , 0 ), // #459 {rel16|rel32} + ROW(3, 1, 1, 2, 91 , 35 , 36 , 0 , 0 , 0 ), // #460 {mem, <edx>, <eax>} + ROW(3, 0, 1, 2, 91 , 35 , 36 , 0 , 0 , 0 ) // #461 {mem, <edx>, <eax>} }; #undef ROW @@ -3451,104 +3452,104 @@ const uint8_t InstDB::rwInfoIndex[Inst::_kIdCount * 2] = { 0, 81, 0, 36, 0, 112, 0, 111, 0, 86, 0, 110, 0, 110, 0, 113, 0, 114, 0, 114, 0, 115, 0, 116, 0, 116, 0, 117, 0, 117, 0, 97, 0, 97, 0, 111, 0, 97, 0, 97, 0, 116, 0, 116, 0, 118, 0, 82, 0, 86, 0, 119, 0, 82, 0, 7, 0, 7, 0, 81, 0, 120, - 0, 121, 0, 110, 0, 110, 0, 120, 0, 0, 4, 49, 122, 4, 0, 4, 0, 5, 0, 6, 0, 0, - 123, 124, 0, 0, 125, 0, 48, 0, 126, 0, 48, 2, 0, 4, 0, 4, 0, 127, 0, 128, 0, 11, + 0, 11, 0, 110, 0, 110, 0, 120, 0, 0, 4, 49, 121, 4, 0, 4, 0, 5, 0, 6, 0, 0, 122, + 123, 0, 0, 124, 0, 48, 0, 125, 0, 48, 2, 0, 4, 0, 4, 0, 126, 0, 127, 0, 11, 0, 11, 0, 11, 0, 3, 0, 3, 0, 4, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, - 3, 0, 3, 0, 0, 3, 3, 0, 3, 0, 0, 0, 3, 0, 129, 0, 3, 0, 0, 12, 0, 4, 0, 4, 3, - 0, 3, 0, 4, 0, 3, 0, 0, 130, 0, 131, 3, 0, 3, 0, 4, 0, 3, 0, 0, 132, 0, 133, - 0, 0, 0, 8, 0, 8, 0, 134, 0, 52, 0, 135, 0, 136, 39, 0, 39, 0, 129, 0, 129, 0, - 129, 0, 129, 0, 129, 0, 129, 0, 129, 0, 129, 0, 129, 0, 129, 0, 39, 0, 129, - 0, 129, 0, 129, 0, 39, 0, 39, 0, 129, 0, 129, 0, 129, 0, 3, 0, 3, 0, 3, 0, 137, - 0, 3, 0, 3, 0, 3, 0, 39, 0, 39, 0, 0, 138, 0, 72, 0, 139, 0, 140, 3, 0, 3, 0, - 4, 0, 4, 0, 3, 0, 3, 0, 4, 0, 4, 0, 4, 0, 4, 0, 3, 0, 3, 0, 4, 0, 4, 0, 141, - 0, 142, 0, 143, 0, 36, 0, 36, 0, 36, 0, 142, 0, 142, 0, 143, 0, 36, 0, 36, 0, - 36, 0, 142, 0, 4, 0, 3, 0, 129, 0, 3, 0, 3, 0, 4, 0, 3, 0, 3, 0, 0, 144, 0, 0, + 3, 0, 3, 0, 0, 3, 3, 0, 3, 0, 0, 0, 3, 0, 128, 0, 3, 0, 0, 12, 0, 4, 0, 4, 3, + 0, 3, 0, 4, 0, 3, 0, 0, 129, 0, 130, 3, 0, 3, 0, 4, 0, 3, 0, 0, 131, 0, 132, + 0, 0, 0, 8, 0, 8, 0, 133, 0, 52, 0, 134, 0, 135, 39, 0, 39, 0, 128, 0, 128, 0, + 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 39, 0, 128, 0, + 128, 0, 128, 0, 39, 0, 39, 0, 128, 0, 128, 0, 128, 0, 3, 0, 3, 0, 3, 0, 136, + 0, 3, 0, 3, 0, 3, 0, 39, 0, 39, 0, 0, 137, 0, 72, 0, 138, 0, 139, 3, 0, 3, 0, + 4, 0, 4, 0, 3, 0, 3, 0, 4, 0, 4, 0, 4, 0, 4, 0, 3, 0, 3, 0, 4, 0, 4, 0, 140, + 0, 141, 0, 142, 0, 36, 0, 36, 0, 36, 0, 141, 0, 141, 0, 142, 0, 36, 0, 36, 0, + 36, 0, 141, 0, 4, 0, 3, 0, 128, 0, 3, 0, 3, 0, 4, 0, 3, 0, 3, 0, 0, 143, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, - 0, 24, 3, 0, 3, 0, 0, 7, 0, 7, 0, 7, 0, 39, 3, 0, 3, 0, 3, 0, 3, 0, 54, 0, - 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 54, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, - 3, 0, 3, 0, 3, 0, 39, 0, 145, 0, 3, 0, 3, 0, 4, 0, 3, 0, 3, 0, 3, 0, 4, 0, 3, - 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 147, 0, 7, 0, 148, 0, 147, 0, - 0, 149, 0, 149, 0, 150, 0, 149, 0, 150, 0, 149, 0, 149, 151, 0, 0, 152, 0, 0, - 147, 0, 147, 0, 0, 11, 0, 7, 0, 7, 0, 38, 0, 148, 0, 0, 7, 0, 148, 0, 0, 153, - 147, 0, 147, 0, 0, 10, 2, 0, 154, 0, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, - 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, - 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, - 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 0, 0, 64, 4, 0, 4, 0, 4, 0, 0, 4, - 4, 0, 4, 0, 0, 12, 147, 0, 0, 156, 0, 10, 147, 0, 0, 156, 0, 10, 0, 4, 0, 4, - 0, 64, 0, 47, 0, 157, 0, 149, 0, 157, 7, 0, 7, 0, 38, 0, 148, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 158, 159, 0, 0, 157, 2, 0, 4, 0, 4, 0, 5, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 19, 0, 11, 0, 11, 0, 31, 0, 32, 0, - 0, 0, 4, 0, 4, 0, 4, 0, 4, 0, 0, 160, 0, 161, 0, 160, 0, 161, 0, 8, 0, 8, 0, 162, - 0, 163, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 7, 0, 0, 7, 0, 8, 0, 8, 0, 8, - 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 164, 0, 164, - 165, 0, 40, 0, 166, 0, 167, 0, 166, 0, 167, 0, 165, 0, 40, 0, 166, 0, 167, - 0, 166, 0, 167, 0, 168, 0, 169, 0, 0, 8, 0, 8, 0, 170, 0, 171, 31, 0, 32, 0, - 172, 0, 172, 0, 173, 0, 11, 0, 0, 8, 120, 0, 174, 0, 174, 0, 11, 0, 174, 0, 11, - 0, 173, 0, 11, 0, 173, 0, 0, 175, 173, 0, 11, 0, 173, 0, 11, 0, 174, 0, 40, - 0, 0, 176, 40, 0, 0, 177, 0, 178, 0, 179, 45, 0, 45, 0, 174, 0, 11, 0, 174, 0, - 11, 0, 11, 0, 173, 0, 11, 0, 173, 0, 40, 0, 40, 0, 45, 0, 45, 0, 173, 0, 11, - 0, 11, 0, 174, 0, 0, 177, 0, 178, 0, 8, 0, 8, 0, 8, 0, 162, 0, 163, 0, 8, 0, 180, - 0, 8, 0, 101, 0, 101, 181, 0, 181, 0, 11, 0, 11, 0, 0, 182, 0, 183, 0, 184, - 0, 183, 0, 184, 0, 182, 0, 183, 0, 184, 0, 183, 0, 184, 0, 52, 0, 185, 0, 185, - 0, 186, 0, 187, 0, 185, 0, 185, 0, 188, 0, 189, 0, 185, 0, 185, 0, 188, 0, - 189, 0, 185, 0, 185, 0, 188, 0, 189, 0, 190, 0, 190, 0, 191, 0, 192, 0, 185, 0, - 185, 0, 185, 0, 185, 0, 185, 0, 185, 0, 190, 0, 190, 0, 185, 0, 185, 0, 188, - 0, 189, 0, 185, 0, 185, 0, 188, 0, 189, 0, 185, 0, 185, 0, 188, 0, 189, 0, 185, - 0, 185, 0, 185, 0, 185, 0, 185, 0, 185, 0, 190, 0, 190, 0, 190, 0, 190, 0, - 191, 0, 192, 0, 185, 0, 185, 0, 188, 0, 189, 0, 185, 0, 185, 0, 188, 0, 189, 0, - 185, 0, 185, 0, 188, 0, 189, 0, 190, 0, 190, 0, 191, 0, 192, 0, 185, 0, 185, - 0, 188, 0, 189, 0, 185, 0, 185, 0, 188, 0, 189, 0, 185, 0, 185, 0, 193, 0, 194, - 0, 190, 0, 190, 0, 191, 0, 192, 0, 195, 0, 195, 0, 39, 0, 121, 11, 0, 11, 0, + 0, 24, 3, 0, 3, 0, 0, 7, 0, 7, 0, 7, 0, 39, 3, 0, 3, 0, 3, 0, 3, 0, 54, 0, 3, + 0, 3, 0, 3, 0, 3, 0, 3, 0, 54, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 39, 0, 144, 0, 3, 0, 3, 0, 4, 0, 3, 0, 3, 0, 3, 0, 4, 0, 3, + 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 146, 0, 7, 0, 147, 0, 146, 0, 0, + 148, 0, 148, 0, 149, 0, 148, 0, 149, 0, 148, 0, 148, 150, 0, 0, 151, 0, 0, 146, + 0, 146, 0, 0, 11, 0, 7, 0, 7, 0, 38, 0, 147, 0, 0, 7, 0, 147, 0, 0, 152, 146, + 0, 146, 0, 0, 10, 2, 0, 153, 0, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, + 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, + 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, + 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 0, 0, 64, 4, 0, 4, 0, 4, 0, 0, 4, + 4, 0, 4, 0, 0, 12, 146, 0, 0, 155, 0, 10, 146, 0, 0, 155, 0, 10, 0, 4, 0, 4, + 0, 64, 0, 47, 0, 156, 0, 148, 0, 156, 7, 0, 7, 0, 38, 0, 147, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 157, 158, 0, 0, 156, 2, 0, 4, 0, 4, 0, 5, 0, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 19, 0, 11, 0, 11, 0, 31, 0, 32, 0, 0, + 0, 4, 0, 4, 0, 4, 0, 4, 0, 0, 159, 0, 160, 0, 159, 0, 160, 0, 8, 0, 8, 0, 161, + 0, 162, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 7, 0, 0, 7, 0, 8, 0, 8, 0, 8, 0, + 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 163, 0, 163, + 164, 0, 40, 0, 165, 0, 166, 0, 165, 0, 166, 0, 164, 0, 40, 0, 165, 0, 166, + 0, 165, 0, 166, 0, 167, 0, 168, 0, 0, 8, 0, 8, 0, 169, 0, 170, 31, 0, 32, 0, 171, + 0, 171, 0, 172, 0, 11, 0, 0, 8, 120, 0, 173, 0, 173, 0, 11, 0, 173, 0, 11, + 0, 172, 0, 11, 0, 172, 0, 0, 174, 172, 0, 11, 0, 172, 0, 11, 0, 173, 0, 40, 0, + 0, 175, 40, 0, 0, 176, 0, 177, 0, 178, 45, 0, 45, 0, 173, 0, 11, 0, 173, 0, + 11, 0, 11, 0, 172, 0, 11, 0, 172, 0, 40, 0, 40, 0, 45, 0, 45, 0, 172, 0, 11, 0, + 11, 0, 173, 0, 0, 176, 0, 177, 0, 8, 0, 8, 0, 8, 0, 161, 0, 162, 0, 8, 0, 179, + 0, 8, 0, 101, 0, 101, 180, 0, 180, 0, 11, 0, 11, 0, 0, 181, 0, 182, 0, 183, + 0, 182, 0, 183, 0, 181, 0, 182, 0, 183, 0, 182, 0, 183, 0, 52, 0, 184, 0, 184, + 0, 185, 0, 186, 0, 184, 0, 184, 0, 187, 0, 188, 0, 184, 0, 184, 0, 187, 0, 188, + 0, 184, 0, 184, 0, 187, 0, 188, 0, 189, 0, 189, 0, 190, 0, 191, 0, 184, 0, + 184, 0, 184, 0, 184, 0, 184, 0, 184, 0, 189, 0, 189, 0, 184, 0, 184, 0, 187, + 0, 188, 0, 184, 0, 184, 0, 187, 0, 188, 0, 184, 0, 184, 0, 187, 0, 188, 0, 184, + 0, 184, 0, 184, 0, 184, 0, 184, 0, 184, 0, 189, 0, 189, 0, 189, 0, 189, 0, 190, + 0, 191, 0, 184, 0, 184, 0, 187, 0, 188, 0, 184, 0, 184, 0, 187, 0, 188, 0, + 184, 0, 184, 0, 187, 0, 188, 0, 189, 0, 189, 0, 190, 0, 191, 0, 184, 0, 184, + 0, 187, 0, 188, 0, 184, 0, 184, 0, 187, 0, 188, 0, 184, 0, 184, 0, 192, 0, 193, + 0, 189, 0, 189, 0, 190, 0, 191, 0, 194, 0, 194, 0, 39, 0, 195, 11, 0, 11, 0, 39, 0, 196, 0, 99, 197, 99, 198, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, - 24, 0, 24, 99, 198, 99, 199, 11, 0, 11, 0, 0, 200, 0, 201, 0, 11, 0, 11, 0, - 200, 0, 201, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 202, 0, 203, 0, 204, - 0, 203, 0, 204, 0, 202, 0, 203, 0, 204, 0, 203, 0, 204, 0, 163, 111, 0, 0, 98, - 0, 106, 0, 205, 0, 205, 0, 8, 0, 8, 0, 162, 0, 163, 0, 0, 0, 206, 0, 0, 0, 8, - 0, 8, 0, 162, 0, 163, 0, 0, 0, 207, 0, 0, 208, 0, 208, 0, 81, 0, 209, 0, 208, + 24, 0, 24, 99, 198, 99, 199, 11, 0, 11, 0, 0, 200, 0, 201, 0, 11, 0, 11, 0, 200, + 0, 201, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 202, 0, 203, 0, 204, + 0, 203, 0, 204, 0, 202, 0, 203, 0, 204, 0, 203, 0, 204, 0, 162, 111, 0, 0, 98, + 0, 106, 0, 205, 0, 205, 0, 8, 0, 8, 0, 161, 0, 162, 0, 0, 0, 206, 0, 0, 0, 8, + 0, 8, 0, 161, 0, 162, 0, 0, 0, 207, 0, 0, 208, 0, 208, 0, 81, 0, 209, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 0, 210, 211, 212, 211, 212, 0, 213, 116, 214, 116, 214, 215, 0, 216, 0, 111, 0, 111, 0, 111, 0, 111, 0, 217, 0, 116, 218, 11, 0, 11, 0, 118, 219, 208, 0, 208, 0, 0, 8, 0, 220, - 0, 206, 172, 0, 0, 0, 0, 221, 0, 207, 0, 8, 0, 8, 0, 162, 0, 163, 222, 0, 0, - 220, 0, 8, 0, 8, 0, 223, 0, 223, 11, 0, 11, 0, 11, 0, 11, 0, 0, 8, 0, 8, 0, - 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, - 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 164, 0, 8, 224, 0, 45, 0, 225, 0, 225, - 0, 40, 0, 226, 0, 0, 8, 0, 190, 0, 227, 0, 227, 0, 8, 0, 8, 0, 8, 0, 8, 0, - 130, 0, 131, 0, 8, 0, 8, 0, 8, 0, 8, 0, 132, 0, 133, 0, 227, 0, 227, 0, 227, 0, - 227, 0, 227, 0, 227, 0, 180, 0, 180, 172, 0, 172, 0, 172, 0, 172, 0, 0, 180, - 0, 180, 0, 180, 0, 180, 0, 180, 0, 180, 11, 0, 11, 0, 0, 185, 0, 185, 0, 185, - 0, 185, 0, 228, 0, 228, 0, 8, 0, 8, 0, 8, 0, 185, 0, 8, 0, 8, 0, 185, 0, 185, - 0, 190, 0, 190, 0, 229, 0, 229, 0, 229, 0, 8, 0, 229, 0, 8, 0, 185, 0, 185, 0, - 185, 0, 185, 0, 185, 0, 8, 11, 0, 11, 0, 11, 0, 11, 0, 0, 134, 0, 52, 0, 135, + 0, 206, 171, 0, 0, 0, 0, 221, 0, 207, 0, 8, 0, 8, 0, 161, 0, 162, 222, 0, 0, + 220, 0, 8, 0, 8, 0, 223, 0, 223, 11, 0, 11, 0, 11, 0, 11, 0, 0, 8, 0, 8, 0, 8, + 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, + 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 163, 0, 8, 224, 0, 45, 0, 225, 0, 225, + 0, 40, 0, 226, 0, 0, 8, 0, 189, 0, 227, 0, 227, 0, 8, 0, 8, 0, 8, 0, 8, 0, 129, + 0, 130, 0, 8, 0, 8, 0, 8, 0, 8, 0, 131, 0, 132, 0, 227, 0, 227, 0, 227, 0, + 227, 0, 227, 0, 227, 0, 179, 0, 179, 171, 0, 171, 0, 171, 0, 171, 0, 0, 179, + 0, 179, 0, 179, 0, 179, 0, 179, 0, 179, 11, 0, 11, 0, 0, 184, 0, 184, 0, 184, + 0, 184, 0, 228, 0, 228, 0, 8, 0, 8, 0, 8, 0, 184, 0, 8, 0, 8, 0, 184, 0, 184, + 0, 189, 0, 189, 0, 229, 0, 229, 0, 229, 0, 8, 0, 229, 0, 8, 0, 184, 0, 184, 0, + 184, 0, 184, 0, 184, 0, 8, 11, 0, 11, 0, 11, 0, 11, 0, 0, 133, 0, 52, 0, 134, 0, 230, 99, 198, 99, 197, 99, 199, 99, 198, 7, 0, 7, 0, 7, 0, 0, 8, 7, 0, 0, - 8, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 8, 7, 0, 7, 0, 137, 0, 7, 0, 0, 8, - 7, 0, 0, 8, 0, 8, 7, 0, 0, 231, 0, 163, 0, 162, 0, 232, 11, 0, 11, 0, 0, 233, - 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, - 0, 233, 0, 185, 0, 185, 0, 8, 0, 8, 0, 205, 0, 205, 0, 8, 0, 8, 0, 8, 0, 8, - 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 234, 0, - 234, 0, 235, 0, 175, 0, 225, 0, 225, 0, 225, 0, 225, 0, 141, 0, 234, 0, 236, - 0, 175, 0, 235, 0, 235, 0, 175, 0, 236, 0, 175, 0, 235, 0, 175, 0, 237, 0, 238, - 0, 173, 0, 173, 0, 173, 0, 237, 0, 235, 0, 175, 0, 236, 0, 175, 0, 235, 0, - 175, 0, 234, 0, 175, 0, 237, 0, 238, 0, 173, 0, 173, 0, 173, 0, 237, 0, 0, 8, - 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 11, 0, 11, 0, 11, 0, 11, 0, 0, + 8, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 8, 7, 0, 7, 0, 136, 0, 7, 0, 0, 8, 7, + 0, 0, 8, 0, 8, 7, 0, 0, 231, 0, 162, 0, 161, 0, 232, 11, 0, 11, 0, 0, 233, 0, + 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, + 0, 233, 0, 184, 0, 184, 0, 8, 0, 8, 0, 205, 0, 205, 0, 8, 0, 8, 0, 8, 0, 8, 0, + 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 234, 0, + 234, 0, 235, 0, 174, 0, 225, 0, 225, 0, 225, 0, 225, 0, 140, 0, 234, 0, 236, + 0, 174, 0, 235, 0, 235, 0, 174, 0, 236, 0, 174, 0, 235, 0, 174, 0, 237, 0, 238, + 0, 172, 0, 172, 0, 172, 0, 237, 0, 235, 0, 174, 0, 236, 0, 174, 0, 235, 0, 174, + 0, 234, 0, 174, 0, 237, 0, 238, 0, 172, 0, 172, 0, 172, 0, 237, 0, 0, 8, 0, + 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 11, 0, 11, 0, 11, 0, 11, 0, 0, 8, 0, 8, 0, 8, 0, 239, 0, 11, 0, 11, 0, 8, 0, 8, 0, 11, 0, 11, 0, 8, 0, 8, 0, 240, 0, 240, 0, 240, 0, 240, 0, 8, 111, 0, 111, 0, 241, 0, 111, 0, 0, 240, 0, - 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 8, 0, 8, 0, 185, 0, 185, 0, 185, 0, 8, - 0, 240, 0, 240, 0, 8, 0, 8, 0, 185, 0, 185, 0, 185, 0, 8, 0, 8, 0, 227, 0, 11, + 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 8, 0, 8, 0, 184, 0, 184, 0, 184, 0, 8, + 0, 240, 0, 240, 0, 8, 0, 8, 0, 184, 0, 184, 0, 184, 0, 8, 0, 8, 0, 227, 0, 11, 0, 11, 0, 11, 0, 8, 0, 8, 0, 8, 0, 242, 0, 243, 0, 242, 0, 8, 0, 8, 0, 8, 0, 242, 0, 242, 0, 242, 0, 8, 0, 8, 0, 8, 0, 242, 0, 242, 0, 243, 0, 242, 0, 8, - 0, 8, 0, 8, 0, 242, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 185, 0, - 185, 222, 0, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, + 0, 8, 0, 8, 0, 242, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 184, 0, + 184, 222, 0, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, - 0, 200, 0, 201, 11, 0, 11, 0, 0, 200, 0, 201, 181, 0, 181, 0, 0, 200, 0, 201, + 0, 200, 0, 201, 11, 0, 11, 0, 0, 200, 0, 201, 180, 0, 180, 0, 0, 200, 0, 201, 11, 0, 0, 201, 0, 11, 0, 11, 0, 200, 0, 201, 0, 11, 0, 11, 0, 200, 0, 201, 0, - 11, 0, 11, 0, 200, 0, 201, 11, 0, 11, 0, 0, 200, 0, 201, 181, 0, 181, 0, 0, 200, - 0, 201, 11, 0, 0, 201, 0, 8, 0, 8, 0, 162, 0, 163, 111, 0, 111, 0, 0, 24, - 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 111, 0, 241, 0, 0, 8, 0, 8, 0, - 8, 0, 8, 0, 8, 0, 8, 11, 0, 11, 0, 0, 200, 0, 201, 0, 158, 0, 8, 0, 8, 0, 162, - 0, 163, 222, 0, 222, 0, 31, 0, 32, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 102, 0, 102, 0, 244, 0, 0, 245, 0, 0, 0, 246, 0, 0, - 0, 0, 150, 0, 0, 2, 0, 4, 0, 4, 0, 0, 247, 0, 247, 0, 247, 0, 247, 0, 248, 0, - 248, 0, 248, 0, 248, 0, 248, 0, 248, 0, 248, 0, 248, 0, 244, 0, 0 + 11, 0, 11, 0, 200, 0, 201, 11, 0, 11, 0, 0, 200, 0, 201, 180, 0, 180, 0, 0, 200, + 0, 201, 11, 0, 0, 201, 0, 8, 0, 8, 0, 161, 0, 162, 111, 0, 111, 0, 0, 24, 0, + 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 111, 0, 241, 0, 0, 8, 0, 8, 0, + 8, 0, 8, 0, 8, 0, 8, 11, 0, 11, 0, 0, 200, 0, 201, 0, 157, 0, 8, 0, 8, 0, 161, + 0, 162, 222, 0, 222, 0, 31, 0, 32, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 102, 0, 102, 0, 244, 0, 0, 245, 0, 0, 0, 246, 0, 0, 0, + 0, 149, 0, 0, 2, 0, 4, 0, 4, 0, 0, 247, 0, 247, 0, 247, 0, 247, 0, 248, 0, 248, + 0, 248, 0, 248, 0, 248, 0, 248, 0, 248, 0, 248, 0, 244, 0, 0 }; const InstDB::RWInfo InstDB::rwInfo[] = { @@ -3563,7 +3564,7 @@ const InstDB::RWInfo InstDB::rwInfo[] = { { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 3 , 3 , 0 , 0 , 0 } }, // #8 [ref=186x] { InstDB::RWInfo::kCategoryGeneric , 7 , { 12, 13, 0 , 0 , 0 , 0 } }, // #9 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 2 , { 11, 3 , 3 , 0 , 0 , 0 } }, // #10 [ref=5x] - { InstDB::RWInfo::kCategoryGeneric , 2 , { 11, 3 , 0 , 0 , 0 , 0 } }, // #11 [ref=80x] + { InstDB::RWInfo::kCategoryGeneric , 2 , { 11, 3 , 0 , 0 , 0 , 0 } }, // #11 [ref=81x] { InstDB::RWInfo::kCategoryGeneric , 3 , { 4 , 5 , 14, 0 , 0 , 0 } }, // #12 [ref=4x] { InstDB::RWInfo::kCategoryGeneric , 2 , { 5 , 3 , 0 , 0 , 0 , 0 } }, // #13 [ref=3x] { InstDB::RWInfo::kCategoryGeneric , 8 , { 10, 3 , 0 , 0 , 0 , 0 } }, // #14 [ref=2x] @@ -3673,81 +3674,81 @@ const InstDB::RWInfo InstDB::rwInfo[] = { { InstDB::RWInfo::kCategoryGeneric , 28, { 42, 9 , 0 , 0 , 0 , 0 } }, // #118 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 20, 19, 0 , 0 , 0 , 0 } }, // #119 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 14, { 11, 3 , 0 , 0 , 0 , 0 } }, // #120 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 5 , { 34, 9 , 0 , 0 , 0 , 0 } }, // #121 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 6 , { 59, 41, 3 , 0 , 0 , 0 } }, // #122 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 11, 3 , 60, 0 , 0 } }, // #123 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 28, 0 , 0 , 0 , 0 } }, // #124 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 28, 29, 0 , 0 , 0 } }, // #125 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 3 , 0 , 0 , 0 , 0 , 0 } }, // #126 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 50, 21, 0 , 0 , 0 , 0 } }, // #127 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 50, 61, 0 , 0 , 0 , 0 } }, // #128 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 4 , { 25, 7 , 0 , 0 , 0 , 0 } }, // #129 [ref=18x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 62, 16, 56 } }, // #130 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 63, 16, 56 } }, // #131 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 62, 0 , 0 } }, // #132 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 63, 0 , 0 } }, // #133 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 31, { 53, 5 , 0 , 0 , 0 , 0 } }, // #134 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 32, { 34, 5 , 0 , 0 , 0 , 0 } }, // #135 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 33, { 47, 3 , 0 , 0 , 0 , 0 } }, // #136 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 64, 5 , 0 , 0 , 0 , 0 } }, // #137 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 15, { 4 , 39, 0 , 0 , 0 , 0 } }, // #138 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 4 , { 4 , 7 , 0 , 0 , 0 , 0 } }, // #139 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 27, { 2 , 13, 0 , 0 , 0 , 0 } }, // #140 [ref=1x] - { InstDB::RWInfo::kCategoryVmov1_8 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #141 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 5 , { 10, 9 , 0 , 0 , 0 , 0 } }, // #142 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 27, { 10, 13, 0 , 0 , 0 , 0 } }, // #143 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 65, 0 , 0 , 0 , 0 , 0 } }, // #144 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 0 , 0 , 0 } }, // #145 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 60, 0 , 0 , 0 , 0 , 0 } }, // #146 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 2 , 66, 0 , 0 , 0 , 0 } }, // #147 [ref=8x] - { InstDB::RWInfo::kCategoryGeneric , 5 , { 36, 9 , 0 , 0 , 0 , 0 } }, // #148 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 11, 0 , 0 , 0 , 0 , 0 } }, // #149 [ref=6x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 28, 0 , 0 , 0 } }, // #150 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 0 , 0 , 0 , 0 } }, // #151 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 62, 0 , 0 , 0 } }, // #152 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 68, 0 , 0 , 0 , 0 , 0 } }, // #153 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 21, 20, 0 , 0 , 0 , 0 } }, // #154 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 31, { 69, 0 , 0 , 0 , 0 , 0 } }, // #155 [ref=30x] - { InstDB::RWInfo::kCategoryGeneric , 11, { 2 , 3 , 66, 0 , 0 , 0 } }, // #156 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 34, { 11, 0 , 0 , 0 , 0 , 0 } }, // #157 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 28, { 42, 0 , 0 , 0 , 0 , 0 } }, // #158 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 20, 21, 0 , 0 , 0 , 0 } }, // #159 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 12, { 70, 43, 43, 43, 43, 5 } }, // #160 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 12, { 4 , 5 , 5 , 5 , 5 , 5 } }, // #161 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 10, 5 , 7 , 0 , 0 , 0 } }, // #162 [ref=8x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 5 , 9 , 0 , 0 , 0 } }, // #163 [ref=9x] - { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 3 , 3 , 3 , 0 , 0 } }, // #164 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 12, { 71, 5 , 0 , 0 , 0 , 0 } }, // #165 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 12, { 11, 5 , 0 , 0 , 0 , 0 } }, // #166 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 37, { 72, 73, 0 , 0 , 0 , 0 } }, // #167 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 11, 7 , 0 , 0 , 0 , 0 } }, // #168 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 39, { 11, 9 , 0 , 0 , 0 , 0 } }, // #169 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 11, 5 , 7 , 0 , 0 , 0 } }, // #170 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 11, 5 , 9 , 0 , 0 , 0 } }, // #171 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 11, { 11, 3 , 0 , 0 , 0 , 0 } }, // #172 [ref=7x] - { InstDB::RWInfo::kCategoryVmov2_1 , 40, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #173 [ref=14x] - { InstDB::RWInfo::kCategoryVmov1_2 , 14, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #174 [ref=7x] - { InstDB::RWInfo::kCategoryVmov1_2 , 41, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #175 [ref=10x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 10, 74, 7 , 0 , 0 , 0 } }, // #176 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 57, 3 , 0 , 0 , 0 } }, // #177 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 74, 3 , 0 , 0 , 0 } }, // #178 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 57, 9 , 0 , 0 , 0 } }, // #179 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 43, { 10, 5 , 5 , 0 , 0 , 0 } }, // #180 [ref=9x] - { InstDB::RWInfo::kCategoryGeneric , 44, { 72, 43, 0 , 0 , 0 , 0 } }, // #181 [ref=6x] - { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 73, 0 , 0 , 0 , 0 } }, // #182 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 3 , 0 , 0 , 0 , 0 } }, // #183 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 46, { 71, 43, 0 , 0 , 0 , 0 } }, // #184 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 6 , { 2 , 3 , 3 , 0 , 0 , 0 } }, // #185 [ref=60x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 4 , 57, 7 , 0 , 0 , 0 } }, // #186 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 4 , 74, 9 , 0 , 0 , 0 } }, // #187 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 6 , 7 , 7 , 0 , 0 , 0 } }, // #188 [ref=11x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 8 , 9 , 9 , 0 , 0 , 0 } }, // #189 [ref=11x] - { InstDB::RWInfo::kCategoryGeneric , 47, { 11, 3 , 3 , 3 , 0 , 0 } }, // #190 [ref=15x] - { InstDB::RWInfo::kCategoryGeneric , 48, { 34, 7 , 7 , 7 , 0 , 0 } }, // #191 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 49, { 42, 9 , 9 , 9 , 0 , 0 } }, // #192 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 25, 7 , 7 , 0 , 0 , 0 } }, // #193 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 75, 9 , 9 , 0 , 0 , 0 } }, // #194 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 14, { 34, 3 , 0 , 0 , 0 , 0 } }, // #195 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 6 , { 59, 41, 3 , 0 , 0 , 0 } }, // #121 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 11, 3 , 60, 0 , 0 } }, // #122 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 28, 0 , 0 , 0 , 0 } }, // #123 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 28, 29, 0 , 0 , 0 } }, // #124 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 3 , 0 , 0 , 0 , 0 , 0 } }, // #125 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 50, 21, 0 , 0 , 0 , 0 } }, // #126 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 50, 61, 0 , 0 , 0 , 0 } }, // #127 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 4 , { 25, 7 , 0 , 0 , 0 , 0 } }, // #128 [ref=18x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 62, 16, 56 } }, // #129 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 63, 16, 56 } }, // #130 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 62, 0 , 0 } }, // #131 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 63, 0 , 0 } }, // #132 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 31, { 53, 5 , 0 , 0 , 0 , 0 } }, // #133 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 32, { 34, 5 , 0 , 0 , 0 , 0 } }, // #134 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 33, { 47, 3 , 0 , 0 , 0 , 0 } }, // #135 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 64, 5 , 0 , 0 , 0 , 0 } }, // #136 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 15, { 4 , 39, 0 , 0 , 0 , 0 } }, // #137 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 4 , { 4 , 7 , 0 , 0 , 0 , 0 } }, // #138 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 27, { 2 , 13, 0 , 0 , 0 , 0 } }, // #139 [ref=1x] + { InstDB::RWInfo::kCategoryVmov1_8 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #140 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 5 , { 10, 9 , 0 , 0 , 0 , 0 } }, // #141 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 27, { 10, 13, 0 , 0 , 0 , 0 } }, // #142 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 65, 0 , 0 , 0 , 0 , 0 } }, // #143 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 0 , 0 , 0 } }, // #144 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 60, 0 , 0 , 0 , 0 , 0 } }, // #145 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 2 , 66, 0 , 0 , 0 , 0 } }, // #146 [ref=8x] + { InstDB::RWInfo::kCategoryGeneric , 5 , { 36, 9 , 0 , 0 , 0 , 0 } }, // #147 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 11, 0 , 0 , 0 , 0 , 0 } }, // #148 [ref=6x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 28, 0 , 0 , 0 } }, // #149 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 0 , 0 , 0 , 0 } }, // #150 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 62, 0 , 0 , 0 } }, // #151 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 68, 0 , 0 , 0 , 0 , 0 } }, // #152 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 21, 20, 0 , 0 , 0 , 0 } }, // #153 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 31, { 69, 0 , 0 , 0 , 0 , 0 } }, // #154 [ref=30x] + { InstDB::RWInfo::kCategoryGeneric , 11, { 2 , 3 , 66, 0 , 0 , 0 } }, // #155 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 34, { 11, 0 , 0 , 0 , 0 , 0 } }, // #156 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 28, { 42, 0 , 0 , 0 , 0 , 0 } }, // #157 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 20, 21, 0 , 0 , 0 , 0 } }, // #158 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 12, { 70, 43, 43, 43, 43, 5 } }, // #159 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 12, { 4 , 5 , 5 , 5 , 5 , 5 } }, // #160 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 10, 5 , 7 , 0 , 0 , 0 } }, // #161 [ref=8x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 5 , 9 , 0 , 0 , 0 } }, // #162 [ref=9x] + { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 3 , 3 , 3 , 0 , 0 } }, // #163 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 12, { 71, 5 , 0 , 0 , 0 , 0 } }, // #164 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 12, { 11, 5 , 0 , 0 , 0 , 0 } }, // #165 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 37, { 72, 73, 0 , 0 , 0 , 0 } }, // #166 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 38, { 11, 7 , 0 , 0 , 0 , 0 } }, // #167 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 39, { 11, 9 , 0 , 0 , 0 , 0 } }, // #168 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 11, 5 , 7 , 0 , 0 , 0 } }, // #169 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 11, 5 , 9 , 0 , 0 , 0 } }, // #170 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 11, { 11, 3 , 0 , 0 , 0 , 0 } }, // #171 [ref=7x] + { InstDB::RWInfo::kCategoryVmov2_1 , 40, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #172 [ref=14x] + { InstDB::RWInfo::kCategoryVmov1_2 , 14, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #173 [ref=7x] + { InstDB::RWInfo::kCategoryVmov1_2 , 41, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #174 [ref=10x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 10, 74, 7 , 0 , 0 , 0 } }, // #175 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 57, 3 , 0 , 0 , 0 } }, // #176 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 74, 3 , 0 , 0 , 0 } }, // #177 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 57, 9 , 0 , 0 , 0 } }, // #178 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 43, { 10, 5 , 5 , 0 , 0 , 0 } }, // #179 [ref=9x] + { InstDB::RWInfo::kCategoryGeneric , 44, { 72, 43, 0 , 0 , 0 , 0 } }, // #180 [ref=6x] + { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 73, 0 , 0 , 0 , 0 } }, // #181 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 3 , 0 , 0 , 0 , 0 } }, // #182 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 46, { 71, 43, 0 , 0 , 0 , 0 } }, // #183 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 6 , { 2 , 3 , 3 , 0 , 0 , 0 } }, // #184 [ref=60x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 4 , 57, 7 , 0 , 0 , 0 } }, // #185 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 4 , 74, 9 , 0 , 0 , 0 } }, // #186 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 6 , 7 , 7 , 0 , 0 , 0 } }, // #187 [ref=11x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 8 , 9 , 9 , 0 , 0 , 0 } }, // #188 [ref=11x] + { InstDB::RWInfo::kCategoryGeneric , 47, { 11, 3 , 3 , 3 , 0 , 0 } }, // #189 [ref=15x] + { InstDB::RWInfo::kCategoryGeneric , 48, { 34, 7 , 7 , 7 , 0 , 0 } }, // #190 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 49, { 42, 9 , 9 , 9 , 0 , 0 } }, // #191 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 25, 7 , 7 , 0 , 0 , 0 } }, // #192 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 75, 9 , 9 , 0 , 0 , 0 } }, // #193 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 14, { 34, 3 , 0 , 0 , 0 , 0 } }, // #194 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 5 , { 34, 9 , 0 , 0 , 0 , 0 } }, // #195 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 5 , { 42, 9 , 0 , 0 , 0 , 0 } }, // #196 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 8 , { 2 , 3 , 2 , 0 , 0 , 0 } }, // #197 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 2 , 3 , 2 , 0 , 0 , 0 } }, // #198 [ref=4x] @@ -3807,15 +3808,15 @@ const InstDB::RWInfoOp InstDB::rwInfoOp[] = { { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, 0 }, // #0 [ref=14957x] { 0x0000000000000003u, 0x0000000000000003u, 0x00, { 0 }, OpRWInfo::kRW | OpRWInfo::kRegPhysId }, // #1 [ref=10x] { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRW | OpRWInfo::kZExt }, // #2 [ref=217x] - { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #3 [ref=978x] + { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #3 [ref=979x] { 0x000000000000FFFFu, 0x000000000000FFFFu, 0xFF, { 0 }, OpRWInfo::kRW | OpRWInfo::kZExt }, // #4 [ref=92x] { 0x000000000000FFFFu, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #5 [ref=305x] { 0x00000000000000FFu, 0x00000000000000FFu, 0xFF, { 0 }, OpRWInfo::kRW }, // #6 [ref=18x] { 0x00000000000000FFu, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #7 [ref=181x] { 0x000000000000000Fu, 0x000000000000000Fu, 0xFF, { 0 }, OpRWInfo::kRW }, // #8 [ref=18x] - { 0x000000000000000Fu, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #9 [ref=130x] + { 0x000000000000000Fu, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #9 [ref=129x] { 0x0000000000000000u, 0x000000000000FFFFu, 0xFF, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt }, // #10 [ref=160x] - { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt }, // #11 [ref=415x] + { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt }, // #11 [ref=416x] { 0x0000000000000003u, 0x0000000000000003u, 0xFF, { 0 }, OpRWInfo::kRW }, // #12 [ref=1x] { 0x0000000000000003u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #13 [ref=34x] { 0x000000000000FFFFu, 0x0000000000000000u, 0x00, { 0 }, OpRWInfo::kRead | OpRWInfo::kRegPhysId }, // #14 [ref=4x] @@ -3838,7 +3839,7 @@ const InstDB::RWInfoOp InstDB::rwInfoOp[] = { { 0x000000000000000Fu, 0x000000000000000Fu, 0x01, { 0 }, OpRWInfo::kRW | OpRWInfo::kZExt | OpRWInfo::kRegPhysId }, // #31 [ref=1x] { 0x0000000000000000u, 0x00000000000000FFu, 0x02, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt | OpRWInfo::kRegPhysId }, // #32 [ref=1x] { 0x00000000000000FFu, 0x0000000000000000u, 0x00, { 0 }, OpRWInfo::kRead | OpRWInfo::kRegPhysId }, // #33 [ref=1x] - { 0x0000000000000000u, 0x00000000000000FFu, 0xFF, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt }, // #34 [ref=76x] + { 0x0000000000000000u, 0x00000000000000FFu, 0xFF, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt }, // #34 [ref=75x] { 0x0000000000000000u, 0x00000000000000FFu, 0xFF, { 0 }, OpRWInfo::kWrite }, // #35 [ref=6x] { 0x0000000000000000u, 0x000000000000000Fu, 0xFF, { 0 }, OpRWInfo::kWrite }, // #36 [ref=6x] { 0x0000000000000000u, 0x0000000000000003u, 0x02, { 0 }, OpRWInfo::kWrite | OpRWInfo::kRegPhysId }, // #37 [ref=1x] @@ -3886,10 +3887,10 @@ const InstDB::RWInfoOp InstDB::rwInfoOp[] = { const InstDB::RWInfoRm InstDB::rwInfoRm[] = { { InstDB::RWInfoRm::kCategoryNone , 0x00, 0 , 0, 0 }, // #0 [ref=1809x] { InstDB::RWInfoRm::kCategoryConsistent, 0x03, 0 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #1 [ref=8x] - { InstDB::RWInfoRm::kCategoryConsistent, 0x02, 0 , 0, 0 }, // #2 [ref=193x] + { InstDB::RWInfoRm::kCategoryConsistent, 0x02, 0 , 0, 0 }, // #2 [ref=194x] { InstDB::RWInfoRm::kCategoryFixed , 0x02, 16, 0, 0 }, // #3 [ref=122x] { InstDB::RWInfoRm::kCategoryFixed , 0x02, 8 , 0, 0 }, // #4 [ref=66x] - { InstDB::RWInfoRm::kCategoryFixed , 0x02, 4 , 0, 0 }, // #5 [ref=34x] + { InstDB::RWInfoRm::kCategoryFixed , 0x02, 4 , 0, 0 }, // #5 [ref=33x] { InstDB::RWInfoRm::kCategoryConsistent, 0x04, 0 , 0, 0 }, // #6 [ref=270x] { InstDB::RWInfoRm::kCategoryFixed , 0x01, 2 , 0, 0 }, // #7 [ref=9x] { InstDB::RWInfoRm::kCategoryFixed , 0x00, 0 , 0, 0 }, // #8 [ref=60x] diff --git a/3rdparty/asmjit/src/asmjit/x86/x86instdb.h b/3rdparty/asmjit/src/asmjit/x86/x86instdb.h index d03b87035c3..6bc2af5000a 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86instdb.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86instdb.h @@ -46,9 +46,9 @@ enum Mode : uint32_t { kModeAny = 0x03u //!< Both X86 and X64 modes supported. }; -static constexpr uint32_t modeFromArchId(uint32_t archId) noexcept { - return archId == ArchInfo::kIdX86 ? kModeX86 : - archId == ArchInfo::kIdX64 ? kModeX64 : kModeNone; +static constexpr uint32_t modeFromArch(uint32_t arch) noexcept { + return arch == Environment::kArchX86 ? kModeX86 : + arch == Environment::kArchX64 ? kModeX64 : kModeNone; } // ============================================================================ @@ -142,12 +142,6 @@ enum MemFlags : uint32_t { enum Flags : uint32_t { kFlagNone = 0x00000000u, //!< No flags. - // TODO: Deprecated - // ---------------- - - kFlagVolatile = 0x00000040u, - kFlagPrivileged = 0x00000080u, //!< This is a privileged operation that cannot run in user mode. - // Instruction Family // ------------------ // diff --git a/3rdparty/asmjit/src/asmjit/x86/x86internal.cpp b/3rdparty/asmjit/src/asmjit/x86/x86internal.cpp index a35b0d34e33..062525f5982 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86internal.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86internal.cpp @@ -24,7 +24,7 @@ #include "../core/api-build_p.h" #ifdef ASMJIT_BUILD_X86 -#include "../core/logging.h" +#include "../core/formatter.h" #include "../core/string.h" #include "../core/support.h" #include "../core/type.h" @@ -67,11 +67,9 @@ static inline uint32_t x86KmovFromSize(uint32_t size) noexcept { // [asmjit::X86Internal - FuncDetail] // ============================================================================ -ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const FuncSignature& sign, uint32_t gpSize) noexcept { - DebugUtils::unused(sign); - +ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const FuncSignature& signature, uint32_t registerSize) noexcept { const CallConv& cc = func.callConv(); - uint32_t archId = cc.archId(); + uint32_t arch = cc.arch(); uint32_t stackOffset = cc._spillZoneSize; uint32_t i; @@ -82,7 +80,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const Func switch (typeId) { case Type::kIdI64: case Type::kIdU64: { - if (archId == ArchInfo::kIdX86) { + if (Environment::is32Bit(arch)) { // Convert a 64-bit return value to two 32-bit return values. func._retCount = 2; typeId -= 2; @@ -114,7 +112,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const Func case Type::kIdF32: case Type::kIdF64: { - uint32_t regType = (archId == ArchInfo::kIdX86) ? Reg::kTypeSt : Reg::kTypeXmm; + uint32_t regType = Environment::is32Bit(arch) ? Reg::kTypeSt : Reg::kTypeXmm; func._rets[0].initReg(regType, 0, typeId); break; } @@ -127,9 +125,9 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const Func case Type::kIdMmx32: case Type::kIdMmx64: { - // MM registers are returned through XMM or GPQ (Win64). + // MM registers are returned through XMM (SystemV) or GPQ (Win64). uint32_t regType = Reg::kTypeMm; - if (archId != ArchInfo::kIdX86) + if (Environment::is64Bit(arch)) regType = cc.strategy() == CallConv::kStrategyDefault ? Reg::kTypeXmm : Reg::kTypeGpq; func._rets[0].initReg(regType, 0, typeId); @@ -143,90 +141,156 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const Func } } - if (cc.strategy() == CallConv::kStrategyDefault) { - uint32_t gpzPos = 0; - uint32_t vecPos = 0; - - for (i = 0; i < argCount; i++) { - FuncValue& arg = func._args[i]; - uint32_t typeId = arg.typeId(); - - if (Type::isInt(typeId)) { - uint32_t regId = gpzPos < CallConv::kMaxRegArgsPerGroup ? cc._passedOrder[Reg::kGroupGp].id[gpzPos] : uint8_t(BaseReg::kIdBad); - if (regId != BaseReg::kIdBad) { - uint32_t regType = (typeId <= Type::kIdU32) ? Reg::kTypeGpd : Reg::kTypeGpq; - arg.assignRegData(regType, regId); - func.addUsedRegs(Reg::kGroupGp, Support::bitMask(regId)); - gpzPos++; - } - else { - uint32_t size = Support::max<uint32_t>(Type::sizeOf(typeId), gpSize); - arg.assignStackOffset(int32_t(stackOffset)); - stackOffset += size; - } - continue; - } + switch (cc.strategy()) { + case CallConv::kStrategyDefault: { + uint32_t gpzPos = 0; + uint32_t vecPos = 0; + + for (i = 0; i < argCount; i++) { + FuncValue& arg = func._args[i]; + uint32_t typeId = arg.typeId(); - if (Type::isFloat(typeId) || Type::isVec(typeId)) { - uint32_t regId = vecPos < CallConv::kMaxRegArgsPerGroup ? cc._passedOrder[Reg::kGroupVec].id[vecPos] : uint8_t(BaseReg::kIdBad); + if (Type::isInt(typeId)) { + uint32_t regId = BaseReg::kIdBad; - // If this is a float, but `floatByVec` is false, we have to pass by stack. - if (Type::isFloat(typeId) && !cc.hasFlag(CallConv::kFlagPassFloatsByVec)) - regId = BaseReg::kIdBad; + if (gpzPos < CallConv::kMaxRegArgsPerGroup) + regId = cc._passedOrder[Reg::kGroupGp].id[gpzPos]; - if (regId != BaseReg::kIdBad) { - arg.initTypeId(typeId); - arg.assignRegData(x86VecTypeIdToRegType(typeId), regId); - func.addUsedRegs(Reg::kGroupVec, Support::bitMask(regId)); - vecPos++; + if (regId != BaseReg::kIdBad) { + uint32_t regType = (typeId <= Type::kIdU32) ? Reg::kTypeGpd : Reg::kTypeGpq; + arg.assignRegData(regType, regId); + func.addUsedRegs(Reg::kGroupGp, Support::bitMask(regId)); + gpzPos++; + } + else { + uint32_t size = Support::max<uint32_t>(Type::sizeOf(typeId), registerSize); + arg.assignStackOffset(int32_t(stackOffset)); + stackOffset += size; + } + continue; } - else { - uint32_t size = Type::sizeOf(typeId); - arg.assignStackOffset(int32_t(stackOffset)); - stackOffset += size; + + if (Type::isFloat(typeId) || Type::isVec(typeId)) { + uint32_t regId = BaseReg::kIdBad; + + if (vecPos < CallConv::kMaxRegArgsPerGroup) + regId = cc._passedOrder[Reg::kGroupVec].id[vecPos]; + + if (Type::isFloat(typeId)) { + // If this is a float, but `kFlagPassFloatsByVec` is false, we have + // to use stack instead. This should be only used by 32-bit calling + // conventions. + if (!cc.hasFlag(CallConv::kFlagPassFloatsByVec)) + regId = BaseReg::kIdBad; + } + else { + // Pass vector registers via stack if this is a variable arguments + // function. This should be only used by 32-bit calling conventions. + if (signature.hasVarArgs() && cc.hasFlag(CallConv::kFlagPassVecByStackIfVA)) + regId = BaseReg::kIdBad; + } + + if (regId != BaseReg::kIdBad) { + arg.initTypeId(typeId); + arg.assignRegData(x86VecTypeIdToRegType(typeId), regId); + func.addUsedRegs(Reg::kGroupVec, Support::bitMask(regId)); + vecPos++; + } + else { + uint32_t size = Type::sizeOf(typeId); + arg.assignStackOffset(int32_t(stackOffset)); + stackOffset += size; + } + continue; } - continue; } + break; } - } - if (cc.strategy() == CallConv::kStrategyWin64) { - for (i = 0; i < argCount; i++) { - FuncValue& arg = func._args[i]; + case CallConv::kStrategyX64Windows: + case CallConv::kStrategyX64VectorCall: { + // Both X64 and VectorCall behave similarly - arguments are indexed + // from left to right. The position of the argument determines in + // which register the argument is allocated, so it's either GP or + // one of XMM/YMM/ZMM registers. + // + // [ X64 ] [VecCall] + // Index: #0 #1 #2 #3 #4 #5 + // + // GP : RCX RDX R8 R9 + // VEC : XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 + // + // For example function `f(int a, double b, int c, double d)` will be: + // + // (a) (b) (c) (d) + // RCX XMM1 R8 XMM3 + // + // Unused vector registers are used by HVA. + + bool isVectorCall = (cc.strategy() == CallConv::kStrategyX64VectorCall); + + for (i = 0; i < argCount; i++) { + FuncValue& arg = func._args[i]; + + uint32_t typeId = arg.typeId(); + uint32_t size = Type::sizeOf(typeId); + + if (Type::isInt(typeId) || Type::isMmx(typeId)) { + uint32_t regId = BaseReg::kIdBad; + + if (i < CallConv::kMaxRegArgsPerGroup) + regId = cc._passedOrder[Reg::kGroupGp].id[i]; + + if (regId != BaseReg::kIdBad) { + uint32_t regType = (size <= 4 && !Type::isMmx(typeId)) ? Reg::kTypeGpd : Reg::kTypeGpq; + arg.assignRegData(regType, regId); + func.addUsedRegs(Reg::kGroupGp, Support::bitMask(regId)); + } + else { + arg.assignStackOffset(int32_t(stackOffset)); + stackOffset += 8; + } + continue; + } - uint32_t typeId = arg.typeId(); - uint32_t size = Type::sizeOf(typeId); + if (Type::isFloat(typeId) || Type::isVec(typeId)) { + uint32_t regId = BaseReg::kIdBad; - if (Type::isInt(typeId) || Type::isMmx(typeId)) { - uint32_t regId = i < CallConv::kMaxRegArgsPerGroup ? cc._passedOrder[Reg::kGroupGp].id[i] : uint8_t(BaseReg::kIdBad); - if (regId != BaseReg::kIdBad) { - uint32_t regType = (size <= 4 && !Type::isMmx(typeId)) ? Reg::kTypeGpd : Reg::kTypeGpq; - arg.assignRegData(regType, regId); - func.addUsedRegs(Reg::kGroupGp, Support::bitMask(regId)); - } - else { - arg.assignStackOffset(int32_t(stackOffset)); - stackOffset += gpSize; - } - continue; - } + if (i < CallConv::kMaxRegArgsPerGroup) + regId = cc._passedOrder[Reg::kGroupVec].id[i]; - if (Type::isFloat(typeId) || Type::isVec(typeId)) { - uint32_t regId = BaseReg::kIdBad; - if (i < CallConv::kMaxRegArgsPerGroup) - regId = cc._passedOrder[Reg::kGroupVec].id[i]; + if (regId != BaseReg::kIdBad) { + // X64-ABI doesn't allow vector types (XMM|YMM|ZMM) to be passed + // via registers, however, VectorCall was designed for that purpose. + if (Type::isFloat(typeId) || isVectorCall) { + uint32_t regType = x86VecTypeIdToRegType(typeId); + arg.assignRegData(regType, regId); + func.addUsedRegs(Reg::kGroupVec, Support::bitMask(regId)); + continue; + } + } - if (regId != BaseReg::kIdBad && (Type::isFloat(typeId) || cc.hasFlag(CallConv::kFlagVectorCall))) { - uint32_t regType = x86VecTypeIdToRegType(typeId); - arg.assignRegData(regType, regId); - func.addUsedRegs(Reg::kGroupVec, Support::bitMask(regId)); - } - else { - arg.assignStackOffset(int32_t(stackOffset)); - stackOffset += 8; // Always 8 bytes (float/double). + // Passed via stack if the argument is float/double or indirectly. + // The trap is - if the argument is passed indirectly, the address + // can be passed via register, if the argument's index has GP one. + if (Type::isFloat(typeId)) { + arg.assignStackOffset(int32_t(stackOffset)); + } + else { + uint32_t gpRegId = cc._passedOrder[Reg::kGroupGp].id[i]; + if (gpRegId != BaseReg::kIdBad) + arg.assignRegData(Reg::kTypeGpq, gpRegId); + else + arg.assignStackOffset(int32_t(stackOffset)); + arg.addFlags(FuncValue::kFlagIsIndirect); + } + + // Always 8 bytes (float/double/pointer). + stackOffset += 8; + continue; } - continue; } + break; } } @@ -238,14 +302,14 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const Func // [asmjit::X86FuncArgsContext] // ============================================================================ -static RegInfo x86GetRegForMemToMemMove(uint32_t archId, uint32_t dstTypeId, uint32_t srcTypeId) noexcept { +static RegInfo x86GetRegForMemToMemMove(uint32_t arch, uint32_t dstTypeId, uint32_t srcTypeId) noexcept { uint32_t dstSize = Type::sizeOf(dstTypeId); uint32_t srcSize = Type::sizeOf(srcTypeId); uint32_t maxSize = Support::max<uint32_t>(dstSize, srcSize); - uint32_t gpSize = archId == ArchInfo::kIdX86 ? 4 : 8; + uint32_t regSize = Environment::registerSizeFromArch(arch); uint32_t signature = 0; - if (maxSize <= gpSize || (Type::isInt(dstTypeId) && Type::isInt(srcTypeId))) + if (maxSize <= regSize || (Type::isInt(dstTypeId) && Type::isInt(srcTypeId))) signature = maxSize <= 4 ? Gpd::kSignature : Gpq::kSignature; else if (maxSize <= 16) signature = Xmm::kSignature; @@ -360,7 +424,7 @@ public: uint8_t _physToVarId[32]; //!< Physical ID to variable ID mapping. }; - uint8_t _archId; + uint8_t _arch; bool _hasStackSrc; //!< Has arguments passed via stack (SRC). bool _hasPreservedFP; //!< Has preserved frame-pointer (FP). uint8_t _stackDstMask; //!< Has arguments assigned to stack (DST). @@ -372,12 +436,12 @@ public: X86FuncArgsContext() noexcept; - inline uint32_t archId() const noexcept { return _archId; } + inline uint32_t arch() const noexcept { return _arch; } inline uint32_t varCount() const noexcept { return _varCount; } - inline Var& var(uint32_t varId) noexcept { return _vars[varId]; } - inline const Var& var(uint32_t varId) const noexcept { return _vars[varId]; } - inline uint32_t indexOf(const Var* var) const noexcept { return uint32_t((size_t)(var - _vars)); } + inline Var& var(size_t varId) noexcept { return _vars[varId]; } + inline const Var& var(size_t varId) const noexcept { return _vars[varId]; } + inline size_t indexOf(const Var* var) const noexcept { return (size_t)(var - _vars); } Error initWorkData(const FuncFrame& frame, const FuncArgsAssignment& args) noexcept; Error markScratchRegs(FuncFrame& frame) noexcept; @@ -386,7 +450,7 @@ public: }; X86FuncArgsContext::X86FuncArgsContext() noexcept { - _archId = ArchInfo::kIdNone; + _arch = Environment::kArchUnknown; _varCount = 0; _hasStackSrc = false; _hasPreservedFP = false; @@ -405,11 +469,11 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::initWorkData(const FuncFrame& frame, uint32_t i; const FuncDetail& func = *args.funcDetail(); - // Initialize ArchType. - uint32_t archId = func.callConv().archId(); - uint32_t archRegCount = (archId == ArchInfo::kIdX86) ? 8 : 16; + // Initialize Architecture. + uint32_t arch = func.callConv().arch(); + uint32_t archRegCount = Environment::is32Bit(arch) ? 8 : 16; - _archId = uint8_t(archId); + _arch = uint8_t(arch); // Initialize `_archRegs`. _workData[Reg::kGroupGp ]._archRegs = Support::lsbMask<uint32_t>(archRegCount) & ~Support::bitMask(Gp::kIdSp); @@ -424,7 +488,8 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::initWorkData(const FuncFrame& frame, uint32_t varId = 0; for (i = 0; i < kFuncArgCountLoHi; i++) { const FuncValue& dst_ = args.arg(i); - if (!dst_.isAssigned()) continue; + if (!dst_.isAssigned()) + continue; const FuncValue& src_ = func.arg(i); if (ASMJIT_UNLIKELY(!src_.isAssigned())) @@ -440,6 +505,10 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::initWorkData(const FuncFrame& frame, uint32_t dstId = BaseReg::kIdBad; WorkData* dstWd = nullptr; + // Not supported. + if (src.isIndirect()) + return DebugUtils::errored(kErrorInvalidAssignment); + if (dst.isReg()) { uint32_t dstType = dst.regType(); if (ASMJIT_UNLIKELY(dstType >= Reg::kTypeCount)) @@ -471,7 +540,7 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::initWorkData(const FuncFrame& frame, if (!dst.hasTypeId()) dst.setTypeId(src.typeId()); - RegInfo regInfo = x86GetRegForMemToMemMove(archId, dst.typeId(), src.typeId()); + RegInfo regInfo = x86GetRegForMemToMemMove(arch, dst.typeId(), src.typeId()); if (ASMJIT_UNLIKELY(!regInfo.isValid())) return DebugUtils::errored(kErrorInvalidState); _stackDstMask = uint8_t(_stackDstMask | Support::bitMask(regInfo.group())); @@ -530,8 +599,8 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::initWorkData(const FuncFrame& frame, } if (saRegRequired) { - uint32_t ptrTypeId = (archId == ArchInfo::kIdX86) ? Type::kIdU32 : Type::kIdU64; - uint32_t ptrRegType = (archId == ArchInfo::kIdX86) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64; + uint32_t ptrTypeId = Environment::is32Bit(arch) ? Type::kIdU32 : Type::kIdU64; + uint32_t ptrRegType = Environment::is32Bit(arch) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64; _saVarId = uint8_t(varId); _hasPreservedFP = frame.hasPreservedFP(); @@ -622,7 +691,7 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::markScratchRegs(FuncFrame& frame) no if (!groupMask) return kErrorOk; - // selects one dirty register per affected group that can be used as a scratch register. + // Selects one dirty register per affected group that can be used as a scratch register. for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) { if (Support::bitTest(groupMask, group)) { WorkData& wd = _workData[group]; @@ -632,15 +701,18 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::markScratchRegs(FuncFrame& frame) no uint32_t regs = workRegs & ~(wd.usedRegs() | wd._dstShuf); // If that didn't work out pick some register which is not in 'used'. - if (!regs) regs = workRegs & ~wd.usedRegs(); + if (!regs) + regs = workRegs & ~wd.usedRegs(); // If that didn't work out pick any other register that is allocable. // This last resort case will, however, result in marking one more // register dirty. - if (!regs) regs = wd.archRegs() & ~workRegs; + if (!regs) + regs = wd.archRegs() & ~workRegs; // If that didn't work out we will have to use XORs instead of MOVs. - if (!regs) continue; + if (!regs) + continue; uint32_t regMask = Support::blsi(regs); wd._workRegs |= regMask; @@ -652,7 +724,6 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::markScratchRegs(FuncFrame& frame) no } ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::markStackArgsReg(FuncFrame& frame) noexcept { - // TODO: Validate, improve... if (_saVarId != kVarIdNone) { const Var& var = _vars[_saVarId]; frame.setSARegId(var.cur.regId()); @@ -670,14 +741,14 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::markStackArgsReg(FuncFrame& frame) n // ============================================================================ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncFrame(FuncFrame& frame, const FuncDetail& func) noexcept { - uint32_t archId = func.callConv().archId(); + uint32_t arch = func.callConv().arch(); // Initializing FuncFrame means making a copy of some properties of `func`. // Properties like `_localStackSize` will be set by the user before the frame // is finalized. frame.reset(); - frame._archId = uint8_t(archId); + frame._arch = uint8_t(arch); frame._spRegId = Gp::kIdSp; frame._saRegId = Gp::kIdBad; @@ -710,7 +781,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncFrame(FuncFrame& frame, const FuncD } ASMJIT_FAVOR_SIZE Error X86Internal::finalizeFuncFrame(FuncFrame& frame) noexcept { - uint32_t gpSize = frame.archId() == ArchInfo::kIdX86 ? 4 : 8; + uint32_t registerSize = Environment::registerSizeFromArch(frame.arch()); // The final stack alignment must be updated accordingly to call and local stack alignments. uint32_t stackAlignment = frame._finalStackAlignment; @@ -746,7 +817,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::finalizeFuncFrame(FuncFrame& frame) noexcep frame._saRegId = uint8_t(saRegId); // Setup stack size used to save preserved registers. - frame._gpSaveSize = uint16_t(Support::popcnt(frame.savedRegs(Reg::kGroupGp )) * gpSize); + frame._gpSaveSize = uint16_t(Support::popcnt(frame.savedRegs(Reg::kGroupGp )) * registerSize); frame._nonGpSaveSize = uint16_t(Support::popcnt(frame.savedRegs(Reg::kGroupVec )) * vecSize + Support::popcnt(frame.savedRegs(Reg::kGroupMm )) * 8 + Support::popcnt(frame.savedRegs(Reg::kGroupKReg)) * 8); @@ -772,15 +843,15 @@ ASMJIT_FAVOR_SIZE Error X86Internal::finalizeFuncFrame(FuncFrame& frame) noexcep // Calculate if dynamic alignment (DA) slot (stored as offset relative to SP) is required and its offset. if (hasDA && !hasFP) { frame._daOffset = v; // Store 'daOffset' <- DA pointer would be stored here. - v += gpSize; // Count 'daOffset'. + v += registerSize; // Count 'daOffset'. } else { frame._daOffset = FuncFrame::kTagInvalidOffset; } // The return address should be stored after GP save/restore regs. It has - // the same size as `gpSize` (basically the native register/pointer size). - // We don't adjust it now as `v` now contains the exact size that the + // the same size as `registerSize` (basically the native register/pointer + // size). We don't adjust it now as `v` now contains the exact size that the // function requires to adjust (call frame + stack frame, vec stack size). // The stack (if we consider this size) is misaligned now, as it's always // aligned before the function call - when `call()` is executed it pushes @@ -788,27 +859,27 @@ ASMJIT_FAVOR_SIZE Error X86Internal::finalizeFuncFrame(FuncFrame& frame) noexcep // (depending on the architecture). So count number of bytes needed to align // it up to the function's CallFrame (the beginning). if (v || frame.hasFuncCalls()) - v += Support::alignUpDiff(v + frame.gpSaveSize() + gpSize, stackAlignment); + v += Support::alignUpDiff(v + frame.gpSaveSize() + registerSize, stackAlignment); frame._gpSaveOffset = v; // Store 'gpSaveOffset' <- Function's GP Save/Restore starts here. frame._stackAdjustment = v; // Store 'stackAdjustment' <- SA used by 'add zsp, SA' and 'sub zsp, SA'. v += frame._gpSaveSize; // Count 'gpSaveSize' <- Function's GP Save/Restore ends here. - v += gpSize; // Count 'ReturnAddress' <- As CALL pushes onto stack. + v += registerSize; // Count 'ReturnAddress' <- As CALL pushes onto stack. // If the function performs dynamic stack alignment then the stack-adjustment must be aligned. if (hasDA) frame._stackAdjustment = Support::alignUp(frame._stackAdjustment, stackAlignment); uint32_t saInvOff = FuncFrame::kTagInvalidOffset; - uint32_t saTmpOff = gpSize + frame._gpSaveSize; + uint32_t saTmpOff = registerSize + frame._gpSaveSize; // Calculate where the function arguments start relative to SP. frame._saOffsetFromSP = hasDA ? saInvOff : v; // Calculate where the function arguments start relative to FP or user-provided register. - frame._saOffsetFromSA = hasFP ? gpSize * 2 // Return address + frame pointer. - : saTmpOff; // Return address + all saved GP regs. + frame._saOffsetFromSA = hasFP ? registerSize * 2 // Return address + frame pointer. + : saTmpOff; // Return address + all saved GP regs. return kErrorOk; } @@ -943,7 +1014,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, const Operand_& src_, uint32_t srcTypeId, bool avxEnabled, const char* comment) { // Deduce optional `dstTypeId`, which may be `Type::kIdVoid` in some cases. - if (!dstTypeId) dstTypeId = opData.archRegs.regTypeToTypeId[dst_.type()]; + if (!dstTypeId) + dstTypeId = opData.archRegs.regTypeToTypeId[dst_.type()]; // Invalid or abstract TypeIds are not allowed. ASMJIT_ASSERT(Type::isValid(dstTypeId) && !Type::isAbstract(dstTypeId)); @@ -969,11 +1041,13 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, typeOp == ((Type::kIdI32 << 8) | Type::kIdI8 ) || typeOp == ((Type::kIdI32 << 8) | Type::kIdI16) || typeOp == ((Type::kIdI64 << 8) | Type::kIdI8 ) || - typeOp == ((Type::kIdI64 << 8) | Type::kIdI16)) break; + typeOp == ((Type::kIdI64 << 8) | Type::kIdI16)) + break; // Sign extend by using 'movsxd'. instId = Inst::kIdMovsxd; - if (typeOp == ((Type::kIdI64 << 8) | Type::kIdI32)) break; + if (typeOp == ((Type::kIdI64 << 8) | Type::kIdI32)) + break; } if (Type::isInt(srcTypeId) || src_.isMem()) { @@ -991,7 +1065,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, dst.setSignature(srcSize == 4 ? Reg::signatureOfT<Reg::kTypeGpd>() : Reg::signatureOfT<Reg::kTypeGpq>()); - if (src.isReg()) src.setSignature(dst.signature()); + if (src.isReg()) + src.setSignature(dst.signature()); } break; } @@ -1003,7 +1078,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, if (Type::isMmx(srcTypeId)) { // 64-bit move. instId = Inst::kIdMovq; - if (srcSize == 8) break; + if (srcSize == 8) + break; // 32-bit move. instId = Inst::kIdMovd; @@ -1021,7 +1097,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, if (Type::isVec(srcTypeId)) { // 64-bit move. instId = avxEnabled ? Inst::kIdVmovq : Inst::kIdMovq; - if (srcSize == 8) break; + if (srcSize == 8) + break; // 32-bit move. instId = avxEnabled ? Inst::kIdVmovd : Inst::kIdMovd; @@ -1036,19 +1113,23 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, if (Type::isInt(srcTypeId) || src.isMem()) { // 64-bit move. - if (srcSize == 8) break; + if (srcSize == 8) + break; // 32-bit move. instId = Inst::kIdMovd; - if (src.isReg()) src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); + if (src.isReg()) + src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); break; } - if (Type::isMmx(srcTypeId)) break; + if (Type::isMmx(srcTypeId)) + break; // This will hurt if `avxEnabled`. instId = Inst::kIdMovdq2q; - if (Type::isVec(srcTypeId)) break; + if (Type::isVec(srcTypeId)) +break; } if (Type::isMask(dstTypeId)) { @@ -1056,7 +1137,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, if (Type::isInt(srcTypeId) || Type::isMask(srcTypeId) || src.isMem()) { instId = x86KmovFromSize(srcSize); - if (Reg::isGp(src) && srcSize <= 4) src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); + if (Reg::isGp(src) && srcSize <= 4) + src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); break; } } @@ -1112,7 +1194,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, // 32-bit move. if (srcSize <= 4) { instId = avxEnabled ? Inst::kIdVmovd : Inst::kIdMovd; - if (src.isReg()) src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); + if (src.isReg()) + src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); break; } @@ -1125,10 +1208,14 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, if (Reg::isVec(src) || src.isMem()) { instId = avxEnabled ? Inst::kIdVmovaps : Inst::kIdMovaps; - uint32_t sign = Reg::signatureOfVecBySize(srcSize); - dst.setSignature(sign); - if (src.isReg()) src.setSignature(sign); + if (src.isMem() && srcSize < emitter->environment().stackAlignment()) + instId = avxEnabled ? Inst::kIdVmovups : Inst::kIdMovups; + + uint32_t signature = Reg::signatureOfVecBySize(srcSize); + dst.setSignature(signature); + if (src.isReg()) + src.setSignature(signature); break; } } @@ -1249,7 +1336,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitEpilog(Emitter* emitter, const FuncFram uint32_t i; uint32_t regId; - uint32_t gpSize = emitter->gpSize(); + uint32_t registerSize = emitter->registerSize(); uint32_t gpSaved = frame.savedRegs(Reg::kGroupGp); Gp zsp = emitter->zsp(); // ESP|RSP register. @@ -1287,7 +1374,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitEpilog(Emitter* emitter, const FuncFram if (frame.hasPreservedFP()) { // Emit 'mov zsp, zbp' or 'lea zsp, [zbp - x]' - int32_t count = int32_t(frame.gpSaveSize() - gpSize); + int32_t count = int32_t(frame.gpSaveSize() - registerSize); if (!count) ASMJIT_PROPAGATE(emitter->mov(zsp, zbp)); else @@ -1338,24 +1425,28 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitEpilog(Emitter* emitter, const FuncFram // ============================================================================ #ifdef ASMJIT_DUMP_ARGS_ASSIGNMENT -static void dumpFuncValue(String& sb, uint32_t archId, const FuncValue& value) noexcept { - Logging::formatTypeId(sb, value.typeId()); - sb.appendChar('@'); - if (value.isReg()) { - Logging::formatRegister(sb, 0, nullptr, archId, value.regType(), value.regId()); - } - else if (value.isStack()) { +static void dumpFuncValue(String& sb, uint32_t arch, const FuncValue& value) noexcept { + Formatter::formatTypeId(sb, value.typeId()); + sb.append('@'); + + if (value.isIndirect()) + sb.append('['); + + if (value.isReg()) + Formatter::formatRegister(sb, 0, nullptr, arch, value.regType(), value.regId()); + else if (value.isStack()) sb.appendFormat("[%d]", value.stackOffset()); - } - else { - sb.appendString("<none>"); - } + else + sb.append("<none>"); + + if (value.isIndirect()) + sb.append(']'); } static void dumpAssignment(String& sb, const X86FuncArgsContext& ctx) noexcept { typedef X86FuncArgsContext::Var Var; - uint32_t archId = ctx.archId(); + uint32_t arch = ctx.arch(); uint32_t varCount = ctx.varCount(); for (uint32_t i = 0; i < varCount; i++) { @@ -1364,14 +1455,14 @@ static void dumpAssignment(String& sb, const X86FuncArgsContext& ctx) noexcept { const FuncValue& cur = var.cur; sb.appendFormat("Var%u: ", i); - dumpFuncValue(sb, archId, dst); - sb.appendString(" <- "); - dumpFuncValue(sb, archId, cur); + dumpFuncValue(sb, arch, dst); + sb.append(" <- "); + dumpFuncValue(sb, arch, cur); if (var.isDone()) - sb.appendString(" {Done}"); + sb.append(" {Done}"); - sb.appendChar('\n'); + sb.append('\n'); } } #endif @@ -1398,7 +1489,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgsAssignment(Emitter* emitter, const } #endif - uint32_t archId = ctx.archId(); + uint32_t arch = ctx.arch(); uint32_t varCount = ctx._varCount; WorkData* workData = ctx._workData; @@ -1415,6 +1506,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgsAssignment(Emitter* emitter, const saRegId = saVarId < varCount ? ctx._vars[saVarId].cur.regId() : frame.saRegId(); } + RegInfo gpRegInfo = emitter->_gpRegInfo; + // -------------------------------------------------------------------------- // Register to stack and stack to stack moves must be first as now we have // the biggest chance of having as many as possible unassigned registers. @@ -1427,24 +1520,42 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgsAssignment(Emitter* emitter, const for (uint32_t varId = 0; varId < varCount; varId++) { Var& var = ctx._vars[varId]; - if (!var.out.isStack()) continue; - ASMJIT_ASSERT(var.cur.isReg() || var.cur.isStack()); + if (!var.out.isStack()) + continue; + + FuncValue& cur = var.cur; + FuncValue& out = var.out; + + ASMJIT_ASSERT(cur.isReg() || cur.isStack()); Reg reg; - if (var.cur.isReg()) { - WorkData& wd = workData[Reg::groupOf(var.cur.regType())]; - uint32_t rId = var.cur.regId(); + Mem dstStackPtr = baseStackPtr.cloneAdjusted(out.stackOffset()); + Mem srcStackPtr = baseArgPtr.cloneAdjusted(cur.stackOffset()); + + if (cur.isIndirect()) { + if (cur.isStack()) { + // TODO: Indirect stack. + return DebugUtils::errored(kErrorInvalidAssignment); + } + else { + srcStackPtr = ptr(Gp(gpRegInfo.signature(), cur.regId())); + } + } + + if (cur.isReg() && !cur.isIndirect()) { + WorkData& wd = workData[Reg::groupOf(cur.regType())]; + uint32_t rId = cur.regId(); - reg.setSignatureAndId(Reg::signatureOf(var.cur.regType()), rId); + reg.setSignatureAndId(Reg::signatureOf(cur.regType()), rId); wd.unassign(varId, rId); } else { // Stack to reg move - tricky since we move stack to stack we can decide which // register to use. In general we follow the rule that IntToInt moves will use - // GP regs with possibility to sign or zero extend, and all other moves will + // GP regs with possibility to signature or zero extend, and all other moves will // either use GP or VEC regs depending on the size of the move. - RegInfo rInfo = x86GetRegForMemToMemMove(archId, var.out.typeId(), var.cur.typeId()); + RegInfo rInfo = x86GetRegForMemToMemMove(arch, out.typeId(), cur.typeId()); if (ASMJIT_UNLIKELY(!rInfo.isValid())) return DebugUtils::errored(kErrorInvalidState); @@ -1456,54 +1567,42 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgsAssignment(Emitter* emitter, const uint32_t rId = Support::ctz(availableRegs); reg.setSignatureAndId(rInfo.signature(), rId); - ASMJIT_PROPAGATE( - emitArgMove(emitter, - reg, - var.out.typeId(), - baseArgPtr.cloneAdjusted(var.cur.stackOffset()), - var.cur.typeId(), - avxEnabled)); + ASMJIT_PROPAGATE(emitArgMove(emitter, reg, out.typeId(), srcStackPtr, cur.typeId(), avxEnabled)); } - // Register to stack move. - ASMJIT_PROPAGATE( - emitRegMove(emitter, baseStackPtr.cloneAdjusted(var.out.stackOffset()), reg, var.cur.typeId(), avxEnabled)); + if (cur.isIndirect() && cur.isReg()) + workData[BaseReg::kGroupGp].unassign(varId, cur.regId()); + // Register to stack move. + ASMJIT_PROPAGATE(emitRegMove(emitter, dstStackPtr, reg, cur.typeId(), avxEnabled)); var.markDone(); } } // -------------------------------------------------------------------------- - // Shuffle all registers that are currently assigned accordingly to the assignment. + // Shuffle all registers that are currently assigned accordingly to target + // assignment. // -------------------------------------------------------------------------- uint32_t workFlags = kWorkNone; for (;;) { for (uint32_t varId = 0; varId < varCount; varId++) { Var& var = ctx._vars[varId]; - if (var.isDone() || !var.cur.isReg()) continue; + if (var.isDone() || !var.cur.isReg()) + continue; - uint32_t curType = var.cur.regType(); - uint32_t outType = var.out.regType(); + FuncValue& cur = var.cur; + FuncValue& out = var.out; - uint32_t curGroup = Reg::groupOf(curType); - uint32_t outGroup = Reg::groupOf(outType); + uint32_t curGroup = Reg::groupOf(cur.regType()); + uint32_t outGroup = Reg::groupOf(out.regType()); - uint32_t curId = var.cur.regId(); - uint32_t outId = var.out.regId(); + uint32_t curId = cur.regId(); + uint32_t outId = out.regId(); if (curGroup != outGroup) { - ASMJIT_ASSERT(false); - - // Requires a conversion between two register groups. - if (workData[outGroup]._numSwaps) { - // TODO: Postponed - workFlags |= kWorkPending; - } - else { - // TODO: - workFlags |= kWorkPending; - } + // TODO: Conversion is not supported. + return DebugUtils::errored(kErrorInvalidAssignment); } else { WorkData& wd = workData[outGroup]; @@ -1511,13 +1610,13 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgsAssignment(Emitter* emitter, const EmitMove: ASMJIT_PROPAGATE( emitArgMove(emitter, - Reg::fromTypeAndId(outType, outId), var.out.typeId(), - Reg::fromTypeAndId(curType, curId), var.cur.typeId(), avxEnabled)); + Reg::fromTypeAndId(out.regType(), outId), out.typeId(), + Reg::fromTypeAndId(cur.regType(), curId), cur.typeId(), avxEnabled)); wd.reassign(varId, outId, curId); - var.cur.initReg(outType, outId, var.out.typeId()); + cur.initReg(out.regType(), outId, out.typeId()); - if (outId == var.out.regId()) + if (outId == out.regId()) var.markDone(); workFlags |= kWorkDidSome | kWorkPending; } @@ -1528,13 +1627,13 @@ EmitMove: if (!altVar.out.isInitialized() || (altVar.out.isReg() && altVar.out.regId() == curId)) { // Swap operation is possible only between two GP registers. if (curGroup == Reg::kGroupGp) { - uint32_t highestType = Support::max(var.cur.regType(), altVar.cur.regType()); + uint32_t highestType = Support::max(cur.regType(), altVar.cur.regType()); uint32_t signature = highestType == Reg::kTypeGpq ? Reg::signatureOfT<Reg::kTypeGpq>() : Reg::signatureOfT<Reg::kTypeGpd>(); ASMJIT_PROPAGATE(emitter->emit(Inst::kIdXchg, Reg(signature, outId), Reg(signature, curId))); wd.swap(varId, curId, altId, outId); - var.cur.setRegId(outId); + cur.setRegId(outId); var.markDone(); altVar.cur.setRegId(curId); @@ -1590,7 +1689,8 @@ EmitMove: for (uint32_t iter = 0; iter < iterCount; iter++) { for (uint32_t varId = 0; varId < varCount; varId++) { Var& var = ctx._vars[varId]; - if (var.isDone()) continue; + if (var.isDone()) + continue; if (var.cur.isStack()) { ASMJIT_ASSERT(var.out.isReg()); diff --git a/3rdparty/asmjit/src/asmjit/x86/x86internal_p.h b/3rdparty/asmjit/src/asmjit/x86/x86internal_p.h index a1b76963f2a..d4ea8e1f9bf 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86internal_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86internal_p.h @@ -43,10 +43,10 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! X86 utilities used at multiple places, not part of public API, not exported. struct X86Internal { //! Initialize `FuncDetail` (X86 specific). - static Error initFuncDetail(FuncDetail& func, const FuncSignature& sign, uint32_t gpSize) noexcept; + static Error initFuncDetail(FuncDetail& func, const FuncSignature& signature, uint32_t registerSize) noexcept; //! Initialize `FuncFrame` (X86 specific). - static Error initFuncFrame(FuncFrame& frame, const FuncDetail& func) noexcept; + static Error initFuncFrame(FuncFrame& frame, const FuncDetail& signature) noexcept; //! Finalize `FuncFrame` (X86 specific). static Error finalizeFuncFrame(FuncFrame& frame) noexcept; diff --git a/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h b/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h index 69cafe5be7c..164b26c1dea 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h @@ -24,8 +24,6 @@ #ifndef ASMJIT_X86_X86OPCODE_P_H_INCLUDED #define ASMJIT_X86_X86OPCODE_P_H_INCLUDED -#include "../core/logging.h" -#include "../core/string.h" #include "../x86/x86globals.h" ASMJIT_BEGIN_SUB_NAMESPACE(x86) diff --git a/3rdparty/asmjit/src/asmjit/x86/x86operand.h b/3rdparty/asmjit/src/asmjit/x86/x86operand.h index 7e220214271..ccbe87e9ea3 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86operand.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86operand.h @@ -31,6 +31,58 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) +#define ASMJIT_MEM_PTR(FUNC, SIZE) \ + static constexpr Mem FUNC(const Gp& base, int32_t offset = 0) noexcept { \ + return Mem(base, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ + return Mem(base, index, shift, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Gp& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ + return Mem(base, index, shift, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Label& base, int32_t offset = 0) noexcept { \ + return Mem(base, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Label& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ + return Mem(base, index, shift, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Rip& rip_, int32_t offset = 0) noexcept { \ + return Mem(rip_, offset, SIZE); \ + } \ + static constexpr Mem FUNC(uint64_t base) noexcept { \ + return Mem(base, SIZE); \ + } \ + static constexpr Mem FUNC(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE); \ + } \ + static constexpr Mem FUNC(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE); \ + } \ + \ + static constexpr Mem FUNC##_abs(uint64_t base) noexcept { \ + return Mem(base, SIZE, BaseMem::kSignatureMemAbs); \ + } \ + static constexpr Mem FUNC##_abs(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemAbs); \ + } \ + static constexpr Mem FUNC##_abs(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemAbs); \ + } \ + \ + static constexpr Mem FUNC##_rel(uint64_t base) noexcept { \ + return Mem(base, SIZE, BaseMem::kSignatureMemRel); \ + } \ + static constexpr Mem FUNC##_rel(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemRel); \ + } \ + static constexpr Mem FUNC##_rel(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemRel); \ + } + +//! \addtogroup asmjit_x86 +//! \{ + // ============================================================================ // [Forward Declarations] // ============================================================================ @@ -58,11 +110,8 @@ class St; class Bnd; class Rip; -//! \addtogroup asmjit_x86 -//! \{ - // ============================================================================ -// [asmjit::x86::RegTraits] +// [asmjit::x86::Reg] // ============================================================================ //! Register traits (X86). @@ -96,10 +145,6 @@ ASMJIT_DEFINE_REG_TRAITS(Bnd , BaseReg::kTypeCustom + 4, BaseReg::kGroupVirt + ASMJIT_DEFINE_REG_TRAITS(Rip , BaseReg::kTypeIP , BaseReg::kGroupVirt + 5, 0 , 1 , Type::kIdVoid ); //! \endcond -// ============================================================================ -// [asmjit::x86::Reg] -// ============================================================================ - //! Register (X86). class Reg : public BaseReg { public: @@ -403,6 +448,303 @@ inline Ymm Vec::ymm() const noexcept { return Ymm(id()); } inline Zmm Vec::zmm() const noexcept { return Zmm(id()); } //! \endcond +//! \namespace asmjit::x86::regs +//! +//! Registers provided by X86 and X64 ISAs are in both `asmjit::x86` and +//! `asmjit::x86::regs` namespaces so they can be included with using directive. +//! For example `using namespace asmjit::x86::regs` would include all registers, +//! but not other X86-specific API, whereas `using namespace asmjit::x86` would +//! include everything X86-specific. +#ifndef _DOXYGEN +namespace regs { +#endif + +//! Creates an 8-bit low GPB register operand. +static constexpr GpbLo gpb(uint32_t rId) noexcept { return GpbLo(rId); } +//! Creates an 8-bit low GPB register operand. +static constexpr GpbLo gpb_lo(uint32_t rId) noexcept { return GpbLo(rId); } +//! Creates an 8-bit high GPB register operand. +static constexpr GpbHi gpb_hi(uint32_t rId) noexcept { return GpbHi(rId); } +//! Creates a 16-bit GPW register operand. +static constexpr Gpw gpw(uint32_t rId) noexcept { return Gpw(rId); } +//! Creates a 32-bit GPD register operand. +static constexpr Gpd gpd(uint32_t rId) noexcept { return Gpd(rId); } +//! Creates a 64-bit GPQ register operand (64-bit). +static constexpr Gpq gpq(uint32_t rId) noexcept { return Gpq(rId); } +//! Creates a 128-bit XMM register operand. +static constexpr Xmm xmm(uint32_t rId) noexcept { return Xmm(rId); } +//! Creates a 256-bit YMM register operand. +static constexpr Ymm ymm(uint32_t rId) noexcept { return Ymm(rId); } +//! Creates a 512-bit ZMM register operand. +static constexpr Zmm zmm(uint32_t rId) noexcept { return Zmm(rId); } +//! Creates a 64-bit Mm register operand. +static constexpr Mm mm(uint32_t rId) noexcept { return Mm(rId); } +//! Creates a 64-bit K register operand. +static constexpr KReg k(uint32_t rId) noexcept { return KReg(rId); } +//! Creates a 32-bit or 64-bit control register operand. +static constexpr CReg cr(uint32_t rId) noexcept { return CReg(rId); } +//! Creates a 32-bit or 64-bit debug register operand. +static constexpr DReg dr(uint32_t rId) noexcept { return DReg(rId); } +//! Creates an 80-bit st register operand. +static constexpr St st(uint32_t rId) noexcept { return St(rId); } +//! Creates a 128-bit bound register operand. +static constexpr Bnd bnd(uint32_t rId) noexcept { return Bnd(rId); } + +static constexpr Gp al = Gp(GpbLo::kSignature, Gp::kIdAx); +static constexpr Gp bl = Gp(GpbLo::kSignature, Gp::kIdBx); +static constexpr Gp cl = Gp(GpbLo::kSignature, Gp::kIdCx); +static constexpr Gp dl = Gp(GpbLo::kSignature, Gp::kIdDx); +static constexpr Gp spl = Gp(GpbLo::kSignature, Gp::kIdSp); +static constexpr Gp bpl = Gp(GpbLo::kSignature, Gp::kIdBp); +static constexpr Gp sil = Gp(GpbLo::kSignature, Gp::kIdSi); +static constexpr Gp dil = Gp(GpbLo::kSignature, Gp::kIdDi); +static constexpr Gp r8b = Gp(GpbLo::kSignature, Gp::kIdR8); +static constexpr Gp r9b = Gp(GpbLo::kSignature, Gp::kIdR9); +static constexpr Gp r10b = Gp(GpbLo::kSignature, Gp::kIdR10); +static constexpr Gp r11b = Gp(GpbLo::kSignature, Gp::kIdR11); +static constexpr Gp r12b = Gp(GpbLo::kSignature, Gp::kIdR12); +static constexpr Gp r13b = Gp(GpbLo::kSignature, Gp::kIdR13); +static constexpr Gp r14b = Gp(GpbLo::kSignature, Gp::kIdR14); +static constexpr Gp r15b = Gp(GpbLo::kSignature, Gp::kIdR15); + +static constexpr Gp ah = Gp(GpbHi::kSignature, Gp::kIdAx); +static constexpr Gp bh = Gp(GpbHi::kSignature, Gp::kIdBx); +static constexpr Gp ch = Gp(GpbHi::kSignature, Gp::kIdCx); +static constexpr Gp dh = Gp(GpbHi::kSignature, Gp::kIdDx); + +static constexpr Gp ax = Gp(Gpw::kSignature, Gp::kIdAx); +static constexpr Gp bx = Gp(Gpw::kSignature, Gp::kIdBx); +static constexpr Gp cx = Gp(Gpw::kSignature, Gp::kIdCx); +static constexpr Gp dx = Gp(Gpw::kSignature, Gp::kIdDx); +static constexpr Gp sp = Gp(Gpw::kSignature, Gp::kIdSp); +static constexpr Gp bp = Gp(Gpw::kSignature, Gp::kIdBp); +static constexpr Gp si = Gp(Gpw::kSignature, Gp::kIdSi); +static constexpr Gp di = Gp(Gpw::kSignature, Gp::kIdDi); +static constexpr Gp r8w = Gp(Gpw::kSignature, Gp::kIdR8); +static constexpr Gp r9w = Gp(Gpw::kSignature, Gp::kIdR9); +static constexpr Gp r10w = Gp(Gpw::kSignature, Gp::kIdR10); +static constexpr Gp r11w = Gp(Gpw::kSignature, Gp::kIdR11); +static constexpr Gp r12w = Gp(Gpw::kSignature, Gp::kIdR12); +static constexpr Gp r13w = Gp(Gpw::kSignature, Gp::kIdR13); +static constexpr Gp r14w = Gp(Gpw::kSignature, Gp::kIdR14); +static constexpr Gp r15w = Gp(Gpw::kSignature, Gp::kIdR15); + +static constexpr Gp eax = Gp(Gpd::kSignature, Gp::kIdAx); +static constexpr Gp ebx = Gp(Gpd::kSignature, Gp::kIdBx); +static constexpr Gp ecx = Gp(Gpd::kSignature, Gp::kIdCx); +static constexpr Gp edx = Gp(Gpd::kSignature, Gp::kIdDx); +static constexpr Gp esp = Gp(Gpd::kSignature, Gp::kIdSp); +static constexpr Gp ebp = Gp(Gpd::kSignature, Gp::kIdBp); +static constexpr Gp esi = Gp(Gpd::kSignature, Gp::kIdSi); +static constexpr Gp edi = Gp(Gpd::kSignature, Gp::kIdDi); +static constexpr Gp r8d = Gp(Gpd::kSignature, Gp::kIdR8); +static constexpr Gp r9d = Gp(Gpd::kSignature, Gp::kIdR9); +static constexpr Gp r10d = Gp(Gpd::kSignature, Gp::kIdR10); +static constexpr Gp r11d = Gp(Gpd::kSignature, Gp::kIdR11); +static constexpr Gp r12d = Gp(Gpd::kSignature, Gp::kIdR12); +static constexpr Gp r13d = Gp(Gpd::kSignature, Gp::kIdR13); +static constexpr Gp r14d = Gp(Gpd::kSignature, Gp::kIdR14); +static constexpr Gp r15d = Gp(Gpd::kSignature, Gp::kIdR15); + +static constexpr Gp rax = Gp(Gpq::kSignature, Gp::kIdAx); +static constexpr Gp rbx = Gp(Gpq::kSignature, Gp::kIdBx); +static constexpr Gp rcx = Gp(Gpq::kSignature, Gp::kIdCx); +static constexpr Gp rdx = Gp(Gpq::kSignature, Gp::kIdDx); +static constexpr Gp rsp = Gp(Gpq::kSignature, Gp::kIdSp); +static constexpr Gp rbp = Gp(Gpq::kSignature, Gp::kIdBp); +static constexpr Gp rsi = Gp(Gpq::kSignature, Gp::kIdSi); +static constexpr Gp rdi = Gp(Gpq::kSignature, Gp::kIdDi); +static constexpr Gp r8 = Gp(Gpq::kSignature, Gp::kIdR8); +static constexpr Gp r9 = Gp(Gpq::kSignature, Gp::kIdR9); +static constexpr Gp r10 = Gp(Gpq::kSignature, Gp::kIdR10); +static constexpr Gp r11 = Gp(Gpq::kSignature, Gp::kIdR11); +static constexpr Gp r12 = Gp(Gpq::kSignature, Gp::kIdR12); +static constexpr Gp r13 = Gp(Gpq::kSignature, Gp::kIdR13); +static constexpr Gp r14 = Gp(Gpq::kSignature, Gp::kIdR14); +static constexpr Gp r15 = Gp(Gpq::kSignature, Gp::kIdR15); + +static constexpr Xmm xmm0 = Xmm(0); +static constexpr Xmm xmm1 = Xmm(1); +static constexpr Xmm xmm2 = Xmm(2); +static constexpr Xmm xmm3 = Xmm(3); +static constexpr Xmm xmm4 = Xmm(4); +static constexpr Xmm xmm5 = Xmm(5); +static constexpr Xmm xmm6 = Xmm(6); +static constexpr Xmm xmm7 = Xmm(7); +static constexpr Xmm xmm8 = Xmm(8); +static constexpr Xmm xmm9 = Xmm(9); +static constexpr Xmm xmm10 = Xmm(10); +static constexpr Xmm xmm11 = Xmm(11); +static constexpr Xmm xmm12 = Xmm(12); +static constexpr Xmm xmm13 = Xmm(13); +static constexpr Xmm xmm14 = Xmm(14); +static constexpr Xmm xmm15 = Xmm(15); +static constexpr Xmm xmm16 = Xmm(16); +static constexpr Xmm xmm17 = Xmm(17); +static constexpr Xmm xmm18 = Xmm(18); +static constexpr Xmm xmm19 = Xmm(19); +static constexpr Xmm xmm20 = Xmm(20); +static constexpr Xmm xmm21 = Xmm(21); +static constexpr Xmm xmm22 = Xmm(22); +static constexpr Xmm xmm23 = Xmm(23); +static constexpr Xmm xmm24 = Xmm(24); +static constexpr Xmm xmm25 = Xmm(25); +static constexpr Xmm xmm26 = Xmm(26); +static constexpr Xmm xmm27 = Xmm(27); +static constexpr Xmm xmm28 = Xmm(28); +static constexpr Xmm xmm29 = Xmm(29); +static constexpr Xmm xmm30 = Xmm(30); +static constexpr Xmm xmm31 = Xmm(31); + +static constexpr Ymm ymm0 = Ymm(0); +static constexpr Ymm ymm1 = Ymm(1); +static constexpr Ymm ymm2 = Ymm(2); +static constexpr Ymm ymm3 = Ymm(3); +static constexpr Ymm ymm4 = Ymm(4); +static constexpr Ymm ymm5 = Ymm(5); +static constexpr Ymm ymm6 = Ymm(6); +static constexpr Ymm ymm7 = Ymm(7); +static constexpr Ymm ymm8 = Ymm(8); +static constexpr Ymm ymm9 = Ymm(9); +static constexpr Ymm ymm10 = Ymm(10); +static constexpr Ymm ymm11 = Ymm(11); +static constexpr Ymm ymm12 = Ymm(12); +static constexpr Ymm ymm13 = Ymm(13); +static constexpr Ymm ymm14 = Ymm(14); +static constexpr Ymm ymm15 = Ymm(15); +static constexpr Ymm ymm16 = Ymm(16); +static constexpr Ymm ymm17 = Ymm(17); +static constexpr Ymm ymm18 = Ymm(18); +static constexpr Ymm ymm19 = Ymm(19); +static constexpr Ymm ymm20 = Ymm(20); +static constexpr Ymm ymm21 = Ymm(21); +static constexpr Ymm ymm22 = Ymm(22); +static constexpr Ymm ymm23 = Ymm(23); +static constexpr Ymm ymm24 = Ymm(24); +static constexpr Ymm ymm25 = Ymm(25); +static constexpr Ymm ymm26 = Ymm(26); +static constexpr Ymm ymm27 = Ymm(27); +static constexpr Ymm ymm28 = Ymm(28); +static constexpr Ymm ymm29 = Ymm(29); +static constexpr Ymm ymm30 = Ymm(30); +static constexpr Ymm ymm31 = Ymm(31); + +static constexpr Zmm zmm0 = Zmm(0); +static constexpr Zmm zmm1 = Zmm(1); +static constexpr Zmm zmm2 = Zmm(2); +static constexpr Zmm zmm3 = Zmm(3); +static constexpr Zmm zmm4 = Zmm(4); +static constexpr Zmm zmm5 = Zmm(5); +static constexpr Zmm zmm6 = Zmm(6); +static constexpr Zmm zmm7 = Zmm(7); +static constexpr Zmm zmm8 = Zmm(8); +static constexpr Zmm zmm9 = Zmm(9); +static constexpr Zmm zmm10 = Zmm(10); +static constexpr Zmm zmm11 = Zmm(11); +static constexpr Zmm zmm12 = Zmm(12); +static constexpr Zmm zmm13 = Zmm(13); +static constexpr Zmm zmm14 = Zmm(14); +static constexpr Zmm zmm15 = Zmm(15); +static constexpr Zmm zmm16 = Zmm(16); +static constexpr Zmm zmm17 = Zmm(17); +static constexpr Zmm zmm18 = Zmm(18); +static constexpr Zmm zmm19 = Zmm(19); +static constexpr Zmm zmm20 = Zmm(20); +static constexpr Zmm zmm21 = Zmm(21); +static constexpr Zmm zmm22 = Zmm(22); +static constexpr Zmm zmm23 = Zmm(23); +static constexpr Zmm zmm24 = Zmm(24); +static constexpr Zmm zmm25 = Zmm(25); +static constexpr Zmm zmm26 = Zmm(26); +static constexpr Zmm zmm27 = Zmm(27); +static constexpr Zmm zmm28 = Zmm(28); +static constexpr Zmm zmm29 = Zmm(29); +static constexpr Zmm zmm30 = Zmm(30); +static constexpr Zmm zmm31 = Zmm(31); + +static constexpr Mm mm0 = Mm(0); +static constexpr Mm mm1 = Mm(1); +static constexpr Mm mm2 = Mm(2); +static constexpr Mm mm3 = Mm(3); +static constexpr Mm mm4 = Mm(4); +static constexpr Mm mm5 = Mm(5); +static constexpr Mm mm6 = Mm(6); +static constexpr Mm mm7 = Mm(7); + +static constexpr KReg k0 = KReg(0); +static constexpr KReg k1 = KReg(1); +static constexpr KReg k2 = KReg(2); +static constexpr KReg k3 = KReg(3); +static constexpr KReg k4 = KReg(4); +static constexpr KReg k5 = KReg(5); +static constexpr KReg k6 = KReg(6); +static constexpr KReg k7 = KReg(7); + +static constexpr SReg no_seg = SReg(SReg::kIdNone); +static constexpr SReg es = SReg(SReg::kIdEs); +static constexpr SReg cs = SReg(SReg::kIdCs); +static constexpr SReg ss = SReg(SReg::kIdSs); +static constexpr SReg ds = SReg(SReg::kIdDs); +static constexpr SReg fs = SReg(SReg::kIdFs); +static constexpr SReg gs = SReg(SReg::kIdGs); + +static constexpr CReg cr0 = CReg(0); +static constexpr CReg cr1 = CReg(1); +static constexpr CReg cr2 = CReg(2); +static constexpr CReg cr3 = CReg(3); +static constexpr CReg cr4 = CReg(4); +static constexpr CReg cr5 = CReg(5); +static constexpr CReg cr6 = CReg(6); +static constexpr CReg cr7 = CReg(7); +static constexpr CReg cr8 = CReg(8); +static constexpr CReg cr9 = CReg(9); +static constexpr CReg cr10 = CReg(10); +static constexpr CReg cr11 = CReg(11); +static constexpr CReg cr12 = CReg(12); +static constexpr CReg cr13 = CReg(13); +static constexpr CReg cr14 = CReg(14); +static constexpr CReg cr15 = CReg(15); + +static constexpr DReg dr0 = DReg(0); +static constexpr DReg dr1 = DReg(1); +static constexpr DReg dr2 = DReg(2); +static constexpr DReg dr3 = DReg(3); +static constexpr DReg dr4 = DReg(4); +static constexpr DReg dr5 = DReg(5); +static constexpr DReg dr6 = DReg(6); +static constexpr DReg dr7 = DReg(7); +static constexpr DReg dr8 = DReg(8); +static constexpr DReg dr9 = DReg(9); +static constexpr DReg dr10 = DReg(10); +static constexpr DReg dr11 = DReg(11); +static constexpr DReg dr12 = DReg(12); +static constexpr DReg dr13 = DReg(13); +static constexpr DReg dr14 = DReg(14); +static constexpr DReg dr15 = DReg(15); + +static constexpr St st0 = St(0); +static constexpr St st1 = St(1); +static constexpr St st2 = St(2); +static constexpr St st3 = St(3); +static constexpr St st4 = St(4); +static constexpr St st5 = St(5); +static constexpr St st6 = St(6); +static constexpr St st7 = St(7); + +static constexpr Bnd bnd0 = Bnd(0); +static constexpr Bnd bnd1 = Bnd(1); +static constexpr Bnd bnd2 = Bnd(2); +static constexpr Bnd bnd3 = Bnd(3); + +static constexpr Rip rip = Rip(0); + +#ifndef _DOXYGEN +} // {regs} + +// Make `x86::regs` accessible through `x86` namespace as well. +using namespace regs; +#endif + // ============================================================================ // [asmjit::x86::Mem] // ============================================================================ @@ -552,328 +894,6 @@ public: inline Mem& operator=(const Mem& other) noexcept = default; }; -// ============================================================================ -// [asmjit::x86::OpData] -// ============================================================================ - -struct OpData { - //! Information about all architecture registers. - ArchRegs archRegs; -}; -ASMJIT_VARAPI const OpData opData; - -//! \cond -// ... Reg methods that require `opData`. -inline uint32_t Reg::groupOf(uint32_t rType) noexcept { - ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); - return opData.archRegs.regInfo[rType].group(); -} - -inline uint32_t Reg::typeIdOf(uint32_t rType) noexcept { - ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); - return opData.archRegs.regTypeToTypeId[rType]; -} - -inline uint32_t Reg::signatureOf(uint32_t rType) noexcept { - ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); - return opData.archRegs.regInfo[rType].signature(); -} -//! \endcond - -// ============================================================================ -// [asmjit::x86::regs] -// ============================================================================ - -namespace regs { - -//! Creates an 8-bit low GPB register operand. -static constexpr GpbLo gpb(uint32_t rId) noexcept { return GpbLo(rId); } -//! Creates an 8-bit low GPB register operand. -static constexpr GpbLo gpb_lo(uint32_t rId) noexcept { return GpbLo(rId); } -//! Creates an 8-bit high GPB register operand. -static constexpr GpbHi gpb_hi(uint32_t rId) noexcept { return GpbHi(rId); } -//! Creates a 16-bit GPW register operand. -static constexpr Gpw gpw(uint32_t rId) noexcept { return Gpw(rId); } -//! Creates a 32-bit GPD register operand. -static constexpr Gpd gpd(uint32_t rId) noexcept { return Gpd(rId); } -//! Creates a 64-bit GPQ register operand (64-bit). -static constexpr Gpq gpq(uint32_t rId) noexcept { return Gpq(rId); } -//! Creates a 128-bit XMM register operand. -static constexpr Xmm xmm(uint32_t rId) noexcept { return Xmm(rId); } -//! Creates a 256-bit YMM register operand. -static constexpr Ymm ymm(uint32_t rId) noexcept { return Ymm(rId); } -//! Creates a 512-bit ZMM register operand. -static constexpr Zmm zmm(uint32_t rId) noexcept { return Zmm(rId); } -//! Creates a 64-bit Mm register operand. -static constexpr Mm mm(uint32_t rId) noexcept { return Mm(rId); } -//! Creates a 64-bit K register operand. -static constexpr KReg k(uint32_t rId) noexcept { return KReg(rId); } -//! Creates a 32-bit or 64-bit control register operand. -static constexpr CReg cr(uint32_t rId) noexcept { return CReg(rId); } -//! Creates a 32-bit or 64-bit debug register operand. -static constexpr DReg dr(uint32_t rId) noexcept { return DReg(rId); } -//! Creates an 80-bit st register operand. -static constexpr St st(uint32_t rId) noexcept { return St(rId); } -//! Creates a 128-bit bound register operand. -static constexpr Bnd bnd(uint32_t rId) noexcept { return Bnd(rId); } - -static constexpr Gp al(GpbLo::kSignature, Gp::kIdAx); -static constexpr Gp bl(GpbLo::kSignature, Gp::kIdBx); -static constexpr Gp cl(GpbLo::kSignature, Gp::kIdCx); -static constexpr Gp dl(GpbLo::kSignature, Gp::kIdDx); -static constexpr Gp spl(GpbLo::kSignature, Gp::kIdSp); -static constexpr Gp bpl(GpbLo::kSignature, Gp::kIdBp); -static constexpr Gp sil(GpbLo::kSignature, Gp::kIdSi); -static constexpr Gp dil(GpbLo::kSignature, Gp::kIdDi); -static constexpr Gp r8b(GpbLo::kSignature, Gp::kIdR8); -static constexpr Gp r9b(GpbLo::kSignature, Gp::kIdR9); -static constexpr Gp r10b(GpbLo::kSignature, Gp::kIdR10); -static constexpr Gp r11b(GpbLo::kSignature, Gp::kIdR11); -static constexpr Gp r12b(GpbLo::kSignature, Gp::kIdR12); -static constexpr Gp r13b(GpbLo::kSignature, Gp::kIdR13); -static constexpr Gp r14b(GpbLo::kSignature, Gp::kIdR14); -static constexpr Gp r15b(GpbLo::kSignature, Gp::kIdR15); - -static constexpr Gp ah(GpbHi::kSignature, Gp::kIdAx); -static constexpr Gp bh(GpbHi::kSignature, Gp::kIdBx); -static constexpr Gp ch(GpbHi::kSignature, Gp::kIdCx); -static constexpr Gp dh(GpbHi::kSignature, Gp::kIdDx); - -static constexpr Gp ax(Gpw::kSignature, Gp::kIdAx); -static constexpr Gp bx(Gpw::kSignature, Gp::kIdBx); -static constexpr Gp cx(Gpw::kSignature, Gp::kIdCx); -static constexpr Gp dx(Gpw::kSignature, Gp::kIdDx); -static constexpr Gp sp(Gpw::kSignature, Gp::kIdSp); -static constexpr Gp bp(Gpw::kSignature, Gp::kIdBp); -static constexpr Gp si(Gpw::kSignature, Gp::kIdSi); -static constexpr Gp di(Gpw::kSignature, Gp::kIdDi); -static constexpr Gp r8w(Gpw::kSignature, Gp::kIdR8); -static constexpr Gp r9w(Gpw::kSignature, Gp::kIdR9); -static constexpr Gp r10w(Gpw::kSignature, Gp::kIdR10); -static constexpr Gp r11w(Gpw::kSignature, Gp::kIdR11); -static constexpr Gp r12w(Gpw::kSignature, Gp::kIdR12); -static constexpr Gp r13w(Gpw::kSignature, Gp::kIdR13); -static constexpr Gp r14w(Gpw::kSignature, Gp::kIdR14); -static constexpr Gp r15w(Gpw::kSignature, Gp::kIdR15); - -static constexpr Gp eax(Gpd::kSignature, Gp::kIdAx); -static constexpr Gp ebx(Gpd::kSignature, Gp::kIdBx); -static constexpr Gp ecx(Gpd::kSignature, Gp::kIdCx); -static constexpr Gp edx(Gpd::kSignature, Gp::kIdDx); -static constexpr Gp esp(Gpd::kSignature, Gp::kIdSp); -static constexpr Gp ebp(Gpd::kSignature, Gp::kIdBp); -static constexpr Gp esi(Gpd::kSignature, Gp::kIdSi); -static constexpr Gp edi(Gpd::kSignature, Gp::kIdDi); -static constexpr Gp r8d(Gpd::kSignature, Gp::kIdR8); -static constexpr Gp r9d(Gpd::kSignature, Gp::kIdR9); -static constexpr Gp r10d(Gpd::kSignature, Gp::kIdR10); -static constexpr Gp r11d(Gpd::kSignature, Gp::kIdR11); -static constexpr Gp r12d(Gpd::kSignature, Gp::kIdR12); -static constexpr Gp r13d(Gpd::kSignature, Gp::kIdR13); -static constexpr Gp r14d(Gpd::kSignature, Gp::kIdR14); -static constexpr Gp r15d(Gpd::kSignature, Gp::kIdR15); - -static constexpr Gp rax(Gpq::kSignature, Gp::kIdAx); -static constexpr Gp rbx(Gpq::kSignature, Gp::kIdBx); -static constexpr Gp rcx(Gpq::kSignature, Gp::kIdCx); -static constexpr Gp rdx(Gpq::kSignature, Gp::kIdDx); -static constexpr Gp rsp(Gpq::kSignature, Gp::kIdSp); -static constexpr Gp rbp(Gpq::kSignature, Gp::kIdBp); -static constexpr Gp rsi(Gpq::kSignature, Gp::kIdSi); -static constexpr Gp rdi(Gpq::kSignature, Gp::kIdDi); -static constexpr Gp r8(Gpq::kSignature, Gp::kIdR8); -static constexpr Gp r9(Gpq::kSignature, Gp::kIdR9); -static constexpr Gp r10(Gpq::kSignature, Gp::kIdR10); -static constexpr Gp r11(Gpq::kSignature, Gp::kIdR11); -static constexpr Gp r12(Gpq::kSignature, Gp::kIdR12); -static constexpr Gp r13(Gpq::kSignature, Gp::kIdR13); -static constexpr Gp r14(Gpq::kSignature, Gp::kIdR14); -static constexpr Gp r15(Gpq::kSignature, Gp::kIdR15); - -static constexpr Xmm xmm0(0); -static constexpr Xmm xmm1(1); -static constexpr Xmm xmm2(2); -static constexpr Xmm xmm3(3); -static constexpr Xmm xmm4(4); -static constexpr Xmm xmm5(5); -static constexpr Xmm xmm6(6); -static constexpr Xmm xmm7(7); -static constexpr Xmm xmm8(8); -static constexpr Xmm xmm9(9); -static constexpr Xmm xmm10(10); -static constexpr Xmm xmm11(11); -static constexpr Xmm xmm12(12); -static constexpr Xmm xmm13(13); -static constexpr Xmm xmm14(14); -static constexpr Xmm xmm15(15); -static constexpr Xmm xmm16(16); -static constexpr Xmm xmm17(17); -static constexpr Xmm xmm18(18); -static constexpr Xmm xmm19(19); -static constexpr Xmm xmm20(20); -static constexpr Xmm xmm21(21); -static constexpr Xmm xmm22(22); -static constexpr Xmm xmm23(23); -static constexpr Xmm xmm24(24); -static constexpr Xmm xmm25(25); -static constexpr Xmm xmm26(26); -static constexpr Xmm xmm27(27); -static constexpr Xmm xmm28(28); -static constexpr Xmm xmm29(29); -static constexpr Xmm xmm30(30); -static constexpr Xmm xmm31(31); - -static constexpr Ymm ymm0(0); -static constexpr Ymm ymm1(1); -static constexpr Ymm ymm2(2); -static constexpr Ymm ymm3(3); -static constexpr Ymm ymm4(4); -static constexpr Ymm ymm5(5); -static constexpr Ymm ymm6(6); -static constexpr Ymm ymm7(7); -static constexpr Ymm ymm8(8); -static constexpr Ymm ymm9(9); -static constexpr Ymm ymm10(10); -static constexpr Ymm ymm11(11); -static constexpr Ymm ymm12(12); -static constexpr Ymm ymm13(13); -static constexpr Ymm ymm14(14); -static constexpr Ymm ymm15(15); -static constexpr Ymm ymm16(16); -static constexpr Ymm ymm17(17); -static constexpr Ymm ymm18(18); -static constexpr Ymm ymm19(19); -static constexpr Ymm ymm20(20); -static constexpr Ymm ymm21(21); -static constexpr Ymm ymm22(22); -static constexpr Ymm ymm23(23); -static constexpr Ymm ymm24(24); -static constexpr Ymm ymm25(25); -static constexpr Ymm ymm26(26); -static constexpr Ymm ymm27(27); -static constexpr Ymm ymm28(28); -static constexpr Ymm ymm29(29); -static constexpr Ymm ymm30(30); -static constexpr Ymm ymm31(31); - -static constexpr Zmm zmm0(0); -static constexpr Zmm zmm1(1); -static constexpr Zmm zmm2(2); -static constexpr Zmm zmm3(3); -static constexpr Zmm zmm4(4); -static constexpr Zmm zmm5(5); -static constexpr Zmm zmm6(6); -static constexpr Zmm zmm7(7); -static constexpr Zmm zmm8(8); -static constexpr Zmm zmm9(9); -static constexpr Zmm zmm10(10); -static constexpr Zmm zmm11(11); -static constexpr Zmm zmm12(12); -static constexpr Zmm zmm13(13); -static constexpr Zmm zmm14(14); -static constexpr Zmm zmm15(15); -static constexpr Zmm zmm16(16); -static constexpr Zmm zmm17(17); -static constexpr Zmm zmm18(18); -static constexpr Zmm zmm19(19); -static constexpr Zmm zmm20(20); -static constexpr Zmm zmm21(21); -static constexpr Zmm zmm22(22); -static constexpr Zmm zmm23(23); -static constexpr Zmm zmm24(24); -static constexpr Zmm zmm25(25); -static constexpr Zmm zmm26(26); -static constexpr Zmm zmm27(27); -static constexpr Zmm zmm28(28); -static constexpr Zmm zmm29(29); -static constexpr Zmm zmm30(30); -static constexpr Zmm zmm31(31); - -static constexpr Mm mm0(0); -static constexpr Mm mm1(1); -static constexpr Mm mm2(2); -static constexpr Mm mm3(3); -static constexpr Mm mm4(4); -static constexpr Mm mm5(5); -static constexpr Mm mm6(6); -static constexpr Mm mm7(7); - -static constexpr KReg k0(0); -static constexpr KReg k1(1); -static constexpr KReg k2(2); -static constexpr KReg k3(3); -static constexpr KReg k4(4); -static constexpr KReg k5(5); -static constexpr KReg k6(6); -static constexpr KReg k7(7); - -static constexpr SReg no_seg(SReg::kIdNone); -static constexpr SReg es(SReg::kIdEs); -static constexpr SReg cs(SReg::kIdCs); -static constexpr SReg ss(SReg::kIdSs); -static constexpr SReg ds(SReg::kIdDs); -static constexpr SReg fs(SReg::kIdFs); -static constexpr SReg gs(SReg::kIdGs); - -static constexpr CReg cr0(0); -static constexpr CReg cr1(1); -static constexpr CReg cr2(2); -static constexpr CReg cr3(3); -static constexpr CReg cr4(4); -static constexpr CReg cr5(5); -static constexpr CReg cr6(6); -static constexpr CReg cr7(7); -static constexpr CReg cr8(8); -static constexpr CReg cr9(9); -static constexpr CReg cr10(10); -static constexpr CReg cr11(11); -static constexpr CReg cr12(12); -static constexpr CReg cr13(13); -static constexpr CReg cr14(14); -static constexpr CReg cr15(15); - -static constexpr DReg dr0(0); -static constexpr DReg dr1(1); -static constexpr DReg dr2(2); -static constexpr DReg dr3(3); -static constexpr DReg dr4(4); -static constexpr DReg dr5(5); -static constexpr DReg dr6(6); -static constexpr DReg dr7(7); -static constexpr DReg dr8(8); -static constexpr DReg dr9(9); -static constexpr DReg dr10(10); -static constexpr DReg dr11(11); -static constexpr DReg dr12(12); -static constexpr DReg dr13(13); -static constexpr DReg dr14(14); -static constexpr DReg dr15(15); - -static constexpr St st0(0); -static constexpr St st1(1); -static constexpr St st2(2); -static constexpr St st3(3); -static constexpr St st4(4); -static constexpr St st5(5); -static constexpr St st6(6); -static constexpr St st7(7); - -static constexpr Bnd bnd0(0); -static constexpr Bnd bnd1(1); -static constexpr Bnd bnd2(2); -static constexpr Bnd bnd3(3); - -static constexpr Rip rip(0); - -} // {regs} - -// Make `x86::regs` accessible through `x86` namespace as well. -using namespace regs; - -// ============================================================================ -// [asmjit::x86::ptr] -// ============================================================================ - //! Creates `[base.reg + offset]` memory operand. static constexpr Mem ptr(const Gp& base, int32_t offset = 0, uint32_t size = 0) noexcept { return Mem(base, offset, size); @@ -944,70 +964,6 @@ static constexpr Mem ptr_rel(uint64_t base, const Vec& index, uint32_t shift = 0 return Mem(base, index, shift, size, BaseMem::kSignatureMemRel); } -#define ASMJIT_MEM_PTR(FUNC, SIZE) \ - /*! Creates `[base + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Gp& base, int32_t offset = 0) noexcept { \ - return Mem(base, offset, SIZE); \ - } \ - /*! Creates `[base + (index << shift) + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ - return Mem(base, index, shift, offset, SIZE); \ - } \ - /*! Creates `[base + (vec_index << shift) + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Gp& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ - return Mem(base, index, shift, offset, SIZE); \ - } \ - /*! Creates `[base + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Label& base, int32_t offset = 0) noexcept { \ - return Mem(base, offset, SIZE); \ - } \ - /*! Creates `[base + (index << shift) + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Label& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ - return Mem(base, index, shift, offset, SIZE); \ - } \ - /*! Creates `[rip + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Rip& rip_, int32_t offset = 0) noexcept { \ - return Mem(rip_, offset, SIZE); \ - } \ - /*! Creates `[ptr]` memory operand. */ \ - static constexpr Mem FUNC(uint64_t base) noexcept { \ - return Mem(base, SIZE); \ - } \ - /*! Creates `[base + (index << shift) + offset]` memory operand. */ \ - static constexpr Mem FUNC(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE); \ - } \ - /*! Creates `[base + (vec_index << shift) + offset]` memory operand. */ \ - static constexpr Mem FUNC(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE); \ - } \ - \ - /*! Creates `[base + offset]` memory operand (absolute). */ \ - static constexpr Mem FUNC##_abs(uint64_t base) noexcept { \ - return Mem(base, SIZE, BaseMem::kSignatureMemAbs); \ - } \ - /*! Creates `[base + (index << shift) + offset]` memory operand (absolute). */ \ - static constexpr Mem FUNC##_abs(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemAbs); \ - } \ - /*! Creates `[base + (vec_index << shift) + offset]` memory operand (absolute). */ \ - static constexpr Mem FUNC##_abs(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemAbs); \ - } \ - \ - /*! Creates `[base + offset]` memory operand (relative). */ \ - static constexpr Mem FUNC##_rel(uint64_t base) noexcept { \ - return Mem(base, SIZE, BaseMem::kSignatureMemRel); \ - } \ - /*! Creates `[base + (index << shift) + offset]` memory operand (relative). */ \ - static constexpr Mem FUNC##_rel(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemRel); \ - } \ - /*! Creates `[base + (vec_index << shift) + offset]` memory operand (relative). */ \ - static constexpr Mem FUNC##_rel(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemRel); \ - } - // Definition of memory operand constructors that use platform independent naming. ASMJIT_MEM_PTR(ptr_8, 1) ASMJIT_MEM_PTR(ptr_16, 2) @@ -1032,7 +988,33 @@ ASMJIT_MEM_PTR(xmmword_ptr, 16) ASMJIT_MEM_PTR(ymmword_ptr, 32) ASMJIT_MEM_PTR(zmmword_ptr, 64) -#undef ASMJIT_MEM_PTR +// ============================================================================ +// [asmjit::x86::OpData] +// ============================================================================ + +struct OpData { + //! Information about all architecture registers. + ArchRegs archRegs; +}; +ASMJIT_VARAPI const OpData opData; + +//! \cond +// ... Reg methods that require `opData`. +inline uint32_t Reg::groupOf(uint32_t rType) noexcept { + ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); + return opData.archRegs.regInfo[rType].group(); +} + +inline uint32_t Reg::typeIdOf(uint32_t rType) noexcept { + ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); + return opData.archRegs.regTypeToTypeId[rType]; +} + +inline uint32_t Reg::signatureOf(uint32_t rType) noexcept { + ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); + return opData.archRegs.regInfo[rType].signature(); +} +//! \endcond //! \} @@ -1043,7 +1025,6 @@ ASMJIT_END_SUB_NAMESPACE // ============================================================================ //! \cond INTERNAL - ASMJIT_BEGIN_NAMESPACE ASMJIT_DEFINE_TYPE_ID(x86::Gpb, kIdI8); ASMJIT_DEFINE_TYPE_ID(x86::Gpw, kIdI16); @@ -1054,7 +1035,8 @@ ASMJIT_DEFINE_TYPE_ID(x86::Xmm, kIdI32x4); ASMJIT_DEFINE_TYPE_ID(x86::Ymm, kIdI32x8); ASMJIT_DEFINE_TYPE_ID(x86::Zmm, kIdI32x16); ASMJIT_END_NAMESPACE - //! \endcond +#undef ASMJIT_MEM_PTR + #endif // ASMJIT_X86_X86OPERAND_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/x86/x86rapass.cpp b/3rdparty/asmjit/src/asmjit/x86/x86rapass.cpp index cd6ebb5d6d5..6cbb0064388 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86rapass.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86rapass.cpp @@ -91,14 +91,14 @@ static ASMJIT_INLINE uint32_t raMemIndexRwFlags(uint32_t flags) noexcept { class X86RACFGBuilder : public RACFGBuilder<X86RACFGBuilder> { public: - uint32_t _archId; + uint32_t _arch; bool _is64Bit; bool _avxEnabled; inline X86RACFGBuilder(X86RAPass* pass) noexcept : RACFGBuilder<X86RACFGBuilder>(pass), - _archId(pass->cc()->archId()), - _is64Bit(pass->gpSize() == 8), + _arch(pass->cc()->arch()), + _is64Bit(pass->registerSize() == 8), _avxEnabled(pass->_avxEnabled) { } @@ -110,12 +110,13 @@ public: Error onInst(InstNode* inst, uint32_t& controlType, RAInstBuilder& ib) noexcept; - Error onBeforeCall(FuncCallNode* call) noexcept; - Error onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept; + Error onBeforeInvoke(InvokeNode* invokeNode) noexcept; + Error onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept; - Error moveImmToRegArg(FuncCallNode* call, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept; - Error moveImmToStackArg(FuncCallNode* call, const FuncValue& arg, const Imm& imm_) noexcept; - Error moveRegToStackArg(FuncCallNode* call, const FuncValue& arg, const BaseReg& reg) noexcept; + Error moveVecToPtr(InvokeNode* invokeNode, const FuncValue& arg, const Vec& src, BaseReg* out) noexcept; + Error moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept; + Error moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept; + Error moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept; Error onBeforeRet(FuncRetNode* funcRet) noexcept; Error onRet(FuncRetNode* funcRet, RAInstBuilder& ib) noexcept; @@ -132,7 +133,7 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild if (Inst::isDefinedId(instId)) { uint32_t opCount = inst->opCount(); const Operand* opArray = inst->operands(); - ASMJIT_PROPAGATE(InstInternal::queryRWInfo(_archId, inst->baseInst(), opArray, opCount, rwInfo)); + ASMJIT_PROPAGATE(InstInternal::queryRWInfo(_arch, inst->baseInst(), opArray, opCount, &rwInfo)); const InstDB::InstInfo& instInfo = InstDB::infoById(instId); bool hasGpbHiConstraint = false; @@ -343,10 +344,10 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild if (singleRegOps == opCount) { singleRegCase = instInfo.singleRegCase(); } - else if (opCount == 2 && inst->opType(1).isImm()) { + else if (opCount == 2 && inst->op(1).isImm()) { // Handle some tricks used by X86 asm. - const BaseReg& reg = inst->opType(0).as<BaseReg>(); - const Imm& imm = inst->opType(1).as<Imm>(); + const BaseReg& reg = inst->op(0).as<BaseReg>(); + const Imm& imm = inst->op(1).as<Imm>(); const RAWorkReg* workReg = _pass->workRegById(ib[0]->workId()); uint32_t workRegSize = workReg->info().size(); @@ -355,7 +356,7 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild case Inst::kIdOr: { // Sets the value of the destination register to -1, previous content unused. if (reg.size() >= 4 || reg.size() >= workRegSize) { - if (imm.i64() == -1 || imm.u64() == raImmMaskFromSize(reg.size())) + if (imm.value() == -1 || imm.valueAs<uint64_t>() == raImmMaskFromSize(reg.size())) singleRegCase = InstDB::kSingleRegWO; } ASMJIT_FALLTHROUGH; @@ -372,7 +373,7 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild case Inst::kIdXor: { // Updates [E|R]FLAGS without changing the content. if (reg.size() != 4 || reg.size() >= workRegSize) { - if (imm.u64() == 0) + if (imm.value() == 0) singleRegCase = InstDB::kSingleRegRO; } break; @@ -402,20 +403,23 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild // [asmjit::x86::X86RACFGBuilder - OnCall] // ============================================================================ -Error X86RACFGBuilder::onBeforeCall(FuncCallNode* call) noexcept { - uint32_t argCount = call->argCount(); - uint32_t retCount = call->retCount(); - const FuncDetail& fd = call->detail(); +Error X86RACFGBuilder::onBeforeInvoke(InvokeNode* invokeNode) noexcept { + uint32_t argCount = invokeNode->argCount(); + uint32_t retCount = invokeNode->retCount(); + const FuncDetail& fd = invokeNode->detail(); - cc()->_setCursor(call->prev()); + cc()->_setCursor(invokeNode->prev()); - for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { - for (uint32_t argHi = 0; argHi <= kFuncArgHi; argHi += kFuncArgHi) { - if (!fd.hasArg(argIndex + argHi)) + uint32_t nativeRegType = cc()->_gpRegInfo.type(); + + for (uint32_t loIndex = 0; loIndex < argCount; loIndex++) { + for (uint32_t hiIndex = 0; hiIndex <= kFuncArgHi; hiIndex += kFuncArgHi) { + uint32_t argIndex = loIndex + hiIndex; + if (!fd.hasArg(argIndex)) continue; - const FuncValue& arg = fd.arg(argIndex + argHi); - const Operand& op = call->arg(argIndex + argHi); + const FuncValue& arg = fd.arg(argIndex); + const Operand& op = invokeNode->arg(argIndex); if (op.isNone()) continue; @@ -429,35 +433,64 @@ Error X86RACFGBuilder::onBeforeCall(FuncCallNode* call) noexcept { uint32_t regGroup = workReg->group(); uint32_t argGroup = Reg::groupOf(arg.regType()); - if (regGroup != argGroup) { - // TODO: - ASMJIT_ASSERT(false); + if (arg.isIndirect()) { + if (reg.isGp()) { + if (reg.type() != nativeRegType) + return DebugUtils::errored(kErrorInvalidAssignment); + // It's considered allocated if this is an indirect argument and the user used GP. + continue; + } + + BaseReg indirectReg; + moveVecToPtr(invokeNode, arg, reg.as<Vec>(), &indirectReg); + invokeNode->_args[argIndex] = indirectReg; + } + else { + if (regGroup != argGroup) { + // TODO: Conversion is not supported. + return DebugUtils::errored(kErrorInvalidAssignment); + } } } else { - ASMJIT_PROPAGATE(moveRegToStackArg(call, arg, op.as<BaseReg>())); + if (arg.isIndirect()) { + if (reg.isGp()) { + if (reg.type() != nativeRegType) + return DebugUtils::errored(kErrorInvalidAssignment); + + ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, reg)); + continue; + } + + BaseReg indirectReg; + moveVecToPtr(invokeNode, arg, reg.as<Vec>(), &indirectReg); + ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, indirectReg)); + } + else { + ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, reg)); + } } } else if (op.isImm()) { if (arg.isReg()) { BaseReg reg; - ASMJIT_PROPAGATE(moveImmToRegArg(call, arg, op.as<Imm>(), ®)); - call->_args[argIndex + argHi] = reg; + ASMJIT_PROPAGATE(moveImmToRegArg(invokeNode, arg, op.as<Imm>(), ®)); + invokeNode->_args[argIndex] = reg; } else { - ASMJIT_PROPAGATE(moveImmToStackArg(call, arg, op.as<Imm>())); + ASMJIT_PROPAGATE(moveImmToStackArg(invokeNode, arg, op.as<Imm>())); } } } } - cc()->_setCursor(call); + cc()->_setCursor(invokeNode); if (fd.hasFlag(CallConv::kFlagCalleePopsStack)) ASMJIT_PROPAGATE(cc()->sub(cc()->zsp(), fd.argStackSize())); for (uint32_t retIndex = 0; retIndex < retCount; retIndex++) { const FuncValue& ret = fd.ret(retIndex); - const Operand& op = call->ret(retIndex); + const Operand& op = invokeNode->ret(retIndex); if (op.isReg()) { const Reg& reg = op.as<Reg>(); @@ -500,15 +533,15 @@ Error X86RACFGBuilder::onBeforeCall(FuncCallNode* call) noexcept { uint32_t retGroup = Reg::groupOf(ret.regType()); if (regGroup != retGroup) { - // TODO: - ASMJIT_ASSERT(false); + // TODO: Conversion is not supported. + return DebugUtils::errored(kErrorInvalidAssignment); } } } } } - // This block has function call(s). + // This block has function invokeNode(s). _curBlock->addFlags(RABlock::kFlagHasFuncCalls); _pass->func()->frame().addAttributes(FuncFrame::kAttrHasFuncCalls); _pass->func()->frame().updateCallStackSize(fd.argStackSize()); @@ -516,10 +549,10 @@ Error X86RACFGBuilder::onBeforeCall(FuncCallNode* call) noexcept { return kErrorOk; } -Error X86RACFGBuilder::onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept { - uint32_t argCount = call->argCount(); - uint32_t retCount = call->retCount(); - const FuncDetail& fd = call->detail(); +Error X86RACFGBuilder::onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept { + uint32_t argCount = invokeNode->argCount(); + uint32_t retCount = invokeNode->retCount(); + const FuncDetail& fd = invokeNode->detail(); for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { for (uint32_t argHi = 0; argHi <= kFuncArgHi; argHi += kFuncArgHi) { @@ -527,7 +560,7 @@ Error X86RACFGBuilder::onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept { continue; const FuncValue& arg = fd.arg(argIndex + argHi); - const Operand& op = call->arg(argIndex + argHi); + const Operand& op = invokeNode->arg(argIndex + argHi); if (op.isNone()) continue; @@ -537,7 +570,13 @@ Error X86RACFGBuilder::onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept { RAWorkReg* workReg; ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(reg.id()), &workReg)); - if (arg.isReg()) { + if (arg.isIndirect()) { + uint32_t regGroup = workReg->group(); + if (regGroup != BaseReg::kGroupGp) + return DebugUtils::errored(kErrorInvalidState); + ASMJIT_PROPAGATE(ib.addCallArg(workReg, arg.regId())); + } + else if (arg.isReg()) { uint32_t regGroup = workReg->group(); uint32_t argGroup = Reg::groupOf(arg.regType()); @@ -551,7 +590,7 @@ Error X86RACFGBuilder::onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept { for (uint32_t retIndex = 0; retIndex < retCount; retIndex++) { const FuncValue& ret = fd.ret(retIndex); - const Operand& op = call->ret(retIndex); + const Operand& op = invokeNode->ret(retIndex); // Not handled here... if (ret.regType() == Reg::kTypeSt) @@ -586,11 +625,62 @@ Error X86RACFGBuilder::onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept { } // ============================================================================ +// [asmjit::x86::X86RACFGBuilder - MoveVecToPtr] +// ============================================================================ + +static uint32_t x86VecRegSignatureBySize(uint32_t size) noexcept { + if (size >= 64) + return Zmm::kSignature; + else if (size >= 32) + return Ymm::kSignature; + else + return Xmm::kSignature; +} + +Error X86RACFGBuilder::moveVecToPtr(InvokeNode* invokeNode, const FuncValue& arg, const Vec& src, BaseReg* out) noexcept { + DebugUtils::unused(invokeNode); + ASMJIT_ASSERT(arg.isReg()); + + uint32_t argSize = Type::sizeOf(arg.typeId()); + if (argSize == 0) + return DebugUtils::errored(kErrorInvalidState); + + if (argSize < 16) + argSize = 16; + + uint32_t argStackOffset = Support::alignUp(invokeNode->detail()._argStackSize, argSize); + _funcNode->frame().updateCallStackAlignment(argSize); + invokeNode->detail()._argStackSize = argStackOffset + argSize; + + Vec vecReg(x86VecRegSignatureBySize(argSize), src.id()); + Mem vecPtr = ptr(_pass->_sp.as<Gp>(), int32_t(argStackOffset)); + + uint32_t vMovInstId = choose(Inst::kIdMovaps, Inst::kIdVmovaps); + if (argSize > 16) + vMovInstId = Inst::kIdVmovaps; + + ASMJIT_PROPAGATE(cc()->_newReg(out, cc()->_gpRegInfo.type(), nullptr)); + + VirtReg* vReg = cc()->virtRegById(out->id()); + vReg->setWeight(RAPass::kCallArgWeight); + + ASMJIT_PROPAGATE(cc()->lea(out->as<Gp>(), vecPtr)); + ASMJIT_PROPAGATE(cc()->emit(vMovInstId, ptr(out->as<Gp>()), vecReg)); + + if (arg.isStack()) { + Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset()); + ASMJIT_PROPAGATE(cc()->mov(stackPtr, out->as<Gp>())); + } + + return kErrorOk; +} + +// ============================================================================ // [asmjit::x86::X86RACFGBuilder - MoveImmToRegArg] // ============================================================================ -Error X86RACFGBuilder::moveImmToRegArg(FuncCallNode* call, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept { - DebugUtils::unused(call); +Error X86RACFGBuilder::moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept { + DebugUtils::unused(invokeNode); ASMJIT_ASSERT(arg.isReg()); Imm imm(imm_); @@ -620,10 +710,10 @@ MovU32: break; default: - return DebugUtils::errored(kErrorInvalidState); + return DebugUtils::errored(kErrorInvalidAssignment); } - ASMJIT_PROPAGATE(cc()->_newReg(*out, rTypeId, nullptr)); + ASMJIT_PROPAGATE(cc()->_newReg(out, rTypeId, nullptr)); cc()->virtRegById(out->id())->setWeight(RAPass::kCallArgWeight); return cc()->mov(out->as<x86::Gp>(), imm); @@ -633,14 +723,14 @@ MovU32: // [asmjit::x86::X86RACFGBuilder - MoveImmToStackArg] // ============================================================================ -Error X86RACFGBuilder::moveImmToStackArg(FuncCallNode* call, const FuncValue& arg, const Imm& imm_) noexcept { - DebugUtils::unused(call); +Error X86RACFGBuilder::moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept { + DebugUtils::unused(invokeNode); ASMJIT_ASSERT(arg.isStack()); - Mem mem = ptr(_pass->_sp.as<Gp>(), arg.stackOffset()); + Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset()); Imm imm[2]; - mem.setSize(4); + stackPtr.setSize(4); imm[0] = imm_; uint32_t nMovs = 0; @@ -669,23 +759,23 @@ MovU32: case Type::kIdMmx32: case Type::kIdMmx64: if (_is64Bit && imm[0].isInt32()) { - mem.setSize(8); + stackPtr.setSize(8); nMovs = 1; break; } - imm[1].setU32(imm[0].u32Hi()); + imm[1].setValue(imm[0].uint32Hi()); imm[0].zeroExtend32Bits(); nMovs = 2; break; default: - return DebugUtils::errored(kErrorInvalidState); + return DebugUtils::errored(kErrorInvalidAssignment); } for (uint32_t i = 0; i < nMovs; i++) { - ASMJIT_PROPAGATE(cc()->mov(mem, imm[i])); - mem.addOffsetLo32(int32_t(mem.size())); + ASMJIT_PROPAGATE(cc()->mov(stackPtr, imm[i])); + stackPtr.addOffsetLo32(int32_t(stackPtr.size())); } return kErrorOk; @@ -695,15 +785,15 @@ MovU32: // [asmjit::x86::X86RACFGBuilder - MoveRegToStackArg] // ============================================================================ -Error X86RACFGBuilder::moveRegToStackArg(FuncCallNode* call, const FuncValue& arg, const BaseReg& reg) noexcept { - DebugUtils::unused(call); +Error X86RACFGBuilder::moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept { + DebugUtils::unused(invokeNode); ASMJIT_ASSERT(arg.isStack()); - Mem mem = ptr(_pass->_sp.as<Gp>(), arg.stackOffset()); + Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset()); Reg r0, r1; VirtReg* vr = cc()->virtRegById(reg.id()); - uint32_t gpSize = cc()->gpSize(); + uint32_t registerSize = cc()->registerSize(); uint32_t instId = 0; uint32_t dstTypeId = arg.typeId(); @@ -812,75 +902,89 @@ Error X86RACFGBuilder::moveRegToStackArg(FuncCallNode* call, const FuncValue& ar break; default: - // TODO: Vector types by stack. + if (Type::isVec(dstTypeId) && reg.as<Reg>().isVec()) { + stackPtr.setSize(Type::sizeOf(dstTypeId)); + uint32_t vMovInstId = choose(Inst::kIdMovaps, Inst::kIdVmovaps); + + if (Type::isVec128(dstTypeId)) + r0.setRegT<Reg::kTypeXmm>(reg.id()); + else if (Type::isVec256(dstTypeId)) + r0.setRegT<Reg::kTypeYmm>(reg.id()); + else if (Type::isVec512(dstTypeId)) + r0.setRegT<Reg::kTypeZmm>(reg.id()); + else + break; + + return cc()->emit(vMovInstId, stackPtr, r0); + } break; } - return DebugUtils::errored(kErrorInvalidState); + return DebugUtils::errored(kErrorInvalidAssignment); // Extend+Move Gp. ExtendMovGpD: - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeGpd>(reg.id()); ASMJIT_PROPAGATE(cc()->emit(instId, r0, r1)); - ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, mem, r0)); + ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, stackPtr, r0)); return kErrorOk; ExtendMovGpXQ: - if (gpSize == 8) { - mem.setSize(8); + if (registerSize == 8) { + stackPtr.setSize(8); r0.setRegT<Reg::kTypeGpq>(reg.id()); ASMJIT_PROPAGATE(cc()->emit(instId, r0, r1)); - ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, mem, r0)); + ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, stackPtr, r0)); } else { - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeGpd>(reg.id()); ASMJIT_PROPAGATE(cc()->emit(instId, r0, r1)); ExtendMovGpDQ: - ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, mem, r0)); - mem.addOffsetLo32(4); - ASMJIT_PROPAGATE(cc()->emit(Inst::kIdAnd, mem, 0)); + ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, stackPtr, r0)); + stackPtr.addOffsetLo32(4); + ASMJIT_PROPAGATE(cc()->emit(Inst::kIdAnd, stackPtr, 0)); } return kErrorOk; ZeroExtendGpDQ: - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeGpd>(reg.id()); goto ExtendMovGpDQ; MovGpD: - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeGpd>(reg.id()); - return cc()->emit(Inst::kIdMov, mem, r0); + return cc()->emit(Inst::kIdMov, stackPtr, r0); MovGpQ: - mem.setSize(8); + stackPtr.setSize(8); r0.setRegT<Reg::kTypeGpq>(reg.id()); - return cc()->emit(Inst::kIdMov, mem, r0); + return cc()->emit(Inst::kIdMov, stackPtr, r0); MovMmD: - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeMm>(reg.id()); - return cc()->emit(choose(Inst::kIdMovd, Inst::kIdVmovd), mem, r0); + return cc()->emit(choose(Inst::kIdMovd, Inst::kIdVmovd), stackPtr, r0); MovMmQ: - mem.setSize(8); + stackPtr.setSize(8); r0.setRegT<Reg::kTypeMm>(reg.id()); - return cc()->emit(choose(Inst::kIdMovq, Inst::kIdVmovq), mem, r0); + return cc()->emit(choose(Inst::kIdMovq, Inst::kIdVmovq), stackPtr, r0); MovXmmD: - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeXmm>(reg.id()); - return cc()->emit(choose(Inst::kIdMovss, Inst::kIdVmovss), mem, r0); + return cc()->emit(choose(Inst::kIdMovss, Inst::kIdVmovss), stackPtr, r0); MovXmmQ: - mem.setSize(8); + stackPtr.setSize(8); r0.setRegT<Reg::kTypeXmm>(reg.id()); - return cc()->emit(choose(Inst::kIdMovlps, Inst::kIdVmovlps), mem, r0); + return cc()->emit(choose(Inst::kIdMovlps, Inst::kIdVmovlps), stackPtr, r0); } // ============================================================================ @@ -997,8 +1101,8 @@ X86RAPass::~X86RAPass() noexcept {} // ============================================================================ void X86RAPass::onInit() noexcept { - uint32_t archId = cc()->archId(); - uint32_t baseRegCount = archId == ArchInfo::kIdX86 ? 8u : 16u; + uint32_t arch = cc()->arch(); + uint32_t baseRegCount = Environment::is32Bit(arch) ? 8u : 16u; _archRegsInfo = &opData.archRegs; _archTraits[Reg::kGroupGp] |= RAArchTraits::kHasSwap; @@ -1117,13 +1221,13 @@ Error X86RAPass::onEmitJump(const Label& label) noexcept { return cc()->jmp(label); } -Error X86RAPass::onEmitPreCall(FuncCallNode* call) noexcept { - if (call->detail().hasVarArgs()) { - uint32_t argCount = call->argCount(); - const FuncDetail& fd = call->detail(); +Error X86RAPass::onEmitPreCall(InvokeNode* invokeNode) noexcept { + if (invokeNode->detail().hasVarArgs() && cc()->is64Bit()) { + uint32_t argCount = invokeNode->argCount(); + const FuncDetail& fd = invokeNode->detail(); - switch (call->detail().callConv().id()) { - case CallConv::kIdX86SysV64: { + switch (invokeNode->detail().callConv().id()) { + case CallConv::kIdX64SystemV: { // AL register contains the number of arguments passed in XMM register(s). uint32_t n = 0; for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { @@ -1144,7 +1248,7 @@ Error X86RAPass::onEmitPreCall(FuncCallNode* call) noexcept { break; } - case CallConv::kIdX86Win64: { + case CallConv::kIdX64Windows: { // Each double-precision argument passed in XMM must be also passed in GP. for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { for (uint32_t argHi = 0; argHi <= kFuncArgHi; argHi += kFuncArgHi) { @@ -1161,6 +1265,9 @@ Error X86RAPass::onEmitPreCall(FuncCallNode* call) noexcept { } break; } + + default: + return DebugUtils::errored(kErrorInvalidState); } } diff --git a/3rdparty/asmjit/src/asmjit/x86/x86rapass_p.h b/3rdparty/asmjit/src/asmjit/x86/x86rapass_p.h index 4fa688b41a3..99093ab69f8 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86rapass_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86rapass_p.h @@ -37,12 +37,9 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! \cond INTERNAL -//! \defgroup asmjit_x86_ra X86 RA -//! \ingroup asmjit_x86 -//! //! \brief X86/X64 register allocation. -//! \addtogroup asmjit_x86_ra +//! \addtogroup asmjit_ra //! \{ // ============================================================================ @@ -106,7 +103,7 @@ public: Error onEmitSave(uint32_t workId, uint32_t srcPhysId) noexcept override; Error onEmitJump(const Label& label) noexcept override; - Error onEmitPreCall(FuncCallNode* node) noexcept override; + Error onEmitPreCall(InvokeNode* invokeNode) noexcept override; }; //! \} |