asmjit 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/asmjit.gemspec +1 -1
- data/ext/asmjit/asmjit/.editorconfig +10 -0
- data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
- data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
- data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
- data/ext/asmjit/asmjit/.gitignore +6 -0
- data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
- data/ext/asmjit/asmjit/LICENSE.md +17 -0
- data/ext/asmjit/asmjit/README.md +69 -0
- data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
- data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
- data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
- data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
- data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
- data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
- data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
- data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
- data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
- data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
- data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
- data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
- data/ext/asmjit/asmjit/test/broken.cpp +312 -0
- data/ext/asmjit/asmjit/test/broken.h +148 -0
- data/ext/asmjit/asmjit/test/cmdline.h +61 -0
- data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
- data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
- data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
- data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
- data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
- data/ext/asmjit/asmjit.cc +18 -0
- data/lib/asmjit/version.rb +1 -1
- metadata +197 -2
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
// This file is part of AsmJit project <https://asmjit.com>
|
|
2
|
+
//
|
|
3
|
+
// See asmjit.h or LICENSE.md for license and copyright information
|
|
4
|
+
// SPDX-License-Identifier: Zlib
|
|
5
|
+
|
|
6
|
+
#ifndef ASMJIT_X86_X86OPCODE_P_H_INCLUDED
|
|
7
|
+
#define ASMJIT_X86_X86OPCODE_P_H_INCLUDED
|
|
8
|
+
|
|
9
|
+
#include "../x86/x86globals.h"
|
|
10
|
+
|
|
11
|
+
ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
|
12
|
+
|
|
13
|
+
//! \cond INTERNAL
|
|
14
|
+
//! \addtogroup asmjit_x86
|
|
15
|
+
//! \{
|
|
16
|
+
|
|
17
|
+
//! Helper class to store and manipulate X86 opcodes.
|
|
18
|
+
//!
|
|
19
|
+
//! The first 8 least significant bits describe the opcode byte as defined in ISA manuals, all other bits
|
|
20
|
+
//! describe other properties like prefixes, see `Opcode::Bits` for more information.
|
|
21
|
+
struct Opcode {
|
|
22
|
+
uint32_t v;
|
|
23
|
+
|
|
24
|
+
//! Describes a meaning of all bits of AsmJit's 32-bit opcode value.
|
|
25
|
+
//!
|
|
26
|
+
//! This schema is AsmJit specific and has been designed to allow encoding of all X86 instructions available. X86,
|
|
27
|
+
//! MMX, and SSE+ instructions always use `MM` and `PP` fields, which are encoded to corresponding prefixes needed
|
|
28
|
+
//! by X86 or SIMD instructions. AVX+ instructions embed `MMMMM` and `PP` fields in a VEX prefix, and AVX-512
|
|
29
|
+
//! instructions embed `MM` and `PP` in EVEX prefix.
|
|
30
|
+
//!
|
|
31
|
+
//! The instruction opcode definition uses 1 or 2 bytes as an opcode value. 1 byte is needed by most of the
|
|
32
|
+
//! instructions, 2 bytes are only used by legacy X87-FPU instructions. This means that a second byte is free to
|
|
33
|
+
//! by used by instructions encoded by using VEX and/or EVEX prefix.
|
|
34
|
+
//!
|
|
35
|
+
//! The fields description:
|
|
36
|
+
//!
|
|
37
|
+
//! - `MM` field is used to encode prefixes needed by the instruction or as a part of VEX/EVEX prefix. Described as
|
|
38
|
+
//! `mm` and `mmmmm` in instruction manuals.
|
|
39
|
+
//!
|
|
40
|
+
//! NOTE: Since `MM` field is defined as `mmmmm` (5 bits), but only 2 least significant bits are used by VEX and
|
|
41
|
+
//! EVEX prefixes, and additional 4th bit is used by XOP prefix, AsmJit uses the 3rd and 5th bit for it's own
|
|
42
|
+
//! purposes. These bits will probably never be used in future encodings as AVX512 uses only `000mm` from `mmmmm`.
|
|
43
|
+
//!
|
|
44
|
+
//! - `PP` field is used to encode prefixes needed by the instruction or as a part of VEX/EVEX prefix. Described as
|
|
45
|
+
//! `pp` in instruction manuals.
|
|
46
|
+
//!
|
|
47
|
+
//! - `LL` field is used exclusively by AVX+ and AVX512+ instruction sets. It describes vector size, which is `L.128`
|
|
48
|
+
//! for XMM register, `L.256` for for YMM register, and `L.512` for ZMM register. The `LL` field is omitted in case
|
|
49
|
+
//! that instruction supports multiple vector lengths, however, if the instruction requires specific `L` value it
|
|
50
|
+
//! must be specified as a part of the opcode.
|
|
51
|
+
//!
|
|
52
|
+
//! NOTE: `LL` having value `11` is not defined yet.
|
|
53
|
+
//!
|
|
54
|
+
//! - `W` field is the most complicated. It was added by 64-bit architecture to promote default operation width
|
|
55
|
+
//! (instructions that perform 32-bit operation by default require to override the width to 64-bit explicitly).
|
|
56
|
+
//! There is nothing wrong on this, however, some instructions introduced implicit `W` override, for example a
|
|
57
|
+
//! `cdqe` instruction is basically a `cwde` instruction with overridden `W` (set to 1). There are some others
|
|
58
|
+
//! in the base X86 instruction set. More recent instruction sets started using `W` field more often:
|
|
59
|
+
//!
|
|
60
|
+
//! - AVX instructions started using `W` field as an extended opcode for FMA, GATHER, PERM, and other instructions.
|
|
61
|
+
//! It also uses `W` field to override the default operation width in instructions like `vmovq`.
|
|
62
|
+
//!
|
|
63
|
+
//! - AVX-512 instructions started using `W` field as an extended opcode for all new instructions. This wouldn't
|
|
64
|
+
//! have been an issue if the `W` field of AVX-512 have matched AVX, but this is not always the case.
|
|
65
|
+
//!
|
|
66
|
+
//! - `O` field is an extended opcode field (3 bits) embedded in ModR/M BYTE.
|
|
67
|
+
//!
|
|
68
|
+
//! - `CDSHL` and `CDTT` fields describe 'compressed-displacement'. `CDSHL` is defined for each instruction that is
|
|
69
|
+
//! AVX-512 encodable (EVEX) and contains a base N shift (base shift to perform the calculation). The `CDTT` field
|
|
70
|
+
//! is derived from instruction specification and describes additional shift to calculate the final `CDSHL` that
|
|
71
|
+
//! will be used in SIB byte.
|
|
72
|
+
//!
|
|
73
|
+
//! \note Don't reorder any fields here, the shifts and masks were defined carefully to make encoding of X86
|
|
74
|
+
//! instructions fast, especially to construct REX, VEX, and EVEX prefixes in the most efficient way. Changing
|
|
75
|
+
//! values defined by these enums many cause AsmJit to emit invalid binary representations of instructions passed to
|
|
76
|
+
//! `x86::Assembler::_emit`.
|
|
77
|
+
enum Bits : uint32_t {
|
|
78
|
+
// MM & VEX & EVEX & XOP
|
|
79
|
+
// ---------------------
|
|
80
|
+
//
|
|
81
|
+
// Two meanings:
|
|
82
|
+
// * Part of a legacy opcode (prefixes emitted before the main opcode byte).
|
|
83
|
+
// * `MMMMM` field in VEX|EVEX|XOP instruction.
|
|
84
|
+
//
|
|
85
|
+
// AVX reserves 5 bits for `MMMMM` field, however AVX instructions only use 2 bits and XOP 3 bits. AVX-512 shrinks
|
|
86
|
+
// `MMMMM` field into `MMM` so it's safe to use [4:3] bits of `MMMMM` field for internal payload.
|
|
87
|
+
//
|
|
88
|
+
// AsmJit divides MMMMM field into this layout:
|
|
89
|
+
//
|
|
90
|
+
// [2:0] - Used to describe 0F, 0F38 and 0F3A legacy prefix bytes and 3 bits of MMMMM field for XOP/AVX/AVX512.
|
|
91
|
+
// [3] - Required by XOP instructions, so we use this bit also to indicate that this is a XOP opcode.
|
|
92
|
+
// [4] - Used to force EVEX prefix - this bit is not used by any X86 instruction yet, so AsmJit uses it to
|
|
93
|
+
// describe EVEX only instructions or sets its bit when user uses InstOptions::kX86_Evex to force EVEX.
|
|
94
|
+
kMM_Shift = 8,
|
|
95
|
+
kMM_Mask = 0x1Fu << kMM_Shift,
|
|
96
|
+
kMM_00 = 0x00u << kMM_Shift,
|
|
97
|
+
kMM_0F = 0x01u << kMM_Shift,
|
|
98
|
+
kMM_0F38 = 0x02u << kMM_Shift,
|
|
99
|
+
kMM_0F3A = 0x03u << kMM_Shift, // Described also as XOP.M3 in AMD manuals.
|
|
100
|
+
kMM_0F01 = 0x04u << kMM_Shift, // AsmJit way to describe 0F01 (never VEX/EVEX).
|
|
101
|
+
|
|
102
|
+
kMM_MAP5 = 0x05u << kMM_Shift, // EVEX.MAP5.
|
|
103
|
+
kMM_MAP6 = 0x06u << kMM_Shift, // EVEX.MAP6.
|
|
104
|
+
|
|
105
|
+
// `XOP` field is only used to force XOP prefix instead of VEX3 prefix. We know XOP encodings always use 0b1000
|
|
106
|
+
// bit of MM field and that no VEX and EVEX instruction use such bit yet, so we can use this bit to force XOP
|
|
107
|
+
// prefix to be emitted instead of VEX3 prefix. See `x86VEXPrefix` defined in `x86assembler.cpp`.
|
|
108
|
+
kMM_XOP08 = 0x08u << kMM_Shift, // XOP.M8.
|
|
109
|
+
kMM_XOP09 = 0x09u << kMM_Shift, // XOP.M9.
|
|
110
|
+
kMM_XOP0A = 0x0Au << kMM_Shift, // XOP.MA.
|
|
111
|
+
|
|
112
|
+
kMM_IsXOP_Shift= kMM_Shift + 3,
|
|
113
|
+
kMM_IsXOP = kMM_XOP08,
|
|
114
|
+
|
|
115
|
+
// NOTE: Force VEX3 allows to force to emit VEX3 instead of VEX2 in some cases (similar to forcing REX prefix).
|
|
116
|
+
// Force EVEX will force emitting EVEX prefix instead of VEX2|VEX3. EVEX-only instructions will have ForceEvex
|
|
117
|
+
// always set, however. instructions that can be encoded by either VEX or EVEX prefix should not have ForceEvex
|
|
118
|
+
// set.
|
|
119
|
+
kMM_ForceEvex = 0x10u << kMM_Shift, // Force 4-BYTE EVEX prefix.
|
|
120
|
+
|
|
121
|
+
// FPU_2B - Second-Byte of the Opcode used by FPU
|
|
122
|
+
// ----------------------------------------------
|
|
123
|
+
//
|
|
124
|
+
// Second byte opcode. This BYTE is ONLY used by FPU instructions and collides with 3 bits from `MM` and 5 bits
|
|
125
|
+
// from 'CDSHL' and 'CDTT'. It's fine as FPU and AVX512 flags are never used at the same time.
|
|
126
|
+
kFPU_2B_Shift = 10,
|
|
127
|
+
kFPU_2B_Mask = 0xFF << kFPU_2B_Shift,
|
|
128
|
+
|
|
129
|
+
// CDSHL & CDTT
|
|
130
|
+
// ------------
|
|
131
|
+
//
|
|
132
|
+
// Compressed displacement bits.
|
|
133
|
+
//
|
|
134
|
+
// Each opcode defines the base size (N) shift:
|
|
135
|
+
// [0]: BYTE (1 byte).
|
|
136
|
+
// [1]: WORD (2 bytes).
|
|
137
|
+
// [2]: DWORD (4 bytes - float/int32).
|
|
138
|
+
// [3]: QWORD (8 bytes - double/int64).
|
|
139
|
+
// [4]: OWORD (16 bytes - used by FV|FVM|M128).
|
|
140
|
+
//
|
|
141
|
+
// Which is then scaled by the instruction's TT (TupleType) into possible:
|
|
142
|
+
// [5]: YWORD (32 bytes)
|
|
143
|
+
// [6]: ZWORD (64 bytes)
|
|
144
|
+
//
|
|
145
|
+
// These bits are then adjusted before calling EmitModSib or EmitModVSib.
|
|
146
|
+
kCDSHL_Shift = 13,
|
|
147
|
+
kCDSHL_Mask = 0x7u << kCDSHL_Shift,
|
|
148
|
+
|
|
149
|
+
kCDSHL__ = 0x0u << kCDSHL_Shift, // Base element size not used.
|
|
150
|
+
kCDSHL_0 = 0x0u << kCDSHL_Shift, // N << 0.
|
|
151
|
+
kCDSHL_1 = 0x1u << kCDSHL_Shift, // N << 1.
|
|
152
|
+
kCDSHL_2 = 0x2u << kCDSHL_Shift, // N << 2.
|
|
153
|
+
kCDSHL_3 = 0x3u << kCDSHL_Shift, // N << 3.
|
|
154
|
+
kCDSHL_4 = 0x4u << kCDSHL_Shift, // N << 4.
|
|
155
|
+
kCDSHL_5 = 0x5u << kCDSHL_Shift, // N << 5.
|
|
156
|
+
|
|
157
|
+
// Compressed displacement tuple-type (specific to AsmJit).
|
|
158
|
+
//
|
|
159
|
+
// Since we store the base offset independently of CDTT we can simplify the number of 'TUPLE_TYPE' groups
|
|
160
|
+
// significantly and just handle special cases.
|
|
161
|
+
kCDTT_Shift = 16,
|
|
162
|
+
kCDTT_Mask = 0x3u << kCDTT_Shift,
|
|
163
|
+
kCDTT_None = 0x0u << kCDTT_Shift, // Does nothing.
|
|
164
|
+
kCDTT_ByLL = 0x1u << kCDTT_Shift, // Scales by LL (1x 2x 4x).
|
|
165
|
+
kCDTT_T1W = 0x2u << kCDTT_Shift, // Used to add 'W' to the shift.
|
|
166
|
+
kCDTT_DUP = 0x3u << kCDTT_Shift, // Special 'VMOVDDUP' case.
|
|
167
|
+
|
|
168
|
+
// Aliases that match names used in instruction manuals.
|
|
169
|
+
kCDTT__ = kCDTT_None,
|
|
170
|
+
kCDTT_FV = kCDTT_ByLL,
|
|
171
|
+
kCDTT_HV = kCDTT_ByLL,
|
|
172
|
+
kCDTT_QV = kCDTT_ByLL,
|
|
173
|
+
kCDTT_FVM = kCDTT_ByLL,
|
|
174
|
+
kCDTT_T1S = kCDTT_None,
|
|
175
|
+
kCDTT_T1F = kCDTT_None,
|
|
176
|
+
kCDTT_T1_4X = kCDTT_None,
|
|
177
|
+
kCDTT_T4X = kCDTT_None, // Alias to have only 3 letters.
|
|
178
|
+
kCDTT_T2 = kCDTT_None,
|
|
179
|
+
kCDTT_T4 = kCDTT_None,
|
|
180
|
+
kCDTT_T8 = kCDTT_None,
|
|
181
|
+
kCDTT_HVM = kCDTT_ByLL,
|
|
182
|
+
kCDTT_QVM = kCDTT_ByLL,
|
|
183
|
+
kCDTT_OVM = kCDTT_ByLL,
|
|
184
|
+
kCDTT_128 = kCDTT_None,
|
|
185
|
+
|
|
186
|
+
// `O` Field in ModR/M (??:xxx:???)
|
|
187
|
+
// --------------------------------
|
|
188
|
+
|
|
189
|
+
kModO_Shift = 18,
|
|
190
|
+
kModO_Mask = 0x7u << kModO_Shift,
|
|
191
|
+
|
|
192
|
+
kModO__ = 0x0u,
|
|
193
|
+
kModO_0 = 0x0u << kModO_Shift,
|
|
194
|
+
kModO_1 = 0x1u << kModO_Shift,
|
|
195
|
+
kModO_2 = 0x2u << kModO_Shift,
|
|
196
|
+
kModO_3 = 0x3u << kModO_Shift,
|
|
197
|
+
kModO_4 = 0x4u << kModO_Shift,
|
|
198
|
+
kModO_5 = 0x5u << kModO_Shift,
|
|
199
|
+
kModO_6 = 0x6u << kModO_Shift,
|
|
200
|
+
kModO_7 = 0x7u << kModO_Shift,
|
|
201
|
+
|
|
202
|
+
// `RM` Field in ModR/M (??:???:xxx)
|
|
203
|
+
// ---------------------------------
|
|
204
|
+
//
|
|
205
|
+
// Second data field used by ModR/M byte. This is only used by few instructions that use OPCODE+MOD/RM where both
|
|
206
|
+
// values in Mod/RM are part of the opcode.
|
|
207
|
+
|
|
208
|
+
kModRM_Shift = 13,
|
|
209
|
+
kModRM_Mask = 0x7u << kModRM_Shift,
|
|
210
|
+
|
|
211
|
+
kModRM__ = 0x0u,
|
|
212
|
+
kModRM_0 = 0x0u << kModRM_Shift,
|
|
213
|
+
kModRM_1 = 0x1u << kModRM_Shift,
|
|
214
|
+
kModRM_2 = 0x2u << kModRM_Shift,
|
|
215
|
+
kModRM_3 = 0x3u << kModRM_Shift,
|
|
216
|
+
kModRM_4 = 0x4u << kModRM_Shift,
|
|
217
|
+
kModRM_5 = 0x5u << kModRM_Shift,
|
|
218
|
+
kModRM_6 = 0x6u << kModRM_Shift,
|
|
219
|
+
kModRM_7 = 0x7u << kModRM_Shift,
|
|
220
|
+
|
|
221
|
+
// `PP` Field
|
|
222
|
+
// ----------
|
|
223
|
+
//
|
|
224
|
+
// These fields are stored deliberately right after each other as it makes it easier to construct VEX prefix from
|
|
225
|
+
// the opcode value stored in the instruction database.
|
|
226
|
+
//
|
|
227
|
+
// Two meanings:
|
|
228
|
+
// * "PP" field in AVX/XOP/AVX-512 instruction.
|
|
229
|
+
// * Mandatory Prefix in legacy encoding.
|
|
230
|
+
//
|
|
231
|
+
// AVX reserves 2 bits for `PP` field, but AsmJit extends the storage by 1 more bit that is used to emit 9B prefix
|
|
232
|
+
// for some X87-FPU instructions.
|
|
233
|
+
|
|
234
|
+
kPP_Shift = 21,
|
|
235
|
+
kPP_VEXMask = 0x03u << kPP_Shift, // PP field mask used by VEX/EVEX.
|
|
236
|
+
kPP_FPUMask = 0x07u << kPP_Shift, // Mask used by EMIT_PP, also includes '0x9B'.
|
|
237
|
+
kPP_00 = 0x00u << kPP_Shift,
|
|
238
|
+
kPP_66 = 0x01u << kPP_Shift,
|
|
239
|
+
kPP_F3 = 0x02u << kPP_Shift,
|
|
240
|
+
kPP_F2 = 0x03u << kPP_Shift,
|
|
241
|
+
|
|
242
|
+
kPP_9B = 0x07u << kPP_Shift, // AsmJit specific to emit FPU's '9B' byte.
|
|
243
|
+
|
|
244
|
+
// REX|VEX|EVEX B|X|R|W Bits
|
|
245
|
+
// -------------------------
|
|
246
|
+
//
|
|
247
|
+
// NOTE: REX.[B|X|R] are never stored within the opcode itself, they are reserved by AsmJit are are added
|
|
248
|
+
// dynamically to the opcode to represent [REX|VEX|EVEX].[B|X|R] bits. REX.W can be stored in DB as it's sometimes
|
|
249
|
+
// part of the opcode itself.
|
|
250
|
+
|
|
251
|
+
// These must be binary compatible with instruction options.
|
|
252
|
+
kREX_Shift = 24,
|
|
253
|
+
kREX_Mask = 0x0Fu << kREX_Shift,
|
|
254
|
+
kB = 0x01u << kREX_Shift, // Never stored in DB, used by encoder.
|
|
255
|
+
kX = 0x02u << kREX_Shift, // Never stored in DB, used by encoder.
|
|
256
|
+
kR = 0x04u << kREX_Shift, // Never stored in DB, used by encoder.
|
|
257
|
+
kW = 0x08u << kREX_Shift,
|
|
258
|
+
kW_Shift = kREX_Shift + 3,
|
|
259
|
+
|
|
260
|
+
kW__ = 0u << kW_Shift, // REX.W/VEX.W is unspecified.
|
|
261
|
+
kW_x = 0u << kW_Shift, // REX.W/VEX.W is based on instruction operands.
|
|
262
|
+
kW_I = 0u << kW_Shift, // REX.W/VEX.W is ignored (WIG).
|
|
263
|
+
kW_0 = 0u << kW_Shift, // REX.W/VEX.W is 0 (W0).
|
|
264
|
+
kW_1 = 1u << kW_Shift, // REX.W/VEX.W is 1 (W1).
|
|
265
|
+
|
|
266
|
+
// EVEX.W Field
|
|
267
|
+
// ------------
|
|
268
|
+
//
|
|
269
|
+
// `W` field used by EVEX instruction encoding.
|
|
270
|
+
|
|
271
|
+
kEvex_W_Shift = 28,
|
|
272
|
+
kEvex_W_Mask = 1u << kEvex_W_Shift,
|
|
273
|
+
|
|
274
|
+
kEvex_W__ = 0u << kEvex_W_Shift, // EVEX.W is unspecified (not EVEX instruction).
|
|
275
|
+
kEvex_W_x = 0u << kEvex_W_Shift, // EVEX.W is based on instruction operands.
|
|
276
|
+
kEvex_W_I = 0u << kEvex_W_Shift, // EVEX.W is ignored (WIG).
|
|
277
|
+
kEvex_W_0 = 0u << kEvex_W_Shift, // EVEX.W is 0 (W0).
|
|
278
|
+
kEvex_W_1 = 1u << kEvex_W_Shift, // EVEX.W is 1 (W1).
|
|
279
|
+
|
|
280
|
+
// `L` or `LL` field in AVX/XOP/AVX-512
|
|
281
|
+
// ------------------------------------
|
|
282
|
+
//
|
|
283
|
+
// VEX/XOP prefix can only use the first bit `L.128` or `L.256`. EVEX prefix prefix makes it possible to use also
|
|
284
|
+
// `L.512`. If the instruction set manual describes an instruction by `LIG` it means that the `L` field is ignored
|
|
285
|
+
// and AsmJit defaults to `0` in such case.
|
|
286
|
+
kLL_Shift = 29,
|
|
287
|
+
kLL_Mask = 0x3u << kLL_Shift,
|
|
288
|
+
|
|
289
|
+
kLL__ = 0x0u << kLL_Shift, // LL is unspecified.
|
|
290
|
+
kLL_x = 0x0u << kLL_Shift, // LL is based on instruction operands.
|
|
291
|
+
kLL_I = 0x0u << kLL_Shift, // LL is ignored (LIG).
|
|
292
|
+
kLL_0 = 0x0u << kLL_Shift, // LL is 0 (L.128).
|
|
293
|
+
kLL_1 = 0x1u << kLL_Shift, // LL is 1 (L.256).
|
|
294
|
+
kLL_2 = 0x2u << kLL_Shift, // LL is 2 (L.512).
|
|
295
|
+
|
|
296
|
+
// Opcode Combinations
|
|
297
|
+
// -------------------
|
|
298
|
+
|
|
299
|
+
k0 = 0, // '__' (no prefix, used internally).
|
|
300
|
+
k000000 = kPP_00 | kMM_00, // '__' (no prefix, to be the same width as others).
|
|
301
|
+
k000F00 = kPP_00 | kMM_0F, // '0F'
|
|
302
|
+
k000F01 = kPP_00 | kMM_0F01, // '0F01'
|
|
303
|
+
k000F0F = kPP_00 | kMM_0F, // '0F0F' - 3DNOW, equal to 0x0F, must have special encoding to take effect.
|
|
304
|
+
k000F38 = kPP_00 | kMM_0F38, // 'NP.0F38'
|
|
305
|
+
k000F3A = kPP_00 | kMM_0F3A, // 'NP.0F3A'
|
|
306
|
+
k00MAP5 = kPP_00 | kMM_MAP5, // 'NP.MAP5'
|
|
307
|
+
k00MAP6 = kPP_00 | kMM_MAP6, // 'NP.MAP5'
|
|
308
|
+
k660000 = kPP_66 | kMM_00, // '66'
|
|
309
|
+
k660F00 = kPP_66 | kMM_0F, // '66.0F'
|
|
310
|
+
k660F01 = kPP_66 | kMM_0F01, // '66.0F01'
|
|
311
|
+
k660F38 = kPP_66 | kMM_0F38, // '66.0F38'
|
|
312
|
+
k660F3A = kPP_66 | kMM_0F3A, // '66.0F3A'
|
|
313
|
+
k66MAP5 = kPP_66 | kMM_MAP5, // '66.MAP5'
|
|
314
|
+
k66MAP6 = kPP_66 | kMM_MAP6, // '66.MAP5'
|
|
315
|
+
kF20000 = kPP_F2 | kMM_00, // 'F2'
|
|
316
|
+
kF20F00 = kPP_F2 | kMM_0F, // 'F2.0F'
|
|
317
|
+
kF20F01 = kPP_F2 | kMM_0F01, // 'F2.0F01'
|
|
318
|
+
kF20F38 = kPP_F2 | kMM_0F38, // 'F2.0F38'
|
|
319
|
+
kF20F3A = kPP_F2 | kMM_0F3A, // 'F2.0F3A'
|
|
320
|
+
kF2MAP5 = kPP_F2 | kMM_MAP5, // 'F2.MAP5'
|
|
321
|
+
kF2MAP6 = kPP_F2 | kMM_MAP6, // 'F2.MAP5'
|
|
322
|
+
kF30000 = kPP_F3 | kMM_00, // 'F3'
|
|
323
|
+
kF30F00 = kPP_F3 | kMM_0F, // 'F3.0F'
|
|
324
|
+
kF30F01 = kPP_F3 | kMM_0F01, // 'F3.0F01'
|
|
325
|
+
kF30F38 = kPP_F3 | kMM_0F38, // 'F3.0F38'
|
|
326
|
+
kF30F3A = kPP_F3 | kMM_0F3A, // 'F3.0F3A'
|
|
327
|
+
kF3MAP5 = kPP_F3 | kMM_MAP5, // 'F3.MAP5'
|
|
328
|
+
kF3MAP6 = kPP_F3 | kMM_MAP6, // 'F3.MAP5'
|
|
329
|
+
kFPU_00 = kPP_00 | kMM_00, // '__' (FPU)
|
|
330
|
+
kFPU_9B = kPP_9B | kMM_00, // '9B' (FPU)
|
|
331
|
+
kXOP_M8 = kPP_00 | kMM_XOP08, // 'M8' (XOP)
|
|
332
|
+
kXOP_M9 = kPP_00 | kMM_XOP09, // 'M9' (XOP)
|
|
333
|
+
kXOP_MA = kPP_00 | kMM_XOP0A // 'MA' (XOP)
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
// Opcode Builder
|
|
337
|
+
// --------------
|
|
338
|
+
|
|
339
|
+
inline uint32_t get() const noexcept { return v; }
|
|
340
|
+
|
|
341
|
+
inline bool hasW() const noexcept { return (v & kW) != 0; }
|
|
342
|
+
inline bool has66h() const noexcept { return (v & kPP_66) != 0; }
|
|
343
|
+
|
|
344
|
+
inline Opcode& add(uint32_t x) noexcept { return operator+=(x); }
|
|
345
|
+
|
|
346
|
+
inline Opcode& add66h() noexcept { return operator|=(kPP_66); }
|
|
347
|
+
template<typename T>
|
|
348
|
+
inline Opcode& add66hIf(T exp) noexcept { return operator|=(uint32_t(exp) << kPP_Shift); }
|
|
349
|
+
template<typename T>
|
|
350
|
+
inline Opcode& add66hBySize(T size) noexcept { return add66hIf(size == 2); }
|
|
351
|
+
|
|
352
|
+
inline Opcode& addW() noexcept { return operator|=(kW); }
|
|
353
|
+
template<typename T>
|
|
354
|
+
inline Opcode& addWIf(T exp) noexcept { return operator|=(uint32_t(exp) << kW_Shift); }
|
|
355
|
+
template<typename T>
|
|
356
|
+
inline Opcode& addWBySize(T size) noexcept { return addWIf(size == 8); }
|
|
357
|
+
|
|
358
|
+
template<typename T>
|
|
359
|
+
inline Opcode& addPrefixBySize(T size) noexcept {
|
|
360
|
+
static const uint32_t mask[16] = {
|
|
361
|
+
0, // #0
|
|
362
|
+
0, // #1 -> nothing (already handled or not possible)
|
|
363
|
+
kPP_66, // #2 -> 66H
|
|
364
|
+
0, // #3
|
|
365
|
+
0, // #4 -> nothing
|
|
366
|
+
0, // #5
|
|
367
|
+
0, // #6
|
|
368
|
+
0, // #7
|
|
369
|
+
kW // #8 -> REX.W
|
|
370
|
+
};
|
|
371
|
+
return operator|=(mask[size & 0xF]);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
template<typename T>
|
|
375
|
+
inline Opcode& addArithBySize(T size) noexcept {
|
|
376
|
+
static const uint32_t mask[16] = {
|
|
377
|
+
0, // #0
|
|
378
|
+
0, // #1 -> nothing
|
|
379
|
+
1 | kPP_66, // #2 -> NOT_BYTE_OP(1) and 66H
|
|
380
|
+
0, // #3
|
|
381
|
+
1, // #4 -> NOT_BYTE_OP(1)
|
|
382
|
+
0, // #5
|
|
383
|
+
0, // #6
|
|
384
|
+
0, // #7
|
|
385
|
+
1 | kW // #8 -> NOT_BYTE_OP(1) and REX.W
|
|
386
|
+
};
|
|
387
|
+
return operator|=(mask[size & 0xF]);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
inline Opcode& forceEvex() noexcept { return operator|=(kMM_ForceEvex); }
|
|
391
|
+
template<typename T>
|
|
392
|
+
inline Opcode& forceEvexIf(T exp) noexcept { return operator|=(uint32_t(exp) << Support::ConstCTZ<uint32_t(kMM_ForceEvex)>::value); }
|
|
393
|
+
|
|
394
|
+
//! Extract `O` field (R) from the opcode (specified as /0..7 in instruction manuals).
|
|
395
|
+
inline uint32_t extractModO() const noexcept {
|
|
396
|
+
return (v >> kModO_Shift) & 0x07;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
//! Extract `RM` field (RM) from the opcode (usually specified as another opcode value).
|
|
400
|
+
inline uint32_t extractModRM() const noexcept {
|
|
401
|
+
return (v >> kModRM_Shift) & 0x07;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
//! Extract `REX` prefix from opcode combined with `options`.
|
|
405
|
+
inline uint32_t extractRex(InstOptions options) const noexcept {
|
|
406
|
+
// kREX was designed in a way that when shifted there will be no bytes set except REX.[B|X|R|W].
|
|
407
|
+
// The returned value forms a real REX prefix byte. This case should be unit-tested as well.
|
|
408
|
+
return (v | uint32_t(options)) >> kREX_Shift;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
inline uint32_t extractLLMMMMM(InstOptions options) const noexcept {
|
|
412
|
+
uint32_t llMmmmm = uint32_t(v & (kLL_Mask | kMM_Mask));
|
|
413
|
+
uint32_t vexEvex = uint32_t(options & InstOptions::kX86_Evex);
|
|
414
|
+
return (llMmmmm | vexEvex) >> kMM_Shift;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
inline Opcode& operator=(uint32_t x) noexcept { v = x; return *this; }
|
|
418
|
+
inline Opcode& operator+=(uint32_t x) noexcept { v += x; return *this; }
|
|
419
|
+
inline Opcode& operator-=(uint32_t x) noexcept { v -= x; return *this; }
|
|
420
|
+
inline Opcode& operator&=(uint32_t x) noexcept { v &= x; return *this; }
|
|
421
|
+
inline Opcode& operator|=(uint32_t x) noexcept { v |= x; return *this; }
|
|
422
|
+
inline Opcode& operator^=(uint32_t x) noexcept { v ^= x; return *this; }
|
|
423
|
+
|
|
424
|
+
inline uint32_t operator&(uint32_t x) const noexcept { return v & x; }
|
|
425
|
+
inline uint32_t operator|(uint32_t x) const noexcept { return v | x; }
|
|
426
|
+
inline uint32_t operator^(uint32_t x) const noexcept { return v ^ x; }
|
|
427
|
+
inline uint32_t operator<<(uint32_t x) const noexcept { return v << x; }
|
|
428
|
+
inline uint32_t operator>>(uint32_t x) const noexcept { return v >> x; }
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
//! \}
|
|
432
|
+
//! \endcond
|
|
433
|
+
|
|
434
|
+
ASMJIT_END_SUB_NAMESPACE
|
|
435
|
+
|
|
436
|
+
#endif // ASMJIT_X86_X86OPCODE_P_H_INCLUDED
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// This file is part of AsmJit project <https://asmjit.com>
|
|
2
|
+
//
|
|
3
|
+
// See asmjit.h or LICENSE.md for license and copyright information
|
|
4
|
+
// SPDX-License-Identifier: Zlib
|
|
5
|
+
|
|
6
|
+
#include "../core/api-build_p.h"
|
|
7
|
+
#if !defined(ASMJIT_NO_X86)
|
|
8
|
+
|
|
9
|
+
#include "../core/misc_p.h"
|
|
10
|
+
#include "../x86/x86operand.h"
|
|
11
|
+
|
|
12
|
+
ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
|
13
|
+
|
|
14
|
+
// x86::Operand - Tests
|
|
15
|
+
// ====================
|
|
16
|
+
|
|
17
|
+
#if defined(ASMJIT_TEST)
|
|
18
|
+
UNIT(x86_operand) {
|
|
19
|
+
Label L(1000); // Label with some ID.
|
|
20
|
+
|
|
21
|
+
INFO("Checking basic properties of built-in X86 registers");
|
|
22
|
+
EXPECT(gpb(Gp::kIdAx) == al);
|
|
23
|
+
EXPECT(gpb(Gp::kIdBx) == bl);
|
|
24
|
+
EXPECT(gpb(Gp::kIdCx) == cl);
|
|
25
|
+
EXPECT(gpb(Gp::kIdDx) == dl);
|
|
26
|
+
|
|
27
|
+
EXPECT(gpb_lo(Gp::kIdAx) == al);
|
|
28
|
+
EXPECT(gpb_lo(Gp::kIdBx) == bl);
|
|
29
|
+
EXPECT(gpb_lo(Gp::kIdCx) == cl);
|
|
30
|
+
EXPECT(gpb_lo(Gp::kIdDx) == dl);
|
|
31
|
+
|
|
32
|
+
EXPECT(gpb_hi(Gp::kIdAx) == ah);
|
|
33
|
+
EXPECT(gpb_hi(Gp::kIdBx) == bh);
|
|
34
|
+
EXPECT(gpb_hi(Gp::kIdCx) == ch);
|
|
35
|
+
EXPECT(gpb_hi(Gp::kIdDx) == dh);
|
|
36
|
+
|
|
37
|
+
EXPECT(gpw(Gp::kIdAx) == ax);
|
|
38
|
+
EXPECT(gpw(Gp::kIdBx) == bx);
|
|
39
|
+
EXPECT(gpw(Gp::kIdCx) == cx);
|
|
40
|
+
EXPECT(gpw(Gp::kIdDx) == dx);
|
|
41
|
+
|
|
42
|
+
EXPECT(gpd(Gp::kIdAx) == eax);
|
|
43
|
+
EXPECT(gpd(Gp::kIdBx) == ebx);
|
|
44
|
+
EXPECT(gpd(Gp::kIdCx) == ecx);
|
|
45
|
+
EXPECT(gpd(Gp::kIdDx) == edx);
|
|
46
|
+
|
|
47
|
+
EXPECT(gpq(Gp::kIdAx) == rax);
|
|
48
|
+
EXPECT(gpq(Gp::kIdBx) == rbx);
|
|
49
|
+
EXPECT(gpq(Gp::kIdCx) == rcx);
|
|
50
|
+
EXPECT(gpq(Gp::kIdDx) == rdx);
|
|
51
|
+
|
|
52
|
+
EXPECT(gpb(Gp::kIdAx) != dl);
|
|
53
|
+
EXPECT(gpw(Gp::kIdBx) != cx);
|
|
54
|
+
EXPECT(gpd(Gp::kIdCx) != ebx);
|
|
55
|
+
EXPECT(gpq(Gp::kIdDx) != rax);
|
|
56
|
+
|
|
57
|
+
INFO("Checking if x86::reg(...) matches built-in IDs");
|
|
58
|
+
EXPECT(gpb(5) == bpl);
|
|
59
|
+
EXPECT(gpw(5) == bp);
|
|
60
|
+
EXPECT(gpd(5) == ebp);
|
|
61
|
+
EXPECT(gpq(5) == rbp);
|
|
62
|
+
EXPECT(st(5) == st5);
|
|
63
|
+
EXPECT(mm(5) == mm5);
|
|
64
|
+
EXPECT(k(5) == k5);
|
|
65
|
+
EXPECT(cr(5) == cr5);
|
|
66
|
+
EXPECT(dr(5) == dr5);
|
|
67
|
+
EXPECT(xmm(5) == xmm5);
|
|
68
|
+
EXPECT(ymm(5) == ymm5);
|
|
69
|
+
EXPECT(zmm(5) == zmm5);
|
|
70
|
+
|
|
71
|
+
INFO("Checking x86::Gp register properties");
|
|
72
|
+
EXPECT(Gp().isReg() == true);
|
|
73
|
+
EXPECT(eax.isReg() == true);
|
|
74
|
+
EXPECT(eax.id() == 0);
|
|
75
|
+
EXPECT(eax.size() == 4);
|
|
76
|
+
EXPECT(eax.type() == RegType::kX86_Gpd);
|
|
77
|
+
EXPECT(eax.group() == RegGroup::kGp);
|
|
78
|
+
|
|
79
|
+
INFO("Checking x86::Xmm register properties");
|
|
80
|
+
EXPECT(Xmm().isReg() == true);
|
|
81
|
+
EXPECT(xmm4.isReg() == true);
|
|
82
|
+
EXPECT(xmm4.id() == 4);
|
|
83
|
+
EXPECT(xmm4.size() == 16);
|
|
84
|
+
EXPECT(xmm4.type() == RegType::kX86_Xmm);
|
|
85
|
+
EXPECT(xmm4.group() == RegGroup::kVec);
|
|
86
|
+
EXPECT(xmm4.isVec());
|
|
87
|
+
|
|
88
|
+
INFO("Checking x86::Ymm register properties");
|
|
89
|
+
EXPECT(Ymm().isReg() == true);
|
|
90
|
+
EXPECT(ymm5.isReg() == true);
|
|
91
|
+
EXPECT(ymm5.id() == 5);
|
|
92
|
+
EXPECT(ymm5.size() == 32);
|
|
93
|
+
EXPECT(ymm5.type() == RegType::kX86_Ymm);
|
|
94
|
+
EXPECT(ymm5.group() == RegGroup::kVec);
|
|
95
|
+
EXPECT(ymm5.isVec());
|
|
96
|
+
|
|
97
|
+
INFO("Checking x86::Zmm register properties");
|
|
98
|
+
EXPECT(Zmm().isReg() == true);
|
|
99
|
+
EXPECT(zmm6.isReg() == true);
|
|
100
|
+
EXPECT(zmm6.id() == 6);
|
|
101
|
+
EXPECT(zmm6.size() == 64);
|
|
102
|
+
EXPECT(zmm6.type() == RegType::kX86_Zmm);
|
|
103
|
+
EXPECT(zmm6.group() == RegGroup::kVec);
|
|
104
|
+
EXPECT(zmm6.isVec());
|
|
105
|
+
|
|
106
|
+
INFO("Checking x86::Vec register properties");
|
|
107
|
+
EXPECT(Vec().isReg() == true);
|
|
108
|
+
// Converts a VEC register to a type of the passed register, but keeps the ID.
|
|
109
|
+
EXPECT(xmm4.cloneAs(ymm10) == ymm4);
|
|
110
|
+
EXPECT(xmm4.cloneAs(zmm11) == zmm4);
|
|
111
|
+
EXPECT(ymm5.cloneAs(xmm12) == xmm5);
|
|
112
|
+
EXPECT(ymm5.cloneAs(zmm13) == zmm5);
|
|
113
|
+
EXPECT(zmm6.cloneAs(xmm14) == xmm6);
|
|
114
|
+
EXPECT(zmm6.cloneAs(ymm15) == ymm6);
|
|
115
|
+
|
|
116
|
+
EXPECT(xmm7.xmm() == xmm7);
|
|
117
|
+
EXPECT(xmm7.ymm() == ymm7);
|
|
118
|
+
EXPECT(xmm7.zmm() == zmm7);
|
|
119
|
+
|
|
120
|
+
EXPECT(ymm7.xmm() == xmm7);
|
|
121
|
+
EXPECT(ymm7.ymm() == ymm7);
|
|
122
|
+
EXPECT(ymm7.zmm() == zmm7);
|
|
123
|
+
|
|
124
|
+
EXPECT(zmm7.xmm() == xmm7);
|
|
125
|
+
EXPECT(zmm7.ymm() == ymm7);
|
|
126
|
+
EXPECT(zmm7.zmm() == zmm7);
|
|
127
|
+
|
|
128
|
+
INFO("Checking x86::Mm register properties");
|
|
129
|
+
EXPECT(Mm().isReg() == true);
|
|
130
|
+
EXPECT(mm2.isReg() == true);
|
|
131
|
+
EXPECT(mm2.id() == 2);
|
|
132
|
+
EXPECT(mm2.size() == 8);
|
|
133
|
+
EXPECT(mm2.type() == RegType::kX86_Mm);
|
|
134
|
+
EXPECT(mm2.group() == RegGroup::kX86_MM);
|
|
135
|
+
|
|
136
|
+
INFO("Checking x86::KReg register properties");
|
|
137
|
+
EXPECT(KReg().isReg() == true);
|
|
138
|
+
EXPECT(k3.isReg() == true);
|
|
139
|
+
EXPECT(k3.id() == 3);
|
|
140
|
+
EXPECT(k3.size() == 0);
|
|
141
|
+
EXPECT(k3.type() == RegType::kX86_KReg);
|
|
142
|
+
EXPECT(k3.group() == RegGroup::kX86_K);
|
|
143
|
+
|
|
144
|
+
INFO("Checking x86::St register properties");
|
|
145
|
+
EXPECT(St().isReg() == true);
|
|
146
|
+
EXPECT(st1.isReg() == true);
|
|
147
|
+
EXPECT(st1.id() == 1);
|
|
148
|
+
EXPECT(st1.size() == 10);
|
|
149
|
+
EXPECT(st1.type() == RegType::kX86_St);
|
|
150
|
+
EXPECT(st1.group() == RegGroup::kX86_St);
|
|
151
|
+
|
|
152
|
+
INFO("Checking if default constructed regs behave as expected");
|
|
153
|
+
EXPECT(Reg().isValid() == false);
|
|
154
|
+
EXPECT(Gp().isValid() == false);
|
|
155
|
+
EXPECT(Xmm().isValid() == false);
|
|
156
|
+
EXPECT(Ymm().isValid() == false);
|
|
157
|
+
EXPECT(Zmm().isValid() == false);
|
|
158
|
+
EXPECT(Mm().isValid() == false);
|
|
159
|
+
EXPECT(KReg().isValid() == false);
|
|
160
|
+
EXPECT(SReg().isValid() == false);
|
|
161
|
+
EXPECT(CReg().isValid() == false);
|
|
162
|
+
EXPECT(DReg().isValid() == false);
|
|
163
|
+
EXPECT(St().isValid() == false);
|
|
164
|
+
EXPECT(Bnd().isValid() == false);
|
|
165
|
+
|
|
166
|
+
INFO("Checking x86::Mem operand");
|
|
167
|
+
Mem m;
|
|
168
|
+
EXPECT(m == Mem(), "Two default constructed x86::Mem operands must be equal");
|
|
169
|
+
|
|
170
|
+
m = ptr(L);
|
|
171
|
+
EXPECT(m.hasBase() == true);
|
|
172
|
+
EXPECT(m.hasBaseReg() == false);
|
|
173
|
+
EXPECT(m.hasBaseLabel() == true);
|
|
174
|
+
EXPECT(m.hasOffset() == false);
|
|
175
|
+
EXPECT(m.isOffset64Bit() == false);
|
|
176
|
+
EXPECT(m.offset() == 0);
|
|
177
|
+
EXPECT(m.offsetLo32() == 0);
|
|
178
|
+
|
|
179
|
+
m = ptr(0x0123456789ABCDEFu);
|
|
180
|
+
EXPECT(m.hasBase() == false);
|
|
181
|
+
EXPECT(m.hasBaseReg() == false);
|
|
182
|
+
EXPECT(m.hasIndex() == false);
|
|
183
|
+
EXPECT(m.hasIndexReg() == false);
|
|
184
|
+
EXPECT(m.hasOffset() == true);
|
|
185
|
+
EXPECT(m.isOffset64Bit() == true);
|
|
186
|
+
EXPECT(m.offset() == int64_t(0x0123456789ABCDEFu));
|
|
187
|
+
EXPECT(m.offsetLo32() == int32_t(0x89ABCDEFu));
|
|
188
|
+
m.addOffset(1);
|
|
189
|
+
EXPECT(m.offset() == int64_t(0x0123456789ABCDF0u));
|
|
190
|
+
|
|
191
|
+
m = ptr(0x0123456789ABCDEFu, rdi, 3);
|
|
192
|
+
EXPECT(m.hasSegment() == false);
|
|
193
|
+
EXPECT(m.hasBase() == false);
|
|
194
|
+
EXPECT(m.hasBaseReg() == false);
|
|
195
|
+
EXPECT(m.hasIndex() == true);
|
|
196
|
+
EXPECT(m.hasIndexReg() == true);
|
|
197
|
+
EXPECT(m.indexType() == rdi.type());
|
|
198
|
+
EXPECT(m.indexId() == rdi.id());
|
|
199
|
+
EXPECT(m.shift() == 3);
|
|
200
|
+
EXPECT(m.hasOffset() == true);
|
|
201
|
+
EXPECT(m.isOffset64Bit() == true);
|
|
202
|
+
EXPECT(m.offset() == int64_t(0x0123456789ABCDEFu));
|
|
203
|
+
EXPECT(m.offsetLo32() == int32_t(0x89ABCDEFu));
|
|
204
|
+
m.resetIndex();
|
|
205
|
+
EXPECT(m.hasIndex() == false);
|
|
206
|
+
EXPECT(m.hasIndexReg() == false);
|
|
207
|
+
|
|
208
|
+
m = ptr(rax);
|
|
209
|
+
EXPECT(m.hasBase() == true);
|
|
210
|
+
EXPECT(m.hasBaseReg() == true);
|
|
211
|
+
EXPECT(m.baseType() == rax.type());
|
|
212
|
+
EXPECT(m.baseId() == rax.id());
|
|
213
|
+
EXPECT(m.hasIndex() == false);
|
|
214
|
+
EXPECT(m.hasIndexReg() == false);
|
|
215
|
+
EXPECT(m.indexType() == RegType::kNone);
|
|
216
|
+
EXPECT(m.indexId() == 0);
|
|
217
|
+
EXPECT(m.hasOffset() == false);
|
|
218
|
+
EXPECT(m.isOffset64Bit() == false);
|
|
219
|
+
EXPECT(m.offset() == 0);
|
|
220
|
+
EXPECT(m.offsetLo32() == 0);
|
|
221
|
+
m.setIndex(rsi);
|
|
222
|
+
EXPECT(m.hasIndex() == true);
|
|
223
|
+
EXPECT(m.hasIndexReg() == true);
|
|
224
|
+
EXPECT(m.indexType() == rsi.type());
|
|
225
|
+
EXPECT(m.indexId() == rsi.id());
|
|
226
|
+
}
|
|
227
|
+
#endif
|
|
228
|
+
|
|
229
|
+
ASMJIT_END_SUB_NAMESPACE
|
|
230
|
+
|
|
231
|
+
#endif // !ASMJIT_NO_X86
|