asmjit 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/Rakefile +5 -3
  4. data/asmjit.gemspec +1 -3
  5. data/ext/asmjit/asmjit/.editorconfig +10 -0
  6. data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
  7. data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
  8. data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
  9. data/ext/asmjit/asmjit/.gitignore +6 -0
  10. data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
  11. data/ext/asmjit/asmjit/LICENSE.md +17 -0
  12. data/ext/asmjit/asmjit/README.md +69 -0
  13. data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
  14. data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
  15. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
  16. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
  17. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
  18. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
  19. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
  20. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
  21. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
  22. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
  23. data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
  24. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
  25. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
  26. data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
  27. data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
  28. data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
  29. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
  30. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
  31. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
  32. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
  33. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
  34. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
  35. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
  36. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
  37. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
  38. data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
  39. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
  40. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
  41. data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
  42. data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
  43. data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
  44. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
  45. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
  46. data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
  47. data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
  48. data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
  49. data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
  50. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
  51. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
  52. data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
  53. data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
  54. data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
  55. data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
  56. data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
  57. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
  58. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
  59. data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
  60. data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
  61. data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
  62. data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
  63. data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
  64. data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
  65. data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
  66. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
  67. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
  68. data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
  69. data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
  70. data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
  71. data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
  72. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
  73. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
  74. data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
  75. data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
  76. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
  77. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
  78. data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
  79. data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
  80. data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
  81. data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
  82. data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
  83. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
  84. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
  85. data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
  86. data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
  87. data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
  88. data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
  89. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
  90. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
  91. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
  92. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
  93. data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
  94. data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
  95. data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
  96. data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
  97. data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
  98. data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
  99. data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
  100. data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
  101. data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
  102. data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
  103. data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
  104. data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
  105. data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
  106. data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
  107. data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
  108. data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
  109. data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
  110. data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
  111. data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
  112. data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
  113. data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
  114. data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
  115. data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
  116. data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
  117. data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
  118. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
  119. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
  120. data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
  121. data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
  122. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
  123. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
  124. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
  125. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
  126. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
  127. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
  128. data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
  129. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
  130. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
  131. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
  132. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
  133. data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
  134. data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
  135. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
  136. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
  137. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
  138. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
  139. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
  140. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
  141. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
  142. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
  143. data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
  144. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
  145. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
  146. data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
  147. data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
  148. data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
  149. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
  150. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
  151. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
  152. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
  153. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
  154. data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
  155. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
  156. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
  157. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
  158. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
  159. data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
  160. data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
  161. data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
  162. data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
  163. data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
  164. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
  165. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
  166. data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
  167. data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
  168. data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
  169. data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
  170. data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
  171. data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
  172. data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
  173. data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
  174. data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
  175. data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
  176. data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
  177. data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
  178. data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
  179. data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
  180. data/ext/asmjit/asmjit/test/broken.cpp +312 -0
  181. data/ext/asmjit/asmjit/test/broken.h +148 -0
  182. data/ext/asmjit/asmjit/test/cmdline.h +61 -0
  183. data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
  184. data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
  185. data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
  186. data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
  187. data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
  188. data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
  189. data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
  190. data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
  191. data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
  192. data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
  193. data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
  194. data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
  195. data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
  196. data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
  197. data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
  198. data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
  199. data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
  200. data/ext/asmjit/asmjit.cc +167 -30
  201. data/ext/asmjit/extconf.rb +9 -9
  202. data/lib/asmjit/version.rb +1 -1
  203. data/lib/asmjit.rb +14 -4
  204. metadata +198 -17
