asmjit 0.2.0 → 0.2.2
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/Rakefile +5 -3
- data/asmjit.gemspec +1 -3
- 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 +167 -30
- data/ext/asmjit/extconf.rb +9 -9
- data/lib/asmjit/version.rb +1 -1
- data/lib/asmjit.rb +14 -4
- metadata +198 -17
@@ -0,0 +1,741 @@
|
|
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_EMITTER_H_INCLUDED
|
7
|
+
#define ASMJIT_CORE_EMITTER_H_INCLUDED
|
8
|
+
|
9
|
+
#include "../core/archtraits.h"
|
10
|
+
#include "../core/codeholder.h"
|
11
|
+
#include "../core/formatter.h"
|
12
|
+
#include "../core/inst.h"
|
13
|
+
#include "../core/operand.h"
|
14
|
+
#include "../core/type.h"
|
15
|
+
|
16
|
+
ASMJIT_BEGIN_NAMESPACE
|
17
|
+
|
18
|
+
//! \addtogroup asmjit_core
|
19
|
+
//! \{
|
20
|
+
|
21
|
+
class ConstPool;
|
22
|
+
class FuncFrame;
|
23
|
+
class FuncArgsAssignment;
|
24
|
+
|
25
|
+
//! Align mode, used by \ref BaseEmitter::align().
|
26
|
+
enum class AlignMode : uint8_t {
|
27
|
+
//! Align executable code.
|
28
|
+
kCode = 0,
|
29
|
+
//! Align non-executable code.
|
30
|
+
kData = 1,
|
31
|
+
//! Align by a sequence of zeros.
|
32
|
+
kZero = 2,
|
33
|
+
|
34
|
+
//! Maximum value of `AlignMode`.
|
35
|
+
kMaxValue = kZero
|
36
|
+
};
|
37
|
+
|
38
|
+
//! Emitter type used by \ref BaseEmitter.
|
39
|
+
enum class EmitterType : uint8_t {
|
40
|
+
//! Unknown or uninitialized.
|
41
|
+
kNone = 0,
|
42
|
+
//! Emitter inherits from \ref BaseAssembler.
|
43
|
+
kAssembler = 1,
|
44
|
+
//! Emitter inherits from \ref BaseBuilder.
|
45
|
+
kBuilder = 2,
|
46
|
+
//! Emitter inherits from \ref BaseCompiler.
|
47
|
+
kCompiler = 3,
|
48
|
+
|
49
|
+
//! Maximum value of `EmitterType`.
|
50
|
+
kMaxValue = kCompiler
|
51
|
+
};
|
52
|
+
|
53
|
+
//! Emitter flags, used by \ref BaseEmitter.
|
54
|
+
enum class EmitterFlags : uint8_t {
|
55
|
+
//! No flags.
|
56
|
+
kNone = 0u,
|
57
|
+
//! Emitter is attached to CodeHolder.
|
58
|
+
kAttached = 0x01u,
|
59
|
+
//! The emitter must emit comments.
|
60
|
+
kLogComments = 0x08u,
|
61
|
+
//! The emitter has its own \ref Logger (not propagated from \ref CodeHolder).
|
62
|
+
kOwnLogger = 0x10u,
|
63
|
+
//! The emitter has its own \ref ErrorHandler (not propagated from \ref CodeHolder).
|
64
|
+
kOwnErrorHandler = 0x20u,
|
65
|
+
//! The emitter was finalized.
|
66
|
+
kFinalized = 0x40u,
|
67
|
+
//! The emitter was destroyed.
|
68
|
+
//!
|
69
|
+
//! This flag is used for a very short time when an emitter is being destroyed by
|
70
|
+
//! CodeHolder.
|
71
|
+
kDestroyed = 0x80u
|
72
|
+
};
|
73
|
+
ASMJIT_DEFINE_ENUM_FLAGS(EmitterFlags)
|
74
|
+
|
75
|
+
//! Encoding options.
|
76
|
+
enum class EncodingOptions : uint32_t {
|
77
|
+
//! No encoding options.
|
78
|
+
kNone = 0,
|
79
|
+
|
80
|
+
//! Emit instructions that are optimized for size, if possible.
|
81
|
+
//!
|
82
|
+
//! Default: false.
|
83
|
+
//!
|
84
|
+
//! X86 Specific
|
85
|
+
//! ------------
|
86
|
+
//!
|
87
|
+
//! When this option is set it the assembler will try to fix instructions if possible into operation equivalent
|
88
|
+
//! instructions that take less bytes by taking advantage of implicit zero extension. For example instruction
|
89
|
+
//! like `mov r64, imm` and `and r64, imm` can be translated to `mov r32, imm` and `and r32, imm` when the
|
90
|
+
//! immediate constant is lesser than `2^31`.
|
91
|
+
kOptimizeForSize = 0x00000001u,
|
92
|
+
|
93
|
+
//! Emit optimized code-alignment sequences.
|
94
|
+
//!
|
95
|
+
//! Default: false.
|
96
|
+
//!
|
97
|
+
//! X86 Specific
|
98
|
+
//! ------------
|
99
|
+
//!
|
100
|
+
//! Default align sequence used by X86 architecture is one-byte (0x90) opcode that is often shown by disassemblers
|
101
|
+
//! as NOP. However there are more optimized align sequences for 2-11 bytes that may execute faster on certain CPUs.
|
102
|
+
//! If this feature is enabled AsmJit will generate specialized sequences for alignment between 2 to 11 bytes.
|
103
|
+
kOptimizedAlign = 0x00000002u,
|
104
|
+
|
105
|
+
//! Emit jump-prediction hints.
|
106
|
+
//!
|
107
|
+
//! Default: false.
|
108
|
+
//!
|
109
|
+
//! X86 Specific
|
110
|
+
//! ------------
|
111
|
+
//!
|
112
|
+
//! Jump prediction is usually based on the direction of the jump. If the jump is backward it is usually predicted as
|
113
|
+
//! taken; and if the jump is forward it is usually predicted as not-taken. The reason is that loops generally use
|
114
|
+
//! backward jumps and conditions usually use forward jumps. However this behavior can be overridden by using
|
115
|
+
//! instruction prefixes. If this option is enabled these hints will be emitted.
|
116
|
+
//!
|
117
|
+
//! This feature is disabled by default, because the only processor that used to take into consideration prediction
|
118
|
+
//! hints was P4. Newer processors implement heuristics for branch prediction and ignore static hints. This means
|
119
|
+
//! that this feature can be only used for annotation purposes.
|
120
|
+
kPredictedJumps = 0x00000010u
|
121
|
+
};
|
122
|
+
ASMJIT_DEFINE_ENUM_FLAGS(EncodingOptions)
|
123
|
+
|
124
|
+
//! Diagnostic options are used to tell emitters and their passes to perform diagnostics when emitting or processing
|
125
|
+
//! user code. These options control validation and extra diagnostics that can be performed by higher level emitters.
|
126
|
+
//!
|
127
|
+
//! Instruction Validation
|
128
|
+
//! ----------------------
|
129
|
+
//!
|
130
|
+
//! \ref BaseAssembler implementation perform by default only basic checks that are necessary to identify all
|
131
|
+
//! variations of an instruction so the correct encoding can be selected. This is fine for production-ready code
|
132
|
+
//! as the assembler doesn't have to perform checks that would slow it down. However, sometimes these checks are
|
133
|
+
//! beneficial especially when the project that uses AsmJit is in a development phase, in which mistakes happen
|
134
|
+
//! often. To make the experience of using AsmJit seamless it offers validation features that can be controlled
|
135
|
+
//! by \ref DiagnosticOptions.
|
136
|
+
//!
|
137
|
+
//! Compiler Diagnostics
|
138
|
+
//! --------------------
|
139
|
+
//!
|
140
|
+
//! Diagnostic options work with \ref BaseCompiler passes (precisely with its register allocation pass). These options
|
141
|
+
//! can be used to enable logging of all operations that the Compiler does.
|
142
|
+
enum class DiagnosticOptions : uint32_t {
|
143
|
+
//! No validation options.
|
144
|
+
kNone = 0,
|
145
|
+
|
146
|
+
//! Perform strict validation in \ref BaseAssembler::emit() implementations.
|
147
|
+
//!
|
148
|
+
//! This flag ensures that each instruction is checked before it's encoded into a binary representation. This flag
|
149
|
+
//! is only relevant for \ref BaseAssembler implementations, but can be set in any other emitter type, in that case
|
150
|
+
//! if that emitter needs to create an assembler on its own, for the purpose of \ref BaseEmitter::finalize() it
|
151
|
+
//! would propagate this flag to such assembler so all instructions passed to it are explicitly validated.
|
152
|
+
//!
|
153
|
+
//! Default: false.
|
154
|
+
kValidateAssembler = 0x00000001u,
|
155
|
+
|
156
|
+
//! Perform strict validation in \ref BaseBuilder::emit() and \ref BaseCompiler::emit() implementations.
|
157
|
+
//!
|
158
|
+
//! This flag ensures that each instruction is checked before an \ref InstNode representing the instruction is
|
159
|
+
//! created by \ref BaseBuilder or \ref BaseCompiler. This option could be more useful than \ref kValidateAssembler
|
160
|
+
//! in cases in which there is an invalid instruction passed to an assembler, which was invalid much earlier, most
|
161
|
+
//! likely when such instruction was passed to Builder/Compiler.
|
162
|
+
//!
|
163
|
+
//! This is a separate option that was introduced, because it's possible to manipulate the instruction stream
|
164
|
+
//! emitted by \ref BaseBuilder and \ref BaseCompiler - this means that it's allowed to emit invalid instructions
|
165
|
+
//! (for example with missing operands) that will be fixed later before finalizing it.
|
166
|
+
//!
|
167
|
+
//! Default: false.
|
168
|
+
kValidateIntermediate = 0x00000002u,
|
169
|
+
|
170
|
+
//! Annotate all nodes processed by register allocator (Compiler/RA).
|
171
|
+
//!
|
172
|
+
//! \note Annotations don't need debug options, however, some debug options like `kRADebugLiveness` may influence
|
173
|
+
//! their output (for example the mentioned option would add liveness information to per-instruction annotation).
|
174
|
+
kRAAnnotate = 0x00000080u,
|
175
|
+
|
176
|
+
//! Debug CFG generation and other related algorithms / operations (Compiler/RA).
|
177
|
+
kRADebugCFG = 0x00000100u,
|
178
|
+
|
179
|
+
//! Debug liveness analysis (Compiler/RA).
|
180
|
+
kRADebugLiveness = 0x00000200u,
|
181
|
+
|
182
|
+
//! Debug register allocation assignment (Compiler/RA).
|
183
|
+
kRADebugAssignment = 0x00000400u,
|
184
|
+
|
185
|
+
//! Debug the removal of code part of unreachable blocks.
|
186
|
+
kRADebugUnreachable = 0x00000800u,
|
187
|
+
|
188
|
+
//! Enable all debug options (Compiler/RA).
|
189
|
+
kRADebugAll = 0x0000FF00u,
|
190
|
+
};
|
191
|
+
ASMJIT_DEFINE_ENUM_FLAGS(DiagnosticOptions)
|
192
|
+
|
193
|
+
//! Provides a base foundation to emitting code - specialized by \ref BaseAssembler and \ref BaseBuilder.
|
194
|
+
class ASMJIT_VIRTAPI BaseEmitter {
|
195
|
+
public:
|
196
|
+
ASMJIT_BASE_CLASS(BaseEmitter)
|
197
|
+
|
198
|
+
//! \name Members
|
199
|
+
//! \{
|
200
|
+
|
201
|
+
//! See \ref EmitterType.
|
202
|
+
EmitterType _emitterType = EmitterType::kNone;
|
203
|
+
//! See \ref EmitterFlags.
|
204
|
+
EmitterFlags _emitterFlags = EmitterFlags::kNone;
|
205
|
+
//! Validation flags in case validation is used.
|
206
|
+
//!
|
207
|
+
//! \note Validation flags are specific to the emitter and they are setup at construction time and then never
|
208
|
+
//! changed.
|
209
|
+
ValidationFlags _validationFlags = ValidationFlags::kNone;
|
210
|
+
//! Validation options.
|
211
|
+
DiagnosticOptions _diagnosticOptions = DiagnosticOptions::kNone;
|
212
|
+
|
213
|
+
//! All supported architectures in a bit-mask, where LSB is the bit with a zero index.
|
214
|
+
uint64_t _archMask = 0;
|
215
|
+
|
216
|
+
//! Encoding options.
|
217
|
+
EncodingOptions _encodingOptions = EncodingOptions::kNone;
|
218
|
+
|
219
|
+
//! Forced instruction options, combined with \ref _instOptions by \ref emit().
|
220
|
+
InstOptions _forcedInstOptions = InstOptions::kReserved;
|
221
|
+
//! Internal private data used freely by any emitter.
|
222
|
+
uint32_t _privateData = 0;
|
223
|
+
|
224
|
+
//! CodeHolder the emitter is attached to.
|
225
|
+
CodeHolder* _code = nullptr;
|
226
|
+
//! Attached \ref Logger.
|
227
|
+
Logger* _logger = nullptr;
|
228
|
+
//! Attached \ref ErrorHandler.
|
229
|
+
ErrorHandler* _errorHandler = nullptr;
|
230
|
+
|
231
|
+
//! Describes the target environment, matches \ref CodeHolder::environment().
|
232
|
+
Environment _environment {};
|
233
|
+
//! Native GP register signature and signature related information.
|
234
|
+
OperandSignature _gpSignature {};
|
235
|
+
|
236
|
+
//! Next instruction options (affects the next instruction).
|
237
|
+
InstOptions _instOptions = InstOptions::kNone;
|
238
|
+
//! Extra register (op-mask {k} on AVX-512) (affects the next instruction).
|
239
|
+
RegOnly _extraReg {};
|
240
|
+
//! Inline comment of the next instruction (affects the next instruction).
|
241
|
+
const char* _inlineComment = nullptr;
|
242
|
+
|
243
|
+
//! Function callbacks used by emitter implementation.
|
244
|
+
//!
|
245
|
+
//! These are typically shared between Assembler/Builder/Compiler of a single backend.
|
246
|
+
struct Funcs {
|
247
|
+
typedef Error (ASMJIT_CDECL* EmitProlog)(BaseEmitter* emitter, const FuncFrame& frame);
|
248
|
+
typedef Error (ASMJIT_CDECL* EmitEpilog)(BaseEmitter* emitter, const FuncFrame& frame);
|
249
|
+
typedef Error (ASMJIT_CDECL* EmitArgsAssignment)(BaseEmitter* emitter, const FuncFrame& frame, const FuncArgsAssignment& args);
|
250
|
+
|
251
|
+
typedef Error (ASMJIT_CDECL* FormatInstruction)(
|
252
|
+
String& sb,
|
253
|
+
FormatFlags formatFlags,
|
254
|
+
const BaseEmitter* emitter,
|
255
|
+
Arch arch,
|
256
|
+
const BaseInst& inst, const Operand_* operands, size_t opCount) ASMJIT_NOEXCEPT_TYPE;
|
257
|
+
|
258
|
+
typedef Error (ASMJIT_CDECL* ValidateFunc)(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) ASMJIT_NOEXCEPT_TYPE;
|
259
|
+
|
260
|
+
//! Emit prolog implementation.
|
261
|
+
EmitProlog emitProlog;
|
262
|
+
//! Emit epilog implementation.
|
263
|
+
EmitEpilog emitEpilog;
|
264
|
+
//! Emit arguments assignment implementation.
|
265
|
+
EmitArgsAssignment emitArgsAssignment;
|
266
|
+
//! Instruction formatter implementation.
|
267
|
+
FormatInstruction formatInstruction;
|
268
|
+
//! Instruction validation implementation.
|
269
|
+
ValidateFunc validate;
|
270
|
+
|
271
|
+
//! Resets all functions to nullptr.
|
272
|
+
inline void reset() noexcept {
|
273
|
+
emitProlog = nullptr;
|
274
|
+
emitEpilog = nullptr;
|
275
|
+
emitArgsAssignment = nullptr;
|
276
|
+
validate = nullptr;
|
277
|
+
}
|
278
|
+
};
|
279
|
+
|
280
|
+
Funcs _funcs {};
|
281
|
+
|
282
|
+
//! \}
|
283
|
+
|
284
|
+
//! \name Construction & Destruction
|
285
|
+
//! \{
|
286
|
+
|
287
|
+
ASMJIT_API explicit BaseEmitter(EmitterType emitterType) noexcept;
|
288
|
+
ASMJIT_API virtual ~BaseEmitter() noexcept;
|
289
|
+
|
290
|
+
//! \}
|
291
|
+
|
292
|
+
//! \name Cast
|
293
|
+
//! \{
|
294
|
+
|
295
|
+
template<typename T>
|
296
|
+
inline T* as() noexcept { return reinterpret_cast<T*>(this); }
|
297
|
+
|
298
|
+
template<typename T>
|
299
|
+
inline const T* as() const noexcept { return reinterpret_cast<const T*>(this); }
|
300
|
+
|
301
|
+
//! \}
|
302
|
+
|
303
|
+
//! \name Emitter Type & Flags
|
304
|
+
//! \{
|
305
|
+
|
306
|
+
//! Returns the type of this emitter, see `EmitterType`.
|
307
|
+
inline EmitterType emitterType() const noexcept { return _emitterType; }
|
308
|
+
//! Returns emitter flags , see `Flags`.
|
309
|
+
inline EmitterFlags emitterFlags() const noexcept { return _emitterFlags; }
|
310
|
+
|
311
|
+
//! Tests whether the emitter inherits from `BaseAssembler`.
|
312
|
+
inline bool isAssembler() const noexcept { return _emitterType == EmitterType::kAssembler; }
|
313
|
+
//! Tests whether the emitter inherits from `BaseBuilder`.
|
314
|
+
//!
|
315
|
+
//! \note Both Builder and Compiler emitters would return `true`.
|
316
|
+
inline bool isBuilder() const noexcept { return uint32_t(_emitterType) >= uint32_t(EmitterType::kBuilder); }
|
317
|
+
//! Tests whether the emitter inherits from `BaseCompiler`.
|
318
|
+
inline bool isCompiler() const noexcept { return _emitterType == EmitterType::kCompiler; }
|
319
|
+
|
320
|
+
//! Tests whether the emitter has the given `flag` enabled.
|
321
|
+
inline bool hasEmitterFlag(EmitterFlags flag) const noexcept { return Support::test(_emitterFlags, flag); }
|
322
|
+
//! Tests whether the emitter is finalized.
|
323
|
+
inline bool isFinalized() const noexcept { return hasEmitterFlag(EmitterFlags::kFinalized); }
|
324
|
+
//! Tests whether the emitter is destroyed (only used during destruction).
|
325
|
+
inline bool isDestroyed() const noexcept { return hasEmitterFlag(EmitterFlags::kDestroyed); }
|
326
|
+
|
327
|
+
inline void _addEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags |= flags; }
|
328
|
+
inline void _clearEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags &= _emitterFlags & ~flags; }
|
329
|
+
|
330
|
+
//! \}
|
331
|
+
|
332
|
+
//! \name Target Information
|
333
|
+
//! \{
|
334
|
+
|
335
|
+
//! Returns the CodeHolder this emitter is attached to.
|
336
|
+
inline CodeHolder* code() const noexcept { return _code; }
|
337
|
+
|
338
|
+
//! Returns the target environment.
|
339
|
+
//!
|
340
|
+
//! The returned \ref Environment reference matches \ref CodeHolder::environment().
|
341
|
+
inline const Environment& environment() const noexcept { return _environment; }
|
342
|
+
|
343
|
+
//! Tests whether the target architecture is 32-bit.
|
344
|
+
inline bool is32Bit() const noexcept { return environment().is32Bit(); }
|
345
|
+
//! Tests whether the target architecture is 64-bit.
|
346
|
+
inline bool is64Bit() const noexcept { return environment().is64Bit(); }
|
347
|
+
|
348
|
+
//! Returns the target architecture type.
|
349
|
+
inline Arch arch() const noexcept { return environment().arch(); }
|
350
|
+
//! Returns the target architecture sub-type.
|
351
|
+
inline SubArch subArch() const noexcept { return environment().subArch(); }
|
352
|
+
|
353
|
+
//! Returns the target architecture's GP register size (4 or 8 bytes).
|
354
|
+
inline uint32_t registerSize() const noexcept { return environment().registerSize(); }
|
355
|
+
|
356
|
+
//! \}
|
357
|
+
|
358
|
+
//! \name Initialization & Finalization
|
359
|
+
//! \{
|
360
|
+
|
361
|
+
//! Tests whether the emitter is initialized (i.e. attached to \ref CodeHolder).
|
362
|
+
inline bool isInitialized() const noexcept { return _code != nullptr; }
|
363
|
+
|
364
|
+
//! Finalizes this emitter.
|
365
|
+
//!
|
366
|
+
//! Materializes the content of the emitter by serializing it to the attached \ref CodeHolder through an architecture
|
367
|
+
//! specific \ref BaseAssembler. This function won't do anything if the emitter inherits from \ref BaseAssembler as
|
368
|
+
//! assemblers emit directly to a \ref CodeBuffer held by \ref CodeHolder. However, if this is an emitter that
|
369
|
+
//! inherits from \ref BaseBuilder or \ref BaseCompiler then these emitters need the materialization phase as they
|
370
|
+
//! store their content in a representation not visible to \ref CodeHolder.
|
371
|
+
ASMJIT_API virtual Error finalize();
|
372
|
+
|
373
|
+
//! \}
|
374
|
+
|
375
|
+
//! \name Logging
|
376
|
+
//! \{
|
377
|
+
|
378
|
+
//! Tests whether the emitter has a logger.
|
379
|
+
inline bool hasLogger() const noexcept { return _logger != nullptr; }
|
380
|
+
|
381
|
+
//! Tests whether the emitter has its own logger.
|
382
|
+
//!
|
383
|
+
//! Own logger means that it overrides the possible logger that may be used by \ref CodeHolder this emitter is
|
384
|
+
//! attached to.
|
385
|
+
inline bool hasOwnLogger() const noexcept { return hasEmitterFlag(EmitterFlags::kOwnLogger); }
|
386
|
+
|
387
|
+
//! Returns the logger this emitter uses.
|
388
|
+
//!
|
389
|
+
//! The returned logger is either the emitter's own logger or it's logger used by \ref CodeHolder this emitter
|
390
|
+
//! is attached to.
|
391
|
+
inline Logger* logger() const noexcept { return _logger; }
|
392
|
+
|
393
|
+
//! Sets or resets the logger of the emitter.
|
394
|
+
//!
|
395
|
+
//! If the `logger` argument is non-null then the logger will be considered emitter's own logger, see \ref
|
396
|
+
//! hasOwnLogger() for more details. If the given `logger` is null then the emitter will automatically use logger
|
397
|
+
//! that is attached to the \ref CodeHolder this emitter is attached to.
|
398
|
+
ASMJIT_API void setLogger(Logger* logger) noexcept;
|
399
|
+
|
400
|
+
//! Resets the logger of this emitter.
|
401
|
+
//!
|
402
|
+
//! The emitter will bail to using a logger attached to \ref CodeHolder this emitter is attached to, or no logger
|
403
|
+
//! at all if \ref CodeHolder doesn't have one.
|
404
|
+
inline void resetLogger() noexcept { return setLogger(nullptr); }
|
405
|
+
|
406
|
+
//! \}
|
407
|
+
|
408
|
+
//! \name Error Handling
|
409
|
+
//! \{
|
410
|
+
|
411
|
+
//! Tests whether the emitter has an error handler attached.
|
412
|
+
inline bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; }
|
413
|
+
|
414
|
+
//! Tests whether the emitter has its own error handler.
|
415
|
+
//!
|
416
|
+
//! Own error handler means that it overrides the possible error handler that may be used by \ref CodeHolder this
|
417
|
+
//! emitter is attached to.
|
418
|
+
inline bool hasOwnErrorHandler() const noexcept { return hasEmitterFlag(EmitterFlags::kOwnErrorHandler); }
|
419
|
+
|
420
|
+
//! Returns the error handler this emitter uses.
|
421
|
+
//!
|
422
|
+
//! The returned error handler is either the emitter's own error handler or it's error handler used by
|
423
|
+
//! \ref CodeHolder this emitter is attached to.
|
424
|
+
inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; }
|
425
|
+
|
426
|
+
//! Sets or resets the error handler of the emitter.
|
427
|
+
ASMJIT_API void setErrorHandler(ErrorHandler* errorHandler) noexcept;
|
428
|
+
|
429
|
+
//! Resets the error handler.
|
430
|
+
inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
|
431
|
+
|
432
|
+
//! Handles the given error in the following way:
|
433
|
+
//! 1. If the emitter has \ref ErrorHandler attached, it calls its \ref ErrorHandler::handleError() member function
|
434
|
+
//! first, and then returns the error. The `handleError()` function may throw.
|
435
|
+
//! 2. if the emitter doesn't have \ref ErrorHandler, the error is simply returned.
|
436
|
+
ASMJIT_API Error reportError(Error err, const char* message = nullptr);
|
437
|
+
|
438
|
+
//! \}
|
439
|
+
|
440
|
+
//! \name Encoding Options
|
441
|
+
//! \{
|
442
|
+
|
443
|
+
//! Returns encoding options.
|
444
|
+
inline EncodingOptions encodingOptions() const noexcept { return _encodingOptions; }
|
445
|
+
//! Tests whether the encoding `option` is set.
|
446
|
+
inline bool hasEncodingOption(EncodingOptions option) const noexcept { return Support::test(_encodingOptions, option); }
|
447
|
+
|
448
|
+
//! Enables the given encoding `options`.
|
449
|
+
inline void addEncodingOptions(EncodingOptions options) noexcept { _encodingOptions |= options; }
|
450
|
+
//! Disables the given encoding `options`.
|
451
|
+
inline void clearEncodingOptions(EncodingOptions options) noexcept { _encodingOptions &= ~options; }
|
452
|
+
|
453
|
+
//! \}
|
454
|
+
|
455
|
+
//! \name Diagnostic Options
|
456
|
+
//! \{
|
457
|
+
|
458
|
+
//! Returns the emitter's diagnostic options.
|
459
|
+
inline DiagnosticOptions diagnosticOptions() const noexcept { return _diagnosticOptions; }
|
460
|
+
|
461
|
+
//! Tests whether the given `option` is present in the emitter's diagnostic options.
|
462
|
+
inline bool hasDiagnosticOption(DiagnosticOptions option) const noexcept { return Support::test(_diagnosticOptions, option); }
|
463
|
+
|
464
|
+
//! Activates the given diagnostic `options`.
|
465
|
+
//!
|
466
|
+
//! This function is used to activate explicit validation options that will be then used by all emitter
|
467
|
+
//! implementations. There are in general two possibilities:
|
468
|
+
//!
|
469
|
+
//! - Architecture specific assembler is used. In this case a \ref DiagnosticOptions::kValidateAssembler can be
|
470
|
+
//! used to turn on explicit validation that will be used before an instruction is emitted. This means that
|
471
|
+
//! internally an extra step will be performed to make sure that the instruction is correct. This is needed,
|
472
|
+
//! because by default assemblers prefer speed over strictness.
|
473
|
+
//!
|
474
|
+
//! This option should be used in debug builds as it's pretty expensive.
|
475
|
+
//!
|
476
|
+
//! - Architecture specific builder or compiler is used. In this case the user can turn on
|
477
|
+
//! \ref DiagnosticOptions::kValidateIntermediate option that adds explicit validation step before the Builder
|
478
|
+
//! or Compiler creates an \ref InstNode to represent an emitted instruction. Error will be returned if the
|
479
|
+
//! instruction is ill-formed. In addition, also \ref DiagnosticOptions::kValidateAssembler can be used, which
|
480
|
+
//! would not be consumed by Builder / Compiler directly, but it would be propagated to an architecture specific
|
481
|
+
//! \ref BaseAssembler implementation it creates during \ref BaseEmitter::finalize().
|
482
|
+
ASMJIT_API void addDiagnosticOptions(DiagnosticOptions options) noexcept;
|
483
|
+
|
484
|
+
//! Deactivates the given validation `options`.
|
485
|
+
//!
|
486
|
+
//! See \ref addDiagnosticOptions() and \ref DiagnosticOptions for more details.
|
487
|
+
ASMJIT_API void clearDiagnosticOptions(DiagnosticOptions options) noexcept;
|
488
|
+
|
489
|
+
//! \}
|
490
|
+
|
491
|
+
//! \name Instruction Options
|
492
|
+
//! \{
|
493
|
+
|
494
|
+
//! Returns forced instruction options.
|
495
|
+
//!
|
496
|
+
//! Forced instruction options are merged with next instruction options before the instruction is encoded. These
|
497
|
+
//! options have some bits reserved that are used by error handling, logging, and instruction validation purposes.
|
498
|
+
//! Other options are globals that affect each instruction.
|
499
|
+
inline InstOptions forcedInstOptions() const noexcept { return _forcedInstOptions; }
|
500
|
+
|
501
|
+
//! Returns options of the next instruction.
|
502
|
+
inline InstOptions instOptions() const noexcept { return _instOptions; }
|
503
|
+
//! Returns options of the next instruction.
|
504
|
+
inline void setInstOptions(InstOptions options) noexcept { _instOptions = options; }
|
505
|
+
//! Adds options of the next instruction.
|
506
|
+
inline void addInstOptions(InstOptions options) noexcept { _instOptions |= options; }
|
507
|
+
//! Resets options of the next instruction.
|
508
|
+
inline void resetInstOptions() noexcept { _instOptions = InstOptions::kNone; }
|
509
|
+
|
510
|
+
//! Tests whether the extra register operand is valid.
|
511
|
+
inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); }
|
512
|
+
//! Returns an extra operand that will be used by the next instruction (architecture specific).
|
513
|
+
inline const RegOnly& extraReg() const noexcept { return _extraReg; }
|
514
|
+
//! Sets an extra operand that will be used by the next instruction (architecture specific).
|
515
|
+
inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); }
|
516
|
+
//! Sets an extra operand that will be used by the next instruction (architecture specific).
|
517
|
+
inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
|
518
|
+
//! Resets an extra operand that will be used by the next instruction (architecture specific).
|
519
|
+
inline void resetExtraReg() noexcept { _extraReg.reset(); }
|
520
|
+
|
521
|
+
//! Returns comment/annotation of the next instruction.
|
522
|
+
inline const char* inlineComment() const noexcept { return _inlineComment; }
|
523
|
+
//! Sets comment/annotation of the next instruction.
|
524
|
+
//!
|
525
|
+
//! \note This string is set back to null by `_emit()`, but until that it has to remain valid as the Emitter is not
|
526
|
+
//! required to make a copy of it (and it would be slow to do that for each instruction).
|
527
|
+
inline void setInlineComment(const char* s) noexcept { _inlineComment = s; }
|
528
|
+
//! Resets the comment/annotation to nullptr.
|
529
|
+
inline void resetInlineComment() noexcept { _inlineComment = nullptr; }
|
530
|
+
|
531
|
+
//! \}
|
532
|
+
|
533
|
+
//! \name Sections
|
534
|
+
//! \{
|
535
|
+
|
536
|
+
virtual Error section(Section* section) = 0;
|
537
|
+
|
538
|
+
//! \}
|
539
|
+
|
540
|
+
//! \name Labels
|
541
|
+
//! \{
|
542
|
+
|
543
|
+
//! Creates a new label.
|
544
|
+
virtual Label newLabel() = 0;
|
545
|
+
//! Creates a new named label.
|
546
|
+
virtual Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, LabelType type = LabelType::kGlobal, uint32_t parentId = Globals::kInvalidId) = 0;
|
547
|
+
|
548
|
+
//! Creates a new anonymous label with a name, which can only be used for debugging purposes.
|
549
|
+
inline Label newAnonymousLabel(const char* name, size_t nameSize = SIZE_MAX) { return newNamedLabel(name, nameSize, LabelType::kAnonymous); }
|
550
|
+
//! Creates a new external label.
|
551
|
+
inline Label newExternalLabel(const char* name, size_t nameSize = SIZE_MAX) { return newNamedLabel(name, nameSize, LabelType::kExternal); }
|
552
|
+
|
553
|
+
//! Returns `Label` by `name`.
|
554
|
+
//!
|
555
|
+
//! Returns invalid Label in case that the name is invalid or label was not found.
|
556
|
+
//!
|
557
|
+
//! \note This function doesn't trigger ErrorHandler in case the name is invalid or no such label exist. You must
|
558
|
+
//! always check the validity of the `Label` returned.
|
559
|
+
ASMJIT_API Label labelByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept;
|
560
|
+
|
561
|
+
//! Binds the `label` to the current position of the current section.
|
562
|
+
//!
|
563
|
+
//! \note Attempt to bind the same label multiple times will return an error.
|
564
|
+
virtual Error bind(const Label& label) = 0;
|
565
|
+
|
566
|
+
//! Tests whether the label `id` is valid (i.e. registered).
|
567
|
+
ASMJIT_API bool isLabelValid(uint32_t labelId) const noexcept;
|
568
|
+
//! Tests whether the `label` is valid (i.e. registered).
|
569
|
+
inline bool isLabelValid(const Label& label) const noexcept { return isLabelValid(label.id()); }
|
570
|
+
|
571
|
+
//! \}
|
572
|
+
|
573
|
+
//! \name Emit
|
574
|
+
//! \{
|
575
|
+
|
576
|
+
// NOTE: These `emit()` helpers are designed to address a code-bloat generated by C++ compilers to call a function
|
577
|
+
// having many arguments. Each parameter to `_emit()` requires some code to pass it, which means that if we default
|
578
|
+
// to 5 arguments in `_emit()` and instId the C++ compiler would have to generate a virtual function call having 5
|
579
|
+
// parameters and additional `this` argument, which is quite a lot. Since by default most instructions have 2 to 3
|
580
|
+
// operands it's better to introduce helpers that pass from 0 to 6 operands that help to reduce the size of emit(...)
|
581
|
+
// function call.
|
582
|
+
|
583
|
+
//! Emits an instruction (internal).
|
584
|
+
ASMJIT_API Error _emitI(InstId instId);
|
585
|
+
//! \overload
|
586
|
+
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0);
|
587
|
+
//! \overload
|
588
|
+
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1);
|
589
|
+
//! \overload
|
590
|
+
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2);
|
591
|
+
//! \overload
|
592
|
+
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3);
|
593
|
+
//! \overload
|
594
|
+
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4);
|
595
|
+
//! \overload
|
596
|
+
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5);
|
597
|
+
|
598
|
+
//! Emits an instruction `instId` with the given `operands`.
|
599
|
+
template<typename... Args>
|
600
|
+
ASMJIT_FORCE_INLINE Error emit(InstId instId, Args&&... operands) {
|
601
|
+
return _emitI(instId, Support::ForwardOp<Args>::forward(operands)...);
|
602
|
+
}
|
603
|
+
|
604
|
+
ASMJIT_FORCE_INLINE Error emitOpArray(InstId instId, const Operand_* operands, size_t opCount) {
|
605
|
+
return _emitOpArray(instId, operands, opCount);
|
606
|
+
}
|
607
|
+
|
608
|
+
ASMJIT_FORCE_INLINE Error emitInst(const BaseInst& inst, const Operand_* operands, size_t opCount) {
|
609
|
+
setInstOptions(inst.options());
|
610
|
+
setExtraReg(inst.extraReg());
|
611
|
+
return _emitOpArray(inst.id(), operands, opCount);
|
612
|
+
}
|
613
|
+
|
614
|
+
//! \cond INTERNAL
|
615
|
+
//! Emits an instruction - all 6 operands must be defined.
|
616
|
+
virtual Error _emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt) = 0;
|
617
|
+
//! Emits instruction having operands stored in array.
|
618
|
+
ASMJIT_API virtual Error _emitOpArray(InstId instId, const Operand_* operands, size_t opCount);
|
619
|
+
//! \endcond
|
620
|
+
|
621
|
+
//! \}
|
622
|
+
|
623
|
+
//! \name Emit Utilities
|
624
|
+
//! \{
|
625
|
+
|
626
|
+
ASMJIT_API Error emitProlog(const FuncFrame& frame);
|
627
|
+
ASMJIT_API Error emitEpilog(const FuncFrame& frame);
|
628
|
+
ASMJIT_API Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args);
|
629
|
+
|
630
|
+
//! \}
|
631
|
+
|
632
|
+
//! \name Align
|
633
|
+
//! \{
|
634
|
+
|
635
|
+
//! Aligns the current CodeBuffer position to the `alignment` specified.
|
636
|
+
//!
|
637
|
+
//! The sequence that is used to fill the gap between the aligned location and the current location depends on the
|
638
|
+
//! align `mode`, see \ref AlignMode. The `alignment` argument specifies alignment in bytes, so for example when
|
639
|
+
//! it's `32` it means that the code buffer will be aligned to `32` bytes.
|
640
|
+
virtual Error align(AlignMode alignMode, uint32_t alignment) = 0;
|
641
|
+
|
642
|
+
//! \}
|
643
|
+
|
644
|
+
//! \name Embed
|
645
|
+
//! \{
|
646
|
+
|
647
|
+
//! Embeds raw data into the \ref CodeBuffer.
|
648
|
+
virtual Error embed(const void* data, size_t dataSize) = 0;
|
649
|
+
|
650
|
+
//! Embeds a typed data array.
|
651
|
+
//!
|
652
|
+
//! This is the most flexible function for embedding data as it allows to:
|
653
|
+
//!
|
654
|
+
//! - Assign a `typeId` to the data, so the emitter knows the type of items stored in `data`. Binary data should
|
655
|
+
//! use \ref TypeId::kUInt8.
|
656
|
+
//!
|
657
|
+
//! - Repeat the given data `repeatCount` times, so the data can be used as a fill pattern for example, or as a
|
658
|
+
//! pattern used by SIMD instructions.
|
659
|
+
virtual Error embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1) = 0;
|
660
|
+
|
661
|
+
//! Embeds int8_t `value` repeated by `repeatCount`.
|
662
|
+
inline Error embedInt8(int8_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt8, &value, 1, repeatCount); }
|
663
|
+
//! Embeds uint8_t `value` repeated by `repeatCount`.
|
664
|
+
inline Error embedUInt8(uint8_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt8, &value, 1, repeatCount); }
|
665
|
+
//! Embeds int16_t `value` repeated by `repeatCount`.
|
666
|
+
inline Error embedInt16(int16_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt16, &value, 1, repeatCount); }
|
667
|
+
//! Embeds uint16_t `value` repeated by `repeatCount`.
|
668
|
+
inline Error embedUInt16(uint16_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt16, &value, 1, repeatCount); }
|
669
|
+
//! Embeds int32_t `value` repeated by `repeatCount`.
|
670
|
+
inline Error embedInt32(int32_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt32, &value, 1, repeatCount); }
|
671
|
+
//! Embeds uint32_t `value` repeated by `repeatCount`.
|
672
|
+
inline Error embedUInt32(uint32_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt32, &value, 1, repeatCount); }
|
673
|
+
//! Embeds int64_t `value` repeated by `repeatCount`.
|
674
|
+
inline Error embedInt64(int64_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt64, &value, 1, repeatCount); }
|
675
|
+
//! Embeds uint64_t `value` repeated by `repeatCount`.
|
676
|
+
inline Error embedUInt64(uint64_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt64, &value, 1, repeatCount); }
|
677
|
+
//! Embeds a floating point `value` repeated by `repeatCount`.
|
678
|
+
inline Error embedFloat(float value, size_t repeatCount = 1) { return embedDataArray(TypeId(TypeUtils::TypeIdOfT<float>::kTypeId), &value, 1, repeatCount); }
|
679
|
+
//! Embeds a floating point `value` repeated by `repeatCount`.
|
680
|
+
inline Error embedDouble(double value, size_t repeatCount = 1) { return embedDataArray(TypeId(TypeUtils::TypeIdOfT<double>::kTypeId), &value, 1, repeatCount); }
|
681
|
+
|
682
|
+
//! Embeds a constant pool at the current offset by performing the following:
|
683
|
+
//! 1. Aligns by using AlignMode::kData to the minimum `pool` alignment.
|
684
|
+
//! 2. Binds the ConstPool label so it's bound to an aligned location.
|
685
|
+
//! 3. Emits ConstPool content.
|
686
|
+
virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0;
|
687
|
+
|
688
|
+
//! Embeds an absolute `label` address as data.
|
689
|
+
//!
|
690
|
+
//! The `dataSize` is an optional argument that can be used to specify the size of the address data. If it's zero
|
691
|
+
//! (default) the address size is deduced from the target architecture (either 4 or 8 bytes).
|
692
|
+
virtual Error embedLabel(const Label& label, size_t dataSize = 0) = 0;
|
693
|
+
|
694
|
+
//! Embeds a delta (distance) between the `label` and `base` calculating it as `label - base`. This function was
|
695
|
+
//! designed to make it easier to embed lookup tables where each index is a relative distance of two labels.
|
696
|
+
virtual Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) = 0;
|
697
|
+
|
698
|
+
//! \}
|
699
|
+
|
700
|
+
//! \name Comment
|
701
|
+
//! \{
|
702
|
+
|
703
|
+
//! Emits a comment stored in `data` with an optional `size` parameter.
|
704
|
+
virtual Error comment(const char* data, size_t size = SIZE_MAX) = 0;
|
705
|
+
|
706
|
+
//! Emits a formatted comment specified by `fmt` and variable number of arguments.
|
707
|
+
ASMJIT_API Error commentf(const char* fmt, ...);
|
708
|
+
//! Emits a formatted comment specified by `fmt` and `ap`.
|
709
|
+
ASMJIT_API Error commentv(const char* fmt, va_list ap);
|
710
|
+
|
711
|
+
//! \}
|
712
|
+
|
713
|
+
//! \name Events
|
714
|
+
//! \{
|
715
|
+
|
716
|
+
//! Called after the emitter was attached to `CodeHolder`.
|
717
|
+
virtual Error onAttach(CodeHolder* ASMJIT_NONNULL(code)) noexcept = 0;
|
718
|
+
//! Called after the emitter was detached from `CodeHolder`.
|
719
|
+
virtual Error onDetach(CodeHolder* ASMJIT_NONNULL(code)) noexcept = 0;
|
720
|
+
|
721
|
+
//! Called when \ref CodeHolder has updated an important setting, which involves the following:
|
722
|
+
//!
|
723
|
+
//! - \ref Logger has been changed (\ref CodeHolder::setLogger() has been called).
|
724
|
+
//!
|
725
|
+
//! - \ref ErrorHandler has been changed (\ref CodeHolder::setErrorHandler() has been called).
|
726
|
+
//!
|
727
|
+
//! This function ensures that the settings are properly propagated from \ref CodeHolder to the emitter.
|
728
|
+
//!
|
729
|
+
//! \note This function is virtual and can be overridden, however, if you do so, always call \ref
|
730
|
+
//! BaseEmitter::onSettingsUpdated() within your own implementation to ensure that the emitter is
|
731
|
+
//! in a consistent state.
|
732
|
+
ASMJIT_API virtual void onSettingsUpdated() noexcept;
|
733
|
+
|
734
|
+
//! \}
|
735
|
+
};
|
736
|
+
|
737
|
+
//! \}
|
738
|
+
|
739
|
+
ASMJIT_END_NAMESPACE
|
740
|
+
|
741
|
+
#endif // ASMJIT_CORE_EMITTER_H_INCLUDED
|