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,1732 @@
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
+ // ----------------------------------------------------------------------------
7
+ // IMPORTANT: AsmJit now uses an external instruction database to populate
8
+ // static tables within this file. Perform the following steps to regenerate
9
+ // all tables enclosed by ${...}:
10
+ //
11
+ // 1. Install node.js environment <https://nodejs.org>
12
+ // 2. Go to asmjit/tools directory
13
+ // 3. Get the latest asmdb from <https://github.com/asmjit/asmdb> and
14
+ // copy/link the `asmdb` directory to `asmjit/tools/asmdb`.
15
+ // 4. Execute `node tablegen-x86.js`
16
+ //
17
+ // Instruction encoding and opcodes were added to the `x86inst.cpp` database
18
+ // manually in the past and they are not updated by the script as it became
19
+ // tricky. However, everything else is updated including instruction operands
20
+ // and tables required to validate them, instruction read/write information
21
+ // (including registers and flags), and all indexes to all tables.
22
+ // ----------------------------------------------------------------------------
23
+
24
+ #include "../core/api-build_p.h"
25
+ #if !defined(ASMJIT_NO_X86)
26
+
27
+ #include "../core/cpuinfo.h"
28
+ #include "../core/misc_p.h"
29
+ #include "../core/support.h"
30
+ #include "../x86/x86instapi_p.h"
31
+ #include "../x86/x86instdb_p.h"
32
+ #include "../x86/x86opcode_p.h"
33
+ #include "../x86/x86operand.h"
34
+
35
+ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
36
+
37
+ // x86::InstInternal - Text
38
+ // ========================
39
+
40
+ #ifndef ASMJIT_NO_TEXT
41
+ Error InstInternal::instIdToString(Arch arch, InstId instId, String& output) noexcept {
42
+ DebugUtils::unused(arch);
43
+
44
+ if (ASMJIT_UNLIKELY(!Inst::isDefinedId(instId)))
45
+ return DebugUtils::errored(kErrorInvalidInstruction);
46
+
47
+ const InstDB::InstInfo& info = InstDB::infoById(instId);
48
+ return output.append(InstDB::_nameData + info._nameDataIndex);
49
+ }
50
+
51
+ InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexcept {
52
+ DebugUtils::unused(arch);
53
+
54
+ if (ASMJIT_UNLIKELY(!s))
55
+ return Inst::kIdNone;
56
+
57
+ if (len == SIZE_MAX)
58
+ len = strlen(s);
59
+
60
+ if (ASMJIT_UNLIKELY(len == 0 || len > InstDB::kMaxNameSize))
61
+ return Inst::kIdNone;
62
+
63
+ uint32_t prefix = uint32_t(s[0]) - 'a';
64
+ if (ASMJIT_UNLIKELY(prefix > 'z' - 'a'))
65
+ return Inst::kIdNone;
66
+
67
+ uint32_t index = InstDB::instNameIndex[prefix].start;
68
+ if (ASMJIT_UNLIKELY(!index))
69
+ return Inst::kIdNone;
70
+
71
+ const char* nameData = InstDB::_nameData;
72
+ const InstDB::InstInfo* table = InstDB::_instInfoTable;
73
+
74
+ const InstDB::InstInfo* base = table + index;
75
+ const InstDB::InstInfo* end = table + InstDB::instNameIndex[prefix].end;
76
+
77
+ for (size_t lim = (size_t)(end - base); lim != 0; lim >>= 1) {
78
+ const InstDB::InstInfo* cur = base + (lim >> 1);
79
+ int result = Support::cmpInstName(nameData + cur[0]._nameDataIndex, s, len);
80
+
81
+ if (result < 0) {
82
+ base = cur + 1;
83
+ lim--;
84
+ continue;
85
+ }
86
+
87
+ if (result > 0)
88
+ continue;
89
+
90
+ return InstId((size_t)(cur - table));
91
+ }
92
+
93
+ return Inst::kIdNone;
94
+ }
95
+ #endif // !ASMJIT_NO_TEXT
96
+
97
+ // x86::InstInternal - Validate
98
+ // ============================
99
+
100
+ #ifndef ASMJIT_NO_VALIDATION
101
+ struct X86ValidationData {
102
+ //! Allowed registers by \ref RegType.
103
+ RegMask allowedRegMask[uint32_t(RegType::kMaxValue) + 1];
104
+ uint32_t allowedMemBaseRegs;
105
+ uint32_t allowedMemIndexRegs;
106
+ };
107
+
108
+ #define VALUE(x) \
109
+ (x == uint32_t(RegType::kX86_GpbLo)) ? InstDB::OpFlags::kRegGpbLo : \
110
+ (x == uint32_t(RegType::kX86_GpbHi)) ? InstDB::OpFlags::kRegGpbHi : \
111
+ (x == uint32_t(RegType::kX86_Gpw )) ? InstDB::OpFlags::kRegGpw : \
112
+ (x == uint32_t(RegType::kX86_Gpd )) ? InstDB::OpFlags::kRegGpd : \
113
+ (x == uint32_t(RegType::kX86_Gpq )) ? InstDB::OpFlags::kRegGpq : \
114
+ (x == uint32_t(RegType::kX86_Xmm )) ? InstDB::OpFlags::kRegXmm : \
115
+ (x == uint32_t(RegType::kX86_Ymm )) ? InstDB::OpFlags::kRegYmm : \
116
+ (x == uint32_t(RegType::kX86_Zmm )) ? InstDB::OpFlags::kRegZmm : \
117
+ (x == uint32_t(RegType::kX86_Mm )) ? InstDB::OpFlags::kRegMm : \
118
+ (x == uint32_t(RegType::kX86_KReg )) ? InstDB::OpFlags::kRegKReg : \
119
+ (x == uint32_t(RegType::kX86_SReg )) ? InstDB::OpFlags::kRegSReg : \
120
+ (x == uint32_t(RegType::kX86_CReg )) ? InstDB::OpFlags::kRegCReg : \
121
+ (x == uint32_t(RegType::kX86_DReg )) ? InstDB::OpFlags::kRegDReg : \
122
+ (x == uint32_t(RegType::kX86_St )) ? InstDB::OpFlags::kRegSt : \
123
+ (x == uint32_t(RegType::kX86_Bnd )) ? InstDB::OpFlags::kRegBnd : \
124
+ (x == uint32_t(RegType::kX86_Tmm )) ? InstDB::OpFlags::kRegTmm : \
125
+ (x == uint32_t(RegType::kX86_Rip )) ? InstDB::OpFlags::kNone : InstDB::OpFlags::kNone
126
+ static const InstDB::OpFlags _x86OpFlagFromRegType[uint32_t(RegType::kMaxValue) + 1] = { ASMJIT_LOOKUP_TABLE_32(VALUE, 0) };
127
+ #undef VALUE
128
+
129
+ #define REG_MASK_FROM_REG_TYPE_X86(x) \
130
+ (x == uint32_t(RegType::kX86_GpbLo)) ? 0x0000000Fu : \
131
+ (x == uint32_t(RegType::kX86_GpbHi)) ? 0x0000000Fu : \
132
+ (x == uint32_t(RegType::kX86_Gpw )) ? 0x000000FFu : \
133
+ (x == uint32_t(RegType::kX86_Gpd )) ? 0x000000FFu : \
134
+ (x == uint32_t(RegType::kX86_Gpq )) ? 0x000000FFu : \
135
+ (x == uint32_t(RegType::kX86_Xmm )) ? 0x000000FFu : \
136
+ (x == uint32_t(RegType::kX86_Ymm )) ? 0x000000FFu : \
137
+ (x == uint32_t(RegType::kX86_Zmm )) ? 0x000000FFu : \
138
+ (x == uint32_t(RegType::kX86_Mm )) ? 0x000000FFu : \
139
+ (x == uint32_t(RegType::kX86_KReg )) ? 0x000000FFu : \
140
+ (x == uint32_t(RegType::kX86_SReg )) ? 0x0000007Eu : \
141
+ (x == uint32_t(RegType::kX86_CReg )) ? 0x0000FFFFu : \
142
+ (x == uint32_t(RegType::kX86_DReg )) ? 0x000000FFu : \
143
+ (x == uint32_t(RegType::kX86_St )) ? 0x000000FFu : \
144
+ (x == uint32_t(RegType::kX86_Bnd )) ? 0x0000000Fu : \
145
+ (x == uint32_t(RegType::kX86_Tmm )) ? 0x000000FFu : \
146
+ (x == uint32_t(RegType::kX86_Rip )) ? 0x00000001u : 0u
147
+
148
+ #define REG_MASK_FROM_REG_TYPE_X64(x) \
149
+ (x == uint32_t(RegType::kX86_GpbLo)) ? 0x0000FFFFu : \
150
+ (x == uint32_t(RegType::kX86_GpbHi)) ? 0x0000000Fu : \
151
+ (x == uint32_t(RegType::kX86_Gpw )) ? 0x0000FFFFu : \
152
+ (x == uint32_t(RegType::kX86_Gpd )) ? 0x0000FFFFu : \
153
+ (x == uint32_t(RegType::kX86_Gpq )) ? 0x0000FFFFu : \
154
+ (x == uint32_t(RegType::kX86_Xmm )) ? 0xFFFFFFFFu : \
155
+ (x == uint32_t(RegType::kX86_Ymm )) ? 0xFFFFFFFFu : \
156
+ (x == uint32_t(RegType::kX86_Zmm )) ? 0xFFFFFFFFu : \
157
+ (x == uint32_t(RegType::kX86_Mm )) ? 0x000000FFu : \
158
+ (x == uint32_t(RegType::kX86_KReg )) ? 0x000000FFu : \
159
+ (x == uint32_t(RegType::kX86_SReg )) ? 0x0000007Eu : \
160
+ (x == uint32_t(RegType::kX86_CReg )) ? 0x0000FFFFu : \
161
+ (x == uint32_t(RegType::kX86_DReg )) ? 0x0000FFFFu : \
162
+ (x == uint32_t(RegType::kX86_St )) ? 0x000000FFu : \
163
+ (x == uint32_t(RegType::kX86_Bnd )) ? 0x0000000Fu : \
164
+ (x == uint32_t(RegType::kX86_Tmm )) ? 0x000000FFu : \
165
+ (x == uint32_t(RegType::kX86_Rip )) ? 0x00000001u : 0u
166
+
167
+ #define B(RegType) (uint32_t(1) << uint32_t(RegType))
168
+
169
+ static const X86ValidationData _x86ValidationData = {
170
+ { ASMJIT_LOOKUP_TABLE_32(REG_MASK_FROM_REG_TYPE_X86, 0) },
171
+ B(RegType::kX86_Gpw) | B(RegType::kX86_Gpd) | B(RegType::kX86_Rip) | B(RegType::kLabelTag),
172
+ B(RegType::kX86_Gpw) | B(RegType::kX86_Gpd) | B(RegType::kX86_Xmm) | B(RegType::kX86_Ymm) | B(RegType::kX86_Zmm)
173
+ };
174
+
175
+ static const X86ValidationData _x64ValidationData = {
176
+ { ASMJIT_LOOKUP_TABLE_32(REG_MASK_FROM_REG_TYPE_X64, 0) },
177
+ B(RegType::kX86_Gpd) | B(RegType::kX86_Gpq) | B(RegType::kX86_Rip) | B(RegType::kLabelTag),
178
+ B(RegType::kX86_Gpd) | B(RegType::kX86_Gpq) | B(RegType::kX86_Xmm) | B(RegType::kX86_Ymm) | B(RegType::kX86_Zmm)
179
+ };
180
+
181
+ #undef B
182
+
183
+ #undef REG_MASK_FROM_REG_TYPE_X64
184
+ #undef REG_MASK_FROM_REG_TYPE_X86
185
+
186
+ static ASMJIT_FORCE_INLINE bool x86IsZmmOrM512(const Operand_& op) noexcept {
187
+ return Reg::isZmm(op) || (op.isMem() && op.size() == 64);
188
+ }
189
+
190
+ static ASMJIT_FORCE_INLINE bool x86CheckOSig(const InstDB::OpSignature& op, const InstDB::OpSignature& ref, bool& immOutOfRange) noexcept {
191
+ // Fail if operand types are incompatible.
192
+ InstDB::OpFlags commonFlags = op.flags() & ref.flags();
193
+
194
+ if (!Support::test(commonFlags, InstDB::OpFlags::kOpMask)) {
195
+ // Mark temporarily `immOutOfRange` so we can return a more descriptive error later.
196
+ if (op.hasImm() && ref.hasImm()) {
197
+ immOutOfRange = true;
198
+ return true;
199
+ }
200
+
201
+ return false;
202
+ }
203
+
204
+ // Fail if some memory specific flags do not match.
205
+ if (Support::test(commonFlags, InstDB::OpFlags::kMemMask)) {
206
+ if (ref.hasFlag(InstDB::OpFlags::kFlagMemBase) && !op.hasFlag(InstDB::OpFlags::kFlagMemBase))
207
+ return false;
208
+ }
209
+
210
+ // Fail if register indexes do not match.
211
+ if (Support::test(commonFlags, InstDB::OpFlags::kRegMask)) {
212
+ if (ref.regMask() && !Support::test(op.regMask(), ref.regMask()))
213
+ return false;
214
+ }
215
+
216
+ return true;
217
+ }
218
+
219
+ ASMJIT_FAVOR_SIZE Error InstInternal::validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
220
+ // Only called when `arch` matches X86 family.
221
+ ASMJIT_ASSERT(Environment::isFamilyX86(arch));
222
+
223
+ const X86ValidationData* vd;
224
+ if (arch == Arch::kX86)
225
+ vd = &_x86ValidationData;
226
+ else
227
+ vd = &_x64ValidationData;
228
+
229
+ uint32_t i;
230
+ InstDB::Mode mode = InstDB::modeFromArch(arch);
231
+
232
+ // Get the instruction data.
233
+ InstId instId = inst.id();
234
+ InstOptions options = inst.options();
235
+
236
+ if (ASMJIT_UNLIKELY(!Inst::isDefinedId(instId)))
237
+ return DebugUtils::errored(kErrorInvalidInstruction);
238
+
239
+ const InstDB::InstInfo& instInfo = InstDB::infoById(instId);
240
+ const InstDB::CommonInfo& commonInfo = instInfo.commonInfo();
241
+
242
+ InstDB::InstFlags iFlags = instInfo.flags();
243
+
244
+ constexpr InstOptions kRepAny = InstOptions::kX86_Rep | InstOptions::kX86_Repne;
245
+ constexpr InstOptions kXAcqXRel = InstOptions::kX86_XAcquire | InstOptions::kX86_XRelease;
246
+ constexpr InstOptions kAvx512Options = InstOptions::kX86_ZMask | InstOptions::kX86_ER | InstOptions::kX86_SAE;
247
+
248
+ // Validate LOCK|XACQUIRE|XRELEASE Prefixes
249
+ // ----------------------------------------
250
+
251
+ if (Support::test(options, InstOptions::kX86_Lock | kXAcqXRel)) {
252
+ if (Support::test(options, InstOptions::kX86_Lock)) {
253
+ if (ASMJIT_UNLIKELY(!Support::test(iFlags, InstDB::InstFlags::kLock) && !Support::test(options, kXAcqXRel)))
254
+ return DebugUtils::errored(kErrorInvalidLockPrefix);
255
+
256
+ if (ASMJIT_UNLIKELY(opCount < 1 || !operands[0].isMem()))
257
+ return DebugUtils::errored(kErrorInvalidLockPrefix);
258
+ }
259
+
260
+ if (Support::test(options, kXAcqXRel)) {
261
+ if (ASMJIT_UNLIKELY(!Support::test(options, InstOptions::kX86_Lock) || (options & kXAcqXRel) == kXAcqXRel))
262
+ return DebugUtils::errored(kErrorInvalidPrefixCombination);
263
+
264
+ if (ASMJIT_UNLIKELY(Support::test(options, InstOptions::kX86_XAcquire) && !Support::test(iFlags, InstDB::InstFlags::kXAcquire)))
265
+ return DebugUtils::errored(kErrorInvalidXAcquirePrefix);
266
+
267
+ if (ASMJIT_UNLIKELY(Support::test(options, InstOptions::kX86_XRelease) && !Support::test(iFlags, InstDB::InstFlags::kXRelease)))
268
+ return DebugUtils::errored(kErrorInvalidXReleasePrefix);
269
+ }
270
+ }
271
+
272
+ // Validate REP and REPNE Prefixes
273
+ // -------------------------------
274
+
275
+ if (Support::test(options, kRepAny)) {
276
+ if (ASMJIT_UNLIKELY((options & kRepAny) == kRepAny))
277
+ return DebugUtils::errored(kErrorInvalidPrefixCombination);
278
+
279
+ if (ASMJIT_UNLIKELY(!Support::test(iFlags, InstDB::InstFlags::kRep)))
280
+ return DebugUtils::errored(kErrorInvalidRepPrefix);
281
+ }
282
+
283
+ // Translate Each Operand to the Corresponding OpSignature
284
+ // -------------------------------------------------------
285
+
286
+ InstDB::OpSignature oSigTranslated[Globals::kMaxOpCount];
287
+ InstDB::OpFlags combinedOpFlags = InstDB::OpFlags::kNone;
288
+ uint32_t combinedRegMask = 0;
289
+ const Mem* memOp = nullptr;
290
+
291
+ for (i = 0; i < opCount; i++) {
292
+ const Operand_& op = operands[i];
293
+ if (op.opType() == OperandType::kNone)
294
+ break;
295
+
296
+ InstDB::OpFlags opFlags = InstDB::OpFlags::kNone;
297
+ RegMask regMask = 0;
298
+
299
+ switch (op.opType()) {
300
+ case OperandType::kReg: {
301
+ RegType regType = op.as<BaseReg>().type();
302
+ opFlags = _x86OpFlagFromRegType[size_t(regType)];
303
+
304
+ if (ASMJIT_UNLIKELY(opFlags == InstDB::OpFlags::kNone))
305
+ return DebugUtils::errored(kErrorInvalidRegType);
306
+
307
+ // If `regId` is equal or greater than Operand::kVirtIdMin it means that the register is virtual and its
308
+ // index will be assigned later by the register allocator. We must pass unless asked to disallow virtual
309
+ // registers.
310
+ uint32_t regId = op.id();
311
+ if (regId < Operand::kVirtIdMin) {
312
+ if (ASMJIT_UNLIKELY(regId >= 32))
313
+ return DebugUtils::errored(kErrorInvalidPhysId);
314
+
315
+ if (ASMJIT_UNLIKELY(Support::bitTest(vd->allowedRegMask[size_t(regType)], regId) == 0))
316
+ return DebugUtils::errored(kErrorInvalidPhysId);
317
+
318
+ regMask = Support::bitMask(regId);
319
+ combinedRegMask |= regMask;
320
+ }
321
+ else {
322
+ if (uint32_t(validationFlags & ValidationFlags::kEnableVirtRegs) == 0)
323
+ return DebugUtils::errored(kErrorIllegalVirtReg);
324
+ regMask = 0xFFFFFFFFu;
325
+ }
326
+ break;
327
+ }
328
+
329
+ // TODO: Validate base and index and combine these with `combinedRegMask`.
330
+ case OperandType::kMem: {
331
+ const Mem& m = op.as<Mem>();
332
+ memOp = &m;
333
+
334
+ uint32_t memSize = m.size();
335
+ RegType baseType = m.baseType();
336
+ RegType indexType = m.indexType();
337
+
338
+ if (m.segmentId() > 6)
339
+ return DebugUtils::errored(kErrorInvalidSegment);
340
+
341
+ // Validate AVX-512 broadcast {1tox}.
342
+ if (m.hasBroadcast()) {
343
+ if (memSize != 0) {
344
+ // If the size is specified it has to match the broadcast size.
345
+ if (ASMJIT_UNLIKELY(commonInfo.hasAvx512B32() && memSize != 4))
346
+ return DebugUtils::errored(kErrorInvalidBroadcast);
347
+
348
+ if (ASMJIT_UNLIKELY(commonInfo.hasAvx512B64() && memSize != 8))
349
+ return DebugUtils::errored(kErrorInvalidBroadcast);
350
+ }
351
+ else {
352
+ // If there is no size we implicitly calculate it so we can validate N in {1toN} properly.
353
+ memSize = commonInfo.hasAvx512B64() ? 8 :
354
+ commonInfo.hasAvx512B32() ? 4 : 2;
355
+ }
356
+
357
+ memSize <<= uint32_t(m.getBroadcast());
358
+ }
359
+
360
+ if (baseType != RegType::kNone && baseType > RegType::kLabelTag) {
361
+ uint32_t baseId = m.baseId();
362
+
363
+ if (m.isRegHome()) {
364
+ // Home address of a virtual register. In such case we don't want to validate the type of the
365
+ // base register as it will always be patched to ESP|RSP.
366
+ }
367
+ else {
368
+ if (ASMJIT_UNLIKELY(!Support::bitTest(vd->allowedMemBaseRegs, baseType)))
369
+ return DebugUtils::errored(kErrorInvalidAddress);
370
+ }
371
+
372
+ // Create information that will be validated only if this is an implicit memory operand. Basically
373
+ // only usable for string instructions and other instructions where memory operand is implicit and
374
+ // has 'seg:[reg]' form.
375
+ if (baseId < Operand::kVirtIdMin) {
376
+ if (ASMJIT_UNLIKELY(baseId >= 32))
377
+ return DebugUtils::errored(kErrorInvalidPhysId);
378
+
379
+ // Physical base id.
380
+ regMask = Support::bitMask(baseId);
381
+ combinedRegMask |= regMask;
382
+ }
383
+ else {
384
+ // Virtual base id - fill the whole mask for implicit mem validation. The register is not assigned
385
+ // yet, so we cannot predict the phys id.
386
+ if (uint32_t(validationFlags & ValidationFlags::kEnableVirtRegs) == 0)
387
+ return DebugUtils::errored(kErrorIllegalVirtReg);
388
+ regMask = 0xFFFFFFFFu;
389
+ }
390
+
391
+ if (indexType == RegType::kNone && !m.offsetLo32())
392
+ opFlags |= InstDB::OpFlags::kFlagMemBase;
393
+ }
394
+ else if (baseType == RegType::kLabelTag) {
395
+ // [Label] - there is no need to validate the base as it's label.
396
+ }
397
+ else {
398
+ // Base is a 64-bit address.
399
+ int64_t offset = m.offset();
400
+ if (!Support::isInt32(offset)) {
401
+ if (mode == InstDB::Mode::kX86) {
402
+ // 32-bit mode: Make sure that the address is either `int32_t` or `uint32_t`.
403
+ if (!Support::isUInt32(offset))
404
+ return DebugUtils::errored(kErrorInvalidAddress64Bit);
405
+ }
406
+ else {
407
+ // 64-bit mode: Zero extension is allowed if the address has 32-bit index register or the address
408
+ // has no index register (it's still encodable).
409
+ if (indexType != RegType::kNone) {
410
+ if (!Support::isUInt32(offset))
411
+ return DebugUtils::errored(kErrorInvalidAddress64Bit);
412
+
413
+ if (indexType != RegType::kX86_Gpd)
414
+ return DebugUtils::errored(kErrorInvalidAddress64BitZeroExtension);
415
+ }
416
+ else {
417
+ // We don't validate absolute 64-bit addresses without an index register as this also depends
418
+ // on the target's base address. We don't have the information to do it at this moment.
419
+ }
420
+ }
421
+ }
422
+ }
423
+
424
+ if (indexType != RegType::kNone) {
425
+ if (ASMJIT_UNLIKELY(!Support::bitTest(vd->allowedMemIndexRegs, indexType)))
426
+ return DebugUtils::errored(kErrorInvalidAddress);
427
+
428
+ if (indexType == RegType::kX86_Xmm) {
429
+ opFlags |= InstDB::OpFlags::kVm32x | InstDB::OpFlags::kVm64x;
430
+ }
431
+ else if (indexType == RegType::kX86_Ymm) {
432
+ opFlags |= InstDB::OpFlags::kVm32y | InstDB::OpFlags::kVm64y;
433
+ }
434
+ else if (indexType == RegType::kX86_Zmm) {
435
+ opFlags |= InstDB::OpFlags::kVm32z | InstDB::OpFlags::kVm64z;
436
+ }
437
+ else {
438
+ if (baseType != RegType::kNone)
439
+ opFlags |= InstDB::OpFlags::kFlagMib;
440
+ }
441
+
442
+ // [RIP + {XMM|YMM|ZMM}] is not allowed.
443
+ if (baseType == RegType::kX86_Rip && Support::test(opFlags, InstDB::OpFlags::kVmMask))
444
+ return DebugUtils::errored(kErrorInvalidAddress);
445
+
446
+ uint32_t indexId = m.indexId();
447
+ if (indexId < Operand::kVirtIdMin) {
448
+ if (ASMJIT_UNLIKELY(indexId >= 32))
449
+ return DebugUtils::errored(kErrorInvalidPhysId);
450
+
451
+ combinedRegMask |= Support::bitMask(indexId);
452
+ }
453
+ else {
454
+ if (uint32_t(validationFlags & ValidationFlags::kEnableVirtRegs) == 0)
455
+ return DebugUtils::errored(kErrorIllegalVirtReg);
456
+ }
457
+
458
+ // Only used for implicit memory operands having 'seg:[reg]' form, so clear it.
459
+ regMask = 0;
460
+ }
461
+
462
+ switch (memSize) {
463
+ case 0: opFlags |= InstDB::OpFlags::kMemUnspecified; break;
464
+ case 1: opFlags |= InstDB::OpFlags::kMem8; break;
465
+ case 2: opFlags |= InstDB::OpFlags::kMem16; break;
466
+ case 4: opFlags |= InstDB::OpFlags::kMem32; break;
467
+ case 6: opFlags |= InstDB::OpFlags::kMem48; break;
468
+ case 8: opFlags |= InstDB::OpFlags::kMem64; break;
469
+ case 10: opFlags |= InstDB::OpFlags::kMem80; break;
470
+ case 16: opFlags |= InstDB::OpFlags::kMem128; break;
471
+ case 32: opFlags |= InstDB::OpFlags::kMem256; break;
472
+ case 64: opFlags |= InstDB::OpFlags::kMem512; break;
473
+
474
+ default:
475
+ return DebugUtils::errored(kErrorInvalidOperandSize);
476
+ }
477
+
478
+ break;
479
+ }
480
+
481
+ case OperandType::kImm: {
482
+ uint64_t immValue = op.as<Imm>().valueAs<uint64_t>();
483
+
484
+ if (int64_t(immValue) >= 0) {
485
+ if (immValue <= 0x7u)
486
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmU64 | InstDB::OpFlags::kImmI32 | InstDB::OpFlags::kImmU32 |
487
+ InstDB::OpFlags::kImmI16 | InstDB::OpFlags::kImmU16 | InstDB::OpFlags::kImmI8 | InstDB::OpFlags::kImmU8 |
488
+ InstDB::OpFlags::kImmI4 | InstDB::OpFlags::kImmU4 ;
489
+ else if (immValue <= 0xFu)
490
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmU64 | InstDB::OpFlags::kImmI32 | InstDB::OpFlags::kImmU32 |
491
+ InstDB::OpFlags::kImmI16 | InstDB::OpFlags::kImmU16 | InstDB::OpFlags::kImmI8 | InstDB::OpFlags::kImmU8 |
492
+ InstDB::OpFlags::kImmU4 ;
493
+ else if (immValue <= 0x7Fu)
494
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmU64 | InstDB::OpFlags::kImmI32 | InstDB::OpFlags::kImmU32 |
495
+ InstDB::OpFlags::kImmI16 | InstDB::OpFlags::kImmU16 | InstDB::OpFlags::kImmI8 | InstDB::OpFlags::kImmU8 ;
496
+ else if (immValue <= 0xFFu)
497
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmU64 | InstDB::OpFlags::kImmI32 | InstDB::OpFlags::kImmU32 |
498
+ InstDB::OpFlags::kImmI16 | InstDB::OpFlags::kImmU16 | InstDB::OpFlags::kImmU8 ;
499
+ else if (immValue <= 0x7FFFu)
500
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmU64 | InstDB::OpFlags::kImmI32 | InstDB::OpFlags::kImmU32 |
501
+ InstDB::OpFlags::kImmI16 | InstDB::OpFlags::kImmU16 ;
502
+ else if (immValue <= 0xFFFFu)
503
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmU64 | InstDB::OpFlags::kImmI32 | InstDB::OpFlags::kImmU32 |
504
+ InstDB::OpFlags::kImmU16 ;
505
+ else if (immValue <= 0x7FFFFFFFu)
506
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmU64 | InstDB::OpFlags::kImmI32 | InstDB::OpFlags::kImmU32;
507
+ else if (immValue <= 0xFFFFFFFFu)
508
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmU64 | InstDB::OpFlags::kImmU32;
509
+ else if (immValue <= 0x7FFFFFFFFFFFFFFFu)
510
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmU64;
511
+ else
512
+ opFlags = InstDB::OpFlags::kImmU64;
513
+ }
514
+ else {
515
+ immValue = Support::neg(immValue);
516
+ if (immValue <= 0x8u)
517
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmI32 | InstDB::OpFlags::kImmI16 | InstDB::OpFlags::kImmI8 | InstDB::OpFlags::kImmI4;
518
+ else if (immValue <= 0x80u)
519
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmI32 | InstDB::OpFlags::kImmI16 | InstDB::OpFlags::kImmI8;
520
+ else if (immValue <= 0x8000u)
521
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmI32 | InstDB::OpFlags::kImmI16;
522
+ else if (immValue <= 0x80000000u)
523
+ opFlags = InstDB::OpFlags::kImmI64 | InstDB::OpFlags::kImmI32;
524
+ else
525
+ opFlags = InstDB::OpFlags::kImmI64;
526
+ }
527
+ break;
528
+ }
529
+
530
+ case OperandType::kLabel: {
531
+ opFlags |= InstDB::OpFlags::kRel8 | InstDB::OpFlags::kRel32;
532
+ break;
533
+ }
534
+
535
+ default:
536
+ return DebugUtils::errored(kErrorInvalidState);
537
+ }
538
+
539
+ InstDB::OpSignature& oSigDst = oSigTranslated[i];
540
+ oSigDst._flags = uint64_t(opFlags) & 0x00FFFFFFFFFFFFFFu;
541
+ oSigDst._regMask = uint8_t(regMask & 0xFFu);
542
+ combinedOpFlags |= opFlags;
543
+ }
544
+
545
+ // Decrease the number of operands of those that are none. This is important as Assembler and Compiler may just pass
546
+ // more operands padded with none (which means that no operand is given at that index). However, validate that there
547
+ // are no gaps (like [reg, none, reg] or [none, reg]).
548
+ if (i < opCount) {
549
+ while (--opCount > i)
550
+ if (ASMJIT_UNLIKELY(!operands[opCount].isNone()))
551
+ return DebugUtils::errored(kErrorInvalidInstruction);
552
+ }
553
+
554
+ // Validate X86 and X64 specific cases.
555
+ if (mode == InstDB::Mode::kX86) {
556
+ // Illegal use of 64-bit register in 32-bit mode.
557
+ if (ASMJIT_UNLIKELY(Support::test(combinedOpFlags, InstDB::OpFlags::kRegGpq)))
558
+ return DebugUtils::errored(kErrorInvalidUseOfGpq);
559
+ }
560
+ else {
561
+ // Illegal use of a high 8-bit register with REX prefix.
562
+ bool hasREX = inst.hasOption(InstOptions::kX86_Rex) || (combinedRegMask & 0xFFFFFF00u) != 0;
563
+ if (ASMJIT_UNLIKELY(hasREX && Support::test(combinedOpFlags, InstDB::OpFlags::kRegGpbHi)))
564
+ return DebugUtils::errored(kErrorInvalidUseOfGpbHi);
565
+ }
566
+
567
+ // Validate Instruction Signature by Comparing Against All `iSig` Rows
568
+ // -------------------------------------------------------------------
569
+
570
+ const InstDB::InstSignature* iSig = InstDB::_instSignatureTable + commonInfo._iSignatureIndex;
571
+ const InstDB::InstSignature* iEnd = iSig + commonInfo._iSignatureCount;
572
+
573
+ if (iSig != iEnd) {
574
+ const InstDB::OpSignature* opSignatureTable = InstDB::_opSignatureTable;
575
+
576
+ // If set it means that we matched a signature where only immediate value
577
+ // was out of bounds. We can return a more descriptive error if we know this.
578
+ bool globalImmOutOfRange = false;
579
+
580
+ do {
581
+ // Check if the architecture is compatible.
582
+ if (!iSig->supportsMode(mode))
583
+ continue;
584
+
585
+ // Compare the operands table with reference operands.
586
+ uint32_t j = 0;
587
+ uint32_t iSigCount = iSig->opCount();
588
+ bool localImmOutOfRange = false;
589
+
590
+ if (iSigCount == opCount) {
591
+ for (j = 0; j < opCount; j++)
592
+ if (!x86CheckOSig(oSigTranslated[j], iSig->opSignature(j), localImmOutOfRange))
593
+ break;
594
+ }
595
+ else if (iSigCount - iSig->implicitOpCount() == opCount) {
596
+ uint32_t r = 0;
597
+ for (j = 0; j < opCount && r < iSigCount; j++, r++) {
598
+ const InstDB::OpSignature* oChk = oSigTranslated + j;
599
+ const InstDB::OpSignature* oRef;
600
+ Next:
601
+ oRef = opSignatureTable + iSig->opSignatureIndex(r);
602
+ // Skip implicit operands.
603
+ if (oRef->isImplicit()) {
604
+ if (++r >= iSigCount)
605
+ break;
606
+ else
607
+ goto Next;
608
+ }
609
+
610
+ if (!x86CheckOSig(*oChk, *oRef, localImmOutOfRange))
611
+ break;
612
+ }
613
+ }
614
+
615
+ if (j == opCount) {
616
+ if (!localImmOutOfRange) {
617
+ // Match, must clear possible `globalImmOutOfRange`.
618
+ globalImmOutOfRange = false;
619
+ break;
620
+ }
621
+ globalImmOutOfRange = localImmOutOfRange;
622
+ }
623
+ } while (++iSig != iEnd);
624
+
625
+ if (iSig == iEnd) {
626
+ if (globalImmOutOfRange)
627
+ return DebugUtils::errored(kErrorInvalidImmediate);
628
+ else
629
+ return DebugUtils::errored(kErrorInvalidInstruction);
630
+ }
631
+ }
632
+
633
+ // Validate AVX512 Options
634
+ // -----------------------
635
+
636
+ const RegOnly& extraReg = inst.extraReg();
637
+
638
+ if (Support::test(options, kAvx512Options)) {
639
+ if (commonInfo.hasFlag(InstDB::InstFlags::kEvex)) {
640
+ // Validate AVX-512 {z}.
641
+ if (Support::test(options, InstOptions::kX86_ZMask)) {
642
+ if (ASMJIT_UNLIKELY(Support::test(options, InstOptions::kX86_ZMask) && !commonInfo.hasAvx512Z()))
643
+ return DebugUtils::errored(kErrorInvalidKZeroUse);
644
+ }
645
+
646
+ // Validate AVX-512 {sae} and {er}.
647
+ if (Support::test(options, InstOptions::kX86_SAE | InstOptions::kX86_ER)) {
648
+ // Rounding control is impossible if the instruction is not reg-to-reg.
649
+ if (ASMJIT_UNLIKELY(memOp))
650
+ return DebugUtils::errored(kErrorInvalidEROrSAE);
651
+
652
+ // Check if {sae} or {er} is supported by the instruction.
653
+ if (Support::test(options, InstOptions::kX86_ER)) {
654
+ // NOTE: if both {sae} and {er} are set, we don't care, as {sae} is implied.
655
+ if (ASMJIT_UNLIKELY(!commonInfo.hasAvx512ER()))
656
+ return DebugUtils::errored(kErrorInvalidEROrSAE);
657
+ }
658
+ else {
659
+ if (ASMJIT_UNLIKELY(!commonInfo.hasAvx512SAE()))
660
+ return DebugUtils::errored(kErrorInvalidEROrSAE);
661
+ }
662
+
663
+ // {sae} and {er} are defined for either scalar ops or vector ops that require LL to be 10 (512-bit vector
664
+ // operations). We don't need any more bits in the instruction database to be able to validate this, as
665
+ // each AVX512 instruction that has broadcast is vector instruction (in this case we require zmm registers),
666
+ // otherwise it's a scalar instruction, which is valid.
667
+ if (commonInfo.hasAvx512B()) {
668
+ // Supports broadcast, thus we require LL to be '10', which means there have to be ZMM registers used. We
669
+ // don't calculate LL here, but we know that it would be '10' if there is at least one ZMM register used.
670
+
671
+ // There is no {er}/{sae}-enabled instruction with less than two operands.
672
+ ASMJIT_ASSERT(opCount >= 2);
673
+ if (ASMJIT_UNLIKELY(!x86IsZmmOrM512(operands[0]) && !x86IsZmmOrM512(operands[1])))
674
+ return DebugUtils::errored(kErrorInvalidEROrSAE);
675
+ }
676
+ }
677
+ }
678
+ else {
679
+ // Not an AVX512 instruction - maybe OpExtra is xCX register used by REP/REPNE prefix.
680
+ if (Support::test(options, kAvx512Options) || !Support::test(options, kRepAny))
681
+ return DebugUtils::errored(kErrorInvalidInstruction);
682
+ }
683
+ }
684
+
685
+ // Validate {Extra} Register
686
+ // -------------------------
687
+
688
+ if (extraReg.isReg()) {
689
+ if (Support::test(options, kRepAny)) {
690
+ // Validate REP|REPNE {cx|ecx|rcx}.
691
+ if (ASMJIT_UNLIKELY(Support::test(iFlags, InstDB::InstFlags::kRepIgnored)))
692
+ return DebugUtils::errored(kErrorInvalidExtraReg);
693
+
694
+ if (extraReg.isPhysReg()) {
695
+ if (ASMJIT_UNLIKELY(extraReg.id() != Gp::kIdCx))
696
+ return DebugUtils::errored(kErrorInvalidExtraReg);
697
+ }
698
+
699
+ // The type of the {...} register must match the type of the base register
700
+ // of memory operand. So if the memory operand uses 32-bit register the
701
+ // count register must also be 32-bit, etc...
702
+ if (ASMJIT_UNLIKELY(!memOp || extraReg.type() != memOp->baseType()))
703
+ return DebugUtils::errored(kErrorInvalidExtraReg);
704
+ }
705
+ else if (commonInfo.hasFlag(InstDB::InstFlags::kEvex)) {
706
+ // Validate AVX-512 {k}.
707
+ if (ASMJIT_UNLIKELY(extraReg.type() != RegType::kX86_KReg))
708
+ return DebugUtils::errored(kErrorInvalidExtraReg);
709
+
710
+ if (ASMJIT_UNLIKELY(extraReg.id() == 0 || !commonInfo.hasAvx512K()))
711
+ return DebugUtils::errored(kErrorInvalidKMaskUse);
712
+ }
713
+ else {
714
+ return DebugUtils::errored(kErrorInvalidExtraReg);
715
+ }
716
+ }
717
+
718
+ return kErrorOk;
719
+ }
720
+ #endif // !ASMJIT_NO_VALIDATION
721
+
722
+ // x86::InstInternal - QueryRWInfo
723
+ // ===============================
724
+
725
+ #ifndef ASMJIT_NO_INTROSPECTION
726
+ static const Support::Array<uint64_t, uint32_t(RegGroup::kMaxValue) + 1> rwRegGroupByteMask = {{
727
+ 0x00000000000000FFu, // GP.
728
+ 0xFFFFFFFFFFFFFFFFu, // XMM|YMM|ZMM.
729
+ 0x00000000000000FFu, // MM.
730
+ 0x00000000000000FFu, // KReg.
731
+ 0x0000000000000003u, // SReg.
732
+ 0x00000000000000FFu, // CReg.
733
+ 0x00000000000000FFu, // DReg.
734
+ 0x00000000000003FFu, // St().
735
+ 0x000000000000FFFFu, // BND.
736
+ 0x00000000000000FFu // RIP.
737
+ }};
738
+
739
+ static ASMJIT_FORCE_INLINE void rwZeroExtendGp(OpRWInfo& opRwInfo, const Gp& reg, uint32_t nativeGpSize) noexcept {
740
+ ASMJIT_ASSERT(BaseReg::isGp(reg.as<Operand>()));
741
+ if (reg.size() + 4 == nativeGpSize) {
742
+ opRwInfo.addOpFlags(OpRWFlags::kZExt);
743
+ opRwInfo.setExtendByteMask(~opRwInfo.writeByteMask() & 0xFFu);
744
+ }
745
+ }
746
+
747
+ static ASMJIT_FORCE_INLINE void rwZeroExtendAvxVec(OpRWInfo& opRwInfo, const Vec& reg) noexcept {
748
+ DebugUtils::unused(reg);
749
+
750
+ uint64_t msk = ~Support::fillTrailingBits(opRwInfo.writeByteMask());
751
+ if (msk) {
752
+ opRwInfo.addOpFlags(OpRWFlags::kZExt);
753
+ opRwInfo.setExtendByteMask(msk);
754
+ }
755
+ }
756
+
757
+ static ASMJIT_FORCE_INLINE void rwZeroExtendNonVec(OpRWInfo& opRwInfo, const Reg& reg) noexcept {
758
+ uint64_t msk = ~Support::fillTrailingBits(opRwInfo.writeByteMask()) & rwRegGroupByteMask[reg.group()];
759
+ if (msk) {
760
+ opRwInfo.addOpFlags(OpRWFlags::kZExt);
761
+ opRwInfo.setExtendByteMask(msk);
762
+ }
763
+ }
764
+
765
+ static ASMJIT_FORCE_INLINE Error rwHandleAVX512(const BaseInst& inst, const InstDB::CommonInfo& commonInfo, InstRWInfo* out) noexcept {
766
+ if (inst.hasExtraReg() && inst.extraReg().type() == RegType::kX86_KReg && out->opCount() > 0) {
767
+ // AVX-512 instruction that uses a destination with {k} register (zeroing vs masking).
768
+ out->_extraReg.addOpFlags(OpRWFlags::kRead);
769
+ out->_extraReg.setReadByteMask(0xFF);
770
+ if (!inst.hasOption(InstOptions::kX86_ZMask) && !commonInfo.hasAvx512Flag(InstDB::Avx512Flags::kImplicitZ)) {
771
+ out->_operands[0].addOpFlags(OpRWFlags::kRead);
772
+ out->_operands[0]._readByteMask |= out->_operands[0]._writeByteMask;
773
+ }
774
+ }
775
+
776
+ return kErrorOk;
777
+ }
778
+
779
+ static ASMJIT_FORCE_INLINE bool hasSameRegType(const BaseReg* regs, size_t opCount) noexcept {
780
+ ASMJIT_ASSERT(opCount > 0);
781
+ RegType regType = regs[0].type();
782
+ for (size_t i = 1; i < opCount; i++)
783
+ if (regs[i].type() != regType)
784
+ return false;
785
+ return true;
786
+ }
787
+
788
+ Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
789
+ // Only called when `arch` matches X86 family.
790
+ ASMJIT_ASSERT(Environment::isFamilyX86(arch));
791
+
792
+ // Get the instruction data.
793
+ InstId instId = inst.id();
794
+ if (ASMJIT_UNLIKELY(!Inst::isDefinedId(instId)))
795
+ return DebugUtils::errored(kErrorInvalidInstruction);
796
+
797
+ // Read/Write flags.
798
+ const InstDB::InstInfo& instInfo = InstDB::_instInfoTable[instId];
799
+ const InstDB::CommonInfo& commonInfo = InstDB::_commonInfoTable[instInfo._commonInfoIndex];
800
+ const InstDB::AdditionalInfo& additionalInfo = InstDB::_additionalInfoTable[instInfo._additionalInfoIndex];
801
+ const InstDB::RWFlagsInfoTable& rwFlags = InstDB::_rwFlagsInfoTable[additionalInfo._rwFlagsIndex];
802
+
803
+ // There are two data tables, one for `opCount == 2` and the second for
804
+ // `opCount != 2`. There are two reasons for that:
805
+ // - There are instructions that share the same name that have both 2 or 3 operands, which have different
806
+ // RW information / semantics.
807
+ // - There must be 2 tables otherwise the lookup index won't fit into 8 bits (there is more than 256 records
808
+ // of combined rwInfo A and B).
809
+ const InstDB::RWInfo& instRwInfo = opCount == 2 ? InstDB::rwInfoA[InstDB::rwInfoIndexA[instId]]
810
+ : InstDB::rwInfoB[InstDB::rwInfoIndexB[instId]];
811
+ const InstDB::RWInfoRm& instRmInfo = InstDB::rwInfoRm[instRwInfo.rmInfo];
812
+
813
+ out->_instFlags = InstDB::_instFlagsTable[additionalInfo._instFlagsIndex];
814
+ out->_opCount = uint8_t(opCount);
815
+ out->_rmFeature = instRmInfo.rmFeature;
816
+ out->_extraReg.reset();
817
+ out->_readFlags = CpuRWFlags(rwFlags.readFlags);
818
+ out->_writeFlags = CpuRWFlags(rwFlags.writeFlags);
819
+
820
+ uint32_t opTypeMask = 0u;
821
+ uint32_t nativeGpSize = Environment::registerSizeFromArch(arch);
822
+
823
+ constexpr OpRWFlags R = OpRWFlags::kRead;
824
+ constexpr OpRWFlags W = OpRWFlags::kWrite;
825
+ constexpr OpRWFlags X = OpRWFlags::kRW;
826
+ constexpr OpRWFlags RegM = OpRWFlags::kRegMem;
827
+ constexpr OpRWFlags RegPhys = OpRWFlags::kRegPhysId;
828
+ constexpr OpRWFlags MibRead = OpRWFlags::kMemBaseRead | OpRWFlags::kMemIndexRead;
829
+
830
+ if (instRwInfo.category == InstDB::RWInfo::kCategoryGeneric) {
831
+ uint32_t i;
832
+ uint32_t rmOpsMask = 0;
833
+ uint32_t rmMaxSize = 0;
834
+
835
+ for (i = 0; i < opCount; i++) {
836
+ OpRWInfo& op = out->_operands[i];
837
+ const Operand_& srcOp = operands[i];
838
+ const InstDB::RWInfoOp& rwOpData = InstDB::rwInfoOp[instRwInfo.opInfoIndex[i]];
839
+
840
+ opTypeMask |= Support::bitMask(srcOp.opType());
841
+
842
+ if (!srcOp.isRegOrMem()) {
843
+ op.reset();
844
+ continue;
845
+ }
846
+
847
+ op._opFlags = rwOpData.flags & ~OpRWFlags::kZExt;
848
+ op._physId = rwOpData.physId;
849
+ op._rmSize = 0;
850
+ op._resetReserved();
851
+
852
+ uint64_t rByteMask = rwOpData.rByteMask;
853
+ uint64_t wByteMask = rwOpData.wByteMask;
854
+
855
+ if (op.isRead() && !rByteMask) rByteMask = Support::lsbMask<uint64_t>(srcOp.size());
856
+ if (op.isWrite() && !wByteMask) wByteMask = Support::lsbMask<uint64_t>(srcOp.size());
857
+
858
+ op._readByteMask = rByteMask;
859
+ op._writeByteMask = wByteMask;
860
+ op._extendByteMask = 0;
861
+ op._consecutiveLeadCount = rwOpData.consecutiveLeadCount;
862
+
863
+ if (srcOp.isReg()) {
864
+ // Zero extension.
865
+ if (op.isWrite()) {
866
+ if (srcOp.as<Reg>().isGp()) {
867
+ // GP registers on X64 are special:
868
+ // - 8-bit and 16-bit writes aren't zero extended.
869
+ // - 32-bit writes ARE zero extended.
870
+ rwZeroExtendGp(op, srcOp.as<Gp>(), nativeGpSize);
871
+ }
872
+ else if (Support::test(rwOpData.flags, OpRWFlags::kZExt)) {
873
+ // Otherwise follow ZExt.
874
+ rwZeroExtendNonVec(op, srcOp.as<Gp>());
875
+ }
876
+ }
877
+
878
+ // Aggregate values required to calculate valid Reg/M info.
879
+ rmMaxSize = Support::max(rmMaxSize, srcOp.size());
880
+ rmOpsMask |= Support::bitMask<uint32_t>(i);
881
+ }
882
+ else {
883
+ const x86::Mem& memOp = srcOp.as<x86::Mem>();
884
+ // The RW flags of BASE+INDEX are either provided by the data, which means
885
+ // that the instruction is border-case, or they are deduced from the operand.
886
+ if (memOp.hasBaseReg() && !op.hasOpFlag(OpRWFlags::kMemBaseRW))
887
+ op.addOpFlags(OpRWFlags::kMemBaseRead);
888
+ if (memOp.hasIndexReg() && !op.hasOpFlag(OpRWFlags::kMemIndexRW))
889
+ op.addOpFlags(OpRWFlags::kMemIndexRead);
890
+ }
891
+ }
892
+
893
+ // Only keep kMovOp if the instruction is actually register to register move of the same kind.
894
+ if (out->hasInstFlag(InstRWFlags::kMovOp)) {
895
+ if (!(opCount >= 2 && opTypeMask == Support::bitMask(OperandType::kReg) && hasSameRegType(reinterpret_cast<const BaseReg*>(operands), opCount)))
896
+ out->_instFlags &= ~InstRWFlags::kMovOp;
897
+ }
898
+
899
+ // Special cases require more logic.
900
+ if (instRmInfo.flags & (InstDB::RWInfoRm::kFlagMovssMovsd | InstDB::RWInfoRm::kFlagPextrw | InstDB::RWInfoRm::kFlagFeatureIfRMI)) {
901
+ if (instRmInfo.flags & InstDB::RWInfoRm::kFlagMovssMovsd) {
902
+ if (opCount == 2) {
903
+ if (operands[0].isReg() && operands[1].isReg()) {
904
+ // Doesn't zero extend the destination.
905
+ out->_operands[0]._extendByteMask = 0;
906
+ }
907
+ }
908
+ }
909
+ else if (instRmInfo.flags & InstDB::RWInfoRm::kFlagPextrw) {
910
+ if (opCount == 3 && Reg::isMm(operands[1])) {
911
+ out->_rmFeature = 0;
912
+ rmOpsMask = 0;
913
+ }
914
+ }
915
+ else if (instRmInfo.flags & InstDB::RWInfoRm::kFlagFeatureIfRMI) {
916
+ if (opCount != 3 || !operands[2].isImm()) {
917
+ out->_rmFeature = 0;
918
+ }
919
+ }
920
+ }
921
+
922
+ rmOpsMask &= instRmInfo.rmOpsMask;
923
+ if (rmOpsMask) {
924
+ Support::BitWordIterator<uint32_t> it(rmOpsMask);
925
+ do {
926
+ i = it.next();
927
+
928
+ OpRWInfo& op = out->_operands[i];
929
+ op.addOpFlags(RegM);
930
+
931
+ switch (instRmInfo.category) {
932
+ case InstDB::RWInfoRm::kCategoryFixed:
933
+ op.setRmSize(instRmInfo.fixedSize);
934
+ break;
935
+ case InstDB::RWInfoRm::kCategoryConsistent:
936
+ op.setRmSize(operands[i].size());
937
+ break;
938
+ case InstDB::RWInfoRm::kCategoryHalf:
939
+ op.setRmSize(rmMaxSize / 2u);
940
+ break;
941
+ case InstDB::RWInfoRm::kCategoryQuarter:
942
+ op.setRmSize(rmMaxSize / 4u);
943
+ break;
944
+ case InstDB::RWInfoRm::kCategoryEighth:
945
+ op.setRmSize(rmMaxSize / 8u);
946
+ break;
947
+ }
948
+ } while (it.hasNext());
949
+ }
950
+
951
+ return rwHandleAVX512(inst, commonInfo, out);
952
+ }
953
+
954
+ switch (instRwInfo.category) {
955
+ case InstDB::RWInfo::kCategoryMov: {
956
+ // Special case for 'mov' instruction. Here there are some variants that we have to handle as 'mov' can be
957
+ // used to move between GP, segment, control and debug registers. Moving between GP registers also allow to
958
+ // use memory operand.
959
+
960
+ // We will again set the flag if it's actually a move from GP to GP register, otherwise this flag cannot be set.
961
+ out->_instFlags &= ~InstRWFlags::kMovOp;
962
+
963
+ if (opCount == 2) {
964
+ if (operands[0].isReg() && operands[1].isReg()) {
965
+ const Reg& o0 = operands[0].as<Reg>();
966
+ const Reg& o1 = operands[1].as<Reg>();
967
+
968
+ if (o0.isGp() && o1.isGp()) {
969
+ out->_operands[0].reset(W | RegM, operands[0].size());
970
+ out->_operands[1].reset(R | RegM, operands[1].size());
971
+
972
+ rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize);
973
+ out->_instFlags |= InstRWFlags::kMovOp;
974
+ return kErrorOk;
975
+ }
976
+
977
+ if (o0.isGp() && o1.isSReg()) {
978
+ out->_operands[0].reset(W | RegM, nativeGpSize);
979
+ out->_operands[0].setRmSize(2);
980
+ out->_operands[1].reset(R, 2);
981
+ return kErrorOk;
982
+ }
983
+
984
+ if (o0.isSReg() && o1.isGp()) {
985
+ out->_operands[0].reset(W, 2);
986
+ out->_operands[1].reset(R | RegM, 2);
987
+ out->_operands[1].setRmSize(2);
988
+ return kErrorOk;
989
+ }
990
+
991
+ if (o0.isGp() && (o1.isCReg() || o1.isDReg())) {
992
+ out->_operands[0].reset(W, nativeGpSize);
993
+ out->_operands[1].reset(R, nativeGpSize);
994
+ out->_writeFlags = CpuRWFlags::kX86_OF |
995
+ CpuRWFlags::kX86_SF |
996
+ CpuRWFlags::kX86_ZF |
997
+ CpuRWFlags::kX86_AF |
998
+ CpuRWFlags::kX86_PF |
999
+ CpuRWFlags::kX86_CF;
1000
+ return kErrorOk;
1001
+ }
1002
+
1003
+ if ((o0.isCReg() || o0.isDReg()) && o1.isGp()) {
1004
+ out->_operands[0].reset(W, nativeGpSize);
1005
+ out->_operands[1].reset(R, nativeGpSize);
1006
+ out->_writeFlags = CpuRWFlags::kX86_OF |
1007
+ CpuRWFlags::kX86_SF |
1008
+ CpuRWFlags::kX86_ZF |
1009
+ CpuRWFlags::kX86_AF |
1010
+ CpuRWFlags::kX86_PF |
1011
+ CpuRWFlags::kX86_CF;
1012
+ return kErrorOk;
1013
+ }
1014
+ }
1015
+
1016
+ if (operands[0].isReg() && operands[1].isMem()) {
1017
+ const Reg& o0 = operands[0].as<Reg>();
1018
+ const Mem& o1 = operands[1].as<Mem>();
1019
+
1020
+ if (o0.isGp()) {
1021
+ if (!o1.isOffset64Bit())
1022
+ out->_operands[0].reset(W, o0.size());
1023
+ else
1024
+ out->_operands[0].reset(W | RegPhys, o0.size(), Gp::kIdAx);
1025
+
1026
+ out->_operands[1].reset(R | MibRead, o0.size());
1027
+ rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize);
1028
+ return kErrorOk;
1029
+ }
1030
+
1031
+ if (o0.isSReg()) {
1032
+ out->_operands[0].reset(W, 2);
1033
+ out->_operands[1].reset(R, 2);
1034
+ return kErrorOk;
1035
+ }
1036
+ }
1037
+
1038
+ if (operands[0].isMem() && operands[1].isReg()) {
1039
+ const Mem& o0 = operands[0].as<Mem>();
1040
+ const Reg& o1 = operands[1].as<Reg>();
1041
+
1042
+ if (o1.isGp()) {
1043
+ out->_operands[0].reset(W | MibRead, o1.size());
1044
+ if (!o0.isOffset64Bit())
1045
+ out->_operands[1].reset(R, o1.size());
1046
+ else
1047
+ out->_operands[1].reset(R | RegPhys, o1.size(), Gp::kIdAx);
1048
+ return kErrorOk;
1049
+ }
1050
+
1051
+ if (o1.isSReg()) {
1052
+ out->_operands[0].reset(W | MibRead, 2);
1053
+ out->_operands[1].reset(R, 2);
1054
+ return kErrorOk;
1055
+ }
1056
+ }
1057
+
1058
+ if (Reg::isGp(operands[0]) && operands[1].isImm()) {
1059
+ const Reg& o0 = operands[0].as<Reg>();
1060
+ out->_operands[0].reset(W | RegM, o0.size());
1061
+ out->_operands[1].reset();
1062
+
1063
+ rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize);
1064
+ return kErrorOk;
1065
+ }
1066
+
1067
+ if (operands[0].isMem() && operands[1].isImm()) {
1068
+ const Reg& o0 = operands[0].as<Reg>();
1069
+ out->_operands[0].reset(W | MibRead, o0.size());
1070
+ out->_operands[1].reset();
1071
+ return kErrorOk;
1072
+ }
1073
+ }
1074
+ break;
1075
+ }
1076
+
1077
+ case InstDB::RWInfo::kCategoryMovabs: {
1078
+ if (opCount == 2) {
1079
+ if (Reg::isGp(operands[0]) && operands[1].isMem()) {
1080
+ const Reg& o0 = operands[0].as<Reg>();
1081
+ out->_operands[0].reset(W | RegPhys, o0.size(), Gp::kIdAx);
1082
+ out->_operands[1].reset(R | MibRead, o0.size());
1083
+ rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize);
1084
+ return kErrorOk;
1085
+ }
1086
+
1087
+ if (operands[0].isMem() && Reg::isGp(operands[1])) {
1088
+ const Reg& o1 = operands[1].as<Reg>();
1089
+ out->_operands[0].reset(W | MibRead, o1.size());
1090
+ out->_operands[1].reset(R | RegPhys, o1.size(), Gp::kIdAx);
1091
+ return kErrorOk;
1092
+ }
1093
+
1094
+ if (Reg::isGp(operands[0]) && operands[1].isImm()) {
1095
+ const Reg& o0 = operands[0].as<Reg>();
1096
+ out->_operands[0].reset(W, o0.size());
1097
+ out->_operands[1].reset();
1098
+
1099
+ rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize);
1100
+ return kErrorOk;
1101
+ }
1102
+ }
1103
+ break;
1104
+ }
1105
+
1106
+ case InstDB::RWInfo::kCategoryImul: {
1107
+ // Special case for 'imul' instruction.
1108
+ //
1109
+ // There are 3 variants in general:
1110
+ //
1111
+ // 1. Standard multiplication: 'A = A * B'.
1112
+ // 2. Multiplication with imm: 'A = B * C'.
1113
+ // 3. Extended multiplication: 'A:B = B * C'.
1114
+
1115
+ if (opCount == 2) {
1116
+ if (operands[0].isReg() && operands[1].isImm()) {
1117
+ out->_operands[0].reset(X, operands[0].size());
1118
+ out->_operands[1].reset();
1119
+
1120
+ rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize);
1121
+ return kErrorOk;
1122
+ }
1123
+
1124
+ if (Reg::isGpw(operands[0]) && operands[1].size() == 1) {
1125
+ // imul ax, r8/m8 <- AX = AL * r8/m8
1126
+ out->_operands[0].reset(X | RegPhys, 2, Gp::kIdAx);
1127
+ out->_operands[0].setReadByteMask(Support::lsbMask<uint64_t>(1));
1128
+ out->_operands[1].reset(R | RegM, 1);
1129
+ }
1130
+ else {
1131
+ // imul r?, r?/m?
1132
+ out->_operands[0].reset(X, operands[0].size());
1133
+ out->_operands[1].reset(R | RegM, operands[0].size());
1134
+ rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize);
1135
+ }
1136
+
1137
+ if (operands[1].isMem())
1138
+ out->_operands[1].addOpFlags(MibRead);
1139
+ return kErrorOk;
1140
+ }
1141
+
1142
+ if (opCount == 3) {
1143
+ if (operands[2].isImm()) {
1144
+ out->_operands[0].reset(W, operands[0].size());
1145
+ out->_operands[1].reset(R | RegM, operands[1].size());
1146
+ out->_operands[2].reset();
1147
+
1148
+ rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize);
1149
+ if (operands[1].isMem())
1150
+ out->_operands[1].addOpFlags(MibRead);
1151
+ return kErrorOk;
1152
+ }
1153
+ else {
1154
+ out->_operands[0].reset(W | RegPhys, operands[0].size(), Gp::kIdDx);
1155
+ out->_operands[1].reset(X | RegPhys, operands[1].size(), Gp::kIdAx);
1156
+ out->_operands[2].reset(R | RegM, operands[2].size());
1157
+
1158
+ rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize);
1159
+ rwZeroExtendGp(out->_operands[1], operands[1].as<Gp>(), nativeGpSize);
1160
+ if (operands[2].isMem())
1161
+ out->_operands[2].addOpFlags(MibRead);
1162
+ return kErrorOk;
1163
+ }
1164
+ }
1165
+ break;
1166
+ }
1167
+
1168
+ case InstDB::RWInfo::kCategoryMovh64: {
1169
+ // Special case for 'movhpd|movhps' instructions. Note that this is only required for legacy (non-AVX)
1170
+ // variants as AVX instructions use either 2 or 3 operands that are in `kCategoryGeneric` category.
1171
+ if (opCount == 2) {
1172
+ if (BaseReg::isVec(operands[0]) && operands[1].isMem()) {
1173
+ out->_operands[0].reset(W, 8);
1174
+ out->_operands[0].setWriteByteMask(Support::lsbMask<uint64_t>(8) << 8);
1175
+ out->_operands[1].reset(R | MibRead, 8);
1176
+ return kErrorOk;
1177
+ }
1178
+
1179
+ if (operands[0].isMem() && BaseReg::isVec(operands[1])) {
1180
+ out->_operands[0].reset(W | MibRead, 8);
1181
+ out->_operands[1].reset(R, 8);
1182
+ out->_operands[1].setReadByteMask(Support::lsbMask<uint64_t>(8) << 8);
1183
+ return kErrorOk;
1184
+ }
1185
+ }
1186
+ break;
1187
+ }
1188
+
1189
+ case InstDB::RWInfo::kCategoryPunpcklxx: {
1190
+ // Special case for 'punpcklbw|punpckldq|punpcklwd' instructions.
1191
+ if (opCount == 2) {
1192
+ if (Reg::isXmm(operands[0])) {
1193
+ out->_operands[0].reset(X, 16);
1194
+ out->_operands[0].setReadByteMask(0x0F0Fu);
1195
+ out->_operands[0].setWriteByteMask(0xFFFFu);
1196
+ out->_operands[1].reset(R, 16);
1197
+ out->_operands[1].setWriteByteMask(0x0F0Fu);
1198
+
1199
+ if (Reg::isXmm(operands[1])) {
1200
+ return kErrorOk;
1201
+ }
1202
+
1203
+ if (operands[1].isMem()) {
1204
+ out->_operands[1].addOpFlags(MibRead);
1205
+ return kErrorOk;
1206
+ }
1207
+ }
1208
+
1209
+ if (Reg::isMm(operands[0])) {
1210
+ out->_operands[0].reset(X, 8);
1211
+ out->_operands[0].setReadByteMask(0x0Fu);
1212
+ out->_operands[0].setWriteByteMask(0xFFu);
1213
+ out->_operands[1].reset(R, 4);
1214
+ out->_operands[1].setReadByteMask(0x0Fu);
1215
+
1216
+ if (Reg::isMm(operands[1])) {
1217
+ return kErrorOk;
1218
+ }
1219
+
1220
+ if (operands[1].isMem()) {
1221
+ out->_operands[1].addOpFlags(MibRead);
1222
+ return kErrorOk;
1223
+ }
1224
+ }
1225
+ }
1226
+ break;
1227
+ }
1228
+
1229
+ case InstDB::RWInfo::kCategoryVmaskmov: {
1230
+ // Special case for 'vmaskmovpd|vmaskmovps|vpmaskmovd|vpmaskmovq' instructions.
1231
+ if (opCount == 3) {
1232
+ if (BaseReg::isVec(operands[0]) && BaseReg::isVec(operands[1]) && operands[2].isMem()) {
1233
+ out->_operands[0].reset(W, operands[0].size());
1234
+ out->_operands[1].reset(R, operands[1].size());
1235
+ out->_operands[2].reset(R | MibRead, operands[1].size());
1236
+
1237
+ rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
1238
+ return kErrorOk;
1239
+ }
1240
+
1241
+ if (operands[0].isMem() && BaseReg::isVec(operands[1]) && BaseReg::isVec(operands[2])) {
1242
+ out->_operands[0].reset(X | MibRead, operands[1].size());
1243
+ out->_operands[1].reset(R, operands[1].size());
1244
+ out->_operands[2].reset(R, operands[2].size());
1245
+ return kErrorOk;
1246
+ }
1247
+ }
1248
+ break;
1249
+ }
1250
+
1251
+ case InstDB::RWInfo::kCategoryVmovddup: {
1252
+ // Special case for 'vmovddup' instruction. This instruction has an interesting semantic as 128-bit XMM
1253
+ // version only uses 64-bit memory operand (m64), however, 256/512-bit versions use 256/512-bit memory
1254
+ // operand, respectively.
1255
+ if (opCount == 2) {
1256
+ if (BaseReg::isVec(operands[0]) && BaseReg::isVec(operands[1])) {
1257
+ uint32_t o0Size = operands[0].size();
1258
+ uint32_t o1Size = o0Size == 16 ? 8 : o0Size;
1259
+
1260
+ out->_operands[0].reset(W, o0Size);
1261
+ out->_operands[1].reset(R | RegM, o1Size);
1262
+ out->_operands[1]._readByteMask &= 0x00FF00FF00FF00FFu;
1263
+
1264
+ rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
1265
+ return rwHandleAVX512(inst, commonInfo, out);
1266
+ }
1267
+
1268
+ if (BaseReg::isVec(operands[0]) && operands[1].isMem()) {
1269
+ uint32_t o0Size = operands[0].size();
1270
+ uint32_t o1Size = o0Size == 16 ? 8 : o0Size;
1271
+
1272
+ out->_operands[0].reset(W, o0Size);
1273
+ out->_operands[1].reset(R | MibRead, o1Size);
1274
+
1275
+ rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
1276
+ return rwHandleAVX512(inst, commonInfo, out);
1277
+ }
1278
+ }
1279
+ break;
1280
+ }
1281
+
1282
+ case InstDB::RWInfo::kCategoryVmovmskpd:
1283
+ case InstDB::RWInfo::kCategoryVmovmskps: {
1284
+ // Special case for 'vmovmskpd|vmovmskps' instructions.
1285
+ if (opCount == 2) {
1286
+ if (BaseReg::isGp(operands[0]) && BaseReg::isVec(operands[1])) {
1287
+ out->_operands[0].reset(W, 1);
1288
+ out->_operands[0].setExtendByteMask(Support::lsbMask<uint32_t>(nativeGpSize - 1) << 1);
1289
+ out->_operands[1].reset(R, operands[1].size());
1290
+ return kErrorOk;
1291
+ }
1292
+ }
1293
+ break;
1294
+ }
1295
+
1296
+ case InstDB::RWInfo::kCategoryVmov1_2:
1297
+ case InstDB::RWInfo::kCategoryVmov1_4:
1298
+ case InstDB::RWInfo::kCategoryVmov1_8: {
1299
+ // Special case for instructions where the destination is 1:N (narrowing).
1300
+ //
1301
+ // Vmov1_2:
1302
+ // vcvtpd2dq|vcvttpd2dq
1303
+ // vcvtpd2udq|vcvttpd2udq
1304
+ // vcvtpd2ps|vcvtps2ph
1305
+ // vcvtqq2ps|vcvtuqq2ps
1306
+ // vpmovwb|vpmovswb|vpmovuswb
1307
+ // vpmovdw|vpmovsdw|vpmovusdw
1308
+ // vpmovqd|vpmovsqd|vpmovusqd
1309
+ //
1310
+ // Vmov1_4:
1311
+ // vpmovdb|vpmovsdb|vpmovusdb
1312
+ // vpmovqw|vpmovsqw|vpmovusqw
1313
+ //
1314
+ // Vmov1_8:
1315
+ // pmovmskb|vpmovmskb
1316
+ // vpmovqb|vpmovsqb|vpmovusqb
1317
+ uint32_t shift = instRwInfo.category - InstDB::RWInfo::kCategoryVmov1_2 + 1;
1318
+
1319
+ if (opCount >= 2) {
1320
+ if (opCount >= 3) {
1321
+ if (opCount > 3)
1322
+ return DebugUtils::errored(kErrorInvalidInstruction);
1323
+ out->_operands[2].reset();
1324
+ }
1325
+
1326
+ if (operands[0].isReg() && operands[1].isReg()) {
1327
+ uint32_t size1 = operands[1].size();
1328
+ uint32_t size0 = size1 >> shift;
1329
+
1330
+ out->_operands[0].reset(W, size0);
1331
+ out->_operands[1].reset(R, size1);
1332
+
1333
+ if (instRmInfo.rmOpsMask & 0x1) {
1334
+ out->_operands[0].addOpFlags(RegM);
1335
+ out->_operands[0].setRmSize(size0);
1336
+ }
1337
+
1338
+ if (instRmInfo.rmOpsMask & 0x2) {
1339
+ out->_operands[1].addOpFlags(RegM);
1340
+ out->_operands[1].setRmSize(size1);
1341
+ }
1342
+
1343
+ // Handle 'pmovmskb|vpmovmskb'.
1344
+ if (BaseReg::isGp(operands[0]))
1345
+ rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize);
1346
+
1347
+ if (BaseReg::isVec(operands[0]))
1348
+ rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
1349
+
1350
+ return rwHandleAVX512(inst, commonInfo, out);
1351
+ }
1352
+
1353
+ if (operands[0].isReg() && operands[1].isMem()) {
1354
+ uint32_t size1 = operands[1].size() ? operands[1].size() : uint32_t(16);
1355
+ uint32_t size0 = size1 >> shift;
1356
+
1357
+ out->_operands[0].reset(W, size0);
1358
+ out->_operands[1].reset(R | MibRead, size1);
1359
+ return kErrorOk;
1360
+ }
1361
+
1362
+ if (operands[0].isMem() && operands[1].isReg()) {
1363
+ uint32_t size1 = operands[1].size();
1364
+ uint32_t size0 = size1 >> shift;
1365
+
1366
+ out->_operands[0].reset(W | MibRead, size0);
1367
+ out->_operands[1].reset(R, size1);
1368
+
1369
+ return rwHandleAVX512(inst, commonInfo, out);
1370
+ }
1371
+ }
1372
+ break;
1373
+ }
1374
+
1375
+ case InstDB::RWInfo::kCategoryVmov2_1:
1376
+ case InstDB::RWInfo::kCategoryVmov4_1:
1377
+ case InstDB::RWInfo::kCategoryVmov8_1: {
1378
+ // Special case for instructions where the destination is N:1 (widening).
1379
+ //
1380
+ // Vmov2_1:
1381
+ // vcvtdq2pd|vcvtudq2pd
1382
+ // vcvtps2pd|vcvtph2ps
1383
+ // vcvtps2qq|vcvtps2uqq
1384
+ // vcvttps2qq|vcvttps2uqq
1385
+ // vpmovsxbw|vpmovzxbw
1386
+ // vpmovsxwd|vpmovzxwd
1387
+ // vpmovsxdq|vpmovzxdq
1388
+ //
1389
+ // Vmov4_1:
1390
+ // vpmovsxbd|vpmovzxbd
1391
+ // vpmovsxwq|vpmovzxwq
1392
+ //
1393
+ // Vmov8_1:
1394
+ // vpmovsxbq|vpmovzxbq
1395
+ uint32_t shift = instRwInfo.category - InstDB::RWInfo::kCategoryVmov2_1 + 1;
1396
+
1397
+ if (opCount >= 2) {
1398
+ if (opCount >= 3) {
1399
+ if (opCount > 3)
1400
+ return DebugUtils::errored(kErrorInvalidInstruction);
1401
+ out->_operands[2].reset();
1402
+ }
1403
+
1404
+ uint32_t size0 = operands[0].size();
1405
+ uint32_t size1 = size0 >> shift;
1406
+
1407
+ out->_operands[0].reset(W, size0);
1408
+ out->_operands[1].reset(R, size1);
1409
+
1410
+ if (operands[0].isReg() && operands[1].isReg()) {
1411
+ if (instRmInfo.rmOpsMask & 0x1) {
1412
+ out->_operands[0].addOpFlags(RegM);
1413
+ out->_operands[0].setRmSize(size0);
1414
+ }
1415
+
1416
+ if (instRmInfo.rmOpsMask & 0x2) {
1417
+ out->_operands[1].addOpFlags(RegM);
1418
+ out->_operands[1].setRmSize(size1);
1419
+ }
1420
+
1421
+ return rwHandleAVX512(inst, commonInfo, out);
1422
+ }
1423
+
1424
+ if (operands[0].isReg() && operands[1].isMem()) {
1425
+ out->_operands[1].addOpFlags(MibRead);
1426
+
1427
+ return rwHandleAVX512(inst, commonInfo, out);
1428
+ }
1429
+ }
1430
+ break;
1431
+ }
1432
+ }
1433
+
1434
+ return DebugUtils::errored(kErrorInvalidInstruction);
1435
+ }
1436
+ #endif // !ASMJIT_NO_INTROSPECTION
1437
+
1438
+ // x86::InstInternal - QueryFeatures
1439
+ // =================================
1440
+
1441
+ #ifndef ASMJIT_NO_INTROSPECTION
1442
+ struct RegAnalysis {
1443
+ uint32_t regTypeMask;
1444
+ uint32_t highVecUsed;
1445
+
1446
+ inline bool hasRegType(RegType regType) const noexcept {
1447
+ return Support::bitTest(regTypeMask, regType);
1448
+ }
1449
+ };
1450
+
1451
+ static RegAnalysis InstInternal_regAnalysis(const Operand_* operands, size_t opCount) noexcept {
1452
+ uint32_t mask = 0;
1453
+ uint32_t highVecUsed = 0;
1454
+
1455
+ for (uint32_t i = 0; i < opCount; i++) {
1456
+ const Operand_& op = operands[i];
1457
+ if (op.isReg()) {
1458
+ const BaseReg& reg = op.as<BaseReg>();
1459
+ mask |= Support::bitMask(reg.type());
1460
+ if (reg.isVec())
1461
+ highVecUsed |= uint32_t(reg.id() >= 16 && reg.id() < 32);
1462
+ }
1463
+ else if (op.isMem()) {
1464
+ const BaseMem& mem = op.as<BaseMem>();
1465
+ if (mem.hasBaseReg()) mask |= Support::bitMask(mem.baseType());
1466
+ if (mem.hasIndexReg()) {
1467
+ mask |= Support::bitMask(mem.indexType());
1468
+ highVecUsed |= uint32_t(mem.indexId() >= 16 && mem.indexId() < 32);
1469
+ }
1470
+ }
1471
+ }
1472
+
1473
+ return RegAnalysis { mask, highVecUsed };
1474
+ }
1475
+
1476
+ static inline uint32_t InstInternal_usesAvx512(InstOptions instOptions, const RegOnly& extraReg, const RegAnalysis& regAnalysis) noexcept {
1477
+ uint32_t hasEvex = uint32_t(instOptions & (InstOptions::kX86_Evex | InstOptions::kX86_AVX512Mask));
1478
+ uint32_t hasKMask = extraReg.type() == RegType::kX86_KReg;
1479
+ uint32_t hasKOrZmm = regAnalysis.regTypeMask & Support::bitMask(RegType::kX86_Zmm, RegType::kX86_KReg);
1480
+
1481
+ return hasEvex | hasKMask | hasKOrZmm;
1482
+ }
1483
+
1484
+ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept {
1485
+ // Only called when `arch` matches X86 family.
1486
+ DebugUtils::unused(arch);
1487
+ ASMJIT_ASSERT(Environment::isFamilyX86(arch));
1488
+
1489
+ // Get the instruction data.
1490
+ InstId instId = inst.id();
1491
+ InstOptions options = inst.options();
1492
+
1493
+ if (ASMJIT_UNLIKELY(!Inst::isDefinedId(instId)))
1494
+ return DebugUtils::errored(kErrorInvalidInstruction);
1495
+
1496
+ const InstDB::InstInfo& instInfo = InstDB::infoById(instId);
1497
+ const InstDB::AdditionalInfo& additionalInfo = InstDB::_additionalInfoTable[instInfo._additionalInfoIndex];
1498
+
1499
+ const uint8_t* fData = additionalInfo.featuresBegin();
1500
+ const uint8_t* fEnd = additionalInfo.featuresEnd();
1501
+
1502
+ // Copy all features to `out`.
1503
+ out->reset();
1504
+ do {
1505
+ uint32_t feature = fData[0];
1506
+ if (!feature)
1507
+ break;
1508
+ out->add(feature);
1509
+ } while (++fData != fEnd);
1510
+
1511
+ // Since AsmJit aggregates instructions that share the same name we have to
1512
+ // deal with some special cases and also with MMX/SSE and AVX/AVX2 overlaps.
1513
+ if (fData != additionalInfo.featuresBegin()) {
1514
+ RegAnalysis regAnalysis = InstInternal_regAnalysis(operands, opCount);
1515
+
1516
+ // Handle MMX vs SSE overlap.
1517
+ if (out->has(CpuFeatures::X86::kMMX) || out->has(CpuFeatures::X86::kMMX2)) {
1518
+ // Only instructions defined by SSE and SSE2 overlap. Instructions introduced by newer instruction sets like
1519
+ // SSE3+ don't state MMX as they require SSE3+.
1520
+ if (out->has(CpuFeatures::X86::kSSE) || out->has(CpuFeatures::X86::kSSE2)) {
1521
+ if (!regAnalysis.hasRegType(RegType::kX86_Xmm)) {
1522
+ // The instruction doesn't use XMM register(s), thus it's MMX/MMX2 only.
1523
+ out->remove(CpuFeatures::X86::kSSE);
1524
+ out->remove(CpuFeatures::X86::kSSE2);
1525
+ out->remove(CpuFeatures::X86::kSSE4_1);
1526
+ }
1527
+ else {
1528
+ out->remove(CpuFeatures::X86::kMMX);
1529
+ out->remove(CpuFeatures::X86::kMMX2);
1530
+ }
1531
+
1532
+ // Special case: PEXTRW instruction is MMX/SSE2 instruction. However, MMX/SSE version cannot access memory
1533
+ // (only register to register extract) so when SSE4.1 introduced the whole family of PEXTR/PINSR instructions
1534
+ // they also introduced PEXTRW with a new opcode 0x15 that can extract directly to memory. This instruction
1535
+ // is, of course, not compatible with MMX/SSE2 and would #UD if SSE4.1 is not supported.
1536
+ if (instId == Inst::kIdPextrw) {
1537
+ if (opCount >= 1 && operands[0].isMem())
1538
+ out->remove(CpuFeatures::X86::kSSE2);
1539
+ else
1540
+ out->remove(CpuFeatures::X86::kSSE4_1);
1541
+ }
1542
+ }
1543
+ }
1544
+
1545
+ // Handle PCLMULQDQ vs VPCLMULQDQ.
1546
+ if (out->has(CpuFeatures::X86::kVPCLMULQDQ)) {
1547
+ if (regAnalysis.hasRegType(RegType::kX86_Zmm) || Support::test(options, InstOptions::kX86_Evex)) {
1548
+ // AVX512_F & VPCLMULQDQ.
1549
+ out->remove(CpuFeatures::X86::kAVX, CpuFeatures::X86::kPCLMULQDQ);
1550
+ }
1551
+ else if (regAnalysis.hasRegType(RegType::kX86_Ymm)) {
1552
+ out->remove(CpuFeatures::X86::kAVX512_F, CpuFeatures::X86::kAVX512_VL);
1553
+ }
1554
+ else {
1555
+ // AVX & PCLMULQDQ.
1556
+ out->remove(CpuFeatures::X86::kAVX512_F, CpuFeatures::X86::kAVX512_VL, CpuFeatures::X86::kVPCLMULQDQ);
1557
+ }
1558
+ }
1559
+
1560
+ // Handle AVX vs AVX2 overlap.
1561
+ if (out->has(CpuFeatures::X86::kAVX) && out->has(CpuFeatures::X86::kAVX2)) {
1562
+ bool isAVX2 = true;
1563
+ // Special case: VBROADCASTSS and VBROADCASTSD were introduced in AVX, but only version that uses memory as a
1564
+ // source operand. AVX2 then added support for register source operand.
1565
+ if (instId == Inst::kIdVbroadcastss || instId == Inst::kIdVbroadcastsd) {
1566
+ if (opCount > 1 && operands[1].isMem())
1567
+ isAVX2 = false;
1568
+ }
1569
+ else {
1570
+ // AVX instruction set doesn't support integer operations on YMM registers as these were later introcuced by
1571
+ // AVX2. In our case we have to check if YMM register(s) are in use and if that is the case this is an AVX2
1572
+ // instruction.
1573
+ if (!(regAnalysis.regTypeMask & Support::bitMask(RegType::kX86_Ymm, RegType::kX86_Zmm)))
1574
+ isAVX2 = false;
1575
+ }
1576
+
1577
+ if (isAVX2)
1578
+ out->remove(CpuFeatures::X86::kAVX);
1579
+ else
1580
+ out->remove(CpuFeatures::X86::kAVX2);
1581
+ }
1582
+
1583
+ // Handle AVX|AVX2|FMA|F16C vs AVX512 overlap.
1584
+ if (out->has(CpuFeatures::X86::kAVX) || out->has(CpuFeatures::X86::kAVX2) || out->has(CpuFeatures::X86::kFMA) || out->has(CpuFeatures::X86::kF16C)) {
1585
+ // Only AVX512-F|BW|DQ allow to encode AVX/AVX2/FMA/F16C instructions
1586
+ if (out->has(CpuFeatures::X86::kAVX512_F) || out->has(CpuFeatures::X86::kAVX512_BW) || out->has(CpuFeatures::X86::kAVX512_DQ)) {
1587
+ uint32_t usesAvx512 = InstInternal_usesAvx512(options, inst.extraReg(), regAnalysis);
1588
+ uint32_t mustUseEvex = 0;
1589
+
1590
+ switch (instId) {
1591
+ // Special case: VPSLLDQ and VPSRLDQ instructions only allow `reg, reg. imm` combination in AVX|AVX2 mode,
1592
+ // then AVX-512 introduced `reg, reg/mem, imm` combination that uses EVEX prefix. This means that if the
1593
+ // second operand is memory then this is AVX-512_BW instruction and not AVX/AVX2 instruction.
1594
+ case Inst::kIdVpslldq:
1595
+ case Inst::kIdVpsrldq:
1596
+ mustUseEvex = opCount >= 2 && operands[1].isMem();
1597
+ break;
1598
+
1599
+ // Special case: VPBROADCAST[B|D|Q|W] only supports r32/r64 with EVEX prefix.
1600
+ case Inst::kIdVpbroadcastb:
1601
+ case Inst::kIdVpbroadcastd:
1602
+ case Inst::kIdVpbroadcastq:
1603
+ case Inst::kIdVpbroadcastw:
1604
+ mustUseEvex = opCount >= 2 && x86::Reg::isGp(operands[1]);
1605
+ break;
1606
+
1607
+ // Special case: VPERMPD - AVX2 vs AVX512-F case.
1608
+ case Inst::kIdVpermpd:
1609
+ mustUseEvex = opCount >= 3 && !operands[2].isImm();
1610
+ break;
1611
+
1612
+ // Special case: VPERMQ - AVX2 vs AVX512-F case.
1613
+ case Inst::kIdVpermq:
1614
+ mustUseEvex = opCount >= 3 && (operands[1].isMem() || !operands[2].isImm());
1615
+ break;
1616
+ }
1617
+
1618
+ if (!(usesAvx512 | mustUseEvex | regAnalysis.highVecUsed))
1619
+ out->remove(CpuFeatures::X86::kAVX512_F, CpuFeatures::X86::kAVX512_BW, CpuFeatures::X86::kAVX512_DQ, CpuFeatures::X86::kAVX512_VL);
1620
+ else
1621
+ out->remove(CpuFeatures::X86::kAVX, CpuFeatures::X86::kAVX2, CpuFeatures::X86::kFMA, CpuFeatures::X86::kF16C);
1622
+ }
1623
+ }
1624
+
1625
+ // Handle AVX_VNNI vs AVX512_VNNI overlap.
1626
+ if (out->has(CpuFeatures::X86::kAVX512_VNNI)) {
1627
+ // By default the AVX512_VNNI instruction should be used, because it was introduced first. However, VEX|VEX3
1628
+ // prefix can be used to force AVX_VNNI instead.
1629
+ uint32_t usesAvx512 = InstInternal_usesAvx512(options, inst.extraReg(), regAnalysis);
1630
+
1631
+ if (!usesAvx512 && Support::test(options, InstOptions::kX86_Vex | InstOptions::kX86_Vex3))
1632
+ out->remove(CpuFeatures::X86::kAVX512_VNNI, CpuFeatures::X86::kAVX512_VL);
1633
+ else
1634
+ out->remove(CpuFeatures::X86::kAVX_VNNI);
1635
+ }
1636
+
1637
+ // Clear AVX512_VL if ZMM register is used.
1638
+ if (regAnalysis.hasRegType(RegType::kX86_Zmm))
1639
+ out->remove(CpuFeatures::X86::kAVX512_VL);
1640
+ }
1641
+
1642
+ return kErrorOk;
1643
+ }
1644
+ #endif // !ASMJIT_NO_INTROSPECTION
1645
+
1646
+ // x86::InstInternal - Tests
1647
+ // =========================
1648
+
1649
+ #if defined(ASMJIT_TEST)
1650
+ UNIT(x86_inst_api_text) {
1651
+ // All known instructions should be matched.
1652
+ INFO("Matching all X86 instructions");
1653
+ for (uint32_t a = 1; a < Inst::_kIdCount; a++) {
1654
+ StringTmp<128> aName;
1655
+ EXPECT(InstInternal::instIdToString(Arch::kX86, a, aName) == kErrorOk,
1656
+ "Failed to get the name of instruction #%u", a);
1657
+
1658
+ uint32_t b = InstInternal::stringToInstId(Arch::kX86, aName.data(), aName.size());
1659
+ StringTmp<128> bName;
1660
+ InstInternal::instIdToString(Arch::kX86, b, bName);
1661
+
1662
+ EXPECT(a == b,
1663
+ "Instructions do not match \"%s\" (#%u) != \"%s\" (#%u)", aName.data(), a, bName.data(), b);
1664
+ }
1665
+ }
1666
+
1667
+ template<typename... Args>
1668
+ static Error queryRWInfoSimple(InstRWInfo* out, Arch arch, InstId instId, InstOptions options, Args&&... args) {
1669
+ BaseInst inst(instId);
1670
+ inst.addOptions(options);
1671
+ Operand_ opArray[] = { std::forward<Args>(args)... };
1672
+ return InstInternal::queryRWInfo(arch, inst, opArray, sizeof...(args), out);
1673
+ }
1674
+
1675
+ UNIT(x86_inst_api_rm_feature) {
1676
+ INFO("Verifying whether RM/feature is reported correctly for PEXTRW instruction");
1677
+ {
1678
+ InstRWInfo rwi;
1679
+
1680
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdPextrw, InstOptions::kNone, eax, mm1, imm(1));
1681
+ EXPECT(rwi.rmFeature() == 0);
1682
+
1683
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdPextrw, InstOptions::kNone, eax, xmm1, imm(1));
1684
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kSSE4_1);
1685
+ }
1686
+
1687
+ INFO("Verifying whether RM/feature is reported correctly for AVX512 shift instructions");
1688
+ {
1689
+ InstRWInfo rwi;
1690
+
1691
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpslld, InstOptions::kNone, xmm1, xmm2, imm(8));
1692
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_F);
1693
+
1694
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsllq, InstOptions::kNone, ymm1, ymm2, imm(8));
1695
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_F);
1696
+
1697
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsrad, InstOptions::kNone, xmm1, xmm2, imm(8));
1698
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_F);
1699
+
1700
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsrld, InstOptions::kNone, ymm1, ymm2, imm(8));
1701
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_F);
1702
+
1703
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsrlq, InstOptions::kNone, xmm1, xmm2, imm(8));
1704
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_F);
1705
+
1706
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpslldq, InstOptions::kNone, xmm1, xmm2, imm(8));
1707
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_BW);
1708
+
1709
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsllw, InstOptions::kNone, ymm1, ymm2, imm(8));
1710
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_BW);
1711
+
1712
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsraw, InstOptions::kNone, xmm1, xmm2, imm(8));
1713
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_BW);
1714
+
1715
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsrldq, InstOptions::kNone, ymm1, ymm2, imm(8));
1716
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_BW);
1717
+
1718
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsrlw, InstOptions::kNone, xmm1, xmm2, imm(8));
1719
+ EXPECT(rwi.rmFeature() == CpuFeatures::X86::kAVX512_BW);
1720
+
1721
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpslld, InstOptions::kNone, xmm1, xmm2, xmm3);
1722
+ EXPECT(rwi.rmFeature() == 0);
1723
+
1724
+ queryRWInfoSimple(&rwi, Arch::kX64, Inst::kIdVpsllw, InstOptions::kNone, xmm1, xmm2, xmm3);
1725
+ EXPECT(rwi.rmFeature() == 0);
1726
+ }
1727
+ }
1728
+ #endif
1729
+
1730
+ ASMJIT_END_SUB_NAMESPACE
1731
+
1732
+ #endif // !ASMJIT_NO_X86