asmjit 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/asmjit.gemspec +1 -1
  4. data/ext/asmjit/asmjit/.editorconfig +10 -0
  5. data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
  6. data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
  7. data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
  8. data/ext/asmjit/asmjit/.gitignore +6 -0
  9. data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
  10. data/ext/asmjit/asmjit/LICENSE.md +17 -0
  11. data/ext/asmjit/asmjit/README.md +69 -0
  12. data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
  13. data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
  14. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
  15. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
  16. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
  17. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
  18. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
  19. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
  20. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
  21. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
  22. data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
  23. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
  24. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
  25. data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
  26. data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
  27. data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
  28. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
  29. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
  30. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
  31. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
  32. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
  33. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
  34. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
  35. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
  36. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
  37. data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
  38. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
  39. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
  40. data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
  41. data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
  42. data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
  43. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
  44. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
  45. data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
  46. data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
  47. data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
  48. data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
  49. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
  50. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
  51. data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
  52. data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
  53. data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
  54. data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
  55. data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
  56. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
  57. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
  58. data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
  59. data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
  60. data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
  61. data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
  62. data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
  63. data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
  64. data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
  65. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
  66. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
  67. data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
  68. data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
  69. data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
  70. data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
  71. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
  72. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
  73. data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
  74. data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
  75. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
  76. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
  77. data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
  78. data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
  79. data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
  80. data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
  81. data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
  82. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
  83. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
  84. data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
  85. data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
  86. data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
  87. data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
  88. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
  89. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
  90. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
  91. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
  92. data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
  93. data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
  94. data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
  95. data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
  96. data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
  97. data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
  98. data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
  99. data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
  100. data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
  101. data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
  102. data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
  103. data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
  104. data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
  105. data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
  106. data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
  107. data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
  108. data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
  109. data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
  110. data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
  111. data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
  112. data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
  113. data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
  114. data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
  115. data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
  116. data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
  117. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
  118. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
  119. data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
  120. data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
  121. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
  122. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
  123. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
  124. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
  125. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
  126. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
  127. data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
  128. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
  129. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
  130. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
  131. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
  132. data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
  133. data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
  134. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
  135. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
  136. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
  137. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
  138. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
  139. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
  140. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
  141. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
  142. data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
  143. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
  144. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
  145. data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
  146. data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
  147. data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
  148. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
  149. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
  150. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
  151. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
  152. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
  153. data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
  154. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
  155. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
  156. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
  157. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
  158. data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
  159. data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
  160. data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
  161. data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
  162. data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
  163. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
  164. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
  165. data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
  166. data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
  167. data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
  168. data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
  169. data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
  170. data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
  171. data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
  172. data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
  173. data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
  174. data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
  175. data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
  176. data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
  177. data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
  178. data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
  179. data/ext/asmjit/asmjit/test/broken.cpp +312 -0
  180. data/ext/asmjit/asmjit/test/broken.h +148 -0
  181. data/ext/asmjit/asmjit/test/cmdline.h +61 -0
  182. data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
  183. data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
  184. data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
  185. data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
  186. data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
  187. data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
  188. data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
  189. data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
  190. data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
  191. data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
  192. data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
  193. data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
  194. data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
  195. data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
  196. data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
  197. data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
  198. data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
  199. data/ext/asmjit/asmjit.cc +18 -0
  200. data/lib/asmjit/version.rb +1 -1
  201. metadata +197 -2
