summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asmjit/tools/tablegen.js
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asmjit/tools/tablegen.js')
-rw-r--r--3rdparty/asmjit/tools/tablegen.js871
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;