asmjit 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/asmjit.gemspec +1 -1
- data/ext/asmjit/asmjit/.editorconfig +10 -0
- data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
- data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
- data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
- data/ext/asmjit/asmjit/.gitignore +6 -0
- data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
- data/ext/asmjit/asmjit/LICENSE.md +17 -0
- data/ext/asmjit/asmjit/README.md +69 -0
- data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
- data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
- data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
- data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
- data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
- data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
- data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
- data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
- data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
- data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
- data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
- data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
- data/ext/asmjit/asmjit/test/broken.cpp +312 -0
- data/ext/asmjit/asmjit/test/broken.h +148 -0
- data/ext/asmjit/asmjit/test/cmdline.h +61 -0
- data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
- data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
- data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
- data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
- data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
- data/ext/asmjit/asmjit.cc +18 -0
- data/lib/asmjit/version.rb +1 -1
- metadata +197 -2
|
@@ -0,0 +1,1391 @@
|
|
|
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_BUILDER_H_INCLUDED
|
|
7
|
+
#define ASMJIT_CORE_BUILDER_H_INCLUDED
|
|
8
|
+
|
|
9
|
+
#include "../core/api-config.h"
|
|
10
|
+
#ifndef ASMJIT_NO_BUILDER
|
|
11
|
+
|
|
12
|
+
#include "../core/assembler.h"
|
|
13
|
+
#include "../core/codeholder.h"
|
|
14
|
+
#include "../core/constpool.h"
|
|
15
|
+
#include "../core/formatter.h"
|
|
16
|
+
#include "../core/inst.h"
|
|
17
|
+
#include "../core/operand.h"
|
|
18
|
+
#include "../core/string.h"
|
|
19
|
+
#include "../core/support.h"
|
|
20
|
+
#include "../core/type.h"
|
|
21
|
+
#include "../core/zone.h"
|
|
22
|
+
#include "../core/zonevector.h"
|
|
23
|
+
|
|
24
|
+
ASMJIT_BEGIN_NAMESPACE
|
|
25
|
+
|
|
26
|
+
//! \addtogroup asmjit_builder
|
|
27
|
+
//! \{
|
|
28
|
+
|
|
29
|
+
class BaseBuilder;
|
|
30
|
+
class Pass;
|
|
31
|
+
|
|
32
|
+
class BaseNode;
|
|
33
|
+
class InstNode;
|
|
34
|
+
class SectionNode;
|
|
35
|
+
class LabelNode;
|
|
36
|
+
class AlignNode;
|
|
37
|
+
class EmbedDataNode;
|
|
38
|
+
class EmbedLabelNode;
|
|
39
|
+
class ConstPoolNode;
|
|
40
|
+
class CommentNode;
|
|
41
|
+
class SentinelNode;
|
|
42
|
+
class LabelDeltaNode;
|
|
43
|
+
|
|
44
|
+
//! Type of node used by \ref BaseBuilder and \ref BaseCompiler.
|
|
45
|
+
enum class NodeType : uint8_t {
|
|
46
|
+
//! Invalid node (internal, don't use).
|
|
47
|
+
kNone = 0,
|
|
48
|
+
|
|
49
|
+
// [BaseBuilder]
|
|
50
|
+
|
|
51
|
+
//! Node is \ref InstNode or \ref InstExNode.
|
|
52
|
+
kInst = 1,
|
|
53
|
+
//! Node is \ref SectionNode.
|
|
54
|
+
kSection = 2,
|
|
55
|
+
//! Node is \ref LabelNode.
|
|
56
|
+
kLabel = 3,
|
|
57
|
+
//! Node is \ref AlignNode.
|
|
58
|
+
kAlign = 4,
|
|
59
|
+
//! Node is \ref EmbedDataNode.
|
|
60
|
+
kEmbedData = 5,
|
|
61
|
+
//! Node is \ref EmbedLabelNode.
|
|
62
|
+
kEmbedLabel = 6,
|
|
63
|
+
//! Node is \ref EmbedLabelDeltaNode.
|
|
64
|
+
kEmbedLabelDelta = 7,
|
|
65
|
+
//! Node is \ref ConstPoolNode.
|
|
66
|
+
kConstPool = 8,
|
|
67
|
+
//! Node is \ref CommentNode.
|
|
68
|
+
kComment = 9,
|
|
69
|
+
//! Node is \ref SentinelNode.
|
|
70
|
+
kSentinel = 10,
|
|
71
|
+
|
|
72
|
+
// [BaseCompiler]
|
|
73
|
+
|
|
74
|
+
//! Node is \ref JumpNode (acts as InstNode).
|
|
75
|
+
kJump = 15,
|
|
76
|
+
//! Node is \ref FuncNode (acts as LabelNode).
|
|
77
|
+
kFunc = 16,
|
|
78
|
+
//! Node is \ref FuncRetNode (acts as InstNode).
|
|
79
|
+
kFuncRet = 17,
|
|
80
|
+
//! Node is \ref InvokeNode (acts as InstNode).
|
|
81
|
+
kInvoke = 18,
|
|
82
|
+
|
|
83
|
+
// [UserDefined]
|
|
84
|
+
|
|
85
|
+
//! First id of a user-defined node.
|
|
86
|
+
kUser = 32
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
//! Node flags, specify what the node is and/or does.
|
|
90
|
+
enum class NodeFlags : uint8_t {
|
|
91
|
+
//! No flags.
|
|
92
|
+
kNone = 0,
|
|
93
|
+
//! Node is code that can be executed (instruction, label, align, etc...).
|
|
94
|
+
kIsCode = 0x01u,
|
|
95
|
+
//! Node is data that cannot be executed (data, const-pool, etc...).
|
|
96
|
+
kIsData = 0x02u,
|
|
97
|
+
//! Node is informative, can be removed and ignored.
|
|
98
|
+
kIsInformative = 0x04u,
|
|
99
|
+
//! Node can be safely removed if unreachable.
|
|
100
|
+
kIsRemovable = 0x08u,
|
|
101
|
+
//! Node does nothing when executed (label, align, explicit nop).
|
|
102
|
+
kHasNoEffect = 0x10u,
|
|
103
|
+
//! Node is an instruction or acts as it.
|
|
104
|
+
kActsAsInst = 0x20u,
|
|
105
|
+
//! Node is a label or acts as it.
|
|
106
|
+
kActsAsLabel = 0x40u,
|
|
107
|
+
//! Node is active (part of the code).
|
|
108
|
+
kIsActive = 0x80u
|
|
109
|
+
};
|
|
110
|
+
ASMJIT_DEFINE_ENUM_FLAGS(NodeFlags)
|
|
111
|
+
|
|
112
|
+
//! Type of the sentinel (purery informative purpose).
|
|
113
|
+
enum class SentinelType : uint8_t {
|
|
114
|
+
//! Type of the sentinel is not known.
|
|
115
|
+
kUnknown = 0u,
|
|
116
|
+
//! This is a sentinel used at the end of \ref FuncNode.
|
|
117
|
+
kFuncEnd = 1u
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
//! Builder interface.
|
|
121
|
+
//!
|
|
122
|
+
//! `BaseBuilder` interface was designed to be used as a \ref BaseAssembler replacement in case pre-processing or
|
|
123
|
+
//! post-processing of the generated code is required. The code can be modified during or after code generation.
|
|
124
|
+
//! Pre processing or post processing can be done manually or through a \ref Pass object. \ref BaseBuilder stores
|
|
125
|
+
//! the emitted code as a double-linked list of nodes, which allows O(1) insertion and removal during processing.
|
|
126
|
+
//!
|
|
127
|
+
//! Check out architecture specific builders for more details and examples:
|
|
128
|
+
//!
|
|
129
|
+
//! - \ref x86::Builder - X86/X64 builder implementation.
|
|
130
|
+
class ASMJIT_VIRTAPI BaseBuilder : public BaseEmitter {
|
|
131
|
+
public:
|
|
132
|
+
ASMJIT_NONCOPYABLE(BaseBuilder)
|
|
133
|
+
typedef BaseEmitter Base;
|
|
134
|
+
|
|
135
|
+
//! \name Members
|
|
136
|
+
//! \{
|
|
137
|
+
|
|
138
|
+
//! Base zone used to allocate nodes and passes.
|
|
139
|
+
Zone _codeZone;
|
|
140
|
+
//! Data zone used to allocate data and names.
|
|
141
|
+
Zone _dataZone;
|
|
142
|
+
//! Pass zone, passed to `Pass::run()`.
|
|
143
|
+
Zone _passZone;
|
|
144
|
+
//! Allocator that uses `_codeZone`.
|
|
145
|
+
ZoneAllocator _allocator;
|
|
146
|
+
|
|
147
|
+
//! Array of `Pass` objects.
|
|
148
|
+
ZoneVector<Pass*> _passes {};
|
|
149
|
+
//! Maps section indexes to `LabelNode` nodes.
|
|
150
|
+
ZoneVector<SectionNode*> _sectionNodes {};
|
|
151
|
+
//! Maps label indexes to `LabelNode` nodes.
|
|
152
|
+
ZoneVector<LabelNode*> _labelNodes {};
|
|
153
|
+
|
|
154
|
+
//! Current node (cursor).
|
|
155
|
+
BaseNode* _cursor = nullptr;
|
|
156
|
+
//! First node of the current section.
|
|
157
|
+
BaseNode* _firstNode = nullptr;
|
|
158
|
+
//! Last node of the current section.
|
|
159
|
+
BaseNode* _lastNode = nullptr;
|
|
160
|
+
|
|
161
|
+
//! Flags assigned to each new node.
|
|
162
|
+
NodeFlags _nodeFlags = NodeFlags::kNone;
|
|
163
|
+
//! The sections links are dirty (used internally).
|
|
164
|
+
bool _dirtySectionLinks = false;
|
|
165
|
+
|
|
166
|
+
//! \}
|
|
167
|
+
|
|
168
|
+
//! \name Construction & Destruction
|
|
169
|
+
//! \{
|
|
170
|
+
|
|
171
|
+
//! Creates a new `BaseBuilder` instance.
|
|
172
|
+
ASMJIT_API BaseBuilder() noexcept;
|
|
173
|
+
//! Destroys the `BaseBuilder` instance.
|
|
174
|
+
ASMJIT_API virtual ~BaseBuilder() noexcept;
|
|
175
|
+
|
|
176
|
+
//! \}
|
|
177
|
+
|
|
178
|
+
//! \name Node Management
|
|
179
|
+
//! \{
|
|
180
|
+
|
|
181
|
+
//! Returns the first node.
|
|
182
|
+
inline BaseNode* firstNode() const noexcept { return _firstNode; }
|
|
183
|
+
//! Returns the last node.
|
|
184
|
+
inline BaseNode* lastNode() const noexcept { return _lastNode; }
|
|
185
|
+
|
|
186
|
+
//! Allocates and instantiates a new node of type `T` and returns its instance. If the allocation fails `nullptr`
|
|
187
|
+
//! is returned.
|
|
188
|
+
//!
|
|
189
|
+
//! The template argument `T` must be a type that is extends \ref BaseNode.
|
|
190
|
+
//!
|
|
191
|
+
//! \remarks The pointer returned (if non-null) is owned by the Builder or Compiler. When the Builder/Compiler
|
|
192
|
+
//! is destroyed it destroys all nodes it created so no manual memory management is required.
|
|
193
|
+
template<typename T, typename... Args>
|
|
194
|
+
inline Error _newNodeT(T** ASMJIT_NONNULL(out), Args&&... args) {
|
|
195
|
+
*out = _allocator.newT<T>(this, std::forward<Args>(args)...);
|
|
196
|
+
if (ASMJIT_UNLIKELY(!*out))
|
|
197
|
+
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
|
198
|
+
return kErrorOk;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
//! Creates a new \ref InstNode.
|
|
202
|
+
ASMJIT_API Error newInstNode(InstNode** ASMJIT_NONNULL(out), InstId instId, InstOptions instOptions, uint32_t opCount);
|
|
203
|
+
//! Creates a new \ref LabelNode.
|
|
204
|
+
ASMJIT_API Error newLabelNode(LabelNode** ASMJIT_NONNULL(out));
|
|
205
|
+
//! Creates a new \ref AlignNode.
|
|
206
|
+
ASMJIT_API Error newAlignNode(AlignNode** ASMJIT_NONNULL(out), AlignMode alignMode, uint32_t alignment);
|
|
207
|
+
//! Creates a new \ref EmbedDataNode.
|
|
208
|
+
ASMJIT_API Error newEmbedDataNode(EmbedDataNode** ASMJIT_NONNULL(out), TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1);
|
|
209
|
+
//! Creates a new \ref ConstPoolNode.
|
|
210
|
+
ASMJIT_API Error newConstPoolNode(ConstPoolNode** ASMJIT_NONNULL(out));
|
|
211
|
+
//! Creates a new \ref CommentNode.
|
|
212
|
+
ASMJIT_API Error newCommentNode(CommentNode** ASMJIT_NONNULL(out), const char* data, size_t size);
|
|
213
|
+
|
|
214
|
+
//! Adds `node` after the current and sets the current node to the given `node`.
|
|
215
|
+
ASMJIT_API BaseNode* addNode(BaseNode* ASMJIT_NONNULL(node)) noexcept;
|
|
216
|
+
//! Inserts the given `node` after `ref`.
|
|
217
|
+
ASMJIT_API BaseNode* addAfter(BaseNode* ASMJIT_NONNULL(node), BaseNode* ASMJIT_NONNULL(ref)) noexcept;
|
|
218
|
+
//! Inserts the given `node` before `ref`.
|
|
219
|
+
ASMJIT_API BaseNode* addBefore(BaseNode* ASMJIT_NONNULL(node), BaseNode* ASMJIT_NONNULL(ref)) noexcept;
|
|
220
|
+
//! Removes the given `node`.
|
|
221
|
+
ASMJIT_API BaseNode* removeNode(BaseNode* ASMJIT_NONNULL(node)) noexcept;
|
|
222
|
+
//! Removes multiple nodes.
|
|
223
|
+
ASMJIT_API void removeNodes(BaseNode* first, BaseNode* last) noexcept;
|
|
224
|
+
|
|
225
|
+
//! Returns the cursor.
|
|
226
|
+
//!
|
|
227
|
+
//! When the Builder/Compiler is created it automatically creates a '.text' \ref SectionNode, which will be the
|
|
228
|
+
//! initial one. When instructions are added they are always added after the cursor and the cursor is changed
|
|
229
|
+
//! to be that newly added node. Use `setCursor()` to change where new nodes are inserted.
|
|
230
|
+
inline BaseNode* cursor() const noexcept { return _cursor; }
|
|
231
|
+
|
|
232
|
+
//! Sets the current node to `node` and return the previous one.
|
|
233
|
+
ASMJIT_API BaseNode* setCursor(BaseNode* node) noexcept;
|
|
234
|
+
|
|
235
|
+
//! Sets the current node without returning the previous node.
|
|
236
|
+
//!
|
|
237
|
+
//! Only use this function if you are concerned about performance and want this inlined (for example if you set
|
|
238
|
+
//! the cursor in a loop, etc...).
|
|
239
|
+
inline void _setCursor(BaseNode* node) noexcept { _cursor = node; }
|
|
240
|
+
|
|
241
|
+
//! \}
|
|
242
|
+
|
|
243
|
+
//! \name Section Management
|
|
244
|
+
//! \{
|
|
245
|
+
|
|
246
|
+
//! Returns a vector of SectionNode objects.
|
|
247
|
+
//!
|
|
248
|
+
//! \note If a section of some id is not associated with the Builder/Compiler it would be null, so always check
|
|
249
|
+
//! for nulls if you iterate over the vector.
|
|
250
|
+
inline const ZoneVector<SectionNode*>& sectionNodes() const noexcept {
|
|
251
|
+
return _sectionNodes;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
//! Tests whether the `SectionNode` of the given `sectionId` was registered.
|
|
255
|
+
inline bool hasRegisteredSectionNode(uint32_t sectionId) const noexcept {
|
|
256
|
+
return sectionId < _sectionNodes.size() && _sectionNodes[sectionId] != nullptr;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
//! Returns or creates a `SectionNode` that matches the given `sectionId`.
|
|
260
|
+
//!
|
|
261
|
+
//! \remarks This function will either get the existing `SectionNode` or create it in case it wasn't created before.
|
|
262
|
+
//! You can check whether a section has a registered `SectionNode` by using `BaseBuilder::hasRegisteredSectionNode()`.
|
|
263
|
+
ASMJIT_API Error sectionNodeOf(SectionNode** ASMJIT_NONNULL(out), uint32_t sectionId);
|
|
264
|
+
|
|
265
|
+
ASMJIT_API Error section(Section* ASMJIT_NONNULL(section)) override;
|
|
266
|
+
|
|
267
|
+
//! Returns whether the section links of active section nodes are dirty. You can update these links by calling
|
|
268
|
+
//! `updateSectionLinks()` in such case.
|
|
269
|
+
inline bool hasDirtySectionLinks() const noexcept { return _dirtySectionLinks; }
|
|
270
|
+
|
|
271
|
+
//! Updates links of all active section nodes.
|
|
272
|
+
ASMJIT_API void updateSectionLinks() noexcept;
|
|
273
|
+
|
|
274
|
+
//! \}
|
|
275
|
+
|
|
276
|
+
//! \name Label Management
|
|
277
|
+
//! \{
|
|
278
|
+
|
|
279
|
+
//! Returns a vector of \ref LabelNode nodes.
|
|
280
|
+
//!
|
|
281
|
+
//! \note If a label of some id is not associated with the Builder/Compiler it would be null, so always check for
|
|
282
|
+
//! nulls if you iterate over the vector.
|
|
283
|
+
inline const ZoneVector<LabelNode*>& labelNodes() const noexcept { return _labelNodes; }
|
|
284
|
+
|
|
285
|
+
//! Tests whether the `LabelNode` of the given `labelId` was registered.
|
|
286
|
+
inline bool hasRegisteredLabelNode(uint32_t labelId) const noexcept {
|
|
287
|
+
return labelId < _labelNodes.size() && _labelNodes[labelId] != nullptr;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
//! \overload
|
|
291
|
+
inline bool hasRegisteredLabelNode(const Label& label) const noexcept {
|
|
292
|
+
return hasRegisteredLabelNode(label.id());
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
//! Gets or creates a \ref LabelNode that matches the given `labelId`.
|
|
296
|
+
//!
|
|
297
|
+
//! \remarks This function will either get the existing `LabelNode` or create it in case it wasn't created before.
|
|
298
|
+
//! You can check whether a label has a registered `LabelNode` by calling \ref BaseBuilder::hasRegisteredLabelNode().
|
|
299
|
+
ASMJIT_API Error labelNodeOf(LabelNode** ASMJIT_NONNULL(out), uint32_t labelId);
|
|
300
|
+
|
|
301
|
+
//! \overload
|
|
302
|
+
inline Error labelNodeOf(LabelNode** ASMJIT_NONNULL(out), const Label& label) {
|
|
303
|
+
return labelNodeOf(out, label.id());
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
//! Registers this \ref LabelNode (internal).
|
|
307
|
+
//!
|
|
308
|
+
//! This function is used internally to register a newly created `LabelNode` with this instance of Builder/Compiler.
|
|
309
|
+
//! Use \ref labelNodeOf() functions to get back \ref LabelNode from a label or its identifier.
|
|
310
|
+
ASMJIT_API Error registerLabelNode(LabelNode* ASMJIT_NONNULL(node));
|
|
311
|
+
|
|
312
|
+
ASMJIT_API Label newLabel() override;
|
|
313
|
+
ASMJIT_API Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, LabelType type = LabelType::kGlobal, uint32_t parentId = Globals::kInvalidId) override;
|
|
314
|
+
ASMJIT_API Error bind(const Label& label) override;
|
|
315
|
+
|
|
316
|
+
//! \}
|
|
317
|
+
|
|
318
|
+
//! \name Passes
|
|
319
|
+
//! \{
|
|
320
|
+
|
|
321
|
+
//! Returns a vector of `Pass` instances that will be executed by `runPasses()`.
|
|
322
|
+
inline const ZoneVector<Pass*>& passes() const noexcept { return _passes; }
|
|
323
|
+
|
|
324
|
+
//! Allocates and instantiates a new pass of type `T` and returns its instance. If the allocation fails `nullptr` is
|
|
325
|
+
//! returned.
|
|
326
|
+
//!
|
|
327
|
+
//! The template argument `T` must be a type that is extends \ref Pass.
|
|
328
|
+
//!
|
|
329
|
+
//! \remarks The pointer returned (if non-null) is owned by the Builder or Compiler. When the Builder/Compiler is
|
|
330
|
+
//! destroyed it destroys all passes it created so no manual memory management is required.
|
|
331
|
+
template<typename T>
|
|
332
|
+
inline T* newPassT() noexcept { return _codeZone.newT<T>(); }
|
|
333
|
+
|
|
334
|
+
//! \overload
|
|
335
|
+
template<typename T, typename... Args>
|
|
336
|
+
inline T* newPassT(Args&&... args) noexcept { return _codeZone.newT<T>(std::forward<Args>(args)...); }
|
|
337
|
+
|
|
338
|
+
template<typename T>
|
|
339
|
+
inline Error addPassT() { return addPass(newPassT<T>()); }
|
|
340
|
+
|
|
341
|
+
template<typename T, typename... Args>
|
|
342
|
+
inline Error addPassT(Args&&... args) { return addPass(newPassT<T, Args...>(std::forward<Args>(args)...)); }
|
|
343
|
+
|
|
344
|
+
//! Returns `Pass` by name.
|
|
345
|
+
//!
|
|
346
|
+
//! If the pass having the given `name` doesn't exist `nullptr` is returned.
|
|
347
|
+
ASMJIT_API Pass* passByName(const char* name) const noexcept;
|
|
348
|
+
//! Adds `pass` to the list of passes.
|
|
349
|
+
ASMJIT_API Error addPass(Pass* pass) noexcept;
|
|
350
|
+
//! Removes `pass` from the list of passes and delete it.
|
|
351
|
+
ASMJIT_API Error deletePass(Pass* pass) noexcept;
|
|
352
|
+
|
|
353
|
+
//! Runs all passes in order.
|
|
354
|
+
ASMJIT_API Error runPasses();
|
|
355
|
+
|
|
356
|
+
//! \}
|
|
357
|
+
|
|
358
|
+
//! \name Emit
|
|
359
|
+
//! \{
|
|
360
|
+
|
|
361
|
+
ASMJIT_API Error _emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) override;
|
|
362
|
+
|
|
363
|
+
//! \}
|
|
364
|
+
|
|
365
|
+
//! \name Align
|
|
366
|
+
//! \{
|
|
367
|
+
|
|
368
|
+
ASMJIT_API Error align(AlignMode alignMode, uint32_t alignment) override;
|
|
369
|
+
|
|
370
|
+
//! \}
|
|
371
|
+
|
|
372
|
+
//! \name Embed
|
|
373
|
+
//! \{
|
|
374
|
+
|
|
375
|
+
ASMJIT_API Error embed(const void* data, size_t dataSize) override;
|
|
376
|
+
ASMJIT_API Error embedDataArray(TypeId typeId, const void* data, size_t count, size_t repeat = 1) override;
|
|
377
|
+
ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override;
|
|
378
|
+
|
|
379
|
+
ASMJIT_API Error embedLabel(const Label& label, size_t dataSize = 0) override;
|
|
380
|
+
ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) override;
|
|
381
|
+
|
|
382
|
+
//! \}
|
|
383
|
+
|
|
384
|
+
//! \name Comment
|
|
385
|
+
//! \{
|
|
386
|
+
|
|
387
|
+
ASMJIT_API Error comment(const char* data, size_t size = SIZE_MAX) override;
|
|
388
|
+
|
|
389
|
+
//! \}
|
|
390
|
+
|
|
391
|
+
//! \name Serialization
|
|
392
|
+
//! \{
|
|
393
|
+
|
|
394
|
+
//! Serializes everything the given emitter `dst`.
|
|
395
|
+
//!
|
|
396
|
+
//! Although not explicitly required the emitter will most probably be of Assembler type. The reason is that
|
|
397
|
+
//! there is no known use of serializing nodes held by Builder/Compiler into another Builder-like emitter.
|
|
398
|
+
ASMJIT_API Error serializeTo(BaseEmitter* dst);
|
|
399
|
+
|
|
400
|
+
//! \}
|
|
401
|
+
|
|
402
|
+
//! \name Events
|
|
403
|
+
//! \{
|
|
404
|
+
|
|
405
|
+
ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
|
|
406
|
+
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
|
|
407
|
+
|
|
408
|
+
//! \}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
//! Base node.
|
|
412
|
+
//!
|
|
413
|
+
//! Every node represents a building-block used by \ref BaseBuilder. It can be instruction, data, label, comment,
|
|
414
|
+
//! directive, or any other high-level representation that can be transformed to the building blocks mentioned.
|
|
415
|
+
//! Every class that inherits \ref BaseBuilder can define its own high-level nodes that can be later lowered to
|
|
416
|
+
//! basic nodes like instructions.
|
|
417
|
+
class BaseNode {
|
|
418
|
+
public:
|
|
419
|
+
ASMJIT_NONCOPYABLE(BaseNode)
|
|
420
|
+
|
|
421
|
+
//! \name Members
|
|
422
|
+
//! \{
|
|
423
|
+
|
|
424
|
+
union {
|
|
425
|
+
struct {
|
|
426
|
+
//! Previous node.
|
|
427
|
+
BaseNode* _prev;
|
|
428
|
+
//! Next node.
|
|
429
|
+
BaseNode* _next;
|
|
430
|
+
};
|
|
431
|
+
//! Links (an alternative view to previous and next nodes).
|
|
432
|
+
BaseNode* _links[2];
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
//! Data shared between all types of nodes.
|
|
436
|
+
struct AnyData {
|
|
437
|
+
//! Node type.
|
|
438
|
+
NodeType _nodeType;
|
|
439
|
+
//! Node flags.
|
|
440
|
+
NodeFlags _nodeFlags;
|
|
441
|
+
//! Not used by BaseNode.
|
|
442
|
+
uint8_t _reserved0;
|
|
443
|
+
//! Not used by BaseNode.
|
|
444
|
+
uint8_t _reserved1;
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
//! Data used by \ref AlignNode.
|
|
448
|
+
struct AlignData {
|
|
449
|
+
//! Node type.
|
|
450
|
+
NodeType _nodeType;
|
|
451
|
+
//! Node flags.
|
|
452
|
+
NodeFlags _nodeFlags;
|
|
453
|
+
//! Align mode.
|
|
454
|
+
AlignMode _alignMode;
|
|
455
|
+
//! Not used by AlignNode.
|
|
456
|
+
uint8_t _reserved;
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
//! Data used by \ref InstNode.
|
|
460
|
+
struct InstData {
|
|
461
|
+
//! Node type.
|
|
462
|
+
NodeType _nodeType;
|
|
463
|
+
//! Node flags.
|
|
464
|
+
NodeFlags _nodeFlags;
|
|
465
|
+
//! Instruction operands count (used).
|
|
466
|
+
uint8_t _opCount;
|
|
467
|
+
//! Instruction operands capacity (allocated).
|
|
468
|
+
uint8_t _opCapacity;
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
//! Data used by \ref EmbedDataNode.
|
|
472
|
+
struct EmbedData {
|
|
473
|
+
//! Node type.
|
|
474
|
+
NodeType _nodeType;
|
|
475
|
+
//! Node flags.
|
|
476
|
+
NodeFlags _nodeFlags;
|
|
477
|
+
//! Type id.
|
|
478
|
+
TypeId _typeId;
|
|
479
|
+
//! Size of `_typeId`.
|
|
480
|
+
uint8_t _typeSize;
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
//! Data used by \ref SentinelNode.
|
|
484
|
+
struct SentinelData {
|
|
485
|
+
//! Node type.
|
|
486
|
+
NodeType _nodeType;
|
|
487
|
+
//! Node flags.
|
|
488
|
+
NodeFlags _nodeFlags;
|
|
489
|
+
//! Sentinel type.
|
|
490
|
+
SentinelType _sentinelType;
|
|
491
|
+
//! Not used by BaseNode.
|
|
492
|
+
uint8_t _reserved1;
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
//! Data that can have different meaning dependning on \ref NodeType.
|
|
496
|
+
union {
|
|
497
|
+
//! Data useful by any node type.
|
|
498
|
+
AnyData _any;
|
|
499
|
+
//! Data specific to \ref AlignNode.
|
|
500
|
+
AlignData _alignData;
|
|
501
|
+
//! Data specific to \ref InstNode.
|
|
502
|
+
InstData _inst;
|
|
503
|
+
//! Data specific to \ref EmbedDataNode.
|
|
504
|
+
EmbedData _embed;
|
|
505
|
+
//! Data specific to \ref SentinelNode.
|
|
506
|
+
SentinelData _sentinel;
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
//! Node position in code (should be unique).
|
|
510
|
+
uint32_t _position;
|
|
511
|
+
|
|
512
|
+
//! Value reserved for AsmJit users never touched by AsmJit itself.
|
|
513
|
+
union {
|
|
514
|
+
//! User data as 64-bit integer.
|
|
515
|
+
uint64_t _userDataU64;
|
|
516
|
+
//! User data as pointer.
|
|
517
|
+
void* _userDataPtr;
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
//! Data used exclusively by the current `Pass`.
|
|
521
|
+
void* _passData;
|
|
522
|
+
|
|
523
|
+
//! Inline comment/annotation or nullptr if not used.
|
|
524
|
+
const char* _inlineComment;
|
|
525
|
+
|
|
526
|
+
//! \}
|
|
527
|
+
|
|
528
|
+
//! \name Construction & Destruction
|
|
529
|
+
//! \{
|
|
530
|
+
|
|
531
|
+
//! Creates a new `BaseNode` - always use `BaseBuilder` to allocate nodes.
|
|
532
|
+
inline BaseNode(BaseBuilder* cb, NodeType nodeType, NodeFlags nodeFlags = NodeFlags::kNone) noexcept {
|
|
533
|
+
_prev = nullptr;
|
|
534
|
+
_next = nullptr;
|
|
535
|
+
_any._nodeType = nodeType;
|
|
536
|
+
_any._nodeFlags = nodeFlags | cb->_nodeFlags;
|
|
537
|
+
_any._reserved0 = 0;
|
|
538
|
+
_any._reserved1 = 0;
|
|
539
|
+
_position = 0;
|
|
540
|
+
_userDataU64 = 0;
|
|
541
|
+
_passData = nullptr;
|
|
542
|
+
_inlineComment = nullptr;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
//! \}
|
|
546
|
+
|
|
547
|
+
//! \name Accessors
|
|
548
|
+
//! \{
|
|
549
|
+
|
|
550
|
+
//! Casts this node to `T*`.
|
|
551
|
+
template<typename T>
|
|
552
|
+
inline T* as() noexcept { return static_cast<T*>(this); }
|
|
553
|
+
//! Casts this node to `const T*`.
|
|
554
|
+
template<typename T>
|
|
555
|
+
inline const T* as() const noexcept { return static_cast<const T*>(this); }
|
|
556
|
+
|
|
557
|
+
//! Returns previous node or `nullptr` if this node is either first or not
|
|
558
|
+
//! part of Builder/Compiler node-list.
|
|
559
|
+
inline BaseNode* prev() const noexcept { return _prev; }
|
|
560
|
+
//! Returns next node or `nullptr` if this node is either last or not part
|
|
561
|
+
//! of Builder/Compiler node-list.
|
|
562
|
+
inline BaseNode* next() const noexcept { return _next; }
|
|
563
|
+
|
|
564
|
+
//! Returns the type of the node, see `NodeType`.
|
|
565
|
+
inline NodeType type() const noexcept { return _any._nodeType; }
|
|
566
|
+
|
|
567
|
+
//! Sets the type of the node, see `NodeType` (internal).
|
|
568
|
+
//!
|
|
569
|
+
//! \remarks You should never set a type of a node to anything else than the initial value. This function is only
|
|
570
|
+
//! provided for users that use custom nodes and need to change the type either during construction or later.
|
|
571
|
+
inline void setType(NodeType type) noexcept { _any._nodeType = type; }
|
|
572
|
+
|
|
573
|
+
//! Tests whether this node is either `InstNode` or extends it.
|
|
574
|
+
inline bool isInst() const noexcept { return hasFlag(NodeFlags::kActsAsInst); }
|
|
575
|
+
//! Tests whether this node is `SectionNode`.
|
|
576
|
+
inline bool isSection() const noexcept { return type() == NodeType::kSection; }
|
|
577
|
+
//! Tests whether this node is either `LabelNode` or extends it.
|
|
578
|
+
inline bool isLabel() const noexcept { return hasFlag(NodeFlags::kActsAsLabel); }
|
|
579
|
+
//! Tests whether this node is `AlignNode`.
|
|
580
|
+
inline bool isAlign() const noexcept { return type() == NodeType::kAlign; }
|
|
581
|
+
//! Tests whether this node is `EmbedDataNode`.
|
|
582
|
+
inline bool isEmbedData() const noexcept { return type() == NodeType::kEmbedData; }
|
|
583
|
+
//! Tests whether this node is `EmbedLabelNode`.
|
|
584
|
+
inline bool isEmbedLabel() const noexcept { return type() == NodeType::kEmbedLabel; }
|
|
585
|
+
//! Tests whether this node is `EmbedLabelDeltaNode`.
|
|
586
|
+
inline bool isEmbedLabelDelta() const noexcept { return type() == NodeType::kEmbedLabelDelta; }
|
|
587
|
+
//! Tests whether this node is `ConstPoolNode`.
|
|
588
|
+
inline bool isConstPool() const noexcept { return type() == NodeType::kConstPool; }
|
|
589
|
+
//! Tests whether this node is `CommentNode`.
|
|
590
|
+
inline bool isComment() const noexcept { return type() == NodeType::kComment; }
|
|
591
|
+
//! Tests whether this node is `SentinelNode`.
|
|
592
|
+
inline bool isSentinel() const noexcept { return type() == NodeType::kSentinel; }
|
|
593
|
+
|
|
594
|
+
//! Tests whether this node is `FuncNode`.
|
|
595
|
+
inline bool isFunc() const noexcept { return type() == NodeType::kFunc; }
|
|
596
|
+
//! Tests whether this node is `FuncRetNode`.
|
|
597
|
+
inline bool isFuncRet() const noexcept { return type() == NodeType::kFuncRet; }
|
|
598
|
+
//! Tests whether this node is `InvokeNode`.
|
|
599
|
+
inline bool isInvoke() const noexcept { return type() == NodeType::kInvoke; }
|
|
600
|
+
|
|
601
|
+
//! Returns the node flags.
|
|
602
|
+
inline NodeFlags flags() const noexcept { return _any._nodeFlags; }
|
|
603
|
+
//! Tests whether the node has the given `flag` set.
|
|
604
|
+
inline bool hasFlag(NodeFlags flag) const noexcept { return Support::test(_any._nodeFlags, flag); }
|
|
605
|
+
//! Replaces node flags with `flags`.
|
|
606
|
+
inline void setFlags(NodeFlags flags) noexcept { _any._nodeFlags = flags; }
|
|
607
|
+
//! Adds the given `flags` to node flags.
|
|
608
|
+
inline void addFlags(NodeFlags flags) noexcept { _any._nodeFlags |= flags; }
|
|
609
|
+
//! Clears the given `flags` from node flags.
|
|
610
|
+
inline void clearFlags(NodeFlags flags) noexcept { _any._nodeFlags &= ~flags; }
|
|
611
|
+
|
|
612
|
+
//! Tests whether the node is code that can be executed.
|
|
613
|
+
inline bool isCode() const noexcept { return hasFlag(NodeFlags::kIsCode); }
|
|
614
|
+
//! Tests whether the node is data that cannot be executed.
|
|
615
|
+
inline bool isData() const noexcept { return hasFlag(NodeFlags::kIsData); }
|
|
616
|
+
//! Tests whether the node is informative only (is never encoded like comment, etc...).
|
|
617
|
+
inline bool isInformative() const noexcept { return hasFlag(NodeFlags::kIsInformative); }
|
|
618
|
+
//! Tests whether the node is removable if it's in an unreachable code block.
|
|
619
|
+
inline bool isRemovable() const noexcept { return hasFlag(NodeFlags::kIsRemovable); }
|
|
620
|
+
//! Tests whether the node has no effect when executed (label, .align, nop, ...).
|
|
621
|
+
inline bool hasNoEffect() const noexcept { return hasFlag(NodeFlags::kHasNoEffect); }
|
|
622
|
+
//! Tests whether the node is part of the code.
|
|
623
|
+
inline bool isActive() const noexcept { return hasFlag(NodeFlags::kIsActive); }
|
|
624
|
+
|
|
625
|
+
//! Tests whether the node has a position assigned.
|
|
626
|
+
//!
|
|
627
|
+
//! \remarks Returns `true` if node position is non-zero.
|
|
628
|
+
inline bool hasPosition() const noexcept { return _position != 0; }
|
|
629
|
+
//! Returns node position.
|
|
630
|
+
inline uint32_t position() const noexcept { return _position; }
|
|
631
|
+
//! Sets node position.
|
|
632
|
+
//!
|
|
633
|
+
//! Node position is a 32-bit unsigned integer that is used by Compiler to track where the node is relatively to
|
|
634
|
+
//! the start of the function. It doesn't describe a byte position in a binary, instead it's just a pseudo position
|
|
635
|
+
//! used by liveness analysis and other tools around Compiler.
|
|
636
|
+
//!
|
|
637
|
+
//! If you don't use Compiler then you may use `position()` and `setPosition()` freely for your own purposes if
|
|
638
|
+
//! the 32-bit value limit is okay for you.
|
|
639
|
+
inline void setPosition(uint32_t position) noexcept { _position = position; }
|
|
640
|
+
|
|
641
|
+
//! Returns user data casted to `T*`.
|
|
642
|
+
//!
|
|
643
|
+
//! User data is decicated to be used only by AsmJit users and not touched by the library. The data has a pointer
|
|
644
|
+
//! size so you can either store a pointer or `intptr_t` value through `setUserDataAsIntPtr()`.
|
|
645
|
+
template<typename T>
|
|
646
|
+
inline T* userDataAsPtr() const noexcept { return static_cast<T*>(_userDataPtr); }
|
|
647
|
+
//! Returns user data casted to `int64_t`.
|
|
648
|
+
inline int64_t userDataAsInt64() const noexcept { return int64_t(_userDataU64); }
|
|
649
|
+
//! Returns user data casted to `uint64_t`.
|
|
650
|
+
inline uint64_t userDataAsUInt64() const noexcept { return _userDataU64; }
|
|
651
|
+
|
|
652
|
+
//! Sets user data to `data`.
|
|
653
|
+
template<typename T>
|
|
654
|
+
inline void setUserDataAsPtr(T* data) noexcept { _userDataPtr = static_cast<void*>(data); }
|
|
655
|
+
//! Sets used data to the given 64-bit signed `value`.
|
|
656
|
+
inline void setUserDataAsInt64(int64_t value) noexcept { _userDataU64 = uint64_t(value); }
|
|
657
|
+
//! Sets used data to the given 64-bit unsigned `value`.
|
|
658
|
+
inline void setUserDataAsUInt64(uint64_t value) noexcept { _userDataU64 = value; }
|
|
659
|
+
|
|
660
|
+
//! Resets user data to zero / nullptr.
|
|
661
|
+
inline void resetUserData() noexcept { _userDataU64 = 0; }
|
|
662
|
+
|
|
663
|
+
//! Tests whether the node has an associated pass data.
|
|
664
|
+
inline bool hasPassData() const noexcept { return _passData != nullptr; }
|
|
665
|
+
//! Returns the node pass data - data used during processing & transformations.
|
|
666
|
+
template<typename T>
|
|
667
|
+
inline T* passData() const noexcept { return (T*)_passData; }
|
|
668
|
+
//! Sets the node pass data to `data`.
|
|
669
|
+
template<typename T>
|
|
670
|
+
inline void setPassData(T* data) noexcept { _passData = (void*)data; }
|
|
671
|
+
//! Resets the node pass data to nullptr.
|
|
672
|
+
inline void resetPassData() noexcept { _passData = nullptr; }
|
|
673
|
+
|
|
674
|
+
//! Tests whether the node has an inline comment/annotation.
|
|
675
|
+
inline bool hasInlineComment() const noexcept { return _inlineComment != nullptr; }
|
|
676
|
+
//! Returns an inline comment/annotation string.
|
|
677
|
+
inline const char* inlineComment() const noexcept { return _inlineComment; }
|
|
678
|
+
//! Sets an inline comment/annotation string to `s`.
|
|
679
|
+
inline void setInlineComment(const char* s) noexcept { _inlineComment = s; }
|
|
680
|
+
//! Resets an inline comment/annotation string to nullptr.
|
|
681
|
+
inline void resetInlineComment() noexcept { _inlineComment = nullptr; }
|
|
682
|
+
|
|
683
|
+
//! \}
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
//! Instruction node.
|
|
687
|
+
//!
|
|
688
|
+
//! Wraps an instruction with its options and operands.
|
|
689
|
+
class InstNode : public BaseNode {
|
|
690
|
+
public:
|
|
691
|
+
ASMJIT_NONCOPYABLE(InstNode)
|
|
692
|
+
|
|
693
|
+
//! \name Constants
|
|
694
|
+
//! \{
|
|
695
|
+
|
|
696
|
+
enum : uint32_t {
|
|
697
|
+
//! Count of embedded operands per `InstNode` that are always allocated as a part of the instruction. Minimum
|
|
698
|
+
//! embedded operands is 4, but in 32-bit more pointers are smaller and we can embed 5. The rest (up to 6 operands)
|
|
699
|
+
//! is always stored in `InstExNode`.
|
|
700
|
+
kBaseOpCapacity = uint32_t((128 - sizeof(BaseNode) - sizeof(BaseInst)) / sizeof(Operand_))
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
//! \}
|
|
704
|
+
|
|
705
|
+
//! \name Members
|
|
706
|
+
//! \{
|
|
707
|
+
|
|
708
|
+
//! Base instruction data.
|
|
709
|
+
BaseInst _baseInst;
|
|
710
|
+
//! First 4 or 5 operands (indexed from 0).
|
|
711
|
+
Operand_ _opArray[kBaseOpCapacity];
|
|
712
|
+
|
|
713
|
+
//! \}
|
|
714
|
+
|
|
715
|
+
//! \name Construction & Destruction
|
|
716
|
+
//! \{
|
|
717
|
+
|
|
718
|
+
//! Creates a new `InstNode` instance.
|
|
719
|
+
inline InstNode(BaseBuilder* cb, InstId instId, InstOptions options, uint32_t opCount, uint32_t opCapacity = kBaseOpCapacity) noexcept
|
|
720
|
+
: BaseNode(cb, NodeType::kInst, NodeFlags::kIsCode | NodeFlags::kIsRemovable | NodeFlags::kActsAsInst),
|
|
721
|
+
_baseInst(instId, options) {
|
|
722
|
+
_inst._opCapacity = uint8_t(opCapacity);
|
|
723
|
+
_inst._opCount = uint8_t(opCount);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
//! \cond INTERNAL
|
|
727
|
+
//! Reset all built-in operands, including `extraReg`.
|
|
728
|
+
inline void _resetOps() noexcept {
|
|
729
|
+
_baseInst.resetExtraReg();
|
|
730
|
+
resetOpRange(0, opCapacity());
|
|
731
|
+
}
|
|
732
|
+
//! \endcond
|
|
733
|
+
|
|
734
|
+
//! \}
|
|
735
|
+
|
|
736
|
+
//! \name Instruction Object
|
|
737
|
+
//! \{
|
|
738
|
+
|
|
739
|
+
inline BaseInst& baseInst() noexcept { return _baseInst; }
|
|
740
|
+
inline const BaseInst& baseInst() const noexcept { return _baseInst; }
|
|
741
|
+
|
|
742
|
+
//! \}
|
|
743
|
+
|
|
744
|
+
//! \name Instruction Id
|
|
745
|
+
//! \{
|
|
746
|
+
|
|
747
|
+
//! Returns the instruction id, see `BaseInst::Id`.
|
|
748
|
+
inline InstId id() const noexcept { return _baseInst.id(); }
|
|
749
|
+
//! Returns the instruction real id, see `BaseInst::Id`.
|
|
750
|
+
inline InstId realId() const noexcept { return _baseInst.realId(); }
|
|
751
|
+
|
|
752
|
+
//! Sets the instruction id to `id`, see `BaseInst::Id`.
|
|
753
|
+
inline void setId(InstId id) noexcept { _baseInst.setId(id); }
|
|
754
|
+
|
|
755
|
+
//! \}
|
|
756
|
+
|
|
757
|
+
//! \name Instruction Options
|
|
758
|
+
//! \{
|
|
759
|
+
|
|
760
|
+
inline InstOptions options() const noexcept { return _baseInst.options(); }
|
|
761
|
+
inline bool hasOption(InstOptions option) const noexcept { return _baseInst.hasOption(option); }
|
|
762
|
+
inline void setOptions(InstOptions options) noexcept { _baseInst.setOptions(options); }
|
|
763
|
+
inline void addOptions(InstOptions options) noexcept { _baseInst.addOptions(options); }
|
|
764
|
+
inline void clearOptions(InstOptions options) noexcept { _baseInst.clearOptions(options); }
|
|
765
|
+
inline void resetOptions() noexcept { _baseInst.resetOptions(); }
|
|
766
|
+
|
|
767
|
+
//! \}
|
|
768
|
+
|
|
769
|
+
//! \name Extra Register
|
|
770
|
+
//! \{
|
|
771
|
+
|
|
772
|
+
//! Tests whether the node has an extra register operand.
|
|
773
|
+
inline bool hasExtraReg() const noexcept { return _baseInst.hasExtraReg(); }
|
|
774
|
+
//! Returns extra register operand.
|
|
775
|
+
inline RegOnly& extraReg() noexcept { return _baseInst.extraReg(); }
|
|
776
|
+
//! \overload
|
|
777
|
+
inline const RegOnly& extraReg() const noexcept { return _baseInst.extraReg(); }
|
|
778
|
+
//! Sets extra register operand to `reg`.
|
|
779
|
+
inline void setExtraReg(const BaseReg& reg) noexcept { _baseInst.setExtraReg(reg); }
|
|
780
|
+
//! Sets extra register operand to `reg`.
|
|
781
|
+
inline void setExtraReg(const RegOnly& reg) noexcept { _baseInst.setExtraReg(reg); }
|
|
782
|
+
//! Resets extra register operand.
|
|
783
|
+
inline void resetExtraReg() noexcept { _baseInst.resetExtraReg(); }
|
|
784
|
+
|
|
785
|
+
//! \}
|
|
786
|
+
|
|
787
|
+
//! \name Instruction Operands
|
|
788
|
+
//! \{
|
|
789
|
+
|
|
790
|
+
//! Returns operand count.
|
|
791
|
+
inline uint32_t opCount() const noexcept { return _inst._opCount; }
|
|
792
|
+
//! Returns operand capacity.
|
|
793
|
+
inline uint32_t opCapacity() const noexcept { return _inst._opCapacity; }
|
|
794
|
+
|
|
795
|
+
//! Sets operand count.
|
|
796
|
+
inline void setOpCount(uint32_t opCount) noexcept { _inst._opCount = uint8_t(opCount); }
|
|
797
|
+
|
|
798
|
+
//! Returns operands array.
|
|
799
|
+
inline Operand* operands() noexcept { return (Operand*)_opArray; }
|
|
800
|
+
//! Returns operands array (const).
|
|
801
|
+
inline const Operand* operands() const noexcept { return (const Operand*)_opArray; }
|
|
802
|
+
|
|
803
|
+
//! Returns operand at the given `index`.
|
|
804
|
+
inline Operand& op(uint32_t index) noexcept {
|
|
805
|
+
ASMJIT_ASSERT(index < opCapacity());
|
|
806
|
+
return _opArray[index].as<Operand>();
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
//! Returns operand at the given `index` (const).
|
|
810
|
+
inline const Operand& op(uint32_t index) const noexcept {
|
|
811
|
+
ASMJIT_ASSERT(index < opCapacity());
|
|
812
|
+
return _opArray[index].as<Operand>();
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
//! Sets operand at the given `index` to `op`.
|
|
816
|
+
inline void setOp(uint32_t index, const Operand_& op) noexcept {
|
|
817
|
+
ASMJIT_ASSERT(index < opCapacity());
|
|
818
|
+
_opArray[index].copyFrom(op);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
//! Resets operand at the given `index` to none.
|
|
822
|
+
inline void resetOp(uint32_t index) noexcept {
|
|
823
|
+
ASMJIT_ASSERT(index < opCapacity());
|
|
824
|
+
_opArray[index].reset();
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
//! Resets operands at `[start, end)` range.
|
|
828
|
+
inline void resetOpRange(uint32_t start, uint32_t end) noexcept {
|
|
829
|
+
for (uint32_t i = start; i < end; i++)
|
|
830
|
+
_opArray[i].reset();
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
//! \}
|
|
834
|
+
|
|
835
|
+
//! \name Utilities
|
|
836
|
+
//! \{
|
|
837
|
+
|
|
838
|
+
inline bool hasOpType(OperandType opType) const noexcept {
|
|
839
|
+
for (uint32_t i = 0, count = opCount(); i < count; i++)
|
|
840
|
+
if (_opArray[i].opType() == opType)
|
|
841
|
+
return true;
|
|
842
|
+
return false;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
inline bool hasRegOp() const noexcept { return hasOpType(OperandType::kReg); }
|
|
846
|
+
inline bool hasMemOp() const noexcept { return hasOpType(OperandType::kMem); }
|
|
847
|
+
inline bool hasImmOp() const noexcept { return hasOpType(OperandType::kImm); }
|
|
848
|
+
inline bool hasLabelOp() const noexcept { return hasOpType(OperandType::kLabel); }
|
|
849
|
+
|
|
850
|
+
inline uint32_t indexOfOpType(OperandType opType) const noexcept {
|
|
851
|
+
uint32_t i = 0;
|
|
852
|
+
uint32_t count = opCount();
|
|
853
|
+
|
|
854
|
+
while (i < count) {
|
|
855
|
+
if (_opArray[i].opType() == opType)
|
|
856
|
+
break;
|
|
857
|
+
i++;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
return i;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
inline uint32_t indexOfMemOp() const noexcept { return indexOfOpType(OperandType::kMem); }
|
|
864
|
+
inline uint32_t indexOfImmOp() const noexcept { return indexOfOpType(OperandType::kImm); }
|
|
865
|
+
inline uint32_t indexOfLabelOp() const noexcept { return indexOfOpType(OperandType::kLabel); }
|
|
866
|
+
|
|
867
|
+
//! \}
|
|
868
|
+
|
|
869
|
+
//! \name Rewriting
|
|
870
|
+
//! \{
|
|
871
|
+
|
|
872
|
+
//! \cond INTERNAL
|
|
873
|
+
inline uint32_t* _getRewriteArray() noexcept { return &_baseInst._extraReg._id; }
|
|
874
|
+
inline const uint32_t* _getRewriteArray() const noexcept { return &_baseInst._extraReg._id; }
|
|
875
|
+
|
|
876
|
+
inline uint32_t getRewriteIndex(const uint32_t* id) const noexcept {
|
|
877
|
+
const uint32_t* array = _getRewriteArray();
|
|
878
|
+
ASMJIT_ASSERT(array <= id);
|
|
879
|
+
|
|
880
|
+
size_t index = (size_t)(id - array);
|
|
881
|
+
ASMJIT_ASSERT(index < 32);
|
|
882
|
+
|
|
883
|
+
return uint32_t(index);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
inline void rewriteIdAtIndex(uint32_t index, uint32_t id) noexcept {
|
|
887
|
+
uint32_t* array = _getRewriteArray();
|
|
888
|
+
array[index] = id;
|
|
889
|
+
}
|
|
890
|
+
//! \endcond
|
|
891
|
+
|
|
892
|
+
//! \}
|
|
893
|
+
|
|
894
|
+
//! \name Static Functions
|
|
895
|
+
//! \{
|
|
896
|
+
|
|
897
|
+
//! \cond INTERNAL
|
|
898
|
+
static inline uint32_t capacityOfOpCount(uint32_t opCount) noexcept {
|
|
899
|
+
return opCount <= kBaseOpCapacity ? kBaseOpCapacity : Globals::kMaxOpCount;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
static inline size_t nodeSizeOfOpCapacity(uint32_t opCapacity) noexcept {
|
|
903
|
+
size_t base = sizeof(InstNode) - kBaseOpCapacity * sizeof(Operand);
|
|
904
|
+
return base + opCapacity * sizeof(Operand);
|
|
905
|
+
}
|
|
906
|
+
//! \endcond
|
|
907
|
+
|
|
908
|
+
//! \}
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
//! Instruction node with maximum number of operands.
|
|
912
|
+
//!
|
|
913
|
+
//! This node is created automatically by Builder/Compiler in case that the required number of operands exceeds
|
|
914
|
+
//! the default capacity of `InstNode`.
|
|
915
|
+
class InstExNode : public InstNode {
|
|
916
|
+
public:
|
|
917
|
+
ASMJIT_NONCOPYABLE(InstExNode)
|
|
918
|
+
|
|
919
|
+
//! \name Members
|
|
920
|
+
//! \{
|
|
921
|
+
|
|
922
|
+
//! Continued `_opArray[]` to hold up to `kMaxOpCount` operands.
|
|
923
|
+
Operand_ _opArrayEx[Globals::kMaxOpCount - kBaseOpCapacity];
|
|
924
|
+
|
|
925
|
+
//! \}
|
|
926
|
+
|
|
927
|
+
//! \name Construction & Destruction
|
|
928
|
+
//! \{
|
|
929
|
+
|
|
930
|
+
//! Creates a new `InstExNode` instance.
|
|
931
|
+
inline InstExNode(BaseBuilder* cb, InstId instId, InstOptions options, uint32_t opCapacity = Globals::kMaxOpCount) noexcept
|
|
932
|
+
: InstNode(cb, instId, options, opCapacity) {}
|
|
933
|
+
|
|
934
|
+
//! \}
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
//! Section node.
|
|
938
|
+
class SectionNode : public BaseNode {
|
|
939
|
+
public:
|
|
940
|
+
ASMJIT_NONCOPYABLE(SectionNode)
|
|
941
|
+
|
|
942
|
+
//! \name Members
|
|
943
|
+
//! \{
|
|
944
|
+
|
|
945
|
+
//! Section id.
|
|
946
|
+
uint32_t _id;
|
|
947
|
+
|
|
948
|
+
//! Next section node that follows this section.
|
|
949
|
+
//!
|
|
950
|
+
//! This link is only valid when the section is active (is part of the code) and when `Builder::hasDirtySectionLinks()`
|
|
951
|
+
//! returns `false`. If you intend to use this field you should always call `Builder::updateSectionLinks()` before you
|
|
952
|
+
//! do so.
|
|
953
|
+
SectionNode* _nextSection;
|
|
954
|
+
|
|
955
|
+
//! \}
|
|
956
|
+
|
|
957
|
+
//! \name Construction & Destruction
|
|
958
|
+
//! \{
|
|
959
|
+
|
|
960
|
+
//! Creates a new `SectionNode` instance.
|
|
961
|
+
inline SectionNode(BaseBuilder* cb, uint32_t secionId = 0) noexcept
|
|
962
|
+
: BaseNode(cb, NodeType::kSection, NodeFlags::kHasNoEffect),
|
|
963
|
+
_id(secionId),
|
|
964
|
+
_nextSection(nullptr) {}
|
|
965
|
+
|
|
966
|
+
//! \}
|
|
967
|
+
|
|
968
|
+
//! \name Accessors
|
|
969
|
+
//! \{
|
|
970
|
+
|
|
971
|
+
//! Returns the section id.
|
|
972
|
+
inline uint32_t id() const noexcept { return _id; }
|
|
973
|
+
|
|
974
|
+
//! \}
|
|
975
|
+
};
|
|
976
|
+
|
|
977
|
+
//! Label node.
|
|
978
|
+
class LabelNode : public BaseNode {
|
|
979
|
+
public:
|
|
980
|
+
ASMJIT_NONCOPYABLE(LabelNode)
|
|
981
|
+
|
|
982
|
+
//! \name Members
|
|
983
|
+
//! \{
|
|
984
|
+
|
|
985
|
+
//! Label identifier.
|
|
986
|
+
uint32_t _labelId;
|
|
987
|
+
|
|
988
|
+
//! \}
|
|
989
|
+
|
|
990
|
+
//! \name Construction & Destruction
|
|
991
|
+
//! \{
|
|
992
|
+
|
|
993
|
+
//! Creates a new `LabelNode` instance.
|
|
994
|
+
inline LabelNode(BaseBuilder* cb, uint32_t labelId = 0) noexcept
|
|
995
|
+
: BaseNode(cb, NodeType::kLabel, NodeFlags::kHasNoEffect | NodeFlags::kActsAsLabel),
|
|
996
|
+
_labelId(labelId) {}
|
|
997
|
+
|
|
998
|
+
//! \}
|
|
999
|
+
|
|
1000
|
+
//! \name Accessors
|
|
1001
|
+
//! \{
|
|
1002
|
+
|
|
1003
|
+
//! Returns \ref Label representation of the \ref LabelNode.
|
|
1004
|
+
inline Label label() const noexcept { return Label(_labelId); }
|
|
1005
|
+
//! Returns the id of the label.
|
|
1006
|
+
inline uint32_t labelId() const noexcept { return _labelId; }
|
|
1007
|
+
|
|
1008
|
+
//! \}
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1011
|
+
//! Align directive (BaseBuilder).
|
|
1012
|
+
//!
|
|
1013
|
+
//! Wraps `.align` directive.
|
|
1014
|
+
class AlignNode : public BaseNode {
|
|
1015
|
+
public:
|
|
1016
|
+
ASMJIT_NONCOPYABLE(AlignNode)
|
|
1017
|
+
|
|
1018
|
+
//! \name Members
|
|
1019
|
+
//! \{
|
|
1020
|
+
|
|
1021
|
+
//! Alignment (in bytes).
|
|
1022
|
+
uint32_t _alignment;
|
|
1023
|
+
|
|
1024
|
+
//! \}
|
|
1025
|
+
|
|
1026
|
+
//! \name Construction & Destruction
|
|
1027
|
+
//! \{
|
|
1028
|
+
|
|
1029
|
+
//! Creates a new `AlignNode` instance.
|
|
1030
|
+
inline AlignNode(BaseBuilder* cb, AlignMode alignMode, uint32_t alignment) noexcept
|
|
1031
|
+
: BaseNode(cb, NodeType::kAlign, NodeFlags::kIsCode | NodeFlags::kHasNoEffect) {
|
|
1032
|
+
|
|
1033
|
+
_alignData._alignMode = alignMode;
|
|
1034
|
+
_alignment = alignment;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
//! \}
|
|
1038
|
+
|
|
1039
|
+
//! \name Accessors
|
|
1040
|
+
//! \{
|
|
1041
|
+
|
|
1042
|
+
//! Returns align mode.
|
|
1043
|
+
inline AlignMode alignMode() const noexcept { return _alignData._alignMode; }
|
|
1044
|
+
//! Sets align mode to `alignMode`.
|
|
1045
|
+
inline void setAlignMode(AlignMode alignMode) noexcept { _alignData._alignMode = alignMode; }
|
|
1046
|
+
|
|
1047
|
+
//! Returns align offset in bytes.
|
|
1048
|
+
inline uint32_t alignment() const noexcept { return _alignment; }
|
|
1049
|
+
//! Sets align offset in bytes to `offset`.
|
|
1050
|
+
inline void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
|
|
1051
|
+
|
|
1052
|
+
//! \}
|
|
1053
|
+
};
|
|
1054
|
+
|
|
1055
|
+
//! Embed data node.
|
|
1056
|
+
//!
|
|
1057
|
+
//! Wraps `.data` directive. The node contains data that will be placed at the node's position in the assembler
|
|
1058
|
+
//! stream. The data is considered to be RAW; no analysis nor byte-order conversion is performed on RAW data.
|
|
1059
|
+
class EmbedDataNode : public BaseNode {
|
|
1060
|
+
public:
|
|
1061
|
+
ASMJIT_NONCOPYABLE(EmbedDataNode)
|
|
1062
|
+
|
|
1063
|
+
//! \cond INTERNAL
|
|
1064
|
+
enum : uint32_t {
|
|
1065
|
+
kInlineBufferSize = 128 - (sizeof(BaseNode) + sizeof(size_t) * 2)
|
|
1066
|
+
};
|
|
1067
|
+
//! \endcond
|
|
1068
|
+
|
|
1069
|
+
//! \name Members
|
|
1070
|
+
//! \{
|
|
1071
|
+
|
|
1072
|
+
size_t _itemCount;
|
|
1073
|
+
size_t _repeatCount;
|
|
1074
|
+
|
|
1075
|
+
union {
|
|
1076
|
+
uint8_t* _externalData;
|
|
1077
|
+
uint8_t _inlineData[kInlineBufferSize];
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
//! \}
|
|
1081
|
+
|
|
1082
|
+
//! \name Construction & Destruction
|
|
1083
|
+
//! \{
|
|
1084
|
+
|
|
1085
|
+
//! Creates a new `EmbedDataNode` instance.
|
|
1086
|
+
inline EmbedDataNode(BaseBuilder* cb) noexcept
|
|
1087
|
+
: BaseNode(cb, NodeType::kEmbedData, NodeFlags::kIsData),
|
|
1088
|
+
_itemCount(0),
|
|
1089
|
+
_repeatCount(0) {
|
|
1090
|
+
_embed._typeId = TypeId::kUInt8;
|
|
1091
|
+
_embed._typeSize = uint8_t(1);
|
|
1092
|
+
memset(_inlineData, 0, kInlineBufferSize);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
//! \}
|
|
1096
|
+
|
|
1097
|
+
//! \name Accessors
|
|
1098
|
+
//! \{
|
|
1099
|
+
|
|
1100
|
+
//! Returns data type as \ref TypeId.
|
|
1101
|
+
inline TypeId typeId() const noexcept { return _embed._typeId; }
|
|
1102
|
+
//! Returns the size of a single data element.
|
|
1103
|
+
inline uint32_t typeSize() const noexcept { return _embed._typeSize; }
|
|
1104
|
+
|
|
1105
|
+
//! Returns a pointer to the data casted to `uint8_t`.
|
|
1106
|
+
inline uint8_t* data() const noexcept {
|
|
1107
|
+
return dataSize() <= kInlineBufferSize ? const_cast<uint8_t*>(_inlineData) : _externalData;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
//! Returns a pointer to the data casted to `T`.
|
|
1111
|
+
template<typename T>
|
|
1112
|
+
inline T* dataAs() const noexcept { return reinterpret_cast<T*>(data()); }
|
|
1113
|
+
|
|
1114
|
+
//! Returns the number of (typed) items in the array.
|
|
1115
|
+
inline size_t itemCount() const noexcept { return _itemCount; }
|
|
1116
|
+
|
|
1117
|
+
//! Returns how many times the data is repeated (default 1).
|
|
1118
|
+
//!
|
|
1119
|
+
//! Repeated data is useful when defining constants for SIMD, for example.
|
|
1120
|
+
inline size_t repeatCount() const noexcept { return _repeatCount; }
|
|
1121
|
+
|
|
1122
|
+
//! Returns the size of the data, not considering the number of times it repeats.
|
|
1123
|
+
//!
|
|
1124
|
+
//! \note The returned value is the same as `typeSize() * itemCount()`.
|
|
1125
|
+
inline size_t dataSize() const noexcept { return typeSize() * _itemCount; }
|
|
1126
|
+
|
|
1127
|
+
//! \}
|
|
1128
|
+
};
|
|
1129
|
+
|
|
1130
|
+
//! Label data node.
|
|
1131
|
+
class EmbedLabelNode : public BaseNode {
|
|
1132
|
+
public:
|
|
1133
|
+
ASMJIT_NONCOPYABLE(EmbedLabelNode)
|
|
1134
|
+
|
|
1135
|
+
//! \name Members
|
|
1136
|
+
//! \{
|
|
1137
|
+
|
|
1138
|
+
uint32_t _labelId;
|
|
1139
|
+
uint32_t _dataSize;
|
|
1140
|
+
|
|
1141
|
+
//! \}
|
|
1142
|
+
|
|
1143
|
+
//! \name Construction & Destruction
|
|
1144
|
+
//! \{
|
|
1145
|
+
|
|
1146
|
+
//! Creates a new `EmbedLabelNode` instance.
|
|
1147
|
+
inline EmbedLabelNode(BaseBuilder* cb, uint32_t labelId = 0, uint32_t dataSize = 0) noexcept
|
|
1148
|
+
: BaseNode(cb, NodeType::kEmbedLabel, NodeFlags::kIsData),
|
|
1149
|
+
_labelId(labelId),
|
|
1150
|
+
_dataSize(dataSize) {}
|
|
1151
|
+
|
|
1152
|
+
//! \}
|
|
1153
|
+
|
|
1154
|
+
//! \name Accessors
|
|
1155
|
+
//! \{
|
|
1156
|
+
|
|
1157
|
+
//! Returns the label to embed as \ref Label operand.
|
|
1158
|
+
inline Label label() const noexcept { return Label(_labelId); }
|
|
1159
|
+
//! Returns the id of the label.
|
|
1160
|
+
inline uint32_t labelId() const noexcept { return _labelId; }
|
|
1161
|
+
|
|
1162
|
+
//! Sets the label id from `label` operand.
|
|
1163
|
+
inline void setLabel(const Label& label) noexcept { setLabelId(label.id()); }
|
|
1164
|
+
//! Sets the label id (use with caution, improper use can break a lot of things).
|
|
1165
|
+
inline void setLabelId(uint32_t labelId) noexcept { _labelId = labelId; }
|
|
1166
|
+
|
|
1167
|
+
//! Returns the data size.
|
|
1168
|
+
inline uint32_t dataSize() const noexcept { return _dataSize; }
|
|
1169
|
+
//! Sets the data size.
|
|
1170
|
+
inline void setDataSize(uint32_t dataSize) noexcept { _dataSize = dataSize; }
|
|
1171
|
+
|
|
1172
|
+
//! \}
|
|
1173
|
+
};
|
|
1174
|
+
|
|
1175
|
+
//! Label data node.
|
|
1176
|
+
class EmbedLabelDeltaNode : public BaseNode {
|
|
1177
|
+
public:
|
|
1178
|
+
ASMJIT_NONCOPYABLE(EmbedLabelDeltaNode)
|
|
1179
|
+
|
|
1180
|
+
//! \name Members
|
|
1181
|
+
//! \{
|
|
1182
|
+
|
|
1183
|
+
uint32_t _labelId;
|
|
1184
|
+
uint32_t _baseLabelId;
|
|
1185
|
+
uint32_t _dataSize;
|
|
1186
|
+
|
|
1187
|
+
//! \}
|
|
1188
|
+
|
|
1189
|
+
//! \name Construction & Destruction
|
|
1190
|
+
//! \{
|
|
1191
|
+
|
|
1192
|
+
//! Creates a new `EmbedLabelDeltaNode` instance.
|
|
1193
|
+
inline EmbedLabelDeltaNode(BaseBuilder* cb, uint32_t labelId = 0, uint32_t baseLabelId = 0, uint32_t dataSize = 0) noexcept
|
|
1194
|
+
: BaseNode(cb, NodeType::kEmbedLabelDelta, NodeFlags::kIsData),
|
|
1195
|
+
_labelId(labelId),
|
|
1196
|
+
_baseLabelId(baseLabelId),
|
|
1197
|
+
_dataSize(dataSize) {}
|
|
1198
|
+
|
|
1199
|
+
//! \}
|
|
1200
|
+
|
|
1201
|
+
//! \name Accessors
|
|
1202
|
+
//! \{
|
|
1203
|
+
|
|
1204
|
+
//! Returns the label as `Label` operand.
|
|
1205
|
+
inline Label label() const noexcept { return Label(_labelId); }
|
|
1206
|
+
//! Returns the id of the label.
|
|
1207
|
+
inline uint32_t labelId() const noexcept { return _labelId; }
|
|
1208
|
+
|
|
1209
|
+
//! Sets the label id from `label` operand.
|
|
1210
|
+
inline void setLabel(const Label& label) noexcept { setLabelId(label.id()); }
|
|
1211
|
+
//! Sets the label id.
|
|
1212
|
+
inline void setLabelId(uint32_t labelId) noexcept { _labelId = labelId; }
|
|
1213
|
+
|
|
1214
|
+
//! Returns the base label as `Label` operand.
|
|
1215
|
+
inline Label baseLabel() const noexcept { return Label(_baseLabelId); }
|
|
1216
|
+
//! Returns the id of the base label.
|
|
1217
|
+
inline uint32_t baseLabelId() const noexcept { return _baseLabelId; }
|
|
1218
|
+
|
|
1219
|
+
//! Sets the base label id from `label` operand.
|
|
1220
|
+
inline void setBaseLabel(const Label& baseLabel) noexcept { setBaseLabelId(baseLabel.id()); }
|
|
1221
|
+
//! Sets the base label id.
|
|
1222
|
+
inline void setBaseLabelId(uint32_t baseLabelId) noexcept { _baseLabelId = baseLabelId; }
|
|
1223
|
+
|
|
1224
|
+
//! Returns the size of the embedded label address.
|
|
1225
|
+
inline uint32_t dataSize() const noexcept { return _dataSize; }
|
|
1226
|
+
//! Sets the size of the embedded label address.
|
|
1227
|
+
inline void setDataSize(uint32_t dataSize) noexcept { _dataSize = dataSize; }
|
|
1228
|
+
|
|
1229
|
+
//! \}
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
//! A node that wraps `ConstPool`.
|
|
1233
|
+
class ConstPoolNode : public LabelNode {
|
|
1234
|
+
public:
|
|
1235
|
+
ASMJIT_NONCOPYABLE(ConstPoolNode)
|
|
1236
|
+
|
|
1237
|
+
//! \name Members
|
|
1238
|
+
//! \{
|
|
1239
|
+
|
|
1240
|
+
ConstPool _constPool;
|
|
1241
|
+
|
|
1242
|
+
//! \}
|
|
1243
|
+
|
|
1244
|
+
//! \name Construction & Destruction
|
|
1245
|
+
//! \{
|
|
1246
|
+
|
|
1247
|
+
//! Creates a new `ConstPoolNode` instance.
|
|
1248
|
+
inline ConstPoolNode(BaseBuilder* cb, uint32_t id = 0) noexcept
|
|
1249
|
+
: LabelNode(cb, id),
|
|
1250
|
+
_constPool(&cb->_codeZone) {
|
|
1251
|
+
|
|
1252
|
+
setType(NodeType::kConstPool);
|
|
1253
|
+
addFlags(NodeFlags::kIsData);
|
|
1254
|
+
clearFlags(NodeFlags::kIsCode | NodeFlags::kHasNoEffect);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
//! \}
|
|
1258
|
+
|
|
1259
|
+
//! \name Accessors
|
|
1260
|
+
//! \{
|
|
1261
|
+
|
|
1262
|
+
//! Tests whether the constant-pool is empty.
|
|
1263
|
+
inline bool empty() const noexcept { return _constPool.empty(); }
|
|
1264
|
+
//! Returns the size of the constant-pool in bytes.
|
|
1265
|
+
inline size_t size() const noexcept { return _constPool.size(); }
|
|
1266
|
+
//! Returns minimum alignment.
|
|
1267
|
+
inline size_t alignment() const noexcept { return _constPool.alignment(); }
|
|
1268
|
+
|
|
1269
|
+
//! Returns the wrapped `ConstPool` instance.
|
|
1270
|
+
inline ConstPool& constPool() noexcept { return _constPool; }
|
|
1271
|
+
//! Returns the wrapped `ConstPool` instance (const).
|
|
1272
|
+
inline const ConstPool& constPool() const noexcept { return _constPool; }
|
|
1273
|
+
|
|
1274
|
+
//! \}
|
|
1275
|
+
|
|
1276
|
+
//! \name Utilities
|
|
1277
|
+
//! \{
|
|
1278
|
+
|
|
1279
|
+
//! See `ConstPool::add()`.
|
|
1280
|
+
inline Error add(const void* data, size_t size, size_t& dstOffset) noexcept {
|
|
1281
|
+
return _constPool.add(data, size, dstOffset);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
//! \}
|
|
1285
|
+
};
|
|
1286
|
+
|
|
1287
|
+
//! Comment node.
|
|
1288
|
+
class CommentNode : public BaseNode {
|
|
1289
|
+
public:
|
|
1290
|
+
ASMJIT_NONCOPYABLE(CommentNode)
|
|
1291
|
+
|
|
1292
|
+
//! \name Construction & Destruction
|
|
1293
|
+
//! \{
|
|
1294
|
+
|
|
1295
|
+
//! Creates a new `CommentNode` instance.
|
|
1296
|
+
inline CommentNode(BaseBuilder* cb, const char* comment) noexcept
|
|
1297
|
+
: BaseNode(cb, NodeType::kComment, NodeFlags::kIsInformative | NodeFlags::kHasNoEffect | NodeFlags::kIsRemovable) {
|
|
1298
|
+
_inlineComment = comment;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
//! \}
|
|
1302
|
+
};
|
|
1303
|
+
|
|
1304
|
+
//! Sentinel node.
|
|
1305
|
+
//!
|
|
1306
|
+
//! Sentinel is a marker that is completely ignored by the code builder. It's used to remember a position in a code
|
|
1307
|
+
//! as it never gets removed by any pass.
|
|
1308
|
+
class SentinelNode : public BaseNode {
|
|
1309
|
+
public:
|
|
1310
|
+
ASMJIT_NONCOPYABLE(SentinelNode)
|
|
1311
|
+
|
|
1312
|
+
//! \name Construction & Destruction
|
|
1313
|
+
//! \{
|
|
1314
|
+
|
|
1315
|
+
//! Creates a new `SentinelNode` instance.
|
|
1316
|
+
inline SentinelNode(BaseBuilder* cb, SentinelType sentinelType = SentinelType::kUnknown) noexcept
|
|
1317
|
+
: BaseNode(cb, NodeType::kSentinel, NodeFlags::kIsInformative | NodeFlags::kHasNoEffect) {
|
|
1318
|
+
|
|
1319
|
+
_sentinel._sentinelType = sentinelType;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
//! \}
|
|
1323
|
+
|
|
1324
|
+
//! \name Accessors
|
|
1325
|
+
//! \{
|
|
1326
|
+
|
|
1327
|
+
//! Returns the type of the sentinel.
|
|
1328
|
+
inline SentinelType sentinelType() const noexcept {
|
|
1329
|
+
return _sentinel._sentinelType;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
//! Sets the type of the sentinel.
|
|
1333
|
+
inline void setSentinelType(SentinelType type) noexcept {
|
|
1334
|
+
_sentinel._sentinelType = type;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
//! \}
|
|
1338
|
+
};
|
|
1339
|
+
|
|
1340
|
+
//! Pass can be used to implement code transformations, analysis, and lowering.
|
|
1341
|
+
class ASMJIT_VIRTAPI Pass {
|
|
1342
|
+
public:
|
|
1343
|
+
ASMJIT_BASE_CLASS(Pass)
|
|
1344
|
+
ASMJIT_NONCOPYABLE(Pass)
|
|
1345
|
+
|
|
1346
|
+
//! \name Members
|
|
1347
|
+
//! \{
|
|
1348
|
+
|
|
1349
|
+
//! BaseBuilder this pass is assigned to.
|
|
1350
|
+
BaseBuilder* _cb = nullptr;
|
|
1351
|
+
//! Name of the pass.
|
|
1352
|
+
const char* _name = nullptr;
|
|
1353
|
+
|
|
1354
|
+
//! \}
|
|
1355
|
+
|
|
1356
|
+
//! \name Construction & Destruction
|
|
1357
|
+
//! \{
|
|
1358
|
+
|
|
1359
|
+
ASMJIT_API Pass(const char* name) noexcept;
|
|
1360
|
+
ASMJIT_API virtual ~Pass() noexcept;
|
|
1361
|
+
|
|
1362
|
+
//! \}
|
|
1363
|
+
|
|
1364
|
+
//! \name Accessors
|
|
1365
|
+
//! \{
|
|
1366
|
+
|
|
1367
|
+
//! Returns \ref BaseBuilder associated with the pass.
|
|
1368
|
+
inline const BaseBuilder* cb() const noexcept { return _cb; }
|
|
1369
|
+
//! Returns the name of the pass.
|
|
1370
|
+
inline const char* name() const noexcept { return _name; }
|
|
1371
|
+
|
|
1372
|
+
//! \}
|
|
1373
|
+
|
|
1374
|
+
//! \name Pass Interface
|
|
1375
|
+
//! \{
|
|
1376
|
+
|
|
1377
|
+
//! Processes the code stored in Builder or Compiler.
|
|
1378
|
+
//!
|
|
1379
|
+
//! This is the only function that is called by the `BaseBuilder` to process the code. It passes `zone`,
|
|
1380
|
+
//! which will be reset after the `run()` finishes.
|
|
1381
|
+
virtual Error run(Zone* zone, Logger* logger) = 0;
|
|
1382
|
+
|
|
1383
|
+
//! \}
|
|
1384
|
+
};
|
|
1385
|
+
|
|
1386
|
+
//! \}
|
|
1387
|
+
|
|
1388
|
+
ASMJIT_END_NAMESPACE
|
|
1389
|
+
|
|
1390
|
+
#endif // !ASMJIT_NO_BUILDER
|
|
1391
|
+
#endif // ASMJIT_CORE_BUILDER_H_INCLUDED
|