diff options
Diffstat (limited to '3rdparty/asmjit/tools/tablegen-x86.js')
-rw-r--r-- | 3rdparty/asmjit/tools/tablegen-x86.js | 1675 |
1 files changed, 940 insertions, 735 deletions
diff --git a/3rdparty/asmjit/tools/tablegen-x86.js b/3rdparty/asmjit/tools/tablegen-x86.js index dfd0f40b6ef..377a71045e7 100644 --- a/3rdparty/asmjit/tools/tablegen-x86.js +++ b/3rdparty/asmjit/tools/tablegen-x86.js @@ -1,95 +1,45 @@ -// AsmJit - Machine code generation for C++ +// This file is part of AsmJit project <https://asmjit.com> // -// * Official AsmJit Home Page: https://asmjit.com -// * Official Github Repository: https://github.com/asmjit/asmjit -// -// Copyright (c) 2008-2020 The AsmJit Authors -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -// ============================================================================ -// tablegen-x86.js -// -// The purpose of this script is to fetch all instructions' names into a single -// string and to optimize common patterns that appear in instruction data. It -// prevents relocation of small strings (instruction names) that has to be done -// by a linker to make all pointers the binary application/library uses valid. -// This approach decreases the final size of AsmJit binary and relocation data. -// -// NOTE: This script relies on 'asmdb' package. Either install it by using -// node.js package manager (npm) or by copying/symlinking the whole asmdb -// directory as [asmjit]/tools/asmdb. -// ============================================================================ +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib "use strict"; +const fs = require("fs"); +const path = require("path"); + +const commons = require("./generator-commons.js"); +const cxx = require("./generator-cxx.js"); const core = require("./tablegen.js"); + const asmdb = core.asmdb; -const kIndent = core.kIndent; -const Lang = core.Lang; -const CxxUtils = core.CxxUtils; -const MapUtils = core.MapUtils; -const ArrayUtils = core.ArrayUtils; -const StringUtils = core.StringUtils; -const IndexedArray = core.IndexedArray; +const DEBUG = commons.DEBUG; +const FATAL = commons.FATAL; +const kIndent = commons.kIndent; +const ArrayUtils = commons.ArrayUtils; +const IndexedArray = commons.IndexedArray; +const ObjectUtils = commons.ObjectUtils; +const StringUtils = commons.StringUtils; const hasOwn = Object.prototype.hasOwnProperty; const disclaimer = StringUtils.disclaimer; -const FAIL = core.FAIL; -const DEBUG = core.DEBUG; - const decToHex = StringUtils.decToHex; +function readJSON(fileName) { + const content = fs.readFileSync(fileName); + return JSON.parse(content); +} + +const x86data = readJSON(path.join(__dirname, "..", "db", asmdb.x86.dbName)); + // ============================================================================ // [tablegen.x86.x86isa] // ============================================================================ // Create the X86 database and add some special cases recognized by AsmJit. -const x86isa = new asmdb.x86.ISA({ - instructions: [ - // Imul in [reg, imm] form is encoded as [reg, reg, imm]. - ["imul", "r16, ib" , "RMI" , "66 6B /r ib" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"], - ["imul", "r32, ib" , "RMI" , "6B /r ib" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"], - ["imul", "r64, ib" , "RMI" , "REX.W 6B /r ib", "X64 OF=W SF=W ZF=U AF=U PF=U CF=W"], - ["imul", "r16, iw" , "RMI" , "66 69 /r iw" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"], - ["imul", "r32, id" , "RMI" , "69 /r id" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"], - ["imul", "r64, id" , "RMI" , "REX.W 69 /r id", "X64 OF=W SF=W ZF=U AF=U PF=U CF=W"] - ] -}); - -// Remapped instructions contain mapping between instructions that AsmJit expects -// and instructions provided by asmdb. In general, AsmJit uses string instructions -// (like cmps, movs, etc...) without the suffix, so we just remap these and keep -// all others. -const RemappedInsts = { - __proto__: null, - - "cmpsd": { names: ["cmpsd"] , rep: false }, - "movsd": { names: ["movsd"] , rep: false }, - "cmps" : { names: ["cmpsb", "cmpsw", "cmpsd", "cmpsq"], rep: true }, - "movs" : { names: ["movsb", "movsw", "movsd", "movsq"], rep: true }, - "lods" : { names: ["lodsb", "lodsw", "lodsd", "lodsq"], rep: null }, - "scas" : { names: ["scasb", "scasw", "scasd", "scasq"], rep: null }, - "stos" : { names: ["stosb", "stosw", "stosd", "stosq"], rep: null }, - "ins" : { names: ["insb" , "insw" , "insd" ] , rep: null }, - "outs" : { names: ["outsb", "outsw", "outsd"] , rep: null } -}; +const x86isa = new asmdb.x86.ISA(x86data); // ============================================================================ // [tablegen.x86.Filter] @@ -102,7 +52,7 @@ class Filter { for (var i = 0; i < instArray.length; i++) { const inst = instArray[i]; - if (inst.attributes.AltForm) + if (inst.altForm) continue; const s = inst.operands.map((op) => { return op.isImm() ? "imm" : op.toString(); }).join(", "); @@ -120,7 +70,7 @@ class Filter { const result = []; for (var i = 0; i < instArray.length; i++) { const inst = instArray[i]; - if (inst.attributes.AltForm) + if (inst.altForm) continue; result.push(inst); } @@ -138,6 +88,25 @@ class Filter { // [tablegen.x86.GenUtils] // ============================================================================ +const VexToEvexMap = { + "vbroadcastf128": "vbroadcastf32x4", + "vbroadcasti128": "vbroadcasti32x4", + "vextractf128": "vextractf32x4", + "vextracti128": "vextracti32x4", + "vinsertf128": "vinsertf32x4", + "vinserti128": "vinserti32x4", + "vmovdqa": "vmovdqa32", + "vmovdqu": "vmovdqu32", + "vpand": "vpandd", + "vpandn": "vpandnd", + "vpor": "vpord", + "vpxor": "vpxord", + "vroundpd": "vrndscalepd", + "vroundps": "vrndscaleps", + "vroundsd": "vrndscalesd", + "vroundss": "vrndscaless" +}; + class GenUtils { static cpuArchOf(dbInsts) { var anyArch = false; @@ -155,23 +124,90 @@ class GenUtils { } static cpuFeaturesOf(dbInsts) { - return ArrayUtils.sorted(dbInsts.unionCpuFeatures()); + function cmp(a, b) { + if (a.startsWith("AVX512") && !b.startsWith("AVX512")) + return 1; + if (b.startsWith("AVX512") && !a.startsWith("AVX512")) + return -1; + + if (a.startsWith("AVX") && !b.startsWith("AVX")) + return 1; + if (b.startsWith("AVX") && !a.startsWith("AVX")) + return -1; + + if (a === "FPU" && b !== "FPU") + return 1; + if (b === "FPU" && a !== "FPU") + return -1; + + return a < b ? -1 : a === b ? 0 : 1; + } + + const features = Object.getOwnPropertyNames(dbInsts.unionCpuFeatures()); + features.sort(cmp); + return features; } - static flagsOf(dbInsts) { - function replace(map, a, b, c) { - if (map[a] && map[b]) { - delete map[a]; - delete map[b]; - map[c] = true; + static assignVexEvexCompatibilityFlags(f, dbInsts) { + const vexInsts = dbInsts.filter((inst) => { return inst.prefix === "VEX"; }); + const evexInsts = dbInsts.filter((inst) => { return inst.prefix === "EVEX"; }); + + function isCompatible(vexInst, evexInst) { + if (vexInst.operands.length !== evexInst.operands.length) + return false; + + for (let i = 0; i < vexInst.operands.length; i++) { + const vexOp = vexInst.operands[i]; + const evexOp = evexInst.operands[i]; + + if (vexOp.data === evexOp.data) + continue; + + if (vexOp.reg && vexOp.reg === evexOp.reg) + continue; + if (vexOp.mem && vexOp.mem === evexOp.mem) + continue; + + return false; + } + return true; + } + + let compatible = 0; + for (const vexInst of vexInsts) { + for (const evexInst of evexInsts) { + if (isCompatible(vexInst, evexInst)) { + compatible++; + break; + } } } + if (compatible == vexInsts.length) { + f.EvexCompat = true; + return true; + } + + if (evexInsts[0].operands[0].reg === "k") { + f.EvexKReg = true; + return true; + } + + if (evexInsts[0].operands.length == 2 && vexInsts[0].operands.length === 3) { + f.EvexTwoOp = true; + return true; + } + + return false; + } + + static flagsOf(dbInsts) { const f = Object.create(null); var i, j; var mib = dbInsts.length > 0 && /^(?:bndldx|bndstx)$/.test(dbInsts[0].name); - if (mib) f.Mib = true; + if (mib) + f.Mib = true; var mmx = false; var vec = false; @@ -190,7 +226,7 @@ class GenUtils { const op = operands[j]; if (op.reg === "mm") mmx = true; - else if (/^(k|xmm|ymm|zmm)$/.test(op.reg)) { + else if (/^(xmm|ymm|zmm)$/.test(op.reg)) { vec = true; } } @@ -203,15 +239,16 @@ class GenUtils { const dbInst = dbInsts[i]; const operands = dbInst.operands; - if (dbInst.attributes.Lock ) f.Lock = true; - if (dbInst.attributes.XAcquire ) f.XAcquire = true; - if (dbInst.attributes.XRelease ) f.XRelease = true; - if (dbInst.attributes.BND ) f.Rep = true; - if (dbInst.attributes.REP ) f.Rep = true; - if (dbInst.attributes.REPNE ) f.Rep = true; - if (dbInst.attributes.RepIgnored) f.RepIgnored = true; + if (dbInst.prefixes.lock ) f.Lock = true; + if (dbInst.prefixes.xacquire ) f.XAcquire = true; + if (dbInst.prefixes.xrelease ) f.XRelease = true; + if (dbInst.prefixes.bnd ) f.Rep = true; + if (dbInst.prefixes.rep ) f.Rep = true; + if (dbInst.prefixes.repne ) f.Rep = true; + if (dbInst.prefixes.repIgnore ) f.RepIgnored = true; + if (dbInst.k === "zeroing" ) f.Avx512ImplicitZ = true; - if (dbInst.fpu) { + if (dbInst.category.FPU) { for (var j = 0; j < operands.length; j++) { const op = operands[j]; if (op.memSize === 16) f.FpuM16 = true; @@ -221,15 +258,20 @@ class GenUtils { } } + if (dbInst.tsib) + f.Tsib = true; + if (dbInst.vsibReg) f.Vsib = true; if (dbInst.prefix === "VEX" || dbInst.prefix === "XOP") f.Vex = true; + if (dbInst.encodingPreference === "EVEX") + f.PreferEvex = true; + if (dbInst.prefix === "EVEX") { f.Evex = true; - if (dbInst.kmask) f.Avx512K = true; if (dbInst.zmask) f.Avx512Z = true; @@ -239,22 +281,18 @@ class GenUtils { if (dbInst.broadcast) f["Avx512B" + String(dbInst.elementSize)] = true; if (dbInst.tupleType === "T1_4X") f.Avx512T4X = true; } + + if (VexToEvexMap[dbInst.name]) + f.EvexTransformable = true; } - replace(f, "Avx512K" , "Avx512Z" , "Avx512KZ"); - replace(f, "Avx512ER" , "Avx512SAE" , "Avx512ER_SAE"); - replace(f, "Avx512KZ" , "Avx512SAE" , "Avx512KZ_SAE"); - replace(f, "Avx512KZ" , "Avx512ER_SAE", "Avx512KZ_ER_SAE"); - replace(f, "Avx512K" , "Avx512B32" , "Avx512K_B32"); - replace(f, "Avx512K" , "Avx512B64" , "Avx512K_B64"); - replace(f, "Avx512KZ" , "Avx512B32" , "Avx512KZ_B32"); - replace(f, "Avx512KZ" , "Avx512B64" , "Avx512KZ_B64"); - replace(f, "Avx512KZ_SAE" , "Avx512B32" , "Avx512KZ_SAE_B32"); - replace(f, "Avx512KZ_SAE" , "Avx512B64" , "Avx512KZ_SAE_B64"); - replace(f, "Avx512KZ_ER_SAE", "Avx512B32" , "Avx512KZ_ER_SAE_B32"); - replace(f, "Avx512KZ_ER_SAE", "Avx512B64" , "Avx512KZ_ER_SAE_B64"); - - return Object.getOwnPropertyNames(f); + if (f.Vex && f.Evex) { + GenUtils.assignVexEvexCompatibilityFlags(f, dbInsts) + } + + const result = Object.getOwnPropertyNames(f); + result.sort(); + return result; } static eqOps(aOps, aFrom, bOps, bFrom) { @@ -279,6 +317,20 @@ class GenUtils { } } + // Prevent some instructions from having implicit memory size if that would + // make them ambiguous. There are some instructions where the ambiguity is + // okay, but some like 'push' and 'pop' where it isn't. + static canUseImplicitMemSize(name) { + switch (name) { + case "pop": + case "push": + return false; + + default: + return true; + } + } + static singleRegCase(name) { switch (name) { case "xchg" : @@ -308,6 +360,16 @@ class GenUtils { case "xorpd" : case "vxorpd" : case "xorps" : case "vxorps" : + case "kxnorb": + case "kxnord": + case "kxnorw": + case "kxnorq": + + case "kxorb": + case "kxord": + case "kxorw": + case "kxorq": + case "sub" : case "sbb" : case "psubb" : case "vpsubb" : @@ -333,7 +395,7 @@ class GenUtils { } } - static fixedRegOf(reg) { + static fixedRegOfRegName(reg) { switch (reg) { case "es" : return 1; case "cs" : return 2; @@ -362,12 +424,24 @@ class GenUtils { } } - static controlType(dbInsts) { - if (dbInsts.checkAttribute("Control", "Jump")) return "Jump"; - if (dbInsts.checkAttribute("Control", "Call")) return "Call"; - if (dbInsts.checkAttribute("Control", "Branch")) return "Branch"; - if (dbInsts.checkAttribute("Control", "Return")) return "Return"; - return "None"; + static fixedRegOf(op) { + if (op.isReg()) { + return GenUtils.fixedRegOfRegName(op.reg); + } + else if (op.isMem() && op.memRegOnly) { + return GenUtils.fixedRegOfRegName(op.memRegOnly); + } + else { + return -1; + } + } + + static controlFlow(dbInsts) { + if (dbInsts.checkAttribute("control", "jump")) return "Jump"; + if (dbInsts.checkAttribute("control", "call")) return "Call"; + if (dbInsts.checkAttribute("control", "branch")) return "Branch"; + if (dbInsts.checkAttribute("control", "return")) return "Return"; + return "Regular"; } } @@ -378,6 +452,8 @@ class GenUtils { class X86TableGen extends core.TableGen { constructor() { super("X86"); + + this.emitMissingString = ""; } // -------------------------------------------------------------------------- @@ -386,16 +462,7 @@ class X86TableGen extends core.TableGen { // Get instructions (dbInsts) having the same name as understood by AsmJit. query(name) { - const remapped = RemappedInsts[name]; - if (!remapped) return x86isa.query(name); - - const dbInsts = x86isa.query(remapped.names); - const rep = remapped.rep; - if (rep === null) return dbInsts; - - return dbInsts.filter((inst) => { - return rep === !!(inst.attributes.REP || inst.attributes.REPNE); - }); + return x86isa.query(name); } // -------------------------------------------------------------------------- @@ -413,9 +480,8 @@ class X86TableGen extends core.TableGen { // --- autogenerated fields --- "([^\\)]+)" + "," + // [05] MainOpcodeIndex. "([^\\)]+)" + "," + // [06] AltOpcodeIndex. - "([^\\)]+)" + "," + // [07] NameIndex. - "([^\\)]+)" + "," + // [08] CommonDataIndex. - "([^\\)]+)" + "\\)", // [09] OperationDataIndex. + "([^\\)]+)" + "," + // [07] CommonDataIndex. + "([^\\)]+)" + "\\)", // [08] OperationDataIndex. "g"); var m; @@ -428,39 +494,40 @@ class X86TableGen extends core.TableGen { const dbInsts = this.query(name); if (name && !dbInsts.length) - FAIL(`Instruction '${name}' not found in asmdb`); + FATAL(`Instruction '${name}' not found in asmdb`); const flags = GenUtils.flagsOf(dbInsts); - const controlType = GenUtils.controlType(dbInsts); + const controlFlow = GenUtils.controlFlow(dbInsts); const singleRegCase = GenUtils.singleRegCase(name); this.addInst({ - id : 0, // Instruction id (numeric value). - name : name, // Instruction name. - enum : enum_, // Instruction enum without `kId` prefix. - dbInsts : dbInsts, // All dbInsts returned from asmdb query. - encoding : encoding, // Instruction encoding. - opcode0 : opcode0, // Primary opcode. - opcode1 : opcode1, // Secondary opcode. - flags : flags, - signatures : null, // Instruction signatures. - controlType : controlType, - singleRegCase : singleRegCase, - - mainOpcodeValue : -1, // Main opcode value (0.255 hex). - mainOpcodeIndex : -1, // Index to InstDB::_mainOpcodeTable. - altOpcodeIndex : -1, // Index to InstDB::_altOpcodeTable. - nameIndex : -1, // Index to InstDB::_nameData. - commonInfoIndexA : -1, - commomInfoIndexB : -1, - - signatureIndex : -1, - signatureCount : -1 + id : 0, // Instruction id (numeric value). + name : name, // Instruction name. + displayName : name, // Instruction name to display. + enum : enum_, // Instruction enum without `kId` prefix. + dbInsts : dbInsts, // All dbInsts returned from asmdb query. + encoding : encoding, // Instruction encoding. + opcode0 : opcode0, // Primary opcode. + opcode1 : opcode1, // Secondary opcode. + flags : flags, + signatures : null, // Instruction signatures. + controlFlow : controlFlow, + singleRegCase : singleRegCase, + + mainOpcodeValue : -1, // Main opcode value (0.255 hex). + mainOpcodeIndex : -1, // Index to InstDB::_mainOpcodeTable. + altOpcodeIndex : -1, // Index to InstDB::_altOpcodeTable. + nameIndex : -1, // Index to InstDB::_nameData. + commonInfoIndex : -1, + additionalInfoIndex: -1, + + signatureIndex : -1, + signatureCount : -1 }); } if (this.insts.length === 0) - FAIL("X86TableGen.parse(): Invalid parsing regexp (no data parsed)"); + FATAL("X86TableGen.parse(): Invalid parsing regexp (no data parsed)"); console.log("Number of Instructions: " + this.insts.length); } @@ -468,15 +535,14 @@ class X86TableGen extends core.TableGen { merge() { var s = StringUtils.format(this.insts, "", true, function(inst) { return "INST(" + - String(inst.enum ).padEnd(17) + ", " + - String(inst.encoding ).padEnd(19) + ", " + - String(inst.opcode0 ).padEnd(26) + ", " + - String(inst.opcode1 ).padEnd(26) + ", " + - String(inst.mainOpcodeIndex ).padEnd( 3) + ", " + - String(inst.altOpcodeIndex ).padEnd( 3) + ", " + - String(inst.nameIndex ).padEnd( 5) + ", " + - String(inst.commonInfoIndexA).padEnd( 3) + ", " + - String(inst.commomInfoIndexB).padEnd( 3) + ")"; + String(inst.enum ).padEnd(17) + ", " + + String(inst.encoding ).padEnd(19) + ", " + + String(inst.opcode0 ).padEnd(26) + ", " + + String(inst.opcode1 ).padEnd(26) + ", " + + String(inst.mainOpcodeIndex ).padEnd( 3) + ", " + + String(inst.altOpcodeIndex ).padEnd( 3) + ", " + + String(inst.commonInfoIndex ).padEnd( 3) + ", " + + String(inst.additionalInfoIndex).padEnd( 3) + ")"; }) + "\n"; this.inject("InstInfo", s, this.insts.length * 8); } @@ -486,7 +552,7 @@ class X86TableGen extends core.TableGen { // -------------------------------------------------------------------------- printMissing() { - const ignored = MapUtils.arrayToMap([ + const ignored = ArrayUtils.toDict([ "cmpsb", "cmpsw", "cmpsd", "cmpsq", "lodsb", "lodsw", "lodsd", "lodsq", "movsb", "movsw", "movsd", "movsq", @@ -509,13 +575,16 @@ class X86TableGen extends core.TableGen { String(inst.encoding ).padEnd(19) + ", " + String(inst.opcode0 ).padEnd(26) + ", " + String(inst.opcode1 ).padEnd(26) + ", " + - String("0" ).padEnd( 4) + ", " + + String("0" ).padEnd( 3) + ", " + + String("0" ).padEnd( 3) + ", " + + String("0" ).padEnd( 5) + ", " + String("0" ).padEnd( 3) + ", " + String("0" ).padEnd( 3) + "),\n"; } } }, this); console.log(out); + console.log(this.emitMissingString); } newInstFromGroup(dbInsts) { @@ -540,24 +609,83 @@ class X86TableGen extends core.TableGen { return s === "VEX" || s === "EVEX" || s === "XOP"; } + function formatEmit(dbi) { + const results = []; + const nameUp = dbi.name[0].toUpperCase() + dbi.name.substr(1); + + for (let choice = 0; choice < 2; choice++) { + let s = `ASMJIT_INST_${dbi.operands.length}x(${dbi.name}, ${nameUp}`; + for (let j = 0; j < dbi.operands.length; j++) { + s += ", "; + const op = dbi.operands[j]; + var reg = op.reg; + var mem = op.mem; + + if (op.isReg() && op.isMem()) { + if (choice == 0) mem = null; + if (choice == 1) reg = null; + } + + if (reg) { + if (reg === "xmm" || reg === "ymm" || reg === "zmm") + s += "Vec"; + else if (reg === "k") + s += "KReg"; + else if (reg === "r32" || reg === "r64" || reg === "r16" || reg === "r8") + s += "Gp"; + else + s += reg; + } + else if (mem) { + s += "Mem"; + } + else if (op.isImm()) { + s += "Imm"; + } + else { + s += "Unknown"; + } + } + s += `)`; + results.push(s); + } + + return results; + } + var dbi = dbInsts[0]; - var id = this.insts.length; - var name = dbi.name; - var enum_ = name[0].toUpperCase() + name.substr(1); + var id = this.insts.length; + var name = dbi.name; + var enum_ = name[0].toUpperCase() + name.substr(1); - var opcode = dbi.opcodeHex; - var rm = dbi.rm; - var mm = dbi.mm; - var pp = dbi.pp; + var opcode = dbi.opcodeHex; + var modR = dbi.modR; + var mm = dbi.mm; + var pp = dbi.pp; var encoding = dbi.encoding; - var isVec = isVecPrefix(dbi.prefix); - - var access = GetAccess(dbi); + var isVec = isVecPrefix(dbi.prefix); + var evexCount = 0; + + var access = GetAccess(dbi); + + var vexL = undefined; + var vexW = undefined; + var evexW = undefined; + var cdshl = "_"; + var tupleType = "_"; + + const tupleTypeToCDSHL = { + "FVM": "4", + "FV": "4", + "HVM": "3", + "HV": "3", + "QVM": "2", + "QV": "2", + "T1S": "?" + } - var vexL = undefined; - var vexW = undefined; - var evexW = undefined; + const emitMap = {}; for (var i = 0; i < dbInsts.length; i++) { dbi = dbInsts[i]; @@ -577,47 +705,66 @@ class X86TableGen extends core.TableGen { } if (dbi.prefix === "EVEX") { + evexCount++; var newEvexW = String(dbi.w === "W0" ? 0 : dbi.w === "W1" ? 1 : "_"); if (evexW !== undefined && evexW !== newEvexW) evexW = "x"; else evexW = newEvexW; + + if (dbi.tupleType) { + if (tupleType !== "_" && tupleType !== dbi.tupleType) { + console.log(`${dbi.name}: WARNING: TupleType ${tupleType} != ${dbi.tupleType}`); + } + + tupleType = dbi.tupleType; + } } - if (opcode !== dbi.opcodeHex ) { console.log(`ISSUE: Opcode ${opcode} != ${dbi.opcodeHex}`); return null; } - if (rm !== dbi.rm ) { console.log(`ISSUE: RM ${rm} != ${dbi.rm}`); return null; } - if (mm !== dbi.mm ) { console.log(`ISSUE: MM ${mm} != ${dbi.mm}`); return null; } - if (pp !== dbi.pp ) { console.log(`ISSUE: PP ${pp} != ${dbi.pp}`); return null; } - if (encoding !== dbi.encoding ) { console.log(`ISSUE: Enc ${encoding} != ${dbi.encoding}`); return null; } - if (access !== GetAccess(dbi)) { console.log(`ISSUE: Access ${access} != ${GetAccess(dbi)}`); return null; } - if (isVec != isVecPrefix(dbi.prefix)) { console.log(`ISSUE: Vex/Non-Vex mismatch`); return null; } + if (opcode !== dbi.opcodeHex ) { console.log(`${dbi.name}: ISSUE: Opcode ${opcode} != ${dbi.opcodeHex}`); return null; } + if (modR !== dbi.modR ) { console.log(`${dbi.name}: ISSUE: ModR ${modR} != ${dbi.modR}`); return null; } + if (mm !== dbi.mm ) { console.log(`${dbi.name}: ISSUE: MM ${mm} != ${dbi.mm}`); return null; } + if (pp !== dbi.pp ) { console.log(`${dbi.name}: ISSUE: PP ${pp} != ${dbi.pp}`); return null; } + if (encoding !== dbi.encoding ) { console.log(`${dbi.name}: ISSUE: Enc ${encoding} != ${dbi.encoding}`); return null; } + if (access !== GetAccess(dbi)) { console.log(`${dbi.name}: ISSUE: Access ${access} != ${GetAccess(dbi)}`); return null; } + if (isVec != isVecPrefix(dbi.prefix)) { console.log(`${dbi.name}: ISSUE: Vex/Non-Vex mismatch`); return null; } + + formatEmit(dbi).forEach((emit) => { + if (!emitMap[emit]) { + emitMap[emit] = true; + this.emitMissingString += emit + "\n"; + } + }); } + if (tupleType !== "_") + cdshl = tupleTypeToCDSHL[tupleType] || "?"; + var ppmm = pp.padEnd(2).replace(/ /g, "0") + mm.padEnd(4).replace(/ /g, "0") ; var composed = composeOpCode({ - type : isVec ? "V" : "O", + type : evexCount == dbInsts.length ? "E" : isVec ? "V" : "O", prefix: ppmm, opcode: opcode, - o : rm === "r" ? "_" : (rm ? rm : "_"), + o : modR === "r" ? "_" : (modR ? modR : "_"), l : vexL !== undefined ? vexL : "_", w : vexW !== undefined ? vexW : "_", ew : evexW !== undefined ? evexW : "_", - en : "_", - tt : "_ " + en : cdshl, + tt : dbi.modRM ? dbi.modRM + " " : tupleType.padEnd(3) }); return { - id : id, - name : name, - enum : enum_, - encoding : encoding, - opcode0 : composed, - opcode1 : "0", - nameIndex : -1, - commonInfoIndexA : -1, - commomInfoIndexB : -1 + id : id, + name : name, + enum : enum_, + encoding : encoding, + opcode0 : composed, + opcode1 : "0", + nameIndex : -1, + commonInfoIndex : -1, + additionalInfoIndex: -1 }; } @@ -663,11 +810,21 @@ class IdEnum extends core.IdEnum { var text = ""; var features = GenUtils.cpuFeaturesOf(dbInsts); + const priorityFeatures = ["AVX_VNNI", "AVX_VNNI_INT8", "AVX_IFMA", "AVX_NE_CONVERT"]; + if (features.length) { text += "{"; const avxFeatures = filterAVX(features, true); const otherFeatures = filterAVX(features, false); + for (const pf of priorityFeatures) { + const index = avxFeatures.indexOf(pf); + if (index != -1) { + avxFeatures.splice(index, 1); + avxFeatures.unshift(pf); + } + } + const vl = avxFeatures.indexOf("AVX512_VL"); if (vl !== -1) avxFeatures.splice(vl, 1); @@ -716,39 +873,103 @@ class AltOpcodeTable extends core.Task { const mainOpcodeTable = new IndexedArray(); const altOpcodeTable = new IndexedArray(); - mainOpcodeTable.addIndexed("O(000000,00,0,0,0,0,0,_ )"); + const cdttSimplification = { + "0" : "None", + "_" : "None", + "FV" : "ByLL", + "HV" : "ByLL", + "QV" : "ByLL", + "FVM" : "ByLL", + "T1S" : "None", + "T1F" : "None", + "T1_4X": "None", + "T2" : "None", + "T4" : "None", + "T8" : "None", + "HVM" : "ByLL", + "QVM" : "ByLL", + "OVM" : "ByLL", + "128" : "None", + "T4X" : "None" + } - function indexOpcode(opcode) { - if (opcode === "0") - return ["00", 0]; + const noOp = "O(000000,00,0,0,0,0,0,0 )"; - // O_FPU(__,__OP,_) - if (opcode.startsWith("O_FPU(")) { - var value = opcode.substring(11, 13); - var remaining = opcode.substring(0, 11) + "00" + opcode.substring(13); + mainOpcodeTable.addIndexed(noOp); - return [value, mainOpcodeTable.addIndexed(remaining.padEnd(26))]; + function splitOpcodeToComponents(opcode) { + const i = opcode.indexOf("("); + const prefix = opcode.substr(0, i); + return [prefix].concat(opcode.substring(i + 1, opcode.length - 1).split(",")); + } + + function normalizeOpcodeComponents(components) { + for (let i = 1; i < components.length; i++) { + components[i] = components[i].trim(); + // These all are zeros that only have some contextual meaning in the table, but the assembler doesn't care. + if (components[i] === "_" || components[i] === "I" || components[i] === "x") + components[i] = "0"; } - // X(______,OP,_,_,_,_,_,_ ) - if (opcode.startsWith("O_FPU(") || opcode.startsWith("O(") || opcode.startsWith("V(") || opcode.startsWith("E(")) { - var value = opcode.substring(9, 11); - var remaining = opcode.substring(0, 9) + "00" + opcode.substring(11); + // Simplify CDTT (compressed displacement TupleType). + if (components.length >= 9) { + if (components[0] === "V" || components[0] === "E") { + const cdtt = components[8]; + if (cdttSimplification[cdtt] !== undefined) + components[8] = cdttSimplification[cdtt]; + } + } + return components; + } + + function joinOpcodeComponents(components) { + const prefix = components[0]; + const values = components.slice(1); + if (values.length >= 8) + values[7] = values[7].padEnd(4); + return prefix + "(" + values.join(",") + ")"; + } + + function indexMainOpcode(opcode) { + if (opcode === "0") + return ["00", 0]; - remaining = remaining.replace(/,[_xI],/g, ",0,"); - remaining = remaining.replace(/,[_xI],/g, ",0,"); - return [value, mainOpcodeTable.addIndexed(remaining.padEnd(26))]; + var opcodeByte = ""; + const components = normalizeOpcodeComponents(splitOpcodeToComponents(opcode)); + + if (components[0] === "O_FPU") { + // Reset opcode byte, this is stored in the instruction data itself. + opcodeByte = components[2].substr(2, 2); + components[2] = components[2].substr(0, 2) + "00"; + } + else if (components[0] === "O" || components[0] === "V" || components[0] === "E") { + // Reset opcode byte, this is stored in the instruction data itself. + opcodeByte = components[2]; + components[2] = "00"; } + else { + FATAL(`Failed to process opcode '${opcode}'`); + } + + const newOpcode = joinOpcodeComponents(components); + return [opcodeByte, mainOpcodeTable.addIndexed(newOpcode.padEnd(27))]; + } - FAIL(`Failed to process opcode '${opcode}'`); + function indexAltOpcode(opcode) { + if (opcode === "0") + opcode = noOp; + else + opcode = joinOpcodeComponents(normalizeOpcodeComponents(splitOpcodeToComponents(opcode))); + return altOpcodeTable.addIndexed(opcode.padEnd(27)); } insts.map((inst) => { - const [value, index] = indexOpcode(inst.opcode0); + const [value, index] = indexMainOpcode(inst.opcode0); inst.mainOpcodeValue = value; inst.mainOpcodeIndex = index; - inst.altOpcodeIndex = altOpcodeTable.addIndexed(inst.opcode1.padEnd(26)); + inst.altOpcodeIndex = indexAltOpcode(inst.opcode1); }); + // console.log(mainOpcodeTable.length); // console.log(StringUtils.format(mainOpcodeTable, kIndent, true)); @@ -763,222 +984,39 @@ class AltOpcodeTable extends core.Task { } // ============================================================================ -// [tablegen.x86.SseToAvxTable] -// ============================================================================ -/* -// Removed from asmjit. -class InstSseToAvxTable extends core.Task { - constructor() { - super("InstSseToAvxTable", ["IdEnum"]); - } - - run() { - const insts = this.ctx.insts; - - const dataTable = new IndexedArray(); - const indexTable = []; - - function add(data) { - return dataTable.addIndexed("{ " + `SseToAvxData::kMode${data.mode}`.padEnd(28) + ", " + String(data.delta).padEnd(4) + " }"); - } - - // This will receive a zero index, which means that no SseToAvx or AvxToSSe translation is possible. - const kInvalidIndex = add({ mode: "None", delta: 0 }); - insts.forEach((inst) => { indexTable.push(kInvalidIndex); }); - - insts.forEach((inst) => { - // If it's not `kInvalidIndex` it's an AVX instruction that shares the - // SseToAvx data. We won't touch it as it already has the index assigned. - if (indexTable[inst.id] === kInvalidIndex) { - const data = this.calcSseToAvxData(inst.dbInsts); - const index = add(data); - - indexTable[inst.id] = index; - if (data.delta !== 0) - indexTable[this.ctx.instMap["v" + inst.name].id] = index; - } - }); - - this.inject("SseToAvxIndex", - disclaimer(`static const uint8_t sseToAvxIndex[] = {\n${StringUtils.format(indexTable, kIndent, -1)}\n};\n`), - indexTable.length * 1); - - this.inject("SseToAvxTable", - disclaimer(`static const SseToAvxData sseToAvxData[] = {\n${StringUtils.format(dataTable, kIndent, true)}\n};\n`), - dataTable.length * 2); - } - - filterSseToAvx(dbInsts) { - const filtered = []; - for (var x = 0; x < dbInsts.length; x++) { - const dbInst = dbInsts[x]; - const ops = dbInst.operands; - - // SSE instruction does never share its name with AVX one. - if (/^(VEX|XOP|EVEX)$/.test(dbInst.prefix)) - return []; - - var ok = false; - for (var y = 0; y < ops.length; y++) { - // There is no AVX instruction that works with MMX regs. - if (ops[y].reg === "mm") { ok = false; break; } - if (ops[y].reg === "xmm") { ok = true; } - } - - if (ok) - filtered.push(dbInst); - } - - return filtered; - } - - calcSseToAvxData(dbInsts) { - const data = { - mode : "None", // No conversion by default. - delta: 0 // 0 if no conversion is possible. - }; - - const dbSseInsts = this.filterSseToAvx(dbInsts); - if (!dbSseInsts.length) - return data; - - const sseName = dbSseInsts[0].name; - const avxName = "v" + sseName; - - const dbAvxInsts = this.ctx.query(avxName); - if (!dbAvxInsts.length) { - DEBUG(`SseToAvx: Instruction '${sseName}' has no AVX counterpart`); - return data; - } - - if (avxName === "vblendvpd" || avxName === "vblendvps" || avxName === "vpblendvb") { - // Special cases first. - data.mode = "Blend"; - } - else { - // Common case, deduce conversion mode by checking both SSE and AVX instructions. - const map = Object.create(null); - for (var sseIndex = 0; sseIndex < dbSseInsts.length; sseIndex++) { - const sseInst = dbSseInsts[sseIndex]; - var match = false; - - for (var avxIndex = 0; avxIndex < dbAvxInsts.length; avxIndex++) { - const avxInst = dbAvxInsts[avxIndex]; - - // Select only VEX instructions. - if (avxInst.prefix !== "VEX") continue; - - // Check if the AVX version is the same. - if (GenUtils.eqOps(avxInst.operands, 0, sseInst.operands, 0)) { - map.raw = true; - match = true; - } - else if (avxInst.operands[0].data === "xmm" && GenUtils.eqOps(avxInst.operands, 1, sseInst.operands, 0)) { - map.nds = true; - match = true; - } - } - - if (!match) { - const signature = sseInst.operands.map(function(op) { return op.data; }).join(", "); - console.log(`SseToAvx: Instruction '${sseName}(${signature})' has no AVX counterpart`); - return data; - } - } - - data.mode = (map.raw && !map.nds) ? "Move" : (map.raw && map.nds) ? "MoveIfMem" : "Extend"; - } - data.delta = this.ctx.instMap[avxName].id - this.ctx.instMap[sseName].id; - return data; - } -} -*/ - -// ============================================================================ // [tablegen.x86.InstSignatureTable] // ============================================================================ -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"]); -const MemOp = MapUtils.arrayToMap(["m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024"]); +const RegOp = ArrayUtils.toDict(["al", "ah", "ax", "eax", "rax", "cl", "r8lo", "r8hi", "r16", "r32", "r64", "xmm", "ymm", "zmm", "mm", "k", "sreg", "creg", "dreg", "st", "bnd"]); +const MemOp = ArrayUtils.toDict(["m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024"]); const cmpOp = StringUtils.makePriorityCompare([ - "r8lo", "r8hi", "r16", "r32", "r64", "xmm", "ymm", "zmm", "mm", "k", "sreg", "creg", "dreg", "st", "bnd", - "mem", "vm", "m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024", - "mib", - "vm32x", "vm32y", "vm32z", "vm64x", "vm64y", "vm64z", - "memBase", "memES", "memDS", - "i4", "u4", "i8", "u8", "i16", "u16", "i32", "u32", "i64", "u64", - "rel8", "rel32", - "implicit" + "RegGpbLo", "RegGpbHi", "RegGpw", "RegGpd", "RegGpq", "RegXmm", "RegYmm", "RegZmm", "RegMm", "RegKReg", "RegSReg", "RegCReg", "RegDReg", "RegSt", "RegBnd", "RegTmm", + "MemUnspecified", "Mem8", "Mem16", "Mem32", "Mem48", "Mem64", "Mem80", "Mem128", "Mem256", "Mem512", "Mem1024", + "Vm32x", "Vm32y", "Vm32z", "Vm64x", "Vm64y", "Vm64z", + "ImmI4", "ImmU4", "ImmI8", "ImmU8", "ImmI16", "ImmU16", "ImmI32", "ImmU32", "ImmI64", "ImmU64", + "Rel8", "Rel32", + "FlagMemBase", + "FlagMemDs", + "FlagMemEs", + "FlagMib", + "FlagTMem", + "FlagConsecutive", + "FlagImplicit" ]); -const OpToAsmJitOp = { - "implicit": "F(Implicit)", - - "r8lo" : "F(GpbLo)", - "r8hi" : "F(GpbHi)", - "r16" : "F(Gpw)", - "r32" : "F(Gpd)", - "r64" : "F(Gpq)", - "xmm" : "F(Xmm)", - "ymm" : "F(Ymm)", - "zmm" : "F(Zmm)", - "mm" : "F(Mm)", - "k" : "F(KReg)", - "sreg" : "F(SReg)", - "creg" : "F(CReg)", - "dreg" : "F(DReg)", - "st" : "F(St)", - "bnd" : "F(Bnd)", - - "mem" : "F(Mem)", - "vm" : "F(Vm)", - - "i4" : "F(I4)", - "u4" : "F(U4)", - "i8" : "F(I8)", - "u8" : "F(U8)", - "i16" : "F(I16)", - "u16" : "F(U16)", - "i32" : "F(I32)", - "u32" : "F(U32)", - "i64" : "F(I64)", - "u64" : "F(U64)", - - "rel8" : "F(Rel8)", - "rel32" : "F(Rel32)", - - "m8" : "M(M8)", - "m16" : "M(M16)", - "m32" : "M(M32)", - "m48" : "M(M48)", - "m64" : "M(M64)", - "m80" : "M(M80)", - "m128" : "M(M128)", - "m256" : "M(M256)", - "m512" : "M(M512)", - "m1024" : "M(M1024)", - "mib" : "M(Mib)", - "mAny" : "M(Any)", - "vm32x" : "M(Vm32x)", - "vm32y" : "M(Vm32y)", - "vm32z" : "M(Vm32z)", - "vm64x" : "M(Vm64x)", - "vm64y" : "M(Vm64y)", - "vm64z" : "M(Vm64z)", - - "memBase" : "M(BaseOnly)", - "memDS" : "M(Ds)", - "memES" : "M(Es)" -}; - -function StringifyArray(a, map) { +function StringifyOpArray(a, map) { var s = ""; for (var i = 0; i < a.length; i++) { const op = a[i]; - if (!hasOwn.call(map, op)) - FAIL(`UNHANDLED OPERAND '${op}'`); - s += (s ? " | " : "") + map[op]; + var mapped = null; + if (typeof map === "function") + mapped = map(op); + else if (hasOwn.call(map, op)) + mapped = map[op]; + else + FATAL(`UNHANDLED OPERAND '${op}'`); + s += (s ? " | " : "") + mapped; } return s ? s : "0"; } @@ -989,11 +1027,11 @@ class OSignature { } equals(other) { - return MapUtils.equals(this.flags, other.flags); + return ObjectUtils.equals(this.flags, other.flags); } xor(other) { - const result = MapUtils.xor(this.flags, other.flags); + const result = ObjectUtils.xor(this.flags, other.flags); return Object.getOwnPropertyNames(result).length === 0 ? null : result; } @@ -1021,32 +1059,18 @@ class OSignature { const index = asmdb.x86.Utils.regIndexOf(k); if (index !== null && index !== -1) { const kind = asmdb.x86.Utils.regKindOf(k); - if (indexKind !== kind) return false; + if (indexKind !== kind) + return false; } } } // Can merge... - for (k in bf) af[k] = true; + for (k in bf) + af[k] = true; return true; } - simplify() { - const flags = this.flags; - - // 32-bit register or 16-bit memory implies also 16-bit reg. - if (flags.r32 && flags.m16) { - flags.r16 = true; - } - - // 32-bit register or 8-bit memory implies also 16-bit and 8-bit reg. - if (flags.r32 && flags.m8) { - flags.r8lo = true; - flags.r8hi = true; - flags.r16 = true; - } - } - toString() { var s = ""; var flags = this.flags; @@ -1072,132 +1096,117 @@ class OSignature { } toAsmJitOpData() { - var oFlags = this.flags; + var opFlags = Object.create(null); + var regMask = 0; - var mFlags = Object.create(null); - var mMemFlags = Object.create(null); - var mExtFlags = Object.create(null); - var sRegMask = 0; - - for (var k in oFlags) { + for (var k in this.flags) { switch (k) { - case "implicit": - case "r8lo" : - case "r8hi" : - case "r16" : - case "r32" : - case "r64" : - case "creg" : - case "dreg" : - case "sreg" : - case "bnd" : - case "st" : - case "k" : - case "mm" : - case "xmm" : - case "ymm" : - case "zmm" : mFlags[k] = true; break; - - case "m8" : - case "m16" : - case "m32" : - case "m48" : - case "m64" : - case "m80" : - case "m128" : - case "m256" : - case "m512" : - case "m1024" : mFlags.mem = true; mMemFlags[k] = true; break; - case "mib" : mFlags.mem = true; mMemFlags.mib = true; break; - case "mem" : mFlags.mem = true; mMemFlags.mAny = true; break; - - case "memBase" : mFlags.mem = true; mMemFlags.memBase = true; break; - case "memDS" : mFlags.mem = true; mMemFlags.memDS = true; break; - case "memES" : mFlags.mem = true; mMemFlags.memES = true; break; - case "memZAX" : mFlags.mem = true; sRegMask |= 1 << 0; break; - case "memZSI" : mFlags.mem = true; sRegMask |= 1 << 6; break; - case "memZDI" : mFlags.mem = true; sRegMask |= 1 << 7; break; - - case "vm32x" : mFlags.vm = true; mMemFlags.vm32x = true; break; - case "vm32y" : mFlags.vm = true; mMemFlags.vm32y = true; break; - case "vm32z" : mFlags.vm = true; mMemFlags.vm32z = true; break; - case "vm64x" : mFlags.vm = true; mMemFlags.vm64x = true; break; - case "vm64y" : mFlags.vm = true; mMemFlags.vm64y = true; break; - case "vm64z" : mFlags.vm = true; mMemFlags.vm64z = true; break; - - case "i4" : - case "u4" : - case "i8" : - case "u8" : - case "i16" : - case "u16" : - case "i32" : - case "u32" : - case "i64" : - case "u64" : mFlags[k] = true; break; - - case "rel8" : - case "rel32" : - mFlags.i32 = true; - mFlags.i64 = true; - mFlags[k] = true; - break; - - case "rel16" : - mFlags.i32 = true; - mFlags.i64 = true; - mFlags.rel32 = true; - break; - - default: { - switch (k) { - case "es" : mFlags.sreg = true; sRegMask |= 1 << 1; break; - case "cs" : mFlags.sreg = true; sRegMask |= 1 << 2; break; - case "ss" : mFlags.sreg = true; sRegMask |= 1 << 3; break; - case "ds" : mFlags.sreg = true; sRegMask |= 1 << 4; break; - case "fs" : mFlags.sreg = true; sRegMask |= 1 << 5; break; - case "gs" : mFlags.sreg = true; sRegMask |= 1 << 6; break; - case "al" : mFlags.r8lo = true; sRegMask |= 1 << 0; break; - case "ah" : mFlags.r8hi = true; sRegMask |= 1 << 0; break; - case "ax" : mFlags.r16 = true; sRegMask |= 1 << 0; break; - case "eax" : mFlags.r32 = true; sRegMask |= 1 << 0; break; - case "rax" : mFlags.r64 = true; sRegMask |= 1 << 0; break; - case "cl" : mFlags.r8lo = true; sRegMask |= 1 << 1; break; - case "ch" : mFlags.r8hi = true; sRegMask |= 1 << 1; break; - case "cx" : mFlags.r16 = true; sRegMask |= 1 << 1; break; - case "ecx" : mFlags.r32 = true; sRegMask |= 1 << 1; break; - case "rcx" : mFlags.r64 = true; sRegMask |= 1 << 1; break; - case "dl" : mFlags.r8lo = true; sRegMask |= 1 << 2; break; - case "dh" : mFlags.r8hi = true; sRegMask |= 1 << 2; break; - case "dx" : mFlags.r16 = true; sRegMask |= 1 << 2; break; - case "edx" : mFlags.r32 = true; sRegMask |= 1 << 2; break; - case "rdx" : mFlags.r64 = true; sRegMask |= 1 << 2; break; - case "bl" : mFlags.r8lo = true; sRegMask |= 1 << 3; break; - case "bh" : mFlags.r8hi = true; sRegMask |= 1 << 3; break; - case "bx" : mFlags.r16 = true; sRegMask |= 1 << 3; break; - case "ebx" : mFlags.r32 = true; sRegMask |= 1 << 3; break; - case "rbx" : mFlags.r64 = true; sRegMask |= 1 << 3; break; - case "si" : mFlags.r16 = true; sRegMask |= 1 << 6; break; - case "esi" : mFlags.r32 = true; sRegMask |= 1 << 6; break; - case "rsi" : mFlags.r64 = true; sRegMask |= 1 << 6; break; - case "di" : mFlags.r16 = true; sRegMask |= 1 << 7; break; - case "edi" : mFlags.r32 = true; sRegMask |= 1 << 7; break; - case "rdi" : mFlags.r64 = true; sRegMask |= 1 << 7; break; - case "st0" : mFlags.st = true; sRegMask |= 1 << 0; break; - case "xmm0" : mFlags.xmm = true; sRegMask |= 1 << 0; break; - case "ymm0" : mFlags.ymm = true; sRegMask |= 1 << 0; break; - default: - console.log(`UNKNOWN OPERAND '${k}'`); - } - } + case "r8lo" : opFlags.RegGpbLo = true; break; + case "r8hi" : opFlags.RegGpbHi = true; break; + case "r16" : opFlags.RegGpw = true; break; + case "r32" : opFlags.RegGpd = true; break; + case "r64" : opFlags.RegGpq = true; break; + case "creg" : opFlags.RegCReg = true; break; + case "dreg" : opFlags.RegDReg = true; break; + case "sreg" : opFlags.RegSReg = true; break; + case "bnd" : opFlags.RegBnd = true; break; + case "st" : opFlags.RegSt = true; break; + case "k" : opFlags.RegKReg = true; break; + case "mm" : opFlags.RegMm = true; break; + case "xmm" : opFlags.RegXmm = true; break; + case "ymm" : opFlags.RegYmm = true; break; + case "zmm" : opFlags.RegZmm = true; break; + case "tmm" : opFlags.RegTmm = true; break; + + case "m8" : opFlags.Mem8 = true; break; + case "m16" : opFlags.Mem16 = true; break; + case "m32" : opFlags.Mem32 = true; break; + case "m48" : opFlags.Mem48 = true; break; + case "m64" : opFlags.Mem64 = true; break; + case "m80" : opFlags.Mem80 = true; break; + case "m128" : opFlags.Mem128 = true; break; + case "m256" : opFlags.Mem256 = true; break; + case "m512" : opFlags.Mem512 = true; break; + case "m1024" : opFlags.Mem1024 = true; break; + + case "mem" : opFlags.MemUnspecified = true; break; + case "mib" : opFlags.MemUnspecified = true; opFlags.FlagMib = true; break; + case "tmem" : opFlags.MemUnspecified = true; opFlags.FlagTMem = true; break; + + case "memBase" : opFlags.FlagMemBase = true; break; + case "memDS" : opFlags.FlagMemDs = true; break; + case "memES" : opFlags.FlagMemEs = true; break; + case "memZAX" : regMask |= 1 << 0; break; + case "memZSI" : regMask |= 1 << 6; break; + case "memZDI" : regMask |= 1 << 7; break; + + case "vm32x" : opFlags.Vm32x = true; break; + case "vm32y" : opFlags.Vm32y = true; break; + case "vm32z" : opFlags.Vm32z = true; break; + case "vm64x" : opFlags.Vm64x = true; break; + case "vm64y" : opFlags.Vm64y = true; break; + case "vm64z" : opFlags.Vm64z = true; break; + + case "i4" : opFlags.ImmI4 = true; break; + case "u4" : opFlags.ImmU4 = true; break; + case "i8" : opFlags.ImmI8 = true; break; + case "u8" : opFlags.ImmU8 = true; break; + case "i16" : opFlags.ImmI16 = true; break; + case "u16" : opFlags.ImmU16 = true; break; + case "i32" : opFlags.ImmI32 = true; break; + case "u32" : opFlags.ImmU32 = true; break; + case "i64" : opFlags.ImmI64 = true; break; + case "u64" : opFlags.ImmU64 = true; break; + + case "rel8" : opFlags.ImmI32 = true; opFlags.ImmI64 = true; opFlags.Rel8 = true; break; + case "rel16" : opFlags.ImmI32 = true; opFlags.ImmI64 = true; opFlags.Rel32 = true; break; + case "rel32" : opFlags.ImmI32 = true; opFlags.ImmI64 = true; opFlags.Rel32 = true; break; + + case "es" : opFlags.RegSReg = true; regMask |= 1 << 1; break; + case "cs" : opFlags.RegSReg = true; regMask |= 1 << 2; break; + case "ss" : opFlags.RegSReg = true; regMask |= 1 << 3; break; + case "ds" : opFlags.RegSReg = true; regMask |= 1 << 4; break; + case "fs" : opFlags.RegSReg = true; regMask |= 1 << 5; break; + case "gs" : opFlags.RegSReg = true; regMask |= 1 << 6; break; + case "al" : opFlags.RegGpbLo = true; regMask |= 1 << 0; break; + case "ah" : opFlags.RegGpbHi = true; regMask |= 1 << 0; break; + case "ax" : opFlags.RegGpw = true; regMask |= 1 << 0; break; + case "eax" : opFlags.RegGpd = true; regMask |= 1 << 0; break; + case "rax" : opFlags.RegGpq = true; regMask |= 1 << 0; break; + case "cl" : opFlags.RegGpbLo = true; regMask |= 1 << 1; break; + case "ch" : opFlags.RegGpbHi = true; regMask |= 1 << 1; break; + case "cx" : opFlags.RegGpw = true; regMask |= 1 << 1; break; + case "ecx" : opFlags.RegGpd = true; regMask |= 1 << 1; break; + case "rcx" : opFlags.RegGpq = true; regMask |= 1 << 1; break; + case "dl" : opFlags.RegGpbLo = true; regMask |= 1 << 2; break; + case "dh" : opFlags.RegGpbHi = true; regMask |= 1 << 2; break; + case "dx" : opFlags.RegGpw = true; regMask |= 1 << 2; break; + case "edx" : opFlags.RegGpd = true; regMask |= 1 << 2; break; + case "rdx" : opFlags.RegGpq = true; regMask |= 1 << 2; break; + case "bl" : opFlags.RegGpbLo = true; regMask |= 1 << 3; break; + case "bh" : opFlags.RegGpbHi = true; regMask |= 1 << 3; break; + case "bx" : opFlags.RegGpw = true; regMask |= 1 << 3; break; + case "ebx" : opFlags.RegGpd = true; regMask |= 1 << 3; break; + case "rbx" : opFlags.RegGpq = true; regMask |= 1 << 3; break; + case "si" : opFlags.RegGpw = true; regMask |= 1 << 6; break; + case "esi" : opFlags.RegGpd = true; regMask |= 1 << 6; break; + case "rsi" : opFlags.RegGpq = true; regMask |= 1 << 6; break; + case "di" : opFlags.RegGpw = true; regMask |= 1 << 7; break; + case "edi" : opFlags.RegGpd = true; regMask |= 1 << 7; break; + case "rdi" : opFlags.RegGpq = true; regMask |= 1 << 7; break; + case "st0" : opFlags.RegSt = true; regMask |= 1 << 0; break; + case "xmm0" : opFlags.RegXmm = true; regMask |= 1 << 0; break; + case "ymm0" : opFlags.RegYmm = true; regMask |= 1 << 0; break; + + case "implicit": opFlags.FlagImplicit = true; break; + + default: + console.log(`UNKNOWN OPERAND '${k}'`); } } - const sFlags = StringifyArray(ArrayUtils.sorted(mFlags , cmpOp), OpToAsmJitOp); - const sMemFlags = StringifyArray(ArrayUtils.sorted(mMemFlags, cmpOp), OpToAsmJitOp); - const sExtFlags = StringifyArray(ArrayUtils.sorted(mExtFlags, cmpOp), OpToAsmJitOp); - - return `ROW(${sFlags || 0}, ${sMemFlags || 0}, ${sExtFlags || 0}, ${decToHex(sRegMask, 2)})`; + const outputFlags = StringifyOpArray(ArrayUtils.sorted(opFlags, cmpOp), function(k) { return `F(${k})`; }); + return `ROW(${outputFlags || 0}, ${decToHex(regMask, 2)})`; } } @@ -1210,11 +1219,6 @@ class ISignature extends Array { this.implicit = 0; // Number of implicit operands. } - simplify() { - for (var i = 0; i < this.length; i++) - this[i].simplify(); - } - opEquals(other) { const len = this.length; if (len !== other.length) return false; @@ -1228,14 +1232,14 @@ class ISignature extends Array { mergeWith(other) { // If both architectures are the same, it's fine to merge. - var ok = this.x86 === other.x86 && this.x64 === other.x64; + const sameArch = this.x86 === other.x86 && this.x64 === other.x64; // If the first arch is [X86|X64] and the second [X64] it's also fine. - if (!ok && this.x86 && this.x64 && !other.x86 && other.x64) - ok = true; + // if (!ok && this.x86 && this.x64 && !other.x86 && other.x64) + // ok = true; // It's not ok if both signatures have different number of implicit operands. - if (!ok || this.implicit !== other.implicit) + if (!sameArch || this.implicit !== other.implicit) return false; // It's not ok if both signatures have different number of operands. @@ -1243,8 +1247,8 @@ class ISignature extends Array { if (len !== other.length) return false; - var xorIndex = -1; - for (var i = 0; i < len; i++) { + let xorIndex = -1; + for (let i = 0; i < len; i++) { const xor = this[i].xor(other[i]); if (xor === null) continue; @@ -1255,12 +1259,9 @@ class ISignature extends Array { } // Bail if mergeWidth at operand-level failed. - if (xorIndex !== -1 && !this[xorIndex].mergeWith(other[xorIndex])) + if (xorIndex === -1 || !this[xorIndex].mergeWith(other[xorIndex])) return false; - this.x86 = this.x86 || other.x86; - this.x64 = this.x64 || other.x64; - return true; } @@ -1271,14 +1272,14 @@ class ISignature extends Array { class SignatureArray extends Array { // Iterate over all signatures and check which operands don't need explicit memory size. - calcImplicitMemSize() { + calcImplicitMemSize(instName) { // Calculates a hash-value (aka key) of all register operands specified by `regOps` in `inst`. function keyOf(inst, regOps) { var s = ""; for (var i = 0; i < inst.length; i++) { const op = inst[i]; if (regOps & (1 << i)) - s += "{" + ArrayUtils.sorted(MapUtils.and(op.flags, RegOp)).join("|") + "}"; + s += "{" + ArrayUtils.sorted(ObjectUtils.and(op.flags, RegOp)).join("|") + "}"; } return s || "?"; } @@ -1297,7 +1298,7 @@ class SignatureArray extends Array { // Check if this instruction signature has a memory operand of explicit size. for (i = 0; i < len; i++) { const aOp = aInst[i]; - const mem = MapUtils.firstOf(aOp.flags, MemOp); + const mem = ObjectUtils.findKey(aOp.flags, MemOp); if (mem) { // Stop if the memory operand has implicit-size or if there is more than one. @@ -1310,7 +1311,7 @@ class SignatureArray extends Array { memPos = i; } } - else if (MapUtils.anyOf(aOp.flags, RegOp)) { + else if (ObjectUtils.hasAny(aOp.flags, RegOp)) { // Doesn't consider 'r/m' as we already checked 'm'. regOps |= (1 << i); } @@ -1335,7 +1336,7 @@ class SignatureArray extends Array { for (i = 0; i < len; i++) { if (i === memPos) continue; - const reg = MapUtils.anyOf(bInst[i].flags, RegOp); + const reg = ObjectUtils.hasAny(bInst[i].flags, RegOp); if (regOps & (1 << i)) hasMatch &= reg; else if (reg) @@ -1346,7 +1347,7 @@ class SignatureArray extends Array { const bOp = bInst[memPos]; if (bOp.flags.mem) continue; - const mem = MapUtils.firstOf(bOp.flags, MemOp); + const mem = ObjectUtils.findKey(bOp.flags, MemOp); if (mem === memOp) { sameSizeSet.push(bInst); } @@ -1386,6 +1387,8 @@ class SignatureArray extends Array { // then keep this implicit as it won't do any harm. These instructions // cannot be mixed and it will make implicit the 32-bit one in cases // where X64 introduced 64-bit ones like `cvtsi2ss`. + if (!/^(bndcl|bndcn|bndcu|ptwrite|(v)?cvtsi2ss|(v)?cvtsi2sd|vcvtusi2ss|vcvtusi2sd)$/.test(instName)) + implicit = false; } else { implicit = false; @@ -1398,7 +1401,9 @@ class SignatureArray extends Array { // Patch all instructions to accept implicit-size memory operand. for (bIndex = 0; bIndex < sameSizeSet.length; bIndex++) { const bInst = sameSizeSet[bIndex]; - if (implicit) bInst[memPos].flags.mem = true; + if (implicit) { + bInst[memPos].flags.mem = true; + } if (!implicit) DEBUG(`${this.name}: Explicit: ${bInst}`); @@ -1406,21 +1411,21 @@ class SignatureArray extends Array { } } - simplify() { - for (var i = 0; i < this.length; i++) - this[i].simplify(); - } - compact() { - for (var i = 0; i < this.length; i++) { - var row = this[i]; - var j = i + 1; - while (j < this.length) { - if (row.mergeWith(this[j])) { - this.splice(j, 1); - continue; + var didSomething = true; + while (didSomething) { + didSomething = false; + for (var i = 0; i < this.length; i++) { + var row = this[i]; + var j = i + 1; + while (j < this.length) { + if (row.mergeWith(this[j])) { + this.splice(j, 1); + didSomething = true; + continue; + } + j++; } - j++; } } } @@ -1433,14 +1438,7 @@ class SignatureArray extends Array { class InstSignatureTable extends core.Task { constructor() { super("InstSignatureTable"); - this.maxOpRows = 0; - this.opBlackList = { - "moff8" : true, - "moff16": true, - "moff32": true, - "moff64": true - }; } run() { @@ -1458,7 +1456,7 @@ class InstSignatureTable extends core.Task { const oSignatureArr = []; // Must be first to be assigned to zero. - const oSignatureNone = "ROW(0, 0, 0, 0xFF)"; + const oSignatureNone = "ROW(0, 0xFF)"; oSignatureMap[oSignatureNone] = [0]; oSignatureArr.push(oSignatureNone); @@ -1555,28 +1553,28 @@ class InstSignatureTable extends core.Task { }); } - var s = `#define ROW(count, x86, x64, implicit, o0, o1, o2, o3, o4, o5) \\\n` + - ` { count, (x86 ? uint8_t(InstDB::kModeX86) : uint8_t(0)) | \\\n` + - ` (x64 ? uint8_t(InstDB::kModeX64) : uint8_t(0)) , \\\n` + - ` implicit, \\\n` + - ` 0, \\\n` + - ` { o0, o1, o2, o3, o4, o5 } \\\n` + + var s = `#define ROW(count, x86, x64, implicit, o0, o1, o2, o3, o4, o5) \\\n` + + ` { count, uint8_t(x86 ? uint8_t(InstDB::Mode::kX86) : uint8_t(0)) | \\\n` + + ` (x64 ? uint8_t(InstDB::Mode::kX64) : uint8_t(0)) , \\\n` + + ` implicit, \\\n` + + ` 0, \\\n` + + ` { o0, o1, o2, o3, o4, o5 } \\\n` + ` }\n` + StringUtils.makeCxxArrayWithComment(iSignatureArr, "const InstDB::InstSignature InstDB::_instSignatureTable[]") + `#undef ROW\n` + `\n` + - `#define ROW(flags, mFlags, extFlags, regId) { uint32_t(flags), uint16_t(mFlags), uint8_t(extFlags), uint8_t(regId) }\n` + - `#define F(VAL) InstDB::kOp##VAL\n` + - `#define M(VAL) InstDB::kMemOp##VAL\n` + + `#define ROW(opFlags, regId) { opFlags, uint8_t(regId) }\n` + + `#define F(VAL) uint64_t(InstDB::OpFlags::k##VAL)\n` + StringUtils.makeCxxArray(oSignatureArr, "const InstDB::OpSignature InstDB::_opSignatureTable[]") + - `#undef M\n` + `#undef F\n` + `#undef ROW\n`; this.inject("InstSignatureTable", disclaimer(s), oSignatureArr.length * 8 + iSignatureArr.length * 8); } makeSignatures(dbInsts) { + const instName = dbInsts.length ? dbInsts[0].name : ""; const signatures = new SignatureArray(); + for (var i = 0; i < dbInsts.length; i++) { const inst = dbInsts[i]; const ops = inst.operands; @@ -1614,17 +1612,23 @@ class InstSignatureTable extends core.Task { var imm = iop.imm; var rel = iop.rel; - // Terminate if this operand is something asmjit doesn't support - // and skip all instructions having implicit `imm` operand of `1`, - // which are handled fine by asmjit. - if (this.opBlackList[mem] === true || iop.immValue !== null) + // Skip all instructions having implicit `imm` operand of `1`. + if (iop.immValue !== null) + break; + + // Shorten the number of signatures of 'mov' instruction. + if (inst.name === "mov" && mem.startsWith("moff")) break; - if (reg === "r8") reg = "r8lo"; if (reg === "seg") reg = "sreg"; if (reg === "st(i)") reg = "st"; if (reg === "st(0)") reg = "st0"; + if (mem === "moff8") mem = "m8"; + if (mem === "moff16") mem = "m16"; + if (mem === "moff32") mem = "m32"; + if (mem === "moff64") mem = "m64"; + if (mem === "m32fp") mem = "m32"; if (mem === "m64fp") mem = "m64"; if (mem === "m80fp") mem = "m80"; @@ -1654,8 +1658,31 @@ class InstSignatureTable extends core.Task { op.flags.implicit = true; } - const seg = iop.memSeg; + const seg = iop.memSegment; if (seg) { + switch (inst.name) { + case "insb": op.flags.m8 = true; break; + case "insw": op.flags.m16 = true; break; + case "insd": op.flags.m32 = true; break; + case "outsb": op.flags.m8 = true; break; + case "outsw": op.flags.m16 = true; break; + case "outsd": op.flags.m32 = true; break; + case "clzero": op.flags.mem = true; op.flags.m512 = true; break; + case "enqcmd": op.flags.mem = true; op.flags.m512 = true; break; + case "enqcmds": op.flags.mem = true; op.flags.m512 = true; break; + case "movdir64b": op.flags.mem = true; op.flags.m512 = true; break; + case "maskmovq": op.flags.mem = true; op.flags.m64 = true; break; + case "maskmovdqu": op.flags.mem = true; op.flags.m128 = true; break; + case "vmaskmovdqu": op.flags.mem = true; op.flags.m128 = true; break; + case "monitor": op.flags.mem = true; break; + case "monitorx": op.flags.mem = true; break; + case "umonitor": op.flags.mem = true; break; + default: console.log(`UNKNOWN MEM IN INSTRUCTION '${inst.name}'`); break; + } + + if (iop.memRegOnly) + reg = iop.memRegOnly; + if (seg === "ds") op.flags.memDS = true; if (seg === "es") op.flags.memES = true; if (reg === "reg") { op.flags.memBase = true; } @@ -1666,19 +1693,39 @@ class InstSignatureTable extends core.Task { if (reg === "zdi") { op.flags.memBase = true; op.flags.memZDI = true; } } else if (reg) { - op.flags[reg] = true; - if (reg === "r8lo") op.flags.r8hi = true; + if (reg == "r8") { + op.flags["r8lo"] = true; + + if (!inst.w || inst.w === "W0") + op.flags["r8hi"] = true; + } + else { + op.flags[reg] = true; + } } + if (mem) { op.flags[mem] = true; - // Exception: Allow LEA to use any memory size. - if (inst.name === "lea") MapUtils.add(op.flags, MemOp); + // HACK: Allow LEA to use any memory size. + if (/^(lea)$/.test(inst.name)) { + op.flags.mem = true; + Object.assign(op.flags, MemOp); + } + + // HACK: These instructions specify explicit memory size, but it's just informational. + if (/^(call|enqcmd|enqcmds|lcall|ljmp|movdir64b)$/.test(inst.name)) { + op.flags.mem = true; + } } + if (imm) { if (iop.immSign === "any" || iop.immSign === "signed" ) op.flags["i" + imm] = true; if (iop.immSign === "any" || iop.immSign === "unsigned") op.flags["u" + imm] = true; } - if (rel) op.flags["rel" + rel] = true; + + if (rel) { + op.flags["rel" + rel] = true; + } row.push(op); } @@ -1689,30 +1736,28 @@ class InstSignatureTable extends core.Task { } } - signatures.calcImplicitMemSize(); - signatures.simplify(); - signatures.compact(); + if (signatures.length && GenUtils.canUseImplicitMemSize(instName)) + signatures.calcImplicitMemSize(instName); - signatures.simplify(); signatures.compact(); - return signatures; } } // ============================================================================ -// [tablegen.x86.InstCommonInfoTableB] +// [tablegen.x86.AdditionalInfoTable] // ============================================================================ -class InstCommonInfoTableB extends core.Task { +class AdditionalInfoTable extends core.Task { constructor() { - super("InstCommonInfoTableB"); + super("AdditionalInfoTable"); } run() { const insts = this.ctx.insts; - const commonTableB = new IndexedArray(); const rwInfoTable = new IndexedArray(); + const instFlagsTable = new IndexedArray(); + const additionaInfoTable = new IndexedArray(); // If the instruction doesn't read any flags it should point to the first index. rwInfoTable.addIndexed(`{ 0, 0 }`); @@ -1726,19 +1771,62 @@ class InstCommonInfoTableB extends core.Task { var [r, w] = this.rwFlagsOf(dbInsts); const rData = r.map(function(flag) { return `FLAG(${flag})`; }).join(" | ") || "0"; const wData = w.map(function(flag) { return `FLAG(${flag})`; }).join(" | ") || "0"; - const rwDataIndex = rwInfoTable.addIndexed(`{ ${rData}, ${wData} }`); + const instFlags = Object.create(null); + + switch (inst.name) { + case "kmovb": + case "kmovd": + case "kmovq": + case "kmovw": + case "mov": + case "movq": + case "movsd": + case "movss": + case "movapd": + case "movaps": + case "movdqa": + case "movdqu": + case "movupd": + case "movups": + case "vmovapd": + case "vmovaps": + case "vmovdqa": + case "vmovdqa8": + case "vmovdqa16": + case "vmovdqa32": + case "vmovdqa64": + case "vmovdqu": + case "vmovdqu8": + case "vmovdqu16": + case "vmovdqu32": + case "vmovdqu64": + case "vmovq": + case "vmovsd": + case "vmovss": + case "vmovupd": + case "vmovups": + instFlags["MovOp"] = true; + break; + } + + const instFlagsIndex = instFlagsTable.addIndexed("InstRWFlags(" + StringUtils.formatCppFlags(instFlags, (f) => { return `FLAG(${f})`; }, "FLAG(None)") + ")"); + const rwInfoIndex = rwInfoTable.addIndexed(`{ ${rData}, ${wData} }`); - inst.commomInfoIndexB = commonTableB.addIndexed(`{ { ${features} }, ${rwDataIndex}, 0 }`); + inst.additionalInfoIndex = additionaInfoTable.addIndexed(`{ ${instFlagsIndex}, ${rwInfoIndex}, { ${features} } }`); }); - var s = `#define EXT(VAL) uint32_t(Features::k##VAL)\n` + - `const InstDB::CommonInfoTableB InstDB::_commonInfoTableB[] = {\n${StringUtils.format(commonTableB, kIndent, true)}\n};\n` + + var s = `#define EXT(VAL) uint32_t(CpuFeatures::X86::k##VAL)\n` + + `const InstDB::AdditionalInfo InstDB::_additionalInfoTable[] = {\n${StringUtils.format(additionaInfoTable, kIndent, true)}\n};\n` + `#undef EXT\n` + `\n` + - `#define FLAG(VAL) uint32_t(Status::k##VAL)\n` + + `#define FLAG(VAL) uint32_t(CpuRWFlags::kX86_##VAL)\n` + `const InstDB::RWFlagsInfoTable InstDB::_rwFlagsInfoTable[] = {\n${StringUtils.format(rwInfoTable, kIndent, true)}\n};\n` + + `#undef FLAG\n` + + `\n` + + `#define FLAG(VAL) uint32_t(InstRWFlags::k##VAL)\n` + + `const InstRWFlags InstDB::_instFlagsTable[] = {\n${StringUtils.format(instFlagsTable, kIndent, true)}\n};\n` + `#undef FLAG\n`; - this.inject("InstCommonInfoTableB", disclaimer(s), commonTableB.length * 8 + rwInfoTable.length * 8); + this.inject("AdditionalInfoTable", disclaimer(s), additionaInfoTable.length * 8 + rwInfoTable.length * 8 + instFlagsTable.length * 4); } rwFlagsOf(dbInsts) { @@ -1752,7 +1840,7 @@ class InstCommonInfoTableB extends core.Task { if (dbInst.name === "mov") continue; - const specialRegs = dbInst.specialRegs; + const regs = dbInst.io; // Mov is a special case, moving to/from control regs makes flags undefined, // which we don't want to have in `X86InstDB::operationData`. This is, thus, @@ -1760,28 +1848,28 @@ class InstCommonInfoTableB extends core.Task { if (dbInst.name === "mov") continue; - for (var specialReg in specialRegs) { + for (var reg in regs) { var flag = ""; - switch (specialReg) { - case "FLAGS.CF": flag = "CF"; break; - case "FLAGS.OF": flag = "OF"; break; - case "FLAGS.SF": flag = "SF"; break; - case "FLAGS.ZF": flag = "ZF"; break; - case "FLAGS.AF": flag = "AF"; break; - case "FLAGS.PF": flag = "PF"; break; - case "FLAGS.DF": flag = "DF"; break; - case "FLAGS.IF": flag = "IF"; break; - //case "FLAGS.TF": flag = "TF"; break; - case "FLAGS.AC": flag = "AC"; break; - case "X86SW.C0": flag = "C0"; break; - case "X86SW.C1": flag = "C1"; break; - case "X86SW.C2": flag = "C2"; break; - case "X86SW.C3": flag = "C3"; break; + switch (reg) { + case "CF": flag = "CF"; break; + case "OF": flag = "OF"; break; + case "SF": flag = "SF"; break; + case "ZF": flag = "ZF"; break; + case "AF": flag = "AF"; break; + case "PF": flag = "PF"; break; + case "DF": flag = "DF"; break; + case "IF": flag = "IF"; break; + //case "TF": flag = "TF"; break; + case "AC": flag = "AC"; break; + case "C0": flag = "C0"; break; + case "C1": flag = "C1"; break; + case "C2": flag = "C2"; break; + case "C3": flag = "C3"; break; default: continue; } - switch (specialRegs[specialReg]) { + switch (regs[reg]) { case "R": r[flag] = true; break; @@ -1806,7 +1894,7 @@ class InstCommonInfoTableB extends core.Task { // [tablegen.x86.InstRWInfoTable] // ============================================================================ -const NOT_MEM_AMBIGUOUS = MapUtils.arrayToMap([ +const NOT_MEM_AMBIGUOUS = ArrayUtils.toDict([ "call", "movq" ]); @@ -1814,17 +1902,23 @@ class InstRWInfoTable extends core.Task { constructor() { super("InstRWInfoTable"); - this.rwInfoIndex = []; - this.rwInfoTable = new IndexedArray(); + this.rwInfoIndexA = []; + this.rwInfoIndexB = []; + this.rwInfoTableA = new IndexedArray(); + this.rwInfoTableB = new IndexedArray(); + this.rmInfoTable = new IndexedArray(); this.opInfoTable = new IndexedArray(); - const _ = null; this.rwCategoryByName = { "imul" : "Imul", "mov" : "Mov", + "movabs" : "Movabs", "movhpd" : "Movh64", "movhps" : "Movh64", + "punpcklbw" : "Punpcklxx", + "punpckldq" : "Punpcklxx", + "punpcklwd" : "Punpcklxx", "vmaskmovpd": "Vmaskmov", "vmaskmovps": "Vmaskmov", "vmovddup" : "Vmovddup", @@ -1833,37 +1927,39 @@ class InstRWInfoTable extends core.Task { "vpmaskmovd": "Vmaskmov", "vpmaskmovq": "Vmaskmov" }; + + const _ = null; this.rwCategoryByData = { Vmov1_8: [ - [{access: "W", flags: {}, fixed: -1, index: 0, width: 8}, {access: "R", flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width: 16}, {access: "R", flags: {}, fixed: -1, index: 0, width:128},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width: 32}, {access: "R", flags: {}, fixed: -1, index: 0, width:256},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", flags: {}, fixed: -1, index: 0, width:512},_,_,_,_] + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 8}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 16}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:128},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 32}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:256},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:512},_,_,_,_] ], Vmov1_4: [ - [{access: "W", flags: {}, fixed: -1, index: 0, width: 32}, {access: "R", flags: {}, fixed: -1, index: 0, width:128},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", flags: {}, fixed: -1, index: 0, width:256},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width:128}, {access: "R", flags: {}, fixed: -1, index: 0, width:512},_,_,_,_] + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 32}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:128},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:256},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width:128}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:512},_,_,_,_] ], Vmov1_2: [ - [{access: "W", flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", flags: {}, fixed: -1, index: 0, width:128},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width:128}, {access: "R", flags: {}, fixed: -1, index: 0, width:256},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width:256}, {access: "R", flags: {}, fixed: -1, index: 0, width:512},_,_,_,_] + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 64}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:128},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width:128}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:256},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width:256}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:512},_,_,_,_] ], Vmov2_1: [ - [{access: "W", flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", flags: {}, fixed: -1, index: 0, width:128},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", flags: {}, fixed: -1, index: 0, width:256},_,_,_,_] + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:128},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:256},_,_,_,_] ], Vmov4_1: [ - [{access: "W", flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", flags: {}, fixed: -1, index: 0, width: 32},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", flags: {}, fixed: -1, index: 0, width:128},_,_,_,_] + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 32},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width:128},_,_,_,_] ], Vmov8_1: [ - [{access: "W", flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", flags: {}, fixed: -1, index: 0, width: 16},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", flags: {}, fixed: -1, index: 0, width: 32},_,_,_,_], - [{access: "W", flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_] + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 128}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 16},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 256}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 32},_,_,_,_], + [{access: "W", clc: 0, flags: {}, fixed: -1, index: 0, width: 512}, {access: "R", clc: 0, flags: {}, fixed: -1, index: 0, width: 64},_,_,_,_] ] }; } @@ -1871,20 +1967,21 @@ class InstRWInfoTable extends core.Task { run() { const insts = this.ctx.insts; - const noRmInfo = CxxUtils.struct( + const noRmInfo = StringUtils.formatCppStruct( "InstDB::RWInfoRm::kCategory" + "None".padEnd(10), StringUtils.decToHex(0, 2), String(0).padEnd(2), - CxxUtils.flags({}), + StringUtils.formatCppFlags({}), "0" ); - const noOpInfo = CxxUtils.struct( + const noOpInfo = StringUtils.formatCppStruct( "0x0000000000000000u", "0x0000000000000000u", "0xFF", - CxxUtils.struct(0), - "0" + "0", + StringUtils.formatCppStruct(0), + "OpRWFlags::kNone" ); this.rmInfoTable.addIndexed(noRmInfo); @@ -1900,8 +1997,8 @@ class InstRWInfoTable extends core.Task { const o2Insts = dbInsts.filter((inst) => { return inst.operands.length === 2; }); const oxInsts = dbInsts.filter((inst) => { return inst.operands.length !== 2; }); - const rwInfoArray = [this.rwInfo(o2Insts), this.rwInfo(oxInsts)]; - const rmInfoArray = [this.rmInfo(o2Insts), this.rmInfo(oxInsts)]; + const rwInfoArray = [this.rwInfo(inst, o2Insts), this.rwInfo(inst, oxInsts)]; + const rmInfoArray = [this.rmInfo(inst, o2Insts), this.rmInfo(inst, oxInsts)]; for (var i = 0; i < 2; i++) { const rwInfo = rwInfoArray[i]; @@ -1922,53 +2019,70 @@ class InstRWInfoTable extends core.Task { if (opAcc === "R") flags.Read = true; if (opAcc === "W") flags.Write = true; if (opAcc === "X") flags.RW = true; - Lang.merge(flags, op.flags); + ObjectUtils.merge(flags, op.flags); const rIndex = opAcc === "X" || opAcc === "R" ? op.index : -1; const rWidth = opAcc === "X" || opAcc === "R" ? op.width : -1; const wIndex = opAcc === "X" || opAcc === "W" ? op.index : -1; const wWidth = opAcc === "X" || opAcc === "W" ? op.width : -1; - const opData = CxxUtils.struct( + const consecutiveLeadCount = op.clc; + + const opData = StringUtils.formatCppStruct( this.byteMaskFromBitRanges([{ start: rIndex, end: rIndex + rWidth - 1 }]) + "u", this.byteMaskFromBitRanges([{ start: wIndex, end: wIndex + wWidth - 1 }]) + "u", StringUtils.decToHex(op.fixed === -1 ? 0xFF : op.fixed, 2), - CxxUtils.struct(0), - CxxUtils.flags(flags, function(flag) { return "OpRWInfo::k" + flag; }) + String(consecutiveLeadCount), + StringUtils.formatCppStruct(0), + StringUtils.formatCppFlags(flags, function(flag) { return "OpRWFlags::k" + flag; }, "OpRWFlags::kNone") ); rwOpsIndex.push(this.opInfoTable.addIndexed(opData)); } - const rmData = CxxUtils.struct( + const rmData = StringUtils.formatCppStruct( "InstDB::RWInfoRm::kCategory" + rmInfo.category.padEnd(10), StringUtils.decToHex(rmInfo.rmIndexes, 2), String(Math.max(rmInfo.memFixed, 0)).padEnd(2), - CxxUtils.flags({ "InstDB::RWInfoRm::kFlagAmbiguous": Boolean(rmInfo.memAmbiguous) }), - rmInfo.memExtension === "None" ? "0" : "Features::k" + rmInfo.memExtension + StringUtils.formatCppFlags({ + "InstDB::RWInfoRm::kFlagAmbiguous": Boolean(rmInfo.memAmbiguous), + "InstDB::RWInfoRm::kFlagMovssMovsd": Boolean(inst.name === "movss" || inst.name === "movsd"), + "InstDB::RWInfoRm::kFlagPextrw": Boolean(inst.name === "pextrw"), + "InstDB::RWInfoRm::kFlagFeatureIfRMI": Boolean(rmInfo.memExtensionIfRMI) + }), + rmInfo.memExtension === "None" ? "0" : "uint32_t(CpuFeatures::X86::k" + rmInfo.memExtension + ")" ); - const rwData = CxxUtils.struct( + const rwData = StringUtils.formatCppStruct( "InstDB::RWInfo::kCategory" + rwInfo.category.padEnd(10), String(this.rmInfoTable.addIndexed(rmData)).padEnd(2), - CxxUtils.struct(...(rwOpsIndex.map(function(item) { return String(item).padEnd(2); }))) + StringUtils.formatCppStruct(...(rwOpsIndex.map(function(item) { return String(item).padEnd(2); }))) ); - this.rwInfoIndex.push(this.rwInfoTable.addIndexed(rwData)); + if (i == 0) + this.rwInfoIndexA.push(this.rwInfoTableA.addIndexed(rwData)); + else + this.rwInfoIndexB.push(this.rwInfoTableB.addIndexed(rwData)); } }); var s = ""; - s += "const uint8_t InstDB::rwInfoIndex[Inst::_kIdCount * 2] = {\n" + StringUtils.format(this.rwInfoIndex, kIndent, -1) + "\n};\n"; + s += "const uint8_t InstDB::rwInfoIndexA[Inst::_kIdCount] = {\n" + StringUtils.format(this.rwInfoIndexA, kIndent, -1) + "\n};\n"; s += "\n"; - s += "const InstDB::RWInfo InstDB::rwInfo[] = {\n" + StringUtils.format(this.rwInfoTable, kIndent, true) + "\n};\n"; + s += "const uint8_t InstDB::rwInfoIndexB[Inst::_kIdCount] = {\n" + StringUtils.format(this.rwInfoIndexB, kIndent, -1) + "\n};\n"; + s += "\n"; + s += "const InstDB::RWInfo InstDB::rwInfoA[] = {\n" + StringUtils.format(this.rwInfoTableA, kIndent, true) + "\n};\n"; + s += "\n"; + s += "const InstDB::RWInfo InstDB::rwInfoB[] = {\n" + StringUtils.format(this.rwInfoTableB, kIndent, true) + "\n};\n"; s += "\n"; s += "const InstDB::RWInfoOp InstDB::rwInfoOp[] = {\n" + StringUtils.format(this.opInfoTable, kIndent, true) + "\n};\n"; s += "\n"; s += "const InstDB::RWInfoRm InstDB::rwInfoRm[] = {\n" + StringUtils.format(this.rmInfoTable, kIndent, true) + "\n};\n"; - const size = this.rwInfoIndex.length + - this.rwInfoTable.length * 8 + + const size = this.rwInfoIndexA.length + + this.rwInfoIndexB.length + + this.rwInfoTableA.length * 8 + + this.rwInfoTableB.length * 8 + this.rmInfoTable.length * 4 + this.opInfoTable.length * 24; @@ -1990,7 +2104,7 @@ class InstRWInfoTable extends core.Task { for (var j = start; j <= end; j++) { const bytePos = j >> 3; if (bytePos < 0 || bytePos >= arr.length) - FAIL(`Range ${start}:${end} cannot be used to create a byte-mask`); + FATAL(`Range ${start}:${end} cannot be used to create a byte-mask`); arr[bytePos] = 1; } } @@ -2006,7 +2120,9 @@ class InstRWInfoTable extends core.Task { // Read/Write Info // --------------- - rwInfo(dbInsts) { + rwInfo(asmInst, dbInsts) { + const self = this; + function nullOps() { return [null, null, null, null, null, null]; } @@ -2017,8 +2133,9 @@ class InstRWInfoTable extends core.Task { return { access: op.read && op.write ? "X" : op.read ? "R" : op.write ? "W" : "?", + clc: 0, flags: {}, - fixed: GenUtils.fixedRegOf(op.reg), + fixed: GenUtils.fixedRegOf(op), index: op.rwxIndex, width: op.rwxWidth }; @@ -2038,27 +2155,53 @@ class InstRWInfoTable extends core.Task { const opSize = op.isReg() ? op.regSize : op.memSize; var d = { access: op.read && op.write ? "X" : op.read ? "R" : op.write ? "W" : "?", + clc: 0, flags: {}, fixed: -1, index: -1, width: -1 }; - if (op.isReg()) - d.fixed = GenUtils.fixedRegOf(op.reg); - else - d.fixed = GenUtils.fixedRegOf(op.mem); + if (op.consecutiveLeadCount) + d.clc = op.consecutiveLeadCount; + + const instName = dbInst.name; + // NOTE: Avoid push/pop here as PUSH/POP has many variations for segment registers, + // which would set 'd.fixed' field even for GP variation of the instuction. + if (instName !== "push" && instName !== "pop") { + d.fixed = GenUtils.fixedRegOf(op); + } + + switch (instName) { + case "vfcmaddcph": + case "vfmaddcph": + case "vfcmaddcsh": + case "vfmaddcsh": + case "vfcmulcsh": + case "vfmulcsh": + case "vfcmulcph": + case "vfmulcph": + if (j === 0) + d.flags.Unique = true; + break; + } if (op.zext) d.flags.ZExt = true; + if (op.regIndexRel) + d.flags.Consecutive = true; + + for (var k in self.rwOpFlagsForInstruction(asmInst.name, j)) + d.flags[k] = true; + if ((step === -1 || step === j) || op.rwxIndex !== 0 || op.rwxWidth !== opSize) { d.index = op.rwxIndex; d.width = op.rwxWidth; } if (d.fixed !== -1) { - if (op.memSeg) + if (op.memSegment) d.flags.MemPhysId = true; else d.flags.RegPhysId = true; @@ -2068,16 +2211,26 @@ class InstRWInfoTable extends core.Task { rwOps[j] = d; } else { - if (!Lang.deepEqExcept(rwOps[j], d, { "fixed": true, "flags": true })) + if (!ObjectUtils.equalsExcept(rwOps[j], d, { "fixed": true, "flags": true })) return null; if (rwOps[j].fixed === -1) rwOps[j].fixed = d.fixed; - Lang.merge(rwOps[j].flags, d.flags); + ObjectUtils.merge(rwOps[j].flags, d.flags); } } } - return { category: "Generic", rwOps }; + + const name = dbInsts.length ? dbInsts[0].name : ""; + + switch (name) { + case "vpternlogd": + case "vpternlogq": + return { category: "GenericEx", rwOps }; + + default: + return { category: "Generic", rwOps }; + } } function queryRwByData(dbInsts, rwOpsArray) { @@ -2086,12 +2239,13 @@ class InstRWInfoTable extends core.Task { const operands = dbInst.operands; const rwOps = nullOps(); - for (var j = 0; j < operands.length; j++) + for (var j = 0; j < operands.length; j++) { rwOps[j] = makeRwFromOp(operands[j]) + } var match = 0; for (var j = 0; j < rwOpsArray.length; j++) - match |= Lang.deepEq(rwOps, rwOpsArray[j]); + match |= ObjectUtils.equals(rwOps, rwOpsArray[j]); if (!match) return false; @@ -2135,7 +2289,7 @@ class InstRWInfoTable extends core.Task { if (queryRwByData(dbInsts, this.rwCategoryByData[k])) return { category: k, rwOps: nullOps() }; - // FAILURE: Missing data to categorize this instruction. + // FATALURE: Missing data to categorize this instruction. if (name) { const items = dumpRwToData(dbInsts) console.log(`RW: ${dbInsts.length ? dbInsts[0].name : ""}:`); @@ -2147,17 +2301,37 @@ class InstRWInfoTable extends core.Task { return null; } + rwOpFlagsForInstruction(instName, opIndex) { + const toMap = ArrayUtils.toDict; + + // TODO: We should be able to get this information from asmdb. + switch (instName + "@" + opIndex) { + case "cmps@0": return toMap(['MemBaseRW', 'MemBasePostModify']); + case "cmps@1": return toMap(['MemBaseRW', 'MemBasePostModify']); + case "movs@0": return toMap(['MemBaseRW', 'MemBasePostModify']); + case "movs@1": return toMap(['MemBaseRW', 'MemBasePostModify']); + case "lods@1": return toMap(['MemBaseRW', 'MemBasePostModify']); + case "stos@0": return toMap(['MemBaseRW', 'MemBasePostModify']); + case "scas@1": return toMap(['MemBaseRW', 'MemBasePostModify']); + case "bndstx@0": return toMap(['MemBaseWrite', 'MemIndexWrite']); + + default: + return {}; + } + } + // Reg/Mem Info // ------------ - rmInfo(dbInsts) { + rmInfo(asmInst, dbInsts) { const info = { category: "None", rmIndexes: this.rmReplaceableIndexes(dbInsts), memFixed: this.rmFixedSize(dbInsts), memAmbiguous: this.rmIsAmbiguous(dbInsts), memConsistent: this.rmIsConsistent(dbInsts), - memExtension: this.rmExtension(dbInsts) + memExtension: this.rmExtension(dbInsts), + memExtensionIfRMI: this.rmExtensionIfRMI(dbInsts) }; if (info.memFixed !== -1) @@ -2198,9 +2372,14 @@ class InstRWInfoTable extends core.Task { if (category === null) category = c; else if (category !== c) { + // Special cases. if (dbInst.name === "mov" || dbInst.name === "vmovddup") - return "None"; // Special case - return StringUtils.capitalize(dbInst.name); // Special case. + return "None"; + + if (/^(punpcklbw|punpckldq|punpcklwd)$/.test(dbInst.name)) + return "None"; + + return cxx.Utils.capitalize(dbInst.name); } } @@ -2361,14 +2540,32 @@ class InstRWInfoTable extends core.Task { case "pextrw": return "SSE4_1"; + case "vpslld": + case "vpsllq": + case "vpsrad": + case "vpsrld": + case "vpsrlq": + return "AVX512_F"; + case "vpslldq": + case "vpsllw": + case "vpsraw": case "vpsrldq": + case "vpsrlw": return "AVX512_BW"; default: return "None"; } } + + rmExtensionIfRMI(dbInsts) { + if (!dbInsts.length) + return 0; + + const name = dbInsts[0].name; + return /^(vpslld|vpsllq|vpsrad|vpsrld|vpsrlq|vpslldq|vpsllw|vpsraw|vpsrldq|vpsrlw)$/.test(name); + } } // ============================================================================ @@ -2381,7 +2578,7 @@ class InstCommonTable extends core.Task { "IdEnum", "NameTable", "InstSignatureTable", - "InstCommonInfoTableB", + "AdditionalInfoTable", "InstRWInfoTable" ]); } @@ -2391,25 +2588,33 @@ class InstCommonTable extends core.Task { const table = new IndexedArray(); insts.forEach((inst) => { - const flags = inst.flags.map(function(flag) { return `F(${flag})`; }).join("|") || "0"; - const singleRegCase = `SINGLE_REG(${inst.singleRegCase})`; - const controlType = `CONTROL(${inst.controlType})`; + const commonFlagsArray = inst.flags.filter((flag) => { return !flag.startsWith("Avx512"); }); + const avx512FlagsArray = inst.flags.filter((flag) => { return flag.startsWith("Avx512"); }); + + const commonFlags = commonFlagsArray.map(function(flag) { return `F(${flag })`; }).join("|") || "0"; + const avx512Flags = avx512FlagsArray.map(function(flag) { return `X(${flag.substr(6)})`; }).join("|") || "0"; + + const controlFlow = `CONTROL_FLOW(${inst.controlFlow})`; + const singleRegCase = `SAME_REG_HINT(${inst.singleRegCase})`; const row = "{ " + - String(flags ).padEnd(54) + ", " + + String(commonFlags ).padEnd(50) + ", " + + String(avx512Flags ).padEnd(30) + ", " + String(inst.signatureIndex).padEnd( 3) + ", " + String(inst.signatureCount).padEnd( 2) + ", " + - String(controlType ).padEnd(16) + ", " + - String(singleRegCase ).padEnd(16) + ", " + "0 }"; - inst.commonInfoIndexA = table.addIndexed(row); + String(controlFlow ).padEnd(16) + ", " + + String(singleRegCase ).padEnd(16) + "}"; + inst.commonInfoIndex = table.addIndexed(row); }); - var s = `#define F(VAL) InstDB::kFlag##VAL\n` + - `#define CONTROL(VAL) Inst::kControl##VAL\n` + - `#define SINGLE_REG(VAL) InstDB::kSingleReg##VAL\n` + + var s = `#define F(VAL) uint32_t(InstDB::InstFlags::k##VAL)\n` + + `#define X(VAL) uint32_t(InstDB::Avx512Flags::k##VAL)\n` + + `#define CONTROL_FLOW(VAL) uint8_t(InstControlFlow::k##VAL)\n` + + `#define SAME_REG_HINT(VAL) uint8_t(InstSameRegHint::k##VAL)\n` + `const InstDB::CommonInfo InstDB::_commonInfoTable[] = {\n${StringUtils.format(table, kIndent, true)}\n};\n` + - `#undef SINGLE_REG\n` + - `#undef CONTROL\n` + + `#undef SAME_REG_HINT\n` + + `#undef CONTROL_FLOW\n` + + `#undef X\n` + `#undef F\n`; this.inject("InstCommonTable", disclaimer(s), table.length * 8); } @@ -2424,7 +2629,7 @@ new X86TableGen() .addTask(new NameTable()) .addTask(new AltOpcodeTable()) .addTask(new InstSignatureTable()) - .addTask(new InstCommonInfoTableB()) + .addTask(new AdditionalInfoTable()) .addTask(new InstRWInfoTable()) .addTask(new InstCommonTable()) .run(); |