asmjit 0.2.0 → 0.2.1

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