diff options
Diffstat (limited to '3rdparty/asmjit/tools/tablegen.js')
-rw-r--r-- | 3rdparty/asmjit/tools/tablegen.js | 871 |
1 files changed, 246 insertions, 625 deletions
diff --git a/3rdparty/asmjit/tools/tablegen.js b/3rdparty/asmjit/tools/tablegen.js index fdc65fd1cbd..a151805675b 100644 --- a/3rdparty/asmjit/tools/tablegen.js +++ b/3rdparty/asmjit/tools/tablegen.js @@ -12,618 +12,227 @@ "use strict"; -const VERBOSE = false; - // ============================================================================ // [Imports] // ============================================================================ const fs = require("fs"); -const hasOwn = Object.prototype.hasOwnProperty; -const asmdb = (function() { - // Try to import a local 'asmdb' package, if available. - try { - return require("./asmdb"); - } - catch (ex) { - if (ex.code !== "MODULE_NOT_FOUND") { - console.log(`FATAL ERROR: ${ex.message}`); - throw ex; - } - } +const commons = require("./generator-commons.js"); +const cxx = require("./generator-cxx.js"); +const asmdb = require("../db"); - // Try to import global 'asmdb' package as local package is not available. - return require("asmdb"); -})(); exports.asmdb = asmdb; +exports.exp = asmdb.base.exp; -// ============================================================================ -// [Constants] -// ============================================================================ +const hasOwn = Object.prototype.hasOwnProperty; -const kIndent = " "; -const kJustify = 119; -const kAsmJitRoot = ".."; +const FATAL = commons.FATAL; +const StringUtils = commons.StringUtils; -exports.kIndent = kIndent; -exports.kJustify = kJustify; +const kAsmJitRoot = ".."; exports.kAsmJitRoot = kAsmJitRoot; // ============================================================================ -// [Debugging] +// [InstructionNameData] // ============================================================================ -function DEBUG(msg) { - if (VERBOSE) - console.log(msg); -} -exports.DEBUG = DEBUG; - -function WARN(msg) { - console.log(msg); -} -exports.WARN = WARN; - -function FAIL(msg) { - console.log(`FATAL ERROR: ${msg}`); - throw new Error(msg); +function charTo5Bit(c) { + if (c >= 'a' && c <= 'z') + return 1 + (c.charCodeAt(0) - 'a'.charCodeAt(0)); + else if (c >= '0' && c <= '4') + return 1 + 26 + (c.charCodeAt(0) - '0'.charCodeAt(0)); + else + FATAL(`Character '${c}' cannot be encoded into a 5-bit string`); } -exports.FAIL = FAIL; - -// ============================================================================ -// [Lang] -// ============================================================================ - -function nop(x) { return x; } -class Lang { - static merge(a, b) { - if (a === b) - return a; - - for (var k in b) { - var av = a[k]; - var bv = b[k]; - - if (typeof av === "object" && typeof bv === "object") - Lang.merge(av, bv); - else - a[k] = bv; - } - - return a; +class InstructionNameData { + constructor() { + this.names = []; + this.primaryTable = []; + this.stringTable = ""; + this.size = 0; + this.indexComment = []; + this.maxNameLength = 0; } - static deepEq(a, b) { - if (a === b) - return true; - - if (typeof a !== typeof b) - return false; - - if (typeof a !== "object") - return a === b; - - if (Array.isArray(a) || Array.isArray(b)) { - if (Array.isArray(a) !== Array.isArray(b)) - return false; - - const len = a.length; - if (b.length !== len) - return false; - - for (var i = 0; i < len; i++) - if (!Lang.deepEq(a[i], b[i])) - return false; + 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); + + this.names.push(s); + this.primaryTable.push(index | (1 << 31)); + this.indexComment.push(`Small '${s}'.`); } else { - if (a === null || b === null) - return a === b; - - for (var k in a) - if (!hasOwn.call(b, k) || !Lang.deepEq(a[k], b[k])) - return false; - - for (var k in b) - if (!hasOwn.call(a, k)) - return false; + // Put the string into a string table. + this.names.push(s); + this.primaryTable.push(-1); + this.indexComment.push(``); } - return true; + if (this.maxNameLength < s.length) + this.maxNameLength = s.length; } - static deepEqExcept(a, b, except) { - if (a === b) - return true; - - if (typeof a !== "object" || typeof b !== "object" || Array.isArray(a) || Array.isArray(b)) - return Lang.deepEq(a, b); - - for (var k in a) - if (!hasOwn.call(except, k) && (!hasOwn.call(b, k) || !Lang.deepEq(a[k], b[k]))) - return false; - - for (var k in b) - if (!hasOwn.call(except, k) && !hasOwn.call(a, k)) - return false; - - return true; - } -} -exports.Lang = Lang; - -// ============================================================================ -// [StringUtils] -// ============================================================================ - -class StringUtils { - static asString(x) { return String(x); } - - static countOf(s, pattern) { - if (!pattern) - FAIL(`Pattern cannot be empty`); - - var n = 0; - var pos = 0; + index() { + const kMaxPrefixSize = 15; + const kMaxSuffixSize = 7; + const names = []; - while ((pos = s.indexOf(pattern, pos)) >= 0) { - n++; - pos += pattern.length; + for (let idx = 0; idx < this.primaryTable.length; idx++) { + if (this.primaryTable[idx] === -1) { + names.push({ name: this.names[idx], index: idx }); + } } - return n; - } + names.sort(function(a, b) { + if (a.name.length > b.name.length) + return -1; + if (a.name.length < b.name.length) + return 1; + return (a > b) ? 1 : (a < b) ? -1 : 0; + }); - static capitalize(s) { - s = String(s); - return !s ? s : s[0].toUpperCase() + s.substr(1); - } + for (let z = 0; z < names.length; z++) { + const idx = names[z].index; + const name = names[z].name; - static trimLeft(s) { return s.replace(/^\s+/, ""); } - static trimRight(s) { return s.replace(/\s+$/, ""); } + let done = false; + let longestPrefix = 0; + let longestSuffix = 0; - static upFirst(s) { - if (!s) return ""; - return s[0].toUpperCase() + s.substr(1); - } + let prefix = ""; + let suffix = ""; - static decToHex(n, nPad) { - var hex = Number(n < 0 ? 0x100000000 + n : n).toString(16); - while (nPad > hex.length) - hex = "0" + hex; - return "0x" + hex.toUpperCase(); - } + for (let i = Math.min(name.length, kMaxPrefixSize); i > 0; i--) { + prefix = name.substring(0, i); + suffix = name.substring(i); - static format(array, indent, showIndex, mapFn) { - if (!mapFn) - mapFn = StringUtils.asString; + const prefixIndex = this.stringTable.indexOf(prefix); + const suffixIndex = this.stringTable.indexOf(suffix); - var s = ""; - var threshold = 80; + // Matched both parts? + if (prefixIndex !== -1 && suffix === "") { + done = true; + break; + } - if (showIndex === -1) - s += indent; + if (prefixIndex !== -1 && suffixIndex !== -1) { + done = true; + break; + } - for (var i = 0; i < array.length; i++) { - const item = array[i]; - const last = i === array.length - 1; + if (prefixIndex !== -1 && longestPrefix === 0) + longestPrefix = prefix.length; - if (showIndex !== -1) - s += indent; + if (suffixIndex !== -1 && suffix.length > longestSuffix) + longestSuffix = suffix.length; - s += mapFn(item); - if (showIndex > 0) { - s += `${last ? " " : ","} // #${i}`; - if (typeof array.refCountOf === "function") - s += ` [ref=${array.refCountOf(item)}x]`; - } - else if (!last) { - s += ","; + if (suffix.length === kMaxSuffixSize) + break; } - if (showIndex === -1) { - if (s.length >= threshold - 1 && !last) { - s += "\n" + indent; - threshold += 80; + if (!done) { + let minPrefixSize = name.length >= 8 ? name.length / 2 + 1 : name.length - 2; + + prefix = ""; + suffix = ""; + + if (longestPrefix >= minPrefixSize) { + prefix = name.substring(0, longestPrefix); + suffix = name.substring(longestPrefix); + } + else if (longestSuffix) { + const splitAt = Math.min(name.length - longestSuffix, kMaxPrefixSize); + prefix = name.substring(0, splitAt); + suffix = name.substring(splitAt); + } + else if (name.length > kMaxPrefixSize) { + prefix = name.substring(0, kMaxPrefixSize); + suffix = name.substring(kMaxPrefixSize); } else { - if (!last) s += " "; + prefix = name; + suffix = ""; } } - else { - if (!last) s += "\n"; - } - } - return s; - } + if (suffix) { + const prefixIndex = this.addOrReferenceString(prefix); + const suffixIndex = this.addOrReferenceString(suffix); - static makeCxxArray(array, code, indent) { - if (!indent) indent = kIndent; - return `${code} = {\n${indent}` + array.join(`,\n${indent}`) + `\n};\n`; - } - - static makeCxxArrayWithComment(array, code, indent) { - if (!indent) indent = kIndent; - var s = ""; - for (var i = 0; i < array.length; i++) { - const last = i === array.length - 1; - s += indent + array[i].data + - (last ? " // " : ", // ") + (array[i].refs ? "#" + String(i) : "").padEnd(5) + array[i].comment + "\n"; - } - return `${code} = {\n${s}};\n`; - } - - static disclaimer(s) { - return "// ------------------- Automatically generated, do not edit -------------------\n" + - s + - "// ----------------------------------------------------------------------------\n"; - } - - static indent(s, indentation) { - var lines = s.split(/\r?\n/g); - if (indentation) { - for (var i = 0; i < lines.length; i++) { - var line = lines[i]; - if (line) lines[i] = indentation + line; + this.primaryTable[idx] = prefixIndex | (prefix.length << 12) | (suffixIndex << 16) | (suffix.length << 28); + this.indexComment[idx] = `Large '${prefix}|${suffix}'.`; } - } - - return lines.join("\n"); - } - - static extract(s, start, end) { - var iStart = s.indexOf(start); - var iEnd = s.indexOf(end); - - if (iStart === -1) - FAIL(`StringUtils.extract(): Couldn't locate start mark '${start}'`); - - if (iEnd === -1) - FAIL(`StringUtils.extract(): Couldn't locate end mark '${end}'`); - - return s.substring(iStart + start.length, iEnd).trim(); - } - - static inject(s, start, end, code) { - var iStart = s.indexOf(start); - var iEnd = s.indexOf(end); - - if (iStart === -1) - FAIL(`StringUtils.inject(): Couldn't locate start mark '${start}'`); - - if (iEnd === -1) - FAIL(`StringUtils.inject(): Couldn't locate end mark '${end}'`); - - var nIndent = 0; - while (iStart > 0 && s[iStart-1] === " ") { - iStart--; - nIndent++; - } + else { + const prefixIndex = this.addOrReferenceString(prefix); - if (nIndent) { - const indentation = " ".repeat(nIndent); - code = StringUtils.indent(code, indentation) + indentation; + this.primaryTable[idx] = prefixIndex | (prefix.length << 12); + this.indexComment[idx] = `Large '${prefix}'.`; + } } - - return s.substr(0, iStart + start.length + nIndent) + code + s.substr(iEnd); } - static makePriorityCompare(priorityArray) { - const map = Object.create(null); - priorityArray.forEach((str, index) => { map[str] = index; }); - - return function(a, b) { - const ax = hasOwn.call(map, a) ? map[a] : Infinity; - const bx = hasOwn.call(map, b) ? map[b] : Infinity; - return ax != bx ? ax - bx : a < b ? -1 : a > b ? 1 : 0; + addOrReferenceString(s) { + let index = this.stringTable.indexOf(s); + if (index === -1) { + index = this.stringTable.length; + this.stringTable += s; } + return index; } -} -exports.StringUtils = StringUtils; - -// ============================================================================ -// [ArrayUtils] -// ============================================================================ - -class ArrayUtils { - static min(arr, fn) { - if (!arr.length) - return null; - - if (!fn) - fn = nop; - - var v = fn(arr[0]); - for (var i = 1; i < arr.length; i++) - v = Math.min(v, fn(arr[i])); - return v; - } - - static max(arr, fn) { - if (!arr.length) - return null; - - if (!fn) - fn = nop; - - var v = fn(arr[0]); - for (var i = 1; i < arr.length; i++) - v = Math.max(v, fn(arr[i])); - return v; - } - - static sorted(obj, cmp) { - const out = Array.isArray(obj) ? obj.slice() : Object.getOwnPropertyNames(obj); - out.sort(cmp); - return out; - } - - static deepIndexOf(arr, what) { - for (var i = 0; i < arr.length; i++) - if (Lang.deepEq(arr[i], what)) - return i; - return -1; - } -} -exports.ArrayUtils = ArrayUtils; - -// ============================================================================ -// [MapUtils] -// ============================================================================ - -class MapUtils { - static clone(map) { - return Object.assign(Object.create(null), map); - } - - static arrayToMap(arr, value) { - if (value === undefined) - value = true; - - const out = Object.create(null); - for (var i = 0; i < arr.length; i++) - out[arr[i]] = value; - return out; - } - - static equals(a, b) { - for (var k in a) if (!hasOwn.call(b, k)) return false; - for (var k in b) if (!hasOwn.call(a, k)) return false; - return true; - } - - static firstOf(map, flags) { - for (var k in flags) - if (hasOwn.call(map, k)) - return k; - return undefined; - } - - static anyOf(map, flags) { - for (var k in flags) - if (hasOwn.call(map, k)) - return true; - return false; - } - - static add(a, b) { - for (var k in b) - a[k] = b[k]; - return a; - } - - static and(a, b) { - const out = Object.create(null); - for (var k in a) - if (hasOwn.call(b, k)) - out[k] = true; - return out; - } - - static xor(a, b) { - const out = Object.create(null); - for (var k in a) if (!hasOwn.call(b, k)) out[k] = true; - for (var k in b) if (!hasOwn.call(a, k)) out[k] = true; - return out; - } -}; -exports.MapUtils = MapUtils; - -// ============================================================================ -// [CxxUtils] -// ============================================================================ - -class CxxUtils { - static flags(obj, fn, none) { - if (none == null) - none = "0"; - - if (!fn) - fn = nop; - - var out = ""; - for (var k in obj) { - if (obj[k]) - out += (out ? " | " : "") + fn(k); - } - return out ? out : none; - } - - static struct(...args) { - return "{ " + args.join(", ") + " }"; - } -}; -exports.CxxUtils = CxxUtils; - -// ============================================================================ -// [IndexedString] -// ============================================================================ - -// IndexedString is mostly used to merge all instruction names into a single -// string with external index. It's designed mostly for generating C++ tables. -// -// Consider the following cases in C++: -// -// a) static const char* const* instNames = { "add", "mov", "vpunpcklbw" }; -// -// b) static const char instNames[] = { "add\0" "mov\0" "vpunpcklbw\0" }; -// static const uint16_t instNameIndex[] = { 0, 4, 8 }; -// -// The latter (b) has an advantage that it doesn't have to be relocated by the -// linker, which saves a lot of space in the resulting binary and a lot of CPU -// cycles (and memory) when the linker loads it. AsmJit supports thousands of -// instructions so each optimization like this makes it smaller and faster to -// load. -class IndexedString { - constructor() { - this.map = Object.create(null); - this.array = []; - this.size = -1; - } - - add(s) { - this.map[s] = -1; - } - - index() { - const map = this.map; - const array = this.array; - const partialMap = Object.create(null); - - var k, kp; - var i, len; - - // Create a map that will contain all keys and partial keys. - for (k in map) { - if (!k) { - partialMap[k] = k; - } - else { - for (i = 0, len = k.length; i < len; i++) { - kp = k.substr(i); - if (!hasOwn.call(partialMap, kp) || partialMap[kp].length < len) - partialMap[kp] = k; - } - } - } - - // Create an array that will only contain keys that are needed. - for (k in map) - if (partialMap[k] === k) - array.push(k); - array.sort(); - - // Create valid offsets to the `array`. - var offMap = Object.create(null); - var offset = 0; - for (i = 0, len = array.length; i < len; i++) { - k = array[i]; + formatIndexTable(tableName) { + if (this.size === -1) + FATAL(`IndexedString.formatIndexTable(): Not indexed yet, call index()`); - offMap[k] = offset; - offset += k.length + 1; + let s = ""; + for (let i = 0; i < this.primaryTable.length; i++) { + s += cxx.Utils.toHex(this.primaryTable[i], 8); + s += i !== this.primaryTable.length - 1 ? "," : " "; + s += " // " + this.indexComment[i] + "\n"; } - this.size = offset; - // Assign valid offsets to `map`. - for (kp in map) { - k = partialMap[kp]; - map[kp] = offMap[k] + k.length - kp.length; - } + return `const uint32_t ${tableName}[] = {\n${StringUtils.indent(s, " ")}};\n`; } - format(indent, justify) { + formatStringTable(tableName) { if (this.size === -1) - FAIL(`IndexedString.format(): not indexed yet, call index()`); - - const array = this.array; - if (!justify) justify = 0; - - var i; - var s = ""; - var line = ""; + FATAL(`IndexedString.formatStringTable(): Not indexed yet, call index()`); - for (i = 0; i < array.length; i++) { - const item = "\"" + array[i] + ((i !== array.length - 1) ? "\\0\"" : "\";"); - const newl = line + (line ? " " : indent) + item; - - if (newl.length <= justify) { - line = newl; - continue; - } - else { - s += line + "\n"; - line = indent + item; - } + let s = ""; + for (let i = 0; i < this.stringTable.length; i += 80) { + if (s) + s += "\n" + s += '"' + this.stringTable.substring(i, i + 80) + '"'; } + s += ";\n"; - return s + line; + return `const char ${tableName}[] =\n${StringUtils.indent(s, " ")}\n`; } getSize() { if (this.size === -1) - FAIL(`IndexedString.getSize(): Not indexed yet, call index()`); - return this.size; + FATAL(`IndexedString.getSize(): Not indexed yet, call index()`); + + return this.primaryTable.length * 4 + this.stringTable.length; } getIndex(k) { if (this.size === -1) - FAIL(`IndexedString.getIndex(): Not indexed yet, call index()`); + FATAL(`IndexedString.getIndex(): Not indexed yet, call index()`); if (!hasOwn.call(this.map, k)) - FAIL(`IndexedString.getIndex(): Key '${k}' not found.`); + FATAL(`IndexedString.getIndex(): Key '${k}' not found.`); return this.map[k]; } } -exports.IndexedString = IndexedString; - -// ============================================================================ -// [IndexedArray] -// ============================================================================ - -// IndexedArray is an Array replacement that allows to index each item inserted -// to it. Its main purpose is to avoid data duplication, if an item passed to -// `addIndexed()` is already within the Array then it's not inserted and the -// existing index is returned instead. -function IndexedArray_keyOf(item) { - return typeof item === "string" ? item : JSON.stringify(item); -} - -class IndexedArray extends Array { - constructor() { - super(); - this._index = Object.create(null); - } - - refCountOf(item) { - const key = IndexedArray_keyOf(item); - const idx = this._index[key]; - - return idx !== undefined ? idx.refCount : 0; - } - - addIndexed(item) { - const key = IndexedArray_keyOf(item); - var idx = this._index[key]; - - if (idx !== undefined) { - idx.refCount++; - return idx.data; - } - - idx = this.length; - this._index[key] = { - data: idx, - refCount: 1 - }; - this.push(item); - return idx; - } -} -exports.IndexedArray = IndexedArray; +exports.InstructionNameData = InstructionNameData; // ============================================================================ // [Task] @@ -643,7 +252,7 @@ class Task { } run() { - FAIL("Task.run(): Must be reimplemented"); + FATAL("Task.run(): Must be reimplemented"); } } exports.Task = Task; @@ -652,29 +261,12 @@ exports.Task = Task; // [TableGen] // ============================================================================ -// 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 { - constructor(arch) { - this.arch = arch; +class Injector { + constructor() { this.files = Object.create(null); this.tableSizes = Object.create(null); - - this.tasks = []; - this.taskMap = Object.create(null); - - this.insts = []; - this.instMap = Object.create(null); - - this.aliases = []; - this.aliasMem = Object.create(null); } - // -------------------------------------------------------------------------- - // [File Management] - // -------------------------------------------------------------------------- - load(fileList) { for (var i = 0; i < fileList.length; i++) { const file = fileList[i]; @@ -705,7 +297,7 @@ class TableGen { dataOfFile(file) { const obj = this.files[file]; if (!obj) - FAIL(`TableGen.dataOfFile(): File '${file}' not loaded`); + FATAL(`TableGen.dataOfFile(): File '${file}' not loaded`); return obj.data; } @@ -726,7 +318,7 @@ class TableGen { } if (!done) - FAIL(`TableGen.inject(): Cannot find '${key}'`); + FATAL(`TableGen.inject(): Cannot find '${key}'`); if (size) this.tableSizes[key] = size; @@ -734,20 +326,56 @@ class TableGen { return this; } + dumpTableSizes() { + const sizes = this.tableSizes; + + var pad = 26; + var total = 0; + + for (var name in sizes) { + const size = sizes[name]; + total += size; + console.log(("Size of " + name).padEnd(pad) + ": " + size); + } + + console.log("Size of all tables".padEnd(pad) + ": " + total); + } +} +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{ + constructor(arch) { + super(); + + this.arch = arch; + + this.tasks = []; + this.taskMap = Object.create(null); + + this.insts = []; + this.instMap = Object.create(null); + + this.aliases = []; + this.aliasMem = Object.create(null); + } + // -------------------------------------------------------------------------- // [Task Management] // -------------------------------------------------------------------------- addTask(task) { if (!task.name) - FAIL(`TableGen.addModule(): Module must have a name`); + FATAL(`TableGen.addModule(): Module must have a name`); if (this.taskMap[task.name]) - FAIL(`TableGen.addModule(): Module '${task.name}' already added`); + FATAL(`TableGen.addModule(): Module '${task.name}' already added`); task.deps.forEach((dependency) => { if (!this.taskMap[dependency]) - FAIL(`TableGen.addModule(): Dependency '${dependency}' of module '${task.name}' doesn't exist`); + FATAL(`TableGen.addModule(): Dependency '${dependency}' of module '${task.name}' doesn't exist`); }); this.tasks.push(task); @@ -792,7 +420,7 @@ class TableGen { addInst(inst) { if (this.instMap[inst.name]) - FAIL(`TableGen.addInst(): Instruction '${inst.name}' already added`); + FATAL(`TableGen.addInst(): Instruction '${inst.name}' already added`); inst.id = this.insts.length; this.insts.push(inst); @@ -819,25 +447,6 @@ class TableGen { } // -------------------------------------------------------------------------- - // [Other] - // -------------------------------------------------------------------------- - - dumpTableSizes() { - const sizes = this.tableSizes; - - var pad = 26; - var total = 0; - - for (var name in sizes) { - const size = sizes[name]; - total += size; - console.log(("Size of " + name).padEnd(pad) + ": " + size); - } - - console.log("Size of all tables".padEnd(pad) + ": " + total); - } - - // -------------------------------------------------------------------------- // [Hooks] // -------------------------------------------------------------------------- @@ -856,7 +465,7 @@ class IdEnum extends Task { } comment(name) { - FAIL("IdEnum.comment(): Must be reimplemented"); + FATAL("IdEnum.comment(): Must be reimplemented"); } run() { @@ -885,63 +494,75 @@ exports.IdEnum = IdEnum; // [NameTable] // ============================================================================ -class NameTable extends Task { - constructor(name, deps) { - super(name || "NameTable", deps); +class Output { + constructor() { + this.content = Object.create(null); + this.tableSize = Object.create(null); } - run() { - const arch = this.ctx.arch; - const none = "Inst::kIdNone"; + add(id, content, tableSize) { + this.content[id] = content; + this.tableSize[id] = typeof tableSize === "number" ? tableSize : 0; + } +}; +exports.Output = Output; - const insts = this.ctx.insts; - const instNames = new IndexedString(); +function generateNameData(out, instructions) { + const none = "Inst::kIdNone"; - const instFirst = new Array(26); - const instLast = new Array(26); + const instFirst = new Array(26); + const instLast = new Array(26); + const instNameData = new InstructionNameData(); - var maxLength = 0; - for (var i = 0; i < insts.length; i++) { - const inst = insts[i]; - instNames.add(inst.displayName); - maxLength = Math.max(maxLength, inst.displayName.length); - } - instNames.index(); + for (let i = 0; i < instructions.length; i++) + instNameData.add(instructions[i].displayName); + instNameData.index(); - for (var i = 0; i < insts.length; i++) { - const inst = insts[i]; - const name = inst.displayName; - const nameIndex = instNames.getIndex(name); + for (let i = 0; i < instructions.length; i++) { + const inst = instructions[i]; + const displayName = inst.displayName; + const alphaIndex = displayName.charCodeAt(0) - 'a'.charCodeAt(0); - const index = name.charCodeAt(0) - 'a'.charCodeAt(0); - if (index < 0 || index >= 26) - FAIL(`TableGen.generateNameData(): Invalid lookup character '${name[0]}' of '${name}'`); + if (alphaIndex < 0 || alphaIndex >= 26) + FATAL(`generateNameData(): Invalid lookup character '${displayName[0]}' of '${displayName}'`); - inst.nameIndex = nameIndex; - if (instFirst[index] === undefined) - instFirst[index] = `Inst::kId${inst.enum}`; - instLast[index] = `Inst::kId${inst.enum}`; - } + if (instFirst[alphaIndex] === undefined) + instFirst[alphaIndex] = `Inst::kId${inst.enum}`; + instLast[alphaIndex] = `Inst::kId${inst.enum}`; + } - var s = ""; - s += `const char InstDB::_nameData[] =\n${instNames.format(kIndent, kJustify)}\n`; + var s = ""; + s += `const InstNameIndex InstDB::instNameIndex = {{\n`; + for (var i = 0; i < instFirst.length; i++) { + const firstId = instFirst[i] || none; + const lastId = instLast[i] || none; + + s += ` { ${String(firstId).padEnd(22)}, ${String(lastId).padEnd(22)} + 1 }`; + if (i !== 26 - 1) + s += `,`; s += `\n`; - s += `const InstDB::InstNameIndex InstDB::instNameIndex[26] = {\n`; - for (var i = 0; i < instFirst.length; i++) { - const firstId = instFirst[i] || none; - const lastId = instLast[i] || none; - - s += ` { ${String(firstId).padEnd(22)}, ${String(lastId).padEnd(22)} + 1 }`; - if (i !== 26 - 1) - s += `,`; - s += `\n`; - } - s += `};\n`; + } + s += `}, uint16_t(${instNameData.maxNameLength})};\n`; + s += `\n`; + s += instNameData.formatStringTable("InstDB::_instNameStringTable"); + s += `\n`; + s += instNameData.formatIndexTable("InstDB::_instNameIndexTable"); + + const dataSize = instNameData.getSize() + 26 * 4; + out.add("NameData", StringUtils.disclaimer(s), dataSize); + return out; +} +exports.generateNameData = generateNameData; - this.ctx.inject("NameLimits", - StringUtils.disclaimer(`enum : uint32_t { kMaxNameSize = ${maxLength} };\n`)); +class NameTable extends Task { + constructor(name, deps) { + super(name || "NameTable", deps); + } - return this.ctx.inject("NameData", StringUtils.disclaimer(s), instNames.getSize() + 26 * 4); + run() { + const output = new Output(); + generateNameData(output, this.ctx.insts); + this.ctx.inject("NameData", output.content["NameData"], output.tableSize["NameData"]); } } exports.NameTable = NameTable; |