diff options
Diffstat (limited to '3rdparty/asmjit/tools/tablegen-x86.js')
-rw-r--r-- | 3rdparty/asmjit/tools/tablegen-x86.js | 403 |
1 files changed, 200 insertions, 203 deletions
diff --git a/3rdparty/asmjit/tools/tablegen-x86.js b/3rdparty/asmjit/tools/tablegen-x86.js index 4750edfa205..377a71045e7 100644 --- a/3rdparty/asmjit/tools/tablegen-x86.js +++ b/3rdparty/asmjit/tools/tablegen-x86.js @@ -3,86 +3,43 @@ // See asmjit.h or LICENSE.md for license and copyright information // SPDX-License-Identifier: Zlib -// ============================================================================ -// 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. -// ============================================================================ - "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"], - - // Movabs (X64 only). - ["movabs", "W:r64, iq/uq" , "I" , "REX.W B8+r iq", "X64"], - ["movabs", "w:al, moff8" , "NONE", "A0" , "X64"], - ["movabs", "w:ax, moff16" , "NONE", "66 A1" , "X64"], - ["movabs", "W:eax, moff32", "NONE", "A1" , "X64"], - ["movabs", "W:rax, moff64", "NONE", "REX.W A1" , "X64"], - ["movabs", "W:moff8, al" , "NONE", "A2" , "X64"], - ["movabs", "W:moff16, ax" , "NONE", "66 A3" , "X64"], - ["movabs", "W:moff32, eax", "NONE", "A3" , "X64"], - ["movabs", "W:moff64, rax", "NONE", "REX.W A3" , "X64"] - ] -}); - -// 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] @@ -95,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(", "); @@ -113,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); } @@ -167,7 +124,28 @@ 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 assignVexEvexCompatibilityFlags(f, dbInsts) { @@ -261,16 +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.attributes.ImplicitZeroing) f.Avx512ImplicitZ = 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; @@ -280,7 +258,7 @@ class GenUtils { } } - if (dbInst.attributes.Tsib) + if (dbInst.tsib) f.Tsib = true; if (dbInst.vsibReg) @@ -289,12 +267,11 @@ class GenUtils { 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.extensions["AVX512_VNNI"]) - f.PreferEvex = true; - if (dbInst.kmask) f.Avx512K = true; if (dbInst.zmask) f.Avx512Z = true; @@ -418,7 +395,7 @@ class GenUtils { } } - static fixedRegOf(reg) { + static fixedRegOfRegName(reg) { switch (reg) { case "es" : return 1; case "cs" : return 2; @@ -447,11 +424,23 @@ class GenUtils { } } + 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"; + 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"; } } @@ -473,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); } // -------------------------------------------------------------------------- @@ -500,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; @@ -515,7 +494,7 @@ 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 controlFlow = GenUtils.controlFlow(dbInsts); @@ -548,7 +527,7 @@ class X86TableGen extends core.TableGen { } 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); } @@ -562,7 +541,6 @@ class X86TableGen extends core.TableGen { String(inst.opcode1 ).padEnd(26) + ", " + String(inst.mainOpcodeIndex ).padEnd( 3) + ", " + String(inst.altOpcodeIndex ).padEnd( 3) + ", " + - String(inst.nameIndex ).padEnd( 5) + ", " + String(inst.commonInfoIndex ).padEnd( 3) + ", " + String(inst.additionalInfoIndex).padEnd( 3) + ")"; }) + "\n"; @@ -574,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", @@ -832,7 +810,7 @@ class IdEnum extends core.IdEnum { var text = ""; var features = GenUtils.cpuFeaturesOf(dbInsts); - const priorityFeatures = ["AVX_VNNI"]; + const priorityFeatures = ["AVX_VNNI", "AVX_VNNI_INT8", "AVX_IFMA", "AVX_NE_CONVERT"]; if (features.length) { text += "{"; @@ -970,7 +948,7 @@ class AltOpcodeTable extends core.Task { components[2] = "00"; } else { - FAIL(`Failed to process opcode '${opcode}'`); + FATAL(`Failed to process opcode '${opcode}'`); } const newOpcode = joinOpcodeComponents(components); @@ -1009,8 +987,8 @@ class AltOpcodeTable extends core.Task { // [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([ "RegGpbLo", "RegGpbHi", "RegGpw", "RegGpd", "RegGpq", "RegXmm", "RegYmm", "RegZmm", "RegMm", "RegKReg", "RegSReg", "RegCReg", "RegDReg", "RegSt", "RegBnd", "RegTmm", @@ -1037,7 +1015,7 @@ function StringifyOpArray(a, map) { else if (hasOwn.call(map, op)) mapped = map[op]; else - FAIL(`UNHANDLED OPERAND '${op}'`); + FATAL(`UNHANDLED OPERAND '${op}'`); s += (s ? " | " : "") + mapped; } return s ? s : "0"; @@ -1049,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; } @@ -1254,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. @@ -1269,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; @@ -1281,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; } @@ -1297,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 || "?"; } @@ -1323,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. @@ -1336,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); } @@ -1361,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) @@ -1372,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); } @@ -1412,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; @@ -1424,8 +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) + if (implicit) { bInst[memPos].flags.mem = true; + } if (!implicit) DEBUG(`${this.name}: Explicit: ${bInst}`); @@ -1594,7 +1572,9 @@ class InstSignatureTable extends core.Task { } 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; @@ -1678,29 +1658,9 @@ class InstSignatureTable extends core.Task { op.flags.implicit = true; } - const seg = iop.memSeg; + const seg = iop.memSegment; if (seg) { switch (inst.name) { - case "cmpsb": op.flags.m8 = true; break; - case "cmpsw": op.flags.m16 = true; break; - case "cmpsd": op.flags.m32 = true; break; - case "cmpsq": op.flags.m64 = true; break; - case "lodsb": op.flags.m8 = true; break; - case "lodsw": op.flags.m16 = true; break; - case "lodsd": op.flags.m32 = true; break; - case "lodsq": op.flags.m64 = true; break; - case "movsb": op.flags.m8 = true; break; - case "movsw": op.flags.m16 = true; break; - case "movsd": op.flags.m32 = true; break; - case "movsq": op.flags.m64 = true; break; - case "scasb": op.flags.m8 = true; break; - case "scasw": op.flags.m16 = true; break; - case "scasd": op.flags.m32 = true; break; - case "scasq": op.flags.m64 = true; break; - case "stosb": op.flags.m8 = true; break; - case "stosw": op.flags.m16 = true; break; - case "stosd": op.flags.m32 = true; break; - case "stosq": op.flags.m64 = true; break; case "insb": op.flags.m8 = true; break; case "insw": op.flags.m16 = true; break; case "insd": op.flags.m32 = true; break; @@ -1720,6 +1680,9 @@ class InstSignatureTable extends core.Task { 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; } @@ -1732,30 +1695,37 @@ class InstSignatureTable extends core.Task { else if (reg) { if (reg == "r8") { op.flags["r8lo"] = true; - op.flags["r8hi"] = true; + + if (!inst.w || inst.w === "W0") + op.flags["r8hi"] = true; } else { op.flags[reg] = true; } } + if (mem) { op.flags[mem] = true; - // HACK: Allow LEA|CL*|PREFETCH* to use any memory size. - if (/^(cldemote|clwb|clflush\w*|lea|prefetch\w*)$/.test(inst.name)) { + // 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 (inst.name === "enqcmd" || inst.name === "enqcmds" || inst.name === "movdir64b") + 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); } @@ -1766,8 +1736,8 @@ class InstSignatureTable extends core.Task { } } - if (signatures.length && GenUtils.canUseImplicitMemSize(dbInsts[0].name)) - signatures.calcImplicitMemSize(); + if (signatures.length && GenUtils.canUseImplicitMemSize(instName)) + signatures.calcImplicitMemSize(instName); signatures.compact(); return signatures; @@ -1839,7 +1809,7 @@ class AdditionalInfoTable extends core.Task { break; } - const instFlagsIndex = instFlagsTable.addIndexed("InstRWFlags(" + CxxUtils.flags(instFlags, (f) => { return `FLAG(${f})`; }, "FLAG(None)") + ")"); + const instFlagsIndex = instFlagsTable.addIndexed("InstRWFlags(" + StringUtils.formatCppFlags(instFlags, (f) => { return `FLAG(${f})`; }, "FLAG(None)") + ")"); const rwInfoIndex = rwInfoTable.addIndexed(`{ ${rData}, ${wData} }`); inst.additionalInfoIndex = additionaInfoTable.addIndexed(`{ ${instFlagsIndex}, ${rwInfoIndex}, { ${features} } }`); @@ -1870,7 +1840,7 @@ class AdditionalInfoTable 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, @@ -1878,28 +1848,28 @@ class AdditionalInfoTable 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; @@ -1924,7 +1894,7 @@ class AdditionalInfoTable extends core.Task { // [tablegen.x86.InstRWInfoTable] // ============================================================================ -const NOT_MEM_AMBIGUOUS = MapUtils.arrayToMap([ +const NOT_MEM_AMBIGUOUS = ArrayUtils.toDict([ "call", "movq" ]); @@ -1997,20 +1967,20 @@ 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", "0", - CxxUtils.struct(0), + StringUtils.formatCppStruct(0), "OpRWFlags::kNone" ); @@ -2049,7 +2019,7 @@ 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; @@ -2058,23 +2028,23 @@ class InstRWInfoTable extends core.Task { const consecutiveLeadCount = op.clc; - const opData = CxxUtils.struct( + 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), String(consecutiveLeadCount), - CxxUtils.struct(0), - CxxUtils.flags(flags, function(flag) { return "OpRWFlags::k" + flag; }, "OpRWFlags::kNone") + 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({ + 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"), @@ -2083,10 +2053,10 @@ class InstRWInfoTable extends core.Task { 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); }))) ); if (i == 0) @@ -2134,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; } } @@ -2165,7 +2135,7 @@ class InstRWInfoTable extends core.Task { 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 }; @@ -2195,10 +2165,26 @@ class InstRWInfoTable extends core.Task { if (op.consecutiveLeadCount) d.clc = op.consecutiveLeadCount; - if (op.isReg()) - d.fixed = GenUtils.fixedRegOf(op.reg); - else - d.fixed = GenUtils.fixedRegOf(op.mem); + 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; @@ -2215,7 +2201,7 @@ class InstRWInfoTable extends core.Task { } if (d.fixed !== -1) { - if (op.memSeg) + if (op.memSegment) d.flags.MemPhysId = true; else d.flags.RegPhysId = true; @@ -2225,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) { @@ -2243,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; @@ -2292,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 : ""}:`); @@ -2305,7 +2302,7 @@ class InstRWInfoTable extends core.Task { } rwOpFlagsForInstruction(instName, opIndex) { - const toMap = MapUtils.arrayToMap; + const toMap = ArrayUtils.toDict; // TODO: We should be able to get this information from asmdb. switch (instName + "@" + opIndex) { @@ -2382,7 +2379,7 @@ class InstRWInfoTable extends core.Task { if (/^(punpcklbw|punpckldq|punpcklwd)$/.test(dbInst.name)) return "None"; - return StringUtils.capitalize(dbInst.name); + return cxx.Utils.capitalize(dbInst.name); } } |