mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 20:44:37 +03:00
[ABI] Completely reworked instruction DB and generators
* Instruction database is now part of asmjit to keep it in sync * X86/X64 ISA data has been reworked, now in a proper JSON format * ARM32 ISA data has been added (currently only DB, support later) * ARM64 ISA data has been added * ARM features detection has been updated
This commit is contained in:
270
tools/gencxx.js
Normal file
270
tools/gencxx.js
Normal 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("./gencommons.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;
|
||||
Reference in New Issue
Block a user