asmjit 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|