asmjit 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/asmjit.gemspec +1 -1
  4. data/ext/asmjit/asmjit/.editorconfig +10 -0
  5. data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
  6. data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
  7. data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
  8. data/ext/asmjit/asmjit/.gitignore +6 -0
  9. data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
  10. data/ext/asmjit/asmjit/LICENSE.md +17 -0
  11. data/ext/asmjit/asmjit/README.md +69 -0
  12. data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
  13. data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
  14. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
  15. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
  16. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
  17. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
  18. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
  19. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
  20. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
  21. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
  22. data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
  23. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
  24. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
  25. data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
  26. data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
  27. data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
  28. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
  29. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
  30. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
  31. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
  32. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
  33. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
  34. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
  35. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
  36. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
  37. data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
  38. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
  39. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
  40. data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
  41. data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
  42. data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
  43. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
  44. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
  45. data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
  46. data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
  47. data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
  48. data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
  49. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
  50. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
  51. data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
  52. data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
  53. data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
  54. data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
  55. data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
  56. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
  57. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
  58. data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
  59. data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
  60. data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
  61. data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
  62. data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
  63. data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
  64. data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
  65. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
  66. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
  67. data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
  68. data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
  69. data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
  70. data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
  71. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
  72. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
  73. data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
  74. data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
  75. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
  76. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
  77. data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
  78. data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
  79. data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
  80. data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
  81. data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
  82. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
  83. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
  84. data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
  85. data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
  86. data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
  87. data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
  88. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
  89. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
  90. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
  91. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
  92. data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
  93. data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
  94. data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
  95. data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
  96. data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
  97. data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
  98. data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
  99. data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
  100. data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
  101. data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
  102. data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
  103. data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
  104. data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
  105. data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
  106. data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
  107. data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
  108. data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
  109. data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
  110. data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
  111. data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
  112. data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
  113. data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
  114. data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
  115. data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
  116. data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
  117. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
  118. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
  119. data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
  120. data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
  121. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
  122. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
  123. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
  124. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
  125. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
  126. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
  127. data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
  128. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
  129. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
  130. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
  131. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
  132. data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
  133. data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
  134. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
  135. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
  136. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
  137. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
  138. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
  139. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
  140. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
  141. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
  142. data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
  143. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
  144. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
  145. data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
  146. data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
  147. data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
  148. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
  149. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
  150. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
  151. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
  152. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
  153. data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
  154. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
  155. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
  156. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
  157. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
  158. data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
  159. data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
  160. data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
  161. data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
  162. data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
  163. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
  164. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
  165. data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
  166. data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
  167. data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
  168. data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
  169. data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
  170. data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
  171. data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
  172. data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
  173. data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
  174. data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
  175. data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
  176. data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
  177. data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
  178. data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
  179. data/ext/asmjit/asmjit/test/broken.cpp +312 -0
  180. data/ext/asmjit/asmjit/test/broken.h +148 -0
  181. data/ext/asmjit/asmjit/test/cmdline.h +61 -0
  182. data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
  183. data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
  184. data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
  185. data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
  186. data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
  187. data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
  188. data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
  189. data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
  190. data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
  191. data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
  192. data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
  193. data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
  194. data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
  195. data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
  196. data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
  197. data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
  198. data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
  199. data/ext/asmjit/asmjit.cc +18 -0
  200. data/lib/asmjit/version.rb +1 -1
  201. metadata +197 -2
@@ -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