@@ -0,0 +1,2638 @@
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
+ // tablegen-x86.js
8
+ //
9
+ // The purpose of this script is to fetch all instructions' names into a single
10
+ // string and to optimize common patterns that appear in instruction data. It
11
+ // prevents relocation of small strings (instruction names) that has to be done
12
+ // by a linker to make all pointers the binary application/library uses valid.
13
+ // This approach decreases the final size of AsmJit binary and relocation data.
14
+ //
15
+ // NOTE: This script relies on 'asmdb' package. Either install it by using
16
+ // node.js package manager (npm) or by copying/symlinking the whole asmdb
17
+ // directory as [asmjit]/tools/asmdb.
18
+ // ============================================================================
19
+
20
+ "use strict";
21
+
22
+ const core = require("./tablegen.js");
23
+ const asmdb = core.asmdb;
24
+ const kIndent = core.kIndent;
25
+
26
+ const Lang = core.Lang;
27
+ const CxxUtils = core.CxxUtils;
28
+ const MapUtils = core.MapUtils;
29
+ const ArrayUtils = core.ArrayUtils;
30
+ const StringUtils = core.StringUtils;
31
+ const IndexedArray = core.IndexedArray;
32
+
33
+ const hasOwn = Object.prototype.hasOwnProperty;
34
+ const disclaimer = StringUtils.disclaimer;
35
+
36
+ const FAIL = core.FAIL;
37
+ const DEBUG = core.DEBUG;
38
+
39
+ const decToHex = StringUtils.decToHex;
40
+
41
+ // ============================================================================
42
+ // [tablegen.x86.x86isa]
43
+ // ============================================================================
44
+
45
+ // Create the X86 database and add some special cases recognized by AsmJit.
46
+ const x86isa = new asmdb.x86.ISA({
47
+ instructions: [
48
+ // Imul in [reg, imm] form is encoded as [reg, reg, imm].
49
+ ["imul", "r16, ib" , "RMI" , "66 6B /r ib" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
50
+ ["imul", "r32, ib" , "RMI" , "6B /r ib" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
51
+ ["imul", "r64, ib" , "RMI" , "REX.W 6B /r ib", "X64 OF=W SF=W ZF=U AF=U PF=U CF=W"],
52
+ ["imul", "r16, iw" , "RMI" , "66 69 /r iw" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
53
+ ["imul", "r32, id" , "RMI" , "69 /r id" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
54
+ ["imul", "r64, id" , "RMI" , "REX.W 69 /r id", "X64 OF=W SF=W ZF=U AF=U PF=U CF=W"],
55
+
56
+ // Movabs (X64 only).
57
+ ["movabs", "W:r64, iq/uq" , "I" , "REX.W B8+r iq", "X64"],
58
+ ["movabs", "w:al, moff8" , "NONE", "A0" , "X64"],
59
+ ["movabs", "w:ax, moff16" , "NONE", "66 A1" , "X64"],
60
+ ["movabs", "W:eax, moff32", "NONE", "A1" , "X64"],
61
+ ["movabs", "W:rax, moff64", "NONE", "REX.W A1" , "X64"],
62
+ ["movabs", "W:moff8, al" , "NONE", "A2" , "X64"],
63
+ ["movabs", "W:moff16, ax" , "NONE", "66 A3" , "X64"],
64
+ ["movabs", "W:moff32, eax", "NONE", "A3" , "X64"],
65
+ ["movabs", "W:moff64, rax", "NONE", "REX.W A3" , "X64"]
66
+ ]
67
+ });
68
+
69
+ // Remapped instructions contain mapping between instructions that AsmJit expects
70
+ // and instructions provided by asmdb. In general, AsmJit uses string instructions
71
+ // (like cmps, movs, etc...) without the suffix, so we just remap these and keep
72
+ // all others.
73
+ const RemappedInsts = {
74
+ __proto__: null,
75
+
76
+ "cmpsd": { names: ["cmpsd"] , rep: false },
77
+ "movsd": { names: ["movsd"] , rep: false },
78
+ "cmps" : { names: ["cmpsb", "cmpsw", "cmpsd", "cmpsq"], rep: true },
79
+ "movs" : { names: ["movsb", "movsw", "movsd", "movsq"], rep: true },
80
+ "lods" : { names: ["lodsb", "lodsw", "lodsd", "lodsq"], rep: null },
81
+ "scas" : { names: ["scasb", "scasw", "scasd", "scasq"], rep: null },
82
+ "stos" : { names: ["stosb", "stosw", "stosd", "stosq"], rep: null },
83
+ "ins" : { names: ["insb" , "insw" , "insd" ] , rep: null },
84
+ "outs" : { names: ["outsb", "outsw", "outsd"] , rep: null }
85
+ };
86
+
87
+ // ============================================================================
88
+ // [tablegen.x86.Filter]
89
+ // ============================================================================
90
+
91
+ class Filter {
92
+ static unique(instArray) {
93
+ const result = [];
94
+ const known = {};
95
+
96
+ for (var i = 0; i < instArray.length; i++) {
97
+ const inst = instArray[i];
98
+ if (inst.attributes.AltForm)
99
+ continue;
100
+
101
+ const s = inst.operands.map((op) => { return op.isImm() ? "imm" : op.toString(); }).join(", ");
102
+ if (known[s] === true)
103
+ continue;
104
+
105
+ known[s] = true;
106
+ result.push(inst);
107
+ }
108
+
109
+ return result;
110
+ }
111
+
112
+ static noAltForm(instArray) {
113
+ const result = [];
114
+ for (var i = 0; i < instArray.length; i++) {
115
+ const inst = instArray[i];
116
+ if (inst.attributes.AltForm)
117
+ continue;
118
+ result.push(inst);
119
+ }
120
+ return result;
121
+ }
122
+
123
+ static byArch(instArray, arch) {
124
+ return instArray.filter(function(inst) {
125
+ return inst.arch === "ANY" || inst.arch === arch;
126
+ });
127
+ }
128
+ }
129
+
130
+ // ============================================================================
131
+ // [tablegen.x86.GenUtils]
132
+ // ============================================================================
133
+
134
+ const VexToEvexMap = {
135
+ "vbroadcastf128": "vbroadcastf32x4",
136
+ "vbroadcasti128": "vbroadcasti32x4",
137
+ "vextractf128": "vextractf32x4",
138
+ "vextracti128": "vextracti32x4",
139
+ "vinsertf128": "vinsertf32x4",
140
+ "vinserti128": "vinserti32x4",
141
+ "vmovdqa": "vmovdqa32",
142
+ "vmovdqu": "vmovdqu32",
143
+ "vpand": "vpandd",
144
+ "vpandn": "vpandnd",
145
+ "vpor": "vpord",
146
+ "vpxor": "vpxord",
147
+ "vroundpd": "vrndscalepd",
148
+ "vroundps": "vrndscaleps",
149
+ "vroundsd": "vrndscalesd",
150
+ "vroundss": "vrndscaless"
151
+ };
152
+
153
+ class GenUtils {
154
+ static cpuArchOf(dbInsts) {
155
+ var anyArch = false;
156
+ var x86Arch = false;
157
+ var x64Arch = false;
158
+
159
+ for (var i = 0; i < dbInsts.length; i++) {
160
+ const dbInst = dbInsts[i];
161
+ if (dbInst.arch === "ANY") anyArch = true;
162
+ if (dbInst.arch === "X86") x86Arch = true;
163
+ if (dbInst.arch === "X64") x64Arch = true;
164
+ }
165
+
166
+ return anyArch || (x86Arch && x64Arch) ? "" : x86Arch ? "(X86)" : "(X64)";
167
+ }
168
+
169
+ static cpuFeaturesOf(dbInsts) {
170
+ return ArrayUtils.sorted(dbInsts.unionCpuFeatures());
171
+ }
172
+
173
+ static assignVexEvexCompatibilityFlags(f, dbInsts) {
174
+ const vexInsts = dbInsts.filter((inst) => { return inst.prefix === "VEX"; });
175
+ const evexInsts = dbInsts.filter((inst) => { return inst.prefix === "EVEX"; });
176
+
177
+ function isCompatible(vexInst, evexInst) {
178
+ if (vexInst.operands.length !== evexInst.operands.length)
179
+ return false;
180
+
181
+ for (let i = 0; i < vexInst.operands.length; i++) {
182
+ const vexOp = vexInst.operands[i];
183
+ const evexOp = evexInst.operands[i];
184
+
185
+ if (vexOp.data === evexOp.data)
186
+ continue;
187
+
188
+ if (vexOp.reg && vexOp.reg === evexOp.reg)
189
+ continue;
190
+ if (vexOp.mem && vexOp.mem === evexOp.mem)
191
+ continue;
192
+
193
+ return false;
194
+ }
195
+ return true;
196
+ }
197
+
198
+ let compatible = 0;
199
+ for (const vexInst of vexInsts) {
200
+ for (const evexInst of evexInsts) {
201
+ if (isCompatible(vexInst, evexInst)) {
202
+ compatible++;
203
+ break;
204
+ }
205
+ }
206
+ }
207
+
208
+ if (compatible == vexInsts.length) {
209
+ f.EvexCompat = true;
210
+ return true;
211
+ }
212
+
213
+ if (evexInsts[0].operands[0].reg === "k") {
214
+ f.EvexKReg = true;
215
+ return true;
216
+ }
217
+
218
+ if (evexInsts[0].operands.length == 2 && vexInsts[0].operands.length === 3) {
219
+ f.EvexTwoOp = true;
220
+ return true;
221
+ }
222
+
223
+ return false;
224
+ }
225
+
226
+ static flagsOf(dbInsts) {
227
+ const f = Object.create(null);
228
+ var i, j;
229
+
230
+ var mib = dbInsts.length > 0 && /^(?:bndldx|bndstx)$/.test(dbInsts[0].name);
231
+ if (mib)
232
+ f.Mib = true;
233
+
234
+ var mmx = false;
235
+ var vec = false;
236
+
237
+ for (i = 0; i < dbInsts.length; i++) {
238
+ const dbInst = dbInsts[i];
239
+ const operands = dbInst.operands;
240
+
241
+ if (dbInst.name === "emms")
242
+ mmx = true;
243
+
244
+ if (dbInst.name === "vzeroall" || dbInst.name === "vzeroupper")
245
+ vec = true;
246
+
247
+ for (j = 0; j < operands.length; j++) {
248
+ const op = operands[j];
249
+ if (op.reg === "mm")
250
+ mmx = true;
251
+ else if (/^(xmm|ymm|zmm)$/.test(op.reg)) {
252
+ vec = true;
253
+ }
254
+ }
255
+ }
256
+
257
+ if (mmx) f.Mmx = true;
258
+ if (vec) f.Vec = true;
259
+
260
+ for (i = 0; i < dbInsts.length; i++) {
261
+ const dbInst = dbInsts[i];
262
+ const operands = dbInst.operands;
263
+
264
+ if (dbInst.attributes.Lock ) f.Lock = true;
265
+ if (dbInst.attributes.XAcquire ) f.XAcquire = true;
266
+ if (dbInst.attributes.XRelease ) f.XRelease = true;
267
+ if (dbInst.attributes.BND ) f.Rep = true;
268
+ if (dbInst.attributes.REP ) f.Rep = true;
269
+ if (dbInst.attributes.REPNE ) f.Rep = true;
270
+ if (dbInst.attributes.RepIgnored ) f.RepIgnored = true;
271
+ if (dbInst.attributes.ImplicitZeroing) f.Avx512ImplicitZ = true;
272
+
273
+ if (dbInst.fpu) {
274
+ for (var j = 0; j < operands.length; j++) {
275
+ const op = operands[j];
276
+ if (op.memSize === 16) f.FpuM16 = true;
277
+ if (op.memSize === 32) f.FpuM32 = true;
278
+ if (op.memSize === 64) f.FpuM64 = true;
279
+ if (op.memSize === 80) f.FpuM80 = true;
280
+ }
281
+ }
282
+
283
+ if (dbInst.attributes.Tsib)
284
+ f.Tsib = true;
285
+
286
+ if (dbInst.vsibReg)
287
+ f.Vsib = true;
288
+
289
+ if (dbInst.prefix === "VEX" || dbInst.prefix === "XOP")
290
+ f.Vex = true;
291
+
292
+ if (dbInst.prefix === "EVEX") {
293
+ f.Evex = true;
294
+
295
+ if (dbInst.extensions["AVX512_VNNI"])
296
+ f.PreferEvex = true;
297
+
298
+ if (dbInst.kmask) f.Avx512K = true;
299
+ if (dbInst.zmask) f.Avx512Z = true;
300
+
301
+ if (dbInst.er) f.Avx512ER = true;
302
+ if (dbInst.sae) f.Avx512SAE = true;
303
+
304
+ if (dbInst.broadcast) f["Avx512B" + String(dbInst.elementSize)] = true;
305
+ if (dbInst.tupleType === "T1_4X") f.Avx512T4X = true;
306
+ }
307
+
308
+ if (VexToEvexMap[dbInst.name])
309
+ f.EvexTransformable = true;
310
+ }
311
+
312
+ if (f.Vex && f.Evex) {
313
+ GenUtils.assignVexEvexCompatibilityFlags(f, dbInsts)
314
+ }
315
+
316
+ const result = Object.getOwnPropertyNames(f);
317
+ result.sort();
318
+ return result;
319
+ }
320
+
321
+ static eqOps(aOps, aFrom, bOps, bFrom) {
322
+ var x = 0;
323
+ for (;;) {
324
+ const aIndex = x + aFrom;
325
+ const bIndex = x + bFrom;
326
+
327
+ const aOut = aIndex >= aOps.length;
328
+ const bOut = bIndex >= bOps.length;
329
+
330
+ if (aOut || bOut)
331
+ return !!(aOut && bOut);
332
+
333
+ const aOp = aOps[aIndex];
334
+ const bOp = bOps[bIndex];
335
+
336
+ if (aOp.data !== bOp.data)
337
+ return false;
338
+
339
+ x++;
340
+ }
341
+ }
342
+
343
+ // Prevent some instructions from having implicit memory size if that would
344
+ // make them ambiguous. There are some instructions where the ambiguity is
345
+ // okay, but some like 'push' and 'pop' where it isn't.
346
+ static canUseImplicitMemSize(name) {
347
+ switch (name) {
348
+ case "pop":
349
+ case "push":
350
+ return false;
351
+
352
+ default:
353
+ return true;
354
+ }
355
+ }
356
+
357
+ static singleRegCase(name) {
358
+ switch (name) {
359
+ case "xchg" :
360
+
361
+ case "and" :
362
+ case "pand" : case "vpand" : case "vpandd" : case "vpandq" :
363
+ case "andpd" : case "vandpd" :
364
+ case "andps" : case "vandps" :
365
+
366
+ case "or" :
367
+ case "por" : case "vpor" : case "vpord" : case "vporq" :
368
+ case "orpd" : case "vorpd" :
369
+ case "orps" : case "vorps" :
370
+
371
+ case "pminsb" : case "vpminsb": case "pmaxsb" : case "vpmaxsb" :
372
+ case "pminsw" : case "vpminsw": case "pmaxsw" : case "vpmaxsw" :
373
+ case "pminsd" : case "vpminsd": case "pmaxsd" : case "vpmaxsd" :
374
+ case "pminub" : case "vpminub": case "pmaxub" : case "vpmaxub" :
375
+ case "pminuw" : case "vpminuw": case "pmaxuw" : case "vpmaxuw" :
376
+ case "pminud" : case "vpminud": case "pmaxud" : case "vpmaxud" :
377
+ return "RO";
378
+
379
+ case "pandn" : case "vpandn" : case "vpandnd" : case "vpandnq" :
380
+
381
+ case "xor" :
382
+ case "pxor" : case "vpxor" : case "vpxord" : case "vpxorq" :
383
+ case "xorpd" : case "vxorpd" :
384
+ case "xorps" : case "vxorps" :
385
+
386
+ case "kxnorb":
387
+ case "kxnord":
388
+ case "kxnorw":
389
+ case "kxnorq":
390
+
391
+ case "kxorb":
392
+ case "kxord":
393
+ case "kxorw":
394
+ case "kxorq":
395
+
396
+ case "sub" :
397
+ case "sbb" :
398
+ case "psubb" : case "vpsubb" :
399
+ case "psubw" : case "vpsubw" :
400
+ case "psubd" : case "vpsubd" :
401
+ case "psubq" : case "vpsubq" :
402
+ case "psubsb" : case "vpsubsb": case "psubusb" : case "vpsubusb" :
403
+ case "psubsw" : case "vpsubsw": case "psubusw" : case "vpsubusw" :
404
+
405
+ case "vpcmpeqb": case "pcmpeqb": case "vpcmpgtb": case "pcmpgtb" :
406
+ case "vpcmpeqw": case "pcmpeqw": case "vpcmpgtw": case "pcmpgtw" :
407
+ case "vpcmpeqd": case "pcmpeqd": case "vpcmpgtd": case "pcmpgtd" :
408
+ case "vpcmpeqq": case "pcmpeqq": case "vpcmpgtq": case "pcmpgtq" :
409
+
410
+ case "vpcmpb" : case "vpcmpub":
411
+ case "vpcmpd" : case "vpcmpud":
412
+ case "vpcmpw" : case "vpcmpuw":
413
+ case "vpcmpq" : case "vpcmpuq":
414
+ return "WO";
415
+
416
+ default:
417
+ return "None";
418
+ }
419
+ }
420
+
421
+ static fixedRegOf(reg) {
422
+ switch (reg) {
423
+ case "es" : return 1;
424
+ case "cs" : return 2;
425
+ case "ss" : return 3;
426
+ case "ds" : return 4;
427
+ case "fs" : return 5;
428
+ case "gs" : return 6;
429
+ case "ah" : return 0;
430
+ case "ch" : return 1;
431
+ case "dh" : return 2;
432
+ case "bh" : return 3;
433
+ case "al" : case "ax": case "eax": case "rax": case "zax": return 0;
434
+ case "cl" : case "cx": case "ecx": case "rcx": case "zcx": return 1;
435
+ case "dl" : case "dx": case "edx": case "rdx": case "zdx": return 2;
436
+ case "bl" : case "bx": case "ebx": case "rbx": case "zbx": return 3;
437
+ case "spl" : case "sp": case "esp": case "rsp": case "zsp": return 4;
438
+ case "bpl" : case "bp": case "ebp": case "rbp": case "zbp": return 5;
439
+ case "sil" : case "si": case "esi": case "rsi": case "zsi": return 6;
440
+ case "dil" : case "di": case "edi": case "rdi": case "zdi": return 7;
441
+ case "st0" : return 0;
442
+ case "xmm0": return 0;
443
+ case "ymm0": return 0;
444
+ case "zmm0": return 0;
445
+ default:
446
+ return -1;
447
+ }
448
+ }
449
+
450
+ static controlFlow(dbInsts) {
451
+ if (dbInsts.checkAttribute("Control", "Jump")) return "Jump";
452
+ if (dbInsts.checkAttribute("Control", "Call")) return "Call";
453
+ if (dbInsts.checkAttribute("Control", "Branch")) return "Branch";
454
+ if (dbInsts.checkAttribute("Control", "Return")) return "Return";
455
+ return "Regular";
456
+ }
457
+ }
458
+
459
+ // ============================================================================
460
+ // [tablegen.x86.X86TableGen]
461
+ // ============================================================================
462
+
463
+ class X86TableGen extends core.TableGen {
464
+ constructor() {
465
+ super("X86");
466
+
467
+ this.emitMissingString = "";
468
+ }
469
+
470
+ // --------------------------------------------------------------------------
471
+ // [Query]
472
+ // --------------------------------------------------------------------------
473
+
474
+ // Get instructions (dbInsts) having the same name as understood by AsmJit.
475
+ query(name) {
476
+ const remapped = RemappedInsts[name];
477
+ if (!remapped) return x86isa.query(name);
478
+
479
+ const dbInsts = x86isa.query(remapped.names);
480
+ const rep = remapped.rep;
481
+ if (rep === null) return dbInsts;
482
+
483
+ return dbInsts.filter((inst) => {
484
+ return rep === !!(inst.attributes.REP || inst.attributes.REPNE);
485
+ });
486
+ }
487
+
488
+ // --------------------------------------------------------------------------
489
+ // [Parse / Merge]
490
+ // --------------------------------------------------------------------------
491
+
492
+ parse() {
493
+ const data = this.dataOfFile("src/asmjit/x86/x86instdb.cpp");
494
+ const re = new RegExp(
495
+ "INST\\(" +
496
+ "([A-Za-z0-9_]+)\\s*" + "," + // [01] Instruction.
497
+ "([^,]+)" + "," + // [02] Encoding.
498
+ "(.{26}[^,]*)" + "," + // [03] Opcode[0].
499
+ "(.{26}[^,]*)" + "," + // [04] Opcode[1].
500
+ // --- autogenerated fields ---
501
+ "([^\\)]+)" + "," + // [05] MainOpcodeIndex.
502
+ "([^\\)]+)" + "," + // [06] AltOpcodeIndex.
503
+ "([^\\)]+)" + "," + // [07] NameIndex.
504
+ "([^\\)]+)" + "," + // [08] CommonDataIndex.
505
+ "([^\\)]+)" + "\\)", // [09] OperationDataIndex.
506
+ "g");
507
+
508
+ var m;
509
+ while ((m = re.exec(data)) !== null) {
510
+ var enum_ = m[1];
511
+ var name = enum_ === "None" ? "" : enum_.toLowerCase();
512
+ var encoding = m[2].trim();
513
+ var opcode0 = m[3].trim();
514
+ var opcode1 = m[4].trim();
515
+
516
+ const dbInsts = this.query(name);
517
+ if (name && !dbInsts.length)
518
+ FAIL(`Instruction '${name}' not found in asmdb`);
519
+
520
+ const flags = GenUtils.flagsOf(dbInsts);
521
+ const controlFlow = GenUtils.controlFlow(dbInsts);
522
+ const singleRegCase = GenUtils.singleRegCase(name);
523
+
524
+ this.addInst({
525
+ id : 0, // Instruction id (numeric value).
526
+ name : name, // Instruction name.
527
+ displayName : name, // Instruction name to display.
528
+ enum : enum_, // Instruction enum without `kId` prefix.
529
+ dbInsts : dbInsts, // All dbInsts returned from asmdb query.
530
+ encoding : encoding, // Instruction encoding.
531
+ opcode0 : opcode0, // Primary opcode.
532
+ opcode1 : opcode1, // Secondary opcode.
533
+ flags : flags,
534
+ signatures : null, // Instruction signatures.
535
+ controlFlow : controlFlow,
536
+ singleRegCase : singleRegCase,
537
+
538
+ mainOpcodeValue : -1, // Main opcode value (0.255 hex).
539
+ mainOpcodeIndex : -1, // Index to InstDB::_mainOpcodeTable.
540
+ altOpcodeIndex : -1, // Index to InstDB::_altOpcodeTable.
541
+ nameIndex : -1, // Index to InstDB::_nameData.
542
+ commonInfoIndex : -1,
543
+ additionalInfoIndex: -1,
544
+
545
+ signatureIndex : -1,
546
+ signatureCount : -1
547
+ });
548
+ }
549
+
550
+ if (this.insts.length === 0)
551
+ FAIL("X86TableGen.parse(): Invalid parsing regexp (no data parsed)");
552
+
553
+ console.log("Number of Instructions: " + this.insts.length);
554
+ }
555
+
556
+ merge() {
557
+ var s = StringUtils.format(this.insts, "", true, function(inst) {
558
+ return "INST(" +
559
+ String(inst.enum ).padEnd(17) + ", " +
560
+ String(inst.encoding ).padEnd(19) + ", " +
561
+ String(inst.opcode0 ).padEnd(26) + ", " +
562
+ String(inst.opcode1 ).padEnd(26) + ", " +
563
+ String(inst.mainOpcodeIndex ).padEnd( 3) + ", " +
564
+ String(inst.altOpcodeIndex ).padEnd( 3) + ", " +
565
+ String(inst.nameIndex ).padEnd( 5) + ", " +
566
+ String(inst.commonInfoIndex ).padEnd( 3) + ", " +
567
+ String(inst.additionalInfoIndex).padEnd( 3) + ")";
568
+ }) + "\n";
569
+ this.inject("InstInfo", s, this.insts.length * 8);
570
+ }
571
+
572
+ // --------------------------------------------------------------------------
573
+ // [Other]
574
+ // --------------------------------------------------------------------------
575
+
576
+ printMissing() {
577
+ const ignored = MapUtils.arrayToMap([
578
+ "cmpsb", "cmpsw", "cmpsd", "cmpsq",
579
+ "lodsb", "lodsw", "lodsd", "lodsq",
580
+ "movsb", "movsw", "movsd", "movsq",
581
+ "scasb", "scasw", "scasd", "scasq",
582
+ "stosb", "stosw", "stosd", "stosq",
583
+ "insb" , "insw" , "insd" ,
584
+ "outsb", "outsw", "outsd",
585
+ "wait" // Maps to `fwait`, which AsmJit uses instead.
586
+ ]);
587
+
588
+ var out = "";
589
+ x86isa.instructionNames.forEach(function(name) {
590
+ var dbInsts = x86isa.query(name);
591
+ if (!this.instMap[name] && ignored[name] !== true) {
592
+ console.log(`MISSING INSTRUCTION '${name}'`);
593
+ var inst = this.newInstFromGroup(dbInsts);
594
+ if (inst) {
595
+ out += " INST(" +
596
+ String(inst.enum ).padEnd(17) + ", " +
597
+ String(inst.encoding ).padEnd(19) + ", " +
598
+ String(inst.opcode0 ).padEnd(26) + ", " +
599
+ String(inst.opcode1 ).padEnd(26) + ", " +
600
+ String("0" ).padEnd( 3) + ", " +
601
+ String("0" ).padEnd( 3) + ", " +
602
+ String("0" ).padEnd( 5) + ", " +
603
+ String("0" ).padEnd( 3) + ", " +
604
+ String("0" ).padEnd( 3) + "),\n";
605
+ }
606
+ }
607
+ }, this);
608
+ console.log(out);
609
+ console.log(this.emitMissingString);
610
+ }
611
+
612
+ newInstFromGroup(dbInsts) {
613
+ function composeOpCode(obj) {
614
+ return `${obj.type}(${obj.prefix},${obj.opcode},${obj.o},${obj.l},${obj.w},${obj.ew},${obj.en},${obj.tt})`;
615
+ }
616
+
617
+ function GetAccess(dbInst) {
618
+ var operands = dbInst.operands;
619
+ if (!operands.length) return "";
620
+
621
+ var op = operands[0];
622
+ if (op.read && op.write)
623
+ return "RW";
624
+ else if (op.read)
625
+ return "RO";
626
+ else
627
+ return "WO";
628
+ }
629
+
630
+ function isVecPrefix(s) {
631
+ return s === "VEX" || s === "EVEX" || s === "XOP";
632
+ }
633
+
634
+ function formatEmit(dbi) {
635
+ const results = [];
636
+ const nameUp = dbi.name[0].toUpperCase() + dbi.name.substr(1);
637
+
638
+ for (let choice = 0; choice < 2; choice++) {
639
+ let s = `ASMJIT_INST_${dbi.operands.length}x(${dbi.name}, ${nameUp}`;
640
+ for (let j = 0; j < dbi.operands.length; j++) {
641
+ s += ", ";
642
+ const op = dbi.operands[j];
643
+ var reg = op.reg;
644
+ var mem = op.mem;
645
+
646
+ if (op.isReg() && op.isMem()) {
647
+ if (choice == 0) mem = null;
648
+ if (choice == 1) reg = null;
649
+ }
650
+
651
+ if (reg) {
652
+ if (reg === "xmm" || reg === "ymm" || reg === "zmm")
653
+ s += "Vec";
654
+ else if (reg === "k")
655
+ s += "KReg";
656
+ else if (reg === "r32" || reg === "r64" || reg === "r16" || reg === "r8")
657
+ s += "Gp";
658
+ else
659
+ s += reg;
660
+ }
661
+ else if (mem) {
662
+ s += "Mem";
663
+ }
664
+ else if (op.isImm()) {
665
+ s += "Imm";
666
+ }
667
+ else {
668
+ s += "Unknown";
669
+ }
670
+ }
671
+ s += `)`;
672
+ results.push(s);
673
+ }
674
+
675
+ return results;
676
+ }
677
+
678
+ var dbi = dbInsts[0];
679
+
680
+ var id = this.insts.length;
681
+ var name = dbi.name;
682
+ var enum_ = name[0].toUpperCase() + name.substr(1);
683
+
684
+ var opcode = dbi.opcodeHex;
685
+ var modR = dbi.modR;
686
+ var mm = dbi.mm;
687
+ var pp = dbi.pp;
688
+ var encoding = dbi.encoding;
689
+ var isVec = isVecPrefix(dbi.prefix);
690
+ var evexCount = 0;
691
+
692
+ var access = GetAccess(dbi);
693
+
694
+ var vexL = undefined;
695
+ var vexW = undefined;
696
+ var evexW = undefined;
697
+ var cdshl = "_";
698
+ var tupleType = "_";
699
+
700
+ const tupleTypeToCDSHL = {
701
+ "FVM": "4",
702
+ "FV": "4",
703
+ "HVM": "3",
704
+ "HV": "3",
705
+ "QVM": "2",
706
+ "QV": "2",
707
+ "T1S": "?"
708
+ }
709
+
710
+ const emitMap = {};
711
+
712
+ for (var i = 0; i < dbInsts.length; i++) {
713
+ dbi = dbInsts[i];
714
+
715
+ if (dbi.prefix === "VEX" || dbi.prefix === "XOP") {
716
+ var newVexL = String(dbi.l === "128" ? 0 : dbi.l === "256" ? 1 : dbi.l === "512" ? 2 : "_");
717
+ var newVexW = String(dbi.w === "W0" ? 0 : dbi.w === "W1" ? 1 : "_");
718
+
719
+ if (vexL !== undefined && vexL !== newVexL)
720
+ vexL = "x";
721
+ else
722
+ vexL = newVexL;
723
+ if (vexW !== undefined && vexW !== newVexW)
724
+ vexW = "x";
725
+ else
726
+ vexW = newVexW;
727
+ }
728
+
729
+ if (dbi.prefix === "EVEX") {
730
+ evexCount++;
731
+ var newEvexW = String(dbi.w === "W0" ? 0 : dbi.w === "W1" ? 1 : "_");
732
+ if (evexW !== undefined && evexW !== newEvexW)
733
+ evexW = "x";
734
+ else
735
+ evexW = newEvexW;
736
+
737
+ if (dbi.tupleType) {
738
+ if (tupleType !== "_" && tupleType !== dbi.tupleType) {
739
+ console.log(`${dbi.name}: WARNING: TupleType ${tupleType} != ${dbi.tupleType}`);
740
+ }
741
+
742
+ tupleType = dbi.tupleType;
743
+ }
744
+ }
745
+
746
+ if (opcode !== dbi.opcodeHex ) { console.log(`${dbi.name}: ISSUE: Opcode ${opcode} != ${dbi.opcodeHex}`); return null; }
747
+ if (modR !== dbi.modR ) { console.log(`${dbi.name}: ISSUE: ModR ${modR} != ${dbi.modR}`); return null; }
748
+ if (mm !== dbi.mm ) { console.log(`${dbi.name}: ISSUE: MM ${mm} != ${dbi.mm}`); return null; }
749
+ if (pp !== dbi.pp ) { console.log(`${dbi.name}: ISSUE: PP ${pp} != ${dbi.pp}`); return null; }
750
+ if (encoding !== dbi.encoding ) { console.log(`${dbi.name}: ISSUE: Enc ${encoding} != ${dbi.encoding}`); return null; }
751
+ if (access !== GetAccess(dbi)) { console.log(`${dbi.name}: ISSUE: Access ${access} != ${GetAccess(dbi)}`); return null; }
752
+ if (isVec != isVecPrefix(dbi.prefix)) { console.log(`${dbi.name}: ISSUE: Vex/Non-Vex mismatch`); return null; }
753
+
754
+ formatEmit(dbi).forEach((emit) => {
755
+ if (!emitMap[emit]) {
756
+ emitMap[emit] = true;
757
+ this.emitMissingString += emit + "\n";
758
+ }
759
+ });
760
+ }
761
+
762
+ if (tupleType !== "_")
763
+ cdshl = tupleTypeToCDSHL[tupleType] || "?";
764
+
765
+ var ppmm = pp.padEnd(2).replace(/ /g, "0") +
766
+ mm.padEnd(4).replace(/ /g, "0") ;
767
+
768
+ var composed = composeOpCode({
769
+ type : evexCount == dbInsts.length ? "E" : isVec ? "V" : "O",
770
+ prefix: ppmm,
771
+ opcode: opcode,
772
+ o : modR === "r" ? "_" : (modR ? modR : "_"),
773
+ l : vexL !== undefined ? vexL : "_",
774
+ w : vexW !== undefined ? vexW : "_",
775
+ ew : evexW !== undefined ? evexW : "_",
776
+ en : cdshl,
777
+ tt : dbi.modRM ? dbi.modRM + " " : tupleType.padEnd(3)
778
+ });
779
+
780
+ return {
781
+ id : id,
782
+ name : name,
783
+ enum : enum_,
784
+ encoding : encoding,
785
+ opcode0 : composed,
786
+ opcode1 : "0",
787
+ nameIndex : -1,
788
+ commonInfoIndex : -1,
789
+ additionalInfoIndex: -1
790
+ };
791
+ }
792
+
793
+ // --------------------------------------------------------------------------
794
+ // [Hooks]
795
+ // --------------------------------------------------------------------------
796
+
797
+ onBeforeRun() {
798
+ this.load([
799
+ "src/asmjit/x86/x86globals.h",
800
+ "src/asmjit/x86/x86instdb.cpp",
801
+ "src/asmjit/x86/x86instdb.h",
802
+ "src/asmjit/x86/x86instdb_p.h"
803
+ ]);
804
+ this.parse();
805
+ }
806
+
807
+ onAfterRun() {
808
+ this.merge();
809
+ this.save();
810
+ this.dumpTableSizes();
811
+ this.printMissing();
812
+ }
813
+ }
814
+
815
+ // ============================================================================
816
+ // [tablegen.x86.IdEnum]
817
+ // ============================================================================
818
+
819
+ class IdEnum extends core.IdEnum {
820
+ constructor() {
821
+ super("IdEnum");
822
+ }
823
+
824
+ comment(inst) {
825
+ function filterAVX(features, avx) {
826
+ return features.filter(function(item) { return /^(AVX|FMA)/.test(item) === avx; });
827
+ }
828
+
829
+ var dbInsts = inst.dbInsts;
830
+ if (!dbInsts.length) return "Invalid instruction id.";
831
+
832
+ var text = "";
833
+ var features = GenUtils.cpuFeaturesOf(dbInsts);
834
+
835
+ const priorityFeatures = ["AVX_VNNI"];
836
+
837
+ if (features.length) {
838
+ text += "{";
839
+ const avxFeatures = filterAVX(features, true);
840
+ const otherFeatures = filterAVX(features, false);
841
+
842
+ for (const pf of priorityFeatures) {
843
+ const index = avxFeatures.indexOf(pf);
844
+ if (index != -1) {
845
+ avxFeatures.splice(index, 1);
846
+ avxFeatures.unshift(pf);
847
+ }
848
+ }
849
+
850
+ const vl = avxFeatures.indexOf("AVX512_VL");
851
+ if (vl !== -1) avxFeatures.splice(vl, 1);
852
+
853
+ const fma = avxFeatures.indexOf("FMA");
854
+ if (fma !== -1) { avxFeatures.splice(fma, 1); avxFeatures.splice(0, 0, "FMA"); }
855
+
856
+ text += avxFeatures.join("|");
857
+ if (vl !== -1) text += "+VL";
858
+
859
+ if (otherFeatures.length)
860
+ text += (avxFeatures.length ? " & " : "") + otherFeatures.join("|");
861
+
862
+ text += "}";
863
+ }
864
+
865
+ var arch = GenUtils.cpuArchOf(dbInsts);
866
+ if (arch)
867
+ text += (text ? " " : "") + arch;
868
+
869
+ return `Instruction '${inst.name}'${(text ? " " + text : "")}.`;
870
+ }
871
+ }
872
+
873
+ // ============================================================================
874
+ // [tablegen.x86.NameTable]
875
+ // ============================================================================
876
+
877
+ class NameTable extends core.NameTable {
878
+ constructor() {
879
+ super("NameTable");
880
+ }
881
+ }
882
+
883
+ // ============================================================================
884
+ // [tablegen.x86.AltOpcodeTable]
885
+ // ============================================================================
886
+
887
+ class AltOpcodeTable extends core.Task {
888
+ constructor() {
889
+ super("AltOpcodeTable");
890
+ }
891
+
892
+ run() {
893
+ const insts = this.ctx.insts;
894
+
895
+ const mainOpcodeTable = new IndexedArray();
896
+ const altOpcodeTable = new IndexedArray();
897
+
898
+ const cdttSimplification = {
899
+ "0" : "None",
900
+ "_" : "None",
901
+ "FV" : "ByLL",
902
+ "HV" : "ByLL",
903
+ "QV" : "ByLL",
904
+ "FVM" : "ByLL",
905
+ "T1S" : "None",
906
+ "T1F" : "None",
907
+ "T1_4X": "None",
908
+ "T2" : "None",
909
+ "T4" : "None",
910
+ "T8" : "None",
911
+ "HVM" : "ByLL",
912
+ "QVM" : "ByLL",
913
+ "OVM" : "ByLL",
914
+ "128" : "None",
915
+ "T4X" : "None"
916
+ }
917
+
918
+ const noOp = "O(000000,00,0,0,0,0,0,0 )";
919
+
920
+ mainOpcodeTable.addIndexed(noOp);
921
+
922
+ function splitOpcodeToComponents(opcode) {
923
+ const i = opcode.indexOf("(");
924
+ const prefix = opcode.substr(0, i);
925
+ return [prefix].concat(opcode.substring(i + 1, opcode.length - 1).split(","));
926
+ }
927
+
928
+ function normalizeOpcodeComponents(components) {
929
+ for (let i = 1; i < components.length; i++) {
930
+ components[i] = components[i].trim();
931
+ // These all are zeros that only have some contextual meaning in the table, but the assembler doesn't care.
932
+ if (components[i] === "_" || components[i] === "I" || components[i] === "x")
933
+ components[i] = "0";
934
+ }
935
+
936
+ // Simplify CDTT (compressed displacement TupleType).
937
+ if (components.length >= 9) {
938
+ if (components[0] === "V" || components[0] === "E") {
939
+ const cdtt = components[8];
940
+ if (cdttSimplification[cdtt] !== undefined)
941
+ components[8] = cdttSimplification[cdtt];
942
+ }
943
+ }
944
+ return components;
945
+ }
946
+
947
+ function joinOpcodeComponents(components) {
948
+ const prefix = components[0];
949
+ const values = components.slice(1);
950
+ if (values.length >= 8)
951
+ values[7] = values[7].padEnd(4);
952
+ return prefix + "(" + values.join(",") + ")";
953
+ }
954
+
955
+ function indexMainOpcode(opcode) {
956
+ if (opcode === "0")
957
+ return ["00", 0];
958
+
959
+ var opcodeByte = "";
960
+ const components = normalizeOpcodeComponents(splitOpcodeToComponents(opcode));
961
+
962
+ if (components[0] === "O_FPU") {
963
+ // Reset opcode byte, this is stored in the instruction data itself.
964
+ opcodeByte = components[2].substr(2, 2);
965
+ components[2] = components[2].substr(0, 2) + "00";
966
+ }
967
+ else if (components[0] === "O" || components[0] === "V" || components[0] === "E") {
968
+ // Reset opcode byte, this is stored in the instruction data itself.
969
+ opcodeByte = components[2];
970
+ components[2] = "00";
971
+ }
972
+ else {
973
+ FAIL(`Failed to process opcode '${opcode}'`);
974
+ }
975
+
976
+ const newOpcode = joinOpcodeComponents(components);
977
+ return [opcodeByte, mainOpcodeTable.addIndexed(newOpcode.padEnd(27))];
978
+ }
979
+
980
+ function indexAltOpcode(opcode) {
981
+ if (opcode === "0")
982
+ opcode = noOp;
983
+ else
984
+ opcode = joinOpcodeComponents(normalizeOpcodeComponents(splitOpcodeToComponents(opcode)));
985
+ return altOpcodeTable.addIndexed(opcode.padEnd(27));
986
+ }
987
+
988
+ insts.map((inst) => {
989
+ const [value, index] = indexMainOpcode(inst.opcode0);
990
+ inst.mainOpcodeValue = value;
991
+ inst.mainOpcodeIndex = index;
992
+ inst.altOpcodeIndex = indexAltOpcode(inst.opcode1);
993
+ });
994
+
995
+ // console.log(mainOpcodeTable.length);
996
+ // console.log(StringUtils.format(mainOpcodeTable, kIndent, true));
997
+
998
+ this.inject("MainOpcodeTable",
999
+ disclaimer(`const uint32_t InstDB::_mainOpcodeTable[] = {\n${StringUtils.format(mainOpcodeTable, kIndent, true)}\n};\n`),
1000
+ mainOpcodeTable.length * 4);
1001
+
1002
+ this.inject("AltOpcodeTable",
1003
+ disclaimer(`const uint32_t InstDB::_altOpcodeTable[] = {\n${StringUtils.format(altOpcodeTable, kIndent, true)}\n};\n`),
1004
+ altOpcodeTable.length * 4);
1005
+ }
1006
+ }
1007
+
1008
+ // ============================================================================
1009
+ // [tablegen.x86.InstSignatureTable]
1010
+ // ============================================================================
1011
+
1012
+ const RegOp = MapUtils.arrayToMap(["al", "ah", "ax", "eax", "rax", "cl", "r8lo", "r8hi", "r16", "r32", "r64", "xmm", "ymm", "zmm", "mm", "k", "sreg", "creg", "dreg", "st", "bnd"]);
1013
+ const MemOp = MapUtils.arrayToMap(["m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024"]);
1014
+
1015
+ const cmpOp = StringUtils.makePriorityCompare([
1016
+ "RegGpbLo", "RegGpbHi", "RegGpw", "RegGpd", "RegGpq", "RegXmm", "RegYmm", "RegZmm", "RegMm", "RegKReg", "RegSReg", "RegCReg", "RegDReg", "RegSt", "RegBnd", "RegTmm",
1017
+ "MemUnspecified", "Mem8", "Mem16", "Mem32", "Mem48", "Mem64", "Mem80", "Mem128", "Mem256", "Mem512", "Mem1024",
1018
+ "Vm32x", "Vm32y", "Vm32z", "Vm64x", "Vm64y", "Vm64z",
1019
+ "ImmI4", "ImmU4", "ImmI8", "ImmU8", "ImmI16", "ImmU16", "ImmI32", "ImmU32", "ImmI64", "ImmU64",
1020
+ "Rel8", "Rel32",
1021
+ "FlagMemBase",
1022
+ "FlagMemDs",
1023
+ "FlagMemEs",
1024
+ "FlagMib",
1025
+ "FlagTMem",
1026
+ "FlagConsecutive",
1027
+ "FlagImplicit"
1028
+ ]);
1029
+
1030
+ function StringifyOpArray(a, map) {
1031
+ var s = "";
1032
+ for (var i = 0; i < a.length; i++) {
1033
+ const op = a[i];
1034
+ var mapped = null;
1035
+ if (typeof map === "function")
1036
+ mapped = map(op);
1037
+ else if (hasOwn.call(map, op))
1038
+ mapped = map[op];
1039
+ else
1040
+ FAIL(`UNHANDLED OPERAND '${op}'`);
1041
+ s += (s ? " | " : "") + mapped;
1042
+ }
1043
+ return s ? s : "0";
1044
+ }
1045
+
1046
+ class OSignature {
1047
+ constructor() {
1048
+ this.flags = Object.create(null);
1049
+ }
1050
+
1051
+ equals(other) {
1052
+ return MapUtils.equals(this.flags, other.flags);
1053
+ }
1054
+
1055
+ xor(other) {
1056
+ const result = MapUtils.xor(this.flags, other.flags);
1057
+ return Object.getOwnPropertyNames(result).length === 0 ? null : result;
1058
+ }
1059
+
1060
+ mergeWith(other) {
1061
+ const af = this.flags;
1062
+ const bf = other.flags;
1063
+
1064
+ var k;
1065
+ var indexKind = "";
1066
+ var hasReg = false;
1067
+
1068
+ for (k in af) {
1069
+ const index = asmdb.x86.Utils.regIndexOf(k);
1070
+ const kind = asmdb.x86.Utils.regKindOf(k);
1071
+
1072
+ if (kind)
1073
+ hasReg = true;
1074
+
1075
+ if (index !== null && index !== -1)
1076
+ indexKind = kind;
1077
+ }
1078
+
1079
+ if (hasReg) {
1080
+ for (k in bf) {
1081
+ const index = asmdb.x86.Utils.regIndexOf(k);
1082
+ if (index !== null && index !== -1) {
1083
+ const kind = asmdb.x86.Utils.regKindOf(k);
1084
+ if (indexKind !== kind)
1085
+ return false;
1086
+ }
1087
+ }
1088
+ }
1089
+
1090
+ // Can merge...
1091
+ for (k in bf)
1092
+ af[k] = true;
1093
+ return true;
1094
+ }
1095
+
1096
+ toString() {
1097
+ var s = "";
1098
+ var flags = this.flags;
1099
+
1100
+ for (var k in flags) {
1101
+ if (k === "read" || k === "write" || k === "implicit" || k === "memDS" || k === "memES")
1102
+ continue;
1103
+
1104
+ var x = k;
1105
+ if (x === "memZAX") x = "zax";
1106
+ if (x === "memZDI") x = "zdi";
1107
+ if (x === "memZSI") x = "zsi";
1108
+ s += (s ? "|" : "") + x;
1109
+ }
1110
+
1111
+ if (flags.memDS) s = "ds:[" + s + "]";
1112
+ if (flags.memES) s = "es:[" + s + "]";
1113
+
1114
+ if (flags.implicit)
1115
+ s = "<" + s + ">";
1116
+
1117
+ return s;
1118
+ }
1119
+
1120
+ toAsmJitOpData() {
1121
+ var opFlags = Object.create(null);
1122
+ var regMask = 0;
1123
+
1124
+ for (var k in this.flags) {
1125
+ switch (k) {
1126
+ case "r8lo" : opFlags.RegGpbLo = true; break;
1127
+ case "r8hi" : opFlags.RegGpbHi = true; break;
1128
+ case "r16" : opFlags.RegGpw = true; break;
1129
+ case "r32" : opFlags.RegGpd = true; break;
1130
+ case "r64" : opFlags.RegGpq = true; break;
1131
+ case "creg" : opFlags.RegCReg = true; break;
1132
+ case "dreg" : opFlags.RegDReg = true; break;
1133
+ case "sreg" : opFlags.RegSReg = true; break;
1134
+ case "bnd" : opFlags.RegBnd = true; break;
1135
+ case "st" : opFlags.RegSt = true; break;
1136
+ case "k" : opFlags.RegKReg = true; break;
1137
+ case "mm" : opFlags.RegMm = true; break;
1138
+ case "xmm" : opFlags.RegXmm = true; break;
1139
+ case "ymm" : opFlags.RegYmm = true; break;
1140
+ case "zmm" : opFlags.RegZmm = true; break;
1141
+ case "tmm" : opFlags.RegTmm = true; break;
1142
+
1143
+ case "m8" : opFlags.Mem8 = true; break;
1144
+ case "m16" : opFlags.Mem16 = true; break;
1145
+ case "m32" : opFlags.Mem32 = true; break;
1146
+ case "m48" : opFlags.Mem48 = true; break;
1147
+ case "m64" : opFlags.Mem64 = true; break;
1148
+ case "m80" : opFlags.Mem80 = true; break;
1149
+ case "m128" : opFlags.Mem128 = true; break;
1150
+ case "m256" : opFlags.Mem256 = true; break;
1151
+ case "m512" : opFlags.Mem512 = true; break;
1152
+ case "m1024" : opFlags.Mem1024 = true; break;
1153
+
1154
+ case "mem" : opFlags.MemUnspecified = true; break;
1155
+ case "mib" : opFlags.MemUnspecified = true; opFlags.FlagMib = true; break;
1156
+ case "tmem" : opFlags.MemUnspecified = true; opFlags.FlagTMem = true; break;
1157
+
1158
+ case "memBase" : opFlags.FlagMemBase = true; break;
1159
+ case "memDS" : opFlags.FlagMemDs = true; break;
1160
+ case "memES" : opFlags.FlagMemEs = true; break;
1161
+ case "memZAX" : regMask |= 1 << 0; break;
1162
+ case "memZSI" : regMask |= 1 << 6; break;
1163
+ case "memZDI" : regMask |= 1 << 7; break;
1164
+
1165
+ case "vm32x" : opFlags.Vm32x = true; break;
1166
+ case "vm32y" : opFlags.Vm32y = true; break;
1167
+ case "vm32z" : opFlags.Vm32z = true; break;
1168
+ case "vm64x" : opFlags.Vm64x = true; break;
1169
+ case "vm64y" : opFlags.Vm64y = true; break;
1170
+ case "vm64z" : opFlags.Vm64z = true; break;
1171
+
1172
+ case "i4" : opFlags.ImmI4 = true; break;
1173
+ case "u4" : opFlags.ImmU4 = true; break;
1174
+ case "i8" : opFlags.ImmI8 = true; break;
1175
+ case "u8" : opFlags.ImmU8 = true; break;
1176
+ case "i16" : opFlags.ImmI16 = true; break;
1177
+ case "u16" : opFlags.ImmU16 = true; break;
1178
+ case "i32" : opFlags.ImmI32 = true; break;
1179
+ case "u32" : opFlags.ImmU32 = true; break;
1180
+ case "i64" : opFlags.ImmI64 = true; break;
1181
+ case "u64" : opFlags.ImmU64 = true; break;
1182
+
1183
+ case "rel8" : opFlags.ImmI32 = true; opFlags.ImmI64 = true; opFlags.Rel8 = true; break;
1184
+ case "rel16" : opFlags.ImmI32 = true; opFlags.ImmI64 = true; opFlags.Rel32 = true; break;
1185
+ case "rel32" : opFlags.ImmI32 = true; opFlags.ImmI64 = true; opFlags.Rel32 = true; break;
1186
+
1187
+ case "es" : opFlags.RegSReg = true; regMask |= 1 << 1; break;
1188
+ case "cs" : opFlags.RegSReg = true; regMask |= 1 << 2; break;
1189
+ case "ss" : opFlags.RegSReg = true; regMask |= 1 << 3; break;
1190
+ case "ds" : opFlags.RegSReg = true; regMask |= 1 << 4; break;
1191
+ case "fs" : opFlags.RegSReg = true; regMask |= 1 << 5; break;
1192
+ case "gs" : opFlags.RegSReg = true; regMask |= 1 << 6; break;
1193
+ case "al" : opFlags.RegGpbLo = true; regMask |= 1 << 0; break;
1194
+ case "ah" : opFlags.RegGpbHi = true; regMask |= 1 << 0; break;
1195
+ case "ax" : opFlags.RegGpw = true; regMask |= 1 << 0; break;
1196
+ case "eax" : opFlags.RegGpd = true; regMask |= 1 << 0; break;
1197
+ case "rax" : opFlags.RegGpq = true; regMask |= 1 << 0; break;
1198
+ case "cl" : opFlags.RegGpbLo = true; regMask |= 1 << 1; break;
1199
+ case "ch" : opFlags.RegGpbHi = true; regMask |= 1 << 1; break;
1200
+ case "cx" : opFlags.RegGpw = true; regMask |= 1 << 1; break;
1201
+ case "ecx" : opFlags.RegGpd = true; regMask |= 1 << 1; break;
1202
+ case "rcx" : opFlags.RegGpq = true; regMask |= 1 << 1; break;
1203
+ case "dl" : opFlags.RegGpbLo = true; regMask |= 1 << 2; break;
1204
+ case "dh" : opFlags.RegGpbHi = true; regMask |= 1 << 2; break;
1205
+ case "dx" : opFlags.RegGpw = true; regMask |= 1 << 2; break;
1206
+ case "edx" : opFlags.RegGpd = true; regMask |= 1 << 2; break;
1207
+ case "rdx" : opFlags.RegGpq = true; regMask |= 1 << 2; break;
1208
+ case "bl" : opFlags.RegGpbLo = true; regMask |= 1 << 3; break;
1209
+ case "bh" : opFlags.RegGpbHi = true; regMask |= 1 << 3; break;
1210
+ case "bx" : opFlags.RegGpw = true; regMask |= 1 << 3; break;
1211
+ case "ebx" : opFlags.RegGpd = true; regMask |= 1 << 3; break;
1212
+ case "rbx" : opFlags.RegGpq = true; regMask |= 1 << 3; break;
1213
+ case "si" : opFlags.RegGpw = true; regMask |= 1 << 6; break;
1214
+ case "esi" : opFlags.RegGpd = true; regMask |= 1 << 6; break;
1215
+ case "rsi" : opFlags.RegGpq = true; regMask |= 1 << 6; break;
1216
+ case "di" : opFlags.RegGpw = true; regMask |= 1 << 7; break;
1217
+ case "edi" : opFlags.RegGpd = true; regMask |= 1 << 7; break;
1218
+ case "rdi" : opFlags.RegGpq = true; regMask |= 1 << 7; break;
1219
+ case "st0" : opFlags.RegSt = true; regMask |= 1 << 0; break;
1220
+ case "xmm0" : opFlags.RegXmm = true; regMask |= 1 << 0; break;
1221
+ case "ymm0" : opFlags.RegYmm = true; regMask |= 1 << 0; break;
1222
+
1223
+ case "implicit": opFlags.FlagImplicit = true; break;
1224
+
1225
+ default:
1226
+ console.log(`UNKNOWN OPERAND '${k}'`);
1227
+ }
1228
+ }
1229
+
1230
+ const outputFlags = StringifyOpArray(ArrayUtils.sorted(opFlags, cmpOp), function(k) { return `F(${k})`; });
1231
+ return `ROW(${outputFlags || 0}, ${decToHex(regMask, 2)})`;
1232
+ }
1233
+ }
1234
+
1235
+ class ISignature extends Array {
1236
+ constructor(name) {
1237
+ super();
1238
+ this.name = name;
1239
+ this.x86 = false;
1240
+ this.x64 = false;
1241
+ this.implicit = 0; // Number of implicit operands.
1242
+ }
1243
+
1244
+ opEquals(other) {
1245
+ const len = this.length;
1246
+ if (len !== other.length) return false;
1247
+
1248
+ for (var i = 0; i < len; i++)
1249
+ if (!this[i].equals(other[i]))
1250
+ return false;
1251
+
1252
+ return true;
1253
+ }
1254
+
1255
+ mergeWith(other) {
1256
+ // If both architectures are the same, it's fine to merge.
1257
+ var ok = this.x86 === other.x86 && this.x64 === other.x64;
1258
+
1259
+ // If the first arch is [X86|X64] and the second [X64] it's also fine.
1260
+ if (!ok && this.x86 && this.x64 && !other.x86 && other.x64)
1261
+ ok = true;
1262
+
1263
+ // It's not ok if both signatures have different number of implicit operands.
1264
+ if (!ok || this.implicit !== other.implicit)
1265
+ return false;
1266
+
1267
+ // It's not ok if both signatures have different number of operands.
1268
+ const len = this.length;
1269
+ if (len !== other.length)
1270
+ return false;
1271
+
1272
+ var xorIndex = -1;
1273
+ for (var i = 0; i < len; i++) {
1274
+ const xor = this[i].xor(other[i]);
1275
+ if (xor === null) continue;
1276
+
1277
+ if (xorIndex === -1)
1278
+ xorIndex = i;
1279
+ else
1280
+ return false;
1281
+ }
1282
+
1283
+ // Bail if mergeWidth at operand-level failed.
1284
+ if (xorIndex !== -1 && !this[xorIndex].mergeWith(other[xorIndex]))
1285
+ return false;
1286
+
1287
+ this.x86 = this.x86 || other.x86;
1288
+ this.x64 = this.x64 || other.x64;
1289
+
1290
+ return true;
1291
+ }
1292
+
1293
+ toString() {
1294
+ return "{" + this.join(", ") + "}";
1295
+ }
1296
+ }
1297
+
1298
+ class SignatureArray extends Array {
1299
+ // Iterate over all signatures and check which operands don't need explicit memory size.
1300
+ calcImplicitMemSize() {
1301
+ // Calculates a hash-value (aka key) of all register operands specified by `regOps` in `inst`.
1302
+ function keyOf(inst, regOps) {
1303
+ var s = "";
1304
+ for (var i = 0; i < inst.length; i++) {
1305
+ const op = inst[i];
1306
+ if (regOps & (1 << i))
1307
+ s += "{" + ArrayUtils.sorted(MapUtils.and(op.flags, RegOp)).join("|") + "}";
1308
+ }
1309
+ return s || "?";
1310
+ }
1311
+
1312
+ var i;
1313
+ var aIndex, bIndex;
1314
+
1315
+ for (aIndex = 0; aIndex < this.length; aIndex++) {
1316
+ const aInst = this[aIndex];
1317
+ const len = aInst.length;
1318
+
1319
+ var memOp = "";
1320
+ var memPos = -1;
1321
+ var regOps = 0;
1322
+
1323
+ // Check if this instruction signature has a memory operand of explicit size.
1324
+ for (i = 0; i < len; i++) {
1325
+ const aOp = aInst[i];
1326
+ const mem = MapUtils.firstOf(aOp.flags, MemOp);
1327
+
1328
+ if (mem) {
1329
+ // Stop if the memory operand has implicit-size or if there is more than one.
1330
+ if (aOp.flags.mem || memPos >= 0) {
1331
+ memPos = -1;
1332
+ break;
1333
+ }
1334
+ else {
1335
+ memOp = mem;
1336
+ memPos = i;
1337
+ }
1338
+ }
1339
+ else if (MapUtils.anyOf(aOp.flags, RegOp)) {
1340
+ // Doesn't consider 'r/m' as we already checked 'm'.
1341
+ regOps |= (1 << i);
1342
+ }
1343
+ }
1344
+
1345
+ if (memPos < 0)
1346
+ continue;
1347
+
1348
+ // Create a `sameSizeSet` set of all instructions having the exact
1349
+ // explicit memory operand at the same position and registers at
1350
+ // positions matching `regOps` bits and `diffSizeSet` having memory
1351
+ // operand of different size, but registers at the same positions.
1352
+ const sameSizeSet = [aInst];
1353
+ const diffSizeSet = [];
1354
+ const diffSizeHash = Object.create(null);
1355
+
1356
+ for (bIndex = 0; bIndex < this.length; bIndex++) {
1357
+ const bInst = this[bIndex];
1358
+ if (aIndex === bIndex || len !== bInst.length) continue;
1359
+
1360
+ var hasMatch = 1;
1361
+ for (i = 0; i < len; i++) {
1362
+ if (i === memPos) continue;
1363
+
1364
+ const reg = MapUtils.anyOf(bInst[i].flags, RegOp);
1365
+ if (regOps & (1 << i))
1366
+ hasMatch &= reg;
1367
+ else if (reg)
1368
+ hasMatch = 0;
1369
+ }
1370
+
1371
+ if (hasMatch) {
1372
+ const bOp = bInst[memPos];
1373
+ if (bOp.flags.mem) continue;
1374
+
1375
+ const mem = MapUtils.firstOf(bOp.flags, MemOp);
1376
+ if (mem === memOp) {
1377
+ sameSizeSet.push(bInst);
1378
+ }
1379
+ else if (mem) {
1380
+ const key = keyOf(bInst, regOps);
1381
+ diffSizeSet.push(bInst);
1382
+ if (!diffSizeHash[key])
1383
+ diffSizeHash[key] = [bInst];
1384
+ else
1385
+ diffSizeHash[key].push(bInst);
1386
+ }
1387
+ }
1388
+ }
1389
+
1390
+ // Two cases.
1391
+ // A) The memory operand has implicit-size if `diffSizeSet` is empty. That
1392
+ // means that the instruction only uses one size for all reg combinations.
1393
+ //
1394
+ // B) The memory operand has implicit-size if `diffSizeSet` contains different
1395
+ // register signatures than `sameSizeSet`.
1396
+ var implicit = true;
1397
+
1398
+ if (!diffSizeSet.length) {
1399
+ // Case A:
1400
+ }
1401
+ else {
1402
+ // Case B: Find collisions in `sameSizeSet` and `diffSizeSet`.
1403
+ for (bIndex = 0; bIndex < sameSizeSet.length; bIndex++) {
1404
+ const bInst = sameSizeSet[bIndex];
1405
+ const key = keyOf(bInst, regOps);
1406
+
1407
+ const diff = diffSizeHash[key];
1408
+ if (diff) {
1409
+ diff.forEach((diffInst) => {
1410
+ if ((bInst.x86 && !diffInst.x86) || (!bInst.x86 && diffInst.x86)) {
1411
+ // If this is X86|ANY instruction and the other is X64, or vice-versa,
1412
+ // then keep this implicit as it won't do any harm. These instructions
1413
+ // cannot be mixed and it will make implicit the 32-bit one in cases
1414
+ // where X64 introduced 64-bit ones like `cvtsi2ss`.
1415
+ }
1416
+ else {
1417
+ implicit = false;
1418
+ }
1419
+ });
1420
+ }
1421
+ }
1422
+ }
1423
+
1424
+ // Patch all instructions to accept implicit-size memory operand.
1425
+ for (bIndex = 0; bIndex < sameSizeSet.length; bIndex++) {
1426
+ const bInst = sameSizeSet[bIndex];
1427
+ if (implicit)
1428
+ bInst[memPos].flags.mem = true;
1429
+
1430
+ if (!implicit)
1431
+ DEBUG(`${this.name}: Explicit: ${bInst}`);
1432
+ }
1433
+ }
1434
+ }
1435
+
1436
+ compact() {
1437
+ var didSomething = true;
1438
+ while (didSomething) {
1439
+ didSomething = false;
1440
+ for (var i = 0; i < this.length; i++) {
1441
+ var row = this[i];
1442
+ var j = i + 1;
1443
+ while (j < this.length) {
1444
+ if (row.mergeWith(this[j])) {
1445
+ this.splice(j, 1);
1446
+ didSomething = true;
1447
+ continue;
1448
+ }
1449
+ j++;
1450
+ }
1451
+ }
1452
+ }
1453
+ }
1454
+
1455
+ toString() {
1456
+ return `[${this.join(", ")}]`;
1457
+ }
1458
+ }
1459
+
1460
+ class InstSignatureTable extends core.Task {
1461
+ constructor() {
1462
+ super("InstSignatureTable");
1463
+ this.maxOpRows = 0;
1464
+ }
1465
+
1466
+ run() {
1467
+ const insts = this.ctx.insts;
1468
+
1469
+ insts.forEach((inst) => {
1470
+ inst.signatures = this.makeSignatures(Filter.noAltForm(inst.dbInsts));
1471
+ this.maxOpRows = Math.max(this.maxOpRows, inst.signatures.length);
1472
+ });
1473
+
1474
+ const iSignatureMap = Object.create(null);
1475
+ const iSignatureArr = [];
1476
+
1477
+ const oSignatureMap = Object.create(null);
1478
+ const oSignatureArr = [];
1479
+
1480
+ // Must be first to be assigned to zero.
1481
+ const oSignatureNone = "ROW(0, 0xFF)";
1482
+ oSignatureMap[oSignatureNone] = [0];
1483
+ oSignatureArr.push(oSignatureNone);
1484
+
1485
+ function findSignaturesIndex(rows) {
1486
+ const len = rows.length;
1487
+ if (!len) return 0;
1488
+
1489
+ const indexes = iSignatureMap[rows[0].data];
1490
+ if (indexes === undefined) return -1;
1491
+
1492
+ for (var i = 0; i < indexes.length; i++) {
1493
+ const index = indexes[i];
1494
+ if (index + len > iSignatureArr.length) continue;
1495
+
1496
+ var ok = true;
1497
+ for (var j = 0; j < len; j++) {
1498
+ if (iSignatureArr[index + j].data !== rows[j].data) {
1499
+ ok = false;
1500
+ break;
1501
+ }
1502
+ }
1503
+
1504
+ if (ok)
1505
+ return index;
1506
+ }
1507
+
1508
+ return -1;
1509
+ }
1510
+
1511
+ function indexSignatures(signatures) {
1512
+ const result = iSignatureArr.length;
1513
+
1514
+ for (var i = 0; i < signatures.length; i++) {
1515
+ const signature = signatures[i];
1516
+ const idx = iSignatureArr.length;
1517
+
1518
+ if (!hasOwn.call(iSignatureMap, signature.data))
1519
+ iSignatureMap[signature.data] = [];
1520
+
1521
+ iSignatureMap[signature.data].push(idx);
1522
+ iSignatureArr.push(signature);
1523
+ }
1524
+
1525
+ return result;
1526
+ }
1527
+
1528
+ for (var len = this.maxOpRows; len >= 0; len--) {
1529
+ insts.forEach((inst) => {
1530
+ const signatures = inst.signatures;
1531
+ if (signatures.length === len) {
1532
+ const signatureEntries = [];
1533
+ for (var j = 0; j < len; j++) {
1534
+ const signature = signatures[j];
1535
+
1536
+ var signatureEntry = `ROW(${signature.length}, ${signature.x86 ? 1 : 0}, ${signature.x64 ? 1 : 0}, ${signature.implicit}`;
1537
+ var signatureComment = signature.toString();
1538
+
1539
+ var x = 0;
1540
+ while (x < signature.length) {
1541
+ const h = signature[x].toAsmJitOpData();
1542
+ var index = -1;
1543
+ if (!hasOwn.call(oSignatureMap, h)) {
1544
+ index = oSignatureArr.length;
1545
+ oSignatureMap[h] = index;
1546
+ oSignatureArr.push(h);
1547
+ }
1548
+ else {
1549
+ index = oSignatureMap[h];
1550
+ }
1551
+
1552
+ signatureEntry += `, ${String(index).padEnd(3)}`;
1553
+ x++;
1554
+ }
1555
+
1556
+ while (x < 6) {
1557
+ signatureEntry += `, ${String(0).padEnd(3)}`;
1558
+ x++;
1559
+ }
1560
+
1561
+ signatureEntry += `)`;
1562
+ signatureEntries.push({ data: signatureEntry, comment: signatureComment, refs: 0 });
1563
+ }
1564
+
1565
+ var count = signatureEntries.length;
1566
+ var index = findSignaturesIndex(signatureEntries);
1567
+
1568
+ if (index === -1)
1569
+ index = indexSignatures(signatureEntries);
1570
+
1571
+ iSignatureArr[index].refs++;
1572
+ inst.signatureIndex = index;
1573
+ inst.signatureCount = count;
1574
+ }
1575
+ });
1576
+ }
1577
+
1578
+ var s = `#define ROW(count, x86, x64, implicit, o0, o1, o2, o3, o4, o5) \\\n` +
1579
+ ` { count, uint8_t(x86 ? uint8_t(InstDB::Mode::kX86) : uint8_t(0)) | \\\n` +
1580
+ ` (x64 ? uint8_t(InstDB::Mode::kX64) : uint8_t(0)) , \\\n` +
1581
+ ` implicit, \\\n` +
1582
+ ` 0, \\\n` +
1583
+ ` { o0, o1, o2, o3, o4, o5 } \\\n` +
1584
+ ` }\n` +
1585
+ StringUtils.makeCxxArrayWithComment(iSignatureArr, "const InstDB::InstSignature InstDB::_instSignatureTable[]") +
1586
+ `#undef ROW\n` +
1587
+ `\n` +
1588
+ `#define ROW(opFlags, regId) { opFlags, uint8_t(regId) }\n` +
1589
+ `#define F(VAL) uint64_t(InstDB::OpFlags::k##VAL)\n` +
1590
+ StringUtils.makeCxxArray(oSignatureArr, "const InstDB::OpSignature InstDB::_opSignatureTable[]") +
1591
+ `#undef F\n` +
1592
+ `#undef ROW\n`;
1593
+ this.inject("InstSignatureTable", disclaimer(s), oSignatureArr.length * 8 + iSignatureArr.length * 8);
1594
+ }
1595
+
1596
+ makeSignatures(dbInsts) {
1597
+ const signatures = new SignatureArray();
1598
+ for (var i = 0; i < dbInsts.length; i++) {
1599
+ const inst = dbInsts[i];
1600
+ const ops = inst.operands;
1601
+
1602
+ // NOTE: This changed from having reg|mem merged into creating two signatures
1603
+ // instead. Imagine two instructions in one `dbInsts` array:
1604
+ //
1605
+ // 1. mov reg, reg/mem
1606
+ // 2. mov reg/mem, reg
1607
+ //
1608
+ // If we merge them and then unmerge, we will have 4 signatures, when iterated:
1609
+ //
1610
+ // 1a. mov reg, reg
1611
+ // 1b. mov reg, mem
1612
+ // 2a. mov reg, reg
1613
+ // 2b. mov mem, reg
1614
+ //
1615
+ // So, instead of merging them here, we insert separated signatures and let
1616
+ // the tool merge them in a way that can be easily unmerged at runtime into:
1617
+ //
1618
+ // 1a. mov reg, reg
1619
+ // 1b. mov reg, mem
1620
+ // 2b. mov mem, reg
1621
+ var modrmCount = 1;
1622
+ for (var modrm = 0; modrm < modrmCount; modrm++) {
1623
+ var row = new ISignature(inst.name);
1624
+ row.x86 = (inst.arch === "ANY" || inst.arch === "X86");
1625
+ row.x64 = (inst.arch === "ANY" || inst.arch === "X64");
1626
+
1627
+ for (var j = 0; j < ops.length; j++) {
1628
+ var iop = ops[j];
1629
+
1630
+ var reg = iop.reg;
1631
+ var mem = iop.mem;
1632
+ var imm = iop.imm;
1633
+ var rel = iop.rel;
1634
+
1635
+ // Skip all instructions having implicit `imm` operand of `1`.
1636
+ if (iop.immValue !== null)
1637
+ break;
1638
+
1639
+ // Shorten the number of signatures of 'mov' instruction.
1640
+ if (inst.name === "mov" && mem.startsWith("moff"))
1641
+ break;
1642
+
1643
+ if (reg === "seg") reg = "sreg";
1644
+ if (reg === "st(i)") reg = "st";
1645
+ if (reg === "st(0)") reg = "st0";
1646
+
1647
+ if (mem === "moff8") mem = "m8";
1648
+ if (mem === "moff16") mem = "m16";
1649
+ if (mem === "moff32") mem = "m32";
1650
+ if (mem === "moff64") mem = "m64";
1651
+
1652
+ if (mem === "m32fp") mem = "m32";
1653
+ if (mem === "m64fp") mem = "m64";
1654
+ if (mem === "m80fp") mem = "m80";
1655
+ if (mem === "m80bcd") mem = "m80";
1656
+ if (mem === "m80dec") mem = "m80";
1657
+ if (mem === "m16int") mem = "m16";
1658
+ if (mem === "m32int") mem = "m32";
1659
+ if (mem === "m64int") mem = "m64";
1660
+
1661
+ if (mem === "m16_16") mem = "m32";
1662
+ if (mem === "m16_32") mem = "m48";
1663
+ if (mem === "m16_64") mem = "m80";
1664
+
1665
+ if (reg && mem) {
1666
+ if (modrmCount === 1) {
1667
+ mem = null;
1668
+ modrmCount++;
1669
+ }
1670
+ else {
1671
+ reg = null;
1672
+ }
1673
+ }
1674
+
1675
+ const op = new OSignature();
1676
+ if (iop.implicit) {
1677
+ row.implicit++;
1678
+ op.flags.implicit = true;
1679
+ }
1680
+
1681
+ const seg = iop.memSeg;
1682
+ if (seg) {
1683
+ switch (inst.name) {
1684
+ case "cmpsb": op.flags.m8 = true; break;
1685
+ case "cmpsw": op.flags.m16 = true; break;
1686
+ case "cmpsd": op.flags.m32 = true; break;
1687
+ case "cmpsq": op.flags.m64 = true; break;
1688
+ case "lodsb": op.flags.m8 = true; break;
1689
+ case "lodsw": op.flags.m16 = true; break;
1690
+ case "lodsd": op.flags.m32 = true; break;
1691
+ case "lodsq": op.flags.m64 = true; break;
1692
+ case "movsb": op.flags.m8 = true; break;
1693
+ case "movsw": op.flags.m16 = true; break;
1694
+ case "movsd": op.flags.m32 = true; break;
1695
+ case "movsq": op.flags.m64 = true; break;
1696
+ case "scasb": op.flags.m8 = true; break;
1697
+ case "scasw": op.flags.m16 = true; break;
1698
+ case "scasd": op.flags.m32 = true; break;
1699
+ case "scasq": op.flags.m64 = true; break;
1700
+ case "stosb": op.flags.m8 = true; break;
1701
+ case "stosw": op.flags.m16 = true; break;
1702
+ case "stosd": op.flags.m32 = true; break;
1703
+ case "stosq": op.flags.m64 = true; break;
1704
+ case "insb": op.flags.m8 = true; break;
1705
+ case "insw": op.flags.m16 = true; break;
1706
+ case "insd": op.flags.m32 = true; break;
1707
+ case "outsb": op.flags.m8 = true; break;
1708
+ case "outsw": op.flags.m16 = true; break;
1709
+ case "outsd": op.flags.m32 = true; break;
1710
+ case "clzero": op.flags.mem = true; op.flags.m512 = true; break;
1711
+ case "enqcmd": op.flags.mem = true; op.flags.m512 = true; break;
1712
+ case "enqcmds": op.flags.mem = true; op.flags.m512 = true; break;
1713
+ case "movdir64b": op.flags.mem = true; op.flags.m512 = true; break;
1714
+ case "maskmovq": op.flags.mem = true; op.flags.m64 = true; break;
1715
+ case "maskmovdqu": op.flags.mem = true; op.flags.m128 = true; break;
1716
+ case "vmaskmovdqu": op.flags.mem = true; op.flags.m128 = true; break;
1717
+ case "monitor": op.flags.mem = true; break;
1718
+ case "monitorx": op.flags.mem = true; break;
1719
+ case "umonitor": op.flags.mem = true; break;
1720
+ default: console.log(`UNKNOWN MEM IN INSTRUCTION '${inst.name}'`); break;
1721
+ }
1722
+
1723
+ if (seg === "ds") op.flags.memDS = true;
1724
+ if (seg === "es") op.flags.memES = true;
1725
+ if (reg === "reg") { op.flags.memBase = true; }
1726
+ if (reg === "r32") { op.flags.memBase = true; }
1727
+ if (reg === "r64") { op.flags.memBase = true; }
1728
+ if (reg === "zax") { op.flags.memBase = true; op.flags.memZAX = true; }
1729
+ if (reg === "zsi") { op.flags.memBase = true; op.flags.memZSI = true; }
1730
+ if (reg === "zdi") { op.flags.memBase = true; op.flags.memZDI = true; }
1731
+ }
1732
+ else if (reg) {
1733
+ if (reg == "r8") {
1734
+ op.flags["r8lo"] = true;
1735
+ op.flags["r8hi"] = true;
1736
+ }
1737
+ else {
1738
+ op.flags[reg] = true;
1739
+ }
1740
+ }
1741
+ if (mem) {
1742
+ op.flags[mem] = true;
1743
+ // HACK: Allow LEA|CL*|PREFETCH* to use any memory size.
1744
+ if (/^(cldemote|clwb|clflush\w*|lea|prefetch\w*)$/.test(inst.name)) {
1745
+ op.flags.mem = true;
1746
+ Object.assign(op.flags, MemOp);
1747
+ }
1748
+
1749
+ // HACK: These instructions specify explicit memory size, but it's just informational.
1750
+ if (inst.name === "enqcmd" || inst.name === "enqcmds" || inst.name === "movdir64b")
1751
+ op.flags.mem = true;
1752
+
1753
+ }
1754
+ if (imm) {
1755
+ if (iop.immSign === "any" || iop.immSign === "signed" ) op.flags["i" + imm] = true;
1756
+ if (iop.immSign === "any" || iop.immSign === "unsigned") op.flags["u" + imm] = true;
1757
+ }
1758
+ if (rel) op.flags["rel" + rel] = true;
1759
+
1760
+ row.push(op);
1761
+ }
1762
+
1763
+ // Not equal if we terminated the loop.
1764
+ if (j === ops.length)
1765
+ signatures.push(row);
1766
+ }
1767
+ }
1768
+
1769
+ if (signatures.length && GenUtils.canUseImplicitMemSize(dbInsts[0].name))
1770
+ signatures.calcImplicitMemSize();
1771
+
1772
+ signatures.compact();
1773
+ return signatures;
1774
+ }
1775
+ }
1776
+
1777
+ // ============================================================================
1778
+ // [tablegen.x86.AdditionalInfoTable]
1779
+ // ============================================================================
1780
+
1781
+ class AdditionalInfoTable extends core.Task {
1782
+ constructor() {
1783
+ super("AdditionalInfoTable");
1784
+ }
1785
+
1786
+ run() {
1787
+ const insts = this.ctx.insts;
1788
+ const rwInfoTable = new IndexedArray();
1789
+ const instFlagsTable = new IndexedArray();
1790
+ const additionaInfoTable = new IndexedArray();
1791
+
1792
+ // If the instruction doesn't read any flags it should point to the first index.
1793
+ rwInfoTable.addIndexed(`{ 0, 0 }`);
1794
+
1795
+ insts.forEach((inst) => {
1796
+ const dbInsts = inst.dbInsts;
1797
+
1798
+ var features = GenUtils.cpuFeaturesOf(dbInsts).map(function(f) { return `EXT(${f})`; }).join(", ");
1799
+ if (!features) features = "0";
1800
+
1801
+ var [r, w] = this.rwFlagsOf(dbInsts);
1802
+ const rData = r.map(function(flag) { return `FLAG(${flag})`; }).join(" | ") || "0";
1803
+ const wData = w.map(function(flag) { return `FLAG(${flag})`; }).join(" | ") || "0";
1804
+ const instFlags = Object.create(null);
1805
+
1806
+ switch (inst.name) {
1807
+ case "kmovb":
1808
+ case "kmovd":
1809
+ case "kmovq":
1810
+ case "kmovw":
1811
+ case "mov":
1812
+ case "movq":
1813
+ case "movsd":
1814
+ case "movss":
1815
+ case "movapd":
1816
+ case "movaps":
1817
+ case "movdqa":
1818
+ case "movdqu":
1819
+ case "movupd":
1820
+ case "movups":
1821
+ case "vmovapd":
1822
+ case "vmovaps":
1823
+ case "vmovdqa":
1824
+ case "vmovdqa8":
1825
+ case "vmovdqa16":
1826
+ case "vmovdqa32":
1827
+ case "vmovdqa64":
1828
+ case "vmovdqu":
1829
+ case "vmovdqu8":
1830
+ case "vmovdqu16":
1831
+ case "vmovdqu32":
1832
+ case "vmovdqu64":
1833
+ case "vmovq":
1834
+ case "vmovsd":
1835
+ case "vmovss":
1836
+ case "vmovupd":
1837
+ case "vmovups":
1838
+ instFlags["MovOp"] = true;
1839
+ break;
1840
+ }
1841
+
1842
+ const instFlagsIndex = instFlagsTable.addIndexed("InstRWFlags(" + CxxUtils.flags(instFlags, (f) => { return `FLAG(${f})`; }, "FLAG(None)") + ")");
1843
+ const rwInfoIndex = rwInfoTable.addIndexed(`{ ${rData}, ${wData} }`);
1844
+
1845
+ inst.additionalInfoIndex = additionaInfoTable.addIndexed(`{ ${instFlagsIndex}, ${rwInfoIndex}, { ${features} } }`);
1846
+ });
1847
+
1848
+ var s = `#define EXT(VAL) uint32_t(CpuFeatures::X86::k##VAL)\n` +
1849
+ `const InstDB::AdditionalInfo InstDB::_additionalInfoTable[] = {\n${StringUtils.format(additionaInfoTable, kIndent, true)}\n};\n` +
1850
+ `#undef EXT\n` +
1851
+ `\n` +
1852
+ `#define FLAG(VAL) uint32_t(CpuRWFlags::kX86_##VAL)\n` +
1853
+ `const InstDB::RWFlagsInfoTable InstDB::_rwFlagsInfoTable[] = {\n${StringUtils.format(rwInfoTable, kIndent, true)}\n};\n` +
1854
+ `#undef FLAG\n` +
1855
+ `\n` +
1856
+ `#define FLAG(VAL) uint32_t(InstRWFlags::k##VAL)\n` +
1857
+ `const InstRWFlags InstDB::_instFlagsTable[] = {\n${StringUtils.format(instFlagsTable, kIndent, true)}\n};\n` +
1858
+ `#undef FLAG\n`;
1859
+ this.inject("AdditionalInfoTable", disclaimer(s), additionaInfoTable.length * 8 + rwInfoTable.length * 8 + instFlagsTable.length * 4);
1860
+ }
1861
+
1862
+ rwFlagsOf(dbInsts) {
1863
+ const r = Object.create(null);
1864
+ const w = Object.create(null);
1865
+
1866
+ for (var i = 0; i < dbInsts.length; i++) {
1867
+ const dbInst = dbInsts[i];
1868
+
1869
+ // Omit special cases, this is handled well in C++ code.
1870
+ if (dbInst.name === "mov")
1871
+ continue;
1872
+
1873
+ const specialRegs = dbInst.specialRegs;
1874
+
1875
+ // Mov is a special case, moving to/from control regs makes flags undefined,
1876
+ // which we don't want to have in `X86InstDB::operationData`. This is, thus,
1877
+ // a special case instruction analyzer must deal with.
1878
+ if (dbInst.name === "mov")
1879
+ continue;
1880
+
1881
+ for (var specialReg in specialRegs) {
1882
+ var flag = "";
1883
+ switch (specialReg) {
1884
+ case "FLAGS.CF": flag = "CF"; break;
1885
+ case "FLAGS.OF": flag = "OF"; break;
1886
+ case "FLAGS.SF": flag = "SF"; break;
1887
+ case "FLAGS.ZF": flag = "ZF"; break;
1888
+ case "FLAGS.AF": flag = "AF"; break;
1889
+ case "FLAGS.PF": flag = "PF"; break;
1890
+ case "FLAGS.DF": flag = "DF"; break;
1891
+ case "FLAGS.IF": flag = "IF"; break;
1892
+ //case "FLAGS.TF": flag = "TF"; break;
1893
+ case "FLAGS.AC": flag = "AC"; break;
1894
+ case "X86SW.C0": flag = "C0"; break;
1895
+ case "X86SW.C1": flag = "C1"; break;
1896
+ case "X86SW.C2": flag = "C2"; break;
1897
+ case "X86SW.C3": flag = "C3"; break;
1898
+ default:
1899
+ continue;
1900
+ }
1901
+
1902
+ switch (specialRegs[specialReg]) {
1903
+ case "R":
1904
+ r[flag] = true;
1905
+ break;
1906
+ case "X":
1907
+ r[flag] = true;
1908
+ // ... fallthrough ...
1909
+ case "W":
1910
+ case "U":
1911
+ case "0":
1912
+ case "1":
1913
+ w[flag] = true;
1914
+ break;
1915
+ }
1916
+ }
1917
+ }
1918
+
1919
+ return [ArrayUtils.sorted(r), ArrayUtils.sorted(w)];
1920
+ }
1921
+ }
1922
+
1923
+ // ============================================================================
1924
+ // [tablegen.x86.InstRWInfoTable]
1925
+ // ============================================================================
1926
+
1927
+ const NOT_MEM_AMBIGUOUS = MapUtils.arrayToMap([
1928
+ "call", "movq"
1929
+ ]);
1930
+
1931
+ class InstRWInfoTable extends core.Task {
1932
+ constructor() {
1933
+ super("InstRWInfoTable");
1934
+
1935
+ this.rwInfoIndexA = [];
1936
+ this.rwInfoIndexB = [];
1937
+ this.rwInfoTableA = new IndexedArray();
1938
+ this.rwInfoTableB = new IndexedArray();
1939
+
1940
+ this.rmInfoTable = new IndexedArray();
1941
+ this.opInfoTable = new IndexedArray();
1942
+
1943
+ this.rwCategoryByName = {
1944
+ "imul" : "Imul",
1945
+ "mov" : "Mov",
1946
+ "movabs" : "Movabs",
1947
+ "movhpd" : "Movh64",
1948
+ "movhps" : "Movh64",
1949
+ "punpcklbw" : "Punpcklxx",
1950
+ "punpckldq" : "Punpcklxx",
1951
+ "punpcklwd" : "Punpcklxx",
1952
+ "vmaskmovpd": "Vmaskmov",
1953
+ "vmaskmovps": "Vmaskmov",
1954
+ "vmovddup" : "Vmovddup",
1955
+ "vmovmskpd" : "Vmovmskpd",
1956
+ "vmovmskps" : "Vmovmskps",
1957
+ "vpmaskmovd": "Vmaskmov",
1958
+ "vpmaskmovq": "Vmaskmov"
1959
+ };
1960
+
1961
+ const _ = null;
1962
+ this.rwCategoryByData = {
1963
+ Vmov1_8: [
1964
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 8}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_],
1965
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 16}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:128},_,_,_,_],
1966
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 32}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:256},_,_,_,_],
1967
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:512},_,_,_,_]
1968
+ ],
1969
+ Vmov1_4: [
1970
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 32}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:128},_,_,_,_],
1971
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:256},_,_,_,_],
1972
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width:128}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:512},_,_,_,_]
1973
+ ],
1974
+ Vmov1_2: [
1975
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:128},_,_,_,_],
1976
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width:128}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:256},_,_,_,_],
1977
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width:256}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:512},_,_,_,_]
1978
+ ],
1979
+ Vmov2_1: [
1980
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_],
1981
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:128},_,_,_,_],
1982
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:256},_,_,_,_]
1983
+ ],
1984
+ Vmov4_1: [
1985
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 32},_,_,_,_],
1986
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_],
1987
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:128},_,_,_,_]
1988
+ ],
1989
+ Vmov8_1: [
1990
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 16},_,_,_,_],
1991
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 32},_,_,_,_],
1992
+ [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_]
1993
+ ]
1994
+ };
1995
+ }
1996
+
1997
+ run() {
1998
+ const insts = this.ctx.insts;
1999
+
2000
+ const noRmInfo = CxxUtils.struct(
2001
+ "InstDB::RWInfoRm::kCategory" + "None".padEnd(10),
2002
+ StringUtils.decToHex(0, 2),
2003
+ String(0).padEnd(2),
2004
+ CxxUtils.flags({}),
2005
+ "0"
2006
+ );
2007
+
2008
+ const noOpInfo = CxxUtils.struct(
2009
+ "0x0000000000000000u",
2010
+ "0x0000000000000000u",
2011
+ "0xFF",
2012
+ "0",
2013
+ CxxUtils.struct(0),
2014
+ "OpRWFlags::kNone"
2015
+ );
2016
+
2017
+ this.rmInfoTable.addIndexed(noRmInfo);
2018
+ this.opInfoTable.addIndexed(noOpInfo);
2019
+
2020
+ insts.forEach((inst) => {
2021
+ // Alternate forms would only mess this up, so filter them out.
2022
+ const dbInsts = Filter.noAltForm(inst.dbInsts);
2023
+
2024
+ // The best we can do is to divide instructions that have 2 operands and others.
2025
+ // This gives us the highest chance of preventing special cases (which were not
2026
+ // entirely avoided).
2027
+ const o2Insts = dbInsts.filter((inst) => { return inst.operands.length === 2; });
2028
+ const oxInsts = dbInsts.filter((inst) => { return inst.operands.length !== 2; });
2029
+
2030
+ const rwInfoArray = [this.rwInfo(inst, o2Insts), this.rwInfo(inst, oxInsts)];
2031
+ const rmInfoArray = [this.rmInfo(inst, o2Insts), this.rmInfo(inst, oxInsts)];
2032
+
2033
+ for (var i = 0; i < 2; i++) {
2034
+ const rwInfo = rwInfoArray[i];
2035
+ const rmInfo = rmInfoArray[i];
2036
+
2037
+ const rwOps = rwInfo.rwOps;
2038
+ const rwOpsIndex = [];
2039
+ for (var j = 0; j < rwOps.length; j++) {
2040
+ const op = rwOps[j];
2041
+ if (!op) {
2042
+ rwOpsIndex.push(this.opInfoTable.addIndexed(noOpInfo));
2043
+ continue;
2044
+ }
2045
+
2046
+ const flags = {};
2047
+ const opAcc = op.access;
2048
+
2049
+ if (opAcc === "R") flags.Read = true;
2050
+ if (opAcc === "W") flags.Write = true;
2051
+ if (opAcc === "X") flags.RW = true;
2052
+ Lang.merge(flags, op.flags);
2053
+
2054
+ const rIndex = opAcc === "X" || opAcc === "R" ? op.index : -1;
2055
+ const rWidth = opAcc === "X" || opAcc === "R" ? op.width : -1;
2056
+ const wIndex = opAcc === "X" || opAcc === "W" ? op.index : -1;
2057
+ const wWidth = opAcc === "X" || opAcc === "W" ? op.width : -1;
2058
+
2059
+ const consecutiveLeadCount = op.clc;
2060
+
2061
+ const opData = CxxUtils.struct(
2062
+ this.byteMaskFromBitRanges([{ start: rIndex, end: rIndex + rWidth - 1 }]) + "u",
2063
+ this.byteMaskFromBitRanges([{ start: wIndex, end: wIndex + wWidth - 1 }]) + "u",
2064
+ StringUtils.decToHex(op.fixed === -1 ? 0xFF : op.fixed, 2),
2065
+ String(consecutiveLeadCount),
2066
+ CxxUtils.struct(0),
2067
+ CxxUtils.flags(flags, function(flag) { return "OpRWFlags::k" + flag; }, "OpRWFlags::kNone")
2068
+ );
2069
+
2070
+ rwOpsIndex.push(this.opInfoTable.addIndexed(opData));
2071
+ }
2072
+
2073
+ const rmData = CxxUtils.struct(
2074
+ "InstDB::RWInfoRm::kCategory" + rmInfo.category.padEnd(10),
2075
+ StringUtils.decToHex(rmInfo.rmIndexes, 2),
2076
+ String(Math.max(rmInfo.memFixed, 0)).padEnd(2),
2077
+ CxxUtils.flags({
2078
+ "InstDB::RWInfoRm::kFlagAmbiguous": Boolean(rmInfo.memAmbiguous),
2079
+ "InstDB::RWInfoRm::kFlagMovssMovsd": Boolean(inst.name === "movss" || inst.name === "movsd"),
2080
+ "InstDB::RWInfoRm::kFlagPextrw": Boolean(inst.name === "pextrw"),
2081
+ "InstDB::RWInfoRm::kFlagFeatureIfRMI": Boolean(rmInfo.memExtensionIfRMI)
2082
+ }),
2083
+ rmInfo.memExtension === "None" ? "0" : "uint32_t(CpuFeatures::X86::k" + rmInfo.memExtension + ")"
2084
+ );
2085
+
2086
+ const rwData = CxxUtils.struct(
2087
+ "InstDB::RWInfo::kCategory" + rwInfo.category.padEnd(10),
2088
+ String(this.rmInfoTable.addIndexed(rmData)).padEnd(2),
2089
+ CxxUtils.struct(...(rwOpsIndex.map(function(item) { return String(item).padEnd(2); })))
2090
+ );
2091
+
2092
+ if (i == 0)
2093
+ this.rwInfoIndexA.push(this.rwInfoTableA.addIndexed(rwData));
2094
+ else
2095
+ this.rwInfoIndexB.push(this.rwInfoTableB.addIndexed(rwData));
2096
+ }
2097
+ });
2098
+
2099
+ var s = "";
2100
+ s += "const uint8_t InstDB::rwInfoIndexA[Inst::_kIdCount] = {\n" + StringUtils.format(this.rwInfoIndexA, kIndent, -1) + "\n};\n";
2101
+ s += "\n";
2102
+ s += "const uint8_t InstDB::rwInfoIndexB[Inst::_kIdCount] = {\n" + StringUtils.format(this.rwInfoIndexB, kIndent, -1) + "\n};\n";
2103
+ s += "\n";
2104
+ s += "const InstDB::RWInfo InstDB::rwInfoA[] = {\n" + StringUtils.format(this.rwInfoTableA, kIndent, true) + "\n};\n";
2105
+ s += "\n";
2106
+ s += "const InstDB::RWInfo InstDB::rwInfoB[] = {\n" + StringUtils.format(this.rwInfoTableB, kIndent, true) + "\n};\n";
2107
+ s += "\n";
2108
+ s += "const InstDB::RWInfoOp InstDB::rwInfoOp[] = {\n" + StringUtils.format(this.opInfoTable, kIndent, true) + "\n};\n";
2109
+ s += "\n";
2110
+ s += "const InstDB::RWInfoRm InstDB::rwInfoRm[] = {\n" + StringUtils.format(this.rmInfoTable, kIndent, true) + "\n};\n";
2111
+
2112
+ const size = this.rwInfoIndexA.length +
2113
+ this.rwInfoIndexB.length +
2114
+ this.rwInfoTableA.length * 8 +
2115
+ this.rwInfoTableB.length * 8 +
2116
+ this.rmInfoTable.length * 4 +
2117
+ this.opInfoTable.length * 24;
2118
+
2119
+ this.inject("InstRWInfoTable", disclaimer(s), size);
2120
+ }
2121
+
2122
+ byteMaskFromBitRanges(ranges) {
2123
+ const arr = [];
2124
+ for (var i = 0; i < 64; i++)
2125
+ arr.push(0);
2126
+
2127
+ for (var i = 0; i < ranges.length; i++) {
2128
+ const start = ranges[i].start;
2129
+ const end = ranges[i].end;
2130
+
2131
+ if (start < 0)
2132
+ continue;
2133
+
2134
+ for (var j = start; j <= end; j++) {
2135
+ const bytePos = j >> 3;
2136
+ if (bytePos < 0 || bytePos >= arr.length)
2137
+ FAIL(`Range ${start}:${end} cannot be used to create a byte-mask`);
2138
+ arr[bytePos] = 1;
2139
+ }
2140
+ }
2141
+
2142
+ var s = "0x";
2143
+ for (var i = arr.length - 4; i >= 0; i -= 4) {
2144
+ const value = (arr[i + 3] << 3) | (arr[i + 2] << 2) | (arr[i + 1] << 1) | arr[i];
2145
+ s += value.toString(16).toUpperCase();
2146
+ }
2147
+ return s;
2148
+ }
2149
+
2150
+ // Read/Write Info
2151
+ // ---------------
2152
+
2153
+ rwInfo(asmInst, dbInsts) {
2154
+ const self = this;
2155
+
2156
+ function nullOps() {
2157
+ return [null, null, null, null, null, null];
2158
+ }
2159
+
2160
+ function makeRwFromOp(op) {
2161
+ if (!op.isRegOrMem())
2162
+ return null;
2163
+
2164
+ return {
2165
+ access: op.read && op.write ? "X" : op.read ? "R" : op.write ? "W" : "?",
2166
+ clc: 0,
2167
+ flags: {},
2168
+ fixed: GenUtils.fixedRegOf(op.reg),
2169
+ index: op.rwxIndex,
2170
+ width: op.rwxWidth
2171
+ };
2172
+ }
2173
+
2174
+ function queryRwGeneric(dbInsts, step) {
2175
+ var rwOps = nullOps();
2176
+ for (var i = 0; i < dbInsts.length; i++) {
2177
+ const dbInst = dbInsts[i];
2178
+ const operands = dbInst.operands;
2179
+
2180
+ for (var j = 0; j < operands.length; j++) {
2181
+ const op = operands[j];
2182
+ if (!op.isRegOrMem())
2183
+ continue;
2184
+
2185
+ const opSize = op.isReg() ? op.regSize : op.memSize;
2186
+ var d = {
2187
+ access: op.read && op.write ? "X" : op.read ? "R" : op.write ? "W" : "?",
2188
+ clc: 0,
2189
+ flags: {},
2190
+ fixed: -1,
2191
+ index: -1,
2192
+ width: -1
2193
+ };
2194
+
2195
+ if (op.consecutiveLeadCount)
2196
+ d.clc = op.consecutiveLeadCount;
2197
+
2198
+ if (op.isReg())
2199
+ d.fixed = GenUtils.fixedRegOf(op.reg);
2200
+ else
2201
+ d.fixed = GenUtils.fixedRegOf(op.mem);
2202
+
2203
+ if (op.zext)
2204
+ d.flags.ZExt = true;
2205
+
2206
+ if (op.regIndexRel)
2207
+ d.flags.Consecutive = true;
2208
+
2209
+ for (var k in self.rwOpFlagsForInstruction(asmInst.name, j))
2210
+ d.flags[k] = true;
2211
+
2212
+ if ((step === -1 || step === j) || op.rwxIndex !== 0 || op.rwxWidth !== opSize) {
2213
+ d.index = op.rwxIndex;
2214
+ d.width = op.rwxWidth;
2215
+ }
2216
+
2217
+ if (d.fixed !== -1) {
2218
+ if (op.memSeg)
2219
+ d.flags.MemPhysId = true;
2220
+ else
2221
+ d.flags.RegPhysId = true;
2222
+ }
2223
+
2224
+ if (rwOps[j] === null) {
2225
+ rwOps[j] = d;
2226
+ }
2227
+ else {
2228
+ if (!Lang.deepEqExcept(rwOps[j], d, { "fixed": true, "flags": true }))
2229
+ return null;
2230
+
2231
+ if (rwOps[j].fixed === -1)
2232
+ rwOps[j].fixed = d.fixed;
2233
+ Lang.merge(rwOps[j].flags, d.flags);
2234
+ }
2235
+ }
2236
+ }
2237
+ return { category: "Generic", rwOps };
2238
+ }
2239
+
2240
+ function queryRwByData(dbInsts, rwOpsArray) {
2241
+ for (var i = 0; i < dbInsts.length; i++) {
2242
+ const dbInst = dbInsts[i];
2243
+ const operands = dbInst.operands;
2244
+ const rwOps = nullOps();
2245
+
2246
+ for (var j = 0; j < operands.length; j++)
2247
+ rwOps[j] = makeRwFromOp(operands[j])
2248
+
2249
+ var match = 0;
2250
+ for (var j = 0; j < rwOpsArray.length; j++)
2251
+ match |= Lang.deepEq(rwOps, rwOpsArray[j]);
2252
+
2253
+ if (!match)
2254
+ return false;
2255
+ }
2256
+
2257
+ return true;
2258
+ }
2259
+
2260
+ function dumpRwToData(dbInsts) {
2261
+ const out = [];
2262
+ for (var i = 0; i < dbInsts.length; i++) {
2263
+ const dbInst = dbInsts[i];
2264
+ const operands = dbInst.operands;
2265
+ const rwOps = nullOps();
2266
+
2267
+ for (var j = 0; j < operands.length; j++)
2268
+ rwOps[j] = makeRwFromOp(operands[j])
2269
+
2270
+ if (ArrayUtils.deepIndexOf(out, rwOps) !== -1)
2271
+ continue;
2272
+
2273
+ out.push(rwOps);
2274
+ }
2275
+ return out;
2276
+ }
2277
+
2278
+ // Some instructions are just special...
2279
+ const name = dbInsts.length ? dbInsts[0].name : "";
2280
+ if (name in this.rwCategoryByName)
2281
+ return { category: this.rwCategoryByName[name], rwOps: nullOps() };
2282
+
2283
+ // Generic rules.
2284
+ for (var i = -1; i <= 6; i++) {
2285
+ const rwInfo = queryRwGeneric(dbInsts, i);
2286
+ if (rwInfo)
2287
+ return rwInfo;
2288
+ }
2289
+
2290
+ // Specific rules.
2291
+ for (var k in this.rwCategoryByData)
2292
+ if (queryRwByData(dbInsts, this.rwCategoryByData[k]))
2293
+ return { category: k, rwOps: nullOps() };
2294
+
2295
+ // FAILURE: Missing data to categorize this instruction.
2296
+ if (name) {
2297
+ const items = dumpRwToData(dbInsts)
2298
+ console.log(`RW: ${dbInsts.length ? dbInsts[0].name : ""}:`);
2299
+ items.forEach((item) => {
2300
+ console.log(" " + JSON.stringify(item));
2301
+ });
2302
+ }
2303
+
2304
+ return null;
2305
+ }
2306
+
2307
+ rwOpFlagsForInstruction(instName, opIndex) {
2308
+ const toMap = MapUtils.arrayToMap;
2309
+
2310
+ // TODO: We should be able to get this information from asmdb.
2311
+ switch (instName + "@" + opIndex) {
2312
+ case "cmps@0": return toMap(['MemBaseRW', 'MemBasePostModify']);
2313
+ case "cmps@1": return toMap(['MemBaseRW', 'MemBasePostModify']);
2314
+ case "movs@0": return toMap(['MemBaseRW', 'MemBasePostModify']);
2315
+ case "movs@1": return toMap(['MemBaseRW', 'MemBasePostModify']);
2316
+ case "lods@1": return toMap(['MemBaseRW', 'MemBasePostModify']);
2317
+ case "stos@0": return toMap(['MemBaseRW', 'MemBasePostModify']);
2318
+ case "scas@1": return toMap(['MemBaseRW', 'MemBasePostModify']);
2319
+ case "bndstx@0": return toMap(['MemBaseWrite', 'MemIndexWrite']);
2320
+
2321
+ default:
2322
+ return {};
2323
+ }
2324
+ }
2325
+
2326
+ // Reg/Mem Info
2327
+ // ------------
2328
+
2329
+ rmInfo(asmInst, dbInsts) {
2330
+ const info = {
2331
+ category: "None",
2332
+ rmIndexes: this.rmReplaceableIndexes(dbInsts),
2333
+ memFixed: this.rmFixedSize(dbInsts),
2334
+ memAmbiguous: this.rmIsAmbiguous(dbInsts),
2335
+ memConsistent: this.rmIsConsistent(dbInsts),
2336
+ memExtension: this.rmExtension(dbInsts),
2337
+ memExtensionIfRMI: this.rmExtensionIfRMI(dbInsts)
2338
+ };
2339
+
2340
+ if (info.memFixed !== -1)
2341
+ info.category = "Fixed";
2342
+ else if (info.memConsistent)
2343
+ info.category = "Consistent";
2344
+ else if (info.rmIndexes)
2345
+ info.category = this.rmReplaceableCategory(dbInsts);
2346
+
2347
+ return info;
2348
+ }
2349
+
2350
+ rmReplaceableCategory(dbInsts) {
2351
+ var category = null;
2352
+
2353
+ for (var i = 0; i < dbInsts.length; i++) {
2354
+ const dbInst = dbInsts[i];
2355
+ const operands = dbInst.operands;
2356
+
2357
+ var rs = -1;
2358
+ var ms = -1;
2359
+
2360
+ for (var j = 0; j < operands.length; j++) {
2361
+ const op = operands[j];
2362
+ if (op.isMem())
2363
+ ms = op.memSize;
2364
+ else if (op.isReg())
2365
+ rs = Math.max(rs, op.regSize);
2366
+ }
2367
+
2368
+ var c = (rs === -1 ) ? "None" :
2369
+ (ms === -1 ) ? "None" :
2370
+ (ms === rs ) ? "Fixed" :
2371
+ (ms === rs / 2) ? "Half" :
2372
+ (ms === rs / 4) ? "Quarter" :
2373
+ (ms === rs / 8) ? "Eighth" : "Unknown";
2374
+
2375
+ if (category === null)
2376
+ category = c;
2377
+ else if (category !== c) {
2378
+ // Special cases.
2379
+ if (dbInst.name === "mov" || dbInst.name === "vmovddup")
2380
+ return "None";
2381
+
2382
+ if (/^(punpcklbw|punpckldq|punpcklwd)$/.test(dbInst.name))
2383
+ return "None";
2384
+
2385
+ return StringUtils.capitalize(dbInst.name);
2386
+ }
2387
+ }
2388
+
2389
+ if (category === "Unknown")
2390
+ console.log(`Instruction '${dbInsts[0].name}' has no RMInfo category.`);
2391
+
2392
+ return category || "Unknown";
2393
+ }
2394
+
2395
+ rmReplaceableIndexes(dbInsts) {
2396
+ function maskOf(inst, fn) {
2397
+ var m = 0;
2398
+ var operands = inst.operands;
2399
+ for (var i = 0; i < operands.length; i++)
2400
+ if (fn(operands[i]))
2401
+ m |= (1 << i);
2402
+ return m;
2403
+ }
2404
+
2405
+ function getRegIndexes(inst) { return maskOf(inst, function(op) { return op.isReg(); }); };
2406
+ function getMemIndexes(inst) { return maskOf(inst, function(op) { return op.isMem(); }); };
2407
+
2408
+ var mask = 0;
2409
+
2410
+ for (var i = 0; i < dbInsts.length; i++) {
2411
+ const dbInst = dbInsts[i];
2412
+
2413
+ var mi = getMemIndexes(dbInst);
2414
+ var ri = getRegIndexes(dbInst) & ~mi;
2415
+
2416
+ if (!mi)
2417
+ continue;
2418
+
2419
+ const match = dbInsts.some((inst) => {
2420
+ var ti = getRegIndexes(inst);
2421
+ return ((ri & ti) === ri && (mi & ti) === mi);
2422
+ });
2423
+
2424
+ if (!match)
2425
+ return 0;
2426
+ mask |= mi;
2427
+ }
2428
+
2429
+ return mask;
2430
+ }
2431
+
2432
+ rmFixedSize(insts) {
2433
+ var savedOp = null;
2434
+
2435
+ for (var i = 0; i < insts.length; i++) {
2436
+ const inst = insts[i];
2437
+ const operands = inst.operands;
2438
+
2439
+ for (var j = 0; j < operands.length; j++) {
2440
+ const op = operands[j];
2441
+ if (op.mem) {
2442
+ if (savedOp && savedOp.mem !== op.mem)
2443
+ return -1;
2444
+ savedOp = op;
2445
+ }
2446
+ }
2447
+ }
2448
+
2449
+ return savedOp ? Math.max(savedOp.memSize, 0) / 8 : -1;
2450
+ }
2451
+
2452
+ rmIsConsistent(insts) {
2453
+ var hasMem = 0;
2454
+ for (var i = 0; i < insts.length; i++) {
2455
+ const inst = insts[i];
2456
+ const operands = inst.operands;
2457
+ for (var j = 0; j < operands.length; j++) {
2458
+ const op = operands[j];
2459
+ if (op.mem) {
2460
+ hasMem = 1;
2461
+ if (!op.reg)
2462
+ return 0;
2463
+ if (asmdb.x86.Utils.regSize(op.reg) !== op.memSize)
2464
+ return 0;
2465
+ }
2466
+ }
2467
+ }
2468
+ return hasMem;
2469
+ }
2470
+
2471
+ rmIsAmbiguous(dbInsts) {
2472
+ function isAmbiguous(dbInsts) {
2473
+ const memMap = {};
2474
+ const immMap = {};
2475
+
2476
+ for (var i = 0; i < dbInsts.length; i++) {
2477
+ const dbInst = dbInsts[i];
2478
+ const operands = dbInst.operands;
2479
+
2480
+ var memStr = "";
2481
+ var immStr = "";
2482
+ var hasMem = false;
2483
+ var hasImm = false;
2484
+
2485
+ for (var j = 0; j < operands.length; j++) {
2486
+ const op = operands[j];
2487
+ if (j) {
2488
+ memStr += ", ";
2489
+ immStr += ", ";
2490
+ }
2491
+
2492
+ if (op.isImm()) {
2493
+ immStr += "imm";
2494
+ hasImm = true;
2495
+ }
2496
+ else {
2497
+ immStr += op.toString();
2498
+ }
2499
+
2500
+ if (op.mem) {
2501
+ memStr += "m";
2502
+ hasMem = true;
2503
+ }
2504
+ else {
2505
+ memStr += op.isImm() ? "imm" : op.toString();
2506
+ }
2507
+ }
2508
+
2509
+ if (hasImm) {
2510
+ if (immMap[immStr] === true)
2511
+ continue;
2512
+ immMap[immStr] = true;
2513
+ }
2514
+
2515
+ if (hasMem) {
2516
+ if (memMap[memStr] === true)
2517
+ return 1;
2518
+ memMap[memStr] = true;
2519
+ }
2520
+ }
2521
+ return 0;
2522
+ }
2523
+
2524
+ const uniqueInsts = Filter.unique(dbInsts);
2525
+
2526
+ // Special cases.
2527
+ if (!dbInsts.length)
2528
+ return 0;
2529
+
2530
+ if (NOT_MEM_AMBIGUOUS[dbInsts[0].name])
2531
+ return 0;
2532
+
2533
+ return (isAmbiguous(Filter.byArch(uniqueInsts, "X86")) << 0) |
2534
+ (isAmbiguous(Filter.byArch(uniqueInsts, "X64")) << 1) ;
2535
+ }
2536
+
2537
+ rmExtension(dbInsts) {
2538
+ if (!dbInsts.length)
2539
+ return "None";
2540
+
2541
+ const name = dbInsts[0].name;
2542
+ switch (name) {
2543
+ case "pextrw":
2544
+ return "SSE4_1";
2545
+
2546
+ case "vpslld":
2547
+ case "vpsllq":
2548
+ case "vpsrad":
2549
+ case "vpsrld":
2550
+ case "vpsrlq":
2551
+ return "AVX512_F";
2552
+
2553
+ case "vpslldq":
2554
+ case "vpsllw":
2555
+ case "vpsraw":
2556
+ case "vpsrldq":
2557
+ case "vpsrlw":
2558
+ return "AVX512_BW";
2559
+
2560
+ default:
2561
+ return "None";
2562
+ }
2563
+ }
2564
+
2565
+ rmExtensionIfRMI(dbInsts) {
2566
+ if (!dbInsts.length)
2567
+ return 0;
2568
+
2569
+ const name = dbInsts[0].name;
2570
+ return /^(vpslld|vpsllq|vpsrad|vpsrld|vpsrlq|vpslldq|vpsllw|vpsraw|vpsrldq|vpsrlw)$/.test(name);
2571
+ }
2572
+ }
2573
+
2574
+ // ============================================================================
2575
+ // [tablegen.x86.InstCommonTable]
2576
+ // ============================================================================
2577
+
2578
+ class InstCommonTable extends core.Task {
2579
+ constructor() {
2580
+ super("InstCommonTable", [
2581
+ "IdEnum",
2582
+ "NameTable",
2583
+ "InstSignatureTable",
2584
+ "AdditionalInfoTable",
2585
+ "InstRWInfoTable"
2586
+ ]);
2587
+ }
2588
+
2589
+ run() {
2590
+ const insts = this.ctx.insts;
2591
+ const table = new IndexedArray();
2592
+
2593
+ insts.forEach((inst) => {
2594
+ const commonFlagsArray = inst.flags.filter((flag) => { return !flag.startsWith("Avx512"); });
2595
+ const avx512FlagsArray = inst.flags.filter((flag) => { return flag.startsWith("Avx512"); });
2596
+
2597
+ const commonFlags = commonFlagsArray.map(function(flag) { return `F(${flag })`; }).join("|") || "0";
2598
+ const avx512Flags = avx512FlagsArray.map(function(flag) { return `X(${flag.substr(6)})`; }).join("|") || "0";
2599
+
2600
+ const controlFlow = `CONTROL_FLOW(${inst.controlFlow})`;
2601
+ const singleRegCase = `SAME_REG_HINT(${inst.singleRegCase})`;
2602
+
2603
+ const row = "{ " +
2604
+ String(commonFlags ).padEnd(50) + ", " +
2605
+ String(avx512Flags ).padEnd(30) + ", " +
2606
+ String(inst.signatureIndex).padEnd( 3) + ", " +
2607
+ String(inst.signatureCount).padEnd( 2) + ", " +
2608
+ String(controlFlow ).padEnd(16) + ", " +
2609
+ String(singleRegCase ).padEnd(16) + "}";
2610
+ inst.commonInfoIndex = table.addIndexed(row);
2611
+ });
2612
+
2613
+ var s = `#define F(VAL) uint32_t(InstDB::InstFlags::k##VAL)\n` +
2614
+ `#define X(VAL) uint32_t(InstDB::Avx512Flags::k##VAL)\n` +
2615
+ `#define CONTROL_FLOW(VAL) uint8_t(InstControlFlow::k##VAL)\n` +
2616
+ `#define SAME_REG_HINT(VAL) uint8_t(InstSameRegHint::k##VAL)\n` +
2617
+ `const InstDB::CommonInfo InstDB::_commonInfoTable[] = {\n${StringUtils.format(table, kIndent, true)}\n};\n` +
2618
+ `#undef SAME_REG_HINT\n` +
2619
+ `#undef CONTROL_FLOW\n` +
2620
+ `#undef X\n` +
2621
+ `#undef F\n`;
2622
+ this.inject("InstCommonTable", disclaimer(s), table.length * 8);
2623
+ }
2624
+ }
2625
+
2626
+ // ============================================================================
2627
+ // [Main]
2628
+ // ============================================================================
2629
+
2630
+ new X86TableGen()
2631
+ .addTask(new IdEnum())
2632
+ .addTask(new NameTable())
2633
+ .addTask(new AltOpcodeTable())
2634
+ .addTask(new InstSignatureTable())
2635
+ .addTask(new AdditionalInfoTable())
2636
+ .addTask(new InstRWInfoTable())
2637
+ .addTask(new InstCommonTable())
2638
+ .run();