// [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*\\)" , "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. }); } 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) + ")" ; }) + "\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();