asmjit 0.2.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/Rakefile +5 -3
- data/asmjit.gemspec +1 -3
- data/ext/asmjit/asmjit/.editorconfig +10 -0
- data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
- data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
- data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
- data/ext/asmjit/asmjit/.gitignore +6 -0
- data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
- data/ext/asmjit/asmjit/LICENSE.md +17 -0
- data/ext/asmjit/asmjit/README.md +69 -0
- data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
- data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
- data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
- data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
- data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
- data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
- data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
- data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
- data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
- data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
- data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
- data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
- data/ext/asmjit/asmjit/test/broken.cpp +312 -0
- data/ext/asmjit/asmjit/test/broken.h +148 -0
- data/ext/asmjit/asmjit/test/cmdline.h +61 -0
- data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
- data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
- data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
- data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
- data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
- data/ext/asmjit/asmjit.cc +167 -30
- data/ext/asmjit/extconf.rb +9 -9
- data/lib/asmjit/version.rb +1 -1
- data/lib/asmjit.rb +14 -4
- metadata +198 -17
@@ -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();
|