mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 04:24:37 +03:00
[abi] Reorganized instruction DB, removed deprecated instructions
* Removed AVX512_ER, AVX512_PF, AVX512_4FMAPS, and AVX512_4VNNIW
extensions and corresponding instructions (these were never
advertised by any x86 CPU and were only used by Xeon Phi acc.,
which AsmJit never supported)
* Removed CPU extensions HLE, MPX, and TSX
* Kept extension RTM, which is only for backward compatibility to
recognize instructions, but it's no longer checked by CpuInfo as
it's been deprecated together with HLE and MPX
* The xtest instruction now reports it requires RTM
* Reorganized x86 extensions a bit - they are now reordered to group
them by category, preparing for the future where extension IDs will
be always added after existing records for ABI compatibility
* Instruction vcvtneps2bf16 no longer accepts form without an explicit
memory operand size
* Removed aliased instructions in CMOVcc, Jcc, And SETcc categories,
now there is only a single instruction id for all aliased instructions.
* Added a new feature to always show instruction aliases in Logger, which
includes formatting instructio nodes (Builder, Compiler)
Instruction DB-only updates (not applied to C++ yet):
* AsmJit DB from now uses the same license as AsmJit (Zlib) and
no longer applies dual licensing (Zlib and Public Domain)
* Added support for aggregated instruction definitions in
x86 instruction database, which should simplify the maintenance
and reduce bugs (also the syntax is comparable to descriptions
used by Intel APX instruction manuals)
* Added support for APX instructions and new features
* Added support for AVX10.1 and AVX10.2 instructions (both new
instructions and new encodings of existing instructions)
* Added support for MOVRS instructions
* Added support for KL instructions (loadiwkey)
* Added support for AESKLE instructions
* Added support for AESKLEWIDE_KL instructions
* Added support for AMX_[AVX512|MOVRS|FP8|TF32|TRANSPOSE]
* NOTE: None of the instruction additions is currently used by
Asmjit, it's a pure database update that needs more work to
make all the instructions available in future AsmJit
This commit is contained in:
@@ -215,6 +215,9 @@ exports.ArrayUtils = ArrayUtils;
|
||||
class StringUtils {
|
||||
static asString(x) { return String(x); }
|
||||
|
||||
static makeEnumName(name) {
|
||||
return name ? name.charAt(0).toUpperCase() + name.substring(1) : "";
|
||||
}
|
||||
static countOf(s, pattern) {
|
||||
if (!pattern)
|
||||
FATAL(`Pattern cannot be empty`);
|
||||
|
||||
@@ -9,7 +9,7 @@ const FATAL = commons.FATAL;
|
||||
|
||||
// Utilities to convert primitives to C++ code.
|
||||
class Utils {
|
||||
static toHex(val, pad) {
|
||||
static toHexRaw(val, pad) {
|
||||
if (val < 0)
|
||||
val = 0xFFFFFFFF + val + 1;
|
||||
|
||||
@@ -17,7 +17,11 @@ class Utils {
|
||||
if (pad != null && s.length < pad)
|
||||
s = "0".repeat(pad - s.length) + s;
|
||||
|
||||
return "0x" + s.toUpperCase();
|
||||
return s.toUpperCase();
|
||||
}
|
||||
|
||||
static toHex(val, pad) {
|
||||
return "0x" + Utils.toHexRaw(val, pad);
|
||||
}
|
||||
|
||||
static capitalize(s) {
|
||||
|
||||
@@ -132,8 +132,8 @@ class ArmTableGen extends core.TableGen {
|
||||
|
||||
var m;
|
||||
while ((m = re.exec(stringData)) !== null) {
|
||||
var enum_ = m[1];
|
||||
var name = enum_ === "None" ? "" : enum_.toLowerCase();
|
||||
var enumName = m[1];
|
||||
var name = enumName === "None" ? "" : enumName.toLowerCase();
|
||||
var encoding = m[2].trim();
|
||||
var opcodeData = m[3].trim();
|
||||
var rwInfo = m[4].trim();
|
||||
@@ -149,11 +149,11 @@ class ArmTableGen extends core.TableGen {
|
||||
encodingDataIndex === "encodingDataIndex")
|
||||
continue;
|
||||
|
||||
this.addInst({
|
||||
this.addInstruction({
|
||||
id : 0, // Instruction id (numeric value).
|
||||
name : name, // Instruction name.
|
||||
displayName : displayName, // Instruction name to display.
|
||||
enum : enum_, // Instruction enum without `kId` prefix.
|
||||
enum : enumName, // Instruction enum without `kId` prefix.
|
||||
encoding : encoding, // Opcode encoding.
|
||||
opcodeData : opcodeData, // Opcode data.
|
||||
opcodeDataIndex : -1, // Opcode data index.
|
||||
|
||||
@@ -50,7 +50,7 @@ class Filter {
|
||||
const result = [];
|
||||
const known = {};
|
||||
|
||||
for (var i = 0; i < instArray.length; i++) {
|
||||
for (let i = 0; i < instArray.length; i++) {
|
||||
const inst = instArray[i];
|
||||
if (inst.altForm)
|
||||
continue;
|
||||
@@ -68,9 +68,9 @@ class Filter {
|
||||
|
||||
static noAltForm(instArray) {
|
||||
const result = [];
|
||||
for (var i = 0; i < instArray.length; i++) {
|
||||
for (let i = 0; i < instArray.length; i++) {
|
||||
const inst = instArray[i];
|
||||
if (inst.altForm)
|
||||
if (inst.alt)
|
||||
continue;
|
||||
result.push(inst);
|
||||
}
|
||||
@@ -109,11 +109,11 @@ const VexToEvexMap = {
|
||||
|
||||
class GenUtils {
|
||||
static cpuArchOf(dbInsts) {
|
||||
var anyArch = false;
|
||||
var x86Arch = false;
|
||||
var x64Arch = false;
|
||||
let anyArch = false;
|
||||
let x86Arch = false;
|
||||
let x64Arch = false;
|
||||
|
||||
for (var i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const dbInst = dbInsts[i];
|
||||
if (dbInst.arch === "ANY") anyArch = true;
|
||||
if (dbInst.arch === "X86") x86Arch = true;
|
||||
@@ -203,16 +203,15 @@ class GenUtils {
|
||||
|
||||
static flagsOf(dbInsts) {
|
||||
const f = Object.create(null);
|
||||
var i, j;
|
||||
|
||||
var mib = dbInsts.length > 0 && /^(?:bndldx|bndstx)$/.test(dbInsts[0].name);
|
||||
let mib = dbInsts.length > 0 && /^(?:bndldx|bndstx)$/.test(dbInsts[0].name);
|
||||
if (mib)
|
||||
f.Mib = true;
|
||||
|
||||
var mmx = false;
|
||||
var vec = false;
|
||||
let mmx = false;
|
||||
let vec = false;
|
||||
|
||||
for (i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const dbInst = dbInsts[i];
|
||||
const operands = dbInst.operands;
|
||||
|
||||
@@ -222,7 +221,7 @@ class GenUtils {
|
||||
if (dbInst.name === "vzeroall" || dbInst.name === "vzeroupper")
|
||||
vec = true;
|
||||
|
||||
for (j = 0; j < operands.length; j++) {
|
||||
for (let j = 0; j < operands.length; j++) {
|
||||
const op = operands[j];
|
||||
if (op.reg === "mm")
|
||||
mmx = true;
|
||||
@@ -235,7 +234,7 @@ class GenUtils {
|
||||
if (mmx) f.Mmx = true;
|
||||
if (vec) f.Vec = true;
|
||||
|
||||
for (i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const dbInst = dbInsts[i];
|
||||
const operands = dbInst.operands;
|
||||
|
||||
@@ -249,7 +248,7 @@ class GenUtils {
|
||||
if (dbInst.k === "zeroing" ) f.Avx512ImplicitZ = true;
|
||||
|
||||
if (dbInst.category.FPU) {
|
||||
for (var j = 0; j < operands.length; j++) {
|
||||
for (let j = 0; j < operands.length; j++) {
|
||||
const op = operands[j];
|
||||
if (op.memSize === 16) f.FpuM16 = true;
|
||||
if (op.memSize === 32) f.FpuM32 = true;
|
||||
@@ -296,7 +295,7 @@ class GenUtils {
|
||||
}
|
||||
|
||||
static eqOps(aOps, aFrom, bOps, bFrom) {
|
||||
var x = 0;
|
||||
let x = 0;
|
||||
for (;;) {
|
||||
const aIndex = x + aFrom;
|
||||
const bIndex = x + bFrom;
|
||||
@@ -462,7 +461,9 @@ class X86TableGen extends core.TableGen {
|
||||
|
||||
// Get instructions (dbInsts) having the same name as understood by AsmJit.
|
||||
query(name) {
|
||||
return x86isa.query(name);
|
||||
return x86isa.query({ name: name, filter: function(inst) {
|
||||
return !inst.ext.APX_F && !inst.ext.AVX10_1 && !inst.ext.AVX10_2;
|
||||
}});
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -484,13 +485,13 @@ class X86TableGen extends core.TableGen {
|
||||
"([^\\)]+)" + "\\)", // [08] OperationDataIndex.
|
||||
"g");
|
||||
|
||||
var m;
|
||||
let m;
|
||||
while ((m = re.exec(data)) !== null) {
|
||||
var enum_ = m[1];
|
||||
var name = enum_ === "None" ? "" : enum_.toLowerCase();
|
||||
var encoding = m[2].trim();
|
||||
var opcode0 = m[3].trim();
|
||||
var opcode1 = m[4].trim();
|
||||
let enum_ = m[1];
|
||||
let name = enum_ === "None" ? "" : enum_.toLowerCase();
|
||||
let encoding = m[2].trim();
|
||||
let opcode0 = m[3].trim();
|
||||
let opcode1 = m[4].trim();
|
||||
|
||||
const dbInsts = this.query(name);
|
||||
if (name && !dbInsts.length)
|
||||
@@ -500,7 +501,9 @@ class X86TableGen extends core.TableGen {
|
||||
const controlFlow = GenUtils.controlFlow(dbInsts);
|
||||
const singleRegCase = GenUtils.singleRegCase(name);
|
||||
|
||||
this.addInst({
|
||||
const aliasData = x86isa.aliasData(name);
|
||||
|
||||
this.addInstruction({
|
||||
id : 0, // Instruction id (numeric value).
|
||||
name : name, // Instruction name.
|
||||
displayName : name, // Instruction name to display.
|
||||
@@ -514,6 +517,8 @@ class X86TableGen extends core.TableGen {
|
||||
controlFlow : controlFlow,
|
||||
singleRegCase : singleRegCase,
|
||||
|
||||
aliases : aliasData,
|
||||
|
||||
mainOpcodeValue : -1, // Main opcode value (0.255 hex).
|
||||
mainOpcodeIndex : -1, // Index to InstDB::_mainOpcodeTable.
|
||||
altOpcodeIndex : -1, // Index to InstDB::_altOpcodeTable.
|
||||
@@ -533,7 +538,7 @@ class X86TableGen extends core.TableGen {
|
||||
}
|
||||
|
||||
merge() {
|
||||
var s = StringUtils.format(this.insts, "", true, function(inst) {
|
||||
let s = StringUtils.format(this.insts, "", true, function(inst) {
|
||||
return "INST(" +
|
||||
String(inst.enum ).padEnd(17) + ", " +
|
||||
String(inst.encoding ).padEnd(19) + ", " +
|
||||
@@ -563,12 +568,12 @@ class X86TableGen extends core.TableGen {
|
||||
"wait" // Maps to `fwait`, which AsmJit uses instead.
|
||||
]);
|
||||
|
||||
var out = "";
|
||||
let out = "";
|
||||
x86isa.instructionNames.forEach(function(name) {
|
||||
var dbInsts = x86isa.query(name);
|
||||
let dbInsts = x86isa.query(name);
|
||||
if (!this.instMap[name] && ignored[name] !== true) {
|
||||
console.log(`MISSING INSTRUCTION '${name}'`);
|
||||
var inst = this.newInstFromGroup(dbInsts);
|
||||
let inst = this.newInstFromGroup(dbInsts);
|
||||
if (inst) {
|
||||
out += " INST(" +
|
||||
String(inst.enum ).padEnd(17) + ", " +
|
||||
@@ -593,10 +598,10 @@ class X86TableGen extends core.TableGen {
|
||||
}
|
||||
|
||||
function GetAccess(dbInst) {
|
||||
var operands = dbInst.operands;
|
||||
let operands = dbInst.operands;
|
||||
if (!operands.length) return "";
|
||||
|
||||
var op = operands[0];
|
||||
let op = operands[0];
|
||||
if (op.read && op.write)
|
||||
return "RW";
|
||||
else if (op.read)
|
||||
@@ -618,8 +623,8 @@ class X86TableGen extends core.TableGen {
|
||||
for (let j = 0; j < dbi.operands.length; j++) {
|
||||
s += ", ";
|
||||
const op = dbi.operands[j];
|
||||
var reg = op.reg;
|
||||
var mem = op.mem;
|
||||
let reg = op.reg;
|
||||
let mem = op.mem;
|
||||
|
||||
if (op.isReg() && op.isMem()) {
|
||||
if (choice == 0) mem = null;
|
||||
@@ -653,27 +658,27 @@ class X86TableGen extends core.TableGen {
|
||||
return results;
|
||||
}
|
||||
|
||||
var dbi = dbInsts[0];
|
||||
let dbi = dbInsts[0];
|
||||
|
||||
var id = this.insts.length;
|
||||
var name = dbi.name;
|
||||
var enum_ = name[0].toUpperCase() + name.substr(1);
|
||||
let id = this.insts.length;
|
||||
let name = dbi.name;
|
||||
let enum_ = name[0].toUpperCase() + name.substr(1);
|
||||
|
||||
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 evexCount = 0;
|
||||
let opcode = dbi.opcode.byte;
|
||||
let modR = dbi.opcode.modr;
|
||||
let mm = dbi.opcode.mm;
|
||||
let pp = dbi.opcode.pp;
|
||||
let encoding = dbi.encoding;
|
||||
let isVec = isVecPrefix(dbi.prefix);
|
||||
let evexCount = 0;
|
||||
|
||||
var access = GetAccess(dbi);
|
||||
let access = GetAccess(dbi);
|
||||
|
||||
var vexL = undefined;
|
||||
var vexW = undefined;
|
||||
var evexW = undefined;
|
||||
var cdshl = "_";
|
||||
var tupleType = "_";
|
||||
let vexL = undefined;
|
||||
let vexW = undefined;
|
||||
let evexW = undefined;
|
||||
let cdshl = "_";
|
||||
let tupleType = "_";
|
||||
|
||||
const tupleTypeToCDSHL = {
|
||||
"FVM": "4",
|
||||
@@ -687,12 +692,12 @@ class X86TableGen extends core.TableGen {
|
||||
|
||||
const emitMap = {};
|
||||
|
||||
for (var i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
dbi = dbInsts[i];
|
||||
|
||||
if (dbi.prefix === "VEX" || dbi.prefix === "XOP") {
|
||||
var newVexL = String(dbi.l === "128" ? 0 : dbi.l === "256" ? 1 : dbi.l === "512" ? 2 : "_");
|
||||
var newVexW = String(dbi.w === "W0" ? 0 : dbi.w === "W1" ? 1 : "_");
|
||||
let newVexL = String(dbi.opcode.l === "128" ? 0 : dbi.opcode.l === "256" ? 1 : dbi.opcode.l === "512" ? 2 : "_");
|
||||
let newVexW = String(dbi.opcode.w === "W0" ? 0 : dbi.opcode.w === "W1" ? 1 : "_");
|
||||
|
||||
if (vexL !== undefined && vexL !== newVexL)
|
||||
vexL = "x";
|
||||
@@ -706,7 +711,7 @@ class X86TableGen extends core.TableGen {
|
||||
|
||||
if (dbi.prefix === "EVEX") {
|
||||
evexCount++;
|
||||
var newEvexW = String(dbi.w === "W0" ? 0 : dbi.w === "W1" ? 1 : "_");
|
||||
let newEvexW = String(dbi.opcode.w === "W0" ? 0 : dbi.opcode.w === "W1" ? 1 : "_");
|
||||
if (evexW !== undefined && evexW !== newEvexW)
|
||||
evexW = "x";
|
||||
else
|
||||
@@ -721,12 +726,12 @@ class X86TableGen extends core.TableGen {
|
||||
}
|
||||
}
|
||||
|
||||
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 (opcode !== dbi.opcode.byte) { console.log(`${dbi.name}: ISSUE: Opcode ${opcode} != ${dbi.opcode.byte}`); return null; }
|
||||
if (modR !== dbi.opcode.modr) { console.log(`${dbi.name}: ISSUE: ModR ${modR} != ${dbi.opcode.modr}`); return null; }
|
||||
if (mm !== dbi.opcode.mm ) { console.log(`${dbi.name}: ISSUE: MM ${mm} != ${dbi.opcode.mm}`); return null; }
|
||||
if (pp !== dbi.opcode.pp ) { console.log(`${dbi.name}: ISSUE: PP ${pp} != ${dbi.opcode.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) => {
|
||||
@@ -740,10 +745,10 @@ class X86TableGen extends core.TableGen {
|
||||
if (tupleType !== "_")
|
||||
cdshl = tupleTypeToCDSHL[tupleType] || "?";
|
||||
|
||||
var ppmm = pp.padEnd(2).replace(/ /g, "0") +
|
||||
let ppmm = pp.padEnd(2).replace(/ /g, "0") +
|
||||
mm.padEnd(4).replace(/ /g, "0") ;
|
||||
|
||||
var composed = composeOpCode({
|
||||
let composed = composeOpCode({
|
||||
type : evexCount == dbInsts.length ? "E" : isVec ? "V" : "O",
|
||||
prefix: ppmm,
|
||||
opcode: opcode,
|
||||
@@ -804,11 +809,11 @@ class IdEnum extends core.IdEnum {
|
||||
return features.filter(function(item) { return /^(AVX|FMA)/.test(item) === avx; });
|
||||
}
|
||||
|
||||
var dbInsts = inst.dbInsts;
|
||||
let dbInsts = inst.dbInsts;
|
||||
if (!dbInsts.length) return "Invalid instruction id.";
|
||||
|
||||
var text = "";
|
||||
var features = GenUtils.cpuFeaturesOf(dbInsts);
|
||||
let text = "";
|
||||
let features = GenUtils.cpuFeaturesOf(dbInsts);
|
||||
|
||||
const priorityFeatures = ["AVX_VNNI", "AVX_VNNI_INT8", "AVX_IFMA", "AVX_NE_CONVERT"];
|
||||
|
||||
@@ -840,7 +845,7 @@ class IdEnum extends core.IdEnum {
|
||||
text += "}";
|
||||
}
|
||||
|
||||
var arch = GenUtils.cpuArchOf(dbInsts);
|
||||
let arch = GenUtils.cpuArchOf(dbInsts);
|
||||
if (arch)
|
||||
text += (text ? " " : "") + arch;
|
||||
|
||||
@@ -854,7 +859,7 @@ class IdEnum extends core.IdEnum {
|
||||
|
||||
class NameTable extends core.NameTable {
|
||||
constructor() {
|
||||
super("NameTable");
|
||||
super("NameTable", null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -934,7 +939,7 @@ class AltOpcodeTable extends core.Task {
|
||||
if (opcode === "0")
|
||||
return ["00", 0];
|
||||
|
||||
var opcodeByte = "";
|
||||
let opcodeByte = "";
|
||||
const components = normalizeOpcodeComponents(splitOpcodeToComponents(opcode));
|
||||
|
||||
if (components[0] === "O_FPU") {
|
||||
@@ -1006,10 +1011,10 @@ const cmpOp = StringUtils.makePriorityCompare([
|
||||
]);
|
||||
|
||||
function StringifyOpArray(a, map) {
|
||||
var s = "";
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
let s = "";
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
const op = a[i];
|
||||
var mapped = null;
|
||||
let mapped = null;
|
||||
if (typeof map === "function")
|
||||
mapped = map(op);
|
||||
else if (hasOwn.call(map, op))
|
||||
@@ -1039,11 +1044,10 @@ class OSignature {
|
||||
const af = this.flags;
|
||||
const bf = other.flags;
|
||||
|
||||
var k;
|
||||
var indexKind = "";
|
||||
var hasReg = false;
|
||||
let hasReg = false;
|
||||
let indexKind = "";
|
||||
|
||||
for (k in af) {
|
||||
for (let k in af) {
|
||||
const index = asmdb.x86.Utils.regIndexOf(k);
|
||||
const kind = asmdb.x86.Utils.regKindOf(k);
|
||||
|
||||
@@ -1055,7 +1059,7 @@ class OSignature {
|
||||
}
|
||||
|
||||
if (hasReg) {
|
||||
for (k in bf) {
|
||||
for (let k in bf) {
|
||||
const index = asmdb.x86.Utils.regIndexOf(k);
|
||||
if (index !== null && index !== -1) {
|
||||
const kind = asmdb.x86.Utils.regKindOf(k);
|
||||
@@ -1066,20 +1070,20 @@ class OSignature {
|
||||
}
|
||||
|
||||
// Can merge...
|
||||
for (k in bf)
|
||||
for (let k in bf)
|
||||
af[k] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
toString() {
|
||||
var s = "";
|
||||
var flags = this.flags;
|
||||
let s = "";
|
||||
let flags = this.flags;
|
||||
|
||||
for (var k in flags) {
|
||||
for (let k in flags) {
|
||||
if (k === "read" || k === "write" || k === "implicit" || k === "memDS" || k === "memES")
|
||||
continue;
|
||||
|
||||
var x = k;
|
||||
let x = k;
|
||||
if (x === "memZAX") x = "zax";
|
||||
if (x === "memZDI") x = "zdi";
|
||||
if (x === "memZSI") x = "zsi";
|
||||
@@ -1096,10 +1100,10 @@ class OSignature {
|
||||
}
|
||||
|
||||
toAsmJitOpData() {
|
||||
var opFlags = Object.create(null);
|
||||
var regMask = 0;
|
||||
let opFlags = Object.create(null);
|
||||
let regMask = 0;
|
||||
|
||||
for (var k in this.flags) {
|
||||
for (let k in this.flags) {
|
||||
switch (k) {
|
||||
case "r8lo" : opFlags.RegGpbLo = true; break;
|
||||
case "r8hi" : opFlags.RegGpbHi = true; break;
|
||||
@@ -1223,7 +1227,7 @@ class ISignature extends Array {
|
||||
const len = this.length;
|
||||
if (len !== other.length) return false;
|
||||
|
||||
for (var i = 0; i < len; i++)
|
||||
for (let i = 0; i < len; i++)
|
||||
if (!this[i].equals(other[i]))
|
||||
return false;
|
||||
|
||||
@@ -1239,8 +1243,9 @@ class ISignature extends Array {
|
||||
// ok = true;
|
||||
|
||||
// It's not ok if both signatures have different number of implicit operands.
|
||||
if (!sameArch || this.implicit !== other.implicit)
|
||||
if (!sameArch || this.implicit !== other.implicit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// It's not ok if both signatures have different number of operands.
|
||||
const len = this.length;
|
||||
@@ -1250,7 +1255,8 @@ class ISignature extends Array {
|
||||
let xorIndex = -1;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const xor = this[i].xor(other[i]);
|
||||
if (xor === null) continue;
|
||||
if (xor === null)
|
||||
continue;
|
||||
|
||||
if (xorIndex === -1)
|
||||
xorIndex = i;
|
||||
@@ -1258,7 +1264,7 @@ class ISignature extends Array {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bail if mergeWidth at operand-level failed.
|
||||
// Bail if mergeWith at operand-level failed.
|
||||
if (xorIndex === -1 || !this[xorIndex].mergeWith(other[xorIndex]))
|
||||
return false;
|
||||
|
||||
@@ -1271,12 +1277,16 @@ class ISignature extends Array {
|
||||
}
|
||||
|
||||
class SignatureArray extends Array {
|
||||
constructor(instructionName) {
|
||||
super();
|
||||
this.instructionName = instructionName;
|
||||
}
|
||||
// Iterate over all signatures and check which operands don't need explicit memory size.
|
||||
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++) {
|
||||
let s = "";
|
||||
for (let i = 0; i < inst.length; i++) {
|
||||
const op = inst[i];
|
||||
if (regOps & (1 << i))
|
||||
s += "{" + ArrayUtils.sorted(ObjectUtils.and(op.flags, RegOp)).join("|") + "}";
|
||||
@@ -1284,19 +1294,16 @@ class SignatureArray extends Array {
|
||||
return s || "?";
|
||||
}
|
||||
|
||||
var i;
|
||||
var aIndex, bIndex;
|
||||
|
||||
for (aIndex = 0; aIndex < this.length; aIndex++) {
|
||||
for (let aIndex = 0; aIndex < this.length; aIndex++) {
|
||||
const aInst = this[aIndex];
|
||||
const len = aInst.length;
|
||||
|
||||
var memOp = "";
|
||||
var memPos = -1;
|
||||
var regOps = 0;
|
||||
let memOp = "";
|
||||
let memPos = -1;
|
||||
let regOps = 0;
|
||||
|
||||
// Check if this instruction signature has a memory operand of explicit size.
|
||||
for (i = 0; i < len; i++) {
|
||||
for (let i = 0; i < len; i++) {
|
||||
const aOp = aInst[i];
|
||||
const mem = ObjectUtils.findKey(aOp.flags, MemOp);
|
||||
|
||||
@@ -1328,12 +1335,12 @@ class SignatureArray extends Array {
|
||||
const diffSizeSet = [];
|
||||
const diffSizeHash = Object.create(null);
|
||||
|
||||
for (bIndex = 0; bIndex < this.length; bIndex++) {
|
||||
for (let bIndex = 0; bIndex < this.length; bIndex++) {
|
||||
const bInst = this[bIndex];
|
||||
if (aIndex === bIndex || len !== bInst.length) continue;
|
||||
|
||||
var hasMatch = 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
let hasMatch = 1;
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (i === memPos) continue;
|
||||
|
||||
const reg = ObjectUtils.hasAny(bInst[i].flags, RegOp);
|
||||
@@ -1368,14 +1375,14 @@ class SignatureArray extends Array {
|
||||
//
|
||||
// B) The memory operand has implicit-size if `diffSizeSet` contains different
|
||||
// register signatures than `sameSizeSet`.
|
||||
var implicit = true;
|
||||
let implicit = true;
|
||||
|
||||
if (!diffSizeSet.length) {
|
||||
// Case A:
|
||||
}
|
||||
else {
|
||||
// Case B: Find collisions in `sameSizeSet` and `diffSizeSet`.
|
||||
for (bIndex = 0; bIndex < sameSizeSet.length; bIndex++) {
|
||||
for (let bIndex = 0; bIndex < sameSizeSet.length; bIndex++) {
|
||||
const bInst = sameSizeSet[bIndex];
|
||||
const key = keyOf(bInst, regOps);
|
||||
|
||||
@@ -1399,25 +1406,26 @@ class SignatureArray extends Array {
|
||||
}
|
||||
|
||||
// Patch all instructions to accept implicit-size memory operand.
|
||||
for (bIndex = 0; bIndex < sameSizeSet.length; bIndex++) {
|
||||
for (let bIndex = 0; bIndex < sameSizeSet.length; bIndex++) {
|
||||
const bInst = sameSizeSet[bIndex];
|
||||
if (implicit) {
|
||||
bInst[memPos].flags.mem = true;
|
||||
}
|
||||
|
||||
if (!implicit)
|
||||
if (!implicit) {
|
||||
DEBUG(`${this.name}: Explicit: ${bInst}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compact() {
|
||||
var didSomething = true;
|
||||
let didSomething = true;
|
||||
while (didSomething) {
|
||||
didSomething = false;
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
var row = this[i];
|
||||
var j = i + 1;
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
let row = this[i];
|
||||
let j = i + 1;
|
||||
while (j < this.length) {
|
||||
if (row.mergeWith(this[j])) {
|
||||
this.splice(j, 1);
|
||||
@@ -1431,7 +1439,7 @@ class SignatureArray extends Array {
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `[${this.join(", ")}]`;
|
||||
return `[${this.join(",\n")}]`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1467,12 +1475,12 @@ class InstSignatureTable extends core.Task {
|
||||
const indexes = iSignatureMap[rows[0].data];
|
||||
if (indexes === undefined) return -1;
|
||||
|
||||
for (var i = 0; i < indexes.length; i++) {
|
||||
for (let i = 0; i < indexes.length; i++) {
|
||||
const index = indexes[i];
|
||||
if (index + len > iSignatureArr.length) continue;
|
||||
|
||||
var ok = true;
|
||||
for (var j = 0; j < len; j++) {
|
||||
let ok = true;
|
||||
for (let j = 0; j < len; j++) {
|
||||
if (iSignatureArr[index + j].data !== rows[j].data) {
|
||||
ok = false;
|
||||
break;
|
||||
@@ -1489,7 +1497,7 @@ class InstSignatureTable extends core.Task {
|
||||
function indexSignatures(signatures) {
|
||||
const result = iSignatureArr.length;
|
||||
|
||||
for (var i = 0; i < signatures.length; i++) {
|
||||
for (let i = 0; i < signatures.length; i++) {
|
||||
const signature = signatures[i];
|
||||
const idx = iSignatureArr.length;
|
||||
|
||||
@@ -1503,21 +1511,21 @@ class InstSignatureTable extends core.Task {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (var len = this.maxOpRows; len >= 0; len--) {
|
||||
for (let len = this.maxOpRows; len >= 0; len--) {
|
||||
insts.forEach((inst) => {
|
||||
const signatures = inst.signatures;
|
||||
if (signatures.length === len) {
|
||||
const signatureEntries = [];
|
||||
for (var j = 0; j < len; j++) {
|
||||
for (let j = 0; j < len; j++) {
|
||||
const signature = signatures[j];
|
||||
|
||||
var signatureEntry = `ROW(${signature.length}, ${signature.x86 ? 1 : 0}, ${signature.x64 ? 1 : 0}, ${signature.implicit}`;
|
||||
var signatureComment = signature.toString();
|
||||
let signatureEntry = `ROW(${signature.length}, ${signature.x86 ? 1 : 0}, ${signature.x64 ? 1 : 0}, ${signature.implicit}`;
|
||||
let signatureComment = signature.toString();
|
||||
|
||||
var x = 0;
|
||||
let x = 0;
|
||||
while (x < signature.length) {
|
||||
const h = signature[x].toAsmJitOpData();
|
||||
var index = -1;
|
||||
let index = -1;
|
||||
if (!hasOwn.call(oSignatureMap, h)) {
|
||||
index = oSignatureArr.length;
|
||||
oSignatureMap[h] = index;
|
||||
@@ -1540,8 +1548,8 @@ class InstSignatureTable extends core.Task {
|
||||
signatureEntries.push({ data: signatureEntry, comment: signatureComment, refs: 0 });
|
||||
}
|
||||
|
||||
var count = signatureEntries.length;
|
||||
var index = findSignaturesIndex(signatureEntries);
|
||||
let count = signatureEntries.length;
|
||||
let index = findSignaturesIndex(signatureEntries);
|
||||
|
||||
if (index === -1)
|
||||
index = indexSignatures(signatureEntries);
|
||||
@@ -1553,7 +1561,7 @@ class InstSignatureTable extends core.Task {
|
||||
});
|
||||
}
|
||||
|
||||
var s = `#define ROW(count, x86, x64, implicit, o0, o1, o2, o3, o4, o5) \\\n` +
|
||||
let 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` +
|
||||
@@ -1573,9 +1581,9 @@ class InstSignatureTable extends core.Task {
|
||||
|
||||
makeSignatures(dbInsts) {
|
||||
const instName = dbInsts.length ? dbInsts[0].name : "";
|
||||
const signatures = new SignatureArray();
|
||||
const signatures = new SignatureArray(instName);
|
||||
|
||||
for (var i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const inst = dbInsts[i];
|
||||
const ops = inst.operands;
|
||||
|
||||
@@ -1598,19 +1606,21 @@ class InstSignatureTable extends core.Task {
|
||||
// 1a. mov reg, reg
|
||||
// 1b. mov reg, mem
|
||||
// 2b. mov mem, reg
|
||||
var modrmCount = 1;
|
||||
for (var modrm = 0; modrm < modrmCount; modrm++) {
|
||||
var row = new ISignature(inst.name);
|
||||
let modrmCount = 1;
|
||||
for (let modrm = 0; modrm < modrmCount; modrm++) {
|
||||
let row = new ISignature(inst.name);
|
||||
|
||||
row.x86 = (inst.arch === "ANY" || inst.arch === "X86");
|
||||
row.x64 = (inst.arch === "ANY" || inst.arch === "X64");
|
||||
|
||||
for (var j = 0; j < ops.length; j++) {
|
||||
var iop = ops[j];
|
||||
let j;
|
||||
for (j = 0; j < ops.length; j++) {
|
||||
let iop = ops[j];
|
||||
|
||||
var reg = iop.reg;
|
||||
var mem = iop.mem;
|
||||
var imm = iop.imm;
|
||||
var rel = iop.rel;
|
||||
let reg = iop.reg;
|
||||
let mem = iop.mem;
|
||||
let imm = iop.imm;
|
||||
let rel = iop.rel;
|
||||
|
||||
// Skip all instructions having implicit `imm` operand of `1`.
|
||||
if (iop.immValue !== null)
|
||||
@@ -1731,8 +1741,9 @@ class InstSignatureTable extends core.Task {
|
||||
}
|
||||
|
||||
// Not equal if we terminated the loop.
|
||||
if (j === ops.length)
|
||||
if (j === ops.length) {
|
||||
signatures.push(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1765,10 +1776,10 @@ class AdditionalInfoTable extends core.Task {
|
||||
insts.forEach((inst) => {
|
||||
const dbInsts = inst.dbInsts;
|
||||
|
||||
var features = GenUtils.cpuFeaturesOf(dbInsts).map(function(f) { return `EXT(${f})`; }).join(", ");
|
||||
let features = GenUtils.cpuFeaturesOf(dbInsts).map(function(f) { return `EXT(${f})`; }).join(", ");
|
||||
if (!features) features = "0";
|
||||
|
||||
var [r, w] = this.rwFlagsOf(dbInsts);
|
||||
let [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 instFlags = Object.create(null);
|
||||
@@ -1815,7 +1826,7 @@ class AdditionalInfoTable extends core.Task {
|
||||
inst.additionalInfoIndex = additionaInfoTable.addIndexed(`{ ${instFlagsIndex}, ${rwInfoIndex}, { ${features} } }`);
|
||||
});
|
||||
|
||||
var s = `#define EXT(VAL) uint32_t(CpuFeatures::X86::k##VAL)\n` +
|
||||
let 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` +
|
||||
@@ -1833,7 +1844,7 @@ class AdditionalInfoTable extends core.Task {
|
||||
const r = Object.create(null);
|
||||
const w = Object.create(null);
|
||||
|
||||
for (var i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const dbInst = dbInsts[i];
|
||||
|
||||
// Omit special cases, this is handled well in C++ code.
|
||||
@@ -1848,8 +1859,8 @@ class AdditionalInfoTable extends core.Task {
|
||||
if (dbInst.name === "mov")
|
||||
continue;
|
||||
|
||||
for (var reg in regs) {
|
||||
var flag = "";
|
||||
for (let reg in regs) {
|
||||
let flag = "";
|
||||
switch (reg) {
|
||||
case "CF": flag = "CF"; break;
|
||||
case "OF": flag = "OF"; break;
|
||||
@@ -2000,13 +2011,13 @@ class InstRWInfoTable extends core.Task {
|
||||
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++) {
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const rwInfo = rwInfoArray[i];
|
||||
const rmInfo = rmInfoArray[i];
|
||||
|
||||
const rwOps = rwInfo.rwOps;
|
||||
const rwOpsIndex = [];
|
||||
for (var j = 0; j < rwOps.length; j++) {
|
||||
for (let j = 0; j < rwOps.length; j++) {
|
||||
const op = rwOps[j];
|
||||
if (!op) {
|
||||
rwOpsIndex.push(this.opInfoTable.addIndexed(noOpInfo));
|
||||
@@ -2066,7 +2077,7 @@ class InstRWInfoTable extends core.Task {
|
||||
}
|
||||
});
|
||||
|
||||
var s = "";
|
||||
let s = "";
|
||||
s += "const uint8_t InstDB::rwInfoIndexA[Inst::_kIdCount] = {\n" + StringUtils.format(this.rwInfoIndexA, kIndent, -1) + "\n};\n";
|
||||
s += "\n";
|
||||
s += "const uint8_t InstDB::rwInfoIndexB[Inst::_kIdCount] = {\n" + StringUtils.format(this.rwInfoIndexB, kIndent, -1) + "\n};\n";
|
||||
@@ -2091,17 +2102,17 @@ class InstRWInfoTable extends core.Task {
|
||||
|
||||
byteMaskFromBitRanges(ranges) {
|
||||
const arr = [];
|
||||
for (var i = 0; i < 64; i++)
|
||||
for (let i = 0; i < 64; i++)
|
||||
arr.push(0);
|
||||
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
for (let i = 0; i < ranges.length; i++) {
|
||||
const start = ranges[i].start;
|
||||
const end = ranges[i].end;
|
||||
|
||||
if (start < 0)
|
||||
continue;
|
||||
|
||||
for (var j = start; j <= end; j++) {
|
||||
for (let j = start; j <= end; j++) {
|
||||
const bytePos = j >> 3;
|
||||
if (bytePos < 0 || bytePos >= arr.length)
|
||||
FATAL(`Range ${start}:${end} cannot be used to create a byte-mask`);
|
||||
@@ -2109,8 +2120,8 @@ class InstRWInfoTable extends core.Task {
|
||||
}
|
||||
}
|
||||
|
||||
var s = "0x";
|
||||
for (var i = arr.length - 4; i >= 0; i -= 4) {
|
||||
let s = "0x";
|
||||
for (let i = arr.length - 4; i >= 0; i -= 4) {
|
||||
const value = (arr[i + 3] << 3) | (arr[i + 2] << 2) | (arr[i + 1] << 1) | arr[i];
|
||||
s += value.toString(16).toUpperCase();
|
||||
}
|
||||
@@ -2142,18 +2153,18 @@ class InstRWInfoTable extends core.Task {
|
||||
}
|
||||
|
||||
function queryRwGeneric(dbInsts, step) {
|
||||
var rwOps = nullOps();
|
||||
for (var i = 0; i < dbInsts.length; i++) {
|
||||
let rwOps = nullOps();
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const dbInst = dbInsts[i];
|
||||
const operands = dbInst.operands;
|
||||
|
||||
for (var j = 0; j < operands.length; j++) {
|
||||
for (let j = 0; j < operands.length; j++) {
|
||||
const op = operands[j];
|
||||
if (!op.isRegOrMem())
|
||||
continue;
|
||||
|
||||
const opSize = op.isReg() ? op.regSize : op.memSize;
|
||||
var d = {
|
||||
let d = {
|
||||
access: op.read && op.write ? "X" : op.read ? "R" : op.write ? "W" : "?",
|
||||
clc: 0,
|
||||
flags: {},
|
||||
@@ -2192,7 +2203,7 @@ class InstRWInfoTable extends core.Task {
|
||||
if (op.regIndexRel)
|
||||
d.flags.Consecutive = true;
|
||||
|
||||
for (var k in self.rwOpFlagsForInstruction(asmInst.name, j))
|
||||
for (let k in self.rwOpFlagsForInstruction(asmInst.name, j))
|
||||
d.flags[k] = true;
|
||||
|
||||
if ((step === -1 || step === j) || op.rwxIndex !== 0 || op.rwxWidth !== opSize) {
|
||||
@@ -2234,17 +2245,17 @@ class InstRWInfoTable extends core.Task {
|
||||
}
|
||||
|
||||
function queryRwByData(dbInsts, rwOpsArray) {
|
||||
for (var i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const dbInst = dbInsts[i];
|
||||
const operands = dbInst.operands;
|
||||
const rwOps = nullOps();
|
||||
|
||||
for (var j = 0; j < operands.length; j++) {
|
||||
for (let j = 0; j < operands.length; j++) {
|
||||
rwOps[j] = makeRwFromOp(operands[j])
|
||||
}
|
||||
|
||||
var match = 0;
|
||||
for (var j = 0; j < rwOpsArray.length; j++)
|
||||
let match = 0;
|
||||
for (let j = 0; j < rwOpsArray.length; j++)
|
||||
match |= ObjectUtils.equals(rwOps, rwOpsArray[j]);
|
||||
|
||||
if (!match)
|
||||
@@ -2256,12 +2267,12 @@ class InstRWInfoTable extends core.Task {
|
||||
|
||||
function dumpRwToData(dbInsts) {
|
||||
const out = [];
|
||||
for (var i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const dbInst = dbInsts[i];
|
||||
const operands = dbInst.operands;
|
||||
const rwOps = nullOps();
|
||||
|
||||
for (var j = 0; j < operands.length; j++)
|
||||
for (let j = 0; j < operands.length; j++)
|
||||
rwOps[j] = makeRwFromOp(operands[j])
|
||||
|
||||
if (ArrayUtils.deepIndexOf(out, rwOps) !== -1)
|
||||
@@ -2278,18 +2289,18 @@ class InstRWInfoTable extends core.Task {
|
||||
return { category: this.rwCategoryByName[name], rwOps: nullOps() };
|
||||
|
||||
// Generic rules.
|
||||
for (var i = -1; i <= 6; i++) {
|
||||
for (let i = -1; i <= 6; i++) {
|
||||
const rwInfo = queryRwGeneric(dbInsts, i);
|
||||
if (rwInfo)
|
||||
return rwInfo;
|
||||
}
|
||||
|
||||
// Specific rules.
|
||||
for (var k in this.rwCategoryByData)
|
||||
for (let k in this.rwCategoryByData)
|
||||
if (queryRwByData(dbInsts, this.rwCategoryByData[k]))
|
||||
return { category: k, rwOps: nullOps() };
|
||||
|
||||
// FATALURE: Missing data to categorize this instruction.
|
||||
// FATAL: Missing data to categorize this instruction.
|
||||
if (name) {
|
||||
const items = dumpRwToData(dbInsts)
|
||||
console.log(`RW: ${dbInsts.length ? dbInsts[0].name : ""}:`);
|
||||
@@ -2345,16 +2356,16 @@ class InstRWInfoTable extends core.Task {
|
||||
}
|
||||
|
||||
rmReplaceableCategory(dbInsts) {
|
||||
var category = null;
|
||||
let category = null;
|
||||
|
||||
for (var i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const dbInst = dbInsts[i];
|
||||
const operands = dbInst.operands;
|
||||
|
||||
var rs = -1;
|
||||
var ms = -1;
|
||||
let rs = -1;
|
||||
let ms = -1;
|
||||
|
||||
for (var j = 0; j < operands.length; j++) {
|
||||
for (let j = 0; j < operands.length; j++) {
|
||||
const op = operands[j];
|
||||
if (op.isMem())
|
||||
ms = op.memSize;
|
||||
@@ -2362,7 +2373,7 @@ class InstRWInfoTable extends core.Task {
|
||||
rs = Math.max(rs, op.regSize);
|
||||
}
|
||||
|
||||
var c = (rs === -1 ) ? "None" :
|
||||
let c = (rs === -1 ) ? "None" :
|
||||
(ms === -1 ) ? "None" :
|
||||
(ms === rs ) ? "Fixed" :
|
||||
(ms === rs / 2) ? "Half" :
|
||||
@@ -2391,9 +2402,9 @@ class InstRWInfoTable extends core.Task {
|
||||
|
||||
rmReplaceableIndexes(dbInsts) {
|
||||
function maskOf(inst, fn) {
|
||||
var m = 0;
|
||||
var operands = inst.operands;
|
||||
for (var i = 0; i < operands.length; i++)
|
||||
let m = 0;
|
||||
let operands = inst.operands;
|
||||
for (let i = 0; i < operands.length; i++)
|
||||
if (fn(operands[i]))
|
||||
m |= (1 << i);
|
||||
return m;
|
||||
@@ -2402,19 +2413,19 @@ class InstRWInfoTable extends core.Task {
|
||||
function getRegIndexes(inst) { return maskOf(inst, function(op) { return op.isReg(); }); };
|
||||
function getMemIndexes(inst) { return maskOf(inst, function(op) { return op.isMem(); }); };
|
||||
|
||||
var mask = 0;
|
||||
let mask = 0;
|
||||
|
||||
for (var i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const dbInst = dbInsts[i];
|
||||
|
||||
var mi = getMemIndexes(dbInst);
|
||||
var ri = getRegIndexes(dbInst) & ~mi;
|
||||
let mi = getMemIndexes(dbInst);
|
||||
let ri = getRegIndexes(dbInst) & ~mi;
|
||||
|
||||
if (!mi)
|
||||
continue;
|
||||
|
||||
const match = dbInsts.some((inst) => {
|
||||
var ti = getRegIndexes(inst);
|
||||
let ti = getRegIndexes(inst);
|
||||
return ((ri & ti) === ri && (mi & ti) === mi);
|
||||
});
|
||||
|
||||
@@ -2427,13 +2438,13 @@ class InstRWInfoTable extends core.Task {
|
||||
}
|
||||
|
||||
rmFixedSize(insts) {
|
||||
var savedOp = null;
|
||||
let savedOp = null;
|
||||
|
||||
for (var i = 0; i < insts.length; i++) {
|
||||
for (let i = 0; i < insts.length; i++) {
|
||||
const inst = insts[i];
|
||||
const operands = inst.operands;
|
||||
|
||||
for (var j = 0; j < operands.length; j++) {
|
||||
for (let j = 0; j < operands.length; j++) {
|
||||
const op = operands[j];
|
||||
if (op.mem) {
|
||||
if (savedOp && savedOp.mem !== op.mem)
|
||||
@@ -2447,11 +2458,11 @@ class InstRWInfoTable extends core.Task {
|
||||
}
|
||||
|
||||
rmIsConsistent(insts) {
|
||||
var hasMem = 0;
|
||||
for (var i = 0; i < insts.length; i++) {
|
||||
let hasMem = 0;
|
||||
for (let i = 0; i < insts.length; i++) {
|
||||
const inst = insts[i];
|
||||
const operands = inst.operands;
|
||||
for (var j = 0; j < operands.length; j++) {
|
||||
for (let j = 0; j < operands.length; j++) {
|
||||
const op = operands[j];
|
||||
if (op.mem) {
|
||||
hasMem = 1;
|
||||
@@ -2470,16 +2481,16 @@ class InstRWInfoTable extends core.Task {
|
||||
const memMap = {};
|
||||
const immMap = {};
|
||||
|
||||
for (var i = 0; i < dbInsts.length; i++) {
|
||||
for (let i = 0; i < dbInsts.length; i++) {
|
||||
const dbInst = dbInsts[i];
|
||||
const operands = dbInst.operands;
|
||||
|
||||
var memStr = "";
|
||||
var immStr = "";
|
||||
var hasMem = false;
|
||||
var hasImm = false;
|
||||
let memStr = "";
|
||||
let immStr = "";
|
||||
let hasMem = false;
|
||||
let hasImm = false;
|
||||
|
||||
for (var j = 0; j < operands.length; j++) {
|
||||
for (let j = 0; j < operands.length; j++) {
|
||||
const op = operands[j];
|
||||
if (j) {
|
||||
memStr += ", ";
|
||||
@@ -2607,7 +2618,7 @@ class InstCommonTable extends core.Task {
|
||||
inst.commonInfoIndex = table.addIndexed(row);
|
||||
});
|
||||
|
||||
var s = `#define F(VAL) uint32_t(InstDB::InstFlags::k##VAL)\n` +
|
||||
let 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` +
|
||||
|
||||
@@ -56,35 +56,50 @@ class InstructionNameData {
|
||||
this.maxNameLength = 0;
|
||||
}
|
||||
|
||||
add(s) {
|
||||
// First try to encode the string with 5-bit characters that fit into a 32-bit int.
|
||||
if (/^[a-z0-4]{0,6}$/.test(s)) {
|
||||
let index = 0;
|
||||
for (let i = 0; i < s.length; i++)
|
||||
index |= charTo5Bit(s[i]) << (i * 5);
|
||||
add(name, alt) {
|
||||
if (name === alt) {
|
||||
alt = "";
|
||||
}
|
||||
|
||||
this.names.push(s);
|
||||
if (this.maxNameLength < name.length) {
|
||||
this.maxNameLength = name.length;
|
||||
}
|
||||
|
||||
this.names.push(name);
|
||||
|
||||
// First try to encode the string with 5-bit characters that fit into a 32-bit int.
|
||||
if (/^[a-z0-4]{0,6}$/.test(name) && !alt) {
|
||||
let index = 0;
|
||||
for (let i = 0; i < name.length; i++) {
|
||||
index |= charTo5Bit(name[i]) << (i * 5);
|
||||
}
|
||||
|
||||
this.indexComment.push(`Small '${name}'.`);
|
||||
this.primaryTable.push(index | (1 << 31));
|
||||
this.indexComment.push(`Small '${s}'.`);
|
||||
}
|
||||
else if (alt) {
|
||||
const prefixIndex = this.addOrReferenceString(name + String.fromCharCode(alt.length) + alt);
|
||||
|
||||
if (name === "jz") {
|
||||
console.log(`jz prefix: ${prefixIndex}`);
|
||||
}
|
||||
|
||||
this.indexComment.push(`Large '${name}' + '${alt}'`);
|
||||
this.primaryTable.push(prefixIndex | (name.length << 12) | (0xFFF << 16) | 0);
|
||||
}
|
||||
else {
|
||||
// Put the string into a string table.
|
||||
this.names.push(s);
|
||||
this.primaryTable.push(-1);
|
||||
this.indexComment.push(``);
|
||||
this.primaryTable.push(0);
|
||||
}
|
||||
|
||||
if (this.maxNameLength < s.length)
|
||||
this.maxNameLength = s.length;
|
||||
}
|
||||
|
||||
index() {
|
||||
const kMaxPrefixSize = 15;
|
||||
const kMaxSuffixSize = 7;
|
||||
const kMaxSuffixSize = 6;
|
||||
const names = [];
|
||||
|
||||
for (let idx = 0; idx < this.primaryTable.length; idx++) {
|
||||
if (this.primaryTable[idx] === -1) {
|
||||
if (this.primaryTable[idx] === 0) {
|
||||
names.push({ name: this.names[idx], index: idx });
|
||||
}
|
||||
}
|
||||
@@ -205,11 +220,20 @@ class InstructionNameData {
|
||||
FATAL(`IndexedString.formatStringTable(): Not indexed yet, call index()`);
|
||||
|
||||
let s = "";
|
||||
for (let i = 0; i < this.stringTable.length; i += 80) {
|
||||
if (s)
|
||||
s += "\n"
|
||||
s += '"' + this.stringTable.substring(i, i + 80) + '"';
|
||||
let line = "";
|
||||
|
||||
for (let i = 0; i < this.stringTable.length; i++) {
|
||||
const c = this.stringTable.charCodeAt(i);
|
||||
line += "\\x" + cxx.Utils.toHexRaw(c, 2);
|
||||
|
||||
if (line.length >= 115 || i === this.stringTable.length - 1) {
|
||||
if (s)
|
||||
s += "\n"
|
||||
s += `"${line}"`;
|
||||
line = "";
|
||||
}
|
||||
}
|
||||
|
||||
s += ";\n";
|
||||
|
||||
return `const char ${tableName}[] =\n${StringUtils.indent(s, " ")}\n`;
|
||||
@@ -288,7 +312,9 @@ class Injector {
|
||||
const path = kAsmJitRoot + "/" + file;
|
||||
console.log(`MODIFIED '${file}'`);
|
||||
|
||||
fs.writeFileSync(path + ".backup", obj.prev, "utf8");
|
||||
if (!fs.existsSync(path + ".backup")) {
|
||||
fs.writeFileSync(path + ".backup", obj.prev, "utf8");
|
||||
}
|
||||
fs.writeFileSync(path, obj.data, "utf8");
|
||||
}
|
||||
}
|
||||
@@ -346,7 +372,7 @@ exports.Injector = Injector;
|
||||
// Main context used to load, generate, and store instruction tables. The idea
|
||||
// is to be extensible, so it stores 'Task's to be executed with minimal deps
|
||||
// management.
|
||||
class TableGen extends Injector{
|
||||
class TableGen extends Injector {
|
||||
constructor(arch) {
|
||||
super();
|
||||
|
||||
@@ -418,7 +444,7 @@ class TableGen extends Injector{
|
||||
// [Instruction Management]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
addInst(inst) {
|
||||
addInstruction(inst) {
|
||||
if (this.instMap[inst.name])
|
||||
FATAL(`TableGen.addInst(): Instruction '${inst.name}' already added`);
|
||||
|
||||
@@ -471,19 +497,35 @@ class IdEnum extends Task {
|
||||
run() {
|
||||
const insts = this.ctx.insts;
|
||||
|
||||
var s = "";
|
||||
for (var i = 0; i < insts.length; i++) {
|
||||
let s = "";
|
||||
let aliases = "";
|
||||
|
||||
for (let i = 0; i < insts.length; i++) {
|
||||
const inst = insts[i];
|
||||
|
||||
var line = "kId" + inst.enum + (i ? "" : " = 0") + ",";
|
||||
var text = this.comment(inst);
|
||||
let line = "kId" + inst.enum + (i ? "" : " = 0") + ",";
|
||||
let text = this.comment(inst);
|
||||
|
||||
if (text)
|
||||
line = line.padEnd(37) + "//!< " + text;
|
||||
|
||||
s += line + "\n";
|
||||
|
||||
if (inst.aliases) {
|
||||
for (let aliasName of inst.aliases.aliasNames) {
|
||||
if (aliases) aliases += ",\n";
|
||||
aliases += `kId${StringUtils.makeEnumName(aliasName)} = kId${inst.enum}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
s += "_kIdCount";
|
||||
|
||||
if (aliases) {
|
||||
s += ",\n\n" + "// Aliases.\n" + aliases + "\n";
|
||||
}
|
||||
else {
|
||||
s += "\n";
|
||||
}
|
||||
s += "_kIdCount\n";
|
||||
|
||||
return this.ctx.inject("InstId", s);
|
||||
}
|
||||
@@ -507,16 +549,43 @@ class Output {
|
||||
};
|
||||
exports.Output = Output;
|
||||
|
||||
function generateNameData(out, instructions) {
|
||||
function cmp(a, b) { return (a < b) ? -1 : a > b ? 1 : 0; }
|
||||
|
||||
function generateNameData(out, instructions, generateAliases) {
|
||||
const none = "Inst::kIdNone";
|
||||
|
||||
const aliases = [];
|
||||
const aliasNameData = new InstructionNameData();
|
||||
const aliasLinkData = [];
|
||||
|
||||
const instFirst = new Array(26);
|
||||
const instLast = new Array(26);
|
||||
const instNameData = new InstructionNameData();
|
||||
|
||||
for (let i = 0; i < instructions.length; i++)
|
||||
instNameData.add(instructions[i].displayName);
|
||||
for (let i = 0; i < instructions.length; i++) {
|
||||
const instruction = instructions[i];
|
||||
|
||||
if (instruction.aliases) {
|
||||
instNameData.add(instruction.displayName, instruction.aliases.format);
|
||||
for (let aliasName of instruction.aliases.aliasNames) {
|
||||
aliases.push({ name: instruction.name, alt: aliasName });
|
||||
}
|
||||
}
|
||||
else {
|
||||
instNameData.add(instruction.displayName);
|
||||
}
|
||||
}
|
||||
|
||||
aliases.sort(function(a, b) { return cmp(a.alt, b.alt); });
|
||||
|
||||
for (let i = 0; i < aliases.length; i++) {
|
||||
const alias = aliases[i];
|
||||
aliasNameData.add(alias.alt);
|
||||
aliasLinkData.push(`Inst::kId${StringUtils.makeEnumName(alias.name)}`);
|
||||
}
|
||||
|
||||
instNameData.index();
|
||||
aliasNameData.index();
|
||||
|
||||
for (let i = 0; i < instructions.length; i++) {
|
||||
const inst = instructions[i];
|
||||
@@ -548,21 +617,41 @@ function generateNameData(out, instructions) {
|
||||
s += `\n`;
|
||||
s += instNameData.formatIndexTable("InstDB::_instNameIndexTable");
|
||||
|
||||
const dataSize = instNameData.getSize() + 26 * 4;
|
||||
let dataSize = instNameData.getSize() + 26 * 4;
|
||||
|
||||
if (generateAliases) {
|
||||
s += `\n`;
|
||||
s += aliasNameData.formatStringTable("InstDB::_aliasNameStringTable");
|
||||
s += `\n`;
|
||||
s += aliasNameData.formatIndexTable("InstDB::_aliasNameIndexTable");
|
||||
s += "\n";
|
||||
s += "const uint32_t InstDB::_aliasIndexToInstId[] = {\n" + StringUtils.format(aliasLinkData, " ", true, null) + "\n};\n";
|
||||
|
||||
dataSize += aliasNameData.getSize();
|
||||
let info = `static constexpr uint32_t kAliasTableSize = ${aliasLinkData.length};\n`;
|
||||
out.add("NameDataInfo", StringUtils.disclaimer(info), 0);
|
||||
}
|
||||
|
||||
out.add("NameData", StringUtils.disclaimer(s), dataSize);
|
||||
return out;
|
||||
}
|
||||
exports.generateNameData = generateNameData;
|
||||
|
||||
class NameTable extends Task {
|
||||
constructor(name, deps) {
|
||||
constructor(name, deps, generateAliases) {
|
||||
super(name || "NameTable", deps);
|
||||
this.generateAliases = generateAliases;
|
||||
}
|
||||
|
||||
run() {
|
||||
const output = new Output();
|
||||
generateNameData(output, this.ctx.insts);
|
||||
generateNameData(output, this.ctx.insts, this.generateAliases);
|
||||
|
||||
this.ctx.inject("NameData", output.content["NameData"], output.tableSize["NameData"]);
|
||||
|
||||
if (this.generateAliases) {
|
||||
this.ctx.inject("NameDataInfo", output.content["NameDataInfo"], output.tableSize["NameDataInfo"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.NameTable = NameTable;
|
||||
|
||||
Reference in New Issue
Block a user