summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asmjit/tools
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asmjit/tools')
-rwxr-xr-x[-rw-r--r--]3rdparty/asmjit/tools/configure-makefiles.sh0
-rwxr-xr-x[-rw-r--r--]3rdparty/asmjit/tools/configure-ninja.sh0
-rwxr-xr-x[-rw-r--r--]3rdparty/asmjit/tools/configure-sanitizers.sh4
-rwxr-xr-x[-rw-r--r--]3rdparty/asmjit/tools/configure-xcode.sh0
-rwxr-xr-x[-rw-r--r--]3rdparty/asmjit/tools/enumgen.sh0
-rw-r--r--3rdparty/asmjit/tools/generator-commons.js592
-rw-r--r--3rdparty/asmjit/tools/generator-cxx.js270
-rw-r--r--3rdparty/asmjit/tools/tablegen-a64.js (renamed from 3rdparty/asmjit/tools/tablegen-arm.js)45
-rwxr-xr-x3rdparty/asmjit/tools/tablegen-a64.sh3
-rw-r--r--3rdparty/asmjit/tools/tablegen-arm.sh3
-rw-r--r--3rdparty/asmjit/tools/tablegen-x86.js403
-rwxr-xr-x[-rw-r--r--]3rdparty/asmjit/tools/tablegen-x86.sh0
-rw-r--r--3rdparty/asmjit/tools/tablegen.js871
-rwxr-xr-x[-rw-r--r--]3rdparty/asmjit/tools/tablegen.sh3
14 files changed, 1333 insertions, 861 deletions
diff --git a/3rdparty/asmjit/tools/configure-makefiles.sh b/3rdparty/asmjit/tools/configure-makefiles.sh
index 69503dc28ef..69503dc28ef 100644..100755
--- a/3rdparty/asmjit/tools/configure-makefiles.sh
+++ b/3rdparty/asmjit/tools/configure-makefiles.sh
diff --git a/3rdparty/asmjit/tools/configure-ninja.sh b/3rdparty/asmjit/tools/configure-ninja.sh
index 84808d24363..84808d24363 100644..100755
--- a/3rdparty/asmjit/tools/configure-ninja.sh
+++ b/3rdparty/asmjit/tools/configure-ninja.sh
diff --git a/3rdparty/asmjit/tools/configure-sanitizers.sh b/3rdparty/asmjit/tools/configure-sanitizers.sh
index a9f64969b70..d35b9a4cad3 100644..100755
--- a/3rdparty/asmjit/tools/configure-sanitizers.sh
+++ b/3rdparty/asmjit/tools/configure-sanitizers.sh
@@ -11,3 +11,7 @@ echo ""
echo "== [Configuring Build - Release_UBSAN] =="
eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}/Release_UBSAN" ${BUILD_OPTIONS} -DCMAKE_BUILD_TYPE=Release -DASMJIT_SANITIZE=undefined
echo ""
+
+echo "== [Configuring Build - Release_MSAN] =="
+eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}/Release_MSAN" ${BUILD_OPTIONS} -DCMAKE_BUILD_TYPE=Release -DASMJIT_SANITIZE=memory
+echo ""
diff --git a/3rdparty/asmjit/tools/configure-xcode.sh b/3rdparty/asmjit/tools/configure-xcode.sh
index d9c7d983d75..d9c7d983d75 100644..100755
--- a/3rdparty/asmjit/tools/configure-xcode.sh
+++ b/3rdparty/asmjit/tools/configure-xcode.sh
diff --git a/3rdparty/asmjit/tools/enumgen.sh b/3rdparty/asmjit/tools/enumgen.sh
index 4783db2449d..4783db2449d 100644..100755
--- a/3rdparty/asmjit/tools/enumgen.sh
+++ b/3rdparty/asmjit/tools/enumgen.sh
diff --git a/3rdparty/asmjit/tools/generator-commons.js b/3rdparty/asmjit/tools/generator-commons.js
new file mode 100644
index 00000000000..eb3a0721ccc
--- /dev/null
+++ b/3rdparty/asmjit/tools/generator-commons.js
@@ -0,0 +1,592 @@
+// This file is part of AsmJit project <https://asmjit.com>
+//
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
+
+const hasOwn = Object.prototype.hasOwnProperty;
+function nop(x) { return x; }
+
+// Generator - Constants
+// ---------------------
+
+const kIndent = " ";
+exports.kIndent = kIndent;
+
+const kLineWidth = 120;
+
+// Generator - Logging
+// -------------------
+
+let VERBOSE = false;
+
+function setDebugVerbosity(value) {
+ VERBOSE = value;
+}
+exports.setDebugVerbosity = setDebugVerbosity;
+
+function DEBUG(msg) {
+ if (VERBOSE)
+ console.log(msg);
+}
+exports.DEBUG = DEBUG;
+
+function WARN(msg) {
+ console.log(msg);
+}
+exports.WARN = WARN;
+
+function FATAL(msg) {
+ console.log(`FATAL: ${msg}`);
+ throw new Error(msg);
+}
+exports.FATAL = FATAL;
+
+// Generator - Object Utilities
+// ----------------------------
+
+class ObjectUtils {
+ static clone(map) {
+ return Object.assign(Object.create(null), map);
+ }
+
+ static merge(a, b) {
+ if (a === b)
+ return a;
+
+ for (let k in b) {
+ let av = a[k];
+ let bv = b[k];
+
+ if (typeof av === "object" && typeof bv === "object")
+ ObjectUtils.merge(av, bv);
+ else
+ a[k] = bv;
+ }
+
+ return a;
+ }
+
+ static equals(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 (let i = 0; i < len; i++)
+ if (!ObjectUtils.equals(a[i], b[i]))
+ return false;
+ }
+ else {
+ if (a === null || b === null)
+ return a === b;
+
+ for (let k in a)
+ if (!hasOwn.call(b, k) || !ObjectUtils.equals(a[k], b[k]))
+ return false;
+
+ for (let k in b)
+ if (!hasOwn.call(a, k))
+ return false;
+ }
+
+ return true;
+ }
+
+ static equalsExcept(a, b, except) {
+ if (a === b)
+ return true;
+
+ if (typeof a !== "object" || typeof b !== "object" || Array.isArray(a) || Array.isArray(b))
+ return ObjectUtils.equals(a, b);
+
+ for (let k in a)
+ if (!hasOwn.call(except, k) && (!hasOwn.call(b, k) || !ObjectUtils.equals(a[k], b[k])))
+ return false;
+
+ for (let k in b)
+ if (!hasOwn.call(except, k) && !hasOwn.call(a, k))
+ return false;
+
+ return true;
+ }
+
+ static findKey(map, keys) {
+ for (let key in keys)
+ if (hasOwn.call(map, key))
+ return key;
+ return undefined;
+ }
+
+ static hasAny(map, keys) {
+ for (let key in keys)
+ if (hasOwn.call(map, key))
+ return true;
+ return false;
+ }
+
+ static and(a, b) {
+ const out = Object.create(null);
+ for (let k in a)
+ if (hasOwn.call(b, k))
+ out[k] = true;
+ return out;
+ }
+
+ static xor(a, b) {
+ const out = Object.create(null);
+ for (let k in a) if (!hasOwn.call(b, k)) out[k] = true;
+ for (let k in b) if (!hasOwn.call(a, k)) out[k] = true;
+ return out;
+ }
+}
+exports.ObjectUtils = ObjectUtils;
+
+// Generator - Array Utilities
+// ---------------------------
+
+class ArrayUtils {
+ static min(arr, fn) {
+ if (!arr.length)
+ return null;
+
+ if (!fn)
+ fn = nop;
+
+ let v = fn(arr[0]);
+ for (let 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;
+
+ let v = fn(arr[0]);
+ for (let 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 (let i = 0; i < arr.length; i++)
+ if (ObjectUtils.equals(arr[i], what))
+ return i;
+ return -1;
+ }
+
+ static toDict(arr, value) {
+ if (value === undefined)
+ value = true;
+
+ const out = Object.create(null);
+ for (let i = 0; i < arr.length; i++)
+ out[arr[i]] = value;
+ return out;
+ }
+}
+exports.ArrayUtils = ArrayUtils;
+
+
+// Generator - String Utilities
+// ----------------------------
+
+class StringUtils {
+ static asString(x) { return String(x); }
+
+ static countOf(s, pattern) {
+ if (!pattern)
+ FATAL(`Pattern cannot be empty`);
+
+ let n = 0;
+ let pos = 0;
+
+ while ((pos = s.indexOf(pattern, pos)) >= 0) {
+ n++;
+ pos += pattern.length;
+ }
+
+ return n;
+ }
+
+ static trimLeft(s) { return s.replace(/^\s+/, ""); }
+ static trimRight(s) { return s.replace(/\s+$/, ""); }
+
+ static upFirst(s) {
+ if (!s) return "";
+ return s[0].toUpperCase() + s.substr(1);
+ }
+
+ static decToHex(n, nPad) {
+ let hex = Number(n < 0 ? 0x100000000 + n : n).toString(16);
+ while (nPad > hex.length)
+ hex = "0" + hex;
+ return "0x" + hex.toUpperCase();
+ }
+
+ static format(array, indent, showIndex, mapFn) {
+ if (!mapFn)
+ mapFn = StringUtils.asString;
+
+ let s = "";
+ let threshold = 80;
+
+ if (showIndex === -1)
+ s += indent;
+
+ for (let i = 0; i < array.length; i++) {
+ const item = array[i];
+ const last = i === array.length - 1;
+
+ if (showIndex !== -1)
+ s += indent;
+
+ 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 (showIndex === -1) {
+ if (s.length >= threshold - 1 && !last) {
+ s += "\n" + indent;
+ threshold += 80;
+ }
+ else {
+ if (!last) s += " ";
+ }
+ }
+ else {
+ if (!last) s += "\n";
+ }
+ }
+
+ return s;
+ }
+
+ static makeCxxArray(array, code, indent) {
+ if (typeof indent !== "string")
+ indent = kIndent;
+
+ return `${code} = {\n${indent}` + array.join(`,\n${indent}`) + `\n};\n`;
+ }
+
+ static makeCxxArrayWithComment(array, code, indent) {
+ if (typeof indent !== "string")
+ indent = kIndent;
+
+ let s = "";
+ for (let 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 formatCppStruct(...args) {
+ return "{ " + args.join(", ") + " }";
+ }
+
+ static formatCppFlags(obj, fn, none) {
+ if (none == null)
+ none = "0";
+
+ if (!fn)
+ fn = nop;
+
+ let out = "";
+ for (let k in obj) {
+ if (obj[k])
+ out += (out ? " | " : "") + fn(k);
+ }
+ return out ? out : none;
+ }
+
+ static formatRecords(array, indent, fn) {
+ if (typeof indent !== "string")
+ indent = kIndent;
+
+ if (!fn)
+ fn = nop;
+
+ let s = "";
+ let line = "";
+ for (let i = 0; i < array.length; i++) {
+ const item = fn(array[i]);
+ const combined = line ? line + ", " + item : item;
+
+ if (combined.length >= kLineWidth) {
+ s = s ? s + ",\n" + line : line;
+ line = item;
+ }
+ else {
+ line = combined;
+ }
+ }
+
+ if (line) {
+ s = s ? s + ",\n" + line : line;
+ }
+
+ return StringUtils.indent(s, indent);
+ }
+
+ static disclaimer(s) {
+ return "// ------------------- Automatically generated, do not edit -------------------\n" +
+ s +
+ "// ----------------------------------------------------------------------------\n";
+ }
+
+ static indent(s, indentation) {
+ if (typeof indentation === "number")
+ indentation = " ".repeat(indentation);
+
+ let lines = s.split(/\r?\n/g);
+ if (indentation) {
+ for (let i = 0; i < lines.length; i++) {
+ let line = lines[i];
+ if (line)
+ lines[i] = indentation + line;
+ }
+ }
+
+ return lines.join("\n");
+ }
+
+ static extract(s, start, end) {
+ const iStart = s.indexOf(start);
+ const iEnd = s.indexOf(end);
+
+ if (iStart === -1)
+ FATAL(`StringUtils.extract(): Couldn't locate start mark '${start}'`);
+
+ if (iEnd === -1)
+ FATAL(`StringUtils.extract(): Couldn't locate end mark '${end}'`);
+
+ return s.substring(iStart + start.length, iEnd).trim();
+ }
+
+ static inject(s, start, end, code) {
+ let iStart = s.indexOf(start);
+ let iEnd = s.indexOf(end);
+
+ if (iStart === -1)
+ FATAL(`StringUtils.inject(): Couldn't locate start mark '${start}'`);
+
+ if (iEnd === -1)
+ FATAL(`StringUtils.inject(): Couldn't locate end mark '${end}'`);
+
+ let nIndent = 0;
+ while (iStart > 0 && s[iStart-1] === " ") {
+ iStart--;
+ nIndent++;
+ }
+
+ if (nIndent) {
+ const indentation = " ".repeat(nIndent);
+ code = StringUtils.indent(code, indentation) + indentation;
+ }
+
+ 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;
+ }
+ }
+}
+exports.StringUtils = StringUtils;
+
+// Generator - Indexed Array
+// =========================
+
+// 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);
+ let 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;
+
+// Generator - Indexed String
+// ==========================
+
+// 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);
+
+ let k, kp;
+ let 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`.
+ let offMap = Object.create(null);
+ let offset = 0;
+
+ for (i = 0, len = array.length; i < len; i++) {
+ k = array[i];
+
+ offMap[k] = offset;
+ offset += k.length + 1;
+ }
+ this.size = offset;
+
+ // Assign valid offsets to `map`.
+ for (kp in map) {
+ k = partialMap[kp];
+ map[kp] = offMap[k] + k.length - kp.length;
+ }
+ }
+
+ format(indent, justify) {
+ if (this.size === -1)
+ FATAL(`IndexedString.format(): not indexed yet, call index()`);
+
+ const array = this.array;
+ if (!justify) justify = 0;
+
+ let i;
+ let s = "";
+ let line = "";
+
+ 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;
+ }
+ }
+
+ return s + line;
+ }
+
+ getSize() {
+ if (this.size === -1)
+ FATAL(`IndexedString.getSize(): Not indexed yet, call index()`);
+ return this.size;
+ }
+
+ getIndex(k) {
+ if (this.size === -1)
+ FATAL(`IndexedString.getIndex(): Not indexed yet, call index()`);
+
+ if (!hasOwn.call(this.map, k))
+ FATAL(`IndexedString.getIndex(): Key '${k}' not found.`);
+
+ return this.map[k];
+ }
+}
+exports.IndexedString = IndexedString;
diff --git a/3rdparty/asmjit/tools/generator-cxx.js b/3rdparty/asmjit/tools/generator-cxx.js
new file mode 100644
index 00000000000..b1b1d946cae
--- /dev/null
+++ b/3rdparty/asmjit/tools/generator-cxx.js
@@ -0,0 +1,270 @@
+// This file is part of AsmJit project <https://asmjit.com>
+//
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
+
+// C++ code generation helpers.
+const commons = require("./generator-commons.js");
+const FATAL = commons.FATAL;
+
+// Utilities to convert primitives to C++ code.
+class Utils {
+ static toHex(val, pad) {
+ if (val < 0)
+ val = 0xFFFFFFFF + val + 1;
+
+ let s = val.toString(16);
+ if (pad != null && s.length < pad)
+ s = "0".repeat(pad - s.length) + s;
+
+ return "0x" + s.toUpperCase();
+ }
+
+ static capitalize(s) {
+ s = String(s);
+ return !s ? s : s[0].toUpperCase() + s.substr(1);
+ }
+
+ static camelCase(s) {
+ if (s == null || s === "")
+ return s;
+
+ s = String(s);
+ if (/^[A-Z]+$/.test(s))
+ return s.toLowerCase();
+ else
+ return s[0].toLowerCase() + s.substr(1);
+ }
+
+ static normalizeSymbolName(s) {
+ switch (s) {
+ case "and":
+ case "or":
+ case "xor":
+ return s + "_";
+ default:
+ return s;
+ }
+ }
+
+ static indent(s, indentation) {
+ if (typeof indentation === "number")
+ indentation = " ".repeat(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;
+ }
+ }
+
+ return lines.join("\n");
+ }
+}
+exports.Utils = Utils;
+
+// A node that represents a C++ construct.
+class Node {
+ constructor(kind) {
+ this.kind = kind;
+ }
+};
+exports.Node = Node;
+
+// A single line of C++ code that declares a variable with optional initialization.
+class Var extends Node {
+ constructor(type, name, init) {
+ super("var");
+
+ this.type = type;
+ this.name = name;
+ this.init = init || "";
+ }
+
+ toString() {
+ let s = this.type + " " + this.name;
+ if (this.init)
+ s += " = " + this.init;
+ return s + ";\n";
+ }
+};
+exports.Var = Var;
+
+// A single line of C++ code, which should not contain any branch or a variable declaration.
+class Line extends Node {
+ constructor(code) {
+ super("line");
+
+ this.code = code;
+ }
+
+ toString() {
+ return String(this.code) + "\n";
+ }
+};
+exports.Line = Line;
+
+// A block containing an array of `Node` items (may contain nested blocks, etc...).
+class Block extends Node {
+ constructor(nodes) {
+ super("block");
+
+ this.nodes = nodes || [];
+ }
+
+ isEmpty() {
+ return this.nodes.length === 0;
+ }
+
+ appendNode(node) {
+ if (!(node instanceof Node))
+ FATAL("Block.appendNode(): Node must be an instance of Node");
+
+ this.nodes.push(node);
+ return this;
+ }
+
+ prependNode(node) {
+ if (!(node instanceof Node))
+ FATAL("Block.prependNode(): Node must be an instance of Node");
+
+ this.nodes.unshift(node);
+ return this;
+ }
+
+ insertNode(index, node) {
+ if (!(node instanceof Node))
+ FATAL("Block.insertNode(): Node must be an instance of Node");
+
+ if (index >= this.nodes.length)
+ this.nodes.push(node);
+ else
+ this.nodes.splice(index, 0, node);
+
+ return this;
+ }
+
+ addVarDecl(type, name, init) {
+ let node = type;
+
+ if (!(node instanceof Var))
+ node = new Var(type, name, init);
+
+ let i = 0;
+ while (i < this.nodes.length) {
+ const n = this.nodes[i];
+ if (n.kind === "var" && n.name === node.name && n.init === node.init)
+ return this;
+
+ if (n.kind !== "var")
+ break;
+
+ i++;
+ }
+
+ this.insertNode(i, node);
+ return this;
+ }
+
+ addLine(code) {
+ if (typeof code !== "string")
+ FATAL("Block.addLine(): Line must be string");
+
+ this.nodes.push(new Line(code));
+ return this;
+ }
+
+ prependEmptyLine() {
+ if (!this.isEmpty())
+ this.nodes.splice(0, 0, new Line(""));
+ return this;
+ }
+
+ addEmptyLine() {
+ if (!this.isEmpty())
+ this.nodes.push(new Line(""));
+ return this;
+ }
+
+ toString() {
+ let s = "";
+ for (let node of this.nodes)
+ s += String(node);
+ return s;
+ }
+}
+exports.Block = Block;
+
+// A C++ 'condition' (if statement) and its 'body' if it's taken.
+class If extends Node {
+ constructor(cond, body) {
+ super("if");
+
+ if (body == null)
+ body = new Block();
+
+ if (!(body instanceof Block))
+ FATAL("If() - body must be a Block");
+
+ this.cond = cond;
+ this.body = body;
+ }
+
+ toString() {
+ const cond = String(this.cond);
+ const body = String(this.body);
+
+ return `if (${cond}) {\n` + Utils.indent(body, 2) + `}\n`;
+ }
+}
+exports.If = If;
+
+//! A C++ switch statement.
+class Case extends Node {
+ constructor(cond, body) {
+ super("case");
+
+ this.cond = cond;
+ this.body = body || new Block();
+ }
+
+ toString() {
+ let s = "";
+ for (let node of this.body.nodes)
+ s += String(node)
+
+ if (this.cond !== "default")
+ return `case ${this.cond}: {\n` + Utils.indent(s, 2) + `}\n`;
+ else
+ return `default: {\n` + Utils.indent(s, 2) + `}\n`;
+ }
+};
+exports.Case = Case;
+
+class Switch extends Node {
+ constructor(expression, cases) {
+ super("switch");
+
+ this.expression = expression;
+ this.cases = cases || [];
+ }
+
+ addCase(cond, body) {
+ this.cases.push(new Case(cond, body));
+ return this;
+ }
+
+ toString() {
+ let s = "";
+ for (let c of this.cases) {
+ if (s)
+ s += "\n";
+ s += String(c);
+ }
+
+ return `switch (${this.expression}) {\n` + Utils.indent(s, 2) + `}\n`;
+ }
+}
+exports.Switch = Switch;
diff --git a/3rdparty/asmjit/tools/tablegen-arm.js b/3rdparty/asmjit/tools/tablegen-a64.js
index e1c829358e2..1466fc63b01 100644
--- a/3rdparty/asmjit/tools/tablegen-arm.js
+++ b/3rdparty/asmjit/tools/tablegen-a64.js
@@ -1,37 +1,29 @@
-// [AsmJit]
-// Machine Code Generation for C++.
+// This file is part of AsmJit project <https://asmjit.com>
//
-// [License]
-// ZLIB - See LICENSE.md file in the package.
-
-// ============================================================================
-// tablegen-arm.js
-// ============================================================================
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
"use strict";
-const { executionAsyncResource } = require("async_hooks");
const core = require("./tablegen.js");
+const commons = require("./generator-commons.js");
const hasOwn = Object.prototype.hasOwnProperty;
const asmdb = core.asmdb;
-const kIndent = core.kIndent;
-const IndexedArray = core.IndexedArray;
-const StringUtils = core.StringUtils;
+const kIndent = commons.kIndent;
+const IndexedArray = commons.IndexedArray;
+const StringUtils = commons.StringUtils;
-const FAIL = core.FAIL;
+const FATAL = commons.FATAL;
// ============================================================================
// [ArmDB]
// ============================================================================
-// Create ARM ISA.
-const isa = new asmdb.arm.ISA();
-
-// ============================================================================
-// [tablegen.arm.GenUtils]
-// ============================================================================
+// Create AArch64 ISA.
+const isa = new asmdb.aarch64.ISA();
+/*
class GenUtils {
// Get a list of instructions based on `name` and optional `mode`.
static query(name, mode) {
@@ -76,6 +68,7 @@ class GenUtils {
return arr;
}
}
+*/
// ============================================================================
// [tablegen.arm.ArmTableGen]
@@ -133,11 +126,8 @@ class ArmTableGen extends core.TableGen {
// [06] OpcodeDataIndex.
"([^\\)]+)" +
- "\\s*,\\s*" +
-
- // [07] NameDataIndex.
- "([^\\)]+)" +
"\\s*\\)"
+
, "g");
var m;
@@ -168,14 +158,12 @@ class ArmTableGen extends core.TableGen {
opcodeData : opcodeData, // Opcode data.
opcodeDataIndex : -1, // Opcode data index.
rwInfo : rwInfo, // RW info.
- flags : instFlags, // Instruction flags.
-
- nameIndex : -1 // Index to InstDB::_nameData.
+ 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)");
+ FATAL("ARMTableGen.parse(): Invalid parsing regexp (no data parsed)");
console.log("Number of Instructions: " + this.insts.length);
}
@@ -188,8 +176,7 @@ class ArmTableGen extends core.TableGen {
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) + ")";
+ String(inst.opcodeDataIndex ).padEnd( 3) + ")" ;
}) + "\n";
return this.inject("InstInfo", s, this.insts.length * 4);
}
diff --git a/3rdparty/asmjit/tools/tablegen-a64.sh b/3rdparty/asmjit/tools/tablegen-a64.sh
new file mode 100755
index 00000000000..2cbd85ece16
--- /dev/null
+++ b/3rdparty/asmjit/tools/tablegen-a64.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+node ./tablegen-a64.js
diff --git a/3rdparty/asmjit/tools/tablegen-arm.sh b/3rdparty/asmjit/tools/tablegen-arm.sh
deleted file mode 100644
index 8545c1e71ba..00000000000
--- a/3rdparty/asmjit/tools/tablegen-arm.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-node ./tablegen-arm.js
diff --git a/3rdparty/asmjit/tools/tablegen-x86.js b/3rdparty/asmjit/tools/tablegen-x86.js
index 4750edfa205..377a71045e7 100644
--- a/3rdparty/asmjit/tools/tablegen-x86.js
+++ b/3rdparty/asmjit/tools/tablegen-x86.js
@@ -3,86 +3,43 @@
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
-// ============================================================================
-// tablegen-x86.js
-//
-// The purpose of this script is to fetch all instructions' names into a single
-// string and to optimize common patterns that appear in instruction data. It
-// prevents relocation of small strings (instruction names) that has to be done
-// by a linker to make all pointers the binary application/library uses valid.
-// This approach decreases the final size of AsmJit binary and relocation data.
-//
-// NOTE: This script relies on 'asmdb' package. Either install it by using
-// node.js package manager (npm) or by copying/symlinking the whole asmdb
-// directory as [asmjit]/tools/asmdb.
-// ============================================================================
-
"use strict";
+const fs = require("fs");
+const path = require("path");
+
+const commons = require("./generator-commons.js");
+const cxx = require("./generator-cxx.js");
const core = require("./tablegen.js");
+
const asmdb = core.asmdb;
-const kIndent = core.kIndent;
-const Lang = core.Lang;
-const CxxUtils = core.CxxUtils;
-const MapUtils = core.MapUtils;
-const ArrayUtils = core.ArrayUtils;
-const StringUtils = core.StringUtils;
-const IndexedArray = core.IndexedArray;
+const DEBUG = commons.DEBUG;
+const FATAL = commons.FATAL;
+const kIndent = commons.kIndent;
+const ArrayUtils = commons.ArrayUtils;
+const IndexedArray = commons.IndexedArray;
+const ObjectUtils = commons.ObjectUtils;
+const StringUtils = commons.StringUtils;
const hasOwn = Object.prototype.hasOwnProperty;
const disclaimer = StringUtils.disclaimer;
-const FAIL = core.FAIL;
-const DEBUG = core.DEBUG;
-
const decToHex = StringUtils.decToHex;
+function readJSON(fileName) {
+ const content = fs.readFileSync(fileName);
+ return JSON.parse(content);
+}
+
+const x86data = readJSON(path.join(__dirname, "..", "db", asmdb.x86.dbName));
+
// ============================================================================
// [tablegen.x86.x86isa]
// ============================================================================
// Create the X86 database and add some special cases recognized by AsmJit.
-const x86isa = new asmdb.x86.ISA({
- instructions: [
- // Imul in [reg, imm] form is encoded as [reg, reg, imm].
- ["imul", "r16, ib" , "RMI" , "66 6B /r ib" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
- ["imul", "r32, ib" , "RMI" , "6B /r ib" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
- ["imul", "r64, ib" , "RMI" , "REX.W 6B /r ib", "X64 OF=W SF=W ZF=U AF=U PF=U CF=W"],
- ["imul", "r16, iw" , "RMI" , "66 69 /r iw" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
- ["imul", "r32, id" , "RMI" , "69 /r id" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
- ["imul", "r64, id" , "RMI" , "REX.W 69 /r id", "X64 OF=W SF=W ZF=U AF=U PF=U CF=W"],
-
- // Movabs (X64 only).
- ["movabs", "W:r64, iq/uq" , "I" , "REX.W B8+r iq", "X64"],
- ["movabs", "w:al, moff8" , "NONE", "A0" , "X64"],
- ["movabs", "w:ax, moff16" , "NONE", "66 A1" , "X64"],
- ["movabs", "W:eax, moff32", "NONE", "A1" , "X64"],
- ["movabs", "W:rax, moff64", "NONE", "REX.W A1" , "X64"],
- ["movabs", "W:moff8, al" , "NONE", "A2" , "X64"],
- ["movabs", "W:moff16, ax" , "NONE", "66 A3" , "X64"],
- ["movabs", "W:moff32, eax", "NONE", "A3" , "X64"],
- ["movabs", "W:moff64, rax", "NONE", "REX.W A3" , "X64"]
- ]
-});
-
-// Remapped instructions contain mapping between instructions that AsmJit expects
-// and instructions provided by asmdb. In general, AsmJit uses string instructions
-// (like cmps, movs, etc...) without the suffix, so we just remap these and keep
-// all others.
-const RemappedInsts = {
- __proto__: null,
-
- "cmpsd": { names: ["cmpsd"] , rep: false },
- "movsd": { names: ["movsd"] , rep: false },
- "cmps" : { names: ["cmpsb", "cmpsw", "cmpsd", "cmpsq"], rep: true },
- "movs" : { names: ["movsb", "movsw", "movsd", "movsq"], rep: true },
- "lods" : { names: ["lodsb", "lodsw", "lodsd", "lodsq"], rep: null },
- "scas" : { names: ["scasb", "scasw", "scasd", "scasq"], rep: null },
- "stos" : { names: ["stosb", "stosw", "stosd", "stosq"], rep: null },
- "ins" : { names: ["insb" , "insw" , "insd" ] , rep: null },
- "outs" : { names: ["outsb", "outsw", "outsd"] , rep: null }
-};
+const x86isa = new asmdb.x86.ISA(x86data);
// ============================================================================
// [tablegen.x86.Filter]
@@ -95,7 +52,7 @@ class Filter {
for (var i = 0; i < instArray.length; i++) {
const inst = instArray[i];
- if (inst.attributes.AltForm)
+ if (inst.altForm)
continue;
const s = inst.operands.map((op) => { return op.isImm() ? "imm" : op.toString(); }).join(", ");
@@ -113,7 +70,7 @@ class Filter {
const result = [];
for (var i = 0; i < instArray.length; i++) {
const inst = instArray[i];
- if (inst.attributes.AltForm)
+ if (inst.altForm)
continue;
result.push(inst);
}
@@ -167,7 +124,28 @@ class GenUtils {
}
static cpuFeaturesOf(dbInsts) {
- return ArrayUtils.sorted(dbInsts.unionCpuFeatures());
+ function cmp(a, b) {
+ if (a.startsWith("AVX512") && !b.startsWith("AVX512"))
+ return 1;
+ if (b.startsWith("AVX512") && !a.startsWith("AVX512"))
+ return -1;
+
+ if (a.startsWith("AVX") && !b.startsWith("AVX"))
+ return 1;
+ if (b.startsWith("AVX") && !a.startsWith("AVX"))
+ return -1;
+
+ if (a === "FPU" && b !== "FPU")
+ return 1;
+ if (b === "FPU" && a !== "FPU")
+ return -1;
+
+ return a < b ? -1 : a === b ? 0 : 1;
+ }
+
+ const features = Object.getOwnPropertyNames(dbInsts.unionCpuFeatures());
+ features.sort(cmp);
+ return features;
}
static assignVexEvexCompatibilityFlags(f, dbInsts) {
@@ -261,16 +239,16 @@ class GenUtils {
const dbInst = dbInsts[i];
const operands = dbInst.operands;
- if (dbInst.attributes.Lock ) f.Lock = true;
- if (dbInst.attributes.XAcquire ) f.XAcquire = true;
- if (dbInst.attributes.XRelease ) f.XRelease = true;
- if (dbInst.attributes.BND ) f.Rep = true;
- if (dbInst.attributes.REP ) f.Rep = true;
- if (dbInst.attributes.REPNE ) f.Rep = true;
- if (dbInst.attributes.RepIgnored ) f.RepIgnored = true;
- if (dbInst.attributes.ImplicitZeroing) f.Avx512ImplicitZ = true;
+ if (dbInst.prefixes.lock ) f.Lock = true;
+ if (dbInst.prefixes.xacquire ) f.XAcquire = true;
+ if (dbInst.prefixes.xrelease ) f.XRelease = true;
+ if (dbInst.prefixes.bnd ) f.Rep = true;
+ if (dbInst.prefixes.rep ) f.Rep = true;
+ if (dbInst.prefixes.repne ) f.Rep = true;
+ if (dbInst.prefixes.repIgnore ) f.RepIgnored = true;
+ if (dbInst.k === "zeroing" ) f.Avx512ImplicitZ = true;
- if (dbInst.fpu) {
+ if (dbInst.category.FPU) {
for (var j = 0; j < operands.length; j++) {
const op = operands[j];
if (op.memSize === 16) f.FpuM16 = true;
@@ -280,7 +258,7 @@ class GenUtils {
}
}
- if (dbInst.attributes.Tsib)
+ if (dbInst.tsib)
f.Tsib = true;
if (dbInst.vsibReg)
@@ -289,12 +267,11 @@ class GenUtils {
if (dbInst.prefix === "VEX" || dbInst.prefix === "XOP")
f.Vex = true;
+ if (dbInst.encodingPreference === "EVEX")
+ f.PreferEvex = true;
+
if (dbInst.prefix === "EVEX") {
f.Evex = true;
-
- if (dbInst.extensions["AVX512_VNNI"])
- f.PreferEvex = true;
-
if (dbInst.kmask) f.Avx512K = true;
if (dbInst.zmask) f.Avx512Z = true;
@@ -418,7 +395,7 @@ class GenUtils {
}
}
- static fixedRegOf(reg) {
+ static fixedRegOfRegName(reg) {
switch (reg) {
case "es" : return 1;
case "cs" : return 2;
@@ -447,11 +424,23 @@ class GenUtils {
}
}
+ static fixedRegOf(op) {
+ if (op.isReg()) {
+ return GenUtils.fixedRegOfRegName(op.reg);
+ }
+ else if (op.isMem() && op.memRegOnly) {
+ return GenUtils.fixedRegOfRegName(op.memRegOnly);
+ }
+ else {
+ return -1;
+ }
+ }
+
static controlFlow(dbInsts) {
- if (dbInsts.checkAttribute("Control", "Jump")) return "Jump";
- if (dbInsts.checkAttribute("Control", "Call")) return "Call";
- if (dbInsts.checkAttribute("Control", "Branch")) return "Branch";
- if (dbInsts.checkAttribute("Control", "Return")) return "Return";
+ if (dbInsts.checkAttribute("control", "jump")) return "Jump";
+ if (dbInsts.checkAttribute("control", "call")) return "Call";
+ if (dbInsts.checkAttribute("control", "branch")) return "Branch";
+ if (dbInsts.checkAttribute("control", "return")) return "Return";
return "Regular";
}
}
@@ -473,16 +462,7 @@ class X86TableGen extends core.TableGen {
// Get instructions (dbInsts) having the same name as understood by AsmJit.
query(name) {
- const remapped = RemappedInsts[name];
- if (!remapped) return x86isa.query(name);
-
- const dbInsts = x86isa.query(remapped.names);
- const rep = remapped.rep;
- if (rep === null) return dbInsts;
-
- return dbInsts.filter((inst) => {
- return rep === !!(inst.attributes.REP || inst.attributes.REPNE);
- });
+ return x86isa.query(name);
}
// --------------------------------------------------------------------------
@@ -500,9 +480,8 @@ class X86TableGen extends core.TableGen {
// --- autogenerated fields ---
"([^\\)]+)" + "," + // [05] MainOpcodeIndex.
"([^\\)]+)" + "," + // [06] AltOpcodeIndex.
- "([^\\)]+)" + "," + // [07] NameIndex.
- "([^\\)]+)" + "," + // [08] CommonDataIndex.
- "([^\\)]+)" + "\\)", // [09] OperationDataIndex.
+ "([^\\)]+)" + "," + // [07] CommonDataIndex.
+ "([^\\)]+)" + "\\)", // [08] OperationDataIndex.
"g");
var m;
@@ -515,7 +494,7 @@ class X86TableGen extends core.TableGen {
const dbInsts = this.query(name);
if (name && !dbInsts.length)
- FAIL(`Instruction '${name}' not found in asmdb`);
+ FATAL(`Instruction '${name}' not found in asmdb`);
const flags = GenUtils.flagsOf(dbInsts);
const controlFlow = GenUtils.controlFlow(dbInsts);
@@ -548,7 +527,7 @@ class X86TableGen extends core.TableGen {
}
if (this.insts.length === 0)
- FAIL("X86TableGen.parse(): Invalid parsing regexp (no data parsed)");
+ FATAL("X86TableGen.parse(): Invalid parsing regexp (no data parsed)");
console.log("Number of Instructions: " + this.insts.length);
}
@@ -562,7 +541,6 @@ class X86TableGen extends core.TableGen {
String(inst.opcode1 ).padEnd(26) + ", " +
String(inst.mainOpcodeIndex ).padEnd( 3) + ", " +
String(inst.altOpcodeIndex ).padEnd( 3) + ", " +
- String(inst.nameIndex ).padEnd( 5) + ", " +
String(inst.commonInfoIndex ).padEnd( 3) + ", " +
String(inst.additionalInfoIndex).padEnd( 3) + ")";
}) + "\n";
@@ -574,7 +552,7 @@ class X86TableGen extends core.TableGen {
// --------------------------------------------------------------------------
printMissing() {
- const ignored = MapUtils.arrayToMap([
+ const ignored = ArrayUtils.toDict([
"cmpsb", "cmpsw", "cmpsd", "cmpsq",
"lodsb", "lodsw", "lodsd", "lodsq",
"movsb", "movsw", "movsd", "movsq",
@@ -832,7 +810,7 @@ class IdEnum extends core.IdEnum {
var text = "";
var features = GenUtils.cpuFeaturesOf(dbInsts);
- const priorityFeatures = ["AVX_VNNI"];
+ const priorityFeatures = ["AVX_VNNI", "AVX_VNNI_INT8", "AVX_IFMA", "AVX_NE_CONVERT"];
if (features.length) {
text += "{";
@@ -970,7 +948,7 @@ class AltOpcodeTable extends core.Task {
components[2] = "00";
}
else {
- FAIL(`Failed to process opcode '${opcode}'`);
+ FATAL(`Failed to process opcode '${opcode}'`);
}
const newOpcode = joinOpcodeComponents(components);
@@ -1009,8 +987,8 @@ class AltOpcodeTable extends core.Task {
// [tablegen.x86.InstSignatureTable]
// ============================================================================
-const RegOp = MapUtils.arrayToMap(["al", "ah", "ax", "eax", "rax", "cl", "r8lo", "r8hi", "r16", "r32", "r64", "xmm", "ymm", "zmm", "mm", "k", "sreg", "creg", "dreg", "st", "bnd"]);
-const MemOp = MapUtils.arrayToMap(["m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024"]);
+const RegOp = ArrayUtils.toDict(["al", "ah", "ax", "eax", "rax", "cl", "r8lo", "r8hi", "r16", "r32", "r64", "xmm", "ymm", "zmm", "mm", "k", "sreg", "creg", "dreg", "st", "bnd"]);
+const MemOp = ArrayUtils.toDict(["m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024"]);
const cmpOp = StringUtils.makePriorityCompare([
"RegGpbLo", "RegGpbHi", "RegGpw", "RegGpd", "RegGpq", "RegXmm", "RegYmm", "RegZmm", "RegMm", "RegKReg", "RegSReg", "RegCReg", "RegDReg", "RegSt", "RegBnd", "RegTmm",
@@ -1037,7 +1015,7 @@ function StringifyOpArray(a, map) {
else if (hasOwn.call(map, op))
mapped = map[op];
else
- FAIL(`UNHANDLED OPERAND '${op}'`);
+ FATAL(`UNHANDLED OPERAND '${op}'`);
s += (s ? " | " : "") + mapped;
}
return s ? s : "0";
@@ -1049,11 +1027,11 @@ class OSignature {
}
equals(other) {
- return MapUtils.equals(this.flags, other.flags);
+ return ObjectUtils.equals(this.flags, other.flags);
}
xor(other) {
- const result = MapUtils.xor(this.flags, other.flags);
+ const result = ObjectUtils.xor(this.flags, other.flags);
return Object.getOwnPropertyNames(result).length === 0 ? null : result;
}
@@ -1254,14 +1232,14 @@ class ISignature extends Array {
mergeWith(other) {
// If both architectures are the same, it's fine to merge.
- var ok = this.x86 === other.x86 && this.x64 === other.x64;
+ const sameArch = this.x86 === other.x86 && this.x64 === other.x64;
// If the first arch is [X86|X64] and the second [X64] it's also fine.
- if (!ok && this.x86 && this.x64 && !other.x86 && other.x64)
- ok = true;
+ // if (!ok && this.x86 && this.x64 && !other.x86 && other.x64)
+ // ok = true;
// It's not ok if both signatures have different number of implicit operands.
- if (!ok || this.implicit !== other.implicit)
+ if (!sameArch || this.implicit !== other.implicit)
return false;
// It's not ok if both signatures have different number of operands.
@@ -1269,8 +1247,8 @@ class ISignature extends Array {
if (len !== other.length)
return false;
- var xorIndex = -1;
- for (var i = 0; i < len; i++) {
+ let xorIndex = -1;
+ for (let i = 0; i < len; i++) {
const xor = this[i].xor(other[i]);
if (xor === null) continue;
@@ -1281,12 +1259,9 @@ class ISignature extends Array {
}
// Bail if mergeWidth at operand-level failed.
- if (xorIndex !== -1 && !this[xorIndex].mergeWith(other[xorIndex]))
+ if (xorIndex === -1 || !this[xorIndex].mergeWith(other[xorIndex]))
return false;
- this.x86 = this.x86 || other.x86;
- this.x64 = this.x64 || other.x64;
-
return true;
}
@@ -1297,14 +1272,14 @@ class ISignature extends Array {
class SignatureArray extends Array {
// Iterate over all signatures and check which operands don't need explicit memory size.
- calcImplicitMemSize() {
+ 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++) {
const op = inst[i];
if (regOps & (1 << i))
- s += "{" + ArrayUtils.sorted(MapUtils.and(op.flags, RegOp)).join("|") + "}";
+ s += "{" + ArrayUtils.sorted(ObjectUtils.and(op.flags, RegOp)).join("|") + "}";
}
return s || "?";
}
@@ -1323,7 +1298,7 @@ class SignatureArray extends Array {
// Check if this instruction signature has a memory operand of explicit size.
for (i = 0; i < len; i++) {
const aOp = aInst[i];
- const mem = MapUtils.firstOf(aOp.flags, MemOp);
+ const mem = ObjectUtils.findKey(aOp.flags, MemOp);
if (mem) {
// Stop if the memory operand has implicit-size or if there is more than one.
@@ -1336,7 +1311,7 @@ class SignatureArray extends Array {
memPos = i;
}
}
- else if (MapUtils.anyOf(aOp.flags, RegOp)) {
+ else if (ObjectUtils.hasAny(aOp.flags, RegOp)) {
// Doesn't consider 'r/m' as we already checked 'm'.
regOps |= (1 << i);
}
@@ -1361,7 +1336,7 @@ class SignatureArray extends Array {
for (i = 0; i < len; i++) {
if (i === memPos) continue;
- const reg = MapUtils.anyOf(bInst[i].flags, RegOp);
+ const reg = ObjectUtils.hasAny(bInst[i].flags, RegOp);
if (regOps & (1 << i))
hasMatch &= reg;
else if (reg)
@@ -1372,7 +1347,7 @@ class SignatureArray extends Array {
const bOp = bInst[memPos];
if (bOp.flags.mem) continue;
- const mem = MapUtils.firstOf(bOp.flags, MemOp);
+ const mem = ObjectUtils.findKey(bOp.flags, MemOp);
if (mem === memOp) {
sameSizeSet.push(bInst);
}
@@ -1412,6 +1387,8 @@ class SignatureArray extends Array {
// then keep this implicit as it won't do any harm. These instructions
// cannot be mixed and it will make implicit the 32-bit one in cases
// where X64 introduced 64-bit ones like `cvtsi2ss`.
+ if (!/^(bndcl|bndcn|bndcu|ptwrite|(v)?cvtsi2ss|(v)?cvtsi2sd|vcvtusi2ss|vcvtusi2sd)$/.test(instName))
+ implicit = false;
}
else {
implicit = false;
@@ -1424,8 +1401,9 @@ class SignatureArray extends Array {
// Patch all instructions to accept implicit-size memory operand.
for (bIndex = 0; bIndex < sameSizeSet.length; bIndex++) {
const bInst = sameSizeSet[bIndex];
- if (implicit)
+ if (implicit) {
bInst[memPos].flags.mem = true;
+ }
if (!implicit)
DEBUG(`${this.name}: Explicit: ${bInst}`);
@@ -1594,7 +1572,9 @@ class InstSignatureTable extends core.Task {
}
makeSignatures(dbInsts) {
+ const instName = dbInsts.length ? dbInsts[0].name : "";
const signatures = new SignatureArray();
+
for (var i = 0; i < dbInsts.length; i++) {
const inst = dbInsts[i];
const ops = inst.operands;
@@ -1678,29 +1658,9 @@ class InstSignatureTable extends core.Task {
op.flags.implicit = true;
}
- const seg = iop.memSeg;
+ const seg = iop.memSegment;
if (seg) {
switch (inst.name) {
- case "cmpsb": op.flags.m8 = true; break;
- case "cmpsw": op.flags.m16 = true; break;
- case "cmpsd": op.flags.m32 = true; break;
- case "cmpsq": op.flags.m64 = true; break;
- case "lodsb": op.flags.m8 = true; break;
- case "lodsw": op.flags.m16 = true; break;
- case "lodsd": op.flags.m32 = true; break;
- case "lodsq": op.flags.m64 = true; break;
- case "movsb": op.flags.m8 = true; break;
- case "movsw": op.flags.m16 = true; break;
- case "movsd": op.flags.m32 = true; break;
- case "movsq": op.flags.m64 = true; break;
- case "scasb": op.flags.m8 = true; break;
- case "scasw": op.flags.m16 = true; break;
- case "scasd": op.flags.m32 = true; break;
- case "scasq": op.flags.m64 = true; break;
- case "stosb": op.flags.m8 = true; break;
- case "stosw": op.flags.m16 = true; break;
- case "stosd": op.flags.m32 = true; break;
- case "stosq": op.flags.m64 = true; break;
case "insb": op.flags.m8 = true; break;
case "insw": op.flags.m16 = true; break;
case "insd": op.flags.m32 = true; break;
@@ -1720,6 +1680,9 @@ class InstSignatureTable extends core.Task {
default: console.log(`UNKNOWN MEM IN INSTRUCTION '${inst.name}'`); break;
}
+ if (iop.memRegOnly)
+ reg = iop.memRegOnly;
+
if (seg === "ds") op.flags.memDS = true;
if (seg === "es") op.flags.memES = true;
if (reg === "reg") { op.flags.memBase = true; }
@@ -1732,30 +1695,37 @@ class InstSignatureTable extends core.Task {
else if (reg) {
if (reg == "r8") {
op.flags["r8lo"] = true;
- op.flags["r8hi"] = true;
+
+ if (!inst.w || inst.w === "W0")
+ op.flags["r8hi"] = true;
}
else {
op.flags[reg] = true;
}
}
+
if (mem) {
op.flags[mem] = true;
- // HACK: Allow LEA|CL*|PREFETCH* to use any memory size.
- if (/^(cldemote|clwb|clflush\w*|lea|prefetch\w*)$/.test(inst.name)) {
+ // HACK: Allow LEA to use any memory size.
+ if (/^(lea)$/.test(inst.name)) {
op.flags.mem = true;
Object.assign(op.flags, MemOp);
}
// HACK: These instructions specify explicit memory size, but it's just informational.
- if (inst.name === "enqcmd" || inst.name === "enqcmds" || inst.name === "movdir64b")
+ if (/^(call|enqcmd|enqcmds|lcall|ljmp|movdir64b)$/.test(inst.name)) {
op.flags.mem = true;
-
+ }
}
+
if (imm) {
if (iop.immSign === "any" || iop.immSign === "signed" ) op.flags["i" + imm] = true;
if (iop.immSign === "any" || iop.immSign === "unsigned") op.flags["u" + imm] = true;
}
- if (rel) op.flags["rel" + rel] = true;
+
+ if (rel) {
+ op.flags["rel" + rel] = true;
+ }
row.push(op);
}
@@ -1766,8 +1736,8 @@ class InstSignatureTable extends core.Task {
}
}
- if (signatures.length && GenUtils.canUseImplicitMemSize(dbInsts[0].name))
- signatures.calcImplicitMemSize();
+ if (signatures.length && GenUtils.canUseImplicitMemSize(instName))
+ signatures.calcImplicitMemSize(instName);
signatures.compact();
return signatures;
@@ -1839,7 +1809,7 @@ class AdditionalInfoTable extends core.Task {
break;
}
- const instFlagsIndex = instFlagsTable.addIndexed("InstRWFlags(" + CxxUtils.flags(instFlags, (f) => { return `FLAG(${f})`; }, "FLAG(None)") + ")");
+ const instFlagsIndex = instFlagsTable.addIndexed("InstRWFlags(" + StringUtils.formatCppFlags(instFlags, (f) => { return `FLAG(${f})`; }, "FLAG(None)") + ")");
const rwInfoIndex = rwInfoTable.addIndexed(`{ ${rData}, ${wData} }`);
inst.additionalInfoIndex = additionaInfoTable.addIndexed(`{ ${instFlagsIndex}, ${rwInfoIndex}, { ${features} } }`);
@@ -1870,7 +1840,7 @@ class AdditionalInfoTable extends core.Task {
if (dbInst.name === "mov")
continue;
- const specialRegs = dbInst.specialRegs;
+ const regs = dbInst.io;
// Mov is a special case, moving to/from control regs makes flags undefined,
// which we don't want to have in `X86InstDB::operationData`. This is, thus,
@@ -1878,28 +1848,28 @@ class AdditionalInfoTable extends core.Task {
if (dbInst.name === "mov")
continue;
- for (var specialReg in specialRegs) {
+ for (var reg in regs) {
var flag = "";
- switch (specialReg) {
- case "FLAGS.CF": flag = "CF"; break;
- case "FLAGS.OF": flag = "OF"; break;
- case "FLAGS.SF": flag = "SF"; break;
- case "FLAGS.ZF": flag = "ZF"; break;
- case "FLAGS.AF": flag = "AF"; break;
- case "FLAGS.PF": flag = "PF"; break;
- case "FLAGS.DF": flag = "DF"; break;
- case "FLAGS.IF": flag = "IF"; break;
- //case "FLAGS.TF": flag = "TF"; break;
- case "FLAGS.AC": flag = "AC"; break;
- case "X86SW.C0": flag = "C0"; break;
- case "X86SW.C1": flag = "C1"; break;
- case "X86SW.C2": flag = "C2"; break;
- case "X86SW.C3": flag = "C3"; break;
+ switch (reg) {
+ case "CF": flag = "CF"; break;
+ case "OF": flag = "OF"; break;
+ case "SF": flag = "SF"; break;
+ case "ZF": flag = "ZF"; break;
+ case "AF": flag = "AF"; break;
+ case "PF": flag = "PF"; break;
+ case "DF": flag = "DF"; break;
+ case "IF": flag = "IF"; break;
+ //case "TF": flag = "TF"; break;
+ case "AC": flag = "AC"; break;
+ case "C0": flag = "C0"; break;
+ case "C1": flag = "C1"; break;
+ case "C2": flag = "C2"; break;
+ case "C3": flag = "C3"; break;
default:
continue;
}
- switch (specialRegs[specialReg]) {
+ switch (regs[reg]) {
case "R":
r[flag] = true;
break;
@@ -1924,7 +1894,7 @@ class AdditionalInfoTable extends core.Task {
// [tablegen.x86.InstRWInfoTable]
// ============================================================================
-const NOT_MEM_AMBIGUOUS = MapUtils.arrayToMap([
+const NOT_MEM_AMBIGUOUS = ArrayUtils.toDict([
"call", "movq"
]);
@@ -1997,20 +1967,20 @@ class InstRWInfoTable extends core.Task {
run() {
const insts = this.ctx.insts;
- const noRmInfo = CxxUtils.struct(
+ const noRmInfo = StringUtils.formatCppStruct(
"InstDB::RWInfoRm::kCategory" + "None".padEnd(10),
StringUtils.decToHex(0, 2),
String(0).padEnd(2),
- CxxUtils.flags({}),
+ StringUtils.formatCppFlags({}),
"0"
);
- const noOpInfo = CxxUtils.struct(
+ const noOpInfo = StringUtils.formatCppStruct(
"0x0000000000000000u",
"0x0000000000000000u",
"0xFF",
"0",
- CxxUtils.struct(0),
+ StringUtils.formatCppStruct(0),
"OpRWFlags::kNone"
);
@@ -2049,7 +2019,7 @@ class InstRWInfoTable extends core.Task {
if (opAcc === "R") flags.Read = true;
if (opAcc === "W") flags.Write = true;
if (opAcc === "X") flags.RW = true;
- Lang.merge(flags, op.flags);
+ ObjectUtils.merge(flags, op.flags);
const rIndex = opAcc === "X" || opAcc === "R" ? op.index : -1;
const rWidth = opAcc === "X" || opAcc === "R" ? op.width : -1;
@@ -2058,23 +2028,23 @@ class InstRWInfoTable extends core.Task {
const consecutiveLeadCount = op.clc;
- const opData = CxxUtils.struct(
+ const opData = StringUtils.formatCppStruct(
this.byteMaskFromBitRanges([{ start: rIndex, end: rIndex + rWidth - 1 }]) + "u",
this.byteMaskFromBitRanges([{ start: wIndex, end: wIndex + wWidth - 1 }]) + "u",
StringUtils.decToHex(op.fixed === -1 ? 0xFF : op.fixed, 2),
String(consecutiveLeadCount),
- CxxUtils.struct(0),
- CxxUtils.flags(flags, function(flag) { return "OpRWFlags::k" + flag; }, "OpRWFlags::kNone")
+ StringUtils.formatCppStruct(0),
+ StringUtils.formatCppFlags(flags, function(flag) { return "OpRWFlags::k" + flag; }, "OpRWFlags::kNone")
);
rwOpsIndex.push(this.opInfoTable.addIndexed(opData));
}
- const rmData = CxxUtils.struct(
+ const rmData = StringUtils.formatCppStruct(
"InstDB::RWInfoRm::kCategory" + rmInfo.category.padEnd(10),
StringUtils.decToHex(rmInfo.rmIndexes, 2),
String(Math.max(rmInfo.memFixed, 0)).padEnd(2),
- CxxUtils.flags({
+ StringUtils.formatCppFlags({
"InstDB::RWInfoRm::kFlagAmbiguous": Boolean(rmInfo.memAmbiguous),
"InstDB::RWInfoRm::kFlagMovssMovsd": Boolean(inst.name === "movss" || inst.name === "movsd"),
"InstDB::RWInfoRm::kFlagPextrw": Boolean(inst.name === "pextrw"),
@@ -2083,10 +2053,10 @@ class InstRWInfoTable extends core.Task {
rmInfo.memExtension === "None" ? "0" : "uint32_t(CpuFeatures::X86::k" + rmInfo.memExtension + ")"
);
- const rwData = CxxUtils.struct(
+ const rwData = StringUtils.formatCppStruct(
"InstDB::RWInfo::kCategory" + rwInfo.category.padEnd(10),
String(this.rmInfoTable.addIndexed(rmData)).padEnd(2),
- CxxUtils.struct(...(rwOpsIndex.map(function(item) { return String(item).padEnd(2); })))
+ StringUtils.formatCppStruct(...(rwOpsIndex.map(function(item) { return String(item).padEnd(2); })))
);
if (i == 0)
@@ -2134,7 +2104,7 @@ class InstRWInfoTable extends core.Task {
for (var j = start; j <= end; j++) {
const bytePos = j >> 3;
if (bytePos < 0 || bytePos >= arr.length)
- FAIL(`Range ${start}:${end} cannot be used to create a byte-mask`);
+ FATAL(`Range ${start}:${end} cannot be used to create a byte-mask`);
arr[bytePos] = 1;
}
}
@@ -2165,7 +2135,7 @@ class InstRWInfoTable extends core.Task {
access: op.read && op.write ? "X" : op.read ? "R" : op.write ? "W" : "?",
clc: 0,
flags: {},
- fixed: GenUtils.fixedRegOf(op.reg),
+ fixed: GenUtils.fixedRegOf(op),
index: op.rwxIndex,
width: op.rwxWidth
};
@@ -2195,10 +2165,26 @@ class InstRWInfoTable extends core.Task {
if (op.consecutiveLeadCount)
d.clc = op.consecutiveLeadCount;
- if (op.isReg())
- d.fixed = GenUtils.fixedRegOf(op.reg);
- else
- d.fixed = GenUtils.fixedRegOf(op.mem);
+ const instName = dbInst.name;
+ // NOTE: Avoid push/pop here as PUSH/POP has many variations for segment registers,
+ // which would set 'd.fixed' field even for GP variation of the instuction.
+ if (instName !== "push" && instName !== "pop") {
+ d.fixed = GenUtils.fixedRegOf(op);
+ }
+
+ switch (instName) {
+ case "vfcmaddcph":
+ case "vfmaddcph":
+ case "vfcmaddcsh":
+ case "vfmaddcsh":
+ case "vfcmulcsh":
+ case "vfmulcsh":
+ case "vfcmulcph":
+ case "vfmulcph":
+ if (j === 0)
+ d.flags.Unique = true;
+ break;
+ }
if (op.zext)
d.flags.ZExt = true;
@@ -2215,7 +2201,7 @@ class InstRWInfoTable extends core.Task {
}
if (d.fixed !== -1) {
- if (op.memSeg)
+ if (op.memSegment)
d.flags.MemPhysId = true;
else
d.flags.RegPhysId = true;
@@ -2225,16 +2211,26 @@ class InstRWInfoTable extends core.Task {
rwOps[j] = d;
}
else {
- if (!Lang.deepEqExcept(rwOps[j], d, { "fixed": true, "flags": true }))
+ if (!ObjectUtils.equalsExcept(rwOps[j], d, { "fixed": true, "flags": true }))
return null;
if (rwOps[j].fixed === -1)
rwOps[j].fixed = d.fixed;
- Lang.merge(rwOps[j].flags, d.flags);
+ ObjectUtils.merge(rwOps[j].flags, d.flags);
}
}
}
- return { category: "Generic", rwOps };
+
+ const name = dbInsts.length ? dbInsts[0].name : "";
+
+ switch (name) {
+ case "vpternlogd":
+ case "vpternlogq":
+ return { category: "GenericEx", rwOps };
+
+ default:
+ return { category: "Generic", rwOps };
+ }
}
function queryRwByData(dbInsts, rwOpsArray) {
@@ -2243,12 +2239,13 @@ class InstRWInfoTable extends core.Task {
const operands = dbInst.operands;
const rwOps = nullOps();
- for (var j = 0; j < operands.length; j++)
+ for (var j = 0; j < operands.length; j++) {
rwOps[j] = makeRwFromOp(operands[j])
+ }
var match = 0;
for (var j = 0; j < rwOpsArray.length; j++)
- match |= Lang.deepEq(rwOps, rwOpsArray[j]);
+ match |= ObjectUtils.equals(rwOps, rwOpsArray[j]);
if (!match)
return false;
@@ -2292,7 +2289,7 @@ class InstRWInfoTable extends core.Task {
if (queryRwByData(dbInsts, this.rwCategoryByData[k]))
return { category: k, rwOps: nullOps() };
- // FAILURE: Missing data to categorize this instruction.
+ // FATALURE: Missing data to categorize this instruction.
if (name) {
const items = dumpRwToData(dbInsts)
console.log(`RW: ${dbInsts.length ? dbInsts[0].name : ""}:`);
@@ -2305,7 +2302,7 @@ class InstRWInfoTable extends core.Task {
}
rwOpFlagsForInstruction(instName, opIndex) {
- const toMap = MapUtils.arrayToMap;
+ const toMap = ArrayUtils.toDict;
// TODO: We should be able to get this information from asmdb.
switch (instName + "@" + opIndex) {
@@ -2382,7 +2379,7 @@ class InstRWInfoTable extends core.Task {
if (/^(punpcklbw|punpckldq|punpcklwd)$/.test(dbInst.name))
return "None";
- return StringUtils.capitalize(dbInst.name);
+ return cxx.Utils.capitalize(dbInst.name);
}
}
diff --git a/3rdparty/asmjit/tools/tablegen-x86.sh b/3rdparty/asmjit/tools/tablegen-x86.sh
index 40facf326dc..40facf326dc 100644..100755
--- a/3rdparty/asmjit/tools/tablegen-x86.sh
+++ b/3rdparty/asmjit/tools/tablegen-x86.sh
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;
diff --git a/3rdparty/asmjit/tools/tablegen.sh b/3rdparty/asmjit/tools/tablegen.sh
index b2c9cac368c..0ef1e580634 100644..100755
--- a/3rdparty/asmjit/tools/tablegen.sh
+++ b/3rdparty/asmjit/tools/tablegen.sh
@@ -1,4 +1,5 @@
#!/usr/bin/env sh
set -e
-node ./tablegen-arm.js $@
+node ./tablegen-a32.js $@
+node ./tablegen-a64.js $@
node ./tablegen-x86.js $@