[ABI] Updated instruction DB, operands, and minor API changes

This changeset contains an updated instruction database that brings
ARM32 instructions for the first time. It also updates instruction
database tooling especially for ARM64, which will also be used by
ARM32 generator.

Additionally, new operan has been added, which represents a register
list as used by ARM32 instruction set.

Other minor changes are related to ARM - some stuff had to be moved
to a64 namespace from arm namespace as it's incompatible between
32-bit and 64-bit ISA.
This commit is contained in:
kobalicek
2023-12-26 23:28:40 +01:00
parent 13bd440022
commit b25df5554d
75 changed files with 5007 additions and 3934 deletions

270
tools/generator-cxx.js Normal file
View File

@@ -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;