@@ -0,0 +1,1611 @@
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_OPERAND_H_INCLUDED
7
+ #define ASMJIT_CORE_OPERAND_H_INCLUDED
8
+
9
+ #include "../core/archcommons.h"
10
+ #include "../core/support.h"
11
+ #include "../core/type.h"
12
+
13
+ ASMJIT_BEGIN_NAMESPACE
14
+
15
+ //! \addtogroup asmjit_assembler
16
+ //! \{
17
+
18
+ //! Operand type used by \ref Operand_.
19
+ enum class OperandType : uint32_t {
20
+ //! Not an operand or not initialized.
21
+ kNone = 0,
22
+ //! Operand is a register.
23
+ kReg = 1,
24
+ //! Operand is a memory.
25
+ kMem = 2,
26
+ //! Operand is an immediate value.
27
+ kImm = 3,
28
+ //! Operand is a label.
29
+ kLabel = 4,
30
+
31
+ //! Maximum value of `OperandType`.
32
+ kMaxValue = kLabel
33
+ };
34
+
35
+ static_assert(uint32_t(OperandType::kMem) == uint32_t(OperandType::kReg) + 1,
36
+ "AsmJit requires that `OperandType::kMem` equals to `OperandType::kReg + 1`");
37
+
38
+ //! Register mask is a convenience typedef that describes a mask where each bit describes a physical register id
39
+ //! in the same \ref RegGroup. At the moment 32 bits are enough as AsmJit doesn't support any architecture that
40
+ //! would provide more than 32 registers for a register group.
41
+ typedef uint32_t RegMask;
42
+
43
+ //! Register type.
44
+ //!
45
+ //! Provides a unique type that can be used to identify a register or its view.
46
+ enum class RegType : uint8_t {
47
+ //! No register - unused, invalid, multiple meanings.
48
+ kNone = 0,
49
+
50
+ //! This is not a register type. This value is reserved for a \ref Label that used in \ref BaseMem as a base.
51
+ //!
52
+ //! Label tag is used as a sub-type, forming a unique signature across all operand types as 0x1 is never associated
53
+ //! with any register type. This means that a memory operand's BASE register can be constructed from virtually any
54
+ //! operand (register vs. label) by just assigning its type (register type or label-tag) and operand id.
55
+ kLabelTag = 1,
56
+
57
+ //! Universal type describing program counter (PC) or instruction pointer (IP) register, if the target architecture
58
+ //! actually exposes it as a separate register type, which most modern targets do.
59
+ kPC = 2,
60
+
61
+ //! 8-bit low general purpose register (X86).
62
+ kGp8Lo = 3,
63
+ //! 8-bit high general purpose register (X86).
64
+ kGp8Hi = 4,
65
+ //! 16-bit general purpose register (X86).
66
+ kGp16 = 5,
67
+ //! 32-bit general purpose register (X86|ARM).
68
+ kGp32 = 6,
69
+ //! 64-bit general purpose register (X86|ARM).
70
+ kGp64 = 7,
71
+ //! 8-bit view of a vector register (ARM).
72
+ kVec8 = 8,
73
+ //! 16-bit view of a vector register (ARM).
74
+ kVec16 = 9,
75
+ //! 32-bit view of a vector register (ARM).
76
+ kVec32 = 10,
77
+ //! 64-bit view of a vector register (ARM).
78
+ //!
79
+ //! \note This is never used for MMX registers on X86, MMX registers have its own category.
80
+ kVec64 = 11,
81
+ //! 128-bit view of a vector register (X86|ARM).
82
+ kVec128 = 12,
83
+ //! 256-bit view of a vector register (X86).
84
+ kVec256 = 13,
85
+ //! 512-bit view of a vector register (X86).
86
+ kVec512 = 14,
87
+ //! 1024-bit view of a vector register (future).
88
+ kVec1024 = 15,
89
+ //! View of a vector register, which width is implementation specific (AArch64).
90
+ kVecNLen = 16,
91
+
92
+ //! Mask register (X86).
93
+ kMask = 17,
94
+
95
+ //! Start of architecture dependent register types.
96
+ kExtra = 18,
97
+
98
+ // X86 Specific Register Types
99
+ // ---------------------------
100
+
101
+ // X86 Specific Register Types
102
+ // ===========================
103
+
104
+ //! Instruction pointer (RIP), only addressable in \ref x86::Mem in 64-bit targets.
105
+ kX86_Rip = kPC,
106
+ //! Low GPB register (AL, BL, CL, DL, ...).
107
+ kX86_GpbLo = kGp8Lo,
108
+ //! High GPB register (AH, BH, CH, DH only).
109
+ kX86_GpbHi = kGp8Hi,
110
+ //! GPW register.
111
+ kX86_Gpw = kGp16,
112
+ //! GPD register.
113
+ kX86_Gpd = kGp32,
114
+ //! GPQ register (64-bit).
115
+ kX86_Gpq = kGp64,
116
+ //! XMM register (SSE+).
117
+ kX86_Xmm = kVec128,
118
+ //! YMM register (AVX+).
119
+ kX86_Ymm = kVec256,
120
+ //! ZMM register (AVX512+).
121
+ kX86_Zmm = kVec512,
122
+ //! K register (AVX512+).
123
+ kX86_KReg = kMask,
124
+ //! MMX register.
125
+ kX86_Mm = kExtra + 0,
126
+ //! Segment register (None, ES, CS, SS, DS, FS, GS).
127
+ kX86_SReg = kExtra + 1,
128
+ //! Control register (CR).
129
+ kX86_CReg = kExtra + 2,
130
+ //! Debug register (DR).
131
+ kX86_DReg = kExtra + 3,
132
+ //! FPU (x87) register.
133
+ kX86_St = kExtra + 4,
134
+ //! Bound register (BND).
135
+ kX86_Bnd = kExtra + 5,
136
+ //! TMM register (AMX_TILE)
137
+ kX86_Tmm = kExtra + 6,
138
+
139
+ // ARM Specific Register Types
140
+ // ===========================
141
+
142
+ //! Program pointer (PC) register (AArch64).
143
+ kARM_PC = kPC,
144
+ //! 32-bit general purpose register (R or W).
145
+ kARM_GpW = kGp32,
146
+ //! 64-bit general purpose register (X).
147
+ kARM_GpX = kGp64,
148
+ //! 8-bit view of VFP/ASIMD register (B).
149
+ kARM_VecB = kVec8,
150
+ //! 16-bit view of VFP/ASIMD register (H).
151
+ kARM_VecH = kVec16,
152
+ //! 32-bit view of VFP/ASIMD register (S).
153
+ kARM_VecS = kVec32,
154
+ //! 64-bit view of VFP/ASIMD register (D).
155
+ kARM_VecD = kVec64,
156
+ //! 128-bit view of VFP/ASIMD register (Q|V).
157
+ kARM_VecV = kVec128,
158
+
159
+ //! Maximum value of `RegType`.
160
+ kMaxValue = 31
161
+ };
162
+ ASMJIT_DEFINE_ENUM_COMPARE(RegType)
163
+
164
+ //! Register group.
165
+ //!
166
+ //! Provides a unique value that identifies groups of registers and their views.
167
+ enum class RegGroup : uint8_t {
168
+ //! General purpose register group compatible with all backends.
169
+ kGp = 0,
170
+ //! Vector register group compatible with all backends.
171
+ //!
172
+ //! Describes X86 XMM|YMM|ZMM registers ARM/AArch64 V registers.
173
+ kVec = 1,
174
+
175
+ //! Extra virtual group #2 that can be used by Compiler for register allocation.
176
+ kExtraVirt2 = 2,
177
+ //! Extra virtual group #3 that can be used by Compiler for register allocation.
178
+ kExtraVirt3 = 3,
179
+
180
+ //! Program counter group.
181
+ kPC = 4,
182
+
183
+ //! Extra non-virtual group that can be used by registers not managed by Compiler.
184
+ kExtraNonVirt = 5,
185
+
186
+ // X86 Specific Register Groups
187
+ // ----------------------------
188
+
189
+ //! K register group (KReg) - maps to \ref RegGroup::kExtraVirt2 (X86, X86_64).
190
+ kX86_K = kExtraVirt2,
191
+ //! MMX register group (MM) - maps to \ref RegGroup::kExtraVirt3 (X86, X86_64).
192
+ kX86_MM = kExtraVirt3,
193
+
194
+ //! Instruction pointer (X86, X86_64).
195
+ kX86_Rip = kPC,
196
+ //! Segment register group (X86, X86_64).
197
+ kX86_SReg = kExtraNonVirt + 0,
198
+ //! CR register group (X86, X86_64).
199
+ kX86_CReg = kExtraNonVirt + 1,
200
+ //! DR register group (X86, X86_64).
201
+ kX86_DReg = kExtraNonVirt + 2,
202
+ //! FPU register group (X86, X86_64).
203
+ kX86_St = kExtraNonVirt + 3,
204
+ //! BND register group (X86, X86_64).
205
+ kX86_Bnd = kExtraNonVirt + 4,
206
+ //! TMM register group (X86, X86_64).
207
+ kX86_Tmm = kExtraNonVirt + 5,
208
+
209
+ //! First group - only used in loops.
210
+ k0 = 0,
211
+ //! Last value of a virtual register that is managed by \ref BaseCompiler.
212
+ kMaxVirt = Globals::kNumVirtGroups - 1,
213
+ //! Maximum value of `RegGroup`.
214
+ kMaxValue = 15
215
+ };
216
+ ASMJIT_DEFINE_ENUM_COMPARE(RegGroup)
217
+
218
+ typedef Support::EnumValues<RegGroup, RegGroup::kGp, RegGroup::kMaxVirt> RegGroupVirtValues;
219
+
220
+ //! Operand signature is a 32-bit number describing \ref Operand and some of its payload.
221
+ //!
222
+ //! In AsmJit operand signature is used to store additional payload of register, memory, and immediate operands.
223
+ //! In practice the biggest pressure on OperandSignature is from \ref BaseMem and architecture specific memory
224
+ //! operands that need to store additional payload that cannot be stored elsewhere as values of all other members
225
+ //! are fully specified by \ref BaseMem.
226
+ struct OperandSignature {
227
+ //! \name Constants
228
+ //! \{
229
+
230
+ enum : uint32_t {
231
+ // Operand type (3 least significant bits).
232
+ // |........|........|........|.....XXX|
233
+ kOpTypeShift = 0,
234
+ kOpTypeMask = 0x07u << kOpTypeShift,
235
+
236
+ // Register type (5 bits).
237
+ // |........|........|........|XXXXX...|
238
+ kRegTypeShift = 3,
239
+ kRegTypeMask = 0x1Fu << kRegTypeShift,
240
+
241
+ // Register group (4 bits).
242
+ // |........|........|....XXXX|........|
243
+ kRegGroupShift = 8,
244
+ kRegGroupMask = 0x0Fu << kRegGroupShift,
245
+
246
+ // Memory base type (5 bits).
247
+ // |........|........|........|XXXXX...|
248
+ kMemBaseTypeShift = 3,
249
+ kMemBaseTypeMask = 0x1Fu << kMemBaseTypeShift,
250
+
251
+ // Memory index type (5 bits).
252
+ // |........|........|...XXXXX|........|
253
+ kMemIndexTypeShift = 8,
254
+ kMemIndexTypeMask = 0x1Fu << kMemIndexTypeShift,
255
+
256
+ // Memory base+index combined (10 bits).
257
+ // |........|........|...XXXXX|XXXXX...|
258
+ kMemBaseIndexShift = 3,
259
+ kMemBaseIndexMask = 0x3FFu << kMemBaseIndexShift,
260
+
261
+ // This memory operand represents a home-slot or stack (Compiler) (1 bit).
262
+ // |........|........|..X.....|........|
263
+ kMemRegHomeShift = 13,
264
+ kMemRegHomeFlag = 0x01u << kMemRegHomeShift,
265
+
266
+ // Immediate type (1 bit).
267
+ // |........|........|........|....X...|
268
+ kImmTypeShift = 3,
269
+ kImmTypeMask = 0x01u << kImmTypeShift,
270
+
271
+ // Predicate used by either registers or immediate values (4 bits).
272
+ // |........|XXXX....|........|........|
273
+ kPredicateShift = 20,
274
+ kPredicateMask = 0x0Fu << kPredicateShift,
275
+
276
+ // Operand size (8 most significant bits).
277
+ // |XXXXXXXX|........|........|........|
278
+ kSizeShift = 24,
279
+ kSizeMask = 0xFFu << kSizeShift
280
+ };
281
+
282
+ //! \}
283
+
284
+ //! \name Members
285
+ //! \{
286
+
287
+ uint32_t _bits;
288
+
289
+ //! \}
290
+
291
+ //! \name Overloaded Operators
292
+ //!
293
+ //! Overloaded operators make `OperandSignature` behave like regular integer.
294
+ //!
295
+ //! \{
296
+
297
+ inline constexpr bool operator!() const noexcept { return _bits != 0; }
298
+ inline constexpr explicit operator bool() const noexcept { return _bits != 0; }
299
+
300
+ inline OperandSignature& operator|=(uint32_t x) noexcept { _bits |= x; return *this; }
301
+ inline OperandSignature& operator&=(uint32_t x) noexcept { _bits &= x; return *this; }
302
+ inline OperandSignature& operator^=(uint32_t x) noexcept { _bits ^= x; return *this; }
303
+
304
+ inline OperandSignature& operator|=(const OperandSignature& other) noexcept { return operator|=(other._bits); }
305
+ inline OperandSignature& operator&=(const OperandSignature& other) noexcept { return operator&=(other._bits); }
306
+ inline OperandSignature& operator^=(const OperandSignature& other) noexcept { return operator^=(other._bits); }
307
+
308
+ inline constexpr OperandSignature operator~() const noexcept { return OperandSignature{~_bits}; }
309
+
310
+ inline constexpr OperandSignature operator|(uint32_t x) const noexcept { return OperandSignature{_bits | x}; }
311
+ inline constexpr OperandSignature operator&(uint32_t x) const noexcept { return OperandSignature{_bits & x}; }
312
+ inline constexpr OperandSignature operator^(uint32_t x) const noexcept { return OperandSignature{_bits ^ x}; }
313
+
314
+ inline constexpr OperandSignature operator|(const OperandSignature& other) const noexcept { return OperandSignature{_bits | other._bits}; }
315
+ inline constexpr OperandSignature operator&(const OperandSignature& other) const noexcept { return OperandSignature{_bits & other._bits}; }
316
+ inline constexpr OperandSignature operator^(const OperandSignature& other) const noexcept { return OperandSignature{_bits ^ other._bits}; }
317
+
318
+ inline constexpr bool operator==(uint32_t x) const noexcept { return _bits == x; }
319
+ inline constexpr bool operator!=(uint32_t x) const noexcept { return _bits != x; }
320
+
321
+ inline constexpr bool operator==(const OperandSignature& other) const noexcept { return _bits == other._bits; }
322
+ inline constexpr bool operator!=(const OperandSignature& other) const noexcept { return _bits != other._bits; }
323
+
324
+ //! \}
325
+
326
+ //! \name Accessors
327
+ //! \{
328
+
329
+ inline void reset() noexcept { _bits = 0; }
330
+
331
+ inline constexpr uint32_t bits() const noexcept { return _bits; }
332
+ inline void setBits(uint32_t bits) noexcept { _bits = bits; }
333
+
334
+ template<uint32_t kFieldMask, uint32_t kFieldShift = Support::ConstCTZ<kFieldMask>::value>
335
+ inline constexpr bool hasField() const noexcept {
336
+ return (_bits & kFieldMask) != 0;
337
+ }
338
+
339
+ template<uint32_t kFieldMask, uint32_t kFieldShift = Support::ConstCTZ<kFieldMask>::value>
340
+ inline constexpr bool hasField(uint32_t value) const noexcept {
341
+ return (_bits & kFieldMask) != value << kFieldShift;
342
+ }
343
+
344
+ template<uint32_t kFieldMask, uint32_t kFieldShift = Support::ConstCTZ<kFieldMask>::value>
345
+ inline constexpr uint32_t getField() const noexcept {
346
+ return (_bits >> kFieldShift) & (kFieldMask >> kFieldShift);
347
+ }
348
+
349
+ template<uint32_t kFieldMask, uint32_t kFieldShift = Support::ConstCTZ<kFieldMask>::value>
350
+ inline void setField(uint32_t value) noexcept {
351
+ ASMJIT_ASSERT((value & ~(kFieldMask >> kFieldShift)) == 0);
352
+ _bits = (_bits & ~kFieldMask) | (value << kFieldShift);
353
+ }
354
+
355
+ inline constexpr OperandSignature subset(uint32_t mask) const noexcept { return OperandSignature{_bits & mask}; }
356
+
357
+ template<uint32_t kFieldMask>
358
+ inline constexpr bool matchesSignature(const OperandSignature& signature) const noexcept {
359
+ return (_bits & kFieldMask) == signature._bits;
360
+ }
361
+
362
+ template<uint32_t kFieldMask>
363
+ inline constexpr bool matchesFields(uint32_t bits) const noexcept {
364
+ return (_bits & kFieldMask) == bits;
365
+ }
366
+
367
+ template<uint32_t kFieldMask>
368
+ inline constexpr bool matchesFields(const OperandSignature& fields) const noexcept {
369
+ return (_bits & kFieldMask) == fields._bits;
370
+ }
371
+
372
+ inline constexpr bool isValid() const noexcept { return _bits != 0; }
373
+
374
+ inline constexpr OperandType opType() const noexcept { return (OperandType)getField<kOpTypeMask>(); }
375
+
376
+ inline constexpr RegType regType() const noexcept { return (RegType)getField<kRegTypeMask>(); }
377
+ inline constexpr RegGroup regGroup() const noexcept { return (RegGroup)getField<kRegGroupMask>(); }
378
+
379
+ inline constexpr RegType memBaseType() const noexcept { return (RegType)getField<kMemBaseTypeMask>(); }
380
+ inline constexpr RegType memIndexType() const noexcept { return (RegType)getField<kMemIndexTypeMask>(); }
381
+
382
+ inline constexpr uint32_t predicate() const noexcept { return getField<kPredicateMask>(); }
383
+ inline constexpr uint32_t size() const noexcept { return getField<kSizeMask>(); }
384
+
385
+ inline void setOpType(OperandType opType) noexcept { setField<kOpTypeMask>(uint32_t(opType)); }
386
+ inline void setRegType(RegType regType) noexcept { setField<kRegTypeMask>(uint32_t(regType)); }
387
+ inline void setRegGroup(RegGroup regGroup) noexcept { setField<kRegGroupMask>(uint32_t(regGroup)); }
388
+
389
+ inline void setMemBaseType(RegGroup baseType) noexcept { setField<kMemBaseTypeMask>(uint32_t(baseType)); }
390
+ inline void setMemIndexType(RegGroup indexType) noexcept { setField<kMemIndexTypeMask>(uint32_t(indexType)); }
391
+
392
+ inline void setPredicate(uint32_t predicate) noexcept { setField<kPredicateMask>(predicate); }
393
+ inline void setSize(uint32_t size) noexcept { setField<kSizeMask>(size); }
394
+
395
+ //! \}
396
+
397
+ //! \name Static Constructors
398
+ //! \{
399
+
400
+ static inline constexpr OperandSignature fromBits(uint32_t bits) noexcept {
401
+ return OperandSignature{bits};
402
+ }
403
+
404
+ template<uint32_t kFieldMask, typename T>
405
+ static inline constexpr OperandSignature fromValue(const T& value) noexcept {
406
+ return OperandSignature{uint32_t(value) << Support::ConstCTZ<kFieldMask>::value};
407
+ }
408
+
409
+ static inline constexpr OperandSignature fromOpType(OperandType opType) noexcept {
410
+ return OperandSignature{uint32_t(opType) << kOpTypeShift};
411
+ }
412
+
413
+ static inline constexpr OperandSignature fromRegType(RegType regType) noexcept {
414
+ return OperandSignature{uint32_t(regType) << kRegTypeShift};
415
+ }
416
+
417
+ static inline constexpr OperandSignature fromRegGroup(RegGroup regGroup) noexcept {
418
+ return OperandSignature{uint32_t(regGroup) << kRegGroupShift};
419
+ }
420
+
421
+ static inline constexpr OperandSignature fromRegTypeAndGroup(RegType regType, RegGroup regGroup) noexcept {
422
+ return fromRegType(regType) | fromRegGroup(regGroup);
423
+ }
424
+
425
+ static inline constexpr OperandSignature fromMemBaseType(RegType baseType) noexcept {
426
+ return OperandSignature{uint32_t(baseType) << kMemBaseTypeShift};
427
+ }
428
+
429
+ static inline constexpr OperandSignature fromMemIndexType(RegType indexType) noexcept {
430
+ return OperandSignature{uint32_t(indexType) << kMemIndexTypeShift};
431
+ }
432
+
433
+ static inline constexpr OperandSignature fromPredicate(uint32_t predicate) noexcept {
434
+ return OperandSignature{predicate << kPredicateShift};
435
+ }
436
+
437
+ static inline constexpr OperandSignature fromSize(uint32_t size) noexcept {
438
+ return OperandSignature{size << kSizeShift};
439
+ }
440
+
441
+ //! \}
442
+ };
443
+
444
+ //! Base class representing an operand in AsmJit (non-default constructed version).
445
+ //!
446
+ //! Contains no initialization code and can be used safely to define an array of operands that won't be initialized.
447
+ //! This is a \ref Operand base structure designed to be statically initialized, static const, or to be used by user
448
+ //! code to define an array of operands without having them default initialized at construction time.
449
+ //!
450
+ //! The key difference between \ref Operand and \ref Operand_ is:
451
+ //!
452
+ //! ```
453
+ //! Operand_ xArray[10]; // Not initialized, contains garbage.
454
+ //! Operand_ yArray[10] {}; // All operands initialized to none explicitly (zero initialized).
455
+ //! Operand yArray[10]; // All operands initialized to none implicitly (zero initialized).
456
+ //! ```
457
+ struct Operand_ {
458
+ //! \name Types
459
+ //! \{
460
+
461
+ typedef OperandSignature Signature;
462
+
463
+ //! \}
464
+
465
+ //! \name Constants
466
+ //! \{
467
+
468
+ // Indexes to `_data` array.
469
+ enum DataIndex : uint32_t {
470
+ kDataMemIndexId = 0,
471
+ kDataMemOffsetLo = 1,
472
+
473
+ kDataImmValueLo = ASMJIT_ARCH_LE ? 0 : 1,
474
+ kDataImmValueHi = ASMJIT_ARCH_LE ? 1 : 0
475
+ };
476
+
477
+ //! Constants useful for VirtId <-> Index translation.
478
+ enum VirtIdConstants : uint32_t {
479
+ //! Minimum valid packed-id.
480
+ kVirtIdMin = 256,
481
+ //! Maximum valid packed-id, excludes Globals::kInvalidId.
482
+ kVirtIdMax = Globals::kInvalidId - 1,
483
+ //! Count of valid packed-ids.
484
+ kVirtIdCount = uint32_t(kVirtIdMax - kVirtIdMin + 1)
485
+ };
486
+
487
+ //! \}
488
+
489
+ //! \name Members
490
+ //! \{
491
+
492
+ //! Provides operand type and additional payload.
493
+ Signature _signature;
494
+ //! Either base id as used by memory operand or any id as used by others.
495
+ uint32_t _baseId;
496
+
497
+ //! Data specific to the operand type.
498
+ //!
499
+ //! The reason we don't use union is that we have `constexpr` constructors that construct operands and other
500
+ //!`constexpr` functions that return whether another Operand or something else. These cannot generally work with
501
+ //! unions so we also cannot use `union` if we want to be standard compliant.
502
+ uint32_t _data[2];
503
+
504
+ //! \}
505
+
506
+ //! Tests whether the given `id` is a valid virtual register id. Since AsmJit supports both physical and virtual
507
+ //! registers it must be able to distinguish between these two. The idea is that physical registers are always
508
+ //! limited in size, so virtual identifiers start from `kVirtIdMin` and end at `kVirtIdMax`.
509
+ static inline bool isVirtId(uint32_t id) noexcept { return id - kVirtIdMin < uint32_t(kVirtIdCount); }
510
+ //! Converts a real-id into a packed-id that can be stored in Operand.
511
+ static inline uint32_t indexToVirtId(uint32_t id) noexcept { return id + kVirtIdMin; }
512
+ //! Converts a packed-id back to real-id.
513
+ static inline uint32_t virtIdToIndex(uint32_t id) noexcept { return id - kVirtIdMin; }
514
+
515
+ //! \name Construction & Destruction
516
+ //! \{
517
+
518
+ //! \cond INTERNAL
519
+ //! Initializes a `BaseReg` operand from `signature` and register `id`.
520
+ inline void _initReg(const Signature& signature, uint32_t id) noexcept {
521
+ _signature = signature;
522
+ _baseId = id;
523
+ _data[0] = 0;
524
+ _data[1] = 0;
525
+ }
526
+ //! \endcond
527
+
528
+ //! Initializes the operand from `other` operand (used by operator overloads).
529
+ inline void copyFrom(const Operand_& other) noexcept { memcpy(this, &other, sizeof(Operand_)); }
530
+
531
+ //! Resets the `Operand` to none.
532
+ //!
533
+ //! None operand is defined the following way:
534
+ //! - Its signature is zero (OperandType::kNone, and the rest zero as well).
535
+ //! - Its id is `0`.
536
+ //! - The reserved8_4 field is set to `0`.
537
+ //! - The reserved12_4 field is set to zero.
538
+ //!
539
+ //! In other words, reset operands have all members set to zero. Reset operand must match the Operand state
540
+ //! right after its construction. Alternatively, if you have an array of operands, you can simply use `memset()`.
541
+ //!
542
+ //! ```
543
+ //! using namespace asmjit;
544
+ //!
545
+ //! Operand a;
546
+ //! Operand b;
547
+ //! assert(a == b);
548
+ //!
549
+ //! b = x86::eax;
550
+ //! assert(a != b);
551
+ //!
552
+ //! b.reset();
553
+ //! assert(a == b);
554
+ //!
555
+ //! memset(&b, 0, sizeof(Operand));
556
+ //! assert(a == b);
557
+ //! ```
558
+ inline void reset() noexcept {
559
+ _signature.reset();
560
+ _baseId = 0;
561
+ _data[0] = 0;
562
+ _data[1] = 0;
563
+ }
564
+
565
+ //! \}
566
+
567
+ //! \name Overloaded Operators
568
+ //! \{
569
+
570
+ //! Tests whether this operand is the same as `other`.
571
+ inline constexpr bool operator==(const Operand_& other) const noexcept { return equals(other); }
572
+ //! Tests whether this operand is not the same as `other`.
573
+ inline constexpr bool operator!=(const Operand_& other) const noexcept { return !equals(other); }
574
+
575
+ //! \}
576
+
577
+ //! \name Cast
578
+ //! \{
579
+
580
+ //! Casts this operand to `T` type.
581
+ template<typename T>
582
+ inline T& as() noexcept { return static_cast<T&>(*this); }
583
+
584
+ //! Casts this operand to `T` type (const).
585
+ template<typename T>
586
+ inline const T& as() const noexcept { return static_cast<const T&>(*this); }
587
+
588
+ //! \}
589
+
590
+ //! \name Accessors
591
+ //! \{
592
+
593
+ //! Tests whether the operand's signature matches the signature of the `other` operand.
594
+ inline constexpr bool hasSignature(const Operand_& other) const noexcept { return _signature == other._signature; }
595
+ //! Tests whether the operand's signature matches the given signature `sign`.
596
+ inline constexpr bool hasSignature(const Signature& other) const noexcept { return _signature == other; }
597
+
598
+ //! Returns operand signature as unsigned 32-bit integer.
599
+ //!
600
+ //! Signature is first 4 bytes of the operand data. It's used mostly for operand checking as it's
601
+ //! much faster to check packed 4 bytes at once than having to check these bytes individually.
602
+ inline constexpr Signature signature() const noexcept { return _signature; }
603
+
604
+ //! Sets the operand signature, see `signature()`.
605
+ //!
606
+ //! \note Improper use of `setSignature()` can lead to hard-to-debug errors.
607
+ inline void setSignature(const Signature& signature) noexcept { _signature = signature; }
608
+
609
+ //! Returns the type of the operand, see `OpType`.
610
+ inline constexpr OperandType opType() const noexcept { return _signature.opType(); }
611
+ //! Tests whether the operand is none (`OperandType::kNone`).
612
+ inline constexpr bool isNone() const noexcept { return _signature == Signature::fromBits(0); }
613
+ //! Tests whether the operand is a register (`OperandType::kReg`).
614
+ inline constexpr bool isReg() const noexcept { return opType() == OperandType::kReg; }
615
+ //! Tests whether the operand is a memory location (`OperandType::kMem`).
616
+ inline constexpr bool isMem() const noexcept { return opType() == OperandType::kMem; }
617
+ //! Tests whether the operand is an immediate (`OperandType::kImm`).
618
+ inline constexpr bool isImm() const noexcept { return opType() == OperandType::kImm; }
619
+ //! Tests whether the operand is a label (`OperandType::kLabel`).
620
+ inline constexpr bool isLabel() const noexcept { return opType() == OperandType::kLabel; }
621
+
622
+ //! Tests whether the operand is a physical register.
623
+ inline constexpr bool isPhysReg() const noexcept { return isReg() && _baseId < 0xFFu; }
624
+ //! Tests whether the operand is a virtual register.
625
+ inline constexpr bool isVirtReg() const noexcept { return isReg() && _baseId > 0xFFu; }
626
+
627
+ //! Tests whether the operand specifies a size (i.e. the size is not zero).
628
+ inline constexpr bool hasSize() const noexcept { return _signature.hasField<Signature::kSizeMask>(); }
629
+ //! Tests whether the size of the operand matches `size`.
630
+ inline constexpr bool hasSize(uint32_t s) const noexcept { return size() == s; }
631
+
632
+ //! Returns the size of the operand in bytes.
633
+ //!
634
+ //! The value returned depends on the operand type:
635
+ //! * None - Should always return zero size.
636
+ //! * Reg - Should always return the size of the register. If the register size depends on architecture
637
+ //! (like `x86::CReg` and `x86::DReg`) the size returned should be the greatest possible (so it
638
+ //! should return 64-bit size in such case).
639
+ //! * Mem - Size is optional and will be in most cases zero.
640
+ //! * Imm - Should always return zero size.
641
+ //! * Label - Should always return zero size.
642
+ inline constexpr uint32_t size() const noexcept { return _signature.getField<Signature::kSizeMask>(); }
643
+
644
+ //! Returns the operand id.
645
+ //!
646
+ //! The value returned should be interpreted accordingly to the operand type:
647
+ //! * None - Should be `0`.
648
+ //! * Reg - Physical or virtual register id.
649
+ //! * Mem - Multiple meanings - BASE address (register or label id), or high value of a 64-bit absolute address.
650
+ //! * Imm - Should be `0`.
651
+ //! * Label - Label id if it was created by using `newLabel()` or `Globals::kInvalidId` if the label is invalid or
652
+ //! not initialized.
653
+ inline constexpr uint32_t id() const noexcept { return _baseId; }
654
+
655
+ //! Tests whether the operand is 100% equal to `other` operand.
656
+ //!
657
+ //! \note This basically performs a binary comparison, if aby bit is
658
+ //! different the operands are not equal.
659
+ inline constexpr bool equals(const Operand_& other) const noexcept {
660
+ return (_signature == other._signature) &
661
+ (_baseId == other._baseId ) &
662
+ (_data[0] == other._data[0] ) &
663
+ (_data[1] == other._data[1] ) ;
664
+ }
665
+
666
+ //! Tests whether the operand is a register matching the given register `type`.
667
+ inline constexpr bool isReg(RegType type) const noexcept {
668
+ return _signature.subset(Signature::kOpTypeMask | Signature::kRegTypeMask) == (Signature::fromOpType(OperandType::kReg) | Signature::fromRegType(type));
669
+ }
670
+
671
+ //! Tests whether the operand is register and of register `type` and `id`.
672
+ inline constexpr bool isReg(RegType type, uint32_t id) const noexcept {
673
+ return isReg(type) && this->id() == id;
674
+ }
675
+
676
+ //! Tests whether the operand is a register or memory.
677
+ inline constexpr bool isRegOrMem() const noexcept {
678
+ return Support::isBetween<uint32_t>(uint32_t(opType()), uint32_t(OperandType::kReg), uint32_t(OperandType::kMem));
679
+ }
680
+
681
+ //! \}
682
+ };
683
+
684
+ //! Base class representing an operand in AsmJit (default constructed version).
685
+ class Operand : public Operand_ {
686
+ public:
687
+ //! \name Construction & Destruction
688
+ //! \{
689
+
690
+ //! Creates `kOpNone` operand having all members initialized to zero.
691
+ inline constexpr Operand() noexcept
692
+ : Operand_{ Signature::fromOpType(OperandType::kNone), 0u, { 0u, 0u }} {}
693
+
694
+ //! Creates a cloned `other` operand.
695
+ inline constexpr Operand(const Operand& other) noexcept = default;
696
+
697
+ //! Creates a cloned `other` operand.
698
+ inline constexpr explicit Operand(const Operand_& other)
699
+ : Operand_(other) {}
700
+
701
+ //! Creates an operand initialized to raw `[u0, u1, u2, u3]` values.
702
+ inline constexpr Operand(Globals::Init_, const Signature& u0, uint32_t u1, uint32_t u2, uint32_t u3) noexcept
703
+ : Operand_{ u0, u1, { u2, u3 }} {}
704
+
705
+ //! Creates an uninitialized operand (dangerous).
706
+ inline explicit Operand(Globals::NoInit_) noexcept {}
707
+
708
+ //! \}
709
+
710
+ //! \name Overloaded Operators
711
+ //! \{
712
+
713
+ inline Operand& operator=(const Operand& other) noexcept = default;
714
+ inline Operand& operator=(const Operand_& other) noexcept { return operator=(static_cast<const Operand&>(other)); }
715
+
716
+ //! \}
717
+
718
+ //! \name Clone
719
+ //! \{
720
+
721
+ //! Clones this operand and returns its copy.
722
+ inline constexpr Operand clone() const noexcept { return Operand(*this); }
723
+
724
+ //! \}
725
+ };
726
+
727
+ static_assert(sizeof(Operand) == 16, "asmjit::Operand must be exactly 16 bytes long");
728
+
729
+ //! Label (jump target or data location).
730
+ //!
731
+ //! Label represents a location in code typically used as a jump target, but may be also a reference to some data or
732
+ //! a static variable. Label has to be explicitly created by BaseEmitter.
733
+ //!
734
+ //! Example of using labels:
735
+ //!
736
+ //! ```
737
+ //! // Create some emitter (for example x86::Assembler).
738
+ //! x86::Assembler a;
739
+ //!
740
+ //! // Create Label instance.
741
+ //! Label L1 = a.newLabel();
742
+ //!
743
+ //! // ... your code ...
744
+ //!
745
+ //! // Using label.
746
+ //! a.jump(L1);
747
+ //!
748
+ //! // ... your code ...
749
+ //!
750
+ //! // Bind label to the current position, see `BaseEmitter::bind()`.
751
+ //! a.bind(L1);
752
+ //! ```
753
+ class Label : public Operand {
754
+ public:
755
+ //! \name Construction & Destruction
756
+ //! \{
757
+
758
+ //! Creates a label operand without ID (you must set the ID to make it valid).
759
+ inline constexpr Label() noexcept
760
+ : Operand(Globals::Init, Signature::fromOpType(OperandType::kLabel), Globals::kInvalidId, 0, 0) {}
761
+
762
+ //! Creates a cloned label operand of `other`.
763
+ inline constexpr Label(const Label& other) noexcept
764
+ : Operand(other) {}
765
+
766
+ //! Creates a label operand of the given `id`.
767
+ inline constexpr explicit Label(uint32_t id) noexcept
768
+ : Operand(Globals::Init, Signature::fromOpType(OperandType::kLabel), id, 0, 0) {}
769
+
770
+ inline explicit Label(Globals::NoInit_) noexcept
771
+ : Operand(Globals::NoInit) {}
772
+
773
+ //! Resets the label, will reset all properties and set its ID to `Globals::kInvalidId`.
774
+ inline void reset() noexcept {
775
+ _signature = Signature::fromOpType(OperandType::kLabel);
776
+ _baseId = Globals::kInvalidId;
777
+ _data[0] = 0;
778
+ _data[1] = 0;
779
+ }
780
+
781
+ //! \}
782
+
783
+ //! \name Overloaded Operators
784
+ //! \{
785
+
786
+ inline Label& operator=(const Label& other) noexcept = default;
787
+
788
+ //! \}
789
+
790
+ //! \name Accessors
791
+ //! \{
792
+
793
+ //! Tests whether the label was created by CodeHolder and/or an attached emitter.
794
+ inline constexpr bool isValid() const noexcept { return _baseId != Globals::kInvalidId; }
795
+ //! Sets the label `id`.
796
+ inline void setId(uint32_t id) noexcept { _baseId = id; }
797
+
798
+ //! \}
799
+ };
800
+
801
+ //! \cond INTERNAL
802
+ //! Default register traits.
803
+ struct BaseRegTraits {
804
+ enum : uint32_t {
805
+ //! \ref TypeId representing this register type, could be \ref TypeId::kVoid if such type doesn't exist.
806
+ kTypeId = uint32_t(TypeId::kVoid),
807
+ //! RegType is not valid by default.
808
+ kValid = 0,
809
+ //! Count of registers (0 if none).
810
+ kCount = 0,
811
+
812
+ //! Zero type by default (defeaults to None).
813
+ kType = uint32_t(RegType::kNone),
814
+ //! Zero group by default (defaults to GP).
815
+ kGroup = uint32_t(RegGroup::kGp),
816
+ //! No size by default.
817
+ kSize = 0,
818
+
819
+ //! Empty signature by default (not even having operand type set to register).
820
+ kSignature = 0
821
+ };
822
+ };
823
+ //! \endcond
824
+
825
+ //! Physical or virtual register operand.
826
+ class BaseReg : public Operand {
827
+ public:
828
+ //! \name Constants
829
+ //! \{
830
+
831
+ enum : uint32_t {
832
+ //! None or any register (mostly internal).
833
+ kIdBad = 0xFFu,
834
+
835
+ kBaseSignatureMask =
836
+ Signature::kOpTypeMask |
837
+ Signature::kRegTypeMask |
838
+ Signature::kRegGroupMask |
839
+ Signature::kSizeMask,
840
+
841
+ kTypeNone = uint32_t(RegType::kNone),
842
+ kSignature = Signature::fromOpType(OperandType::kReg).bits()
843
+ };
844
+
845
+ //! \}
846
+
847
+ //! \name Construction & Destruction
848
+ //! \{
849
+
850
+ //! Creates a dummy register operand.
851
+ inline constexpr BaseReg() noexcept
852
+ : Operand(Globals::Init, Signature::fromOpType(OperandType::kReg), kIdBad, 0, 0) {}
853
+
854
+ //! Creates a new register operand which is the same as `other` .
855
+ inline constexpr BaseReg(const BaseReg& other) noexcept
856
+ : Operand(other) {}
857
+
858
+ //! Creates a new register operand compatible with `other`, but with a different `id`.
859
+ inline constexpr BaseReg(const BaseReg& other, uint32_t id) noexcept
860
+ : Operand(Globals::Init, other._signature, id, 0, 0) {}
861
+
862
+ //! Creates a register initialized to the given `signature` and `id`.
863
+ inline constexpr BaseReg(const Signature& signature, uint32_t id) noexcept
864
+ : Operand(Globals::Init, signature, id, 0, 0) {}
865
+
866
+ inline explicit BaseReg(Globals::NoInit_) noexcept
867
+ : Operand(Globals::NoInit) {}
868
+
869
+ //! \}
870
+
871
+ //! \name Overloaded Operators
872
+ //! \{
873
+
874
+ inline BaseReg& operator=(const BaseReg& other) noexcept = default;
875
+
876
+ //! \}
877
+
878
+ //! \name Accessors
879
+ //! \{
880
+
881
+ //! Returns base signature of the register associated with each register type.
882
+ //!
883
+ //! Base signature only contains the operand type, register type, register group, and register size. It doesn't
884
+ //! contain element type, predicate, or other architecture-specific data. Base signature is a signature that is
885
+ //! provided by architecture-specific `RegTraits`, like \ref x86::RegTraits.
886
+ inline constexpr OperandSignature baseSignature() const noexcept { return _signature & kBaseSignatureMask; }
887
+
888
+ //! Tests whether the operand's base signature matches the given signature `sign`.
889
+ inline constexpr bool hasBaseSignature(uint32_t signature) const noexcept { return baseSignature() == signature; }
890
+ //! Tests whether the operand's base signature matches the given signature `sign`.
891
+ inline constexpr bool hasBaseSignature(const OperandSignature& signature) const noexcept { return baseSignature() == signature; }
892
+ //! Tests whether the operand's base signature matches the base signature of the `other` operand.
893
+ inline constexpr bool hasBaseSignature(const BaseReg& other) const noexcept { return baseSignature() == other.baseSignature(); }
894
+
895
+ //! Tests whether this register is the same as `other`.
896
+ //!
897
+ //! This is just an optimization. Registers by default only use the first 8 bytes of Operand data, so this method
898
+ //! takes advantage of this knowledge and only compares these 8 bytes. If both operands were created correctly
899
+ //! both \ref equals() and \ref isSame() should give the same answer, however, if any of these two contains garbage
900
+ //! or other metadata in the upper 8 bytes then \ref isSame() may return `true` in cases in which \ref equals()
901
+ //! returns false.
902
+ inline constexpr bool isSame(const BaseReg& other) const noexcept {
903
+ return (_signature == other._signature) & (_baseId == other._baseId);
904
+ }
905
+
906
+ //! Tests whether the register is valid (either virtual or physical).
907
+ inline constexpr bool isValid() const noexcept { return (_signature != 0) & (_baseId != kIdBad); }
908
+
909
+ //! Tests whether this is a physical register.
910
+ inline constexpr bool isPhysReg() const noexcept { return _baseId < kIdBad; }
911
+ //! Tests whether this is a virtual register.
912
+ inline constexpr bool isVirtReg() const noexcept { return _baseId > kIdBad; }
913
+
914
+ //! Tests whether the register type matches `type` - same as `isReg(type)`, provided for convenience.
915
+ inline constexpr bool isType(RegType type) const noexcept { return _signature.subset(Signature::kRegTypeMask) == Signature::fromRegType(type); }
916
+ //! Tests whether the register group matches `group`.
917
+ inline constexpr bool isGroup(RegGroup group) const noexcept { return _signature.subset(Signature::kRegGroupMask) == Signature::fromRegGroup(group); }
918
+
919
+ //! Tests whether the register is a general purpose register (any size).
920
+ inline constexpr bool isGp() const noexcept { return isGroup(RegGroup::kGp); }
921
+ //! Tests whether the register is a vector register.
922
+ inline constexpr bool isVec() const noexcept { return isGroup(RegGroup::kVec); }
923
+
924
+ using Operand_::isReg;
925
+
926
+ //! Same as `isType()`, provided for convenience.
927
+ inline constexpr bool isReg(RegType rType) const noexcept { return isType(rType); }
928
+ //! Tests whether the register type matches `type` and register id matches `id`.
929
+ inline constexpr bool isReg(RegType rType, uint32_t id) const noexcept { return isType(rType) && this->id() == id; }
930
+
931
+ //! Returns the register type.
932
+ inline constexpr RegType type() const noexcept { return _signature.regType(); }
933
+ //! Returns the register group.
934
+ inline constexpr RegGroup group() const noexcept { return _signature.regGroup(); }
935
+
936
+ //! Returns operation predicate of the register (ARM/AArch64).
937
+ //!
938
+ //! The meaning depends on architecture, for example on ARM hardware this describes \ref arm::ShiftOp
939
+ //! of the register.
940
+ inline constexpr uint32_t predicate() const noexcept { return _signature.getField<Signature::kPredicateMask>(); }
941
+
942
+ //! Sets operation predicate of the register to `predicate` (ARM/AArch64).
943
+ //!
944
+ //! The meaning depends on architecture, for example on ARM hardware this describes \ref arm::ShiftOp
945
+ //! of the register.
946
+ inline void setPredicate(uint32_t predicate) noexcept { _signature.setField<Signature::kPredicateMask>(predicate); }
947
+
948
+ //! Resets shift operation type of the register to the default value (ARM/AArch64).
949
+ inline void resetPredicate() noexcept { _signature.setField<Signature::kPredicateMask>(0); }
950
+
951
+ //! Clones the register operand.
952
+ inline constexpr BaseReg clone() const noexcept { return BaseReg(*this); }
953
+
954
+ //! Casts this register to `RegT` by also changing its signature.
955
+ //!
956
+ //! \note Improper use of `cloneAs()` can lead to hard-to-debug errors.
957
+ template<typename RegT>
958
+ inline constexpr RegT cloneAs() const noexcept { return RegT(Signature(RegT::kSignature), id()); }
959
+
960
+ //! Casts this register to `other` by also changing its signature.
961
+ //!
962
+ //! \note Improper use of `cloneAs()` can lead to hard-to-debug errors.
963
+ template<typename RegT>
964
+ inline constexpr RegT cloneAs(const RegT& other) const noexcept { return RegT(other.signature(), id()); }
965
+
966
+ //! Sets the register id to `id`.
967
+ inline void setId(uint32_t id) noexcept { _baseId = id; }
968
+
969
+ //! Sets a 32-bit operand signature based on traits of `RegT`.
970
+ template<typename RegT>
971
+ inline void setSignatureT() noexcept { _signature = RegT::kSignature; }
972
+
973
+ //! Sets the register `signature` and `id`.
974
+ inline void setSignatureAndId(const OperandSignature& signature, uint32_t id) noexcept {
975
+ _signature = signature;
976
+ _baseId = id;
977
+ }
978
+
979
+ //! \}
980
+
981
+ //! \name Static Functions
982
+ //! \{
983
+
984
+ //! Tests whether the `op` operand is a general purpose register.
985
+ static inline bool isGp(const Operand_& op) noexcept {
986
+ // Check operand type and register group. Not interested in register type and size.
987
+ return op.signature().subset(Signature::kOpTypeMask | Signature::kRegGroupMask) == (Signature::fromOpType(OperandType::kReg) | Signature::fromRegGroup(RegGroup::kGp));
988
+ }
989
+
990
+ //! Tests whether the `op` operand is a vector register.
991
+ static inline bool isVec(const Operand_& op) noexcept {
992
+ // Check operand type and register group. Not interested in register type and size.
993
+ return op.signature().subset(Signature::kOpTypeMask | Signature::kRegGroupMask) == (Signature::fromOpType(OperandType::kReg) | Signature::fromRegGroup(RegGroup::kVec));
994
+ }
995
+
996
+ //! Tests whether the `op` is a general purpose register of the given `id`.
997
+ static inline bool isGp(const Operand_& op, uint32_t id) noexcept { return isGp(op) & (op.id() == id); }
998
+ //! Tests whether the `op` is a vector register of the given `id`.
999
+ static inline bool isVec(const Operand_& op, uint32_t id) noexcept { return isVec(op) & (op.id() == id); }
1000
+
1001
+ //! \}
1002
+ };
1003
+
1004
+ //! RegOnly is 8-byte version of `BaseReg` that allows to store either register or nothing.
1005
+ //!
1006
+ //! It's designed to decrease the space consumed by an extra "operand" in \ref BaseEmitter and \ref InstNode.
1007
+ struct RegOnly {
1008
+ //! \name Types
1009
+ //! \{
1010
+
1011
+ typedef OperandSignature Signature;
1012
+
1013
+ //! \}
1014
+
1015
+ //! Operand signature - only \ref OperandType::kNone and \ref OperandType::kReg are supported.
1016
+ Signature _signature;
1017
+ //! Physical or virtual register id.
1018
+ uint32_t _id;
1019
+
1020
+ //! \name Construction & Destruction
1021
+ //! \{
1022
+
1023
+ //! Initializes the `RegOnly` instance to hold register `signature` and `id`.
1024
+ inline void init(const OperandSignature& signature, uint32_t id) noexcept {
1025
+ _signature = signature;
1026
+ _id = id;
1027
+ }
1028
+
1029
+ inline void init(const BaseReg& reg) noexcept { init(reg.signature(), reg.id()); }
1030
+ inline void init(const RegOnly& reg) noexcept { init(reg.signature(), reg.id()); }
1031
+
1032
+ //! Resets the `RegOnly` members to zeros (none).
1033
+ inline void reset() noexcept { init(Signature::fromBits(0), 0); }
1034
+
1035
+ //! \}
1036
+
1037
+ //! \name Accessors
1038
+ //! \{
1039
+
1040
+ //! Tests whether this ExtraReg is none (same as calling `Operand_::isNone()`).
1041
+ inline constexpr bool isNone() const noexcept { return _signature == 0; }
1042
+ //! Tests whether the register is valid (either virtual or physical).
1043
+ inline constexpr bool isReg() const noexcept { return _signature != 0; }
1044
+
1045
+ //! Tests whether this is a physical register.
1046
+ inline constexpr bool isPhysReg() const noexcept { return _id < BaseReg::kIdBad; }
1047
+ //! Tests whether this is a virtual register (used by `BaseCompiler`).
1048
+ inline constexpr bool isVirtReg() const noexcept { return _id > BaseReg::kIdBad; }
1049
+
1050
+ //! Returns the register signature or 0 if no register is assigned.
1051
+ inline constexpr OperandSignature signature() const noexcept { return _signature; }
1052
+ //! Returns the register id.
1053
+ //!
1054
+ //! \note Always check whether the register is assigned before using the returned identifier as
1055
+ //! non-assigned `RegOnly` instance would return zero id, which is still a valid register id.
1056
+ inline constexpr uint32_t id() const noexcept { return _id; }
1057
+
1058
+ //! Sets the register id.
1059
+ inline void setId(uint32_t id) noexcept { _id = id; }
1060
+
1061
+ //! Returns the register type.
1062
+ inline constexpr RegType type() const noexcept { return _signature.regType(); }
1063
+ //! Returns the register group.
1064
+ inline constexpr RegGroup group() const noexcept { return _signature.regGroup(); }
1065
+
1066
+ //! \}
1067
+
1068
+ //! \name Utilities
1069
+ //! \{
1070
+
1071
+ //! Converts this ExtraReg to a real `RegT` operand.
1072
+ template<typename RegT>
1073
+ inline constexpr RegT toReg() const noexcept { return RegT(_signature, _id); }
1074
+
1075
+ //! \}
1076
+ };
1077
+
1078
+ //! \cond INTERNAL
1079
+ //! Adds a template specialization for `REG_TYPE` into the local `RegTraits`.
1080
+ #define ASMJIT_DEFINE_REG_TRAITS(REG, REG_TYPE, GROUP, SIZE, COUNT, TYPE_ID) \
1081
+ template<> \
1082
+ struct RegTraits<REG_TYPE> { \
1083
+ typedef REG RegT; \
1084
+ \
1085
+ enum : uint32_t { \
1086
+ kValid = uint32_t(true), \
1087
+ kCount = uint32_t(COUNT), \
1088
+ kType = uint32_t(REG_TYPE), \
1089
+ kGroup = uint32_t(GROUP), \
1090
+ kSize = uint32_t(SIZE), \
1091
+ kTypeId = uint32_t(TYPE_ID), \
1092
+ \
1093
+ kSignature = (OperandSignature::fromOpType(OperandType::kReg) | \
1094
+ OperandSignature::fromRegType(REG_TYPE) | \
1095
+ OperandSignature::fromRegGroup(GROUP) | \
1096
+ OperandSignature::fromSize(kSize)).bits(), \
1097
+ }; \
1098
+ }
1099
+
1100
+ //! Adds constructors and member functions to a class that implements abstract register. Abstract register is register
1101
+ //! that doesn't have type or signature yet, it's a base class like `x86::Reg` or `arm::Reg`.
1102
+ #define ASMJIT_DEFINE_ABSTRACT_REG(REG, BASE) \
1103
+ public: \
1104
+ /*! Default constructor that only setups basics. */ \
1105
+ inline constexpr REG() noexcept \
1106
+ : BASE(Signature{kSignature}, kIdBad) {} \
1107
+ \
1108
+ /*! Makes a copy of the `other` register operand. */ \
1109
+ inline constexpr REG(const REG& other) noexcept \
1110
+ : BASE(other) {} \
1111
+ \
1112
+ /*! Makes a copy of the `other` register having id set to `id` */ \
1113
+ inline constexpr REG(const BaseReg& other, uint32_t id) noexcept \
1114
+ : BASE(other, id) {} \
1115
+ \
1116
+ /*! Creates a register based on `signature` and `id`. */ \
1117
+ inline constexpr REG(const OperandSignature& sgn, uint32_t id) noexcept \
1118
+ : BASE(sgn, id) {} \
1119
+ \
1120
+ /*! Creates a completely uninitialized REG register operand (garbage). */ \
1121
+ inline explicit REG(Globals::NoInit_) noexcept \
1122
+ : BASE(Globals::NoInit) {} \
1123
+ \
1124
+ /*! Creates a new register from register type and id. */ \
1125
+ static inline REG fromTypeAndId(RegType type, uint32_t id) noexcept { \
1126
+ return REG(signatureOf(type), id); \
1127
+ } \
1128
+ \
1129
+ /*! Clones the register operand. */ \
1130
+ inline constexpr REG clone() const noexcept { return REG(*this); } \
1131
+ \
1132
+ inline REG& operator=(const REG& other) noexcept = default;
1133
+
1134
+ //! Adds constructors and member functions to a class that implements final register. Final registers MUST HAVE a valid
1135
+ //! signature.
1136
+ #define ASMJIT_DEFINE_FINAL_REG(REG, BASE, TRAITS) \
1137
+ public: \
1138
+ enum : uint32_t { \
1139
+ kThisType = TRAITS::kType, \
1140
+ kThisGroup = TRAITS::kGroup, \
1141
+ kThisSize = TRAITS::kSize, \
1142
+ kSignature = TRAITS::kSignature \
1143
+ }; \
1144
+ \
1145
+ ASMJIT_DEFINE_ABSTRACT_REG(REG, BASE) \
1146
+ \
1147
+ /*! Creates a register operand having its id set to `id`. */ \
1148
+ inline constexpr explicit REG(uint32_t id) noexcept \
1149
+ : BASE(Signature{kSignature}, id) {}
1150
+ //! \endcond
1151
+
1152
+ //! Base class for all memory operands.
1153
+ //!
1154
+ //! The data is split into the following parts:
1155
+ //!
1156
+ //! - BASE - Base register or label - requires 36 bits total. 4 bits are used to encode the type of the BASE operand
1157
+ //! (label vs. register type) and the remaining 32 bits define the BASE id, which can be a physical or virtual
1158
+ //! register index. If BASE type is zero, which is never used as a register type and label doesn't use it as well
1159
+ //! then BASE field contains a high DWORD of a possible 64-bit absolute address, which is possible on X64.
1160
+ //!
1161
+ //! - INDEX - Index register (or theoretically Label, which doesn't make sense). Encoding is similar to BASE - it
1162
+ //! also requires 36 bits and splits the encoding to INDEX type (4 bits defining the register type) and 32-bit id.
1163
+ //!
1164
+ //! - OFFSET - A relative offset of the address. Basically if BASE is specified the relative displacement adjusts
1165
+ //! BASE and an optional INDEX. if BASE is not specified then the OFFSET should be considered as ABSOLUTE address
1166
+ //! (at least on X86). In that case its low 32 bits are stored in DISPLACEMENT field and the remaining high 32
1167
+ //! bits are stored in BASE.
1168
+ //!
1169
+ //! - OTHER - There is rest 8 bits that can be used for whatever purpose. For example \ref x86::Mem operand uses
1170
+ //! these bits to store segment override prefix and index shift (or scale).
1171
+ class BaseMem : public Operand {
1172
+ public:
1173
+ //! \name Construction & Destruction
1174
+ //! \{
1175
+
1176
+ //! Creates a default `BaseMem` operand, that points to [0].
1177
+ inline constexpr BaseMem() noexcept
1178
+ : Operand(Globals::Init, Signature::fromOpType(OperandType::kMem), 0, 0, 0) {}
1179
+
1180
+ //! Creates a `BaseMem` operand that is a clone of `other`.
1181
+ inline constexpr BaseMem(const BaseMem& other) noexcept
1182
+ : Operand(other) {}
1183
+
1184
+ //! Creates a `BaseMem` operand from `baseReg` and `offset`.
1185
+ //!
1186
+ //! \note This is an architecture independent constructor that can be used to create an architecture
1187
+ //! independent memory operand to be used in portable code that can handle multiple architectures.
1188
+ inline constexpr explicit BaseMem(const BaseReg& baseReg, int32_t offset = 0) noexcept
1189
+ : Operand(Globals::Init,
1190
+ Signature::fromOpType(OperandType::kMem) | Signature::fromMemBaseType(baseReg.type()),
1191
+ baseReg.id(),
1192
+ 0,
1193
+ uint32_t(offset)) {}
1194
+
1195
+ //! \cond INTERNAL
1196
+ //! Creates a `BaseMem` operand from 4 integers as used by `Operand_` struct.
1197
+ inline constexpr BaseMem(const OperandSignature& u0, uint32_t baseId, uint32_t indexId, int32_t offset) noexcept
1198
+ : Operand(Globals::Init, u0, baseId, indexId, uint32_t(offset)) {}
1199
+ //! \endcond
1200
+
1201
+ //! Creates a completely uninitialized `BaseMem` operand.
1202
+ inline explicit BaseMem(Globals::NoInit_) noexcept
1203
+ : Operand(Globals::NoInit) {}
1204
+
1205
+ //! Resets the memory operand - after the reset the memory points to [0].
1206
+ inline void reset() noexcept {
1207
+ _signature = Signature::fromOpType(OperandType::kMem);
1208
+ _baseId = 0;
1209
+ _data[0] = 0;
1210
+ _data[1] = 0;
1211
+ }
1212
+
1213
+ //! \}
1214
+
1215
+ //! \name Overloaded Operators
1216
+ //! \{
1217
+
1218
+ inline BaseMem& operator=(const BaseMem& other) noexcept { copyFrom(other); return *this; }
1219
+
1220
+ //! \}
1221
+
1222
+ //! \name Accessors
1223
+ //! \{
1224
+
1225
+ //! Clones the memory operand.
1226
+ inline constexpr BaseMem clone() const noexcept { return BaseMem(*this); }
1227
+
1228
+ //! Creates a new copy of this memory operand adjusted by `off`.
1229
+ inline BaseMem cloneAdjusted(int64_t off) const noexcept {
1230
+ BaseMem result(*this);
1231
+ result.addOffset(off);
1232
+ return result;
1233
+ }
1234
+
1235
+ //! Tests whether this memory operand is a register home (only used by \ref asmjit_compiler)
1236
+ inline constexpr bool isRegHome() const noexcept { return _signature.hasField<Signature::kMemRegHomeFlag>(); }
1237
+ //! Mark this memory operand as register home (only used by \ref asmjit_compiler).
1238
+ inline void setRegHome() noexcept { _signature |= Signature::kMemRegHomeFlag; }
1239
+ //! Marks this operand to not be a register home (only used by \ref asmjit_compiler).
1240
+ inline void clearRegHome() noexcept { _signature &= ~Signature::kMemRegHomeFlag; }
1241
+
1242
+ //! Tests whether the memory operand has a BASE register or label specified.
1243
+ inline constexpr bool hasBase() const noexcept {
1244
+ return (_signature & Signature::kMemBaseTypeMask) != 0;
1245
+ }
1246
+
1247
+ //! Tests whether the memory operand has an INDEX register specified.
1248
+ inline constexpr bool hasIndex() const noexcept {
1249
+ return (_signature & Signature::kMemIndexTypeMask) != 0;
1250
+ }
1251
+
1252
+ //! Tests whether the memory operand has BASE or INDEX register.
1253
+ inline constexpr bool hasBaseOrIndex() const noexcept {
1254
+ return (_signature & Signature::kMemBaseIndexMask) != 0;
1255
+ }
1256
+
1257
+ //! Tests whether the memory operand has BASE and INDEX register.
1258
+ inline constexpr bool hasBaseAndIndex() const noexcept {
1259
+ return (_signature & Signature::kMemBaseTypeMask) != 0 && (_signature & Signature::kMemIndexTypeMask) != 0;
1260
+ }
1261
+
1262
+ //! Tests whether the BASE operand is a label.
1263
+ inline constexpr bool hasBaseLabel() const noexcept {
1264
+ return _signature.subset(Signature::kMemBaseTypeMask) == Signature::fromMemBaseType(RegType::kLabelTag);
1265
+ }
1266
+
1267
+ //! Tests whether the BASE operand is a register (registers start after `RegType::kLabelTag`).
1268
+ inline constexpr bool hasBaseReg() const noexcept {
1269
+ return _signature.subset(Signature::kMemBaseTypeMask).bits() > Signature::fromMemBaseType(RegType::kLabelTag).bits();
1270
+ }
1271
+
1272
+ //! Tests whether the INDEX operand is a register (registers start after `RegType::kLabelTag`).
1273
+ inline constexpr bool hasIndexReg() const noexcept {
1274
+ return _signature.subset(Signature::kMemIndexTypeMask).bits() > Signature::fromMemIndexType(RegType::kLabelTag).bits();
1275
+ }
1276
+
1277
+ //! Returns the type of the BASE register (0 if this memory operand doesn't use the BASE register).
1278
+ //!
1279
+ //! \note If the returned type is one (a value never associated to a register type) the BASE is not register, but it
1280
+ //! is a label. One equals to `kLabelTag`. You should always check `hasBaseLabel()` before using `baseId()` result.
1281
+ inline constexpr RegType baseType() const noexcept { return _signature.memBaseType(); }
1282
+
1283
+ //! Returns the type of an INDEX register (0 if this memory operand doesn't
1284
+ //! use the INDEX register).
1285
+ inline constexpr RegType indexType() const noexcept { return _signature.memIndexType(); }
1286
+
1287
+ //! This is used internally for BASE+INDEX validation.
1288
+ inline constexpr uint32_t baseAndIndexTypes() const noexcept { return _signature.getField<Signature::kMemBaseIndexMask>(); }
1289
+
1290
+ //! Returns both BASE (4:0 bits) and INDEX (9:5 bits) types combined into a single value.
1291
+ //!
1292
+ //! \remarks Returns id of the BASE register or label (if the BASE was specified as label).
1293
+ inline constexpr uint32_t baseId() const noexcept { return _baseId; }
1294
+
1295
+ //! Returns the id of the INDEX register.
1296
+ inline constexpr uint32_t indexId() const noexcept { return _data[kDataMemIndexId]; }
1297
+
1298
+ //! Sets the id of the BASE register (without modifying its type).
1299
+ inline void setBaseId(uint32_t id) noexcept { _baseId = id; }
1300
+ //! Sets the id of the INDEX register (without modifying its type).
1301
+ inline void setIndexId(uint32_t id) noexcept { _data[kDataMemIndexId] = id; }
1302
+
1303
+ //! Sets the base register to type and id of the given `base` operand.
1304
+ inline void setBase(const BaseReg& base) noexcept { return _setBase(base.type(), base.id()); }
1305
+ //! Sets the index register to type and id of the given `index` operand.
1306
+ inline void setIndex(const BaseReg& index) noexcept { return _setIndex(index.type(), index.id()); }
1307
+
1308
+ //! \cond INTERNAL
1309
+ inline void _setBase(RegType type, uint32_t id) noexcept {
1310
+ _signature.setField<Signature::kMemBaseTypeMask>(uint32_t(type));
1311
+ _baseId = id;
1312
+ }
1313
+
1314
+ inline void _setIndex(RegType type, uint32_t id) noexcept {
1315
+ _signature.setField<Signature::kMemIndexTypeMask>(uint32_t(type));
1316
+ _data[kDataMemIndexId] = id;
1317
+ }
1318
+ //! \endcond
1319
+
1320
+ //! Resets the memory operand's BASE register or label.
1321
+ inline void resetBase() noexcept { _setBase(RegType::kNone, 0); }
1322
+ //! Resets the memory operand's INDEX register.
1323
+ inline void resetIndex() noexcept { _setIndex(RegType::kNone, 0); }
1324
+
1325
+ //! Sets the memory operand size (in bytes).
1326
+ inline void setSize(uint32_t size) noexcept { _signature.setField<Signature::kSizeMask>(size); }
1327
+
1328
+ //! Tests whether the memory operand has a 64-bit offset or absolute address.
1329
+ //!
1330
+ //! If this is true then `hasBase()` must always report false.
1331
+ inline constexpr bool isOffset64Bit() const noexcept { return baseType() == RegType::kNone; }
1332
+
1333
+ //! Tests whether the memory operand has a non-zero offset or absolute address.
1334
+ inline constexpr bool hasOffset() const noexcept {
1335
+ return (_data[kDataMemOffsetLo] | uint32_t(_baseId & Support::bitMaskFromBool<uint32_t>(isOffset64Bit()))) != 0;
1336
+ }
1337
+
1338
+ //! Returns either relative offset or absolute address as 64-bit integer.
1339
+ inline constexpr int64_t offset() const noexcept {
1340
+ return isOffset64Bit() ? int64_t(uint64_t(_data[kDataMemOffsetLo]) | (uint64_t(_baseId) << 32))
1341
+ : int64_t(int32_t(_data[kDataMemOffsetLo])); // Sign extend 32-bit offset.
1342
+ }
1343
+
1344
+ //! Returns a 32-bit low part of a 64-bit offset or absolute address.
1345
+ inline constexpr int32_t offsetLo32() const noexcept { return int32_t(_data[kDataMemOffsetLo]); }
1346
+ //! Returns a 32-but high part of a 64-bit offset or absolute address.
1347
+ //!
1348
+ //! \note This function is UNSAFE and returns garbage if `isOffset64Bit()`
1349
+ //! returns false. Never use it blindly without checking it first.
1350
+ inline constexpr int32_t offsetHi32() const noexcept { return int32_t(_baseId); }
1351
+
1352
+ //! Sets a 64-bit offset or an absolute address to `offset`.
1353
+ //!
1354
+ //! \note This functions attempts to set both high and low parts of a 64-bit offset, however, if the operand has
1355
+ //! a BASE register it will store only the low 32 bits of the offset / address as there is no way to store both
1356
+ //! BASE and 64-bit offset, and there is currently no architecture that has such capability targeted by AsmJit.
1357
+ inline void setOffset(int64_t offset) noexcept {
1358
+ uint32_t lo = uint32_t(uint64_t(offset) & 0xFFFFFFFFu);
1359
+ uint32_t hi = uint32_t(uint64_t(offset) >> 32);
1360
+ uint32_t hiMsk = Support::bitMaskFromBool<uint32_t>(isOffset64Bit());
1361
+
1362
+ _data[kDataMemOffsetLo] = lo;
1363
+ _baseId = (hi & hiMsk) | (_baseId & ~hiMsk);
1364
+ }
1365
+ //! Sets a low 32-bit offset to `offset` (don't use without knowing how BaseMem works).
1366
+ inline void setOffsetLo32(int32_t offset) noexcept { _data[kDataMemOffsetLo] = uint32_t(offset); }
1367
+
1368
+ //! Adjusts the offset by `offset`.
1369
+ //!
1370
+ //! \note This is a fast function that doesn't use the HI 32-bits of a 64-bit offset. Use it only if you know that
1371
+ //! there is a BASE register and the offset is only 32 bits anyway.
1372
+
1373
+ //! Adjusts the memory operand offset by a `offset`.
1374
+ inline void addOffset(int64_t offset) noexcept {
1375
+ if (isOffset64Bit()) {
1376
+ int64_t result = offset + int64_t(uint64_t(_data[kDataMemOffsetLo]) | (uint64_t(_baseId) << 32));
1377
+ _data[kDataMemOffsetLo] = uint32_t(uint64_t(result) & 0xFFFFFFFFu);
1378
+ _baseId = uint32_t(uint64_t(result) >> 32);
1379
+ }
1380
+ else {
1381
+ _data[kDataMemOffsetLo] += uint32_t(uint64_t(offset) & 0xFFFFFFFFu);
1382
+ }
1383
+ }
1384
+
1385
+ //! Adds `offset` to a low 32-bit offset part (don't use without knowing how BaseMem works).
1386
+ inline void addOffsetLo32(int32_t offset) noexcept { _data[kDataMemOffsetLo] += uint32_t(offset); }
1387
+
1388
+ //! Resets the memory offset to zero.
1389
+ inline void resetOffset() noexcept { setOffset(0); }
1390
+
1391
+ //! Resets the lo part of the memory offset to zero (don't use without knowing how BaseMem works).
1392
+ inline void resetOffsetLo32() noexcept { setOffsetLo32(0); }
1393
+
1394
+ //! \}
1395
+ };
1396
+
1397
+ //! Type of the an immediate value.
1398
+ enum class ImmType : uint32_t {
1399
+ //! Immediate is integer.
1400
+ kInt = 0,
1401
+ //! Immediate is a floating point stored as double-precision.
1402
+ kDouble = 1
1403
+ };
1404
+
1405
+ //! Immediate operands are encoded with instruction data.
1406
+ class Imm : public Operand {
1407
+ public:
1408
+ //! \cond INTERNAL
1409
+ template<typename T>
1410
+ struct IsConstexprConstructibleAsImmType
1411
+ : public std::integral_constant<bool, std::is_enum<T>::value ||
1412
+ std::is_pointer<T>::value ||
1413
+ std::is_integral<T>::value ||
1414
+ std::is_function<T>::value> {};
1415
+
1416
+ template<typename T>
1417
+ struct IsConvertibleToImmType
1418
+ : public std::integral_constant<bool, IsConstexprConstructibleAsImmType<T>::value ||
1419
+ std::is_floating_point<T>::value> {};
1420
+ //! \endcond
1421
+
1422
+ //! \name Construction & Destruction
1423
+ //! \{
1424
+
1425
+ //! Creates a new immediate value (initial value is 0).
1426
+ inline constexpr Imm() noexcept
1427
+ : Operand(Globals::Init, Signature::fromOpType(OperandType::kImm), 0, 0, 0) {}
1428
+
1429
+ //! Creates a new immediate value from `other`.
1430
+ inline constexpr Imm(const Imm& other) noexcept
1431
+ : Operand(other) {}
1432
+
1433
+ //! Creates a new immediate value from ARM/AArch64 specific `shift`.
1434
+ inline constexpr Imm(const arm::Shift& shift) noexcept
1435
+ : Operand(Globals::Init,
1436
+ Signature::fromOpType(OperandType::kImm) | Signature::fromPredicate(uint32_t(shift.op())),
1437
+ 0,
1438
+ Support::unpackU32At0(shift.value()),
1439
+ Support::unpackU32At1(shift.value())) {}
1440
+
1441
+ //! Creates a new signed immediate value, assigning the value to `val` and an architecture-specific predicate
1442
+ //! to `predicate`.
1443
+ //!
1444
+ //! \note Predicate is currently only used by ARM architectures.
1445
+ template<typename T, typename = typename std::enable_if<IsConstexprConstructibleAsImmType<typename std::decay<T>::type>::value>::type>
1446
+ inline constexpr Imm(const T& val, const uint32_t predicate = 0) noexcept
1447
+ : Operand(Globals::Init,
1448
+ Signature::fromOpType(OperandType::kImm) | Signature::fromPredicate(predicate),
1449
+ 0,
1450
+ Support::unpackU32At0(int64_t(val)),
1451
+ Support::unpackU32At1(int64_t(val))) {}
1452
+
1453
+ inline Imm(const float& val, const uint32_t predicate = 0) noexcept
1454
+ : Operand(Globals::Init,
1455
+ Signature::fromOpType(OperandType::kImm) | Signature::fromPredicate(predicate),
1456
+ 0,
1457
+ 0,
1458
+ 0) { setValue(val); }
1459
+
1460
+ inline Imm(const double& val, const uint32_t predicate = 0) noexcept
1461
+ : Operand(Globals::Init,
1462
+ Signature::fromOpType(OperandType::kImm) | Signature::fromPredicate(predicate),
1463
+ 0,
1464
+ 0,
1465
+ 0) { setValue(val); }
1466
+
1467
+ inline explicit Imm(Globals::NoInit_) noexcept
1468
+ : Operand(Globals::NoInit) {}
1469
+
1470
+ //! \}
1471
+
1472
+ //! \name Overloaded Operators
1473
+ //! \{
1474
+
1475
+ //! Assigns the value of the `other` operand to this immediate.
1476
+ inline Imm& operator=(const Imm& other) noexcept { copyFrom(other); return *this; }
1477
+
1478
+ //! \}
1479
+
1480
+ //! \name Accessors
1481
+ //! \{
1482
+
1483
+ //! Returns immediate type.
1484
+ inline constexpr ImmType type() const noexcept { return (ImmType)_signature.getField<Signature::kImmTypeMask>(); }
1485
+ //! Sets the immediate type to `type`.
1486
+ inline void setType(ImmType type) noexcept { _signature.setField<Signature::kImmTypeMask>(uint32_t(type)); }
1487
+ //! Resets immediate type to \ref ImmType::kInt.
1488
+ inline void resetType() noexcept { setType(ImmType::kInt); }
1489
+
1490
+ //! Returns operation predicate of the immediate.
1491
+ //!
1492
+ //! The meaning depends on architecture, for example on ARM hardware this describes \ref arm::ShiftOp
1493
+ //! of the immediate.
1494
+ inline constexpr uint32_t predicate() const noexcept { return _signature.getField<Signature::kPredicateMask>(); }
1495
+
1496
+ //! Sets operation predicate of the immediate to `predicate`.
1497
+ //!
1498
+ //! The meaning depends on architecture, for example on ARM hardware this describes \ref arm::ShiftOp
1499
+ //! of the immediate.
1500
+ inline void setPredicate(uint32_t predicate) noexcept { _signature.setField<Signature::kPredicateMask>(predicate); }
1501
+
1502
+ //! Resets the shift operation type of the immediate to the default value (no operation).
1503
+ inline void resetPredicate() noexcept { _signature.setField<Signature::kPredicateMask>(0); }
1504
+
1505
+ //! Returns the immediate value as `int64_t`, which is the internal format Imm uses.
1506
+ inline constexpr int64_t value() const noexcept {
1507
+ return int64_t((uint64_t(_data[kDataImmValueHi]) << 32) | _data[kDataImmValueLo]);
1508
+ }
1509
+
1510
+ //! Tests whether this immediate value is integer of any size.
1511
+ inline constexpr uint32_t isInt() const noexcept { return type() == ImmType::kInt; }
1512
+ //! Tests whether this immediate value is a double precision floating point value.
1513
+ inline constexpr uint32_t isDouble() const noexcept { return type() == ImmType::kDouble; }
1514
+
1515
+ //! Tests whether the immediate can be casted to 8-bit signed integer.
1516
+ inline constexpr bool isInt8() const noexcept { return type() == ImmType::kInt && Support::isInt8(value()); }
1517
+ //! Tests whether the immediate can be casted to 8-bit unsigned integer.
1518
+ inline constexpr bool isUInt8() const noexcept { return type() == ImmType::kInt && Support::isUInt8(value()); }
1519
+ //! Tests whether the immediate can be casted to 16-bit signed integer.
1520
+ inline constexpr bool isInt16() const noexcept { return type() == ImmType::kInt && Support::isInt16(value()); }
1521
+ //! Tests whether the immediate can be casted to 16-bit unsigned integer.
1522
+ inline constexpr bool isUInt16() const noexcept { return type() == ImmType::kInt && Support::isUInt16(value()); }
1523
+ //! Tests whether the immediate can be casted to 32-bit signed integer.
1524
+ inline constexpr bool isInt32() const noexcept { return type() == ImmType::kInt && Support::isInt32(value()); }
1525
+ //! Tests whether the immediate can be casted to 32-bit unsigned integer.
1526
+ inline constexpr bool isUInt32() const noexcept { return type() == ImmType::kInt && _data[kDataImmValueHi] == 0; }
1527
+
1528
+ //! Returns the immediate value casted to `T`.
1529
+ //!
1530
+ //! The value is masked before it's casted to `T` so the returned value is simply the representation of `T`
1531
+ //! considering the original value's lowest bits.
1532
+ template<typename T>
1533
+ inline T valueAs() const noexcept { return Support::immediateToT<T>(value()); }
1534
+
1535
+ //! Returns low 32-bit signed integer.
1536
+ inline constexpr int32_t int32Lo() const noexcept { return int32_t(_data[kDataImmValueLo]); }
1537
+ //! Returns high 32-bit signed integer.
1538
+ inline constexpr int32_t int32Hi() const noexcept { return int32_t(_data[kDataImmValueHi]); }
1539
+ //! Returns low 32-bit signed integer.
1540
+ inline constexpr uint32_t uint32Lo() const noexcept { return _data[kDataImmValueLo]; }
1541
+ //! Returns high 32-bit signed integer.
1542
+ inline constexpr uint32_t uint32Hi() const noexcept { return _data[kDataImmValueHi]; }
1543
+
1544
+ //! Sets immediate value to `val`, the value is casted to a signed 64-bit integer.
1545
+ template<typename T>
1546
+ inline void setValue(const T& val) noexcept {
1547
+ _setValueInternal(Support::immediateFromT(val), std::is_floating_point<T>::value ? ImmType::kDouble : ImmType::kInt);
1548
+ }
1549
+
1550
+ inline void _setValueInternal(int64_t val, ImmType type) noexcept {
1551
+ setType(type);
1552
+ _data[kDataImmValueHi] = uint32_t(uint64_t(val) >> 32);
1553
+ _data[kDataImmValueLo] = uint32_t(uint64_t(val) & 0xFFFFFFFFu);
1554
+ }
1555
+
1556
+ //! \}
1557
+
1558
+ //! \name Utilities
1559
+ //! \{
1560
+
1561
+ //! Clones the immediate operand.
1562
+ inline constexpr Imm clone() const noexcept { return Imm(*this); }
1563
+
1564
+ inline void signExtend8Bits() noexcept { setValue(int64_t(valueAs<int8_t>())); }
1565
+ inline void signExtend16Bits() noexcept { setValue(int64_t(valueAs<int16_t>())); }
1566
+ inline void signExtend32Bits() noexcept { setValue(int64_t(valueAs<int32_t>())); }
1567
+
1568
+ inline void zeroExtend8Bits() noexcept { setValue(valueAs<uint8_t>()); }
1569
+ inline void zeroExtend16Bits() noexcept { setValue(valueAs<uint16_t>()); }
1570
+ inline void zeroExtend32Bits() noexcept { _data[kDataImmValueHi] = 0u; }
1571
+
1572
+ //! \}
1573
+ };
1574
+
1575
+ //! Creates a new immediate operand.
1576
+ template<typename T>
1577
+ static inline constexpr Imm imm(const T& val) noexcept { return Imm(val); }
1578
+
1579
+ //! \}
1580
+
1581
+ namespace Globals {
1582
+ //! \ingroup asmjit_assembler
1583
+ //!
1584
+ //! A default-constructed operand of `Operand_::kOpNone` type.
1585
+ static constexpr const Operand none;
1586
+ }
1587
+
1588
+ //! \cond INTERNAL
1589
+ namespace Support {
1590
+
1591
+ template<typename T, bool kIsImm>
1592
+ struct ForwardOpImpl {
1593
+ static inline const T& forward(const T& value) noexcept { return value; }
1594
+ };
1595
+
1596
+ template<typename T>
1597
+ struct ForwardOpImpl<T, true> {
1598
+ static inline Imm forward(const T& value) noexcept { return Imm(value); }
1599
+ };
1600
+
1601
+ //! Either forwards operand T or returns a new operand that wraps it if T is a type convertible to operand.
1602
+ //! At the moment this is only used to convert integers, floats, and enumarations to \ref Imm operands.
1603
+ template<typename T>
1604
+ struct ForwardOp : public ForwardOpImpl<T, Imm::IsConvertibleToImmType<typename std::decay<T>::type>::value> {};
1605
+
1606
+ } // {Support}
1607
+ //! \endcond
1608
+
1609
+ ASMJIT_END_NAMESPACE
1610
+
1611
+ #endif // ASMJIT_CORE_OPERAND_H_INCLUDED