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,772 @@
|
|
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_CORE_INST_H_INCLUDED
|
7
|
+
#define ASMJIT_CORE_INST_H_INCLUDED
|
8
|
+
|
9
|
+
#include "../core/cpuinfo.h"
|
10
|
+
#include "../core/operand.h"
|
11
|
+
#include "../core/string.h"
|
12
|
+
#include "../core/support.h"
|
13
|
+
|
14
|
+
ASMJIT_BEGIN_NAMESPACE
|
15
|
+
|
16
|
+
//! \addtogroup asmjit_instruction_db
|
17
|
+
//! \{
|
18
|
+
|
19
|
+
//! Describes an instruction id and modifiers used together with the id.
|
20
|
+
//!
|
21
|
+
//! Each architecture has a set of valid instructions indexed from 0. Instruction with 0 id is, however, a special
|
22
|
+
//! instruction that describes a "no instruction" or "invalid instruction". Different architectures can assign a.
|
23
|
+
//! different instruction to the same id, each architecture typicall has its own instructions indexed from 1.
|
24
|
+
//!
|
25
|
+
//! Instruction identifiers listed by architecture:
|
26
|
+
//!
|
27
|
+
//! - \ref x86::Inst (X86 and X86_64)
|
28
|
+
//! - \ref a64::Inst (AArch64)
|
29
|
+
typedef uint32_t InstId;
|
30
|
+
|
31
|
+
//! Instruction id parts.
|
32
|
+
//!
|
33
|
+
//! A mask that specifies a bit-layout of \ref InstId.
|
34
|
+
enum class InstIdParts : uint32_t {
|
35
|
+
// Common Masks
|
36
|
+
// ------------
|
37
|
+
|
38
|
+
//! Real id without any modifiers (always 16 least significant bits).
|
39
|
+
kRealId = 0x0000FFFFu,
|
40
|
+
//! Instruction is abstract (or virtual, IR, etc...).
|
41
|
+
kAbstract = 0x80000000u,
|
42
|
+
|
43
|
+
// ARM Specific
|
44
|
+
// ------------
|
45
|
+
|
46
|
+
//! AArch32 first data type, used by ASIMD instructions (`inst.dt.dt2`).
|
47
|
+
kA32_DT = 0x000F0000u,
|
48
|
+
//! AArch32 second data type, used by ASIMD instructions (`inst.dt.dt2`).
|
49
|
+
kA32_DT2 = 0x00F00000u,
|
50
|
+
//! AArch32/AArch64 condition code.
|
51
|
+
kARM_Cond = 0x78000000u
|
52
|
+
};
|
53
|
+
|
54
|
+
//! Instruction options.
|
55
|
+
//!
|
56
|
+
//! Instruction options complement instruction identifier and attributes.
|
57
|
+
enum class InstOptions : uint32_t {
|
58
|
+
//! No options.
|
59
|
+
kNone = 0,
|
60
|
+
|
61
|
+
//! Used internally by emitters for handling errors and rare cases.
|
62
|
+
kReserved = 0x00000001u,
|
63
|
+
|
64
|
+
//! Prevents following a jump during compilation (Compiler).
|
65
|
+
kUnfollow = 0x00000002u,
|
66
|
+
|
67
|
+
//! Overwrite the destination operand(s) (Compiler).
|
68
|
+
//!
|
69
|
+
//! Hint that is important for register liveness analysis. It tells the compiler that the destination operand will
|
70
|
+
//! be overwritten now or by adjacent instructions. Compiler knows when a register is completely overwritten by a
|
71
|
+
//! single instruction, for example you don't have to mark "movaps" or "pxor x, x", however, if a pair of
|
72
|
+
//! instructions is used and the first of them doesn't completely overwrite the content of the destination,
|
73
|
+
//! Compiler fails to mark that register as dead.
|
74
|
+
//!
|
75
|
+
//! X86 Specific
|
76
|
+
//! ------------
|
77
|
+
//!
|
78
|
+
//! - All instructions that always overwrite at least the size of the register the virtual-register uses, for
|
79
|
+
//! example "mov", "movq", "movaps" don't need the overwrite option to be used - conversion, shuffle, and
|
80
|
+
//! other miscellaneous instructions included.
|
81
|
+
//!
|
82
|
+
//! - All instructions that clear the destination register if all operands are the same, for example "xor x, x",
|
83
|
+
//! "pcmpeqb x x", etc...
|
84
|
+
//!
|
85
|
+
//! - Consecutive instructions that partially overwrite the variable until there is no old content require
|
86
|
+
//! `BaseCompiler::overwrite()` to be used. Some examples (not always the best use cases thought):
|
87
|
+
//!
|
88
|
+
//! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa
|
89
|
+
//! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa
|
90
|
+
//! - `mov al, ?` followed by `and ax, 0xFF`
|
91
|
+
//! - `mov al, ?` followed by `mov ah, al`
|
92
|
+
//! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1`
|
93
|
+
//!
|
94
|
+
//! - If the allocated virtual register is used temporarily for scalar operations. For example if you allocate a
|
95
|
+
//! full vector like `x86::Compiler::newXmm()` and then use that vector for scalar operations you should use
|
96
|
+
//! `overwrite()` directive:
|
97
|
+
//!
|
98
|
+
//! - `sqrtss x, y` - only LO element of `x` is changed, if you don't
|
99
|
+
//! use HI elements, use `compiler.overwrite().sqrtss(x, y)`.
|
100
|
+
kOverwrite = 0x00000004u,
|
101
|
+
|
102
|
+
//! Emit short-form of the instruction.
|
103
|
+
kShortForm = 0x00000010u,
|
104
|
+
//! Emit long-form of the instruction.
|
105
|
+
kLongForm = 0x00000020u,
|
106
|
+
|
107
|
+
//! Conditional jump is likely to be taken.
|
108
|
+
kTaken = 0x00000040u,
|
109
|
+
//! Conditional jump is unlikely to be taken.
|
110
|
+
kNotTaken = 0x00000080u,
|
111
|
+
|
112
|
+
// X86 & X64 Options
|
113
|
+
// -----------------
|
114
|
+
|
115
|
+
//! Use ModMR instead of ModRM if applicable.
|
116
|
+
kX86_ModMR = 0x00000100u,
|
117
|
+
//! Use ModRM instead of ModMR if applicable.
|
118
|
+
kX86_ModRM = 0x00000200u,
|
119
|
+
//! Use 3-byte VEX prefix if possible (AVX) (must be 0x00000400).
|
120
|
+
kX86_Vex3 = 0x00000400u,
|
121
|
+
//! Use VEX prefix when both VEX|EVEX prefixes are available (HINT: AVX_VNNI).
|
122
|
+
kX86_Vex = 0x00000800u,
|
123
|
+
//! Use 4-byte EVEX prefix if possible (AVX-512) (must be 0x00001000).
|
124
|
+
kX86_Evex = 0x00001000u,
|
125
|
+
|
126
|
+
//! LOCK prefix (lock-enabled instructions only).
|
127
|
+
kX86_Lock = 0x00002000u,
|
128
|
+
//! REP prefix (string instructions only).
|
129
|
+
kX86_Rep = 0x00004000u,
|
130
|
+
//! REPNE prefix (string instructions only).
|
131
|
+
kX86_Repne = 0x00008000u,
|
132
|
+
|
133
|
+
//! XACQUIRE prefix (only allowed instructions).
|
134
|
+
kX86_XAcquire = 0x00010000u,
|
135
|
+
//! XRELEASE prefix (only allowed instructions).
|
136
|
+
kX86_XRelease = 0x00020000u,
|
137
|
+
|
138
|
+
//! AVX-512: embedded-rounding {er} and implicit {sae}.
|
139
|
+
kX86_ER = 0x00040000u,
|
140
|
+
//! AVX-512: suppress-all-exceptions {sae}.
|
141
|
+
kX86_SAE = 0x00080000u,
|
142
|
+
//! AVX-512: round-to-nearest (even) {rn-sae} (bits 00).
|
143
|
+
kX86_RN_SAE = 0x00000000u,
|
144
|
+
//! AVX-512: round-down (toward -inf) {rd-sae} (bits 01).
|
145
|
+
kX86_RD_SAE = 0x00200000u,
|
146
|
+
//! AVX-512: round-up (toward +inf) {ru-sae} (bits 10).
|
147
|
+
kX86_RU_SAE = 0x00400000u,
|
148
|
+
//! AVX-512: round-toward-zero (truncate) {rz-sae} (bits 11).
|
149
|
+
kX86_RZ_SAE = 0x00600000u,
|
150
|
+
//! AVX-512: Use zeroing {k}{z} instead of merging {k}.
|
151
|
+
kX86_ZMask = 0x00800000u,
|
152
|
+
|
153
|
+
//! AVX-512: Mask to get embedded rounding bits (2 bits).
|
154
|
+
kX86_ERMask = kX86_RZ_SAE,
|
155
|
+
//! AVX-512: Mask of all possible AVX-512 options except EVEX prefix flag.
|
156
|
+
kX86_AVX512Mask = 0x00FC0000u,
|
157
|
+
|
158
|
+
//! Force REX.B and/or VEX.B field (X64 only).
|
159
|
+
kX86_OpCodeB = 0x01000000u,
|
160
|
+
//! Force REX.X and/or VEX.X field (X64 only).
|
161
|
+
kX86_OpCodeX = 0x02000000u,
|
162
|
+
//! Force REX.R and/or VEX.R field (X64 only).
|
163
|
+
kX86_OpCodeR = 0x04000000u,
|
164
|
+
//! Force REX.W and/or VEX.W field (X64 only).
|
165
|
+
kX86_OpCodeW = 0x08000000u,
|
166
|
+
//! Force REX prefix (X64 only).
|
167
|
+
kX86_Rex = 0x40000000u,
|
168
|
+
//! Invalid REX prefix (set by X86 or when AH|BH|CH|DH regs are used on X64).
|
169
|
+
kX86_InvalidRex = 0x80000000u
|
170
|
+
};
|
171
|
+
ASMJIT_DEFINE_ENUM_FLAGS(InstOptions)
|
172
|
+
|
173
|
+
//! Instruction control flow.
|
174
|
+
enum class InstControlFlow : uint32_t {
|
175
|
+
//! Regular instruction.
|
176
|
+
kRegular = 0u,
|
177
|
+
//! Unconditional jump.
|
178
|
+
kJump = 1u,
|
179
|
+
//! Conditional jump (branch).
|
180
|
+
kBranch = 2u,
|
181
|
+
//! Function call.
|
182
|
+
kCall = 3u,
|
183
|
+
//! Function return.
|
184
|
+
kReturn = 4u,
|
185
|
+
|
186
|
+
//! Maximum value of `InstType`.
|
187
|
+
kMaxValue = kReturn
|
188
|
+
};
|
189
|
+
|
190
|
+
//! Hint that is used when both input operands to the instruction are the same.
|
191
|
+
//!
|
192
|
+
//! Provides hints to the instrution RW query regarding special cases in which two or more operands are the same
|
193
|
+
//! registers. This is required by instructions such as XOR, AND, OR, SUB, etc... These hints will influence the
|
194
|
+
//! RW operations query.
|
195
|
+
enum class InstSameRegHint : uint8_t {
|
196
|
+
//! No special handling.
|
197
|
+
kNone = 0,
|
198
|
+
//! Operands become read-only, the operation doesn't change the content - `X & X` and similar.
|
199
|
+
kRO = 1,
|
200
|
+
//! Operands become write-only, the content of the input(s) don't matter - `X ^ X`, `X - X`, and similar.
|
201
|
+
kWO = 2
|
202
|
+
};
|
203
|
+
|
204
|
+
//! Instruction id, options, and extraReg in a single structure. This structure exists mainly to simplify analysis
|
205
|
+
//! and validation API that requires `BaseInst` and `Operand[]` array.
|
206
|
+
class BaseInst {
|
207
|
+
public:
|
208
|
+
//! \name Members
|
209
|
+
//! \{
|
210
|
+
|
211
|
+
//! Instruction id with modifiers.
|
212
|
+
InstId _id;
|
213
|
+
//! Instruction options.
|
214
|
+
InstOptions _options;
|
215
|
+
//! Extra register used by the instruction (either REP register or AVX-512 selector).
|
216
|
+
RegOnly _extraReg;
|
217
|
+
|
218
|
+
enum Id : uint32_t {
|
219
|
+
//! Invalid or uninitialized instruction id.
|
220
|
+
kIdNone = 0x00000000u,
|
221
|
+
//! Abstract instruction (BaseBuilder and BaseCompiler).
|
222
|
+
kIdAbstract = 0x80000000u
|
223
|
+
};
|
224
|
+
|
225
|
+
//! \}
|
226
|
+
|
227
|
+
//! \name Construction & Destruction
|
228
|
+
//! \{
|
229
|
+
|
230
|
+
//! Creates a new BaseInst instance with `id` and `options` set.
|
231
|
+
//!
|
232
|
+
//! Default values of `id` and `options` are zero, which means 'none' instruction. Such instruction is guaranteed
|
233
|
+
//! to never exist for any architecture supported by AsmJit.
|
234
|
+
inline explicit BaseInst(InstId instId = 0, InstOptions options = InstOptions::kNone) noexcept
|
235
|
+
: _id(instId),
|
236
|
+
_options(options),
|
237
|
+
_extraReg() {}
|
238
|
+
|
239
|
+
inline BaseInst(InstId instId, InstOptions options, const RegOnly& extraReg) noexcept
|
240
|
+
: _id(instId),
|
241
|
+
_options(options),
|
242
|
+
_extraReg(extraReg) {}
|
243
|
+
|
244
|
+
inline BaseInst(InstId instId, InstOptions options, const BaseReg& extraReg) noexcept
|
245
|
+
: _id(instId),
|
246
|
+
_options(options),
|
247
|
+
_extraReg { extraReg.signature(), extraReg.id() } {}
|
248
|
+
|
249
|
+
//! \}
|
250
|
+
|
251
|
+
//! \name Instruction id and modifiers
|
252
|
+
//! \{
|
253
|
+
|
254
|
+
//! Returns the instruction id with modifiers.
|
255
|
+
inline InstId id() const noexcept { return _id; }
|
256
|
+
//! Sets the instruction id and modiiers from `id`.
|
257
|
+
inline void setId(InstId id) noexcept { _id = id; }
|
258
|
+
//! Resets the instruction id and modifiers to zero, see \ref kIdNone.
|
259
|
+
inline void resetId() noexcept { _id = 0; }
|
260
|
+
|
261
|
+
//! Returns a real instruction id that doesn't contain any modifiers.
|
262
|
+
inline InstId realId() const noexcept { return _id & uint32_t(InstIdParts::kRealId); }
|
263
|
+
|
264
|
+
template<InstIdParts kPart>
|
265
|
+
inline uint32_t getInstIdPart() const noexcept {
|
266
|
+
return (uint32_t(_id) & uint32_t(kPart)) >> Support::ConstCTZ<uint32_t(kPart)>::value;
|
267
|
+
}
|
268
|
+
|
269
|
+
template<InstIdParts kPart>
|
270
|
+
inline void setInstIdPart(uint32_t value) noexcept {
|
271
|
+
_id = (_id & ~uint32_t(kPart)) | (value << Support::ConstCTZ<uint32_t(kPart)>::value);
|
272
|
+
}
|
273
|
+
|
274
|
+
//! \}
|
275
|
+
|
276
|
+
//! \name Instruction Options
|
277
|
+
//! \{
|
278
|
+
|
279
|
+
inline InstOptions options() const noexcept { return _options; }
|
280
|
+
inline bool hasOption(InstOptions option) const noexcept { return Support::test(_options, option); }
|
281
|
+
inline void setOptions(InstOptions options) noexcept { _options = options; }
|
282
|
+
inline void addOptions(InstOptions options) noexcept { _options |= options; }
|
283
|
+
inline void clearOptions(InstOptions options) noexcept { _options &= ~options; }
|
284
|
+
inline void resetOptions() noexcept { _options = InstOptions::kNone; }
|
285
|
+
|
286
|
+
//! \}
|
287
|
+
|
288
|
+
//! \name Extra Register
|
289
|
+
//! \{
|
290
|
+
|
291
|
+
inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); }
|
292
|
+
inline RegOnly& extraReg() noexcept { return _extraReg; }
|
293
|
+
inline const RegOnly& extraReg() const noexcept { return _extraReg; }
|
294
|
+
inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); }
|
295
|
+
inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
|
296
|
+
inline void resetExtraReg() noexcept { _extraReg.reset(); }
|
297
|
+
|
298
|
+
//! \}
|
299
|
+
|
300
|
+
//! \name ARM Specific
|
301
|
+
//! \{
|
302
|
+
|
303
|
+
inline arm::CondCode armCondCode() const noexcept { return (arm::CondCode)getInstIdPart<InstIdParts::kARM_Cond>(); }
|
304
|
+
inline void setArmCondCode(arm::CondCode cc) noexcept { setInstIdPart<InstIdParts::kARM_Cond>(uint32_t(cc)); }
|
305
|
+
|
306
|
+
//! \}
|
307
|
+
|
308
|
+
//! \name Statics
|
309
|
+
//! \{
|
310
|
+
|
311
|
+
static inline constexpr InstId composeARMInstId(uint32_t id, arm::CondCode cc) noexcept {
|
312
|
+
return id | (uint32_t(cc) << Support::ConstCTZ<uint32_t(InstIdParts::kARM_Cond)>::value);
|
313
|
+
}
|
314
|
+
|
315
|
+
static inline constexpr InstId extractRealId(uint32_t id) noexcept {
|
316
|
+
return id & uint32_t(InstIdParts::kRealId);
|
317
|
+
}
|
318
|
+
|
319
|
+
static inline constexpr arm::CondCode extractARMCondCode(uint32_t id) noexcept {
|
320
|
+
return (arm::CondCode)((uint32_t(id) & uint32_t(InstIdParts::kARM_Cond)) >> Support::ConstCTZ<uint32_t(InstIdParts::kARM_Cond)>::value);
|
321
|
+
}
|
322
|
+
|
323
|
+
//! \}
|
324
|
+
};
|
325
|
+
|
326
|
+
//! CPU read/write flags used by \ref InstRWInfo.
|
327
|
+
//!
|
328
|
+
//! These flags can be used to get a basic overview about CPU specifics flags used by instructions.
|
329
|
+
enum class CpuRWFlags : uint32_t {
|
330
|
+
//! No flags.
|
331
|
+
kNone = 0x00000000u,
|
332
|
+
|
333
|
+
// Common RW Flags (0x000000FF)
|
334
|
+
// ----------------------------
|
335
|
+
|
336
|
+
//! Carry flag.
|
337
|
+
kCF = 0x00000001u,
|
338
|
+
//! Signed overflow flag.
|
339
|
+
kOF = 0x00000002u,
|
340
|
+
//! Sign flag (negative/sign, if set).
|
341
|
+
kSF = 0x00000004u,
|
342
|
+
//! Zero and/or equality flag (1 if zero/equal).
|
343
|
+
kZF = 0x00000008u,
|
344
|
+
|
345
|
+
// X86 Specific RW Flags (0xFFFFFF00)
|
346
|
+
// ----------------------------------
|
347
|
+
|
348
|
+
//! Carry flag (X86, X86_64).
|
349
|
+
kX86_CF = kCF,
|
350
|
+
//! Overflow flag (X86, X86_64).
|
351
|
+
kX86_OF = kOF,
|
352
|
+
//! Sign flag (X86, X86_64).
|
353
|
+
kX86_SF = kSF,
|
354
|
+
//! Zero flag (X86, X86_64).
|
355
|
+
kX86_ZF = kZF,
|
356
|
+
|
357
|
+
//! Adjust flag (X86, X86_64).
|
358
|
+
kX86_AF = 0x00000100u,
|
359
|
+
//! Parity flag (X86, X86_64).
|
360
|
+
kX86_PF = 0x00000200u,
|
361
|
+
//! Direction flag (X86, X86_64).
|
362
|
+
kX86_DF = 0x00000400u,
|
363
|
+
//! Interrupt enable flag (X86, X86_64).
|
364
|
+
kX86_IF = 0x00000800u,
|
365
|
+
|
366
|
+
//! Alignment check flag (X86, X86_64).
|
367
|
+
kX86_AC = 0x00001000u,
|
368
|
+
|
369
|
+
//! FPU C0 status flag (X86, X86_64).
|
370
|
+
kX86_C0 = 0x00010000u,
|
371
|
+
//! FPU C1 status flag (X86, X86_64).
|
372
|
+
kX86_C1 = 0x00020000u,
|
373
|
+
//! FPU C2 status flag (X86, X86_64).
|
374
|
+
kX86_C2 = 0x00040000u,
|
375
|
+
//! FPU C3 status flag (X86, X86_64).
|
376
|
+
kX86_C3 = 0x00080000u
|
377
|
+
};
|
378
|
+
ASMJIT_DEFINE_ENUM_FLAGS(CpuRWFlags)
|
379
|
+
|
380
|
+
//! Operand read/write flags describe how the operand is accessed and some additional features.
|
381
|
+
enum class OpRWFlags {
|
382
|
+
//! No flags.
|
383
|
+
kNone = 0,
|
384
|
+
|
385
|
+
//! Operand is read.
|
386
|
+
kRead = 0x00000001u,
|
387
|
+
|
388
|
+
//! Operand is written.
|
389
|
+
kWrite = 0x00000002u,
|
390
|
+
|
391
|
+
//! Operand is both read and written.
|
392
|
+
kRW = 0x00000003u,
|
393
|
+
|
394
|
+
//! Register operand can be replaced by a memory operand.
|
395
|
+
kRegMem = 0x00000004u,
|
396
|
+
|
397
|
+
//! The register must be allocated to the index of the previous register + 1.
|
398
|
+
//!
|
399
|
+
//! This flag is used by all architectures to describe instructions that use consecutive registers, where only the
|
400
|
+
//! first one is encoded in the instruction, and the others are just a sequence that starts with the first one. On
|
401
|
+
//! X86/X86_64 architecture this is used by instructions such as V4FMADDPS, V4FMADDSS, V4FNMADDPS, V4FNMADDSS,
|
402
|
+
//! VP4DPWSSD, VP4DPWSSDS, VP2INTERSECTD, and VP2INTERSECTQ. On ARM/AArch64 this is used by vector load and store
|
403
|
+
//! instructions that can load or store multiple registers at once.
|
404
|
+
kConsecutive = 0x00000008u,
|
405
|
+
|
406
|
+
//! The `extendByteMask()` represents a zero extension.
|
407
|
+
kZExt = 0x00000010u,
|
408
|
+
|
409
|
+
//! Register operand must use \ref OpRWInfo::physId().
|
410
|
+
kRegPhysId = 0x00000100u,
|
411
|
+
//! Base register of a memory operand must use \ref OpRWInfo::physId().
|
412
|
+
kMemPhysId = 0x00000200u,
|
413
|
+
|
414
|
+
//! This memory operand is only used to encode registers and doesn't access memory.
|
415
|
+
//!
|
416
|
+
//! X86 Specific
|
417
|
+
//! ------------
|
418
|
+
//!
|
419
|
+
//! Instructions that use such feature include BNDLDX, BNDSTX, and LEA.
|
420
|
+
kMemFake = 0x000000400u,
|
421
|
+
|
422
|
+
//! Base register of the memory operand will be read.
|
423
|
+
kMemBaseRead = 0x00001000u,
|
424
|
+
//! Base register of the memory operand will be written.
|
425
|
+
kMemBaseWrite = 0x00002000u,
|
426
|
+
//! Base register of the memory operand will be read & written.
|
427
|
+
kMemBaseRW = 0x00003000u,
|
428
|
+
|
429
|
+
//! Index register of the memory operand will be read.
|
430
|
+
kMemIndexRead = 0x00004000u,
|
431
|
+
//! Index register of the memory operand will be written.
|
432
|
+
kMemIndexWrite = 0x00008000u,
|
433
|
+
//! Index register of the memory operand will be read & written.
|
434
|
+
kMemIndexRW = 0x0000C000u,
|
435
|
+
|
436
|
+
//! Base register of the memory operand will be modified before the operation.
|
437
|
+
kMemBasePreModify = 0x00010000u,
|
438
|
+
//! Base register of the memory operand will be modified after the operation.
|
439
|
+
kMemBasePostModify = 0x00020000u
|
440
|
+
};
|
441
|
+
ASMJIT_DEFINE_ENUM_FLAGS(OpRWFlags)
|
442
|
+
|
443
|
+
// Don't remove these asserts. Read/Write flags are used extensively
|
444
|
+
// by Compiler and they must always be compatible with constants below.
|
445
|
+
static_assert(uint32_t(OpRWFlags::kRead) == 0x1, "OpRWFlags::kRead flag must be 0x1");
|
446
|
+
static_assert(uint32_t(OpRWFlags::kWrite) == 0x2, "OpRWFlags::kWrite flag must be 0x2");
|
447
|
+
static_assert(uint32_t(OpRWFlags::kRegMem) == 0x4, "OpRWFlags::kRegMem flag must be 0x4");
|
448
|
+
|
449
|
+
//! Read/Write information related to a single operand, used by \ref InstRWInfo.
|
450
|
+
struct OpRWInfo {
|
451
|
+
//! \name Members
|
452
|
+
//! \{
|
453
|
+
|
454
|
+
//! Read/Write flags.
|
455
|
+
OpRWFlags _opFlags;
|
456
|
+
//! Physical register index, if required.
|
457
|
+
uint8_t _physId;
|
458
|
+
//! Size of a possible memory operand that can replace a register operand.
|
459
|
+
uint8_t _rmSize;
|
460
|
+
//! If non-zero, then this is a consecutive lead register, and the value describes how many registers follow.
|
461
|
+
uint8_t _consecutiveLeadCount;
|
462
|
+
//! Reserved for future use.
|
463
|
+
uint8_t _reserved[1];
|
464
|
+
//! Read bit-mask where each bit represents one byte read from Reg/Mem.
|
465
|
+
uint64_t _readByteMask;
|
466
|
+
//! Write bit-mask where each bit represents one byte written to Reg/Mem.
|
467
|
+
uint64_t _writeByteMask;
|
468
|
+
//! Zero/Sign extend bit-mask where each bit represents one byte written to Reg/Mem.
|
469
|
+
uint64_t _extendByteMask;
|
470
|
+
|
471
|
+
//! \}
|
472
|
+
|
473
|
+
//! \name Reset
|
474
|
+
//! \{
|
475
|
+
|
476
|
+
//! Resets this operand information to all zeros.
|
477
|
+
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
478
|
+
|
479
|
+
//! Resets this operand info (resets all members) and set common information
|
480
|
+
//! to the given `opFlags`, `regSize`, and possibly `physId`.
|
481
|
+
inline void reset(OpRWFlags opFlags, uint32_t regSize, uint32_t physId = BaseReg::kIdBad) noexcept {
|
482
|
+
_opFlags = opFlags;
|
483
|
+
_physId = uint8_t(physId);
|
484
|
+
_rmSize = Support::test(opFlags, OpRWFlags::kRegMem) ? uint8_t(regSize) : uint8_t(0);
|
485
|
+
_consecutiveLeadCount = 0;
|
486
|
+
_resetReserved();
|
487
|
+
|
488
|
+
uint64_t mask = Support::lsbMask<uint64_t>(regSize);
|
489
|
+
_readByteMask = Support::test(opFlags, OpRWFlags::kRead) ? mask : uint64_t(0);
|
490
|
+
_writeByteMask = Support::test(opFlags, OpRWFlags::kWrite) ? mask : uint64_t(0);
|
491
|
+
_extendByteMask = 0;
|
492
|
+
}
|
493
|
+
|
494
|
+
inline void _resetReserved() noexcept {
|
495
|
+
_reserved[0] = 0;
|
496
|
+
}
|
497
|
+
|
498
|
+
//! \}
|
499
|
+
|
500
|
+
//! \name Operand Flags
|
501
|
+
//! \{
|
502
|
+
|
503
|
+
//! Returns operand flags.
|
504
|
+
inline OpRWFlags opFlags() const noexcept { return _opFlags; }
|
505
|
+
//! Tests whether operand flags contain the given `flag`.
|
506
|
+
inline bool hasOpFlag(OpRWFlags flag) const noexcept { return Support::test(_opFlags, flag); }
|
507
|
+
|
508
|
+
//! Adds the given `flags` to operand flags.
|
509
|
+
inline void addOpFlags(OpRWFlags flags) noexcept { _opFlags |= flags; }
|
510
|
+
//! Removes the given `flags` from operand flags.
|
511
|
+
inline void clearOpFlags(OpRWFlags flags) noexcept { _opFlags &= ~flags; }
|
512
|
+
|
513
|
+
//! Tests whether this operand is read from.
|
514
|
+
inline bool isRead() const noexcept { return hasOpFlag(OpRWFlags::kRead); }
|
515
|
+
//! Tests whether this operand is written to.
|
516
|
+
inline bool isWrite() const noexcept { return hasOpFlag(OpRWFlags::kWrite); }
|
517
|
+
//! Tests whether this operand is both read and write.
|
518
|
+
inline bool isReadWrite() const noexcept { return (_opFlags & OpRWFlags::kRW) == OpRWFlags::kRW; }
|
519
|
+
//! Tests whether this operand is read only.
|
520
|
+
inline bool isReadOnly() const noexcept { return (_opFlags & OpRWFlags::kRW) == OpRWFlags::kRead; }
|
521
|
+
//! Tests whether this operand is write only.
|
522
|
+
inline bool isWriteOnly() const noexcept { return (_opFlags & OpRWFlags::kRW) == OpRWFlags::kWrite; }
|
523
|
+
|
524
|
+
//! Returns the type of a lead register, which is followed by consecutive registers.
|
525
|
+
inline uint32_t consecutiveLeadCount() const noexcept { return _consecutiveLeadCount; }
|
526
|
+
|
527
|
+
//! Tests whether this operand is Reg/Mem
|
528
|
+
//!
|
529
|
+
//! Reg/Mem operands can use either register or memory.
|
530
|
+
inline bool isRm() const noexcept { return hasOpFlag(OpRWFlags::kRegMem); }
|
531
|
+
|
532
|
+
//! Tests whether the operand will be zero extended.
|
533
|
+
inline bool isZExt() const noexcept { return hasOpFlag(OpRWFlags::kZExt); }
|
534
|
+
|
535
|
+
//! \}
|
536
|
+
|
537
|
+
//! \name Memory Flags
|
538
|
+
//! \{
|
539
|
+
|
540
|
+
//! Tests whether this is a fake memory operand, which is only used, because of encoding. Fake memory operands do
|
541
|
+
//! not access any memory, they are only used to encode registers.
|
542
|
+
inline bool isMemFake() const noexcept { return hasOpFlag(OpRWFlags::kMemFake); }
|
543
|
+
|
544
|
+
//! Tests whether the instruction's memory BASE register is used.
|
545
|
+
inline bool isMemBaseUsed() const noexcept { return hasOpFlag(OpRWFlags::kMemBaseRW); }
|
546
|
+
//! Tests whether the instruction reads from its BASE registers.
|
547
|
+
inline bool isMemBaseRead() const noexcept { return hasOpFlag(OpRWFlags::kMemBaseRead); }
|
548
|
+
//! Tests whether the instruction writes to its BASE registers.
|
549
|
+
inline bool isMemBaseWrite() const noexcept { return hasOpFlag(OpRWFlags::kMemBaseWrite); }
|
550
|
+
//! Tests whether the instruction reads and writes from/to its BASE registers.
|
551
|
+
inline bool isMemBaseReadWrite() const noexcept { return (_opFlags & OpRWFlags::kMemBaseRW) == OpRWFlags::kMemBaseRW; }
|
552
|
+
//! Tests whether the instruction only reads from its BASE registers.
|
553
|
+
inline bool isMemBaseReadOnly() const noexcept { return (_opFlags & OpRWFlags::kMemBaseRW) == OpRWFlags::kMemBaseRead; }
|
554
|
+
//! Tests whether the instruction only writes to its BASE registers.
|
555
|
+
inline bool isMemBaseWriteOnly() const noexcept { return (_opFlags & OpRWFlags::kMemBaseRW) == OpRWFlags::kMemBaseWrite; }
|
556
|
+
|
557
|
+
//! Tests whether the instruction modifies the BASE register before it uses it to calculate the target address.
|
558
|
+
inline bool isMemBasePreModify() const noexcept { return hasOpFlag(OpRWFlags::kMemBasePreModify); }
|
559
|
+
//! Tests whether the instruction modifies the BASE register after it uses it to calculate the target address.
|
560
|
+
inline bool isMemBasePostModify() const noexcept { return hasOpFlag(OpRWFlags::kMemBasePostModify); }
|
561
|
+
|
562
|
+
//! Tests whether the instruction's memory INDEX register is used.
|
563
|
+
inline bool isMemIndexUsed() const noexcept { return hasOpFlag(OpRWFlags::kMemIndexRW); }
|
564
|
+
//! Tests whether the instruction reads the INDEX registers.
|
565
|
+
inline bool isMemIndexRead() const noexcept { return hasOpFlag(OpRWFlags::kMemIndexRead); }
|
566
|
+
//! Tests whether the instruction writes to its INDEX registers.
|
567
|
+
inline bool isMemIndexWrite() const noexcept { return hasOpFlag(OpRWFlags::kMemIndexWrite); }
|
568
|
+
//! Tests whether the instruction reads and writes from/to its INDEX registers.
|
569
|
+
inline bool isMemIndexReadWrite() const noexcept { return (_opFlags & OpRWFlags::kMemIndexRW) == OpRWFlags::kMemIndexRW; }
|
570
|
+
//! Tests whether the instruction only reads from its INDEX registers.
|
571
|
+
inline bool isMemIndexReadOnly() const noexcept { return (_opFlags & OpRWFlags::kMemIndexRW) == OpRWFlags::kMemIndexRead; }
|
572
|
+
//! Tests whether the instruction only writes to its INDEX registers.
|
573
|
+
inline bool isMemIndexWriteOnly() const noexcept { return (_opFlags & OpRWFlags::kMemIndexRW) == OpRWFlags::kMemIndexWrite; }
|
574
|
+
|
575
|
+
//! \}
|
576
|
+
|
577
|
+
//! \name Physical Register ID
|
578
|
+
//! \{
|
579
|
+
|
580
|
+
//! Returns a physical id of the register that is fixed for this operand.
|
581
|
+
//!
|
582
|
+
//! Returns \ref BaseReg::kIdBad if any register can be used.
|
583
|
+
inline uint32_t physId() const noexcept { return _physId; }
|
584
|
+
//! Tests whether \ref physId() would return a valid physical register id.
|
585
|
+
inline bool hasPhysId() const noexcept { return _physId != BaseReg::kIdBad; }
|
586
|
+
//! Sets physical register id, which would be fixed for this operand.
|
587
|
+
inline void setPhysId(uint32_t physId) noexcept { _physId = uint8_t(physId); }
|
588
|
+
|
589
|
+
//! \}
|
590
|
+
|
591
|
+
//! \name Reg/Mem Information
|
592
|
+
//! \{
|
593
|
+
|
594
|
+
//! Returns Reg/Mem size of the operand.
|
595
|
+
inline uint32_t rmSize() const noexcept { return _rmSize; }
|
596
|
+
//! Sets Reg/Mem size of the operand.
|
597
|
+
inline void setRmSize(uint32_t rmSize) noexcept { _rmSize = uint8_t(rmSize); }
|
598
|
+
|
599
|
+
//! \}
|
600
|
+
|
601
|
+
//! \name Read & Write Masks
|
602
|
+
//! \{
|
603
|
+
|
604
|
+
//! Returns read mask.
|
605
|
+
inline uint64_t readByteMask() const noexcept { return _readByteMask; }
|
606
|
+
//! Returns write mask.
|
607
|
+
inline uint64_t writeByteMask() const noexcept { return _writeByteMask; }
|
608
|
+
//! Returns extend mask.
|
609
|
+
inline uint64_t extendByteMask() const noexcept { return _extendByteMask; }
|
610
|
+
|
611
|
+
//! Sets read mask.
|
612
|
+
inline void setReadByteMask(uint64_t mask) noexcept { _readByteMask = mask; }
|
613
|
+
//! Sets write mask.
|
614
|
+
inline void setWriteByteMask(uint64_t mask) noexcept { _writeByteMask = mask; }
|
615
|
+
//! Sets externd mask.
|
616
|
+
inline void setExtendByteMask(uint64_t mask) noexcept { _extendByteMask = mask; }
|
617
|
+
|
618
|
+
//! \}
|
619
|
+
};
|
620
|
+
|
621
|
+
//! Flags used by \ref InstRWInfo.
|
622
|
+
enum class InstRWFlags : uint32_t {
|
623
|
+
//! No flags.
|
624
|
+
kNone = 0x00000000u,
|
625
|
+
|
626
|
+
//! Describes a move operation.
|
627
|
+
//!
|
628
|
+
//! This flag is used by RA to eliminate moves that are guaranteed to be moves only.
|
629
|
+
kMovOp = 0x00000001u
|
630
|
+
};
|
631
|
+
ASMJIT_DEFINE_ENUM_FLAGS(InstRWFlags)
|
632
|
+
|
633
|
+
//! Read/Write information of an instruction.
|
634
|
+
struct InstRWInfo {
|
635
|
+
//! \name Members
|
636
|
+
//! \{
|
637
|
+
|
638
|
+
//! Instruction flags (there are no flags at the moment, this field is reserved).
|
639
|
+
InstRWFlags _instFlags;
|
640
|
+
//! CPU flags read.
|
641
|
+
CpuRWFlags _readFlags;
|
642
|
+
//! CPU flags written.
|
643
|
+
CpuRWFlags _writeFlags;
|
644
|
+
//! Count of operands.
|
645
|
+
uint8_t _opCount;
|
646
|
+
//! CPU feature required for replacing register operand with memory operand.
|
647
|
+
uint8_t _rmFeature;
|
648
|
+
//! Reserved for future use.
|
649
|
+
uint8_t _reserved[18];
|
650
|
+
//! Read/Write onfo of extra register (rep{} or kz{}).
|
651
|
+
OpRWInfo _extraReg;
|
652
|
+
//! Read/Write info of instruction operands.
|
653
|
+
OpRWInfo _operands[Globals::kMaxOpCount];
|
654
|
+
|
655
|
+
//! \}
|
656
|
+
|
657
|
+
//! \name Commons
|
658
|
+
//! \{
|
659
|
+
|
660
|
+
//! Resets this RW information to all zeros.
|
661
|
+
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
662
|
+
|
663
|
+
//! \}
|
664
|
+
|
665
|
+
//! \name Instruction Flags
|
666
|
+
//! \{
|
667
|
+
|
668
|
+
//! Returns flags associated with the instruction, see \ref InstRWFlags.
|
669
|
+
inline InstRWFlags instFlags() const noexcept { return _instFlags; }
|
670
|
+
|
671
|
+
//! Tests whether the instruction flags contain `flag`.
|
672
|
+
inline bool hasInstFlag(InstRWFlags flag) const noexcept { return Support::test(_instFlags, flag); }
|
673
|
+
|
674
|
+
//! Tests whether the instruction flags contain \ref InstRWFlags::kMovOp.
|
675
|
+
inline bool isMovOp() const noexcept { return hasInstFlag(InstRWFlags::kMovOp); }
|
676
|
+
|
677
|
+
//! \}
|
678
|
+
|
679
|
+
//! \name CPU Flags Information
|
680
|
+
//! \{
|
681
|
+
|
682
|
+
//! Returns a mask of CPU flags read.
|
683
|
+
inline CpuRWFlags readFlags() const noexcept { return _readFlags; }
|
684
|
+
//! Returns a mask of CPU flags written.
|
685
|
+
inline CpuRWFlags writeFlags() const noexcept { return _writeFlags; }
|
686
|
+
|
687
|
+
//! \}
|
688
|
+
|
689
|
+
//! \name Reg/Mem Information
|
690
|
+
//! \{
|
691
|
+
|
692
|
+
//! Returns the CPU feature required to replace a register operand with memory operand. If the returned feature is
|
693
|
+
//! zero (none) then this instruction either doesn't provide memory operand combination or there is no extra CPU
|
694
|
+
//! feature required.
|
695
|
+
//!
|
696
|
+
//! X86 Specific
|
697
|
+
//! ------------
|
698
|
+
//!
|
699
|
+
//! Some AVX+ instructions may require extra features for replacing registers with memory operands, for example
|
700
|
+
//! VPSLLDQ instruction only supports `vpslldq reg, reg, imm` combination on AVX/AVX2 capable CPUs and requires
|
701
|
+
//! AVX-512 for `vpslldq reg, mem, imm` combination.
|
702
|
+
inline uint32_t rmFeature() const noexcept { return _rmFeature; }
|
703
|
+
|
704
|
+
//! \}
|
705
|
+
|
706
|
+
//! \name Operand Read/Write Information
|
707
|
+
//! \{
|
708
|
+
|
709
|
+
//! Returns RW information of extra register operand (extraReg).
|
710
|
+
inline const OpRWInfo& extraReg() const noexcept { return _extraReg; }
|
711
|
+
|
712
|
+
//! Returns RW information of all instruction's operands.
|
713
|
+
inline const OpRWInfo* operands() const noexcept { return _operands; }
|
714
|
+
|
715
|
+
//! Returns RW information of the operand at the given `index`.
|
716
|
+
inline const OpRWInfo& operand(size_t index) const noexcept {
|
717
|
+
ASMJIT_ASSERT(index < Globals::kMaxOpCount);
|
718
|
+
return _operands[index];
|
719
|
+
}
|
720
|
+
|
721
|
+
//! Returns the number of operands this instruction has.
|
722
|
+
inline uint32_t opCount() const noexcept { return _opCount; }
|
723
|
+
|
724
|
+
//! \}
|
725
|
+
};
|
726
|
+
|
727
|
+
//! Validation flags that can be used with \ref InstAPI::validate().
|
728
|
+
enum class ValidationFlags : uint32_t {
|
729
|
+
//! No flags.
|
730
|
+
kNone = 0,
|
731
|
+
//! Allow virtual registers in the instruction.
|
732
|
+
kEnableVirtRegs = 0x01u
|
733
|
+
};
|
734
|
+
ASMJIT_DEFINE_ENUM_FLAGS(ValidationFlags)
|
735
|
+
|
736
|
+
//! Instruction API.
|
737
|
+
namespace InstAPI {
|
738
|
+
|
739
|
+
#ifndef ASMJIT_NO_TEXT
|
740
|
+
//! Appends the name of the instruction specified by `instId` and `instOptions` into the `output` string.
|
741
|
+
//!
|
742
|
+
//! \note Instruction options would only affect instruction prefix & suffix, other options would be ignored.
|
743
|
+
//! If `instOptions` is zero then only raw instruction name (without any additional text) will be appended.
|
744
|
+
ASMJIT_API Error instIdToString(Arch arch, InstId instId, String& output) noexcept;
|
745
|
+
|
746
|
+
//! Parses an instruction name in the given string `s`. Length is specified by `len` argument, which can be
|
747
|
+
//! `SIZE_MAX` if `s` is known to be null terminated.
|
748
|
+
//!
|
749
|
+
//! Returns the parsed instruction id or \ref BaseInst::kIdNone if no such instruction exists.
|
750
|
+
ASMJIT_API InstId stringToInstId(Arch arch, const char* s, size_t len) noexcept;
|
751
|
+
#endif // !ASMJIT_NO_TEXT
|
752
|
+
|
753
|
+
#ifndef ASMJIT_NO_VALIDATION
|
754
|
+
//! Validates the given instruction considering the given `validationFlags`.
|
755
|
+
ASMJIT_API Error validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags = ValidationFlags::kNone) noexcept;
|
756
|
+
#endif // !ASMJIT_NO_VALIDATION
|
757
|
+
|
758
|
+
#ifndef ASMJIT_NO_INTROSPECTION
|
759
|
+
//! Gets Read/Write information of the given instruction.
|
760
|
+
ASMJIT_API Error queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept;
|
761
|
+
|
762
|
+
//! Gets CPU features required by the given instruction.
|
763
|
+
ASMJIT_API Error queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept;
|
764
|
+
#endif // !ASMJIT_NO_INTROSPECTION
|
765
|
+
|
766
|
+
} // {InstAPI}
|
767
|
+
|
768
|
+
//! \}
|
769
|
+
|
770
|
+
ASMJIT_END_NAMESPACE
|
771
|
+
|
772
|
+
#endif // ASMJIT_CORE_INST_H_INCLUDED
|