diff options
Diffstat (limited to '3rdparty/asmjit/tools/tablegen-arm.js')
-rw-r--r-- | 3rdparty/asmjit/tools/tablegen-arm.js | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/3rdparty/asmjit/tools/tablegen-arm.js b/3rdparty/asmjit/tools/tablegen-arm.js new file mode 100644 index 00000000000..e1c829358e2 --- /dev/null +++ b/3rdparty/asmjit/tools/tablegen-arm.js @@ -0,0 +1,365 @@ +// [AsmJit] +// Machine Code Generation for C++. +// +// [License] +// ZLIB - See LICENSE.md file in the package. + +// ============================================================================ +// tablegen-arm.js +// ============================================================================ + +"use strict"; + +const { executionAsyncResource } = require("async_hooks"); +const core = require("./tablegen.js"); +const hasOwn = Object.prototype.hasOwnProperty; + +const asmdb = core.asmdb; +const kIndent = core.kIndent; +const IndexedArray = core.IndexedArray; +const StringUtils = core.StringUtils; + +const FAIL = core.FAIL; + +// ============================================================================ +// [ArmDB] +// ============================================================================ + +// Create ARM ISA. +const isa = new asmdb.arm.ISA(); + +// ============================================================================ +// [tablegen.arm.GenUtils] +// ============================================================================ + +class GenUtils { + // Get a list of instructions based on `name` and optional `mode`. + static query(name, mode) { + const insts = isa.query(name); + return !mode ? insts : insts.filter(function(inst) { return inst.arch === mode; }); + } + + static archOf(records) { + var t16Arch = false; + var t32Arch = false; + var a32Arch = false; + var a64Arch = false; + + for (var i = 0; i < records.length; i++) { + const record = records[i]; + if (record.encoding === "T16") t16Arch = true; + if (record.encoding === "T32") t32Arch = true; + if (record.encoding === "A32") a32Arch = true; + if (record.encoding === "A64") a64Arch = true; + } + + var s = (t16Arch && !t32Arch) ? "T16" : + (t32Arch && !t16Arch) ? "T32" : + (t16Arch && t32Arch) ? "Txx" : "---"; + s += " "; + s += (a32Arch) ? "A32" : "---"; + s += " "; + s += (a64Arch) ? "A64" : "---"; + + return `[${s}]`; + } + + static featuresOf(records) { + const exts = Object.create(null); + for (var i = 0; i < records.length; i++) { + const record = records[i]; + for (var k in record.extensions) + exts[k] = true; + } + const arr = Object.keys(exts); + arr.sort(); + return arr; + } +} + +// ============================================================================ +// [tablegen.arm.ArmTableGen] +// ============================================================================ + +class ArmTableGen extends core.TableGen { + constructor() { + super("A64"); + } + + // -------------------------------------------------------------------------- + // [Parse / Merge] + // -------------------------------------------------------------------------- + + parse() { + const rawData = this.dataOfFile("src/asmjit/arm/a64instdb.cpp"); + const stringData = StringUtils.extract(rawData, "// ${InstInfo:Begin}", "// ${InstInfo:End"); + + const re = new RegExp( + "INST\\(\\s*" + + // [01] Instruction. + "(" + + "[A-Za-z0-9_]+" + + ")\\s*,\\s*" + + + // [02] Encoding. + "(" + + "[^,]+" + + ")\\s*,\\s*" + + + // [03] OpcodeData. + "(" + + "\\([^\\)]+\\)" + + ")\\s*,\\s*" + + + // [04] RWInfo. + "(" + + "[^,]+" + + ")\\s*,\\s*" + + + // [05] InstructionFlags. + "(\\s*" + + "(?:" + + "(?:" + + "[\\d]+" + + "|" + + "F\\([^\\)]*\\)" + + ")" + + "\\s*" + + "[|]?\\s*" + + ")+" + + ")\\s*,\\s*" + + + // --- autogenerated fields --- + + // [06] OpcodeDataIndex. + "([^\\)]+)" + + "\\s*,\\s*" + + + // [07] NameDataIndex. + "([^\\)]+)" + + "\\s*\\)" + , "g"); + + var m; + while ((m = re.exec(stringData)) !== null) { + var enum_ = m[1]; + var name = enum_ === "None" ? "" : enum_.toLowerCase(); + var encoding = m[2].trim(); + var opcodeData = m[3].trim(); + var rwInfo = m[4].trim(); + var instFlags = m[5].trim(); + + var displayName = name; + if (name.endsWith("_v")) + displayName = name.substring(0, name.length - 2); + + // We have just matched #define INST() + if (name == "id" && + encoding === "encoding" && + encodingDataIndex === "encodingDataIndex") + continue; + + this.addInst({ + id : 0, // Instruction id (numeric value). + name : name, // Instruction name. + displayName : displayName, // Instruction name to display. + enum : enum_, // Instruction enum without `kId` prefix. + encoding : encoding, // Opcode encoding. + opcodeData : opcodeData, // Opcode data. + opcodeDataIndex : -1, // Opcode data index. + rwInfo : rwInfo, // RW info. + flags : instFlags, // Instruction flags. + + nameIndex : -1 // Index to InstDB::_nameData. + }); + } + + if (this.insts.length === 0 || this.insts.length !== StringUtils.countOf(stringData, "INST(")) + FAIL("ARMTableGen.parse(): Invalid parsing regexp (no data parsed)"); + + console.log("Number of Instructions: " + this.insts.length); + } + + merge() { + var s = StringUtils.format(this.insts, "", true, function(inst) { + return "INST(" + + String(inst.enum ).padEnd(17) + ", " + + String(inst.encoding ).padEnd(19) + ", " + + String(inst.opcodeData ).padEnd(86) + ", " + + String(inst.rwInfo ).padEnd(10) + ", " + + String(inst.flags ).padEnd(26) + ", " + + String(inst.opcodeDataIndex ).padEnd( 3) + ", " + + String(inst.nameIndex ).padEnd( 4) + ")"; + }) + "\n"; + return this.inject("InstInfo", s, this.insts.length * 4); + } + + // -------------------------------------------------------------------------- + // [Hooks] + // -------------------------------------------------------------------------- + + onBeforeRun() { + this.load([ + "src/asmjit/arm/a64emitter.h", + "src/asmjit/arm/a64globals.h", + "src/asmjit/arm/a64instdb.cpp", + "src/asmjit/arm/a64instdb.h", + "src/asmjit/arm/a64instdb_p.h" + ]); + this.parse(); + } + + onAfterRun() { + this.merge(); + this.save(); + this.dumpTableSizes(); + } +} + +// ============================================================================ +// [tablegen.arm.IdEnum] +// ============================================================================ + +class IdEnum extends core.IdEnum { + constructor() { + super("IdEnum"); + } + + comment(inst) { + let name = inst.name; + let ext = []; + + if (name.endsWith("_v")) { + name = name.substr(0, name.length - 2); + ext.push("ASIMD"); + } + + let exts = ""; + if (ext.length) + exts = " {" + ext.join("&") + "}"; + + return `Instruction '${name}'${exts}.`; + } +} + +// ============================================================================ +// [tablegen.arm.NameTable] +// ============================================================================ + +class NameTable extends core.NameTable { + constructor() { + super("NameTable"); + } +} + +// ============================================================================ +// [tablegen.arm.EncodingTable] +// ============================================================================ + +class EncodingTable extends core.Task { + constructor() { + super("EncodingTable"); + } + + run() { + const insts = this.ctx.insts; + const map = {}; + + for (var i = 0; i < insts.length; i++) { + const inst = insts[i]; + + const encoding = inst.encoding; + const opcodeData = inst.opcodeData.replace(/\(/g, "{ ").replace(/\)/g, " }"); + + if (!hasOwn.call(map, encoding)) + map[encoding] = []; + + if (inst.opcodeData === "(_)") { + inst.opcodeDataIndex = 0; + continue; + } + + const opcodeTable = map[encoding]; + const opcodeDataIndex = opcodeTable.length; + + opcodeTable.push({ name: inst.name, data: opcodeData }); + inst.opcodeDataIndex = opcodeDataIndex; + } + + const keys = Object.keys(map); + keys.sort(); + + var tableSource = ""; + var tableHeader = ""; + var encodingIds = ""; + + encodingIds += "enum EncodingId : uint32_t {\n" + encodingIds += " kEncodingNone = 0"; + + keys.forEach((dataClass) => { + const dataName = dataClass[0].toLowerCase() + dataClass.substr(1); + const opcodeTable = map[dataClass]; + const count = opcodeTable.length; + + if (dataClass !== "None") { + encodingIds += ",\n" + encodingIds += " kEncoding" + dataClass; + } + + if (count) { + tableHeader += `extern const ${dataClass} ${dataName}[${count}];\n`; + + if (tableSource) + tableSource += "\n"; + + tableSource += `const ${dataClass} ${dataName}[${count}] = {\n`; + for (var i = 0; i < count; i++) { + tableSource += ` ${opcodeTable[i].data}` + (i == count - 1 ? " " : ",") + " // " + opcodeTable[i].name + "\n"; + } + tableSource += `};\n`; + } + }); + + encodingIds += "\n};\n"; + + return this.ctx.inject("EncodingId" , StringUtils.disclaimer(encodingIds), 0) + + this.ctx.inject("EncodingDataForward", StringUtils.disclaimer(tableHeader), 0) + + this.ctx.inject("EncodingData" , StringUtils.disclaimer(tableSource), 0); + } +} +// ============================================================================ +// [tablegen.arm.CommonTable] +// ============================================================================ + +class CommonTable extends core.Task { + constructor() { + super("CommonTable", [ + "IdEnum", + "NameTable" + ]); + } + + run() { + //const table = new IndexedArray(); + + //for (var i = 0; i < insts.length; i++) { + // const inst = insts[i]; + // const item = "{ " + "0" + "}"; + // inst.commonIndex = table.addIndexed(item); + //} + + // return this.ctx.inject("InstInfo", StringUtils.disclaimer(s), 0); + return 0; + } +} + +// ============================================================================ +// [Main] +// ============================================================================ + +new ArmTableGen() + .addTask(new IdEnum()) + .addTask(new NameTable()) + .addTask(new EncodingTable()) + .addTask(new CommonTable()) + .run(); |